From: patrick Date: Fri, 17 Dec 2021 12:25:18 +0000 (+0000) Subject: Import LLVM 13.0.0 release. X-Git-Url: http://artulab.com/gitweb/?a=commitdiff_plain;h=be691f3bb6417f04a68938fadbcaee2d5795e764;p=openbsd Import LLVM 13.0.0 release. --- diff --git a/gnu/llvm/lldb/.clang-tidy b/gnu/llvm/lldb/.clang-tidy index e949902171e..2cde63668d0 100644 --- a/gnu/llvm/lldb/.clang-tidy +++ b/gnu/llvm/lldb/.clang-tidy @@ -1,2 +1,7 @@ -# Checks enabled in the top-level .clang-tidy minus readability-identifier-naming -Checks: '-*,clang-diagnostic-*,llvm-*,misc-*,-misc-unused-parameters,-misc-non-private-member-variables-in-classes' +Checks: '-readability-identifier-naming,modernize-use-default-member-init,modernize-use-equals-default' +InheritParentConfig: true +CheckOptions: + - key: modernize-use-default-member-init.IgnoreMacros + value: '1' + - key: modernize-use-default-member-init.UseAssignment + value: '1' diff --git a/gnu/llvm/lldb/CMakeLists.txt b/gnu/llvm/lldb/CMakeLists.txt index bf748020ea4..2bb05c1e220 100644 --- a/gnu/llvm/lldb/CMakeLists.txt +++ b/gnu/llvm/lldb/CMakeLists.txt @@ -1,11 +1,4 @@ -cmake_minimum_required(VERSION 3.4.3) -if(CMAKE_SYSTEM_NAME STREQUAL Windows) - cmake_minimum_required(VERSION 3.13) -endif() - -if(POLICY CMP0075) - cmake_policy(SET CMP0075 NEW) -endif() +cmake_minimum_required(VERSION 3.13.4) # Add path for custom modules. set(CMAKE_MODULE_PATH @@ -29,14 +22,8 @@ include(LLDBConfig) include(AddLLDB) # Define the LLDB_CONFIGURATION_xxx matching the build type. -if( uppercase_CMAKE_BUILD_TYPE STREQUAL "DEBUG" ) - add_definitions( -DLLDB_CONFIGURATION_DEBUG ) -else() - add_definitions( -DLLDB_CONFIGURATION_RELEASE ) -endif() - -if(APPLE) - add_definitions(-DLLDB_USE_OS_LOG) +if(uppercase_CMAKE_BUILD_TYPE STREQUAL "DEBUG" ) + add_definitions(-DLLDB_CONFIGURATION_DEBUG) endif() if (WIN32) @@ -44,13 +31,22 @@ if (WIN32) endif() if (LLDB_ENABLE_PYTHON) - execute_process( - COMMAND ${PYTHON_EXECUTABLE} - -c "import distutils.sysconfig; print(distutils.sysconfig.get_python_lib(True, False, ''))" - OUTPUT_VARIABLE LLDB_PYTHON_DEFAULT_RELATIVE_PATH - OUTPUT_STRIP_TRAILING_WHITESPACE) + if (NOT CMAKE_CROSSCOMPILING) + execute_process( + COMMAND ${Python3_EXECUTABLE} + -c "import distutils.sysconfig; print(distutils.sysconfig.get_python_lib(True, False, ''))" + OUTPUT_VARIABLE LLDB_PYTHON_DEFAULT_RELATIVE_PATH + OUTPUT_STRIP_TRAILING_WHITESPACE) + + file(TO_CMAKE_PATH ${LLDB_PYTHON_DEFAULT_RELATIVE_PATH} LLDB_PYTHON_DEFAULT_RELATIVE_PATH) + else () + if ("${LLDB_PYTHON_RELATIVE_PATH}" STREQUAL "") + message(FATAL_ERROR + "Crosscompiling LLDB with Python requires manually setting + LLDB_PYTHON_RELATIVE_PATH.") + endif () + endif () - file(TO_CMAKE_PATH ${LLDB_PYTHON_DEFAULT_RELATIVE_PATH} LLDB_PYTHON_DEFAULT_RELATIVE_PATH) set(LLDB_PYTHON_RELATIVE_PATH ${LLDB_PYTHON_DEFAULT_RELATIVE_PATH} CACHE STRING "Path where Python modules are installed, relative to install prefix") endif () @@ -64,7 +60,7 @@ endif () # some of these generated headers. This approach is copied from Clang's main # CMakeLists.txt, so it should kept in sync the code in Clang which was added # in llvm-svn 308844. -if(LLVM_ENABLE_MODULES AND NOT LLDB_BUILT_STANDALONE) +if(LLVM_ENABLE_MODULES) list(APPEND LLVM_COMMON_DEPENDS intrinsics_gen) endif() @@ -88,6 +84,16 @@ add_subdirectory(source) add_subdirectory(tools) add_subdirectory(docs) +if (LLDB_ENABLE_PYTHON) + if(LLDB_BUILD_FRAMEWORK) + set(lldb_python_target_dir "${LLDB_FRAMEWORK_ABSOLUTE_BUILD_DIR}/LLDB.framework/Resources/Python/lldb") + else() + set(lldb_python_target_dir "${CMAKE_BINARY_DIR}/${CMAKE_CFG_INTDIR}/${LLDB_PYTHON_RELATIVE_PATH}/lldb") + endif() + get_target_property(lldb_python_bindings_dir swig_wrapper_python BINARY_DIR) + finish_swig_python("lldb-python" "${lldb_python_bindings_dir}" "${lldb_python_target_dir}") +endif() + option(LLDB_INCLUDE_TESTS "Generate build targets for the LLDB unit tests." ${LLVM_INCLUDE_TESTS}) if(LLDB_INCLUDE_TESTS) add_subdirectory(test) @@ -95,164 +101,6 @@ if(LLDB_INCLUDE_TESTS) add_subdirectory(utils) endif() -if (LLDB_ENABLE_PYTHON) - get_target_property(lldb_bindings_dir swig_wrapper BINARY_DIR) - - if(LLDB_BUILD_FRAMEWORK) - set(lldb_python_build_path "${LLDB_FRAMEWORK_ABSOLUTE_BUILD_DIR}/LLDB.framework/Resources/Python/lldb") - else() - set(lldb_python_build_path "${CMAKE_BINARY_DIR}/${CMAKE_CFG_INTDIR}/${LLDB_PYTHON_RELATIVE_PATH}/lldb") - endif() - - # Add a Post-Build Event to copy over Python files and create the symlink - # to liblldb.so for the Python API(hardlink on Windows). - add_custom_target(finish_swig ALL VERBATIM - COMMAND ${CMAKE_COMMAND} -E make_directory ${lldb_python_build_path} - DEPENDS ${lldb_bindings_dir}/lldb.py - COMMENT "Python script sym-linking LLDB Python API") - - if(NOT LLDB_USE_SYSTEM_SIX) - add_custom_command(TARGET finish_swig POST_BUILD VERBATIM - COMMAND ${CMAKE_COMMAND} -E copy - "${LLDB_SOURCE_DIR}/third_party/Python/module/six/six.py" - "${lldb_python_build_path}/../six.py") - endif() - - add_custom_command(TARGET finish_swig POST_BUILD VERBATIM - COMMAND ${CMAKE_COMMAND} -E copy - "${lldb_bindings_dir}/lldb.py" - "${lldb_python_build_path}/__init__.py") - - function(create_python_package pkg_dir) - cmake_parse_arguments(ARG "NOINIT" "" "FILES" ${ARGN}) - if(ARG_FILES) - set(copy_cmd COMMAND ${CMAKE_COMMAND} -E copy ${ARG_FILES} ${pkg_dir}) - endif() - if(NOT ARG_NOINIT) - set(init_cmd COMMAND ${PYTHON_EXECUTABLE} - "${LLDB_SOURCE_DIR}/bindings/python/createPythonInit.py" - "${pkg_dir}" ${ARG_FILES}) - endif() - add_custom_command(TARGET finish_swig POST_BUILD VERBATIM - COMMAND ${CMAKE_COMMAND} -E make_directory ${pkg_dir} - ${copy_cmd} - ${init_cmd} - WORKING_DIRECTORY ${lldb_python_build_path}) - endfunction() - - add_custom_command(TARGET finish_swig POST_BUILD VERBATIM - COMMAND ${CMAKE_COMMAND} -E copy - "${LLDB_SOURCE_DIR}/source/Interpreter/embedded_interpreter.py" ${lldb_python_build_path}) - - # Distribute the examples as python packages. - create_python_package("formatters/cpp" - FILES "${LLDB_SOURCE_DIR}/examples/synthetic/gnu_libstdcpp.py" - "${LLDB_SOURCE_DIR}/examples/synthetic/libcxx.py") - - create_python_package("formatters" - FILES "${LLDB_SOURCE_DIR}/examples/summaries/cocoa/cache.py" - "${LLDB_SOURCE_DIR}/examples/summaries/synth.py" - "${LLDB_SOURCE_DIR}/examples/summaries/cocoa/metrics.py" - "${LLDB_SOURCE_DIR}/examples/summaries/cocoa/attrib_fromdict.py" - "${LLDB_SOURCE_DIR}/examples/summaries/cocoa/Logger.py") - - create_python_package("utils" - FILES "${LLDB_SOURCE_DIR}/examples/python/in_call_stack.py" - "${LLDB_SOURCE_DIR}/examples/python/symbolication.py") - - if(APPLE) - create_python_package("macosx" - FILES "${LLDB_SOURCE_DIR}/examples/python/crashlog.py" - "${LLDB_SOURCE_DIR}/examples/darwin/heap_find/heap.py") - - create_python_package("macosx/heap" - FILES "${LLDB_SOURCE_DIR}/examples/darwin/heap_find/heap/heap_find.cpp" - "${LLDB_SOURCE_DIR}/examples/darwin/heap_find/heap/Makefile" - NOINIT) - - create_python_package("diagnose" - FILES "${LLDB_SOURCE_DIR}/examples/python/diagnose_unwind.py" - "${LLDB_SOURCE_DIR}/examples/python/diagnose_nsstring.py") - endif() - - function(create_relative_symlink target dest_file output_dir output_name) - get_filename_component(dest_file ${dest_file} ABSOLUTE) - get_filename_component(output_dir ${output_dir} ABSOLUTE) - file(RELATIVE_PATH rel_dest_file ${output_dir} ${dest_file}) - if(CMAKE_HOST_UNIX) - set(LLVM_LINK_OR_COPY create_symlink) - else() - set(LLVM_LINK_OR_COPY copy) - endif() - add_custom_command(TARGET ${target} POST_BUILD VERBATIM - COMMAND ${CMAKE_COMMAND} -E ${LLVM_LINK_OR_COPY} ${rel_dest_file} ${output_name} - WORKING_DIRECTORY ${output_dir}) - endfunction() - - if(LLDB_BUILD_FRAMEWORK) - set(LIBLLDB_SYMLINK_DEST "${LLDB_FRAMEWORK_ABSOLUTE_BUILD_DIR}/LLDB.framework/LLDB") - else() - set(LIBLLDB_SYMLINK_DEST "${LLVM_SHLIB_OUTPUT_INTDIR}/liblldb${CMAKE_SHARED_LIBRARY_SUFFIX}") - endif() - if(WIN32) - if(CMAKE_BUILD_TYPE STREQUAL Debug) - set(LIBLLDB_SYMLINK_OUTPUT_FILE "_lldb_d.pyd") - else() - set(LIBLLDB_SYMLINK_OUTPUT_FILE "_lldb.pyd") - endif() - else() - set(LIBLLDB_SYMLINK_OUTPUT_FILE "_lldb.so") - endif() - create_relative_symlink(finish_swig ${LIBLLDB_SYMLINK_DEST} - ${lldb_python_build_path} ${LIBLLDB_SYMLINK_OUTPUT_FILE}) - - if(NOT LLDB_BUILD_FRAMEWORK) - set(LLDB_ARGDUMPER_FILENAME "lldb-argdumper${CMAKE_EXECUTABLE_SUFFIX}") - create_relative_symlink(finish_swig "${LLVM_RUNTIME_OUTPUT_INTDIR}/${LLDB_ARGDUMPER_FILENAME}" - ${lldb_python_build_path} ${LLDB_ARGDUMPER_FILENAME}) - endif() - - add_dependencies(finish_swig swig_wrapper liblldb lldb-argdumper) - set_target_properties(finish_swig swig_wrapper PROPERTIES FOLDER "lldb misc") - - # Ensure we do the python post-build step when building lldb. - add_dependencies(lldb finish_swig) - - # Install the LLDB python module - if(LLDB_BUILD_FRAMEWORK) - set(LLDB_PYTHON_INSTALL_PATH ${LLDB_FRAMEWORK_INSTALL_DIR}/LLDB.framework/Resources/Python) - else() - set(LLDB_PYTHON_INSTALL_PATH ${LLDB_PYTHON_RELATIVE_PATH}) - endif() - if (NOT CMAKE_CFG_INTDIR STREQUAL ".") - string(REPLACE ${CMAKE_CFG_INTDIR} "\$\{CMAKE_INSTALL_CONFIG_NAME\}" LLDB_PYTHON_INSTALL_PATH ${LLDB_PYTHON_INSTALL_PATH}) - string(REPLACE ${CMAKE_CFG_INTDIR} "\$\{CMAKE_INSTALL_CONFIG_NAME\}" lldb_python_build_path ${lldb_python_build_path}) - endif() - add_custom_target(lldb-python-scripts) - add_dependencies(lldb-python-scripts finish_swig) - install(DIRECTORY ${lldb_python_build_path}/../ - DESTINATION ${LLDB_PYTHON_INSTALL_PATH} - COMPONENT lldb-python-scripts) - if (NOT LLVM_ENABLE_IDE) - add_llvm_install_targets(install-lldb-python-scripts - COMPONENT lldb-python-scripts - DEPENDS lldb-python-scripts) - endif() - - # Add a Post-Build Event to copy the custom Python DLL to the lldb binaries dir so that Windows can find it when launching - # lldb.exe or any other executables that were linked with liblldb. - if (WIN32 AND NOT "${PYTHON_DLL}" STREQUAL "") - # When using the Visual Studio CMake generator the lldb binaries end up in Release/bin, Debug/bin etc. - file(TO_NATIVE_PATH "${CMAKE_BINARY_DIR}/${CMAKE_CFG_INTDIR}/bin" LLDB_BIN_DIR) - file(TO_NATIVE_PATH "${PYTHON_DLL}" PYTHON_DLL_NATIVE_PATH) - add_custom_command( - TARGET finish_swig - POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy ${PYTHON_DLL_NATIVE_PATH} ${LLDB_BIN_DIR} VERBATIM - COMMENT "Copying Python DLL to LLDB binaries directory.") - endif () -endif () - if(LLDB_BUILT_STANDALONE AND NOT LLVM_ENABLE_IDE) llvm_distribution_add_targets() endif() diff --git a/gnu/llvm/lldb/bindings/CMakeLists.txt b/gnu/llvm/lldb/bindings/CMakeLists.txt index a2e51c263f7..9759b069fdc 100644 --- a/gnu/llvm/lldb/bindings/CMakeLists.txt +++ b/gnu/llvm/lldb/bindings/CMakeLists.txt @@ -29,49 +29,12 @@ set(SWIG_COMMON_FLAGS -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS ${DARWIN_EXTRAS} - -outdir ${CMAKE_CURRENT_BINARY_DIR} ) if (LLDB_ENABLE_PYTHON) - add_custom_command( - OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/LLDBWrapPython.cpp - OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/lldb.py - DEPENDS ${SWIG_SOURCES} - DEPENDS ${SWIG_INTERFACES} - DEPENDS ${SWIG_HEADERS} - COMMAND ${SWIG_EXECUTABLE} - ${SWIG_COMMON_FLAGS} - -c++ - -shadow - -python - -threads - -o ${CMAKE_CURRENT_BINARY_DIR}/LLDBWrapPython.cpp - ${LLDB_SOURCE_DIR}/bindings/python.swig - VERBATIM - COMMENT "Building LLDB Python wrapper") - - add_custom_target(swig_wrapper ALL DEPENDS - ${CMAKE_CURRENT_BINARY_DIR}/LLDBWrapPython.cpp - ${CMAKE_CURRENT_BINARY_DIR}/lldb.py - ) + add_subdirectory(python) endif() if (LLDB_ENABLE_LUA) - add_custom_command( - OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/LLDBWrapLua.cpp - DEPENDS ${SWIG_SOURCES} - DEPENDS ${SWIG_INTERFACES} - DEPENDS ${SWIG_HEADERS} - COMMAND ${SWIG_EXECUTABLE} - ${SWIG_COMMON_FLAGS} - -lua - -w503 - -o ${CMAKE_CURRENT_BINARY_DIR}/LLDBWrapLua.cpp - ${LLDB_SOURCE_DIR}/bindings/lua.swig - VERBATIM - COMMENT "Building LLDB Lua wrapper") - - add_custom_target(swig_wrapper_lua ALL DEPENDS - ${CMAKE_CURRENT_BINARY_DIR}/LLDBWrapLua.cpp - ) + add_subdirectory(lua) endif() diff --git a/gnu/llvm/lldb/bindings/headers.swig b/gnu/llvm/lldb/bindings/headers.swig index 6e1668ea4c4..3c2cd85f504 100644 --- a/gnu/llvm/lldb/bindings/headers.swig +++ b/gnu/llvm/lldb/bindings/headers.swig @@ -62,7 +62,6 @@ #include "lldb/API/SBThreadCollection.h" #include "lldb/API/SBThreadPlan.h" #include "lldb/API/SBTrace.h" -#include "lldb/API/SBTraceOptions.h" #include "lldb/API/SBType.h" #include "lldb/API/SBTypeCategory.h" #include "lldb/API/SBTypeEnumMember.h" diff --git a/gnu/llvm/lldb/bindings/interface/SBAddress.i b/gnu/llvm/lldb/bindings/interface/SBAddress.i index 6fd06c83d29..8e95d36e580 100644 --- a/gnu/llvm/lldb/bindings/interface/SBAddress.i +++ b/gnu/llvm/lldb/bindings/interface/SBAddress.i @@ -17,8 +17,9 @@ libraries, bundles, frameworks) being loaded at different addresses than the addresses found in the object file that represents them on disk. There are currently two types of addresses for a section: - o file addresses - o load addresses + +* file addresses +* load addresses File addresses represents the virtual addresses that are in the 'on disk' object files. These virtual addresses are converted to be @@ -108,18 +109,17 @@ public: An address might refer to code or data from an existing module, or it might refer to something on the stack or heap. The following functions will only return valid values if the address has been resolved to a code - or data address using 'void SBAddress::SetLoadAddress(...)' or - 'lldb::SBAddress SBTarget::ResolveLoadAddress (...)'.") GetSymbolContext; + or data address using :py:class:`SBAddress.SetLoadAddress' or + :py:class:`SBTarget.ResolveLoadAddress`.") GetSymbolContext; lldb::SBSymbolContext GetSymbolContext (uint32_t resolve_scope); %feature("docstring", " GetModule() and the following grab individual objects for a given address and are less efficient if you want more than one symbol related objects. - Use one of the following when you want multiple debug symbol related - objects for an address: - lldb::SBSymbolContext SBAddress::GetSymbolContext (uint32_t resolve_scope); - lldb::SBSymbolContext SBTarget::ResolveSymbolContextForAddress (const SBAddress &addr, uint32_t resolve_scope); + Use :py:class:`SBAddress.GetSymbolContext` or + :py:class:`SBTarget.ResolveSymbolContextForAddress` when you want multiple + debug symbol related objects for an address. One or more bits from the SymbolContextItem enumerations can be logically OR'ed together to more efficiently retrieve multiple symbol objects.") GetModule; lldb::SBModule diff --git a/gnu/llvm/lldb/bindings/interface/SBAttachInfo.i b/gnu/llvm/lldb/bindings/interface/SBAttachInfo.i index 3f4634e1461..9ac96e6dd7b 100644 --- a/gnu/llvm/lldb/bindings/interface/SBAttachInfo.i +++ b/gnu/llvm/lldb/bindings/interface/SBAttachInfo.i @@ -7,7 +7,9 @@ //===----------------------------------------------------------------------===// namespace lldb { - +%feature("docstring", +"Describes how to attach when calling :py:class:`SBTarget.Attach`." +) SBAttachInfo; class SBAttachInfo { public: diff --git a/gnu/llvm/lldb/bindings/interface/SBBlock.i b/gnu/llvm/lldb/bindings/interface/SBBlock.i index 812b41fe5c3..3972b939b18 100644 --- a/gnu/llvm/lldb/bindings/interface/SBBlock.i +++ b/gnu/llvm/lldb/bindings/interface/SBBlock.i @@ -22,7 +22,7 @@ public: ~SBBlock (); %feature("docstring", - "Does this block represent an inlined function?" + "Is this block contained within an inlined function?" ) IsInlined; bool IsInlined () const; diff --git a/gnu/llvm/lldb/bindings/interface/SBBreakpoint.i b/gnu/llvm/lldb/bindings/interface/SBBreakpoint.i index a2d747db0bf..a7048309edd 100644 --- a/gnu/llvm/lldb/bindings/interface/SBBreakpoint.i +++ b/gnu/llvm/lldb/bindings/interface/SBBreakpoint.i @@ -11,7 +11,7 @@ namespace lldb { "Represents a logical breakpoint and its associated settings. For example (from test/functionalities/breakpoint/breakpoint_ignore_count/ -TestBreakpointIgnoreCount.py), +TestBreakpointIgnoreCount.py),:: def breakpoint_ignore_count_python(self): '''Use Python APIs to set breakpoint ignore count.''' @@ -62,13 +62,13 @@ TestBreakpointIgnoreCount.py), process.Continue() -SBBreakpoint supports breakpoint location iteration, for example, +SBBreakpoint supports breakpoint location iteration, for example,:: for bl in breakpoint: print('breakpoint location load addr: %s' % hex(bl.GetLoadAddress())) print('breakpoint location condition: %s' % hex(bl.GetCondition())) -and rich comparison methods which allow the API program to use, +and rich comparison methods which allow the API program to use,:: if aBreakpoint == bBreakpoint: ... @@ -100,6 +100,9 @@ public: void ClearAllBreakpointSites (); + lldb::SBTarget + GetTarget() const; + lldb::SBBreakpointLocation FindLocationByAddress (lldb::addr_t vm_addr); @@ -181,7 +184,7 @@ public: %feature("docstring", " Set the name of the script function to be called when the breakpoint is hit. - To use this variant, the function should take (frame, bp_loc, extra_args, dict) and + To use this variant, the function should take (frame, bp_loc, extra_args, internal_dict) and when the breakpoint is hit the extra_args will be passed to the callback function.") SetScriptCallbackFunction; SBError SetScriptCallbackFunction (const char *callback_function_name, @@ -234,6 +237,8 @@ public: SBError AddLocation(SBAddress &address); + SBStructuredData SBBreakpoint::SerializeToStructuredData(); + static bool EventIsBreakpointEvent (const lldb::SBEvent &event); @@ -308,6 +313,10 @@ public: class SBBreakpointListImpl; + +%feature("docstring", +"Represents a list of :py:class:`SBBreakpoint`." +) SBBreakpointList; class LLDB_API SBBreakpointList { public: diff --git a/gnu/llvm/lldb/bindings/interface/SBBreakpointLocation.i b/gnu/llvm/lldb/bindings/interface/SBBreakpointLocation.i index dc39c83c2d6..354737b98c6 100644 --- a/gnu/llvm/lldb/bindings/interface/SBBreakpointLocation.i +++ b/gnu/llvm/lldb/bindings/interface/SBBreakpointLocation.i @@ -15,7 +15,7 @@ A breakpoint location is defined by the breakpoint that produces it, and the address that resulted in this particular instantiation. Each breakpoint location has its settable options. -SBBreakpoint contains SBBreakpointLocation(s). See docstring of SBBreakpoint +:py:class:`SBBreakpoint` contains SBBreakpointLocation(s). See docstring of SBBreakpoint for retrieval of an SBBreakpointLocation from an SBBreakpoint." ) SBBreakpointLocation; class SBBreakpointLocation @@ -74,13 +74,13 @@ public: %feature("docstring", " Set the callback to the given Python function name. - The function takes three arguments (frame, bp_loc, dict).") SetScriptCallbackFunction; + The function takes three arguments (frame, bp_loc, internal_dict).") SetScriptCallbackFunction; void SetScriptCallbackFunction (const char *callback_function_name); %feature("docstring", " Set the name of the script function to be called when the breakpoint is hit. - To use this variant, the function should take (frame, bp_loc, extra_args, dict) and + To use this variant, the function should take (frame, bp_loc, extra_args, internal_dict) and when the breakpoint is hit the extra_args will be passed to the callback function.") SetScriptCallbackFunction; SBError SetScriptCallbackFunction (const char *callback_function_name, diff --git a/gnu/llvm/lldb/bindings/interface/SBBreakpointName.i b/gnu/llvm/lldb/bindings/interface/SBBreakpointName.i index e280d422459..c0fdcc74898 100644 --- a/gnu/llvm/lldb/bindings/interface/SBBreakpointName.i +++ b/gnu/llvm/lldb/bindings/interface/SBBreakpointName.i @@ -8,12 +8,12 @@ namespace lldb { %feature("docstring", -"Represents a breakpoint name registered in a given SBTarget. +"Represents a breakpoint name registered in a given :py:class:`SBTarget`. Breakpoint names provide a way to act on groups of breakpoints. When you add a name to a group of breakpoints, you can then use the name in all the command line lldb commands for that name. You can also configure the SBBreakpointName -options and those options will be propagated to any SBBreakpoints currently +options and those options will be propagated to any :py:class:`SBBreakpoint` s currently using that name. Adding a name to a breakpoint will also apply any of the set options to that breakpoint. diff --git a/gnu/llvm/lldb/bindings/interface/SBBroadcaster.i b/gnu/llvm/lldb/bindings/interface/SBBroadcaster.i index 79100e171b4..e97d8f964bd 100644 --- a/gnu/llvm/lldb/bindings/interface/SBBroadcaster.i +++ b/gnu/llvm/lldb/bindings/interface/SBBroadcaster.i @@ -9,9 +9,11 @@ namespace lldb { %feature("docstring", -"Represents an entity which can broadcast events. A default broadcaster is +"Represents an entity which can broadcast events. + +A default broadcaster is associated with an SBCommandInterpreter, SBProcess, and SBTarget. For -example, use +example, use :: broadcaster = process.GetBroadcaster() diff --git a/gnu/llvm/lldb/bindings/interface/SBCommandInterpreter.i b/gnu/llvm/lldb/bindings/interface/SBCommandInterpreter.i index 498084ae3ab..b9a32716cfd 100644 --- a/gnu/llvm/lldb/bindings/interface/SBCommandInterpreter.i +++ b/gnu/llvm/lldb/bindings/interface/SBCommandInterpreter.i @@ -9,9 +9,11 @@ namespace lldb { %feature("docstring", -"SBCommandInterpreter handles/interprets commands for lldb. You get the -command interpreter from the SBDebugger instance. For example (from test/ -python_api/interpreter/TestCommandInterpreterAPI.py), +"SBCommandInterpreter handles/interprets commands for lldb. + +You get the command interpreter from the :py:class:`SBDebugger` instance. + +For example (from test/ python_api/interpreter/TestCommandInterpreterAPI.py),:: def command_interpreter_api(self): '''Test the SBCommandInterpreter APIs.''' diff --git a/gnu/llvm/lldb/bindings/interface/SBCommandInterpreterRunOptions.i b/gnu/llvm/lldb/bindings/interface/SBCommandInterpreterRunOptions.i index f9ccbbd24db..28437abb60c 100644 --- a/gnu/llvm/lldb/bindings/interface/SBCommandInterpreterRunOptions.i +++ b/gnu/llvm/lldb/bindings/interface/SBCommandInterpreterRunOptions.i @@ -10,13 +10,16 @@ namespace lldb { %feature("docstring", "SBCommandInterpreterRunOptions controls how the RunCommandInterpreter runs the code it is fed. + A default SBCommandInterpreterRunOptions object has: - StopOnContinue: false - StopOnError: false - StopOnCrash: false - EchoCommands: true - PrintResults: true - AddToHistory: true + +* StopOnContinue: false +* StopOnError: false +* StopOnCrash: false +* EchoCommands: true +* PrintResults: true +* PrintErrors: true +* AddToHistory: true ") SBCommandInterpreterRunOptions; class SBCommandInterpreterRunOptions @@ -56,6 +59,12 @@ public: void SetPrintResults (bool); + bool + GetPrintErrors () const; + + void + SetPrintErrors (bool); + bool GetAddToHistory () const; diff --git a/gnu/llvm/lldb/bindings/interface/SBCommandReturnObject.i b/gnu/llvm/lldb/bindings/interface/SBCommandReturnObject.i index affa16520f2..b07ef1c5eb1 100644 --- a/gnu/llvm/lldb/bindings/interface/SBCommandReturnObject.i +++ b/gnu/llvm/lldb/bindings/interface/SBCommandReturnObject.i @@ -10,10 +10,10 @@ namespace lldb { %feature("docstring", "Represents a container which holds the result from command execution. -It works with SBCommandInterpreter.HandleCommand() to encapsulate the result +It works with :py:class:`SBCommandInterpreter.HandleCommand()` to encapsulate the result of command execution. -See SBCommandInterpreter for example usage of SBCommandReturnObject." +See :py:class:`SBCommandInterpreter` for example usage of SBCommandReturnObject." ) SBCommandReturnObject; class SBCommandReturnObject { diff --git a/gnu/llvm/lldb/bindings/interface/SBCommunication.i b/gnu/llvm/lldb/bindings/interface/SBCommunication.i index 87d3d0c9c5e..8611e83e92a 100644 --- a/gnu/llvm/lldb/bindings/interface/SBCommunication.i +++ b/gnu/llvm/lldb/bindings/interface/SBCommunication.i @@ -8,6 +8,9 @@ namespace lldb { +%feature("docstring", +"Allows sending/receiving data." +) SBCommunication; class SBCommunication { public: diff --git a/gnu/llvm/lldb/bindings/interface/SBCompileUnit.i b/gnu/llvm/lldb/bindings/interface/SBCompileUnit.i index d6a4c07038c..4c8efaedb7d 100644 --- a/gnu/llvm/lldb/bindings/interface/SBCompileUnit.i +++ b/gnu/llvm/lldb/bindings/interface/SBCompileUnit.i @@ -11,7 +11,7 @@ namespace lldb { %feature("docstring", "Represents a compilation unit, or compiled source file. -SBCompileUnit supports line entry iteration. For example, +SBCompileUnit supports line entry iteration. For example,:: # Now get the SBSymbolContext from this frame. We want everything. :-) context = frame0.GetSymbolContext(lldb.eSymbolContextEverything) @@ -25,23 +25,23 @@ SBCompileUnit supports line entry iteration. For example, print('start addr: %s' % str(lineEntry.GetStartAddress())) print('end addr: %s' % str(lineEntry.GetEndAddress())) -produces: - -line entry: /Volumes/data/lldb/svn/trunk/test/python_api/symbol-context/main.c:20 -start addr: a.out[0x100000d98] -end addr: a.out[0x100000da3] -line entry: /Volumes/data/lldb/svn/trunk/test/python_api/symbol-context/main.c:21 -start addr: a.out[0x100000da3] -end addr: a.out[0x100000da9] -line entry: /Volumes/data/lldb/svn/trunk/test/python_api/symbol-context/main.c:22 -start addr: a.out[0x100000da9] -end addr: a.out[0x100000db6] -line entry: /Volumes/data/lldb/svn/trunk/test/python_api/symbol-context/main.c:23 -start addr: a.out[0x100000db6] -end addr: a.out[0x100000dbc] -... - -See also SBSymbolContext and SBLineEntry" +produces: :: + + line entry: /Volumes/data/lldb/svn/trunk/test/python_api/symbol-context/main.c:20 + start addr: a.out[0x100000d98] + end addr: a.out[0x100000da3] + line entry: /Volumes/data/lldb/svn/trunk/test/python_api/symbol-context/main.c:21 + start addr: a.out[0x100000da3] + end addr: a.out[0x100000da9] + line entry: /Volumes/data/lldb/svn/trunk/test/python_api/symbol-context/main.c:22 + start addr: a.out[0x100000da9] + end addr: a.out[0x100000db6] + line entry: /Volumes/data/lldb/svn/trunk/test/python_api/symbol-context/main.c:23 + start addr: a.out[0x100000db6] + end addr: a.out[0x100000dbc] + ... + +See also :py:class:`SBSymbolContext` and :py:class:`SBLineEntry`" ) SBCompileUnit; class SBCompileUnit { diff --git a/gnu/llvm/lldb/bindings/interface/SBData.i b/gnu/llvm/lldb/bindings/interface/SBData.i index 3e74240329e..a1fb4472cd2 100644 --- a/gnu/llvm/lldb/bindings/interface/SBData.i +++ b/gnu/llvm/lldb/bindings/interface/SBData.i @@ -9,6 +9,9 @@ namespace lldb { +%feature("docstring", +"Represents a data buffer." +) SBData; class SBData { public: diff --git a/gnu/llvm/lldb/bindings/interface/SBDebugger.i b/gnu/llvm/lldb/bindings/interface/SBDebugger.i index f2e23a7ed78..cf4411980cc 100644 --- a/gnu/llvm/lldb/bindings/interface/SBDebugger.i +++ b/gnu/llvm/lldb/bindings/interface/SBDebugger.i @@ -12,108 +12,108 @@ namespace lldb { "SBDebugger is the primordial object that creates SBTargets and provides access to them. It also manages the overall debugging experiences. -For example (from example/disasm.py), - -import lldb -import os -import sys - -def disassemble_instructions (insts): - for i in insts: - print i - -... - -# Create a new debugger instance -debugger = lldb.SBDebugger.Create() - -# When we step or continue, don't return from the function until the process -# stops. We do this by setting the async mode to false. -debugger.SetAsync (False) - -# Create a target from a file and arch -print('Creating a target for \'%s\'' % exe) - -target = debugger.CreateTargetWithFileAndArch (exe, lldb.LLDB_ARCH_DEFAULT) - -if target: - # If the target is valid set a breakpoint at main - main_bp = target.BreakpointCreateByName (fname, target.GetExecutable().GetFilename()); - - print main_bp - - # Launch the process. Since we specified synchronous mode, we won't return - # from this function until we hit the breakpoint at main - process = target.LaunchSimple (None, None, os.getcwd()) - - # Make sure the launch went ok - if process: - # Print some simple process info - state = process.GetState () - print process - if state == lldb.eStateStopped: - # Get the first thread - thread = process.GetThreadAtIndex (0) - if thread: - # Print some simple thread info - print thread - # Get the first frame - frame = thread.GetFrameAtIndex (0) - if frame: - # Print some simple frame info - print frame - function = frame.GetFunction() - # See if we have debug info (a function) - if function: - # We do have a function, print some info for the function - print function - # Now get all instructions for this function and print them - insts = function.GetInstructions(target) - disassemble_instructions (insts) - else: - # See if we have a symbol in the symbol table for where we stopped - symbol = frame.GetSymbol(); - if symbol: - # We do have a symbol, print some info for the symbol - print symbol - # Now get all instructions for this symbol and print them - insts = symbol.GetInstructions(target) +For example (from example/disasm.py),:: + + import lldb + import os + import sys + + def disassemble_instructions (insts): + for i in insts: + print i + + ... + + # Create a new debugger instance + debugger = lldb.SBDebugger.Create() + + # When we step or continue, don't return from the function until the process + # stops. We do this by setting the async mode to false. + debugger.SetAsync (False) + + # Create a target from a file and arch + print('Creating a target for \'%s\'' % exe) + + target = debugger.CreateTargetWithFileAndArch (exe, lldb.LLDB_ARCH_DEFAULT) + + if target: + # If the target is valid set a breakpoint at main + main_bp = target.BreakpointCreateByName (fname, target.GetExecutable().GetFilename()); + + print main_bp + + # Launch the process. Since we specified synchronous mode, we won't return + # from this function until we hit the breakpoint at main + process = target.LaunchSimple (None, None, os.getcwd()) + + # Make sure the launch went ok + if process: + # Print some simple process info + state = process.GetState () + print process + if state == lldb.eStateStopped: + # Get the first thread + thread = process.GetThreadAtIndex (0) + if thread: + # Print some simple thread info + print thread + # Get the first frame + frame = thread.GetFrameAtIndex (0) + if frame: + # Print some simple frame info + print frame + function = frame.GetFunction() + # See if we have debug info (a function) + if function: + # We do have a function, print some info for the function + print function + # Now get all instructions for this function and print them + insts = function.GetInstructions(target) disassemble_instructions (insts) - - registerList = frame.GetRegisters() - print('Frame registers (size of register set = %d):' % registerList.GetSize()) - for value in registerList: - #print value - print('%s (number of children = %d):' % (value.GetName(), value.GetNumChildren())) - for child in value: - print('Name: ', child.GetName(), ' Value: ', child.GetValue()) - - print('Hit the breakpoint at main, enter to continue and wait for program to exit or \'Ctrl-D\'/\'quit\' to terminate the program') - next = sys.stdin.readline() - if not next or next.rstrip('\n') == 'quit': - print('Terminating the inferior process...') - process.Kill() + else: + # See if we have a symbol in the symbol table for where we stopped + symbol = frame.GetSymbol(); + if symbol: + # We do have a symbol, print some info for the symbol + print symbol + # Now get all instructions for this symbol and print them + insts = symbol.GetInstructions(target) + disassemble_instructions (insts) + + registerList = frame.GetRegisters() + print('Frame registers (size of register set = %d):' % registerList.GetSize()) + for value in registerList: + #print value + print('%s (number of children = %d):' % (value.GetName(), value.GetNumChildren())) + for child in value: + print('Name: ', child.GetName(), ' Value: ', child.GetValue()) + + print('Hit the breakpoint at main, enter to continue and wait for program to exit or \'Ctrl-D\'/\'quit\' to terminate the program') + next = sys.stdin.readline() + if not next or next.rstrip('\\n') == 'quit': + print('Terminating the inferior process...') + process.Kill() + else: + # Now continue to the program exit + process.Continue() + # When we return from the above function we will hopefully be at the + # program exit. Print out some process info + print process + elif state == lldb.eStateExited: + print('Didn\'t hit the breakpoint at main, program has exited...') else: - # Now continue to the program exit - process.Continue() - # When we return from the above function we will hopefully be at the - # program exit. Print out some process info - print process - elif state == lldb.eStateExited: - print('Didn\'t hit the breakpoint at main, program has exited...') - else: - print('Unexpected process state: %s, killing process...' % debugger.StateAsCString (state)) - process.Kill() + print('Unexpected process state: %s, killing process...' % debugger.StateAsCString (state)) + process.Kill() Sometimes you need to create an empty target that will get filled in later. The most common use for this is to attach to a process by name or pid where you don't know the executable up front. The most convenient way -to do this is: +to do this is: :: -target = debugger.CreateTarget('') -error = lldb.SBError() -process = target.AttachToProcessWithName(debugger.GetListener(), 'PROCESS_NAME', False, error) + target = debugger.CreateTarget('') + error = lldb.SBError() + process = target.AttachToProcessWithName(debugger.GetListener(), 'PROCESS_NAME', False, error) -or the equivalent arguments for AttachToProcessWithID.") SBDebugger; +or the equivalent arguments for :py:class:`SBTarget.AttachToProcessWithID` .") SBDebugger; class SBDebugger { public: @@ -498,12 +498,12 @@ A tuple with the number of errors encountered by the interpreter, a boolean indicating whether quitting the interpreter was requested and another boolean set to True in case of a crash. -Example: +Example: :: -# Start an interactive lldb session from a script (with a valid debugger object -# created beforehand): -n_errors, quit_requested, has_crashed = debugger.RunCommandInterpreter(True, - False, lldb.SBCommandInterpreterRunOptions(), 0, False, False)") RunCommandInterpreter; + # Start an interactive lldb session from a script (with a valid debugger object + # created beforehand): + n_errors, quit_requested, has_crashed = debugger.RunCommandInterpreter(True, + False, lldb.SBCommandInterpreterRunOptions(), 0, False, False)") RunCommandInterpreter; %apply int& INOUT { int& num_errors }; %apply bool& INOUT { bool& quit_requested }; %apply bool& INOUT { bool& stopped_for_crash }; diff --git a/gnu/llvm/lldb/bindings/interface/SBEnvironment.i b/gnu/llvm/lldb/bindings/interface/SBEnvironment.i index 4ca22fc314d..daf25bc26d9 100644 --- a/gnu/llvm/lldb/bindings/interface/SBEnvironment.i +++ b/gnu/llvm/lldb/bindings/interface/SBEnvironment.i @@ -11,7 +11,8 @@ namespace lldb { %feature("docstring", "Represents the environment of a certain process. -Example: +Example: :: + for entry in lldb.debugger.GetSelectedTarget().GetEnvironment().GetEntries(): print(entry) diff --git a/gnu/llvm/lldb/bindings/interface/SBError.i b/gnu/llvm/lldb/bindings/interface/SBError.i index ea48e2263a7..5af6b4856bd 100644 --- a/gnu/llvm/lldb/bindings/interface/SBError.i +++ b/gnu/llvm/lldb/bindings/interface/SBError.i @@ -11,7 +11,7 @@ namespace lldb { %feature("docstring", "Represents a container for holding any error code. -For example (from test/python_api/hello_world/TestHelloWorld.py), +For example (from test/python_api/hello_world/TestHelloWorld.py), :: def hello_world_attach_with_id_api(self): '''Create target, spawn a process, and attach to it by id.''' @@ -45,7 +45,7 @@ For example (from test/python_api/hello_world/TestHelloWorld.py), checks that after the attach, there is no error condition by asserting that error.Success() is True and we get back a valid process object. -And (from test/python_api/event/TestEvent.py), +And (from test/python_api/event/TestEvent.py), :: # Now launch the process, and do not stop at entry point. error = lldb.SBError() diff --git a/gnu/llvm/lldb/bindings/interface/SBEvent.i b/gnu/llvm/lldb/bindings/interface/SBEvent.i index 99aa5319e37..2ebf599eb89 100644 --- a/gnu/llvm/lldb/bindings/interface/SBEvent.i +++ b/gnu/llvm/lldb/bindings/interface/SBEvent.i @@ -13,27 +13,27 @@ class SBBroadcaster; %feature("docstring", "API clients can register to receive events. -For example, check out the following output: +For example, check out the following output: :: -Try wait for event... -Event description: 0x103d0bb70 Event: broadcaster = 0x1009c8410, type = 0x00000001, data = { process = 0x1009c8400 (pid = 21528), state = running} -Event data flavor: Process::ProcessEventData -Process state: running + Try wait for event... + Event description: 0x103d0bb70 Event: broadcaster = 0x1009c8410, type = 0x00000001, data = { process = 0x1009c8400 (pid = 21528), state = running} + Event data flavor: Process::ProcessEventData + Process state: running -Try wait for event... -Event description: 0x103a700a0 Event: broadcaster = 0x1009c8410, type = 0x00000001, data = { process = 0x1009c8400 (pid = 21528), state = stopped} -Event data flavor: Process::ProcessEventData -Process state: stopped + Try wait for event... + Event description: 0x103a700a0 Event: broadcaster = 0x1009c8410, type = 0x00000001, data = { process = 0x1009c8400 (pid = 21528), state = stopped} + Event data flavor: Process::ProcessEventData + Process state: stopped -Try wait for event... -Event description: 0x103d0d4a0 Event: broadcaster = 0x1009c8410, type = 0x00000001, data = { process = 0x1009c8400 (pid = 21528), state = exited} -Event data flavor: Process::ProcessEventData -Process state: exited + Try wait for event... + Event description: 0x103d0d4a0 Event: broadcaster = 0x1009c8410, type = 0x00000001, data = { process = 0x1009c8400 (pid = 21528), state = exited} + Event data flavor: Process::ProcessEventData + Process state: exited -Try wait for event... -timeout occurred waiting for event... + Try wait for event... + timeout occurred waiting for event... -from test/python_api/event/TestEventspy: +from test/python_api/event/TestEventspy: :: def do_listen_for_and_print_event(self): '''Create a listener and use SBEvent API to print the events received.''' diff --git a/gnu/llvm/lldb/bindings/interface/SBExecutionContext.i b/gnu/llvm/lldb/bindings/interface/SBExecutionContext.i index 46968d04ae3..5fc5c057118 100644 --- a/gnu/llvm/lldb/bindings/interface/SBExecutionContext.i +++ b/gnu/llvm/lldb/bindings/interface/SBExecutionContext.i @@ -8,6 +8,9 @@ namespace lldb { +%feature("docstring", +"Describes the program context in which a command should be executed." +) SBExecutionContext; class SBExecutionContext { public: diff --git a/gnu/llvm/lldb/bindings/interface/SBFile.i b/gnu/llvm/lldb/bindings/interface/SBFile.i index c86c5f26f14..4a2f58e0e78 100644 --- a/gnu/llvm/lldb/bindings/interface/SBFile.i +++ b/gnu/llvm/lldb/bindings/interface/SBFile.i @@ -93,7 +93,7 @@ public: If there is no underlying python file to unwrap, GetFile will use the file descriptor, if available to create a new python - file object using `open(fd, mode=..., closefd=False)` + file object using ``open(fd, mode=..., closefd=False)`` "); FileSP GetFile(); }; diff --git a/gnu/llvm/lldb/bindings/interface/SBFileSpec.i b/gnu/llvm/lldb/bindings/interface/SBFileSpec.i index d287a940c05..b549321487e 100644 --- a/gnu/llvm/lldb/bindings/interface/SBFileSpec.i +++ b/gnu/llvm/lldb/bindings/interface/SBFileSpec.i @@ -13,7 +13,7 @@ namespace lldb { basename. The string values of the paths are put into uniqued string pools for fast comparisons and efficient memory usage. -For example, the following code +For example, the following code :: lineEntry = context.GetLineEntry() self.expect(lineEntry.GetFileSpec().GetDirectory(), 'The line entry should have the correct directory', diff --git a/gnu/llvm/lldb/bindings/interface/SBFileSpecList.i b/gnu/llvm/lldb/bindings/interface/SBFileSpecList.i index 96641613f45..384dd4c4ae0 100644 --- a/gnu/llvm/lldb/bindings/interface/SBFileSpecList.i +++ b/gnu/llvm/lldb/bindings/interface/SBFileSpecList.i @@ -8,6 +8,9 @@ namespace lldb { +%feature("docstring", +"Represents a list of :py:class:`SBFileSpec`." +) SBFileSpecList; class SBFileSpecList { public: diff --git a/gnu/llvm/lldb/bindings/interface/SBFrame.i b/gnu/llvm/lldb/bindings/interface/SBFrame.i index c65b88f863e..7bbf63c713f 100644 --- a/gnu/llvm/lldb/bindings/interface/SBFrame.i +++ b/gnu/llvm/lldb/bindings/interface/SBFrame.i @@ -10,34 +10,35 @@ namespace lldb { %feature("docstring", "Represents one of the stack frames associated with a thread. -SBThread contains SBFrame(s). For example (from test/lldbutil.py), -def print_stacktrace(thread, string_buffer = False): - '''Prints a simple stack trace of this thread.''' +SBThread contains SBFrame(s). For example (from test/lldbutil.py), :: - ... + def print_stacktrace(thread, string_buffer = False): + '''Prints a simple stack trace of this thread.''' - for i in range(depth): - frame = thread.GetFrameAtIndex(i) - function = frame.GetFunction() + ... - load_addr = addrs[i].GetLoadAddress(target) - if not function: - file_addr = addrs[i].GetFileAddress() - start_addr = frame.GetSymbol().GetStartAddress().GetFileAddress() - symbol_offset = file_addr - start_addr - print >> output, ' frame #{num}: {addr:#016x} {mod}`{symbol} + {offset}'.format( - num=i, addr=load_addr, mod=mods[i], symbol=symbols[i], offset=symbol_offset) - else: - print >> output, ' frame #{num}: {addr:#016x} {mod}`{func} at {file}:{line} {args}'.format( - num=i, addr=load_addr, mod=mods[i], - func='%s [inlined]' % funcs[i] if frame.IsInlined() else funcs[i], - file=files[i], line=lines[i], - args=get_args_as_string(frame, showFuncName=False) if not frame.IsInlined() else '()') + for i in range(depth): + frame = thread.GetFrameAtIndex(i) + function = frame.GetFunction() - ... + load_addr = addrs[i].GetLoadAddress(target) + if not function: + file_addr = addrs[i].GetFileAddress() + start_addr = frame.GetSymbol().GetStartAddress().GetFileAddress() + symbol_offset = file_addr - start_addr + print >> output, ' frame #{num}: {addr:#016x} {mod}`{symbol} + {offset}'.format( + num=i, addr=load_addr, mod=mods[i], symbol=symbols[i], offset=symbol_offset) + else: + print >> output, ' frame #{num}: {addr:#016x} {mod}`{func} at {file}:{line} {args}'.format( + num=i, addr=load_addr, mod=mods[i], + func='%s [inlined]' % funcs[i] if frame.IsInlined() else funcs[i], + file=files[i], line=lines[i], + args=get_args_as_string(frame, showFuncName=False) if not frame.IsInlined() else '()') + + ... -And, +And, :: for frame in thread: print frame @@ -246,20 +247,27 @@ public: %feature("docstring", " Get a lldb.SBValue for a variable path. - Variable paths can include access to pointer or instance members: + Variable paths can include access to pointer or instance members: :: + rect_ptr->origin.y pt.x - Pointer dereferences: + + Pointer dereferences: :: + *this->foo_ptr **argv - Address of: + + Address of: :: + &pt &my_array[3].x - Array accesses and treating pointers as arrays: + + Array accesses and treating pointers as arrays: :: + int_array[1] pt_ptr[22].x - Unlike EvaluateExpression() which returns lldb.SBValue objects + Unlike `EvaluateExpression()` which returns :py:class:`SBValue` objects with constant copies of the values at the time of evaluation, the result of this function is a value that will continue to track the current value of the value as execution progresses @@ -274,7 +282,7 @@ public: Find variables, register sets, registers, or persistent variables using the frame as the scope. - The version that doesn't supply a 'use_dynamic' value will use the + The version that doesn't supply a ``use_dynamic`` value will use the target's default.") FindValue; lldb::SBValue FindValue (const char *name, ValueType value_type); diff --git a/gnu/llvm/lldb/bindings/interface/SBFunction.i b/gnu/llvm/lldb/bindings/interface/SBFunction.i index 630c4db22c5..dec073e9e12 100644 --- a/gnu/llvm/lldb/bindings/interface/SBFunction.i +++ b/gnu/llvm/lldb/bindings/interface/SBFunction.i @@ -11,7 +11,7 @@ namespace lldb { %feature("docstring", "Represents a generic function, which can be inlined or not. -For example (from test/lldbutil.py, but slightly modified for doc purpose), +For example (from test/lldbutil.py, but slightly modified for doc purpose),:: ... diff --git a/gnu/llvm/lldb/bindings/interface/SBHostOS.i b/gnu/llvm/lldb/bindings/interface/SBHostOS.i index 14f4186cb9f..791fa5a2085 100644 --- a/gnu/llvm/lldb/bindings/interface/SBHostOS.i +++ b/gnu/llvm/lldb/bindings/interface/SBHostOS.i @@ -8,6 +8,9 @@ namespace lldb { +%feature("docstring", +"Provides information about the host system." +) SBHostOS; class SBHostOS { public: diff --git a/gnu/llvm/lldb/bindings/interface/SBInstruction.i b/gnu/llvm/lldb/bindings/interface/SBInstruction.i index d50a080fd04..e9e018b7dee 100644 --- a/gnu/llvm/lldb/bindings/interface/SBInstruction.i +++ b/gnu/llvm/lldb/bindings/interface/SBInstruction.i @@ -13,6 +13,9 @@ namespace lldb { +%feature("docstring", +"Represents a (machine language) instruction." +) SBInstruction; class SBInstruction { public: diff --git a/gnu/llvm/lldb/bindings/interface/SBInstructionList.i b/gnu/llvm/lldb/bindings/interface/SBInstructionList.i index 13573230275..b51c0374c3a 100644 --- a/gnu/llvm/lldb/bindings/interface/SBInstructionList.i +++ b/gnu/llvm/lldb/bindings/interface/SBInstructionList.i @@ -14,12 +14,12 @@ namespace lldb { "Represents a list of machine instructions. SBFunction and SBSymbol have GetInstructions() methods which return SBInstructionList instances. -SBInstructionList supports instruction (SBInstruction instance) iteration. -For example (see also SBDebugger for a more complete example), +SBInstructionList supports instruction (:py:class:`SBInstruction` instance) iteration. +For example (see also :py:class:`SBDebugger` for a more complete example), :: -def disassemble_instructions (insts): - for i in insts: - print i + def disassemble_instructions (insts): + for i in insts: + print i defines a function which takes an SBInstructionList instance and prints out the machine instructions in assembly format." diff --git a/gnu/llvm/lldb/bindings/interface/SBLanguageRuntime.i b/gnu/llvm/lldb/bindings/interface/SBLanguageRuntime.i index f28170b9ce7..d8698ee36c0 100644 --- a/gnu/llvm/lldb/bindings/interface/SBLanguageRuntime.i +++ b/gnu/llvm/lldb/bindings/interface/SBLanguageRuntime.i @@ -8,6 +8,9 @@ namespace lldb { +%feature("docstring", +"Utility functions for :ref:`LanguageType`" +) SBLanguageRuntime; class SBLanguageRuntime { public: diff --git a/gnu/llvm/lldb/bindings/interface/SBLaunchInfo.i b/gnu/llvm/lldb/bindings/interface/SBLaunchInfo.i index 1de89b58b27..535ed3b7906 100644 --- a/gnu/llvm/lldb/bindings/interface/SBLaunchInfo.i +++ b/gnu/llvm/lldb/bindings/interface/SBLaunchInfo.i @@ -8,6 +8,9 @@ namespace lldb { +%feature("docstring", +"Describes how a target or program should be launched." +) SBLaunchInfo; class SBLaunchInfo { public: @@ -132,6 +135,16 @@ public: void SetDetachOnError(bool enable); + + const char * + GetScriptedProcessClassName() const; + + void SetScriptedProcessClassName(const char *class_name); + + lldb::SBStructuredData + GetScriptedProcessDictionary() const; + + void SetScriptedProcessDictionary(lldb::SBStructuredData dict); }; } // namespace lldb diff --git a/gnu/llvm/lldb/bindings/interface/SBLineEntry.i b/gnu/llvm/lldb/bindings/interface/SBLineEntry.i index be365377ba8..24f25ed1b4e 100644 --- a/gnu/llvm/lldb/bindings/interface/SBLineEntry.i +++ b/gnu/llvm/lldb/bindings/interface/SBLineEntry.i @@ -10,7 +10,9 @@ namespace lldb { %feature("docstring", "Specifies an association with a contiguous range of instructions and -a source file location. SBCompileUnit contains SBLineEntry(s). For example, +a source file location. + +:py:class:`SBCompileUnit` contains SBLineEntry(s). For example, :: for lineEntry in compileUnit: print('line entry: %s:%d' % (str(lineEntry.GetFileSpec()), @@ -18,23 +20,23 @@ a source file location. SBCompileUnit contains SBLineEntry(s). For example, print('start addr: %s' % str(lineEntry.GetStartAddress())) print('end addr: %s' % str(lineEntry.GetEndAddress())) -produces: - -line entry: /Volumes/data/lldb/svn/trunk/test/python_api/symbol-context/main.c:20 -start addr: a.out[0x100000d98] -end addr: a.out[0x100000da3] -line entry: /Volumes/data/lldb/svn/trunk/test/python_api/symbol-context/main.c:21 -start addr: a.out[0x100000da3] -end addr: a.out[0x100000da9] -line entry: /Volumes/data/lldb/svn/trunk/test/python_api/symbol-context/main.c:22 -start addr: a.out[0x100000da9] -end addr: a.out[0x100000db6] -line entry: /Volumes/data/lldb/svn/trunk/test/python_api/symbol-context/main.c:23 -start addr: a.out[0x100000db6] -end addr: a.out[0x100000dbc] -... - -See also SBCompileUnit." +produces: :: + + line entry: /Volumes/data/lldb/svn/trunk/test/python_api/symbol-context/main.c:20 + start addr: a.out[0x100000d98] + end addr: a.out[0x100000da3] + line entry: /Volumes/data/lldb/svn/trunk/test/python_api/symbol-context/main.c:21 + start addr: a.out[0x100000da3] + end addr: a.out[0x100000da9] + line entry: /Volumes/data/lldb/svn/trunk/test/python_api/symbol-context/main.c:22 + start addr: a.out[0x100000da9] + end addr: a.out[0x100000db6] + line entry: /Volumes/data/lldb/svn/trunk/test/python_api/symbol-context/main.c:23 + start addr: a.out[0x100000db6] + end addr: a.out[0x100000dbc] + ... + +See also :py:class:`SBCompileUnit` ." ) SBLineEntry; class SBLineEntry { diff --git a/gnu/llvm/lldb/bindings/interface/SBListener.i b/gnu/llvm/lldb/bindings/interface/SBListener.i index 535aef9f0ae..9062e753442 100644 --- a/gnu/llvm/lldb/bindings/interface/SBListener.i +++ b/gnu/llvm/lldb/bindings/interface/SBListener.i @@ -11,7 +11,7 @@ namespace lldb { %feature("docstring", "API clients can register its own listener to debugger events. -See aslo SBEvent for example usage of creating and adding a listener." +See also :py:class:`SBEvent` for example usage of creating and adding a listener." ) SBListener; class SBListener { diff --git a/gnu/llvm/lldb/bindings/interface/SBMemoryRegionInfo.i b/gnu/llvm/lldb/bindings/interface/SBMemoryRegionInfo.i index 6a2ad6a3e36..3460dc0d06e 100644 --- a/gnu/llvm/lldb/bindings/interface/SBMemoryRegionInfo.i +++ b/gnu/llvm/lldb/bindings/interface/SBMemoryRegionInfo.i @@ -46,6 +46,42 @@ public: const char * GetName (); + %feature("autodoc", " + GetRegionEnd(SBMemoryRegionInfo self) -> lldb::addr_t + Returns whether this memory region has a list of modified (dirty) + pages available or not. When calling GetNumDirtyPages(), you will + have 0 returned for both \"dirty page list is not known\" and + \"empty dirty page list\" (that is, no modified pages in this + memory region). You must use this method to disambiguate.") HasDirtyMemoryPageList; + bool + HasDirtyMemoryPageList(); + + %feature("autodoc", " + GetNumDirtyPages(SBMemoryRegionInfo self) -> uint32_t + Return the number of dirty (modified) memory pages in this + memory region, if available. You must use the + SBMemoryRegionInfo::HasDirtyMemoryPageList() method to + determine if a dirty memory list is available; it will depend + on the target system can provide this information.") GetNumDirtyPages; + uint32_t + GetNumDirtyPages(); + + %feature("autodoc", " + GetDirtyPageAddressAtIndex(SBMemoryRegionInfo self, uint32_t idx) -> lldb::addr_t + Return the address of a modified, or dirty, page of memory. + If the provided index is out of range, or this memory region + does not have dirty page information, LLDB_INVALID_ADDRESS + is returned.") GetDirtyPageAddressAtIndex; + addr_t + GetDirtyPageAddressAtIndex(uint32_t idx); + + %feature("autodoc", " + GetPageSize(SBMemoryRegionInfo self) -> int + Return the size of pages in this memory region. 0 will be returned + if this information was unavailable.") GetPageSize(); + int + GetPageSize(); + bool operator == (const lldb::SBMemoryRegionInfo &rhs) const; diff --git a/gnu/llvm/lldb/bindings/interface/SBMemoryRegionInfoList.i b/gnu/llvm/lldb/bindings/interface/SBMemoryRegionInfoList.i index e408fc0f88b..c2e74f1cd0d 100644 --- a/gnu/llvm/lldb/bindings/interface/SBMemoryRegionInfoList.i +++ b/gnu/llvm/lldb/bindings/interface/SBMemoryRegionInfoList.i @@ -8,6 +8,9 @@ namespace lldb { +%feature("docstring", +"Represents a list of :py:class:`SBMemoryRegionInfo`." +) SBMemoryRegionInfoList; class SBMemoryRegionInfoList { public: diff --git a/gnu/llvm/lldb/bindings/interface/SBModule.i b/gnu/llvm/lldb/bindings/interface/SBModule.i index e902af0c49c..606c9a5bbd0 100644 --- a/gnu/llvm/lldb/bindings/interface/SBModule.i +++ b/gnu/llvm/lldb/bindings/interface/SBModule.i @@ -40,30 +40,30 @@ The module is designed to be able to select a single slice of an executable image as it would appear on disk and during program execution. -You can retrieve SBModule from SBSymbolContext, which in turn is available +You can retrieve SBModule from :py:class:`SBSymbolContext` , which in turn is available from SBFrame. -SBModule supports symbol iteration, for example, +SBModule supports symbol iteration, for example, :: for symbol in module: name = symbol.GetName() saddr = symbol.GetStartAddress() eaddr = symbol.GetEndAddress() -and rich comparison methods which allow the API program to use, +and rich comparison methods which allow the API program to use, :: if thisModule == thatModule: print('This module is the same as that module') to test module equality. A module also contains object file sections, namely -SBSection. SBModule supports section iteration through section_iter(), for -example, +:py:class:`SBSection` . SBModule supports section iteration through section_iter(), for +example, :: print('Number of sections: %d' % module.GetNumSections()) for sec in module.section_iter(): print(sec) -And to iterate the symbols within a SBSection, use symbol_in_section_iter(), +And to iterate the symbols within a SBSection, use symbol_in_section_iter(), :: # Iterates the text section and prints each symbols within each sub-section. for subsec in text_sec: @@ -72,7 +72,7 @@ And to iterate the symbols within a SBSection, use symbol_in_section_iter(), print(INDENT2 + repr(sym)) print(INDENT2 + 'symbol type: %s' % symbol_type_to_str(sym.GetType())) -produces this following output: +produces this following output: :: [0x0000000100001780-0x0000000100001d5c) a.out.__TEXT.__text id = {0x00000004}, name = 'mask_access(MaskAction, unsigned int)', range = [0x00000001000017c0-0x0000000100001870) @@ -204,15 +204,15 @@ public: GetCompileUnitAtIndex (uint32_t); %feature("docstring", " - Find compile units related to *this module and passed source + Find compile units related to this module and passed source file. @param[in] sb_file_spec - A lldb::SBFileSpec object that contains source file + A :py:class:`SBFileSpec` object that contains source file specification. @return - A lldb::SBSymbolContextList that gets filled in with all of + A :py:class:`SBSymbolContextList` that gets filled in with all of the symbol contexts for all the matches.") FindCompileUnits; lldb::SBSymbolContextList FindCompileUnits (const lldb::SBFileSpec &sb_file_spec); @@ -353,6 +353,17 @@ public: static uint32_t GetNumberAllocatedModules(); + %feature("docstring", " + Removes all modules which are no longer needed by any part of LLDB from + the module cache. + + This is an implementation detail exposed for testing and should not be + relied upon. Use SBDebugger::MemoryPressureDetected instead to reduce + LLDB's memory consumption during execution. + ") GarbageCollectAllocatedModules; + static void + GarbageCollectAllocatedModules(); + STRING_EXTENSION(SBModule) #ifdef SWIGPYTHON diff --git a/gnu/llvm/lldb/bindings/interface/SBModuleSpec.i b/gnu/llvm/lldb/bindings/interface/SBModuleSpec.i index 64d0aa641a7..8b4c6a92160 100644 --- a/gnu/llvm/lldb/bindings/interface/SBModuleSpec.i +++ b/gnu/llvm/lldb/bindings/interface/SBModuleSpec.i @@ -95,6 +95,9 @@ public: }; +%feature("docstring", +"Represents a list of :py:class:`SBModuleSpec`." +) SBModuleSpecList; class SBModuleSpecList { public: diff --git a/gnu/llvm/lldb/bindings/interface/SBPlatform.i b/gnu/llvm/lldb/bindings/interface/SBPlatform.i index 81945222c05..65615be7a36 100644 --- a/gnu/llvm/lldb/bindings/interface/SBPlatform.i +++ b/gnu/llvm/lldb/bindings/interface/SBPlatform.i @@ -9,6 +9,9 @@ namespace lldb { +%feature("docstring", +"Describes how :py:class:`SBPlatform.ConnectRemote` connects to a remote platform." +) SBPlatformConnectOptions; class SBPlatformConnectOptions { public: @@ -42,9 +45,13 @@ public: SetLocalCacheDirectory(const char *path); }; +%feature("docstring", +"Represents a shell command that can be run by :py:class:`SBPlatform.Run`." +) SBPlatformShellCommand; class SBPlatformShellCommand { public: + SBPlatformShellCommand (const char *shell, const char *shell_command); SBPlatformShellCommand (const char *shell_command); SBPlatformShellCommand (const SBPlatformShellCommand &rhs); @@ -54,6 +61,12 @@ public: void Clear(); + const char * + GetShell(); + + void + SetShell(const char *shell_interpreter); + const char * GetCommand(); @@ -97,7 +110,7 @@ current processes on the remote host, attach to one of those processes, install programs on the remote system, attach and launch processes, and much more. -Every SBTarget has a corresponding SBPlatform. The platform can be +Every :py:class:`SBTarget` has a corresponding SBPlatform. The platform can be specified upon target creation, or the currently selected platform will attempt to be used when creating the target automatically as long as the currently selected platform matches the target architecture diff --git a/gnu/llvm/lldb/bindings/interface/SBProcess.i b/gnu/llvm/lldb/bindings/interface/SBProcess.i index b54c4629f9d..14566a2942d 100644 --- a/gnu/llvm/lldb/bindings/interface/SBProcess.i +++ b/gnu/llvm/lldb/bindings/interface/SBProcess.i @@ -11,24 +11,22 @@ namespace lldb { %feature("docstring", "Represents the process associated with the target program. -SBProcess supports thread iteration. For example (from test/lldbutil.py), - -# ================================================== -# Utility functions related to Threads and Processes -# ================================================== - -def get_stopped_threads(process, reason): - '''Returns the thread(s) with the specified stop reason in a list. - - The list can be empty if no such thread exists. - ''' - threads = [] - for t in process: - if t.GetStopReason() == reason: - threads.append(t) - return threads - -... +SBProcess supports thread iteration. For example (from test/lldbutil.py), :: + + # ================================================== + # Utility functions related to Threads and Processes + # ================================================== + + def get_stopped_threads(process, reason): + '''Returns the thread(s) with the specified stop reason in a list. + + The list can be empty if no such thread exists. + ''' + threads = [] + for t in process: + if t.GetStopReason() == reason: + threads.append(t) + return threads " ) SBProcess; class SBProcess @@ -246,67 +244,67 @@ public: %feature("autodoc", " Reads memory from the current process's address space and removes any traps that may have been inserted into the memory. It returns the byte - buffer in a Python string. Example: + buffer in a Python string. Example: :: - # Read 4 bytes from address 'addr' and assume error.Success() is True. - content = process.ReadMemory(addr, 4, error) - new_bytes = bytearray(content)") ReadMemory; + # Read 4 bytes from address 'addr' and assume error.Success() is True. + content = process.ReadMemory(addr, 4, error) + new_bytes = bytearray(content)") ReadMemory; size_t ReadMemory (addr_t addr, void *buf, size_t size, lldb::SBError &error); %feature("autodoc", " Writes memory to the current process's address space and maintains any - traps that might be present due to software breakpoints. Example: + traps that might be present due to software breakpoints. Example: :: - # Create a Python string from the byte array. - new_value = str(bytes) - result = process.WriteMemory(addr, new_value, error) - if not error.Success() or result != len(bytes): - print('SBProcess.WriteMemory() failed!')") WriteMemory; + # Create a Python string from the byte array. + new_value = str(bytes) + result = process.WriteMemory(addr, new_value, error) + if not error.Success() or result != len(bytes): + print('SBProcess.WriteMemory() failed!')") WriteMemory; size_t WriteMemory (addr_t addr, const void *buf, size_t size, lldb::SBError &error); %feature("autodoc", " Reads a NULL terminated C string from the current process's address space. It returns a python string of the exact length, or truncates the string if - the maximum character limit is reached. Example: + the maximum character limit is reached. Example: :: - # Read a C string of at most 256 bytes from address '0x1000' - error = lldb.SBError() - cstring = process.ReadCStringFromMemory(0x1000, 256, error) - if error.Success(): - print('cstring: ', cstring) - else - print('error: ', error)") ReadCStringFromMemory; + # Read a C string of at most 256 bytes from address '0x1000' + error = lldb.SBError() + cstring = process.ReadCStringFromMemory(0x1000, 256, error) + if error.Success(): + print('cstring: ', cstring) + else + print('error: ', error)") ReadCStringFromMemory; size_t ReadCStringFromMemory (addr_t addr, void *char_buf, size_t size, lldb::SBError &error); %feature("autodoc", " Reads an unsigned integer from memory given a byte size and an address. - Returns the unsigned integer that was read. Example: + Returns the unsigned integer that was read. Example: :: - # Read a 4 byte unsigned integer from address 0x1000 - error = lldb.SBError() - uint = ReadUnsignedFromMemory(0x1000, 4, error) - if error.Success(): - print('integer: %u' % uint) - else - print('error: ', error)") ReadUnsignedFromMemory; + # Read a 4 byte unsigned integer from address 0x1000 + error = lldb.SBError() + uint = ReadUnsignedFromMemory(0x1000, 4, error) + if error.Success(): + print('integer: %u' % uint) + else + print('error: ', error)") ReadUnsignedFromMemory; uint64_t ReadUnsignedFromMemory (addr_t addr, uint32_t byte_size, lldb::SBError &error); %feature("autodoc", " - Reads a pointer from memory from an address and returns the value. Example: + Reads a pointer from memory from an address and returns the value. Example: :: - # Read a pointer from address 0x1000 - error = lldb.SBError() - ptr = ReadPointerFromMemory(0x1000, error) - if error.Success(): - print('pointer: 0x%x' % ptr) - else - print('error: ', error)") ReadPointerFromMemory; + # Read a pointer from address 0x1000 + error = lldb.SBError() + ptr = ReadPointerFromMemory(0x1000, error) + if error.Success(): + print('pointer: 0x%x' % ptr) + else + print('error: ', error)") ReadPointerFromMemory; lldb::addr_t ReadPointerFromMemory (addr_t addr, lldb::SBError &error); @@ -402,9 +400,6 @@ public: lldb::SBError SaveCore(const char *file_name); - lldb::SBTrace - StartTrace(SBTraceOptions &options, lldb::SBError &error); - lldb::SBError GetMemoryRegionInfo(lldb::addr_t load_addr, lldb::SBMemoryRegionInfo ®ion_info); @@ -414,14 +409,33 @@ public: %feature("autodoc", " Get information about the process. Valid process info will only be returned when the process is alive, - use IsValid() to check if the info returned is valid. + use IsValid() to check if the info returned is valid. :: - process_info = process.GetProcessInfo() - if process_info.IsValid(): - process_info.GetProcessID()") GetProcessInfo; + process_info = process.GetProcessInfo() + if process_info.IsValid(): + process_info.GetProcessID()") GetProcessInfo; lldb::SBProcessInfo GetProcessInfo(); + %feature("autodoc", " + Allocates a block of memory within the process, with size and + access permissions specified in the arguments. The permisssions + argument is an or-combination of zero or more of + lldb.ePermissionsWritable, lldb.ePermissionsReadable, and + lldb.ePermissionsExecutable. Returns the address + of the allocated buffer in the process, or + lldb.LLDB_INVALID_ADDRESS if the allocation failed.") AllocateMemory; + + lldb::addr_t + AllocateMemory(size_t size, uint32_t permissions, lldb::SBError &error); + + %feature("autodoc", " + Deallocates the block of memory (previously allocated using + AllocateMemory) given in the argument.") DeallocateMemory; + + lldb::SBError + DeallocateMemory(lldb::addr_t ptr); + STRING_EXTENSION(SBProcess) #ifdef SWIGPYTHON diff --git a/gnu/llvm/lldb/bindings/interface/SBProcessInfo.i b/gnu/llvm/lldb/bindings/interface/SBProcessInfo.i index 009842599bf..17b2761a344 100644 --- a/gnu/llvm/lldb/bindings/interface/SBProcessInfo.i +++ b/gnu/llvm/lldb/bindings/interface/SBProcessInfo.i @@ -62,6 +62,12 @@ public: lldb::pid_t GetParentProcessID (); + + %feature("docstring", + "Return the target triple (arch-vendor-os) for the described process." + ) GetTriple; + const char * + GetTriple (); }; } // namespace lldb diff --git a/gnu/llvm/lldb/bindings/interface/SBQueue.i b/gnu/llvm/lldb/bindings/interface/SBQueue.i index f209d59f1bf..9f2ec56b241 100644 --- a/gnu/llvm/lldb/bindings/interface/SBQueue.i +++ b/gnu/llvm/lldb/bindings/interface/SBQueue.i @@ -8,6 +8,9 @@ namespace lldb { +%feature("docstring", +"Represents a libdispatch queue in the process." +) SBQueue; class SBQueue { public: diff --git a/gnu/llvm/lldb/bindings/interface/SBQueueItem.i b/gnu/llvm/lldb/bindings/interface/SBQueueItem.i index 089771e8037..2270d958e17 100644 --- a/gnu/llvm/lldb/bindings/interface/SBQueueItem.i +++ b/gnu/llvm/lldb/bindings/interface/SBQueueItem.i @@ -8,6 +8,9 @@ namespace lldb { +%feature("docstring", +"This class represents an item in an :py:class:`SBQueue`." +) SBQueueItem; class SBQueueItem { public: diff --git a/gnu/llvm/lldb/bindings/interface/SBReproducer.i b/gnu/llvm/lldb/bindings/interface/SBReproducer.i index 7c9b007db3c..bc9a5bab3cf 100644 --- a/gnu/llvm/lldb/bindings/interface/SBReproducer.i +++ b/gnu/llvm/lldb/bindings/interface/SBReproducer.i @@ -7,6 +7,10 @@ //===----------------------------------------------------------------------===// namespace lldb { + +%feature("docstring", +"Controls LLDB's reproducer functionality." +) SBReproducer; class SBReproducer { public: diff --git a/gnu/llvm/lldb/bindings/interface/SBSection.i b/gnu/llvm/lldb/bindings/interface/SBSection.i index 3d1c900917f..b86d4e99c5e 100644 --- a/gnu/llvm/lldb/bindings/interface/SBSection.i +++ b/gnu/llvm/lldb/bindings/interface/SBSection.i @@ -12,7 +12,7 @@ namespace lldb { "Represents an executable image section. SBSection supports iteration through its subsection, represented as SBSection -as well. For example, +as well. For example, :: for sec in exe_module: if sec.GetName() == '__TEXT': @@ -22,18 +22,18 @@ as well. For example, for subsec in sec: print INDENT + repr(subsec) -produces: +produces: :: -[0x0000000100000000-0x0000000100002000) a.out.__TEXT - Number of subsections: 6 - [0x0000000100001780-0x0000000100001d5c) a.out.__TEXT.__text - [0x0000000100001d5c-0x0000000100001da4) a.out.__TEXT.__stubs - [0x0000000100001da4-0x0000000100001e2c) a.out.__TEXT.__stub_helper - [0x0000000100001e2c-0x0000000100001f10) a.out.__TEXT.__cstring - [0x0000000100001f10-0x0000000100001f68) a.out.__TEXT.__unwind_info - [0x0000000100001f68-0x0000000100001ff8) a.out.__TEXT.__eh_frame + [0x0000000100000000-0x0000000100002000) a.out.__TEXT + Number of subsections: 6 + [0x0000000100001780-0x0000000100001d5c) a.out.__TEXT.__text + [0x0000000100001d5c-0x0000000100001da4) a.out.__TEXT.__stubs + [0x0000000100001da4-0x0000000100001e2c) a.out.__TEXT.__stub_helper + [0x0000000100001e2c-0x0000000100001f10) a.out.__TEXT.__cstring + [0x0000000100001f10-0x0000000100001f68) a.out.__TEXT.__unwind_info + [0x0000000100001f68-0x0000000100001ff8) a.out.__TEXT.__eh_frame -See also SBModule." +See also :py:class:`SBModule` ." ) SBSection; class SBSection diff --git a/gnu/llvm/lldb/bindings/interface/SBSourceManager.i b/gnu/llvm/lldb/bindings/interface/SBSourceManager.i index dfbdc612a06..12dd1bdb0d1 100644 --- a/gnu/llvm/lldb/bindings/interface/SBSourceManager.i +++ b/gnu/llvm/lldb/bindings/interface/SBSourceManager.i @@ -11,7 +11,7 @@ namespace lldb { %feature("docstring", "Represents a central authority for displaying source code. -For example (from test/source-manager/TestSourceManager.py), +For example (from test/source-manager/TestSourceManager.py), :: # Create the filespec for 'main.c'. filespec = lldb.SBFileSpec('main.c', False) diff --git a/gnu/llvm/lldb/bindings/interface/SBStream.i b/gnu/llvm/lldb/bindings/interface/SBStream.i index edd67f87c3f..acf44e351d5 100644 --- a/gnu/llvm/lldb/bindings/interface/SBStream.i +++ b/gnu/llvm/lldb/bindings/interface/SBStream.i @@ -14,7 +14,7 @@ namespace lldb { "Represents a destination for streaming data output to. By default, a string stream is created. -For example (from test/source-manager/TestSourceManager.py), +For example (from test/source-manager/TestSourceManager.py), :: # Create the filespec for 'main.c'. filespec = lldb.SBFileSpec('main.c', False) diff --git a/gnu/llvm/lldb/bindings/interface/SBStringList.i b/gnu/llvm/lldb/bindings/interface/SBStringList.i index c8e1e357ed2..d80ae9f9c5b 100644 --- a/gnu/llvm/lldb/bindings/interface/SBStringList.i +++ b/gnu/llvm/lldb/bindings/interface/SBStringList.i @@ -8,6 +8,9 @@ namespace lldb { +%feature("docstring", +"Represents a list of strings." +) SBStringList; class SBStringList { public: diff --git a/gnu/llvm/lldb/bindings/interface/SBStructuredData.i b/gnu/llvm/lldb/bindings/interface/SBStructuredData.i index c7601bf6cf9..ba5b7e07506 100644 --- a/gnu/llvm/lldb/bindings/interface/SBStructuredData.i +++ b/gnu/llvm/lldb/bindings/interface/SBStructuredData.i @@ -8,12 +8,11 @@ namespace lldb { - %feature("docstring", - "A class representing a StructuredData event. +%feature("docstring", + "A class representing a StructuredData event. - This class wraps the event type generated by StructuredData - features." - ) SBStructuredData; +This class wraps the event type generated by StructuredData features." +) SBStructuredData; class SBStructuredData { public: @@ -59,5 +58,8 @@ namespace lldb { lldb::SBError SetFromJSON(lldb::SBStream &stream); + + lldb::SBError + SetFromJSON(const char *json); }; } diff --git a/gnu/llvm/lldb/bindings/interface/SBSymbol.i b/gnu/llvm/lldb/bindings/interface/SBSymbol.i index 4e17ab5af0f..fa0b3e4e137 100644 --- a/gnu/llvm/lldb/bindings/interface/SBSymbol.i +++ b/gnu/llvm/lldb/bindings/interface/SBSymbol.i @@ -10,9 +10,7 @@ namespace lldb { %feature("docstring", "Represents the symbol possibly associated with a stack frame. -SBModule contains SBSymbol(s). SBSymbol can also be retrieved from SBFrame. - -See also SBModule and SBFrame." +:py:class:`SBModule` contains SBSymbol(s). SBSymbol can also be retrieved from :py:class:`SBFrame` ." ) SBSymbol; class SBSymbol { diff --git a/gnu/llvm/lldb/bindings/interface/SBSymbolContext.i b/gnu/llvm/lldb/bindings/interface/SBSymbolContext.i index b6b336516c9..9818fdb0949 100644 --- a/gnu/llvm/lldb/bindings/interface/SBSymbolContext.i +++ b/gnu/llvm/lldb/bindings/interface/SBSymbolContext.i @@ -15,7 +15,7 @@ Many debugger functions require a context when doing lookups. This class provides a common structure that can be used as the result of a query that can contain a single result. -For example, +For example, :: exe = os.path.join(os.getcwd(), 'a.out') diff --git a/gnu/llvm/lldb/bindings/interface/SBSymbolContextList.i b/gnu/llvm/lldb/bindings/interface/SBSymbolContextList.i index f5adcfcebfb..e9d4aa8d62d 100644 --- a/gnu/llvm/lldb/bindings/interface/SBSymbolContextList.i +++ b/gnu/llvm/lldb/bindings/interface/SBSymbolContextList.i @@ -11,7 +11,7 @@ namespace lldb { %feature("docstring", "Represents a list of symbol context object. See also SBSymbolContext. -For example (from test/python_api/target/TestTargetAPI.py), +For example (from test/python_api/target/TestTargetAPI.py), :: def find_functions(self, exe_name): '''Exercise SBTaget.FindFunctions() API.''' diff --git a/gnu/llvm/lldb/bindings/interface/SBTarget.i b/gnu/llvm/lldb/bindings/interface/SBTarget.i index 57b5ccea639..3f9e4cdc6d6 100644 --- a/gnu/llvm/lldb/bindings/interface/SBTarget.i +++ b/gnu/llvm/lldb/bindings/interface/SBTarget.i @@ -11,40 +11,40 @@ namespace lldb { %feature("docstring", "Represents the target program running under the debugger. -SBTarget supports module, breakpoint, and watchpoint iterations. For example, +SBTarget supports module, breakpoint, and watchpoint iterations. For example, :: for m in target.module_iter(): print m -produces: +produces: :: -(x86_64) /Volumes/data/lldb/svn/trunk/test/python_api/lldbutil/iter/a.out -(x86_64) /usr/lib/dyld -(x86_64) /usr/lib/libstdc++.6.dylib -(x86_64) /usr/lib/libSystem.B.dylib -(x86_64) /usr/lib/system/libmathCommon.A.dylib -(x86_64) /usr/lib/libSystem.B.dylib(__commpage) + (x86_64) /Volumes/data/lldb/svn/trunk/test/python_api/lldbutil/iter/a.out + (x86_64) /usr/lib/dyld + (x86_64) /usr/lib/libstdc++.6.dylib + (x86_64) /usr/lib/libSystem.B.dylib + (x86_64) /usr/lib/system/libmathCommon.A.dylib + (x86_64) /usr/lib/libSystem.B.dylib(__commpage) -and, +and, :: for b in target.breakpoint_iter(): print b -produces: +produces: :: -SBBreakpoint: id = 1, file ='main.cpp', line = 66, locations = 1 -SBBreakpoint: id = 2, file ='main.cpp', line = 85, locations = 1 + SBBreakpoint: id = 1, file ='main.cpp', line = 66, locations = 1 + SBBreakpoint: id = 2, file ='main.cpp', line = 85, locations = 1 -and, +and, :: for wp_loc in target.watchpoint_iter(): print wp_loc -produces: +produces: :: -Watchpoint 1: addr = 0x1034ca048 size = 4 state = enabled type = rw - declare @ '/Volumes/data/lldb/svn/trunk/test/python_api/watchpoint/main.c:12' - hw_index = 0 hit_count = 2 ignore_count = 0" + Watchpoint 1: addr = 0x1034ca048 size = 4 state = enabled type = rw + declare @ '/Volumes/data/lldb/svn/trunk/test/python_api/watchpoint/main.c:12' + hw_index = 0 hit_count = 2 ignore_count = 0" ) SBTarget; class SBTarget { @@ -208,30 +208,16 @@ public: %feature("docstring", " Launch a new process with sensible defaults. - @param[in] argv - The argument array. - - @param[in] envp - The environment array. - - @param[in] working_directory - The working directory to have the child process run in - - Default: listener - Set to the target's debugger (SBTarget::GetDebugger()) + :param argv: The argument array. + :param envp: The environment array. + :param working_directory: The working directory to have the child process run in + :return: The newly created process. + :rtype: SBProcess - Default: launch_flags - Empty launch flags + A pseudo terminal will be used as stdin/stdout/stderr. + No launch flags are passed and the target's debuger is used as a listener. - Default: stdin_path - Default: stdout_path - Default: stderr_path - A pseudo terminal will be used. - - @return - A process object for the newly created process. - - For example, + For example, :: process = target.LaunchSimple(['X', 'Y', 'Z'], None, os.getcwd()) @@ -389,16 +375,13 @@ public: FindModule (const lldb::SBFileSpec &file_spec); %feature("docstring", " - Find compile units related to *this target and passed source + Find compile units related to this target and passed source file. - @param[in] sb_file_spec - A lldb::SBFileSpec object that contains source file + :param sb_file_spec: A :py:class:`lldb::SBFileSpec` object that contains source file specification. - - @return - A lldb::SBSymbolContextList that gets filled in with all of - the symbol contexts for all the matches.") FindCompileUnits; + :return: The symbol contexts for all the matches. + :rtype: SBSymbolContextList") FindCompileUnits; lldb::SBSymbolContextList FindCompileUnits (const lldb::SBFileSpec &sb_file_spec); @@ -414,18 +397,18 @@ public: %feature("docstring", " Architecture data byte width accessor - @return - The size in 8-bit (host) bytes of a minimum addressable - unit from the Architecture's data bus") GetDataByteSize; + :return: The size in 8-bit (host) bytes of a minimum addressable unit from the Architecture's data bus. + + ") GetDataByteSize; uint32_t GetDataByteSize (); %feature("docstring", " - Architecture code byte width accessor + Architecture code byte width accessor. - @return - The size in 8-bit (host) bytes of a minimum addressable - unit from the Architecture's code bus") GetCodeByteSize; + :return: The size in 8-bit (host) bytes of a minimum addressable unit from the Architecture's code bus. + + ") GetCodeByteSize; uint32_t GetCodeByteSize (); @@ -446,17 +429,16 @@ public: %feature("docstring", " Find functions by name. - @param[in] name - The name of the function we are looking for. + :param name: The name of the function we are looking for. - @param[in] name_type_mask + :param name_type_mask: A logical OR of one or more FunctionNameType enum bits that indicate what kind of names should be used when doing the lookup. Bits include fully qualified names, base names, C++ methods, or ObjC selectors. See FunctionNameType for more details. - @return + :return: A lldb::SBSymbolContextList that gets filled in with all of the symbol contexts for all the matches.") FindFunctions; lldb::SBSymbolContextList @@ -579,6 +561,12 @@ public: uint32_t column, lldb::addr_t offset, SBFileSpecList &module_list); + lldb::SBBreakpoint + BreakpointCreateByLocation (const lldb::SBFileSpec &file_spec, uint32_t line, + uint32_t column, lldb::addr_t offset, + SBFileSpecList &module_list, + bool move_to_nearest_code); + lldb::SBBreakpoint BreakpointCreateByName (const char *symbol_name, const char *module_name = NULL); @@ -688,41 +676,42 @@ public: @param[in] class_name This is the name of the class that implements a scripted resolver. - The class should have the following signature: - class Resolver: - def __init__(self, bkpt, extra_args): - # bkpt - the breakpoint for which this is the resolver. When - # the resolver finds an interesting address, call AddLocation - # on this breakpoint to add it. - # - # extra_args - an SBStructuredData that can be used to - # parametrize this instance. Same as the extra_args passed - # to BreakpointCreateFromScript. - - def __get_depth__ (self): - # This is optional, but if defined, you should return the - # depth at which you want the callback to be called. The - # available options are: - # lldb.eSearchDepthModule - # lldb.eSearchDepthCompUnit - # The default if you don't implement this method is - # eSearchDepthModule. - - def __callback__(self, sym_ctx): - # sym_ctx - an SBSymbolContext that is the cursor in the - # search through the program to resolve breakpoints. - # The sym_ctx will be filled out to the depth requested in - # __get_depth__. - # Look in this sym_ctx for new breakpoint locations, - # and if found use bkpt.AddLocation to add them. - # Note, you will only get called for modules/compile_units that - # pass the SearchFilter provided by the module_list & file_list - # passed into BreakpointCreateFromScript. - - def get_short_help(self): - # Optional, but if implemented return a short string that will - # be printed at the beginning of the break list output for the - # breakpoint. + The class should have the following signature: :: + + class Resolver: + def __init__(self, bkpt, extra_args): + # bkpt - the breakpoint for which this is the resolver. When + # the resolver finds an interesting address, call AddLocation + # on this breakpoint to add it. + # + # extra_args - an SBStructuredData that can be used to + # parametrize this instance. Same as the extra_args passed + # to BreakpointCreateFromScript. + + def __get_depth__ (self): + # This is optional, but if defined, you should return the + # depth at which you want the callback to be called. The + # available options are: + # lldb.eSearchDepthModule + # lldb.eSearchDepthCompUnit + # The default if you don't implement this method is + # eSearchDepthModule. + + def __callback__(self, sym_ctx): + # sym_ctx - an SBSymbolContext that is the cursor in the + # search through the program to resolve breakpoints. + # The sym_ctx will be filled out to the depth requested in + # __get_depth__. + # Look in this sym_ctx for new breakpoint locations, + # and if found use bkpt.AddLocation to add them. + # Note, you will only get called for modules/compile_units that + # pass the SearchFilter provided by the module_list & file_list + # passed into BreakpointCreateFromScript. + + def get_short_help(self): + # Optional, but if implemented return a short string that will + # be printed at the beginning of the break list output for the + # breakpoint. @param[in] extra_args This is an SBStructuredData object that will get passed to the @@ -902,11 +891,12 @@ public: %feature("docstring", " Disassemble a specified number of instructions starting at an address. - Parameters: - base_addr -- the address to start disassembly from - count -- the number of instructions to disassemble - flavor_string -- may be 'intel' or 'att' on x86 targets to specify that style of disassembly - Returns an SBInstructionList.") + + :param base_addr: the address to start disassembly from. + :param count: the number of instructions to disassemble. + :param flavor_string: may be 'intel' or 'att' on x86 targets to specify that style of disassembly. + :rtype: SBInstructionList + ") ReadInstructions; lldb::SBInstructionList ReadInstructions (lldb::SBAddress base_addr, uint32_t count); @@ -916,23 +906,25 @@ public: %feature("docstring", " Disassemble the bytes in a buffer and return them in an SBInstructionList. - Parameters: - base_addr -- used for symbolicating the offsets in the byte stream when disassembling - buf -- bytes to be disassembled - size -- (C++) size of the buffer - Returns an SBInstructionList.") + + :param base_addr: used for symbolicating the offsets in the byte stream when disassembling. + :param buf: bytes to be disassembled. + :param size: (C++) size of the buffer. + :rtype: SBInstructionList + ") GetInstructions; lldb::SBInstructionList GetInstructions (lldb::SBAddress base_addr, const void *buf, size_t size); %feature("docstring", " Disassemble the bytes in a buffer and return them in an SBInstructionList, with a supplied flavor. - Parameters: - base_addr -- used for symbolicating the offsets in the byte stream when disassembling - flavor -- may be 'intel' or 'att' on x86 targets to specify that style of disassembly - buf -- bytes to be disassembled - size -- (C++) size of the buffer - Returns an SBInstructionList.") + + :param base_addr: used for symbolicating the offsets in the byte stream when disassembling. + :param flavor: may be 'intel' or 'att' on x86 targets to specify that style of disassembly. + :param buf: bytes to be disassembled. + :param size: (C++) size of the buffer. + :rtype: SBInstructionList + ") GetInstructionsWithFlavor; lldb::SBInstructionList GetInstructionsWithFlavor (lldb::SBAddress base_addr, const char *flavor_string, const void *buf, size_t size); @@ -946,6 +938,16 @@ public: lldb::addr_t GetStackRedZoneSize(); + %feature("docstring", " + Returns true if the module has been loaded in this `SBTarget`. + A module can be loaded either by the dynamic loader or by being manually + added to the target (see `SBTarget.AddModule` and the `target module add` command). + + :rtype: bool + ") IsLoaded; + bool + IsLoaded (const lldb::SBModule &module) const; + lldb::SBLaunchInfo GetLaunchInfo () const; @@ -972,6 +974,12 @@ public: STRING_EXTENSION_LEVEL(SBTarget, lldb::eDescriptionLevelBrief) + lldb::SBTrace + GetTrace (); + + lldb::SBTrace + CreateTrace (lldb::SBError &error); + #ifdef SWIGPYTHON %pythoncode %{ class modules_access(object): diff --git a/gnu/llvm/lldb/bindings/interface/SBThread.i b/gnu/llvm/lldb/bindings/interface/SBThread.i index 66466b7947f..d847d38f0d6 100644 --- a/gnu/llvm/lldb/bindings/interface/SBThread.i +++ b/gnu/llvm/lldb/bindings/interface/SBThread.i @@ -9,7 +9,7 @@ namespace lldb { %feature("docstring", -"Represents a thread of execution. SBProcess contains SBThread(s). +"Represents a thread of execution. :py:class:`SBProcess` contains SBThread(s). SBThreads can be referred to by their ID, which maps to the system specific thread identifier, or by IndexID. The ID may or may not be unique depending on whether the @@ -18,7 +18,7 @@ that will always uniquely reference a particular thread, and when that thread go away it will not be reused. SBThread supports frame iteration. For example (from test/python_api/ -lldbutil/iter/TestLLDBIterator.py), +lldbutil/iter/TestLLDBIterator.py), :: from lldbutil import print_stacktrace stopped_due_to_breakpoint = False @@ -35,7 +35,7 @@ lldbutil/iter/TestLLDBIterator.py), self.assertTrue(stopped_due_to_breakpoint) -See also SBProcess and SBFrame." +See also :py:class:`SBFrame` ." ) SBThread; class SBThread { @@ -104,6 +104,9 @@ public: eStopReasonSignal 1 unix signal number eStopReasonException N exception data eStopReasonExec 0 + eStopReasonFork 1 pid of the child process + eStopReasonVFork 1 pid of the child process + eStopReasonVForkDone 0 eStopReasonPlanComplete 0") GetStopReasonDataAtIndex; uint64_t GetStopReasonDataAtIndex(uint32_t idx); diff --git a/gnu/llvm/lldb/bindings/interface/SBThreadPlan.i b/gnu/llvm/lldb/bindings/interface/SBThreadPlan.i index 36131d529b7..9e105352535 100644 --- a/gnu/llvm/lldb/bindings/interface/SBThreadPlan.i +++ b/gnu/llvm/lldb/bindings/interface/SBThreadPlan.i @@ -18,8 +18,8 @@ namespace lldb { %feature("docstring", "Represents a plan for the execution control of a given thread. -See also SBThread and SBFrame." -) SBThread; +See also :py:class:`SBThread` and :py:class:`SBFrame`." +) SBThreadPlan; class SBThreadPlan { @@ -73,6 +73,9 @@ public: eStopReasonSignal 1 unix signal number eStopReasonException N exception data eStopReasonExec 0 + eStopReasonFork 1 pid of the child process + eStopReasonVFork 1 pid of the child process + eStopReasonVForkDone 0 eStopReasonPlanComplete 0") GetStopReasonDataAtIndex; uint64_t GetStopReasonDataAtIndex(uint32_t idx); @@ -92,6 +95,14 @@ public: bool IsPlanStale(); + %feature("docstring", "Return whether this plan will ask to stop other threads when it runs.") GetStopOthers; + bool + GetStopOthers(); + + %feature("docstring", "Set whether this plan will ask to stop other threads when it runs.") GetStopOthers; + void + SetStopOthers(bool stop_others); + SBThreadPlan QueueThreadPlanForStepOverRange (SBAddress &start_address, lldb::addr_t range_size); diff --git a/gnu/llvm/lldb/bindings/interface/SBTrace.i b/gnu/llvm/lldb/bindings/interface/SBTrace.i index a4cb2667ec1..0f5bf0ecc8d 100644 --- a/gnu/llvm/lldb/bindings/interface/SBTrace.i +++ b/gnu/llvm/lldb/bindings/interface/SBTrace.i @@ -8,28 +8,25 @@ namespace lldb { +%feature("docstring", +"Represents a processor trace." +) SBTrace; class LLDB_API SBTrace { public: SBTrace(); - size_t GetTraceData(SBError &error, void *buf, - size_t size, size_t offset, - lldb::tid_t thread_id); - size_t GetMetaData(SBError &error, void *buf, - size_t size, size_t offset, - lldb::tid_t thread_id); + const char *GetStartConfigurationHelp(); - void StopTrace(SBError &error, - lldb::tid_t thread_id); + SBError Start(const SBStructuredData &configuration); - void GetTraceConfig(SBTraceOptions &options, - SBError &error); + SBError Start(const SBThread &thread, const SBStructuredData &configuration); - lldb::user_id_t GetTraceUID(); + SBError Stop(); + + SBError Stop(const SBThread &thread); explicit operator bool() const; bool IsValid(); - }; -} // namespace lldb \ No newline at end of file +} // namespace lldb diff --git a/gnu/llvm/lldb/bindings/interface/SBType.i b/gnu/llvm/lldb/bindings/interface/SBType.i index 3cd82452084..500bc99ca8c 100644 --- a/gnu/llvm/lldb/bindings/interface/SBType.i +++ b/gnu/llvm/lldb/bindings/interface/SBType.i @@ -9,7 +9,7 @@ namespace lldb { %feature("docstring", -"Represents a member of a type in lldb.") SBTypeMember; +"Represents a member of a type.") SBTypeMember; class SBTypeMember { @@ -60,6 +60,9 @@ protected: std::unique_ptr m_opaque_ap; }; +%feature("docstring", +"Represents a member function of a type." +) SBTypeMemberFunction; class SBTypeMemberFunction { public: @@ -108,77 +111,93 @@ protected: }; %feature("docstring", -"Represents a data type in lldb. The FindFirstType() method of SBTarget/SBModule -returns a SBType. - -SBType supports the eq/ne operator. For example, - -main.cpp: - -class Task { -public: - int id; - Task *next; - Task(int i, Task *n): - id(i), - next(n) - {} -}; - -int main (int argc, char const *argv[]) -{ - Task *task_head = new Task(-1, NULL); - Task *task1 = new Task(1, NULL); - Task *task2 = new Task(2, NULL); - Task *task3 = new Task(3, NULL); // Orphaned. - Task *task4 = new Task(4, NULL); - Task *task5 = new Task(5, NULL); - - task_head->next = task1; - task1->next = task2; - task2->next = task4; - task4->next = task5; - - int total = 0; - Task *t = task_head; - while (t != NULL) { - if (t->id >= 0) - ++total; - t = t->next; +"Represents a data type in lldb. + +The actual characteristics of each type are defined by the semantics of the +programming language and the specific language implementation that was used +to compile the target program. See the language-specific notes in the +documentation of each method. + +SBType instances can be obtained by a variety of methods. +`SBTarget.FindFirstType` and `SBModule.FindFirstType` can be used to create +`SBType` representations of types in executables/libraries with debug +information. For some languages such as C, C++ and Objective-C it is possible +to create new types by evaluating expressions that define a new type. + +Note that most `SBType` properties are computed independently of any runtime +information so for dynamic languages the functionality can be very limited. +`SBValue` can be used to represent runtime values which then can be more +accurately queried for certain information such as byte size. + + +SBType supports the eq/ne operator. For example,:: + + //main.cpp: + + class Task { + public: + int id; + Task *next; + Task(int i, Task *n): + id(i), + next(n) + {} + }; + + int main (int argc, char const *argv[]) + { + Task *task_head = new Task(-1, NULL); + Task *task1 = new Task(1, NULL); + Task *task2 = new Task(2, NULL); + Task *task3 = new Task(3, NULL); // Orphaned. + Task *task4 = new Task(4, NULL); + Task *task5 = new Task(5, NULL); + + task_head->next = task1; + task1->next = task2; + task2->next = task4; + task4->next = task5; + + int total = 0; + Task *t = task_head; + while (t != NULL) { + if (t->id >= 0) + ++total; + t = t->next; + } + printf('We have a total number of %d tasks\\n', total); + + // This corresponds to an empty task list. + Task *empty_task_head = new Task(-1, NULL); + + return 0; // Break at this line } - printf('We have a total number of %d tasks\\n', total); - - // This corresponds to an empty task list. - Task *empty_task_head = new Task(-1, NULL); - return 0; // Break at this line -} + # find_type.py: -find_type.py: + # Get the type 'Task'. + task_type = target.FindFirstType('Task') + self.assertTrue(task_type) - # Get the type 'Task'. - task_type = target.FindFirstType('Task') - self.assertTrue(task_type) + # Get the variable 'task_head'. + frame0.FindVariable('task_head') + task_head_type = task_head.GetType() + self.assertTrue(task_head_type.IsPointerType()) - # Get the variable 'task_head'. - frame0.FindVariable('task_head') - task_head_type = task_head.GetType() - self.assertTrue(task_head_type.IsPointerType()) + # task_head_type is 'Task *'. + task_pointer_type = task_type.GetPointerType() + self.assertTrue(task_head_type == task_pointer_type) - # task_head_type is 'Task *'. - task_pointer_type = task_type.GetPointerType() - self.assertTrue(task_head_type == task_pointer_type) + # Get the child mmember 'id' from 'task_head'. + id = task_head.GetChildMemberWithName('id') + id_type = id.GetType() - # Get the child mmember 'id' from 'task_head'. - id = task_head.GetChildMemberWithName('id') - id_type = id.GetType() + # SBType.GetBasicType() takes an enum 'BasicType' (lldb-enumerations.h). + int_type = id_type.GetBasicType(lldb.eBasicTypeInt) + # id_type and int_type should be the same type! + self.assertTrue(id_type == int_type) - # SBType.GetBasicType() takes an enum 'BasicType' (lldb-enumerations.h). - int_type = id_type.GetBasicType(lldb.eBasicTypeInt) - # id_type and int_type should be the same type! - self.assertTrue(id_type == int_type) - -...") SBType; +") SBType; class SBType { public: @@ -193,123 +212,649 @@ public: explicit operator bool() const; + + %feature("docstring", + "Returns the number of bytes a variable with the given types occupies in memory. + + Returns ``0`` if the size can't be determined. + + If a type occupies ``N`` bytes + ``M`` bits in memory, this function returns + the rounded up amount of bytes (i.e., if ``M`` is ``0``, + this function returns ``N`` and otherwise ``N + 1``). + + Language-specific behaviour: + + * C: The output is expected to match the value of ``sizeof(Type)``. If + ``sizeof(Type)`` is not a valid expression for the given type, the + function returns ``0``. + * C++: Same as in C. + * Objective-C: Same as in C. For Objective-C classes this always returns + `0`` as the actual size depends on runtime information. + ") GetByteSize; uint64_t GetByteSize(); + + %feature("docstring", + "Returns true if this type is a pointer type. + + Language-specific behaviour: + + * C: Returns true for C pointer types (or typedefs of these types). + * C++: Pointer types include the C pointer types as well as pointers to data + mebers or member functions. + * Objective-C: Pointer types include the C pointer types. ``id``, ``Class`` + and pointers to blocks are also considered pointer types. + ") IsPointerType; bool IsPointerType(); + %feature("docstring", + "Returns true if this type is a reference type. + + Language-specific behaviour: + + * C: Returns false for all types. + * C++: Both l-value and r-value references are considered reference types. + * Objective-C: Returns false for all types. + ") IsReferenceType; bool IsReferenceType(); + %feature("docstring", + "Returns true if this type is a function type. + + Language-specific behaviour: + + * C: Returns true for types that represent functions. Note that function + pointers are not function types (but their `GetPointeeType()` are function + types). + * C++: Same as in C. + * Objective-C: Returns false for all types. + ") IsPolymorphicClass; bool IsFunctionType (); + %feature("docstring", + "Returns true if this type is a polymorphic type. + + Language-specific behaviour: + + * C: Returns false for all types. + * C++: Returns true if the type is a class type that contains at least one + virtual member function or if at least one of its base classes is + considered a polymorphic type. + * Objective-C: Returns false for all types. + ") IsPolymorphicClass; bool IsPolymorphicClass (); + %feature("docstring", + "Returns true if this type is an array type. + + Language-specific behaviour: + + * C: Returns true if the types is an array type. This includes incomplete + array types ``T[]`` and array types with integer (``T[1]``) or variable + length (``T[some_variable]``). Pointer types are not considered arrays. + * C++: Includes C's array types and dependent array types (i.e., array types + in templates which size depends on template arguments). + * Objective-C: Same as in C. + ") IsArrayType; bool IsArrayType (); + %feature("docstring", + "Returns true if this type is a vector type. + + Language-specific behaviour: + + * C: Returns true if the types is a vector type created with + GCC's ``vector_size`` or Clang's ``ext_vector_type`` feature. + * C++: Same as in C. + * Objective-C: Same as in C. + ") IsVectorType; bool IsVectorType (); + %feature("docstring", + "Returns true if this type is a typedef. + + Language-specific behaviour: + + * C: Returns true if the type is a C typedef. + * C++: Same as in C. Also treats type aliases as typedefs. + * Objective-C: Same as in C. + ") IsTypedefType; bool IsTypedefType (); + %feature("docstring", + "Returns true if this type is an anonymous type. + + Language-specific behaviour: + + * C: Returns true for anonymous unions. Also returns true for + anonymous structs (which are a GNU language extension). + * C++: Same as in C. + * Objective-C: Same as in C. + ") IsAnonymousType; bool IsAnonymousType (); + %feature("docstring", + "Returns true if this type is a scoped enum. + + Language-specific behaviour: + + * C: Returns false for all types. + * C++: Return true only for C++11 scoped enums. + * Objective-C: Returns false for all types. + ") IsScopedEnumerationType; + bool + IsScopedEnumerationType (); + + %feature("docstring", + "Returns a type that represents a pointer to this type. + + If the type system of the current language can't represent a pointer to this + type or this type is invalid, an invalid `SBType` is returned. + + Language-specific behaviour: + + * C: Returns the pointer type of this type. + * C++: Same as in C. + * Objective-C: Same as in C. + ") GetPointerType; lldb::SBType GetPointerType(); + %feature("docstring", + "Returns the underlying pointee type. + + If this type is a pointer type as specified by `IsPointerType` then this + returns the underlying type. If this is not a pointer type or an invalid + `SBType` then this returns an invalid `SBType`. + + Language-specific behaviour: + + * C: Returns the underlying type for for C pointer types or typedefs of + these types). For example, ``int *`` will return ``int``. + * C++: Same as in C. Returns an `SBType` representation for data members/ + member functions in case the `SBType` is a pointer to data member or + pointer to member function. + * Objective-C: Same as in C. The pointee type of ``id`` and ``Class`` is + an invalid `SBType`. The pointee type of pointers Objective-C types is an + `SBType` for the non-pointer type of the respective type. For example, + ``NSString *`` will return ``NSString`` as a pointee type. + ") GetPointeeType; lldb::SBType GetPointeeType(); + %feature("docstring", + "Returns a type that represents a reference to this type. + + If the type system of the current language can't represent a reference to + this type, an invalid `SBType` is returned. + + Language-specific behaviour: + + * C: Currently assumes the type system is C++ and returns an l-value + reference type. For example, ``int`` will return ``int&``. This behavior + is likely to change in the future and shouldn't be relied on. + * C++: Same as in C. + * Objective-C: Same as in C. + ") GetReferenceType; lldb::SBType GetReferenceType(); + %feature("docstring", + "Returns the underlying type of a typedef. + + If this type is a typedef as designated by `IsTypedefType`, then the + underlying type is being returned. Otherwise an invalid `SBType` is + returned. + + Language-specific behaviour: + + * C: Returns the underlying type of a typedef type. + * C++: Same as in C. For type aliases, the underlying type is returned. + * Objective-C: Same as in C. + ") GetTypedefedType; lldb::SBType SBType::GetTypedefedType(); + %feature("docstring", + "Returns the underlying type of a reference type. + + If this type is a reference as designated by `IsReferenceType`, then the + underlying type is being returned. Otherwise an invalid `SBType` is + returned. + + Language-specific behaviour: + + * C: Always returns an invalid type. + * C++: For l-value and r-value references the underlying type is returned. + For example, ``int &`` will return ``int``. + * Objective-C: Same as in C. + ") GetDereferencedType; lldb::SBType GetDereferencedType(); + %feature("docstring", + "Returns the unqualified version of this type. + + Language-specific behaviour: + + * C: If this type with any const or volatile specifier removed. + * C++: Same as in C. + * Objective-C: Same as in C. + ") GetUnqualifiedType; lldb::SBType GetUnqualifiedType(); lldb::SBType GetCanonicalType(); + %feature("docstring", + "Returns the underlying integer type if this is an enumeration type. + + If this type is an invalid `SBType` or not an enumeration type an invalid + `SBType` is returned. + + Language-specific behaviour: + + * C: Returns the underlying type for enums. + * C++: Same as in C but also returns the underlying type for scoped enums. + * Objective-C: Same as in C. + ") GetEnumerationIntegerType; + lldb::SBType + GetEnumerationIntegerType(); + + %feature("docstring", + "Returns the array element type if this type is an array type. + + Otherwise returns an invalid `SBType` if this type is invalid or not an + array type. + + Language-specific behaviour: + + * C: If this is an array type (see `IsArrayType`) such as ``T[]``, returns + the element type. + * C++: Same as in C. + * Objective-C: Same as in C. + + See also `IsArrayType`. + ") GetArrayElementType; lldb::SBType GetArrayElementType (); + %feature("docstring", + "Returns the array type with the given constant size. + + Language-specific behaviour: + + * C: Returns a constant-size array `T[size]` for any non-void type. + * C++: Same as in C. + * Objective-C: Same as in C. + + See also `IsArrayType` and `GetArrayElementType`. + ") GetArrayType; lldb::SBType GetArrayType (uint64_t size); + %feature("docstring", + "Returns the vector element type if this type is a vector type. + + Otherwise returns an invalid `SBType` if this type is invalid or not a + vector type. + + Language-specific behaviour: + + * C: If this is a vector type (see `IsVectorType`), returns the element + type. + * C++: Same as in C. + * Objective-C: Same as in C. + + See also `IsVectorType`. + ") GetVectorElementType; lldb::SBType GetVectorElementType (); + %feature("docstring", + "Returns the `BasicType` value that is most appropriate to this type. + + Returns `eBasicTypeInvalid` if no appropriate `BasicType` was found or this + type is invalid. See the `BasicType` documentation for the language-specific m + aning of each `BasicType` value. + + **Overload behaviour:** When called with a `BasicType` parameter, the + following behaviour applies: + + Returns the `SBType` that represents the passed `BasicType` value. Returns + an invalid `SBType` if no fitting `SBType` could be created. + + Language-specific behaviour: + + * C: Returns the respective builtin type. Note that some types + (e.g. ``__uint128_t``) might even be successfully created even if they are + not available on the target platform. C++ and Objective-C specific types + might also be created even if the target program is not written in C++ or + Objective-C. + * C++: Same as in C. + * Objective-C: Same as in C. + "); lldb::BasicType GetBasicType(); lldb::SBType GetBasicType (lldb::BasicType type); + %feature("docstring", + "Returns the number of fields of this type. + + Returns ``0`` if this type does not have fields. + + Language-specific behaviour: + + * C: Returns the number of fields if the type is a struct. If the type + contains an anonymous struct/union it only counts as a single field (even + if the struct/union contains several fields). + * C++: Returns the number of non-static fields if the type is a + struct/class. If the type contains an anonymous struct/union it only + counts as a single field (even if the struct/union contains several + fields). The fields of any base classes are not included in the count. + * Objective-C: Same as in C for structs. For Objective-C classes the number + of ivars is returned. + + See also `GetFieldAtIndex`. + ") GetNumberOfFields; uint32_t GetNumberOfFields (); + %feature("docstring", + "Returns the number of base/parent classes of this type. + + Returns ``0`` if this type doesn't have any base classes. + + Language-specific behaviour: + + * C: Returns always ``0``. + * C++: The number of direct non-virtual base classes if this type is + a class. + * Objective-C: The number of super classes for Objective-C classes. + As Objective-C doesn't have multiple inheritance this is usually returns 1 + except for NSObject. + ") GetNumberOfDirectBaseClasses; uint32_t GetNumberOfDirectBaseClasses (); + %feature("docstring", + "Returns the number of virtual base/parent classes of this type + + Returns ``0`` if this type doesn't have any base classes. + + Language-specific behaviour: + + * C: Returns always ``0``. + * C++: The number of direct virtual base classes if this type is a + class. + * Objective-C: Returns always ``0``. + ") GetNumberOfVirtualBaseClasses; uint32_t GetNumberOfVirtualBaseClasses (); + %feature("docstring", + "Returns the field at the given index. + + Returns an invalid `SBType` if the index is out of range or the current + type doesn't have any fields. + + Language-specific behaviour: + + * C: Returns the field with the given index for struct types. Fields are + ordered/indexed starting from ``0`` for the first field in a struct (as + declared in the definition). + * C++: Returns the non-static field with the given index for struct types. + Fields are ordered/indexed starting from ``0`` for the first field in a + struct (as declared in the definition). + * Objective-C: Same as in C for structs. For Objective-C classes the ivar + with the given index is returned. ivars are indexed starting from ``0``. + ") GetFieldAtIndex; lldb::SBTypeMember GetFieldAtIndex (uint32_t idx); + %feature("docstring", + "Returns the direct base class as indexed by `GetNumberOfDirectBaseClasses`. + + Returns an invalid SBTypeMember if the index is invalid or this SBType is + invalid. + ") GetDirectBaseClassAtIndex; lldb::SBTypeMember GetDirectBaseClassAtIndex (uint32_t idx); + %feature("docstring", + "Returns the virtual base class as indexed by + `GetNumberOfVirtualBaseClasses`. + + Returns an invalid SBTypeMember if the index is invalid or this SBType is + invalid. + ") GetVirtualBaseClassAtIndex; lldb::SBTypeMember GetVirtualBaseClassAtIndex (uint32_t idx); lldb::SBTypeEnumMemberList GetEnumMembers(); + %feature("docstring", + "Returns the `SBModule` this `SBType` belongs to. + + Returns no `SBModule` if this type does not belong to any specific + `SBModule` or this `SBType` is invalid. An invalid `SBModule` might also + indicate that once came from an `SBModule` but LLDB could no longer + determine the original module. + ") GetModule; + lldb::SBModule + GetModule(); + + %feature("autodoc", "GetName() -> string") GetName; + %feature("docstring", + "Returns the name of this type. + + Returns an empty string if an error occurred or this type is invalid. + + Use this function when trying to match a specific type by name in a script. + The names returned by this function try to uniquely identify a name but + conflicts can occur (for example, if a C++ program contains two different + classes with the same name in different translation units. `GetName` can + return the same name for both class types.) + + + Language-specific behaviour: + * C: The name of the type. For structs the ``struct`` prefix is omitted. + * C++: Returns the qualified name of the type (including anonymous/inline + namespaces and all template arguments). + * Objective-C: Same as in C. + ") GetName; const char* GetName(); + %feature("autodoc", "GetDisplayTypeName() -> string") GetDisplayTypeName; + %feature("docstring", + "Returns the name of this type in a user-friendly format. + + Returns an empty string if an error occurred or this type is invalid. + + Use this function when displaying a type name to the user. + + Language-specific behaviour: + + * C: Returns the type name. For structs the ``struct`` prefix is omitted. + * C++: Returns the qualified name. Anonymous/inline namespaces are omitted. + Template arguments that match their default value might also be hidden + (this functionality depends on whether LLDB can determine the template's + default arguments). + * Objective-C: Same as in C. + ") GetDisplayTypeName; const char * GetDisplayTypeName (); + %feature("autodoc", "GetTypeClass() -> TypeClass") GetTypeClass; + %feature("docstring", + "Returns the `TypeClass` for this type. + + Returns an `eTypeClassInvalid` if this `SBType` is invalid. + + See `TypeClass` for the language-specific meaning of each `TypeClass` value. + ") GetTypeClass; lldb::TypeClass GetTypeClass (); + %feature("docstring", + "Returns the number of template arguments of this type. + + Returns ``0`` if this type is not a template. + + Language-specific behaviour: + + * C: Always returns ``0``. + * C++: If this type is a class template instantiation then this returns the + number of template parameters that were used in this instantiation. This i + cludes both explicit and implicit template parameters. + * Objective-C: Always returns ``0``. + ") GetNumberOfTemplateArguments; uint32_t GetNumberOfTemplateArguments (); + %feature("docstring", + "Returns the type of the template argument with the given index. + + Returns an invalid `SBType` if there is no template argument with the given + index or this type is not a template. The first template argument has the + index ``0``. + + Language-specific behaviour: + + * C: Always returns an invalid SBType. + * C++: If this type is a class template instantiation and the template + parameter with the given index is a type template parameter, then this + returns the type of that parameter. Otherwise returns an invalid `SBType`. + * Objective-C: Always returns an invalid SBType. + ") GetTemplateArgumentType; lldb::SBType GetTemplateArgumentType (uint32_t idx); + %feature("docstring", + "Returns the kind of the template argument with the given index. + + Returns `eTemplateArgumentKindNull` if there is no template argument + with the given index or this type is not a template. The first template + argument has the index ``0``. + + Language-specific behaviour: + + * C: Always returns `eTemplateArgumentKindNull`. + * C++: If this type is a class template instantiation then this returns + the appropriate `TemplateArgument` value for the parameter with the given + index. See the documentation of `TemplateArgument` for how certain C++ + template parameter kinds are mapped to `TemplateArgument` values. + * Objective-C: Always returns `eTemplateArgumentKindNull`. + ") GetTemplateArgumentKind; lldb::TemplateArgumentKind GetTemplateArgumentKind (uint32_t idx); + %feature("docstring", + "Returns the return type if this type represents a function. + + Returns an invalid `SBType` if this type is not a function type or invalid. + + Language-specific behaviour: + + * C: For functions return the return type. Returns an invalid `SBType` if + this type is a function pointer type. + * C++: Same as in C for functions and instantiated template functions. + Member functions are also considered functions. For functions that have + their return type specified by a placeholder type specifier (``auto``) + this returns the deduced return type. + * Objective-C: Same as in C for functions. For Objective-C methods this + returns the return type of the method. + ") GetFunctionReturnType; lldb::SBType GetFunctionReturnType (); + %feature("docstring", + "Returns the list of argument types if this type represents a function. + + Returns an invalid `SBType` if this type is not a function type or invalid. + + Language-specific behaviour: + + * C: For functions return the types of each parameter. Returns an invalid + `SBType` if this type is a function pointer. For variadic functions this + just returns the list of parameters before the variadic arguments. + * C++: Same as in C for functions and instantiated template functions. + Member functions are also considered functions. + * Objective-C: Always returns an invalid SBType for Objective-C methods. + ") GetFunctionArgumentTypes; lldb::SBTypeList GetFunctionArgumentTypes (); + %feature("docstring", + "Returns the number of member functions of this type. + + Returns ``0`` if an error occurred or this type is invalid. + + Language-specific behaviour: + + * C: Always returns ``0``. + * C++: If this type represents a struct/class, then the number of + member functions (static and non-static) is returned. The count includes + constructors and destructors (both explicit and implicit). Member + functions of base classes are not included in the count. + * Objective-C: If this type represents a struct/class, then the + number of methods is returned. Methods in categories or super classes + are not counted. + ") GetNumberOfMemberFunctions; uint32_t GetNumberOfMemberFunctions (); + %feature("docstring", + "Returns the member function of this type with the given index. + + Returns an invalid `SBTypeMemberFunction` if the index is invalid or this + type is invalid. + + Language-specific behaviour: + + * C: Always returns an invalid `SBTypeMemberFunction`. + * C++: Returns the member function or constructor/destructor with the given + index. + * Objective-C: Returns the method with the given index. + + See `GetNumberOfMemberFunctions` for what functions can be queried by this + function. + ") GetMemberFunctionAtIndex; lldb::SBTypeMemberFunction GetMemberFunctionAtIndex (uint32_t idx); bool IsTypeComplete (); + %feature("docstring", + "Returns the `TypeFlags` values for this type. + + See the respective `TypeFlags` values for what values can be set. Returns an + integer in which each `TypeFlags` value is represented by a bit. Specific + flags can be checked via Python's bitwise operators. For example, the + `eTypeIsInteger` flag can be checked like this: + + ``(an_sb_type.GetTypeFlags() & lldb.eTypeIsInteger) != 0`` + + If this type is invalid this returns ``0``. + + See the different values for `TypeFlags` for the language-specific meanings + of each `TypeFlags` value. + ") GetTypeFlags; uint32_t GetTypeFlags (); @@ -330,6 +875,7 @@ public: return template_args return None + module = property(GetModule, None, doc='''A read only property that returns the module in which type is defined.''') name = property(GetName, None, doc='''A read only property that returns the name for this type as a string.''') size = property(GetByteSize, None, doc='''A read only property that returns size in bytes for this type as an integer.''') is_pointer = property(IsPointerType, None, doc='''A read only property that returns a boolean value that indicates if this type is a pointer type.''') @@ -421,35 +967,38 @@ public: }; %feature("docstring", -"Represents a list of SBTypes. The FindTypes() method of SBTarget/SBModule -returns a SBTypeList. +"Represents a list of :py:class:`SBType` s. -SBTypeList supports SBType iteration. For example, +The FindTypes() method of :py:class:`SBTarget`/:py:class:`SBModule` returns a SBTypeList. -main.cpp: +SBTypeList supports :py:class:`SBType` iteration. For example, -class Task { -public: - int id; - Task *next; - Task(int i, Task *n): - id(i), - next(n) - {} -}; +.. code-block:: cpp + + // main.cpp: + + class Task { + public: + int id; + Task *next; + Task(int i, Task *n): + id(i), + next(n) + {} + }; -... +.. code-block:: python -find_type.py: + # find_type.py: - # Get the type 'Task'. - type_list = target.FindTypes('Task') - self.assertTrue(len(type_list) == 1) - # To illustrate the SBType iteration. - for type in type_list: - # do something with type + # Get the type 'Task'. + type_list = target.FindTypes('Task') + self.assertTrue(len(type_list) == 1) + # To illustrate the SBType iteration. + for type in type_list: + # do something with type -...") SBTypeList; +") SBTypeList; class SBTypeList { public: diff --git a/gnu/llvm/lldb/bindings/interface/SBTypeEnumMember.i b/gnu/llvm/lldb/bindings/interface/SBTypeEnumMember.i index 006bdeaa8ce..b4190102724 100644 --- a/gnu/llvm/lldb/bindings/interface/SBTypeEnumMember.i +++ b/gnu/llvm/lldb/bindings/interface/SBTypeEnumMember.i @@ -71,10 +71,19 @@ protected: SBTypeEnumMember (const lldb::TypeEnumMemberImplSP &); }; -%feature( - "docstring", - "Represents a list of SBTypeEnumMembers." -) SBTypeEnumMemberList; +%feature("docstring", +"Represents a list of SBTypeEnumMembers. + +SBTypeEnumMemberList supports SBTypeEnumMember iteration. +It also supports [] access either by index, or by enum +element name by doing: :: + + myType = target.FindFirstType('MyEnumWithElementA') + members = myType.GetEnumMembers() + first_elem = members[0] + elem_A = members['A'] + +") SBTypeEnumMemberList; class SBTypeEnumMemberList { @@ -99,6 +108,29 @@ public: uint32_t GetSize(); +#ifdef SWIGPYTHON + %pythoncode %{ + def __iter__(self): + '''Iterate over all members in a lldb.SBTypeEnumMemberList object.''' + return lldb_iter(self, 'GetSize', 'GetTypeEnumMemberAtIndex') + + def __len__(self): + '''Return the number of members in a lldb.SBTypeEnumMemberList object.''' + return self.GetSize() + + def __getitem__(self, key): + num_elements = self.GetSize() + if type(key) is int: + if key < num_elements: + return self.GetTypeEnumMemberAtIndex(key) + elif type(key) is str: + for idx in range(num_elements): + item = self.GetTypeEnumMemberAtIndex(idx) + if item.name == key: + return item + return None + %} +#endif private: std::unique_ptr m_opaque_ap; diff --git a/gnu/llvm/lldb/bindings/interface/SBValue.i b/gnu/llvm/lldb/bindings/interface/SBValue.i index fb899805c39..dd012e667a2 100644 --- a/gnu/llvm/lldb/bindings/interface/SBValue.i +++ b/gnu/llvm/lldb/bindings/interface/SBValue.i @@ -13,7 +13,7 @@ namespace lldb { SBValue supports iteration through its child, which in turn is represented as an SBValue. For example, we can get the general purpose registers of a -frame as an SBValue, and iterate through all the registers, +frame as an SBValue, and iterate through all the registers,:: registerSet = frame.registers # Returns an SBValueList. for regs in registerSet: @@ -25,30 +25,30 @@ frame as an SBValue, and iterate through all the registers, for reg in GPRs: print('Name: ', reg.name, ' Value: ', reg.value) -produces the output: - -General Purpose Registers (number of children = 21): -Name: rax Value: 0x0000000100000c5c -Name: rbx Value: 0x0000000000000000 -Name: rcx Value: 0x00007fff5fbffec0 -Name: rdx Value: 0x00007fff5fbffeb8 -Name: rdi Value: 0x0000000000000001 -Name: rsi Value: 0x00007fff5fbffea8 -Name: rbp Value: 0x00007fff5fbffe80 -Name: rsp Value: 0x00007fff5fbffe60 -Name: r8 Value: 0x0000000008668682 -Name: r9 Value: 0x0000000000000000 -Name: r10 Value: 0x0000000000001200 -Name: r11 Value: 0x0000000000000206 -Name: r12 Value: 0x0000000000000000 -Name: r13 Value: 0x0000000000000000 -Name: r14 Value: 0x0000000000000000 -Name: r15 Value: 0x0000000000000000 -Name: rip Value: 0x0000000100000dae -Name: rflags Value: 0x0000000000000206 -Name: cs Value: 0x0000000000000027 -Name: fs Value: 0x0000000000000010 -Name: gs Value: 0x0000000000000048 +produces the output: :: + + General Purpose Registers (number of children = 21): + Name: rax Value: 0x0000000100000c5c + Name: rbx Value: 0x0000000000000000 + Name: rcx Value: 0x00007fff5fbffec0 + Name: rdx Value: 0x00007fff5fbffeb8 + Name: rdi Value: 0x0000000000000001 + Name: rsi Value: 0x00007fff5fbffea8 + Name: rbp Value: 0x00007fff5fbffe80 + Name: rsp Value: 0x00007fff5fbffe60 + Name: r8 Value: 0x0000000008668682 + Name: r9 Value: 0x0000000000000000 + Name: r10 Value: 0x0000000000001200 + Name: r11 Value: 0x0000000000000206 + Name: r12 Value: 0x0000000000000000 + Name: r13 Value: 0x0000000000000000 + Name: r14 Value: 0x0000000000000000 + Name: r15 Value: 0x0000000000000000 + Name: rip Value: 0x0000000100000dae + Name: rflags Value: 0x0000000000000206 + Name: cs Value: 0x0000000000000027 + Name: fs Value: 0x0000000000000010 + Name: gs Value: 0x0000000000000048 See also linked_list_iter() for another perspective on how to iterate through an SBValue instance which interprets the value object as representing the head of a @@ -379,22 +379,18 @@ public: Get an SBData wrapping what this SBValue points to. This method will dereference the current SBValue, if its - data type is a T* or T[], and extract item_count elements - of type T from it, copying their contents in an SBData. + data type is a ``T\*`` or ``T[]``, and extract ``item_count`` elements + of type ``T`` from it, copying their contents in an :py:class:`SBData`. - @param[in] item_idx - The index of the first item to retrieve. For an array + :param item_idx: The index of the first item to retrieve. For an array this is equivalent to array[item_idx], for a pointer - to *(pointer + item_idx). In either case, the measurement - unit for item_idx is the sizeof(T) rather than the byte - - @param[in] item_count - How many items should be copied into the output. By default + to ``\*(pointer + item_idx)``. In either case, the measurement + unit for item_idx is the ``sizeof(T)`` rather than the byte + :param item_count: How many items should be copied into the output. By default only one item is copied, but more can be asked for. - - @return - An SBData with the contents of the copied items, on success. - An empty SBData otherwise.") GetPointeeData; + :return: The contents of the copied items on success. An empty :py:class:`SBData` otherwise. + :rtype: SBData + ") GetPointeeData; lldb::SBData GetPointeeData (uint32_t item_idx = 0, uint32_t item_count = 1); diff --git a/gnu/llvm/lldb/bindings/interface/SBValueList.i b/gnu/llvm/lldb/bindings/interface/SBValueList.i index 17ba2056f0c..76fa937b987 100644 --- a/gnu/llvm/lldb/bindings/interface/SBValueList.i +++ b/gnu/llvm/lldb/bindings/interface/SBValueList.i @@ -9,61 +9,62 @@ namespace lldb { %feature("docstring", -"Represents a collection of SBValues. Both SBFrame's GetVariables() and -GetRegisters() return a SBValueList. - -SBValueList supports SBValue iteration. For example (from test/lldbutil.py), - -def get_registers(frame, kind): - '''Returns the registers given the frame and the kind of registers desired. - - Returns None if there's no such kind. - ''' - registerSet = frame.GetRegisters() # Return type of SBValueList. - for value in registerSet: - if kind.lower() in value.GetName().lower(): - return value - - return None - -def get_GPRs(frame): - '''Returns the general purpose registers of the frame as an SBValue. - - The returned SBValue object is iterable. An example: - ... - from lldbutil import get_GPRs - regs = get_GPRs(frame) - for reg in regs: - print('%s => %s' % (reg.GetName(), reg.GetValue())) - ... - ''' - return get_registers(frame, 'general purpose') - -def get_FPRs(frame): - '''Returns the floating point registers of the frame as an SBValue. - - The returned SBValue object is iterable. An example: - ... - from lldbutil import get_FPRs - regs = get_FPRs(frame) - for reg in regs: - print('%s => %s' % (reg.GetName(), reg.GetValue())) - ... - ''' - return get_registers(frame, 'floating point') - -def get_ESRs(frame): - '''Returns the exception state registers of the frame as an SBValue. - - The returned SBValue object is iterable. An example: - ... - from lldbutil import get_ESRs - regs = get_ESRs(frame) - for reg in regs: - print('%s => %s' % (reg.GetName(), reg.GetValue())) - ... - ''' - return get_registers(frame, 'exception state')" +"Represents a collection of SBValues. Both :py:class:`SBFrame.GetVariables()` and +:py:class:`SBFrame.GetRegisters()` return a SBValueList. + +SBValueList supports :py:class:`SBValue` iteration. For example (from test/lldbutil.py),:: + + def get_registers(frame, kind): + '''Returns the registers given the frame and the kind of registers desired. + + Returns None if there's no such kind. + ''' + registerSet = frame.GetRegisters() # Return type of SBValueList. + for value in registerSet: + if kind.lower() in value.GetName().lower(): + return value + + return None + + def get_GPRs(frame): + '''Returns the general purpose registers of the frame as an SBValue. + + The returned SBValue object is iterable. An example: + ... + from lldbutil import get_GPRs + regs = get_GPRs(frame) + for reg in regs: + print('%s => %s' % (reg.GetName(), reg.GetValue())) + ... + ''' + return get_registers(frame, 'general purpose') + + def get_FPRs(frame): + '''Returns the floating point registers of the frame as an SBValue. + + The returned SBValue object is iterable. An example: + ... + from lldbutil import get_FPRs + regs = get_FPRs(frame) + for reg in regs: + print('%s => %s' % (reg.GetName(), reg.GetValue())) + ... + ''' + return get_registers(frame, 'floating point') + + def get_ESRs(frame): + '''Returns the exception state registers of the frame as an SBValue. + + The returned SBValue object is iterable. An example: + ... + from lldbutil import get_ESRs + regs = get_ESRs(frame) + for reg in regs: + print('%s => %s' % (reg.GetName(), reg.GetValue())) + ... + ''' + return get_registers(frame, 'exception state') +" ) SBValueList; class SBValueList { diff --git a/gnu/llvm/lldb/bindings/interface/SBVariablesOptions.i b/gnu/llvm/lldb/bindings/interface/SBVariablesOptions.i index 362f7159d7d..dfdc8cf5df6 100644 --- a/gnu/llvm/lldb/bindings/interface/SBVariablesOptions.i +++ b/gnu/llvm/lldb/bindings/interface/SBVariablesOptions.i @@ -8,6 +8,9 @@ namespace lldb { +%feature("docstring", +"Describes which variables should be returned from :py:class:`SBFrame.GetVariables`." +) SBVariablesOptions; class SBVariablesOptions { public: diff --git a/gnu/llvm/lldb/bindings/interface/SBWatchpoint.i b/gnu/llvm/lldb/bindings/interface/SBWatchpoint.i index cb0bc5f9859..ac31c60a561 100644 --- a/gnu/llvm/lldb/bindings/interface/SBWatchpoint.i +++ b/gnu/llvm/lldb/bindings/interface/SBWatchpoint.i @@ -14,7 +14,7 @@ namespace lldb { A watchpoint is determined by the address and the byte size that resulted in this particular instantiation. Each watchpoint has its settable options. -See also SBTarget.watchpoint_iter() for example usage of iterating through the +See also :py:class:`SBTarget.watchpoint_iter()` for example usage of iterating through the watchpoints of the target." ) SBWatchpoint; class SBWatchpoint diff --git a/gnu/llvm/lldb/bindings/interfaces.swig b/gnu/llvm/lldb/bindings/interfaces.swig index 2df7a05b4f4..c9a6d0f0605 100644 --- a/gnu/llvm/lldb/bindings/interfaces.swig +++ b/gnu/llvm/lldb/bindings/interfaces.swig @@ -69,7 +69,6 @@ %include "./interface/SBThreadCollection.i" %include "./interface/SBThreadPlan.i" %include "./interface/SBTrace.i" -%include "./interface/SBTraceOptions.i" %include "./interface/SBType.i" %include "./interface/SBTypeCategory.i" %include "./interface/SBTypeEnumMember.i" diff --git a/gnu/llvm/lldb/bindings/lua/CMakeLists.txt b/gnu/llvm/lldb/bindings/lua/CMakeLists.txt new file mode 100644 index 00000000000..7148f137045 --- /dev/null +++ b/gnu/llvm/lldb/bindings/lua/CMakeLists.txt @@ -0,0 +1,19 @@ +add_custom_command( + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/LLDBWrapLua.cpp + DEPENDS ${SWIG_SOURCES} + DEPENDS ${SWIG_INTERFACES} + DEPENDS ${SWIG_HEADERS} + COMMAND ${SWIG_EXECUTABLE} + ${SWIG_COMMON_FLAGS} + -I${CMAKE_CURRENT_SOURCE_DIR} + -lua + -w503 + -outdir ${CMAKE_CURRENT_BINARY_DIR} + -o ${CMAKE_CURRENT_BINARY_DIR}/LLDBWrapLua.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/lua.swig + VERBATIM + COMMENT "Building LLDB Lua wrapper") + +add_custom_target(swig_wrapper_lua ALL DEPENDS + ${CMAKE_CURRENT_BINARY_DIR}/LLDBWrapLua.cpp +) diff --git a/gnu/llvm/lldb/bindings/lua/lua-swigsafecast.swig b/gnu/llvm/lldb/bindings/lua/lua-swigsafecast.swig new file mode 100644 index 00000000000..0b67c41434e --- /dev/null +++ b/gnu/llvm/lldb/bindings/lua/lua-swigsafecast.swig @@ -0,0 +1,27 @@ +template +void +PushSBClass (lua_State* L, SBClass* obj); + +void +PushSBClass (lua_State* L, lldb::SBFrame* frame_sb) +{ + SWIG_NewPointerObj(L, frame_sb, SWIGTYPE_p_lldb__SBFrame, 0); +} + +void +PushSBClass (lua_State* L, lldb::SBBreakpointLocation* breakpoint_location_sb) +{ + SWIG_NewPointerObj(L, breakpoint_location_sb, SWIGTYPE_p_lldb__SBBreakpointLocation, 0); +} + +void +PushSBClass (lua_State* L, lldb::SBWatchpoint* watchpoint_sb) +{ + SWIG_NewPointerObj(L, watchpoint_sb, SWIGTYPE_p_lldb__SBWatchpoint, 0); +} + +void +PushSBClass (lua_State* L, lldb::SBStructuredData* structured_data_sb) +{ + SWIG_NewPointerObj(L, structured_data_sb, SWIGTYPE_p_lldb__SBStructuredData, 0); +} diff --git a/gnu/llvm/lldb/bindings/lua/lua-typemaps.swig b/gnu/llvm/lldb/bindings/lua/lua-typemaps.swig index 28d63fa2f40..d912137a567 100644 --- a/gnu/llvm/lldb/bindings/lua/lua-typemaps.swig +++ b/gnu/llvm/lldb/bindings/lua/lua-typemaps.swig @@ -1 +1,105 @@ %include + +// FIXME: We need to port more typemaps from Python + +//===----------------------------------------------------------------------===// + +// In Lua 5.3 and beyond the VM supports integers, so we need to remap +// SWIG's internal handling of integers. + + +%define LLDB_NUMBER_TYPEMAP(TYPE) + +// Primitive integer mapping +%typemap(in,checkfn="lua_isinteger") TYPE +%{ $1 = (TYPE)lua_tointeger(L, $input); %} +%typemap(in,checkfn="lua_isinteger") const TYPE&($basetype temp) +%{ temp=($basetype)lua_tointeger(L,$input); $1=&temp;%} +%typemap(out) TYPE +%{ lua_pushinteger(L, (lua_Integer) $1); SWIG_arg++;%} +%typemap(out) const TYPE& +%{ lua_pushinteger(L, (lua_Integer) $1); SWIG_arg++;%} + +// Pointer and reference mapping +%typemap(in,checkfn="lua_isinteger") TYPE *INPUT($*ltype temp), TYPE &INPUT($*ltype temp) +%{ temp = ($*ltype)lua_tointeger(L,$input); + $1 = &temp; %} +%typemap(in, numinputs=0) TYPE *OUTPUT ($*ltype temp) +%{ $1 = &temp; %} +%typemap(argout) TYPE *OUTPUT +%{ lua_pushinteger(L, (lua_Integer) *$1); SWIG_arg++;%} +%typemap(in) TYPE *INOUT = TYPE *INPUT; +%typemap(argout) TYPE *INOUT = TYPE *OUTPUT; +%typemap(in) TYPE &OUTPUT = TYPE *OUTPUT; +%typemap(argout) TYPE &OUTPUT = TYPE *OUTPUT; +%typemap(in) TYPE &INOUT = TYPE *INPUT; +%typemap(argout) TYPE &INOUT = TYPE *OUTPUT; +%typemap(in,checkfn="lua_isinteger") const TYPE *INPUT($*ltype temp) +%{ temp = ($*ltype)lua_tointeger(L,$input); + $1 = &temp; %} + +%enddef // LLDB_NUMBER_TYPEMAP + +LLDB_NUMBER_TYPEMAP(unsigned char); +LLDB_NUMBER_TYPEMAP(signed char); +LLDB_NUMBER_TYPEMAP(short); +LLDB_NUMBER_TYPEMAP(unsigned short); +LLDB_NUMBER_TYPEMAP(signed short); +LLDB_NUMBER_TYPEMAP(int); +LLDB_NUMBER_TYPEMAP(unsigned int); +LLDB_NUMBER_TYPEMAP(signed int); +LLDB_NUMBER_TYPEMAP(long); +LLDB_NUMBER_TYPEMAP(unsigned long); +LLDB_NUMBER_TYPEMAP(signed long); +LLDB_NUMBER_TYPEMAP(long long); +LLDB_NUMBER_TYPEMAP(unsigned long long); +LLDB_NUMBER_TYPEMAP(signed long long); + +%apply unsigned long { size_t }; +%apply const unsigned long & { const size_t & }; +%apply long { ssize_t }; +%apply const long & { const ssize_t & }; + +//===----------------------------------------------------------------------===// + +// FIXME: +// Ideally all the typemaps should be revisited in a future SB API revision. +// Typemaps, usually, modifies the function signatures and might spawn +// different LLDB APIs across languages (C++, Python, Lua...). +// Historically, typemaps have been used to replace SWIG's deficiencies, +// but SWIG itself evolved and some API design choices are now redundant. + +//===----------------------------------------------------------------------===// + +// Typemap definitions to allow SWIG to properly handle char buffer. + +// typemap for a char buffer +%typemap(in) (char *dst, size_t dst_len) { + $2 = luaL_checkinteger(L, $input); + if ($2 <= 0) { + return luaL_error(L, "Positive integer expected"); + } + $1 = (char *) malloc($2); +} + +// SBProcess::ReadCStringFromMemory() uses a void*, but needs to be treated +// as char data instead of byte data. +%typemap(in) (void *char_buf, size_t size) = (char *dst, size_t dst_len); + +// Return the char buffer. Discarding any previous return result +%typemap(argout) (char *dst, size_t dst_len) { + lua_pop(L, 1); // Blow away the previous result + if ($result == 0) { + lua_pushliteral(L, ""); + } else { + lua_pushlstring(L, (const char *)$1, $result); + } + free($1); + // SWIG_arg was already incremented +} + +// SBProcess::ReadCStringFromMemory() uses a void*, but needs to be treated +// as char data instead of byte data. +%typemap(argout) (void *char_buf, size_t size) = (char *dst, size_t dst_len); + +//===----------------------------------------------------------------------===// diff --git a/gnu/llvm/lldb/bindings/lua/lua-wrapper.swig b/gnu/llvm/lldb/bindings/lua/lua-wrapper.swig new file mode 100644 index 00000000000..e070bae2368 --- /dev/null +++ b/gnu/llvm/lldb/bindings/lua/lua-wrapper.swig @@ -0,0 +1,92 @@ +%header %{ + +template +void +PushSBClass(lua_State* L, T* obj); + +%} + +%wrapper %{ + +// This function is called from Lua::CallBreakpointCallback +SWIGEXPORT llvm::Expected +LLDBSwigLuaBreakpointCallbackFunction +( + lua_State *L, + lldb::StackFrameSP stop_frame_sp, + lldb::BreakpointLocationSP bp_loc_sp, + StructuredDataImpl *extra_args_impl +) +{ + lldb::SBFrame sb_frame(stop_frame_sp); + lldb::SBBreakpointLocation sb_bp_loc(bp_loc_sp); + int nargs = 2; + + llvm::Optional extra_args; + if (extra_args_impl) + extra_args = lldb::SBStructuredData(extra_args_impl); + + // Push the Lua wrappers + PushSBClass(L, &sb_frame); + PushSBClass(L, &sb_bp_loc); + + if (extra_args.hasValue()) { + PushSBClass(L, extra_args.getPointer()); + nargs++; + } + + // Call into the Lua callback passing 'sb_frame' and 'sb_bp_loc'. + // Expects a boolean return. + if (lua_pcall(L, nargs, 1, 0) != LUA_OK) { + llvm::Error E = llvm::make_error( + llvm::formatv("{0}\n", lua_tostring(L, -1)), + llvm::inconvertibleErrorCode()); + // Pop error message from the stack. + lua_pop(L, 1); + return std::move(E); + } + + // Boolean return from the callback + bool stop = lua_toboolean(L, -1); + lua_pop(L, 1); + + return stop; +} + +// This function is called from Lua::CallWatchpointCallback +SWIGEXPORT llvm::Expected +LLDBSwigLuaWatchpointCallbackFunction +( + lua_State *L, + lldb::StackFrameSP stop_frame_sp, + lldb::WatchpointSP wp_sp +) +{ + lldb::SBFrame sb_frame(stop_frame_sp); + lldb::SBWatchpoint sb_wp(wp_sp); + int nargs = 2; + + // Push the Lua wrappers + PushSBClass(L, &sb_frame); + PushSBClass(L, &sb_wp); + + // Call into the Lua callback passing 'sb_frame' and 'sb_wp'. + // Expects a boolean return. + if (lua_pcall(L, nargs, 1, 0) != LUA_OK) { + llvm::Error E = llvm::make_error( + llvm::formatv("{0}\n", lua_tostring(L, -1)), + llvm::inconvertibleErrorCode()); + // Pop error message from the stack. + lua_pop(L, 1); + return std::move(E); + } + + // Boolean return from the callback + bool stop = lua_toboolean(L, -1); + lua_pop(L, 1); + + return stop; +} + + +%} diff --git a/gnu/llvm/lldb/bindings/lua/lua.swig b/gnu/llvm/lldb/bindings/lua/lua.swig new file mode 100644 index 00000000000..c702e496408 --- /dev/null +++ b/gnu/llvm/lldb/bindings/lua/lua.swig @@ -0,0 +1,25 @@ +/* + lldb.swig + + This is the input file for SWIG, to create the appropriate C++ wrappers and + functions for various scripting languages, to enable them to call the + liblldb Script Bridge functions. +*/ + +%module lldb + +%include +%include "lua-typemaps.swig" +%include "macros.swig" +%include "headers.swig" + +%{ +#include "llvm/Support/Error.h" +#include "llvm/Support/FormatVariadic.h" +#include "../bindings/lua/lua-swigsafecast.swig" +using namespace lldb_private; +using namespace lldb; +%} + +%include "interfaces.swig" +%include "lua-wrapper.swig" diff --git a/gnu/llvm/lldb/bindings/macros.swig b/gnu/llvm/lldb/bindings/macros.swig index 0387f27f3cb..6793a11c5bd 100644 --- a/gnu/llvm/lldb/bindings/macros.swig +++ b/gnu/llvm/lldb/bindings/macros.swig @@ -1,6 +1,5 @@ %define STRING_EXTENSION_LEVEL(Class, Level) %extend { - %nothreadallow; std::string lldb:: ## Class ## ::__str__(){ lldb::SBStream stream; $self->GetDescription (stream, Level); @@ -11,13 +10,11 @@ } return std::string(desc, desc_len); } - %clearnothreadallow; } %enddef %define STRING_EXTENSION(Class) %extend { - %nothreadallow; std::string lldb:: ## Class ## ::__str__(){ lldb::SBStream stream; $self->GetDescription (stream); @@ -28,6 +25,5 @@ } return std::string(desc, desc_len); } - %clearnothreadallow; } %enddef diff --git a/gnu/llvm/lldb/bindings/python/CMakeLists.txt b/gnu/llvm/lldb/bindings/python/CMakeLists.txt new file mode 100644 index 00000000000..9422ee00cb5 --- /dev/null +++ b/gnu/llvm/lldb/bindings/python/CMakeLists.txt @@ -0,0 +1,199 @@ +add_custom_command( + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/LLDBWrapPython.cpp + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/lldb.py + DEPENDS ${SWIG_SOURCES} + DEPENDS ${SWIG_INTERFACES} + DEPENDS ${SWIG_HEADERS} + COMMAND ${SWIG_EXECUTABLE} + ${SWIG_COMMON_FLAGS} + -I${CMAKE_CURRENT_SOURCE_DIR} + -c++ + -shadow + -python + -py3 + -threads + -outdir ${CMAKE_CURRENT_BINARY_DIR} + -o ${CMAKE_CURRENT_BINARY_DIR}/LLDBWrapPython.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/python.swig + VERBATIM + COMMENT "Building LLDB Python wrapper") + +add_custom_target(swig_wrapper_python ALL DEPENDS + ${CMAKE_CURRENT_BINARY_DIR}/LLDBWrapPython.cpp + ${CMAKE_CURRENT_BINARY_DIR}/lldb.py +) + +function(create_python_package swig_target working_dir pkg_dir) + cmake_parse_arguments(ARG "NOINIT" "" "FILES" ${ARGN}) + if(ARG_FILES) + set(copy_cmd COMMAND ${CMAKE_COMMAND} -E copy ${ARG_FILES} ${pkg_dir}) + endif() + if(NOT ARG_NOINIT) + set(init_cmd COMMAND ${Python3_EXECUTABLE} + "${LLDB_SOURCE_DIR}/bindings/python/createPythonInit.py" + "${pkg_dir}" ${ARG_FILES}) + endif() + add_custom_command(TARGET ${swig_target} POST_BUILD VERBATIM + COMMAND ${CMAKE_COMMAND} -E make_directory ${pkg_dir} + ${copy_cmd} + ${init_cmd} + WORKING_DIRECTORY ${working_dir}) +endfunction() + +function(create_relative_symlink swig_target dest_file output_dir output_name) + get_filename_component(dest_file ${dest_file} ABSOLUTE) + get_filename_component(output_dir ${output_dir} ABSOLUTE) + file(RELATIVE_PATH rel_dest_file ${output_dir} ${dest_file}) + if(CMAKE_HOST_UNIX) + set(LLVM_LINK_OR_COPY create_symlink) + else() + set(LLVM_LINK_OR_COPY copy) + endif() + add_custom_command(TARGET ${swig_target} POST_BUILD VERBATIM + COMMAND ${CMAKE_COMMAND} -E ${LLVM_LINK_OR_COPY} ${rel_dest_file} ${output_name} + WORKING_DIRECTORY ${output_dir}) +endfunction() + +function(finish_swig_python swig_target lldb_python_bindings_dir lldb_python_target_dir) + # Add a Post-Build Event to copy over Python files and create the symlink to + # liblldb.so for the Python API(hardlink on Windows). + add_custom_target(${swig_target} ALL VERBATIM + COMMAND ${CMAKE_COMMAND} -E make_directory ${lldb_python_target_dir} + DEPENDS ${lldb_python_bindings_dir}/lldb.py + COMMENT "Python script sym-linking LLDB Python API") + + if(NOT LLDB_USE_SYSTEM_SIX) + add_custom_command(TARGET ${swig_target} POST_BUILD VERBATIM + COMMAND ${CMAKE_COMMAND} -E copy + "${LLDB_SOURCE_DIR}/third_party/Python/module/six/six.py" + "${lldb_python_target_dir}/../six.py") + endif() + + add_custom_command(TARGET ${swig_target} POST_BUILD VERBATIM + COMMAND ${CMAKE_COMMAND} -E copy + "${lldb_python_bindings_dir}/lldb.py" + "${lldb_python_target_dir}/__init__.py") + + add_custom_command(TARGET ${swig_target} POST_BUILD VERBATIM + COMMAND ${CMAKE_COMMAND} -E copy + "${LLDB_SOURCE_DIR}/source/Interpreter/embedded_interpreter.py" + "${lldb_python_target_dir}") + + # Distribute the examples as python packages. + create_python_package( + ${swig_target} + ${lldb_python_target_dir} + "formatters/cpp" + FILES "${LLDB_SOURCE_DIR}/examples/synthetic/gnu_libstdcpp.py" + "${LLDB_SOURCE_DIR}/examples/synthetic/libcxx.py") + + create_python_package( + ${swig_target} + ${lldb_python_target_dir} + "formatters" + FILES "${LLDB_SOURCE_DIR}/examples/summaries/cocoa/cache.py" + "${LLDB_SOURCE_DIR}/examples/summaries/synth.py" + "${LLDB_SOURCE_DIR}/examples/summaries/cocoa/metrics.py" + "${LLDB_SOURCE_DIR}/examples/summaries/cocoa/attrib_fromdict.py" + "${LLDB_SOURCE_DIR}/examples/summaries/cocoa/Logger.py") + + create_python_package( + ${swig_target} + ${lldb_python_target_dir} + "utils" + FILES "${LLDB_SOURCE_DIR}/examples/python/in_call_stack.py" + "${LLDB_SOURCE_DIR}/examples/python/symbolication.py") + + create_python_package( + ${swig_target} + ${lldb_python_target_dir} + "plugins" + FILES + "${LLDB_SOURCE_DIR}/examples/python/scripted_process/scripted_process.py") + + if(APPLE) + create_python_package( + ${swig_target} + ${lldb_python_target_dir} "macosx" + FILES "${LLDB_SOURCE_DIR}/examples/python/crashlog.py" + "${LLDB_SOURCE_DIR}/examples/darwin/heap_find/heap.py") + + create_python_package( + ${swig_target} + ${lldb_python_target_dir} "macosx/heap" + FILES "${LLDB_SOURCE_DIR}/examples/darwin/heap_find/heap/heap_find.cpp" + "${LLDB_SOURCE_DIR}/examples/darwin/heap_find/heap/Makefile" + NOINIT) + + create_python_package( + ${swig_target} + ${lldb_python_target_dir} "diagnose" + FILES "${LLDB_SOURCE_DIR}/examples/python/diagnose_unwind.py" + "${LLDB_SOURCE_DIR}/examples/python/diagnose_nsstring.py") + endif() + + if(LLDB_BUILD_FRAMEWORK) + set(LIBLLDB_SYMLINK_DEST "${LLDB_FRAMEWORK_ABSOLUTE_BUILD_DIR}/LLDB.framework/LLDB") + else() + set(LIBLLDB_SYMLINK_DEST "${LLVM_SHLIB_OUTPUT_INTDIR}/liblldb${CMAKE_SHARED_LIBRARY_SUFFIX}") + endif() + if(WIN32) + if(CMAKE_BUILD_TYPE STREQUAL Debug) + set(LIBLLDB_SYMLINK_OUTPUT_FILE "_lldb_d.pyd") + else() + set(LIBLLDB_SYMLINK_OUTPUT_FILE "_lldb.pyd") + endif() + else() + set(LIBLLDB_SYMLINK_OUTPUT_FILE "_lldb.so") + endif() + create_relative_symlink(${swig_target} ${LIBLLDB_SYMLINK_DEST} + ${lldb_python_target_dir} ${LIBLLDB_SYMLINK_OUTPUT_FILE}) + + if(NOT LLDB_BUILD_FRAMEWORK) + set(LLDB_ARGDUMPER_FILENAME "lldb-argdumper${CMAKE_EXECUTABLE_SUFFIX}") + create_relative_symlink(${swig_target} "${LLVM_RUNTIME_OUTPUT_INTDIR}/${LLDB_ARGDUMPER_FILENAME}" + ${lldb_python_target_dir} ${LLDB_ARGDUMPER_FILENAME}) + endif() + + add_dependencies(${swig_target} swig_wrapper_python liblldb lldb-argdumper) + set_target_properties(${swig_target} swig_wrapper_python PROPERTIES FOLDER "lldb misc") + + # Ensure we do the python post-build step when building lldb. + add_dependencies(lldb ${swig_target}) + + # Install the LLDB python module + if(LLDB_BUILD_FRAMEWORK) + set(LLDB_PYTHON_INSTALL_PATH ${LLDB_FRAMEWORK_INSTALL_DIR}/LLDB.framework/Resources/Python) + else() + set(LLDB_PYTHON_INSTALL_PATH ${LLDB_PYTHON_RELATIVE_PATH}) + endif() + if (NOT CMAKE_CFG_INTDIR STREQUAL ".") + string(REPLACE ${CMAKE_CFG_INTDIR} "\$\{CMAKE_INSTALL_CONFIG_NAME\}" LLDB_PYTHON_INSTALL_PATH ${LLDB_PYTHON_INSTALL_PATH}) + string(REPLACE ${CMAKE_CFG_INTDIR} "\$\{CMAKE_INSTALL_CONFIG_NAME\}" lldb_python_target_dir ${lldb_python_target_dir}) + endif() + set(python_scripts_target "${swig_target}-scripts") + set(python_scripts_install_target "install-${python_scripts_target}") + add_custom_target(${python_scripts_target}) + add_dependencies(${python_scripts_target} ${swig_target}) + install(DIRECTORY ${lldb_python_target_dir}/../ + DESTINATION ${LLDB_PYTHON_INSTALL_PATH} + COMPONENT ${python_scripts_target}) + if (NOT LLVM_ENABLE_IDE) + add_llvm_install_targets(${python_scripts_install_target} + COMPONENT ${python_scripts_target} + DEPENDS ${python_scripts_target}) + endif() + + # Add a Post-Build Event to copy the custom Python DLL to the lldb binaries dir so that Windows can find it when launching + # lldb.exe or any other executables that were linked with liblldb. + if (WIN32 AND NOT "${PYTHON_DLL}" STREQUAL "") + # When using the Visual Studio CMake generator the lldb binaries end up in Release/bin, Debug/bin etc. + file(TO_NATIVE_PATH "${CMAKE_BINARY_DIR}/${CMAKE_CFG_INTDIR}/bin" LLDB_BIN_DIR) + file(TO_NATIVE_PATH "${PYTHON_DLL}" PYTHON_DLL_NATIVE_PATH) + add_custom_command( + TARGET ${swig_target} + POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy ${PYTHON_DLL_NATIVE_PATH} ${LLDB_BIN_DIR} VERBATIM + COMMENT "Copying Python DLL to LLDB binaries directory.") + endif() +endfunction() diff --git a/gnu/llvm/lldb/bindings/python/python-extensions.swig b/gnu/llvm/lldb/bindings/python/python-extensions.swig index 0b23fdd4000..b98b0d458f0 100644 --- a/gnu/llvm/lldb/bindings/python/python-extensions.swig +++ b/gnu/llvm/lldb/bindings/python/python-extensions.swig @@ -290,6 +290,7 @@ class declaration(object): self.col = col class value_iter(object): + '''Allows iterating over the children of an :py:class:`SBValue`.''' def __iter__(self): return self @@ -311,19 +312,19 @@ class value_iter(object): self.length = self.sbvalue.GetNumChildren() class value(object): - '''A class designed to wrap lldb.SBValue() objects so the resulting object - can be used as a variable would be in code. So if you have a Point structure - variable in your code in the current frame named "pt", you can initialize an instance - of this class with it: - - pt = lldb.value(lldb.frame.FindVariable("pt")) - print pt - print pt.x - print pt.y - - pt = lldb.value(lldb.frame.FindVariable("rectangle_array")) - print rectangle_array[12] - print rectangle_array[5].origin.x''' + '''Wraps :py:class:`SBValue` objects so the resulting object can be used as a variable would be in code. + + So if you have a Point structure variable in your code in the current frame named "pt", + you can initialize an instance of this class with it: :: + + pt = lldb.value(lldb.frame.FindVariable("pt")) + print pt + print pt.x + print pt.y + + pt = lldb.value(lldb.frame.FindVariable("rectangle_array")) + print rectangle_array[12] + print rectangle_array[5].origin.x''' def __init__(self, sbvalue): self.sbvalue = sbvalue diff --git a/gnu/llvm/lldb/bindings/python/python-swigsafecast.swig b/gnu/llvm/lldb/bindings/python/python-swigsafecast.swig index d5cafbfa67c..091fc29b105 100644 --- a/gnu/llvm/lldb/bindings/python/python-swigsafecast.swig +++ b/gnu/llvm/lldb/bindings/python/python-swigsafecast.swig @@ -152,3 +152,10 @@ SBTypeToSWIGWrapper (lldb::SBSymbolContext* sym_ctx_sb) { return SWIG_NewPointerObj((void *) sym_ctx_sb, SWIGTYPE_p_lldb__SBSymbolContext, 0); } + +template <> +PyObject* +SBTypeToSWIGWrapper (lldb::SBStream* stream_sb) +{ + return SWIG_NewPointerObj((void *) stream_sb, SWIGTYPE_p_lldb__SBStream, 0); +} diff --git a/gnu/llvm/lldb/bindings/python/python-typemaps.h b/gnu/llvm/lldb/bindings/python/python-typemaps.h new file mode 100644 index 00000000000..b45352ad629 --- /dev/null +++ b/gnu/llvm/lldb/bindings/python/python-typemaps.h @@ -0,0 +1,17 @@ +#ifndef LLDB_BINDINGS_PYTHON_PYTHON_TYPEMAPS_H +#define LLDB_BINDINGS_PYTHON_PYTHON_TYPEMAPS_H + +// Defined here instead of a .swig file because SWIG 2 doesn't support +// explicit deleted functions. +struct Py_buffer_RAII { + Py_buffer buffer = {}; + Py_buffer_RAII(){}; + Py_buffer &operator=(const Py_buffer_RAII &) = delete; + Py_buffer_RAII(const Py_buffer_RAII &) = delete; + ~Py_buffer_RAII() { + if (buffer.obj) + PyBuffer_Release(&buffer); + } +}; + +#endif // LLDB_BINDINGS_PYTHON_PYTHON_TYPEMAPS_H diff --git a/gnu/llvm/lldb/bindings/python/python-typemaps.swig b/gnu/llvm/lldb/bindings/python/python-typemaps.swig index c08aeab71f7..b1ace4ff3b1 100644 --- a/gnu/llvm/lldb/bindings/python/python-typemaps.swig +++ b/gnu/llvm/lldb/bindings/python/python-typemaps.swig @@ -1,5 +1,11 @@ /* Typemap definitions, to allow SWIG to properly handle 'char**' data types. */ +%inline %{ + +#include "../bindings/python/python-typemaps.h" + +%} + %typemap(in) char ** { /* Check if is a list */ if (PythonList::Check($input)) { @@ -61,7 +67,7 @@ %typemap(in) lldb::tid_t { PythonObject obj = Retain($input); - lldb::tid_t value = unwrapOrSetPythonException(As(obj)); + lldb::tid_t value = unwrapOrSetPythonException(As(obj)); if (PyErr_Occurred()) return nullptr; $1 = value; @@ -476,21 +482,6 @@ bool SetNumberFromPyObject(double &number, PyObject *obj) { } } -%inline %{ - -struct Py_buffer_RAII { - Py_buffer buffer = {}; - Py_buffer_RAII() {}; - Py_buffer &operator=(const Py_buffer_RAII &) = delete; - Py_buffer_RAII(const Py_buffer_RAII &) = delete; - ~Py_buffer_RAII() { - if (buffer.obj) - PyBuffer_Release(&buffer); - } -}; - -%} - // These two pybuffer macros are copied out of swig/Lib/python/pybuffer.i, // and fixed so they will not crash if PyObject_GetBuffer fails. // https://github.com/swig/swig/issues/1640 diff --git a/gnu/llvm/lldb/bindings/python/python-wrapper.swig b/gnu/llvm/lldb/bindings/python/python-wrapper.swig index f9e89373fe2..4c39e9c2c77 100644 --- a/gnu/llvm/lldb/bindings/python/python-wrapper.swig +++ b/gnu/llvm/lldb/bindings/python/python-wrapper.swig @@ -39,6 +39,17 @@ private: // This function is called by lldb_private::ScriptInterpreterPython::BreakpointCallbackFunction(...) // and is used when a script command is attached to a breakpoint for execution. +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wreturn-type-c-linkage" + +// Disable warning C4190: 'LLDBSwigPythonBreakpointCallbackFunction' has +// C-linkage specified, but returns UDT 'llvm::Expected' which is +// incompatible with C +#if _MSC_VER +#pragma warning (push) +#pragma warning (disable : 4190) +#endif + SWIGEXPORT llvm::Expected LLDBSwigPythonBreakpointCallbackFunction ( @@ -85,6 +96,12 @@ LLDBSwigPythonBreakpointCallbackFunction return result.get().get() != Py_False; } +#if _MSC_VER +#pragma warning (pop) +#endif + +#pragma clang diagnostic pop + // This function is called by lldb_private::ScriptInterpreterPython::WatchpointCallbackFunction(...) // and is used when a script command is attached to a watchpoint for execution. @@ -258,6 +275,72 @@ LLDBSwigPythonCreateCommandObject Py_RETURN_NONE; } +SWIGEXPORT void* +LLDBSwigPythonCreateScriptedProcess +( + const char *python_class_name, + const char *session_dictionary_name, + const lldb::TargetSP& target_sp, + lldb_private::StructuredDataImpl *args_impl, + std::string &error_string +) +{ + if (python_class_name == NULL || python_class_name[0] == '\0' || !session_dictionary_name) + Py_RETURN_NONE; + + + PyErr_Cleaner py_err_cleaner(true); + + auto dict = PythonModule::MainModule().ResolveName(session_dictionary_name); + auto pfunc = PythonObject::ResolveNameWithDictionary(python_class_name, dict); + + if (!pfunc.IsAllocated()) { + error_string.append("could not find script class: "); + error_string.append(python_class_name); + return nullptr; + } + + // I do not want the SBTarget to be deallocated when going out of scope + // because python has ownership of it and will manage memory for this + // object by itself + PythonObject target_arg(PyRefType::Owned, SBTypeToSWIGWrapper(new lldb::SBTarget(target_sp))); + + if (!target_arg.IsAllocated()) + Py_RETURN_NONE; + + llvm::Expected arg_info = pfunc.GetArgInfo(); + if (!arg_info) { + llvm::handleAllErrors( + arg_info.takeError(), + [&](PythonException &E) { + error_string.append(E.ReadBacktrace()); + }, + [&](const llvm::ErrorInfoBase &E) { + error_string.append(E.message()); + }); + Py_RETURN_NONE; + } + + PythonObject result = {}; + if (arg_info.get().max_positional_args == 2) { + if (args_impl != nullptr) { + error_string.assign("args passed, but __init__ does not take an args dictionary"); + Py_RETURN_NONE; + } + result = pfunc(target_arg, dict); + } else if (arg_info.get().max_positional_args >= 3) { + PythonObject args_arg(PyRefType::Owned, SBTypeToSWIGWrapper(new lldb::SBStructuredData(args_impl))); + result = pfunc(target_arg, args_arg, dict); + } else { + error_string.assign("wrong number of arguments in __init__, should be 2 or 3 (not including self)"); + Py_RETURN_NONE; + } + + if (result.IsAllocated()) + return result.release(); + Py_RETURN_NONE; +} + SWIGEXPORT void* LLDBSwigPythonCreateScriptedThreadPlan ( @@ -271,9 +354,6 @@ LLDBSwigPythonCreateScriptedThreadPlan if (python_class_name == NULL || python_class_name[0] == '\0' || !session_dictionary_name) Py_RETURN_NONE; - // I do not want the SBThreadPlan to be deallocated when going out of scope because python - // has ownership of it and will manage memory for this object by itself - lldb::SBThreadPlan *tp_value = new lldb::SBThreadPlan(thread_plan_sp); PyErr_Cleaner py_err_cleaner(true); @@ -286,7 +366,10 @@ LLDBSwigPythonCreateScriptedThreadPlan return nullptr; } - PythonObject tp_arg(PyRefType::Owned, SBTypeToSWIGWrapper(tp_value)); + // I do not want the SBThreadPlan to be deallocated when going out of scope + // because python has ownership of it and will manage memory for this + // object by itself + PythonObject tp_arg(PyRefType::Owned, SBTypeToSWIGWrapper(new lldb::SBThreadPlan(thread_plan_sp))); if (!tp_arg.IsAllocated()) Py_RETURN_NONE; @@ -312,8 +395,7 @@ LLDBSwigPythonCreateScriptedThreadPlan } result = pfunc(tp_arg, dict); } else if (arg_info.get().max_positional_args >= 3) { - lldb::SBStructuredData *args_value = new lldb::SBStructuredData(args_impl); - PythonObject args_arg(PyRefType::Owned, SBTypeToSWIGWrapper(args_value)); + PythonObject args_arg(PyRefType::Owned, SBTypeToSWIGWrapper(new lldb::SBStructuredData(args_impl))); result = pfunc(tp_arg, args_arg, dict); } else { error_string.assign("wrong number of arguments in __init__, should be 2 or 3 (not including self)"); @@ -469,6 +551,127 @@ LLDBSwigPythonCallBreakpointResolver return ret_val; } +SWIGEXPORT void * +LLDBSwigPythonCreateScriptedStopHook +( + lldb::TargetSP target_sp, + const char *python_class_name, + const char *session_dictionary_name, + lldb_private::StructuredDataImpl *args_impl, + Status &error +) +{ + if (python_class_name == NULL || python_class_name[0] == '\0') { + error.SetErrorString("Empty class name."); + Py_RETURN_NONE; + } + if (!session_dictionary_name) { + error.SetErrorString("No session dictionary"); + Py_RETURN_NONE; + } + + PyErr_Cleaner py_err_cleaner(true); + + auto dict = + PythonModule::MainModule().ResolveName( + session_dictionary_name); + auto pfunc = + PythonObject::ResolveNameWithDictionary( + python_class_name, dict); + + if (!pfunc.IsAllocated()) { + error.SetErrorStringWithFormat("Could not find class: %s.", + python_class_name); + return nullptr; + } + + lldb::SBTarget *target_val + = new lldb::SBTarget(target_sp); + + PythonObject target_arg(PyRefType::Owned, SBTypeToSWIGWrapper(target_val)); + + lldb::SBStructuredData *args_value = new lldb::SBStructuredData(args_impl); + PythonObject args_arg(PyRefType::Owned, SBTypeToSWIGWrapper(args_value)); + + PythonObject result = pfunc(target_arg, args_arg, dict); + + if (result.IsAllocated()) + { + // Check that the handle_stop callback is defined: + auto callback_func = result.ResolveName("handle_stop"); + if (callback_func.IsAllocated()) { + if (auto args_info = callback_func.GetArgInfo()) { + size_t num_args = (*args_info).max_positional_args; + if (num_args != 2) { + error.SetErrorStringWithFormat("Wrong number of args for " + "handle_stop callback, should be 2 (excluding self), got: %zu", + num_args); + Py_RETURN_NONE; + } else + return result.release(); + } else { + error.SetErrorString("Couldn't get num arguments for handle_stop " + "callback."); + Py_RETURN_NONE; + } + return result.release(); + } + else { + error.SetErrorStringWithFormat("Class \"%s\" is missing the required " + "handle_stop callback.", + python_class_name); + result.release(); + } + } + Py_RETURN_NONE; +} + +SWIGEXPORT bool +LLDBSwigPythonStopHookCallHandleStop +( + void *implementor, + lldb::ExecutionContextRefSP exc_ctx_sp, + lldb::StreamSP stream +) +{ + // handle_stop will return a bool with the meaning "should_stop"... + // If you return nothing we'll assume we are going to stop. + // Also any errors should return true, since we should stop on error. + + PyErr_Cleaner py_err_cleaner(false); + PythonObject self(PyRefType::Borrowed, static_cast(implementor)); + auto pfunc = self.ResolveName("handle_stop"); + + if (!pfunc.IsAllocated()) + return true; + + PythonObject result; + lldb::SBExecutionContext sb_exc_ctx(exc_ctx_sp); + PythonObject exc_ctx_arg(PyRefType::Owned, SBTypeToSWIGWrapper(sb_exc_ctx)); + lldb::SBStream sb_stream; + PythonObject sb_stream_arg(PyRefType::Owned, + SBTypeToSWIGWrapper(sb_stream)); + result = pfunc(exc_ctx_arg, sb_stream_arg); + + if (PyErr_Occurred()) + { + stream->PutCString("Python error occurred handling stop-hook."); + PyErr_Print(); + PyErr_Clear(); + return true; + } + + // Now add the result to the output stream. SBStream only + // makes an internally help StreamString which I can't interpose, so I + // have to copy it over here. + stream->PutCString(sb_stream.GetData()); + + if (result.get() == Py_False) + return false; + else + return true; +} + // wrapper that calls an optional instance member of an object taking no arguments static PyObject* LLDBSwigPython_CallOptionalMember @@ -665,6 +868,40 @@ LLDBSwigPython_GetValueSynthProviderInstance return ret_val; } +SWIGEXPORT void* +LLDBSWIGPython_CastPyObjectToSBData +( + PyObject* data +) +{ + lldb::SBData* sb_ptr = nullptr; + + int valid_cast = SWIG_ConvertPtr(data, (void**)&sb_ptr, SWIGTYPE_p_lldb__SBData, 0); + + if (valid_cast == -1) + return NULL; + + return sb_ptr; +} + + +SWIGEXPORT void* +LLDBSWIGPython_CastPyObjectToSBError +( + PyObject* data +) +{ + lldb::SBError* sb_ptr = nullptr; + + int valid_cast = SWIG_ConvertPtr(data, (void**)&sb_ptr, SWIGTYPE_p_lldb__SBError, 0); + + if (valid_cast == -1) + return NULL; + + return sb_ptr; +} + + SWIGEXPORT void* LLDBSWIGPython_CastPyObjectToSBValue ( diff --git a/gnu/llvm/lldb/bindings/python/python.swig b/gnu/llvm/lldb/bindings/python/python.swig new file mode 100644 index 00000000000..9dc4ab87a4b --- /dev/null +++ b/gnu/llvm/lldb/bindings/python/python.swig @@ -0,0 +1,149 @@ +/* + lldb.swig + + This is the input file for SWIG, to create the appropriate C++ wrappers and + functions for various scripting languages, to enable them to call the + liblldb Script Bridge functions. +*/ + +/* Define our module docstring. */ +%define DOCSTRING +"The lldb module contains the public APIs for Python binding. + +Some of the important classes are described here: + +* :py:class:`SBTarget`: Represents the target program running under the debugger. +* :py:class:`SBProcess`: Represents the process associated with the target program. +* :py:class:`SBThread`: Represents a thread of execution. :py:class:`SBProcess` contains SBThreads. +* :py:class:`SBFrame`: Represents one of the stack frames associated with a thread. :py:class:`SBThread` + contains SBFrame(s). +* :py:class:`SBSymbolContext`: A container that stores various debugger related info. +* :py:class:`SBValue`: Represents the value of a variable, a register, or an expression. +* :py:class:`SBModule`: Represents an executable image and its associated object and symbol + files. :py:class:`SBTarget` contains SBModule. +* :py:class:`SBBreakpoint`: Represents a logical breakpoint and its associated settings. + :py:class:`SBTarget` contains SBBreakpoints. +* :py:class:`SBSymbol`: Represents the symbol possibly associated with a stack frame. +* :py:class:`SBCompileUnit`: Represents a compilation unit, or compiled source file. +* :py:class:`SBFunction`: Represents a generic function, which can be inlined or not. +* :py:class:`SBBlock`: Represents a lexical block. :py:class:`SBFunction` contains SBBlocks. +* :py:class:`SBLineEntry`: Specifies an association with a contiguous range of instructions + and a source file location. :py:class:`SBCompileUnit` contains SBLineEntry. + +The different enums in the `lldb` module are described in :doc:`python_api_enums`. + +" +%enddef + +/* +Since version 3.0.9, swig's logic for importing the native module has changed in +a way that is incompatible with our usage of the python module as __init__.py +(See swig bug #769). Fortunately, since version 3.0.11, swig provides a way for +us to override the module import logic to suit our needs. This does that. + +Older swig versions will simply ignore this setting. +*/ +%define MODULEIMPORT +"try: + # Try an absolute import first. If we're being loaded from lldb, + # _lldb should be a built-in module. + import $module +except ImportError: + # Relative import should work if we are being loaded by Python. + from . import $module" +%enddef +// These versions will not generate working python modules, so error out early. +#if SWIG_VERSION >= 0x030009 && SWIG_VERSION < 0x030011 +#error Swig versions 3.0.9 and 3.0.10 are incompatible with lldb. +#endif + +// The name of the module to be created. +%module(docstring=DOCSTRING, moduleimport=MODULEIMPORT) lldb + +// Parameter types will be used in the autodoc string. +%feature("autodoc", "1"); + +%define ARRAYHELPER(type,name) +%inline %{ +type *new_ ## name (int nitems) { + return (type *) malloc(sizeof(type)*nitems); +} +void delete_ ## name(type *t) { + free(t); +} +type name ## _get(type *t, int index) { + return t[index]; +} +void name ## _set(type *t, int index, type val) { + t[index] = val; +} +%} +%enddef + +%pythoncode%{ +import uuid +import re +import os + +import six +%} + +// Include the version of swig that was used to generate this interface. +%define EMBED_VERSION(VERSION) +%pythoncode%{ +# SWIG_VERSION is written as a single hex number, but the components of it are +# meant to be interpreted in decimal. So, 0x030012 is swig 3.0.12, and not +# 3.0.18. +def _to_int(hex): + return hex // 0x10 % 0x10 * 10 + hex % 0x10 +swig_version = (_to_int(VERSION // 0x10000), _to_int(VERSION // 0x100), _to_int(VERSION)) +del _to_int +%} +%enddef +EMBED_VERSION(SWIG_VERSION) + +%pythoncode%{ +# =================================== +# Iterator for lldb container objects +# =================================== +def lldb_iter(obj, getsize, getelem): + """A generator adaptor to support iteration for lldb container objects.""" + size = getattr(obj, getsize) + elem = getattr(obj, getelem) + for i in range(size()): + yield elem(i) +%} + +%include +%include "python-typemaps.swig" +%include "macros.swig" +%include "headers.swig" + +%{ +#include "../source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h" +#include "../bindings/python/python-swigsafecast.swig" +using namespace lldb_private; +using namespace lldb_private::python; +using namespace lldb; +%} + +%include "interfaces.swig" +%include "python-extensions.swig" +%include "python-wrapper.swig" + +%pythoncode%{ +_initialize = True +try: + import lldbconfig + _initialize = lldbconfig.INITIALIZE +except ImportError: + pass +debugger_unique_id = 0 +if _initialize: + SBDebugger.Initialize() +debugger = None +target = None +process = None +thread = None +frame = None +%} diff --git a/gnu/llvm/lldb/cmake/caches/Apple-lldb-macOS.cmake b/gnu/llvm/lldb/cmake/caches/Apple-lldb-macOS.cmake index 50421d269c9..2aef41157ba 100644 --- a/gnu/llvm/lldb/cmake/caches/Apple-lldb-macOS.cmake +++ b/gnu/llvm/lldb/cmake/caches/Apple-lldb-macOS.cmake @@ -2,6 +2,7 @@ include(${CMAKE_CURRENT_LIST_DIR}/Apple-lldb-base.cmake) set(LLDB_BUILD_FRAMEWORK ON CACHE BOOL "") set(LLDB_NO_INSTALL_DEFAULT_RPATH ON CACHE BOOL "") +set(LLDB_SKIP_STRIP ON CACHE BOOL "") set(CMAKE_OSX_DEPLOYMENT_TARGET 10.11 CACHE STRING "") # Default install location on the enduser machine. On the build machine, use the diff --git a/gnu/llvm/lldb/cmake/modules/AddLLDB.cmake b/gnu/llvm/lldb/cmake/modules/AddLLDB.cmake index 4ed5c647c5d..8be214a8509 100644 --- a/gnu/llvm/lldb/cmake/modules/AddLLDB.cmake +++ b/gnu/llvm/lldb/cmake/modules/AddLLDB.cmake @@ -276,19 +276,21 @@ function(lldb_add_post_install_steps_darwin name install_prefix) endif() # Generate dSYM - set(dsym_name ${output_name}.dSYM) - if(is_framework) - set(dsym_name ${output_name}.framework.dSYM) - endif() - if(LLDB_DEBUGINFO_INSTALL_PREFIX) - # This makes the path absolute, so we must respect DESTDIR. - set(dsym_name "\$ENV\{DESTDIR\}${LLDB_DEBUGINFO_INSTALL_PREFIX}/${dsym_name}") - endif() + if(NOT LLDB_SKIP_DSYM) + set(dsym_name ${output_name}.dSYM) + if(is_framework) + set(dsym_name ${output_name}.framework.dSYM) + endif() + if(LLDB_DEBUGINFO_INSTALL_PREFIX) + # This makes the path absolute, so we must respect DESTDIR. + set(dsym_name "\$ENV\{DESTDIR\}${LLDB_DEBUGINFO_INSTALL_PREFIX}/${dsym_name}") + endif() - set(buildtree_name ${buildtree_dir}/${bundle_subdir}${output_name}) - install(CODE "message(STATUS \"Externalize debuginfo: ${dsym_name}\")" COMPONENT ${name}) - install(CODE "execute_process(COMMAND xcrun dsymutil -o=${dsym_name} ${buildtree_name})" - COMPONENT ${name}) + set(buildtree_name ${buildtree_dir}/${bundle_subdir}${output_name}) + install(CODE "message(STATUS \"Externalize debuginfo: ${dsym_name}\")" COMPONENT ${name}) + install(CODE "execute_process(COMMAND xcrun dsymutil -o=${dsym_name} ${buildtree_name})" + COMPONENT ${name}) + endif() if(NOT LLDB_SKIP_STRIP) # Strip distribution binary with -ST (removing debug symbol table entries and diff --git a/gnu/llvm/lldb/cmake/modules/FindLuaAndSwig.cmake b/gnu/llvm/lldb/cmake/modules/FindLuaAndSwig.cmake index 968f905ef2d..f6251bbd104 100644 --- a/gnu/llvm/lldb/cmake/modules/FindLuaAndSwig.cmake +++ b/gnu/llvm/lldb/cmake/modules/FindLuaAndSwig.cmake @@ -7,7 +7,7 @@ if(LUA_LIBRARIES AND LUA_INCLUDE_DIR AND SWIG_EXECUTABLE) set(LUAANDSWIG_FOUND TRUE) else() - find_package(SWIG 2.0) + find_package(SWIG 3.0) if (SWIG_FOUND) find_package(Lua 5.3) if(LUA_FOUND AND SWIG_FOUND) @@ -17,7 +17,7 @@ else() SWIG_EXECUTABLE) endif() else() - message(STATUS "SWIG 2 or later is required for Lua support in LLDB but could not be found") + message(STATUS "SWIG 3 or later is required for Lua support in LLDB but could not be found") endif() include(FindPackageHandleStandardArgs) diff --git a/gnu/llvm/lldb/cmake/modules/FindPythonAndSwig.cmake b/gnu/llvm/lldb/cmake/modules/FindPythonAndSwig.cmake new file mode 100644 index 00000000000..3535b548c45 --- /dev/null +++ b/gnu/llvm/lldb/cmake/modules/FindPythonAndSwig.cmake @@ -0,0 +1,68 @@ +#.rst: +# FindPythonAndSwig +# ----------- +# +# Find the python interpreter and libraries as a whole. + +macro(FindPython3) + # Use PYTHON_HOME as a hint to find Python 3. + set(Python3_ROOT_DIR "${PYTHON_HOME}") + find_package(Python3 COMPONENTS Interpreter Development) + if(Python3_FOUND AND Python3_Interpreter_FOUND) + + # The install name for the Python 3 framework in Xcode is relative to + # the framework's location and not the dylib itself. + # + # @rpath/Python3.framework/Versions/3.x/Python3 + # + # This means that we need to compute the path to the Python3.framework + # and use that as the RPATH instead of the usual dylib's directory. + # + # The check below shouldn't match Homebrew's Python framework as it is + # called Python.framework instead of Python3.framework. + if (APPLE AND Python3_LIBRARIES MATCHES "Python3.framework") + string(FIND "${Python3_LIBRARIES}" "Python3.framework" python_framework_pos) + string(SUBSTRING "${Python3_LIBRARIES}" "0" ${python_framework_pos} Python3_RPATH) + endif() + + set(PYTHON3_FOUND TRUE) + mark_as_advanced( + Python3_LIBRARIES + Python3_INCLUDE_DIRS + Python3_EXECUTABLE + Python3_RPATH + SWIG_EXECUTABLE) + endif() +endmacro() + +if(Python3_LIBRARIES AND Python3_INCLUDE_DIRS AND Python3_EXECUTABLE AND SWIG_EXECUTABLE) + set(PYTHONANDSWIG_FOUND TRUE) +else() + find_package(SWIG 3.0) + if (SWIG_FOUND) + FindPython3() + else() + message(STATUS "SWIG 3 or later is required for Python support in LLDB but could not be found") + endif() + + get_property(MULTI_CONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) + if ("${Python3_VERSION}" VERSION_GREATER_EQUAL "3.7" AND + "${SWIG_VERSION}" VERSION_LESS "4.0" AND WIN32 AND ( + ${MULTI_CONFIG} OR (uppercase_CMAKE_BUILD_TYPE STREQUAL "DEBUG"))) + # Technically this can happen with non-Windows builds too, but we are not + # able to detect whether Python was built with assertions, and only Windows + # has the requirement that Debug LLDB must use Debug Python. + message(WARNING "Debug builds of LLDB are likely to be unusable due to " + ". Please use SWIG >= 4.0.") + endif() + + include(FindPackageHandleStandardArgs) + find_package_handle_standard_args(PythonAndSwig + FOUND_VAR + PYTHONANDSWIG_FOUND + REQUIRED_VARS + Python3_LIBRARIES + Python3_INCLUDE_DIRS + Python3_EXECUTABLE + SWIG_EXECUTABLE) +endif() diff --git a/gnu/llvm/lldb/cmake/modules/LLDBConfig.cmake b/gnu/llvm/lldb/cmake/modules/LLDBConfig.cmake index 8465cfe3b7b..b62cd7d2443 100644 --- a/gnu/llvm/lldb/cmake/modules/LLDBConfig.cmake +++ b/gnu/llvm/lldb/cmake/modules/LLDBConfig.cmake @@ -56,7 +56,7 @@ add_optional_dependency(LLDB_ENABLE_LIBEDIT "Enable editline support in LLDB" Li add_optional_dependency(LLDB_ENABLE_CURSES "Enable curses support in LLDB" CursesAndPanel CURSESANDPANEL_FOUND) add_optional_dependency(LLDB_ENABLE_LZMA "Enable LZMA compression support in LLDB" LibLZMA LIBLZMA_FOUND) add_optional_dependency(LLDB_ENABLE_LUA "Enable Lua scripting support in LLDB" LuaAndSwig LUAANDSWIG_FOUND) -add_optional_dependency(LLDB_ENABLE_PYTHON "Enable Python scripting support in LLDB" PythonInterpAndLibs PYTHONINTERPANDLIBS_FOUND) +add_optional_dependency(LLDB_ENABLE_PYTHON "Enable Python scripting support in LLDB" PythonAndSwig PYTHONANDSWIG_FOUND) add_optional_dependency(LLDB_ENABLE_LIBXML2 "Enable Libxml 2 support in LLDB" LibXml2 LIBXML2_FOUND VERSION 2.8) option(LLDB_USE_SYSTEM_SIX "Use six.py shipped with system and do not install a copy of it" OFF) @@ -65,6 +65,7 @@ option(LLDB_BUILD_FRAMEWORK "Build LLDB.framework (Darwin only)" OFF) option(LLDB_NO_INSTALL_DEFAULT_RPATH "Disable default RPATH settings in binaries" OFF) option(LLDB_USE_SYSTEM_DEBUGSERVER "Use the system's debugserver for testing (Darwin only)." OFF) option(LLDB_SKIP_STRIP "Whether to skip stripping of binaries when installing lldb." OFF) +option(LLDB_SKIP_DSYM "Whether to skip generating a dSYM when installing lldb." OFF) if (LLDB_USE_SYSTEM_DEBUGSERVER) # The custom target for the system debugserver has no install target, so we @@ -79,11 +80,6 @@ if(LLDB_BUILD_FRAMEWORK) if(NOT APPLE) message(FATAL_ERROR "LLDB.framework can only be generated when targeting Apple platforms") endif() - # CMake 3.6 did not correctly emit POST_BUILD commands for Apple Framework targets - # CMake < 3.8 did not have the BUILD_RPATH target property - if(CMAKE_VERSION VERSION_LESS 3.8) - message(FATAL_ERROR "LLDB_BUILD_FRAMEWORK is not supported on CMake < 3.8") - endif() set(LLDB_FRAMEWORK_VERSION A CACHE STRING "LLDB.framework version (default is A)") set(LLDB_FRAMEWORK_BUILD_DIR bin CACHE STRING "Output directory for LLDB.framework") @@ -148,9 +144,9 @@ if (LLDB_ENABLE_PYTHON) "Embed PYTHONHOME in the binary. If set to OFF, PYTHONHOME environment variable will be used to to locate Python." ${default_embed_python_home}) - include_directories(${PYTHON_INCLUDE_DIRS}) + include_directories(${Python3_INCLUDE_DIRS}) if (LLDB_EMBED_PYTHON_HOME) - get_filename_component(PYTHON_HOME "${PYTHON_EXECUTABLE}" DIRECTORY) + get_filename_component(PYTHON_HOME "${Python3_EXECUTABLE}" DIRECTORY) set(LLDB_PYTHON_HOME "${PYTHON_HOME}" CACHE STRING "Path to use as PYTHONHOME in lldb. If a relative path is specified, it will be resolved at runtime relative to liblldb directory.") endif() @@ -164,36 +160,21 @@ endif () include_directories("${CMAKE_CURRENT_BINARY_DIR}/../clang/include") # Disable GCC warnings -check_cxx_compiler_flag("-Wno-deprecated-declarations" - CXX_SUPPORTS_NO_DEPRECATED_DECLARATIONS) -if (CXX_SUPPORTS_NO_DEPRECATED_DECLARATIONS) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-deprecated-declarations") -endif () +check_cxx_compiler_flag("-Wno-deprecated-declarations" CXX_SUPPORTS_NO_DEPRECATED_DECLARATIONS) +append_if(CXX_SUPPORTS_NO_DEPRECATED_DECLARATIONS "-Wno-deprecated-declarations" CMAKE_CXX_FLAGS) -check_cxx_compiler_flag("-Wno-unknown-pragmas" - CXX_SUPPORTS_NO_UNKNOWN_PRAGMAS) -if (CXX_SUPPORTS_NO_UNKNOWN_PRAGMAS) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unknown-pragmas") -endif () +check_cxx_compiler_flag("-Wno-unknown-pragmas" CXX_SUPPORTS_NO_UNKNOWN_PRAGMAS) +append_if(CXX_SUPPORTS_NO_UNKNOWN_PRAGMAS "-Wno-unknown-pragmas" CMAKE_CXX_FLAGS) -check_cxx_compiler_flag("-Wno-strict-aliasing" - CXX_SUPPORTS_NO_STRICT_ALIASING) -if (CXX_SUPPORTS_NO_STRICT_ALIASING) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-strict-aliasing") -endif () +check_cxx_compiler_flag("-Wno-strict-aliasing" CXX_SUPPORTS_NO_STRICT_ALIASING) +append_if(CXX_SUPPORTS_NO_STRICT_ALIASING "-Wno-strict-aliasing" CMAKE_CXX_FLAGS) # Disable Clang warnings -check_cxx_compiler_flag("-Wno-deprecated-register" - CXX_SUPPORTS_NO_DEPRECATED_REGISTER) -if (CXX_SUPPORTS_NO_DEPRECATED_REGISTER) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-deprecated-register") -endif () +check_cxx_compiler_flag("-Wno-deprecated-register" CXX_SUPPORTS_NO_DEPRECATED_REGISTER) +append_if(CXX_SUPPORTS_NO_DEPRECATED_REGISTER "-Wno-deprecated-register" CMAKE_CXX_FLAGS) -check_cxx_compiler_flag("-Wno-vla-extension" - CXX_SUPPORTS_NO_VLA_EXTENSION) -if (CXX_SUPPORTS_NO_VLA_EXTENSION) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-vla-extension") -endif () +check_cxx_compiler_flag("-Wno-vla-extension" CXX_SUPPORTS_NO_VLA_EXTENSION) +append_if(CXX_SUPPORTS_NO_VLA_EXTENSION "-Wno-vla-extension" CMAKE_CXX_FLAGS) # Disable MSVC warnings if( MSVC ) @@ -248,7 +229,6 @@ if (NOT LLVM_INSTALL_TOOLCHAIN_ONLY) DESTINATION include FILES_MATCHING PATTERN "*.h" - PATTERN ".svn" EXCLUDE PATTERN ".cmake" EXCLUDE ) @@ -257,7 +237,6 @@ if (NOT LLVM_INSTALL_TOOLCHAIN_ONLY) DESTINATION include FILES_MATCHING PATTERN "*.h" - PATTERN ".svn" EXCLUDE PATTERN ".cmake" EXCLUDE ) @@ -270,9 +249,33 @@ if (NOT LLVM_INSTALL_TOOLCHAIN_ONLY) endif() endif() + +# If LLDB is building against a prebuilt Clang, then the Clang resource +# directory that LLDB is using for its embedded Clang instance needs to point +# to the resource directory of the used Clang installation. +if (NOT TARGET clang-resource-headers) + set(LLDB_CLANG_RESOURCE_DIR_NAME "${LLVM_VERSION_MAJOR}.${LLVM_VERSION_MINOR}.${LLVM_VERSION_PATCH}") + # Iterate over the possible places where the external resource directory + # could be and pick the first that exists. + foreach(CANDIDATE "${Clang_DIR}/../.." "${LLVM_DIR}" "${LLVM_LIBRARY_DIRS}" + "${LLVM_BUILD_LIBRARY_DIR}" + "${LLVM_BINARY_DIR}/lib${LLVM_LIBDIR_SUFFIX}") + # Build the resource directory path by appending 'clang/'. + set(CANDIDATE_RESOURCE_DIR "${CANDIDATE}/clang/${LLDB_CLANG_RESOURCE_DIR_NAME}") + if (IS_DIRECTORY "${CANDIDATE_RESOURCE_DIR}") + set(LLDB_EXTERNAL_CLANG_RESOURCE_DIR "${CANDIDATE_RESOURCE_DIR}") + break() + endif() + endforeach() + + if (NOT LLDB_EXTERNAL_CLANG_RESOURCE_DIR) + message(FATAL_ERROR "Expected directory for clang-resource headers not found: ${LLDB_EXTERNAL_CLANG_RESOURCE_DIR}") + endif() +endif() + # Find Apple-specific libraries or frameworks that may be needed. if (APPLE) - if(NOT IOS) + if(NOT APPLE_EMBEDDED) find_library(CARBON_LIBRARY Carbon) find_library(CORE_SERVICES_LIBRARY CoreServices) endif() @@ -312,5 +315,4 @@ if ((CMAKE_SYSTEM_NAME MATCHES "Android") AND LLVM_BUILD_STATIC AND add_definitions(-DANDROID_USE_ACCEPT_WORKAROUND) endif() -find_package(Backtrace) include(LLDBGenerateConfig) diff --git a/gnu/llvm/lldb/cmake/modules/LLDBFramework.cmake b/gnu/llvm/lldb/cmake/modules/LLDBFramework.cmake index c52daaa4fa8..2e82f497866 100644 --- a/gnu/llvm/lldb/cmake/modules/LLDBFramework.cmake +++ b/gnu/llvm/lldb/cmake/modules/LLDBFramework.cmake @@ -3,22 +3,38 @@ message(STATUS "LLDB.framework: install path is '${LLDB_FRAMEWORK_INSTALL_DIR}'" message(STATUS "LLDB.framework: resources subdirectory is 'Versions/${LLDB_FRAMEWORK_VERSION}/Resources'") # Configure liblldb as a framework bundle -set_target_properties(liblldb PROPERTIES - FRAMEWORK ON - FRAMEWORK_VERSION ${LLDB_FRAMEWORK_VERSION} +if(NOT APPLE_EMBEDDED) + set_target_properties(liblldb PROPERTIES + FRAMEWORK ON + FRAMEWORK_VERSION ${LLDB_FRAMEWORK_VERSION} - OUTPUT_NAME LLDB - VERSION ${LLDB_VERSION} - LIBRARY_OUTPUT_DIRECTORY ${LLDB_FRAMEWORK_ABSOLUTE_BUILD_DIR} + OUTPUT_NAME LLDB + VERSION ${LLDB_VERSION} + LIBRARY_OUTPUT_DIRECTORY ${LLDB_FRAMEWORK_ABSOLUTE_BUILD_DIR} - # Compatibility version - SOVERSION "1.0.0" + # Compatibility version + SOVERSION "1.0.0" - MACOSX_FRAMEWORK_IDENTIFIER com.apple.LLDB.framework - MACOSX_FRAMEWORK_BUNDLE_VERSION ${LLDB_VERSION} - MACOSX_FRAMEWORK_SHORT_VERSION_STRING ${LLDB_VERSION} - MACOSX_FRAMEWORK_INFO_PLIST ${LLDB_SOURCE_DIR}/resources/LLDB-Info.plist.in -) + MACOSX_FRAMEWORK_IDENTIFIER com.apple.LLDB.framework + MACOSX_FRAMEWORK_BUNDLE_VERSION ${LLDB_VERSION} + MACOSX_FRAMEWORK_SHORT_VERSION_STRING ${LLDB_VERSION} + MACOSX_FRAMEWORK_INFO_PLIST ${LLDB_SOURCE_DIR}/resources/LLDB-Info.plist.in + ) +else() + set_target_properties(liblldb PROPERTIES + FRAMEWORK ON + FRAMEWORK_VERSION ${LLDB_FRAMEWORK_VERSION} + + # Note: iOS doesn't specify version, as the framework layout is flat. + OUTPUT_NAME LLDB + LIBRARY_OUTPUT_DIRECTORY ${LLDB_FRAMEWORK_ABSOLUTE_BUILD_DIR} + + MACOSX_FRAMEWORK_IDENTIFIER com.apple.LLDB.framework + MACOSX_FRAMEWORK_BUNDLE_VERSION ${LLDB_VERSION} + MACOSX_FRAMEWORK_SHORT_VERSION_STRING ${LLDB_VERSION} + MACOSX_FRAMEWORK_INFO_PLIST ${LLDB_SOURCE_DIR}/resources/LLDB-Info.plist.in + ) +endif() # Used in llvm_add_library() to set default output directories for multi-config # generators. Overwrite to account for special framework output directory. @@ -30,7 +46,7 @@ set_output_directory(liblldb lldb_add_post_install_steps_darwin(liblldb ${LLDB_FRAMEWORK_INSTALL_DIR}) # Affects the layout of the framework bundle (default is macOS layout). -if(IOS) +if(APPLE_EMBEDDED) set_target_properties(liblldb PROPERTIES XCODE_ATTRIBUTE_IPHONEOS_DEPLOYMENT_TARGET "${IPHONEOS_DEPLOYMENT_TARGET}") else() @@ -41,13 +57,16 @@ endif() # Add -Wdocumentation parameter set(CMAKE_XCODE_ATTRIBUTE_CLANG_WARN_DOCUMENTATION_COMMENTS "YES") -# Apart from this one, CMake creates all required symlinks in the framework bundle. -add_custom_command(TARGET liblldb POST_BUILD - COMMAND ${CMAKE_COMMAND} -E create_symlink - Versions/Current/Headers - ${LLDB_FRAMEWORK_ABSOLUTE_BUILD_DIR}/LLDB.framework/Headers - COMMENT "LLDB.framework: create Headers symlink" -) +# On iOS, there is no versioned framework layout. Skip this symlink step. +if(NOT APPLE_EMBEDDED) + # Apart from this one, CMake creates all required symlinks in the framework bundle. + add_custom_command(TARGET liblldb POST_BUILD + COMMAND ${CMAKE_COMMAND} -E create_symlink + Versions/Current/Headers + ${LLDB_FRAMEWORK_ABSOLUTE_BUILD_DIR}/LLDB.framework/Headers + COMMENT "LLDB.framework: create Headers symlink" + ) +endif() # At configuration time, collect headers for the framework bundle and copy them # into a staging directory. Later we can copy over the entire folder. @@ -79,34 +98,19 @@ add_dependencies(liblldb liblldb-resource-headers) # At build time, copy the staged headers into the framework bundle (and do # some post-processing in-place). -if (NOT IOS) add_custom_command(TARGET liblldb POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_directory ${lldb_header_staging} $/Headers COMMAND ${LLDB_SOURCE_DIR}/scripts/framework-header-fix.sh $/Headers ${LLDB_VERSION} COMMENT "LLDB.framework: copy framework headers" ) -endif() # Copy vendor-specific headers from clang (without staging). -if(NOT IOS) +if(NOT APPLE_EMBEDDED) if (TARGET clang-resource-headers) add_dependencies(liblldb clang-resource-headers) set(clang_resource_headers_dir $) else() - # In standalone builds try the best possible guess - if(Clang_DIR) - set(clang_lib_dir ${Clang_DIR}/../..) - elseif(LLVM_DIR) - set(clang_lib_dir ${LLVM_DIR}/../..) - elseif(LLVM_LIBRARY_DIRS) - set(clang_lib_dir ${LLVM_LIBRARY_DIRS}) - elseif(LLVM_BUILD_LIBRARY_DIR) - set(clang_lib_dir ${LLVM_BUILD_LIBRARY_DIR}) - elseif(LLVM_BINARY_DIR) - set(clang_lib_dir ${LLVM_BINARY_DIR}/lib${LLVM_LIBDIR_SUFFIX}) - endif() - set(clang_version ${LLVM_VERSION_MAJOR}.${LLVM_VERSION_MINOR}.${LLVM_VERSION_PATCH}) - set(clang_resource_headers_dir ${clang_lib_dir}/clang/${clang_version}/include) + set(clang_resource_headers_dir ${LLDB_EXTERNAL_CLANG_RESOURCE_DIR}/include) if(NOT EXISTS ${clang_resource_headers_dir}) message(WARNING "Expected directory for clang-resource headers not found: ${clang_resource_headers_dir}") endif() diff --git a/gnu/llvm/lldb/cmake/modules/LLDBGenerateConfig.cmake b/gnu/llvm/lldb/cmake/modules/LLDBGenerateConfig.cmake index 0d3a7fdb181..caeb3969002 100644 --- a/gnu/llvm/lldb/cmake/modules/LLDBGenerateConfig.cmake +++ b/gnu/llvm/lldb/cmake/modules/LLDBGenerateConfig.cmake @@ -7,6 +7,7 @@ include(CheckLibraryExists) set(CMAKE_REQUIRED_DEFINITIONS -D_GNU_SOURCE) check_symbol_exists(ppoll poll.h HAVE_PPOLL) +check_symbol_exists(ptsname_r stdlib.h HAVE_PTSNAME_R) set(CMAKE_REQUIRED_DEFINITIONS) check_symbol_exists(sigaction signal.h HAVE_SIGACTION) check_cxx_symbol_exists(accept4 "sys/socket.h" HAVE_ACCEPT4) diff --git a/gnu/llvm/lldb/cmake/modules/LLDBStandalone.cmake b/gnu/llvm/lldb/cmake/modules/LLDBStandalone.cmake index 752113bcc6c..98d7848ce99 100644 --- a/gnu/llvm/lldb/cmake/modules/LLDBStandalone.cmake +++ b/gnu/llvm/lldb/cmake/modules/LLDBStandalone.cmake @@ -10,6 +10,8 @@ set(LLVM_MAIN_SRC_DIR ${LLVM_BUILD_MAIN_SRC_DIR} CACHE PATH "Path to LLVM source set(LLVM_MAIN_INCLUDE_DIR ${LLVM_MAIN_INCLUDE_DIR} CACHE PATH "Path to llvm/include") set(LLVM_BINARY_DIR ${LLVM_BINARY_DIR} CACHE PATH "Path to LLVM build tree") +set(LLVM_LIT_ARGS "-sv" CACHE STRING "Default options for lit") + set(lit_file_name "llvm-lit") if(CMAKE_HOST_WIN32 AND NOT CYGWIN) set(lit_file_name "${lit_file_name}.py") @@ -73,6 +75,7 @@ endif() # We append the directory in which LLVMConfig.cmake lives. We expect LLVM's # CMake modules to be in that directory as well. list(APPEND CMAKE_MODULE_PATH "${LLVM_DIR}") + include(AddLLVM) include(TableGen) include(HandleLLVMOptions) diff --git a/gnu/llvm/lldb/docs/.htaccess b/gnu/llvm/lldb/docs/.htaccess index 596f4481ab4..91b25fb504f 100644 --- a/gnu/llvm/lldb/docs/.htaccess +++ b/gnu/llvm/lldb/docs/.htaccess @@ -1,3 +1,4 @@ +# Old website redirects Redirect 301 /architecture/index.html https://lldb.llvm.org/resources/architecture.html Redirect 301 /cpp_reference/html/index.html https://lldb.llvm.org/cpp_reference/index.html Redirect 301 /features.html https://lldb.llvm.org/status/features.html @@ -10,7 +11,95 @@ Redirect 301 /source.html https://lldb.llvm.org/resources/contributing.html Redirect 301 /tutorial.html https://lldb.llvm.org/use/tutorial.html Redirect 301 /varformats.html https://lldb.llvm.org/use/variable.html -# Sphinx redirects +# Current website redirects Redirect 301 /resources/source.html https://lldb.llvm.org/resources/contributing.html Redirect 301 /resources/download.html https://lldb.llvm.org/status/releases.html Redirect 301 /use/architecture.html https://lldb.llvm.org/resources/architecture.html +Redirect 301 /resources/architecture.html https://lldb.llvm.org/design/overview.html +Redirect 301 /resources/reproducers.html https://lldb.llvm.org/design/reproducers.html +Redirect 301 /resources/sbapi.html https://lldb.llvm.org/design/sbapi.html + +# Redirect old Python API to new Python API. +Redirect 301 /python_reference/lldb-module.html https://lldb.llvm.org/python_api.html + +Redirect 301 /python_reference/lldb.SBAddress-class.html https://lldb.llvm.org/python_api/lldb.SBAddress.html +Redirect 301 /python_reference/lldb.SBAttachInfo-class.html https://lldb.llvm.org/python_api/lldb.SBAttachInfo.html +Redirect 301 /python_reference/lldb.SBBlock-class.html https://lldb.llvm.org/python_api/lldb.SBBlock.html +Redirect 301 /python_reference/lldb.SBBreakpoint-class.html https://lldb.llvm.org/python_api/lldb.SBBreakpoint.html +Redirect 301 /python_reference/lldb.SBBreakpointList-class.html https://lldb.llvm.org/python_api/lldb.SBBreakpointList.html +Redirect 301 /python_reference/lldb.SBBreakpointLocation-class.html https://lldb.llvm.org/python_api/lldb.SBBreakpointLocation.html +Redirect 301 /python_reference/lldb.SBBreakpointName-class.html https://lldb.llvm.org/python_api/lldb.SBBreakpointName.html +Redirect 301 /python_reference/lldb.SBBroadcaster-class.html https://lldb.llvm.org/python_api/lldb.SBBroadcaster.html +Redirect 301 /python_reference/lldb.SBCommandInterpreter-class.html https://lldb.llvm.org/python_api/lldb.SBCommandInterpreter.html +Redirect 301 /python_reference/lldb.SBCommandInterpreterRunOptions-class.html https://lldb.llvm.org/python_api/lldb.SBCommandInterpreterRunOptions.html +Redirect 301 /python_reference/lldb.SBCommandReturnObject-class.html https://lldb.llvm.org/python_api/lldb.SBCommandReturnObject.html +Redirect 301 /python_reference/lldb.SBCommunication-class.html https://lldb.llvm.org/python_api/lldb.SBCommunication.html +Redirect 301 /python_reference/lldb.SBCompileUnit-class.html https://lldb.llvm.org/python_api/lldb.SBCompileUnit.html +Redirect 301 /python_reference/lldb.SBData-class.html https://lldb.llvm.org/python_api/lldb.SBData.html +Redirect 301 /python_reference/lldb.SBDebugger-class.html https://lldb.llvm.org/python_api/lldb.SBDebugger.html +Redirect 301 /python_reference/lldb.SBDeclaration-class.html https://lldb.llvm.org/python_api/lldb.SBDeclaration.html +Redirect 301 /python_reference/lldb.SBEnvironment-class.html https://lldb.llvm.org/python_api/lldb.SBEnvironment.html +Redirect 301 /python_reference/lldb.SBError-class.html https://lldb.llvm.org/python_api/lldb.SBError.html +Redirect 301 /python_reference/lldb.SBEvent-class.html https://lldb.llvm.org/python_api/lldb.SBEvent.html +Redirect 301 /python_reference/lldb.SBExecutionContext-class.html https://lldb.llvm.org/python_api/lldb.SBExecutionContext.html +Redirect 301 /python_reference/lldb.SBExpressionOptions-class.html https://lldb.llvm.org/python_api/lldb.SBExpressionOptions.html +Redirect 301 /python_reference/lldb.SBFile-class.html https://lldb.llvm.org/python_api/lldb.SBFile.html +Redirect 301 /python_reference/lldb.SBFileSpec-class.html https://lldb.llvm.org/python_api/lldb.SBFileSpec.html +Redirect 301 /python_reference/lldb.SBFileSpecList-class.html https://lldb.llvm.org/python_api/lldb.SBFileSpecList.html +Redirect 301 /python_reference/lldb.SBFrame-class.html https://lldb.llvm.org/python_api/lldb.SBFrame.html +Redirect 301 /python_reference/lldb.SBFunction-class.html https://lldb.llvm.org/python_api/lldb.SBFunction.html +Redirect 301 /python_reference/lldb.SBHostOS-class.html https://lldb.llvm.org/python_api/lldb.SBHostOS.html +Redirect 301 /python_reference/lldb.SBInstruction-class.html https://lldb.llvm.org/python_api/lldb.SBInstruction.html +Redirect 301 /python_reference/lldb.SBInstructionList-class.html https://lldb.llvm.org/python_api/lldb.SBInstructionList.html +Redirect 301 /python_reference/lldb.SBLanguageRuntime-class.html https://lldb.llvm.org/python_api/lldb.SBLanguageRuntime.html +Redirect 301 /python_reference/lldb.SBLaunchInfo-class.html https://lldb.llvm.org/python_api/lldb.SBLaunchInfo.html +Redirect 301 /python_reference/lldb.SBLineEntry-class.html https://lldb.llvm.org/python_api/lldb.SBLineEntry.html +Redirect 301 /python_reference/lldb.SBListener-class.html https://lldb.llvm.org/python_api/lldb.SBListener.html +Redirect 301 /python_reference/lldb.SBMemoryRegionInfo-class.html https://lldb.llvm.org/python_api/lldb.SBMemoryRegionInfo.html +Redirect 301 /python_reference/lldb.SBMemoryRegionInfoList-class.html https://lldb.llvm.org/python_api/lldb.SBMemoryRegionInfoList.html +Redirect 301 /python_reference/lldb.SBModule-class.html https://lldb.llvm.org/python_api/lldb.SBModule.html +Redirect 301 /python_reference/lldb.SBModuleSpec-class.html https://lldb.llvm.org/python_api/lldb.SBModuleSpec.html +Redirect 301 /python_reference/lldb.SBModuleSpecList-class.html https://lldb.llvm.org/python_api/lldb.SBModuleSpecList.html +Redirect 301 /python_reference/lldb.SBPlatform-class.html https://lldb.llvm.org/python_api/lldb.SBPlatform.html +Redirect 301 /python_reference/lldb.SBPlatformConnectOptions-class.html https://lldb.llvm.org/python_api/lldb.SBPlatformConnectOptions.html +Redirect 301 /python_reference/lldb.SBPlatformShellCommand-class.html https://lldb.llvm.org/python_api/lldb.SBPlatformShellCommand.html +Redirect 301 /python_reference/lldb.SBProcess-class.html https://lldb.llvm.org/python_api/lldb.SBProcess.html +Redirect 301 /python_reference/lldb.SBProcessInfo-class.html https://lldb.llvm.org/python_api/lldb.SBProcessInfo.html +Redirect 301 /python_reference/lldb.SBQueue-class.html https://lldb.llvm.org/python_api/lldb.SBQueue.html +Redirect 301 /python_reference/lldb.SBQueueItem-class.html https://lldb.llvm.org/python_api/lldb.SBQueueItem.html +Redirect 301 /python_reference/lldb.SBReproducer-class.html https://lldb.llvm.org/python_api/lldb.SBReproducer.html +Redirect 301 /python_reference/lldb.SBSection-class.html https://lldb.llvm.org/python_api/lldb.SBSection.html +Redirect 301 /python_reference/lldb.SBSourceManager-class.html https://lldb.llvm.org/python_api/lldb.SBSourceManager.html +Redirect 301 /python_reference/lldb.SBStream-class.html https://lldb.llvm.org/python_api/lldb.SBStream.html +Redirect 301 /python_reference/lldb.SBStringList-class.html https://lldb.llvm.org/python_api/lldb.SBStringList.html +Redirect 301 /python_reference/lldb.SBStructuredData-class.html https://lldb.llvm.org/python_api/lldb.SBStructuredData.html +Redirect 301 /python_reference/lldb.SBSymbol-class.html https://lldb.llvm.org/python_api/lldb.SBSymbol.html +Redirect 301 /python_reference/lldb.SBSymbolContext-class.html https://lldb.llvm.org/python_api/lldb.SBSymbolContext.html +Redirect 301 /python_reference/lldb.SBSymbolContextList-class.html https://lldb.llvm.org/python_api/lldb.SBSymbolContextList.html +Redirect 301 /python_reference/lldb.SBSyntheticValueProvider-class.html https://lldb.llvm.org/python_api/lldb.SBSyntheticValueProvider.html +Redirect 301 /python_reference/lldb.SBTarget-class.html https://lldb.llvm.org/python_api/lldb.SBTarget.html +Redirect 301 /python_reference/lldb.SBThread-class.html https://lldb.llvm.org/python_api/lldb.SBThread.html +Redirect 301 /python_reference/lldb.SBThreadCollection-class.html https://lldb.llvm.org/python_api/lldb.SBThreadCollection.html +Redirect 301 /python_reference/lldb.SBThreadPlan-class.html https://lldb.llvm.org/python_api/lldb.SBThreadPlan.html +Redirect 301 /python_reference/lldb.SBTrace-class.html https://lldb.llvm.org/python_api/lldb.SBTrace.html +Redirect 301 /python_reference/lldb.SBType-class.html https://lldb.llvm.org/python_api/lldb.SBType.html +Redirect 301 /python_reference/lldb.SBTypeCategory-class.html https://lldb.llvm.org/python_api/lldb.SBTypeCategory.html +Redirect 301 /python_reference/lldb.SBTypeEnumMember-class.html https://lldb.llvm.org/python_api/lldb.SBTypeEnumMember.html +Redirect 301 /python_reference/lldb.SBTypeEnumMemberList-class.html https://lldb.llvm.org/python_api/lldb.SBTypeEnumMemberList.html +Redirect 301 /python_reference/lldb.SBTypeFilter-class.html https://lldb.llvm.org/python_api/lldb.SBTypeFilter.html +Redirect 301 /python_reference/lldb.SBTypeFormat-class.html https://lldb.llvm.org/python_api/lldb.SBTypeFormat.html +Redirect 301 /python_reference/lldb.SBTypeList-class.html https://lldb.llvm.org/python_api/lldb.SBTypeList.html +Redirect 301 /python_reference/lldb.SBTypeMember-class.html https://lldb.llvm.org/python_api/lldb.SBTypeMember.html +Redirect 301 /python_reference/lldb.SBTypeMemberFunction-class.html https://lldb.llvm.org/python_api/lldb.SBTypeMemberFunction.html +Redirect 301 /python_reference/lldb.SBTypeNameSpecifier-class.html https://lldb.llvm.org/python_api/lldb.SBTypeNameSpecifier.html +Redirect 301 /python_reference/lldb.SBTypeSummary-class.html https://lldb.llvm.org/python_api/lldb.SBTypeSummary.html +Redirect 301 /python_reference/lldb.SBTypeSummaryOptions-class.html https://lldb.llvm.org/python_api/lldb.SBTypeSummaryOptions.html +Redirect 301 /python_reference/lldb.SBTypeSynthetic-class.html https://lldb.llvm.org/python_api/lldb.SBTypeSynthetic.html +Redirect 301 /python_reference/lldb.SBUnixSignals-class.html https://lldb.llvm.org/python_api/lldb.SBUnixSignals.html +Redirect 301 /python_reference/lldb.SBValue-class.html https://lldb.llvm.org/python_api/lldb.SBValue.html +Redirect 301 /python_reference/lldb.SBValueList-class.html https://lldb.llvm.org/python_api/lldb.SBValueList.html +Redirect 301 /python_reference/lldb.SBVariablesOptions-class.html https://lldb.llvm.org/python_api/lldb.SBVariablesOptions.html +Redirect 301 /python_reference/lldb.SBWatchpoint-class.html https://lldb.llvm.org/python_api/lldb.SBWatchpoint.html +Redirect 301 /python_reference/lldb.declaration-class.html https://lldb.llvm.org/python_api/lldb.declaration.html +Redirect 301 /python_reference/lldb.value-class.html https://lldb.llvm.org/python_api/lldb.value.html +Redirect 301 /python_reference/lldb.value_iter-class.html https://lldb.llvm.org/python_api/lldb.value_iter.html diff --git a/gnu/llvm/lldb/docs/CMakeLists.txt b/gnu/llvm/lldb/docs/CMakeLists.txt index 8fa46860e5c..af18eb22e95 100644 --- a/gnu/llvm/lldb/docs/CMakeLists.txt +++ b/gnu/llvm/lldb/docs/CMakeLists.txt @@ -15,60 +15,39 @@ if(DOXYGEN_FOUND) ) endif() -if (LLDB_ENABLE_PYTHON) - find_program(EPYDOC_EXECUTABLE NAMES epydoc epydoc.py) - if(EPYDOC_EXECUTABLE) - message(STATUS "Found epydoc - ${EPYDOC_EXECUTABLE}") - - find_program(DOT_EXECUTABLE dot) - if(DOT_EXECUTABLE) - set(EPYDOC_OPTIONS ${EPYDOC_OPTIONS} --graph all --dotpath ${DOT_EXECUTABLE}) - message(STATUS "Found dot - ${DOT_EXECUTABLE}") - endif() +if (LLVM_ENABLE_SPHINX) + include(AddSphinxTarget) +endif() - # Pretend to make a python package so that we can generate the reference. - # Because we don't build liblldb, epydoc will complain that the import of - # _lldb.so failed, but that doesn't prevent it from generating the docs. +if (LLDB_ENABLE_PYTHON AND SPHINX_FOUND) + if (${SPHINX_OUTPUT_HTML}) + # Pretend that the SWIG generated API is a Python package. file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/lldb) - get_target_property(lldb_bindings_dir swig_wrapper BINARY_DIR) + get_target_property(lldb_bindings_dir swig_wrapper_python BINARY_DIR) add_custom_target(lldb-python-doc-package COMMAND "${CMAKE_COMMAND}" -E copy "${lldb_bindings_dir}/lldb.py" "${CMAKE_CURRENT_BINARY_DIR}/lldb/__init__.py" - COMMENT "Copying lldb.py to pretend package.") - add_dependencies(lldb-python-doc-package swig_wrapper) - - set(DOC_DIR "${CMAKE_CURRENT_SOURCE_DIR}/doc") - file(MAKE_DIRECTORY "${DOC_DIR}") - add_custom_target(lldb-python-doc - ${EPYDOC_EXECUTABLE} - --html - lldb - -o ${CMAKE_CURRENT_BINARY_DIR}/python_reference - --name "LLDB python API" - --url "http://lldb.llvm.org" - ${EPYDOC_OPTIONS} - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - COMMENT "Generating LLDB Python API reference with epydoc" VERBATIM - ) - add_dependencies(lldb-python-doc swig_wrapper lldb-python-doc-package) - else() - message(STATUS "Could NOT find epydoc") + COMMENT "Copying lldb.py to pretend its a Python package.") + add_dependencies(lldb-python-doc-package swig_wrapper_python) + + # FIXME: Don't treat Sphinx warnings as errors. The files generated by + # automodapi are full of warnings (partly caused by SWIG, our documentation + # and probably also automodapi itself), so those warnings need to be fixed + # first before we can turn this on. + set(SPHINX_WARNINGS_AS_ERRORS Off) + + # The sphinx config needs to know where the generated LLDB Python module is. + # There is no way to pass a variable into our sphinx config, so just pass + # the path to the module via the LLDB_SWIG_MODULE environment variable. + add_sphinx_target(html lldb ENV_VARS "LLDB_SWIG_MODULE=${CMAKE_CURRENT_BINARY_DIR}") + # Sphinx does not reliably update the custom CSS files, so force + # a clean rebuild of the documentation every time. + add_custom_target(clean-lldb-html COMMAND "${CMAKE_COMMAND}" -E + remove_directory ${CMAKE_CURRENT_BINARY_DIR}/html) + add_dependencies(docs-lldb-html swig_wrapper_python + lldb-python-doc-package clean-lldb-html) endif() -endif () - -if (LLVM_ENABLE_SPHINX) - include(AddSphinxTarget) - if (SPHINX_FOUND) - if (${SPHINX_OUTPUT_HTML}) - add_sphinx_target(html lldb) - # Sphinx does not reliably update the custom CSS files, so force - # a clean rebuild of the documentation every time. - add_custom_target(clean-lldb-html COMMAND "${CMAKE_COMMAND}" -E - remove_directory ${CMAKE_CURRENT_BINARY_DIR}/html) - add_dependencies(docs-lldb-html clean-lldb-html) - endif() - if (${SPHINX_OUTPUT_MAN}) - add_sphinx_target(man lldb) - endif() + if (${SPHINX_OUTPUT_MAN}) + add_sphinx_target(man lldb) endif() endif() diff --git a/gnu/llvm/lldb/docs/_lldb/__init__.py b/gnu/llvm/lldb/docs/_lldb/__init__.py new file mode 100644 index 00000000000..084252e46e5 --- /dev/null +++ b/gnu/llvm/lldb/docs/_lldb/__init__.py @@ -0,0 +1,9 @@ +from unittest.mock import Mock +import sys +import types + +# This package acts as a mock implementation of the native _lldb module so +# that generating the LLDB documentation doesn't actually require building all +# of LLDB. +module_name = '_lldb' +sys.modules[module_name] = Mock() diff --git a/gnu/llvm/lldb/docs/_static/lldb.css b/gnu/llvm/lldb/docs/_static/lldb.css index 53b72594083..e1e49f84c90 100644 --- a/gnu/llvm/lldb/docs/_static/lldb.css +++ b/gnu/llvm/lldb/docs/_static/lldb.css @@ -44,6 +44,13 @@ table.mapping td.content { padding-bottom: 15px; } +/* Workaround for a Safari bug that would otherwise make table cells less wide +than the containing text. This just sets it back to the default browser +property.*/ +td { + -webkit-hyphens: manual !important; +} + div.sphinxsidebar .caption { font-family: Helvetica, Verdana, sans-serif; font-size: 10pt; diff --git a/gnu/llvm/lldb/docs/conf.py b/gnu/llvm/lldb/docs/conf.py index ca1d6f79092..0c3cd59fc11 100644 --- a/gnu/llvm/lldb/docs/conf.py +++ b/gnu/llvm/lldb/docs/conf.py @@ -10,14 +10,30 @@ # # All configuration values have a default; values that are commented out # serve to show the default. +from __future__ import print_function -import sys, os +import sys, os, re from datetime import date -# If extensions (or modules to document with autodoc) are in another directory, -# add these directories to sys.path here. If the directory is relative to the -# documentation root, use os.path.abspath to make it absolute, like shown here. -#sys.path.insert(0, os.path.abspath('.')) +building_man_page = tags.has('builder-man') + +# For the website we need to setup the path to the generated LLDB module that +# we can generate documentation for its API. +if not building_man_page: + # If extensions (or modules to document with autodoc) are in another directory, + # add these directories to sys.path here. If the directory is relative to the + # documentation root, use os.path.abspath to make it absolute, like shown here. + + # Add the current directory that contains the mock _lldb native module which + # is imported by the `lldb` module. + sys.path.insert(0, os.path.abspath(".")) + # Add the build directory that contains the `lldb` module. LLDB_SWIG_MODULE is + # set by CMake. + sys.path.insert(0, os.getenv("LLDB_SWIG_MODULE")) + +# Put the generated Python API documentation in the 'python_api' folder. This +# also defines the URL these files will have in the generated website. +automodapi_toctreedirnm = 'python_api' # -- General configuration ----------------------------------------------------- @@ -28,11 +44,37 @@ from datetime import date # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. extensions = ['sphinx.ext.todo', 'sphinx.ext.mathjax', 'sphinx.ext.intersphinx'] +autodoc_default_options = { + 'special-members': '__int__, __len__, __hex__, __oct__, __iter__', +} + +# Unless we only generate the basic manpage we need the plugin for generating +# the Python API documentation. +if not building_man_page: + extensions.append('sphinx_automodapi.automodapi') + # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] # The suffix of source filenames. -source_suffix = '.rst' +source_suffix = { + '.rst': 'restructuredtext', +} + +try: + import recommonmark +except ImportError: + # manpages do not use any .md sources + if not building_man_page: + raise +else: + import sphinx + if sphinx.version_info >= (3, 0): + # This requires 0.5 or later. + extensions.append('recommonmark') + else: + source_parsers = {'.md': 'recommonmark.parser.CommonMarkParser'} + source_suffix['.md'] = 'markdown' # The encoding of source files. #source_encoding = 'utf-8-sig' @@ -68,9 +110,15 @@ copyright = u'2007-%d, The LLDB Team' % date.today().year # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. exclude_patterns = ['_build', 'analyzer'] - -# The reST default role (used for this markup: `text`) to use for all documents. -#default_role = None +# Ignore the generated Python documentation that is only used on the website. +# Without this we will get a lot of warnings about doc pages that aren't +# included by any doctree (as the manpage ignores those pages but they are +# potentially still around from a previous website generation). +if building_man_page: + exclude_patterns.append(automodapi_toctreedirnm) +# Use the recommended 'any' rule so that referencing SB API classes is possible +# by just writing `SBData`. +default_role = 'any' # If true, '()' will be appended to :func: etc. cross-reference text. #add_function_parentheses = True @@ -100,7 +148,9 @@ html_theme = 'alabaster' # further. For a list of options available for each theme, see the # documentation. html_theme_options = { - 'font_size': '11pt' + 'font_size': '11pt', + # Don't generate any links to GitHub. + 'github_button' : 'false', } # Add any paths that contain custom themes here, relative to this directory. @@ -228,11 +278,26 @@ latex_documents = [ # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). -man_pages = [('man/lldb', 'lldb', u'LLDB Documentation', [u'LLVM project'], 1)] +man_pages = [('man/lldb', 'lldb', u'LLDB Documentation', [u'LLVM project'], 1), + ('man/lldb-server', 'lldb-server', u'LLDB Documentation', [u'LLVM project'], 1), + ] # If true, show URL addresses after external links. #man_show_urls = False +def process_md(name): + file_subpath = os.path.join(command_guide_subpath, name) + with open(os.path.join(command_guide_path, name)) as f: + title = f.readline().rstrip('\n') + + m = re.match(r'^# (\S+) - (.+)$', title) + if m is None: + print("error: invalid title in %r " + "(expected '# - ')" % file_subpath, + file=sys.stderr) + else: + man_pages.append((file_subpath.replace('.md',''), m.group(1), + m.group(2), man_page_authors, 1)) # -- Options for Texinfo output ------------------------------------------------ @@ -253,3 +318,36 @@ texinfo_documents = [ # How to display URL addresses: 'footnote', 'no', or 'inline'. #texinfo_show_urls = 'footnote' + +empty_attr_summary = re.compile(r'\.\. rubric:: Attributes Summary\s*\.\. autosummary::\s*\.\. rubric::') +empty_attr_documentation = re.compile(r'\.\. rubric:: Attributes Documentation\s*\.\. rubric::') + +def cleanup_source(app, docname, source): + """ Cleans up source files generated by automodapi. """ + # Don't cleanup anything beside automodapi-generated sources. + if not automodapi_toctreedirnm in docname: + return + processed = source[0] + + # Don't show the list of inheritance info as there is no inheritance in the + # SBI API. This avoids all the repeated text on all doc pages that a + # class inherits from 'object'. + + processed = processed.replace(":show-inheritance:", "") + # Remove the SWIG generated 'thisown' attribute. It just bloats the generated + # documentation and users shouldn't fiddle with the value anyway. + processed = re.sub(r'~SB[a-zA-Z]+\.thisown', "", processed) + processed = processed.replace(" .. autoattribute:: thisown", "") + + # After removing 'thisown', many objects don't have any attributes left. + # Remove all now empty attribute summary/documentation sections with + # some rather ugly regex. + processed = empty_attr_summary.sub('.. rubric::', processed) + processed = empty_attr_documentation.sub('.. rubric::', processed) + + # Replace the original source with the processed one (source is a single + # element list). + source[0] = processed + +def setup(app): + app.connect('source-read', cleanup_source) diff --git a/gnu/llvm/lldb/docs/design/overview.rst b/gnu/llvm/lldb/docs/design/overview.rst new file mode 100644 index 00000000000..1555ea35bfb --- /dev/null +++ b/gnu/llvm/lldb/docs/design/overview.rst @@ -0,0 +1,192 @@ +Overview +======== + +LLDB is a large and complex codebase. This section will help you become more +familiar with the pieces that make up LLDB and give a general overview of the +general architecture. + +LLDB has many code groupings that makeup the source base: + +.. contents:: + :local: + +API +--- + +The API folder contains the public interface to LLDB. + +We are currently vending a C++ API. In order to be able to add methods to this +API and allow people to link to our classes, we have certain rules that we must +follow: + +- Classes can't inherit from any other classes. +- Classes can't contain virtual methods. +- Classes should be compatible with script bridging utilities like swig. +- Classes should be lightweight and be backed by a single member. Pointers (or + shared pointers) are the preferred choice since they allow changing the + contents of the backend without affecting the public object layout. +- The interface should be as minimal as possible in order to give a complete + API. + +By adhering to these rules we should be able to continue to vend a C++ API, and +make changes to the API as any additional methods added to these classes will +just be a dynamic loader lookup and they won't affect the class layout (since +they aren't virtual methods, and no members can be added to the class). + +Breakpoint +---------- + +A collection of classes that implement our breakpoint classes. Breakpoints are +resolved symbolically and always continue to resolve themselves as your program +runs. Whether settings breakpoints by file and line, by symbol name, by symbol +regular expression, or by address, breakpoints will keep trying to resolve new +locations each time shared libraries are loaded. Breakpoints will of course +unresolve themselves when shared libraries are unloaded. Breakpoints can also +be scoped to be set only in a specific shared library. By default, breakpoints +can be set in any shared library and will continue to attempt to be resolved +with each shared library load. + +Breakpoint options can be set on the breakpoint, or on the individual +locations. This allows flexibility when dealing with breakpoints and allows us +to do what the user wants. + +Commands +-------- + +The command source files represent objects that implement the functionality for +all textual commands available in our command line interface. + +Every command is backed by a ``lldb_private::CommandObject`` or +``lldb_private::CommandObjectMultiword`` object. + +``lldb_private::CommandObjectMultiword`` are commands that have subcommands and +allow command line commands to be logically grouped into a hierarchy. + +``lldb_private::CommandObject`` command line commands are the objects that +implement the functionality of the command. They can optionally define options +for themselves, as well as group those options into logical groups that can go +together. The help system is tied into these objects and can extract the syntax +and option groupings to display appropriate help for each command. + +Core +---- + +The Core source files contain basic functionality that is required in the +debugger as well as the class representing the debugger itself (Debugger). A +wide variety of classes are implemented: + +- Address (section offset addressing) +- AddressRange +- Broadcaster / Event / Listener +- Communication classes that use Connection objects +- Mangled names +- Source manager +- Value objects + +Dataformatters +-------------- + +A collection of classes that implement the data formatters subsystem. + +Data formatters provide a set of user-tweakable hooks in the ValueObjects world +that allow to customize presentation aspects of variables. While users interact +with formatters mostly through the type command, inside LLDB there are a few +layers to the implementation: DataVisualization at the highest end of the +spectrum, backed by classes implementing individual formatters, matching rules, +etc. + +For a general user-level introduction to data formatters, you can look here. + +More details on the architecture are to be found here. + +Expression +---------- + +Expression parsing files cover everything from evaluating DWARF expressions, to +evaluating expressions using Clang. + +The DWARF expression parser has been heavily modified to support type +promotion, new opcodes needed for evaluating expressions with symbolic variable +references (expression local variables, program variables), and other operators +required by typical expressions such as assign, address of, float/double/long +double floating point values, casting, and more. The DWARF expression parser +uses a stack of lldb_private::Value objects. These objects know how to do the +standard C type promotion, and allow for symbolic references to variables in +the program and in the LLDB process (expression local and expression global +variables). + +The expression parser uses a full instance of the Clang compiler in order to +accurately evaluate expressions. Hooks have been put into Clang so that the +compiler knows to ask about identifiers it doesn't know about. Once expressions +have be compiled into an AST, we can then traverse this AST and either generate +a DWARF expression that contains simple opcodes that can be quickly +re-evaluated each time an expression needs to be evaluated, or JIT'ed up into +code that can be run on the process being debugged. + +Host +---- + +LLDB tries to abstract itself from the host upon which it is currently running +by providing a host abstraction layer. This layer includes functionality, whose +implementation varies wildly from host to host. + +Host functionality includes abstraction layers for: + +- Information about the host system (triple, list of running processes, etc.) +- Launching processes +- Various OS primitives like pipes and sockets + +It also includes the base classes of the NativeProcess/Thread hierarchy, which +is used by lldb-server. + +Interpreter +----------- + +The interpreter classes are the classes responsible for being the base classes +needed for each command object, and is responsible for tracking and running +command line commands. + +Symbol +------ + +Symbol classes involve everything needed in order to parse object files and +debug symbols. All the needed classes for compilation units (code and debug +info for a source file), functions, lexical blocks within functions, inlined +functions, types, declaration locations, and variables are in this section. + +Target +------ + +Classes that are related to a debug target include: + +- Target +- Process +- Thread +- Stack frames +- Stack frame registers +- ABI for function calling in process being debugged +- Execution context batons + +Utility +------- + +This module contains the lowest layers of LLDB. A lot of these classes don't +really have anything to do with debugging -- they are just there because the +higher layers of the debugger use these classes to implement their +functionality. Others are data structures used in many other parts of the +debugger. Most of the functionality in this module could be useful in an +application that is not a debugger; however, providing a general purpose C++ +library is an explicit non-goal of this module.. + +This module provides following functionality: + +- Abstract path manipulation (FileSpec) +- Architecture specification +- Data buffers (DataBuffer, DataEncoder, DataExtractor) +- Logging +- Structured data manipulation (JSON) +- Streams +- Timers + +For historic reasons, some of this functionality overlaps that which is +provided by the LLVM support library. diff --git a/gnu/llvm/lldb/docs/design/reproducers.rst b/gnu/llvm/lldb/docs/design/reproducers.rst new file mode 100644 index 00000000000..99e34d812de --- /dev/null +++ b/gnu/llvm/lldb/docs/design/reproducers.rst @@ -0,0 +1,205 @@ +Reproducers +=========== + +As unbelievable as it may sound, the debugger has bugs. These bugs might +manifest themselves as errors, missing results or even a crash. Quite often +these bugs don't reproduce in simple, isolated scenarios. The debugger deals +with a lot of moving parts and subtle differences can easily add up. + +Reproducers in LLDB improve the experience for both the users encountering bugs +and the developers working on resolving them. The general idea consists of +*capturing* all the information necessary to later *replay* a debug session +while debugging the debugger. + +.. contents:: + :local: + +Usage +----- + +Reproducers are a generic concept in LLDB and are not inherently coupled with +the command line driver. The functionality can be used for anything that uses +the SB API and the driver is just one example. However, because it's probably +the most common way users interact with lldb, that's the workflow described in +this section. + +Capture +``````` + +Until reproducer capture is enabled by default, you need to launch LLDB in +capture mode. For the command line driver, this means passing ``--capture``. +You cannot enable reproducer capture from within LLDB, as this would be too +late to capture initialization of the debugger. + +.. code-block:: bash + + > lldb --capture + +In capture mode, LLDB will keep track of all the information it needs to replay +the current debug session. Most data is captured lazily to limit the impact on +performance. To create the reproducer, use the ``reproducer generate`` +sub-command. It's always possible to check the status of the reproducers with +the ``reproducer status`` sub-command. Note that generating the reproducer +terminates the debug session. + +.. code-block:: none + + (lldb) reproducer status + Reproducer is in capture mode. + (lldb) reproducer generate + Reproducer written to '/path/to/reproducer' + Please have a look at the directory to assess if you're willing to share the contained information. + + +The resulting reproducer is a directory. It was a conscious decision to not +compress and archive it automatically. The reproducer can contain potentially +sensitive information like object and symbol files, their paths on disk, debug +information, memory excerpts of the inferior process, etc. + +Replay +`````` + +It is strongly recommended to replay the reproducer locally to ensure it +actually reproduces the expected behavior. If the reproducer doesn't behave +correctly locally, it means there's a bug in the reproducer implementation that +should be addressed. + +To replay a reproducer, simply pass its path to LLDB through the ``--replay`` +flag. It is unnecessary to pass any other command line flags. The flags that +were passed to LLDB during capture are already part of the reproducer. + +.. code-block:: bash + + > lldb --replay /path/to/reproducer + + +During replay LLDB will behave similar to batch mode. The session should be +identical to the recorded debug session. The only expected differences are that +the binary being debugged doesn't actually run during replay. That means that +you won't see any of its side effects, like things being printed to the +terminal. Another expected difference is the behavior of the ``reproducer +generate`` command, which becomes a NOOP during replay. + +Augmenting a Bug Report with a Reproducer +````````````````````````````````````````` + +A reproducer can significantly improve a bug report, but it in itself is not +sufficient. Always describe the expected and unexpected behavior. Just like the +debugger can have bugs, the reproducer can have bugs too. + + +Design +------ + + +Replay +`````` + +Reproducers support two replay modes. The main and most common mode is active +replay. It's called active, because it's LLDB that is driving replay by calling +the captured SB API functions one after each other. The second mode is passive +replay. In this mode, LLDB sits idle until an SB API function is called, for +example from Python, and then replays just this individual call. + +Active Replay +^^^^^^^^^^^^^ + +No matter how a reproducer was captured, they can always be replayed with the +command line driver. When a reproducer is passed with the ``--replay`` flag, the +driver short-circuits and passes off control to the reproducer infrastructure, +effectively bypassing its normal operation. This works because the driver is +implemented using the SB API and is therefore nothing more than a sequence of +SB API calls. + +Replay is driven by the ``Registry::Replay``. As long as there's data in the +buffer holding the API data, the next SB API function call is deserialized. +Once the function is known, the registry can retrieve its signature, and use +that to deserialize its arguments. The function can then be invoked, most +commonly through the synthesized default replayer, or potentially using a +custom defined replay function. This process continues, until more data is +available or a replay error is encountered. + +During replay only a function's side effects matter. The result returned by the +replayed function is ignored because it cannot be observed beyond the driver. +This is sound, because anything that is passed into a subsequent API call will +have been serialized as an input argument. This also works for SB API objects +because the reproducers know about every object that has crossed the API +boundary, which is true by definition for object return values. + + +Passive Replay +^^^^^^^^^^^^^^ + +Passive replay exists to support running the API test suite against a +reproducer. The API test suite is written in Python and tests the debugger by +calling into its API from Python. To make this work, the API must transparently +replay itself when called. This is what makes passive replay different from +driver replay, where it is lldb itself that's driving replay. For passive +replay, the driving factor is external. + +In order to replay API calls, the reproducers need a way to intercept them. +Every API call is already instrumented with an ``LLDB_RECORD_*`` macro that +captures its input arguments. Furthermore, it also contains the necessary logic +to detect which calls cross the API boundary and should be intercepted. We were +able to reuse all of this to implement passive replay. + +During passive replay is enabled, nothing happens until an SB API is called. +Inside that API function, the macro detects whether this call should be +replayed (i.e. crossed the API boundary). If the answer is yes, the next +function is deserialized from the SB API data and compared to the current +function. If the signature matches, we deserialize its input arguments and +reinvoke the current function with the deserialized arguments. We don't need to +do anything special to prevent us from recursively calling the replayed version +again, as the API boundary crossing logic knows that we're still behind the API +boundary when we re-invoked the current function. + +Another big difference with driver replay is the return value. While this +didn't matter for driver replay, it's key for passive replay, because that's +what gets checked by the test suite. Luckily, the ``LLDB_RECORD_*`` macros +contained sufficient type information to derive the result type. + +Testing +------- + +Reproducers are tested in the following ways: + + - Unit tests to cover the reproducer infrastructure. There are tests for the + provider, loader and for the reproducer instrumentation. + - Feature specific end-to-end test cases in the ``test/Shell/Reproducer`` + directory. These tests serve as integration and regression tests for the + reproducers infrastructure, as well as doing some sanity checking for basic + debugger functionality. + - The API and shell tests can be run against a replayed reproducer. The + ``check-lldb-reproducers`` target will run the API and shell test suite + twice: first running the test normally while capturing a reproducer and then + a second time using the replayed session as the test input. For the shell + tests this use a little shim (``lldb-repro``) that uses the arguments and + current working directory to transparently generate or replay a reproducer. + For the API tests an extra argument with the reproducer path is passed to + ``dotest.py`` which initializes the debugger in the appropriate mode. + Certain tests do not fit this paradigm (for example test that check the + output of the binary being debugged) and are skipped by marking them as + unsupported by adding ``UNSUPPORTED: lldb-repro`` to the top of the shell + test or adding the ``skipIfReproducer`` decorator for the API tests. + +Knows Issues +------------ + +The reproducers are still a work in progress. Here's a non-exhaustive list of +outstanding work, limitations and known issues. + + - The VFS cannot deal with more than one current working directory. Changing + the current working directory during the debug session will break relative + paths. + - Not all SB APIs are properly instrumented. We need customer serialization + for APIs that take buffers and lengths. + - We leak memory during replay because the reproducer doesn't capture the end + of an object's life time. We need to add instrumentation to the destructor + of SB API objects. + - The reproducer includes every file opened by LLDB. This is overkill. For + example we do not need to capture source files for code listings. There's + currently no way to say that some file shouldn't be included in the + reproducer. + - We do not yet automatically generate a reproducer on a crash. The reason is + that generating the reproducer is too expensive to do in a signal handler. + We should re-invoke lldb after a crash and do the heavy lifting. diff --git a/gnu/llvm/lldb/docs/design/sbapi.rst b/gnu/llvm/lldb/docs/design/sbapi.rst new file mode 100644 index 00000000000..676509bbd99 --- /dev/null +++ b/gnu/llvm/lldb/docs/design/sbapi.rst @@ -0,0 +1,95 @@ +Scripting Bridge API +==================== + +The SB APIs constitute the stable C++ API that lldb presents to external +clients, and which get processed by SWIG to produce the Python bindings to +lldb. As such it is important that they not suffer from the binary +incompatibilities that C++ is so susceptible to. We've established a few rules +to ensure that this happens. + +The classes in the SB API's are all called SB, where SomeName is in +CamelCase starting with an upper case letter. The method names are all +CamelCase with initial capital letter as well. + +All the SB API classes are non-virtual, single inheritance classes. They should +only include SBDefines.h or other SB headers as needed. There should be no +inlined method implementations in the header files, they should all be in the +implementation files. And there should be no direct ivar access. + +You also need to choose the ivars for the class with care, since you can't add +or remove ivars without breaking binary compatibility. In some cases, the SB +class is a thin wrapper around an internal lldb_private object. In that case, +the class can have a single ivar, which is either a pointer, shared_ptr or +unique_ptr to the object in the lldb_private API. All the lldb_private classes +that get used this way are declared as opaque classes in lldb_forward.h, which +is included in SBDefines.h. So if you need an SB class to wrap an lldb_private +class that isn't in lldb_forward.h, add it there rather than making a direct +opaque declaration in the SB classes .h file. + +If the SB Class needs some state of its own, as well as the backing object, +don't include that as a direct ivar in the SB Class. Instead, make an Impl +class in the SB's .cpp file, and then make the SB object hold a shared or +unique pointer to the Impl object. The theory behind this is that if you need +more state in the SB object, those needs are likely to change over time, and +this way the Impl class can pick up members without changing the size of the +object. An example of this is the SBValue class. Please note that you should +not put this Impl class in the lldb namespace. Failure to do so leads to +leakage of weak-linked symbols in the SBAPI. + +In order to fit into the Python API's, we need to be able to default construct +all the SB objects. Since the ivars of the classes are all pointers of one sort +or other, this can easily be done, but it means all the methods must be +prepared to handle their opaque implementation pointer being empty, and doing +something reasonable. We also always have an "IsValid" method on all the SB +classes to report whether the object is empty or not. + +Another piece of the SB API infrastructure is the Python (or other script +interpreter) customization. SWIG allows you to add property access, iterators +and documentation to classes, but to do that you have to use a Swig interface +file in place of the .h file. Those files have a different format than a +straight C++ header file. These files are called SB.i, and live in +"scripts/interface". They are constructed by starting with the associated .h +file, and adding documentation and the Python decorations, etc. We do this in a +decidedly low-tech way, by maintaining the two files in parallel. That +simplifies the build process, but it does mean that if you add a method to the +C++ API's for an SB class, you have to copy the interface to the .i file. + +API Instrumentation +------------------- + +The reproducer infrastructure requires API methods to be instrumented so that +they can be captured and replayed. Instrumentation consists of two macros, +``LLDB_REGISTER`` and ``LLDB_RECORD``. Both can be automatically generated with +the ``lldb-instr`` utility. + +To add instrumentation for a given file, pass it to the ``lldb-instr`` tool. +Like other clang-based tools it requires a compilation database +(``compile_commands.json``) to be present in the current working directory. + +:: + + ./bin/lldb-instr /path/to/lldb/source/API/SBDebugger.cpp + + +The tool will automatically insert ``LLDB_RECORD`` macros inline, however you +will need to run ``clang-format`` over the processed file, as the tool +(intentionally) makes no attempt to get that right. + +The ``LLDB_REGISTER`` macros are printed to standard out between curly braces. +You'll have to copy-paste those into the corresponding ``RegisterMethods`` +function in the implementation file. This function is fully specialized in the +corresponding type. + +:: + + template <> void RegisterMethods(Registry &R) { + ... + } + + +When adding a new class, you'll also have to add a call to ``RegisterMethods`` +in the ``SBRegistry`` constructor. + +The tool can be used incrementally. However, it will ignore existing macros +even if their signature is wrong. It will only generate a ``LLDB_REGISTER`` if +it emitted a corresponding ``LLDB_RECORD`` macro. diff --git a/gnu/llvm/lldb/docs/doxygen.cfg.in b/gnu/llvm/lldb/docs/doxygen.cfg.in index 7228a1ea4a8..7750d89fd26 100644 --- a/gnu/llvm/lldb/docs/doxygen.cfg.in +++ b/gnu/llvm/lldb/docs/doxygen.cfg.in @@ -1434,7 +1434,7 @@ PERL_PATH = #--------------------------------------------------------------------------- # If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will -# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base +# generate an inheritance diagram (in HTML, RTF and LaTeX) for classes with base # or super classes. Setting the tag to NO turns the diagrams off. Note that # this option is superseded by the HAVE_DOT option below. This is only a # fallback. It is recommended to install and use dot, since it yields more diff --git a/gnu/llvm/lldb/docs/index.rst b/gnu/llvm/lldb/docs/index.rst index 50441f5be91..ffac28a7645 100644 --- a/gnu/llvm/lldb/docs/index.rst +++ b/gnu/llvm/lldb/docs/index.rst @@ -72,12 +72,15 @@ are welcome: * macOS debugging for i386, x86_64 and AArch64 * iOS, tvOS, and watchOS simulator debugging on i386, x86_64 and AArch64 * iOS, tvOS, and watchOS device debugging on ARM and AArch64 -* Linux user-space debugging for i386, x86_64 and PPC64le -* FreeBSD user-space debugging for i386 and x86_64 -* Windows user-space debugging for i386 (*) +* Linux user-space debugging for i386, x86_64, ARM, AArch64, MIPS64, PPC64le, + s390x +* FreeBSD user-space debugging for i386, x86_64, ARM, AArch64, MIPS64, PPC +* NetBSD user-space debugging for i386 and x86_64 +* Windows user-space debugging for i386, x86_64, ARM and AArch64 (*) (*) Support for Windows is under active development. Basic functionality is -expected to work, with functionality improving rapidly. +expected to work, with functionality improving rapidly. ARM and AArch64 support +is more experimental, with more known issues than the others. Get Involved ------------ @@ -133,28 +136,38 @@ interesting areas to contribute to lldb. use/python use/python-reference use/remote + use/qemu-testing use/troubleshooting + use/links .. toctree:: :hidden: :maxdepth: 1 :caption: Development - resources/architecture resources/contributing resources/build resources/test resources/bots - resources/reproducers - resources/sbapi resources/caveats + +.. toctree:: + :hidden: + :maxdepth: 1 + :caption: Design + + design/overview + design/reproducers + design/structureddataplugins + design/sbapi + .. toctree:: :hidden: :maxdepth: 1 :caption: Reference - Public Python API + Public Python API Public C++ API Private C++ API Man Page diff --git a/gnu/llvm/lldb/docs/lldb-for-gdb-users.txt b/gnu/llvm/lldb/docs/lldb-for-gdb-users.txt index d505d639192..e5eae376bb4 100644 --- a/gnu/llvm/lldb/docs/lldb-for-gdb-users.txt +++ b/gnu/llvm/lldb/docs/lldb-for-gdb-users.txt @@ -162,7 +162,7 @@ Current breakpoints: 1.1: where = Sketch`-[SKTGraphicView alignLeftEdges:] + 33 at /Projects/Sketch/SKTGraphicView.m:1405, address = 0x0000000100010d5b, resolved, hit count = 0 Note that each "logical" breakpoint can have multiple "locations". -The logical breakpoint has an integer id, and it's locations have an +The logical breakpoint has an integer id, and its locations have an id within their parent breakpoint (the two are joined by a ".", e.g. 1.1 in the example above.) diff --git a/gnu/llvm/lldb/docs/lldb-gdb-remote.txt b/gnu/llvm/lldb/docs/lldb-gdb-remote.txt index 276beedd047..3eb3dc51c02 100644 --- a/gnu/llvm/lldb/docs/lldb-gdb-remote.txt +++ b/gnu/llvm/lldb/docs/lldb-gdb-remote.txt @@ -235,162 +235,273 @@ send packet: QListThreadsInStopReply read packet: OK //---------------------------------------------------------------------- -// jTraceStart: +// jLLDBTraceSupported // // BRIEF -// Packet for starting trace of type lldb::TraceType. The following -// parameters should be appended to the packet formatted as a JSON -// dictionary, where the schematic for the JSON dictionary in terms of -// the recognized Keys is given below in the table. -// Different tracing types could require different custom parameters. -// Such custom tracing parameters if needed should be collectively -// specified in a JSON dictionary and the dictionary can be appended -// to this packet (as Value corresponding to "params"). Since sending -// JSON data over gdb-remote protocol has certain limitations, binary -// escaping convention should be used. +// Get the processor tracing type supported by the gdb-server for the current +// inferior. Responses might be different depending on the architecture and +// capabilities of the underlying OS. // -// Following is the list of parameters - +// OUTPUT SCHEMA +// { +// "name": , +// Tracing technology name, e.g. intel-pt, arm-coresight. +// "description": , +// Description for this technology. +// } // -// Key Value (Integer) (O)Optional/ -// (except params which should be a (M)Mandatory -// JSON dictionary) -// ========== ==================================================== +// If no tracing technology is supported for the inferior, or no process is +// running, then an error message is returned. // -// type The type of trace to start (see M -// lldb-enumerations for TraceType) -// -// buffersize The size of the buffer to allocate M -// for trace gathering. -// -// threadid The id of the thread to start tracing O -// on. -// -// metabuffersize The size of buffer to hold meta data O -// used for decoding the trace data. -// -// params Any parameters that are specific to O -// certain trace technologies should be -// collectively specified as a JSON -// dictionary -// ========== ==================================================== -// -// Each tracing instance is identified by a trace id which is returned -// as the reply to this packet. In case the tracing failed to begin an -// error code along with a hex encoded ASCII message is returned -// instead. +// NOTE +// This packet is used by Trace plug-ins (see lldb_private::Trace.h) to +// do live tracing. Specifically, the name of the plug-in should match the name +// of the tracing technology returned by this packet. //---------------------------------------------------------------------- -send packet: jTraceStart:{"type":,"buffersize":}] -read packet: /E;AAAAAAAAA +send packet: jLLDBTraceSupported +read packet: {"name":, "description":}/E;AAAAAAAAA //---------------------------------------------------------------------- -// jTraceStop: +// jLLDBTraceStart // // BRIEF -// Stop tracing instance with trace id , of course trace -// needs to be started before. The following parameters should be -// formatted as a JSON dictionary to the packet. Since sending -// JSON data over gdb-remote protocol has certain limitations, binary -// escaping convention should be used. +// Start tracing a process or its threads using a provided tracing technology. +// The input and output are specified as JSON objects. In case of success, an OK +// response is returned, or an error otherwise. +// +// PROCESS TRACING +// This traces existing and future threads of the current process. An error is +// returned if the process is already being traced. +// +// THREAD TRACING +// This traces specific threads. +// +// INPUT SCHEMA +// { +// "type": , +// Tracing technology name, e.g. intel-pt, arm-coresight. +// +// /* thread tracing only */ +// "tids": [], +// Individual threads to trace. +// +// ... other parameters specific to the provided tracing type +// } +// +// NOTES +// - If "tids" is not provided, then the operation is "process tracing", +// otherwise it's "thread tracing". +// - Each tracing technology can have different levels of support for "thread +// tracing" and "process tracing". +// +// INTEL-PT +// intel-pt supports both "thread tracing" and "process tracing". +// +// "Process tracing" is implemented by tracing each thread individually, but +// managed by the same "process trace" instance. +// Each actual thread trace, either from "process tracing" or "thread tracing", +// is stored in an in-memory circular buffer, which keeps the most recent data. +// +// Additional params in the input schema: +// { +// "threadBufferSize": , +// Trace buffer size per thread in bytes. It must be a power of 2 +// greater than or equal to 4096 (2^12) bytes. +// +// "enableTsc": , +// Whether to enable TSC timestamps or not. This is supported on +// all devices that support intel-pt. A TSC timestamp is generated along +// with PSB (synchronization) packets, whose frequency can be configured +// with the "psbPeriod" parameter. +// +// "psbPeriod"?: , +// This value defines the period in which PSB packets will be generated. +// A PSB packet is a synchronization packet that contains a TSC +// timestamp and the current absolute instruction pointer. // -// Following is the list of parameters - +// This parameter can only be used if // -// Key Value (Integer) (O)Optional/ -// (M)Mandatory -// ========== ==================================================== +// /sys/bus/event_source/devices/intel_pt/caps/psb_cyc // -// traceid The trace id of the tracing instance M +// is 1. Otherwise, the PSB period will be defined by the processor. // -// threadid The id of the thread to stop tracing O -// on. Since could map to -// multiple trace instances (in case it -// maps to the complete process), the -// threadid of a particular thread could -// be appended as "threadid:;" -// to stop tracing on that thread. -// ========== ==================================================== +// If supported, valid values for this period can be found in +/ +// /sys/bus/event_source/devices/intel_pt/caps/psb_periods // -// An OK response is sent in case of success else an error code along -// with a hex encoded ASCII message is returned. +// which contains a hexadecimal number, whose bits represent valid +// values e.g. if bit 2 is set, then value 2 is valid. +// +// The psb_period value is converted to the approximate number of +// raw trace bytes between PSB packets as: +// +// 2 ^ (value + 11) +// +// e.g. value 3 means 16KiB between PSB packets. Defaults to +// 0 if supported. +// +// /* process tracing only */ +// "processBufferSizeLimit": , +// Maximum total buffer size per process in bytes. +// This limit applies to the sum of the sizes of all trace buffers for +// the current process, excluding the ones started with "thread tracing". +// +// Whenever a thread is attempted to be traced due to "process tracing" +// and the limit would be reached, the process is stopped with a +// "tracing" reason along with a meaningful description, so that the +// user can retrace the process if needed. +// } +// +// Notes: +// - Modifying the parameters of an existing trace is not supported. The user +// needs to stop the trace and start a new one. +// - If "process tracing" is attempted and there are individual threads +// already being traced with "thread tracing", these traces are left +// unaffected and the threads not traced twice. +// - If "thread tracing" is attempted on a thread already being traced with +// either "thread tracing" or "process tracing", it fails. //---------------------------------------------------------------------- -send packet: jTraceStop:{"traceid":}] -read packet: /E;AAAAAAAAA +Process tracing: +send packet: jLLDBTraceStart:{"type":,...other params}] +read packet: OK/E;AAAAAAAAA + +Thread tracing: +send packet: jLLDBTraceStart:{"type":,"tids":,...other params}] +read packet: OK/E;AAAAAAAAA //---------------------------------------------------------------------- -// jTraceBufferRead: +// jLLDBTraceStop // // BRIEF -// Packet for reading the trace for tracing instance , i.e the -// id obtained from StartTrace API. The following parameters should be -// formatted as a JSON dictionary to the packet. Since sending -// JSON data over gdb-remote protocol has certain limitations, binary -// escaping convention should be used. +// Stop tracing a process or its threads using a provided tracing technology. +// The input and output are specified as JSON objects. In case of success, an OK +// response is returned, or an error otherwise. // -// Following is the list of parameters - +// PROCESS TRACE STOPPING +// Stopping a process trace stops the active traces initiated with +// "thread tracing". // -// Key Value (Integer) (O)Optional/ -// (M)Mandatory -// ========== ==================================================== -// traceid The trace id of the tracing instance M +// THREAD TRACE STOPPING +// This is a best effort request, which tries to stop as many traces as +// possible. // -// offset The offset to start reading the data M -// from. +// INPUT SCHEMA +// The schema for the input is // -// buffersize The size of the data intended to read. M +// { +// "type": +// Tracing technology name, e.g. intel-pt, arm-coresight. // -// threadid The id of the thread to retrieve data O -// from. -// ========== ==================================================== +// /* thread trace stopping only */ +// "tids": [] +// Individual thread traces to stop. +// } // -// The trace data is sent as raw binary data if the read was successful -// else an error code along with a hex encoded ASCII message is sent. +// NOTES +// - If "tids" is not provided, then the operation is "process trace stopping". +// +// INTEL PT +// Stopping a specific thread trace started with "process tracing" is allowed. //---------------------------------------------------------------------- -send packet: jTraceBufferRead:{"traceid":,"offset":,"buffersize":}] -read packet: /E;AAAAAAAAA +Process trace stopping: +send packet: jLLDBTraceStop:{"type":}] +read packet: OK/E;AAAAAAAAA + +Thread trace stopping: +send packet: jLLDBTraceStop:{"type":,"tids":}] +read packet: OK/E;AAAAAAAAA //---------------------------------------------------------------------- -// jTraceMetaRead: +// jLLDBTraceGetState // // BRIEF -// Similar Packet as above except it reads meta data. -//---------------------------------------------------------------------- - -/---------------------------------------------------------------------- -// jTraceConfigRead: +// Get the current state of the process and its threads being traced by +// a given trace technology. The response is a JSON object with custom +// information depending on the trace technology. In case of errors, an +// error message is returned. +// +// INPUT SCHEMA +// { +// "type": +// Tracing technology name, e.g. intel-pt, arm-coresight. +// } +// +// OUTPUT SCHEMA +// { +// "tracedThreads": [{ +// "tid": , +// "binaryData": [ +// { +// "kind": , +// Identifier for some binary data related to this thread to +// fetch with the jLLDBTraceGetBinaryData packet. +// "size": , +// Size in bytes of this thread data. +// }, +// ] +// }], +// "processBinaryData": [ +// { +// "kind": , +// Identifier for some binary data related to this process to +// fetch with the jLLDBTraceGetBinaryData packet. +// "size": , +// Size in bytes of this thread data. +// }, +// }] +// } +// +// NOTES +// - "traceThreads" includes all thread traced by both "process tracing" and +// "thread tracing". +// +// INTEL PT +// +// Binary data kinds: +// - threadTraceBuffer: trace buffer for a thread. +// - cpuInfo: contents of the /proc/cpuinfo file. +//---------------------------------------------------------------------- + +send packet: jLLDBTraceGetState:{"type":}] +read packet: {...object}/E;AAAAAAAAA + +//---------------------------------------------------------------------- +// jLLDBTraceGetBinaryData // // BRIEF -// Request the trace configuration for the tracing instance with id -// . +// Get binary data given a trace technology and a data identifier. +// The input is specified as a JSON object and the response has the same format +// as the "binary memory read" (aka "x") packet. In case of failures, an error +// message is returned. // -// Following is the list of parameters - +// SCHEMA +// The schema for the input is // -// Key Value (Integer) (O)Optional/ -// (M)Mandatory -// ========== ==================================================== -// traceid The trace id of the tracing instance M +// { +// "type": , +// Tracing technology name, e.g. intel-pt, arm-coresight. +// "kind": , +// Identifier for the data. +// "tid"?: , +// Tid in decimal if the data belongs to a thread. +// "offset": , +// Offset of the data in bytes. +// "size": , +// Number of bytes in to read starting from the offset. +// } // -// threadid The id of the thread to obtain trace O -// configuration from. Since -// could map to multiple trace instances -// (in case it maps to the complete -// process), the threadid of a particular -// thread could be appended as -// "threadid:;" to obtain the -// trace configuration of that thread. -// ========== ==================================================== +// INTEL PT // -// In the response packet the trace configuration is sent as text, -// formatted as a JSON dictionary. Since sending JSON data over -// gdb-remote protocol has certain limitations, binary escaping -// convention is used. -// In case the trace instance with the was not found, an -// error code along with a hex encoded ASCII message is returned. +// Binary data kinds: +// - threadTraceBuffer: trace buffer for a thread. +// - cpuInfo: contents of the /proc/cpuinfo file. //---------------------------------------------------------------------- -send packet: jTraceConfigRead:{"traceid":} -read packet: {"conf1":,"conf2":,"params":{"paramName":paramValue}]}];/E;AAAAAAAAA +send packet: jLLDBTraceGetBinaryData:{"type":,"kind":,"tid":,"offset":,"size":}] +read packet: /E;AAAAAAAAA //---------------------------------------------------------------------- // "qRegisterInfo" @@ -790,10 +901,14 @@ distribution_id: optional. For linux, specifies distribution id (e.g. ubuntu, fe osmajor: optional, specifies the major version number of the OS (e.g. for macOS 10.12.2, it would be 10) osminor: optional, specifies the minor version number of the OS (e.g. for macOS 10.12.2, it would be 12) ospatch: optional, specifies the patch level number of the OS (e.g. for macOS 10.12.2, it would be 2) +vm-page-size: optional, specifies the target system VM page size, base 10. + Needed for the "dirty-pages:" list in the qMemoryRegionInfo + packet, where a list of dirty pages is sent from the remote + stub. This page size tells lldb how large each dirty page is. addressing_bits: optional, specifies how many bits in addresses are significant for addressing, base 10. If bits 38..0 in a 64-bit pointer are significant for addressing, - then the value is 39. This is needed on e.g. Aarch64 + then the value is 39. This is needed on e.g. AArch64 v8.3 ABIs that use pointer authentication, so lldb knows which bits to clear/set to get the actual addresses. @@ -1086,10 +1201,27 @@ tuples to return are: // the file while for anonymous regions it have to be the name // associated to the region if that is available. + flags:; // where is a space separated string + // of flag names. Currently the only supported flag + // is "mt" for AArch64 memory tagging. lldb will + // ignore any other flags in this field. + error:; // where is // a hex encoded string value that // contains an error string + dirty-pages:[][, + + Communicate over the given file descriptor instead of sockets. + +.. option:: --named-pipe + + Write the listening port number to the specified named pipe. + +.. option:: --pipe + + Write the listening port number to the specified pipe (fd). + +.. option:: --reverse-connect + + Connect to the client instead of passively waiting for a connection. In this + case, [host]:port denotes the remote address to connect to. + +GENERAL OPTIONS +~~~~~~~~~~~~~~~ + +.. option:: --help + + Prints out the usage information and exits. + +.. option:: --log-channels + + Channels to log. A colon-separated list of entries. Each entry starts with + a channel followed by a space-separated list of categories. + +.. option:: --log-file + + Destination file to log to. If empty, log to stderr. + +.. option:: --setsid + + Run lldb-server in a new session. + +TARGET SELECTION +~~~~~~~~~~~~~~~~ + +.. option:: --attach + + Attach to the process given by a (numeric) process id or a name. + +.. option:: -- program args + + Launch a program for debugging. + +If neither of target options are used, :program:`lldb-server` is started +without a specific target. It can be afterwards instructed by the client +to launch or attach. + +PLATFORM COMMAND +---------------- + +| :program:`lldb-server` p[latform] [*options*] --server --listen [[*host*]:*port*] + +CONNECTION +~~~~~~~~~~ + +.. option:: --server + + Run in server mode, handling multiple connections. If this is not specified, + lldb-server will accept only one connection and exit when it is finished. + +.. option:: --listen : + + Hostname and port to listen on. Obligatory. If *port* is zero, a random port + will be used. + +.. option:: --socket-file + + Write the listening socket port number to the specified file. + +GENERAL OPTIONS +~~~~~~~~~~~~~~~ + +.. option:: --log-channels + + Channels to log. A colon-separated list of entries. Each entry starts with + a channel followed by a space-separated list of categories. + +.. option:: --log-file + + Destination file to log to. If empty, log to stderr. + +GDB-SERVER CONNECTIONS +~~~~~~~~~~~~~~~~~~~~~~ + +.. option:: --gdbserver-port + + Define a port to be used for gdb-server connections. Can be specified multiple + times to allow multiple ports. Has no effect if --min-gdbserver-port + and --max-gdbserver-port are specified. + +.. option:: --min-gdbserver-port +.. option:: --max-gdbserver-port + + Specify the range of ports that can be used for gdb-server connections. Both + options need to be specified simultaneously. Overrides --gdbserver-port. + +.. option:: --port-offset + + Add the specified offset to port numbers returned by server. This is useful + if the server is running behind a firewall, and a range of ports is redirected + to it with an offset. + +EXAMPLES +-------- + +The server can be started in several modes. + +In order to launch a new process inside the debugger, pass the path to it +and the arguments to the debugged executable as positional arguments. +To disambiguate between arguments passed to lldb and arguments passed +to the debugged executable, arguments starting with a - must be passed after +--. The server will launch the new executable and stop it immediately, waiting +for the client to connect. + + lldb-server g :1234 /path/to/program program-argument -- --program-option + +For convenience, passing the executable after -- is also supported. + + lldb-server g :1234 -- /path/to/program program-argument --program-option + +In order to attach to a running process, pass --attach along with the process +identifier or name. The process will be stopped immediately after starting +the server. Note that terminating the server will usually cause the process +to be detached and continue execution. + + lldb-server g :1234 --attach 12345 + lldb-server g :1234 --attach program-name + +Use *gdb-remote* command to connect to the server: + + (lldb) gdb-remote 1234 + +lldb-server can also be started without an inferior. In this case, the client +can select the target after connecting to the server. Note that some commands +(e.g. *target create*) will disconnect and launch a local lldb-server instead. + + lldb-server g :1234 + + (lldb) gdb-remote 1234 + (lldb) process launch a.out + +SEE ALSO +-------- + +The LLDB project page https://lldb.llvm.org has many different resources +for :program:`lldb-server` users. diff --git a/gnu/llvm/lldb/docs/python_api.rst b/gnu/llvm/lldb/docs/python_api.rst new file mode 100644 index 00000000000..5e465e1eae6 --- /dev/null +++ b/gnu/llvm/lldb/docs/python_api.rst @@ -0,0 +1,98 @@ +LLDB Python API +================================ + +.. + The long list of "skip" filters out several global functions that are + generated by SWIG (but which are not useful as they are only the + backend for their respective static functions in the classes). + Without this list +.. automodapi:: lldb + :no-inheritance-diagram: + :skip: SBBreakpoint_EventIsBreakpointEvent + :skip: SBBreakpoint_GetBreakpointEventTypeFromEvent + :skip: SBBreakpoint_GetBreakpointFromEvent + :skip: SBBreakpoint_GetBreakpointLocationAtIndexFromEvent + :skip: SBBreakpoint_GetNumBreakpointLocationsFromEvent + :skip: SBCommandInterpreter_EventIsCommandInterpreterEvent + :skip: SBCommandInterpreter_GetArgumentDescriptionAsCString + :skip: SBCommandInterpreter_GetArgumentTypeAsCString + :skip: SBCommandInterpreter_GetBroadcasterClass + :skip: SBCommunication_GetBroadcasterClass + :skip: SBData_CreateDataFromCString + :skip: SBData_CreateDataFromDoubleArray + :skip: SBData_CreateDataFromSInt32Array + :skip: SBData_CreateDataFromSInt64Array + :skip: SBData_CreateDataFromUInt32Array + :skip: SBData_CreateDataFromUInt64Array + :skip: SBDebugger_Create + :skip: SBDebugger_Create + :skip: SBDebugger_Destroy + :skip: SBDebugger_FindDebuggerWithID + :skip: SBDebugger_GetBuildConfiguration + :skip: SBDebugger_GetDefaultArchitecture + :skip: SBDebugger_GetInternalVariableValue + :skip: SBDebugger_GetVersionString + :skip: SBDebugger_Initialize + :skip: SBDebugger_InitializeWithErrorHandling + :skip: SBDebugger_MemoryPressureDetected + :skip: SBDebugger_SetDefaultArchitecture + :skip: SBDebugger_SetInternalVariable + :skip: SBDebugger_StateAsCString + :skip: SBDebugger_StateIsRunningState + :skip: SBDebugger_StateIsStoppedState + :skip: SBDebugger_Terminate + :skip: SBEvent_GetCStringFromEvent + :skip: SBFileSpec_ResolvePath + :skip: SBFile_MakeBorrowed + :skip: SBFile_MakeBorrowedForcingIOMethods + :skip: SBFile_MakeForcingIOMethods + :skip: SBHostOS_GetLLDBPath + :skip: SBHostOS_GetLLDBPythonPath + :skip: SBHostOS_GetProgramFileSpec + :skip: SBHostOS_GetUserHomeDirectory + :skip: SBHostOS_ThreadCancel + :skip: SBHostOS_ThreadCreate + :skip: SBHostOS_ThreadCreated + :skip: SBHostOS_ThreadDetach + :skip: SBHostOS_ThreadJoin + :skip: SBLanguageRuntime_GetLanguageTypeFromString + :skip: SBLanguageRuntime_GetNameForLanguageType + :skip: SBModuleSpecList_GetModuleSpecifications + :skip: SBModule_GarbageCollectAllocatedModules + :skip: SBModule_GetNumberAllocatedModules + :skip: SBPlatform_GetHostPlatform + :skip: SBProcess_EventIsProcessEvent + :skip: SBProcess_EventIsStructuredDataEvent + :skip: SBProcess_GetBroadcasterClassName + :skip: SBProcess_GetInterruptedFromEvent + :skip: SBProcess_GetNumRestartedReasonsFromEvent + :skip: SBProcess_GetProcessFromEvent + :skip: SBProcess_GetRestartedFromEvent + :skip: SBProcess_GetRestartedReasonAtIndexFromEvent + :skip: SBProcess_GetStateFromEvent + :skip: SBProcess_GetStructuredDataFromEvent + :skip: SBReproducer_Capture + :skip: SBReproducer_PassiveReplay + :skip: SBReproducer_SetAutoGenerate + :skip: SBReproducer_SetWorkingDirectory + :skip: SBTarget_EventIsTargetEvent + :skip: SBTarget_GetBroadcasterClassName + :skip: SBTarget_GetModuleAtIndexFromEvent + :skip: SBTarget_GetNumModulesFromEvent + :skip: SBTarget_GetTargetFromEvent + :skip: SBThread_EventIsThreadEvent + :skip: SBThread_GetBroadcasterClassName + :skip: SBThread_GetStackFrameFromEvent + :skip: SBThread_GetThreadFromEvent + :skip: SBTypeSummary_CreateWithFunctionName + :skip: SBTypeSummary_CreateWithScriptCode + :skip: SBTypeSummary_CreateWithSummaryString + :skip: SBTypeSynthetic_CreateWithClassName + :skip: SBTypeSynthetic_CreateWithScriptCode + :skip: SBWatchpoint_EventIsWatchpointEvent + :skip: SBWatchpoint_GetWatchpointEventTypeFromEvent + :skip: SBWatchpoint_GetWatchpointFromEvent + :skip: command + :skip: in_range + :skip: is_numeric_type + :skip: lldb_iter diff --git a/gnu/llvm/lldb/docs/python_api_enums.rst b/gnu/llvm/lldb/docs/python_api_enums.rst new file mode 100644 index 00000000000..58100b2aa9a --- /dev/null +++ b/gnu/llvm/lldb/docs/python_api_enums.rst @@ -0,0 +1,1408 @@ +.. + This is a sub page of the Python API docs and linked from the main API page. + The page isn't in any toctree, so silence the sphinx warnings by marking it as orphan. + +:orphan: + +Python API enumerators and constants +==================================== + +.. py:currentmodule:: lldb + +Constants +********* + +Generic register numbers +------------------------ + +.. py:data:: LLDB_REGNUM_GENERIC_PC + + Program counter. + +.. py:data:: LLDB_REGNUM_GENERIC_SP + + Stack pointer. +.. py:data:: LLDB_REGNUM_GENERIC_FP + + Frame pointer. + +.. py:data:: LLDB_REGNUM_GENERIC_RA + + Return address. + +.. py:data:: LLDB_REGNUM_GENERIC_FLAGS + + Processor flags register. + +.. py:data:: LLDB_REGNUM_GENERIC_ARG1 + + The register that would contain pointer size or less argument 1 (if any). + +.. py:data:: LLDB_REGNUM_GENERIC_ARG2 + + The register that would contain pointer size or less argument 2 (if any). + +.. py:data:: LLDB_REGNUM_GENERIC_ARG3 + + The register that would contain pointer size or less argument 3 (if any). + +.. py:data:: LLDB_REGNUM_GENERIC_ARG4 + + The register that would contain pointer size or less argument 4 (if any). + +.. py:data:: LLDB_REGNUM_GENERIC_ARG5 + + The register that would contain pointer size or less argument 5 (if any). + +.. py:data:: LLDB_REGNUM_GENERIC_ARG6 + + The register that would contain pointer size or less argument 6 (if any). + +.. py:data:: LLDB_REGNUM_GENERIC_ARG7 + + The register that would contain pointer size or less argument 7 (if any). + +.. py:data:: LLDB_REGNUM_GENERIC_ARG8 + + The register that would contain pointer size or less argument 8 (if any). + + +Invalid value definitions +------------------------- + +.. py:data:: LLDB_INVALID_BREAK_ID +.. py:data:: LLDB_INVALID_WATCH_ID +.. py:data:: LLDB_INVALID_ADDRESS +.. py:data:: LLDB_INVALID_INDEX32 +.. py:data:: LLDB_INVALID_IVAR_OFFSET +.. py:data:: LLDB_INVALID_IMAGE_TOKEN +.. py:data:: LLDB_INVALID_MODULE_VERSION +.. py:data:: LLDB_INVALID_REGNUM +.. py:data:: LLDB_INVALID_UID +.. py:data:: LLDB_INVALID_PROCESS_ID +.. py:data:: LLDB_INVALID_THREAD_ID +.. py:data:: LLDB_INVALID_FRAME_ID +.. py:data:: LLDB_INVALID_SIGNAL_NUMBER +.. py:data:: LLDB_INVALID_OFFSET +.. py:data:: LLDB_INVALID_LINE_NUMBER +.. py:data:: LLDB_INVALID_QUEUE_ID + +CPU types +--------- + +.. py:data:: LLDB_ARCH_DEFAULT +.. py:data:: LLDB_ARCH_DEFAULT_32BIT +.. py:data:: LLDB_ARCH_DEFAULT_64BIT +.. py:data:: LLDB_INVALID_CPUTYPE + + +Option set definitions +---------------------- + +.. py:data:: LLDB_MAX_NUM_OPTION_SETS +.. py:data:: LLDB_OPT_SET_ALL +.. py:data:: LLDB_OPT_SET_1 +.. py:data:: LLDB_OPT_SET_2 +.. py:data:: LLDB_OPT_SET_3 +.. py:data:: LLDB_OPT_SET_4 +.. py:data:: LLDB_OPT_SET_5 +.. py:data:: LLDB_OPT_SET_6 +.. py:data:: LLDB_OPT_SET_7 +.. py:data:: LLDB_OPT_SET_8 +.. py:data:: LLDB_OPT_SET_9 +.. py:data:: LLDB_OPT_SET_10 +.. py:data:: LLDB_OPT_SET_11 + +Miscellaneous constants +------------------------ + +.. py:data:: LLDB_GENERIC_ERROR +.. py:data:: LLDB_DEFAULT_BREAK_SIZE +.. py:data:: LLDB_WATCH_TYPE_READ +.. py:data:: LLDB_WATCH_TYPE_WRITE + + +Enumerators +*********** + + +.. _State: + +State +----- + +.. py:data:: eStateInvalid +.. py:data:: eStateUnloaded + + Process is object is valid, but not currently loaded. + +.. py:data:: eStateConnected + + Process is connected to remote debug services, but not + launched or attached to anything yet. + +.. py:data:: eStateAttaching + + Process is in the process of launching. + +.. py:data:: eStateLaunching + + Process is in the process of launching. + +.. py:data:: eStateStopped + + Process or thread is stopped and can be examined. + +.. py:data:: eStateRunning + + Process or thread is running and can't be examined. + +.. py:data:: eStateStepping + + Process or thread is in the process of stepping and can + not be examined. + +.. py:data:: eStateCrashed + + Process or thread has crashed and can be examined. + +.. py:data:: eStateDetached + + Process has been detached and can't be examined. + +.. py:data:: eStateExited + + Process has exited and can't be examined. + +.. py:data:: eStateSuspended + + Process or thread is in a suspended state as far + as the debugger is concerned while other processes + or threads get the chance to run. + + +.. _LaunchFlag: + +LaunchFlag +---------- + +.. py:data:: eLaunchFlagNone +.. py:data:: eLaunchFlagExec + + Exec when launching and turn the calling process into a new process. + +.. py:data:: eLaunchFlagDebug + + Stop as soon as the process launches to allow the process to be debugged. + +.. py:data:: eLaunchFlagStopAtEntry + + Stop at the program entry point instead of auto-continuing when launching or attaching at entry point. + +.. py:data:: eLaunchFlagDisableASLR + + Disable Address Space Layout Randomization. + +.. py:data:: eLaunchFlagDisableSTDIO + + Disable stdio for inferior process (e.g. for a GUI app). + +.. py:data:: eLaunchFlagLaunchInTTY + + Launch the process in a new TTY if supported by the host. + +.. py:data:: eLaunchFlagLaunchInShell + + Launch the process inside a shell to get shell expansion. + +.. py:data:: eLaunchFlagLaunchInSeparateProcessGroup + + Launch the process in a separate process group if you are going to hand the process off (e.g. to debugserver) + +.. py:data:: eLaunchFlagDontSetExitStatus + + set this flag so lldb & the handee don't race to set its exit status. + +.. py:data:: eLaunchFlagDetachOnError + + If set, then the client stub should detach rather than killing the debugee + if it loses connection with lldb. + +.. py:data:: eLaunchFlagShellExpandArguments + + Perform shell-style argument expansion + +.. py:data:: eLaunchFlagCloseTTYOnExit + + Close the open TTY on exit + +.. py:data:: eLaunchFlagInheritTCCFromParent + + Don't make the inferior responsible for its own TCC + permissions but instead inherit them from its parent. + + +.. _RunMode: + +RunMode +------- +.. py:data:: eOnlyThisThread +.. py:data:: eAllThreads +.. py:data:: eOnlyDuringStepping + + +.. _ByteOrder: + +ByteOrder +--------- + +.. py:data:: eByteOrderInvalid +.. py:data:: eByteOrderBig +.. py:data:: eByteOrderPDP +.. py:data:: eByteOrderLittle + + +.. _Encoding: + +Encoding +-------- + +.. py:data:: eEncodingInvalid +.. py:data:: eEncodingUint +.. py:data:: eEncodingSint +.. py:data:: eEncodingIEEE754 +.. py:data:: eEncodingVector + + +.. _Format: + +Format +------ + +.. py:data:: eFormatDefault +.. py:data:: eFormatInvalid +.. py:data:: eFormatBoolean +.. py:data:: eFormatBinary +.. py:data:: eFormatBytes +.. py:data:: eFormatBytesWithASCII +.. py:data:: eFormatChar +.. py:data:: eFormatCharPrintable +.. py:data:: eFormatComplex +.. py:data:: eFormatComplexFloat +.. py:data:: eFormatCString +.. py:data:: eFormatDecimal +.. py:data:: eFormatEnum +.. py:data:: eFormatHex +.. py:data:: eFormatHexUppercase +.. py:data:: eFormatFloat +.. py:data:: eFormatOctal +.. py:data:: eFormatOSType +.. py:data:: eFormatUnicode16 +.. py:data:: eFormatUnicode32 +.. py:data:: eFormatUnsigned +.. py:data:: eFormatPointer +.. py:data:: eFormatVectorOfChar +.. py:data:: eFormatVectorOfSInt8 +.. py:data:: eFormatVectorOfUInt8 +.. py:data:: eFormatVectorOfSInt16 +.. py:data:: eFormatVectorOfUInt16 +.. py:data:: eFormatVectorOfSInt32 +.. py:data:: eFormatVectorOfUInt32 +.. py:data:: eFormatVectorOfSInt64 +.. py:data:: eFormatVectorOfUInt64 +.. py:data:: eFormatVectorOfFloat16 +.. py:data:: eFormatVectorOfFloat32 +.. py:data:: eFormatVectorOfFloat64 +.. py:data:: eFormatVectorOfUInt128 +.. py:data:: eFormatComplexInteger +.. py:data:: eFormatCharArray +.. py:data:: eFormatAddressInfo +.. py:data:: eFormatHexFloat +.. py:data:: eFormatInstruction +.. py:data:: eFormatVoid +.. py:data:: eFormatUnicode8 + + +.. _DescriptionLevel: + +DescriptionLevel +---------------- + +.. py:data:: eDescriptionLevelBrief +.. py:data:: eDescriptionLevelFull +.. py:data:: eDescriptionLevelVerbose +.. py:data:: eDescriptionLevelInitial + + +.. _ScriptLanguage: + +ScriptLanguage +-------------- + +.. py:data:: eScriptLanguageNone +.. py:data:: eScriptLanguagePython +.. py:data:: eScriptLanguageLua +.. py:data:: eScriptLanguageUnknown +.. py:data:: eScriptLanguageDefault + + +.. _RegisterKind: + +RegisterKind +------------ + +.. py:data:: eRegisterKindEHFrame +.. py:data:: eRegisterKindDWARF +.. py:data:: eRegisterKindGeneric +.. py:data:: eRegisterKindProcessPlugin +.. py:data:: eRegisterKindLLDB + + +.. _StopReason: + +StopReason +---------- + +.. py:data:: eStopReasonInvalid +.. py:data:: eStopReasonNone +.. py:data:: eStopReasonTrace +.. py:data:: eStopReasonBreakpoint +.. py:data:: eStopReasonWatchpoint +.. py:data:: eStopReasonSignal +.. py:data:: eStopReasonException +.. py:data:: eStopReasonExec +.. py:data:: eStopReasonFork +.. py:data:: eStopReasonVFork +.. py:data:: eStopReasonVForkDone +.. py:data:: eStopReasonPlanComplete +.. py:data:: eStopReasonThreadExiting +.. py:data:: eStopReasonInstrumentation + + +.. _ReturnStatus: + +ReturnStatus +------------ + +.. py:data:: eReturnStatusInvalid +.. py:data:: eReturnStatusSuccessFinishNoResult +.. py:data:: eReturnStatusSuccessFinishResult +.. py:data:: eReturnStatusSuccessContinuingNoResult +.. py:data:: eReturnStatusSuccessContinuingResult +.. py:data:: eReturnStatusStarted +.. py:data:: eReturnStatusFailed +.. py:data:: eReturnStatusQuit + + +.. _Expression: + +Expression +---------- + +The results of expression evaluation. + +.. py:data:: eExpressionCompleted +.. py:data:: eExpressionSetupError +.. py:data:: eExpressionParseError +.. py:data:: eExpressionDiscarded +.. py:data:: eExpressionInterrupted +.. py:data:: eExpressionHitBreakpoint +.. py:data:: eExpressionTimedOut +.. py:data:: eExpressionResultUnavailable +.. py:data:: eExpressionStoppedForDebug +.. py:data:: eExpressionThreadVanished + + +.. _SearchDepth: + +SearchDepth +----------- + +.. py:data:: eSearchDepthInvalid +.. py:data:: eSearchDepthTarget +.. py:data:: eSearchDepthModule +.. py:data:: eSearchDepthCompUnit +.. py:data:: eSearchDepthFunction +.. py:data:: eSearchDepthBlock +.. py:data:: eSearchDepthAddress + + +.. _ConnectionStatus: + +ConnectionStatus +---------------- + +.. py:data:: eConnectionStatusSuccess + + Success. + +.. py:data:: eConnectionStatusEndOfFile + + End-of-file encountered. + +.. py:data:: eConnectionStatusError + + Error encountered. + +.. py:data:: eConnectionStatusTimedOut + + Request timed out. + +.. py:data:: eConnectionStatusNoConnection + + No connection. + +.. py:data:: eConnectionStatusLostConnection + + Lost connection while connected to a valid connection. + +.. py:data:: eConnectionStatusInterrupted + + Interrupted read. + + +.. _ErrorType: + +ErrorType +--------- + +.. py:data:: eErrorTypeInvalid +.. py:data:: eErrorTypeGeneric + + Generic errors that can be any value. + +.. py:data:: eErrorTypeMachKernel + + Mach kernel error codes. + +.. py:data:: eErrorTypePOSIX + + POSIX error codes. + +.. py:data:: eErrorTypeExpression + + These are from the ExpressionResults enum. + +.. py:data:: eErrorTypeWin32 + + Standard Win32 error codes. + + +.. _ValueType: + +ValueType +--------- + +.. py:data:: eValueTypeInvalid +.. py:data:: eValueTypeVariableGlobal + + Global variable. + +.. py:data:: eValueTypeVariableStatic + + Static variable. + +.. py:data:: eValueTypeVariableArgument + + Funfction argument variable. + +.. py:data:: eValueTypeVariableLocal + + Function local variable. + +.. py:data:: eValueTypeRegister + + Stack frame register. + +.. py:data:: eValueTypeRegisterSet + + A collection of stack frame register values. + +.. py:data:: eValueTypeConstResult + + Constant result variables. + +.. py:data:: eValueTypeVariableThreadLocal + + Thread local storage variable. + + +.. _InputReaderGranularity: + +InputReaderGranularity +---------------------- + +Token size/granularities for Input Readers. + +.. py:data:: eInputReaderGranularityInvalid +.. py:data:: eInputReaderGranularityByte +.. py:data:: eInputReaderGranularityWord +.. py:data:: eInputReaderGranularityLine +.. py:data:: eInputReaderGranularityAll + + +.. _SymbolContextItem: + +SymbolContextItem +----------------- + +These mask bits allow a common interface for queries that can +limit the amount of information that gets parsed to only the +information that is requested. These bits also can indicate what +actually did get resolved during query function calls. + +Each definition corresponds to one of the member variables +in this class, and requests that that item be resolved, or +indicates that the member did get resolved. + +.. py:data:: eSymbolContextTarget + + Set when target is requested from a query, or was located + in query results. + +.. py:data:: eSymbolContextModule + + Set when module is requested from a query, or was located + in query results. + +.. py:data:: eSymbolContextCompUnit + + Set when compilation unit is requested from a query, or was + located in query results. + +.. py:data:: eSymbolContextFunction + + Set when function is requested from a query, or was located + in query results. + +.. py:data:: eSymbolContextBlock + + Set when the deepest block is requested from a query, or + was located in query results. + +.. py:data:: eSymbolContextLineEntry + + Set when line entry is requested from a query, or was + located in query results. + +.. py:data:: eSymbolContextSymbol + + Set when symbol is requested from a query, or was located + in query results + +.. py:data:: eSymbolContextEverything + + Indicates to try and lookup everything up during a routine + symbol context query. + +.. py:data:: eSymbolContextVariable + + Set when global or static variable is requested from a + query, or was located in query results. + eSymbolContextVariable is potentially expensive to lookup so + it isn't included in eSymbolContextEverything which stops it + from being used during frame PC lookups and many other + potential address to symbol context lookups. + + +.. _Permissions: + +Permissions +----------- +.. py:data:: ePermissionsWritable +.. py:data:: ePermissionsReadable +.. py:data:: ePermissionsExecutable + + +.. _InputReader: + +InputReader +----------- + +.. py:data:: eInputReaderActivate + + Reader is newly pushed onto the reader stack. + +.. py:data:: eInputReaderAsynchronousOutputWritten + + An async output event occurred; the reader may want to do something. + +.. py:data:: eInputReaderReactivate + + Reader is on top of the stack again after another reader was popped off. + +.. py:data:: eInputReaderDeactivate + + Another reader was pushed on the stack. + +.. py:data:: eInputReaderGotToken + + Reader got one of its tokens (granularity). + +.. py:data:: eInputReaderInterrupt + + Reader received an interrupt signal (probably from a control-c). + +.. py:data:: eInputReaderEndOfFile + + Reader received an EOF char (probably from a control-d). + +.. py:data:: eInputReaderDone + + Reader was just popped off the stack and is done. + + +.. _BreakpointEventType: + +BreakpointEventType +------------------- + +.. py:data:: eBreakpointEventTypeInvalidType +.. py:data:: eBreakpointEventTypeAdded +.. py:data:: eBreakpointEventTypeRemoved +.. py:data:: eBreakpointEventTypeLocationsAdded +.. py:data:: eBreakpointEventTypeLocationsRemoved +.. py:data:: eBreakpointEventTypeLocationsResolved +.. py:data:: eBreakpointEventTypeEnabled +.. py:data:: eBreakpointEventTypeDisabled +.. py:data:: eBreakpointEventTypeCommandChanged +.. py:data:: eBreakpointEventTypeConditionChanged +.. py:data:: eBreakpointEventTypeIgnoreChanged +.. py:data:: eBreakpointEventTypeThreadChanged +.. py:data:: eBreakpointEventTypeAutoContinueChanged + + +.. _WatchpointEventType: + +WatchpointEventType +------------------- + +.. py:data:: eWatchpointEventTypeInvalidType +.. py:data:: eWatchpointEventTypeAdded +.. py:data:: eWatchpointEventTypeRemoved +.. py:data:: eWatchpointEventTypeEnabled +.. py:data:: eWatchpointEventTypeDisabled +.. py:data:: eWatchpointEventTypeCommandChanged +.. py:data:: eWatchpointEventTypeConditionChanged +.. py:data:: eWatchpointEventTypeIgnoreChanged +.. py:data:: eWatchpointEventTypeThreadChanged +.. py:data:: eWatchpointEventTypeTypeChanged + + +.. _LanguageType: + +LanguageType +------------ + +.. py:data:: eLanguageTypeUnknown +.. py:data:: eLanguageTypeC89 +.. py:data:: eLanguageTypeC +.. py:data:: eLanguageTypeAda83 +.. py:data:: eLanguageTypeC_plus_plus +.. py:data:: eLanguageTypeCobol74 +.. py:data:: eLanguageTypeCobol85 +.. py:data:: eLanguageTypeFortran77 +.. py:data:: eLanguageTypeFortran90 +.. py:data:: eLanguageTypePascal83 +.. py:data:: eLanguageTypeModula2 +.. py:data:: eLanguageTypeJava +.. py:data:: eLanguageTypeC99 +.. py:data:: eLanguageTypeAda95 +.. py:data:: eLanguageTypeFortran95 +.. py:data:: eLanguageTypePLI +.. py:data:: eLanguageTypeObjC +.. py:data:: eLanguageTypeObjC_plus_plus +.. py:data:: eLanguageTypeUPC +.. py:data:: eLanguageTypeD +.. py:data:: eLanguageTypePython +.. py:data:: eLanguageTypeOpenCL +.. py:data:: eLanguageTypeGo +.. py:data:: eLanguageTypeModula3 +.. py:data:: eLanguageTypeHaskell +.. py:data:: eLanguageTypeC_plus_plus_03 +.. py:data:: eLanguageTypeC_plus_plus_11 +.. py:data:: eLanguageTypeOCaml +.. py:data:: eLanguageTypeRust +.. py:data:: eLanguageTypeC11 +.. py:data:: eLanguageTypeSwift +.. py:data:: eLanguageTypeJulia +.. py:data:: eLanguageTypeDylan +.. py:data:: eLanguageTypeC_plus_plus_14 +.. py:data:: eLanguageTypeFortran03 +.. py:data:: eLanguageTypeFortran08 +.. py:data:: eLanguageTypeMipsAssembler +.. py:data:: eLanguageTypeExtRenderScript +.. py:data:: eNumLanguageTypes + + +.. _InstrumentationRuntimeType: + +InstrumentationRuntimeType +-------------------------- + +.. py:data:: eInstrumentationRuntimeTypeAddressSanitizer +.. py:data:: eInstrumentationRuntimeTypeThreadSanitizer +.. py:data:: eInstrumentationRuntimeTypeUndefinedBehaviorSanitizer +.. py:data:: eInstrumentationRuntimeTypeMainThreadChecker +.. py:data:: eInstrumentationRuntimeTypeSwiftRuntimeReporting +.. py:data:: eNumInstrumentationRuntimeTypes + + +.. _DynamicValueType: + +DynamicValueType +---------------- + +.. py:data:: eNoDynamicValues +.. py:data:: eDynamicCanRunTarget +.. py:data:: eDynamicDontRunTarget + + +.. _StopShowColumn: + +StopShowColumn +-------------- + +.. py:data:: eStopShowColumnAnsiOrCaret +.. py:data:: eStopShowColumnAnsi +.. py:data:: eStopShowColumnCaret +.. py:data:: eStopShowColumnNone + + +.. _AccessType: + +AccessType +---------- + +.. py:data:: eAccessNone +.. py:data:: eAccessPublic +.. py:data:: eAccessPrivate +.. py:data:: eAccessProtected +.. py:data:: eAccessPackage + + +.. _CommandArgumentType: + +CommandArgumentType +------------------- + +.. py:data:: eArgTypeAddress +.. py:data:: eArgTypeAddressOrExpression +.. py:data:: eArgTypeAliasName +.. py:data:: eArgTypeAliasOptions +.. py:data:: eArgTypeArchitecture +.. py:data:: eArgTypeBoolean +.. py:data:: eArgTypeBreakpointID +.. py:data:: eArgTypeBreakpointIDRange +.. py:data:: eArgTypeBreakpointName +.. py:data:: eArgTypeByteSize +.. py:data:: eArgTypeClassName +.. py:data:: eArgTypeCommandName +.. py:data:: eArgTypeCount +.. py:data:: eArgTypeDescriptionVerbosity +.. py:data:: eArgTypeDirectoryName +.. py:data:: eArgTypeDisassemblyFlavor +.. py:data:: eArgTypeEndAddress +.. py:data:: eArgTypeExpression +.. py:data:: eArgTypeExpressionPath +.. py:data:: eArgTypeExprFormat +.. py:data:: eArgTypeFileLineColumn +.. py:data:: eArgTypeFilename +.. py:data:: eArgTypeFormat +.. py:data:: eArgTypeFrameIndex +.. py:data:: eArgTypeFullName +.. py:data:: eArgTypeFunctionName +.. py:data:: eArgTypeFunctionOrSymbol +.. py:data:: eArgTypeGDBFormat +.. py:data:: eArgTypeHelpText +.. py:data:: eArgTypeIndex +.. py:data:: eArgTypeLanguage +.. py:data:: eArgTypeLineNum +.. py:data:: eArgTypeLogCategory +.. py:data:: eArgTypeLogChannel +.. py:data:: eArgTypeMethod +.. py:data:: eArgTypeName +.. py:data:: eArgTypeNewPathPrefix +.. py:data:: eArgTypeNumLines +.. py:data:: eArgTypeNumberPerLine +.. py:data:: eArgTypeOffset +.. py:data:: eArgTypeOldPathPrefix +.. py:data:: eArgTypeOneLiner +.. py:data:: eArgTypePath +.. py:data:: eArgTypePermissionsNumber +.. py:data:: eArgTypePermissionsString +.. py:data:: eArgTypePid +.. py:data:: eArgTypePlugin +.. py:data:: eArgTypeProcessName +.. py:data:: eArgTypePythonClass +.. py:data:: eArgTypePythonFunction +.. py:data:: eArgTypePythonScript +.. py:data:: eArgTypeQueueName +.. py:data:: eArgTypeRegisterName +.. py:data:: eArgTypeRegularExpression +.. py:data:: eArgTypeRunArgs +.. py:data:: eArgTypeRunMode +.. py:data:: eArgTypeScriptedCommandSynchronicity +.. py:data:: eArgTypeScriptLang +.. py:data:: eArgTypeSearchWord +.. py:data:: eArgTypeSelector +.. py:data:: eArgTypeSettingIndex +.. py:data:: eArgTypeSettingKey +.. py:data:: eArgTypeSettingPrefix +.. py:data:: eArgTypeSettingVariableName +.. py:data:: eArgTypeShlibName +.. py:data:: eArgTypeSourceFile +.. py:data:: eArgTypeSortOrder +.. py:data:: eArgTypeStartAddress +.. py:data:: eArgTypeSummaryString +.. py:data:: eArgTypeSymbol +.. py:data:: eArgTypeThreadID +.. py:data:: eArgTypeThreadIndex +.. py:data:: eArgTypeThreadName +.. py:data:: eArgTypeTypeName +.. py:data:: eArgTypeUnsignedInteger +.. py:data:: eArgTypeUnixSignal +.. py:data:: eArgTypeVarName +.. py:data:: eArgTypeValue +.. py:data:: eArgTypeWidth +.. py:data:: eArgTypeNone +.. py:data:: eArgTypePlatform +.. py:data:: eArgTypeWatchpointID +.. py:data:: eArgTypeWatchpointIDRange +.. py:data:: eArgTypeWatchType +.. py:data:: eArgRawInput +.. py:data:: eArgTypeCommand +.. py:data:: eArgTypeColumnNum +.. py:data:: eArgTypeModuleUUID +.. py:data:: eArgTypeLastArg + +.. _SymbolType: + +SymbolType +---------- + +.. py:data:: eSymbolTypeAny +.. py:data:: eSymbolTypeInvalid +.. py:data:: eSymbolTypeAbsolute +.. py:data:: eSymbolTypeCode +.. py:data:: eSymbolTypeResolver +.. py:data:: eSymbolTypeData +.. py:data:: eSymbolTypeTrampoline +.. py:data:: eSymbolTypeRuntime +.. py:data:: eSymbolTypeException +.. py:data:: eSymbolTypeSourceFile +.. py:data:: eSymbolTypeHeaderFile +.. py:data:: eSymbolTypeObjectFile +.. py:data:: eSymbolTypeCommonBlock +.. py:data:: eSymbolTypeBlock +.. py:data:: eSymbolTypeLocal +.. py:data:: eSymbolTypeParam +.. py:data:: eSymbolTypeVariable +.. py:data:: eSymbolTypeVariableType +.. py:data:: eSymbolTypeLineEntry +.. py:data:: eSymbolTypeLineHeader +.. py:data:: eSymbolTypeScopeBegin +.. py:data:: eSymbolTypeScopeEnd +.. py:data:: eSymbolTypeAdditional +.. py:data:: eSymbolTypeCompiler +.. py:data:: eSymbolTypeInstrumentation +.. py:data:: eSymbolTypeUndefined +.. py:data:: eSymbolTypeObjCClass +.. py:data:: eSymbolTypeObjCMetaClass +.. py:data:: eSymbolTypeObjCIVar +.. py:data:: eSymbolTypeReExported + + +.. _SectionType: + +SectionType +----------- + +.. py:data:: eSectionTypeInvalid +.. py:data:: eSectionTypeCode +.. py:data:: eSectionTypeContainer +.. py:data:: eSectionTypeData +.. py:data:: eSectionTypeDataCString +.. py:data:: eSectionTypeDataCStringPointers +.. py:data:: eSectionTypeDataSymbolAddress +.. py:data:: eSectionTypeData4 +.. py:data:: eSectionTypeData8 +.. py:data:: eSectionTypeData16 +.. py:data:: eSectionTypeDataPointers +.. py:data:: eSectionTypeDebug +.. py:data:: eSectionTypeZeroFill +.. py:data:: eSectionTypeDataObjCMessageRefs +.. py:data:: eSectionTypeDataObjCCFStrings +.. py:data:: eSectionTypeDWARFDebugAbbrev +.. py:data:: eSectionTypeDWARFDebugAddr +.. py:data:: eSectionTypeDWARFDebugAranges +.. py:data:: eSectionTypeDWARFDebugCuIndex +.. py:data:: eSectionTypeDWARFDebugFrame +.. py:data:: eSectionTypeDWARFDebugInfo +.. py:data:: eSectionTypeDWARFDebugLine +.. py:data:: eSectionTypeDWARFDebugLoc +.. py:data:: eSectionTypeDWARFDebugMacInfo +.. py:data:: eSectionTypeDWARFDebugMacro +.. py:data:: eSectionTypeDWARFDebugPubNames +.. py:data:: eSectionTypeDWARFDebugPubTypes +.. py:data:: eSectionTypeDWARFDebugRanges +.. py:data:: eSectionTypeDWARFDebugStr +.. py:data:: eSectionTypeDWARFDebugStrOffsets +.. py:data:: eSectionTypeDWARFAppleNames +.. py:data:: eSectionTypeDWARFAppleTypes +.. py:data:: eSectionTypeDWARFAppleNamespaces +.. py:data:: eSectionTypeDWARFAppleObjC +.. py:data:: eSectionTypeELFSymbolTable +.. py:data:: eSectionTypeELFDynamicSymbols +.. py:data:: eSectionTypeELFRelocationEntries +.. py:data:: eSectionTypeELFDynamicLinkInfo +.. py:data:: eSectionTypeEHFrame +.. py:data:: eSectionTypeARMexidx +.. py:data:: eSectionTypeARMextab +.. py:data:: eSectionTypeCompactUnwind +.. py:data:: eSectionTypeGoSymtab +.. py:data:: eSectionTypeAbsoluteAddress +.. py:data:: eSectionTypeDWARFGNUDebugAltLink +.. py:data:: eSectionTypeDWARFDebugTypes +.. py:data:: eSectionTypeDWARFDebugNames +.. py:data:: eSectionTypeOther +.. py:data:: eSectionTypeDWARFDebugLineStr +.. py:data:: eSectionTypeDWARFDebugRngLists +.. py:data:: eSectionTypeDWARFDebugLocLists +.. py:data:: eSectionTypeDWARFDebugAbbrevDwo +.. py:data:: eSectionTypeDWARFDebugInfoDwo +.. py:data:: eSectionTypeDWARFDebugStrDwo +.. py:data:: eSectionTypeDWARFDebugStrOffsetsDwo +.. py:data:: eSectionTypeDWARFDebugTypesDwo +.. py:data:: eSectionTypeDWARFDebugRngListsDwo +.. py:data:: eSectionTypeDWARFDebugLocDwo +.. py:data:: eSectionTypeDWARFDebugLocListsDwo +.. py:data:: eSectionTypeDWARFDebugTuIndex + + +.. _EmulatorInstructionOption: + +EmulatorInstructionOption +------------------------- + +.. py:data:: eEmulateInstructionOptionNone +.. py:data:: eEmulateInstructionOptionAutoAdvancePC +.. py:data:: eEmulateInstructionOptionIgnoreConditions + + +.. _FunctionNameType: + +FunctionNameType +---------------- + +.. py:data:: eFunctionNameTypeNone +.. py:data:: eFunctionNameTypeAuto +.. py:data:: eFunctionNameTypeFull +.. py:data:: eFunctionNameTypeBase +.. py:data:: eFunctionNameTypeMethod +.. py:data:: eFunctionNameTypeSelector +.. py:data:: eFunctionNameTypeAny + + +.. _BasicType: + +BasicType +--------- + +.. py:data:: eBasicTypeInvalid +.. py:data:: eBasicTypeVoid +.. py:data:: eBasicTypeChar +.. py:data:: eBasicTypeSignedChar +.. py:data:: eBasicTypeUnsignedChar +.. py:data:: eBasicTypeWChar +.. py:data:: eBasicTypeSignedWChar +.. py:data:: eBasicTypeUnsignedWChar +.. py:data:: eBasicTypeChar16 +.. py:data:: eBasicTypeChar32 +.. py:data:: eBasicTypeShort +.. py:data:: eBasicTypeUnsignedShort +.. py:data:: eBasicTypeInt +.. py:data:: eBasicTypeUnsignedInt +.. py:data:: eBasicTypeLong +.. py:data:: eBasicTypeUnsignedLong +.. py:data:: eBasicTypeLongLong +.. py:data:: eBasicTypeUnsignedLongLong +.. py:data:: eBasicTypeInt128 +.. py:data:: eBasicTypeUnsignedInt128 +.. py:data:: eBasicTypeBool +.. py:data:: eBasicTypeHalf +.. py:data:: eBasicTypeFloat +.. py:data:: eBasicTypeDouble +.. py:data:: eBasicTypeLongDouble +.. py:data:: eBasicTypeFloatComplex +.. py:data:: eBasicTypeDoubleComplex +.. py:data:: eBasicTypeLongDoubleComplex +.. py:data:: eBasicTypeObjCID +.. py:data:: eBasicTypeObjCClass +.. py:data:: eBasicTypeObjCSel +.. py:data:: eBasicTypeNullPtr +.. py:data:: eBasicTypeOther + + +.. _TraceType: + +TraceType +--------- + +.. py:data:: eTraceTypeNone +.. py:data:: eTraceTypeProcessorTrace + + +.. _StructuredDataType: + +StructuredDataType +------------------ + +.. py:data:: eStructuredDataTypeInvalid +.. py:data:: eStructuredDataTypeNull +.. py:data:: eStructuredDataTypeGeneric +.. py:data:: eStructuredDataTypeArray +.. py:data:: eStructuredDataTypeInteger +.. py:data:: eStructuredDataTypeFloat +.. py:data:: eStructuredDataTypeBoolean +.. py:data:: eStructuredDataTypeString +.. py:data:: eStructuredDataTypeDictionary + + +.. _TypeClass: + +TypeClass +--------- + +.. py:data:: eTypeClassInvalid +.. py:data:: eTypeClassArray +.. py:data:: eTypeClassBlockPointer +.. py:data:: eTypeClassBuiltin +.. py:data:: eTypeClassClass +.. py:data:: eTypeClassFloat +.. py:data:: eTypeClassComplexInteger +.. py:data:: eTypeClassComplexFloat +.. py:data:: eTypeClassFunction +.. py:data:: eTypeClassMemberPointer +.. py:data:: eTypeClassObjCObject +.. py:data:: eTypeClassObjCInterface +.. py:data:: eTypeClassObjCObjectPointer +.. py:data:: eTypeClassPointer +.. py:data:: eTypeClassReference +.. py:data:: eTypeClassStruct +.. py:data:: eTypeClassTypedef +.. py:data:: eTypeClassUnion +.. py:data:: eTypeClassVector +.. py:data:: eTypeClassOther +.. py:data:: eTypeClassAny + + +.. _TemplateArgument: + +TemplateArgument +---------------- + +.. py:data:: eTemplateArgumentKindNull +.. py:data:: eTemplateArgumentKindType +.. py:data:: eTemplateArgumentKindDeclaration +.. py:data:: eTemplateArgumentKindIntegral +.. py:data:: eTemplateArgumentKindTemplate +.. py:data:: eTemplateArgumentKindTemplateExpansion +.. py:data:: eTemplateArgumentKindExpression +.. py:data:: eTemplateArgumentKindPack +.. py:data:: eTemplateArgumentKindNullPtr +.. py:data:: eTemplateArgumentKindUncommonValue + + +.. _TypeOption: + +TypeOption +---------- + +Options that can be set for a formatter to alter its behavior. Not +all of these are applicable to all formatter types. + +.. py:data:: eTypeOptionNone +.. py:data:: eTypeOptionCascade +.. py:data:: eTypeOptionSkipPointers +.. py:data:: eTypeOptionSkipReferences +.. py:data:: eTypeOptionHideChildren +.. py:data:: eTypeOptionHideValue +.. py:data:: eTypeOptionShowOneLiner +.. py:data:: eTypeOptionHideNames +.. py:data:: eTypeOptionNonCacheable +.. py:data:: eTypeOptionHideEmptyAggregates +.. py:data:: eTypeOptionFrontEndWantsDereference + + + +.. _FrameCompare: + +FrameCompare +------------ + +This is the return value for frame comparisons. If you are comparing frame +A to frame B the following cases arise: + + 1) When frame A pushes frame B (or a frame that ends up pushing + B) A is Older than B. + + 2) When frame A pushed frame B (or if frameA is on the stack + but B is not) A is Younger than B. + + 3) When frame A and frame B have the same StackID, they are + Equal. + + 4) When frame A and frame B have the same immediate parent + frame, but are not equal, the comparison yields SameParent. + + 5) If the two frames are on different threads or processes the + comparison is Invalid. + + 6) If for some reason we can't figure out what went on, we + return Unknown. + +.. py:data:: eFrameCompareInvalid +.. py:data:: eFrameCompareUnknown +.. py:data:: eFrameCompareEqual +.. py:data:: eFrameCompareSameParent +.. py:data:: eFrameCompareYounger +.. py:data:: eFrameCompareOlder + + +.. _FilePermissions: + +FilePermissions +--------------- + +.. py:data:: eFilePermissionsUserRead +.. py:data:: eFilePermissionsUserWrite +.. py:data:: eFilePermissionsUserExecute +.. py:data:: eFilePermissionsGroupRead +.. py:data:: eFilePermissionsGroupWrite +.. py:data:: eFilePermissionsGroupExecute +.. py:data:: eFilePermissionsWorldRead +.. py:data:: eFilePermissionsWorldWrite +.. py:data:: eFilePermissionsWorldExecute +.. py:data:: eFilePermissionsUserRW +.. py:data:: eFileFilePermissionsUserRX +.. py:data:: eFilePermissionsUserRWX +.. py:data:: eFilePermissionsGroupRW +.. py:data:: eFilePermissionsGroupRX +.. py:data:: eFilePermissionsGroupRWX +.. py:data:: eFilePermissionsWorldRW +.. py:data:: eFilePermissionsWorldRX +.. py:data:: eFilePermissionsWorldRWX +.. py:data:: eFilePermissionsEveryoneR +.. py:data:: eFilePermissionsEveryoneW +.. py:data:: eFilePermissionsEveryoneX +.. py:data:: eFilePermissionsEveryoneRW +.. py:data:: eFilePermissionsEveryoneRX +.. py:data:: eFilePermissionsEveryoneRWX +.. py:data:: eFilePermissionsFileDefault = eFilePermissionsUserRW, +.. py:data:: eFilePermissionsDirectoryDefault + + +.. _QueueItem: + +QueueItem +--------- +.. py:data:: eQueueItemKindUnknown +.. py:data:: eQueueItemKindFunction +.. py:data:: eQueueItemKindBlock + + +.. _QueueKind: + +QueueKind +--------- + +libdispatch aka Grand Central Dispatch (GCD) queues can be either +serial (executing on one thread) or concurrent (executing on +multiple threads). + +.. py:data:: eQueueKindUnknown +.. py:data:: eQueueKindSerial +.. py:data:: eQueueKindConcurrent + + +.. _ExpressionEvaluationPhase: + +ExpressionEvaluationPhase +------------------------- + +These are the cancellable stages of expression evaluation, passed +to the expression evaluation callback, so that you can interrupt +expression evaluation at the various points in its lifecycle. + +.. py:data:: eExpressionEvaluationParse +.. py:data:: eExpressionEvaluationIRGen +.. py:data:: eExpressionEvaluationExecution +.. py:data:: eExpressionEvaluationComplete + + +.. _WatchpointKind: + +WatchpointKind +-------------- + +Indicates what types of events cause the watchpoint to fire. Used by Native +-Protocol-related classes. + +.. py:data:: eWatchpointKindWrite +.. py:data:: eWatchpointKindRead + + +.. _GdbSignal: + +GdbSignal +--------- + +.. py:data:: eGdbSignalBadAccess +.. py:data:: eGdbSignalBadInstruction +.. py:data:: eGdbSignalArithmetic +.. py:data:: eGdbSignalEmulation +.. py:data:: eGdbSignalSoftware +.. py:data:: eGdbSignalBreakpoint + +.. _PathType: + +PathType +-------- + +Used with `SBHostOS.GetLLDBPath` to find files that are +related to LLDB on the current host machine. Most files are +relative to LLDB or are in known locations. + +.. py:data:: ePathTypeLLDBShlibDir + + The directory where the lldb.so (unix) or LLDB mach-o file in + LLDB.framework (MacOSX) exists. + +.. py:data:: ePathTypeSupportExecutableDir + + Find LLDB support executable directory (debugserver, etc). + +.. py:data:: ePathTypeHeaderDir + + Find LLDB header file directory. + +.. py:data:: ePathTypePythonDir + + Find Python modules (PYTHONPATH) directory. + +.. py:data:: ePathTypeLLDBSystemPlugins + + System plug-ins directory + +.. py:data:: ePathTypeLLDBUserPlugins + + User plug-ins directory + +.. py:data:: ePathTypeLLDBTempSystemDir + + The LLDB temp directory for this system that will be cleaned up on exit. + +.. py:data:: ePathTypeGlobalLLDBTempSystemDir + + The LLDB temp directory for this system, NOT cleaned up on a process + exit. + +.. py:data:: ePathTypeClangDir + + Find path to Clang builtin headers. + + +.. _MemberFunctionKind: + +MemberFunctionKind +------------------ + +.. py:data:: eMemberFunctionKindUnknown +.. py:data:: eMemberFunctionKindConstructor + + A function used to create instances. + +.. py:data:: eMemberFunctionKindDestructor + + A function used to tear down existing instances. + +.. py:data:: eMemberFunctionKindInstanceMethod + + A function that applies to a specific instance. + +.. py:data:: eMemberFunctionKindStaticMethod + + A function that applies to a type rather than any instance, + + +.. _TypeFlags: + +TypeFlags +--------- + +.. py:data:: eTypeHasChildren +.. py:data:: eTypeIsArray +.. py:data:: eTypeIsBuiltIn +.. py:data:: eTypeIsCPlusPlus +.. py:data:: eTypeIsFuncPrototype +.. py:data:: eTypeIsObjC +.. py:data:: eTypeIsReference +.. py:data:: eTypeIsTemplate +.. py:data:: eTypeIsVector +.. py:data:: eTypeIsInteger +.. py:data:: eTypeIsComplex +.. py:data:: eTypeInstanceIsPointer + + +.. _CommandFlags: + +CommandFlags +--------------- + +.. py:data:: eCommandRequiresTarget +.. py:data:: eCommandRequiresProcess +.. py:data:: eCommandRequiresThread +.. py:data:: eCommandRequiresFrame +.. py:data:: eCommandRequiresRegContext +.. py:data:: eCommandTryTargetAPILock +.. py:data:: eCommandProcessMustBeLaunched +.. py:data:: eCommandProcessMustBePaused +.. py:data:: eCommandProcessMustBeTraced + + +.. _TypeSummary: + +TypeSummary +----------- + +Whether a summary should cap how much data it returns to users or not. + +.. py:data:: eTypeSummaryCapped +.. py:data:: eTypeSummaryUncapped + + +.. _CommandInterpreterResult: + +CommandInterpreterResult +------------------------ + +The result from a command interpreter run. + +.. py:data:: eCommandInterpreterResultSuccess + + Command interpreter finished successfully. + +.. py:data:: eCommandInterpreterResultInferiorCrash + + Stopped because the corresponding option was set and the inferior + crashed. + +.. py:data:: eCommandInterpreterResultCommandError + + Stopped because the corresponding option was set and a command returned + an error. + +.. py:data:: eCommandInterpreterResultQuitRequested + + Stopped because quit was requested. diff --git a/gnu/llvm/lldb/docs/resources/bots.rst b/gnu/llvm/lldb/docs/resources/bots.rst index efe8c7116b0..8a43f53bd25 100644 --- a/gnu/llvm/lldb/docs/resources/bots.rst +++ b/gnu/llvm/lldb/docs/resources/bots.rst @@ -7,18 +7,15 @@ Buildbot LLVM Buildbot is the place where volunteers provide build machines. Everyone can `add a buildbot for LLDB `_. -* `lldb-x64-windows-ninja `_ -* `lldb-x86_64-debian `_ -* `lldb-aarch64-ubuntu `_ -* `lldb-x86_64-fedora `_ +* `lldb-x64-windows-ninja `_ +* `lldb-x86_64-debian `_ +* `lldb-aarch64-ubuntu `_ +* `lldb-arm-ubuntu `_ +* `lldb-x86_64-fedora `_ -Documentation -------------- +An overview of all LLDB builders (except Fedora) can be found here: -The documentation bot validates that the website builds correctly with Sphinx. -It does not generate the website itself, which happens on a separate server. - -* `lldb-sphinx-docs `_ +`https://lab.llvm.org/buildbot/#/builders?tags=lldb `_ GreenDragon ----------- @@ -28,7 +25,14 @@ GreenDragon builds and tests LLDB on macOS. It has a `dedicated tab * `lldb-cmake `_ * `lldb-cmake-matrix `_ -* `lldb-cmake-python3 `_ +* `lldb-cmake-reproducers `_ * `lldb-cmake-standalone `_ * `lldb-cmake-sanitized `_ +Documentation +------------- + +The documentation bot validates that the website builds correctly with Sphinx. +It does not generate the website itself, which happens on a separate server. + +* `lldb-sphinx-docs `_ diff --git a/gnu/llvm/lldb/docs/resources/build.rst b/gnu/llvm/lldb/docs/resources/build.rst index c1cb6ec1a93..6e2afcae0e2 100644 --- a/gnu/llvm/lldb/docs/resources/build.rst +++ b/gnu/llvm/lldb/docs/resources/build.rst @@ -12,7 +12,7 @@ Please refer to the `LLVM Getting Started Guide general instructions on how to check out the LLVM monorepo, which contains the LLDB sources. -Git browser: https://github.com/llvm/llvm-project/tree/master/lldb +Git browser: https://github.com/llvm/llvm-project/tree/main/lldb Preliminaries ------------- @@ -34,7 +34,7 @@ If you want to run the test suite, you'll need to build LLDB with Python scripting support. * `Python `_ -* `SWIG `_ 2 or later. +* `SWIG `_ 3 or later. Optional Dependencies ********************* @@ -71,11 +71,17 @@ commands below. :: > yum install libedit-devel libxml2-devel ncurses-devel python-devel swig - > sudo apt-get install build-essential subversion swig python2.7-dev libedit-dev libncurses5-dev + > sudo apt-get install build-essential swig python3-dev libedit-dev libncurses5-dev > pkg install swig python - > pkgin install swig python27 cmake ninja-build + > pkgin install swig python36 cmake ninja-build > brew install swig cmake ninja +Note that there's an `incompatibility +`_ between Python version 3.7 and later +and swig versions older than 4.0.0 which makes builds of LLDB using debug +versions of python unusable. This primarily affects Windows, as debug builds of +LLDB must use debug python as well. + Windows ******* @@ -83,10 +89,9 @@ Windows * The latest Windows SDK. * The Active Template Library (ATL). * `GnuWin32 `_ for CoreUtils and Make. -* `Python 3.6 or 3.8 `_. Python 3.7 - is known to be incompatible. Make sure to (1) get the x64 variant if that's - what you're targetting and (2) install the debug library if you want to build - a debug lldb. +* `Python 3 `_. Make sure to (1) get + the x64 variant if that's what you're targetting and (2) install the debug + library if you want to build a debug lldb. * `Python Tools for Visual Studio `_. If you plan to debug test failures or even write new tests at all, PTVS is an indispensable debugging @@ -128,7 +133,7 @@ macOS Building LLDB with CMake ------------------------ -The LLVM project is migrating to a single monolithic respository for LLVM and +The LLVM project is migrating to a single monolithic repository for LLVM and its subprojects. This is the recommended way to build LLDB. Check out the source-tree with git: @@ -244,7 +249,7 @@ Windows On Windows the LLDB test suite requires lld. Either add ``lld`` to ``LLVM_ENABLE_PROJECTS`` or disable the test suite with -``LLDB_ENABLE_TESTS=OFF``. +``LLDB_INCLUDE_TESTS=OFF``. Although the following CMake variables are by no means Windows specific, they are commonly used on Windows. @@ -300,7 +305,7 @@ macOS On macOS the LLDB test suite requires libc++. Either add ``libcxx`` to ``LLVM_ENABLE_PROJECTS`` or disable the test suite with -``LLDB_ENABLE_TESTS=OFF``. Further useful options: +``LLDB_INCLUDE_TESTS=OFF``. Further useful options: * ``LLDB_BUILD_FRAMEWORK:BOOL``: Builds the LLDB.framework. * ``LLDB_CODESIGN_IDENTITY:STRING``: Set the identity to use for code-signing @@ -321,7 +326,7 @@ CMake scripts and can be useful to reproduce builds for particular use-cases A cache is passed to CMake with the ``-C`` flag, following the absolute path to the file on disk. Subsequent ``-D`` options are still allowed. Please find the currently available caches in the `lldb/cmake/caches/ -`_ +`_ directory. Common configurations on macOS @@ -575,8 +580,11 @@ Code Signing on macOS To use the in-tree debug server on macOS, lldb needs to be code signed. The Debug, DebugClang and Release builds are set to code sign using a code signing -certificate named ``lldb_codesign``. This document explains how to set up the -signing certificate. +certificate named ``lldb_codesign``. + +Automatic setup, run: + +* ``scripts/macos-setup-codesign.sh`` Note that it's possible to build and use lldb on macOS without setting up code signing by using the system's debug server. To configure lldb in this way with @@ -589,56 +597,6 @@ build folders that contained old signed items. The darwin kernel will cache code signing using the executable's file system node, so you will need to delete the file so the kernel clears its cache. -Automatic setup: - -* Run ``scripts/macos-setup-codesign.sh`` - -Manual setup steps: - -* Launch /Applications/Utilities/Keychain Access.app -* In Keychain Access select the ``login`` keychain in the ``Keychains`` list in - the upper left hand corner of the window. -* Select the following menu item: Keychain Access->Certificate Assistant->Create a Certificate... -* Set the following settings - -:: - - Name = lldb_codesign - Identity Type = Self Signed Root - Certificate Type = Code Signing - -* Click Create -* Click Continue -* Click Done -* Click on the "My Certificates" -* Double click on your new ``lldb_codesign`` certificate -* Turn down the "Trust" disclosure triangle, scroll to the "Code Signing" trust - pulldown menu and select "Always Trust" and authenticate as needed using your - username and password. -* Drag the new ``lldb_codesign`` code signing certificate (not the public or - private keys of the same name) from the ``login`` keychain to the ``System`` - keychain in the Keychains pane on the left hand side of the main Keychain - Access window. This will move this certificate to the ``System`` keychain. - You'll have to authorize a few more times, set it to be "Always trusted" when - asked. -* Remove ``~/Desktop/lldb_codesign.cer`` file on your desktop if there is one. -* In the Keychain Access GUI, click and drag ``lldb_codesign`` in the - ``System`` keychain onto the desktop. The drag will create a - ``Desktop/lldb_codesign.cer`` file used in the next step. -* Switch to Terminal, and run the following: - -:: - - sudo security add-trust -d -r trustRoot -p basic -p codeSign -k /Library/Keychains/System.keychain ~/Desktop/lldb_codesign.cer - rm -f ~/Desktop/lldb_codesign.cer - -* Drag the ``lldb_codesign`` certificate from the ``System`` keychain back into - the ``login`` keychain -* Quit Keychain Access -* Reboot -* Clean by removing all previously creating code signed binaries and rebuild - lldb and you should be able to debug. - When you build your LLDB for the first time, the Xcode GUI will prompt you for permission to use the ``lldb_codesign`` keychain. Be sure to click "Always Allow" on your first build. From here on out, the ``lldb_codesign`` will be diff --git a/gnu/llvm/lldb/docs/resources/caveats.rst b/gnu/llvm/lldb/docs/resources/caveats.rst index 2f37a6821ca..e46c364a540 100644 --- a/gnu/llvm/lldb/docs/resources/caveats.rst +++ b/gnu/llvm/lldb/docs/resources/caveats.rst @@ -21,7 +21,7 @@ against Python comes with some constraints to be aware of. use it from Python 2 and vice versa. 2. It is not possible to build and link LLDB against one distribution on - Python and use it through a interpreter coming from another distribution. + Python and use it through an interpreter coming from another distribution. For example, on macOS, if you build and link against Python from python.org, you cannot import the lldb module from the Python interpreter installed with Homebrew. diff --git a/gnu/llvm/lldb/docs/resources/contributing.rst b/gnu/llvm/lldb/docs/resources/contributing.rst index 81171ec8524..26b13a5b745 100644 --- a/gnu/llvm/lldb/docs/resources/contributing.rst +++ b/gnu/llvm/lldb/docs/resources/contributing.rst @@ -8,7 +8,7 @@ Please refer to the `LLVM Getting Started Guide `_ for general information on how to get started on the LLVM project. A detailed explanation on how to build and test LLDB can be found in the `build instructions `_ and `test -instructions `_ respecitvely. +instructions `_ respectively. Contributing to LLDB -------------------- @@ -20,7 +20,7 @@ Policy in the following respects. - **Test infrastructure**: Like LLVM it is important to submit tests with your patches, but note that LLDB uses a different system for tests. Refer to the - `test documentation `_ for more details and the `lldb/test` + `test documentation `_ for more details and the ``lldb/test`` folder on disk for examples. - **Coding Style**: LLDB's code style differs from LLVM's coding style. @@ -50,7 +50,7 @@ rules of thumb: wrapper types instead of using a bool to indicate success. Returning a default value when an error occurred is also discouraged. -* Assertions. Assertions (from `assert.h`) should be used liberally +* Assertions. Assertions (from ``assert.h``) should be used liberally to assert internal consistency. Assertions shall **never** be used to detect invalid user input, such as malformed DWARF. An assertion should be placed to assert invariants that the developer @@ -64,18 +64,18 @@ rules of thumb: errors cannot reasonably be surfaced to the end user, the error may be written to a topical log channel. -* Soft assertions. LLDB provides `lldb_assert()` as a soft +* Soft assertions. LLDB provides ``lldb_assert()`` as a soft alternative to cover the middle ground of situations that indicate a - recoverable bug in LLDB. In a Debug configuration `lldb_assert()` - behaves like `assert()`. In a Release configuration it will print a + recoverable bug in LLDB. In a Debug configuration ``lldb_assert()`` + behaves like ``assert()``. In a Release configuration it will print a warning and encourage the user to file a bug report, similar to LLVM's crash handler, and then return execution. Use these sparingly and only if error handling is not otherwise feasible. Specifically, - new code should not be using `lldb_assert()` and existing + new code should not be using ``lldb_assert()`` and existing uses should be replaced by other means of error handling. * Fatal errors. Aborting LLDB's process using - `llvm::report_fatal_error()` or `abort()` should be avoided at all + ``llvm::report_fatal_error()`` or ``abort()`` should be avoided at all costs. It's acceptable to use `llvm_unreachable() `_ for actually unreachable code such as the default in an otherwise diff --git a/gnu/llvm/lldb/docs/resources/test.rst b/gnu/llvm/lldb/docs/resources/test.rst index 6f39a45d4b7..d2830bc53c1 100644 --- a/gnu/llvm/lldb/docs/resources/test.rst +++ b/gnu/llvm/lldb/docs/resources/test.rst @@ -80,7 +80,7 @@ operating systems. Finally, the shell tests always run in batch mode. You start with some input and the test verifies the output. The debugger can be sensitive to its -environment, such as the the platform it runs on. It can be hard to express +environment, such as the platform it runs on. It can be hard to express that the same test might behave slightly differently on macOS and Linux. Additionally, the debugger is an interactive tool, and the shell test provide no good way of testing those interactive aspects, such as tab completion for @@ -99,10 +99,10 @@ implementation is located under ``lldb/packages/Python/lldbsuite``. We have several extensions and custom test primitives on top of what's offered by `unittest2 `_. Those can be found in -`lldbtest.py `_. +`lldbtest.py `_. Below is the directory layout of the `example API test -`_. +`_. The test directory will always contain a python file, starting with ``Test``. Most of the tests are structured as a binary being debugged, so there will be one or more source files and a ``Makefile``. @@ -127,7 +127,7 @@ Our testing framework also has a bunch of utilities that abstract common operations, such as creating targets, setting breakpoints etc. When code is shared across tests, we extract it into a utility in ``lldbutil``. It's always worth taking a look at `lldbutil -`_ +`_ to see if there's a utility to simplify some of the testing boiler plate. Because we can't always audit every existing test, this is doubly true when looking at an existing test for inspiration. @@ -156,7 +156,7 @@ test, the API test also allow for much more complex scenarios when it comes to building inferiors. Every test has its own ``Makefile``, most of them only a few lines long. A shared ``Makefile`` (``Makefile.rules``) with about a thousand lines of rules takes care of most if not all of the boiler plate, -while individual make files can be used to build more advanced tests. 
 +while individual make files can be used to build more advanced tests. Here's an example of a simple ``Makefile`` used by the example test. @@ -168,7 +168,7 @@ Here's an example of a simple ``Makefile`` used by the example test. include Makefile.rules Finding the right variables to set can be tricky. You can always take a look at -`Makefile.rules `_ +`Makefile.rules `_ but often it's easier to find an existing ``Makefile`` that does something similar to what you want to do. @@ -196,6 +196,129 @@ program being debugged. The fact that the API tests work with different variants mean that more general tests should be API tests, so that they can be run against the different variants. +Guidelines for API tests +^^^^^^^^^^^^^^^^^^^^^^^^ + +API tests are expected to be fast, reliable and maintainable. To achieve this +goal, API tests should conform to the following guidelines in addition to normal +good testing practices. + +**Don't unnecessarily launch the test executable.** + Launching a process and running to a breakpoint can often be the most + expensive part of a test and should be avoided if possible. A large part + of LLDB's functionality is available directly after creating an `SBTarget` + of the test executable. + + The part of the SB API that can be tested with just a target includes + everything that represents information about the executable and its + debug information (e.g., `SBTarget`, `SBModule`, `SBSymbolContext`, + `SBFunction`, `SBInstruction`, `SBCompileUnit`, etc.). For test executables + written in languages with a type system that is mostly defined at compile + time (e.g., C and C++) there is also usually no process necessary to test + the `SBType`-related parts of the API. With those languages it's also + possible to test `SBValue` by running expressions with + `SBTarget.EvaluateExpression` or the `expect_expr` testing utility. + + Functionality that always requires a running process is everything that + tests the `SBProcess`, `SBThread`, and `SBFrame` classes. The same is true + for tests that exercise breakpoints, watchpoints and sanitizers. + Languages such as Objective-C that have a dependency on a runtime + environment also always require a running process. + +**Don't unnecessarily include system headers in test sources.** + Including external headers slows down the compilation of the test executable + and it makes reproducing test failures on other operating systems or + configurations harder. + +**Avoid specifying test-specific compiler flags when including system headers.** + If a test requires including a system header (e.g., a test for a libc++ + formatter includes a libc++ header), try to avoid specifying custom compiler + flags if possible. Certain debug information formats such as ``gmodules`` + use a cache that is shared between all API tests and that contains + precompiled system headers. If you add or remove a specific compiler flag + in your test (e.g., adding ``-DFOO`` to the ``Makefile`` or ``self.build`` + arguments), then the test will not use the shared precompiled header cache + and expensively recompile all system headers from scratch. If you depend on + a specific compiler flag for the test, you can avoid this issue by either + removing all system header includes or decorating the test function with + ``@no_debug_info_test`` (which will avoid running all debug information + variants including ``gmodules``). + +**Test programs should be kept simple.** + Test executables should do the minimum amount of work to bring the process + into the state that is required for the test. Simulating a 'real' program + that actually tries to do some useful task rarely helps with catching bugs + and makes the test much harder to debug and maintain. The test programs + should always be deterministic (i.e., do not generate and check against + random test values). + +**Identifiers in tests should be simple and descriptive.** + Often test programs need to declare functions and classes which require + choosing some form of identifier for them. These identifiers should always + either be kept simple for small tests (e.g., ``A``, ``B``, ...) or have some + descriptive name (e.g., ``ClassWithTailPadding``, ``inlined_func``, ...). + Never choose identifiers that are already used anywhere else in LLVM or + other programs (e.g., don't name a class ``VirtualFileSystem``, a function + ``llvm_unreachable``, or a namespace ``rapidxml``) as this will mislead + people ``grep``'ing the LLVM repository for those strings. + +**Prefer LLDB testing utilities over directly working with the SB API.** + The ``lldbutil`` module and the ``TestBase`` class come with a large amount + of utility functions that can do common test setup tasks (e.g., starting a + test executable and running the process to a breakpoint). Using these + functions not only keeps the test shorter and free of duplicated code, but + they also follow best test suite practices and usually give much clearer + error messages if something goes wrong. The test utilities also contain + custom asserts and checks that should be preferably used (e.g. + ``self.assertSuccess``). + +**Prefer calling the SB API over checking command output.** + Avoid writing your tests on top of ``self.expect(...)`` calls that check + the output of LLDB commands and instead try calling into the SB API. Relying + on LLDB commands makes changing (and improving) the output/syntax of + commands harder and the resulting tests are often prone to accepting + incorrect test results. Especially improved error messages that contain + more information might cause these ``self.expect`` calls to unintentionally + find the required ``substrs``. For example, the following ``self.expect`` + check will unexpectedly pass if it's ran as the first expression in a test: + +:: + + self.expect("expr 2 + 2", substrs=["0"]) + +When running the same command in LLDB the reason for the unexpected success +is that '0' is found in the name of the implicitly created result variable: + +:: + + (lldb) expr 2 + 2 + (int) $0 = 4 + ^ The '0' substring is found here. + +A better way to write the test above would be using LLDB's testing function +``expect_expr`` will only pass if the expression produces a value of 0: + +:: + + self.expect_expr("2 + 2", result_value="0") + +**Prefer using specific asserts over the generic assertTrue/assertFalse.**. + The `self.assertTrue`/`self.assertFalse` functions should always be your + last option as they give non-descriptive error messages. The test class has + several expressive asserts such as `self.assertIn` that automatically + generate an explanation how the received values differ from the expected + ones. Check the documentation of Python's `unittest` module to see what + asserts are available. If you can't find a specific assert that fits your + needs and you fall back to a generic assert, make sure you put useful + information into the assert's `msg` argument that helps explain the failure. + +:: + + # Bad. Will print a generic error such as 'False is not True'. + self.assertTrue(expected_string in list_of_results) + # Good. Will print expected_string and the contents of list_of_results. + self.assertIn(expected_string, list_of_results) + Running The Tests ----------------- @@ -360,11 +483,33 @@ Currently, running the remote test suite is supported only with ``dotest.py`` (o dosep.py with a single thread), but we expect this issue to be addressed in the near future. +Running tests in QEMU System Emulation Environment +`````````````````````````````````````````````````` + +QEMU can be used to test LLDB in an emulation environment in the absence of +actual hardware. `QEMU based testing `_ +page describes how to setup an emulation environment using QEMU helper scripts +found under llvm-project/lldb/scripts/lldb-test-qemu. These scripts currently +work with Arm or AArch64, but support for other architectures can be added easily. + Debugging Test Failures ----------------------- On non-Windows platforms, you can use the ``-d`` option to ``dotest.py`` which -will cause the script to wait for a while until a debugger is attached. +will cause the script to print out the pid of the test and wait for a while +until a debugger is attached. Then run ``lldb -p `` to attach. + +To instead debug a test's python source, edit the test and insert +``import pdb; pdb.set_trace()`` at the point you want to start debugging. In +addition to pdb's debugging facilities, lldb commands can be executed with the +help of a pdb alias. For example ``lldb bt`` and ``lldb v some_var``. Add this +line to your ``~/.pdbrc``: + +:: + + alias lldb self.dbg.HandleCommand("%*") + +:: Debugging Test Failures on Windows `````````````````````````````````` diff --git a/gnu/llvm/lldb/docs/status/projects.rst b/gnu/llvm/lldb/docs/status/projects.rst index 48081da5957..245654dd2ae 100644 --- a/gnu/llvm/lldb/docs/status/projects.rst +++ b/gnu/llvm/lldb/docs/status/projects.rst @@ -253,7 +253,7 @@ Use instruction emulation to reduce the overhead for breakpoints At present, breakpoints are implemented by inserting a trap instruction, then when the trap is hit, replace the trap with the actual instruction and single step. Then swap back and continue. This causes problems for read only text, and -also means that no-stop debugging ust either stop all threads briefly to handle +also means that no-stop debugging must either stop all threads briefly to handle this two-step or risk missing some breakpoint hits. If you emulated the instruction and wrote back the results, you wouldn't have these problems, and it would also save a stop per breakpoint hit. Since we use breakpoints to diff --git a/gnu/llvm/lldb/docs/status/status.rst b/gnu/llvm/lldb/docs/status/status.rst index 5b7fd663577..5ad19b898b9 100644 --- a/gnu/llvm/lldb/docs/status/status.rst +++ b/gnu/llvm/lldb/docs/status/status.rst @@ -43,26 +43,26 @@ section below. Features Matrix --------------- -+-----------------------+------------+-------------------------+-------------------+--------------------+----------------------+ -| Feature | FreeBSD | Linux | macOS | NetBSD | Windows | -+=======================+============+=========================+===================+====================+======================+ -| Backtracing | YES | YES | YES | YES | YES | -+-----------------------+------------+-------------------------+-------------------+--------------------+----------------------+ -| Breakpoints | YES | YES | YES | YES | YES | -+-----------------------+------------+-------------------------+-------------------+--------------------+----------------------+ -| C++11: | YES | YES | YES | YES | Unknown | -+-----------------------+------------+-------------------------+-------------------+--------------------+----------------------+ -| Commandline tool | YES | YES | YES | YES | YES | -+-----------------------+------------+-------------------------+-------------------+--------------------+----------------------+ -| Core file debugging | YES (ELF) | YES (ELF) | YES (MachO) | YES (ELF) | YES (Minidump) | -+-----------------------+------------+-------------------------+-------------------+--------------------+----------------------+ -| Remote debugging | NO | YES (lldb-server) | YES (debugserver) | YES (lldb-server) | NO | -+-----------------------+------------+-------------------------+-------------------+--------------------+----------------------+ -| Disassembly | YES | YES | YES | YES | YES | -+-----------------------+------------+-------------------------+-------------------+--------------------+----------------------+ -| Expression evaluation | Unknown | YES (known issues) | YES | YES (known issues) | YES (known issues) | -+-----------------------+------------+-------------------------+-------------------+--------------------+----------------------+ -| JIT debugging | Unknown | Symbolic debugging only | Untested | Work In Progress | NO | -+-----------------------+------------+-------------------------+-------------------+--------------------+----------------------+ -| Objective-C 2.0: | Unknown | N/A | YES | Unknown | N/A | -+-----------------------+------------+-------------------------+-------------------+--------------------+----------------------+ ++-----------------------+--------------------+-------------------------+-------------------+--------------------+----------------------+ +| Feature | FreeBSD | Linux | macOS | NetBSD | Windows | ++=======================+====================+=========================+===================+====================+======================+ +| Backtracing | YES | YES | YES | YES | YES | ++-----------------------+--------------------+-------------------------+-------------------+--------------------+----------------------+ +| Breakpoints | YES | YES | YES | YES | YES | ++-----------------------+--------------------+-------------------------+-------------------+--------------------+----------------------+ +| C++11: | YES | YES | YES | YES | Unknown | ++-----------------------+--------------------+-------------------------+-------------------+--------------------+----------------------+ +| Commandline tool | YES | YES | YES | YES | YES | ++-----------------------+--------------------+-------------------------+-------------------+--------------------+----------------------+ +| Core file debugging | YES (ELF) | YES (ELF) | YES (MachO) | YES (ELF) | YES (Minidump) | ++-----------------------+--------------------+-------------------------+-------------------+--------------------+----------------------+ +| Remote debugging | YES (lldb-server) | YES (lldb-server) | YES (debugserver) | YES (lldb-server) | NO | ++-----------------------+--------------------+-------------------------+-------------------+--------------------+----------------------+ +| Disassembly | YES | YES | YES | YES | YES | ++-----------------------+--------------------+-------------------------+-------------------+--------------------+----------------------+ +| Expression evaluation | YES (known issues) | YES (known issues) | YES | YES (known issues) | YES (known issues) | ++-----------------------+--------------------+-------------------------+-------------------+--------------------+----------------------+ +| JIT debugging | Unknown | Symbolic debugging only | Untested | Work In Progress | NO | ++-----------------------+--------------------+-------------------------+-------------------+--------------------+----------------------+ +| Objective-C 2.0: | Unknown | N/A | YES | Unknown | N/A | ++-----------------------+--------------------+-------------------------+-------------------+--------------------+----------------------+ diff --git a/gnu/llvm/lldb/docs/use/links.md b/gnu/llvm/lldb/docs/use/links.md new file mode 100644 index 00000000000..8c125a26cb4 --- /dev/null +++ b/gnu/llvm/lldb/docs/use/links.md @@ -0,0 +1,56 @@ +Links +===== + +This page contains links to external resources on how to use LLDB. Being listed +on this page is not an endorsement. + +## Blog Posts + +### [Dancing in the Debugger — A Waltz with LLDB (2014) ](https://www.objc.io/issues/19-debugging/lldb-debugging/) + +A high level overview of LLDB with a focus on debugging Objective-C code. + +## Videos + +### [LLDB: Beyond "po" (2019)](https://developer.apple.com/videos/play/wwdc2019/429/) + +LLDB is a powerful tool for exploring and debugging your app at runtime. +Discover the various ways to display values in your app, how to format custom +data types, and how to extend LLDB using your own Python 3 scripts. + +### [Advanced Debugging with Xcode and LLDB (2018)](https://developer.apple.com/videos/play/wwdc2018/412/) + +Discover advanced techniques, and tips and tricks for enhancing your Xcode +debugging workflows. Learn how to take advantage of LLDB and custom breakpoints +for more powerful debugging. Get the most out of Xcode's view debugging tools +to solve UI issues in your app more efficiently. + +### [Debugging with LLDB (2012)](https://developer.apple.com/videos/play/wwdc2012/415/) + +LLDB is the next-generation debugger for macOS and iOS. Get an introduction to +using LLDB via the console interface and within Xcode's graphical debugger. The +team that created LLDB will demonstrate the latest features and improvements, +helping you track down bugs more efficiently than ever before. + +### [Migrating from GDB to LLDB (2011)](https://developer.apple.com/videos/play/wwdc2011/321/) + +LLDB is the next-generation debugger for macOS and iOS. Discover why you'll +want to start using LLDB in your own development, get expert tips from the team +that created LLDB, and see how it will help you track down bugs more +efficiently than ever before. + +## Books + +### [Advanced Apple Debugging & Reverse Engineering (2018)](https://www.raywenderlich.com/books/advanced-apple-debugging-reverse-engineering/) + +A book about using LLDB on Apple platforms. + +## Extensions + +### [facebook/chisel](https://github.com/facebook/chisel) + +Chisel is a collection of LLDB commands to assist in the debugging of iOS apps. + +### [DerekSelander/LLDB](https://github.com/DerekSelander/LLDB) + +A collection of LLDB aliases/regexes and Python scripts. diff --git a/gnu/llvm/lldb/docs/use/map.rst b/gnu/llvm/lldb/docs/use/map.rst index 0a785f2c0d9..569649a0b2a 100644 --- a/gnu/llvm/lldb/docs/use/map.rst +++ b/gnu/llvm/lldb/docs/use/map.rst @@ -199,7 +199,7 @@ Execution Commands - (lldb) process launch -v DEBUG=1 + (lldb) process launch -E DEBUG=1
diff --git a/gnu/llvm/lldb/docs/use/python-reference.rst b/gnu/llvm/lldb/docs/use/python-reference.rst index 8c76ef1a083..33e1de11e80 100644 --- a/gnu/llvm/lldb/docs/use/python-reference.rst +++ b/gnu/llvm/lldb/docs/use/python-reference.rst @@ -98,39 +98,38 @@ state. In each case, if there is no currently selected entity of the appropriate type, the variable's IsValid method will return false. These variables are: -+-------------------+---------------------+-------------------------------------------------------------------------------------+ -| Variable | Type | Description | -+-------------------+---------------------+-------------------------------------------------------------------------------------+ -| **lldb.debugger** | **lldb.SBDebugger** | Contains the debugger object whose **script** command was invoked. | -| | | The **lldb.SBDebugger** object owns the command interpreter | -| | | and all the targets in your debug session. There will always be a | -| | | Debugger in the embedded interpreter. | -+-------------------+---------------------+-------------------------------------------------------------------------------------+ -| **lldb.target** | **lldb.SBTarget** | Contains the currently selected target - for instance the one made with the | -| | | **file** or selected by the **target select ** command. | -| | | The **lldb.SBTarget** manages one running process, and all the executable | -| | | and debug files for the process. | -+-------------------+---------------------+-------------------------------------------------------------------------------------+ -| **lldb.process** | **lldb.SBProcess** | Contains the process of the currently selected target. | -| | | The **lldb.SBProcess** object manages the threads and allows access to | -| | | memory for the process. | -+-------------------+---------------------+-------------------------------------------------------------------------------------+ -| **lldb.thread** | **lldb.SBThread** | Contains the currently selected thread. | -| | | The **lldb.SBThread** object manages the stack frames in that thread. | -| | | A thread is always selected in the command interpreter when a target stops. | -| | | The **thread select ** command can be used to change the | -| | | currently selected thread. So as long as you have a stopped process, there will be | -| | | some selected thread. | -+-------------------+---------------------+-------------------------------------------------------------------------------------+ -| **lldb.frame** | **lldb.SBFrame** | Contains the currently selected stack frame. | -| | | The **lldb.SBFrame** object manage the stack locals and the register set for | -| | | that stack. | -| | | A stack frame is always selected in the command interpreter when a target stops. | -| | | The **frame select ** command can be used to change the | -| | | currently selected frame. So as long as you have a stopped process, there will | -| | | be some selected frame. | -+-------------------+---------------------+-------------------------------------------------------------------------------------+ - ++-------------------+---------------------+-------------------------------------+-------------------------------------------------------------------------------------+ +| Variable | Type | Equivalent | Description | ++-------------------+---------------------+-------------------------------------+-------------------------------------------------------------------------------------+ +| ``lldb.debugger`` | `lldb.SBDebugger` | `SBTarget.GetDebugger` | Contains the debugger object whose ``script`` command was invoked. | +| | | | The `lldb.SBDebugger` object owns the command interpreter | +| | | | and all the targets in your debug session. There will always be a | +| | | | Debugger in the embedded interpreter. | ++-------------------+---------------------+-------------------------------------+-------------------------------------------------------------------------------------+ +| ``lldb.target`` | `lldb.SBTarget` | `SBDebugger.GetSelectedTarget` | Contains the currently selected target - for instance the one made with the | +| | | | ``file`` or selected by the ``target select `` command. | +| | | `SBProcess.GetTarget` | The `lldb.SBTarget` manages one running process, and all the executable | +| | | | and debug files for the process. | ++-------------------+---------------------+-------------------------------------+-------------------------------------------------------------------------------------+ +| ``lldb.process`` | `lldb.SBProcess` | `SBTarget.GetProcess` | Contains the process of the currently selected target. | +| | | | The `lldb.SBProcess` object manages the threads and allows access to | +| | | `SBThread.GetProcess` | memory for the process. | ++-------------------+---------------------+-------------------------------------+-------------------------------------------------------------------------------------+ +| ``lldb.thread`` | `lldb.SBThread` | `SBProcess.GetSelectedThread` | Contains the currently selected thread. | +| | | | The `lldb.SBThread` object manages the stack frames in that thread. | +| | | `SBFrame.GetThread` | A thread is always selected in the command interpreter when a target stops. | +| | | | The ``thread select `` command can be used to change the | +| | | | currently selected thread. So as long as you have a stopped process, there will be | +| | | | some selected thread. | ++-------------------+---------------------+-------------------------------------+-------------------------------------------------------------------------------------+ +| ``lldb.frame`` | `lldb.SBFrame` | `SBThread.GetSelectedFrame` | Contains the currently selected stack frame. | +| | | | The `lldb.SBFrame` object manage the stack locals and the register set for | +| | | | that stack. | +| | | | A stack frame is always selected in the command interpreter when a target stops. | +| | | | The ``frame select `` command can be used to change the | +| | | | currently selected frame. So as long as you have a stopped process, there will | +| | | | be some selected frame. | ++-------------------+---------------------+-------------------------------------+-------------------------------------------------------------------------------------+ While extremely convenient, these variables have a couple caveats that you should be aware of. First of all, they hold the values of the selected objects @@ -140,8 +139,12 @@ API's to change, for example, the currently selected stack frame or thread. Moreover, they are only defined and meaningful while in the interactive Python interpreter. There is no guarantee on their value in any other situation, hence you should not use them when defining Python formatters, breakpoint scripts and -commands (or any other Python extension point that LLDB provides). As a -rationale for such behavior, consider that lldb can run in a multithreaded +commands (or any other Python extension point that LLDB provides). For the +latter you'll be passed an `SBDebugger`, `SBTarget`, `SBProcess`, `SBThread` or +`SBFrame` instance and you can use the functions from the "Equivalent" column +to navigate between them. + +As a rationale for such behavior, consider that lldb can run in a multithreaded environment, and another thread might call the "script" command, changing the value out from under you. @@ -179,23 +182,35 @@ arguments: :: - def breakpoint_function_wrapper(frame, bp_loc, dict): + def breakpoint_function_wrapper(frame, bp_loc, internal_dict): + # Your code goes here + +or: + +:: + + def breakpoint_function_wrapper(frame, bp_loc, extra_args, internal_dict): # Your code goes here -+------------+-------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ -| Argument | Type | Description | -+------------+-------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ -| **frame** | **lldb.SBFrame** | The current stack frame where the breakpoint got hit. | -| | | The object will always be valid. | -| | | This **frame** argument might *not* match the currently selected stack frame found in the **lldb** module global variable **lldb.frame**. | -+------------+-------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ -| **bp_loc** | **lldb.SBBreakpointLocation** | The breakpoint location that just got hit. Breakpoints are represented by **lldb.SBBreakpoint** | -| | | objects. These breakpoint objects can have one or more locations. These locations | -| | | are represented by **lldb.SBBreakpointLocation** objects. | -+------------+-------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ -| **dict** | **dict** | The python session dictionary as a standard python dictionary object. | -+------------+-------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ ++-------------------+-------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ +| Argument | Type | Description | ++-------------------+-------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ +| ``frame`` | `lldb.SBFrame` | The current stack frame where the breakpoint got hit. | +| | | The object will always be valid. | +| | | This ``frame`` argument might *not* match the currently selected stack frame found in the `lldb` module global variable ``lldb.frame``. | ++-------------------+-------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ +| ``bp_loc`` | `lldb.SBBreakpointLocation` | The breakpoint location that just got hit. Breakpoints are represented by `lldb.SBBreakpoint` | +| | | objects. These breakpoint objects can have one or more locations. These locations | +| | | are represented by `lldb.SBBreakpointLocation` objects. | ++-------------------+-------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ +| ``extra_args`` | `lldb.SBStructuredData` | ``Optional`` If your breakpoint callback function takes this extra parameter, then when the callback gets added to a breakpoint, its | +| | | contents can parametrize this use of the callback. For instance, instead of writing a callback that stops when the caller is "Foo", | +| | | you could take the function name from a field in the ``extra_args``, making the callback more general. The ``-k`` and ``-v`` options | +| | | to ``breakpoint command add`` will be passed as a Dictionary in the ``extra_args`` parameter, or you can provide it with the SB API's. | ++-------------------+-------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ +| ``internal_dict`` | ``dict`` | The python session dictionary as a standard python dictionary object. | ++-------------------+-------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ Optionally, a Python breakpoint command can return a value. Returning False tells LLDB that you do not want to stop at the breakpoint. Any other return @@ -300,8 +315,8 @@ a stop for the recursion. For instance, if you request a Module depth search, then the callback will be called for each Module as it gets added to the Target, but the searcher will not recurse into the Compile Units in the module. -One other slight sublety is that the depth at which you get called back is not -necessarily the depth at which the the SearchFilter is specified. For instance, +One other slight subtlety is that the depth at which you get called back is not +necessarily the depth at which the SearchFilter is specified. For instance, if you are doing symbol searches, it is convenient to use the Module depth for the search, since symbols are stored in the module. But the SearchFilter might specify some subset of CompileUnits, so not all the symbols you might find in @@ -330,40 +345,40 @@ The custom Resolver is provided as a Python class with the following methods: +--------------------+---------------------------------------+------------------------------------------------------------------------------------------------------------------+ | Name | Arguments | Description | +--------------------+---------------------------------------+------------------------------------------------------------------------------------------------------------------+ -| **__init__** | **bkpt: lldb.SBBreakpoint** | This is the constructor for the new Resolver. | -| | **extra_args: lldb.SBStructuredData** | | +| ``__init__`` | ``bkpt``:`lldb.SBBreakpoint` | This is the constructor for the new Resolver. | +| | ``extra_args``:`lldb.SBStructuredData`| | | | | | -| | | **bkpt** is the breakpoint owning this Resolver. | +| | | ``bkpt`` is the breakpoint owning this Resolver. | | | | | | | | | -| | | **extra_args** is an SBStructuredData object that the user can pass in when creating instances of this | +| | | ``extra_args`` is an `SBStructuredData` object that the user can pass in when creating instances of this | | | | breakpoint. It is not required, but is quite handy. For instance if you were implementing a breakpoint on some | | | | symbol name, you could write a generic symbol name based Resolver, and then allow the user to pass | | | | in the particular symbol in the extra_args | +--------------------+---------------------------------------+------------------------------------------------------------------------------------------------------------------+ -| **__callback__** | **sym_ctx: lldb.SBSymbolContext** | This is the Resolver callback. | -| | | The **sym_ctx** argument will be filled with the current stage | +| ``__callback__`` | ``sym_ctx``:`lldb.SBSymbolContext` | This is the Resolver callback. | +| | | The ``sym_ctx`` argument will be filled with the current stage | | | | of the search. | | | | | | | | | | | | For instance, if you asked for a search depth of lldb.eSearchDepthCompUnit, then the | | | | target, module and compile_unit fields of the sym_ctx will be filled. The callback should look just in the | -| | | context passed in **sym_ctx** for new locations. If the callback finds an address of interest, it | -| | | can add it to the breakpoint with the **SBBreakpoint::AddLocation** method, using the breakpoint passed | -| | | in to the **__init__** method. | +| | | context passed in ``sym_ctx`` for new locations. If the callback finds an address of interest, it | +| | | can add it to the breakpoint with the `SBBreakpoint.AddLocation` method, using the breakpoint passed | +| | | in to the ``__init__`` method. | +--------------------+---------------------------------------+------------------------------------------------------------------------------------------------------------------+ -| **__get_depth__** | **None** | Specify the depth at which you wish your callback to get called. The currently supported options are: | +| ``__get_depth__`` | ``None`` | Specify the depth at which you wish your callback to get called. The currently supported options are: | | | | | -| | | lldb.eSearchDepthModule | -| | | lldb.eSearchDepthCompUnit | -| | | lldb.eSearchDepthFunction | +| | | `lldb.eSearchDepthModule` | +| | | `lldb.eSearchDepthCompUnit` | +| | | `lldb.eSearchDepthFunction` | | | | | | | | For instance, if you are looking | | | | up symbols, which are stored at the Module level, you will want to get called back module by module. | -| | | So you would want to return **lldb.eSearchDepthModule**. This method is optional. If not provided the search | +| | | So you would want to return `lldb.eSearchDepthModule`. This method is optional. If not provided the search | | | | will be done at Module depth. | +--------------------+---------------------------------------+------------------------------------------------------------------------------------------------------------------+ -| **get_short_help** | **None** | This is an optional method. If provided, the returned string will be printed at the beginning of | +| ``get_short_help` | ``None`` | This is an optional method. If provided, the returned string will be printed at the beginning of | | | | the description for this breakpoint. | +--------------------+---------------------------------------+------------------------------------------------------------------------------------------------------------------+ @@ -420,11 +435,11 @@ run its operations. There is a longer discussion of scripted thread plans and the state machine, and several interesting examples of their use in: -https://github.com/llvm/llvm-project/blob/master/lldb/examples/python/scripted_step.py +https://github.com/llvm/llvm-project/blob/main/lldb/examples/python/scripted_step.py And for a MUCH fuller discussion of the whole state machine, see: -https://github.com/llvm/llvm-project/blob/master/lldb/include/lldb/Target/ThreadPlan.h +https://github.com/llvm/llvm-project/blob/main/lldb/include/lldb/Target/ThreadPlan.h If you are reading those comments it is useful to know that scripted thread plans are set to be "MasterPlans", and not "OkayToDiscard". @@ -435,21 +450,21 @@ methods: +-------------------+------------------------------------+---------------------------------------------------------------------------------------+ | Name | Arguments | Description | +-------------------+------------------------------------+---------------------------------------------------------------------------------------+ -| **__init__** | **thread_plan: lldb.SBThreadPlan** | This is the underlying SBThreadPlan that is pushed onto the plan stack. | +| ``__init__`` | ``thread_plan``:`lldb.SBThreadPlan`| This is the underlying `SBThreadPlan` that is pushed onto the plan stack. | | | | You will want to store this away in an ivar. Also, if you are going to | | | | use one of the canned thread plans, you can queue it at this point. | +-------------------+------------------------------------+---------------------------------------------------------------------------------------+ -| **explains_stop** | **event: lldb.SBEvent** | Return True if this stop is part of your thread plans logic, false otherwise. | +| ``explains_stop`` | ``event``: `lldb.SBEvent` | Return True if this stop is part of your thread plans logic, false otherwise. | +-------------------+------------------------------------+---------------------------------------------------------------------------------------+ -| **is_stale** | **None** | If your plan is no longer relevant (for instance, you were | +| ``is_stale`` | ``None`` | If your plan is no longer relevant (for instance, you were | | | | stepping in a particular stack frame, but some other operation | | | | pushed that frame off the stack) return True and your plan will | | | | get popped. | +-------------------+------------------------------------+---------------------------------------------------------------------------------------+ -| **should_step** | **None** | Return True if you want lldb to instruction step one instruction, | +| ``should_step`` | ``None`` | Return ``True`` if you want lldb to instruction step one instruction, | | | | or False to continue till the next breakpoint is hit. | +-------------------+------------------------------------+---------------------------------------------------------------------------------------+ -| **should_stop** | **event: lldb.SBEvent** | If your plan wants to stop and return control to the user at this point, return True. | +| ``should_stop`` | ``event``: `lldb.SBEvent` | If your plan wants to stop and return control to the user at this point, return True. | | | | If your plan is done at this point, call SetPlanComplete on your | | | | thread plan instance. | | | | Also, do any work you need here to set up the next stage of stepping. | @@ -510,21 +525,21 @@ signature as such: +-------------------+--------------------------------+----------------------------------------------------------------------------------------------------------------------------------+ | Argument | Type | Description | +-------------------+--------------------------------+----------------------------------------------------------------------------------------------------------------------------------+ -| **debugger** | **lldb.SBDebugger** | The current debugger object. | +| ``debugger`` | `lldb.SBDebugger` | The current debugger object. | +-------------------+--------------------------------+----------------------------------------------------------------------------------------------------------------------------------+ -| **command** | **python string** | A python string containing all arguments for your command. If you need to chop up the arguments | -| | | try using the **shlex** module's shlex.split(command) to properly extract the | +| ``command`` | ``python string`` | A python string containing all arguments for your command. If you need to chop up the arguments | +| | | try using the ``shlex`` module's ``shlex.split(command)`` to properly extract the | | | | arguments. | +-------------------+--------------------------------+----------------------------------------------------------------------------------------------------------------------------------+ -| **exe_ctx** | **lldb.SBExecutionContext** | An execution context object carrying around information on the inferior process' context in which the command is expected to act | +| ``exe_ctx`` | `lldb.SBExecutionContext` | An execution context object carrying around information on the inferior process' context in which the command is expected to act | | | | | | | | *Optional since lldb 3.5.2, unavailable before* | +-------------------+--------------------------------+----------------------------------------------------------------------------------------------------------------------------------+ -| **result** | **lldb.SBCommandReturnObject** | A return object which encapsulates success/failure information for the command and output text | +| ``result`` | `lldb.SBCommandReturnObject` | A return object which encapsulates success/failure information for the command and output text | | | | that needs to be printed as a result of the command. The plain Python "print" command also works but | | | | text won't go in the result by default (it is useful as a temporary logging facility). | +-------------------+--------------------------------+----------------------------------------------------------------------------------------------------------------------------------+ -| **internal_dict** | **python dict object** | The dictionary for the current embedded script session which contains all variables | +| ``internal_dict`` | ``python dict object`` | The dictionary for the current embedded script session which contains all variables | | | | and functions. | +-------------------+--------------------------------+----------------------------------------------------------------------------------------------------------------------------------+ @@ -534,7 +549,7 @@ which should implement the following interface: :: class CommandObjectType: - def __init__(self, debugger, session_dict): + def __init__(self, debugger, internal_dict): this call should initialize the command with respect to the command interpreter for the passed-in debugger def __call__(self, debugger, command, exe_ctx, result): this is the actual bulk of the command, akin to Python command functions @@ -595,7 +610,7 @@ a function that can be used by LLDB's python command code: :: - #!/usr/bin/python + #!/usr/bin/env python import lldb import commands @@ -625,7 +640,7 @@ Now we can load the module into LLDB and use it A more interesting template has been created in the source repository that can help you to create lldb command quickly: -https://github.com/llvm/llvm-project/blob/master/lldb/examples/python/cmdtemplate.py +https://github.com/llvm/llvm-project/blob/main/lldb/examples/python/cmdtemplate.py A commonly required facility is being able to create a command that does some token substitution, and then runs a different debugger command (usually, it @@ -703,7 +718,7 @@ print the process, thread and frame objects if the process stopped: :: - #!/usr/bin/python + #!/usr/bin/env python import lldb import os @@ -775,7 +790,7 @@ Writing lldb frame recognizers in Python Frame recognizers allow for retrieving information about special frames based on ABI, arguments or other special properties of that frame, even without source code or debug info. Currently, one use case is to extract function -arguments that would otherwise be unaccesible, or augment existing arguments. +arguments that would otherwise be inaccessible, or augment existing arguments. Adding a custom frame recognizer is done by implementing a Python class and using the 'frame recognizer add' command. The Python class should have a @@ -797,8 +812,8 @@ functions 'read', 'write' and 'close' follows: return [value] return [] -The file containing this implementation can be imported via 'command script -import' and then we can register this recognizer with 'frame recognizer add'. +The file containing this implementation can be imported via ``command script import`` +and then we can register this recognizer with ``frame recognizer add``. It's important to restrict the recognizer to the libc library (which is libsystem_kernel.dylib on macOS) to avoid matching functions with the same name in other modules: @@ -819,3 +834,49 @@ When the program is stopped at the beginning of the 'read' function in libc, we frame #0: 0x00007fff06013ca0 libsystem_kernel.dylib`read (lldb) frame variable (int) fd = 3 + +Writing Target Stop-Hooks in Python: +------------------------------------ + +Stop hooks fire whenever the process stops just before control is returned to the +user. Stop hooks can either be a set of lldb command-line commands, or can +be implemented by a suitably defined Python class. The Python based stop-hooks +can also be passed as set of -key -value pairs when they are added, and those +will get packaged up into a SBStructuredData Dictionary and passed to the +constructor of the Python object managing the stop hook. This allows for +parametrization of the stop hooks. + +To add a Python-based stop hook, first define a class with the following methods: + ++--------------------+---------------------------------------+------------------------------------------------------------------------------------------------------------------+ +| Name | Arguments | Description | ++--------------------+---------------------------------------+------------------------------------------------------------------------------------------------------------------+ +| ``__init__`` | ``target: lldb.SBTarget`` | This is the constructor for the new stop-hook. | +| | ``extra_args: lldb.SBStructuredData`` | | +| | | | +| | | ``target`` is the SBTarget to which the stop hook is added. | +| | | | +| | | ``extra_args`` is an SBStructuredData object that the user can pass in when creating instances of this | +| | | breakpoint. It is not required, but allows for reuse of stop-hook classes. | ++--------------------+---------------------------------------+------------------------------------------------------------------------------------------------------------------+ +| ``handle_stop`` | ``exe_ctx: lldb.SBExecutionContext`` | This is the called when the target stops. | +| | ``stream: lldb.SBStream`` | | +| | | ``exe_ctx`` argument will be filled with the current stop point for which the stop hook is | +| | | being evaluated. | +| | | | +| | | ``stream`` an lldb.SBStream, anything written to this stream will be written to the debugger console. | +| | | | +| | | The return value is a "Should Stop" vote from this thread. If the method returns either True or no return | +| | | this thread votes to stop. If it returns False, then the thread votes to continue after all the stop-hooks | +| | | are evaluated. | +| | | Note, the --auto-continue flag to 'target stop-hook add' overrides a True return value from the method. | ++--------------------+---------------------------------------+------------------------------------------------------------------------------------------------------------------+ + +To use this class in lldb, run the command: + +:: + + (lldb) command script import MyModule.py + (lldb) target stop-hook add -P MyModule.MyStopHook -k first -v 1 -k second -v 2 + +where MyModule.py is the file containing the class definition MyStopHook. diff --git a/gnu/llvm/lldb/docs/use/python.rst b/gnu/llvm/lldb/docs/use/python.rst index 6b212570508..efbe0d732c1 100644 --- a/gnu/llvm/lldb/docs/use/python.rst +++ b/gnu/llvm/lldb/docs/use/python.rst @@ -110,10 +110,10 @@ kind of Python variable will it be? The answers are to use the LLDB API functions, provided as part of the LLDB Python module. Running Python from inside LLDB, LLDB will automatically give us our current frame object as a Python variable, "lldb.frame". This variable has the type -"SBFrame" (see the LLDB API for more information about SBFrame +`SBFrame` (see the LLDB API for more information about `SBFrame` objects). One of the things we can do with a frame object, is to ask it to find and return its local variable. We will call the API function -"FindVariable" on the lldb.frame object to give us our dictionary +`SBFrame.FindVariable` on the lldb.frame object to give us our dictionary variable as a Python variable: :: @@ -125,11 +125,11 @@ current frame to find the variable named "dictionary" and return it. We then store the returned value in the Python variable named "root". This answers the question of HOW to get the variable, but it still doesn't explain WHAT actually gets put into "root". If you examine the LLDB API, you will find that the -SBFrame method "FindVariable" returns an object of type SBValue. SBValue +`SBFrame` method "FindVariable" returns an object of type `SBValue`. `SBValue` objects are used, among other things, to wrap up program variables and values. -There are many useful methods defined in the SBValue class to allow you to get +There are many useful methods defined in the `SBValue` class to allow you to get information or children values out of SBValues. For complete information, see -the header file SBValue.h. The SBValue methods that we use in our DFS function +the header file SBValue.h. The `SBValue` methods that we use in our DFS function are ``GetChildMemberWithName()``, ``GetSummary()``, and ``GetValue()``. diff --git a/gnu/llvm/lldb/docs/use/qemu-testing.rst b/gnu/llvm/lldb/docs/use/qemu-testing.rst new file mode 100644 index 00000000000..a523137c871 --- /dev/null +++ b/gnu/llvm/lldb/docs/use/qemu-testing.rst @@ -0,0 +1,138 @@ +Testing LLDB using QEMU +======================= + +.. contents:: + :local: + +QEMU system mode emulation +-------------------------- + +QEMU can be used to test LLDB in an emulation environment in the absence of +actual hardware. This page describes instructions to help setup a QEMU emulation +environment for testing LLDB. + +The scripts under llvm-project/lldb/scripts/lldb-test-qemu can quickly help +setup a virtual LLDB testing environment using QEMU. The scripts currently work +with Arm or AArch64, but support for other architectures can be added easily. + +* **setup.sh** is used to build the Linux kernel image and QEMU system emulation executable(s) from source. +* **rootfs.sh** is used to generate Ubuntu root file system images to be used for QEMU system mode emulation. +* **run-qemu.sh** utilizes QEMU to boot a Linux kernel image with a root file system image. + +Once we have booted our kernel we can run lldb-server in emulation environment. +Ubuntu Bionic/Focal x86_64 host was used to test these scripts instructions in this +document. Please update it according to your host distribution/architecture. + +.. note:: + Instructions on this page and QEMU helper scripts are verified on a Ubuntu Bionic/Focal (x86_64) host. Moreover, scripts require sudo/root permissions for installing dependencies and setting up QEMU host/guest network. + +Given below are some examples of common use-cases of LLDB QEMU testing +helper scripts: + +Create Ubuntu root file system image for QEMU system emulation with rootfs.sh +-------------------------------------------------------------------------------- + +**Example:** generate Ubuntu Bionic (armhf) rootfs image of size 1 GB +:: + + $ bash rootfs.sh --arch armhf --distro bionic --size 1G + +**Example:** generate Ubuntu Focal (arm64) rootfs image of size 2 GB +:: + + $ bash rootfs.sh --arch arm64 --distro focal --size 2G + +rootfs.sh has been tested for generating Ubuntu Bionic and Focal images but they can be used to generate rootfs images of other Debian Linux distribution. + +rootfs.sh defaults username of generated image to your current username on host computer. + + +Build QEMU or cross compile Linux kernel from source using setup.sh +----------------------------------------------------------------------- + +**Example:** Build QEMU binaries and Arm/AArch64 Linux kernel image +:: + +$ bash setup.sh --qemu --kernel arm +$ bash setup.sh --qemu --kernel arm64 + +**Example:** Build Linux kernel image only +:: + +$ bash setup.sh --kernel arm +$ bash setup.sh --kernel arm64 + +**Example:** Build qemu-system-arm and qemu-system-aarch64 binaries. +:: + +$ bash setup.sh --qemu + +**Example:** Remove qemu.git, linux.git and linux.build from working directory +:: + +$ bash setup.sh --clean + + +Run QEMU Arm or AArch64 system emulation using run-qemu.sh +---------------------------------------------------------- +run-qemu.sh has following dependencies: + +* Follow https://wiki.qemu.org/Documentation/Networking/NAT and set up bridge + networking for QEMU. + +* Make sure /etc/qemu-ifup script is available with executable permissions. + +* QEMU binaries must be built from source using setup.sh or provided via --qemu + commandline argument. + +* Linux kernel image must be built from source using setup.sh or provided via + --kernel commandline argument. + +* linux.build and qemu.git folder must be present in current directory if + setup.sh was used to build Linux kernel and QEMU binaries. + +* --sve option will enable AArch64 SVE mode. + +* --mte option will enable AArch64 MTE (memory tagging) mode. + (can be used on its own or in addition to --sve) + + +**Example:** Run QEMU Arm or AArch64 system emulation using run-qemu.sh +:: + + $ sudo bash run-qemu.sh --arch arm --rootfs + $ sudo bash run-qemu.sh --arch arm64 --rootfs + +**Example:** Run QEMU with kernel image and qemu binary provided using commandline +:: + + $ sudo bash run-qemu.sh --arch arm64 --rootfs \ + --kernel --qemu + + +Steps for running lldb-server in QEMU system emulation environment +------------------------------------------------------------------ + +* Make sure bridge networking is enabled between host machine and QEMU VM + +* Find out ip address assigned to eth0 in emulation environment + +* Setup ssh access between host machine and emulation environment + +* Login emulation environment and install dependencies + +:: + + $ sudo apt install python-dev libedit-dev libncurses5-dev libexpat1-dev + +* Cross compile LLDB server for AArch64 Linux: Please visit https://lldb.llvm.org/resources/build.html for instructions on how to cross compile LLDB server. + +* Transfer LLDB server executable to emulation environment + +:: + + $ scp lldb-server username@ip-address-of-emulation-environment:/home/username + +* Run lldb-server inside QEMU VM + +* Try connecting to lldb-server running inside QEMU VM with selected ip:port diff --git a/gnu/llvm/lldb/docs/use/tutorial.rst b/gnu/llvm/lldb/docs/use/tutorial.rst index fc41a7ab6a7..3c552a341e0 100644 --- a/gnu/llvm/lldb/docs/use/tutorial.rst +++ b/gnu/llvm/lldb/docs/use/tutorial.rst @@ -28,7 +28,7 @@ may have to quote some arguments in lldb that you wouldn't in gdb. Options can be placed anywhere on the command line, but if the arguments begin with a "-" then you have to tell lldb that you're done with options for the -current command by adding an option termination: "--" So for instance if you +current command by adding an option termination: "--". So for instance, if you want to launch a process and give the "process launch" command the "--stop-at-entry" option, yet you want the process you are about to launch to be launched with the arguments "-program_arg value", you would type: @@ -121,7 +121,7 @@ command: lldb also supports command completion for source file names, symbol names, file names, etc. Completion is initiated by a hitting a TAB. Individual options in a -command can have different completers, so for instance the "--file " +command can have different completers, so for instance, the "--file " option in "breakpoint" completes to source files, the "--shlib " option to currently loaded shared libraries, etc. We can even do things like if you specify "--shlib ", and are completing on "--file ", we will only @@ -134,7 +134,7 @@ help text for all commands for a particular word and dump a summary help string for each matching command. Finally, there is a mechanism to construct aliases for commonly used commands. -So for instance if you get annoyed typing: +For instance, if you get annoyed typing: :: @@ -162,10 +162,10 @@ set up. One alias of note that we do include by popular demand is a weak emulator of gdb's "break" command. It doesn't try to do everything that gdb's break command does (for instance, it doesn't handle foo.c::bar. But it mostly works, and -makes the transition easier. Also by popular demand, it is aliased to b. If you +makes the transition easier. Also, by popular demand, it is aliased to b. If you actually want to learn the lldb command set natively, that means it will get in the way of the rest of the breakpoint commands. Fortunately, if you don't like -one of our aliases, you an easily get rid of it by running (for example): +one of our aliases, you can easily get rid of it by running (for example): :: @@ -183,7 +183,7 @@ The lldb command parser also supports "raw" commands, where, after command options are stripped off, the rest of the command string is passed uninterpreted to the command. This is convenient for commands whose arguments might be some complex expression that would be painful to backslash protect. -For instance the "expression" command is a "raw" command for obvious reasons. +For instance, the "expression" command is a "raw" command for obvious reasons. The "help" output for a command will tell you if it is "raw" or not, so you know what to expect. The one thing you have to watch out for is that since raw commands still can have options, if your command string has dashes in it, @@ -246,11 +246,11 @@ breakpoint on all the methods that implement that selector in the classes in your program. Similarly, a file and line breakpoint might result in multiple locations if that file and line were inlined in different places in your code. -The logical breakpoint has an integer id, and it's locations have an id within +The logical breakpoint has an integer id, and its locations have an id within their parent breakpoint (the two are joined by a ".", e.g. 1.1 in the example -above.) +above). -Also the logical breakpoints remain live so that if another shared library were +Also, the logical breakpoints remain live so that if another shared library were to be loaded that had another implementation of the "alignLeftEdges:" selector, the new location would be added to breakpoint 1 (e.g. a "1.2" breakpoint would be set on the newly loaded selector). @@ -284,7 +284,7 @@ locations were found: You can delete, disable, set conditions and ignore counts either on all the locations generated by your logical breakpoint, or on any one of the particular -locations your specification resolved to. For instance if we wanted to add a +locations your specification resolved to. For instance, if we wanted to add a command to print a backtrace when we hit this breakpoint we could do: :: @@ -299,7 +299,7 @@ commands. You can also specify this explicitly by passing the "--command" option. Use "--script" if you want to implement your breakpoint command using the Python script instead. -This is an convenient point to bring up another feature of the lldb command +This is a convenient point to bring up another feature of the lldb command help. Do: :: @@ -324,7 +324,7 @@ do: Breakpoint Names ---------------- -Breakpoints carry two orthognal sets of information: one specifies where to set the breakpoint, and the other how to react when the breakpoint is hit. The latter set of information (e.g. commands, conditions, hit-count, auto-continue...) we call breakpoint options. +Breakpoints carry two orthogonal sets of information: one specifies where to set the breakpoint, and the other how to react when the breakpoint is hit. The latter set of information (e.g. commands, conditions, hit-count, auto-continue...) we call breakpoint options. It is fairly common to want to apply one set of options to a number of breakpoints. For instance, you might want to check that self == nil and if it is, print a backtrace and continue, on a number of methods. One convenient way to do that would be to make all the breakpoints, then configure the options with: diff --git a/gnu/llvm/lldb/docs/use/variable.rst b/gnu/llvm/lldb/docs/use/variable.rst index 5b1fef7b06c..b3e4de588d5 100644 --- a/gnu/llvm/lldb/docs/use/variable.rst +++ b/gnu/llvm/lldb/docs/use/variable.rst @@ -131,6 +131,20 @@ which provides the desired output: (C) c = {0x03 0x00 0x00 0x00} (D) d = 4 +Note, that qualifiers such as const and volatile will be stripped when matching types for example: + +:: + + (lldb) frame var x y z + (int) x = 1 + (const int) y = 2 + (volatile int) z = 4 + (lldb) type format add -f hex int + (lldb) frame var x y z + (int) x = 0x00000001 + (const int) y = 0x00000002 + (volatile int) z = 0x00000004 + Two additional options that you will want to look at are --skip-pointers (-p) and --skip-references (-r). These two options prevent LLDB from applying a format for type T to values of type T* and T& respectively. @@ -677,7 +691,7 @@ passed two parameters: ``valobj`` and ``internal_dict``. not touch it. ``valobj`` is the object encapsulating the actual variable being displayed, and -its type is SBValue. Out of the many possible operations on an SBValue, the +its type is `SBValue`. Out of the many possible operations on an `SBValue`, the basic one is retrieve the children objects it contains (essentially, the fields of the object wrapped by it), by calling ``GetChildMemberWithName()``, passing it the child's name as a string. @@ -685,15 +699,15 @@ it the child's name as a string. If the variable has a value, you can ask for it, and return it as a string using ``GetValue()``, or as a signed/unsigned number using ``GetValueAsSigned()``, ``GetValueAsUnsigned()``. It is also possible to -retrieve an SBData object by calling ``GetData()`` and then read the object's -contents out of the SBData. +retrieve an `SBData` object by calling ``GetData()`` and then read the object's +contents out of the `SBData`. If you need to delve into several levels of hierarchy, as you can do with summary strings, you can use the method ``GetValueForExpressionPath()``, passing it an expression path just like those you could use for summary strings (one of the differences is that dereferencing a pointer does not occur by prefixing the path with a ``*```, but by calling the ``Dereference()`` method -on the returned SBValue). If you need to access array slices, you cannot do +on the returned `SBValue`). If you need to access array slices, you cannot do that (yet) via this method call, and you must use ``GetChildAtIndex()`` querying it for the array items one by one. Also, handling custom formats is something you have to deal with on your own. @@ -874,9 +888,9 @@ update. implementing it in terms of num_children is acceptable, implementors are encouraged to look for optimized coding alternatives whenever reasonable. -[3] This method is optional (starting with SVN revision 219330). The SBValue +[3] This method is optional (starting with SVN revision 219330). The `SBValue` you return here will most likely be a numeric type (int, float, ...) as its -value bytes will be used as-if they were the value of the root SBValue proper. +value bytes will be used as-if they were the value of the root `SBValue` proper. As a shortcut for this, you can inherit from lldb.SBSyntheticValueProvider, and just define get_value as other methods are defaulted in the superclass as returning default no-children responses. @@ -913,7 +927,7 @@ especially want to begin looking at this example to get a feel for this feature, as it is a very easy and well commented example. The design pattern consistently used in synthetic providers shipping with LLDB -is to use the __init__ to store the SBValue instance as a part of self. The +is to use the __init__ to store the `SBValue` instance as a part of self. The update function is then used to perform the actual initialization. Once a synthetic children provider is written, one must load it into LLDB before it can be used. Currently, one can use the LLDB script command to type Python code @@ -993,7 +1007,7 @@ have many member variables but not all of these are actually necessary for the user to see. A filter will solve this issue by only letting the user see those member -variables he cares about. Of course, the equivalent of a filter can be +variables they care about. Of course, the equivalent of a filter can be implemented easily using synthetic children, but a filter lets you get the job done without having to write Python code. diff --git a/gnu/llvm/lldb/examples/darwin/heap_find/heap.py b/gnu/llvm/lldb/examples/darwin/heap_find/heap.py index a8bc377ffe4..8ee44ae25e4 100644 --- a/gnu/llvm/lldb/examples/darwin/heap_find/heap.py +++ b/gnu/llvm/lldb/examples/darwin/heap_find/heap.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python3 #---------------------------------------------------------------------- # This module is designed to live inside the "lldb" python package @@ -36,7 +36,7 @@ typedef uintptr_t vm_address_t; typedef natural_t task_t; typedef int kern_return_t; #define KERN_SUCCESS 0 -typedef void (*range_callback_t)(task_t task, void *baton, unsigned type, uintptr_t ptr_addr, uintptr_t ptr_size); +typedef void (*range_callback_t)(task_t, void *, unsigned, uintptr_t, uintptr_t); ''' if options.search_vm_regions: expr += ''' @@ -120,8 +120,8 @@ typedef struct vm_range_t { vm_address_t address; vm_size_t size; } vm_range_t; -typedef kern_return_t (*memory_reader_t)(task_t task, vm_address_t remote_address, vm_size_t size, void **local_memory); -typedef void (*vm_range_recorder_t)(task_t task, void *baton, unsigned type, vm_range_t *range, unsigned size); +typedef kern_return_t (*memory_reader_t)(task_t, vm_address_t, vm_size_t, void **); +typedef void (*vm_range_recorder_t)(task_t, void *, unsigned, vm_range_t *, unsigned); typedef struct malloc_introspection_t { kern_return_t (*enumerator)(task_t task, void *, unsigned type_mask, vm_address_t zone_address, memory_reader_t reader, vm_range_recorder_t recorder); /* enumerates all the malloc pointers in use */ } malloc_introspection_t; @@ -129,7 +129,8 @@ typedef struct malloc_zone_t { void *reserved1[12]; struct malloc_introspection_t *introspect; } malloc_zone_t; -memory_reader_t task_peek = [](task_t task, vm_address_t remote_address, vm_size_t size, void **local_memory) -> kern_return_t { +kern_return_t malloc_get_all_zones(task_t task, memory_reader_t reader, vm_address_t **addresses, unsigned *count); +memory_reader_t task_peek = [](task_t, vm_address_t remote_address, vm_size_t, void **local_memory) -> kern_return_t { *local_memory = (void*) remote_address; return KERN_SUCCESS; }; diff --git a/gnu/llvm/lldb/examples/python/armv7_cortex_m_target_defintion.py b/gnu/llvm/lldb/examples/python/armv7_cortex_m_target_defintion.py index 342de89c462..e8f39ccb09e 100755 --- a/gnu/llvm/lldb/examples/python/armv7_cortex_m_target_defintion.py +++ b/gnu/llvm/lldb/examples/python/armv7_cortex_m_target_defintion.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python #===-- armv7_cortex_m_target_definition.py.py ------------------*- C++ -*-===// # # The LLVM Compiler Infrastructure diff --git a/gnu/llvm/lldb/examples/python/bsd.py b/gnu/llvm/lldb/examples/python/bsd.py index c66226e3710..fdf5455fe69 100755 --- a/gnu/llvm/lldb/examples/python/bsd.py +++ b/gnu/llvm/lldb/examples/python/bsd.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python from __future__ import print_function import cmd diff --git a/gnu/llvm/lldb/examples/python/cmdtemplate.py b/gnu/llvm/lldb/examples/python/cmdtemplate.py index 97af943e6de..aa99e4c03be 100644 --- a/gnu/llvm/lldb/examples/python/cmdtemplate.py +++ b/gnu/llvm/lldb/examples/python/cmdtemplate.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python # --------------------------------------------------------------------- # Be sure to add the python path that points to the LLDB shared library. diff --git a/gnu/llvm/lldb/examples/python/crashlog.py b/gnu/llvm/lldb/examples/python/crashlog.py index 1c1602b0131..a7b2d3b52b5 100755 --- a/gnu/llvm/lldb/examples/python/crashlog.py +++ b/gnu/llvm/lldb/examples/python/crashlog.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python3 #---------------------------------------------------------------------- # Be sure to add the python path that points to the LLDB shared library. @@ -34,7 +34,6 @@ import optparse import os import platform import plistlib -import pprint # pp = pprint.PrettyPrinter(indent=4); pp.pprint(command_args) import re import shlex import string @@ -42,83 +41,38 @@ import subprocess import sys import time import uuid - -def read_plist(s): - if sys.version_info.major == 3: - return plistlib.loads(s) - else: - return plistlib.readPlistFromString(s) +import json try: - # Just try for LLDB in case PYTHONPATH is already correctly setup + # First try for LLDB in case PYTHONPATH is already correctly setup. import lldb except ImportError: - lldb_python_dirs = list() - # lldb is not in the PYTHONPATH, try some defaults for the current platform - platform_system = platform.system() - if platform_system == 'Darwin': - # On Darwin, try the currently selected Xcode directory - xcode_dir = subprocess.check_output("xcode-select --print-path", shell=True).decode("utf-8") - if xcode_dir: - lldb_python_dirs.append( - os.path.realpath( - xcode_dir + - '/../SharedFrameworks/LLDB.framework/Resources/Python')) - lldb_python_dirs.append( - xcode_dir + '/Library/PrivateFrameworks/LLDB.framework/Resources/Python') - lldb_python_dirs.append( - '/System/Library/PrivateFrameworks/LLDB.framework/Resources/Python') - success = False - for lldb_python_dir in lldb_python_dirs: - if os.path.exists(lldb_python_dir): - if not (sys.path.__contains__(lldb_python_dir)): - sys.path.append(lldb_python_dir) - try: - import lldb - except ImportError: - pass - else: - print('imported lldb from: "%s"' % (lldb_python_dir)) - success = True - break - if not success: + # Ask the command line driver for the path to the lldb module. Copy over + # the environment so that SDKROOT is propagated to xcrun. + env = os.environ.copy() + env['LLDB_DEFAULT_PYTHON_VERSION'] = str(sys.version_info.major) + command = ['xcrun', 'lldb', '-P'] if platform.system() == 'Darwin' else ['lldb', '-P'] + # Extend the PYTHONPATH if the path exists and isn't already there. + lldb_python_path = subprocess.check_output(command, env=env).decode("utf-8").strip() + if os.path.exists(lldb_python_path) and not sys.path.__contains__(lldb_python_path): + sys.path.append(lldb_python_path) + # Try importing LLDB again. + try: + import lldb + except ImportError: print("error: couldn't locate the 'lldb' module, please set PYTHONPATH correctly") sys.exit(1) from lldb.utils import symbolication -PARSE_MODE_NORMAL = 0 -PARSE_MODE_THREAD = 1 -PARSE_MODE_IMAGES = 2 -PARSE_MODE_THREGS = 3 -PARSE_MODE_SYSTEM = 4 +def read_plist(s): + if sys.version_info.major == 3: + return plistlib.loads(s) + else: + return plistlib.readPlistFromString(s) class CrashLog(symbolication.Symbolicator): - """Class that does parses darwin crash logs""" - parent_process_regex = re.compile('^Parent Process:\s*(.*)\[(\d+)\]') - thread_state_regex = re.compile('^Thread ([0-9]+) crashed with') - thread_regex = re.compile('^Thread ([0-9]+)([^:]*):(.*)') - app_backtrace_regex = re.compile( - '^Application Specific Backtrace ([0-9]+)([^:]*):(.*)') - version = r'(\(.+\)|(arm|x86_)[0-9a-z]+)\s+' - frame_regex = re.compile(r'^([0-9]+)' r'\s' # id - r'+(.+?)' r'\s+' # img_name - r'(' +version+ r')?' # img_version - r'(0x[0-9a-fA-F]{7}[0-9a-fA-F]+)' # addr - r' +(.*)' # offs - ) - null_frame_regex = re.compile(r'^([0-9]+)\s+\?\?\?\s+(0{7}0+) +(.*)') - image_regex_uuid = re.compile(r'(0x[0-9a-fA-F]+)' # img_lo - r'\s+' '-' r'\s+' # - - r'(0x[0-9a-fA-F]+)' r'\s+' # img_hi - r'[+]?(.+?)' r'\s+' # img_name - r'(' +version+ ')?' # img_version - r'(<([-0-9a-fA-F]+)>\s+)?' # img_uuid - r'(/.*)' # img_path - ) - empty_line_regex = re.compile('^$') - class Thread: """Class that represents a thread in a darwin crash log""" @@ -143,7 +97,7 @@ class CrashLog(symbolication.Symbolicator): if self.registers: print("%s Registers:" % (prefix)) for reg in self.registers.keys(): - print("%s %-5s = %#16.16x" % (prefix, reg, self.registers[reg])) + print("%s %-8s = %#16.16x" % (prefix, reg, self.registers[reg])) def dump_symbolicated(self, crash_log, options): this_thread_crashed = self.app_specific_backtrace @@ -153,7 +107,6 @@ class CrashLog(symbolication.Symbolicator): return print("%s" % self) - #prev_frame_index = -1 display_frame_idx = -1 for frame_idx, frame in enumerate(self.frames): disassemble = ( @@ -179,7 +132,7 @@ class CrashLog(symbolication.Symbolicator): if line_entry.IsValid(): strm = lldb.SBStream() if line_entry: - lldb.debugger.GetSourceManager().DisplaySourceLinesWithLineNumbers( + crash_log.debugger.GetSourceManager().DisplaySourceLinesWithLineNumbers( line_entry.file, line_entry.line, source_context, source_context, "->", strm) source_text = strm.GetData() if source_text: @@ -203,6 +156,10 @@ class CrashLog(symbolication.Symbolicator): symbolicated_frame_address_idx += 1 else: print(frame) + if self.registers: + print() + for reg in self.registers.keys(): + print(" %-8s = %#16.16x" % (reg, self.registers[reg])) def add_ident(self, ident): if ident not in self.idents: @@ -358,9 +315,9 @@ class CrashLog(symbolication.Symbolicator): self.unavailable = True return False - def __init__(self, path, verbose): + def __init__(self, debugger, path, verbose): """CrashLog constructor that take a path to a darwin crash log file""" - symbolication.Symbolicator.__init__(self) + symbolication.Symbolicator.__init__(self, debugger) self.path = os.path.expanduser(path) self.info_lines = list() self.system_profile = list() @@ -369,177 +326,8 @@ class CrashLog(symbolication.Symbolicator): self.idents = list() # A list of the required identifiers for doing all stack backtraces self.crashed_thread_idx = -1 self.version = -1 - self.error = None self.target = None self.verbose = verbose - # With possible initial component of ~ or ~user replaced by that user's - # home directory. - try: - f = open(self.path) - except IOError: - self.error = 'error: cannot open "%s"' % self.path - return - - self.file_lines = f.read().splitlines() - parse_mode = PARSE_MODE_NORMAL - thread = None - app_specific_backtrace = False - for line in self.file_lines: - # print line - line_len = len(line) - if line_len == 0: - if thread: - if parse_mode == PARSE_MODE_THREAD: - if thread.index == self.crashed_thread_idx: - thread.reason = '' - if self.thread_exception: - thread.reason += self.thread_exception - if self.thread_exception_data: - thread.reason += " (%s)" % self.thread_exception_data - if app_specific_backtrace: - self.backtraces.append(thread) - else: - self.threads.append(thread) - thread = None - else: - # only append an extra empty line if the previous line - # in the info_lines wasn't empty - if len(self.info_lines) > 0 and len(self.info_lines[-1]): - self.info_lines.append(line) - parse_mode = PARSE_MODE_NORMAL - # print 'PARSE_MODE_NORMAL' - elif parse_mode == PARSE_MODE_NORMAL: - if line.startswith('Process:'): - (self.process_name, pid_with_brackets) = line[ - 8:].strip().split(' [') - self.process_id = pid_with_brackets.strip('[]') - elif line.startswith('Path:'): - self.process_path = line[5:].strip() - elif line.startswith('Identifier:'): - self.process_identifier = line[11:].strip() - elif line.startswith('Version:'): - version_string = line[8:].strip() - matched_pair = re.search("(.+)\((.+)\)", version_string) - if matched_pair: - self.process_version = matched_pair.group(1) - self.process_compatability_version = matched_pair.group( - 2) - else: - self.process = version_string - self.process_compatability_version = version_string - elif self.parent_process_regex.search(line): - parent_process_match = self.parent_process_regex.search( - line) - self.parent_process_name = parent_process_match.group(1) - self.parent_process_id = parent_process_match.group(2) - elif line.startswith('Exception Type:'): - self.thread_exception = line[15:].strip() - continue - elif line.startswith('Exception Codes:'): - self.thread_exception_data = line[16:].strip() - continue - elif line.startswith('Exception Subtype:'): # iOS - self.thread_exception_data = line[18:].strip() - continue - elif line.startswith('Crashed Thread:'): - self.crashed_thread_idx = int(line[15:].strip().split()[0]) - continue - elif line.startswith('Triggered by Thread:'): # iOS - self.crashed_thread_idx = int(line[20:].strip().split()[0]) - continue - elif line.startswith('Report Version:'): - self.version = int(line[15:].strip()) - continue - elif line.startswith('System Profile:'): - parse_mode = PARSE_MODE_SYSTEM - continue - elif (line.startswith('Interval Since Last Report:') or - line.startswith('Crashes Since Last Report:') or - line.startswith('Per-App Interval Since Last Report:') or - line.startswith('Per-App Crashes Since Last Report:') or - line.startswith('Sleep/Wake UUID:') or - line.startswith('Anonymous UUID:')): - # ignore these - continue - elif line.startswith('Thread'): - thread_state_match = self.thread_state_regex.search(line) - if thread_state_match: - app_specific_backtrace = False - thread_state_match = self.thread_regex.search(line) - thread_idx = int(thread_state_match.group(1)) - parse_mode = PARSE_MODE_THREGS - thread = self.threads[thread_idx] - else: - thread_match = self.thread_regex.search(line) - if thread_match: - app_specific_backtrace = False - parse_mode = PARSE_MODE_THREAD - thread_idx = int(thread_match.group(1)) - thread = CrashLog.Thread(thread_idx, False) - continue - elif line.startswith('Binary Images:'): - parse_mode = PARSE_MODE_IMAGES - continue - elif line.startswith('Application Specific Backtrace'): - app_backtrace_match = self.app_backtrace_regex.search(line) - if app_backtrace_match: - parse_mode = PARSE_MODE_THREAD - app_specific_backtrace = True - idx = int(app_backtrace_match.group(1)) - thread = CrashLog.Thread(idx, True) - elif line.startswith('Last Exception Backtrace:'): # iOS - parse_mode = PARSE_MODE_THREAD - app_specific_backtrace = True - idx = 1 - thread = CrashLog.Thread(idx, True) - self.info_lines.append(line.strip()) - elif parse_mode == PARSE_MODE_THREAD: - if line.startswith('Thread'): - continue - if self.null_frame_regex.search(line): - print('warning: thread parser ignored null-frame: "%s"' % line) - continue - frame_match = self.frame_regex.search(line) - if frame_match: - (frame_id, frame_img_name, _, frame_img_version, _, - frame_addr, frame_ofs) = frame_match.groups() - ident = frame_img_name - thread.add_ident(ident) - if ident not in self.idents: - self.idents.append(ident) - thread.frames.append(CrashLog.Frame(int(frame_id), int( - frame_addr, 0), frame_ofs)) - else: - print('error: frame regex failed for line: "%s"' % line) - elif parse_mode == PARSE_MODE_IMAGES: - image_match = self.image_regex_uuid.search(line) - if image_match: - (img_lo, img_hi, img_name, _, img_version, _, - _, img_uuid, img_path) = image_match.groups() - image = CrashLog.DarwinImage(int(img_lo, 0), int(img_hi, 0), - img_name.strip(), - img_version.strip() - if img_version else "", - uuid.UUID(img_uuid), img_path, - self.verbose) - self.images.append(image) - else: - print("error: image regex failed for: %s" % line) - - elif parse_mode == PARSE_MODE_THREGS: - stripped_line = line.strip() - # "r12: 0x00007fff6b5939c8 r13: 0x0000000007000006 r14: 0x0000000000002a03 r15: 0x0000000000000c00" - reg_values = re.findall( - '([a-zA-Z0-9]+: 0[Xx][0-9a-fA-F]+) *', stripped_line) - for reg_value in reg_values: - # print 'reg_value = "%s"' % reg_value - (reg, value) = reg_value.split(': ') - # print 'reg = "%s"' % reg - # print 'value = "%s"' % value - thread.registers[reg.strip()] = int(value, 0) - elif parse_mode == PARSE_MODE_SYSTEM: - self.system_profile.append(line) - f.close() def dump(self): print("Crash Log File: %s" % (self.path)) @@ -566,7 +354,6 @@ class CrashLog(symbolication.Symbolicator): return None def create_target(self): - # print 'crashlog.create_target()...' if self.target is None: self.target = symbolication.Symbolicator.create_target(self) if self.target: @@ -578,12 +365,12 @@ class CrashLog(symbolication.Symbolicator): for ident in self.idents: image = self.find_image_with_identifier(ident) if image: - self.target = image.create_target() + self.target = image.create_target(self.debugger) if self.target: return self.target # success print('crashlog.create_target()...3') for image in self.images: - self.target = image.create_target() + self.target = image.create_target(self.debugger) if self.target: return self.target # success print('crashlog.create_target()...4') @@ -596,6 +383,356 @@ class CrashLog(symbolication.Symbolicator): return self.target +class CrashLogFormatException(Exception): + pass + + +class CrashLogParseException(Exception): + pass + + +class CrashLogParser: + def parse(self, debugger, path, verbose): + try: + return JSONCrashLogParser(debugger, path, verbose).parse() + except CrashLogFormatException: + return TextCrashLogParser(debugger, path, verbose).parse() + + +class JSONCrashLogParser: + def __init__(self, debugger, path, verbose): + self.path = os.path.expanduser(path) + self.verbose = verbose + self.crashlog = CrashLog(debugger, self.path, self.verbose) + + def parse(self): + with open(self.path, 'r') as f: + buffer = f.read() + + # First line is meta-data. + buffer = buffer[buffer.index('\n') + 1:] + + try: + self.data = json.loads(buffer) + except ValueError: + raise CrashLogFormatException() + + try: + self.parse_process_info(self.data) + self.parse_images(self.data['usedImages']) + self.parse_threads(self.data['threads']) + thread = self.crashlog.threads[self.crashlog.crashed_thread_idx] + reason = self.parse_crash_reason(self.data['exception']) + if thread.reason: + thread.reason = '{} {}'.format(thread.reason, reason) + else: + thread.reason = reason + except (KeyError, ValueError, TypeError) as e: + raise CrashLogParseException( + 'Failed to parse JSON crashlog: {}: {}'.format( + type(e).__name__, e)) + + return self.crashlog + + def get_used_image(self, idx): + return self.data['usedImages'][idx] + + def parse_process_info(self, json_data): + self.crashlog.process_id = json_data['pid'] + self.crashlog.process_identifier = json_data['procName'] + self.crashlog.process_path = json_data['procPath'] + + def parse_crash_reason(self, json_exception): + exception_type = json_exception['type'] + exception_signal = json_exception['signal'] + if 'codes' in json_exception: + exception_extra = " ({})".format(json_exception['codes']) + elif 'subtype' in json_exception: + exception_extra = " ({})".format(json_exception['subtype']) + else: + exception_extra = "" + return "{} ({}){}".format(exception_type, exception_signal, + exception_extra) + + def parse_images(self, json_images): + idx = 0 + for json_image in json_images: + img_uuid = uuid.UUID(json_image['uuid']) + low = int(json_image['base']) + high = int(0) + name = json_image['name'] if 'name' in json_image else '' + path = json_image['path'] if 'path' in json_image else '' + version = '' + darwin_image = self.crashlog.DarwinImage(low, high, name, version, + img_uuid, path, + self.verbose) + self.crashlog.images.append(darwin_image) + idx += 1 + + def parse_frames(self, thread, json_frames): + idx = 0 + for json_frame in json_frames: + image_id = int(json_frame['imageIndex']) + ident = self.get_used_image(image_id)['name'] + thread.add_ident(ident) + if ident not in self.crashlog.idents: + self.crashlog.idents.append(ident) + + frame_offset = int(json_frame['imageOffset']) + image_addr = self.get_used_image(image_id)['base'] + pc = image_addr + frame_offset + thread.frames.append(self.crashlog.Frame(idx, pc, frame_offset)) + idx += 1 + + def parse_threads(self, json_threads): + idx = 0 + for json_thread in json_threads: + thread = self.crashlog.Thread(idx, False) + if 'name' in json_thread: + thread.reason = json_thread['name'] + if json_thread.get('triggered', False): + self.crashlog.crashed_thread_idx = idx + thread.registers = self.parse_thread_registers( + json_thread['threadState']) + thread.queue = json_thread.get('queue') + self.parse_frames(thread, json_thread.get('frames', [])) + self.crashlog.threads.append(thread) + idx += 1 + + def parse_thread_registers(self, json_thread_state): + registers = dict() + for key, state in json_thread_state.items(): + try: + value = int(state['value']) + registers[key] = value + except (TypeError, ValueError): + pass + return registers + + +class CrashLogParseMode: + NORMAL = 0 + THREAD = 1 + IMAGES = 2 + THREGS = 3 + SYSTEM = 4 + INSTRS = 5 + + +class TextCrashLogParser: + parent_process_regex = re.compile('^Parent Process:\s*(.*)\[(\d+)\]') + thread_state_regex = re.compile('^Thread ([0-9]+) crashed with') + thread_instrs_regex = re.compile('^Thread ([0-9]+) instruction stream') + thread_regex = re.compile('^Thread ([0-9]+)([^:]*):(.*)') + app_backtrace_regex = re.compile('^Application Specific Backtrace ([0-9]+)([^:]*):(.*)') + version = r'(\(.+\)|(arm|x86_)[0-9a-z]+)\s+' + frame_regex = re.compile(r'^([0-9]+)' r'\s' # id + r'+(.+?)' r'\s+' # img_name + r'(' +version+ r')?' # img_version + r'(0x[0-9a-fA-F]{7}[0-9a-fA-F]+)' # addr + r' +(.*)' # offs + ) + null_frame_regex = re.compile(r'^([0-9]+)\s+\?\?\?\s+(0{7}0+) +(.*)') + image_regex_uuid = re.compile(r'(0x[0-9a-fA-F]+)' # img_lo + r'\s+' '-' r'\s+' # - + r'(0x[0-9a-fA-F]+)' r'\s+' # img_hi + r'[+]?(.+?)' r'\s+' # img_name + r'(' +version+ ')?' # img_version + r'(<([-0-9a-fA-F]+)>\s+)?' # img_uuid + r'(/.*)' # img_path + ) + + + def __init__(self, debugger, path, verbose): + self.path = os.path.expanduser(path) + self.verbose = verbose + self.thread = None + self.app_specific_backtrace = False + self.crashlog = CrashLog(debugger, self.path, self.verbose) + self.parse_mode = CrashLogParseMode.NORMAL + self.parsers = { + CrashLogParseMode.NORMAL : self.parse_normal, + CrashLogParseMode.THREAD : self.parse_thread, + CrashLogParseMode.IMAGES : self.parse_images, + CrashLogParseMode.THREGS : self.parse_thread_registers, + CrashLogParseMode.SYSTEM : self.parse_system, + CrashLogParseMode.INSTRS : self.parse_instructions, + } + + def parse(self): + with open(self.path,'r') as f: + lines = f.read().splitlines() + + for line in lines: + line_len = len(line) + if line_len == 0: + if self.thread: + if self.parse_mode == CrashLogParseMode.THREAD: + if self.thread.index == self.crashlog.crashed_thread_idx: + self.thread.reason = '' + if self.crashlog.thread_exception: + self.thread.reason += self.crashlog.thread_exception + if self.crashlog.thread_exception_data: + self.thread.reason += " (%s)" % self.crashlog.thread_exception_data + if self.app_specific_backtrace: + self.crashlog.backtraces.append(self.thread) + else: + self.crashlog.threads.append(self.thread) + self.thread = None + else: + # only append an extra empty line if the previous line + # in the info_lines wasn't empty + if len(self.crashlog.info_lines) > 0 and len(self.crashlog.info_lines[-1]): + self.crashlog.info_lines.append(line) + self.parse_mode = CrashLogParseMode.NORMAL + else: + self.parsers[self.parse_mode](line) + + return self.crashlog + + + def parse_normal(self, line): + if line.startswith('Process:'): + (self.crashlog.process_name, pid_with_brackets) = line[ + 8:].strip().split(' [') + self.crashlog.process_id = pid_with_brackets.strip('[]') + elif line.startswith('Path:'): + self.crashlog.process_path = line[5:].strip() + elif line.startswith('Identifier:'): + self.crashlog.process_identifier = line[11:].strip() + elif line.startswith('Version:'): + version_string = line[8:].strip() + matched_pair = re.search("(.+)\((.+)\)", version_string) + if matched_pair: + self.crashlog.process_version = matched_pair.group(1) + self.crashlog.process_compatability_version = matched_pair.group( + 2) + else: + self.crashlog.process = version_string + self.crashlog.process_compatability_version = version_string + elif self.parent_process_regex.search(line): + parent_process_match = self.parent_process_regex.search( + line) + self.crashlog.parent_process_name = parent_process_match.group(1) + self.crashlog.parent_process_id = parent_process_match.group(2) + elif line.startswith('Exception Type:'): + self.crashlog.thread_exception = line[15:].strip() + return + elif line.startswith('Exception Codes:'): + self.crashlog.thread_exception_data = line[16:].strip() + return + elif line.startswith('Exception Subtype:'): # iOS + self.crashlog.thread_exception_data = line[18:].strip() + return + elif line.startswith('Crashed Thread:'): + self.crashlog.crashed_thread_idx = int(line[15:].strip().split()[0]) + return + elif line.startswith('Triggered by Thread:'): # iOS + self.crashlog.crashed_thread_idx = int(line[20:].strip().split()[0]) + return + elif line.startswith('Report Version:'): + self.crashlog.version = int(line[15:].strip()) + return + elif line.startswith('System Profile:'): + self.parse_mode = CrashLogParseMode.SYSTEM + return + elif (line.startswith('Interval Since Last Report:') or + line.startswith('Crashes Since Last Report:') or + line.startswith('Per-App Interval Since Last Report:') or + line.startswith('Per-App Crashes Since Last Report:') or + line.startswith('Sleep/Wake UUID:') or + line.startswith('Anonymous UUID:')): + # ignore these + return + elif line.startswith('Thread'): + thread_state_match = self.thread_state_regex.search(line) + if thread_state_match: + self.app_specific_backtrace = False + thread_state_match = self.thread_regex.search(line) + thread_idx = int(thread_state_match.group(1)) + self.parse_mode = CrashLogParseMode.THREGS + self.thread = self.crashlog.threads[thread_idx] + return + thread_insts_match = self.thread_instrs_regex.search(line) + if thread_insts_match: + self.parse_mode = CrashLogParseMode.INSTRS + return + thread_match = self.thread_regex.search(line) + if thread_match: + self.app_specific_backtrace = False + self.parse_mode = CrashLogParseMode.THREAD + thread_idx = int(thread_match.group(1)) + self.thread = self.crashlog.Thread(thread_idx, False) + return + return + elif line.startswith('Binary Images:'): + self.parse_mode = CrashLogParseMode.IMAGES + return + elif line.startswith('Application Specific Backtrace'): + app_backtrace_match = self.app_backtrace_regex.search(line) + if app_backtrace_match: + self.parse_mode = CrashLogParseMode.THREAD + self.app_specific_backtrace = True + idx = int(app_backtrace_match.group(1)) + self.thread = self.crashlog.Thread(idx, True) + elif line.startswith('Last Exception Backtrace:'): # iOS + self.parse_mode = CrashLogParseMode.THREAD + self.app_specific_backtrace = True + idx = 1 + self.thread = self.crashlog.Thread(idx, True) + self.crashlog.info_lines.append(line.strip()) + + def parse_thread(self, line): + if line.startswith('Thread'): + return + if self.null_frame_regex.search(line): + print('warning: thread parser ignored null-frame: "%s"' % line) + return + frame_match = self.frame_regex.search(line) + if frame_match: + (frame_id, frame_img_name, _, frame_img_version, _, + frame_addr, frame_ofs) = frame_match.groups() + ident = frame_img_name + self.thread.add_ident(ident) + if ident not in self.crashlog.idents: + self.crashlog.idents.append(ident) + self.thread.frames.append(self.crashlog.Frame(int(frame_id), int( + frame_addr, 0), frame_ofs)) + else: + print('error: frame regex failed for line: "%s"' % line) + + def parse_images(self, line): + image_match = self.image_regex_uuid.search(line) + if image_match: + (img_lo, img_hi, img_name, _, img_version, _, + _, img_uuid, img_path) = image_match.groups() + image = self.crashlog.DarwinImage(int(img_lo, 0), int(img_hi, 0), + img_name.strip(), + img_version.strip() + if img_version else "", + uuid.UUID(img_uuid), img_path, + self.verbose) + self.crashlog.images.append(image) + else: + print("error: image regex failed for: %s" % line) + + + def parse_thread_registers(self, line): + stripped_line = line.strip() + # "r12: 0x00007fff6b5939c8 r13: 0x0000000007000006 r14: 0x0000000000002a03 r15: 0x0000000000000c00" + reg_values = re.findall( + '([a-zA-Z0-9]+: 0[Xx][0-9a-fA-F]+) *', stripped_line) + for reg_value in reg_values: + (reg, value) = reg_value.split(': ') + self.thread.registers[reg.strip()] = int(value, 0) + + def parse_system(self, line): + self.crashlog.system_profile.append(line) + + def parse_instructions(self, line): + pass + + def usage(): print("Usage: lldb-symbolicate.py [-n name] executable-image") sys.exit(0) @@ -706,7 +843,7 @@ class Interactive(cmd.Cmd): return False -def interactive_crashlogs(options, args): +def interactive_crashlogs(debugger, options, args): crash_log_files = list() for arg in args: for resolved_path in glob.glob(arg): @@ -714,10 +851,10 @@ def interactive_crashlogs(options, args): crash_logs = list() for crash_log_file in crash_log_files: - # print 'crash_log_file = "%s"' % crash_log_file - crash_log = CrashLog(crash_log_file, options.verbose) - if crash_log.error: - print(crash_log.error) + try: + crash_log = CrashLogParser().parse(debugger, crash_log_file, options.verbose) + except Exception as e: + print(e) continue if options.debug: crash_log.dump() @@ -843,15 +980,12 @@ def save_crashlog(debugger, command, exe_ctx, result, dict): def Symbolicate(debugger, command, result, dict): try: - SymbolicateCrashLogs(shlex.split(command)) - except: - result.PutCString("error: python exception %s" % sys.exc_info()[0]) + SymbolicateCrashLogs(debugger, shlex.split(command)) + except Exception as e: + result.PutCString("error: python exception: %s" % e) def SymbolicateCrashLog(crash_log, options): - if crash_log.error: - print(crash_log.error) - return if options.debug: crash_log.dump() if not crash_log.images: @@ -903,7 +1037,6 @@ def SymbolicateCrashLog(crash_log, options): if err: print(err) else: - # print 'loaded %s' % image loaded_images.append(image) if crash_log.backtraces: @@ -1023,7 +1156,7 @@ def CreateSymbolicateCrashLogOptions( return option_parser -def SymbolicateCrashLogs(command_args): +def SymbolicateCrashLogs(debugger, command_args): description = '''Symbolicate one or more darwin crash log files to provide source file and line information, inlined stack frames back to the concrete functions, and disassemble the location of the crash for the first frame of the crashed thread. @@ -1051,19 +1184,18 @@ be disassembled and lookups can be performed using the addresses found in the cr if args: if options.interactive: - interactive_crashlogs(options, args) + interactive_crashlogs(debugger, options, args) else: for crash_log_file in args: - crash_log = CrashLog(crash_log_file, options.verbose) + crash_log = CrashLogParser().parse(debugger, crash_log_file, options.verbose) SymbolicateCrashLog(crash_log, options) if __name__ == '__main__': # Create a new debugger instance - lldb.debugger = lldb.SBDebugger.Create() - SymbolicateCrashLogs(sys.argv[1:]) - lldb.SBDebugger.Destroy(lldb.debugger) + debugger = lldb.SBDebugger.Create() + SymbolicateCrashLogs(debugger, sys.argv[1:]) + lldb.SBDebugger.Destroy(debugger) elif getattr(lldb, 'debugger', None): lldb.debugger.HandleCommand( 'command script add -f lldb.macosx.crashlog.Symbolicate crashlog') lldb.debugger.HandleCommand( 'command script add -f lldb.macosx.crashlog.save_crashlog save_crashlog') - print('"crashlog" and "save_crashlog" command installed, use the "--help" option for detailed help') diff --git a/gnu/llvm/lldb/examples/python/delta.py b/gnu/llvm/lldb/examples/python/delta.py index 1a1f060c5e5..0176fb0b334 100755 --- a/gnu/llvm/lldb/examples/python/delta.py +++ b/gnu/llvm/lldb/examples/python/delta.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python #---------------------------------------------------------------------- # This module will enable GDB remote packet logging when the diff --git a/gnu/llvm/lldb/examples/python/disasm-stress-test.py b/gnu/llvm/lldb/examples/python/disasm-stress-test.py index 5d0ce96fbd6..241a73acd4e 100755 --- a/gnu/llvm/lldb/examples/python/disasm-stress-test.py +++ b/gnu/llvm/lldb/examples/python/disasm-stress-test.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python import argparse import datetime diff --git a/gnu/llvm/lldb/examples/python/disasm.py b/gnu/llvm/lldb/examples/python/disasm.py index 819a0522388..20b441835f1 100755 --- a/gnu/llvm/lldb/examples/python/disasm.py +++ b/gnu/llvm/lldb/examples/python/disasm.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python #---------------------------------------------------------------------- # Be sure to add the python path that points to the LLDB shared library. diff --git a/gnu/llvm/lldb/examples/python/file_extract.py b/gnu/llvm/lldb/examples/python/file_extract.py index decbba0b299..7278ce54a8a 100755 --- a/gnu/llvm/lldb/examples/python/file_extract.py +++ b/gnu/llvm/lldb/examples/python/file_extract.py @@ -1,4 +1,4 @@ -#! /usr/bin/env python +#!/usr/bin/env python import string import struct diff --git a/gnu/llvm/lldb/examples/python/gdbremote.py b/gnu/llvm/lldb/examples/python/gdbremote.py index 52601c09d3b..804977259de 100755 --- a/gnu/llvm/lldb/examples/python/gdbremote.py +++ b/gnu/llvm/lldb/examples/python/gdbremote.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python #---------------------------------------------------------------------- # This module will enable GDB remote packet logging when the diff --git a/gnu/llvm/lldb/examples/python/globals.py b/gnu/llvm/lldb/examples/python/globals.py index 3e773441642..96645afef00 100755 --- a/gnu/llvm/lldb/examples/python/globals.py +++ b/gnu/llvm/lldb/examples/python/globals.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python #---------------------------------------------------------------------- # For the shells csh, tcsh: diff --git a/gnu/llvm/lldb/examples/python/lldb_module_utils.py b/gnu/llvm/lldb/examples/python/lldb_module_utils.py index 2b2fea9d4f1..c0ac5751ce2 100644 --- a/gnu/llvm/lldb/examples/python/lldb_module_utils.py +++ b/gnu/llvm/lldb/examples/python/lldb_module_utils.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python from __future__ import print_function import lldb diff --git a/gnu/llvm/lldb/examples/python/lldbtk.py b/gnu/llvm/lldb/examples/python/lldbtk.py index 3734b14f95b..a6a420ba1bd 100644 --- a/gnu/llvm/lldb/examples/python/lldbtk.py +++ b/gnu/llvm/lldb/examples/python/lldbtk.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python from __future__ import print_function import lldb diff --git a/gnu/llvm/lldb/examples/python/mach_o.py b/gnu/llvm/lldb/examples/python/mach_o.py index 1780bc3e320..03ab73b3be9 100755 --- a/gnu/llvm/lldb/examples/python/mach_o.py +++ b/gnu/llvm/lldb/examples/python/mach_o.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python from __future__ import print_function import cmd diff --git a/gnu/llvm/lldb/examples/python/memory.py b/gnu/llvm/lldb/examples/python/memory.py index 9f8f7e384c4..26703462c2c 100755 --- a/gnu/llvm/lldb/examples/python/memory.py +++ b/gnu/llvm/lldb/examples/python/memory.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python #---------------------------------------------------------------------- # Be sure to add the python path that points to the LLDB shared library. diff --git a/gnu/llvm/lldb/examples/python/operating_system.py b/gnu/llvm/lldb/examples/python/operating_system.py index bfa13f0568e..f4a5d385320 100644 --- a/gnu/llvm/lldb/examples/python/operating_system.py +++ b/gnu/llvm/lldb/examples/python/operating_system.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python import lldb import struct diff --git a/gnu/llvm/lldb/examples/python/performance.py b/gnu/llvm/lldb/examples/python/performance.py index aec6b307f87..57e9d1e0a24 100755 --- a/gnu/llvm/lldb/examples/python/performance.py +++ b/gnu/llvm/lldb/examples/python/performance.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python #---------------------------------------------------------------------- # Be sure to add the python path that points to the LLDB shared library. @@ -255,6 +255,15 @@ class TestCase: select_thread = True if self.verbose: print("signal %d" % (thread.GetStopReasonDataAtIndex(0))) + elif stop_reason == lldb.eStopReasonFork: + if self.verbose: + print("fork pid = %d" % (thread.GetStopReasonDataAtIndex(0))) + elif stop_reason == lldb.eStopReasonVFork: + if self.verbose: + print("vfork pid = %d" % (thread.GetStopReasonDataAtIndex(0))) + elif stop_reason == lldb.eStopReasonVForkDone: + if self.verbose: + print("vfork done") if select_thread and not selected_thread: self.thread = thread diff --git a/gnu/llvm/lldb/examples/python/process_events.py b/gnu/llvm/lldb/examples/python/process_events.py index 6039ebf0020..cb4bf788119 100755 --- a/gnu/llvm/lldb/examples/python/process_events.py +++ b/gnu/llvm/lldb/examples/python/process_events.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python #---------------------------------------------------------------------- # Be sure to add the python path that points to the LLDB shared library. @@ -199,7 +199,7 @@ def main(argv): type='string', metavar='DIR', dest='working_dir', - help='The the current working directory when launching a process.', + help='The current working directory when launching a process.', default=None) parser.add_option( '-p', diff --git a/gnu/llvm/lldb/examples/python/sbvalue.py b/gnu/llvm/lldb/examples/python/sbvalue.py index 6e512998da2..cc7188a8ea0 100755 --- a/gnu/llvm/lldb/examples/python/sbvalue.py +++ b/gnu/llvm/lldb/examples/python/sbvalue.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python import lldb diff --git a/gnu/llvm/lldb/examples/python/scripted_process/my_scripted_process.py b/gnu/llvm/lldb/examples/python/scripted_process/my_scripted_process.py new file mode 100644 index 00000000000..429531e80e1 --- /dev/null +++ b/gnu/llvm/lldb/examples/python/scripted_process/my_scripted_process.py @@ -0,0 +1,45 @@ +import os + +import lldb +from lldb.plugins.scripted_process import ScriptedProcess + +class MyScriptedProcess(ScriptedProcess): + def __init__(self, target: lldb.SBTarget, args : lldb.SBStructuredData): + super().__init__(target, args) + + def get_memory_region_containing_address(self, addr: int) -> lldb.SBMemoryRegionInfo: + return self.memory_regions[0] + + def get_thread_with_id(self, tid: int): + return {} + + def get_registers_for_thread(self, tid: int): + return {} + + def read_memory_at_address(self, addr: int, size: int) -> lldb.SBData: + data = lldb.SBData().CreateDataFromCString( + self.target.GetByteOrder(), + self.target.GetCodeByteSize(), + "Hello, world!") + return data + + def get_loaded_images(self): + return self.loaded_images + + def get_process_id(self) -> int: + return 42 + + def should_stop(self) -> bool: + return True + + def is_alive(self) -> bool: + return True + +def __lldb_init_module(debugger, dict): + if not 'SKIP_SCRIPTED_PROCESS_LAUNCH' in os.environ: + debugger.HandleCommand( + "process launch -C %s.%s" % (__name__, + MyScriptedProcess.__name__)) + else: + print("Name of the class that will manage the scripted process: '%s.%s'" + % (__name__, MyScriptedProcess.__name__)) \ No newline at end of file diff --git a/gnu/llvm/lldb/examples/python/scripted_process/scripted_process.py b/gnu/llvm/lldb/examples/python/scripted_process/scripted_process.py new file mode 100644 index 00000000000..72dce5c1e3b --- /dev/null +++ b/gnu/llvm/lldb/examples/python/scripted_process/scripted_process.py @@ -0,0 +1,165 @@ +from abc import ABCMeta, abstractmethod +import six + +import lldb + +@six.add_metaclass(ABCMeta) +class ScriptedProcess: + + """ + The base class for a scripted process. + + Most of the base class methods are `@abstractmethod` that need to be + overwritten by the inheriting class. + + DISCLAIMER: THIS INTERFACE IS STILL UNDER DEVELOPMENT AND NOT STABLE. + THE METHODS EXPOSED MIGHT CHANGE IN THE FUTURE. + """ + + @abstractmethod + def __init__(self, target, args): + """ Construct a scripted process. + + Args: + target (lldb.SBTarget): The target launching the scripted process. + args (lldb.SBStructuredData): A Dictionary holding arbitrary + key/value pairs used by the scripted process. + """ + self.target = None + self.args = None + if isinstance(target, lldb.SBTarget) and target.IsValid(): + self.target = target + if isinstance(args, lldb.SBStructuredData) and args.IsValid(): + self.args = args + + @abstractmethod + def get_memory_region_containing_address(addr): + """ Get the memory region for the scripted process, containing a + specific address. + + Args: + addr (int): Address to look for in the scripted process memory + regions. + + Returns: + lldb.SBMemoryRegionInfo: The memory region containing the address. + None if out of bounds. + """ + pass + + @abstractmethod + def get_thread_with_id(tid): + """ Get the scripted process thread with a specific ID. + + Args: + tid (int): Thread ID to look for in the scripted process. + + Returns: + Dict: The thread represented as a dictionary, withr the + tid thread ID. None if tid doesn't match any of the scripted + process threads. + """ + pass + + @abstractmethod + def get_registers_for_thread(tid): + """ Get the register context dictionary for a certain thread of + the scripted process. + + Args: + tid (int): Thread ID for the thread's register context. + + Returns: + Dict: The register context represented as a dictionary, for the + tid thread. None if tid doesn't match any of the scripted + process threads. + """ + pass + + @abstractmethod + def read_memory_at_address(addr, size): + """ Get a memory buffer from the scripted process at a certain address, + of a certain size. + + Args: + addr (int): Address from which we should start reading. + size (int): Size of the memory to read. + + Returns: + lldb.SBData: An `lldb.SBData` buffer with the target byte size and + byte order storing the memory read. + """ + pass + + @abstractmethod + def get_loaded_images(self): + """ Get the list of loaded images for the scripted process. + + ``` + class ScriptedProcessImage: + def __init__(name, file_spec, uuid, load_address): + self.name = name + self.file_spec = file_spec + self.uuid = uuid + self.load_address = load_address + ``` + + Returns: + List[ScriptedProcessImage]: A list of `ScriptedProcessImage` + containing for each entry, the name of the library, a UUID, + an `lldb.SBFileSpec` and a load address. + None if the list is empty. + """ + pass + + def get_process_id(self): + """ Get the scripted process identifier. + + Returns: + int: The scripted process identifier. + """ + return 0 + + + def launch(self): + """ Simulate the scripted process launch. + + Returns: + lldb.SBError: An `lldb.SBError` with error code 0. + """ + return lldb.SBError() + + def resume(self): + """ Simulate the scripted process resume. + + Returns: + lldb.SBError: An `lldb.SBError` with error code 0. + """ + return lldb.SBError() + + @abstractmethod + def should_stop(self): + """ Check if the scripted process plugin should produce the stop event. + + Returns: + bool: True if scripted process should broadcast a stop event. + False otherwise. + """ + pass + + def stop(self): + """ Trigger the scripted process stop. + + Returns: + lldb.SBError: An `lldb.SBError` with error code 0. + """ + return lldb.SBError() + + @abstractmethod + def is_alive(self): + """ Check if the scripted process is alive. + + Returns: + bool: True if scripted process is alive. False otherwise. + """ + pass diff --git a/gnu/llvm/lldb/examples/python/shadow.py b/gnu/llvm/lldb/examples/python/shadow.py index b14467c52c9..73534dce535 100644 --- a/gnu/llvm/lldb/examples/python/shadow.py +++ b/gnu/llvm/lldb/examples/python/shadow.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python from __future__ import print_function import lldb diff --git a/gnu/llvm/lldb/examples/python/sources.py b/gnu/llvm/lldb/examples/python/sources.py index 9684f7f6e78..38b3926768b 100644 --- a/gnu/llvm/lldb/examples/python/sources.py +++ b/gnu/llvm/lldb/examples/python/sources.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python from __future__ import print_function import lldb diff --git a/gnu/llvm/lldb/examples/python/stacks.py b/gnu/llvm/lldb/examples/python/stacks.py index a676b82d097..41729ec6744 100755 --- a/gnu/llvm/lldb/examples/python/stacks.py +++ b/gnu/llvm/lldb/examples/python/stacks.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python from __future__ import print_function import lldb import optparse diff --git a/gnu/llvm/lldb/examples/python/symbolication.py b/gnu/llvm/lldb/examples/python/symbolication.py index a6daa802cda..70f2ff3bb27 100755 --- a/gnu/llvm/lldb/examples/python/symbolication.py +++ b/gnu/llvm/lldb/examples/python/symbolication.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python #---------------------------------------------------------------------- # Be sure to add the python path that points to the LLDB shared library. @@ -410,7 +410,7 @@ class Image: return str(self.uuid).upper() return None - def create_target(self): + def create_target(self, debugger): '''Create a target using the information in this Image object.''' if self.unavailable: return None @@ -419,7 +419,7 @@ class Image: resolved_path = self.get_resolved_path() path_spec = lldb.SBFileSpec(resolved_path) error = lldb.SBError() - target = lldb.debugger.CreateTarget( + target = debugger.CreateTarget( resolved_path, self.arch, None, False, error) if target: self.module = target.FindModule(path_spec) @@ -437,17 +437,22 @@ class Image: class Symbolicator: - def __init__(self): - """A class the represents the information needed to symbolicate addresses in a program""" - self.target = None - self.images = list() # a list of images to be used when symbolicating + def __init__(self, debugger=None, target=None, images=list()): + """A class the represents the information needed to symbolicate + addresses in a program. + + Do not call this initializer directly, but rather use the factory + methods. + """ + self.debugger = debugger + self.target = target + self.images = images # a list of images to be used when symbolicating self.addr_mask = 0xffffffffffffffff @classmethod def InitWithSBTarget(cls, target): - obj = cls() - obj.target = target - obj.images = list() + """Initialize a new Symbolicator with an existing SBTarget.""" + obj = cls(target=target) triple = target.triple if triple: arch = triple.split('-')[0] @@ -459,6 +464,13 @@ class Symbolicator: obj.images.append(image) return obj + @classmethod + def InitWithSBDebugger(cls, debugger, images): + """Initialize a new Symbolicator with an existing debugger and list of + images. The Symbolicator will create the target.""" + obj = cls(debugger=debugger, images=images) + return obj + def __str__(self): s = "Symbolicator:\n" if self.target: @@ -496,7 +508,7 @@ class Symbolicator: if self.images: for image in self.images: - self.target = image.create_target() + self.target = image.create_target(self.debugger) if self.target: if self.target.GetAddressByteSize() == 4: triple = self.target.triple @@ -632,7 +644,7 @@ def print_module_symbols(module): print(sym) -def Symbolicate(command_args): +def Symbolicate(debugger, command_args): usage = "usage: %prog [options] [addr2 ...]" description = '''Symbolicate one or more addresses using LLDB's python scripting API..''' @@ -686,7 +698,7 @@ def Symbolicate(command_args): (options, args) = parser.parse_args(command_args) except: return - symbolicator = Symbolicator() + symbolicator = Symbolicator(debugger) images = list() if options.file: image = Image(options.file) @@ -720,5 +732,6 @@ def Symbolicate(command_args): if __name__ == '__main__': # Create a new debugger instance - lldb.debugger = lldb.SBDebugger.Create() - Symbolicate(sys.argv[1:]) + debugger = lldb.SBDebugger.Create() + Symbolicate(debugger, sys.argv[1:]) + SBDebugger.Destroy(debugger) diff --git a/gnu/llvm/lldb/examples/python/types.py b/gnu/llvm/lldb/examples/python/types.py index a401e373f48..513a03b2600 100755 --- a/gnu/llvm/lldb/examples/python/types.py +++ b/gnu/llvm/lldb/examples/python/types.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python #---------------------------------------------------------------------- # Be sure to add the python path that points to the LLDB shared library. diff --git a/gnu/llvm/lldb/examples/python/x86_64_linux_target_definition.py b/gnu/llvm/lldb/examples/python/x86_64_linux_target_definition.py index 13bde540f7e..a39b9bed134 100644 --- a/gnu/llvm/lldb/examples/python/x86_64_linux_target_definition.py +++ b/gnu/llvm/lldb/examples/python/x86_64_linux_target_definition.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python #===-- x86_64_linux_target_definition.py -----------------------------*- C++ -*-===// # # Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. diff --git a/gnu/llvm/lldb/examples/python/x86_64_qemu_target_definition.py b/gnu/llvm/lldb/examples/python/x86_64_qemu_target_definition.py index aa081c16117..f0bed692baa 100644 --- a/gnu/llvm/lldb/examples/python/x86_64_qemu_target_definition.py +++ b/gnu/llvm/lldb/examples/python/x86_64_qemu_target_definition.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python #===-- x86_64_qemu_target_definition.py -----------------------------*- C++ -*-===// # # Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. diff --git a/gnu/llvm/lldb/examples/python/x86_64_target_definition.py b/gnu/llvm/lldb/examples/python/x86_64_target_definition.py index 3f7f60dec9b..533cafca400 100644 --- a/gnu/llvm/lldb/examples/python/x86_64_target_definition.py +++ b/gnu/llvm/lldb/examples/python/x86_64_target_definition.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python #===-- x86_64_target_definition.py -----------------------------*- C++ -*-===// # # Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. diff --git a/gnu/llvm/lldb/examples/synthetic/gnu_libstdcpp.py b/gnu/llvm/lldb/examples/synthetic/gnu_libstdcpp.py index 35f009e1bcb..528b28349bb 100644 --- a/gnu/llvm/lldb/examples/synthetic/gnu_libstdcpp.py +++ b/gnu/llvm/lldb/examples/synthetic/gnu_libstdcpp.py @@ -148,6 +148,7 @@ class StdListSynthProvider: self.data_size = self.data_type.GetByteSize() except: pass + return False def has_children(self): return True @@ -235,7 +236,7 @@ class StdVectorSynthProvider: self.count = 0 except: pass - return True + return False class StdVBoolImplementation(object): @@ -282,7 +283,7 @@ class StdVectorSynthProvider: self.valid = True except: self.valid = False - return True + return False def __init__(self, valobj, dict): logger = lldb.formatters.Logger.Logger() @@ -378,6 +379,7 @@ class StdMapSynthProvider: self.skip_size = self.Mheader.GetType().GetByteSize() except: pass + return False def num_children(self): logger = lldb.formatters.Logger.Logger() diff --git a/gnu/llvm/lldb/examples/test/.lldb-loggings b/gnu/llvm/lldb/examples/test/.lldb-loggings index 9c92bd95847..873bb88c844 100644 --- a/gnu/llvm/lldb/examples/test/.lldb-loggings +++ b/gnu/llvm/lldb/examples/test/.lldb-loggings @@ -3,8 +3,7 @@ def pre_flight(self): import lldb import lldbtest - dname = os.path.join(os.environ["LLDB_TEST"], - os.environ["LLDB_SESSION_DIRNAME"]) + dname = os.path.join(os.environ["LLDB_TEST"]) if not os.path.isdir(dname): os.mkdir(dname) dest = os.path.join(dname, "lldb_log-%s-%s-%s.txt" % (self.getArchitecture(), self.getCompiler(), self.id())) diff --git a/gnu/llvm/lldb/examples/test/usage-lldb-loggings b/gnu/llvm/lldb/examples/test/usage-lldb-loggings index b7d7e2e58fc..4ce9689f3d3 100644 --- a/gnu/llvm/lldb/examples/test/usage-lldb-loggings +++ b/gnu/llvm/lldb/examples/test/usage-lldb-loggings @@ -88,8 +88,7 @@ lldb.pre_flight: def pre_flight(self): import lldb import lldbtest - dname = os.path.join(os.environ["LLDB_TEST"], - os.environ["LLDB_SESSION_DIRNAME"]) + dname = os.path.join(os.environ["LLDB_TEST"]) if not os.path.isdir(dname): os.mkdir(dname) dest = os.path.join(dname, "lldb_log-%s-%s-%s.txt" % (self.getArchitecture(), self.getCompiler(), self.id())) diff --git a/gnu/llvm/lldb/include/lldb/API/LLDB.h b/gnu/llvm/lldb/include/lldb/API/LLDB.h index 83c38d3b616..eacbbeafcf1 100644 --- a/gnu/llvm/lldb/include/lldb/API/LLDB.h +++ b/gnu/llvm/lldb/include/lldb/API/LLDB.h @@ -17,6 +17,7 @@ #include "lldb/API/SBBreakpointName.h" #include "lldb/API/SBBroadcaster.h" #include "lldb/API/SBCommandInterpreter.h" +#include "lldb/API/SBCommandInterpreterRunOptions.h" #include "lldb/API/SBCommandReturnObject.h" #include "lldb/API/SBCommunication.h" #include "lldb/API/SBCompileUnit.h" @@ -64,7 +65,6 @@ #include "lldb/API/SBThreadCollection.h" #include "lldb/API/SBThreadPlan.h" #include "lldb/API/SBTrace.h" -#include "lldb/API/SBTraceOptions.h" #include "lldb/API/SBType.h" #include "lldb/API/SBTypeCategory.h" #include "lldb/API/SBTypeEnumMember.h" diff --git a/gnu/llvm/lldb/include/lldb/API/SBAddress.h b/gnu/llvm/lldb/include/lldb/API/SBAddress.h index cf7555dc2ee..5a792a24cf6 100644 --- a/gnu/llvm/lldb/include/lldb/API/SBAddress.h +++ b/gnu/llvm/lldb/include/lldb/API/SBAddress.h @@ -115,9 +115,9 @@ protected: const lldb_private::Address &ref() const; - SBAddress(const lldb_private::Address *lldb_object_ptr); + SBAddress(const lldb_private::Address &address); - void SetAddress(const lldb_private::Address *lldb_object_ptr); + void SetAddress(const lldb_private::Address &address); private: std::unique_ptr m_opaque_up; diff --git a/gnu/llvm/lldb/include/lldb/API/SBBlock.h b/gnu/llvm/lldb/include/lldb/API/SBBlock.h index be1ae18e9db..2570099f765 100644 --- a/gnu/llvm/lldb/include/lldb/API/SBBlock.h +++ b/gnu/llvm/lldb/include/lldb/API/SBBlock.h @@ -87,7 +87,7 @@ private: void AppendVariables(bool can_create, bool get_parent_variables, lldb_private::VariableList *var_list); - lldb_private::Block *m_opaque_ptr; + lldb_private::Block *m_opaque_ptr = nullptr; }; } // namespace lldb diff --git a/gnu/llvm/lldb/include/lldb/API/SBBreakpoint.h b/gnu/llvm/lldb/include/lldb/API/SBBreakpoint.h index c9a52fcacf1..e13dbc5c351 100644 --- a/gnu/llvm/lldb/include/lldb/API/SBBreakpoint.h +++ b/gnu/llvm/lldb/include/lldb/API/SBBreakpoint.h @@ -42,6 +42,8 @@ public: void ClearAllBreakpointSites(); + lldb::SBTarget GetTarget() const; + lldb::SBBreakpointLocation FindLocationByAddress(lldb::addr_t vm_addr); lldb::break_id_t FindLocationIDByAddress(lldb::addr_t vm_addr); @@ -140,7 +142,9 @@ public: // Can only be called from a ScriptedBreakpointResolver... SBError AddLocation(SBAddress &address); - + + SBStructuredData SerializeToStructuredData(); + private: friend class SBBreakpointList; friend class SBBreakpointLocation; diff --git a/gnu/llvm/lldb/include/lldb/API/SBBroadcaster.h b/gnu/llvm/lldb/include/lldb/API/SBBroadcaster.h index 69a516a8bfb..046473d4223 100644 --- a/gnu/llvm/lldb/include/lldb/API/SBBroadcaster.h +++ b/gnu/llvm/lldb/include/lldb/API/SBBroadcaster.h @@ -63,6 +63,7 @@ public: protected: friend class SBCommandInterpreter; friend class SBCommunication; + friend class SBDebugger; friend class SBEvent; friend class SBListener; friend class SBProcess; @@ -76,7 +77,7 @@ protected: private: lldb::BroadcasterSP m_opaque_sp; - lldb_private::Broadcaster *m_opaque_ptr; + lldb_private::Broadcaster *m_opaque_ptr = nullptr; }; } // namespace lldb diff --git a/gnu/llvm/lldb/include/lldb/API/SBCommandInterpreter.h b/gnu/llvm/lldb/include/lldb/API/SBCommandInterpreter.h index a70e060bec9..2364a8dae88 100644 --- a/gnu/llvm/lldb/include/lldb/API/SBCommandInterpreter.h +++ b/gnu/llvm/lldb/include/lldb/API/SBCommandInterpreter.h @@ -146,6 +146,8 @@ public: const char *auto_repeat_command); void SourceInitFileInHomeDirectory(lldb::SBCommandReturnObject &result); + void SourceInitFileInHomeDirectory(lldb::SBCommandReturnObject &result, + bool is_repl); void SourceInitFileInCurrentWorkingDirectory(lldb::SBCommandReturnObject &result); diff --git a/gnu/llvm/lldb/include/lldb/API/SBCommandInterpreterRunOptions.h b/gnu/llvm/lldb/include/lldb/API/SBCommandInterpreterRunOptions.h index 82d6feedc02..efaacd39eb0 100644 --- a/gnu/llvm/lldb/include/lldb/API/SBCommandInterpreterRunOptions.h +++ b/gnu/llvm/lldb/include/lldb/API/SBCommandInterpreterRunOptions.h @@ -26,8 +26,12 @@ class LLDB_API SBCommandInterpreterRunOptions { public: SBCommandInterpreterRunOptions(); + SBCommandInterpreterRunOptions(const SBCommandInterpreterRunOptions &rhs); ~SBCommandInterpreterRunOptions(); + SBCommandInterpreterRunOptions & + operator=(const SBCommandInterpreterRunOptions &rhs); + bool GetStopOnContinue() const; void SetStopOnContinue(bool); @@ -52,6 +56,10 @@ public: void SetPrintResults(bool); + bool GetPrintErrors() const; + + void SetPrintErrors(bool); + bool GetAddToHistory() const; void SetAddToHistory(bool); diff --git a/gnu/llvm/lldb/include/lldb/API/SBCommandReturnObject.h b/gnu/llvm/lldb/include/lldb/API/SBCommandReturnObject.h index 4ee296eb179..5738c911ae1 100644 --- a/gnu/llvm/lldb/include/lldb/API/SBCommandReturnObject.h +++ b/gnu/llvm/lldb/include/lldb/API/SBCommandReturnObject.h @@ -9,7 +9,7 @@ #ifndef LLDB_API_SBCOMMANDRETURNOBJECT_H #define LLDB_API_SBCOMMANDRETURNOBJECT_H -#include +#include #include @@ -105,9 +105,6 @@ public: void SetError(const char *error_cstr); - // ref() is internal for LLDB only. - lldb_private::CommandReturnObject &ref() const; - protected: friend class SBCommandInterpreter; friend class SBOptions; @@ -119,6 +116,8 @@ protected: lldb_private::CommandReturnObject &operator*() const; private: + lldb_private::CommandReturnObject &ref() const; + std::unique_ptr m_opaque_up; }; diff --git a/gnu/llvm/lldb/include/lldb/API/SBCommunication.h b/gnu/llvm/lldb/include/lldb/API/SBCommunication.h index 84c341c0dfe..e407d859d88 100644 --- a/gnu/llvm/lldb/include/lldb/API/SBCommunication.h +++ b/gnu/llvm/lldb/include/lldb/API/SBCommunication.h @@ -75,8 +75,8 @@ private: SBCommunication(const SBCommunication &) = delete; const SBCommunication &operator=(const SBCommunication &) = delete; - lldb_private::Communication *m_opaque; - bool m_opaque_owned; + lldb_private::Communication *m_opaque = nullptr; + bool m_opaque_owned = false; }; } // namespace lldb diff --git a/gnu/llvm/lldb/include/lldb/API/SBCompileUnit.h b/gnu/llvm/lldb/include/lldb/API/SBCompileUnit.h index 0c05ef44e31..d965b9d966b 100644 --- a/gnu/llvm/lldb/include/lldb/API/SBCompileUnit.h +++ b/gnu/llvm/lldb/include/lldb/API/SBCompileUnit.h @@ -87,7 +87,7 @@ private: void reset(lldb_private::CompileUnit *lldb_object_ptr); - lldb_private::CompileUnit *m_opaque_ptr; + lldb_private::CompileUnit *m_opaque_ptr = nullptr; }; } // namespace lldb diff --git a/gnu/llvm/lldb/include/lldb/API/SBData.h b/gnu/llvm/lldb/include/lldb/API/SBData.h index 95c8086d5d4..85c8110e181 100644 --- a/gnu/llvm/lldb/include/lldb/API/SBData.h +++ b/gnu/llvm/lldb/include/lldb/API/SBData.h @@ -11,6 +11,10 @@ #include "lldb/API/SBDefines.h" +namespace lldb_private { +class ScriptInterpreter; +} // namespace lldb_private + namespace lldb { class LLDB_API SBData { @@ -147,6 +151,8 @@ private: friend class SBTarget; friend class SBValue; + friend class lldb_private::ScriptInterpreter; + lldb::DataExtractorSP m_opaque_sp; }; diff --git a/gnu/llvm/lldb/include/lldb/API/SBDebugger.h b/gnu/llvm/lldb/include/lldb/API/SBDebugger.h index b3bfa230139..ef62141f579 100644 --- a/gnu/llvm/lldb/include/lldb/API/SBDebugger.h +++ b/gnu/llvm/lldb/include/lldb/API/SBDebugger.h @@ -9,7 +9,7 @@ #ifndef LLDB_API_SBDEBUGGER_H #define LLDB_API_SBDEBUGGER_H -#include +#include #include "lldb/API/SBDefines.h" #include "lldb/API/SBPlatform.h" @@ -33,6 +33,8 @@ public: class LLDB_API SBDebugger { public: + FLAGS_ANONYMOUS_ENUM(){eBroadcastBitProgress = (1 << 0)}; + SBDebugger(); SBDebugger(const lldb::SBDebugger &rhs); @@ -41,6 +43,42 @@ public: ~SBDebugger(); + static const char *GetBroadcasterClass(); + + lldb::SBBroadcaster GetBroadcaster(); + + /// Get progress data from a SBEvent whose type is eBroadcastBitProgress. + /// + /// \param [in] event + /// The event to extract the progress information from. + /// + /// \param [out] progress_id + /// The unique integer identifier for the progress to report. + /// + /// \param [out] completed + /// The amount of work completed. If \a completed is zero, then this event + /// is a progress started event. If \a completed is equal to \a total, then + /// this event is a progress end event. Otherwise completed indicates the + /// current progress update. + /// + /// \param [out] total + /// The total amount of work units that need to be completed. If this value + /// is UINT64_MAX, then an indeterminate progress indicator should be + /// displayed. + /// + /// \param [out] is_debugger_specific + /// Set to true if this progress is specific to this debugger only. Many + /// progress events are not specific to a debugger instance, like any + /// progress events for loading information in modules since LLDB has a + /// global module cache that all debuggers use. + /// + /// \return The message for the progress. If the returned value is NULL, then + /// \a event was not a eBroadcastBitProgress event. + static const char *GetProgressFromEvent(const lldb::SBEvent &event, + uint64_t &progress_id, + uint64_t &completed, uint64_t &total, + bool &is_debugger_specific); + lldb::SBDebugger &operator=(const lldb::SBDebugger &rhs); static void Initialize(); diff --git a/gnu/llvm/lldb/include/lldb/API/SBDefines.h b/gnu/llvm/lldb/include/lldb/API/SBDefines.h index a5b639c6dc7..3ab10ad8e06 100644 --- a/gnu/llvm/lldb/include/lldb/API/SBDefines.h +++ b/gnu/llvm/lldb/include/lldb/API/SBDefines.h @@ -76,7 +76,6 @@ class LLDB_API SBThread; class LLDB_API SBThreadCollection; class LLDB_API SBThreadPlan; class LLDB_API SBTrace; -class LLDB_API SBTraceOptions; class LLDB_API SBType; class LLDB_API SBTypeCategory; class LLDB_API SBTypeEnumMember; diff --git a/gnu/llvm/lldb/include/lldb/API/SBError.h b/gnu/llvm/lldb/include/lldb/API/SBError.h index e1960ef9a98..f8289e2fcbb 100644 --- a/gnu/llvm/lldb/include/lldb/API/SBError.h +++ b/gnu/llvm/lldb/include/lldb/API/SBError.h @@ -11,6 +11,10 @@ #include "lldb/API/SBDefines.h" +namespace lldb_private { +class ScriptInterpreter; +} // namespace lldb_private + namespace lldb { class LLDB_API SBError { @@ -72,6 +76,8 @@ protected: friend class SBWatchpoint; friend class SBFile; + friend class lldb_private::ScriptInterpreter; + lldb_private::Status *get(); lldb_private::Status *operator->(); diff --git a/gnu/llvm/lldb/include/lldb/API/SBEvent.h b/gnu/llvm/lldb/include/lldb/API/SBEvent.h index a7975bf9aba..2ce1b60372b 100644 --- a/gnu/llvm/lldb/include/lldb/API/SBEvent.h +++ b/gnu/llvm/lldb/include/lldb/API/SBEvent.h @@ -11,7 +11,7 @@ #include "lldb/API/SBDefines.h" -#include +#include #include namespace lldb { @@ -79,7 +79,7 @@ protected: private: mutable lldb::EventSP m_event_sp; - mutable lldb_private::Event *m_opaque_ptr; + mutable lldb_private::Event *m_opaque_ptr = nullptr; }; } // namespace lldb diff --git a/gnu/llvm/lldb/include/lldb/API/SBExecutionContext.h b/gnu/llvm/lldb/include/lldb/API/SBExecutionContext.h index d8447aeb1a2..06ece6fbc0f 100644 --- a/gnu/llvm/lldb/include/lldb/API/SBExecutionContext.h +++ b/gnu/llvm/lldb/include/lldb/API/SBExecutionContext.h @@ -12,7 +12,7 @@ #include "lldb/API/SBDefines.h" -#include +#include #include namespace lldb { diff --git a/gnu/llvm/lldb/include/lldb/API/SBFunction.h b/gnu/llvm/lldb/include/lldb/API/SBFunction.h index bd643a62206..71b372a818e 100644 --- a/gnu/llvm/lldb/include/lldb/API/SBFunction.h +++ b/gnu/llvm/lldb/include/lldb/API/SBFunction.h @@ -74,7 +74,7 @@ private: SBFunction(lldb_private::Function *lldb_object_ptr); - lldb_private::Function *m_opaque_ptr; + lldb_private::Function *m_opaque_ptr = nullptr; }; } // namespace lldb diff --git a/gnu/llvm/lldb/include/lldb/API/SBInstruction.h b/gnu/llvm/lldb/include/lldb/API/SBInstruction.h index 7d07e168cf0..b9d781550b5 100644 --- a/gnu/llvm/lldb/include/lldb/API/SBInstruction.h +++ b/gnu/llvm/lldb/include/lldb/API/SBInstruction.h @@ -12,7 +12,7 @@ #include "lldb/API/SBData.h" #include "lldb/API/SBDefines.h" -#include +#include // There's a lot to be fixed here, but need to wait for underlying insn // implementation to be revised & settle down first. diff --git a/gnu/llvm/lldb/include/lldb/API/SBInstructionList.h b/gnu/llvm/lldb/include/lldb/API/SBInstructionList.h index ae8988004e2..b9c6c66ebd8 100644 --- a/gnu/llvm/lldb/include/lldb/API/SBInstructionList.h +++ b/gnu/llvm/lldb/include/lldb/API/SBInstructionList.h @@ -11,7 +11,7 @@ #include "lldb/API/SBDefines.h" -#include +#include namespace lldb { diff --git a/gnu/llvm/lldb/include/lldb/API/SBLaunchInfo.h b/gnu/llvm/lldb/include/lldb/API/SBLaunchInfo.h index 04ebb570768..eb4f4a65833 100644 --- a/gnu/llvm/lldb/include/lldb/API/SBLaunchInfo.h +++ b/gnu/llvm/lldb/include/lldb/API/SBLaunchInfo.h @@ -171,6 +171,14 @@ public: void SetDetachOnError(bool enable); + const char *GetScriptedProcessClassName() const; + + void SetScriptedProcessClassName(const char *class_name); + + lldb::SBStructuredData GetScriptedProcessDictionary() const; + + void SetScriptedProcessDictionary(lldb::SBStructuredData dict); + protected: friend class SBPlatform; friend class SBTarget; diff --git a/gnu/llvm/lldb/include/lldb/API/SBListener.h b/gnu/llvm/lldb/include/lldb/API/SBListener.h index 2144e7956b1..eaa8b59d0c4 100644 --- a/gnu/llvm/lldb/include/lldb/API/SBListener.h +++ b/gnu/llvm/lldb/include/lldb/API/SBListener.h @@ -100,7 +100,7 @@ private: void reset(lldb::ListenerSP listener_sp); lldb::ListenerSP m_opaque_sp; - lldb_private::Listener *m_unused_ptr; + lldb_private::Listener *m_unused_ptr = nullptr; }; } // namespace lldb diff --git a/gnu/llvm/lldb/include/lldb/API/SBMemoryRegionInfo.h b/gnu/llvm/lldb/include/lldb/API/SBMemoryRegionInfo.h index d82c7060655..122226b9a0c 100644 --- a/gnu/llvm/lldb/include/lldb/API/SBMemoryRegionInfo.h +++ b/gnu/llvm/lldb/include/lldb/API/SBMemoryRegionInfo.h @@ -73,6 +73,40 @@ public: /// region. If no name can be determined the returns nullptr. const char *GetName(); + /// Returns whether this memory region has a list of memory pages + /// that have been modified -- that are dirty. + /// + /// \return + /// True if the dirty page list is available. + bool HasDirtyMemoryPageList(); + + /// Returns the number of modified pages -- dirty pages -- in this + /// memory region. + /// + /// \return + /// The number of dirty page entries will be returned. If + /// there are no dirty pages in this memory region, 0 will + /// be returned. 0 will also be returned if the dirty page + /// list is not available for this memory region -- you must + /// use HasDirtyMemoryPageList() to check for that. + uint32_t GetNumDirtyPages(); + + /// Returns the address of a memory page that has been modified in + /// this region. + /// + /// \return + /// Returns the address for his dirty page in the list. + /// If this memory region does not have a dirty page list, + /// LLDB_INVALID_ADDRESS is returned. + addr_t GetDirtyPageAddressAtIndex(uint32_t idx); + + /// Returns the size of a memory page in this region. + /// + /// \return + /// Returns the size of the memory pages in this region, + /// or 0 if this information is unavailable. + int GetPageSize(); + bool operator==(const lldb::SBMemoryRegionInfo &rhs) const; bool operator!=(const lldb::SBMemoryRegionInfo &rhs) const; diff --git a/gnu/llvm/lldb/include/lldb/API/SBModule.h b/gnu/llvm/lldb/include/lldb/API/SBModule.h index 859eaffe89a..dd783fe4107 100644 --- a/gnu/llvm/lldb/include/lldb/API/SBModule.h +++ b/gnu/llvm/lldb/include/lldb/API/SBModule.h @@ -291,12 +291,16 @@ public: /// Get the number of global modules. static uint32_t GetNumberAllocatedModules(); + /// Remove any global modules which are no longer needed. + static void GarbageCollectAllocatedModules(); + private: friend class SBAddress; friend class SBFrame; friend class SBSection; friend class SBSymbolContext; friend class SBTarget; + friend class SBType; explicit SBModule(const lldb::ModuleSP &module_sp); diff --git a/gnu/llvm/lldb/include/lldb/API/SBPlatform.h b/gnu/llvm/lldb/include/lldb/API/SBPlatform.h index 4d251b12995..98291f18247 100644 --- a/gnu/llvm/lldb/include/lldb/API/SBPlatform.h +++ b/gnu/llvm/lldb/include/lldb/API/SBPlatform.h @@ -51,6 +51,7 @@ protected: class LLDB_API SBPlatformShellCommand { public: + SBPlatformShellCommand(const char *shell, const char *shell_command); SBPlatformShellCommand(const char *shell_command); SBPlatformShellCommand(const SBPlatformShellCommand &rhs); @@ -61,6 +62,10 @@ public: void Clear(); + const char *GetShell(); + + void SetShell(const char *shell); + const char *GetCommand(); void SetCommand(const char *shell_command); diff --git a/gnu/llvm/lldb/include/lldb/API/SBProcess.h b/gnu/llvm/lldb/include/lldb/API/SBProcess.h index a90ec2a29a3..73a8d918f4d 100644 --- a/gnu/llvm/lldb/include/lldb/API/SBProcess.h +++ b/gnu/llvm/lldb/include/lldb/API/SBProcess.h @@ -14,7 +14,7 @@ #include "lldb/API/SBProcessInfo.h" #include "lldb/API/SBQueue.h" #include "lldb/API/SBTarget.h" -#include +#include namespace lldb { @@ -224,31 +224,6 @@ public: SBStructuredData GetExtendedCrashInformation(); - /// Start Tracing with the given SBTraceOptions. - /// - /// \param[in] options - /// Class containing trace options like trace buffer size, meta - /// data buffer size, TraceType and any custom parameters - /// {formatted as a JSON Dictionary}. In case of errors in - /// formatting, an error would be reported. - /// It must be noted that tracing options such as buffer sizes - /// or other custom parameters passed maybe invalid for some - /// trace technologies. In such cases the trace implementations - /// could choose to either throw an error or could round off to - /// the nearest valid options to start tracing if the passed - /// value is not supported. To obtain the actual used trace - /// options please use the GetTraceConfig API. For the custom - /// parameters, only the parameters recognized by the target - /// would be used and others would be ignored. - /// - /// \param[out] error - /// An error explaining what went wrong. - /// - /// \return - /// A SBTrace instance, which should be used - /// to get the trace data or other trace related operations. - lldb::SBTrace StartTrace(SBTraceOptions &options, lldb::SBError &error); - uint32_t GetNumSupportedHardwareWatchpoints(lldb::SBError &error) const; /// Load a shared library into this process. @@ -301,13 +276,13 @@ public: /// paths till you find a matching library. /// /// \param[in] image_spec - /// The name of the shared library that you want to load. + /// The name of the shared library that you want to load. /// If image_spec is a relative path, the relative path will be /// appended to the search paths. /// If the image_spec is an absolute path, just the basename is used. /// /// \param[in] paths - /// A list of paths to search for the library whose basename is + /// A list of paths to search for the library whose basename is /// local_spec. /// /// \param[out] loaded_path @@ -325,7 +300,7 @@ public: /// library can't be opened. uint32_t LoadImageUsingPaths(const lldb::SBFileSpec &image_spec, SBStringList &paths, - lldb::SBFileSpec &loaded_path, + lldb::SBFileSpec &loaded_path, lldb::SBError &error); lldb::SBError UnloadImage(uint32_t image_token); @@ -395,6 +370,45 @@ public: /// valid. lldb::SBProcessInfo GetProcessInfo(); + /// Allocate memory within the process. + /// + /// This function will allocate memory in the process's address space. + /// + /// \param[in] size + /// The size of the allocation requested. + /// + /// \param[in] permissions + /// Or together any of the lldb::Permissions bits. The + /// permissions on a given memory allocation can't be changed + /// after allocation. Note that a block that isn't set writable + /// can still be written from lldb, just not by the process + /// itself. + /// + /// \param[out] error + /// An error object that gets filled in with any errors that + /// might occur when trying allocate. + /// + /// \return + /// The address of the allocated buffer in the process, or + /// LLDB_INVALID_ADDRESS if the allocation failed. + lldb::addr_t AllocateMemory(size_t size, uint32_t permissions, + lldb::SBError &error); + + /// Deallocate memory in the process. + /// + /// This function will deallocate memory in the process's address + /// space that was allocated with AllocateMemory. + /// + /// \param[in] ptr + /// A return value from AllocateMemory, pointing to the memory you + /// want to deallocate. + /// + /// \return + /// An error object describes any errors that occurred while + /// deallocating. + /// + lldb::SBError DeallocateMemory(lldb::addr_t ptr); + protected: friend class SBAddress; friend class SBBreakpoint; diff --git a/gnu/llvm/lldb/include/lldb/API/SBProcessInfo.h b/gnu/llvm/lldb/include/lldb/API/SBProcessInfo.h index 0cc5f6a2f9f..36fae9e842a 100644 --- a/gnu/llvm/lldb/include/lldb/API/SBProcessInfo.h +++ b/gnu/llvm/lldb/include/lldb/API/SBProcessInfo.h @@ -50,6 +50,9 @@ public: lldb::pid_t GetParentProcessID(); + /// Return the target triple (arch-vendor-os) for the described process. + const char *GetTriple(); + private: friend class SBProcess; diff --git a/gnu/llvm/lldb/include/lldb/API/SBReproducer.h b/gnu/llvm/lldb/include/lldb/API/SBReproducer.h index 78044e9acbc..ecf28d6f0e1 100644 --- a/gnu/llvm/lldb/include/lldb/API/SBReproducer.h +++ b/gnu/llvm/lldb/include/lldb/API/SBReproducer.h @@ -11,8 +11,32 @@ #include "lldb/API/SBDefines.h" +namespace lldb_private { +namespace repro { +struct ReplayOptions; +} +} // namespace lldb_private + namespace lldb { +class LLDB_API SBReplayOptions { +public: + SBReplayOptions(); + SBReplayOptions(const SBReplayOptions &rhs); + ~SBReplayOptions(); + + SBReplayOptions &operator=(const SBReplayOptions &rhs); + + void SetVerify(bool verify); + bool GetVerify() const; + + void SetCheckVersion(bool check); + bool GetCheckVersion() const; + +private: + std::unique_ptr m_opaque_up; +}; + /// The SBReproducer class is special because it bootstraps the capture and /// replay of SB API calls. As a result we cannot rely on any other SB objects /// in the interface or implementation of this class. @@ -22,7 +46,9 @@ public: static const char *Capture(const char *path); static const char *Replay(const char *path); static const char *Replay(const char *path, bool skip_version_check); + static const char *Replay(const char *path, const SBReplayOptions &options); static const char *PassiveReplay(const char *path); + static const char *Finalize(const char *path); static const char *GetPath(); static bool SetAutoGenerate(bool b); static bool Generate(); diff --git a/gnu/llvm/lldb/include/lldb/API/SBSourceManager.h b/gnu/llvm/lldb/include/lldb/API/SBSourceManager.h index c8302dbda3c..e95cfa66e1c 100644 --- a/gnu/llvm/lldb/include/lldb/API/SBSourceManager.h +++ b/gnu/llvm/lldb/include/lldb/API/SBSourceManager.h @@ -11,7 +11,7 @@ #include "lldb/API/SBDefines.h" -#include +#include namespace lldb { diff --git a/gnu/llvm/lldb/include/lldb/API/SBStream.h b/gnu/llvm/lldb/include/lldb/API/SBStream.h index f44b87bb4c9..291109cbe93 100644 --- a/gnu/llvm/lldb/include/lldb/API/SBStream.h +++ b/gnu/llvm/lldb/include/lldb/API/SBStream.h @@ -9,7 +9,7 @@ #ifndef LLDB_API_SBSTREAM_H #define LLDB_API_SBSTREAM_H -#include +#include #include "lldb/API/SBDefines.h" @@ -72,6 +72,7 @@ protected: friend class SBFunction; friend class SBInstruction; friend class SBInstructionList; + friend class SBLaunchInfo; friend class SBLineEntry; friend class SBMemoryRegionInfo; friend class SBModule; @@ -104,7 +105,7 @@ private: SBStream(const SBStream &) = delete; const SBStream &operator=(const SBStream &) = delete; std::unique_ptr m_opaque_up; - bool m_is_file; + bool m_is_file = false; }; } // namespace lldb diff --git a/gnu/llvm/lldb/include/lldb/API/SBStructuredData.h b/gnu/llvm/lldb/include/lldb/API/SBStructuredData.h index 44a86bdabe2..07075abbf1d 100644 --- a/gnu/llvm/lldb/include/lldb/API/SBStructuredData.h +++ b/gnu/llvm/lldb/include/lldb/API/SBStructuredData.h @@ -21,7 +21,7 @@ public: SBStructuredData(const lldb::SBStructuredData &rhs); SBStructuredData(const lldb::EventSP &event_sp); - + SBStructuredData(lldb_private::StructuredDataImpl *impl); ~SBStructuredData(); @@ -34,6 +34,8 @@ public: lldb::SBError SetFromJSON(lldb::SBStream &stream); + lldb::SBError SetFromJSON(const char *json); + void Clear(); lldb::SBError GetAsJSON(lldb::SBStream &stream) const; @@ -42,7 +44,7 @@ public: /// Return the type of data in this data structure lldb::StructuredDataType GetType() const; - + /// Return the size (i.e. number of elements) in this data structure /// if it is an array or dictionary type. For other types, 0 will be // returned. @@ -51,7 +53,7 @@ public: /// Fill keys with the keys in this object and return true if this data /// structure is a dictionary. Returns false otherwise. bool GetKeys(lldb::SBStringList &keys) const; - + /// Return the value corresponding to a key if this data structure /// is a dictionary type. lldb::SBStructuredData GetValueForKey(const char *key) const; @@ -88,7 +90,7 @@ public: size_t GetStringValue(char *dst, size_t dst_len) const; protected: - friend class SBTraceOptions; + friend class SBLaunchInfo; friend class SBDebugger; friend class SBTarget; friend class SBProcess; @@ -97,6 +99,7 @@ protected: friend class SBBreakpoint; friend class SBBreakpointLocation; friend class SBBreakpointName; + friend class SBTrace; StructuredDataImplUP m_impl_up; }; diff --git a/gnu/llvm/lldb/include/lldb/API/SBSymbol.h b/gnu/llvm/lldb/include/lldb/API/SBSymbol.h index 66f73c82a73..5935ccfed02 100644 --- a/gnu/llvm/lldb/include/lldb/API/SBSymbol.h +++ b/gnu/llvm/lldb/include/lldb/API/SBSymbol.h @@ -78,7 +78,7 @@ private: void SetSymbol(lldb_private::Symbol *lldb_object_ptr); - lldb_private::Symbol *m_opaque_ptr; + lldb_private::Symbol *m_opaque_ptr = nullptr; }; } // namespace lldb diff --git a/gnu/llvm/lldb/include/lldb/API/SBTarget.h b/gnu/llvm/lldb/include/lldb/API/SBTarget.h index fad842c9cb1..5a6908f040b 100644 --- a/gnu/llvm/lldb/include/lldb/API/SBTarget.h +++ b/gnu/llvm/lldb/include/lldb/API/SBTarget.h @@ -560,6 +560,12 @@ public: uint32_t column, lldb::addr_t offset, SBFileSpecList &module_list); + lldb::SBBreakpoint + BreakpointCreateByLocation(const lldb::SBFileSpec &file_spec, uint32_t line, + uint32_t column, lldb::addr_t offset, + SBFileSpecList &module_list, + bool move_to_nearest_code); + lldb::SBBreakpoint BreakpointCreateByName(const char *symbol_name, const char *module_name = nullptr); @@ -637,7 +643,7 @@ public: lldb::SBBreakpoint BreakpointCreateByAddress(addr_t address); lldb::SBBreakpoint BreakpointCreateBySBAddress(SBAddress &address); - + /// Create a breakpoint using a scripted resolver. /// /// \param[in] class_name @@ -645,16 +651,16 @@ public: /// /// \param[in] extra_args /// This is an SBStructuredData object that will get passed to the - /// constructor of the class in class_name. You can use this to - /// reuse the same class, parametrizing with entries from this + /// constructor of the class in class_name. You can use this to + /// reuse the same class, parametrizing with entries from this /// dictionary. /// /// \param module_list - /// If this is non-empty, this will be used as the module filter in the + /// If this is non-empty, this will be used as the module filter in the /// SearchFilter created for this breakpoint. /// /// \param file_list - /// If this is non-empty, this will be used as the comp unit filter in the + /// If this is non-empty, this will be used as the comp unit filter in the /// SearchFilter created for this breakpoint. /// /// \return @@ -828,10 +834,27 @@ public: lldb::addr_t GetStackRedZoneSize(); + bool IsLoaded(const lldb::SBModule &module) const; + lldb::SBLaunchInfo GetLaunchInfo() const; void SetLaunchInfo(const lldb::SBLaunchInfo &launch_info); + /// Get a \a SBTrace object the can manage the processor trace information of + /// this target. + /// + /// \return + /// The trace object. The returned SBTrace object might not be valid, so it + /// should be checked with a call to "bool SBTrace::IsValid()". + lldb::SBTrace GetTrace(); + + /// Create a \a Trace object for the current target using the using the + /// default supported tracing technology for this process. + /// + /// \param[out] error + /// An error if a Trace already exists or the trace couldn't be created. + lldb::SBTrace CreateTrace(SBError &error); + protected: friend class SBAddress; friend class SBBlock; diff --git a/gnu/llvm/lldb/include/lldb/API/SBThread.h b/gnu/llvm/lldb/include/lldb/API/SBThread.h index 894120c6d98..ac1b8407a22 100644 --- a/gnu/llvm/lldb/include/lldb/API/SBThread.h +++ b/gnu/llvm/lldb/include/lldb/API/SBThread.h @@ -11,7 +11,7 @@ #include "lldb/API/SBDefines.h" -#include +#include namespace lldb { @@ -66,6 +66,9 @@ public: /// eStopReasonSignal 1 unix signal number /// eStopReasonException N exception data /// eStopReasonExec 0 + /// eStopReasonFork 1 pid of the child process + /// eStopReasonVFork 1 pid of the child process + /// eStopReasonVForkDone 0 /// eStopReasonPlanComplete 0 uint64_t GetStopReasonDataAtIndex(uint32_t idx); @@ -217,6 +220,7 @@ private: friend class lldb_private::QueueImpl; friend class SBQueueItem; friend class SBThreadPlan; + friend class SBTrace; void SetThread(const lldb::ThreadSP &lldb_object_sp); diff --git a/gnu/llvm/lldb/include/lldb/API/SBThreadPlan.h b/gnu/llvm/lldb/include/lldb/API/SBThreadPlan.h index 8f16f4f5c4d..0d166b35ae4 100644 --- a/gnu/llvm/lldb/include/lldb/API/SBThreadPlan.h +++ b/gnu/llvm/lldb/include/lldb/API/SBThreadPlan.h @@ -11,14 +11,12 @@ #include "lldb/API/SBDefines.h" -#include +#include namespace lldb { class LLDB_API SBThreadPlan { - friend class lldb_private::ThreadPlan; - public: SBThreadPlan(); @@ -60,6 +58,9 @@ public: /// eStopReasonSignal 1 unix signal number /// eStopReasonException N exception data /// eStopReasonExec 0 + /// eStopReasonFork 1 pid of the child process + /// eStopReasonVFork 1 pid of the child process + /// eStopReasonVForkDone 0 /// eStopReasonPlanComplete 0 uint64_t GetStopReasonDataAtIndex(uint32_t idx); @@ -77,6 +78,10 @@ public: bool IsValid(); + bool GetStopOthers(); + + void SetStopOthers(bool stop_others); + // This section allows an SBThreadPlan to push another of the common types of // plans... SBThreadPlan QueueThreadPlanForStepOverRange(SBAddress &start_address, @@ -117,10 +122,11 @@ private: friend class lldb_private::QueueImpl; friend class SBQueueItem; - lldb_private::ThreadPlan *get(); + lldb::ThreadPlanSP GetSP() const { return m_opaque_wp.lock(); } + lldb_private::ThreadPlan *get() const { return GetSP().get(); } void SetThreadPlan(const lldb::ThreadPlanSP &lldb_object_sp); - lldb::ThreadPlanSP m_opaque_sp; + lldb::ThreadPlanWP m_opaque_wp; }; } // namespace lldb diff --git a/gnu/llvm/lldb/include/lldb/API/SBTrace.h b/gnu/llvm/lldb/include/lldb/API/SBTrace.h index 053abaeada1..1685caaf4ef 100644 --- a/gnu/llvm/lldb/include/lldb/API/SBTrace.h +++ b/gnu/llvm/lldb/include/lldb/API/SBTrace.h @@ -18,97 +18,88 @@ namespace lldb { class LLDB_API SBTrace { public: + /// Default constructor for an invalid Trace object. SBTrace(); - /// Obtain the trace data as raw bytes. + + SBTrace(const lldb::TraceSP &trace_sp); + + /// \return + /// A description of the parameters to use for the \a SBTrace::Start + /// method, or \b null if the object is invalid. + const char *GetStartConfigurationHelp(); + + /// Start tracing all current and future threads in a live process using a + /// provided configuration. This is referred as "process tracing" in the + /// documentation. /// - /// \param[out] error - /// An error explaining what went wrong. + /// This is equivalent to the command "process trace start". /// - /// \param[in] buf - /// Buffer to write the trace data to. + /// This operation fails if it is invoked twice in a row without + /// first stopping the process trace with \a SBTrace::Stop(). /// - /// \param[in] size - /// The size of the buffer used to read the data. This is - /// also the size of the data intended to read. It is also - /// possible to partially read the trace data for some trace - /// technologies by specifying a smaller buffer. + /// If a thread is already being traced explicitly, e.g. with \a + /// SBTrace::Start(const SBThread &thread, const SBStructuredData + /// &configuration), it is left unaffected by this operation. /// - /// \param[in] offset - /// The start offset to begin reading the trace data. + /// \param[in] configuration + /// Dictionary object with custom fields for the corresponding trace + /// technology. /// - /// \param[in] thread_id - /// Tracing could be started for the complete process or a - /// single thread, in the first case the traceid obtained would - /// map to all the threads existing within the process and the - /// ones spawning later. The thread_id parameter can be used in - /// such a scenario to select the trace data for a specific - /// thread. + /// Full details for the trace start parameters that can be set can be + /// retrieved by calling \a SBTrace::GetStartConfigurationHelp(). /// /// \return - /// The size of the trace data effectively read by the API call. - size_t GetTraceData(SBError &error, void *buf, size_t size, size_t offset = 0, - lldb::tid_t thread_id = LLDB_INVALID_THREAD_ID); - - /// Obtain any meta data as raw bytes for the tracing instance. - /// The input parameter definition is similar to the previous - /// function. - size_t GetMetaData(SBError &error, void *buf, size_t size, size_t offset = 0, - lldb::tid_t thread_id = LLDB_INVALID_THREAD_ID); + /// An error explaining any failures. + SBError Start(const SBStructuredData &configuration); - /// Stop the tracing instance. Stopping the trace will also - /// lead to deletion of any gathered trace data. - /// - /// \param[out] error - /// An error explaining what went wrong. - /// - /// \param[in] thread_id - /// The trace id could map to a tracing instance for a thread - /// or could also map to a group of threads being traced with - /// the same trace options. A thread_id is normally optional - /// except in the case of tracing a complete process and tracing - /// needs to switched off on a particular thread. - /// A situation could occur where initially a thread (lets say - /// thread A) is being individually traced with a particular - /// trace id and then tracing is started on the complete - /// process, in this case thread A will continue without any - /// change. All newly spawned threads would be traced with the - /// trace id of the process. - /// Now if the StopTrace API is called for the whole process, - /// thread A will not be stopped and must be stopped separately. - void StopTrace(SBError &error, - lldb::tid_t thread_id = LLDB_INVALID_THREAD_ID); + /// Start tracing a specific thread in a live process using a provided + /// configuration. This is referred as "thread tracing" in the documentation. + /// + /// This is equivalent to the command "thread trace start". + /// + /// If the thread is already being traced by a "process tracing" operation, + /// e.g. with \a SBTrace::Start(const SBStructuredData &configuration), this + /// operation fails. + /// + /// \param[in] configuration + /// Dictionary object with custom fields for the corresponding trace + /// technology. + /// + /// Full details for the trace start parameters that can be set can be + /// retrieved by calling \a SBTrace::GetStartConfigurationHelp(). + /// + /// \return + /// An error explaining any failures. + SBError Start(const SBThread &thread, const SBStructuredData &configuration); - /// Get the trace configuration being used for the trace instance. - /// The threadid in the SBTraceOptions needs to be set when the - /// configuration used by a specific thread is being requested. + /// Stop tracing all threads in a live process. /// - /// \param[out] options - /// The trace options actually used by the trace instance - /// would be filled by the API. + /// If a "process tracing" operation is active, e.g. \a SBTrace::Start(const + /// SBStructuredData &configuration), this effectively prevents future threads + /// from being traced. /// - /// \param[out] error - /// An error explaining what went wrong. - void GetTraceConfig(SBTraceOptions &options, SBError &error); + /// This is equivalent to the command "process trace stop". + /// + /// \return + /// An error explaining any failures. + SBError Stop(); - lldb::user_id_t GetTraceUID(); + /// Stop tracing a specific thread in a live process regardless of whether the + /// thread was traced explicitly or as part of a "process tracing" operation. + /// + /// This is equivalent to the command "thread trace stop". + /// + /// \return + /// An error explaining any failures. + SBError Stop(const SBThread &thread); explicit operator bool() const; bool IsValid(); protected: - typedef std::shared_ptr TraceImplSP; - - friend class SBProcess; - - void SetTraceUID(lldb::user_id_t uid); - - TraceImplSP m_trace_impl_sp; - - lldb::ProcessSP GetSP() const; - - void SetSP(const ProcessSP &process_sp); - + lldb::TraceSP m_opaque_sp; + /// deprecated lldb::ProcessWP m_opaque_wp; }; } // namespace lldb diff --git a/gnu/llvm/lldb/include/lldb/API/SBType.h b/gnu/llvm/lldb/include/lldb/API/SBType.h index b0af4335119..529b4d0eeff 100644 --- a/gnu/llvm/lldb/include/lldb/API/SBType.h +++ b/gnu/llvm/lldb/include/lldb/API/SBType.h @@ -131,6 +131,8 @@ public: bool IsAnonymousType(); + bool IsScopedEnumerationType(); + lldb::SBType GetPointerType(); lldb::SBType GetPointeeType(); @@ -150,6 +152,9 @@ public: lldb::SBType GetVectorElementType(); lldb::SBType GetCanonicalType(); + + lldb::SBType GetEnumerationIntegerType(); + // Get the "lldb::BasicType" enumeration for a type. If a type is not a basic // type eBasicTypeInvalid will be returned lldb::BasicType GetBasicType(); @@ -185,6 +190,8 @@ public: lldb::SBTypeMemberFunction GetMemberFunctionAtIndex(uint32_t idx); + lldb::SBModule GetModule(); + const char *GetName(); const char *GetDisplayTypeName(); diff --git a/gnu/llvm/lldb/include/lldb/Breakpoint/Breakpoint.h b/gnu/llvm/lldb/include/lldb/Breakpoint/Breakpoint.h index d29d21070fd..f2e2a0d2278 100644 --- a/gnu/llvm/lldb/include/lldb/Breakpoint/Breakpoint.h +++ b/gnu/llvm/lldb/include/lldb/Breakpoint/Breakpoint.h @@ -20,6 +20,7 @@ #include "lldb/Breakpoint/BreakpointName.h" #include "lldb/Breakpoint/BreakpointOptions.h" #include "lldb/Breakpoint/Stoppoint.h" +#include "lldb/Breakpoint/StoppointHitCounter.h" #include "lldb/Core/SearchFilter.h" #include "lldb/Utility/Event.h" #include "lldb/Utility/StringList.h" @@ -480,16 +481,16 @@ public: /// Meant to be used by the BreakpointLocation class. /// /// \return - /// A pointer to this breakpoint's BreakpointOptions. - BreakpointOptions *GetOptions(); + /// A reference to this breakpoint's BreakpointOptions. + BreakpointOptions &GetOptions(); /// Returns the BreakpointOptions structure set at the breakpoint level. /// /// Meant to be used by the BreakpointLocation class. /// /// \return - /// A pointer to this breakpoint's BreakpointOptions. - const BreakpointOptions *GetOptions() const; + /// A reference to this breakpoint's BreakpointOptions. + const BreakpointOptions &GetOptions() const; /// Invoke the callback action when the breakpoint is hit. /// @@ -544,7 +545,7 @@ public: /// if the condition says to stop and false otherwise. /// void SetPrecondition(lldb::BreakpointPreconditionSP precondition_sp) { - m_precondition_sp = precondition_sp; + m_precondition_sp = std::move(precondition_sp); } bool EvaluatePrecondition(StoppointCallbackContext &context); @@ -616,21 +617,6 @@ protected: void DecrementIgnoreCount(); - // BreakpointLocation::IgnoreCountShouldStop & - // Breakpoint::IgnoreCountShouldStop can only be called once per stop, and - // BreakpointLocation::IgnoreCountShouldStop should be tested first, and if - // it returns false we should continue, otherwise we should test - // Breakpoint::IgnoreCountShouldStop. - - bool IgnoreCountShouldStop(); - - void IncrementHitCount() { m_hit_count++; } - - void DecrementHitCount() { - assert(m_hit_count > 0); - m_hit_count--; - } - private: // To call from CopyFromBreakpoint. Breakpoint(Target &new_target, const Breakpoint &bp_to_copy_from); @@ -654,16 +640,17 @@ private: // to skip certain breakpoint hits. For instance, exception breakpoints use // this to limit the stop to certain exception classes, while leaving the // condition & callback free for user specification. - std::unique_ptr - m_options_up; // Settable breakpoint options + BreakpointOptions m_options; // Settable breakpoint options BreakpointLocationList m_locations; // The list of locations currently found for this breakpoint. std::string m_kind_description; bool m_resolve_indirect_symbols; - uint32_t m_hit_count; // Number of times this breakpoint/watchpoint has been - // hit. This is kept - // separately from the locations hit counts, since locations can go away when - // their backing library gets unloaded, and we would lose hit counts. + + /// Number of times this breakpoint has been hit. This is kept separately + /// from the locations hit counts, since locations can go away when their + /// backing library gets unloaded, and we would lose hit counts. + StoppointHitCounter m_hit_counter; + BreakpointName::Permissions m_permissions; void SendBreakpointChangedEvent(lldb::BreakpointEventType eventKind); diff --git a/gnu/llvm/lldb/include/lldb/Breakpoint/BreakpointLocation.h b/gnu/llvm/lldb/include/lldb/Breakpoint/BreakpointLocation.h index 3fc571eaa29..a6d1232162f 100644 --- a/gnu/llvm/lldb/include/lldb/Breakpoint/BreakpointLocation.h +++ b/gnu/llvm/lldb/include/lldb/Breakpoint/BreakpointLocation.h @@ -13,7 +13,7 @@ #include #include "lldb/Breakpoint/BreakpointOptions.h" -#include "lldb/Breakpoint/StoppointLocation.h" +#include "lldb/Breakpoint/StoppointHitCounter.h" #include "lldb/Core/Address.h" #include "lldb/Utility/UserID.h" #include "lldb/lldb-private.h" @@ -35,15 +35,14 @@ namespace lldb_private { /// be useful if you've set options on the locations. class BreakpointLocation - : public std::enable_shared_from_this, - public StoppointLocation { + : public std::enable_shared_from_this { public: - ~BreakpointLocation() override; + ~BreakpointLocation(); /// Gets the load address for this breakpoint location \return /// Returns breakpoint location load address, \b /// LLDB_INVALID_ADDRESS if not yet set. - lldb::addr_t GetLoadAddress() const override; + lldb::addr_t GetLoadAddress() const; /// Gets the Address for this breakpoint location \return /// Returns breakpoint location Address. @@ -63,7 +62,7 @@ public: /// \return /// \b true if this breakpoint location thinks we should stop, /// \b false otherwise. - bool ShouldStop(StoppointCallbackContext *context) override; + bool ShouldStop(StoppointCallbackContext *context); // The next section deals with various breakpoint options. @@ -85,11 +84,14 @@ public: /// \b true if the breakpoint is set to auto-continue, \b false if not. bool IsAutoContinue() const; + /// Return the current Hit Count. + uint32_t GetHitCount() const { return m_hit_counter.GetValue(); } + /// Return the current Ignore Count. /// /// \return /// The number of breakpoint hits to be ignored. - uint32_t GetIgnoreCount(); + uint32_t GetIgnoreCount() const; /// Set the breakpoint to ignore the next \a count breakpoint hits. /// @@ -192,7 +194,7 @@ public: void GetDescription(Stream *s, lldb::DescriptionLevel level); /// Standard "Dump" method. At present it does nothing. - void Dump(Stream *s) const override; + void Dump(Stream *s) const; /// Use this to set location specific breakpoint options. /// @@ -200,8 +202,8 @@ public: /// hasn't been done already /// /// \return - /// A pointer to the breakpoint options. - BreakpointOptions *GetLocationOptions(); + /// A reference to the breakpoint options. + BreakpointOptions &GetLocationOptions(); /// Use this to access breakpoint options from this breakpoint location. /// This will return the options that have a setting for the specified @@ -212,10 +214,10 @@ public: /// \return /// A pointer to the containing breakpoint's options if this /// location doesn't have its own copy. - const BreakpointOptions *GetOptionsSpecifyingKind( - BreakpointOptions::OptionKind kind) const; + const BreakpointOptions & + GetOptionsSpecifyingKind(BreakpointOptions::OptionKind kind) const; - bool ValidForThisThread(Thread *thread); + bool ValidForThisThread(Thread &thread); /// Invoke the callback action when the breakpoint is hit. /// @@ -228,6 +230,12 @@ public: /// \b true if the target should stop at this breakpoint and \b /// false not. bool InvokeCallback(StoppointCallbackContext *context); + + /// Report whether the callback for this location is synchronous or not. + /// + /// \return + /// \b true if the callback is synchronous and \b false if not. + bool IsCallbackSynchronous(); /// Returns whether we should resolve Indirect functions in setting the /// breakpoint site for this location. @@ -268,6 +276,9 @@ public: /// \b true or \b false as given in the description above. bool EquivalentToLocation(BreakpointLocation &location); + /// Returns the breakpoint location ID. + lldb::break_id_t GetID() const { return m_loc_id; } + protected: friend class BreakpointSite; friend class BreakpointLocationList; @@ -286,6 +297,10 @@ protected: void DecrementIgnoreCount(); + /// BreakpointLocation::IgnoreCountShouldStop can only be called once + /// per stop. This method checks first against the loc and then the owner. + /// It also takes care of decrementing the ignore counters. + /// If it returns false we should continue, otherwise stop. bool IgnoreCountShouldStop(); private: @@ -338,6 +353,9 @@ private: /// multiple processes. size_t m_condition_hash; ///< For testing whether the condition source code ///changed. + lldb::break_id_t m_loc_id; ///< Breakpoint location ID. + StoppointHitCounter m_hit_counter; ///< Number of times this breakpoint + /// location has been hit. void SetShouldResolveIndirectFunctions(bool do_resolve) { m_should_resolve_indirect_functions = do_resolve; diff --git a/gnu/llvm/lldb/include/lldb/Breakpoint/BreakpointLocationCollection.h b/gnu/llvm/lldb/include/lldb/Breakpoint/BreakpointLocationCollection.h index ffdb81e363e..34bd3098648 100644 --- a/gnu/llvm/lldb/include/lldb/Breakpoint/BreakpointLocationCollection.h +++ b/gnu/llvm/lldb/include/lldb/Breakpoint/BreakpointLocationCollection.h @@ -136,7 +136,7 @@ public: /// return /// \b true if the collection contains at least one location that /// would be valid for this thread, false otherwise. - bool ValidForThisThread(Thread *thread); + bool ValidForThisThread(Thread &thread); /// Tell whether ALL the breakpoints in the location collection are internal. /// diff --git a/gnu/llvm/lldb/include/lldb/Breakpoint/BreakpointOptions.h b/gnu/llvm/lldb/include/lldb/Breakpoint/BreakpointOptions.h index 615b4eb77be..7b78265920a 100644 --- a/gnu/llvm/lldb/include/lldb/Breakpoint/BreakpointOptions.h +++ b/gnu/llvm/lldb/include/lldb/Breakpoint/BreakpointOptions.h @@ -43,15 +43,13 @@ public: | eCondition | eAutoContinue) }; struct CommandData { - CommandData() - : user_source(), script_source(), - interpreter(lldb::eScriptLanguageNone), stop_on_error(true) {} + CommandData() : user_source(), script_source() {} CommandData(const StringList &user_source, lldb::ScriptLanguage interp) : user_source(user_source), script_source(), interpreter(interp), stop_on_error(true) {} - ~CommandData() = default; + virtual ~CommandData() = default; static const char *GetSerializationKey() { return "BKPTCMDData"; } @@ -63,9 +61,10 @@ public: StringList user_source; std::string script_source; - enum lldb::ScriptLanguage - interpreter; // eScriptLanguageNone means command interpreter. - bool stop_on_error; + enum lldb::ScriptLanguage interpreter = + lldb::eScriptLanguageNone; // eScriptLanguageNone means command + // interpreter. + bool stop_on_error = true; private: enum class OptionNames : uint32_t { diff --git a/gnu/llvm/lldb/include/lldb/Breakpoint/BreakpointResolver.h b/gnu/llvm/lldb/include/lldb/Breakpoint/BreakpointResolver.h index d067b1eea6f..7aa43b9f45d 100644 --- a/gnu/llvm/lldb/include/lldb/Breakpoint/BreakpointResolver.h +++ b/gnu/llvm/lldb/include/lldb/Breakpoint/BreakpointResolver.h @@ -204,7 +204,8 @@ protected: /// filter the results to find the first breakpoint >= (line, column). void SetSCMatchesByLine(SearchFilter &filter, SymbolContextList &sc_list, bool skip_prologue, llvm::StringRef log_ident, - uint32_t line = 0, uint32_t column = 0); + uint32_t line = 0, + llvm::Optional column = llvm::None); void SetSCMatchesByLine(SearchFilter &, SymbolContextList &, bool, const char *) = delete; diff --git a/gnu/llvm/lldb/include/lldb/Breakpoint/BreakpointResolverFileLine.h b/gnu/llvm/lldb/include/lldb/Breakpoint/BreakpointResolverFileLine.h index 222fc6fcd45..bd8d0394d4d 100644 --- a/gnu/llvm/lldb/include/lldb/Breakpoint/BreakpointResolverFileLine.h +++ b/gnu/llvm/lldb/include/lldb/Breakpoint/BreakpointResolverFileLine.h @@ -10,6 +10,7 @@ #define LLDB_BREAKPOINT_BREAKPOINTRESOLVERFILELINE_H #include "lldb/Breakpoint/BreakpointResolver.h" +#include "lldb/Core/SourceLocationSpec.h" namespace lldb_private { @@ -21,10 +22,8 @@ namespace lldb_private { class BreakpointResolverFileLine : public BreakpointResolver { public: BreakpointResolverFileLine(const lldb::BreakpointSP &bkpt, - const FileSpec &resolver, - uint32_t line_no, uint32_t column, - lldb::addr_t m_offset, bool check_inlines, - bool skip_prologue, bool exact_match); + lldb::addr_t offset, bool skip_prologue, + const SourceLocationSpec &location_spec); static BreakpointResolver * CreateFromStructuredData(const lldb::BreakpointSP &bkpt, @@ -60,13 +59,8 @@ protected: void FilterContexts(SymbolContextList &sc_list, bool is_relative); friend class Breakpoint; - FileSpec m_file_spec; ///< This is the file spec we are looking for. - uint32_t m_line_number; ///< This is the line number that we are looking for. - uint32_t m_column; ///< This is the column that we are looking for. - bool m_inlines; ///< This determines whether the resolver looks for inlined - ///< functions or not. + SourceLocationSpec m_location_spec; bool m_skip_prologue; - bool m_exact_match; private: BreakpointResolverFileLine(const BreakpointResolverFileLine &) = delete; diff --git a/gnu/llvm/lldb/include/lldb/Breakpoint/BreakpointSite.h b/gnu/llvm/lldb/include/lldb/Breakpoint/BreakpointSite.h index 5ce17f511db..e4c850206fd 100644 --- a/gnu/llvm/lldb/include/lldb/Breakpoint/BreakpointSite.h +++ b/gnu/llvm/lldb/include/lldb/Breakpoint/BreakpointSite.h @@ -14,7 +14,8 @@ #include "lldb/Breakpoint/BreakpointLocationCollection.h" -#include "lldb/Breakpoint/StoppointLocation.h" +#include "lldb/Breakpoint/StoppointSite.h" +#include "lldb/Utility/LLDBAssert.h" #include "lldb/Utility/UserID.h" #include "lldb/lldb-forward.h" @@ -32,7 +33,7 @@ namespace lldb_private { /// by the process. class BreakpointSite : public std::enable_shared_from_this, - public StoppointLocation { + public StoppointSite { public: enum Type { eSoftware, // Breakpoint opcode has been written to memory and @@ -60,8 +61,6 @@ public: /// Sets the trap opcode bool SetTrapOpcode(const uint8_t *trap_opcode, uint32_t trap_opcode_size); - void SetHardwareIndex(uint32_t index) override; - /// Gets the original instruction bytes that were overwritten by the trap uint8_t *GetSavedOpcodeBytes(); @@ -149,7 +148,7 @@ public: /// return /// \b true if the collection contains at least one location that /// would be valid for this thread, false otherwise. - bool ValidForThisThread(Thread *thread); + bool ValidForThisThread(Thread &thread); /// Print a description of this breakpoint site to the stream \a s. /// GetDescription tells you about the breakpoint site's owners. Use @@ -184,6 +183,12 @@ public: /// \b false otherwise. bool IsInternal() const; + bool IsHardware() const override { + lldbassert(BreakpointSite::Type::eHardware == GetType() || + !HardwareRequired()); + return BreakpointSite::Type::eHardware == GetType(); + } + BreakpointSite::Type GetType() const { return m_type; } void SetType(BreakpointSite::Type type) { m_type = type; } diff --git a/gnu/llvm/lldb/include/lldb/Breakpoint/Stoppoint.h b/gnu/llvm/lldb/include/lldb/Breakpoint/Stoppoint.h index 36df77c4e91..6bb1b6a705b 100644 --- a/gnu/llvm/lldb/include/lldb/Breakpoint/Stoppoint.h +++ b/gnu/llvm/lldb/include/lldb/Breakpoint/Stoppoint.h @@ -33,7 +33,7 @@ public: void SetID(lldb::break_id_t bid); protected: - lldb::break_id_t m_bid; + lldb::break_id_t m_bid = LLDB_INVALID_BREAK_ID; private: // For Stoppoint only diff --git a/gnu/llvm/lldb/include/lldb/Breakpoint/StoppointCallbackContext.h b/gnu/llvm/lldb/include/lldb/Breakpoint/StoppointCallbackContext.h index db02ddd494f..6da8d10d3f3 100644 --- a/gnu/llvm/lldb/include/lldb/Breakpoint/StoppointCallbackContext.h +++ b/gnu/llvm/lldb/include/lldb/Breakpoint/StoppointCallbackContext.h @@ -37,13 +37,14 @@ public: void Clear(); // Member variables - Event *event; // This is the event, the callback can modify this to indicate - // the meaning of the breakpoint hit + Event *event = nullptr; // This is the event, the callback can modify this to + // indicate the meaning of the breakpoint hit ExecutionContextRef exe_ctx_ref; // This tells us where we have stopped, what thread. - bool is_synchronous; // Is the callback being executed synchronously with the - // breakpoint, - // or asynchronously as the event is retrieved? + bool is_synchronous = + false; // Is the callback being executed synchronously with the + // breakpoint, + // or asynchronously as the event is retrieved? }; } // namespace lldb_private diff --git a/gnu/llvm/lldb/include/lldb/Breakpoint/StoppointHitCounter.h b/gnu/llvm/lldb/include/lldb/Breakpoint/StoppointHitCounter.h new file mode 100644 index 00000000000..ae9ec6b3c80 --- /dev/null +++ b/gnu/llvm/lldb/include/lldb/Breakpoint/StoppointHitCounter.h @@ -0,0 +1,43 @@ +//===-- StoppointHitCounter.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_BREAKPOINT_STOPPOINT_HIT_COUNTER_H +#define LLDB_BREAKPOINT_STOPPOINT_HIT_COUNTER_H + +#include +#include +#include + +#include "lldb/Utility/LLDBAssert.h" + +namespace lldb_private { + +class StoppointHitCounter { +public: + uint32_t GetValue() const { return m_hit_count; } + + void Increment(uint32_t difference = 1) { + lldbassert(std::numeric_limits::max() - m_hit_count >= difference); + m_hit_count += difference; + } + + void Decrement(uint32_t difference = 1) { + lldbassert(m_hit_count >= difference); + m_hit_count -= difference; + } + + void Reset() { m_hit_count = 0; } + +private: + /// Number of times this breakpoint/watchpoint has been hit. + uint32_t m_hit_count = 0; +}; + +} // namespace lldb_private + +#endif // LLDB_BREAKPOINT_STOPPOINT_HIT_COUNTER_H diff --git a/gnu/llvm/lldb/include/lldb/Breakpoint/StoppointSite.h b/gnu/llvm/lldb/include/lldb/Breakpoint/StoppointSite.h new file mode 100644 index 00000000000..7e5e3348634 --- /dev/null +++ b/gnu/llvm/lldb/include/lldb/Breakpoint/StoppointSite.h @@ -0,0 +1,81 @@ +//===-- StoppointSite.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_BREAKPOINT_STOPPOINTSITE_H +#define LLDB_BREAKPOINT_STOPPOINTSITE_H + +#include "lldb/Breakpoint/StoppointHitCounter.h" +#include "lldb/Utility/UserID.h" +#include "lldb/lldb-private.h" + +namespace lldb_private { + +class StoppointSite { +public: + StoppointSite(lldb::break_id_t bid, lldb::addr_t m_addr, bool hardware); + + StoppointSite(lldb::break_id_t bid, lldb::addr_t m_addr, + uint32_t byte_size, bool hardware); + + virtual ~StoppointSite() = default; + + virtual lldb::addr_t GetLoadAddress() const { return m_addr; } + + virtual void SetLoadAddress(lldb::addr_t addr) { m_addr = addr; } + + uint32_t GetByteSize() const { return m_byte_size; } + + uint32_t GetHitCount() const { return m_hit_counter.GetValue(); } + + void ResetHitCount() { m_hit_counter.Reset(); } + + bool HardwareRequired() const { return m_is_hardware_required; } + + virtual bool IsHardware() const = 0; + + uint32_t GetHardwareIndex() const { return m_hardware_index; } + + void SetHardwareIndex(uint32_t index) { m_hardware_index = index; } + + virtual bool ShouldStop(StoppointCallbackContext* context) = 0; + + virtual void Dump(Stream* stream) const = 0; + + lldb::break_id_t GetID() const { return m_id; } + +protected: + /// Stoppoint site ID. + lldb::break_id_t m_id; + + /// The load address of this stop point. + lldb::addr_t m_addr; + + /// True if this point is required to use hardware (which may fail due to + /// the lack of resources). + bool m_is_hardware_required; + + /// The hardware resource index for this breakpoint/watchpoint. + uint32_t m_hardware_index; + + /// The size in bytes of stoppoint, e.g. the length of the trap opcode for + /// software breakpoints, or the optional length in bytes for hardware + /// breakpoints, or the length of the watchpoint. + uint32_t m_byte_size; + + /// Number of times this breakpoint/watchpoint has been hit. + StoppointHitCounter m_hit_counter; + +private: + StoppointSite(const StoppointSite &) = delete; + const StoppointSite &operator=(const StoppointSite &) = delete; + StoppointSite() = delete; +}; + +} // namespace lldb_private + +#endif // LLDB_BREAKPOINT_STOPPOINTSITE_H diff --git a/gnu/llvm/lldb/include/lldb/Breakpoint/Watchpoint.h b/gnu/llvm/lldb/include/lldb/Breakpoint/Watchpoint.h index bce15f0a85d..41b723a66b6 100644 --- a/gnu/llvm/lldb/include/lldb/Breakpoint/Watchpoint.h +++ b/gnu/llvm/lldb/include/lldb/Breakpoint/Watchpoint.h @@ -12,7 +12,7 @@ #include #include -#include "lldb/Breakpoint/StoppointLocation.h" +#include "lldb/Breakpoint/StoppointSite.h" #include "lldb/Breakpoint/WatchpointOptions.h" #include "lldb/Symbol/CompilerType.h" #include "lldb/Target/Target.h" @@ -22,7 +22,7 @@ namespace lldb_private { class Watchpoint : public std::enable_shared_from_this, - public StoppointLocation { + public StoppointSite { public: class WatchpointEventData : public EventData { public: @@ -158,8 +158,6 @@ private: friend class Target; friend class WatchpointList; - void ResetHitCount() { m_hit_count = 0; } - void ResetHistoricValues() { m_old_value_sp.reset(); m_new_value_sp.reset(); @@ -199,7 +197,7 @@ private: std::unique_ptr m_condition_up; // The condition to test. - void SetID(lldb::watch_id_t id) { m_loc_id = id; } + void SetID(lldb::watch_id_t id) { m_id = id; } void SendWatchpointChangedEvent(lldb::WatchpointEventType eventKind); diff --git a/gnu/llvm/lldb/include/lldb/Breakpoint/WatchpointList.h b/gnu/llvm/lldb/include/lldb/Breakpoint/WatchpointList.h index 283f991b178..bf87495d79d 100644 --- a/gnu/llvm/lldb/include/lldb/Breakpoint/WatchpointList.h +++ b/gnu/llvm/lldb/include/lldb/Breakpoint/WatchpointList.h @@ -14,6 +14,7 @@ #include #include "lldb/Core/Address.h" +#include "lldb/Utility/Iterable.h" #include "lldb/lldb-private.h" namespace lldb_private { @@ -37,6 +38,11 @@ public: /// Destructor, currently does nothing. ~WatchpointList(); + typedef std::list wp_collection; + typedef LockingAdaptedIterable + WatchpointIterable; + /// Add a Watchpoint to the list. /// /// \param[in] wp_sp @@ -184,8 +190,11 @@ public: /// The locker object that is set. void GetListMutex(std::unique_lock &lock); + WatchpointIterable Watchpoints() const { + return WatchpointIterable(m_watchpoints, m_mutex); + } + protected: - typedef std::list wp_collection; typedef std::vector id_vector; id_vector GetWatchpointIDs() const; @@ -198,7 +207,7 @@ protected: wp_collection m_watchpoints; mutable std::recursive_mutex m_mutex; - lldb::watch_id_t m_next_wp_id; + lldb::watch_id_t m_next_wp_id = 0; }; } // namespace lldb_private diff --git a/gnu/llvm/lldb/include/lldb/Breakpoint/WatchpointOptions.h b/gnu/llvm/lldb/include/lldb/Breakpoint/WatchpointOptions.h index 0a18c52d36d..fbfcb91c424 100644 --- a/gnu/llvm/lldb/include/lldb/Breakpoint/WatchpointOptions.h +++ b/gnu/llvm/lldb/include/lldb/Breakpoint/WatchpointOptions.h @@ -166,13 +166,13 @@ public: lldb::user_id_t watch_id); struct CommandData { - CommandData() : user_source(), script_source(), stop_on_error(true) {} + CommandData() : user_source(), script_source() {} ~CommandData() = default; StringList user_source; std::string script_source; - bool stop_on_error; + bool stop_on_error = true; }; class CommandBaton : public TypedBaton { @@ -191,7 +191,7 @@ private: // For WatchpointOptions only WatchpointHitCallback m_callback; // This is the callback function pointer lldb::BatonSP m_callback_baton_sp; // This is the client data for the callback - bool m_callback_is_synchronous; + bool m_callback_is_synchronous = false; std::unique_ptr m_thread_spec_up; // Thread for which this watchpoint will take }; diff --git a/gnu/llvm/lldb/include/lldb/Core/Address.h b/gnu/llvm/lldb/include/lldb/Core/Address.h index 71e50b91d68..ec393a1871e 100644 --- a/gnu/llvm/lldb/include/lldb/Core/Address.h +++ b/gnu/llvm/lldb/include/lldb/Core/Address.h @@ -14,8 +14,8 @@ #include "lldb/lldb-private-enumerations.h" #include "lldb/lldb-types.h" -#include -#include +#include +#include namespace lldb_private { class Block; @@ -116,7 +116,7 @@ public: /// /// Initialize with a invalid section (NULL) and an invalid offset /// (LLDB_INVALID_ADDRESS). - Address() : m_section_wp(), m_offset(LLDB_INVALID_ADDRESS) {} + Address() : m_section_wp() {} /// Copy constructor /// @@ -487,7 +487,8 @@ public: protected: // Member variables. lldb::SectionWP m_section_wp; ///< The section for the address, can be NULL. - lldb::addr_t m_offset; ///< Offset into section if \a m_section_wp is valid... + lldb::addr_t m_offset = LLDB_INVALID_ADDRESS; ///< Offset into section if \a + ///< m_section_wp is valid... // Returns true if the m_section_wp once had a reference to a valid section // shared pointer, but no longer does. This can happen if we have an address diff --git a/gnu/llvm/lldb/include/lldb/Core/AddressRange.h b/gnu/llvm/lldb/include/lldb/Core/AddressRange.h index 8ccf96a436a..6fbdc35c916 100644 --- a/gnu/llvm/lldb/include/lldb/Core/AddressRange.h +++ b/gnu/llvm/lldb/include/lldb/Core/AddressRange.h @@ -13,7 +13,7 @@ #include "lldb/lldb-forward.h" #include "lldb/lldb-types.h" -#include +#include namespace lldb_private { class SectionList; @@ -94,8 +94,7 @@ public: /// \return /// Returns \b true if \a so_addr is contained in this range, /// \b false otherwise. - // bool - // Contains (const Address &so_addr) const; + bool Contains(const Address &so_addr) const; /// Check if a section offset address is contained in this range. /// @@ -240,7 +239,7 @@ public: protected: // Member variables Address m_base_addr; ///< The section offset base address of this range. - lldb::addr_t m_byte_size; ///< The size in bytes of this address range. + lldb::addr_t m_byte_size = 0; ///< The size in bytes of this address range. }; // bool operator== (const AddressRange& lhs, const AddressRange& rhs); diff --git a/gnu/llvm/lldb/include/lldb/Core/AddressResolver.h b/gnu/llvm/lldb/include/lldb/Core/AddressResolver.h index 9ac058a97cd..cb571bb5cb6 100644 --- a/gnu/llvm/lldb/include/lldb/Core/AddressResolver.h +++ b/gnu/llvm/lldb/include/lldb/Core/AddressResolver.h @@ -13,7 +13,7 @@ #include "lldb/Core/SearchFilter.h" #include "lldb/lldb-defines.h" -#include +#include #include namespace lldb_private { diff --git a/gnu/llvm/lldb/include/lldb/Core/AddressResolverFileLine.h b/gnu/llvm/lldb/include/lldb/Core/AddressResolverFileLine.h index 46bf4155e86..e768256bf61 100644 --- a/gnu/llvm/lldb/include/lldb/Core/AddressResolverFileLine.h +++ b/gnu/llvm/lldb/include/lldb/Core/AddressResolverFileLine.h @@ -11,10 +11,10 @@ #include "lldb/Core/AddressResolver.h" #include "lldb/Core/SearchFilter.h" -#include "lldb/Utility/FileSpec.h" +#include "lldb/Core/SourceLocationSpec.h" #include "lldb/lldb-defines.h" -#include +#include namespace lldb_private { class Address; @@ -28,8 +28,7 @@ class SymbolContext; class AddressResolverFileLine : public AddressResolver { public: - AddressResolverFileLine(const FileSpec &resolver, uint32_t line_no, - bool check_inlines); + AddressResolverFileLine(SourceLocationSpec location_spec); ~AddressResolverFileLine() override; @@ -42,10 +41,7 @@ public: void GetDescription(Stream *s) override; protected: - FileSpec m_file_spec; // This is the file spec we are looking for. - uint32_t m_line_number; // This is the line number that we are looking for. - bool m_inlines; // This determines whether the resolver looks for inlined - // functions or not. + SourceLocationSpec m_src_location_spec; private: AddressResolverFileLine(const AddressResolverFileLine &) = delete; diff --git a/gnu/llvm/lldb/include/lldb/Core/Architecture.h b/gnu/llvm/lldb/include/lldb/Core/Architecture.h index d8dbbb4f540..b68bf27ae0d 100644 --- a/gnu/llvm/lldb/include/lldb/Core/Architecture.h +++ b/gnu/llvm/lldb/include/lldb/Core/Architecture.h @@ -10,14 +10,12 @@ #define LLDB_CORE_ARCHITECTURE_H #include "lldb/Core/PluginInterface.h" +#include "lldb/Target/MemoryTagManager.h" namespace lldb_private { class Architecture : public PluginInterface { public: - Architecture() = default; - ~Architecture() override = default; - /// This is currently intended to handle cases where a /// program stops at an instruction that won't get executed and it /// allows the stop reason, like "breakpoint hit", to be replaced @@ -101,9 +99,16 @@ public: return addr; } -private: - Architecture(const Architecture &) = delete; - void operator=(const Architecture &) = delete; + // Returns a pointer to an object that can manage memory tags for this + // Architecture E.g. masking out tags, unpacking tag streams etc. Returns + // nullptr if the architecture does not have a memory tagging extension. + // + // The return pointer being valid does not mean that the current process has + // memory tagging enabled, just that a tagging technology exists for this + // architecture. + virtual const MemoryTagManager *GetMemoryTagManager() const { + return nullptr; + } }; } // namespace lldb_private diff --git a/gnu/llvm/lldb/include/lldb/Core/Communication.h b/gnu/llvm/lldb/include/lldb/Core/Communication.h index 6b65974f952..930e927f678 100644 --- a/gnu/llvm/lldb/include/lldb/Core/Communication.h +++ b/gnu/llvm/lldb/include/lldb/Core/Communication.h @@ -22,8 +22,8 @@ #include #include -#include -#include +#include +#include namespace lldb_private { class Connection; @@ -285,7 +285,7 @@ public: /// void SynchronizeWithReadThread(); - static const char *ConnectionStatusAsCString(lldb::ConnectionStatus status); + static std::string ConnectionStatusAsString(lldb::ConnectionStatus status); bool GetCloseOnEOF() const { return m_close_on_eof; } diff --git a/gnu/llvm/lldb/include/lldb/Core/Debugger.h b/gnu/llvm/lldb/include/lldb/Core/Debugger.h index 7bea0dbae08..f0849c9ac95 100644 --- a/gnu/llvm/lldb/include/lldb/Core/Debugger.h +++ b/gnu/llvm/lldb/include/lldb/Core/Debugger.h @@ -9,7 +9,7 @@ #ifndef LLDB_CORE_DEBUGGER_H #define LLDB_CORE_DEBUGGER_H -#include +#include #include #include @@ -42,9 +42,9 @@ #include "llvm/Support/DynamicLibrary.h" #include "llvm/Support/Threading.h" -#include -#include -#include +#include +#include +#include namespace llvm { class raw_ostream; @@ -73,6 +73,50 @@ class Debugger : public std::enable_shared_from_this, friend class SourceManager; // For GetSourceFileCache. public: + /// Broadcaster event bits definitions. + enum { + eBroadcastBitProgress = (1 << 0), + }; + + static ConstString GetStaticBroadcasterClass(); + + /// Get the public broadcaster for this debugger. + Broadcaster &GetBroadcaster() { return m_broadcaster; } + const Broadcaster &GetBroadcaster() const { return m_broadcaster; } + + class ProgressEventData : public EventData { + + public: + ProgressEventData(uint64_t progress_id, const std::string &message, + uint64_t completed, uint64_t total, + bool debugger_specific) + : m_message(message), m_id(progress_id), m_completed(completed), + m_total(total), m_debugger_specific(debugger_specific) {} + + static ConstString GetFlavorString(); + + ConstString GetFlavor() const override; + + void Dump(Stream *s) const override; + + static const ProgressEventData * + GetEventDataFromEvent(const Event *event_ptr); + uint64_t GetID() const { return m_id; } + uint64_t GetCompleted() const { return m_completed; } + uint64_t GetTotal() const { return m_total; } + const std::string &GetMessage() const { return m_message; } + bool IsDebuggerSpecific() const { return m_debugger_specific; } + + private: + std::string m_message; + const uint64_t m_id; + uint64_t m_completed; + const uint64_t m_total; + const bool m_debugger_specific; + ProgressEventData(const ProgressEventData &) = delete; + const ProgressEventData &operator=(const ProgressEventData &) = delete; + }; + ~Debugger() override; static lldb::DebuggerSP @@ -246,6 +290,8 @@ public: const FormatEntity::Entry *GetFrameFormatUnique() const; + uint32_t GetStopDisassemblyMaxSize() const; + const FormatEntity::Entry *GetThreadFormat() const; const FormatEntity::Entry *GetThreadStopFormat() const; @@ -273,6 +319,8 @@ public: bool SetUseColor(bool use_color); + bool GetUseAutosuggestion() const; + bool GetUseSourceCache() const; bool SetUseSourceCache(bool use_source_cache); @@ -332,8 +380,8 @@ public: // This is for use in the command interpreter, when you either want the // selected target, or if no target is present you want to prime the dummy // target with entities that will be copied over to new targets. - Target *GetSelectedOrDummyTarget(bool prefer_dummy = false); - Target *GetDummyTarget() { return m_dummy_target_sp.get(); } + Target &GetSelectedOrDummyTarget(bool prefer_dummy = false); + Target &GetDummyTarget() { return *m_dummy_target_sp; } lldb::BroadcasterManagerSP GetBroadcasterManager() { return m_broadcaster_manager_sp; @@ -342,6 +390,40 @@ public: protected: friend class CommandInterpreter; friend class REPL; + friend class Progress; + + /// Report progress events. + /// + /// Progress events will be delivered to any debuggers that have listeners + /// for the eBroadcastBitProgress. This function is called by the + /// lldb_private::Progress class to deliver the events to any debuggers that + /// qualify. + /// + /// \param [in] progress_id + /// The unique integer identifier for the progress to report. + /// + /// \param[in] message + /// The title of the progress dialog to display in the UI. + /// + /// \param [in] completed + /// The amount of work completed. If \a completed is zero, then this event + /// is a progress started event. If \a completed is equal to \a total, then + /// this event is a progress end event. Otherwise completed indicates the + /// current progress compare to the total value. + /// + /// \param [in] total + /// The total amount of work units that need to be completed. If this value + /// is UINT64_MAX, then an indeterminate progress indicator should be + /// displayed. + /// + /// \param [in] debugger_id + /// If this optional parameter has a value, it indicates the unique + /// debugger identifier that this progress should be delivered to. If this + /// optional parameter does not have a value, the progress will be + /// delivered to all debuggers. + static void ReportProgress(uint64_t progress_id, const std::string &message, + uint64_t completed, uint64_t total, + llvm::Optional debugger_id); bool StartEventHandlerThread(); @@ -428,7 +510,8 @@ protected: LoadedPluginsList m_loaded_plugins; HostThread m_event_handler_thread; HostThread m_io_handler_thread; - Broadcaster m_sync_broadcaster; + Broadcaster m_sync_broadcaster; ///< Private debugger synchronization. + Broadcaster m_broadcaster; ///< Public Debugger event broadcaster. lldb::ListenerSP m_forward_listener_sp; llvm::once_flag m_clear_once; lldb::TargetSP m_dummy_target_sp; diff --git a/gnu/llvm/lldb/include/lldb/Core/Declaration.h b/gnu/llvm/lldb/include/lldb/Core/Declaration.h new file mode 100644 index 00000000000..f81de21bc8f --- /dev/null +++ b/gnu/llvm/lldb/include/lldb/Core/Declaration.h @@ -0,0 +1,195 @@ +//===-- Declaration.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_SYMBOL_DECLARATION_H +#define LLDB_SYMBOL_DECLARATION_H + +#include "lldb/Utility/FileSpec.h" +#include "lldb/lldb-private.h" + +namespace lldb_private { + +/// \class Declaration Declaration.h "lldb/Core/Declaration.h" +/// A class that describes the declaration location of a +/// lldb object. +/// +/// The declarations include the file specification, line number, and the +/// column info and can help track where functions, blocks, inlined functions, +/// types, variables, any many other debug core objects were declared. +class Declaration { +public: + /// Default constructor. + Declaration() : m_file() {} + + /// Construct with file specification, and optional line and column. + /// + /// \param[in] file_spec + /// The file specification that describes where this was + /// declared. + /// + /// \param[in] line + /// The line number that describes where this was declared. Set + /// to zero if there is no line number information. + /// + /// \param[in] column + /// The column number that describes where this was declared. + /// Set to zero if there is no column number information. + Declaration(const FileSpec &file_spec, uint32_t line = 0, + uint16_t column = LLDB_INVALID_COLUMN_NUMBER) + : m_file(file_spec), m_line(line), m_column(column) {} + + /// Construct with a pointer to another Declaration object. + Declaration(const Declaration *decl_ptr) + : m_file(), m_line(0), m_column(LLDB_INVALID_COLUMN_NUMBER) { + if (decl_ptr) + *this = *decl_ptr; + } + + /// Clear the object's state. + /// + /// Sets the file specification to be empty, and the line and column to + /// zero. + void Clear() { + m_file.Clear(); + m_line = 0; + m_column = 0; + } + + /// Compare two declaration objects. + /// + /// Compares the two file specifications from \a lhs and \a rhs. If the file + /// specifications are equal, then continue to compare the line number and + /// column numbers respectively. + /// + /// \param[in] lhs + /// The Left Hand Side const Declaration object reference. + /// + /// \param[in] rhs + /// The Right Hand Side const Declaration object reference. + /// + /// \return + /// -1 if lhs < rhs + /// 0 if lhs == rhs + /// 1 if lhs > rhs + static int Compare(const Declaration &lhs, const Declaration &rhs); + + /// Checks if this object has the same file and line as another declaration + /// object. + /// + /// \param[in] declaration + /// The const Declaration object to compare with. + /// + /// \return + /// Returns \b true if \b declaration is at the same file and + /// line, \b false otherwise. + bool FileAndLineEqual(const Declaration &declaration) const; + + /// Dump a description of this object to a Stream. + /// + /// Dump a description of the contents of this object to the supplied stream + /// \a s. + /// + /// \param[in] s + /// The stream to which to dump the object description. + void Dump(Stream *s, bool show_fullpaths) const; + + bool DumpStopContext(Stream *s, bool show_fullpaths) const; + + /// Get accessor for file specification. + /// + /// \return + /// A reference to the file specification object. + FileSpec &GetFile() { return m_file; } + + /// Get const accessor for file specification. + /// + /// \return + /// A const reference to the file specification object. + const FileSpec &GetFile() const { return m_file; } + + /// Get accessor for the declaration line number. + /// + /// \return + /// Non-zero indicates a valid line number, zero indicates no + /// line information is available. + uint32_t GetLine() const { return m_line; } + + /// Get accessor for the declaration column number. + /// + /// \return + /// Non-zero indicates a valid column number, zero indicates no + /// column information is available. + uint16_t GetColumn() const { return m_column; } + + /// Convert to boolean operator. + /// + /// This allows code to check a Declaration object to see if it + /// contains anything valid using code such as: + /// + /// \code + /// Declaration decl(...); + /// if (decl) + /// { ... + /// \endcode + /// + /// \return + /// A \b true if both the file_spec and the line are valid, + /// \b false otherwise. + explicit operator bool() const { return IsValid(); } + + bool IsValid() const { + return m_file && m_line != 0 && m_line != LLDB_INVALID_LINE_NUMBER; + } + + /// Get the memory cost of this object. + /// + /// \return + /// The number of bytes that this object occupies in memory. + /// The returned value does not include the bytes for any + /// shared string values. + /// + /// \see ConstString::StaticMemorySize () + size_t MemorySize() const; + + /// Set accessor for the declaration file specification. + /// + /// \param[in] file_spec + /// The new declaration file specification. + void SetFile(const FileSpec &file_spec) { m_file = file_spec; } + + /// Set accessor for the declaration line number. + /// + /// \param[in] line + /// Non-zero indicates a valid line number, zero indicates no + /// line information is available. + void SetLine(uint32_t line) { m_line = line; } + + /// Set accessor for the declaration column number. + /// + /// \param[in] column + /// Non-zero indicates a valid column number, zero indicates no + /// column information is available. + void SetColumn(uint16_t column) { m_column = column; } + +protected: + /// The file specification that points to the source file where the + /// declaration occurred. + FileSpec m_file; + /// Non-zero values indicates a valid line number, zero indicates no line + /// number information is available. + uint32_t m_line = 0; + /// Non-zero values indicates a valid column number, zero indicates no column + /// information is available. + uint16_t m_column = LLDB_INVALID_COLUMN_NUMBER; +}; + +bool operator==(const Declaration &lhs, const Declaration &rhs); + +} // namespace lldb_private + +#endif // LLDB_SYMBOL_DECLARATION_H diff --git a/gnu/llvm/lldb/include/lldb/Core/Disassembler.h b/gnu/llvm/lldb/include/lldb/Core/Disassembler.h index 926a74b933e..622c23ff649 100644 --- a/gnu/llvm/lldb/include/lldb/Core/Disassembler.h +++ b/gnu/llvm/lldb/include/lldb/Core/Disassembler.h @@ -34,9 +34,9 @@ #include #include -#include -#include -#include +#include +#include +#include namespace llvm { template class SmallVectorImpl; @@ -48,6 +48,7 @@ class DataExtractor; class Debugger; class Disassembler; class Module; +class StackFrame; class Stream; class SymbolContext; class SymbolContextList; @@ -270,6 +271,13 @@ public: lldb::InstructionSP GetInstructionAtIndex(size_t idx) const; + /// Get the instruction at the given address. + /// + /// \return + /// A valid \a InstructionSP if the address could be found, or null + /// otherwise. + lldb::InstructionSP GetInstructionAtAddress(const Address &addr); + //------------------------------------------------------------------ /// Get the index of the next branch instruction. /// @@ -279,9 +287,6 @@ public: /// @param[in] start /// The instruction index of the first instruction to check. /// - /// @param[in] target - /// A LLDB target object that is used to resolve addresses. - /// /// @param[in] ignore_calls /// It true, then fine the first branch instruction that isn't /// a function call (a branch that calls and returns to the next @@ -298,7 +303,6 @@ public: /// found. //------------------------------------------------------------------ uint32_t GetIndexOfNextBranchInstruction(uint32_t start, - Target &target, bool ignore_calls, bool *found_calls) const; @@ -390,10 +394,12 @@ public: lldb::addr_t value; }; - static lldb::DisassemblerSP - DisassembleRange(const ArchSpec &arch, const char *plugin_name, - const char *flavor, Target &target, - const AddressRange &disasm_range, bool prefer_file_cache); + static lldb::DisassemblerSP DisassembleRange(const ArchSpec &arch, + const char *plugin_name, + const char *flavor, + Target &target, + const AddressRange &disasm_range, + bool force_live_memory = false); static lldb::DisassemblerSP DisassembleBytes(const ArchSpec &arch, const char *plugin_name, @@ -408,11 +414,8 @@ public: uint32_t num_mixed_context_lines, uint32_t options, Stream &strm); - static bool - Disassemble(Debugger &debugger, const ArchSpec &arch, const char *plugin_name, - const char *flavor, const ExecutionContext &exe_ctx, - uint32_t num_instructions, bool mixed_source_and_assembly, - uint32_t num_mixed_context_lines, uint32_t options, Stream &strm); + static bool Disassemble(Debugger &debugger, const ArchSpec &arch, + StackFrame &frame, Stream &strm); // Constructors and Destructors Disassembler(const ArchSpec &arch, const char *flavor); @@ -425,7 +428,8 @@ public: Stream &strm); size_t ParseInstructions(Target &target, Address address, Limit limit, - Stream *error_strm_ptr, bool prefer_file_cache); + Stream *error_strm_ptr, + bool force_live_memory = false); virtual size_t DecodeInstructions(const Address &base_addr, const DataExtractor &data, @@ -450,10 +454,10 @@ protected: struct SourceLine { FileSpec file; - uint32_t line; - uint32_t column; + uint32_t line = LLDB_INVALID_LINE_NUMBER; + uint32_t column = 0; - SourceLine() : file(), line(LLDB_INVALID_LINE_NUMBER), column(0) {} + SourceLine() : file() {} bool operator==(const SourceLine &rhs) const { return file == rhs.file && line == rhs.line && rhs.column == column; @@ -472,14 +476,12 @@ protected: // index of the "current" source line, if we want to highlight that when // displaying the source lines. (as opposed to the surrounding source // lines provided to give context) - size_t current_source_line; + size_t current_source_line = -1; // Whether to print a blank line at the end of the source lines. - bool print_source_context_end_eol; + bool print_source_context_end_eol = true; - SourceLinesToDisplay() - : lines(), current_source_line(-1), print_source_context_end_eol(true) { - } + SourceLinesToDisplay() : lines() {} }; // Get the function's declaration line number, hopefully a line number diff --git a/gnu/llvm/lldb/include/lldb/Core/DumpDataExtractor.h b/gnu/llvm/lldb/include/lldb/Core/DumpDataExtractor.h index 2a9d778e0a6..12188609e8c 100644 --- a/gnu/llvm/lldb/include/lldb/Core/DumpDataExtractor.h +++ b/gnu/llvm/lldb/include/lldb/Core/DumpDataExtractor.h @@ -12,8 +12,8 @@ #include "lldb/lldb-enumerations.h" #include "lldb/lldb-types.h" -#include -#include +#include +#include namespace lldb_private { class DataExtractor; diff --git a/gnu/llvm/lldb/include/lldb/Core/EmulateInstruction.h b/gnu/llvm/lldb/include/lldb/Core/EmulateInstruction.h index a575488ba96..f50fee095a8 100644 --- a/gnu/llvm/lldb/include/lldb/Core/EmulateInstruction.h +++ b/gnu/llvm/lldb/include/lldb/Core/EmulateInstruction.h @@ -21,8 +21,8 @@ #include "lldb/lldb-private-types.h" #include "lldb/lldb-types.h" -#include -#include +#include +#include namespace lldb_private { class OptionValueDictionary; @@ -182,8 +182,8 @@ public: } InfoType; struct Context { - ContextType type; - enum InfoType info_type; + ContextType type = eContextInvalid; + enum InfoType info_type = eInfoTypeNoArgs; union { struct RegisterPlusOffset { RegisterInfo reg; // base register @@ -237,7 +237,7 @@ public: uint32_t isa; } info; - Context() : type(eContextInvalid), info_type(eInfoTypeNoArgs) {} + Context() = default; void SetRegisterPlusOffset(RegisterInfo base_reg, int64_t signed_offset) { info_type = eInfoTypeRegisterPlusOffset; diff --git a/gnu/llvm/lldb/include/lldb/Core/FileLineResolver.h b/gnu/llvm/lldb/include/lldb/Core/FileLineResolver.h index 68e252e93bc..16b1db1b50c 100644 --- a/gnu/llvm/lldb/include/lldb/Core/FileLineResolver.h +++ b/gnu/llvm/lldb/include/lldb/Core/FileLineResolver.h @@ -14,7 +14,7 @@ #include "lldb/Utility/FileSpec.h" #include "lldb/lldb-defines.h" -#include +#include namespace lldb_private { class Address; @@ -28,8 +28,8 @@ class FileLineResolver : public Searcher { public: FileLineResolver() : m_file_spec(), - m_line_number(UINT32_MAX), // Set this to zero for all lines in a file - m_sc_list(), m_inlines(true) {} + // Set this to zero for all lines in a file + m_sc_list() {} FileLineResolver(const FileSpec &resolver, uint32_t line_no, bool check_inlines); @@ -52,10 +52,11 @@ public: protected: FileSpec m_file_spec; // This is the file spec we are looking for. - uint32_t m_line_number; // This is the line number that we are looking for. + uint32_t m_line_number = + UINT32_MAX; // This is the line number that we are looking for. SymbolContextList m_sc_list; - bool m_inlines; // This determines whether the resolver looks for inlined - // functions or not. + bool m_inlines = true; // This determines whether the resolver looks for + // inlined functions or not. private: FileLineResolver(const FileLineResolver &) = delete; diff --git a/gnu/llvm/lldb/include/lldb/Core/FileSpecList.h b/gnu/llvm/lldb/include/lldb/Core/FileSpecList.h index 3e412a7e1a3..cab8e9b9b43 100644 --- a/gnu/llvm/lldb/include/lldb/Core/FileSpecList.h +++ b/gnu/llvm/lldb/include/lldb/Core/FileSpecList.h @@ -14,7 +14,7 @@ #include -#include +#include namespace lldb_private { class Stream; diff --git a/gnu/llvm/lldb/include/lldb/Core/FormatEntity.h b/gnu/llvm/lldb/include/lldb/Core/FormatEntity.h index 91999f64ab5..ecae8500df4 100644 --- a/gnu/llvm/lldb/include/lldb/Core/FormatEntity.h +++ b/gnu/llvm/lldb/include/lldb/Core/FormatEntity.h @@ -9,26 +9,27 @@ #ifndef LLDB_CORE_FORMATENTITY_H #define LLDB_CORE_FORMATENTITY_H -#include "lldb/Utility/CompletionRequest.h" -#include "lldb/Utility/FileSpec.h" -#include "lldb/Utility/Status.h" #include "lldb/lldb-enumerations.h" #include "lldb/lldb-types.h" #include -#include -#include +#include +#include #include #include namespace lldb_private { class Address; +class CompletionRequest; class ExecutionContext; +class FileSpec; +class Status; class Stream; class StringList; class SymbolContext; class ValueObject; } + namespace llvm { class StringRef; } @@ -103,20 +104,51 @@ public: }; struct Definition { + /// The name/string placeholder that corresponds to this definition. const char *name; - const char *string; // Insert this exact string into the output - Entry::Type type; - uint64_t data; - uint32_t num_children; - Definition *children; // An array of "num_children" Definition entries, - bool keep_separator; + /// Insert this exact string into the output + const char *string = nullptr; + /// Entry::Type corresponding to this definition. + const Entry::Type type; + /// Data that is returned as the value of the format string. + const uint64_t data = 0; + /// The number of children of this node in the tree of format strings. + const uint32_t num_children = 0; + /// An array of "num_children" Definition entries. + const Definition *children = nullptr; + /// Whether the separator is kept during parsing or not. It's used + /// for entries with parameters. + const bool keep_separator = false; + + constexpr Definition(const char *name, const FormatEntity::Entry::Type t) + : name(name), type(t) {} + + constexpr Definition(const char *name, const char *string) + : name(name), string(string), type(Entry::Type::EscapeCode) {} + + constexpr Definition(const char *name, const FormatEntity::Entry::Type t, + const uint64_t data) + : name(name), type(t), data(data) {} + + constexpr Definition(const char *name, const FormatEntity::Entry::Type t, + const uint64_t num_children, + const Definition *children, + const bool keep_separator = false) + : name(name), type(t), num_children(num_children), children(children), + keep_separator(keep_separator) {} }; + template + static constexpr Definition + DefinitionWithChildren(const char *name, const FormatEntity::Entry::Type t, + const Definition (&children)[N], + bool keep_separator = false) { + return Definition(name, t, N, children, keep_separator); + } + Entry(Type t = Type::Invalid, const char *s = nullptr, const char *f = nullptr) - : string(s ? s : ""), printf_format(f ? f : ""), children(), - definition(nullptr), type(t), fmt(lldb::eFormatDefault), number(0), - deref(false) {} + : string(s ? s : ""), printf_format(f ? f : ""), children(), type(t) {} Entry(llvm::StringRef s); Entry(char ch); @@ -133,7 +165,6 @@ public: string.clear(); printf_format.clear(); children.clear(); - definition = nullptr; type = Type::Invalid; fmt = lldb::eFormatDefault; number = 0; @@ -157,8 +188,6 @@ public: } if (children != rhs.children) return false; - if (definition != rhs.definition) - return false; if (type != rhs.type) return false; if (fmt != rhs.fmt) @@ -171,11 +200,10 @@ public: std::string string; std::string printf_format; std::vector children; - Definition *definition; Type type; - lldb::Format fmt; - lldb::addr_t number; - bool deref; + lldb::Format fmt = lldb::eFormatDefault; + lldb::addr_t number = 0; + bool deref = false; }; static bool Format(const Entry &entry, Stream &s, const SymbolContext *sc, diff --git a/gnu/llvm/lldb/include/lldb/Core/IOHandler.h b/gnu/llvm/lldb/include/lldb/Core/IOHandler.h index 51592afbbab..4a3b788e3ea 100644 --- a/gnu/llvm/lldb/include/lldb/Core/IOHandler.h +++ b/gnu/llvm/lldb/include/lldb/Core/IOHandler.h @@ -15,7 +15,6 @@ #include "lldb/Utility/ConstString.h" #include "lldb/Utility/Flags.h" #include "lldb/Utility/Predicate.h" -#include "lldb/Utility/Reproducer.h" #include "lldb/Utility/Stream.h" #include "lldb/Utility/StringList.h" #include "lldb/lldb-defines.h" @@ -27,11 +26,14 @@ #include #include -#include -#include +#include +#include namespace lldb_private { class Debugger; +namespace repro { +class DataRecorder; +} } namespace curses { @@ -126,11 +128,11 @@ public: FILE *GetErrorFILE(); - lldb::FileSP &GetInputFileSP(); + lldb::FileSP GetInputFileSP(); - lldb::StreamFileSP &GetOutputStreamFileSP(); + lldb::StreamFileSP GetOutputStreamFileSP(); - lldb::StreamFileSP &GetErrorStreamFileSP(); + lldb::StreamFileSP GetErrorStreamFileSP(); Debugger &GetDebugger() { return m_debugger; } @@ -203,6 +205,9 @@ public: virtual void IOHandlerDeactivated(IOHandler &io_handler) {} + virtual llvm::Optional IOHandlerSuggestion(IOHandler &io_handler, + llvm::StringRef line); + virtual void IOHandlerComplete(IOHandler &io_handler, CompletionRequest &request); @@ -414,13 +419,14 @@ public: private: #if LLDB_ENABLE_LIBEDIT - static bool IsInputCompleteCallback(Editline *editline, StringList &lines, - void *baton); + bool IsInputCompleteCallback(Editline *editline, StringList &lines); + + int FixIndentationCallback(Editline *editline, const StringList &lines, + int cursor_position); - static int FixIndentationCallback(Editline *editline, const StringList &lines, - int cursor_position, void *baton); + llvm::Optional SuggestionCallback(llvm::StringRef line); - static void AutoCompleteCallback(CompletionRequest &request, void *baton); + void AutoCompleteCallback(CompletionRequest &request); #endif protected: diff --git a/gnu/llvm/lldb/include/lldb/Core/IOHandlerCursesGUI.h b/gnu/llvm/lldb/include/lldb/Core/IOHandlerCursesGUI.h index fe62eaea643..22ca735063b 100644 --- a/gnu/llvm/lldb/include/lldb/Core/IOHandlerCursesGUI.h +++ b/gnu/llvm/lldb/include/lldb/Core/IOHandlerCursesGUI.h @@ -31,6 +31,8 @@ public: void Deactivate() override; + void TerminalSizeChanged() override; + protected: curses::ApplicationAP m_app_ap; }; diff --git a/gnu/llvm/lldb/include/lldb/Core/LoadedModuleInfoList.h b/gnu/llvm/lldb/include/lldb/Core/LoadedModuleInfoList.h index 49400f7f490..ad6da2bd755 100644 --- a/gnu/llvm/lldb/include/lldb/Core/LoadedModuleInfoList.h +++ b/gnu/llvm/lldb/include/lldb/Core/LoadedModuleInfoList.h @@ -101,14 +101,14 @@ public: lldb::addr_t m_dynamic; }; - LoadedModuleInfoList() : m_list(), m_link_map(LLDB_INVALID_ADDRESS) {} + LoadedModuleInfoList() : m_list() {} void add(const LoadedModuleInfo &mod) { m_list.push_back(mod); } void clear() { m_list.clear(); } std::vector m_list; - lldb::addr_t m_link_map; + lldb::addr_t m_link_map = LLDB_INVALID_ADDRESS; }; } // namespace lldb_private diff --git a/gnu/llvm/lldb/include/lldb/Core/Mangled.h b/gnu/llvm/lldb/include/lldb/Core/Mangled.h index c03fc1eb759..d11d13b63cf 100644 --- a/gnu/llvm/lldb/include/lldb/Core/Mangled.h +++ b/gnu/llvm/lldb/include/lldb/Core/Mangled.h @@ -17,8 +17,8 @@ #include "llvm/ADT/StringRef.h" +#include #include -#include namespace lldb_private { @@ -43,7 +43,8 @@ public: enum ManglingScheme { eManglingSchemeNone = 0, eManglingSchemeMSVC, - eManglingSchemeItanium + eManglingSchemeItanium, + eManglingSchemeRustV0 }; /// Default constructor. diff --git a/gnu/llvm/lldb/include/lldb/Core/MappedHash.h b/gnu/llvm/lldb/include/lldb/Core/MappedHash.h index a27ec82b9b8..7bd3c3a7844 100644 --- a/gnu/llvm/lldb/include/lldb/Core/MappedHash.h +++ b/gnu/llvm/lldb/include/lldb/Core/MappedHash.h @@ -9,8 +9,8 @@ #ifndef LLDB_CORE_MAPPEDHASH_H #define LLDB_CORE_MAPPEDHASH_H -#include -#include +#include +#include #include #include @@ -47,19 +47,17 @@ public: uint32_t magic; // HASH_MAGIC or HASH_CIGAM magic value to allow endian detection - uint16_t version; // Version number - uint16_t hash_function; // The hash function enumeration that was used - uint32_t bucket_count; // The number of buckets in this hash table - uint32_t hashes_count; // The total number of unique hash values and hash - // data offsets in this table + uint16_t version = 1; // Version number + uint16_t hash_function = + eHashFunctionDJB; // The hash function enumeration that was used + uint32_t bucket_count = 0; // The number of buckets in this hash table + uint32_t hashes_count = 0; // The total number of unique hash values and + // hash data offsets in this table uint32_t header_data_len; // The size in bytes of the "header_data" template // member below HeaderData header_data; // - Header() - : magic(HASH_MAGIC), version(1), hash_function(eHashFunctionDJB), - bucket_count(0), hashes_count(0), header_data_len(sizeof(T)), - header_data() {} + Header() : magic(HASH_MAGIC), header_data_len(sizeof(T)), header_data() {} virtual ~Header() = default; diff --git a/gnu/llvm/lldb/include/lldb/Core/Module.h b/gnu/llvm/lldb/include/lldb/Core/Module.h index 8bd70ab16b5..dd7100c4616 100644 --- a/gnu/llvm/lldb/include/lldb/Core/Module.h +++ b/gnu/llvm/lldb/include/lldb/Core/Module.h @@ -32,10 +32,10 @@ #include "llvm/Support/Chrono.h" #include +#include +#include #include #include -#include -#include #include #include @@ -506,10 +506,6 @@ public: return m_object_mod_time; } - void SetObjectModificationTime(const llvm::sys::TimePoint<> &mod_time) { - m_mod_time = mod_time; - } - /// This callback will be called by SymbolFile implementations when /// parsing a compile unit that contains SDK information. /// \param sysroot will be added to the path remapping dictionary. @@ -854,13 +850,10 @@ public: /// \param[in] path /// The original source file path to try and remap. /// - /// \param[out] new_path - /// The newly remapped filespec that is may or may not exist. - /// /// \return - /// /b true if \a path was successfully located and \a new_path - /// is filled in with a new source path, \b false otherwise. - bool RemapSourceFile(llvm::StringRef path, std::string &new_path) const; + /// The newly remapped filespec that is may or may not exist if + /// \a path was successfully located. + llvm::Optional RemapSourceFile(llvm::StringRef path) const; bool RemapSourceFile(const char *, std::string &) const = delete; /// Update the ArchSpec to a more specific variant. @@ -889,10 +882,7 @@ public: /// correctly. class LookupInfo { public: - LookupInfo() - : m_name(), m_lookup_name(), m_language(lldb::eLanguageTypeUnknown), - m_name_type_mask(lldb::eFunctionNameTypeNone), - m_match_name_after_lookup(false) {} + LookupInfo() : m_name(), m_lookup_name() {} LookupInfo(ConstString name, lldb::FunctionNameType name_type_mask, lldb::LanguageType language); @@ -921,15 +911,15 @@ public: ConstString m_lookup_name; /// Limit matches to only be for this language - lldb::LanguageType m_language; + lldb::LanguageType m_language = lldb::eLanguageTypeUnknown; /// One or more bits from lldb::FunctionNameType that indicate what kind of /// names we are looking for - lldb::FunctionNameType m_name_type_mask; + lldb::FunctionNameType m_name_type_mask = lldb::eFunctionNameTypeNone; ///< If \b true, then demangled names that match will need to contain ///< "m_name" in order to be considered a match - bool m_match_name_after_lookup; + bool m_match_name_after_lookup = false; }; protected: @@ -956,7 +946,7 @@ protected: ConstString m_object_name; ///< The name an object within this module that is ///selected, or empty of the module is represented ///by \a m_file. - uint64_t m_object_offset; + uint64_t m_object_offset = 0; llvm::sys::TimePoint<> m_object_mod_time; /// DataBuffer containing the module image, if it was provided at diff --git a/gnu/llvm/lldb/include/lldb/Core/ModuleList.h b/gnu/llvm/lldb/include/lldb/Core/ModuleList.h index d90b27e474a..07dddd18357 100644 --- a/gnu/llvm/lldb/include/lldb/Core/ModuleList.h +++ b/gnu/llvm/lldb/include/lldb/Core/ModuleList.h @@ -27,8 +27,8 @@ #include #include -#include -#include +#include +#include namespace lldb_private { class ConstString; @@ -56,7 +56,7 @@ public: ModuleListProperties(); FileSpec GetClangModulesCachePath() const; - bool SetClangModulesCachePath(llvm::StringRef path); + bool SetClangModulesCachePath(const FileSpec &path); bool GetEnableExternalLookup() const; bool SetEnableExternalLookup(bool new_value); @@ -237,20 +237,6 @@ public: /// \see ModuleList::GetSize() Module *GetModulePointerAtIndex(size_t idx) const; - /// Get the module pointer for the module at index \a idx without acquiring - /// the ModuleList mutex. This MUST already have been acquired with - /// ModuleList::GetMutex and locked for this call to be safe. - /// - /// \param[in] idx - /// An index into this module collection. - /// - /// \return - /// A pointer to a Module which can by nullptr if \a idx is out - /// of range. - /// - /// \see ModuleList::GetSize() - Module *GetModulePointerAtIndexUnlocked(size_t idx) const; - /// Find compile units by partial or full path. /// /// Finds all compile units that match \a path in all of the modules and @@ -485,17 +471,19 @@ protected: collection m_modules; ///< The collection of modules. mutable std::recursive_mutex m_modules_mutex; - Notifier *m_notifier; + Notifier *m_notifier = nullptr; public: typedef LockingAdaptedIterable ModuleIterable; - ModuleIterable Modules() { return ModuleIterable(m_modules, GetMutex()); } + ModuleIterable Modules() const { + return ModuleIterable(m_modules, GetMutex()); + } typedef AdaptedIterable ModuleIterableNoLocking; - ModuleIterableNoLocking ModulesNoLocking() { + ModuleIterableNoLocking ModulesNoLocking() const { return ModuleIterableNoLocking(m_modules); } }; diff --git a/gnu/llvm/lldb/include/lldb/Core/ModuleSpec.h b/gnu/llvm/lldb/include/lldb/Core/ModuleSpec.h index 9dd398a0529..8e5deebbab9 100644 --- a/gnu/llvm/lldb/include/lldb/Core/ModuleSpec.h +++ b/gnu/llvm/lldb/include/lldb/Core/ModuleSpec.h @@ -27,12 +27,11 @@ class ModuleSpec { public: ModuleSpec() : m_file(), m_platform_file(), m_symbol_file(), m_arch(), m_uuid(), - m_object_name(), m_object_offset(0), m_object_size(0), - m_source_mappings() {} + m_object_name(), m_source_mappings() {} - /// If the \param data argument is passed, its contents will be used + /// If the \c data argument is passed, its contents will be used /// as the module contents instead of trying to read them from - /// \param file_spec. + /// \c file_spec . ModuleSpec(const FileSpec &file_spec, const UUID &uuid = UUID(), lldb::DataBufferSP data = lldb::DataBufferSP()) : m_file(file_spec), m_platform_file(), m_symbol_file(), m_arch(), @@ -271,8 +270,8 @@ protected: ArchSpec m_arch; UUID m_uuid; ConstString m_object_name; - uint64_t m_object_offset; - uint64_t m_object_size; + uint64_t m_object_offset = 0; + uint64_t m_object_size = 0; llvm::sys::TimePoint<> m_object_mod_time; mutable PathMappingList m_source_mappings; lldb::DataBufferSP m_data = {}; diff --git a/gnu/llvm/lldb/include/lldb/Core/Opcode.h b/gnu/llvm/lldb/include/lldb/Core/Opcode.h index a812ae23f6b..70f2dbdf639 100644 --- a/gnu/llvm/lldb/include/lldb/Core/Opcode.h +++ b/gnu/llvm/lldb/include/lldb/Core/Opcode.h @@ -14,9 +14,9 @@ #include "llvm/Support/SwapByteOrder.h" -#include -#include -#include +#include +#include +#include namespace lldb { class SBInstruction; @@ -38,7 +38,7 @@ public: eTypeBytes }; - Opcode() : m_byte_order(lldb::eByteOrderInvalid), m_type(eTypeInvalid) {} + Opcode() = default; Opcode(uint8_t inst, lldb::ByteOrder order) : m_byte_order(order), m_type(eType8) { @@ -252,9 +252,9 @@ protected: endian::InlHostByteOrder() == lldb::eByteOrderBig); } - lldb::ByteOrder m_byte_order; + lldb::ByteOrder m_byte_order = lldb::eByteOrderInvalid; - Opcode::Type m_type; + Opcode::Type m_type = eTypeInvalid; union { uint8_t inst8; uint16_t inst16; diff --git a/gnu/llvm/lldb/include/lldb/Core/PluginInterface.h b/gnu/llvm/lldb/include/lldb/Core/PluginInterface.h index 17f6dc36715..5bdb2f45b66 100644 --- a/gnu/llvm/lldb/include/lldb/Core/PluginInterface.h +++ b/gnu/llvm/lldb/include/lldb/Core/PluginInterface.h @@ -15,11 +15,15 @@ namespace lldb_private { class PluginInterface { public: - virtual ~PluginInterface() {} + PluginInterface() = default; + virtual ~PluginInterface() = default; virtual ConstString GetPluginName() = 0; virtual uint32_t GetPluginVersion() = 0; + + PluginInterface(const PluginInterface &) = delete; + PluginInterface &operator=(const PluginInterface &) = delete; }; } // namespace lldb_private diff --git a/gnu/llvm/lldb/include/lldb/Core/PluginManager.h b/gnu/llvm/lldb/include/lldb/Core/PluginManager.h index 5e0c9395dae..be91929c62e 100644 --- a/gnu/llvm/lldb/include/lldb/Core/PluginManager.h +++ b/gnu/llvm/lldb/include/lldb/Core/PluginManager.h @@ -19,8 +19,8 @@ #include "lldb/lldb-private-interfaces.h" #include "llvm/ADT/StringRef.h" -#include -#include +#include +#include #define LLDB_PLUGIN_DEFINE_ADV(ClassName, PluginName) \ namespace lldb_private { \ @@ -191,7 +191,8 @@ public: GetObjectFileCreateMemoryCallbackForPluginName(ConstString name); static Status SaveCore(const lldb::ProcessSP &process_sp, - const FileSpec &outfile); + const FileSpec &outfile, + lldb::SaveCoreStyle &core_style); // ObjectContainer static bool @@ -330,6 +331,66 @@ public: static SymbolVendorCreateInstance GetSymbolVendorCreateCallbackAtIndex(uint32_t idx); + // Trace + static bool RegisterPlugin( + ConstString name, const char *description, + TraceCreateInstanceForSessionFile create_callback_for_session_file, + TraceCreateInstanceForLiveProcess create_callback_for_live_process, + llvm::StringRef schema); + + static bool + UnregisterPlugin(TraceCreateInstanceForSessionFile create_callback); + + static TraceCreateInstanceForSessionFile + GetTraceCreateCallback(ConstString plugin_name); + + static TraceCreateInstanceForLiveProcess + GetTraceCreateCallbackForLiveProcess(ConstString plugin_name); + + /// Get the JSON schema for a trace session file corresponding to the given + /// plugin. + /// + /// \param[in] plugin_name + /// The name of the plugin. + /// + /// \return + /// An empty \a StringRef if no plugin was found with that plugin name, + /// otherwise the actual schema is returned. + static llvm::StringRef GetTraceSchema(ConstString plugin_name); + + /// Get the JSON schema for a trace session file corresponding to the plugin + /// given by its index. + /// + /// \param[in] index + /// The index of the plugin to get the schema of. + /// + /// \return + /// An empty \a StringRef if the index is greater than or equal to the + /// number plugins, otherwise the actual schema is returned. + static llvm::StringRef GetTraceSchema(size_t index); + + // TraceExporter + + /// \param[in] create_thread_trace_export_command + /// This callback is used to create a CommandObject that will be listed + /// under "thread trace export". Can be \b null. + static bool RegisterPlugin( + ConstString name, const char *description, + TraceExporterCreateInstance create_callback, + ThreadTraceExportCommandCreator create_thread_trace_export_command); + + static TraceExporterCreateInstance + GetTraceExporterCreateCallback(ConstString plugin_name); + + static bool UnregisterPlugin(TraceExporterCreateInstance create_callback); + + static const char *GetTraceExporterPluginNameAtIndex(uint32_t index); + + /// Return the callback used to create the CommandObject that will be listed + /// under "thread trace export". Can be \b null. + static ThreadTraceExportCommandCreator + GetThreadTraceExportCommandCreatorAtIndex(uint32_t index); + // UnwindAssembly static bool RegisterPlugin(ConstString name, const char *description, UnwindAssemblyCreateInstance create_callback); diff --git a/gnu/llvm/lldb/include/lldb/Core/Progress.h b/gnu/llvm/lldb/include/lldb/Core/Progress.h new file mode 100644 index 00000000000..f625d014f26 --- /dev/null +++ b/gnu/llvm/lldb/include/lldb/Core/Progress.h @@ -0,0 +1,114 @@ +//===-- Progress.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_CORE_PROGRESS_H +#define LLDB_CORE_PROGRESS_H + +#include "lldb/Utility/ConstString.h" +#include "lldb/lldb-types.h" +#include +#include + +namespace lldb_private { + +/// A Progress indicator helper class. +/// +/// Any potentially long running sections of code in LLDB should report +/// progress so that clients are aware of delays that might appear during +/// debugging. Delays commonly include indexing debug information, parsing +/// symbol tables for object files, downloading symbols from remote +/// repositories, and many more things. +/// +/// The Progress class helps make sure that progress is correctly reported +/// and will always send an initial progress update, updates when +/// Progress::Increment() is called, and also will make sure that a progress +/// completed update is reported even if the user doesn't explicitly cause one +/// to be sent. +/// +/// The progress is reported via a callback whose type is ProgressCallback: +/// +/// typedef void (*ProgressCallback)(uint64_t progress_id, +/// const char *message, +/// uint64_t completed, +/// uint64_t total, +/// void *baton); +/// +/// This callback will always initially be called with "completed" set to zero +/// and "total" set to the total amount specified in the contructor. This is +/// considered the progress start event. As Progress::Increment() is called, +/// the callback will be called as long as the Progress::m_completed has not +/// yet exceeded the Progress::m_total. When the callback is called with +/// Progress::m_completed == Progress::m_total, that is considered a progress +/// completed event. If Progress::m_completed is non-zero and less than +/// Progress::m_total, then this is considered a progress update event. +/// +/// This callback will be called in the destructor if Progress::m_completed is +/// not equal to Progress::m_total with the "completed" set to +/// Progress::m_total. This ensures we always send a progress completed update +/// even if the user does not. + +class Progress { +public: + /// Construct a progress object that will report information. + /// + /// The constructor will create a unique progress reporting object and + /// immediately send out a progress update by calling the installed callback + /// with completed set to zero out of the specified total. + /// + /// @param [in] title The title of this progress activity. + /// + /// @param [in] total The total units of work to be done if specified, if + /// set to UINT64_MAX then an indeterminate progress indicator should be + /// displayed. + /// + /// @param [in] debugger An optional debugger pointer to specify that this + /// progress is to be reported only to specific debuggers. + Progress(std::string title, uint64_t total = UINT64_MAX, + lldb_private::Debugger *debugger = nullptr); + + /// Destroy the progress object. + /// + /// If the progress has not yet sent a completion update, the destructor + /// will send out a notification where the completed == m_total. This ensures + /// that we always send out a progress complete notification. + ~Progress(); + + /// Increment the progress and send a notification to the intalled callback. + /// + /// If incrementing ends up exceeding m_total, m_completed will be updated + /// to match m_total and no subsequent progress notifications will be sent. + /// If no total was specified in the constructor, this function will not do + /// anything nor send any progress updates. + /// + /// @param [in] amount The amount to increment m_completed by. + void Increment(uint64_t amount = 1); + +private: + void ReportProgress(); + static std::atomic g_id; + /// The title of the progress activity. + std::string m_title; + std::mutex m_mutex; + /// A unique integer identifier for progress reporting. + const uint64_t m_id; + /// How much work ([0...m_total]) that has been completed. + uint64_t m_completed; + /// Total amount of work, UINT64_MAX for non deterministic progress. + const uint64_t m_total; + /// The optional debugger ID to report progress to. If this has no value then + /// all debuggers will receive this event. + llvm::Optional m_debugger_id; + /// Set to true when progress has been reported where m_completed == m_total + /// to ensure that we don't send progress updates after progress has + /// completed. + bool m_complete = false; +}; + +} // namespace lldb_private + +#endif // LLDB_CORE_PROGRESS_H diff --git a/gnu/llvm/lldb/include/lldb/Core/RichManglingContext.h b/gnu/llvm/lldb/include/lldb/Core/RichManglingContext.h index 68f80e73b72..48102ec0b1c 100644 --- a/gnu/llvm/lldb/include/lldb/Core/RichManglingContext.h +++ b/gnu/llvm/lldb/include/lldb/Core/RichManglingContext.h @@ -24,12 +24,12 @@ namespace lldb_private { /// providers. See Mangled::DemangleWithRichManglingInfo() class RichManglingContext { public: - RichManglingContext() : m_provider(None), m_ipd_buf_size(2048) { + RichManglingContext() { m_ipd_buf = static_cast(std::malloc(m_ipd_buf_size)); m_ipd_buf[0] = '\0'; } - ~RichManglingContext() { std::free(m_ipd_buf); } + ~RichManglingContext(); /// Use the ItaniumPartialDemangler to obtain rich mangling information from /// the given mangled name. @@ -70,15 +70,18 @@ private: enum InfoProvider { None, ItaniumPartialDemangler, PluginCxxLanguage }; /// Selects the rich mangling info provider. - InfoProvider m_provider; + InfoProvider m_provider = None; /// Reference to the buffer used for results of ParseXy() operations. llvm::StringRef m_buffer; /// Members for ItaniumPartialDemangler llvm::ItaniumPartialDemangler m_ipd; + /// Note: m_ipd_buf is a raw pointer due to being resized by realloc via + /// ItaniumPartialDemangler. It should be managed with malloc/free, not + /// new/delete. char *m_ipd_buf; - size_t m_ipd_buf_size; + size_t m_ipd_buf_size = 2048; /// Members for PluginCxxLanguage /// Cannot forward declare inner class CPlusPlusLanguage::MethodName. The @@ -86,6 +89,9 @@ private: /// dependency. Instead keep a llvm::Any and cast it on-access in the cpp. llvm::Any m_cxx_method_parser; + /// Clean up memory when using PluginCxxLanguage + void ResetCxxMethodParser(); + /// Clean up memory and set a new info provider for this instance. void ResetProvider(InfoProvider new_provider); diff --git a/gnu/llvm/lldb/include/lldb/Core/SearchFilter.h b/gnu/llvm/lldb/include/lldb/Core/SearchFilter.h index 54dc65e4410..491e3ddc598 100644 --- a/gnu/llvm/lldb/include/lldb/Core/SearchFilter.h +++ b/gnu/llvm/lldb/include/lldb/Core/SearchFilter.h @@ -15,7 +15,7 @@ #include "lldb/Utility/FileSpec.h" #include "lldb/lldb-forward.h" -#include +#include namespace lldb_private { class Address; diff --git a/gnu/llvm/lldb/include/lldb/Core/Section.h b/gnu/llvm/lldb/include/lldb/Core/Section.h index af2bb7896a5..3d4ab154e74 100644 --- a/gnu/llvm/lldb/include/lldb/Core/Section.h +++ b/gnu/llvm/lldb/include/lldb/Core/Section.h @@ -21,8 +21,8 @@ #include #include -#include -#include +#include +#include namespace lldb_private { class Address; diff --git a/gnu/llvm/lldb/include/lldb/Core/SourceLocationSpec.h b/gnu/llvm/lldb/include/lldb/Core/SourceLocationSpec.h new file mode 100644 index 00000000000..808931186db --- /dev/null +++ b/gnu/llvm/lldb/include/lldb/Core/SourceLocationSpec.h @@ -0,0 +1,188 @@ +//===-- SourceLocationSpec.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_UTILITY_SOURCELOCATIONSPEC_H +#define LLDB_UTILITY_SOURCELOCATIONSPEC_H + +#include "lldb/Core/Declaration.h" +#include "lldb/lldb-defines.h" +#include "llvm/ADT/Optional.h" + +#include + +namespace lldb_private { + +/// \class SourceLocationSpec SourceLocationSpec.h +/// "lldb/Core/SourceLocationSpec.h" A source location specifier class. +/// +/// A source location specifier class that holds a Declaration object containing +/// a FileSpec with line and column information. The column line is optional. +/// It also holds search flags that can be fetched by resolvers to look inlined +/// declarations and/or exact matches. +class SourceLocationSpec { +public: + /// Constructor. + /// + /// Takes a \a file_spec with a \a line number and a \a column number. If + /// \a column is null or not provided, it is set to llvm::None. + /// + /// \param[in] file_spec + /// The full or partial path to a file. + /// + /// \param[in] line + /// The line number in the source file. + /// + /// \param[in] column + /// The column number in the line of the source file. + /// + /// \param[in] check_inlines + /// Whether to look for a match in inlined declaration. + /// + /// \param[in] exact_match + /// Whether to look for an exact match. + /// + explicit SourceLocationSpec(FileSpec file_spec, uint32_t line, + llvm::Optional column = llvm::None, + bool check_inlines = false, + bool exact_match = false); + + SourceLocationSpec() = delete; + + /// Convert to boolean operator. + /// + /// This allows code to check a SourceLocationSpec object to see if it + /// contains anything valid using code such as: + /// + /// \code + /// SourceLocationSpec location_spec(...); + /// if (location_spec) + /// { ... + /// \endcode + /// + /// \return + /// A pointer to this object if both the file_spec and the line are valid, + /// nullptr otherwise. + explicit operator bool() const; + + /// Logical NOT operator. + /// + /// This allows code to check a SourceLocationSpec object to see if it is + /// invalid using code such as: + /// + /// \code + /// SourceLocationSpec location_spec(...); + /// if (!location_spec) + /// { ... + /// \endcode + /// + /// \return + /// Returns \b true if the object has an invalid file_spec or line number, + /// \b false otherwise. + bool operator!() const; + + /// Equal to operator + /// + /// Tests if this object is equal to \a rhs. + /// + /// \param[in] rhs + /// A const SourceLocationSpec object reference to compare this object + /// to. + /// + /// \return + /// \b true if this object is equal to \a rhs, \b false + /// otherwise. + bool operator==(const SourceLocationSpec &rhs) const; + + /// Not equal to operator + /// + /// Tests if this object is not equal to \a rhs. + /// + /// \param[in] rhs + /// A const SourceLocationSpec object reference to compare this object + /// to. + /// + /// \return + /// \b true if this object is equal to \a rhs, \b false + /// otherwise. + bool operator!=(const SourceLocationSpec &rhs) const; + + /// Less than to operator + /// + /// Tests if this object is less than \a rhs. + /// + /// \param[in] rhs + /// A const SourceLocationSpec object reference to compare this object + /// to. + /// + /// \return + /// \b true if this object is less than \a rhs, \b false + /// otherwise. + bool operator<(const SourceLocationSpec &rhs) const; + + /// Compare two SourceLocationSpec objects. + /// + /// If \a full is true, then the file_spec, the line and column must match. + /// If \a full is false, then only the file_spec and line number for \a lhs + /// and \a rhs are compared. This allows a SourceLocationSpec object that have + /// no column information to match a SourceLocationSpec objects that have + /// column information with matching file_spec and line component. + /// + /// \param[in] lhs + /// A const reference to the Left Hand Side object to compare. + /// + /// \param[in] rhs + /// A const reference to the Right Hand Side object to compare. + /// + /// \param[in] full + /// If true, then the file_spec, the line and column must match for a + /// compare to return zero (equal to). If false, then only the file_spec + /// and line number for \a lhs and \a rhs are compared, else a full + /// comparison is done. + /// + /// \return -1 if \a lhs is less than \a rhs, 0 if \a lhs is equal to \a rhs, + /// 1 if \a lhs is greater than \a rhs + static int Compare(const SourceLocationSpec &lhs, + const SourceLocationSpec &rhs); + + static bool Equal(const SourceLocationSpec &lhs, + const SourceLocationSpec &rhs, bool full); + + /// Dump this object to a Stream. + /// + /// Dump the object to the supplied stream \a s, starting with the file name, + /// then the line number and if available the column number. + /// + /// \param[in] s + /// The stream to which to dump the object description. + void Dump(Stream &s) const; + + std::string GetString() const; + + FileSpec GetFileSpec() const { return m_declaration.GetFile(); } + + llvm::Optional GetLine() const; + + llvm::Optional GetColumn() const; + + bool GetCheckInlines() const { return m_check_inlines; } + + bool GetExactMatch() const { return m_exact_match; } + +protected: + Declaration m_declaration; + /// Tells if the resolver should look in inlined declaration. + bool m_check_inlines; + /// Tells if the resolver should look for an exact match. + bool m_exact_match; +}; + +/// Dump a SourceLocationSpec object to a stream +Stream &operator<<(Stream &s, const SourceLocationSpec &loc); +} // namespace lldb_private + +#endif // LLDB_UTILITY_SOURCELOCATIONSPEC_H diff --git a/gnu/llvm/lldb/include/lldb/Core/SourceManager.h b/gnu/llvm/lldb/include/lldb/Core/SourceManager.h index 7549c308f33..5f2c1de8465 100644 --- a/gnu/llvm/lldb/include/lldb/Core/SourceManager.h +++ b/gnu/llvm/lldb/include/lldb/Core/SourceManager.h @@ -15,10 +15,10 @@ #include "llvm/Support/Chrono.h" +#include #include #include #include -#include #include #include diff --git a/gnu/llvm/lldb/include/lldb/Core/StreamAsynchronousIO.h b/gnu/llvm/lldb/include/lldb/Core/StreamAsynchronousIO.h index 949a798955d..30eff55b2e5 100644 --- a/gnu/llvm/lldb/include/lldb/Core/StreamAsynchronousIO.h +++ b/gnu/llvm/lldb/include/lldb/Core/StreamAsynchronousIO.h @@ -13,7 +13,7 @@ #include -#include +#include namespace lldb_private { class Debugger; diff --git a/gnu/llvm/lldb/include/lldb/Core/StreamBuffer.h b/gnu/llvm/lldb/include/lldb/Core/StreamBuffer.h index 9c48ddb44d7..2e61a214302 100644 --- a/gnu/llvm/lldb/include/lldb/Core/StreamBuffer.h +++ b/gnu/llvm/lldb/include/lldb/Core/StreamBuffer.h @@ -11,7 +11,7 @@ #include "lldb/Utility/Stream.h" #include "llvm/ADT/SmallVector.h" -#include +#include #include namespace lldb_private { @@ -23,7 +23,7 @@ public: StreamBuffer(uint32_t flags, uint32_t addr_size, lldb::ByteOrder byte_order) : Stream(flags, addr_size, byte_order), m_packet() {} - ~StreamBuffer() override {} + ~StreamBuffer() override = default; void Flush() override { // Nothing to do when flushing a buffer based stream... diff --git a/gnu/llvm/lldb/include/lldb/Core/StreamFile.h b/gnu/llvm/lldb/include/lldb/Core/StreamFile.h index e71e31eb1d0..dba4042b6ec 100644 --- a/gnu/llvm/lldb/include/lldb/Core/StreamFile.h +++ b/gnu/llvm/lldb/include/lldb/Core/StreamFile.h @@ -14,8 +14,8 @@ #include "lldb/lldb-defines.h" #include "lldb/lldb-enumerations.h" -#include -#include +#include +#include namespace lldb_private { diff --git a/gnu/llvm/lldb/include/lldb/Core/StructuredDataImpl.h b/gnu/llvm/lldb/include/lldb/Core/StructuredDataImpl.h index 9aea645a3ea..929ce21fb2f 100644 --- a/gnu/llvm/lldb/include/lldb/Core/StructuredDataImpl.h +++ b/gnu/llvm/lldb/include/lldb/Core/StructuredDataImpl.h @@ -68,14 +68,18 @@ public: return error; } - // Grab the plugin. - auto plugin_sp = lldb::StructuredDataPluginSP(m_plugin_wp); + // Grab the plugin + lldb::StructuredDataPluginSP plugin_sp = m_plugin_wp.lock(); + + // If there's no plugin, call underlying data's dump method: if (!plugin_sp) { - error.SetErrorString("Cannot pretty print structured data: " - "plugin doesn't exist."); + if (!m_data_sp) { + error.SetErrorString("No data to describe."); + return error; + } + m_data_sp->Dump(stream, true); return error; } - // Get the data's description. return plugin_sp->GetDescription(m_data_sp, stream); } diff --git a/gnu/llvm/lldb/include/lldb/Core/ThreadSafeValue.h b/gnu/llvm/lldb/include/lldb/Core/ThreadSafeValue.h index 38b8034fad5..51820ec9cd9 100644 --- a/gnu/llvm/lldb/include/lldb/Core/ThreadSafeValue.h +++ b/gnu/llvm/lldb/include/lldb/Core/ThreadSafeValue.h @@ -17,12 +17,10 @@ namespace lldb_private { template class ThreadSafeValue { public: - // Constructors and Destructors - ThreadSafeValue() : m_value(), m_mutex() {} - + ThreadSafeValue() = default; ThreadSafeValue(const T &value) : m_value(value), m_mutex() {} - ~ThreadSafeValue() {} + ~ThreadSafeValue() = default; T GetValue() const { T value; diff --git a/gnu/llvm/lldb/include/lldb/Core/UserSettingsController.h b/gnu/llvm/lldb/include/lldb/Core/UserSettingsController.h index f40ad54ac4d..35555f08c35 100644 --- a/gnu/llvm/lldb/include/lldb/Core/UserSettingsController.h +++ b/gnu/llvm/lldb/include/lldb/Core/UserSettingsController.h @@ -17,8 +17,8 @@ #include -#include -#include +#include +#include namespace lldb_private { class CommandInterpreter; @@ -32,12 +32,12 @@ namespace lldb_private { class Properties { public: - Properties() : m_collection_sp() {} + Properties() = default; Properties(const lldb::OptionValuePropertiesSP &collection_sp) : m_collection_sp(collection_sp) {} - virtual ~Properties() {} + virtual ~Properties() = default; virtual lldb::OptionValuePropertiesSP GetValueProperties() const { // This function is virtual in case subclasses want to lazily implement diff --git a/gnu/llvm/lldb/include/lldb/Core/Value.h b/gnu/llvm/lldb/include/lldb/Core/Value.h index 641a64a3bbb..1ee4fe639e6 100644 --- a/gnu/llvm/lldb/include/lldb/Core/Value.h +++ b/gnu/llvm/lldb/include/lldb/Core/Value.h @@ -21,8 +21,8 @@ #include -#include -#include +#include +#include namespace lldb_private { class DataExtractor; @@ -37,91 +37,36 @@ namespace lldb_private { class Value { public: - // Values Less than zero are an error, greater than or equal to zero returns - // what the Scalar result is. - enum ValueType { - // m_value contains... - // ============================ - eValueTypeScalar, // raw scalar value - eValueTypeVector, // byte array of m_vector.length with endianness of - // m_vector.byte_order - eValueTypeFileAddress, // file address value - eValueTypeLoadAddress, // load address value - eValueTypeHostAddress // host address value (for memory in the process that - // is using liblldb) + /// Type that describes Value::m_value. + enum class ValueType { + Invalid = -1, + // m_value contains: + /// A raw scalar value. + Scalar = 0, + /// A file address value. + FileAddress, + /// A load address value. + LoadAddress, + /// A host address value (for memory in the process that < A is + /// using liblldb). + HostAddress }; - enum ContextType // Type that describes Value::m_context - { - // m_context contains... - // ==================== - eContextTypeInvalid, // undefined - eContextTypeRegisterInfo, // RegisterInfo * (can be a scalar or a vector - // register) - eContextTypeLLDBType, // lldb_private::Type * - eContextTypeVariable // lldb_private::Variable * - }; - - const static size_t kMaxByteSize = 32u; - - struct Vector { - // The byte array must be big enough to hold vector registers for any - // supported target. - uint8_t bytes[kMaxByteSize]; - size_t length; - lldb::ByteOrder byte_order; - - Vector() : length(0), byte_order(lldb::eByteOrderInvalid) {} - - Vector(const Vector &vector) { *this = vector; } - const Vector &operator=(const Vector &vector) { - SetBytes(vector.bytes, vector.length, vector.byte_order); - return *this; - } - - void Clear() { length = 0; } - - bool SetBytes(const void *bytes, size_t length, - lldb::ByteOrder byte_order) { - this->length = length; - this->byte_order = byte_order; - if (length) - ::memcpy(this->bytes, bytes, - length < kMaxByteSize ? length : kMaxByteSize); - return IsValid(); - } - - bool IsValid() const { - return (length > 0 && length < kMaxByteSize && - byte_order != lldb::eByteOrderInvalid); - } - // Casts a vector, if valid, to an unsigned int of matching or largest - // supported size. Truncates to the beginning of the vector if required. - // Returns a default constructed Scalar if the Vector data is internally - // inconsistent. - llvm::APInt rhs = llvm::APInt(BITWIDTH_INT128, NUM_OF_WORDS_INT128, - ((type128 *)bytes)->x); - Scalar GetAsScalar() const { - Scalar scalar; - if (IsValid()) { - if (length == 1) - scalar = *(const uint8_t *)bytes; - else if (length == 2) - scalar = *(const uint16_t *)bytes; - else if (length == 4) - scalar = *(const uint32_t *)bytes; - else if (length == 8) - scalar = *(const uint64_t *)bytes; - else if (length >= 16) - scalar = rhs; - } - return scalar; - } + /// Type that describes Value::m_context. + enum class ContextType { + // m_context contains: + /// Undefined. + Invalid = -1, + /// RegisterInfo * (can be a scalar or a vector register). + RegisterInfo = 0, + /// lldb_private::Type *. + LLDBType, + /// lldb_private::Variable *. + Variable }; Value(); Value(const Scalar &scalar); - Value(const Vector &vector); Value(const void *bytes, int len); Value(const Value &rhs); @@ -145,17 +90,16 @@ public: void ClearContext() { m_context = nullptr; - m_context_type = eContextTypeInvalid; + m_context_type = ContextType::Invalid; } void SetContext(ContextType context_type, void *p) { m_context_type = context_type; m_context = p; - if (m_context_type == eContextTypeRegisterInfo) { + if (m_context_type == ContextType::RegisterInfo) { RegisterInfo *reg_info = GetRegisterInfo(); - if (reg_info->encoding == lldb::eEncodingVector && - m_vector.byte_order != lldb::eByteOrderInvalid) - SetValueType(eValueTypeScalar); + if (reg_info->encoding == lldb::eEncodingVector) + SetValueType(ValueType::Scalar); } } @@ -167,30 +111,8 @@ public: const Scalar &GetScalar() const { return m_value; } - const Vector &GetVector() const { return m_vector; } - Scalar &GetScalar() { return m_value; } - Vector &GetVector() { return m_vector; } - - bool SetVectorBytes(const Vector &vector) { - m_vector = vector; - return m_vector.IsValid(); - } - - bool SetVectorBytes(uint8_t *bytes, size_t length, - lldb::ByteOrder byte_order) { - return m_vector.SetBytes(bytes, length, byte_order); - } - - bool SetScalarFromVector() { - if (m_vector.IsValid()) { - m_value = m_vector.GetAsScalar(); - return true; - } - return false; - } - size_t ResizeData(size_t len); size_t AppendDataToHostBuffer(const Value &rhs); @@ -225,11 +147,10 @@ public: protected: Scalar m_value; - Vector m_vector; CompilerType m_compiler_type; - void *m_context; - ValueType m_value_type; - ContextType m_context_type; + void *m_context = nullptr; + ValueType m_value_type = ValueType::Scalar; + ContextType m_context_type = ContextType::Invalid; DataBufferHeap m_data_buffer; }; diff --git a/gnu/llvm/lldb/include/lldb/Core/ValueObject.h b/gnu/llvm/lldb/include/lldb/Core/ValueObject.h index 0080368fd99..5f1cbc65b32 100644 --- a/gnu/llvm/lldb/include/lldb/Core/ValueObject.h +++ b/gnu/llvm/lldb/include/lldb/Core/ValueObject.h @@ -37,8 +37,8 @@ #include #include -#include -#include +#include +#include namespace lldb_private { class Declaration; @@ -102,7 +102,7 @@ class TypeSummaryOptions; /// Shared Pointer to the contained ValueObject, /// just do so by calling GetSP() on the contained object. -class ValueObject : public UserID { +class ValueObject { public: enum GetExpressionPathFormat { eGetExpressionPathFormatDereferencePointers = 1, @@ -121,55 +121,62 @@ public: }; enum ExpressionPathScanEndReason { - eExpressionPathScanEndReasonEndOfString = 1, // out of data to parse - eExpressionPathScanEndReasonNoSuchChild, // child element not found - eExpressionPathScanEndReasonNoSuchSyntheticChild, // (synthetic) child - // element not found - eExpressionPathScanEndReasonEmptyRangeNotAllowed, // [] only allowed for - // arrays - eExpressionPathScanEndReasonDotInsteadOfArrow, // . used when -> should be - // used - eExpressionPathScanEndReasonArrowInsteadOfDot, // -> used when . should be - // used - eExpressionPathScanEndReasonFragileIVarNotAllowed, // ObjC ivar expansion - // not allowed - eExpressionPathScanEndReasonRangeOperatorNotAllowed, // [] not allowed by - // options - eExpressionPathScanEndReasonRangeOperatorInvalid, // [] not valid on objects - // other than scalars, - // pointers or arrays - eExpressionPathScanEndReasonArrayRangeOperatorMet, // [] is good for arrays, - // but I cannot parse it - eExpressionPathScanEndReasonBitfieldRangeOperatorMet, // [] is good for - // bitfields, but I - // cannot parse after - // it - eExpressionPathScanEndReasonUnexpectedSymbol, // something is malformed in - // the expression - eExpressionPathScanEndReasonTakingAddressFailed, // impossible to apply & - // operator - eExpressionPathScanEndReasonDereferencingFailed, // impossible to apply * - // operator - eExpressionPathScanEndReasonRangeOperatorExpanded, // [] was expanded into a - // VOList - eExpressionPathScanEndReasonSyntheticValueMissing, // getting the synthetic - // children failed + /// Out of data to parse. + eExpressionPathScanEndReasonEndOfString = 1, + /// Child element not found. + eExpressionPathScanEndReasonNoSuchChild, + /// (Synthetic) child element not found. + eExpressionPathScanEndReasonNoSuchSyntheticChild, + /// [] only allowed for arrays. + eExpressionPathScanEndReasonEmptyRangeNotAllowed, + /// . used when -> should be used. + eExpressionPathScanEndReasonDotInsteadOfArrow, + /// -> used when . should be used. + eExpressionPathScanEndReasonArrowInsteadOfDot, + /// ObjC ivar expansion not allowed. + eExpressionPathScanEndReasonFragileIVarNotAllowed, + /// [] not allowed by options. + eExpressionPathScanEndReasonRangeOperatorNotAllowed, + /// [] not valid on objects other than scalars, pointers or arrays. + eExpressionPathScanEndReasonRangeOperatorInvalid, + /// [] is good for arrays, but I cannot parse it. + eExpressionPathScanEndReasonArrayRangeOperatorMet, + /// [] is good for bitfields, but I cannot parse after it. + eExpressionPathScanEndReasonBitfieldRangeOperatorMet, + /// Something is malformed in he expression. + eExpressionPathScanEndReasonUnexpectedSymbol, + /// Impossible to apply & operator. + eExpressionPathScanEndReasonTakingAddressFailed, + /// Impossible to apply * operator. + eExpressionPathScanEndReasonDereferencingFailed, + /// [] was expanded into a VOList. + eExpressionPathScanEndReasonRangeOperatorExpanded, + /// getting the synthetic children failed. + eExpressionPathScanEndReasonSyntheticValueMissing, eExpressionPathScanEndReasonUnknown = 0xFFFF }; enum ExpressionPathEndResultType { - eExpressionPathEndResultTypePlain = 1, // anything but... - eExpressionPathEndResultTypeBitfield, // a bitfield - eExpressionPathEndResultTypeBoundedRange, // a range [low-high] - eExpressionPathEndResultTypeUnboundedRange, // a range [] - eExpressionPathEndResultTypeValueObjectList, // several items in a VOList + /// Anything but... + eExpressionPathEndResultTypePlain = 1, + /// A bitfield. + eExpressionPathEndResultTypeBitfield, + /// A range [low-high]. + eExpressionPathEndResultTypeBoundedRange, + /// A range []. + eExpressionPathEndResultTypeUnboundedRange, + /// Several items in a VOList. + eExpressionPathEndResultTypeValueObjectList, eExpressionPathEndResultTypeInvalid = 0xFFFF }; enum ExpressionPathAftermath { - eExpressionPathAftermathNothing = 1, // just return it - eExpressionPathAftermathDereference, // dereference the target - eExpressionPathAftermathTakeAddress // take target's address + /// Just return it. + eExpressionPathAftermathNothing = 1, + /// Dereference the target. + eExpressionPathAftermathDereference, + /// Take target's address. + eExpressionPathAftermathTakeAddress }; enum ClearUserVisibleDataItems { @@ -265,14 +272,6 @@ public: return m_exe_ctx_ref; } - // Set the EvaluationPoint to the values in exe_scope, Return true if the - // Evaluation Point changed. Since the ExecutionContextScope is always - // going to be valid currently, the Updated Context will also always be - // valid. - - // bool - // SetContext (ExecutionContextScope *exe_scope); - void SetIsConstant() { SetUpdated(); m_mod_id.SetInvalid(); @@ -319,7 +318,7 @@ public: ProcessModID m_mod_id; // This is the stop id when this ValueObject was last // evaluated. ExecutionContextRef m_exe_ctx_ref; - bool m_needs_update; + bool m_needs_update = true; }; virtual ~ValueObject(); @@ -350,37 +349,45 @@ public: void SetNeedsUpdate(); - CompilerType GetCompilerType(); + CompilerType GetCompilerType() { return MaybeCalculateCompleteType(); } // this vends a TypeImpl that is useful at the SB API layer - virtual TypeImpl GetTypeImpl(); + virtual TypeImpl GetTypeImpl() { return TypeImpl(GetCompilerType()); } virtual bool CanProvideValue(); // Subclasses must implement the functions below. - virtual uint64_t GetByteSize() = 0; + virtual llvm::Optional GetByteSize() = 0; virtual lldb::ValueType GetValueType() const = 0; // Subclasses can implement the functions below. - virtual ConstString GetTypeName(); + virtual ConstString GetTypeName() { return GetCompilerType().GetTypeName(); } - virtual ConstString GetDisplayTypeName(); + virtual ConstString GetDisplayTypeName() { return GetTypeName(); } - virtual ConstString GetQualifiedTypeName(); + virtual ConstString GetQualifiedTypeName() { + return GetCompilerType().GetTypeName(); + } - virtual lldb::LanguageType GetObjectRuntimeLanguage(); + virtual lldb::LanguageType GetObjectRuntimeLanguage() { + return GetCompilerType().GetMinimumLanguage(); + } virtual uint32_t - GetTypeInfo(CompilerType *pointee_or_element_compiler_type = nullptr); + GetTypeInfo(CompilerType *pointee_or_element_compiler_type = nullptr) { + return GetCompilerType().GetTypeInfo(pointee_or_element_compiler_type); + } - virtual bool IsPointerType(); + virtual bool IsPointerType() { return GetCompilerType().IsPointerType(); } - virtual bool IsArrayType(); + virtual bool IsArrayType() { return GetCompilerType().IsArrayType(); } - virtual bool IsScalarType(); + virtual bool IsScalarType() { return GetCompilerType().IsScalarType(); } - virtual bool IsPointerOrReferenceType(); + virtual bool IsPointerOrReferenceType() { + return GetCompilerType().IsPointerOrReferenceType(); + } virtual bool IsPossibleDynamicType(); @@ -394,7 +401,9 @@ public: virtual bool IsDereferenceOfParent() { return false; } - bool IsIntegerType(bool &is_signed); + bool IsIntegerType(bool &is_signed) { + return GetCompilerType().IsIntegerType(is_signed); + } virtual void GetExpressionPath( Stream &s, @@ -420,7 +429,9 @@ public: return (GetBitfieldBitSize() != 0) || (GetBitfieldBitOffset() != 0); } - virtual bool IsArrayItemForPointer() { return m_is_array_item_for_pointer; } + virtual bool IsArrayItemForPointer() { + return m_flags.m_is_array_item_for_pointer; + } virtual const char *GetValueAsCString(); @@ -436,16 +447,16 @@ public: virtual bool SetValueFromCString(const char *value_str, Status &error); - // Return the module associated with this value object in case the value is - // from an executable file and might have its data in sections of the file. - // This can be used for variables. + /// Return the module associated with this value object in case the value is + /// from an executable file and might have its data in sections of the file. + /// This can be used for variables. virtual lldb::ModuleSP GetModule(); ValueObject *GetRoot(); - // Given a ValueObject, loop over itself and its parent, and its parent's - // parent, .. until either the given callback returns false, or you end up at - // a null pointer + /// Given a ValueObject, loop over itself and its parent, and its parent's + /// parent, .. until either the given callback returns false, or you end up at + /// a null pointer ValueObject *FollowParentChain(std::function); virtual bool GetDeclaration(Declaration &decl); @@ -453,7 +464,10 @@ public: // The functions below should NOT be modified by subclasses const Status &GetError(); - ConstString GetName() const; + ConstString GetName() const { return m_name; } + + /// Returns a unique id for this ValueObject. + lldb::user_id_t GetID() const { return m_id.GetID(); } virtual lldb::ValueObjectSP GetChildAtIndex(size_t idx, bool can_create); @@ -480,9 +494,9 @@ public: size_t GetNumChildren(uint32_t max = UINT32_MAX); - const Value &GetValue() const; + const Value &GetValue() const { return m_value; } - Value &GetValue(); + Value &GetValue() { return m_value; } virtual bool ResolveValue(Scalar &scalar); @@ -491,7 +505,9 @@ public: // potentially a few others virtual bool IsLogicalTrue(Status &error); - virtual const char *GetLocationAsCString(); + virtual const char *GetLocationAsCString() { + return GetLocationAsCStringImpl(m_value, m_data); + } const char * GetSummaryAsCString(lldb::LanguageType lang = lldb::eLanguageTypeUnknown); @@ -526,11 +542,11 @@ public: PrintableRepresentationSpecialCases special = PrintableRepresentationSpecialCases::eAllow, bool do_dump_error = true); - bool GetValueIsValid() const; + bool GetValueIsValid() const { return m_flags.m_value_is_valid; } // If you call this on a newly created ValueObject, it will always return // false. - bool GetValueDidChange(); + bool GetValueDidChange() { return m_flags.m_value_did_change; } bool UpdateValueIfNeeded(bool update_format = true); @@ -538,10 +554,10 @@ public: lldb::ValueObjectSP GetSP() { return m_manager->GetSharedPointer(this); } - // Change the name of the current ValueObject. Should *not* be used from a - // synthetic child provider as it would change the name of the non synthetic - // child as well. - void SetName(ConstString name); + /// Change the name of the current ValueObject. Should *not* be used from a + /// synthetic child provider as it would change the name of the non synthetic + /// child as well. + void SetName(ConstString name) { m_name = name; } virtual lldb::addr_t GetAddressOf(bool scalar_is_load_address = true, AddressType *address_type = nullptr); @@ -571,9 +587,9 @@ public: lldb::DynamicValueType GetDynamicValueType(); - virtual lldb::ValueObjectSP GetStaticValue(); + virtual lldb::ValueObjectSP GetStaticValue() { return GetSP(); } - virtual lldb::ValueObjectSP GetNonSyntheticValue(); + virtual lldb::ValueObjectSP GetNonSyntheticValue() { return GetSP(); } lldb::ValueObjectSP GetSyntheticValue(); @@ -589,10 +605,10 @@ public: virtual lldb::ValueObjectSP Dereference(Status &error); - // Creates a copy of the ValueObject with a new name and setting the current - // ValueObject as its parent. It should be used when we want to change the - // name of a ValueObject without modifying the actual ValueObject itself - // (e.g. sythetic child provider). + /// Creates a copy of the ValueObject with a new name and setting the current + /// ValueObject as its parent. It should be used when we want to change the + /// name of a ValueObject without modifying the actual ValueObject itself + /// (e.g. sythetic child provider). virtual lldb::ValueObjectSP Clone(ConstString new_name); virtual lldb::ValueObjectSP AddressOf(Status &error); @@ -611,7 +627,7 @@ public: lldb::TypeSP &type_sp); // The backing bits of this value object were updated, clear any descriptive - // string, so we know we have to refetch them + // string, so we know we have to refetch them. virtual void ValueUpdated() { ClearUserVisibleData(eClearUserVisibleDataItemsValue | eClearUserVisibleDataItemsSummary | @@ -622,9 +638,13 @@ public: virtual bool DoesProvideSyntheticValue() { return false; } - virtual bool IsSyntheticChildrenGenerated(); + virtual bool IsSyntheticChildrenGenerated() { + return m_flags.m_is_synthetic_children_generated; + } - virtual void SetSyntheticChildrenGenerated(bool b); + virtual void SetSyntheticChildrenGenerated(bool b) { + m_flags.m_is_synthetic_children_generated = b; + } virtual SymbolContextScope *GetSymbolContextScope(); @@ -652,14 +672,10 @@ public: CreateValueObjectFromData(llvm::StringRef name, const DataExtractor &data, const ExecutionContext &exe_ctx, CompilerType type); - void LogValueObject(Log *log); - - void LogValueObject(Log *log, const DumpValueObjectOptions &options); - lldb::ValueObjectSP Persist(); - // returns true if this is a char* or a char[] if it is a char* and - // check_pointer is true, it also checks that the pointer is valid + /// Returns true if this is a char* or a char[] if it is a char* and + /// check_pointer is true, it also checks that the pointer is valid. bool IsCStringContainer(bool check_pointer = false); std::pair @@ -694,7 +710,9 @@ public: virtual lldb::LanguageType GetPreferredDisplayLanguage(); - void SetPreferredDisplayLanguage(lldb::LanguageType); + void SetPreferredDisplayLanguage(lldb::LanguageType lt) { + m_preferred_display_language = lt; + } lldb::TypeSummaryImplSP GetSummaryFormat() { UpdateFormatsIfNeeded(); @@ -702,12 +720,12 @@ public: } void SetSummaryFormat(lldb::TypeSummaryImplSP format) { - m_type_summary_sp = format; + m_type_summary_sp = std::move(format); ClearUserVisibleData(eClearUserVisibleDataItemsSummary); } void SetValueFormat(lldb::TypeFormatImplSP format) { - m_type_format_sp = format; + m_type_format_sp = std::move(format); ClearUserVisibleData(eClearUserVisibleDataItemsValue); } @@ -744,7 +762,9 @@ public: AddressType GetAddressTypeOfChildren(); - void SetHasCompleteType() { m_did_calculate_complete_objc_class_type = true; } + void SetHasCompleteType() { + m_flags.m_did_calculate_complete_objc_class_type = true; + } /// Find out if a ValueObject might have children. /// @@ -766,16 +786,16 @@ public: virtual bool IsRuntimeSupportValue(); - virtual uint64_t GetLanguageFlags(); + virtual uint64_t GetLanguageFlags() { return m_language_flags; } - virtual void SetLanguageFlags(uint64_t flags); + virtual void SetLanguageFlags(uint64_t flags) { m_language_flags = flags; } protected: typedef ClusterManager ValueObjectManager; class ChildrenManager { public: - ChildrenManager() : m_mutex(), m_children(), m_children_count(0) {} + ChildrenManager() : m_mutex(), m_children() {} bool HasChildAtIndex(size_t idx) { std::lock_guard guard(m_mutex); @@ -811,80 +831,102 @@ protected: typedef ChildrenMap::value_type ChildrenPair; std::recursive_mutex m_mutex; ChildrenMap m_children; - size_t m_children_count; + size_t m_children_count = 0; }; // Classes that inherit from ValueObject can see and modify these - ValueObject - *m_parent; // The parent value object, or nullptr if this has no parent - ValueObject *m_root; // The root of the hierarchy for this ValueObject (or - // nullptr if never calculated) - EvaluationPoint m_update_point; // Stores both the stop id and the full - // context at which this value was last - // updated. When we are asked to update the value object, we check whether - // the context & stop id are the same before updating. - ConstString m_name; // The name of this object - DataExtractor - m_data; // A data extractor that can be used to extract the value. + + /// The parent value object, or nullptr if this has no parent. + ValueObject *m_parent = nullptr; + /// The root of the hierarchy for this ValueObject (or nullptr if never + /// calculated). + ValueObject *m_root = nullptr; + /// Stores both the stop id and the full context at which this value was last + /// updated. When we are asked to update the value object, we check whether + /// the context & stop id are the same before updating. + EvaluationPoint m_update_point; + /// The name of this object. + ConstString m_name; + /// A data extractor that can be used to extract the value. + DataExtractor m_data; Value m_value; - Status - m_error; // An error object that can describe any errors that occur when - // updating values. - std::string m_value_str; // Cached value string that will get cleared if/when - // the value is updated. - std::string m_old_value_str; // Cached old value string from the last time the - // value was gotten - std::string m_location_str; // Cached location string that will get cleared - // if/when the value is updated. - std::string m_summary_str; // Cached summary string that will get cleared - // if/when the value is updated. - std::string m_object_desc_str; // Cached result of the "object printer". This - // differs from the summary - // in that the summary is consed up by us, the object_desc_string is builtin. - - CompilerType m_override_type; // If the type of the value object should be - // overridden, the type to impose. - - ValueObjectManager *m_manager; // This object is managed by the root object - // (any ValueObject that gets created - // without a parent.) The manager gets passed through all the generations of - // dependent objects, and will keep the whole cluster of objects alive as - // long as a shared pointer to any of them has been handed out. Shared - // pointers to value objects must always be made with the GetSP method. + /// An error object that can describe any errors that occur when updating + /// values. + Status m_error; + /// Cached value string that will get cleared if/when the value is updated. + std::string m_value_str; + /// Cached old value string from the last time the value was gotten + std::string m_old_value_str; + /// Cached location string that will get cleared if/when the value is updated. + std::string m_location_str; + /// Cached summary string that will get cleared if/when the value is updated. + std::string m_summary_str; + /// Cached result of the "object printer". This differs from the summary + /// in that the summary is consed up by us, the object_desc_string is builtin. + std::string m_object_desc_str; + /// If the type of the value object should be overridden, the type to impose. + CompilerType m_override_type; + + /// This object is managed by the root object (any ValueObject that gets + /// created without a parent.) The manager gets passed through all the + /// generations of dependent objects, and will keep the whole cluster of + /// objects alive as long as a shared pointer to any of them has been handed + /// out. Shared pointers to value objects must always be made with the GetSP + /// method. + ValueObjectManager *m_manager = nullptr; ChildrenManager m_children; std::map m_synthetic_children; - ValueObject *m_dynamic_value; - ValueObject *m_synthetic_value; - ValueObject *m_deref_valobj; + ValueObject *m_dynamic_value = nullptr; + ValueObject *m_synthetic_value = nullptr; + ValueObject *m_deref_valobj = nullptr; - lldb::ValueObjectSP m_addr_of_valobj_sp; // We have to hold onto a shared - // pointer to this one because it is - // created - // as an independent ValueObjectConstResult, which isn't managed by us. + /// We have to hold onto a shared pointer to this one because it is created + /// as an independent ValueObjectConstResult, which isn't managed by us. + lldb::ValueObjectSP m_addr_of_valobj_sp; - lldb::Format m_format; - lldb::Format m_last_format; - uint32_t m_last_format_mgr_revision; + lldb::Format m_format = lldb::eFormatDefault; + lldb::Format m_last_format = lldb::eFormatDefault; + uint32_t m_last_format_mgr_revision = 0; lldb::TypeSummaryImplSP m_type_summary_sp; lldb::TypeFormatImplSP m_type_format_sp; lldb::SyntheticChildrenSP m_synthetic_children_sp; ProcessModID m_user_id_of_forced_summary; - AddressType m_address_type_of_ptr_or_ref_children; + AddressType m_address_type_of_ptr_or_ref_children = eAddressTypeInvalid; llvm::SmallVector m_value_checksum; - lldb::LanguageType m_preferred_display_language; - - uint64_t m_language_flags; - - bool m_value_is_valid : 1, m_value_did_change : 1, m_children_count_valid : 1, - m_old_value_valid : 1, m_is_deref_of_parent : 1, - m_is_array_item_for_pointer : 1, m_is_bitfield_for_scalar : 1, - m_is_child_at_offset : 1, m_is_getting_summary : 1, - m_did_calculate_complete_objc_class_type : 1, - m_is_synthetic_children_generated : 1; + lldb::LanguageType m_preferred_display_language = lldb::eLanguageTypeUnknown; + + uint64_t m_language_flags = 0; + + /// Unique identifier for every value object. + UserID m_id; + + // Utility class for initializing all bitfields in ValueObject's constructors. + // FIXME: This could be done via default initializers once we have C++20. + struct Bitflags { + bool m_value_is_valid : 1, m_value_did_change : 1, + m_children_count_valid : 1, m_old_value_valid : 1, + m_is_deref_of_parent : 1, m_is_array_item_for_pointer : 1, + m_is_bitfield_for_scalar : 1, m_is_child_at_offset : 1, + m_is_getting_summary : 1, m_did_calculate_complete_objc_class_type : 1, + m_is_synthetic_children_generated : 1; + Bitflags() { + m_value_is_valid = false; + m_value_did_change = false; + m_children_count_valid = false; + m_old_value_valid = false; + m_is_deref_of_parent = false; + m_is_array_item_for_pointer = false; + m_is_bitfield_for_scalar = false; + m_is_child_at_offset = false; + m_is_getting_summary = false; + m_did_calculate_complete_objc_class_type = false; + m_is_synthetic_children_generated = false; + } + } m_flags; friend class ValueObjectChild; friend class ExpressionVariable; // For SetName @@ -892,22 +934,13 @@ protected: friend class ValueObjectConstResultImpl; friend class ValueObjectSynthetic; // For ClearUserVisibleData - // Constructors and Destructors - - // Use the no-argument constructor to make a constant variable object (with - // no ExecutionContextScope.) - - ValueObject(); - - // Use this constructor to create a "root variable object". The ValueObject - // will be locked to this context through-out its lifespan. - + /// Use this constructor to create a "root variable object". The ValueObject + /// will be locked to this context through-out its lifespan. ValueObject(ExecutionContextScope *exe_scope, ValueObjectManager &manager, AddressType child_ptr_or_ref_addr_type = eAddressTypeLoad); - // Use this constructor to create a ValueObject owned by another ValueObject. - // It will inherit the ExecutionContext of its parent. - + /// Use this constructor to create a ValueObject owned by another ValueObject. + /// It will inherit the ExecutionContext of its parent. ValueObject(ValueObject &parent); ValueObjectManager *GetManager() { return m_manager; } @@ -928,20 +961,23 @@ protected: virtual void CalculateSyntheticValue(); - // Should only be called by ValueObject::GetChildAtIndex() Returns a - // ValueObject managed by this ValueObject's manager. + /// Should only be called by ValueObject::GetChildAtIndex(). + /// + /// \return A ValueObject managed by this ValueObject's manager. virtual ValueObject *CreateChildAtIndex(size_t idx, bool synthetic_array_member, int32_t synthetic_index); - // Should only be called by ValueObject::GetNumChildren() + /// Should only be called by ValueObject::GetNumChildren(). virtual size_t CalculateNumChildren(uint32_t max = UINT32_MAX) = 0; void SetNumChildren(size_t num_children); - void SetValueDidChange(bool value_changed); + void SetValueDidChange(bool value_changed) { + m_flags.m_value_did_change = value_changed; + } - void SetValueIsValid(bool valid); + void SetValueIsValid(bool valid) { m_flags.m_value_is_valid = valid; } void ClearUserVisibleData( uint32_t items = ValueObject::eClearUserVisibleDataItemsAllStrings); @@ -959,7 +995,7 @@ protected: const char *GetLocationAsCStringImpl(const Value &value, const DataExtractor &data); - bool IsChecksumEmpty(); + bool IsChecksumEmpty() { return m_value_checksum.empty(); } void SetPreferredDisplayLanguageIfNeeded(lldb::LanguageType); @@ -983,47 +1019,6 @@ private: const ValueObject &operator=(const ValueObject &) = delete; }; -// A value object manager class that is seeded with the static variable value -// and it vends the user facing value object. If the type is dynamic it can -// vend the dynamic type. If this user type also has a synthetic type -// associated with it, it will vend the synthetic type. The class watches the -// process' stop -// ID and will update the user type when needed. -class ValueObjectManager { - // The root value object is the static typed variable object. - lldb::ValueObjectSP m_root_valobj_sp; - // The user value object is the value object the user wants to see. - lldb::ValueObjectSP m_user_valobj_sp; - lldb::DynamicValueType m_use_dynamic; - uint32_t m_stop_id; // The stop ID that m_user_valobj_sp is valid for. - bool m_use_synthetic; - -public: - ValueObjectManager() {} - - ValueObjectManager(lldb::ValueObjectSP in_valobj_sp, - lldb::DynamicValueType use_dynamic, bool use_synthetic); - - bool IsValid() const; - - lldb::ValueObjectSP GetRootSP() const { return m_root_valobj_sp; } - - // Gets the correct value object from the root object for a given process - // stop ID. If dynamic values are enabled, or if synthetic children are - // enabled, the value object that the user wants to see might change while - // debugging. - lldb::ValueObjectSP GetSP(); - - void SetUseDynamic(lldb::DynamicValueType use_dynamic); - void SetUseSynthetic(bool use_synthetic); - lldb::DynamicValueType GetUseDynamic() const { return m_use_dynamic; } - bool GetUseSynthetic() const { return m_use_synthetic; } - lldb::TargetSP GetTargetSP() const; - lldb::ProcessSP GetProcessSP() const; - lldb::ThreadSP GetThreadSP() const; - lldb::StackFrameSP GetFrameSP() const; -}; - } // namespace lldb_private #endif // LLDB_CORE_VALUEOBJECT_H diff --git a/gnu/llvm/lldb/include/lldb/Core/ValueObjectCast.h b/gnu/llvm/lldb/include/lldb/Core/ValueObjectCast.h index d91ca6a92be..84cf13353ae 100644 --- a/gnu/llvm/lldb/include/lldb/Core/ValueObjectCast.h +++ b/gnu/llvm/lldb/include/lldb/Core/ValueObjectCast.h @@ -15,13 +15,13 @@ #include "lldb/lldb-enumerations.h" #include "lldb/lldb-forward.h" -#include -#include +#include +#include namespace lldb_private { class ConstString; -// A ValueObject that represents a given value represented as a different type. +/// A ValueObject that represents a given value represented as a different type. class ValueObjectCast : public ValueObject { public: ~ValueObjectCast() override; @@ -30,7 +30,7 @@ public: ConstString name, const CompilerType &cast_type); - uint64_t GetByteSize() override; + llvm::Optional GetByteSize() override; size_t CalculateNumChildren(uint32_t max) override; diff --git a/gnu/llvm/lldb/include/lldb/Core/ValueObjectChild.h b/gnu/llvm/lldb/include/lldb/Core/ValueObjectChild.h index c6f44a29b05..8a7a7f17bc7 100644 --- a/gnu/llvm/lldb/include/lldb/Core/ValueObjectChild.h +++ b/gnu/llvm/lldb/include/lldb/Core/ValueObjectChild.h @@ -20,17 +20,17 @@ #include "llvm/ADT/Optional.h" -#include -#include +#include +#include namespace lldb_private { -// A child of another ValueObject. +/// A child of another ValueObject. class ValueObjectChild : public ValueObject { public: ~ValueObjectChild() override; - uint64_t GetByteSize() override { return m_byte_size; } + llvm::Optional GetByteSize() override { return m_byte_size; } lldb::offset_t GetByteOffset() override { return m_byte_offset; } @@ -71,10 +71,6 @@ protected: bool m_is_deref_of_parent; llvm::Optional m_can_update_with_invalid_exe_ctx; - // - // void - // ReadValueFromMemory (ValueObject* parent, lldb::addr_t address); - friend class ValueObject; friend class ValueObjectConstResult; friend class ValueObjectConstResultImpl; diff --git a/gnu/llvm/lldb/include/lldb/Core/ValueObjectConstResult.h b/gnu/llvm/lldb/include/lldb/Core/ValueObjectConstResult.h index 0e868c687e9..58cda6fd619 100644 --- a/gnu/llvm/lldb/include/lldb/Core/ValueObjectConstResult.h +++ b/gnu/llvm/lldb/include/lldb/Core/ValueObjectConstResult.h @@ -21,15 +21,15 @@ #include "lldb/lldb-private-enumerations.h" #include "lldb/lldb-types.h" -#include -#include +#include +#include namespace lldb_private { class DataExtractor; class ExecutionContextScope; class Module; -// A frozen ValueObject copied into host memory +/// A frozen ValueObject copied into host memory. class ValueObjectConstResult : public ValueObject { public: ~ValueObjectConstResult() override; @@ -62,7 +62,7 @@ public: static lldb::ValueObjectSP Create(ExecutionContextScope *exe_scope, const Status &error); - uint64_t GetByteSize() override; + llvm::Optional GetByteSize() override; lldb::ValueType GetValueType() const override; @@ -113,7 +113,7 @@ protected: CompilerType GetCompilerTypeImpl() override; ConstString m_type_name; - uint64_t m_byte_size; + llvm::Optional m_byte_size; ValueObjectConstResultImpl m_impl; diff --git a/gnu/llvm/lldb/include/lldb/Core/ValueObjectConstResultCast.h b/gnu/llvm/lldb/include/lldb/Core/ValueObjectConstResultCast.h index ba81785866c..5467ce3db40 100644 --- a/gnu/llvm/lldb/include/lldb/Core/ValueObjectConstResultCast.h +++ b/gnu/llvm/lldb/include/lldb/Core/ValueObjectConstResultCast.h @@ -17,8 +17,8 @@ #include "lldb/lldb-forward.h" #include "lldb/lldb-types.h" -#include -#include +#include +#include namespace lldb_private { class DataExtractor; diff --git a/gnu/llvm/lldb/include/lldb/Core/ValueObjectConstResultChild.h b/gnu/llvm/lldb/include/lldb/Core/ValueObjectConstResultChild.h index b3606bfde0e..26bd9f337a5 100644 --- a/gnu/llvm/lldb/include/lldb/Core/ValueObjectConstResultChild.h +++ b/gnu/llvm/lldb/include/lldb/Core/ValueObjectConstResultChild.h @@ -17,8 +17,8 @@ #include "lldb/lldb-forward.h" #include "lldb/lldb-types.h" -#include -#include +#include +#include namespace lldb_private { class DataExtractor; diff --git a/gnu/llvm/lldb/include/lldb/Core/ValueObjectConstResultImpl.h b/gnu/llvm/lldb/include/lldb/Core/ValueObjectConstResultImpl.h index 1316bf66dfd..2536c51fa57 100644 --- a/gnu/llvm/lldb/include/lldb/Core/ValueObjectConstResultImpl.h +++ b/gnu/llvm/lldb/include/lldb/Core/ValueObjectConstResultImpl.h @@ -15,8 +15,8 @@ #include "lldb/lldb-private-enumerations.h" #include "lldb/lldb-types.h" -#include -#include +#include +#include namespace lldb_private { class CompilerType; class DataExtractor; @@ -26,9 +26,9 @@ class ValueObject; namespace lldb_private { -// A class wrapping common implementation details for operations in -// ValueObjectConstResult ( & Child ) that may need to jump from the host -// memory space into the target's memory space +/// A class wrapping common implementation details for operations in +/// ValueObjectConstResult ( & Child ) that may need to jump from the host +/// memory space into the target's memory space. class ValueObjectConstResultImpl { public: ValueObjectConstResultImpl(ValueObject *valobj, diff --git a/gnu/llvm/lldb/include/lldb/Core/ValueObjectDynamicValue.h b/gnu/llvm/lldb/include/lldb/Core/ValueObjectDynamicValue.h index 9f5304b55e9..8822a1d3924 100644 --- a/gnu/llvm/lldb/include/lldb/Core/ValueObjectDynamicValue.h +++ b/gnu/llvm/lldb/include/lldb/Core/ValueObjectDynamicValue.h @@ -19,22 +19,22 @@ #include "lldb/lldb-forward.h" #include "lldb/lldb-private-enumerations.h" -#include -#include -#include +#include +#include +#include namespace lldb_private { class DataExtractor; class Declaration; class Status; -// A ValueObject that represents memory at a given address, viewed as some -// set lldb type. +/// A ValueObject that represents memory at a given address, viewed as some +/// set lldb type. class ValueObjectDynamicValue : public ValueObject { public: ~ValueObjectDynamicValue() override; - uint64_t GetByteSize() override; + llvm::Optional GetByteSize() override; ConstString GetTypeName() override; diff --git a/gnu/llvm/lldb/include/lldb/Core/ValueObjectList.h b/gnu/llvm/lldb/include/lldb/Core/ValueObjectList.h index f99fba41aa2..fcb358e21a2 100644 --- a/gnu/llvm/lldb/include/lldb/Core/ValueObjectList.h +++ b/gnu/llvm/lldb/include/lldb/Core/ValueObjectList.h @@ -14,12 +14,12 @@ #include -#include +#include namespace lldb_private { class ValueObject; -// A collection of ValueObject values that +/// A collection of ValueObject values that. class ValueObjectList { public: const ValueObjectList &operator=(const ValueObjectList &rhs); diff --git a/gnu/llvm/lldb/include/lldb/Core/ValueObjectMemory.h b/gnu/llvm/lldb/include/lldb/Core/ValueObjectMemory.h index d1cd6ae4144..83671a794b5 100644 --- a/gnu/llvm/lldb/include/lldb/Core/ValueObjectMemory.h +++ b/gnu/llvm/lldb/include/lldb/Core/ValueObjectMemory.h @@ -18,14 +18,14 @@ #include "lldb/lldb-forward.h" #include "llvm/ADT/StringRef.h" -#include -#include +#include +#include namespace lldb_private { class ExecutionContextScope; -// A ValueObject that represents memory at a given address, viewed as some -// set lldb type. +/// A ValueObject that represents memory at a given address, viewed as some +/// set lldb type. class ValueObjectMemory : public ValueObject { public: ~ValueObjectMemory() override; @@ -40,7 +40,7 @@ public: const Address &address, const CompilerType &ast_type); - uint64_t GetByteSize() override; + llvm::Optional GetByteSize() override; ConstString GetTypeName() override; diff --git a/gnu/llvm/lldb/include/lldb/Core/ValueObjectRegister.h b/gnu/llvm/lldb/include/lldb/Core/ValueObjectRegister.h index 41051d93b70..e210b36d2a4 100644 --- a/gnu/llvm/lldb/include/lldb/Core/ValueObjectRegister.h +++ b/gnu/llvm/lldb/include/lldb/Core/ValueObjectRegister.h @@ -18,8 +18,8 @@ #include "lldb/lldb-forward.h" #include "lldb/lldb-private-types.h" -#include -#include +#include +#include namespace lldb_private { class DataExtractor; @@ -36,7 +36,7 @@ public: lldb::RegisterContextSP ®_ctx_sp, uint32_t set_idx); - uint64_t GetByteSize() override; + llvm::Optional GetByteSize() override; lldb::ValueType GetValueType() const override { return lldb::eValueTypeRegisterSet; @@ -86,7 +86,7 @@ public: lldb::RegisterContextSP ®_ctx_sp, uint32_t reg_num); - uint64_t GetByteSize() override; + llvm::Optional GetByteSize() override; lldb::ValueType GetValueType() const override { return lldb::eValueTypeRegister; diff --git a/gnu/llvm/lldb/include/lldb/Core/ValueObjectSyntheticFilter.h b/gnu/llvm/lldb/include/lldb/Core/ValueObjectSyntheticFilter.h index cb471657aec..f7a233047cc 100644 --- a/gnu/llvm/lldb/include/lldb/Core/ValueObjectSyntheticFilter.h +++ b/gnu/llvm/lldb/include/lldb/Core/ValueObjectSyntheticFilter.h @@ -20,23 +20,23 @@ #include #include -#include +#include namespace lldb_private { class Declaration; class Status; class SyntheticChildrenFrontEnd; -// A ValueObject that obtains its children from some source other than -// real information -// This is currently used to implement Python-based children and filters but -// you can bind it to any source of synthetic information and have it behave -// accordingly +/// A ValueObject that obtains its children from some source other than +/// real information. +/// This is currently used to implement Python-based children and filters but +/// you can bind it to any source of synthetic information and have it behave +/// accordingly. class ValueObjectSynthetic : public ValueObject { public: ~ValueObjectSynthetic() override; - uint64_t GetByteSize() override; + llvm::Optional GetByteSize() override; ConstString GetTypeName() override; @@ -148,9 +148,9 @@ protected: /// Guarded by m_child_mutex; SyntheticChildrenCache m_synthetic_children_cache; - uint32_t m_synthetic_children_count; // FIXME use the ValueObject's - // ChildrenManager instead of a special - // purpose solution + // FIXME: use the ValueObject's ChildrenManager instead of a special purpose + // solution. + uint32_t m_synthetic_children_count; ConstString m_parent_type_name; diff --git a/gnu/llvm/lldb/include/lldb/Core/ValueObjectUpdater.h b/gnu/llvm/lldb/include/lldb/Core/ValueObjectUpdater.h new file mode 100644 index 00000000000..54fcb31076a --- /dev/null +++ b/gnu/llvm/lldb/include/lldb/Core/ValueObjectUpdater.h @@ -0,0 +1,43 @@ +//===-- ValueObjectUpdater.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_CORE_VALUEOBJECTUPDATER_H +#define LLDB_CORE_VALUEOBJECTUPDATER_H + +#include "lldb/Core/ValueObject.h" + +namespace lldb_private { + +/// A value object class that is seeded with the static variable value +/// and it vends the user facing value object. If the type is dynamic it can +/// vend the dynamic type. If this user type also has a synthetic type +/// associated with it, it will vend the synthetic type. The class watches the +/// process' stop ID and will update the user type when needed. +class ValueObjectUpdater { + /// The root value object is the static typed variable object. + lldb::ValueObjectSP m_root_valobj_sp; + /// The user value object is the value object the user wants to see. + lldb::ValueObjectSP m_user_valobj_sp; + /// The stop ID that m_user_valobj_sp is valid for. + uint32_t m_stop_id = UINT32_MAX; + +public: + ValueObjectUpdater(lldb::ValueObjectSP in_valobj_sp); + + /// Gets the correct value object from the root object for a given process + /// stop ID. If dynamic values are enabled, or if synthetic children are + /// enabled, the value object that the user wants to see might change while + /// debugging. + lldb::ValueObjectSP GetSP(); + + lldb::ProcessSP GetProcessSP() const; +}; + +} // namespace lldb_private + +#endif // LLDB_CORE_VALUEOBJECTUPDATER_H diff --git a/gnu/llvm/lldb/include/lldb/Core/ValueObjectVariable.h b/gnu/llvm/lldb/include/lldb/Core/ValueObjectVariable.h index b7e262574a1..cbf7e5b52ce 100644 --- a/gnu/llvm/lldb/include/lldb/Core/ValueObjectVariable.h +++ b/gnu/llvm/lldb/include/lldb/Core/ValueObjectVariable.h @@ -18,8 +18,8 @@ #include "lldb/lldb-enumerations.h" #include "lldb/lldb-forward.h" -#include -#include +#include +#include namespace lldb_private { class DataExtractor; @@ -28,8 +28,8 @@ class Status; class ExecutionContextScope; class SymbolContextScope; -// A ValueObject that contains a root variable that may or may not -// have children. +/// A ValueObject that contains a root variable that may or may not +/// have children. class ValueObjectVariable : public ValueObject { public: ~ValueObjectVariable() override; @@ -37,7 +37,7 @@ public: static lldb::ValueObjectSP Create(ExecutionContextScope *exe_scope, const lldb::VariableSP &var_sp); - uint64_t GetByteSize() override; + llvm::Optional GetByteSize() override; ConstString GetTypeName() override; @@ -72,10 +72,11 @@ protected: CompilerType GetCompilerTypeImpl() override; - lldb::VariableSP - m_variable_sp; ///< The variable that this value object is based upon - Value m_resolved_value; ///< The value that DWARFExpression resolves this - ///variable to before we patch it up + /// The variable that this value object is based upon. + lldb::VariableSP m_variable_sp; + ///< The value that DWARFExpression resolves this variable to before we patch + ///< it up. + Value m_resolved_value; private: ValueObjectVariable(ExecutionContextScope *exe_scope, diff --git a/gnu/llvm/lldb/include/lldb/Core/dwarf.h b/gnu/llvm/lldb/include/lldb/Core/dwarf.h index cd9cf249bc6..968418e71c2 100644 --- a/gnu/llvm/lldb/include/lldb/Core/dwarf.h +++ b/gnu/llvm/lldb/include/lldb/Core/dwarf.h @@ -10,7 +10,7 @@ #define LLDB_CORE_DWARF_H #include "lldb/Utility/RangeMap.h" -#include +#include // Get the DWARF constant definitions from llvm #include "llvm/BinaryFormat/Dwarf.h" @@ -38,39 +38,6 @@ typedef uint32_t dw_offset_t; // Dwarf Debug Information Entry offset for any #define DW_EH_PE_MASK_ENCODING 0x0F -//// The following are used only internally within lldb - don't -//// document them in the llvm Dwarf.h header file, we won't see -//// them in executable files anywhere. -//// These constants fit between DW_OP_lo_user (0xe0) and DW_OP_hi_user (0xff). -// -//#define DW_OP_APPLE_array_ref 0xEE // first pops index, then pops array; -//pushes array[index] -//#define DW_OP_APPLE_extern 0xEF // ULEB128 index of external object -//(i.e., an entity from the program that was used in the expression) -#define DW_OP_APPLE_uninit \ - 0xF0 // This is actually generated by some apple compilers in locations lists -//#define DW_OP_APPLE_assign 0xF1 // pops value off and assigns it to -//second item on stack (2nd item must have assignable context) -//#define DW_OP_APPLE_address_of 0xF2 // gets the address of the top stack -//item (top item must be a variable, or have value_type that is an address -//already) -//#define DW_OP_APPLE_value_of 0xF3 // pops the value off the stack and -//pushes the value of that object (top item must be a variable, or expression -//local) -//#define DW_OP_APPLE_deref_type 0xF4 // gets the address of the top stack -//item (top item must be a variable, or a clang type) -//#define DW_OP_APPLE_expr_local 0xF5 // ULEB128 expression local index -//#define DW_OP_APPLE_constf 0xF6 // 1 byte float size, followed by -//constant float data -//#define DW_OP_APPLE_scalar_cast 0xF7 // Cast top of stack to 2nd in stack's -//type leaving all items in place -//#define DW_OP_APPLE_clang_cast 0xF8 // pointer size clang::Type * off the -//stack and cast top stack item to this type -//#define DW_OP_APPLE_clear 0xFE // clears the entire expression stack, -//ok if the stack is empty -//#define DW_OP_APPLE_error 0xFF // Stops expression evaluation and -//returns an error (no args) - typedef lldb_private::RangeVector DWARFRangeList; #endif // LLDB_CORE_DWARF_H diff --git a/gnu/llvm/lldb/include/lldb/DataFormatters/DataVisualization.h b/gnu/llvm/lldb/include/lldb/DataFormatters/DataVisualization.h index b053aa074d9..7be07d65acd 100644 --- a/gnu/llvm/lldb/include/lldb/DataFormatters/DataVisualization.h +++ b/gnu/llvm/lldb/include/lldb/DataFormatters/DataVisualization.h @@ -69,9 +69,9 @@ public: static void Clear(); - static void - ForEach(std::function - callback); + static void ForEach(std::function + callback); static uint32_t GetCount(); }; diff --git a/gnu/llvm/lldb/include/lldb/DataFormatters/DumpValueObjectOptions.h b/gnu/llvm/lldb/include/lldb/DataFormatters/DumpValueObjectOptions.h index 2f3bdf80a6f..cef43f45b8e 100644 --- a/gnu/llvm/lldb/include/lldb/DataFormatters/DumpValueObjectOptions.h +++ b/gnu/llvm/lldb/include/lldb/DataFormatters/DumpValueObjectOptions.h @@ -35,12 +35,11 @@ public: }; struct PointerAsArraySettings { - size_t m_element_count; - size_t m_base_element; - size_t m_stride; + size_t m_element_count = 0; + size_t m_base_element = 0; + size_t m_stride = 0; - PointerAsArraySettings() - : m_element_count(0), m_base_element(0), m_stride() {} + PointerAsArraySettings() = default; PointerAsArraySettings(size_t elem_count, size_t base_elem = 0, size_t stride = 1) @@ -62,8 +61,6 @@ public: DumpValueObjectOptions(); - DumpValueObjectOptions(const DumpValueObjectOptions &rhs) = default; - DumpValueObjectOptions(ValueObject &valobj); DumpValueObjectOptions & diff --git a/gnu/llvm/lldb/include/lldb/DataFormatters/FormatClasses.h b/gnu/llvm/lldb/include/lldb/DataFormatters/FormatClasses.h index e3989133a60..b8540de3d74 100644 --- a/gnu/llvm/lldb/include/lldb/DataFormatters/FormatClasses.h +++ b/gnu/llvm/lldb/include/lldb/DataFormatters/FormatClasses.h @@ -105,7 +105,7 @@ private: class TypeNameSpecifierImpl { public: - TypeNameSpecifierImpl() : m_is_regex(false), m_type() {} + TypeNameSpecifierImpl() : m_type() {} TypeNameSpecifierImpl(llvm::StringRef name, bool is_regex) : m_is_regex(is_regex), m_type() { @@ -143,7 +143,7 @@ public: bool IsRegex() { return m_is_regex; } private: - bool m_is_regex; + bool m_is_regex = false; // TODO: Replace this with TypeAndOrName. struct TypeOrName { std::string m_type_name; diff --git a/gnu/llvm/lldb/include/lldb/DataFormatters/FormatManager.h b/gnu/llvm/lldb/include/lldb/DataFormatters/FormatManager.h index 56a0303f9b0..978ad148d6c 100644 --- a/gnu/llvm/lldb/include/lldb/DataFormatters/FormatManager.h +++ b/gnu/llvm/lldb/include/lldb/DataFormatters/FormatManager.h @@ -34,7 +34,7 @@ namespace lldb_private { // this file's objects directly class FormatManager : public IFormatChangeListener { - typedef FormatMap NamedSummariesMap; + typedef FormattersContainer NamedSummariesMap; typedef TypeCategoryMap::MapType::iterator CategoryMapIterator; public: @@ -144,13 +144,6 @@ public: static const char *GetFormatAsCString(lldb::Format format); - // if the user tries to add formatters for, say, "struct Foo" those will not - // match any type because of the way we strip qualifiers from typenames this - // method looks for the case where the user is adding a - // "class","struct","enum" or "union" Foo and strips the unnecessary - // qualifier - static ConstString GetValidTypeName(ConstString type); - // when DataExtractor dumps a vectorOfT, it uses a predefined format for each // item this method returns it, or eFormatInvalid if vector_format is not a // vectorOf diff --git a/gnu/llvm/lldb/include/lldb/DataFormatters/FormattersContainer.h b/gnu/llvm/lldb/include/lldb/DataFormatters/FormattersContainer.h index d414882bae1..2f56218c43a 100644 --- a/gnu/llvm/lldb/include/lldb/DataFormatters/FormattersContainer.h +++ b/gnu/llvm/lldb/include/lldb/DataFormatters/FormattersContainer.h @@ -37,57 +37,103 @@ public: virtual uint32_t GetCurrentRevision() = 0; }; -// if the user tries to add formatters for, say, "struct Foo" those will not -// match any type because of the way we strip qualifiers from typenames this -// method looks for the case where the user is adding a "class","struct","enum" -// or "union" Foo and strips the unnecessary qualifier -static inline ConstString GetValidTypeName_Impl(ConstString type) { - if (type.IsEmpty()) - return type; +/// Class for matching type names. +class TypeMatcher { + RegularExpression m_type_name_regex; + ConstString m_type_name; + /// False if m_type_name_regex should be used for matching. False if this is + /// just matching by comparing with m_type_name string. + bool m_is_regex; - std::string type_cstr(type.AsCString()); - StringLexer type_lexer(type_cstr); + // if the user tries to add formatters for, say, "struct Foo" those will not + // match any type because of the way we strip qualifiers from typenames this + // method looks for the case where the user is adding a + // "class","struct","enum" or "union" Foo and strips the unnecessary qualifier + static ConstString StripTypeName(ConstString type) { + if (type.IsEmpty()) + return type; - type_lexer.AdvanceIf("class "); - type_lexer.AdvanceIf("enum "); - type_lexer.AdvanceIf("struct "); - type_lexer.AdvanceIf("union "); + std::string type_cstr(type.AsCString()); + StringLexer type_lexer(type_cstr); - while (type_lexer.NextIf({' ', '\t', '\v', '\f'}).first) - ; + type_lexer.AdvanceIf("class "); + type_lexer.AdvanceIf("enum "); + type_lexer.AdvanceIf("struct "); + type_lexer.AdvanceIf("union "); - return ConstString(type_lexer.GetUnlexed()); -} + while (type_lexer.NextIf({' ', '\t', '\v', '\f'}).first) + ; -template class FormattersContainer; + return ConstString(type_lexer.GetUnlexed()); + } -template class FormatMap { public: - typedef typename ValueType::SharedPointer ValueSP; - typedef std::vector> MapType; - typedef typename MapType::iterator MapIterator; - typedef std::function ForEachCallback; + TypeMatcher() = delete; + /// Creates a matcher that accepts any type with exactly the given type name. + TypeMatcher(ConstString type_name) + : m_type_name(type_name), m_is_regex(false) {} + /// Creates a matcher that accepts any type matching the given regex. + TypeMatcher(RegularExpression regex) + : m_type_name_regex(std::move(regex)), m_is_regex(true) {} + + /// True iff this matches the given type name. + bool Matches(ConstString type_name) const { + if (m_is_regex) + return m_type_name_regex.Execute(type_name.GetStringRef()); + return m_type_name == type_name || + StripTypeName(m_type_name) == StripTypeName(type_name); + } + + /// Returns the underlying match string for this TypeMatcher. + ConstString GetMatchString() const { + if (m_is_regex) + return ConstString(m_type_name_regex.GetText()); + return StripTypeName(m_type_name); + } + + /// Returns true if this TypeMatcher and the given one were most created by + /// the same match string. + /// The main purpose of this function is to find existing TypeMatcher + /// instances by the user input that created them. This is necessary as LLDB + /// allows referencing existing TypeMatchers in commands by the user input + /// that originally created them: + /// (lldb) type summary add --summary-string \"A\" -x TypeName + /// (lldb) type summary delete TypeName + bool CreatedBySameMatchString(TypeMatcher other) const { + return GetMatchString() == other.GetMatchString(); + } +}; + +template class FormattersContainer { +public: + typedef typename std::shared_ptr ValueSP; + typedef std::vector> MapType; + typedef std::function + ForEachCallback; + typedef typename std::shared_ptr> + SharedPointer; + + friend class TypeCategoryImpl; - FormatMap(IFormatChangeListener *lst) - : m_map(), m_map_mutex(), listener(lst) {} + FormattersContainer(IFormatChangeListener *lst) : listener(lst) {} - void Add(KeyType name, const ValueSP &entry) { + void Add(TypeMatcher matcher, const ValueSP &entry) { if (listener) entry->GetRevision() = listener->GetCurrentRevision(); else entry->GetRevision() = 0; std::lock_guard guard(m_map_mutex); - Delete(name); - m_map.emplace_back(std::move(name), std::move(entry)); + Delete(matcher); + m_map.emplace_back(std::move(matcher), std::move(entry)); if (listener) listener->Changed(); } - bool Delete(const KeyType &name) { + bool Delete(TypeMatcher matcher) { std::lock_guard guard(m_map_mutex); - for (MapIterator iter = m_map.begin(); iter != m_map.end(); ++iter) - if (iter->first == name) { + for (auto iter = m_map.begin(); iter != m_map.end(); ++iter) + if (iter->first.CreatedBySameMatchString(matcher)) { m_map.erase(iter); if (listener) listener->Changed(); @@ -96,217 +142,78 @@ public: return false; } - void Clear() { + bool Get(ConstString type, ValueSP &entry) { std::lock_guard guard(m_map_mutex); - m_map.clear(); - if (listener) - listener->Changed(); + for (auto &formatter : llvm::reverse(m_map)) { + if (formatter.first.Matches(type)) { + entry = formatter.second; + return true; + } + } + return false; } - bool Get(const KeyType &name, ValueSP &entry) { + bool GetExact(TypeMatcher matcher, ValueSP &entry) { std::lock_guard guard(m_map_mutex); for (const auto &pos : m_map) - if (pos.first == name) { + if (pos.first.CreatedBySameMatchString(matcher)) { entry = pos.second; return true; } return false; } - void ForEach(ForEachCallback callback) { - if (callback) { - std::lock_guard guard(m_map_mutex); - for (const auto &pos : m_map) { - const KeyType &type = pos.first; - if (!callback(type, pos.second)) - break; - } - } - } - - uint32_t GetCount() { return m_map.size(); } - - ValueSP GetValueAtIndex(size_t index) { + ValueSP GetAtIndex(size_t index) { std::lock_guard guard(m_map_mutex); if (index >= m_map.size()) return ValueSP(); return m_map[index].second; } - // If caller holds the mutex we could return a reference without copy ctor. - KeyType GetKeyAtIndex(size_t index) { + lldb::TypeNameSpecifierImplSP GetTypeNameSpecifierAtIndex(size_t index) { std::lock_guard guard(m_map_mutex); if (index >= m_map.size()) - return {}; - return m_map[index].first; - } - -protected: - MapType m_map; - std::recursive_mutex m_map_mutex; - IFormatChangeListener *listener; - - MapType &map() { return m_map; } - - std::recursive_mutex &mutex() { return m_map_mutex; } - - friend class FormattersContainer; - friend class FormatManager; -}; - -template class FormattersContainer { -protected: - typedef FormatMap BackEndType; - -public: - typedef typename BackEndType::MapType MapType; - typedef typename MapType::iterator MapIterator; - typedef KeyType MapKeyType; - typedef std::shared_ptr MapValueType; - typedef typename BackEndType::ForEachCallback ForEachCallback; - typedef typename std::shared_ptr> - SharedPointer; - - friend class TypeCategoryImpl; - - FormattersContainer(std::string name, IFormatChangeListener *lst) - : m_format_map(lst), m_name(name) {} - - void Add(MapKeyType type, const MapValueType &entry) { - Add_Impl(std::move(type), entry, static_cast(nullptr)); - } - - bool Delete(ConstString type) { - return Delete_Impl(type, static_cast(nullptr)); - } - - bool Get(ValueObject &valobj, MapValueType &entry, - lldb::DynamicValueType use_dynamic) { - CompilerType ast_type(valobj.GetCompilerType()); - bool ret = Get(valobj, ast_type, entry, use_dynamic); - if (ret) - entry = MapValueType(entry); - else - entry = MapValueType(); - return ret; + return lldb::TypeNameSpecifierImplSP(); + TypeMatcher type_matcher = m_map[index].first; + return std::make_shared( + type_matcher.GetMatchString().GetStringRef(), true); } - bool Get(ConstString type, MapValueType &entry) { - return Get_Impl(type, entry, static_cast(nullptr)); + void Clear() { + std::lock_guard guard(m_map_mutex); + m_map.clear(); + if (listener) + listener->Changed(); } - bool GetExact(ConstString type, MapValueType &entry) { - return GetExact_Impl(type, entry, static_cast(nullptr)); + void ForEach(ForEachCallback callback) { + if (callback) { + std::lock_guard guard(m_map_mutex); + for (const auto &pos : m_map) { + const TypeMatcher &type = pos.first; + if (!callback(type, pos.second)) + break; + } + } } - MapValueType GetAtIndex(size_t index) { - return m_format_map.GetValueAtIndex(index); + uint32_t GetCount() { + std::lock_guard guard(m_map_mutex); + return m_map.size(); } - lldb::TypeNameSpecifierImplSP GetTypeNameSpecifierAtIndex(size_t index) { - return GetTypeNameSpecifierAtIndex_Impl(index, - static_cast(nullptr)); + void AutoComplete(CompletionRequest &request) { + ForEach([&request](const TypeMatcher &matcher, const ValueSP &value) { + request.TryCompleteCurrentArg(matcher.GetMatchString().GetStringRef()); + return true; + }); } - void Clear() { m_format_map.Clear(); } - - void ForEach(ForEachCallback callback) { m_format_map.ForEach(callback); } - - uint32_t GetCount() { return m_format_map.GetCount(); } - protected: - BackEndType m_format_map; - std::string m_name; - FormattersContainer(const FormattersContainer &) = delete; const FormattersContainer &operator=(const FormattersContainer &) = delete; - void Add_Impl(MapKeyType type, const MapValueType &entry, - RegularExpression *dummy) { - m_format_map.Add(std::move(type), entry); - } - - void Add_Impl(ConstString type, const MapValueType &entry, - ConstString *dummy) { - m_format_map.Add(GetValidTypeName_Impl(type), entry); - } - - bool Delete_Impl(ConstString type, ConstString *dummy) { - return m_format_map.Delete(type); - } - - bool Delete_Impl(ConstString type, RegularExpression *dummy) { - std::lock_guard guard(m_format_map.mutex()); - MapIterator pos, end = m_format_map.map().end(); - for (pos = m_format_map.map().begin(); pos != end; pos++) { - const RegularExpression ®ex = pos->first; - if (type.GetStringRef() == regex.GetText()) { - m_format_map.map().erase(pos); - if (m_format_map.listener) - m_format_map.listener->Changed(); - return true; - } - } - return false; - } - - bool Get_Impl(ConstString type, MapValueType &entry, ConstString *dummy) { - return m_format_map.Get(type, entry); - } - - bool GetExact_Impl(ConstString type, MapValueType &entry, - ConstString *dummy) { - return Get_Impl(type, entry, static_cast(nullptr)); - } - - lldb::TypeNameSpecifierImplSP - GetTypeNameSpecifierAtIndex_Impl(size_t index, ConstString *dummy) { - ConstString key = m_format_map.GetKeyAtIndex(index); - if (key) - return lldb::TypeNameSpecifierImplSP( - new TypeNameSpecifierImpl(key.GetStringRef(), false)); - else - return lldb::TypeNameSpecifierImplSP(); - } - - lldb::TypeNameSpecifierImplSP - GetTypeNameSpecifierAtIndex_Impl(size_t index, RegularExpression *dummy) { - RegularExpression regex = m_format_map.GetKeyAtIndex(index); - if (regex == RegularExpression()) - return lldb::TypeNameSpecifierImplSP(); - return lldb::TypeNameSpecifierImplSP( - new TypeNameSpecifierImpl(regex.GetText().str().c_str(), true)); - } - - bool Get_Impl(ConstString key, MapValueType &value, - RegularExpression *dummy) { - llvm::StringRef key_str = key.GetStringRef(); - std::lock_guard guard(m_format_map.mutex()); - // Patterns are matched in reverse-chronological order. - for (const auto &pos : llvm::reverse(m_format_map.map())) { - const RegularExpression ®ex = pos.first; - if (regex.Execute(key_str)) { - value = pos.second; - return true; - } - } - return false; - } - - bool GetExact_Impl(ConstString key, MapValueType &value, - RegularExpression *dummy) { - std::lock_guard guard(m_format_map.mutex()); - for (const auto &pos : m_format_map.map()) { - const RegularExpression ®ex = pos.first; - if (regex.GetText() == key.GetStringRef()) { - value = pos.second; - return true; - } - } - return false; - } - - bool Get(const FormattersMatchVector &candidates, MapValueType &entry) { + bool Get(const FormattersMatchVector &candidates, ValueSP &entry) { for (const FormattersMatchCandidate &candidate : candidates) { if (Get(candidate.GetTypeName(), entry)) { if (candidate.IsMatch(entry) == false) { @@ -319,6 +226,10 @@ protected: } return false; } + + MapType m_map; + std::recursive_mutex m_map_mutex; + IFormatChangeListener *listener; }; } // namespace lldb_private diff --git a/gnu/llvm/lldb/include/lldb/DataFormatters/FormattersHelpers.h b/gnu/llvm/lldb/include/lldb/DataFormatters/FormattersHelpers.h index a5b0da57e5d..892807063b9 100644 --- a/gnu/llvm/lldb/include/lldb/DataFormatters/FormattersHelpers.h +++ b/gnu/llvm/lldb/include/lldb/DataFormatters/FormattersHelpers.h @@ -36,11 +36,13 @@ void AddOneLineSummary(TypeCategoryImpl::SharedPointer category_sp, ConstString type_name, TypeSummaryImpl::Flags flags, bool regex = false); +/// Add a summary that is implemented by a C++ callback. void AddCXXSummary(TypeCategoryImpl::SharedPointer category_sp, CXXFunctionSummaryFormat::Callback funct, const char *description, ConstString type_name, TypeSummaryImpl::Flags flags, bool regex = false); +/// Add a synthetic that is implemented by a C++ callback. void AddCXXSynthetic(TypeCategoryImpl::SharedPointer category_sp, CXXSyntheticChildren::CreateFrontEndCallback generator, const char *description, ConstString type_name, diff --git a/gnu/llvm/lldb/include/lldb/DataFormatters/StringPrinter.h b/gnu/llvm/lldb/include/lldb/DataFormatters/StringPrinter.h index 17c645f8637..4a6e2e9051b 100644 --- a/gnu/llvm/lldb/include/lldb/DataFormatters/StringPrinter.h +++ b/gnu/llvm/lldb/include/lldb/DataFormatters/StringPrinter.h @@ -109,7 +109,7 @@ public: uint64_t GetLocation() const { return m_location; } - void SetProcessSP(lldb::ProcessSP p) { m_process_sp = p; } + void SetProcessSP(lldb::ProcessSP p) { m_process_sp = std::move(p); } lldb::ProcessSP GetProcessSP() const { return m_process_sp; } diff --git a/gnu/llvm/lldb/include/lldb/DataFormatters/TypeCategory.h b/gnu/llvm/lldb/include/lldb/DataFormatters/TypeCategory.h index 820872a59bd..2c930590183 100644 --- a/gnu/llvm/lldb/include/lldb/DataFormatters/TypeCategory.h +++ b/gnu/llvm/lldb/include/lldb/DataFormatters/TypeCategory.h @@ -25,14 +25,13 @@ namespace lldb_private { template class FormatterContainerPair { public: - typedef FormattersContainer ExactMatchContainer; - typedef FormattersContainer - RegexMatchContainer; + typedef FormattersContainer ExactMatchContainer; + typedef FormattersContainer RegexMatchContainer; - typedef typename ExactMatchContainer::MapType ExactMatchMap; - typedef typename RegexMatchContainer::MapType RegexMatchMap; + typedef TypeMatcher ExactMatchMap; + typedef TypeMatcher RegexMatchMap; - typedef typename ExactMatchContainer::MapValueType MapValueType; + typedef typename ExactMatchContainer::ValueSP MapValueType; typedef typename ExactMatchContainer::SharedPointer ExactMatchContainerSP; typedef typename RegexMatchContainer::SharedPointer RegexMatchContainerSP; @@ -42,10 +41,9 @@ public: typedef typename RegexMatchContainer::ForEachCallback RegexMatchForEachCallback; - FormatterContainerPair(const char *exact_name, const char *regex_name, - IFormatChangeListener *clist) - : m_exact_sp(new ExactMatchContainer(std::string(exact_name), clist)), - m_regex_sp(new RegexMatchContainer(std::string(regex_name), clist)) {} + FormatterContainerPair(IFormatChangeListener *clist) + : m_exact_sp(new ExactMatchContainer(clist)), + m_regex_sp(new RegexMatchContainer(clist)) {} ~FormatterContainerPair() = default; @@ -93,52 +91,52 @@ public: template typename std::enable_if::value, ForEachCallbacks &>::type SetExact(FormatContainer::ExactMatchForEachCallback callback) { - m_format_exact = callback; + m_format_exact = std::move(callback); return *this; } template typename std::enable_if::value, ForEachCallbacks &>::type SetWithRegex(FormatContainer::RegexMatchForEachCallback callback) { - m_format_regex = callback; + m_format_regex = std::move(callback); return *this; } template typename std::enable_if::value, ForEachCallbacks &>::type SetExact(SummaryContainer::ExactMatchForEachCallback callback) { - m_summary_exact = callback; + m_summary_exact = std::move(callback); return *this; } template typename std::enable_if::value, ForEachCallbacks &>::type SetWithRegex(SummaryContainer::RegexMatchForEachCallback callback) { - m_summary_regex = callback; + m_summary_regex = std::move(callback); return *this; } template typename std::enable_if::value, ForEachCallbacks &>::type SetExact(FilterContainer::ExactMatchForEachCallback callback) { - m_filter_exact = callback; + m_filter_exact = std::move(callback); return *this; } template typename std::enable_if::value, ForEachCallbacks &>::type SetWithRegex(FilterContainer::RegexMatchForEachCallback callback) { - m_filter_regex = callback; + m_filter_regex = std::move(callback); return *this; } template typename std::enable_if::value, ForEachCallbacks &>::type SetExact(SynthContainer::ExactMatchForEachCallback callback) { - m_synth_exact = callback; + m_synth_exact = std::move(callback); return *this; } template typename std::enable_if::value, ForEachCallbacks &>::type SetWithRegex(SynthContainer::RegexMatchForEachCallback callback) { - m_synth_regex = callback; + m_synth_regex = std::move(callback); return *this; } @@ -349,19 +347,13 @@ private: friend class LanguageCategory; friend class TypeCategoryMap; - friend class FormattersContainer; - friend class FormattersContainer; + friend class FormattersContainer; - friend class FormattersContainer; - friend class FormattersContainer; + friend class FormattersContainer; - friend class FormattersContainer; - friend class FormattersContainer; - - friend class FormattersContainer; - friend class FormattersContainer; + friend class FormattersContainer; + friend class FormattersContainer; }; } // namespace lldb_private diff --git a/gnu/llvm/lldb/include/lldb/DataFormatters/TypeCategoryMap.h b/gnu/llvm/lldb/include/lldb/DataFormatters/TypeCategoryMap.h index 832652f7d74..4dbca29db06 100644 --- a/gnu/llvm/lldb/include/lldb/DataFormatters/TypeCategoryMap.h +++ b/gnu/llvm/lldb/include/lldb/DataFormatters/TypeCategoryMap.h @@ -84,7 +84,8 @@ private: lldb::TypeCategoryImplSP ptr; public: - delete_matching_categories(lldb::TypeCategoryImplSP p) : ptr(p) {} + delete_matching_categories(lldb::TypeCategoryImplSP p) + : ptr(std::move(p)) {} bool operator()(const lldb::TypeCategoryImplSP &other) { return ptr.get() == other.get(); @@ -103,7 +104,7 @@ private: std::recursive_mutex &mutex() { return m_map_mutex; } - friend class FormattersContainer; + friend class FormattersContainer; friend class FormatManager; }; } // namespace lldb_private diff --git a/gnu/llvm/lldb/include/lldb/DataFormatters/TypeFormat.h b/gnu/llvm/lldb/include/lldb/DataFormatters/TypeFormat.h index b8ed6a3443b..4e19d4cb14a 100644 --- a/gnu/llvm/lldb/include/lldb/DataFormatters/TypeFormat.h +++ b/gnu/llvm/lldb/include/lldb/DataFormatters/TypeFormat.h @@ -25,7 +25,7 @@ class TypeFormatImpl { public: class Flags { public: - Flags() : m_flags(lldb::eTypeOptionCascade) {} + Flags() {} Flags(const Flags &other) : m_flags(other.m_flags) {} @@ -104,7 +104,7 @@ public: void SetValue(uint32_t value) { m_flags = value; } private: - uint32_t m_flags; + uint32_t m_flags = lldb::eTypeOptionCascade; }; TypeFormatImpl(const Flags &flags = Flags()); @@ -149,7 +149,7 @@ public: protected: Flags m_flags; - uint32_t m_my_revision; + uint32_t m_my_revision = 0; private: TypeFormatImpl(const TypeFormatImpl &) = delete; diff --git a/gnu/llvm/lldb/include/lldb/DataFormatters/TypeSummary.h b/gnu/llvm/lldb/include/lldb/DataFormatters/TypeSummary.h index 6c3780f7276..30bc8cbf3fe 100644 --- a/gnu/llvm/lldb/include/lldb/DataFormatters/TypeSummary.h +++ b/gnu/llvm/lldb/include/lldb/DataFormatters/TypeSummary.h @@ -9,7 +9,7 @@ #ifndef LLDB_DATAFORMATTERS_TYPESUMMARY_H #define LLDB_DATAFORMATTERS_TYPESUMMARY_H -#include +#include #include #include @@ -38,8 +38,8 @@ public: TypeSummaryOptions &SetCapping(lldb::TypeSummaryCapping); private: - lldb::LanguageType m_lang; - lldb::TypeSummaryCapping m_capping; + lldb::LanguageType m_lang = lldb::eLanguageTypeUnknown; + lldb::TypeSummaryCapping m_capping = lldb::eTypeSummaryCapped; }; class TypeSummaryImpl { @@ -52,7 +52,7 @@ public: class Flags { public: - Flags() : m_flags(lldb::eTypeOptionCascade) {} + Flags() = default; Flags(const Flags &other) : m_flags(other.m_flags) {} @@ -196,7 +196,7 @@ public: void SetValue(uint32_t value) { m_flags = value; } private: - uint32_t m_flags; + uint32_t m_flags = lldb::eTypeOptionCascade; }; bool Cascades() const { return m_flags.GetCascades(); } @@ -322,7 +322,7 @@ struct CXXFunctionSummaryFormat : public TypeSummaryImpl { const char *GetTextualInfo() const { return m_description.c_str(); } - void SetBackendFunction(Callback cb_func) { m_impl = cb_func; } + void SetBackendFunction(Callback cb_func) { m_impl = std::move(cb_func); } void SetTextualInfo(const char *descr) { if (descr) diff --git a/gnu/llvm/lldb/include/lldb/DataFormatters/TypeSynthetic.h b/gnu/llvm/lldb/include/lldb/DataFormatters/TypeSynthetic.h index c852ff18bfa..24322bd51a0 100644 --- a/gnu/llvm/lldb/include/lldb/DataFormatters/TypeSynthetic.h +++ b/gnu/llvm/lldb/include/lldb/DataFormatters/TypeSynthetic.h @@ -9,7 +9,7 @@ #ifndef LLDB_DATAFORMATTERS_TYPESYNTHETIC_H #define LLDB_DATAFORMATTERS_TYPESYNTHETIC_H -#include +#include #include #include @@ -133,7 +133,7 @@ class SyntheticChildren { public: class Flags { public: - Flags() : m_flags(lldb::eTypeOptionCascade) {} + Flags() = default; Flags(const Flags &other) : m_flags(other.m_flags) {} @@ -225,7 +225,7 @@ public: void SetValue(uint32_t value) { m_flags = value; } private: - uint32_t m_flags; + uint32_t m_flags = lldb::eTypeOptionCascade; }; SyntheticChildren(const Flags &flags) : m_flags(flags) {} @@ -362,7 +362,7 @@ public: CreateFrontEndCallback; CXXSyntheticChildren(const SyntheticChildren::Flags &flags, const char *description, CreateFrontEndCallback callback) - : SyntheticChildren(flags), m_create_callback(callback), + : SyntheticChildren(flags), m_create_callback(std::move(callback)), m_description(description ? description : "") {} bool IsScripted() override { return false; } diff --git a/gnu/llvm/lldb/include/lldb/DataFormatters/ValueObjectPrinter.h b/gnu/llvm/lldb/include/lldb/DataFormatters/ValueObjectPrinter.h index f1301d8595b..833cd5eea35 100644 --- a/gnu/llvm/lldb/include/lldb/DataFormatters/ValueObjectPrinter.h +++ b/gnu/llvm/lldb/include/lldb/DataFormatters/ValueObjectPrinter.h @@ -27,7 +27,7 @@ public: ValueObjectPrinter(ValueObject *valobj, Stream *s, const DumpValueObjectOptions &options); - ~ValueObjectPrinter() {} + ~ValueObjectPrinter() = default; bool PrintValueObject(); diff --git a/gnu/llvm/lldb/include/lldb/Expression/DWARFExpression.h b/gnu/llvm/lldb/include/lldb/Expression/DWARFExpression.h index 6b63b186e3e..1490ac2d614 100644 --- a/gnu/llvm/lldb/include/lldb/Expression/DWARFExpression.h +++ b/gnu/llvm/lldb/include/lldb/Expression/DWARFExpression.h @@ -219,6 +219,10 @@ public: bool MatchesOperand(StackFrame &frame, const Instruction::Operand &op); + llvm::Optional + GetLocationExpression(lldb::addr_t load_function_start, + lldb::addr_t addr) const; + private: /// Pretty-prints the location expression to a stream /// @@ -237,10 +241,6 @@ private: void DumpLocation(Stream *s, const DataExtractor &data, lldb::DescriptionLevel level, ABI *abi) const; - llvm::Optional - GetLocationExpression(lldb::addr_t load_function_start, - lldb::addr_t addr) const; - /// Module which defined this expression. lldb::ModuleWP m_module_wp; @@ -250,10 +250,10 @@ private: /// The DWARF compile unit this expression belongs to. It is used to evaluate /// values indexing into the .debug_addr section (e.g. DW_OP_GNU_addr_index, /// DW_OP_GNU_const_index) - const DWARFUnit *m_dwarf_cu; + const DWARFUnit *m_dwarf_cu = nullptr; /// One of the defines that starts with LLDB_REGKIND_ - lldb::RegisterKind m_reg_kind; + lldb::RegisterKind m_reg_kind = lldb::eRegisterKindDWARF; struct LoclistAddresses { lldb::addr_t cu_file_addr; diff --git a/gnu/llvm/lldb/include/lldb/Expression/Expression.h b/gnu/llvm/lldb/include/lldb/Expression/Expression.h index aaac889e6ed..b4207de958e 100644 --- a/gnu/llvm/lldb/include/lldb/Expression/Expression.h +++ b/gnu/llvm/lldb/include/lldb/Expression/Expression.h @@ -39,7 +39,7 @@ public: Expression(ExecutionContextScope &exe_scope); /// Destructor - virtual ~Expression() {} + virtual ~Expression() = default; /// Return the string that the parser should parse. Must be a full /// translation unit. diff --git a/gnu/llvm/lldb/include/lldb/Expression/ExpressionParser.h b/gnu/llvm/lldb/include/lldb/Expression/ExpressionParser.h index 71d2410ea7c..ab5223c9155 100644 --- a/gnu/llvm/lldb/include/lldb/Expression/ExpressionParser.h +++ b/gnu/llvm/lldb/include/lldb/Expression/ExpressionParser.h @@ -41,7 +41,7 @@ public: : m_expr(expr), m_generate_debug_info(generate_debug_info) {} /// Destructor - virtual ~ExpressionParser(){}; + virtual ~ExpressionParser() = default; /// Attempts to find possible command line completions for the given /// expression. diff --git a/gnu/llvm/lldb/include/lldb/Expression/ExpressionTypeSystemHelper.h b/gnu/llvm/lldb/include/lldb/Expression/ExpressionTypeSystemHelper.h index 1bba30ad862..2ba675db866 100644 --- a/gnu/llvm/lldb/include/lldb/Expression/ExpressionTypeSystemHelper.h +++ b/gnu/llvm/lldb/include/lldb/Expression/ExpressionTypeSystemHelper.h @@ -36,7 +36,7 @@ public: ExpressionTypeSystemHelper(LLVMCastKind kind) : m_kind(kind) {} - ~ExpressionTypeSystemHelper() {} + ~ExpressionTypeSystemHelper() = default; protected: LLVMCastKind m_kind; diff --git a/gnu/llvm/lldb/include/lldb/Expression/ExpressionVariable.h b/gnu/llvm/lldb/include/lldb/Expression/ExpressionVariable.h index 60062d212ba..de700b67661 100644 --- a/gnu/llvm/lldb/include/lldb/Expression/ExpressionVariable.h +++ b/gnu/llvm/lldb/include/lldb/Expression/ExpressionVariable.h @@ -32,7 +32,7 @@ public: virtual ~ExpressionVariable(); - size_t GetByteSize() { return m_frozen_sp->GetByteSize(); } + llvm::Optional GetByteSize() { return m_frozen_sp->GetByteSize(); } ConstString GetName() { return m_frozen_sp->GetName(); } @@ -48,7 +48,7 @@ public: void SetRegisterInfo(const RegisterInfo *reg_info) { return m_frozen_sp->GetValue().SetContext( - Value::eContextTypeRegisterInfo, const_cast(reg_info)); + Value::ContextType::RegisterInfo, const_cast(reg_info)); } CompilerType GetCompilerType() { return m_frozen_sp->GetCompilerType(); } diff --git a/gnu/llvm/lldb/include/lldb/Expression/Materializer.h b/gnu/llvm/lldb/include/lldb/Expression/Materializer.h index 754e67c5dfa..25cf22a8b5b 100644 --- a/gnu/llvm/lldb/include/lldb/Expression/Materializer.h +++ b/gnu/llvm/lldb/include/lldb/Expression/Materializer.h @@ -90,7 +90,7 @@ public: class Entity { public: - Entity() : m_alignment(1), m_size(0), m_offset(0) {} + Entity() = default; virtual ~Entity() = default; @@ -113,9 +113,9 @@ public: void SetOffset(uint32_t offset) { m_offset = offset; } protected: - uint32_t m_alignment; - uint32_t m_size; - uint32_t m_offset; + uint32_t m_alignment = 1; + uint32_t m_size = 0; + uint32_t m_offset = 0; }; private: diff --git a/gnu/llvm/lldb/include/lldb/Expression/UtilityFunction.h b/gnu/llvm/lldb/include/lldb/Expression/UtilityFunction.h index 5ebbc0ede1e..6b558b20e21 100644 --- a/gnu/llvm/lldb/include/lldb/Expression/UtilityFunction.h +++ b/gnu/llvm/lldb/include/lldb/Expression/UtilityFunction.h @@ -42,8 +42,11 @@ public: /// /// \param[in] name /// The name of the function, as used in the text. - UtilityFunction(ExecutionContextScope &exe_scope, const char *text, - const char *name); + /// + /// \param[in] enable_debugging + /// Enable debugging of this function. + UtilityFunction(ExecutionContextScope &exe_scope, std::string text, + std::string name, bool enable_debugging); ~UtilityFunction() override; @@ -110,9 +113,10 @@ public: protected: std::shared_ptr m_execution_unit_sp; lldb::ModuleWP m_jit_module_wp; - std::string m_function_text; ///< The text of the function. Must be a - ///well-formed translation unit. - std::string m_function_name; ///< The name of the function. + /// The text of the function. Must be a well-formed translation unit. + std::string m_function_text; + /// The name of the function. + std::string m_function_name; std::unique_ptr m_caller_up; }; diff --git a/gnu/llvm/lldb/include/lldb/Host/Config.h.cmake b/gnu/llvm/lldb/include/lldb/Host/Config.h.cmake index 42f4ca1a26c..c667708a90a 100644 --- a/gnu/llvm/lldb/include/lldb/Host/Config.h.cmake +++ b/gnu/llvm/lldb/include/lldb/Host/Config.h.cmake @@ -20,6 +20,8 @@ #cmakedefine01 HAVE_PPOLL +#cmakedefine01 HAVE_PTSNAME_R + #cmakedefine01 HAVE_SIGACTION #cmakedefine01 HAVE_PROCESS_VM_READV @@ -38,6 +40,8 @@ #cmakedefine01 LLDB_ENABLE_CURSES +#cmakedefine01 CURSES_HAVE_NCURSES_CURSES_H + #cmakedefine01 LLDB_ENABLE_LIBEDIT #cmakedefine01 LLDB_ENABLE_LIBXML2 @@ -48,7 +52,7 @@ #cmakedefine01 LLDB_EMBED_PYTHON_HOME -#cmakedefine LLDB_PYTHON_HOME "${LLDB_PYTHON_HOME}" +#cmakedefine LLDB_PYTHON_HOME R"(${LLDB_PYTHON_HOME})" #define LLDB_LIBDIR_SUFFIX "${LLVM_LIBDIR_SUFFIX}" diff --git a/gnu/llvm/lldb/include/lldb/Host/Debug.h b/gnu/llvm/lldb/include/lldb/Host/Debug.h index 402325c4c16..7da59dd04a6 100644 --- a/gnu/llvm/lldb/include/lldb/Host/Debug.h +++ b/gnu/llvm/lldb/include/lldb/Host/Debug.h @@ -144,6 +144,12 @@ struct ThreadStopInfo { uint32_t data_count; lldb::addr_t data[8]; } exception; + + // eStopReasonFork / eStopReasonVFork + struct { + lldb::pid_t child_pid; + lldb::tid_t child_tid; + } fork; } details; }; } diff --git a/gnu/llvm/lldb/include/lldb/Host/Editline.h b/gnu/llvm/lldb/include/lldb/Host/Editline.h index 356e8f73473..876f6052311 100644 --- a/gnu/llvm/lldb/include/lldb/Host/Editline.h +++ b/gnu/llvm/lldb/include/lldb/Host/Editline.h @@ -38,12 +38,9 @@ #include #include -#include "lldb/Host/ConnectionFileDescriptor.h" #include "lldb/lldb-private.h" -#if defined(_WIN32) -#include "lldb/Host/windows/editlinewin.h" -#elif !defined(__ANDROID__) +#if !defined(_WIN32) && !defined(__ANDROID__) #include #endif @@ -56,6 +53,9 @@ #include "lldb/Utility/CompletionRequest.h" #include "lldb/Utility/FileSpec.h" #include "lldb/Utility/Predicate.h" +#include "lldb/Utility/StringList.h" + +#include "llvm/ADT/FunctionExtras.h" namespace lldb_private { namespace line_editor { @@ -81,24 +81,26 @@ using EditLineGetCharType = wchar_t; using EditLineGetCharType = char; #endif -typedef int (*EditlineGetCharCallbackType)(::EditLine *editline, - EditLineGetCharType *c); -typedef unsigned char (*EditlineCommandCallbackType)(::EditLine *editline, - int ch); -typedef const char *(*EditlinePromptCallbackType)(::EditLine *editline); +using EditlineGetCharCallbackType = int (*)(::EditLine *editline, + EditLineGetCharType *c); +using EditlineCommandCallbackType = unsigned char (*)(::EditLine *editline, + int ch); +using EditlinePromptCallbackType = const char *(*)(::EditLine *editline); class EditlineHistory; -typedef std::shared_ptr EditlineHistorySP; +using EditlineHistorySP = std::shared_ptr; + +using IsInputCompleteCallbackType = + llvm::unique_function; -typedef bool (*IsInputCompleteCallbackType)(Editline *editline, - StringList &lines, void *baton); +using FixIndentationCallbackType = + llvm::unique_function; -typedef int (*FixIndentationCallbackType)(Editline *editline, - const StringList &lines, - int cursor_position, void *baton); +using SuggestionCallbackType = + llvm::unique_function(llvm::StringRef)>; -typedef void (*CompleteCallbackType)(CompletionRequest &request, void *baton); +using CompleteCallbackType = llvm::unique_function; /// Status used to decide when and how to start editing another line in /// multi-line sessions @@ -184,19 +186,29 @@ public: /// Cancel this edit and oblitarate all trace of it bool Cancel(); + /// Register a callback for autosuggestion. + void SetSuggestionCallback(SuggestionCallbackType callback) { + m_suggestion_callback = std::move(callback); + } + /// Register a callback for the tab key - void SetAutoCompleteCallback(CompleteCallbackType callback, void *baton); + void SetAutoCompleteCallback(CompleteCallbackType callback) { + m_completion_callback = std::move(callback); + } /// Register a callback for testing whether multi-line input is complete - void SetIsInputCompleteCallback(IsInputCompleteCallbackType callback, - void *baton); + void SetIsInputCompleteCallback(IsInputCompleteCallbackType callback) { + m_is_input_complete_callback = std::move(callback); + } /// Register a callback for determining the appropriate indentation for a line /// when creating a newline. An optional set of insertable characters can - /// also - /// trigger the callback. - bool SetFixIndentationCallback(FixIndentationCallbackType callback, - void *baton, const char *indent_chars); + /// also trigger the callback. + void SetFixIndentationCallback(FixIndentationCallbackType callback, + const char *indent_chars) { + m_fix_indentation_callback = std::move(callback); + m_fix_indentation_callback_chars = indent_chars; + } /// Prompts for and reads a single line of user input. bool GetLine(std::string &line, bool &interrupted); @@ -312,6 +324,12 @@ private: /// tab key is typed. unsigned char TabCommand(int ch); + /// Apply autosuggestion part in gray as editline. + unsigned char ApplyAutosuggestCommand(int ch); + + /// Command used when a character is typed. + unsigned char TypedCharacter(int ch); + /// Respond to normal character insertion by fixing line indentation unsigned char FixIndentationCommand(int ch); @@ -326,6 +344,16 @@ private: void ApplyTerminalSizeChange(); + // The following set various editline parameters. It's not any less + // verbose to put the editline calls into a function, but it + // provides type safety, since the editline functions take varargs + // parameters. + void AddFunctionToEditLine(const EditLineCharType *command, + const EditLineCharType *helptext, + EditlineCommandCallbackType callbackFn); + void SetEditLinePromptCallback(EditlinePromptCallbackType callbackFn); + void SetGetCharacterFunction(EditlineGetCharCallbackType callbackFn); + #if LLDB_EDITLINE_USE_WCHAR std::wstring_convert> m_utf8conv; #endif @@ -353,14 +381,17 @@ private: FILE *m_output_file; FILE *m_error_file; ConnectionFileDescriptor m_input_connection; - IsInputCompleteCallbackType m_is_input_complete_callback = nullptr; - void *m_is_input_complete_callback_baton = nullptr; - FixIndentationCallbackType m_fix_indentation_callback = nullptr; - void *m_fix_indentation_callback_baton = nullptr; + + IsInputCompleteCallbackType m_is_input_complete_callback; + + FixIndentationCallbackType m_fix_indentation_callback; const char *m_fix_indentation_callback_chars = nullptr; - CompleteCallbackType m_completion_callback = nullptr; - void *m_completion_callback_baton = nullptr; + CompleteCallbackType m_completion_callback; + + SuggestionCallbackType m_suggestion_callback; + + std::size_t m_previous_autosuggestion_size = 0; std::mutex m_output_mutex; }; } diff --git a/gnu/llvm/lldb/include/lldb/Host/File.h b/gnu/llvm/lldb/include/lldb/Host/File.h index d205a3fe691..d364d954a1c 100644 --- a/gnu/llvm/lldb/include/lldb/Host/File.h +++ b/gnu/llvm/lldb/include/lldb/Host/File.h @@ -15,9 +15,9 @@ #include "lldb/lldb-private.h" #include "llvm/ADT/BitmaskEnum.h" +#include +#include #include -#include -#include #include namespace lldb_private { @@ -65,10 +65,7 @@ public: static llvm::Expected GetStreamOpenModeFromOptions(OpenOptions options); - File() - : IOObject(eFDTypeFile), m_is_interactive(eLazyBoolCalculate), - m_is_real_terminal(eLazyBoolCalculate), - m_supports_colors(eLazyBoolCalculate){}; + File() : IOObject(eFDTypeFile){}; /// Read bytes from a file from the current file position into buf. /// @@ -360,9 +357,9 @@ public: static bool classof(const File *file) { return file->isA(&ID); } protected: - LazyBool m_is_interactive; - LazyBool m_is_real_terminal; - LazyBool m_supports_colors; + LazyBool m_is_interactive = eLazyBoolCalculate; + LazyBool m_is_real_terminal = eLazyBoolCalculate; + LazyBool m_supports_colors = eLazyBoolCalculate; void CalculateInteractiveAndTerminal(); @@ -373,9 +370,7 @@ private: class NativeFile : public File { public: - NativeFile() - : m_descriptor(kInvalidDescriptor), m_own_descriptor(false), - m_stream(kInvalidStream), m_options(), m_own_stream(false) {} + NativeFile() : m_descriptor(kInvalidDescriptor), m_stream(kInvalidStream) {} NativeFile(FILE *fh, bool transfer_ownership) : m_descriptor(kInvalidDescriptor), m_own_descriptor(false), m_stream(fh), @@ -422,10 +417,10 @@ protected: // Member variables int m_descriptor; - bool m_own_descriptor; + bool m_own_descriptor = false; FILE *m_stream; - OpenOptions m_options; - bool m_own_stream; + OpenOptions m_options{}; + bool m_own_stream = false; std::mutex offset_access_mutex; private: diff --git a/gnu/llvm/lldb/include/lldb/Host/FileAction.h b/gnu/llvm/lldb/include/lldb/Host/FileAction.h index 4d333bb327a..d3166c16a58 100644 --- a/gnu/llvm/lldb/include/lldb/Host/FileAction.h +++ b/gnu/llvm/lldb/include/lldb/Host/FileAction.h @@ -46,9 +46,9 @@ public: void Dump(Stream &stream) const; protected: - Action m_action; // The action for this file - int m_fd; // An existing file descriptor - int m_arg; // oflag for eFileActionOpen*, dup_fd for eFileActionDuplicate + Action m_action = eFileActionNone; // The action for this file + int m_fd = -1; // An existing file descriptor + int m_arg = -1; // oflag for eFileActionOpen*, dup_fd for eFileActionDuplicate FileSpec m_file_spec; // A file spec to use for opening after fork or posix_spawn }; diff --git a/gnu/llvm/lldb/include/lldb/Host/FileCache.h b/gnu/llvm/lldb/include/lldb/Host/FileCache.h index df0d9a88c6d..1bf5f0ca80e 100644 --- a/gnu/llvm/lldb/include/lldb/Host/FileCache.h +++ b/gnu/llvm/lldb/include/lldb/Host/FileCache.h @@ -8,8 +8,8 @@ #ifndef LLDB_HOST_FILECACHE_H #define LLDB_HOST_FILECACHE_H +#include #include -#include #include "lldb/lldb-forward.h" #include "lldb/lldb-types.h" @@ -21,7 +21,7 @@ namespace lldb_private { class FileCache { private: - FileCache() {} + FileCache() = default; typedef std::map FDToFileMap; diff --git a/gnu/llvm/lldb/include/lldb/Host/FileSystem.h b/gnu/llvm/lldb/include/lldb/Host/FileSystem.h index 8dcff340259..93563d4d26e 100644 --- a/gnu/llvm/lldb/include/lldb/Host/FileSystem.h +++ b/gnu/llvm/lldb/include/lldb/Host/FileSystem.h @@ -21,8 +21,8 @@ #include "lldb/lldb-types.h" -#include -#include +#include +#include #include namespace lldb_private { @@ -33,13 +33,14 @@ public: FileSystem() : m_fs(llvm::vfs::getRealFileSystem()), m_collector(nullptr), - m_mapped(false) {} - FileSystem(std::shared_ptr collector) - : m_fs(llvm::vfs::getRealFileSystem()), m_collector(collector), - m_mapped(false) {} + m_home_directory() {} + FileSystem(std::shared_ptr collector) + : m_fs(llvm::vfs::getRealFileSystem()), m_collector(std::move(collector)), + m_home_directory(), m_mapped(false) {} FileSystem(llvm::IntrusiveRefCntPtr fs, bool mapped = false) - : m_fs(fs), m_collector(nullptr), m_mapped(mapped) {} + : m_fs(std::move(fs)), m_collector(nullptr), m_home_directory(), + m_mapped(mapped) {} FileSystem(const FileSystem &fs) = delete; FileSystem &operator=(const FileSystem &fs) = delete; @@ -47,7 +48,7 @@ public: static FileSystem &Instance(); static void Initialize(); - static void Initialize(std::shared_ptr collector); + static void Initialize(std::shared_ptr collector); static llvm::Error Initialize(const FileSpec &mapping); static void Initialize(llvm::IntrusiveRefCntPtr fs); static void Terminate(); @@ -154,6 +155,10 @@ public: /// Call into the Host to see if it can help find the file. bool ResolveExecutableLocation(FileSpec &file_spec); + /// Get the user home directory. + bool GetHomeDirectory(llvm::SmallVectorImpl &path) const; + bool GetHomeDirectory(FileSpec &file_spec) const; + enum EnumerateDirectoryResult { /// Enumerate next entry in the current directory. eEnumerateDirectoryResultNext, @@ -189,11 +194,14 @@ public: void Collect(const FileSpec &file_spec); void Collect(const llvm::Twine &file); + void SetHomeDirectory(std::string home_directory); + private: static llvm::Optional &InstanceImpl(); llvm::IntrusiveRefCntPtr m_fs; - std::shared_ptr m_collector; - bool m_mapped; + std::shared_ptr m_collector; + std::string m_home_directory; + bool m_mapped = false; }; } // namespace lldb_private diff --git a/gnu/llvm/lldb/include/lldb/Host/Host.h b/gnu/llvm/lldb/include/lldb/Host/Host.h index f19cb85d232..1fdf7eab7eb 100644 --- a/gnu/llvm/lldb/include/lldb/Host/Host.h +++ b/gnu/llvm/lldb/include/lldb/Host/Host.h @@ -17,8 +17,8 @@ #include "lldb/lldb-private-forward.h" #include "lldb/lldb-private.h" #include +#include #include -#include #include #include @@ -196,19 +196,34 @@ public: static Status ShellExpandArguments(ProcessLaunchInfo &launch_info); /// Run a shell command. - /// \arg command shouldn't be NULL + /// \arg command shouldn't be empty /// \arg working_dir Pass empty FileSpec to use the current working directory /// \arg status_ptr Pass NULL if you don't want the process exit status /// \arg signo_ptr Pass NULL if you don't want the signal that caused the /// process to exit /// \arg command_output Pass NULL if you don't want the command output /// \arg hide_stderr if this is false, redirect stderr to stdout - /// TODO: Convert this function to take a StringRef. - static Status RunShellCommand(const char *command, + static Status RunShellCommand(llvm::StringRef command, const FileSpec &working_dir, int *status_ptr, int *signo_ptr, std::string *command_output, const Timeout &timeout, - bool run_in_default_shell = true, + bool run_in_shell = true, + bool hide_stderr = false); + + /// Run a shell command. + /// \arg shell Pass an empty string if you want to use the default shell + /// interpreter \arg command \arg working_dir Pass empty FileSpec to use the + /// current working directory \arg status_ptr Pass NULL if you don't want + /// the process exit status \arg signo_ptr Pass NULL if you don't want the + /// signal that caused + /// the process to exit + /// \arg command_output Pass NULL if you don't want the command output + /// \arg hide_stderr If this is \b false, redirect stderr to stdout + static Status RunShellCommand(llvm::StringRef shell, llvm::StringRef command, + const FileSpec &working_dir, int *status_ptr, + int *signo_ptr, std::string *command_output, + const Timeout &timeout, + bool run_in_shell = true, bool hide_stderr = false); /// Run a shell command. @@ -222,7 +237,23 @@ public: int *status_ptr, int *signo_ptr, std::string *command_output, const Timeout &timeout, - bool run_in_default_shell = true, + bool run_in_shell = true, + bool hide_stderr = false); + + /// Run a shell command. + /// \arg shell Pass an empty string if you want to use the default + /// shell interpreter \arg command \arg working_dir Pass empty FileSpec to use + /// the current working directory \arg status_ptr Pass NULL if you don't + /// want the process exit status \arg signo_ptr Pass NULL if you don't + /// want the signal that caused the + /// process to exit + /// \arg command_output Pass NULL if you don't want the command output + /// \arg hide_stderr If this is \b false, redirect stderr to stdout + static Status RunShellCommand(llvm::StringRef shell, const Args &args, + const FileSpec &working_dir, int *status_ptr, + int *signo_ptr, std::string *command_output, + const Timeout &timeout, + bool run_in_shell = true, bool hide_stderr = false); static bool OpenFileInExternalEditor(const FileSpec &file_spec, diff --git a/gnu/llvm/lldb/include/lldb/Host/HostInfoBase.h b/gnu/llvm/lldb/include/lldb/Host/HostInfoBase.h index 70682c9b685..eeed881101d 100644 --- a/gnu/llvm/lldb/include/lldb/Host/HostInfoBase.h +++ b/gnu/llvm/lldb/include/lldb/Host/HostInfoBase.h @@ -11,12 +11,13 @@ #include "lldb/Utility/ArchSpec.h" #include "lldb/Utility/FileSpec.h" +#include "lldb/Utility/UUID.h" #include "lldb/Utility/UserIDResolver.h" #include "lldb/Utility/XcodeSDK.h" #include "lldb/lldb-enumerations.h" #include "llvm/ADT/StringRef.h" -#include +#include #include @@ -24,14 +25,25 @@ namespace lldb_private { class FileSpec; +struct SharedCacheImageInfo { + UUID uuid; + lldb::DataBufferSP data_sp; +}; + class HostInfoBase { private: // Static class, unconstructable. - HostInfoBase() {} - ~HostInfoBase() {} + HostInfoBase() = default; + ~HostInfoBase() = default; public: - static void Initialize(); + /// A helper function for determining the liblldb location. It receives a + /// FileSpec with the location of file containing _this_ code. It can + /// (optionally) replace it with a file spec pointing to a more canonical + /// copy. + using SharedLibraryDirectoryHelper = void(FileSpec &this_file); + + static void Initialize(SharedLibraryDirectoryHelper *helper = nullptr); static void Terminate(); /// Gets the host target triple. @@ -98,6 +110,13 @@ public: /// Return the directory containing a specific Xcode SDK. static llvm::StringRef GetXcodeSDKPath(XcodeSDK sdk) { return {}; } + /// Return information about module \p image_name if it is loaded in + /// the current process's address space. + static SharedCacheImageInfo + GetSharedCacheImageInfo(llvm::StringRef image_name) { + return {}; + } + protected: static bool ComputeSharedLibraryDirectory(FileSpec &file_spec); static bool ComputeSupportExeDirectory(FileSpec &file_spec); diff --git a/gnu/llvm/lldb/include/lldb/Host/HostNativeProcessBase.h b/gnu/llvm/lldb/include/lldb/Host/HostNativeProcessBase.h index 642c63443c2..5469f8a50e2 100644 --- a/gnu/llvm/lldb/include/lldb/Host/HostNativeProcessBase.h +++ b/gnu/llvm/lldb/include/lldb/Host/HostNativeProcessBase.h @@ -27,7 +27,7 @@ public: HostNativeProcessBase() : m_process(LLDB_INVALID_PROCESS) {} explicit HostNativeProcessBase(lldb::process_t process) : m_process(process) {} - virtual ~HostNativeProcessBase() {} + virtual ~HostNativeProcessBase() = default; virtual Status Terminate() = 0; virtual Status GetMainModule(FileSpec &file_spec) const = 0; diff --git a/gnu/llvm/lldb/include/lldb/Host/HostNativeThreadBase.h b/gnu/llvm/lldb/include/lldb/Host/HostNativeThreadBase.h index 0dfd363cc8f..bfd70d74559 100644 --- a/gnu/llvm/lldb/include/lldb/Host/HostNativeThreadBase.h +++ b/gnu/llvm/lldb/include/lldb/Host/HostNativeThreadBase.h @@ -27,9 +27,9 @@ class HostNativeThreadBase { const HostNativeThreadBase &operator=(const HostNativeThreadBase &) = delete; public: - HostNativeThreadBase(); + HostNativeThreadBase() = default; explicit HostNativeThreadBase(lldb::thread_t thread); - virtual ~HostNativeThreadBase() {} + virtual ~HostNativeThreadBase() = default; virtual Status Join(lldb::thread_result_t *result) = 0; virtual Status Cancel() = 0; @@ -45,8 +45,8 @@ protected: static lldb::thread_result_t THREAD_ROUTINE ThreadCreateTrampoline(lldb::thread_arg_t arg); - lldb::thread_t m_thread; - lldb::thread_result_t m_result; + lldb::thread_t m_thread = LLDB_INVALID_HOST_THREAD; + lldb::thread_result_t m_result = 0; }; } diff --git a/gnu/llvm/lldb/include/lldb/Host/MainLoop.h b/gnu/llvm/lldb/include/lldb/Host/MainLoop.h index 9ca5040b60a..06785bbdbe2 100644 --- a/gnu/llvm/lldb/include/lldb/Host/MainLoop.h +++ b/gnu/llvm/lldb/include/lldb/Host/MainLoop.h @@ -13,6 +13,7 @@ #include "lldb/Host/MainLoopBase.h" #include "llvm/ADT/DenseMap.h" #include +#include #if !HAVE_PPOLL && !HAVE_SYS_EVENT_H && !defined(__ANDROID__) #define SIGNAL_POLLING_UNSUPPORTED 1 @@ -68,7 +69,7 @@ public: protected: void UnregisterReadObject(IOObject::WaitableHandle handle) override; - void UnregisterSignal(int signo); + void UnregisterSignal(int signo, std::list::iterator callback_it); private: void ProcessReadObject(IOObject::WaitableHandle handle); @@ -76,14 +77,16 @@ private: class SignalHandle { public: - ~SignalHandle() { m_mainloop.UnregisterSignal(m_signo); } + ~SignalHandle() { m_mainloop.UnregisterSignal(m_signo, m_callback_it); } private: - SignalHandle(MainLoop &mainloop, int signo) - : m_mainloop(mainloop), m_signo(signo) {} + SignalHandle(MainLoop &mainloop, int signo, + std::list::iterator callback_it) + : m_mainloop(mainloop), m_signo(signo), m_callback_it(callback_it) {} MainLoop &m_mainloop; int m_signo; + std::list::iterator m_callback_it; friend class MainLoop; SignalHandle(const SignalHandle &) = delete; @@ -91,7 +94,7 @@ private: }; struct SignalInfo { - Callback callback; + std::list callbacks; #if HAVE_SIGACTION struct sigaction old_action; #endif diff --git a/gnu/llvm/lldb/include/lldb/Host/MainLoopBase.h b/gnu/llvm/lldb/include/lldb/Host/MainLoopBase.h index fa8cc77a94b..67857b26ac7 100644 --- a/gnu/llvm/lldb/include/lldb/Host/MainLoopBase.h +++ b/gnu/llvm/lldb/include/lldb/Host/MainLoopBase.h @@ -33,8 +33,8 @@ private: class ReadHandle; public: - MainLoopBase() {} - virtual ~MainLoopBase() {} + MainLoopBase() = default; + virtual ~MainLoopBase() = default; typedef std::unique_ptr ReadHandleUP; diff --git a/gnu/llvm/lldb/include/lldb/Host/ProcessLaunchInfo.h b/gnu/llvm/lldb/include/lldb/Host/ProcessLaunchInfo.h index e83d8396e9f..3ed21637de7 100644 --- a/gnu/llvm/lldb/include/lldb/Host/ProcessLaunchInfo.h +++ b/gnu/llvm/lldb/include/lldb/Host/ProcessLaunchInfo.h @@ -20,6 +20,7 @@ #include "lldb/Host/PseudoTerminal.h" #include "lldb/Utility/FileSpec.h" #include "lldb/Utility/ProcessInfo.h" +#include "lldb/Utility/StructuredData.h" namespace lldb_private { @@ -94,10 +95,9 @@ public: void Clear(); - bool ConvertArgumentsForLaunchingInShell(Status &error, bool localhost, - bool will_debug, + bool ConvertArgumentsForLaunchingInShell(Status &error, bool will_debug, bool first_arg_is_full_shell_command, - int32_t num_resumes); + uint32_t num_resumes); void SetMonitorProcessCallback(const Host::MonitorChildProcessCallback &callback, @@ -147,6 +147,28 @@ public: return m_flags.Test(lldb::eLaunchFlagDetachOnError); } + bool IsScriptedProcess() const { + return !m_scripted_process_class_name.empty(); + } + + std::string GetScriptedProcessClassName() const { + return m_scripted_process_class_name; + } + + void SetScriptedProcessClassName(std::string name) { + m_scripted_process_class_name = name; + } + + lldb_private::StructuredData::DictionarySP + GetScriptedProcessDictionarySP() const { + return m_scripted_process_dictionary_sp; + } + + void SetScriptedProcessDictionarySP( + lldb_private::StructuredData::DictionarySP dictionary_sp) { + m_scripted_process_dictionary_sp = dictionary_sp; + } + protected: FileSpec m_working_dir; std::string m_plugin_name; @@ -154,14 +176,19 @@ protected: Flags m_flags; // Bitwise OR of bits from lldb::LaunchFlags std::vector m_file_actions; // File actions for any other files std::shared_ptr m_pty; - uint32_t m_resume_count; // How many times do we resume after launching + uint32_t m_resume_count = 0; // How many times do we resume after launching Host::MonitorChildProcessCallback m_monitor_callback; - void *m_monitor_callback_baton; - bool m_monitor_signals; + void *m_monitor_callback_baton = nullptr; + bool m_monitor_signals = false; std::string m_event_data; // A string passed to the plugin launch, having no // meaning to the upper levels of lldb. lldb::ListenerSP m_listener_sp; lldb::ListenerSP m_hijack_listener_sp; + std::string m_scripted_process_class_name; // The name of the class that will + // manage a scripted process. + StructuredData::DictionarySP + m_scripted_process_dictionary_sp; // A dictionary that holds key/value + // pairs passed to the scripted process. }; } diff --git a/gnu/llvm/lldb/include/lldb/Host/ProcessLauncher.h b/gnu/llvm/lldb/include/lldb/Host/ProcessLauncher.h index 9467b2c009b..33dbfd72d1e 100644 --- a/gnu/llvm/lldb/include/lldb/Host/ProcessLauncher.h +++ b/gnu/llvm/lldb/include/lldb/Host/ProcessLauncher.h @@ -17,7 +17,7 @@ class HostProcess; class ProcessLauncher { public: - virtual ~ProcessLauncher() {} + virtual ~ProcessLauncher() = default; virtual HostProcess LaunchProcess(const ProcessLaunchInfo &launch_info, Status &error) = 0; }; diff --git a/gnu/llvm/lldb/include/lldb/Host/ProcessRunLock.h b/gnu/llvm/lldb/include/lldb/Host/ProcessRunLock.h index 43463d144de..b5b5328b4a3 100644 --- a/gnu/llvm/lldb/include/lldb/Host/ProcessRunLock.h +++ b/gnu/llvm/lldb/include/lldb/Host/ProcessRunLock.h @@ -9,8 +9,8 @@ #ifndef LLDB_HOST_PROCESSRUNLOCK_H #define LLDB_HOST_PROCESSRUNLOCK_H -#include -#include +#include +#include #include "lldb/lldb-defines.h" @@ -35,7 +35,7 @@ public: class ProcessRunLocker { public: - ProcessRunLocker() : m_lock(nullptr) {} + ProcessRunLocker() = default; ~ProcessRunLocker() { Unlock(); } @@ -64,7 +64,7 @@ public: } } - ProcessRunLock *m_lock; + ProcessRunLock *m_lock = nullptr; private: ProcessRunLocker(const ProcessRunLocker &) = delete; @@ -73,7 +73,7 @@ public: protected: lldb::rwlock_t m_rwlock; - bool m_running; + bool m_running = false; private: ProcessRunLock(const ProcessRunLock &) = delete; diff --git a/gnu/llvm/lldb/include/lldb/Host/PseudoTerminal.h b/gnu/llvm/lldb/include/lldb/Host/PseudoTerminal.h index 8a5a233e774..bd1e2f56241 100644 --- a/gnu/llvm/lldb/include/lldb/Host/PseudoTerminal.h +++ b/gnu/llvm/lldb/include/lldb/Host/PseudoTerminal.h @@ -9,11 +9,11 @@ #ifndef LLDB_HOST_PSEUDOTERMINAL_H #define LLDB_HOST_PSEUDOTERMINAL_H +#include "lldb/lldb-defines.h" +#include "llvm/Support/Error.h" #include #include -#include "lldb/lldb-defines.h" - namespace lldb_private { /// \class PseudoTerminal PseudoTerminal.h "lldb/Host/PseudoTerminal.h" @@ -62,15 +62,11 @@ public: /// @li PseudoTerminal::ReleasePrimaryFileDescriptor() @li /// PseudoTerminal::ReleaseSaveFileDescriptor() /// - /// \param[out] error_str - /// An pointer to an error that can describe any errors that - /// occur. This can be NULL if no error status is desired. - /// /// \return /// \b Parent process: a child process ID that is greater - /// than zero, or -1 if the fork fails. + /// than zero, or an error if the fork fails. /// \b Child process: zero. - lldb::pid_t Fork(char *error_str, size_t error_len); + llvm::Expected Fork(); /// The primary file descriptor accessor. /// @@ -105,20 +101,11 @@ public: /// A primary pseudo terminal should already be valid prior to /// calling this function. /// - /// \param[out] error_str - /// An pointer to an error that can describe any errors that - /// occur. This can be NULL if no error status is desired. - /// /// \return - /// The name of the secondary pseudo terminal as a NULL terminated - /// C. This string that comes from static memory, so a copy of - /// the string should be made as subsequent calls can change - /// this value. NULL is returned if this object doesn't have - /// a valid primary pseudo terminal opened or if the call to - /// \c ptsname() fails. + /// The name of the secondary pseudo terminal. /// /// \see PseudoTerminal::OpenFirstAvailablePrimary() - const char *GetSecondaryName(char *error_str, size_t error_len) const; + std::string GetSecondaryName() const; /// Open the first available pseudo terminal. /// @@ -137,18 +124,9 @@ public: /// Flags to use when calling \c posix_openpt(\a oflag). /// A value of "O_RDWR|O_NOCTTY" is suggested. /// - /// \param[out] error_str - /// An pointer to an error that can describe any errors that - /// occur. This can be NULL if no error status is desired. - /// - /// \return - /// \b true when the primary files descriptor is - /// successfully opened. - /// \b false if anything goes wrong. - /// /// \see PseudoTerminal::GetPrimaryFileDescriptor() @see /// PseudoTerminal::ReleasePrimaryFileDescriptor() - bool OpenFirstAvailablePrimary(int oflag, char *error_str, size_t error_len); + llvm::Error OpenFirstAvailablePrimary(int oflag); /// Open the secondary for the current primary pseudo terminal. /// @@ -166,19 +144,10 @@ public: /// \param[in] oflag /// Flags to use when calling \c open(\a oflag). /// - /// \param[out] error_str - /// An pointer to an error that can describe any errors that - /// occur. This can be NULL if no error status is desired. - /// - /// \return - /// \b true when the primary files descriptor is - /// successfully opened. - /// \b false if anything goes wrong. - /// /// \see PseudoTerminal::OpenFirstAvailablePrimary() @see /// PseudoTerminal::GetSecondaryFileDescriptor() @see /// PseudoTerminal::ReleaseSecondaryFileDescriptor() - bool OpenSecondary(int oflag, char *error_str, size_t error_len); + llvm::Error OpenSecondary(int oflag); /// Release the primary file descriptor. /// @@ -206,8 +175,8 @@ public: protected: // Member variables - int m_primary_fd; ///< The file descriptor for the primary. - int m_secondary_fd; ///< The file descriptor for the secondary. + int m_primary_fd = invalid_fd; ///< The file descriptor for the primary. + int m_secondary_fd = invalid_fd; ///< The file descriptor for the secondary. private: PseudoTerminal(const PseudoTerminal &) = delete; diff --git a/gnu/llvm/lldb/include/lldb/Host/SafeMachO.h b/gnu/llvm/lldb/include/lldb/Host/SafeMachO.h index d7c376d23a4..0540383b8c5 100644 --- a/gnu/llvm/lldb/include/lldb/Host/SafeMachO.h +++ b/gnu/llvm/lldb/include/lldb/Host/SafeMachO.h @@ -23,6 +23,7 @@ #undef CPU_ARCH_MASK #undef CPU_ARCH_ABI64 +#undef CPU_ARCH_ABI64_32 #undef CPU_TYPE_ANY #undef CPU_TYPE_X86 @@ -31,12 +32,13 @@ #undef CPU_TYPE_MC98000 #undef CPU_TYPE_ARM #undef CPU_TYPE_ARM64 +#undef CPU_TYPE_ARM64_32 #undef CPU_TYPE_SPARC #undef CPU_TYPE_POWERPC #undef CPU_TYPE_POWERPC64 -#undef CPU_SUB_TYPE_MASK -#undef CPU_SUB_TYPE_LIB64 +#undef CPU_SUBTYPE_MASK +#undef CPU_SUBTYPE_LIB64 #undef CPU_SUBTYPE_MULTIPLE @@ -88,6 +90,9 @@ #undef CPU_SUBTYPE_ARM_V7M #undef CPU_SUBTYPE_ARM_V7EM +#undef CPU_SUBTYPE_ARM64E +#undef CPU_SUBTYPE_ARM64_32_V8 +#undef CPU_SUBTYPE_ARM64_V8 #undef CPU_SUBTYPE_ARM64_ALL #undef CPU_SUBTYPE_SPARC_ALL @@ -110,6 +115,47 @@ #undef CPU_SUBTYPE_MC980000_ALL #undef CPU_SUBTYPE_MC98601 +#undef VM_PROT_READ +#undef VM_PROT_WRITE +#undef VM_PROT_EXECUTE + +#undef ARM_DEBUG_STATE +#undef ARM_EXCEPTION_STATE +#undef ARM_EXCEPTION_STATE64 +#undef ARM_EXCEPTION_STATE64_COUNT +#undef ARM_THREAD_STATE +#undef ARM_THREAD_STATE64 +#undef ARM_THREAD_STATE64_COUNT +#undef ARM_THREAD_STATE_COUNT +#undef ARM_VFP_STATE +#undef ARN_THREAD_STATE_NONE +#undef PPC_EXCEPTION_STATE +#undef PPC_EXCEPTION_STATE64 +#undef PPC_FLOAT_STATE +#undef PPC_THREAD_STATE +#undef PPC_THREAD_STATE64 +#undef PPC_THREAD_STATE_NONE +#undef PPC_VECTOR_STATE +#undef x86_DEBUG_STATE +#undef x86_DEBUG_STATE32 +#undef x86_DEBUG_STATE64 +#undef x86_EXCEPTION_STATE +#undef x86_EXCEPTION_STATE32 +#undef x86_EXCEPTION_STATE64 +#undef x86_EXCEPTION_STATE64_COUNT +#undef x86_EXCEPTION_STATE_COUNT +#undef x86_FLOAT_STATE +#undef x86_FLOAT_STATE32 +#undef x86_FLOAT_STATE64 +#undef x86_FLOAT_STATE64_COUNT +#undef x86_FLOAT_STATE_COUNT +#undef x86_THREAD_STATE +#undef x86_THREAD_STATE32 +#undef x86_THREAD_STATE32_COUNT +#undef x86_THREAD_STATE64 +#undef x86_THREAD_STATE64_COUNT +#undef x86_THREAD_STATE_COUNT + #include "llvm/BinaryFormat/MachO.h" #endif // LLDB_HOST_SAFEMACHO_H diff --git a/gnu/llvm/lldb/include/lldb/Host/SocketAddress.h b/gnu/llvm/lldb/include/lldb/Host/SocketAddress.h index 862e1104a08..c88cc126065 100644 --- a/gnu/llvm/lldb/include/lldb/Host/SocketAddress.h +++ b/gnu/llvm/lldb/include/lldb/Host/SocketAddress.h @@ -9,7 +9,7 @@ #ifndef LLDB_HOST_SOCKETADDRESS_H #define LLDB_HOST_SOCKETADDRESS_H -#include +#include #ifdef _WIN32 #include "lldb/Host/windows/windows.h" diff --git a/gnu/llvm/lldb/include/lldb/Host/StringConvert.h b/gnu/llvm/lldb/include/lldb/Host/StringConvert.h index ad629ff3042..33608a85ff4 100644 --- a/gnu/llvm/lldb/include/lldb/Host/StringConvert.h +++ b/gnu/llvm/lldb/include/lldb/Host/StringConvert.h @@ -9,9 +9,7 @@ #ifndef LLDB_HOST_STRINGCONVERT_H #define LLDB_HOST_STRINGCONVERT_H -#include - - +#include namespace lldb_private { diff --git a/gnu/llvm/lldb/include/lldb/Host/Terminal.h b/gnu/llvm/lldb/include/lldb/Host/Terminal.h index 61993223ea0..ca91d6b5972 100644 --- a/gnu/llvm/lldb/include/lldb/Host/Terminal.h +++ b/gnu/llvm/lldb/include/lldb/Host/Terminal.h @@ -21,7 +21,7 @@ class Terminal { public: Terminal(int fd = -1) : m_fd(fd) {} - ~Terminal() {} + ~Terminal() = default; bool IsATerminal() const; @@ -116,12 +116,12 @@ protected: // Member variables Terminal m_tty; ///< A terminal - int m_tflags; ///< Cached tflags information. + int m_tflags = -1; ///< Cached tflags information. #if LLDB_ENABLE_TERMIOS std::unique_ptr m_termios_up; ///< Cached terminal state information. #endif - lldb::pid_t m_process_group; ///< Cached process group information. + lldb::pid_t m_process_group = -1; ///< Cached process group information. }; /// \class TerminalStateSwitcher Terminal.h "lldb/Host/Terminal.h" @@ -171,7 +171,8 @@ public: protected: // Member variables - mutable uint32_t m_currentState; ///< The currently active TTY state index. + mutable uint32_t m_currentState = + UINT32_MAX; ///< The currently active TTY state index. TerminalState m_ttystates[2]; ///< The array of TTY states that holds saved TTY info. }; diff --git a/gnu/llvm/lldb/include/lldb/Host/Time.h b/gnu/llvm/lldb/include/lldb/Host/Time.h index 83b76ec0f9d..aee4c43247c 100644 --- a/gnu/llvm/lldb/include/lldb/Host/Time.h +++ b/gnu/llvm/lldb/include/lldb/Host/Time.h @@ -19,7 +19,7 @@ #include extern time_t timegm(struct tm *t); #else -#include +#include #endif #endif // LLDB_HOST_TIME_H diff --git a/gnu/llvm/lldb/include/lldb/Host/XML.h b/gnu/llvm/lldb/include/lldb/Host/XML.h index a80f1e9e4d2..9edf46bf09d 100644 --- a/gnu/llvm/lldb/include/lldb/Host/XML.h +++ b/gnu/llvm/lldb/include/lldb/Host/XML.h @@ -107,7 +107,7 @@ public: void ForEachAttribute(AttributeCallback const &callback) const; protected: - XMLNodeImpl m_node; + XMLNodeImpl m_node = nullptr; }; class XMLDocument { @@ -138,7 +138,7 @@ public: static bool XMLEnabled(); protected: - XMLDocumentImpl m_document; + XMLDocumentImpl m_document = nullptr; StreamString m_errors; }; diff --git a/gnu/llvm/lldb/include/lldb/Host/common/NativeProcessProtocol.h b/gnu/llvm/lldb/include/lldb/Host/common/NativeProcessProtocol.h index 2faab6f587c..770149e3fb2 100644 --- a/gnu/llvm/lldb/include/lldb/Host/common/NativeProcessProtocol.h +++ b/gnu/llvm/lldb/include/lldb/Host/common/NativeProcessProtocol.h @@ -16,7 +16,8 @@ #include "lldb/Host/MainLoop.h" #include "lldb/Utility/ArchSpec.h" #include "lldb/Utility/Status.h" -#include "lldb/Utility/TraceOptions.h" +#include "lldb/Utility/TraceGDBRemotePackets.h" +#include "lldb/Utility/UnimplementedError.h" #include "lldb/lldb-private-forward.h" #include "lldb/lldb-types.h" #include "llvm/ADT/ArrayRef.h" @@ -29,6 +30,8 @@ #include namespace lldb_private { +LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE(); + class MemoryRegionInfo; class ResumeActionList; @@ -43,7 +46,7 @@ struct SVR4LibraryInfo { // NativeProcessProtocol class NativeProcessProtocol { public: - virtual ~NativeProcessProtocol() {} + virtual ~NativeProcessProtocol() = default; virtual Status Resume(const ResumeActionList &resume_actions) = 0; @@ -84,6 +87,12 @@ public: Status ReadMemoryWithoutTrap(lldb::addr_t addr, void *buf, size_t size, size_t &bytes_read); + virtual Status ReadMemoryTags(int32_t type, lldb::addr_t addr, size_t len, + std::vector &tags); + + virtual Status WriteMemoryTags(int32_t type, lldb::addr_t addr, size_t len, + const std::vector &tags); + /// Reads a null terminated string from memory. /// /// Reads up to \p max_size bytes of memory until it finds a '\0'. @@ -112,10 +121,14 @@ public: virtual Status WriteMemory(lldb::addr_t addr, const void *buf, size_t size, size_t &bytes_written) = 0; - virtual Status AllocateMemory(size_t size, uint32_t permissions, - lldb::addr_t &addr) = 0; + virtual llvm::Expected AllocateMemory(size_t size, + uint32_t permissions) { + return llvm::make_error(); + } - virtual Status DeallocateMemory(lldb::addr_t addr) = 0; + virtual llvm::Error DeallocateMemory(lldb::addr_t addr) { + return llvm::make_error(); + } virtual lldb::addr_t GetSharedLibraryInfoAddress() = 0; @@ -207,7 +220,7 @@ public: // Callbacks for low-level process state changes class NativeDelegate { public: - virtual ~NativeDelegate() {} + virtual ~NativeDelegate() = default; virtual void InitializeDelegate(NativeProcessProtocol *process) = 0; @@ -215,37 +228,11 @@ public: lldb::StateType state) = 0; virtual void DidExec(NativeProcessProtocol *process) = 0; - }; - /// Register a native delegate. - /// - /// Clients can register nofication callbacks by passing in a - /// NativeDelegate impl and passing it into this function. - /// - /// Note: it is required that the lifetime of the - /// native_delegate outlive the NativeProcessProtocol. - /// - /// \param[in] native_delegate - /// A NativeDelegate impl to be called when certain events - /// happen within the NativeProcessProtocol or related threads. - /// - /// \return - /// true if the delegate was registered successfully; - /// false if the delegate was already registered. - /// - /// \see NativeProcessProtocol::NativeDelegate. - bool RegisterNativeDelegate(NativeDelegate &native_delegate); - - /// Unregister a native delegate previously registered. - /// - /// \param[in] native_delegate - /// A NativeDelegate impl previously registered with this process. - /// - /// \return Returns \b true if the NativeDelegate was - /// successfully removed from the process, \b false otherwise. - /// - /// \see NativeProcessProtocol::NativeDelegate - bool UnregisterNativeDelegate(NativeDelegate &native_delegate); + virtual void + NewSubprocess(NativeProcessProtocol *parent_process, + std::unique_ptr child_process) = 0; + }; virtual Status GetLoadedModuleFileSpec(const char *module_path, FileSpec &file_spec) = 0; @@ -253,6 +240,20 @@ public: virtual Status GetFileLoadAddress(const llvm::StringRef &file_name, lldb::addr_t &load_addr) = 0; + /// Extension flag constants, returned by Factory::GetSupportedExtensions() + /// and passed to SetEnabledExtension() + enum class Extension { + multiprocess = (1u << 0), + fork = (1u << 1), + vfork = (1u << 2), + pass_signals = (1u << 3), + auxv = (1u << 4), + libraries_svr4 = (1u << 5), + memory_tagging = (1u << 6), + + LLVM_MARK_AS_BITMASK_ENUM(memory_tagging) + }; + class Factory { public: virtual ~Factory(); @@ -299,92 +300,73 @@ public: virtual llvm::Expected> Attach(lldb::pid_t pid, NativeDelegate &native_delegate, MainLoop &mainloop) const = 0; + + /// Get the bitmask of extensions supported by this process plugin. + /// + /// \return + /// A NativeProcessProtocol::Extension bitmask. + virtual Extension GetSupportedExtensions() const { return {}; } }; - /// StartTracing API for starting a tracing instance with the - /// TraceOptions on a specific thread or process. + /// Start tracing a process or its threads. + /// + /// \param[in] json_params + /// JSON object with the information of what and how to trace. + /// In the case of gdb-remote, this object should conform to the + /// jLLDBTraceStart packet. /// - /// \param[in] config - /// The configuration to use when starting tracing. + /// This object should have a string entry called "type", which is the + /// tracing technology name. /// - /// \param[out] error - /// Status indicates what went wrong. + /// \param[in] type + /// Tracing technology type, as described in the \a json_params. /// /// \return - /// The API returns a user_id which can be used to get trace - /// data, trace configuration or stopping the trace instance. - /// The user_id is a key to identify and operate with a tracing - /// instance. It may refer to the complete process or a single - /// thread. - virtual lldb::user_id_t StartTrace(const TraceOptions &config, - Status &error) { - error.SetErrorString("Not implemented"); - return LLDB_INVALID_UID; + /// \a llvm::Error::success if the operation was successful, or an + /// \a llvm::Error otherwise. + virtual llvm::Error TraceStart(llvm::StringRef json_params, + llvm::StringRef type) { + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "Unsupported tracing type '%s'", + type.data()); } - /// StopTracing API as the name suggests stops a tracing instance. - /// - /// \param[in] traceid - /// The user id of the trace intended to be stopped. Now a - /// user_id may map to multiple threads in which case this API - /// could be used to stop the tracing for a specific thread by - /// supplying its thread id. - /// - /// \param[in] thread - /// Thread is needed when the complete process is being traced - /// and the user wishes to stop tracing on a particular thread. - /// - /// \return - /// Status indicating what went wrong. - virtual Status StopTrace(lldb::user_id_t traceid, - lldb::tid_t thread = LLDB_INVALID_THREAD_ID) { - return Status("Not implemented"); + /// \copydoc Process::TraceStop(const TraceStopRequest &) + virtual llvm::Error TraceStop(const TraceStopRequest &request) { + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "Unsupported tracing type '%s'", + request.type.data()); } - /// This API provides the trace data collected in the form of raw - /// data. - /// - /// \param[in] traceid thread - /// The traceid and thread provide the context for the trace - /// instance. - /// - /// \param[in] buffer - /// The buffer provides the destination buffer where the trace - /// data would be read to. The buffer should be truncated to the - /// filled length by this function. - /// - /// \param[in] offset - /// There is possibility to read partially the trace data from - /// a specified offset where in such cases the buffer provided - /// may be smaller than the internal trace collection container. - /// - /// \return - /// The size of the data actually read. - virtual Status GetData(lldb::user_id_t traceid, lldb::tid_t thread, - llvm::MutableArrayRef &buffer, - size_t offset = 0) { - return Status("Not implemented"); + /// \copydoc Process::TraceGetState(llvm::StringRef type) + virtual llvm::Expected + TraceGetState(llvm::StringRef type) { + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "Unsupported tracing type '%s'", + type.data()); } - /// Similar API as above except it aims to provide any extra data - /// useful for decoding the actual trace data. - virtual Status GetMetaData(lldb::user_id_t traceid, lldb::tid_t thread, - llvm::MutableArrayRef &buffer, - size_t offset = 0) { - return Status("Not implemented"); + /// \copydoc Process::TraceGetBinaryData(const TraceGetBinaryDataRequest &) + virtual llvm::Expected> + TraceGetBinaryData(const TraceGetBinaryDataRequest &request) { + return llvm::createStringError( + llvm::inconvertibleErrorCode(), + "Unsupported data kind '%s' for the '%s' tracing technology", + request.kind.c_str(), request.type.c_str()); } - /// API to query the TraceOptions for a given user id - /// - /// \param[in] traceid - /// The user id of the tracing instance. - /// - /// \param[out] config - /// The configuration being used for tracing. + /// \copydoc Process::TraceSupported() + virtual llvm::Expected TraceSupported() { + return llvm::make_error(); + } + + /// Method called in order to propagate the bitmap of protocol + /// extensions supported by the client. /// - /// \return A status indicating what went wrong. - virtual Status GetTraceConfig(lldb::user_id_t traceid, TraceOptions &config) { - return Status("Not implemented"); + /// \param[in] flags + /// The bitmap of enabled extensions. + virtual void SetEnabledExtensions(Extension flags) { + m_enabled_extensions = flags; } protected: @@ -406,8 +388,7 @@ protected: llvm::Optional m_exit_status; - std::recursive_mutex m_delegates_mutex; - std::vector m_delegates; + NativeDelegate &m_delegate; NativeWatchpointList m_watchpoint_list; HardwareBreakpointMap m_hw_breakpoints_map; int m_terminal_fd; @@ -417,6 +398,9 @@ protected: // stopping it. llvm::DenseSet m_signals_to_ignore; + // Extensions enabled per the last SetEnabledExtensions() call. + Extension m_enabled_extensions; + // lldb_private::Host calls should be used to launch a process for debugging, // and then the process should be attached to. When attaching to a process // lldb_private::Host calls should be used to locate the process to attach diff --git a/gnu/llvm/lldb/include/lldb/Host/common/NativeRegisterContext.h b/gnu/llvm/lldb/include/lldb/Host/common/NativeRegisterContext.h index 3b54d4ae1e0..f7568fe31b8 100644 --- a/gnu/llvm/lldb/include/lldb/Host/common/NativeRegisterContext.h +++ b/gnu/llvm/lldb/include/lldb/Host/common/NativeRegisterContext.h @@ -16,6 +16,8 @@ namespace lldb_private { class NativeThreadProtocol; +enum class ExpeditedRegs { Minimal, Full }; + class NativeRegisterContext : public std::enable_shared_from_this { public: @@ -75,6 +77,8 @@ public: virtual bool ClearHardwareWatchpoint(uint32_t hw_index); + virtual Status ClearWatchpointHit(uint32_t hw_index); + virtual Status ClearAllHardwareWatchpoints(); virtual Status IsWatchpointHit(uint32_t wp_index, bool &is_hit); @@ -114,6 +118,11 @@ public: virtual NativeThreadProtocol &GetThread() { return m_thread; } + virtual std::vector + GetExpeditedRegisters(ExpeditedRegs expType) const; + + virtual bool RegisterOffsetIsDynamic() const { return false; } + const RegisterInfo *GetRegisterInfoByName(llvm::StringRef reg_name, uint32_t start_idx = 0); diff --git a/gnu/llvm/lldb/include/lldb/Host/common/NativeThreadProtocol.h b/gnu/llvm/lldb/include/lldb/Host/common/NativeThreadProtocol.h index 8d4c03549bb..5cf26bd9593 100644 --- a/gnu/llvm/lldb/include/lldb/Host/common/NativeThreadProtocol.h +++ b/gnu/llvm/lldb/include/lldb/Host/common/NativeThreadProtocol.h @@ -21,7 +21,7 @@ class NativeThreadProtocol { public: NativeThreadProtocol(NativeProcessProtocol &process, lldb::tid_t tid); - virtual ~NativeThreadProtocol() {} + virtual ~NativeThreadProtocol() = default; virtual std::string GetName() = 0; diff --git a/gnu/llvm/lldb/include/lldb/Host/linux/Host.h b/gnu/llvm/lldb/include/lldb/Host/linux/Host.h new file mode 100644 index 00000000000..409a9fc9b32 --- /dev/null +++ b/gnu/llvm/lldb/include/lldb/Host/linux/Host.h @@ -0,0 +1,22 @@ +//===-- Host.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_HOST_LINUX_HOST_H +#define LLDB_HOST_LINUX_HOST_H + +#include "lldb/lldb-types.h" +#include "llvm/ADT/Optional.h" + +namespace lldb_private { + +// Get PID (i.e. the primary thread ID) corresponding to the specified TID. +llvm::Optional getPIDForTID(lldb::pid_t tid); + +} // namespace lldb_private + +#endif // #ifndef LLDB_HOST_LINUX_HOST_H diff --git a/gnu/llvm/lldb/include/lldb/Host/linux/HostInfoLinux.h b/gnu/llvm/lldb/include/lldb/Host/linux/HostInfoLinux.h index b1c7f9c805b..32200464886 100644 --- a/gnu/llvm/lldb/include/lldb/Host/linux/HostInfoLinux.h +++ b/gnu/llvm/lldb/include/lldb/Host/linux/HostInfoLinux.h @@ -21,13 +21,9 @@ namespace lldb_private { class HostInfoLinux : public HostInfoPosix { friend class HostInfoBase; -private: - // Static class, unconstructable. - HostInfoLinux(); - ~HostInfoLinux(); - public: - static void Initialize(); + static void Initialize(SharedLibraryDirectoryHelper *helper = nullptr); + static void Terminate(); static llvm::VersionTuple GetOSVersion(); static bool GetOSBuildString(std::string &s); diff --git a/gnu/llvm/lldb/include/lldb/Host/linux/Ptrace.h b/gnu/llvm/lldb/include/lldb/Host/linux/Ptrace.h index c54b75f0711..29489d1ae48 100644 --- a/gnu/llvm/lldb/include/lldb/Host/linux/Ptrace.h +++ b/gnu/llvm/lldb/include/lldb/Host/linux/Ptrace.h @@ -50,6 +50,12 @@ typedef int __ptrace_request; #define ARCH_GET_FS 0x1003 #define ARCH_GET_GS 0x1004 #endif +#ifndef PTRACE_PEEKMTETAGS +#define PTRACE_PEEKMTETAGS 33 +#endif +#ifndef PTRACE_POKEMTETAGS +#define PTRACE_POKEMTETAGS 34 +#endif #define LLDB_PTRACE_NT_ARM_TLS 0x401 // ARM TLS register diff --git a/gnu/llvm/lldb/include/lldb/Host/macosx/HostInfoMacOSX.h b/gnu/llvm/lldb/include/lldb/Host/macosx/HostInfoMacOSX.h index 3941414f8ab..4623932ab2b 100644 --- a/gnu/llvm/lldb/include/lldb/Host/macosx/HostInfoMacOSX.h +++ b/gnu/llvm/lldb/include/lldb/Host/macosx/HostInfoMacOSX.h @@ -21,11 +21,6 @@ class ArchSpec; class HostInfoMacOSX : public HostInfoPosix { friend class HostInfoBase; -private: - // Static class, unconstructable. - HostInfoMacOSX() = delete; - ~HostInfoMacOSX() = delete; - public: static llvm::VersionTuple GetOSVersion(); static llvm::VersionTuple GetMacCatalystVersion(); @@ -37,6 +32,11 @@ public: /// Query xcrun to find an Xcode SDK directory. static llvm::StringRef GetXcodeSDKPath(XcodeSDK sdk); + + /// Shared cache utilities + static SharedCacheImageInfo + GetSharedCacheImageInfo(llvm::StringRef image_name); + protected: static bool ComputeSupportExeDirectory(FileSpec &file_spec); static void ComputeHostArchitectureSupport(ArchSpec &arch_32, diff --git a/gnu/llvm/lldb/include/lldb/Host/posix/ConnectionFileDescriptorPosix.h b/gnu/llvm/lldb/include/lldb/Host/posix/ConnectionFileDescriptorPosix.h index 3ee8f9d9133..42be989dfa7 100644 --- a/gnu/llvm/lldb/include/lldb/Host/posix/ConnectionFileDescriptorPosix.h +++ b/gnu/llvm/lldb/include/lldb/Host/posix/ConnectionFileDescriptorPosix.h @@ -108,7 +108,7 @@ protected: std::atomic m_shutting_down; // This marks that we are shutting down so // if we get woken up from // BytesAvailable to disconnect, we won't try to read again. - bool m_waiting_for_accept; + bool m_waiting_for_accept = false; bool m_child_processes_inherit; std::string m_uri; diff --git a/gnu/llvm/lldb/include/lldb/Host/windows/HostInfoWindows.h b/gnu/llvm/lldb/include/lldb/Host/windows/HostInfoWindows.h index 209d9da0821..f01113e9004 100644 --- a/gnu/llvm/lldb/include/lldb/Host/windows/HostInfoWindows.h +++ b/gnu/llvm/lldb/include/lldb/Host/windows/HostInfoWindows.h @@ -19,13 +19,8 @@ class UserIDResolver; class HostInfoWindows : public HostInfoBase { friend class HostInfoBase; -private: - // Static class, unconstructable. - HostInfoWindows(); - ~HostInfoWindows(); - public: - static void Initialize(); + static void Initialize(SharedLibraryDirectoryHelper *helper = nullptr); static void Terminate(); static size_t GetPageSize(); diff --git a/gnu/llvm/lldb/include/lldb/Host/windows/HostThreadWindows.h b/gnu/llvm/lldb/include/lldb/Host/windows/HostThreadWindows.h index 63d0d73faad..a74539543aa 100644 --- a/gnu/llvm/lldb/include/lldb/Host/windows/HostThreadWindows.h +++ b/gnu/llvm/lldb/include/lldb/Host/windows/HostThreadWindows.h @@ -26,10 +26,10 @@ public: void SetOwnsHandle(bool owns); - virtual Status Join(lldb::thread_result_t *result); - virtual Status Cancel(); - virtual void Reset(); - virtual bool EqualsThread(lldb::thread_t thread) const; + Status Join(lldb::thread_result_t *result) override; + Status Cancel() override; + void Reset() override; + bool EqualsThread(lldb::thread_t thread) const override; lldb::tid_t GetThreadId() const; diff --git a/gnu/llvm/lldb/include/lldb/Host/windows/PosixApi.h b/gnu/llvm/lldb/include/lldb/Host/windows/PosixApi.h index a4c3dcdbc52..26398ac5eb1 100644 --- a/gnu/llvm/lldb/include/lldb/Host/windows/PosixApi.h +++ b/gnu/llvm/lldb/include/lldb/Host/windows/PosixApi.h @@ -16,10 +16,10 @@ #endif // va_start, va_end, etc macros. -#include +#include // time_t, timespec, etc. -#include +#include #ifndef PATH_MAX #define PATH_MAX 32768 @@ -68,7 +68,7 @@ #ifdef _MSC_VER // PRIxxx format macros for printf() -#include +#include // open(), close(), creat(), etc. #include @@ -98,7 +98,6 @@ typedef uint32_t pid_t; // custom implementations. int vasprintf(char **ret, const char *fmt, va_list ap); char *strcasestr(const char *s, const char *find); -char *realpath(const char *name, char *resolved); #ifdef _MSC_VER diff --git a/gnu/llvm/lldb/include/lldb/Host/windows/ProcessLauncherWindows.h b/gnu/llvm/lldb/include/lldb/Host/windows/ProcessLauncherWindows.h index e765f1e9ed5..81aea5b2022 100644 --- a/gnu/llvm/lldb/include/lldb/Host/windows/ProcessLauncherWindows.h +++ b/gnu/llvm/lldb/include/lldb/Host/windows/ProcessLauncherWindows.h @@ -18,8 +18,8 @@ class ProcessLaunchInfo; class ProcessLauncherWindows : public ProcessLauncher { public: - virtual HostProcess LaunchProcess(const ProcessLaunchInfo &launch_info, - Status &error); + HostProcess LaunchProcess(const ProcessLaunchInfo &launch_info, + Status &error) override; protected: HANDLE GetStdioHandle(const ProcessLaunchInfo &launch_info, int fd); diff --git a/gnu/llvm/lldb/include/lldb/Initialization/SystemInitializerCommon.h b/gnu/llvm/lldb/include/lldb/Initialization/SystemInitializerCommon.h index 3a508168087..d918b1125a5 100644 --- a/gnu/llvm/lldb/include/lldb/Initialization/SystemInitializerCommon.h +++ b/gnu/llvm/lldb/include/lldb/Initialization/SystemInitializerCommon.h @@ -10,6 +10,7 @@ #define LLDB_INITIALIZATION_SYSTEMINITIALIZERCOMMON_H #include "SystemInitializer.h" +#include "lldb/Host/HostInfo.h" namespace lldb_private { /// Initializes common lldb functionality. @@ -22,11 +23,14 @@ namespace lldb_private { /// the constructor. class SystemInitializerCommon : public SystemInitializer { public: - SystemInitializerCommon(); + SystemInitializerCommon(HostInfo::SharedLibraryDirectoryHelper *helper); ~SystemInitializerCommon() override; llvm::Error Initialize() override; void Terminate() override; + +private: + HostInfo::SharedLibraryDirectoryHelper *m_shlib_dir_helper; }; } // namespace lldb_private diff --git a/gnu/llvm/lldb/include/lldb/Initialization/SystemLifetimeManager.h b/gnu/llvm/lldb/include/lldb/Initialization/SystemLifetimeManager.h index 27e1a22b19d..06328e60133 100644 --- a/gnu/llvm/lldb/include/lldb/Initialization/SystemLifetimeManager.h +++ b/gnu/llvm/lldb/include/lldb/Initialization/SystemLifetimeManager.h @@ -30,7 +30,7 @@ public: private: std::recursive_mutex m_mutex; std::unique_ptr m_initializer; - bool m_initialized; + bool m_initialized = false; // Noncopyable. SystemLifetimeManager(const SystemLifetimeManager &other) = delete; diff --git a/gnu/llvm/lldb/include/lldb/Interpreter/CommandCompletions.h b/gnu/llvm/lldb/include/lldb/Interpreter/CommandCompletions.h index 39d1c98eaa3..c80bde0e719 100644 --- a/gnu/llvm/lldb/include/lldb/Interpreter/CommandCompletions.h +++ b/gnu/llvm/lldb/include/lldb/Interpreter/CommandCompletions.h @@ -37,10 +37,23 @@ public: eRegisterCompletion = (1u << 9), eBreakpointCompletion = (1u << 10), eProcessPluginCompletion = (1u << 11), + eDisassemblyFlavorCompletion = (1u << 12), + eTypeLanguageCompletion = (1u << 13), + eFrameIndexCompletion = (1u << 14), + eModuleUUIDCompletion = (1u << 15), + eStopHookIDCompletion = (1u << 16), + eThreadIndexCompletion = (1u << 17), + eWatchPointIDCompletion = (1u << 18), + eBreakpointNameCompletion = (1u << 19), + eProcessIDCompletion = (1u << 20), + eProcessNameCompletion = (1u << 21), + eRemoteDiskFileCompletion = (1u << 22), + eRemoteDiskDirectoryCompletion = (1u << 23), + eTypeCategoryNameCompletion = (1u << 24), // This item serves two purposes. It is the last element in the enum, so // you can add custom enums starting from here in your Option class. Also // if you & in this bit the base code will not process the option. - eCustomCompletion = (1u << 12) + eCustomCompletion = (1u << 24) }; static bool InvokeCommonCompletionCallbacks( @@ -62,12 +75,23 @@ public: StringList &matches, TildeExpressionResolver &Resolver); + static void RemoteDiskFiles(CommandInterpreter &interpreter, + CompletionRequest &request, + SearchFilter *searcher); + + static void RemoteDiskDirectories(CommandInterpreter &interpreter, + CompletionRequest &request, + SearchFilter *searcher); + static void SourceFiles(CommandInterpreter &interpreter, CompletionRequest &request, SearchFilter *searcher); static void Modules(CommandInterpreter &interpreter, CompletionRequest &request, SearchFilter *searcher); + static void ModuleUUIDs(CommandInterpreter &interpreter, + CompletionRequest &request, SearchFilter *searcher); + static void Symbols(CommandInterpreter &interpreter, CompletionRequest &request, SearchFilter *searcher); @@ -91,9 +115,42 @@ public: static void Breakpoints(CommandInterpreter &interpreter, CompletionRequest &request, SearchFilter *searcher); + static void BreakpointNames(CommandInterpreter &interpreter, + CompletionRequest &request, + SearchFilter *searcher); + static void ProcessPluginNames(CommandInterpreter &interpreter, CompletionRequest &request, SearchFilter *searcher); + + static void ProcessIDs(CommandInterpreter &interpreter, + CompletionRequest &request, SearchFilter *searcher); + + static void ProcessNames(CommandInterpreter &interpreter, + CompletionRequest &request, SearchFilter *searcher); + + static void DisassemblyFlavors(CommandInterpreter &interpreter, + CompletionRequest &request, + SearchFilter *searcher); + + static void TypeLanguages(CommandInterpreter &interpreter, + CompletionRequest &request, SearchFilter *searcher); + + static void FrameIndexes(CommandInterpreter &interpreter, + CompletionRequest &request, SearchFilter *searcher); + + static void StopHookIDs(CommandInterpreter &interpreter, + CompletionRequest &request, SearchFilter *searcher); + + static void ThreadIndexes(CommandInterpreter &interpreter, + CompletionRequest &request, SearchFilter *searcher); + + static void WatchPointIDs(CommandInterpreter &interpreter, + CompletionRequest &request, SearchFilter *searcher); + + static void TypeCategoryNames(CommandInterpreter &interpreter, + CompletionRequest &request, + SearchFilter *searcher); }; } // namespace lldb_private diff --git a/gnu/llvm/lldb/include/lldb/Interpreter/CommandHistory.h b/gnu/llvm/lldb/include/lldb/Interpreter/CommandHistory.h index fbb42247f11..12c170ba5ee 100644 --- a/gnu/llvm/lldb/include/lldb/Interpreter/CommandHistory.h +++ b/gnu/llvm/lldb/include/lldb/Interpreter/CommandHistory.h @@ -20,9 +20,9 @@ namespace lldb_private { class CommandHistory { public: - CommandHistory(); + CommandHistory() = default; - ~CommandHistory(); + ~CommandHistory() = default; size_t GetSize() const; diff --git a/gnu/llvm/lldb/include/lldb/Interpreter/CommandInterpreter.h b/gnu/llvm/lldb/include/lldb/Interpreter/CommandInterpreter.h index 8a9dce7a19b..3b3daced3e3 100644 --- a/gnu/llvm/lldb/include/lldb/Interpreter/CommandInterpreter.h +++ b/gnu/llvm/lldb/include/lldb/Interpreter/CommandInterpreter.h @@ -20,18 +20,20 @@ #include "lldb/Utility/CompletionRequest.h" #include "lldb/Utility/Event.h" #include "lldb/Utility/Log.h" +#include "lldb/Utility/StreamString.h" #include "lldb/Utility/StringList.h" #include "lldb/lldb-forward.h" #include "lldb/lldb-private.h" + #include +#include namespace lldb_private { class CommandInterpreter; class CommandInterpreterRunResult { public: - CommandInterpreterRunResult() - : m_num_errors(0), m_result(lldb::eCommandInterpreterResultSuccess) {} + CommandInterpreterRunResult() = default; uint32_t GetNumErrors() const { return m_num_errors; } @@ -49,8 +51,9 @@ protected: void SetResult(lldb::CommandInterpreterResult result) { m_result = result; } private: - int m_num_errors; - lldb::CommandInterpreterResult m_result; + int m_num_errors = 0; + lldb::CommandInterpreterResult m_result = + lldb::eCommandInterpreterResultSuccess; }; class CommandInterpreterRunOptions { @@ -97,14 +100,7 @@ public: m_echo_comment_commands(echo_comments), m_print_results(print_results), m_print_errors(print_errors), m_add_to_history(add_to_history) {} - CommandInterpreterRunOptions() - : m_stop_on_continue(eLazyBoolCalculate), - m_stop_on_error(eLazyBoolCalculate), - m_stop_on_crash(eLazyBoolCalculate), - m_echo_commands(eLazyBoolCalculate), - m_echo_comment_commands(eLazyBoolCalculate), - m_print_results(eLazyBoolCalculate), m_print_errors(eLazyBoolCalculate), - m_add_to_history(eLazyBoolCalculate) {} + CommandInterpreterRunOptions() = default; void SetSilent(bool silent) { LazyBool value = silent ? eLazyBoolNo : eLazyBoolYes; @@ -184,14 +180,14 @@ public: m_spawn_thread = spawn_thread ? eLazyBoolYes : eLazyBoolNo; } - LazyBool m_stop_on_continue; - LazyBool m_stop_on_error; - LazyBool m_stop_on_crash; - LazyBool m_echo_commands; - LazyBool m_echo_comment_commands; - LazyBool m_print_results; - LazyBool m_print_errors; - LazyBool m_add_to_history; + LazyBool m_stop_on_continue = eLazyBoolCalculate; + LazyBool m_stop_on_error = eLazyBoolCalculate; + LazyBool m_stop_on_crash = eLazyBoolCalculate; + LazyBool m_echo_commands = eLazyBoolCalculate; + LazyBool m_echo_comment_commands = eLazyBoolCalculate; + LazyBool m_print_results = eLazyBoolCalculate; + LazyBool m_print_errors = eLazyBoolCalculate; + LazyBool m_add_to_history = eLazyBoolCalculate; LazyBool m_auto_handle_events; LazyBool m_spawn_thread; @@ -244,7 +240,7 @@ public: CommandInterpreter(Debugger &debugger, bool synchronous_execution); - ~CommandInterpreter() override; + ~CommandInterpreter() override = default; // These two functions fill out the Broadcaster interface: @@ -255,7 +251,7 @@ public: } void SourceInitFileCwd(CommandReturnObject &result); - void SourceInitFileHome(CommandReturnObject &result); + void SourceInitFileHome(CommandReturnObject &result, bool is_repl = false); bool AddCommand(llvm::StringRef name, const lldb::CommandObjectSP &cmd_sp, bool can_replace); @@ -264,7 +260,7 @@ public: bool can_replace); lldb::CommandObjectSP GetCommandSPExact(llvm::StringRef cmd, - bool include_aliases) const; + bool include_aliases = false) const; CommandObject *GetCommandObject(llvm::StringRef cmd, StringList *matches = nullptr, @@ -299,10 +295,11 @@ public: CommandReturnObject &result); bool HandleCommand(const char *command_line, LazyBool add_to_history, - CommandReturnObject &result, - ExecutionContext *override_context = nullptr, - bool repeat_on_empty_command = true, - bool no_context_switching = false); + const ExecutionContext &override_context, + CommandReturnObject &result); + + bool HandleCommand(const char *command_line, LazyBool add_to_history, + CommandReturnObject &result); bool WasInterrupted() const; @@ -311,9 +308,7 @@ public: /// \param[in] commands /// The list of commands to execute. /// \param[in,out] context - /// The execution context in which to run the commands. Can be nullptr in - /// which case the default - /// context will be used. + /// The execution context in which to run the commands. /// \param[in] options /// This object holds the options used to control when to stop, whether to /// execute commands, @@ -323,8 +318,13 @@ public: /// safely, /// and failed with some explanation if we aborted executing the commands /// at some point. - void HandleCommands(const StringList &commands, ExecutionContext *context, - CommandInterpreterRunOptions &options, + void HandleCommands(const StringList &commands, + const ExecutionContext &context, + const CommandInterpreterRunOptions &options, + CommandReturnObject &result); + + void HandleCommands(const StringList &commands, + const CommandInterpreterRunOptions &options, CommandReturnObject &result); /// Execute a list of commands from a file. @@ -332,9 +332,7 @@ public: /// \param[in] file /// The file from which to read in commands. /// \param[in,out] context - /// The execution context in which to run the commands. Can be nullptr in - /// which case the default - /// context will be used. + /// The execution context in which to run the commands. /// \param[in] options /// This object holds the options used to control when to stop, whether to /// execute commands, @@ -344,12 +342,20 @@ public: /// safely, /// and failed with some explanation if we aborted executing the commands /// at some point. - void HandleCommandsFromFile(FileSpec &file, ExecutionContext *context, - CommandInterpreterRunOptions &options, + void HandleCommandsFromFile(FileSpec &file, const ExecutionContext &context, + const CommandInterpreterRunOptions &options, + CommandReturnObject &result); + + void HandleCommandsFromFile(FileSpec &file, + const CommandInterpreterRunOptions &options, CommandReturnObject &result); CommandObject *GetCommandObjectForCommand(llvm::StringRef &command_line); + /// Returns the auto-suggestion string that should be added to the given + /// command line. + llvm::Optional GetAutoSuggestionForCommand(llvm::StringRef line); + // This handles command line completion. void HandleCompletion(CompletionRequest &request); @@ -386,12 +392,7 @@ public: Debugger &GetDebugger() { return m_debugger; } - ExecutionContext GetExecutionContext() { - const bool thread_and_frame_only_if_stopped = true; - return m_exe_ctx_ref.Lock(thread_and_frame_only_if_stopped); - } - - void UpdateExecutionContext(ExecutionContext *override_context); + ExecutionContext GetExecutionContext() const; lldb::PlatformSP GetPlatform(bool prefer_target_platform); @@ -485,19 +486,32 @@ public: bool GetExpandRegexAliases() const; bool GetPromptOnQuit() const; - void SetPromptOnQuit(bool enable); + bool GetSaveSessionOnQuit() const; + void SetSaveSessionOnQuit(bool enable); + + FileSpec GetSaveSessionDirectory() const; + void SetSaveSessionDirectory(llvm::StringRef path); + bool GetEchoCommands() const; void SetEchoCommands(bool enable); bool GetEchoCommentCommands() const; void SetEchoCommentCommands(bool enable); + bool GetRepeatPreviousCommand() const; + const CommandObject::CommandMap &GetUserCommands() const { return m_user_dict; } + const CommandObject::CommandMap &GetCommands() const { + return m_command_dict; + } + + const CommandObject::CommandMap &GetAliases() const { return m_alias_dict; } + /// Specify if the command interpreter should allow that the user can /// specify a custom exit code when calling 'quit'. void AllowExitCodeOnQuit(bool allow); @@ -526,6 +540,20 @@ public: bool GetSpaceReplPrompts() const; + /// Save the current debugger session transcript to a file on disk. + /// \param output_file + /// The file path to which the session transcript will be written. Since + /// the argument is optional, an arbitrary temporary file will be create + /// when no argument is passed. + /// \param result + /// This is used to pass function output and error messages. + /// \return \b true if the session transcript was successfully written to + /// disk, \b false otherwise. + bool SaveTranscript(CommandReturnObject &result, + llvm::Optional output_file = llvm::None); + + FileSpec GetCurrentSourceDir(); + protected: friend class Debugger; @@ -554,6 +582,10 @@ protected: StringList *descriptions = nullptr) const; private: + void OverrideExecutionContext(const ExecutionContext &override_context); + + void RestoreExecutionContext(); + Status PreprocessCommand(std::string &command); void SourceInitFile(FileSpec file, CommandReturnObject &result); @@ -592,8 +624,9 @@ private: Debugger &m_debugger; // The debugger session that this interpreter is // associated with - ExecutionContextRef m_exe_ctx_ref; // The current execution context to use - // when handling commands + // Execution contexts that were temporarily set by some of HandleCommand* + // overloads. + std::stack m_overriden_exe_contexts; bool m_synchronous_execution; bool m_skip_lldbinit_files; bool m_skip_app_init_files; @@ -612,7 +645,13 @@ private: ChildrenTruncatedWarningStatus m_truncation_warning; // Whether we truncated // children and whether // the user has been told + + // FIXME: Stop using this to control adding to the history and then replace + // this with m_command_source_dirs.size(). uint32_t m_command_source_depth; + /// A stack of directory paths. When not empty, the last one is the directory + /// of the file that's currently sourced. + std::vector m_command_source_dirs; std::vector m_command_source_flags; CommandInterpreterRunResult m_result; @@ -621,6 +660,8 @@ private: llvm::Optional m_quit_exit_code; // If the driver is accepts custom exit codes for the 'quit' command. bool m_allow_exit_code = false; + + StreamString m_transcript_stream; }; } // namespace lldb_private diff --git a/gnu/llvm/lldb/include/lldb/Interpreter/CommandObject.h b/gnu/llvm/lldb/include/lldb/Interpreter/CommandObject.h index cc4d40b23c3..8bc5d3e2235 100644 --- a/gnu/llvm/lldb/include/lldb/Interpreter/CommandObject.h +++ b/gnu/llvm/lldb/include/lldb/Interpreter/CommandObject.h @@ -90,14 +90,15 @@ public: { lldb::CommandArgumentType arg_type; ArgumentRepetitionType arg_repetition; - uint32_t arg_opt_set_association; // This arg might be associated only with - // some particular option set(s). - CommandArgumentData() - : arg_type(lldb::eArgTypeNone), arg_repetition(eArgRepeatPlain), - arg_opt_set_association(LLDB_OPT_SET_ALL) // By default, the arg - // associates to all option - // sets. - {} + /// This arg might be associated only with some particular option set(s). By + /// default the arg associates to all option sets. + uint32_t arg_opt_set_association; + + CommandArgumentData(lldb::CommandArgumentType type = lldb::eArgTypeNone, + ArgumentRepetitionType repetition = eArgRepeatPlain, + uint32_t opt_set = LLDB_OPT_SET_ALL) + : arg_type(type), arg_repetition(repetition), + arg_opt_set_association(opt_set) {} }; typedef std::vector @@ -112,7 +113,7 @@ public: llvm::StringRef help = "", llvm::StringRef syntax = "", uint32_t flags = 0); - virtual ~CommandObject(); + virtual ~CommandObject() = default; static const char * GetArgumentTypeAsCString(const lldb::CommandArgumentType arg_type); diff --git a/gnu/llvm/lldb/include/lldb/Interpreter/CommandObjectMultiword.h b/gnu/llvm/lldb/include/lldb/Interpreter/CommandObjectMultiword.h index 6b383f8cfb3..f330a745f9b 100644 --- a/gnu/llvm/lldb/include/lldb/Interpreter/CommandObjectMultiword.h +++ b/gnu/llvm/lldb/include/lldb/Interpreter/CommandObjectMultiword.h @@ -82,6 +82,10 @@ public: // for this object. virtual CommandObject *GetProxyCommandObject() = 0; + llvm::StringRef GetSyntax() override; + + llvm::StringRef GetHelp() override; + llvm::StringRef GetHelpLong() override; bool IsRemovable() const override; @@ -121,6 +125,11 @@ public: const char *GetRepeatCommand(Args ¤t_command_args, uint32_t index) override; + /// \return + /// An error message to be displayed when the command is executed (i.e. + /// Execute is called) and \a GetProxyCommandObject returned null. + virtual llvm::StringRef GetUnsupportedError(); + bool Execute(const char *args_string, CommandReturnObject &result) override; protected: diff --git a/gnu/llvm/lldb/include/lldb/Interpreter/CommandReturnObject.h b/gnu/llvm/lldb/include/lldb/Interpreter/CommandReturnObject.h index a7c2eea5766..0c995b73c46 100644 --- a/gnu/llvm/lldb/include/lldb/Interpreter/CommandReturnObject.h +++ b/gnu/llvm/lldb/include/lldb/Interpreter/CommandReturnObject.h @@ -26,7 +26,7 @@ class CommandReturnObject { public: CommandReturnObject(bool colors); - ~CommandReturnObject(); + ~CommandReturnObject() = default; llvm::StringRef GetOutputData() { lldb::StreamSP stream_sp(m_out_stream.GetStreamAtIndex(eStreamStringIndex)); @@ -63,20 +63,28 @@ public: } void SetImmediateOutputFile(lldb::FileSP file_sp) { + if (m_suppress_immediate_output) + return; lldb::StreamSP stream_sp(new StreamFile(file_sp)); m_out_stream.SetStreamAtIndex(eImmediateStreamIndex, stream_sp); } void SetImmediateErrorFile(lldb::FileSP file_sp) { + if (m_suppress_immediate_output) + return; lldb::StreamSP stream_sp(new StreamFile(file_sp)); m_err_stream.SetStreamAtIndex(eImmediateStreamIndex, stream_sp); } void SetImmediateOutputStream(const lldb::StreamSP &stream_sp) { + if (m_suppress_immediate_output) + return; m_out_stream.SetStreamAtIndex(eImmediateStreamIndex, stream_sp); } void SetImmediateErrorStream(const lldb::StreamSP &stream_sp) { + if (m_suppress_immediate_output) + return; m_err_stream.SetStreamAtIndex(eImmediateStreamIndex, stream_sp); } @@ -95,8 +103,6 @@ public: void AppendMessageWithFormat(const char *format, ...) __attribute__((format(printf, 2, 3))); - void AppendRawWarning(llvm::StringRef in_string); - void AppendWarning(llvm::StringRef in_string); void AppendWarningWithFormat(const char *format, ...) @@ -126,8 +132,6 @@ public: void SetError(const Status &error, const char *fallback_error_cstr = nullptr); - void SetError(llvm::StringRef error_cstr); - lldb::ReturnStatus GetStatus(); void SetStatus(lldb::ReturnStatus status); @@ -144,16 +148,23 @@ public: void SetInteractive(bool b); + bool GetSuppressImmediateOutput() const; + + void SetSuppressImmediateOutput(bool b); + private: enum { eStreamStringIndex = 0, eImmediateStreamIndex = 1 }; StreamTee m_out_stream; StreamTee m_err_stream; - lldb::ReturnStatus m_status; - bool m_did_change_process_state; - bool m_interactive; // If true, then the input handle from the debugger will - // be hooked up + lldb::ReturnStatus m_status = lldb::eReturnStatusStarted; + + bool m_did_change_process_state = false; + bool m_suppress_immediate_output = false; + + /// If true, then the input handle from the debugger will be hooked up. + bool m_interactive = true; }; } // namespace lldb_private diff --git a/gnu/llvm/lldb/include/lldb/Interpreter/OptionGroupArchitecture.h b/gnu/llvm/lldb/include/lldb/Interpreter/OptionGroupArchitecture.h index 1eadf45bae4..4655a68f1e4 100644 --- a/gnu/llvm/lldb/include/lldb/Interpreter/OptionGroupArchitecture.h +++ b/gnu/llvm/lldb/include/lldb/Interpreter/OptionGroupArchitecture.h @@ -18,9 +18,9 @@ namespace lldb_private { class OptionGroupArchitecture : public OptionGroup { public: - OptionGroupArchitecture(); + OptionGroupArchitecture() = default; - ~OptionGroupArchitecture() override; + ~OptionGroupArchitecture() override = default; llvm::ArrayRef GetDefinitions() override; diff --git a/gnu/llvm/lldb/include/lldb/Interpreter/OptionGroupBoolean.h b/gnu/llvm/lldb/include/lldb/Interpreter/OptionGroupBoolean.h index 061e3134085..9e2dad5d9c2 100644 --- a/gnu/llvm/lldb/include/lldb/Interpreter/OptionGroupBoolean.h +++ b/gnu/llvm/lldb/include/lldb/Interpreter/OptionGroupBoolean.h @@ -25,7 +25,7 @@ public: const char *usage_text, bool default_value, bool no_argument_toggle_default); - ~OptionGroupBoolean() override; + ~OptionGroupBoolean() override = default; llvm::ArrayRef GetDefinitions() override { return llvm::ArrayRef(&m_option_definition, 1); @@ -33,7 +33,6 @@ public: Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value, ExecutionContext *execution_context) override; - Status SetOptionValue(uint32_t, const char *, ExecutionContext *) = delete; void OptionParsingStarting(ExecutionContext *execution_context) override; diff --git a/gnu/llvm/lldb/include/lldb/Interpreter/OptionGroupFile.h b/gnu/llvm/lldb/include/lldb/Interpreter/OptionGroupFile.h index 374cf10ea30..1e4eb35eade 100644 --- a/gnu/llvm/lldb/include/lldb/Interpreter/OptionGroupFile.h +++ b/gnu/llvm/lldb/include/lldb/Interpreter/OptionGroupFile.h @@ -24,7 +24,7 @@ public: lldb::CommandArgumentType argument_type, const char *usage_text); - ~OptionGroupFile() override; + ~OptionGroupFile() override = default; llvm::ArrayRef GetDefinitions() override { return llvm::ArrayRef(&m_option_definition, 1); @@ -32,7 +32,6 @@ public: Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value, ExecutionContext *execution_context) override; - Status SetOptionValue(uint32_t, const char *, ExecutionContext *) = delete; void OptionParsingStarting(ExecutionContext *execution_context) override; @@ -63,7 +62,6 @@ public: Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value, ExecutionContext *execution_context) override; - Status SetOptionValue(uint32_t, const char *, ExecutionContext *) = delete; void OptionParsingStarting(ExecutionContext *execution_context) override; diff --git a/gnu/llvm/lldb/include/lldb/Interpreter/OptionGroupFormat.h b/gnu/llvm/lldb/include/lldb/Interpreter/OptionGroupFormat.h index 62c6f97c621..2d445b8a6c2 100644 --- a/gnu/llvm/lldb/include/lldb/Interpreter/OptionGroupFormat.h +++ b/gnu/llvm/lldb/include/lldb/Interpreter/OptionGroupFormat.h @@ -32,13 +32,12 @@ public: uint64_t default_count = UINT64_MAX); // Pass UINT64_MAX to disable the "--count" option - ~OptionGroupFormat() override; + ~OptionGroupFormat() override = default; llvm::ArrayRef GetDefinitions() override; Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value, ExecutionContext *execution_context) override; - Status SetOptionValue(uint32_t, const char *, ExecutionContext *) = delete; void OptionParsingStarting(ExecutionContext *execution_context) override; diff --git a/gnu/llvm/lldb/include/lldb/Interpreter/OptionGroupOutputFile.h b/gnu/llvm/lldb/include/lldb/Interpreter/OptionGroupOutputFile.h index a71998f3bc1..3902247cfb3 100644 --- a/gnu/llvm/lldb/include/lldb/Interpreter/OptionGroupOutputFile.h +++ b/gnu/llvm/lldb/include/lldb/Interpreter/OptionGroupOutputFile.h @@ -20,13 +20,12 @@ class OptionGroupOutputFile : public OptionGroup { public: OptionGroupOutputFile(); - ~OptionGroupOutputFile() override; + ~OptionGroupOutputFile() override = default; llvm::ArrayRef GetDefinitions() override; Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value, ExecutionContext *execution_context) override; - Status SetOptionValue(uint32_t, const char *, ExecutionContext *) = delete; void OptionParsingStarting(ExecutionContext *execution_context) override; diff --git a/gnu/llvm/lldb/include/lldb/Interpreter/OptionGroupPlatform.h b/gnu/llvm/lldb/include/lldb/Interpreter/OptionGroupPlatform.h index 99945e5246f..fed2791a613 100644 --- a/gnu/llvm/lldb/include/lldb/Interpreter/OptionGroupPlatform.h +++ b/gnu/llvm/lldb/include/lldb/Interpreter/OptionGroupPlatform.h @@ -21,8 +21,7 @@ namespace lldb_private { class OptionGroupPlatform : public OptionGroup { public: OptionGroupPlatform(bool include_platform_option) - : OptionGroup(), m_platform_name(), m_sdk_sysroot(), - m_include_platform_option(include_platform_option) {} + : m_include_platform_option(include_platform_option) {} ~OptionGroupPlatform() override = default; diff --git a/gnu/llvm/lldb/include/lldb/Interpreter/OptionGroupPythonClassWithDict.h b/gnu/llvm/lldb/include/lldb/Interpreter/OptionGroupPythonClassWithDict.h index d4c924a4415..a0de1bc8b8a 100644 --- a/gnu/llvm/lldb/include/lldb/Interpreter/OptionGroupPythonClassWithDict.h +++ b/gnu/llvm/lldb/include/lldb/Interpreter/OptionGroupPythonClassWithDict.h @@ -1,4 +1,4 @@ -//===-- OptionGroupPythonClassWithDict.h -------------------------------------*- C++ -*-===// +//===-- OptionGroupPythonClassWithDict.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. @@ -9,9 +9,10 @@ #ifndef LLDB_INTERPRETER_OPTIONGROUPPYTHONCLASSWITHDICT_H #define LLDB_INTERPRETER_OPTIONGROUPPYTHONCLASSWITHDICT_H -#include "lldb/lldb-types.h" #include "lldb/Interpreter/Options.h" +#include "lldb/Utility/Flags.h" #include "lldb/Utility/StructuredData.h" +#include "lldb/lldb-types.h" namespace lldb_private { @@ -23,13 +24,21 @@ namespace lldb_private { // StructuredData::Dictionary is constructed with those pairs. class OptionGroupPythonClassWithDict : public OptionGroup { public: - OptionGroupPythonClassWithDict(const char *class_use, - bool is_class = true, - int class_option = 'C', - int key_option = 'k', - int value_option = 'v'); - - ~OptionGroupPythonClassWithDict() override; + enum OptionKind { + eScriptClass = 1 << 0, + eDictKey = 1 << 1, + eDictValue = 1 << 2, + ePythonFunction = 1 << 3, + eAllOptions = (eScriptClass | eDictKey | eDictValue | ePythonFunction) + }; + + OptionGroupPythonClassWithDict(const char *class_use, bool is_class = true, + int class_option = 'C', int key_option = 'k', + int value_option = 'v', + uint16_t required_options = eScriptClass | + ePythonFunction); + + ~OptionGroupPythonClassWithDict() override = default; llvm::ArrayRef GetDefinitions() override { return llvm::ArrayRef(m_option_definition); @@ -37,7 +46,6 @@ public: Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value, ExecutionContext *execution_context) override; - Status SetOptionValue(uint32_t, const char *, ExecutionContext *) = delete; void OptionParsingStarting(ExecutionContext *execution_context) override; Status OptionParsingFinished(ExecutionContext *execution_context) override; @@ -56,6 +64,7 @@ protected: std::string m_class_usage_text, m_key_usage_text, m_value_usage_text; bool m_is_class; OptionDefinition m_option_definition[4]; + Flags m_required_options; }; } // namespace lldb_private diff --git a/gnu/llvm/lldb/include/lldb/Interpreter/OptionGroupString.h b/gnu/llvm/lldb/include/lldb/Interpreter/OptionGroupString.h index 1a3b5bdd88e..aa022563903 100644 --- a/gnu/llvm/lldb/include/lldb/Interpreter/OptionGroupString.h +++ b/gnu/llvm/lldb/include/lldb/Interpreter/OptionGroupString.h @@ -22,7 +22,7 @@ public: lldb::CommandArgumentType argument_type, const char *usage_text, const char *default_value); - ~OptionGroupString() override; + ~OptionGroupString() override = default; llvm::ArrayRef GetDefinitions() override { return llvm::ArrayRef(&m_option_definition, 1); @@ -30,7 +30,6 @@ public: Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value, ExecutionContext *execution_context) override; - Status SetOptionValue(uint32_t, const char *, ExecutionContext *) = delete; void OptionParsingStarting(ExecutionContext *execution_context) override; diff --git a/gnu/llvm/lldb/include/lldb/Interpreter/OptionGroupUInt64.h b/gnu/llvm/lldb/include/lldb/Interpreter/OptionGroupUInt64.h index 783c4b632f0..71059172540 100644 --- a/gnu/llvm/lldb/include/lldb/Interpreter/OptionGroupUInt64.h +++ b/gnu/llvm/lldb/include/lldb/Interpreter/OptionGroupUInt64.h @@ -23,7 +23,7 @@ public: lldb::CommandArgumentType argument_type, const char *usage_text, uint64_t default_value); - ~OptionGroupUInt64() override; + ~OptionGroupUInt64() override = default; llvm::ArrayRef GetDefinitions() override { return llvm::ArrayRef(&m_option_definition, 1); @@ -31,7 +31,6 @@ public: Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value, ExecutionContext *execution_context) override; - Status SetOptionValue(uint32_t, const char *, ExecutionContext *) = delete; void OptionParsingStarting(ExecutionContext *execution_context) override; diff --git a/gnu/llvm/lldb/include/lldb/Interpreter/OptionGroupUUID.h b/gnu/llvm/lldb/include/lldb/Interpreter/OptionGroupUUID.h index b1c779f7b5a..4ca2a94b7fb 100644 --- a/gnu/llvm/lldb/include/lldb/Interpreter/OptionGroupUUID.h +++ b/gnu/llvm/lldb/include/lldb/Interpreter/OptionGroupUUID.h @@ -18,15 +18,14 @@ namespace lldb_private { class OptionGroupUUID : public OptionGroup { public: - OptionGroupUUID(); + OptionGroupUUID() = default; - ~OptionGroupUUID() override; + ~OptionGroupUUID() override = default; llvm::ArrayRef GetDefinitions() override; Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value, ExecutionContext *execution_context) override; - Status SetOptionValue(uint32_t, const char *, ExecutionContext *) = delete; void OptionParsingStarting(ExecutionContext *execution_context) override; diff --git a/gnu/llvm/lldb/include/lldb/Interpreter/OptionGroupValueObjectDisplay.h b/gnu/llvm/lldb/include/lldb/Interpreter/OptionGroupValueObjectDisplay.h index 1ad53321d26..56452f4956f 100644 --- a/gnu/llvm/lldb/include/lldb/Interpreter/OptionGroupValueObjectDisplay.h +++ b/gnu/llvm/lldb/include/lldb/Interpreter/OptionGroupValueObjectDisplay.h @@ -18,15 +18,14 @@ namespace lldb_private { class OptionGroupValueObjectDisplay : public OptionGroup { public: - OptionGroupValueObjectDisplay(); + OptionGroupValueObjectDisplay() = default; - ~OptionGroupValueObjectDisplay() override; + ~OptionGroupValueObjectDisplay() override = default; llvm::ArrayRef GetDefinitions() override; Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value, ExecutionContext *execution_context) override; - Status SetOptionValue(uint32_t, const char *, ExecutionContext *) = delete; void OptionParsingStarting(ExecutionContext *execution_context) override; diff --git a/gnu/llvm/lldb/include/lldb/Interpreter/OptionGroupVariable.h b/gnu/llvm/lldb/include/lldb/Interpreter/OptionGroupVariable.h index 252ca3b42c5..c9f1283d4de 100644 --- a/gnu/llvm/lldb/include/lldb/Interpreter/OptionGroupVariable.h +++ b/gnu/llvm/lldb/include/lldb/Interpreter/OptionGroupVariable.h @@ -20,13 +20,12 @@ class OptionGroupVariable : public OptionGroup { public: OptionGroupVariable(bool show_frame_options); - ~OptionGroupVariable() override; + ~OptionGroupVariable() override = default; llvm::ArrayRef GetDefinitions() override; Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value, ExecutionContext *execution_context) override; - Status SetOptionValue(uint32_t, const char *, ExecutionContext *) = delete; void OptionParsingStarting(ExecutionContext *execution_context) override; diff --git a/gnu/llvm/lldb/include/lldb/Interpreter/OptionGroupWatchpoint.h b/gnu/llvm/lldb/include/lldb/Interpreter/OptionGroupWatchpoint.h index 6a6c8638aed..33818043cf6 100644 --- a/gnu/llvm/lldb/include/lldb/Interpreter/OptionGroupWatchpoint.h +++ b/gnu/llvm/lldb/include/lldb/Interpreter/OptionGroupWatchpoint.h @@ -17,9 +17,9 @@ namespace lldb_private { class OptionGroupWatchpoint : public OptionGroup { public: - OptionGroupWatchpoint(); + OptionGroupWatchpoint() = default; - ~OptionGroupWatchpoint() override; + ~OptionGroupWatchpoint() override = default; static bool IsWatchSizeSupported(uint32_t watch_size); @@ -27,7 +27,6 @@ public: Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value, ExecutionContext *execution_context) override; - Status SetOptionValue(uint32_t, const char *, ExecutionContext *) = delete; void OptionParsingStarting(ExecutionContext *execution_context) override; diff --git a/gnu/llvm/lldb/include/lldb/Interpreter/OptionValue.h b/gnu/llvm/lldb/include/lldb/Interpreter/OptionValue.h index 5b07427094b..99f52b0411b 100644 --- a/gnu/llvm/lldb/include/lldb/Interpreter/OptionValue.h +++ b/gnu/llvm/lldb/include/lldb/Interpreter/OptionValue.h @@ -10,6 +10,7 @@ #define LLDB_INTERPRETER_OPTIONVALUE_H #include "lldb/Core/FormatEntity.h" +#include "lldb/Utility/Cloneable.h" #include "lldb/Utility/CompletionRequest.h" #include "lldb/Utility/ConstString.h" #include "lldb/Utility/Status.h" @@ -31,6 +32,7 @@ public: eTypeChar, eTypeDictionary, eTypeEnum, + eTypeFileLineColumn, eTypeFileSpec, eTypeFileSpecList, eTypeFormat, @@ -58,7 +60,7 @@ public: eDumpGroupExport = (eDumpOptionCommand | eDumpOptionName | eDumpOptionValue) }; - OptionValue() : m_value_was_set(false) {} + OptionValue() = default; virtual ~OptionValue() = default; @@ -84,9 +86,10 @@ public: SetValueFromString(llvm::StringRef value, VarSetOperationType op = eVarSetOperationAssign); - virtual bool Clear() = 0; + virtual void Clear() = 0; - virtual lldb::OptionValueSP DeepCopy() const = 0; + virtual lldb::OptionValueSP + DeepCopy(const lldb::OptionValueSP &new_parent) const; virtual void AutoComplete(CommandInterpreter &interpreter, CompletionRequest &request); @@ -135,6 +138,8 @@ public: return eTypeDictionary; case 1u << eTypeEnum: return eTypeEnum; + case 1u << eTypeFileLineColumn: + return eTypeFileLineColumn; case 1u << eTypeFileSpec: return eTypeFileSpec; case 1u << eTypeFileSpecList: @@ -303,6 +308,8 @@ public: m_parent_wp = parent_sp; } + lldb::OptionValueSP GetParent() const { return m_parent_wp.lock(); } + void SetValueChangedCallback(std::function callback) { assert(!m_callback); m_callback = std::move(callback); @@ -314,14 +321,20 @@ public: } protected: + using TopmostBase = OptionValue; + + // Must be overriden by a derived class for correct downcasting the result of + // DeepCopy to it. Inherit from Cloneable to avoid doing this manually. + virtual lldb::OptionValueSP Clone() const = 0; + lldb::OptionValueWP m_parent_wp; std::function m_callback; - bool m_value_was_set; // This can be used to see if a value has been set - // by a call to SetValueFromCString(). It is often - // handy to know if an option value was set from the - // command line or as a setting, versus if we just have - // the default value that was already populated in the - // option value. + bool m_value_was_set = false; // This can be used to see if a value has been + // set by a call to SetValueFromCString(). It is + // often handy to know if an option value was + // set from the command line or as a setting, + // versus if we just have the default value that + // was already populated in the option value. }; } // namespace lldb_private diff --git a/gnu/llvm/lldb/include/lldb/Interpreter/OptionValueArch.h b/gnu/llvm/lldb/include/lldb/Interpreter/OptionValueArch.h index 7b63c68fddb..e1752087944 100644 --- a/gnu/llvm/lldb/include/lldb/Interpreter/OptionValueArch.h +++ b/gnu/llvm/lldb/include/lldb/Interpreter/OptionValueArch.h @@ -15,23 +15,21 @@ namespace lldb_private { -class OptionValueArch : public OptionValue { +class OptionValueArch : public Cloneable { public: - OptionValueArch() : OptionValue(), m_current_value(), m_default_value() {} + OptionValueArch() = default; - OptionValueArch(const char *triple) - : OptionValue(), m_current_value(triple), m_default_value() { + OptionValueArch(const char *triple) : m_current_value(triple) { m_default_value = m_current_value; } OptionValueArch(const ArchSpec &value) - : OptionValue(), m_current_value(value), m_default_value(value) {} + : m_current_value(value), m_default_value(value) {} OptionValueArch(const ArchSpec ¤t_value, const ArchSpec &default_value) - : OptionValue(), m_current_value(current_value), - m_default_value(default_value) {} + : m_current_value(current_value), m_default_value(default_value) {} - ~OptionValueArch() override {} + ~OptionValueArch() override = default; // Virtual subclass pure virtual overrides @@ -43,18 +41,12 @@ public: Status SetValueFromString(llvm::StringRef value, VarSetOperationType op = eVarSetOperationAssign) override; - Status - SetValueFromString(const char *, - VarSetOperationType = eVarSetOperationAssign) = delete; - bool Clear() override { + void Clear() override { m_current_value = m_default_value; m_value_was_set = false; - return true; } - lldb::OptionValueSP DeepCopy() const override; - void AutoComplete(CommandInterpreter &interpreter, lldb_private::CompletionRequest &request) override; diff --git a/gnu/llvm/lldb/include/lldb/Interpreter/OptionValueArgs.h b/gnu/llvm/lldb/include/lldb/Interpreter/OptionValueArgs.h index 25f7fdde0bf..1e2a1430d0c 100644 --- a/gnu/llvm/lldb/include/lldb/Interpreter/OptionValueArgs.h +++ b/gnu/llvm/lldb/include/lldb/Interpreter/OptionValueArgs.h @@ -13,15 +13,14 @@ namespace lldb_private { -class OptionValueArgs : public OptionValueArray { +class OptionValueArgs : public Cloneable { public: OptionValueArgs() - : OptionValueArray( - OptionValue::ConvertTypeToMask(OptionValue::eTypeString)) {} + : Cloneable(OptionValue::ConvertTypeToMask(OptionValue::eTypeString)) {} - ~OptionValueArgs() override {} + ~OptionValueArgs() override = default; - size_t GetArgs(Args &args); + size_t GetArgs(Args &args) const; Type GetType() const override { return eTypeArgs; } }; diff --git a/gnu/llvm/lldb/include/lldb/Interpreter/OptionValueArray.h b/gnu/llvm/lldb/include/lldb/Interpreter/OptionValueArray.h index 000351c2f58..011eefc3425 100644 --- a/gnu/llvm/lldb/include/lldb/Interpreter/OptionValueArray.h +++ b/gnu/llvm/lldb/include/lldb/Interpreter/OptionValueArray.h @@ -15,12 +15,12 @@ namespace lldb_private { -class OptionValueArray : public OptionValue { +class OptionValueArray : public Cloneable { public: OptionValueArray(uint32_t type_mask = UINT32_MAX, bool raw_value_dump = false) : m_type_mask(type_mask), m_values(), m_raw_value_dump(raw_value_dump) {} - ~OptionValueArray() override {} + ~OptionValueArray() override = default; // Virtual subclass pure virtual overrides @@ -32,17 +32,14 @@ public: Status SetValueFromString(llvm::StringRef value, VarSetOperationType op = eVarSetOperationAssign) override; - Status - SetValueFromString(const char *, - VarSetOperationType = eVarSetOperationAssign) = delete; - bool Clear() override { + void Clear() override { m_values.clear(); m_value_was_set = false; - return true; } - lldb::OptionValueSP DeepCopy() const override; + lldb::OptionValueSP + DeepCopy(const lldb::OptionValueSP &new_parent) const override; bool IsAggregateValue() const override { return true; } diff --git a/gnu/llvm/lldb/include/lldb/Interpreter/OptionValueBoolean.h b/gnu/llvm/lldb/include/lldb/Interpreter/OptionValueBoolean.h index d221f6d034c..fd15ccb12c4 100644 --- a/gnu/llvm/lldb/include/lldb/Interpreter/OptionValueBoolean.h +++ b/gnu/llvm/lldb/include/lldb/Interpreter/OptionValueBoolean.h @@ -13,15 +13,14 @@ namespace lldb_private { -class OptionValueBoolean : public OptionValue { +class OptionValueBoolean : public Cloneable { public: OptionValueBoolean(bool value) - : OptionValue(), m_current_value(value), m_default_value(value) {} + : m_current_value(value), m_default_value(value) {} OptionValueBoolean(bool current_value, bool default_value) - : OptionValue(), m_current_value(current_value), - m_default_value(default_value) {} + : m_current_value(current_value), m_default_value(default_value) {} - ~OptionValueBoolean() override {} + ~OptionValueBoolean() override = default; // Virtual subclass pure virtual overrides @@ -33,14 +32,10 @@ public: Status SetValueFromString(llvm::StringRef value, VarSetOperationType op = eVarSetOperationAssign) override; - Status - SetValueFromString(const char *, - VarSetOperationType = eVarSetOperationAssign) = delete; - bool Clear() override { + void Clear() override { m_current_value = m_default_value; m_value_was_set = false; - return true; } void AutoComplete(CommandInterpreter &interpreter, @@ -76,8 +71,6 @@ public: void SetDefaultValue(bool value) { m_default_value = value; } - lldb::OptionValueSP DeepCopy() const override; - protected: bool m_current_value; bool m_default_value; diff --git a/gnu/llvm/lldb/include/lldb/Interpreter/OptionValueChar.h b/gnu/llvm/lldb/include/lldb/Interpreter/OptionValueChar.h index 8d0aa91d707..6b8a314a7c9 100644 --- a/gnu/llvm/lldb/include/lldb/Interpreter/OptionValueChar.h +++ b/gnu/llvm/lldb/include/lldb/Interpreter/OptionValueChar.h @@ -13,16 +13,15 @@ namespace lldb_private { -class OptionValueChar : public OptionValue { +class OptionValueChar : public Cloneable { public: OptionValueChar(char value) - : OptionValue(), m_current_value(value), m_default_value(value) {} + : m_current_value(value), m_default_value(value) {} OptionValueChar(char current_value, char default_value) - : OptionValue(), m_current_value(current_value), - m_default_value(default_value) {} + : m_current_value(current_value), m_default_value(default_value) {} - ~OptionValueChar() override {} + ~OptionValueChar() override = default; // Virtual subclass pure virtual overrides @@ -34,14 +33,10 @@ public: Status SetValueFromString(llvm::StringRef value, VarSetOperationType op = eVarSetOperationAssign) override; - Status - SetValueFromString(const char *, - VarSetOperationType = eVarSetOperationAssign) = delete; - bool Clear() override { + void Clear() override { m_current_value = m_default_value; m_value_was_set = false; - return true; } // Subclass specific functions @@ -59,8 +54,6 @@ public: void SetDefaultValue(char value) { m_default_value = value; } - lldb::OptionValueSP DeepCopy() const override; - protected: char m_current_value; char m_default_value; diff --git a/gnu/llvm/lldb/include/lldb/Interpreter/OptionValueDictionary.h b/gnu/llvm/lldb/include/lldb/Interpreter/OptionValueDictionary.h index 1bc45252607..f96cbc9fe9e 100644 --- a/gnu/llvm/lldb/include/lldb/Interpreter/OptionValueDictionary.h +++ b/gnu/llvm/lldb/include/lldb/Interpreter/OptionValueDictionary.h @@ -15,14 +15,14 @@ namespace lldb_private { -class OptionValueDictionary : public OptionValue { +class OptionValueDictionary + : public Cloneable { public: OptionValueDictionary(uint32_t type_mask = UINT32_MAX, bool raw_value_dump = true) - : OptionValue(), m_type_mask(type_mask), m_values(), - m_raw_value_dump(raw_value_dump) {} + : m_type_mask(type_mask), m_raw_value_dump(raw_value_dump) {} - ~OptionValueDictionary() override {} + ~OptionValueDictionary() override = default; // Virtual subclass pure virtual overrides @@ -35,13 +35,13 @@ public: SetValueFromString(llvm::StringRef value, VarSetOperationType op = eVarSetOperationAssign) override; - bool Clear() override { + void Clear() override { m_values.clear(); m_value_was_set = false; - return true; } - lldb::OptionValueSP DeepCopy() const override; + lldb::OptionValueSP + DeepCopy(const lldb::OptionValueSP &new_parent) const override; bool IsAggregateValue() const override { return true; } diff --git a/gnu/llvm/lldb/include/lldb/Interpreter/OptionValueEnumeration.h b/gnu/llvm/lldb/include/lldb/Interpreter/OptionValueEnumeration.h index 26ba7ad5f64..7dc6eea4e69 100644 --- a/gnu/llvm/lldb/include/lldb/Interpreter/OptionValueEnumeration.h +++ b/gnu/llvm/lldb/include/lldb/Interpreter/OptionValueEnumeration.h @@ -19,7 +19,8 @@ namespace lldb_private { -class OptionValueEnumeration : public OptionValue { +class OptionValueEnumeration + : public Cloneable { public: typedef int64_t enum_type; struct EnumeratorInfo { @@ -31,7 +32,7 @@ public: OptionValueEnumeration(const OptionEnumValues &enumerators, enum_type value); - ~OptionValueEnumeration() override; + ~OptionValueEnumeration() override = default; // Virtual subclass pure virtual overrides @@ -43,18 +44,12 @@ public: Status SetValueFromString(llvm::StringRef value, VarSetOperationType op = eVarSetOperationAssign) override; - Status - SetValueFromString(const char *, - VarSetOperationType = eVarSetOperationAssign) = delete; - bool Clear() override { + void Clear() override { m_current_value = m_default_value; m_value_was_set = false; - return true; } - lldb::OptionValueSP DeepCopy() const override; - void AutoComplete(CommandInterpreter &interpreter, CompletionRequest &request) override; diff --git a/gnu/llvm/lldb/include/lldb/Interpreter/OptionValueFileColonLine.h b/gnu/llvm/lldb/include/lldb/Interpreter/OptionValueFileColonLine.h new file mode 100644 index 00000000000..83d36edc1e9 --- /dev/null +++ b/gnu/llvm/lldb/include/lldb/Interpreter/OptionValueFileColonLine.h @@ -0,0 +1,60 @@ +//===-- OptionValueFileColonLine.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_INTERPRETER_OPTIONVALUEFILECOLONLINE_H +#define LLDB_INTERPRETER_OPTIONVALUEFILECOLONLINE_H + +#include "lldb/Interpreter/CommandCompletions.h" +#include "lldb/Interpreter/OptionValue.h" +#include "lldb/Utility/FileSpec.h" +#include "llvm/Support/Chrono.h" + +namespace lldb_private { + +class OptionValueFileColonLine : + public Cloneable { +public: + OptionValueFileColonLine(); + OptionValueFileColonLine(const llvm::StringRef input); + + ~OptionValueFileColonLine() override = default; + + OptionValue::Type GetType() const override { return eTypeFileLineColumn; } + + void DumpValue(const ExecutionContext *exe_ctx, Stream &strm, + uint32_t dump_mask) override; + + Status + SetValueFromString(llvm::StringRef value, + VarSetOperationType op = eVarSetOperationAssign) override; + + void Clear() override { + m_file_spec.Clear(); + m_line_number = LLDB_INVALID_LINE_NUMBER; + m_column_number = LLDB_INVALID_COLUMN_NUMBER; + } + + void AutoComplete(CommandInterpreter &interpreter, + CompletionRequest &request) override; + + FileSpec &GetFileSpec() { return m_file_spec; } + uint32_t GetLineNumber() { return m_line_number; } + uint32_t GetColumnNumber() { return m_column_number; } + + void SetCompletionMask(uint32_t mask) { m_completion_mask = mask; } + +protected: + FileSpec m_file_spec; + uint32_t m_line_number = LLDB_INVALID_LINE_NUMBER; + uint32_t m_column_number = LLDB_INVALID_COLUMN_NUMBER; + uint32_t m_completion_mask = CommandCompletions::eSourceFileCompletion; +}; + +} // namespace lldb_private + +#endif // LLDB_INTERPRETER_OPTIONVALUEFILECOLONLINE_H diff --git a/gnu/llvm/lldb/include/lldb/Interpreter/OptionValueFileSpec.h b/gnu/llvm/lldb/include/lldb/Interpreter/OptionValueFileSpec.h index 2b18c9533f9..6648bbac93e 100644 --- a/gnu/llvm/lldb/include/lldb/Interpreter/OptionValueFileSpec.h +++ b/gnu/llvm/lldb/include/lldb/Interpreter/OptionValueFileSpec.h @@ -9,6 +9,7 @@ #ifndef LLDB_INTERPRETER_OPTIONVALUEFILESPEC_H #define LLDB_INTERPRETER_OPTIONVALUEFILESPEC_H +#include "lldb/Interpreter/CommandCompletions.h" #include "lldb/Interpreter/OptionValue.h" #include "lldb/Utility/FileSpec.h" @@ -16,7 +17,7 @@ namespace lldb_private { -class OptionValueFileSpec : public OptionValue { +class OptionValueFileSpec : public Cloneable { public: OptionValueFileSpec(bool resolve = true); @@ -25,7 +26,7 @@ public: OptionValueFileSpec(const FileSpec ¤t_value, const FileSpec &default_value, bool resolve = true); - ~OptionValueFileSpec() override {} + ~OptionValueFileSpec() override = default; // Virtual subclass pure virtual overrides @@ -37,20 +38,14 @@ public: Status SetValueFromString(llvm::StringRef value, VarSetOperationType op = eVarSetOperationAssign) override; - Status - SetValueFromString(const char *, - VarSetOperationType = eVarSetOperationAssign) = delete; - bool Clear() override { + void Clear() override { m_current_value = m_default_value; m_value_was_set = false; m_data_sp.reset(); m_data_mod_time = llvm::sys::TimePoint<>(); - return true; } - lldb::OptionValueSP DeepCopy() const override; - void AutoComplete(CommandInterpreter &interpreter, CompletionRequest &request) override; @@ -80,7 +75,7 @@ protected: FileSpec m_default_value; lldb::DataBufferSP m_data_sp; llvm::sys::TimePoint<> m_data_mod_time; - uint32_t m_completion_mask; + uint32_t m_completion_mask = CommandCompletions::eDiskFileCompletion; bool m_resolve; }; diff --git a/gnu/llvm/lldb/include/lldb/Interpreter/OptionValueFileSpecList.h b/gnu/llvm/lldb/include/lldb/Interpreter/OptionValueFileSpecList.h index 7b762bf6b30..29641c3a208 100644 --- a/gnu/llvm/lldb/include/lldb/Interpreter/OptionValueFileSpecList.h +++ b/gnu/llvm/lldb/include/lldb/Interpreter/OptionValueFileSpecList.h @@ -16,14 +16,15 @@ namespace lldb_private { -class OptionValueFileSpecList : public OptionValue { +class OptionValueFileSpecList + : public Cloneable { public: - OptionValueFileSpecList() : OptionValue(), m_current_value() {} + OptionValueFileSpecList() = default; - OptionValueFileSpecList(const FileSpecList ¤t_value) - : OptionValue(), m_current_value(current_value) {} + OptionValueFileSpecList(const OptionValueFileSpecList &other) + : Cloneable(other), m_current_value(other.GetCurrentValue()) {} - ~OptionValueFileSpecList() override {} + ~OptionValueFileSpecList() override = default; // Virtual subclass pure virtual overrides @@ -35,19 +36,13 @@ public: Status SetValueFromString(llvm::StringRef value, VarSetOperationType op = eVarSetOperationAssign) override; - Status - SetValueFromString(const char *, - VarSetOperationType = eVarSetOperationAssign) = delete; - bool Clear() override { + void Clear() override { std::lock_guard lock(m_mutex); m_current_value.Clear(); m_value_was_set = false; - return true; } - lldb::OptionValueSP DeepCopy() const override; - bool IsAggregateValue() const override { return true; } // Subclass specific functions @@ -68,6 +63,8 @@ public: } protected: + lldb::OptionValueSP Clone() const override; + mutable std::recursive_mutex m_mutex; FileSpecList m_current_value; }; diff --git a/gnu/llvm/lldb/include/lldb/Interpreter/OptionValueFormat.h b/gnu/llvm/lldb/include/lldb/Interpreter/OptionValueFormat.h index 6904c93a2f3..1f2c66b164d 100644 --- a/gnu/llvm/lldb/include/lldb/Interpreter/OptionValueFormat.h +++ b/gnu/llvm/lldb/include/lldb/Interpreter/OptionValueFormat.h @@ -13,16 +13,16 @@ namespace lldb_private { -class OptionValueFormat : public OptionValue { +class OptionValueFormat + : public Cloneable { public: OptionValueFormat(lldb::Format value) - : OptionValue(), m_current_value(value), m_default_value(value) {} + : m_current_value(value), m_default_value(value) {} OptionValueFormat(lldb::Format current_value, lldb::Format default_value) - : OptionValue(), m_current_value(current_value), - m_default_value(default_value) {} + : m_current_value(current_value), m_default_value(default_value) {} - ~OptionValueFormat() override {} + ~OptionValueFormat() override = default; // Virtual subclass pure virtual overrides @@ -34,18 +34,12 @@ public: Status SetValueFromString(llvm::StringRef value, VarSetOperationType op = eVarSetOperationAssign) override; - Status - SetValueFromString(const char *, - VarSetOperationType = eVarSetOperationAssign) = delete; - bool Clear() override { + void Clear() override { m_current_value = m_default_value; m_value_was_set = false; - return true; } - lldb::OptionValueSP DeepCopy() const override; - // Subclass specific functions lldb::Format GetCurrentValue() const { return m_current_value; } diff --git a/gnu/llvm/lldb/include/lldb/Interpreter/OptionValueFormatEntity.h b/gnu/llvm/lldb/include/lldb/Interpreter/OptionValueFormatEntity.h index beb5d6843a9..cb8b2ef13fa 100644 --- a/gnu/llvm/lldb/include/lldb/Interpreter/OptionValueFormatEntity.h +++ b/gnu/llvm/lldb/include/lldb/Interpreter/OptionValueFormatEntity.h @@ -14,11 +14,12 @@ namespace lldb_private { -class OptionValueFormatEntity : public OptionValue { +class OptionValueFormatEntity + : public Cloneable { public: OptionValueFormatEntity(const char *default_format); - ~OptionValueFormatEntity() override {} + ~OptionValueFormatEntity() override = default; // Virtual subclass pure virtual overrides @@ -30,13 +31,8 @@ public: Status SetValueFromString(llvm::StringRef value, VarSetOperationType op = eVarSetOperationAssign) override; - Status - SetValueFromString(const char *, - VarSetOperationType = eVarSetOperationAssign) = delete; - - bool Clear() override; - lldb::OptionValueSP DeepCopy() const override; + void Clear() override; void AutoComplete(CommandInterpreter &interpreter, CompletionRequest &request) override; diff --git a/gnu/llvm/lldb/include/lldb/Interpreter/OptionValueLanguage.h b/gnu/llvm/lldb/include/lldb/Interpreter/OptionValueLanguage.h index f4ca2fd69ab..c00f71ffff3 100644 --- a/gnu/llvm/lldb/include/lldb/Interpreter/OptionValueLanguage.h +++ b/gnu/llvm/lldb/include/lldb/Interpreter/OptionValueLanguage.h @@ -15,17 +15,16 @@ namespace lldb_private { -class OptionValueLanguage : public OptionValue { +class OptionValueLanguage : public Cloneable { public: OptionValueLanguage(lldb::LanguageType value) - : OptionValue(), m_current_value(value), m_default_value(value) {} + : m_current_value(value), m_default_value(value) {} OptionValueLanguage(lldb::LanguageType current_value, lldb::LanguageType default_value) - : OptionValue(), m_current_value(current_value), - m_default_value(default_value) {} + : m_current_value(current_value), m_default_value(default_value) {} - ~OptionValueLanguage() override {} + ~OptionValueLanguage() override = default; // Virtual subclass pure virtual overrides @@ -37,18 +36,12 @@ public: Status SetValueFromString(llvm::StringRef value, VarSetOperationType op = eVarSetOperationAssign) override; - Status - SetValueFromString(const char *, - VarSetOperationType = eVarSetOperationAssign) = delete; - bool Clear() override { + void Clear() override { m_current_value = m_default_value; m_value_was_set = false; - return true; } - lldb::OptionValueSP DeepCopy() const override; - // Subclass specific functions lldb::LanguageType GetCurrentValue() const { return m_current_value; } diff --git a/gnu/llvm/lldb/include/lldb/Interpreter/OptionValuePathMappings.h b/gnu/llvm/lldb/include/lldb/Interpreter/OptionValuePathMappings.h index 18f5cbaf433..4bc65ce76c7 100644 --- a/gnu/llvm/lldb/include/lldb/Interpreter/OptionValuePathMappings.h +++ b/gnu/llvm/lldb/include/lldb/Interpreter/OptionValuePathMappings.h @@ -14,12 +14,13 @@ namespace lldb_private { -class OptionValuePathMappings : public OptionValue { +class OptionValuePathMappings + : public Cloneable { public: OptionValuePathMappings(bool notify_changes) - : OptionValue(), m_path_mappings(), m_notify_changes(notify_changes) {} + : m_notify_changes(notify_changes) {} - ~OptionValuePathMappings() override {} + ~OptionValuePathMappings() override = default; // Virtual subclass pure virtual overrides @@ -31,18 +32,12 @@ public: Status SetValueFromString(llvm::StringRef value, VarSetOperationType op = eVarSetOperationAssign) override; - Status - SetValueFromString(const char *, - VarSetOperationType = eVarSetOperationAssign) = delete; - bool Clear() override { + void Clear() override { m_path_mappings.Clear(m_notify_changes); m_value_was_set = false; - return true; } - lldb::OptionValueSP DeepCopy() const override; - bool IsAggregateValue() const override { return true; } // Subclass specific functions diff --git a/gnu/llvm/lldb/include/lldb/Interpreter/OptionValueProperties.h b/gnu/llvm/lldb/include/lldb/Interpreter/OptionValueProperties.h index 76f09cc7712..6fa5403ac14 100644 --- a/gnu/llvm/lldb/include/lldb/Interpreter/OptionValueProperties.h +++ b/gnu/llvm/lldb/include/lldb/Interpreter/OptionValueProperties.h @@ -18,25 +18,27 @@ #include "lldb/Utility/ConstString.h" namespace lldb_private { +class Properties; class OptionValueProperties - : public OptionValue, + : public Cloneable, public std::enable_shared_from_this { public: - OptionValueProperties() - : OptionValue(), m_name(), m_properties(), m_name_to_index() {} + OptionValueProperties() = default; OptionValueProperties(ConstString name); - OptionValueProperties(const OptionValueProperties &global_properties); - ~OptionValueProperties() override = default; Type GetType() const override { return eTypeProperties; } - bool Clear() override; + void Clear() override; + + static lldb::OptionValuePropertiesSP + CreateLocalCopy(const Properties &global_properties); - lldb::OptionValueSP DeepCopy() const override; + lldb::OptionValueSP + DeepCopy(const lldb::OptionValueSP &new_parent) const override; Status SetValueFromString(llvm::StringRef value, @@ -104,11 +106,6 @@ public: Status SetSubValue(const ExecutionContext *exe_ctx, VarSetOperationType op, llvm::StringRef path, llvm::StringRef value) override; - virtual bool PredicateMatches(const ExecutionContext *exe_ctx, - llvm::StringRef predicate) const { - return false; - } - OptionValueArch * GetPropertyAtIndexAsOptionValueArch(const ExecutionContext *exe_ctx, uint32_t idx) const; diff --git a/gnu/llvm/lldb/include/lldb/Interpreter/OptionValueRegex.h b/gnu/llvm/lldb/include/lldb/Interpreter/OptionValueRegex.h index b09b8414d5b..129987484f1 100644 --- a/gnu/llvm/lldb/include/lldb/Interpreter/OptionValueRegex.h +++ b/gnu/llvm/lldb/include/lldb/Interpreter/OptionValueRegex.h @@ -14,11 +14,10 @@ namespace lldb_private { -class OptionValueRegex : public OptionValue { +class OptionValueRegex : public Cloneable { public: OptionValueRegex(const char *value = nullptr) - : OptionValue(), m_regex(llvm::StringRef::withNullAsEmpty(value)), - m_default_regex_str(llvm::StringRef::withNullAsEmpty(value).str()) {} + : m_regex(value), m_default_regex_str(value) {} ~OptionValueRegex() override = default; @@ -32,18 +31,12 @@ public: Status SetValueFromString(llvm::StringRef value, VarSetOperationType op = eVarSetOperationAssign) override; - Status - SetValueFromString(const char *, - VarSetOperationType = eVarSetOperationAssign) = delete; - bool Clear() override { + void Clear() override { m_regex = RegularExpression(m_default_regex_str); m_value_was_set = false; - return true; } - lldb::OptionValueSP DeepCopy() const override; - // Subclass specific functions const RegularExpression *GetCurrentValue() const { return (m_regex.IsValid() ? &m_regex : nullptr); diff --git a/gnu/llvm/lldb/include/lldb/Interpreter/OptionValueSInt64.h b/gnu/llvm/lldb/include/lldb/Interpreter/OptionValueSInt64.h index fbabaaeb2ff..3493eb1037c 100644 --- a/gnu/llvm/lldb/include/lldb/Interpreter/OptionValueSInt64.h +++ b/gnu/llvm/lldb/include/lldb/Interpreter/OptionValueSInt64.h @@ -14,27 +14,19 @@ namespace lldb_private { -class OptionValueSInt64 : public OptionValue { +class OptionValueSInt64 : public Cloneable { public: - OptionValueSInt64() - : OptionValue(), m_current_value(0), m_default_value(0), - m_min_value(INT64_MIN), m_max_value(INT64_MAX) {} + OptionValueSInt64() = default; OptionValueSInt64(int64_t value) - : OptionValue(), m_current_value(value), m_default_value(value), - m_min_value(INT64_MIN), m_max_value(INT64_MAX) {} + : m_current_value(value), m_default_value(value) {} OptionValueSInt64(int64_t current_value, int64_t default_value) - : OptionValue(), m_current_value(current_value), - m_default_value(default_value), m_min_value(INT64_MIN), - m_max_value(INT64_MAX) {} + : m_current_value(current_value), m_default_value(default_value) {} - OptionValueSInt64(const OptionValueSInt64 &rhs) - : OptionValue(rhs), m_current_value(rhs.m_current_value), - m_default_value(rhs.m_default_value), m_min_value(rhs.m_min_value), - m_max_value(rhs.m_max_value) {} + OptionValueSInt64(const OptionValueSInt64 &rhs) = default; - ~OptionValueSInt64() override {} + ~OptionValueSInt64() override = default; // Virtual subclass pure virtual overrides @@ -46,18 +38,12 @@ public: Status SetValueFromString(llvm::StringRef value, VarSetOperationType op = eVarSetOperationAssign) override; - Status - SetValueFromString(const char *, - VarSetOperationType = eVarSetOperationAssign) = delete; - bool Clear() override { + void Clear() override { m_current_value = m_default_value; m_value_was_set = false; - return true; } - lldb::OptionValueSP DeepCopy() const override; - // Subclass specific functions const int64_t &operator=(int64_t value) { @@ -94,10 +80,10 @@ public: int64_t GetMaximumValue() const { return m_max_value; } protected: - int64_t m_current_value; - int64_t m_default_value; - int64_t m_min_value; - int64_t m_max_value; + int64_t m_current_value = 0; + int64_t m_default_value = 0; + int64_t m_min_value = INT64_MIN; + int64_t m_max_value = INT64_MAX; }; } // namespace lldb_private diff --git a/gnu/llvm/lldb/include/lldb/Interpreter/OptionValueString.h b/gnu/llvm/lldb/include/lldb/Interpreter/OptionValueString.h index cd371c56702..be42deb80da 100644 --- a/gnu/llvm/lldb/include/lldb/Interpreter/OptionValueString.h +++ b/gnu/llvm/lldb/include/lldb/Interpreter/OptionValueString.h @@ -17,32 +17,25 @@ namespace lldb_private { -class OptionValueString : public OptionValue { +class OptionValueString : public Cloneable { public: typedef Status (*ValidatorCallback)(const char *string, void *baton); enum Options { eOptionEncodeCharacterEscapeSequences = (1u << 0) }; - OptionValueString() - : OptionValue(), m_current_value(), m_default_value(), m_options(), - m_validator(), m_validator_baton() {} + OptionValueString() = default; OptionValueString(ValidatorCallback validator, void *baton = nullptr) - : OptionValue(), m_current_value(), m_default_value(), m_options(), - m_validator(validator), m_validator_baton(baton) {} + : m_validator(validator), m_validator_baton(baton) {} - OptionValueString(const char *value) - : OptionValue(), m_current_value(), m_default_value(), m_options(), - m_validator(), m_validator_baton() { + OptionValueString(const char *value) { if (value && value[0]) { m_current_value.assign(value); m_default_value.assign(value); } } - OptionValueString(const char *current_value, const char *default_value) - : OptionValue(), m_current_value(), m_default_value(), m_options(), - m_validator(), m_validator_baton() { + OptionValueString(const char *current_value, const char *default_value) { if (current_value && current_value[0]) m_current_value.assign(current_value); if (default_value && default_value[0]) @@ -51,8 +44,7 @@ public: OptionValueString(const char *value, ValidatorCallback validator, void *baton = nullptr) - : OptionValue(), m_current_value(), m_default_value(), m_options(), - m_validator(validator), m_validator_baton(baton) { + : m_validator(validator), m_validator_baton(baton) { if (value && value[0]) { m_current_value.assign(value); m_default_value.assign(value); @@ -61,8 +53,7 @@ public: OptionValueString(const char *current_value, const char *default_value, ValidatorCallback validator, void *baton = nullptr) - : OptionValue(), m_current_value(), m_default_value(), m_options(), - m_validator(validator), m_validator_baton(baton) { + : m_validator(validator), m_validator_baton(baton) { if (current_value && current_value[0]) m_current_value.assign(current_value); if (default_value && default_value[0]) @@ -81,18 +72,12 @@ public: Status SetValueFromString(llvm::StringRef value, VarSetOperationType op = eVarSetOperationAssign) override; - Status - SetValueFromString(const char *, - VarSetOperationType = eVarSetOperationAssign) = delete; - bool Clear() override { + void Clear() override { m_current_value = m_default_value; m_value_was_set = false; - return true; } - lldb::OptionValueSP DeepCopy() const override; - // Subclass specific functions Flags &GetOptions() { return m_options; } @@ -100,7 +85,7 @@ public: const Flags &GetOptions() const { return m_options; } const char *operator=(const char *value) { - SetCurrentValue(llvm::StringRef::withNullAsEmpty(value)); + SetCurrentValue(value); return m_current_value.c_str(); } @@ -110,7 +95,6 @@ public: const char *GetDefaultValue() const { return m_default_value.c_str(); } llvm::StringRef GetDefaultValueAsRef() const { return m_default_value; } - Status SetCurrentValue(const char *) = delete; Status SetCurrentValue(llvm::StringRef value); Status AppendToCurrentValue(const char *value); @@ -130,8 +114,8 @@ protected: std::string m_current_value; std::string m_default_value; Flags m_options; - ValidatorCallback m_validator; - void *m_validator_baton; + ValidatorCallback m_validator = nullptr; + void *m_validator_baton = nullptr; }; } // namespace lldb_private diff --git a/gnu/llvm/lldb/include/lldb/Interpreter/OptionValueUInt64.h b/gnu/llvm/lldb/include/lldb/Interpreter/OptionValueUInt64.h index 0096e87de36..f212b2a19de 100644 --- a/gnu/llvm/lldb/include/lldb/Interpreter/OptionValueUInt64.h +++ b/gnu/llvm/lldb/include/lldb/Interpreter/OptionValueUInt64.h @@ -14,24 +14,22 @@ namespace lldb_private { -class OptionValueUInt64 : public OptionValue { +class OptionValueUInt64 : public Cloneable { public: - OptionValueUInt64() : OptionValue(), m_current_value(0), m_default_value(0) {} + OptionValueUInt64() = default; OptionValueUInt64(uint64_t value) - : OptionValue(), m_current_value(value), m_default_value(value) {} + : m_current_value(value), m_default_value(value) {} OptionValueUInt64(uint64_t current_value, uint64_t default_value) - : OptionValue(), m_current_value(current_value), - m_default_value(default_value) {} + : m_current_value(current_value), m_default_value(default_value) {} - ~OptionValueUInt64() override {} + ~OptionValueUInt64() override = default; // Decode a uint64_t from "value_cstr" return a OptionValueUInt64 object // inside of a lldb::OptionValueSP object if all goes well. If the string // isn't a uint64_t value or any other error occurs, return an empty // lldb::OptionValueSP and fill error in with the correct stuff. - static lldb::OptionValueSP Create(const char *, Status &) = delete; static lldb::OptionValueSP Create(llvm::StringRef value_str, Status &error); // Virtual subclass pure virtual overrides @@ -43,18 +41,12 @@ public: Status SetValueFromString(llvm::StringRef value, VarSetOperationType op = eVarSetOperationAssign) override; - Status - SetValueFromString(const char *, - VarSetOperationType = eVarSetOperationAssign) = delete; - bool Clear() override { + void Clear() override { m_current_value = m_default_value; m_value_was_set = false; - return true; } - lldb::OptionValueSP DeepCopy() const override; - // Subclass specific functions const uint64_t &operator=(uint64_t value) { @@ -73,8 +65,8 @@ public: void SetDefaultValue(uint64_t value) { m_default_value = value; } protected: - uint64_t m_current_value; - uint64_t m_default_value; + uint64_t m_current_value = 0; + uint64_t m_default_value = 0; }; } // namespace lldb_private diff --git a/gnu/llvm/lldb/include/lldb/Interpreter/OptionValueUUID.h b/gnu/llvm/lldb/include/lldb/Interpreter/OptionValueUUID.h index 2fb8caa3aa5..0ed490d1811 100644 --- a/gnu/llvm/lldb/include/lldb/Interpreter/OptionValueUUID.h +++ b/gnu/llvm/lldb/include/lldb/Interpreter/OptionValueUUID.h @@ -14,13 +14,13 @@ namespace lldb_private { -class OptionValueUUID : public OptionValue { +class OptionValueUUID : public Cloneable { public: - OptionValueUUID() : OptionValue(), m_uuid() {} + OptionValueUUID() = default; - OptionValueUUID(const UUID &uuid) : OptionValue(), m_uuid(uuid) {} + OptionValueUUID(const UUID &uuid) : m_uuid(uuid) {} - ~OptionValueUUID() override {} + ~OptionValueUUID() override = default; // Virtual subclass pure virtual overrides @@ -32,18 +32,12 @@ public: Status SetValueFromString(llvm::StringRef value, VarSetOperationType op = eVarSetOperationAssign) override; - Status - SetValueFromString(const char *, - VarSetOperationType = eVarSetOperationAssign) = delete; - bool Clear() override { + void Clear() override { m_uuid.Clear(); m_value_was_set = false; - return true; } - lldb::OptionValueSP DeepCopy() const override; - // Subclass specific functions UUID &GetCurrentValue() { return m_uuid; } diff --git a/gnu/llvm/lldb/include/lldb/Interpreter/OptionValues.h b/gnu/llvm/lldb/include/lldb/Interpreter/OptionValues.h index 36e7c192d60..6efc9e1ad06 100644 --- a/gnu/llvm/lldb/include/lldb/Interpreter/OptionValues.h +++ b/gnu/llvm/lldb/include/lldb/Interpreter/OptionValues.h @@ -17,6 +17,7 @@ #include "lldb/Interpreter/OptionValueChar.h" #include "lldb/Interpreter/OptionValueDictionary.h" #include "lldb/Interpreter/OptionValueEnumeration.h" +#include "lldb/Interpreter/OptionValueFileColonLine.h" #include "lldb/Interpreter/OptionValueFileSpec.h" #include "lldb/Interpreter/OptionValueFileSpecList.h" #include "lldb/Interpreter/OptionValueFormat.h" diff --git a/gnu/llvm/lldb/include/lldb/Interpreter/Options.h b/gnu/llvm/lldb/include/lldb/Interpreter/Options.h index ebceaea8383..6bf5c21fe98 100644 --- a/gnu/llvm/lldb/include/lldb/Interpreter/Options.h +++ b/gnu/llvm/lldb/include/lldb/Interpreter/Options.h @@ -14,6 +14,7 @@ #include "lldb/Utility/Args.h" #include "lldb/Utility/CompletionRequest.h" +#include "lldb/Utility/OptionDefinition.h" #include "lldb/Utility/Status.h" #include "lldb/lldb-defines.h" #include "lldb/lldb-private.h" @@ -40,12 +41,6 @@ struct OptionArgElement { typedef std::vector OptionElementVector; -static inline bool isprint8(int ch) { - if (ch & 0xffffff00u) - return false; - return llvm::isPrint(ch); -} - /// \class Options Options.h "lldb/Interpreter/Options.h" /// A command line option parsing protocol class. /// @@ -259,8 +254,7 @@ public: class OptionGroupOptions : public Options { public: - OptionGroupOptions() - : Options(), m_option_defs(), m_option_infos(), m_did_finalize(false) {} + OptionGroupOptions() = default; ~OptionGroupOptions() override = default; @@ -323,7 +317,7 @@ public: std::vector m_option_defs; OptionInfos m_option_infos; - bool m_did_finalize; + bool m_did_finalize = false; }; } // namespace lldb_private diff --git a/gnu/llvm/lldb/include/lldb/Interpreter/ScriptInterpreter.h b/gnu/llvm/lldb/include/lldb/Interpreter/ScriptInterpreter.h index 491923e6a6c..80a054b32ce 100644 --- a/gnu/llvm/lldb/include/lldb/Interpreter/ScriptInterpreter.h +++ b/gnu/llvm/lldb/include/lldb/Interpreter/ScriptInterpreter.h @@ -9,12 +9,15 @@ #ifndef LLDB_INTERPRETER_SCRIPTINTERPRETER_H #define LLDB_INTERPRETER_SCRIPTINTERPRETER_H +#include "lldb/API/SBData.h" +#include "lldb/API/SBError.h" #include "lldb/Breakpoint/BreakpointOptions.h" #include "lldb/Core/Communication.h" #include "lldb/Core/PluginInterface.h" #include "lldb/Core/SearchFilter.h" #include "lldb/Core/StreamFile.h" #include "lldb/Host/PseudoTerminal.h" +#include "lldb/Interpreter/ScriptedProcessInterface.h" #include "lldb/Utility/Broadcaster.h" #include "lldb/Utility/Status.h" #include "lldb/Utility/StructuredData.h" @@ -34,6 +37,62 @@ private: operator=(const ScriptInterpreterLocker &) = delete; }; +class ExecuteScriptOptions { +public: + ExecuteScriptOptions() = default; + + bool GetEnableIO() const { return m_enable_io; } + + bool GetSetLLDBGlobals() const { return m_set_lldb_globals; } + + // If this is true then any exceptions raised by the script will be + // cleared with PyErr_Clear(). If false then they will be left for + // the caller to clean up + bool GetMaskoutErrors() const { return m_maskout_errors; } + + ExecuteScriptOptions &SetEnableIO(bool enable) { + m_enable_io = enable; + return *this; + } + + ExecuteScriptOptions &SetSetLLDBGlobals(bool set) { + m_set_lldb_globals = set; + return *this; + } + + ExecuteScriptOptions &SetMaskoutErrors(bool maskout) { + m_maskout_errors = maskout; + return *this; + } + +private: + bool m_enable_io = true; + bool m_set_lldb_globals = true; + bool m_maskout_errors = true; +}; + +class LoadScriptOptions { +public: + LoadScriptOptions() = default; + + bool GetInitSession() const { return m_init_session; } + bool GetSilent() const { return m_silent; } + + LoadScriptOptions &SetInitSession(bool b) { + m_init_session = b; + return *this; + } + + LoadScriptOptions &SetSilent(bool b) { + m_silent = b; + return *this; + } + +private: + bool m_init_session = false; + bool m_silent = false; +}; + class ScriptInterpreterIORedirect { public: /// Create an IO redirect. If IO is enabled, this will redirects the output @@ -83,44 +142,12 @@ public: eScriptReturnTypeOpaqueObject }; - ScriptInterpreter(Debugger &debugger, lldb::ScriptLanguage script_lang); - - ~ScriptInterpreter() override; - - struct ExecuteScriptOptions { - public: - ExecuteScriptOptions() - : m_enable_io(true), m_set_lldb_globals(true), m_maskout_errors(true) {} - - bool GetEnableIO() const { return m_enable_io; } - - bool GetSetLLDBGlobals() const { return m_set_lldb_globals; } - - // If this is true then any exceptions raised by the script will be - // cleared with PyErr_Clear(). If false then they will be left for - // the caller to clean up - bool GetMaskoutErrors() const { return m_maskout_errors; } + ScriptInterpreter( + Debugger &debugger, lldb::ScriptLanguage script_lang, + lldb::ScriptedProcessInterfaceUP scripted_process_interface_up = + std::make_unique()); - ExecuteScriptOptions &SetEnableIO(bool enable) { - m_enable_io = enable; - return *this; - } - - ExecuteScriptOptions &SetSetLLDBGlobals(bool set) { - m_set_lldb_globals = set; - return *this; - } - - ExecuteScriptOptions &SetMaskoutErrors(bool maskout) { - m_maskout_errors = maskout; - return *this; - } - - private: - bool m_enable_io; - bool m_set_lldb_globals; - bool m_maskout_errors; - }; + ~ScriptInterpreter() override = default; virtual bool Interrupt() { return false; } @@ -298,6 +325,23 @@ public: return lldb::eSearchDepthModule; } + virtual StructuredData::GenericSP + CreateScriptedStopHook(lldb::TargetSP target_sp, const char *class_name, + StructuredDataImpl *args_data, Status &error) { + error.SetErrorString("Creating scripted stop-hooks with the current " + "script interpreter is not supported."); + return StructuredData::GenericSP(); + } + + // This dispatches to the handle_stop method of the stop-hook class. It + // returns a "should_stop" bool. + virtual bool + ScriptedStopHookHandleStop(StructuredData::GenericSP implementor_sp, + ExecutionContext &exc_ctx, + lldb::StreamSP stream_sp) { + return true; + } + virtual StructuredData::ObjectSP LoadPluginModule(const FileSpec &file_spec, lldb_private::Status &error) { return StructuredData::ObjectSP(); @@ -317,18 +361,19 @@ public: } virtual void CollectDataForBreakpointCommandCallback( - std::vector &options, CommandReturnObject &result); + std::vector> &options, + CommandReturnObject &result); virtual void CollectDataForWatchpointCommandCallback(WatchpointOptions *wp_options, CommandReturnObject &result); /// Set the specified text as the callback for the breakpoint. - Status - SetBreakpointCommandCallback(std::vector &bp_options_vec, - const char *callback_text); + Status SetBreakpointCommandCallback( + std::vector> &bp_options_vec, + const char *callback_text); - virtual Status SetBreakpointCommandCallback(BreakpointOptions *bp_options, + virtual Status SetBreakpointCommandCallback(BreakpointOptions &bp_options, const char *callback_text) { Status error; error.SetErrorString("unimplemented"); @@ -337,7 +382,7 @@ public: /// This one is for deserialization: virtual Status SetBreakpointCommandCallback( - BreakpointOptions *bp_options, + BreakpointOptions &bp_options, std::unique_ptr &data_up) { Status error; error.SetErrorString("unimplemented"); @@ -345,15 +390,14 @@ public: } Status SetBreakpointCommandCallbackFunction( - std::vector &bp_options_vec, + std::vector> &bp_options_vec, const char *function_name, StructuredData::ObjectSP extra_args_sp); /// Set a script function as the callback for the breakpoint. virtual Status - SetBreakpointCommandCallbackFunction( - BreakpointOptions *bp_options, - const char *function_name, - StructuredData::ObjectSP extra_args_sp) { + SetBreakpointCommandCallbackFunction(BreakpointOptions &bp_options, + const char *function_name, + StructuredData::ObjectSP extra_args_sp) { Status error; error.SetErrorString("unimplemented"); return error; @@ -488,9 +532,10 @@ public: virtual bool CheckObjectExists(const char *name) { return false; } virtual bool - LoadScriptingModule(const char *filename, bool init_session, + LoadScriptingModule(const char *filename, const LoadScriptOptions &options, lldb_private::Status &error, - StructuredData::ObjectSP *module_sp = nullptr); + StructuredData::ObjectSP *module_sp = nullptr, + FileSpec extra_search_dir = {}); virtual bool IsReservedWord(const char *word) { return false; } @@ -510,9 +555,19 @@ public: lldb::ScriptLanguage GetLanguage() { return m_script_lang; } + ScriptedProcessInterface &GetScriptedProcessInterface() { + return *m_scripted_process_interface_up; + } + + lldb::DataExtractorSP + GetDataExtractorFromSBData(const lldb::SBData &data) const; + + Status GetStatusFromSBError(const lldb::SBError &error) const; + protected: Debugger &m_debugger; lldb::ScriptLanguage m_script_lang; + lldb::ScriptedProcessInterfaceUP m_scripted_process_interface_up; }; } // namespace lldb_private diff --git a/gnu/llvm/lldb/include/lldb/Interpreter/ScriptedProcessInterface.h b/gnu/llvm/lldb/include/lldb/Interpreter/ScriptedProcessInterface.h new file mode 100644 index 00000000000..223e89be87e --- /dev/null +++ b/gnu/llvm/lldb/include/lldb/Interpreter/ScriptedProcessInterface.h @@ -0,0 +1,68 @@ +//===-- ScriptedProcessInterface.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_INTERPRETER_SCRIPTEDPROCESSINTERFACE_H +#define LLDB_INTERPRETER_SCRIPTEDPROCESSINTERFACE_H + +#include "lldb/Core/StructuredDataImpl.h" +#include "lldb/Interpreter/ScriptInterpreter.h" +#include "lldb/lldb-private.h" + +#include + +namespace lldb_private { +class ScriptedProcessInterface { +public: + ScriptedProcessInterface() : m_object_instance_sp(nullptr) {} + + virtual ~ScriptedProcessInterface() = default; + + virtual StructuredData::GenericSP + CreatePluginObject(const llvm::StringRef class_name, lldb::TargetSP target_sp, + StructuredData::DictionarySP args_sp) { + return nullptr; + } + + virtual Status Launch() { return Status("ScriptedProcess did not launch"); } + + virtual Status Resume() { return Status("ScriptedProcess did not resume"); } + + virtual bool ShouldStop() { return true; } + + virtual Status Stop() { return Status("ScriptedProcess did not stop"); } + + virtual lldb::MemoryRegionInfoSP + GetMemoryRegionContainingAddress(lldb::addr_t address) { + return nullptr; + } + + virtual StructuredData::DictionarySP GetThreadWithID(lldb::tid_t tid) { + return nullptr; + } + + virtual StructuredData::DictionarySP GetRegistersForThread(lldb::tid_t tid) { + return nullptr; + } + + virtual lldb::DataExtractorSP + ReadMemoryAtAddress(lldb::addr_t address, size_t size, Status &error) { + return nullptr; + } + + virtual StructuredData::DictionarySP GetLoadedImages() { return nullptr; } + + virtual lldb::pid_t GetProcessID() { return LLDB_INVALID_PROCESS_ID; } + + virtual bool IsAlive() { return true; } + +private: + StructuredData::ObjectSP m_object_instance_sp; +}; +} // namespace lldb_private + +#endif // LLDB_INTERPRETER_SCRIPTEDPROCESSINTERFACE_H diff --git a/gnu/llvm/lldb/include/lldb/Symbol/CompactUnwindInfo.h b/gnu/llvm/lldb/include/lldb/Symbol/CompactUnwindInfo.h index e622c5fde22..ceb501e1c05 100644 --- a/gnu/llvm/lldb/include/lldb/Symbol/CompactUnwindInfo.h +++ b/gnu/llvm/lldb/include/lldb/Symbol/CompactUnwindInfo.h @@ -50,21 +50,20 @@ private: // There are relatively few of these (one per 500/1000 functions, depending // on format) so creating them on first scan will not be too costly. struct UnwindIndex { - uint32_t function_offset; // The offset of the first function covered by - // this index - uint32_t second_level; // The offset (inside unwind_info sect) to the second - // level page for this index + uint32_t function_offset = 0; // The offset of the first function covered by + // this index + uint32_t second_level = 0; // The offset (inside unwind_info sect) to the + // second level page for this index // (either UNWIND_SECOND_LEVEL_REGULAR or UNWIND_SECOND_LEVEL_COMPRESSED) - uint32_t lsda_array_start; // The offset (inside unwind_info sect) LSDA - // array for this index - uint32_t lsda_array_end; // The offset to the LSDA array for the NEXT index - bool sentinal_entry; // There is an empty index at the end which provides - // the upper bound of + uint32_t lsda_array_start = 0; // The offset (inside unwind_info sect) LSDA + // array for this index + uint32_t lsda_array_end = + 0; // The offset to the LSDA array for the NEXT index + bool sentinal_entry = false; // There is an empty index at the end which + // provides the upper bound of // function addresses that are described - UnwindIndex() - : function_offset(0), second_level(0), lsda_array_start(0), - lsda_array_end(0), sentinal_entry(false) {} + UnwindIndex() = default; bool operator<(const CompactUnwindInfo::UnwindIndex &rhs) const { return function_offset < rhs.function_offset; @@ -78,30 +77,26 @@ private: // An internal object used to store the information we retrieve about a // function -- the encoding bits and possibly the LSDA/personality function. struct FunctionInfo { - uint32_t encoding; // compact encoding 32-bit value for this function + uint32_t encoding = 0; // compact encoding 32-bit value for this function Address lsda_address; // the address of the LSDA data for this function Address personality_ptr_address; // the address where the personality // routine addr can be found - uint32_t valid_range_offset_start; // first offset that this encoding is - // valid for (start of the function) - uint32_t - valid_range_offset_end; // the offset of the start of the next function - FunctionInfo() - : encoding(0), lsda_address(), personality_ptr_address(), - valid_range_offset_start(0), valid_range_offset_end(0) {} + uint32_t valid_range_offset_start = 0; // first offset that this encoding is + // valid for (start of the function) + uint32_t valid_range_offset_end = + 0; // the offset of the start of the next function + FunctionInfo() : lsda_address(), personality_ptr_address() {} }; struct UnwindHeader { uint32_t version; - uint32_t common_encodings_array_offset; - uint32_t common_encodings_array_count; - uint32_t personality_array_offset; - uint32_t personality_array_count; - - UnwindHeader() - : common_encodings_array_offset(0), common_encodings_array_count(0), - personality_array_offset(0), personality_array_count(0) {} + uint32_t common_encodings_array_offset = 0; + uint32_t common_encodings_array_count = 0; + uint32_t personality_array_offset = 0; + uint32_t personality_array_count = 0; + + UnwindHeader() = default; }; void ScanIndex(const lldb::ProcessSP &process_sp); diff --git a/gnu/llvm/lldb/include/lldb/Symbol/CompileUnit.h b/gnu/llvm/lldb/include/lldb/Symbol/CompileUnit.h index 256148f20d1..2e52bca7097 100644 --- a/gnu/llvm/lldb/include/lldb/Symbol/CompileUnit.h +++ b/gnu/llvm/lldb/include/lldb/Symbol/CompileUnit.h @@ -11,6 +11,7 @@ #include "lldb/Core/FileSpecList.h" #include "lldb/Core/ModuleChild.h" +#include "lldb/Core/SourceLocationSpec.h" #include "lldb/Symbol/DebugMacros.h" #include "lldb/Symbol/Function.h" #include "lldb/Symbol/LineTable.h" @@ -345,29 +346,22 @@ public: /// Resolve symbol contexts by file and line. /// - /// Given a file in \a file_spec, and a line number, find all instances and + /// Given a file in \a src_location_spec, find all instances and /// append them to the supplied symbol context list \a sc_list. /// - /// \param[in] file_spec - /// A file specification. If \a file_spec contains no directory - /// information, only the basename will be used when matching - /// contexts. If the directory in \a file_spec is valid, a - /// complete file specification match will be performed. - /// - /// \param[in] line - /// The line number to match against the compile unit's line - /// tables. + /// \param[in] src_location_spec + /// The \a src_location_spec containing the \a file_spec, the line and the + /// column of the symbol to look for. Also hold the inlines and + /// exact_match flags. /// - /// \param[in] check_inlines - /// If \b true this function will also match any inline + /// If check_inlines is \b true, this function will also match any inline /// file and line matches. If \b false, the compile unit's /// file specification must match \a file_spec for any matches /// to be returned. /// - /// \param[in] exact - /// If true, only resolve the context if \a line exists in the line table. - /// If false, resolve the context to the closest line greater than \a line - /// in the line table. + /// If exact_match is \b true, only resolve the context if \a line and \a + /// column exists in the line table. If \b false, resolve the context to + /// the closest line greater than \a line in the line table. /// /// \param[in] resolve_scope /// For each matching line entry, this bitfield indicates what @@ -382,8 +376,7 @@ public: /// entries appended to. /// /// \see enum SymbolContext::Scope - void ResolveSymbolContext(const FileSpec &file_spec, uint32_t line, - bool check_inlines, bool exact, + void ResolveSymbolContext(const SourceLocationSpec &src_location_spec, lldb::SymbolContextItem resolve_scope, SymbolContextList &sc_list); diff --git a/gnu/llvm/lldb/include/lldb/Symbol/CompilerType.h b/gnu/llvm/lldb/include/lldb/Symbol/CompilerType.h index 280966a327e..0ad05a27570 100644 --- a/gnu/llvm/lldb/include/lldb/Symbol/CompilerType.h +++ b/gnu/llvm/lldb/include/lldb/Symbol/CompilerType.h @@ -20,7 +20,7 @@ namespace lldb_private { class DataExtractor; -/// Represents a generic type in a programming language. +/// Generic representation of a type in a programming language. /// /// This class serves as an abstraction for a type inside one of the TypeSystems /// implemented by the language plugins. It does not have any actual logic in it @@ -71,10 +71,12 @@ public: bool IsValid() const { return m_type != nullptr && m_type_system != nullptr; } - bool IsArrayType(CompilerType *element_type, uint64_t *size, - bool *is_incomplete) const; + bool IsArrayType(CompilerType *element_type = nullptr, + uint64_t *size = nullptr, + bool *is_incomplete = nullptr) const; - bool IsVectorType(CompilerType *element_type, uint64_t *size) const; + bool IsVectorType(CompilerType *element_type = nullptr, + uint64_t *size = nullptr) const; bool IsArrayOfScalarType() const; @@ -82,6 +84,8 @@ public: bool IsAnonymousType() const; + bool IsScopedEnumerationType() const; + bool IsBeingDefined() const; bool IsCharType() const; @@ -96,7 +100,7 @@ public: bool IsFloatingPointType(uint32_t &count, bool &is_complex) const; - bool IsFunctionType(bool *is_variadic_ptr = nullptr) const; + bool IsFunctionType() const; uint32_t IsHomogeneousAggregate(CompilerType *base_type_ptr) const; @@ -108,7 +112,8 @@ public: bool IsFunctionPointerType() const; - bool IsBlockPointerType(CompilerType *function_pointer_type_ptr) const; + bool + IsBlockPointerType(CompilerType *function_pointer_type_ptr = nullptr) const; bool IsIntegerType(bool &is_signed) const; @@ -177,7 +182,7 @@ public: /// Creating related types. /// \{ - CompilerType GetArrayElementType(uint64_t *stride = nullptr) const; + CompilerType GetArrayElementType(ExecutionContextScope *exe_scope) const; CompilerType GetArrayType(uint64_t size) const; @@ -185,6 +190,8 @@ public: CompilerType GetFullyUnqualifiedType() const; + CompilerType GetEnumerationIntegerType() const; + /// Returns -1 if this isn't a function of if the function doesn't /// have a prototype Returns a value >= 0 if there is a prototype. int GetFunctionArgumentCount() const; @@ -383,7 +390,8 @@ public: /// \} bool GetValueAsScalar(const DataExtractor &data, lldb::offset_t data_offset, - size_t data_byte_size, Scalar &value) const; + size_t data_byte_size, Scalar &value, + ExecutionContextScope *exe_scope) const; void Clear() { m_type = nullptr; m_type_system = nullptr; diff --git a/gnu/llvm/lldb/include/lldb/Symbol/DeclVendor.h b/gnu/llvm/lldb/include/lldb/Symbol/DeclVendor.h index 67dcaf1734b..19ab2bb66e2 100644 --- a/gnu/llvm/lldb/include/lldb/Symbol/DeclVendor.h +++ b/gnu/llvm/lldb/include/lldb/Symbol/DeclVendor.h @@ -28,7 +28,7 @@ public: // Constructors and Destructors DeclVendor(DeclVendorKind kind) : m_kind(kind) {} - virtual ~DeclVendor() {} + virtual ~DeclVendor() = default; DeclVendorKind GetKind() const { return m_kind; } diff --git a/gnu/llvm/lldb/include/lldb/Symbol/Function.h b/gnu/llvm/lldb/include/lldb/Symbol/Function.h index 300d829219d..b703617773f 100644 --- a/gnu/llvm/lldb/include/lldb/Symbol/Function.h +++ b/gnu/llvm/lldb/include/lldb/Symbol/Function.h @@ -10,10 +10,10 @@ #define LLDB_SYMBOL_FUNCTION_H #include "lldb/Core/AddressRange.h" +#include "lldb/Core/Declaration.h" #include "lldb/Core/Mangled.h" #include "lldb/Expression/DWARFExpression.h" #include "lldb/Symbol/Block.h" -#include "lldb/Symbol/Declaration.h" #include "lldb/Utility/UserID.h" #include "llvm/ADT/ArrayRef.h" @@ -271,7 +271,7 @@ using CallSiteParameterArray = llvm::SmallVector; class CallEdge { public: enum class AddrType : uint8_t { Call, AfterCall }; - virtual ~CallEdge() {} + virtual ~CallEdge() = default; /// Get the callee's definition. /// @@ -631,10 +631,10 @@ public: lldb::DisassemblerSP GetInstructions(const ExecutionContext &exe_ctx, const char *flavor, - bool prefer_file_cache); + bool force_live_memory = false); bool GetDisassembly(const ExecutionContext &exe_ctx, const char *flavor, - bool prefer_file_cache, Stream &strm); + Stream &strm, bool force_live_memory = false); protected: enum { diff --git a/gnu/llvm/lldb/include/lldb/Symbol/LineEntry.h b/gnu/llvm/lldb/include/lldb/Symbol/LineEntry.h index 7e56ef81476..698d89974dc 100644 --- a/gnu/llvm/lldb/include/lldb/Symbol/LineEntry.h +++ b/gnu/llvm/lldb/include/lldb/Symbol/LineEntry.h @@ -140,10 +140,12 @@ struct LineEntry { FileSpec file; ///< The source file, possibly mapped by the target.source-map ///setting FileSpec original_file; ///< The original source file, from debug info. - uint32_t line; ///< The source line number, or zero if there is no line number - ///information. - uint16_t column; ///< The column number of the source line, or zero if there - ///is no column information. + uint32_t line = LLDB_INVALID_LINE_NUMBER; ///< The source line number, or zero + ///< if there is no line number + /// information. + uint16_t column = + 0; ///< The column number of the source line, or zero if there + /// is no column information. uint16_t is_start_of_statement : 1, ///< Indicates this entry is the beginning ///of a statement. is_start_of_basic_block : 1, ///< Indicates this entry is the beginning of diff --git a/gnu/llvm/lldb/include/lldb/Symbol/LineTable.h b/gnu/llvm/lldb/include/lldb/Symbol/LineTable.h index d66b58ca4c6..5cd22bd831e 100644 --- a/gnu/llvm/lldb/include/lldb/Symbol/LineTable.h +++ b/gnu/llvm/lldb/include/lldb/Symbol/LineTable.h @@ -9,8 +9,10 @@ #ifndef LLDB_SYMBOL_LINETABLE_H #define LLDB_SYMBOL_LINETABLE_H +#include "lldb/Core/Address.h" #include "lldb/Core/ModuleChild.h" #include "lldb/Core/Section.h" +#include "lldb/Core/SourceLocationSpec.h" #include "lldb/Symbol/LineEntry.h" #include "lldb/Utility/RangeMap.h" #include "lldb/lldb-private.h" @@ -136,12 +138,8 @@ public: /// CompileUnit::GetSupportFiles() /// FileSpecList::FindFileIndex (uint32_t, const FileSpec &) const /// - /// \param[in] line - /// The source line to match. - /// - /// \param[in] exact - /// If true, match only if you find a line entry exactly matching \a line. - /// If false, return the closest line entry greater than \a line. + /// \param[in] src_location_spec + /// The source location specifier to match. /// /// \param[out] line_entry_ptr /// A pointer to a line entry object that will get a copy of @@ -154,13 +152,14 @@ public: /// /// \see CompileUnit::GetSupportFiles() /// \see FileSpecList::FindFileIndex (uint32_t, const FileSpec &) const - uint32_t FindLineEntryIndexByFileIndex(uint32_t start_idx, uint32_t file_idx, - uint32_t line, bool exact, - LineEntry *line_entry_ptr); + uint32_t + FindLineEntryIndexByFileIndex(uint32_t start_idx, uint32_t file_idx, + const SourceLocationSpec &src_location_spec, + LineEntry *line_entry_ptr); uint32_t FindLineEntryIndexByFileIndex( - uint32_t start_idx, const std::vector &file_indexes, - uint32_t line, bool exact, LineEntry *line_entry_ptr); + uint32_t start_idx, const std::vector &file_idx, + const SourceLocationSpec &src_location_spec, LineEntry *line_entry_ptr); size_t FineLineEntriesForFileIndex(uint32_t file_idx, bool append, SymbolContextList &sc_list); @@ -210,10 +209,9 @@ public: protected: struct Entry { Entry() - : file_addr(LLDB_INVALID_ADDRESS), line(0), - is_start_of_statement(false), is_start_of_basic_block(false), + : line(0), is_start_of_statement(false), is_start_of_basic_block(false), is_prologue_end(false), is_epilogue_begin(false), - is_terminal_entry(false), column(0), file_idx(0) {} + is_terminal_entry(false) {} Entry(lldb::addr_t _file_addr, uint32_t _line, uint16_t _column, uint16_t _file_idx, bool _is_start_of_statement, @@ -280,7 +278,7 @@ protected: // Member variables. /// The file address for this line entry. - lldb::addr_t file_addr; + lldb::addr_t file_addr = LLDB_INVALID_ADDRESS; /// The source line number, or zero if there is no line number /// information. uint32_t line : 27; @@ -299,10 +297,10 @@ protected: uint32_t is_terminal_entry : 1; /// The column number of the source line, or zero if there is no /// column information. - uint16_t column; + uint16_t column = 0; /// The file index into CompileUnit's file table, or zero if there /// is no file information. - uint16_t file_idx; + uint16_t file_idx = 0; }; struct EntrySearchInfo { @@ -340,6 +338,75 @@ protected: private: LineTable(const LineTable &) = delete; const LineTable &operator=(const LineTable &) = delete; + + template + uint32_t FindLineEntryIndexByFileIndexImpl( + uint32_t start_idx, T file_idx, + const SourceLocationSpec &src_location_spec, LineEntry *line_entry_ptr, + std::function file_idx_matcher) { + const size_t count = m_entries.size(); + size_t best_match = UINT32_MAX; + + if (!line_entry_ptr) + return best_match; + + const uint32_t line = src_location_spec.GetLine().getValueOr(0); + const uint16_t column = + src_location_spec.GetColumn().getValueOr(LLDB_INVALID_COLUMN_NUMBER); + const bool exact_match = src_location_spec.GetExactMatch(); + + for (size_t idx = start_idx; idx < count; ++idx) { + // Skip line table rows that terminate the previous row (is_terminal_entry + // is non-zero) + if (m_entries[idx].is_terminal_entry) + continue; + + if (!file_idx_matcher(file_idx, m_entries[idx].file_idx)) + continue; + + // Exact match always wins. Otherwise try to find the closest line > the + // desired line. + // FIXME: Maybe want to find the line closest before and the line closest + // after and if they're not in the same function, don't return a match. + + if (column == LLDB_INVALID_COLUMN_NUMBER) { + if (m_entries[idx].line < line) { + continue; + } else if (m_entries[idx].line == line) { + ConvertEntryAtIndexToLineEntry(idx, *line_entry_ptr); + return idx; + } else if (!exact_match) { + if (best_match == UINT32_MAX || + m_entries[idx].line < m_entries[best_match].line) + best_match = idx; + } + } else { + if (m_entries[idx].line < line) { + continue; + } else if (m_entries[idx].line == line && + m_entries[idx].column == column) { + ConvertEntryAtIndexToLineEntry(idx, *line_entry_ptr); + return idx; + } else if (!exact_match) { + if (best_match == UINT32_MAX) + best_match = idx; + else if (m_entries[idx].line < m_entries[best_match].line) + best_match = idx; + else if (m_entries[idx].line == m_entries[best_match].line) + if (m_entries[idx].column && + m_entries[idx].column < m_entries[best_match].column) + best_match = idx; + } + } + } + + if (best_match != UINT32_MAX) { + if (line_entry_ptr) + ConvertEntryAtIndexToLineEntry(best_match, *line_entry_ptr); + return best_match; + } + return UINT32_MAX; + } }; } // namespace lldb_private diff --git a/gnu/llvm/lldb/include/lldb/Symbol/LocateSymbolFile.h b/gnu/llvm/lldb/include/lldb/Symbol/LocateSymbolFile.h index 93b76e53f41..2c3f6a7b7b5 100644 --- a/gnu/llvm/lldb/include/lldb/Symbol/LocateSymbolFile.h +++ b/gnu/llvm/lldb/include/lldb/Symbol/LocateSymbolFile.h @@ -9,7 +9,7 @@ #ifndef LLDB_SYMBOL_LOCATESYMBOLFILE_H #define LLDB_SYMBOL_LOCATESYMBOLFILE_H -#include +#include #include "lldb/Core/FileSpecList.h" #include "lldb/Utility/FileSpec.h" diff --git a/gnu/llvm/lldb/include/lldb/Symbol/ObjectFile.h b/gnu/llvm/lldb/include/lldb/Symbol/ObjectFile.h index e814015c0bf..4ccd7f92064 100644 --- a/gnu/llvm/lldb/include/lldb/Symbol/ObjectFile.h +++ b/gnu/llvm/lldb/include/lldb/Symbol/ObjectFile.h @@ -25,9 +25,9 @@ namespace lldb_private { class ObjectFileJITDelegate { public: - ObjectFileJITDelegate() {} + ObjectFileJITDelegate() = default; - virtual ~ObjectFileJITDelegate() {} + virtual ~ObjectFileJITDelegate() = default; virtual lldb::ByteOrder GetByteOrder() const = 0; @@ -91,6 +91,17 @@ public: eStrataJIT }; + /// If we have a corefile binary hint, this enum + /// specifies the binary type which we can use to + /// select the correct DynamicLoader plugin. + enum BinaryType { + eBinaryTypeInvalid = 0, + eBinaryTypeUnknown, + eBinaryTypeKernel, /// kernel binary + eBinaryTypeUser, /// user process binary + eBinaryTypeStandalone /// standalone binary / firmware + }; + struct LoadableData { lldb::addr_t Dest; llvm::ArrayRef Contents; @@ -484,6 +495,16 @@ public: return std::string(); } + /// Some object files may have the number of bits used for addressing + /// embedded in them, e.g. a Mach-O core file using an LC_NOTE. These + /// object files can return the address mask that should be used in + /// the Process. + /// \return + /// The mask will have bits set which aren't used for addressing -- + /// typically, the high bits. + /// Zero is returned when no address bits mask is available. + virtual lldb::addr_t GetAddressMask() { return 0; } + /// When the ObjectFile is a core file, lldb needs to locate the "binary" in /// the core file. lldb can iterate over the pages looking for a valid /// binary, but some core files may have metadata describing where the main @@ -500,12 +521,17 @@ public: /// If the uuid of the binary is specified, this will be set. /// If no UUID is available, will be cleared. /// + /// \param[out] type + /// Return the type of the binary, which will dictate which + /// DynamicLoader plugin should be used. + /// /// \return /// Returns true if either address or uuid has been set. - virtual bool GetCorefileMainBinaryInfo (lldb::addr_t &address, UUID &uuid) { - address = LLDB_INVALID_ADDRESS; - uuid.Clear(); - return false; + virtual bool GetCorefileMainBinaryInfo(lldb::addr_t &address, UUID &uuid, + ObjectFile::BinaryType &type) { + address = LLDB_INVALID_ADDRESS; + uuid.Clear(); + return false; } virtual lldb::RegisterContextSP @@ -650,6 +676,22 @@ public: /// Creates a plugin-specific call frame info virtual std::unique_ptr CreateCallFrameInfo(); + /// Load binaries listed in a corefile + /// + /// A corefile may have metadata listing binaries that can be loaded, + /// and the offsets at which they were loaded. This method will try + /// to add them to the Target. If any binaries were loaded, + /// + /// \param[in] process + /// Process where to load binaries. + /// + /// \return + /// Returns true if any binaries were loaded. + + virtual bool LoadCoreFileImages(lldb_private::Process &process) { + return false; + } + protected: // Member variables. FileSpec m_file; @@ -680,8 +722,6 @@ protected: /// false otherwise. bool SetModulesArchitecture(const ArchSpec &new_arch); - ConstString GetNextSyntheticSymbolName(); - static lldb::DataBufferSP MapFileData(const FileSpec &file, uint64_t Size, uint64_t Offset); diff --git a/gnu/llvm/lldb/include/lldb/Symbol/Symbol.h b/gnu/llvm/lldb/include/lldb/Symbol/Symbol.h index 3a235f260ba..cb238546870 100644 --- a/gnu/llvm/lldb/include/lldb/Symbol/Symbol.h +++ b/gnu/llvm/lldb/include/lldb/Symbol/Symbol.h @@ -113,14 +113,20 @@ public: lldb::LanguageType GetLanguage() const { // TODO: See if there is a way to determine the language for a symbol // somehow, for now just return our best guess - return m_mangled.GuessLanguage(); + return GetMangled().GuessLanguage(); } void SetID(uint32_t uid) { m_uid = uid; } - Mangled &GetMangled() { return m_mangled; } + Mangled &GetMangled() { + SynthesizeNameIfNeeded(); + return m_mangled; + } - const Mangled &GetMangled() const { return m_mangled; } + const Mangled &GetMangled() const { + SynthesizeNameIfNeeded(); + return m_mangled; + } ConstString GetReExportedSymbolName() const; @@ -149,6 +155,8 @@ public: bool IsSynthetic() const { return m_is_synthetic; } + bool IsSyntheticWithAutoGeneratedName() const; + void SetIsSynthetic(bool b) { m_is_synthetic = b; } bool GetSizeIsSynthesized() const { return m_size_is_synthesized; } @@ -166,9 +174,9 @@ public: bool IsTrampoline() const; bool IsIndirect() const; - + bool IsWeak() const { return m_is_weak; } - + void SetIsWeak (bool b) { m_is_weak = b; } bool GetByteSizeIsValid() const { return m_size_is_valid; } @@ -223,6 +231,10 @@ public: bool ContainsFileAddress(lldb::addr_t file_addr) const; + static llvm::StringRef GetSyntheticSymbolPrefix() { + return "___lldb_unnamed_symbol"; + } + protected: // This is the internal guts of ResolveReExportedSymbol, it assumes // reexport_name is not null, and that module_spec is valid. We track the @@ -233,8 +245,11 @@ protected: lldb_private::ModuleSpec &module_spec, lldb_private::ModuleList &seen_modules) const; - uint32_t m_uid; // User ID (usually the original symbol table index) - uint16_t m_type_data; // data specific to m_type + void SynthesizeNameIfNeeded() const; + + uint32_t m_uid = + UINT32_MAX; // User ID (usually the original symbol table index) + uint16_t m_type_data = 0; // data specific to m_type uint16_t m_type_data_resolved : 1, // True if the data in m_type_data has // already been calculated m_is_synthetic : 1, // non-zero if this symbol is not actually in the @@ -257,12 +272,12 @@ protected: // doing name lookups m_is_weak : 1, m_type : 6; // Values from the lldb::SymbolType enum. - Mangled m_mangled; // uniqued symbol name/mangled name pair + mutable Mangled m_mangled; // uniqued symbol name/mangled name pair AddressRange m_addr_range; // Contains the value, or the section offset // address when the value is an address in a // section, and the size (if any) - uint32_t m_flags; // A copy of the flags from the original symbol table, the - // ObjectFile plug-in can interpret these + uint32_t m_flags = 0; // A copy of the flags from the original symbol table, + // the ObjectFile plug-in can interpret these }; } // namespace lldb_private diff --git a/gnu/llvm/lldb/include/lldb/Symbol/SymbolContext.h b/gnu/llvm/lldb/include/lldb/Symbol/SymbolContext.h index cc49ce51c71..cac951bc19b 100644 --- a/gnu/llvm/lldb/include/lldb/Symbol/SymbolContext.h +++ b/gnu/llvm/lldb/include/lldb/Symbol/SymbolContext.h @@ -139,6 +139,14 @@ public: /// be printed. In disassembly formatting, where we want a format /// like "<*+36>", this should be false and "*" will be printed /// instead. + /// + /// \param[in] show_inline_callsite_line_info + /// When processing an inline block, the line info of the callsite + /// is dumped if this flag is \b true, otherwise the line info + /// of the actual inlined function is dumped. + /// + /// \return + /// \b true if some text was dumped, \b false otherwise. bool DumpStopContext(Stream *s, ExecutionContextScope *exe_scope, const Address &so_addr, bool show_fullpaths, bool show_module, bool show_inlined_frames, @@ -308,12 +316,13 @@ public: // Member variables lldb::TargetSP target_sp; ///< The Target for a given query lldb::ModuleSP module_sp; ///< The Module for a given query - CompileUnit *comp_unit; ///< The CompileUnit for a given query - Function *function; ///< The Function for a given query - Block *block; ///< The Block for a given query + CompileUnit *comp_unit = nullptr; ///< The CompileUnit for a given query + Function *function = nullptr; ///< The Function for a given query + Block *block = nullptr; ///< The Block for a given query LineEntry line_entry; ///< The LineEntry for a given query - Symbol *symbol; ///< The Symbol for a given query - Variable *variable; ///< The global variable matching the given query + Symbol *symbol = nullptr; ///< The Symbol for a given query + Variable *variable = + nullptr; ///< The global variable matching the given query }; class SymbolContextSpecifier { @@ -340,7 +349,7 @@ public: void Clear(); - bool SymbolContextMatches(SymbolContext &sc); + bool SymbolContextMatches(const SymbolContext &sc); bool AddressMatches(lldb::addr_t addr); diff --git a/gnu/llvm/lldb/include/lldb/Symbol/SymbolFile.h b/gnu/llvm/lldb/include/lldb/Symbol/SymbolFile.h index 9f5806915dc..ffdbdc6853f 100644 --- a/gnu/llvm/lldb/include/lldb/Symbol/SymbolFile.h +++ b/gnu/llvm/lldb/include/lldb/Symbol/SymbolFile.h @@ -10,6 +10,7 @@ #define LLDB_SYMBOL_SYMBOLFILE_H #include "lldb/Core/PluginInterface.h" +#include "lldb/Core/SourceLocationSpec.h" #include "lldb/Symbol/CompilerDecl.h" #include "lldb/Symbol/CompilerDeclContext.h" #include "lldb/Symbol/CompilerType.h" @@ -68,7 +69,7 @@ public: : m_objfile_sp(std::move(objfile_sp)), m_abilities(0), m_calculated_abilities(false) {} - ~SymbolFile() override {} + ~SymbolFile() override = default; /// Get a mask of what this symbol file supports for the object file /// that it was constructed with. @@ -209,10 +210,10 @@ public: virtual uint32_t ResolveSymbolContext(const Address &so_addr, lldb::SymbolContextItem resolve_scope, SymbolContext &sc) = 0; - virtual uint32_t ResolveSymbolContext(const FileSpec &file_spec, - uint32_t line, bool check_inlines, - lldb::SymbolContextItem resolve_scope, - SymbolContextList &sc_list); + virtual uint32_t + ResolveSymbolContext(const SourceLocationSpec &src_location_spec, + lldb::SymbolContextItem resolve_scope, + SymbolContextList &sc_list); virtual void DumpClangAST(Stream &s) {} virtual void FindGlobalVariables(ConstString name, diff --git a/gnu/llvm/lldb/include/lldb/Symbol/SymbolVendor.h b/gnu/llvm/lldb/include/lldb/Symbol/SymbolVendor.h index c9c59a3fc1b..5c785e8c5a8 100644 --- a/gnu/llvm/lldb/include/lldb/Symbol/SymbolVendor.h +++ b/gnu/llvm/lldb/include/lldb/Symbol/SymbolVendor.h @@ -14,6 +14,7 @@ #include "lldb/Core/ModuleChild.h" #include "lldb/Core/PluginInterface.h" #include "lldb/Symbol/SourceModule.h" +#include "lldb/Symbol/SymbolFile.h" #include "lldb/Symbol/TypeMap.h" #include "lldb/lldb-private.h" #include "llvm/ADT/DenseSet.h" @@ -35,8 +36,6 @@ public: // Constructors and Destructors SymbolVendor(const lldb::ModuleSP &module_sp); - ~SymbolVendor() override; - void AddSymbolFileRepresentation(const lldb::ObjectFileSP &objfile_sp); SymbolFile *GetSymbolFile() { return m_sym_file_up.get(); } @@ -49,11 +48,6 @@ public: protected: std::unique_ptr m_sym_file_up; // A single symbol file. Subclasses // can add more of these if needed. - -private: - // For SymbolVendor only - SymbolVendor(const SymbolVendor &) = delete; - const SymbolVendor &operator=(const SymbolVendor &) = delete; }; } // namespace lldb_private diff --git a/gnu/llvm/lldb/include/lldb/Symbol/Symtab.h b/gnu/llvm/lldb/include/lldb/Symbol/Symtab.h index c232925eec7..e1ad0dfd2eb 100644 --- a/gnu/llvm/lldb/include/lldb/Symbol/Symtab.h +++ b/gnu/llvm/lldb/include/lldb/Symbol/Symtab.h @@ -13,6 +13,7 @@ #include "lldb/Symbol/Symbol.h" #include "lldb/Utility/RangeMap.h" #include "lldb/lldb-private.h" +#include #include #include @@ -173,15 +174,21 @@ protected: ObjectFile *m_objfile; collection m_symbols; FileRangeToIndexMap m_file_addr_to_index; - UniqueCStringMap m_name_to_index; - UniqueCStringMap m_basename_to_index; - UniqueCStringMap m_method_to_index; - UniqueCStringMap m_selector_to_index; + + /// Maps function names to symbol indices (grouped by FunctionNameTypes) + std::map> + m_name_to_symbol_indices; mutable std::recursive_mutex m_mutex; // Provide thread safety for this symbol table bool m_file_addr_to_index_computed : 1, m_name_indexes_computed : 1; private: + UniqueCStringMap & + GetNameToSymbolIndexMap(lldb::FunctionNameType type) { + auto map = m_name_to_symbol_indices.find(type); + assert(map != m_name_to_symbol_indices.end()); + return map->second; + } bool CheckSymbolAtIndex(size_t idx, Debug symbol_debug_type, Visibility symbol_visibility) const { switch (symbol_debug_type) { @@ -212,6 +219,26 @@ private: return false; } + /// A helper function that looks up full function names. + /// + /// We generate unique names for synthetic symbols so that users can look + /// them up by name when needed. But because doing so is uncommon in normal + /// debugger use, we trade off some performance at lookup time for faster + /// symbol table building by detecting these symbols and generating their + /// names lazily, rather than adding them to the normal symbol indexes. This + /// function does the job of first consulting the name indexes, and if that + /// fails it extracts the information it needs from the synthetic name and + /// locates the symbol. + /// + /// @param[in] symbol_name The symbol name to search for. + /// + /// @param[out] indexes The vector if symbol indexes to update with results. + /// + /// @returns The number of indexes added to the index vector. Zero if no + /// matches were found. + uint32_t GetNameIndexes(ConstString symbol_name, + std::vector &indexes); + void SymbolIndicesToSymbolContextList(std::vector &symbol_indexes, SymbolContextList &sc_list); diff --git a/gnu/llvm/lldb/include/lldb/Symbol/TaggedASTType.h b/gnu/llvm/lldb/include/lldb/Symbol/TaggedASTType.h index f02f99258a3..fe1a2c659d9 100644 --- a/gnu/llvm/lldb/include/lldb/Symbol/TaggedASTType.h +++ b/gnu/llvm/lldb/include/lldb/Symbol/TaggedASTType.h @@ -27,7 +27,7 @@ public: TaggedASTType() : CompilerType() {} - virtual ~TaggedASTType() {} + virtual ~TaggedASTType() = default; TaggedASTType &operator=(const TaggedASTType &tw) { CompilerType::operator=(tw); diff --git a/gnu/llvm/lldb/include/lldb/Symbol/Type.h b/gnu/llvm/lldb/include/lldb/Symbol/Type.h index 8735d016bb2..9e671a565dd 100644 --- a/gnu/llvm/lldb/include/lldb/Symbol/Type.h +++ b/gnu/llvm/lldb/include/lldb/Symbol/Type.h @@ -9,9 +9,9 @@ #ifndef LLDB_SYMBOL_TYPE_H #define LLDB_SYMBOL_TYPE_H +#include "lldb/Core/Declaration.h" #include "lldb/Symbol/CompilerDecl.h" #include "lldb/Symbol/CompilerType.h" -#include "lldb/Symbol/Declaration.h" #include "lldb/Utility/ConstString.h" #include "lldb/Utility/UserID.h" #include "lldb/lldb-private.h" @@ -51,11 +51,12 @@ public: SymbolFileType(SymbolFile &symbol_file, const lldb::TypeSP &type_sp); - ~SymbolFileType() {} + ~SymbolFileType() = default; Type *operator->() { return GetType(); } Type *GetType(); + SymbolFile &GetSymbolFile() const { return m_symbol_file; } protected: SymbolFile &m_symbol_file; @@ -108,20 +109,27 @@ public: void DumpTypeName(Stream *s); - // Since Type instances only keep a "SymbolFile *" internally, other classes - // like TypeImpl need make sure the module is still around before playing - // with - // Type instances. They can store a weak pointer to the Module; + /// Since Type instances only keep a "SymbolFile *" internally, other classes + /// like TypeImpl need make sure the module is still around before playing + /// with + /// Type instances. They can store a weak pointer to the Module; lldb::ModuleSP GetModule(); - void GetDescription(Stream *s, lldb::DescriptionLevel level, bool show_name); + /// GetModule may return module for compile unit's object file. + /// GetExeModule returns module for executable object file that contains + /// compile unit where type was actualy defined. + /// GetModule and GetExeModule may return the same value. + lldb::ModuleSP GetExeModule(); + + void GetDescription(Stream *s, lldb::DescriptionLevel level, bool show_name, + ExecutionContextScope *exe_scope); SymbolFile *GetSymbolFile() { return m_symbol_file; } const SymbolFile *GetSymbolFile() const { return m_symbol_file; } ConstString GetName(); - llvm::Optional GetByteSize(); + llvm::Optional GetByteSize(ExecutionContextScope *exe_scope); uint32_t GetNumChildren(bool omit_empty_base_classes); @@ -205,17 +213,17 @@ public: protected: ConstString m_name; - SymbolFile *m_symbol_file; + SymbolFile *m_symbol_file = nullptr; /// The symbol context in which this type is defined. - SymbolContextScope *m_context; - Type *m_encoding_type; - lldb::user_id_t m_encoding_uid; - EncodingDataType m_encoding_uid_type; + SymbolContextScope *m_context = nullptr; + Type *m_encoding_type = nullptr; + lldb::user_id_t m_encoding_uid = LLDB_INVALID_UID; + EncodingDataType m_encoding_uid_type = eEncodingInvalid; uint64_t m_byte_size : 63; uint64_t m_byte_size_has_value : 1; Declaration m_decl; CompilerType m_compiler_type; - ResolveState m_compiler_type_resolve_state; + ResolveState m_compiler_type_resolve_state = ResolveState::Unresolved; /// Language-specific flags. Payload m_payload; @@ -231,7 +239,7 @@ class TypeImpl { public: TypeImpl() = default; - ~TypeImpl() {} + ~TypeImpl() = default; TypeImpl(const lldb::TypeSP &type_sp); @@ -259,6 +267,8 @@ public: void Clear(); + lldb::ModuleSP GetModule() const; + ConstString GetName() const; ConstString GetDisplayTypeName() const; @@ -286,8 +296,12 @@ public: private: bool CheckModule(lldb::ModuleSP &module_sp) const; + bool CheckExeModule(lldb::ModuleSP &module_sp) const; + bool CheckModuleCommon(const lldb::ModuleWP &input_module_wp, + lldb::ModuleSP &module_sp) const; lldb::ModuleWP m_module_wp; + lldb::ModuleWP m_exe_module_wp; CompilerType m_static_type; CompilerType m_dynamic_type; }; @@ -326,8 +340,7 @@ private: class TypeMemberImpl { public: TypeMemberImpl() - : m_type_impl_sp(), m_bit_offset(0), m_name(), m_bitfield_bit_size(0), - m_is_bitfield(false) + : m_type_impl_sp(), m_name() {} @@ -362,10 +375,10 @@ public: protected: lldb::TypeImplSP m_type_impl_sp; - uint64_t m_bit_offset; + uint64_t m_bit_offset = 0; ConstString m_name; - uint32_t m_bitfield_bit_size; // Bit size for bitfield members only - bool m_is_bitfield; + uint32_t m_bitfield_bit_size = 0; // Bit size for bitfield members only + bool m_is_bitfield = false; }; /// @@ -421,9 +434,7 @@ private: class TypeMemberFunctionImpl { public: - TypeMemberFunctionImpl() - : m_type(), m_decl(), m_name(), m_kind(lldb::eMemberFunctionKindUnknown) { - } + TypeMemberFunctionImpl() : m_type(), m_decl(), m_name() {} TypeMemberFunctionImpl(const CompilerType &type, const CompilerDecl &decl, const std::string &name, @@ -455,13 +466,12 @@ private: CompilerType m_type; CompilerDecl m_decl; ConstString m_name; - lldb::MemberFunctionKind m_kind; + lldb::MemberFunctionKind m_kind = lldb::eMemberFunctionKindUnknown; }; class TypeEnumMemberImpl { public: - TypeEnumMemberImpl() - : m_integer_type_sp(), m_name(""), m_value(), m_valid(false) {} + TypeEnumMemberImpl() : m_integer_type_sp(), m_name(""), m_value() {} TypeEnumMemberImpl(const lldb::TypeImplSP &integer_type_sp, ConstString name, const llvm::APSInt &value); @@ -484,7 +494,7 @@ protected: lldb::TypeImplSP m_integer_type_sp; ConstString m_name; llvm::APSInt m_value; - bool m_valid; + bool m_valid = false; }; class TypeEnumMemberListImpl { diff --git a/gnu/llvm/lldb/include/lldb/Symbol/TypeSystem.h b/gnu/llvm/lldb/include/lldb/Symbol/TypeSystem.h index e188f29354b..a37c1040b16 100644 --- a/gnu/llvm/lldb/include/lldb/Symbol/TypeSystem.h +++ b/gnu/llvm/lldb/include/lldb/Symbol/TypeSystem.h @@ -152,8 +152,7 @@ public: virtual bool IsFloatingPointType(lldb::opaque_compiler_type_t type, uint32_t &count, bool &is_complex) = 0; - virtual bool IsFunctionType(lldb::opaque_compiler_type_t type, - bool *is_variadic_ptr) = 0; + virtual bool IsFunctionType(lldb::opaque_compiler_type_t type) = 0; virtual size_t GetNumberOfFunctionArguments(lldb::opaque_compiler_type_t type) = 0; @@ -176,6 +175,8 @@ public: return false; } + virtual bool IsScopedEnumerationType(lldb::opaque_compiler_type_t type) = 0; + virtual bool IsPossibleDynamicType(lldb::opaque_compiler_type_t type, CompilerType *target_type, // Can pass NULL bool check_cplusplus, bool check_objc) = 0; @@ -217,14 +218,18 @@ public: // Creating related types - virtual CompilerType GetArrayElementType(lldb::opaque_compiler_type_t type, - uint64_t *stride) = 0; + virtual CompilerType + GetArrayElementType(lldb::opaque_compiler_type_t type, + ExecutionContextScope *exe_scope) = 0; virtual CompilerType GetArrayType(lldb::opaque_compiler_type_t type, uint64_t size); virtual CompilerType GetCanonicalType(lldb::opaque_compiler_type_t type) = 0; + virtual CompilerType + GetEnumerationIntegerType(lldb::opaque_compiler_type_t type) = 0; + // Returns -1 if this isn't a function of if the function doesn't have a // prototype Returns a value >= 0 if there is a prototype. virtual int GetFunctionArgumentCount(lldb::opaque_compiler_type_t type) = 0; @@ -464,10 +469,8 @@ public: return nullptr; } - virtual UtilityFunction *GetUtilityFunction(const char *text, - const char *name) { - return nullptr; - } + virtual std::unique_ptr + CreateUtilityFunction(std::string text, std::string name); virtual PersistentExpressionState *GetPersistentExpressionState() { return nullptr; @@ -521,7 +524,23 @@ protected: mutable std::mutex m_mutex; ///< A mutex to keep this object happy in ///multi-threaded environments. collection m_map; - bool m_clear_in_progress; + bool m_clear_in_progress = false; + +private: + typedef llvm::function_ref CreateCallback; + /// Finds the type system for the given language. If no type system could be + /// found for a language and a CreateCallback was provided, the value returned + /// by the callback will be treated as the TypeSystem for the language. + /// + /// \param language The language for which the type system should be found. + /// \param create_callback A callback that will be called if no previously + /// created TypeSystem that fits the given language + /// could found. Can be omitted if a non-existent + /// type system should be treated as an error instead. + /// \return The found type system or an error. + llvm::Expected GetTypeSystemForLanguage( + lldb::LanguageType language, + llvm::Optional create_callback = llvm::None); }; } // namespace lldb_private diff --git a/gnu/llvm/lldb/include/lldb/Symbol/UnwindPlan.h b/gnu/llvm/lldb/include/lldb/Symbol/UnwindPlan.h index 8902b5f4eaa..cc2302d2583 100644 --- a/gnu/llvm/lldb/include/lldb/Symbol/UnwindPlan.h +++ b/gnu/llvm/lldb/include/lldb/Symbol/UnwindPlan.h @@ -71,7 +71,7 @@ public: isDWARFExpression // reg = eval(dwarf_expr) }; - RegisterLocation() : m_type(unspecified), m_location() {} + RegisterLocation() : m_location() {} bool operator==(const RegisterLocation &rhs) const; @@ -181,7 +181,7 @@ public: const UnwindPlan::Row *row, Thread *thread, bool verbose) const; private: - RestoreType m_type; // How do we locate this register? + RestoreType m_type = unspecified; // How do we locate this register? union { // For m_type == atCFAPlusOffset or m_type == isCFAPlusOffset int32_t offset; @@ -205,7 +205,7 @@ public: isRaSearch, // FA = SP + offset + ??? }; - FAValue() : m_type(unspecified), m_value() {} + FAValue() : m_value() {} bool operator==(const FAValue &rhs) const; @@ -301,7 +301,7 @@ public: void Dump(Stream &s, const UnwindPlan *unwind_plan, Thread *thread) const; private: - ValueType m_type; // How do we compute CFA value? + ValueType m_type = unspecified; // How do we compute CFA value? union { struct { // For m_type == isRegisterPlusOffset or m_type == @@ -322,8 +322,6 @@ public: Row(); - Row(const UnwindPlan::Row &rhs) = default; - bool operator==(const Row &rhs) const; bool GetRegisterInfo(uint32_t reg_num, @@ -360,6 +358,25 @@ public: bool SetRegisterLocationToSame(uint32_t reg_num, bool must_replace); + // When this UnspecifiedRegistersAreUndefined mode is + // set, any register that is not specified by this Row will + // be described as Undefined. + // This will prevent the unwinder from iterating down the + // stack looking for a spill location, or a live register value + // at frame 0. + // It would be used for an UnwindPlan row where we can't track + // spilled registers -- for instance a jitted stack frame where + // we have no unwind information or start address -- and registers + // MAY have been spilled and overwritten, so providing the + // spilled/live value from a newer frame may show an incorrect value. + void SetUnspecifiedRegistersAreUndefined(bool unspec_is_undef) { + m_unspecified_registers_are_undefined = unspec_is_undef; + } + + bool GetUnspecifiedRegistersAreUndefined() { + return m_unspecified_registers_are_undefined; + } + void Clear(); void Dump(Stream &s, const UnwindPlan *unwind_plan, Thread *thread, @@ -367,11 +384,12 @@ public: protected: typedef std::map collection; - lldb::addr_t m_offset; // Offset into the function for this row + lldb::addr_t m_offset = 0; // Offset into the function for this row FAValue m_cfa_value; FAValue m_afa_value; collection m_register_locations; + bool m_unspecified_registers_are_undefined = false; }; // class Row typedef std::shared_ptr RowSP; @@ -393,6 +411,7 @@ public: m_plan_is_sourced_from_compiler(rhs.m_plan_is_sourced_from_compiler), m_plan_is_valid_at_all_instruction_locations( rhs.m_plan_is_valid_at_all_instruction_locations), + m_plan_is_for_signal_trap(rhs.m_plan_is_for_signal_trap), m_lsda_address(rhs.m_lsda_address), m_personality_func_addr(rhs.m_personality_func_addr) { m_row_list.reserve(rhs.m_row_list.size()); diff --git a/gnu/llvm/lldb/include/lldb/Symbol/Variable.h b/gnu/llvm/lldb/include/lldb/Symbol/Variable.h index 66abdc0b311..ccd5072c3d2 100644 --- a/gnu/llvm/lldb/include/lldb/Symbol/Variable.h +++ b/gnu/llvm/lldb/include/lldb/Symbol/Variable.h @@ -9,9 +9,9 @@ #ifndef LLDB_SYMBOL_VARIABLE_H #define LLDB_SYMBOL_VARIABLE_H +#include "lldb/Core/Declaration.h" #include "lldb/Core/Mangled.h" #include "lldb/Expression/DWARFExpression.h" -#include "lldb/Symbol/Declaration.h" #include "lldb/Utility/CompletionRequest.h" #include "lldb/Utility/RangeMap.h" #include "lldb/Utility/UserID.h" @@ -33,7 +33,8 @@ public: const lldb::SymbolFileTypeSP &symfile_type_sp, lldb::ValueType scope, SymbolContextScope *owner_scope, const RangeList &scope_range, Declaration *decl, const DWARFExpression &location, bool external, - bool artificial, bool static_member = false); + bool artificial, bool location_is_constant_data, + bool static_member = false); virtual ~Variable(); @@ -64,6 +65,8 @@ public: lldb::ValueType GetScope() const { return m_scope; } + const RangeList &GetScopeRange() const { return m_scope_range; } + bool IsExternal() const { return m_external; } bool IsArtificial() const { return m_artificial; } diff --git a/gnu/llvm/lldb/include/lldb/Target/ABI.h b/gnu/llvm/lldb/include/lldb/Target/ABI.h index b252e4b54f0..8fbb6aae68c 100644 --- a/gnu/llvm/lldb/include/lldb/Target/ABI.h +++ b/gnu/llvm/lldb/include/lldb/Target/ABI.h @@ -117,12 +117,13 @@ public: // "pc". virtual bool CodeAddressIsValid(lldb::addr_t pc) = 0; - virtual lldb::addr_t FixCodeAddress(lldb::addr_t pc) { - // Some targets might use bits in a code address to indicate a mode switch. - // ARM uses bit zero to signify a code address is thumb, so any ARM ABI - // plug-ins would strip those bits. - return pc; - } + /// Some targets might use bits in a code address to indicate a mode switch. + /// ARM uses bit zero to signify a code address is thumb, so any ARM ABI + /// plug-ins would strip those bits. + /// @{ + virtual lldb::addr_t FixCodeAddress(lldb::addr_t pc) { return pc; } + virtual lldb::addr_t FixDataAddress(lldb::addr_t pc) { return pc; } + /// @} llvm::MCRegisterInfo &GetMCRegisterInfo() { return *m_mc_register_info_up; } @@ -147,6 +148,10 @@ protected: lldb::ProcessWP m_process_wp; std::unique_ptr m_mc_register_info_up; + virtual lldb::addr_t FixCodeAddress(lldb::addr_t pc, lldb::addr_t mask) { + return pc; + } + private: ABI(const ABI &) = delete; const ABI &operator=(const ABI &) = delete; @@ -159,7 +164,7 @@ public: protected: using ABI::ABI; - bool GetRegisterInfoByName(ConstString name, RegisterInfo &info); + bool GetRegisterInfoByName(llvm::StringRef name, RegisterInfo &info); virtual const RegisterInfo *GetRegisterInfoArray(uint32_t &count) = 0; }; diff --git a/gnu/llvm/lldb/include/lldb/Target/DynamicLoader.h b/gnu/llvm/lldb/include/lldb/Target/DynamicLoader.h index d3ce1b05ed5..a904fac0c77 100644 --- a/gnu/llvm/lldb/include/lldb/Target/DynamicLoader.h +++ b/gnu/llvm/lldb/include/lldb/Target/DynamicLoader.h @@ -18,8 +18,8 @@ #include "lldb/lldb-private-enumerations.h" #include "lldb/lldb-types.h" -#include -#include +#include +#include namespace lldb_private { class ModuleList; class Process; @@ -68,12 +68,6 @@ public: /// Construct with a process. DynamicLoader(Process *process); - /// Destructor. - /// - /// The destructor is virtual since this class is designed to be inherited - /// from by the plug-in instance. - ~DynamicLoader() override; - /// Called after attaching a process. /// /// Allow DynamicLoader plug-ins to execute some code after attaching to a @@ -257,6 +251,14 @@ public: return false; } + /// Return whether the dynamic loader is fully initialized and it's safe to + /// call its APIs. + /// + /// On some systems (e.g. Darwin based systems), lldb will get notified by + /// the dynamic loader before it itself finished initializing and it's not + /// safe to call certain APIs or SPIs. + virtual bool IsFullyInitialized() { return true; } + protected: // Utility methods for derived classes @@ -300,7 +302,7 @@ protected: // Read a pointer from memory at the given addr. Return LLDB_INVALID_ADDRESS // if the read fails. lldb::addr_t ReadPointer(lldb::addr_t addr); - + // Calls into the Process protected method LoadOperatingSystemPlugin: void LoadOperatingSystemPlugin(bool flush); @@ -308,10 +310,6 @@ protected: // Member variables. Process *m_process; ///< The process that this dynamic loader plug-in is tracking. - -private: - DynamicLoader(const DynamicLoader &) = delete; - const DynamicLoader &operator=(const DynamicLoader &) = delete; }; } // namespace lldb_private diff --git a/gnu/llvm/lldb/include/lldb/Target/ExecutionContext.h b/gnu/llvm/lldb/include/lldb/Target/ExecutionContext.h index 169d56ac9b6..d8c233a666b 100644 --- a/gnu/llvm/lldb/include/lldb/Target/ExecutionContext.h +++ b/gnu/llvm/lldb/include/lldb/Target/ExecutionContext.h @@ -263,8 +263,9 @@ protected: lldb::TargetWP m_target_wp; ///< A weak reference to a target lldb::ProcessWP m_process_wp; ///< A weak reference to a process mutable lldb::ThreadWP m_thread_wp; ///< A weak reference to a thread - lldb::tid_t m_tid; ///< The thread ID that this object refers to in case the - ///backing object changes + lldb::tid_t m_tid = LLDB_INVALID_THREAD_ID; ///< The thread ID that this + ///< object refers to in case the + /// backing object changes StackID m_stack_id; ///< The stack ID that this object refers to in case the ///backing object changes }; diff --git a/gnu/llvm/lldb/include/lldb/Target/ExecutionContextScope.h b/gnu/llvm/lldb/include/lldb/Target/ExecutionContextScope.h index d7003e9a572..4f5b08ed618 100644 --- a/gnu/llvm/lldb/include/lldb/Target/ExecutionContextScope.h +++ b/gnu/llvm/lldb/include/lldb/Target/ExecutionContextScope.h @@ -31,7 +31,7 @@ namespace lldb_private { /// context to allow functions that take a execution contexts to be called. class ExecutionContextScope { public: - virtual ~ExecutionContextScope() {} + virtual ~ExecutionContextScope() = default; virtual lldb::TargetSP CalculateTarget() = 0; diff --git a/gnu/llvm/lldb/include/lldb/Target/InstrumentationRuntime.h b/gnu/llvm/lldb/include/lldb/Target/InstrumentationRuntime.h index dd4da26c215..eeec91f36af 100644 --- a/gnu/llvm/lldb/include/lldb/Target/InstrumentationRuntime.h +++ b/gnu/llvm/lldb/include/lldb/Target/InstrumentationRuntime.h @@ -53,7 +53,7 @@ protected: lldb::ModuleSP GetRuntimeModuleSP() { return m_runtime_module; } void SetRuntimeModuleSP(lldb::ModuleSP module_sp) { - m_runtime_module = module_sp; + m_runtime_module = std::move(module_sp); } lldb::user_id_t GetBreakpointID() const { return m_breakpoint_id; } diff --git a/gnu/llvm/lldb/include/lldb/Target/InstrumentationRuntimeStopInfo.h b/gnu/llvm/lldb/include/lldb/Target/InstrumentationRuntimeStopInfo.h index 2cbf27d7b34..53451608509 100644 --- a/gnu/llvm/lldb/include/lldb/Target/InstrumentationRuntimeStopInfo.h +++ b/gnu/llvm/lldb/include/lldb/Target/InstrumentationRuntimeStopInfo.h @@ -18,7 +18,7 @@ namespace lldb_private { class InstrumentationRuntimeStopInfo : public StopInfo { public: - ~InstrumentationRuntimeStopInfo() override {} + ~InstrumentationRuntimeStopInfo() override = default; lldb::StopReason GetStopReason() const override { return lldb::eStopReasonInstrumentation; diff --git a/gnu/llvm/lldb/include/lldb/Target/Language.h b/gnu/llvm/lldb/include/lldb/Target/Language.h index 9dc9df363d7..11b9daa3894 100644 --- a/gnu/llvm/lldb/include/lldb/Target/Language.h +++ b/gnu/llvm/lldb/include/lldb/Target/Language.h @@ -184,14 +184,31 @@ public: virtual const char *GetLanguageSpecificTypeLookupHelp(); + class MethodNameVariant { + ConstString m_name; + lldb::FunctionNameType m_type; + + public: + MethodNameVariant(ConstString name, lldb::FunctionNameType type) + : m_name(name), m_type(type) {} + ConstString GetName() const { return m_name; } + lldb::FunctionNameType GetType() const { return m_type; } + }; // If a language can have more than one possible name for a method, this // function can be used to enumerate them. This is useful when doing name // lookups. - virtual std::vector + virtual std::vector GetMethodNameVariants(ConstString method_name) const { - return std::vector(); + return std::vector(); }; + /// Returns true iff the given symbol name is compatible with the mangling + /// scheme of this language. + /// + /// This function should only return true if there is a high confidence + /// that the name actually belongs to this language. + virtual bool SymbolNameFitsToLanguage(Mangled name) const { return false; } + // if an individual data formatter can apply to several types and cross a // language boundary it makes sense for individual languages to want to // customize the printing of values of that type by appending proper @@ -211,6 +228,10 @@ public: // nil/null object, this method returns true virtual bool IsNilReference(ValueObject &valobj); + /// Returns the summary string for ValueObjects for which IsNilReference() is + /// true. + virtual llvm::StringRef GetNilReferenceSummaryString() { return {}; } + // for a ValueObject of some "reference type", if the language provides a // technique to decide whether the reference has ever been assigned to some // object, this method will return true if such detection is possible, and if diff --git a/gnu/llvm/lldb/include/lldb/Target/LanguageRuntime.h b/gnu/llvm/lldb/include/lldb/Target/LanguageRuntime.h index b0b9b919911..2f95c264331 100644 --- a/gnu/llvm/lldb/include/lldb/Target/LanguageRuntime.h +++ b/gnu/llvm/lldb/include/lldb/Target/LanguageRuntime.h @@ -18,6 +18,7 @@ #include "lldb/Expression/LLVMUserExpression.h" #include "lldb/Symbol/DeclVendor.h" #include "lldb/Target/ExecutionContextScope.h" +#include "lldb/Target/Runtime.h" #include "lldb/lldb-private.h" #include "lldb/lldb-public.h" @@ -56,10 +57,8 @@ protected: void UpdateModuleListIfNeeded(); }; -class LanguageRuntime : public PluginInterface { +class LanguageRuntime : public Runtime, public PluginInterface { public: - ~LanguageRuntime() override; - static LanguageRuntime *FindPlugin(Process *process, lldb::LanguageType language); @@ -127,10 +126,6 @@ public: return lldb::ThreadSP(); } - Process *GetProcess() { return m_process; } - - Target &GetTargetRef() { return m_process->GetTarget(); } - virtual DeclVendor *GetDeclVendor() { return nullptr; } virtual lldb::BreakpointResolverSP @@ -159,7 +154,7 @@ public: return llvm::None; } - virtual void ModulesDidLoad(const ModuleList &module_list) {} + virtual void ModulesDidLoad(const ModuleList &module_list) override {} // Called by ClangExpressionParser::PrepareForExecution to query for any // custom LLVM IR passes that need to be run before an expression is @@ -178,15 +173,52 @@ public: virtual bool isA(const void *ClassID) const { return ClassID == &ID; } static char ID; + /// A language runtime may be able to provide a special UnwindPlan for + /// the frame represented by the register contents \a regctx when that + /// frame is not following the normal ABI conventions. + /// Instead of using the normal UnwindPlan for the function, we will use + /// this special UnwindPlan for this one backtrace. + /// One example of this would be a language that has asynchronous functions, + /// functions that may not be currently-executing, while waiting on other + /// asynchronous calls they made, but are part of a logical backtrace that + /// we want to show the developer because that's how they think of the + /// program flow. + /// + /// \param[in] thread + /// The thread that the unwind is happening on. + /// + /// \param[in] regctx + /// The RegisterContext for the frame we need to create an UnwindPlan. + /// We don't yet have a StackFrame when we're selecting the UnwindPlan. + /// + /// \param[out] behaves_like_zeroth_frame + /// With normal ABI calls, all stack frames except the zeroth frame need + /// to have the return-pc value backed up by 1 for symbolication purposes. + /// For these LanguageRuntime unwind plans, they may not follow normal ABI + /// calling conventions and the return pc may need to be symbolicated + /// as-is. + /// + /// \return + /// Returns an UnwindPlan to find the caller frame if it should be used, + /// instead of the UnwindPlan that would normally be used for this + /// function. + static lldb::UnwindPlanSP + GetRuntimeUnwindPlan(lldb_private::Thread &thread, + lldb_private::RegisterContext *regctx, + bool &behaves_like_zeroth_frame); + protected: - // Classes that inherit from LanguageRuntime can see and modify these + // The static GetRuntimeUnwindPlan method above is only implemented in the + // base class; subclasses may override this protected member if they can + // provide one of these UnwindPlans. + virtual lldb::UnwindPlanSP + GetRuntimeUnwindPlan(lldb::ProcessSP process_sp, + lldb_private::RegisterContext *regctx, + bool &behaves_like_zeroth_frame) { + return lldb::UnwindPlanSP(); + } LanguageRuntime(Process *process); - Process *m_process; - -private: - LanguageRuntime(const LanguageRuntime &) = delete; - const LanguageRuntime &operator=(const LanguageRuntime &) = delete; }; } // namespace lldb_private diff --git a/gnu/llvm/lldb/include/lldb/Target/MemoryRegionInfo.h b/gnu/llvm/lldb/include/lldb/Target/MemoryRegionInfo.h index a22da8d72b8..c43f27e0c36 100644 --- a/gnu/llvm/lldb/include/lldb/Target/MemoryRegionInfo.h +++ b/gnu/llvm/lldb/include/lldb/Target/MemoryRegionInfo.h @@ -10,8 +10,11 @@ #ifndef LLDB_TARGET_MEMORYREGIONINFO_H #define LLDB_TARGET_MEMORYREGIONINFO_H +#include + #include "lldb/Utility/ConstString.h" #include "lldb/Utility/RangeMap.h" +#include "llvm/ADT/Optional.h" #include "llvm/Support/FormatProviders.h" namespace lldb_private { @@ -24,17 +27,15 @@ public: MemoryRegionInfo() = default; MemoryRegionInfo(RangeType range, OptionalBool read, OptionalBool write, OptionalBool execute, OptionalBool mapped, ConstString name, - OptionalBool flash, lldb::offset_t blocksize) + OptionalBool flash, lldb::offset_t blocksize, + OptionalBool memory_tagged) : m_range(range), m_read(read), m_write(write), m_execute(execute), - m_mapped(mapped), m_name(name), m_flash(flash), m_blocksize(blocksize) { - } + m_mapped(mapped), m_name(name), m_flash(flash), m_blocksize(blocksize), + m_memory_tagged(memory_tagged) {} RangeType &GetRange() { return m_range; } - void Clear() { - m_range.Clear(); - m_read = m_write = m_execute = eDontKnow; - } + void Clear() { *this = MemoryRegionInfo(); } const RangeType &GetRange() const { return m_range; } @@ -48,6 +49,8 @@ public: ConstString GetName() const { return m_name; } + OptionalBool GetMemoryTagged() const { return m_memory_tagged; } + void SetReadable(OptionalBool val) { m_read = val; } void SetWritable(OptionalBool val) { m_write = val; } @@ -66,6 +69,8 @@ public: void SetBlocksize(lldb::offset_t blocksize) { m_blocksize = blocksize; } + void SetMemoryTagged(OptionalBool val) { m_memory_tagged = val; } + // Get permissions as a uint32_t that is a mask of one or more bits from the // lldb::Permissions uint32_t GetLLDBPermissions() const { @@ -91,11 +96,34 @@ public: return m_range == rhs.m_range && m_read == rhs.m_read && m_write == rhs.m_write && m_execute == rhs.m_execute && m_mapped == rhs.m_mapped && m_name == rhs.m_name && - m_flash == rhs.m_flash && m_blocksize == rhs.m_blocksize; + m_flash == rhs.m_flash && m_blocksize == rhs.m_blocksize && + m_memory_tagged == rhs.m_memory_tagged && + m_pagesize == rhs.m_pagesize; } bool operator!=(const MemoryRegionInfo &rhs) const { return !(*this == rhs); } + /// Get the target system's VM page size in bytes. + /// \return + /// 0 is returned if this information is unavailable. + int GetPageSize() { return m_pagesize; } + + /// Get a vector of target VM pages that are dirty -- that have been + /// modified -- within this memory region. This is an Optional return + /// value; it will only be available if the remote stub was able to + /// detail this. + llvm::Optional> &GetDirtyPageList() { + return m_dirty_pages; + } + + void SetPageSize(int pagesize) { m_pagesize = pagesize; } + + void SetDirtyPageList(std::vector pagelist) { + if (m_dirty_pages.hasValue()) + m_dirty_pages.getValue().clear(); + m_dirty_pages = std::move(pagelist); + } + protected: RangeType m_range; OptionalBool m_read = eDontKnow; @@ -105,6 +133,9 @@ protected: ConstString m_name; OptionalBool m_flash = eDontKnow; lldb::offset_t m_blocksize = 0; + OptionalBool m_memory_tagged = eDontKnow; + int m_pagesize = 0; + llvm::Optional> m_dirty_pages; }; inline bool operator<(const MemoryRegionInfo &lhs, diff --git a/gnu/llvm/lldb/include/lldb/Target/MemoryTagManager.h b/gnu/llvm/lldb/include/lldb/Target/MemoryTagManager.h new file mode 100644 index 00000000000..a5e0deba14a --- /dev/null +++ b/gnu/llvm/lldb/include/lldb/Target/MemoryTagManager.h @@ -0,0 +1,135 @@ +//===-- MemoryTagManager.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_TARGET_MEMORYTAGMANAGER_H +#define LLDB_TARGET_MEMORYTAGMANAGER_H + +#include "lldb/Target/MemoryRegionInfo.h" +#include "lldb/Utility/RangeMap.h" +#include "lldb/lldb-private.h" +#include "llvm/Support/Error.h" + +namespace lldb_private { + +// This interface allows high level commands to handle memory tags +// in a generic way. +// +// Definitions: +// logical tag - the tag stored in a pointer +// allocation tag - the tag stored in hardware +// (e.g. special memory, cache line bits) +// granule - number of bytes of memory a single tag applies to + +class MemoryTagManager { +public: + typedef Range TagRange; + + // Extract the logical tag from a pointer + // The tag is returned as a plain value, with any shifts removed. + // For example if your tags are stored in bits 56-60 then the logical tag + // you get will have been shifted down 56 before being returned. + virtual lldb::addr_t GetLogicalTag(lldb::addr_t addr) const = 0; + + // Remove non address bits from a pointer + virtual lldb::addr_t RemoveNonAddressBits(lldb::addr_t addr) const = 0; + + // Return the difference between two addresses, ignoring any logical tags they + // have. If your tags are just part of a larger set of ignored bits, this + // should ignore all those bits. + virtual ptrdiff_t AddressDiff(lldb::addr_t addr1, + lldb::addr_t addr2) const = 0; + + // Return the number of bytes a single tag covers + virtual lldb::addr_t GetGranuleSize() const = 0; + + // Align an address range to granule boundaries. + // So that reading memory tags for the new range returns + // tags that will cover the original range. + // + // Say your granules are 16 bytes and you want + // tags for 16 bytes of memory starting from address 8. + // 1 granule isn't enough because it only covers addresses + // 0-16, we want addresses 8-24. So the range must be + // expanded to 2 granules. + virtual TagRange ExpandToGranule(TagRange range) const = 0; + + // Given a range addr to end_addr, check that: + // * end_addr >= addr (when memory tags are removed) + // * the granule aligned range is completely covered by tagged memory + // (which may include one or more memory regions) + // + // If so, return a modified range which will have been expanded + // to be granule aligned. + // + // Tags in the input addresses are ignored and not present + // in the returned range. + virtual llvm::Expected MakeTaggedRange( + lldb::addr_t addr, lldb::addr_t end_addr, + const lldb_private::MemoryRegionInfos &memory_regions) const = 0; + + // Return the type value to use in GDB protocol qMemTags packets to read + // allocation tags. This is named "Allocation" specifically because the spec + // allows for logical tags to be read the same way, though we do not use that. + // + // This value is unique within a given architecture. Meaning that different + // tagging schemes within the same architecture should use unique values, + // but other architectures can overlap those values. + virtual int32_t GetAllocationTagType() const = 0; + + // Return the number of bytes a single tag will be packed into during + // transport. For example an MTE tag is 4 bits but occupies 1 byte during + // transport. + virtual size_t GetTagSizeInBytes() const = 0; + + // Unpack tags from their stored format (e.g. gdb qMemTags data) into seperate + // tags. + // + // Checks that each tag is within the expected value range and if granules is + // set to non-zero, that the number of tags found matches the number of + // granules we expected to cover. + virtual llvm::Expected> + UnpackTagsData(const std::vector &tags, + size_t granules = 0) const = 0; + + // Pack uncompressed tags into their storage format (e.g. for gdb QMemTags). + // Checks that each tag is within the expected value range. + // We do not check the number of tags or range they apply to because + // it is up to the remote to repeat them as needed. + virtual llvm::Expected> + PackTags(const std::vector &tags) const = 0; + + // Take a set of tags and repeat them as much as needed to cover the given + // range. We assume that this range has been previously expanded/aligned to + // granules. (this method is used by lldb-server to implement QMemTags + // packet handling) + // + // If the range is empty, zero tags are returned. + // If the range is not empty and... + // * there are no tags, an error is returned. + // * there are fewer tags than granules, the tags are repeated to fill the + // range. + // * there are more tags than granules, only the tags required to cover + // the range are returned. + // + // When repeating tags it will not always return a multiple of the original + // list. For example if your range is 3 granules and your tags are 1 and 2. + // You will get tags 1, 2 and 1 returned. Rather than getting 1, 2, 1, 2, + // which would be one too many tags for the range. + // + // A single tag will just be repeated as you'd expected. Tag 1 over 3 granules + // would return 1, 1, 1. + virtual llvm::Expected> + RepeatTagsForRange(const std::vector &tags, + TagRange range) const = 0; + + virtual ~MemoryTagManager() {} +}; + +} // namespace lldb_private + +#endif // LLDB_TARGET_MEMORYTAGMANAGER_H diff --git a/gnu/llvm/lldb/include/lldb/Target/OperatingSystem.h b/gnu/llvm/lldb/include/lldb/Target/OperatingSystem.h index 6db5c0a01f3..ceeddceb0f2 100644 --- a/gnu/llvm/lldb/include/lldb/Target/OperatingSystem.h +++ b/gnu/llvm/lldb/include/lldb/Target/OperatingSystem.h @@ -40,11 +40,8 @@ public: /// should be used. If NULL, pick the best plug-in. static OperatingSystem *FindPlugin(Process *process, const char *plugin_name); - // Class Methods OperatingSystem(Process *process); - ~OperatingSystem() override; - // Plug-in Methods virtual bool UpdateThreadList(ThreadList &old_thread_list, ThreadList &real_thread_list, @@ -68,9 +65,6 @@ protected: // Member variables. Process *m_process; ///< The process that this dynamic loader plug-in is tracking. -private: - OperatingSystem(const OperatingSystem &) = delete; - const OperatingSystem &operator=(const OperatingSystem &) = delete; }; } // namespace lldb_private diff --git a/gnu/llvm/lldb/include/lldb/Target/PathMappingList.h b/gnu/llvm/lldb/include/lldb/Target/PathMappingList.h index 9e1e6eb26eb..d788d120c47 100644 --- a/gnu/llvm/lldb/include/lldb/Target/PathMappingList.h +++ b/gnu/llvm/lldb/include/lldb/Target/PathMappingList.h @@ -72,13 +72,19 @@ public: /// \param[in] path /// The original source file path to try and remap. /// - /// \param[out] new_path - /// The newly remapped filespec that is may or may not exist. + /// \param[in] only_if_exists + /// If \b true, besides matching \p path with the remapping rules, this + /// tries to check with the filesystem that the remapped file exists. If + /// no valid file is found, \b None is returned. This might be expensive, + /// specially on a network. + /// + /// If \b false, then the existence of the returned remapping is not + /// checked. /// /// \return - /// /b true if \a path was successfully located and \a new_path - /// is filled in with a new source path, \b false otherwise. - bool RemapPath(llvm::StringRef path, std::string &new_path) const; + /// The remapped filespec that may or may not exist on disk. + llvm::Optional RemapPath(llvm::StringRef path, + bool only_if_exists = false) const; bool RemapPath(const char *, std::string &) const = delete; bool ReverseRemapPath(const FileSpec &file, FileSpec &fixed) const; @@ -94,14 +100,9 @@ public: /// \param[in] orig_spec /// The original source file path to try and remap. /// - /// \param[out] new_spec - /// The newly remapped filespec that is guaranteed to exist. - /// /// \return - /// /b true if \a orig_spec was successfully located and - /// \a new_spec is filled in with an existing file spec, - /// \b false otherwise. - bool FindFile(const FileSpec &orig_spec, FileSpec &new_spec) const; + /// The newly remapped filespec that is guaranteed to exist. + llvm::Optional FindFile(const FileSpec &orig_spec) const; uint32_t FindIndexForPath(ConstString path) const; @@ -118,9 +119,9 @@ protected: const_iterator FindIteratorForPath(ConstString path) const; collection m_pairs; - ChangedCallback m_callback; - void *m_callback_baton; - uint32_t m_mod_id; // Incremented anytime anything is added or removed. + ChangedCallback m_callback = nullptr; + void *m_callback_baton = nullptr; + uint32_t m_mod_id = 0; // Incremented anytime anything is added or removed. }; } // namespace lldb_private diff --git a/gnu/llvm/lldb/include/lldb/Target/Platform.h b/gnu/llvm/lldb/include/lldb/Target/Platform.h index 277fcf68cb0..df46466655c 100644 --- a/gnu/llvm/lldb/include/lldb/Target/Platform.h +++ b/gnu/llvm/lldb/include/lldb/Target/Platform.h @@ -522,6 +522,9 @@ public: return UINT64_MAX; } + virtual void AutoCompleteDiskFileOrDirectory(CompletionRequest &request, + bool only_dir) {} + virtual uint64_t ReadFile(lldb::user_id_t fd, uint64_t offset, void *dst, uint64_t dst_len, Status &error) { error.SetErrorStringWithFormat( @@ -617,7 +620,18 @@ public: } virtual lldb_private::Status RunShellCommand( - const char *command, // Shouldn't be nullptr + llvm::StringRef command, + const FileSpec &working_dir, // Pass empty FileSpec to use the current + // working directory + int *status_ptr, // Pass nullptr if you don't want the process exit status + int *signo_ptr, // Pass nullptr if you don't want the signal that caused + // the process to exit + std::string + *command_output, // Pass nullptr if you don't want the command output + const Timeout &timeout); + + virtual lldb_private::Status RunShellCommand( + llvm::StringRef shell, llvm::StringRef command, const FileSpec &working_dir, // Pass empty FileSpec to use the current // working directory int *status_ptr, // Pass nullptr if you don't want the process exit status @@ -636,7 +650,7 @@ public: virtual bool CalculateMD5(const FileSpec &file_spec, uint64_t &low, uint64_t &high); - virtual int32_t GetResumeCountForLaunchInfo(ProcessLaunchInfo &launch_info) { + virtual uint32_t GetResumeCountForLaunchInfo(ProcessLaunchInfo &launch_info) { return 1; } @@ -936,9 +950,6 @@ private: Platform &remote_platform); FileSpec GetModuleCacheRoot(); - - Platform(const Platform &) = delete; - const Platform &operator=(const Platform &) = delete; }; class PlatformList { diff --git a/gnu/llvm/lldb/include/lldb/Target/PostMortemProcess.h b/gnu/llvm/lldb/include/lldb/Target/PostMortemProcess.h new file mode 100644 index 00000000000..353bfc0919e --- /dev/null +++ b/gnu/llvm/lldb/include/lldb/Target/PostMortemProcess.h @@ -0,0 +1,32 @@ +//===-- PostMortemProcess.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_TARGET_POSTMORTEMPROCESS_H +#define LLDB_TARGET_POSTMORTEMPROCESS_H + +#include "lldb/Target/Process.h" + +namespace lldb_private { + +/// \class PostMortemProcess +/// Base class for all processes that don't represent a live process, such as +/// coredumps or processes traced in the past. +/// +/// \a lldb_private::Process virtual functions overrides that are common +/// between these kinds of processes can have default implementations in this +/// class. +class PostMortemProcess : public Process { +public: + using Process::Process; + + bool IsLiveDebugSession() const override { return false; } +}; + +} // namespace lldb_private + +#endif // LLDB_TARGET_POSTMORTEMPROCESS_H diff --git a/gnu/llvm/lldb/include/lldb/Target/Process.h b/gnu/llvm/lldb/include/lldb/Target/Process.h index bf9b64547ed..aaa2470d293 100644 --- a/gnu/llvm/lldb/include/lldb/Target/Process.h +++ b/gnu/llvm/lldb/include/lldb/Target/Process.h @@ -11,7 +11,7 @@ #include "lldb/Host/Config.h" -#include +#include #include #include @@ -30,14 +30,15 @@ #include "lldb/Host/HostThread.h" #include "lldb/Host/ProcessLaunchInfo.h" #include "lldb/Host/ProcessRunLock.h" -#include "lldb/Interpreter/Options.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Target/ExecutionContextScope.h" #include "lldb/Target/InstrumentationRuntime.h" #include "lldb/Target/Memory.h" +#include "lldb/Target/MemoryTagManager.h" #include "lldb/Target/QueueList.h" #include "lldb/Target/ThreadList.h" #include "lldb/Target/ThreadPlanStack.h" +#include "lldb/Target/Trace.h" #include "lldb/Utility/ArchSpec.h" #include "lldb/Utility/Broadcaster.h" #include "lldb/Utility/Event.h" @@ -46,7 +47,8 @@ #include "lldb/Utility/ProcessInfo.h" #include "lldb/Utility/Status.h" #include "lldb/Utility/StructuredData.h" -#include "lldb/Utility/TraceOptions.h" +#include "lldb/Utility/TraceGDBRemotePackets.h" +#include "lldb/Utility/UnimplementedError.h" #include "lldb/Utility/UserIDResolver.h" #include "lldb/lldb-private.h" @@ -76,6 +78,8 @@ public: Args GetExtraStartupCommands() const; void SetExtraStartupCommands(const Args &args); FileSpec GetPythonOSPluginPath() const; + uint32_t GetVirtualAddressableBits() const; + void SetVirtualAddressableBits(uint32_t bits); void SetPythonOSPluginPath(const FileSpec &file); bool GetIgnoreBreakpointsInExpressions() const; void SetIgnoreBreakpointsInExpressions(bool ignore); @@ -83,14 +87,18 @@ public: void SetUnwindOnErrorInExpressions(bool ignore); bool GetStopOnSharedLibraryEvents() const; void SetStopOnSharedLibraryEvents(bool stop); + bool GetDisableLangRuntimeUnwindPlans() const; + void SetDisableLangRuntimeUnwindPlans(bool disable); bool GetDetachKeepsStopped() const; void SetDetachKeepsStopped(bool keep_stopped); bool GetWarningsOptimization() const; bool GetWarningsUnsupportedLanguage() const; bool GetStopOnExec() const; std::chrono::seconds GetUtilityExpressionTimeout() const; + std::chrono::seconds GetInterruptTimeout() const; bool GetOSPluginReportsAllThreads() const; void SetOSPluginReportsAllThreads(bool does_report); + bool GetSteppingRunsAllThreads() const; protected: Process *m_process; // Can be nullptr for global ProcessProperties @@ -107,9 +115,7 @@ class ProcessAttachInfo : public ProcessInstanceInfo { public: ProcessAttachInfo() : ProcessInstanceInfo(), m_listener_sp(), m_hijack_listener_sp(), - m_plugin_name(), m_resume_count(0), m_wait_for_launch(false), - m_ignore_existing(true), m_continue_once_attached(false), - m_detach_on_error(true), m_async(false) {} + m_plugin_name() {} ProcessAttachInfo(const ProcessLaunchInfo &launch_info) : ProcessInstanceInfo(), m_listener_sp(), m_hijack_listener_sp(), @@ -194,43 +200,19 @@ protected: lldb::ListenerSP m_listener_sp; lldb::ListenerSP m_hijack_listener_sp; std::string m_plugin_name; - uint32_t m_resume_count; // How many times do we resume after launching - bool m_wait_for_launch; - bool m_ignore_existing; - bool m_continue_once_attached; // Supports the use-case scenario of - // immediately continuing the process once - // attached. - bool m_detach_on_error; // If we are debugging remotely, instruct the stub to - // detach rather than killing the target on error. - bool m_async; // Use an async attach where we start the attach and return - // immediately (used by GUI programs with --waitfor so they can - // call SBProcess::Stop() to cancel attach) -}; - -class ProcessLaunchCommandOptions : public Options { -public: - ProcessLaunchCommandOptions() : Options() { - // Keep default values of all options in one place: OptionParsingStarting - // () - OptionParsingStarting(nullptr); - } - - ~ProcessLaunchCommandOptions() override = default; - - Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, - ExecutionContext *execution_context) override; - - void OptionParsingStarting(ExecutionContext *execution_context) override { - launch_info.Clear(); - disable_aslr = eLazyBoolCalculate; - } - - llvm::ArrayRef GetDefinitions() override; - - // Instance variables to hold the values for command options. - - ProcessLaunchInfo launch_info; - lldb_private::LazyBool disable_aslr; + uint32_t m_resume_count = 0; // How many times do we resume after launching + bool m_wait_for_launch = false; + bool m_ignore_existing = true; + bool m_continue_once_attached = false; // Supports the use-case scenario of + // immediately continuing the process + // once attached. + bool m_detach_on_error = + true; // If we are debugging remotely, instruct the stub to + // detach rather than killing the target on error. + bool m_async = + false; // Use an async attach where we start the attach and return + // immediately (used by GUI programs with --waitfor so they can + // call SBProcess::Stop() to cancel attach) }; // This class tracks the Modification state of the process. Things that can @@ -242,10 +224,7 @@ class ProcessModID { friend bool operator==(const ProcessModID &lhs, const ProcessModID &rhs); public: - ProcessModID() - : m_stop_id(0), m_last_natural_stop_id(0), m_resume_id(0), m_memory_id(0), - m_last_user_expression_resume(0), m_running_user_expression(false), - m_running_utility_function(0) {} + ProcessModID() = default; ProcessModID(const ProcessModID &rhs) : m_stop_id(rhs.m_stop_id), m_memory_id(rhs.m_memory_id) {} @@ -326,7 +305,7 @@ public: } void SetStopEventForLastNaturalStopID(lldb::EventSP event_sp) { - m_last_natural_stop_event = event_sp; + m_last_natural_stop_event = std::move(event_sp); } lldb::EventSP GetStopEventForStopID(uint32_t stop_id) const { @@ -336,13 +315,13 @@ public: } private: - uint32_t m_stop_id; - uint32_t m_last_natural_stop_id; - uint32_t m_resume_id; - uint32_t m_memory_id; - uint32_t m_last_user_expression_resume; - uint32_t m_running_user_expression; - uint32_t m_running_utility_function; + uint32_t m_stop_id = 0; + uint32_t m_last_natural_stop_id = 0; + uint32_t m_resume_id = 0; + uint32_t m_memory_id = 0; + uint32_t m_last_user_expression_resume = 0; + uint32_t m_running_user_expression = false; + uint32_t m_running_utility_function = 0; lldb::EventSP m_last_natural_stop_event; }; @@ -361,7 +340,6 @@ inline bool operator!=(const ProcessModID &lhs, const ProcessModID &rhs) { /// A plug-in interface definition class for debugging a process. class Process : public std::enable_shared_from_this, public ProcessProperties, - public UserID, public Broadcaster, public ExecutionContextScope, public PluginInterface { @@ -492,12 +470,12 @@ public: } lldb::ProcessWP m_process_wp; - lldb::StateType m_state; + lldb::StateType m_state = lldb::eStateInvalid; std::vector m_restarted_reasons; - bool m_restarted; // For "eStateStopped" events, this is true if the target - // was automatically restarted. - int m_update_state; - bool m_interrupted; + bool m_restarted = false; // For "eStateStopped" events, this is true if the + // target was automatically restarted. + int m_update_state = 0; + bool m_interrupted = false; ProcessEventData(const ProcessEventData &) = delete; const ProcessEventData &operator=(const ProcessEventData &) = delete; @@ -535,7 +513,8 @@ public: static lldb::ProcessSP FindPlugin(lldb::TargetSP target_sp, llvm::StringRef plugin_name, lldb::ListenerSP listener_sp, - const FileSpec *crash_file_path); + const FileSpec *crash_file_path, + bool can_connect); /// Static function that can be used with the \b host function /// Host::StartMonitoringChildProcess (). @@ -557,6 +536,15 @@ public: uint32_t GetAddressByteSize() const; + /// Sets the stored pid. + /// + /// This does not change the pid of underlying process. + lldb::pid_t GetID() const { return m_pid; } + + /// Returns the pid of the process or LLDB_INVALID_PROCESS_ID if there is + /// no known pid. + void SetID(lldb::pid_t new_pid) { m_pid = new_pid; } + uint32_t GetUniqueID() const { return m_process_unique_id; } /// Check if a plug-in instance can debug the file in \a module. @@ -582,7 +570,7 @@ public: /// \return /// Returns \b true if this Process has not been finalized /// and \b false otherwise. - bool IsValid() const { return !m_finalize_called; } + bool IsValid() const { return !m_finalizing; } /// Return a multi-word command object that can be used to expose plug-in /// specific commands. @@ -727,11 +715,6 @@ public: /// Attach to a remote system via a URL /// - /// \param[in] strm - /// A stream where output intended for the user - /// (if the driver has a way to display that) generated during - /// the connection. This may be nullptr if no output is needed.A - /// /// \param[in] remote_url /// The URL format that we are connecting to. /// @@ -743,6 +726,12 @@ public: void SetShouldDetach(bool b) { m_should_detach = b; } + /// Get the image vector for the current process. + /// + /// \return + /// The constant reference to the member m_image_tokens. + const std::vector& GetImageTokens() { return m_image_tokens; } + /// Get the image information address for the current process. /// /// Some runtimes have system functions that can help dynamic loaders locate @@ -915,11 +904,6 @@ public: /// Attach to a remote system via a URL /// - /// \param[in] strm - /// A stream where output intended for the user - /// (if the driver has a way to display that) generated during - /// the connection. This may be nullptr if no output is needed.A - /// /// \param[in] remote_url /// The URL format that we are connecting to. /// @@ -1347,6 +1331,17 @@ public: virtual void DidExit() {} + lldb::addr_t GetCodeAddressMask(); + lldb::addr_t GetDataAddressMask(); + + void SetCodeAddressMask(lldb::addr_t code_address_mask) { + m_code_address_mask = code_address_mask; + } + + void SetDataAddressMask(lldb::addr_t data_address_mask) { + m_data_address_mask = data_address_mask; + } + /// Get the Modification ID of the process. /// /// \return @@ -1393,6 +1388,8 @@ public: /// otherwise. virtual bool IsAlive(); + virtual bool IsLiveDebugSession() const { return true; }; + /// Before lldb detaches from a process, it warns the user that they are /// about to lose their debug session. In some cases, this warning doesn't /// need to be emitted -- for instance, with core file debugging where the @@ -1404,35 +1401,6 @@ public: /// this process. virtual bool WarnBeforeDetach() const { return true; } - /// Actually do the reading of memory from a process. - /// - /// Subclasses must override this function and can return fewer bytes than - /// requested when memory requests are too large. This class will break up - /// the memory requests and keep advancing the arguments along as needed. - /// - /// \param[in] vm_addr - /// A virtual load address that indicates where to start reading - /// memory from. - /// - /// \param[in] size - /// The number of bytes to read. - /// - /// \param[out] buf - /// A byte buffer that is at least \a size bytes long that - /// will receive the memory bytes. - /// - /// \param[out] error - /// An error that indicates the success or failure of this - /// operation. If error indicates success (error.Success()), - /// then the value returned can be trusted, otherwise zero - /// will be returned. - /// - /// \return - /// The number of bytes that were actually read into \a buf. - /// Zero is returned in the case of an error. - virtual size_t DoReadMemory(lldb::addr_t vm_addr, void *buf, size_t size, - Status &error) = 0; - /// Read of memory from a process. /// /// This function will read memory from the current process's address space @@ -1741,6 +1709,57 @@ public: lldb::addr_t CallocateMemory(size_t size, uint32_t permissions, Status &error); + /// If this architecture and process supports memory tagging, return a tag + /// manager that can be used to maniupulate those memory tags. + /// + /// \return + /// Either a valid pointer to a tag manager or an error describing why one + /// could not be provided. + llvm::Expected GetMemoryTagManager(); + + /// Read memory tags for the range addr to addr+len. It is assumed + /// that this range has already been granule aligned. + /// (see MemoryTagManager::MakeTaggedRange) + /// + /// This calls DoReadMemoryTags to do the target specific operations. + /// + /// \param[in] addr + /// Start of memory range to read tags for. + /// + /// \param[in] len + /// Length of memory range to read tags for (in bytes). + /// + /// \return + /// If this architecture or process does not support memory tagging, + /// an error saying so. + /// If it does, either the memory tags or an error describing a + /// failure to read or unpack them. + llvm::Expected> ReadMemoryTags(lldb::addr_t addr, + size_t len); + + /// Write memory tags for a range of memory. + /// (calls DoWriteMemoryTags to do the target specific work) + /// + /// \param[in] addr + /// The address to start writing tags from. It is assumed that this + /// address is granule aligned. + /// + /// \param[in] len + /// The size of the range to write tags for. It is assumed that this + /// is some multiple of the granule size. This len can be different + /// from (number of tags * granule size) in the case where you want + /// lldb-server to repeat tags across the range. + /// + /// \param[in] tags + /// Allocation tags to be written. Since lldb-server can repeat tags for a + /// range, the number of tags doesn't have to match the number of granules + /// in the range. (though most of the time it will) + /// + /// \return + /// A Status telling you if the write succeeded or not. + Status WriteMemoryTags(lldb::addr_t addr, size_t len, + const std::vector &tags); + /// Resolve dynamically loaded indirect functions. /// /// \param[in] address @@ -2060,8 +2079,17 @@ public: virtual Status DisableWatchpoint(Watchpoint *wp, bool notify = true); // Thread Queries - virtual bool UpdateThreadList(ThreadList &old_thread_list, - ThreadList &new_thread_list) = 0; + + /// Update the thread list. + /// + /// This method performs some general clean up before invoking + /// \a DoUpdateThreadList, which should be implemented by each + /// process plugin. + /// + /// \return + /// \b true if the new thread list could be generated, \b false otherwise. + bool UpdateThreadList(ThreadList &old_thread_list, + ThreadList &new_thread_list); void UpdateThreadListIfNeeded(); @@ -2163,7 +2191,7 @@ public: public: ProcessEventHijacker(Process &process, lldb::ListenerSP listener_sp) : m_process(process) { - m_process.HijackProcessEvents(listener_sp); + m_process.HijackProcessEvents(std::move(listener_sp)); } ~ProcessEventHijacker() { m_process.RestoreProcessEvents(); } @@ -2238,7 +2266,7 @@ void PruneThreadPlans(); /// Dump the thread plans associated with thread with \a tid. /// - /// \param[in/out] strm + /// \param[in,out] strm /// The stream to which to dump the output /// /// \param[in] tid @@ -2265,7 +2293,7 @@ void PruneThreadPlans(); /// Dump all the thread plans for this process. /// - /// \param[in/out] strm + /// \param[in,out] strm /// The stream to which to dump the output /// /// \param[in] desc_level @@ -2492,57 +2520,66 @@ void PruneThreadPlans(); lldb::StructuredDataPluginSP GetStructuredDataPlugin(ConstString type_name) const; - /// Starts tracing with the configuration provided in options. To enable - /// tracing on the complete process the thread_id in the options should be - /// set to LLDB_INVALID_THREAD_ID. The API returns a user_id which is needed - /// by other API's that manipulate the trace instance. The handling of - /// erroneous or unsupported configuration is left to the trace technology - /// implementations in the server, as they could be returned as an error, or - /// rounded to a valid configuration to start tracing. In the later case the - /// GetTraceConfig should supply the actual used trace configuration. - virtual lldb::user_id_t StartTrace(const TraceOptions &options, - Status &error) { - error.SetErrorString("Not implemented"); - return LLDB_INVALID_UID; - } - - /// Stops the tracing instance leading to deletion of the trace data. The - /// tracing instance is identified by the user_id which is obtained when - /// tracing was started from the StartTrace. In case tracing of the complete - /// process needs to be stopped the thread_id should be set to - /// LLDB_INVALID_THREAD_ID. In the other case that tracing on an individual - /// thread needs to be stopped a thread_id can be supplied. - virtual Status StopTrace(lldb::user_id_t uid, lldb::tid_t thread_id) { - return Status("Not implemented"); - } - - /// Provides the trace data as raw bytes. A buffer needs to be supplied to - /// copy the trace data. The exact behavior of this API may vary across - /// trace technology, as some may support partial reading of the trace data - /// from a specified offset while some may not. The thread_id should be used - /// to select a particular thread for trace extraction. - virtual Status GetData(lldb::user_id_t uid, lldb::tid_t thread_id, - llvm::MutableArrayRef &buffer, - size_t offset = 0) { - return Status("Not implemented"); - } - - /// Similar API as above except for obtaining meta data - virtual Status GetMetaData(lldb::user_id_t uid, lldb::tid_t thread_id, - llvm::MutableArrayRef &buffer, - size_t offset = 0) { - return Status("Not implemented"); - } - - /// API to obtain the trace configuration used by a trace instance. - /// Configurations that may be specific to some trace technology should be - /// stored in the custom parameters. The options are transported to the - /// server, which shall interpret accordingly. The thread_id can be - /// specified in the options to obtain the configuration used by a specific - /// thread. The thread_id specified should also match the uid otherwise an - /// error will be returned. - virtual Status GetTraceConfig(lldb::user_id_t uid, TraceOptions &options) { - return Status("Not implemented"); +protected: + friend class Trace; + /// Get the processor tracing type supported for this process. + /// Responses might be different depending on the architecture and + /// capabilities of the underlying OS. + /// + /// \return + /// The supported trace type or an \a llvm::Error if tracing is + /// not supported for the inferior. + virtual llvm::Expected TraceSupported(); + + /// Start tracing a process or its threads. + /// + /// \param[in] request + /// JSON object with the information necessary to start tracing. In the + /// case of gdb-remote processes, this JSON object should conform to the + /// jLLDBTraceStart packet. + /// + /// \return + /// \a llvm::Error::success if the operation was successful, or + /// \a llvm::Error otherwise. + virtual llvm::Error TraceStart(const llvm::json::Value &request) { + return llvm::make_error(); + } + + /// Stop tracing a live process or its threads. + /// + /// \param[in] request + /// The information determining which threads or process to stop tracing. + /// + /// \return + /// \a llvm::Error::success if the operation was successful, or + /// \a llvm::Error otherwise. + virtual llvm::Error TraceStop(const TraceStopRequest &request) { + return llvm::make_error(); + } + + /// Get the current tracing state of the process and its threads. + /// + /// \param[in] type + /// Tracing technology type to consider. + /// + /// \return + /// A JSON object string with custom data depending on the trace + /// technology, or an \a llvm::Error in case of errors. + virtual llvm::Expected TraceGetState(llvm::StringRef type) { + return llvm::make_error(); + } + + /// Get binary data given a trace technology and a data identifier. + /// + /// \param[in] request + /// Object with the params of the requested data. + /// + /// \return + /// A vector of bytes with the requested data, or an \a llvm::Error in + /// case of failures. + virtual llvm::Expected> + TraceGetBinaryData(const TraceGetBinaryDataRequest &request) { + return llvm::make_error(); } // This calls a function of the form "void * (*)(void)". @@ -2550,8 +2587,43 @@ void PruneThreadPlans(); lldb::addr_t &returned_func, bool trap_exceptions = false); -protected: - void SetState(lldb::EventSP &event_sp); + /// Update the thread list following process plug-in's specific logic. + /// + /// This method should only be invoked by \a UpdateThreadList. + /// + /// \return + /// \b true if the new thread list could be generated, \b false otherwise. + virtual bool DoUpdateThreadList(ThreadList &old_thread_list, + ThreadList &new_thread_list) = 0; + + /// Actually do the reading of memory from a process. + /// + /// Subclasses must override this function and can return fewer bytes than + /// requested when memory requests are too large. This class will break up + /// the memory requests and keep advancing the arguments along as needed. + /// + /// \param[in] vm_addr + /// A virtual load address that indicates where to start reading + /// memory from. + /// + /// \param[in] size + /// The number of bytes to read. + /// + /// \param[out] buf + /// A byte buffer that is at least \a size bytes long that + /// will receive the memory bytes. + /// + /// \param[out] error + /// An error that indicates the success or failure of this + /// operation. If error indicates success (error.Success()), + /// then the value returned can be trusted, otherwise zero + /// will be returned. + /// + /// \return + /// The number of bytes that were actually read into \a buf. + /// Zero is returned in the case of an error. + virtual size_t DoReadMemory(lldb::addr_t vm_addr, void *buf, size_t size, + Status &error) = 0; lldb::StateType GetPrivateState(); @@ -2698,6 +2770,60 @@ protected: /// false. bool RouteAsyncStructuredData(const StructuredData::ObjectSP object_sp); + /// Check whether the process supports memory tagging. + /// + /// \return + /// true if the process supports memory tagging, + /// false otherwise. + virtual bool SupportsMemoryTagging() { return false; } + + /// Does the final operation to read memory tags. E.g. sending a GDB packet. + /// It assumes that ReadMemoryTags has checked that memory tagging is enabled + /// and has expanded the memory range as needed. + /// + /// \param[in] addr + /// Start of address range to read memory tags for. + /// + /// \param[in] len + /// Length of the memory range to read tags for (in bytes). + /// + /// \param[in] type + /// Type of tags to read (get this from a MemoryTagManager) + /// + /// \return + /// The packed tag data received from the remote or an error + /// if the read failed. + virtual llvm::Expected> + DoReadMemoryTags(lldb::addr_t addr, size_t len, int32_t type) { + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "%s does not support reading memory tags", + GetPluginName().GetCString()); + } + + /// Does the final operation to write memory tags. E.g. sending a GDB packet. + /// It assumes that WriteMemoryTags has checked that memory tagging is enabled + /// and has packed the tag data. + /// + /// \param[in] addr + /// Start of address range to write memory tags for. + /// + /// \param[in] len + /// Length of the memory range to write tags for (in bytes). + /// + /// \param[in] type + /// Type of tags to read (get this from a MemoryTagManager) + /// + /// \param[in] tags + /// Packed tags to be written. + /// + /// \return + /// Status telling you whether the write succeeded. + virtual Status DoWriteMemoryTags(lldb::addr_t addr, size_t len, int32_t type, + const std::vector &tags) { + return Status("%s does not support writing memory tags", + GetPluginName().GetCString()); + } + // Type definitions typedef std::map LanguageRuntimeCollection; @@ -2720,6 +2846,7 @@ protected: // Member variables std::weak_ptr m_target_wp; ///< The target that owns this process. + lldb::pid_t m_pid = LLDB_INVALID_PROCESS_ID; ThreadSafeValue m_public_state; ThreadSafeValue m_private_state; // The actual state of our process @@ -2811,10 +2938,19 @@ protected: // m_currently_handling_do_on_removals are true, // Resume will only request a resume, using this // flag to check. - bool m_finalizing; // This is set at the beginning of Process::Finalize() to - // stop functions from looking up or creating things - // during a finalize call - bool m_finalize_called; // This is set at the end of Process::Finalize() + + /// This is set at the beginning of Process::Finalize() to stop functions + /// from looking up or creating things during or after a finalize call. + std::atomic m_finalizing; + + /// Mask for code an data addresses. The default value (0) means no mask is + /// set. The bits set to 1 indicate bits that are NOT significant for + /// addressing. + /// @{ + lldb::addr_t m_code_address_mask = 0; + lldb::addr_t m_data_address_mask = 0; + /// @} + bool m_clear_thread_plans_on_stop; bool m_force_next_event_delivery; lldb::StateType m_last_broadcast_state; /// This helps with the Public event @@ -2918,6 +3054,8 @@ protected: void LoadOperatingSystemPlugin(bool flush); private: + Status DestroyImpl(bool force_kill); + /// This is the part of the event handling that for a process event. It /// decides what to do with the event and returns true if the event needs to /// be propagated to the user, and false otherwise. If the event is not diff --git a/gnu/llvm/lldb/include/lldb/Target/ProcessTrace.h b/gnu/llvm/lldb/include/lldb/Target/ProcessTrace.h new file mode 100644 index 00000000000..7b9d6b13dd6 --- /dev/null +++ b/gnu/llvm/lldb/include/lldb/Target/ProcessTrace.h @@ -0,0 +1,86 @@ +//===-- ProcessTrace.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_TARGET_PROCESSTRACE_H +#define LLDB_TARGET_PROCESSTRACE_H + +#include "lldb/Target/PostMortemProcess.h" +#include "lldb/Utility/ConstString.h" +#include "lldb/Utility/Status.h" + +namespace lldb_private { + +/// Class that represents a defunct process loaded on memory via the "trace +/// load" command. +class ProcessTrace : public PostMortemProcess { +public: + static void Initialize(); + + static void Terminate(); + + static ConstString GetPluginNameStatic(); + + static const char *GetPluginDescriptionStatic(); + + ProcessTrace(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp); + + ~ProcessTrace() override; + + bool CanDebug(lldb::TargetSP target_sp, + bool plugin_specified_by_name) override; + + void DidAttach(ArchSpec &process_arch) override; + + DynamicLoader *GetDynamicLoader() override { return nullptr; } + + SystemRuntime *GetSystemRuntime() override { return nullptr; } + + ConstString GetPluginName() override; + + uint32_t GetPluginVersion() override; + + Status DoDestroy() override; + + void RefreshStateAfterStop() override; + + Status WillResume() override { + Status error; + error.SetErrorStringWithFormat( + "error: %s does not support resuming processes", + GetPluginName().GetCString()); + return error; + } + + bool WarnBeforeDetach() const override { return false; } + + size_t ReadMemory(lldb::addr_t addr, void *buf, size_t size, + Status &error) override; + + size_t DoReadMemory(lldb::addr_t addr, void *buf, size_t size, + Status &error) override; + + ArchSpec GetArchitecture(); + + bool GetProcessInfo(ProcessInstanceInfo &info) override; + +protected: + void Clear(); + + bool DoUpdateThreadList(ThreadList &old_thread_list, + ThreadList &new_thread_list) override; + +private: + static lldb::ProcessSP CreateInstance(lldb::TargetSP target_sp, + lldb::ListenerSP listener_sp, + const FileSpec *crash_file_path, + bool can_connect); +}; + +} // namespace lldb_private + +#endif // LLDB_TARGET_PROCESSTRACE_H diff --git a/gnu/llvm/lldb/include/lldb/Target/RegisterCheckpoint.h b/gnu/llvm/lldb/include/lldb/Target/RegisterCheckpoint.h index d2bcc614f58..daf20db999b 100644 --- a/gnu/llvm/lldb/include/lldb/Target/RegisterCheckpoint.h +++ b/gnu/llvm/lldb/include/lldb/Target/RegisterCheckpoint.h @@ -34,7 +34,7 @@ public: RegisterCheckpoint(Reason reason) : UserID(0), m_data_sp(), m_reason(reason) {} - ~RegisterCheckpoint() {} + ~RegisterCheckpoint() = default; lldb::DataBufferSP &GetData() { return m_data_sp; } diff --git a/gnu/llvm/lldb/include/lldb/Target/RegisterContext.h b/gnu/llvm/lldb/include/lldb/Target/RegisterContext.h index 5e795e59f94..c5068feedd5 100644 --- a/gnu/llvm/lldb/include/lldb/Target/RegisterContext.h +++ b/gnu/llvm/lldb/include/lldb/Target/RegisterContext.h @@ -148,6 +148,31 @@ public: uint64_t GetPC(uint64_t fail_value = LLDB_INVALID_ADDRESS); + /// Get an address suitable for symbolication. + /// When symbolicating -- computing line, block, function -- + /// for a function in the middle of the stack, using the return + /// address can lead to unexpected results for the user. + /// A function that ends in a tail-call may have another function + /// as the "return" address, but it will never actually return. + /// Or a noreturn call in the middle of a function is the end of + /// a block of instructions, and a DWARF location list entry for + /// the return address may be a very different code path with + /// incorrect results when printing variables for this frame. + /// + /// At a source line view, the user expects the current-line indictation + /// to point to the function call they're under, not the next source line. + /// + /// The return address (GetPC()) should always be shown to the user, + /// but when computing context, keeping within the bounds of the + /// call instruction is what the user expects to see. + /// + /// \param [out] address + /// An Address object that will be filled in, if a PC can be retrieved. + /// + /// \return + /// Returns true if the Address param was filled in. + bool GetPCForSymbolication(Address &address); + bool SetPC(uint64_t pc); bool SetPC(Address addr); @@ -196,6 +221,19 @@ public: void SetStopID(uint32_t stop_id) { m_stop_id = stop_id; } protected: + /// Indicates that this frame is currently executing code, + /// that the PC value is not a return-pc but an actual executing + /// instruction. Some places in lldb will treat a return-pc + /// value differently than the currently-executing-pc value, + /// and this method can indicate if that should be done. + /// The base class implementation only uses the frame index, + /// but subclasses may have additional information that they + /// can use to detect frames in this state, for instance a + /// frame above a trap handler (sigtramp etc).. + virtual bool BehavesLikeZerothFrame() const { + return m_concrete_frame_idx == 0; + } + // Classes that inherit from RegisterContext can see and modify these Thread &m_thread; // The thread that this register context belongs to. uint32_t m_concrete_frame_idx; // The concrete frame index for this register diff --git a/gnu/llvm/lldb/include/lldb/Target/RegisterContextUnwind.h b/gnu/llvm/lldb/include/lldb/Target/RegisterContextUnwind.h index fa96c3e42c7..edda281d5aa 100644 --- a/gnu/llvm/lldb/include/lldb/Target/RegisterContextUnwind.h +++ b/gnu/llvm/lldb/include/lldb/Target/RegisterContextUnwind.h @@ -67,6 +67,11 @@ public: bool ReadPC(lldb::addr_t &start_pc); + // Indicates whether this frame *behaves* like frame zero -- the currently + // executing frame -- or not. This can be true in the middle of the stack + // above asynchronous trap handlers (sigtramp) for instance. + bool BehavesLikeZerothFrame() const override; + private: enum FrameType { eNormalFrame, @@ -228,14 +233,16 @@ private: // unknown // 0 if no instructions have been executed yet. - int m_current_offset_backed_up_one; // how far into the function we've - // executed; -1 if unknown // 0 if no instructions have been executed yet. // On architectures where the return address on the stack points // to the instruction after the CALL, this value will have 1 // subtracted from it. Else a function that ends in a CALL will // have an offset pointing into the next function's address range. // m_current_pc has the actual address of the "current" pc. + int m_current_offset_backed_up_one; // how far into the function we've + // executed; -1 if unknown + + bool m_behaves_like_zeroth_frame; // this frame behaves like frame zero lldb_private::SymbolContext &m_sym_ctx; bool m_sym_ctx_valid; // if ResolveSymbolContextForAddress fails, don't try to diff --git a/gnu/llvm/lldb/include/lldb/Target/RegisterNumber.h b/gnu/llvm/lldb/include/lldb/Target/RegisterNumber.h index 362812bcffd..90f95319896 100644 --- a/gnu/llvm/lldb/include/lldb/Target/RegisterNumber.h +++ b/gnu/llvm/lldb/include/lldb/Target/RegisterNumber.h @@ -50,10 +50,10 @@ private: typedef std::map Collection; lldb::RegisterContextSP m_reg_ctx_sp; - uint32_t m_regnum; - lldb::RegisterKind m_kind; + uint32_t m_regnum = LLDB_INVALID_REGNUM; + lldb::RegisterKind m_kind = lldb::kNumRegisterKinds; Collection m_kind_regnum_map; - const char *m_name; + const char *m_name = nullptr; }; #endif // LLDB_TARGET_REGISTERNUMBER_H diff --git a/gnu/llvm/lldb/include/lldb/Target/RemoteAwarePlatform.h b/gnu/llvm/lldb/include/lldb/Target/RemoteAwarePlatform.h index 5741dbe027b..269d1529988 100644 --- a/gnu/llvm/lldb/include/lldb/Target/RemoteAwarePlatform.h +++ b/gnu/llvm/lldb/include/lldb/Target/RemoteAwarePlatform.h @@ -68,11 +68,16 @@ public: bool GetRemoteOSKernelDescription(std::string &s) override; ArchSpec GetRemoteSystemArchitecture() override; - Status RunShellCommand(const char *command, const FileSpec &working_dir, + Status RunShellCommand(llvm::StringRef command, const FileSpec &working_dir, int *status_ptr, int *signo_ptr, std::string *command_output, const Timeout &timeout) override; + Status RunShellCommand(llvm::StringRef interpreter, llvm::StringRef command, + const FileSpec &working_dir, int *status_ptr, + int *signo_ptr, std::string *command_output, + const Timeout &timeout) override; + const char *GetHostname() override; UserIDResolver &GetUserIDResolver() override; lldb_private::Environment GetEnvironment() override; @@ -92,6 +97,9 @@ public: Status KillProcess(const lldb::pid_t pid) override; + size_t ConnectToWaitingProcesses(Debugger &debugger, + Status &error) override; + protected: lldb::PlatformSP m_remote_platform_sp; }; diff --git a/gnu/llvm/lldb/include/lldb/Target/Runtime.h b/gnu/llvm/lldb/include/lldb/Target/Runtime.h new file mode 100644 index 00000000000..06f0b610e40 --- /dev/null +++ b/gnu/llvm/lldb/include/lldb/Target/Runtime.h @@ -0,0 +1,33 @@ +//===-- Runtime.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_TARGET_RUNTIME_H +#define LLDB_TARGET_RUNTIME_H + +#include "lldb/Target/Process.h" + +namespace lldb_private { +class Runtime { +public: + Runtime(Process *process) : m_process(process) {} + virtual ~Runtime() = default; + Runtime(const Runtime &) = delete; + const Runtime &operator=(const Runtime &) = delete; + + Process *GetProcess() { return m_process; } + Target &GetTargetRef() { return m_process->GetTarget(); } + + /// Called when modules have been loaded in the process. + virtual void ModulesDidLoad(const ModuleList &module_list) = 0; + +protected: + Process *m_process; +}; +} // namespace lldb_private + +#endif // LLDB_TARGET_RUNTIME_H diff --git a/gnu/llvm/lldb/include/lldb/Target/StackFrame.h b/gnu/llvm/lldb/include/lldb/Target/StackFrame.h index 905c56c9126..1a9aaad1a4d 100644 --- a/gnu/llvm/lldb/include/lldb/Target/StackFrame.h +++ b/gnu/llvm/lldb/include/lldb/Target/StackFrame.h @@ -134,6 +134,24 @@ public: /// The Address object set to the current PC value. const Address &GetFrameCodeAddress(); + /// Get the current code Address suitable for symbolication, + /// may not be the same as GetFrameCodeAddress(). + /// + /// For a frame in the middle of the stack, the return-pc is the + /// current code address, but for symbolication purposes the + /// return address after a noreturn call may point to the next + /// function, a DWARF location list entry that is a completely + /// different code path, or the wrong source line. + /// + /// The address returned should be used for symbolication (source line, + /// block, function, DWARF location entry selection) but should NOT + /// be shown to the user. It may not point to an actual instruction + /// boundary. + /// + /// \return + /// The Address object set to the current PC value. + Address GetFrameCodeAddressForSymbolication(); + /// Change the pc value for a given thread. /// /// Change the current pc value for the frame on this thread. @@ -404,22 +422,6 @@ public: GetValueObjectForFrameVariable(const lldb::VariableSP &variable_sp, lldb::DynamicValueType use_dynamic); - /// Add an arbitrary Variable object (e.g. one that specifics a global or - /// static) to a StackFrame's list of ValueObjects. - /// - /// \params [in] variable_sp - /// The Variable to base this ValueObject on - /// - /// \params [in] use_dynamic - /// Whether the correct dynamic type of the variable should be - /// determined before creating the ValueObject, or if the static type - /// is sufficient. One of the DynamicValueType enumerated values. - /// - /// \return - /// A ValueObject for this variable. - lldb::ValueObjectSP TrackGlobalVariable(const lldb::VariableSP &variable_sp, - lldb::DynamicValueType use_dynamic); - /// Query this frame to determine what the default language should be when /// parsing expressions given the execution context. /// diff --git a/gnu/llvm/lldb/include/lldb/Target/StackFrameList.h b/gnu/llvm/lldb/include/lldb/Target/StackFrameList.h index 1b0b986d705..c98995cad36 100644 --- a/gnu/llvm/lldb/include/lldb/Target/StackFrameList.h +++ b/gnu/llvm/lldb/include/lldb/Target/StackFrameList.h @@ -89,9 +89,6 @@ protected: bool SetFrameAtIndex(uint32_t idx, lldb::StackFrameSP &frame_sp); - static void Merge(std::unique_ptr &curr_up, - lldb::StackFrameListSP &prev_sp); - void GetFramesUpTo(uint32_t end_idx); void GetOnlyConcreteFramesUpTo(uint32_t end_idx, Unwind &unwinder); diff --git a/gnu/llvm/lldb/include/lldb/Target/StackFrameRecognizer.h b/gnu/llvm/lldb/include/lldb/Target/StackFrameRecognizer.h index 9c9105ac04e..64be759dc79 100644 --- a/gnu/llvm/lldb/include/lldb/Target/StackFrameRecognizer.h +++ b/gnu/llvm/lldb/include/lldb/Target/StackFrameRecognizer.h @@ -17,6 +17,8 @@ #include "lldb/lldb-private-forward.h" #include "lldb/lldb-public.h" +#include + namespace lldb_private { /// \class RecognizedStackFrame @@ -35,7 +37,7 @@ public: return lldb::ValueObjectSP(); } virtual lldb::StackFrameSP GetMostRelevantFrame() { return nullptr; }; - virtual ~RecognizedStackFrame(){}; + virtual ~RecognizedStackFrame() = default; std::string GetStopDescription() { return m_stop_desc; } @@ -61,7 +63,7 @@ public: return ""; } - virtual ~StackFrameRecognizer(){}; + virtual ~StackFrameRecognizer() = default; }; /// \class ScriptedStackFrameRecognizer @@ -78,7 +80,7 @@ class ScriptedStackFrameRecognizer : public StackFrameRecognizer { public: ScriptedStackFrameRecognizer(lldb_private::ScriptInterpreter *interpreter, const char *pclass); - ~ScriptedStackFrameRecognizer() override {} + ~ScriptedStackFrameRecognizer() override = default; std::string GetName() override { return GetPythonClassName(); @@ -95,37 +97,44 @@ private: operator=(const ScriptedStackFrameRecognizer &) = delete; }; -/// \class StackFrameRecognizerManager -/// -/// Static class that provides a registry of known stack frame recognizers. -/// Has static methods to add, enumerate, remove, query and invoke recognizers. - +/// Class that provides a registry of known stack frame recognizers. class StackFrameRecognizerManager { public: - static void AddRecognizer(lldb::StackFrameRecognizerSP recognizer, - ConstString module, - llvm::ArrayRef symbols, - bool first_instruction_only = true); + void AddRecognizer(lldb::StackFrameRecognizerSP recognizer, + ConstString module, llvm::ArrayRef symbols, + bool first_instruction_only = true); + + void AddRecognizer(lldb::StackFrameRecognizerSP recognizer, + lldb::RegularExpressionSP module, + lldb::RegularExpressionSP symbol, + bool first_instruction_only = true); - static void AddRecognizer(lldb::StackFrameRecognizerSP recognizer, - lldb::RegularExpressionSP module, - lldb::RegularExpressionSP symbol, - bool first_instruction_only = true); + void ForEach(std::function< + void(uint32_t recognizer_id, std::string recognizer_name, + std::string module, llvm::ArrayRef symbols, + bool regexp)> const &callback); - static void - ForEach(std::function symbols, - bool regexp)> const &callback); + bool RemoveRecognizerWithID(uint32_t recognizer_id); - static bool RemoveRecognizerWithID(uint32_t recognizer_id); + void RemoveAllRecognizers(); - static void RemoveAllRecognizers(); + lldb::StackFrameRecognizerSP GetRecognizerForFrame(lldb::StackFrameSP frame); - static lldb::StackFrameRecognizerSP GetRecognizerForFrame( - lldb::StackFrameSP frame); + lldb::RecognizedStackFrameSP RecognizeFrame(lldb::StackFrameSP frame); - static lldb::RecognizedStackFrameSP RecognizeFrame(lldb::StackFrameSP frame); +private: + struct RegisteredEntry { + uint32_t recognizer_id; + lldb::StackFrameRecognizerSP recognizer; + bool is_regexp; + ConstString module; + lldb::RegularExpressionSP module_regexp; + std::vector symbols; + lldb::RegularExpressionSP symbol_regexp; + bool first_instruction_only; + }; + + std::deque m_recognizers; }; /// \class ValueObjectRecognizerSynthesizedValue @@ -145,7 +154,9 @@ class ValueObjectRecognizerSynthesizedValue : public ValueObject { SetName(parent.GetName()); } - uint64_t GetByteSize() override { return m_parent->GetByteSize(); } + llvm::Optional GetByteSize() override { + return m_parent->GetByteSize(); + } lldb::ValueType GetValueType() const override { return m_type; } bool UpdateValue() override { if (!m_parent->UpdateValueIfNeeded()) return false; diff --git a/gnu/llvm/lldb/include/lldb/Target/StackID.h b/gnu/llvm/lldb/include/lldb/Target/StackID.h index 827ed1be7c0..95d12df6742 100644 --- a/gnu/llvm/lldb/include/lldb/Target/StackID.h +++ b/gnu/llvm/lldb/include/lldb/Target/StackID.h @@ -18,8 +18,8 @@ class StackID { public: // Constructors and Destructors StackID() - : m_pc(LLDB_INVALID_ADDRESS), m_cfa(LLDB_INVALID_ADDRESS), - m_symbol_scope(nullptr) {} + + {} explicit StackID(lldb::addr_t pc, lldb::addr_t cfa, SymbolContextScope *symbol_scope) @@ -69,23 +69,25 @@ protected: void SetCFA(lldb::addr_t cfa) { m_cfa = cfa; } - lldb::addr_t - m_pc; // The pc value for the function/symbol for this frame. This will + lldb::addr_t m_pc = + LLDB_INVALID_ADDRESS; // The pc value for the function/symbol for this + // frame. This will // only get used if the symbol scope is nullptr (the code where we are // stopped is not represented by any function or symbol in any shared // library). - lldb::addr_t m_cfa; // The call frame address (stack pointer) value - // at the beginning of the function that uniquely - // identifies this frame (along with m_symbol_scope - // below) - SymbolContextScope * - m_symbol_scope; // If nullptr, there is no block or symbol for this frame. - // If not nullptr, this will either be the scope for the - // lexical block for the frame, or the scope for the - // symbol. Symbol context scopes are always be unique - // pointers since the are part of the Block and Symbol - // objects and can easily be used to tell if a stack ID - // is the same as another. + lldb::addr_t m_cfa = + LLDB_INVALID_ADDRESS; // The call frame address (stack pointer) value + // at the beginning of the function that uniquely + // identifies this frame (along with m_symbol_scope + // below) + SymbolContextScope *m_symbol_scope = + nullptr; // If nullptr, there is no block or symbol for this frame. + // If not nullptr, this will either be the scope for the + // lexical block for the frame, or the scope for the + // symbol. Symbol context scopes are always be unique + // pointers since the are part of the Block and Symbol + // objects and can easily be used to tell if a stack ID + // is the same as another. }; bool operator==(const StackID &lhs, const StackID &rhs); diff --git a/gnu/llvm/lldb/include/lldb/Target/StopInfo.h b/gnu/llvm/lldb/include/lldb/Target/StopInfo.h index 4378d2d6379..0e81e516084 100644 --- a/gnu/llvm/lldb/include/lldb/Target/StopInfo.h +++ b/gnu/llvm/lldb/include/lldb/Target/StopInfo.h @@ -25,7 +25,7 @@ public: // Constructors and Destructors StopInfo(Thread &thread, uint64_t value); - virtual ~StopInfo() {} + virtual ~StopInfo() = default; bool IsValid() const; @@ -129,6 +129,9 @@ public: static lldb::StopInfoSP CreateStopReasonWithExec(Thread &thread); + static lldb::StopInfoSP + CreateStopReasonProcessorTrace(Thread &thread, const char *description); + static lldb::ValueObjectSP GetReturnValueObject(lldb::StopInfoSP &stop_info_sp); diff --git a/gnu/llvm/lldb/include/lldb/Target/SystemRuntime.h b/gnu/llvm/lldb/include/lldb/Target/SystemRuntime.h index 4f07d7ab52e..0ec0793e95f 100644 --- a/gnu/llvm/lldb/include/lldb/Target/SystemRuntime.h +++ b/gnu/llvm/lldb/include/lldb/Target/SystemRuntime.h @@ -15,6 +15,7 @@ #include "lldb/Core/PluginInterface.h" #include "lldb/Target/QueueItem.h" #include "lldb/Target/QueueList.h" +#include "lldb/Target/Runtime.h" #include "lldb/Utility/ConstString.h" #include "lldb/Utility/StructuredData.h" #include "lldb/lldb-private.h" @@ -39,7 +40,7 @@ namespace lldb_private { /// can be asked to provide that information. /// -class SystemRuntime : public PluginInterface { +class SystemRuntime : public Runtime, public PluginInterface { public: /// Find a system runtime plugin for a given process. /// @@ -52,7 +53,7 @@ public: static SystemRuntime *FindPlugin(Process *process); /// Construct with a process. - SystemRuntime(lldb_private::Process *process); + SystemRuntime(Process *process); /// Destructor. /// @@ -76,7 +77,7 @@ public: /// /// Allow the SystemRuntime plugin to enable logging features in the system /// runtime libraries. - virtual void ModulesDidLoad(lldb_private::ModuleList &module_list); + virtual void ModulesDidLoad(const ModuleList &module_list) override; /// Called before detaching from a process. /// @@ -294,9 +295,6 @@ public: } protected: - // Member variables. - Process *m_process; - std::vector m_types; private: diff --git a/gnu/llvm/lldb/include/lldb/Target/Target.h b/gnu/llvm/lldb/include/lldb/Target/Target.h index 280ce6359c7..ac8d002b09a 100644 --- a/gnu/llvm/lldb/include/lldb/Target/Target.h +++ b/gnu/llvm/lldb/include/lldb/Target/Target.h @@ -28,6 +28,7 @@ #include "lldb/Target/ExecutionContextScope.h" #include "lldb/Target/PathMappingList.h" #include "lldb/Target/SectionLoadHistory.h" +#include "lldb/Target/ThreadSpec.h" #include "lldb/Utility/ArchSpec.h" #include "lldb/Utility/Broadcaster.h" #include "lldb/Utility/LLDBAssert.h" @@ -36,8 +37,6 @@ namespace lldb_private { -class ClangModulesDeclVendor; - OptionEnumValues GetDynamicValueTypes(); enum InlineStrategy { @@ -64,6 +63,12 @@ enum LoadDependentFiles { eLoadDependentsNo, }; +enum ImportStdModule { + eImportStdModuleFalse, + eImportStdModuleFallback, + eImportStdModuleTrue, +}; + class TargetExperimentalProperties : public Properties { public: TargetExperimentalProperties(); @@ -93,6 +98,10 @@ public: void SetDisableASLR(bool b); + bool GetInheritTCC() const; + + void SetInheritTCC(bool b); + bool GetDetachOnError() const; void SetDetachOnError(bool b); @@ -130,7 +139,7 @@ public: bool GetEnableAutoImportClangModules() const; - bool GetEnableImportStdModule() const; + ImportStdModule GetImportStdModule() const; bool GetEnableAutoApplyFixIts() const; @@ -168,6 +177,8 @@ public: llvm::StringRef GetExpressionPrefixContents(); + uint64_t GetExprErrorLimit() const; + bool GetUseHexImmediates() const; bool GetUseFastStepping() const; @@ -198,14 +209,14 @@ public: void SetDisplayRecognizedArguments(bool b); - const ProcessLaunchInfo &GetProcessLaunchInfo(); + const ProcessLaunchInfo &GetProcessLaunchInfo() const; void SetProcessLaunchInfo(const ProcessLaunchInfo &launch_info); bool GetInjectLocalVariables(ExecutionContext *exe_ctx) const; void SetInjectLocalVariables(ExecutionContext *exe_ctx, bool b); - + void SetRequireHardwareBreakpoints(bool b); bool GetRequireHardwareBreakpoints() const; @@ -214,6 +225,9 @@ public: void UpdateLaunchInfoFromProperties(); + void SetDebugUtilityExpression(bool debug); + + bool GetDebugUtilityExpression() const; private: // Callbacks for m_launch_info. @@ -225,6 +239,7 @@ private: void ErrorPathValueChangedCallback(); void DetachOnErrorValueChangedCallback(); void DisableASLRValueChangedCallback(); + void InheritTCCValueChangedCallback(); void DisableSTDIOValueChangedCallback(); Environment ComputeEnvironment() const; @@ -434,6 +449,7 @@ class Target : public std::enable_shared_from_this, public ModuleList::Notifier { public: friend class TargetList; + friend class Debugger; /// Broadcaster event bits definitions. enum { @@ -503,6 +519,8 @@ public: static void SetDefaultArchitecture(const ArchSpec &arch); + bool IsDummyTarget() const { return m_is_dummy_target; } + /// Find a binary on the system and return its Module, /// or return an existing Module that is already in the Target. /// @@ -563,7 +581,8 @@ public: // used. const lldb::ProcessSP &CreateProcess(lldb::ListenerSP listener_sp, llvm::StringRef plugin_name, - const FileSpec *crash_file); + const FileSpec *crash_file, + bool can_connect); const lldb::ProcessSP &GetProcessSP() const; @@ -984,11 +1003,12 @@ public: // read from const sections in object files, read from the target. This // version of ReadMemory will try and read memory from the process if the // process is alive. The order is: - // 1 - if (prefer_file_cache == true) then read from object file cache - // 2 - if there is a valid process, try and read from its memory - // 3 - if (prefer_file_cache == false) then read from object file cache - size_t ReadMemory(const Address &addr, bool prefer_file_cache, void *dst, - size_t dst_len, Status &error, + // 1 - if (force_live_memory == false) and the address falls in a read-only + // section, then read from the file cache + // 2 - if there is a process, then read from memory + // 3 - if there is no process, then read from the file cache + size_t ReadMemory(const Address &addr, void *dst, size_t dst_len, + Status &error, bool force_live_memory = false, lldb::addr_t *load_addr_ptr = nullptr); size_t ReadCStringFromMemory(const Address &addr, std::string &out_str, @@ -997,18 +1017,19 @@ public: size_t ReadCStringFromMemory(const Address &addr, char *dst, size_t dst_max_len, Status &result_error); - size_t ReadScalarIntegerFromMemory(const Address &addr, - bool prefer_file_cache, uint32_t byte_size, + size_t ReadScalarIntegerFromMemory(const Address &addr, uint32_t byte_size, bool is_signed, Scalar &scalar, - Status &error); + Status &error, + bool force_live_memory = false); uint64_t ReadUnsignedIntegerFromMemory(const Address &addr, - bool prefer_file_cache, size_t integer_byte_size, - uint64_t fail_value, Status &error); + uint64_t fail_value, Status &error, + bool force_live_memory = false); - bool ReadPointerFromMemory(const Address &addr, bool prefer_file_cache, - Status &error, Address &pointer_addr); + bool ReadPointerFromMemory(const Address &addr, Status &error, + Address &pointer_addr, + bool force_live_memory = false); SectionLoadList &GetSectionLoadList() { return m_section_load_history.GetCurrentSectionLoadList(); @@ -1064,14 +1085,10 @@ public: const ValueList &arg_value_list, const char *name, Status &error); - // Creates a UtilityFunction for the given language, the rest of the - // parameters have the same meaning as for the UtilityFunction constructor. - // Returns a new-ed object which the caller owns. - - UtilityFunction *GetUtilityFunctionForLanguage(const char *expr, - lldb::LanguageType language, - const char *name, - Status &error); + /// Creates and installs a UtilityFunction for the given language. + llvm::Expected> + CreateUtilityFunction(std::string expression, std::string name, + lldb::LanguageType language, ExecutionContext &exe_ctx); // Install any files through the platform that need be to installed prior to // launching or attaching. @@ -1097,6 +1114,32 @@ public: void ClearAllLoadedSections(); + /// Set the \a Trace object containing processor trace information of this + /// target. + /// + /// \param[in] trace_sp + /// The trace object. + void SetTrace(const lldb::TraceSP &trace_sp); + + /// Get the \a Trace object containing processor trace information of this + /// target. + /// + /// \return + /// The trace object. It might be undefined. + lldb::TraceSP GetTrace(); + + /// Create a \a Trace object for the current target using the using the + /// default supported tracing technology for this process. + /// + /// \return + /// The new \a Trace or an \a llvm::Error if a \a Trace already exists or + /// the trace couldn't be created. + llvm::Expected CreateTrace(); + + /// If a \a Trace object is present, this returns it, otherwise a new Trace is + /// created with \a Trace::CreateTrace. + llvm::Expected GetTraceOrCreate(); + // Since expressions results can persist beyond the lifetime of a process, // and the const expression results are available after a process is gone, we // provide a way for expressions to be evaluated from the Target itself. If @@ -1134,23 +1177,32 @@ public: class StopHook : public UserID { public: StopHook(const StopHook &rhs); + virtual ~StopHook() = default; - ~StopHook(); - - StringList *GetCommandPointer() { return &m_commands; } - - const StringList &GetCommands() { return m_commands; } + enum class StopHookKind : uint32_t { CommandBased = 0, ScriptBased }; + enum class StopHookResult : uint32_t { + KeepStopped = 0, + RequestContinue, + AlreadyContinued + }; lldb::TargetSP &GetTarget() { return m_target_sp; } - void SetCommands(StringList &in_commands) { m_commands = in_commands; } - // Set the specifier. The stop hook will own the specifier, and is // responsible for deleting it when we're done. void SetSpecifier(SymbolContextSpecifier *specifier); SymbolContextSpecifier *GetSpecifier() { return m_specifier_sp.get(); } + bool ExecutionContextPasses(const ExecutionContext &exe_ctx); + + // Called on stop, this gets passed the ExecutionContext for each "stop + // with a reason" thread. It should add to the stream whatever text it + // wants to show the user, and return False to indicate it wants the target + // not to stop. + virtual StopHookResult HandleStop(ExecutionContext &exe_ctx, + lldb::StreamSP output) = 0; + // Set the Thread Specifier. The stop hook will own the thread specifier, // and is responsible for deleting it when we're done. void SetThreadSpecifier(ThreadSpec *specifier); @@ -1168,28 +1220,84 @@ public: bool GetAutoContinue() const { return m_auto_continue; } void GetDescription(Stream *s, lldb::DescriptionLevel level) const; + virtual void GetSubclassDescription(Stream *s, + lldb::DescriptionLevel level) const = 0; - private: + protected: lldb::TargetSP m_target_sp; - StringList m_commands; lldb::SymbolContextSpecifierSP m_specifier_sp; std::unique_ptr m_thread_spec_up; bool m_active = true; bool m_auto_continue = false; + StopHook(lldb::TargetSP target_sp, lldb::user_id_t uid); + }; + + class StopHookCommandLine : public StopHook { + public: + virtual ~StopHookCommandLine() = default; + + StringList &GetCommands() { return m_commands; } + void SetActionFromString(const std::string &strings); + void SetActionFromStrings(const std::vector &strings); + + StopHookResult HandleStop(ExecutionContext &exc_ctx, + lldb::StreamSP output_sp) override; + void GetSubclassDescription(Stream *s, + lldb::DescriptionLevel level) const override; + + private: + StringList m_commands; // Use CreateStopHook to make a new empty stop hook. The GetCommandPointer // and fill it with commands, and SetSpecifier to set the specifier shared // pointer (can be null, that will match anything.) - StopHook(lldb::TargetSP target_sp, lldb::user_id_t uid); + StopHookCommandLine(lldb::TargetSP target_sp, lldb::user_id_t uid) + : StopHook(target_sp, uid) {} + friend class Target; + }; + + class StopHookScripted : public StopHook { + public: + virtual ~StopHookScripted() = default; + StopHookResult HandleStop(ExecutionContext &exc_ctx, + lldb::StreamSP output) override; + + Status SetScriptCallback(std::string class_name, + StructuredData::ObjectSP extra_args_sp); + + void GetSubclassDescription(Stream *s, + lldb::DescriptionLevel level) const override; + + private: + std::string m_class_name; + /// This holds the dictionary of keys & values that can be used to + /// parametrize any given callback's behavior. + StructuredDataImpl *m_extra_args; // We own this structured data, + // but the SD itself manages the UP. + /// This holds the python callback object. + StructuredData::GenericSP m_implementation_sp; + + /// Use CreateStopHook to make a new empty stop hook. The GetCommandPointer + /// and fill it with commands, and SetSpecifier to set the specifier shared + /// pointer (can be null, that will match anything.) + StopHookScripted(lldb::TargetSP target_sp, lldb::user_id_t uid) + : StopHook(target_sp, uid) {} friend class Target; }; + typedef std::shared_ptr StopHookSP; - // Add an empty stop hook to the Target's stop hook list, and returns a - // shared pointer to it in new_hook. Returns the id of the new hook. - StopHookSP CreateStopHook(); + /// Add an empty stop hook to the Target's stop hook list, and returns a + /// shared pointer to it in new_hook. Returns the id of the new hook. + StopHookSP CreateStopHook(StopHook::StopHookKind kind); + + /// If you tried to create a stop hook, and that failed, call this to + /// remove the stop hook, as it will also reset the stop hook counter. + void UndoCreateStopHook(lldb::user_id_t uid); - void RunStopHooks(); + // Runs the stop hooks that have been registered for this target. + // Returns true if the stop hooks cause the target to resume. + bool RunStopHooks(); size_t GetStopHookSize(); @@ -1233,8 +1341,6 @@ public: SourceManager &GetSourceManager(); - ClangModulesDeclVendor *GetClangModulesDeclVendor(); - // Methods. lldb::SearchFilterSP GetSearchFilterForModule(const FileSpec *containingModule); @@ -1251,6 +1357,10 @@ public: void SetREPL(lldb::LanguageType language, lldb::REPLSP repl_sp); + StackFrameRecognizerManager &GetFrameRecognizerManager() { + return *m_frame_recognizer_manager_up; + } + protected: /// Implementing of ModuleList::Notifier. @@ -1285,12 +1395,12 @@ protected: lldb::PlatformSP m_platform_sp; ///< The platform for this target. std::recursive_mutex m_mutex; ///< An API mutex that is used by the lldb::SB* /// classes make the SB interface thread safe - /// When the private state thread calls SB API's - usually because it is + /// When the private state thread calls SB API's - usually because it is /// running OS plugin or Python ThreadPlan code - it should not block on the /// API mutex that is held by the code that kicked off the sequence of events - /// that led us to run the code. We hand out this mutex instead when we + /// that led us to run the code. We hand out this mutex instead when we /// detect that code is running on the private state thread. - std::recursive_mutex m_private_mutex; + std::recursive_mutex m_private_mutex; Arch m_arch; ModuleList m_images; ///< The list of images for this process (shared /// libraries and anything dynamically loaded). @@ -1314,17 +1424,22 @@ protected: typedef std::map REPLMap; REPLMap m_repl_map; - std::unique_ptr m_clang_modules_decl_vendor_up; - lldb::SourceManagerUP m_source_manager_up; typedef std::map StopHookCollection; StopHookCollection m_stop_hooks; lldb::user_id_t m_stop_hook_next_id; + uint32_t m_latest_stop_hook_id; /// This records the last natural stop at + /// which we ran a stop-hook. bool m_valid; - bool m_suppress_stop_hooks; + bool m_suppress_stop_hooks; /// Used to not run stop hooks for expressions bool m_is_dummy_target; unsigned m_next_persistent_variable_index = 0; + /// An optional \a lldb_private::Trace object containing processor trace + /// information of this target. + lldb::TraceSP m_trace_sp; + /// Stores the frame recognizers of this target. + lldb::StackFrameRecognizerManagerUP m_frame_recognizer_manager_up; static void ImageSearchPathsChanged(const PathMappingList &path_list, void *baton); @@ -1364,7 +1479,7 @@ private: bool ProcessIsValid(); // Copy breakpoints, stop hooks and so forth from the dummy target: - void PrimeFromDummyTarget(Target *dummy_target); + void PrimeFromDummyTarget(Target &target); void AddBreakpoint(lldb::BreakpointSP breakpoint_sp, bool internal); diff --git a/gnu/llvm/lldb/include/lldb/Target/TargetList.h b/gnu/llvm/lldb/include/lldb/Target/TargetList.h index 5ed0344f175..65781a4811f 100644 --- a/gnu/llvm/lldb/include/lldb/Target/TargetList.h +++ b/gnu/llvm/lldb/include/lldb/Target/TargetList.h @@ -14,6 +14,7 @@ #include "lldb/Target/Target.h" #include "lldb/Utility/Broadcaster.h" +#include "lldb/Utility/Iterable.h" namespace lldb_private { @@ -42,7 +43,10 @@ public: return GetStaticBroadcasterClass(); } - ~TargetList() override; + typedef std::vector collection; + typedef LockingAdaptedIterable + TargetIterable; /// Create a new Target. /// @@ -175,36 +179,36 @@ public: uint32_t SignalIfRunning(lldb::pid_t pid, int signo); - uint32_t SetSelectedTarget(Target *target); + void SetSelectedTarget(uint32_t index); + + void SetSelectedTarget(const lldb::TargetSP &target); lldb::TargetSP GetSelectedTarget(); -protected: - typedef std::vector collection; - // Member variables. + TargetIterable Targets() { + return TargetIterable(m_target_list, m_target_list_mutex); + } + +private: collection m_target_list; - lldb::TargetSP m_dummy_target_sp; mutable std::recursive_mutex m_target_list_mutex; uint32_t m_selected_target_idx; -private: - lldb::TargetSP GetDummyTarget(lldb_private::Debugger &debugger); - - Status CreateDummyTarget(Debugger &debugger, - llvm::StringRef specified_arch_name, - lldb::TargetSP &target_sp); - - Status CreateTargetInternal(Debugger &debugger, llvm::StringRef user_exe_path, - llvm::StringRef triple_str, - LoadDependentFiles load_dependent_files, - const OptionGroupPlatform *platform_options, - lldb::TargetSP &target_sp, bool is_dummy_target); - - Status CreateTargetInternal(Debugger &debugger, llvm::StringRef user_exe_path, - const ArchSpec &arch, - LoadDependentFiles get_dependent_modules, - lldb::PlatformSP &platform_sp, - lldb::TargetSP &target_sp, bool is_dummy_target); + static Status CreateTargetInternal( + Debugger &debugger, llvm::StringRef user_exe_path, + llvm::StringRef triple_str, LoadDependentFiles load_dependent_files, + const OptionGroupPlatform *platform_options, lldb::TargetSP &target_sp); + + static Status CreateTargetInternal(Debugger &debugger, + llvm::StringRef user_exe_path, + const ArchSpec &arch, + LoadDependentFiles get_dependent_modules, + lldb::PlatformSP &platform_sp, + lldb::TargetSP &target_sp); + + void AddTargetInternal(lldb::TargetSP target_sp, bool do_select); + + void SetSelectedTargetInternal(uint32_t index); TargetList(const TargetList &) = delete; const TargetList &operator=(const TargetList &) = delete; diff --git a/gnu/llvm/lldb/include/lldb/Target/Thread.h b/gnu/llvm/lldb/include/lldb/Target/Thread.h index 205a0d965c6..0f6b5741573 100644 --- a/gnu/llvm/lldb/include/lldb/Target/Thread.h +++ b/gnu/llvm/lldb/include/lldb/Target/Thread.h @@ -19,6 +19,7 @@ #include "lldb/Target/RegisterCheckpoint.h" #include "lldb/Target/StackFrameList.h" #include "lldb/Utility/Broadcaster.h" +#include "lldb/Utility/CompletionRequest.h" #include "lldb/Utility/Event.h" #include "lldb/Utility/StructuredData.h" #include "lldb/Utility/UserID.h" @@ -253,9 +254,9 @@ public: bool ThreadStoppedForAReason(); - static const char *RunModeAsCString(lldb::RunMode mode); + static std::string RunModeAsString(lldb::RunMode mode); - static const char *StopReasonAsCString(lldb::StopReason reason); + static std::string StopReasonAsString(lldb::StopReason reason); virtual const char *GetInfo() { return nullptr; } @@ -468,6 +469,24 @@ public: // the backing thread for all memory threads each time we stop. } + /// Dump \a count instructions of the thread's \a Trace starting at the \a + /// start_position position in reverse order. + /// + /// The instructions are indexed in reverse order, which means that the \a + /// start_position 0 represents the last instruction of the trace + /// chronologically. + /// + /// \param[in] s + /// The stream object where the instructions are printed. + /// + /// \param[in] count + /// The number of instructions to print. + /// + /// \param[in] start_position + /// The position of the first instruction to print. + void DumpTraceInstructions(Stream &s, size_t count, + size_t start_position = 0) const; + // If stop_format is true, this will be the form used when we print stop // info. If false, it will be the form we use for thread list and co. void DumpUsingSettingsFormat(Stream &strm, uint32_t frame_idx, @@ -596,7 +615,7 @@ public: /// \return /// A shared pointer to the newly queued thread plan, or nullptr if the /// plan could not be queued. - virtual lldb::ThreadPlanSP QueueFundamentalPlan(bool abort_other_plans); + lldb::ThreadPlanSP QueueBasePlan(bool abort_other_plans); /// Queues the plan used to step one instruction from the current PC of \a /// thread. @@ -762,10 +781,10 @@ public: /// \param[in] stop_other_threads /// \b true if we will stop other threads while we single step this one. /// - /// \param[in] stop_vote + /// \param[in] report_stop_vote /// See standard meanings for the stop & run votes in ThreadPlan.h. /// - /// \param[in] run_vote + /// \param[in] report_run_vote /// See standard meanings for the stop & run votes in ThreadPlan.h. /// /// \param[out] status @@ -781,7 +800,7 @@ public: /// plan could not be queued. virtual lldb::ThreadPlanSP QueueThreadPlanForStepOut( bool abort_other_plans, SymbolContext *addr_context, bool first_insn, - bool stop_other_threads, Vote stop_vote, Vote run_vote, + bool stop_other_threads, Vote report_stop_vote, Vote report_run_vote, uint32_t frame_idx, Status &status, LazyBool step_out_avoids_code_without_debug_info = eLazyBoolCalculate); @@ -811,10 +830,10 @@ public: /// \param[in] stop_other_threads /// \b true if we will stop other threads while we single step this one. /// - /// \param[in] stop_vote + /// \param[in] report_stop_vote /// See standard meanings for the stop & run votes in ThreadPlan.h. /// - /// \param[in] run_vote + /// \param[in] report_run_vote /// See standard meanings for the stop & run votes in ThreadPlan.h. /// /// \param[in] frame_idx @@ -845,7 +864,7 @@ public: /// plan could not be queued. virtual lldb::ThreadPlanSP QueueThreadPlanForStepOutNoShouldStop( bool abort_other_plans, SymbolContext *addr_context, bool first_insn, - bool stop_other_threads, Vote stop_vote, Vote run_vote, + bool stop_other_threads, Vote report_stop_vote, Vote report_run_vote, uint32_t frame_idx, Status &status, bool continue_to_next_branch = false); /// Gets the plan used to step through the code that steps from a function @@ -911,6 +930,12 @@ public: // Thread Plan accessors: + /// Format the thread plan information for auto completion. + /// + /// \param[in] request + /// The reference to the completion handler. + void AutoCompleteThreadPlans(CompletionRequest &request) const; + /// Gets the plan which will execute next on the plan stack. /// /// \return @@ -1025,12 +1050,7 @@ public: virtual bool RestoreRegisterStateFromCheckpoint(ThreadStateCheckpoint &saved_state); - virtual bool - RestoreThreadStateFromCheckpoint(ThreadStateCheckpoint &saved_state); - - void EnableTracer(bool value, bool single_step); - - void SetTracer(lldb::ThreadPlanTracerSP &tracer_sp); + void RestoreThreadStateFromCheckpoint(ThreadStateCheckpoint &saved_state); // Get the thread index ID. The index ID that is guaranteed to not be re-used // by a process. They start at 1 and increase with each new thread. This diff --git a/gnu/llvm/lldb/include/lldb/Target/ThreadCollection.h b/gnu/llvm/lldb/include/lldb/Target/ThreadCollection.h index 40dc938976f..29f5103e7ee 100644 --- a/gnu/llvm/lldb/include/lldb/Target/ThreadCollection.h +++ b/gnu/llvm/lldb/include/lldb/Target/ThreadCollection.h @@ -28,7 +28,7 @@ public: ThreadCollection(collection threads); - virtual ~ThreadCollection() {} + virtual ~ThreadCollection() = default; uint32_t GetSize(); diff --git a/gnu/llvm/lldb/include/lldb/Target/ThreadPlan.h b/gnu/llvm/lldb/include/lldb/Target/ThreadPlan.h index 8c2f9776eeb..5e14a1fd657 100644 --- a/gnu/llvm/lldb/include/lldb/Target/ThreadPlan.h +++ b/gnu/llvm/lldb/include/lldb/Target/ThreadPlan.h @@ -23,316 +23,265 @@ namespace lldb_private { // ThreadPlan: +// // This is the pure virtual base class for thread plans. // -// The thread plans provide the "atoms" of behavior that -// all the logical process control, either directly from commands or through -// more complex composite plans will rely on. +// The thread plans provide the "atoms" of behavior that all the logical +// process control, either directly from commands or through more complex +// composite plans will rely on. // // Plan Stack: // -// The thread maintaining a thread plan stack, and you program the actions of a -// particular thread -// by pushing plans onto the plan stack. -// There is always a "Current" plan, which is the top of the plan stack, -// though in some cases +// The thread maintaining a thread plan stack, and you program the actions of +// a particular thread by pushing plans onto the plan stack. There is always +// a "Current" plan, which is the top of the plan stack, though in some cases // a plan may defer to plans higher in the stack for some piece of information // (let us define that the plan stack grows downwards). // // The plan stack is never empty, there is always a Base Plan which persists -// through the life -// of the running process. +// through the life of the running process. // // // Creating Plans: // -// The thread plan is generally created and added to the plan stack through the -// QueueThreadPlanFor... API -// in lldb::Thread. Those API's will return the plan that performs the named -// operation in a manner -// appropriate for the current process. The plans in lldb/source/Target are -// generic +// The thread plan is generally created and added to the plan stack through +// the QueueThreadPlanFor... API in lldb::Thread. Those API's will return the +// plan that performs the named operation in a manner appropriate for the +// current process. The plans in lldb/source/Target are generic // implementations, but a Process plugin can override them. // // ValidatePlan is then called. If it returns false, the plan is unshipped. -// This is a little -// convenience which keeps us from having to error out of the constructor. +// This is a little convenience which keeps us from having to error out of the +// constructor. // // Then the plan is added to the plan stack. When the plan is added to the -// plan stack its DidPush -// will get called. This is useful if a plan wants to push any additional -// plans as it is constructed, -// since you need to make sure you're already on the stack before you push -// additional plans. +// plan stack its DidPush will get called. This is useful if a plan wants to +// push any additional plans as it is constructed, since you need to make sure +// you're already on the stack before you push additional plans. // // Completed Plans: // -// When the target process stops the plans are queried, among other things, for -// whether their job is done. -// If it is they are moved from the plan stack to the Completed Plan stack in -// reverse order from their position -// on the plan stack (since multiple plans may be done at a given stop.) This -// is used primarily so that -// the lldb::Thread::StopInfo for the thread can be set properly. If one plan -// pushes another to achieve part of -// its job, but it doesn't want that sub-plan to be the one that sets the -// StopInfo, then call SetPrivate on the -// sub-plan when you create it, and the Thread will pass over that plan in -// reporting the reason for the stop. +// When the target process stops the plans are queried, among other things, +// for whether their job is done. If it is they are moved from the plan stack +// to the Completed Plan stack in reverse order from their position on the +// plan stack (since multiple plans may be done at a given stop.) This is +// used primarily so that the lldb::Thread::StopInfo for the thread can be set +// properly. If one plan pushes another to achieve part of its job, but it +// doesn't want that sub-plan to be the one that sets the StopInfo, then call +// SetPrivate on the sub-plan when you create it, and the Thread will pass +// over that plan in reporting the reason for the stop. // // Discarded plans: // // Your plan may also get discarded, i.e. moved from the plan stack to the -// "discarded plan stack". This can -// happen, for instance, if the plan is calling a function and the function -// call crashes and you want -// to unwind the attempt to call. So don't assume that your plan will always -// successfully stop. Which leads to: +// "discarded plan stack". This can happen, for instance, if the plan is +// calling a function and the function call crashes and you want to unwind the +// attempt to call. So don't assume that your plan will always successfully +// stop. Which leads to: // // Cleaning up after your plans: // // When the plan is moved from the plan stack its WillPop method is always -// called, no matter why. Once it is -// moved off the plan stack it is done, and won't get a chance to run again. -// So you should -// undo anything that affects target state in this method. But be sure to -// leave the plan able to correctly -// fill the StopInfo, however. -// N.B. Don't wait to do clean up target state till the destructor, since that -// will usually get called when +// called, no matter why. Once it is moved off the plan stack it is done, and +// won't get a chance to run again. So you should undo anything that affects +// target state in this method. But be sure to leave the plan able to +// correctly fill the StopInfo, however. N.B. Don't wait to do clean up +// target state till the destructor, since that will usually get called when // the target resumes, and you want to leave the target state correct for new -// plans in the time between when -// your plan gets unshipped and the next resume. +// plans in the time between when your plan gets unshipped and the next +// resume. // // Thread State Checkpoint: // -// Note that calling functions on target process (ThreadPlanCallFunction) changes -// current thread state. The function can be called either by direct user demand or -// internally, for example lldb allocates memory on device to calculate breakpoint -// condition expression - on Linux it is performed by calling mmap on device. -// ThreadStateCheckpoint saves Thread state (stop info and completed -// plan stack) to restore it after completing function call. +// Note that calling functions on target process (ThreadPlanCallFunction) +// changes current thread state. The function can be called either by direct +// user demand or internally, for example lldb allocates memory on device to +// calculate breakpoint condition expression - on Linux it is performed by +// calling mmap on device. ThreadStateCheckpoint saves Thread state (stop +// info and completed plan stack) to restore it after completing function +// call. // // Over the lifetime of the plan, various methods of the ThreadPlan are then -// called in response to changes of state in -// the process we are debugging as follows: +// called in response to changes of state in the process we are debugging as +// follows: // // Resuming: // // When the target process is about to be restarted, the plan's WillResume -// method is called, -// giving the plan a chance to prepare for the run. If WillResume returns -// false, then the -// process is not restarted. Be sure to set an appropriate error value in the -// Process if -// you have to do this. Note, ThreadPlans actually implement DoWillResume, -// WillResume wraps that call. +// method is called, giving the plan a chance to prepare for the run. If +// WillResume returns false, then the process is not restarted. Be sure to +// set an appropriate error value in the Process if you have to do this. +// Note, ThreadPlans actually implement DoWillResume, WillResume wraps that +// call. // // Next the "StopOthers" method of all the threads are polled, and if one -// thread's Current plan -// returns "true" then only that thread gets to run. If more than one returns -// "true" the threads that want to run solo -// get run one by one round robin fashion. Otherwise all are let to run. +// thread's Current plan returns "true" then only that thread gets to run. If +// more than one returns "true" the threads that want to run solo get run one +// by one round robin fashion. Otherwise all are let to run. // // Note, the way StopOthers is implemented, the base class implementation just -// asks the previous plan. So if your plan -// has no opinion about whether it should run stopping others or not, just -// don't implement StopOthers, and the parent -// will be asked. +// asks the previous plan. So if your plan has no opinion about whether it +// should run stopping others or not, just don't implement StopOthers, and the +// parent will be asked. // // Finally, for each thread that is running, it run state is set to the return -// of RunState from the -// thread's Current plan. +// of RunState from the thread's Current plan. // // Responding to a stop: // // When the target process stops, the plan is called in the following stages: // -// First the thread asks the Current Plan if it can handle this stop by calling -// PlanExplainsStop. -// If the Current plan answers "true" then it is asked if the stop should -// percolate all the way to the -// user by calling the ShouldStop method. If the current plan doesn't explain -// the stop, then we query up -// the plan stack for a plan that does explain the stop. The plan that does -// explain the stop then needs to -// figure out what to do about the plans below it in the stack. If the stop is -// recoverable, then the plan that -// understands it can just do what it needs to set up to restart, and then -// continue. -// Otherwise, the plan that understood the stop should call DiscardPlanStack to -// clean up the stack below it. -// Note, plans actually implement DoPlanExplainsStop, the result is cached in -// PlanExplainsStop so the DoPlanExplainsStop -// itself will only get called once per stop. +// First the thread asks the Current Plan if it can handle this stop by +// calling PlanExplainsStop. If the Current plan answers "true" then it is +// asked if the stop should percolate all the way to the user by calling the +// ShouldStop method. If the current plan doesn't explain the stop, then we +// query up the plan stack for a plan that does explain the stop. The plan +// that does explain the stop then needs to figure out what to do about the +// plans below it in the stack. If the stop is recoverable, then the plan +// that understands it can just do what it needs to set up to restart, and +// then continue. Otherwise, the plan that understood the stop should call +// DiscardPlanStack to clean up the stack below it. Note, plans actually +// implement DoPlanExplainsStop, the result is cached in PlanExplainsStop so +// the DoPlanExplainsStop itself will only get called once per stop. // // Master plans: // -// In the normal case, when we decide to stop, we will collapse the plan stack -// up to the point of the plan that understood -// the stop reason. However, if a plan wishes to stay on the stack after an -// event it didn't directly handle -// it can designate itself a "Master" plan by responding true to IsMasterPlan, -// and then if it wants not to be -// discarded, it can return false to OkayToDiscard, and it and all its dependent -// plans will be preserved when -// we resume execution. -// -// The other effect of being a master plan is that when the Master plan is done -// , if it has set "OkayToDiscard" to false, -// then it will be popped & execution will stop and return to the user. -// Remember that if OkayToDiscard is false, the -// plan will be popped and control will be given to the next plan above it on -// the stack So setting OkayToDiscard to -// false means the user will regain control when the MasterPlan is completed. -// -// Between these two controls this allows things like: a MasterPlan/DontDiscard -// Step Over to hit a breakpoint, stop and -// return control to the user, but then when the user continues, the step out -// succeeds. -// Even more tricky, when the breakpoint is hit, the user can continue to step -// in/step over/etc, and finally when they -// continue, they will finish up the Step Over. +// In the normal case, when we decide to stop, we will collapse the plan +// stack up to the point of the plan that understood the stop reason. +// However, if a plan wishes to stay on the stack after an event it didn't +// directly handle it can designate itself a "Master" plan by responding true +// to IsMasterPlan, and then if it wants not to be discarded, it can return +// false to OkayToDiscard, and it and all its dependent plans will be +// preserved when we resume execution. +// +// The other effect of being a master plan is that when the Master plan is +// done , if it has set "OkayToDiscard" to false, then it will be popped & +// execution will stop and return to the user. Remember that if OkayToDiscard +// is false, the plan will be popped and control will be given to the next +// plan above it on the stack So setting OkayToDiscard to false means the +// user will regain control when the MasterPlan is completed. +// +// Between these two controls this allows things like: a +// MasterPlan/DontDiscard Step Over to hit a breakpoint, stop and return +// control to the user, but then when the user continues, the step out +// succeeds. Even more tricky, when the breakpoint is hit, the user can +// continue to step in/step over/etc, and finally when they continue, they +// will finish up the Step Over. // // FIXME: MasterPlan & OkayToDiscard aren't really orthogonal. MasterPlan -// designation means that this plan controls -// it's fate and the fate of plans below it. OkayToDiscard tells whether the -// MasterPlan wants to stay on the stack. I -// originally thought "MasterPlan-ness" would need to be a fixed characteristic -// of a ThreadPlan, in which case you needed -// the extra control. But that doesn't seem to be true. So we should be able -// to convert to only MasterPlan status to mean -// the current "MasterPlan/DontDiscard". Then no plans would be MasterPlans by -// default, and you would set the ones you +// designation means that this plan controls it's fate and the fate of plans +// below it. OkayToDiscard tells whether the MasterPlan wants to stay on the +// stack. I originally thought "MasterPlan-ness" would need to be a fixed +// characteristic of a ThreadPlan, in which case you needed the extra control. +// But that doesn't seem to be true. So we should be able to convert to only +// MasterPlan status to mean the current "MasterPlan/DontDiscard". Then no +// plans would be MasterPlans by default, and you would set the ones you // wanted to be "user level" in this way. // // // Actually Stopping: // // If a plan says responds "true" to ShouldStop, then it is asked if it's job -// is complete by calling -// MischiefManaged. If that returns true, the plan is popped from the plan -// stack and added to the -// Completed Plan Stack. Then the next plan in the stack is asked if it -// ShouldStop, and it returns "true", -// it is asked if it is done, and if yes popped, and so on till we reach a plan -// that is not done. -// -// Since you often know in the ShouldStop method whether your plan is complete, -// as a convenience you can call -// SetPlanComplete and the ThreadPlan implementation of MischiefManaged will -// return "true", without your having -// to redo the calculation when your sub-classes MischiefManaged is called. If -// you call SetPlanComplete, you can -// later use IsPlanComplete to determine whether the plan is complete. This is -// only a convenience for sub-classes, +// is complete by calling MischiefManaged. If that returns true, the plan is +// popped from the plan stack and added to the Completed Plan Stack. Then the +// next plan in the stack is asked if it ShouldStop, and it returns "true", +// it is asked if it is done, and if yes popped, and so on till we reach a +// plan that is not done. +// +// Since you often know in the ShouldStop method whether your plan is +// complete, as a convenience you can call SetPlanComplete and the ThreadPlan +// implementation of MischiefManaged will return "true", without your having +// to redo the calculation when your sub-classes MischiefManaged is called. +// If you call SetPlanComplete, you can later use IsPlanComplete to determine +// whether the plan is complete. This is only a convenience for sub-classes, // the logic in lldb::Thread will only call MischiefManaged. // -// One slightly tricky point is you have to be careful using SetPlanComplete in -// PlanExplainsStop because you -// are not guaranteed that PlanExplainsStop for a plan will get called before -// ShouldStop gets called. If your sub-plan +// One slightly tricky point is you have to be careful using SetPlanComplete +// in PlanExplainsStop because you are not guaranteed that PlanExplainsStop +// for a plan will get called before ShouldStop gets called. If your sub-plan // explained the stop and then popped itself, only your ShouldStop will get // called. // -// If ShouldStop for any thread returns "true", then the WillStop method of the -// Current plan of -// all threads will be called, the stop event is placed on the Process's public -// broadcaster, and -// control returns to the upper layers of the debugger. +// If ShouldStop for any thread returns "true", then the WillStop method of +// the Current plan of all threads will be called, the stop event is placed on +// the Process's public broadcaster, and control returns to the upper layers +// of the debugger. // // Reporting the stop: // // When the process stops, the thread is given a StopReason, in the form of a -// StopInfo object. If there is a completed -// plan corresponding to the stop, then the "actual" stop reason can be -// suppressed, and instead a StopInfoThreadPlan -// object will be cons'ed up from the top completed plan in the stack. -// However, if the plan doesn't want to be -// the stop reason, then it can call SetPlanComplete and pass in "false" for -// the "success" parameter. In that case, -// the real stop reason will be used instead. One example of this is the -// "StepRangeStepIn" thread plan. If it stops -// because of a crash or breakpoint hit, it wants to unship itself, because it -// isn't so useful to have step in keep going -// after a breakpoint hit. But it can't be the reason for the stop or no-one -// would see that they had hit a breakpoint. +// StopInfo object. If there is a completed plan corresponding to the stop, +// then the "actual" stop reason can be suppressed, and instead a +// StopInfoThreadPlan object will be cons'ed up from the top completed plan in +// the stack. However, if the plan doesn't want to be the stop reason, then +// it can call SetPlanComplete and pass in "false" for the "success" +// parameter. In that case, the real stop reason will be used instead. One +// example of this is the "StepRangeStepIn" thread plan. If it stops because +// of a crash or breakpoint hit, it wants to unship itself, because it isn't +// so useful to have step in keep going after a breakpoint hit. But it can't +// be the reason for the stop or no-one would see that they had hit a +// breakpoint. // // Cleaning up the plan stack: // // One of the complications of MasterPlans is that you may get past the limits -// of a plan without triggering it to clean -// itself up. For instance, if you are doing a MasterPlan StepOver, and hit a -// breakpoint in a called function, then -// step over enough times to step out of the initial StepOver range, each of -// the step overs will explain the stop & -// take themselves off the stack, but control would never be returned to the -// original StepOver. Eventually, the user -// will continue, and when that continue stops, the old stale StepOver plan -// that was left on the stack will get woken -// up and notice it is done. But that can leave junk on the stack for a while. -// To avoid that, the plans implement a -// "IsPlanStale" method, that can check whether it is relevant anymore. On -// stop, after the regular plan negotiation, -// the remaining plan stack is consulted and if any plan says it is stale, it -// and the plans below it are discarded from -// the stack. +// of a plan without triggering it to clean itself up. For instance, if you +// are doing a MasterPlan StepOver, and hit a breakpoint in a called function, +// then step over enough times to step out of the initial StepOver range, each +// of the step overs will explain the stop & take themselves off the stack, +// but control would never be returned to the original StepOver. Eventually, +// the user will continue, and when that continue stops, the old stale +// StepOver plan that was left on the stack will get woken up and notice it is +// done. But that can leave junk on the stack for a while. To avoid that, the +// plans implement a "IsPlanStale" method, that can check whether it is +// relevant anymore. On stop, after the regular plan negotiation, the +// remaining plan stack is consulted and if any plan says it is stale, it and +// the plans below it are discarded from the stack. // // Automatically Resuming: // // If ShouldStop for all threads returns "false", then the target process will -// resume. This then cycles back to -// Resuming above. +// resume. This then cycles back to Resuming above. // // Reporting eStateStopped events when the target is restarted: // // If a plan decides to auto-continue the target by returning "false" from -// ShouldStop, then it will be asked -// whether the Stopped event should still be reported. For instance, if you -// hit a breakpoint that is a User set -// breakpoint, but the breakpoint callback said to continue the target process, -// you might still want to inform -// the upper layers of lldb that the stop had happened. -// The way this works is every thread gets to vote on whether to report the -// stop. If all votes are eVoteNoOpinion, -// then the thread list will decide what to do (at present it will pretty much -// always suppress these stopped events.) -// If there is an eVoteYes, then the event will be reported regardless of the -// other votes. If there is an eVoteNo -// and no eVoteYes's, then the event won't be reported. +// ShouldStop, then it will be asked whether the Stopped event should still be +// reported. For instance, if you hit a breakpoint that is a User set +// breakpoint, but the breakpoint callback said to continue the target +// process, you might still want to inform the upper layers of lldb that the +// stop had happened. The way this works is every thread gets to vote on +// whether to report the stop. If all votes are eVoteNoOpinion, then the +// thread list will decide what to do (at present it will pretty much always +// suppress these stopped events.) If there is an eVoteYes, then the event +// will be reported regardless of the other votes. If there is an eVoteNo and +// no eVoteYes's, then the event won't be reported. // // One other little detail here, sometimes a plan will push another plan onto -// the plan stack to do some part of -// the first plan's job, and it would be convenient to tell that plan how it -// should respond to ShouldReportStop. -// You can do that by setting the stop_vote in the child plan when you create -// it. +// the plan stack to do some part of the first plan's job, and it would be +// convenient to tell that plan how it should respond to ShouldReportStop. +// You can do that by setting the report_stop_vote in the child plan when you +// create it. // // Suppressing the initial eStateRunning event: // // The private process running thread will take care of ensuring that only one -// "eStateRunning" event will be -// delivered to the public Process broadcaster per public eStateStopped event. -// However there are some cases -// where the public state of this process is eStateStopped, but a thread plan -// needs to restart the target, but -// doesn't want the running event to be publicly broadcast. The obvious -// example of this is running functions -// by hand as part of expression evaluation. To suppress the running event -// return eVoteNo from ShouldReportStop, -// to force a running event to be reported return eVoteYes, in general though -// you should return eVoteNoOpinion -// which will allow the ThreadList to figure out the right thing to do. -// The run_vote argument to the constructor works like stop_vote, and is a way -// for a plan to instruct a sub-plan -// on how to respond to ShouldReportStop. -// +// "eStateRunning" event will be delivered to the public Process broadcaster +// per public eStateStopped event. However there are some cases where the +// public state of this process is eStateStopped, but a thread plan needs to +// restart the target, but doesn't want the running event to be publicly +// broadcast. The obvious example of this is running functions by hand as +// part of expression evaluation. To suppress the running event return +// eVoteNo from ShouldReportStop, to force a running event to be reported +// return eVoteYes, in general though you should return eVoteNoOpinion which +// will allow the ThreadList to figure out the right thing to do. The +// report_run_vote argument to the constructor works like report_stop_vote, and +// is a way for a plan to instruct a sub-plan on how to respond to +// ShouldReportStop. class ThreadPlan : public std::enable_shared_from_this, public UserID { public: - enum ThreadScope { eAllThreads, eSomeThreads, eThisThread }; - // We use these enums so that we can cast a base thread plan to it's real // type without having to resort to dynamic casting. enum ThreadPlanKind { @@ -348,15 +297,9 @@ public: eKindStepInRange, eKindRunToAddress, eKindStepThrough, - eKindStepUntil, - eKindTestCondition - + eKindStepUntil }; - // Constructors and Destructors - ThreadPlan(ThreadPlanKind kind, const char *name, Thread &thread, - Vote stop_vote, Vote run_vote); - virtual ~ThreadPlan(); /// Returns the name of this thread plan. @@ -375,6 +318,12 @@ public: const Target &GetTarget() const; + /// Clear the Thread* cache. + /// + /// This is useful in situations like when a new Thread list is being + /// generated. + void ClearThreadCache(); + /// Print a description of this thread to the stream \a s. /// \a thread. Don't expect that the result of GetThread is valid in /// the description method. This might get called when the underlying @@ -412,6 +361,12 @@ public: virtual bool ShouldStop(Event *event_ptr) = 0; + /// Returns whether this thread plan overrides the `ShouldStop` of + /// subsequently processed plans. + /// + /// When processing the thread plan stack, this function gives plans the + /// ability to continue - even when subsequent plans return true from + /// `ShouldStop`. \see Thread::ShouldStop virtual bool ShouldAutoContinue(Event *event_ptr) { return false; } // Whether a "stop class" event should be reported to the "outside world". @@ -419,7 +374,7 @@ public: virtual Vote ShouldReportStop(Event *event_ptr); - virtual Vote ShouldReportRun(Event *event_ptr); + Vote ShouldReportRun(Event *event_ptr); virtual void SetStopOthers(bool new_value); @@ -460,15 +415,6 @@ public: virtual void WillPop(); - // This pushes a plan onto the plan stack of the current plan's thread. - // Also sets the plans to private and not master plans. A plan pushed by - // another thread plan is never either of the above. - void PushPlan(lldb::ThreadPlanSP &thread_plan_sp) { - GetThread().PushPlan(thread_plan_sp); - thread_plan_sp->SetPrivate(false); - thread_plan_sp->SetIsMasterPlan(false); - } - ThreadPlanKind GetKind() const { return m_kind; } bool IsPlanComplete(); @@ -492,15 +438,6 @@ public: m_tracer_sp->Log(); } - // Some thread plans hide away the actual stop info which caused any - // particular stop. For instance the ThreadPlanCallFunction restores the - // original stop reason so that stopping and calling a few functions won't - // lose the history of the run. This call can be implemented to get you back - // to the real stop info. - virtual lldb::StopInfoSP GetRealStopInfo() { - return GetThread().GetStopInfo(); - } - // If the completion of the thread plan stepped out of a function, the return // value of the function might have been captured by the thread plan // (currently only ThreadPlanStepOut does this.) If so, the ReturnValueObject @@ -525,14 +462,11 @@ public: // to restore the state when it is done. This will do that job. This is // mostly useful for artificial plans like CallFunction plans. - virtual bool RestoreThreadState() { - // Nothing to do in general. - return true; - } + virtual void RestoreThreadState() {} virtual bool IsVirtualStep() { return false; } - virtual bool SetIterationCount(size_t count) { + bool SetIterationCount(size_t count) { if (m_takes_iteration_count) { // Don't tell me to do something 0 times... if (count == 0) @@ -542,14 +476,11 @@ public: return m_takes_iteration_count; } - virtual size_t GetIterationCount() { - if (!m_takes_iteration_count) - return 0; - else - return m_iteration_count; - } - protected: + // Constructors and Destructors + ThreadPlan(ThreadPlanKind kind, const char *name, Thread &thread, + Vote report_stop_vote, Vote report_run_vote); + // Classes that inherit from ThreadPlan can see and modify these virtual bool DoWillResume(lldb::StateType resume_state, bool current_plan) { @@ -558,6 +489,15 @@ protected: virtual bool DoPlanExplainsStop(Event *event_ptr) = 0; + // This pushes a plan onto the plan stack of the current plan's thread. + // Also sets the plans to private and not master plans. A plan pushed by + // another thread plan is never either of the above. + void PushPlan(lldb::ThreadPlanSP &thread_plan_sp) { + GetThread().PushPlan(thread_plan_sp); + thread_plan_sp->SetPrivate(true); + thread_plan_sp->SetIsMasterPlan(false); + } + // This gets the previous plan to the current plan (for forwarding requests). // This is mostly a formal requirement, it allows us to make the Thread's // GetPreviousPlan protected, but only friend ThreadPlan to thread. @@ -575,14 +515,6 @@ protected: GetThread().SetStopInfo(stop_reason_sp); } - void CachePlanExplainsStop(bool does_explain) { - m_cached_plan_explains_stop = does_explain ? eLazyBoolYes : eLazyBoolNo; - } - - LazyBool GetCachedPlanExplainsStop() const { - return m_cached_plan_explains_stop; - } - virtual lldb::StateType GetPlanRunState() = 0; bool IsUsuallyUnexplainedStopReason(lldb::StopReason); @@ -590,13 +522,17 @@ protected: Status m_status; Process &m_process; lldb::tid_t m_tid; - Vote m_stop_vote; - Vote m_run_vote; + Vote m_report_stop_vote; + Vote m_report_run_vote; bool m_takes_iteration_count; bool m_could_not_resolve_hw_bp; int32_t m_iteration_count = 1; private: + void CachePlanExplainsStop(bool does_explain) { + m_cached_plan_explains_stop = does_explain ? eLazyBoolYes : eLazyBoolNo; + } + // For ThreadPlan only static lldb::user_id_t GetNextID(); diff --git a/gnu/llvm/lldb/include/lldb/Target/ThreadPlanBase.h b/gnu/llvm/lldb/include/lldb/Target/ThreadPlanBase.h index 48058a9b40a..5c44b9fb17b 100644 --- a/gnu/llvm/lldb/include/lldb/Target/ThreadPlanBase.h +++ b/gnu/llvm/lldb/include/lldb/Target/ThreadPlanBase.h @@ -44,8 +44,7 @@ protected: ThreadPlanBase(Thread &thread); private: - friend lldb::ThreadPlanSP - Thread::QueueFundamentalPlan(bool abort_other_plans); + friend lldb::ThreadPlanSP Thread::QueueBasePlan(bool abort_other_plans); ThreadPlanBase(const ThreadPlanBase &) = delete; const ThreadPlanBase &operator=(const ThreadPlanBase &) = delete; diff --git a/gnu/llvm/lldb/include/lldb/Target/ThreadPlanCallFunction.h b/gnu/llvm/lldb/include/lldb/Target/ThreadPlanCallFunction.h index 5b432e5e604..24c5736f44c 100644 --- a/gnu/llvm/lldb/include/lldb/Target/ThreadPlanCallFunction.h +++ b/gnu/llvm/lldb/include/lldb/Target/ThreadPlanCallFunction.h @@ -81,7 +81,7 @@ public: // stop reason. But if something bad goes wrong, it is nice to be able to // tell the user what really happened. - lldb::StopInfoSP GetRealStopInfo() override { + virtual lldb::StopInfoSP GetRealStopInfo() { if (m_real_stop_info_sp) return m_real_stop_info_sp; else @@ -90,7 +90,7 @@ public: lldb::addr_t GetStopAddress() { return m_stop_address; } - bool RestoreThreadState() override; + void RestoreThreadState() override; void ThreadDestroyed() override { m_takedown_done = true; } diff --git a/gnu/llvm/lldb/include/lldb/Target/ThreadPlanPython.h b/gnu/llvm/lldb/include/lldb/Target/ThreadPlanPython.h index 27bf3a560b1..7b37b2b9ce5 100644 --- a/gnu/llvm/lldb/include/lldb/Target/ThreadPlanPython.h +++ b/gnu/llvm/lldb/include/lldb/Target/ThreadPlanPython.h @@ -45,7 +45,9 @@ public: bool WillStop() override; - bool StopOthers() override; + bool StopOthers() override { return m_stop_others; } + + void SetStopOthers(bool new_value) override { m_stop_others = new_value; } void DidPush() override; @@ -67,6 +69,7 @@ private: std::string m_error_str; StructuredData::ObjectSP m_implementation_sp; bool m_did_push; + bool m_stop_others; ThreadPlanPython(const ThreadPlanPython &) = delete; const ThreadPlanPython &operator=(const ThreadPlanPython &) = delete; diff --git a/gnu/llvm/lldb/include/lldb/Target/ThreadPlanStack.h b/gnu/llvm/lldb/include/lldb/Target/ThreadPlanStack.h index f1874136cad..e0f76f8e1df 100644 --- a/gnu/llvm/lldb/include/lldb/Target/ThreadPlanStack.h +++ b/gnu/llvm/lldb/include/lldb/Target/ThreadPlanStack.h @@ -33,9 +33,7 @@ class ThreadPlanStack { public: ThreadPlanStack(const Thread &thread, bool make_empty = false); - ~ThreadPlanStack() {} - - enum StackKind { ePlans, eCompletedPlans, eDiscardedPlans }; + ~ThreadPlanStack() = default; using PlanStack = std::vector; @@ -50,10 +48,6 @@ public: void ThreadDestroyed(Thread *thread); - void EnableTracer(bool value, bool single_stepping); - - void SetTracer(lldb::ThreadPlanTracerSP &tracer_sp); - void PushPlan(lldb::ThreadPlanSP new_plan_sp); lldb::ThreadPlanSP PopPlan(); @@ -95,9 +89,13 @@ public: void WillResume(); -private: - const PlanStack &GetStackOfKind(ThreadPlanStack::StackKind kind) const; + /// Clear the Thread* cache that each ThreadPlan contains. + /// + /// This is useful in situations like when a new Thread list is being + /// generated. + void ClearThreadCache(); +private: void PrintOneStack(Stream &s, llvm::StringRef stack_name, const PlanStack &stack, lldb::DescriptionLevel desc_level, bool include_internal) const; @@ -112,12 +110,13 @@ private: size_t m_completed_plan_checkpoint = 0; // Monotonically increasing token for // completed plan checkpoints. std::unordered_map m_completed_plan_store; + mutable std::recursive_mutex m_stack_mutex; }; class ThreadPlanStackMap { public: ThreadPlanStackMap(Process &process) : m_process(process) {} - ~ThreadPlanStackMap() {} + ~ThreadPlanStackMap() = default; // Prune the map using the current_threads list. void Update(ThreadList ¤t_threads, bool delete_missing, @@ -145,8 +144,17 @@ public: return &result->second; } + /// Clear the Thread* cache that each ThreadPlan contains. + /// + /// This is useful in situations like when a new Thread list is being + /// generated. + void ClearThreadCache() { + for (auto &plan_list : m_plans_list) + plan_list.second.ClearThreadCache(); + } + void Clear() { - for (auto plan : m_plans_list) + for (auto &plan : m_plans_list) plan.second.ThreadDestroyed(nullptr); m_plans_list.clear(); } diff --git a/gnu/llvm/lldb/include/lldb/Target/ThreadPlanStepInRange.h b/gnu/llvm/lldb/include/lldb/Target/ThreadPlanStepInRange.h index 59b5721998b..f9ef87942a7 100644 --- a/gnu/llvm/lldb/include/lldb/Target/ThreadPlanStepInRange.h +++ b/gnu/llvm/lldb/include/lldb/Target/ThreadPlanStepInRange.h @@ -22,14 +22,7 @@ class ThreadPlanStepInRange : public ThreadPlanStepRange, public: ThreadPlanStepInRange(Thread &thread, const AddressRange &range, const SymbolContext &addr_context, - lldb::RunMode stop_others, - LazyBool step_in_avoids_code_without_debug_info, - LazyBool step_out_avoids_code_without_debug_info); - - ThreadPlanStepInRange(Thread &thread, const AddressRange &range, - const SymbolContext &addr_context, - const char *step_into_function_name, - lldb::RunMode stop_others, + const char *step_into_target, lldb::RunMode stop_others, LazyBool step_in_avoids_code_without_debug_info, LazyBool step_out_avoids_code_without_debug_info); @@ -41,10 +34,6 @@ public: void SetAvoidRegexp(const char *name); - void SetStepInTarget(const char *target) { - m_step_into_target.SetCString(target); - } - static void SetDefaultFlagValue(uint32_t new_value); bool IsVirtualStep() override; @@ -78,17 +67,6 @@ protected: bool FrameMatchesAvoidCriteria(); private: - friend lldb::ThreadPlanSP Thread::QueueThreadPlanForStepOverRange( - bool abort_other_plans, const AddressRange &range, - const SymbolContext &addr_context, lldb::RunMode stop_others, - Status &status, LazyBool avoid_code_without_debug_info); - friend lldb::ThreadPlanSP Thread::QueueThreadPlanForStepInRange( - bool abort_other_plans, const AddressRange &range, - const SymbolContext &addr_context, const char *step_in_target, - lldb::RunMode stop_others, Status &status, - LazyBool step_in_avoids_code_without_debug_info, - LazyBool step_out_avoids_code_without_debug_info); - void SetupAvoidNoDebug(LazyBool step_in_avoids_code_without_debug_info, LazyBool step_out_avoids_code_without_debug_info); // Need an appropriate marker for the current stack so we can tell step out diff --git a/gnu/llvm/lldb/include/lldb/Target/ThreadPlanStepInstruction.h b/gnu/llvm/lldb/include/lldb/Target/ThreadPlanStepInstruction.h index 760bc4886fa..52a5a2efc0a 100644 --- a/gnu/llvm/lldb/include/lldb/Target/ThreadPlanStepInstruction.h +++ b/gnu/llvm/lldb/include/lldb/Target/ThreadPlanStepInstruction.h @@ -18,7 +18,7 @@ namespace lldb_private { class ThreadPlanStepInstruction : public ThreadPlan { public: ThreadPlanStepInstruction(Thread &thread, bool step_over, bool stop_others, - Vote stop_vote, Vote run_vote); + Vote report_stop_vote, Vote report_run_vote); ~ThreadPlanStepInstruction() override; diff --git a/gnu/llvm/lldb/include/lldb/Target/ThreadPlanStepOut.h b/gnu/llvm/lldb/include/lldb/Target/ThreadPlanStepOut.h index 5c39232fd2e..b1d8769f7c5 100644 --- a/gnu/llvm/lldb/include/lldb/Target/ThreadPlanStepOut.h +++ b/gnu/llvm/lldb/include/lldb/Target/ThreadPlanStepOut.h @@ -18,8 +18,8 @@ namespace lldb_private { class ThreadPlanStepOut : public ThreadPlan, public ThreadPlanShouldStopHere { public: ThreadPlanStepOut(Thread &thread, SymbolContext *addr_context, - bool first_insn, bool stop_others, Vote stop_vote, - Vote run_vote, uint32_t frame_idx, + bool first_insn, bool stop_others, Vote report_stop_vote, + Vote report_run_vote, uint32_t frame_idx, LazyBool step_out_avoids_code_without_debug_info, bool continue_to_next_branch = false, bool gather_return_value = true); @@ -76,8 +76,9 @@ private: friend lldb::ThreadPlanSP Thread::QueueThreadPlanForStepOut( bool abort_other_plans, SymbolContext *addr_context, bool first_insn, - bool stop_others, Vote stop_vote, Vote run_vote, uint32_t frame_idx, - Status &status, LazyBool step_out_avoids_code_without_debug_info); + bool stop_others, Vote report_stop_vote, Vote report_run_vote, + uint32_t frame_idx, Status &status, + LazyBool step_out_avoids_code_without_debug_info); void SetupAvoidNoDebug(LazyBool step_out_avoids_code_without_debug_info); // Need an appropriate marker for the current stack so we can tell step out diff --git a/gnu/llvm/lldb/include/lldb/Target/ThreadPlanTracer.h b/gnu/llvm/lldb/include/lldb/Target/ThreadPlanTracer.h index 677a2c0dd93..a6fd2f031dc 100644 --- a/gnu/llvm/lldb/include/lldb/Target/ThreadPlanTracer.h +++ b/gnu/llvm/lldb/include/lldb/Target/ThreadPlanTracer.h @@ -50,14 +50,6 @@ public: bool TracingEnabled() { return m_enabled; } - bool EnableSingleStep(bool value) { - bool old_value = m_single_step; - m_single_step = value; - return old_value; - } - - bool SingleStepEnabled() { return m_single_step; } - Thread &GetThread(); protected: @@ -71,7 +63,6 @@ protected: private: bool TracerExplainsStop(); - bool m_single_step; bool m_enabled; lldb::StreamSP m_stream_sp; Thread *m_thread; diff --git a/gnu/llvm/lldb/include/lldb/Target/ThreadSpec.h b/gnu/llvm/lldb/include/lldb/Target/ThreadSpec.h index 8c22d53185f..7c7c8327411 100644 --- a/gnu/llvm/lldb/include/lldb/Target/ThreadSpec.h +++ b/gnu/llvm/lldb/include/lldb/Target/ThreadSpec.h @@ -120,8 +120,8 @@ private: return g_option_names[(size_t) enum_value]; } - uint32_t m_index; - lldb::tid_t m_tid; + uint32_t m_index = UINT32_MAX; + lldb::tid_t m_tid = LLDB_INVALID_THREAD_ID; std::string m_name; std::string m_queue_name; }; diff --git a/gnu/llvm/lldb/include/lldb/Target/Trace.h b/gnu/llvm/lldb/include/lldb/Target/Trace.h new file mode 100644 index 00000000000..f5654988b20 --- /dev/null +++ b/gnu/llvm/lldb/include/lldb/Target/Trace.h @@ -0,0 +1,310 @@ +//===-- Trace.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_TARGET_TRACE_H +#define LLDB_TARGET_TRACE_H + +#include + +#include "llvm/Support/JSON.h" + +#include "lldb/Core/PluginInterface.h" +#include "lldb/Target/Thread.h" +#include "lldb/Target/TraceCursor.h" +#include "lldb/Utility/ArchSpec.h" +#include "lldb/Utility/TraceGDBRemotePackets.h" +#include "lldb/Utility/UnimplementedError.h" +#include "lldb/lldb-private.h" + +namespace lldb_private { + +/// \class Trace Trace.h "lldb/Target/Trace.h" +/// A plug-in interface definition class for trace information. +/// +/// Trace plug-ins allow processor trace information to be loaded into LLDB so +/// that the data can be dumped, used for reverse and forward stepping to allow +/// introspection into the reason your process crashed or found its way to its +/// current state. +/// +/// Trace information can be loaded into a target without a process to allow +/// introspection of the trace information during post mortem analysis, such as +/// when loading core files. +/// +/// Processor trace information can also be fetched through the process +/// interfaces during a live debug session if your process supports gathering +/// this information. +/// +/// In order to support live tracing, the name of the plug-in should match the +/// name of the tracing type returned by the gdb-remote packet +/// \a jLLDBTraceSupported. +class Trace : public PluginInterface, + public std::enable_shared_from_this { +public: + /// Dump the trace data that this plug-in has access to. + /// + /// This function will dump all of the trace data for all threads in a user + /// readable format. Options for dumping can be added as this API is iterated + /// on. + /// + /// \param[in] s + /// A stream object to dump the information to. + virtual void Dump(Stream *s) const = 0; + + /// Find a trace plug-in using JSON data. + /// + /// When loading trace data from disk, the information for the trace data + /// can be contained in multiple files and require plug-in specific + /// information about the CPU. Using data like JSON provides an + /// easy way to specify all of the settings and information that we will need + /// to load trace data into LLDB. This structured data can include: + /// - The plug-in name (this allows a specific plug-in to be selected) + /// - Architecture or target triple + /// - one or more paths to the trace data file on disk + /// - core trace data + /// - thread events or related information + /// - shared library load information to use for this trace data that + /// allows a target to be created so the trace information can be + /// symbolicated so that the trace information can be displayed to the + /// user + /// - shared library path + /// - load address + /// - information on how to fetch the shared library + /// - path to locally cached file on disk + /// - URL to download the file + /// - Any information needed to load the trace file + /// - CPU information + /// - Custom plug-in information needed to decode the trace information + /// correctly. + /// + /// \param[in] debugger + /// The debugger instance where new Targets will be created as part of the + /// JSON data parsing. + /// + /// \param[in] trace_session_file + /// The contents of the trace session file describing the trace session. + /// See \a TraceSessionFileParser::BuildSchema for more information about + /// the schema of this JSON file. + /// + /// \param[in] session_file_dir + /// The path to the directory that contains the session file. It's used to + /// resolved relative paths in the session file. + static llvm::Expected + FindPluginForPostMortemProcess(Debugger &debugger, + const llvm::json::Value &trace_session_file, + llvm::StringRef session_file_dir); + + /// Find a trace plug-in to trace a live process. + /// + /// \param[in] plugin_name + /// Plug-in name to search. + /// + /// \param[in] process + /// Live process to trace. + /// + /// \return + /// A \a TraceSP instance, or an \a llvm::Error if the plug-in name + /// doesn't match any registered plug-ins or tracing couldn't be + /// started. + static llvm::Expected + FindPluginForLiveProcess(llvm::StringRef plugin_name, Process &process); + + /// Get the schema of a Trace plug-in given its name. + /// + /// \param[in] plugin_name + /// Name of the trace plugin. + static llvm::Expected + FindPluginSchema(llvm::StringRef plugin_name); + + /// Get the command handle for the "process trace start" command. + virtual lldb::CommandObjectSP + GetProcessTraceStartCommand(CommandInterpreter &interpreter) = 0; + + /// Get the command handle for the "thread trace start" command. + virtual lldb::CommandObjectSP + GetThreadTraceStartCommand(CommandInterpreter &interpreter) = 0; + + /// \return + /// The JSON schema of this Trace plug-in. + virtual llvm::StringRef GetSchema() = 0; + + /// Get a \a TraceCursor for the given thread's trace. + /// + /// \return + /// A \a TraceCursorUP. If the thread is not traced or its trace + /// information failed to load, the corresponding error is embedded in the + /// trace. + virtual lldb::TraceCursorUP GetCursor(Thread &thread) = 0; + + /// Dump general info about a given thread's trace. Each Trace plug-in + /// decides which data to show. + /// + /// \param[in] thread + /// The thread that owns the trace in question. + /// + /// \param[in] s + /// The stream object where the info will be printed printed. + /// + /// \param[in] verbose + /// If \b true, print detailed info + /// If \b false, print compact info + virtual void DumpTraceInfo(Thread &thread, Stream &s, bool verbose) = 0; + + /// Check if a thread is currently traced by this object. + /// + /// \param[in] thread + /// The thread in question. + /// + /// \return + /// \b true if the thread is traced by this instance, \b false otherwise. + virtual bool IsTraced(const Thread &thread) = 0; + + /// \return + /// A description of the parameters to use for the \a Trace::Start method. + virtual const char *GetStartConfigurationHelp() = 0; + + /// Start tracing a live process. + /// + /// \param[in] configuration + /// See \a SBTrace::Start(const lldb::SBStructuredData &) for more + /// information. + /// + /// \return + /// \a llvm::Error::success if the operation was successful, or + /// \a llvm::Error otherwise. + virtual llvm::Error Start( + StructuredData::ObjectSP configuration = StructuredData::ObjectSP()) = 0; + + /// Start tracing live threads. + /// + /// \param[in] tids + /// Threads to trace. This method tries to trace as many threads as + /// possible. + /// + /// \param[in] configuration + /// See \a SBTrace::Start(const lldb::SBThread &, const + /// lldb::SBStructuredData &) for more information. + /// + /// \return + /// \a llvm::Error::success if the operation was successful, or + /// \a llvm::Error otherwise. + virtual llvm::Error Start( + llvm::ArrayRef tids, + StructuredData::ObjectSP configuration = StructuredData::ObjectSP()) = 0; + + /// Stop tracing live threads. + /// + /// \param[in] tids + /// The threads to stop tracing on. + /// + /// \return + /// \a llvm::Error::success if the operation was successful, or + /// \a llvm::Error otherwise. + llvm::Error Stop(llvm::ArrayRef tids); + + /// Stop tracing all current and future threads of a live process. + /// + /// \param[in] request + /// The information determining which threads or process to stop tracing. + /// + /// \return + /// \a llvm::Error::success if the operation was successful, or + /// \a llvm::Error otherwise. + llvm::Error Stop(); + + /// Get the trace file of the given post mortem thread. + llvm::Expected GetPostMortemTraceFile(lldb::tid_t tid); + + /// \return + /// The stop ID of the live process being traced, or an invalid stop ID + /// if the trace is in an error or invalid state. + uint32_t GetStopID(); + +protected: + /// Get binary data of a live thread given a data identifier. + /// + /// \param[in] tid + /// The thread whose data is requested. + /// + /// \param[in] kind + /// The kind of data requested. + /// + /// \return + /// A vector of bytes with the requested data, or an \a llvm::Error in + /// case of failures. + llvm::Expected> + GetLiveThreadBinaryData(lldb::tid_t tid, llvm::StringRef kind); + + /// Get binary data of the current process given a data identifier. + /// + /// \param[in] kind + /// The kind of data requested. + /// + /// \return + /// A vector of bytes with the requested data, or an \a llvm::Error in + /// case of failures. + llvm::Expected> + GetLiveProcessBinaryData(llvm::StringRef kind); + + /// Get the size of the data returned by \a GetLiveThreadBinaryData + llvm::Optional GetLiveThreadBinaryDataSize(lldb::tid_t tid, + llvm::StringRef kind); + + /// Get the size of the data returned by \a GetLiveProcessBinaryData + llvm::Optional GetLiveProcessBinaryDataSize(llvm::StringRef kind); + /// Constructor for post mortem processes + Trace() = default; + + /// Constructor for a live process + Trace(Process &live_process) : m_live_process(&live_process) {} + + /// Start tracing a live process or its threads. + /// + /// \param[in] request + /// JSON object with the information necessary to start tracing. In the + /// case of gdb-remote processes, this JSON object should conform to the + /// jLLDBTraceStart packet. + /// + /// \return + /// \a llvm::Error::success if the operation was successful, or + /// \a llvm::Error otherwise. + llvm::Error Start(const llvm::json::Value &request); + + /// Get the current tracing state of a live process and its threads. + /// + /// \return + /// A JSON object string with custom data depending on the trace + /// technology, or an \a llvm::Error in case of errors. + llvm::Expected GetLiveProcessState(); + + /// Method to be overriden by the plug-in to refresh its own state. + /// + /// This is invoked by RefreshLiveProcessState when a new state is found. + /// + /// \param[in] state + /// The jLLDBTraceGetState response. + virtual void + DoRefreshLiveProcessState(llvm::Expected state) = 0; + + /// Method to be invoked by the plug-in to refresh the live process state. + /// + /// The result is cached through the same process stop. + void RefreshLiveProcessState(); + + uint32_t m_stop_id = LLDB_INVALID_STOP_ID; + /// Process traced by this object if doing live tracing. Otherwise it's null. + Process *m_live_process = nullptr; + /// tid -> data kind -> size + std::map> + m_live_thread_data; + /// data kind -> size + std::unordered_map m_live_process_data; +}; + +} // namespace lldb_private + +#endif // LLDB_TARGET_TRACE_H diff --git a/gnu/llvm/lldb/include/lldb/Target/TraceCursor.h b/gnu/llvm/lldb/include/lldb/Target/TraceCursor.h new file mode 100644 index 00000000000..14fc00d5f95 --- /dev/null +++ b/gnu/llvm/lldb/include/lldb/Target/TraceCursor.h @@ -0,0 +1,211 @@ +//===-- TraceCursor.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_TARGET_TRACE_CURSOR_H +#define LLDB_TARGET_TRACE_CURSOR_H + +#include "lldb/lldb-private.h" + +#include "lldb/Target/ExecutionContext.h" + +namespace lldb_private { + +/// Class used for iterating over the instructions of a thread's trace. +/// +/// This class attempts to be a generic interface for accessing the instructions +/// of the trace so that each Trace plug-in can reconstruct, represent and store +/// the instruction data in an flexible way that is efficient for the given +/// technology. +/// +/// Live processes: +/// In the case of a live process trace, an instance of a \a TraceCursor should +/// point to the trace at the moment it was collected. If the process is later +/// resumed and new trace data is collected, that should leave that old cursor +/// unaffected. +/// +/// Errors in the trace: +/// As there could be errors when reconstructing the instructions of a trace, +/// these errors are represented as failed instructions, and the cursor can +/// point at them. The consumer should invoke \a TraceCursor::GetError() to +/// check if the cursor is pointing to either a valid instruction or an error. +/// +/// Instructions: +/// A \a TraceCursor always points to a specific instruction or error in the +/// trace. +/// +/// Defaults: +/// By default, the cursor points at the end item of the trace, moves +/// backwards, has a move granularity of \a +/// eTraceInstructionControlFlowTypeInstruction (i.e. visit every instruction) +/// and stops at every error (the "ignore errors" flag is \b false). See the +/// \a TraceCursor::Next() method for more documentation. +/// +/// Sample usage: +/// +/// TraceCursorUP cursor = trace.GetTrace(thread); +/// +/// cursor->SetGranularity(eTraceInstructionControlFlowTypeCall | +/// eTraceInstructionControlFlowTypeReturn); +/// +/// do { +/// if (llvm::Error error = cursor->GetError()) +/// cout << "error found at: " << llvm::toString(error) << endl; +/// else if (cursor->GetInstructionControlFlowType() & +/// eTraceInstructionControlFlowTypeCall) +/// std::cout << "call found at " << cursor->GetLoadAddress() << +/// std::endl; +/// else if (cursor->GetInstructionControlFlowType() & +/// eTraceInstructionControlFlowTypeReturn) +/// std::cout << "return found at " << cursor->GetLoadAddress() << +/// std::endl; +/// } while(cursor->Next()); +/// +/// Low level traversal: +/// Unlike the \a TraceCursor::Next() API, which uses a given granularity and +/// direction to advance the cursor, the \a TraceCursor::Seek() method can be +/// used to reposition the cursor to an offset of the end, beginning, or +/// current position of the trace. +class TraceCursor { +public: + /// Helper enum to indicate the reference point when invoking + /// \a TraceCursor::Seek(). + enum class SeekType { + /// The beginning of the trace, i.e the oldest item. + Set = 0, + /// The current position in the trace. + Current, + /// The end of the trace, i.e the most recent item. + End + }; + + /// Create a cursor that initially points to the end of the trace, i.e. the + /// most recent item. + TraceCursor(lldb::ThreadSP thread_sp); + + virtual ~TraceCursor() = default; + + /// Set the granularity to use in the \a TraceCursor::Next() method. + void SetGranularity(lldb::TraceInstructionControlFlowType granularity); + + /// Set the "ignore errors" flag to use in the \a TraceCursor::Next() method. + void SetIgnoreErrors(bool ignore_errors); + + /// Set the direction to use in the \a TraceCursor::Next() method. + /// + /// \param[in] forwards + /// If \b true, then the traversal will be forwards, otherwise backwards. + void SetForwards(bool forwards); + + /// Check if the direction to use in the \a TraceCursor::Next() method is + /// forwards. + /// + /// \return + /// \b true if the current direction is forwards, \b false if backwards. + bool IsForwards() const; + + /// Move the cursor to the next instruction that matches the current + /// granularity. + /// + /// Direction: + /// The traversal is done following the current direction of the trace. If + /// it is forwards, the instructions are visited forwards + /// chronologically. Otherwise, the traversal is done in + /// the opposite direction. By default, a cursor moves backwards unless + /// changed with \a TraceCursor::SetForwards(). + /// + /// Granularity: + /// The cursor will traverse the trace looking for the first instruction + /// that matches the current granularity. If there aren't any matching + /// instructions, the cursor won't move, to give the opportunity of + /// changing granularities. + /// + /// Ignore errors: + /// If the "ignore errors" flags is \b false, the traversal will stop as + /// soon as it finds an error in the trace and the cursor will point at + /// it. + /// + /// \return + /// \b true if the cursor effectively moved, \b false otherwise. + virtual bool Next() = 0; + + /// Make the cursor point to an item in the trace based on an origin point and + /// an offset. This API doesn't distinguishes instruction types nor errors in + /// the trace, unlike the \a TraceCursor::Next() method. + /// + /// The resulting position of the trace is + /// origin + offset + /// + /// If this resulting position would be out of bounds, it will be adjusted to + /// the last or first item in the trace correspondingly. + /// + /// \param[in] offset + /// How many items to move forwards (if positive) or backwards (if + /// negative) from the given origin point. + /// + /// \param[in] origin + /// The reference point to use when moving the cursor. + /// + /// \return + /// The number of trace items moved from the origin. + virtual size_t Seek(ssize_t offset, SeekType origin) = 0; + + /// \return + /// The \a ExecutionContextRef of the backing thread from the creation time + /// of this cursor. + ExecutionContextRef &GetExecutionContextRef(); + + /// Instruction or error information + /// \{ + + /// \return + /// Whether the cursor points to an error or not. + virtual bool IsError() = 0; + + /// Get the corresponding error message if the cursor points to an error in + /// the trace. + /// + /// \return + /// \b llvm::Error::success if the cursor is not pointing to an error in + /// the trace. Otherwise return an \a llvm::Error describing the issue. + virtual llvm::Error GetError() = 0; + + /// \return + /// The load address of the instruction the cursor is pointing at. If the + /// cursor points to an error in the trace, return \b + /// LLDB_INVALID_ADDRESS. + virtual lldb::addr_t GetLoadAddress() = 0; + + /// Get the timestamp counter associated with the current instruction. + /// Modern Intel, ARM and AMD processors support this counter. However, a + /// trace plugin might decide to use a different time unit instead of an + /// actual TSC. + /// + /// \return + /// The timestamp or \b llvm::None if not available. + virtual llvm::Optional GetTimestampCounter() = 0; + + /// \return + /// The \a lldb::TraceInstructionControlFlowType categories the + /// instruction the cursor is pointing at falls into. If the cursor points + /// to an error in the trace, return \b 0. + virtual lldb::TraceInstructionControlFlowType + GetInstructionControlFlowType() = 0; + /// \} + +protected: + ExecutionContextRef m_exe_ctx_ref; + + lldb::TraceInstructionControlFlowType m_granularity = + lldb::eTraceInstructionControlFlowTypeInstruction; + bool m_ignore_errors = false; + bool m_forwards = false; +}; + +} // namespace lldb_private + +#endif // LLDB_TARGET_TRACE_CURSOR_H diff --git a/gnu/llvm/lldb/include/lldb/Target/TraceExporter.h b/gnu/llvm/lldb/include/lldb/Target/TraceExporter.h new file mode 100644 index 00000000000..6560b39fd42 --- /dev/null +++ b/gnu/llvm/lldb/include/lldb/Target/TraceExporter.h @@ -0,0 +1,42 @@ +//===-- TraceExporter.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_TARGET_TRACE_EXPORTER_H +#define LLDB_TARGET_TRACE_EXPORTER_H + +#include "lldb/Core/PluginInterface.h" + +namespace lldb_private { + +/// \class TraceExporter TraceExporter.h "lldb/Target/TraceExporter.h" +/// A plug-in interface definition class for trace exporters. +/// +/// Trace exporter plug-ins operate on traces, converting the trace data +/// provided by an \a lldb_private::TraceCursor into a different format that can +/// be digested by other tools, e.g. Chrome Trace Event Profiler. +/// +/// Trace exporters are supposed to operate on an architecture-agnostic fashion, +/// as a TraceCursor, which feeds the data, hides the actual trace technology +/// being used. +class TraceExporter : public PluginInterface { +public: + /// Create an instance of a trace exporter plugin given its name. + /// + /// \param[in] plugin_Name + /// Plug-in name to search. + /// + /// \return + /// A \a TraceExporterUP instance, or an \a llvm::Error if the plug-in + /// name doesn't match any registered plug-ins. + static llvm::Expected + FindPlugin(llvm::StringRef plugin_name); +}; + +} // namespace lldb_private + +#endif // LLDB_TARGET_TRACE_EXPORTER_H diff --git a/gnu/llvm/lldb/include/lldb/Target/TraceInstructionDumper.h b/gnu/llvm/lldb/include/lldb/Target/TraceInstructionDumper.h new file mode 100644 index 00000000000..c4878bfd3fd --- /dev/null +++ b/gnu/llvm/lldb/include/lldb/Target/TraceInstructionDumper.h @@ -0,0 +1,77 @@ +//===-- TraceInstructionDumper.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 +// +//===----------------------------------------------------------------------===// + +#include "lldb/Target/TraceCursor.h" + +#ifndef LLDB_TARGET_TRACE_INSTRUCTION_DUMPER_H +#define LLDB_TARGET_TRACE_INSTRUCTION_DUMPER_H + +namespace lldb_private { + +/// Class used to dump the instructions of a \a TraceCursor using its current +/// state and granularity. +class TraceInstructionDumper { +public: + /// Create a instruction dumper for the cursor. + /// + /// \param[in] cursor + /// The cursor whose instructions will be dumped. + /// + /// \param[in] initial_index + /// Presentation index to use for referring to the current instruction + /// of the cursor. If the direction is forwards, the index will increase, + /// and if the direction is backwards, the index will decrease. + /// + /// \param[in] raw + /// Dump only instruction addresses without disassembly nor symbol + /// information. + /// + /// \param[in] show_tsc + /// For each instruction, print the corresponding timestamp counter if + /// available. + TraceInstructionDumper(lldb::TraceCursorUP &&cursor_up, int initial_index = 0, + bool raw = false, bool show_tsc = false); + + /// Dump \a count instructions of the thread trace starting at the current + /// cursor position. + /// + /// This effectively moves the cursor to the next unvisited position, so that + /// a subsequent call to this method continues where it left off. + /// + /// \param[in] s + /// The stream object where the instructions are printed. + /// + /// \param[in] count + /// The number of instructions to print. + void DumpInstructions(Stream &s, size_t count); + + /// Indicate the dumper that no more data is available in the trace. + void SetNoMoreData(); + + /// \return + /// \b true if there's still more data to traverse in the trace. + bool HasMoreData(); + +private: + /// Move the cursor one step. + /// + /// \return + /// \b true if the cursor moved. + bool TryMoveOneStep(); + + lldb::TraceCursorUP m_cursor_up; + int m_index; + bool m_raw; + bool m_show_tsc; + /// If \b true, all the instructions have been traversed. + bool m_no_more_data = false; +}; + +} // namespace lldb_private + +#endif // LLDB_TARGET_TRACE_INSTRUCTION_DUMPER_H diff --git a/gnu/llvm/lldb/include/lldb/Target/UnixSignals.h b/gnu/llvm/lldb/include/lldb/Target/UnixSignals.h index cc24b76e4c3..6fecdda12de 100644 --- a/gnu/llvm/lldb/include/lldb/Target/UnixSignals.h +++ b/gnu/llvm/lldb/include/lldb/Target/UnixSignals.h @@ -104,7 +104,7 @@ protected: Signal(const char *name, bool default_suppress, bool default_stop, bool default_notify, const char *description, const char *alias); - ~Signal() {} + ~Signal() = default; }; virtual void Reset(); diff --git a/gnu/llvm/lldb/include/lldb/Target/Unwind.h b/gnu/llvm/lldb/include/lldb/Target/Unwind.h index 783b7103e8f..3faef139b00 100644 --- a/gnu/llvm/lldb/include/lldb/Target/Unwind.h +++ b/gnu/llvm/lldb/include/lldb/Target/Unwind.h @@ -21,7 +21,7 @@ protected: Unwind(Thread &thread) : m_thread(thread), m_unwind_mutex() {} public: - virtual ~Unwind() {} + virtual ~Unwind() = default; void Clear() { std::lock_guard guard(m_unwind_mutex); diff --git a/gnu/llvm/lldb/include/lldb/Target/UnwindAssembly.h b/gnu/llvm/lldb/include/lldb/Target/UnwindAssembly.h index abfd3877439..d20aa52d6f5 100644 --- a/gnu/llvm/lldb/include/lldb/Target/UnwindAssembly.h +++ b/gnu/llvm/lldb/include/lldb/Target/UnwindAssembly.h @@ -20,8 +20,6 @@ class UnwindAssembly : public std::enable_shared_from_this, public: static lldb::UnwindAssemblySP FindPlugin(const ArchSpec &arch); - ~UnwindAssembly() override; - virtual bool GetNonCallSiteUnwindPlanFromAssembly(AddressRange &func, Thread &thread, UnwindPlan &unwind_plan) = 0; @@ -42,11 +40,6 @@ public: protected: UnwindAssembly(const ArchSpec &arch); ArchSpec m_arch; - -private: - UnwindAssembly() = delete; - UnwindAssembly(const UnwindAssembly &) = delete; - const UnwindAssembly &operator=(const UnwindAssembly &) = delete; }; } // namespace lldb_private diff --git a/gnu/llvm/lldb/include/lldb/Target/UnwindLLDB.h b/gnu/llvm/lldb/include/lldb/Target/UnwindLLDB.h index c7c9cfbccba..f6750171c54 100644 --- a/gnu/llvm/lldb/include/lldb/Target/UnwindLLDB.h +++ b/gnu/llvm/lldb/include/lldb/Target/UnwindLLDB.h @@ -109,17 +109,17 @@ protected: private: struct Cursor { - lldb::addr_t start_pc; // The start address of the function/symbol for this - // frame - current pc if unknown - lldb::addr_t cfa; // The canonical frame address for this stack frame + lldb::addr_t start_pc = + LLDB_INVALID_ADDRESS; // The start address of the function/symbol for + // this frame - current pc if unknown + lldb::addr_t cfa = LLDB_INVALID_ADDRESS; // The canonical frame address for + // this stack frame lldb_private::SymbolContext sctx; // A symbol context we'll contribute to & // provide to the StackFrame creation RegisterContextLLDBSP reg_ctx_lldb_sp; // These are all RegisterContextUnwind's - Cursor() - : start_pc(LLDB_INVALID_ADDRESS), cfa(LLDB_INVALID_ADDRESS), sctx(), - reg_ctx_lldb_sp() {} + Cursor() : sctx(), reg_ctx_lldb_sp() {} private: Cursor(const Cursor &) = delete; diff --git a/gnu/llvm/lldb/include/lldb/Utility/Args.h b/gnu/llvm/lldb/include/lldb/Utility/Args.h index 2cce7d0c697..cecf6b1502b 100644 --- a/gnu/llvm/lldb/include/lldb/Utility/Args.h +++ b/gnu/llvm/lldb/include/lldb/Utility/Args.h @@ -66,6 +66,7 @@ public: Args(const Args &rhs); explicit Args(const StringList &list); + explicit Args(llvm::ArrayRef args); Args &operator=(const Args &rhs); @@ -114,7 +115,8 @@ public: /// /// \return /// The number or arguments in this object. - size_t GetArgumentCount() const; + size_t GetArgumentCount() const { return m_entries.size(); } + bool empty() const { return GetArgumentCount() == 0; } /// Gets the NULL terminated C string argument pointer for the argument at @@ -251,9 +253,9 @@ public: /// If the argument was originally quoted, put in the quote char here. void Unshift(llvm::StringRef arg_str, char quote_char = '\0'); - // Clear the arguments. - // - // For re-setting or blanking out the list of arguments. + /// Clear the arguments. + /// + /// For re-setting or blanking out the list of arguments. void Clear(); static lldb::Encoding @@ -262,25 +264,23 @@ public: static uint32_t StringToGenericRegister(llvm::StringRef s); - static const char *GetShellSafeArgument(const FileSpec &shell, - const char *unsafe_arg, - std::string &safe_arg); - - // EncodeEscapeSequences will change the textual representation of common - // escape sequences like "\n" (two characters) into a single '\n'. It does - // this for all of the supported escaped sequences and for the \0ooo (octal) - // and \xXX (hex). The resulting "dst" string will contain the character - // versions of all supported escape sequences. The common supported escape - // sequences are: "\a", "\b", "\f", "\n", "\r", "\t", "\v", "\'", "\"", "\\". + static std::string GetShellSafeArgument(const FileSpec &shell, + llvm::StringRef unsafe_arg); + /// EncodeEscapeSequences will change the textual representation of common + /// escape sequences like "\n" (two characters) into a single '\n'. It does + /// this for all of the supported escaped sequences and for the \0ooo (octal) + /// and \xXX (hex). The resulting "dst" string will contain the character + /// versions of all supported escape sequences. The common supported escape + /// sequences are: "\a", "\b", "\f", "\n", "\r", "\t", "\v", "\'", "\"", "\\". static void EncodeEscapeSequences(const char *src, std::string &dst); - // ExpandEscapeSequences will change a string of possibly non-printable - // characters and expand them into text. So '\n' will turn into two - // characters like "\n" which is suitable for human reading. When a character - // is not printable and isn't one of the common in escape sequences listed in - // the help for EncodeEscapeSequences, then it will be encoded as octal. - // Printable characters are left alone. + /// ExpandEscapeSequences will change a string of possibly non-printable + /// characters and expand them into text. So '\n' will turn into two + /// characters like "\n" which is suitable for human reading. When a character + /// is not printable and isn't one of the common in escape sequences listed in + /// the help for EncodeEscapeSequences, then it will be encoded as octal. + /// Printable characters are left alone. static void ExpandEscapedCharacters(const char *src, std::string &dst); static std::string EscapeLLDBCommandArgument(const std::string &arg, @@ -290,6 +290,10 @@ private: friend struct llvm::yaml::MappingTraits; std::vector m_entries; + /// The arguments as C strings with a trailing nullptr element. + /// + /// These strings are owned by the ArgEntry object in m_entries with the + /// same index. std::vector m_argv; }; diff --git a/gnu/llvm/lldb/include/lldb/Utility/Baton.h b/gnu/llvm/lldb/include/lldb/Utility/Baton.h index 010f8da4386..8a2f0416368 100644 --- a/gnu/llvm/lldb/include/lldb/Utility/Baton.h +++ b/gnu/llvm/lldb/include/lldb/Utility/Baton.h @@ -34,8 +34,8 @@ namespace lldb_private { /// needed resources in their destructors. class Baton { public: - Baton() {} - virtual ~Baton() {} + Baton() = default; + virtual ~Baton() = default; virtual void *data() = 0; diff --git a/gnu/llvm/lldb/include/lldb/Utility/Broadcaster.h b/gnu/llvm/lldb/include/lldb/Utility/Broadcaster.h index 03995454ecb..9c025a7c7dd 100644 --- a/gnu/llvm/lldb/include/lldb/Utility/Broadcaster.h +++ b/gnu/llvm/lldb/include/lldb/Utility/Broadcaster.h @@ -39,7 +39,7 @@ namespace lldb_private { /// Debugger maintains a list of BroadcastEventSpec's and when it is made class BroadcastEventSpec { public: - BroadcastEventSpec(ConstString broadcaster_class, uint32_t event_bits) + BroadcastEventSpec(const ConstString &broadcaster_class, uint32_t event_bits) : m_broadcaster_class(broadcaster_class), m_event_bits(event_bits) {} ~BroadcastEventSpec() = default; @@ -117,7 +117,7 @@ private: class BroadcasterClassMatches { public: - BroadcasterClassMatches(ConstString broadcaster_class) + BroadcasterClassMatches(const ConstString &broadcaster_class) : m_broadcaster_class(broadcaster_class) {} ~BroadcasterClassMatches() = default; diff --git a/gnu/llvm/lldb/include/lldb/Utility/Cloneable.h b/gnu/llvm/lldb/include/lldb/Utility/Cloneable.h new file mode 100644 index 00000000000..4c9b7ae340d --- /dev/null +++ b/gnu/llvm/lldb/include/lldb/Utility/Cloneable.h @@ -0,0 +1,56 @@ +//===-- Cloneable.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_UTILITY_CLONEABLE_H +#define LLDB_UTILITY_CLONEABLE_H + +#include +#include + +namespace lldb_private { + +/// \class Cloneable Cloneable.h "lldb/Utility/Cloneable.h" +/// A class that implements CRTP-based "virtual constructor" idiom. +/// +/// Example: +/// @code +/// class Base { +/// using TopmostBase = Base; +/// public: +/// virtual std::shared_ptr Clone() const = 0; +/// }; +/// @endcode +/// +/// To define a class derived from the Base with overridden Clone: +/// @code +/// class Intermediate : public Cloneable {}; +/// @endcode +/// +/// To define a class at the next level of inheritance with overridden Clone: +/// @code +/// class Derived : public Cloneable {}; +/// @endcode + +template +class Cloneable : public Base { +public: + using Base::Base; + + std::shared_ptr Clone() const override { + // std::is_base_of requires derived type to be complete, that's why class + // scope static_assert cannot be used. + static_assert(std::is_base_of::value, + "Derived class must be derived from this."); + + return std::make_shared(static_cast(*this)); + } +}; + +} // namespace lldb_private + +#endif // LLDB_UTILITY_CLONEABLE_H diff --git a/gnu/llvm/lldb/include/lldb/Utility/Connection.h b/gnu/llvm/lldb/include/lldb/Utility/Connection.h index 39e6e40191b..0b587b81c99 100644 --- a/gnu/llvm/lldb/include/lldb/Utility/Connection.h +++ b/gnu/llvm/lldb/include/lldb/Utility/Connection.h @@ -18,7 +18,7 @@ #include #include -#include +#include namespace lldb_private { class Status; diff --git a/gnu/llvm/lldb/include/lldb/Utility/ConstString.h b/gnu/llvm/lldb/include/lldb/Utility/ConstString.h index 1e55b2ebb95..52d3556418f 100644 --- a/gnu/llvm/lldb/include/lldb/Utility/ConstString.h +++ b/gnu/llvm/lldb/include/lldb/Utility/ConstString.h @@ -14,7 +14,7 @@ #include "llvm/Support/FormatVariadic.h" #include "llvm/Support/YAMLTraits.h" -#include +#include namespace lldb_private { class Stream; @@ -42,15 +42,7 @@ public: /// Default constructor /// /// Initializes the string to an empty string. - ConstString() : m_string(nullptr) {} - - /// Copy constructor - /// - /// Copies the string value in \a rhs into this object. - /// - /// \param[in] rhs - /// Another string object to copy. - ConstString(const ConstString &rhs) : m_string(rhs.m_string) {} + ConstString() = default; explicit ConstString(const llvm::StringRef &s); @@ -86,12 +78,6 @@ public: /// from \a cstr. explicit ConstString(const char *cstr, size_t max_cstr_len); - /// Destructor - /// - /// Since constant string values are currently not reference counted, there - /// isn't much to do here. - ~ConstString() = default; - /// C string equality binary predicate function object for ConstString /// objects. struct StringIsEqual { @@ -124,20 +110,6 @@ public: /// false otherwise. explicit operator bool() const { return !IsEmpty(); } - /// Assignment operator - /// - /// Assigns the string in this object with the value from \a rhs. - /// - /// \param[in] rhs - /// Another string object to copy into this object. - /// - /// \return - /// A const reference to this object. - ConstString operator=(ConstString rhs) { - m_string = rhs.m_string; - return *this; - } - /// Equal to operator /// /// Returns true if this string is equal to the string in \a rhs. This @@ -192,9 +164,7 @@ public: /// \return /// \b true if this object is not equal to \a rhs. /// \b false if this object is equal to \a rhs. - bool operator!=(ConstString rhs) const { - return m_string != rhs.m_string; - } + bool operator!=(ConstString rhs) const { return m_string != rhs.m_string; } /// Not equal to operator against a non-ConstString value. /// @@ -447,8 +417,7 @@ protected: return s; }; - // Member variables - const char *m_string; + const char *m_string = nullptr; }; /// Stream the string value \a str to the stream \a s diff --git a/gnu/llvm/lldb/include/lldb/Utility/DataBuffer.h b/gnu/llvm/lldb/include/lldb/Utility/DataBuffer.h index 302b1330795..c778299b89a 100644 --- a/gnu/llvm/lldb/include/lldb/Utility/DataBuffer.h +++ b/gnu/llvm/lldb/include/lldb/Utility/DataBuffer.h @@ -10,8 +10,8 @@ #define LLDB_UTILITY_DATABUFFER_H #if defined(__cplusplus) -#include -#include +#include +#include #include "lldb/lldb-types.h" @@ -48,7 +48,7 @@ public: /// and be downcast to the DataBuffer pure virtual interface. The virtual /// destructor ensures that destructing the base class will destruct the /// class that inherited from it correctly. - virtual ~DataBuffer() {} + virtual ~DataBuffer() = default; /// Get a pointer to the data. /// diff --git a/gnu/llvm/lldb/include/lldb/Utility/DataBufferLLVM.h b/gnu/llvm/lldb/include/lldb/Utility/DataBufferLLVM.h index 4dc800c348c..abb1bb40d53 100644 --- a/gnu/llvm/lldb/include/lldb/Utility/DataBufferLLVM.h +++ b/gnu/llvm/lldb/include/lldb/Utility/DataBufferLLVM.h @@ -12,8 +12,8 @@ #include "lldb/Utility/DataBuffer.h" #include "lldb/lldb-types.h" +#include #include -#include namespace llvm { class WritableMemoryBuffer; diff --git a/gnu/llvm/lldb/include/lldb/Utility/DataEncoder.h b/gnu/llvm/lldb/include/lldb/Utility/DataEncoder.h index 8edec54c36f..b944c09d5c4 100644 --- a/gnu/llvm/lldb/include/lldb/Utility/DataEncoder.h +++ b/gnu/llvm/lldb/include/lldb/Utility/DataEncoder.h @@ -16,8 +16,8 @@ #include "lldb/lldb-forward.h" #include "lldb/lldb-types.h" -#include -#include +#include +#include namespace lldb_private { @@ -226,10 +226,10 @@ private: size_t GetByteSize() const { return m_end - m_start; } /// A pointer to the first byte of data. - uint8_t *m_start; + uint8_t *m_start = nullptr; /// A pointer to the byte that is past the end of the data. - uint8_t *m_end; + uint8_t *m_end = nullptr; /// The byte order of the data we are extracting from. lldb::ByteOrder m_byte_order; diff --git a/gnu/llvm/lldb/include/lldb/Utility/DataExtractor.h b/gnu/llvm/lldb/include/lldb/Utility/DataExtractor.h index 0210af5cf6d..0923e5280cb 100644 --- a/gnu/llvm/lldb/include/lldb/Utility/DataExtractor.h +++ b/gnu/llvm/lldb/include/lldb/Utility/DataExtractor.h @@ -19,8 +19,8 @@ #include "llvm/Support/SwapByteOrder.h" #include -#include -#include +#include +#include namespace lldb_private { class Log; @@ -997,15 +997,15 @@ protected: } // Member variables - const uint8_t *m_start; ///< A pointer to the first byte of data. - const uint8_t - *m_end; ///< A pointer to the byte that is past the end of the data. + const uint8_t *m_start = nullptr; ///< A pointer to the first byte of data. + const uint8_t *m_end = + nullptr; ///< A pointer to the byte that is past the end of the data. lldb::ByteOrder m_byte_order; ///< The byte order of the data we are extracting from. uint32_t m_addr_size; ///< The address size to use when extracting addresses. /// The shared pointer to data that can be shared among multiple instances lldb::DataBufferSP m_data_sp; - const uint32_t m_target_byte_size; + const uint32_t m_target_byte_size = 1; }; } // namespace lldb_private diff --git a/gnu/llvm/lldb/include/lldb/Utility/Endian.h b/gnu/llvm/lldb/include/lldb/Utility/Endian.h index 1d1f8fa333b..7822dfa766d 100644 --- a/gnu/llvm/lldb/include/lldb/Utility/Endian.h +++ b/gnu/llvm/lldb/include/lldb/Utility/Endian.h @@ -11,7 +11,7 @@ #include "lldb/lldb-enumerations.h" -#include +#include namespace lldb_private { diff --git a/gnu/llvm/lldb/include/lldb/Utility/Event.h b/gnu/llvm/lldb/include/lldb/Utility/Event.h index 06c02629d44..4e38f98a02f 100644 --- a/gnu/llvm/lldb/include/lldb/Utility/Event.h +++ b/gnu/llvm/lldb/include/lldb/Utility/Event.h @@ -22,8 +22,8 @@ #include #include -#include -#include +#include +#include namespace lldb_private { class Event; @@ -101,7 +101,7 @@ class EventDataReceipt : public EventData { public: EventDataReceipt() : EventData(), m_predicate(false) {} - ~EventDataReceipt() override {} + ~EventDataReceipt() override = default; static ConstString GetFlavorString() { static ConstString g_flavor("Process::ProcessEventData"); diff --git a/gnu/llvm/lldb/include/lldb/Utility/FileSpec.h b/gnu/llvm/lldb/include/lldb/Utility/FileSpec.h index f7cbeb24710..0f4e6505e43 100644 --- a/gnu/llvm/lldb/include/lldb/Utility/FileSpec.h +++ b/gnu/llvm/lldb/include/lldb/Utility/FileSpec.h @@ -20,8 +20,8 @@ #include "llvm/Support/Path.h" #include "llvm/Support/YAMLTraits.h" -#include -#include +#include +#include namespace lldb_private { class Stream; @@ -38,7 +38,7 @@ template class SmallVectorImpl; namespace lldb_private { -/// \class FileSpec FileSpec.h "lldb/Host/FileSpec.h" +/// \class FileSpec FileSpec.h "lldb/Utility/FileSpec.h" /// A file utility class. /// /// A file specification class that divides paths up into a directory diff --git a/gnu/llvm/lldb/include/lldb/Utility/GDBRemote.h b/gnu/llvm/lldb/include/lldb/Utility/GDBRemote.h index f5749b7e6ea..f658818de80 100644 --- a/gnu/llvm/lldb/include/lldb/Utility/GDBRemote.h +++ b/gnu/llvm/lldb/include/lldb/Utility/GDBRemote.h @@ -10,15 +10,15 @@ #define LLDB_UTILITY_GDBREMOTE_H #include "lldb/Utility/FileSpec.h" -#include "lldb/Utility/Reproducer.h" +#include "lldb/Utility/ReproducerProvider.h" #include "lldb/Utility/StreamString.h" #include "lldb/lldb-enumerations.h" #include "lldb/lldb-public.h" #include "llvm/Support/YAMLTraits.h" #include "llvm/Support/raw_ostream.h" -#include -#include +#include +#include #include #include @@ -55,9 +55,7 @@ struct GDBRemotePacket { enum Type { ePacketTypeInvalid = 0, ePacketTypeSend, ePacketTypeRecv }; - GDBRemotePacket() - : packet(), type(ePacketTypeInvalid), bytes_transmitted(0), packet_idx(0), - tid(LLDB_INVALID_THREAD_ID) {} + GDBRemotePacket() : packet() {} void Clear() { packet.data.clear(); @@ -74,10 +72,10 @@ struct GDBRemotePacket { void Dump(Stream &strm) const; BinaryData packet; - Type type; - uint32_t bytes_transmitted; - uint32_t packet_idx; - lldb::tid_t tid; + Type type = ePacketTypeInvalid; + uint32_t bytes_transmitted = 0; + uint32_t packet_idx = 0; + lldb::tid_t tid = LLDB_INVALID_THREAD_ID; private: llvm::StringRef GetTypeStr() const; diff --git a/gnu/llvm/lldb/include/lldb/Utility/IOObject.h b/gnu/llvm/lldb/include/lldb/Utility/IOObject.h index 9b2b9cfcfec..8cf42992e7b 100644 --- a/gnu/llvm/lldb/include/lldb/Utility/IOObject.h +++ b/gnu/llvm/lldb/include/lldb/Utility/IOObject.h @@ -9,8 +9,8 @@ #ifndef LLDB_UTILITY_IOOBJECT_H #define LLDB_UTILITY_IOOBJECT_H -#include -#include +#include +#include #include #include "lldb/lldb-private.h" diff --git a/gnu/llvm/lldb/include/lldb/Utility/Iterable.h b/gnu/llvm/lldb/include/lldb/Utility/Iterable.h index 3f9b8b1e4c5..5c38e46feb9 100644 --- a/gnu/llvm/lldb/include/lldb/Utility/Iterable.h +++ b/gnu/llvm/lldb/include/lldb/Utility/Iterable.h @@ -170,7 +170,7 @@ template class LockingAdaptedIterable : public AdaptedIterable { public: - LockingAdaptedIterable(C &container, MutexType &mutex) + LockingAdaptedIterable(const C &container, MutexType &mutex) : AdaptedIterable(container), m_mutex(&mutex) { m_mutex->lock(); } diff --git a/gnu/llvm/lldb/include/lldb/Utility/LLDBAssert.h b/gnu/llvm/lldb/include/lldb/Utility/LLDBAssert.h index 845af1d4cc2..471a2f7e824 100644 --- a/gnu/llvm/lldb/include/lldb/Utility/LLDBAssert.h +++ b/gnu/llvm/lldb/include/lldb/Utility/LLDBAssert.h @@ -20,6 +20,6 @@ namespace lldb_private { void lldb_assert(bool expression, const char *expr_text, const char *func, const char *file, unsigned int line); -} +} // namespace lldb_private #endif // LLDB_UTILITY_LLDBASSERT_H diff --git a/gnu/llvm/lldb/include/lldb/Utility/Listener.h b/gnu/llvm/lldb/include/lldb/Utility/Listener.h index 9d96e36c5ab..d70e778c948 100644 --- a/gnu/llvm/lldb/include/lldb/Utility/Listener.h +++ b/gnu/llvm/lldb/include/lldb/Utility/Listener.h @@ -23,8 +23,8 @@ #include #include -#include -#include +#include +#include namespace lldb_private { class ConstString; diff --git a/gnu/llvm/lldb/include/lldb/Utility/OptionDefinition.h b/gnu/llvm/lldb/include/lldb/Utility/OptionDefinition.h new file mode 100644 index 00000000000..082f0f0aa3f --- /dev/null +++ b/gnu/llvm/lldb/include/lldb/Utility/OptionDefinition.h @@ -0,0 +1,58 @@ +//===-- OptionDefinition.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_UTILITY_OPTIONDEFINITION_H +#define LLDB_UTILITY_OPTIONDEFINITION_H + +#include "lldb/lldb-enumerations.h" +#include "lldb/lldb-private-types.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/Support/MathExtras.h" +#include +#include + +namespace lldb_private { +struct OptionDefinition { + /// Used to mark options that can be used together. If + /// `(1 << n & usage_mask) != 0` then this option belongs to option set n. + uint32_t usage_mask; + /// This option is required (in the current usage level). + bool required; + /// Full name for this option. + const char *long_option; + /// Single character for this option. If the option doesn't use a short + /// option character, this has to be a integer value that is not a printable + /// ASCII code point and also unique in the used set of options. + /// @see OptionDefinition::HasShortOption + int short_option; + /// no_argument, required_argument or optional_argument + int option_has_arg; + /// If non-NULL, option is valid iff |validator->IsValid()|, otherwise + /// always valid. + OptionValidator *validator; + /// If not empty, an array of enum values. + OptionEnumValues enum_values; + /// The kind of completion for this option. + /// Contains values of the CommandCompletions::CommonCompletionTypes enum. + uint32_t completion_type; + /// Type of argument this option takes. + lldb::CommandArgumentType argument_type; + /// Full text explaining what this options does and what (if any) argument to + /// pass it. + const char *usage_text; + + /// Whether this has a short option character. + bool HasShortOption() const { + // See the short_option documentation for more. + return llvm::isUInt(short_option) && + llvm::isPrint(short_option); + } +}; +} // namespace lldb_private + +#endif // LLDB_UTILITY_OPTIONDEFINITION_H diff --git a/gnu/llvm/lldb/include/lldb/Utility/Predicate.h b/gnu/llvm/lldb/include/lldb/Utility/Predicate.h index a17ac05f6e5..af16abc1a1d 100644 --- a/gnu/llvm/lldb/include/lldb/Utility/Predicate.h +++ b/gnu/llvm/lldb/include/lldb/Utility/Predicate.h @@ -9,8 +9,8 @@ #ifndef LLDB_UTILITY_PREDICATE_H #define LLDB_UTILITY_PREDICATE_H -#include -#include +#include +#include #include #include diff --git a/gnu/llvm/lldb/include/lldb/Utility/ProcessInfo.h b/gnu/llvm/lldb/include/lldb/Utility/ProcessInfo.h index ec91060cda5..3c595692639 100644 --- a/gnu/llvm/lldb/include/lldb/Utility/ProcessInfo.h +++ b/gnu/llvm/lldb/include/lldb/Utility/ProcessInfo.h @@ -14,7 +14,6 @@ #include "lldb/Utility/Environment.h" #include "lldb/Utility/FileSpec.h" #include "lldb/Utility/NameMatches.h" -#include "lldb/Utility/Reproducer.h" #include "llvm/Support/YAMLTraits.h" #include @@ -96,10 +95,10 @@ protected: // the resolved platform executable (which is in m_executable) Args m_arguments; // All program arguments except argv[0] Environment m_environment; - uint32_t m_uid; - uint32_t m_gid; + uint32_t m_uid = UINT32_MAX; + uint32_t m_gid = UINT32_MAX; ArchSpec m_arch; - lldb::pid_t m_pid; + lldb::pid_t m_pid = LLDB_INVALID_PROCESS_ID; }; // ProcessInstanceInfo @@ -108,9 +107,7 @@ protected: // to that process. class ProcessInstanceInfo : public ProcessInfo { public: - ProcessInstanceInfo() - : ProcessInfo(), m_euid(UINT32_MAX), m_egid(UINT32_MAX), - m_parent_pid(LLDB_INVALID_PROCESS_ID) {} + ProcessInstanceInfo() : ProcessInfo() {} ProcessInstanceInfo(const char *name, const ArchSpec &arch, lldb::pid_t pid) : ProcessInfo(name, arch, pid), m_euid(UINT32_MAX), m_egid(UINT32_MAX), @@ -152,9 +149,9 @@ public: protected: friend struct llvm::yaml::MappingTraits; - uint32_t m_euid; - uint32_t m_egid; - lldb::pid_t m_parent_pid; + uint32_t m_euid = UINT32_MAX; + uint32_t m_egid = UINT32_MAX; + lldb::pid_t m_parent_pid = LLDB_INVALID_PROCESS_ID; }; typedef std::vector ProcessInstanceInfoList; @@ -165,9 +162,7 @@ typedef std::vector ProcessInstanceInfoList; class ProcessInstanceInfoMatch { public: - ProcessInstanceInfoMatch() - : m_match_info(), m_name_match_type(NameMatch::Ignore), - m_match_all_users(false) {} + ProcessInstanceInfoMatch() : m_match_info() {} ProcessInstanceInfoMatch(const char *process_name, NameMatch process_name_match_type) @@ -212,45 +207,12 @@ public: protected: ProcessInstanceInfo m_match_info; - NameMatch m_name_match_type; - bool m_match_all_users; + NameMatch m_name_match_type = NameMatch::Ignore; + bool m_match_all_users = false; }; namespace repro { -class ProcessInfoRecorder : public AbstractRecorder { -public: - ProcessInfoRecorder(const FileSpec &filename, std::error_code &ec) - : AbstractRecorder(filename, ec) {} - - static llvm::Expected> - Create(const FileSpec &filename); - - void Record(const ProcessInstanceInfoList &process_infos); -}; - -class ProcessInfoProvider : public repro::Provider { -public: - struct Info { - static const char *name; - static const char *file; - }; - - ProcessInfoProvider(const FileSpec &directory) : Provider(directory) {} - - ProcessInfoRecorder *GetNewProcessInfoRecorder(); - - void Keep() override; - void Discard() override; - - static char ID; - -private: - std::unique_ptr m_stream_up; - std::vector> m_process_info_recorders; -}; - llvm::Optional GetReplayProcessInstanceInfoList(); - } // namespace repro } // namespace lldb_private diff --git a/gnu/llvm/lldb/include/lldb/Utility/RangeMap.h b/gnu/llvm/lldb/include/lldb/Utility/RangeMap.h index fb24c5a4347..118fdfd85fa 100644 --- a/gnu/llvm/lldb/include/lldb/Utility/RangeMap.h +++ b/gnu/llvm/lldb/include/lldb/Utility/RangeMap.h @@ -194,41 +194,25 @@ public: #ifdef ASSERT_RANGEMAP_ARE_SORTED assert(IsSorted()); #endif - // Can't combine if ranges if we have zero or one range - if (m_entries.size() > 1) { - // The list should be sorted prior to calling this function - typename Collection::iterator pos; - typename Collection::iterator end; - typename Collection::iterator prev; - bool can_combine = false; - // First we determine if we can combine any of the Entry objects so we - // don't end up allocating and making a new collection for no reason - for (pos = m_entries.begin(), end = m_entries.end(), prev = end; - pos != end; prev = pos++) { - if (prev != end && prev->DoesAdjoinOrIntersect(*pos)) { - can_combine = true; - break; - } - } + auto first_intersect = std::adjacent_find( + m_entries.begin(), m_entries.end(), [](const Entry &a, const Entry &b) { + return a.DoesAdjoinOrIntersect(b); + }); + if (first_intersect == m_entries.end()) + return; - // We we can combine at least one entry, then we make a new collection - // and populate it accordingly, and then swap it into place. - if (can_combine) { - Collection minimal_ranges; - for (pos = m_entries.begin(), end = m_entries.end(), prev = end; - pos != end; prev = pos++) { - if (prev != end && prev->DoesAdjoinOrIntersect(*pos)) - minimal_ranges.back().SetRangeEnd( - std::max(prev->GetRangeEnd(), pos->GetRangeEnd())); - else - minimal_ranges.push_back(*pos); - } - // Use the swap technique in case our new vector is much smaller. We - // must swap when using the STL because std::vector objects never - // release or reduce the memory once it has been allocated/reserved. - m_entries.swap(minimal_ranges); - } + // We we can combine at least one entry, then we make a new collection and + // populate it accordingly, and then swap it into place. + auto pos = std::next(first_intersect); + Collection minimal_ranges(m_entries.begin(), pos); + for (; pos != m_entries.end(); ++pos) { + Entry &back = minimal_ranges.back(); + if (back.DoesAdjoinOrIntersect(*pos)) + back.SetRangeEnd(std::max(back.GetRangeEnd(), pos->GetRangeEnd())); + else + minimal_ranges.push_back(*pos); } + m_entries.swap(minimal_ranges); } BaseType GetMinRangeBase(BaseType fail_value) const { @@ -353,6 +337,10 @@ public: return nullptr; } + using const_iterator = typename Collection::const_iterator; + const_iterator begin() const { return m_entries.begin(); } + const_iterator end() const { return m_entries.end(); } + protected: void CombinePrevAndNext(typename Collection::iterator pos) { // Check if the prev or next entries in case they need to be unioned with diff --git a/gnu/llvm/lldb/include/lldb/Utility/RegisterValue.h b/gnu/llvm/lldb/include/lldb/Utility/RegisterValue.h index c9f295a8d95..1ece4f0eb79 100644 --- a/gnu/llvm/lldb/include/lldb/Utility/RegisterValue.h +++ b/gnu/llvm/lldb/include/lldb/Utility/RegisterValue.h @@ -18,6 +18,7 @@ #include "llvm/ADT/StringRef.h" #include #include +#include namespace lldb_private { class DataExtractor; @@ -42,8 +43,7 @@ public: eTypeBytes }; - RegisterValue() - : m_type(eTypeInvalid), m_scalar(static_cast(0)) {} + RegisterValue() : m_scalar(static_cast(0)) {} explicit RegisterValue(uint8_t inst) : m_type(eTypeUInt8) { m_scalar = inst; } @@ -60,7 +60,7 @@ public: } explicit RegisterValue(llvm::APInt inst) : m_type(eTypeUInt128) { - m_scalar = llvm::APInt(inst); + m_scalar = llvm::APInt(std::move(inst)); } explicit RegisterValue(float value) : m_type(eTypeFloat) { m_scalar = value; } @@ -73,9 +73,9 @@ public: m_scalar = value; } - explicit RegisterValue(uint8_t *bytes, size_t length, + explicit RegisterValue(llvm::ArrayRef bytes, lldb::ByteOrder byte_order) { - SetBytes(bytes, length, byte_order); + SetBytes(bytes.data(), bytes.size(), byte_order); } RegisterValue::Type GetType() const { return m_type; } @@ -169,7 +169,7 @@ public: void operator=(llvm::APInt uint) { m_type = eTypeUInt128; - m_scalar = llvm::APInt(uint); + m_scalar = llvm::APInt(std::move(uint)); } void operator=(float f) { @@ -209,7 +209,7 @@ public: void SetUInt128(llvm::APInt uint) { m_type = eTypeUInt128; - m_scalar = uint; + m_scalar = std::move(uint); } bool SetUInt(uint64_t uint, uint32_t byte_size); @@ -256,7 +256,7 @@ public: void Clear(); protected: - RegisterValue::Type m_type; + RegisterValue::Type m_type = eTypeInvalid; Scalar m_scalar; struct { diff --git a/gnu/llvm/lldb/include/lldb/Utility/Reproducer.h b/gnu/llvm/lldb/include/lldb/Utility/Reproducer.h index ab673e5e001..4659254e57d 100644 --- a/gnu/llvm/lldb/include/lldb/Utility/Reproducer.h +++ b/gnu/llvm/lldb/include/lldb/Utility/Reproducer.h @@ -11,15 +11,18 @@ #include "lldb/Utility/FileSpec.h" #include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/StringRef.h" #include "llvm/Support/Error.h" -#include "llvm/Support/FileCollector.h" +#include "llvm/Support/VirtualFileSystem.h" #include "llvm/Support/YAMLTraits.h" #include #include +#include #include namespace lldb_private { +class UUID; namespace repro { class Reproducer; @@ -82,211 +85,6 @@ protected: using ProviderBase::ProviderBase; // Inherit constructor. }; -class FileProvider : public Provider { -public: - struct Info { - static const char *name; - static const char *file; - }; - - FileProvider(const FileSpec &directory) - : Provider(directory), - m_collector(std::make_shared( - directory.CopyByAppendingPathComponent("root").GetPath(), - directory.GetPath())) {} - - std::shared_ptr GetFileCollector() { - return m_collector; - } - - void recordInterestingDirectory(const llvm::Twine &dir); - - void Keep() override { - auto mapping = GetRoot().CopyByAppendingPathComponent(Info::file); - // Temporary files that are removed during execution can cause copy errors. - if (auto ec = m_collector->copyFiles(/*stop_on_error=*/false)) - return; - m_collector->writeMapping(mapping.GetPath()); - } - - static char ID; - -private: - std::shared_ptr m_collector; -}; - -/// Provider for the LLDB version number. -/// -/// When the reproducer is kept, it writes the lldb version to a file named -/// version.txt in the reproducer root. -class VersionProvider : public Provider { -public: - VersionProvider(const FileSpec &directory) : Provider(directory) {} - struct Info { - static const char *name; - static const char *file; - }; - void SetVersion(std::string version) { - assert(m_version.empty()); - m_version = std::move(version); - } - void Keep() override; - std::string m_version; - static char ID; -}; - -/// Provider for the LLDB current working directory. -/// -/// When the reproducer is kept, it writes lldb's current working directory to -/// a file named cwd.txt in the reproducer root. -class WorkingDirectoryProvider : public Provider { -public: - WorkingDirectoryProvider(const FileSpec &directory) : Provider(directory) { - llvm::SmallString<128> cwd; - if (std::error_code EC = llvm::sys::fs::current_path(cwd)) - return; - m_cwd = std::string(cwd.str()); - } - - void Update(llvm::StringRef path) { m_cwd = std::string(path); } - - struct Info { - static const char *name; - static const char *file; - }; - void Keep() override; - std::string m_cwd; - static char ID; -}; - -/// The recorder is a small object handed out by a provider to record data. It -/// is commonly used in combination with a MultiProvider which is meant to -/// record information for multiple instances of the same source of data. -class AbstractRecorder { -protected: - AbstractRecorder(const FileSpec &filename, std::error_code &ec) - : m_filename(filename.GetFilename().GetStringRef()), - m_os(filename.GetPath(), ec, llvm::sys::fs::OF_Text), m_record(true) {} - -public: - const FileSpec &GetFilename() { return m_filename; } - - void Stop() { - assert(m_record); - m_record = false; - } - -private: - FileSpec m_filename; - -protected: - llvm::raw_fd_ostream m_os; - bool m_record; -}; - -/// Recorder that records its data as text to a file. -class DataRecorder : public AbstractRecorder { -public: - DataRecorder(const FileSpec &filename, std::error_code &ec) - : AbstractRecorder(filename, ec) {} - - static llvm::Expected> - Create(const FileSpec &filename); - - template void Record(const T &t, bool newline = false) { - if (!m_record) - return; - m_os << t; - if (newline) - m_os << '\n'; - m_os.flush(); - } -}; - -/// Recorder that records its data as YAML to a file. -class YamlRecorder : public AbstractRecorder { -public: - YamlRecorder(const FileSpec &filename, std::error_code &ec) - : AbstractRecorder(filename, ec) {} - - static llvm::Expected> - Create(const FileSpec &filename); - - template void Record(const T &t) { - if (!m_record) - return; - llvm::yaml::Output yout(m_os); - // The YAML traits are defined as non-const because they are used for - // serialization and deserialization. The cast is safe because - // serialization doesn't modify the object. - yout << const_cast(t); - m_os.flush(); - } -}; - -/// The MultiProvider is a provider that hands out recorder which can be used -/// to capture data for different instances of the same object. The recorders -/// can be passed around or stored as an instance member. -/// -/// The Info::file for the MultiProvider contains an index of files for every -/// recorder. Use the MultiLoader to read the index and get the individual -/// files. -template -class MultiProvider : public repro::Provider { -public: - MultiProvider(const FileSpec &directory) : Provider(directory) {} - - T *GetNewRecorder() { - std::size_t i = m_recorders.size() + 1; - std::string filename = (llvm::Twine(V::Info::name) + llvm::Twine("-") + - llvm::Twine(i) + llvm::Twine(".yaml")) - .str(); - auto recorder_or_error = - T::Create(this->GetRoot().CopyByAppendingPathComponent(filename)); - if (!recorder_or_error) { - llvm::consumeError(recorder_or_error.takeError()); - return nullptr; - } - - m_recorders.push_back(std::move(*recorder_or_error)); - return m_recorders.back().get(); - } - - void Keep() override { - std::vector files; - for (auto &recorder : m_recorders) { - recorder->Stop(); - files.push_back(recorder->GetFilename().GetPath()); - } - - FileSpec file = this->GetRoot().CopyByAppendingPathComponent(V::Info::file); - std::error_code ec; - llvm::raw_fd_ostream os(file.GetPath(), ec, llvm::sys::fs::OF_Text); - if (ec) - return; - llvm::yaml::Output yout(os); - yout << files; - } - - void Discard() override { m_recorders.clear(); } - -private: - std::vector> m_recorders; -}; - -class CommandProvider : public MultiProvider { -public: - struct Info { - static const char *name; - static const char *file; - }; - - CommandProvider(const FileSpec &directory) - : MultiProvider(directory) {} - - static char ID; -}; - /// The generator is responsible for the logic needed to generate a /// reproducer. For doing so it relies on providers, who serialize data that /// is necessary for reproducing a failure. @@ -399,6 +197,7 @@ public: static Reproducer &Instance(); static llvm::Error Initialize(ReproducerMode mode, llvm::Optional root); + static void Initialize(); static bool Initialized(); static void Terminate(); @@ -428,51 +227,25 @@ private: mutable std::mutex m_mutex; }; -/// Loader for data captured with the MultiProvider. It will read the index and -/// return the path to the files in the index. -template class MultiLoader { +class Verifier { public: - MultiLoader(std::vector files) : m_files(files) {} - - static std::unique_ptr Create(Loader *loader) { - if (!loader) - return {}; - - FileSpec file = loader->GetFile(); - if (!file) - return {}; - - auto error_or_file = llvm::MemoryBuffer::getFile(file.GetPath()); - if (auto err = error_or_file.getError()) - return {}; - - std::vector files; - llvm::yaml::Input yin((*error_or_file)->getBuffer()); - yin >> files; - - if (auto err = yin.error()) - return {}; - - for (auto &file : files) { - FileSpec absolute_path = - loader->GetRoot().CopyByAppendingPathComponent(file); - file = absolute_path.GetPath(); - } - - return std::make_unique>(std::move(files)); - } - - llvm::Optional GetNextFile() { - if (m_index >= m_files.size()) - return {}; - return m_files[m_index++]; - } + Verifier(Loader *loader) : m_loader(loader) {} + void Verify(llvm::function_ref error_callback, + llvm::function_ref warning_callback, + llvm::function_ref note_callback) const; private: - std::vector m_files; - unsigned m_index = 0; + Loader *m_loader; }; +struct ReplayOptions { + bool verify = true; + bool check_version = true; +}; + +llvm::Error Finalize(Loader *loader); +llvm::Error Finalize(const FileSpec &root); + } // namespace repro } // namespace lldb_private diff --git a/gnu/llvm/lldb/include/lldb/Utility/ReproducerInstrumentation.h b/gnu/llvm/lldb/include/lldb/Utility/ReproducerInstrumentation.h index 5fc33ad1a17..2b2d273a17a 100644 --- a/gnu/llvm/lldb/include/lldb/Utility/ReproducerInstrumentation.h +++ b/gnu/llvm/lldb/include/lldb/Utility/ReproducerInstrumentation.h @@ -17,6 +17,7 @@ #include "llvm/Support/ErrorHandling.h" #include +#include #include template inline std::string stringify_args(const Ts &... ts) { // is initialized or enabled. // #define LLDB_REPRO_INSTR_TRACE +#ifdef LLDB_REPRO_INSTR_TRACE +inline llvm::raw_ostream &this_thread_id() { + size_t tid = std::hash{}(std::this_thread::get_id()); + return llvm::errs().write_hex(tid) << " :: "; +} +#endif + #define LLDB_REGISTER_CONSTRUCTOR(Class, Signature) \ R.Register(&construct::record, "", \ #Class, #Class, #Signature) @@ -325,6 +333,7 @@ public: } template const T &HandleReplayResult(const T &t) { + CheckSequence(Deserialize()); unsigned result = Deserialize(); if (is_trivially_serializable::value) return t; @@ -334,6 +343,7 @@ public: /// Store the returned value in the index-to-object mapping. template T &HandleReplayResult(T &t) { + CheckSequence(Deserialize()); unsigned result = Deserialize(); if (is_trivially_serializable::value) return t; @@ -343,6 +353,7 @@ public: /// Store the returned value in the index-to-object mapping. template T *HandleReplayResult(T *t) { + CheckSequence(Deserialize()); unsigned result = Deserialize(); if (is_trivially_serializable::value) return t; @@ -352,6 +363,7 @@ public: /// All returned types are recorded, even when the function returns a void. /// The latter requires special handling. void HandleReplayResultVoid() { + CheckSequence(Deserialize()); unsigned result = Deserialize(); assert(result == 0); (void)result; @@ -361,6 +373,10 @@ public: return m_index_to_object.GetAllObjects(); } + void SetExpectedSequence(unsigned sequence) { + m_expected_sequence = sequence; + } + private: template T Read(ValueTag) { assert(HasData(sizeof(T))); @@ -402,11 +418,17 @@ private: return *(new UnderlyingT(Deserialize())); } + /// Verify that the given sequence number matches what we expect. + void CheckSequence(unsigned sequence); + /// Mapping of indices to objects. IndexToObject m_index_to_object; /// Buffer containing the serialized data. llvm::StringRef m_buffer; + + /// The result's expected sequence number. + llvm::Optional m_expected_sequence; }; /// Partial specialization for C-style strings. We read the string value @@ -447,7 +469,7 @@ template <> struct DeserializationHelper<> { /// The replayer interface. struct Replayer { - virtual ~Replayer() {} + virtual ~Replayer() = default; virtual void operator()(Deserializer &deserializer) const = 0; }; @@ -600,8 +622,8 @@ private: /// objects (in which case we serialize their index). template void Serialize(T *t) { #ifdef LLDB_REPRO_INSTR_TRACE - llvm::errs() << "Serializing with " << LLVM_PRETTY_FUNCTION << " -> " - << stringify_args(t) << "\n"; + this_thread_id() << "Serializing with " << LLVM_PRETTY_FUNCTION << " -> " + << stringify_args(t) << "\n"; #endif if (std::is_fundamental::value) { Serialize(*t); @@ -616,8 +638,8 @@ private: /// to objects (in which case we serialize their index). template void Serialize(T &t) { #ifdef LLDB_REPRO_INSTR_TRACE - llvm::errs() << "Serializing with " << LLVM_PRETTY_FUNCTION << " -> " - << stringify_args(t) << "\n"; + this_thread_id() << "Serializing with " << LLVM_PRETTY_FUNCTION << " -> " + << stringify_args(t) << "\n"; #endif if (is_trivially_serializable::value) { m_stream.write(reinterpret_cast(&t), sizeof(T)); @@ -637,8 +659,8 @@ private: void Serialize(const char *t) { #ifdef LLDB_REPRO_INSTR_TRACE - llvm::errs() << "Serializing with " << LLVM_PRETTY_FUNCTION << " -> " - << stringify_args(t) << "\n"; + this_thread_id() << "Serializing with " << LLVM_PRETTY_FUNCTION << " -> " + << stringify_args(t) << "\n"; #endif const size_t size = t ? strlen(t) : std::numeric_limits::max(); Serialize(size); @@ -692,8 +714,7 @@ protected: friend llvm::optional_detail::OptionalStorage; friend llvm::Optional; - InstrumentationData() - : m_serializer(nullptr), m_deserializer(nullptr), m_registry(nullptr) {} + InstrumentationData() = default; InstrumentationData(Serializer &serializer, Registry ®istry) : m_serializer(&serializer), m_deserializer(nullptr), m_registry(®istry) {} @@ -704,9 +725,9 @@ protected: private: static llvm::Optional &InstanceImpl(); - Serializer *m_serializer; - Deserializer *m_deserializer; - Registry *m_registry; + Serializer *m_serializer = nullptr; + Deserializer *m_deserializer = nullptr; + Registry *m_registry = nullptr; }; struct EmptyArg {}; @@ -737,12 +758,15 @@ public: if (!ShouldCapture()) return; + std::lock_guard lock(g_mutex); + unsigned sequence = GetSequenceNumber(); unsigned id = registry.GetID(uintptr_t(f)); #ifdef LLDB_REPRO_INSTR_TRACE Log(id); #endif + serializer.SerializeAll(sequence); serializer.SerializeAll(id); serializer.SerializeAll(args...); @@ -750,6 +774,7 @@ public: typename std::remove_reference::type>::type>::value) { m_result_recorded = false; } else { + serializer.SerializeAll(sequence); serializer.SerializeAll(0); m_result_recorded = true; } @@ -763,16 +788,20 @@ public: if (!ShouldCapture()) return; + std::lock_guard lock(g_mutex); + unsigned sequence = GetSequenceNumber(); unsigned id = registry.GetID(uintptr_t(f)); #ifdef LLDB_REPRO_INSTR_TRACE Log(id); #endif + serializer.SerializeAll(sequence); serializer.SerializeAll(id); serializer.SerializeAll(args...); // Record result. + serializer.SerializeAll(sequence); serializer.SerializeAll(0); m_result_recorded = true; } @@ -798,7 +827,9 @@ public: if (update_boundary) UpdateBoundary(); if (m_serializer && ShouldCapture()) { + std::lock_guard lock(g_mutex); assert(!m_result_recorded); + m_serializer->SerializeAll(GetSequenceNumber()); m_serializer->SerializeAll(r); m_result_recorded = true; } @@ -808,6 +839,7 @@ public: template Result Replay(Deserializer &deserializer, Registry ®istry, uintptr_t addr, bool update_boundary) { + deserializer.SetExpectedSequence(deserializer.Deserialize()); unsigned actual_id = registry.GetID(addr); unsigned id = deserializer.Deserialize(); registry.CheckID(id, actual_id); @@ -818,6 +850,7 @@ public: } void Replay(Deserializer &deserializer, Registry ®istry, uintptr_t addr) { + deserializer.SetExpectedSequence(deserializer.Deserialize()); unsigned actual_id = registry.GetID(addr); unsigned id = deserializer.Deserialize(); registry.CheckID(id, actual_id); @@ -833,7 +866,14 @@ public: bool ShouldCapture() { return m_local_boundary; } + /// Mark the current thread as a private thread and pretend that everything + /// on this thread is behind happening behind the API boundary. + static void PrivateThread() { g_global_boundary = true; } + private: + static unsigned GetNextSequenceNumber() { return g_sequence++; } + unsigned GetSequenceNumber() const; + template friend struct replay; void UpdateBoundary() { if (m_local_boundary) @@ -842,25 +882,34 @@ private: #ifdef LLDB_REPRO_INSTR_TRACE void Log(unsigned id) { - llvm::errs() << "Recording " << id << ": " << m_pretty_func << " (" - << m_pretty_args << ")\n"; + this_thread_id() << "Recording " << id << ": " << m_pretty_func << " (" + << m_pretty_args << ")\n"; } #endif - Serializer *m_serializer; + Serializer *m_serializer = nullptr; /// Pretty function for logging. llvm::StringRef m_pretty_func; std::string m_pretty_args; /// Whether this function call was the one crossing the API boundary. - bool m_local_boundary; + bool m_local_boundary = false; /// Whether the return value was recorded explicitly. - bool m_result_recorded; + bool m_result_recorded = true; + + /// The sequence number for this pair of function and result. + unsigned m_sequence; /// Whether we're currently across the API boundary. - static bool g_global_boundary; + static thread_local bool g_global_boundary; + + /// Global mutex to protect concurrent access. + static std::mutex g_mutex; + + /// Unique, monotonically increasing sequence number. + static std::atomic g_sequence; }; /// To be used as the "Runtime ID" of a constructor. It also invokes the @@ -1002,6 +1051,7 @@ struct invoke_char_ptr { static Result replay(Recorder &recorder, Deserializer &deserializer, Registry ®istry, char *str) { + deserializer.SetExpectedSequence(deserializer.Deserialize()); deserializer.Deserialize(); Class *c = deserializer.Deserialize(); deserializer.Deserialize(); @@ -1023,6 +1073,7 @@ struct invoke_char_ptr { static Result replay(Recorder &recorder, Deserializer &deserializer, Registry ®istry, char *str) { + deserializer.SetExpectedSequence(deserializer.Deserialize()); deserializer.Deserialize(); Class *c = deserializer.Deserialize(); deserializer.Deserialize(); @@ -1043,6 +1094,7 @@ struct invoke_char_ptr { static Result replay(Recorder &recorder, Deserializer &deserializer, Registry ®istry, char *str) { + deserializer.SetExpectedSequence(deserializer.Deserialize()); deserializer.Deserialize(); deserializer.Deserialize(); size_t l = deserializer.Deserialize(); diff --git a/gnu/llvm/lldb/include/lldb/Utility/ReproducerProvider.h b/gnu/llvm/lldb/include/lldb/Utility/ReproducerProvider.h new file mode 100644 index 00000000000..db7378069a8 --- /dev/null +++ b/gnu/llvm/lldb/include/lldb/Utility/ReproducerProvider.h @@ -0,0 +1,435 @@ +//===-- Reproducer.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_UTILITY_REPRODUCER_PROVIDER_H +#define LLDB_UTILITY_REPRODUCER_PROVIDER_H + +#include "lldb/Utility/FileSpec.h" +#include "lldb/Utility/ProcessInfo.h" +#include "lldb/Utility/Reproducer.h" +#include "lldb/Utility/UUID.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/FileCollector.h" +#include "llvm/Support/YAMLTraits.h" + +#include +#include +#include + +namespace lldb_private { +namespace repro { + +/// The recorder is a small object handed out by a provider to record data. It +/// is commonly used in combination with a MultiProvider which is meant to +/// record information for multiple instances of the same source of data. +class AbstractRecorder { +protected: + AbstractRecorder(const FileSpec &filename, std::error_code &ec) + : m_filename(filename.GetFilename().GetStringRef()), + m_os(filename.GetPath(), ec, llvm::sys::fs::OF_TextWithCRLF), + m_record(true) {} + +public: + const FileSpec &GetFilename() { return m_filename; } + + void Stop() { + assert(m_record); + m_record = false; + } + +private: + FileSpec m_filename; + +protected: + llvm::raw_fd_ostream m_os; + bool m_record; +}; + +/// Recorder that records its data as text to a file. +class DataRecorder : public AbstractRecorder { +public: + DataRecorder(const FileSpec &filename, std::error_code &ec) + : AbstractRecorder(filename, ec) {} + + static llvm::Expected> + Create(const FileSpec &filename); + + template void Record(const T &t, bool newline = false) { + if (!m_record) + return; + m_os << t; + if (newline) + m_os << '\n'; + m_os.flush(); + } +}; + +/// Recorder that records its data as YAML to a file. +class YamlRecorder : public AbstractRecorder { +public: + YamlRecorder(const FileSpec &filename, std::error_code &ec) + : AbstractRecorder(filename, ec) {} + + static llvm::Expected> + Create(const FileSpec &filename); + + template void Record(const T &t) { + if (!m_record) + return; + llvm::yaml::Output yout(m_os); + // The YAML traits are defined as non-const because they are used for + // serialization and deserialization. The cast is safe because + // serialization doesn't modify the object. + yout << const_cast(t); + m_os.flush(); + } +}; + +class FlushingFileCollector : public llvm::FileCollectorBase { +public: + FlushingFileCollector(llvm::StringRef files_path, llvm::StringRef dirs_path, + std::error_code &ec); + +protected: + void addFileImpl(llvm::StringRef file) override; + + llvm::vfs::directory_iterator + addDirectoryImpl(const llvm::Twine &dir, + llvm::IntrusiveRefCntPtr vfs, + std::error_code &dir_ec) override; + + llvm::Optional m_files_os; + llvm::Optional m_dirs_os; +}; + +class FileProvider : public Provider { +public: + struct Info { + static const char *name; + static const char *file; + }; + + FileProvider(const FileSpec &directory) : Provider(directory) { + std::error_code ec; + m_collector = std::make_shared( + directory.CopyByAppendingPathComponent("files.txt").GetPath(), + directory.CopyByAppendingPathComponent("dirs.txt").GetPath(), ec); + if (ec) + m_collector.reset(); + } + + std::shared_ptr GetFileCollector() { + return m_collector; + } + + void RecordInterestingDirectory(const llvm::Twine &dir); + void RecordInterestingDirectoryRecursive(const llvm::Twine &dir); + + static char ID; + +private: + std::shared_ptr m_collector; +}; + +/// Provider for the LLDB version number. +/// +/// When the reproducer is kept, it writes the lldb version to a file named +/// version.txt in the reproducer root. +class VersionProvider : public Provider { +public: + VersionProvider(const FileSpec &directory) : Provider(directory) {} + struct Info { + static const char *name; + static const char *file; + }; + void SetVersion(std::string version) { + assert(m_version.empty()); + m_version = std::move(version); + } + void Keep() override; + std::string m_version; + static char ID; +}; + +/// Abstract provider to storing directory paths. +template class DirectoryProvider : public repro::Provider { +public: + DirectoryProvider(const FileSpec &root) : Provider(root) {} + void SetDirectory(std::string directory) { + m_directory = std::move(directory); + } + llvm::StringRef GetDirectory() { return m_directory; } + + void Keep() override { + FileSpec file = this->GetRoot().CopyByAppendingPathComponent(T::Info::file); + std::error_code ec; + llvm::raw_fd_ostream os(file.GetPath(), ec, llvm::sys::fs::OF_TextWithCRLF); + if (ec) + return; + os << m_directory << "\n"; + } + +protected: + std::string m_directory; +}; + +/// Provider for the current working directory. +/// +/// When the reproducer is kept, it writes lldb's current working directory to +/// a file named cwd.txt in the reproducer root. +class WorkingDirectoryProvider + : public DirectoryProvider { +public: + WorkingDirectoryProvider(const FileSpec &directory) + : DirectoryProvider(directory) { + llvm::SmallString<128> cwd; + if (std::error_code EC = llvm::sys::fs::current_path(cwd)) + return; + SetDirectory(std::string(cwd)); + } + struct Info { + static const char *name; + static const char *file; + }; + static char ID; +}; + +/// Provider for the home directory. +/// +/// When the reproducer is kept, it writes the user's home directory to a file +/// a file named home.txt in the reproducer root. +class HomeDirectoryProvider : public DirectoryProvider { +public: + HomeDirectoryProvider(const FileSpec &directory) + : DirectoryProvider(directory) { + llvm::SmallString<128> home_dir; + llvm::sys::path::home_directory(home_dir); + SetDirectory(std::string(home_dir)); + } + struct Info { + static const char *name; + static const char *file; + }; + static char ID; +}; + +/// Provider for mapping UUIDs to symbol and executable files. +class SymbolFileProvider : public Provider { +public: + SymbolFileProvider(const FileSpec &directory) + : Provider(directory), m_symbol_files() {} + + void AddSymbolFile(const UUID *uuid, const FileSpec &module_path, + const FileSpec &symbol_path); + void Keep() override; + + struct Entry { + Entry() = default; + Entry(std::string uuid) : uuid(std::move(uuid)) {} + Entry(std::string uuid, std::string module_path, std::string symbol_path) + : uuid(std::move(uuid)), module_path(std::move(module_path)), + symbol_path(std::move(symbol_path)) {} + + bool operator==(const Entry &rhs) const { return uuid == rhs.uuid; } + bool operator<(const Entry &rhs) const { return uuid < rhs.uuid; } + + std::string uuid; + std::string module_path; + std::string symbol_path; + }; + + struct Info { + static const char *name; + static const char *file; + }; + static char ID; + +private: + std::vector m_symbol_files; +}; + +/// The MultiProvider is a provider that hands out recorder which can be used +/// to capture data for different instances of the same object. The recorders +/// can be passed around or stored as an instance member. +/// +/// The Info::file for the MultiProvider contains an index of files for every +/// recorder. Use the MultiLoader to read the index and get the individual +/// files. +template +class MultiProvider : public repro::Provider { +public: + MultiProvider(const FileSpec &directory) : Provider(directory) {} + + T *GetNewRecorder() { + std::size_t i = m_recorders.size() + 1; + std::string filename = (llvm::Twine(V::Info::name) + llvm::Twine("-") + + llvm::Twine(i) + llvm::Twine(".yaml")) + .str(); + auto recorder_or_error = + T::Create(this->GetRoot().CopyByAppendingPathComponent(filename)); + if (!recorder_or_error) { + llvm::consumeError(recorder_or_error.takeError()); + return nullptr; + } + + m_recorders.push_back(std::move(*recorder_or_error)); + return m_recorders.back().get(); + } + + void Keep() override { + std::vector files; + for (auto &recorder : m_recorders) { + recorder->Stop(); + files.push_back(recorder->GetFilename().GetPath()); + } + + FileSpec file = this->GetRoot().CopyByAppendingPathComponent(V::Info::file); + std::error_code ec; + llvm::raw_fd_ostream os(file.GetPath(), ec, llvm::sys::fs::OF_TextWithCRLF); + if (ec) + return; + llvm::yaml::Output yout(os); + yout << files; + } + + void Discard() override { m_recorders.clear(); } + +private: + std::vector> m_recorders; +}; + +class CommandProvider : public MultiProvider { +public: + struct Info { + static const char *name; + static const char *file; + }; + + CommandProvider(const FileSpec &directory) + : MultiProvider(directory) {} + + static char ID; +}; + +class ProcessInfoRecorder : public AbstractRecorder { +public: + ProcessInfoRecorder(const FileSpec &filename, std::error_code &ec) + : AbstractRecorder(filename, ec) {} + + static llvm::Expected> + Create(const FileSpec &filename); + + void Record(const ProcessInstanceInfoList &process_infos); +}; + +class ProcessInfoProvider : public repro::Provider { +public: + struct Info { + static const char *name; + static const char *file; + }; + + ProcessInfoProvider(const FileSpec &directory) : Provider(directory) {} + + ProcessInfoRecorder *GetNewProcessInfoRecorder(); + + void Keep() override; + void Discard() override; + + static char ID; + +private: + std::unique_ptr m_stream_up; + std::vector> m_process_info_recorders; +}; + +/// Loader for data captured with the MultiProvider. It will read the index and +/// return the path to the files in the index. +template class MultiLoader { +public: + MultiLoader(std::vector files) : m_files(std::move(files)) {} + + static std::unique_ptr Create(Loader *loader) { + if (!loader) + return {}; + + FileSpec file = loader->GetFile(); + if (!file) + return {}; + + auto error_or_file = llvm::MemoryBuffer::getFile(file.GetPath()); + if (auto err = error_or_file.getError()) + return {}; + + std::vector files; + llvm::yaml::Input yin((*error_or_file)->getBuffer()); + yin >> files; + + if (auto err = yin.error()) + return {}; + + for (auto &file : files) { + FileSpec absolute_path = + loader->GetRoot().CopyByAppendingPathComponent(file); + file = absolute_path.GetPath(); + } + + return std::make_unique>(std::move(files)); + } + + llvm::Optional GetNextFile() { + if (m_index >= m_files.size()) + return {}; + return m_files[m_index++]; + } + +private: + std::vector m_files; + unsigned m_index = 0; +}; + +class SymbolFileLoader { +public: + SymbolFileLoader(Loader *loader); + std::pair GetPaths(const UUID *uuid) const; + +private: + // Sorted list of UUID to path mappings. + std::vector m_symbol_files; +}; + +/// Helper to read directories written by the DirectoryProvider. +template +llvm::Expected GetDirectoryFrom(repro::Loader *loader) { + llvm::Expected dir = loader->LoadBuffer(); + if (!dir) + return dir.takeError(); + return std::string(llvm::StringRef(*dir).rtrim()); +} + +} // namespace repro +} // namespace lldb_private + +LLVM_YAML_IS_SEQUENCE_VECTOR(lldb_private::repro::SymbolFileProvider::Entry) + +namespace llvm { +namespace yaml { +template <> +struct MappingTraits { + static void mapping(IO &io, + lldb_private::repro::SymbolFileProvider::Entry &entry) { + io.mapRequired("uuid", entry.uuid); + io.mapRequired("module-path", entry.module_path); + io.mapRequired("symbol-path", entry.symbol_path); + } +}; +} // namespace yaml +} // namespace llvm + +#endif // LLDB_UTILITY_REPRODUCER_PROVIDER_H diff --git a/gnu/llvm/lldb/include/lldb/Utility/Scalar.h b/gnu/llvm/lldb/include/lldb/Utility/Scalar.h index f215fa71c84..2801b1bd632 100644 --- a/gnu/llvm/lldb/include/lldb/Utility/Scalar.h +++ b/gnu/llvm/lldb/include/lldb/Utility/Scalar.h @@ -9,94 +9,68 @@ #ifndef LLDB_UTILITY_SCALAR_H #define LLDB_UTILITY_SCALAR_H +#include "lldb/Utility/LLDBAssert.h" #include "lldb/Utility/Status.h" #include "lldb/lldb-enumerations.h" #include "lldb/lldb-private-types.h" -#include "lldb/Utility/LLDBAssert.h" #include "llvm/ADT/APFloat.h" -#include "llvm/ADT/APInt.h" +#include "llvm/ADT/APSInt.h" #include #include +#include namespace lldb_private { + class DataExtractor; class Stream; -} // namespace lldb_private #define NUM_OF_WORDS_INT128 2 #define BITWIDTH_INT128 128 -#define NUM_OF_WORDS_INT256 4 -#define BITWIDTH_INT256 256 -#define NUM_OF_WORDS_INT512 8 -#define BITWIDTH_INT512 512 - -namespace lldb_private { // A class designed to hold onto values and their corresponding types. // Operators are defined and Scalar objects will correctly promote their types // and values before performing these operations. Type promotion currently // follows the ANSI C type promotion rules. class Scalar { + template + static llvm::APSInt MakeAPSInt(T v) { + static_assert(std::is_integral::value, ""); + static_assert(sizeof(T) <= sizeof(uint64_t), "Conversion loses precision!"); + return llvm::APSInt( + llvm::APInt(sizeof(T) * 8, uint64_t(v), std::is_signed::value), + std::is_unsigned::value); + } + public: - // FIXME: These are host types which seems to be an odd choice. enum Type { e_void = 0, - e_sint, - e_uint, - e_slong, - e_ulong, - e_slonglong, - e_ulonglong, - e_sint128, - e_uint128, - e_sint256, - e_uint256, - e_sint512, - e_uint512, + e_int, e_float, - e_double, - e_long_double }; // Constructors and Destructors - Scalar(); - Scalar(int v) : m_type(e_sint), m_float(static_cast(0)) { - m_integer = llvm::APInt(sizeof(int) * 8, v, true); - } - Scalar(unsigned int v) : m_type(e_uint), m_float(static_cast(0)) { - m_integer = llvm::APInt(sizeof(int) * 8, v); - } - Scalar(long v) : m_type(e_slong), m_float(static_cast(0)) { - m_integer = llvm::APInt(sizeof(long) * 8, v, true); - } - Scalar(unsigned long v) : m_type(e_ulong), m_float(static_cast(0)) { - m_integer = llvm::APInt(sizeof(long) * 8, v); - } - Scalar(long long v) : m_type(e_slonglong), m_float(static_cast(0)) { - m_integer = llvm::APInt(sizeof(long long) * 8, v, true); - } + Scalar() : m_float(0.0f) {} + Scalar(int v) : m_type(e_int), m_integer(MakeAPSInt(v)), m_float(0.0f) {} + Scalar(unsigned int v) + : m_type(e_int), m_integer(MakeAPSInt(v)), m_float(0.0f) {} + Scalar(long v) : m_type(e_int), m_integer(MakeAPSInt(v)), m_float(0.0f) {} + Scalar(unsigned long v) + : m_type(e_int), m_integer(MakeAPSInt(v)), m_float(0.0f) {} + Scalar(long long v) + : m_type(e_int), m_integer(MakeAPSInt(v)), m_float(0.0f) {} Scalar(unsigned long long v) - : m_type(e_ulonglong), m_float(static_cast(0)) { - m_integer = llvm::APInt(sizeof(long long) * 8, v); - } - Scalar(float v) : m_type(e_float), m_float(v) { m_float = llvm::APFloat(v); } - Scalar(double v) : m_type(e_double), m_float(v) { - m_float = llvm::APFloat(v); + : m_type(e_int), m_integer(MakeAPSInt(v)), m_float(0.0f) {} + Scalar(float v) : m_type(e_float), m_float(v) {} + Scalar(double v) : m_type(e_float), m_float(v) {} + Scalar(long double v) : m_type(e_float), m_float(double(v)) { + bool ignore; + m_float.convert(llvm::APFloat::x87DoubleExtended(), + llvm::APFloat::rmNearestTiesToEven, &ignore); } - Scalar(long double v) - : m_type(e_long_double), - m_float(llvm::APFloat::x87DoubleExtended(), - llvm::APInt(BITWIDTH_INT128, NUM_OF_WORDS_INT128, - (reinterpret_cast(&v))->x)) {} - Scalar(llvm::APInt v) : m_type(), m_float(static_cast(0)) { - m_integer = llvm::APInt(v); - m_type = GetBestTypeForBitSize(m_integer.getBitWidth(), true); - } - // Scalar(const RegisterValue& reg_value); - virtual ~Scalar(); - - /// Return the most efficient Scalar::Type for the requested bit size. - static Type GetBestTypeForBitSize(size_t bit_size, bool sign); + Scalar(llvm::APInt v) + : m_type(e_int), m_integer(std::move(v), false), m_float(0.0f) {} + Scalar(llvm::APSInt v) + : m_type(e_int), m_integer(std::move(v)), m_float(0.0f) {} bool SignExtend(uint32_t bit_pos); @@ -129,34 +103,26 @@ public: void GetValue(Stream *s, bool show_type) const; - bool IsValid() const { - return (m_type >= e_sint) && (m_type <= e_long_double); - } + bool IsValid() const { return (m_type >= e_int) && (m_type <= e_float); } /// Convert to an integer with \p bits and the given signedness. void TruncOrExtendTo(uint16_t bits, bool sign); - bool Promote(Scalar::Type type); + bool IntegralPromote(uint16_t bits, bool sign); + bool FloatPromote(const llvm::fltSemantics &semantics); + bool IsSigned() const; bool MakeSigned(); bool MakeUnsigned(); static const char *GetValueTypeAsCString(Scalar::Type value_type); - static Scalar::Type - GetValueTypeForSignedIntegerWithByteSize(size_t byte_size); - - static Scalar::Type - GetValueTypeForUnsignedIntegerWithByteSize(size_t byte_size); - - static Scalar::Type GetValueTypeForFloatWithByteSize(size_t byte_size); - // All operators can benefits from the implicit conversions that will happen // automagically by the compiler, so no temporary objects will need to be // created. As a result, we currently don't need a variety of overloaded set // value accessors. - Scalar &operator+=(const Scalar &rhs); + Scalar &operator+=(Scalar rhs); Scalar &operator<<=(const Scalar &rhs); // Shift left Scalar &operator>>=(const Scalar &rhs); // Shift right (arithmetic) Scalar &operator&=(const Scalar &rhs); @@ -217,72 +183,37 @@ public: Status SetValueFromCString(const char *s, lldb::Encoding encoding, size_t byte_size); - Status SetValueFromData(DataExtractor &data, lldb::Encoding encoding, + Status SetValueFromData(const DataExtractor &data, lldb::Encoding encoding, size_t byte_size); - static bool UIntValueIsValidForSize(uint64_t uval64, size_t total_byte_size) { - if (total_byte_size > 8) - return false; - - if (total_byte_size == 8) - return true; - - const uint64_t max = (static_cast(1) - << static_cast(total_byte_size * 8)) - - 1; - return uval64 <= max; - } - - static bool SIntValueIsValidForSize(int64_t sval64, size_t total_byte_size) { - if (total_byte_size > 8) - return false; - - if (total_byte_size == 8) - return true; - - const int64_t max = (static_cast(1) - << static_cast(total_byte_size * 8 - 1)) - - 1; - const int64_t min = ~(max); - return min <= sval64 && sval64 <= max; - } - protected: - typedef char schar_t; - typedef unsigned char uchar_t; - typedef short sshort_t; - typedef unsigned short ushort_t; - typedef int sint_t; - typedef unsigned int uint_t; - typedef long slong_t; - typedef unsigned long ulong_t; - typedef long long slonglong_t; - typedef unsigned long long ulonglong_t; - typedef float float_t; - typedef double double_t; - typedef long double long_double_t; - - // Classes that inherit from Scalar can see and modify these - Scalar::Type m_type; - llvm::APInt m_integer; + Scalar::Type m_type = e_void; + llvm::APSInt m_integer; llvm::APFloat m_float; template T GetAs(T fail_value) const; + static Type PromoteToMaxType(Scalar &lhs, Scalar &rhs); + + using PromotionKey = std::tuple; + PromotionKey GetPromoKey() const; + + static PromotionKey GetFloatPromoKey(const llvm::fltSemantics &semantics); + private: friend const Scalar operator+(const Scalar &lhs, const Scalar &rhs); - friend const Scalar operator-(const Scalar &lhs, const Scalar &rhs); - friend const Scalar operator/(const Scalar &lhs, const Scalar &rhs); - friend const Scalar operator*(const Scalar &lhs, const Scalar &rhs); - friend const Scalar operator&(const Scalar &lhs, const Scalar &rhs); - friend const Scalar operator|(const Scalar &lhs, const Scalar &rhs); - friend const Scalar operator%(const Scalar &lhs, const Scalar &rhs); - friend const Scalar operator^(const Scalar &lhs, const Scalar &rhs); + friend const Scalar operator-(Scalar lhs, Scalar rhs); + friend const Scalar operator/(Scalar lhs, Scalar rhs); + friend const Scalar operator*(Scalar lhs, Scalar rhs); + friend const Scalar operator&(Scalar lhs, Scalar rhs); + friend const Scalar operator|(Scalar lhs, Scalar rhs); + friend const Scalar operator%(Scalar lhs, Scalar rhs); + friend const Scalar operator^(Scalar lhs, Scalar rhs); friend const Scalar operator<<(const Scalar &lhs, const Scalar &rhs); friend const Scalar operator>>(const Scalar &lhs, const Scalar &rhs); - friend bool operator==(const Scalar &lhs, const Scalar &rhs); + friend bool operator==(Scalar lhs, Scalar rhs); friend bool operator!=(const Scalar &lhs, const Scalar &rhs); - friend bool operator<(const Scalar &lhs, const Scalar &rhs); + friend bool operator<(Scalar lhs, Scalar rhs); friend bool operator<=(const Scalar &lhs, const Scalar &rhs); friend bool operator>(const Scalar &lhs, const Scalar &rhs); friend bool operator>=(const Scalar &lhs, const Scalar &rhs); @@ -302,18 +233,18 @@ private: // Differentiate among members functions, non-member functions, and // friend functions const Scalar operator+(const Scalar &lhs, const Scalar &rhs); -const Scalar operator-(const Scalar &lhs, const Scalar &rhs); -const Scalar operator/(const Scalar &lhs, const Scalar &rhs); -const Scalar operator*(const Scalar &lhs, const Scalar &rhs); -const Scalar operator&(const Scalar &lhs, const Scalar &rhs); -const Scalar operator|(const Scalar &lhs, const Scalar &rhs); -const Scalar operator%(const Scalar &lhs, const Scalar &rhs); -const Scalar operator^(const Scalar &lhs, const Scalar &rhs); +const Scalar operator-(Scalar lhs, Scalar rhs); +const Scalar operator/(Scalar lhs, Scalar rhs); +const Scalar operator*(Scalar lhs, Scalar rhs); +const Scalar operator&(Scalar lhs, Scalar rhs); +const Scalar operator|(Scalar lhs, Scalar rhs); +const Scalar operator%(Scalar lhs, Scalar rhs); +const Scalar operator^(Scalar lhs, Scalar rhs); const Scalar operator<<(const Scalar &lhs, const Scalar &rhs); const Scalar operator>>(const Scalar &lhs, const Scalar &rhs); -bool operator==(const Scalar &lhs, const Scalar &rhs); +bool operator==(Scalar lhs, Scalar rhs); bool operator!=(const Scalar &lhs, const Scalar &rhs); -bool operator<(const Scalar &lhs, const Scalar &rhs); +bool operator<(Scalar lhs, Scalar rhs); bool operator<=(const Scalar &lhs, const Scalar &rhs); bool operator>(const Scalar &lhs, const Scalar &rhs); bool operator>=(const Scalar &lhs, const Scalar &rhs); diff --git a/gnu/llvm/lldb/include/lldb/Utility/Status.h b/gnu/llvm/lldb/include/lldb/Utility/Status.h index 9babad18edc..61d663bdccb 100644 --- a/gnu/llvm/lldb/include/lldb/Utility/Status.h +++ b/gnu/llvm/lldb/include/lldb/Utility/Status.h @@ -15,7 +15,7 @@ #include "llvm/Support/Error.h" #include "llvm/Support/FormatVariadic.h" #include -#include +#include #include #include #include @@ -196,8 +196,9 @@ public: protected: /// Member variables - ValueType m_code; ///< Status code as an integer value. - lldb::ErrorType m_type; ///< The type of the above error code. + ValueType m_code = 0; ///< Status code as an integer value. + lldb::ErrorType m_type = + lldb::eErrorTypeInvalid; ///< The type of the above error code. mutable std::string m_string; ///< A string representation of the error code. }; diff --git a/gnu/llvm/lldb/include/lldb/Utility/Stream.h b/gnu/llvm/lldb/include/lldb/Utility/Stream.h index e7f065a1fc7..1a5fd343e4d 100644 --- a/gnu/llvm/lldb/include/lldb/Utility/Stream.h +++ b/gnu/llvm/lldb/include/lldb/Utility/Stream.h @@ -16,9 +16,9 @@ #include "llvm/Support/FormatVariadic.h" #include "llvm/Support/raw_ostream.h" -#include -#include -#include +#include +#include +#include #include namespace lldb_private { @@ -361,10 +361,10 @@ public: protected: // Member variables Flags m_flags; ///< Dump flags. - uint32_t m_addr_size; ///< Size of an address in bytes. + uint32_t m_addr_size = 4; ///< Size of an address in bytes. lldb::ByteOrder m_byte_order; ///< Byte order to use when encoding scalar types. - unsigned m_indent_level; ///< Indention level. + unsigned m_indent_level = 0; ///< Indention level. std::size_t m_bytes_written = 0; ///< Number of bytes written so far. void _PutHex8(uint8_t uvalue, bool add_prefix); diff --git a/gnu/llvm/lldb/include/lldb/Utility/StreamCallback.h b/gnu/llvm/lldb/include/lldb/Utility/StreamCallback.h index d6d74fb8479..d234cbea85c 100644 --- a/gnu/llvm/lldb/include/lldb/Utility/StreamCallback.h +++ b/gnu/llvm/lldb/include/lldb/Utility/StreamCallback.h @@ -12,8 +12,8 @@ #include "lldb/lldb-types.h" #include "llvm/Support/raw_ostream.h" -#include -#include +#include +#include namespace lldb_private { diff --git a/gnu/llvm/lldb/include/lldb/Utility/StreamString.h b/gnu/llvm/lldb/include/lldb/Utility/StreamString.h index b0be0f7dd76..4c568acdcc6 100644 --- a/gnu/llvm/lldb/include/lldb/Utility/StreamString.h +++ b/gnu/llvm/lldb/include/lldb/Utility/StreamString.h @@ -15,8 +15,8 @@ #include -#include -#include +#include +#include namespace lldb_private { diff --git a/gnu/llvm/lldb/include/lldb/Utility/StreamTee.h b/gnu/llvm/lldb/include/lldb/Utility/StreamTee.h index 2995bc07f42..b5d3b9679e9 100644 --- a/gnu/llvm/lldb/include/lldb/Utility/StreamTee.h +++ b/gnu/llvm/lldb/include/lldb/Utility/StreamTee.h @@ -9,7 +9,7 @@ #ifndef LLDB_UTILITY_STREAMTEE_H #define LLDB_UTILITY_STREAMTEE_H -#include +#include #include @@ -45,7 +45,7 @@ public: m_streams = rhs.m_streams; } - ~StreamTee() override {} + ~StreamTee() override = default; StreamTee &operator=(const StreamTee &rhs) { if (this != &rhs) { diff --git a/gnu/llvm/lldb/include/lldb/Utility/StringExtractor.h b/gnu/llvm/lldb/include/lldb/Utility/StringExtractor.h index 6a5bb24779a..a4819378ce3 100644 --- a/gnu/llvm/lldb/include/lldb/Utility/StringExtractor.h +++ b/gnu/llvm/lldb/include/lldb/Utility/StringExtractor.h @@ -12,8 +12,8 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringRef.h" -#include -#include +#include +#include #include class StringExtractor { @@ -115,7 +115,7 @@ protected: /// When extracting data from a packet, this index will march along as things /// get extracted. If set to UINT64_MAX the end of the packet data was /// reached when decoding information. - uint64_t m_index; + uint64_t m_index = 0; }; #endif // LLDB_UTILITY_STRINGEXTRACTOR_H diff --git a/gnu/llvm/lldb/include/lldb/Utility/StringExtractorGDBRemote.h b/gnu/llvm/lldb/include/lldb/Utility/StringExtractorGDBRemote.h index 715f3cb2541..c67c05bdf18 100644 --- a/gnu/llvm/lldb/include/lldb/Utility/StringExtractorGDBRemote.h +++ b/gnu/llvm/lldb/include/lldb/Utility/StringExtractorGDBRemote.h @@ -15,15 +15,15 @@ #include -#include -#include +#include +#include class StringExtractorGDBRemote : public StringExtractor { public: typedef bool (*ResponseValidatorCallback)( void *baton, const StringExtractorGDBRemote &response); - StringExtractorGDBRemote() : StringExtractor(), m_validator(nullptr) {} + StringExtractorGDBRemote() : StringExtractor() {} StringExtractorGDBRemote(llvm::StringRef str) : StringExtractor(str), m_validator(nullptr) {} @@ -76,6 +76,7 @@ public: eServerPacketType_QSetSTDERR, eServerPacketType_QSetWorkingDir, eServerPacketType_QStartNoAckMode, + eServerPacketType_qPathComplete, eServerPacketType_qPlatform_shell, eServerPacketType_qPlatform_mkdir, eServerPacketType_qPlatform_chmod, @@ -161,11 +162,14 @@ public: eServerPacketType__m, eServerPacketType_notify, // '%' notification - eServerPacketType_jTraceStart, - eServerPacketType_jTraceBufferRead, - eServerPacketType_jTraceMetaRead, - eServerPacketType_jTraceStop, - eServerPacketType_jTraceConfigRead, + eServerPacketType_jLLDBTraceSupported, + eServerPacketType_jLLDBTraceStart, + eServerPacketType_jLLDBTraceStop, + eServerPacketType_jLLDBTraceGetState, + eServerPacketType_jLLDBTraceGetBinaryData, + + eServerPacketType_qMemTags, // read memory tags + eServerPacketType_QMemTags, // write memory tags }; ServerPacketType GetServerPacketType() const; @@ -190,8 +194,17 @@ public: size_t GetEscapedBinaryData(std::string &str); + static constexpr lldb::pid_t AllProcesses = UINT64_MAX; + static constexpr lldb::tid_t AllThreads = UINT64_MAX; + + // Read thread-id from the packet. If the packet is valid, returns + // the pair (PID, TID), otherwise returns llvm::None. If the packet + // does not list a PID, default_pid is used. + llvm::Optional> + GetPidTid(lldb::pid_t default_pid); + protected: - ResponseValidatorCallback m_validator; + ResponseValidatorCallback m_validator = nullptr; void *m_validator_baton; }; diff --git a/gnu/llvm/lldb/include/lldb/Utility/StringList.h b/gnu/llvm/lldb/include/lldb/Utility/StringList.h index 591a1586159..70f4654a6ac 100644 --- a/gnu/llvm/lldb/include/lldb/Utility/StringList.h +++ b/gnu/llvm/lldb/include/lldb/Utility/StringList.h @@ -11,7 +11,7 @@ #include "llvm/ADT/StringRef.h" -#include +#include #include #include @@ -102,7 +102,7 @@ public: StringList &operator<<(const std::string &s); - StringList &operator<<(StringList strings); + StringList &operator<<(const StringList &strings); // Copy assignment for a vector of strings StringList &operator=(const std::vector &rhs); diff --git a/gnu/llvm/lldb/include/lldb/Utility/StructuredData.h b/gnu/llvm/lldb/include/lldb/Utility/StructuredData.h index 14c82e66967..4d03af18e52 100644 --- a/gnu/llvm/lldb/include/lldb/Utility/StructuredData.h +++ b/gnu/llvm/lldb/include/lldb/Utility/StructuredData.h @@ -271,9 +271,9 @@ public: return false; } - void Push(ObjectSP item) { m_items.push_back(item); } + void Push(const ObjectSP &item) { m_items.push_back(item); } - void AddItem(ObjectSP item) { m_items.push_back(item); } + void AddItem(const ObjectSP &item) { m_items.push_back(item); } void Serialize(llvm::json::OStream &s) const override; @@ -493,7 +493,7 @@ public: void AddItem(llvm::StringRef key, ObjectSP value_sp) { ConstString key_cs(key); - m_dict[key_cs] = value_sp; + m_dict[key_cs] = std::move(value_sp); } void AddIntegerItem(llvm::StringRef key, uint64_t value) { @@ -547,7 +547,7 @@ public: void *m_object; }; - static ObjectSP ParseJSON(std::string json_text); + static ObjectSP ParseJSON(const std::string &json_text); static ObjectSP ParseJSONFromFile(const FileSpec &file, Status &error); }; diff --git a/gnu/llvm/lldb/include/lldb/Utility/Timeout.h b/gnu/llvm/lldb/include/lldb/Utility/Timeout.h index 80e20151557..29f8c1bbee3 100644 --- a/gnu/llvm/lldb/include/lldb/Utility/Timeout.h +++ b/gnu/llvm/lldb/include/lldb/Utility/Timeout.h @@ -37,7 +37,6 @@ private: public: Timeout(llvm::NoneType none) : Base(none) {} - Timeout(const Timeout &other) = default; template ::type> diff --git a/gnu/llvm/lldb/include/lldb/Utility/Timer.h b/gnu/llvm/lldb/include/lldb/Utility/Timer.h index f97315b2db0..c70c1804942 100644 --- a/gnu/llvm/lldb/include/lldb/Utility/Timer.h +++ b/gnu/llvm/lldb/include/lldb/Utility/Timer.h @@ -9,10 +9,15 @@ #ifndef LLDB_UTILITY_TIMER_H #define LLDB_UTILITY_TIMER_H -#include "lldb/lldb-defines.h" +#include "llvm/ADT/ScopeExit.h" #include "llvm/Support/Chrono.h" +#include "llvm/Support/Signposts.h" #include -#include +#include + +namespace llvm { + class SignpostEmitter; +} namespace lldb_private { class Stream; @@ -25,6 +30,7 @@ public: class Category { public: explicit Category(const char *category_name); + llvm::StringRef GetName() { return m_name; } private: friend class Timer; @@ -40,7 +46,11 @@ public: /// Default constructor. Timer(Category &category, const char *format, ...) - __attribute__((format(printf, 3, 4))); +#if !defined(_MSC_VER) + // MSVC appears to have trouble recognizing the this argument in the constructor. + __attribute__((format(printf, 3, 4))) +#endif + ; /// Destructor ~Timer(); @@ -71,6 +81,28 @@ private: const Timer &operator=(const Timer &) = delete; }; +llvm::SignpostEmitter &GetSignposts(); + } // namespace lldb_private +// Use a format string because LLVM_PRETTY_FUNCTION might not be a string +// literal. +#define LLDB_SCOPED_TIMER() \ + static ::lldb_private::Timer::Category _cat(LLVM_PRETTY_FUNCTION); \ + ::lldb_private::Timer _scoped_timer(_cat, "%s", LLVM_PRETTY_FUNCTION); \ + SIGNPOST_EMITTER_START_INTERVAL(::lldb_private::GetSignposts(), \ + &_scoped_timer, "%s", LLVM_PRETTY_FUNCTION); \ + auto _scoped_signpost = llvm::make_scope_exit([&_scoped_timer]() { \ + ::lldb_private::GetSignposts().endInterval(&_scoped_timer); \ + }) + +#define LLDB_SCOPED_TIMERF(FMT, ...) \ + static ::lldb_private::Timer::Category _cat(LLVM_PRETTY_FUNCTION); \ + ::lldb_private::Timer _scoped_timer(_cat, FMT, __VA_ARGS__); \ + SIGNPOST_EMITTER_START_INTERVAL(::lldb_private::GetSignposts(), \ + &_scoped_timer, FMT, __VA_ARGS__); \ + auto _scoped_signpost = llvm::make_scope_exit([&_scoped_timer]() { \ + ::lldb_private::GetSignposts().endInterval(&_scoped_timer); \ + }) + #endif // LLDB_UTILITY_TIMER_H diff --git a/gnu/llvm/lldb/include/lldb/Utility/TraceGDBRemotePackets.h b/gnu/llvm/lldb/include/lldb/Utility/TraceGDBRemotePackets.h new file mode 100644 index 00000000000..1d2448b05f2 --- /dev/null +++ b/gnu/llvm/lldb/include/lldb/Utility/TraceGDBRemotePackets.h @@ -0,0 +1,154 @@ +//===-- TraceGDBRemotePackets.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_UTILITY_TRACEGDBREMOTEPACKETS_H +#define LLDB_UTILITY_TRACEGDBREMOTEPACKETS_H + +#include "llvm/Support/JSON.h" + +#include "lldb/lldb-defines.h" +#include "lldb/lldb-enumerations.h" + +/// See docs/lldb-gdb-remote.txt for more information. +namespace lldb_private { + +/// jLLDBTraceSupported gdb-remote packet +/// \{ +struct TraceSupportedResponse { + /// The name of the technology, e.g. intel-pt or arm-coresight. + /// + /// In order for a Trace plug-in (see \a lldb_private::Trace.h) to support the + /// trace technology given by this struct, it should match its name with this + /// field. + std::string name; + /// The description for the technology. + std::string description; +}; + +bool fromJSON(const llvm::json::Value &value, TraceSupportedResponse &info, + llvm::json::Path path); + +llvm::json::Value toJSON(const TraceSupportedResponse &packet); +/// \} + +/// jLLDBTraceStart gdb-remote packet +/// \{ +struct TraceStartRequest { + /// Tracing technology name, e.g. intel-pt, arm-coresight. + std::string type; + + /// If \a llvm::None, then this starts tracing the whole process. Otherwise, + /// only tracing for the specified threads is enabled. + llvm::Optional> tids; + + /// \return + /// \b true if \a tids is \a None, i.e. whole process tracing. + bool IsProcessTracing() const; +}; + +bool fromJSON(const llvm::json::Value &value, TraceStartRequest &packet, + llvm::json::Path path); + +llvm::json::Value toJSON(const TraceStartRequest &packet); +/// \} + +/// jLLDBTraceStop gdb-remote packet +/// \{ +struct TraceStopRequest { + TraceStopRequest() = default; + + TraceStopRequest(llvm::StringRef type, const std::vector &tids); + + TraceStopRequest(llvm::StringRef type) : type(type){}; + + bool IsProcessTracing() const; + + /// Tracing technology name, e.g. intel-pt, arm-coresight. + std::string type; + /// If \a llvm::None, then this stops tracing the whole process. Otherwise, + /// only tracing for the specified threads is stopped. + llvm::Optional> tids; +}; + +bool fromJSON(const llvm::json::Value &value, TraceStopRequest &packet, + llvm::json::Path path); + +llvm::json::Value toJSON(const TraceStopRequest &packet); +///} + +/// jLLDBTraceGetState gdb-remote packet +/// \{ +struct TraceGetStateRequest { + /// Tracing technology name, e.g. intel-pt, arm-coresight. + std::string type; +}; + +bool fromJSON(const llvm::json::Value &value, TraceGetStateRequest &packet, + llvm::json::Path path); + +llvm::json::Value toJSON(const TraceGetStateRequest &packet); + +struct TraceBinaryData { + /// Identifier of data to fetch with jLLDBTraceGetBinaryData. + std::string kind; + /// Size in bytes for this data. + int64_t size; +}; + +bool fromJSON(const llvm::json::Value &value, TraceBinaryData &packet, + llvm::json::Path path); + +llvm::json::Value toJSON(const TraceBinaryData &packet); + +struct TraceThreadState { + int64_t tid; + /// List of binary data objects for this thread. + std::vector binaryData; +}; + +bool fromJSON(const llvm::json::Value &value, TraceThreadState &packet, + llvm::json::Path path); + +llvm::json::Value toJSON(const TraceThreadState &packet); + +struct TraceGetStateResponse { + std::vector tracedThreads; + std::vector processBinaryData; +}; + +bool fromJSON(const llvm::json::Value &value, TraceGetStateResponse &packet, + llvm::json::Path path); + +llvm::json::Value toJSON(const TraceGetStateResponse &packet); +/// \} + +/// jLLDBTraceGetBinaryData gdb-remote packet +/// \{ +struct TraceGetBinaryDataRequest { + /// Tracing technology name, e.g. intel-pt, arm-coresight. + std::string type; + /// Identifier for the data. + std::string kind; + /// Optional tid if the data is related to a thread. + llvm::Optional tid; + /// Offset in bytes from where to start reading the data. + int64_t offset; + /// Number of bytes to read. + int64_t size; +}; + +bool fromJSON(const llvm::json::Value &value, + lldb_private::TraceGetBinaryDataRequest &packet, + llvm::json::Path path); + +llvm::json::Value toJSON(const lldb_private::TraceGetBinaryDataRequest &packet); +/// \} + +} // namespace lldb_private + +#endif // LLDB_UTILITY_TRACEGDBREMOTEPACKETS_H diff --git a/gnu/llvm/lldb/include/lldb/Utility/TraceIntelPTGDBRemotePackets.h b/gnu/llvm/lldb/include/lldb/Utility/TraceIntelPTGDBRemotePackets.h new file mode 100644 index 00000000000..8f4947b1f18 --- /dev/null +++ b/gnu/llvm/lldb/include/lldb/Utility/TraceIntelPTGDBRemotePackets.h @@ -0,0 +1,45 @@ +//===-- TraceIntelPTGDBRemotePackets.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_UTILITY_TRACEINTELPTGDBREMOTEPACKETS_H +#define LLDB_UTILITY_TRACEINTELPTGDBREMOTEPACKETS_H + +#include "lldb/Utility/TraceGDBRemotePackets.h" + +/// See docs/lldb-gdb-remote.txt for more information. +namespace lldb_private { + +/// jLLDBTraceStart gdb-remote packet +/// \{ +struct TraceIntelPTStartRequest : TraceStartRequest { + /// Size in bytes to use for each thread's trace buffer. + int64_t threadBufferSize; + + /// Whether to enable TSC + bool enableTsc; + + /// PSB packet period + llvm::Optional psbPeriod; + + /// Required when doing "process tracing". + /// + /// Limit in bytes on all the thread traces started by this "process trace" + /// instance. When a thread is about to be traced and the limit would be hit, + /// then a "tracing" stop event is triggered. + llvm::Optional processBufferSizeLimit; +}; + +bool fromJSON(const llvm::json::Value &value, TraceIntelPTStartRequest &packet, + llvm::json::Path path); + +llvm::json::Value toJSON(const TraceIntelPTStartRequest &packet); +/// \} + +} // namespace lldb_private + +#endif // LLDB_UTILITY_TRACEINTELPTGDBREMOTEPACKETS_H diff --git a/gnu/llvm/lldb/include/lldb/Utility/UUID.h b/gnu/llvm/lldb/include/lldb/Utility/UUID.h index 5327719094c..1c7c04758da 100644 --- a/gnu/llvm/lldb/include/lldb/Utility/UUID.h +++ b/gnu/llvm/lldb/include/lldb/Utility/UUID.h @@ -11,8 +11,9 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringRef.h" -#include -#include +#include "llvm/Support/Endian.h" +#include +#include #include namespace lldb_private { @@ -23,6 +24,22 @@ class UUID { public: UUID() = default; + // Reference: + // https://crashpad.chromium.org/doxygen/structcrashpad_1_1CodeViewRecordPDB70.html + struct CvRecordPdb70 { + struct { + llvm::support::ulittle32_t Data1; + llvm::support::ulittle16_t Data2; + llvm::support::ulittle16_t Data3; + uint8_t Data4[8]; + } Uuid; + llvm::support::ulittle32_t Age; + // char PDBFileName[]; + }; + + /// Create a UUID from CvRecordPdb70. + static UUID fromCvRecord(CvRecordPdb70 debug_info); + /// Creates a UUID from the data pointed to by the bytes argument. No special /// significance is attached to any of the values. static UUID fromData(const void *bytes, uint32_t num_bytes) { diff --git a/gnu/llvm/lldb/include/lldb/Utility/UnimplementedError.h b/gnu/llvm/lldb/include/lldb/Utility/UnimplementedError.h new file mode 100644 index 00000000000..c6fab0a9483 --- /dev/null +++ b/gnu/llvm/lldb/include/lldb/Utility/UnimplementedError.h @@ -0,0 +1,28 @@ +//===-- UnimplementedError.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_UTILITY_UNIMPLEMENTEDERROR_H +#define LLDB_UTILITY_UNIMPLEMENTEDERROR_H + +#include "llvm/Support/Errc.h" +#include "llvm/Support/Error.h" + +namespace lldb_private { +class UnimplementedError : public llvm::ErrorInfo { +public: + static char ID; + + void log(llvm::raw_ostream &OS) const override { OS << "Not implemented"; } + + std::error_code convertToErrorCode() const override { + return llvm::errc::not_supported; + }; +}; +} // namespace lldb_private + +#endif // LLDB_UTILITY_UNIMPLEMENTEDERROR_H diff --git a/gnu/llvm/lldb/include/lldb/Utility/UserID.h b/gnu/llvm/lldb/include/lldb/Utility/UserID.h index 9fc6985a5a9..19e0052fc51 100644 --- a/gnu/llvm/lldb/include/lldb/Utility/UserID.h +++ b/gnu/llvm/lldb/include/lldb/Utility/UserID.h @@ -33,7 +33,7 @@ struct UserID { UserID(lldb::user_id_t uid = LLDB_INVALID_UID) : m_uid(uid) {} /// Destructor. - ~UserID() {} + ~UserID() = default; /// Clears the object state. /// diff --git a/gnu/llvm/lldb/include/lldb/Utility/VMRange.h b/gnu/llvm/lldb/include/lldb/Utility/VMRange.h index 4b01cd86da2..095092c1a38 100644 --- a/gnu/llvm/lldb/include/lldb/Utility/VMRange.h +++ b/gnu/llvm/lldb/include/lldb/Utility/VMRange.h @@ -12,8 +12,8 @@ #include "lldb/lldb-types.h" #include "llvm/Support/raw_ostream.h" -#include -#include +#include +#include #include namespace lldb_private { @@ -26,13 +26,13 @@ public: typedef collection::iterator iterator; typedef collection::const_iterator const_iterator; - VMRange() : m_base_addr(0), m_byte_size(0) {} + VMRange() = default; VMRange(lldb::addr_t start_addr, lldb::addr_t end_addr) : m_base_addr(start_addr), m_byte_size(end_addr > start_addr ? end_addr - start_addr : 0) {} - ~VMRange() {} + ~VMRange() = default; void Clear() { m_base_addr = 0; @@ -88,8 +88,8 @@ public: const VMRange &range); protected: - lldb::addr_t m_base_addr; - lldb::addr_t m_byte_size; + lldb::addr_t m_base_addr = 0; + lldb::addr_t m_byte_size = 0; }; bool operator==(const VMRange &lhs, const VMRange &rhs); diff --git a/gnu/llvm/lldb/include/lldb/Utility/XcodeSDK.h b/gnu/llvm/lldb/include/lldb/Utility/XcodeSDK.h index 307fe7f4679..878b131a181 100644 --- a/gnu/llvm/lldb/include/lldb/Utility/XcodeSDK.h +++ b/gnu/llvm/lldb/include/lldb/Utility/XcodeSDK.h @@ -65,11 +65,11 @@ public: /// The merge function follows a strict order to maintain monotonicity: /// 1. SDK with the higher SDKType wins. /// 2. The newer SDK wins. - void Merge(XcodeSDK other); + void Merge(const XcodeSDK &other); - XcodeSDK &operator=(XcodeSDK other); + XcodeSDK &operator=(const XcodeSDK &other); XcodeSDK(const XcodeSDK&) = default; - bool operator==(XcodeSDK other); + bool operator==(const XcodeSDK &other); /// Return parsed SDK type and version number. Info Parse() const; diff --git a/gnu/llvm/lldb/include/lldb/lldb-defines.h b/gnu/llvm/lldb/include/lldb/lldb-defines.h index fea8079779a..4bf01c3f86c 100644 --- a/gnu/llvm/lldb/include/lldb/lldb-defines.h +++ b/gnu/llvm/lldb/include/lldb/lldb-defines.h @@ -82,6 +82,7 @@ #define LLDB_REGNUM_GENERIC_ARG8 \ 12 // The register that would contain pointer size or less argument 8 (if any) /// Invalid value definitions +#define LLDB_INVALID_STOP_ID 0 #define LLDB_INVALID_ADDRESS UINT64_MAX #define LLDB_INVALID_INDEX32 UINT32_MAX #define LLDB_INVALID_IVAR_OFFSET UINT32_MAX @@ -95,6 +96,7 @@ #define LLDB_INVALID_SIGNAL_NUMBER INT32_MAX #define LLDB_INVALID_OFFSET UINT64_MAX // Must match max of lldb::offset_t #define LLDB_INVALID_LINE_NUMBER UINT32_MAX +#define LLDB_INVALID_COLUMN_NUMBER 0 #define LLDB_INVALID_QUEUE_ID 0 /// CPU Type definitions @@ -119,6 +121,7 @@ #define LLDB_OPT_SET_9 (1U << 8) #define LLDB_OPT_SET_10 (1U << 9) #define LLDB_OPT_SET_11 (1U << 10) +#define LLDB_OPT_SET_12 (1U << 11) #define LLDB_OPT_SET_FROM_TO(A, B) \ (((1U << (B)) - 1) ^ (((1U << (A)) - 1) >> 1)) diff --git a/gnu/llvm/lldb/include/lldb/lldb-enumerations.h b/gnu/llvm/lldb/include/lldb/lldb-enumerations.h index b3e8d604913..81f6be3eec7 100644 --- a/gnu/llvm/lldb/include/lldb/lldb-enumerations.h +++ b/gnu/llvm/lldb/include/lldb/lldb-enumerations.h @@ -126,6 +126,9 @@ FLAGS_ENUM(LaunchFlags){ eLaunchFlagShellExpandArguments = (1u << 10), ///< Perform shell-style argument expansion eLaunchFlagCloseTTYOnExit = (1u << 11), ///< Close the open TTY on exit + eLaunchFlagInheritTCCFromParent = + (1u << 12), ///< Don't make the inferior responsible for its own TCC + ///< permissions but instead inherit them from its parent. }; /// Thread Run Modes. @@ -157,7 +160,7 @@ enum Format { eFormatBytes, eFormatBytesWithASCII, eFormatChar, - eFormatCharPrintable, ///< Only printable characters, space if not printable + eFormatCharPrintable, ///< Only printable characters, '.' if not printable eFormatComplex, ///< Floating point complex type eFormatComplexFloat = eFormatComplex, eFormatCString, ///< NULL terminated C strings @@ -244,7 +247,11 @@ enum StopReason { eStopReasonExec, ///< Program was re-exec'ed eStopReasonPlanComplete, eStopReasonThreadExiting, - eStopReasonInstrumentation + eStopReasonInstrumentation, + eStopReasonProcessorTrace, + eStopReasonFork, + eStopReasonVFork, + eStopReasonVForkDone, }; /// Command Return Status Types. @@ -526,6 +533,7 @@ enum CommandArgumentType { eArgTypeExpression, eArgTypeExpressionPath, eArgTypeExprFormat, + eArgTypeFileLineColumn, eArgTypeFilename, eArgTypeFormat, eArgTypeFrameIndex, @@ -592,6 +600,8 @@ enum CommandArgumentType { eArgRawInput, eArgTypeCommand, eArgTypeColumnNum, + eArgTypeModuleUUID, + eArgTypeSaveCoreStyle, eArgTypeLastArg // Always keep this entry as the last entry in this // enumeration!! }; @@ -764,10 +774,11 @@ enum BasicType { eBasicTypeOther }; +/// Deprecated enum TraceType { eTraceTypeNone = 0, - // Hardware Trace generated by the processor. + /// Intel Processor Trace eTraceTypeProcessorTrace }; @@ -948,6 +959,25 @@ enum ExpressionEvaluationPhase { eExpressionEvaluationComplete }; +/// Architecture-agnostic categorization of instructions for traversing the +/// control flow of a trace. +/// +/// A single instruction can match one or more of these categories. +FLAGS_ENUM(TraceInstructionControlFlowType){ + /// Any instruction. + eTraceInstructionControlFlowTypeInstruction = (1u << 1), + /// A conditional or unconditional branch/jump. + eTraceInstructionControlFlowTypeBranch = (1u << 2), + /// A conditional or unconditional branch/jump that changed + /// the control flow of the program. + eTraceInstructionControlFlowTypeTakenBranch = (1u << 3), + /// A call to a function. + eTraceInstructionControlFlowTypeCall = (1u << 4), + /// A return from a function. + eTraceInstructionControlFlowTypeReturn = (1u << 5)}; + +LLDB_MARK_AS_BITMASK_ENUM(TraceInstructionControlFlowType) + /// Watchpoint Kind. /// /// Indicates what types of events cause the watchpoint to fire. Used by Native @@ -964,7 +994,7 @@ enum GdbSignal { eGdbSignalBreakpoint = 0x96 }; -/// Used with SBHost::GetPath (lldb::PathType) to find files that are +/// Used with SBHostOS::GetLLDBPath (lldb::PathType) to find files that are /// related to LLDB on the current host machine. Most files are /// relative to LLDB or are in known locations. enum PathType { @@ -1075,7 +1105,12 @@ FLAGS_ENUM(CommandFlags){ /// /// Verifies that there is a paused process in m_exe_ctx, if there isn't, /// the command will fail with an appropriate error message. - eCommandProcessMustBePaused = (1u << 7)}; + eCommandProcessMustBePaused = (1u << 7), + /// eCommandProcessMustBeTraced + /// + /// Verifies that the process is being traced by a Trace plug-in, if it + /// isn't the command will fail with an appropriate error message. + eCommandProcessMustBeTraced = (1u << 8)}; /// Whether a summary should cap how much data it returns to users or not. enum TypeSummaryCapping { @@ -1096,6 +1131,14 @@ enum CommandInterpreterResult { /// Stopped because quit was requested. eCommandInterpreterResultQuitRequested, }; + +// Style of core file to create when calling SaveCore. +enum SaveCoreStyle { + eSaveCoreUnspecified = 0, + eSaveCoreFull = 1, + eSaveCoreDirtyOnly = 2, +}; + } // namespace lldb #endif // LLDB_LLDB_ENUMERATIONS_H diff --git a/gnu/llvm/lldb/include/lldb/lldb-forward.h b/gnu/llvm/lldb/include/lldb/lldb-forward.h index 4fd2a07dd61..ad5298151e4 100644 --- a/gnu/llvm/lldb/include/lldb/lldb-forward.h +++ b/gnu/llvm/lldb/include/lldb/lldb-forward.h @@ -174,6 +174,7 @@ class RichManglingContext; class Scalar; class ScriptInterpreter; class ScriptInterpreterLocker; +class ScriptedProcessInterface; class ScriptedSyntheticChildren; class SearchFilter; class Section; @@ -192,7 +193,6 @@ class Status; class StopInfo; class Stoppoint; class StoppointCallbackContext; -class StoppointLocation; class Stream; class StreamFile; class StreamString; @@ -227,7 +227,10 @@ class ThreadPlanStepRange; class ThreadPlanStepThrough; class ThreadPlanTracer; class ThreadSpec; -class TraceOptions; +class ThreadPostMortemTrace; +class Trace; +class TraceCursor; +class TraceExporter; class Type; class TypeAndOrName; class TypeCategoryImpl; @@ -339,6 +342,7 @@ typedef std::shared_ptr ListenerSP; typedef std::weak_ptr ListenerWP; typedef std::shared_ptr MemoryHistorySP; typedef std::unique_ptr MemoryRegionInfoUP; +typedef std::shared_ptr MemoryRegionInfoSP; typedef std::shared_ptr ModuleSP; typedef std::weak_ptr ModuleWP; typedef std::shared_ptr ObjectFileSP; @@ -389,6 +393,8 @@ typedef std::shared_ptr ScriptSummaryFormatSP; typedef std::shared_ptr ScriptInterpreterSP; typedef std::unique_ptr ScriptInterpreterUP; +typedef std::unique_ptr + ScriptedProcessInterfaceUP; typedef std::shared_ptr SectionSP; typedef std::unique_ptr SectionListUP; typedef std::weak_ptr SectionWP; @@ -402,8 +408,9 @@ typedef std::weak_ptr StackFrameWP; typedef std::shared_ptr StackFrameListSP; typedef std::shared_ptr StackFrameRecognizerSP; +typedef std::unique_ptr + StackFrameRecognizerManagerUP; typedef std::shared_ptr StopInfoSP; -typedef std::shared_ptr StoppointLocationSP; typedef std::shared_ptr StreamSP; typedef std::weak_ptr StreamWP; typedef std::shared_ptr StreamFileSP; @@ -430,8 +437,13 @@ typedef std::shared_ptr ThreadSP; typedef std::weak_ptr ThreadWP; typedef std::shared_ptr ThreadCollectionSP; typedef std::shared_ptr ThreadPlanSP; +typedef std::shared_ptr + ThreadPostMortemTraceSP; +typedef std::weak_ptr ThreadPlanWP; typedef std::shared_ptr ThreadPlanTracerSP; -typedef std::shared_ptr TraceOptionsSP; +typedef std::shared_ptr TraceSP; +typedef std::unique_ptr TraceExporterUP; +typedef std::unique_ptr TraceCursorUP; typedef std::shared_ptr TypeSP; typedef std::weak_ptr TypeWP; typedef std::shared_ptr TypeCategoryImplSP; diff --git a/gnu/llvm/lldb/include/lldb/lldb-private-interfaces.h b/gnu/llvm/lldb/include/lldb/lldb-private-interfaces.h index 1568e7a3cb5..2ed083ec8ae 100644 --- a/gnu/llvm/lldb/include/lldb/lldb-private-interfaces.h +++ b/gnu/llvm/lldb/include/lldb/lldb-private-interfaces.h @@ -18,6 +18,13 @@ #include #include +namespace llvm { +namespace json { +class Object; +class Value; +} +} // namespace llvm + namespace lldb_private { typedef lldb::ABISP (*ABICreateInstance)(lldb::ProcessSP process_sp, const ArchSpec &arch); @@ -47,7 +54,9 @@ typedef ObjectFile *(*ObjectFileCreateMemoryInstance)( const lldb::ModuleSP &module_sp, lldb::DataBufferSP &data_sp, const lldb::ProcessSP &process_sp, lldb::addr_t offset); typedef bool (*ObjectFileSaveCore)(const lldb::ProcessSP &process_sp, - const FileSpec &outfile, Status &error); + const FileSpec &outfile, + lldb::SaveCoreStyle &core_style, + Status &error); typedef EmulateInstruction *(*EmulateInstructionCreateInstance)( const ArchSpec &arch, InstructionType inst_type); typedef OperatingSystem *(*OperatingSystemCreateInstance)(Process *process, @@ -69,7 +78,7 @@ typedef lldb::PlatformSP (*PlatformCreateInstance)(bool force, const ArchSpec *arch); typedef lldb::ProcessSP (*ProcessCreateInstance)( lldb::TargetSP target_sp, lldb::ListenerSP listener_sp, - const FileSpec *crash_file_path); + const FileSpec *crash_file_path, bool can_connect); typedef lldb::ScriptInterpreterSP (*ScriptInterpreterCreateInstance)( Debugger &debugger); typedef SymbolFile *(*SymbolFileCreateInstance)(lldb::ObjectFileSP objfile_sp); @@ -104,7 +113,17 @@ typedef lldb::REPLSP (*REPLCreateInstance)(Status &error, const char *repl_options); typedef int (*ComparisonFunction)(const void *, const void *); typedef void (*DebuggerInitializeCallback)(Debugger &debugger); - +/// Trace +/// \{ +typedef llvm::Expected (*TraceCreateInstanceForSessionFile)( + const llvm::json::Value &trace_session_file, + llvm::StringRef session_file_dir, lldb_private::Debugger &debugger); +typedef llvm::Expected (*TraceCreateInstanceForLiveProcess)( + Process &process); +typedef llvm::Expected (*TraceExporterCreateInstance)(); +typedef lldb::CommandObjectSP (*ThreadTraceExportCommandCreator)( + CommandInterpreter &interpreter); +/// \} } // namespace lldb_private #endif // #if defined(__cplusplus) diff --git a/gnu/llvm/lldb/include/lldb/lldb-private-types.h b/gnu/llvm/lldb/include/lldb/lldb-private-types.h index fb8c2db2e21..73d618d7069 100644 --- a/gnu/llvm/lldb/include/lldb/lldb-private-types.h +++ b/gnu/llvm/lldb/include/lldb/lldb-private-types.h @@ -100,40 +100,13 @@ struct OptionEnumValueElement { using OptionEnumValues = llvm::ArrayRef; struct OptionValidator { - virtual ~OptionValidator() {} + virtual ~OptionValidator() = default; virtual bool IsValid(Platform &platform, const ExecutionContext &target) const = 0; virtual const char *ShortConditionString() const = 0; virtual const char *LongConditionString() const = 0; }; -struct OptionDefinition { - /// Used to mark options that can be used together. If - /// `(1 << n & usage_mask) != 0` then this option belongs to option set n. - uint32_t usage_mask; - /// This option is required (in the current usage level). - bool required; - /// Full name for this option. - const char *long_option; - /// Single character for this option. - int short_option; - /// no_argument, required_argument or optional_argument - int option_has_arg; - /// If non-NULL, option is valid iff |validator->IsValid()|, otherwise - /// always valid. - OptionValidator *validator; - /// If not empty, an array of enum values. - OptionEnumValues enum_values; - /// The kind of completion for this option. - /// Contains values of the CommandCompletions::CommonCompletionTypes enum. - uint32_t completion_type; - /// Type of argument this option takes. - lldb::CommandArgumentType argument_type; - /// Full text explaining what this options does and what (if any) argument to - /// pass it. - const char *usage_text; -}; - typedef struct type128 { uint64_t x[2]; } type128; typedef struct type256 { uint64_t x[4]; } type256; diff --git a/gnu/llvm/lldb/include/lldb/lldb-types.h b/gnu/llvm/lldb/include/lldb/lldb-types.h index c3e2f07acc4..976da35b11d 100644 --- a/gnu/llvm/lldb/include/lldb/lldb-types.h +++ b/gnu/llvm/lldb/include/lldb/lldb-types.h @@ -12,7 +12,7 @@ #include "lldb/lldb-enumerations.h" #include "lldb/lldb-forward.h" -#include +#include // All host systems must define: // lldb::thread_t The native thread type for spawned threads on the diff --git a/gnu/llvm/lldb/packages/Python/lldbsuite/__init__.py b/gnu/llvm/lldb/packages/Python/lldbsuite/__init__.py index 195b2683f7b..dfe2eec8eac 100644 --- a/gnu/llvm/lldb/packages/Python/lldbsuite/__init__.py +++ b/gnu/llvm/lldb/packages/Python/lldbsuite/__init__.py @@ -6,16 +6,17 @@ import sys def find_lldb_root(): - lldb_root = os.path.dirname(inspect.getfile(inspect.currentframe())) + lldb_root = os.path.realpath( + os.path.dirname(inspect.getfile(inspect.currentframe()))) while True: - lldb_root = os.path.dirname(lldb_root) - if lldb_root is None: - return None + parent = os.path.dirname(lldb_root) + if parent == lldb_root: # dirname('/') == '/' + raise Exception("use_lldb_suite_root.py not found") + lldb_root = parent test_path = os.path.join(lldb_root, "use_lldb_suite_root.py") if os.path.isfile(test_path): return lldb_root - return None # lldbsuite.lldb_root refers to the root of the git/svn source checkout lldb_root = find_lldb_root() diff --git a/gnu/llvm/lldb/packages/Python/lldbsuite/test/builders/__init__.py b/gnu/llvm/lldb/packages/Python/lldbsuite/test/builders/__init__.py new file mode 100644 index 00000000000..84024f29181 --- /dev/null +++ b/gnu/llvm/lldb/packages/Python/lldbsuite/test/builders/__init__.py @@ -0,0 +1,16 @@ +""" +This module builds test binaries for the test suite using Make. + +Platform specific builders can override methods in the Builder base class. The +factory method below hands out builders based on the given platform. +""" + + +def get_builder(platform): + """Returns a Builder instance for the given platform.""" + if platform == 'darwin': + from .darwin import BuilderDarwin + return BuilderDarwin() + + from .builder import Builder + return Builder() diff --git a/gnu/llvm/lldb/packages/Python/lldbsuite/test/builders/builder.py b/gnu/llvm/lldb/packages/Python/lldbsuite/test/builders/builder.py new file mode 100644 index 00000000000..6c9584224f4 --- /dev/null +++ b/gnu/llvm/lldb/packages/Python/lldbsuite/test/builders/builder.py @@ -0,0 +1,243 @@ +import os +import platform +import subprocess +import sys + +import lldbsuite.test.lldbtest as lldbtest +import lldbsuite.test.lldbutil as lldbutil +from lldbsuite.test import configuration +from lldbsuite.test_event import build_exception + + +class Builder: + def getArchitecture(self): + """Returns the architecture in effect the test suite is running with.""" + return configuration.arch if configuration.arch else "" + + def getCompiler(self): + """Returns the compiler in effect the test suite is running with.""" + compiler = configuration.compiler if configuration.compiler else "clang" + compiler = lldbutil.which(compiler) + return os.path.abspath(compiler) + + def getExtraMakeArgs(self): + """ + Helper function to return extra argumentsfor the make system. This + method is meant to be overridden by platform specific builders. + """ + return "" + + def getArchCFlags(self, architecture): + """Returns the ARCH_CFLAGS for the make system.""" + return "" + + def getMake(self, test_subdir, test_name): + """Returns the invocation for GNU make. + The first argument is a tuple of the relative path to the testcase + and its filename stem.""" + if platform.system() == "FreeBSD" or platform.system() == "NetBSD": + make = "gmake" + else: + make = "make" + + # Construct the base make invocation. + lldb_test = os.environ["LLDB_TEST"] + if not (lldb_test and configuration.test_build_dir and test_subdir + and test_name and (not os.path.isabs(test_subdir))): + raise Exception("Could not derive test directories") + build_dir = os.path.join(configuration.test_build_dir, test_subdir, + test_name) + src_dir = os.path.join(configuration.test_src_root, test_subdir) + # This is a bit of a hack to make inline testcases work. + makefile = os.path.join(src_dir, "Makefile") + if not os.path.isfile(makefile): + makefile = os.path.join(build_dir, "Makefile") + return [ + make, "VPATH=" + src_dir, "-C", build_dir, "-I", src_dir, "-I", + os.path.join(lldb_test, "make"), "-f", makefile + ] + + def getCmdLine(self, d): + """ + Helper function to return a properly formatted command line argument(s) + string used for the make system. + """ + + # If d is None or an empty mapping, just return an empty string. + if not d: + return "" + pattern = '%s="%s"' if "win32" in sys.platform else "%s='%s'" + + def setOrAppendVariable(k, v): + append_vars = ["CFLAGS", "CFLAGS_EXTRAS", "LD_EXTRAS"] + if k in append_vars and k in os.environ: + v = os.environ[k] + " " + v + return pattern % (k, v) + + cmdline = " ".join( + [setOrAppendVariable(k, v) for k, v in list(d.items())]) + + return cmdline + + def runBuildCommands(self, commands, sender): + try: + lldbtest.system(commands, sender=sender) + except subprocess.CalledProcessError as called_process_error: + # Convert to a build-specific error. + # We don't do that in lldbtest.system() since that + # is more general purpose. + raise build_exception.BuildError(called_process_error) + + def getArchSpec(self, architecture): + """ + Helper function to return the key-value string to specify the architecture + used for the make system. + """ + return ("ARCH=" + architecture) if architecture else "" + + def getCCSpec(self, compiler): + """ + Helper function to return the key-value string to specify the compiler + used for the make system. + """ + cc = compiler if compiler else None + if not cc and configuration.compiler: + cc = configuration.compiler + if cc: + return "CC=\"%s\"" % cc + else: + return "" + + def getSDKRootSpec(self): + """ + Helper function to return the key-value string to specify the SDK root + used for the make system. + """ + if configuration.sdkroot: + return "SDKROOT={}".format(configuration.sdkroot) + return "" + + def getModuleCacheSpec(self): + """ + Helper function to return the key-value string to specify the clang + module cache used for the make system. + """ + if configuration.clang_module_cache_dir: + return "CLANG_MODULE_CACHE_DIR={}".format( + configuration.clang_module_cache_dir) + return "" + + def buildDefault(self, + sender=None, + architecture=None, + compiler=None, + dictionary=None, + testdir=None, + testname=None): + """Build the binaries the default way.""" + commands = [] + commands.append( + self.getMake(testdir, testname) + [ + "all", + self.getArchCFlags(architecture), + self.getArchSpec(architecture), + self.getCCSpec(compiler), + self.getExtraMakeArgs(), + self.getSDKRootSpec(), + self.getModuleCacheSpec(), + self.getCmdLine(dictionary) + ]) + + self.runBuildCommands(commands, sender=sender) + + # True signifies that we can handle building default. + return True + + def buildDwarf(self, + sender=None, + architecture=None, + compiler=None, + dictionary=None, + testdir=None, + testname=None): + """Build the binaries with dwarf debug info.""" + commands = [] + commands.append( + self.getMake(testdir, testname) + [ + "MAKE_DSYM=NO", + self.getArchCFlags(architecture), + self.getArchSpec(architecture), + self.getCCSpec(compiler), + self.getExtraMakeArgs(), + self.getSDKRootSpec(), + self.getModuleCacheSpec(), + self.getCmdLine(dictionary) + ]) + + self.runBuildCommands(commands, sender=sender) + # True signifies that we can handle building dwarf. + return True + + def buildDwo(self, + sender=None, + architecture=None, + compiler=None, + dictionary=None, + testdir=None, + testname=None): + """Build the binaries with dwarf debug info.""" + commands = [] + commands.append( + self.getMake(testdir, testname) + [ + "MAKE_DSYM=NO", "MAKE_DWO=YES", + self.getArchCFlags(architecture), + self.getArchSpec(architecture), + self.getCCSpec(compiler), + self.getExtraMakeArgs(), + self.getSDKRootSpec(), + self.getModuleCacheSpec(), + self.getCmdLine(dictionary) + ]) + + self.runBuildCommands(commands, sender=sender) + # True signifies that we can handle building dwo. + return True + + def buildGModules(self, + sender=None, + architecture=None, + compiler=None, + dictionary=None, + testdir=None, + testname=None): + """Build the binaries with dwarf debug info.""" + commands = [] + commands.append( + self.getMake(testdir, testname) + [ + "MAKE_DSYM=NO", "MAKE_GMODULES=YES", + self.getArchCFlags(architecture), + self.getArchSpec(architecture), + self.getCCSpec(compiler), + self.getExtraMakeArgs(), + self.getSDKRootSpec(), + self.getModuleCacheSpec(), + self.getCmdLine(dictionary) + ]) + + self.runBuildCommands(commands, sender=sender) + # True signifies that we can handle building with gmodules. + return True + + def buildDsym(self, + sender=None, + architecture=None, + compiler=None, + dictionary=None, + testdir=None, + testname=None): + # False signifies that we cannot handle building with dSYM. + return False + + def cleanup(self, sender=None, dictionary=None): + """Perform a platform-specific cleanup after the test.""" + return True diff --git a/gnu/llvm/lldb/packages/Python/lldbsuite/test/builders/darwin.py b/gnu/llvm/lldb/packages/Python/lldbsuite/test/builders/darwin.py new file mode 100644 index 00000000000..c4a057e7158 --- /dev/null +++ b/gnu/llvm/lldb/packages/Python/lldbsuite/test/builders/darwin.py @@ -0,0 +1,128 @@ +import re +import os +import subprocess + +from .builder import Builder +from lldbsuite.test import configuration +import lldbsuite.test.lldbutil as lldbutil + +REMOTE_PLATFORM_NAME_RE = re.compile(r"^remote-(.+)$") +SIMULATOR_PLATFORM_RE = re.compile(r"^(.+)-simulator$") + + +def get_os_env_from_platform(platform): + match = REMOTE_PLATFORM_NAME_RE.match(platform) + if match: + return match.group(1), "" + match = SIMULATOR_PLATFORM_RE.match(platform) + if match: + return match.group(1), "simulator" + return None, None + + +def get_os_from_sdk(sdk): + return sdk[:sdk.find('.')], "" + + +def get_os_and_env(): + if configuration.lldb_platform_name: + return get_os_env_from_platform(configuration.lldb_platform_name) + if configuration.apple_sdk: + return get_os_from_sdk(configuration.apple_sdk) + return None, None + + +def get_triple(): + # Construct the vendor component. + vendor = "apple" + + # Construct the os component. + os, env = get_os_and_env() + if os is None or env is None: + return None, None, None, None + + # Get the SDK from the os and env. + sdk = lldbutil.get_xcode_sdk(os, env) + if sdk is None: + return None, None, None, None + + # Get the version from the SDK. + version = lldbutil.get_xcode_sdk_version(sdk) + if version is None: + return None, None, None, None + + return vendor, os, version, env + + +class BuilderDarwin(Builder): + def getExtraMakeArgs(self): + """ + Helper function to return extra argumentsfor the make system. This + method is meant to be overridden by platform specific builders. + """ + args = dict() + + if configuration.dsymutil: + args['DSYMUTIL'] = configuration.dsymutil + + operating_system, env = get_os_and_env() + if operating_system and operating_system != "macosx": + builder_dir = os.path.dirname(os.path.abspath(__file__)) + test_dir = os.path.dirname(builder_dir) + if env == "simulator": + entitlements_file = 'entitlements-simulator.plist' + else: + entitlements_file = 'entitlements.plist' + entitlements = os.path.join(test_dir, 'make', entitlements_file) + args['CODESIGN'] = 'codesign --entitlements {}'.format( + entitlements) + + # Return extra args as a formatted string. + return ' '.join( + {'{}="{}"'.format(key, value) + for key, value in args.items()}) + + def getArchCFlags(self, arch): + """Returns the ARCH_CFLAGS for the make system.""" + # Get the triple components. + vendor, os, version, env = get_triple() + if vendor is None or os is None or version is None or env is None: + return "" + + # Construct the triple from its components. + triple = '-'.join([arch, vendor, os, version, env]) + + # Construct min version argument + version_min = "" + if env == "simulator": + version_min = "-m{}-simulator-version-min={}".format(os, version) + elif os == "macosx": + version_min = "-m{}-version-min={}".format(os, version) + + return "ARCH_CFLAGS=\"-target {} {}\"".format(triple, version_min) + + def buildDsym(self, + sender=None, + architecture=None, + compiler=None, + dictionary=None, + testdir=None, + testname=None): + """Build the binaries with dsym debug info.""" + commands = [] + commands.append( + self.getMake(testdir, testname) + [ + "MAKE_DSYM=YES", + self.getArchCFlags(architecture), + self.getArchSpec(architecture), + self.getCCSpec(compiler), + self.getExtraMakeArgs(), + self.getSDKRootSpec(), + self.getModuleCacheSpec(), "all", + self.getCmdLine(dictionary) + ]) + + self.runBuildCommands(commands, sender=sender) + + # True signifies that we can handle building dsym. + return True diff --git a/gnu/llvm/lldb/packages/Python/lldbsuite/test/configuration.py b/gnu/llvm/lldb/packages/Python/lldbsuite/test/configuration.py index 84de0130f99..9b57666f92b 100644 --- a/gnu/llvm/lldb/packages/Python/lldbsuite/test/configuration.py +++ b/gnu/llvm/lldb/packages/Python/lldbsuite/test/configuration.py @@ -29,7 +29,7 @@ categories_list = None # set to true if we are going to use categories for cherry-picking test cases use_categories = False # Categories we want to skip -skip_categories = ["darwin-log"] +skip_categories = [] # Categories we expect to fail xfail_categories = [] # use this to track per-category failures @@ -76,20 +76,6 @@ regexp = None skip_tests = None xfail_tests = None -# By default, recorded session info for errored/failed test are dumped into its -# own file under a session directory named after the timestamp of the test suite -# run. Use '-s session-dir-name' to specify a specific dir name. -sdir_name = None - -# Valid options: -# f - test file name (without extension) -# n - test class name -# m - test method name -# a - architecture -# c - compiler path -# The default is to write all fields. -session_file_format = 'fnmac' - # Set this flag if there is any session info dumped during the test run. sdir_has_content = False # svn_info stores the output from 'svn info lldb.base.dir'. @@ -103,6 +89,10 @@ verbose = 0 # because it doesn't work under a debugger testdirs = [lldbsuite.lldb_test_root] +# The root of the test case tree (where the actual tests reside, not the test +# infrastructure). +test_src_root = lldbsuite.lldb_test_root + # Separator string. separator = '-' * 70 @@ -113,6 +103,9 @@ lldb_platform_name = None lldb_platform_url = None lldb_platform_working_dir = None +# Apple SDK +apple_sdk = None + # The base directory in which the tests are being built. test_build_dir = None @@ -128,9 +121,6 @@ test_result = None capture_path = None replay_path = None -# Test rerun configuration vars -rerun_all_issues = False - # The names of all tests. Used to assert we don't have two tests with the # same base name. all_tests = set() diff --git a/gnu/llvm/lldb/packages/Python/lldbsuite/test/decorators.py b/gnu/llvm/lldb/packages/Python/lldbsuite/test/decorators.py index 534bcbf59ac..d67572e75ec 100644 --- a/gnu/llvm/lldb/packages/Python/lldbsuite/test/decorators.py +++ b/gnu/llvm/lldb/packages/Python/lldbsuite/test/decorators.py @@ -3,6 +3,8 @@ from __future__ import absolute_import # System modules from distutils.version import LooseVersion from functools import wraps +import ctypes +import locale import os import platform import re @@ -19,7 +21,6 @@ import lldb from . import configuration from . import test_categories from . import lldbtest_config -from lldbsuite.test_event.event_builder import EventBuilder from lldbsuite.support import funcutils from lldbsuite.test import lldbplatform from lldbsuite.test import lldbplatformutil @@ -86,7 +87,23 @@ def _match_decorator_property(expected, actual): return expected == actual -def expectedFailure(expected_fn, bugnumber=None): +def _compiler_supports(compiler, flag): + """Test whether the compiler supports the given flag.""" + if platform.system() == 'Darwin': + compiler = "xcrun " + compiler + f = tempfile.NamedTemporaryFile() + try: + cmd = "echo 'int main() {}' | %s %s -x c -o %s -" % (compiler, flag, f.name) + subprocess.check_call(cmd, shell=True) + except subprocess.CalledProcessError: + return False + return True + + +def expectedFailure(func): + return unittest2.expectedFailure(func) + +def expectedFailureIfFn(expected_fn, bugnumber=None): def expectedFailure_impl(func): if isinstance(func, type) and issubclass(func, unittest2.TestCase): raise Exception( @@ -94,16 +111,8 @@ def expectedFailure(expected_fn, bugnumber=None): @wraps(func) def wrapper(*args, **kwargs): - self = args[0] - if funcutils.requires_self(expected_fn): - xfail_reason = expected_fn(self) - else: - xfail_reason = expected_fn() + xfail_reason = expected_fn(*args, **kwargs) if xfail_reason is not None: - if configuration.results_formatter_object is not None: - # Mark this test as expected to fail. - configuration.results_formatter_object.handle_event( - EventBuilder.event_for_mark_test_expected_failure(self)) xfail_func = unittest2.expectedFailure(func) xfail_func(*args, **kwargs) else: @@ -137,7 +146,7 @@ def skipTestIfFn(expected_fn, bugnumber=None): if reason is not None: self.skipTest(reason) else: - func(*args, **kwargs) + return func(*args, **kwargs) return wrapper # Some decorators can be called both with no arguments (e.g. @expectedFailureWindows) @@ -239,7 +248,7 @@ def _decorateTest(mode, if mode == DecorateMode.Skip: return skipTestIfFn(fn, bugnumber) elif mode == DecorateMode.Xfail: - return expectedFailure(fn, bugnumber) + return expectedFailureIfFn(fn, bugnumber) else: return None @@ -378,23 +387,12 @@ def apple_simulator_test(platform): def debugserver_test(func): """Decorate the item as a debugserver test.""" - def should_skip_debugserver_test(): - return "debugserver tests" if configuration.dont_do_debugserver_test else None - return skipTestIfFn(should_skip_debugserver_test)(func) + return add_test_categories(["debugserver"])(func) def llgs_test(func): """Decorate the item as a lldb-server test.""" - def should_skip_llgs_tests(): - return "llgs tests" if configuration.dont_do_llgs_test else None - return skipTestIfFn(should_skip_llgs_tests)(func) - - -def not_remote_testsuite_ready(func): - """Decorate the item as a test which is not ready yet for remote testsuite.""" - def is_remote(): - return "Not ready for remote testsuite" if lldb.remote_platform else None - return skipTestIfFn(is_remote)(func) + return add_test_categories(["llgs"])(func) def expectedFailureOS( @@ -432,7 +430,7 @@ def expectedFailureAndroid(bugnumber=None, api_levels=None, archs=None): arch - A sequence of architecture names specifying the architectures for which a test is expected to fail. None means all architectures. """ - return expectedFailure( + return expectedFailureIfFn( _skip_for_android( "xfailing on android", api_levels, @@ -445,21 +443,11 @@ def expectedFailureNetBSD(bugnumber=None): ['netbsd'], bugnumber) -# Flakey tests get two chances to run. If they fail the first time round, the result formatter -# makes sure it is run one more time. - - +# TODO: This decorator does not do anything. Remove it. def expectedFlakey(expected_fn, bugnumber=None): def expectedFailure_impl(func): @wraps(func) def wrapper(*args, **kwargs): - self = args[0] - if expected_fn(self): - # Send event marking test as explicitly eligible for rerunning. - if configuration.results_formatter_object is not None: - # Mark this test as rerunnable. - configuration.results_formatter_object.handle_event( - EventBuilder.event_for_mark_test_rerun_eligible(self)) func(*args, **kwargs) return wrapper # Some decorators can be called both with no arguments (e.g. @expectedFailureWindows) @@ -517,9 +505,7 @@ def skipIfOutOfTreeDebugserver(func): def skipIfRemote(func): """Decorate the item to skip tests if testing remotely.""" - def is_remote(): - return "skip on remote platform" if lldb.remote_platform else None - return skipTestIfFn(is_remote)(func) + return unittest2.skipIf(lldb.remote_platform, "skip on remote platform")(func) def skipIfNoSBHeaders(func): @@ -528,10 +514,9 @@ def skipIfNoSBHeaders(func): if lldb.remote_platform: return "skip because SBHeaders tests make no sense remotely" - if lldbplatformutil.getHostPlatform() == 'darwin': + if lldbplatformutil.getHostPlatform() == 'darwin' and configuration.lldb_framework_path: header = os.path.join( - os.environ["LLDB_LIB_DIR"], - 'LLDB.framework', + configuration.lldb_framework_path, 'Versions', 'Current', 'Headers', @@ -555,10 +540,9 @@ def skipIfNoSBHeaders(func): def skipIfRosetta(bugnumber): """Skip a test when running the testsuite on macOS under the Rosetta translation layer.""" def is_running_rosetta(self): - if not lldbplatformutil.getPlatform() in ['darwin', 'macosx']: - return "not on macOS" - if (platform.uname()[5] == "arm") and (self.getArchitecture() == "x86_64"): - return "skipped under Rosetta" + if lldbplatformutil.getPlatform() in ['darwin', 'macosx']: + if (platform.uname()[5] == "arm") and (self.getArchitecture() == "x86_64"): + return "skipped under Rosetta" return None return skipTestIfFn(is_running_rosetta) @@ -569,16 +553,16 @@ def skipIfiOSSimulator(func): return skipTestIfFn(is_ios_simulator)(func) def skipIfiOS(func): - return skipIfPlatform(["ios"])(func) + return skipIfPlatform(lldbplatform.translate(lldbplatform.ios))(func) def skipIftvOS(func): - return skipIfPlatform(["tvos"])(func) + return skipIfPlatform(lldbplatform.translate(lldbplatform.tvos))(func) def skipIfwatchOS(func): - return skipIfPlatform(["watchos"])(func) + return skipIfPlatform(lldbplatform.translate(lldbplatform.watchos))(func) def skipIfbridgeOS(func): - return skipIfPlatform(["bridgeos"])(func) + return skipIfPlatform(lldbplatform.translate(lldbplatform.bridgeos))(func) def skipIfDarwinEmbedded(func): """Decorate the item to skip tests that should be skipped on Darwin armv7/arm64 targets.""" @@ -586,6 +570,12 @@ def skipIfDarwinEmbedded(func): lldbplatform.translate( lldbplatform.darwin_embedded))(func) +def skipIfDarwinSimulator(func): + """Decorate the item to skip tests that should be skipped on Darwin simulator targets.""" + return skipIfPlatform( + lldbplatform.translate( + lldbplatform.darwin_simulator))(func) + def skipIfFreeBSD(func): """Decorate the item to skip tests that should be skipped on FreeBSD.""" return skipIfPlatform(["freebsd"])(func) @@ -612,6 +602,17 @@ def skipIfWindows(func): """Decorate the item to skip tests that should be skipped on Windows.""" return skipIfPlatform(["windows"])(func) +def skipIfWindowsAndNonEnglish(func): + """Decorate the item to skip tests that should be skipped on non-English locales on Windows.""" + def is_Windows_NonEnglish(self): + if sys.platform != "win32": + return None + kernel = ctypes.windll.kernel32 + if locale.windows_locale[ kernel.GetUserDefaultUILanguage() ] == "en_US": + return None + return "skipping non-English Windows locale" + return skipTestIfFn(is_Windows_NonEnglish)(func) + def skipUnlessWindows(func): """Decorate the item to skip tests that should be skipped on any non-Windows platform.""" return skipUnlessPlatform(["windows"])(func) @@ -742,12 +743,7 @@ def skipUnlessThreadSanitizer(func): # rdar://28659145 - TSAN tests don't look like they're supported on i386 if self.getArchitecture() == 'i386' and platform.system() == 'Darwin': return "TSAN tests not compatible with i386 targets" - f = tempfile.NamedTemporaryFile() - cmd = "echo 'int main() {}' | %s -x c -o %s -" % (compiler_path, f.name) - if os.popen(cmd).close() is not None: - return None # The compiler cannot compile at all, let's *not* skip the test - cmd = "echo 'int main() {}' | %s -fsanitize=thread -x c -o %s -" % (compiler_path, f.name) - if os.popen(cmd).close() is not None: + if not _compiler_supports(compiler_path, '-fsanitize=thread'): return "Compiler cannot compile with -fsanitize=thread" return None return skipTestIfFn(is_compiler_clang_with_thread_sanitizer)(func) @@ -768,8 +764,7 @@ def skipUnlessUndefinedBehaviorSanitizer(func): outputf = tempfile.NamedTemporaryFile() # Try to compile with ubsan turned on. - cmd = '%s -fsanitize=undefined %s -o %s' % (self.getCompiler(), inputf.name, outputf.name) - if os.popen(cmd).close() is not None: + if not _compiler_supports(self.getCompiler(), '-fsanitize=undefined'): return "Compiler cannot compile with -fsanitize=undefined" # Check that we actually see ubsan instrumentation in the binary. @@ -817,16 +812,9 @@ def skipUnlessAddressSanitizer(func): if is_running_under_asan(): return "Address sanitizer tests are disabled when runing under ASAN" - compiler_path = self.getCompiler() - compiler = os.path.basename(compiler_path) - f = tempfile.NamedTemporaryFile() if lldbplatformutil.getPlatform() == 'windows': return "ASAN tests not compatible with 'windows'" - cmd = "echo 'int main() {}' | %s -x c -o %s -" % (compiler_path, f.name) - if os.popen(cmd).close() is not None: - return None # The compiler cannot compile at all, let's *not* skip the test - cmd = "echo 'int main() {}' | %s -fsanitize=address -x c -o %s -" % (compiler_path, f.name) - if os.popen(cmd).close() is not None: + if not _compiler_supports(self.getCompiler(), '-fsanitize=address'): return "Compiler cannot compile with -fsanitize=address" return None return skipTestIfFn(is_compiler_with_address_sanitizer)(func) @@ -835,11 +823,53 @@ def skipIfAsan(func): """Skip this test if the environment is set up to run LLDB *itself* under ASAN.""" return skipTestIfFn(is_running_under_asan)(func) -def _get_bool_config_skip_if_decorator(key): +def skipUnlessAArch64MTELinuxCompiler(func): + """Decorate the item to skip test unless MTE is supported by the test compiler.""" + + def is_toolchain_with_mte(self): + compiler_path = self.getCompiler() + compiler = os.path.basename(compiler_path) + f = tempfile.NamedTemporaryFile() + if lldbplatformutil.getPlatform() == 'windows': + return "MTE tests are not compatible with 'windows'" + + cmd = "echo 'int main() {}' | %s -x c -o %s -" % (compiler_path, f.name) + if os.popen(cmd).close() is not None: + # Cannot compile at all, don't skip the test + # so that we report the broken compiler normally. + return None + + # We need the Linux headers and ACLE MTE intrinsics + test_src = """ + #include + #include + #ifndef HWCAP2_MTE + #error + #endif + int main() { + void* ptr = __arm_mte_create_random_tag((void*)(0), 0); + }""" + cmd = "echo '%s' | %s -march=armv8.5-a+memtag -x c -o %s -" % (test_src, compiler_path, f.name) + if os.popen(cmd).close() is not None: + return "Toolchain does not support MTE" + return None + + return skipTestIfFn(is_toolchain_with_mte)(func) + +def _get_bool_config(key, fail_value = True): + """ + Returns the current LLDB's build config value. + :param key The key to lookup in LLDB's build configuration. + :param fail_value The error value to return when the key can't be found. + Defaults to true so that if an unknown key is lookup up we rather + enable more tests (that then fail) than silently skipping them. + """ config = lldb.SBDebugger.GetBuildConfiguration() value_node = config.GetValueForKey(key) - fail_value = True # More likely to notice if something goes wrong - have = value_node.GetValueForKey("value").GetBooleanValue(fail_value) + return value_node.GetValueForKey("value").GetBooleanValue(fail_value) + +def _get_bool_config_skip_if_decorator(key): + have = _get_bool_config(key) return unittest2.skipIf(not have, "requires " + key) def skipIfCursesSupportMissing(func): @@ -881,8 +911,6 @@ def skipUnlessFeature(feature): def skipIfReproducer(func): """Skip this test if the environment is set up to run LLDB with reproducers.""" - def is_reproducer(): - if configuration.capture_path or configuration.replay_path: - return "reproducers unsupported" - return None - return skipTestIfFn(is_reproducer)(func) + return unittest2.skipIf( + configuration.capture_path or configuration.replay_path, + "reproducers unsupported")(func) diff --git a/gnu/llvm/lldb/packages/Python/lldbsuite/test/dotest.py b/gnu/llvm/lldb/packages/Python/lldbsuite/test/dotest.py index 67f227cad71..5c5583fb570 100644 --- a/gnu/llvm/lldb/packages/Python/lldbsuite/test/dotest.py +++ b/gnu/llvm/lldb/packages/Python/lldbsuite/test/dotest.py @@ -29,6 +29,7 @@ import logging import os import platform import re +import shutil import signal import subprocess import sys @@ -44,9 +45,7 @@ from . import configuration from . import dotest_args from . import lldbtest_config from . import test_categories -from lldbsuite.test_event import formatter from . import test_result -from lldbsuite.test_event.event_builder import EventBuilder from ..support import seven @@ -54,6 +53,9 @@ def is_exe(fpath): """Returns true if fpath is an executable.""" if fpath == None: return False + if sys.platform == 'win32': + if not fpath.endswith(".exe"): + fpath += ".exe" return os.path.isfile(fpath) and os.access(fpath, os.X_OK) @@ -243,7 +245,7 @@ def parseOptionsAndInitTestdirs(): do_help = True if args.compiler: - configuration.compiler = os.path.realpath(args.compiler) + configuration.compiler = os.path.abspath(args.compiler) if not is_exe(configuration.compiler): configuration.compiler = which(args.compiler) if not is_exe(configuration.compiler): @@ -271,21 +273,13 @@ def parseOptionsAndInitTestdirs(): elif platform_system == 'Darwin': configuration.dsymutil = seven.get_command_output( 'xcrun -find -toolchain default dsymutil') - - - # The lldb-dotest script produced by the CMake build passes in a path to a - # working FileCheck and yaml2obj binary. So does one specific Xcode - # project target. However, when invoking dotest.py directly, a valid - # --filecheck and --yaml2obj option needs to be given. - if args.filecheck: - configuration.filecheck = os.path.abspath(args.filecheck) - - if args.yaml2obj: - configuration.yaml2obj = os.path.abspath(args.yaml2obj) + if args.llvm_tools_dir: + configuration.filecheck = shutil.which("FileCheck", path=args.llvm_tools_dir) + configuration.yaml2obj = shutil.which("yaml2obj", path=args.llvm_tools_dir) if not configuration.get_filecheck_path(): logging.warning('No valid FileCheck executable; some tests may fail...') - logging.warning('(Double-check the --filecheck argument to dotest.py)') + logging.warning('(Double-check the --llvm-tools-dir argument to dotest.py)') if args.channels: lldbtest_config.channels = args.channels @@ -301,6 +295,11 @@ def parseOptionsAndInitTestdirs(): configuration.sdkroot = seven.get_command_output( 'xcrun --sdk "%s" --show-sdk-path 2> /dev/null' % (args.apple_sdk)) + if not configuration.sdkroot: + logging.error( + 'No SDK found with the name %s; aborting...', + args.apple_sdk) + sys.exit(-1) if args.arch: configuration.arch = args.arch @@ -367,12 +366,6 @@ def parseOptionsAndInitTestdirs(): args.executable) sys.exit(-1) - if args.server and args.out_of_tree_debugserver: - logging.warning('Both --server and --out-of-tree-debugserver are set') - - if args.server and not args.out_of_tree_debugserver: - os.environ['LLDB_DEBUGSERVER_PATH'] = args.server - if args.excluded: for excl_file in args.excluded: parseExclusion(excl_file) @@ -382,14 +375,6 @@ def parseOptionsAndInitTestdirs(): usage(parser) configuration.regexp = args.p - if args.s: - configuration.sdir_name = args.s - else: - timestamp_started = datetime.datetime.now().strftime("%Y-%m-%d-%H_%M_%S") - configuration.sdir_name = os.path.join(os.getcwd(), timestamp_started) - - configuration.session_file_format = args.session_file_format - if args.t: os.environ['LLDB_COMMAND_TRACE'] = 'YES' @@ -418,16 +403,14 @@ def parseOptionsAndInitTestdirs(): if args.replay_path: configuration.replay_path = args.replay_path - - # rerun-related arguments - configuration.rerun_all_issues = args.rerun_all_issues - if args.lldb_platform_name: configuration.lldb_platform_name = args.lldb_platform_name if args.lldb_platform_url: configuration.lldb_platform_url = args.lldb_platform_url if args.lldb_platform_working_dir: configuration.lldb_platform_working_dir = args.lldb_platform_working_dir + if platform_system == 'Darwin' and args.apple_sdk: + configuration.apple_sdk = args.apple_sdk if args.test_build_dir: configuration.test_build_dir = args.test_build_dir if args.lldb_module_cache_dir: @@ -453,26 +436,17 @@ def parseOptionsAndInitTestdirs(): lldbtest_config.codesign_identity = args.codesign_identity +def registerFaulthandler(): + try: + import faulthandler + except ImportError: + # faulthandler is not available until python3 + return -def setupTestResults(): - """Sets up test results-related objects based on arg settings.""" - - # Create the results formatter. - formatter_spec = formatter.create_results_formatter( - "lldbsuite.test_event.formatter.results_formatter.ResultsFormatter") - if formatter_spec is not None and formatter_spec.formatter is not None: - configuration.results_formatter_object = formatter_spec.formatter - - # Send an initialize message to the formatter. - initialize_event = EventBuilder.bare_event("initialize") - initialize_event["worker_count"] = 1 - - formatter_spec.formatter.handle_event(initialize_event) - - # Make sure we clean up the formatter on shutdown. - if formatter_spec.cleanup_func is not None: - atexit.register(formatter_spec.cleanup_func) - + faulthandler.enable() + # faulthandler.register is not available on Windows. + if getattr(faulthandler, 'register', None): + faulthandler.register(signal.SIGTERM, chain=True) def setupSysPath(): """ @@ -484,13 +458,12 @@ def setupSysPath(): if "DOTEST_PROFILE" in os.environ and "DOTEST_SCRIPT_DIR" in os.environ: scriptPath = os.environ["DOTEST_SCRIPT_DIR"] else: - scriptPath = os.path.dirname(os.path.realpath(__file__)) + scriptPath = os.path.dirname(os.path.abspath(__file__)) if not scriptPath.endswith('test'): print("This script expects to reside in lldb's test directory.") sys.exit(-1) os.environ["LLDB_TEST"] = scriptPath - os.environ["LLDB_TEST_SRC"] = lldbsuite.lldb_test_root # Set up the root build directory. if not configuration.test_build_dir: @@ -504,6 +477,7 @@ def setupSysPath(): pluginPath = os.path.join(scriptPath, 'plugins') toolsLLDBVSCode = os.path.join(scriptPath, 'tools', 'lldb-vscode') toolsLLDBServerPath = os.path.join(scriptPath, 'tools', 'lldb-server') + intelpt = os.path.join(scriptPath, 'tools', 'intelpt') # Insert script dir, plugin dir and lldb-server dir to the sys.path. sys.path.insert(0, pluginPath) @@ -511,8 +485,11 @@ def setupSysPath(): # "import lldb_vscode_testcase" from the VSCode tests sys.path.insert(0, toolsLLDBVSCode) # Adding test/tools/lldb-server to the path makes it easy - sys.path.insert(0, toolsLLDBServerPath) # to "import lldbgdbserverutils" from the lldb-server tests + sys.path.insert(0, toolsLLDBServerPath) + # Adding test/tools/intelpt to the path makes it easy + # to "import intelpt_testcase" from the lldb-server tests + sys.path.insert(0, intelpt) # This is the root of the lldb git/svn checkout # When this changes over to a package instead of a standalone script, this @@ -545,13 +522,6 @@ def setupSysPath(): print("The 'lldb' executable cannot be located. Some of the tests may not be run as a result.") sys.exit(-1) - # confusingly, this is the "bin" directory - lldbLibDir = os.path.dirname(lldbtest_config.lldbExec) - os.environ["LLDB_LIB_DIR"] = lldbLibDir - lldbImpLibDir = configuration.lldb_libs_dir - os.environ["LLDB_IMPLIB_DIR"] = lldbImpLibDir - print("LLDB library dir:", os.environ["LLDB_LIB_DIR"]) - print("LLDB import library dir:", os.environ["LLDB_IMPLIB_DIR"]) os.system('%s -v' % lldbtest_config.lldbExec) lldbDir = os.path.dirname(lldbtest_config.lldbExec) @@ -566,70 +536,33 @@ def setupSysPath(): configuration.skip_categories.append("lldb-vscode") lldbPythonDir = None # The directory that contains 'lldb/__init__.py' - if not configuration.lldb_framework_path and os.path.exists(os.path.join(lldbLibDir, "LLDB.framework")): - configuration.lldb_framework_path = os.path.join(lldbLibDir, "LLDB.framework") - if configuration.lldb_framework_path: - lldbtest_config.lldb_framework_path = configuration.lldb_framework_path - candidatePath = os.path.join( - configuration.lldb_framework_path, 'Resources', 'Python') - if os.path.isfile(os.path.join(candidatePath, 'lldb/__init__.py')): - lldbPythonDir = candidatePath - if not lldbPythonDir: - print( - 'Resources/Python/lldb/__init__.py was not found in ' + - configuration.lldb_framework_path) - sys.exit(-1) - else: - # If our lldb supports the -P option, use it to find the python path: - init_in_python_dir = os.path.join('lldb', '__init__.py') - - lldb_dash_p_result = subprocess.check_output( - [lldbtest_config.lldbExec, "-P"], stderr=subprocess.STDOUT, universal_newlines=True) - - if lldb_dash_p_result and not lldb_dash_p_result.startswith( - ("<", "lldb: invalid option:")) and not lldb_dash_p_result.startswith("Traceback"): - lines = lldb_dash_p_result.splitlines() - - # Workaround for readline vs libedit issue on FreeBSD. If stdout - # is not a terminal Python executes - # rl_variable_bind ("enable-meta-key", "off"); - # This produces a warning with FreeBSD's libedit because the - # enable-meta-key variable is unknown. Not an issue on Apple - # because cpython commit f0ab6f9f0603 added a #ifndef __APPLE__ - # around the call. See http://bugs.python.org/issue19884 for more - # information. For now we just discard the warning output. - if len(lines) >= 1 and lines[0].startswith( - "bind: Invalid command"): - lines.pop(0) - - # Taking the last line because lldb outputs - # 'Cannot read termcap database;\nusing dumb terminal settings.\n' - # before the path - if len(lines) >= 1 and os.path.isfile( - os.path.join(lines[-1], init_in_python_dir)): - lldbPythonDir = lines[-1] - if "freebsd" in sys.platform or "linux" in sys.platform: - os.environ['LLDB_LIB_DIR'] = os.path.join( - lldbPythonDir, '..', '..') - - if not lldbPythonDir: - print( - "Unable to load lldb extension module. Possible reasons for this include:") - print(" 1) LLDB was built with LLDB_ENABLE_PYTHON=0") - print( - " 2) PYTHONPATH and PYTHONHOME are not set correctly. PYTHONHOME should refer to") - print( - " the version of Python that LLDB built and linked against, and PYTHONPATH") - print( - " should contain the Lib directory for the same python distro, as well as the") - print(" location of LLDB\'s site-packages folder.") - print( - " 3) A different version of Python than that which was built against is exported in") - print(" the system\'s PATH environment variable, causing conflicts.") - print( - " 4) The executable '%s' could not be found. Please check " % - lldbtest_config.lldbExec) - print(" that it exists and is executable.") + + # If our lldb supports the -P option, use it to find the python path: + lldb_dash_p_result = subprocess.check_output([lldbtest_config.lldbExec, "-P"], universal_newlines=True) + if lldb_dash_p_result: + for line in lldb_dash_p_result.splitlines(): + if os.path.isdir(line) and os.path.exists(os.path.join(line, 'lldb', '__init__.py')): + lldbPythonDir = line + break + + if not lldbPythonDir: + print( + "Unable to load lldb extension module. Possible reasons for this include:") + print(" 1) LLDB was built with LLDB_ENABLE_PYTHON=0") + print( + " 2) PYTHONPATH and PYTHONHOME are not set correctly. PYTHONHOME should refer to") + print( + " the version of Python that LLDB built and linked against, and PYTHONPATH") + print( + " should contain the Lib directory for the same python distro, as well as the") + print(" location of LLDB\'s site-packages folder.") + print( + " 3) A different version of Python than that which was built against is exported in") + print(" the system\'s PATH environment variable, causing conflicts.") + print( + " 4) The executable '%s' could not be found. Please check " % + lldbtest_config.lldbExec) + print(" that it exists and is executable.") if lldbPythonDir: lldbPythonDir = os.path.normpath(lldbPythonDir) @@ -643,6 +576,9 @@ def setupSysPath(): lldbPythonDir = os.path.abspath(lldbPythonDir) + if "freebsd" in sys.platform or "linux" in sys.platform: + os.environ['LLDB_LIB_DIR'] = os.path.join(lldbPythonDir, '..', '..') + # If tests need to find LLDB_FRAMEWORK, now they can do it os.environ["LLDB_FRAMEWORK"] = os.path.dirname( os.path.dirname(lldbPythonDir)) @@ -732,31 +668,17 @@ def visit(prefix, dir, names): # Visit all the python test files. for name in python_test_files: - try: - # Ensure we error out if we have multiple tests with the same - # base name. - # Future improvement: find all the places where we work with base - # names and convert to full paths. We have directory structure - # to disambiguate these, so we shouldn't need this constraint. - if name in configuration.all_tests: - raise Exception("Found multiple tests with the name %s" % name) - configuration.all_tests.add(name) - - # Run the relevant tests in the python file. - visit_file(dir, name) - except Exception as ex: - # Convert this exception to a test event error for the file. - test_filename = os.path.abspath(os.path.join(dir, name)) - if configuration.results_formatter_object is not None: - # Grab the backtrace for the exception. - import traceback - backtrace = traceback.format_exc() - - # Generate the test event. - configuration.results_formatter_object.handle_event( - EventBuilder.event_for_job_test_add_error( - test_filename, ex, backtrace)) - raise + # Ensure we error out if we have multiple tests with the same + # base name. + # Future improvement: find all the places where we work with base + # names and convert to full paths. We have directory structure + # to disambiguate these, so we shouldn't need this constraint. + if name in configuration.all_tests: + raise Exception("Found multiple tests with the name %s" % name) + configuration.all_tests.add(name) + + # Run the relevant tests in the python file. + visit_file(dir, name) # ======================================== # @@ -802,15 +724,6 @@ def getVersionForSDK(sdk): return ver -def setDefaultTripleForPlatform(): - if configuration.lldb_platform_name == 'ios-simulator': - triple_str = 'x86_64-apple-ios%s' % ( - getVersionForSDK('iphonesimulator')) - os.environ['TRIPLE'] = triple_str - return {'TRIPLE': triple_str} - return {} - - def checkCompiler(): # Add some intervention here to sanity check that the compiler requested is sane. # If found not to be an executable program, we abort. @@ -839,12 +752,10 @@ def canRunLibcxxTests(): return True, "libc++ always present" if platform == "linux": - if os.path.isdir("/usr/include/c++/v1"): - return True, "Headers found, let's hope they work" with tempfile.NamedTemporaryFile() as f: cmd = [configuration.compiler, "-xc++", "-stdlib=libc++", "-o", f.name, "-"] p = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True) - _, stderr = p.communicate("#include \nint main() {}") + _, stderr = p.communicate("#include \nint main() {}") if not p.returncode: return True, "Compiling with -stdlib=libc++ works" return False, "Compiling with -stdlib=libc++ fails with the error: %s" % stderr @@ -857,7 +768,8 @@ def checkLibcxxSupport(): return # libc++ supported if "libc++" in configuration.categories_list: return # libc++ category explicitly requested, let it run. - print("Libc++ tests will not be run because: " + reason) + if configuration.verbose: + print("libc++ tests will not be run because: " + reason) configuration.skip_categories.append("libc++") def canRunLibstdcxxTests(): @@ -876,7 +788,8 @@ def checkLibstdcxxSupport(): return # libstdcxx supported if "libstdcxx" in configuration.categories_list: return # libstdcxx category explicitly requested, let it run. - print("libstdcxx tests will not be run because: " + reason) + if configuration.verbose: + print("libstdcxx tests will not be run because: " + reason) configuration.skip_categories.append("libstdcxx") def canRunWatchpointTests(): @@ -894,6 +807,10 @@ def canRunWatchpointTests(): except subprocess.CalledProcessError: pass return False, "security.models.extensions.user_set_dbregs disabled" + elif platform == "freebsd" and configuration.arch == "aarch64": + import lldb + if lldb.SBPlatform.GetHostPlatform().GetOSMajorVersion() < 13: + return False, "Watchpoint support on arm64 requires FreeBSD 13.0" return True, "watchpoint support available" def checkWatchpointSupport(): @@ -902,24 +819,57 @@ def checkWatchpointSupport(): return # watchpoints supported if "watchpoint" in configuration.categories_list: return # watchpoint category explicitly requested, let it run. - print("watchpoint tests will not be run because: " + reason) + if configuration.verbose: + print("watchpoint tests will not be run because: " + reason) configuration.skip_categories.append("watchpoint") +def checkObjcSupport(): + from lldbsuite.test import lldbplatformutil + + if not lldbplatformutil.platformIsDarwin(): + if configuration.verbose: + print("objc tests will be skipped because of unsupported platform") + configuration.skip_categories.append("objc") + def checkDebugInfoSupport(): import lldb platform = lldb.selected_platform.GetTriple().split('-')[2] compiler = configuration.compiler - skipped = [] for cat in test_categories.debug_info_categories: if cat in configuration.categories_list: continue # Category explicitly requested, let it run. if test_categories.is_supported_on_platform(cat, platform, compiler): continue configuration.skip_categories.append(cat) - skipped.append(cat) - if skipped: - print("Skipping following debug info categories:", skipped) + +def checkDebugServerSupport(): + from lldbsuite.test import lldbplatformutil + import lldb + + skip_msg = "Skipping %s tests, as they are not compatible with remote testing on this platform" + if lldbplatformutil.platformIsDarwin(): + configuration.skip_categories.append("llgs") + if lldb.remote_platform: + # + configuration.skip_categories.append("debugserver") + if configuration.verbose: + print(skip_msg%"debugserver"); + else: + configuration.skip_categories.append("debugserver") + if lldb.remote_platform and lldbplatformutil.getPlatform() == "windows": + configuration.skip_categories.append("llgs") + if configuration.verbose: + print(skip_msg%"lldb-server"); + + +def checkForkVForkSupport(): + from lldbsuite.test import lldbplatformutil + + platform = lldbplatformutil.getPlatform() + if platform not in ["freebsd", "linux", "netbsd"]: + configuration.skip_categories.append("fork") + def run_suite(): # On MacOS X, check to make sure that domain for com.apple.DebugSymbols defaults @@ -933,8 +883,8 @@ def run_suite(): # parseOptionsAndInitTestdirs() - # Setup test results (test results formatter and output handling). - setupTestResults() + # Print a stack trace if the test hangs or is passed SIGTERM. + registerFaulthandler() setupSysPath() @@ -979,6 +929,7 @@ def run_suite(): err = lldb.remote_platform.ConnectRemote(platform_connect_options) if err.Success(): print("Connected.") + lldb.selected_platform = lldb.remote_platform else: print("error: failed to connect to remote platform using URL '%s': %s" % ( configuration.lldb_platform_url, err)) @@ -986,14 +937,6 @@ def run_suite(): else: configuration.lldb_platform_url = None - platform_changes = setDefaultTripleForPlatform() - first = True - for key in platform_changes: - if first: - print("Environment variables setup for platform support:") - first = False - print("%s = %s" % (key, platform_changes[key])) - if configuration.lldb_platform_working_dir: print("Setting remote platform working directory to '%s'..." % (configuration.lldb_platform_working_dir)) @@ -1016,25 +959,15 @@ def run_suite(): # Note that it's not dotest's job to clean this directory. lldbutil.mkdir_p(configuration.test_build_dir) - target_platform = lldb.selected_platform.GetTriple().split('-')[2] - checkLibcxxSupport() checkLibstdcxxSupport() checkWatchpointSupport() checkDebugInfoSupport() + checkDebugServerSupport() + checkObjcSupport() + checkForkVForkSupport() - # Don't do debugserver tests on anything except OS X. - configuration.dont_do_debugserver_test = ( - "linux" in target_platform or - "freebsd" in target_platform or - "netbsd" in target_platform or - "windows" in target_platform) - - # Don't do lldb-server (llgs) tests on anything except Linux and Windows. - configuration.dont_do_llgs_test = not ( - "linux" in target_platform or - "netbsd" in target_platform or - "windows" in target_platform) + print("Skipping the following test categories: {}".format(configuration.skip_categories)) for testdir in configuration.testdirs: for (dirpath, dirnames, filenames) in os.walk(testdir): @@ -1047,14 +980,6 @@ def run_suite(): # Install the control-c handler. unittest2.signals.installHandler() - lldbutil.mkdir_p(configuration.sdir_name) - os.environ["LLDB_SESSION_DIRNAME"] = configuration.sdir_name - - sys.stderr.write( - "\nSession logs for test failures/errors/unexpected successes" - " will go into directory '%s'\n" % - configuration.sdir_name) - # # Invoke the default TextTestRunner to run the test suite # @@ -1079,6 +1004,10 @@ def run_suite(): (configuration.suite.countTestCases(), configuration.suite.countTestCases() != 1 and "s" or "")) + if configuration.suite.countTestCases() == 0: + logging.error("did not discover any matching tests") + exitTestSuite(1) + # Invoke the test runner. if configuration.count == 1: result = unittest2.TextTestRunner( @@ -1104,8 +1033,7 @@ def run_suite(): if configuration.sdir_has_content and configuration.verbose: sys.stderr.write( "Session logs for test failures/errors/unexpected successes" - " can be found in directory '%s'\n" % - configuration.sdir_name) + " can be found in the test build directory\n") if configuration.use_categories and len( configuration.failures_per_category) > 0: diff --git a/gnu/llvm/lldb/packages/Python/lldbsuite/test/dotest_args.py b/gnu/llvm/lldb/packages/Python/lldbsuite/test/dotest_args.py index 05dd523e744..af45205ae3e 100644 --- a/gnu/llvm/lldb/packages/Python/lldbsuite/test/dotest_args.py +++ b/gnu/llvm/lldb/packages/Python/lldbsuite/test/dotest_args.py @@ -51,8 +51,8 @@ def create_parser(): suggestions: do not lump the "-A arch1 -A arch2" together such that the -E option applies to only one of the architectures''')) group.add_argument('--dsymutil', metavar='dsymutil', dest='dsymutil', help=textwrap.dedent('Specify which dsymutil to use.')) - group.add_argument('--yaml2obj', metavar='yaml2obj', dest='yaml2obj', help=textwrap.dedent('Specify which yaml2obj binary to use.')) - group.add_argument('--filecheck', metavar='filecheck', dest='filecheck', help=textwrap.dedent('Specify which FileCheck binary to use.')) + group.add_argument('--llvm-tools-dir', metavar='dir', dest='llvm_tools_dir', + help=textwrap.dedent('The location of llvm tools used for testing (yaml2obj, FileCheck, etc.).')) # Test filtering options group = parser.add_argument_group('Test filtering options') @@ -100,10 +100,6 @@ def create_parser(): '--executable', metavar='executable-path', help='The path to the lldb executable') - group.add_argument( - '--server', - metavar='server-path', - help='The path to the debug server executable to use') group.add_argument( '--out-of-tree-debugserver', dest='out_of_tree_debugserver', @@ -123,16 +119,6 @@ def create_parser(): nargs=1, action='append', help='Run "setting set SETTING VALUE" before executing any test.') - group.add_argument( - '-s', - metavar='name', - help='Specify the name of the dir created to store the session files of tests with errored or failed status. If not specified, the test driver uses the timestamp as the session dir name') - group.add_argument( - '-S', - '--session-file-format', - default=configuration.session_file_format, - metavar='format', - help='Specify session file name format. See configuration.py for a description.') group.add_argument( '-y', type=int, @@ -244,16 +230,6 @@ def create_parser(): help='(Windows only) When LLDB crashes, display the Windows crash dialog.') group.set_defaults(disable_crash_dialog=True) - # Re-run related arguments - group = parser.add_argument_group('Test Re-run Options') - group.add_argument( - '--rerun-all-issues', - action='store_true', - help=('Re-run all issues that occurred during the test run ' - 'irrespective of the test method\'s marking as flakey. ' - 'Default behavior is to apply re-runs only to flakey ' - 'tests that generate issues.')) - # Remove the reference to our helper function del X diff --git a/gnu/llvm/lldb/packages/Python/lldbsuite/test/lldbdwarf.py b/gnu/llvm/lldb/packages/Python/lldbsuite/test/lldbdwarf.py index 217f8bc0e2b..5492960d2d7 100644 --- a/gnu/llvm/lldb/packages/Python/lldbsuite/test/lldbdwarf.py +++ b/gnu/llvm/lldb/packages/Python/lldbsuite/test/lldbdwarf.py @@ -159,7 +159,6 @@ DW_OP_implicit_value = 0x9E DW_OP_stack_value = 0x9F DW_OP_lo_user = 0xE0 DW_OP_GNU_push_tls_address = 0xE0 -DW_OP_APPLE_uninit = 0xF0 DW_OP_hi_user = 0xFF diff --git a/gnu/llvm/lldb/packages/Python/lldbsuite/test/lldbpexpect.py b/gnu/llvm/lldb/packages/Python/lldbsuite/test/lldbpexpect.py index d599bc39762..388e9189288 100644 --- a/gnu/llvm/lldb/packages/Python/lldbsuite/test/lldbpexpect.py +++ b/gnu/llvm/lldb/packages/Python/lldbsuite/test/lldbpexpect.py @@ -11,58 +11,67 @@ import six import lldb from .lldbtest import * from . import lldbutil +from lldbsuite.test.decorators import * -if sys.platform.startswith('win32'): - # llvm.org/pr22274: need a pexpect replacement for windows - class PExpectTest(object): - pass -else: - import pexpect +@skipIfRemote +@skipIfWindows # llvm.org/pr22274: need a pexpect replacement for windows +class PExpectTest(TestBase): - class PExpectTest(TestBase): + NO_DEBUG_INFO_TESTCASE = True + PROMPT = "(lldb) " - NO_DEBUG_INFO_TESTCASE = True - PROMPT = "(lldb) " + def expect_prompt(self): + self.child.expect_exact(self.PROMPT) - def expect_prompt(self): - self.child.expect_exact(self.PROMPT) + def launch(self, executable=None, extra_args=None, timeout=30, dimensions=None): + logfile = getattr(sys.stdout, 'buffer', + sys.stdout) if self.TraceOn() else None - def launch(self, executable=None, extra_args=None, timeout=30, dimensions=None): - logfile = getattr(sys.stdout, 'buffer', - sys.stdout) if self.TraceOn() else None + args = ['--no-lldbinit', '--no-use-colors'] + for cmd in self.setUpCommands(): + args += ['-O', cmd] + if executable is not None: + args += ['--file', executable] + if extra_args is not None: + args.extend(extra_args) - args = ['--no-lldbinit', '--no-use-colors'] - for cmd in self.setUpCommands(): - args += ['-O', cmd] - if executable is not None: - args += ['--file', executable] - if extra_args is not None: - args.extend(extra_args) + env = dict(os.environ) + env["TERM"]="vt100" - env = dict(os.environ) - env["TERM"]="vt100" - - self.child = pexpect.spawn( - lldbtest_config.lldbExec, args=args, logfile=logfile, - timeout=timeout, dimensions=dimensions, env=env) + import pexpect + self.child = pexpect.spawn( + lldbtest_config.lldbExec, args=args, logfile=logfile, + timeout=timeout, dimensions=dimensions, env=env) + self.expect_prompt() + for cmd in self.setUpCommands(): + self.child.expect_exact(cmd) self.expect_prompt() - for cmd in self.setUpCommands(): - self.child.expect_exact(cmd) - self.expect_prompt() - if executable is not None: - self.child.expect_exact("target create") - self.child.expect_exact("Current executable set to") - self.expect_prompt() - - def expect(self, cmd, substrs=None): - self.assertNotIn('\n', cmd) - self.child.sendline(cmd) - if substrs is not None: - for s in substrs: - self.child.expect_exact(s) + if executable is not None: + self.child.expect_exact("target create") + self.child.expect_exact("Current executable set to") self.expect_prompt() - def quit(self, gracefully=True): - self.child.sendeof() - self.child.close(force=not gracefully) - self.child = None + def expect(self, cmd, substrs=None): + self.assertNotIn('\n', cmd) + # If 'substrs' is a string then this code would just check that every + # character of the string is in the output. + assert not isinstance(substrs, six.string_types), \ + "substrs must be a collection of strings" + + self.child.sendline(cmd) + if substrs is not None: + for s in substrs: + self.child.expect_exact(s) + self.expect_prompt() + + def quit(self, gracefully=True): + self.child.sendeof() + self.child.close(force=not gracefully) + self.child = None + + def cursor_forward_escape_seq(self, chars_to_move): + """ + Returns the escape sequence to move the cursor forward/right + by a certain amount of characters. + """ + return b"\x1b\[" + str(chars_to_move).encode("utf-8") + b"C" diff --git a/gnu/llvm/lldb/packages/Python/lldbsuite/test/lldbplatform.py b/gnu/llvm/lldb/packages/Python/lldbsuite/test/lldbplatform.py index 365c752758d..18a4fe5754d 100644 --- a/gnu/llvm/lldb/packages/Python/lldbsuite/test/lldbplatform.py +++ b/gnu/llvm/lldb/packages/Python/lldbsuite/test/lldbplatform.py @@ -11,20 +11,25 @@ import six # LLDB modules import lldb -windows, linux, macosx, darwin, ios, tvos, watchos, bridgeos, darwin_all, darwin_embedded, freebsd, netbsd, bsd_all, android = range( - 14) +windows, linux, macosx, darwin, ios, tvos, watchos, bridgeos, darwin_all, \ + darwin_embedded, darwin_simulator, freebsd, netbsd, bsd_all, android \ + = range(15) + +__darwin_embedded = ["ios", "tvos", "watchos", "bridgeos"] +__darwin_simulators = ["iphonesimulator", "watchsimulator", "appletvsimulator"] __name_lookup = { windows: ["windows"], linux: ["linux"], macosx: ["macosx"], darwin: ["darwin"], - ios: ["ios"], - tvos: ["tvos"], - watchos: ["watchos"], + ios: ["ios", "iphonesimulator"], + tvos: ["tvos", "appletvsimulator"], + watchos: ["watchos", "watchsimulator"], bridgeos: ["bridgeos"], - darwin_all: ["macosx", "darwin", "ios", "tvos", "watchos", "bridgeos"], - darwin_embedded: ["ios", "tvos", "watchos", "bridgeos"], + darwin_all: ["macosx", "darwin"] + __darwin_embedded + __darwin_simulators, + darwin_embedded: __darwin_embedded + __darwin_simulators, + darwin_simulator: __darwin_simulators, freebsd: ["freebsd"], netbsd: ["netbsd"], bsd_all: ["freebsd", "netbsd"], diff --git a/gnu/llvm/lldb/packages/Python/lldbsuite/test/lldbplatformutil.py b/gnu/llvm/lldb/packages/Python/lldbsuite/test/lldbplatformutil.py index 44659cac4c7..94b133589dc 100644 --- a/gnu/llvm/lldb/packages/Python/lldbsuite/test/lldbplatformutil.py +++ b/gnu/llvm/lldb/packages/Python/lldbsuite/test/lldbplatformutil.py @@ -4,11 +4,12 @@ architecture and/or the platform dependent nature of the tests. """ from __future__ import absolute_import # System modules +import ctypes import itertools +import os import re import subprocess import sys -import os # Third-party modules import six @@ -124,22 +125,32 @@ def getHostPlatform(): def getDarwinOSTriples(): - return ['darwin', 'macosx', 'ios', 'watchos', 'tvos', 'bridgeos'] - + return lldbplatform.translate(lldbplatform.darwin_all) def getPlatform(): """Returns the target platform which the tests are running on.""" + # Use the Apple SDK to determine the platform if set. + if configuration.apple_sdk: + platform = configuration.apple_sdk + dot = platform.find('.') + if dot != -1: + platform = platform[:dot] + if platform == 'iphoneos': + platform = 'ios' + return platform + + # Use the triple to determine the platform if set. triple = lldb.selected_platform.GetTriple() - if triple is None: - # It might be an unconnected remote platform. - return '' + if triple: + platform = triple.split('-')[2] + if platform.startswith('freebsd'): + platform = 'freebsd' + elif platform.startswith('netbsd'): + platform = 'netbsd' + return platform - platform = triple.split('-')[2] - if platform.startswith('freebsd'): - platform = 'freebsd' - elif platform.startswith('netbsd'): - platform = 'netbsd' - return platform + # It still might be an unconnected remote platform. + return '' def platformIsDarwin(): @@ -188,3 +199,14 @@ def hasChattyStderr(test_case): if match_android_device(test_case.getArchitecture(), ['aarch64'], range(22, 25+1)): return True # The dynamic linker on the device will complain about unknown DT entries return False + +if getHostPlatform() == "linux": + def enable_attach(): + """Enable attaching to _this_ process, if host requires such an action. + Suitable for use as a preexec_fn in subprocess.Popen and similar.""" + c = ctypes.CDLL(None) + PR_SET_PTRACER = ctypes.c_int(0x59616d61) + PR_SET_PTRACER_ANY = ctypes.c_ulong(-1) + c.prctl(PR_SET_PTRACER, PR_SET_PTRACER_ANY) +else: + enable_attach = None diff --git a/gnu/llvm/lldb/packages/Python/lldbsuite/test/lldbtest.py b/gnu/llvm/lldb/packages/Python/lldbsuite/test/lldbtest.py index 9c32bdb42e2..7e1fdce36ed 100644 --- a/gnu/llvm/lldb/packages/Python/lldbsuite/test/lldbtest.py +++ b/gnu/llvm/lldb/packages/Python/lldbsuite/test/lldbtest.py @@ -67,6 +67,7 @@ from . import lldbutil from . import test_categories from lldbsuite.support import encoded_file from lldbsuite.support import funcutils +from lldbsuite.test.builders import get_builder # See also dotest.parseOptionsAndInitTestdirs(), where the environment variables # LLDB_COMMAND_TRACE is set from '-t' option. @@ -125,6 +126,8 @@ OBJECT_PRINTED_CORRECTLY = "Object printed correctly" SOURCE_DISPLAYED_CORRECTLY = "Source code displayed correctly" +STEP_IN_SUCCEEDED = "Thread step-in succeeded" + STEP_OUT_SUCCEEDED = "Thread step-out succeeded" STOPPED_DUE_TO_EXC_BAD_ACCESS = "Process should be stopped due to bad access exception" @@ -178,27 +181,27 @@ WATCHPOINT_CREATED = "Watchpoint created successfully" def CMD_MSG(str): - '''A generic "Command '%s' returns successfully" message generator.''' - return "Command '%s' returns successfully" % str + '''A generic "Command '%s' did not return successfully" message generator.''' + return "Command '%s' did not return successfully" % str def COMPLETION_MSG(str_before, str_after, completions): - '''A generic message generator for the completion mechanism.''' + '''A generic assertion failed message generator for the completion mechanism.''' return ("'%s' successfully completes to '%s', but completions were:\n%s" % (str_before, str_after, "\n".join(completions))) def EXP_MSG(str, actual, exe): - '''A generic "'%s' returns expected result" message generator if exe. - Otherwise, it generates "'%s' matches expected result" message.''' + '''A generic "'%s' returned unexpected result" message generator if exe. + Otherwise, it generates "'%s' does not match expected result" message.''' - return "'%s' %s expected result, got '%s'" % ( - str, 'returns' if exe else 'matches', actual.strip()) + return "'%s' %s result, got '%s'" % ( + str, 'returned unexpected' if exe else 'does not match expected', actual.strip()) def SETTING_MSG(setting): - '''A generic "Value of setting '%s' is correct" message generator.''' - return "Value of setting '%s' is correct" % setting + '''A generic "Value of setting '%s' is not correct" message generator.''' + return "Value of setting '%s' is not correct" % setting def line_number(filename, string_to_match): @@ -242,6 +245,77 @@ def which(program): return exe_file return None +class ValueCheck: + def __init__(self, name=None, value=None, type=None, summary=None, + children=None): + """ + :param name: The name that the SBValue should have. None if the summary + should not be checked. + :param summary: The summary that the SBValue should have. None if the + summary should not be checked. + :param value: The value that the SBValue should have. None if the value + should not be checked. + :param type: The type that the SBValue result should have. None if the + type should not be checked. + :param children: A list of ValueChecks that need to match the children + of this SBValue. None if children shouldn't be checked. + The order of checks is the order of the checks in the + list. The number of checks has to match the number of + children. + """ + self.expect_name = name + self.expect_value = value + self.expect_type = type + self.expect_summary = summary + self.children = children + + def check_value(self, test_base, val, error_msg=None): + """ + Checks that the given value matches the currently set properties + of this ValueCheck. If a match failed, the given TestBase will + be used to emit an error. A custom error message can be specified + that will be used to describe failed check for this SBValue (but + not errors in the child values). + """ + + this_error_msg = error_msg if error_msg else "" + this_error_msg += "\nChecking SBValue: " + str(val) + + test_base.assertSuccess(val.GetError()) + + if self.expect_name: + test_base.assertEqual(self.expect_name, val.GetName(), + this_error_msg) + if self.expect_value: + test_base.assertEqual(self.expect_value, val.GetValue(), + this_error_msg) + if self.expect_type: + test_base.assertEqual(self.expect_type, val.GetDisplayTypeName(), + this_error_msg) + if self.expect_summary: + test_base.assertEqual(self.expect_summary, val.GetSummary(), + this_error_msg) + if self.children is not None: + self.check_value_children(test_base, val, error_msg) + + def check_value_children(self, test_base, val, error_msg=None): + """ + Checks that the children of a SBValue match a certain structure and + have certain properties. + + :param test_base: The current test's TestBase object. + :param val: The SBValue to check. + """ + + this_error_msg = error_msg if error_msg else "" + this_error_msg += "\nChecking SBValue: " + str(val) + + test_base.assertEqual(len(self.children), val.GetNumChildren(), this_error_msg) + + for i in range(0, val.GetNumChildren()): + expected_child = self.children[i] + actual_child = val.GetChildAtIndex(i) + expected_child.check_value(test_base, actual_child, error_msg) class recording(SixStringIO): """ @@ -310,7 +384,8 @@ class _LocalProcess(_BaseProcess): [executable] + args, stdout=open( os.devnull) if not self._trace_on else None, - stdin=PIPE) + stdin=PIPE, + preexec_fn=lldbplatformutil.enable_attach) def terminate(self): if self._proc.poll() is None: @@ -426,7 +501,7 @@ def system(commands, **kwargs): process = Popen( shellCommand, stdout=PIPE, - stderr=PIPE, + stderr=STDOUT, shell=True, **kwargs) pid = process.pid @@ -440,14 +515,12 @@ def system(commands, **kwargs): cpe = CalledProcessError(retcode, cmd) # Ensure caller can access the stdout/stderr. cpe.lldb_extensions = { - "stdout_content": this_output, - "stderr_content": this_error, + "combined_output": this_output, "command": shellCommand } raise cpe - output = output + this_output.decode("utf-8") - error = error + this_error.decode("utf-8") - return (output, error) + output = output + this_output.decode("utf-8", errors='ignore') + return output def getsource_if_available(obj): @@ -463,17 +536,7 @@ def getsource_if_available(obj): def builder_module(): - if sys.platform.startswith("freebsd"): - return __import__("builder_freebsd") - if sys.platform.startswith("openbsd"): - return __import__("builder_openbsd") - if sys.platform.startswith("netbsd"): - return __import__("builder_netbsd") - if sys.platform.startswith("linux"): - # sys.platform with Python-3.x returns 'linux', but with - # Python-2.x it returns 'linux2'. - return __import__("builder_linux") - return __import__("builder_" + sys.platform) + return get_builder(sys.platform) class Base(unittest2.TestCase): @@ -498,8 +561,12 @@ class Base(unittest2.TestCase): mydir = TestBase.compute_mydir(__file__) ''' # /abs/path/to/packages/group/subdir/mytest.py -> group/subdir - rel_prefix = test_file[len(os.environ["LLDB_TEST_SRC"]) + 1:] - return os.path.dirname(rel_prefix) + lldb_test_src = configuration.test_src_root + if not test_file.startswith(lldb_test_src): + raise Exception( + "Test file '%s' must reside within lldb_test_src " + "(which is '%s')." % (test_file, lldb_test_src)) + return os.path.dirname(os.path.relpath(test_file, start=lldb_test_src)) def TraceOn(self): """Returns True if we are in trace mode (tracing detailed test execution).""" @@ -522,15 +589,11 @@ class Base(unittest2.TestCase): # Save old working directory. cls.oldcwd = os.getcwd() - # Change current working directory if ${LLDB_TEST_SRC} is defined. - # See also dotest.py which sets up ${LLDB_TEST_SRC}. - if ("LLDB_TEST_SRC" in os.environ): - full_dir = os.path.join(os.environ["LLDB_TEST_SRC"], - cls.mydir) - if traceAlways: - print("Change dir to:", full_dir, file=sys.stderr) - os.chdir(full_dir) - lldb.SBReproducer.SetWorkingDirectory(full_dir) + full_dir = os.path.join(configuration.test_src_root, cls.mydir) + if traceAlways: + print("Change dir to:", full_dir, file=sys.stderr) + os.chdir(full_dir) + lldb.SBReproducer.SetWorkingDirectory(full_dir) # Set platform context. cls.platformContext = lldbplatformutil.createPlatformContext() @@ -664,7 +727,7 @@ class Base(unittest2.TestCase): def getSourceDir(self): """Return the full path to the current test.""" - return os.path.join(os.environ["LLDB_TEST_SRC"], self.mydir) + return os.path.join(configuration.test_src_root, self.mydir) def getBuildDirBasename(self): return self.__class__.__module__ + "." + self.testMethodName @@ -719,6 +782,12 @@ class Base(unittest2.TestCase): # differ in the debug info, which is not being hashed. "settings set symbols.enable-external-lookup false", + # Inherit the TCC permissions from the inferior's parent. + "settings set target.inherit-tcc true", + + # Kill rather than detach from the inferior if something goes wrong. + "settings set target.detach-on-error false", + # Disable fix-its by default so that incorrect expressions in tests don't # pass just because Clang thinks it has a fix-it. "settings set target.auto-apply-fixits false", @@ -800,12 +869,14 @@ class Base(unittest2.TestCase): # List of spawned subproces.Popen objects self.subprocesses = [] - # List of forked process PIDs - self.forkedProcessPids = [] - # List of log files produced by the current test. self.log_files = [] + # Create the build directory. + # The logs are stored in the build directory, so we have to create it + # before creating the first log file. + self.makeBuildDir() + session_file = self.getLogBasenameForCurrentTest()+".log" self.log_files.append(session_file) @@ -856,29 +927,17 @@ class Base(unittest2.TestCase): self.setPlatformWorkingDir() self.enableLogChannelsForCurrentTest() - lib_dir = os.environ["LLDB_LIB_DIR"] - self.dsym = None + self.lib_lldb = None self.framework_dir = None - self.darwinWithFramework = self.platformIsDarwin() - if sys.platform.startswith("darwin"): - # Handle the framework environment variable if it is set - if hasattr(lldbtest_config, 'lldb_framework_path'): - framework_path = lldbtest_config.lldb_framework_path - # Framework dir should be the directory containing the framework - self.framework_dir = framework_path[:framework_path.rfind('LLDB.framework')] - # If a framework dir was not specified assume the Xcode build - # directory layout where the framework is in LLDB_LIB_DIR. - else: - self.framework_dir = lib_dir - self.dsym = os.path.join(self.framework_dir, 'LLDB.framework', 'LLDB') - # If the framework binary doesn't exist, assume we didn't actually - # build a framework, and fallback to standard *nix behavior by - # setting framework_dir and dsym to None. - if not os.path.exists(self.dsym): - self.framework_dir = None - self.dsym = None - self.darwinWithFramework = False - self.makeBuildDir() + self.darwinWithFramework = False + + if sys.platform.startswith("darwin") and configuration.lldb_framework_path: + framework = configuration.lldb_framework_path + lib = os.path.join(framework, 'LLDB') + if os.path.exists(lib): + self.framework_dir = os.path.dirname(framework) + self.lib_lldb = lib + self.darwinWithFramework = self.platformIsDarwin() def setAsync(self, value): """ Sets async mode to True/False and ensures it is reset after the testcase completes.""" @@ -887,18 +946,11 @@ class Base(unittest2.TestCase): self.addTearDownHook(lambda: self.dbg.SetAsync(old_async)) def cleanupSubprocesses(self): - # Ensure any subprocesses are cleaned up - for p in self.subprocesses: + # Terminate subprocesses in reverse order from how they were created. + for p in reversed(self.subprocesses): p.terminate() del p del self.subprocesses[:] - # Ensure any forked processes are cleaned up - for pid in self.forkedProcessPids: - try: - os.kill(pid, signal.SIGTERM) - except OSError: - pass - del self.forkedProcessPids[:] def spawnSubprocess(self, executable, args=[], install_remote=True): """ Creates a subprocess.Popen object with the specified executable and arguments, @@ -910,23 +962,6 @@ class Base(unittest2.TestCase): self.subprocesses.append(proc) return proc - def forkSubprocess(self, executable, args=[]): - """ Fork a subprocess with its own group ID. - """ - child_pid = os.fork() - if child_pid == 0: - # If more I/O support is required, this can be beefed up. - fd = os.open(os.devnull, os.O_RDWR) - os.dup2(fd, 1) - os.dup2(fd, 2) - # This call causes the child to have its of group ID - os.setpgid(0, 0) - os.execvp(executable, [executable] + args) - # Give the child time to get through the execvp() call - time.sleep(0.1) - self.forkedProcessPids.append(child_pid) - return child_pid - def HideStdout(self): """Hide output to stdout from the user. @@ -1049,6 +1084,17 @@ class Base(unittest2.TestCase): lldb.SBDebugger.Destroy(self.dbg) del self.dbg + # All modules should be orphaned now so that they can be cleared from + # the shared module cache. + lldb.SBModule.GarbageCollectAllocatedModules() + + # Modules are not orphaned during reproducer replay because they're + # leaked on purpose. + if not configuration.is_reproducer(): + # Assert that the global module cache is empty. + self.assertEqual(lldb.SBModule.GetNumberAllocatedModules(), 0) + + # ========================================================= # Various callbacks to allow introspection of test progress # ========================================================= @@ -1117,45 +1163,12 @@ class Base(unittest2.TestCase): def getRerunArgs(self): return " -f %s.%s" % (self.__class__.__name__, self._testMethodName) - def getLogBasenameForCurrentTest(self, prefix=None): + def getLogBasenameForCurrentTest(self, prefix="Incomplete"): """ returns a partial path that can be used as the beginning of the name of multiple log files pertaining to this test - - /--.. """ - dname = os.path.join(os.environ["LLDB_TEST_SRC"], - os.environ["LLDB_SESSION_DIRNAME"]) - if not os.path.isdir(dname): - os.mkdir(dname) - - components = [] - if prefix is not None: - components.append(prefix) - for c in configuration.session_file_format: - if c == 'f': - components.append(self.__class__.__module__) - elif c == 'n': - components.append(self.__class__.__name__) - elif c == 'c': - compiler = self.getCompiler() - - if compiler[1] == ':': - compiler = compiler[2:] - if os.path.altsep is not None: - compiler = compiler.replace(os.path.altsep, os.path.sep) - path_components = [x for x in compiler.split(os.path.sep) if x != ""] - - # Add at most 4 path components to avoid generating very long - # filenames - components.extend(path_components[-4:]) - elif c == 'a': - components.append(self.getArchitecture()) - elif c == 'm': - components.append(self.testMethodName) - fname = "-".join(components) - - return os.path.join(dname, fname) + return os.path.join(self.getBuildDir(), prefix) def dumpSessionInfo(self): """ @@ -1215,7 +1228,7 @@ class Base(unittest2.TestCase): # process the log files if prefix != 'Success' or lldbtest_config.log_success: # keep all log files, rename them to include prefix - src_log_basename = self.getLogBasenameForCurrentTest(None) + src_log_basename = self.getLogBasenameForCurrentTest() dst_log_basename = self.getLogBasenameForCurrentTest(prefix) for src in self.log_files: if os.path.isfile(src): @@ -1256,6 +1269,41 @@ class Base(unittest2.TestCase): return True return False + def getCPUInfo(self): + triple = self.dbg.GetSelectedPlatform().GetTriple() + + # TODO other platforms, please implement this function + if not re.match(".*-.*-linux", triple): + return "" + + # Need to do something different for non-Linux/Android targets + cpuinfo_path = self.getBuildArtifact("cpuinfo") + if configuration.lldb_platform_name: + self.runCmd('platform get-file "/proc/cpuinfo" ' + cpuinfo_path) + else: + cpuinfo_path = "/proc/cpuinfo" + + try: + with open(cpuinfo_path, 'r') as f: + cpuinfo = f.read() + except: + return "" + + return cpuinfo + + def isAArch64(self): + """Returns true if the architecture is AArch64.""" + return self.getArchitecture().lower() == "aarch64" + + def isAArch64SVE(self): + return self.isAArch64() and "sve" in self.getCPUInfo() + + def isAArch64MTE(self): + return self.isAArch64() and "mte" in self.getCPUInfo() + + def isAArch64PAuth(self): + return self.isAArch64() and "paca" in self.getCPUInfo() + def getArchitecture(self): """Returns the architecture in effect the test suite is running with.""" module = builder_module() @@ -1304,15 +1352,13 @@ class Base(unittest2.TestCase): """ Returns a string that represents the compiler version. Supports: llvm, clang. """ - version = 'unknown' - compiler = self.getCompilerBinary() - version_output = system([[compiler, "-v"]])[1] + version_output = system([[compiler, "--version"]]) for line in version_output.split(os.linesep): - m = re.search('version ([0-9\.]+)', line) + m = re.search('version ([0-9.]+)', line) if m: - version = m.group(1) - return version + return m.group(1) + return 'unknown' def getDwarfVersion(self): """ Returns the dwarf version generated by clang or '0'. """ @@ -1351,25 +1397,35 @@ class Base(unittest2.TestCase): Use compiler_version[0] to specify the operator used to determine if a match has occurred. Any operator other than the following defaults to an equality test: '>', '>=', "=>", '<', '<=', '=<', '!=', "!" or 'not' + + If the current compiler version cannot be determined, we assume it is close to the top + of trunk, so any less-than or equal-to comparisons will return False, and any + greater-than or not-equal-to comparisons will return True. """ - if (compiler_version is None): + if compiler_version is None: return True operator = str(compiler_version[0]) version = compiler_version[1] - if (version is None): + if version is None: return True - if (operator == '>'): - return LooseVersion(self.getCompilerVersion()) > LooseVersion(version) - if (operator == '>=' or operator == '=>'): - return LooseVersion(self.getCompilerVersion()) >= LooseVersion(version) - if (operator == '<'): - return LooseVersion(self.getCompilerVersion()) < LooseVersion(version) - if (operator == '<=' or operator == '=<'): - return LooseVersion(self.getCompilerVersion()) <= LooseVersion(version) - if (operator == '!=' or operator == '!' or operator == 'not'): - return str(version) not in str(self.getCompilerVersion()) - return str(version) in str(self.getCompilerVersion()) + + test_compiler_version = self.getCompilerVersion() + if test_compiler_version == 'unknown': + # Assume the compiler version is at or near the top of trunk. + return operator in ['>', '>=', '!', '!=', 'not'] + + if operator == '>': + return LooseVersion(test_compiler_version) > LooseVersion(version) + if operator == '>=' or operator == '=>': + return LooseVersion(test_compiler_version) >= LooseVersion(version) + if operator == '<': + return LooseVersion(test_compiler_version) < LooseVersion(version) + if operator == '<=' or operator == '=<': + return LooseVersion(test_compiler_version) <= LooseVersion(version) + if operator == '!=' or operator == '!' or operator == 'not': + return str(version) not in str(test_compiler_version) + return str(version) in str(test_compiler_version) def expectedCompiler(self, compilers): """Returns True iff any element of compilers is a sub-string of the current compiler.""" @@ -1442,7 +1498,7 @@ class Base(unittest2.TestCase): 'EXE': exe_name, 'CFLAGS_EXTRAS': "%s %s" % (stdflag, stdlibflag), 'FRAMEWORK_INCLUDES': "-F%s" % self.framework_dir, - 'LD_EXTRAS': "%s -Wl,-rpath,%s" % (self.dsym, self.framework_dir), + 'LD_EXTRAS': "%s -Wl,-rpath,%s" % (self.lib_lldb, self.framework_dir), } elif sys.platform.startswith('win'): d = { @@ -1453,7 +1509,7 @@ class Base(unittest2.TestCase): os.path.join( os.environ["LLDB_SRC"], "include")), - 'LD_EXTRAS': "-L%s -lliblldb" % os.environ["LLDB_IMPLIB_DIR"]} + 'LD_EXTRAS': "-L%s -lliblldb" % lib_dir} else: d = { 'CXX_SOURCES': sources, @@ -1482,7 +1538,7 @@ class Base(unittest2.TestCase): 'DYLIB_NAME': lib_name, 'CFLAGS_EXTRAS': "%s -stdlib=libc++" % stdflag, 'FRAMEWORK_INCLUDES': "-F%s" % self.framework_dir, - 'LD_EXTRAS': "%s -Wl,-rpath,%s -dynamiclib" % (self.dsym, self.framework_dir), + 'LD_EXTRAS': "%s -Wl,-rpath,%s -dynamiclib" % (self.lib_lldb, self.framework_dir), } elif self.getPlatform() == 'windows': d = { @@ -1492,7 +1548,7 @@ class Base(unittest2.TestCase): os.path.join( os.environ["LLDB_SRC"], "include")), - 'LD_EXTRAS': "-shared -l%s\liblldb.lib" % self.os.environ["LLDB_IMPLIB_DIR"]} + 'LD_EXTRAS': "-shared -l%s\liblldb.lib" % lib_dir} else: d = { 'DYLIB_CXX_SOURCES': sources, @@ -1523,6 +1579,10 @@ class Base(unittest2.TestCase): """Platform specific way to build the default binaries.""" testdir = self.mydir testname = self.getBuildDirBasename() + + if not architecture and configuration.arch: + architecture = configuration.arch + if self.getDebugInfo(): raise Exception("buildDefault tests must set NO_DEBUG_INFO_TESTCASE") module = builder_module() @@ -1637,7 +1697,7 @@ class Base(unittest2.TestCase): """ yaml2obj_bin = configuration.get_yaml2obj_path() if not yaml2obj_bin: - self.assertTrue(False, "No valid FileCheck executable specified") + self.assertTrue(False, "No valid yaml2obj executable specified") command = [yaml2obj_bin, "-o=%s" % obj_path, yaml_path] system([command]) @@ -1694,6 +1754,19 @@ class Base(unittest2.TestCase): "Don't know how to do cleanup with dictionary: " + dictionary) + def invoke(self, obj, name, trace=False): + """Use reflection to call a method dynamically with no argument.""" + trace = (True if traceAlways else trace) + + method = getattr(obj, name) + import inspect + self.assertTrue(inspect.ismethod(method), + name + "is a method name of object: " + str(obj)) + result = method() + with recording(self, trace) as sbuf: + print(str(method) + ":", result, file=sbuf) + return result + def getLLDBLibraryEnvVal(self): """ Returns the path that the OS-specific library search environment variable (self.dylibPath) should be set to in order for a program to find the LLDB @@ -1702,13 +1775,11 @@ class Base(unittest2.TestCase): """ existing_library_path = os.environ[ self.dylibPath] if self.dylibPath in os.environ else None - lib_dir = os.environ["LLDB_LIB_DIR"] if existing_library_path: - return "%s:%s" % (existing_library_path, lib_dir) - elif sys.platform.startswith("darwin"): - return os.path.join(lib_dir, 'LLDB.framework') - else: - return lib_dir + return "%s:%s" % (existing_library_path, configuration.lldb_libs_dir) + if sys.platform.startswith("darwin") and configuration.lldb_framework_path: + return configuration.lldb_framework_path + return configuration.lldb_libs_dir def getLibcPlusPlusLibs(self): if self.getPlatform() in ('freebsd', 'linux', 'netbsd', 'openbsd'): @@ -1716,6 +1787,12 @@ class Base(unittest2.TestCase): else: return ['libc++.1.dylib', 'libc++abi.'] + def run_platform_command(self, cmd): + platform = self.dbg.GetSelectedPlatform() + shell_command = lldb.SBPlatformShellCommand(cmd) + err = platform.Run(shell_command) + return (err, shell_command.GetStatus(), shell_command.GetOutput()) + # Metaclass for TestBase to change the list of test metods when a new TestCase is loaded. # We change the test methods to create a new test method for each test for each debug info we are # testing. The name of the new test method will be '_' and with adding @@ -1825,7 +1902,7 @@ class TestBase(Base): - The build methods buildDefault, buildDsym, and buildDwarf are used to build the binaries used during a particular test scenario. A plugin should be provided for the sys.platform running the test suite. The - Mac OS X implementation is located in plugins/darwin.py. + Mac OS X implementation is located in builders/darwin.py. """ # Subclasses can set this to true (if they don't depend on debug info) to avoid running the @@ -1861,6 +1938,7 @@ class TestBase(Base): header.startswith("SB") and header.endswith(".h"))] includes = '\n'.join(list) new_content = content.replace('%include_SB_APIs%', includes) + new_content = new_content.replace('%SOURCE_DIR%', self.getSourceDir()) src = os.path.join(self.getBuildDir(), source) with open(src, 'w') as f: f.write(new_content) @@ -1908,8 +1986,7 @@ class TestBase(Base): shlib_prefix = self.platformContext.shlib_prefix shlib_extension = '.' + self.platformContext.shlib_extension - working_dir = self.get_process_working_directory() - environment = ['%s=%s' % (shlib_environment_var, working_dir)] + dirs = [] # Add any shared libraries to our target if remote so they get # uploaded into the working directory on the remote side for name in shlibs: @@ -1932,6 +2009,7 @@ class TestBase(Base): # Make sure we found the local shared library in the above code self.assertTrue(os.path.exists(local_shlib_path)) + # Add the shared library to our target shlib_module = target.AddModule(local_shlib_path, None, None, None) if lldb.remote_platform: @@ -1941,8 +2019,15 @@ class TestBase(Base): os.path.basename(local_shlib_path)) shlib_module.SetRemoteInstallFileSpec( lldb.SBFileSpec(remote_shlib_path, False)) + dir_to_add = self.get_process_working_directory() + else: + dir_to_add = os.path.dirname(local_shlib_path) - return environment + if dir_to_add not in dirs: + dirs.append(dir_to_add) + + env_value = self.platformContext.shlib_path_separator.join(dirs) + return ['%s=%s' % (shlib_environment_var, env_value)] def registerSanitizerLibrariesWithTarget(self, target): runtimes = [] @@ -2006,13 +2091,9 @@ class TestBase(Base): for target in targets: self.dbg.DeleteTarget(target) - # Modules are not orphaned during reproducer replay because they're - # leaked on purpose. if not configuration.is_reproducer(): # Assert that all targets are deleted. - assert self.dbg.GetNumTargets() == 0 - # Assert that the global module cache is empty. - assert lldb.SBModule.GetNumberAllocatedModules() == 0 + self.assertEqual(self.dbg.GetNumTargets(), 0) # Do this last, to make sure it's in reverse order from how we setup. Base.tearDown(self) @@ -2039,7 +2120,7 @@ class TestBase(Base): return status. """ # Fail fast if 'cmd' is not meaningful. - if not cmd or len(cmd) == 0: + if cmd is None: raise Exception("Bad 'cmd' parameter encountered") trace = (True if traceAlways else trace) @@ -2248,6 +2329,17 @@ class TestBase(Base): self.assertItemsEqual(completions, list(match_strings)[1:], "List of returned completion is wrong") + def completions_contain(self, command, completions): + """Checks that the completions for the given command contain the given + list of completions.""" + interp = self.dbg.GetCommandInterpreter() + match_strings = lldb.SBStringList() + interp.HandleCompletion(command, len(command), 0, -1, match_strings) + for completion in completions: + # match_strings is a 1-indexed list, so we have to slice... + self.assertIn(completion, list(match_strings)[1:], + "Couldn't find expected completion") + def filecheck( self, command, @@ -2344,6 +2436,22 @@ FileCheck output: set to False, the 'str' is treated as a string to be matched/not-matched against the golden input. """ + # Catch cases where `expect` has been miscalled. Specifically, prevent + # this easy to make mistake: + # self.expect("lldb command", "some substr") + # The `msg` parameter is used only when a failed match occurs. A failed + # match can only occur when one of `patterns`, `startstr`, `endstr`, or + # `substrs` has been given. Thus, if a `msg` is given, it's an error to + # not also provide one of the matcher parameters. + if msg and not (patterns or startstr or endstr or substrs or error): + assert False, "expect() missing a matcher argument" + + # Check `patterns` and `substrs` are not accidentally given as strings. + assert not isinstance(patterns, six.string_types), \ + "patterns must be a collection of strings" + assert not isinstance(substrs, six.string_types), \ + "substrs must be a collection of strings" + trace = (True if traceAlways else trace) if exe: @@ -2374,58 +2482,76 @@ FileCheck output: with recording(self, trace) as sbuf: print("looking at:", output, file=sbuf) - # The heading says either "Expecting" or "Not expecting". - heading = "Expecting" if matching else "Not expecting" + expecting_str = "Expecting" if matching else "Not expecting" + def found_str(matched): + return "was found" if matched else "was not found" + + # To be used as assert fail message and/or trace content + log_lines = [ + "{}:".format("Ran command" if exe else "Checking string"), + "\"{}\"".format(str), + # Space out command and output + "", + ] + if exe: + # Newline before output to make large strings more readable + log_lines.append("Got output:\n{}".format(output)) - # Start from the startstr, if specified. - # If there's no startstr, set the initial state appropriately. - matched = output.startswith(startstr) if startstr else ( - True if matching else False) + # Assume that we start matched if we want a match + # Meaning if you have no conditions, matching or + # not matching will always pass + matched = matching + # We will stop checking on first failure if startstr: - with recording(self, trace) as sbuf: - print("%s start string: %s" % (heading, startstr), file=sbuf) - print("Matched" if matched else "Not matched", file=sbuf) + matched = output.startswith(startstr) + log_lines.append("{} start string: \"{}\" ({})".format( + expecting_str, startstr, found_str(matched))) - # Look for endstr, if specified. - keepgoing = matched if matching else not matched - if endstr: + if endstr and matched == matching: matched = output.endswith(endstr) - with recording(self, trace) as sbuf: - print("%s end string: %s" % (heading, endstr), file=sbuf) - print("Matched" if matched else "Not matched", file=sbuf) + log_lines.append("{} end string: \"{}\" ({})".format( + expecting_str, endstr, found_str(matched))) - # Look for sub strings, if specified. - keepgoing = matched if matching else not matched - if substrs and keepgoing: + if substrs and matched == matching: start = 0 for substr in substrs: index = output[start:].find(substr) start = start + index if ordered and matching else 0 matched = index != -1 - with recording(self, trace) as sbuf: - print("%s sub string: %s" % (heading, substr), file=sbuf) - print("Matched" if matched else "Not matched", file=sbuf) - keepgoing = matched if matching else not matched - if not keepgoing: + log_lines.append("{} sub string: \"{}\" ({})".format( + expecting_str, substr, found_str(matched))) + + if matched != matching: break - # Search for regular expression patterns, if specified. - keepgoing = matched if matching else not matched - if patterns and keepgoing: + if patterns and matched == matching: for pattern in patterns: - # Match Objects always have a boolean value of True. - matched = bool(re.search(pattern, output)) - with recording(self, trace) as sbuf: - print("%s pattern: %s" % (heading, pattern), file=sbuf) - print("Matched" if matched else "Not matched", file=sbuf) - keepgoing = matched if matching else not matched - if not keepgoing: + matched = re.search(pattern, output) + + pattern_line = "{} regex pattern: \"{}\" ({}".format( + expecting_str, pattern, found_str(matched)) + if matched: + pattern_line += ", matched \"{}\"".format( + matched.group(0)) + pattern_line += ")" + log_lines.append(pattern_line) + + # Convert to bool because match objects + # are True-ish but != True itself + matched = bool(matched) + if matched != matching: break - self.assertTrue(matched if matching else not matched, - msg + "\nCommand output:\n" + EXP_MSG(str, output, exe) - if msg else EXP_MSG(str, output, exe)) + # If a check failed, add any extra assert message + if msg is not None and matched != matching: + log_lines.append(msg) + + log_msg = "\n".join(log_lines) + with recording(self, trace) as sbuf: + print(log_msg, file=sbuf) + if matched != matching: + self.fail(log_msg) def expect_expr( self, @@ -2433,6 +2559,7 @@ FileCheck output: result_summary=None, result_value=None, result_type=None, + result_children=None ): """ Evaluates the given expression and verifies the result. @@ -2440,6 +2567,8 @@ FileCheck output: :param result_summary: The summary that the expression should have. None if the summary should not be checked. :param result_value: The value that the expression should have. None if the value should not be checked. :param result_type: The type that the expression result should have. None if the type should not be checked. + :param result_children: The expected children of the expression result + as a list of ValueChecks. None if the children shouldn't be checked. """ self.assertTrue(expr.strip() == expr, "Expression contains trailing/leading whitespace: '" + expr + "'") @@ -2456,31 +2585,46 @@ FileCheck output: options.SetLanguage(frame.GuessLanguage()) eval_result = self.frame().EvaluateExpression(expr, options) else: - eval_result = self.target().EvaluateExpression(expr, options) - - self.assertSuccess(eval_result.GetError()) - - if result_type: - self.assertEqual(result_type, eval_result.GetDisplayTypeName()) - - if result_value: - self.assertEqual(result_value, eval_result.GetValue()) - - if result_summary: - self.assertEqual(result_summary, eval_result.GetSummary()) + target = self.target() + # If there is no selected target, run the expression in the dummy + # target. + if not target.IsValid(): + target = self.dbg.GetDummyTarget() + eval_result = target.EvaluateExpression(expr, options) + + value_check = ValueCheck(type=result_type, value=result_value, + summary=result_summary, children=result_children) + value_check.check_value(self, eval_result, str(eval_result)) + return eval_result + + def expect_var_path( + self, + var_path, + summary=None, + value=None, + type=None, + children=None + ): + """ + Evaluates the given variable path and verifies the result. + See also 'frame variable' and SBFrame.GetValueForVariablePath. + :param var_path: The variable path as a string. + :param summary: The summary that the variable should have. None if the summary should not be checked. + :param value: The value that the variable should have. None if the value should not be checked. + :param type: The type that the variable result should have. None if the type should not be checked. + :param children: The expected children of the variable as a list of ValueChecks. + None if the children shouldn't be checked. + """ + self.assertTrue(var_path.strip() == var_path, + "Expression contains trailing/leading whitespace: '" + var_path + "'") - def invoke(self, obj, name, trace=False): - """Use reflection to call a method dynamically with no argument.""" - trace = (True if traceAlways else trace) + frame = self.frame() + eval_result = frame.GetValueForVariablePath(var_path) - method = getattr(obj, name) - import inspect - self.assertTrue(inspect.ismethod(method), - name + "is a method name of object: " + str(obj)) - result = method() - with recording(self, trace) as sbuf: - print(str(method) + ":", result, file=sbuf) - return result + value_check = ValueCheck(type=type, value=value, + summary=summary, children=children) + value_check.check_value(self, eval_result, str(eval_result)) + return eval_result def build( self, @@ -2490,6 +2634,9 @@ FileCheck output: """Platform specific way to build the default binaries.""" module = builder_module() + if not architecture and configuration.arch: + architecture = configuration.arch + dictionary = lldbplatformutil.finalize_build_dictionary(dictionary) if self.getDebugInfo() is None: return self.buildDefault(architecture, compiler, dictionary) @@ -2504,12 +2651,6 @@ FileCheck output: else: self.fail("Can't build for debug info: %s" % self.getDebugInfo()) - def run_platform_command(self, cmd): - platform = self.dbg.GetSelectedPlatform() - shell_command = lldb.SBPlatformShellCommand(cmd) - err = platform.Run(shell_command) - return (err, shell_command.GetStatus(), shell_command.GetOutput()) - """Assert that an lldb.SBError is in the "success" state.""" def assertSuccess(self, obj, msg=None): if not obj.Success(): @@ -2517,6 +2658,31 @@ FileCheck output: self.fail(self._formatMessage(msg, "'{}' is not success".format(error))) + def createTestTarget(self, file_path=None, msg=None): + """ + Creates a target from the file found at the given file path. + Asserts that the resulting target is valid. + :param file_path: The file path that should be used to create the target. + The default argument opens the current default test + executable in the current test directory. + :param msg: A custom error message. + """ + if file_path is None: + file_path = self.getBuildArtifact("a.out") + error = lldb.SBError() + triple = "" + platform = "" + load_dependent_modules = True + target = self.dbg.CreateTarget(file_path, triple, platform, + load_dependent_modules, error) + if error.Fail(): + err = "Couldn't create target for path '{}': {}".format(file_path, + str(error)) + self.fail(self._formatMessage(msg, err)) + + self.assertTrue(target.IsValid(), "Got invalid target without error") + return target + # ================================================= # Misc. helper methods for debugging test execution # ================================================= diff --git a/gnu/llvm/lldb/packages/Python/lldbsuite/test/lldbutil.py b/gnu/llvm/lldb/packages/Python/lldbsuite/test/lldbutil.py index 25fcd5f29ee..20a6d28274b 100644 --- a/gnu/llvm/lldb/packages/Python/lldbsuite/test/lldbutil.py +++ b/gnu/llvm/lldb/packages/Python/lldbsuite/test/lldbutil.py @@ -12,6 +12,7 @@ import errno import os import re import sys +import subprocess # Third-party modules from six import StringIO as SixStringIO @@ -20,7 +21,10 @@ import six # LLDB modules import lldb from . import lldbtest_config +from . import configuration +# How often failed simulator process launches are retried. +SIMULATOR_RETRY = 3 # =================================================== # Utilities for locating/checking executable programs @@ -52,6 +56,50 @@ def mkdir_p(path): raise if not os.path.isdir(path): raise OSError(errno.ENOTDIR, "%s is not a directory"%path) + + +# ============================ +# Dealing with SDK and triples +# ============================ + +def get_xcode_sdk(os, env): + # Respect --apple-sdk if it's specified. If the SDK is simply + # mounted from some disk image, and not actually installed, this is the + # only way to use it. + if configuration.apple_sdk: + return configuration.apple_sdk + if os == "ios": + if env == "simulator": + return "iphonesimulator" + if env == "macabi": + return "macosx" + return "iphoneos" + elif os == "tvos": + if env == "simulator": + return "appletvsimulator" + return "appletvos" + elif os == "watchos": + if env == "simulator": + return "watchsimulator" + return "watchos" + return os + + +def get_xcode_sdk_version(sdk): + return subprocess.check_output( + ['xcrun', '--sdk', sdk, '--show-sdk-version']).rstrip().decode('utf-8') + + +def get_xcode_sdk_root(sdk): + return subprocess.check_output(['xcrun', '--sdk', sdk, '--show-sdk-path' + ]).rstrip().decode('utf-8') + + +def get_xcode_clang(sdk): + return subprocess.check_output(['xcrun', '-sdk', sdk, '-f', 'clang' + ]).rstrip().decode("utf-8") + + # =================================================== # Disassembly for an SBFunction or an SBSymbol object # =================================================== @@ -204,6 +252,12 @@ def stop_reason_to_str(enum): return "watchpoint" elif enum == lldb.eStopReasonExec: return "exec" + elif enum == lldb.eStopReasonFork: + return "fork" + elif enum == lldb.eStopReasonVFork: + return "vfork" + elif enum == lldb.eStopReasonVForkDone: + return "vforkdone" elif enum == lldb.eStopReasonSignal: return "signal" elif enum == lldb.eStopReasonException: @@ -502,6 +556,29 @@ def run_break_set_by_source_regexp( return get_bpno_from_match(break_results) +def run_break_set_by_file_colon_line( + test, + specifier, + path, + line_number, + column_number = 0, + extra_options=None, + num_expected_locations=-1): + command = 'breakpoint set -y "%s"'%(specifier) + if extra_options: + command += " " + extra_options + + print("About to run: '%s'", command) + break_results = run_break_set_command(test, command) + check_breakpoint_result( + test, + break_results, + num_locations = num_expected_locations, + file_name = path, + line_number = line_number, + column_number = column_number) + + return get_bpno_from_match(break_results) def run_break_set_command(test, command): """Run the command passed in - it must be some break set variant - and analyze the result. @@ -515,6 +592,7 @@ def run_break_set_command(test, command): If there is only one location, the dictionary MAY contain: file - source file name line_no - source line number + column - source column number symbol - symbol name inline_symbol - inlined symbol name offset - offset from the original symbol @@ -566,6 +644,7 @@ def check_breakpoint_result( break_results, file_name=None, line_number=-1, + column_number=0, symbol_name=None, symbol_match_exact=True, module_name=None, @@ -605,6 +684,17 @@ def check_breakpoint_result( (line_number, out_line_number)) + if column_number != 0: + out_column_number = 0 + if 'column' in break_results: + out_column_number = break_results['column'] + + test.assertTrue( + column_number == out_column_number, + "Breakpoint column number %s doesn't match resultant column %s." % + (column_number, + out_column_number)) + if symbol_name: out_symbol_name = "" # Look first for the inlined symbol name, otherwise use the symbol @@ -782,9 +872,20 @@ def run_to_breakpoint_do_run(test, target, bkpt, launch_info = None, error = lldb.SBError() process = target.Launch(launch_info, error) + # Unfortunate workaround for the iPhone simulator. + retry = SIMULATOR_RETRY + while (retry and error.Fail() and error.GetCString() and + "Unable to boot the Simulator" in error.GetCString()): + retry -= 1 + print("** Simulator is unresponsive. Retrying %d more time(s)"%retry) + import time + time.sleep(60) + error = lldb.SBError() + process = target.Launch(launch_info, error) + test.assertTrue(process, - "Could not create a valid process for %s: %s"%(target.GetExecutable().GetFilename(), - error.GetCString())) + "Could not create a valid process for %s: %s" % + (target.GetExecutable().GetFilename(), error.GetCString())) test.assertFalse(error.Fail(), "Process launch failed: %s" % (error.GetCString())) @@ -1422,3 +1523,41 @@ def wait_for_file_on_target(testcase, file_path, max_attempts=6): (file_path, max_attempts)) return read_file_on_target(testcase, file_path) + +def packetlog_get_process_info(log): + """parse a gdb-remote packet log file and extract the response to qProcessInfo""" + process_info = dict() + with open(log, "r") as logfile: + process_info_ostype = None + expect_process_info_response = False + for line in logfile: + if expect_process_info_response: + for pair in line.split(';'): + keyval = pair.split(':') + if len(keyval) == 2: + process_info[keyval[0]] = keyval[1] + break + if 'send packet: $qProcessInfo#' in line: + expect_process_info_response = True + return process_info + +def packetlog_get_dylib_info(log): + """parse a gdb-remote packet log file and extract the *last* complete + (=> fetch_all_solibs=true) response to jGetLoadedDynamicLibrariesInfos""" + import json + dylib_info = None + with open(log, "r") as logfile: + dylib_info = None + expect_dylib_info_response = False + for line in logfile: + if expect_dylib_info_response: + while line[0] != '$': + line = line[1:] + line = line[1:] + # Unescape '}'. + dylib_info = json.loads(line.replace('}]','}')[:-4]) + expect_dylib_info_response = False + if 'send packet: $jGetLoadedDynamicLibrariesInfos:{"fetch_all_solibs":true}' in line: + expect_dylib_info_response = True + + return dylib_info diff --git a/gnu/llvm/lldb/packages/Python/lldbsuite/test/make/Makefile.rules b/gnu/llvm/lldb/packages/Python/lldbsuite/test/make/Makefile.rules index 5316c51899c..f4aa6d64671 100644 --- a/gnu/llvm/lldb/packages/Python/lldbsuite/test/make/Makefile.rules +++ b/gnu/llvm/lldb/packages/Python/lldbsuite/test/make/Makefile.rules @@ -26,15 +26,13 @@ # SPLIT_DEBUG_SYMBOLS := YES # CROSS_COMPILE := # USE_PRIVATE_MODULE_CACHE := YES -# -# And test/functionalities/archives/Makefile: -# MAKE_DSYM := NO -# ARCHIVE_NAME := libfoo.a -# ARCHIVE_C_SOURCES := a.c b.c # Uncomment line below for debugging shell commands # SHELL = /bin/sh -x +# Suppress built-in suffix rules. We explicitly define rules for %.o. +.SUFFIXES: + SRCDIR := $(shell dirname $(firstword $(MAKEFILE_LIST))) BUILDDIR := $(shell pwd) MAKEFILE_RULES := $(lastword $(MAKEFILE_LIST)) @@ -56,12 +54,12 @@ LLDB_BASE_DIR := $(THIS_FILE_DIR)/../../../../../ # When running tests from Visual Studio, the environment variable isn't # inherited all the way down to the process spawned for make. #---------------------------------------------------------------------- -HOST_OS = $(shell uname -s) +HOST_OS := $(shell uname -s) ifneq (,$(findstring windows32,$(HOST_OS))) - HOST_OS = Windows_NT + HOST_OS := Windows_NT endif ifeq "$(OS)" "" - OS = $(HOST_OS) + OS := $(HOST_OS) endif #---------------------------------------------------------------------- @@ -82,11 +80,9 @@ endif # we strictly required double-quotes #---------------------------------------------------------------------- ifeq "$(HOST_OS)" "Windows_NT" - JOIN_CMD = & QUOTE = " FIXUP_SYNTAX_HIGHLIGHTING_IN_MY_EDITOR = " else - JOIN_CMD = ; QUOTE = ' FIXUP_SYNTAX_HIGHLIGHTING_IN_MY_EDITOR = ' endif @@ -96,65 +92,6 @@ endif # from the triple alone #---------------------------------------------------------------------- ARCH_CFLAGS := -ifneq "$(TRIPLE)" "" - triple_space = $(subst -, ,$(TRIPLE)) - ARCH =$(word 1, $(triple_space)) - TRIPLE_VENDOR =$(word 2, $(triple_space)) - triple_os_and_version =$(shell echo $(word 3, $(triple_space)) | sed 's/\([a-z]*\)\(.*\)/\1 \2/') - TRIPLE_OS =$(word 1, $(triple_os_and_version)) - TRIPLE_VERSION =$(word 2, $(triple_os_and_version)) - TRIPLE_ENV =$(word 4, $(triple_space)) - ifeq "$(TRIPLE_VENDOR)" "apple" - ifeq "$(TRIPLE_OS)" "ios" - ifeq "$(TRIPLE_ENV)" "simulator" - SDK_NAME := iphonesimulator - else - ifeq "$(TRIPLE_ENV)" "macabi" - SDK_NAME := macosx - else - SDK_NAME := iphoneos - endif - endif - endif - ifeq "$(TRIPLE_OS)" "tvos" - ifeq "$(TRIPLE_ENV)" "simulator" - SDK_NAME := appletvsimulator - else - SDK_NAME := appletvos - endif - endif - ifeq "$(TRIPLE_OS)" "watchos" - ifeq "$(TRIPLE_ENV)" "simulator" - SDK_NAME := watchsimulator - else - SDK_NAME := watchos - endif - endif - ifneq "$(TRIPLE_OS)" "macosx" - ifeq "$(TRIPLE_ENV)" "" - CODESIGN := codesign - endif - endif - - ifeq "$(SDKROOT)" "" - SDKROOT := $(shell xcrun --sdk $(SDK_NAME) --show-sdk-path) - endif - ifeq "$(TRIPLE_VERSION)" "" - ifeq "$(SDK_NAME)" "" - $(error "SDK_NAME is empty") - endif - TRIPLE_VERSION := $(shell xcrun --sdk $(SDK_NAME) --show-sdk-version) - endif - ifeq "$(TRIPLE_ENV)" "simulator" - ARCH_CFLAGS := -m$(TRIPLE_OS)-simulator-version-min=$(TRIPLE_VERSION) - else - ifneq "$(TRIPLE_OS)" "macosx" - ARCH_CFLAGS := -m$(TRIPLE_OS)-version-min=$(TRIPLE_VERSION) - endif - endif - endif - ARCH_CFLAGS += -target $(TRIPLE) -endif ifeq "$(OS)" "Android" include $(THIS_FILE_DIR)/Android.rules endif @@ -174,7 +111,7 @@ endif # CC defaults to clang. # # If you change the defaults of CC, be sure to also change it in the file -# test/plugins/builder_base.py, which provides a Python way to return the +# test/builders/builder_base.py, which provides a Python way to return the # value of the make variable CC -- getCompiler(). # # See also these functions: @@ -342,11 +279,6 @@ CXXFLAGS += -std=c++11 $(CFLAGS) $(ARCH_CXXFLAGS) $(CXXFLAGS_EXTRAS) LD = $(CC) LDFLAGS ?= $(CFLAGS) LDFLAGS += $(LD_EXTRAS) $(ARCH_LDFLAGS) -ifneq (,$(LLVM_LIBS_DIR)) - ifeq ($(OS),NetBSD) - LDFLAGS += -L$(LLVM_LIBS_DIR) -Wl,-rpath,$(LLVM_LIBS_DIR) - endif -endif ifeq (,$(filter $(OS), Windows_NT Android Darwin)) ifneq (,$(filter YES,$(ENABLE_THREADS))) LDFLAGS += -pthread @@ -456,21 +388,18 @@ endif ifeq (1,$(USE_LIBCPP)) CXXFLAGS += -DLLDB_USING_LIBCPP - ifeq "$(OS)" "Linux" - ifneq (,$(findstring clang,$(CC))) - CXXFLAGS += -stdlib=libc++ - LDFLAGS += -stdlib=libc++ - else - CXXFLAGS += -isystem /usr/include/c++/v1 - LDFLAGS += -lc++ - endif - else ifeq "$(OS)" "Android" + ifeq "$(OS)" "Android" # Nothing to do, this is already handled in # Android.rules. else CXXFLAGS += -stdlib=libc++ LDFLAGS += -stdlib=libc++ endif + ifneq (,$(filter $(OS), FreeBSD Linux NetBSD)) + ifneq (,$(LLVM_LIBS_DIR)) + LDFLAGS += -Wl,-rpath,$(LLVM_LIBS_DIR) + endif + endif endif #---------------------------------------------------------------------- @@ -538,56 +467,6 @@ ifneq "$(strip $(OBJCXX_SOURCES))" "" endif endif -#---------------------------------------------------------------------- -# Check if we have any C source files for archive -#---------------------------------------------------------------------- -ifneq "$(strip $(ARCHIVE_C_SOURCES))" "" - ARCHIVE_OBJECTS +=$(strip $(ARCHIVE_C_SOURCES:.c=.o)) -endif - -#---------------------------------------------------------------------- -# Check if we have any C++ source files for archive -#---------------------------------------------------------------------- -ifneq "$(strip $(ARCHIVE_CXX_SOURCES))" "" - ARCHIVE_OBJECTS +=$(strip $(ARCHIVE_CXX_SOURCES:.cpp=.o)) - CXX = $(call cxx_compiler,$(CC)) - LD = $(call cxx_linker,$(CC)) -endif - -#---------------------------------------------------------------------- -# Check if we have any ObjC source files for archive -#---------------------------------------------------------------------- -ifneq "$(strip $(ARCHIVE_OBJC_SOURCES))" "" - ARCHIVE_OBJECTS +=$(strip $(ARCHIVE_OBJC_SOURCES:.m=.o)) - LDFLAGS +=-lobjc -endif - -#---------------------------------------------------------------------- -# Check if we have any ObjC++ source files for archive -#---------------------------------------------------------------------- -ifneq "$(strip $(ARCHIVE_OBJCXX_SOURCES))" "" - ARCHIVE_OBJECTS +=$(strip $(ARCHIVE_OBJCXX_SOURCES:.mm=.o)) - CXX = $(call cxx_compiler,$(CC)) - LD = $(call cxx_linker,$(CC)) - ifeq "$(findstring lobjc,$(LDFLAGS))" "" - LDFLAGS +=-lobjc - endif -endif - -#---------------------------------------------------------------------- -# Check if we are compiling with gcc 4.6 -#---------------------------------------------------------------------- -ifneq "$(strip $(CXX_SOURCES) $(OBJCXX_SOURCES))" "" -ifneq "$(filter g++,$(CXX))" "" - CXXVERSION = $(shell $(CXX) -dumpversion | cut -b 1-3) - ifeq "$(CXXVERSION)" "4.6" - # GCC 4.6 cannot handle -std=c++11, so replace it with -std=c++0x - # instead. FIXME: remove once GCC version is upgraded. - override CXXFLAGS := $(subst -std=c++11,-std=c++0x,$(CXXFLAGS)) - endif -endif -endif - ifeq ($(findstring clang, $(CXX)), clang) CXXFLAGS += --driver-mode=g++ endif @@ -609,8 +488,8 @@ endif #---------------------------------------------------------------------- ifneq "$(DYLIB_NAME)" "" ifeq "$(DYLIB_ONLY)" "" -$(EXE) : $(OBJECTS) $(ARCHIVE_NAME) $(DYLIB_FILENAME) - $(LD) $(OBJECTS) $(ARCHIVE_NAME) -L. -l$(DYLIB_NAME) $(LDFLAGS) -o "$(EXE)" +$(EXE) : $(OBJECTS) $(DYLIB_FILENAME) + $(LD) $(OBJECTS) -L. -l$(DYLIB_NAME) $(LDFLAGS) -o "$(EXE)" ifneq "$(CODESIGN)" "" $(CODESIGN) -s - "$(EXE)" endif @@ -618,8 +497,8 @@ else EXE = $(DYLIB_FILENAME) endif else -$(EXE) : $(OBJECTS) $(ARCHIVE_NAME) - $(LD) $(OBJECTS) $(LDFLAGS) $(ARCHIVE_NAME) -o "$(EXE)" +$(EXE) : $(OBJECTS) + $(LD) $(OBJECTS) $(LDFLAGS) -o "$(EXE)" ifneq "$(CODESIGN)" "" $(CODESIGN) -s - "$(EXE)" endif @@ -641,19 +520,6 @@ ifeq "$(SPLIT_DEBUG_SYMBOLS)" "YES" endif endif -#---------------------------------------------------------------------- -# Make the archive -#---------------------------------------------------------------------- -ifneq "$(ARCHIVE_NAME)" "" -ifeq "$(OS)" "Darwin" -$(ARCHIVE_NAME) : $(ARCHIVE_OBJECTS) - $(AR) $(ARFLAGS) $(ARCHIVE_NAME) $(ARCHIVE_OBJECTS) - $(RM) $(ARCHIVE_OBJECTS) -else -$(ARCHIVE_NAME) : $(foreach ar_obj,$(ARCHIVE_OBJECTS),$(ARCHIVE_NAME)($(ar_obj))) -endif -endif - #---------------------------------------------------------------------- # Make the dylib #---------------------------------------------------------------------- @@ -703,12 +569,22 @@ endif # Make the precompiled header and compile C++ sources against it #---------------------------------------------------------------------- -#ifneq "$(PCH_OUTPUT)" "" +ifneq "$(PCH_OUTPUT)" "" $(PCH_OUTPUT) : $(PCH_CXX_SOURCE) $(CXX) $(CXXFLAGS) -x c++-header -o $@ $< -%.o : %.cpp $(PCH_OUTPUT) - $(CXX) $(PCHFLAGS) $(CXXFLAGS) -c -o $@ $< -#endif +endif + +%.o: %.c %.d + $(CC) $(CFLAGS) -MT $@ -MD -MP -MF $*.d -c -o $@ $< + +%.o: %.cpp %.d $(PCH_OUTPUT) + $(CXX) $(PCHFLAGS) $(CXXFLAGS) -MT $@ -MD -MP -MF $*.d -c -o $@ $< + +%.o: %.m %.d + $(CC) $(CFLAGS) -MT $@ -MD -MP -MF $*.d -c -o $@ $< + +%.o: %.mm %.d + $(CXX) $(CXXFLAGS) -MT $@ -MD -MP -MF $*.d -c -o $@ $< #---------------------------------------------------------------------- # Automatic variables based on items already entered. Below we create @@ -717,54 +593,20 @@ $(PCH_OUTPUT) : $(PCH_CXX_SOURCE) # files by replacing all .c files with .d. #---------------------------------------------------------------------- PREREQS := $(OBJECTS:.o=.d) -DWOS := $(OBJECTS:.o=.dwo) $(ARCHIVE_OBJECTS:.o=.dwo) +DWOS := $(OBJECTS:.o=.dwo) ifneq "$(DYLIB_NAME)" "" DYLIB_PREREQS := $(DYLIB_OBJECTS:.o=.d) DYLIB_DWOS := $(DYLIB_OBJECTS:.o=.dwo) endif -#---------------------------------------------------------------------- -# Rule for Generating Prerequisites Automatically using .d files and -# the compiler -MM option. The -M option will list all system headers, -# and the -MM option will list all non-system dependencies. -#---------------------------------------------------------------------- -%.d: %.c - @rm -f $@ $(JOIN_CMD) \ - $(CC) -M $(CFLAGS) $< > $@.tmp && \ - sed $(QUOTE)s,\($*\)\.o[ :]*,\1.o $@ : ,g$(QUOTE) < $@.tmp > $@ $(JOIN_CMD) \ - rm -f $@.tmp - -%.d: %.cpp - @rm -f $@ $(JOIN_CMD) \ - $(CXX) -M $(CXXFLAGS) $< > $@.tmp && \ - sed $(QUOTE)s,\($*\)\.o[ :]*,\1.o $@ : ,g$(QUOTE) < $@.tmp > $@ $(JOIN_CMD) \ - rm -f $@.tmp - -%.d: %.m - @rm -f $@ $(JOIN_CMD) \ - $(CC) -M $(CFLAGS) $< > $@.tmp && \ - sed $(QUOTE)s,\($*\)\.o[ :]*,\1.o $@ : ,g$(QUOTE) < $@.tmp > $@ $(JOIN_CMD) \ - rm -f $@.tmp - -%.d: %.mm - @rm -f $@ $(JOIN_CMD) \ - $(CXX) -M $(CXXFLAGS) $< > $@.tmp && \ - sed $(QUOTE)s,\($*\)\.o[ :]*,\1.o $@ : ,g$(QUOTE) < $@.tmp > $@ $(JOIN_CMD) \ - rm -f $@.tmp +# Don't error if a .d file is deleted. +$(PREREQS) $(DYLIB_PREREQS): ; #---------------------------------------------------------------------- # Include all of the makefiles for each source file so we don't have # to manually track all of the prerequisites for each source file. #---------------------------------------------------------------------- -sinclude $(PREREQS) -ifneq "$(DYLIB_NAME)" "" - sinclude $(DYLIB_PREREQS) -endif - -# Define a suffix rule for .mm -> .o -.SUFFIXES: .mm .o -.mm.o: - $(CXX) $(CXXFLAGS) -c $< +include $(wildcard $(PREREQS) $(DYLIB_PREREQS)) .PHONY: clean dsym: $(DSYM) diff --git a/gnu/llvm/lldb/packages/Python/lldbsuite/test/make/entitlements-simulator.plist b/gnu/llvm/lldb/packages/Python/lldbsuite/test/make/entitlements-simulator.plist new file mode 100644 index 00000000000..9acd12816c9 --- /dev/null +++ b/gnu/llvm/lldb/packages/Python/lldbsuite/test/make/entitlements-simulator.plist @@ -0,0 +1,8 @@ + + + + + com.apple.security.get-task-allow + + + diff --git a/gnu/llvm/lldb/packages/Python/lldbsuite/test/make/entitlements.plist b/gnu/llvm/lldb/packages/Python/lldbsuite/test/make/entitlements.plist new file mode 100644 index 00000000000..3c009ffaa59 --- /dev/null +++ b/gnu/llvm/lldb/packages/Python/lldbsuite/test/make/entitlements.plist @@ -0,0 +1,10 @@ + + + + + com.apple.security.get-task-allow + + com.apple.private.security.no-sandbox + + + diff --git a/gnu/llvm/lldb/packages/Python/lldbsuite/test/make/thread.h b/gnu/llvm/lldb/packages/Python/lldbsuite/test/make/thread.h new file mode 100644 index 00000000000..3cfa16b8476 --- /dev/null +++ b/gnu/llvm/lldb/packages/Python/lldbsuite/test/make/thread.h @@ -0,0 +1,35 @@ +#ifndef LLDB_THREAD_H +#define LLDB_THREAD_H + +#include + +#if defined(__APPLE__) +__OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_3_2) +int pthread_threadid_np(pthread_t, __uint64_t *); +#elif defined(__linux__) +#include +#include +#elif defined(__NetBSD__) +#include +#elif defined(_WIN32) +#include +#endif + +inline uint64_t get_thread_id() { +#if defined(__APPLE__) + __uint64_t tid = 0; + pthread_threadid_np(pthread_self(), &tid); + return tid; +#elif defined(__linux__) + return syscall(__NR_gettid); +#elif defined(__NetBSD__) + // Technically lwpid_t is 32-bit signed integer + return static_cast(_lwp_self()); +#elif defined(_WIN32) + return static_cast(::GetCurrentThreadId()); +#else + return -1; +#endif +} + +#endif // LLDB_THREAD_H diff --git a/gnu/llvm/lldb/packages/Python/lldbsuite/test/test_categories.py b/gnu/llvm/lldb/packages/Python/lldbsuite/test/test_categories.py index 177c50ee17c..2fbf1a27904 100644 --- a/gnu/llvm/lldb/packages/Python/lldbsuite/test/test_categories.py +++ b/gnu/llvm/lldb/packages/Python/lldbsuite/test/test_categories.py @@ -19,26 +19,29 @@ debug_info_categories = [ ] all_categories = { + 'basic_process': 'Basic process execution sniff tests.', + 'cmdline': 'Tests related to the LLDB command-line interface', 'dataformatters': 'Tests related to the type command and the data formatters subsystem', + 'debugserver': 'Debugserver tests', + 'dsym': 'Tests that can be run with DSYM debug information', 'dwarf': 'Tests that can be run with DWARF debug information', 'dwo': 'Tests that can be run with DWO debug information', - 'dsym': 'Tests that can be run with DSYM debug information', - 'gmodules': 'Tests that can be run with -gmodules debug information', + 'dyntype': 'Tests related to dynamic type support', 'expression': 'Tests related to the expression parser', + 'flakey': 'Flakey test cases, i.e. tests that do not reliably pass at each execution', + 'fork': 'Tests requiring the process plugin fork/vfork event support', + 'gmodules': 'Tests that can be run with -gmodules debug information', + 'instrumentation-runtime': 'Tests for the instrumentation runtime plugins', 'libc++': 'Test for libc++ data formatters', 'libstdcxx': 'Test for libstdcxx data formatters', + 'lldb-server': 'Tests related to lldb-server', + 'lldb-vscode': 'Visual Studio Code debug adaptor tests', + 'llgs': 'Tests for the gdb-server functionality of lldb-server', 'objc': 'Tests related to the Objective-C programming language support', 'pyapi': 'Tests related to the Python API', - 'basic_process': 'Basic process execution sniff tests.', - 'cmdline': 'Tests related to the LLDB command-line interface', - 'dyntype': 'Tests related to dynamic type support', - 'stresstest': 'Tests related to stressing lldb limits', - 'flakey': 'Flakey test cases, i.e. tests that do not reliably pass at each execution', - 'darwin-log': 'Darwin log tests', 'std-module': 'Tests related to importing the std module', + 'stresstest': 'Tests related to stressing lldb limits', 'watchpoint': 'Watchpoint-related tests', - 'lldb-vscode': 'Visual Studio Code debug adaptor tests', - 'lldb-server': 'Tests related to lldb-server', } diff --git a/gnu/llvm/lldb/packages/Python/lldbsuite/test/test_result.py b/gnu/llvm/lldb/packages/Python/lldbsuite/test/test_result.py index 7e13e09d9bf..ff01b21a561 100644 --- a/gnu/llvm/lldb/packages/Python/lldbsuite/test/test_result.py +++ b/gnu/llvm/lldb/packages/Python/lldbsuite/test/test_result.py @@ -9,13 +9,13 @@ and results of a single test run. # System modules import os +import traceback # Third-party modules import unittest2 # LLDB Modules from . import configuration -from lldbsuite.test_event.event_builder import EventBuilder from lldbsuite.test_event import build_exception @@ -72,7 +72,6 @@ class LLDBTestResult(unittest2.TextTestResult): # This counts from 1 .. suite.countTestCases(). self.counter = 0 (width, height) = LLDBTestResult.getTerminalSize() - self.results_formatter = configuration.results_formatter_object def _config_string(self, test): compiler = getattr(test, "getCompiler", None) @@ -113,7 +112,7 @@ class LLDBTestResult(unittest2.TextTestResult): def _getFileBasedCategories(self, test): """ Returns the list of categories to which this test case belongs by - collecting values of ".categories" files. We start at the folder the test is in + collecting values of "categories" files. We start at the folder the test is in and traverse the hierarchy upwards until the test-suite root directory. """ start_path = self._getTestPath(test) @@ -127,7 +126,7 @@ class LLDBTestResult(unittest2.TextTestResult): categories = set() while not os.path.samefile(folder, test_root): - categories_file_name = os.path.join(folder, ".categories") + categories_file_name = os.path.join(folder, "categories") if os.path.exists(categories_file_name): categories_file = open(categories_file_name, 'r') categories_str = categories_file.readline().strip() @@ -181,9 +180,6 @@ class LLDBTestResult(unittest2.TextTestResult): if self.showAll: self.stream.write(self.fmt % self.counter) super(LLDBTestResult, self).startTest(test) - if self.results_formatter: - self.results_formatter.handle_event( - EventBuilder.event_for_start(test)) def addSuccess(self, test): if (self.checkExclusion( @@ -197,9 +193,6 @@ class LLDBTestResult(unittest2.TextTestResult): self.stream.write( "PASS: LLDB (%s) :: %s\n" % (self._config_string(test), str(test))) - if self.results_formatter: - self.results_formatter.handle_event( - EventBuilder.event_for_success(test)) def _isBuildError(self, err_tuple): exception = err_tuple[1] @@ -228,13 +221,6 @@ class LLDBTestResult(unittest2.TextTestResult): self.stream.write( "FAIL: LLDB (%s) :: %s\n" % (self._config_string(test), str(test))) - if self.results_formatter: - # Handle build errors as a separate event type - if self._isBuildError(err): - error_event = EventBuilder.event_for_build_error(test, err) - else: - error_event = EventBuilder.event_for_error(test, err) - self.results_formatter.handle_event(error_event) def addCleanupError(self, test, err): configuration.sdir_has_content = True @@ -243,12 +229,8 @@ class LLDBTestResult(unittest2.TextTestResult): if method: method() self.stream.write( - "CLEANUP ERROR: LLDB (%s) :: %s\n" % - (self._config_string(test), str(test))) - if self.results_formatter: - self.results_formatter.handle_event( - EventBuilder.event_for_cleanup_error( - test, err)) + "CLEANUP ERROR: LLDB (%s) :: %s\n%s\n" % + (self._config_string(test), str(test), traceback.format_exc())) def addFailure(self, test, err): if (self.checkExclusion( @@ -274,9 +256,6 @@ class LLDBTestResult(unittest2.TextTestResult): category] = configuration.failures_per_category[category] + 1 else: configuration.failures_per_category[category] = 1 - if self.results_formatter: - self.results_formatter.handle_event( - EventBuilder.event_for_failure(test, err)) def addExpectedFailure(self, test, err, bugnumber): configuration.sdir_has_content = True @@ -287,10 +266,6 @@ class LLDBTestResult(unittest2.TextTestResult): self.stream.write( "XFAIL: LLDB (%s) :: %s\n" % (self._config_string(test), str(test))) - if self.results_formatter: - self.results_formatter.handle_event( - EventBuilder.event_for_expected_failure( - test, err, bugnumber)) def addSkip(self, test, reason): configuration.sdir_has_content = True @@ -301,9 +276,6 @@ class LLDBTestResult(unittest2.TextTestResult): self.stream.write( "UNSUPPORTED: LLDB (%s) :: %s (%s) \n" % (self._config_string(test), str(test), reason)) - if self.results_formatter: - self.results_formatter.handle_event( - EventBuilder.event_for_skip(test, reason)) def addUnexpectedSuccess(self, test, bugnumber): configuration.sdir_has_content = True @@ -314,7 +286,3 @@ class LLDBTestResult(unittest2.TextTestResult): self.stream.write( "XPASS: LLDB (%s) :: %s\n" % (self._config_string(test), str(test))) - if self.results_formatter: - self.results_formatter.handle_event( - EventBuilder.event_for_unexpected_success( - test, bugnumber)) diff --git a/gnu/llvm/lldb/packages/Python/lldbsuite/test/tools/intelpt/intelpt_testcase.py b/gnu/llvm/lldb/packages/Python/lldbsuite/test/tools/intelpt/intelpt_testcase.py new file mode 100644 index 00000000000..a2f63bc88bd --- /dev/null +++ b/gnu/llvm/lldb/packages/Python/lldbsuite/test/tools/intelpt/intelpt_testcase.py @@ -0,0 +1,118 @@ +from lldbsuite.test.lldbtest import * +import os +import time +import json + +ADDRESS_REGEX = '0x[0-9a-fA-F]*' + +# Decorator that runs a test with both modes of USE_SB_API. +# It assumes that no tests can be executed in parallel. +def testSBAPIAndCommands(func): + def wrapper(*args, **kwargs): + TraceIntelPTTestCaseBase.USE_SB_API = True + func(*args, **kwargs) + TraceIntelPTTestCaseBase.USE_SB_API = False + func(*args, **kwargs) + return wrapper + +# Class that should be used by all python Intel PT tests. +# +# It has a handy check that skips the test if the intel-pt plugin is not enabled. +# +# It also contains many functions that can test both the SB API or the command line version +# of the most important tracing actions. +class TraceIntelPTTestCaseBase(TestBase): + + NO_DEBUG_INFO_TESTCASE = True + + # If True, the trace test methods will use the SB API, otherwise they'll use raw commands. + USE_SB_API = False + + def setUp(self): + TestBase.setUp(self) + if 'intel-pt' not in configuration.enabled_plugins: + self.skipTest("The intel-pt test plugin is not enabled") + + def getTraceOrCreate(self): + if not self.target().GetTrace().IsValid(): + error = lldb.SBError() + self.target().CreateTrace(error) + return self.target().GetTrace() + + def assertSBError(self, sberror, error=False): + if error: + self.assertTrue(sberror.Fail()) + else: + self.assertSuccess(sberror) + + def createConfiguration(self, threadBufferSize=None, + processBufferSizeLimit=None, enableTsc=False, + psbPeriod=None): + obj = {} + if processBufferSizeLimit is not None: + obj["processBufferSizeLimit"] = processBufferSizeLimit + if threadBufferSize is not None: + obj["threadBufferSize"] = threadBufferSize + if psbPeriod is not None: + obj["psbPeriod"] = psbPeriod + obj["enableTsc"] = enableTsc + + configuration = lldb.SBStructuredData() + configuration.SetFromJSON(json.dumps(obj)) + return configuration + + def traceStartThread(self, thread=None, error=False, substrs=None, + threadBufferSize=None, enableTsc=False, psbPeriod=None): + if self.USE_SB_API: + trace = self.getTraceOrCreate() + thread = thread if thread is not None else self.thread() + configuration = self.createConfiguration( + threadBufferSize=threadBufferSize, enableTsc=enableTsc, + psbPeriod=psbPeriod) + self.assertSBError(trace.Start(thread, configuration), error) + else: + command = "thread trace start" + if thread is not None: + command += " " + str(thread.GetIndexID()) + if threadBufferSize is not None: + command += " -s " + str(threadBufferSize) + if enableTsc: + command += " --tsc" + if psbPeriod is not None: + command += " --psb-period " + str(psbPeriod) + self.expect(command, error=error, substrs=substrs) + + def traceStartProcess(self, processBufferSizeLimit=None, error=False, + substrs=None, enableTsc=False, psbPeriod=None): + if self.USE_SB_API: + trace = self.getTraceOrCreate() + configuration = self.createConfiguration( + processBufferSizeLimit=processBufferSizeLimit, enableTsc=enableTsc, + psbPeriod=psbPeriod) + self.assertSBError(trace.Start(configuration), error=error) + else: + command = "process trace start" + if processBufferSizeLimit != None: + command += " -l " + str(processBufferSizeLimit) + if enableTsc: + command += " --tsc" + if psbPeriod is not None: + command += " --psb-period " + str(psbPeriod) + self.expect(command, error=error, substrs=substrs) + + def traceStopProcess(self): + if self.USE_SB_API: + self.assertSuccess(self.target().GetTrace().Stop()) + else: + self.expect("process trace stop") + + def traceStopThread(self, thread=None, error=False): + if self.USE_SB_API: + thread = thread if thread is not None else self.thread() + self.assertSBError(self.target().GetTrace().Stop(thread), error) + + else: + command = "thread trace stop" + if thread is not None: + command += " " + str(thread.GetIndexID()) + self.expect(command, error=error) diff --git a/gnu/llvm/lldb/packages/Python/lldbsuite/test/tools/lldb-server/gdbremote_testcase.py b/gnu/llvm/lldb/packages/Python/lldbsuite/test/tools/lldb-server/gdbremote_testcase.py index ac611bcca16..b6243af5435 100644 --- a/gnu/llvm/lldb/packages/Python/lldbsuite/test/tools/lldb-server/gdbremote_testcase.py +++ b/gnu/llvm/lldb/packages/Python/lldbsuite/test/tools/lldb-server/gdbremote_testcase.py @@ -27,16 +27,47 @@ class _ConnectionRefused(IOError): pass -class GdbRemoteTestCaseBase(TestBase): +class GdbRemoteTestCaseFactory(type): - NO_DEBUG_INFO_TESTCASE = True + def __new__(cls, name, bases, attrs): + newattrs = {} + for attrname, attrvalue in attrs.items(): + if not attrname.startswith("test"): + newattrs[attrname] = attrvalue + continue + + # If any debug server categories were explicitly tagged, assume + # that list to be authoritative. If none were specified, try + # all of them. + all_categories = set(["debugserver", "llgs"]) + categories = set( + getattr(attrvalue, "categories", [])) & all_categories + if not categories: + categories = all_categories + + for cat in categories: + @decorators.add_test_categories([cat]) + @wraps(attrvalue) + def test_method(self, attrvalue=attrvalue): + return attrvalue(self) + + method_name = attrname + "_" + cat + test_method.__name__ = method_name + test_method.debug_server = cat + newattrs[method_name] = test_method - _TIMEOUT_SECONDS = 120 * (10 if ('ASAN_OPTIONS' in os.environ) else 1) - _DEFAULT_TIMEOUT = 10 * (10 if ('ASAN_OPTIONS' in os.environ) else 1) - _READ_TIMEOUT = 5 * (10 if ('ASAN_OPTIONS' in os.environ) else 1) - _WAIT_TIMEOUT = 5 * (10 if ('ASAN_OPTIONS' in os.environ) else 1) + return super(GdbRemoteTestCaseFactory, cls).__new__( + cls, name, bases, newattrs) - _GDBREMOTE_KILL_PACKET = "$k#6b" +@add_metaclass(GdbRemoteTestCaseFactory) +class GdbRemoteTestCaseBase(Base): + + # Default time out in seconds. The timeout is increased tenfold under Asan. + DEFAULT_TIMEOUT = 20 * (10 if ('ASAN_OPTIONS' in os.environ) else 1) + # Default sleep time in seconds. The sleep time is doubled under Asan. + DEFAULT_SLEEP = 5 * (2 if ('ASAN_OPTIONS' in os.environ) else 1) + + _GDBREMOTE_KILL_PACKET = b"$k#6b" # Start the inferior separately, attach to the inferior on the stub # command line. @@ -82,17 +113,20 @@ class GdbRemoteTestCaseBase(TestBase): return any(("gdb-remote" in channel) for channel in lldbtest_config.channels) + def getDebugServer(self): + method = getattr(self, self.testMethodName) + return getattr(method, "debug_server", None) + def setUp(self): - TestBase.setUp(self) + super(GdbRemoteTestCaseBase, self).setUp() self.setUpBaseLogging() self.debug_monitor_extra_args = [] - self._pump_queues = socket_packet_pump.PumpQueues() if self.isVerboseLoggingRequested(): # If requested, full logs go to a log file self._verbose_log_handler = logging.FileHandler( - self.log_basename + "-host.log") + self.getLogBasenameForCurrentTest() + "-host.log") self._verbose_log_handler.setFormatter(self._log_formatter) self._verbose_log_handler.setLevel(logging.DEBUG) self.logger.addHandler(self._verbose_log_handler) @@ -100,9 +134,6 @@ class GdbRemoteTestCaseBase(TestBase): self.test_sequence = GdbRemoteTestSequence(self.logger) self.set_inferior_startup_launch() self.port = self.get_next_port() - self.named_pipe_path = None - self.named_pipe = None - self.named_pipe_fd = None self.stub_sends_two_stop_notifications_on_kill = False if configuration.lldb_platform_url: if configuration.lldb_platform_url.startswith('unix-'): @@ -120,15 +151,22 @@ class GdbRemoteTestCaseBase(TestBase): else: self.stub_hostname = "localhost" - def tearDown(self): - self._pump_queues.verify_queues_empty() + debug_server = self.getDebugServer() + if debug_server == "debugserver": + self._init_debugserver_test() + else: + self._init_llgs_test() + def tearDown(self): self.logger.removeHandler(self._verbose_log_handler) self._verbose_log_handler = None TestBase.tearDown(self) + def build(self, *args, **kwargs): + self.buildDefault(*args, **kwargs) + def getLocalServerLogFile(self): - return self.log_basename + "-server.log" + return self.getLogBasenameForCurrentTest() + "-server.log" def setUpServerLogging(self, is_llgs): if len(lldbtest_config.channels) == 0: @@ -154,91 +192,14 @@ class GdbRemoteTestCaseBase(TestBase): def reset_test_sequence(self): self.test_sequence = GdbRemoteTestSequence(self.logger) - def create_named_pipe(self): - # Create a temp dir and name for a pipe. - temp_dir = tempfile.mkdtemp() - named_pipe_path = os.path.join(temp_dir, "stub_port_number") - - # Create the named pipe. - os.mkfifo(named_pipe_path) - - # Open the read side of the pipe in non-blocking mode. This will - # return right away, ready or not. - named_pipe_fd = os.open(named_pipe_path, os.O_RDONLY | os.O_NONBLOCK) - - # Create the file for the named pipe. Note this will follow semantics of - # a non-blocking read side of a named pipe, which has different semantics - # than a named pipe opened for read in non-blocking mode. - named_pipe = os.fdopen(named_pipe_fd, "r") - self.assertIsNotNone(named_pipe) - - def shutdown_named_pipe(): - # Close the pipe. - try: - named_pipe.close() - except: - print("failed to close named pipe") - None - - # Delete the pipe. - try: - os.remove(named_pipe_path) - except: - print("failed to delete named pipe: {}".format(named_pipe_path)) - None - - # Delete the temp directory. - try: - os.rmdir(temp_dir) - except: - print( - "failed to delete temp dir: {}, directory contents: '{}'".format( - temp_dir, os.listdir(temp_dir))) - None - - # Add the shutdown hook to clean up the named pipe. - self.addTearDownHook(shutdown_named_pipe) - - # Clear the port so the stub selects a port number. - self.port = 0 - - return (named_pipe_path, named_pipe, named_pipe_fd) - - def get_stub_port_from_named_socket(self, read_timeout_seconds): - # Wait for something to read with a max timeout. - (ready_readers, _, _) = select.select( - [self.named_pipe_fd], [], [], read_timeout_seconds) - self.assertIsNotNone( - ready_readers, - "write side of pipe has not written anything - stub isn't writing to pipe.") - self.assertNotEqual( - len(ready_readers), - 0, - "write side of pipe has not written anything - stub isn't writing to pipe.") - - # Read the port from the named pipe. - stub_port_raw = self.named_pipe.read() - self.assertIsNotNone(stub_port_raw) - self.assertNotEqual( - len(stub_port_raw), - 0, - "no content to read on pipe") - - # Trim null byte, convert to int. - stub_port_raw = stub_port_raw[:-1] - stub_port = int(stub_port_raw) - self.assertTrue(stub_port > 0) - - return stub_port - - def init_llgs_test(self, use_named_pipe=True): + + def _init_llgs_test(self): + reverse_connect = True if lldb.remote_platform: - # Remote platforms don't support named pipe based port negotiation - use_named_pipe = False + # Reverse connections may be tricky due to firewalls/NATs. + reverse_connect = False - triple = self.dbg.GetSelectedPlatform().GetTriple() - if re.match(".*-.*-windows", triple): - self.skipTest("Remotely testing is not supported on Windows yet.") + # FIXME: This is extremely linux-oriented # Grab the ppid from /proc/[shell pid]/stat err, retcode, shell_stat = self.run_platform_command( @@ -265,29 +226,18 @@ class GdbRemoteTestCaseBase(TestBase): # Remove if it's there. self.debug_monitor_exe = re.sub(r' \(deleted\)$', '', exe) else: - # Need to figure out how to create a named pipe on Windows. - if platform.system() == 'Windows': - use_named_pipe = False - self.debug_monitor_exe = get_lldb_server_exe() - if not self.debug_monitor_exe: - self.skipTest("lldb-server exe not found") self.debug_monitor_extra_args = ["gdbserver"] self.setUpServerLogging(is_llgs=True) - if use_named_pipe: - (self.named_pipe_path, self.named_pipe, - self.named_pipe_fd) = self.create_named_pipe() + self.reverse_connect = reverse_connect - def init_debugserver_test(self, use_named_pipe=True): + def _init_debugserver_test(self): self.debug_monitor_exe = get_debugserver_exe() - if not self.debug_monitor_exe: - self.skipTest("debugserver exe not found") self.setUpServerLogging(is_llgs=False) - if use_named_pipe: - (self.named_pipe_path, self.named_pipe, - self.named_pipe_fd) = self.create_named_pipe() + self.reverse_connect = True + # The debugserver stub has a race on handling the 'k' command, so it sends an X09 right away, then sends the real X notification # when the process truly dies. self.stub_sends_two_stop_notifications_on_kill = True @@ -318,7 +268,13 @@ class GdbRemoteTestCaseBase(TestBase): raise _ConnectionRefused() # Got EOF, connection dropped. def create_socket(self): - sock = socket.socket() + try: + sock = socket.socket(family=socket.AF_INET) + except OSError as e: + if e.errno != errno.EAFNOSUPPORT: + raise + sock = socket.socket(family=socket.AF_INET6) + logger = self.logger triple = self.dbg.GetSelectedPlatform().GetTriple() @@ -374,17 +330,17 @@ class GdbRemoteTestCaseBase(TestBase): self._inferior_startup = self._STARTUP_ATTACH_MANUALLY def get_debug_monitor_command_line_args(self, attach_pid=None): - if lldb.remote_platform: - commandline_args = self.debug_monitor_extra_args + \ - ["*:{}".format(self.port)] - else: - commandline_args = self.debug_monitor_extra_args + \ - ["127.0.0.1:{}".format(self.port)] - + commandline_args = self.debug_monitor_extra_args if attach_pid: commandline_args += ["--attach=%d" % attach_pid] - if self.named_pipe_path: - commandline_args += ["--named-pipe", self.named_pipe_path] + if self.reverse_connect: + commandline_args += ["--reverse-connect", self.connect_address] + else: + if lldb.remote_platform: + commandline_args += ["*:{}".format(self.port)] + else: + commandline_args += ["localhost:{}".format(self.port)] + return commandline_args def get_target_byte_order(self): @@ -393,6 +349,17 @@ class GdbRemoteTestCaseBase(TestBase): return target.GetByteOrder() def launch_debug_monitor(self, attach_pid=None, logfile=None): + if self.reverse_connect: + family, type, proto, _, addr = socket.getaddrinfo("localhost", 0, proto=socket.IPPROTO_TCP)[0] + sock = socket.socket(family, type, proto) + sock.settimeout(self.DEFAULT_TIMEOUT) + + sock.bind(addr) + sock.listen(1) + addr = sock.getsockname() + self.connect_address = "[{}]:{}".format(*addr) + + # Create the command line. commandline_args = self.get_debug_monitor_command_line_args( attach_pid=attach_pid) @@ -402,36 +369,24 @@ class GdbRemoteTestCaseBase(TestBase): self.debug_monitor_exe, commandline_args, install_remote=False) - self.addTearDownHook(self.cleanupSubprocesses) self.assertIsNotNone(server) - # If we're receiving the stub's listening port from the named pipe, do - # that here. - if self.named_pipe: - self.port = self.get_stub_port_from_named_socket(self._READ_TIMEOUT) + if self.reverse_connect: + self.sock = sock.accept()[0] + self.sock.settimeout(self.DEFAULT_TIMEOUT) return server def connect_to_debug_monitor(self, attach_pid=None): - if self.named_pipe: + if self.reverse_connect: # Create the stub. server = self.launch_debug_monitor(attach_pid=attach_pid) self.assertIsNotNone(server) - def shutdown_debug_monitor(): - try: - server.terminate() - except: - logger.warning( - "failed to terminate server for debug monitor: {}; ignoring".format( - sys.exc_info()[0])) - self.addTearDownHook(shutdown_debug_monitor) - # Schedule debug monitor to be shut down during teardown. logger = self.logger - # Attach to the stub and return a socket opened to it. - self.sock = self.create_socket() + self._server = Server(self.sock, server) return server # We're using a random port algorithm to try not to collide with other ports, @@ -445,15 +400,6 @@ class GdbRemoteTestCaseBase(TestBase): # Schedule debug monitor to be shut down during teardown. logger = self.logger - def shutdown_debug_monitor(): - try: - server.terminate() - except: - logger.warning( - "failed to terminate server for debug monitor: {}; ignoring".format( - sys.exc_info()[0])) - self.addTearDownHook(shutdown_debug_monitor) - connect_attemps = 0 MAX_CONNECT_ATTEMPTS = 10 @@ -462,6 +408,7 @@ class GdbRemoteTestCaseBase(TestBase): try: logger.info("Connect attempt %d", connect_attemps + 1) self.sock = self.create_socket() + self._server = Server(self.sock, server) return server except _ConnectionRefused as serr: # Ignore, and try again. @@ -506,17 +453,7 @@ class GdbRemoteTestCaseBase(TestBase): if sleep_seconds: args.append("sleep:%d" % sleep_seconds) - inferior = self.spawnSubprocess(exe_path, args) - - def shutdown_process_for_attach(): - try: - inferior.terminate() - except: - logger.warning( - "failed to terminate inferior process for attach: {}; ignoring".format( - sys.exc_info()[0])) - self.addTearDownHook(shutdown_process_for_attach) - return inferior + return self.spawnSubprocess(exe_path, args) def prep_debug_monitor_and_inferior( self, @@ -584,8 +521,9 @@ class GdbRemoteTestCaseBase(TestBase): server = self.connect_to_debug_monitor(attach_pid=attach_pid) self.assertIsNotNone(server) + self.do_handshake() + # Build the expected protocol stream - self.add_no_ack_remote_stream() if inferior_env: for name, value in inferior_env.items(): self.add_set_environment_packets(name, value) @@ -594,63 +532,13 @@ class GdbRemoteTestCaseBase(TestBase): return {"inferior": inferior, "server": server} - def expect_socket_recv( - self, - sock, - expected_content_regex, - timeout_seconds): - response = "" - timeout_time = time.time() + timeout_seconds - - while not expected_content_regex.match( - response) and time.time() < timeout_time: - can_read, _, _ = select.select([sock], [], [], timeout_seconds) - if can_read and sock in can_read: - recv_bytes = sock.recv(4096) - if recv_bytes: - response += seven.bitcast_to_string(recv_bytes) - - self.assertTrue(expected_content_regex.match(response)) - - def expect_socket_send(self, sock, content, timeout_seconds): - request_bytes_remaining = content - timeout_time = time.time() + timeout_seconds - - while len(request_bytes_remaining) > 0 and time.time() < timeout_time: - _, can_write, _ = select.select([], [sock], [], timeout_seconds) - if can_write and sock in can_write: - written_byte_count = sock.send(request_bytes_remaining.encode()) - request_bytes_remaining = request_bytes_remaining[ - written_byte_count:] - self.assertEqual(len(request_bytes_remaining), 0) - - def do_handshake(self, stub_socket, timeout_seconds=None): - if not timeout_seconds: - timeout_seconds = self._WAIT_TIMEOUT - - # Write the ack. - self.expect_socket_send(stub_socket, "+", timeout_seconds) - - # Send the start no ack mode packet. - NO_ACK_MODE_REQUEST = "$QStartNoAckMode#b0" - bytes_sent = stub_socket.send(NO_ACK_MODE_REQUEST.encode()) - self.assertEqual(bytes_sent, len(NO_ACK_MODE_REQUEST)) - - # Receive the ack and "OK" - self.expect_socket_recv(stub_socket, re.compile( - r"^\+\$OK#[0-9a-fA-F]{2}$"), timeout_seconds) - - # Send the final ack. - self.expect_socket_send(stub_socket, "+", timeout_seconds) - - def add_no_ack_remote_stream(self): - self.test_sequence.add_log_lines( - ["read packet: +", - "read packet: $QStartNoAckMode#b0", - "send packet: +", - "send packet: $OK#9a", - "read packet: +"], - True) + def do_handshake(self): + server = self._server + server.send_ack() + server.send_packet(b"QStartNoAckMode") + self.assertEqual(server.get_normal_packet(), b"+") + self.assertEqual(server.get_normal_packet(), b"OK") + server.send_ack() def add_verified_launch_packets(self, launch_args): self.test_sequence.add_log_lines( @@ -729,15 +617,12 @@ class GdbRemoteTestCaseBase(TestBase): return [parse_reg_info_response(reg_info_response) for reg_info_response in reg_info_responses] - def expect_gdbremote_sequence(self, timeout_seconds=None): - if not timeout_seconds: - timeout_seconds = self._TIMEOUT_SECONDS + def expect_gdbremote_sequence(self): return expect_lldb_gdbserver_replay( self, - self.sock, + self._server, self.test_sequence, - self._pump_queues, - timeout_seconds, + self.DEFAULT_TIMEOUT * len(self.test_sequence), self.logger) _KNOWN_REGINFO_KEYS = [ @@ -766,7 +651,10 @@ class GdbRemoteTestCaseBase(TestBase): # Check the bare-minimum expected set of register info keys. self.assertTrue("name" in reg_info) self.assertTrue("bitsize" in reg_info) - self.assertTrue("offset" in reg_info) + + if not self.getArchitecture() == 'aarch64': + self.assertTrue("offset" in reg_info) + self.assertTrue("encoding" in reg_info) self.assertTrue("format" in reg_info) @@ -829,13 +717,14 @@ class GdbRemoteTestCaseBase(TestBase): # Validate keys are known. for (key, val) in list(mem_region_dict.items()): - self.assertTrue( - key in [ - "start", - "size", - "permissions", - "name", - "error"]) + self.assertIn(key, + ["start", + "size", + "permissions", + "flags", + "name", + "error", + "dirty-pages"]) self.assertIsNotNone(val) mem_region_dict["name"] = seven.unhexlify(mem_region_dict.get("name", "")) @@ -885,11 +774,9 @@ class GdbRemoteTestCaseBase(TestBase): thread_ids.extend(new_thread_infos) return thread_ids - def wait_for_thread_count(self, thread_count, timeout_seconds=None): - if not timeout_seconds: - timeout_seconds = self._WAIT_TIMEOUT + def wait_for_thread_count(self, thread_count): start_time = time.time() - timeout_time = start_time + timeout_seconds + timeout_time = start_time + self.DEFAULT_TIMEOUT actual_thread_count = 0 while actual_thread_count < thread_count: @@ -907,7 +794,7 @@ class GdbRemoteTestCaseBase(TestBase): if time.time() > timeout_time: raise Exception( 'timed out after {} seconds while waiting for theads: waiting for at least {} threads, found {}'.format( - timeout_seconds, thread_count, actual_thread_count)) + self.DEFAULT_TIMEOUT, thread_count, actual_thread_count)) return threads @@ -949,9 +836,10 @@ class GdbRemoteTestCaseBase(TestBase): "send packet: $OK#00", ], True) - def add_qSupported_packets(self): + def add_qSupported_packets(self, client_features=[]): + features = ''.join(';' + x for x in client_features) self.test_sequence.add_log_lines( - ["read packet: $qSupported#00", + ["read packet: $qSupported{}#00".format(features), {"direction": "send", "regex": r"^\$(.*)#[0-9a-fA-F]{2}", "capture": {1: "qSupported_response"}}, ], True) @@ -966,7 +854,11 @@ class GdbRemoteTestCaseBase(TestBase): "qXfer:libraries-svr4:read", "qXfer:features:read", "qEcho", - "QPassSignals" + "QPassSignals", + "multiprocess", + "fork-events", + "vfork-events", + "memory-tagging", ] def parse_qSupported_response(self, context): @@ -1096,6 +988,13 @@ class GdbRemoteTestCaseBase(TestBase): return reg_info return None + def find_register_with_name_and_dwarf_regnum(self, reg_infos, name, dwarf_num): + self.assertIsNotNone(reg_infos) + for reg_info in reg_infos: + if (reg_info["name"] == name) and (reg_info["dwarf"] == dwarf_num): + return reg_info + return None + def decode_gdbremote_binary(self, encoded_bytes): decoded_bytes = "" i = 0 @@ -1573,7 +1472,7 @@ class GdbRemoteTestCaseBase(TestBase): g_c2_address = int(context.get("g_c2_address"), 16) # Set a breakpoint at the given address. - if self.getArchitecture() == "arm": + if self.getArchitecture().startswith("arm"): # TODO: Handle case when setting breakpoint in thumb code BREAKPOINT_KIND = 4 else: @@ -1637,8 +1536,18 @@ class GdbRemoteTestCaseBase(TestBase): # variable value if re.match("s390x", arch): expected_step_count = 2 + # ARM64 requires "4" instructions: 2 to compute the address (adrp, add), + # one to materialize the constant (mov) and the store + if re.match("arm64", arch): + expected_step_count = 4 + self.assertEqual(step_count, expected_step_count) + # ARM64: Once addresses and constants are materialized, only one + # instruction is needed. + if re.match("arm64", arch): + expected_step_count = 1 + # Verify we hit the next state. args["expected_g_c1"] = "0" args["expected_g_c2"] = "0" diff --git a/gnu/llvm/lldb/packages/Python/lldbsuite/test/tools/lldb-server/lldbgdbserverutils.py b/gnu/llvm/lldb/packages/Python/lldbsuite/test/tools/lldb-server/lldbgdbserverutils.py index 815ba3491c1..4323e97126d 100644 --- a/gnu/llvm/lldb/packages/Python/lldbsuite/test/tools/lldb-server/lldbgdbserverutils.py +++ b/gnu/llvm/lldb/packages/Python/lldbsuite/test/tools/lldb-server/lldbgdbserverutils.py @@ -3,66 +3,24 @@ from __future__ import division, print_function - +import binascii import os import os.path import platform import re import six -import socket_packet_pump +import socket import subprocess +from lldbsuite.support import seven from lldbsuite.test.lldbtest import * +from lldbsuite.test import configuration +from textwrap import dedent +import shutil -from six.moves import queue - - -def _get_debug_monitor_from_lldb(lldb_exe, debug_monitor_basename): - """Return the debug monitor exe path given the lldb exe path. - - This method attempts to construct a valid debug monitor exe name - from a given lldb exe name. It will return None if the synthesized - debug monitor name is not found to exist. - - The debug monitor exe path is synthesized by taking the directory - of the lldb exe, and replacing the portion of the base name that - matches "lldb" (case insensitive) and replacing with the value of - debug_monitor_basename. - - Args: - lldb_exe: the path to an lldb executable. - - debug_monitor_basename: the base name portion of the debug monitor - that will replace 'lldb'. - - Returns: - A path to the debug monitor exe if it is found to exist; otherwise, - returns None. - - """ - if not lldb_exe: - return None - - exe_dir = os.path.dirname(lldb_exe) - exe_base = os.path.basename(lldb_exe) +def _get_support_exe(basename): + support_dir = lldb.SBHostOS.GetLLDBPath(lldb.ePathTypeSupportExecutableDir) - # we'll rebuild the filename by replacing lldb with - # the debug monitor basename, keeping any prefix or suffix in place. - regex = re.compile(r"lldb", re.IGNORECASE) - new_base = regex.sub(debug_monitor_basename, exe_base) - - debug_monitor_exe = os.path.join(exe_dir, new_base) - if os.path.exists(debug_monitor_exe): - return debug_monitor_exe - - new_base = regex.sub( - 'LLDB.framework/Versions/A/Resources/' + - debug_monitor_basename, - exe_base) - debug_monitor_exe = os.path.join(exe_dir, new_base) - if os.path.exists(debug_monitor_exe): - return debug_monitor_exe - - return None + return shutil.which(basename, path=support_dir.GetDirectory()) def get_lldb_server_exe(): @@ -72,11 +30,8 @@ def get_lldb_server_exe(): A path to the lldb-server exe if it is found to exist; otherwise, returns None. """ - if "LLDB_DEBUGSERVER_PATH" in os.environ: - return os.environ["LLDB_DEBUGSERVER_PATH"] - return _get_debug_monitor_from_lldb( - lldbtest_config.lldbExec, "lldb-server") + return _get_support_exe("lldb-server") def get_debugserver_exe(): @@ -86,11 +41,11 @@ def get_debugserver_exe(): A path to the debugserver exe if it is found to exist; otherwise, returns None. """ - if "LLDB_DEBUGSERVER_PATH" in os.environ: - return os.environ["LLDB_DEBUGSERVER_PATH"] + if configuration.arch and configuration.arch == "x86_64" and \ + platform.machine().startswith("arm64"): + return '/Library/Apple/usr/libexec/oah/debugserver' - return _get_debug_monitor_from_lldb( - lldbtest_config.lldbExec, "debugserver") + return _get_support_exe("debugserver") _LOG_LINE_REGEX = re.compile(r'^(lldb-server|debugserver)\s+<\s*(\d+)>' + '\s+(read|send)\s+packet:\s+(.+)$') @@ -160,9 +115,8 @@ def assert_packets_equal(asserter, actual_packet, expected_packet): def expect_lldb_gdbserver_replay( asserter, - sock, + server, test_sequence, - pump_queues, timeout_seconds, logger=None): """Replay socket communication with lldb-gdbserver and verify responses. @@ -170,8 +124,6 @@ def expect_lldb_gdbserver_replay( Args: asserter: the object providing assertEqual(first, second, msg=None), e.g. TestCase instance. - sock: the TCP socket connected to the lldb-gdbserver exe. - test_sequence: a GdbRemoteTestSequence instance that describes the messages sent to the gdb remote and the responses expected from it. @@ -202,75 +154,62 @@ def expect_lldb_gdbserver_replay( return {} context = {"O_count": 0, "O_content": ""} - with socket_packet_pump.SocketPacketPump(sock, pump_queues, logger) as pump: - # Grab the first sequence entry. - sequence_entry = test_sequence.entries.pop(0) - - # While we have an active sequence entry, send messages - # destined for the stub and collect/match/process responses - # expected from the stub. - while sequence_entry: - if sequence_entry.is_send_to_remote(): - # This is an entry to send to the remote debug monitor. - send_packet = sequence_entry.get_send_packet() - if logger: - if len(send_packet) == 1 and send_packet[0] == chr(3): - packet_desc = "^C" - else: - packet_desc = send_packet - logger.info( - "sending packet to remote: {}".format(packet_desc)) - sock.sendall(send_packet.encode()) - else: - # This is an entry expecting to receive content from the remote - # debug monitor. - # We'll pull from (and wait on) the queue appropriate for the type of matcher. - # We keep separate queues for process output (coming from non-deterministic - # $O packet division) and for all other packets. - if sequence_entry.is_output_matcher(): - try: - # Grab next entry from the output queue. - content = pump_queues.output_queue().get(True, timeout_seconds) - except queue.Empty: - if logger: - logger.warning( - "timeout waiting for stub output (accumulated output:{})".format( - pump.get_accumulated_output())) - raise Exception( - "timed out while waiting for output match (accumulated output: {})".format( - pump.get_accumulated_output())) + # Grab the first sequence entry. + sequence_entry = test_sequence.entries.pop(0) + + # While we have an active sequence entry, send messages + # destined for the stub and collect/match/process responses + # expected from the stub. + while sequence_entry: + if sequence_entry.is_send_to_remote(): + # This is an entry to send to the remote debug monitor. + send_packet = sequence_entry.get_send_packet() + if logger: + if len(send_packet) == 1 and send_packet[0] == chr(3): + packet_desc = "^C" else: - try: - content = pump_queues.packet_queue().get(True, timeout_seconds) - except queue.Empty: - if logger: - logger.warning( - "timeout waiting for packet match (receive buffer: {})".format( - pump.get_receive_buffer())) - raise Exception( - "timed out while waiting for packet match (receive buffer: {})".format( - pump.get_receive_buffer())) - - # Give the sequence entry the opportunity to match the content. - # Output matchers might match or pass after more output accumulates. - # Other packet types generally must match. - asserter.assertIsNotNone(content) - context = sequence_entry.assert_match( - asserter, content, context=context) - - # Move on to next sequence entry as needed. Some sequence entries support executing multiple - # times in different states (for looping over query/response - # packets). - if sequence_entry.is_consumed(): - if len(test_sequence.entries) > 0: - sequence_entry = test_sequence.entries.pop(0) + packet_desc = send_packet + logger.info( + "sending packet to remote: {}".format(packet_desc)) + server.send_raw(send_packet.encode()) + else: + # This is an entry expecting to receive content from the remote + # debug monitor. + + # We'll pull from (and wait on) the queue appropriate for the type of matcher. + # We keep separate queues for process output (coming from non-deterministic + # $O packet division) and for all other packets. + try: + if sequence_entry.is_output_matcher(): + # Grab next entry from the output queue. + content = server.get_raw_output_packet() else: - sequence_entry = None + content = server.get_raw_normal_packet() + content = seven.bitcast_to_string(content) + except socket.timeout: + asserter.fail( + "timed out while waiting for '{}':\n{}".format(sequence_entry, server)) + + # Give the sequence entry the opportunity to match the content. + # Output matchers might match or pass after more output accumulates. + # Other packet types generally must match. + asserter.assertIsNotNone(content) + context = sequence_entry.assert_match( + asserter, content, context=context) + + # Move on to next sequence entry as needed. Some sequence entries support executing multiple + # times in different states (for looping over query/response + # packets). + if sequence_entry.is_consumed(): + if len(test_sequence.entries) > 0: + sequence_entry = test_sequence.entries.pop(0) + else: + sequence_entry = None - # Fill in the O_content entries. - context["O_count"] = 1 - context["O_content"] = pump.get_accumulated_output() + # Fill in the O_content entries. + context["O_count"] = 1 + context["O_content"] = server.consume_accumulated_output() return context @@ -442,8 +381,7 @@ class GdbRemoteEntry(GdbRemoteEntryBase): is_send_to_remote=True, exact_payload=None, regex=None, - capture=None, - expect_captures=None): + capture=None): """Create an entry representing one piece of the I/O to/from a gdb remote debug monitor. Args: @@ -460,16 +398,12 @@ class GdbRemoteEntry(GdbRemoteEntryBase): no-ack makes the checksum content essentially undefined. - regex: currently only valid for receives from gdbremote. - When specified (and only if exact_payload is None), - indicates the gdbremote response must match the given - regex. Match groups in the regex can be used for two - different purposes: saving the match (see capture - arg), or validating that a match group matches a - previously established value (see expect_captures). It - is perfectly valid to have just a regex arg and to - specify neither capture or expect_captures args. This - arg only makes sense if exact_payload is not + regex: currently only valid for receives from gdbremote. When + specified (and only if exact_payload is None), indicates the + gdbremote response must match the given regex. Match groups in + the regex can be used for the matching portion (see capture + arg). It is perfectly valid to have just a regex arg without a + capture arg. This arg only makes sense if exact_payload is not specified. capture: if specified, is a dictionary of regex match @@ -478,24 +412,12 @@ class GdbRemoteEntry(GdbRemoteEntryBase): index. For example, {1:"thread_id"} will store capture group 1's content in the context dictionary where "thread_id" is the key and the match group value is - the value. The value stored off can be used later in a - expect_captures expression. This arg only makes sense - when regex is specified. - - expect_captures: if specified, is a dictionary of regex - match group indices (should start with 1) to variable - names, where the match group should match the value - existing in the context at the given variable name. - For example, {2:"thread_id"} indicates that the second - match group must match the value stored under the - context's previously stored "thread_id" key. This arg - only makes sense when regex is specified. + the value. This arg only makes sense when regex is specified. """ self._is_send_to_remote = is_send_to_remote self.exact_payload = exact_payload self.regex = regex self.capture = capture - self.expect_captures = expect_captures def is_send_to_remote(self): return self._is_send_to_remote @@ -534,15 +456,6 @@ class GdbRemoteEntry(GdbRemoteEntryBase): # above. context[var_name] = capture_text - if self.expect_captures: - # Handle comparing matched groups to context dictionary entries. - for group_index, var_name in list(self.expect_captures.items()): - capture_text = match.group(group_index) - if not capture_text: - raise Exception( - "No content to expect for group index {}".format(group_index)) - asserter.assertEqual(capture_text, context[var_name]) - return context def assert_match(self, asserter, actual_packet, context=None): @@ -719,8 +632,7 @@ class MatchRemoteOutputEntry(GdbRemoteEntryBase): with 1) to variable names that will store the capture group indicated by the index. For example, {1:"thread_id"} will store capture group 1's content in the context dictionary where "thread_id" is the key and the match group value is - the value. The value stored off can be used later in a expect_captures expression. - This arg only makes sense when regex is specified. + the value. This arg only makes sense when regex is specified. """ def __init__(self, regex=None, regex_mode="match", capture=None): @@ -804,6 +716,9 @@ class GdbRemoteTestSequence(object): self.entries = [] self.logger = logger + def __len__(self): + return len(self.entries) + def add_log_lines(self, log_lines, remote_input_is_read): for line in log_lines: if isinstance(line, str): @@ -841,7 +756,6 @@ class GdbRemoteTestSequence(object): direction = line.get("direction", None) regex = line.get("regex", None) capture = line.get("capture", None) - expect_captures = line.get("expect_captures", None) # Compile the regex. if regex and (isinstance(regex, str)): @@ -856,8 +770,7 @@ class GdbRemoteTestSequence(object): GdbRemoteEntry( is_send_to_remote=True, regex=regex, - capture=capture, - expect_captures=expect_captures)) + capture=capture)) else: # Log line represents content to be expected from the remote debug monitor. # if self.logger: @@ -866,8 +779,7 @@ class GdbRemoteTestSequence(object): GdbRemoteEntry( is_send_to_remote=False, regex=regex, - capture=capture, - expect_captures=expect_captures)) + capture=capture)) elif entry_type == "multi_response": self.entries.append(MultiResponseGdbRemoteEntry(line)) elif entry_type == "output_match": @@ -942,9 +854,125 @@ def process_is_running(pid, unknown_value=True): # Check if the pid is in the process_ids return pid in process_ids -if __name__ == '__main__': - EXE_PATH = get_lldb_server_exe() - if EXE_PATH: - print("lldb-server path detected: {}".format(EXE_PATH)) +def _handle_output_packet_string(packet_contents): + if (not packet_contents) or (len(packet_contents) < 1): + return None + elif packet_contents[0:1] != b"O": + return None + elif packet_contents == b"OK": + return None else: - print("lldb-server could not be found") + return binascii.unhexlify(packet_contents[1:]) + +class Server(object): + + _GDB_REMOTE_PACKET_REGEX = re.compile(br'^\$([^\#]*)#[0-9a-fA-F]{2}') + + class ChecksumMismatch(Exception): + pass + + def __init__(self, sock, proc = None): + self._accumulated_output = b"" + self._receive_buffer = b"" + self._normal_queue = [] + self._output_queue = [] + self._sock = sock + self._proc = proc + + def send_raw(self, frame): + self._sock.sendall(frame) + + def send_ack(self): + self.send_raw(b"+") + + def send_packet(self, packet): + self.send_raw(b'$%s#%02x'%(packet, self._checksum(packet))) + + @staticmethod + def _checksum(packet): + checksum = 0 + for c in six.iterbytes(packet): + checksum += c + return checksum % 256 + + def _read(self, q): + while not q: + new_bytes = self._sock.recv(4096) + self._process_new_bytes(new_bytes) + return q.pop(0) + + def _process_new_bytes(self, new_bytes): + # Add new bytes to our accumulated unprocessed packet bytes. + self._receive_buffer += new_bytes + + # Parse fully-formed packets into individual packets. + has_more = len(self._receive_buffer) > 0 + while has_more: + if len(self._receive_buffer) <= 0: + has_more = False + # handle '+' ack + elif self._receive_buffer[0:1] == b"+": + self._normal_queue += [b"+"] + self._receive_buffer = self._receive_buffer[1:] + else: + packet_match = self._GDB_REMOTE_PACKET_REGEX.match( + self._receive_buffer) + if packet_match: + # Our receive buffer matches a packet at the + # start of the receive buffer. + new_output_content = _handle_output_packet_string( + packet_match.group(1)) + if new_output_content: + # This was an $O packet with new content. + self._accumulated_output += new_output_content + self._output_queue += [self._accumulated_output] + else: + # Any packet other than $O. + self._normal_queue += [packet_match.group(0)] + + # Remove the parsed packet from the receive + # buffer. + self._receive_buffer = self._receive_buffer[ + len(packet_match.group(0)):] + else: + # We don't have enough in the receive bufferto make a full + # packet. Stop trying until we read more. + has_more = False + + def get_raw_output_packet(self): + return self._read(self._output_queue) + + def get_raw_normal_packet(self): + return self._read(self._normal_queue) + + @staticmethod + def _get_payload(frame): + payload = frame[1:-3] + checksum = int(frame[-2:], 16) + if checksum != Server._checksum(payload): + raise ChecksumMismatch + return payload + + def get_normal_packet(self): + frame = self.get_raw_normal_packet() + if frame == b"+": return frame + return self._get_payload(frame) + + def get_accumulated_output(self): + return self._accumulated_output + + def consume_accumulated_output(self): + output = self._accumulated_output + self._accumulated_output = b"" + return output + + def __str__(self): + return dedent("""\ + server '{}' on '{}' + _receive_buffer: {} + _normal_queue: {} + _output_queue: {} + _accumulated_output: {} + """).format(self._proc, self._sock, self._receive_buffer, + self._normal_queue, self._output_queue, + self._accumulated_output) diff --git a/gnu/llvm/lldb/packages/Python/lldbsuite/test/tools/lldb-vscode/lldbvscode_testcase.py b/gnu/llvm/lldb/packages/Python/lldbsuite/test/tools/lldb-vscode/lldbvscode_testcase.py index c1b33c220b4..0a55fc0ead1 100644 --- a/gnu/llvm/lldb/packages/Python/lldbsuite/test/tools/lldb-vscode/lldbvscode_testcase.py +++ b/gnu/llvm/lldb/packages/Python/lldbsuite/test/tools/lldb-vscode/lldbvscode_testcase.py @@ -9,18 +9,18 @@ class VSCodeTestCaseBase(TestBase): NO_DEBUG_INFO_TESTCASE = True - def create_debug_adaptor(self): + def create_debug_adaptor(self, lldbVSCodeEnv=None): '''Create the Visual Studio Code debug adaptor''' self.assertTrue(os.path.exists(self.lldbVSCodeExec), 'lldb-vscode must exist') log_file_path = self.getBuildArtifact('vscode.txt') self.vscode = vscode.DebugAdaptor( executable=self.lldbVSCodeExec, init_commands=self.setUpCommands(), - log_file=log_file_path) + log_file=log_file_path, env=lldbVSCodeEnv) - def build_and_create_debug_adaptor(self): + def build_and_create_debug_adaptor(self, lldbVSCodeEnv=None): self.build() - self.create_debug_adaptor() + self.create_debug_adaptor(lldbVSCodeEnv) def set_source_breakpoints(self, source_path, lines, condition=None, hitCondition=None): @@ -53,11 +53,12 @@ class VSCodeTestCaseBase(TestBase): breakpoint_ids.append('%i' % (breakpoint['id'])) return breakpoint_ids - def waitUntil(self, condition): - while True: - if condition(): - break + def waitUntil(self, condition_callback): + for _ in range(20): + if condition_callback(): + return True time.sleep(0.5) + return False def verify_breakpoint_hit(self, breakpoint_ids): '''Wait for the process we are debugging to stop, and verify we hit @@ -84,7 +85,6 @@ class VSCodeTestCaseBase(TestBase): # the right breakpoint matches and not worry about the actual # location. description = body['description'] - print("description: %s" % (description)) for breakpoint_id in breakpoint_ids: match_desc = 'breakpoint %s.' % (breakpoint_id) if match_desc in description: @@ -250,7 +250,8 @@ class VSCodeTestCaseBase(TestBase): def attach(self, program=None, pid=None, waitFor=None, trace=None, initCommands=None, preRunCommands=None, stopCommands=None, exitCommands=None, attachCommands=None, coreFile=None, - disconnectAutomatically=True, terminateCommands=None): + disconnectAutomatically=True, terminateCommands=None, + postRunCommands=None): '''Build the default Makefile target, create the VSCode debug adaptor, and attach to the process. ''' @@ -270,7 +271,7 @@ class VSCodeTestCaseBase(TestBase): initCommands=initCommands, preRunCommands=preRunCommands, stopCommands=stopCommands, exitCommands=exitCommands, attachCommands=attachCommands, terminateCommands=terminateCommands, - coreFile=coreFile) + coreFile=coreFile, postRunCommands=postRunCommands) if not (response and response['success']): self.assertTrue(response['success'], 'attach failed (%s)' % (response['message'])) @@ -281,7 +282,8 @@ class VSCodeTestCaseBase(TestBase): trace=False, initCommands=None, preRunCommands=None, stopCommands=None, exitCommands=None, terminateCommands=None, sourcePath=None, debuggerRoot=None, launchCommands=None, - sourceMap=None, disconnectAutomatically=True): + sourceMap=None, disconnectAutomatically=True, runInTerminal=False, + expectFailure=False, postRunCommands=None): '''Sending launch request to vscode ''' @@ -315,10 +317,23 @@ class VSCodeTestCaseBase(TestBase): sourcePath=sourcePath, debuggerRoot=debuggerRoot, launchCommands=launchCommands, - sourceMap=sourceMap) + sourceMap=sourceMap, + runInTerminal=runInTerminal, + expectFailure=expectFailure, + postRunCommands=postRunCommands) + + if expectFailure: + return response + if not (response and response['success']): self.assertTrue(response['success'], 'launch failed (%s)' % (response['message'])) + # We need to trigger a request_configurationDone after we've successfully + # attached a runInTerminal process to finish initialization. + if runInTerminal: + self.vscode.request_configurationDone() + return response + def build_and_launch(self, program, args=None, cwd=None, env=None, stopOnEntry=False, disableASLR=True, @@ -326,14 +341,18 @@ class VSCodeTestCaseBase(TestBase): trace=False, initCommands=None, preRunCommands=None, stopCommands=None, exitCommands=None, terminateCommands=None, sourcePath=None, - debuggerRoot=None): + debuggerRoot=None, runInTerminal=False, + disconnectAutomatically=True, postRunCommands=None, + lldbVSCodeEnv=None): '''Build the default Makefile target, create the VSCode debug adaptor, and launch the process. ''' - self.build_and_create_debug_adaptor() + self.build_and_create_debug_adaptor(lldbVSCodeEnv) self.assertTrue(os.path.exists(program), 'executable must exist') - self.launch(program, args, cwd, env, stopOnEntry, disableASLR, + return self.launch(program, args, cwd, env, stopOnEntry, disableASLR, disableSTDIO, shellExpandArguments, trace, initCommands, preRunCommands, stopCommands, exitCommands, - terminateCommands, sourcePath, debuggerRoot) + terminateCommands, sourcePath, debuggerRoot, runInTerminal=runInTerminal, + disconnectAutomatically=disconnectAutomatically, + postRunCommands=postRunCommands) diff --git a/gnu/llvm/lldb/packages/Python/lldbsuite/test/tools/lldb-vscode/vscode.py b/gnu/llvm/lldb/packages/Python/lldbsuite/test/tools/lldb-vscode/vscode.py index 6b1c1c961b5..df057d5e63a 100644 --- a/gnu/llvm/lldb/packages/Python/lldbsuite/test/tools/lldb-vscode/vscode.py +++ b/gnu/llvm/lldb/packages/Python/lldbsuite/test/tools/lldb-vscode/vscode.py @@ -81,39 +81,51 @@ def read_packet(f, verbose=False, trace_file=None): # Decode the JSON bytes into a python dictionary return json.loads(json_str) - return None + raise Exception("unexpected malformed message from lldb-vscode: " + line) def packet_type_is(packet, packet_type): return 'type' in packet and packet['type'] == packet_type +def dump_dap_log(log_file): + print("========= DEBUG ADAPTER PROTOCOL LOGS =========") + if log_file is None: + print("no log file available") + else: + with open(log_file, "r") as file: + print(file.read()) + print("========= END =========") + -def read_packet_thread(vs_comm): +def read_packet_thread(vs_comm, log_file): done = False - while not done: - packet = read_packet(vs_comm.recv, trace_file=vs_comm.trace_file) - # `packet` will be `None` on EOF. We want to pass it down to - # handle_recv_packet anyway so the main thread can handle unexpected - # termination of lldb-vscode and stop waiting for new packets. - done = not vs_comm.handle_recv_packet(packet) + try: + while not done: + packet = read_packet(vs_comm.recv, trace_file=vs_comm.trace_file) + # `packet` will be `None` on EOF. We want to pass it down to + # handle_recv_packet anyway so the main thread can handle unexpected + # termination of lldb-vscode and stop waiting for new packets. + done = not vs_comm.handle_recv_packet(packet) + finally: + dump_dap_log(log_file) class DebugCommunication(object): - def __init__(self, recv, send, init_commands): + def __init__(self, recv, send, init_commands, log_file=None): self.trace_file = None self.send = send self.recv = recv self.recv_packets = [] self.recv_condition = threading.Condition() self.recv_thread = threading.Thread(target=read_packet_thread, - args=(self,)) + args=(self, log_file)) self.process_event_body = None self.exit_status = None self.initialize_body = None self.thread_stop_reasons = {} self.breakpoint_events = [] - self.module_events = {} + self.progress_events = [] self.sequence = 1 self.threads = None self.recv_thread.start() @@ -134,9 +146,13 @@ class DebugCommunication(object): if command['seq'] != response['request_seq']: raise ValueError('seq mismatch in response') - def get_active_modules(self): - return self.module_events - + def get_modules(self): + module_list = self.request_modules()['body']['modules'] + modules = {} + for module in module_list: + modules[module['name']] = module + return modules + def get_output(self, category, timeout=0.0, clear=True): self.output_condition.acquire() output = None @@ -222,13 +238,12 @@ class DebugCommunication(object): self.breakpoint_events.append(packet) # no need to add 'breakpoint' event packets to our packets list return keepGoing - elif event == 'module': - reason = body['reason'] - if (reason == 'new' or reason == 'changed'): - self.module_events[body['module']['name']] = body['module'] - elif reason == 'removed': - if body['module']['name'] in self.module_events: - self.module_events.pop(body['module']['name']) + elif event.startswith('progress'): + # Progress events come in as 'progressStart', 'progressUpdate', + # and 'progressEnd' events. Keep these around in case test + # cases want to verify them. + self.progress_events.append(packet) + # No need to add 'progress' event packets to our packets list. return keepGoing elif packet_type == 'response': @@ -300,12 +315,29 @@ class DebugCommunication(object): self.send_packet(command) done = False while not done: - response = self.recv_packet(filter_type='response') - if response is None: + response_or_request = self.recv_packet(filter_type=['response', 'request']) + if response_or_request is None: desc = 'no response for "%s"' % (command['command']) raise ValueError(desc) - self.validate_response(command, response) - return response + if response_or_request['type'] == 'response': + self.validate_response(command, response_or_request) + return response_or_request + else: + if response_or_request['command'] == 'runInTerminal': + subprocess.Popen(response_or_request['arguments']['args'], + env=response_or_request['arguments']['env']) + self.send_packet({ + "type": "response", + "seq": -1, + "request_seq": response_or_request['seq'], + "success": True, + "command": "runInTerminal", + "body": {} + }, set_sequence=False) + else: + desc = 'unkonwn reverse request "%s"' % (response_or_request['command']) + raise ValueError(desc) + return None def wait_for_event(self, filter=None, timeout=None): @@ -474,7 +506,7 @@ class DebugCommunication(object): initCommands=None, preRunCommands=None, stopCommands=None, exitCommands=None, attachCommands=None, terminateCommands=None, - coreFile=None): + coreFile=None, postRunCommands=None): args_dict = {} if pid is not None: args_dict['pid'] = pid @@ -499,6 +531,8 @@ class DebugCommunication(object): args_dict['attachCommands'] = attachCommands if coreFile: args_dict['coreFile'] = coreFile + if postRunCommands: + args_dict['postRunCommands'] = postRunCommands command_dict = { 'command': 'attach', 'type': 'request', @@ -555,13 +589,14 @@ class DebugCommunication(object): } return self.send_recv(command_dict) - def request_evaluate(self, expression, frameIndex=0, threadId=None): + def request_evaluate(self, expression, frameIndex=0, threadId=None, context=None): stackFrame = self.get_stackFrame(frameIndex=frameIndex, threadId=threadId) if stackFrame is None: return [] args_dict = { 'expression': expression, + 'context': context, 'frameId': stackFrame['id'], } command_dict = { @@ -599,7 +634,9 @@ class DebugCommunication(object): trace=False, initCommands=None, preRunCommands=None, stopCommands=None, exitCommands=None, terminateCommands=None ,sourcePath=None, - debuggerRoot=None, launchCommands=None, sourceMap=None): + debuggerRoot=None, launchCommands=None, sourceMap=None, + runInTerminal=False, expectFailure=False, + postRunCommands=None): args_dict = { 'program': program } @@ -638,6 +675,10 @@ class DebugCommunication(object): args_dict['launchCommands'] = launchCommands if sourceMap: args_dict['sourceMap'] = sourceMap + if runInTerminal: + args_dict['runInTerminal'] = runInTerminal + if postRunCommands: + args_dict['postRunCommands'] = postRunCommands command_dict = { 'command': 'launch', 'type': 'request', @@ -645,9 +686,10 @@ class DebugCommunication(object): } response = self.send_recv(command_dict) - # Wait for a 'process' and 'initialized' event in any order - self.wait_for_event(filter=['process', 'initialized']) - self.wait_for_event(filter=['process', 'initialized']) + if not expectFailure: + # Wait for a 'process' and 'initialized' event in any order + self.wait_for_event(filter=['process', 'initialized']) + self.wait_for_event(filter=['process', 'initialized']) return response def request_next(self, threadId): @@ -708,24 +750,26 @@ class DebugCommunication(object): def request_setBreakpoints(self, file_path, line_array, condition=None, hitCondition=None): (dir, base) = os.path.split(file_path) - breakpoints = [] - for line in line_array: - bp = {'line': line} - if condition is not None: - bp['condition'] = condition - if hitCondition is not None: - bp['hitCondition'] = hitCondition - breakpoints.append(bp) source_dict = { 'name': base, 'path': file_path } args_dict = { 'source': source_dict, - 'breakpoints': breakpoints, - 'lines': '%s' % (line_array), 'sourceModified': False, } + if line_array is not None: + args_dict['lines'] = '%s' % line_array + breakpoints = [] + for line in line_array: + bp = {'line': line} + if condition is not None: + bp['condition'] = condition + if hitCondition is not None: + bp['hitCondition'] = hitCondition + breakpoints.append(bp) + args_dict['breakpoints'] = breakpoints + command_dict = { 'command': 'setBreakpoints', 'type': 'request', @@ -760,16 +804,16 @@ class DebugCommunication(object): } return self.send_recv(command_dict) - def request_getCompileUnits(self, moduleId): + def request_compileUnits(self, moduleId): args_dict = {'moduleId': moduleId} command_dict = { - 'command': 'getCompileUnits', + 'command': 'compileUnits', 'type': 'request', 'arguments': args_dict } response = self.send_recv(command_dict) return response - + def request_completions(self, text): args_dict = { 'text': text, @@ -782,6 +826,12 @@ class DebugCommunication(object): } return self.send_recv(command_dict) + def request_modules(self): + return self.send_recv({ + 'command': 'modules', + 'type': 'request' + }) + def request_stackTrace(self, threadId=None, startFrame=None, levels=None, dump=False): if threadId is None: @@ -890,10 +940,13 @@ class DebugCommunication(object): class DebugAdaptor(DebugCommunication): - def __init__(self, executable=None, port=None, init_commands=[], log_file=None): + def __init__(self, executable=None, port=None, init_commands=[], log_file=None, env=None): self.process = None if executable is not None: adaptor_env = os.environ.copy() + if env is not None: + adaptor_env.update(env) + if log_file: adaptor_env['LLDBVSCODE_LOG'] = log_file self.process = subprocess.Popen([executable], @@ -902,7 +955,7 @@ class DebugAdaptor(DebugCommunication): stderr=subprocess.PIPE, env=adaptor_env) DebugCommunication.__init__(self, self.process.stdout, - self.process.stdin, init_commands) + self.process.stdin, init_commands, log_file) elif port is not None: s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect(('127.0.0.1', port)) diff --git a/gnu/llvm/lldb/packages/Python/lldbsuite/test_event/build_exception.py b/gnu/llvm/lldb/packages/Python/lldbsuite/test_event/build_exception.py index 3347d9fd7cf..e08b632eb9a 100644 --- a/gnu/llvm/lldb/packages/Python/lldbsuite/test_event/build_exception.py +++ b/gnu/llvm/lldb/packages/Python/lldbsuite/test_event/build_exception.py @@ -4,8 +4,7 @@ class BuildError(Exception): super(BuildError, self).__init__("Error when building test subject") self.command = called_process_error.lldb_extensions.get( "command", "") - self.build_error = called_process_error.lldb_extensions.get( - "stderr_content", "") + self.build_error = called_process_error.lldb_extensions["combined_output"] def __str__(self): return self.format_build_error(self.command, self.build_error) @@ -13,4 +12,4 @@ class BuildError(Exception): @staticmethod def format_build_error(command, command_output): return "Error when building test subject.\n\nBuild Command:\n{}\n\nBuild Command Output:\n{}".format( - command, command_output.decode("utf-8")) + command, command_output.decode("utf-8", errors='ignore')) diff --git a/gnu/llvm/lldb/scripts/analyze-project-deps.py b/gnu/llvm/lldb/scripts/analyze-project-deps.py index a120260abfe..89da3dc9df7 100755 --- a/gnu/llvm/lldb/scripts/analyze-project-deps.py +++ b/gnu/llvm/lldb/scripts/analyze-project-deps.py @@ -1,4 +1,4 @@ -#! /usr/bin/env python +#!/usr/bin/env python import argparse import itertools diff --git a/gnu/llvm/lldb/scripts/disasm-gdb-remote.pl b/gnu/llvm/lldb/scripts/disasm-gdb-remote.pl index e4c7066ff21..c0e7665cc72 100755 --- a/gnu/llvm/lldb/scripts/disasm-gdb-remote.pl +++ b/gnu/llvm/lldb/scripts/disasm-gdb-remote.pl @@ -1,4 +1,4 @@ -#!/usr/bin/perl +#!/usr/bin/env perl use strict; diff --git a/gnu/llvm/lldb/scripts/lldb-test-qemu/rootfs.sh b/gnu/llvm/lldb/scripts/lldb-test-qemu/rootfs.sh new file mode 100644 index 00000000000..33ff278c170 --- /dev/null +++ b/gnu/llvm/lldb/scripts/lldb-test-qemu/rootfs.sh @@ -0,0 +1,97 @@ +#!/bin/bash + +set -e + +print_usage() { + echo "Usage: $(basename $0) [options]" + echo -e "Creates a Ubuntu root file system image.\n" + echo -e " --help\t\t\tDisplay this information." + echo -e " --arch {armhf|arm64}\t\tSelects architecture of rootfs image." + echo -e " --distro {bionic|focal}\tSelects Ubuntu distribution of rootfs image." + echo -e " --size n{K|M|G}\t\tSets size of rootfs image to n Kilo, Mega or Giga bytes." + exit "$1" +} + +invalid_arg() { + echo "ERROR: Unrecognized argument: $1" >&2 + print_usage 1 +} + +update_repositories() { + echo -e "\nUpdating apt repositories. " + echo -e "\nPress 'y' to continue or any other key to exit..." + read -s -n 1 user_input + if [[ $user_input == 'Y' ]] || [[ $user_input == 'y' ]]; then + sudo apt update + else + exit + fi +} + +# Parse options +while [[ $# -gt 0 ]]; do + case "${END_OF_OPT}${1}" in + --help) print_usage 0 ;; + --arch) rfs_arch=$2; shift;; + --distro) rfs_distro=$2; shift;; + --size) rfs_size=$2; shift;; + *) invalid_arg "$1" ;; + esac + shift +done + +if [ -z "$rfs_arch" ]; then + echo "Missing architecture" + print_usage 1 +fi +if [ -z "$rfs_distro" ]; then + echo "Missing distribution" + print_usage 1 +fi +if [ -z "$rfs_size" ]; then + echo "Missing size" + print_usage 1 +fi + +if [[ "$rfs_arch" != "arm64" && "$rfs_arch" != "armhf" ]]; then + echo "Invalid architecture: $rfs_arch" + print_usage 1 +fi + +pat='^[0-9]+[K|M|G]$' +if [[ ! $rfs_size =~ $pat ]]; then + echo "Invalid size: $rfs_size" + print_usage 1 +fi + +update_repositories + +echo "Installing build dependencies ..." +sudo apt-get install debootstrap qemu-user-static schroot qemu-utils + +image_name=$rfs_distro-$rfs_arch-"rootfs" +echo "Creating $rfs_distro ($rfs_arch) root file system ..." +echo "Image name: $image_name.img" +echo "Image size: $rfs_size" + +qemu-img create $image_name.img $rfs_size + +mkfs.ext4 $image_name.img +mkdir $image_name.dir +sudo mount -o loop $image_name.img $image_name.dir + +sudo qemu-debootstrap --arch $rfs_arch $rfs_distro $image_name.dir + +sudo chroot $image_name.dir locale-gen en_US.UTF-8 + +sudo chroot $image_name.dir sed -i \ +'s/main/main restricted multiverse universe/g' /etc/apt/sources.list + +sudo chroot $image_name.dir sed -i '$ a\nameserver 8.8.8.8' /etc/resolv.conf + +sudo chroot $image_name.dir apt update +sudo chroot $image_name.dir apt -y install ssh bash-completion +sudo chroot $image_name.dir adduser --gecos "" $USER +sudo chroot $image_name.dir adduser $USER sudo +sudo umount $image_name.dir +rmdir $image_name.dir diff --git a/gnu/llvm/lldb/scripts/lldb-test-qemu/run-qemu.sh b/gnu/llvm/lldb/scripts/lldb-test-qemu/run-qemu.sh new file mode 100644 index 00000000000..339b8d955e6 --- /dev/null +++ b/gnu/llvm/lldb/scripts/lldb-test-qemu/run-qemu.sh @@ -0,0 +1,120 @@ +#!/bin/bash + +print_usage() { + echo "Usage: $(basename $0) --arch [arm|arm64] [options]" + echo -e "Starts QEMU system mode emulation for the architecture.\n" + echo -e " --help\t\t\tDisplay this information." + echo -e " --arch {arm|arm64}\t\tSelects architecture QEMU system emulation." + echo -e " --sve\t\t\t\tEnables AArch64 SVE mode." + echo -e " --mte\t\t\t\tEnables AArch64 MTE mode.\n" + echo -e " --rootfs {path}\t\tPath of root file system image." + echo -e " --qemu {path}\t\t\tPath of pre-installed qemu-system-* executable." + echo -e " --kernel {path}\t\tPath of Linux kernel prebuilt image.\n" + echo -e "By default this utility will use:" + echo -e " QEMU image built from source in qemu.git directory" + echo -e " Linux kernel image from linux.build/(arm or arm64) directory." + echo -e "Custom Linux kernel image or QEMU binary can be provided using commandline." + exit "$1" +} + +invalid_arg() { + echo "ERROR: Unrecognized argument: $1" >&2 + print_usage 1 +} + +run_qemu() { + QEMU_CORES=2 + QEMU_MEMORY=1024 + + $QEMU_BIN \ + -cpu $QEMU_CPU \ + -m $QEMU_MEMORY \ + -smp $QEMU_CORES \ + -kernel $KERNEL_IMG \ + -machine $QEMU_MACHINE \ + -drive file=$ROOTFS_IMG,if=none,format=raw,id=hd0 \ + -device virtio-blk-device,drive=hd0 \ + -append "root=/dev/vda rw ip=dhcp mem=1024M raid=noautodetect \ + crashkernel=128M rootwait console=ttyAMA0 devtmpfs.mount=0" \ + -netdev type=tap,id=net0 \ + -device virtio-net-device,netdev=net0 \ + -nographic +} + +# Parse options +while [[ $# -gt 0 ]]; do + case "${END_OF_OPT}${1}" in + --arch) ARCH=$2; shift;; + --rootfs) ROOTFS_IMG=$2; shift;; + --kernel) KERNEL_IMG=$2; shift;; + --qemu) QEMU_BIN=$2; shift;; + --sve) SVE=1;; + --mte) MTE=1;; + --help) print_usage 0 ;; + *) invalid_arg "$1" ;; + esac + shift +done + +if [ "$ARCH" == "arm64" ] && [ "$ARCH" == "arm" ]; then + echo "Invalid architecture: $ARCH" + print_usage 1 +fi + +if [[ ! -f "$ROOTFS_IMG" ]]; then + echo "No root file system image image available for emulation." + exit +fi + +if [[ ! -f "$KERNEL_IMG" ]]; then + KERNEL_IMG_PATH=$(pwd)/linux.build/"$ARCH"/arch/"$ARCH"/boot/ + + if [[ ! -d "$KERNEL_IMG_PATH" ]]; then + echo "No Linux kernel image available for emulation." + exit + fi + + if [[ "$ARCH" == "arm" ]]; then + KERNEL_IMG=$KERNEL_IMG_PATH/zImage + elif [[ "$ARCH" == "arm64" ]]; then + KERNEL_IMG=$KERNEL_IMG_PATH/Image + fi +fi + +if [[ ! -f "$QEMU_BIN" ]]; then + if [[ "$ARCH" == "arm" ]]; then + QEMU_BIN=$(pwd)/qemu.git/arm-softmmu/qemu-system-arm + elif [[ "$ARCH" == "arm64" ]]; then + QEMU_BIN=$(pwd)/qemu.git/aarch64-softmmu/qemu-system-aarch64 + fi + + if [[ ! -f "$QEMU_BIN" ]]; then + echo "QEMU $ARCH system emulation executable not found." + exit + fi +fi + +if [[ "$ARCH" == "arm" ]]; then + QEMU_MACHINE="virt,highmem=off" + QEMU_CPU="cortex-a15" + + if [[ $SVE ]]; then + echo "warning: --sve is supported by AArch64 targets only" + fi + if [[ $MTE ]]; then + echo "warning: --mte is supported by AArch64 targets only" + fi +elif [[ "$ARCH" == "arm64" ]]; then + QEMU_MACHINE=virt + QEMU_SVE_MAX_VQ=4 + QEMU_CPU="cortex-a53" + + if [[ $SVE ]]; then + QEMU_CPU="max,sve-max-vq=$QEMU_SVE_MAX_VQ" + fi + if [[ $MTE ]]; then + QEMU_MACHINE="$QEMU_MACHINE,mte=on" + fi +fi + +run_qemu diff --git a/gnu/llvm/lldb/scripts/lldb-test-qemu/setup.sh b/gnu/llvm/lldb/scripts/lldb-test-qemu/setup.sh new file mode 100644 index 00000000000..c89dc168200 --- /dev/null +++ b/gnu/llvm/lldb/scripts/lldb-test-qemu/setup.sh @@ -0,0 +1,151 @@ +#!/bin/bash + +print_usage() { + echo "Usage: $(basename $0) [options]" + echo -e "Builds QEMU and Linux kernel from source.\n" + echo -e " --help\t\t\tDisplay this information." + echo -e " --kernel {arm|arm64}\t\tBuild Linux kernel for the architecture." + echo -e " --qemu\t\t\tBuild QEMU from source." + echo -e " --clean\t\t\tRemove qemu.git and linux.git directories in current directory." + exit "$1" +} + +update_repositories() { + echo -e "\nUpdating apt repositories. " + echo -e "\nPress 'y' to continue or any other key to exit..." + read -s -n 1 user_input + if [[ $user_input == 'Y' ]] || [[ $user_input == 'y' ]]; then + sudo apt update + else + exit + fi +} + +check_dir_exists() { + user_input= + if [ -d "$1" ]; then + echo -e "\n$1 already exists in working directory and will not be updated." + echo -e "\nPress 'y' to continue or any other key to exit..." + read -s -n 1 user_input + if [[ $user_input != 'Y' ]] && [[ $user_input != 'y' ]]; then + exit + fi + fi +} + +invalid_arg() { + echo "ERROR: Unrecognized argument: $1" >&2 + print_usage 1 +} + +build_qemu() { + echo "Installing QEMU build dependencies ..." + sudo apt install git python3-dev libsdl1.2-dev build-essential libpixman-1-dev + + # Checkout source code + check_dir_exists "qemu.git" + if [ ! -d "qemu.git" ]; then + git clone --depth 1 git://git.qemu.org/qemu.git qemu.git + fi + + cd qemu.git + # We are going to build QEMU Arm and AArch64 system mode emulation. + # ./configure --help emits a list of other possible targets supported by QEMU. + ./configure --target-list=arm-softmmu,aarch64-softmmu + make -j`getconf _NPROCESSORS_ONLN` +} + +build_linux() { + echo "Installing Linux kernel build dependencies ..." + sudo apt install git bison flex build-essential libssl-dev bc + + check_dir_exists "linux.git" + + if [ ! -d "linux.git" ]; then + git clone --depth 1 \ + https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git linux.git + fi + + cd linux.git + make mrproper + + if [[ "$1" == "arm" ]]; then + echo "Installing gcc-arm-linux-gnueabihf ..." + sudo apt install gcc-arm-linux-gnueabihf + + # Configure kernel_branch=master arch=arm config=vexpress_defconfig + make O=../linux.build/arm ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- \ + vexpress_defconfig + + # Trigger Arm kernel build + make -j`getconf _NPROCESSORS_ONLN` O=../linux.build/arm ARCH=arm \ + CROSS_COMPILE=arm-linux-gnueabihf- + elif [[ "$1" == "arm64" ]]; then + echo "Installing gcc-aarch64-linux-gnu ..." + sudo apt install gcc-aarch64-linux-gnu + + # Configure kernel_branch=master arch=arm64 config=defconfig + make O=../linux.build/arm64 ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- \ + defconfig + + # Trigger AArch64 kernel build + make -j`getconf _NPROCESSORS_ONLN` O=../linux.build/arm64 ARCH=arm64 \ + CROSS_COMPILE=aarch64-linux-gnu- + else + echo "ERROR: Unrecognized architecture: $1" >&2 + print_usage 1 + exit + fi +} + +clean() { + if [ -d "linux.git" ]; then + echo "Removing linux.git ..." + rm -rf linux.git + fi + + if [ -d "linux.build" ]; then + echo "Removing linux.build ..." + rm -rf linux.build + fi + + if [ -d "qemu.git" ]; then + echo "Removing qemu.git ..." + rm -rf qemu.git + fi + + exit +} + +# Parse options +while [[ $# -gt 0 ]]; do + case "${END_OF_OPT}${1}" in + -h|--help) print_usage 0 ;; + -k|--kernel) + if [ "$2" == "arm64" ] || [ "$2" == "arm" ]; then + KERNEL_ARCH=$2 + else + invalid_arg "$2" + fi + shift;; + -q|--qemu) + QEMU=1;; + -c|--clean) clean ;; + *) invalid_arg "$1" ;; + esac + shift +done + +update_repositories + +if [ "$KERNEL_ARCH" != "" ]; then + pushd . + build_linux $KERNEL_ARCH + popd +fi + +if [[ $QEMU -eq 1 ]]; then + pushd . + build_qemu + popd +fi diff --git a/gnu/llvm/lldb/scripts/reproducer-replay.py b/gnu/llvm/lldb/scripts/reproducer-replay.py index 4dd34705834..40d7cebca05 100755 --- a/gnu/llvm/lldb/scripts/reproducer-replay.py +++ b/gnu/llvm/lldb/scripts/reproducer-replay.py @@ -1,4 +1,4 @@ -#! /usr/bin/env python3 +#!/usr/bin/env python3 from multiprocessing import Pool import multiprocessing diff --git a/gnu/llvm/lldb/scripts/use_lldb_suite.py b/gnu/llvm/lldb/scripts/use_lldb_suite.py index a1a2e8b9367..84380f6a559 100644 --- a/gnu/llvm/lldb/scripts/use_lldb_suite.py +++ b/gnu/llvm/lldb/scripts/use_lldb_suite.py @@ -8,20 +8,18 @@ def find_lldb_root(): while True: parent = os.path.dirname(lldb_root) if parent == lldb_root: # dirname('/') == '/' - break + raise Exception("use_lldb_suite_root.py not found") lldb_root = parent test_path = os.path.join(lldb_root, "use_lldb_suite_root.py") if os.path.isfile(test_path): return lldb_root - return None lldb_root = find_lldb_root() -if lldb_root is not None: - import imp - fp, pathname, desc = imp.find_module("use_lldb_suite_root", [lldb_root]) - try: - imp.load_module("use_lldb_suite_root", fp, pathname, desc) - finally: - if fp: - fp.close() +import imp +fp, pathname, desc = imp.find_module("use_lldb_suite_root", [lldb_root]) +try: + imp.load_module("use_lldb_suite_root", fp, pathname, desc) +finally: + if fp: + fp.close() diff --git a/gnu/llvm/lldb/source/API/CMakeLists.txt b/gnu/llvm/lldb/source/API/CMakeLists.txt index ce6a7ec830f..2e33f5c05c1 100644 --- a/gnu/llvm/lldb/source/API/CMakeLists.txt +++ b/gnu/llvm/lldb/source/API/CMakeLists.txt @@ -4,19 +4,19 @@ endif() get_property(LLDB_ALL_PLUGINS GLOBAL PROPERTY LLDB_PLUGINS) -if(LLDB_ENABLE_PYTHON) - get_target_property(lldb_bindings_dir swig_wrapper BINARY_DIR) - set(lldb_python_wrapper ${lldb_bindings_dir}/LLDBWrapPython.cpp) +if(LLDB_BUILD_FRAMEWORK) + set(option_install_prefix INSTALL_PREFIX ${LLDB_FRAMEWORK_INSTALL_DIR}) + set(option_framework FRAMEWORK) endif() -if(LLDB_ENABLE_LUA) - get_target_property(lldb_bindings_dir swig_wrapper_lua BINARY_DIR) - set(lldb_lua_wrapper ${lldb_bindings_dir}/LLDBWrapLua.cpp) +if(LLDB_ENABLE_PYTHON) + get_target_property(python_bindings_dir swig_wrapper_python BINARY_DIR) + set(lldb_python_wrapper ${python_bindings_dir}/LLDBWrapPython.cpp) endif() -if(LLDB_BUILD_FRAMEWORK) - set(option_install_prefix INSTALL_PREFIX ${LLDB_FRAMEWORK_INSTALL_DIR}) - set(option_framework FRAMEWORK) +if(LLDB_ENABLE_LUA) + get_target_property(lua_bindings_dir swig_wrapper_lua BINARY_DIR) + set(lldb_lua_wrapper ${lua_bindings_dir}/LLDBWrapLua.cpp) endif() add_lldb_library(liblldb SHARED ${option_framework} @@ -76,7 +76,6 @@ add_lldb_library(liblldb SHARED ${option_framework} SBThreadCollection.cpp SBThreadPlan.cpp SBTrace.cpp - SBTraceOptions.cpp SBType.cpp SBTypeCategory.cpp SBTypeEnumMember.cpp @@ -121,17 +120,14 @@ if(LLDB_ENABLE_PYTHON AND (BUILD_SHARED_LIBS OR LLVM_LINK_LLVM_DYLIB) AND UNIX A set_property(TARGET liblldb APPEND PROPERTY INSTALL_RPATH "\$ORIGIN/../../../../lib${LLVM_LIBDIR_SUFFIX}") endif() -if(PYTHON_RPATH) - set_property(TARGET liblldb APPEND PROPERTY INSTALL_RPATH "${PYTHON_RPATH}") - set_property(TARGET liblldb APPEND PROPERTY BUILD_RPATH "${PYTHON_RPATH}") +if(Python3_RPATH) + set_property(TARGET liblldb APPEND PROPERTY INSTALL_RPATH "${Python3_RPATH}") + set_property(TARGET liblldb APPEND PROPERTY BUILD_RPATH "${Python3_RPATH}") endif() -if (MSVC) - set_source_files_properties(SBReproducer.cpp PROPERTIES COMPILE_FLAGS /bigobj) -endif() -if(lldb_python_wrapper) - add_dependencies(liblldb swig_wrapper) +if(LLDB_ENABLE_PYTHON) + add_dependencies(liblldb swig_wrapper_python) if (MSVC) set_property(SOURCE ${lldb_python_wrapper} APPEND_STRING PROPERTY COMPILE_FLAGS " /W0") @@ -151,7 +147,7 @@ if(lldb_python_wrapper) endif () endif() -if(lldb_lua_wrapper) +if(LLDB_ENABLE_LUA) add_dependencies(liblldb swig_wrapper_lua) target_include_directories(liblldb PRIVATE ${LUA_INCLUDE_DIR}) @@ -185,21 +181,34 @@ if (NOT CMAKE_SYSTEM_NAME MATCHES "Windows") set_target_properties(liblldb_exports PROPERTIES FOLDER "lldb misc") endif() -if ( CMAKE_SYSTEM_NAME MATCHES "Windows" ) - # Only MSVC has the ABI compatibility problem and avoids using FindPythonLibs, - # so only it needs to explicitly link against ${PYTHON_LIBRARIES} - if (MSVC AND LLDB_ENABLE_PYTHON) - target_link_libraries(liblldb PRIVATE ${PYTHON_LIBRARIES}) - endif() -else() +if (NOT MSVC) set_target_properties(liblldb PROPERTIES OUTPUT_NAME lldb ) endif() -if (NOT LLDB_BUILT_STANDALONE) +# The Clang expression parser in LLDB requires the Clang resource directory to function. +if (TARGET clang-resource-headers) + # If building alongside Clang, just add a dependency to ensure it is build together with liblldb. add_dependencies(liblldb clang-resource-headers) +else() + # In a standalone build create a symlink from the LLDB library directory that points to the + # resource directory in the Clang library directory. LLDB searches relative to its install path, + # and the symlink is created in the same relative path as the resource directory of Clang when + # building alongside Clang. + # When building the LLDB framework, this isn't necessary as there we copy everything we need into + # the framework (including the Clang resourece directory). + if(NOT LLDB_BUILD_FRAMEWORK) + set(LLDB_CLANG_RESOURCE_DIR_PARENT "$/clang") + file(MAKE_DIRECTORY "${LLDB_CLANG_RESOURCE_DIR_PARENT}") + add_custom_command(TARGET liblldb POST_BUILD + COMMENT "Linking Clang resource dir into LLDB build directory: ${LLDB_CLANG_RESOURCE_DIR_PARENT}" + COMMAND ${CMAKE_COMMAND} -E make_directory "${LLDB_CLANG_RESOURCE_DIR_PARENT}" + COMMAND ${CMAKE_COMMAND} -E create_symlink "${LLDB_EXTERNAL_CLANG_RESOURCE_DIR}" + "${LLDB_CLANG_RESOURCE_DIR_PARENT}/${LLDB_CLANG_RESOURCE_DIR_NAME}" + ) + endif() endif() if(LLDB_BUILD_FRAMEWORK) diff --git a/gnu/llvm/lldb/source/API/SBAddress.cpp b/gnu/llvm/lldb/source/API/SBAddress.cpp index 6444a006c0f..7c102270a87 100644 --- a/gnu/llvm/lldb/source/API/SBAddress.cpp +++ b/gnu/llvm/lldb/source/API/SBAddress.cpp @@ -25,11 +25,8 @@ SBAddress::SBAddress() : m_opaque_up(new Address()) { LLDB_RECORD_CONSTRUCTOR_NO_ARGS(SBAddress); } -SBAddress::SBAddress(const Address *lldb_object_ptr) - : m_opaque_up(new Address()) { - if (lldb_object_ptr) - m_opaque_up = std::make_unique
(*lldb_object_ptr); -} +SBAddress::SBAddress(const Address &address) + : m_opaque_up(std::make_unique
(address)) {} SBAddress::SBAddress(const SBAddress &rhs) : m_opaque_up(new Address()) { LLDB_RECORD_CONSTRUCTOR(SBAddress, (const lldb::SBAddress &), rhs); @@ -101,12 +98,7 @@ void SBAddress::SetAddress(lldb::SBSection section, lldb::addr_t offset) { addr.SetOffset(offset); } -void SBAddress::SetAddress(const Address *lldb_object_ptr) { - if (lldb_object_ptr) - ref() = *lldb_object_ptr; - else - m_opaque_up = std::make_unique
(); -} +void SBAddress::SetAddress(const Address &address) { ref() = address; } lldb::addr_t SBAddress::GetFileAddress() const { LLDB_RECORD_METHOD_CONST_NO_ARGS(lldb::addr_t, SBAddress, GetFileAddress); diff --git a/gnu/llvm/lldb/source/API/SBBlock.cpp b/gnu/llvm/lldb/source/API/SBBlock.cpp index a5fee445d5c..5c49053dd97 100644 --- a/gnu/llvm/lldb/source/API/SBBlock.cpp +++ b/gnu/llvm/lldb/source/API/SBBlock.cpp @@ -25,9 +25,7 @@ using namespace lldb; using namespace lldb_private; -SBBlock::SBBlock() : m_opaque_ptr(nullptr) { - LLDB_RECORD_CONSTRUCTOR_NO_ARGS(SBBlock); -} +SBBlock::SBBlock() { LLDB_RECORD_CONSTRUCTOR_NO_ARGS(SBBlock); } SBBlock::SBBlock(lldb_private::Block *lldb_object_ptr) : m_opaque_ptr(lldb_object_ptr) {} diff --git a/gnu/llvm/lldb/source/API/SBBreakpoint.cpp b/gnu/llvm/lldb/source/API/SBBreakpoint.cpp index eb75bf8b33f..0f0a9351999 100644 --- a/gnu/llvm/lldb/source/API/SBBreakpoint.cpp +++ b/gnu/llvm/lldb/source/API/SBBreakpoint.cpp @@ -81,6 +81,16 @@ bool SBBreakpoint::operator!=(const lldb::SBBreakpoint &rhs) { return m_opaque_wp.lock() != rhs.m_opaque_wp.lock(); } +SBTarget SBBreakpoint::GetTarget() const { + LLDB_RECORD_METHOD_CONST_NO_ARGS(lldb::SBTarget, SBBreakpoint, GetTarget); + + BreakpointSP bkpt_sp = GetSP(); + if (bkpt_sp) + return LLDB_RECORD_RESULT(SBTarget(bkpt_sp->GetTargetSP())); + + return LLDB_RECORD_RESULT(SBTarget()); +} + break_id_t SBBreakpoint::GetID() const { LLDB_RECORD_METHOD_CONST_NO_ARGS(lldb::break_id_t, SBBreakpoint, GetID); @@ -374,7 +384,7 @@ void SBBreakpoint::SetThreadIndex(uint32_t index) { if (bkpt_sp) { std::lock_guard guard( bkpt_sp->GetTarget().GetAPIMutex()); - bkpt_sp->GetOptions()->GetThreadSpec()->SetIndex(index); + bkpt_sp->GetOptions().GetThreadSpec()->SetIndex(index); } } @@ -387,7 +397,7 @@ uint32_t SBBreakpoint::GetThreadIndex() const { std::lock_guard guard( bkpt_sp->GetTarget().GetAPIMutex()); const ThreadSpec *thread_spec = - bkpt_sp->GetOptions()->GetThreadSpecNoCreate(); + bkpt_sp->GetOptions().GetThreadSpecNoCreate(); if (thread_spec != nullptr) thread_idx = thread_spec->GetIndex(); } @@ -404,7 +414,7 @@ void SBBreakpoint::SetThreadName(const char *thread_name) { if (bkpt_sp) { std::lock_guard guard( bkpt_sp->GetTarget().GetAPIMutex()); - bkpt_sp->GetOptions()->GetThreadSpec()->SetName(thread_name); + bkpt_sp->GetOptions().GetThreadSpec()->SetName(thread_name); } } @@ -417,7 +427,7 @@ const char *SBBreakpoint::GetThreadName() const { std::lock_guard guard( bkpt_sp->GetTarget().GetAPIMutex()); const ThreadSpec *thread_spec = - bkpt_sp->GetOptions()->GetThreadSpecNoCreate(); + bkpt_sp->GetOptions().GetThreadSpecNoCreate(); if (thread_spec != nullptr) name = thread_spec->GetName(); } @@ -433,7 +443,7 @@ void SBBreakpoint::SetQueueName(const char *queue_name) { if (bkpt_sp) { std::lock_guard guard( bkpt_sp->GetTarget().GetAPIMutex()); - bkpt_sp->GetOptions()->GetThreadSpec()->SetQueueName(queue_name); + bkpt_sp->GetOptions().GetThreadSpec()->SetQueueName(queue_name); } } @@ -446,7 +456,7 @@ const char *SBBreakpoint::GetQueueName() const { std::lock_guard guard( bkpt_sp->GetTarget().GetAPIMutex()); const ThreadSpec *thread_spec = - bkpt_sp->GetOptions()->GetThreadSpecNoCreate(); + bkpt_sp->GetOptions().GetThreadSpecNoCreate(); if (thread_spec) name = thread_spec->GetQueueName(); } @@ -496,7 +506,7 @@ void SBBreakpoint::SetCommandLineCommands(SBStringList &commands) { std::unique_ptr cmd_data_up( new BreakpointOptions::CommandData(*commands, eScriptLanguageNone)); - bkpt_sp->GetOptions()->SetCommandDataCallback(cmd_data_up); + bkpt_sp->GetOptions().SetCommandDataCallback(cmd_data_up); } bool SBBreakpoint::GetCommandLineCommands(SBStringList &commands) { @@ -508,7 +518,7 @@ bool SBBreakpoint::GetCommandLineCommands(SBStringList &commands) { return false; StringList command_list; bool has_commands = - bkpt_sp->GetOptions()->GetCommandLineCallbacks(command_list); + bkpt_sp->GetOptions().GetCommandLineCallbacks(command_list); if (has_commands) commands.AppendList(command_list); return has_commands; @@ -575,7 +585,22 @@ SBError SBBreakpoint::AddLocation(SBAddress &address) { return LLDB_RECORD_RESULT(error); } -void SBBreakpoint ::SetCallback(SBBreakpointHitCallback callback, void *baton) { +SBStructuredData SBBreakpoint::SerializeToStructuredData() { + LLDB_RECORD_METHOD_NO_ARGS(lldb::SBStructuredData, SBBreakpoint, + SerializeToStructuredData); + + SBStructuredData data; + BreakpointSP bkpt_sp = GetSP(); + + if (!bkpt_sp) + return LLDB_RECORD_RESULT(data); + + StructuredData::ObjectSP bkpt_dict = bkpt_sp->SerializeToStructuredData(); + data.m_impl_up->SetObjectSP(bkpt_dict); + return LLDB_RECORD_RESULT(data); +} + +void SBBreakpoint::SetCallback(SBBreakpointHitCallback callback, void *baton) { LLDB_RECORD_DUMMY(void, SBBreakpoint, SetCallback, (lldb::SBBreakpointHitCallback, void *), callback, baton); @@ -611,7 +636,7 @@ SBError SBBreakpoint::SetScriptCallbackFunction( Status error; std::lock_guard guard( bkpt_sp->GetTarget().GetAPIMutex()); - BreakpointOptions *bp_options = bkpt_sp->GetOptions(); + BreakpointOptions &bp_options = bkpt_sp->GetOptions(); error = bkpt_sp->GetTarget() .GetDebugger() .GetScriptInterpreter() @@ -636,7 +661,7 @@ SBError SBBreakpoint::SetScriptCallbackBody(const char *callback_body_text) { if (bkpt_sp) { std::lock_guard guard( bkpt_sp->GetTarget().GetAPIMutex()); - BreakpointOptions *bp_options = bkpt_sp->GetOptions(); + BreakpointOptions &bp_options = bkpt_sp->GetOptions(); Status error = bkpt_sp->GetTarget() .GetDebugger() @@ -972,6 +997,7 @@ void RegisterMethods(Registry &R) { SBBreakpoint, operator==,(const lldb::SBBreakpoint &)); LLDB_REGISTER_METHOD(bool, SBBreakpoint, operator!=,(const lldb::SBBreakpoint &)); + LLDB_REGISTER_METHOD_CONST(lldb::SBTarget, SBBreakpoint, GetTarget, ()); LLDB_REGISTER_METHOD_CONST(lldb::break_id_t, SBBreakpoint, GetID, ()); LLDB_REGISTER_METHOD_CONST(bool, SBBreakpoint, IsValid, ()); LLDB_REGISTER_METHOD_CONST(bool, SBBreakpoint, operator bool, ()); @@ -1017,6 +1043,8 @@ void RegisterMethods(Registry &R) { (lldb::SBStream &, bool)); LLDB_REGISTER_METHOD(lldb::SBError, SBBreakpoint, AddLocation, (lldb::SBAddress &)); + LLDB_REGISTER_METHOD(lldb::SBStructuredData, SBBreakpoint, + SerializeToStructuredData, ()); LLDB_REGISTER_METHOD(void, SBBreakpoint, SetScriptCallbackFunction, (const char *)); LLDB_REGISTER_METHOD(lldb::SBError, SBBreakpoint, SetScriptCallbackFunction, diff --git a/gnu/llvm/lldb/source/API/SBBreakpointLocation.cpp b/gnu/llvm/lldb/source/API/SBBreakpointLocation.cpp index e29f3fd9c50..17512042992 100644 --- a/gnu/llvm/lldb/source/API/SBBreakpointLocation.cpp +++ b/gnu/llvm/lldb/source/API/SBBreakpointLocation.cpp @@ -80,7 +80,7 @@ SBAddress SBBreakpointLocation::GetAddress() { BreakpointLocationSP loc_sp = GetSP(); if (loc_sp) { - return LLDB_RECORD_RESULT(SBAddress(&loc_sp->GetAddress())); + return LLDB_RECORD_RESULT(SBAddress(loc_sp->GetAddress())); } return LLDB_RECORD_RESULT(SBAddress()); @@ -218,8 +218,8 @@ SBError SBBreakpointLocation::SetScriptCallbackFunction( const char *callback_function_name, SBStructuredData &extra_args) { LLDB_RECORD_METHOD(SBError, SBBreakpointLocation, SetScriptCallbackFunction, - (const char *, SBStructuredData &), - callback_function_name, extra_args); + (const char *, SBStructuredData &), callback_function_name, + extra_args); SBError sb_error; BreakpointLocationSP loc_sp = GetSP(); @@ -227,7 +227,7 @@ SBError SBBreakpointLocation::SetScriptCallbackFunction( Status error; std::lock_guard guard( loc_sp->GetTarget().GetAPIMutex()); - BreakpointOptions *bp_options = loc_sp->GetLocationOptions(); + BreakpointOptions &bp_options = loc_sp->GetLocationOptions(); error = loc_sp->GetBreakpoint() .GetTarget() .GetDebugger() @@ -239,7 +239,7 @@ SBError SBBreakpointLocation::SetScriptCallbackFunction( sb_error.SetError(error); } else sb_error.SetErrorString("invalid breakpoint"); - + return LLDB_RECORD_RESULT(sb_error); } @@ -254,7 +254,7 @@ SBBreakpointLocation::SetScriptCallbackBody(const char *callback_body_text) { if (loc_sp) { std::lock_guard guard( loc_sp->GetTarget().GetAPIMutex()); - BreakpointOptions *bp_options = loc_sp->GetLocationOptions(); + BreakpointOptions &bp_options = loc_sp->GetLocationOptions(); Status error = loc_sp->GetBreakpoint() .GetTarget() @@ -283,7 +283,7 @@ void SBBreakpointLocation::SetCommandLineCommands(SBStringList &commands) { std::unique_ptr cmd_data_up( new BreakpointOptions::CommandData(*commands, eScriptLanguageNone)); - loc_sp->GetLocationOptions()->SetCommandDataCallback(cmd_data_up); + loc_sp->GetLocationOptions().SetCommandDataCallback(cmd_data_up); } bool SBBreakpointLocation::GetCommandLineCommands(SBStringList &commands) { @@ -295,7 +295,7 @@ bool SBBreakpointLocation::GetCommandLineCommands(SBStringList &commands) { return false; StringList command_list; bool has_commands = - loc_sp->GetLocationOptions()->GetCommandLineCallbacks(command_list); + loc_sp->GetLocationOptions().GetCommandLineCallbacks(command_list); if (has_commands) commands.AppendList(command_list); return has_commands; diff --git a/gnu/llvm/lldb/source/API/SBBreakpointName.cpp b/gnu/llvm/lldb/source/API/SBBreakpointName.cpp index 3995defcf97..b5c700c78bb 100644 --- a/gnu/llvm/lldb/source/API/SBBreakpointName.cpp +++ b/gnu/llvm/lldb/source/API/SBBreakpointName.cpp @@ -144,7 +144,7 @@ SBBreakpointName::SBBreakpointName(SBBreakpoint &sb_bkpt, const char *name) { } // Now copy over the breakpoint's options: - target.ConfigureBreakpointName(*bp_name, *bkpt_sp->GetOptions(), + target.ConfigureBreakpointName(*bp_name, bkpt_sp->GetOptions(), BreakpointName::Permissions()); } @@ -594,12 +594,11 @@ SBError SBBreakpointName::SetScriptCallbackFunction( BreakpointOptions &bp_options = bp_name->GetOptions(); Status error; error = m_impl_up->GetTarget() - ->GetDebugger() - .GetScriptInterpreter() - ->SetBreakpointCommandCallbackFunction(&bp_options, - callback_function_name, - extra_args.m_impl_up - ->GetObjectSP()); + ->GetDebugger() + .GetScriptInterpreter() + ->SetBreakpointCommandCallbackFunction( + bp_options, callback_function_name, + extra_args.m_impl_up->GetObjectSP()); sb_error.SetError(error); UpdateName(*bp_name); return LLDB_RECORD_RESULT(sb_error); @@ -623,7 +622,7 @@ SBBreakpointName::SetScriptCallbackBody(const char *callback_body_text) { m_impl_up->GetTarget() ->GetDebugger() .GetScriptInterpreter() - ->SetBreakpointCommandCallback(&bp_options, callback_body_text); + ->SetBreakpointCommandCallback(bp_options, callback_body_text); sb_error.SetError(error); if (!sb_error.Fail()) UpdateName(*bp_name); diff --git a/gnu/llvm/lldb/source/API/SBBroadcaster.cpp b/gnu/llvm/lldb/source/API/SBBroadcaster.cpp index d42d7ce2a53..2e6d837f102 100644 --- a/gnu/llvm/lldb/source/API/SBBroadcaster.cpp +++ b/gnu/llvm/lldb/source/API/SBBroadcaster.cpp @@ -16,7 +16,7 @@ using namespace lldb; using namespace lldb_private; -SBBroadcaster::SBBroadcaster() : m_opaque_sp(), m_opaque_ptr(nullptr) { +SBBroadcaster::SBBroadcaster() : m_opaque_sp() { LLDB_RECORD_CONSTRUCTOR_NO_ARGS(SBBroadcaster); } diff --git a/gnu/llvm/lldb/source/API/SBCommandInterpreter.cpp b/gnu/llvm/lldb/source/API/SBCommandInterpreter.cpp index f4f19577b36..b4a69c3e972 100644 --- a/gnu/llvm/lldb/source/API/SBCommandInterpreter.cpp +++ b/gnu/llvm/lldb/source/API/SBCommandInterpreter.cpp @@ -171,27 +171,22 @@ lldb::ReturnStatus SBCommandInterpreter::HandleCommand( lldb::SBCommandReturnObject &, bool), command_line, override_context, result, add_to_history); - - ExecutionContext ctx, *ctx_ptr; - if (override_context.get()) { - ctx = override_context.get()->Lock(true); - ctx_ptr = &ctx; - } else - ctx_ptr = nullptr; - result.Clear(); if (command_line && IsValid()) { result.ref().SetInteractive(false); - m_opaque_ptr->HandleCommand(command_line, - add_to_history ? eLazyBoolYes : eLazyBoolNo, - result.ref(), ctx_ptr); + auto do_add_to_history = add_to_history ? eLazyBoolYes : eLazyBoolNo; + if (override_context.get()) + m_opaque_ptr->HandleCommand(command_line, do_add_to_history, + override_context.get()->Lock(true), + result.ref()); + else + m_opaque_ptr->HandleCommand(command_line, do_add_to_history, + result.ref()); } else { result->AppendError( "SBCommandInterpreter or the command line is not valid"); - result->SetStatus(eReturnStatusFailed); } - return result.GetStatus(); } @@ -207,7 +202,6 @@ void SBCommandInterpreter::HandleCommandsFromFile( if (!IsValid()) { result->AppendError("SBCommandInterpreter is not valid."); - result->SetStatus(eReturnStatusFailed); return; } @@ -215,19 +209,17 @@ void SBCommandInterpreter::HandleCommandsFromFile( SBStream s; file.GetDescription(s); result->AppendErrorWithFormat("File is not valid: %s.", s.GetData()); - result->SetStatus(eReturnStatusFailed); } FileSpec tmp_spec = file.ref(); - ExecutionContext ctx, *ctx_ptr; - if (override_context.get()) { - ctx = override_context.get()->Lock(true); - ctx_ptr = &ctx; - } else - ctx_ptr = nullptr; + if (override_context.get()) + m_opaque_ptr->HandleCommandsFromFile(tmp_spec, + override_context.get()->Lock(true), + options.ref(), + result.ref()); - m_opaque_ptr->HandleCommandsFromFile(tmp_spec, ctx_ptr, options.ref(), - result.ref()); + else + m_opaque_ptr->HandleCommandsFromFile(tmp_spec, options.ref(), result.ref()); } int SBCommandInterpreter::HandleCompletion( @@ -444,7 +436,6 @@ void SBCommandInterpreter::ResolveCommand(const char *command_line, } else { result->AppendError( "SBCommandInterpreter or the command line is not valid"); - result->SetStatus(eReturnStatusFailed); } } @@ -474,7 +465,23 @@ void SBCommandInterpreter::SourceInitFileInHomeDirectory( m_opaque_ptr->SourceInitFileHome(result.ref()); } else { result->AppendError("SBCommandInterpreter is not valid"); - result->SetStatus(eReturnStatusFailed); + } +} + +void SBCommandInterpreter::SourceInitFileInHomeDirectory( + SBCommandReturnObject &result, bool is_repl) { + LLDB_RECORD_METHOD(void, SBCommandInterpreter, SourceInitFileInHomeDirectory, + (lldb::SBCommandReturnObject &, bool), result, is_repl); + + result.Clear(); + if (IsValid()) { + TargetSP target_sp(m_opaque_ptr->GetDebugger().GetSelectedTarget()); + std::unique_lock lock; + if (target_sp) + lock = std::unique_lock(target_sp->GetAPIMutex()); + m_opaque_ptr->SourceInitFileHome(result.ref(), is_repl); + } else { + result->AppendError("SBCommandInterpreter is not valid"); } } @@ -493,7 +500,6 @@ void SBCommandInterpreter::SourceInitFileInCurrentWorkingDirectory( m_opaque_ptr->SourceInitFileCwd(result.ref()); } else { result->AppendError("SBCommandInterpreter is not valid"); - result->SetStatus(eReturnStatusFailed); } } @@ -806,6 +812,9 @@ template <> void RegisterMethods(Registry &R) { LLDB_REGISTER_METHOD(void, SBCommandInterpreter, SourceInitFileInHomeDirectory, (lldb::SBCommandReturnObject &)); + LLDB_REGISTER_METHOD(void, SBCommandInterpreter, + SourceInitFileInHomeDirectory, + (lldb::SBCommandReturnObject &, bool)); LLDB_REGISTER_METHOD(void, SBCommandInterpreter, SourceInitFileInCurrentWorkingDirectory, (lldb::SBCommandReturnObject &)); diff --git a/gnu/llvm/lldb/source/API/SBCommandInterpreterRunOptions.cpp b/gnu/llvm/lldb/source/API/SBCommandInterpreterRunOptions.cpp index fcfbf5e5401..317ec6d3712 100644 --- a/gnu/llvm/lldb/source/API/SBCommandInterpreterRunOptions.cpp +++ b/gnu/llvm/lldb/source/API/SBCommandInterpreterRunOptions.cpp @@ -24,8 +24,29 @@ SBCommandInterpreterRunOptions::SBCommandInterpreterRunOptions() { m_opaque_up = std::make_unique(); } +SBCommandInterpreterRunOptions::SBCommandInterpreterRunOptions( + const SBCommandInterpreterRunOptions &rhs) + : m_opaque_up() { + LLDB_RECORD_CONSTRUCTOR(SBCommandInterpreterRunOptions, + (const lldb::SBCommandInterpreterRunOptions &), rhs); + + m_opaque_up = std::make_unique(rhs.ref()); +} + SBCommandInterpreterRunOptions::~SBCommandInterpreterRunOptions() = default; +SBCommandInterpreterRunOptions &SBCommandInterpreterRunOptions::operator=( + const SBCommandInterpreterRunOptions &rhs) { + LLDB_RECORD_METHOD(lldb::SBCommandInterpreterRunOptions &, + SBCommandInterpreterRunOptions, operator=, + (const lldb::SBCommandInterpreterRunOptions &), rhs); + + if (this == &rhs) + return LLDB_RECORD_RESULT(*this); + *m_opaque_up = *rhs.m_opaque_up; + return LLDB_RECORD_RESULT(*this); +} + bool SBCommandInterpreterRunOptions::GetStopOnContinue() const { LLDB_RECORD_METHOD_CONST_NO_ARGS(bool, SBCommandInterpreterRunOptions, GetStopOnContinue); @@ -110,6 +131,20 @@ void SBCommandInterpreterRunOptions::SetPrintResults(bool print_results) { m_opaque_up->SetPrintResults(print_results); } +bool SBCommandInterpreterRunOptions::GetPrintErrors() const { + LLDB_RECORD_METHOD_CONST_NO_ARGS(bool, SBCommandInterpreterRunOptions, + GetPrintErrors); + + return m_opaque_up->GetPrintErrors(); +} + +void SBCommandInterpreterRunOptions::SetPrintErrors(bool print_errors) { + LLDB_RECORD_METHOD(void, SBCommandInterpreterRunOptions, SetPrintErrors, + (bool), print_errors); + + m_opaque_up->SetPrintErrors(print_errors); +} + bool SBCommandInterpreterRunOptions::GetAddToHistory() const { LLDB_RECORD_METHOD_CONST_NO_ARGS(bool, SBCommandInterpreterRunOptions, GetAddToHistory); @@ -190,12 +225,11 @@ SBCommandInterpreterRunResult::~SBCommandInterpreterRunResult() = default; SBCommandInterpreterRunResult &SBCommandInterpreterRunResult::operator=( const SBCommandInterpreterRunResult &rhs) { LLDB_RECORD_METHOD(lldb::SBCommandInterpreterRunResult &, - SBCommandInterpreterRunResult, - operator=,(const lldb::SBCommandInterpreterRunResult &), - rhs); + SBCommandInterpreterRunResult, operator=, + (const lldb::SBCommandInterpreterRunResult &), rhs); if (this == &rhs) - return *this; + return LLDB_RECORD_RESULT(*this); *m_opaque_up = *rhs.m_opaque_up; return LLDB_RECORD_RESULT(*this); } @@ -220,6 +254,11 @@ namespace repro { template <> void RegisterMethods(Registry &R) { LLDB_REGISTER_CONSTRUCTOR(SBCommandInterpreterRunOptions, ()); + LLDB_REGISTER_CONSTRUCTOR(SBCommandInterpreterRunOptions, + (const lldb::SBCommandInterpreterRunOptions &)); + LLDB_REGISTER_METHOD(lldb::SBCommandInterpreterRunOptions &, + SBCommandInterpreterRunOptions, operator=, + (const lldb::SBCommandInterpreterRunOptions &)); LLDB_REGISTER_METHOD_CONST(bool, SBCommandInterpreterRunOptions, GetStopOnContinue, ()); LLDB_REGISTER_METHOD(void, SBCommandInterpreterRunOptions, SetStopOnContinue, @@ -244,6 +283,10 @@ template <> void RegisterMethods(Registry &R) { GetPrintResults, ()); LLDB_REGISTER_METHOD(void, SBCommandInterpreterRunOptions, SetPrintResults, (bool)); + LLDB_REGISTER_METHOD_CONST(bool, SBCommandInterpreterRunOptions, + GetPrintErrors, ()); + LLDB_REGISTER_METHOD(void, SBCommandInterpreterRunOptions, SetPrintErrors, + (bool)); LLDB_REGISTER_METHOD_CONST(bool, SBCommandInterpreterRunOptions, GetAddToHistory, ()); LLDB_REGISTER_METHOD(void, SBCommandInterpreterRunOptions, SetAddToHistory, @@ -260,8 +303,8 @@ template <> void RegisterMethods(Registry &R) { LLDB_REGISTER_CONSTRUCTOR(SBCommandInterpreterRunResult, (const lldb::SBCommandInterpreterRunResult &)); LLDB_REGISTER_METHOD(lldb::SBCommandInterpreterRunResult &, - SBCommandInterpreterRunResult, - operator=,(const lldb::SBCommandInterpreterRunResult &)); + SBCommandInterpreterRunResult, operator=, + (const lldb::SBCommandInterpreterRunResult &)); LLDB_REGISTER_METHOD_CONST(int, SBCommandInterpreterRunResult, GetNumberOfErrors, ()); LLDB_REGISTER_METHOD_CONST(lldb::CommandInterpreterResult, diff --git a/gnu/llvm/lldb/source/API/SBCommandReturnObject.cpp b/gnu/llvm/lldb/source/API/SBCommandReturnObject.cpp index fddf90b6648..00150d198fc 100644 --- a/gnu/llvm/lldb/source/API/SBCommandReturnObject.cpp +++ b/gnu/llvm/lldb/source/API/SBCommandReturnObject.cpp @@ -21,8 +21,7 @@ using namespace lldb_private; class lldb_private::SBCommandReturnObjectImpl { public: - SBCommandReturnObjectImpl() - : m_ptr(new CommandReturnObject(false)), m_owned(true) {} + SBCommandReturnObjectImpl() : m_ptr(new CommandReturnObject(false)) {} SBCommandReturnObjectImpl(CommandReturnObject &ref) : m_ptr(&ref), m_owned(false) {} SBCommandReturnObjectImpl(const SBCommandReturnObjectImpl &rhs) @@ -42,7 +41,7 @@ public: private: CommandReturnObject *m_ptr; - bool m_owned; + bool m_owned = true; }; SBCommandReturnObject::SBCommandReturnObject() @@ -364,7 +363,7 @@ void SBCommandReturnObject::SetError(const char *error_cstr) { error_cstr); if (error_cstr) - ref().SetError(error_cstr); + ref().AppendError(error_cstr); } namespace lldb_private { diff --git a/gnu/llvm/lldb/source/API/SBCommunication.cpp b/gnu/llvm/lldb/source/API/SBCommunication.cpp index d55ecd35b55..9a2ab89d5e4 100644 --- a/gnu/llvm/lldb/source/API/SBCommunication.cpp +++ b/gnu/llvm/lldb/source/API/SBCommunication.cpp @@ -16,7 +16,7 @@ using namespace lldb; using namespace lldb_private; -SBCommunication::SBCommunication() : m_opaque(nullptr), m_opaque_owned(false) { +SBCommunication::SBCommunication() { LLDB_RECORD_CONSTRUCTOR_NO_ARGS(SBCommunication); } diff --git a/gnu/llvm/lldb/source/API/SBCompileUnit.cpp b/gnu/llvm/lldb/source/API/SBCompileUnit.cpp index 765957d680c..a44d3b89711 100644 --- a/gnu/llvm/lldb/source/API/SBCompileUnit.cpp +++ b/gnu/llvm/lldb/source/API/SBCompileUnit.cpp @@ -21,7 +21,7 @@ using namespace lldb; using namespace lldb_private; -SBCompileUnit::SBCompileUnit() : m_opaque_ptr(nullptr) { +SBCompileUnit::SBCompileUnit() { LLDB_RECORD_CONSTRUCTOR_NO_ARGS(SBCompileUnit); } @@ -108,9 +108,10 @@ uint32_t SBCompileUnit::FindLineEntryIndex(uint32_t start_idx, uint32_t line, else file_spec = m_opaque_ptr->GetPrimaryFile(); + LineEntry line_entry; index = m_opaque_ptr->FindLineEntry( start_idx, line, inline_file_spec ? inline_file_spec->get() : nullptr, - exact, nullptr); + exact, &line_entry); } return index; diff --git a/gnu/llvm/lldb/source/API/SBDebugger.cpp b/gnu/llvm/lldb/source/API/SBDebugger.cpp index 5f62987f37d..a854c22bb21 100644 --- a/gnu/llvm/lldb/source/API/SBDebugger.cpp +++ b/gnu/llvm/lldb/source/API/SBDebugger.cpp @@ -38,6 +38,7 @@ #include "lldb/Core/Debugger.h" #include "lldb/Core/PluginManager.h" +#include "lldb/Core/Progress.h" #include "lldb/Core/StreamFile.h" #include "lldb/Core/StructuredDataImpl.h" #include "lldb/DataFormatters/DataVisualization.h" @@ -149,6 +150,41 @@ SBDebugger &SBDebugger::operator=(const SBDebugger &rhs) { return LLDB_RECORD_RESULT(*this); } +const char *SBDebugger::GetBroadcasterClass() { + LLDB_RECORD_STATIC_METHOD_NO_ARGS(const char *, SBDebugger, + GetBroadcasterClass); + + return Debugger::GetStaticBroadcasterClass().AsCString(); +} + +const char *SBDebugger::GetProgressFromEvent(const lldb::SBEvent &event, + uint64_t &progress_id, + uint64_t &completed, + uint64_t &total, + bool &is_debugger_specific) { + const Debugger::ProgressEventData *progress_data = + Debugger::ProgressEventData::GetEventDataFromEvent(event.get()); + if (progress_data == nullptr) + return nullptr; + progress_id = progress_data->GetID(); + completed = progress_data->GetCompleted(); + total = progress_data->GetTotal(); + is_debugger_specific = progress_data->IsDebuggerSpecific(); + // We must record the static method _after_ the out parameters have been + // filled in. + LLDB_RECORD_STATIC_METHOD( + const char *, SBDebugger, GetProgressFromEvent, + (const lldb::SBEvent &, uint64_t &, uint64_t &, uint64_t &, bool &), + event, progress_id, completed, total, is_debugger_specific); + return LLDB_RECORD_RESULT(progress_data->GetMessage().c_str()) +} + +SBBroadcaster SBDebugger::GetBroadcaster() { + LLDB_RECORD_METHOD_NO_ARGS(lldb::SBBroadcaster, SBDebugger, GetBroadcaster); + SBBroadcaster broadcaster(&m_opaque_sp->GetBroadcaster(), false); + return LLDB_RECORD_RESULT(broadcaster); +} + void SBDebugger::Initialize() { LLDB_RECORD_STATIC_METHOD_NO_ARGS(void, SBDebugger, Initialize); SBError ignored = SBDebugger::InitializeWithErrorHandling(); @@ -220,7 +256,7 @@ SBDebugger SBDebugger::Create(bool source_init_files, interp.get()->SkipLLDBInitFiles(false); interp.get()->SkipAppInitFiles(false); SBCommandReturnObject result; - interp.SourceInitFileInHomeDirectory(result); + interp.SourceInitFileInHomeDirectory(result, false); } else { interp.get()->SkipLLDBInitFiles(true); interp.get()->SkipAppInitFiles(true); @@ -804,23 +840,33 @@ SBTarget SBDebugger::CreateTargetWithFileAndArch(const char *filename, TargetSP target_sp; if (m_opaque_sp) { Status error; - const bool add_dependent_modules = true; - - error = m_opaque_sp->GetTargetList().CreateTarget( - *m_opaque_sp, filename, arch_cstr, - add_dependent_modules ? eLoadDependentsYes : eLoadDependentsNo, nullptr, - target_sp); - - if (error.Success()) { - m_opaque_sp->GetTargetList().SetSelectedTarget(target_sp.get()); - sb_target.SetSP(target_sp); + if (arch_cstr == nullptr) { + // The version of CreateTarget that takes an ArchSpec won't accept an + // empty ArchSpec, so when the arch hasn't been specified, we need to + // call the target triple version. + error = m_opaque_sp->GetTargetList().CreateTarget(*m_opaque_sp, filename, + arch_cstr, eLoadDependentsYes, nullptr, target_sp); + } else { + PlatformSP platform_sp = m_opaque_sp->GetPlatformList() + .GetSelectedPlatform(); + ArchSpec arch = Platform::GetAugmentedArchSpec(platform_sp.get(), + arch_cstr); + if (arch.IsValid()) + error = m_opaque_sp->GetTargetList().CreateTarget(*m_opaque_sp, filename, + arch, eLoadDependentsYes, platform_sp, target_sp); + else + error.SetErrorStringWithFormat("invalid arch_cstr: %s", arch_cstr); } + if (error.Success()) + sb_target.SetSP(target_sp); } LLDB_LOGF(log, "SBDebugger(%p)::CreateTargetWithFileAndArch (filename=\"%s\", " "arch=%s) => SBTarget(%p)", - static_cast(m_opaque_sp.get()), filename, arch_cstr, + static_cast(m_opaque_sp.get()), + filename ? filename : "", + arch_cstr ? arch_cstr : "", static_cast(target_sp.get())); return LLDB_RECORD_RESULT(sb_target); @@ -840,10 +886,8 @@ SBTarget SBDebugger::CreateTarget(const char *filename) { add_dependent_modules ? eLoadDependentsYes : eLoadDependentsNo, nullptr, target_sp); - if (error.Success()) { - m_opaque_sp->GetTargetList().SetSelectedTarget(target_sp.get()); + if (error.Success()) sb_target.SetSP(target_sp); - } } Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_API)); LLDB_LOGF(log, @@ -858,7 +902,7 @@ SBTarget SBDebugger::GetDummyTarget() { SBTarget sb_target; if (m_opaque_sp) { - sb_target.SetSP(m_opaque_sp->GetDummyTarget()->shared_from_this()); + sb_target.SetSP(m_opaque_sp->GetDummyTarget().shared_from_this()); } Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_API)); LLDB_LOGF(log, "SBDebugger(%p)::GetDummyTarget() => SBTarget(%p)", @@ -879,8 +923,6 @@ bool SBDebugger::DeleteTarget(lldb::SBTarget &target) { result = m_opaque_sp->GetTargetList().DeleteTarget(target_sp); target_sp->Destroy(); target.Clear(); - const bool mandatory = true; - ModuleList::RemoveOrphanSharedModules(mandatory); } } @@ -1000,7 +1042,7 @@ void SBDebugger::SetSelectedTarget(SBTarget &sb_target) { TargetSP target_sp(sb_target.GetSP()); if (m_opaque_sp) { - m_opaque_sp->GetTargetList().SetSelectedTarget(target_sp.get()); + m_opaque_sp->GetTargetList().SetSelectedTarget(target_sp); } if (log) { SBStream sstr; @@ -1292,7 +1334,6 @@ SBDebugger::GetInternalVariableValue(const char *var_name, lldb::SBStringList, SBDebugger, GetInternalVariableValue, (const char *, const char *), var_name, debugger_instance_name); - SBStringList ret_value; DebuggerSP debugger_sp(Debugger::FindDebuggerWithInstanceName( ConstString(debugger_instance_name))); Status error; @@ -1345,7 +1386,7 @@ void SBDebugger::SetPrompt(const char *prompt) { LLDB_RECORD_METHOD(void, SBDebugger, SetPrompt, (const char *), prompt); if (m_opaque_sp) - m_opaque_sp->SetPrompt(llvm::StringRef::withNullAsEmpty(prompt)); + m_opaque_sp->SetPrompt(llvm::StringRef(prompt)); } const char *SBDebugger::GetReproducerPath() const { @@ -1705,6 +1746,12 @@ template <> void RegisterMethods(Registry &R) { LLDB_REGISTER_METHOD(void, SBDebugger, Clear, ()); LLDB_REGISTER_STATIC_METHOD(lldb::SBDebugger, SBDebugger, Create, ()); LLDB_REGISTER_STATIC_METHOD(lldb::SBDebugger, SBDebugger, Create, (bool)); + LLDB_REGISTER_STATIC_METHOD( + const char *, SBDebugger, GetProgressFromEvent, + (const lldb::SBEvent &, uint64_t &, uint64_t &, uint64_t &, bool &)); + LLDB_REGISTER_STATIC_METHOD(const char *, SBDebugger, GetBroadcasterClass, + ()); + LLDB_REGISTER_METHOD(SBBroadcaster, SBDebugger, GetBroadcaster, ()); LLDB_REGISTER_STATIC_METHOD(void, SBDebugger, Destroy, (lldb::SBDebugger &)); LLDB_REGISTER_STATIC_METHOD(void, SBDebugger, MemoryPressureDetected, ()); LLDB_REGISTER_METHOD_CONST(bool, SBDebugger, IsValid, ()); diff --git a/gnu/llvm/lldb/source/API/SBDeclaration.cpp b/gnu/llvm/lldb/source/API/SBDeclaration.cpp index f1066d63c06..1496096e46d 100644 --- a/gnu/llvm/lldb/source/API/SBDeclaration.cpp +++ b/gnu/llvm/lldb/source/API/SBDeclaration.cpp @@ -10,11 +10,11 @@ #include "SBReproducerPrivate.h" #include "Utils.h" #include "lldb/API/SBStream.h" +#include "lldb/Core/Declaration.h" #include "lldb/Host/PosixApi.h" -#include "lldb/Symbol/Declaration.h" #include "lldb/Utility/Stream.h" -#include +#include using namespace lldb; using namespace lldb_private; diff --git a/gnu/llvm/lldb/source/API/SBError.cpp b/gnu/llvm/lldb/source/API/SBError.cpp index 67c7663d358..89b5f26fd80 100644 --- a/gnu/llvm/lldb/source/API/SBError.cpp +++ b/gnu/llvm/lldb/source/API/SBError.cpp @@ -12,7 +12,7 @@ #include "lldb/API/SBStream.h" #include "lldb/Utility/Status.h" -#include +#include using namespace lldb; using namespace lldb_private; @@ -118,7 +118,7 @@ void SBError::SetErrorToGenericError() { LLDB_RECORD_METHOD_NO_ARGS(void, SBError, SetErrorToGenericError); CreateIfNeeded(); - m_opaque_up->SetErrorToErrno(); + m_opaque_up->SetErrorToGenericError(); } void SBError::SetErrorString(const char *err_str) { diff --git a/gnu/llvm/lldb/source/API/SBEvent.cpp b/gnu/llvm/lldb/source/API/SBEvent.cpp index 2776ec49c09..a0b606e3812 100644 --- a/gnu/llvm/lldb/source/API/SBEvent.cpp +++ b/gnu/llvm/lldb/source/API/SBEvent.cpp @@ -22,9 +22,7 @@ using namespace lldb; using namespace lldb_private; -SBEvent::SBEvent() : m_event_sp(), m_opaque_ptr(nullptr) { - LLDB_RECORD_CONSTRUCTOR_NO_ARGS(SBEvent); -} +SBEvent::SBEvent() : m_event_sp() { LLDB_RECORD_CONSTRUCTOR_NO_ARGS(SBEvent); } SBEvent::SBEvent(uint32_t event_type, const char *cstr, uint32_t cstr_len) : m_event_sp(new Event(event_type, new EventDataBytes(cstr, cstr_len))), diff --git a/gnu/llvm/lldb/source/API/SBFileSpec.cpp b/gnu/llvm/lldb/source/API/SBFileSpec.cpp index 7bfb665df4f..0a6b63bb460 100644 --- a/gnu/llvm/lldb/source/API/SBFileSpec.cpp +++ b/gnu/llvm/lldb/source/API/SBFileSpec.cpp @@ -17,8 +17,8 @@ #include "llvm/ADT/SmallString.h" -#include -#include +#include +#include using namespace lldb; using namespace lldb_private; diff --git a/gnu/llvm/lldb/source/API/SBFileSpecList.cpp b/gnu/llvm/lldb/source/API/SBFileSpecList.cpp index 7afa3436327..768ff0affd1 100644 --- a/gnu/llvm/lldb/source/API/SBFileSpecList.cpp +++ b/gnu/llvm/lldb/source/API/SBFileSpecList.cpp @@ -16,7 +16,7 @@ #include "lldb/Utility/FileSpec.h" #include "lldb/Utility/Stream.h" -#include +#include using namespace lldb; using namespace lldb_private; diff --git a/gnu/llvm/lldb/source/API/SBFrame.cpp b/gnu/llvm/lldb/source/API/SBFrame.cpp index 81782dbf838..8f9e426e066 100644 --- a/gnu/llvm/lldb/source/API/SBFrame.cpp +++ b/gnu/llvm/lldb/source/API/SBFrame.cpp @@ -431,7 +431,7 @@ SBAddress SBFrame::GetPCAddress() const { if (stop_locker.TryLock(&process->GetRunLock())) { frame = exe_ctx.GetFramePtr(); if (frame) - sb_addr.SetAddress(&frame->GetFrameCodeAddress()); + sb_addr.SetAddress(frame->GetFrameCodeAddress()); } } return LLDB_RECORD_RESULT(sb_addr); diff --git a/gnu/llvm/lldb/source/API/SBFunction.cpp b/gnu/llvm/lldb/source/API/SBFunction.cpp index e49513bd0da..2d0cb239de7 100644 --- a/gnu/llvm/lldb/source/API/SBFunction.cpp +++ b/gnu/llvm/lldb/source/API/SBFunction.cpp @@ -22,9 +22,7 @@ using namespace lldb; using namespace lldb_private; -SBFunction::SBFunction() : m_opaque_ptr(nullptr) { - LLDB_RECORD_CONSTRUCTOR_NO_ARGS(SBFunction); -} +SBFunction::SBFunction() { LLDB_RECORD_CONSTRUCTOR_NO_ARGS(SBFunction); } SBFunction::SBFunction(lldb_private::Function *lldb_object_ptr) : m_opaque_ptr(lldb_object_ptr) {} @@ -132,10 +130,10 @@ SBInstructionList SBFunction::GetInstructions(SBTarget target, m_opaque_ptr->GetAddressRange().GetBaseAddress().GetModule()); if (target_sp && module_sp) { lock = std::unique_lock(target_sp->GetAPIMutex()); - const bool prefer_file_cache = false; + const bool force_live_memory = true; sb_instructions.SetDisassembler(Disassembler::DisassembleRange( module_sp->GetArchitecture(), nullptr, flavor, *target_sp, - m_opaque_ptr->GetAddressRange(), prefer_file_cache)); + m_opaque_ptr->GetAddressRange(), force_live_memory)); } } return LLDB_RECORD_RESULT(sb_instructions); @@ -152,7 +150,7 @@ SBAddress SBFunction::GetStartAddress() { SBAddress addr; if (m_opaque_ptr) - addr.SetAddress(&m_opaque_ptr->GetAddressRange().GetBaseAddress()); + addr.SetAddress(m_opaque_ptr->GetAddressRange().GetBaseAddress()); return LLDB_RECORD_RESULT(addr); } @@ -163,7 +161,7 @@ SBAddress SBFunction::GetEndAddress() { if (m_opaque_ptr) { addr_t byte_size = m_opaque_ptr->GetAddressRange().GetByteSize(); if (byte_size > 0) { - addr.SetAddress(&m_opaque_ptr->GetAddressRange().GetBaseAddress()); + addr.SetAddress(m_opaque_ptr->GetAddressRange().GetBaseAddress()); addr->Slide(byte_size); } } diff --git a/gnu/llvm/lldb/source/API/SBHostOS.cpp b/gnu/llvm/lldb/source/API/SBHostOS.cpp index 9d3d119e4c2..deca4ac81a1 100644 --- a/gnu/llvm/lldb/source/API/SBHostOS.cpp +++ b/gnu/llvm/lldb/source/API/SBHostOS.cpp @@ -91,14 +91,13 @@ SBFileSpec SBHostOS::GetUserHomeDirectory() { LLDB_RECORD_STATIC_METHOD_NO_ARGS(lldb::SBFileSpec, SBHostOS, GetUserHomeDirectory); - SBFileSpec sb_fspec; - - llvm::SmallString<64> home_dir_path; - llvm::sys::path::home_directory(home_dir_path); - FileSpec homedir(home_dir_path.c_str()); + FileSpec homedir; + FileSystem::Instance().GetHomeDirectory(homedir); FileSystem::Instance().Resolve(homedir); + SBFileSpec sb_fspec; sb_fspec.SetFileSpec(homedir); + return LLDB_RECORD_RESULT(sb_fspec); } diff --git a/gnu/llvm/lldb/source/API/SBInstruction.cpp b/gnu/llvm/lldb/source/API/SBInstruction.cpp index 207e81272e5..579ddf84cf4 100644 --- a/gnu/llvm/lldb/source/API/SBInstruction.cpp +++ b/gnu/llvm/lldb/source/API/SBInstruction.cpp @@ -107,7 +107,7 @@ SBAddress SBInstruction::GetAddress() { SBAddress sb_addr; lldb::InstructionSP inst_sp(GetOpaque()); if (inst_sp && inst_sp->GetAddress().IsValid()) - sb_addr.SetAddress(&inst_sp->GetAddress()); + sb_addr.SetAddress(inst_sp->GetAddress()); return LLDB_RECORD_RESULT(sb_addr); } diff --git a/gnu/llvm/lldb/source/API/SBLanguageRuntime.cpp b/gnu/llvm/lldb/source/API/SBLanguageRuntime.cpp index 33c900d20c3..e65b5827051 100644 --- a/gnu/llvm/lldb/source/API/SBLanguageRuntime.cpp +++ b/gnu/llvm/lldb/source/API/SBLanguageRuntime.cpp @@ -18,8 +18,7 @@ SBLanguageRuntime::GetLanguageTypeFromString(const char *string) { LLDB_RECORD_STATIC_METHOD(lldb::LanguageType, SBLanguageRuntime, GetLanguageTypeFromString, (const char *), string); - return Language::GetLanguageTypeFromString( - llvm::StringRef::withNullAsEmpty(string)); + return Language::GetLanguageTypeFromString(llvm::StringRef(string)); } const char * diff --git a/gnu/llvm/lldb/source/API/SBLaunchInfo.cpp b/gnu/llvm/lldb/source/API/SBLaunchInfo.cpp index ba13072e8f9..70cd1c6ecf7 100644 --- a/gnu/llvm/lldb/source/API/SBLaunchInfo.cpp +++ b/gnu/llvm/lldb/source/API/SBLaunchInfo.cpp @@ -10,8 +10,12 @@ #include "SBReproducerPrivate.h" #include "lldb/API/SBEnvironment.h" +#include "lldb/API/SBError.h" #include "lldb/API/SBFileSpec.h" #include "lldb/API/SBListener.h" +#include "lldb/API/SBStream.h" +#include "lldb/API/SBStructuredData.h" +#include "lldb/Core/StructuredDataImpl.h" #include "lldb/Host/ProcessLaunchInfo.h" using namespace lldb; @@ -190,9 +194,10 @@ void SBLaunchInfo::SetEnvironment(const SBEnvironment &env, bool append) { LLDB_RECORD_METHOD(void, SBLaunchInfo, SetEnvironment, (const lldb::SBEnvironment &, bool), env, append); Environment &refEnv = env.ref(); - if (append) - m_opaque_sp->GetEnvironment().insert(refEnv.begin(), refEnv.end()); - else + if (append) { + for (auto &KV : refEnv) + m_opaque_sp->GetEnvironment().insert_or_assign(KV.first(), KV.second); + } else m_opaque_sp->GetEnvironment() = refEnv; m_opaque_sp->RegenerateEnvp(); } @@ -342,6 +347,53 @@ bool SBLaunchInfo::GetDetachOnError() const { return m_opaque_sp->GetDetachOnError(); } +const char *SBLaunchInfo::GetScriptedProcessClassName() const { + LLDB_RECORD_METHOD_CONST_NO_ARGS(const char *, SBLaunchInfo, + GetScriptedProcessClassName); + + // Constify this string so that it is saved in the string pool. Otherwise it + // would be freed when this function goes out of scope. + ConstString class_name(m_opaque_sp->GetScriptedProcessClassName().c_str()); + return class_name.AsCString(); +} + +void SBLaunchInfo::SetScriptedProcessClassName(const char *class_name) { + LLDB_RECORD_METHOD(void, SBLaunchInfo, SetScriptedProcessClassName, + (const char *), class_name); + + m_opaque_sp->SetScriptedProcessClassName(class_name); +} + +lldb::SBStructuredData SBLaunchInfo::GetScriptedProcessDictionary() const { + LLDB_RECORD_METHOD_CONST_NO_ARGS(lldb::SBStructuredData, SBLaunchInfo, + GetScriptedProcessDictionary); + + lldb_private::StructuredData::DictionarySP dict_sp = + m_opaque_sp->GetScriptedProcessDictionarySP(); + + SBStructuredData data; + data.m_impl_up->SetObjectSP(dict_sp); + + return LLDB_RECORD_RESULT(data); +} + +void SBLaunchInfo::SetScriptedProcessDictionary(lldb::SBStructuredData dict) { + LLDB_RECORD_METHOD(void, SBLaunchInfo, SetScriptedProcessDictionary, + (lldb::SBStructuredData), dict); + + SBStream stream; + SBError error = dict.GetAsJSON(stream); + + if (error.Fail()) + return; + + StructuredData::DictionarySP dict_sp; + llvm::json::OStream s(stream.ref().AsRawOstream()); + dict_sp->Serialize(s); + + m_opaque_sp->SetScriptedProcessDictionarySP(dict_sp); +} + namespace lldb_private { namespace repro { @@ -402,6 +454,14 @@ void RegisterMethods(Registry &R) { ()); LLDB_REGISTER_METHOD(void, SBLaunchInfo, SetDetachOnError, (bool)); LLDB_REGISTER_METHOD_CONST(bool, SBLaunchInfo, GetDetachOnError, ()); + LLDB_REGISTER_METHOD_CONST(const char *, SBLaunchInfo, + GetScriptedProcessClassName, ()); + LLDB_REGISTER_METHOD(void, SBLaunchInfo, SetScriptedProcessClassName, + (const char *)); + LLDB_REGISTER_METHOD_CONST(lldb::SBStructuredData, SBLaunchInfo, + GetScriptedProcessDictionary, ()); + LLDB_REGISTER_METHOD(void, SBLaunchInfo, SetScriptedProcessDictionary, + (lldb::SBStructuredData)); LLDB_REGISTER_METHOD(void, SBLaunchInfo, SetEnvironment, (const lldb::SBEnvironment &, bool)); LLDB_REGISTER_METHOD(lldb::SBEnvironment, SBLaunchInfo, GetEnvironment, ()); diff --git a/gnu/llvm/lldb/source/API/SBLineEntry.cpp b/gnu/llvm/lldb/source/API/SBLineEntry.cpp index cefbe3ee1a1..29ffda9b047 100644 --- a/gnu/llvm/lldb/source/API/SBLineEntry.cpp +++ b/gnu/llvm/lldb/source/API/SBLineEntry.cpp @@ -14,7 +14,7 @@ #include "lldb/Symbol/LineEntry.h" #include "lldb/Utility/StreamString.h" -#include +#include using namespace lldb; using namespace lldb_private; @@ -56,7 +56,7 @@ SBAddress SBLineEntry::GetStartAddress() const { SBAddress sb_address; if (m_opaque_up) - sb_address.SetAddress(&m_opaque_up->range.GetBaseAddress()); + sb_address.SetAddress(m_opaque_up->range.GetBaseAddress()); return LLDB_RECORD_RESULT(sb_address); } @@ -66,7 +66,7 @@ SBAddress SBLineEntry::GetEndAddress() const { SBAddress sb_address; if (m_opaque_up) { - sb_address.SetAddress(&m_opaque_up->range.GetBaseAddress()); + sb_address.SetAddress(m_opaque_up->range.GetBaseAddress()); sb_address.OffsetAddress(m_opaque_up->range.GetByteSize()); } return LLDB_RECORD_RESULT(sb_address); diff --git a/gnu/llvm/lldb/source/API/SBListener.cpp b/gnu/llvm/lldb/source/API/SBListener.cpp index f3463268b3b..6e5e15de7b3 100644 --- a/gnu/llvm/lldb/source/API/SBListener.cpp +++ b/gnu/llvm/lldb/source/API/SBListener.cpp @@ -20,7 +20,7 @@ using namespace lldb; using namespace lldb_private; -SBListener::SBListener() : m_opaque_sp(), m_unused_ptr(nullptr) { +SBListener::SBListener() : m_opaque_sp() { LLDB_RECORD_CONSTRUCTOR_NO_ARGS(SBListener); } diff --git a/gnu/llvm/lldb/source/API/SBMemoryRegionInfo.cpp b/gnu/llvm/lldb/source/API/SBMemoryRegionInfo.cpp index 2a28b99c72d..ab74d559387 100644 --- a/gnu/llvm/lldb/source/API/SBMemoryRegionInfo.cpp +++ b/gnu/llvm/lldb/source/API/SBMemoryRegionInfo.cpp @@ -116,6 +116,42 @@ const char *SBMemoryRegionInfo::GetName() { return m_opaque_up->GetName().AsCString(); } +bool SBMemoryRegionInfo::HasDirtyMemoryPageList() { + LLDB_RECORD_METHOD_NO_ARGS(bool, SBMemoryRegionInfo, HasDirtyMemoryPageList); + + return m_opaque_up->GetDirtyPageList().hasValue(); +} + +uint32_t SBMemoryRegionInfo::GetNumDirtyPages() { + LLDB_RECORD_METHOD_NO_ARGS(uint32_t, SBMemoryRegionInfo, GetNumDirtyPages); + + uint32_t num_dirty_pages = 0; + llvm::Optional> dirty_page_list = + m_opaque_up->GetDirtyPageList(); + if (dirty_page_list.hasValue()) + num_dirty_pages = dirty_page_list.getValue().size(); + + return num_dirty_pages; +} + +addr_t SBMemoryRegionInfo::GetDirtyPageAddressAtIndex(uint32_t idx) { + LLDB_RECORD_METHOD(addr_t, SBMemoryRegionInfo, GetDirtyPageAddressAtIndex, + (uint32_t), idx); + + addr_t dirty_page_addr = LLDB_INVALID_ADDRESS; + const llvm::Optional> &dirty_page_list = + m_opaque_up->GetDirtyPageList(); + if (dirty_page_list.hasValue() && idx < dirty_page_list.getValue().size()) + dirty_page_addr = dirty_page_list.getValue()[idx]; + + return dirty_page_addr; +} + +int SBMemoryRegionInfo::GetPageSize() { + LLDB_RECORD_METHOD_NO_ARGS(int, SBMemoryRegionInfo, GetPageSize); + return m_opaque_up->GetPageSize(); +} + bool SBMemoryRegionInfo::GetDescription(SBStream &description) { LLDB_RECORD_METHOD(bool, SBMemoryRegionInfo, GetDescription, (lldb::SBStream &), description); diff --git a/gnu/llvm/lldb/source/API/SBModule.cpp b/gnu/llvm/lldb/source/API/SBModule.cpp index c30529b37eb..b5b9fe16aa6 100644 --- a/gnu/llvm/lldb/source/API/SBModule.cpp +++ b/gnu/llvm/lldb/source/API/SBModule.cpp @@ -67,8 +67,8 @@ SBModule::SBModule(lldb::SBProcess &process, lldb::addr_t header_addr) } const SBModule &SBModule::operator=(const SBModule &rhs) { - LLDB_RECORD_METHOD(const lldb::SBModule &, - SBModule, operator=,(const lldb::SBModule &), rhs); + LLDB_RECORD_METHOD(const lldb::SBModule &, SBModule, operator=, + (const lldb::SBModule &), rhs); if (this != &rhs) m_opaque_sp = rhs.m_opaque_sp; @@ -108,7 +108,6 @@ lldb::SBFileSpec SBModule::GetPlatformFileSpec() const { LLDB_RECORD_METHOD_CONST_NO_ARGS(lldb::SBFileSpec, SBModule, GetPlatformFileSpec); - SBFileSpec file_spec; ModuleSP module_sp(GetSP()); if (module_sp) @@ -187,7 +186,7 @@ const char *SBModule::GetUUIDString() const { } bool SBModule::operator==(const SBModule &rhs) const { - LLDB_RECORD_METHOD_CONST(bool, SBModule, operator==,(const lldb::SBModule &), + LLDB_RECORD_METHOD_CONST(bool, SBModule, operator==, (const lldb::SBModule &), rhs); if (m_opaque_sp) @@ -196,7 +195,7 @@ bool SBModule::operator==(const SBModule &rhs) const { } bool SBModule::operator!=(const SBModule &rhs) const { - LLDB_RECORD_METHOD_CONST(bool, SBModule, operator!=,(const lldb::SBModule &), + LLDB_RECORD_METHOD_CONST(bool, SBModule, operator!=, (const lldb::SBModule &), rhs); if (m_opaque_sp) @@ -625,7 +624,7 @@ uint32_t SBModule::GetVersion(uint32_t *versions, uint32_t num_versions) { ++result; if (version.getMinor()) ++result; - if(version.getSubminor()) + if (version.getSubminor()) ++result; if (!versions) @@ -690,17 +689,24 @@ uint32_t SBModule::GetNumberAllocatedModules() { return Module::GetNumberAllocatedModules(); } +void SBModule::GarbageCollectAllocatedModules() { + LLDB_RECORD_STATIC_METHOD_NO_ARGS(void, SBModule, + GarbageCollectAllocatedModules); + + const bool mandatory = false; + ModuleList::RemoveOrphanSharedModules(mandatory); +} + namespace lldb_private { namespace repro { -template <> -void RegisterMethods(Registry &R) { +template <> void RegisterMethods(Registry &R) { LLDB_REGISTER_CONSTRUCTOR(SBModule, ()); LLDB_REGISTER_CONSTRUCTOR(SBModule, (const lldb::SBModuleSpec &)); LLDB_REGISTER_CONSTRUCTOR(SBModule, (const lldb::SBModule &)); LLDB_REGISTER_CONSTRUCTOR(SBModule, (lldb::SBProcess &, lldb::addr_t)); - LLDB_REGISTER_METHOD(const lldb::SBModule &, - SBModule, operator=,(const lldb::SBModule &)); + LLDB_REGISTER_METHOD(const lldb::SBModule &, SBModule, operator=, + (const lldb::SBModule &)); LLDB_REGISTER_METHOD_CONST(bool, SBModule, IsValid, ()); LLDB_REGISTER_METHOD_CONST(bool, SBModule, operator bool, ()); LLDB_REGISTER_METHOD(void, SBModule, Clear, ()); @@ -714,10 +720,10 @@ void RegisterMethods(Registry &R) { LLDB_REGISTER_METHOD(bool, SBModule, SetRemoteInstallFileSpec, (lldb::SBFileSpec &)); LLDB_REGISTER_METHOD_CONST(const char *, SBModule, GetUUIDString, ()); - LLDB_REGISTER_METHOD_CONST(bool, - SBModule, operator==,(const lldb::SBModule &)); - LLDB_REGISTER_METHOD_CONST(bool, - SBModule, operator!=,(const lldb::SBModule &)); + LLDB_REGISTER_METHOD_CONST(bool, SBModule, operator==, + (const lldb::SBModule &)); + LLDB_REGISTER_METHOD_CONST(bool, SBModule, operator!=, + (const lldb::SBModule &)); LLDB_REGISTER_METHOD(lldb::SBAddress, SBModule, ResolveFileAddress, (lldb::addr_t)); LLDB_REGISTER_METHOD(lldb::SBSymbolContext, SBModule, @@ -736,8 +742,7 @@ void RegisterMethods(Registry &R) { LLDB_REGISTER_METHOD(lldb::SBSymbolContextList, SBModule, FindSymbols, (const char *, lldb::SymbolType)); LLDB_REGISTER_METHOD(size_t, SBModule, GetNumSections, ()); - LLDB_REGISTER_METHOD(lldb::SBSection, SBModule, GetSectionAtIndex, - (size_t)); + LLDB_REGISTER_METHOD(lldb::SBSection, SBModule, GetSectionAtIndex, (size_t)); LLDB_REGISTER_METHOD(lldb::SBSymbolContextList, SBModule, FindFunctions, (const char *, uint32_t)); LLDB_REGISTER_METHOD(lldb::SBValueList, SBModule, FindGlobalVariables, @@ -745,28 +750,25 @@ void RegisterMethods(Registry &R) { LLDB_REGISTER_METHOD(lldb::SBValue, SBModule, FindFirstGlobalVariable, (lldb::SBTarget &, const char *)); LLDB_REGISTER_METHOD(lldb::SBType, SBModule, FindFirstType, (const char *)); - LLDB_REGISTER_METHOD(lldb::SBType, SBModule, GetBasicType, - (lldb::BasicType)); + LLDB_REGISTER_METHOD(lldb::SBType, SBModule, GetBasicType, (lldb::BasicType)); LLDB_REGISTER_METHOD(lldb::SBTypeList, SBModule, FindTypes, (const char *)); - LLDB_REGISTER_METHOD(lldb::SBType, SBModule, GetTypeByID, - (lldb::user_id_t)); + LLDB_REGISTER_METHOD(lldb::SBType, SBModule, GetTypeByID, (lldb::user_id_t)); LLDB_REGISTER_METHOD(lldb::SBTypeList, SBModule, GetTypes, (uint32_t)); - LLDB_REGISTER_METHOD(lldb::SBSection, SBModule, FindSection, - (const char *)); + LLDB_REGISTER_METHOD(lldb::SBSection, SBModule, FindSection, (const char *)); LLDB_REGISTER_METHOD(lldb::ByteOrder, SBModule, GetByteOrder, ()); LLDB_REGISTER_METHOD(const char *, SBModule, GetTriple, ()); LLDB_REGISTER_METHOD(uint32_t, SBModule, GetAddressByteSize, ()); - LLDB_REGISTER_METHOD(uint32_t, SBModule, GetVersion, - (uint32_t *, uint32_t)); - LLDB_REGISTER_METHOD_CONST(lldb::SBFileSpec, SBModule, GetSymbolFileSpec, - ()); + LLDB_REGISTER_METHOD(uint32_t, SBModule, GetVersion, (uint32_t *, uint32_t)); + LLDB_REGISTER_METHOD_CONST(lldb::SBFileSpec, SBModule, GetSymbolFileSpec, ()); LLDB_REGISTER_METHOD_CONST(lldb::SBAddress, SBModule, GetObjectFileHeaderAddress, ()); LLDB_REGISTER_METHOD_CONST(lldb::SBAddress, SBModule, GetObjectFileEntryPointAddress, ()); LLDB_REGISTER_STATIC_METHOD(uint32_t, SBModule, GetNumberAllocatedModules, ()); + LLDB_REGISTER_STATIC_METHOD(void, SBModule, GarbageCollectAllocatedModules, + ()); } -} -} +} // namespace repro +} // namespace lldb_private diff --git a/gnu/llvm/lldb/source/API/SBPlatform.cpp b/gnu/llvm/lldb/source/API/SBPlatform.cpp index 7ac852488ff..496c40a0678 100644 --- a/gnu/llvm/lldb/source/API/SBPlatform.cpp +++ b/gnu/llvm/lldb/source/API/SBPlatform.cpp @@ -32,7 +32,7 @@ using namespace lldb_private; struct PlatformConnectOptions { PlatformConnectOptions(const char *url = nullptr) : m_url(), m_rsync_options(), m_rsync_remote_path_prefix(), - m_rsync_enabled(false), m_rsync_omit_hostname_from_remote_path(false), + m_local_cache_directory() { if (url && url[0]) m_url = url; @@ -43,26 +43,37 @@ struct PlatformConnectOptions { std::string m_url; std::string m_rsync_options; std::string m_rsync_remote_path_prefix; - bool m_rsync_enabled; - bool m_rsync_omit_hostname_from_remote_path; + bool m_rsync_enabled = false; + bool m_rsync_omit_hostname_from_remote_path = false; ConstString m_local_cache_directory; }; // PlatformShellCommand struct PlatformShellCommand { - PlatformShellCommand(const char *shell_command = nullptr) + PlatformShellCommand(llvm::StringRef shell_interpreter, + llvm::StringRef shell_command) : m_command(), m_working_dir(), m_status(0), m_signo(0) { - if (shell_command && shell_command[0]) - m_command = shell_command; + if (!shell_interpreter.empty()) + m_shell = shell_interpreter.str(); + + if (!m_shell.empty() && !shell_command.empty()) + m_command = shell_command.str(); + } + + PlatformShellCommand(llvm::StringRef shell_command = llvm::StringRef()) + : m_shell(), m_command(), m_working_dir() { + if (!shell_command.empty()) + m_command = shell_command.str(); } ~PlatformShellCommand() = default; + std::string m_shell; std::string m_command; std::string m_working_dir; std::string m_output; - int m_status; - int m_signo; + int m_status = 0; + int m_signo = 0; Timeout> m_timeout = llvm::None; }; // SBPlatformConnectOptions @@ -82,8 +93,8 @@ SBPlatformConnectOptions::SBPlatformConnectOptions( SBPlatformConnectOptions::~SBPlatformConnectOptions() { delete m_opaque_ptr; } -SBPlatformConnectOptions &SBPlatformConnectOptions:: -operator=(const SBPlatformConnectOptions &rhs) { +SBPlatformConnectOptions & +SBPlatformConnectOptions::operator=(const SBPlatformConnectOptions &rhs) { LLDB_RECORD_METHOD( SBPlatformConnectOptions &, SBPlatformConnectOptions, operator=,( @@ -163,6 +174,13 @@ void SBPlatformConnectOptions::SetLocalCacheDirectory(const char *path) { } // SBPlatformShellCommand +SBPlatformShellCommand::SBPlatformShellCommand(const char *shell_interpreter, + const char *shell_command) + : m_opaque_ptr(new PlatformShellCommand(shell_interpreter, shell_command)) { + LLDB_RECORD_CONSTRUCTOR(SBPlatformShellCommand, (const char *, const char *), + shell_interpreter, shell_command); +} + SBPlatformShellCommand::SBPlatformShellCommand(const char *shell_command) : m_opaque_ptr(new PlatformShellCommand(shell_command)) { LLDB_RECORD_CONSTRUCTOR(SBPlatformShellCommand, (const char *), @@ -178,8 +196,8 @@ SBPlatformShellCommand::SBPlatformShellCommand( *m_opaque_ptr = *rhs.m_opaque_ptr; } -SBPlatformShellCommand &SBPlatformShellCommand:: -operator=(const SBPlatformShellCommand &rhs) { +SBPlatformShellCommand & +SBPlatformShellCommand::operator=(const SBPlatformShellCommand &rhs) { LLDB_RECORD_METHOD( SBPlatformShellCommand &, @@ -200,6 +218,24 @@ void SBPlatformShellCommand::Clear() { m_opaque_ptr->m_signo = 0; } +const char *SBPlatformShellCommand::GetShell() { + LLDB_RECORD_METHOD_NO_ARGS(const char *, SBPlatformShellCommand, GetShell); + + if (m_opaque_ptr->m_shell.empty()) + return nullptr; + return m_opaque_ptr->m_shell.c_str(); +} + +void SBPlatformShellCommand::SetShell(const char *shell_interpreter) { + LLDB_RECORD_METHOD(void, SBPlatformShellCommand, SetShell, (const char *), + shell_interpreter); + + if (shell_interpreter && shell_interpreter[0]) + m_opaque_ptr->m_shell = shell_interpreter; + else + m_opaque_ptr->m_shell.clear(); +} + const char *SBPlatformShellCommand::GetCommand() { LLDB_RECORD_METHOD_NO_ARGS(const char *, SBPlatformShellCommand, GetCommand); @@ -377,8 +413,7 @@ SBError SBPlatform::ConnectRemote(SBPlatformConnectOptions &connect_options) { PlatformSP platform_sp(GetSP()); if (platform_sp && connect_options.GetURL()) { Args args; - args.AppendArgument( - llvm::StringRef::withNullAsEmpty(connect_options.GetURL())); + args.AppendArgument(connect_options.GetURL()); sb_error.ref() = platform_sp->ConnectRemote(args); } else { sb_error.SetErrorString("invalid platform"); @@ -545,24 +580,25 @@ SBError SBPlatform::Install(SBFileSpec &src, SBFileSpec &dst) { SBError SBPlatform::Run(SBPlatformShellCommand &shell_command) { LLDB_RECORD_METHOD(lldb::SBError, SBPlatform, Run, (lldb::SBPlatformShellCommand &), shell_command); - return LLDB_RECORD_RESULT(ExecuteConnected([&](const lldb::PlatformSP - &platform_sp) { - const char *command = shell_command.GetCommand(); - if (!command) - return Status("invalid shell command (empty)"); - - const char *working_dir = shell_command.GetWorkingDirectory(); - if (working_dir == nullptr) { - working_dir = platform_sp->GetWorkingDirectory().GetCString(); - if (working_dir) - shell_command.SetWorkingDirectory(working_dir); - } - return platform_sp->RunShellCommand(command, FileSpec(working_dir), - &shell_command.m_opaque_ptr->m_status, - &shell_command.m_opaque_ptr->m_signo, - &shell_command.m_opaque_ptr->m_output, - shell_command.m_opaque_ptr->m_timeout); - })); + return LLDB_RECORD_RESULT( + ExecuteConnected([&](const lldb::PlatformSP &platform_sp) { + const char *command = shell_command.GetCommand(); + if (!command) + return Status("invalid shell command (empty)"); + + const char *working_dir = shell_command.GetWorkingDirectory(); + if (working_dir == nullptr) { + working_dir = platform_sp->GetWorkingDirectory().GetCString(); + if (working_dir) + shell_command.SetWorkingDirectory(working_dir); + } + return platform_sp->RunShellCommand( + shell_command.m_opaque_ptr->m_shell, command, FileSpec(working_dir), + &shell_command.m_opaque_ptr->m_status, + &shell_command.m_opaque_ptr->m_signo, + &shell_command.m_opaque_ptr->m_output, + shell_command.m_opaque_ptr->m_timeout); + })); } SBError SBPlatform::Launch(SBLaunchInfo &launch_info) { @@ -668,8 +704,7 @@ SBEnvironment SBPlatform::GetEnvironment() { namespace lldb_private { namespace repro { -template <> -void RegisterMethods(Registry &R) { +template <> void RegisterMethods(Registry &R) { LLDB_REGISTER_CONSTRUCTOR(SBPlatformConnectOptions, (const char *)); LLDB_REGISTER_CONSTRUCTOR(SBPlatformConnectOptions, (const lldb::SBPlatformConnectOptions &)); @@ -678,8 +713,7 @@ void RegisterMethods(Registry &R) { SBPlatformConnectOptions, operator=,( const lldb::SBPlatformConnectOptions &)); LLDB_REGISTER_METHOD(const char *, SBPlatformConnectOptions, GetURL, ()); - LLDB_REGISTER_METHOD(void, SBPlatformConnectOptions, SetURL, - (const char *)); + LLDB_REGISTER_METHOD(void, SBPlatformConnectOptions, SetURL, (const char *)); LLDB_REGISTER_METHOD(bool, SBPlatformConnectOptions, GetRsyncEnabled, ()); LLDB_REGISTER_METHOD(void, SBPlatformConnectOptions, EnableRsync, (const char *, const char *, bool)); @@ -690,8 +724,7 @@ void RegisterMethods(Registry &R) { (const char *)); } -template <> -void RegisterMethods(Registry &R) { +template <> void RegisterMethods(Registry &R) { LLDB_REGISTER_CONSTRUCTOR(SBPlatformShellCommand, (const char *)); LLDB_REGISTER_CONSTRUCTOR(SBPlatformShellCommand, (const lldb::SBPlatformShellCommand &)); @@ -699,6 +732,8 @@ void RegisterMethods(Registry &R) { SBPlatformShellCommand &, SBPlatformShellCommand, operator=,(const lldb::SBPlatformShellCommand &)); LLDB_REGISTER_METHOD(void, SBPlatformShellCommand, Clear, ()); + LLDB_REGISTER_METHOD(const char *, SBPlatformShellCommand, GetShell, ()); + LLDB_REGISTER_METHOD(void, SBPlatformShellCommand, SetShell, (const char *)); LLDB_REGISTER_METHOD(const char *, SBPlatformShellCommand, GetCommand, ()); LLDB_REGISTER_METHOD(void, SBPlatformShellCommand, SetCommand, (const char *)); @@ -706,8 +741,7 @@ void RegisterMethods(Registry &R) { GetWorkingDirectory, ()); LLDB_REGISTER_METHOD(void, SBPlatformShellCommand, SetWorkingDirectory, (const char *)); - LLDB_REGISTER_METHOD(uint32_t, SBPlatformShellCommand, GetTimeoutSeconds, - ()); + LLDB_REGISTER_METHOD(uint32_t, SBPlatformShellCommand, GetTimeoutSeconds, ()); LLDB_REGISTER_METHOD(void, SBPlatformShellCommand, SetTimeoutSeconds, (uint32_t)); LLDB_REGISTER_METHOD(int, SBPlatformShellCommand, GetSignal, ()); @@ -715,15 +749,16 @@ void RegisterMethods(Registry &R) { LLDB_REGISTER_METHOD(const char *, SBPlatformShellCommand, GetOutput, ()); } -template <> -void RegisterMethods(Registry &R) { +template <> void RegisterMethods(Registry &R) { LLDB_REGISTER_CONSTRUCTOR(SBPlatform, ()); LLDB_REGISTER_CONSTRUCTOR(SBPlatform, (const char *)); LLDB_REGISTER_CONSTRUCTOR(SBPlatform, (const lldb::SBPlatform &)); + LLDB_REGISTER_CONSTRUCTOR(SBPlatformShellCommand, + (const char *, const char *)); LLDB_REGISTER_METHOD(SBPlatform &, SBPlatform, operator=,(const lldb::SBPlatform &)); LLDB_REGISTER_METHOD_CONST(bool, SBPlatform, IsValid, ()); - LLDB_REGISTER_METHOD_CONST(bool, SBPlatform, operator bool, ()); + LLDB_REGISTER_METHOD_CONST(bool, SBPlatform, operator bool,()); LLDB_REGISTER_METHOD(void, SBPlatform, Clear, ()); LLDB_REGISTER_METHOD(const char *, SBPlatform, GetName, ()); LLDB_REGISTER_METHOD(const char *, SBPlatform, GetWorkingDirectory, ()); @@ -763,5 +798,5 @@ void RegisterMethods(Registry &R) { ()); } -} -} +} // namespace repro +} // namespace lldb_private diff --git a/gnu/llvm/lldb/source/API/SBProcess.cpp b/gnu/llvm/lldb/source/API/SBProcess.cpp index d7b7fd7caca..47c35a23b07 100644 --- a/gnu/llvm/lldb/source/API/SBProcess.cpp +++ b/gnu/llvm/lldb/source/API/SBProcess.cpp @@ -9,7 +9,7 @@ #include "lldb/API/SBProcess.h" #include "SBReproducerPrivate.h" -#include +#include #include "lldb/lldb-defines.h" #include "lldb/lldb-types.h" @@ -44,7 +44,6 @@ #include "lldb/API/SBThread.h" #include "lldb/API/SBThreadCollection.h" #include "lldb/API/SBTrace.h" -#include "lldb/API/SBTraceOptions.h" #include "lldb/API/SBUnixSignals.h" using namespace lldb; @@ -312,26 +311,6 @@ size_t SBProcess::GetAsyncProfileData(char *dst, size_t dst_len) const { return bytes_read; } -lldb::SBTrace SBProcess::StartTrace(SBTraceOptions &options, - lldb::SBError &error) { - LLDB_RECORD_METHOD(lldb::SBTrace, SBProcess, StartTrace, - (lldb::SBTraceOptions &, lldb::SBError &), options, error); - - ProcessSP process_sp(GetSP()); - error.Clear(); - SBTrace trace_instance; - trace_instance.SetSP(process_sp); - lldb::user_id_t uid = LLDB_INVALID_UID; - - if (!process_sp) { - error.SetErrorString("invalid process"); - } else { - uid = process_sp->StartTrace(*(options.m_traceoptions_sp), error.ref()); - trace_instance.SetTraceUID(uid); - } - return LLDB_RECORD_RESULT(trace_instance); -} - void SBProcess::ReportEventState(const SBEvent &event, SBFile out) const { LLDB_RECORD_METHOD_CONST(void, SBProcess, ReportEventState, (const SBEvent &, SBFile), event, out); @@ -1248,7 +1227,8 @@ lldb::SBError SBProcess::SaveCore(const char *file_name) { } FileSpec core_file(file_name); - error.ref() = PluginManager::SaveCore(process_sp, core_file); + SaveCoreStyle core_style = SaveCoreStyle::eSaveCoreFull; + error.ref() = PluginManager::SaveCore(process_sp, core_file, core_style); return LLDB_RECORD_RESULT(error); } @@ -1308,6 +1288,51 @@ lldb::SBProcessInfo SBProcess::GetProcessInfo() { return LLDB_RECORD_RESULT(sb_proc_info); } +lldb::addr_t SBProcess::AllocateMemory(size_t size, uint32_t permissions, + lldb::SBError &sb_error) { + LLDB_RECORD_METHOD(lldb::addr_t, SBProcess, AllocateMemory, + (size_t, uint32_t, lldb::SBError &), size, permissions, + sb_error); + + lldb::addr_t addr = LLDB_INVALID_ADDRESS; + ProcessSP process_sp(GetSP()); + if (process_sp) { + Process::StopLocker stop_locker; + if (stop_locker.TryLock(&process_sp->GetRunLock())) { + std::lock_guard guard( + process_sp->GetTarget().GetAPIMutex()); + addr = process_sp->AllocateMemory(size, permissions, sb_error.ref()); + } else { + sb_error.SetErrorString("process is running"); + } + } else { + sb_error.SetErrorString("SBProcess is invalid"); + } + return addr; +} + +lldb::SBError SBProcess::DeallocateMemory(lldb::addr_t ptr) { + LLDB_RECORD_METHOD(lldb::SBError, SBProcess, DeallocateMemory, (lldb::addr_t), + ptr); + + lldb::SBError sb_error; + ProcessSP process_sp(GetSP()); + if (process_sp) { + Process::StopLocker stop_locker; + if (stop_locker.TryLock(&process_sp->GetRunLock())) { + std::lock_guard guard( + process_sp->GetTarget().GetAPIMutex()); + Status error = process_sp->DeallocateMemory(ptr); + sb_error.SetError(error); + } else { + sb_error.SetErrorString("process is running"); + } + } else { + sb_error.SetErrorString("SBProcess is invalid"); + } + return sb_error; +} + namespace lldb_private { namespace repro { @@ -1338,8 +1363,6 @@ void RegisterMethods(Registry &R) { (lldb::tid_t, lldb::addr_t)); LLDB_REGISTER_METHOD_CONST(lldb::SBTarget, SBProcess, GetTarget, ()); LLDB_REGISTER_METHOD(size_t, SBProcess, PutSTDIN, (const char *, size_t)); - LLDB_REGISTER_METHOD(lldb::SBTrace, SBProcess, StartTrace, - (lldb::SBTraceOptions &, lldb::SBError &)); LLDB_REGISTER_METHOD_CONST(void, SBProcess, ReportEventState, (const lldb::SBEvent &, FILE *)); LLDB_REGISTER_METHOD_CONST(void, SBProcess, ReportEventState, @@ -1439,6 +1462,10 @@ void RegisterMethods(Registry &R) { LLDB_REGISTER_METHOD(lldb::SBMemoryRegionInfoList, SBProcess, GetMemoryRegions, ()); LLDB_REGISTER_METHOD(lldb::SBProcessInfo, SBProcess, GetProcessInfo, ()); + LLDB_REGISTER_METHOD(lldb::addr_t, SBProcess, AllocateMemory, + (size_t, uint32_t, lldb::SBError &)); + LLDB_REGISTER_METHOD(lldb::SBError, SBProcess, DeallocateMemory, + (lldb::addr_t)); LLDB_REGISTER_CHAR_PTR_METHOD_CONST(size_t, SBProcess, GetSTDOUT); LLDB_REGISTER_CHAR_PTR_METHOD_CONST(size_t, SBProcess, GetSTDERR); diff --git a/gnu/llvm/lldb/source/API/SBProcessInfo.cpp b/gnu/llvm/lldb/source/API/SBProcessInfo.cpp index 29a9c7b24b5..cba3bdc179f 100644 --- a/gnu/llvm/lldb/source/API/SBProcessInfo.cpp +++ b/gnu/llvm/lldb/source/API/SBProcessInfo.cpp @@ -179,6 +179,21 @@ lldb::pid_t SBProcessInfo::GetParentProcessID() { return proc_id; } +const char *SBProcessInfo::GetTriple() { + LLDB_RECORD_METHOD_NO_ARGS(const char *, SBProcessInfo, GetTriple); + + const char *triple = nullptr; + if (m_opaque_up) { + const auto &arch = m_opaque_up->GetArchitecture(); + if (arch.IsValid()) { + // Const-ify the string so we don't need to worry about the lifetime of + // the string + triple = ConstString(arch.GetTriple().getTriple().c_str()).GetCString(); + } + } + return triple; +} + namespace lldb_private { namespace repro { @@ -204,6 +219,7 @@ void RegisterMethods(Registry &R) { LLDB_REGISTER_METHOD(bool, SBProcessInfo, EffectiveUserIDIsValid, ()); LLDB_REGISTER_METHOD(bool, SBProcessInfo, EffectiveGroupIDIsValid, ()); LLDB_REGISTER_METHOD(lldb::pid_t, SBProcessInfo, GetParentProcessID, ()); + LLDB_REGISTER_METHOD(const char *, SBProcessInfo, GetTriple, ()); } } diff --git a/gnu/llvm/lldb/source/API/SBQueue.cpp b/gnu/llvm/lldb/source/API/SBQueue.cpp index 2e6571392ea..746df9e79d6 100644 --- a/gnu/llvm/lldb/source/API/SBQueue.cpp +++ b/gnu/llvm/lldb/source/API/SBQueue.cpp @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// -#include +#include #include "SBReproducerPrivate.h" #include "lldb/API/SBQueue.h" @@ -27,9 +27,7 @@ namespace lldb_private { class QueueImpl { public: - QueueImpl() - : m_queue_wp(), m_threads(), m_thread_list_fetched(false), - m_pending_items(), m_pending_items_fetched(false) {} + QueueImpl() : m_queue_wp(), m_threads(), m_pending_items() {} QueueImpl(const lldb::QueueSP &queue_sp) : m_queue_wp(), m_threads(), m_thread_list_fetched(false), @@ -210,10 +208,11 @@ private: lldb::QueueWP m_queue_wp; std::vector m_threads; // threads currently executing this queue's items - bool - m_thread_list_fetched; // have we tried to fetch the threads list already? + bool m_thread_list_fetched = + false; // have we tried to fetch the threads list already? std::vector m_pending_items; // items currently enqueued - bool m_pending_items_fetched; // have we tried to fetch the item list already? + bool m_pending_items_fetched = + false; // have we tried to fetch the item list already? }; } diff --git a/gnu/llvm/lldb/source/API/SBQueueItem.cpp b/gnu/llvm/lldb/source/API/SBQueueItem.cpp index 0f92e2e0412..6cd9e4514ca 100644 --- a/gnu/llvm/lldb/source/API/SBQueueItem.cpp +++ b/gnu/llvm/lldb/source/API/SBQueueItem.cpp @@ -80,7 +80,7 @@ SBAddress SBQueueItem::GetAddress() const { SBAddress result; if (m_queue_item_sp) { - result.SetAddress(&m_queue_item_sp->GetAddress()); + result.SetAddress(m_queue_item_sp->GetAddress()); } return LLDB_RECORD_RESULT(result); } diff --git a/gnu/llvm/lldb/source/API/SBReproducer.cpp b/gnu/llvm/lldb/source/API/SBReproducer.cpp index 0eb3429c4fe..68e632da1bd 100644 --- a/gnu/llvm/lldb/source/API/SBReproducer.cpp +++ b/gnu/llvm/lldb/source/API/SBReproducer.cpp @@ -8,7 +8,6 @@ #include "SBReproducerPrivate.h" -#include "SBReproducerPrivate.h" #include "lldb/API/LLDB.h" #include "lldb/API/SBAddress.h" #include "lldb/API/SBAttachInfo.h" @@ -30,6 +29,33 @@ using namespace lldb; using namespace lldb_private; using namespace lldb_private::repro; +SBReplayOptions::SBReplayOptions() + : m_opaque_up(std::make_unique()){} + +SBReplayOptions::SBReplayOptions(const SBReplayOptions &rhs) + : m_opaque_up(std::make_unique(*rhs.m_opaque_up)) {} + +SBReplayOptions::~SBReplayOptions() = default; + +SBReplayOptions &SBReplayOptions::operator=(const SBReplayOptions &rhs) { + if (this == &rhs) + return *this; + *m_opaque_up = *rhs.m_opaque_up; + return *this; +} + +void SBReplayOptions::SetVerify(bool verify) { m_opaque_up->verify = verify; } + +bool SBReplayOptions::GetVerify() const { return m_opaque_up->verify; } + +void SBReplayOptions::SetCheckVersion(bool check) { + m_opaque_up->check_version = check; +} + +bool SBReplayOptions::GetCheckVersion() const { + return m_opaque_up->check_version; +} + SBRegistry::SBRegistry() { Registry &R = *this; @@ -91,7 +117,6 @@ SBRegistry::SBRegistry() { RegisterMethods(R); RegisterMethods(R); RegisterMethods(R); - RegisterMethods(R); RegisterMethods(R); RegisterMethods(R); RegisterMethods(R); @@ -163,10 +188,18 @@ const char *SBReproducer::PassiveReplay(const char *path) { } const char *SBReproducer::Replay(const char *path) { - return SBReproducer::Replay(path, false); + SBReplayOptions options; + return SBReproducer::Replay(path, options); } const char *SBReproducer::Replay(const char *path, bool skip_version_check) { + SBReplayOptions options; + options.SetCheckVersion(!skip_version_check); + return SBReproducer::Replay(path, options); +} + +const char *SBReproducer::Replay(const char *path, + const SBReplayOptions &options) { static std::string error; if (auto e = Reproducer::Initialize(ReproducerMode::Replay, FileSpec(path))) { error = llvm::toString(std::move(e)); @@ -179,7 +212,7 @@ const char *SBReproducer::Replay(const char *path, bool skip_version_check) { return error.c_str(); } - if (!skip_version_check) { + if (options.GetCheckVersion()) { llvm::Expected version = loader->LoadBuffer(); if (!version) { error = llvm::toString(version.takeError()); @@ -195,6 +228,30 @@ const char *SBReproducer::Replay(const char *path, bool skip_version_check) { } } + if (options.GetVerify()) { + bool verification_failed = false; + llvm::raw_string_ostream os(error); + auto error_callback = [&](llvm::StringRef error) { + verification_failed = true; + os << "\nerror: " << error; + }; + + auto warning_callback = [&](llvm::StringRef warning) { + verification_failed = true; + os << "\nwarning: " << warning; + }; + + auto note_callback = [&](llvm::StringRef warning) {}; + + Verifier verifier(loader); + verifier.Verify(error_callback, warning_callback, note_callback); + + if (verification_failed) { + os.flush(); + return error.c_str(); + } + } + FileSpec file = loader->GetFile(); if (!file) { error = "unable to get replay data from reproducer."; @@ -207,6 +264,27 @@ const char *SBReproducer::Replay(const char *path, bool skip_version_check) { return nullptr; } +const char *SBReproducer::Finalize(const char *path) { + static std::string error; + if (auto e = Reproducer::Initialize(ReproducerMode::Replay, FileSpec(path))) { + error = llvm::toString(std::move(e)); + return error.c_str(); + } + + repro::Loader *loader = repro::Reproducer::Instance().GetLoader(); + if (!loader) { + error = "unable to get replay loader."; + return error.c_str(); + } + + if (auto e = repro::Finalize(loader)) { + error = llvm::toString(std::move(e)); + return error.c_str(); + } + + return nullptr; +} + bool SBReproducer::Generate() { auto &r = Reproducer::Instance(); if (auto generator = r.GetGenerator()) { @@ -226,15 +304,19 @@ bool SBReproducer::SetAutoGenerate(bool b) { } const char *SBReproducer::GetPath() { - static std::string path; + ConstString path; auto &r = Reproducer::Instance(); - path = r.GetReproducerPath().GetCString(); - return path.c_str(); + if (FileSpec reproducer_path = Reproducer::Instance().GetReproducerPath()) + path = ConstString(r.GetReproducerPath().GetCString()); + return path.GetCString(); } void SBReproducer::SetWorkingDirectory(const char *path) { if (auto *g = lldb_private::repro::Reproducer::Instance().GetGenerator()) { - g->GetOrCreate().Update(path); + auto &wp = g->GetOrCreate(); + wp.SetDirectory(path); + auto &fp = g->GetOrCreate(); + fp.RecordInterestingDirectory(wp.GetDirectory()); } } diff --git a/gnu/llvm/lldb/source/API/SBReproducerPrivate.h b/gnu/llvm/lldb/source/API/SBReproducerPrivate.h index a4c6eb94627..02ac31c2ad8 100644 --- a/gnu/llvm/lldb/source/API/SBReproducerPrivate.h +++ b/gnu/llvm/lldb/source/API/SBReproducerPrivate.h @@ -16,6 +16,7 @@ #include "lldb/Utility/Log.h" #include "lldb/Utility/Reproducer.h" #include "lldb/Utility/ReproducerInstrumentation.h" +#include "lldb/Utility/ReproducerProvider.h" #include "llvm/ADT/DenseMap.h" diff --git a/gnu/llvm/lldb/source/API/SBStream.cpp b/gnu/llvm/lldb/source/API/SBStream.cpp index eb81153084e..66172d248bf 100644 --- a/gnu/llvm/lldb/source/API/SBStream.cpp +++ b/gnu/llvm/lldb/source/API/SBStream.cpp @@ -19,7 +19,7 @@ using namespace lldb; using namespace lldb_private; -SBStream::SBStream() : m_opaque_up(new StreamString()), m_is_file(false) { +SBStream::SBStream() : m_opaque_up(new StreamString()) { LLDB_RECORD_CONSTRUCTOR_NO_ARGS(SBStream); } diff --git a/gnu/llvm/lldb/source/API/SBStructuredData.cpp b/gnu/llvm/lldb/source/API/SBStructuredData.cpp index 2ae3005fd8d..97a9eadcaf0 100644 --- a/gnu/llvm/lldb/source/API/SBStructuredData.cpp +++ b/gnu/llvm/lldb/source/API/SBStructuredData.cpp @@ -29,7 +29,7 @@ SBStructuredData::SBStructuredData() : m_impl_up(new StructuredDataImpl()) { } SBStructuredData::SBStructuredData(const lldb::SBStructuredData &rhs) - : m_impl_up(new StructuredDataImpl(*rhs.m_impl_up.get())) { + : m_impl_up(new StructuredDataImpl(*rhs.m_impl_up)) { LLDB_RECORD_CONSTRUCTOR(SBStructuredData, (const lldb::SBStructuredData &), rhs); } @@ -40,7 +40,7 @@ SBStructuredData::SBStructuredData(const lldb::EventSP &event_sp) } SBStructuredData::SBStructuredData(lldb_private::StructuredDataImpl *impl) - : m_impl_up(impl) { + : m_impl_up(impl ? impl : new StructuredDataImpl()) { LLDB_RECORD_CONSTRUCTOR(SBStructuredData, (lldb_private::StructuredDataImpl *), impl); } @@ -72,10 +72,19 @@ lldb::SBError SBStructuredData::SetFromJSON(lldb::SBStream &stream) { return LLDB_RECORD_RESULT(error); } +lldb::SBError SBStructuredData::SetFromJSON(const char *json) { + LLDB_RECORD_METHOD(lldb::SBError, SBStructuredData, SetFromJSON, + (const char *), json); + lldb::SBStream s; + s.Print(json); + return LLDB_RECORD_RESULT(SetFromJSON(s)); +} + bool SBStructuredData::IsValid() const { LLDB_RECORD_METHOD_CONST_NO_ARGS(bool, SBStructuredData, IsValid); return this->operator bool(); } + SBStructuredData::operator bool() const { LLDB_RECORD_METHOD_CONST_NO_ARGS(bool, SBStructuredData, operator bool); @@ -111,22 +120,19 @@ StructuredDataType SBStructuredData::GetType() const { LLDB_RECORD_METHOD_CONST_NO_ARGS(lldb::StructuredDataType, SBStructuredData, GetType); - return (m_impl_up ? m_impl_up->GetType() : eStructuredDataTypeInvalid); + return m_impl_up->GetType(); } size_t SBStructuredData::GetSize() const { LLDB_RECORD_METHOD_CONST_NO_ARGS(size_t, SBStructuredData, GetSize); - return (m_impl_up ? m_impl_up->GetSize() : 0); + return m_impl_up->GetSize(); } bool SBStructuredData::GetKeys(lldb::SBStringList &keys) const { LLDB_RECORD_METHOD_CONST(bool, SBStructuredData, GetKeys, (lldb::SBStringList &), keys); - if (!m_impl_up) - return false; - if (GetType() != eStructuredDataTypeDictionary) return false; @@ -154,9 +160,6 @@ lldb::SBStructuredData SBStructuredData::GetValueForKey(const char *key) const { LLDB_RECORD_METHOD_CONST(lldb::SBStructuredData, SBStructuredData, GetValueForKey, (const char *), key); - if (!m_impl_up) - return LLDB_RECORD_RESULT(SBStructuredData()); - SBStructuredData result; result.m_impl_up->SetObjectSP(m_impl_up->GetValueForKey(key)); return LLDB_RECORD_RESULT(result); @@ -166,9 +169,6 @@ lldb::SBStructuredData SBStructuredData::GetItemAtIndex(size_t idx) const { LLDB_RECORD_METHOD_CONST(lldb::SBStructuredData, SBStructuredData, GetItemAtIndex, (size_t), idx); - if (!m_impl_up) - return LLDB_RECORD_RESULT(SBStructuredData()); - SBStructuredData result; result.m_impl_up->SetObjectSP(m_impl_up->GetItemAtIndex(idx)); return LLDB_RECORD_RESULT(result); @@ -178,28 +178,28 @@ uint64_t SBStructuredData::GetIntegerValue(uint64_t fail_value) const { LLDB_RECORD_METHOD_CONST(uint64_t, SBStructuredData, GetIntegerValue, (uint64_t), fail_value); - return (m_impl_up ? m_impl_up->GetIntegerValue(fail_value) : fail_value); + return m_impl_up->GetIntegerValue(fail_value); } double SBStructuredData::GetFloatValue(double fail_value) const { LLDB_RECORD_METHOD_CONST(double, SBStructuredData, GetFloatValue, (double), fail_value); - return (m_impl_up ? m_impl_up->GetFloatValue(fail_value) : fail_value); + return m_impl_up->GetFloatValue(fail_value); } bool SBStructuredData::GetBooleanValue(bool fail_value) const { LLDB_RECORD_METHOD_CONST(bool, SBStructuredData, GetBooleanValue, (bool), fail_value); - return (m_impl_up ? m_impl_up->GetBooleanValue(fail_value) : fail_value); + return m_impl_up->GetBooleanValue(fail_value); } size_t SBStructuredData::GetStringValue(char *dst, size_t dst_len) const { LLDB_RECORD_CHAR_PTR_METHOD_CONST(size_t, SBStructuredData, GetStringValue, (char *, size_t), dst, "", dst_len); - return (m_impl_up ? m_impl_up->GetStringValue(dst, dst_len) : 0); + return m_impl_up->GetStringValue(dst, dst_len); } namespace lldb_private { @@ -216,6 +216,8 @@ template <> void RegisterMethods(Registry &R) { SBStructuredData, operator=,(const lldb::SBStructuredData &)); LLDB_REGISTER_METHOD(lldb::SBError, SBStructuredData, SetFromJSON, (lldb::SBStream &)); + LLDB_REGISTER_METHOD(lldb::SBError, SBStructuredData, SetFromJSON, + (const char *)); LLDB_REGISTER_METHOD_CONST(bool, SBStructuredData, IsValid, ()); LLDB_REGISTER_METHOD_CONST(bool, SBStructuredData, operator bool, ()); LLDB_REGISTER_METHOD(void, SBStructuredData, Clear, ()); diff --git a/gnu/llvm/lldb/source/API/SBSymbol.cpp b/gnu/llvm/lldb/source/API/SBSymbol.cpp index e4f2f351827..d3abc13675f 100644 --- a/gnu/llvm/lldb/source/API/SBSymbol.cpp +++ b/gnu/llvm/lldb/source/API/SBSymbol.cpp @@ -18,9 +18,7 @@ using namespace lldb; using namespace lldb_private; -SBSymbol::SBSymbol() : m_opaque_ptr(nullptr) { - LLDB_RECORD_CONSTRUCTOR_NO_ARGS(SBSymbol); -} +SBSymbol::SBSymbol() { LLDB_RECORD_CONSTRUCTOR_NO_ARGS(SBSymbol); } SBSymbol::SBSymbol(lldb_private::Symbol *lldb_object_ptr) : m_opaque_ptr(lldb_object_ptr) {} @@ -132,10 +130,10 @@ SBInstructionList SBSymbol::GetInstructions(SBTarget target, ModuleSP module_sp = symbol_addr.GetModule(); if (module_sp) { AddressRange symbol_range(symbol_addr, m_opaque_ptr->GetByteSize()); - const bool prefer_file_cache = false; + const bool force_live_memory = true; sb_instructions.SetDisassembler(Disassembler::DisassembleRange( module_sp->GetArchitecture(), nullptr, flavor_string, *target_sp, - symbol_range, prefer_file_cache)); + symbol_range, force_live_memory)); } } } @@ -151,7 +149,7 @@ SBAddress SBSymbol::GetStartAddress() { SBAddress addr; if (m_opaque_ptr && m_opaque_ptr->ValueIsAddress()) { - addr.SetAddress(&m_opaque_ptr->GetAddressRef()); + addr.SetAddress(m_opaque_ptr->GetAddressRef()); } return LLDB_RECORD_RESULT(addr); } @@ -163,7 +161,7 @@ SBAddress SBSymbol::GetEndAddress() { if (m_opaque_ptr && m_opaque_ptr->ValueIsAddress()) { lldb::addr_t range_size = m_opaque_ptr->GetByteSize(); if (range_size > 0) { - addr.SetAddress(&m_opaque_ptr->GetAddressRef()); + addr.SetAddress(m_opaque_ptr->GetAddressRef()); addr->Slide(m_opaque_ptr->GetByteSize()); } } diff --git a/gnu/llvm/lldb/source/API/SBTarget.cpp b/gnu/llvm/lldb/source/API/SBTarget.cpp index b84e9f10faf..6f0633288a2 100644 --- a/gnu/llvm/lldb/source/API/SBTarget.cpp +++ b/gnu/llvm/lldb/source/API/SBTarget.cpp @@ -26,13 +26,13 @@ #include "lldb/API/SBStringList.h" #include "lldb/API/SBStructuredData.h" #include "lldb/API/SBSymbolContextList.h" +#include "lldb/API/SBTrace.h" #include "lldb/Breakpoint/BreakpointID.h" #include "lldb/Breakpoint/BreakpointIDList.h" #include "lldb/Breakpoint/BreakpointList.h" #include "lldb/Breakpoint/BreakpointLocation.h" #include "lldb/Core/Address.h" #include "lldb/Core/AddressResolver.h" -#include "lldb/Core/AddressResolverName.h" #include "lldb/Core/Debugger.h" #include "lldb/Core/Disassembler.h" #include "lldb/Core/Module.h" @@ -267,7 +267,7 @@ SBProcess SBTarget::LoadCore(const char *core_file, lldb::SBError &error) { FileSpec filespec(core_file); FileSystem::Instance().Resolve(filespec); ProcessSP process_sp(target_sp->CreateProcess( - target_sp->GetDebugger().GetListener(), "", &filespec)); + target_sp->GetDebugger().GetListener(), "", &filespec, false)); if (process_sp) { error.SetError(process_sp->LoadCore()); if (error.Success()) @@ -287,16 +287,24 @@ SBProcess SBTarget::LaunchSimple(char const **argv, char const **envp, (const char **, const char **, const char *), argv, envp, working_directory); - char *stdin_path = nullptr; - char *stdout_path = nullptr; - char *stderr_path = nullptr; - uint32_t launch_flags = 0; - bool stop_at_entry = false; + TargetSP target_sp = GetSP(); + if (!target_sp) + return LLDB_RECORD_RESULT(SBProcess()); + + SBLaunchInfo launch_info = GetLaunchInfo(); + + if (Module *exe_module = target_sp->GetExecutableModulePointer()) + launch_info.SetExecutableFile(exe_module->GetPlatformFileSpec(), + /*add_as_first_arg*/ true); + if (argv) + launch_info.SetArguments(argv, /*append*/ true); + if (envp) + launch_info.SetEnvironmentEntries(envp, /*append*/ false); + if (working_directory) + launch_info.SetWorkingDirectory(working_directory); + SBError error; - SBListener listener = GetDebugger().GetListener(); - return LLDB_RECORD_RESULT(Launch(listener, argv, envp, stdin_path, - stdout_path, stderr_path, working_directory, - launch_flags, stop_at_entry, error)); + return LLDB_RECORD_RESULT(Launch(launch_info, error)); } SBError SBTarget::Install() { @@ -559,10 +567,11 @@ lldb::SBProcess SBTarget::ConnectRemote(SBListener &listener, const char *url, std::lock_guard guard(target_sp->GetAPIMutex()); if (listener.IsValid()) process_sp = - target_sp->CreateProcess(listener.m_opaque_sp, plugin_name, nullptr); + target_sp->CreateProcess(listener.m_opaque_sp, plugin_name, nullptr, + true); else process_sp = target_sp->CreateProcess( - target_sp->GetDebugger().GetListener(), plugin_name, nullptr); + target_sp->GetDebugger().GetListener(), plugin_name, nullptr, true); if (process_sp) { sb_process.SetSP(process_sp); @@ -697,7 +706,7 @@ size_t SBTarget::ReadMemory(const SBAddress addr, void *buf, size_t size, if (target_sp) { std::lock_guard guard(target_sp->GetAPIMutex()); bytes_read = - target_sp->ReadMemory(addr.ref(), false, buf, size, sb_error.ref()); + target_sp->ReadMemory(addr.ref(), buf, size, sb_error.ref(), true); } else { sb_error.SetErrorString("invalid target"); } @@ -778,6 +787,38 @@ SBBreakpoint SBTarget::BreakpointCreateByLocation( return LLDB_RECORD_RESULT(sb_bp); } +SBBreakpoint SBTarget::BreakpointCreateByLocation( + const SBFileSpec &sb_file_spec, uint32_t line, uint32_t column, + lldb::addr_t offset, SBFileSpecList &sb_module_list, + bool move_to_nearest_code) { + LLDB_RECORD_METHOD(lldb::SBBreakpoint, SBTarget, BreakpointCreateByLocation, + (const lldb::SBFileSpec &, uint32_t, uint32_t, + lldb::addr_t, lldb::SBFileSpecList &, bool), + sb_file_spec, line, column, offset, sb_module_list, + move_to_nearest_code); + + SBBreakpoint sb_bp; + TargetSP target_sp(GetSP()); + if (target_sp && line != 0) { + std::lock_guard guard(target_sp->GetAPIMutex()); + + const LazyBool check_inlines = eLazyBoolCalculate; + const LazyBool skip_prologue = eLazyBoolCalculate; + const bool internal = false; + const bool hardware = false; + const FileSpecList *module_list = nullptr; + if (sb_module_list.GetSize() > 0) { + module_list = sb_module_list.get(); + } + sb_bp = target_sp->CreateBreakpoint( + module_list, *sb_file_spec, line, column, offset, check_inlines, + skip_prologue, internal, hardware, + move_to_nearest_code ? eLazyBoolYes : eLazyBoolNo); + } + + return LLDB_RECORD_RESULT(sb_bp); +} + SBBreakpoint SBTarget::BreakpointCreateByName(const char *symbol_name, const char *module_name) { LLDB_RECORD_METHOD(lldb::SBBreakpoint, SBTarget, BreakpointCreateByName, @@ -1783,7 +1824,7 @@ lldb::SBSymbolContextList SBTarget::FindFunctions(const char *name, (const char *, uint32_t), name, name_type_mask); lldb::SBSymbolContextList sb_sc_list; - if (!name | !name[0]) + if (!name || !name[0]) return LLDB_RECORD_RESULT(sb_sc_list); TargetSP target_sp(GetSP()); @@ -2045,12 +2086,12 @@ lldb::SBInstructionList SBTarget::ReadInstructions(lldb::SBAddress base_addr, if (addr_ptr) { DataBufferHeap data( target_sp->GetArchitecture().GetMaximumOpcodeByteSize() * count, 0); - bool prefer_file_cache = false; + bool force_live_memory = true; lldb_private::Status error; lldb::addr_t load_addr = LLDB_INVALID_ADDRESS; const size_t bytes_read = - target_sp->ReadMemory(*addr_ptr, prefer_file_cache, data.GetBytes(), - data.GetByteSize(), error, &load_addr); + target_sp->ReadMemory(*addr_ptr, data.GetBytes(), data.GetByteSize(), + error, force_live_memory, &load_addr); const bool data_from_file = load_addr == LLDB_INVALID_ADDRESS; sb_instructions.SetDisassembler(Disassembler::DisassembleBytes( target_sp->GetArchitecture(), nullptr, flavor_string, *addr_ptr, @@ -2369,6 +2410,21 @@ lldb::addr_t SBTarget::GetStackRedZoneSize() { return 0; } +bool SBTarget::IsLoaded(const SBModule &module) const { + LLDB_RECORD_METHOD_CONST(bool, SBTarget, IsLoaded, (const lldb::SBModule &), + module); + + TargetSP target_sp(GetSP()); + if (!target_sp) + return false; + + ModuleSP module_sp(module.GetSP()); + if (!module_sp) + return false; + + return module_sp->IsLoadedInTarget(target_sp.get()); +} + lldb::SBLaunchInfo SBTarget::GetLaunchInfo() const { LLDB_RECORD_METHOD_CONST_NO_ARGS(lldb::SBLaunchInfo, SBTarget, GetLaunchInfo); @@ -2399,6 +2455,34 @@ SBEnvironment SBTarget::GetEnvironment() { return LLDB_RECORD_RESULT(SBEnvironment()); } +lldb::SBTrace SBTarget::GetTrace() { + LLDB_RECORD_METHOD_NO_ARGS(lldb::SBTrace, SBTarget, GetTrace); + TargetSP target_sp(GetSP()); + + if (target_sp) + return LLDB_RECORD_RESULT(SBTrace(target_sp->GetTrace())); + + return LLDB_RECORD_RESULT(SBTrace()); +} + +lldb::SBTrace SBTarget::CreateTrace(lldb::SBError &error) { + LLDB_RECORD_METHOD(lldb::SBTrace, SBTarget, CreateTrace, (lldb::SBError &), + error); + TargetSP target_sp(GetSP()); + error.Clear(); + + if (target_sp) { + if (llvm::Expected trace_sp = target_sp->CreateTrace()) { + return LLDB_RECORD_RESULT(SBTrace(*trace_sp)); + } else { + error.SetErrorString(llvm::toString(trace_sp.takeError()).c_str()); + } + } else { + error.SetErrorString("missing target"); + } + return LLDB_RECORD_RESULT(SBTrace()); +} + namespace lldb_private { namespace repro { @@ -2480,6 +2564,9 @@ void RegisterMethods(Registry &R) { BreakpointCreateByLocation, (const lldb::SBFileSpec &, uint32_t, uint32_t, lldb::addr_t, lldb::SBFileSpecList &)); + LLDB_REGISTER_METHOD(lldb::SBBreakpoint, SBTarget, BreakpointCreateByLocation, + (const lldb::SBFileSpec &, uint32_t, uint32_t, + lldb::addr_t, lldb::SBFileSpecList &, bool)); LLDB_REGISTER_METHOD(lldb::SBBreakpoint, SBTarget, BreakpointCreateByName, (const char *, const char *)); LLDB_REGISTER_METHOD(lldb::SBBreakpoint, SBTarget, BreakpointCreateByName, @@ -2638,6 +2725,8 @@ void RegisterMethods(Registry &R) { LLDB_REGISTER_METHOD(lldb::SBValue, SBTarget, EvaluateExpression, (const char *, const lldb::SBExpressionOptions &)); LLDB_REGISTER_METHOD(lldb::addr_t, SBTarget, GetStackRedZoneSize, ()); + LLDB_REGISTER_METHOD_CONST(bool, SBTarget, IsLoaded, + (const lldb::SBModule &)); LLDB_REGISTER_METHOD_CONST(lldb::SBLaunchInfo, SBTarget, GetLaunchInfo, ()); LLDB_REGISTER_METHOD(void, SBTarget, SetLaunchInfo, (const lldb::SBLaunchInfo &)); @@ -2655,6 +2744,8 @@ void RegisterMethods(Registry &R) { GetInstructionsWithFlavor, (lldb::addr_t, const char *, const void *, size_t)); LLDB_REGISTER_METHOD(lldb::SBEnvironment, SBTarget, GetEnvironment, ()); + LLDB_REGISTER_METHOD(lldb::SBTrace, SBTarget, GetTrace, ()); + LLDB_REGISTER_METHOD(lldb::SBTrace, SBTarget, CreateTrace, (lldb::SBError &)); } } diff --git a/gnu/llvm/lldb/source/API/SBThread.cpp b/gnu/llvm/lldb/source/API/SBThread.cpp index 0d50aceee5e..e0ab8b2e9fa 100644 --- a/gnu/llvm/lldb/source/API/SBThread.cpp +++ b/gnu/llvm/lldb/source/API/SBThread.cpp @@ -172,6 +172,8 @@ size_t SBThread::GetStopReasonDataCount() { case eStopReasonPlanComplete: case eStopReasonThreadExiting: case eStopReasonInstrumentation: + case eStopReasonProcessorTrace: + case eStopReasonVForkDone: // There is no data for these stop reasons. return 0; @@ -194,6 +196,12 @@ size_t SBThread::GetStopReasonDataCount() { case eStopReasonException: return 1; + + case eStopReasonFork: + return 1; + + case eStopReasonVFork: + return 1; } } } @@ -223,6 +231,8 @@ uint64_t SBThread::GetStopReasonDataAtIndex(uint32_t idx) { case eStopReasonPlanComplete: case eStopReasonThreadExiting: case eStopReasonInstrumentation: + case eStopReasonProcessorTrace: + case eStopReasonVForkDone: // There is no data for these stop reasons. return 0; @@ -256,6 +266,12 @@ uint64_t SBThread::GetStopReasonDataAtIndex(uint32_t idx) { case eStopReasonException: return stop_info_sp->GetValue(); + + case eStopReasonFork: + return stop_info_sp->GetValue(); + + case eStopReasonVFork: + return stop_info_sp->GetValue(); } } } @@ -841,12 +857,13 @@ SBError SBThread::StepOverUntil(lldb::SBFrame &sb_frame, std::vector step_over_until_addrs; const bool abort_other_plans = false; const bool stop_other_threads = false; - const bool check_inlines = true; - const bool exact = false; + // TODO: Handle SourceLocationSpec column information + SourceLocationSpec location_spec( + step_file_spec, line, /*column=*/llvm::None, /*check_inlines=*/true, + /*exact_match=*/false); SymbolContextList sc_list; - frame_sc.comp_unit->ResolveSymbolContext(step_file_spec, line, - check_inlines, exact, + frame_sc.comp_unit->ResolveSymbolContext(location_spec, eSymbolContextLineEntry, sc_list); const uint32_t num_matches = sc_list.GetSize(); if (num_matches > 0) { diff --git a/gnu/llvm/lldb/source/API/SBThreadPlan.cpp b/gnu/llvm/lldb/source/API/SBThreadPlan.cpp index 1a947bbc260..9af673b0f3a 100644 --- a/gnu/llvm/lldb/source/API/SBThreadPlan.cpp +++ b/gnu/llvm/lldb/source/API/SBThreadPlan.cpp @@ -53,13 +53,13 @@ using namespace lldb_private; SBThreadPlan::SBThreadPlan() { LLDB_RECORD_CONSTRUCTOR_NO_ARGS(SBThreadPlan); } SBThreadPlan::SBThreadPlan(const ThreadPlanSP &lldb_object_sp) - : m_opaque_sp(lldb_object_sp) { + : m_opaque_wp(lldb_object_sp) { LLDB_RECORD_CONSTRUCTOR(SBThreadPlan, (const lldb::ThreadPlanSP &), lldb_object_sp); } SBThreadPlan::SBThreadPlan(const SBThreadPlan &rhs) - : m_opaque_sp(rhs.m_opaque_sp) { + : m_opaque_wp(rhs.m_opaque_wp) { LLDB_RECORD_CONSTRUCTOR(SBThreadPlan, (const lldb::SBThreadPlan &), rhs); } @@ -69,8 +69,8 @@ SBThreadPlan::SBThreadPlan(lldb::SBThread &sb_thread, const char *class_name) { Thread *thread = sb_thread.get(); if (thread) - m_opaque_sp = std::make_shared(*thread, class_name, - nullptr); + m_opaque_wp = + std::make_shared(*thread, class_name, nullptr); } SBThreadPlan::SBThreadPlan(lldb::SBThread &sb_thread, const char *class_name, @@ -81,7 +81,7 @@ SBThreadPlan::SBThreadPlan(lldb::SBThread &sb_thread, const char *class_name, Thread *thread = sb_thread.get(); if (thread) - m_opaque_sp = std::make_shared(*thread, class_name, + m_opaque_wp = std::make_shared(*thread, class_name, args_data.m_impl_up.get()); } @@ -92,14 +92,12 @@ const lldb::SBThreadPlan &SBThreadPlan::operator=(const SBThreadPlan &rhs) { SBThreadPlan, operator=,(const lldb::SBThreadPlan &), rhs); if (this != &rhs) - m_opaque_sp = rhs.m_opaque_sp; + m_opaque_wp = rhs.m_opaque_wp; return LLDB_RECORD_RESULT(*this); } // Destructor SBThreadPlan::~SBThreadPlan() = default; -lldb_private::ThreadPlan *SBThreadPlan::get() { return m_opaque_sp.get(); } - bool SBThreadPlan::IsValid() const { LLDB_RECORD_METHOD_CONST_NO_ARGS(bool, SBThreadPlan, IsValid); return this->operator bool(); @@ -107,13 +105,13 @@ bool SBThreadPlan::IsValid() const { SBThreadPlan::operator bool() const { LLDB_RECORD_METHOD_CONST_NO_ARGS(bool, SBThreadPlan, operator bool); - return m_opaque_sp.get() != nullptr; + return static_cast(GetSP()); } void SBThreadPlan::Clear() { LLDB_RECORD_METHOD_NO_ARGS(void, SBThreadPlan, Clear); - m_opaque_sp.reset(); + m_opaque_wp.reset(); } lldb::StopReason SBThreadPlan::GetStopReason() { @@ -138,9 +136,10 @@ uint64_t SBThreadPlan::GetStopReasonDataAtIndex(uint32_t idx) { SBThread SBThreadPlan::GetThread() const { LLDB_RECORD_METHOD_CONST_NO_ARGS(lldb::SBThread, SBThreadPlan, GetThread); - if (m_opaque_sp) { + ThreadPlanSP thread_plan_sp(GetSP()); + if (thread_plan_sp) { return LLDB_RECORD_RESULT( - SBThread(m_opaque_sp->GetThread().shared_from_this())); + SBThread(thread_plan_sp->GetThread().shared_from_this())); } else return LLDB_RECORD_RESULT(SBThread()); } @@ -149,50 +148,69 @@ bool SBThreadPlan::GetDescription(lldb::SBStream &description) const { LLDB_RECORD_METHOD_CONST(bool, SBThreadPlan, GetDescription, (lldb::SBStream &), description); - if (m_opaque_sp) { - m_opaque_sp->GetDescription(description.get(), eDescriptionLevelFull); + ThreadPlanSP thread_plan_sp(GetSP()); + if (thread_plan_sp) { + thread_plan_sp->GetDescription(description.get(), eDescriptionLevelFull); } else { description.Printf("Empty SBThreadPlan"); } return true; } -void SBThreadPlan::SetThreadPlan(const ThreadPlanSP &lldb_object_sp) { - m_opaque_sp = lldb_object_sp; +void SBThreadPlan::SetThreadPlan(const ThreadPlanSP &lldb_object_wp) { + m_opaque_wp = lldb_object_wp; } void SBThreadPlan::SetPlanComplete(bool success) { LLDB_RECORD_METHOD(void, SBThreadPlan, SetPlanComplete, (bool), success); - if (m_opaque_sp) - m_opaque_sp->SetPlanComplete(success); + ThreadPlanSP thread_plan_sp(GetSP()); + if (thread_plan_sp) + thread_plan_sp->SetPlanComplete(success); } bool SBThreadPlan::IsPlanComplete() { LLDB_RECORD_METHOD_NO_ARGS(bool, SBThreadPlan, IsPlanComplete); - if (m_opaque_sp) - return m_opaque_sp->IsPlanComplete(); - else - return true; + ThreadPlanSP thread_plan_sp(GetSP()); + if (thread_plan_sp) + return thread_plan_sp->IsPlanComplete(); + return true; } bool SBThreadPlan::IsPlanStale() { LLDB_RECORD_METHOD_NO_ARGS(bool, SBThreadPlan, IsPlanStale); - if (m_opaque_sp) - return m_opaque_sp->IsPlanStale(); - else - return true; + ThreadPlanSP thread_plan_sp(GetSP()); + if (thread_plan_sp) + return thread_plan_sp->IsPlanStale(); + return true; } bool SBThreadPlan::IsValid() { LLDB_RECORD_METHOD_NO_ARGS(bool, SBThreadPlan, IsValid); - if (m_opaque_sp) - return m_opaque_sp->ValidatePlan(nullptr); - else - return false; + ThreadPlanSP thread_plan_sp(GetSP()); + if (thread_plan_sp) + return thread_plan_sp->ValidatePlan(nullptr); + return false; +} + +bool SBThreadPlan::GetStopOthers() { + LLDB_RECORD_METHOD_NO_ARGS(bool, SBThreadPlan, GetStopOthers); + + ThreadPlanSP thread_plan_sp(GetSP()); + if (thread_plan_sp) + return thread_plan_sp->StopOthers(); + return false; +} + +void SBThreadPlan::SetStopOthers(bool stop_others) { + LLDB_RECORD_METHOD(void, SBThreadPlan, SetStopOthers, (bool), stop_others); + + ThreadPlanSP thread_plan_sp(GetSP()); + if (thread_plan_sp) + thread_plan_sp->SetStopOthers(stop_others); } // This section allows an SBThreadPlan to push another of the common types of @@ -220,7 +238,8 @@ SBThreadPlan SBThreadPlan::QueueThreadPlanForStepOverRange( (lldb::SBAddress &, lldb::addr_t, lldb::SBError &), sb_start_address, size, error); - if (m_opaque_sp) { + ThreadPlanSP thread_plan_sp(GetSP()); + if (thread_plan_sp) { Address *start_address = sb_start_address.get(); if (!start_address) { return LLDB_RECORD_RESULT(SBThreadPlan()); @@ -231,19 +250,18 @@ SBThreadPlan SBThreadPlan::QueueThreadPlanForStepOverRange( start_address->CalculateSymbolContext(&sc); Status plan_status; - SBThreadPlan plan = - SBThreadPlan(m_opaque_sp->GetThread().QueueThreadPlanForStepOverRange( + SBThreadPlan plan = SBThreadPlan( + thread_plan_sp->GetThread().QueueThreadPlanForStepOverRange( false, range, sc, eAllThreads, plan_status)); if (plan_status.Fail()) error.SetErrorString(plan_status.AsCString()); else - plan.m_opaque_sp->SetPrivate(true); - + plan.GetSP()->SetPrivate(true); + return LLDB_RECORD_RESULT(plan); - } else { - return LLDB_RECORD_RESULT(SBThreadPlan()); } + return LLDB_RECORD_RESULT(SBThreadPlan()); } SBThreadPlan @@ -266,7 +284,8 @@ SBThreadPlan::QueueThreadPlanForStepInRange(SBAddress &sb_start_address, (lldb::SBAddress &, lldb::addr_t, lldb::SBError &), sb_start_address, size, error); - if (m_opaque_sp) { + ThreadPlanSP thread_plan_sp(GetSP()); + if (thread_plan_sp) { Address *start_address = sb_start_address.get(); if (!start_address) { return LLDB_RECORD_RESULT(SBThreadPlan()); @@ -278,18 +297,17 @@ SBThreadPlan::QueueThreadPlanForStepInRange(SBAddress &sb_start_address, Status plan_status; SBThreadPlan plan = - SBThreadPlan(m_opaque_sp->GetThread().QueueThreadPlanForStepInRange( + SBThreadPlan(thread_plan_sp->GetThread().QueueThreadPlanForStepInRange( false, range, sc, nullptr, eAllThreads, plan_status)); if (plan_status.Fail()) error.SetErrorString(plan_status.AsCString()); else - plan.m_opaque_sp->SetPrivate(true); + plan.GetSP()->SetPrivate(true); return LLDB_RECORD_RESULT(plan); - } else { - return LLDB_RECORD_RESULT(SBThreadPlan()); } + return LLDB_RECORD_RESULT(SBThreadPlan()); } SBThreadPlan @@ -312,26 +330,26 @@ SBThreadPlan::QueueThreadPlanForStepOut(uint32_t frame_idx_to_step_to, (uint32_t, bool, lldb::SBError &), frame_idx_to_step_to, first_insn, error); - if (m_opaque_sp) { + ThreadPlanSP thread_plan_sp(GetSP()); + if (thread_plan_sp) { SymbolContext sc; - sc = m_opaque_sp->GetThread().GetStackFrameAtIndex(0)->GetSymbolContext( + sc = thread_plan_sp->GetThread().GetStackFrameAtIndex(0)->GetSymbolContext( lldb::eSymbolContextEverything); Status plan_status; SBThreadPlan plan = - SBThreadPlan(m_opaque_sp->GetThread().QueueThreadPlanForStepOut( + SBThreadPlan(thread_plan_sp->GetThread().QueueThreadPlanForStepOut( false, &sc, first_insn, false, eVoteYes, eVoteNoOpinion, frame_idx_to_step_to, plan_status)); if (plan_status.Fail()) error.SetErrorString(plan_status.AsCString()); else - plan.m_opaque_sp->SetPrivate(true); + plan.GetSP()->SetPrivate(true); return LLDB_RECORD_RESULT(plan); - } else { - return LLDB_RECORD_RESULT(SBThreadPlan()); } + return LLDB_RECORD_RESULT(SBThreadPlan()); } SBThreadPlan @@ -350,25 +368,25 @@ SBThreadPlan SBThreadPlan::QueueThreadPlanForRunToAddress(SBAddress sb_address, QueueThreadPlanForRunToAddress, (lldb::SBAddress, lldb::SBError &), sb_address, error); - if (m_opaque_sp) { + ThreadPlanSP thread_plan_sp(GetSP()); + if (thread_plan_sp) { Address *address = sb_address.get(); if (!address) return LLDB_RECORD_RESULT(SBThreadPlan()); Status plan_status; SBThreadPlan plan = - SBThreadPlan(m_opaque_sp->GetThread().QueueThreadPlanForRunToAddress( + SBThreadPlan(thread_plan_sp->GetThread().QueueThreadPlanForRunToAddress( false, *address, false, plan_status)); if (plan_status.Fail()) error.SetErrorString(plan_status.AsCString()); else - plan.m_opaque_sp->SetPrivate(true); + plan.GetSP()->SetPrivate(true); return LLDB_RECORD_RESULT(plan); - } else { - return LLDB_RECORD_RESULT(SBThreadPlan()); } + return LLDB_RECORD_RESULT(SBThreadPlan()); } SBThreadPlan @@ -389,22 +407,22 @@ SBThreadPlan::QueueThreadPlanForStepScripted(const char *script_class_name, QueueThreadPlanForStepScripted, (const char *, lldb::SBError &), script_class_name, error); - if (m_opaque_sp) { + ThreadPlanSP thread_plan_sp(GetSP()); + if (thread_plan_sp) { Status plan_status; StructuredData::ObjectSP empty_args; SBThreadPlan plan = - SBThreadPlan(m_opaque_sp->GetThread().QueueThreadPlanForStepScripted( + SBThreadPlan(thread_plan_sp->GetThread().QueueThreadPlanForStepScripted( false, script_class_name, empty_args, false, plan_status)); if (plan_status.Fail()) error.SetErrorString(plan_status.AsCString()); else - plan.m_opaque_sp->SetPrivate(true); + plan.GetSP()->SetPrivate(true); return LLDB_RECORD_RESULT(plan); - } else { - return LLDB_RECORD_RESULT(SBThreadPlan()); } + return LLDB_RECORD_RESULT(SBThreadPlan()); } SBThreadPlan @@ -416,17 +434,18 @@ SBThreadPlan::QueueThreadPlanForStepScripted(const char *script_class_name, (const char *, lldb::SBStructuredData &, lldb::SBError &), script_class_name, args_data, error); - if (m_opaque_sp) { + ThreadPlanSP thread_plan_sp(GetSP()); + if (thread_plan_sp) { Status plan_status; StructuredData::ObjectSP args_obj = args_data.m_impl_up->GetObjectSP(); SBThreadPlan plan = - SBThreadPlan(m_opaque_sp->GetThread().QueueThreadPlanForStepScripted( + SBThreadPlan(thread_plan_sp->GetThread().QueueThreadPlanForStepScripted( false, script_class_name, args_obj, false, plan_status)); if (plan_status.Fail()) error.SetErrorString(plan_status.AsCString()); else - plan.m_opaque_sp->SetPrivate(true); + plan.GetSP()->SetPrivate(true); return LLDB_RECORD_RESULT(plan); } else { @@ -461,6 +480,8 @@ void RegisterMethods(Registry &R) { LLDB_REGISTER_METHOD(bool, SBThreadPlan, IsPlanComplete, ()); LLDB_REGISTER_METHOD(bool, SBThreadPlan, IsPlanStale, ()); LLDB_REGISTER_METHOD(bool, SBThreadPlan, IsValid, ()); + LLDB_REGISTER_METHOD(void, SBThreadPlan, SetStopOthers, (bool)); + LLDB_REGISTER_METHOD(bool, SBThreadPlan, GetStopOthers, ()); LLDB_REGISTER_METHOD(lldb::SBThreadPlan, SBThreadPlan, QueueThreadPlanForStepOverRange, (lldb::SBAddress &, lldb::addr_t)); diff --git a/gnu/llvm/lldb/source/API/SBTrace.cpp b/gnu/llvm/lldb/source/API/SBTrace.cpp index 3fdabaa29ac..079c33a562c 100644 --- a/gnu/llvm/lldb/source/API/SBTrace.cpp +++ b/gnu/llvm/lldb/source/API/SBTrace.cpp @@ -9,123 +9,88 @@ #include "SBReproducerPrivate.h" #include "lldb/Target/Process.h" +#include "lldb/API/SBStructuredData.h" +#include "lldb/API/SBThread.h" #include "lldb/API/SBTrace.h" -#include "lldb/API/SBTraceOptions.h" + +#include "lldb/Core/StructuredDataImpl.h" #include using namespace lldb; using namespace lldb_private; -class TraceImpl { -public: - lldb::user_id_t uid; -}; - -lldb::ProcessSP SBTrace::GetSP() const { return m_opaque_wp.lock(); } - -size_t SBTrace::GetTraceData(SBError &error, void *buf, size_t size, - size_t offset, lldb::tid_t thread_id) { - LLDB_RECORD_DUMMY(size_t, SBTrace, GetTraceData, - (lldb::SBError &, void *, size_t, size_t, lldb::tid_t), - error, buf, size, offset, thread_id); +SBTrace::SBTrace() { LLDB_RECORD_CONSTRUCTOR_NO_ARGS(SBTrace); } - ProcessSP process_sp(GetSP()); - llvm::MutableArrayRef buffer(static_cast(buf), size); - error.Clear(); - - if (!process_sp) { - error.SetErrorString("invalid process"); - } else { - error.SetError( - process_sp->GetData(GetTraceUID(), thread_id, buffer, offset)); - } - return buffer.size(); +SBTrace::SBTrace(const lldb::TraceSP &trace_sp) : m_opaque_sp(trace_sp) { + LLDB_RECORD_CONSTRUCTOR(SBTrace, (const lldb::TraceSP &), trace_sp); } -size_t SBTrace::GetMetaData(SBError &error, void *buf, size_t size, - size_t offset, lldb::tid_t thread_id) { - LLDB_RECORD_DUMMY(size_t, SBTrace, GetMetaData, - (lldb::SBError &, void *, size_t, size_t, lldb::tid_t), - error, buf, size, offset, thread_id); - - ProcessSP process_sp(GetSP()); - llvm::MutableArrayRef buffer(static_cast(buf), size); - error.Clear(); - - if (!process_sp) { - error.SetErrorString("invalid process"); - } else { - error.SetError( - process_sp->GetMetaData(GetTraceUID(), thread_id, buffer, offset)); - } - return buffer.size(); +const char *SBTrace::GetStartConfigurationHelp() { + LLDB_RECORD_METHOD_NO_ARGS(const char *, SBTrace, GetStartConfigurationHelp); + return LLDB_RECORD_RESULT( + m_opaque_sp ? m_opaque_sp->GetStartConfigurationHelp() : nullptr); } -void SBTrace::StopTrace(SBError &error, lldb::tid_t thread_id) { - LLDB_RECORD_METHOD(void, SBTrace, StopTrace, (lldb::SBError &, lldb::tid_t), - error, thread_id); - - ProcessSP process_sp(GetSP()); - error.Clear(); - - if (!process_sp) { - error.SetErrorString("invalid process"); - return; - } - error.SetError(process_sp->StopTrace(GetTraceUID(), thread_id)); +SBError SBTrace::Start(const SBStructuredData &configuration) { + LLDB_RECORD_METHOD(SBError, SBTrace, Start, (const SBStructuredData &), + configuration); + SBError error; + if (!m_opaque_sp) + error.SetErrorString("error: invalid trace"); + else if (llvm::Error err = + m_opaque_sp->Start(configuration.m_impl_up->GetObjectSP())) + error.SetErrorString(llvm::toString(std::move(err)).c_str()); + return LLDB_RECORD_RESULT(error); } -void SBTrace::GetTraceConfig(SBTraceOptions &options, SBError &error) { - LLDB_RECORD_METHOD(void, SBTrace, GetTraceConfig, - (lldb::SBTraceOptions &, lldb::SBError &), options, error); - - ProcessSP process_sp(GetSP()); - error.Clear(); - - if (!process_sp) { - error.SetErrorString("invalid process"); - } else { - error.SetError(process_sp->GetTraceConfig(GetTraceUID(), - *(options.m_traceoptions_sp))); +SBError SBTrace::Start(const SBThread &thread, + const SBStructuredData &configuration) { + LLDB_RECORD_METHOD(SBError, SBTrace, Start, + (const SBThread &, const SBStructuredData &), thread, + configuration); + + SBError error; + if (!m_opaque_sp) + error.SetErrorString("error: invalid trace"); + else { + if (llvm::Error err = + m_opaque_sp->Start(std::vector{thread.GetThreadID()}, + configuration.m_impl_up->GetObjectSP())) + error.SetErrorString(llvm::toString(std::move(err)).c_str()); } -} - -lldb::user_id_t SBTrace::GetTraceUID() { - LLDB_RECORD_METHOD_NO_ARGS(lldb::user_id_t, SBTrace, GetTraceUID); - if (m_trace_impl_sp) - return m_trace_impl_sp->uid; - return LLDB_INVALID_UID; + return LLDB_RECORD_RESULT(error); } -void SBTrace::SetTraceUID(lldb::user_id_t uid) { - if (m_trace_impl_sp) - m_trace_impl_sp->uid = uid; +SBError SBTrace::Stop() { + LLDB_RECORD_METHOD_NO_ARGS(SBError, SBTrace, Stop); + SBError error; + if (!m_opaque_sp) + error.SetErrorString("error: invalid trace"); + else if (llvm::Error err = m_opaque_sp->Stop()) + error.SetErrorString(llvm::toString(std::move(err)).c_str()); + return LLDB_RECORD_RESULT(error); } -SBTrace::SBTrace() { - LLDB_RECORD_CONSTRUCTOR_NO_ARGS(SBTrace); - - m_trace_impl_sp = std::make_shared(); - if (m_trace_impl_sp) - m_trace_impl_sp->uid = LLDB_INVALID_UID; +SBError SBTrace::Stop(const SBThread &thread) { + LLDB_RECORD_METHOD(SBError, SBTrace, Stop, (const SBThread &), thread); + SBError error; + if (!m_opaque_sp) + error.SetErrorString("error: invalid trace"); + else if (llvm::Error err = m_opaque_sp->Stop({thread.GetThreadID()})) + error.SetErrorString(llvm::toString(std::move(err)).c_str()); + return LLDB_RECORD_RESULT(error); } -void SBTrace::SetSP(const ProcessSP &process_sp) { m_opaque_wp = process_sp; } - bool SBTrace::IsValid() { LLDB_RECORD_METHOD_NO_ARGS(bool, SBTrace, IsValid); return this->operator bool(); } + SBTrace::operator bool() const { LLDB_RECORD_METHOD_CONST_NO_ARGS(bool, SBTrace, operator bool); - - if (!m_trace_impl_sp) - return false; - if (!GetSP()) - return false; - return true; + return (bool)m_opaque_sp; } namespace lldb_private { @@ -133,13 +98,15 @@ namespace repro { template <> void RegisterMethods(Registry &R) { - LLDB_REGISTER_METHOD(void, SBTrace, StopTrace, - (lldb::SBError &, lldb::tid_t)); - LLDB_REGISTER_METHOD(void, SBTrace, GetTraceConfig, - (lldb::SBTraceOptions &, lldb::SBError &)); - LLDB_REGISTER_METHOD(lldb::user_id_t, SBTrace, GetTraceUID, ()); LLDB_REGISTER_CONSTRUCTOR(SBTrace, ()); + LLDB_REGISTER_CONSTRUCTOR(SBTrace, (const lldb::TraceSP &)); + LLDB_REGISTER_METHOD(SBError, SBTrace, Start, (const SBStructuredData &)); + LLDB_REGISTER_METHOD(SBError, SBTrace, Start, + (const SBThread &, const SBStructuredData &)); + LLDB_REGISTER_METHOD(SBError, SBTrace, Stop, (const SBThread &)); + LLDB_REGISTER_METHOD(SBError, SBTrace, Stop, ()); LLDB_REGISTER_METHOD(bool, SBTrace, IsValid, ()); + LLDB_REGISTER_METHOD(const char *, SBTrace, GetStartConfigurationHelp, ()); LLDB_REGISTER_METHOD_CONST(bool, SBTrace, operator bool, ()); } diff --git a/gnu/llvm/lldb/source/API/SBType.cpp b/gnu/llvm/lldb/source/API/SBType.cpp index 852630f2d01..550c4b06591 100644 --- a/gnu/llvm/lldb/source/API/SBType.cpp +++ b/gnu/llvm/lldb/source/API/SBType.cpp @@ -9,6 +9,7 @@ #include "lldb/API/SBType.h" #include "SBReproducerPrivate.h" #include "lldb/API/SBDefines.h" +#include "lldb/API/SBModule.h" #include "lldb/API/SBStream.h" #include "lldb/API/SBTypeEnumMember.h" #include "lldb/Core/Mangled.h" @@ -212,10 +213,8 @@ SBType SBType::GetArrayElementType() { if (!IsValid()) return LLDB_RECORD_RESULT(SBType()); - CompilerType canonical_type = - m_opaque_sp->GetCompilerType(true).GetCanonicalType(); - return LLDB_RECORD_RESULT( - SBType(TypeImplSP(new TypeImpl(canonical_type.GetArrayElementType())))); + return LLDB_RECORD_RESULT(SBType(TypeImplSP(new TypeImpl( + m_opaque_sp->GetCompilerType(true).GetArrayElementType(nullptr))))); } SBType SBType::GetArrayType(uint64_t size) { @@ -272,6 +271,14 @@ bool SBType::IsAnonymousType() { return m_opaque_sp->GetCompilerType(true).IsAnonymousType(); } +bool SBType::IsScopedEnumerationType() { + LLDB_RECORD_METHOD_NO_ARGS(bool, SBType, IsScopedEnumerationType); + + if (!IsValid()) + return false; + return m_opaque_sp->GetCompilerType(true).IsScopedEnumerationType(); +} + lldb::SBType SBType::GetFunctionReturnType() { LLDB_RECORD_METHOD_NO_ARGS(lldb::SBType, SBType, GetFunctionReturnType); @@ -337,6 +344,16 @@ lldb::SBType SBType::GetCanonicalType() { return LLDB_RECORD_RESULT(SBType()); } +SBType SBType::GetEnumerationIntegerType() { + LLDB_RECORD_METHOD_NO_ARGS(lldb::SBType, SBType, GetEnumerationIntegerType); + + if (IsValid()) { + return LLDB_RECORD_RESULT( + SBType(m_opaque_sp->GetCompilerType(true).GetEnumerationIntegerType())); + } + return LLDB_RECORD_RESULT(SBType()); +} + lldb::BasicType SBType::GetBasicType() { LLDB_RECORD_METHOD_NO_ARGS(lldb::BasicType, SBType, GetBasicType); @@ -495,6 +512,17 @@ uint32_t SBType::GetTypeFlags() { return m_opaque_sp->GetCompilerType(true).GetTypeInfo(); } +lldb::SBModule SBType::GetModule() { + LLDB_RECORD_METHOD_NO_ARGS(lldb::SBModule, SBType, GetModule); + + lldb::SBModule sb_module; + if (!IsValid()) + return LLDB_RECORD_RESULT(sb_module); + + sb_module.SetSP(m_opaque_sp->GetModule()); + return LLDB_RECORD_RESULT(sb_module); +} + const char *SBType::GetName() { LLDB_RECORD_METHOD_NO_ARGS(const char *, SBType, GetName); @@ -925,6 +953,7 @@ void RegisterMethods(Registry &R) { LLDB_REGISTER_METHOD(bool, SBType, IsPolymorphicClass, ()); LLDB_REGISTER_METHOD(bool, SBType, IsTypedefType, ()); LLDB_REGISTER_METHOD(bool, SBType, IsAnonymousType, ()); + LLDB_REGISTER_METHOD(bool, SBType, IsScopedEnumerationType, ()); LLDB_REGISTER_METHOD(lldb::SBType, SBType, GetFunctionReturnType, ()); LLDB_REGISTER_METHOD(lldb::SBTypeList, SBType, GetFunctionArgumentTypes, ()); @@ -933,6 +962,7 @@ void RegisterMethods(Registry &R) { GetMemberFunctionAtIndex, (uint32_t)); LLDB_REGISTER_METHOD(lldb::SBType, SBType, GetUnqualifiedType, ()); LLDB_REGISTER_METHOD(lldb::SBType, SBType, GetCanonicalType, ()); + LLDB_REGISTER_METHOD(lldb::SBType, SBType, GetEnumerationIntegerType, ()); LLDB_REGISTER_METHOD(lldb::BasicType, SBType, GetBasicType, ()); LLDB_REGISTER_METHOD(lldb::SBType, SBType, GetBasicType, (lldb::BasicType)); LLDB_REGISTER_METHOD(uint32_t, SBType, GetNumberOfDirectBaseClasses, ()); @@ -950,6 +980,7 @@ void RegisterMethods(Registry &R) { (uint32_t)); LLDB_REGISTER_METHOD(bool, SBType, IsTypeComplete, ()); LLDB_REGISTER_METHOD(uint32_t, SBType, GetTypeFlags, ()); + LLDB_REGISTER_METHOD(lldb::SBModule, SBType, GetModule, ()); LLDB_REGISTER_METHOD(const char *, SBType, GetName, ()); LLDB_REGISTER_METHOD(const char *, SBType, GetDisplayTypeName, ()); LLDB_REGISTER_METHOD(lldb::TypeClass, SBType, GetTypeClass, ()); diff --git a/gnu/llvm/lldb/source/API/SBTypeCategory.cpp b/gnu/llvm/lldb/source/API/SBTypeCategory.cpp index 9ce1a57ec4f..e7432959b26 100644 --- a/gnu/llvm/lldb/source/API/SBTypeCategory.cpp +++ b/gnu/llvm/lldb/source/API/SBTypeCategory.cpp @@ -363,9 +363,7 @@ bool SBTypeCategory::AddTypeFormat(SBTypeNameSpecifier type_name, if (type_name.IsRegex()) m_opaque_sp->GetRegexTypeFormatsContainer()->Add( - RegularExpression( - llvm::StringRef::withNullAsEmpty(type_name.GetName())), - format.GetSP()); + RegularExpression(type_name.GetName()), format.GetSP()); else m_opaque_sp->GetTypeFormatsContainer()->Add( ConstString(type_name.GetName()), format.GetSP()); @@ -442,9 +440,7 @@ bool SBTypeCategory::AddTypeSummary(SBTypeNameSpecifier type_name, if (type_name.IsRegex()) m_opaque_sp->GetRegexTypeSummariesContainer()->Add( - RegularExpression( - llvm::StringRef::withNullAsEmpty(type_name.GetName())), - summary.GetSP()); + RegularExpression(type_name.GetName()), summary.GetSP()); else m_opaque_sp->GetTypeSummariesContainer()->Add( ConstString(type_name.GetName()), summary.GetSP()); @@ -487,9 +483,7 @@ bool SBTypeCategory::AddTypeFilter(SBTypeNameSpecifier type_name, if (type_name.IsRegex()) m_opaque_sp->GetRegexTypeFiltersContainer()->Add( - RegularExpression( - llvm::StringRef::withNullAsEmpty(type_name.GetName())), - filter.GetSP()); + RegularExpression(type_name.GetName()), filter.GetSP()); else m_opaque_sp->GetTypeFiltersContainer()->Add( ConstString(type_name.GetName()), filter.GetSP()); @@ -566,9 +560,7 @@ bool SBTypeCategory::AddTypeSynthetic(SBTypeNameSpecifier type_name, if (type_name.IsRegex()) m_opaque_sp->GetRegexTypeSyntheticsContainer()->Add( - RegularExpression( - llvm::StringRef::withNullAsEmpty(type_name.GetName())), - synth.GetSP()); + RegularExpression(type_name.GetName()), synth.GetSP()); else m_opaque_sp->GetTypeSyntheticsContainer()->Add( ConstString(type_name.GetName()), synth.GetSP()); diff --git a/gnu/llvm/lldb/source/API/SBValue.cpp b/gnu/llvm/lldb/source/API/SBValue.cpp index 7485b0ee183..9faee102c5e 100644 --- a/gnu/llvm/lldb/source/API/SBValue.cpp +++ b/gnu/llvm/lldb/source/API/SBValue.cpp @@ -17,6 +17,7 @@ #include "lldb/API/SBTypeSynthetic.h" #include "lldb/Breakpoint/Watchpoint.h" +#include "lldb/Core/Declaration.h" #include "lldb/Core/Module.h" #include "lldb/Core/Section.h" #include "lldb/Core/StreamFile.h" @@ -25,7 +26,6 @@ #include "lldb/Core/ValueObjectConstResult.h" #include "lldb/DataFormatters/DataVisualization.h" #include "lldb/Symbol/Block.h" -#include "lldb/Symbol/Declaration.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Symbol/Type.h" #include "lldb/Symbol/Variable.h" @@ -333,7 +333,7 @@ size_t SBValue::GetByteSize() { ValueLocker locker; lldb::ValueObjectSP value_sp(GetSP(locker)); if (value_sp) { - result = value_sp->GetByteSize(); + result = value_sp->GetByteSize().getValueOr(0); } return result; @@ -1356,7 +1356,7 @@ lldb::SBAddress SBValue::GetAddress() { } } - return LLDB_RECORD_RESULT(SBAddress(new Address(addr))); + return LLDB_RECORD_RESULT(SBAddress(addr)); } lldb::SBData SBValue::GetPointeeData(uint32_t item_idx, uint32_t item_count) { diff --git a/gnu/llvm/lldb/source/API/SBVariablesOptions.cpp b/gnu/llvm/lldb/source/API/SBVariablesOptions.cpp index 4ef16364e62..1af582a0c3d 100644 --- a/gnu/llvm/lldb/source/API/SBVariablesOptions.cpp +++ b/gnu/llvm/lldb/source/API/SBVariablesOptions.cpp @@ -21,9 +21,7 @@ public: VariablesOptionsImpl() : m_include_arguments(false), m_include_locals(false), m_include_statics(false), m_in_scope_only(false), - m_include_runtime_support_values(false), - m_include_recognized_arguments(eLazyBoolCalculate), - m_use_dynamic(lldb::eNoDynamicValues) {} + m_include_runtime_support_values(false) {} VariablesOptionsImpl(const VariablesOptionsImpl &) = default; @@ -75,8 +73,9 @@ private: bool m_include_statics : 1; bool m_in_scope_only : 1; bool m_include_runtime_support_values : 1; - LazyBool m_include_recognized_arguments; // can be overridden with a setting - lldb::DynamicValueType m_use_dynamic; + LazyBool m_include_recognized_arguments = + eLazyBoolCalculate; // can be overridden with a setting + lldb::DynamicValueType m_use_dynamic = lldb::eNoDynamicValues; }; SBVariablesOptions::SBVariablesOptions() diff --git a/gnu/llvm/lldb/source/API/SystemInitializerFull.cpp b/gnu/llvm/lldb/source/API/SystemInitializerFull.cpp index 7f95e7acf62..cc6cb6925bd 100644 --- a/gnu/llvm/lldb/source/API/SystemInitializerFull.cpp +++ b/gnu/llvm/lldb/source/API/SystemInitializerFull.cpp @@ -14,7 +14,10 @@ #include "lldb/Host/Host.h" #include "lldb/Initialization/SystemInitializerCommon.h" #include "lldb/Interpreter/CommandInterpreter.h" +#include "lldb/Target/ProcessTrace.h" +#include "lldb/Utility/Reproducer.h" #include "lldb/Utility/Timer.h" +#include "llvm/Support/CommandLine.h" #include "llvm/Support/TargetSelect.h" #pragma clang diagnostic push @@ -27,24 +30,55 @@ #define LLDB_PLUGIN(p) LLDB_PLUGIN_DECLARE(p) #include "Plugins/Plugins.def" +#if LLDB_ENABLE_PYTHON +#include "Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h" + +constexpr lldb_private::HostInfo::SharedLibraryDirectoryHelper + *g_shlib_dir_helper = + lldb_private::ScriptInterpreterPython::SharedLibraryDirectoryHelper; + +#else +constexpr lldb_private::HostInfo::SharedLibraryDirectoryHelper + *g_shlib_dir_helper = 0; +#endif + using namespace lldb_private; -SystemInitializerFull::SystemInitializerFull() = default; +SystemInitializerFull::SystemInitializerFull() + : SystemInitializerCommon(g_shlib_dir_helper) {} SystemInitializerFull::~SystemInitializerFull() = default; llvm::Error SystemInitializerFull::Initialize() { - if (auto e = SystemInitializerCommon::Initialize()) - return e; + llvm::Error error = SystemInitializerCommon::Initialize(); + if (error) { + // During active replay, the ::Initialize call is replayed like any other + // SB API call and the return value is ignored. Since we can't intercept + // this, we terminate here before the uninitialized debugger inevitably + // crashes. + if (repro::Reproducer::Instance().IsReplaying()) + llvm::report_fatal_error(std::move(error)); + return error; + } // Initialize LLVM and Clang llvm::InitializeAllTargets(); llvm::InitializeAllAsmPrinters(); llvm::InitializeAllTargetMCs(); llvm::InitializeAllDisassemblers(); + // Initialize the command line parser in LLVM. This usually isn't necessary + // as we aren't dealing with command line options here, but otherwise some + // other code in Clang/LLVM might be tempted to call this function from a + // different thread later on which won't work (as the function isn't + // thread-safe). + const char *arg0 = "lldb"; + llvm::cl::ParseCommandLineOptions(1, &arg0); #define LLDB_PLUGIN(p) LLDB_PLUGIN_INITIALIZE(p); #include "Plugins/Plugins.def" + // Initialize plug-ins in core LLDB + ProcessTrace::Initialize(); + // Scan for any system or user LLDB plug-ins PluginManager::Initialize(); @@ -56,11 +90,11 @@ llvm::Error SystemInitializerFull::Initialize() { } void SystemInitializerFull::Terminate() { - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer(func_cat, LLVM_PRETTY_FUNCTION); - Debugger::SettingsTerminate(); + // Terminate plug-ins in core LLDB + ProcessTrace::Terminate(); + // Terminate and unload and loaded system or user LLDB plug-ins PluginManager::Terminate(); diff --git a/gnu/llvm/lldb/source/Breakpoint/Breakpoint.cpp b/gnu/llvm/lldb/source/Breakpoint/Breakpoint.cpp index 317dfa23109..8d5d5a31337 100644 --- a/gnu/llvm/lldb/source/Breakpoint/Breakpoint.cpp +++ b/gnu/llvm/lldb/source/Breakpoint/Breakpoint.cpp @@ -49,19 +49,18 @@ Breakpoint::Breakpoint(Target &target, SearchFilterSP &filter_sp, BreakpointResolverSP &resolver_sp, bool hardware, bool resolve_indirect_symbols) : m_being_created(true), m_hardware(hardware), m_target(target), - m_filter_sp(filter_sp), m_resolver_sp(resolver_sp), - m_options_up(new BreakpointOptions(true)), m_locations(*this), - m_resolve_indirect_symbols(resolve_indirect_symbols), m_hit_count(0) { + m_filter_sp(filter_sp), m_resolver_sp(resolver_sp), m_options(true), + m_locations(*this), m_resolve_indirect_symbols(resolve_indirect_symbols), + m_hit_counter() { m_being_created = false; } Breakpoint::Breakpoint(Target &new_target, const Breakpoint &source_bp) : m_being_created(true), m_hardware(source_bp.m_hardware), m_target(new_target), m_name_list(source_bp.m_name_list), - m_options_up(new BreakpointOptions(*source_bp.m_options_up)), - m_locations(*this), + m_options(source_bp.m_options), m_locations(*this), m_resolve_indirect_symbols(source_bp.m_resolve_indirect_symbols), - m_hit_count(0) {} + m_hit_counter() {} // Destructor Breakpoint::~Breakpoint() = default; @@ -116,7 +115,7 @@ StructuredData::ObjectSP Breakpoint::SerializeToStructuredData() { filter_dict_sp); StructuredData::ObjectSP options_dict_sp( - m_options_up->SerializeToStructuredData()); + m_options.SerializeToStructuredData()); if (!options_dict_sp) return StructuredData::ObjectSP(); @@ -144,8 +143,7 @@ lldb::BreakpointSP Breakpoint::CreateFromStructuredData( bool success = breakpoint_dict->GetValueForKeyAsDictionary( BreakpointResolver::GetSerializationKey(), resolver_dict); if (!success) { - error.SetErrorStringWithFormat( - "Breakpoint data missing toplevel resolver key"); + error.SetErrorString("Breakpoint data missing toplevel resolver key"); return result_sp; } @@ -202,7 +200,7 @@ lldb::BreakpointSP Breakpoint::CreateFromStructuredData( hardware, true); if (result_sp && options_up) { - result_sp->m_options_up = std::move(options_up); + result_sp->m_options = *options_up; } StructuredData::Array *names_array; @@ -242,15 +240,12 @@ bool Breakpoint::SerializedBreakpointMatchesNames( return false; size_t num_names = names_array->GetSize(); - std::vector::iterator begin = names.begin(); - std::vector::iterator end = names.end(); for (size_t i = 0; i < num_names; i++) { llvm::StringRef name; if (names_array->GetItemAtIndexAsString(i, name)) { - if (std::find(begin, end, name) != end) { + if (llvm::is_contained(names, name)) return true; - } } } return false; @@ -297,10 +292,10 @@ void Breakpoint::RemoveInvalidLocations(const ArchSpec &arch) { // individual settings. void Breakpoint::SetEnabled(bool enable) { - if (enable == m_options_up->IsEnabled()) + if (enable == m_options.IsEnabled()) return; - m_options_up->SetEnabled(enable); + m_options.SetEnabled(enable); if (enable) m_locations.ResolveAllBreakpointSites(); else @@ -310,123 +305,107 @@ void Breakpoint::SetEnabled(bool enable) { : eBreakpointEventTypeDisabled); } -bool Breakpoint::IsEnabled() { return m_options_up->IsEnabled(); } +bool Breakpoint::IsEnabled() { return m_options.IsEnabled(); } void Breakpoint::SetIgnoreCount(uint32_t n) { - if (m_options_up->GetIgnoreCount() == n) + if (m_options.GetIgnoreCount() == n) return; - m_options_up->SetIgnoreCount(n); + m_options.SetIgnoreCount(n); SendBreakpointChangedEvent(eBreakpointEventTypeIgnoreChanged); } void Breakpoint::DecrementIgnoreCount() { - uint32_t ignore = m_options_up->GetIgnoreCount(); + uint32_t ignore = m_options.GetIgnoreCount(); if (ignore != 0) - m_options_up->SetIgnoreCount(ignore - 1); + m_options.SetIgnoreCount(ignore - 1); } uint32_t Breakpoint::GetIgnoreCount() const { - return m_options_up->GetIgnoreCount(); -} - -bool Breakpoint::IgnoreCountShouldStop() { - uint32_t ignore = GetIgnoreCount(); - if (ignore != 0) { - // When we get here we know the location that caused the stop doesn't have - // an ignore count, since by contract we call it first... So we don't have - // to find & decrement it, we only have to decrement our own ignore count. - DecrementIgnoreCount(); - return false; - } else - return true; + return m_options.GetIgnoreCount(); } -uint32_t Breakpoint::GetHitCount() const { return m_hit_count; } +uint32_t Breakpoint::GetHitCount() const { return m_hit_counter.GetValue(); } -bool Breakpoint::IsOneShot() const { return m_options_up->IsOneShot(); } +bool Breakpoint::IsOneShot() const { return m_options.IsOneShot(); } -void Breakpoint::SetOneShot(bool one_shot) { - m_options_up->SetOneShot(one_shot); -} +void Breakpoint::SetOneShot(bool one_shot) { m_options.SetOneShot(one_shot); } -bool Breakpoint::IsAutoContinue() const { - return m_options_up->IsAutoContinue(); -} +bool Breakpoint::IsAutoContinue() const { return m_options.IsAutoContinue(); } void Breakpoint::SetAutoContinue(bool auto_continue) { - m_options_up->SetAutoContinue(auto_continue); + m_options.SetAutoContinue(auto_continue); } void Breakpoint::SetThreadID(lldb::tid_t thread_id) { - if (m_options_up->GetThreadSpec()->GetTID() == thread_id) + if (m_options.GetThreadSpec()->GetTID() == thread_id) return; - m_options_up->GetThreadSpec()->SetTID(thread_id); + m_options.GetThreadSpec()->SetTID(thread_id); SendBreakpointChangedEvent(eBreakpointEventTypeThreadChanged); } lldb::tid_t Breakpoint::GetThreadID() const { - if (m_options_up->GetThreadSpecNoCreate() == nullptr) + if (m_options.GetThreadSpecNoCreate() == nullptr) return LLDB_INVALID_THREAD_ID; else - return m_options_up->GetThreadSpecNoCreate()->GetTID(); + return m_options.GetThreadSpecNoCreate()->GetTID(); } void Breakpoint::SetThreadIndex(uint32_t index) { - if (m_options_up->GetThreadSpec()->GetIndex() == index) + if (m_options.GetThreadSpec()->GetIndex() == index) return; - m_options_up->GetThreadSpec()->SetIndex(index); + m_options.GetThreadSpec()->SetIndex(index); SendBreakpointChangedEvent(eBreakpointEventTypeThreadChanged); } uint32_t Breakpoint::GetThreadIndex() const { - if (m_options_up->GetThreadSpecNoCreate() == nullptr) + if (m_options.GetThreadSpecNoCreate() == nullptr) return 0; else - return m_options_up->GetThreadSpecNoCreate()->GetIndex(); + return m_options.GetThreadSpecNoCreate()->GetIndex(); } void Breakpoint::SetThreadName(const char *thread_name) { - if (m_options_up->GetThreadSpec()->GetName() != nullptr && - ::strcmp(m_options_up->GetThreadSpec()->GetName(), thread_name) == 0) + if (m_options.GetThreadSpec()->GetName() != nullptr && + ::strcmp(m_options.GetThreadSpec()->GetName(), thread_name) == 0) return; - m_options_up->GetThreadSpec()->SetName(thread_name); + m_options.GetThreadSpec()->SetName(thread_name); SendBreakpointChangedEvent(eBreakpointEventTypeThreadChanged); } const char *Breakpoint::GetThreadName() const { - if (m_options_up->GetThreadSpecNoCreate() == nullptr) + if (m_options.GetThreadSpecNoCreate() == nullptr) return nullptr; else - return m_options_up->GetThreadSpecNoCreate()->GetName(); + return m_options.GetThreadSpecNoCreate()->GetName(); } void Breakpoint::SetQueueName(const char *queue_name) { - if (m_options_up->GetThreadSpec()->GetQueueName() != nullptr && - ::strcmp(m_options_up->GetThreadSpec()->GetQueueName(), queue_name) == 0) + if (m_options.GetThreadSpec()->GetQueueName() != nullptr && + ::strcmp(m_options.GetThreadSpec()->GetQueueName(), queue_name) == 0) return; - m_options_up->GetThreadSpec()->SetQueueName(queue_name); + m_options.GetThreadSpec()->SetQueueName(queue_name); SendBreakpointChangedEvent(eBreakpointEventTypeThreadChanged); } const char *Breakpoint::GetQueueName() const { - if (m_options_up->GetThreadSpecNoCreate() == nullptr) + if (m_options.GetThreadSpecNoCreate() == nullptr) return nullptr; else - return m_options_up->GetThreadSpecNoCreate()->GetQueueName(); + return m_options.GetThreadSpecNoCreate()->GetQueueName(); } void Breakpoint::SetCondition(const char *condition) { - m_options_up->SetCondition(condition); + m_options.SetCondition(condition); SendBreakpointChangedEvent(eBreakpointEventTypeConditionChanged); } const char *Breakpoint::GetConditionText() const { - return m_options_up->GetConditionText(); + return m_options.GetConditionText(); } // This function is used when "baton" doesn't need to be freed @@ -434,8 +413,8 @@ void Breakpoint::SetCallback(BreakpointHitCallback callback, void *baton, bool is_synchronous) { // The default "Baton" class will keep a copy of "baton" and won't free or // delete it when it goes goes out of scope. - m_options_up->SetCallback(callback, std::make_shared(baton), - is_synchronous); + m_options.SetCallback(callback, std::make_shared(baton), + is_synchronous); SendBreakpointChangedEvent(eBreakpointEventTypeCommandChanged); } @@ -445,21 +424,19 @@ void Breakpoint::SetCallback(BreakpointHitCallback callback, void *baton, void Breakpoint::SetCallback(BreakpointHitCallback callback, const BatonSP &callback_baton_sp, bool is_synchronous) { - m_options_up->SetCallback(callback, callback_baton_sp, is_synchronous); + m_options.SetCallback(callback, callback_baton_sp, is_synchronous); } -void Breakpoint::ClearCallback() { m_options_up->ClearCallback(); } +void Breakpoint::ClearCallback() { m_options.ClearCallback(); } bool Breakpoint::InvokeCallback(StoppointCallbackContext *context, break_id_t bp_loc_id) { - return m_options_up->InvokeCallback(context, GetID(), bp_loc_id); + return m_options.InvokeCallback(context, GetID(), bp_loc_id); } -BreakpointOptions *Breakpoint::GetOptions() { return m_options_up.get(); } +BreakpointOptions &Breakpoint::GetOptions() { return m_options; } -const BreakpointOptions *Breakpoint::GetOptions() const { - return m_options_up.get(); -} +const BreakpointOptions &Breakpoint::GetOptions() const { return m_options; } void Breakpoint::ResolveBreakpoint() { if (m_resolver_sp) @@ -512,7 +489,6 @@ void Breakpoint::ModulesChanged(ModuleList &module_list, bool load, "delete_locations: %i\n", module_list.GetSize(), load, delete_locations); - std::lock_guard guard(module_list.GetMutex()); if (load) { // The logic for handling new modules is: // 1) If the filter rejects this module, then skip it. 2) Run through the @@ -529,7 +505,7 @@ void Breakpoint::ModulesChanged(ModuleList &module_list, bool load, // them after the locations pass. Have to do it this way because resolving // breakpoints will add new locations potentially. - for (ModuleSP module_sp : module_list.ModulesNoLocking()) { + for (ModuleSP module_sp : module_list.Modules()) { bool seen = false; if (!m_filter_sp->ModulePasses(module_sp)) continue; @@ -593,9 +569,7 @@ void Breakpoint::ModulesChanged(ModuleList &module_list, bool load, else removed_locations_event = nullptr; - size_t num_modules = module_list.GetSize(); - for (size_t i = 0; i < num_modules; i++) { - ModuleSP module_sp(module_list.GetModuleAtIndexUnlocked(i)); + for (ModuleSP module_sp : module_list.Modules()) { if (m_filter_sp->ModulePasses(module_sp)) { size_t loc_idx = 0; size_t num_locations = m_locations.GetSize(); @@ -909,7 +883,7 @@ void Breakpoint::GetDescription(Stream *s, lldb::DescriptionLevel level, s->Printf(", locations = 0 (pending)"); } - GetOptions()->GetDescription(s, level); + m_options.GetDescription(s, level); if (m_precondition_sp) m_precondition_sp->GetDescription(*s, level); @@ -951,7 +925,7 @@ void Breakpoint::GetDescription(Stream *s, lldb::DescriptionLevel level, Dump(s); s->EOL(); // s->Indent(); - GetOptions()->GetDescription(s, level); + m_options.GetDescription(s, level); break; default: @@ -987,9 +961,12 @@ bool Breakpoint::GetMatchingFileLine(ConstString filename, if (m_resolver_sp) { BreakpointResolverFileLine *resolverFileLine = dyn_cast(m_resolver_sp.get()); + + // TODO: Handle SourceLocationSpec column information if (resolverFileLine && - resolverFileLine->m_file_spec.GetFilename() == filename && - resolverFileLine->m_line_number == line_number) { + resolverFileLine->m_location_spec.GetFileSpec().GetFilename() == + filename && + resolverFileLine->m_location_spec.GetLine() == line_number) { return true; } } diff --git a/gnu/llvm/lldb/source/Breakpoint/BreakpointID.cpp b/gnu/llvm/lldb/source/Breakpoint/BreakpointID.cpp index 293baf4ad1c..f2057214406 100644 --- a/gnu/llvm/lldb/source/Breakpoint/BreakpointID.cpp +++ b/gnu/llvm/lldb/source/Breakpoint/BreakpointID.cpp @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// -#include +#include #include "lldb/Breakpoint/Breakpoint.h" #include "lldb/Breakpoint/BreakpointID.h" @@ -96,7 +96,7 @@ bool BreakpointID::StringIsBreakpointName(llvm::StringRef str, Status &error) { error.Clear(); if (str.empty()) { - error.SetErrorStringWithFormat("Empty breakpoint names are not allowed"); + error.SetErrorString("Empty breakpoint names are not allowed"); return false; } diff --git a/gnu/llvm/lldb/source/Breakpoint/BreakpointIDList.cpp b/gnu/llvm/lldb/source/Breakpoint/BreakpointIDList.cpp index 705bc5ee1c8..172674dc2dd 100644 --- a/gnu/llvm/lldb/source/Breakpoint/BreakpointIDList.cpp +++ b/gnu/llvm/lldb/source/Breakpoint/BreakpointIDList.cpp @@ -141,7 +141,6 @@ void BreakpointIDList::FindAndReplaceIDRanges(Args &old_args, Target *target, if (!error.Success()) { new_args.Clear(); result.AppendError(error.AsCString()); - result.SetStatus(eReturnStatusFailed); return; } else names_found.insert(std::string(current_arg)); @@ -170,7 +169,6 @@ void BreakpointIDList::FindAndReplaceIDRanges(Args &old_args, Target *target, new_args.Clear(); result.AppendErrorWithFormat("'%d' is not a valid breakpoint ID.\n", bp_id->GetBreakpointID()); - result.SetStatus(eReturnStatusFailed); return; } const size_t num_locations = breakpoint_sp->GetNumLocations(); @@ -199,7 +197,6 @@ void BreakpointIDList::FindAndReplaceIDRanges(Args &old_args, Target *target, new_args.Clear(); result.AppendErrorWithFormat("'%s' is not a valid breakpoint ID.\n", range_from.str().c_str()); - result.SetStatus(eReturnStatusFailed); return; } @@ -208,7 +205,6 @@ void BreakpointIDList::FindAndReplaceIDRanges(Args &old_args, Target *target, new_args.Clear(); result.AppendErrorWithFormat("'%s' is not a valid breakpoint ID.\n", range_to.str().c_str()); - result.SetStatus(eReturnStatusFailed); return; } break_id_t start_bp_id = start_bp->GetBreakpointID(); @@ -220,11 +216,10 @@ void BreakpointIDList::FindAndReplaceIDRanges(Args &old_args, Target *target, ((start_loc_id != LLDB_INVALID_BREAK_ID) && (end_loc_id == LLDB_INVALID_BREAK_ID))) { new_args.Clear(); - result.AppendErrorWithFormat("Invalid breakpoint id range: Either " - "both ends of range must specify" - " a breakpoint location, or neither can " - "specify a breakpoint location.\n"); - result.SetStatus(eReturnStatusFailed); + result.AppendError("Invalid breakpoint id range: Either " + "both ends of range must specify" + " a breakpoint location, or neither can " + "specify a breakpoint location."); return; } @@ -247,7 +242,6 @@ void BreakpointIDList::FindAndReplaceIDRanges(Args &old_args, Target *target, " must be within the same major breakpoint; you specified two" " different major breakpoints, %d and %d.\n", start_bp_id, end_bp_id); - result.SetStatus(eReturnStatusFailed); return; } } diff --git a/gnu/llvm/lldb/source/Breakpoint/BreakpointList.cpp b/gnu/llvm/lldb/source/Breakpoint/BreakpointList.cpp index a962703b951..a00f6bed618 100644 --- a/gnu/llvm/lldb/source/Breakpoint/BreakpointList.cpp +++ b/gnu/llvm/lldb/source/Breakpoint/BreakpointList.cpp @@ -26,7 +26,7 @@ BreakpointList::BreakpointList(bool is_internal) : m_mutex(), m_breakpoints(), m_next_break_id(0), m_is_internal(is_internal) {} -BreakpointList::~BreakpointList() {} +BreakpointList::~BreakpointList() = default; break_id_t BreakpointList::Add(BreakpointSP &bp_sp, bool notify) { std::lock_guard guard(m_mutex); diff --git a/gnu/llvm/lldb/source/Breakpoint/BreakpointLocation.cpp b/gnu/llvm/lldb/source/Breakpoint/BreakpointLocation.cpp index 93d54c051ee..0c4d3e052c5 100644 --- a/gnu/llvm/lldb/source/Breakpoint/BreakpointLocation.cpp +++ b/gnu/llvm/lldb/source/Breakpoint/BreakpointLocation.cpp @@ -31,11 +31,10 @@ using namespace lldb_private; BreakpointLocation::BreakpointLocation(break_id_t loc_id, Breakpoint &owner, const Address &addr, lldb::tid_t tid, bool hardware, bool check_for_resolver) - : StoppointLocation(loc_id, addr.GetOpcodeLoadAddress(&owner.GetTarget()), - hardware), - m_being_created(true), m_should_resolve_indirect_functions(false), + : m_being_created(true), m_should_resolve_indirect_functions(false), m_is_reexported(false), m_is_indirect(false), m_address(addr), - m_owner(owner), m_options_up(), m_bp_site_sp(), m_condition_mutex() { + m_owner(owner), m_options_up(), m_bp_site_sp(), m_condition_mutex(), + m_condition_hash(0), m_loc_id(loc_id), m_hit_counter() { if (check_for_resolver) { Symbol *symbol = m_address.CalculateSymbolContextSymbol(); if (symbol && symbol->IsIndirect()) { @@ -53,11 +52,10 @@ lldb::addr_t BreakpointLocation::GetLoadAddress() const { return m_address.GetOpcodeLoadAddress(&m_owner.GetTarget()); } -const BreakpointOptions * -BreakpointLocation::GetOptionsSpecifyingKind(BreakpointOptions::OptionKind kind) -const { +const BreakpointOptions &BreakpointLocation::GetOptionsSpecifyingKind( + BreakpointOptions::OptionKind kind) const { if (m_options_up && m_options_up->IsOptionSet(kind)) - return m_options_up.get(); + return *m_options_up; else return m_owner.GetOptions(); } @@ -78,7 +76,7 @@ bool BreakpointLocation::IsEnabled() const { } void BreakpointLocation::SetEnabled(bool enabled) { - GetLocationOptions()->SetEnabled(enabled); + GetLocationOptions().SetEnabled(enabled); if (enabled) { ResolveBreakpointSite(); } else { @@ -97,13 +95,13 @@ bool BreakpointLocation::IsAutoContinue() const { } void BreakpointLocation::SetAutoContinue(bool auto_continue) { - GetLocationOptions()->SetAutoContinue(auto_continue); + GetLocationOptions().SetAutoContinue(auto_continue); SendBreakpointLocationChangedEvent(eBreakpointEventTypeAutoContinueChanged); } void BreakpointLocation::SetThreadID(lldb::tid_t thread_id) { if (thread_id != LLDB_INVALID_THREAD_ID) - GetLocationOptions()->SetThreadID(thread_id); + GetLocationOptions().SetThreadID(thread_id); else { // If we're resetting this to an invalid thread id, then don't make an // options pointer just to do that. @@ -114,9 +112,9 @@ void BreakpointLocation::SetThreadID(lldb::tid_t thread_id) { } lldb::tid_t BreakpointLocation::GetThreadID() { - const ThreadSpec *thread_spec = + const ThreadSpec *thread_spec = GetOptionsSpecifyingKind(BreakpointOptions::eThreadSpec) - ->GetThreadSpecNoCreate(); + .GetThreadSpecNoCreate(); if (thread_spec) return thread_spec->GetTID(); else @@ -125,7 +123,7 @@ lldb::tid_t BreakpointLocation::GetThreadID() { void BreakpointLocation::SetThreadIndex(uint32_t index) { if (index != 0) - GetLocationOptions()->GetThreadSpec()->SetIndex(index); + GetLocationOptions().GetThreadSpec()->SetIndex(index); else { // If we're resetting this to an invalid thread id, then don't make an // options pointer just to do that. @@ -136,9 +134,9 @@ void BreakpointLocation::SetThreadIndex(uint32_t index) { } uint32_t BreakpointLocation::GetThreadIndex() const { - const ThreadSpec *thread_spec = + const ThreadSpec *thread_spec = GetOptionsSpecifyingKind(BreakpointOptions::eThreadSpec) - ->GetThreadSpecNoCreate(); + .GetThreadSpecNoCreate(); if (thread_spec) return thread_spec->GetIndex(); else @@ -147,7 +145,7 @@ uint32_t BreakpointLocation::GetThreadIndex() const { void BreakpointLocation::SetThreadName(const char *thread_name) { if (thread_name != nullptr) - GetLocationOptions()->GetThreadSpec()->SetName(thread_name); + GetLocationOptions().GetThreadSpec()->SetName(thread_name); else { // If we're resetting this to an invalid thread id, then don't make an // options pointer just to do that. @@ -158,9 +156,9 @@ void BreakpointLocation::SetThreadName(const char *thread_name) { } const char *BreakpointLocation::GetThreadName() const { - const ThreadSpec *thread_spec = + const ThreadSpec *thread_spec = GetOptionsSpecifyingKind(BreakpointOptions::eThreadSpec) - ->GetThreadSpecNoCreate(); + .GetThreadSpecNoCreate(); if (thread_spec) return thread_spec->GetName(); else @@ -169,7 +167,7 @@ const char *BreakpointLocation::GetThreadName() const { void BreakpointLocation::SetQueueName(const char *queue_name) { if (queue_name != nullptr) - GetLocationOptions()->GetThreadSpec()->SetQueueName(queue_name); + GetLocationOptions().GetThreadSpec()->SetQueueName(queue_name); else { // If we're resetting this to an invalid thread id, then don't make an // options pointer just to do that. @@ -180,9 +178,9 @@ void BreakpointLocation::SetQueueName(const char *queue_name) { } const char *BreakpointLocation::GetQueueName() const { - const ThreadSpec *thread_spec = + const ThreadSpec *thread_spec = GetOptionsSpecifyingKind(BreakpointOptions::eThreadSpec) - ->GetThreadSpecNoCreate(); + .GetThreadSpecNoCreate(); if (thread_spec) return thread_spec->GetQueueName(); else @@ -196,11 +194,18 @@ bool BreakpointLocation::InvokeCallback(StoppointCallbackContext *context) { return m_owner.InvokeCallback(context, GetID()); } +bool BreakpointLocation::IsCallbackSynchronous() { + if (m_options_up != nullptr && m_options_up->HasCallback()) + return m_options_up->IsCallbackSynchronous(); + else + return m_owner.GetOptions().IsCallbackSynchronous(); +} + void BreakpointLocation::SetCallback(BreakpointHitCallback callback, void *baton, bool is_synchronous) { // The default "Baton" class will keep a copy of "baton" and won't free or // delete it when it goes goes out of scope. - GetLocationOptions()->SetCallback( + GetLocationOptions().SetCallback( callback, std::make_shared(baton), is_synchronous); SendBreakpointLocationChangedEvent(eBreakpointEventTypeCommandChanged); } @@ -208,22 +213,22 @@ void BreakpointLocation::SetCallback(BreakpointHitCallback callback, void BreakpointLocation::SetCallback(BreakpointHitCallback callback, const BatonSP &baton_sp, bool is_synchronous) { - GetLocationOptions()->SetCallback(callback, baton_sp, is_synchronous); + GetLocationOptions().SetCallback(callback, baton_sp, is_synchronous); SendBreakpointLocationChangedEvent(eBreakpointEventTypeCommandChanged); } void BreakpointLocation::ClearCallback() { - GetLocationOptions()->ClearCallback(); + GetLocationOptions().ClearCallback(); } void BreakpointLocation::SetCondition(const char *condition) { - GetLocationOptions()->SetCondition(condition); + GetLocationOptions().SetCondition(condition); SendBreakpointLocationChangedEvent(eBreakpointEventTypeConditionChanged); } const char *BreakpointLocation::GetConditionText(size_t *hash) const { return GetOptionsSpecifyingKind(BreakpointOptions::eCondition) - ->GetConditionText(hash); + .GetConditionText(hash); } bool BreakpointLocation::ConditionSaysStop(ExecutionContext &exe_ctx, @@ -332,13 +337,13 @@ bool BreakpointLocation::ConditionSaysStop(ExecutionContext &exe_ctx, return ret; } -uint32_t BreakpointLocation::GetIgnoreCount() { +uint32_t BreakpointLocation::GetIgnoreCount() const { return GetOptionsSpecifyingKind(BreakpointOptions::eIgnoreCount) - ->GetIgnoreCount(); + .GetIgnoreCount(); } void BreakpointLocation::SetIgnoreCount(uint32_t n) { - GetLocationOptions()->SetIgnoreCount(n); + GetLocationOptions().SetIgnoreCount(n); SendBreakpointLocationChangedEvent(eBreakpointEventTypeIgnoreChanged); } @@ -351,33 +356,34 @@ void BreakpointLocation::DecrementIgnoreCount() { } bool BreakpointLocation::IgnoreCountShouldStop() { - if (m_options_up != nullptr) { - uint32_t loc_ignore = m_options_up->GetIgnoreCount(); - if (loc_ignore != 0) { - m_owner.DecrementIgnoreCount(); - DecrementIgnoreCount(); // Have to decrement our owners' ignore count, - // since it won't get a - // chance to. - return false; - } + uint32_t owner_ignore = GetBreakpoint().GetIgnoreCount(); + uint32_t loc_ignore = 0; + if (m_options_up != nullptr) + loc_ignore = m_options_up->GetIgnoreCount(); + + if (loc_ignore != 0 || owner_ignore != 0) { + m_owner.DecrementIgnoreCount(); + DecrementIgnoreCount(); // Have to decrement our owners' ignore count, + // since it won't get a chance to. + return false; } return true; } -BreakpointOptions *BreakpointLocation::GetLocationOptions() { +BreakpointOptions &BreakpointLocation::GetLocationOptions() { // If we make the copy we don't copy the callbacks because that is // potentially expensive and we don't want to do that for the simple case // where someone is just disabling the location. if (m_options_up == nullptr) m_options_up = std::make_unique(false); - return m_options_up.get(); + return *m_options_up; } -bool BreakpointLocation::ValidForThisThread(Thread *thread) { - return thread - ->MatchesSpec(GetOptionsSpecifyingKind(BreakpointOptions::eThreadSpec) - ->GetThreadSpecNoCreate()); +bool BreakpointLocation::ValidForThisThread(Thread &thread) { + return thread.MatchesSpec( + GetOptionsSpecifyingKind(BreakpointOptions::eThreadSpec) + .GetThreadSpecNoCreate()); } // RETURNS - true if we should stop at this breakpoint, false if we @@ -394,12 +400,6 @@ bool BreakpointLocation::ShouldStop(StoppointCallbackContext *context) { if (!IsEnabled()) return false; - if (!IgnoreCountShouldStop()) - return false; - - if (!m_owner.IgnoreCountShouldStop()) - return false; - // We only run synchronous callbacks in ShouldStop: context->is_synchronous = true; should_stop = InvokeCallback(context); @@ -417,16 +417,16 @@ bool BreakpointLocation::ShouldStop(StoppointCallbackContext *context) { void BreakpointLocation::BumpHitCount() { if (IsEnabled()) { // Step our hit count, and also step the hit count of the owner. - IncrementHitCount(); - m_owner.IncrementHitCount(); + m_hit_counter.Increment(); + m_owner.m_hit_counter.Increment(); } } void BreakpointLocation::UndoBumpHitCount() { if (IsEnabled()) { // Step our hit count, and also step the hit count of the owner. - DecrementHitCount(); - m_owner.DecrementHitCount(); + m_hit_counter.Decrement(); + m_owner.m_hit_counter.Decrement(); } } @@ -593,12 +593,15 @@ void BreakpointLocation::GetDescription(Stream *s, } } + bool is_resolved = IsResolved(); + bool is_hardware = is_resolved && m_bp_site_sp->IsHardware(); + if (level == lldb::eDescriptionLevelVerbose) { s->EOL(); s->Indent(); - s->Printf("resolved = %s\n", IsResolved() ? "true" : "false"); + s->Printf("resolved = %s\n", is_resolved ? "true" : "false"); s->Indent(); - s->Printf("hardware = %s\n", IsHardware() ? "true" : "false"); + s->Printf("hardware = %s\n", is_hardware ? "true" : "false"); s->Indent(); s->Printf("hit count = %-4u\n", GetHitCount()); @@ -609,8 +612,8 @@ void BreakpointLocation::GetDescription(Stream *s, } s->IndentLess(); } else if (level != eDescriptionLevelInitial) { - s->Printf(", %sresolved, %shit count = %u ", (IsResolved() ? "" : "un"), - (IsHardware() ? "hardware, " : ""), GetHitCount()); + s->Printf(", %sresolved, %shit count = %u ", (is_resolved ? "" : "un"), + (is_hardware ? "hardware, " : ""), GetHitCount()); if (m_options_up) { m_options_up->GetDescription(s, level); } @@ -621,8 +624,14 @@ void BreakpointLocation::Dump(Stream *s) const { if (s == nullptr) return; + bool is_resolved = IsResolved(); + bool is_hardware = is_resolved && m_bp_site_sp->IsHardware(); + auto hardware_index = is_resolved ? + m_bp_site_sp->GetHardwareIndex() : LLDB_INVALID_INDEX32; + lldb::tid_t tid = GetOptionsSpecifyingKind(BreakpointOptions::eThreadSpec) - ->GetThreadSpecNoCreate()->GetTID(); + .GetThreadSpecNoCreate() + ->GetTID(); s->Printf("BreakpointLocation %u: tid = %4.4" PRIx64 " load addr = 0x%8.8" PRIx64 " state = %s type = %s breakpoint " "hw_index = %i hit_count = %-4u ignore_count = %-4u", @@ -631,10 +640,10 @@ void BreakpointLocation::Dump(Stream *s) const { (m_options_up ? m_options_up->IsEnabled() : m_owner.IsEnabled()) ? "enabled " : "disabled", - IsHardware() ? "hardware" : "software", GetHardwareIndex(), + is_hardware ? "hardware" : "software", hardware_index, GetHitCount(), GetOptionsSpecifyingKind(BreakpointOptions::eIgnoreCount) - ->GetIgnoreCount()); + .GetIgnoreCount()); } void BreakpointLocation::SendBreakpointLocationChangedEvent( diff --git a/gnu/llvm/lldb/source/Breakpoint/BreakpointLocationCollection.cpp b/gnu/llvm/lldb/source/Breakpoint/BreakpointLocationCollection.cpp index 1eb13cb12ba..6c55629b5aa 100644 --- a/gnu/llvm/lldb/source/Breakpoint/BreakpointLocationCollection.cpp +++ b/gnu/llvm/lldb/source/Breakpoint/BreakpointLocationCollection.cpp @@ -21,7 +21,7 @@ BreakpointLocationCollection::BreakpointLocationCollection() : m_break_loc_collection(), m_collection_mutex() {} // Destructor -BreakpointLocationCollection::~BreakpointLocationCollection() {} +BreakpointLocationCollection::~BreakpointLocationCollection() = default; void BreakpointLocationCollection::Add(const BreakpointLocationSP &bp_loc) { std::lock_guard guard(m_collection_mutex); @@ -134,7 +134,7 @@ bool BreakpointLocationCollection::ShouldStop( return shouldStop; } -bool BreakpointLocationCollection::ValidForThisThread(Thread *thread) { +bool BreakpointLocationCollection::ValidForThisThread(Thread &thread) { std::lock_guard guard(m_collection_mutex); collection::iterator pos, begin = m_break_loc_collection.begin(), end = m_break_loc_collection.end(); diff --git a/gnu/llvm/lldb/source/Breakpoint/BreakpointName.cpp b/gnu/llvm/lldb/source/Breakpoint/BreakpointName.cpp index 37903a00236..cb513fb436d 100644 --- a/gnu/llvm/lldb/source/Breakpoint/BreakpointName.cpp +++ b/gnu/llvm/lldb/source/Breakpoint/BreakpointName.cpp @@ -81,6 +81,6 @@ bool BreakpointName::GetDescription(Stream *s, lldb::DescriptionLevel level) { void BreakpointName::ConfigureBreakpoint(lldb::BreakpointSP bp_sp) { - bp_sp->GetOptions()->CopyOverSetOptions(GetOptions()); - bp_sp->GetPermissions().MergeInto(GetPermissions()); + bp_sp->GetOptions().CopyOverSetOptions(GetOptions()); + bp_sp->GetPermissions().MergeInto(GetPermissions()); } diff --git a/gnu/llvm/lldb/source/Breakpoint/BreakpointOptions.cpp b/gnu/llvm/lldb/source/Breakpoint/BreakpointOptions.cpp index 0ce7b0f852e..86a7c483df8 100644 --- a/gnu/llvm/lldb/source/Breakpoint/BreakpointOptions.cpp +++ b/gnu/llvm/lldb/source/Breakpoint/BreakpointOptions.cpp @@ -319,7 +319,7 @@ std::unique_ptr BreakpointOptions::CreateFromStructuredData( else { ScriptInterpreter *interp = target.GetDebugger().GetScriptInterpreter(); if (!interp) { - error.SetErrorStringWithFormat( + error.SetErrorString( "Can't set script commands - no script interpreter"); return nullptr; } @@ -332,7 +332,7 @@ std::unique_ptr BreakpointOptions::CreateFromStructuredData( } Status script_error; script_error = - interp->SetBreakpointCommandCallback(bp_options.get(), cmd_data_up); + interp->SetBreakpointCommandCallback(*bp_options, cmd_data_up); if (script_error.Fail()) { error.SetErrorStringWithFormat("Error generating script callback: %s.", error.AsCString()); @@ -453,8 +453,6 @@ bool BreakpointOptions::InvokeCallback(StoppointCallbackContext *context, : nullptr, context, break_id, break_loc_id); } else if (IsCallbackSynchronous()) { - // If a synchronous callback is called at async time, it should not say - // to stop. return false; } } @@ -649,7 +647,7 @@ bool BreakpointOptions::BreakpointOptionsCallbackFunction( options.SetPrintErrors(true); options.SetAddToHistory(false); - debugger.GetCommandInterpreter().HandleCommands(commands, &exe_ctx, + debugger.GetCommandInterpreter().HandleCommands(commands, exe_ctx, options, result); result.GetImmediateOutputStream()->Flush(); result.GetImmediateErrorStream()->Flush(); diff --git a/gnu/llvm/lldb/source/Breakpoint/BreakpointResolver.cpp b/gnu/llvm/lldb/source/Breakpoint/BreakpointResolver.cpp index 7c03a0745ac..d3d57a282d0 100644 --- a/gnu/llvm/lldb/source/Breakpoint/BreakpointResolver.cpp +++ b/gnu/llvm/lldb/source/Breakpoint/BreakpointResolver.cpp @@ -65,7 +65,7 @@ BreakpointResolver::BreakpointResolver(const BreakpointSP &bkpt, lldb::addr_t offset) : m_breakpoint(bkpt), m_offset(offset), SubclassID(resolverTy) {} -BreakpointResolver::~BreakpointResolver() {} +BreakpointResolver::~BreakpointResolver() = default; BreakpointResolverSP BreakpointResolver::CreateFromStructuredData( const StructuredData::Dictionary &resolver_dict, Status &error) { @@ -81,8 +81,7 @@ BreakpointResolverSP BreakpointResolver::CreateFromStructuredData( GetSerializationSubclassKey(), subclass_name); if (!success) { - error.SetErrorStringWithFormat( - "Resolver data missing subclass resolver key"); + error.SetErrorString("Resolver data missing subclass resolver key"); return result_sp; } @@ -181,29 +180,29 @@ void BreakpointResolver::ResolveBreakpoint(SearchFilter &filter) { namespace { struct SourceLoc { uint32_t line = UINT32_MAX; - uint32_t column; - SourceLoc(uint32_t l, uint32_t c) : line(l), column(c ? c : UINT32_MAX) {} + uint16_t column; + SourceLoc(uint32_t l, llvm::Optional c) + : line(l), column(c ? *c : LLDB_INVALID_COLUMN_NUMBER) {} SourceLoc(const SymbolContext &sc) : line(sc.line_entry.line), - column(sc.line_entry.column ? sc.line_entry.column : UINT32_MAX) {} + column(sc.line_entry.column ? sc.line_entry.column + : LLDB_INVALID_COLUMN_NUMBER) {} }; -bool operator<(const SourceLoc a, const SourceLoc b) { - if (a.line < b.line) +bool operator<(const SourceLoc lhs, const SourceLoc rhs) { + if (lhs.line < rhs.line) return true; - if (a.line > b.line) + if (lhs.line > rhs.line) return false; - uint32_t a_col = a.column ? a.column : UINT32_MAX; - uint32_t b_col = b.column ? b.column : UINT32_MAX; - return a_col < b_col; + // uint32_t a_col = lhs.column ? lhs.column : LLDB_INVALID_COLUMN_NUMBER; + // uint32_t b_col = rhs.column ? rhs.column : LLDB_INVALID_COLUMN_NUMBER; + return lhs.column < rhs.column; } } // namespace -void BreakpointResolver::SetSCMatchesByLine(SearchFilter &filter, - SymbolContextList &sc_list, - bool skip_prologue, - llvm::StringRef log_ident, - uint32_t line, uint32_t column) { +void BreakpointResolver::SetSCMatchesByLine( + SearchFilter &filter, SymbolContextList &sc_list, bool skip_prologue, + llvm::StringRef log_ident, uint32_t line, llvm::Optional column) { llvm::SmallVector all_scs; for (uint32_t i = 0; i < sc_list.GetSize(); ++i) all_scs.push_back(sc_list[i]); @@ -229,13 +228,13 @@ void BreakpointResolver::SetSCMatchesByLine(SearchFilter &filter, if (column) { // If a column was requested, do a more precise match and only - // return the first location that comes after or at the + // return the first location that comes before or at the // requested location. - SourceLoc requested(line, column); + SourceLoc requested(line, *column); // First, filter out all entries left of the requested column. worklist_end = std::remove_if( worklist_begin, worklist_end, - [&](const SymbolContext &sc) { return SourceLoc(sc) < requested; }); + [&](const SymbolContext &sc) { return requested < SourceLoc(sc); }); // Sort the remaining entries by (line, column). llvm::sort(worklist_begin, worklist_end, [](const SymbolContext &a, const SymbolContext &b) { diff --git a/gnu/llvm/lldb/source/Breakpoint/BreakpointResolverAddress.cpp b/gnu/llvm/lldb/source/Breakpoint/BreakpointResolverAddress.cpp index 2c56912b56a..3187e8464f6 100644 --- a/gnu/llvm/lldb/source/Breakpoint/BreakpointResolverAddress.cpp +++ b/gnu/llvm/lldb/source/Breakpoint/BreakpointResolverAddress.cpp @@ -87,7 +87,6 @@ BreakpointResolverAddress::SerializeToStructuredData() { } return WrapOptionsDict(options_dict_sp); - return StructuredData::ObjectSP(); } void BreakpointResolverAddress::ResolveBreakpoint(SearchFilter &filter) { diff --git a/gnu/llvm/lldb/source/Breakpoint/BreakpointResolverFileLine.cpp b/gnu/llvm/lldb/source/Breakpoint/BreakpointResolverFileLine.cpp index 22a4b4ae33a..1d1ac2e90bd 100644 --- a/gnu/llvm/lldb/source/Breakpoint/BreakpointResolverFileLine.cpp +++ b/gnu/llvm/lldb/source/Breakpoint/BreakpointResolverFileLine.cpp @@ -20,20 +20,17 @@ using namespace lldb_private; // BreakpointResolverFileLine: BreakpointResolverFileLine::BreakpointResolverFileLine( - const BreakpointSP &bkpt, const FileSpec &file_spec, uint32_t line_no, - uint32_t column, lldb::addr_t offset, bool check_inlines, - bool skip_prologue, bool exact_match) + const BreakpointSP &bkpt, lldb::addr_t offset, bool skip_prologue, + const SourceLocationSpec &location_spec) : BreakpointResolver(bkpt, BreakpointResolver::FileLineResolver, offset), - m_file_spec(file_spec), m_line_number(line_no), m_column(column), - m_inlines(check_inlines), m_skip_prologue(skip_prologue), - m_exact_match(exact_match) {} + m_location_spec(location_spec), m_skip_prologue(skip_prologue) {} BreakpointResolver *BreakpointResolverFileLine::CreateFromStructuredData( const BreakpointSP &bkpt, const StructuredData::Dictionary &options_dict, Status &error) { llvm::StringRef filename; - uint32_t line_no; - uint32_t column; + uint32_t line; + uint16_t column; bool check_inlines; bool skip_prologue; bool exact_match; @@ -49,7 +46,7 @@ BreakpointResolver *BreakpointResolverFileLine::CreateFromStructuredData( } success = options_dict.GetValueForKeyAsInteger( - GetKey(OptionNames::LineNumber), line_no); + GetKey(OptionNames::LineNumber), line); if (!success) { error.SetErrorString("BRFL::CFSD: Couldn't find line number entry."); return nullptr; @@ -83,11 +80,13 @@ BreakpointResolver *BreakpointResolverFileLine::CreateFromStructuredData( return nullptr; } - FileSpec file_spec(filename); + SourceLocationSpec location_spec(FileSpec(filename), line, column, + check_inlines, exact_match); + if (!location_spec) + return nullptr; - return new BreakpointResolverFileLine(bkpt, file_spec, line_no, column, - offset, check_inlines, skip_prologue, - exact_match); + return new BreakpointResolverFileLine(bkpt, offset, skip_prologue, + location_spec); } StructuredData::ObjectSP @@ -95,17 +94,19 @@ BreakpointResolverFileLine::SerializeToStructuredData() { StructuredData::DictionarySP options_dict_sp( new StructuredData::Dictionary()); - options_dict_sp->AddStringItem(GetKey(OptionNames::FileName), - m_file_spec.GetPath()); - options_dict_sp->AddIntegerItem(GetKey(OptionNames::LineNumber), - m_line_number); - options_dict_sp->AddIntegerItem(GetKey(OptionNames::Column), - m_column); - options_dict_sp->AddBooleanItem(GetKey(OptionNames::Inlines), m_inlines); options_dict_sp->AddBooleanItem(GetKey(OptionNames::SkipPrologue), m_skip_prologue); + options_dict_sp->AddStringItem(GetKey(OptionNames::FileName), + m_location_spec.GetFileSpec().GetPath()); + options_dict_sp->AddIntegerItem(GetKey(OptionNames::LineNumber), + m_location_spec.GetLine().getValueOr(0)); + options_dict_sp->AddIntegerItem( + GetKey(OptionNames::Column), + m_location_spec.GetColumn().getValueOr(LLDB_INVALID_COLUMN_NUMBER)); + options_dict_sp->AddBooleanItem(GetKey(OptionNames::Inlines), + m_location_spec.GetCheckInlines()); options_dict_sp->AddBooleanItem(GetKey(OptionNames::ExactMatch), - m_exact_match); + m_location_spec.GetExactMatch()); return WrapOptionsDict(options_dict_sp); } @@ -119,12 +120,12 @@ BreakpointResolverFileLine::SerializeToStructuredData() { // inlined into. void BreakpointResolverFileLine::FilterContexts(SymbolContextList &sc_list, bool is_relative) { - if (m_exact_match) + if (m_location_spec.GetExactMatch()) return; // Nothing to do. Contexts are precise. llvm::StringRef relative_path; if (is_relative) - relative_path = m_file_spec.GetDirectory().GetStringRef(); + relative_path = m_location_spec.GetFileSpec().GetDirectory().GetStringRef(); Log * log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_BREAKPOINTS); for(uint32_t i = 0; i < sc_list.GetSize(); ++i) { @@ -187,8 +188,17 @@ void BreakpointResolverFileLine::FilterContexts(SymbolContextList &sc_list, // is 0, then we can't do this calculation. That can happen if // GetStartLineSourceInfo gets an error, or if the first line number in // the function really is 0 - which happens for some languages. + + // But only do this calculation if the line number we found in the SC + // was different from the one requested in the source file. If we actually + // found an exact match it must be valid. + + if (m_location_spec.GetLine() == sc.line_entry.line) + continue; + const int decl_line_is_too_late_fudge = 1; - if (line && m_line_number < line - decl_line_is_too_late_fudge) { + if (line && + m_location_spec.GetLine() < line - decl_line_is_too_late_fudge) { LLDB_LOG(log, "removing symbol context at {0}:{1}", file, line); sc_list.RemoveContextAtIndex(i); --i; @@ -216,8 +226,11 @@ Searcher::CallbackReturn BreakpointResolverFileLine::SearchCallback( // file. So we go through the match list and pull out the sets that have the // same file spec in their line_entry and treat each set separately. - FileSpec search_file_spec = m_file_spec; - const bool is_relative = m_file_spec.IsRelative(); + const uint32_t line = m_location_spec.GetLine().getValueOr(0); + const llvm::Optional column = m_location_spec.GetColumn(); + + FileSpec search_file_spec = m_location_spec.GetFileSpec(); + const bool is_relative = search_file_spec.IsRelative(); if (is_relative) search_file_spec.GetDirectory().Clear(); @@ -226,8 +239,7 @@ Searcher::CallbackReturn BreakpointResolverFileLine::SearchCallback( CompUnitSP cu_sp(context.module_sp->GetCompileUnitAtIndex(i)); if (cu_sp) { if (filter.CompUnitPasses(*cu_sp)) - cu_sp->ResolveSymbolContext(search_file_spec, m_line_number, m_inlines, - m_exact_match, eSymbolContextEverything, + cu_sp->ResolveSymbolContext(m_location_spec, eSymbolContextEverything, sc_list); } } @@ -235,11 +247,12 @@ Searcher::CallbackReturn BreakpointResolverFileLine::SearchCallback( FilterContexts(sc_list, is_relative); StreamString s; - s.Printf("for %s:%d ", m_file_spec.GetFilename().AsCString(""), - m_line_number); + s.Printf("for %s:%d ", + m_location_spec.GetFileSpec().GetFilename().AsCString(""), + line); - SetSCMatchesByLine(filter, sc_list, m_skip_prologue, s.GetString(), - m_line_number, m_column); + SetSCMatchesByLine(filter, sc_list, m_skip_prologue, s.GetString(), line, + column); return Searcher::eCallbackReturnContinue; } @@ -249,11 +262,13 @@ lldb::SearchDepth BreakpointResolverFileLine::GetDepth() { } void BreakpointResolverFileLine::GetDescription(Stream *s) { - s->Printf("file = '%s', line = %u, ", m_file_spec.GetPath().c_str(), - m_line_number); - if (m_column) - s->Printf("column = %u, ", m_column); - s->Printf("exact_match = %d", m_exact_match); + s->Printf("file = '%s', line = %u, ", + m_location_spec.GetFileSpec().GetPath().c_str(), + m_location_spec.GetLine().getValueOr(0)); + auto column = m_location_spec.GetColumn(); + if (column) + s->Printf("column = %u, ", *column); + s->Printf("exact_match = %d", m_location_spec.GetExactMatch()); } void BreakpointResolverFileLine::Dump(Stream *s) const {} @@ -261,8 +276,7 @@ void BreakpointResolverFileLine::Dump(Stream *s) const {} lldb::BreakpointResolverSP BreakpointResolverFileLine::CopyForBreakpoint(BreakpointSP &breakpoint) { lldb::BreakpointResolverSP ret_sp(new BreakpointResolverFileLine( - breakpoint, m_file_spec, m_line_number, m_column, GetOffset(), m_inlines, - m_skip_prologue, m_exact_match)); + breakpoint, GetOffset(), m_skip_prologue, m_location_spec)); return ret_sp; } diff --git a/gnu/llvm/lldb/source/Breakpoint/BreakpointResolverFileRegex.cpp b/gnu/llvm/lldb/source/Breakpoint/BreakpointResolverFileRegex.cpp index 62462b2f544..435983769c0 100644 --- a/gnu/llvm/lldb/source/Breakpoint/BreakpointResolverFileRegex.cpp +++ b/gnu/llvm/lldb/source/Breakpoint/BreakpointResolverFileRegex.cpp @@ -107,10 +107,11 @@ Searcher::CallbackReturn BreakpointResolverFileRegex::SearchCallback( uint32_t num_matches = line_matches.size(); for (uint32_t i = 0; i < num_matches; i++) { SymbolContextList sc_list; - const bool search_inlines = false; - - cu->ResolveSymbolContext(cu_file_spec, line_matches[i], search_inlines, - m_exact_match, eSymbolContextEverything, sc_list); + // TODO: Handle SourceLocationSpec column information + SourceLocationSpec location_spec(cu_file_spec, line_matches[i], + /*column=*/llvm::None, + /*search_inlines=*/false, m_exact_match); + cu->ResolveSymbolContext(location_spec, eSymbolContextEverything, sc_list); // Find all the function names: if (!m_function_names.empty()) { std::vector sc_to_remove; diff --git a/gnu/llvm/lldb/source/Breakpoint/BreakpointResolverName.cpp b/gnu/llvm/lldb/source/Breakpoint/BreakpointResolverName.cpp index 25f5bb3f6ee..121ac5690d7 100644 --- a/gnu/llvm/lldb/source/Breakpoint/BreakpointResolverName.cpp +++ b/gnu/llvm/lldb/source/Breakpoint/BreakpointResolverName.cpp @@ -31,7 +31,7 @@ BreakpointResolverName::BreakpointResolverName(const BreakpointSP &bkpt, m_class_name(), m_regex(), m_match_type(type), m_language(language), m_skip_prologue(skip_prologue) { if (m_match_type == Breakpoint::Regexp) { - m_regex = RegularExpression(llvm::StringRef::withNullAsEmpty(name_cstr)); + m_regex = RegularExpression(name_cstr); if (!m_regex.IsValid()) { Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_BREAKPOINTS)); @@ -108,7 +108,7 @@ BreakpointResolver *BreakpointResolverName::CreateFromStructuredData( success = options_dict.GetValueForKeyAsInteger(GetKey(OptionNames::Offset), offset); if (!success) { - error.SetErrorStringWithFormat("BRN::CFSD: Missing offset entry."); + error.SetErrorString("BRN::CFSD: Missing offset entry."); return nullptr; } @@ -116,7 +116,7 @@ BreakpointResolver *BreakpointResolverName::CreateFromStructuredData( success = options_dict.GetValueForKeyAsBoolean( GetKey(OptionNames::SkipPrologue), skip_prologue); if (!success) { - error.SetErrorStringWithFormat("BRN::CFSD: Missing Skip prologue entry."); + error.SetErrorString("BRN::CFSD: Missing Skip prologue entry."); return nullptr; } @@ -131,15 +131,14 @@ BreakpointResolver *BreakpointResolverName::CreateFromStructuredData( success = options_dict.GetValueForKeyAsArray( GetKey(OptionNames::SymbolNameArray), names_array); if (!success) { - error.SetErrorStringWithFormat("BRN::CFSD: Missing symbol names entry."); + error.SetErrorString("BRN::CFSD: Missing symbol names entry."); return nullptr; } StructuredData::Array *names_mask_array; success = options_dict.GetValueForKeyAsArray( GetKey(OptionNames::NameMaskArray), names_mask_array); if (!success) { - error.SetErrorStringWithFormat( - "BRN::CFSD: Missing symbol names mask entry."); + error.SetErrorString("BRN::CFSD: Missing symbol names mask entry."); return nullptr; } @@ -221,11 +220,15 @@ void BreakpointResolverName::AddNameLookup(ConstString name, m_lookups.emplace_back(lookup); auto add_variant_funcs = [&](Language *lang) { - for (ConstString variant_name : lang->GetMethodNameVariants(name)) { - Module::LookupInfo variant_lookup(name, name_type_mask, - lang->GetLanguageType()); - variant_lookup.SetLookupName(variant_name); - m_lookups.emplace_back(variant_lookup); + for (Language::MethodNameVariant variant : + lang->GetMethodNameVariants(name)) { + // FIXME: Should we be adding variants that aren't of type Full? + if (variant.GetType() & lldb::eFunctionNameTypeFull) { + Module::LookupInfo variant_lookup(name, variant.GetType(), + lang->GetLanguageType()); + variant_lookup.SetLookupName(variant.GetName()); + m_lookups.emplace_back(variant_lookup); + } } return true; }; diff --git a/gnu/llvm/lldb/source/Breakpoint/BreakpointSite.cpp b/gnu/llvm/lldb/source/Breakpoint/BreakpointSite.cpp index a33fd0a1c46..f0469326657 100644 --- a/gnu/llvm/lldb/source/Breakpoint/BreakpointSite.cpp +++ b/gnu/llvm/lldb/source/Breakpoint/BreakpointSite.cpp @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// -#include +#include #include "lldb/Breakpoint/BreakpointSite.h" @@ -21,7 +21,7 @@ using namespace lldb_private; BreakpointSite::BreakpointSite(BreakpointSiteList *list, const BreakpointLocationSP &owner, lldb::addr_t addr, bool use_hardware) - : StoppointLocation(GetNextID(), addr, 0, use_hardware), + : StoppointSite(GetNextID(), addr, 0, use_hardware), m_type(eSoftware), // Process subclasses need to set this correctly using // SetType() m_saved_opcode(), m_trap_opcode(), @@ -48,7 +48,7 @@ break_id_t BreakpointSite::GetNextID() { // should continue. bool BreakpointSite::ShouldStop(StoppointCallbackContext *context) { - IncrementHitCount(); + m_hit_counter.Increment(); // ShouldStop can do a lot of work, and might even come come back and hit // this breakpoint site again. So don't hold the m_owners_mutex the whole // while. Instead make a local copy of the collection and call ShouldStop on @@ -144,7 +144,7 @@ BreakpointLocationSP BreakpointSite::GetOwnerAtIndex(size_t index) { return m_owners.GetByIndex(index); } -bool BreakpointSite::ValidForThisThread(Thread *thread) { +bool BreakpointSite::ValidForThisThread(Thread &thread) { std::lock_guard guard(m_owners_mutex); return m_owners.ValidForThisThread(thread); } @@ -156,51 +156,46 @@ void BreakpointSite::BumpHitCounts() { } } -void BreakpointSite::SetHardwareIndex(uint32_t index) { - std::lock_guard guard(m_owners_mutex); - for (BreakpointLocationSP loc_sp : m_owners.BreakpointLocations()) { - loc_sp->SetHardwareIndex(index); - } -} - bool BreakpointSite::IntersectsRange(lldb::addr_t addr, size_t size, lldb::addr_t *intersect_addr, size_t *intersect_size, size_t *opcode_offset) const { - // We only use software traps for software breakpoints - if (!IsHardware()) { - if (m_byte_size > 0) { - const lldb::addr_t bp_end_addr = m_addr + m_byte_size; - const lldb::addr_t end_addr = addr + size; - // Is the breakpoint end address before the passed in start address? - if (bp_end_addr <= addr) - return false; - // Is the breakpoint start address after passed in end address? - if (end_addr <= m_addr) - return false; - if (intersect_addr || intersect_size || opcode_offset) { - if (m_addr < addr) { - if (intersect_addr) - *intersect_addr = addr; - if (intersect_size) - *intersect_size = - std::min(bp_end_addr, end_addr) - addr; - if (opcode_offset) - *opcode_offset = addr - m_addr; - } else { - if (intersect_addr) - *intersect_addr = m_addr; - if (intersect_size) - *intersect_size = - std::min(bp_end_addr, end_addr) - m_addr; - if (opcode_offset) - *opcode_offset = 0; - } - } - return true; + // The function should be called only for software breakpoints. + lldbassert(GetType() == Type::eSoftware); + + if (m_byte_size == 0) + return false; + + const lldb::addr_t bp_end_addr = m_addr + m_byte_size; + const lldb::addr_t end_addr = addr + size; + // Is the breakpoint end address before the passed in start address? + if (bp_end_addr <= addr) + return false; + + // Is the breakpoint start address after passed in end address? + if (end_addr <= m_addr) + return false; + + if (intersect_addr || intersect_size || opcode_offset) { + if (m_addr < addr) { + if (intersect_addr) + *intersect_addr = addr; + if (intersect_size) + *intersect_size = + std::min(bp_end_addr, end_addr) - addr; + if (opcode_offset) + *opcode_offset = addr - m_addr; + } else { + if (intersect_addr) + *intersect_addr = m_addr; + if (intersect_size) + *intersect_size = + std::min(bp_end_addr, end_addr) - m_addr; + if (opcode_offset) + *opcode_offset = 0; } } - return false; + return true; } size_t diff --git a/gnu/llvm/lldb/source/Breakpoint/BreakpointSiteList.cpp b/gnu/llvm/lldb/source/Breakpoint/BreakpointSiteList.cpp index 873ba6236a7..c6966145e42 100644 --- a/gnu/llvm/lldb/source/Breakpoint/BreakpointSiteList.cpp +++ b/gnu/llvm/lldb/source/Breakpoint/BreakpointSiteList.cpp @@ -16,7 +16,7 @@ using namespace lldb_private; BreakpointSiteList::BreakpointSiteList() : m_mutex(), m_bp_site_list() {} -BreakpointSiteList::~BreakpointSiteList() {} +BreakpointSiteList::~BreakpointSiteList() = default; // Add breakpoint site to the list. However, if the element already exists in // the list, then we don't add it, and return LLDB_INVALID_BREAK_ID. diff --git a/gnu/llvm/lldb/source/Breakpoint/CMakeLists.txt b/gnu/llvm/lldb/source/Breakpoint/CMakeLists.txt index a7c0baf21af..4862c2b3640 100644 --- a/gnu/llvm/lldb/source/Breakpoint/CMakeLists.txt +++ b/gnu/llvm/lldb/source/Breakpoint/CMakeLists.txt @@ -19,7 +19,7 @@ add_lldb_library(lldbBreakpoint BreakpointSiteList.cpp Stoppoint.cpp StoppointCallbackContext.cpp - StoppointLocation.cpp + StoppointSite.cpp Watchpoint.cpp WatchpointList.cpp WatchpointOptions.cpp diff --git a/gnu/llvm/lldb/source/Breakpoint/Stoppoint.cpp b/gnu/llvm/lldb/source/Breakpoint/Stoppoint.cpp index b5c8334333c..94e97cd4542 100644 --- a/gnu/llvm/lldb/source/Breakpoint/Stoppoint.cpp +++ b/gnu/llvm/lldb/source/Breakpoint/Stoppoint.cpp @@ -14,10 +14,10 @@ using namespace lldb; using namespace lldb_private; // Stoppoint constructor -Stoppoint::Stoppoint() : m_bid(LLDB_INVALID_BREAK_ID) {} +Stoppoint::Stoppoint() = default; // Destructor -Stoppoint::~Stoppoint() {} +Stoppoint::~Stoppoint() = default; break_id_t Stoppoint::GetID() const { return m_bid; } diff --git a/gnu/llvm/lldb/source/Breakpoint/StoppointCallbackContext.cpp b/gnu/llvm/lldb/source/Breakpoint/StoppointCallbackContext.cpp index 640db8bb9c9..a561c99b1d9 100644 --- a/gnu/llvm/lldb/source/Breakpoint/StoppointCallbackContext.cpp +++ b/gnu/llvm/lldb/source/Breakpoint/StoppointCallbackContext.cpp @@ -10,8 +10,7 @@ using namespace lldb_private; -StoppointCallbackContext::StoppointCallbackContext() - : event(nullptr), exe_ctx_ref(), is_synchronous(false) {} +StoppointCallbackContext::StoppointCallbackContext() : exe_ctx_ref() {} StoppointCallbackContext::StoppointCallbackContext( Event *e, const ExecutionContext &exe_ctx, bool synchronously) diff --git a/gnu/llvm/lldb/source/Breakpoint/StoppointSite.cpp b/gnu/llvm/lldb/source/Breakpoint/StoppointSite.cpp new file mode 100644 index 00000000000..ba8c48326bd --- /dev/null +++ b/gnu/llvm/lldb/source/Breakpoint/StoppointSite.cpp @@ -0,0 +1,23 @@ +//===-- StoppointSite.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 "lldb/Breakpoint/StoppointSite.h" + + +using namespace lldb; +using namespace lldb_private; + +StoppointSite::StoppointSite(break_id_t id, addr_t addr, bool hardware) + : m_id(id), m_addr(addr), m_is_hardware_required(hardware), + m_hardware_index(LLDB_INVALID_INDEX32), m_byte_size(0), m_hit_counter() {} + +StoppointSite::StoppointSite(break_id_t id, addr_t addr, + uint32_t byte_size, bool hardware) + : m_id(id), m_addr(addr), m_is_hardware_required(hardware), + m_hardware_index(LLDB_INVALID_INDEX32), m_byte_size(byte_size), + m_hit_counter() {} diff --git a/gnu/llvm/lldb/source/Breakpoint/Watchpoint.cpp b/gnu/llvm/lldb/source/Breakpoint/Watchpoint.cpp index df73c6a1723..29ae1ef3df2 100644 --- a/gnu/llvm/lldb/source/Breakpoint/Watchpoint.cpp +++ b/gnu/llvm/lldb/source/Breakpoint/Watchpoint.cpp @@ -25,7 +25,7 @@ using namespace lldb_private; Watchpoint::Watchpoint(Target &target, lldb::addr_t addr, uint32_t size, const CompilerType *type, bool hardware) - : StoppointLocation(0, addr, size, hardware), m_target(target), + : StoppointSite(0, addr, size, hardware), m_target(target), m_enabled(false), m_is_hardware(hardware), m_is_watch_variable(false), m_is_ephemeral(false), m_disabled_count(0), m_watch_read(0), m_watch_write(0), m_watch_was_read(0), m_watch_was_written(0), @@ -93,9 +93,10 @@ void Watchpoint::SetWatchSpec(const std::string &str) { m_watch_spec_str = str; } -// Override default impl of StoppointLocation::IsHardware() since m_is_hardware -// member field is more accurate. -bool Watchpoint::IsHardware() const { return m_is_hardware; } +bool Watchpoint::IsHardware() const { + lldbassert(m_is_hardware || !HardwareRequired()); + return m_is_hardware; +} bool Watchpoint::IsWatchVariable() const { return m_is_watch_variable; } @@ -123,12 +124,12 @@ bool Watchpoint::CaptureWatchedValue(const ExecutionContext &exe_ctx) { void Watchpoint::IncrementFalseAlarmsAndReviseHitCount() { ++m_false_alarms; if (m_false_alarms) { - if (m_hit_count >= m_false_alarms) { - m_hit_count -= m_false_alarms; + if (m_hit_counter.GetValue() >= m_false_alarms) { + m_hit_counter.Decrement(m_false_alarms); m_false_alarms = 0; } else { - m_false_alarms -= m_hit_count; - m_hit_count = 0; + m_false_alarms -= m_hit_counter.GetValue(); + m_hit_counter.Reset(); } } } @@ -137,7 +138,7 @@ void Watchpoint::IncrementFalseAlarmsAndReviseHitCount() { // should continue. bool Watchpoint::ShouldStop(StoppointCallbackContext *context) { - IncrementHitCount(); + m_hit_counter.Increment(); return IsEnabled(); } diff --git a/gnu/llvm/lldb/source/Breakpoint/WatchpointList.cpp b/gnu/llvm/lldb/source/Breakpoint/WatchpointList.cpp index a6f651e8495..100c1e51ac5 100644 --- a/gnu/llvm/lldb/source/Breakpoint/WatchpointList.cpp +++ b/gnu/llvm/lldb/source/Breakpoint/WatchpointList.cpp @@ -12,10 +12,9 @@ using namespace lldb; using namespace lldb_private; -WatchpointList::WatchpointList() - : m_watchpoints(), m_mutex(), m_next_wp_id(0) {} +WatchpointList::WatchpointList() : m_watchpoints(), m_mutex() {} -WatchpointList::~WatchpointList() {} +WatchpointList::~WatchpointList() = default; // Add a watchpoint to the list. lldb::watch_id_t WatchpointList::Add(const WatchpointSP &wp_sp, bool notify) { diff --git a/gnu/llvm/lldb/source/Breakpoint/WatchpointOptions.cpp b/gnu/llvm/lldb/source/Breakpoint/WatchpointOptions.cpp index f01f5ad3dd2..a578e8744ef 100644 --- a/gnu/llvm/lldb/source/Breakpoint/WatchpointOptions.cpp +++ b/gnu/llvm/lldb/source/Breakpoint/WatchpointOptions.cpp @@ -28,7 +28,7 @@ bool WatchpointOptions::NullCallback(void *baton, // WatchpointOptions constructor WatchpointOptions::WatchpointOptions() : m_callback(WatchpointOptions::NullCallback), m_callback_baton_sp(), - m_callback_is_synchronous(false), m_thread_spec_up() {} + m_thread_spec_up() {} // WatchpointOptions copy constructor WatchpointOptions::WatchpointOptions(const WatchpointOptions &rhs) diff --git a/gnu/llvm/lldb/source/CMakeLists.txt b/gnu/llvm/lldb/source/CMakeLists.txt index b196147e68e..56ea8342be4 100644 --- a/gnu/llvm/lldb/source/CMakeLists.txt +++ b/gnu/llvm/lldb/source/CMakeLists.txt @@ -4,16 +4,8 @@ set(lldbBase_SOURCES lldb.cpp ) -foreach(file - "${LLDB_SOURCE_DIR}/.git/logs/HEAD" # Git - "${LLDB_SOURCE_DIR}/.svn/wc.db" # SVN 1.7 - "${LLDB_SOURCE_DIR}/.svn/entries" # SVN 1.6 - ) - if(EXISTS "${file}") - set(lldb_vc "${file}") - break() - endif() -endforeach() + +find_first_existing_vc_file("${LLDB_SOURCE_DIR}" lldb_vc) set(version_inc "${CMAKE_CURRENT_BINARY_DIR}/VCSVersion.inc") set(generate_vcs_version_script "${LLVM_CMAKE_PATH}/GenerateVersionFromVCS.cmake") @@ -34,9 +26,6 @@ set_source_files_properties("${version_inc}" PROPERTIES GENERATED TRUE HEADER_FILE_ONLY TRUE) -set_property(SOURCE lldb.cpp APPEND PROPERTY - COMPILE_DEFINITIONS "HAVE_VCS_VERSION_INC") - list(APPEND lldbBase_SOURCES ${version_inc}) if(LLDB_VERSION_STRING) diff --git a/gnu/llvm/lldb/source/Commands/CMakeLists.txt b/gnu/llvm/lldb/source/Commands/CMakeLists.txt index 28cbb2cd6cf..4a6d0c5fa86 100644 --- a/gnu/llvm/lldb/source/Commands/CMakeLists.txt +++ b/gnu/llvm/lldb/source/Commands/CMakeLists.txt @@ -13,25 +13,32 @@ add_lldb_library(lldbCommands CommandObjectFrame.cpp CommandObjectGUI.cpp CommandObjectHelp.cpp + CommandObjectLanguage.cpp CommandObjectLog.cpp CommandObjectMemory.cpp + CommandObjectMemoryTag.cpp CommandObjectMultiword.cpp CommandObjectPlatform.cpp CommandObjectPlugin.cpp CommandObjectProcess.cpp CommandObjectQuit.cpp + CommandObjectRegexCommand.cpp CommandObjectRegister.cpp CommandObjectReproducer.cpp + CommandObjectScript.cpp + CommandObjectSession.cpp CommandObjectSettings.cpp CommandObjectSource.cpp CommandObjectStats.cpp CommandObjectTarget.cpp CommandObjectThread.cpp + CommandObjectThreadUtil.cpp + CommandObjectTrace.cpp CommandObjectType.cpp CommandObjectVersion.cpp CommandObjectWatchpoint.cpp CommandObjectWatchpointCommand.cpp - CommandObjectLanguage.cpp + CommandOptionsProcessLaunch.cpp LINK_LIBS lldbBase diff --git a/gnu/llvm/lldb/source/Commands/CommandCompletions.cpp b/gnu/llvm/lldb/source/Commands/CommandCompletions.cpp index 48df7735720..55018cef57d 100644 --- a/gnu/llvm/lldb/source/Commands/CommandCompletions.cpp +++ b/gnu/llvm/lldb/source/Commands/CommandCompletions.cpp @@ -9,16 +9,21 @@ #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringSet.h" +#include "lldb/Breakpoint/Watchpoint.h" #include "lldb/Core/FileSpecList.h" #include "lldb/Core/Module.h" #include "lldb/Core/PluginManager.h" +#include "lldb/DataFormatters/DataVisualization.h" #include "lldb/Host/FileSystem.h" #include "lldb/Interpreter/CommandCompletions.h" #include "lldb/Interpreter/CommandInterpreter.h" #include "lldb/Interpreter/OptionValueProperties.h" #include "lldb/Symbol/CompileUnit.h" #include "lldb/Symbol/Variable.h" +#include "lldb/Target/Language.h" +#include "lldb/Target/Process.h" #include "lldb/Target/RegisterContext.h" +#include "lldb/Target/Thread.h" #include "lldb/Utility/FileSpec.h" #include "lldb/Utility/StreamString.h" #include "lldb/Utility/TildeExpressionResolver.h" @@ -52,6 +57,7 @@ bool CommandCompletions::InvokeCommonCompletionCallbacks( {eDiskDirectoryCompletion, CommandCompletions::DiskDirectories}, {eSymbolCompletion, CommandCompletions::Symbols}, {eModuleCompletion, CommandCompletions::Modules}, + {eModuleUUIDCompletion, CommandCompletions::ModuleUUIDs}, {eSettingsNameCompletion, CommandCompletions::SettingsNames}, {ePlatformPluginCompletion, CommandCompletions::PlatformPluginNames}, {eArchitectureCompletion, CommandCompletions::ArchitectureNames}, @@ -59,6 +65,19 @@ bool CommandCompletions::InvokeCommonCompletionCallbacks( {eRegisterCompletion, CommandCompletions::Registers}, {eBreakpointCompletion, CommandCompletions::Breakpoints}, {eProcessPluginCompletion, CommandCompletions::ProcessPluginNames}, + {eDisassemblyFlavorCompletion, CommandCompletions::DisassemblyFlavors}, + {eTypeLanguageCompletion, CommandCompletions::TypeLanguages}, + {eFrameIndexCompletion, CommandCompletions::FrameIndexes}, + {eStopHookIDCompletion, CommandCompletions::StopHookIDs}, + {eThreadIndexCompletion, CommandCompletions::ThreadIndexes}, + {eWatchPointIDCompletion, CommandCompletions::WatchPointIDs}, + {eBreakpointNameCompletion, CommandCompletions::BreakpointNames}, + {eProcessIDCompletion, CommandCompletions::ProcessIDs}, + {eProcessNameCompletion, CommandCompletions::ProcessNames}, + {eRemoteDiskFileCompletion, CommandCompletions::RemoteDiskFiles}, + {eRemoteDiskDirectoryCompletion, + CommandCompletions::RemoteDiskDirectories}, + {eTypeCategoryNameCompletion, CommandCompletions::TypeCategoryNames}, {eNoCompletion, nullptr} // This one has to be last in the list. }; @@ -312,7 +331,7 @@ static void DiskFilesOrDirectories(const llvm::Twine &partial_name, llvm::StringRef PartialItem; if (CompletionBuffer.startswith("~")) { - llvm::StringRef Buffer(CompletionBuffer); + llvm::StringRef Buffer = CompletionBuffer; size_t FirstSep = Buffer.find_if([](char c) { return path::is_separator(c); }); @@ -472,6 +491,24 @@ void CommandCompletions::DiskDirectories(const llvm::Twine &partial_file_name, DiskFilesOrDirectories(partial_file_name, true, matches, Resolver); } +void CommandCompletions::RemoteDiskFiles(CommandInterpreter &interpreter, + CompletionRequest &request, + SearchFilter *searcher) { + lldb::PlatformSP platform_sp = + interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform(); + if (platform_sp) + platform_sp->AutoCompleteDiskFileOrDirectory(request, false); +} + +void CommandCompletions::RemoteDiskDirectories(CommandInterpreter &interpreter, + CompletionRequest &request, + SearchFilter *searcher) { + lldb::PlatformSP platform_sp = + interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform(); + if (platform_sp) + platform_sp->AutoCompleteDiskFileOrDirectory(request, true); +} + void CommandCompletions::Modules(CommandInterpreter &interpreter, CompletionRequest &request, SearchFilter *searcher) { @@ -486,6 +523,24 @@ void CommandCompletions::Modules(CommandInterpreter &interpreter, } } +void CommandCompletions::ModuleUUIDs(CommandInterpreter &interpreter, + CompletionRequest &request, + SearchFilter *searcher) { + const ExecutionContext &exe_ctx = interpreter.GetExecutionContext(); + if (!exe_ctx.HasTargetScope()) + return; + + exe_ctx.GetTargetPtr()->GetImages().ForEach( + [&request](const lldb::ModuleSP &module) { + StreamString strm; + module->GetDescription(strm.AsRawOstream(), + lldb::eDescriptionLevelInitial); + request.TryCompleteCurrentArg(module->GetUUID().GetAsString(), + strm.GetString()); + return true; + }); +} + void CommandCompletions::Symbols(CommandInterpreter &interpreter, CompletionRequest &request, SearchFilter *searcher) { @@ -588,9 +643,152 @@ void CommandCompletions::Breakpoints(CommandInterpreter &interpreter, } } +void CommandCompletions::BreakpointNames(CommandInterpreter &interpreter, + CompletionRequest &request, + SearchFilter *searcher) { + lldb::TargetSP target = interpreter.GetDebugger().GetSelectedTarget(); + if (!target) + return; + + std::vector name_list; + target->GetBreakpointNames(name_list); + + for (const std::string &name : name_list) + request.TryCompleteCurrentArg(name); +} + void CommandCompletions::ProcessPluginNames(CommandInterpreter &interpreter, CompletionRequest &request, SearchFilter *searcher) { PluginManager::AutoCompleteProcessName(request.GetCursorArgumentPrefix(), request); -} \ No newline at end of file +} +void CommandCompletions::DisassemblyFlavors(CommandInterpreter &interpreter, + CompletionRequest &request, + SearchFilter *searcher) { + // Currently the only valid options for disassemble -F are default, and for + // Intel architectures, att and intel. + static const char *flavors[] = {"default", "att", "intel"}; + for (const char *flavor : flavors) { + request.TryCompleteCurrentArg(flavor); + } +} + +void CommandCompletions::ProcessIDs(CommandInterpreter &interpreter, + CompletionRequest &request, + SearchFilter *searcher) { + lldb::PlatformSP platform_sp(interpreter.GetPlatform(true)); + if (!platform_sp) + return; + ProcessInstanceInfoList process_infos; + ProcessInstanceInfoMatch match_info; + platform_sp->FindProcesses(match_info, process_infos); + for (const ProcessInstanceInfo &info : process_infos) + request.TryCompleteCurrentArg(std::to_string(info.GetProcessID()), + info.GetNameAsStringRef()); +} + +void CommandCompletions::ProcessNames(CommandInterpreter &interpreter, + CompletionRequest &request, + SearchFilter *searcher) { + lldb::PlatformSP platform_sp(interpreter.GetPlatform(true)); + if (!platform_sp) + return; + ProcessInstanceInfoList process_infos; + ProcessInstanceInfoMatch match_info; + platform_sp->FindProcesses(match_info, process_infos); + for (const ProcessInstanceInfo &info : process_infos) + request.TryCompleteCurrentArg(info.GetNameAsStringRef()); +} + +void CommandCompletions::TypeLanguages(CommandInterpreter &interpreter, + CompletionRequest &request, + SearchFilter *searcher) { + for (int bit : + Language::GetLanguagesSupportingTypeSystems().bitvector.set_bits()) { + request.TryCompleteCurrentArg( + Language::GetNameForLanguageType(static_cast(bit))); + } +} + +void CommandCompletions::FrameIndexes(CommandInterpreter &interpreter, + CompletionRequest &request, + SearchFilter *searcher) { + const ExecutionContext &exe_ctx = interpreter.GetExecutionContext(); + if (!exe_ctx.HasProcessScope()) + return; + + lldb::ThreadSP thread_sp = exe_ctx.GetThreadSP(); + const uint32_t frame_num = thread_sp->GetStackFrameCount(); + for (uint32_t i = 0; i < frame_num; ++i) { + lldb::StackFrameSP frame_sp = thread_sp->GetStackFrameAtIndex(i); + StreamString strm; + frame_sp->Dump(&strm, false, true); + request.TryCompleteCurrentArg(std::to_string(i), strm.GetString()); + } +} + +void CommandCompletions::StopHookIDs(CommandInterpreter &interpreter, + CompletionRequest &request, + SearchFilter *searcher) { + const lldb::TargetSP target_sp = + interpreter.GetExecutionContext().GetTargetSP(); + if (!target_sp) + return; + + const size_t num = target_sp->GetNumStopHooks(); + for (size_t idx = 0; idx < num; ++idx) { + StreamString strm; + // The value 11 is an offset to make the completion description looks + // neater. + strm.SetIndentLevel(11); + const Target::StopHookSP stophook_sp = target_sp->GetStopHookAtIndex(idx); + stophook_sp->GetDescription(&strm, lldb::eDescriptionLevelInitial); + request.TryCompleteCurrentArg(std::to_string(stophook_sp->GetID()), + strm.GetString()); + } +} + +void CommandCompletions::ThreadIndexes(CommandInterpreter &interpreter, + CompletionRequest &request, + SearchFilter *searcher) { + const ExecutionContext &exe_ctx = interpreter.GetExecutionContext(); + if (!exe_ctx.HasProcessScope()) + return; + + ThreadList &threads = exe_ctx.GetProcessPtr()->GetThreadList(); + lldb::ThreadSP thread_sp; + for (uint32_t idx = 0; (thread_sp = threads.GetThreadAtIndex(idx)); ++idx) { + StreamString strm; + thread_sp->GetStatus(strm, 0, 1, 1, true); + request.TryCompleteCurrentArg(std::to_string(thread_sp->GetIndexID()), + strm.GetString()); + } +} + +void CommandCompletions::WatchPointIDs(CommandInterpreter &interpreter, + CompletionRequest &request, + SearchFilter *searcher) { + const ExecutionContext &exe_ctx = interpreter.GetExecutionContext(); + if (!exe_ctx.HasTargetScope()) + return; + + const WatchpointList &wp_list = exe_ctx.GetTargetPtr()->GetWatchpointList(); + for (lldb::WatchpointSP wp_sp : wp_list.Watchpoints()) { + StreamString strm; + wp_sp->Dump(&strm); + request.TryCompleteCurrentArg(std::to_string(wp_sp->GetID()), + strm.GetString()); + } +} + +void CommandCompletions::TypeCategoryNames(CommandInterpreter &interpreter, + CompletionRequest &request, + SearchFilter *searcher) { + DataVisualization::Categories::ForEach( + [&request](const lldb::TypeCategoryImplSP &category_sp) { + request.TryCompleteCurrentArg(category_sp->GetName(), + category_sp->GetDescription()); + return true; + }); +} diff --git a/gnu/llvm/lldb/source/Commands/CommandObjectApropos.cpp b/gnu/llvm/lldb/source/Commands/CommandObjectApropos.cpp index 6e1e1f06173..656487169a3 100644 --- a/gnu/llvm/lldb/source/Commands/CommandObjectApropos.cpp +++ b/gnu/llvm/lldb/source/Commands/CommandObjectApropos.cpp @@ -86,11 +86,9 @@ bool CommandObjectApropos::DoExecute(Args &args, CommandReturnObject &result) { result.SetStatus(eReturnStatusSuccessFinishNoResult); } else { result.AppendError("'' is not a valid search word.\n"); - result.SetStatus(eReturnStatusFailed); } } else { result.AppendError("'apropos' must be called with exactly one argument.\n"); - result.SetStatus(eReturnStatusFailed); } return result.Succeeded(); diff --git a/gnu/llvm/lldb/source/Commands/CommandObjectBreakpoint.cpp b/gnu/llvm/lldb/source/Commands/CommandObjectBreakpoint.cpp index be7ef8a1b60..722d5c4d8f4 100644 --- a/gnu/llvm/lldb/source/Commands/CommandObjectBreakpoint.cpp +++ b/gnu/llvm/lldb/source/Commands/CommandObjectBreakpoint.cpp @@ -17,6 +17,7 @@ #include "lldb/Interpreter/OptionArgParser.h" #include "lldb/Interpreter/OptionGroupPythonClassWithDict.h" #include "lldb/Interpreter/OptionValueBoolean.h" +#include "lldb/Interpreter/OptionValueFileColonLine.h" #include "lldb/Interpreter/OptionValueString.h" #include "lldb/Interpreter/OptionValueUInt64.h" #include "lldb/Interpreter/Options.h" @@ -241,15 +242,8 @@ public: class CommandOptions : public OptionGroup { public: CommandOptions() - : OptionGroup(), m_condition(), m_filenames(), m_line_num(0), - m_column(0), m_func_names(), - m_func_name_type_mask(eFunctionNameTypeNone), m_func_regexp(), - m_source_text_regexp(), m_modules(), m_load_addr(), m_catch_bp(false), - m_throw_bp(true), m_hardware(false), - m_exception_language(eLanguageTypeUnknown), - m_language(lldb::eLanguageTypeUnknown), - m_skip_prologue(eLazyBoolCalculate), m_all_files(false), - m_move_to_nearest_code(eLazyBoolCalculate) {} + : OptionGroup(), m_condition(), m_filenames(), m_func_names(), + m_func_regexp(), m_source_text_regexp(), m_modules() {} ~CommandOptions() override = default; @@ -443,7 +437,22 @@ public: case 'X': m_source_regex_func_names.insert(std::string(option_arg)); break; - + + case 'y': + { + OptionValueFileColonLine value; + Status fcl_err = value.SetValueFromString(option_arg); + if (!fcl_err.Success()) { + error.SetErrorStringWithFormat( + "Invalid value for file:line specifier: %s", + fcl_err.AsCString()); + } else { + m_filenames.AppendIfUnique(value.GetFileSpec()); + m_line_num = value.GetLineNumber(); + m_column = value.GetColumnNumber(); + } + } break; + default: llvm_unreachable("Unimplemented option"); } @@ -484,25 +493,25 @@ public: std::string m_condition; FileSpecList m_filenames; - uint32_t m_line_num; - uint32_t m_column; + uint32_t m_line_num = 0; + uint32_t m_column = 0; std::vector m_func_names; std::vector m_breakpoint_names; - lldb::FunctionNameType m_func_name_type_mask; + lldb::FunctionNameType m_func_name_type_mask = eFunctionNameTypeNone; std::string m_func_regexp; std::string m_source_text_regexp; FileSpecList m_modules; - lldb::addr_t m_load_addr; + lldb::addr_t m_load_addr = 0; lldb::addr_t m_offset_addr; - bool m_catch_bp; - bool m_throw_bp; - bool m_hardware; // Request to use hardware breakpoints - lldb::LanguageType m_exception_language; - lldb::LanguageType m_language; - LazyBool m_skip_prologue; - bool m_all_files; + bool m_catch_bp = false; + bool m_throw_bp = true; + bool m_hardware = false; // Request to use hardware breakpoints + lldb::LanguageType m_exception_language = eLanguageTypeUnknown; + lldb::LanguageType m_language = lldb::eLanguageTypeUnknown; + LazyBool m_skip_prologue = eLazyBoolCalculate; + bool m_all_files = false; Args m_exception_extra_args; - LazyBool m_move_to_nearest_code; + LazyBool m_move_to_nearest_code = eLazyBoolCalculate; std::unordered_set m_source_regex_func_names; std::string m_current_key; }; @@ -557,13 +566,11 @@ protected: if (num_files == 0) { if (!GetDefaultFile(target, file, result)) { result.AppendError("No file supplied and no default file available."); - result.SetStatus(eReturnStatusFailed); return false; } } else if (num_files > 1) { result.AppendError("Only one file at a time is allowed for file and " "line breakpoints."); - result.SetStatus(eReturnStatusFailed); return false; } else file = m_options.m_filenames.GetFileSpecAtIndex(0); @@ -595,7 +602,6 @@ protected: } else { result.AppendError("Only one shared library can be specified for " "address breakpoints."); - result.SetStatus(eReturnStatusFailed); return false; } break; @@ -630,7 +636,6 @@ protected: result.AppendWarning( "Function name regex does not accept glob patterns."); } - result.SetStatus(eReturnStatusFailed); return false; } @@ -648,7 +653,6 @@ protected: if (!GetDefaultFile(target, file, result)) { result.AppendError( "No files provided and could not find default file."); - result.SetStatus(eReturnStatusFailed); return false; } else { m_options.m_filenames.Append(file); @@ -660,7 +664,6 @@ protected: result.AppendErrorWithFormat( "Source text regular expression could not be compiled: \"%s\"", llvm::toString(std::move(err)).c_str()); - result.SetStatus(eReturnStatusFailed); return false; } bp_sp = target.CreateSourceRegexBreakpoint( @@ -679,7 +682,6 @@ protected: "Error setting extra exception arguments: %s", precond_error.AsCString()); target.RemoveBreakpointByID(bp_sp->GetID()); - result.SetStatus(eReturnStatusFailed); return false; } } break; @@ -694,7 +696,6 @@ protected: result.AppendErrorWithFormat( "Error setting extra exception arguments: %s", error.AsCString()); target.RemoveBreakpointByID(bp_sp->GetID()); - result.SetStatus(eReturnStatusFailed); return false; } } break; @@ -704,7 +705,7 @@ protected: // Now set the various options that were passed in: if (bp_sp) { - bp_sp->GetOptions()->CopyOverSetOptions(m_bp_opts.GetBreakpointOptions()); + bp_sp->GetOptions().CopyOverSetOptions(m_bp_opts.GetBreakpointOptions()); if (!m_options.m_breakpoint_names.empty()) { Status name_error; @@ -714,7 +715,6 @@ protected: result.AppendErrorWithFormat("Invalid breakpoint name: %s", name.c_str()); target.RemoveBreakpointByID(bp_sp->GetID()); - result.SetStatus(eReturnStatusFailed); return false; } } @@ -741,7 +741,6 @@ protected: result.SetStatus(eReturnStatusSuccessFinishResult); } else if (!bp_sp) { result.AppendError("Breakpoint creation failed: No breakpoint created."); - result.SetStatus(eReturnStatusFailed); } return result.Succeeded(); @@ -758,12 +757,10 @@ private: if (cur_frame == nullptr) { result.AppendError( "No selected frame to use to find the default file."); - result.SetStatus(eReturnStatusFailed); return false; } else if (!cur_frame->HasDebugInformation()) { result.AppendError("Cannot use the selected frame to find the default " "file, it has no debug info."); - result.SetStatus(eReturnStatusFailed); return false; } else { const SymbolContext &sc = @@ -773,7 +770,6 @@ private: } else { result.AppendError("Can't find the file for the selected frame to " "use as the default file."); - result.SetStatus(eReturnStatusFailed); return false; } } @@ -854,10 +850,10 @@ protected: BreakpointLocation *location = bp->FindLocationByID(cur_bp_id.GetLocationID()).get(); if (location) - location->GetLocationOptions()->CopyOverSetOptions( + location->GetLocationOptions().CopyOverSetOptions( m_bp_opts.GetBreakpointOptions()); } else { - bp->GetOptions()->CopyOverSetOptions( + bp->GetOptions().CopyOverSetOptions( m_bp_opts.GetBreakpointOptions()); } } @@ -914,7 +910,6 @@ protected: if (num_breakpoints == 0) { result.AppendError("No breakpoints exist to be enabled."); - result.SetStatus(eReturnStatusFailed); return false; } @@ -1028,7 +1023,6 @@ protected: if (num_breakpoints == 0) { result.AppendError("No breakpoints exist to be disabled."); - result.SetStatus(eReturnStatusFailed); return false; } @@ -1117,9 +1111,7 @@ public: class CommandOptions : public Options { public: - CommandOptions() - : Options(), m_level(lldb::eDescriptionLevelBrief), m_use_dummy(false) { - } + CommandOptions() : Options() {} ~CommandOptions() override = default; @@ -1163,10 +1155,10 @@ public: // Instance variables to hold the values for command options. - lldb::DescriptionLevel m_level; + lldb::DescriptionLevel m_level = lldb::eDescriptionLevelBrief; bool m_internal; - bool m_use_dummy; + bool m_use_dummy = false; }; protected: @@ -1216,7 +1208,6 @@ protected: result.SetStatus(eReturnStatusSuccessFinishNoResult); } else { result.AppendError("Invalid breakpoint ID."); - result.SetStatus(eReturnStatusFailed); } } @@ -1252,7 +1243,7 @@ public: class CommandOptions : public Options { public: - CommandOptions() : Options(), m_filename(), m_line_num(0) {} + CommandOptions() : Options(), m_filename() {} ~CommandOptions() override = default; @@ -1289,7 +1280,7 @@ public: // Instance variables to hold the values for command options. std::string m_filename; - uint32_t m_line_num; + uint32_t m_line_num = 0; }; protected: @@ -1314,7 +1305,6 @@ protected: // Early return if there's no breakpoint at all. if (num_breakpoints == 0) { result.AppendError("Breakpoint clear: No breakpoint cleared."); - result.SetStatus(eReturnStatusFailed); return result.Succeeded(); } @@ -1361,7 +1351,6 @@ protected: result.SetStatus(eReturnStatusSuccessFinishNoResult); } else { result.AppendError("Breakpoint clear: No breakpoint cleared."); - result.SetStatus(eReturnStatusFailed); } return result.Succeeded(); @@ -1407,7 +1396,7 @@ public: class CommandOptions : public Options { public: - CommandOptions() : Options(), m_use_dummy(false), m_force(false) {} + CommandOptions() : Options() {} ~CommandOptions() override = default; @@ -1424,6 +1413,10 @@ public: case 'D': m_use_dummy = true; break; + + case 'd': + m_delete_disabled = true; + break; default: llvm_unreachable("Unimplemented option"); @@ -1435,6 +1428,7 @@ public: void OptionParsingStarting(ExecutionContext *execution_context) override { m_use_dummy = false; m_force = false; + m_delete_disabled = false; } llvm::ArrayRef GetDefinitions() override { @@ -1442,28 +1436,30 @@ public: } // Instance variables to hold the values for command options. - bool m_use_dummy; - bool m_force; + bool m_use_dummy = false; + bool m_force = false; + bool m_delete_disabled = false; }; protected: bool DoExecute(Args &command, CommandReturnObject &result) override { Target &target = GetSelectedOrDummyTarget(m_options.m_use_dummy); - + result.Clear(); + std::unique_lock lock; target.GetBreakpointList().GetListMutex(lock); - const BreakpointList &breakpoints = target.GetBreakpointList(); + BreakpointList &breakpoints = target.GetBreakpointList(); size_t num_breakpoints = breakpoints.GetSize(); if (num_breakpoints == 0) { result.AppendError("No breakpoints exist to be deleted."); - result.SetStatus(eReturnStatusFailed); return false; } - if (command.empty()) { + // Handle the delete all breakpoints case: + if (command.empty() && !m_options.m_delete_disabled) { if (!m_options.m_force && !m_interpreter.Confirm( "About to delete all breakpoints, do you want to do that?", @@ -1476,44 +1472,73 @@ protected: (uint64_t)num_breakpoints, num_breakpoints > 1 ? "s" : ""); } result.SetStatus(eReturnStatusSuccessFinishNoResult); + return result.Succeeded(); + } + + // Either we have some kind of breakpoint specification(s), + // or we are handling "break disable --deleted". Gather the list + // of breakpoints to delete here, the we'll delete them below. + BreakpointIDList valid_bp_ids; + + if (m_options.m_delete_disabled) { + BreakpointIDList excluded_bp_ids; + + if (!command.empty()) { + CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs( + command, &target, result, &excluded_bp_ids, + BreakpointName::Permissions::PermissionKinds::deletePerm); + if (!result.Succeeded()) + return false; + } + + for (auto breakpoint_sp : breakpoints.Breakpoints()) { + if (!breakpoint_sp->IsEnabled() && breakpoint_sp->AllowDelete()) { + BreakpointID bp_id(breakpoint_sp->GetID()); + size_t pos = 0; + if (!excluded_bp_ids.FindBreakpointID(bp_id, &pos)) + valid_bp_ids.AddBreakpointID(breakpoint_sp->GetID()); + } + } + if (valid_bp_ids.GetSize() == 0) { + result.AppendError("No disabled breakpoints."); + return false; + } } else { - // Particular breakpoint selected; disable that breakpoint. - BreakpointIDList valid_bp_ids; CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs( command, &target, result, &valid_bp_ids, BreakpointName::Permissions::PermissionKinds::deletePerm); + if (!result.Succeeded()) + return false; + } + + int delete_count = 0; + int disable_count = 0; + const size_t count = valid_bp_ids.GetSize(); + for (size_t i = 0; i < count; ++i) { + BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex(i); - if (result.Succeeded()) { - int delete_count = 0; - int disable_count = 0; - const size_t count = valid_bp_ids.GetSize(); - for (size_t i = 0; i < count; ++i) { - BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex(i); - - if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID) { - if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID) { - Breakpoint *breakpoint = - target.GetBreakpointByID(cur_bp_id.GetBreakpointID()).get(); - BreakpointLocation *location = - breakpoint->FindLocationByID(cur_bp_id.GetLocationID()).get(); - // It makes no sense to try to delete individual locations, so we - // disable them instead. - if (location) { - location->SetEnabled(false); - ++disable_count; - } - } else { - target.RemoveBreakpointByID(cur_bp_id.GetBreakpointID()); - ++delete_count; - } + if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID) { + if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID) { + Breakpoint *breakpoint = + target.GetBreakpointByID(cur_bp_id.GetBreakpointID()).get(); + BreakpointLocation *location = + breakpoint->FindLocationByID(cur_bp_id.GetLocationID()).get(); + // It makes no sense to try to delete individual locations, so we + // disable them instead. + if (location) { + location->SetEnabled(false); + ++disable_count; } + } else { + target.RemoveBreakpointByID(cur_bp_id.GetBreakpointID()); + ++delete_count; } - result.AppendMessageWithFormat( - "%d breakpoints deleted; %d breakpoint locations disabled.\n", - delete_count, disable_count); - result.SetStatus(eReturnStatusSuccessFinishNoResult); } } + result.AppendMessageWithFormat( + "%d breakpoints deleted; %d breakpoint locations disabled.\n", + delete_count, disable_count); + result.SetStatus(eReturnStatusSuccessFinishNoResult); return result.Succeeded(); } @@ -1688,7 +1713,6 @@ protected: const size_t argc = command.GetArgumentCount(); if (argc == 0) { result.AppendError("No names provided."); - result.SetStatus(eReturnStatusFailed); return false; } @@ -1703,7 +1727,6 @@ protected: if (!BreakpointID::StringIsBreakpointName(entry.ref(), error)) { result.AppendErrorWithFormat("Invalid breakpoint name: %s - %s", entry.c_str(), error.AsCString()); - result.SetStatus(eReturnStatusFailed); return false; } } @@ -1716,7 +1739,6 @@ protected: if (!bp_sp) { result.AppendErrorWithFormatv("Could not find specified breakpoint {0}", bp_id); - result.SetStatus(eReturnStatusFailed); return false; } } @@ -1731,7 +1753,7 @@ protected: bp_name->SetHelp(m_bp_id.m_help_string.GetStringValue().str().c_str()); if (bp_sp) - target.ConfigureBreakpointName(*bp_name, *bp_sp->GetOptions(), + target.ConfigureBreakpointName(*bp_name, bp_sp->GetOptions(), m_access_options.GetPermissions()); else target.ConfigureBreakpointName(*bp_name, @@ -1783,7 +1805,7 @@ public: protected: bool DoExecute(Args &command, CommandReturnObject &result) override { if (!m_name_options.m_name.OptionWasSet()) { - result.SetError("No name option provided."); + result.AppendError("No name option provided."); return false; } @@ -1797,8 +1819,7 @@ protected: size_t num_breakpoints = breakpoints.GetSize(); if (num_breakpoints == 0) { - result.SetError("No breakpoints, cannot add names."); - result.SetStatus(eReturnStatusFailed); + result.AppendError("No breakpoints, cannot add names."); return false; } @@ -1810,8 +1831,7 @@ protected: if (result.Succeeded()) { if (valid_bp_ids.GetSize() == 0) { - result.SetError("No breakpoints specified, cannot add names."); - result.SetStatus(eReturnStatusFailed); + result.AppendError("No breakpoints specified, cannot add names."); return false; } size_t num_valid_ids = valid_bp_ids.GetSize(); @@ -1870,7 +1890,7 @@ public: protected: bool DoExecute(Args &command, CommandReturnObject &result) override { if (!m_name_options.m_name.OptionWasSet()) { - result.SetError("No name option provided."); + result.AppendError("No name option provided."); return false; } @@ -1884,8 +1904,7 @@ protected: size_t num_breakpoints = breakpoints.GetSize(); if (num_breakpoints == 0) { - result.SetError("No breakpoints, cannot delete names."); - result.SetStatus(eReturnStatusFailed); + result.AppendError("No breakpoints, cannot delete names."); return false; } @@ -1897,8 +1916,7 @@ protected: if (result.Succeeded()) { if (valid_bp_ids.GetSize() == 0) { - result.SetError("No breakpoints specified, cannot delete names."); - result.SetStatus(eReturnStatusFailed); + result.AppendError("No breakpoints specified, cannot delete names."); return false; } ConstString bp_name(m_name_options.m_name.GetCurrentValue()); @@ -2081,7 +2099,79 @@ public: return llvm::makeArrayRef(g_breakpoint_read_options); } - // Instance variables to hold the values for command options. + void HandleOptionArgumentCompletion( + CompletionRequest &request, OptionElementVector &opt_element_vector, + int opt_element_index, CommandInterpreter &interpreter) override { + int opt_arg_pos = opt_element_vector[opt_element_index].opt_arg_pos; + int opt_defs_index = opt_element_vector[opt_element_index].opt_defs_index; + + switch (GetDefinitions()[opt_defs_index].short_option) { + case 'f': + CommandCompletions::InvokeCommonCompletionCallbacks( + interpreter, CommandCompletions::eDiskFileCompletion, request, + nullptr); + break; + + case 'N': + llvm::Optional file_spec; + const llvm::StringRef dash_f("-f"); + for (int arg_idx = 0; arg_idx < opt_arg_pos; arg_idx++) { + if (dash_f == request.GetParsedLine().GetArgumentAtIndex(arg_idx)) { + file_spec.emplace( + request.GetParsedLine().GetArgumentAtIndex(arg_idx + 1)); + break; + } + } + if (!file_spec) + return; + + FileSystem::Instance().Resolve(*file_spec); + Status error; + StructuredData::ObjectSP input_data_sp = + StructuredData::ParseJSONFromFile(*file_spec, error); + if (!error.Success()) + return; + + StructuredData::Array *bkpt_array = input_data_sp->GetAsArray(); + if (!bkpt_array) + return; + + const size_t num_bkpts = bkpt_array->GetSize(); + for (size_t i = 0; i < num_bkpts; i++) { + StructuredData::ObjectSP bkpt_object_sp = + bkpt_array->GetItemAtIndex(i); + if (!bkpt_object_sp) + return; + + StructuredData::Dictionary *bkpt_dict = + bkpt_object_sp->GetAsDictionary(); + if (!bkpt_dict) + return; + + StructuredData::ObjectSP bkpt_data_sp = + bkpt_dict->GetValueForKey(Breakpoint::GetSerializationKey()); + if (!bkpt_data_sp) + return; + + bkpt_dict = bkpt_data_sp->GetAsDictionary(); + if (!bkpt_dict) + return; + + StructuredData::Array *names_array; + + if (!bkpt_dict->GetValueForKeyAsArray("Names", names_array)) + return; + + size_t num_names = names_array->GetSize(); + + for (size_t i = 0; i < num_names; i++) { + llvm::StringRef name; + if (names_array->GetItemAtIndexAsString(i, name)) + request.TryCompleteCurrentArg(name); + } + } + } + } std::string m_filename; std::vector m_names; @@ -2102,7 +2192,6 @@ protected: if (!error.Success()) { result.AppendError(error.AsCString()); - result.SetStatus(eReturnStatusFailed); return false; } @@ -2231,7 +2320,6 @@ protected: if (!error.Success()) { result.AppendErrorWithFormat("error serializing breakpoints: %s.", error.AsCString()); - result.SetStatus(eReturnStatusFailed); } return result.Succeeded(); } @@ -2324,7 +2412,6 @@ void CommandObjectMultiwordBreakpoint::VerifyIDs( } else { result.AppendError( "No breakpoint specified and no last created breakpoint."); - result.SetStatus(eReturnStatusFailed); } return; } @@ -2366,14 +2453,12 @@ void CommandObjectMultiwordBreakpoint::VerifyIDs( result.AppendErrorWithFormat( "'%s' is not a currently valid breakpoint/location id.\n", id_str.GetData()); - result.SetStatus(eReturnStatusFailed); } } else { i = valid_ids->GetSize() + 1; result.AppendErrorWithFormat( "'%d' is not a currently valid breakpoint ID.\n", cur_bp_id.GetBreakpointID()); - result.SetStatus(eReturnStatusFailed); } } } diff --git a/gnu/llvm/lldb/source/Commands/CommandObjectBreakpointCommand.cpp b/gnu/llvm/lldb/source/Commands/CommandObjectBreakpointCommand.cpp index 45df8658901..26d35c82f57 100644 --- a/gnu/llvm/lldb/source/Commands/CommandObjectBreakpointCommand.cpp +++ b/gnu/llvm/lldb/source/Commands/CommandObjectBreakpointCommand.cpp @@ -61,7 +61,9 @@ public: CommandObjectBreakpointCommandAdd(CommandInterpreter &interpreter) : CommandObjectParsed(interpreter, "add", "Add LLDB commands to a breakpoint, to be executed " - "whenever the breakpoint is hit." + "whenever the breakpoint is hit. " + "The commands added to the breakpoint replace any " + "commands previously added to it." " If no breakpoint is specified, adds the " "commands to the last created breakpoint.", nullptr), @@ -117,14 +119,22 @@ to supply the function name prepended by the module name:" --python-function myutils.breakpoint_callback -The function itself must have the following prototype: +The function itself must have either of the following prototypes: -def breakpoint_callback(frame, bp_loc, dict): +def breakpoint_callback(frame, bp_loc, internal_dict): + # Your code goes here + +or: + +def breakpoint_callback(frame, bp_loc, extra_args, internal_dict): # Your code goes here )" "The arguments are the same as the arguments passed to generated functions as \ -described above. Note that the global variable 'lldb.frame' will NOT be updated when \ +described above. In the second form, any -k and -v pairs provided to the command will \ +be packaged into a SBDictionary in an SBStructuredData and passed as the extra_args parameter. \ +\n\n\ +Note that the global variable 'lldb.frame' will NOT be updated when \ this function is called, so be sure to use the 'frame' argument. The 'frame' argument \ can get you to the thread via frame.GetThread(), the thread can get you to the \ process via thread.GetProcess(), and the process can get you back to the target \ @@ -141,12 +151,16 @@ Example Python one-line breakpoint command: (lldb) breakpoint command add -s python 1 Enter your Python command(s). Type 'DONE' to end. -> print "Hit this breakpoint!" -> DONE +def function (frame, bp_loc, internal_dict): + """frame: the lldb.SBFrame for the location at which you stopped + bp_loc: an lldb.SBBreakpointLocation for the breakpoint location information + internal_dict: an LLDB support object not to be used""" + print("Hit this breakpoint!") + DONE As a convenience, this also works for a short Python one-liner: -(lldb) breakpoint command add -s python 1 -o 'import time; print time.asctime()' +(lldb) breakpoint command add -s python 1 -o 'import time; print(time.asctime())' (lldb) run Launching '.../a.out' (x86_64) (lldb) Fri Sep 10 12:17:45 2010 @@ -164,21 +178,14 @@ Example multiple line Python breakpoint command: (lldb) breakpoint command add -s p 1 Enter your Python command(s). Type 'DONE' to end. -> global bp_count -> bp_count = bp_count + 1 -> print "Hit this breakpoint " + repr(bp_count) + " times!" -> DONE - -Example multiple line Python breakpoint command, using function definition: - -(lldb) breakpoint command add -s python 1 -Enter your Python command(s). Type 'DONE' to end. -> def breakpoint_output (bp_no): -> out_string = "Hit breakpoint number " + repr (bp_no) -> print out_string -> return True -> breakpoint_output (1) -> DONE +def function (frame, bp_loc, internal_dict): + """frame: the lldb.SBFrame for the location at which you stopped + bp_loc: an lldb.SBBreakpointLocation for the breakpoint location information + internal_dict: an LLDB support object not to be used""" + global bp_count + bp_count = bp_count + 1 + print("Hit this breakpoint " + repr(bp_count) + " times!") + DONE )" "In this case, since there is a reference to a global variable, \ @@ -238,20 +245,18 @@ are no syntax errors may indicate that a function was declared but never called. std::string &line) override { io_handler.SetIsDone(true); - std::vector *bp_options_vec = - (std::vector *)io_handler.GetUserData(); - for (BreakpointOptions *bp_options : *bp_options_vec) { - if (!bp_options) - continue; - + std::vector> *bp_options_vec = + (std::vector> *) + io_handler.GetUserData(); + for (BreakpointOptions &bp_options : *bp_options_vec) { auto cmd_data = std::make_unique(); cmd_data->user_source.SplitIntoLines(line.c_str(), line.size()); - bp_options->SetCommandDataCallback(cmd_data); + bp_options.SetCommandDataCallback(cmd_data); } } void CollectDataForBreakpointCommandCallback( - std::vector &bp_options_vec, + std::vector> &bp_options_vec, CommandReturnObject &result) { m_interpreter.GetLLDBCommandsFromIOHandler( "> ", // Prompt @@ -261,25 +266,22 @@ are no syntax errors may indicate that a function was declared but never called. } /// Set a one-liner as the callback for the breakpoint. - void - SetBreakpointCommandCallback(std::vector &bp_options_vec, - const char *oneliner) { - for (auto bp_options : bp_options_vec) { + void SetBreakpointCommandCallback( + std::vector> &bp_options_vec, + const char *oneliner) { + for (BreakpointOptions &bp_options : bp_options_vec) { auto cmd_data = std::make_unique(); cmd_data->user_source.AppendString(oneliner); cmd_data->stop_on_error = m_options.m_stop_on_error; - bp_options->SetCommandDataCallback(cmd_data); + bp_options.SetCommandDataCallback(cmd_data); } } class CommandOptions : public OptionGroup { public: - CommandOptions() - : OptionGroup(), m_use_commands(false), m_use_script_language(false), - m_script_language(eScriptLanguageNone), m_use_one_liner(false), - m_one_liner() {} + CommandOptions() : OptionGroup(), m_one_liner() {} ~CommandOptions() override = default; @@ -349,12 +351,12 @@ are no syntax errors may indicate that a function was declared but never called. // Instance variables to hold the values for command options. - bool m_use_commands; - bool m_use_script_language; - lldb::ScriptLanguage m_script_language; + bool m_use_commands = false; + bool m_use_script_language = false; + lldb::ScriptLanguage m_script_language = eScriptLanguageNone; // Instance variables to hold the values for one_liner options. - bool m_use_one_liner; + bool m_use_one_liner = false; std::string m_one_liner; bool m_stop_on_error; bool m_use_dummy; @@ -369,7 +371,6 @@ protected: if (num_breakpoints == 0) { result.AppendError("No breakpoints exist to have commands added"); - result.SetStatus(eReturnStatusFailed); return false; } @@ -396,20 +397,17 @@ protected: if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID) { Breakpoint *bp = target.GetBreakpointByID(cur_bp_id.GetBreakpointID()).get(); - BreakpointOptions *bp_options = nullptr; if (cur_bp_id.GetLocationID() == LLDB_INVALID_BREAK_ID) { // This breakpoint does not have an associated location. - bp_options = bp->GetOptions(); + m_bp_options_vec.push_back(bp->GetOptions()); } else { BreakpointLocationSP bp_loc_sp( bp->FindLocationByID(cur_bp_id.GetLocationID())); // This breakpoint does have an associated location. Get its // breakpoint options. if (bp_loc_sp) - bp_options = bp_loc_sp->GetLocationOptions(); + m_bp_options_vec.push_back(bp_loc_sp->GetLocationOptions()); } - if (bp_options) - m_bp_options_vec.push_back(bp_options); } } @@ -417,22 +415,23 @@ protected: // to set or collect command callback. Otherwise, call the methods // associated with this object. if (m_options.m_use_script_language) { + Status error; ScriptInterpreter *script_interp = GetDebugger().GetScriptInterpreter( /*can_create=*/true, m_options.m_script_language); // Special handling for one-liner specified inline. if (m_options.m_use_one_liner) { - script_interp->SetBreakpointCommandCallback( + error = script_interp->SetBreakpointCommandCallback( m_bp_options_vec, m_options.m_one_liner.c_str()); } else if (!m_func_options.GetName().empty()) { - Status error = script_interp->SetBreakpointCommandCallbackFunction( + error = script_interp->SetBreakpointCommandCallbackFunction( m_bp_options_vec, m_func_options.GetName().c_str(), m_func_options.GetStructuredData()); - if (!error.Success()) - result.SetError(error); } else { script_interp->CollectDataForBreakpointCommandCallback( m_bp_options_vec, result); } + if (!error.Success()) + result.SetError(error); } else { // Special handling for one-liner specified inline. if (m_options.m_use_one_liner) @@ -451,9 +450,10 @@ private: OptionGroupPythonClassWithDict m_func_options; OptionGroupOptions m_all_options; - std::vector m_bp_options_vec; // This stores the - // breakpoint options that - // we are currently + std::vector> + m_bp_options_vec; // This stores the + // breakpoint options that + // we are currently // collecting commands for. In the CollectData... calls we need to hand this // off to the IOHandler, which may run asynchronously. So we have to have // some way to keep it alive, and not leak it. Making it an ivar of the @@ -502,7 +502,7 @@ public: class CommandOptions : public Options { public: - CommandOptions() : Options(), m_use_dummy(false) {} + CommandOptions() : Options() {} ~CommandOptions() override = default; @@ -532,7 +532,7 @@ public: } // Instance variables to hold the values for command options. - bool m_use_dummy; + bool m_use_dummy = false; }; protected: @@ -544,14 +544,12 @@ protected: if (num_breakpoints == 0) { result.AppendError("No breakpoints exist to have commands deleted"); - result.SetStatus(eReturnStatusFailed); return false; } if (command.empty()) { result.AppendError( "No breakpoint specified from which to delete the commands"); - result.SetStatus(eReturnStatusFailed); return false; } @@ -576,7 +574,6 @@ protected: result.AppendErrorWithFormat("Invalid breakpoint ID: %u.%u.\n", cur_bp_id.GetBreakpointID(), cur_bp_id.GetLocationID()); - result.SetStatus(eReturnStatusFailed); return false; } } else { @@ -627,14 +624,12 @@ protected: if (num_breakpoints == 0) { result.AppendError("No breakpoints exist for which to list commands"); - result.SetStatus(eReturnStatusFailed); return false; } if (command.empty()) { result.AppendError( "No breakpoint specified for which to list the commands"); - result.SetStatus(eReturnStatusFailed); return false; } @@ -659,7 +654,6 @@ protected: result.AppendErrorWithFormat("Invalid breakpoint ID: %u.%u.\n", cur_bp_id.GetBreakpointID(), cur_bp_id.GetLocationID()); - result.SetStatus(eReturnStatusFailed); return false; } } @@ -673,9 +667,9 @@ protected: baton = bp_loc_sp ->GetOptionsSpecifyingKind(BreakpointOptions::eCallback) - ->GetBaton(); + .GetBaton(); else - baton = bp->GetOptions()->GetBaton(); + baton = bp->GetOptions().GetBaton(); if (baton) { result.GetOutputStream().Printf("Breakpoint %s:\n", @@ -694,7 +688,6 @@ protected: } else { result.AppendErrorWithFormat("Invalid breakpoint ID: %u.\n", cur_bp_id.GetBreakpointID()); - result.SetStatus(eReturnStatusFailed); } } } diff --git a/gnu/llvm/lldb/source/Commands/CommandObjectCommands.cpp b/gnu/llvm/lldb/source/Commands/CommandObjectCommands.cpp index d77e69c6f6a..9a8b81c007a 100644 --- a/gnu/llvm/lldb/source/Commands/CommandObjectCommands.cpp +++ b/gnu/llvm/lldb/source/Commands/CommandObjectCommands.cpp @@ -6,15 +6,13 @@ // //===----------------------------------------------------------------------===// -#include "llvm/ADT/StringRef.h" - #include "CommandObjectCommands.h" #include "CommandObjectHelp.h" +#include "CommandObjectRegexCommand.h" #include "lldb/Core/Debugger.h" #include "lldb/Core/IOHandler.h" #include "lldb/Interpreter/CommandHistory.h" #include "lldb/Interpreter/CommandInterpreter.h" -#include "lldb/Interpreter/CommandObjectRegexCommand.h" #include "lldb/Interpreter/CommandReturnObject.h" #include "lldb/Interpreter/OptionArgParser.h" #include "lldb/Interpreter/OptionValueBoolean.h" @@ -24,161 +22,13 @@ #include "lldb/Interpreter/ScriptInterpreter.h" #include "lldb/Utility/Args.h" #include "lldb/Utility/StringList.h" +#include "llvm/ADT/StringRef.h" using namespace lldb; using namespace lldb_private; // CommandObjectCommandsSource -#define LLDB_OPTIONS_history -#include "CommandOptions.inc" - -class CommandObjectCommandsHistory : public CommandObjectParsed { -public: - CommandObjectCommandsHistory(CommandInterpreter &interpreter) - : CommandObjectParsed(interpreter, "command history", - "Dump the history of commands in this session.\n" - "Commands in the history list can be run again " - "using \"!\". \"!-\" will re-run " - "the command that is commands from the end" - " of the list (counting the current command).", - nullptr), - m_options() {} - - ~CommandObjectCommandsHistory() override = default; - - Options *GetOptions() override { return &m_options; } - -protected: - class CommandOptions : public Options { - public: - CommandOptions() - : Options(), m_start_idx(0), m_stop_idx(0), m_count(0), m_clear(false) { - } - - ~CommandOptions() override = default; - - Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, - ExecutionContext *execution_context) override { - Status error; - const int short_option = m_getopt_table[option_idx].val; - - switch (short_option) { - case 'c': - error = m_count.SetValueFromString(option_arg, eVarSetOperationAssign); - break; - case 's': - if (option_arg == "end") { - m_start_idx.SetCurrentValue(UINT64_MAX); - m_start_idx.SetOptionWasSet(); - } else - error = m_start_idx.SetValueFromString(option_arg, - eVarSetOperationAssign); - break; - case 'e': - error = - m_stop_idx.SetValueFromString(option_arg, eVarSetOperationAssign); - break; - case 'C': - m_clear.SetCurrentValue(true); - m_clear.SetOptionWasSet(); - break; - default: - llvm_unreachable("Unimplemented option"); - } - - return error; - } - - void OptionParsingStarting(ExecutionContext *execution_context) override { - m_start_idx.Clear(); - m_stop_idx.Clear(); - m_count.Clear(); - m_clear.Clear(); - } - - llvm::ArrayRef GetDefinitions() override { - return llvm::makeArrayRef(g_history_options); - } - - // Instance variables to hold the values for command options. - - OptionValueUInt64 m_start_idx; - OptionValueUInt64 m_stop_idx; - OptionValueUInt64 m_count; - OptionValueBoolean m_clear; - }; - - bool DoExecute(Args &command, CommandReturnObject &result) override { - if (m_options.m_clear.GetCurrentValue() && - m_options.m_clear.OptionWasSet()) { - m_interpreter.GetCommandHistory().Clear(); - result.SetStatus(lldb::eReturnStatusSuccessFinishNoResult); - } else { - if (m_options.m_start_idx.OptionWasSet() && - m_options.m_stop_idx.OptionWasSet() && - m_options.m_count.OptionWasSet()) { - result.AppendError("--count, --start-index and --end-index cannot be " - "all specified in the same invocation"); - result.SetStatus(lldb::eReturnStatusFailed); - } else { - std::pair start_idx( - m_options.m_start_idx.OptionWasSet(), - m_options.m_start_idx.GetCurrentValue()); - std::pair stop_idx( - m_options.m_stop_idx.OptionWasSet(), - m_options.m_stop_idx.GetCurrentValue()); - std::pair count(m_options.m_count.OptionWasSet(), - m_options.m_count.GetCurrentValue()); - - const CommandHistory &history(m_interpreter.GetCommandHistory()); - - if (start_idx.first && start_idx.second == UINT64_MAX) { - if (count.first) { - start_idx.second = history.GetSize() - count.second; - stop_idx.second = history.GetSize() - 1; - } else if (stop_idx.first) { - start_idx.second = stop_idx.second; - stop_idx.second = history.GetSize() - 1; - } else { - start_idx.second = 0; - stop_idx.second = history.GetSize() - 1; - } - } else { - if (!start_idx.first && !stop_idx.first && !count.first) { - start_idx.second = 0; - stop_idx.second = history.GetSize() - 1; - } else if (start_idx.first) { - if (count.first) { - stop_idx.second = start_idx.second + count.second - 1; - } else if (!stop_idx.first) { - stop_idx.second = history.GetSize() - 1; - } - } else if (stop_idx.first) { - if (count.first) { - if (stop_idx.second >= count.second) - start_idx.second = stop_idx.second - count.second + 1; - else - start_idx.second = 0; - } - } else /* if (count.first) */ - { - start_idx.second = 0; - stop_idx.second = count.second - 1; - } - } - history.Dump(result.GetOutputStream(), start_idx.second, - stop_idx.second); - } - } - return result.Succeeded(); - } - - CommandOptions m_options; -}; - -// CommandObjectCommandsSource - #define LLDB_OPTIONS_source #include "CommandOptions.inc" @@ -278,21 +128,17 @@ protected: result.AppendErrorWithFormat( "'%s' takes exactly one executable filename argument.\n", GetCommandName().str().c_str()); - result.SetStatus(eReturnStatusFailed); return false; } FileSpec cmd_file(command[0].ref()); FileSystem::Instance().Resolve(cmd_file); - ExecutionContext *exe_ctx = nullptr; // Just use the default context. + CommandInterpreterRunOptions options; // If any options were set, then use them if (m_options.m_stop_on_error.OptionWasSet() || m_options.m_silent_run.OptionWasSet() || m_options.m_stop_on_continue.OptionWasSet()) { - // Use user set settings - CommandInterpreterRunOptions options; - if (m_options.m_stop_on_continue.OptionWasSet()) options.SetStopOnContinue( m_options.m_stop_on_continue.GetCurrentValue()); @@ -309,14 +155,9 @@ protected: options.SetEchoCommands(m_interpreter.GetEchoCommands()); options.SetEchoCommentCommands(m_interpreter.GetEchoCommentCommands()); } - - m_interpreter.HandleCommandsFromFile(cmd_file, exe_ctx, options, result); - } else { - // No options were set, inherit any settings from nested "command source" - // commands, or set to sane default settings... - CommandInterpreterRunOptions options; - m_interpreter.HandleCommandsFromFile(cmd_file, exe_ctx, options, result); } + + m_interpreter.HandleCommandsFromFile(cmd_file, options, result); return result.Succeeded(); } @@ -538,7 +379,6 @@ protected: if (args.GetArgumentCount() < 2) { result.AppendError("'command alias' requires at least two arguments"); - result.SetStatus(eReturnStatusFailed); return false; } @@ -551,7 +391,6 @@ protected: result.AppendWarning("if trying to pass options to 'command alias' add " "a -- at the end of the options"); } - result.SetStatus(eReturnStatusFailed); return false; } @@ -565,7 +404,6 @@ protected: raw_command_string = raw_command_string.substr(pos); } else { result.AppendError("Error parsing command string. No alias created."); - result.SetStatus(eReturnStatusFailed); return false; } @@ -574,7 +412,6 @@ protected: result.AppendErrorWithFormat( "'%s' is a permanent debugger command and cannot be redefined.\n", args[0].c_str()); - result.SetStatus(eReturnStatusFailed); return false; } @@ -590,7 +427,6 @@ protected: "'%s' does not begin with a valid command." " No alias created.", original_raw_command_string.str().c_str()); - result.SetStatus(eReturnStatusFailed); return false; } else if (!cmd_obj->WantsRawCommandString()) { // Note that args was initialized with the original command, and has not @@ -614,7 +450,7 @@ protected: OptionArgVectorSP(new OptionArgVector); if (CommandObjectSP cmd_obj_sp = - m_interpreter.GetCommandSPExact(cmd_obj.GetCommandName(), false)) { + m_interpreter.GetCommandSPExact(cmd_obj.GetCommandName())) { if (m_interpreter.AliasExists(alias_command) || m_interpreter.UserCommandExists(alias_command)) { result.AppendWarningWithFormat( @@ -630,12 +466,10 @@ protected: result.SetStatus(eReturnStatusSuccessFinishNoResult); } else { result.AppendError("Unable to create requested alias.\n"); - result.SetStatus(eReturnStatusFailed); } } else { result.AppendError("Unable to create requested alias.\n"); - result.SetStatus(eReturnStatusFailed); } return result.Succeeded(); @@ -646,7 +480,6 @@ protected: if (argc < 2) { result.AppendError("'command alias' requires at least two arguments"); - result.SetStatus(eReturnStatusFailed); return false; } @@ -664,7 +497,6 @@ protected: result.AppendErrorWithFormat( "'%s' is a permanent debugger command and cannot be redefined.\n", alias_command.c_str()); - result.SetStatus(eReturnStatusFailed); return false; } @@ -675,7 +507,6 @@ protected: if (!command_obj_sp) { result.AppendErrorWithFormat("'%s' is not an existing command.\n", actual_command.c_str()); - result.SetStatus(eReturnStatusFailed); return false; } CommandObject *cmd_obj = command_obj_sp.get(); @@ -692,7 +523,6 @@ protected: "'%s' is not a valid sub-command of '%s'. " "Unable to create alias.\n", args[0].c_str(), actual_command.c_str()); - result.SetStatus(eReturnStatusFailed); return false; } @@ -708,10 +538,9 @@ protected: if (!args.empty()) { CommandObjectSP tmp_sp = - m_interpreter.GetCommandSPExact(cmd_obj->GetCommandName(), false); + m_interpreter.GetCommandSPExact(cmd_obj->GetCommandName()); if (use_subcommand) - tmp_sp = m_interpreter.GetCommandSPExact(sub_cmd_obj->GetCommandName(), - false); + tmp_sp = m_interpreter.GetCommandSPExact(sub_cmd_obj->GetCommandName()); args.GetCommandString(args_string); } @@ -732,7 +561,6 @@ protected: result.SetStatus(eReturnStatusSuccessFinishNoResult); } else { result.AppendError("Unable to create requested alias.\n"); - result.SetStatus(eReturnStatusFailed); return false; } @@ -767,6 +595,17 @@ public: ~CommandObjectCommandsUnalias() override = default; + void + HandleArgumentCompletion(CompletionRequest &request, + OptionElementVector &opt_element_vector) override { + if (!m_interpreter.HasCommands() || request.GetCursorIndex() != 0) + return; + + for (const auto &ent : m_interpreter.GetAliases()) { + request.TryCompleteCurrentArg(ent.first, ent.second->GetHelp()); + } + } + protected: bool DoExecute(Args &args, CommandReturnObject &result) override { CommandObject::CommandMap::iterator pos; @@ -774,7 +613,6 @@ protected: if (args.empty()) { result.AppendError("must call 'unalias' with a valid alias"); - result.SetStatus(eReturnStatusFailed); return false; } @@ -785,7 +623,6 @@ protected: "'%s' is not a known command.\nTry 'help' to see a " "current list of commands.\n", args[0].c_str()); - result.SetStatus(eReturnStatusFailed); return false; } @@ -800,7 +637,6 @@ protected: "'%s' is a permanent debugger command and cannot be removed.\n", args[0].c_str()); } - result.SetStatus(eReturnStatusFailed); return false; } @@ -812,7 +648,6 @@ protected: else result.AppendErrorWithFormat("'%s' is not an existing alias.\n", args[0].c_str()); - result.SetStatus(eReturnStatusFailed); return false; } @@ -848,6 +683,18 @@ public: ~CommandObjectCommandsDelete() override = default; + void + HandleArgumentCompletion(CompletionRequest &request, + OptionElementVector &opt_element_vector) override { + if (!m_interpreter.HasCommands() || request.GetCursorIndex() != 0) + return; + + for (const auto &ent : m_interpreter.GetCommands()) { + if (ent.second->IsRemovable()) + request.TryCompleteCurrentArg(ent.first, ent.second->GetHelp()); + } + } + protected: bool DoExecute(Args &args, CommandReturnObject &result) override { CommandObject::CommandMap::iterator pos; @@ -856,7 +703,6 @@ protected: result.AppendErrorWithFormat("must call '%s' with one or more valid user " "defined regular expression command names", GetCommandName().str().c_str()); - result.SetStatus(eReturnStatusFailed); return false; } @@ -869,7 +715,6 @@ protected: &error_msg_stream, command_name, llvm::StringRef(), llvm::StringRef(), generate_upropos, generate_type_lookup); result.AppendError(error_msg_stream.GetString()); - result.SetStatus(eReturnStatusFailed); return false; } @@ -877,7 +722,6 @@ protected: result.AppendErrorWithFormat( "'%s' is a permanent debugger command and cannot be removed.\n", args[0].c_str()); - result.SetStatus(eReturnStatusFailed); return false; } @@ -982,7 +826,6 @@ protected: if (argc == 0) { result.AppendError("usage: 'command regex " "[s/// s/// ...]'\n"); - result.SetStatus(eReturnStatusFailed); return false; } @@ -1023,7 +866,6 @@ protected: } if (error.Fail()) { result.AppendError(error.AsCString()); - result.SetStatus(eReturnStatusFailed); } return result.Succeeded(); @@ -1119,7 +961,7 @@ protected: std::string subst(std::string(regex_sed.substr( second_separator_char_pos + 1, third_separator_char_pos - second_separator_char_pos - 1))); - m_regex_cmd_up->AddRegexCommand(regex.c_str(), subst.c_str()); + m_regex_cmd_up->AddRegexCommand(regex, subst); } return error; } @@ -1239,7 +1081,6 @@ protected: m_function_name.c_str(), raw_command_line, m_synchro, result, error, m_exe_ctx)) { result.AppendError(error.AsCString()); - result.SetStatus(eReturnStatusFailed); } else { // Don't change the status if the command already set it... if (result.GetStatus() == eReturnStatusInvalid) { @@ -1325,7 +1166,6 @@ protected: !scripter->RunScriptBasedCommand(m_cmd_obj_sp, raw_command_line, m_synchro, result, error, m_exe_ctx)) { result.AppendError(error.AsCString()); - result.SetStatus(eReturnStatusFailed); } else { // Don't change the status if the command already set it... if (result.GetStatus() == eReturnStatusInvalid) { @@ -1399,6 +1239,12 @@ protected: case 'r': // NO-OP break; + case 'c': + relative_to_command_file = true; + break; + case 's': + silent = true; + break; default: llvm_unreachable("Unimplemented option"); } @@ -1407,24 +1253,39 @@ protected: } void OptionParsingStarting(ExecutionContext *execution_context) override { + relative_to_command_file = false; } llvm::ArrayRef GetDefinitions() override { return llvm::makeArrayRef(g_script_import_options); } + bool relative_to_command_file = false; + bool silent = false; }; bool DoExecute(Args &command, CommandReturnObject &result) override { if (command.empty()) { result.AppendError("command script import needs one or more arguments"); - result.SetStatus(eReturnStatusFailed); return false; } + FileSpec source_dir = {}; + if (m_options.relative_to_command_file) { + source_dir = GetDebugger().GetCommandInterpreter().GetCurrentSourceDir(); + if (!source_dir) { + result.AppendError("command script import -c can only be specified " + "from a command file"); + return false; + } + } + for (auto &entry : command.entries()) { Status error; - const bool init_session = true; + LoadScriptOptions options; + options.SetInitSession(true); + options.SetSilent(m_options.silent); + // FIXME: this is necessary because CommandObject::CheckRequirements() // assumes that commands won't ever be recursively invoked, but it's // actually possible to craft a Python script that does other "command @@ -1435,12 +1296,12 @@ protected: // more) m_exe_ctx.Clear(); if (GetDebugger().GetScriptInterpreter()->LoadScriptingModule( - entry.c_str(), init_session, error)) { + entry.c_str(), options, error, /*module_sp=*/nullptr, + source_dir)) { result.SetStatus(eReturnStatusSuccessFinishNoResult); } else { result.AppendErrorWithFormat("module importing failed: %s", error.AsCString()); - result.SetStatus(eReturnStatusFailed); } } @@ -1507,8 +1368,7 @@ protected: class CommandOptions : public Options { public: CommandOptions() - : Options(), m_class_name(), m_funct_name(), m_short_help(), - m_synchronicity(eScriptedCommandSynchronicitySynchronous) {} + : Options(), m_class_name(), m_funct_name(), m_short_help() {} ~CommandOptions() override = default; @@ -1562,7 +1422,8 @@ protected: std::string m_class_name; std::string m_funct_name; std::string m_short_help; - ScriptedCommandSynchronicity m_synchronicity; + ScriptedCommandSynchronicity m_synchronicity = + eScriptedCommandSynchronicitySynchronous; }; void IOHandlerActivated(IOHandler &io_handler, bool interactive) override { @@ -1625,13 +1486,11 @@ protected: if (GetDebugger().GetScriptLanguage() != lldb::eScriptLanguagePython) { result.AppendError("only scripting language supported for scripted " "commands is currently Python"); - result.SetStatus(eReturnStatusFailed); return false; } if (command.GetArgumentCount() != 1) { result.AppendError("'command script add' requires one argument"); - result.SetStatus(eReturnStatusFailed); return false; } @@ -1653,14 +1512,12 @@ protected: result.SetStatus(eReturnStatusSuccessFinishNoResult); } else { result.AppendError("cannot add command"); - result.SetStatus(eReturnStatusFailed); } } } else { ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter(); if (!interpreter) { result.AppendError("cannot find ScriptInterpreter"); - result.SetStatus(eReturnStatusFailed); return false; } @@ -1668,7 +1525,6 @@ protected: m_options.m_class_name.c_str()); if (!cmd_obj_sp) { result.AppendError("cannot create helper object"); - result.SetStatus(eReturnStatusFailed); return false; } @@ -1678,7 +1534,6 @@ protected: result.SetStatus(eReturnStatusSuccessFinishNoResult); } else { result.AppendError("cannot add command"); - result.SetStatus(eReturnStatusFailed); } } @@ -1704,7 +1559,6 @@ public: bool DoExecute(Args &command, CommandReturnObject &result) override { if (command.GetArgumentCount() != 0) { result.AppendError("'command script list' doesn't take any arguments"); - result.SetStatus(eReturnStatusFailed); return false; } @@ -1730,7 +1584,6 @@ protected: bool DoExecute(Args &command, CommandReturnObject &result) override { if (command.GetArgumentCount() != 0) { result.AppendError("'command script clear' doesn't take any arguments"); - result.SetStatus(eReturnStatusFailed); return false; } @@ -1781,7 +1634,6 @@ protected: if (command.GetArgumentCount() != 1) { result.AppendError("'command script delete' requires one argument"); - result.SetStatus(eReturnStatusFailed); return false; } @@ -1790,7 +1642,6 @@ protected: if (cmd_name.empty() || !m_interpreter.HasUserCommands() || !m_interpreter.UserCommandExists(cmd_name)) { result.AppendErrorWithFormat("command %s not found", command[0].c_str()); - result.SetStatus(eReturnStatusFailed); return false; } @@ -1850,8 +1701,6 @@ CommandObjectMultiwordCommands::CommandObjectMultiwordCommands( CommandObjectSP(new CommandObjectCommandsDelete(interpreter))); LoadSubCommand( "regex", CommandObjectSP(new CommandObjectCommandsAddRegex(interpreter))); - LoadSubCommand("history", CommandObjectSP( - new CommandObjectCommandsHistory(interpreter))); LoadSubCommand( "script", CommandObjectSP(new CommandObjectMultiwordCommandsScript(interpreter))); diff --git a/gnu/llvm/lldb/source/Commands/CommandObjectDisassemble.cpp b/gnu/llvm/lldb/source/Commands/CommandObjectDisassemble.cpp index cf4d8ed04f8..5e73fb8218a 100644 --- a/gnu/llvm/lldb/source/Commands/CommandObjectDisassemble.cpp +++ b/gnu/llvm/lldb/source/Commands/CommandObjectDisassemble.cpp @@ -23,7 +23,6 @@ static constexpr unsigned default_disasm_byte_size = 32; static constexpr unsigned default_disasm_num_ins = 4; -static constexpr unsigned large_function_threshold = 8000; using namespace lldb; using namespace lldb_private; @@ -32,10 +31,7 @@ using namespace lldb_private; #include "CommandOptions.inc" CommandObjectDisassemble::CommandOptions::CommandOptions() - : Options(), num_lines_context(0), num_instructions(0), func_name(), - current_function(false), start_addr(), end_addr(), at_pc(false), - frame_line(false), plugin_name(), flavor_string(), arch(), - some_location_specified(false), symbol_containing_addr() { + : Options(), func_name(), plugin_name(), flavor_string(), arch() { OptionParsingStarting(nullptr); } @@ -223,7 +219,7 @@ CommandObjectDisassemble::~CommandObjectDisassemble() = default; llvm::Error CommandObjectDisassemble::CheckRangeSize(const AddressRange &range, llvm::StringRef what) { if (m_options.num_instructions > 0 || m_options.force || - range.GetByteSize() < large_function_threshold) + range.GetByteSize() < GetDebugger().GetStopDisassemblyMaxSize()) return llvm::Error::success(); StreamString msg; msg << "Not disassembling " << what << " because it is very large "; @@ -418,7 +414,6 @@ bool CommandObjectDisassemble::DoExecute(Args &command, if (!m_options.arch.IsValid()) { result.AppendError( "use the --arch option or set the target architecture to disassemble"); - result.SetStatus(eReturnStatusFailed); return false; } @@ -438,7 +433,6 @@ bool CommandObjectDisassemble::DoExecute(Args &command, result.AppendErrorWithFormat( "Unable to find Disassembler plug-in for the '%s' architecture.\n", m_options.arch.GetArchitectureName()); - result.SetStatus(eReturnStatusFailed); return false; } else if (flavor_string != nullptr && !disassembler->FlavorValidForArchSpec( m_options.arch, flavor_string)) @@ -454,7 +448,6 @@ bool CommandObjectDisassemble::DoExecute(Args &command, GetCommandInterpreter().GetDebugger().GetTerminalWidth(); GetOptions()->GenerateOptionUsage(result.GetErrorStream(), this, terminal_width); - result.SetStatus(eReturnStatusFailed); return false; } @@ -479,7 +472,6 @@ bool CommandObjectDisassemble::DoExecute(Args &command, GetRangesForSelectedMode(result); if (!ranges) { result.AppendError(toString(ranges.takeError())); - result.SetStatus(eReturnStatusFailed); return result.Succeeded(); } @@ -509,7 +501,6 @@ bool CommandObjectDisassemble::DoExecute(Args &command, "Failed to disassemble memory at 0x%8.8" PRIx64 ".\n", cur_range.GetBaseAddress().GetLoadAddress(target)); } - result.SetStatus(eReturnStatusFailed); } if (print_sc_header) result.GetOutputStream() << "\n"; diff --git a/gnu/llvm/lldb/source/Commands/CommandObjectDisassemble.h b/gnu/llvm/lldb/source/Commands/CommandObjectDisassemble.h index 340bf648de1..a4b3df8724d 100644 --- a/gnu/llvm/lldb/source/Commands/CommandObjectDisassemble.h +++ b/gnu/llvm/lldb/source/Commands/CommandObjectDisassemble.h @@ -46,22 +46,22 @@ public: bool show_mixed; // Show mixed source/assembly bool show_bytes; - uint32_t num_lines_context; - uint32_t num_instructions; + uint32_t num_lines_context = 0; + uint32_t num_instructions = 0; bool raw; std::string func_name; - bool current_function; - lldb::addr_t start_addr; - lldb::addr_t end_addr; - bool at_pc; - bool frame_line; + bool current_function = false; + lldb::addr_t start_addr = 0; + lldb::addr_t end_addr = 0; + bool at_pc = false; + bool frame_line = false; std::string plugin_name; std::string flavor_string; ArchSpec arch; - bool some_location_specified; // If no location was specified, we'll select - // "at_pc". This should be set + bool some_location_specified = false; // If no location was specified, we'll + // select "at_pc". This should be set // in SetOptionValue if anything the selects a location is set. - lldb::addr_t symbol_containing_addr; + lldb::addr_t symbol_containing_addr = 0; bool force = false; }; diff --git a/gnu/llvm/lldb/source/Commands/CommandObjectExpression.cpp b/gnu/llvm/lldb/source/Commands/CommandObjectExpression.cpp index b23adb087b4..bf62f3f297c 100644 --- a/gnu/llvm/lldb/source/Commands/CommandObjectExpression.cpp +++ b/gnu/llvm/lldb/source/Commands/CommandObjectExpression.cpp @@ -292,23 +292,14 @@ void CommandObjectExpression::HandleCompletion(CompletionRequest &request) { options.SetAutoApplyFixIts(false); options.SetGenerateDebugInfo(false); - // We need a valid execution context with a frame pointer for this - // completion, so if we don't have one we should try to make a valid - // execution context. - if (m_interpreter.GetExecutionContext().GetFramePtr() == nullptr) - m_interpreter.UpdateExecutionContext(nullptr); - - // This didn't work, so let's get out before we start doing things that - // expect a valid frame pointer. - if (m_interpreter.GetExecutionContext().GetFramePtr() == nullptr) - return; - ExecutionContext exe_ctx(m_interpreter.GetExecutionContext()); - Target *target = exe_ctx.GetTargetPtr(); + // Get out before we start doing things that expect a valid frame pointer. + if (exe_ctx.GetFramePtr() == nullptr) + return; - if (!target) - target = &GetDummyTarget(); + Target *exe_target = exe_ctx.GetTargetPtr(); + Target &target = exe_target ? *exe_target : GetDummyTarget(); unsigned cursor_pos = request.GetRawCursorPos(); // Get the full user input including the suffix. The suffix is necessary @@ -342,7 +333,7 @@ void CommandObjectExpression::HandleCompletion(CompletionRequest &request) { auto language = exe_ctx.GetFrameRef().GetLanguage(); Status error; - lldb::UserExpressionSP expr(target->GetUserExpressionForLanguage( + lldb::UserExpressionSP expr(target.GetUserExpressionForLanguage( code, llvm::StringRef(), language, UserExpression::eResultTypeAny, options, nullptr, error)); if (error.Fail()) @@ -411,22 +402,25 @@ bool CommandObjectExpression::EvaluateExpression(llvm::StringRef expr, // command object DoExecute has finished when doing multi-line expression // that use an input reader... ExecutionContext exe_ctx(m_interpreter.GetExecutionContext()); - - Target *target = exe_ctx.GetTargetPtr(); - - if (!target) - target = &GetDummyTarget(); + Target *exe_target = exe_ctx.GetTargetPtr(); + Target &target = exe_target ? *exe_target : GetDummyTarget(); lldb::ValueObjectSP result_valobj_sp; StackFrame *frame = exe_ctx.GetFramePtr(); - const EvaluateExpressionOptions options = GetEvalOptions(*target); - ExpressionResults success = target->EvaluateExpression( + if (m_command_options.top_level && !m_command_options.allow_jit) { + result.AppendErrorWithFormat( + "Can't disable JIT compilation for top-level expressions.\n"); + return false; + } + + const EvaluateExpressionOptions options = GetEvalOptions(target); + ExpressionResults success = target.EvaluateExpression( expr, frame, result_valobj_sp, options, &m_fixed_expression); // We only tell you about the FixIt if we applied it. The compiler errors // will suggest the FixIt if it parsed. - if (!m_fixed_expression.empty() && target->GetEnableNotifyAboutFixIts()) { + if (!m_fixed_expression.empty() && target.GetEnableNotifyAboutFixIts()) { if (success == eExpressionCompleted) error_stream.Printf(" Fix-it applied, fixed expression was: \n %s\n", m_fixed_expression.c_str()); @@ -446,7 +440,6 @@ bool CommandObjectExpression::EvaluateExpression(llvm::StringRef expr, result.AppendErrorWithFormat( "expression cannot be used with --element-count %s\n", error.AsCString("")); - result.SetStatus(eReturnStatusFailed); return false; } } diff --git a/gnu/llvm/lldb/source/Commands/CommandObjectFrame.cpp b/gnu/llvm/lldb/source/Commands/CommandObjectFrame.cpp index 6ebad9b5c48..d90e357bf1a 100644 --- a/gnu/llvm/lldb/source/Commands/CommandObjectFrame.cpp +++ b/gnu/llvm/lldb/source/Commands/CommandObjectFrame.cpp @@ -141,7 +141,6 @@ protected: if (m_options.reg.hasValue() || m_options.offset.hasValue()) { result.AppendError( "`frame diagnose --address` is incompatible with other arguments."); - result.SetStatus(eReturnStatusFailed); return false; } valobj_sp = frame_sp->GuessValueForAddress(m_options.address.getValue()); @@ -152,7 +151,6 @@ protected: StopInfoSP stop_info_sp = thread->GetStopInfo(); if (!stop_info_sp) { result.AppendError("No arguments provided, and no stop info."); - result.SetStatus(eReturnStatusFailed); return false; } @@ -161,7 +159,6 @@ protected: if (!valobj_sp) { result.AppendError("No diagnosis available."); - result.SetStatus(eReturnStatusFailed); return false; } @@ -291,17 +288,12 @@ public: void HandleArgumentCompletion(CompletionRequest &request, OptionElementVector &opt_element_vector) override { - if (!m_exe_ctx.HasProcessScope() || request.GetCursorIndex() != 0) + if (request.GetCursorIndex() != 0) return; - lldb::ThreadSP thread_sp = m_exe_ctx.GetThreadSP(); - const uint32_t frame_num = thread_sp->GetStackFrameCount(); - for (uint32_t i = 0; i < frame_num; ++i) { - lldb::StackFrameSP frame_sp = thread_sp->GetStackFrameAtIndex(i); - StreamString strm; - frame_sp->Dump(&strm, false, true); - request.TryCompleteCurrentArg(std::to_string(i), strm.GetString()); - } + CommandCompletions::InvokeCommonCompletionCallbacks( + GetCommandInterpreter(), CommandCompletions::eFrameIndexCompletion, + request, nullptr); } Options *GetOptions() override { return &m_options; } @@ -328,7 +320,6 @@ protected: // If you are already at the bottom of the stack, then just warn // and don't reset the frame. result.AppendError("Already at the bottom of the stack."); - result.SetStatus(eReturnStatusFailed); return false; } else frame_idx = 0; @@ -347,7 +338,6 @@ protected: // If we are already at the top of the stack, just warn and don't // reset the frame. result.AppendError("Already at the top of the stack."); - result.SetStatus(eReturnStatusFailed); return false; } else frame_idx = num_frames - 1; @@ -368,7 +358,6 @@ protected: if (command[0].ref().getAsInteger(0, frame_idx)) { result.AppendErrorWithFormat("invalid frame index argument '%s'.", command[0].c_str()); - result.SetStatus(eReturnStatusFailed); return false; } } else if (command.GetArgumentCount() == 0) { @@ -387,7 +376,6 @@ protected: } else { result.AppendErrorWithFormat("Frame index (%u) out of range.\n", frame_idx); - result.SetStatus(eReturnStatusFailed); } return result.Succeeded(); @@ -465,7 +453,7 @@ public: protected: llvm::StringRef GetScopeString(VariableSP var_sp) { if (!var_sp) - return llvm::StringRef::withNullAsEmpty(nullptr); + return llvm::StringRef(); switch (var_sp->GetScope()) { case eValueTypeVariableGlobal: @@ -482,7 +470,7 @@ protected: break; } - return llvm::StringRef::withNullAsEmpty(nullptr); + return llvm::StringRef(); } bool DoExecute(Args &command, CommandReturnObject &result) override { @@ -855,14 +843,12 @@ bool CommandObjectFrameRecognizerAdd::DoExecute(Args &command, if (m_options.m_class_name.empty()) { result.AppendErrorWithFormat( "%s needs a Python class name (-l argument).\n", m_cmd_name.c_str()); - result.SetStatus(eReturnStatusFailed); return false; } if (m_options.m_module.empty()) { result.AppendErrorWithFormat("%s needs a module name (-s argument).\n", m_cmd_name.c_str()); - result.SetStatus(eReturnStatusFailed); return false; } @@ -870,7 +856,6 @@ bool CommandObjectFrameRecognizerAdd::DoExecute(Args &command, result.AppendErrorWithFormat( "%s needs at least one symbol name (-n argument).\n", m_cmd_name.c_str()); - result.SetStatus(eReturnStatusFailed); return false; } @@ -878,7 +863,6 @@ bool CommandObjectFrameRecognizerAdd::DoExecute(Args &command, result.AppendErrorWithFormat( "%s needs only one symbol regular expression (-n argument).\n", m_cmd_name.c_str()); - result.SetStatus(eReturnStatusFailed); return false; } @@ -898,12 +882,14 @@ bool CommandObjectFrameRecognizerAdd::DoExecute(Args &command, RegularExpressionSP(new RegularExpression(m_options.m_module)); auto func = RegularExpressionSP(new RegularExpression(m_options.m_symbols.front())); - StackFrameRecognizerManager::AddRecognizer(recognizer_sp, module, func); + GetSelectedOrDummyTarget().GetFrameRecognizerManager().AddRecognizer( + recognizer_sp, module, func); } else { auto module = ConstString(m_options.m_module); std::vector symbols(m_options.m_symbols.begin(), m_options.m_symbols.end()); - StackFrameRecognizerManager::AddRecognizer(recognizer_sp, module, symbols); + GetSelectedOrDummyTarget().GetFrameRecognizerManager().AddRecognizer( + recognizer_sp, module, symbols); } #endif @@ -921,7 +907,9 @@ public: protected: bool DoExecute(Args &command, CommandReturnObject &result) override { - StackFrameRecognizerManager::RemoveAllRecognizers(); + GetSelectedOrDummyTarget() + .GetFrameRecognizerManager() + .RemoveAllRecognizers(); result.SetStatus(eReturnStatusSuccessFinishResult); return result.Succeeded(); } @@ -941,7 +929,7 @@ public: if (request.GetCursorIndex() != 0) return; - StackFrameRecognizerManager::ForEach( + GetSelectedOrDummyTarget().GetFrameRecognizerManager().ForEach( [&request](uint32_t rid, std::string rname, std::string module, llvm::ArrayRef symbols, bool regexp) { @@ -969,11 +957,12 @@ protected: "About to delete all frame recognizers, do you want to do that?", true)) { result.AppendMessage("Operation cancelled..."); - result.SetStatus(eReturnStatusFailed); return false; } - StackFrameRecognizerManager::RemoveAllRecognizers(); + GetSelectedOrDummyTarget() + .GetFrameRecognizerManager() + .RemoveAllRecognizers(); result.SetStatus(eReturnStatusSuccessFinishResult); return result.Succeeded(); } @@ -981,7 +970,6 @@ protected: if (command.GetArgumentCount() != 1) { result.AppendErrorWithFormat("'%s' takes zero or one arguments.\n", m_cmd_name.c_str()); - result.SetStatus(eReturnStatusFailed); return false; } @@ -989,11 +977,16 @@ protected: if (!llvm::to_integer(command.GetArgumentAtIndex(0), recognizer_id)) { result.AppendErrorWithFormat("'%s' is not a valid recognizer id.\n", command.GetArgumentAtIndex(0)); - result.SetStatus(eReturnStatusFailed); return false; } - StackFrameRecognizerManager::RemoveRecognizerWithID(recognizer_id); + if (!GetSelectedOrDummyTarget() + .GetFrameRecognizerManager() + .RemoveRecognizerWithID(recognizer_id)) { + result.AppendErrorWithFormat("'%s' is not a valid recognizer id.\n", + command.GetArgumentAtIndex(0)); + return false; + } result.SetStatus(eReturnStatusSuccessFinishResult); return result.Succeeded(); } @@ -1011,7 +1004,7 @@ public: protected: bool DoExecute(Args &command, CommandReturnObject &result) override { bool any_printed = false; - StackFrameRecognizerManager::ForEach( + GetSelectedOrDummyTarget().GetFrameRecognizerManager().ForEach( [&result, &any_printed]( uint32_t recognizer_id, std::string name, std::string module, llvm::ArrayRef symbols, bool regexp) { @@ -1076,38 +1069,34 @@ protected: if (!llvm::to_integer(frame_index_str, frame_index)) { result.AppendErrorWithFormat("'%s' is not a valid frame index.", frame_index_str); - result.SetStatus(eReturnStatusFailed); return false; } Process *process = m_exe_ctx.GetProcessPtr(); if (process == nullptr) { result.AppendError("no process"); - result.SetStatus(eReturnStatusFailed); return false; } Thread *thread = m_exe_ctx.GetThreadPtr(); if (thread == nullptr) { result.AppendError("no thread"); - result.SetStatus(eReturnStatusFailed); return false; } if (command.GetArgumentCount() != 1) { result.AppendErrorWithFormat( "'%s' takes exactly one frame index argument.\n", m_cmd_name.c_str()); - result.SetStatus(eReturnStatusFailed); return false; } StackFrameSP frame_sp = thread->GetStackFrameAtIndex(frame_index); if (!frame_sp) { result.AppendErrorWithFormat("no frame with index %u", frame_index); - result.SetStatus(eReturnStatusFailed); return false; } - auto recognizer = - StackFrameRecognizerManager::GetRecognizerForFrame(frame_sp); + auto recognizer = GetSelectedOrDummyTarget() + .GetFrameRecognizerManager() + .GetRecognizerForFrame(frame_sp); Stream &output_stream = result.GetOutputStream(); output_stream.Printf("frame %d ", frame_index); diff --git a/gnu/llvm/lldb/source/Commands/CommandObjectGUI.cpp b/gnu/llvm/lldb/source/Commands/CommandObjectGUI.cpp index 3f45a26de22..86c47a2f063 100644 --- a/gnu/llvm/lldb/source/Commands/CommandObjectGUI.cpp +++ b/gnu/llvm/lldb/source/Commands/CommandObjectGUI.cpp @@ -22,7 +22,7 @@ CommandObjectGUI::CommandObjectGUI(CommandInterpreter &interpreter) : CommandObjectParsed(interpreter, "gui", "Switch into the curses based GUI mode.", "gui") {} -CommandObjectGUI::~CommandObjectGUI() {} +CommandObjectGUI::~CommandObjectGUI() = default; bool CommandObjectGUI::DoExecute(Args &args, CommandReturnObject &result) { #if LLDB_ENABLE_CURSES @@ -39,11 +39,9 @@ bool CommandObjectGUI::DoExecute(Args &args, CommandReturnObject &result) { result.SetStatus(eReturnStatusSuccessFinishResult); } else { result.AppendError("the gui command requires an interactive terminal."); - result.SetStatus(eReturnStatusFailed); } } else { result.AppendError("the gui command takes no arguments."); - result.SetStatus(eReturnStatusFailed); } return true; #else diff --git a/gnu/llvm/lldb/source/Commands/CommandObjectHelp.cpp b/gnu/llvm/lldb/source/Commands/CommandObjectHelp.cpp index 6dc1868a2af..4643ee30f0f 100644 --- a/gnu/llvm/lldb/source/Commands/CommandObjectHelp.cpp +++ b/gnu/llvm/lldb/source/Commands/CommandObjectHelp.cpp @@ -139,7 +139,6 @@ bool CommandObjectHelp::DoExecute(Args &command, CommandReturnObject &result) { } s.Printf("\n"); result.AppendError(s.GetString()); - result.SetStatus(eReturnStatusFailed); return false; } else if (!sub_cmd_obj) { StreamString error_msg_stream; @@ -147,7 +146,6 @@ bool CommandObjectHelp::DoExecute(Args &command, CommandReturnObject &result) { &error_msg_stream, cmd_string.c_str(), m_interpreter.GetCommandPrefix(), sub_command.c_str()); result.AppendError(error_msg_stream.GetString()); - result.SetStatus(eReturnStatusFailed); return false; } else { GenerateAdditionalHelpAvenuesMessage( @@ -193,7 +191,6 @@ bool CommandObjectHelp::DoExecute(Args &command, CommandReturnObject &result) { m_interpreter.GetCommandPrefix(), ""); result.AppendError(error_msg_stream.GetString()); - result.SetStatus(eReturnStatusFailed); } } } diff --git a/gnu/llvm/lldb/source/Commands/CommandObjectHelp.h b/gnu/llvm/lldb/source/Commands/CommandObjectHelp.h index 8f45db55666..c924dda7c6d 100644 --- a/gnu/llvm/lldb/source/Commands/CommandObjectHelp.h +++ b/gnu/llvm/lldb/source/Commands/CommandObjectHelp.h @@ -34,7 +34,7 @@ public: public: CommandOptions() : Options() {} - ~CommandOptions() override {} + ~CommandOptions() override = default; Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, ExecutionContext *execution_context) override { diff --git a/gnu/llvm/lldb/source/Commands/CommandObjectLanguage.cpp b/gnu/llvm/lldb/source/Commands/CommandObjectLanguage.cpp index e6d22ec4ae4..925db599e4a 100644 --- a/gnu/llvm/lldb/source/Commands/CommandObjectLanguage.cpp +++ b/gnu/llvm/lldb/source/Commands/CommandObjectLanguage.cpp @@ -23,4 +23,4 @@ CommandObjectLanguage::CommandObjectLanguage(CommandInterpreter &interpreter) LanguageRuntime::InitializeCommands(this); } -CommandObjectLanguage::~CommandObjectLanguage() {} +CommandObjectLanguage::~CommandObjectLanguage() = default; diff --git a/gnu/llvm/lldb/source/Commands/CommandObjectLog.cpp b/gnu/llvm/lldb/source/Commands/CommandObjectLog.cpp index 4016b07c91e..05ffba27e65 100644 --- a/gnu/llvm/lldb/source/Commands/CommandObjectLog.cpp +++ b/gnu/llvm/lldb/source/Commands/CommandObjectLog.cpp @@ -76,7 +76,7 @@ public: class CommandOptions : public Options { public: - CommandOptions() : Options(), log_file(), log_options(0) {} + CommandOptions() : Options(), log_file() {} ~CommandOptions() override = default; @@ -136,7 +136,7 @@ public: // Instance variables to hold the values for command options. FileSpec log_file; - uint32_t log_options; + uint32_t log_options = 0; }; void @@ -151,7 +151,6 @@ protected: result.AppendErrorWithFormat( "%s takes a log channel and one or more log types.\n", m_cmd_name.c_str()); - result.SetStatus(eReturnStatusFailed); return false; } @@ -225,7 +224,6 @@ protected: result.AppendErrorWithFormat( "%s takes a log channel and one or more log types.\n", m_cmd_name.c_str()); - result.SetStatus(eReturnStatusFailed); return false; } diff --git a/gnu/llvm/lldb/source/Commands/CommandObjectMemory.cpp b/gnu/llvm/lldb/source/Commands/CommandObjectMemory.cpp index 474c3771014..5487d94c901 100644 --- a/gnu/llvm/lldb/source/Commands/CommandObjectMemory.cpp +++ b/gnu/llvm/lldb/source/Commands/CommandObjectMemory.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "CommandObjectMemory.h" +#include "CommandObjectMemoryTag.h" #include "lldb/Core/DumpDataExtractor.h" #include "lldb/Core/Section.h" #include "lldb/Core/ValueObjectMemory.h" @@ -33,8 +34,7 @@ #include "lldb/Utility/DataBufferHeap.h" #include "lldb/Utility/DataBufferLLVM.h" #include "lldb/Utility/StreamString.h" - - +#include "llvm/Support/MathExtras.h" #include #include @@ -47,8 +47,8 @@ using namespace lldb_private; class OptionGroupReadMemory : public OptionGroup { public: OptionGroupReadMemory() - : m_num_per_line(1, 1), m_output_as_binary(false), m_view_as_type(), - m_offset(0, 0), m_language_for_type(eLanguageTypeUnknown) {} + : m_num_per_line(1, 1), m_view_as_type(), m_offset(0, 0), + m_language_for_type(eLanguageTypeUnknown) {} ~OptionGroupReadMemory() override = default; @@ -271,7 +271,7 @@ public: } OptionValueUInt64 m_num_per_line; - bool m_output_as_binary; + bool m_output_as_binary = false; OptionValueString m_view_as_type; bool m_force; OptionValueUInt64 m_offset; @@ -357,9 +357,8 @@ protected: result.AppendErrorWithFormat("%s takes a start address expression with " "an optional end address expression.\n", m_cmd_name.c_str()); - result.AppendRawWarning("Expressions should be quoted if they contain " - "spaces or other special characters.\n"); - result.SetStatus(eReturnStatusFailed); + result.AppendWarning("Expressions should be quoted if they contain " + "spaces or other special characters."); return false; } @@ -440,7 +439,6 @@ protected: } else { result.AppendErrorWithFormat("invalid type string: '%s'\n", view_as_type_cstr); - result.SetStatus(eReturnStatusFailed); return false; } break; @@ -490,7 +488,6 @@ protected: "Mutiple types found matching raw type '%s', please disambiguate " "by specifying the language with -x", lookup_type_name.GetCString()); - result.SetStatus(eReturnStatusFailed); return false; } @@ -505,7 +502,6 @@ protected: "the raw type '%s' for full type '%s'\n", lookup_type_name.GetCString(), view_as_type_cstr); - result.SetStatus(eReturnStatusFailed); return false; } else { TypeSP type_sp(type_list.GetTypeAtIndex(0)); @@ -519,7 +515,6 @@ protected: compiler_type = pointer_type; else { result.AppendError("unable make a pointer type\n"); - result.SetStatus(eReturnStatusFailed); return false; } --pointer_count; @@ -530,7 +525,6 @@ protected: result.AppendErrorWithFormat( "unable to get the byte size of the type '%s'\n", view_as_type_cstr); - result.SetStatus(eReturnStatusFailed); return false; } m_format_options.GetByteSizeValue() = *size; @@ -544,7 +538,6 @@ protected: // Look for invalid combinations of settings if (error.Fail()) { result.AppendError(error.AsCString()); - result.SetStatus(eReturnStatusFailed); return false; } @@ -594,7 +587,6 @@ protected: if (addr == LLDB_INVALID_ADDRESS) { result.AppendError("invalid start address expression."); result.AppendError(error.AsCString()); - result.SetStatus(eReturnStatusFailed); return false; } @@ -604,21 +596,18 @@ protected: if (end_addr == LLDB_INVALID_ADDRESS) { result.AppendError("invalid end address expression."); result.AppendError(error.AsCString()); - result.SetStatus(eReturnStatusFailed); return false; } else if (end_addr <= addr) { result.AppendErrorWithFormat( "end address (0x%" PRIx64 - ") must be greater that the start address (0x%" PRIx64 ").\n", + ") must be greater than the start address (0x%" PRIx64 ").\n", end_addr, addr); - result.SetStatus(eReturnStatusFailed); return false; } else if (m_format_options.GetCountValue().OptionWasSet()) { result.AppendErrorWithFormat( "specify either the end address (0x%" PRIx64 ") or the count (--count %" PRIu64 "), not both.\n", end_addr, (uint64_t)item_count); - result.SetStatus(eReturnStatusFailed); return false; } @@ -665,13 +654,12 @@ protected: "can't allocate 0x%" PRIx32 " bytes for the memory read buffer, specify a smaller size to read", (uint32_t)total_byte_size); - result.SetStatus(eReturnStatusFailed); return false; } Address address(addr, nullptr); - bytes_read = target->ReadMemory(address, false, data_sp->GetBytes(), - data_sp->GetByteSize(), error); + bytes_read = target->ReadMemory(address, data_sp->GetBytes(), + data_sp->GetByteSize(), error, true); if (bytes_read == 0) { const char *error_cstr = error.AsCString(); if (error_cstr && error_cstr[0]) { @@ -680,7 +668,6 @@ protected: result.AppendErrorWithFormat( "failed to read memory from 0x%" PRIx64 ".\n", addr); } - result.SetStatus(eReturnStatusFailed); return false; } @@ -707,7 +694,6 @@ protected: "can't allocate 0x%" PRIx64 " bytes for the memory read buffer, specify a smaller size to read", (uint64_t)((item_byte_size + 1) * item_count)); - result.SetStatus(eReturnStatusFailed); return false; } uint8_t *data_ptr = data_sp->GetBytes(); @@ -724,7 +710,6 @@ protected: if (error.Fail()) { result.AppendErrorWithFormat( "failed to read memory from 0x%" PRIx64 ".\n", addr); - result.SetStatus(eReturnStatusFailed); return false; } @@ -768,10 +753,11 @@ protected: std::string path = outfile_spec.GetPath(); if (outfile_spec) { - auto open_options = File::eOpenOptionWrite | File::eOpenOptionCanCreate; + File::OpenOptions open_options = + File::eOpenOptionWrite | File::eOpenOptionCanCreate; const bool append = m_outfile_options.GetAppend().GetCurrentValue(); - if (append) - open_options |= File::eOpenOptionAppend; + open_options |= + append ? File::eOpenOptionAppend : File::eOpenOptionTruncate; auto outfile = FileSystem::Instance().Open(outfile_spec, open_options); @@ -790,7 +776,6 @@ protected: result.AppendErrorWithFormat("Failed to write %" PRIu64 " bytes to '%s'.\n", (uint64_t)bytes_read, path.c_str()); - result.SetStatus(eReturnStatusFailed); return false; } } else { @@ -804,7 +789,6 @@ protected: path.c_str(), append ? "append" : "write"); result.AppendError(llvm::toString(outfile.takeError())); - result.SetStatus(eReturnStatusFailed); return false; } } else { @@ -833,7 +817,6 @@ protected: result.AppendErrorWithFormat( "failed to create a value object for: (%s) %s\n", view_as_type_cstr, name_strm.GetData()); - result.SetStatus(eReturnStatusFailed); return false; } } @@ -863,7 +846,6 @@ protected: result.AppendErrorWithFormat( "reading memory as characters of size %" PRIu64 " is not supported", (uint64_t)item_byte_size); - result.SetStatus(eReturnStatusFailed); return false; } } @@ -1281,29 +1263,6 @@ public: Options *GetOptions() override { return &m_option_group; } - bool UIntValueIsValidForSize(uint64_t uval64, size_t total_byte_size) { - if (total_byte_size > 8) - return false; - - if (total_byte_size == 8) - return true; - - const uint64_t max = ((uint64_t)1 << (uint64_t)(total_byte_size * 8)) - 1; - return uval64 <= max; - } - - bool SIntValueIsValidForSize(int64_t sval64, size_t total_byte_size) { - if (total_byte_size > 8) - return false; - - if (total_byte_size == 8) - return true; - - const int64_t max = ((int64_t)1 << (uint64_t)(total_byte_size * 8 - 1)) - 1; - const int64_t min = ~(max); - return min <= sval64 && sval64 <= max; - } - protected: bool DoExecute(Args &command, CommandReturnObject &result) override { // No need to check "process" for validity as eCommandRequiresProcess @@ -1317,14 +1276,12 @@ protected: result.AppendErrorWithFormat( "%s takes a destination address when writing file contents.\n", m_cmd_name.c_str()); - result.SetStatus(eReturnStatusFailed); return false; } } else if (argc < 2) { result.AppendErrorWithFormat( "%s takes a destination address and at least one value.\n", m_cmd_name.c_str()); - result.SetStatus(eReturnStatusFailed); return false; } @@ -1343,7 +1300,6 @@ protected: if (addr == LLDB_INVALID_ADDRESS) { result.AppendError("invalid address expression\n"); result.AppendError(error.AsCString()); - result.SetStatus(eReturnStatusFailed); return false; } @@ -1378,12 +1334,10 @@ protected: result.AppendErrorWithFormat("Memory write to 0x%" PRIx64 " failed: %s.\n", addr, error.AsCString()); - result.SetStatus(eReturnStatusFailed); } } } else { result.AppendErrorWithFormat("Unable to read contents of file.\n"); - result.SetStatus(eReturnStatusFailed); } return result.Succeeded(); } else if (item_byte_size == 0) { @@ -1428,7 +1382,6 @@ protected: case eFormatInstruction: case eFormatVoid: result.AppendError("unsupported format for writing memory"); - result.SetStatus(eReturnStatusFailed); return false; case eFormatDefault: @@ -1447,14 +1400,12 @@ protected: if (!success) { result.AppendErrorWithFormat( "'%s' is not a valid hex string value.\n", entry.c_str()); - result.SetStatus(eReturnStatusFailed); return false; - } else if (!UIntValueIsValidForSize(uval64, item_byte_size)) { + } else if (!llvm::isUIntN(item_byte_size * 8, uval64)) { result.AppendErrorWithFormat("Value 0x%" PRIx64 " is too large to fit in a %" PRIu64 " byte unsigned integer value.\n", uval64, (uint64_t)item_byte_size); - result.SetStatus(eReturnStatusFailed); return false; } buffer.PutMaxHex64(uval64, item_byte_size); @@ -1465,7 +1416,6 @@ protected: if (!success) { result.AppendErrorWithFormat( "'%s' is not a valid boolean string value.\n", entry.c_str()); - result.SetStatus(eReturnStatusFailed); return false; } buffer.PutMaxHex64(uval64, item_byte_size); @@ -1475,14 +1425,12 @@ protected: if (entry.ref().getAsInteger(2, uval64)) { result.AppendErrorWithFormat( "'%s' is not a valid binary string value.\n", entry.c_str()); - result.SetStatus(eReturnStatusFailed); return false; - } else if (!UIntValueIsValidForSize(uval64, item_byte_size)) { + } else if (!llvm::isUIntN(item_byte_size * 8, uval64)) { result.AppendErrorWithFormat("Value 0x%" PRIx64 " is too large to fit in a %" PRIu64 " byte unsigned integer value.\n", uval64, (uint64_t)item_byte_size); - result.SetStatus(eReturnStatusFailed); return false; } buffer.PutMaxHex64(uval64, item_byte_size); @@ -1505,7 +1453,6 @@ protected: result.AppendErrorWithFormat("Memory write to 0x%" PRIx64 " failed: %s.\n", addr, error.AsCString()); - result.SetStatus(eReturnStatusFailed); return false; } break; @@ -1514,14 +1461,12 @@ protected: if (entry.ref().getAsInteger(0, sval64)) { result.AppendErrorWithFormat( "'%s' is not a valid signed decimal value.\n", entry.c_str()); - result.SetStatus(eReturnStatusFailed); return false; - } else if (!SIntValueIsValidForSize(sval64, item_byte_size)) { + } else if (!llvm::isIntN(item_byte_size * 8, sval64)) { result.AppendErrorWithFormat( "Value %" PRIi64 " is too large or small to fit in a %" PRIu64 " byte signed integer value.\n", sval64, (uint64_t)item_byte_size); - result.SetStatus(eReturnStatusFailed); return false; } buffer.PutMaxHex64(sval64, item_byte_size); @@ -1529,18 +1474,16 @@ protected: case eFormatUnsigned: - if (!entry.ref().getAsInteger(0, uval64)) { + if (entry.ref().getAsInteger(0, uval64)) { result.AppendErrorWithFormat( "'%s' is not a valid unsigned decimal string value.\n", entry.c_str()); - result.SetStatus(eReturnStatusFailed); return false; - } else if (!UIntValueIsValidForSize(uval64, item_byte_size)) { + } else if (!llvm::isUIntN(item_byte_size * 8, uval64)) { result.AppendErrorWithFormat("Value %" PRIu64 " is too large to fit in a %" PRIu64 " byte unsigned integer value.\n", uval64, (uint64_t)item_byte_size); - result.SetStatus(eReturnStatusFailed); return false; } buffer.PutMaxHex64(uval64, item_byte_size); @@ -1550,14 +1493,12 @@ protected: if (entry.ref().getAsInteger(8, uval64)) { result.AppendErrorWithFormat( "'%s' is not a valid octal string value.\n", entry.c_str()); - result.SetStatus(eReturnStatusFailed); return false; - } else if (!UIntValueIsValidForSize(uval64, item_byte_size)) { + } else if (!llvm::isUIntN(item_byte_size * 8, uval64)) { result.AppendErrorWithFormat("Value %" PRIo64 " is too large to fit in a %" PRIu64 " byte unsigned integer value.\n", uval64, (uint64_t)item_byte_size); - result.SetStatus(eReturnStatusFailed); return false; } buffer.PutMaxHex64(uval64, item_byte_size); @@ -1575,7 +1516,6 @@ protected: result.AppendErrorWithFormat("Memory write to 0x%" PRIx64 " failed: %s.\n", addr, error.AsCString()); - result.SetStatus(eReturnStatusFailed); return false; } } @@ -1628,7 +1568,6 @@ protected: if (argc == 0 || argc > 1) { result.AppendErrorWithFormat("%s takes an address expression", m_cmd_name.c_str()); - result.SetStatus(eReturnStatusFailed); return false; } @@ -1639,7 +1578,6 @@ protected: if (addr == LLDB_INVALID_ADDRESS) { result.AppendError("invalid address expression"); result.AppendError(error.AsCString()); - result.SetStatus(eReturnStatusFailed); return false; } @@ -1651,7 +1589,6 @@ protected: if (!memory_history) { result.AppendError("no available memory history provider"); - result.SetStatus(eReturnStatusFailed); return false; } @@ -1687,63 +1624,90 @@ public: protected: bool DoExecute(Args &command, CommandReturnObject &result) override { ProcessSP process_sp = m_exe_ctx.GetProcessSP(); - if (process_sp) { - Status error; - lldb::addr_t load_addr = m_prev_end_addr; + if (!process_sp) { m_prev_end_addr = LLDB_INVALID_ADDRESS; + result.AppendError("invalid process"); + return false; + } - const size_t argc = command.GetArgumentCount(); - if (argc > 1 || (argc == 0 && load_addr == LLDB_INVALID_ADDRESS)) { - result.AppendErrorWithFormat("'%s' takes one argument:\nUsage: %s\n", - m_cmd_name.c_str(), m_cmd_syntax.c_str()); - result.SetStatus(eReturnStatusFailed); - } else { - if (command.GetArgumentCount() == 1) { - auto load_addr_str = command[0].ref(); - load_addr = OptionArgParser::ToAddress(&m_exe_ctx, load_addr_str, - LLDB_INVALID_ADDRESS, &error); - if (error.Fail() || load_addr == LLDB_INVALID_ADDRESS) { - result.AppendErrorWithFormat( - "invalid address argument \"%s\": %s\n", command[0].c_str(), - error.AsCString()); - result.SetStatus(eReturnStatusFailed); - } + Status error; + lldb::addr_t load_addr = m_prev_end_addr; + m_prev_end_addr = LLDB_INVALID_ADDRESS; + + const size_t argc = command.GetArgumentCount(); + if (argc > 1 || (argc == 0 && load_addr == LLDB_INVALID_ADDRESS)) { + result.AppendErrorWithFormat("'%s' takes one argument:\nUsage: %s\n", + m_cmd_name.c_str(), m_cmd_syntax.c_str()); + return false; + } + + if (argc == 1) { + auto load_addr_str = command[0].ref(); + load_addr = OptionArgParser::ToAddress(&m_exe_ctx, load_addr_str, + LLDB_INVALID_ADDRESS, &error); + if (error.Fail() || load_addr == LLDB_INVALID_ADDRESS) { + result.AppendErrorWithFormat("invalid address argument \"%s\": %s\n", + command[0].c_str(), error.AsCString()); + return false; + } + } + + lldb_private::MemoryRegionInfo range_info; + error = process_sp->GetMemoryRegionInfo(load_addr, range_info); + if (error.Success()) { + lldb_private::Address addr; + ConstString name = range_info.GetName(); + ConstString section_name; + if (process_sp->GetTarget().ResolveLoadAddress(load_addr, addr)) { + SectionSP section_sp(addr.GetSection()); + if (section_sp) { + // Got the top most section, not the deepest section + while (section_sp->GetParent()) + section_sp = section_sp->GetParent(); + section_name = section_sp->GetName(); } + } - lldb_private::MemoryRegionInfo range_info; - error = process_sp->GetMemoryRegionInfo(load_addr, range_info); - if (error.Success()) { - lldb_private::Address addr; - ConstString name = range_info.GetName(); - ConstString section_name; - if (process_sp->GetTarget().ResolveLoadAddress(load_addr, addr)) { - SectionSP section_sp(addr.GetSection()); - if (section_sp) { - // Got the top most section, not the deepest section - while (section_sp->GetParent()) - section_sp = section_sp->GetParent(); - section_name = section_sp->GetName(); - } + result.AppendMessageWithFormatv( + "[{0:x16}-{1:x16}) {2:r}{3:w}{4:x}{5}{6}{7}{8}", + range_info.GetRange().GetRangeBase(), + range_info.GetRange().GetRangeEnd(), range_info.GetReadable(), + range_info.GetWritable(), range_info.GetExecutable(), name ? " " : "", + name, section_name ? " " : "", section_name); + MemoryRegionInfo::OptionalBool memory_tagged = + range_info.GetMemoryTagged(); + if (memory_tagged == MemoryRegionInfo::OptionalBool::eYes) + result.AppendMessage("memory tagging: enabled"); + + const llvm::Optional> &dirty_page_list = + range_info.GetDirtyPageList(); + if (dirty_page_list.hasValue()) { + const size_t page_count = dirty_page_list.getValue().size(); + result.AppendMessageWithFormat( + "Modified memory (dirty) page list provided, %zu entries.\n", + page_count); + if (page_count > 0) { + bool print_comma = false; + result.AppendMessageWithFormat("Dirty pages: "); + for (size_t i = 0; i < page_count; i++) { + if (print_comma) + result.AppendMessageWithFormat(", "); + else + print_comma = true; + result.AppendMessageWithFormat("0x%" PRIx64, + dirty_page_list.getValue()[i]); } - result.AppendMessageWithFormatv( - "[{0:x16}-{1:x16}) {2:r}{3:w}{4:x}{5}{6}{7}{8}\n", - range_info.GetRange().GetRangeBase(), - range_info.GetRange().GetRangeEnd(), range_info.GetReadable(), - range_info.GetWritable(), range_info.GetExecutable(), - name ? " " : "", name, section_name ? " " : "", section_name); - m_prev_end_addr = range_info.GetRange().GetRangeEnd(); - result.SetStatus(eReturnStatusSuccessFinishResult); - } else { - result.SetStatus(eReturnStatusFailed); - result.AppendErrorWithFormat("%s\n", error.AsCString()); + result.AppendMessageWithFormat(".\n"); } } - } else { - m_prev_end_addr = LLDB_INVALID_ADDRESS; - result.AppendError("invalid process"); - result.SetStatus(eReturnStatusFailed); + + m_prev_end_addr = range_info.GetRange().GetRangeEnd(); + result.SetStatus(eReturnStatusSuccessFinishResult); + return true; } - return result.Succeeded(); + + result.AppendErrorWithFormat("%s\n", error.AsCString()); + return false; } const char *GetRepeatCommand(Args ¤t_command_args, @@ -1773,6 +1737,8 @@ CommandObjectMemory::CommandObjectMemory(CommandInterpreter &interpreter) CommandObjectSP(new CommandObjectMemoryHistory(interpreter))); LoadSubCommand("region", CommandObjectSP(new CommandObjectMemoryRegion(interpreter))); + LoadSubCommand("tag", + CommandObjectSP(new CommandObjectMemoryTag(interpreter))); } CommandObjectMemory::~CommandObjectMemory() = default; diff --git a/gnu/llvm/lldb/source/Commands/CommandObjectMemoryTag.cpp b/gnu/llvm/lldb/source/Commands/CommandObjectMemoryTag.cpp new file mode 100644 index 00000000000..840f81719d7 --- /dev/null +++ b/gnu/llvm/lldb/source/Commands/CommandObjectMemoryTag.cpp @@ -0,0 +1,300 @@ +//===-- CommandObjectMemoryTag.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 "CommandObjectMemoryTag.h" +#include "lldb/Host/OptionParser.h" +#include "lldb/Interpreter/CommandReturnObject.h" +#include "lldb/Interpreter/OptionArgParser.h" +#include "lldb/Interpreter/OptionGroupFormat.h" +#include "lldb/Interpreter/OptionValueString.h" +#include "lldb/Target/Process.h" + +using namespace lldb; +using namespace lldb_private; + +#define LLDB_OPTIONS_memory_tag_read +#include "CommandOptions.inc" + +class CommandObjectMemoryTagRead : public CommandObjectParsed { +public: + CommandObjectMemoryTagRead(CommandInterpreter &interpreter) + : CommandObjectParsed(interpreter, "tag", + "Read memory tags for the given range of memory." + " Mismatched tags will be marked.", + nullptr, + eCommandRequiresTarget | eCommandRequiresProcess | + eCommandProcessMustBePaused) { + // Address + m_arguments.push_back( + CommandArgumentEntry{CommandArgumentData(eArgTypeAddressOrExpression)}); + // Optional end address + m_arguments.push_back(CommandArgumentEntry{ + CommandArgumentData(eArgTypeAddressOrExpression, eArgRepeatOptional)}); + } + + ~CommandObjectMemoryTagRead() override = default; + +protected: + bool DoExecute(Args &command, CommandReturnObject &result) override { + if ((command.GetArgumentCount() < 1) || (command.GetArgumentCount() > 2)) { + result.AppendError( + "wrong number of arguments; expected at least , " + "at most "); + return false; + } + + Status error; + addr_t start_addr = OptionArgParser::ToAddress( + &m_exe_ctx, command[0].ref(), LLDB_INVALID_ADDRESS, &error); + if (start_addr == LLDB_INVALID_ADDRESS) { + result.AppendErrorWithFormatv("Invalid address expression, {0}", + error.AsCString()); + return false; + } + + // Default 1 byte beyond start, rounds up to at most 1 granule later + addr_t end_addr = start_addr + 1; + + if (command.GetArgumentCount() > 1) { + end_addr = OptionArgParser::ToAddress(&m_exe_ctx, command[1].ref(), + LLDB_INVALID_ADDRESS, &error); + if (end_addr == LLDB_INVALID_ADDRESS) { + result.AppendErrorWithFormatv("Invalid end address expression, {0}", + error.AsCString()); + return false; + } + } + + Process *process = m_exe_ctx.GetProcessPtr(); + llvm::Expected tag_manager_or_err = + process->GetMemoryTagManager(); + + if (!tag_manager_or_err) { + result.SetError(Status(tag_manager_or_err.takeError())); + return false; + } + + const MemoryTagManager *tag_manager = *tag_manager_or_err; + + MemoryRegionInfos memory_regions; + // If this fails the list of regions is cleared, so we don't need to read + // the return status here. + process->GetMemoryRegions(memory_regions); + llvm::Expected tagged_range = + tag_manager->MakeTaggedRange(start_addr, end_addr, memory_regions); + + if (!tagged_range) { + result.SetError(Status(tagged_range.takeError())); + return false; + } + + llvm::Expected> tags = process->ReadMemoryTags( + tagged_range->GetRangeBase(), tagged_range->GetByteSize()); + + if (!tags) { + result.SetError(Status(tags.takeError())); + return false; + } + + lldb::addr_t logical_tag = tag_manager->GetLogicalTag(start_addr); + result.AppendMessageWithFormatv("Logical tag: {0:x}", logical_tag); + result.AppendMessage("Allocation tags:"); + + addr_t addr = tagged_range->GetRangeBase(); + for (auto tag : *tags) { + addr_t next_addr = addr + tag_manager->GetGranuleSize(); + // Showing tagged adresses here until we have non address bit handling + result.AppendMessageWithFormatv("[{0:x}, {1:x}): {2:x}{3}", addr, + next_addr, tag, + logical_tag == tag ? "" : " (mismatch)"); + addr = next_addr; + } + + result.SetStatus(eReturnStatusSuccessFinishResult); + return true; + } +}; + +#define LLDB_OPTIONS_memory_tag_write +#include "CommandOptions.inc" + +class CommandObjectMemoryTagWrite : public CommandObjectParsed { +public: + class OptionGroupTagWrite : public OptionGroup { + public: + OptionGroupTagWrite() : OptionGroup(), m_end_addr(LLDB_INVALID_ADDRESS) {} + + ~OptionGroupTagWrite() override = default; + + llvm::ArrayRef GetDefinitions() override { + return llvm::makeArrayRef(g_memory_tag_write_options); + } + + Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_value, + ExecutionContext *execution_context) override { + Status status; + const int short_option = + g_memory_tag_write_options[option_idx].short_option; + + switch (short_option) { + case 'e': + m_end_addr = OptionArgParser::ToAddress(execution_context, option_value, + LLDB_INVALID_ADDRESS, &status); + break; + default: + llvm_unreachable("Unimplemented option"); + } + + return status; + } + + void OptionParsingStarting(ExecutionContext *execution_context) override { + m_end_addr = LLDB_INVALID_ADDRESS; + } + + lldb::addr_t m_end_addr; + }; + + CommandObjectMemoryTagWrite(CommandInterpreter &interpreter) + : CommandObjectParsed(interpreter, "tag", + "Write memory tags starting from the granule that " + "contains the given address.", + nullptr, + eCommandRequiresTarget | eCommandRequiresProcess | + eCommandProcessMustBePaused), + m_option_group(), m_tag_write_options() { + // Address + m_arguments.push_back( + CommandArgumentEntry{CommandArgumentData(eArgTypeAddressOrExpression)}); + // One or more tag values + m_arguments.push_back(CommandArgumentEntry{ + CommandArgumentData(eArgTypeValue, eArgRepeatPlus)}); + + m_option_group.Append(&m_tag_write_options); + m_option_group.Finalize(); + } + + ~CommandObjectMemoryTagWrite() override = default; + + Options *GetOptions() override { return &m_option_group; } + +protected: + bool DoExecute(Args &command, CommandReturnObject &result) override { + if (command.GetArgumentCount() < 2) { + result.AppendError("wrong number of arguments; expected " + " [ [...]]"); + return false; + } + + Status error; + addr_t start_addr = OptionArgParser::ToAddress( + &m_exe_ctx, command[0].ref(), LLDB_INVALID_ADDRESS, &error); + if (start_addr == LLDB_INVALID_ADDRESS) { + result.AppendErrorWithFormatv("Invalid address expression, {0}", + error.AsCString()); + return false; + } + + command.Shift(); // shift off start address + + std::vector tags; + for (auto &entry : command) { + lldb::addr_t tag_value; + // getAsInteger returns true on failure + if (entry.ref().getAsInteger(0, tag_value)) { + result.AppendErrorWithFormat( + "'%s' is not a valid unsigned decimal string value.\n", + entry.c_str()); + return false; + } + tags.push_back(tag_value); + } + + Process *process = m_exe_ctx.GetProcessPtr(); + llvm::Expected tag_manager_or_err = + process->GetMemoryTagManager(); + + if (!tag_manager_or_err) { + result.SetError(Status(tag_manager_or_err.takeError())); + return false; + } + + const MemoryTagManager *tag_manager = *tag_manager_or_err; + + MemoryRegionInfos memory_regions; + // If this fails the list of regions is cleared, so we don't need to read + // the return status here. + process->GetMemoryRegions(memory_regions); + + // We have to assume start_addr is not granule aligned. + // So if we simply made a range: + // (start_addr, start_addr + (N * granule_size)) + // We would end up with a range that isn't N granules but N+1 + // granules. To avoid this we'll align the start first using the method that + // doesn't check memory attributes. (if the final range is untagged we'll + // handle that error later) + lldb::addr_t aligned_start_addr = + tag_manager->ExpandToGranule(MemoryTagManager::TagRange(start_addr, 1)) + .GetRangeBase(); + + lldb::addr_t end_addr = 0; + // When you have an end address you want to align the range like tag read + // does. Meaning, align the start down (which we've done) and align the end + // up. + if (m_tag_write_options.m_end_addr != LLDB_INVALID_ADDRESS) + end_addr = m_tag_write_options.m_end_addr; + else + // Without an end address assume number of tags matches number of granules + // to write to + end_addr = + aligned_start_addr + (tags.size() * tag_manager->GetGranuleSize()); + + // Now we've aligned the start address so if we ask for another range + // using the number of tags N, we'll get back a range that is also N + // granules in size. + llvm::Expected tagged_range = + tag_manager->MakeTaggedRange(aligned_start_addr, end_addr, + memory_regions); + + if (!tagged_range) { + result.SetError(Status(tagged_range.takeError())); + return false; + } + + Status status = process->WriteMemoryTags(tagged_range->GetRangeBase(), + tagged_range->GetByteSize(), tags); + + if (status.Fail()) { + result.SetError(status); + return false; + } + + result.SetStatus(eReturnStatusSuccessFinishResult); + return true; + } + + OptionGroupOptions m_option_group; + OptionGroupTagWrite m_tag_write_options; +}; + +CommandObjectMemoryTag::CommandObjectMemoryTag(CommandInterpreter &interpreter) + : CommandObjectMultiword( + interpreter, "tag", "Commands for manipulating memory tags", + "memory tag []") { + CommandObjectSP read_command_object( + new CommandObjectMemoryTagRead(interpreter)); + read_command_object->SetCommandName("memory tag read"); + LoadSubCommand("read", read_command_object); + + CommandObjectSP write_command_object( + new CommandObjectMemoryTagWrite(interpreter)); + write_command_object->SetCommandName("memory tag write"); + LoadSubCommand("write", write_command_object); +} + +CommandObjectMemoryTag::~CommandObjectMemoryTag() = default; diff --git a/gnu/llvm/lldb/source/Commands/CommandObjectMemoryTag.h b/gnu/llvm/lldb/source/Commands/CommandObjectMemoryTag.h new file mode 100644 index 00000000000..54909ac9081 --- /dev/null +++ b/gnu/llvm/lldb/source/Commands/CommandObjectMemoryTag.h @@ -0,0 +1,25 @@ +//===-- CommandObjectMemoryTag.h --------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SOURCE_COMMANDS_COMMANDOBJECTMEMORYTAG_H +#define LLDB_SOURCE_COMMANDS_COMMANDOBJECTMEMORYTAG_H + +#include "lldb/Interpreter/CommandObjectMultiword.h" + +namespace lldb_private { + +class CommandObjectMemoryTag : public CommandObjectMultiword { +public: + CommandObjectMemoryTag(CommandInterpreter &interpreter); + + ~CommandObjectMemoryTag() override; +}; + +} // namespace lldb_private + +#endif // LLDB_SOURCE_COMMANDS_COMMANDOBJECTMEMORYTAG_H diff --git a/gnu/llvm/lldb/source/Commands/CommandObjectMultiword.cpp b/gnu/llvm/lldb/source/Commands/CommandObjectMultiword.cpp index 9033cfebf46..a523fd0b156 100644 --- a/gnu/llvm/lldb/source/Commands/CommandObjectMultiword.cpp +++ b/gnu/llvm/lldb/source/Commands/CommandObjectMultiword.cpp @@ -98,7 +98,7 @@ bool CommandObjectMultiword::Execute(const char *args_string, return result.Succeeded(); } - if (sub_command.equals_lower("help")) { + if (sub_command.equals_insensitive("help")) { this->CommandObject::GenerateHelpText(result); return result.Succeeded(); } @@ -106,7 +106,6 @@ bool CommandObjectMultiword::Execute(const char *args_string, if (m_subcommand_dict.empty()) { result.AppendErrorWithFormat("'%s' does not have any subcommands.\n", GetCommandName().str().c_str()); - result.SetStatus(eReturnStatusFailed); return false; } @@ -144,7 +143,6 @@ bool CommandObjectMultiword::Execute(const char *args_string, } error_msg.append("\n"); result.AppendRawError(error_msg.c_str()); - result.SetStatus(eReturnStatusFailed); return false; } @@ -261,11 +259,32 @@ CommandObjectProxy::CommandObjectProxy(CommandInterpreter &interpreter, CommandObjectProxy::~CommandObjectProxy() = default; +Options *CommandObjectProxy::GetOptions() { + CommandObject *proxy_command = GetProxyCommandObject(); + if (proxy_command) + return proxy_command->GetOptions(); + return CommandObject::GetOptions(); +} + +llvm::StringRef CommandObjectProxy::GetHelp() { + CommandObject *proxy_command = GetProxyCommandObject(); + if (proxy_command) + return proxy_command->GetHelp(); + return CommandObject::GetHelp(); +} + +llvm::StringRef CommandObjectProxy::GetSyntax() { + CommandObject *proxy_command = GetProxyCommandObject(); + if (proxy_command) + return proxy_command->GetSyntax(); + return CommandObject::GetSyntax(); +} + llvm::StringRef CommandObjectProxy::GetHelpLong() { CommandObject *proxy_command = GetProxyCommandObject(); if (proxy_command) return proxy_command->GetHelpLong(); - return llvm::StringRef(); + return CommandObject::GetHelpLong(); } bool CommandObjectProxy::IsRemovable() const { @@ -293,7 +312,9 @@ CommandObjectMultiword *CommandObjectProxy::GetAsMultiwordCommand() { void CommandObjectProxy::GenerateHelpText(Stream &result) { CommandObject *proxy_command = GetProxyCommandObject(); if (proxy_command) - return proxy_command->GenerateHelpText(result); + proxy_command->GenerateHelpText(result); + else + CommandObject::GenerateHelpText(result); } lldb::CommandObjectSP @@ -345,13 +366,6 @@ bool CommandObjectProxy::WantsCompletion() { return false; } -Options *CommandObjectProxy::GetOptions() { - CommandObject *proxy_command = GetProxyCommandObject(); - if (proxy_command) - return proxy_command->GetOptions(); - return nullptr; -} - void CommandObjectProxy::HandleCompletion(CompletionRequest &request) { CommandObject *proxy_command = GetProxyCommandObject(); if (proxy_command) @@ -373,12 +387,15 @@ const char *CommandObjectProxy::GetRepeatCommand(Args ¤t_command_args, return nullptr; } +llvm::StringRef CommandObjectProxy::GetUnsupportedError() { + return "command is not implemented"; +} + bool CommandObjectProxy::Execute(const char *args_string, CommandReturnObject &result) { CommandObject *proxy_command = GetProxyCommandObject(); if (proxy_command) return proxy_command->Execute(args_string, result); - result.AppendError("command is not implemented"); - result.SetStatus(eReturnStatusFailed); + result.AppendError(GetUnsupportedError()); return false; } diff --git a/gnu/llvm/lldb/source/Commands/CommandObjectPlatform.cpp b/gnu/llvm/lldb/source/Commands/CommandObjectPlatform.cpp index fcc8af6f915..bf23c4552aa 100644 --- a/gnu/llvm/lldb/source/Commands/CommandObjectPlatform.cpp +++ b/gnu/llvm/lldb/source/Commands/CommandObjectPlatform.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "CommandObjectPlatform.h" +#include "CommandOptionsProcessLaunch.h" #include "lldb/Core/Debugger.h" #include "lldb/Core/Module.h" #include "lldb/Core/PluginManager.h" @@ -59,7 +60,7 @@ static mode_t ParsePermissionString(llvm::StringRef permissions) { class OptionPermissions : public OptionGroup { public: - OptionPermissions() {} + OptionPermissions() = default; ~OptionPermissions() override = default; @@ -179,16 +180,13 @@ protected: result.SetStatus(eReturnStatusSuccessFinishResult); } else { result.AppendError(error.AsCString()); - result.SetStatus(eReturnStatusFailed); } } else { result.AppendError("invalid platform name"); - result.SetStatus(eReturnStatusFailed); } } else { result.AppendError( "platform create takes a platform name as an argument\n"); - result.SetStatus(eReturnStatusFailed); } return result.Succeeded(); } @@ -231,7 +229,6 @@ protected: if (idx == 0) { result.AppendError("no platforms are available\n"); - result.SetStatus(eReturnStatusFailed); } else result.SetStatus(eReturnStatusSuccessFinishResult); return result.Succeeded(); @@ -265,7 +262,6 @@ protected: result.SetStatus(eReturnStatusSuccessFinishResult); } else { result.AppendError("no platform is currently selected\n"); - result.SetStatus(eReturnStatusFailed); } return result.Succeeded(); } @@ -297,15 +293,12 @@ protected: platform_sp->ConnectToWaitingProcesses(GetDebugger(), error); if (error.Fail()) { result.AppendError(error.AsCString()); - result.SetStatus(eReturnStatusFailed); } } else { result.AppendErrorWithFormat("%s\n", error.AsCString()); - result.SetStatus(eReturnStatusFailed); } } else { result.AppendError("no platform is currently selected\n"); - result.SetStatus(eReturnStatusFailed); } return result.Succeeded(); } @@ -360,24 +353,20 @@ protected: result.SetStatus(eReturnStatusSuccessFinishResult); } else { result.AppendErrorWithFormat("%s", error.AsCString()); - result.SetStatus(eReturnStatusFailed); } } else { // Not connected... result.AppendErrorWithFormat( "not connected to '%s'", platform_sp->GetPluginName().GetCString()); - result.SetStatus(eReturnStatusFailed); } } else { // Bad args result.AppendError( "\"platform disconnect\" doesn't take any arguments"); - result.SetStatus(eReturnStatusFailed); } } else { result.AppendError("no platform is currently selected"); - result.SetStatus(eReturnStatusFailed); } return result.Succeeded(); } @@ -392,7 +381,8 @@ public: "or for a platform by name.", "platform settings", 0), m_options(), - m_option_working_dir(LLDB_OPT_SET_1, false, "working-dir", 'w', 0, + m_option_working_dir(LLDB_OPT_SET_1, false, "working-dir", 'w', + CommandCompletions::eRemoteDiskDirectoryCompletion, eArgTypePath, "The working directory for the platform.") { m_options.Append(&m_option_working_dir, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1); @@ -410,7 +400,6 @@ protected: m_option_working_dir.GetOptionValue().GetCurrentValue()); } else { result.AppendError("no platform is currently selected"); - result.SetStatus(eReturnStatusFailed); } return result.Succeeded(); } @@ -455,11 +444,9 @@ public: result.SetStatus(eReturnStatusSuccessFinishResult); } else { result.AppendError(error.AsCString()); - result.SetStatus(eReturnStatusFailed); } } else { result.AppendError("no platform currently selected\n"); - result.SetStatus(eReturnStatusFailed); } return result.Succeeded(); } @@ -485,6 +472,15 @@ public: ~CommandObjectPlatformFOpen() override = default; + void + HandleArgumentCompletion(CompletionRequest &request, + OptionElementVector &opt_element_vector) override { + if (request.GetCursorIndex() == 0) + CommandCompletions::InvokeCommonCompletionCallbacks( + GetCommandInterpreter(), + CommandCompletions::eRemoteDiskFileCompletion, request, nullptr); + } + bool DoExecute(Args &args, CommandReturnObject &result) override { PlatformSP platform_sp( GetDebugger().GetPlatformList().GetSelectedPlatform()); @@ -510,11 +506,9 @@ public: result.SetStatus(eReturnStatusSuccessFinishResult); } else { result.AppendError(error.AsCString()); - result.SetStatus(eReturnStatusFailed); } } else { result.AppendError("no platform currently selected\n"); - result.SetStatus(eReturnStatusFailed); } return result.Succeeded(); } @@ -549,7 +543,6 @@ public: if (!llvm::to_integer(cmd_line, fd)) { result.AppendErrorWithFormatv("'{0}' is not a valid file descriptor.\n", cmd_line); - result.SetStatus(eReturnStatusFailed); return result.Succeeded(); } Status error; @@ -559,11 +552,9 @@ public: result.SetStatus(eReturnStatusSuccessFinishResult); } else { result.AppendError(error.AsCString()); - result.SetStatus(eReturnStatusFailed); } } else { result.AppendError("no platform currently selected\n"); - result.SetStatus(eReturnStatusFailed); } return result.Succeeded(); } @@ -594,7 +585,6 @@ public: if (!llvm::to_integer(cmd_line, fd)) { result.AppendErrorWithFormatv("'{0}' is not a valid file descriptor.\n", cmd_line); - result.SetStatus(eReturnStatusFailed); return result.Succeeded(); } std::string buffer(m_options.m_count, 0); @@ -606,7 +596,6 @@ public: result.SetStatus(eReturnStatusSuccessFinishResult); } else { result.AppendError("no platform currently selected\n"); - result.SetStatus(eReturnStatusFailed); } return result.Succeeded(); } @@ -687,7 +676,6 @@ public: if (!llvm::to_integer(cmd_line, fd)) { result.AppendErrorWithFormatv("'{0}' is not a valid file descriptor.", cmd_line); - result.SetStatus(eReturnStatusFailed); return result.Succeeded(); } uint32_t retcode = @@ -697,7 +685,6 @@ public: result.SetStatus(eReturnStatusSuccessFinishResult); } else { result.AppendError("no platform currently selected\n"); - result.SetStatus(eReturnStatusFailed); } return result.Succeeded(); } @@ -817,13 +804,24 @@ public: ~CommandObjectPlatformGetFile() override = default; + void + HandleArgumentCompletion(CompletionRequest &request, + OptionElementVector &opt_element_vector) override { + if (request.GetCursorIndex() == 0) + CommandCompletions::InvokeCommonCompletionCallbacks( + GetCommandInterpreter(), + CommandCompletions::eRemoteDiskFileCompletion, request, nullptr); + else if (request.GetCursorIndex() == 1) + CommandCompletions::InvokeCommonCompletionCallbacks( + GetCommandInterpreter(), CommandCompletions::eDiskFileCompletion, + request, nullptr); + } + bool DoExecute(Args &args, CommandReturnObject &result) override { // If the number of arguments is incorrect, issue an error message. if (args.GetArgumentCount() != 2) { - result.GetErrorStream().Printf("error: required arguments missing; " - "specify both the source and destination " - "file paths\n"); - result.SetStatus(eReturnStatusFailed); + result.AppendError("required arguments missing; specify both the " + "source and destination file paths"); return false; } @@ -842,11 +840,9 @@ public: } else { result.AppendMessageWithFormat("get-file failed: %s\n", error.AsCString()); - result.SetStatus(eReturnStatusFailed); } } else { result.AppendError("no platform currently selected\n"); - result.SetStatus(eReturnStatusFailed); } return result.Succeeded(); } @@ -882,13 +878,22 @@ public: ~CommandObjectPlatformGetSize() override = default; + void + HandleArgumentCompletion(CompletionRequest &request, + OptionElementVector &opt_element_vector) override { + if (request.GetCursorIndex() != 0) + return; + + CommandCompletions::InvokeCommonCompletionCallbacks( + GetCommandInterpreter(), CommandCompletions::eRemoteDiskFileCompletion, + request, nullptr); + } + bool DoExecute(Args &args, CommandReturnObject &result) override { // If the number of arguments is incorrect, issue an error message. if (args.GetArgumentCount() != 1) { - result.GetErrorStream().Printf("error: required argument missing; " - "specify the source file path as the only " - "argument\n"); - result.SetStatus(eReturnStatusFailed); + result.AppendError("required argument missing; specify the source file " + "path as the only argument"); return false; } @@ -906,11 +911,9 @@ public: result.AppendMessageWithFormat( "Error getting file size of %s (remote)\n", remote_file_path.c_str()); - result.SetStatus(eReturnStatusFailed); } } else { result.AppendError("no platform currently selected\n"); - result.SetStatus(eReturnStatusFailed); } return result.Succeeded(); } @@ -927,6 +930,19 @@ public: ~CommandObjectPlatformPutFile() override = default; + void + HandleArgumentCompletion(CompletionRequest &request, + OptionElementVector &opt_element_vector) override { + if (request.GetCursorIndex() == 0) + CommandCompletions::InvokeCommonCompletionCallbacks( + GetCommandInterpreter(), CommandCompletions::eDiskFileCompletion, + request, nullptr); + else if (request.GetCursorIndex() == 1) + CommandCompletions::InvokeCommonCompletionCallbacks( + GetCommandInterpreter(), + CommandCompletions::eRemoteDiskFileCompletion, request, nullptr); + } + bool DoExecute(Args &args, CommandReturnObject &result) override { const char *src = args.GetArgumentAtIndex(0); const char *dst = args.GetArgumentAtIndex(1); @@ -943,11 +959,9 @@ public: result.SetStatus(eReturnStatusSuccessFinishNoResult); } else { result.AppendError(error.AsCString()); - result.SetStatus(eReturnStatusFailed); } } else { result.AppendError("no platform currently selected\n"); - result.SetStatus(eReturnStatusFailed); } return result.Succeeded(); } @@ -961,11 +975,14 @@ public: "Launch a new process on a remote platform.", "platform process launch program", eCommandRequiresTarget | eCommandTryTargetAPILock), - m_options() {} + m_options(), m_all_options() { + m_all_options.Append(&m_options); + m_all_options.Finalize(); + } ~CommandObjectPlatformProcessLaunch() override = default; - Options *GetOptions() override { return &m_options; } + Options *GetOptions() override { return &m_all_options; } protected: bool DoExecute(Args &args, CommandReturnObject &result) override { @@ -1022,12 +1039,10 @@ protected: result.AppendError("process launch failed"); else result.AppendError(error.AsCString()); - result.SetStatus(eReturnStatusFailed); } else { result.AppendError("'platform process launch' uses the current target " "file and arguments, or the executable and its " "arguments can be specified in this command"); - result.SetStatus(eReturnStatusFailed); return false; } } else { @@ -1036,7 +1051,8 @@ protected: return result.Succeeded(); } - ProcessLaunchCommandOptions m_options; + CommandOptionsProcessLaunch m_options; + OptionGroupOptions m_all_options; }; // "platform process list" @@ -1088,7 +1104,6 @@ protected: } else { result.AppendErrorWithFormat( "no process found with pid = %" PRIu64 "\n", pid); - result.SetStatus(eReturnStatusFailed); } } else { ProcessInstanceInfoList proc_infos; @@ -1130,7 +1145,6 @@ protected: result.AppendErrorWithFormat( "no processes were found on the \"%s\" platform\n", platform_sp->GetPluginName().GetCString()); - result.SetStatus(eReturnStatusFailed); } else { result.AppendMessageWithFormat( "%u matching process%s found on \"%s\"", matches, @@ -1152,19 +1166,16 @@ protected: } } else { result.AppendError("invalid args: process list takes only options\n"); - result.SetStatus(eReturnStatusFailed); } } else { result.AppendError("no platform is selected\n"); - result.SetStatus(eReturnStatusFailed); } return result.Succeeded(); } class CommandOptions : public Options { public: - CommandOptions() - : Options(), match_info(), show_args(false), verbose(false) {} + CommandOptions() : Options(), match_info() {} ~CommandOptions() override = default; @@ -1299,8 +1310,8 @@ protected: // Instance variables to hold the values for command options. ProcessInstanceInfoMatch match_info; - bool show_args; - bool verbose; + bool show_args = false; + bool verbose = false; }; CommandOptions m_options; @@ -1331,6 +1342,14 @@ public: ~CommandObjectPlatformProcessInfo() override = default; + void + HandleArgumentCompletion(CompletionRequest &request, + OptionElementVector &opt_element_vector) override { + CommandCompletions::InvokeCommonCompletionCallbacks( + GetCommandInterpreter(), CommandCompletions::eProcessIDCompletion, + request, nullptr); + } + protected: bool DoExecute(Args &args, CommandReturnObject &result) override { Target *target = GetDebugger().GetSelectedTarget().get(); @@ -1354,7 +1373,6 @@ protected: if (entry.ref().getAsInteger(0, pid)) { result.AppendErrorWithFormat("invalid process ID argument '%s'", entry.ref().str().c_str()); - result.SetStatus(eReturnStatusFailed); break; } else { ProcessInstanceInfo proc_info; @@ -1375,16 +1393,13 @@ protected: result.AppendErrorWithFormat( "not connected to '%s'", platform_sp->GetPluginName().GetCString()); - result.SetStatus(eReturnStatusFailed); } } else { // No args result.AppendError("one or more process id(s) must be specified"); - result.SetStatus(eReturnStatusFailed); } } else { result.AppendError("no platform is currently selected"); - result.SetStatus(eReturnStatusFailed); } return result.Succeeded(); } @@ -1447,46 +1462,6 @@ public: return llvm::makeArrayRef(g_platform_process_attach_options); } - void HandleOptionArgumentCompletion( - CompletionRequest &request, OptionElementVector &opt_element_vector, - int opt_element_index, CommandInterpreter &interpreter) override { - int opt_arg_pos = opt_element_vector[opt_element_index].opt_arg_pos; - int opt_defs_index = opt_element_vector[opt_element_index].opt_defs_index; - - // We are only completing the name option for now... - - // Are we in the name? - if (GetDefinitions()[opt_defs_index].short_option != 'n') - return; - - // Look to see if there is a -P argument provided, and if so use that - // plugin, otherwise use the default plugin. - - const char *partial_name = nullptr; - partial_name = request.GetParsedLine().GetArgumentAtIndex(opt_arg_pos); - - PlatformSP platform_sp(interpreter.GetPlatform(true)); - if (!platform_sp) - return; - - ProcessInstanceInfoList process_infos; - ProcessInstanceInfoMatch match_info; - if (partial_name) { - match_info.GetProcessInfo().GetExecutableFile().SetFile( - partial_name, FileSpec::Style::native); - match_info.SetNameMatchType(NameMatch::StartsWith); - } - platform_sp->FindProcesses(match_info, process_infos); - const uint32_t num_matches = process_infos.size(); - if (num_matches == 0) - return; - - for (uint32_t i = 0; i < num_matches; ++i) { - request.AddCompletion(process_infos[i].GetNameAsStringRef()); - } - return; - } - // Options table: Required for subclasses of Options. static OptionDefinition g_option_table[]; @@ -1513,15 +1488,12 @@ public: m_options.attach_info, GetDebugger(), nullptr, err); if (err.Fail()) { result.AppendError(err.AsCString()); - result.SetStatus(eReturnStatusFailed); } else if (!remote_process_sp) { result.AppendError("could not attach: unknown reason"); - result.SetStatus(eReturnStatusFailed); } else result.SetStatus(eReturnStatusSuccessFinishResult); } else { result.AppendError("no platform is currently selected"); - result.SetStatus(eReturnStatusFailed); } return result.Succeeded(); } @@ -1596,6 +1568,16 @@ public: else m_timeout = std::chrono::seconds(timeout_sec); break; + case 's': { + if (option_arg.empty()) { + error.SetErrorStringWithFormat( + "missing shell interpreter path for option -i|--interpreter."); + return error; + } + + m_shell_interpreter = option_arg.str(); + break; + } default: llvm_unreachable("Unimplemented option"); } @@ -1606,10 +1588,12 @@ public: void OptionParsingStarting(ExecutionContext *execution_context) override { m_timeout.reset(); m_use_host_platform = false; + m_shell_interpreter.clear(); } Timeout m_timeout = std::chrono::seconds(10); bool m_use_host_platform; + std::string m_shell_interpreter; }; CommandObjectPlatformShell(CommandInterpreter &interpreter) @@ -1635,7 +1619,6 @@ public: const bool is_alias = !raw_command_line.contains("platform"); OptionsWithRaw args(raw_command_line); - const char *expr = args.GetRawPart().c_str(); if (args.HasArgs()) if (!ParseOptions(args.GetArgs(), result)) @@ -1647,6 +1630,8 @@ public: return false; } + llvm::StringRef cmd = args.GetRawPart(); + PlatformSP platform_sp( m_options.m_use_host_platform ? Platform::GetHostPlatform() @@ -1657,7 +1642,8 @@ public: std::string output; int status = -1; int signo = -1; - error = (platform_sp->RunShellCommand(expr, working_dir, &status, &signo, + error = (platform_sp->RunShellCommand(m_options.m_shell_interpreter, cmd, + working_dir, &status, &signo, &output, m_options.m_timeout)); if (!output.empty()) result.GetOutputStream().PutCString(output); @@ -1685,7 +1671,6 @@ public: if (error.Fail()) { result.AppendError(error.AsCString()); - result.SetStatus(eReturnStatusFailed); } else { result.SetStatus(eReturnStatusSuccessFinishResult); } @@ -1706,10 +1691,19 @@ public: ~CommandObjectPlatformInstall() override = default; + void + HandleArgumentCompletion(CompletionRequest &request, + OptionElementVector &opt_element_vector) override { + if (request.GetCursorIndex()) + return; + CommandCompletions::InvokeCommonCompletionCallbacks( + GetCommandInterpreter(), CommandCompletions::eDiskFileCompletion, + request, nullptr); + } + bool DoExecute(Args &args, CommandReturnObject &result) override { if (args.GetArgumentCount() != 2) { result.AppendError("platform target-install takes two arguments"); - result.SetStatus(eReturnStatusFailed); return false; } // TODO: move the bulk of this code over to the platform itself @@ -1718,14 +1712,12 @@ public: FileSpec dst(args.GetArgumentAtIndex(1)); if (!FileSystem::Instance().Exists(src)) { result.AppendError("source location does not exist or is not accessible"); - result.SetStatus(eReturnStatusFailed); return false; } PlatformSP platform_sp( GetDebugger().GetPlatformList().GetSelectedPlatform()); if (!platform_sp) { result.AppendError("no platform currently selected"); - result.SetStatus(eReturnStatusFailed); return false; } @@ -1734,7 +1726,6 @@ public: result.SetStatus(eReturnStatusSuccessFinishNoResult); } else { result.AppendErrorWithFormat("install failed: %s", error.AsCString()); - result.SetStatus(eReturnStatusFailed); } return result.Succeeded(); } diff --git a/gnu/llvm/lldb/source/Commands/CommandObjectPlugin.cpp b/gnu/llvm/lldb/source/Commands/CommandObjectPlugin.cpp index 98a212eef0f..881415a4947 100644 --- a/gnu/llvm/lldb/source/Commands/CommandObjectPlugin.cpp +++ b/gnu/llvm/lldb/source/Commands/CommandObjectPlugin.cpp @@ -50,7 +50,6 @@ protected: if (argc != 1) { result.AppendError("'plugin load' requires one argument"); - result.SetStatus(eReturnStatusFailed); return false; } @@ -63,7 +62,6 @@ protected: result.SetStatus(eReturnStatusSuccessFinishResult); else { result.AppendError(error.AsCString()); - result.SetStatus(eReturnStatusFailed); } return result.Succeeded(); diff --git a/gnu/llvm/lldb/source/Commands/CommandObjectProcess.cpp b/gnu/llvm/lldb/source/Commands/CommandObjectProcess.cpp index f86779d85b5..7aaba373150 100644 --- a/gnu/llvm/lldb/source/Commands/CommandObjectProcess.cpp +++ b/gnu/llvm/lldb/source/Commands/CommandObjectProcess.cpp @@ -7,6 +7,8 @@ //===----------------------------------------------------------------------===// #include "CommandObjectProcess.h" +#include "CommandObjectTrace.h" +#include "CommandOptionsProcessLaunch.h" #include "lldb/Breakpoint/Breakpoint.h" #include "lldb/Breakpoint/BreakpointLocation.h" #include "lldb/Breakpoint/BreakpointSite.h" @@ -16,6 +18,7 @@ #include "lldb/Interpreter/CommandInterpreter.h" #include "lldb/Interpreter/CommandReturnObject.h" #include "lldb/Interpreter/OptionArgParser.h" +#include "lldb/Interpreter/OptionGroupPythonClassWithDict.h" #include "lldb/Interpreter/Options.h" #include "lldb/Target/Platform.h" #include "lldb/Target/Process.h" @@ -26,6 +29,8 @@ #include "lldb/Utility/Args.h" #include "lldb/Utility/State.h" +#include + using namespace lldb; using namespace lldb_private; @@ -48,19 +53,19 @@ protected: state = process->GetState(); if (process->IsAlive() && state != eStateConnected) { - char message[1024]; + std::string message; if (process->GetState() == eStateAttaching) - ::snprintf(message, sizeof(message), - "There is a pending attach, abort it and %s?", - m_new_process_action.c_str()); + message = + llvm::formatv("There is a pending attach, abort it and {0}?", + m_new_process_action); else if (process->GetShouldDetach()) - ::snprintf(message, sizeof(message), - "There is a running process, detach from it and %s?", - m_new_process_action.c_str()); + message = llvm::formatv( + "There is a running process, detach from it and {0}?", + m_new_process_action); else - ::snprintf(message, sizeof(message), - "There is a running process, kill it and %s?", - m_new_process_action.c_str()); + message = + llvm::formatv("There is a running process, kill it and {0}?", + m_new_process_action); if (!m_interpreter.Confirm(message, true)) { result.SetStatus(eReturnStatusFailed); @@ -76,7 +81,6 @@ protected: result.AppendErrorWithFormat( "Failed to detach from process: %s\n", detach_error.AsCString()); - result.SetStatus(eReturnStatusFailed); } } else { Status destroy_error(process->Destroy(false)); @@ -86,7 +90,6 @@ protected: } else { result.AppendErrorWithFormat("Failed to kill process: %s\n", destroy_error.AsCString()); - result.SetStatus(eReturnStatusFailed); } } } @@ -107,7 +110,14 @@ public: interpreter, "process launch", "Launch the executable in the debugger.", nullptr, eCommandRequiresTarget, "restart"), - m_options() { + m_options(), + m_class_options("scripted process", true, 'C', 'k', 'v', 0), + m_all_options() { + m_all_options.Append(&m_options); + m_all_options.Append(&m_class_options, LLDB_OPT_SET_1 | LLDB_OPT_SET_2, + LLDB_OPT_SET_ALL); + m_all_options.Finalize(); + CommandArgumentEntry arg; CommandArgumentData run_args_arg; @@ -134,7 +144,7 @@ public: request, nullptr); } - Options *GetOptions() override { return &m_options; } + Options *GetOptions() override { return &m_all_options; } const char *GetRepeatCommand(Args ¤t_command_args, uint32_t index) override { @@ -152,7 +162,6 @@ protected: if (exe_module_sp == nullptr) { result.AppendError("no file in target, create a debug target using the " "'target create' command"); - result.SetStatus(eReturnStatusFailed); return false; } @@ -179,11 +188,23 @@ protected: disable_aslr = target->GetDisableASLR(); } + if (!m_class_options.GetName().empty()) { + m_options.launch_info.SetProcessPluginName("ScriptedProcess"); + m_options.launch_info.SetScriptedProcessClassName( + m_class_options.GetName()); + m_options.launch_info.SetScriptedProcessDictionarySP( + m_class_options.GetStructuredData()); + target->SetProcessLaunchInfo(m_options.launch_info); + } + if (disable_aslr) m_options.launch_info.GetFlags().Set(eLaunchFlagDisableASLR); else m_options.launch_info.GetFlags().Clear(eLaunchFlagDisableASLR); + if (target->GetInheritTCC()) + m_options.launch_info.GetFlags().Set(eLaunchFlagInheritTCCFromParent); + if (target->GetDetachOnError()) m_options.launch_info.GetFlags().Set(eLaunchFlagDetachOnError); @@ -239,16 +260,16 @@ protected: } else { result.AppendError( "no error returned from Target::Launch, and target has no process"); - result.SetStatus(eReturnStatusFailed); } } else { result.AppendError(error.AsCString()); - result.SetStatus(eReturnStatusFailed); } return result.Succeeded(); } - ProcessLaunchCommandOptions m_options; + CommandOptionsProcessLaunch m_options; + OptionGroupPythonClassWithDict m_class_options; + OptionGroupOptions m_all_options; }; #define LLDB_OPTIONS_process_attach @@ -317,49 +338,6 @@ public: return llvm::makeArrayRef(g_process_attach_options); } - void HandleOptionArgumentCompletion( - CompletionRequest &request, OptionElementVector &opt_element_vector, - int opt_element_index, CommandInterpreter &interpreter) override { - int opt_arg_pos = opt_element_vector[opt_element_index].opt_arg_pos; - int opt_defs_index = opt_element_vector[opt_element_index].opt_defs_index; - - switch (GetDefinitions()[opt_defs_index].short_option) { - case 'n': { - // Look to see if there is a -P argument provided, and if so use that - // plugin, otherwise use the default plugin. - - const char *partial_name = nullptr; - partial_name = request.GetParsedLine().GetArgumentAtIndex(opt_arg_pos); - - PlatformSP platform_sp(interpreter.GetPlatform(true)); - if (!platform_sp) - return; - ProcessInstanceInfoList process_infos; - ProcessInstanceInfoMatch match_info; - if (partial_name) { - match_info.GetProcessInfo().GetExecutableFile().SetFile( - partial_name, FileSpec::Style::native); - match_info.SetNameMatchType(NameMatch::StartsWith); - } - platform_sp->FindProcesses(match_info, process_infos); - const size_t num_matches = process_infos.size(); - if (num_matches == 0) - return; - for (size_t i = 0; i < num_matches; ++i) { - request.AddCompletion(process_infos[i].GetNameAsStringRef()); - } - } break; - - case 'P': - CommandCompletions::InvokeCommonCompletionCallbacks( - interpreter, CommandCompletions::eProcessPluginCompletion, request, - nullptr); - break; - } - } - - // Instance variables to hold the values for command options. - ProcessAttachInfo attach_info; }; @@ -404,7 +382,6 @@ protected: result.AppendError(error.AsCString("Error creating target")); return false; } - GetDebugger().GetTargetList().SetSelectedTarget(target); } // Record the old executable module, we want to issue a warning if the @@ -417,11 +394,9 @@ protected: if (command.GetArgumentCount()) { result.AppendErrorWithFormat("Invalid arguments for '%s'.\nUsage: %s\n", m_cmd_name.c_str(), m_cmd_syntax.c_str()); - result.SetStatus(eReturnStatusFailed); return false; } - m_interpreter.UpdateExecutionContext(nullptr); StreamString stream; const auto error = target->Attach(m_options.attach_info, &stream); if (error.Success()) { @@ -433,11 +408,9 @@ protected: } else { result.AppendError( "no error returned from Target::Attach, and target has no process"); - result.SetStatus(eReturnStatusFailed); } } else { result.AppendErrorWithFormat("attach failed: %s\n", error.AsCString()); - result.SetStatus(eReturnStatusFailed); } if (!result.Succeeded()) @@ -557,7 +530,6 @@ protected: result.AppendErrorWithFormat( "The '%s' command does not take any arguments.\n", m_cmd_name.c_str()); - result.SetStatus(eReturnStatusFailed); return false; } @@ -629,13 +601,11 @@ protected: } else { result.AppendErrorWithFormat("Failed to resume process: %s.\n", error.AsCString()); - result.SetStatus(eReturnStatusFailed); } } else { result.AppendErrorWithFormat( "Process cannot be continued from its current state (%s).\n", StateAsCString(state)); - result.SetStatus(eReturnStatusFailed); } return result.Succeeded(); } @@ -727,7 +697,6 @@ protected: result.SetStatus(eReturnStatusSuccessFinishResult); } else { result.AppendErrorWithFormat("Detach failed: %s\n", error.AsCString()); - result.SetStatus(eReturnStatusFailed); return false; } return result.Succeeded(); @@ -799,7 +768,6 @@ protected: result.AppendErrorWithFormat( "'%s' takes exactly one argument:\nUsage: %s\n", m_cmd_name.c_str(), m_cmd_syntax.c_str()); - result.SetStatus(eReturnStatusFailed); return false; } @@ -809,7 +777,6 @@ protected: "Process %" PRIu64 " is currently being debugged, kill the process before connecting.\n", process->GetID()); - result.SetStatus(eReturnStatusFailed); return false; } @@ -831,7 +798,6 @@ protected: error); if (error.Fail() || process_sp == nullptr) { result.AppendError(error.AsCString("Error connecting to the process")); - result.SetStatus(eReturnStatusFailed); return false; } return true; @@ -920,6 +886,17 @@ public: ~CommandObjectProcessLoad() override = default; + void + HandleArgumentCompletion(CompletionRequest &request, + OptionElementVector &opt_element_vector) override { + if (!m_exe_ctx.HasProcessScope()) + return; + + CommandCompletions::InvokeCommonCompletionCallbacks( + GetCommandInterpreter(), CommandCompletions::eDiskFileCompletion, + request, nullptr); + } + Options *GetOptions() override { return &m_options; } protected: @@ -960,7 +937,6 @@ protected: result.AppendErrorWithFormat("failed to load '%s': %s", image_path.str().c_str(), error.AsCString()); - result.SetStatus(eReturnStatusFailed); } } return result.Succeeded(); @@ -985,6 +961,24 @@ public: ~CommandObjectProcessUnload() override = default; + void + HandleArgumentCompletion(CompletionRequest &request, + OptionElementVector &opt_element_vector) override { + + if (request.GetCursorIndex() || !m_exe_ctx.HasProcessScope()) + return; + + Process *process = m_exe_ctx.GetProcessPtr(); + + const std::vector &tokens = process->GetImageTokens(); + const size_t token_num = tokens.size(); + for (size_t i = 0; i < token_num; ++i) { + if (tokens[i] == LLDB_INVALID_IMAGE_TOKEN) + continue; + request.TryCompleteCurrentArg(std::to_string(i)); + } + } + protected: bool DoExecute(Args &command, CommandReturnObject &result) override { Process *process = m_exe_ctx.GetProcessPtr(); @@ -994,7 +988,6 @@ protected: if (entry.ref().getAsInteger(0, image_token)) { result.AppendErrorWithFormat("invalid image index argument '%s'", entry.ref().str().c_str()); - result.SetStatus(eReturnStatusFailed); break; } else { Status error(process->GetTarget().GetPlatform()->UnloadImage( @@ -1006,7 +999,6 @@ protected: } else { result.AppendErrorWithFormat("failed to unload image: %s", error.AsCString()); - result.SetStatus(eReturnStatusFailed); break; } } @@ -1051,7 +1043,7 @@ public: UnixSignalsSP signals = m_exe_ctx.GetProcessPtr()->GetUnixSignals(); int signo = signals->GetFirstSignalNumber(); while (signo != LLDB_INVALID_SIGNAL_NUMBER) { - request.AddCompletion(signals->GetSignalAsCString(signo), ""); + request.TryCompleteCurrentArg(signals->GetSignalAsCString(signo)); signo = signals->GetNextSignalNumber(signo); } } @@ -1073,7 +1065,6 @@ protected: if (signo == LLDB_INVALID_SIGNAL_NUMBER) { result.AppendErrorWithFormat("Invalid signal argument '%s'.\n", command.GetArgumentAtIndex(0)); - result.SetStatus(eReturnStatusFailed); } else { Status error(process->Signal(signo)); if (error.Success()) { @@ -1081,14 +1072,12 @@ protected: } else { result.AppendErrorWithFormat("Failed to send signal %i: %s\n", signo, error.AsCString()); - result.SetStatus(eReturnStatusFailed); } } } else { result.AppendErrorWithFormat( "'%s' takes exactly one signal number argument:\nUsage: %s\n", m_cmd_name.c_str(), m_cmd_syntax.c_str()); - result.SetStatus(eReturnStatusFailed); } return result.Succeeded(); } @@ -1113,7 +1102,6 @@ protected: Process *process = m_exe_ctx.GetProcessPtr(); if (process == nullptr) { result.AppendError("no process to halt"); - result.SetStatus(eReturnStatusFailed); return false; } @@ -1125,12 +1113,10 @@ protected: } else { result.AppendErrorWithFormat("Failed to halt process: %s\n", error.AsCString()); - result.SetStatus(eReturnStatusFailed); } } else { result.AppendErrorWithFormat("'%s' takes no arguments:\nUsage: %s\n", m_cmd_name.c_str(), m_cmd_syntax.c_str()); - result.SetStatus(eReturnStatusFailed); } return result.Succeeded(); } @@ -1155,7 +1141,6 @@ protected: Process *process = m_exe_ctx.GetProcessPtr(); if (process == nullptr) { result.AppendError("no process to kill"); - result.SetStatus(eReturnStatusFailed); return false; } @@ -1166,12 +1151,10 @@ protected: } else { result.AppendErrorWithFormat("Failed to kill process: %s\n", error.AsCString()); - result.SetStatus(eReturnStatusFailed); } } else { result.AppendErrorWithFormat("'%s' takes no arguments:\nUsage: %s\n", m_cmd_name.c_str(), m_cmd_syntax.c_str()); - result.SetStatus(eReturnStatusFailed); } return result.Succeeded(); } @@ -1180,45 +1163,109 @@ protected: // CommandObjectProcessSaveCore #pragma mark CommandObjectProcessSaveCore +static constexpr OptionEnumValueElement g_corefile_save_style[] = { + {eSaveCoreFull, "full", "Create a core file with all memory saved"}, + {eSaveCoreDirtyOnly, "modified-memory", + "Create a corefile with only modified memory saved"}}; + +static constexpr OptionEnumValues SaveCoreStyles() { + return OptionEnumValues(g_corefile_save_style); +} + +#define LLDB_OPTIONS_process_save_core +#include "CommandOptions.inc" + class CommandObjectProcessSaveCore : public CommandObjectParsed { public: CommandObjectProcessSaveCore(CommandInterpreter &interpreter) : CommandObjectParsed(interpreter, "process save-core", "Save the current process as a core file using an " "appropriate file type.", - "process save-core FILE", + "process save-core [-s corefile-style] FILE", eCommandRequiresProcess | eCommandTryTargetAPILock | eCommandProcessMustBeLaunched) {} ~CommandObjectProcessSaveCore() override = default; + Options *GetOptions() override { return &m_options; } + + class CommandOptions : public Options { + public: + CommandOptions() + : Options(), m_requested_save_core_style(eSaveCoreUnspecified) {} + + ~CommandOptions() override = default; + + llvm::ArrayRef GetDefinitions() override { + return llvm::makeArrayRef(g_process_save_core_options); + } + + Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, + ExecutionContext *execution_context) override { + const int short_option = m_getopt_table[option_idx].val; + Status error; + + switch (short_option) { + case 's': + m_requested_save_core_style = + (lldb::SaveCoreStyle)OptionArgParser::ToOptionEnum( + option_arg, GetDefinitions()[option_idx].enum_values, + eSaveCoreUnspecified, error); + break; + default: + llvm_unreachable("Unimplemented option"); + } + + return {}; + } + + void OptionParsingStarting(ExecutionContext *execution_context) override { + m_requested_save_core_style = eSaveCoreUnspecified; + } + + // Instance variables to hold the values for command options. + SaveCoreStyle m_requested_save_core_style; + }; + protected: bool DoExecute(Args &command, CommandReturnObject &result) override { ProcessSP process_sp = m_exe_ctx.GetProcessSP(); if (process_sp) { if (command.GetArgumentCount() == 1) { FileSpec output_file(command.GetArgumentAtIndex(0)); - Status error = PluginManager::SaveCore(process_sp, output_file); + SaveCoreStyle corefile_style = m_options.m_requested_save_core_style; + Status error = + PluginManager::SaveCore(process_sp, output_file, corefile_style); if (error.Success()) { + if (corefile_style == SaveCoreStyle::eSaveCoreDirtyOnly) { + result.AppendMessageWithFormat( + "\nModified-memory only corefile " + "created. This corefile may not show \n" + "library/framework/app binaries " + "on a different system, or when \n" + "those binaries have " + "been updated/modified. Copies are not included\n" + "in this corefile. Use --style full to include all " + "process memory.\n"); + } result.SetStatus(eReturnStatusSuccessFinishResult); } else { result.AppendErrorWithFormat( "Failed to save core file for process: %s\n", error.AsCString()); - result.SetStatus(eReturnStatusFailed); } } else { result.AppendErrorWithFormat("'%s' takes one arguments:\nUsage: %s\n", m_cmd_name.c_str(), m_cmd_syntax.c_str()); - result.SetStatus(eReturnStatusFailed); } } else { result.AppendError("invalid process"); - result.SetStatus(eReturnStatusFailed); return false; } return result.Succeeded(); } + + CommandOptions m_options; }; // CommandObjectProcessStatus @@ -1242,7 +1289,7 @@ public: class CommandOptions : public Options { public: - CommandOptions() : Options(), m_verbose(false) {} + CommandOptions() : Options() {} ~CommandOptions() override = default; @@ -1270,7 +1317,7 @@ public: } // Instance variables to hold the values for command options. - bool m_verbose; + bool m_verbose = false; }; protected: @@ -1280,7 +1327,6 @@ protected: if (command.GetArgumentCount()) { result.AppendError("'process status' takes no arguments"); - result.SetStatus(eReturnStatusFailed); return result.Succeeded(); } @@ -1297,10 +1343,21 @@ protected: num_frames, num_frames_with_source, stop_format); if (m_options.m_verbose) { + addr_t code_mask = process->GetCodeAddressMask(); + addr_t data_mask = process->GetDataAddressMask(); + if (code_mask != 0) { + int bits = std::bitset<64>(~code_mask).count(); + result.AppendMessageWithFormat( + "Addressable code address mask: 0x%" PRIx64 "\n", code_mask); + result.AppendMessageWithFormat( + "Addressable data address mask: 0x%" PRIx64 "\n", data_mask); + result.AppendMessageWithFormat( + "Number of bits used in addressing (code): %d\n", bits); + } + PlatformSP platform_sp = process->GetTarget().GetPlatform(); if (!platform_sp) { result.AppendError("Couldn'retrieve the target's platform"); - result.SetStatus(eReturnStatusFailed); return result.Succeeded(); } @@ -1309,7 +1366,6 @@ protected: if (!expected_crash_info) { result.AppendError(llvm::toString(expected_crash_info.takeError())); - result.SetStatus(eReturnStatusFailed); return result.Succeeded(); } @@ -1478,7 +1534,6 @@ protected: if (!process_sp) { result.AppendError("No current process; cannot handle signals until you " "have a valid process.\n"); - result.SetStatus(eReturnStatusFailed); return false; } @@ -1490,7 +1545,6 @@ protected: !VerifyCommandOptionValue(m_options.stop, stop_action)) { result.AppendError("Invalid argument for command option --stop; must be " "true or false.\n"); - result.SetStatus(eReturnStatusFailed); return false; } @@ -1498,7 +1552,6 @@ protected: !VerifyCommandOptionValue(m_options.notify, notify_action)) { result.AppendError("Invalid argument for command option --notify; must " "be true or false.\n"); - result.SetStatus(eReturnStatusFailed); return false; } @@ -1506,7 +1559,6 @@ protected: !VerifyCommandOptionValue(m_options.pass, pass_action)) { result.AppendError("Invalid argument for command option --pass; must be " "true or false.\n"); - result.SetStatus(eReturnStatusFailed); return false; } @@ -1570,6 +1622,71 @@ protected: CommandOptions m_options; }; +// Next are the subcommands of CommandObjectMultiwordProcessTrace + +// CommandObjectProcessTraceStart +class CommandObjectProcessTraceStart : public CommandObjectTraceProxy { +public: + CommandObjectProcessTraceStart(CommandInterpreter &interpreter) + : CommandObjectTraceProxy( + /*live_debug_session_only*/ true, interpreter, + "process trace start", + "Start tracing this process with the corresponding trace " + "plug-in.", + "process trace start []") {} + +protected: + lldb::CommandObjectSP GetDelegateCommand(Trace &trace) override { + return trace.GetProcessTraceStartCommand(m_interpreter); + } +}; + +// CommandObjectProcessTraceStop +class CommandObjectProcessTraceStop : public CommandObjectParsed { +public: + CommandObjectProcessTraceStop(CommandInterpreter &interpreter) + : CommandObjectParsed(interpreter, "process trace stop", + "Stop tracing this process. This does not affect " + "traces started with the " + "\"thread trace start\" command.", + "process trace stop", + eCommandRequiresProcess | eCommandTryTargetAPILock | + eCommandProcessMustBeLaunched | + eCommandProcessMustBePaused | + eCommandProcessMustBeTraced) {} + + ~CommandObjectProcessTraceStop() override = default; + + bool DoExecute(Args &command, CommandReturnObject &result) override { + ProcessSP process_sp = m_exe_ctx.GetProcessSP(); + + TraceSP trace_sp = process_sp->GetTarget().GetTrace(); + + if (llvm::Error err = trace_sp->Stop()) + result.AppendError(toString(std::move(err))); + else + result.SetStatus(eReturnStatusSuccessFinishResult); + + return result.Succeeded(); + } +}; + +// CommandObjectMultiwordProcessTrace +class CommandObjectMultiwordProcessTrace : public CommandObjectMultiword { +public: + CommandObjectMultiwordProcessTrace(CommandInterpreter &interpreter) + : CommandObjectMultiword( + interpreter, "trace", "Commands for tracing the current process.", + "process trace []") { + LoadSubCommand("start", CommandObjectSP(new CommandObjectProcessTraceStart( + interpreter))); + LoadSubCommand("stop", CommandObjectSP( + new CommandObjectProcessTraceStop(interpreter))); + } + + ~CommandObjectMultiwordProcessTrace() override = default; +}; + // CommandObjectMultiwordProcess CommandObjectMultiwordProcess::CommandObjectMultiwordProcess( @@ -1606,6 +1723,9 @@ CommandObjectMultiwordProcess::CommandObjectMultiwordProcess( CommandObjectSP(new CommandObjectProcessPlugin(interpreter))); LoadSubCommand("save-core", CommandObjectSP(new CommandObjectProcessSaveCore( interpreter))); + LoadSubCommand( + "trace", + CommandObjectSP(new CommandObjectMultiwordProcessTrace(interpreter))); } CommandObjectMultiwordProcess::~CommandObjectMultiwordProcess() = default; diff --git a/gnu/llvm/lldb/source/Commands/CommandObjectQuit.cpp b/gnu/llvm/lldb/source/Commands/CommandObjectQuit.cpp index d0c7bbd3abf..c6e2e21de6b 100644 --- a/gnu/llvm/lldb/source/Commands/CommandObjectQuit.cpp +++ b/gnu/llvm/lldb/source/Commands/CommandObjectQuit.cpp @@ -22,7 +22,7 @@ CommandObjectQuit::CommandObjectQuit(CommandInterpreter &interpreter) : CommandObjectParsed(interpreter, "quit", "Quit the LLDB debugger.", "quit [exit-code]") {} -CommandObjectQuit::~CommandObjectQuit() {} +CommandObjectQuit::~CommandObjectQuit() = default; // returns true if there is at least one alive process is_a_detach will be true // if all alive processes will be detached when you quit and false if at least @@ -75,7 +75,6 @@ bool CommandObjectQuit::DoExecute(Args &command, CommandReturnObject &result) { if (command.GetArgumentCount() > 1) { result.AppendError("Too many arguments for 'quit'. Only an optional exit " "code is allowed"); - result.SetStatus(eReturnStatusFailed); return false; } @@ -88,13 +87,11 @@ bool CommandObjectQuit::DoExecute(Args &command, CommandReturnObject &result) { std::string arg_str = arg.str(); s.Printf("Couldn't parse '%s' as integer for exit code.", arg_str.data()); result.AppendError(s.GetString()); - result.SetStatus(eReturnStatusFailed); return false; } if (!m_interpreter.SetQuitExitCode(exit_code)) { result.AppendError("The current driver doesn't allow custom exit codes" " for the quit command."); - result.SetStatus(eReturnStatusFailed); return false; } } @@ -103,5 +100,6 @@ bool CommandObjectQuit::DoExecute(Args &command, CommandReturnObject &result) { CommandInterpreter::eBroadcastBitQuitCommandReceived; m_interpreter.BroadcastEvent(event_type); result.SetStatus(eReturnStatusQuit); + return true; } diff --git a/gnu/llvm/lldb/source/Commands/CommandObjectRegexCommand.cpp b/gnu/llvm/lldb/source/Commands/CommandObjectRegexCommand.cpp new file mode 100644 index 00000000000..46295421834 --- /dev/null +++ b/gnu/llvm/lldb/source/Commands/CommandObjectRegexCommand.cpp @@ -0,0 +1,90 @@ +//===-- CommandObjectRegexCommand.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 "CommandObjectRegexCommand.h" +#include "lldb/Interpreter/CommandInterpreter.h" +#include "lldb/Interpreter/CommandReturnObject.h" + +using namespace lldb; +using namespace lldb_private; + +// CommandObjectRegexCommand constructor +CommandObjectRegexCommand::CommandObjectRegexCommand( + CommandInterpreter &interpreter, llvm::StringRef name, llvm::StringRef help, + llvm::StringRef syntax, uint32_t max_matches, uint32_t completion_type_mask, + bool is_removable) + : CommandObjectRaw(interpreter, name, help, syntax), + m_max_matches(max_matches), m_completion_type_mask(completion_type_mask), + m_entries(), m_is_removable(is_removable) {} + +// Destructor +CommandObjectRegexCommand::~CommandObjectRegexCommand() = default; + +bool CommandObjectRegexCommand::DoExecute(llvm::StringRef command, + CommandReturnObject &result) { + EntryCollection::const_iterator pos, end = m_entries.end(); + for (pos = m_entries.begin(); pos != end; ++pos) { + llvm::SmallVector matches; + if (pos->regex.Execute(command, &matches)) { + std::string new_command(pos->command); + char percent_var[8]; + size_t idx, percent_var_idx; + for (uint32_t match_idx = 1; match_idx <= m_max_matches; ++match_idx) { + if (match_idx < matches.size()) { + const std::string match_str = matches[match_idx].str(); + const int percent_var_len = + ::snprintf(percent_var, sizeof(percent_var), "%%%u", match_idx); + for (idx = 0; (percent_var_idx = new_command.find( + percent_var, idx)) != std::string::npos;) { + new_command.erase(percent_var_idx, percent_var_len); + new_command.insert(percent_var_idx, match_str); + idx = percent_var_idx + match_str.size(); + } + } + } + // Interpret the new command and return this as the result! + if (m_interpreter.GetExpandRegexAliases()) + result.GetOutputStream().Printf("%s\n", new_command.c_str()); + // Pass in true for "no context switching". The command that called us + // should have set up the context appropriately, we shouldn't have to + // redo that. + return m_interpreter.HandleCommand(new_command.c_str(), + eLazyBoolCalculate, result); + } + } + result.SetStatus(eReturnStatusFailed); + if (!GetSyntax().empty()) + result.AppendError(GetSyntax()); + else + result.GetOutputStream() << "Command contents '" << command + << "' failed to match any " + "regular expression in the '" + << m_cmd_name << "' regex "; + return false; +} + +bool CommandObjectRegexCommand::AddRegexCommand(llvm::StringRef re_cstr, + llvm::StringRef command_cstr) { + m_entries.resize(m_entries.size() + 1); + // Only add the regular expression if it compiles + m_entries.back().regex = RegularExpression(re_cstr); + if (m_entries.back().regex.IsValid()) { + m_entries.back().command = command_cstr.str(); + return true; + } + // The regex didn't compile... + m_entries.pop_back(); + return false; +} + +void CommandObjectRegexCommand::HandleCompletion(CompletionRequest &request) { + if (m_completion_type_mask) { + CommandCompletions::InvokeCommonCompletionCallbacks( + GetCommandInterpreter(), m_completion_type_mask, request, nullptr); + } +} diff --git a/gnu/llvm/lldb/source/Commands/CommandObjectRegexCommand.h b/gnu/llvm/lldb/source/Commands/CommandObjectRegexCommand.h new file mode 100644 index 00000000000..2f65c2cd815 --- /dev/null +++ b/gnu/llvm/lldb/source/Commands/CommandObjectRegexCommand.h @@ -0,0 +1,61 @@ +//===-- CommandObjectRegexCommand.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_INTERPRETER_COMMANDOBJECTREGEXCOMMAND_H +#define LLDB_INTERPRETER_COMMANDOBJECTREGEXCOMMAND_H + +#include + +#include "lldb/Interpreter/CommandObject.h" +#include "lldb/Utility/CompletionRequest.h" +#include "lldb/Utility/RegularExpression.h" + +namespace lldb_private { + +// CommandObjectRegexCommand + +class CommandObjectRegexCommand : public CommandObjectRaw { +public: + CommandObjectRegexCommand(CommandInterpreter &interpreter, + llvm::StringRef name, llvm::StringRef help, + llvm::StringRef syntax, uint32_t max_matches, + uint32_t completion_type_mask, bool is_removable); + + ~CommandObjectRegexCommand() override; + + bool IsRemovable() const override { return m_is_removable; } + + bool AddRegexCommand(llvm::StringRef re_cstr, llvm::StringRef command_cstr); + + bool HasRegexEntries() const { return !m_entries.empty(); } + + void HandleCompletion(CompletionRequest &request) override; + +protected: + bool DoExecute(llvm::StringRef command, CommandReturnObject &result) override; + + struct Entry { + RegularExpression regex; + std::string command; + }; + + typedef std::list EntryCollection; + const uint32_t m_max_matches; + const uint32_t m_completion_type_mask; + EntryCollection m_entries; + bool m_is_removable; + +private: + CommandObjectRegexCommand(const CommandObjectRegexCommand &) = delete; + const CommandObjectRegexCommand & + operator=(const CommandObjectRegexCommand &) = delete; +}; + +} // namespace lldb_private + +#endif // LLDB_INTERPRETER_COMMANDOBJECTREGEXCOMMAND_H diff --git a/gnu/llvm/lldb/source/Commands/CommandObjectRegister.cpp b/gnu/llvm/lldb/source/Commands/CommandObjectRegister.cpp index 56e8c3fb4b8..6fd71c90c32 100644 --- a/gnu/llvm/lldb/source/Commands/CommandObjectRegister.cpp +++ b/gnu/llvm/lldb/source/Commands/CommandObjectRegister.cpp @@ -178,13 +178,11 @@ protected: llvm::sys::StrError()); else result.AppendError("unknown error while reading registers.\n"); - result.SetStatus(eReturnStatusFailed); break; } } else { result.AppendErrorWithFormat( "invalid register set index: %" PRIu64 "\n", (uint64_t)set_idx); - result.SetStatus(eReturnStatusFailed); break; } } @@ -203,11 +201,9 @@ protected: if (m_command_options.dump_all_sets) { result.AppendError("the --all option can't be used when registers " "names are supplied as arguments\n"); - result.SetStatus(eReturnStatusFailed); } else if (m_command_options.set_indexes.GetSize() > 0) { result.AppendError("the --set option can't be used when " "registers names are supplied as arguments\n"); - result.SetStatus(eReturnStatusFailed); } else { for (auto &entry : command) { // in most LLDB commands we accept $rbx as the name for register RBX @@ -353,7 +349,6 @@ protected: if (command.GetArgumentCount() != 2) { result.AppendError( "register write takes exactly 2 arguments: "); - result.SetStatus(eReturnStatusFailed); } else { auto reg_name = command[0].ref(); auto value_str = command[1].ref(); @@ -390,11 +385,9 @@ protected: "Failed to write register '%s' with value '%s'", reg_name.str().c_str(), value_str.str().c_str()); } - result.SetStatus(eReturnStatusFailed); } else { result.AppendErrorWithFormat("Register not found for '%s'.\n", reg_name.str().c_str()); - result.SetStatus(eReturnStatusFailed); } } return result.Succeeded(); diff --git a/gnu/llvm/lldb/source/Commands/CommandObjectReproducer.cpp b/gnu/llvm/lldb/source/Commands/CommandObjectReproducer.cpp index 104130b70b2..01f9dc64e6f 100644 --- a/gnu/llvm/lldb/source/Commands/CommandObjectReproducer.cpp +++ b/gnu/llvm/lldb/source/Commands/CommandObjectReproducer.cpp @@ -27,10 +27,12 @@ using namespace lldb_private::repro; enum ReproducerProvider { eReproducerProviderCommands, eReproducerProviderFiles, + eReproducerProviderSymbolFiles, eReproducerProviderGDB, eReproducerProviderProcessInfo, eReproducerProviderVersion, eReproducerProviderWorkingDirectory, + eReproducerProviderHomeDirectory, eReproducerProviderNone }; @@ -45,6 +47,11 @@ static constexpr OptionEnumValueElement g_reproducer_provider_type[] = { "files", "Files", }, + { + eReproducerProviderSymbolFiles, + "symbol-files", + "Symbol Files", + }, { eReproducerProviderGDB, "gdb", @@ -65,6 +72,11 @@ static constexpr OptionEnumValueElement g_reproducer_provider_type[] = { "cwd", "Working Directory", }, + { + eReproducerProviderHomeDirectory, + "home", + "Home Directory", + }, { eReproducerProviderNone, "none", @@ -104,6 +116,9 @@ static constexpr OptionEnumValues ReproducerSignalType() { #define LLDB_OPTIONS_reproducer_xcrash #include "CommandOptions.inc" +#define LLDB_OPTIONS_reproducer_verify +#include "CommandOptions.inc" + template llvm::Expected static ReadFromYAML(StringRef filename) { auto error_or_file = MemoryBuffer::getFile(filename); @@ -122,6 +137,37 @@ llvm::Expected static ReadFromYAML(StringRef filename) { return t; } +static void SetError(CommandReturnObject &result, Error err) { + result.AppendError(toString(std::move(err))); +} + +/// Create a loader from the given path if specified. Otherwise use the current +/// loader used for replay. +static Loader * +GetLoaderFromPathOrCurrent(llvm::Optional &loader_storage, + CommandReturnObject &result, + FileSpec reproducer_path) { + if (reproducer_path) { + loader_storage.emplace(reproducer_path); + Loader *loader = &(*loader_storage); + if (Error err = loader->LoadIndex()) { + // This is a hard error and will set the result to eReturnStatusFailed. + SetError(result, std::move(err)); + return nullptr; + } + return loader; + } + + if (Loader *loader = Reproducer::Instance().GetLoader()) + return loader; + + // This is a soft error because this is expected to fail during capture. + result.AppendError( + "Not specifying a reproducer is only support during replay."); + result.SetStatus(eReturnStatusSuccessFinishNoResult); + return nullptr; +} + class CommandObjectReproducerGenerate : public CommandObjectParsed { public: CommandObjectReproducerGenerate(CommandInterpreter &interpreter) @@ -145,13 +191,16 @@ protected: auto &r = Reproducer::Instance(); if (auto generator = r.GetGenerator()) { generator->Keep(); + if (llvm::Error e = repro::Finalize(r.GetReproducerPath())) { + SetError(result, std::move(e)); + return result.Succeeded(); + } } else if (r.IsReplaying()) { // Make this operation a NO-OP in replay mode. result.SetStatus(eReturnStatusSuccessFinishNoResult); return result.Succeeded(); } else { result.AppendErrorWithFormat("Unable to get the reproducer generator"); - result.SetStatus(eReturnStatusFailed); return false; } @@ -228,7 +277,7 @@ protected: auto &r = Reproducer::Instance(); if (!r.IsCapturing() && !r.IsReplaying()) { - result.SetError( + result.AppendError( "forcing a crash is only supported when capturing a reproducer."); result.SetStatus(eReturnStatusSuccessFinishNoResult); return false; @@ -300,12 +349,6 @@ protected: } }; -static void SetError(CommandReturnObject &result, Error err) { - result.GetErrorStream().Printf("error: %s\n", - toString(std::move(err)).c_str()); - result.SetStatus(eReturnStatusFailed); -} - class CommandObjectReproducerDump : public CommandObjectParsed { public: CommandObjectReproducerDump(CommandInterpreter &interpreter) @@ -370,29 +413,11 @@ protected: return false; } - // If no reproducer path is specified, use the loader currently used for - // replay. Otherwise create a new loader just for dumping. llvm::Optional loader_storage; - Loader *loader = nullptr; - if (!m_options.file) { - loader = Reproducer::Instance().GetLoader(); - if (loader == nullptr) { - result.SetError( - "Not specifying a reproducer is only support during replay."); - result.SetStatus(eReturnStatusSuccessFinishNoResult); - return false; - } - } else { - loader_storage.emplace(m_options.file); - loader = &(*loader_storage); - if (Error err = loader->LoadIndex()) { - SetError(result, std::move(err)); - return false; - } - } - - // If we get here we should have a valid loader. - assert(loader); + Loader *loader = + GetLoaderFromPathOrCurrent(loader_storage, result, m_options.file); + if (!loader) + return false; switch (m_options.provider) { case eReproducerProviderFiles: { @@ -421,6 +446,29 @@ protected: result.SetStatus(eReturnStatusSuccessFinishResult); return true; } + case eReproducerProviderSymbolFiles: { + Expected symbol_files = + loader->LoadBuffer(); + if (!symbol_files) { + SetError(result, symbol_files.takeError()); + return false; + } + + std::vector entries; + llvm::yaml::Input yin(*symbol_files); + yin >> entries; + + for (const auto &entry : entries) { + result.AppendMessageWithFormat("- uuid: %s\n", + entry.uuid.c_str()); + result.AppendMessageWithFormat(" module path: %s\n", + entry.module_path.c_str()); + result.AppendMessageWithFormat(" symbol path: %s\n", + entry.symbol_path.c_str()); + } + result.SetStatus(eReturnStatusSuccessFinishResult); + return true; + } case eReproducerProviderVersion: { Expected version = loader->LoadBuffer(); if (!version) { @@ -433,7 +481,7 @@ protected: } case eReproducerProviderWorkingDirectory: { Expected cwd = - loader->LoadBuffer(); + repro::GetDirectoryFrom(loader); if (!cwd) { SetError(result, cwd.takeError()); return false; @@ -442,6 +490,17 @@ protected: result.SetStatus(eReturnStatusSuccessFinishResult); return true; } + case eReproducerProviderHomeDirectory: { + Expected home = + repro::GetDirectoryFrom(loader); + if (!home) { + SetError(result, home.takeError()); + return false; + } + result.AppendMessage(*home); + result.SetStatus(eReturnStatusSuccessFinishResult); + return true; + } case eReproducerProviderCommands: { std::unique_ptr> multi_loader = repro::MultiLoader::Create(loader); @@ -525,7 +584,7 @@ protected: return true; } case eReproducerProviderNone: - result.SetError("No valid provider specified."); + result.AppendError("No valid provider specified."); return false; } @@ -537,6 +596,101 @@ private: CommandOptions m_options; }; +class CommandObjectReproducerVerify : public CommandObjectParsed { +public: + CommandObjectReproducerVerify(CommandInterpreter &interpreter) + : CommandObjectParsed(interpreter, "reproducer verify", + "Verify the contents of a reproducer. " + "If no reproducer is specified during replay, it " + "verifies the content of the current reproducer.", + nullptr) {} + + ~CommandObjectReproducerVerify() override = default; + + Options *GetOptions() override { return &m_options; } + + class CommandOptions : public Options { + public: + CommandOptions() : Options(), file() {} + + ~CommandOptions() override = default; + + Status SetOptionValue(uint32_t option_idx, StringRef option_arg, + ExecutionContext *execution_context) override { + Status error; + const int short_option = m_getopt_table[option_idx].val; + + switch (short_option) { + case 'f': + file.SetFile(option_arg, FileSpec::Style::native); + FileSystem::Instance().Resolve(file); + break; + default: + llvm_unreachable("Unimplemented option"); + } + + return error; + } + + void OptionParsingStarting(ExecutionContext *execution_context) override { + file.Clear(); + } + + ArrayRef GetDefinitions() override { + return makeArrayRef(g_reproducer_verify_options); + } + + FileSpec file; + }; + +protected: + bool DoExecute(Args &command, CommandReturnObject &result) override { + if (!command.empty()) { + result.AppendErrorWithFormat("'%s' takes no arguments", + m_cmd_name.c_str()); + return false; + } + + llvm::Optional loader_storage; + Loader *loader = + GetLoaderFromPathOrCurrent(loader_storage, result, m_options.file); + if (!loader) + return false; + + bool errors = false; + auto error_callback = [&](llvm::StringRef error) { + errors = true; + result.AppendError(error); + }; + + bool warnings = false; + auto warning_callback = [&](llvm::StringRef warning) { + warnings = true; + result.AppendWarning(warning); + }; + + auto note_callback = [&](llvm::StringRef warning) { + result.AppendMessage(warning); + }; + + Verifier verifier(loader); + verifier.Verify(error_callback, warning_callback, note_callback); + + if (warnings || errors) { + result.AppendMessage("reproducer verification failed"); + result.SetStatus(eReturnStatusFailed); + } else { + result.AppendMessage("reproducer verification succeeded"); + result.SetStatus(eReturnStatusSuccessFinishResult); + } + + return result.Succeeded(); + } + +private: + CommandOptions m_options; +}; + CommandObjectReproducer::CommandObjectReproducer( CommandInterpreter &interpreter) : CommandObjectMultiword( @@ -559,6 +713,8 @@ CommandObjectReproducer::CommandObjectReproducer( new CommandObjectReproducerStatus(interpreter))); LoadSubCommand("dump", CommandObjectSP(new CommandObjectReproducerDump(interpreter))); + LoadSubCommand("verify", CommandObjectSP( + new CommandObjectReproducerVerify(interpreter))); LoadSubCommand("xcrash", CommandObjectSP( new CommandObjectReproducerXCrash(interpreter))); } diff --git a/gnu/llvm/lldb/source/Commands/CommandObjectScript.cpp b/gnu/llvm/lldb/source/Commands/CommandObjectScript.cpp new file mode 100644 index 00000000000..f53d6540bc0 --- /dev/null +++ b/gnu/llvm/lldb/source/Commands/CommandObjectScript.cpp @@ -0,0 +1,136 @@ +//===-- CommandObjectScript.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 "CommandObjectScript.h" +#include "lldb/Core/Debugger.h" +#include "lldb/DataFormatters/DataVisualization.h" +#include "lldb/Host/Config.h" +#include "lldb/Host/OptionParser.h" +#include "lldb/Interpreter/CommandInterpreter.h" +#include "lldb/Interpreter/CommandReturnObject.h" +#include "lldb/Interpreter/OptionArgParser.h" +#include "lldb/Interpreter/ScriptInterpreter.h" +#include "lldb/Utility/Args.h" + +using namespace lldb; +using namespace lldb_private; + +static constexpr OptionEnumValueElement g_script_option_enumeration[] = { + { + eScriptLanguagePython, + "python", + "Python", + }, + { + eScriptLanguageLua, + "lua", + "Lua", + }, + { + eScriptLanguageNone, + "default", + "The default scripting language.", + }, +}; + +static constexpr OptionEnumValues ScriptOptionEnum() { + return OptionEnumValues(g_script_option_enumeration); +} + +#define LLDB_OPTIONS_script +#include "CommandOptions.inc" + +Status CommandObjectScript::CommandOptions::SetOptionValue( + uint32_t option_idx, llvm::StringRef option_arg, + ExecutionContext *execution_context) { + Status error; + const int short_option = m_getopt_table[option_idx].val; + + switch (short_option) { + case 'l': + language = (lldb::ScriptLanguage)OptionArgParser::ToOptionEnum( + option_arg, GetDefinitions()[option_idx].enum_values, + eScriptLanguageNone, error); + if (!error.Success()) + error.SetErrorStringWithFormat("unrecognized value for language '%s'", + option_arg.str().c_str()); + break; + default: + llvm_unreachable("Unimplemented option"); + } + + return error; +} + +void CommandObjectScript::CommandOptions::OptionParsingStarting( + ExecutionContext *execution_context) { + language = lldb::eScriptLanguageNone; +} + +llvm::ArrayRef +CommandObjectScript::CommandOptions::GetDefinitions() { + return llvm::makeArrayRef(g_script_options); +} + +CommandObjectScript::CommandObjectScript(CommandInterpreter &interpreter) + : CommandObjectRaw( + interpreter, "script", + "Invoke the script interpreter with provided code and display any " + "results. Start the interactive interpreter if no code is supplied.", + "script [--language --] []") {} + +CommandObjectScript::~CommandObjectScript() = default; + +bool CommandObjectScript::DoExecute(llvm::StringRef command, + CommandReturnObject &result) { + // Try parsing the language option but when the command contains a raw part + // separated by the -- delimiter. + OptionsWithRaw raw_args(command); + if (raw_args.HasArgs()) { + if (!ParseOptions(raw_args.GetArgs(), result)) + return false; + command = raw_args.GetRawPart(); + } + + lldb::ScriptLanguage language = + (m_options.language == lldb::eScriptLanguageNone) + ? m_interpreter.GetDebugger().GetScriptLanguage() + : m_options.language; + + if (language == lldb::eScriptLanguageNone) { + result.AppendError( + "the script-lang setting is set to none - scripting not available"); + return false; + } + + ScriptInterpreter *script_interpreter = + GetDebugger().GetScriptInterpreter(true, language); + + if (script_interpreter == nullptr) { + result.AppendError("no script interpreter"); + return false; + } + + // Script might change Python code we use for formatting. Make sure we keep + // up to date with it. + DataVisualization::ForceUpdate(); + + if (command.empty()) { + script_interpreter->ExecuteInterpreterLoop(); + result.SetStatus(eReturnStatusSuccessFinishNoResult); + return result.Succeeded(); + } + + // We can do better when reporting the status of one-liner script execution. + if (script_interpreter->ExecuteOneLine(command, &result)) + result.SetStatus(eReturnStatusSuccessFinishNoResult); + else + result.SetStatus(eReturnStatusFailed); + + return result.Succeeded(); +} diff --git a/gnu/llvm/lldb/source/Commands/CommandObjectScript.h b/gnu/llvm/lldb/source/Commands/CommandObjectScript.h new file mode 100644 index 00000000000..b9fee712481 --- /dev/null +++ b/gnu/llvm/lldb/source/Commands/CommandObjectScript.h @@ -0,0 +1,42 @@ +//===-- CommandObjectScript.h -----------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SOURCE_INTERPRETER_COMMANDOBJECTSCRIPT_H +#define LLDB_SOURCE_INTERPRETER_COMMANDOBJECTSCRIPT_H + +#include "lldb/Interpreter/CommandObject.h" + +namespace lldb_private { + +class CommandObjectScript : public CommandObjectRaw { +public: + CommandObjectScript(CommandInterpreter &interpreter); + ~CommandObjectScript() override; + Options *GetOptions() override { return &m_options; } + + class CommandOptions : public Options { + public: + CommandOptions() : Options() {} + ~CommandOptions() override = default; + Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, + ExecutionContext *execution_context) override; + void OptionParsingStarting(ExecutionContext *execution_context) override; + llvm::ArrayRef GetDefinitions() override; + lldb::ScriptLanguage language = lldb::eScriptLanguageNone; + }; + +protected: + bool DoExecute(llvm::StringRef command, CommandReturnObject &result) override; + +private: + CommandOptions m_options; +}; + +} // namespace lldb_private + +#endif // LLDB_SOURCE_INTERPRETER_COMMANDOBJECTSCRIPT_H diff --git a/gnu/llvm/lldb/source/Commands/CommandObjectSession.cpp b/gnu/llvm/lldb/source/Commands/CommandObjectSession.cpp new file mode 100644 index 00000000000..c2cdfa29a3f --- /dev/null +++ b/gnu/llvm/lldb/source/Commands/CommandObjectSession.cpp @@ -0,0 +1,208 @@ +#include "CommandObjectSession.h" +#include "lldb/Host/OptionParser.h" +#include "lldb/Interpreter/CommandInterpreter.h" +#include "lldb/Interpreter/CommandReturnObject.h" +#include "lldb/Interpreter/OptionArgParser.h" +#include "lldb/Interpreter/OptionValue.h" +#include "lldb/Interpreter/OptionValueBoolean.h" +#include "lldb/Interpreter/OptionValueString.h" +#include "lldb/Interpreter/OptionValueUInt64.h" +#include "lldb/Interpreter/Options.h" + +using namespace lldb; +using namespace lldb_private; + +class CommandObjectSessionSave : public CommandObjectParsed { +public: + CommandObjectSessionSave(CommandInterpreter &interpreter) + : CommandObjectParsed(interpreter, "session save", + "Save the current session transcripts to a file.\n" + "If no file if specified, transcripts will be " + "saved to a temporary file.", + "session save [file]") { + CommandArgumentEntry arg1; + arg1.emplace_back(eArgTypePath, eArgRepeatOptional); + m_arguments.push_back(arg1); + } + + ~CommandObjectSessionSave() override = default; + + void + HandleArgumentCompletion(CompletionRequest &request, + OptionElementVector &opt_element_vector) override { + CommandCompletions::InvokeCommonCompletionCallbacks( + GetCommandInterpreter(), CommandCompletions::eDiskFileCompletion, + request, nullptr); + } + +protected: + bool DoExecute(Args &args, CommandReturnObject &result) override { + llvm::StringRef file_path; + + if (!args.empty()) + file_path = args[0].ref(); + + if (m_interpreter.SaveTranscript(result, file_path.str())) + result.SetStatus(eReturnStatusSuccessFinishNoResult); + else + result.SetStatus(eReturnStatusFailed); + return result.Succeeded(); + } +}; + +#define LLDB_OPTIONS_history +#include "CommandOptions.inc" + +class CommandObjectSessionHistory : public CommandObjectParsed { +public: + CommandObjectSessionHistory(CommandInterpreter &interpreter) + : CommandObjectParsed(interpreter, "session history", + "Dump the history of commands in this session.\n" + "Commands in the history list can be run again " + "using \"!\". \"!-\" will re-run " + "the command that is commands from the end" + " of the list (counting the current command).", + nullptr), + m_options() {} + + ~CommandObjectSessionHistory() override = default; + + Options *GetOptions() override { return &m_options; } + +protected: + class CommandOptions : public Options { + public: + CommandOptions() + : Options(), m_start_idx(0), m_stop_idx(0), m_count(0), m_clear(false) { + } + + ~CommandOptions() override = default; + + Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, + ExecutionContext *execution_context) override { + Status error; + const int short_option = m_getopt_table[option_idx].val; + + switch (short_option) { + case 'c': + error = m_count.SetValueFromString(option_arg, eVarSetOperationAssign); + break; + case 's': + if (option_arg == "end") { + m_start_idx.SetCurrentValue(UINT64_MAX); + m_start_idx.SetOptionWasSet(); + } else + error = m_start_idx.SetValueFromString(option_arg, + eVarSetOperationAssign); + break; + case 'e': + error = + m_stop_idx.SetValueFromString(option_arg, eVarSetOperationAssign); + break; + case 'C': + m_clear.SetCurrentValue(true); + m_clear.SetOptionWasSet(); + break; + default: + llvm_unreachable("Unimplemented option"); + } + + return error; + } + + void OptionParsingStarting(ExecutionContext *execution_context) override { + m_start_idx.Clear(); + m_stop_idx.Clear(); + m_count.Clear(); + m_clear.Clear(); + } + + llvm::ArrayRef GetDefinitions() override { + return llvm::makeArrayRef(g_history_options); + } + + // Instance variables to hold the values for command options. + + OptionValueUInt64 m_start_idx; + OptionValueUInt64 m_stop_idx; + OptionValueUInt64 m_count; + OptionValueBoolean m_clear; + }; + + bool DoExecute(Args &command, CommandReturnObject &result) override { + if (m_options.m_clear.GetCurrentValue() && + m_options.m_clear.OptionWasSet()) { + m_interpreter.GetCommandHistory().Clear(); + result.SetStatus(lldb::eReturnStatusSuccessFinishNoResult); + } else { + if (m_options.m_start_idx.OptionWasSet() && + m_options.m_stop_idx.OptionWasSet() && + m_options.m_count.OptionWasSet()) { + result.AppendError("--count, --start-index and --end-index cannot be " + "all specified in the same invocation"); + result.SetStatus(lldb::eReturnStatusFailed); + } else { + std::pair start_idx( + m_options.m_start_idx.OptionWasSet(), + m_options.m_start_idx.GetCurrentValue()); + std::pair stop_idx( + m_options.m_stop_idx.OptionWasSet(), + m_options.m_stop_idx.GetCurrentValue()); + std::pair count(m_options.m_count.OptionWasSet(), + m_options.m_count.GetCurrentValue()); + + const CommandHistory &history(m_interpreter.GetCommandHistory()); + + if (start_idx.first && start_idx.second == UINT64_MAX) { + if (count.first) { + start_idx.second = history.GetSize() - count.second; + stop_idx.second = history.GetSize() - 1; + } else if (stop_idx.first) { + start_idx.second = stop_idx.second; + stop_idx.second = history.GetSize() - 1; + } else { + start_idx.second = 0; + stop_idx.second = history.GetSize() - 1; + } + } else { + if (!start_idx.first && !stop_idx.first && !count.first) { + start_idx.second = 0; + stop_idx.second = history.GetSize() - 1; + } else if (start_idx.first) { + if (count.first) { + stop_idx.second = start_idx.second + count.second - 1; + } else if (!stop_idx.first) { + stop_idx.second = history.GetSize() - 1; + } + } else if (stop_idx.first) { + if (count.first) { + if (stop_idx.second >= count.second) + start_idx.second = stop_idx.second - count.second + 1; + else + start_idx.second = 0; + } + } else /* if (count.first) */ + { + start_idx.second = 0; + stop_idx.second = count.second - 1; + } + } + history.Dump(result.GetOutputStream(), start_idx.second, + stop_idx.second); + } + } + return result.Succeeded(); + } + + CommandOptions m_options; +}; + +CommandObjectSession::CommandObjectSession(CommandInterpreter &interpreter) + : CommandObjectMultiword(interpreter, "session", + "Commands controlling LLDB session.", + "session []") { + LoadSubCommand("save", + CommandObjectSP(new CommandObjectSessionSave(interpreter))); + LoadSubCommand("history", + CommandObjectSP(new CommandObjectSessionHistory(interpreter))); +} diff --git a/gnu/llvm/lldb/source/Commands/CommandObjectSession.h b/gnu/llvm/lldb/source/Commands/CommandObjectSession.h new file mode 100644 index 00000000000..0af0e279f47 --- /dev/null +++ b/gnu/llvm/lldb/source/Commands/CommandObjectSession.h @@ -0,0 +1,23 @@ +//===-- CommandObjectSession.h ----------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SOURCE_COMMANDS_COMMANDOBJECTSESSION_H +#define LLDB_SOURCE_COMMANDS_COMMANDOBJECTSESSION_H + +#include "lldb/Interpreter/CommandObjectMultiword.h" + +namespace lldb_private { + +class CommandObjectSession : public CommandObjectMultiword { +public: + CommandObjectSession(CommandInterpreter &interpreter); +}; + +} // namespace lldb_private + +#endif // LLDB_SOURCE_COMMANDS_COMMANDOBJECTSESSION_H diff --git a/gnu/llvm/lldb/source/Commands/CommandObjectSettings.cpp b/gnu/llvm/lldb/source/Commands/CommandObjectSettings.cpp index 87e0352636e..cd79680e31f 100644 --- a/gnu/llvm/lldb/source/Commands/CommandObjectSettings.cpp +++ b/gnu/llvm/lldb/source/Commands/CommandObjectSettings.cpp @@ -87,7 +87,7 @@ insert-before or insert-after."); class CommandOptions : public Options { public: - CommandOptions() : Options(), m_global(false) {} + CommandOptions() : Options() {} ~CommandOptions() override = default; @@ -120,7 +120,7 @@ insert-before or insert-after."); } // Instance variables to hold the values for command options. - bool m_global; + bool m_global = false; bool m_force; }; @@ -177,7 +177,6 @@ protected: if ((argc < min_argc) && (!m_options.m_global)) { result.AppendError("'settings set' takes more arguments"); - result.SetStatus(eReturnStatusFailed); return false; } @@ -185,7 +184,6 @@ protected: if ((var_name == nullptr) || (var_name[0] == '\0')) { result.AppendError( "'settings set' command requires a valid variable name"); - result.SetStatus(eReturnStatusFailed); return false; } @@ -196,7 +194,6 @@ protected: &m_exe_ctx, eVarSetOperationClear, var_name, llvm::StringRef())); if (error.Fail()) { result.AppendError(error.AsCString()); - result.SetStatus(eReturnStatusFailed); return false; } return result.Succeeded(); @@ -225,7 +222,6 @@ protected: if (error.Fail()) { result.AppendError(error.AsCString()); - result.SetStatus(eReturnStatusFailed); return false; } else { result.SetStatus(eReturnStatusSuccessFinishResult); @@ -285,7 +281,6 @@ protected: result.GetOutputStream().EOL(); } else { result.AppendError(error.AsCString()); - result.SetStatus(eReturnStatusFailed); } } } else { @@ -385,7 +380,6 @@ protected: if (!out_file.GetFile().IsValid()) { result.AppendErrorWithFormat("%s: unable to write to file", path.c_str()); - result.SetStatus(eReturnStatusFailed); return false; } @@ -403,7 +397,6 @@ protected: &clean_ctx, out_file, arg.ref(), OptionValue::eDumpGroupExport)); if (!error.Success()) { result.AppendError(error.AsCString()); - result.SetStatus(eReturnStatusFailed); } } @@ -469,14 +462,13 @@ protected: bool DoExecute(Args &command, CommandReturnObject &result) override { FileSpec file(m_options.m_filename); FileSystem::Instance().Resolve(file); - ExecutionContext clean_ctx; CommandInterpreterRunOptions options; options.SetAddToHistory(false); options.SetEchoCommands(false); options.SetPrintResults(true); options.SetPrintErrors(true); options.SetStopOnError(false); - m_interpreter.HandleCommandsFromFile(file, &clean_ctx, options, result); + m_interpreter.HandleCommandsFromFile(file, options, result); return result.Succeeded(); } @@ -544,7 +536,6 @@ protected: } else { result.AppendErrorWithFormat("invalid property path '%s'", property_path); - result.SetStatus(eReturnStatusFailed); } } } else { @@ -625,7 +616,6 @@ protected: "or an array followed by one or more indexes, or a " "dictionary followed by one or more key names to " "remove"); - result.SetStatus(eReturnStatusFailed); return false; } @@ -633,7 +623,6 @@ protected: if ((var_name == nullptr) || (var_name[0] == '\0')) { result.AppendError( "'settings remove' command requires a valid variable name"); - result.SetStatus(eReturnStatusFailed); return false; } @@ -645,7 +634,6 @@ protected: &m_exe_ctx, eVarSetOperationRemove, var_name, var_value)); if (error.Fail()) { result.AppendError(error.AsCString()); - result.SetStatus(eReturnStatusFailed); return false; } @@ -729,7 +717,6 @@ protected: if ((var_name == nullptr) || (var_name[0] == '\0')) { result.AppendError("'settings replace' command requires a valid variable " "name; No value supplied"); - result.SetStatus(eReturnStatusFailed); return false; } @@ -741,7 +728,6 @@ protected: &m_exe_ctx, eVarSetOperationReplace, var_name, var_value)); if (error.Fail()) { result.AppendError(error.AsCString()); - result.SetStatus(eReturnStatusFailed); return false; } else { result.SetStatus(eReturnStatusSuccessFinishNoResult); @@ -823,7 +809,6 @@ protected: if (argc < 3) { result.AppendError("'settings insert-before' takes more arguments"); - result.SetStatus(eReturnStatusFailed); return false; } @@ -831,7 +816,6 @@ protected: if ((var_name == nullptr) || (var_name[0] == '\0')) { result.AppendError("'settings insert-before' command requires a valid " "variable name; No value supplied"); - result.SetStatus(eReturnStatusFailed); return false; } @@ -843,7 +827,6 @@ protected: &m_exe_ctx, eVarSetOperationInsertBefore, var_name, var_value)); if (error.Fail()) { result.AppendError(error.AsCString()); - result.SetStatus(eReturnStatusFailed); return false; } @@ -922,7 +905,6 @@ protected: if (argc < 3) { result.AppendError("'settings insert-after' takes more arguments"); - result.SetStatus(eReturnStatusFailed); return false; } @@ -930,7 +912,6 @@ protected: if ((var_name == nullptr) || (var_name[0] == '\0')) { result.AppendError("'settings insert-after' command requires a valid " "variable name; No value supplied"); - result.SetStatus(eReturnStatusFailed); return false; } @@ -942,7 +923,6 @@ protected: &m_exe_ctx, eVarSetOperationInsertAfter, var_name, var_value)); if (error.Fail()) { result.AppendError(error.AsCString()); - result.SetStatus(eReturnStatusFailed); return false; } @@ -1009,7 +989,6 @@ protected: if (argc < 2) { result.AppendError("'settings append' takes more arguments"); - result.SetStatus(eReturnStatusFailed); return false; } @@ -1017,7 +996,6 @@ protected: if ((var_name == nullptr) || (var_name[0] == '\0')) { result.AppendError("'settings append' command requires a valid variable " "name; No value supplied"); - result.SetStatus(eReturnStatusFailed); return false; } @@ -1032,7 +1010,6 @@ protected: &m_exe_ctx, eVarSetOperationAppend, var_name, var_value)); if (error.Fail()) { result.AppendError(error.AsCString()); - result.SetStatus(eReturnStatusFailed); return false; } @@ -1118,7 +1095,6 @@ protected: if (m_options.m_clear_all) { if (argc != 0) { result.AppendError("'settings clear --all' doesn't take any arguments"); - result.SetStatus(eReturnStatusFailed); return false; } GetDebugger().GetValueProperties()->Clear(); @@ -1127,7 +1103,6 @@ protected: if (argc != 1) { result.AppendError("'settings clear' takes exactly one argument"); - result.SetStatus(eReturnStatusFailed); return false; } @@ -1135,7 +1110,6 @@ protected: if ((var_name == nullptr) || (var_name[0] == '\0')) { result.AppendError("'settings clear' command requires a valid variable " "name; No value supplied"); - result.SetStatus(eReturnStatusFailed); return false; } @@ -1143,7 +1117,6 @@ protected: &m_exe_ctx, eVarSetOperationClear, var_name, llvm::StringRef())); if (error.Fail()) { result.AppendError(error.AsCString()); - result.SetStatus(eReturnStatusFailed); return false; } diff --git a/gnu/llvm/lldb/source/Commands/CommandObjectSource.cpp b/gnu/llvm/lldb/source/Commands/CommandObjectSource.cpp index 1ccfd3a5166..7a0338e35bc 100644 --- a/gnu/llvm/lldb/source/Commands/CommandObjectSource.cpp +++ b/gnu/llvm/lldb/source/Commands/CommandObjectSource.cpp @@ -16,6 +16,7 @@ #include "lldb/Host/OptionParser.h" #include "lldb/Interpreter/CommandReturnObject.h" #include "lldb/Interpreter/OptionArgParser.h" +#include "lldb/Interpreter/OptionValueFileColonLine.h" #include "lldb/Interpreter/Options.h" #include "lldb/Symbol/CompileUnit.h" #include "lldb/Symbol/Function.h" @@ -540,7 +541,6 @@ protected: if (argc != 0) { result.AppendErrorWithFormat("'%s' takes no arguments, only flags.\n", GetCommandName().str().c_str()); - result.SetStatus(eReturnStatusFailed); return false; } @@ -550,7 +550,6 @@ protected: if (target == nullptr) { result.AppendError("invalid target, create a debug target using the " "'target create' command."); - result.SetStatus(eReturnStatusFailed); return false; } } @@ -574,12 +573,10 @@ protected: } if (!m_module_list.GetSize()) { result.AppendError("No modules match the input."); - result.SetStatus(eReturnStatusFailed); return false; } } else if (target->GetImages().GetSize() == 0) { result.AppendError("The target has no associated executable images."); - result.SetStatus(eReturnStatusFailed); return false; } @@ -667,6 +664,22 @@ class CommandObjectSourceList : public CommandObjectParsed { case 'r': reverse = true; break; + case 'y': + { + OptionValueFileColonLine value; + Status fcl_err = value.SetValueFromString(option_arg); + if (!fcl_err.Success()) { + error.SetErrorStringWithFormat( + "Invalid value for file:line specifier: %s", + fcl_err.AsCString()); + } else { + file_name = value.GetFileSpec().GetPath(); + start_line = value.GetLineNumber(); + // I don't see anything useful to do with a column number, but I don't + // want to complain since someone may well have cut and pasted a + // listing from somewhere that included a column. + } + } break; default: llvm_unreachable("Unimplemented option"); } @@ -794,7 +807,6 @@ protected: result.AppendErrorWithFormat("Could not find line information for " "start of function: \"%s\".\n", source_info.function.GetCString()); - result.SetStatus(eReturnStatusFailed); return 0; } sc.function->GetEndLineSourceInfo(end_file, end_line); @@ -916,7 +928,6 @@ protected: if (argc != 0) { result.AppendErrorWithFormat("'%s' takes no arguments, only flags.\n", GetCommandName().str().c_str()); - result.SetStatus(eReturnStatusFailed); return false; } @@ -954,7 +965,6 @@ protected: if (num_matches == 0) { result.AppendErrorWithFormat("Could not find function named: \"%s\".\n", m_options.symbol_name.c_str()); - result.SetStatus(eReturnStatusFailed); return false; } @@ -1021,7 +1031,6 @@ protected: "no modules have source information for file address 0x%" PRIx64 ".\n", m_options.address); - result.SetStatus(eReturnStatusFailed); return false; } } else { @@ -1044,7 +1053,6 @@ protected: "is no line table information " "available for this address.\n", error_strm.GetData()); - result.SetStatus(eReturnStatusFailed); return false; } } @@ -1054,7 +1062,6 @@ protected: result.AppendErrorWithFormat( "no modules contain load address 0x%" PRIx64 ".\n", m_options.address); - result.SetStatus(eReturnStatusFailed); return false; } } @@ -1174,7 +1181,6 @@ protected: if (num_matches == 0) { result.AppendErrorWithFormat("Could not find source file \"%s\".\n", m_options.file_name.c_str()); - result.SetStatus(eReturnStatusFailed); return false; } @@ -1198,7 +1204,6 @@ protected: result.AppendErrorWithFormat( "Multiple source files found matching: \"%s.\"\n", m_options.file_name.c_str()); - result.SetStatus(eReturnStatusFailed); return false; } } @@ -1228,7 +1233,6 @@ protected: } else { result.AppendErrorWithFormat("No comp unit found for: \"%s.\"\n", m_options.file_name.c_str()); - result.SetStatus(eReturnStatusFailed); return false; } } diff --git a/gnu/llvm/lldb/source/Commands/CommandObjectStats.cpp b/gnu/llvm/lldb/source/Commands/CommandObjectStats.cpp index 6b06581f5a8..23c7dbbaf37 100644 --- a/gnu/llvm/lldb/source/Commands/CommandObjectStats.cpp +++ b/gnu/llvm/lldb/source/Commands/CommandObjectStats.cpp @@ -28,7 +28,6 @@ protected: if (target.GetCollectingStats()) { result.AppendError("statistics already enabled"); - result.SetStatus(eReturnStatusFailed); return false; } @@ -53,7 +52,6 @@ protected: if (!target.GetCollectingStats()) { result.AppendError("need to enable statistics before disabling them"); - result.SetStatus(eReturnStatusFailed); return false; } diff --git a/gnu/llvm/lldb/source/Commands/CommandObjectTarget.cpp b/gnu/llvm/lldb/source/Commands/CommandObjectTarget.cpp index 7bb71f4d518..b25514b1ffb 100644 --- a/gnu/llvm/lldb/source/Commands/CommandObjectTarget.cpp +++ b/gnu/llvm/lldb/source/Commands/CommandObjectTarget.cpp @@ -23,6 +23,8 @@ #include "lldb/Interpreter/OptionGroupBoolean.h" #include "lldb/Interpreter/OptionGroupFile.h" #include "lldb/Interpreter/OptionGroupFormat.h" +#include "lldb/Interpreter/OptionGroupPlatform.h" +#include "lldb/Interpreter/OptionGroupPythonClassWithDict.h" #include "lldb/Interpreter/OptionGroupString.h" #include "lldb/Interpreter/OptionGroupUInt64.h" #include "lldb/Interpreter/OptionGroupUUID.h" @@ -48,6 +50,7 @@ #include "lldb/Utility/State.h" #include "lldb/Utility/Timer.h" +#include "llvm/ADT/ScopeExit.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/FormatAdapters.h" @@ -155,9 +158,9 @@ static constexpr OptionEnumValueElement g_dependents_enumaration[] = { class OptionGroupDependents : public OptionGroup { public: - OptionGroupDependents() {} + OptionGroupDependents() = default; - ~OptionGroupDependents() override {} + ~OptionGroupDependents() override = default; llvm::ArrayRef GetDefinitions() override { return llvm::makeArrayRef(g_target_dependents_options); @@ -206,8 +209,6 @@ private: #pragma mark CommandObjectTargetCreate -// "target create" - class CommandObjectTargetCreate : public CommandObjectParsed { public: CommandObjectTargetCreate(CommandInterpreter &interpreter) @@ -216,11 +217,9 @@ public: "Create a target using the argument as the main executable.", nullptr), m_option_group(), m_arch_option(), + m_platform_options(true), // Include the --platform option. m_core_file(LLDB_OPT_SET_1, false, "core", 'c', 0, eArgTypeFilename, "Fullpath to a core file to use for this target."), - m_platform_path(LLDB_OPT_SET_1, false, "platform-path", 'P', 0, - eArgTypePath, - "Path to the remote file to use for this target."), m_symbol_file(LLDB_OPT_SET_1, false, "symfile", 's', 0, eArgTypeFilename, "Fullpath to a stand alone debug " @@ -245,8 +244,8 @@ public: m_arguments.push_back(arg); m_option_group.Append(&m_arch_option, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1); + m_option_group.Append(&m_platform_options, LLDB_OPT_SET_ALL, 1); m_option_group.Append(&m_core_file, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1); - m_option_group.Append(&m_platform_path, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1); m_option_group.Append(&m_symbol_file, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1); m_option_group.Append(&m_remote_file, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1); m_option_group.Append(&m_add_dependents, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1); @@ -279,7 +278,6 @@ protected: result.AppendErrorWithFormatv("Cannot open '{0}': {1}.", core_file.GetPath(), llvm::toString(file.takeError())); - result.SetStatus(eReturnStatusFailed); return false; } } @@ -294,14 +292,12 @@ protected: result.AppendErrorWithFormatv("Cannot open '{0}': {1}.", symfile.GetPath(), llvm::toString(file.takeError())); - result.SetStatus(eReturnStatusFailed); return false; } } const char *file_path = command.GetArgumentAtIndex(0); - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer(func_cat, "(lldb) target create '%s'", file_path); + LLDB_SCOPED_TIMERF("(lldb) target create '%s'", file_path); FileSpec file_spec; if (file_path) { @@ -317,139 +313,135 @@ protected: llvm::StringRef arch_cstr = m_arch_option.GetArchitectureName(); Status error(debugger.GetTargetList().CreateTarget( debugger, file_path, arch_cstr, - m_add_dependents.m_load_dependent_files, nullptr, target_sp)); + m_add_dependents.m_load_dependent_files, &m_platform_options, + target_sp)); - if (target_sp) { - // Only get the platform after we create the target because we might - // have switched platforms depending on what the arguments were to - // CreateTarget() we can't rely on the selected platform. - - PlatformSP platform_sp = target_sp->GetPlatform(); - - if (remote_file) { - if (platform_sp) { - // I have a remote file.. two possible cases - if (file_spec && FileSystem::Instance().Exists(file_spec)) { - // if the remote file does not exist, push it there - if (!platform_sp->GetFileExists(remote_file)) { - Status err = platform_sp->PutFile(file_spec, remote_file); - if (err.Fail()) { - result.AppendError(err.AsCString()); - result.SetStatus(eReturnStatusFailed); - return false; - } - } - } else { - // there is no local file and we need one - // in order to make the remote ---> local transfer we need a - // platform - // TODO: if the user has passed in a --platform argument, use it - // to fetch the right platform - if (!platform_sp) { - result.AppendError( - "unable to perform remote debugging without a platform"); - result.SetStatus(eReturnStatusFailed); + if (!target_sp) { + result.AppendError(error.AsCString()); + return false; + } + + auto on_error = llvm::make_scope_exit( + [&target_list = debugger.GetTargetList(), &target_sp]() { + target_list.DeleteTarget(target_sp); + }); + + // Only get the platform after we create the target because we might + // have switched platforms depending on what the arguments were to + // CreateTarget() we can't rely on the selected platform. + + PlatformSP platform_sp = target_sp->GetPlatform(); + + if (remote_file) { + if (platform_sp) { + // I have a remote file.. two possible cases + if (file_spec && FileSystem::Instance().Exists(file_spec)) { + // if the remote file does not exist, push it there + if (!platform_sp->GetFileExists(remote_file)) { + Status err = platform_sp->PutFile(file_spec, remote_file); + if (err.Fail()) { + result.AppendError(err.AsCString()); return false; } - if (file_path) { - // copy the remote file to the local file - Status err = platform_sp->GetFile(remote_file, file_spec); - if (err.Fail()) { - result.AppendError(err.AsCString()); - result.SetStatus(eReturnStatusFailed); - return false; - } - } else { - // make up a local file - result.AppendError("remote --> local transfer without local " - "path is not implemented yet"); - result.SetStatus(eReturnStatusFailed); + } + } else { + // there is no local file and we need one + // in order to make the remote ---> local transfer we need a + // platform + // TODO: if the user has passed in a --platform argument, use it + // to fetch the right platform + if (file_path) { + // copy the remote file to the local file + Status err = platform_sp->GetFile(remote_file, file_spec); + if (err.Fail()) { + result.AppendError(err.AsCString()); return false; } + } else { + // make up a local file + result.AppendError("remote --> local transfer without local " + "path is not implemented yet"); + return false; } - } else { - result.AppendError("no platform found for target"); - result.SetStatus(eReturnStatusFailed); - return false; } + } else { + result.AppendError("no platform found for target"); + return false; } + } - if (symfile || remote_file) { - ModuleSP module_sp(target_sp->GetExecutableModule()); - if (module_sp) { - if (symfile) - module_sp->SetSymbolFileFileSpec(symfile); - if (remote_file) { - std::string remote_path = remote_file.GetPath(); - target_sp->SetArg0(remote_path.c_str()); - module_sp->SetPlatformFileSpec(remote_file); - } + if (symfile || remote_file) { + ModuleSP module_sp(target_sp->GetExecutableModule()); + if (module_sp) { + if (symfile) + module_sp->SetSymbolFileFileSpec(symfile); + if (remote_file) { + std::string remote_path = remote_file.GetPath(); + target_sp->SetArg0(remote_path.c_str()); + module_sp->SetPlatformFileSpec(remote_file); } } + } - debugger.GetTargetList().SetSelectedTarget(target_sp.get()); - if (must_set_platform_path) { - ModuleSpec main_module_spec(file_spec); - ModuleSP module_sp = - target_sp->GetOrCreateModule(main_module_spec, true /* notify */); - if (module_sp) - module_sp->SetPlatformFileSpec(remote_file); - } + if (must_set_platform_path) { + ModuleSpec main_module_spec(file_spec); + ModuleSP module_sp = + target_sp->GetOrCreateModule(main_module_spec, true /* notify */); + if (module_sp) + module_sp->SetPlatformFileSpec(remote_file); + } - if (core_file) { - FileSpec core_file_dir; - core_file_dir.GetDirectory() = core_file.GetDirectory(); - target_sp->AppendExecutableSearchPaths(core_file_dir); + if (core_file) { + FileSpec core_file_dir; + core_file_dir.GetDirectory() = core_file.GetDirectory(); + target_sp->AppendExecutableSearchPaths(core_file_dir); - ProcessSP process_sp(target_sp->CreateProcess( - GetDebugger().GetListener(), llvm::StringRef(), &core_file)); + ProcessSP process_sp(target_sp->CreateProcess( + GetDebugger().GetListener(), llvm::StringRef(), &core_file, false)); - if (process_sp) { - // Seems weird that we Launch a core file, but that is what we - // do! - error = process_sp->LoadCore(); + if (process_sp) { + // Seems weird that we Launch a core file, but that is what we + // do! + error = process_sp->LoadCore(); - if (error.Fail()) { - result.AppendError( - error.AsCString("can't find plug-in for core file")); - result.SetStatus(eReturnStatusFailed); - return false; - } else { - result.AppendMessageWithFormatv("Core file '{0}' ({1}) was loaded.\n", core_file.GetPath(), - target_sp->GetArchitecture().GetArchitectureName()); - result.SetStatus(eReturnStatusSuccessFinishNoResult); - } + if (error.Fail()) { + result.AppendError( + error.AsCString("can't find plug-in for core file")); + return false; } else { - result.AppendErrorWithFormatv( - "Unable to find process plug-in for core file '{0}'\n", - core_file.GetPath()); - result.SetStatus(eReturnStatusFailed); + result.AppendMessageWithFormatv( + "Core file '{0}' ({1}) was loaded.\n", core_file.GetPath(), + target_sp->GetArchitecture().GetArchitectureName()); + result.SetStatus(eReturnStatusSuccessFinishNoResult); + on_error.release(); } } else { - result.AppendMessageWithFormat( - "Current executable set to '%s' (%s).\n", - file_spec.GetPath().c_str(), - target_sp->GetArchitecture().GetArchitectureName()); - result.SetStatus(eReturnStatusSuccessFinishNoResult); + result.AppendErrorWithFormatv( + "Unable to find process plug-in for core file '{0}'\n", + core_file.GetPath()); } } else { - result.AppendError(error.AsCString()); - result.SetStatus(eReturnStatusFailed); + result.AppendMessageWithFormat( + "Current executable set to '%s' (%s).\n", + file_spec.GetPath().c_str(), + target_sp->GetArchitecture().GetArchitectureName()); + result.SetStatus(eReturnStatusSuccessFinishNoResult); + on_error.release(); } } else { result.AppendErrorWithFormat("'%s' takes exactly one executable path " "argument, or use the --core option.\n", m_cmd_name.c_str()); - result.SetStatus(eReturnStatusFailed); } + return result.Succeeded(); } private: OptionGroupOptions m_option_group; OptionGroupArchitecture m_arch_option; + OptionGroupPlatform m_platform_options; OptionGroupFile m_core_file; - OptionGroupFile m_platform_path; OptionGroupFile m_symbol_file; OptionGroupFile m_remote_file; OptionGroupDependents m_add_dependents; @@ -457,8 +449,6 @@ private: #pragma mark CommandObjectTargetList -// "target list" - class CommandObjectTargetList : public CommandObjectParsed { public: CommandObjectTargetList(CommandInterpreter &interpreter) @@ -482,7 +472,6 @@ protected: result.SetStatus(eReturnStatusSuccessFinishResult); } else { result.AppendError("the 'target list' command takes no arguments\n"); - result.SetStatus(eReturnStatusFailed); } return result.Succeeded(); } @@ -490,8 +479,6 @@ protected: #pragma mark CommandObjectTargetSelect -// "target select" - class CommandObjectTargetSelect : public CommandObjectParsed { public: CommandObjectTargetSelect(CommandInterpreter &interpreter) @@ -511,18 +498,11 @@ protected: TargetList &target_list = GetDebugger().GetTargetList(); const uint32_t num_targets = target_list.GetNumTargets(); if (target_idx < num_targets) { - TargetSP target_sp(target_list.GetTargetAtIndex(target_idx)); - if (target_sp) { - Stream &strm = result.GetOutputStream(); - target_list.SetSelectedTarget(target_sp.get()); - bool show_stopped_process_status = false; - DumpTargetList(target_list, show_stopped_process_status, strm); - result.SetStatus(eReturnStatusSuccessFinishResult); - } else { - result.AppendErrorWithFormat("target #%u is NULL in target list\n", - target_idx); - result.SetStatus(eReturnStatusFailed); - } + target_list.SetSelectedTarget(target_idx); + Stream &strm = result.GetOutputStream(); + bool show_stopped_process_status = false; + DumpTargetList(target_list, show_stopped_process_status, strm); + result.SetStatus(eReturnStatusSuccessFinishResult); } else { if (num_targets > 0) { result.AppendErrorWithFormat( @@ -533,17 +513,14 @@ protected: "index %u is out of range since there are no active targets\n", target_idx); } - result.SetStatus(eReturnStatusFailed); } } else { result.AppendErrorWithFormat("invalid index string value '%s'\n", target_idx_arg); - result.SetStatus(eReturnStatusFailed); } } else { result.AppendError( "'target select' takes a single argument: a target index\n"); - result.SetStatus(eReturnStatusFailed); } return result.Succeeded(); } @@ -551,8 +528,6 @@ protected: #pragma mark CommandObjectTargetDelete -// "target delete" - class CommandObjectTargetDelete : public CommandObjectParsed { public: CommandObjectTargetDelete(CommandInterpreter &interpreter) @@ -595,7 +570,6 @@ protected: // Bail out if don't have any targets. if (num_targets == 0) { result.AppendError("no targets to delete"); - result.SetStatus(eReturnStatusFailed); return false; } @@ -604,7 +578,6 @@ protected: if (entry.ref().getAsInteger(0, target_idx)) { result.AppendErrorWithFormat("invalid target index '%s'\n", entry.c_str()); - result.SetStatus(eReturnStatusFailed); return false; } if (target_idx < num_targets) { @@ -623,14 +596,12 @@ protected: "target index %u is out of range, the only valid index is 0\n", target_idx); - result.SetStatus(eReturnStatusFailed); return false; } } else { target_sp = target_list.GetSelectedTarget(); if (!target_sp) { result.AppendErrorWithFormat("no target is currently selected\n"); - result.SetStatus(eReturnStatusFailed); return false; } delete_target_list.push_back(target_sp); @@ -697,8 +668,6 @@ protected: #pragma mark CommandObjectTargetVariable -// "target variable" - class CommandObjectTargetVariable : public CommandObjectParsed { static const uint32_t SHORT_OPTION_FILE = 0x66696c65; // 'file' static const uint32_t SHORT_OPTION_SHLB = 0x73686c62; // 'shlb' @@ -861,12 +830,10 @@ protected: size_t matches = 0; bool use_var_name = false; if (m_option_variable.use_regex) { - RegularExpression regex( - llvm::StringRef::withNullAsEmpty(arg.c_str())); + RegularExpression regex(arg.ref()); if (!regex.IsValid()) { result.GetErrorStream().Printf( "error: invalid regular expression: '%s'\n", arg.c_str()); - result.SetStatus(eReturnStatusFailed); return false; } use_var_name = true; @@ -881,9 +848,8 @@ protected: } if (matches == 0) { - result.GetErrorStream().Printf( - "error: can't find global variable '%s'\n", arg.c_str()); - result.SetStatus(eReturnStatusFailed); + result.AppendErrorWithFormat("can't find global variable '%s'", + arg.c_str()); return false; } else { for (uint32_t global_idx = 0; global_idx < matches; ++global_idx) { @@ -917,6 +883,7 @@ protected: CompileUnit *comp_unit = nullptr; if (frame) { SymbolContext sc = frame->GetSymbolContext(eSymbolContextCompUnit); + comp_unit = sc.comp_unit; if (sc.comp_unit) { const bool can_create = true; VariableListSP comp_unit_varlist_sp( @@ -943,7 +910,6 @@ protected: } else result.AppendError("'target variable' takes one or more global " "variable names as arguments\n"); - result.SetStatus(eReturnStatusFailed); } } else { SymbolContextList sc_list; @@ -1066,7 +1032,6 @@ protected: const size_t argc = command.GetArgumentCount(); if (argc & 1) { result.AppendError("add requires an even number of arguments\n"); - result.SetStatus(eReturnStatusFailed); } else { for (size_t i = 0; i < argc; i += 2) { const char *from = command.GetArgumentAtIndex(i); @@ -1090,7 +1055,6 @@ protected: result.AppendError(" can't be empty\n"); else result.AppendError(" can't be empty\n"); - result.SetStatus(eReturnStatusFailed); } } } @@ -1167,6 +1131,25 @@ public: ~CommandObjectTargetModulesSearchPathsInsert() override = default; + void + HandleArgumentCompletion(CompletionRequest &request, + OptionElementVector &opt_element_vector) override { + if (!m_exe_ctx.HasTargetScope() || request.GetCursorIndex() != 0) + return; + + Target *target = m_exe_ctx.GetTargetPtr(); + const PathMappingList &list = target->GetImageSearchPathList(); + const size_t num = list.GetSize(); + ConstString old_path, new_path; + for (size_t i = 0; i < num; ++i) { + if (!list.GetPathsAtIndex(i, old_path, new_path)) + break; + StreamString strm; + strm << old_path << " -> " << new_path; + request.TryCompleteCurrentArg(std::to_string(i), strm.GetString()); + } + } + protected: bool DoExecute(Args &command, CommandReturnObject &result) override { Target *target = &GetSelectedTarget(); @@ -1179,7 +1162,6 @@ protected: result.AppendErrorWithFormat( " parameter is not an integer: '%s'.\n", command.GetArgumentAtIndex(0)); - result.SetStatus(eReturnStatusFailed); return result.Succeeded(); } @@ -1201,13 +1183,11 @@ protected: result.AppendError(" can't be empty\n"); else result.AppendError(" can't be empty\n"); - result.SetStatus(eReturnStatusFailed); return false; } } } else { result.AppendError("insert requires at least three arguments\n"); - result.SetStatus(eReturnStatusFailed); return result.Succeeded(); } return result.Succeeded(); @@ -1232,7 +1212,6 @@ protected: Target *target = &GetSelectedTarget(); if (command.GetArgumentCount() != 0) { result.AppendError("list takes no arguments\n"); - result.SetStatus(eReturnStatusFailed); return result.Succeeded(); } @@ -1273,7 +1252,6 @@ protected: Target *target = &GetSelectedTarget(); if (command.GetArgumentCount() != 1) { result.AppendError("query requires one argument\n"); - result.SetStatus(eReturnStatusFailed); return result.Succeeded(); } @@ -1392,31 +1370,30 @@ static void DumpBasename(Stream &strm, const FileSpec *file_spec_ptr, } static size_t DumpModuleObjfileHeaders(Stream &strm, ModuleList &module_list) { - size_t num_dumped = 0; std::lock_guard guard(module_list.GetMutex()); const size_t num_modules = module_list.GetSize(); - if (num_modules > 0) { - strm.Printf("Dumping headers for %" PRIu64 " module(s).\n", - static_cast(num_modules)); - strm.IndentMore(); - for (size_t image_idx = 0; image_idx < num_modules; ++image_idx) { - Module *module = module_list.GetModulePointerAtIndexUnlocked(image_idx); - if (module) { - if (num_dumped++ > 0) { - strm.EOL(); - strm.EOL(); - } - ObjectFile *objfile = module->GetObjectFile(); - if (objfile) - objfile->Dump(&strm); - else { - strm.Format("No object file for module: {0:F}\n", - module->GetFileSpec()); - } + if (num_modules == 0) + return 0; + + size_t num_dumped = 0; + strm.Format("Dumping headers for {0} module(s).\n", num_modules); + strm.IndentMore(); + for (ModuleSP module_sp : module_list.ModulesNoLocking()) { + if (module_sp) { + if (num_dumped++ > 0) { + strm.EOL(); + strm.EOL(); + } + ObjectFile *objfile = module_sp->GetObjectFile(); + if (objfile) + objfile->Dump(&strm); + else { + strm.Format("No object file for module: {0:F}\n", + module_sp->GetFileSpec()); } } - strm.IndentLess(); } + strm.IndentLess(); return num_dumped; } @@ -1624,7 +1601,8 @@ static size_t LookupFunctionInModule(CommandInterpreter &interpreter, return 0; } -static size_t LookupTypeInModule(CommandInterpreter &interpreter, Stream &strm, +static size_t LookupTypeInModule(Target *target, + CommandInterpreter &interpreter, Stream &strm, Module *module, const char *name_cstr, bool name_is_regex) { TypeList type_list; @@ -1652,7 +1630,7 @@ static size_t LookupTypeInModule(CommandInterpreter &interpreter, Stream &strm, // Resolve the clang type so that any forward references to types // that haven't yet been parsed will get parsed. type_sp->GetFullCompilerType(); - type_sp->GetDescription(&strm, eDescriptionLevelFull, true); + type_sp->GetDescription(&strm, eDescriptionLevelFull, true, target); // Print all typedef chains TypeSP typedef_type_sp(type_sp); TypeSP typedefed_type_sp(typedef_type_sp->GetTypedefType()); @@ -1661,7 +1639,8 @@ static size_t LookupTypeInModule(CommandInterpreter &interpreter, Stream &strm, strm.Printf(" typedef '%s': ", typedef_type_sp->GetName().GetCString()); typedefed_type_sp->GetFullCompilerType(); - typedefed_type_sp->GetDescription(&strm, eDescriptionLevelFull, true); + typedefed_type_sp->GetDescription(&strm, eDescriptionLevelFull, true, + target); typedef_type_sp = typedefed_type_sp; typedefed_type_sp = typedef_type_sp->GetTypedefType(); } @@ -1671,9 +1650,9 @@ static size_t LookupTypeInModule(CommandInterpreter &interpreter, Stream &strm, return type_list.GetSize(); } -static size_t LookupTypeHere(CommandInterpreter &interpreter, Stream &strm, - Module &module, const char *name_cstr, - bool name_is_regex) { +static size_t LookupTypeHere(Target *target, CommandInterpreter &interpreter, + Stream &strm, Module &module, + const char *name_cstr, bool name_is_regex) { TypeList type_list; const uint32_t max_num_matches = UINT32_MAX; bool name_is_fully_qualified = false; @@ -1696,8 +1675,8 @@ static size_t LookupTypeHere(CommandInterpreter &interpreter, Stream &strm, // Resolve the clang type so that any forward references to types that // haven't yet been parsed will get parsed. type_sp->GetFullCompilerType(); - type_sp->GetDescription(&strm, eDescriptionLevelFull, true); - // Print all typedef chains + type_sp->GetDescription(&strm, eDescriptionLevelFull, true, target); + // Print all typedef chains. TypeSP typedef_type_sp(type_sp); TypeSP typedefed_type_sp(typedef_type_sp->GetTypedefType()); while (typedefed_type_sp) { @@ -1705,7 +1684,8 @@ static size_t LookupTypeHere(CommandInterpreter &interpreter, Stream &strm, strm.Printf(" typedef '%s': ", typedef_type_sp->GetName().GetCString()); typedefed_type_sp->GetFullCompilerType(); - typedefed_type_sp->GetDescription(&strm, eDescriptionLevelFull, true); + typedefed_type_sp->GetDescription(&strm, eDescriptionLevelFull, true, + target); typedef_type_sp = typedefed_type_sp; typedefed_type_sp = typedef_type_sp->GetTypedefType(); } @@ -1891,7 +1871,6 @@ protected: target->GetImages()); if (num_dumped == 0) { result.AppendError("the target has no associated executable images"); - result.SetStatus(eReturnStatusFailed); } } else { // Find the modules that match the basename or full path. @@ -1916,7 +1895,6 @@ protected: result.SetStatus(eReturnStatusSuccessFinishResult); } else { result.AppendError("no matching executable images found"); - result.SetStatus(eReturnStatusFailed); } return result.Succeeded(); } @@ -1961,7 +1939,7 @@ public: class CommandOptions : public Options { public: - CommandOptions() : Options(), m_sort_order(eSortOrderNone) {} + CommandOptions() : Options() {} ~CommandOptions() override = default; @@ -1997,7 +1975,7 @@ public: return llvm::makeArrayRef(g_target_modules_dump_symtab_options); } - SortOrder m_sort_order; + SortOrder m_sort_order = eSortOrderNone; OptionValueBoolean m_prefer_mangled = {false, false}; }; @@ -2015,14 +1993,13 @@ protected: if (command.GetArgumentCount() == 0) { // Dump all sections for all modules images - std::lock_guard guard( - target->GetImages().GetMutex()); - const size_t num_modules = target->GetImages().GetSize(); + const ModuleList &module_list = target->GetImages(); + std::lock_guard guard(module_list.GetMutex()); + const size_t num_modules = module_list.GetSize(); if (num_modules > 0) { - result.GetOutputStream().Printf("Dumping symbol table for %" PRIu64 - " modules.\n", - (uint64_t)num_modules); - for (size_t image_idx = 0; image_idx < num_modules; ++image_idx) { + result.GetOutputStream().Format( + "Dumping symbol table for {0} modules.\n", num_modules); + for (ModuleSP module_sp : module_list.ModulesNoLocking()) { if (num_dumped > 0) { result.GetOutputStream().EOL(); result.GetOutputStream().EOL(); @@ -2030,14 +2007,12 @@ protected: if (m_interpreter.WasInterrupted()) break; num_dumped++; - DumpModuleSymtab( - m_interpreter, result.GetOutputStream(), - target->GetImages().GetModulePointerAtIndexUnlocked(image_idx), - m_options.m_sort_order, name_preference); + DumpModuleSymtab(m_interpreter, result.GetOutputStream(), + module_sp.get(), m_options.m_sort_order, + name_preference); } } else { result.AppendError("the target has no associated executable images"); - result.SetStatus(eReturnStatusFailed); return false; } } else { @@ -2050,9 +2025,8 @@ protected: const size_t num_matches = FindModulesByName(target, arg_cstr, module_list, true); if (num_matches > 0) { - for (size_t i = 0; i < num_matches; ++i) { - Module *module = module_list.GetModulePointerAtIndex(i); - if (module) { + for (ModuleSP module_sp : module_list.Modules()) { + if (module_sp) { if (num_dumped > 0) { result.GetOutputStream().EOL(); result.GetOutputStream().EOL(); @@ -2060,8 +2034,9 @@ protected: if (m_interpreter.WasInterrupted()) break; num_dumped++; - DumpModuleSymtab(m_interpreter, result.GetOutputStream(), module, - m_options.m_sort_order, name_preference); + DumpModuleSymtab(m_interpreter, result.GetOutputStream(), + module_sp.get(), m_options.m_sort_order, + name_preference); } } } else @@ -2074,7 +2049,6 @@ protected: result.SetStatus(eReturnStatusSuccessFinishResult); else { result.AppendError("no matching executable images found"); - result.SetStatus(eReturnStatusFailed); } return result.Succeeded(); } @@ -2110,23 +2084,21 @@ protected: if (command.GetArgumentCount() == 0) { // Dump all sections for all modules images const size_t num_modules = target->GetImages().GetSize(); - if (num_modules > 0) { - result.GetOutputStream().Printf("Dumping sections for %" PRIu64 - " modules.\n", - (uint64_t)num_modules); - for (size_t image_idx = 0; image_idx < num_modules; ++image_idx) { - if (m_interpreter.WasInterrupted()) - break; - num_dumped++; - DumpModuleSections( - m_interpreter, result.GetOutputStream(), - target->GetImages().GetModulePointerAtIndex(image_idx)); - } - } else { + if (num_modules == 0) { result.AppendError("the target has no associated executable images"); - result.SetStatus(eReturnStatusFailed); return false; } + + result.GetOutputStream().Format("Dumping sections for {0} modules.\n", + num_modules); + for (size_t image_idx = 0; image_idx < num_modules; ++image_idx) { + if (m_interpreter.WasInterrupted()) + break; + num_dumped++; + DumpModuleSections( + m_interpreter, result.GetOutputStream(), + target->GetImages().GetModulePointerAtIndex(image_idx)); + } } else { // Dump specified images (by basename or fullpath) const char *arg_cstr; @@ -2162,7 +2134,6 @@ protected: result.SetStatus(eReturnStatusSuccessFinishResult); else { result.AppendError("no matching executable images found"); - result.SetStatus(eReturnStatusFailed); } return result.Succeeded(); } @@ -2188,23 +2159,21 @@ protected: bool DoExecute(Args &command, CommandReturnObject &result) override { Target *target = &GetSelectedTarget(); - const size_t num_modules = target->GetImages().GetSize(); + const ModuleList &module_list = target->GetImages(); + const size_t num_modules = module_list.GetSize(); if (num_modules == 0) { result.AppendError("the target has no associated executable images"); - result.SetStatus(eReturnStatusFailed); return false; } if (command.GetArgumentCount() == 0) { // Dump all ASTs for all modules images - result.GetOutputStream().Printf("Dumping clang ast for %" PRIu64 - " modules.\n", - (uint64_t)num_modules); - for (size_t image_idx = 0; image_idx < num_modules; ++image_idx) { + result.GetOutputStream().Format("Dumping clang ast for {0} modules.\n", + num_modules); + for (ModuleSP module_sp : module_list.ModulesNoLocking()) { if (m_interpreter.WasInterrupted()) break; - Module *m = target->GetImages().GetModulePointerAtIndex(image_idx); - if (SymbolFile *sf = m->GetSymbolFile()) + if (SymbolFile *sf = module_sp->GetSymbolFile()) sf->DumpClangAST(result.GetOutputStream()); } result.SetStatus(eReturnStatusSuccessFinishResult); @@ -2269,23 +2238,18 @@ protected: const ModuleList &target_modules = target->GetImages(); std::lock_guard guard(target_modules.GetMutex()); const size_t num_modules = target_modules.GetSize(); - if (num_modules > 0) { - result.GetOutputStream().Printf("Dumping debug symbols for %" PRIu64 - " modules.\n", - (uint64_t)num_modules); - for (uint32_t image_idx = 0; image_idx < num_modules; ++image_idx) { - if (m_interpreter.WasInterrupted()) - break; - if (DumpModuleSymbolFile( - result.GetOutputStream(), - target_modules.GetModulePointerAtIndexUnlocked(image_idx))) - num_dumped++; - } - } else { + if (num_modules == 0) { result.AppendError("the target has no associated executable images"); - result.SetStatus(eReturnStatusFailed); return false; } + result.GetOutputStream().Format( + "Dumping debug symbols for {0} modules.\n", num_modules); + for (ModuleSP module_sp : target_modules.ModulesNoLocking()) { + if (m_interpreter.WasInterrupted()) + break; + if (DumpModuleSymbolFile(result.GetOutputStream(), module_sp.get())) + num_dumped++; + } } else { // Dump specified images (by basename or fullpath) const char *arg_cstr; @@ -2315,7 +2279,6 @@ protected: result.SetStatus(eReturnStatusSuccessFinishResult); else { result.AppendError("no matching executable images found"); - result.SetStatus(eReturnStatusFailed); } return result.Succeeded(); } @@ -2351,7 +2314,6 @@ protected: if (command.GetArgumentCount() == 0) { result.AppendError("file option must be specified."); - result.SetStatus(eReturnStatusFailed); return result.Succeeded(); } else { // Dump specified images (by basename or fullpath) @@ -2363,15 +2325,13 @@ protected: const ModuleList &target_modules = target->GetImages(); std::lock_guard guard(target_modules.GetMutex()); - const size_t num_modules = target_modules.GetSize(); - if (num_modules > 0) { + if (target_modules.GetSize() > 0) { uint32_t num_dumped = 0; - for (uint32_t i = 0; i < num_modules; ++i) { + for (ModuleSP module_sp : target_modules.ModulesNoLocking()) { if (m_interpreter.WasInterrupted()) break; if (DumpCompileUnitLineTable( - m_interpreter, result.GetOutputStream(), - target_modules.GetModulePointerAtIndexUnlocked(i), + m_interpreter, result.GetOutputStream(), module_sp.get(), file_spec, m_options.m_verbose ? eDescriptionLevelFull : eDescriptionLevelBrief)) @@ -2390,7 +2350,6 @@ protected: result.SetStatus(eReturnStatusSuccessFinishResult); else { result.AppendError("no source filenames matched any command arguments"); - result.SetStatus(eReturnStatusFailed); } return result.Succeeded(); } @@ -2536,7 +2495,6 @@ protected: "or symbol file with UUID %s", strm.GetData()); } - result.SetStatus(eReturnStatusFailed); return false; } } else { @@ -2545,13 +2503,11 @@ protected: result.AppendErrorWithFormat( "Unable to locate the executable or symbol file with UUID %s", strm.GetData()); - result.SetStatus(eReturnStatusFailed); return false; } } else { result.AppendError( "one or more executable image paths must be specified"); - result.SetStatus(eReturnStatusFailed); return false; } } else { @@ -2580,7 +2536,6 @@ protected: else result.AppendErrorWithFormat("unsupported module: %s", entry.c_str()); - result.SetStatus(eReturnStatusFailed); return false; } else { flush = true; @@ -2588,7 +2543,6 @@ protected: result.SetStatus(eReturnStatusSuccessFinishResult); } else { std::string resolved_path = file_spec.GetPath(); - result.SetStatus(eReturnStatusFailed); if (resolved_path != entry.ref()) { result.AppendErrorWithFormat( "invalid module path '%s' with resolved path '%s'\n", @@ -2686,12 +2640,10 @@ protected: search_using_module_spec = false; result.AppendErrorWithFormat( "more than 1 module matched by name '%s'\n", arg_cstr); - result.SetStatus(eReturnStatusFailed); } else { search_using_module_spec = false; result.AppendErrorWithFormat("no object file for module '%s'\n", arg_cstr); - result.SetStatus(eReturnStatusFailed); } } @@ -2725,7 +2677,6 @@ protected: } else { result.AppendError("one or more section name + load " "address pair must be specified"); - result.SetStatus(eReturnStatusFailed); return false; } } else { @@ -2733,7 +2684,6 @@ protected: result.AppendError("The \"--slide \" option can't " "be used in conjunction with setting " "section load addresses.\n"); - result.SetStatus(eReturnStatusFailed); return false; } @@ -2752,7 +2702,6 @@ protected: "thread specific sections are not yet " "supported (section '%s')\n", sect_name); - result.SetStatus(eReturnStatusFailed); break; } else { if (target->GetSectionLoadList() @@ -2767,13 +2716,11 @@ protected: "matches the section " "name '%s'\n", sect_name); - result.SetStatus(eReturnStatusFailed); break; } } else { result.AppendErrorWithFormat( "invalid load address string '%s'\n", load_addr_cstr); - result.SetStatus(eReturnStatusFailed); break; } } else { @@ -2783,7 +2730,6 @@ protected: else result.AppendError("one or more section name + load " "address pair must be specified.\n"); - result.SetStatus(eReturnStatusFailed); break; } } @@ -2826,7 +2772,6 @@ protected: result.AppendErrorWithFormat("failed to set PC value to " "0x%" PRIx64 "\n", file_entry_addr); - result.SetStatus(eReturnStatusFailed); } } } @@ -2834,13 +2779,11 @@ protected: module->GetFileSpec().GetPath(path, sizeof(path)); result.AppendErrorWithFormat("no sections in object file '%s'\n", path); - result.SetStatus(eReturnStatusFailed); } } else { module->GetFileSpec().GetPath(path, sizeof(path)); result.AppendErrorWithFormat("no object file for module '%s'\n", path); - result.SetStatus(eReturnStatusFailed); } } else { FileSpec *module_spec_file = module_spec.GetFileSpecPtr(); @@ -2849,7 +2792,6 @@ protected: result.AppendErrorWithFormat("invalid module '%s'.\n", path); } else result.AppendError("no module spec"); - result.SetStatus(eReturnStatusFailed); } } else { std::string uuid_str; @@ -2877,12 +2819,10 @@ protected: path[0] ? " file=" : "", path, !uuid_str.empty() ? " uuid=" : "", uuid_str.c_str()); } - result.SetStatus(eReturnStatusFailed); } } else { result.AppendError("either the \"--file \" or the \"--uuid " "\" option must be specified.\n"); - result.SetStatus(eReturnStatusFailed); return false; } return result.Succeeded(); @@ -2904,9 +2844,7 @@ class CommandObjectTargetModulesList : public CommandObjectParsed { public: class CommandOptions : public Options { public: - CommandOptions() - : Options(), m_format_array(), m_use_global_module_list(false), - m_module_addr(LLDB_INVALID_ADDRESS) {} + CommandOptions() : Options(), m_format_array() {} ~CommandOptions() override = default; @@ -2941,8 +2879,8 @@ public: // Instance variables to hold the values for command options. typedef std::vector> FormatWidthCollection; FormatWidthCollection m_format_array; - bool m_use_global_module_list; - lldb::addr_t m_module_addr; + bool m_use_global_module_list = false; + lldb::addr_t m_module_addr = LLDB_INVALID_ADDRESS; }; CommandObjectTargetModulesList(CommandInterpreter &interpreter) @@ -2967,7 +2905,6 @@ protected: if (target == nullptr && !use_global_module_list) { result.AppendError("invalid target, create a debug target using the " "'target create' command"); - result.SetStatus(eReturnStatusFailed); return false; } else { if (target) { @@ -2991,18 +2928,15 @@ protected: result.AppendErrorWithFormat( "Couldn't find module matching address: 0x%" PRIx64 ".", m_options.m_module_addr); - result.SetStatus(eReturnStatusFailed); } } else { result.AppendErrorWithFormat( "Couldn't find module containing address: 0x%" PRIx64 ".", m_options.m_module_addr); - result.SetStatus(eReturnStatusFailed); } } else { result.AppendError( "Can only look up modules by address with a valid target."); - result.SetStatus(eReturnStatusFailed); } return result.Succeeded(); } @@ -3034,7 +2968,6 @@ protected: if (argc == 1) { result.AppendErrorWithFormat("no modules found that match '%s'", arg.c_str()); - result.SetStatus(eReturnStatusFailed); return false; } } @@ -3081,7 +3014,6 @@ protected: result.AppendError( "the target has no associated executable images"); } - result.SetStatus(eReturnStatusFailed); return false; } } @@ -3255,9 +3187,7 @@ public: class CommandOptions : public Options { public: - CommandOptions() - : Options(), m_type(eLookupTypeInvalid), m_str(), - m_addr(LLDB_INVALID_ADDRESS) {} + CommandOptions() : Options(), m_str() {} ~CommandOptions() override = default; @@ -3303,9 +3233,10 @@ public: // Instance variables to hold the values for command options. - int m_type; // Should be a eLookupTypeXXX enum after parsing options + int m_type = eLookupTypeInvalid; // Should be a eLookupTypeXXX enum after + // parsing options std::string m_str; // Holds name lookup - lldb::addr_t m_addr; // Holds the address to lookup + lldb::addr_t m_addr = LLDB_INVALID_ADDRESS; // Holds the address to lookup }; CommandObjectTargetModulesShowUnwind(CommandInterpreter &interpreter) @@ -3331,21 +3262,18 @@ protected: if (process == nullptr) { result.AppendError( "You must have a process running to use this command."); - result.SetStatus(eReturnStatusFailed); return false; } ThreadList threads(process->GetThreadList()); if (threads.GetSize() == 0) { result.AppendError("The process must be paused to use this command."); - result.SetStatus(eReturnStatusFailed); return false; } ThreadSP thread(threads.GetThreadAtIndex(0)); if (!thread) { result.AppendError("The process must be paused to use this command."); - result.SetStatus(eReturnStatusFailed); return false; } @@ -3370,7 +3298,6 @@ protected: } else { result.AppendError( "address-expression or function name option must be specified."); - result.SetStatus(eReturnStatusFailed); return false; } @@ -3378,7 +3305,6 @@ protected: if (num_matches == 0) { result.AppendErrorWithFormat("no unwind data found that matches '%s'.", m_options.m_str.c_str()); - result.SetStatus(eReturnStatusFailed); return false; } @@ -3409,10 +3335,35 @@ protected: continue; result.GetOutputStream().Printf( - "UNWIND PLANS for %s`%s (start addr 0x%" PRIx64 ")\n\n", + "UNWIND PLANS for %s`%s (start addr 0x%" PRIx64 ")\n", sc.module_sp->GetPlatformFileSpec().GetFilename().AsCString(), funcname.AsCString(), start_addr); + Args args; + target->GetUserSpecifiedTrapHandlerNames(args); + size_t count = args.GetArgumentCount(); + for (size_t i = 0; i < count; i++) { + const char *trap_func_name = args.GetArgumentAtIndex(i); + if (strcmp(funcname.GetCString(), trap_func_name) == 0) + result.GetOutputStream().Printf( + "This function is " + "treated as a trap handler function via user setting.\n"); + } + PlatformSP platform_sp(target->GetPlatform()); + if (platform_sp) { + const std::vector trap_handler_names( + platform_sp->GetTrapHandlerSymbolNames()); + for (ConstString trap_name : trap_handler_names) { + if (trap_name == funcname) { + result.GetOutputStream().Printf( + "This function's " + "name is listed by the platform as a trap handler.\n"); + } + } + } + + result.GetOutputStream().Printf("\n"); + UnwindPlanSP non_callsite_unwind_plan = func_unwinders_sp->GetUnwindPlanAtNonCallSite(*target, *thread); if (non_callsite_unwind_plan) { @@ -3745,9 +3696,9 @@ public: return false; case eLookupTypeType: if (!m_options.m_str.empty()) { - if (LookupTypeHere(m_interpreter, result.GetOutputStream(), - *sym_ctx.module_sp, m_options.m_str.c_str(), - m_options.m_use_regex)) { + if (LookupTypeHere(&GetSelectedTarget(), m_interpreter, + result.GetOutputStream(), *sym_ctx.module_sp, + m_options.m_str.c_str(), m_options.m_use_regex)) { result.SetStatus(eReturnStatusSuccessFinishResult); return true; } @@ -3817,9 +3768,9 @@ public: case eLookupTypeType: if (!m_options.m_str.empty()) { - if (LookupTypeInModule(m_interpreter, result.GetOutputStream(), module, - m_options.m_str.c_str(), - m_options.m_use_regex)) { + if (LookupTypeInModule( + &GetSelectedTarget(), m_interpreter, result.GetOutputStream(), + module, m_options.m_str.c_str(), m_options.m_use_regex)) { result.SetStatus(eReturnStatusSuccessFinishResult); return true; } @@ -3868,25 +3819,19 @@ protected: const ModuleList &target_modules = target->GetImages(); std::lock_guard guard(target_modules.GetMutex()); - const size_t num_modules = target_modules.GetSize(); - if (num_modules > 0) { - for (i = 0; i < num_modules && !syntax_error; ++i) { - Module *module_pointer = - target_modules.GetModulePointerAtIndexUnlocked(i); - - if (module_pointer != current_module.get() && - LookupInModule(m_interpreter, - target_modules.GetModulePointerAtIndexUnlocked(i), - result, syntax_error)) { - result.GetOutputStream().EOL(); - num_successful_lookups++; - } - } - } else { + if (target_modules.GetSize() == 0) { result.AppendError("the target has no associated executable images"); - result.SetStatus(eReturnStatusFailed); return false; } + + for (ModuleSP module_sp : target_modules.ModulesNoLocking()) { + if (module_sp != current_module && + LookupInModule(m_interpreter, module_sp.get(), result, + syntax_error)) { + result.GetOutputStream().EOL(); + num_successful_lookups++; + } + } } else { // Dump specified images (by basename or fullpath) const char *arg_cstr; @@ -4045,7 +3990,6 @@ protected: if (!symbol_fspec) { result.AppendError( "one or more executable image paths must be specified"); - result.SetStatus(eReturnStatusFailed); return false; } @@ -4127,7 +4071,6 @@ protected: "use the --uuid option to resolve the " "ambiguity.\n", symfile_path); - result.SetStatus(eReturnStatusFailed); return false; } @@ -4194,7 +4137,6 @@ protected: !llvm::sys::fs::is_regular_file(symbol_fspec.GetPath()) ? "\n please specify the full path to the symbol file" : ""); - result.SetStatus(eReturnStatusFailed); return false; } @@ -4332,7 +4274,6 @@ protected: module_spec.GetSymbolFileSpec() = symfile_spec; } - ArchSpec arch; bool symfile_exists = FileSystem::Instance().Exists(module_spec.GetSymbolFileSpec()); @@ -4405,13 +4346,9 @@ private: class CommandObjectTargetStopHookAdd : public CommandObjectParsed, public IOHandlerDelegateMultiline { public: - class CommandOptions : public Options { + class CommandOptions : public OptionGroup { public: - CommandOptions() - : Options(), m_line_start(0), m_line_end(UINT_MAX), - m_func_name_type_mask(eFunctionNameTypeAuto), - m_sym_ctx_specified(false), m_thread_specified(false), - m_use_one_liner(false), m_one_liner() {} + CommandOptions() : OptionGroup(), m_line_end(UINT_MAX), m_one_liner() {} ~CommandOptions() override = default; @@ -4422,7 +4359,8 @@ public: Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, ExecutionContext *execution_context) override { Status error; - const int short_option = m_getopt_table[option_idx].val; + const int short_option = + g_target_stop_hook_add_options[option_idx].short_option; switch (short_option) { case 'c': @@ -4537,35 +4475,91 @@ public: std::string m_class_name; std::string m_function_name; - uint32_t m_line_start; + uint32_t m_line_start = 0; uint32_t m_line_end; std::string m_file_name; std::string m_module_name; - uint32_t m_func_name_type_mask; // A pick from lldb::FunctionNameType. + uint32_t m_func_name_type_mask = + eFunctionNameTypeAuto; // A pick from lldb::FunctionNameType. lldb::tid_t m_thread_id; uint32_t m_thread_index; std::string m_thread_name; std::string m_queue_name; - bool m_sym_ctx_specified; + bool m_sym_ctx_specified = false; bool m_no_inlines; - bool m_thread_specified; + bool m_thread_specified = false; // Instance variables to hold the values for one_liner options. - bool m_use_one_liner; + bool m_use_one_liner = false; std::vector m_one_liner; + bool m_auto_continue; }; CommandObjectTargetStopHookAdd(CommandInterpreter &interpreter) : CommandObjectParsed(interpreter, "target stop-hook add", - "Add a hook to be executed when the target stops.", + "Add a hook to be executed when the target stops." + "The hook can either be a list of commands or an " + "appropriately defined Python class. You can also " + "add filters so the hook only runs a certain stop " + "points.", "target stop-hook add"), IOHandlerDelegateMultiline("DONE", IOHandlerDelegate::Completion::LLDBCommand), - m_options() {} + m_options(), m_python_class_options("scripted stop-hook", true, 'P') { + SetHelpLong( + R"( +Command Based stop-hooks: +------------------------- + Stop hooks can run a list of lldb commands by providing one or more + --one-line-command options. The commands will get run in the order they are + added. Or you can provide no commands, in which case you will enter a + command editor where you can enter the commands to be run. + +Python Based Stop Hooks: +------------------------ + Stop hooks can be implemented with a suitably defined Python class, whose name + is passed in the --python-class option. + + When the stop hook is added, the class is initialized by calling: + + def __init__(self, target, extra_args, internal_dict): + + target: The target that the stop hook is being added to. + extra_args: An SBStructuredData Dictionary filled with the -key -value + option pairs passed to the command. + dict: An implementation detail provided by lldb. + + Then when the stop-hook triggers, lldb will run the 'handle_stop' method. + The method has the signature: + + def handle_stop(self, exe_ctx, stream): + + exe_ctx: An SBExecutionContext for the thread that has stopped. + stream: An SBStream, anything written to this stream will be printed in the + the stop message when the process stops. + + Return Value: The method returns "should_stop". If should_stop is false + from all the stop hook executions on threads that stopped + with a reason, then the process will continue. Note that this + will happen only after all the stop hooks are run. + +Filter Options: +--------------- + Stop hooks can be set to always run, or to only run when the stopped thread + matches the filter options passed on the command line. The available filter + options include a shared library or a thread or queue specification, + a line range in a source file, a function name or a class name. + )"); + m_all_options.Append(&m_python_class_options, + LLDB_OPT_SET_1 | LLDB_OPT_SET_2, + LLDB_OPT_SET_FROM_TO(4, 6)); + m_all_options.Append(&m_options); + m_all_options.Finalize(); + } ~CommandObjectTargetStopHookAdd() override = default; - Options *GetOptions() override { return &m_options; } + Options *GetOptions() override { return &m_all_options; } protected: void IOHandlerActivated(IOHandler &io_handler, bool interactive) override { @@ -4589,10 +4583,15 @@ protected: error_sp->Flush(); } Target *target = GetDebugger().GetSelectedTarget().get(); - if (target) - target->RemoveStopHookByID(m_stop_hook_sp->GetID()); + if (target) { + target->UndoCreateStopHook(m_stop_hook_sp->GetID()); + } } else { - m_stop_hook_sp->GetCommandPointer()->SplitIntoLines(line); + // The IOHandler editor is only for command lines stop hooks: + Target::StopHookCommandLine *hook_ptr = + static_cast(m_stop_hook_sp.get()); + + hook_ptr->SetActionFromString(line); StreamFileSP output_sp(io_handler.GetOutputStreamFileSP()); if (output_sp) { output_sp->Printf("Stop hook #%" PRIu64 " added.\n", @@ -4609,7 +4608,10 @@ protected: m_stop_hook_sp.reset(); Target &target = GetSelectedOrDummyTarget(); - Target::StopHookSP new_hook_sp = target.CreateStopHook(); + Target::StopHookSP new_hook_sp = + target.CreateStopHook(m_python_class_options.GetName().empty() ? + Target::StopHook::StopHookKind::CommandBased + : Target::StopHook::StopHookKind::ScriptBased); // First step, make the specifier. std::unique_ptr specifier_up; @@ -4678,11 +4680,29 @@ protected: new_hook_sp->SetAutoContinue(m_options.m_auto_continue); if (m_options.m_use_one_liner) { - // Use one-liners. - for (auto cmd : m_options.m_one_liner) - new_hook_sp->GetCommandPointer()->AppendString(cmd.c_str()); + // This is a command line stop hook: + Target::StopHookCommandLine *hook_ptr = + static_cast(new_hook_sp.get()); + hook_ptr->SetActionFromStrings(m_options.m_one_liner); result.AppendMessageWithFormat("Stop hook #%" PRIu64 " added.\n", new_hook_sp->GetID()); + } else if (!m_python_class_options.GetName().empty()) { + // This is a scripted stop hook: + Target::StopHookScripted *hook_ptr = + static_cast(new_hook_sp.get()); + Status error = hook_ptr->SetScriptCallback( + m_python_class_options.GetName(), + m_python_class_options.GetStructuredData()); + if (error.Success()) + result.AppendMessageWithFormat("Stop hook #%" PRIu64 " added.\n", + new_hook_sp->GetID()); + else { + // FIXME: Set the stop hook ID counter back. + result.AppendErrorWithFormat("Couldn't add stop hook: %s", + error.AsCString()); + target.UndoCreateStopHook(new_hook_sp->GetID()); + return false; + } } else { m_stop_hook_sp = new_hook_sp; m_interpreter.GetLLDBCommandsFromIOHandler("> ", // Prompt @@ -4695,6 +4715,9 @@ protected: private: CommandOptions m_options; + OptionGroupPythonClassWithDict m_python_class_options; + OptionGroupOptions m_all_options; + Target::StopHookSP m_stop_hook_sp; }; @@ -4711,6 +4734,14 @@ public: ~CommandObjectTargetStopHookDelete() override = default; + void + HandleArgumentCompletion(CompletionRequest &request, + OptionElementVector &opt_element_vector) override { + CommandCompletions::InvokeCommonCompletionCallbacks( + GetCommandInterpreter(), CommandCompletions::eStopHookIDCompletion, + request, nullptr); + } + protected: bool DoExecute(Args &command, CommandReturnObject &result) override { Target &target = GetSelectedOrDummyTarget(); @@ -4729,13 +4760,11 @@ protected: if (!llvm::to_integer(command.GetArgumentAtIndex(i), user_id)) { result.AppendErrorWithFormat("invalid stop hook id: \"%s\".\n", command.GetArgumentAtIndex(i)); - result.SetStatus(eReturnStatusFailed); return false; } if (!target.RemoveStopHookByID(user_id)) { result.AppendErrorWithFormat("unknown stop hook id: \"%s\".\n", command.GetArgumentAtIndex(i)); - result.SetStatus(eReturnStatusFailed); return false; } } @@ -4759,6 +4788,16 @@ public: ~CommandObjectTargetStopHookEnableDisable() override = default; + void + HandleArgumentCompletion(CompletionRequest &request, + OptionElementVector &opt_element_vector) override { + if (request.GetCursorIndex()) + return; + CommandCompletions::InvokeCommonCompletionCallbacks( + GetCommandInterpreter(), CommandCompletions::eStopHookIDCompletion, + request, nullptr); + } + protected: bool DoExecute(Args &command, CommandReturnObject &result) override { Target &target = GetSelectedOrDummyTarget(); @@ -4774,14 +4813,12 @@ protected: if (!llvm::to_integer(command.GetArgumentAtIndex(i), user_id)) { result.AppendErrorWithFormat("invalid stop hook id: \"%s\".\n", command.GetArgumentAtIndex(i)); - result.SetStatus(eReturnStatusFailed); return false; } success = target.SetStopHookActiveStateByID(user_id, m_enable); if (!success) { result.AppendErrorWithFormat("unknown stop hook id: \"%s\".\n", command.GetArgumentAtIndex(i)); - result.SetStatus(eReturnStatusFailed); return false; } } diff --git a/gnu/llvm/lldb/source/Commands/CommandObjectThread.cpp b/gnu/llvm/lldb/source/Commands/CommandObjectThread.cpp index f0ad1798fec..7247601b292 100644 --- a/gnu/llvm/lldb/source/Commands/CommandObjectThread.cpp +++ b/gnu/llvm/lldb/source/Commands/CommandObjectThread.cpp @@ -8,6 +8,12 @@ #include "CommandObjectThread.h" +#include +#include + +#include "CommandObjectThreadUtil.h" +#include "CommandObjectTrace.h" +#include "lldb/Core/PluginManager.h" #include "lldb/Core/ValueObject.h" #include "lldb/Host/OptionParser.h" #include "lldb/Interpreter/CommandInterpreter.h" @@ -26,207 +32,13 @@ #include "lldb/Target/Thread.h" #include "lldb/Target/ThreadPlan.h" #include "lldb/Target/ThreadPlanStepInRange.h" +#include "lldb/Target/Trace.h" +#include "lldb/Target/TraceInstructionDumper.h" #include "lldb/Utility/State.h" using namespace lldb; using namespace lldb_private; -// CommandObjectIterateOverThreads - -class CommandObjectIterateOverThreads : public CommandObjectParsed { - - class UniqueStack { - - public: - UniqueStack(std::stack stack_frames, uint32_t thread_index_id) - : m_stack_frames(stack_frames) { - m_thread_index_ids.push_back(thread_index_id); - } - - void AddThread(uint32_t thread_index_id) const { - m_thread_index_ids.push_back(thread_index_id); - } - - const std::vector &GetUniqueThreadIndexIDs() const { - return m_thread_index_ids; - } - - lldb::tid_t GetRepresentativeThread() const { - return m_thread_index_ids.front(); - } - - friend bool inline operator<(const UniqueStack &lhs, - const UniqueStack &rhs) { - return lhs.m_stack_frames < rhs.m_stack_frames; - } - - protected: - // Mark the thread index as mutable, as we don't care about it from a const - // perspective, we only care about m_stack_frames so we keep our std::set - // sorted. - mutable std::vector m_thread_index_ids; - std::stack m_stack_frames; - }; - -public: - CommandObjectIterateOverThreads(CommandInterpreter &interpreter, - const char *name, const char *help, - const char *syntax, uint32_t flags) - : CommandObjectParsed(interpreter, name, help, syntax, flags) {} - - ~CommandObjectIterateOverThreads() override = default; - - bool DoExecute(Args &command, CommandReturnObject &result) override { - result.SetStatus(m_success_return); - - bool all_threads = false; - if (command.GetArgumentCount() == 0) { - Thread *thread = m_exe_ctx.GetThreadPtr(); - if (!thread || !HandleOneThread(thread->GetID(), result)) - return false; - return result.Succeeded(); - } else if (command.GetArgumentCount() == 1) { - all_threads = ::strcmp(command.GetArgumentAtIndex(0), "all") == 0; - m_unique_stacks = ::strcmp(command.GetArgumentAtIndex(0), "unique") == 0; - } - - // Use tids instead of ThreadSPs to prevent deadlocking problems which - // result from JIT-ing code while iterating over the (locked) ThreadSP - // list. - std::vector tids; - - if (all_threads || m_unique_stacks) { - Process *process = m_exe_ctx.GetProcessPtr(); - - for (ThreadSP thread_sp : process->Threads()) - tids.push_back(thread_sp->GetID()); - } else { - const size_t num_args = command.GetArgumentCount(); - Process *process = m_exe_ctx.GetProcessPtr(); - - std::lock_guard guard( - process->GetThreadList().GetMutex()); - - for (size_t i = 0; i < num_args; i++) { - uint32_t thread_idx; - if (!llvm::to_integer(command.GetArgumentAtIndex(i), thread_idx)) { - result.AppendErrorWithFormat("invalid thread specification: \"%s\"\n", - command.GetArgumentAtIndex(i)); - result.SetStatus(eReturnStatusFailed); - return false; - } - - ThreadSP thread = - process->GetThreadList().FindThreadByIndexID(thread_idx); - - if (!thread) { - result.AppendErrorWithFormat("no thread with index: \"%s\"\n", - command.GetArgumentAtIndex(i)); - result.SetStatus(eReturnStatusFailed); - return false; - } - - tids.push_back(thread->GetID()); - } - } - - if (m_unique_stacks) { - // Iterate over threads, finding unique stack buckets. - std::set unique_stacks; - for (const lldb::tid_t &tid : tids) { - if (!BucketThread(tid, unique_stacks, result)) { - return false; - } - } - - // Write the thread id's and unique call stacks to the output stream - Stream &strm = result.GetOutputStream(); - Process *process = m_exe_ctx.GetProcessPtr(); - for (const UniqueStack &stack : unique_stacks) { - // List the common thread ID's - const std::vector &thread_index_ids = - stack.GetUniqueThreadIndexIDs(); - strm.Format("{0} thread(s) ", thread_index_ids.size()); - for (const uint32_t &thread_index_id : thread_index_ids) { - strm.Format("#{0} ", thread_index_id); - } - strm.EOL(); - - // List the shared call stack for this set of threads - uint32_t representative_thread_id = stack.GetRepresentativeThread(); - ThreadSP thread = process->GetThreadList().FindThreadByIndexID( - representative_thread_id); - if (!HandleOneThread(thread->GetID(), result)) { - return false; - } - } - } else { - uint32_t idx = 0; - for (const lldb::tid_t &tid : tids) { - if (idx != 0 && m_add_return) - result.AppendMessage(""); - - if (!HandleOneThread(tid, result)) - return false; - - ++idx; - } - } - return result.Succeeded(); - } - -protected: - // Override this to do whatever you need to do for one thread. - // - // If you return false, the iteration will stop, otherwise it will proceed. - // The result is set to m_success_return (defaults to - // eReturnStatusSuccessFinishResult) before the iteration, so you only need - // to set the return status in HandleOneThread if you want to indicate an - // error. If m_add_return is true, a blank line will be inserted between each - // of the listings (except the last one.) - - virtual bool HandleOneThread(lldb::tid_t, CommandReturnObject &result) = 0; - - bool BucketThread(lldb::tid_t tid, std::set &unique_stacks, - CommandReturnObject &result) { - // Grab the corresponding thread for the given thread id. - Process *process = m_exe_ctx.GetProcessPtr(); - Thread *thread = process->GetThreadList().FindThreadByID(tid).get(); - if (thread == nullptr) { - result.AppendErrorWithFormatv("Failed to process thread #{0}.\n", tid); - result.SetStatus(eReturnStatusFailed); - return false; - } - - // Collect the each frame's address for this call-stack - std::stack stack_frames; - const uint32_t frame_count = thread->GetStackFrameCount(); - for (uint32_t frame_index = 0; frame_index < frame_count; frame_index++) { - const lldb::StackFrameSP frame_sp = - thread->GetStackFrameAtIndex(frame_index); - const lldb::addr_t pc = frame_sp->GetStackID().GetPC(); - stack_frames.push(pc); - } - - uint32_t thread_index_id = thread->GetIndexID(); - UniqueStack new_unique_stack(stack_frames, thread_index_id); - - // Try to match the threads stack to and existing entry. - std::set::iterator matching_stack = - unique_stacks.find(new_unique_stack); - if (matching_stack != unique_stacks.end()) { - matching_stack->AddThread(thread_index_id); - } else { - unique_stacks.insert(new_unique_stack); - } - return true; - } - - ReturnStatus m_success_return = eReturnStatusSuccessFinishResult; - bool m_unique_stacks = false; - bool m_add_return = true; -}; - // CommandObjectThreadBacktrace #define LLDB_OPTIONS_thread_backtrace #include "CommandOptions.inc" @@ -344,7 +156,6 @@ protected: result.AppendErrorWithFormat( "thread disappeared while computing backtraces: 0x%" PRIx64 "\n", tid); - result.SetStatus(eReturnStatusFailed); return false; } @@ -363,7 +174,6 @@ protected: result.AppendErrorWithFormat( "error displaying backtrace for thread: \"0x%4.4x\"\n", thread->GetIndexID()); - result.SetStatus(eReturnStatusFailed); return false; } if (m_options.m_extended_backtrace) { @@ -482,8 +292,16 @@ public: // Check if we are in Non-Stop mode TargetSP target_sp = execution_context ? execution_context->GetTargetSP() : TargetSP(); - if (target_sp && target_sp->GetNonStopModeEnabled()) + if (target_sp && target_sp->GetNonStopModeEnabled()) { + // NonStopMode runs all threads by definition, so when it is on we don't + // need to check the process setting for runs all threads. m_run_mode = eOnlyThisThread; + } else { + ProcessSP process_sp = + execution_context ? execution_context->GetProcessSP() : ProcessSP(); + if (process_sp && process_sp->GetSteppingRunsAllThreads()) + m_run_mode = eAllThreads; + } m_avoid_regexp.clear(); m_step_in_target.clear(); @@ -541,6 +359,17 @@ public: ~CommandObjectThreadStepWithTypeAndScope() override = default; + void + HandleArgumentCompletion(CompletionRequest &request, + OptionElementVector &opt_element_vector) override { + if (request.GetCursorIndex()) + return; + + CommandCompletions::InvokeCommonCompletionCallbacks( + GetCommandInterpreter(), CommandCompletions::eThreadIndexCompletion, + request, nullptr); + } + Options *GetOptions() override { return &m_all_options; } protected: @@ -556,7 +385,6 @@ protected: if (thread == nullptr) { result.AppendError("no selected thread in process"); - result.SetStatus(eReturnStatusFailed); return false; } } else { @@ -566,7 +394,6 @@ protected: if (!llvm::to_integer(thread_idx_cstr, step_thread_idx)) { result.AppendErrorWithFormat("invalid thread index '%s'.\n", thread_idx_cstr); - result.SetStatus(eReturnStatusFailed); return false; } thread = @@ -575,7 +402,6 @@ protected: result.AppendErrorWithFormat( "Thread index %u is out of range (valid values are 0 - %u).\n", step_thread_idx, num_threads); - result.SetStatus(eReturnStatusFailed); return false; } } @@ -583,14 +409,12 @@ protected: if (m_step_type == eStepTypeScripted) { if (m_class_options.GetName().empty()) { result.AppendErrorWithFormat("empty class name for scripted step."); - result.SetStatus(eReturnStatusFailed); return false; } else if (!GetDebugger().GetScriptInterpreter()->CheckObjectExists( m_class_options.GetName().c_str())) { result.AppendErrorWithFormat( "class for scripted step: \"%s\" does not exist.", m_class_options.GetName().c_str()); - result.SetStatus(eReturnStatusFailed); return false; } } @@ -599,7 +423,6 @@ protected: m_step_type != eStepTypeInto) { result.AppendErrorWithFormat( "end line option is only valid for step into"); - result.SetStatus(eReturnStatusFailed); return false; } @@ -612,8 +435,7 @@ protected: if (m_options.m_run_mode == eAllThreads) bool_stop_other_threads = false; else if (m_options.m_run_mode == eOnlyDuringStepping) - bool_stop_other_threads = - (m_step_type != eStepTypeOut && m_step_type != eStepTypeScripted); + bool_stop_other_threads = (m_step_type != eStepTypeOut); else bool_stop_other_threads = true; @@ -633,7 +455,6 @@ protected: error)) { result.AppendErrorWithFormat("invalid end-line option: %s.", error.AsCString()); - result.SetStatus(eReturnStatusFailed); return false; } } else if (m_options.m_end_line_is_block_end) { @@ -641,7 +462,6 @@ protected: Block *block = frame->GetSymbolContext(eSymbolContextBlock).block; if (!block) { result.AppendErrorWithFormat("Could not find the current block."); - result.SetStatus(eReturnStatusFailed); return false; } @@ -651,7 +471,6 @@ protected: if (!block_range.GetBaseAddress().IsValid()) { result.AppendErrorWithFormat( "Could not find the current block address."); - result.SetStatus(eReturnStatusFailed); return false; } lldb::addr_t pc_offset_in_block = @@ -710,7 +529,6 @@ protected: new_plan_status); } else { result.AppendError("step type is not supported"); - result.SetStatus(eReturnStatusFailed); return false; } @@ -742,7 +560,6 @@ protected: if (!error.Success()) { result.AppendMessage(error.AsCString()); - result.SetStatus(eReturnStatusFailed); return false; } @@ -766,7 +583,6 @@ protected: } } else { result.SetError(new_plan_status); - result.SetStatus(eReturnStatusFailed); } return result.Succeeded(); } @@ -808,13 +624,20 @@ public: ~CommandObjectThreadContinue() override = default; + void + HandleArgumentCompletion(CompletionRequest &request, + OptionElementVector &opt_element_vector) override { + CommandCompletions::InvokeCommonCompletionCallbacks( + GetCommandInterpreter(), CommandCompletions::eThreadIndexCompletion, + request, nullptr); + } + bool DoExecute(Args &command, CommandReturnObject &result) override { bool synchronous_execution = m_interpreter.GetSynchronous(); Process *process = m_exe_ctx.GetProcessPtr(); if (process == nullptr) { result.AppendError("no process exists. Cannot continue"); - result.SetStatus(eReturnStatusFailed); return false; } @@ -835,7 +658,6 @@ public: if (entry.ref().getAsInteger(0, thread_idx)) { result.AppendErrorWithFormat( "invalid thread index argument: \"%s\".\n", entry.c_str()); - result.SetStatus(eReturnStatusFailed); return false; } Thread *thread = @@ -846,14 +668,12 @@ public: } else { result.AppendErrorWithFormat("invalid thread index %u.\n", thread_idx); - result.SetStatus(eReturnStatusFailed); return false; } } if (resume_threads.empty()) { result.AppendError("no valid thread indexes were specified"); - result.SetStatus(eReturnStatusFailed); return false; } else { if (resume_threads.size() == 1) @@ -893,7 +713,6 @@ public: Thread *current_thread = GetDefaultThread(); if (current_thread == nullptr) { result.AppendError("the process doesn't have a current thread"); - result.SetStatus(eReturnStatusFailed); return false; } // Set the actions that the threads should each take when resuming @@ -936,13 +755,11 @@ public: } else { result.AppendErrorWithFormat("Failed to resume process: %s\n", error.AsCString()); - result.SetStatus(eReturnStatusFailed); } } else { result.AppendErrorWithFormat( "Process cannot be continued from its current state (%s).\n", StateAsCString(state)); - result.SetStatus(eReturnStatusFailed); } return result.Succeeded(); @@ -966,12 +783,10 @@ class CommandObjectThreadUntil : public CommandObjectParsed { public: class CommandOptions : public Options { public: - uint32_t m_thread_idx; - uint32_t m_frame_idx; + uint32_t m_thread_idx = LLDB_INVALID_THREAD_ID; + uint32_t m_frame_idx = LLDB_INVALID_FRAME_ID; - CommandOptions() - : Options(), m_thread_idx(LLDB_INVALID_THREAD_ID), - m_frame_idx(LLDB_INVALID_FRAME_ID) { + CommandOptions() : Options() { // Keep default values of all options in one place: OptionParsingStarting // () OptionParsingStarting(nullptr); @@ -1082,7 +897,6 @@ protected: Process *process = m_exe_ctx.GetProcessPtr(); if (process == nullptr) { result.AppendError("need a valid process to step"); - result.SetStatus(eReturnStatusFailed); } else { Thread *thread = nullptr; std::vector line_numbers; @@ -1094,7 +908,6 @@ protected: if (!llvm::to_integer(command.GetArgumentAtIndex(i), line_number)) { result.AppendErrorWithFormat("invalid line number: '%s'.\n", command.GetArgumentAtIndex(i)); - result.SetStatus(eReturnStatusFailed); return false; } else line_numbers.push_back(line_number); @@ -1102,7 +915,6 @@ protected: } else if (m_options.m_until_addrs.empty()) { result.AppendErrorWithFormat("No line number or address provided:\n%s", GetSyntax().str().c_str()); - result.SetStatus(eReturnStatusFailed); return false; } @@ -1119,7 +931,6 @@ protected: result.AppendErrorWithFormat( "Thread index %u is out of range (valid values are 0 - %u).\n", m_options.m_thread_idx, num_threads); - result.SetStatus(eReturnStatusFailed); return false; } @@ -1131,7 +942,6 @@ protected: result.AppendErrorWithFormat( "Frame index %u is out of range for thread %u.\n", m_options.m_frame_idx, m_options.m_thread_idx); - result.SetStatus(eReturnStatusFailed); return false; } @@ -1151,7 +961,6 @@ protected: "frame %u of thread index %u.\n", m_options.m_frame_idx, m_options.m_thread_idx); - result.SetStatus(eReturnStatusFailed); return false; } @@ -1211,7 +1020,6 @@ protected: result.AppendErrorWithFormat( "Until target outside of the current function.\n"); - result.SetStatus(eReturnStatusFailed); return false; } @@ -1227,14 +1035,12 @@ protected: new_plan_sp->SetOkayToDiscard(false); } else { result.SetError(new_plan_status); - result.SetStatus(eReturnStatusFailed); return false; } } else { result.AppendErrorWithFormat( "Frame index %u of thread %u has no debug information.\n", m_options.m_frame_idx, m_options.m_thread_idx); - result.SetStatus(eReturnStatusFailed); return false; } @@ -1264,7 +1070,6 @@ protected: } else { result.AppendErrorWithFormat("Failed to resume process: %s.\n", error.AsCString()); - result.SetStatus(eReturnStatusFailed); } } return result.Succeeded(); @@ -1300,18 +1105,27 @@ public: ~CommandObjectThreadSelect() override = default; + void + HandleArgumentCompletion(CompletionRequest &request, + OptionElementVector &opt_element_vector) override { + if (request.GetCursorIndex()) + return; + + CommandCompletions::InvokeCommonCompletionCallbacks( + GetCommandInterpreter(), CommandCompletions::eThreadIndexCompletion, + request, nullptr); + } + protected: bool DoExecute(Args &command, CommandReturnObject &result) override { Process *process = m_exe_ctx.GetProcessPtr(); if (process == nullptr) { result.AppendError("no process"); - result.SetStatus(eReturnStatusFailed); return false; } else if (command.GetArgumentCount() != 1) { result.AppendErrorWithFormat( "'%s' takes exactly one thread index argument:\nUsage: %s\n", m_cmd_name.c_str(), m_cmd_syntax.c_str()); - result.SetStatus(eReturnStatusFailed); return false; } @@ -1319,7 +1133,6 @@ protected: if (!llvm::to_integer(command.GetArgumentAtIndex(0), index_id)) { result.AppendErrorWithFormat("Invalid thread index '%s'", command.GetArgumentAtIndex(0)); - result.SetStatus(eReturnStatusFailed); return false; } @@ -1328,7 +1141,6 @@ protected: if (new_thread == nullptr) { result.AppendErrorWithFormat("invalid thread #%s.\n", command.GetArgumentAtIndex(0)); - result.SetStatus(eReturnStatusFailed); return false; } @@ -1431,6 +1243,14 @@ public: ~CommandObjectThreadInfo() override = default; + void + HandleArgumentCompletion(CompletionRequest &request, + OptionElementVector &opt_element_vector) override { + CommandCompletions::InvokeCommonCompletionCallbacks( + GetCommandInterpreter(), CommandCompletions::eThreadIndexCompletion, + request, nullptr); + } + Options *GetOptions() override { return &m_options; } bool HandleOneThread(lldb::tid_t tid, CommandReturnObject &result) override { @@ -1439,7 +1259,6 @@ public: if (!thread_sp) { result.AppendErrorWithFormat("thread no longer exists: 0x%" PRIx64 "\n", tid); - result.SetStatus(eReturnStatusFailed); return false; } @@ -1451,7 +1270,6 @@ public: m_options.m_json_stopinfo)) { result.AppendErrorWithFormat("error displaying info for thread: \"%d\"\n", thread->GetIndexID()); - result.SetStatus(eReturnStatusFailed); return false; } return true; @@ -1475,13 +1293,20 @@ public: ~CommandObjectThreadException() override = default; + void + HandleArgumentCompletion(CompletionRequest &request, + OptionElementVector &opt_element_vector) override { + CommandCompletions::InvokeCommonCompletionCallbacks( + GetCommandInterpreter(), CommandCompletions::eThreadIndexCompletion, + request, nullptr); + } + bool HandleOneThread(lldb::tid_t tid, CommandReturnObject &result) override { ThreadSP thread_sp = m_exe_ctx.GetProcessPtr()->GetThreadList().FindThreadByID(tid); if (!thread_sp) { result.AppendErrorWithFormat("thread no longer exists: 0x%" PRIx64 "\n", tid); - result.SetStatus(eReturnStatusFailed); return false; } @@ -1511,7 +1336,7 @@ class CommandObjectThreadReturn : public CommandObjectRaw { public: class CommandOptions : public Options { public: - CommandOptions() : Options(), m_from_expression(false) { + CommandOptions() : Options() { // Keep default values of all options in one place: OptionParsingStarting // () OptionParsingStarting(nullptr); @@ -1551,7 +1376,7 @@ public: return llvm::makeArrayRef(g_thread_return_options); } - bool m_from_expression; + bool m_from_expression = false; // Instance variables to hold the values for command options. }; @@ -1604,7 +1429,6 @@ protected: if (!error.Success()) { result.AppendErrorWithFormat("Unwinding expression failed - %s.", error.AsCString()); - result.SetStatus(eReturnStatusFailed); } else { bool success = thread->SetSelectedFrameByIndexNoisily(0, result.GetOutputStream()); @@ -1614,7 +1438,6 @@ protected: } else { result.AppendErrorWithFormat( "Could not select 0th frame after unwinding expression."); - result.SetStatus(eReturnStatusFailed); } } return result.Succeeded(); @@ -1627,7 +1450,6 @@ protected: if (frame_sp->IsInlined()) { result.AppendError("Don't know how to return from inlined frames."); - result.SetStatus(eReturnStatusFailed); return false; } @@ -1649,7 +1471,6 @@ protected: else result.AppendErrorWithFormat( "Unknown error evaluating result expression."); - result.SetStatus(eReturnStatusFailed); return false; } } @@ -1662,7 +1483,6 @@ protected: result.AppendErrorWithFormat( "Error returning from frame %d of thread %d: %s.", frame_idx, thread_sp->GetIndexID(), error.AsCString()); - result.SetStatus(eReturnStatusFailed); return false; } @@ -1764,14 +1584,12 @@ protected: lldb::addr_t callAddr = dest.GetCallableLoadAddress(target); if (callAddr == LLDB_INVALID_ADDRESS) { result.AppendErrorWithFormat("Invalid destination address."); - result.SetStatus(eReturnStatusFailed); return false; } if (!reg_ctx->SetPC(callAddr)) { result.AppendErrorWithFormat("Error changing PC value for thread %d.", thread->GetIndexID()); - result.SetStatus(eReturnStatusFailed); return false; } } else { @@ -1788,7 +1606,6 @@ protected: if (!file) { result.AppendErrorWithFormat( "No source file available for the current location."); - result.SetStatus(eReturnStatusFailed); return false; } @@ -1913,9 +1730,8 @@ public: true /* condense_trivial */, m_options.m_unreported); // If we didn't find a TID, stop here and return an error. if (!success) { - result.SetError("Error dumping plans:"); + result.AppendError("Error dumping plans:"); result.AppendError(tmp_strm.GetString()); - result.SetStatus(eReturnStatusFailed); return false; } // Otherwise, add our data to the output: @@ -1929,8 +1745,7 @@ public: protected: bool HandleOneThread(lldb::tid_t tid, CommandReturnObject &result) override { // If we have already handled this from a -t option, skip it here. - if (std::find(m_options.m_tids.begin(), m_options.m_tids.end(), tid) != - m_options.m_tids.end()) + if (llvm::is_contained(m_options.m_tids, tid)) return true; Process *process = m_exe_ctx.GetProcessPtr(); @@ -1978,13 +1793,21 @@ public: ~CommandObjectThreadPlanDiscard() override = default; + void + HandleArgumentCompletion(CompletionRequest &request, + OptionElementVector &opt_element_vector) override { + if (!m_exe_ctx.HasThreadScope() || request.GetCursorIndex()) + return; + + m_exe_ctx.GetThreadPtr()->AutoCompleteThreadPlans(request); + } + bool DoExecute(Args &args, CommandReturnObject &result) override { Thread *thread = m_exe_ctx.GetThreadPtr(); if (args.GetArgumentCount() != 1) { result.AppendErrorWithFormat("Too many arguments, expected one - the " "thread plan index - but got %zu.", args.GetArgumentCount()); - result.SetStatus(eReturnStatusFailed); return false; } @@ -1993,14 +1816,12 @@ public: result.AppendErrorWithFormat( "Invalid thread index: \"%s\" - should be unsigned int.", args.GetArgumentAtIndex(0)); - result.SetStatus(eReturnStatusFailed); return false; } if (thread_plan_idx == 0) { result.AppendErrorWithFormat( "You wouldn't really want me to discard the base thread plan."); - result.SetStatus(eReturnStatusFailed); return false; } @@ -2011,7 +1832,6 @@ public: result.AppendErrorWithFormat( "Could not find User thread plan with index %s.", args.GetArgumentAtIndex(0)); - result.SetStatus(eReturnStatusFailed); return false; } } @@ -2050,11 +1870,11 @@ public: bool DoExecute(Args &args, CommandReturnObject &result) override { Process *process = m_exe_ctx.GetProcessPtr(); - + if (args.GetArgumentCount() == 0) { process->PruneThreadPlans(); result.SetStatus(eReturnStatusSuccessFinishNoResult); - return true; + return true; } const size_t num_args = args.GetArgumentCount(); @@ -2067,13 +1887,11 @@ public: if (!llvm::to_integer(args.GetArgumentAtIndex(i), tid)) { result.AppendErrorWithFormat("invalid thread specification: \"%s\"\n", args.GetArgumentAtIndex(i)); - result.SetStatus(eReturnStatusFailed); return false; } if (!process->PruneThreadPlansForTID(tid)) { result.AppendErrorWithFormat("Could not find unreported tid: \"%s\"\n", args.GetArgumentAtIndex(i)); - result.SetStatus(eReturnStatusFailed); return false; } } @@ -2104,6 +1922,364 @@ public: ~CommandObjectMultiwordThreadPlan() override = default; }; +// Next are the subcommands of CommandObjectMultiwordTrace + +// CommandObjectTraceExport + +class CommandObjectTraceExport : public CommandObjectMultiword { +public: + CommandObjectTraceExport(CommandInterpreter &interpreter) + : CommandObjectMultiword( + interpreter, "trace thread export", + "Commands for exporting traces of the threads in the current " + "process to different formats.", + "thread trace export []") { + + for (uint32_t i = 0; true; i++) { + if (const char *plugin_name = + PluginManager::GetTraceExporterPluginNameAtIndex(i)) { + if (ThreadTraceExportCommandCreator command_creator = + PluginManager::GetThreadTraceExportCommandCreatorAtIndex(i)) { + LoadSubCommand(plugin_name, command_creator(interpreter)); + } + } else { + break; + } + } + } +}; + +// CommandObjectTraceStart + +class CommandObjectTraceStart : public CommandObjectTraceProxy { +public: + CommandObjectTraceStart(CommandInterpreter &interpreter) + : CommandObjectTraceProxy( + /*live_debug_session_only=*/true, interpreter, "thread trace start", + "Start tracing threads with the corresponding trace " + "plug-in for the current process.", + "thread trace start []") {} + +protected: + lldb::CommandObjectSP GetDelegateCommand(Trace &trace) override { + return trace.GetThreadTraceStartCommand(m_interpreter); + } +}; + +// CommandObjectTraceStop + +class CommandObjectTraceStop : public CommandObjectMultipleThreads { +public: + CommandObjectTraceStop(CommandInterpreter &interpreter) + : CommandObjectMultipleThreads( + interpreter, "thread trace stop", + "Stop tracing threads, including the ones traced with the " + "\"process trace start\" command." + "Defaults to the current thread. Thread indices can be " + "specified as arguments.\n Use the thread-index \"all\" to stop " + "tracing " + "for all existing threads.", + "thread trace stop [ ...]", + eCommandRequiresProcess | eCommandTryTargetAPILock | + eCommandProcessMustBeLaunched | eCommandProcessMustBePaused | + eCommandProcessMustBeTraced) {} + + ~CommandObjectTraceStop() override = default; + + bool DoExecuteOnThreads(Args &command, CommandReturnObject &result, + llvm::ArrayRef tids) override { + ProcessSP process_sp = m_exe_ctx.GetProcessSP(); + + TraceSP trace_sp = process_sp->GetTarget().GetTrace(); + + if (llvm::Error err = trace_sp->Stop(tids)) + result.AppendError(toString(std::move(err))); + else + result.SetStatus(eReturnStatusSuccessFinishResult); + + return result.Succeeded(); + } +}; + +// CommandObjectTraceDumpInstructions +#define LLDB_OPTIONS_thread_trace_dump_instructions +#include "CommandOptions.inc" + +class CommandObjectTraceDumpInstructions + : public CommandObjectIterateOverThreads { +public: + class CommandOptions : public Options { + public: + CommandOptions() : Options() { OptionParsingStarting(nullptr); } + + ~CommandOptions() override = default; + + Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, + ExecutionContext *execution_context) override { + Status error; + const int short_option = m_getopt_table[option_idx].val; + + switch (short_option) { + case 'c': { + int32_t count; + if (option_arg.empty() || option_arg.getAsInteger(0, count) || + count < 0) + error.SetErrorStringWithFormat( + "invalid integer value for option '%s'", + option_arg.str().c_str()); + else + m_count = count; + break; + } + case 's': { + int32_t skip; + if (option_arg.empty() || option_arg.getAsInteger(0, skip) || skip < 0) + error.SetErrorStringWithFormat( + "invalid integer value for option '%s'", + option_arg.str().c_str()); + else + m_skip = skip; + break; + } + case 'r': { + m_raw = true; + break; + } + case 'f': { + m_forwards = true; + break; + } + case 't': { + m_show_tsc = true; + break; + } + default: + llvm_unreachable("Unimplemented option"); + } + return error; + } + + void OptionParsingStarting(ExecutionContext *execution_context) override { + m_count = kDefaultCount; + m_skip = 0; + m_raw = false; + m_forwards = false; + m_show_tsc = false; + } + + llvm::ArrayRef GetDefinitions() override { + return llvm::makeArrayRef(g_thread_trace_dump_instructions_options); + } + + static const size_t kDefaultCount = 20; + + // Instance variables to hold the values for command options. + size_t m_count; + size_t m_skip; + bool m_raw; + bool m_forwards; + bool m_show_tsc; + }; + + CommandObjectTraceDumpInstructions(CommandInterpreter &interpreter) + : CommandObjectIterateOverThreads( + interpreter, "thread trace dump instructions", + "Dump the traced instructions for one or more threads. If no " + "threads are specified, show the current thread. Use the " + "thread-index \"all\" to see all threads.", + nullptr, + eCommandRequiresProcess | eCommandTryTargetAPILock | + eCommandProcessMustBeLaunched | eCommandProcessMustBePaused | + eCommandProcessMustBeTraced), + m_options(), m_create_repeat_command_just_invoked(false) {} + + ~CommandObjectTraceDumpInstructions() override = default; + + Options *GetOptions() override { return &m_options; } + + const char *GetRepeatCommand(Args ¤t_command_args, + uint32_t index) override { + current_command_args.GetCommandString(m_repeat_command); + m_create_repeat_command_just_invoked = true; + return m_repeat_command.c_str(); + } + +protected: + bool DoExecute(Args &args, CommandReturnObject &result) override { + if (!IsRepeatCommand()) + m_dumpers.clear(); + + bool status = CommandObjectIterateOverThreads::DoExecute(args, result); + + m_create_repeat_command_just_invoked = false; + return status; + } + + bool IsRepeatCommand() { + return !m_repeat_command.empty() && !m_create_repeat_command_just_invoked; + } + + bool HandleOneThread(lldb::tid_t tid, CommandReturnObject &result) override { + Stream &s = result.GetOutputStream(); + + const TraceSP &trace_sp = m_exe_ctx.GetTargetSP()->GetTrace(); + ThreadSP thread_sp = + m_exe_ctx.GetProcessPtr()->GetThreadList().FindThreadByID(tid); + + if (!m_dumpers.count(thread_sp->GetID())) { + lldb::TraceCursorUP cursor_up = trace_sp->GetCursor(*thread_sp); + // Set up the cursor and return the presentation index of the first + // instruction to dump after skipping instructions. + auto setUpCursor = [&]() { + cursor_up->SetForwards(m_options.m_forwards); + if (m_options.m_forwards) + return cursor_up->Seek(m_options.m_skip, TraceCursor::SeekType::Set); + return -cursor_up->Seek(-m_options.m_skip, TraceCursor::SeekType::End); + }; + + int initial_index = setUpCursor(); + + auto dumper = std::make_unique( + std::move(cursor_up), initial_index, m_options.m_raw, + m_options.m_show_tsc); + + // This happens when the seek value was more than the number of available + // instructions. + if (std::abs(initial_index) < (int)m_options.m_skip) + dumper->SetNoMoreData(); + + m_dumpers[thread_sp->GetID()] = std::move(dumper); + } + + m_dumpers[thread_sp->GetID()]->DumpInstructions(s, m_options.m_count); + return true; + } + + CommandOptions m_options; + + // Repeat command helpers + std::string m_repeat_command; + bool m_create_repeat_command_just_invoked; + std::map> m_dumpers; +}; + +// CommandObjectTraceDumpInfo +#define LLDB_OPTIONS_thread_trace_dump_info +#include "CommandOptions.inc" + +class CommandObjectTraceDumpInfo : public CommandObjectIterateOverThreads { +public: + class CommandOptions : public Options { + public: + CommandOptions() : Options() { OptionParsingStarting(nullptr); } + + ~CommandOptions() override = default; + + Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, + ExecutionContext *execution_context) override { + Status error; + const int short_option = m_getopt_table[option_idx].val; + + switch (short_option) { + case 'v': { + m_verbose = true; + break; + } + default: + llvm_unreachable("Unimplemented option"); + } + return error; + } + + void OptionParsingStarting(ExecutionContext *execution_context) override { + m_verbose = false; + } + + llvm::ArrayRef GetDefinitions() override { + return llvm::makeArrayRef(g_thread_trace_dump_info_options); + } + + // Instance variables to hold the values for command options. + bool m_verbose; + }; + + bool DoExecute(Args &command, CommandReturnObject &result) override { + Target &target = m_exe_ctx.GetTargetRef(); + result.GetOutputStream().Printf( + "Trace technology: %s\n", + target.GetTrace()->GetPluginName().AsCString()); + return CommandObjectIterateOverThreads::DoExecute(command, result); + } + + CommandObjectTraceDumpInfo(CommandInterpreter &interpreter) + : CommandObjectIterateOverThreads( + interpreter, "thread trace dump info", + "Dump the traced information for one or more threads. If no " + "threads are specified, show the current thread. Use the " + "thread-index \"all\" to see all threads.", + nullptr, + eCommandRequiresProcess | eCommandTryTargetAPILock | + eCommandProcessMustBeLaunched | eCommandProcessMustBePaused | + eCommandProcessMustBeTraced), + m_options() {} + + ~CommandObjectTraceDumpInfo() override = default; + + Options *GetOptions() override { return &m_options; } + +protected: + bool HandleOneThread(lldb::tid_t tid, CommandReturnObject &result) override { + const TraceSP &trace_sp = m_exe_ctx.GetTargetSP()->GetTrace(); + ThreadSP thread_sp = + m_exe_ctx.GetProcessPtr()->GetThreadList().FindThreadByID(tid); + trace_sp->DumpTraceInfo(*thread_sp, result.GetOutputStream(), + m_options.m_verbose); + return true; + } + + CommandOptions m_options; +}; + +// CommandObjectMultiwordTraceDump +class CommandObjectMultiwordTraceDump : public CommandObjectMultiword { +public: + CommandObjectMultiwordTraceDump(CommandInterpreter &interpreter) + : CommandObjectMultiword( + interpreter, "dump", + "Commands for displaying trace information of the threads " + "in the current process.", + "thread trace dump []") { + LoadSubCommand( + "instructions", + CommandObjectSP(new CommandObjectTraceDumpInstructions(interpreter))); + LoadSubCommand( + "info", CommandObjectSP(new CommandObjectTraceDumpInfo(interpreter))); + } + ~CommandObjectMultiwordTraceDump() override = default; +}; + +// CommandObjectMultiwordTrace +class CommandObjectMultiwordTrace : public CommandObjectMultiword { +public: + CommandObjectMultiwordTrace(CommandInterpreter &interpreter) + : CommandObjectMultiword( + interpreter, "trace", + "Commands for operating on traces of the threads in the current " + "process.", + "thread trace []") { + LoadSubCommand("dump", CommandObjectSP(new CommandObjectMultiwordTraceDump( + interpreter))); + LoadSubCommand("start", + CommandObjectSP(new CommandObjectTraceStart(interpreter))); + LoadSubCommand("stop", + CommandObjectSP(new CommandObjectTraceStop(interpreter))); + LoadSubCommand("export", + CommandObjectSP(new CommandObjectTraceExport(interpreter))); + } + + ~CommandObjectMultiwordTrace() override = default; +}; + // CommandObjectMultiwordThread CommandObjectMultiwordThread::CommandObjectMultiwordThread( @@ -2179,6 +2355,8 @@ CommandObjectMultiwordThread::CommandObjectMultiwordThread( LoadSubCommand("plan", CommandObjectSP(new CommandObjectMultiwordThreadPlan( interpreter))); + LoadSubCommand("trace", + CommandObjectSP(new CommandObjectMultiwordTrace(interpreter))); } CommandObjectMultiwordThread::~CommandObjectMultiwordThread() = default; diff --git a/gnu/llvm/lldb/source/Commands/CommandObjectThreadUtil.cpp b/gnu/llvm/lldb/source/Commands/CommandObjectThreadUtil.cpp new file mode 100644 index 00000000000..d330da7e684 --- /dev/null +++ b/gnu/llvm/lldb/source/Commands/CommandObjectThreadUtil.cpp @@ -0,0 +1,197 @@ +//===-- CommandObjectThreadUtil.cpp -----------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#include "CommandObjectThreadUtil.h" + +#include "lldb/Interpreter/CommandReturnObject.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/Thread.h" + +using namespace lldb; +using namespace lldb_private; +using namespace llvm; + +CommandObjectIterateOverThreads::CommandObjectIterateOverThreads( + CommandInterpreter &interpreter, const char *name, const char *help, + const char *syntax, uint32_t flags) + : CommandObjectParsed(interpreter, name, help, syntax, flags) {} + +bool CommandObjectIterateOverThreads::DoExecute(Args &command, + CommandReturnObject &result) { + result.SetStatus(m_success_return); + + bool all_threads = false; + if (command.GetArgumentCount() == 0) { + Thread *thread = m_exe_ctx.GetThreadPtr(); + if (!thread || !HandleOneThread(thread->GetID(), result)) + return false; + return result.Succeeded(); + } else if (command.GetArgumentCount() == 1) { + all_threads = ::strcmp(command.GetArgumentAtIndex(0), "all") == 0; + m_unique_stacks = ::strcmp(command.GetArgumentAtIndex(0), "unique") == 0; + } + + // Use tids instead of ThreadSPs to prevent deadlocking problems which + // result from JIT-ing code while iterating over the (locked) ThreadSP + // list. + std::vector tids; + + if (all_threads || m_unique_stacks) { + Process *process = m_exe_ctx.GetProcessPtr(); + + for (ThreadSP thread_sp : process->Threads()) + tids.push_back(thread_sp->GetID()); + } else { + const size_t num_args = command.GetArgumentCount(); + Process *process = m_exe_ctx.GetProcessPtr(); + + std::lock_guard guard( + process->GetThreadList().GetMutex()); + + for (size_t i = 0; i < num_args; i++) { + uint32_t thread_idx; + if (!llvm::to_integer(command.GetArgumentAtIndex(i), thread_idx)) { + result.AppendErrorWithFormat("invalid thread specification: \"%s\"\n", + command.GetArgumentAtIndex(i)); + return false; + } + + ThreadSP thread = + process->GetThreadList().FindThreadByIndexID(thread_idx); + + if (!thread) { + result.AppendErrorWithFormat("no thread with index: \"%s\"\n", + command.GetArgumentAtIndex(i)); + return false; + } + + tids.push_back(thread->GetID()); + } + } + + if (m_unique_stacks) { + // Iterate over threads, finding unique stack buckets. + std::set unique_stacks; + for (const lldb::tid_t &tid : tids) { + if (!BucketThread(tid, unique_stacks, result)) { + return false; + } + } + + // Write the thread id's and unique call stacks to the output stream + Stream &strm = result.GetOutputStream(); + Process *process = m_exe_ctx.GetProcessPtr(); + for (const UniqueStack &stack : unique_stacks) { + // List the common thread ID's + const std::vector &thread_index_ids = + stack.GetUniqueThreadIndexIDs(); + strm.Format("{0} thread(s) ", thread_index_ids.size()); + for (const uint32_t &thread_index_id : thread_index_ids) { + strm.Format("#{0} ", thread_index_id); + } + strm.EOL(); + + // List the shared call stack for this set of threads + uint32_t representative_thread_id = stack.GetRepresentativeThread(); + ThreadSP thread = process->GetThreadList().FindThreadByIndexID( + representative_thread_id); + if (!HandleOneThread(thread->GetID(), result)) { + return false; + } + } + } else { + uint32_t idx = 0; + for (const lldb::tid_t &tid : tids) { + if (idx != 0 && m_add_return) + result.AppendMessage(""); + + if (!HandleOneThread(tid, result)) + return false; + + ++idx; + } + } + return result.Succeeded(); +} + +bool CommandObjectIterateOverThreads::BucketThread( + lldb::tid_t tid, std::set &unique_stacks, + CommandReturnObject &result) { + // Grab the corresponding thread for the given thread id. + Process *process = m_exe_ctx.GetProcessPtr(); + Thread *thread = process->GetThreadList().FindThreadByID(tid).get(); + if (thread == nullptr) { + result.AppendErrorWithFormatv("Failed to process thread #{0}.\n", tid); + return false; + } + + // Collect the each frame's address for this call-stack + std::stack stack_frames; + const uint32_t frame_count = thread->GetStackFrameCount(); + for (uint32_t frame_index = 0; frame_index < frame_count; frame_index++) { + const lldb::StackFrameSP frame_sp = + thread->GetStackFrameAtIndex(frame_index); + const lldb::addr_t pc = frame_sp->GetStackID().GetPC(); + stack_frames.push(pc); + } + + uint32_t thread_index_id = thread->GetIndexID(); + UniqueStack new_unique_stack(stack_frames, thread_index_id); + + // Try to match the threads stack to and existing entry. + std::set::iterator matching_stack = + unique_stacks.find(new_unique_stack); + if (matching_stack != unique_stacks.end()) { + matching_stack->AddThread(thread_index_id); + } else { + unique_stacks.insert(new_unique_stack); + } + return true; +} + +bool CommandObjectMultipleThreads::DoExecute(Args &command, + CommandReturnObject &result) { + Process &process = m_exe_ctx.GetProcessRef(); + + std::vector tids; + const size_t num_args = command.GetArgumentCount(); + + std::lock_guard guard( + process.GetThreadList().GetMutex()); + + if (num_args > 0 && ::strcmp(command.GetArgumentAtIndex(0), "all") == 0) { + for (ThreadSP thread_sp : process.Threads()) + tids.push_back(thread_sp->GetID()); + } else { + if (num_args == 0) { + Thread &thread = m_exe_ctx.GetThreadRef(); + tids.push_back(thread.GetID()); + } + + for (size_t i = 0; i < num_args; i++) { + uint32_t thread_idx; + if (!llvm::to_integer(command.GetArgumentAtIndex(i), thread_idx)) { + result.AppendErrorWithFormat("invalid thread specification: \"%s\"\n", + command.GetArgumentAtIndex(i)); + return false; + } + + ThreadSP thread = process.GetThreadList().FindThreadByIndexID(thread_idx); + + if (!thread) { + result.AppendErrorWithFormat("no thread with index: \"%s\"\n", + command.GetArgumentAtIndex(i)); + return false; + } + + tids.push_back(thread->GetID()); + } + } + + return DoExecuteOnThreads(command, result, tids); +} diff --git a/gnu/llvm/lldb/source/Commands/CommandObjectThreadUtil.h b/gnu/llvm/lldb/source/Commands/CommandObjectThreadUtil.h new file mode 100644 index 00000000000..289ffdfc189 --- /dev/null +++ b/gnu/llvm/lldb/source/Commands/CommandObjectThreadUtil.h @@ -0,0 +1,101 @@ +//===-- CommandObjectThreadUtil.h -------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SOURCE_COMMANDS_COMMANDOBJECTTHREADUTIL_H +#define LLDB_SOURCE_COMMANDS_COMMANDOBJECTTHREADUTIL_H + +#include "lldb/Interpreter/CommandObjectMultiword.h" + +namespace lldb_private { + +class CommandObjectIterateOverThreads : public CommandObjectParsed { + + class UniqueStack { + public: + UniqueStack(std::stack stack_frames, uint32_t thread_index_id) + : m_stack_frames(stack_frames) { + m_thread_index_ids.push_back(thread_index_id); + } + + void AddThread(uint32_t thread_index_id) const { + m_thread_index_ids.push_back(thread_index_id); + } + + const std::vector &GetUniqueThreadIndexIDs() const { + return m_thread_index_ids; + } + + lldb::tid_t GetRepresentativeThread() const { + return m_thread_index_ids.front(); + } + + friend bool inline operator<(const UniqueStack &lhs, + const UniqueStack &rhs) { + return lhs.m_stack_frames < rhs.m_stack_frames; + } + + protected: + // Mark the thread index as mutable, as we don't care about it from a const + // perspective, we only care about m_stack_frames so we keep our std::set + // sorted. + mutable std::vector m_thread_index_ids; + std::stack m_stack_frames; + }; + +public: + CommandObjectIterateOverThreads(CommandInterpreter &interpreter, + const char *name, const char *help, + const char *syntax, uint32_t flags); + + ~CommandObjectIterateOverThreads() override = default; + + bool DoExecute(Args &command, CommandReturnObject &result) override; + +protected: + // Override this to do whatever you need to do for one thread. + // + // If you return false, the iteration will stop, otherwise it will proceed. + // The result is set to m_success_return (defaults to + // eReturnStatusSuccessFinishResult) before the iteration, so you only need + // to set the return status in HandleOneThread if you want to indicate an + // error. If m_add_return is true, a blank line will be inserted between each + // of the listings (except the last one.) + + virtual bool HandleOneThread(lldb::tid_t, CommandReturnObject &result) = 0; + + bool BucketThread(lldb::tid_t tid, std::set &unique_stacks, + CommandReturnObject &result); + + lldb::ReturnStatus m_success_return = lldb::eReturnStatusSuccessFinishResult; + bool m_unique_stacks = false; + bool m_add_return = true; +}; + +/// Class similar to \a CommandObjectIterateOverThreads, but which performs +/// an action on multiple threads at once instead of iterating over each thread. +class CommandObjectMultipleThreads : public CommandObjectParsed { +public: + using CommandObjectParsed::CommandObjectParsed; + + bool DoExecute(Args &command, CommandReturnObject &result) override; + +protected: + /// Method that handles the command after the main arguments have been parsed. + /// + /// \param[in] tids + /// The thread ids passed as arguments. + /// + /// \return + /// A boolean result similar to the one expected from \a DoExecute. + virtual bool DoExecuteOnThreads(Args &command, CommandReturnObject &result, + llvm::ArrayRef tids) = 0; +}; + +} // namespace lldb_private + +#endif // LLDB_SOURCE_COMMANDS_COMMANDOBJECTTHREADUTIL_H diff --git a/gnu/llvm/lldb/source/Commands/CommandObjectTrace.cpp b/gnu/llvm/lldb/source/Commands/CommandObjectTrace.cpp new file mode 100644 index 00000000000..c55fed45d4f --- /dev/null +++ b/gnu/llvm/lldb/source/Commands/CommandObjectTrace.cpp @@ -0,0 +1,333 @@ +//===-- CommandObjectTrace.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 "CommandObjectTrace.h" + +#include "llvm/Support/JSON.h" +#include "llvm/Support/MemoryBuffer.h" + +#include "lldb/Core/Debugger.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Host/OptionParser.h" +#include "lldb/Interpreter/CommandInterpreter.h" +#include "lldb/Interpreter/CommandObject.h" +#include "lldb/Interpreter/CommandReturnObject.h" +#include "lldb/Interpreter/OptionArgParser.h" +#include "lldb/Interpreter/OptionGroupFormat.h" +#include "lldb/Interpreter/OptionValueBoolean.h" +#include "lldb/Interpreter/OptionValueLanguage.h" +#include "lldb/Interpreter/OptionValueString.h" +#include "lldb/Interpreter/Options.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/Trace.h" + +using namespace lldb; +using namespace lldb_private; +using namespace llvm; + +// CommandObjectTraceLoad +#define LLDB_OPTIONS_trace_load +#include "CommandOptions.inc" + +#pragma mark CommandObjectTraceLoad + +class CommandObjectTraceLoad : public CommandObjectParsed { +public: + class CommandOptions : public Options { + public: + CommandOptions() : Options() { OptionParsingStarting(nullptr); } + + ~CommandOptions() override = default; + + Status SetOptionValue(uint32_t option_idx, StringRef option_arg, + ExecutionContext *execution_context) override { + Status error; + const int short_option = m_getopt_table[option_idx].val; + + switch (short_option) { + case 'v': { + m_verbose = true; + break; + } + default: + llvm_unreachable("Unimplemented option"); + } + return error; + } + + void OptionParsingStarting(ExecutionContext *execution_context) override { + m_verbose = false; + } + + ArrayRef GetDefinitions() override { + return makeArrayRef(g_trace_load_options); + } + + bool m_verbose; // Enable verbose logging for debugging purposes. + }; + + CommandObjectTraceLoad(CommandInterpreter &interpreter) + : CommandObjectParsed(interpreter, "trace load", + "Load a processor trace session from a JSON file.", + "trace load"), + m_options() {} + + ~CommandObjectTraceLoad() override = default; + + Options *GetOptions() override { return &m_options; } + +protected: + bool DoExecute(Args &command, CommandReturnObject &result) override { + if (command.size() != 1) { + result.AppendError( + "a single path to a JSON file containing a trace session" + "is required"); + return false; + } + + auto end_with_failure = [&result](llvm::Error err) -> bool { + result.AppendErrorWithFormat("%s\n", + llvm::toString(std::move(err)).c_str()); + return false; + }; + + FileSpec json_file(command[0].ref()); + + auto buffer_or_error = llvm::MemoryBuffer::getFile(json_file.GetPath()); + if (!buffer_or_error) { + return end_with_failure(llvm::createStringError( + std::errc::invalid_argument, "could not open input file: %s - %s.", + json_file.GetPath().c_str(), + buffer_or_error.getError().message().c_str())); + } + + llvm::Expected session_file = + json::parse(buffer_or_error.get()->getBuffer().str()); + if (!session_file) + return end_with_failure(session_file.takeError()); + + if (Expected traceOrErr = + Trace::FindPluginForPostMortemProcess( + GetDebugger(), *session_file, + json_file.GetDirectory().AsCString())) { + lldb::TraceSP trace_sp = traceOrErr.get(); + if (m_options.m_verbose && trace_sp) + result.AppendMessageWithFormat("loading trace with plugin %s\n", + trace_sp->GetPluginName().AsCString()); + } else + return end_with_failure(traceOrErr.takeError()); + + result.SetStatus(eReturnStatusSuccessFinishResult); + return true; + } + + CommandOptions m_options; +}; + +// CommandObjectTraceDump +#define LLDB_OPTIONS_trace_dump +#include "CommandOptions.inc" + +#pragma mark CommandObjectTraceDump + +class CommandObjectTraceDump : public CommandObjectParsed { +public: + class CommandOptions : public Options { + public: + CommandOptions() : Options() { OptionParsingStarting(nullptr); } + + ~CommandOptions() override = default; + + Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, + ExecutionContext *execution_context) override { + Status error; + const int short_option = m_getopt_table[option_idx].val; + + switch (short_option) { + case 'v': { + m_verbose = true; + break; + } + default: + llvm_unreachable("Unimplemented option"); + } + return error; + } + + void OptionParsingStarting(ExecutionContext *execution_context) override { + m_verbose = false; + } + + llvm::ArrayRef GetDefinitions() override { + return llvm::makeArrayRef(g_trace_dump_options); + } + + bool m_verbose; // Enable verbose logging for debugging purposes. + }; + + CommandObjectTraceDump(CommandInterpreter &interpreter) + : CommandObjectParsed(interpreter, "trace dump", + "Dump the loaded processor trace data.", + "trace dump"), + m_options() {} + + ~CommandObjectTraceDump() override = default; + + Options *GetOptions() override { return &m_options; } + +protected: + bool DoExecute(Args &command, CommandReturnObject &result) override { + Status error; + // TODO: fill in the dumping code here! + if (error.Success()) { + result.SetStatus(eReturnStatusSuccessFinishResult); + } else { + result.AppendErrorWithFormat("%s\n", error.AsCString()); + } + return result.Succeeded(); + } + + CommandOptions m_options; +}; + +// CommandObjectTraceSchema +#define LLDB_OPTIONS_trace_schema +#include "CommandOptions.inc" + +#pragma mark CommandObjectTraceSchema + +class CommandObjectTraceSchema : public CommandObjectParsed { +public: + class CommandOptions : public Options { + public: + CommandOptions() : Options() { OptionParsingStarting(nullptr); } + + ~CommandOptions() override = default; + + Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, + ExecutionContext *execution_context) override { + Status error; + const int short_option = m_getopt_table[option_idx].val; + + switch (short_option) { + case 'v': { + m_verbose = true; + break; + } + default: + llvm_unreachable("Unimplemented option"); + } + return error; + } + + void OptionParsingStarting(ExecutionContext *execution_context) override { + m_verbose = false; + } + + llvm::ArrayRef GetDefinitions() override { + return llvm::makeArrayRef(g_trace_schema_options); + } + + bool m_verbose; // Enable verbose logging for debugging purposes. + }; + + CommandObjectTraceSchema(CommandInterpreter &interpreter) + : CommandObjectParsed(interpreter, "trace schema", + "Show the schema of the given trace plugin.", + "trace schema . Use the plug-in name " + "\"all\" to see all schemas.\n"), + m_options() {} + + ~CommandObjectTraceSchema() override = default; + + Options *GetOptions() override { return &m_options; } + +protected: + bool DoExecute(Args &command, CommandReturnObject &result) override { + Status error; + if (command.empty()) { + result.AppendError( + "trace schema cannot be invoked without a plug-in as argument"); + return false; + } + + StringRef plugin_name(command[0].c_str()); + if (plugin_name == "all") { + size_t index = 0; + while (true) { + StringRef schema = PluginManager::GetTraceSchema(index++); + if (schema.empty()) + break; + + result.AppendMessage(schema); + } + } else { + if (Expected schemaOrErr = + Trace::FindPluginSchema(plugin_name)) + result.AppendMessage(*schemaOrErr); + else + error = schemaOrErr.takeError(); + } + + if (error.Success()) { + result.SetStatus(eReturnStatusSuccessFinishResult); + } else { + result.AppendErrorWithFormat("%s\n", error.AsCString()); + } + return result.Succeeded(); + } + + CommandOptions m_options; +}; + +// CommandObjectTrace + +CommandObjectTrace::CommandObjectTrace(CommandInterpreter &interpreter) + : CommandObjectMultiword(interpreter, "trace", + "Commands for loading and using processor " + "trace information.", + "trace []") { + LoadSubCommand("load", + CommandObjectSP(new CommandObjectTraceLoad(interpreter))); + LoadSubCommand("dump", + CommandObjectSP(new CommandObjectTraceDump(interpreter))); + LoadSubCommand("schema", + CommandObjectSP(new CommandObjectTraceSchema(interpreter))); +} + +CommandObjectTrace::~CommandObjectTrace() = default; + +Expected CommandObjectTraceProxy::DoGetProxyCommandObject() { + ProcessSP process_sp = m_interpreter.GetExecutionContext().GetProcessSP(); + + if (!process_sp) + return createStringError(inconvertibleErrorCode(), + "Process not available."); + if (m_live_debug_session_only && !process_sp->IsLiveDebugSession()) + return createStringError(inconvertibleErrorCode(), + "Process must be alive."); + + if (Expected trace_sp = process_sp->GetTarget().GetTraceOrCreate()) + return GetDelegateCommand(**trace_sp); + else + return createStringError(inconvertibleErrorCode(), + "Tracing is not supported. %s", + toString(trace_sp.takeError()).c_str()); +} + +CommandObject *CommandObjectTraceProxy::GetProxyCommandObject() { + if (Expected delegate = DoGetProxyCommandObject()) { + m_delegate_sp = *delegate; + m_delegate_error.clear(); + return m_delegate_sp.get(); + } else { + m_delegate_sp.reset(); + m_delegate_error = toString(delegate.takeError()); + return nullptr; + } +} diff --git a/gnu/llvm/lldb/source/Commands/CommandObjectTrace.h b/gnu/llvm/lldb/source/Commands/CommandObjectTrace.h new file mode 100644 index 00000000000..b96a3094cef --- /dev/null +++ b/gnu/llvm/lldb/source/Commands/CommandObjectTrace.h @@ -0,0 +1,51 @@ +//===-- CommandObjectTrace.h ------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SOURCE_COMMANDS_COMMANDOBJECTTRACE_H +#define LLDB_SOURCE_COMMANDS_COMMANDOBJECTTRACE_H + +#include "CommandObjectThreadUtil.h" + +namespace lldb_private { + +class CommandObjectTrace : public CommandObjectMultiword { +public: + CommandObjectTrace(CommandInterpreter &interpreter); + + ~CommandObjectTrace() override; +}; + +/// This class works by delegating the logic to the actual trace plug-in that +/// can support the current process. +class CommandObjectTraceProxy : public CommandObjectProxy { +public: + CommandObjectTraceProxy(bool live_debug_session_only, + CommandInterpreter &interpreter, const char *name, + const char *help = nullptr, + const char *syntax = nullptr, uint32_t flags = 0) + : CommandObjectProxy(interpreter, name, help, syntax, flags), + m_live_debug_session_only(live_debug_session_only) {} + +protected: + virtual lldb::CommandObjectSP GetDelegateCommand(Trace &trace) = 0; + + llvm::Expected DoGetProxyCommandObject(); + + CommandObject *GetProxyCommandObject() override; + +private: + llvm::StringRef GetUnsupportedError() override { return m_delegate_error; } + + bool m_live_debug_session_only; + lldb::CommandObjectSP m_delegate_sp; + std::string m_delegate_error; +}; + +} // namespace lldb_private + +#endif // LLDB_SOURCE_COMMANDS_COMMANDOBJECTTRACE_H diff --git a/gnu/llvm/lldb/source/Commands/CommandObjectType.cpp b/gnu/llvm/lldb/source/Commands/CommandObjectType.cpp index b2020f26621..90e224867e2 100644 --- a/gnu/llvm/lldb/source/Commands/CommandObjectType.cpp +++ b/gnu/llvm/lldb/source/Commands/CommandObjectType.cpp @@ -37,6 +37,9 @@ #include #include +#define CHECK_FORMATTER_KIND_MASK(VAL) \ + ((m_formatter_kind_mask & (VAL)) == (VAL)) + using namespace lldb; using namespace lldb_private; @@ -267,7 +270,7 @@ protected: static const char *g_synth_addreader_instructions = "Enter your Python command(s). Type 'DONE' to end.\n" "You must define a Python class with these methods:\n" - " def __init__(self, valobj, dict):\n" + " def __init__(self, valobj, internal_dict):\n" " def num_children(self):\n" " def get_child_at_index(self, index):\n" " def get_child_index(self, name):\n" @@ -374,7 +377,6 @@ protected: result.AppendError("must either provide a children list, a Python class " "name, or use -P and type a Python class " "line-by-line"); - result.SetStatus(eReturnStatusFailed); return false; } } @@ -636,7 +638,6 @@ protected: if (argc < 1) { result.AppendErrorWithFormat("%s takes one or more args.\n", m_cmd_name.c_str()); - result.SetStatus(eReturnStatusFailed); return false; } @@ -645,7 +646,6 @@ protected: m_command_options.m_custom_type_name.empty()) { result.AppendErrorWithFormat("%s needs a valid format.\n", m_cmd_name.c_str()); - result.SetStatus(eReturnStatusFailed); return false; } @@ -678,7 +678,6 @@ protected: for (auto &arg_entry : command.entries()) { if (arg_entry.ref().empty()) { result.AppendError("empty typenames not allowed"); - result.SetStatus(eReturnStatusFailed); return false; } @@ -688,7 +687,6 @@ protected: if (!typeRX.IsValid()) { result.AppendError( "regex format error (maybe this is not really a regex?)"); - result.SetStatus(eReturnStatusFailed); return false; } category_sp->GetRegexTypeSummariesContainer()->Delete(typeCS); @@ -777,6 +775,39 @@ public: ~CommandObjectTypeFormatterDelete() override = default; + void + HandleArgumentCompletion(CompletionRequest &request, + OptionElementVector &opt_element_vector) override { + if (request.GetCursorIndex()) + return; + + DataVisualization::Categories::ForEach( + [this, &request](const lldb::TypeCategoryImplSP &category_sp) { + if (CHECK_FORMATTER_KIND_MASK(eFormatCategoryItemValue)) + category_sp->GetTypeFormatsContainer()->AutoComplete(request); + if (CHECK_FORMATTER_KIND_MASK(eFormatCategoryItemRegexValue)) + category_sp->GetRegexTypeFormatsContainer()->AutoComplete(request); + + if (CHECK_FORMATTER_KIND_MASK(eFormatCategoryItemSummary)) + category_sp->GetTypeSummariesContainer()->AutoComplete(request); + if (CHECK_FORMATTER_KIND_MASK(eFormatCategoryItemRegexSummary)) + category_sp->GetRegexTypeSummariesContainer()->AutoComplete( + request); + + if (CHECK_FORMATTER_KIND_MASK(eFormatCategoryItemFilter)) + category_sp->GetTypeFiltersContainer()->AutoComplete(request); + if (CHECK_FORMATTER_KIND_MASK(eFormatCategoryItemRegexFilter)) + category_sp->GetRegexTypeFiltersContainer()->AutoComplete(request); + + if (CHECK_FORMATTER_KIND_MASK(eFormatCategoryItemSynth)) + category_sp->GetTypeSyntheticsContainer()->AutoComplete(request); + if (CHECK_FORMATTER_KIND_MASK(eFormatCategoryItemRegexSynth)) + category_sp->GetRegexTypeSyntheticsContainer()->AutoComplete( + request); + return true; + }); + } + protected: virtual bool FormatterSpecificDeletion(ConstString typeCS) { return false; } @@ -785,7 +816,6 @@ protected: if (argc != 1) { result.AppendErrorWithFormat("%s takes 1 arg.\n", m_cmd_name.c_str()); - result.SetStatus(eReturnStatusFailed); return false; } @@ -794,7 +824,6 @@ protected: if (!typeCS) { result.AppendError("empty typenames not allowed"); - result.SetStatus(eReturnStatusFailed); return false; } @@ -832,7 +861,6 @@ protected: return result.Succeeded(); } else { result.AppendErrorWithFormat("no custom formatter for %s.\n", typeA); - result.SetStatus(eReturnStatusFailed); return false; } } @@ -1037,19 +1065,16 @@ protected: result.AppendErrorWithFormat( "syntax error in category regular expression '%s'", m_options.m_category_regex.GetCurrentValueAsRef().str().c_str()); - result.SetStatus(eReturnStatusFailed); return false; } } if (argc == 1) { const char *arg = command.GetArgumentAtIndex(0); - formatter_regex = std::make_unique( - llvm::StringRef::withNullAsEmpty(arg)); + formatter_regex = std::make_unique(arg); if (!formatter_regex->IsValid()) { result.AppendErrorWithFormat("syntax error in regular expression '%s'", arg); - result.SetStatus(eReturnStatusFailed); return false; } } @@ -1066,13 +1091,15 @@ protected: TypeCategoryImpl::ForEachCallbacks foreach; foreach .SetExact([&result, &formatter_regex, &any_printed]( - ConstString name, + const TypeMatcher &type_matcher, const FormatterSharedPointer &format_sp) -> bool { if (formatter_regex) { bool escape = true; - if (name.GetStringRef() == formatter_regex->GetText()) { + if (type_matcher.CreatedBySameMatchString( + ConstString(formatter_regex->GetText()))) { escape = false; - } else if (formatter_regex->Execute(name.GetStringRef())) { + } else if (formatter_regex->Execute( + type_matcher.GetMatchString().GetStringRef())) { escape = false; } @@ -1081,20 +1108,23 @@ protected: } any_printed = true; - result.GetOutputStream().Printf("%s: %s\n", name.AsCString(), - format_sp->GetDescription().c_str()); + result.GetOutputStream().Printf( + "%s: %s\n", type_matcher.GetMatchString().GetCString(), + format_sp->GetDescription().c_str()); return true; }); foreach .SetWithRegex([&result, &formatter_regex, &any_printed]( - const RegularExpression ®ex, + const TypeMatcher &type_matcher, const FormatterSharedPointer &format_sp) -> bool { if (formatter_regex) { bool escape = true; - if (regex.GetText() == formatter_regex->GetText()) { + if (type_matcher.CreatedBySameMatchString( + ConstString(formatter_regex->GetText()))) { escape = false; - } else if (formatter_regex->Execute(regex.GetText())) { + } else if (formatter_regex->Execute( + type_matcher.GetMatchString().GetStringRef())) { escape = false; } @@ -1103,9 +1133,9 @@ protected: } any_printed = true; - result.GetOutputStream().Printf("%s: %s\n", - regex.GetText().str().c_str(), - format_sp->GetDescription().c_str()); + result.GetOutputStream().Printf( + "%s: %s\n", type_matcher.GetMatchString().GetCString(), + format_sp->GetDescription().c_str()); return true; }); @@ -1126,9 +1156,7 @@ protected: bool escape = true; if (category->GetName() == category_regex->GetText()) { escape = false; - } else if (category_regex->Execute( - llvm::StringRef::withNullAsEmpty( - category->GetName()))) { + } else if (category_regex->Execute(category->GetName())) { escape = false; } @@ -1255,7 +1283,6 @@ bool CommandObjectTypeSummaryAdd::Execute_ScriptSummary( if (argc < 1 && !m_options.m_name) { result.AppendErrorWithFormat("%s takes one or more args.\n", m_cmd_name.c_str()); - result.SetStatus(eReturnStatusFailed); return false; } @@ -1267,7 +1294,6 @@ bool CommandObjectTypeSummaryAdd::Execute_ScriptSummary( const char *funct_name = m_options.m_python_function.c_str(); if (!funct_name || !funct_name[0]) { result.AppendError("function name empty.\n"); - result.SetStatus(eReturnStatusFailed); return false; } @@ -1291,7 +1317,6 @@ bool CommandObjectTypeSummaryAdd::Execute_ScriptSummary( if (!interpreter) { result.AppendError("script interpreter missing - unable to generate " "function wrapper.\n"); - result.SetStatus(eReturnStatusFailed); return false; } StringList funct_sl; @@ -1299,13 +1324,11 @@ bool CommandObjectTypeSummaryAdd::Execute_ScriptSummary( std::string funct_name_str; if (!interpreter->GenerateTypeScriptFunction(funct_sl, funct_name_str)) { result.AppendError("unable to generate function wrapper.\n"); - result.SetStatus(eReturnStatusFailed); return false; } if (funct_name_str.empty()) { result.AppendError( "script interpreter failed to generate a valid function name.\n"); - result.SetStatus(eReturnStatusFailed); return false; } @@ -1322,7 +1345,6 @@ bool CommandObjectTypeSummaryAdd::Execute_ScriptSummary( for (auto &entry : command.entries()) { if (entry.ref().empty()) { result.AppendError("empty typenames not allowed"); - result.SetStatus(eReturnStatusFailed); return false; } @@ -1351,7 +1373,6 @@ bool CommandObjectTypeSummaryAdd::Execute_ScriptSummary( m_options.m_category, &error); if (error.Fail()) { result.AppendError(error.AsCString()); - result.SetStatus(eReturnStatusFailed); return false; } } @@ -1362,7 +1383,6 @@ bool CommandObjectTypeSummaryAdd::Execute_ScriptSummary( if (error.Fail()) { result.AppendError(error.AsCString()); result.AppendError("added to types, but not given a name"); - result.SetStatus(eReturnStatusFailed); return false; } } @@ -1379,14 +1399,12 @@ bool CommandObjectTypeSummaryAdd::Execute_StringSummary( if (argc < 1 && !m_options.m_name) { result.AppendErrorWithFormat("%s takes one or more args.\n", m_cmd_name.c_str()); - result.SetStatus(eReturnStatusFailed); return false; } if (!m_options.m_flags.GetShowMembersOneLiner() && m_options.m_format_string.empty()) { result.AppendError("empty summary strings not allowed"); - result.SetStatus(eReturnStatusFailed); return false; } @@ -1397,7 +1415,6 @@ bool CommandObjectTypeSummaryAdd::Execute_StringSummary( // ${var%S} is an endless recursion, prevent it if (strcmp(format_cstr, "${var%S}") == 0) { result.AppendError("recursive summary not allowed"); - result.SetStatus(eReturnStatusFailed); return false; } @@ -1405,13 +1422,11 @@ bool CommandObjectTypeSummaryAdd::Execute_StringSummary( new StringSummaryFormat(m_options.m_flags, format_cstr)); if (!string_format) { result.AppendError("summary creation failed"); - result.SetStatus(eReturnStatusFailed); return false; } if (string_format->m_error.Fail()) { result.AppendErrorWithFormat("syntax error: %s", string_format->m_error.AsCString("")); - result.SetStatus(eReturnStatusFailed); return false; } lldb::TypeSummaryImplSP entry(string_format.release()); @@ -1421,7 +1436,6 @@ bool CommandObjectTypeSummaryAdd::Execute_StringSummary( for (auto &arg_entry : command.entries()) { if (arg_entry.ref().empty()) { result.AppendError("empty typenames not allowed"); - result.SetStatus(eReturnStatusFailed); return false; } ConstString typeCS(arg_entry.ref()); @@ -1432,7 +1446,6 @@ bool CommandObjectTypeSummaryAdd::Execute_StringSummary( if (error.Fail()) { result.AppendError(error.AsCString()); - result.SetStatus(eReturnStatusFailed); return false; } } @@ -1443,7 +1456,6 @@ bool CommandObjectTypeSummaryAdd::Execute_StringSummary( if (error.Fail()) { result.AppendError(error.AsCString()); result.AppendError("added to types, but not given a name"); - result.SetStatus(eReturnStatusFailed); return false; } } @@ -1572,7 +1584,6 @@ bool CommandObjectTypeSummaryAdd::DoExecute(Args &command, return Execute_ScriptSummary(command, result); #else result.AppendError("python is disabled"); - result.SetStatus(eReturnStatusFailed); return false; #endif } @@ -1681,10 +1692,10 @@ protected: if (DataVisualization::NamedSummaryFormats::GetCount() > 0) { result.GetOutputStream().Printf("Named summaries:\n"); DataVisualization::NamedSummaryFormats::ForEach( - [&result](ConstString name, + [&result](const TypeMatcher &type_matcher, const TypeSummaryImplSP &summary_sp) -> bool { result.GetOutputStream().Printf( - "%s: %s\n", name.AsCString(), + "%s: %s\n", type_matcher.GetMatchString().GetCString(), summary_sp->GetDescription().c_str()); return true; }); @@ -1764,6 +1775,14 @@ public: ~CommandObjectTypeCategoryDefine() override = default; + void + HandleArgumentCompletion(CompletionRequest &request, + OptionElementVector &opt_element_vector) override { + CommandCompletions::InvokeCommonCompletionCallbacks( + GetCommandInterpreter(), + CommandCompletions::eTypeCategoryNameCompletion, request, nullptr); + } + protected: bool DoExecute(Args &command, CommandReturnObject &result) override { const size_t argc = command.GetArgumentCount(); @@ -1771,7 +1790,6 @@ protected: if (argc < 1) { result.AppendErrorWithFormat("%s takes 1 or more args.\n", m_cmd_name.c_str()); - result.SetStatus(eReturnStatusFailed); return false; } @@ -1860,6 +1878,14 @@ public: ~CommandObjectTypeCategoryEnable() override = default; + void + HandleArgumentCompletion(CompletionRequest &request, + OptionElementVector &opt_element_vector) override { + CommandCompletions::InvokeCommonCompletionCallbacks( + GetCommandInterpreter(), + CommandCompletions::eTypeCategoryNameCompletion, request, nullptr); + } + protected: bool DoExecute(Args &command, CommandReturnObject &result) override { const size_t argc = command.GetArgumentCount(); @@ -1867,7 +1893,6 @@ protected: if (argc < 1 && m_options.m_language == lldb::eLanguageTypeUnknown) { result.AppendErrorWithFormat("%s takes arguments and/or a language", m_cmd_name.c_str()); - result.SetStatus(eReturnStatusFailed); return false; } @@ -1880,7 +1905,6 @@ protected: if (!typeCS) { result.AppendError("empty category name not allowed"); - result.SetStatus(eReturnStatusFailed); return false; } DataVisualization::Categories::Enable(typeCS); @@ -1922,6 +1946,14 @@ public: ~CommandObjectTypeCategoryDelete() override = default; + void + HandleArgumentCompletion(CompletionRequest &request, + OptionElementVector &opt_element_vector) override { + CommandCompletions::InvokeCommonCompletionCallbacks( + GetCommandInterpreter(), + CommandCompletions::eTypeCategoryNameCompletion, request, nullptr); + } + protected: bool DoExecute(Args &command, CommandReturnObject &result) override { const size_t argc = command.GetArgumentCount(); @@ -1929,7 +1961,6 @@ protected: if (argc < 1) { result.AppendErrorWithFormat("%s takes 1 or more arg.\n", m_cmd_name.c_str()); - result.SetStatus(eReturnStatusFailed); return false; } @@ -1942,7 +1973,6 @@ protected: if (!typeCS) { result.AppendError("empty category name not allowed"); - result.SetStatus(eReturnStatusFailed); return false; } if (!DataVisualization::Categories::Delete(typeCS)) @@ -1953,7 +1983,6 @@ protected: return result.Succeeded(); } else { result.AppendError("cannot delete one or more categories\n"); - result.SetStatus(eReturnStatusFailed); return false; } } @@ -2027,6 +2056,14 @@ public: ~CommandObjectTypeCategoryDisable() override = default; + void + HandleArgumentCompletion(CompletionRequest &request, + OptionElementVector &opt_element_vector) override { + CommandCompletions::InvokeCommonCompletionCallbacks( + GetCommandInterpreter(), + CommandCompletions::eTypeCategoryNameCompletion, request, nullptr); + } + protected: bool DoExecute(Args &command, CommandReturnObject &result) override { const size_t argc = command.GetArgumentCount(); @@ -2034,7 +2071,6 @@ protected: if (argc < 1 && m_options.m_language == lldb::eLanguageTypeUnknown) { result.AppendErrorWithFormat("%s takes arguments and/or a language", m_cmd_name.c_str()); - result.SetStatus(eReturnStatusFailed); return false; } @@ -2048,7 +2084,6 @@ protected: if (!typeCS) { result.AppendError("empty category name not allowed"); - result.SetStatus(eReturnStatusFailed); return false; } DataVisualization::Categories::Disable(typeCS); @@ -2084,6 +2119,16 @@ public: ~CommandObjectTypeCategoryList() override = default; + void + HandleArgumentCompletion(CompletionRequest &request, + OptionElementVector &opt_element_vector) override { + if (request.GetCursorIndex()) + return; + CommandCompletions::InvokeCommonCompletionCallbacks( + GetCommandInterpreter(), + CommandCompletions::eTypeCategoryNameCompletion, request, nullptr); + } + protected: bool DoExecute(Args &command, CommandReturnObject &result) override { const size_t argc = command.GetArgumentCount(); @@ -2092,18 +2137,15 @@ protected: if (argc == 1) { const char *arg = command.GetArgumentAtIndex(0); - regex = std::make_unique( - llvm::StringRef::withNullAsEmpty(arg)); + regex = std::make_unique(arg); if (!regex->IsValid()) { result.AppendErrorWithFormat( "syntax error in category regular expression '%s'", arg); - result.SetStatus(eReturnStatusFailed); return false; } } else if (argc != 0) { result.AppendErrorWithFormat("%s takes 0 or one arg.\n", m_cmd_name.c_str()); - result.SetStatus(eReturnStatusFailed); return false; } @@ -2113,8 +2155,7 @@ protected: bool escape = true; if (regex->GetText() == category_sp->GetName()) { escape = false; - } else if (regex->Execute(llvm::StringRef::withNullAsEmpty( - category_sp->GetName()))) { + } else if (regex->Execute(category_sp->GetName())) { escape = false; } @@ -2222,7 +2263,6 @@ bool CommandObjectTypeSynthAdd::Execute_HandwritePython( for (auto &entry : command.entries()) { if (entry.ref().empty()) { result.AppendError("empty typenames not allowed"); - result.SetStatus(eReturnStatusFailed); return false; } @@ -2245,7 +2285,6 @@ bool CommandObjectTypeSynthAdd::Execute_PythonClass( if (argc < 1) { result.AppendErrorWithFormat("%s takes one or more args.\n", m_cmd_name.c_str()); - result.SetStatus(eReturnStatusFailed); return false; } @@ -2253,7 +2292,6 @@ bool CommandObjectTypeSynthAdd::Execute_PythonClass( result.AppendErrorWithFormat("%s needs either a Python class name or -P to " "directly input Python code.\n", m_cmd_name.c_str()); - result.SetStatus(eReturnStatusFailed); return false; } @@ -2286,7 +2324,6 @@ bool CommandObjectTypeSynthAdd::Execute_PythonClass( for (auto &arg_entry : command.entries()) { if (arg_entry.ref().empty()) { result.AppendError("empty typenames not allowed"); - result.SetStatus(eReturnStatusFailed); return false; } @@ -2295,7 +2332,6 @@ bool CommandObjectTypeSynthAdd::Execute_PythonClass( m_options.m_regex ? eRegexSynth : eRegularSynth, m_options.m_category, &error)) { result.AppendError(error.AsCString()); - result.SetStatus(eReturnStatusFailed); return false; } } @@ -2550,14 +2586,12 @@ protected: if (argc < 1) { result.AppendErrorWithFormat("%s takes one or more args.\n", m_cmd_name.c_str()); - result.SetStatus(eReturnStatusFailed); return false; } if (m_options.m_expr_paths.empty()) { result.AppendErrorWithFormat("%s needs one or more children.\n", m_cmd_name.c_str()); - result.SetStatus(eReturnStatusFailed); return false; } @@ -2587,7 +2621,6 @@ protected: for (auto &arg_entry : command.entries()) { if (arg_entry.ref().empty()) { result.AppendError("empty typenames not allowed"); - result.SetStatus(eReturnStatusFailed); return false; } @@ -2596,7 +2629,6 @@ protected: m_options.m_regex ? eRegexFilter : eRegularFilter, m_options.m_category, &error)) { result.AppendError(error.AsCString()); - result.SetStatus(eReturnStatusFailed); return false; } } @@ -2634,8 +2666,7 @@ protected: class CommandOptions : public OptionGroup { public: - CommandOptions() - : OptionGroup(), m_show_help(false), m_language(eLanguageTypeUnknown) {} + CommandOptions() : OptionGroup() {} ~CommandOptions() override = default; @@ -2672,8 +2703,8 @@ protected: // Options table: Required for subclasses of Options. - bool m_show_help; - lldb::LanguageType m_language; + bool m_show_help = false; + lldb::LanguageType m_language = eLanguageTypeUnknown; }; OptionGroupOptions m_option_group; @@ -2713,7 +2744,7 @@ public: bool DoExecute(llvm::StringRef raw_command_line, CommandReturnObject &result) override { if (raw_command_line.empty()) { - result.SetError( + result.AppendError( "type lookup cannot be invoked without a type name as argument"); return false; } @@ -2844,7 +2875,6 @@ protected: Thread *thread = GetDefaultThread(); if (!thread) { result.AppendError("no default thread"); - result.SetStatus(lldb::eReturnStatusFailed); return false; } @@ -2877,7 +2907,6 @@ protected: return true; } else { result.AppendError("failed to evaluate expression"); - result.SetStatus(lldb::eReturnStatusFailed); return false; } } diff --git a/gnu/llvm/lldb/source/Commands/CommandObjectVersion.cpp b/gnu/llvm/lldb/source/Commands/CommandObjectVersion.cpp index 065cbe4660d..20c2d25b745 100644 --- a/gnu/llvm/lldb/source/Commands/CommandObjectVersion.cpp +++ b/gnu/llvm/lldb/source/Commands/CommandObjectVersion.cpp @@ -20,7 +20,7 @@ CommandObjectVersion::CommandObjectVersion(CommandInterpreter &interpreter) : CommandObjectParsed(interpreter, "version", "Show the LLDB debugger version.", "version") {} -CommandObjectVersion::~CommandObjectVersion() {} +CommandObjectVersion::~CommandObjectVersion() = default; bool CommandObjectVersion::DoExecute(Args &args, CommandReturnObject &result) { if (args.GetArgumentCount() == 0) { @@ -28,7 +28,6 @@ bool CommandObjectVersion::DoExecute(Args &args, CommandReturnObject &result) { result.SetStatus(eReturnStatusSuccessFinishResult); } else { result.AppendError("the version command takes no arguments."); - result.SetStatus(eReturnStatusFailed); } return true; } diff --git a/gnu/llvm/lldb/source/Commands/CommandObjectWatchpoint.cpp b/gnu/llvm/lldb/source/Commands/CommandObjectWatchpoint.cpp index ce4662930a7..d7a446fc366 100644 --- a/gnu/llvm/lldb/source/Commands/CommandObjectWatchpoint.cpp +++ b/gnu/llvm/lldb/source/Commands/CommandObjectWatchpoint.cpp @@ -42,7 +42,6 @@ static bool CheckTargetForWatchpointOperations(Target *target, target->GetProcessSP() && target->GetProcessSP()->IsAlive(); if (!process_is_valid) { result.AppendError("There's no process or it is not alive."); - result.SetStatus(eReturnStatusFailed); return false; } // Target passes our checks, return true. @@ -166,11 +165,7 @@ public: class CommandOptions : public Options { public: - CommandOptions() - : Options(), - m_level(lldb::eDescriptionLevelBrief) // Watchpoint List defaults to - // brief descriptions - {} + CommandOptions() : Options() {} ~CommandOptions() override = default; @@ -206,7 +201,7 @@ public: // Instance variables to hold the values for command options. - lldb::DescriptionLevel m_level; + lldb::DescriptionLevel m_level = lldb::eDescriptionLevelBrief; }; protected: @@ -252,7 +247,6 @@ protected: if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs( target, command, wp_ids)) { result.AppendError("Invalid watchpoints specification."); - result.SetStatus(eReturnStatusFailed); return false; } @@ -292,6 +286,14 @@ public: ~CommandObjectWatchpointEnable() override = default; + void + HandleArgumentCompletion(CompletionRequest &request, + OptionElementVector &opt_element_vector) override { + CommandCompletions::InvokeCommonCompletionCallbacks( + GetCommandInterpreter(), CommandCompletions::eWatchPointIDCompletion, + request, nullptr); + } + protected: bool DoExecute(Args &command, CommandReturnObject &result) override { Target *target = &GetSelectedTarget(); @@ -307,7 +309,6 @@ protected: if (num_watchpoints == 0) { result.AppendError("No watchpoints exist to be enabled."); - result.SetStatus(eReturnStatusFailed); return false; } @@ -324,7 +325,6 @@ protected: if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs( target, command, wp_ids)) { result.AppendError("Invalid watchpoints specification."); - result.SetStatus(eReturnStatusFailed); return false; } @@ -362,6 +362,14 @@ public: ~CommandObjectWatchpointDisable() override = default; + void + HandleArgumentCompletion(CompletionRequest &request, + OptionElementVector &opt_element_vector) override { + CommandCompletions::InvokeCommonCompletionCallbacks( + GetCommandInterpreter(), CommandCompletions::eWatchPointIDCompletion, + request, nullptr); + } + protected: bool DoExecute(Args &command, CommandReturnObject &result) override { Target *target = &GetSelectedTarget(); @@ -376,7 +384,6 @@ protected: if (num_watchpoints == 0) { result.AppendError("No watchpoints exist to be disabled."); - result.SetStatus(eReturnStatusFailed); return false; } @@ -389,7 +396,6 @@ protected: result.SetStatus(eReturnStatusSuccessFinishNoResult); } else { result.AppendError("Disable all watchpoints failed\n"); - result.SetStatus(eReturnStatusFailed); } } else { // Particular watchpoints selected; disable them. @@ -397,7 +403,6 @@ protected: if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs( target, command, wp_ids)) { result.AppendError("Invalid watchpoints specification."); - result.SetStatus(eReturnStatusFailed); return false; } @@ -439,11 +444,19 @@ public: ~CommandObjectWatchpointDelete() override = default; + void + HandleArgumentCompletion(CompletionRequest &request, + OptionElementVector &opt_element_vector) override { + CommandCompletions::InvokeCommonCompletionCallbacks( + GetCommandInterpreter(), CommandCompletions::eWatchPointIDCompletion, + request, nullptr); + } + Options *GetOptions() override { return &m_options; } class CommandOptions : public Options { public: - CommandOptions() : Options(), m_force(false) {} + CommandOptions() : Options() {} ~CommandOptions() override = default; @@ -471,7 +484,7 @@ public: } // Instance variables to hold the values for command options. - bool m_force; + bool m_force = false; }; protected: @@ -489,7 +502,6 @@ protected: if (num_watchpoints == 0) { result.AppendError("No watchpoints exist to be deleted."); - result.SetStatus(eReturnStatusFailed); return false; } @@ -514,7 +526,6 @@ protected: if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(target, command, wp_ids)) { result.AppendError("Invalid watchpoints specification."); - result.SetStatus(eReturnStatusFailed); return false; } @@ -557,11 +568,19 @@ public: ~CommandObjectWatchpointIgnore() override = default; + void + HandleArgumentCompletion(CompletionRequest &request, + OptionElementVector &opt_element_vector) override { + CommandCompletions::InvokeCommonCompletionCallbacks( + GetCommandInterpreter(), CommandCompletions::eWatchPointIDCompletion, + request, nullptr); + } + Options *GetOptions() override { return &m_options; } class CommandOptions : public Options { public: - CommandOptions() : Options(), m_ignore_count(0) {} + CommandOptions() : Options() {} ~CommandOptions() override = default; @@ -593,7 +612,7 @@ public: // Instance variables to hold the values for command options. - uint32_t m_ignore_count; + uint32_t m_ignore_count = 0; }; protected: @@ -611,7 +630,6 @@ protected: if (num_watchpoints == 0) { result.AppendError("No watchpoints exist to be ignored."); - result.SetStatus(eReturnStatusFailed); return false; } @@ -627,7 +645,6 @@ protected: if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs( target, command, wp_ids)) { result.AppendError("Invalid watchpoints specification."); - result.SetStatus(eReturnStatusFailed); return false; } @@ -677,11 +694,19 @@ public: ~CommandObjectWatchpointModify() override = default; + void + HandleArgumentCompletion(CompletionRequest &request, + OptionElementVector &opt_element_vector) override { + CommandCompletions::InvokeCommonCompletionCallbacks( + GetCommandInterpreter(), CommandCompletions::eWatchPointIDCompletion, + request, nullptr); + } + Options *GetOptions() override { return &m_options; } class CommandOptions : public Options { public: - CommandOptions() : Options(), m_condition(), m_condition_passed(false) {} + CommandOptions() : Options(), m_condition() {} ~CommandOptions() override = default; @@ -714,7 +739,7 @@ public: // Instance variables to hold the values for command options. std::string m_condition; - bool m_condition_passed; + bool m_condition_passed = false; }; protected: @@ -732,7 +757,6 @@ protected: if (num_watchpoints == 0) { result.AppendError("No watchpoints exist to be modified."); - result.SetStatus(eReturnStatusFailed); return false; } @@ -746,7 +770,6 @@ protected: if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs( target, command, wp_ids)) { result.AppendError("Invalid watchpoints specification."); - result.SetStatus(eReturnStatusFailed); return false; } @@ -823,6 +846,16 @@ corresponding to the byte size of the data type."); ~CommandObjectWatchpointSetVariable() override = default; + void + HandleArgumentCompletion(CompletionRequest &request, + OptionElementVector &opt_element_vector) override { + if (request.GetCursorIndex() != 0) + return; + CommandCompletions::InvokeCommonCompletionCallbacks( + GetCommandInterpreter(), CommandCompletions::eVariablePathCompletion, + request, nullptr); + } + Options *GetOptions() override { return &m_option_group; } protected: @@ -843,10 +876,8 @@ protected: // If no argument is present, issue an error message. There's no way to // set a watchpoint. if (command.GetArgumentCount() <= 0) { - result.GetErrorStream().Printf("error: required argument missing; " - "specify your program variable to watch " - "for\n"); - result.SetStatus(eReturnStatusFailed); + result.AppendError("required argument missing; " + "specify your program variable to watch for"); return false; } @@ -866,9 +897,7 @@ protected: // A simple watch variable gesture allows only one argument. if (command.GetArgumentCount() != 1) { - result.GetErrorStream().Printf( - "error: specify exactly one variable to watch for\n"); - result.SetStatus(eReturnStatusFailed); + result.AppendError("specify exactly one variable to watch for"); return false; } @@ -905,18 +934,18 @@ protected: // We're in business. // Find out the size of this variable. size = m_option_watchpoint.watch_size == 0 - ? valobj_sp->GetByteSize() + ? valobj_sp->GetByteSize().getValueOr(0) : m_option_watchpoint.watch_size; } compiler_type = valobj_sp->GetCompilerType(); } else { const char *error_cstr = error.AsCString(nullptr); if (error_cstr) - result.GetErrorStream().Printf("error: %s\n", error_cstr); + result.AppendError(error_cstr); else - result.GetErrorStream().Printf("error: unable to find any variable " - "expression path that matches '%s'\n", - command.GetArgumentAtIndex(0)); + result.AppendErrorWithFormat("unable to find any variable " + "expression path that matches '%s'", + command.GetArgumentAtIndex(0)); return false; } @@ -947,7 +976,6 @@ protected: addr, (uint64_t)size, command.GetArgumentAtIndex(0)); if (error.AsCString(nullptr)) result.AppendError(error.AsCString()); - result.SetStatus(eReturnStatusFailed); } return result.Succeeded(); @@ -1037,10 +1065,8 @@ protected: // If no argument is present, issue an error message. There's no way to // set a watchpoint. if (raw_command.trim().empty()) { - result.GetErrorStream().Printf("error: required argument missing; " - "specify an expression to evaluate into " - "the address to watch for\n"); - result.SetStatus(eReturnStatusFailed); + result.AppendError("required argument missing; specify an expression " + "to evaluate into the address to watch for"); return false; } @@ -1067,12 +1093,10 @@ protected: ExpressionResults expr_result = target->EvaluateExpression(expr, frame, valobj_sp, options); if (expr_result != eExpressionCompleted) { - result.GetErrorStream().Printf( - "error: expression evaluation of address to watch failed\n"); - result.GetErrorStream() << "expression evaluated: \n" << expr << "\n"; + result.AppendError("expression evaluation of address to watch failed"); + result.AppendErrorWithFormat("expression evaluated: \n%s", expr.data()); if (valobj_sp && !valobj_sp->GetError().Success()) - result.GetErrorStream() << valobj_sp->GetError().AsCString() << "\n"; - result.SetStatus(eReturnStatusFailed); + result.AppendError(valobj_sp->GetError().AsCString()); return false; } @@ -1080,9 +1104,7 @@ protected: bool success = false; addr = valobj_sp->GetValueAsUnsigned(0, &success); if (!success) { - result.GetErrorStream().Printf( - "error: expression did not evaluate to an address\n"); - result.SetStatus(eReturnStatusFailed); + result.AppendError("expression did not evaluate to an address"); return false; } @@ -1115,7 +1137,6 @@ protected: addr, (uint64_t)size); if (error.AsCString(nullptr)) result.AppendError(error.AsCString()); - result.SetStatus(eReturnStatusFailed); } return result.Succeeded(); diff --git a/gnu/llvm/lldb/source/Commands/CommandObjectWatchpointCommand.cpp b/gnu/llvm/lldb/source/Commands/CommandObjectWatchpointCommand.cpp index fe3052a775a..1f4e9536638 100644 --- a/gnu/llvm/lldb/source/Commands/CommandObjectWatchpointCommand.cpp +++ b/gnu/llvm/lldb/source/Commands/CommandObjectWatchpointCommand.cpp @@ -61,7 +61,9 @@ public: CommandObjectWatchpointCommandAdd(CommandInterpreter &interpreter) : CommandObjectParsed(interpreter, "add", "Add a set of LLDB commands to a watchpoint, to be " - "executed whenever the watchpoint is hit.", + "executed whenever the watchpoint is hit. " + "The commands added to the watchpoint replace any " + "commands previously added to it.", nullptr, eCommandRequiresTarget), IOHandlerDelegateMultiline("DONE", IOHandlerDelegate::Completion::LLDBCommand), @@ -301,7 +303,7 @@ are no syntax errors may indicate that a function was declared but never called. options.SetPrintErrors(true); options.SetAddToHistory(false); - debugger.GetCommandInterpreter().HandleCommands(commands, &exe_ctx, + debugger.GetCommandInterpreter().HandleCommands(commands, exe_ctx, options, result); result.GetImmediateOutputStream()->Flush(); result.GetImmediateErrorStream()->Flush(); @@ -312,10 +314,7 @@ are no syntax errors may indicate that a function was declared but never called. class CommandOptions : public Options { public: - CommandOptions() - : Options(), m_use_commands(false), m_use_script_language(false), - m_script_language(eScriptLanguageNone), m_use_one_liner(false), - m_one_liner(), m_function_name() {} + CommandOptions() : Options(), m_one_liner(), m_function_name() {} ~CommandOptions() override = default; @@ -385,12 +384,12 @@ are no syntax errors may indicate that a function was declared but never called. // Instance variables to hold the values for command options. - bool m_use_commands; - bool m_use_script_language; - lldb::ScriptLanguage m_script_language; + bool m_use_commands = false; + bool m_use_script_language = false; + lldb::ScriptLanguage m_script_language = eScriptLanguageNone; // Instance variables to hold the values for one_liner options. - bool m_use_one_liner; + bool m_use_one_liner = false; std::string m_one_liner; bool m_stop_on_error; std::string m_function_name; @@ -405,7 +404,6 @@ protected: if (num_watchpoints == 0) { result.AppendError("No watchpoints exist to have commands added"); - result.SetStatus(eReturnStatusFailed); return false; } @@ -420,7 +418,6 @@ protected: if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(target, command, valid_wp_ids)) { result.AppendError("Invalid watchpoints specification."); - result.SetStatus(eReturnStatusFailed); return false; } @@ -515,14 +512,12 @@ protected: if (num_watchpoints == 0) { result.AppendError("No watchpoints exist to have commands deleted"); - result.SetStatus(eReturnStatusFailed); return false; } if (command.GetArgumentCount() == 0) { result.AppendError( "No watchpoint specified from which to delete the commands"); - result.SetStatus(eReturnStatusFailed); return false; } @@ -530,7 +525,6 @@ protected: if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(target, command, valid_wp_ids)) { result.AppendError("Invalid watchpoints specification."); - result.SetStatus(eReturnStatusFailed); return false; } @@ -544,7 +538,6 @@ protected: wp->ClearCallback(); } else { result.AppendErrorWithFormat("Invalid watchpoint ID: %u.\n", cur_wp_id); - result.SetStatus(eReturnStatusFailed); return false; } } @@ -587,14 +580,12 @@ protected: if (num_watchpoints == 0) { result.AppendError("No watchpoints exist for which to list commands"); - result.SetStatus(eReturnStatusFailed); return false; } if (command.GetArgumentCount() == 0) { result.AppendError( "No watchpoint specified for which to list the commands"); - result.SetStatus(eReturnStatusFailed); return false; } @@ -602,7 +593,6 @@ protected: if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(target, command, valid_wp_ids)) { result.AppendError("Invalid watchpoints specification."); - result.SetStatus(eReturnStatusFailed); return false; } @@ -634,7 +624,6 @@ protected: } else { result.AppendErrorWithFormat("Invalid watchpoint ID: %u.\n", cur_wp_id); - result.SetStatus(eReturnStatusFailed); } } } diff --git a/gnu/llvm/lldb/source/Commands/CommandOptionsProcessLaunch.cpp b/gnu/llvm/lldb/source/Commands/CommandOptionsProcessLaunch.cpp new file mode 100644 index 00000000000..a618796156a --- /dev/null +++ b/gnu/llvm/lldb/source/Commands/CommandOptionsProcessLaunch.cpp @@ -0,0 +1,147 @@ +//===-- CommandOptionsProcessLaunch.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 "CommandOptionsProcessLaunch.h" + +#include "lldb/Host/FileSystem.h" +#include "lldb/Host/HostInfo.h" +#include "lldb/Host/OptionParser.h" +#include "lldb/Interpreter/CommandCompletions.h" +#include "lldb/Interpreter/OptionArgParser.h" +#include "lldb/Target/ExecutionContext.h" +#include "lldb/Target/Platform.h" +#include "lldb/Target/Target.h" + +#include "llvm/ADT/ArrayRef.h" + +using namespace llvm; +using namespace lldb; +using namespace lldb_private; + +#define LLDB_OPTIONS_process_launch +#include "CommandOptions.inc" + +Status CommandOptionsProcessLaunch::SetOptionValue( + uint32_t option_idx, llvm::StringRef option_arg, + ExecutionContext *execution_context) { + Status error; + const int short_option = g_process_launch_options[option_idx].short_option; + + switch (short_option) { + case 's': // Stop at program entry point + launch_info.GetFlags().Set(eLaunchFlagStopAtEntry); + break; + + case 'i': // STDIN for read only + { + FileAction action; + if (action.Open(STDIN_FILENO, FileSpec(option_arg), true, false)) + launch_info.AppendFileAction(action); + break; + } + + case 'o': // Open STDOUT for write only + { + FileAction action; + if (action.Open(STDOUT_FILENO, FileSpec(option_arg), false, true)) + launch_info.AppendFileAction(action); + break; + } + + case 'e': // STDERR for write only + { + FileAction action; + if (action.Open(STDERR_FILENO, FileSpec(option_arg), false, true)) + launch_info.AppendFileAction(action); + break; + } + + case 'P': // Process plug-in name + launch_info.SetProcessPluginName(option_arg); + break; + + case 'n': // Disable STDIO + { + FileAction action; + const FileSpec dev_null(FileSystem::DEV_NULL); + if (action.Open(STDIN_FILENO, dev_null, true, false)) + launch_info.AppendFileAction(action); + if (action.Open(STDOUT_FILENO, dev_null, false, true)) + launch_info.AppendFileAction(action); + if (action.Open(STDERR_FILENO, dev_null, false, true)) + launch_info.AppendFileAction(action); + break; + } + + case 'w': + launch_info.SetWorkingDirectory(FileSpec(option_arg)); + break; + + case 't': // Open process in new terminal window + launch_info.GetFlags().Set(eLaunchFlagLaunchInTTY); + break; + + case 'a': { + TargetSP target_sp = + execution_context ? execution_context->GetTargetSP() : TargetSP(); + PlatformSP platform_sp = + target_sp ? target_sp->GetPlatform() : PlatformSP(); + launch_info.GetArchitecture() = + Platform::GetAugmentedArchSpec(platform_sp.get(), option_arg); + } break; + + case 'A': // Disable ASLR. + { + bool success; + const bool disable_aslr_arg = + OptionArgParser::ToBoolean(option_arg, true, &success); + if (success) + disable_aslr = disable_aslr_arg ? eLazyBoolYes : eLazyBoolNo; + else + error.SetErrorStringWithFormat( + "Invalid boolean value for disable-aslr option: '%s'", + option_arg.empty() ? "" : option_arg.str().c_str()); + break; + } + + case 'X': // shell expand args. + { + bool success; + const bool expand_args = + OptionArgParser::ToBoolean(option_arg, true, &success); + if (success) + launch_info.SetShellExpandArguments(expand_args); + else + error.SetErrorStringWithFormat( + "Invalid boolean value for shell-expand-args option: '%s'", + option_arg.empty() ? "" : option_arg.str().c_str()); + break; + } + + case 'c': + if (!option_arg.empty()) + launch_info.SetShell(FileSpec(option_arg)); + else + launch_info.SetShell(HostInfo::GetDefaultShell()); + break; + + case 'E': + launch_info.GetEnvironment().insert(option_arg); + break; + + default: + error.SetErrorStringWithFormat("unrecognized short option character '%c'", + short_option); + break; + } + return error; +} + +llvm::ArrayRef CommandOptionsProcessLaunch::GetDefinitions() { + return llvm::makeArrayRef(g_process_launch_options); +} diff --git a/gnu/llvm/lldb/source/Commands/CommandOptionsProcessLaunch.h b/gnu/llvm/lldb/source/Commands/CommandOptionsProcessLaunch.h new file mode 100644 index 00000000000..d18a2324508 --- /dev/null +++ b/gnu/llvm/lldb/source/Commands/CommandOptionsProcessLaunch.h @@ -0,0 +1,49 @@ +//===-- CommandOptionsProcessLaunch.h ---------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SOURCE_COMMANDS_COMMANDOPTIONSPROCESSLAUNCH_H +#define LLDB_SOURCE_COMMANDS_COMMANDOPTIONSPROCESSLAUNCH_H + +#include "lldb/Host/ProcessLaunchInfo.h" +#include "lldb/Interpreter/Options.h" + +namespace lldb_private { + +// CommandOptionsProcessLaunch + +class CommandOptionsProcessLaunch : public lldb_private::OptionGroup { +public: + CommandOptionsProcessLaunch() : lldb_private::OptionGroup() { + // Keep default values of all options in one place: OptionParsingStarting + // () + OptionParsingStarting(nullptr); + } + + ~CommandOptionsProcessLaunch() override = default; + + lldb_private::Status + SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, + lldb_private::ExecutionContext *execution_context) override; + + void OptionParsingStarting( + lldb_private::ExecutionContext *execution_context) override { + launch_info.Clear(); + disable_aslr = lldb_private::eLazyBoolCalculate; + } + + llvm::ArrayRef GetDefinitions() override; + + // Instance variables to hold the values for command options. + + lldb_private::ProcessLaunchInfo launch_info; + lldb_private::LazyBool disable_aslr; +}; // CommandOptionsProcessLaunch + +} // namespace lldb_private + +#endif // LLDB_SOURCE_COMMANDS_COMMANDOPTIONSPROCESSLAUNCH_H diff --git a/gnu/llvm/lldb/source/Commands/Options.td b/gnu/llvm/lldb/source/Commands/Options.td index d6f1e0a3c96..6abb4788bed 100644 --- a/gnu/llvm/lldb/source/Commands/Options.td +++ b/gnu/llvm/lldb/source/Commands/Options.td @@ -105,7 +105,7 @@ let Command = "breakpoint dummy" in { let Command = "breakpoint set" in { def breakpoint_set_shlib : Option<"shlib", "s">, Arg<"ShlibName">, - Completion<"Module">, Groups<[1,2,3,4,5,6,7,8,9,11]>, // *not* in group 10 + Completion<"Module">, Groups<[1,2,3,4,5,6,7,8,9,11,12]>, // *not* in group 10 Desc<"Set the breakpoint only in this shared library. Can repeat this " "option multiple times to specify multiple shared libraries.">; def breakpoint_set_hardware : Option<"hardware", "H">, @@ -125,7 +125,7 @@ let Command = "breakpoint set" in { def breakpoint_set_address : Option<"address", "a">, Group<2>, Arg<"AddressOrExpression">, Required, Desc<"Set the breakpoint at the specified address. If the address maps " - "uniquely toa particular binary, then the address will be converted to " + "uniquely to a particular binary, then the address will be converted to " "a \"file\"address, so that the breakpoint will track that binary+offset " "no matter where the binary eventually loads. Alternately, if you also " "specify the module - with the -s option - then the address will be " @@ -186,21 +186,24 @@ let Command = "breakpoint set" in { "expression (note: currently only implemented for setting breakpoints on " "identifiers). If not set the target.language setting is used.">; def breakpoint_set_skip_prologue : Option<"skip-prologue", "K">, - Arg<"Boolean">, Groups<[1,3,4,5,6,7,8]>, + Arg<"Boolean">, Groups<[1,3,4,5,6,7,8,12]>, Desc<"sKip the prologue if the breakpoint is at the beginning of a " "function. If not set the target.skip-prologue setting is used.">; def breakpoint_set_breakpoint_name : Option<"breakpoint-name", "N">, Arg<"BreakpointName">, Desc<"Adds this to the list of names for this breakpoint.">; def breakpoint_set_address_slide : Option<"address-slide", "R">, - Arg<"Address">, Groups<[1,3,4,5,6,7,8]>, + Arg<"Address">, Groups<[1,3,4,5,6,7,8,12]>, Desc<"Add the specified offset to whatever address(es) the breakpoint " "resolves to. At present this applies the offset directly as given, and " "doesn't try to align it to instruction boundaries.">; def breakpoint_set_move_to_nearest_code : Option<"move-to-nearest-code", "m">, - Groups<[1, 9]>, Arg<"Boolean">, + Groups<[1,9,12]>, Arg<"Boolean">, Desc<"Move breakpoints to nearest code. If not set the " - "target.move-to-nearest-codesetting is used.">; + "target.move-to-nearest-code setting is used.">; + def breakpoint_set_file_colon_line : Option<"joint-specifier", "y">, Group<12>, Arg<"FileLineColumn">, + Required, Completion<"SourceFile">, + Desc<"A specifier in the form filename:line[:column] for setting file & line breakpoints.">; /* Don't add this option till it actually does something useful... def breakpoint_set_exception_typename : Option<"exception-typename", "O">, Arg<"TypeName">, Desc<"The breakpoint will only stop if an " @@ -224,6 +227,9 @@ let Command = "breakpoint delete" in { def breakpoint_delete_dummy_breakpoints : Option<"dummy-breakpoints", "D">, Group<1>, Desc<"Delete Dummy breakpoints - i.e. breakpoints set before a " "file is provided, which prime new targets.">; + def breakpoint_delete_disabled : Option<"disabled", "d">, Group<1>, + Desc<"Delete all breakpoints which are currently disabled. When using the disabled option " + "any breakpoints listed on the command line are EXCLUDED from deletion.">; } let Command = "breakpoint name" in { @@ -321,7 +327,7 @@ let Command = "disassemble" in { def disassemble_options_pc : Option<"pc", "p">, Group<5>, Desc<"Disassemble around the current pc.">; def disassemble_options_line : Option<"line", "l">, Group<6>, - Desc<"Disassemble the current frame's current source line instructions if" + Desc<"Disassemble the current frame's current source line instructions if " "there is debug line table information, else disassemble around the pc.">; def disassemble_options_address : Option<"address", "a">, Group<7>, Arg<"AddressOrExpression">, @@ -366,7 +372,7 @@ let Command = "expression" in { "top-level entities without a $ prefix.">; def expression_options_allow_jit : Option<"allow-jit", "j">, Groups<[1,2]>, Arg<"Boolean">, - Desc<"Controls whether the expression can fall back to being JITted if it's" + Desc<"Controls whether the expression can fall back to being JITted if it's " "not supported by the interpreter (defaults to true).">; } @@ -448,6 +454,12 @@ let Command = "reproducer dump" in { "provided, that reproducer is dumped.">; } +let Command = "reproducer verify" in { + def reproducer_verify_file : Option<"file", "f">, Group<1>, Arg<"Filename">, + Desc<"The reproducer path. If a reproducer is replayed and no path is " + "provided, that reproducer is dumped.">; +} + let Command = "reproducer xcrash" in { def reproducer_signal : Option<"signal", "s">, Group<1>, EnumArg<"None", "ReproducerSignalType()">, @@ -492,6 +504,14 @@ let Command = "memory write" in { Desc<"Start writing bytes from an offset within the input file.">; } +let Command = "memory tag write" in { + def memory_write_end_addr : Option<"end-addr", "e">, Group<1>, + Arg<"AddressOrExpression">, Desc< + "Set tags for start address to end-addr, repeating tags as needed" + " to cover the range. (instead of calculating the range from the" + " number of tags given)">; +} + let Command = "register read" in { def register_read_alternate : Option<"alternate", "A">, Desc<"Display register names using the alternate register name if there " @@ -628,6 +648,39 @@ let Command = "platform shell" in { Desc<"Run the commands on the host shell when enabled.">; def platform_shell_timeout : Option<"timeout", "t">, Arg<"Value">, Desc<"Seconds to wait for the remote host to finish running the command.">; + def platform_shell_interpreter : Option<"shell", "s">, Arg<"Path">, + Desc<"Shell interpreter path. This is the binary used to run the command.">; +} + +let Command = "process launch" in { + def process_launch_stop_at_entry : Option<"stop-at-entry", "s">, + Desc<"Stop at the entry point of the program when launching a process.">; + def process_launch_disable_aslr : Option<"disable-aslr", "A">, Arg<"Boolean">, + Desc<"Set whether to disable address space layout randomization when launching a process.">; + def process_launch_plugin : Option<"plugin", "P">, Arg<"Plugin">, + Desc<"Name of the process plugin you want to use.">; + def process_launch_working_dir : Option<"working-dir", "w">, Arg<"DirectoryName">, + Desc<"Set the current working directory to when running the inferior.">; + def process_launch_arch : Option<"arch", "a">, Arg<"Architecture">, + Desc<"Set the architecture for the process to launch when ambiguous.">; + def process_launch_environment : Option<"environment", "E">, + Arg<"None">, Desc<"Specify an environment variable name/value string " + "(--environment NAME=VALUE). Can be specified multiple times for subsequent " + "environment entries.">; + def process_launch_shell : Option<"shell", "c">, GroupRange<1,3>, + OptionalArg<"Filename">, Desc<"Run the process in a shell (not supported on all platforms).">; + def process_launch_stdin : Option<"stdin", "i">, Group<1>, + Arg<"Filename">, Desc<"Redirect stdin for the process to .">; + def process_launch_stdout : Option<"stdout", "o">, Group<1>, + Arg<"Filename">, Desc<"Redirect stdout for the process to .">; + def process_launch_stderr : Option<"stderr", "e">, Group<1>, + Arg<"Filename">, Desc<"Redirect stderr for the process to .">; + def process_launch_tty : Option<"tty", "t">, Group<2>, + Desc<"Start the process in a terminal (not supported on all platforms).">; + def process_launch_no_stdio : Option<"no-stdio", "n">, Group<3>, + Desc<"Do not set up for terminal I/O to go to running process.">; + def process_launch_shell_expand_args : Option<"shell-expand-args", "X">, Group<4>, + Arg<"Boolean">, Desc<"Set whether to shell expand arguments to the process when launching.">; } let Command = "process attach" in { @@ -685,11 +738,23 @@ let Command = "process status" in { Desc<"Show verbose process status including extended crash information.">; } +let Command = "process save_core" in { + def process_save_core_style : Option<"style", "s">, Group<1>, + EnumArg<"SaveCoreStyle", "SaveCoreStyles()">, Desc<"Request a specific style " + "of corefile to be saved.">; +} + let Command = "script import" in { def script_import_allow_reload : Option<"allow-reload", "r">, Group<1>, Desc<"Allow the script to be loaded even if it was already loaded before. " "This argument exists for backwards compatibility, but reloading is always " "allowed, whether you specify it or not.">; + def relative_to_command_file : Option<"relative-to-command-file", "c">, + Group<1>, Desc<"Resolve non-absolute paths relative to the location of the " + "current command file. This argument can only be used when the command is " + "being sourced from a file.">; + def silent : Option<"silent", "s">, Group<1>, + Desc<"If true don't print any script output while importing.">; } let Command = "script add" in { @@ -706,6 +771,12 @@ let Command = "script add" in { "LLDB event system.">; } +let Command = "script" in { + def script_language : Option<"language", "l">, + EnumArg<"ScriptLang", "ScriptOptionEnum()">, Desc<"Specify the scripting " + " language. If none is specific the default scripting language is used.">; +} + let Command = "source info" in { def source_info_count : Option<"count", "c">, Arg<"Count">, Desc<"The number of line entries to display.">; @@ -729,7 +800,7 @@ let Command = "source info" in { let Command = "source list" in { def source_list_count : Option<"count", "c">, Arg<"Count">, Desc<"The number of source lines to display.">; - def source_list_shlib : Option<"shlib", "s">, Groups<[1,2]>, Arg<"ShlibName">, + def source_list_shlib : Option<"shlib", "s">, Groups<[1,2,5]>, Arg<"ShlibName">, Completion<"Module">, Desc<"Look up the source file in the given shared library.">; def source_list_show_breakpoints : Option<"show-breakpoints", "b">, @@ -747,6 +818,10 @@ let Command = "source list" in { " information for the corresponding file and line.">; def source_list_reverse : Option<"reverse", "r">, Group<4>, Desc<"Reverse the" " listing to look backwards from the last displayed block of source.">; + def source_list_file_colon_line : Option<"joint-specifier", "y">, Group<5>, + Arg<"FileLineColumn">, Completion<"SourceFile">, + Desc<"A specifier in the form filename:line[:column] from which to display" + " source.">; } let Command = "target dependents" in { @@ -855,7 +930,7 @@ let Command = "target modules lookup" in { } let Command = "target stop hook add" in { - def target_stop_hook_add_one_liner : Option<"one-liner", "o">, + def target_stop_hook_add_one_liner : Option<"one-liner", "o">, GroupRange<1,3>, Arg<"OneLiner">, Desc<"Add a command for the stop hook. Can be specified " "more than once, and commands will be run in the order they appear.">; def target_stop_hook_add_shlib : Option<"shlib", "s">, Arg<"ShlibName">, @@ -873,19 +948,19 @@ let Command = "target stop hook add" in { def target_stop_hook_add_queue_name : Option<"queue-name", "q">, Arg<"QueueName">, Desc<"The stop hook is run only for threads in the queue " "whose name is given by this argument.">; - def target_stop_hook_add_file : Option<"file", "f">, Group<1>, + def target_stop_hook_add_file : Option<"file", "f">, Groups<[1,4]>, Arg<"Filename">, Desc<"Specify the source file within which the stop-hook " "is to be run.">, Completion<"SourceFile">; - def target_stop_hook_add_start_line : Option<"start-line", "l">, Group<1>, + def target_stop_hook_add_start_line : Option<"start-line", "l">, Groups<[1,4]>, Arg<"LineNum">, Desc<"Set the start of the line range for which the " "stop-hook is to be run.">; - def target_stop_hook_add_end_line : Option<"end-line", "e">, Group<1>, + def target_stop_hook_add_end_line : Option<"end-line", "e">, Groups<[1,4]>, Arg<"LineNum">, Desc<"Set the end of the line range for which the stop-hook" " is to be run.">; - def target_stop_hook_add_classname : Option<"classname", "c">, Group<2>, + def target_stop_hook_add_classname : Option<"classname", "c">, Groups<[2,5]>, Arg<"ClassName">, Desc<"Specify the class within which the stop-hook is to be run.">; - def target_stop_hook_add_name : Option<"name", "n">, Group<3>, + def target_stop_hook_add_name : Option<"name", "n">, Groups<[3,6]>, Arg<"FunctionName">, Desc<"Set the function name within which the stop hook" " will be run.">, Completion<"Symbol">; def target_stop_hook_add_auto_continue : Option<"auto-continue", "G">, @@ -924,7 +999,7 @@ let Command = "thread step scope" in { EnumArg<"RunMode", "TriRunningModes()">, Desc<"Determine how to run other " "threads while stepping the current thread.">; def thread_step_scope_step_over_regexp : Option<"step-over-regexp", "r">, - Group<1>, Arg<"RegularExpression">, Desc<"A regular expression that defines" + Group<1>, Arg<"RegularExpression">, Desc<"A regular expression that defines " "function names to not to stop at when stepping in.">; def thread_step_scope_step_in_target : Option<"step-in-target", "t">, Group<1>, Arg<"FunctionName">, Desc<"The name of the directly called " @@ -937,10 +1012,10 @@ let Command = "thread until" in { def thread_until_thread : Option<"thread", "t">, Group<1>, Arg<"ThreadIndex">, Desc<"Thread index for the thread for until operation">; def thread_until_run_mode : Option<"run-mode", "m">, Group<1>, - EnumArg<"RunMode", "DuoRunningModes()">, Desc<"Determine how to run other" + EnumArg<"RunMode", "DuoRunningModes()">, Desc<"Determine how to run other " "threads while stepping this one">; def thread_until_address : Option<"address", "a">, Group<1>, - Arg<"AddressOrExpression">, Desc<"Run until we reach the specified address," + Arg<"AddressOrExpression">, Desc<"Run until we reach the specified address, " "or leave the function - can be specified multiple times.">; } @@ -981,6 +1056,33 @@ let Command = "thread plan list" in { Desc<"Display thread plans for unreported threads">; } +let Command = "thread trace dump instructions" in { + def thread_trace_dump_instructions_forwards: Option<"forwards", "f">, Group<1>, + Desc<"If specified, the trace is traversed forwards chronologically " + "starting at the oldest instruction. Otherwise, it starts at the most " + "recent one and the traversal is backwards.">; + def thread_trace_dump_instructions_count : Option<"count", "c">, Group<1>, + Arg<"Count">, + Desc<"The number of instructions to display starting at the most recent " + "instruction, or the oldest if --forwards is provided.">; + def thread_trace_dump_instructions_skip: Option<"skip", "s">, + Group<1>, + Arg<"Index">, + Desc<"How many instruction to skip from the end of the trace to start " + "dumping instructions, or from the beginning if --forwards is provided">; + def thread_trace_dump_instructions_raw : Option<"raw", "r">, + Group<1>, + Desc<"Dump only instruction address without disassembly nor symbol information.">; + def thread_trace_dump_instructions_show_tsc : Option<"tsc", "t">, + Group<1>, + Desc<"For each instruction, print the corresponding timestamp counter if available.">; +} + +let Command = "thread trace dump info" in { + def thread_trace_dump_info_verbose : Option<"verbose", "v">, Group<1>, + Desc<"show verbose thread trace dump info">; +} + let Command = "type summary add" in { def type_summary_add_category : Option<"category", "w">, Arg<"Name">, Desc<"Add this to the given category instead of the default one.">; @@ -1117,7 +1219,7 @@ let Command = "watchpoint list" in { "brief description of the watchpoint (no location info).">; def watchpoint_list_full : Option<"full", "f">, Group<2>, Desc<"Give a full " "description of the watchpoint and its locations.">; - def watchpoint_list_verbose : Option<"verbose", "v">, Group<3>, Desc<"Explain" + def watchpoint_list_verbose : Option<"verbose", "v">, Group<3>, Desc<"Explain " "everything we know about the watchpoint (for debugging debugger bugs).">; } @@ -1154,3 +1256,19 @@ let Command = "watchpoint delete" in { def watchpoint_delete_force : Option<"force", "f">, Group<1>, Desc<"Delete all watchpoints without querying for confirmation.">; } + +let Command = "trace load" in { + def trace_load_verbose : Option<"verbose", "v">, Group<1>, + Desc<"Show verbose trace load logging for debugging the plug-in " + "implementation.">; +} + +let Command = "trace dump" in { + def trace_dump_verbose : Option<"verbose", "v">, Group<1>, + Desc<"Show verbose trace information.">; +} + +let Command = "trace schema" in { + def trace_schema_verbose : Option<"verbose", "v">, Group<1>, + Desc<"Show verbose trace schema logging for debugging the plug-in.">; +} diff --git a/gnu/llvm/lldb/source/Core/Address.cpp b/gnu/llvm/lldb/source/Core/Address.cpp index 9d52f1db891..f0c7e2b34f9 100644 --- a/gnu/llvm/lldb/source/Core/Address.cpp +++ b/gnu/llvm/lldb/source/Core/Address.cpp @@ -7,12 +7,12 @@ //===----------------------------------------------------------------------===// #include "lldb/Core/Address.h" +#include "lldb/Core/Declaration.h" #include "lldb/Core/DumpDataExtractor.h" #include "lldb/Core/Module.h" #include "lldb/Core/ModuleList.h" #include "lldb/Core/Section.h" #include "lldb/Symbol/Block.h" -#include "lldb/Symbol/Declaration.h" #include "lldb/Symbol/LineEntry.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Symbol/Symbol.h" @@ -43,9 +43,9 @@ #include #include -#include -#include -#include +#include +#include +#include namespace lldb_private { class CompileUnit; @@ -65,9 +65,9 @@ static size_t ReadBytes(ExecutionContextScope *exe_scope, TargetSP target_sp(exe_scope->CalculateTarget()); if (target_sp) { Status error; - bool prefer_file_cache = false; - return target_sp->ReadMemory(address, prefer_file_cache, dst, dst_len, - error); + bool force_live_memory = true; + return target_sp->ReadMemory(address, dst, dst_len, error, + force_live_memory); } return 0; } diff --git a/gnu/llvm/lldb/source/Core/AddressRange.cpp b/gnu/llvm/lldb/source/Core/AddressRange.cpp index 0868ac5e088..af6e31a67da 100644 --- a/gnu/llvm/lldb/source/Core/AddressRange.cpp +++ b/gnu/llvm/lldb/source/Core/AddressRange.cpp @@ -8,6 +8,7 @@ #include "lldb/Core/AddressRange.h" #include "lldb/Core/Module.h" +#include "lldb/Core/Section.h" #include "lldb/Target/Target.h" #include "lldb/Utility/ConstString.h" #include "lldb/Utility/FileSpec.h" @@ -18,7 +19,7 @@ #include -#include +#include namespace lldb_private { class SectionList; @@ -27,7 +28,7 @@ class SectionList; using namespace lldb; using namespace lldb_private; -AddressRange::AddressRange() : m_base_addr(), m_byte_size(0) {} +AddressRange::AddressRange() : m_base_addr() {} AddressRange::AddressRange(addr_t file_addr, addr_t byte_size, const SectionList *section_list) @@ -40,16 +41,24 @@ AddressRange::AddressRange(const lldb::SectionSP §ion, addr_t offset, AddressRange::AddressRange(const Address &so_addr, addr_t byte_size) : m_base_addr(so_addr), m_byte_size(byte_size) {} -AddressRange::~AddressRange() {} +AddressRange::~AddressRange() = default; + +bool AddressRange::Contains(const Address &addr) const { + SectionSP range_sect_sp = GetBaseAddress().GetSection(); + SectionSP addr_sect_sp = addr.GetSection(); + if (range_sect_sp) { + if (!addr_sect_sp || + range_sect_sp->GetModule() != addr_sect_sp->GetModule()) + return false; // Modules do not match. + } else if (addr_sect_sp) { + return false; // Range has no module but "addr" does because addr has a + // section + } + // Either the modules match, or both have no module, so it is ok to compare + // the file addresses in this case only. + return ContainsFileAddress(addr); +} -// bool -// AddressRange::Contains (const Address &addr) const -//{ -// const addr_t byte_size = GetByteSize(); -// if (byte_size) -// return addr.GetSection() == m_base_addr.GetSection() && -// (addr.GetOffset() - m_base_addr.GetOffset()) < byte_size; -//} // // bool // AddressRange::Contains (const Address *addr) const diff --git a/gnu/llvm/lldb/source/Core/AddressResolver.cpp b/gnu/llvm/lldb/source/Core/AddressResolver.cpp index 16b849b721d..87b0abd34e5 100644 --- a/gnu/llvm/lldb/source/Core/AddressResolver.cpp +++ b/gnu/llvm/lldb/source/Core/AddressResolver.cpp @@ -17,9 +17,9 @@ class ModuleList; using namespace lldb_private; // AddressResolver: -AddressResolver::AddressResolver() {} +AddressResolver::AddressResolver() = default; -AddressResolver::~AddressResolver() {} +AddressResolver::~AddressResolver() = default; void AddressResolver::ResolveAddressInModules(SearchFilter &filter, ModuleList &modules) { diff --git a/gnu/llvm/lldb/source/Core/AddressResolverFileLine.cpp b/gnu/llvm/lldb/source/Core/AddressResolverFileLine.cpp index b0d8dcdde2d..fb61a6100b0 100644 --- a/gnu/llvm/lldb/source/Core/AddressResolverFileLine.cpp +++ b/gnu/llvm/lldb/source/Core/AddressResolverFileLine.cpp @@ -21,20 +21,18 @@ #include "lldb/lldb-enumerations.h" #include "lldb/lldb-types.h" -#include +#include #include using namespace lldb; using namespace lldb_private; // AddressResolverFileLine: -AddressResolverFileLine::AddressResolverFileLine(const FileSpec &file_spec, - uint32_t line_no, - bool check_inlines) - : AddressResolver(), m_file_spec(file_spec), m_line_number(line_no), - m_inlines(check_inlines) {} +AddressResolverFileLine::AddressResolverFileLine( + SourceLocationSpec location_spec) + : AddressResolver(), m_src_location_spec(location_spec) {} -AddressResolverFileLine::~AddressResolverFileLine() {} +AddressResolverFileLine::~AddressResolverFileLine() = default; Searcher::CallbackReturn AddressResolverFileLine::SearchCallback(SearchFilter &filter, @@ -44,8 +42,9 @@ AddressResolverFileLine::SearchCallback(SearchFilter &filter, Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_BREAKPOINTS)); - cu->ResolveSymbolContext(m_file_spec, m_line_number, m_inlines, false, - eSymbolContextEverything, sc_list); + // TODO: Handle SourceLocationSpec column information + cu->ResolveSymbolContext(m_src_location_spec, eSymbolContextEverything, + sc_list); uint32_t sc_list_size = sc_list.GetSize(); for (uint32_t i = 0; i < sc_list_size; i++) { SymbolContext sc; @@ -55,18 +54,14 @@ AddressResolverFileLine::SearchCallback(SearchFilter &filter, if (line_start.IsValid()) { AddressRange new_range(line_start, byte_size); m_address_ranges.push_back(new_range); - if (log) { - StreamString s; - // new_bp_loc->GetDescription (&s, lldb::eDescriptionLevelVerbose); - // LLDB_LOGF(log, "Added address: %s\n", s.GetData()); - } } else { LLDB_LOGF(log, "error: Unable to resolve address at file address 0x%" PRIx64 " for %s:%d\n", line_start.GetFileAddress(), - m_file_spec.GetFilename().AsCString(""), - m_line_number); + m_src_location_spec.GetFileSpec().GetFilename().AsCString( + ""), + m_src_location_spec.GetLine().getValueOr(0)); } } } @@ -78,6 +73,8 @@ lldb::SearchDepth AddressResolverFileLine::GetDepth() { } void AddressResolverFileLine::GetDescription(Stream *s) { - s->Printf("File and line address - file: \"%s\" line: %u", - m_file_spec.GetFilename().AsCString(""), m_line_number); + s->Printf( + "File and line address - file: \"%s\" line: %u", + m_src_location_spec.GetFileSpec().GetFilename().AsCString(""), + m_src_location_spec.GetLine().getValueOr(0)); } diff --git a/gnu/llvm/lldb/source/Core/CMakeLists.txt b/gnu/llvm/lldb/source/Core/CMakeLists.txt index a4057d11077..65be803addf 100644 --- a/gnu/llvm/lldb/source/Core/CMakeLists.txt +++ b/gnu/llvm/lldb/source/Core/CMakeLists.txt @@ -11,8 +11,8 @@ set(LLDB_LIBEDIT_LIBS) if (LLDB_ENABLE_CURSES) list(APPEND LLDB_CURSES_LIBS ${CURSES_LIBRARIES} ${PANEL_LIBRARIES}) - if(LLVM_ENABLE_TERMINFO AND HAVE_TERMINFO) - list(APPEND LLDB_CURSES_LIBS ${TERMINFO_LIBS}) + if(LLVM_ENABLE_TERMINFO) + list(APPEND LLDB_CURSES_LIBS ${TERMINFO_LIB}) endif() if (LLVM_BUILD_STATIC) list(APPEND LLDB_CURSES_LIBS gpm) @@ -24,9 +24,9 @@ add_lldb_library(lldbCore AddressRange.cpp AddressResolver.cpp AddressResolverFileLine.cpp - AddressResolverName.cpp Communication.cpp Debugger.cpp + Declaration.cpp Disassembler.cpp DumpDataExtractor.cpp DumpRegisterValue.cpp @@ -44,9 +44,11 @@ add_lldb_library(lldbCore ModuleList.cpp Opcode.cpp PluginManager.cpp + Progress.cpp RichManglingContext.cpp SearchFilter.cpp Section.cpp + SourceLocationSpec.cpp SourceManager.cpp StreamAsynchronousIO.cpp StreamFile.cpp @@ -64,6 +66,7 @@ add_lldb_library(lldbCore ValueObjectMemory.cpp ValueObjectRegister.cpp ValueObjectSyntheticFilter.cpp + ValueObjectUpdater.cpp ValueObjectVariable.cpp DEPENDS diff --git a/gnu/llvm/lldb/source/Core/Communication.cpp b/gnu/llvm/lldb/source/Core/Communication.cpp index b358e70b1a9..5640e0510cf 100644 --- a/gnu/llvm/lldb/source/Core/Communication.cpp +++ b/gnu/llvm/lldb/source/Core/Communication.cpp @@ -27,9 +27,9 @@ #include #include -#include -#include -#include +#include +#include +#include using namespace lldb; using namespace lldb_private; @@ -199,9 +199,8 @@ bool Communication::StartReadThread(Status *error_ptr) { LLDB_LOG(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_COMMUNICATION), "{0} Communication::StartReadThread ()", this); - char thread_name[1024]; - snprintf(thread_name, sizeof(thread_name), "", - GetBroadcasterName().AsCString()); + const std::string thread_name = + llvm::formatv("", GetBroadcasterName()); m_read_thread_enabled = true; m_read_thread_did_exit = false; @@ -340,7 +339,7 @@ lldb::thread_result_t Communication::ReadThread(lldb::thread_arg_t p) { } if (error.Fail()) LLDB_LOG(log, "error: {0}, status = {1}", error, - Communication::ConnectionStatusAsCString(status)); + Communication::ConnectionStatusAsString(status)); break; case eConnectionStatusInterrupted: // Synchronization signal from // SynchronizeWithReadThread() @@ -356,7 +355,7 @@ lldb::thread_result_t Communication::ReadThread(lldb::thread_arg_t p) { case eConnectionStatusTimedOut: // Request timed out if (error.Fail()) LLDB_LOG(log, "error: {0}, status = {1}", error, - Communication::ConnectionStatusAsCString(status)); + Communication::ConnectionStatusAsString(status)); break; } } @@ -417,8 +416,8 @@ void Communication::SetConnection(std::unique_ptr connection) { m_connection_sp = std::move(connection); } -const char * -Communication::ConnectionStatusAsCString(lldb::ConnectionStatus status) { +std::string +Communication::ConnectionStatusAsString(lldb::ConnectionStatus status) { switch (status) { case eConnectionStatusSuccess: return "success"; @@ -436,8 +435,5 @@ Communication::ConnectionStatusAsCString(lldb::ConnectionStatus status) { return "interrupted"; } - static char unknown_state_string[64]; - snprintf(unknown_state_string, sizeof(unknown_state_string), - "ConnectionStatus = %i", status); - return unknown_state_string; + return "@" + std::to_string(status); } diff --git a/gnu/llvm/lldb/source/Core/CoreProperties.td b/gnu/llvm/lldb/source/Core/CoreProperties.td index b04738175f3..e4887966040 100644 --- a/gnu/llvm/lldb/source/Core/CoreProperties.td +++ b/gnu/llvm/lldb/source/Core/CoreProperties.td @@ -51,6 +51,10 @@ let Definition = "debugger" in { DefaultEnumValue<"Debugger::eStopDisassemblyTypeNoDebugInfo">, EnumValues<"OptionEnumValues(g_show_disassembly_enum_values)">, Desc<"Control when to display disassembly when displaying a stopped context.">; + def StopDisassemblyMaxSize: Property<"stop-disassembly-max-size", "UInt64">, + Global, + DefaultUnsignedValue<32000>, + Desc<"The size limit to use when disassembling large functions (default: 32KB).">; def StopLineCountAfter: Property<"stop-line-count-after", "SInt64">, Global, DefaultUnsignedValue<3>, @@ -131,4 +135,8 @@ let Definition = "debugger" in { Global, DefaultStringValue<"frame #${frame.index}: ${ansi.fg.yellow}${frame.pc}${ansi.normal}{ ${module.file.basename}{`${function.name-without-args}{${frame.no-debug}${function.pc-offset}}}}{ at ${ansi.fg.cyan}${line.file.basename}${ansi.normal}:${ansi.fg.yellow}${line.number}${ansi.normal}{:${ansi.fg.yellow}${line.column}${ansi.normal}}}{${function.is-optimized} [opt]}{${frame.is-artificial} [artificial]}\\\\n">, Desc<"The default frame format string to use when displaying stack frameinformation for threads from thread backtrace unique.">; + def ShowAutosuggestion: Property<"show-autosuggestion", "Boolean">, + Global, + DefaultFalse, + Desc<"If true, LLDB will show suggestions to complete the command the user typed. Suggestions may be accepted using Ctrl-F.">; } diff --git a/gnu/llvm/lldb/source/Core/Debugger.cpp b/gnu/llvm/lldb/source/Core/Debugger.cpp index 5f4f1e266d8..17c3ba426f7 100644 --- a/gnu/llvm/lldb/source/Core/Debugger.cpp +++ b/gnu/llvm/lldb/source/Core/Debugger.cpp @@ -23,6 +23,7 @@ #include "lldb/Host/Terminal.h" #include "lldb/Host/ThreadLauncher.h" #include "lldb/Interpreter/CommandInterpreter.h" +#include "lldb/Interpreter/CommandReturnObject.h" #include "lldb/Interpreter/OptionValue.h" #include "lldb/Interpreter/OptionValueProperties.h" #include "lldb/Interpreter/OptionValueSInt64.h" @@ -64,13 +65,13 @@ #include "llvm/Support/Threading.h" #include "llvm/Support/raw_ostream.h" +#include +#include +#include #include #include #include #include -#include -#include -#include #include #include @@ -258,6 +259,12 @@ const FormatEntity::Entry *Debugger::GetFrameFormatUnique() const { return m_collection_sp->GetPropertyAtIndexAsFormatEntity(nullptr, idx); } +uint32_t Debugger::GetStopDisassemblyMaxSize() const { + const uint32_t idx = ePropertyStopDisassemblyMaxSize; + return m_collection_sp->GetPropertyAtIndexAsUInt64( + nullptr, idx, g_debugger_properties[idx].default_uint_value); +} + bool Debugger::GetNotifyVoid() const { const uint32_t idx = ePropertyNotiftVoid; return m_collection_sp->GetPropertyAtIndexAsBoolean( @@ -346,6 +353,12 @@ bool Debugger::SetUseColor(bool b) { return ret; } +bool Debugger::GetUseAutosuggestion() const { + const uint32_t idx = ePropertyShowAutosuggestion; + return m_collection_sp->GetPropertyAtIndexAsBoolean( + nullptr, idx, g_debugger_properties[idx].default_uint_value != 0); +} + bool Debugger::GetUseSourceCache() const { const uint32_t idx = ePropertyUseSourceCache; return m_collection_sp->GetPropertyAtIndexAsBoolean( @@ -592,6 +605,17 @@ void Debugger::Destroy(DebuggerSP &debugger_sp) { if (!debugger_sp) return; + CommandInterpreter &cmd_interpreter = debugger_sp->GetCommandInterpreter(); + + if (cmd_interpreter.GetSaveSessionOnQuit()) { + CommandReturnObject result(debugger_sp->GetUseColor()); + cmd_interpreter.SaveTranscript(result); + if (result.Succeeded()) + debugger_sp->GetOutputStream() << result.GetOutputData() << '\n'; + else + debugger_sp->GetErrorStream() << result.GetErrorData() << '\n'; + } + debugger_sp->Clear(); if (g_debugger_list_ptr && g_debugger_list_mutex_ptr) { @@ -649,6 +673,11 @@ TargetSP Debugger::FindTargetWithProcess(Process *process) { return target_sp; } +ConstString Debugger::GetStaticBroadcasterClass() { + static ConstString class_name("lldb.debugger"); + return class_name; +} + Debugger::Debugger(lldb::LogOutputCallback log_callback, void *baton) : UserID(g_unique_id++), Properties(std::make_shared()), @@ -665,10 +694,10 @@ Debugger::Debugger(lldb::LogOutputCallback log_callback, void *baton) m_io_handler_stack(), m_instance_name(), m_loaded_plugins(), m_event_handler_thread(), m_io_handler_thread(), m_sync_broadcaster(nullptr, "lldb.debugger.sync"), + m_broadcaster(m_broadcaster_manager_sp, + GetStaticBroadcasterClass().AsCString()), m_forward_listener_sp(), m_clear_once() { - char instance_cstr[256]; - snprintf(instance_cstr, sizeof(instance_cstr), "debugger_%d", (int)GetID()); - m_instance_name.SetCString(instance_cstr); + m_instance_name.SetString(llvm::formatv("debugger_{0}", GetID()).str()); if (log_callback) m_log_callback_stream_sp = std::make_shared(log_callback, baton); @@ -678,7 +707,16 @@ Debugger::Debugger(lldb::LogOutputCallback log_callback, void *baton) assert(default_platform_sp); m_platform_list.Append(default_platform_sp, true); - m_dummy_target_sp = m_target_list.GetDummyTarget(*this); + // Create the dummy target. + { + ArchSpec arch(Target::GetDefaultArchitecture()); + if (!arch.IsValid()) + arch = HostInfo::GetArchitecture(); + assert(arch.IsValid() && "No valid default or host archspec"); + const bool is_dummy_target = true; + m_dummy_target_sp.reset( + new Target(*this, arch, default_platform_sp, is_dummy_target)); + } assert(m_dummy_target_sp.get() && "Couldn't construct dummy target?"); m_collection_sp->Initialize(g_debugger_properties); @@ -735,12 +773,9 @@ void Debugger::Clear() { StopIOHandlerThread(); StopEventHandlerThread(); m_listener_sp->Clear(); - int num_targets = m_target_list.GetNumTargets(); - for (int i = 0; i < num_targets; i++) { - TargetSP target_sp(m_target_list.GetTargetAtIndex(i)); + for (TargetSP target_sp : m_target_list.Targets()) { if (target_sp) { - ProcessSP process_sp(target_sp->GetProcessSP()); - if (process_sp) + if (ProcessSP process_sp = target_sp->GetProcessSP()) process_sp->Finalize(); target_sp->Destroy(); } @@ -778,7 +813,7 @@ repro::DataRecorder *Debugger::GetInputRecorder() { return m_input_recorder; } void Debugger::SetInputFile(FileSP file_sp, repro::DataRecorder *recorder) { assert(file_sp && file_sp->IsValid()); m_input_recorder = recorder; - m_input_file_sp = file_sp; + m_input_file_sp = std::move(file_sp); // Save away the terminal state if that is relevant, so that we can restore // it in RestoreInputState. SaveInputTerminalState(); @@ -803,24 +838,9 @@ void Debugger::SaveInputTerminalState() { void Debugger::RestoreInputTerminalState() { m_terminal_state.Restore(); } ExecutionContext Debugger::GetSelectedExecutionContext() { - ExecutionContext exe_ctx; - TargetSP target_sp(GetSelectedTarget()); - exe_ctx.SetTargetSP(target_sp); - - if (target_sp) { - ProcessSP process_sp(target_sp->GetProcessSP()); - exe_ctx.SetProcessSP(process_sp); - if (process_sp && !process_sp->IsRunning()) { - ThreadSP thread_sp(process_sp->GetThreadList().GetSelectedThread()); - if (thread_sp) { - exe_ctx.SetThreadSP(thread_sp); - exe_ctx.SetFrameSP(thread_sp->GetSelectedFrame()); - if (exe_ctx.GetFramePtr() == nullptr) - exe_ctx.SetFrameSP(thread_sp->GetStackFrameAtIndex(0)); - } - } - } - return exe_ctx; + bool adopt_selected = true; + ExecutionContextRef exe_ctx_ref(GetSelectedTarget().get(), adopt_selected); + return ExecutionContext(exe_ctx_ref); } void Debugger::DispatchInputInterrupt() { @@ -1133,6 +1153,74 @@ void Debugger::SetLoggingCallback(lldb::LogOutputCallback log_callback, std::make_shared(log_callback, baton); } +ConstString Debugger::ProgressEventData::GetFlavorString() { + static ConstString g_flavor("Debugger::ProgressEventData"); + return g_flavor; +} + +ConstString Debugger::ProgressEventData::GetFlavor() const { + return Debugger::ProgressEventData::GetFlavorString(); +} + +void Debugger::ProgressEventData::Dump(Stream *s) const { + s->Printf(" id = %" PRIu64 ", message = \"%s\"", m_id, m_message.c_str()); + if (m_completed == 0 || m_completed == m_total) + s->Printf(", type = %s", m_completed == 0 ? "start" : "end"); + else + s->PutCString(", type = update"); + // If m_total is UINT64_MAX, there is no progress to report, just "start" + // and "end". If it isn't we will show the completed and total amounts. + if (m_total != UINT64_MAX) + s->Printf(", progress = %" PRIu64 " of %" PRIu64, m_completed, m_total); +} + +const Debugger::ProgressEventData * +Debugger::ProgressEventData::GetEventDataFromEvent(const Event *event_ptr) { + if (event_ptr) + if (const EventData *event_data = event_ptr->GetData()) + if (event_data->GetFlavor() == ProgressEventData::GetFlavorString()) + return static_cast(event_ptr->GetData()); + return nullptr; +} + +static void PrivateReportProgress(Debugger &debugger, uint64_t progress_id, + const std::string &message, + uint64_t completed, uint64_t total, + bool is_debugger_specific) { + // Only deliver progress events if we have any progress listeners. + const uint32_t event_type = Debugger::eBroadcastBitProgress; + if (!debugger.GetBroadcaster().EventTypeHasListeners(event_type)) + return; + EventSP event_sp(new Event(event_type, new Debugger::ProgressEventData( + progress_id, message, completed, + total, is_debugger_specific))); + debugger.GetBroadcaster().BroadcastEvent(event_sp); +} + +void Debugger::ReportProgress(uint64_t progress_id, const std::string &message, + uint64_t completed, uint64_t total, + llvm::Optional debugger_id) { + // Check if this progress is for a specific debugger. + if (debugger_id.hasValue()) { + // It is debugger specific, grab it and deliver the event if the debugger + // still exists. + DebuggerSP debugger_sp = FindDebuggerWithID(*debugger_id); + if (debugger_sp) + PrivateReportProgress(*debugger_sp, progress_id, message, completed, + total, /*is_debugger_specific*/ true); + return; + } + // The progress event is not debugger specific, iterate over all debuggers + // and deliver a progress event to each one. + if (g_debugger_list_ptr && g_debugger_list_mutex_ptr) { + std::lock_guard guard(*g_debugger_list_mutex_ptr); + DebuggerList::iterator pos, end = g_debugger_list_ptr->end(); + for (pos = g_debugger_list_ptr->begin(); pos != end; ++pos) + PrivateReportProgress(*(*pos), progress_id, message, completed, total, + /*is_debugger_specific*/ false); + } +} + bool Debugger::EnableLog(llvm::StringRef channel, llvm::ArrayRef categories, llvm::StringRef log_file, uint32_t log_options, @@ -1160,11 +1248,11 @@ bool Debugger::EnableLog(llvm::StringRef channel, flags |= File::eOpenOptionAppend; else flags |= File::eOpenOptionTruncate; - auto file = FileSystem::Instance().Open( + llvm::Expected file = FileSystem::Instance().Open( FileSpec(log_file), flags, lldb::eFilePermissionsFileDefault, false); if (!file) { - // FIXME: This gets garbled when called from the log command. - error_stream << "Unable to open log file: " << log_file; + error_stream << "Unable to open log file '" << log_file + << "': " << llvm::toString(file.takeError()) << "\n"; return false; } @@ -1565,14 +1653,11 @@ void Debugger::JoinIOHandlerThread() { } } -Target *Debugger::GetSelectedOrDummyTarget(bool prefer_dummy) { - Target *target = nullptr; +Target &Debugger::GetSelectedOrDummyTarget(bool prefer_dummy) { if (!prefer_dummy) { - target = m_target_list.GetSelectedTarget().get(); - if (target) - return target; + if (TargetSP target = m_target_list.GetSelectedTarget()) + return *target; } - return GetDummyTarget(); } diff --git a/gnu/llvm/lldb/source/Core/Declaration.cpp b/gnu/llvm/lldb/source/Core/Declaration.cpp new file mode 100644 index 00000000000..579a3999d14 --- /dev/null +++ b/gnu/llvm/lldb/source/Core/Declaration.cpp @@ -0,0 +1,83 @@ +//===-- Declaration.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 "lldb/Core/Declaration.h" +#include "lldb/Utility/Stream.h" + +using namespace lldb_private; + +void Declaration::Dump(Stream *s, bool show_fullpaths) const { + if (m_file) { + *s << ", decl = "; + if (show_fullpaths) + *s << m_file; + else + *s << m_file.GetFilename(); + if (m_line > 0) + s->Printf(":%u", m_line); + if (m_column != LLDB_INVALID_COLUMN_NUMBER) + s->Printf(":%u", m_column); + } else { + if (m_line > 0) { + s->Printf(", line = %u", m_line); + if (m_column != LLDB_INVALID_COLUMN_NUMBER) + s->Printf(":%u", m_column); + } else if (m_column != LLDB_INVALID_COLUMN_NUMBER) + s->Printf(", column = %u", m_column); + } +} + +bool Declaration::DumpStopContext(Stream *s, bool show_fullpaths) const { + if (m_file) { + if (show_fullpaths) + *s << m_file; + else + m_file.GetFilename().Dump(s); + + if (m_line > 0) + s->Printf(":%u", m_line); + if (m_column != LLDB_INVALID_COLUMN_NUMBER) + s->Printf(":%u", m_column); + return true; + } else if (m_line > 0) { + s->Printf(" line %u", m_line); + if (m_column != LLDB_INVALID_COLUMN_NUMBER) + s->Printf(":%u", m_column); + return true; + } + return false; +} + +size_t Declaration::MemorySize() const { return sizeof(Declaration); } + +int Declaration::Compare(const Declaration &a, const Declaration &b) { + int result = FileSpec::Compare(a.m_file, b.m_file, true); + if (result) + return result; + if (a.m_line < b.m_line) + return -1; + else if (a.m_line > b.m_line) + return 1; + if (a.m_column < b.m_column) + return -1; + else if (a.m_column > b.m_column) + return 1; + return 0; +} + +bool Declaration::FileAndLineEqual(const Declaration &declaration) const { + int file_compare = FileSpec::Compare(this->m_file, declaration.m_file, true); + return file_compare == 0 && this->m_line == declaration.m_line; +} + +bool lldb_private::operator==(const Declaration &lhs, const Declaration &rhs) { + if (lhs.GetColumn() != rhs.GetColumn()) + return false; + + return lhs.GetLine() == rhs.GetLine() && lhs.GetFile() == rhs.GetFile(); +} diff --git a/gnu/llvm/lldb/source/Core/Disassembler.cpp b/gnu/llvm/lldb/source/Core/Disassembler.cpp index 4da823c7a24..704b3df4b2a 100644 --- a/gnu/llvm/lldb/source/Core/Disassembler.cpp +++ b/gnu/llvm/lldb/source/Core/Disassembler.cpp @@ -48,7 +48,7 @@ #include #include -#include +#include #define DEFAULT_DISASM_BYTE_SIZE 32 @@ -58,9 +58,7 @@ using namespace lldb_private; DisassemblerSP Disassembler::FindPlugin(const ArchSpec &arch, const char *flavor, const char *plugin_name) { - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer(func_cat, - "Disassembler::FindPlugin (arch = %s, plugin_name = %s)", + LLDB_SCOPED_TIMERF("Disassembler::FindPlugin (arch = %s, plugin_name = %s)", arch.GetArchitectureName(), plugin_name); DisassemblerCreateInstance create_callback = nullptr; @@ -124,7 +122,7 @@ static Address ResolveAddress(Target &target, const Address &addr) { lldb::DisassemblerSP Disassembler::DisassembleRange( const ArchSpec &arch, const char *plugin_name, const char *flavor, - Target &target, const AddressRange &range, bool prefer_file_cache) { + Target &target, const AddressRange &range, bool force_live_memory) { if (range.GetByteSize() <= 0) return {}; @@ -139,7 +137,7 @@ lldb::DisassemblerSP Disassembler::DisassembleRange( const size_t bytes_disassembled = disasm_sp->ParseInstructions( target, range.GetBaseAddress(), {Limit::Bytes, range.GetByteSize()}, - nullptr, prefer_file_cache); + nullptr, force_live_memory); if (bytes_disassembled == 0) return {}; @@ -183,9 +181,9 @@ bool Disassembler::Disassemble(Debugger &debugger, const ArchSpec &arch, if (!disasm_sp) return false; - const bool prefer_file_cache = false; + const bool force_live_memory = true; size_t bytes_disassembled = disasm_sp->ParseInstructions( - exe_ctx.GetTargetRef(), address, limit, &strm, prefer_file_cache); + exe_ctx.GetTargetRef(), address, limit, &strm, force_live_memory); if (bytes_disassembled == 0) return false; @@ -540,34 +538,29 @@ void Disassembler::PrintInstructions(Debugger &debugger, const ArchSpec &arch, } bool Disassembler::Disassemble(Debugger &debugger, const ArchSpec &arch, - const char *plugin_name, const char *flavor, - const ExecutionContext &exe_ctx, - uint32_t num_instructions, - bool mixed_source_and_assembly, - uint32_t num_mixed_context_lines, - uint32_t options, Stream &strm) { + StackFrame &frame, Stream &strm) { AddressRange range; - StackFrame *frame = exe_ctx.GetFramePtr(); - if (frame) { - SymbolContext sc( - frame->GetSymbolContext(eSymbolContextFunction | eSymbolContextSymbol)); - if (sc.function) { - range = sc.function->GetAddressRange(); - } else if (sc.symbol && sc.symbol->ValueIsAddress()) { - range.GetBaseAddress() = sc.symbol->GetAddressRef(); - range.SetByteSize(sc.symbol->GetByteSize()); - } else { - range.GetBaseAddress() = frame->GetFrameCodeAddress(); - } + SymbolContext sc( + frame.GetSymbolContext(eSymbolContextFunction | eSymbolContextSymbol)); + if (sc.function) { + range = sc.function->GetAddressRange(); + } else if (sc.symbol && sc.symbol->ValueIsAddress()) { + range.GetBaseAddress() = sc.symbol->GetAddressRef(); + range.SetByteSize(sc.symbol->GetByteSize()); + } else { + range.GetBaseAddress() = frame.GetFrameCodeAddress(); + } if (range.GetBaseAddress().IsValid() && range.GetByteSize() == 0) range.SetByteSize(DEFAULT_DISASM_BYTE_SIZE); - } - return Disassemble( - debugger, arch, plugin_name, flavor, exe_ctx, range.GetBaseAddress(), - {Limit::Instructions, num_instructions}, mixed_source_and_assembly, - num_mixed_context_lines, options, strm); + Disassembler::Limit limit = {Disassembler::Limit::Bytes, + range.GetByteSize()}; + if (limit.value == 0) + limit.value = DEFAULT_DISASM_BYTE_SIZE; + + return Disassemble(debugger, arch, nullptr, nullptr, frame, + range.GetBaseAddress(), limit, false, 0, 0, strm); } Instruction::Instruction(const Address &address, AddressClass addr_class) @@ -957,6 +950,13 @@ InstructionSP InstructionList::GetInstructionAtIndex(size_t idx) const { return inst_sp; } +InstructionSP InstructionList::GetInstructionAtAddress(const Address &address) { + uint32_t index = GetIndexOfInstructionAtAddress(address); + if (index != UINT32_MAX) + return GetInstructionAtIndex(index); + return nullptr; +} + void InstructionList::Dump(Stream *s, bool show_address, bool show_bytes, const ExecutionContext *exe_ctx) { const uint32_t max_opcode_byte_size = GetMaxOpcocdeByteSize(); @@ -990,17 +990,15 @@ void InstructionList::Append(lldb::InstructionSP &inst_sp) { uint32_t InstructionList::GetIndexOfNextBranchInstruction(uint32_t start, - Target &target, bool ignore_calls, bool *found_calls) const { size_t num_instructions = m_instructions.size(); uint32_t next_branch = UINT32_MAX; - size_t i; if (found_calls) *found_calls = false; - for (i = start; i < num_instructions; i++) { + for (size_t i = start; i < num_instructions; i++) { if (m_instructions[i]->DoesBranch()) { if (ignore_calls && m_instructions[i]->IsCall()) { if (found_calls) @@ -1012,42 +1010,6 @@ InstructionList::GetIndexOfNextBranchInstruction(uint32_t start, } } - // Hexagon needs the first instruction of the packet with the branch. Go - // backwards until we find an instruction marked end-of-packet, or until we - // hit start. - if (target.GetArchitecture().GetTriple().getArch() == llvm::Triple::hexagon) { - // If we didn't find a branch, find the last packet start. - if (next_branch == UINT32_MAX) { - i = num_instructions - 1; - } - - while (i > start) { - --i; - - Status error; - uint32_t inst_bytes; - bool prefer_file_cache = false; // Read from process if process is running - lldb::addr_t load_addr = LLDB_INVALID_ADDRESS; - target.ReadMemory(m_instructions[i]->GetAddress(), prefer_file_cache, - &inst_bytes, sizeof(inst_bytes), error, &load_addr); - // If we have an error reading memory, return start - if (!error.Success()) - return start; - // check if this is the last instruction in a packet bits 15:14 will be - // 11b or 00b for a duplex - if (((inst_bytes & 0xC000) == 0xC000) || - ((inst_bytes & 0xC000) == 0x0000)) { - // instruction after this should be the start of next packet - next_branch = i + 1; - break; - } - } - - if (next_branch == UINT32_MAX) { - // We couldn't find the previous packet, so return start - next_branch = start; - } - } return next_branch; } @@ -1074,7 +1036,7 @@ InstructionList::GetIndexOfInstructionAtLoadAddress(lldb::addr_t load_addr, size_t Disassembler::ParseInstructions(Target &target, Address start, Limit limit, Stream *error_strm_ptr, - bool prefer_file_cache) { + bool force_live_memory) { m_instruction_list.Clear(); if (!start.IsValid()) @@ -1090,8 +1052,8 @@ size_t Disassembler::ParseInstructions(Target &target, Address start, Status error; lldb::addr_t load_addr = LLDB_INVALID_ADDRESS; const size_t bytes_read = - target.ReadMemory(start, prefer_file_cache, data_sp->GetBytes(), - data_sp->GetByteSize(), error, &load_addr); + target.ReadMemory(start, data_sp->GetBytes(), data_sp->GetByteSize(), + error, force_live_memory, &load_addr); const bool data_from_file = load_addr == LLDB_INVALID_ADDRESS; if (bytes_read == 0) { diff --git a/gnu/llvm/lldb/source/Core/DumpDataExtractor.cpp b/gnu/llvm/lldb/source/Core/DumpDataExtractor.cpp index dbfedfae27a..175ffef04a8 100644 --- a/gnu/llvm/lldb/source/Core/DumpDataExtractor.cpp +++ b/gnu/llvm/lldb/source/Core/DumpDataExtractor.cpp @@ -14,8 +14,10 @@ #include "lldb/Core/Address.h" #include "lldb/Core/Disassembler.h" #include "lldb/Core/ModuleList.h" +#include "lldb/Target/ABI.h" #include "lldb/Target/ExecutionContext.h" #include "lldb/Target/ExecutionContextScope.h" +#include "lldb/Target/Process.h" #include "lldb/Target/SectionLoadList.h" #include "lldb/Target/Target.h" #include "lldb/Utility/DataExtractor.h" @@ -32,10 +34,10 @@ #include #include -#include -#include -#include -#include +#include +#include +#include +#include #include #include @@ -50,7 +52,9 @@ static float half2float(uint16_t half) { float f; uint32_t u; } u; - int32_t v = (int16_t)half; + // Sign extend to 4 byte. + int32_t sign_extended = static_cast(half); + uint32_t v = static_cast(sign_extended); if (0 == (v & 0x7c00)) { u.u = v & 0x80007FFFU; @@ -112,7 +116,7 @@ static lldb::offset_t DumpAPInt(Stream *s, const DataExtractor &data, bool is_signed, unsigned radix) { llvm::Optional apint = GetAPInt(data, &offset, byte_size); if (apint.hasValue()) { - std::string apint_str(apint.getValue().toString(radix, is_signed)); + std::string apint_str = toString(apint.getValue(), radix, is_signed); switch (radix) { case 2: s->Write("0b", 2); @@ -226,6 +230,29 @@ static void DumpCharacter(Stream &s, const char c) { s.Printf("\\x%2.2x", c); } +/// Dump a floating point type. +template +void DumpFloatingPoint(std::ostringstream &ss, FloatT f) { + static_assert(std::is_floating_point::value, + "Only floating point types can be dumped."); + // NaN and Inf are potentially implementation defined and on Darwin it + // seems NaNs are printed without their sign. Manually implement dumping them + // here to avoid having to deal with platform differences. + if (std::isnan(f)) { + if (std::signbit(f)) + ss << '-'; + ss << "nan"; + return; + } + if (std::isinf(f)) { + if (std::signbit(f)) + ss << '-'; + ss << "inf"; + return; + } + ss << f; +} + lldb::offset_t lldb_private::DumpDataExtractor( const DataExtractor &DE, Stream *s, offset_t start_offset, lldb::Format item_format, size_t item_byte_size, size_t item_count, @@ -566,14 +593,14 @@ lldb::offset_t lldb_private::DumpDataExtractor( f = DE.GetFloat(&offset); } ss.precision(std::numeric_limits::digits10); - ss << f; + DumpFloatingPoint(ss, f); } else if (item_byte_size == sizeof(double)) { ss.precision(std::numeric_limits::digits10); - ss << DE.GetDouble(&offset); + DumpFloatingPoint(ss, DE.GetDouble(&offset)); } else if (item_byte_size == sizeof(long double) || item_byte_size == 10) { ss.precision(std::numeric_limits::digits10); - ss << DE.GetLongDouble(&offset); + DumpFloatingPoint(ss, DE.GetLongDouble(&offset)); } else { s->Printf("error: unsupported byte size (%" PRIu64 ") for float format", @@ -611,6 +638,21 @@ lldb::offset_t lldb_private::DumpDataExtractor( so_addr.SetOffset(addr); so_addr.Dump(s, exe_scope, Address::DumpStyleResolvedPointerDescription); + if (ProcessSP process_sp = exe_scope->CalculateProcess()) { + if (ABISP abi_sp = process_sp->GetABI()) { + addr_t addr_fixed = abi_sp->FixCodeAddress(addr); + if (target_sp->GetSectionLoadList().ResolveLoadAddress( + addr_fixed, so_addr)) { + s->PutChar(' '); + s->Printf("(0x%*.*" PRIx64 ")", (int)(2 * item_byte_size), + (int)(2 * item_byte_size), addr_fixed); + s->PutChar(' '); + so_addr.Dump(s, exe_scope, + Address::DumpStyleResolvedDescription, + Address::DumpStyleModuleWithFileAddress); + } + } + } } } } diff --git a/gnu/llvm/lldb/source/Core/DynamicLoader.cpp b/gnu/llvm/lldb/source/Core/DynamicLoader.cpp index ceccbe437e1..10d2b720701 100644 --- a/gnu/llvm/lldb/source/Core/DynamicLoader.cpp +++ b/gnu/llvm/lldb/source/Core/DynamicLoader.cpp @@ -24,7 +24,7 @@ #include -#include +#include using namespace lldb; using namespace lldb_private; @@ -60,8 +60,6 @@ DynamicLoader *DynamicLoader::FindPlugin(Process *process, DynamicLoader::DynamicLoader(Process *process) : m_process(process) {} -DynamicLoader::~DynamicLoader() = default; - // Accessosors to the global setting as to whether to stop at image (shared // library) loading/unloading. diff --git a/gnu/llvm/lldb/source/Core/EmulateInstruction.cpp b/gnu/llvm/lldb/source/Core/EmulateInstruction.cpp index f7f56e9fc54..9b911140820 100644 --- a/gnu/llvm/lldb/source/Core/EmulateInstruction.cpp +++ b/gnu/llvm/lldb/source/Core/EmulateInstruction.cpp @@ -30,8 +30,8 @@ #include #include -#include -#include +#include +#include namespace lldb_private { class Target; diff --git a/gnu/llvm/lldb/source/Core/FileLineResolver.cpp b/gnu/llvm/lldb/source/Core/FileLineResolver.cpp index 37435f9e904..2cf7007165b 100644 --- a/gnu/llvm/lldb/source/Core/FileLineResolver.cpp +++ b/gnu/llvm/lldb/source/Core/FileLineResolver.cpp @@ -29,7 +29,7 @@ FileLineResolver::FileLineResolver(const FileSpec &file_spec, uint32_t line_no, : Searcher(), m_file_spec(file_spec), m_line_number(line_no), m_inlines(check_inlines) {} -FileLineResolver::~FileLineResolver() {} +FileLineResolver::~FileLineResolver() = default; Searcher::CallbackReturn FileLineResolver::SearchCallback(SearchFilter &filter, SymbolContext &context, diff --git a/gnu/llvm/lldb/source/Core/FileSpecList.cpp b/gnu/llvm/lldb/source/Core/FileSpecList.cpp index 3ada7b495fd..1a1cf284ea0 100644 --- a/gnu/llvm/lldb/source/Core/FileSpecList.cpp +++ b/gnu/llvm/lldb/source/Core/FileSpecList.cpp @@ -13,7 +13,7 @@ #include -#include +#include using namespace lldb_private; using namespace std; diff --git a/gnu/llvm/lldb/source/Core/IOHandler.cpp b/gnu/llvm/lldb/source/Core/IOHandler.cpp index 6cf09aaa7f9..c6f05d43a2a 100644 --- a/gnu/llvm/lldb/source/Core/IOHandler.cpp +++ b/gnu/llvm/lldb/source/Core/IOHandler.cpp @@ -18,6 +18,7 @@ #include "lldb/Host/Config.h" #include "lldb/Host/File.h" #include "lldb/Utility/Predicate.h" +#include "lldb/Utility/ReproducerProvider.h" #include "lldb/Utility/Status.h" #include "lldb/Utility/StreamString.h" #include "lldb/Utility/StringList.h" @@ -37,13 +38,13 @@ #include #include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include #include using namespace lldb; @@ -102,11 +103,11 @@ FILE *IOHandler::GetErrorFILE() { return (m_error_sp ? m_error_sp->GetFile().GetStream() : nullptr); } -FileSP &IOHandler::GetInputFileSP() { return m_input_sp; } +FileSP IOHandler::GetInputFileSP() { return m_input_sp; } -StreamFileSP &IOHandler::GetOutputStreamFileSP() { return m_output_sp; } +StreamFileSP IOHandler::GetOutputStreamFileSP() { return m_output_sp; } -StreamFileSP &IOHandler::GetErrorStreamFileSP() { return m_error_sp; } +StreamFileSP IOHandler::GetErrorStreamFileSP() { return m_error_sp; } bool IOHandler::GetIsInteractive() { return GetInputFileSP() ? GetInputFileSP()->GetIsInteractive() : false; @@ -195,6 +196,14 @@ void IOHandlerConfirm::IOHandlerInputComplete(IOHandler &io_handler, } } +llvm::Optional +IOHandlerDelegate::IOHandlerSuggestion(IOHandler &io_handler, + llvm::StringRef line) { + return io_handler.GetDebugger() + .GetCommandInterpreter() + .GetAutoSuggestionForCommand(line); +} + void IOHandlerDelegate::IOHandlerComplete(IOHandler &io_handler, CompletionRequest &request) { switch (m_completion) { @@ -256,15 +265,31 @@ IOHandlerEditline::IOHandlerEditline( m_editline_up = std::make_unique(editline_name, GetInputFILE(), GetOutputFILE(), GetErrorFILE(), m_color_prompts); - m_editline_up->SetIsInputCompleteCallback(IsInputCompleteCallback, this); - m_editline_up->SetAutoCompleteCallback(AutoCompleteCallback, this); + m_editline_up->SetIsInputCompleteCallback( + [this](Editline *editline, StringList &lines) { + return this->IsInputCompleteCallback(editline, lines); + }); + + m_editline_up->SetAutoCompleteCallback([this](CompletionRequest &request) { + this->AutoCompleteCallback(request); + }); + + if (debugger.GetUseAutosuggestion() && debugger.GetUseColor()) { + m_editline_up->SetSuggestionCallback([this](llvm::StringRef line) { + return this->SuggestionCallback(line); + }); + } // See if the delegate supports fixing indentation const char *indent_chars = delegate.IOHandlerGetFixIndentationCharacters(); if (indent_chars) { // The delegate does support indentation, hook it up so when any // indentation character is typed, the delegate gets a chance to fix it - m_editline_up->SetFixIndentationCallback(FixIndentationCallback, this, - indent_chars); + FixIndentationCallbackType f = [this](Editline *editline, + const StringList &lines, + int cursor_position) { + return this->FixIndentationCallback(editline, lines, cursor_position); + }; + m_editline_up->SetFixIndentationCallback(std::move(f), indent_chars); } } #endif @@ -414,27 +439,23 @@ bool IOHandlerEditline::GetLine(std::string &line, bool &interrupted) { #if LLDB_ENABLE_LIBEDIT bool IOHandlerEditline::IsInputCompleteCallback(Editline *editline, - StringList &lines, - void *baton) { - IOHandlerEditline *editline_reader = (IOHandlerEditline *)baton; - return editline_reader->m_delegate.IOHandlerIsInputComplete(*editline_reader, - lines); + StringList &lines) { + return m_delegate.IOHandlerIsInputComplete(*this, lines); } int IOHandlerEditline::FixIndentationCallback(Editline *editline, const StringList &lines, - int cursor_position, - void *baton) { - IOHandlerEditline *editline_reader = (IOHandlerEditline *)baton; - return editline_reader->m_delegate.IOHandlerFixIndentation( - *editline_reader, lines, cursor_position); -} - -void IOHandlerEditline::AutoCompleteCallback(CompletionRequest &request, - void *baton) { - IOHandlerEditline *editline_reader = (IOHandlerEditline *)baton; - if (editline_reader) - editline_reader->m_delegate.IOHandlerComplete(*editline_reader, request); + int cursor_position) { + return m_delegate.IOHandlerFixIndentation(*this, lines, cursor_position); +} + +llvm::Optional +IOHandlerEditline::SuggestionCallback(llvm::StringRef line) { + return m_delegate.IOHandlerSuggestion(*this, line); +} + +void IOHandlerEditline::AutoCompleteCallback(CompletionRequest &request) { + m_delegate.IOHandlerComplete(*this, request); } #endif diff --git a/gnu/llvm/lldb/source/Core/IOHandlerCursesGUI.cpp b/gnu/llvm/lldb/source/Core/IOHandlerCursesGUI.cpp index f8fc9177219..4bed788d486 100644 --- a/gnu/llvm/lldb/source/Core/IOHandlerCursesGUI.cpp +++ b/gnu/llvm/lldb/source/Core/IOHandlerCursesGUI.cpp @@ -10,9 +10,14 @@ #include "lldb/Host/Config.h" #if LLDB_ENABLE_CURSES +#if CURSES_HAVE_NCURSES_CURSES_H +#include +#include +#else #include #include #endif +#endif #if defined(__APPLE__) #include @@ -21,6 +26,7 @@ #include "lldb/Core/Debugger.h" #include "lldb/Core/StreamFile.h" +#include "lldb/Core/ValueObjectUpdater.h" #include "lldb/Host/File.h" #include "lldb/Utility/Predicate.h" #include "lldb/Utility/Status.h" @@ -34,6 +40,7 @@ #if LLDB_ENABLE_CURSES #include "lldb/Breakpoint/BreakpointLocation.h" #include "lldb/Core/Module.h" +#include "lldb/Core/PluginManager.h" #include "lldb/Core/ValueObject.h" #include "lldb/Core/ValueObjectRegister.h" #include "lldb/Symbol/Block.h" @@ -58,13 +65,13 @@ #include #include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include #include using namespace lldb; @@ -79,6 +86,8 @@ using llvm::StringRef; #define KEY_RETURN 10 #define KEY_ESCAPE 27 +#define KEY_SHIFT_TAB (KEY_MAX + 1) + namespace curses { class Menu; class MenuDelegate; @@ -268,6 +277,32 @@ struct KeyHelp { const char *description; }; +// COLOR_PAIR index names +enum { + // First 16 colors are 8 black background and 8 blue background colors, + // needed by OutputColoredStringTruncated(). + BlackOnBlack = 1, + RedOnBlack, + GreenOnBlack, + YellowOnBlack, + BlueOnBlack, + MagentaOnBlack, + CyanOnBlack, + WhiteOnBlack, + BlackOnBlue, + RedOnBlue, + GreenOnBlue, + YellowOnBlue, + BlueOnBlue, + MagentaOnBlue, + CyanOnBlue, + WhiteOnBlue, + // Other colors, as needed. + BlackOnWhite, + MagentaOnWhite, + LastColorPairIndex = MagentaOnWhite +}; + class WindowDelegate { public: virtual ~WindowDelegate() = default; @@ -304,17 +339,236 @@ protected: int m_first_visible_line; }; -class Window { +// A surface is an abstraction for something than can be drawn on. The surface +// have a width, a height, a cursor position, and a multitude of drawing +// operations. This type should be sub-classed to get an actually useful ncurses +// object, such as a Window, SubWindow, Pad, or a SubPad. +class Surface { +public: + Surface() : m_window(nullptr) {} + + WINDOW *get() { return m_window; } + + operator WINDOW *() { return m_window; } + + // Copy a region of the surface to another surface. + void CopyToSurface(Surface &target, Point source_origin, Point target_origin, + Size size) { + ::copywin(m_window, target.get(), source_origin.y, source_origin.x, + target_origin.y, target_origin.x, + target_origin.y + size.height - 1, + target_origin.x + size.width - 1, false); + } + + int GetCursorX() const { return getcurx(m_window); } + int GetCursorY() const { return getcury(m_window); } + void MoveCursor(int x, int y) { ::wmove(m_window, y, x); } + + void AttributeOn(attr_t attr) { ::wattron(m_window, attr); } + void AttributeOff(attr_t attr) { ::wattroff(m_window, attr); } + + int GetMaxX() const { return getmaxx(m_window); } + int GetMaxY() const { return getmaxy(m_window); } + int GetWidth() const { return GetMaxX(); } + int GetHeight() const { return GetMaxY(); } + Size GetSize() const { return Size(GetWidth(), GetHeight()); } + // Get a zero origin rectangle width the surface size. + Rect GetFrame() const { return Rect(Point(), GetSize()); } + + void Clear() { ::wclear(m_window); } + void Erase() { ::werase(m_window); } + + void SetBackground(int color_pair_idx) { + ::wbkgd(m_window, COLOR_PAIR(color_pair_idx)); + } + + void PutChar(int ch) { ::waddch(m_window, ch); } + void PutCString(const char *s, int len = -1) { ::waddnstr(m_window, s, len); } + + void PutCStringTruncated(int right_pad, const char *s, int len = -1) { + int bytes_left = GetWidth() - GetCursorX(); + if (bytes_left > right_pad) { + bytes_left -= right_pad; + ::waddnstr(m_window, s, len < 0 ? bytes_left : std::min(bytes_left, len)); + } + } + + void Printf(const char *format, ...) __attribute__((format(printf, 2, 3))) { + va_list args; + va_start(args, format); + vw_printw(m_window, format, args); + va_end(args); + } + + void PrintfTruncated(int right_pad, const char *format, ...) + __attribute__((format(printf, 3, 4))) { + va_list args; + va_start(args, format); + StreamString strm; + strm.PrintfVarArg(format, args); + va_end(args); + PutCStringTruncated(right_pad, strm.GetData()); + } + + void VerticalLine(int n, chtype v_char = ACS_VLINE) { + ::wvline(m_window, v_char, n); + } + void HorizontalLine(int n, chtype h_char = ACS_HLINE) { + ::whline(m_window, h_char, n); + } + void Box(chtype v_char = ACS_VLINE, chtype h_char = ACS_HLINE) { + ::box(m_window, v_char, h_char); + } + + void TitledBox(const char *title, chtype v_char = ACS_VLINE, + chtype h_char = ACS_HLINE) { + Box(v_char, h_char); + int title_offset = 2; + MoveCursor(title_offset, 0); + PutChar('['); + PutCString(title, GetWidth() - title_offset); + PutChar(']'); + } + + void Box(const Rect &bounds, chtype v_char = ACS_VLINE, + chtype h_char = ACS_HLINE) { + MoveCursor(bounds.origin.x, bounds.origin.y); + VerticalLine(bounds.size.height); + HorizontalLine(bounds.size.width); + PutChar(ACS_ULCORNER); + + MoveCursor(bounds.origin.x + bounds.size.width - 1, bounds.origin.y); + VerticalLine(bounds.size.height); + PutChar(ACS_URCORNER); + + MoveCursor(bounds.origin.x, bounds.origin.y + bounds.size.height - 1); + HorizontalLine(bounds.size.width); + PutChar(ACS_LLCORNER); + + MoveCursor(bounds.origin.x + bounds.size.width - 1, + bounds.origin.y + bounds.size.height - 1); + PutChar(ACS_LRCORNER); + } + + void TitledBox(const Rect &bounds, const char *title, + chtype v_char = ACS_VLINE, chtype h_char = ACS_HLINE) { + Box(bounds, v_char, h_char); + int title_offset = 2; + MoveCursor(bounds.origin.x + title_offset, bounds.origin.y); + PutChar('['); + PutCString(title, bounds.size.width - title_offset); + PutChar(']'); + } + + // Curses doesn't allow direct output of color escape sequences, but that's + // how we get source lines from the Highligher class. Read the line and + // convert color escape sequences to curses color attributes. Use + // first_skip_count to skip leading visible characters. Returns false if all + // visible characters were skipped due to first_skip_count. + bool OutputColoredStringTruncated(int right_pad, StringRef string, + size_t skip_first_count, + bool use_blue_background) { + attr_t saved_attr; + short saved_pair; + bool result = false; + wattr_get(m_window, &saved_attr, &saved_pair, nullptr); + if (use_blue_background) + ::wattron(m_window, COLOR_PAIR(WhiteOnBlue)); + while (!string.empty()) { + size_t esc_pos = string.find('\x1b'); + if (esc_pos == StringRef::npos) { + string = string.substr(skip_first_count); + if (!string.empty()) { + PutCStringTruncated(right_pad, string.data(), string.size()); + result = true; + } + break; + } + if (esc_pos > 0) { + if (skip_first_count > 0) { + int skip = std::min(esc_pos, skip_first_count); + string = string.substr(skip); + skip_first_count -= skip; + esc_pos -= skip; + } + if (esc_pos > 0) { + PutCStringTruncated(right_pad, string.data(), esc_pos); + result = true; + string = string.drop_front(esc_pos); + } + } + bool consumed = string.consume_front("\x1b"); + assert(consumed); + UNUSED_IF_ASSERT_DISABLED(consumed); + // This is written to match our Highlighter classes, which seem to + // generate only foreground color escape sequences. If necessary, this + // will need to be extended. + if (!string.consume_front("[")) { + llvm::errs() << "Missing '[' in color escape sequence.\n"; + continue; + } + // Only 8 basic foreground colors and reset, our Highlighter doesn't use + // anything else. + int value; + if (!!string.consumeInteger(10, value) || // Returns false on success. + !(value == 0 || (value >= 30 && value <= 37))) { + llvm::errs() << "No valid color code in color escape sequence.\n"; + continue; + } + if (!string.consume_front("m")) { + llvm::errs() << "Missing 'm' in color escape sequence.\n"; + continue; + } + if (value == 0) { // Reset. + wattr_set(m_window, saved_attr, saved_pair, nullptr); + if (use_blue_background) + ::wattron(m_window, COLOR_PAIR(WhiteOnBlue)); + } else { + // Mapped directly to first 16 color pairs (black/blue background). + ::wattron(m_window, + COLOR_PAIR(value - 30 + 1 + (use_blue_background ? 8 : 0))); + } + } + wattr_set(m_window, saved_attr, saved_pair, nullptr); + return result; + } + +protected: + WINDOW *m_window; +}; + +class Pad : public Surface { +public: + Pad(Size size) { m_window = ::newpad(size.height, size.width); } + + ~Pad() { ::delwin(m_window); } +}; + +class SubPad : public Surface { +public: + SubPad(Pad &pad, Rect bounds) { + m_window = ::subpad(pad.get(), bounds.size.height, bounds.size.width, + bounds.origin.y, bounds.origin.x); + } + SubPad(SubPad &subpad, Rect bounds) { + m_window = ::subpad(subpad.get(), bounds.size.height, bounds.size.width, + bounds.origin.y, bounds.origin.x); + } + + ~SubPad() { ::delwin(m_window); } +}; + +class Window : public Surface { public: Window(const char *name) - : m_name(name), m_window(nullptr), m_panel(nullptr), m_parent(nullptr), - m_subwindows(), m_delegate_sp(), m_curr_active_window_idx(UINT32_MAX), + : m_name(name), m_panel(nullptr), m_parent(nullptr), m_subwindows(), + m_delegate_sp(), m_curr_active_window_idx(UINT32_MAX), m_prev_active_window_idx(UINT32_MAX), m_delete(false), m_needs_update(true), m_can_activate(true), m_is_subwin(false) {} Window(const char *name, WINDOW *w, bool del = true) - : m_name(name), m_window(nullptr), m_panel(nullptr), m_parent(nullptr), - m_subwindows(), m_delegate_sp(), m_curr_active_window_idx(UINT32_MAX), + : m_name(name), m_panel(nullptr), m_parent(nullptr), m_subwindows(), + m_delegate_sp(), m_curr_active_window_idx(UINT32_MAX), m_prev_active_window_idx(UINT32_MAX), m_delete(del), m_needs_update(true), m_can_activate(true), m_is_subwin(false) { if (w) @@ -322,8 +576,8 @@ public: } Window(const char *name, const Rect &bounds) - : m_name(name), m_window(nullptr), m_parent(nullptr), m_subwindows(), - m_delegate_sp(), m_curr_active_window_idx(UINT32_MAX), + : m_name(name), m_parent(nullptr), m_subwindows(), m_delegate_sp(), + m_curr_active_window_idx(UINT32_MAX), m_prev_active_window_idx(UINT32_MAX), m_delete(true), m_needs_update(true), m_can_activate(true), m_is_subwin(false) { Reset(::newwin(bounds.size.height, bounds.size.width, bounds.origin.y, @@ -355,50 +609,27 @@ public: } } - void AttributeOn(attr_t attr) { ::wattron(m_window, attr); } - void AttributeOff(attr_t attr) { ::wattroff(m_window, attr); } - void Box(chtype v_char = ACS_VLINE, chtype h_char = ACS_HLINE) { - ::box(m_window, v_char, h_char); + // Get the rectangle in our parent window + Rect GetBounds() const { return Rect(GetParentOrigin(), GetSize()); } + + Rect GetCenteredRect(int width, int height) { + Size size = GetSize(); + width = std::min(size.width, width); + height = std::min(size.height, height); + int x = (size.width - width) / 2; + int y = (size.height - height) / 2; + return Rect(Point(x, y), Size(width, height)); } - void Clear() { ::wclear(m_window); } - void Erase() { ::werase(m_window); } - Rect GetBounds() { - return Rect(GetParentOrigin(), GetSize()); - } // Get the rectangle in our parent window + int GetChar() { return ::wgetch(m_window); } - int GetCursorX() { return getcurx(m_window); } - int GetCursorY() { return getcury(m_window); } - Rect GetFrame() { - return Rect(Point(), GetSize()); - } // Get our rectangle in our own coordinate system - Point GetParentOrigin() { return Point(GetParentX(), GetParentY()); } - Size GetSize() { return Size(GetWidth(), GetHeight()); } - int GetParentX() { return getparx(m_window); } - int GetParentY() { return getpary(m_window); } - int GetMaxX() { return getmaxx(m_window); } - int GetMaxY() { return getmaxy(m_window); } - int GetWidth() { return GetMaxX(); } - int GetHeight() { return GetMaxY(); } - void MoveCursor(int x, int y) { ::wmove(m_window, y, x); } + Point GetParentOrigin() const { return Point(GetParentX(), GetParentY()); } + int GetParentX() const { return getparx(m_window); } + int GetParentY() const { return getpary(m_window); } void MoveWindow(int x, int y) { MoveWindow(Point(x, y)); } void Resize(int w, int h) { ::wresize(m_window, h, w); } void Resize(const Size &size) { ::wresize(m_window, size.height, size.width); } - void PutChar(int ch) { ::waddch(m_window, ch); } - void PutCString(const char *s, int len = -1) { ::waddnstr(m_window, s, len); } - void SetBackground(int color_pair_idx) { - ::wbkgd(m_window, COLOR_PAIR(color_pair_idx)); - } - - void PutCStringTruncated(const char *s, int right_pad) { - int bytes_left = GetWidth() - GetCursorX(); - if (bytes_left > right_pad) { - bytes_left -= right_pad; - ::waddnstr(m_window, s, bytes_left); - } - } - void MoveWindow(const Point &origin) { const bool moving_window = origin != GetParentOrigin(); if (m_is_subwin && moving_window) { @@ -426,13 +657,6 @@ public: } } - void Printf(const char *format, ...) __attribute__((format(printf, 2, 3))) { - va_list args; - va_start(args, format); - vwprintw(m_window, format, args); - va_end(args); - } - void Touch() { ::touchwin(m_window); if (m_parent) @@ -513,15 +737,11 @@ public: ::touchwin(stdscr); } - WINDOW *get() { return m_window; } - - operator WINDOW *() { return m_window; } - // Window drawing utilities void DrawTitleBox(const char *title, const char *bottom_message = nullptr) { attr_t attr = 0; if (IsActive()) - attr = A_BOLD | COLOR_PAIR(2); + attr = A_BOLD | COLOR_PAIR(BlackOnWhite); else attr = 0; if (attr) @@ -548,7 +768,7 @@ public: } else { MoveCursor(1, GetHeight() - 1); PutChar('['); - PutCStringTruncated(bottom_message, 1); + PutCStringTruncated(1, bottom_message); } } if (attr) @@ -641,111 +861,1794 @@ public: return eKeyNotHandled; } - WindowSP GetActiveWindow() { - if (!m_subwindows.empty()) { - if (m_curr_active_window_idx >= m_subwindows.size()) { - if (m_prev_active_window_idx < m_subwindows.size()) { - m_curr_active_window_idx = m_prev_active_window_idx; - m_prev_active_window_idx = UINT32_MAX; - } else if (IsActive()) { - m_prev_active_window_idx = UINT32_MAX; - m_curr_active_window_idx = UINT32_MAX; + WindowSP GetActiveWindow() { + if (!m_subwindows.empty()) { + if (m_curr_active_window_idx >= m_subwindows.size()) { + if (m_prev_active_window_idx < m_subwindows.size()) { + m_curr_active_window_idx = m_prev_active_window_idx; + m_prev_active_window_idx = UINT32_MAX; + } else if (IsActive()) { + m_prev_active_window_idx = UINT32_MAX; + m_curr_active_window_idx = UINT32_MAX; + + // Find first window that wants to be active if this window is active + const size_t num_subwindows = m_subwindows.size(); + for (size_t i = 0; i < num_subwindows; ++i) { + if (m_subwindows[i]->GetCanBeActive()) { + m_curr_active_window_idx = i; + break; + } + } + } + } + + if (m_curr_active_window_idx < m_subwindows.size()) + return m_subwindows[m_curr_active_window_idx]; + } + return WindowSP(); + } + + bool GetCanBeActive() const { return m_can_activate; } + + void SetCanBeActive(bool b) { m_can_activate = b; } + + void SetDelegate(const WindowDelegateSP &delegate_sp) { + m_delegate_sp = delegate_sp; + } + + Window *GetParent() const { return m_parent; } + + bool IsActive() const { + if (m_parent) + return m_parent->GetActiveWindow().get() == this; + else + return true; // Top level window is always active + } + + void SelectNextWindowAsActive() { + // Move active focus to next window + const int num_subwindows = m_subwindows.size(); + int start_idx = 0; + if (m_curr_active_window_idx != UINT32_MAX) { + m_prev_active_window_idx = m_curr_active_window_idx; + start_idx = m_curr_active_window_idx + 1; + } + for (int idx = start_idx; idx < num_subwindows; ++idx) { + if (m_subwindows[idx]->GetCanBeActive()) { + m_curr_active_window_idx = idx; + return; + } + } + for (int idx = 0; idx < start_idx; ++idx) { + if (m_subwindows[idx]->GetCanBeActive()) { + m_curr_active_window_idx = idx; + break; + } + } + } + + void SelectPreviousWindowAsActive() { + // Move active focus to previous window + const int num_subwindows = m_subwindows.size(); + int start_idx = num_subwindows - 1; + if (m_curr_active_window_idx != UINT32_MAX) { + m_prev_active_window_idx = m_curr_active_window_idx; + start_idx = m_curr_active_window_idx - 1; + } + for (int idx = start_idx; idx >= 0; --idx) { + if (m_subwindows[idx]->GetCanBeActive()) { + m_curr_active_window_idx = idx; + return; + } + } + for (int idx = num_subwindows - 1; idx > start_idx; --idx) { + if (m_subwindows[idx]->GetCanBeActive()) { + m_curr_active_window_idx = idx; + break; + } + } + } + + const char *GetName() const { return m_name.c_str(); } + +protected: + std::string m_name; + PANEL *m_panel; + Window *m_parent; + Windows m_subwindows; + WindowDelegateSP m_delegate_sp; + uint32_t m_curr_active_window_idx; + uint32_t m_prev_active_window_idx; + bool m_delete; + bool m_needs_update; + bool m_can_activate; + bool m_is_subwin; + +private: + Window(const Window &) = delete; + const Window &operator=(const Window &) = delete; +}; + +class DerivedWindow : public Surface { +public: + DerivedWindow(Window &window, Rect bounds) { + m_window = ::derwin(window.get(), bounds.size.height, bounds.size.width, + bounds.origin.y, bounds.origin.x); + } + DerivedWindow(DerivedWindow &derived_window, Rect bounds) { + m_window = ::derwin(derived_window.get(), bounds.size.height, + bounds.size.width, bounds.origin.y, bounds.origin.x); + } + + ~DerivedWindow() { ::delwin(m_window); } +}; + +///////// +// Forms +///////// + +// A scroll context defines a vertical region that needs to be visible in a +// scrolling area. The region is defined by the index of the start and end lines +// of the region. The start and end lines may be equal, in which case, the +// region is a single line. +struct ScrollContext { + int start; + int end; + + ScrollContext(int line) : start(line), end(line) {} + ScrollContext(int _start, int _end) : start(_start), end(_end) {} + + void Offset(int offset) { + start += offset; + end += offset; + } +}; + +class FieldDelegate { +public: + virtual ~FieldDelegate() = default; + + // Returns the number of lines needed to draw the field. The draw method will + // be given a surface that have exactly this number of lines. + virtual int FieldDelegateGetHeight() = 0; + + // Returns the scroll context in the local coordinates of the field. By + // default, the scroll context spans the whole field. Bigger fields with + // internal navigation should override this method to provide a finer context. + // Typical override methods would first get the scroll context of the internal + // element then add the offset of the element in the field. + virtual ScrollContext FieldDelegateGetScrollContext() { + return ScrollContext(0, FieldDelegateGetHeight() - 1); + } + + // Draw the field in the given subpad surface. The surface have a height that + // is equal to the height returned by FieldDelegateGetHeight(). If the field + // is selected in the form window, then is_selected will be true. + virtual void FieldDelegateDraw(SubPad &surface, bool is_selected) = 0; + + // Handle the key that wasn't handled by the form window or a container field. + virtual HandleCharResult FieldDelegateHandleChar(int key) { + return eKeyNotHandled; + } + + // This is executed once the user exists the field, that is, once the user + // navigates to the next or the previous field. This is particularly useful to + // do in-field validation and error setting. Fields with internal navigation + // should call this method on their fields. + virtual void FieldDelegateExitCallback() { return; } + + // Fields may have internal navigation, for instance, a List Field have + // multiple internal elements, which needs to be navigated. To allow for this + // mechanism, the window shouldn't handle the navigation keys all the time, + // and instead call the key handing method of the selected field. It should + // only handle the navigation keys when the field contains a single element or + // have the last or first element selected depending on if the user is + // navigating forward or backward. Additionally, once a field is selected in + // the forward or backward direction, its first or last internal element + // should be selected. The following methods implements those mechanisms. + + // Returns true if the first element in the field is selected or if the field + // contains a single element. + virtual bool FieldDelegateOnFirstOrOnlyElement() { return true; } + + // Returns true if the last element in the field is selected or if the field + // contains a single element. + virtual bool FieldDelegateOnLastOrOnlyElement() { return true; } + + // Select the first element in the field if multiple elements exists. + virtual void FieldDelegateSelectFirstElement() { return; } + + // Select the last element in the field if multiple elements exists. + virtual void FieldDelegateSelectLastElement() { return; } + + // Returns true if the field has an error, false otherwise. + virtual bool FieldDelegateHasError() { return false; } + + bool FieldDelegateIsVisible() { return m_is_visible; } + + void FieldDelegateHide() { m_is_visible = false; } + + void FieldDelegateShow() { m_is_visible = true; } + +protected: + bool m_is_visible = true; +}; + +typedef std::unique_ptr FieldDelegateUP; + +class TextFieldDelegate : public FieldDelegate { +public: + TextFieldDelegate(const char *label, const char *content, bool required) + : m_label(label), m_required(required), m_cursor_position(0), + m_first_visibile_char(0) { + if (content) + m_content = content; + } + + // Text fields are drawn as titled boxes of a single line, with a possible + // error messages at the end. + // + // __[Label]___________ + // | | + // |__________________| + // - Error message if it exists. + + // The text field has a height of 3 lines. 2 lines for borders and 1 line for + // the content. + int GetFieldHeight() { return 3; } + + // The text field has a full height of 3 or 4 lines. 3 lines for the actual + // field and an optional line for an error if it exists. + int FieldDelegateGetHeight() override { + int height = GetFieldHeight(); + if (FieldDelegateHasError()) + height++; + return height; + } + + // Get the cursor X position in the surface coordinate. + int GetCursorXPosition() { return m_cursor_position - m_first_visibile_char; } + + int GetContentLength() { return m_content.length(); } + + void DrawContent(SubPad &surface, bool is_selected) { + surface.MoveCursor(0, 0); + const char *text = m_content.c_str() + m_first_visibile_char; + surface.PutCString(text, surface.GetWidth()); + m_last_drawn_content_width = surface.GetWidth(); + + // Highlight the cursor. + surface.MoveCursor(GetCursorXPosition(), 0); + if (is_selected) + surface.AttributeOn(A_REVERSE); + if (m_cursor_position == GetContentLength()) + // Cursor is past the last character. Highlight an empty space. + surface.PutChar(' '); + else + surface.PutChar(m_content[m_cursor_position]); + if (is_selected) + surface.AttributeOff(A_REVERSE); + } + + void DrawField(SubPad &surface, bool is_selected) { + surface.TitledBox(m_label.c_str()); + + Rect content_bounds = surface.GetFrame(); + content_bounds.Inset(1, 1); + SubPad content_surface = SubPad(surface, content_bounds); + + DrawContent(content_surface, is_selected); + } + + void DrawError(SubPad &surface) { + if (!FieldDelegateHasError()) + return; + surface.MoveCursor(0, 0); + surface.AttributeOn(COLOR_PAIR(RedOnBlack)); + surface.PutChar(ACS_DIAMOND); + surface.PutChar(' '); + surface.PutCStringTruncated(1, GetError().c_str()); + surface.AttributeOff(COLOR_PAIR(RedOnBlack)); + } + + void FieldDelegateDraw(SubPad &surface, bool is_selected) override { + Rect frame = surface.GetFrame(); + Rect field_bounds, error_bounds; + frame.HorizontalSplit(GetFieldHeight(), field_bounds, error_bounds); + SubPad field_surface = SubPad(surface, field_bounds); + SubPad error_surface = SubPad(surface, error_bounds); + + DrawField(field_surface, is_selected); + DrawError(error_surface); + } + + // The cursor is allowed to move one character past the string. + // m_cursor_position is in range [0, GetContentLength()]. + void MoveCursorRight() { + if (m_cursor_position < GetContentLength()) + m_cursor_position++; + } + + void MoveCursorLeft() { + if (m_cursor_position > 0) + m_cursor_position--; + } + + // If the cursor moved past the last visible character, scroll right by one + // character. + void ScrollRightIfNeeded() { + if (m_cursor_position - m_first_visibile_char == m_last_drawn_content_width) + m_first_visibile_char++; + } + + void ScrollLeft() { + if (m_first_visibile_char > 0) + m_first_visibile_char--; + } + + // If the cursor moved past the first visible character, scroll left by one + // character. + void ScrollLeftIfNeeded() { + if (m_cursor_position < m_first_visibile_char) + m_first_visibile_char--; + } + + // Insert a character at the current cursor position, advance the cursor + // position, and make sure to scroll right if needed. + void InsertChar(char character) { + m_content.insert(m_cursor_position, 1, character); + m_cursor_position++; + ScrollRightIfNeeded(); + } + + // Remove the character before the cursor position, retreat the cursor + // position, and make sure to scroll left if needed. + void RemoveChar() { + if (m_cursor_position == 0) + return; + + m_content.erase(m_cursor_position - 1, 1); + m_cursor_position--; + ScrollLeft(); + } + + // True if the key represents a char that can be inserted in the field + // content, false otherwise. + virtual bool IsAcceptableChar(int key) { return isprint(key); } + + HandleCharResult FieldDelegateHandleChar(int key) override { + if (IsAcceptableChar(key)) { + ClearError(); + InsertChar((char)key); + return eKeyHandled; + } + + switch (key) { + case KEY_RIGHT: + MoveCursorRight(); + ScrollRightIfNeeded(); + return eKeyHandled; + case KEY_LEFT: + MoveCursorLeft(); + ScrollLeftIfNeeded(); + return eKeyHandled; + case KEY_BACKSPACE: + ClearError(); + RemoveChar(); + return eKeyHandled; + default: + break; + } + return eKeyNotHandled; + } + + bool FieldDelegateHasError() override { return !m_error.empty(); } + + void FieldDelegateExitCallback() override { + if (!IsSpecified() && m_required) + SetError("This field is required!"); + } + + bool IsSpecified() { return !m_content.empty(); } + + void ClearError() { m_error.clear(); } + + const std::string &GetError() { return m_error; } + + void SetError(const char *error) { m_error = error; } + + const std::string &GetText() { return m_content; } + +protected: + std::string m_label; + bool m_required; + // The position of the top left corner character of the border. + std::string m_content; + // The cursor position in the content string itself. Can be in the range + // [0, GetContentLength()]. + int m_cursor_position; + // The index of the first visible character in the content. + int m_first_visibile_char; + // The width of the fields content that was last drawn. Width can change, so + // this is used to determine if scrolling is needed dynamically. + int m_last_drawn_content_width; + // Optional error message. If empty, field is considered to have no error. + std::string m_error; +}; + +class IntegerFieldDelegate : public TextFieldDelegate { +public: + IntegerFieldDelegate(const char *label, int content, bool required) + : TextFieldDelegate(label, std::to_string(content).c_str(), required) {} + + // Only accept digits. + bool IsAcceptableChar(int key) override { return isdigit(key); } + + // Returns the integer content of the field. + int GetInteger() { return std::stoi(m_content); } +}; + +class FileFieldDelegate : public TextFieldDelegate { +public: + FileFieldDelegate(const char *label, const char *content, bool need_to_exist, + bool required) + : TextFieldDelegate(label, content, required), + m_need_to_exist(need_to_exist) {} + + void FieldDelegateExitCallback() override { + TextFieldDelegate::FieldDelegateExitCallback(); + if (!IsSpecified()) + return; + + if (!m_need_to_exist) + return; + + FileSpec file = GetResolvedFileSpec(); + if (!FileSystem::Instance().Exists(file)) { + SetError("File doesn't exist!"); + return; + } + if (FileSystem::Instance().IsDirectory(file)) { + SetError("Not a file!"); + return; + } + } + + FileSpec GetFileSpec() { + FileSpec file_spec(GetPath()); + return file_spec; + } + + FileSpec GetResolvedFileSpec() { + FileSpec file_spec(GetPath()); + FileSystem::Instance().Resolve(file_spec); + return file_spec; + } + + const std::string &GetPath() { return m_content; } + +protected: + bool m_need_to_exist; +}; + +class DirectoryFieldDelegate : public TextFieldDelegate { +public: + DirectoryFieldDelegate(const char *label, const char *content, + bool need_to_exist, bool required) + : TextFieldDelegate(label, content, required), + m_need_to_exist(need_to_exist) {} + + void FieldDelegateExitCallback() override { + TextFieldDelegate::FieldDelegateExitCallback(); + if (!IsSpecified()) + return; + + if (!m_need_to_exist) + return; + + FileSpec file = GetResolvedFileSpec(); + if (!FileSystem::Instance().Exists(file)) { + SetError("Directory doesn't exist!"); + return; + } + if (!FileSystem::Instance().IsDirectory(file)) { + SetError("Not a directory!"); + return; + } + } + + FileSpec GetFileSpec() { + FileSpec file_spec(GetPath()); + return file_spec; + } + + FileSpec GetResolvedFileSpec() { + FileSpec file_spec(GetPath()); + FileSystem::Instance().Resolve(file_spec); + return file_spec; + } + + const std::string &GetPath() { return m_content; } + +protected: + bool m_need_to_exist; +}; + +class ArchFieldDelegate : public TextFieldDelegate { +public: + ArchFieldDelegate(const char *label, const char *content, bool required) + : TextFieldDelegate(label, content, required) {} + + void FieldDelegateExitCallback() override { + TextFieldDelegate::FieldDelegateExitCallback(); + if (!IsSpecified()) + return; + + if (!GetArchSpec().IsValid()) + SetError("Not a valid arch!"); + } + + const std::string &GetArchString() { return m_content; } + + ArchSpec GetArchSpec() { return ArchSpec(GetArchString()); } +}; + +class BooleanFieldDelegate : public FieldDelegate { +public: + BooleanFieldDelegate(const char *label, bool content) + : m_label(label), m_content(content) {} + + // Boolean fields are drawn as checkboxes. + // + // [X] Label or [ ] Label + + // Boolean fields are have a single line. + int FieldDelegateGetHeight() override { return 1; } + + void FieldDelegateDraw(SubPad &surface, bool is_selected) override { + surface.MoveCursor(0, 0); + surface.PutChar('['); + if (is_selected) + surface.AttributeOn(A_REVERSE); + surface.PutChar(m_content ? ACS_DIAMOND : ' '); + if (is_selected) + surface.AttributeOff(A_REVERSE); + surface.PutChar(']'); + surface.PutChar(' '); + surface.PutCString(m_label.c_str()); + } + + void ToggleContent() { m_content = !m_content; } + + void SetContentToTrue() { m_content = true; } + + void SetContentToFalse() { m_content = false; } + + HandleCharResult FieldDelegateHandleChar(int key) override { + switch (key) { + case 't': + case '1': + SetContentToTrue(); + return eKeyHandled; + case 'f': + case '0': + SetContentToFalse(); + return eKeyHandled; + case ' ': + case '\r': + case '\n': + case KEY_ENTER: + ToggleContent(); + return eKeyHandled; + default: + break; + } + return eKeyNotHandled; + } + + // Returns the boolean content of the field. + bool GetBoolean() { return m_content; } + +protected: + std::string m_label; + bool m_content; +}; + +class ChoicesFieldDelegate : public FieldDelegate { +public: + ChoicesFieldDelegate(const char *label, int number_of_visible_choices, + std::vector choices) + : m_label(label), m_number_of_visible_choices(number_of_visible_choices), + m_choices(choices), m_choice(0), m_first_visibile_choice(0) {} + + // Choices fields are drawn as titles boxses of a number of visible choices. + // The rest of the choices become visible as the user scroll. The selected + // choice is denoted by a diamond as the first character. + // + // __[Label]___________ + // |-Choice 1 | + // | Choice 2 | + // | Choice 3 | + // |__________________| + + // Choices field have two border characters plus the number of visible + // choices. + int FieldDelegateGetHeight() override { + return m_number_of_visible_choices + 2; + } + + int GetNumberOfChoices() { return m_choices.size(); } + + // Get the index of the last visible choice. + int GetLastVisibleChoice() { + int index = m_first_visibile_choice + m_number_of_visible_choices; + return std::min(index, GetNumberOfChoices()) - 1; + } + + void DrawContent(SubPad &surface, bool is_selected) { + int choices_to_draw = GetLastVisibleChoice() - m_first_visibile_choice + 1; + for (int i = 0; i < choices_to_draw; i++) { + surface.MoveCursor(0, i); + int current_choice = m_first_visibile_choice + i; + const char *text = m_choices[current_choice].c_str(); + bool highlight = is_selected && current_choice == m_choice; + if (highlight) + surface.AttributeOn(A_REVERSE); + surface.PutChar(current_choice == m_choice ? ACS_DIAMOND : ' '); + surface.PutCString(text); + if (highlight) + surface.AttributeOff(A_REVERSE); + } + } + + void FieldDelegateDraw(SubPad &surface, bool is_selected) override { + UpdateScrolling(); + + surface.TitledBox(m_label.c_str()); + + Rect content_bounds = surface.GetFrame(); + content_bounds.Inset(1, 1); + SubPad content_surface = SubPad(surface, content_bounds); + + DrawContent(content_surface, is_selected); + } + + void SelectPrevious() { + if (m_choice > 0) + m_choice--; + } + + void SelectNext() { + if (m_choice < GetNumberOfChoices() - 1) + m_choice++; + } + + void UpdateScrolling() { + if (m_choice > GetLastVisibleChoice()) { + m_first_visibile_choice = m_choice - (m_number_of_visible_choices - 1); + return; + } + + if (m_choice < m_first_visibile_choice) + m_first_visibile_choice = m_choice; + } + + HandleCharResult FieldDelegateHandleChar(int key) override { + switch (key) { + case KEY_UP: + SelectPrevious(); + return eKeyHandled; + case KEY_DOWN: + SelectNext(); + return eKeyHandled; + default: + break; + } + return eKeyNotHandled; + } + + // Returns the content of the choice as a string. + std::string GetChoiceContent() { return m_choices[m_choice]; } + + // Returns the index of the choice. + int GetChoice() { return m_choice; } + + void SetChoice(const std::string &choice) { + for (int i = 0; i < GetNumberOfChoices(); i++) { + if (choice == m_choices[i]) { + m_choice = i; + return; + } + } + } + +protected: + std::string m_label; + int m_number_of_visible_choices; + std::vector m_choices; + // The index of the selected choice. + int m_choice; + // The index of the first visible choice in the field. + int m_first_visibile_choice; +}; + +class PlatformPluginFieldDelegate : public ChoicesFieldDelegate { +public: + PlatformPluginFieldDelegate(Debugger &debugger) + : ChoicesFieldDelegate("Platform Plugin", 3, GetPossiblePluginNames()) { + PlatformSP platform_sp = debugger.GetPlatformList().GetSelectedPlatform(); + if (platform_sp) + SetChoice(platform_sp->GetName().AsCString()); + } + + std::vector GetPossiblePluginNames() { + std::vector names; + size_t i = 0; + while (auto name = PluginManager::GetPlatformPluginNameAtIndex(i++)) + names.push_back(name); + return names; + } + + std::string GetPluginName() { + std::string plugin_name = GetChoiceContent(); + return plugin_name; + } +}; + +class ProcessPluginFieldDelegate : public ChoicesFieldDelegate { +public: + ProcessPluginFieldDelegate() + : ChoicesFieldDelegate("Process Plugin", 3, GetPossiblePluginNames()) {} + + std::vector GetPossiblePluginNames() { + std::vector names; + names.push_back(""); + + size_t i = 0; + while (auto name = PluginManager::GetProcessPluginNameAtIndex(i++)) + names.push_back(name); + return names; + } + + std::string GetPluginName() { + std::string plugin_name = GetChoiceContent(); + if (plugin_name == "") + return ""; + return plugin_name; + } +}; + +template class ListFieldDelegate : public FieldDelegate { +public: + ListFieldDelegate(const char *label, T default_field) + : m_label(label), m_default_field(default_field), m_selection_index(0), + m_selection_type(SelectionType::NewButton) {} + + // Signify which element is selected. If a field or a remove button is + // selected, then m_selection_index signifies the particular field that + // is selected or the field that the remove button belongs to. + enum class SelectionType { Field, RemoveButton, NewButton }; + + // A List field is drawn as a titled box of a number of other fields of the + // same type. Each field has a Remove button next to it that removes the + // corresponding field. Finally, the last line contains a New button to add a + // new field. + // + // __[Label]___________ + // | Field 0 [Remove] | + // | Field 1 [Remove] | + // | Field 2 [Remove] | + // | [New] | + // |__________________| + + // List fields have two lines for border characters, 1 line for the New + // button, and the total height of the available fields. + int FieldDelegateGetHeight() override { + // 2 border characters. + int height = 2; + // Total height of the fields. + for (int i = 0; i < GetNumberOfFields(); i++) { + height += m_fields[i].FieldDelegateGetHeight(); + } + // A line for the New button. + height++; + return height; + } + + ScrollContext FieldDelegateGetScrollContext() override { + int height = FieldDelegateGetHeight(); + if (m_selection_type == SelectionType::NewButton) + return ScrollContext(height - 2, height - 1); + + FieldDelegate &field = m_fields[m_selection_index]; + ScrollContext context = field.FieldDelegateGetScrollContext(); + + // Start at 1 because of the top border. + int offset = 1; + for (int i = 0; i < m_selection_index; i++) { + offset += m_fields[i].FieldDelegateGetHeight(); + } + context.Offset(offset); + + // If the scroll context is touching the top border, include it in the + // context to show the label. + if (context.start == 1) + context.start--; + + // If the scroll context is touching the new button, include it as well as + // the bottom border in the context. + if (context.end == height - 3) + context.end += 2; + + return context; + } + + void DrawRemoveButton(SubPad &surface, int highlight) { + surface.MoveCursor(1, surface.GetHeight() / 2); + if (highlight) + surface.AttributeOn(A_REVERSE); + surface.PutCString("[Remove]"); + if (highlight) + surface.AttributeOff(A_REVERSE); + } + + void DrawFields(SubPad &surface, bool is_selected) { + int line = 0; + int width = surface.GetWidth(); + for (int i = 0; i < GetNumberOfFields(); i++) { + int height = m_fields[i].FieldDelegateGetHeight(); + Rect bounds = Rect(Point(0, line), Size(width, height)); + Rect field_bounds, remove_button_bounds; + bounds.VerticalSplit(bounds.size.width - sizeof(" [Remove]"), + field_bounds, remove_button_bounds); + SubPad field_surface = SubPad(surface, field_bounds); + SubPad remove_button_surface = SubPad(surface, remove_button_bounds); + + bool is_element_selected = m_selection_index == i && is_selected; + bool is_field_selected = + is_element_selected && m_selection_type == SelectionType::Field; + bool is_remove_button_selected = + is_element_selected && + m_selection_type == SelectionType::RemoveButton; + m_fields[i].FieldDelegateDraw(field_surface, is_field_selected); + DrawRemoveButton(remove_button_surface, is_remove_button_selected); + + line += height; + } + } + + void DrawNewButton(SubPad &surface, bool is_selected) { + const char *button_text = "[New]"; + int x = (surface.GetWidth() - sizeof(button_text) - 1) / 2; + surface.MoveCursor(x, 0); + bool highlight = + is_selected && m_selection_type == SelectionType::NewButton; + if (highlight) + surface.AttributeOn(A_REVERSE); + surface.PutCString(button_text); + if (highlight) + surface.AttributeOff(A_REVERSE); + } + + void FieldDelegateDraw(SubPad &surface, bool is_selected) override { + surface.TitledBox(m_label.c_str()); + + Rect content_bounds = surface.GetFrame(); + content_bounds.Inset(1, 1); + Rect fields_bounds, new_button_bounds; + content_bounds.HorizontalSplit(content_bounds.size.height - 1, + fields_bounds, new_button_bounds); + SubPad fields_surface = SubPad(surface, fields_bounds); + SubPad new_button_surface = SubPad(surface, new_button_bounds); + + DrawFields(fields_surface, is_selected); + DrawNewButton(new_button_surface, is_selected); + } + + void AddNewField() { + m_fields.push_back(m_default_field); + m_selection_index = GetNumberOfFields() - 1; + m_selection_type = SelectionType::Field; + FieldDelegate &field = m_fields[m_selection_index]; + field.FieldDelegateSelectFirstElement(); + } + + void RemoveField() { + m_fields.erase(m_fields.begin() + m_selection_index); + if (m_selection_index != 0) + m_selection_index--; + + if (GetNumberOfFields() > 0) { + m_selection_type = SelectionType::Field; + FieldDelegate &field = m_fields[m_selection_index]; + field.FieldDelegateSelectFirstElement(); + } else + m_selection_type = SelectionType::NewButton; + } + + HandleCharResult SelectNext(int key) { + if (m_selection_type == SelectionType::NewButton) + return eKeyNotHandled; + + if (m_selection_type == SelectionType::RemoveButton) { + if (m_selection_index == GetNumberOfFields() - 1) { + m_selection_type = SelectionType::NewButton; + return eKeyHandled; + } + m_selection_index++; + m_selection_type = SelectionType::Field; + FieldDelegate &next_field = m_fields[m_selection_index]; + next_field.FieldDelegateSelectFirstElement(); + return eKeyHandled; + } + + FieldDelegate &field = m_fields[m_selection_index]; + if (!field.FieldDelegateOnLastOrOnlyElement()) { + return field.FieldDelegateHandleChar(key); + } + + field.FieldDelegateExitCallback(); + + m_selection_type = SelectionType::RemoveButton; + return eKeyHandled; + } + + HandleCharResult SelectPrevious(int key) { + if (FieldDelegateOnFirstOrOnlyElement()) + return eKeyNotHandled; + + if (m_selection_type == SelectionType::RemoveButton) { + m_selection_type = SelectionType::Field; + FieldDelegate &field = m_fields[m_selection_index]; + field.FieldDelegateSelectLastElement(); + return eKeyHandled; + } + + if (m_selection_type == SelectionType::NewButton) { + m_selection_type = SelectionType::RemoveButton; + m_selection_index = GetNumberOfFields() - 1; + return eKeyHandled; + } + + FieldDelegate &field = m_fields[m_selection_index]; + if (!field.FieldDelegateOnFirstOrOnlyElement()) { + return field.FieldDelegateHandleChar(key); + } + + field.FieldDelegateExitCallback(); + + m_selection_type = SelectionType::RemoveButton; + m_selection_index--; + return eKeyHandled; + } + + HandleCharResult FieldDelegateHandleChar(int key) override { + switch (key) { + case '\r': + case '\n': + case KEY_ENTER: + switch (m_selection_type) { + case SelectionType::NewButton: + AddNewField(); + return eKeyHandled; + case SelectionType::RemoveButton: + RemoveField(); + return eKeyHandled; + default: + break; + } + break; + case '\t': + SelectNext(key); + return eKeyHandled; + case KEY_SHIFT_TAB: + SelectPrevious(key); + return eKeyHandled; + default: + break; + } + + // If the key wasn't handled and one of the fields is selected, pass the key + // to that field. + if (m_selection_type == SelectionType::Field) { + return m_fields[m_selection_index].FieldDelegateHandleChar(key); + } + + return eKeyNotHandled; + } + + bool FieldDelegateOnLastOrOnlyElement() override { + if (m_selection_type == SelectionType::NewButton) { + return true; + } + return false; + } + + bool FieldDelegateOnFirstOrOnlyElement() override { + if (m_selection_type == SelectionType::NewButton && + GetNumberOfFields() == 0) + return true; + + if (m_selection_type == SelectionType::Field && m_selection_index == 0) { + FieldDelegate &field = m_fields[m_selection_index]; + return field.FieldDelegateOnFirstOrOnlyElement(); + } + + return false; + } + + void FieldDelegateSelectFirstElement() override { + if (GetNumberOfFields() == 0) { + m_selection_type = SelectionType::NewButton; + return; + } + + m_selection_type = SelectionType::Field; + m_selection_index = 0; + } + + void FieldDelegateSelectLastElement() override { + m_selection_type = SelectionType::NewButton; + return; + } + + int GetNumberOfFields() { return m_fields.size(); } + + // Returns the form delegate at the current index. + T &GetField(int index) { return m_fields[index]; } + +protected: + std::string m_label; + // The default field delegate instance from which new field delegates will be + // created though a copy. + T m_default_field; + std::vector m_fields; + int m_selection_index; + // See SelectionType class enum. + SelectionType m_selection_type; +}; + +class FormAction { +public: + FormAction(const char *label, std::function action) + : m_action(action) { + if (label) + m_label = label; + } + + // Draw a centered [Label]. + void Draw(SubPad &surface, bool is_selected) { + int x = (surface.GetWidth() - m_label.length()) / 2; + surface.MoveCursor(x, 0); + if (is_selected) + surface.AttributeOn(A_REVERSE); + surface.PutChar('['); + surface.PutCString(m_label.c_str()); + surface.PutChar(']'); + if (is_selected) + surface.AttributeOff(A_REVERSE); + } + + void Execute(Window &window) { m_action(window); } + + const std::string &GetLabel() { return m_label; } + +protected: + std::string m_label; + std::function m_action; +}; + +class FormDelegate { +public: + FormDelegate() {} + + virtual ~FormDelegate() = default; + + virtual std::string GetName() = 0; + + virtual void UpdateFieldsVisibility() { return; } + + FieldDelegate *GetField(uint32_t field_index) { + if (field_index < m_fields.size()) + return m_fields[field_index].get(); + return nullptr; + } + + FormAction &GetAction(int action_index) { return m_actions[action_index]; } + + int GetNumberOfFields() { return m_fields.size(); } + + int GetNumberOfActions() { return m_actions.size(); } + + bool HasError() { return !m_error.empty(); } + + void ClearError() { m_error.clear(); } + + const std::string &GetError() { return m_error; } + + void SetError(const char *error) { m_error = error; } + + // If all fields are valid, true is returned. Otherwise, an error message is + // set and false is returned. This method is usually called at the start of an + // action that requires valid fields. + bool CheckFieldsValidity() { + for (int i = 0; i < GetNumberOfFields(); i++) { + if (GetField(i)->FieldDelegateHasError()) { + SetError("Some fields are invalid!"); + return false; + } + } + return true; + } + + // Factory methods to create and add fields of specific types. + + TextFieldDelegate *AddTextField(const char *label, const char *content, + bool required) { + TextFieldDelegate *delegate = + new TextFieldDelegate(label, content, required); + m_fields.push_back(FieldDelegateUP(delegate)); + return delegate; + } + + FileFieldDelegate *AddFileField(const char *label, const char *content, + bool need_to_exist, bool required) { + FileFieldDelegate *delegate = + new FileFieldDelegate(label, content, need_to_exist, required); + m_fields.push_back(FieldDelegateUP(delegate)); + return delegate; + } + + DirectoryFieldDelegate *AddDirectoryField(const char *label, + const char *content, + bool need_to_exist, bool required) { + DirectoryFieldDelegate *delegate = + new DirectoryFieldDelegate(label, content, need_to_exist, required); + m_fields.push_back(FieldDelegateUP(delegate)); + return delegate; + } + + ArchFieldDelegate *AddArchField(const char *label, const char *content, + bool required) { + ArchFieldDelegate *delegate = + new ArchFieldDelegate(label, content, required); + m_fields.push_back(FieldDelegateUP(delegate)); + return delegate; + } + + IntegerFieldDelegate *AddIntegerField(const char *label, int content, + bool required) { + IntegerFieldDelegate *delegate = + new IntegerFieldDelegate(label, content, required); + m_fields.push_back(FieldDelegateUP(delegate)); + return delegate; + } + + BooleanFieldDelegate *AddBooleanField(const char *label, bool content) { + BooleanFieldDelegate *delegate = new BooleanFieldDelegate(label, content); + m_fields.push_back(FieldDelegateUP(delegate)); + return delegate; + } + + ChoicesFieldDelegate *AddChoicesField(const char *label, int height, + std::vector choices) { + ChoicesFieldDelegate *delegate = + new ChoicesFieldDelegate(label, height, choices); + m_fields.push_back(FieldDelegateUP(delegate)); + return delegate; + } + + PlatformPluginFieldDelegate *AddPlatformPluginField(Debugger &debugger) { + PlatformPluginFieldDelegate *delegate = + new PlatformPluginFieldDelegate(debugger); + m_fields.push_back(FieldDelegateUP(delegate)); + return delegate; + } + + ProcessPluginFieldDelegate *AddProcessPluginField() { + ProcessPluginFieldDelegate *delegate = new ProcessPluginFieldDelegate(); + m_fields.push_back(FieldDelegateUP(delegate)); + return delegate; + } + + template + ListFieldDelegate *AddListField(const char *label, T default_field) { + ListFieldDelegate *delegate = + new ListFieldDelegate(label, default_field); + m_fields.push_back(FieldDelegateUP(delegate)); + return delegate; + } + + // Factory methods for adding actions. + + void AddAction(const char *label, std::function action) { + m_actions.push_back(FormAction(label, action)); + } + +protected: + std::vector m_fields; + std::vector m_actions; + // Optional error message. If empty, form is considered to have no error. + std::string m_error; +}; + +typedef std::shared_ptr FormDelegateSP; + +class FormWindowDelegate : public WindowDelegate { +public: + FormWindowDelegate(FormDelegateSP &delegate_sp) + : m_delegate_sp(delegate_sp), m_selection_index(0), + m_first_visible_line(0) { + assert(m_delegate_sp->GetNumberOfActions() > 0); + if (m_delegate_sp->GetNumberOfFields() > 0) + m_selection_type = SelectionType::Field; + else + m_selection_type = SelectionType::Action; + } + + // Signify which element is selected. If a field or an action is selected, + // then m_selection_index signifies the particular field or action that is + // selected. + enum class SelectionType { Field, Action }; + + // A form window is padded by one character from all sides. First, if an error + // message exists, it is drawn followed by a separator. Then one or more + // fields are drawn. Finally, all available actions are drawn on a single + // line. + // + // ___
_________________________________________________ + // | | + // | - Error message if it exists. | + // |-------------------------------------------------------------| + // | Form elements here. | + // | Form actions here. | + // | | + // |______________________________________[Press Esc to cancel]__| + // + + // One line for the error and another for the horizontal line. + int GetErrorHeight() { + if (m_delegate_sp->HasError()) + return 2; + return 0; + } + + // Actions span a single line. + int GetActionsHeight() { + if (m_delegate_sp->GetNumberOfActions() > 0) + return 1; + return 0; + } + + // Get the total number of needed lines to draw the contents. + int GetContentHeight() { + int height = 0; + height += GetErrorHeight(); + for (int i = 0; i < m_delegate_sp->GetNumberOfFields(); i++) { + if (!m_delegate_sp->GetField(i)->FieldDelegateIsVisible()) + continue; + height += m_delegate_sp->GetField(i)->FieldDelegateGetHeight(); + } + height += GetActionsHeight(); + return height; + } + + ScrollContext GetScrollContext() { + if (m_selection_type == SelectionType::Action) + return ScrollContext(GetContentHeight() - 1); + + FieldDelegate *field = m_delegate_sp->GetField(m_selection_index); + ScrollContext context = field->FieldDelegateGetScrollContext(); + + int offset = GetErrorHeight(); + for (int i = 0; i < m_selection_index; i++) { + if (!m_delegate_sp->GetField(i)->FieldDelegateIsVisible()) + continue; + offset += m_delegate_sp->GetField(i)->FieldDelegateGetHeight(); + } + context.Offset(offset); + + // If the context is touching the error, include the error in the context as + // well. + if (context.start == GetErrorHeight()) + context.start = 0; + + return context; + } + + void UpdateScrolling(DerivedWindow &surface) { + ScrollContext context = GetScrollContext(); + int content_height = GetContentHeight(); + int surface_height = surface.GetHeight(); + int visible_height = std::min(content_height, surface_height); + int last_visible_line = m_first_visible_line + visible_height - 1; + + // If the last visible line is bigger than the content, then it is invalid + // and needs to be set to the last line in the content. This can happen when + // a field has shrunk in height. + if (last_visible_line > content_height - 1) { + m_first_visible_line = content_height - visible_height; + } + + if (context.start < m_first_visible_line) { + m_first_visible_line = context.start; + return; + } + + if (context.end > last_visible_line) { + m_first_visible_line = context.end - visible_height + 1; + } + } + + void DrawError(SubPad &surface) { + if (!m_delegate_sp->HasError()) + return; + surface.MoveCursor(0, 0); + surface.AttributeOn(COLOR_PAIR(RedOnBlack)); + surface.PutChar(ACS_DIAMOND); + surface.PutChar(' '); + surface.PutCStringTruncated(1, m_delegate_sp->GetError().c_str()); + surface.AttributeOff(COLOR_PAIR(RedOnBlack)); + + surface.MoveCursor(0, 1); + surface.HorizontalLine(surface.GetWidth()); + } + + void DrawFields(SubPad &surface) { + int line = 0; + int width = surface.GetWidth(); + bool a_field_is_selected = m_selection_type == SelectionType::Field; + for (int i = 0; i < m_delegate_sp->GetNumberOfFields(); i++) { + FieldDelegate *field = m_delegate_sp->GetField(i); + if (!field->FieldDelegateIsVisible()) + continue; + bool is_field_selected = a_field_is_selected && m_selection_index == i; + int height = field->FieldDelegateGetHeight(); + Rect bounds = Rect(Point(0, line), Size(width, height)); + SubPad field_surface = SubPad(surface, bounds); + field->FieldDelegateDraw(field_surface, is_field_selected); + line += height; + } + } + + void DrawActions(SubPad &surface) { + int number_of_actions = m_delegate_sp->GetNumberOfActions(); + int width = surface.GetWidth() / number_of_actions; + bool an_action_is_selected = m_selection_type == SelectionType::Action; + int x = 0; + for (int i = 0; i < number_of_actions; i++) { + bool is_action_selected = an_action_is_selected && m_selection_index == i; + FormAction &action = m_delegate_sp->GetAction(i); + Rect bounds = Rect(Point(x, 0), Size(width, 1)); + SubPad action_surface = SubPad(surface, bounds); + action.Draw(action_surface, is_action_selected); + x += width; + } + } + + void DrawElements(SubPad &surface) { + Rect frame = surface.GetFrame(); + Rect fields_bounds, actions_bounds; + frame.HorizontalSplit(surface.GetHeight() - GetActionsHeight(), + fields_bounds, actions_bounds); + SubPad fields_surface = SubPad(surface, fields_bounds); + SubPad actions_surface = SubPad(surface, actions_bounds); + + DrawFields(fields_surface); + DrawActions(actions_surface); + } + + // Contents are first drawn on a pad. Then a subset of that pad is copied to + // the derived window starting at the first visible line. This essentially + // provides scrolling functionality. + void DrawContent(DerivedWindow &surface) { + UpdateScrolling(surface); + + int width = surface.GetWidth(); + int height = GetContentHeight(); + Pad pad = Pad(Size(width, height)); + + Rect frame = pad.GetFrame(); + Rect error_bounds, elements_bounds; + frame.HorizontalSplit(GetErrorHeight(), error_bounds, elements_bounds); + SubPad error_surface = SubPad(pad, error_bounds); + SubPad elements_surface = SubPad(pad, elements_bounds); + + DrawError(error_surface); + DrawElements(elements_surface); + + int copy_height = std::min(surface.GetHeight(), pad.GetHeight()); + pad.CopyToSurface(surface, Point(0, m_first_visible_line), Point(), + Size(width, copy_height)); + } + + bool WindowDelegateDraw(Window &window, bool force) override { + m_delegate_sp->UpdateFieldsVisibility(); + + window.Erase(); + + window.DrawTitleBox(m_delegate_sp->GetName().c_str(), + "Press Esc to cancel"); + + Rect content_bounds = window.GetFrame(); + content_bounds.Inset(2, 2); + DerivedWindow content_surface = DerivedWindow(window, content_bounds); + + DrawContent(content_surface); + return true; + } + + void SkipNextHiddenFields() { + while (true) { + if (m_delegate_sp->GetField(m_selection_index)->FieldDelegateIsVisible()) + return; + + if (m_selection_index == m_delegate_sp->GetNumberOfFields() - 1) { + m_selection_type = SelectionType::Action; + m_selection_index = 0; + return; + } + + m_selection_index++; + } + } + + HandleCharResult SelectNext(int key) { + if (m_selection_type == SelectionType::Action) { + if (m_selection_index < m_delegate_sp->GetNumberOfActions() - 1) { + m_selection_index++; + return eKeyHandled; + } + + m_selection_index = 0; + m_selection_type = SelectionType::Field; + SkipNextHiddenFields(); + if (m_selection_type == SelectionType::Field) { + FieldDelegate *next_field = m_delegate_sp->GetField(m_selection_index); + next_field->FieldDelegateSelectFirstElement(); + } + return eKeyHandled; + } + + FieldDelegate *field = m_delegate_sp->GetField(m_selection_index); + if (!field->FieldDelegateOnLastOrOnlyElement()) { + return field->FieldDelegateHandleChar(key); + } + + field->FieldDelegateExitCallback(); + + if (m_selection_index == m_delegate_sp->GetNumberOfFields() - 1) { + m_selection_type = SelectionType::Action; + m_selection_index = 0; + return eKeyHandled; + } + + m_selection_index++; + SkipNextHiddenFields(); + + if (m_selection_type == SelectionType::Field) { + FieldDelegate *next_field = m_delegate_sp->GetField(m_selection_index); + next_field->FieldDelegateSelectFirstElement(); + } + + return eKeyHandled; + } + + void SkipPreviousHiddenFields() { + while (true) { + if (m_delegate_sp->GetField(m_selection_index)->FieldDelegateIsVisible()) + return; + + if (m_selection_index == 0) { + m_selection_type = SelectionType::Action; + m_selection_index = 0; + return; + } + + m_selection_index--; + } + } + + HandleCharResult SelectPrevious(int key) { + if (m_selection_type == SelectionType::Action) { + if (m_selection_index > 0) { + m_selection_index--; + return eKeyHandled; + } + m_selection_index = m_delegate_sp->GetNumberOfFields() - 1; + m_selection_type = SelectionType::Field; + SkipPreviousHiddenFields(); + if (m_selection_type == SelectionType::Field) { + FieldDelegate *previous_field = + m_delegate_sp->GetField(m_selection_index); + previous_field->FieldDelegateSelectLastElement(); + } + return eKeyHandled; + } + + FieldDelegate *field = m_delegate_sp->GetField(m_selection_index); + if (!field->FieldDelegateOnFirstOrOnlyElement()) { + return field->FieldDelegateHandleChar(key); + } + + field->FieldDelegateExitCallback(); + + if (m_selection_index == 0) { + m_selection_type = SelectionType::Action; + m_selection_index = m_delegate_sp->GetNumberOfActions() - 1; + return eKeyHandled; + } + + m_selection_index--; + SkipPreviousHiddenFields(); + + if (m_selection_type == SelectionType::Field) { + FieldDelegate *previous_field = + m_delegate_sp->GetField(m_selection_index); + previous_field->FieldDelegateSelectLastElement(); + } + + return eKeyHandled; + } + + void ExecuteAction(Window &window) { + FormAction &action = m_delegate_sp->GetAction(m_selection_index); + action.Execute(window); + if (m_delegate_sp->HasError()) { + m_first_visible_line = 0; + m_selection_index = 0; + m_selection_type = SelectionType::Field; + } + } + + HandleCharResult WindowDelegateHandleChar(Window &window, int key) override { + switch (key) { + case '\r': + case '\n': + case KEY_ENTER: + if (m_selection_type == SelectionType::Action) { + ExecuteAction(window); + return eKeyHandled; + } + break; + case '\t': + return SelectNext(key); + case KEY_SHIFT_TAB: + return SelectPrevious(key); + case KEY_ESCAPE: + window.GetParent()->RemoveSubWindow(&window); + return eKeyHandled; + default: + break; + } + + // If the key wasn't handled and one of the fields is selected, pass the key + // to that field. + if (m_selection_type == SelectionType::Field) { + FieldDelegate *field = m_delegate_sp->GetField(m_selection_index); + return field->FieldDelegateHandleChar(key); + } + + return eKeyNotHandled; + } + +protected: + FormDelegateSP m_delegate_sp; + // The index of the currently selected SelectionType. + int m_selection_index; + // See SelectionType class enum. + SelectionType m_selection_type; + // The first visible line from the pad. + int m_first_visible_line; +}; - // Find first window that wants to be active if this window is active - const size_t num_subwindows = m_subwindows.size(); - for (size_t i = 0; i < num_subwindows; ++i) { - if (m_subwindows[i]->GetCanBeActive()) { - m_curr_active_window_idx = i; - break; - } - } - } - } +/////////////////////////// +// Form Delegate Instances +/////////////////////////// - if (m_curr_active_window_idx < m_subwindows.size()) - return m_subwindows[m_curr_active_window_idx]; +class DetachOrKillProcessFormDelegate : public FormDelegate { +public: + DetachOrKillProcessFormDelegate(Process *process) : m_process(process) { + SetError("There is a running process, either detach or kill it."); + + m_keep_stopped_field = + AddBooleanField("Keep process stopped when detaching.", false); + + AddAction("Detach", [this](Window &window) { Detach(window); }); + AddAction("Kill", [this](Window &window) { Kill(window); }); + } + + std::string GetName() override { return "Detach/Kill Process"; } + + void Kill(Window &window) { + Status destroy_status(m_process->Destroy(false)); + if (destroy_status.Fail()) { + SetError("Failed to kill process."); + return; } - return WindowSP(); + window.GetParent()->RemoveSubWindow(&window); } - bool GetCanBeActive() const { return m_can_activate; } + void Detach(Window &window) { + Status detach_status(m_process->Detach(m_keep_stopped_field->GetBoolean())); + if (detach_status.Fail()) { + SetError("Failed to detach from process."); + return; + } + window.GetParent()->RemoveSubWindow(&window); + } - void SetCanBeActive(bool b) { m_can_activate = b; } +protected: + Process *m_process; + BooleanFieldDelegate *m_keep_stopped_field; +}; - void SetDelegate(const WindowDelegateSP &delegate_sp) { - m_delegate_sp = delegate_sp; +class ProcessAttachFormDelegate : public FormDelegate { +public: + ProcessAttachFormDelegate(Debugger &debugger, WindowSP main_window_sp) + : m_debugger(debugger), m_main_window_sp(main_window_sp) { + std::vector types; + types.push_back(std::string("Name")); + types.push_back(std::string("PID")); + m_type_field = AddChoicesField("Attach By", 2, types); + m_pid_field = AddIntegerField("PID", 0, true); + m_name_field = + AddTextField("Process Name", GetDefaultProcessName().c_str(), true); + m_continue_field = AddBooleanField("Continue once attached.", false); + m_wait_for_field = AddBooleanField("Wait for process to launch.", false); + m_include_existing_field = + AddBooleanField("Include existing processes.", false); + m_show_advanced_field = AddBooleanField("Show advanced settings.", false); + m_plugin_field = AddProcessPluginField(); + + AddAction("Attach", [this](Window &window) { Attach(window); }); } - Window *GetParent() const { return m_parent; } + std::string GetName() override { return "Attach Process"; } - bool IsActive() const { - if (m_parent) - return m_parent->GetActiveWindow().get() == this; + void UpdateFieldsVisibility() override { + if (m_type_field->GetChoiceContent() == "Name") { + m_pid_field->FieldDelegateHide(); + m_name_field->FieldDelegateShow(); + m_wait_for_field->FieldDelegateShow(); + if (m_wait_for_field->GetBoolean()) + m_include_existing_field->FieldDelegateShow(); + else + m_include_existing_field->FieldDelegateHide(); + } else { + m_pid_field->FieldDelegateShow(); + m_name_field->FieldDelegateHide(); + m_wait_for_field->FieldDelegateHide(); + m_include_existing_field->FieldDelegateHide(); + } + if (m_show_advanced_field->GetBoolean()) + m_plugin_field->FieldDelegateShow(); else - return true; // Top level window is always active + m_plugin_field->FieldDelegateHide(); } - void SelectNextWindowAsActive() { - // Move active focus to next window - const size_t num_subwindows = m_subwindows.size(); - if (m_curr_active_window_idx == UINT32_MAX) { - uint32_t idx = 0; - for (auto subwindow_sp : m_subwindows) { - if (subwindow_sp->GetCanBeActive()) { - m_curr_active_window_idx = idx; - break; - } - ++idx; - } - } else if (m_curr_active_window_idx + 1 < num_subwindows) { - bool handled = false; - m_prev_active_window_idx = m_curr_active_window_idx; - for (size_t idx = m_curr_active_window_idx + 1; idx < num_subwindows; - ++idx) { - if (m_subwindows[idx]->GetCanBeActive()) { - m_curr_active_window_idx = idx; - handled = true; - break; - } - } - if (!handled) { - for (size_t idx = 0; idx <= m_prev_active_window_idx; ++idx) { - if (m_subwindows[idx]->GetCanBeActive()) { - m_curr_active_window_idx = idx; - break; - } - } - } + // Get the basename of the target's main executable if available, empty string + // otherwise. + std::string GetDefaultProcessName() { + Target *target = m_debugger.GetSelectedTarget().get(); + if (target == nullptr) + return ""; + + ModuleSP module_sp = target->GetExecutableModule(); + if (!module_sp->IsExecutable()) + return ""; + + return module_sp->GetFileSpec().GetFilename().AsCString(); + } + + bool StopRunningProcess() { + ExecutionContext exe_ctx = + m_debugger.GetCommandInterpreter().GetExecutionContext(); + + if (!exe_ctx.HasProcessScope()) + return false; + + Process *process = exe_ctx.GetProcessPtr(); + if (!(process && process->IsAlive())) + return false; + + FormDelegateSP form_delegate_sp = + FormDelegateSP(new DetachOrKillProcessFormDelegate(process)); + Rect bounds = m_main_window_sp->GetCenteredRect(85, 8); + WindowSP form_window_sp = m_main_window_sp->CreateSubWindow( + form_delegate_sp->GetName().c_str(), bounds, true); + WindowDelegateSP window_delegate_sp = + WindowDelegateSP(new FormWindowDelegate(form_delegate_sp)); + form_window_sp->SetDelegate(window_delegate_sp); + + return true; + } + + Target *GetTarget() { + Target *target = m_debugger.GetSelectedTarget().get(); + + if (target != nullptr) + return target; + + TargetSP new_target_sp; + m_debugger.GetTargetList().CreateTarget( + m_debugger, "", "", eLoadDependentsNo, nullptr, new_target_sp); + + target = new_target_sp.get(); + + if (target == nullptr) + SetError("Failed to create target."); + + m_debugger.GetTargetList().SetSelectedTarget(new_target_sp); + + return target; + } + + ProcessAttachInfo GetAttachInfo() { + ProcessAttachInfo attach_info; + attach_info.SetContinueOnceAttached(m_continue_field->GetBoolean()); + if (m_type_field->GetChoiceContent() == "Name") { + attach_info.GetExecutableFile().SetFile(m_name_field->GetText(), + FileSpec::Style::native); + attach_info.SetWaitForLaunch(m_wait_for_field->GetBoolean()); + if (m_wait_for_field->GetBoolean()) + attach_info.SetIgnoreExisting(!m_include_existing_field->GetBoolean()); } else { - m_prev_active_window_idx = m_curr_active_window_idx; - for (size_t idx = 0; idx < num_subwindows; ++idx) { - if (m_subwindows[idx]->GetCanBeActive()) { - m_curr_active_window_idx = idx; - break; - } - } + attach_info.SetProcessID(m_pid_field->GetInteger()); } + attach_info.SetProcessPluginName(m_plugin_field->GetPluginName()); + + return attach_info; } - const char *GetName() const { return m_name.c_str(); } + void Attach(Window &window) { + ClearError(); -protected: - std::string m_name; - WINDOW *m_window; - PANEL *m_panel; - Window *m_parent; - Windows m_subwindows; - WindowDelegateSP m_delegate_sp; - uint32_t m_curr_active_window_idx; - uint32_t m_prev_active_window_idx; - bool m_delete; - bool m_needs_update; - bool m_can_activate; - bool m_is_subwin; + bool all_fields_are_valid = CheckFieldsValidity(); + if (!all_fields_are_valid) + return; -private: - Window(const Window &) = delete; - const Window &operator=(const Window &) = delete; + bool process_is_running = StopRunningProcess(); + if (process_is_running) + return; + + Target *target = GetTarget(); + if (HasError()) + return; + + StreamString stream; + ProcessAttachInfo attach_info = GetAttachInfo(); + Status status = target->Attach(attach_info, &stream); + + if (status.Fail()) { + SetError(status.AsCString()); + return; + } + + ProcessSP process_sp(target->GetProcessSP()); + if (!process_sp) { + SetError("Attached sucessfully but target has no process."); + return; + } + + if (attach_info.GetContinueOnceAttached()) + process_sp->Resume(); + + window.GetParent()->RemoveSubWindow(&window); + } + +protected: + Debugger &m_debugger; + WindowSP m_main_window_sp; + + ChoicesFieldDelegate *m_type_field; + IntegerFieldDelegate *m_pid_field; + TextFieldDelegate *m_name_field; + BooleanFieldDelegate *m_continue_field; + BooleanFieldDelegate *m_wait_for_field; + BooleanFieldDelegate *m_include_existing_field; + BooleanFieldDelegate *m_show_advanced_field; + ProcessPluginFieldDelegate *m_plugin_field; }; class MenuDelegate { @@ -916,9 +2819,9 @@ void Menu::DrawMenuTitle(Window &window, bool highlight) { } else { const int shortcut_key = m_key_value; bool underlined_shortcut = false; - const attr_t hilgight_attr = A_REVERSE; + const attr_t highlight_attr = A_REVERSE; if (highlight) - window.AttributeOn(hilgight_attr); + window.AttributeOn(highlight_attr); if (llvm::isPrint(shortcut_key)) { size_t lower_pos = m_name.find(tolower(shortcut_key)); size_t upper_pos = m_name.find(toupper(shortcut_key)); @@ -945,18 +2848,18 @@ void Menu::DrawMenuTitle(Window &window, bool highlight) { } if (highlight) - window.AttributeOff(hilgight_attr); + window.AttributeOff(highlight_attr); if (m_key_name.empty()) { if (!underlined_shortcut && llvm::isPrint(m_key_value)) { - window.AttributeOn(COLOR_PAIR(3)); + window.AttributeOn(COLOR_PAIR(MagentaOnWhite)); window.Printf(" (%c)", m_key_value); - window.AttributeOff(COLOR_PAIR(3)); + window.AttributeOff(COLOR_PAIR(MagentaOnWhite)); } } else { - window.AttributeOn(COLOR_PAIR(3)); + window.AttributeOn(COLOR_PAIR(MagentaOnWhite)); window.Printf(" (%s)", m_key_name.c_str()); - window.AttributeOff(COLOR_PAIR(3)); + window.AttributeOff(COLOR_PAIR(MagentaOnWhite)); } } } @@ -968,7 +2871,7 @@ bool Menu::WindowDelegateDraw(Window &window, bool force) { Menu::Type menu_type = GetType(); switch (menu_type) { case Menu::Type::Bar: { - window.SetBackground(2); + window.SetBackground(BlackOnWhite); window.MoveCursor(0, 0); for (size_t i = 0; i < num_submenus; ++i) { Menu *menu = submenus[i].get(); @@ -988,7 +2891,7 @@ bool Menu::WindowDelegateDraw(Window &window, bool force) { int cursor_x = 0; int cursor_y = 0; window.Erase(); - window.SetBackground(2); + window.SetBackground(BlackOnWhite); window.Box(); for (size_t i = 0; i < num_submenus; ++i) { const bool is_selected = (i == static_cast(selected_idx)); @@ -1162,8 +3065,6 @@ public: } void Initialize() { - ::setlocale(LC_ALL, ""); - ::setlocale(LC_CTYPE, ""); m_screen = ::newterm(nullptr, m_out, m_in); ::start_color(); ::curs_set(0); @@ -1189,18 +3090,16 @@ public: ListenerSP listener_sp( Listener::MakeListener("lldb.IOHandler.curses.Application")); - ConstString broadcaster_class_target(Target::GetStaticBroadcasterClass()); ConstString broadcaster_class_process(Process::GetStaticBroadcasterClass()); - ConstString broadcaster_class_thread(Thread::GetStaticBroadcasterClass()); debugger.EnableForwardEvents(listener_sp); - bool update = true; + m_update_screen = true; #if defined(__APPLE__) std::deque escape_chars; #endif while (!done) { - if (update) { + if (m_update_screen) { m_window_sp->Draw(false); // All windows should be calling Window::DeferredRefresh() instead of // Window::Refresh() so we can do a single update and avoid any screen @@ -1212,7 +3111,7 @@ public: m_window_sp->MoveCursor(0, 0); doupdate(); - update = false; + m_update_screen = false; } #if defined(__APPLE__) @@ -1272,9 +3171,7 @@ public: ConstString broadcaster_class( broadcaster->GetBroadcasterClass()); if (broadcaster_class == broadcaster_class_process) { - debugger.GetCommandInterpreter().UpdateExecutionContext( - nullptr); - update = true; + m_update_screen = true; continue; // Don't get any key, just update our view } } @@ -1285,10 +3182,13 @@ public: HandleCharResult key_result = m_window_sp->HandleChar(ch); switch (key_result) { case eKeyHandled: - debugger.GetCommandInterpreter().UpdateExecutionContext(nullptr); - update = true; + m_update_screen = true; break; case eKeyNotHandled: + if (ch == 12) { // Ctrl+L, force full redraw + redrawwin(m_window_sp->get()); + m_update_screen = true; + } break; case eQuitApplication: done = true; @@ -1306,12 +3206,65 @@ public: return m_window_sp; } + void TerminalSizeChanged() { + ::endwin(); + ::refresh(); + Rect content_bounds = m_window_sp->GetFrame(); + m_window_sp->SetBounds(content_bounds); + if (WindowSP menubar_window_sp = m_window_sp->FindSubWindow("Menubar")) + menubar_window_sp->SetBounds(content_bounds.MakeMenuBar()); + if (WindowSP status_window_sp = m_window_sp->FindSubWindow("Status")) + status_window_sp->SetBounds(content_bounds.MakeStatusBar()); + + WindowSP source_window_sp = m_window_sp->FindSubWindow("Source"); + WindowSP variables_window_sp = m_window_sp->FindSubWindow("Variables"); + WindowSP registers_window_sp = m_window_sp->FindSubWindow("Registers"); + WindowSP threads_window_sp = m_window_sp->FindSubWindow("Threads"); + + Rect threads_bounds; + Rect source_variables_bounds; + content_bounds.VerticalSplitPercentage(0.80, source_variables_bounds, + threads_bounds); + if (threads_window_sp) + threads_window_sp->SetBounds(threads_bounds); + else + source_variables_bounds = content_bounds; + + Rect source_bounds; + Rect variables_registers_bounds; + source_variables_bounds.HorizontalSplitPercentage( + 0.70, source_bounds, variables_registers_bounds); + if (variables_window_sp || registers_window_sp) { + if (variables_window_sp && registers_window_sp) { + Rect variables_bounds; + Rect registers_bounds; + variables_registers_bounds.VerticalSplitPercentage( + 0.50, variables_bounds, registers_bounds); + variables_window_sp->SetBounds(variables_bounds); + registers_window_sp->SetBounds(registers_bounds); + } else if (variables_window_sp) { + variables_window_sp->SetBounds(variables_registers_bounds); + } else { + registers_window_sp->SetBounds(variables_registers_bounds); + } + } else { + source_bounds = source_variables_bounds; + } + + source_window_sp->SetBounds(source_bounds); + + touchwin(stdscr); + redrawwin(m_window_sp->get()); + m_update_screen = true; + } + protected: WindowSP m_window_sp; WindowDelegates m_window_delegates; SCREEN *m_screen; FILE *m_in; FILE *m_out; + bool m_update_screen = false; }; } // namespace curses @@ -1319,22 +3272,21 @@ protected: using namespace curses; struct Row { - ValueObjectManager value; + ValueObjectUpdater value; Row *parent; // The process stop ID when the children were calculated. - uint32_t children_stop_id; - int row_idx; - int x; - int y; + uint32_t children_stop_id = 0; + int row_idx = 0; + int x = 1; + int y = 1; bool might_have_children; - bool expanded; - bool calculated_children; + bool expanded = false; + bool calculated_children = false; std::vector children; Row(const ValueObjectSP &v, Row *p) - : value(v, lldb::eDynamicDontRunTarget, true), parent(p), row_idx(0), - x(1), y(1), might_have_children(v ? v->MightHaveChildren() : false), - expanded(false), calculated_children(false), children() {} + : value(v), parent(p), + might_have_children(v ? v->MightHaveChildren() : false) {} size_t GetDepth() const { if (parent) @@ -1436,8 +3388,13 @@ public: virtual void TreeDelegateDrawTreeItem(TreeItem &item, Window &window) = 0; virtual void TreeDelegateGenerateChildren(TreeItem &item) = 0; + virtual void TreeDelegateUpdateSelection(TreeItem &root, int &selection_index, + TreeItem *&selected_item) { + return; + } virtual bool TreeDelegateItemSelected( TreeItem &item) = 0; // Return true if we need to update views + virtual bool TreeDelegateExpandRootByDefault() { return false; } }; typedef std::shared_ptr TreeDelegateSP; @@ -1447,7 +3404,10 @@ public: TreeItem(TreeItem *parent, TreeDelegate &delegate, bool might_have_children) : m_parent(parent), m_delegate(delegate), m_user_data(nullptr), m_identifier(0), m_row_idx(-1), m_children(), - m_might_have_children(might_have_children), m_is_expanded(false) {} + m_might_have_children(might_have_children), m_is_expanded(false) { + if (m_parent == nullptr) + m_is_expanded = m_delegate.TreeDelegateExpandRootByDefault(); + } TreeItem &operator=(const TreeItem &rhs) { if (this != &rhs) { @@ -1676,6 +3636,8 @@ public: const int num_visible_rows = NumVisibleRows(); m_num_rows = 0; m_root.CalculateRowIndexes(m_num_rows); + m_delegate_sp->TreeDelegateUpdateSelection(m_root, m_selected_row_idx, + m_selected_item); // If we unexpanded while having something selected our total number of // rows is less than the num visible rows, then make sure we show all the @@ -1849,7 +3811,7 @@ public: if (FormatEntity::Format(m_format, strm, &sc, &exe_ctx, nullptr, nullptr, false, false)) { int right_pad = 1; - window.PutCStringTruncated(strm.GetString().str().c_str(), right_pad); + window.PutCStringTruncated(right_pad, strm.GetString().str().c_str()); } } } @@ -1908,7 +3870,7 @@ public: if (FormatEntity::Format(m_format, strm, nullptr, &exe_ctx, nullptr, nullptr, false, false)) { int right_pad = 1; - window.PutCStringTruncated(strm.GetString().str().c_str(), right_pad); + window.PutCStringTruncated(right_pad, strm.GetString().str().c_str()); } } } @@ -1977,7 +3939,7 @@ class ThreadsTreeDelegate : public TreeDelegate { public: ThreadsTreeDelegate(Debugger &debugger) : TreeDelegate(), m_thread_delegate_sp(), m_debugger(debugger), - m_stop_id(UINT32_MAX) { + m_stop_id(UINT32_MAX), m_update_selection(false) { FormatEntity::Parse("process ${process.id}{, name = ${process.name}}", m_format); } @@ -1998,13 +3960,14 @@ public: if (FormatEntity::Format(m_format, strm, nullptr, &exe_ctx, nullptr, nullptr, false, false)) { int right_pad = 1; - window.PutCStringTruncated(strm.GetString().str().c_str(), right_pad); + window.PutCStringTruncated(right_pad, strm.GetString().str().c_str()); } } } void TreeDelegateGenerateChildren(TreeItem &item) override { ProcessSP process_sp = GetProcess(); + m_update_selection = false; if (process_sp && process_sp->IsAlive()) { StateType state = process_sp->GetState(); if (StateIsStoppedState(state, true)) { @@ -2013,6 +3976,7 @@ public: return; // Children are already up to date m_stop_id = stop_id; + m_update_selection = true; if (!m_thread_delegate_sp) { // Always expand the thread item the first time we show it @@ -2024,11 +3988,15 @@ public: TreeItem t(&item, *m_thread_delegate_sp, false); ThreadList &threads = process_sp->GetThreadList(); std::lock_guard guard(threads.GetMutex()); + ThreadSP selected_thread = threads.GetSelectedThread(); size_t num_threads = threads.GetSize(); item.Resize(num_threads, t); for (size_t i = 0; i < num_threads; ++i) { - item[i].SetIdentifier(threads.GetThreadAtIndex(i)->GetID()); + ThreadSP thread = threads.GetThreadAtIndex(i); + item[i].SetIdentifier(thread->GetID()); item[i].SetMightHaveChildren(true); + if (selected_thread->GetID() == thread->GetID()) + item[i].Expand(); } return; } @@ -2036,20 +4004,48 @@ public: item.ClearChildren(); } + void TreeDelegateUpdateSelection(TreeItem &root, int &selection_index, + TreeItem *&selected_item) override { + if (!m_update_selection) + return; + + ProcessSP process_sp = GetProcess(); + if (!(process_sp && process_sp->IsAlive())) + return; + + StateType state = process_sp->GetState(); + if (!StateIsStoppedState(state, true)) + return; + + ThreadList &threads = process_sp->GetThreadList(); + std::lock_guard guard(threads.GetMutex()); + ThreadSP selected_thread = threads.GetSelectedThread(); + size_t num_threads = threads.GetSize(); + for (size_t i = 0; i < num_threads; ++i) { + ThreadSP thread = threads.GetThreadAtIndex(i); + if (selected_thread->GetID() == thread->GetID()) { + selected_item = &root[i][thread->GetSelectedFrameIndex()]; + selection_index = selected_item->GetRowIndex(); + return; + } + } + } + bool TreeDelegateItemSelected(TreeItem &item) override { return false; } + bool TreeDelegateExpandRootByDefault() override { return true; } + protected: std::shared_ptr m_thread_delegate_sp; Debugger &m_debugger; uint32_t m_stop_id; + bool m_update_selection; FormatEntity::Entry m_format; }; class ValueObjectListDelegate : public WindowDelegate { public: - ValueObjectListDelegate() - : m_rows(), m_selected_row(nullptr), m_selected_row_idx(0), - m_first_visible_row(0), m_num_rows(0), m_max_x(0), m_max_y(0) {} + ValueObjectListDelegate() : m_rows() {} ValueObjectListDelegate(ValueObjectList &valobj_list) : m_rows(), m_selected_row(nullptr), m_selected_row_idx(0), @@ -2237,14 +4233,14 @@ public: protected: std::vector m_rows; - Row *m_selected_row; - uint32_t m_selected_row_idx; - uint32_t m_first_visible_row; - uint32_t m_num_rows; + Row *m_selected_row = nullptr; + uint32_t m_selected_row_idx = 0; + uint32_t m_first_visible_row = 0; + uint32_t m_num_rows = 0; int m_min_x; int m_min_y; - int m_max_x; - int m_max_y; + int m_max_x = 0; + int m_max_y = 0; static Format FormatForChar(int c) { switch (c) { @@ -2301,29 +4297,29 @@ protected: window.AttributeOn(A_REVERSE); if (type_name && type_name[0]) - window.Printf("(%s) ", type_name); + window.PrintfTruncated(1, "(%s) ", type_name); if (name && name[0]) - window.PutCString(name); + window.PutCStringTruncated(1, name); attr_t changd_attr = 0; if (valobj->GetValueDidChange()) - changd_attr = COLOR_PAIR(5) | A_BOLD; + changd_attr = COLOR_PAIR(RedOnBlack) | A_BOLD; if (value && value[0]) { - window.PutCString(" = "); + window.PutCStringTruncated(1, " = "); if (changd_attr) window.AttributeOn(changd_attr); - window.PutCString(value); + window.PutCStringTruncated(1, value); if (changd_attr) window.AttributeOff(changd_attr); } if (summary && summary[0]) { - window.PutChar(' '); + window.PutCStringTruncated(1, " "); if (changd_attr) window.AttributeOn(changd_attr); - window.PutCString(summary); + window.PutCStringTruncated(1, summary); if (changd_attr) window.AttributeOff(changd_attr); } @@ -2761,7 +4757,7 @@ bool HelpDialogDelegate::WindowDelegateDraw(Window &window, bool force) { while (y <= max_y) { window.MoveCursor(x, y); window.PutCStringTruncated( - m_text.GetStringAtIndex(m_first_visible_line + y - min_y), 1); + 1, m_text.GetStringAtIndex(m_first_visible_line + y - min_y)); ++y; } return true; @@ -2831,7 +4827,8 @@ public: eMenuID_Process, eMenuID_ProcessAttach, - eMenuID_ProcessDetach, + eMenuID_ProcessDetachResume, + eMenuID_ProcessDetachSuspended, eMenuID_ProcessLaunch, eMenuID_ProcessContinue, eMenuID_ProcessHalt, @@ -2867,6 +4864,10 @@ public: window.SelectNextWindowAsActive(); return eKeyHandled; + case KEY_SHIFT_TAB: + window.SelectPreviousWindowAsActive(); + return eKeyHandled; + case 'h': window.CreateHelpSubwindow(); return eKeyHandled; @@ -2891,6 +4892,7 @@ public: KeyHelp *WindowDelegateGetKeyHelp() override { static curses::KeyHelp g_source_view_key_help[] = { {'\t', "Select next view"}, + {KEY_BTAB, "Select previous view"}, {'h', "Show help dialog with view specific key bindings"}, {',', "Page up"}, {'.', "Page down"}, @@ -2942,6 +4944,19 @@ public: } return MenuActionResult::Handled; + case eMenuID_ProcessAttach: { + WindowSP main_window_sp = m_app.GetMainWindow(); + FormDelegateSP form_delegate_sp = FormDelegateSP( + new ProcessAttachFormDelegate(m_debugger, main_window_sp)); + Rect bounds = main_window_sp->GetCenteredRect(80, 22); + WindowSP form_window_sp = main_window_sp->CreateSubWindow( + form_delegate_sp->GetName().c_str(), bounds, true); + WindowDelegateSP window_delegate_sp = + WindowDelegateSP(new FormWindowDelegate(form_delegate_sp)); + form_window_sp->SetDelegate(window_delegate_sp); + return MenuActionResult::Handled; + } + case eMenuID_ProcessContinue: { ExecutionContext exe_ctx = m_debugger.GetCommandInterpreter().GetExecutionContext(); @@ -2976,13 +4991,15 @@ public: } return MenuActionResult::Handled; - case eMenuID_ProcessDetach: { + case eMenuID_ProcessDetachResume: + case eMenuID_ProcessDetachSuspended: { ExecutionContext exe_ctx = m_debugger.GetCommandInterpreter().GetExecutionContext(); if (exe_ctx.HasProcessScope()) { Process *process = exe_ctx.GetProcessPtr(); if (process && process->IsAlive()) - process->Detach(false); + process->Detach(menu.GetIdentifier() == + eMenuID_ProcessDetachSuspended); } } return MenuActionResult::Handled; @@ -3072,7 +5089,7 @@ public: new_registers_rect); registers_window_sp->SetBounds(new_registers_rect); } else { - // No variables window, grab the bottom part of the source window + // No registers window, grab the bottom part of the source window Rect new_source_rect; source_bounds.HorizontalSplitPercentage(0.70, new_source_rect, new_variables_rect); @@ -3123,7 +5140,7 @@ public: new_regs_rect); variables_window_sp->SetBounds(new_vars_rect); } else { - // No registers window, grab the bottom part of the source window + // No variables window, grab the bottom part of the source window Rect new_source_rect; source_bounds.HorizontalSplitPercentage(0.70, new_source_rect, new_regs_rect); @@ -3169,7 +5186,7 @@ public: Thread *thread = exe_ctx.GetThreadPtr(); StackFrame *frame = exe_ctx.GetFramePtr(); window.Erase(); - window.SetBackground(2); + window.SetBackground(BlackOnWhite); window.MoveCursor(0, 0); if (process) { const StateType state = process->GetState(); @@ -3181,7 +5198,7 @@ public: if (thread && FormatEntity::Format(m_format, strm, nullptr, &exe_ctx, nullptr, nullptr, false, false)) { window.MoveCursor(40, 0); - window.PutCStringTruncated(strm.GetString().str().c_str(), 1); + window.PutCStringTruncated(1, strm.GetString().str().c_str()); } window.MoveCursor(60, 0); @@ -3212,9 +5229,10 @@ public: SourceFileWindowDelegate(Debugger &debugger) : WindowDelegate(), m_debugger(debugger), m_sc(), m_file_sp(), m_disassembly_scope(nullptr), m_disassembly_sp(), m_disassembly_range(), - m_title(), m_line_width(4), m_selected_line(0), m_pc_line(0), - m_stop_id(0), m_frame_idx(UINT32_MAX), m_first_visible_line(0), - m_min_x(0), m_min_y(0), m_max_x(0), m_max_y(0) {} + m_title(), m_tid(LLDB_INVALID_THREAD_ID), m_line_width(4), + m_selected_line(0), m_pc_line(0), m_stop_id(0), m_frame_idx(UINT32_MAX), + m_first_visible_line(0), m_first_visible_column(0), m_min_x(0), + m_min_y(0), m_max_x(0), m_max_y(0) {} ~SourceFileWindowDelegate() override = default; @@ -3231,19 +5249,21 @@ public: {KEY_RETURN, "Run to selected line with one shot breakpoint"}, {KEY_UP, "Select previous source line"}, {KEY_DOWN, "Select next source line"}, + {KEY_LEFT, "Scroll to the left"}, + {KEY_RIGHT, "Scroll to the right"}, {KEY_PPAGE, "Page up"}, {KEY_NPAGE, "Page down"}, {'b', "Set breakpoint on selected source/disassembly line"}, {'c', "Continue process"}, - {'d', "Detach and resume process"}, {'D', "Detach with process suspended"}, {'h', "Show help dialog"}, - {'k', "Kill process"}, {'n', "Step over (source line)"}, {'N', "Step over (single instruction)"}, - {'o', "Step out"}, + {'f', "Step out (finish)"}, {'s', "Step in (source line)"}, {'S', "Step in (single instruction)"}, + {'u', "Frame up"}, + {'d', "Frame down"}, {',', "Page up"}, {'.', "Page down"}, {'\0', nullptr}}; @@ -3367,7 +5387,7 @@ public: if (m_disassembly_scope != m_sc.function) { m_disassembly_scope = m_sc.function; m_disassembly_sp = m_sc.function->GetInstructions( - exe_ctx, nullptr, prefer_file_cache); + exe_ctx, nullptr, !prefer_file_cache); if (m_disassembly_sp) { set_selected_line_to_pc = true; m_disassembly_range = m_sc.function->GetAddressRange(); @@ -3407,7 +5427,7 @@ public: window.AttributeOn(A_REVERSE); window.MoveCursor(1, 1); window.PutChar(' '); - window.PutCStringTruncated(m_title.GetString().str().c_str(), 1); + window.PutCStringTruncated(1, m_title.GetString().str().c_str()); int x = window.GetCursorX(); if (x < window_width - 1) { window.Printf("%*s", window_width - x - 1, ""); @@ -3441,7 +5461,7 @@ public: } const attr_t selected_highlight_attr = A_REVERSE; - const attr_t pc_highlight_attr = COLOR_PAIR(1); + const attr_t pc_highlight_attr = COLOR_PAIR(BlackOnBlue); for (size_t i = 0; i < num_visible_lines; ++i) { const uint32_t curr_line = m_first_visible_line + i; @@ -3460,7 +5480,7 @@ public: highlight_attr = selected_highlight_attr; if (bp_lines.find(curr_line + 1) != bp_lines.end()) - bp_attr = COLOR_PAIR(2); + bp_attr = COLOR_PAIR(BlackOnWhite); if (bp_attr) window.AttributeOn(bp_attr); @@ -3479,10 +5499,21 @@ public: if (highlight_attr) window.AttributeOn(highlight_attr); - const uint32_t line_len = - m_file_sp->GetLineLength(curr_line + 1, false); - if (line_len > 0) - window.PutCString(m_file_sp->PeekLineData(curr_line + 1), line_len); + + StreamString lineStream; + m_file_sp->DisplaySourceLines(curr_line + 1, {}, 0, 0, &lineStream); + StringRef line = lineStream.GetString(); + if (line.endswith("\n")) + line = line.drop_back(); + bool wasWritten = window.OutputColoredStringTruncated( + 1, line, m_first_visible_column, line_is_selected); + if (line_is_selected && !wasWritten) { + // Draw an empty space to show the selected line if empty, + // or draw '<' if nothing is visible because of scrolling too much + // to the right. + window.PutCStringTruncated( + 1, line.empty() && m_first_visible_column == 0 ? " " : "<"); + } if (is_pc_line && frame_sp && frame_sp->GetConcreteFrameIndex() == 0) { @@ -3494,11 +5525,15 @@ public: if (stop_description && stop_description[0]) { size_t stop_description_len = strlen(stop_description); int desc_x = window_width - stop_description_len - 16; - window.Printf("%*s", desc_x - window.GetCursorX(), ""); - // window.MoveCursor(window_width - stop_description_len - 15, - // line_y); - window.Printf("<<< Thread %u: %s ", thread->GetIndexID(), - stop_description); + if (desc_x - window.GetCursorX() > 0) + window.Printf("%*s", desc_x - window.GetCursorX(), ""); + window.MoveCursor(window_width - stop_description_len - 16, + line_y); + const attr_t stop_reason_attr = COLOR_PAIR(WhiteOnBlue); + window.AttributeOn(stop_reason_attr); + window.PrintfTruncated(1, " <<< Thread %u: %s ", + thread->GetIndexID(), stop_description); + window.AttributeOff(stop_reason_attr); } } else { window.Printf("%*s", window_width - window.GetCursorX() - 1, ""); @@ -3538,7 +5573,7 @@ public: } const attr_t selected_highlight_attr = A_REVERSE; - const attr_t pc_highlight_attr = COLOR_PAIR(1); + const attr_t pc_highlight_attr = COLOR_PAIR(WhiteOnBlue); StreamString strm; @@ -3586,7 +5621,7 @@ public: if (bp_file_addrs.find(inst->GetAddress().GetFileAddress()) != bp_file_addrs.end()) - bp_attr = COLOR_PAIR(2); + bp_attr = COLOR_PAIR(BlackOnWhite); if (bp_attr) window.AttributeOn(bp_attr); @@ -3629,7 +5664,9 @@ public: strm.Printf("%s", mnemonic); int right_pad = 1; - window.PutCStringTruncated(strm.GetData(), right_pad); + window.PutCStringTruncated( + right_pad, + strm.GetString().substr(m_first_visible_column).data()); if (is_pc_line && frame_sp && frame_sp->GetConcreteFrameIndex() == 0) { @@ -3641,11 +5678,12 @@ public: if (stop_description && stop_description[0]) { size_t stop_description_len = strlen(stop_description); int desc_x = window_width - stop_description_len - 16; - window.Printf("%*s", desc_x - window.GetCursorX(), ""); - // window.MoveCursor(window_width - stop_description_len - 15, - // line_y); - window.Printf("<<< Thread %u: %s ", thread->GetIndexID(), - stop_description); + if (desc_x - window.GetCursorX() > 0) + window.Printf("%*s", desc_x - window.GetCursorX(), ""); + window.MoveCursor(window_width - stop_description_len - 15, + line_y); + window.PrintfTruncated(1, "<<< Thread %u: %s ", + thread->GetIndexID(), stop_description); } } else { window.Printf("%*s", window_width - window.GetCursorX() - 1, ""); @@ -3723,6 +5761,15 @@ public: } return eKeyHandled; + case KEY_LEFT: + if (m_first_visible_column > 0) + --m_first_visible_column; + return eKeyHandled; + + case KEY_RIGHT: + ++m_first_visible_column; + return eKeyHandled; + case '\r': case '\n': case KEY_ENTER: @@ -3744,7 +5791,7 @@ public: false, // request_hardware eLazyBoolCalculate); // move_to_nearest_code // Make breakpoint one shot - bp_sp->GetOptions()->SetOneShot(true); + bp_sp->GetOptions().SetOneShot(true); exe_ctx.GetProcessRef().Resume(); } } else if (m_selected_line < GetNumDisassemblyLines()) { @@ -3760,66 +5807,25 @@ public: false, // internal false); // request_hardware // Make breakpoint one shot - bp_sp->GetOptions()->SetOneShot(true); + bp_sp->GetOptions().SetOneShot(true); exe_ctx.GetProcessRef().Resume(); } } return eKeyHandled; case 'b': // 'b' == toggle breakpoint on currently selected line - if (m_selected_line < GetNumSourceLines()) { - ExecutionContext exe_ctx = - m_debugger.GetCommandInterpreter().GetExecutionContext(); - if (exe_ctx.HasTargetScope()) { - BreakpointSP bp_sp = exe_ctx.GetTargetRef().CreateBreakpoint( - nullptr, // Don't limit the breakpoint to certain modules - m_file_sp->GetFileSpec(), // Source file - m_selected_line + - 1, // Source line number (m_selected_line is zero based) - 0, // No column specified. - 0, // No offset - eLazyBoolCalculate, // Check inlines using global setting - eLazyBoolCalculate, // Skip prologue using global setting, - false, // internal - false, // request_hardware - eLazyBoolCalculate); // move_to_nearest_code - } - } else if (m_selected_line < GetNumDisassemblyLines()) { - const Instruction *inst = m_disassembly_sp->GetInstructionList() - .GetInstructionAtIndex(m_selected_line) - .get(); - ExecutionContext exe_ctx = - m_debugger.GetCommandInterpreter().GetExecutionContext(); - if (exe_ctx.HasTargetScope()) { - Address addr = inst->GetAddress(); - BreakpointSP bp_sp = exe_ctx.GetTargetRef().CreateBreakpoint( - addr, // lldb_private::Address - false, // internal - false); // request_hardware - } - } + ToggleBreakpointOnSelectedLine(); return eKeyHandled; - case 'd': // 'd' == detach and let run case 'D': // 'D' == detach and keep stopped { ExecutionContext exe_ctx = m_debugger.GetCommandInterpreter().GetExecutionContext(); if (exe_ctx.HasProcessScope()) - exe_ctx.GetProcessRef().Detach(c == 'D'); + exe_ctx.GetProcessRef().Detach(true); } return eKeyHandled; - case 'k': - // 'k' == kill - { - ExecutionContext exe_ctx = - m_debugger.GetCommandInterpreter().GetExecutionContext(); - if (exe_ctx.HasProcessScope()) - exe_ctx.GetProcessRef().Destroy(false); - } - return eKeyHandled; - case 'c': // 'c' == continue { @@ -3830,8 +5836,8 @@ public: } return eKeyHandled; - case 'o': - // 'o' == step out + case 'f': + // 'f' == step out (finish) { ExecutionContext exe_ctx = m_debugger.GetCommandInterpreter().GetExecutionContext(); @@ -3868,6 +5874,26 @@ public: } return eKeyHandled; + case 'u': // 'u' == frame up + case 'd': // 'd' == frame down + { + ExecutionContext exe_ctx = + m_debugger.GetCommandInterpreter().GetExecutionContext(); + if (exe_ctx.HasThreadScope()) { + Thread *thread = exe_ctx.GetThreadPtr(); + uint32_t frame_idx = thread->GetSelectedFrameIndex(); + if (frame_idx == UINT32_MAX) + frame_idx = 0; + if (c == 'u' && frame_idx + 1 < thread->GetStackFrameCount()) + ++frame_idx; + else if (c == 'd' && frame_idx > 0) + --frame_idx; + if (thread->SetSelectedFrameByIndex(frame_idx, true)) + exe_ctx.SetFrameSP(thread->GetSelectedFrame()); + } + } + return eKeyHandled; + case 'h': window.CreateHelpSubwindow(); return eKeyHandled; @@ -3878,6 +5904,85 @@ public: return eKeyNotHandled; } + void ToggleBreakpointOnSelectedLine() { + ExecutionContext exe_ctx = + m_debugger.GetCommandInterpreter().GetExecutionContext(); + if (!exe_ctx.HasTargetScope()) + return; + if (GetNumSourceLines() > 0) { + // Source file breakpoint. + BreakpointList &bp_list = exe_ctx.GetTargetRef().GetBreakpointList(); + const size_t num_bps = bp_list.GetSize(); + for (size_t bp_idx = 0; bp_idx < num_bps; ++bp_idx) { + BreakpointSP bp_sp = bp_list.GetBreakpointAtIndex(bp_idx); + const size_t num_bps_locs = bp_sp->GetNumLocations(); + for (size_t bp_loc_idx = 0; bp_loc_idx < num_bps_locs; ++bp_loc_idx) { + BreakpointLocationSP bp_loc_sp = + bp_sp->GetLocationAtIndex(bp_loc_idx); + LineEntry bp_loc_line_entry; + if (bp_loc_sp->GetAddress().CalculateSymbolContextLineEntry( + bp_loc_line_entry)) { + if (m_file_sp->GetFileSpec() == bp_loc_line_entry.file && + m_selected_line + 1 == bp_loc_line_entry.line) { + bool removed = + exe_ctx.GetTargetRef().RemoveBreakpointByID(bp_sp->GetID()); + assert(removed); + UNUSED_IF_ASSERT_DISABLED(removed); + return; // Existing breakpoint removed. + } + } + } + } + // No breakpoint found on the location, add it. + BreakpointSP bp_sp = exe_ctx.GetTargetRef().CreateBreakpoint( + nullptr, // Don't limit the breakpoint to certain modules + m_file_sp->GetFileSpec(), // Source file + m_selected_line + + 1, // Source line number (m_selected_line is zero based) + 0, // No column specified. + 0, // No offset + eLazyBoolCalculate, // Check inlines using global setting + eLazyBoolCalculate, // Skip prologue using global setting, + false, // internal + false, // request_hardware + eLazyBoolCalculate); // move_to_nearest_code + } else { + // Disassembly breakpoint. + assert(GetNumDisassemblyLines() > 0); + assert(m_selected_line < GetNumDisassemblyLines()); + const Instruction *inst = m_disassembly_sp->GetInstructionList() + .GetInstructionAtIndex(m_selected_line) + .get(); + Address addr = inst->GetAddress(); + // Try to find it. + BreakpointList &bp_list = exe_ctx.GetTargetRef().GetBreakpointList(); + const size_t num_bps = bp_list.GetSize(); + for (size_t bp_idx = 0; bp_idx < num_bps; ++bp_idx) { + BreakpointSP bp_sp = bp_list.GetBreakpointAtIndex(bp_idx); + const size_t num_bps_locs = bp_sp->GetNumLocations(); + for (size_t bp_loc_idx = 0; bp_loc_idx < num_bps_locs; ++bp_loc_idx) { + BreakpointLocationSP bp_loc_sp = + bp_sp->GetLocationAtIndex(bp_loc_idx); + LineEntry bp_loc_line_entry; + const lldb::addr_t file_addr = + bp_loc_sp->GetAddress().GetFileAddress(); + if (file_addr == addr.GetFileAddress()) { + bool removed = + exe_ctx.GetTargetRef().RemoveBreakpointByID(bp_sp->GetID()); + assert(removed); + UNUSED_IF_ASSERT_DISABLED(removed); + return; // Existing breakpoint removed. + } + } + } + // No breakpoint found on the address, add it. + BreakpointSP bp_sp = + exe_ctx.GetTargetRef().CreateBreakpoint(addr, // lldb_private::Address + false, // internal + false); // request_hardware + } + } + protected: typedef std::set BreakpointLines; typedef std::set BreakpointAddrs; @@ -3896,6 +6001,7 @@ protected: uint32_t m_stop_id; uint32_t m_frame_idx; int m_first_visible_line; + int m_first_visible_column; int m_min_x; int m_min_y; int m_max_x; @@ -3939,8 +6045,12 @@ void IOHandlerCursesGUI::Activate() { ApplicationDelegate::eMenuID_Process)); process_menu_sp->AddSubmenu(MenuSP(new Menu( "Attach", nullptr, 'a', ApplicationDelegate::eMenuID_ProcessAttach))); - process_menu_sp->AddSubmenu(MenuSP(new Menu( - "Detach", nullptr, 'd', ApplicationDelegate::eMenuID_ProcessDetach))); + 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))); @@ -4042,11 +6152,30 @@ void IOHandlerCursesGUI::Activate() { main_window_sp->CreateHelpSubwindow(); } - init_pair(1, COLOR_WHITE, COLOR_BLUE); - init_pair(2, COLOR_BLACK, COLOR_WHITE); - init_pair(3, COLOR_MAGENTA, COLOR_WHITE); - init_pair(4, COLOR_MAGENTA, COLOR_BLACK); - init_pair(5, COLOR_RED, COLOR_BLACK); + // All colors with black background. + init_pair(1, COLOR_BLACK, COLOR_BLACK); + init_pair(2, COLOR_RED, COLOR_BLACK); + init_pair(3, COLOR_GREEN, COLOR_BLACK); + init_pair(4, COLOR_YELLOW, COLOR_BLACK); + init_pair(5, COLOR_BLUE, COLOR_BLACK); + init_pair(6, COLOR_MAGENTA, COLOR_BLACK); + init_pair(7, COLOR_CYAN, COLOR_BLACK); + init_pair(8, COLOR_WHITE, COLOR_BLACK); + // All colors with blue background. + init_pair(9, COLOR_BLACK, COLOR_BLUE); + init_pair(10, COLOR_RED, COLOR_BLUE); + init_pair(11, COLOR_GREEN, COLOR_BLUE); + init_pair(12, COLOR_YELLOW, COLOR_BLUE); + init_pair(13, COLOR_BLUE, COLOR_BLUE); + init_pair(14, COLOR_MAGENTA, COLOR_BLUE); + init_pair(15, COLOR_CYAN, COLOR_BLUE); + init_pair(16, COLOR_WHITE, COLOR_BLUE); + // These must match the order in the color indexes enum. + init_pair(17, COLOR_BLACK, COLOR_WHITE); + init_pair(18, COLOR_MAGENTA, COLOR_WHITE); + static_assert(LastColorPairIndex == 18, "Color indexes do not match."); + + define_key("\033[Z", KEY_SHIFT_TAB); } } @@ -4065,4 +6194,8 @@ bool IOHandlerCursesGUI::Interrupt() { return false; } void IOHandlerCursesGUI::GotEOF() {} +void IOHandlerCursesGUI::TerminalSizeChanged() { + m_app_ap->TerminalSizeChanged(); +} + #endif // LLDB_ENABLE_CURSES diff --git a/gnu/llvm/lldb/source/Core/Mangled.cpp b/gnu/llvm/lldb/source/Core/Mangled.cpp index 143ec8770bf..fbaf9ff7151 100644 --- a/gnu/llvm/lldb/source/Core/Mangled.cpp +++ b/gnu/llvm/lldb/source/Core/Mangled.cpp @@ -14,11 +14,9 @@ #include "lldb/Utility/Logging.h" #include "lldb/Utility/RegularExpression.h" #include "lldb/Utility/Stream.h" -#include "lldb/Utility/Timer.h" #include "lldb/lldb-enumerations.h" #include "Plugins/Language/CPlusPlus/CPlusPlusLanguage.h" -#include "Plugins/Language/ObjC/ObjCLanguage.h" #include "llvm/ADT/StringRef.h" #include "llvm/Demangle/Demangle.h" @@ -28,34 +26,16 @@ #include #include -#include -#include +#include +#include using namespace lldb_private; static inline bool cstring_is_mangled(llvm::StringRef s) { return Mangled::GetManglingScheme(s) != Mangled::eManglingSchemeNone; } -static ConstString -get_demangled_name_without_arguments(ConstString mangled, - ConstString demangled) { - // This pair is - static std::pair - g_most_recent_mangled_to_name_sans_args; - - // Need to have the mangled & demangled names we're currently examining as - // statics so we can return a const ref to them at the end of the func if we - // don't have anything better. - static ConstString g_last_mangled; - static ConstString g_last_demangled; - - if (mangled && g_most_recent_mangled_to_name_sans_args.first == mangled) { - return g_most_recent_mangled_to_name_sans_args.second; - } - - g_last_demangled = demangled; - g_last_mangled = mangled; - +static ConstString GetDemangledNameWithoutArguments(ConstString mangled, + ConstString demangled) { const char *mangled_name_cstr = mangled.GetCString(); if (demangled && mangled_name_cstr && mangled_name_cstr[0]) { @@ -74,17 +54,13 @@ get_demangled_name_without_arguments(ConstString mangled, if (!cxx_method.GetContext().empty()) shortname = cxx_method.GetContext().str() + "::"; shortname += cxx_method.GetBasename().str(); - ConstString result(shortname.c_str()); - g_most_recent_mangled_to_name_sans_args.first = mangled; - g_most_recent_mangled_to_name_sans_args.second = result; - return g_most_recent_mangled_to_name_sans_args.second; + return ConstString(shortname); } } } - if (demangled) - return g_last_demangled; - return g_last_mangled; + return demangled; + return mangled; } #pragma mark Mangled @@ -96,6 +72,9 @@ Mangled::ManglingScheme Mangled::GetManglingScheme(llvm::StringRef const name) { if (name.startswith("?")) return Mangled::eManglingSchemeMSVC; + if (name.startswith("_R")) + return Mangled::eManglingSchemeRustV0; + if (name.startswith("_Z")) return Mangled::eManglingSchemeItanium; @@ -223,16 +202,23 @@ static char *GetItaniumDemangledStr(const char *M) { return demangled_cstr; } +static char *GetRustV0DemangledStr(const char *M) { + char *demangled_cstr = llvm::rustDemangle(M, nullptr, nullptr, nullptr); + + if (Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_DEMANGLE)) { + if (demangled_cstr && demangled_cstr[0]) + LLDB_LOG(log, "demangled rustv0: {0} -> \"{1}\"", M, demangled_cstr); + else + LLDB_LOG(log, "demangled rustv0: {0} -> error: failed to demangle", M); + } + + return demangled_cstr; +} + // Explicit demangling for scheduled requests during batch processing. This // makes use of ItaniumPartialDemangler's rich demangle info bool Mangled::DemangleWithRichManglingInfo( RichManglingContext &context, SkipMangledNameFn *skip_mangled_name) { - // We need to generate and cache the demangled name. - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer(func_cat, - "Mangled::DemangleWithRichNameIndexInfo (m_mangled = %s)", - m_mangled.GetCString()); - // Others are not meant to arrive here. ObjC names or C's main() for example // have their names stored in m_demangled, while m_mangled is empty. assert(m_mangled); @@ -286,6 +272,10 @@ bool Mangled::DemangleWithRichManglingInfo( return context.FromCxxMethodName(m_demangled); } } + + case eManglingSchemeRustV0: + // Rich demangling scheme is not supported for Rust + return false; } llvm_unreachable("Fully covered switch above!"); } @@ -298,11 +288,6 @@ ConstString Mangled::GetDemangledName() const { // Check to make sure we have a valid mangled name and that we haven't // already decoded our mangled name. if (m_mangled && m_demangled.IsNull()) { - // We need to generate and cache the demangled name. - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer(func_cat, "Mangled::GetDemangledName (m_mangled = %s)", - m_mangled.GetCString()); - // Don't bother running anything that isn't mangled const char *mangled_name = m_mangled.GetCString(); ManglingScheme mangling_scheme = GetManglingScheme(m_mangled.GetStringRef()); @@ -319,6 +304,9 @@ ConstString Mangled::GetDemangledName() const { demangled_name = GetItaniumDemangledStr(mangled_name); break; } + case eManglingSchemeRustV0: + demangled_name = GetRustV0DemangledStr(mangled_name); + break; case eManglingSchemeNone: llvm_unreachable("eManglingSchemeNone was handled already"); } @@ -359,7 +347,7 @@ ConstString Mangled::GetName(Mangled::NamePreference preference) const { ConstString demangled = GetDemangledName(); if (preference == ePreferDemangledWithoutArguments) { - return get_demangled_name_without_arguments(m_mangled, demangled); + return GetDemangledNameWithoutArguments(m_mangled, demangled); } if (preference == ePreferDemangled) { // Call the accessor to make sure we get a demangled name in case it hasn't @@ -407,22 +395,16 @@ size_t Mangled::MemorySize() const { // of mangling names from a given language, likewise the compilation units // within those targets. lldb::LanguageType Mangled::GuessLanguage() const { - ConstString mangled = GetMangledName(); - - if (mangled) { - const char *mangled_name = mangled.GetCString(); - if (CPlusPlusLanguage::IsCPPMangledName(mangled_name)) - return lldb::eLanguageTypeC_plus_plus; - } else { - // ObjC names aren't really mangled, so they won't necessarily be in the - // mangled name slot. - ConstString demangled_name = GetDemangledName(); - if (demangled_name - && ObjCLanguage::IsPossibleObjCMethodName(demangled_name.GetCString())) - return lldb::eLanguageTypeObjC; - - } - return lldb::eLanguageTypeUnknown; + lldb::LanguageType result = lldb::eLanguageTypeUnknown; + // Ask each language plugin to check if the mangled name belongs to it. + Language::ForEach([this, &result](Language *l) { + if (l->SymbolNameFitsToLanguage(*this)) { + result = l->GetLanguageType(); + return false; + } + return true; + }); + return result; } // Dump OBJ to the supplied stream S. diff --git a/gnu/llvm/lldb/source/Core/Module.cpp b/gnu/llvm/lldb/source/Core/Module.cpp index b76659ee3e0..19c97be1506 100644 --- a/gnu/llvm/lldb/source/Core/Module.cpp +++ b/gnu/llvm/lldb/source/Core/Module.cpp @@ -59,12 +59,12 @@ #include "llvm/Support/Signals.h" #include "llvm/Support/raw_ostream.h" -#include +#include +#include +#include #include -#include +#include #include -#include -#include #include #include @@ -257,9 +257,7 @@ Module::Module(const FileSpec &file_spec, const ArchSpec &arch, m_object_name.IsEmpty() ? "" : ")"); } -Module::Module() - : m_object_offset(0), m_file_has_changed(false), - m_first_file_changed_log(false) { +Module::Module() : m_file_has_changed(false), m_first_file_changed_log(false) { std::lock_guard guard( GetAllocationModuleCollectionMutex()); GetModuleCollection().push_back(this); @@ -419,8 +417,7 @@ void Module::DumpSymbolContext(Stream *s) { size_t Module::GetNumCompileUnits() { std::lock_guard guard(m_mutex); - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer(func_cat, "Module::GetNumCompileUnits (module = %p)", + LLDB_SCOPED_TIMERF("Module::GetNumCompileUnits (module = %p)", static_cast(this)); if (SymbolFile *symbols = GetSymbolFile()) return symbols->GetNumCompileUnits(); @@ -441,10 +438,6 @@ CompUnitSP Module::GetCompileUnitAtIndex(size_t index) { bool Module::ResolveFileAddress(lldb::addr_t vm_addr, Address &so_addr) { std::lock_guard guard(m_mutex); - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer(func_cat, - "Module::ResolveFileAddress (vm_addr = 0x%" PRIx64 ")", - vm_addr); SectionList *section_list = GetSectionList(); if (section_list) return so_addr.ResolveAddressUsingFileSections(vm_addr, section_list); @@ -594,18 +587,20 @@ uint32_t Module::ResolveSymbolContextsForFileSpec( const FileSpec &file_spec, uint32_t line, bool check_inlines, lldb::SymbolContextItem resolve_scope, SymbolContextList &sc_list) { std::lock_guard guard(m_mutex); - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer(func_cat, - "Module::ResolveSymbolContextForFilePath (%s:%u, " + LLDB_SCOPED_TIMERF("Module::ResolveSymbolContextForFilePath (%s:%u, " "check_inlines = %s, resolve_scope = 0x%8.8x)", file_spec.GetPath().c_str(), line, check_inlines ? "yes" : "no", resolve_scope); const uint32_t initial_count = sc_list.GetSize(); - if (SymbolFile *symbols = GetSymbolFile()) - symbols->ResolveSymbolContext(file_spec, line, check_inlines, resolve_scope, - sc_list); + if (SymbolFile *symbols = GetSymbolFile()) { + // TODO: Handle SourceLocationSpec column information + SourceLocationSpec location_spec(file_spec, line, /*column=*/llvm::None, + check_inlines, /*exact_match=*/false); + + symbols->ResolveSymbolContext(location_spec, resolve_scope, sc_list); + } return sc_list.GetSize() - initial_count; } @@ -922,7 +917,12 @@ void Module::FindAddressesForLine(const lldb::TargetSP target_sp, std::vector
&output_local, std::vector
&output_extern) { SearchFilterByModule filter(target_sp, m_file); - AddressResolverFileLine resolver(file, line, true); + + // TODO: Handle SourceLocationSpec column information + SourceLocationSpec location_spec(file, line, /*column=*/llvm::None, + /*check_inlines=*/true, + /*exact_match=*/false); + AddressResolverFileLine resolver(location_spec); resolver.ResolveAddress(filter); for (size_t n = 0; n < resolver.GetNumberOfAddresses(); n++) { @@ -940,8 +940,7 @@ void Module::FindTypes_Impl( size_t max_matches, llvm::DenseSet &searched_symbol_files, TypeMap &types) { - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer(func_cat, LLVM_PRETTY_FUNCTION); + LLDB_SCOPED_TIMER(); if (SymbolFile *symbols = GetSymbolFile()) symbols->FindTypes(name, parent_decl_ctx, max_matches, searched_symbol_files, types); @@ -1028,8 +1027,7 @@ void Module::FindTypes( llvm::ArrayRef pattern, LanguageSet languages, llvm::DenseSet &searched_symbol_files, TypeMap &types) { - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer(func_cat, LLVM_PRETTY_FUNCTION); + LLDB_SCOPED_TIMER(); if (SymbolFile *symbols = GetSymbolFile()) symbols->FindTypes(pattern, languages, searched_symbol_files, types); } @@ -1040,8 +1038,7 @@ SymbolFile *Module::GetSymbolFile(bool can_create, Stream *feedback_strm) { if (!m_did_load_symfile.load() && can_create) { ObjectFile *obj_file = GetObjectFile(); if (obj_file != nullptr) { - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer(func_cat, LLVM_PRETTY_FUNCTION); + LLDB_SCOPED_TIMER(); m_symfile_up.reset( SymbolVendor::FindPlugin(shared_from_this(), feedback_strm)); m_did_load_symfile = true; @@ -1080,8 +1077,6 @@ std::string Module::GetSpecificationDescription() const { void Module::GetDescription(llvm::raw_ostream &s, lldb::DescriptionLevel level) { - std::lock_guard guard(m_mutex); - if (level >= eDescriptionLevelFull) { if (m_arch.IsValid()) s << llvm::formatv("({0}) ", m_arch.GetArchitectureName()); @@ -1244,8 +1239,7 @@ ObjectFile *Module::GetObjectFile() { if (!m_did_load_objfile.load()) { std::lock_guard guard(m_mutex); if (!m_did_load_objfile.load()) { - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer(func_cat, "Module::GetObjectFile () module = %s", + LLDB_SCOPED_TIMERF("Module::GetObjectFile () module = %s", GetFileSpec().GetFilename().AsCString("")); lldb::offset_t data_offset = 0; lldb::offset_t file_size = 0; @@ -1312,9 +1306,8 @@ SectionList *Module::GetUnifiedSectionList() { const Symbol *Module::FindFirstSymbolWithNameAndType(ConstString name, SymbolType symbol_type) { - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer( - func_cat, "Module::FindFirstSymbolWithNameAndType (name = %s, type = %i)", + LLDB_SCOPED_TIMERF( + "Module::FindFirstSymbolWithNameAndType (name = %s, type = %i)", name.AsCString(), symbol_type); if (Symtab *symtab = GetSymtab()) return symtab->FindFirstSymbolWithNameAndType( @@ -1342,9 +1335,7 @@ void Module::SymbolIndicesToSymbolContextList( void Module::FindFunctionSymbols(ConstString name, uint32_t name_type_mask, SymbolContextList &sc_list) { - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer(func_cat, - "Module::FindSymbolsFunctions (name = %s, mask = 0x%8.8x)", + LLDB_SCOPED_TIMERF("Module::FindSymbolsFunctions (name = %s, mask = 0x%8.8x)", name.AsCString(), name_type_mask); if (Symtab *symtab = GetSymtab()) symtab->FindFunctionSymbols(name, name_type_mask, sc_list); @@ -1355,10 +1346,8 @@ void Module::FindSymbolsWithNameAndType(ConstString name, SymbolContextList &sc_list) { // No need to protect this call using m_mutex all other method calls are // already thread safe. - - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer( - func_cat, "Module::FindSymbolsWithNameAndType (name = %s, type = %i)", + LLDB_SCOPED_TIMERF( + "Module::FindSymbolsWithNameAndType (name = %s, type = %i)", name.AsCString(), symbol_type); if (Symtab *symtab = GetSymtab()) { std::vector symbol_indexes; @@ -1372,10 +1361,7 @@ void Module::FindSymbolsMatchingRegExAndType(const RegularExpression ®ex, SymbolContextList &sc_list) { // No need to protect this call using m_mutex all other method calls are // already thread safe. - - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer( - func_cat, + LLDB_SCOPED_TIMERF( "Module::FindSymbolsMatchingRegExAndType (regex = %s, type = %i)", regex.GetText().str().c_str(), symbol_type); if (Symtab *symtab = GetSymtab()) { @@ -1542,9 +1528,9 @@ bool Module::LoadScriptingResourceInTarget(Target *target, Status &error, } StreamString scripting_stream; scripting_fspec.Dump(scripting_stream.AsRawOstream()); - const bool init_lldb_globals = false; + LoadScriptOptions options; bool did_load = script_interpreter->LoadScriptingModule( - scripting_stream.GetData(), init_lldb_globals, error); + scripting_stream.GetData(), options, error); if (!did_load) return false; } @@ -1612,13 +1598,18 @@ bool Module::MatchesModuleSpec(const ModuleSpec &module_ref) { bool Module::FindSourceFile(const FileSpec &orig_spec, FileSpec &new_spec) const { std::lock_guard guard(m_mutex); - return m_source_mappings.FindFile(orig_spec, new_spec); + if (auto remapped = m_source_mappings.FindFile(orig_spec)) { + new_spec = *remapped; + return true; + } + return false; } -bool Module::RemapSourceFile(llvm::StringRef path, - std::string &new_path) const { +llvm::Optional Module::RemapSourceFile(llvm::StringRef path) const { std::lock_guard guard(m_mutex); - return m_source_mappings.RemapPath(path, new_path); + if (auto remapped = m_source_mappings.RemapPath(path)) + return remapped->GetPath(); + return {}; } void Module::RegisterXcodeSDK(llvm::StringRef sdk_name, llvm::StringRef sysroot) { diff --git a/gnu/llvm/lldb/source/Core/ModuleChild.cpp b/gnu/llvm/lldb/source/Core/ModuleChild.cpp index 6e04bb4589e..7aaa8f2ac25 100644 --- a/gnu/llvm/lldb/source/Core/ModuleChild.cpp +++ b/gnu/llvm/lldb/source/Core/ModuleChild.cpp @@ -13,7 +13,7 @@ using namespace lldb_private; ModuleChild::ModuleChild(const lldb::ModuleSP &module_sp) : m_module_wp(module_sp) {} -ModuleChild::~ModuleChild() {} +ModuleChild::~ModuleChild() = default; const ModuleChild &ModuleChild::operator=(const ModuleChild &rhs) { if (this != &rhs) diff --git a/gnu/llvm/lldb/source/Core/ModuleList.cpp b/gnu/llvm/lldb/source/Core/ModuleList.cpp index 1701cb56338..56bc4c72d8e 100644 --- a/gnu/llvm/lldb/source/Core/ModuleList.cpp +++ b/gnu/llvm/lldb/source/Core/ModuleList.cpp @@ -82,8 +82,9 @@ ModuleListProperties::ModuleListProperties() { [this] { UpdateSymlinkMappings(); }); llvm::SmallString<128> path; - clang::driver::Driver::getDefaultModuleCachePath(path); - SetClangModulesCachePath(path); + if (clang::driver::Driver::getDefaultModuleCachePath(path)) { + lldbassert(SetClangModulesCachePath(FileSpec(path))); + } } bool ModuleListProperties::GetEnableExternalLookup() const { @@ -104,8 +105,8 @@ FileSpec ModuleListProperties::GetClangModulesCachePath() const { ->GetCurrentValue(); } -bool ModuleListProperties::SetClangModulesCachePath(llvm::StringRef path) { - return m_collection_sp->SetPropertyAtIndexAsString( +bool ModuleListProperties::SetClangModulesCachePath(const FileSpec &path) { + return m_collection_sp->SetPropertyAtIndexAsFileSpec( nullptr, ePropertyClangModulesCachePath, path); } @@ -131,8 +132,7 @@ PathMappingList ModuleListProperties::GetSymlinkMappings() const { return m_symlink_paths; } -ModuleList::ModuleList() - : m_modules(), m_modules_mutex(), m_notifier(nullptr) {} +ModuleList::ModuleList() : m_modules(), m_modules_mutex() {} ModuleList::ModuleList(const ModuleList &rhs) : m_modules(), m_modules_mutex(), m_notifier(nullptr) { @@ -296,14 +296,24 @@ size_t ModuleList::RemoveOrphans(bool mandatory) { if (!lock.try_lock()) return 0; } - collection::iterator pos = m_modules.begin(); size_t remove_count = 0; - while (pos != m_modules.end()) { - if (pos->unique()) { - pos = RemoveImpl(pos); - ++remove_count; - } else { - ++pos; + // Modules might hold shared pointers to other modules, so removing one + // module might make other other modules orphans. Keep removing modules until + // there are no further modules that can be removed. + bool made_progress = true; + while (made_progress) { + // Keep track if we make progress this iteration. + made_progress = false; + collection::iterator pos = m_modules.begin(); + while (pos != m_modules.end()) { + if (pos->unique()) { + pos = RemoveImpl(pos); + ++remove_count; + // We did make progress. + made_progress = true; + } else { + ++pos; + } } } return remove_count; @@ -335,10 +345,6 @@ void ModuleList::ClearImpl(bool use_notifier) { Module *ModuleList::GetModulePointerAtIndex(size_t idx) const { std::lock_guard guard(m_modules_mutex); - return GetModulePointerAtIndexUnlocked(idx); -} - -Module *ModuleList::GetModulePointerAtIndexUnlocked(size_t idx) const { if (idx < m_modules.size()) return m_modules[idx].get(); return nullptr; @@ -971,7 +977,7 @@ ModuleList::GetSharedModule(const ModuleSpec &module_spec, ModuleSP &module_sp, error.SetErrorStringWithFormat( "cannot locate a module for UUID '%s'", uuid_str.c_str()); else - error.SetErrorStringWithFormat("cannot locate a module"); + error.SetErrorString("cannot locate a module"); } } } diff --git a/gnu/llvm/lldb/source/Core/Opcode.cpp b/gnu/llvm/lldb/source/Core/Opcode.cpp index b544064b061..a3fc97f9526 100644 --- a/gnu/llvm/lldb/source/Core/Opcode.cpp +++ b/gnu/llvm/lldb/source/Core/Opcode.cpp @@ -16,7 +16,7 @@ #include -#include +#include using namespace lldb; using namespace lldb_private; diff --git a/gnu/llvm/lldb/source/Core/PluginManager.cpp b/gnu/llvm/lldb/source/Core/PluginManager.cpp index 3545ef66cc3..fcaa868b083 100644 --- a/gnu/llvm/lldb/source/Core/PluginManager.cpp +++ b/gnu/llvm/lldb/source/Core/PluginManager.cpp @@ -20,7 +20,7 @@ #include "llvm/Support/DynamicLibrary.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/raw_ostream.h" -#include +#include #include #include #include @@ -38,11 +38,11 @@ typedef bool (*PluginInitCallback)(); typedef void (*PluginTermCallback)(); struct PluginInfo { - PluginInfo() : plugin_init_callback(nullptr), plugin_term_callback(nullptr) {} + PluginInfo() = default; llvm::sys::DynamicLibrary library; - PluginInitCallback plugin_init_callback; - PluginTermCallback plugin_term_callback; + PluginInitCallback plugin_init_callback = nullptr; + PluginTermCallback plugin_term_callback = nullptr; }; typedef std::map PluginTerminateMap; @@ -264,12 +264,13 @@ public: const std::vector &GetInstances() const { return m_instances; } std::vector &GetInstances() { return m_instances; } -private: Instance *GetInstanceAtIndex(uint32_t idx) { if (idx < m_instances.size()) return &m_instances[idx]; return nullptr; } + +private: std::vector m_instances; }; @@ -683,11 +684,13 @@ PluginManager::GetObjectFileCreateMemoryCallbackForPluginName( } Status PluginManager::SaveCore(const lldb::ProcessSP &process_sp, - const FileSpec &outfile) { + const FileSpec &outfile, + lldb::SaveCoreStyle &core_style) { Status error; auto &instances = GetObjectFileInstances().GetInstances(); for (auto &instance : instances) { - if (instance.save_core && instance.save_core(process_sp, outfile, error)) + if (instance.save_core && + instance.save_core(process_sp, outfile, core_style, error)) return error; } error.SetErrorString( @@ -1005,6 +1008,127 @@ PluginManager::GetSymbolVendorCreateCallbackAtIndex(uint32_t idx) { return GetSymbolVendorInstances().GetCallbackAtIndex(idx); } +#pragma mark Trace + +struct TraceInstance + : public PluginInstance { + TraceInstance( + ConstString name, std::string description, + CallbackType create_callback_for_session_file, + TraceCreateInstanceForLiveProcess create_callback_for_live_process, + llvm::StringRef schema) + : PluginInstance( + name, std::move(description), create_callback_for_session_file), + schema(schema), + create_callback_for_live_process(create_callback_for_live_process) {} + + llvm::StringRef schema; + TraceCreateInstanceForLiveProcess create_callback_for_live_process; +}; + +typedef PluginInstances TraceInstances; + +static TraceInstances &GetTracePluginInstances() { + static TraceInstances g_instances; + return g_instances; +} + +bool PluginManager::RegisterPlugin( + ConstString name, const char *description, + TraceCreateInstanceForSessionFile create_callback_for_session_file, + TraceCreateInstanceForLiveProcess create_callback_for_live_process, + llvm::StringRef schema) { + return GetTracePluginInstances().RegisterPlugin( + name, description, create_callback_for_session_file, + create_callback_for_live_process, schema); +} + +bool PluginManager::UnregisterPlugin( + TraceCreateInstanceForSessionFile create_callback_for_session_file) { + return GetTracePluginInstances().UnregisterPlugin( + create_callback_for_session_file); +} + +TraceCreateInstanceForSessionFile +PluginManager::GetTraceCreateCallback(ConstString plugin_name) { + return GetTracePluginInstances().GetCallbackForName(plugin_name); +} + +TraceCreateInstanceForLiveProcess +PluginManager::GetTraceCreateCallbackForLiveProcess(ConstString plugin_name) { + for (const TraceInstance &instance : GetTracePluginInstances().GetInstances()) + if (instance.name == plugin_name) + return instance.create_callback_for_live_process; + return nullptr; +} + +llvm::StringRef PluginManager::GetTraceSchema(ConstString plugin_name) { + for (const TraceInstance &instance : GetTracePluginInstances().GetInstances()) + if (instance.name == plugin_name) + return instance.schema; + return llvm::StringRef(); +} + +llvm::StringRef PluginManager::GetTraceSchema(size_t index) { + if (TraceInstance *instance = + GetTracePluginInstances().GetInstanceAtIndex(index)) + return instance->schema; + return llvm::StringRef(); +} + +#pragma mark TraceExporter + +struct TraceExporterInstance + : public PluginInstance { + TraceExporterInstance( + ConstString name, std::string description, + TraceExporterCreateInstance create_instance, + ThreadTraceExportCommandCreator create_thread_trace_export_command) + : PluginInstance( + name, std::move(description), create_instance), + create_thread_trace_export_command(create_thread_trace_export_command) { + } + + ThreadTraceExportCommandCreator create_thread_trace_export_command; +}; + +typedef PluginInstances TraceExporterInstances; + +static TraceExporterInstances &GetTraceExporterInstances() { + static TraceExporterInstances g_instances; + return g_instances; +} + +bool PluginManager::RegisterPlugin( + ConstString name, const char *description, + TraceExporterCreateInstance create_callback, + ThreadTraceExportCommandCreator create_thread_trace_export_command) { + return GetTraceExporterInstances().RegisterPlugin( + name, description, create_callback, create_thread_trace_export_command); +} + +TraceExporterCreateInstance +PluginManager::GetTraceExporterCreateCallback(ConstString plugin_name) { + return GetTraceExporterInstances().GetCallbackForName(plugin_name); +} + +bool PluginManager::UnregisterPlugin( + TraceExporterCreateInstance create_callback) { + return GetTraceExporterInstances().UnregisterPlugin(create_callback); +} + +ThreadTraceExportCommandCreator +PluginManager::GetThreadTraceExportCommandCreatorAtIndex(uint32_t index) { + if (TraceExporterInstance *instance = + GetTraceExporterInstances().GetInstanceAtIndex(index)) + return instance->create_thread_trace_export_command; + return nullptr; +} + +const char *PluginManager::GetTraceExporterPluginNameAtIndex(uint32_t index) { + return GetTraceExporterInstances().GetNameAtIndex(index); +} + #pragma mark UnwindAssembly typedef PluginInstance UnwindAssemblyInstance; @@ -1218,6 +1342,7 @@ void PluginManager::DebuggerInitialize(Debugger &debugger) { GetSymbolFileInstances().PerformDebuggerCallback(debugger); GetOperatingSystemInstances().PerformDebuggerCallback(debugger); GetStructuredDataPluginInstances().PerformDebuggerCallback(debugger); + GetTracePluginInstances().PerformDebuggerCallback(debugger); } // This is the preferred new way to register plugin specific settings. e.g. diff --git a/gnu/llvm/lldb/source/Core/Progress.cpp b/gnu/llvm/lldb/source/Core/Progress.cpp new file mode 100644 index 00000000000..c54e7774adf --- /dev/null +++ b/gnu/llvm/lldb/source/Core/Progress.cpp @@ -0,0 +1,60 @@ +//===-- Progress.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 "lldb/Core/Progress.h" + +#include "lldb/Core/Debugger.h" +#include "lldb/Utility/StreamString.h" + +using namespace lldb; +using namespace lldb_private; + +std::atomic Progress::g_id(0); + +Progress::Progress(std::string title, uint64_t total, + lldb_private::Debugger *debugger) + : m_title(title), m_id(++g_id), m_completed(0), m_total(total) { + assert(total > 0); + if (debugger) + m_debugger_id = debugger->GetID(); + std::lock_guard guard(m_mutex); + ReportProgress(); +} + +Progress::~Progress() { + // Make sure to always report progress completed when this object is + // destructed so it indicates the progress dialog/activity should go away. + std::lock_guard guard(m_mutex); + if (!m_completed) { + m_completed = m_total; + ReportProgress(); + } +} + +void Progress::Increment(uint64_t amount) { + if (amount > 0) { + std::lock_guard guard(m_mutex); + // Watch out for unsigned overflow and make sure we don't increment too + // much and exceed m_total. + if (amount > (m_total - m_completed)) + m_completed = m_total; + else + m_completed += amount; + ReportProgress(); + } +} + +void Progress::ReportProgress() { + if (!m_complete) { + // Make sure we only send one notification that indicates the progress is + // complete. + m_complete = m_completed == m_total; + Debugger::ReportProgress(m_id, m_title, m_completed, m_total, + m_debugger_id); + } +} diff --git a/gnu/llvm/lldb/source/Core/RichManglingContext.cpp b/gnu/llvm/lldb/source/Core/RichManglingContext.cpp index 2094d96acd7..2dcb1407e6c 100644 --- a/gnu/llvm/lldb/source/Core/RichManglingContext.cpp +++ b/gnu/llvm/lldb/source/Core/RichManglingContext.cpp @@ -19,7 +19,12 @@ using namespace lldb; using namespace lldb_private; // RichManglingContext -void RichManglingContext::ResetProvider(InfoProvider new_provider) { +RichManglingContext::~RichManglingContext() { + std::free(m_ipd_buf); + ResetCxxMethodParser(); +} + +void RichManglingContext::ResetCxxMethodParser() { // If we want to support parsers for other languages some day, we need a // switch here to delete the correct parser type. if (m_cxx_method_parser.hasValue()) { @@ -27,6 +32,10 @@ void RichManglingContext::ResetProvider(InfoProvider new_provider) { delete get(m_cxx_method_parser); m_cxx_method_parser.reset(); } +} + +void RichManglingContext::ResetProvider(InfoProvider new_provider) { + ResetCxxMethodParser(); assert(new_provider != None && "Only reset to a valid provider"); m_provider = new_provider; diff --git a/gnu/llvm/lldb/source/Core/SearchFilter.cpp b/gnu/llvm/lldb/source/Core/SearchFilter.cpp index ea51fb37918..4f9519b5cc9 100644 --- a/gnu/llvm/lldb/source/Core/SearchFilter.cpp +++ b/gnu/llvm/lldb/source/Core/SearchFilter.cpp @@ -27,8 +27,8 @@ #include #include -#include -#include +#include +#include namespace lldb_private { class Address; @@ -89,7 +89,7 @@ SearchFilterSP SearchFilter::CreateFromStructuredData( bool success = filter_dict.GetValueForKeyAsString( GetSerializationSubclassKey(), subclass_name); if (!success) { - error.SetErrorStringWithFormat("Filter data missing subclass key"); + error.SetErrorString("Filter data missing subclass key"); return result_sp; } @@ -228,11 +228,7 @@ void SearchFilter::SearchInModuleList(Searcher &searcher, ModuleList &modules) { return; } - std::lock_guard guard(modules.GetMutex()); - const size_t numModules = modules.GetSize(); - - for (size_t i = 0; i < numModules; i++) { - ModuleSP module_sp(modules.GetModuleAtIndexUnlocked(i)); + for (ModuleSP module_sp : modules.Modules()) { if (!ModulePasses(module_sp)) continue; if (DoModuleIteration(module_sp, searcher) == Searcher::eCallbackReturnStop) @@ -262,14 +258,9 @@ SearchFilter::DoModuleIteration(const SymbolContext &context, return Searcher::eCallbackReturnContinue; } - const ModuleList &target_images = m_target_sp->GetImages(); - std::lock_guard guard(target_images.GetMutex()); - - size_t n_modules = target_images.GetSize(); - for (size_t i = 0; i < n_modules; i++) { + for (ModuleSP module_sp : m_target_sp->GetImages().Modules()) { // If this is the last level supplied, then call the callback directly, // otherwise descend. - ModuleSP module_sp(target_images.GetModuleAtIndexUnlocked(i)); if (!ModulePasses(module_sp)) continue; @@ -434,11 +425,9 @@ void SearchFilterByModule::Search(Searcher &searcher) { const ModuleList &target_modules = m_target_sp->GetImages(); std::lock_guard guard(target_modules.GetMutex()); - const size_t num_modules = target_modules.GetSize(); - for (size_t i = 0; i < num_modules; i++) { - Module *module = target_modules.GetModulePointerAtIndexUnlocked(i); - if (FileSpec::Match(m_module_spec, module->GetFileSpec())) { - SymbolContext matchingContext(m_target_sp, module->shared_from_this()); + for (ModuleSP module_sp : m_target_sp->GetImages().Modules()) { + if (FileSpec::Match(m_module_spec, module_sp->GetFileSpec())) { + SymbolContext matchingContext(m_target_sp, module_sp); Searcher::CallbackReturn shouldContinue; shouldContinue = DoModuleIteration(matchingContext, searcher); @@ -550,17 +539,11 @@ void SearchFilterByModuleList::Search(Searcher &searcher) { // If the module file spec is a full path, then we can just find the one // filespec that passes. Otherwise, we need to go through all modules and // find the ones that match the file name. - - const ModuleList &target_modules = m_target_sp->GetImages(); - std::lock_guard guard(target_modules.GetMutex()); - - const size_t num_modules = target_modules.GetSize(); - for (size_t i = 0; i < num_modules; i++) { - Module *module = target_modules.GetModulePointerAtIndexUnlocked(i); - if (m_module_spec_list.FindFileIndex(0, module->GetFileSpec(), false) == + for (ModuleSP module_sp : m_target_sp->GetImages().Modules()) { + if (m_module_spec_list.FindFileIndex(0, module_sp->GetFileSpec(), false) == UINT32_MAX) continue; - SymbolContext matchingContext(m_target_sp, module->shared_from_this()); + SymbolContext matchingContext(m_target_sp, module_sp); Searcher::CallbackReturn shouldContinue; shouldContinue = DoModuleIteration(matchingContext, searcher); @@ -752,13 +735,9 @@ void SearchFilterByModuleListAndCU::Search(Searcher &searcher) { // find the ones that match the file name. ModuleList matching_modules; - const ModuleList &target_images = m_target_sp->GetImages(); - std::lock_guard guard(target_images.GetMutex()); - const size_t num_modules = target_images.GetSize(); bool no_modules_in_filter = m_module_spec_list.GetSize() == 0; - for (size_t i = 0; i < num_modules; i++) { - lldb::ModuleSP module_sp = target_images.GetModuleAtIndexUnlocked(i); + for (ModuleSP module_sp : m_target_sp->GetImages().Modules()) { if (!no_modules_in_filter && m_module_spec_list.FindFileIndex(0, module_sp->GetFileSpec(), false) == UINT32_MAX) diff --git a/gnu/llvm/lldb/source/Core/Section.cpp b/gnu/llvm/lldb/source/Core/Section.cpp index 9bf1c62c5ab..a5a10141aa6 100644 --- a/gnu/llvm/lldb/source/Core/Section.cpp +++ b/gnu/llvm/lldb/source/Core/Section.cpp @@ -15,7 +15,7 @@ #include "lldb/Utility/FileSpec.h" #include "lldb/Utility/VMRange.h" -#include +#include #include #include diff --git a/gnu/llvm/lldb/source/Core/SourceLocationSpec.cpp b/gnu/llvm/lldb/source/Core/SourceLocationSpec.cpp new file mode 100644 index 00000000000..610754bb187 --- /dev/null +++ b/gnu/llvm/lldb/source/Core/SourceLocationSpec.cpp @@ -0,0 +1,81 @@ +//===-- SourceLocationSpec.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 "lldb/Core/SourceLocationSpec.h" +#include "lldb/Utility/StreamString.h" + +using namespace lldb; +using namespace lldb_private; + +SourceLocationSpec::SourceLocationSpec(FileSpec file_spec, uint32_t line, + llvm::Optional column, + bool check_inlines, bool exact_match) + : m_declaration(file_spec, line, + column.getValueOr(LLDB_INVALID_COLUMN_NUMBER)), + m_check_inlines(check_inlines), m_exact_match(exact_match) {} + +SourceLocationSpec::operator bool() const { return m_declaration.IsValid(); } + +bool SourceLocationSpec::operator!() const { return !operator bool(); } + +bool SourceLocationSpec::operator==(const SourceLocationSpec &rhs) const { + return m_declaration == rhs.m_declaration && + m_check_inlines == rhs.GetCheckInlines() && + m_exact_match == rhs.GetExactMatch(); +} + +bool SourceLocationSpec::operator!=(const SourceLocationSpec &rhs) const { + return !(*this == rhs); +} + +bool SourceLocationSpec::operator<(const SourceLocationSpec &rhs) const { + return SourceLocationSpec::Compare(*this, rhs) < 0; +} + +Stream &lldb_private::operator<<(Stream &s, const SourceLocationSpec &loc) { + loc.Dump(s); + return s; +} + +int SourceLocationSpec::Compare(const SourceLocationSpec &lhs, + const SourceLocationSpec &rhs) { + return Declaration::Compare(lhs.m_declaration, rhs.m_declaration); +} + +bool SourceLocationSpec::Equal(const SourceLocationSpec &lhs, + const SourceLocationSpec &rhs, bool full) { + return full ? lhs == rhs + : (lhs.GetFileSpec() == rhs.GetFileSpec() && + lhs.GetLine() == rhs.GetLine()); +} + +void SourceLocationSpec::Dump(Stream &s) const { + s << "check inlines = " << llvm::toStringRef(m_check_inlines); + s << ", exact match = " << llvm::toStringRef(m_exact_match); + m_declaration.Dump(&s, true); +} + +std::string SourceLocationSpec::GetString() const { + StreamString ss; + Dump(ss); + return ss.GetString().str(); +} + +llvm::Optional SourceLocationSpec::GetLine() const { + uint32_t line = m_declaration.GetLine(); + if (line == 0 || line == LLDB_INVALID_LINE_NUMBER) + return llvm::None; + return line; +} + +llvm::Optional SourceLocationSpec::GetColumn() const { + uint16_t column = m_declaration.GetColumn(); + if (column == LLDB_INVALID_COLUMN_NUMBER) + return llvm::None; + return column; +} diff --git a/gnu/llvm/lldb/source/Core/SourceManager.cpp b/gnu/llvm/lldb/source/Core/SourceManager.cpp index 7414dd281d4..9c1112979c5 100644 --- a/gnu/llvm/lldb/source/Core/SourceManager.cpp +++ b/gnu/llvm/lldb/source/Core/SourceManager.cpp @@ -35,8 +35,8 @@ #include #include -#include -#include +#include +#include namespace lldb_private { class ExecutionContext; @@ -61,7 +61,7 @@ SourceManager::SourceManager(const DebuggerSP &debugger_sp) m_debugger_wp(debugger_sp) {} // Destructor -SourceManager::~SourceManager() {} +SourceManager::~SourceManager() = default; SourceManager::FileSP SourceManager::GetFile(const FileSpec &file_spec) { if (!file_spec) @@ -183,14 +183,14 @@ size_t SourceManager::DisplaySourceLinesWithLineNumbersUsingLastFile( break; } - char prefix[32] = ""; + std::string prefix; if (bp_locs) { uint32_t bp_count = bp_locs->NumLineEntriesWithLine(line); if (bp_count > 0) - ::snprintf(prefix, sizeof(prefix), "[%u] ", bp_count); + prefix = llvm::formatv("[{0}]", bp_count); else - ::snprintf(prefix, sizeof(prefix), " "); + prefix = " "; } char buffer[3]; @@ -206,7 +206,8 @@ size_t SourceManager::DisplaySourceLinesWithLineNumbersUsingLastFile( .str()); } - s->Printf("%s%s %-4u\t", prefix, current_line_highlight.c_str(), line); + s->Printf("%s%s %-4u\t", prefix.c_str(), current_line_highlight.c_str(), + line); // So far we treated column 0 as a special 'no column value', but // DisplaySourceLines starts counting columns from 0 (and no column is @@ -440,13 +441,17 @@ void SourceManager::File::CommonInitializer(const FileSpec &file_spec, } // Try remapping if m_file_spec does not correspond to an existing file. if (!FileSystem::Instance().Exists(m_file_spec)) { - FileSpec new_file_spec; - // Check target specific source remappings first, then fall back to - // modules objects can have individual path remappings that were - // detected when the debug info for a module was found. then - if (target->GetSourcePathMap().FindFile(m_file_spec, new_file_spec) || - target->GetImages().FindSourceFile(m_file_spec, new_file_spec)) { - m_file_spec = new_file_spec; + // Check target specific source remappings (i.e., the + // target.source-map setting), then fall back to the module + // specific remapping (i.e., the .dSYM remapping dictionary). + auto remapped = target->GetSourcePathMap().FindFile(m_file_spec); + if (!remapped) { + FileSpec new_spec; + if (target->GetImages().FindSourceFile(m_file_spec, new_spec)) + remapped = new_spec; + } + if (remapped) { + m_file_spec = *remapped; m_mod_time = FileSystem::Instance().GetModificationTime(m_file_spec); } } diff --git a/gnu/llvm/lldb/source/Core/StreamFile.cpp b/gnu/llvm/lldb/source/Core/StreamFile.cpp index 43a9df802f7..2f922fe1144 100644 --- a/gnu/llvm/lldb/source/Core/StreamFile.cpp +++ b/gnu/llvm/lldb/source/Core/StreamFile.cpp @@ -10,7 +10,7 @@ #include "lldb/Host/FileSystem.h" #include "lldb/Utility/Log.h" -#include +#include using namespace lldb; using namespace lldb_private; @@ -43,7 +43,7 @@ StreamFile::StreamFile(const char *path, File::OpenOptions options, } } -StreamFile::~StreamFile() {} +StreamFile::~StreamFile() = default; void StreamFile::Flush() { m_file_sp->Flush(); } diff --git a/gnu/llvm/lldb/source/Core/Value.cpp b/gnu/llvm/lldb/source/Core/Value.cpp index 63467644cde..fb57c0fedf0 100644 --- a/gnu/llvm/lldb/source/Core/Value.cpp +++ b/gnu/llvm/lldb/source/Core/Value.cpp @@ -33,33 +33,29 @@ #include #include -#include +#include using namespace lldb; using namespace lldb_private; -Value::Value() - : m_value(), m_vector(), m_compiler_type(), m_context(nullptr), - m_value_type(eValueTypeScalar), m_context_type(eContextTypeInvalid), - m_data_buffer() {} +Value::Value() : m_value(), m_compiler_type(), m_data_buffer() {} Value::Value(const Scalar &scalar) - : m_value(scalar), m_vector(), m_compiler_type(), m_context(nullptr), - m_value_type(eValueTypeScalar), m_context_type(eContextTypeInvalid), + : m_value(scalar), m_compiler_type(), m_context(nullptr), + m_value_type(ValueType::Scalar), m_context_type(ContextType::Invalid), m_data_buffer() {} Value::Value(const void *bytes, int len) - : m_value(), m_vector(), m_compiler_type(), m_context(nullptr), - m_value_type(eValueTypeHostAddress), m_context_type(eContextTypeInvalid), + : m_value(), m_compiler_type(), m_context(nullptr), + m_value_type(ValueType::HostAddress), m_context_type(ContextType::Invalid), m_data_buffer() { SetBytes(bytes, len); } Value::Value(const Value &v) - : m_value(v.m_value), m_vector(v.m_vector), - m_compiler_type(v.m_compiler_type), m_context(v.m_context), - m_value_type(v.m_value_type), m_context_type(v.m_context_type), - m_data_buffer() { + : m_value(v.m_value), m_compiler_type(v.m_compiler_type), + m_context(v.m_context), m_value_type(v.m_value_type), + m_context_type(v.m_context_type), m_data_buffer() { const uintptr_t rhs_value = (uintptr_t)v.m_value.ULongLong(LLDB_INVALID_ADDRESS); if ((rhs_value != 0) && @@ -74,7 +70,6 @@ Value::Value(const Value &v) Value &Value::operator=(const Value &rhs) { if (this != &rhs) { m_value = rhs.m_value; - m_vector = rhs.m_vector; m_compiler_type = rhs.m_compiler_type; m_context = rhs.m_context; m_value_type = rhs.m_value_type; @@ -93,13 +88,13 @@ Value &Value::operator=(const Value &rhs) { } void Value::SetBytes(const void *bytes, int len) { - m_value_type = eValueTypeHostAddress; + m_value_type = ValueType::HostAddress; m_data_buffer.CopyData(bytes, len); m_value = (uintptr_t)m_data_buffer.GetBytes(); } void Value::AppendBytes(const void *bytes, int len) { - m_value_type = eValueTypeHostAddress; + m_value_type = ValueType::HostAddress; m_data_buffer.AppendData(bytes, len); m_value = (uintptr_t)m_data_buffer.GetBytes(); } @@ -115,27 +110,27 @@ Value::ValueType Value::GetValueType() const { return m_value_type; } AddressType Value::GetValueAddressType() const { switch (m_value_type) { - default: - case eValueTypeScalar: + case ValueType::Invalid: + case ValueType::Scalar: break; - case eValueTypeLoadAddress: + case ValueType::LoadAddress: return eAddressTypeLoad; - case eValueTypeFileAddress: + case ValueType::FileAddress: return eAddressTypeFile; - case eValueTypeHostAddress: + case ValueType::HostAddress: return eAddressTypeHost; } return eAddressTypeInvalid; } RegisterInfo *Value::GetRegisterInfo() const { - if (m_context_type == eContextTypeRegisterInfo) + if (m_context_type == ContextType::RegisterInfo) return static_cast(m_context); return nullptr; } Type *Value::GetType() { - if (m_context_type == eContextTypeLLDBType) + if (m_context_type == ContextType::LLDBType) return static_cast(m_context); return nullptr; } @@ -147,7 +142,9 @@ size_t Value::AppendDataToHostBuffer(const Value &rhs) { size_t curr_size = m_data_buffer.GetByteSize(); Status error; switch (rhs.GetValueType()) { - case eValueTypeScalar: { + case ValueType::Invalid: + return 0; + case ValueType::Scalar: { const size_t scalar_size = rhs.m_value.GetByteSize(); if (scalar_size > 0) { const size_t new_size = curr_size + scalar_size; @@ -159,20 +156,9 @@ size_t Value::AppendDataToHostBuffer(const Value &rhs) { } } } break; - case eValueTypeVector: { - const size_t vector_size = rhs.m_vector.length; - if (vector_size > 0) { - const size_t new_size = curr_size + vector_size; - if (ResizeData(new_size) == new_size) { - ::memcpy(m_data_buffer.GetBytes() + curr_size, rhs.m_vector.bytes, - vector_size); - return vector_size; - } - } - } break; - case eValueTypeFileAddress: - case eValueTypeLoadAddress: - case eValueTypeHostAddress: { + case ValueType::FileAddress: + case ValueType::LoadAddress: + case ValueType::HostAddress: { const uint8_t *src = rhs.GetBuffer().GetBytes(); const size_t src_len = rhs.GetBuffer().GetByteSize(); if (src && src_len > 0) { @@ -188,7 +174,7 @@ size_t Value::AppendDataToHostBuffer(const Value &rhs) { } size_t Value::ResizeData(size_t len) { - m_value_type = eValueTypeHostAddress; + m_value_type = ValueType::HostAddress; m_data_buffer.SetByteSize(len); m_value = (uintptr_t)m_data_buffer.GetBytes(); return m_data_buffer.GetByteSize(); @@ -196,12 +182,12 @@ size_t Value::ResizeData(size_t len) { bool Value::ValueOf(ExecutionContext *exe_ctx) { switch (m_context_type) { - case eContextTypeInvalid: - case eContextTypeRegisterInfo: // RegisterInfo * - case eContextTypeLLDBType: // Type * + case ContextType::Invalid: + case ContextType::RegisterInfo: // RegisterInfo * + case ContextType::LLDBType: // Type * break; - case eContextTypeVariable: // Variable * + case ContextType::Variable: // Variable * ResolveValue(exe_ctx); return true; } @@ -210,7 +196,7 @@ bool Value::ValueOf(ExecutionContext *exe_ctx) { uint64_t Value::GetValueByteSize(Status *error_ptr, ExecutionContext *exe_ctx) { switch (m_context_type) { - case eContextTypeRegisterInfo: // RegisterInfo * + case ContextType::RegisterInfo: // RegisterInfo * if (GetRegisterInfo()) { if (error_ptr) error_ptr->Clear(); @@ -218,9 +204,9 @@ uint64_t Value::GetValueByteSize(Status *error_ptr, ExecutionContext *exe_ctx) { } break; - case eContextTypeInvalid: - case eContextTypeLLDBType: // Type * - case eContextTypeVariable: // Variable * + case ContextType::Invalid: + case ContextType::LLDBType: // Type * + case ContextType::Variable: // Variable * { auto *scope = exe_ctx ? exe_ctx->GetBestExecutionContextScope() : nullptr; if (llvm::Optional size = GetCompilerType().GetByteSize(scope)) { @@ -239,19 +225,19 @@ uint64_t Value::GetValueByteSize(Status *error_ptr, ExecutionContext *exe_ctx) { const CompilerType &Value::GetCompilerType() { if (!m_compiler_type.IsValid()) { switch (m_context_type) { - case eContextTypeInvalid: + case ContextType::Invalid: break; - case eContextTypeRegisterInfo: + case ContextType::RegisterInfo: break; // TODO: Eventually convert into a compiler type? - case eContextTypeLLDBType: { + case ContextType::LLDBType: { Type *lldb_type = GetType(); if (lldb_type) m_compiler_type = lldb_type->GetForwardCompilerType(); } break; - case eContextTypeVariable: { + case ContextType::Variable: { Variable *variable = GetVariable(); if (variable) { Type *variable_type = variable->GetType(); @@ -271,14 +257,14 @@ void Value::SetCompilerType(const CompilerType &compiler_type) { lldb::Format Value::GetValueDefaultFormat() { switch (m_context_type) { - case eContextTypeRegisterInfo: + case ContextType::RegisterInfo: if (GetRegisterInfo()) return GetRegisterInfo()->format; break; - case eContextTypeInvalid: - case eContextTypeLLDBType: - case eContextTypeVariable: { + case ContextType::Invalid: + case ContextType::LLDBType: + case ContextType::Variable: { const CompilerType &ast_type = GetCompilerType(); if (ast_type.IsValid()) return ast_type.GetFormat(); @@ -291,17 +277,16 @@ lldb::Format Value::GetValueDefaultFormat() { bool Value::GetData(DataExtractor &data) { switch (m_value_type) { - default: - break; - - case eValueTypeScalar: + case ValueType::Invalid: + return false; + case ValueType::Scalar: if (m_value.GetData(data)) return true; break; - case eValueTypeLoadAddress: - case eValueTypeFileAddress: - case eValueTypeHostAddress: + case ValueType::LoadAddress: + case ValueType::FileAddress: + case ValueType::HostAddress: if (m_data_buffer.GetByteSize()) { data.SetData(m_data_buffer.GetBytes(), m_data_buffer.GetByteSize(), data.GetByteOrder()); @@ -329,15 +314,10 @@ Status Value::GetValueAsData(ExecutionContext *exe_ctx, DataExtractor &data, return error; switch (m_value_type) { - case eValueTypeVector: - if (ast_type.IsValid()) - data.SetAddressByteSize(ast_type.GetPointerByteSize()); - else - data.SetAddressByteSize(sizeof(void *)); - data.SetData(m_vector.bytes, m_vector.length, m_vector.byte_order); + case ValueType::Invalid: + error.SetErrorString("invalid value"); break; - - case eValueTypeScalar: { + case ValueType::Scalar: { data.SetByteOrder(endian::InlHostByteOrder()); if (ast_type.IsValid()) data.SetAddressByteSize(ast_type.GetPointerByteSize()); @@ -354,10 +334,10 @@ Status Value::GetValueAsData(ExecutionContext *exe_ctx, DataExtractor &data, return error; // Success; } - error.SetErrorStringWithFormat("extracting data from value failed"); + error.SetErrorString("extracting data from value failed"); break; } - case eValueTypeLoadAddress: + case ValueType::LoadAddress: if (exe_ctx == nullptr) { error.SetErrorString("can't read load address (no execution context)"); } else { @@ -394,7 +374,7 @@ Status Value::GetValueAsData(ExecutionContext *exe_ctx, DataExtractor &data, } break; - case eValueTypeFileAddress: + case ValueType::FileAddress: if (exe_ctx == nullptr) { error.SetErrorString("can't read file address (no execution context)"); } else if (exe_ctx->GetTargetPtr() == nullptr) { @@ -484,7 +464,7 @@ Status Value::GetValueAsData(ExecutionContext *exe_ctx, DataExtractor &data, } break; - case eValueTypeHostAddress: + case ValueType::HostAddress: address = m_value.ULongLong(LLDB_INVALID_ADDRESS); address_type = eAddressTypeHost; if (exe_ctx) { @@ -535,23 +515,17 @@ Status Value::GetValueAsData(ExecutionContext *exe_ctx, DataExtractor &data, if (address_type == eAddressTypeHost) { // The address is an address in this process, so just copy it. if (address == 0) { - error.SetErrorStringWithFormat( - "trying to read from host address of 0."); + error.SetErrorString("trying to read from host address of 0."); return error; } memcpy(dst, reinterpret_cast(address), byte_size); } else if ((address_type == eAddressTypeLoad) || (address_type == eAddressTypeFile)) { if (file_so_addr.IsValid()) { - // We have a file address that we were able to translate into a section - // offset address so we might be able to read this from the object - // files if we don't have a live process. Lets always try and read from - // the process if we have one though since we want to read the actual - // value by setting "prefer_file_cache" to false. - const bool prefer_file_cache = false; - if (exe_ctx->GetTargetRef().ReadMemory(file_so_addr, prefer_file_cache, - dst, byte_size, - error) != byte_size) { + const bool force_live_memory = true; + if (exe_ctx->GetTargetRef().ReadMemory(file_so_addr, dst, byte_size, + error, force_live_memory) != + byte_size) { error.SetErrorStringWithFormat( "read memory from 0x%" PRIx64 " failed", (uint64_t)address); } @@ -580,7 +554,7 @@ Status Value::GetValueAsData(ExecutionContext *exe_ctx, DataExtractor &data, address_type); } } else { - error.SetErrorStringWithFormat("out of memory"); + error.SetErrorString("out of memory"); } return error; @@ -590,13 +564,13 @@ Scalar &Value::ResolveValue(ExecutionContext *exe_ctx) { const CompilerType &compiler_type = GetCompilerType(); if (compiler_type.IsValid()) { switch (m_value_type) { - case eValueTypeScalar: // raw scalar value + case ValueType::Invalid: + case ValueType::Scalar: // raw scalar value break; - default: - case eValueTypeFileAddress: - case eValueTypeLoadAddress: // load address value - case eValueTypeHostAddress: // host address value (for memory in the process + case ValueType::FileAddress: + case ValueType::LoadAddress: // load address value + case ValueType::HostAddress: // host address value (for memory in the process // that is using liblldb) { DataExtractor data; @@ -604,20 +578,21 @@ Scalar &Value::ResolveValue(ExecutionContext *exe_ctx) { Status error(GetValueAsData(exe_ctx, data, nullptr)); if (error.Success()) { Scalar scalar; - if (compiler_type.GetValueAsScalar(data, 0, data.GetByteSize(), - scalar)) { + if (compiler_type.GetValueAsScalar( + data, 0, data.GetByteSize(), scalar, + exe_ctx ? exe_ctx->GetBestExecutionContextScope() : nullptr)) { m_value = scalar; - m_value_type = eValueTypeScalar; + m_value_type = ValueType::Scalar; } else { if ((uintptr_t)addr != (uintptr_t)m_data_buffer.GetBytes()) { m_value.Clear(); - m_value_type = eValueTypeScalar; + m_value_type = ValueType::Scalar; } } } else { if ((uintptr_t)addr != (uintptr_t)m_data_buffer.GetBytes()) { m_value.Clear(); - m_value_type = eValueTypeScalar; + m_value_type = ValueType::Scalar; } } } break; @@ -627,53 +602,52 @@ Scalar &Value::ResolveValue(ExecutionContext *exe_ctx) { } Variable *Value::GetVariable() { - if (m_context_type == eContextTypeVariable) + if (m_context_type == ContextType::Variable) return static_cast(m_context); return nullptr; } void Value::Clear() { m_value.Clear(); - m_vector.Clear(); m_compiler_type.Clear(); - m_value_type = eValueTypeScalar; + m_value_type = ValueType::Scalar; m_context = nullptr; - m_context_type = eContextTypeInvalid; + m_context_type = ContextType::Invalid; m_data_buffer.Clear(); } const char *Value::GetValueTypeAsCString(ValueType value_type) { switch (value_type) { - case eValueTypeScalar: + case ValueType::Invalid: + return "invalid"; + case ValueType::Scalar: return "scalar"; - case eValueTypeVector: - return "vector"; - case eValueTypeFileAddress: + case ValueType::FileAddress: return "file address"; - case eValueTypeLoadAddress: + case ValueType::LoadAddress: return "load address"; - case eValueTypeHostAddress: + case ValueType::HostAddress: return "host address"; }; - return "???"; + llvm_unreachable("enum cases exhausted."); } const char *Value::GetContextTypeAsCString(ContextType context_type) { switch (context_type) { - case eContextTypeInvalid: + case ContextType::Invalid: return "invalid"; - case eContextTypeRegisterInfo: + case ContextType::RegisterInfo: return "RegisterInfo *"; - case eContextTypeLLDBType: + case ContextType::LLDBType: return "Type *"; - case eContextTypeVariable: + case ContextType::Variable: return "Variable *"; }; - return "???"; + llvm_unreachable("enum cases exhausted."); } void Value::ConvertToLoadAddress(Module *module, Target *target) { - if (!module || !target || (GetValueType() != eValueTypeFileAddress)) + if (!module || !target || (GetValueType() != ValueType::FileAddress)) return; lldb::addr_t file_addr = GetScalar().ULongLong(LLDB_INVALID_ADDRESS); @@ -687,7 +661,7 @@ void Value::ConvertToLoadAddress(Module *module, Target *target) { if (load_addr == LLDB_INVALID_ADDRESS) return; - SetValueType(Value::eValueTypeLoadAddress); + SetValueType(Value::ValueType::LoadAddress); GetScalar() = load_addr; } diff --git a/gnu/llvm/lldb/source/Core/ValueObject.cpp b/gnu/llvm/lldb/source/Core/ValueObject.cpp index 3a775b07e5e..9c1ba99da1d 100644 --- a/gnu/llvm/lldb/source/Core/ValueObject.cpp +++ b/gnu/llvm/lldb/source/Core/ValueObject.cpp @@ -9,6 +9,7 @@ #include "lldb/Core/ValueObject.h" #include "lldb/Core/Address.h" +#include "lldb/Core/Declaration.h" #include "lldb/Core/Module.h" #include "lldb/Core/ValueObjectCast.h" #include "lldb/Core/ValueObjectChild.h" @@ -27,7 +28,6 @@ #include "lldb/Host/Config.h" #include "lldb/Symbol/CompileUnit.h" #include "lldb/Symbol/CompilerType.h" -#include "lldb/Symbol/Declaration.h" #include "lldb/Symbol/SymbolContext.h" #include "lldb/Symbol/Type.h" #include "lldb/Symbol/Variable.h" @@ -57,10 +57,12 @@ #include #include -#include -#include -#include -#include +#include +#include +#include +#include + +#include namespace lldb_private { class ExecutionContextScope; @@ -76,27 +78,10 @@ static user_id_t g_value_obj_uid = 0; // ValueObject constructor ValueObject::ValueObject(ValueObject &parent) - : UserID(++g_value_obj_uid), // Unique identifier for every value object - m_parent(&parent), m_root(nullptr), - m_update_point(parent.GetUpdatePoint()), m_name(), m_data(), m_value(), - m_error(), m_value_str(), m_old_value_str(), m_location_str(), - m_summary_str(), m_object_desc_str(), m_manager(parent.GetManager()), - m_children(), m_synthetic_children(), m_dynamic_value(nullptr), - m_synthetic_value(nullptr), m_deref_valobj(nullptr), - m_format(eFormatDefault), m_last_format(eFormatDefault), - m_last_format_mgr_revision(0), m_type_summary_sp(), m_type_format_sp(), - m_synthetic_children_sp(), m_user_id_of_forced_summary(), - m_address_type_of_ptr_or_ref_children(eAddressTypeInvalid), - m_value_checksum(), - m_preferred_display_language(lldb::eLanguageTypeUnknown), - m_language_flags(0), m_value_is_valid(false), m_value_did_change(false), - m_children_count_valid(false), m_old_value_valid(false), - m_is_deref_of_parent(false), m_is_array_item_for_pointer(false), - m_is_bitfield_for_scalar(false), m_is_child_at_offset(false), - m_is_getting_summary(false), - m_did_calculate_complete_objc_class_type(false), - m_is_synthetic_children_generated( - parent.m_is_synthetic_children_generated) { + : m_parent(&parent), m_update_point(parent.GetUpdatePoint()), + m_manager(parent.GetManager()), m_id(++g_value_obj_uid) { + m_flags.m_is_synthetic_children_generated = + parent.m_flags.m_is_synthetic_children_generated; m_data.SetByteOrder(parent.GetDataExtractor().GetByteOrder()); m_data.SetAddressByteSize(parent.GetDataExtractor().GetAddressByteSize()); m_manager->ManageObject(this); @@ -106,26 +91,9 @@ ValueObject::ValueObject(ValueObject &parent) ValueObject::ValueObject(ExecutionContextScope *exe_scope, ValueObjectManager &manager, AddressType child_ptr_or_ref_addr_type) - : UserID(++g_value_obj_uid), // Unique identifier for every value object - m_parent(nullptr), m_root(nullptr), m_update_point(exe_scope), m_name(), - m_data(), m_value(), m_error(), m_value_str(), m_old_value_str(), - m_location_str(), m_summary_str(), m_object_desc_str(), - m_manager(&manager), m_children(), m_synthetic_children(), - m_dynamic_value(nullptr), m_synthetic_value(nullptr), - m_deref_valobj(nullptr), m_format(eFormatDefault), - m_last_format(eFormatDefault), m_last_format_mgr_revision(0), - m_type_summary_sp(), m_type_format_sp(), m_synthetic_children_sp(), - m_user_id_of_forced_summary(), + : m_update_point(exe_scope), m_manager(&manager), m_address_type_of_ptr_or_ref_children(child_ptr_or_ref_addr_type), - m_value_checksum(), - m_preferred_display_language(lldb::eLanguageTypeUnknown), - m_language_flags(0), m_value_is_valid(false), m_value_did_change(false), - m_children_count_valid(false), m_old_value_valid(false), - m_is_deref_of_parent(false), m_is_array_item_for_pointer(false), - m_is_bitfield_for_scalar(false), m_is_child_at_offset(false), - m_is_getting_summary(false), - m_did_calculate_complete_objc_class_type(false), - m_is_synthetic_children_generated(false) { + m_id(++g_value_obj_uid) { if (exe_scope) { TargetSP target_sp(exe_scope->CalculateTarget()); if (target_sp) { @@ -138,7 +106,7 @@ ValueObject::ValueObject(ExecutionContextScope *exe_scope, } // Destructor -ValueObject::~ValueObject() {} +ValueObject::~ValueObject() = default; bool ValueObject::UpdateValueIfNeeded(bool update_format) { @@ -170,9 +138,9 @@ bool ValueObject::UpdateValueIfNeeded(bool update_format) { // Save the old value using swap to avoid a string copy which also will // clear our m_value_str if (m_value_str.empty()) { - m_old_value_valid = false; + m_flags.m_old_value_valid = false; } else { - m_old_value_valid = true; + m_flags.m_old_value_valid = true; m_old_value_str.swap(m_value_str); ClearUserVisibleData(eClearUserVisibleDataItemsValue); } @@ -215,7 +183,7 @@ bool ValueObject::UpdateValueIfNeeded(bool update_format) { if (first_update) SetValueDidChange(false); - else if (!m_value_did_change && !success) { + else if (!m_flags.m_value_did_change && !success) { // The value wasn't gotten successfully, so we mark this as changed if // the value used to be valid and now isn't SetValueDidChange(value_was_valid); @@ -266,8 +234,8 @@ void ValueObject::SetNeedsUpdate() { } void ValueObject::ClearDynamicTypeInformation() { - m_children_count_valid = false; - m_did_calculate_complete_objc_class_type = false; + m_flags.m_children_count_valid = false; + m_flags.m_did_calculate_complete_objc_class_type = false; m_last_format_mgr_revision = 0; m_override_type = CompilerType(); SetValueFormat(lldb::TypeFormatImplSP()); @@ -278,14 +246,14 @@ void ValueObject::ClearDynamicTypeInformation() { CompilerType ValueObject::MaybeCalculateCompleteType() { CompilerType compiler_type(GetCompilerTypeImpl()); - if (m_did_calculate_complete_objc_class_type) { + if (m_flags.m_did_calculate_complete_objc_class_type) { if (m_override_type.IsValid()) return m_override_type; else return compiler_type; } - m_did_calculate_complete_objc_class_type = true; + m_flags.m_did_calculate_complete_objc_class_type = true; ProcessSP process_sp( GetUpdatePoint().GetExecutionContextRef().GetProcessSP()); @@ -305,11 +273,7 @@ CompilerType ValueObject::MaybeCalculateCompleteType() { return compiler_type; } -CompilerType ValueObject::GetCompilerType() { - return MaybeCalculateCompleteType(); -} -TypeImpl ValueObject::GetTypeImpl() { return TypeImpl(GetCompilerType()); } DataExtractor &ValueObject::GetDataExtractor() { UpdateValueIfNeeded(false); @@ -321,12 +285,6 @@ const Status &ValueObject::GetError() { return m_error; } -ConstString ValueObject::GetName() const { return m_name; } - -const char *ValueObject::GetLocationAsCString() { - return GetLocationAsCStringImpl(m_value, m_data); -} - const char *ValueObject::GetLocationAsCStringImpl(const Value &value, const DataExtractor &data) { if (UpdateValueIfNeeded(false)) { @@ -336,9 +294,11 @@ const char *ValueObject::GetLocationAsCStringImpl(const Value &value, Value::ValueType value_type = value.GetValueType(); switch (value_type) { - case Value::eValueTypeScalar: - case Value::eValueTypeVector: - if (value.GetContextType() == Value::eContextTypeRegisterInfo) { + case Value::ValueType::Invalid: + m_location_str = "invalid"; + break; + case Value::ValueType::Scalar: + if (value.GetContextType() == Value::ContextType::RegisterInfo) { RegisterInfo *reg_info = value.GetRegisterInfo(); if (reg_info) { if (reg_info->name) @@ -352,13 +312,12 @@ const char *ValueObject::GetLocationAsCStringImpl(const Value &value, } } if (m_location_str.empty()) - m_location_str = - (value_type == Value::eValueTypeVector) ? "vector" : "scalar"; + m_location_str = "scalar"; break; - case Value::eValueTypeLoadAddress: - case Value::eValueTypeFileAddress: - case Value::eValueTypeHostAddress: { + case Value::ValueType::LoadAddress: + case Value::ValueType::FileAddress: + case Value::ValueType::HostAddress: { uint32_t addr_nibble_size = data.GetAddressByteSize() * 2; sstr.Printf("0x%*.*llx", addr_nibble_size, addr_nibble_size, value.GetScalar().ULongLong(LLDB_INVALID_ADDRESS)); @@ -370,10 +329,6 @@ const char *ValueObject::GetLocationAsCStringImpl(const Value &value, return m_location_str.c_str(); } -Value &ValueObject::GetValue() { return m_value; } - -const Value &ValueObject::GetValue() const { return m_value; } - bool ValueObject::ResolveValue(Scalar &scalar) { if (UpdateValueIfNeeded( false)) // make sure that you are up to date before returning anything @@ -417,16 +372,6 @@ bool ValueObject::IsLogicalTrue(Status &error) { return ret; } -bool ValueObject::GetValueIsValid() const { return m_value_is_valid; } - -void ValueObject::SetValueIsValid(bool b) { m_value_is_valid = b; } - -bool ValueObject::GetValueDidChange() { return m_value_did_change; } - -void ValueObject::SetValueDidChange(bool value_changed) { - m_value_did_change = value_changed; -} - ValueObjectSP ValueObject::GetChildAtIndex(size_t idx, bool can_create) { ValueObjectSP child_sp; // We may need to update our value if we are dynamic @@ -552,14 +497,14 @@ size_t ValueObject::GetNumChildren(uint32_t max) { UpdateValueIfNeeded(); if (max < UINT32_MAX) { - if (m_children_count_valid) { + if (m_flags.m_children_count_valid) { size_t children_count = m_children.GetChildrenCount(); return children_count <= max ? children_count : max; } else return CalculateNumChildren(max); } - if (!m_children_count_valid) { + if (!m_flags.m_children_count_valid) { SetNumChildren(CalculateNumChildren()); } return m_children.GetChildrenCount(); @@ -579,12 +524,10 @@ bool ValueObject::MightHaveChildren() { // Should only be called by ValueObject::GetNumChildren() void ValueObject::SetNumChildren(size_t num_children) { - m_children_count_valid = true; + m_flags.m_children_count_valid = true; m_children.SetChildrenCount(num_children); } -void ValueObject::SetName(ConstString name) { m_name = name; } - ValueObject *ValueObject::CreateChildAtIndex(size_t idx, bool synthetic_array_member, int32_t synthetic_index) { @@ -653,10 +596,10 @@ bool ValueObject::GetSummaryAsCString(TypeSummaryImpl *summary_ptr, // ideally we would like to bail out if passing NULL, but if we do so we end // up not providing the summary for function pointers anymore - if (/*summary_ptr == NULL ||*/ m_is_getting_summary) + if (/*summary_ptr == NULL ||*/ m_flags.m_is_getting_summary) return false; - m_is_getting_summary = true; + m_flags.m_is_getting_summary = true; TypeSummaryOptions actual_options(options); @@ -679,7 +622,7 @@ bool ValueObject::GetSummaryAsCString(TypeSummaryImpl *summary_ptr, // up-to-date (e.g. ${svar%#}) summary_ptr->FormatObject(this, destination, actual_options); } - m_is_getting_summary = false; + m_flags.m_is_getting_summary = false; return !destination.empty(); } @@ -778,7 +721,7 @@ size_t ValueObject::GetPointeeData(DataExtractor &data, uint32_t item_idx, if (target) { heap_buf_ptr->SetByteSize(bytes); size_t bytes_read = target->ReadMemory( - so_addr, false, heap_buf_ptr->GetBytes(), bytes, error); + so_addr, heap_buf_ptr->GetBytes(), bytes, error, true); if (error.Success()) { data.SetData(data_sp); return bytes_read; @@ -849,12 +792,15 @@ bool ValueObject::SetData(DataExtractor &data, Status &error) { uint64_t count = 0; const Encoding encoding = GetCompilerType().GetEncoding(count); - const size_t byte_size = GetByteSize(); + const size_t byte_size = GetByteSize().getValueOr(0); Value::ValueType value_type = m_value.GetValueType(); switch (value_type) { - case Value::eValueTypeScalar: { + case Value::ValueType::Invalid: + error.SetErrorString("invalid location"); + return false; + case Value::ValueType::Scalar: { Status set_error = m_value.GetScalar().SetValueFromData(data, encoding, byte_size); @@ -864,7 +810,7 @@ bool ValueObject::SetData(DataExtractor &data, Status &error) { return false; } } break; - case Value::eValueTypeLoadAddress: { + case Value::ValueType::LoadAddress: { // If it is a load address, then the scalar value is the storage location // of the data, and we have to shove this value down to that load location. ExecutionContext exe_ctx(GetExecutionContextRef()); @@ -881,7 +827,7 @@ bool ValueObject::SetData(DataExtractor &data, Status &error) { } } } break; - case Value::eValueTypeHostAddress: { + case Value::ValueType::HostAddress: { // If it is a host address, then we stuff the scalar as a DataBuffer into // the Value's data. DataBufferSP buffer_sp(new DataBufferHeap(byte_size, 0)); @@ -891,8 +837,7 @@ bool ValueObject::SetData(DataExtractor &data, Status &error) { byte_size, m_data.GetByteOrder()); m_value.GetScalar() = (uintptr_t)m_data.GetDataStart(); } break; - case Value::eValueTypeFileAddress: - case Value::eValueTypeVector: + case Value::ValueType::FileAddress: break; } @@ -945,7 +890,7 @@ ValueObject::ReadPointedString(lldb::DataBufferSP &buffer_sp, Status &error, if (is_array) { // We have an array uint64_t array_size = 0; - if (compiler_type.IsArrayType(nullptr, &array_size, nullptr)) { + if (compiler_type.IsArrayType(nullptr, &array_size)) { cstr_len = array_size; if (cstr_len > max_length) { capped_data = true; @@ -1107,10 +1052,10 @@ const char *ValueObject::GetValueAsCString() { if (m_type_format_sp) format_sp = m_type_format_sp; else { - if (m_is_bitfield_for_scalar) + if (m_flags.m_is_bitfield_for_scalar) my_format = eFormatUnsigned; else { - if (m_value.GetContextType() == Value::eContextTypeRegisterInfo) { + if (m_value.GetContextType() == Value::ContextType::RegisterInfo) { const RegisterInfo *reg_info = m_value.GetRegisterInfo(); if (reg_info) my_format = reg_info->format; @@ -1125,7 +1070,7 @@ const char *ValueObject::GetValueAsCString() { if (!format_sp) format_sp = std::make_shared(my_format); if (GetValueAsCString(*format_sp.get(), m_value_str)) { - if (!m_value_did_change && m_old_value_valid) { + if (!m_flags.m_value_did_change && m_flags.m_old_value_valid) { // The value was gotten successfully, so we consider the value as // changed if the value string differs SetValueDidChange(m_old_value_str != m_value_str); @@ -1458,8 +1403,9 @@ addr_t ValueObject::GetAddressOf(bool scalar_is_load_address, return LLDB_INVALID_ADDRESS; switch (m_value.GetValueType()) { - case Value::eValueTypeScalar: - case Value::eValueTypeVector: + case Value::ValueType::Invalid: + return LLDB_INVALID_ADDRESS; + case Value::ValueType::Scalar: if (scalar_is_load_address) { if (address_type) *address_type = eAddressTypeLoad; @@ -1467,13 +1413,13 @@ addr_t ValueObject::GetAddressOf(bool scalar_is_load_address, } break; - case Value::eValueTypeLoadAddress: - case Value::eValueTypeFileAddress: { + case Value::ValueType::LoadAddress: + case Value::ValueType::FileAddress: { if (address_type) *address_type = m_value.GetValueAddressType(); return m_value.GetScalar().ULongLong(LLDB_INVALID_ADDRESS); } break; - case Value::eValueTypeHostAddress: { + case Value::ValueType::HostAddress: { if (address_type) *address_type = m_value.GetValueAddressType(); return LLDB_INVALID_ADDRESS; @@ -1493,14 +1439,15 @@ addr_t ValueObject::GetPointerValue(AddressType *address_type) { return address; switch (m_value.GetValueType()) { - case Value::eValueTypeScalar: - case Value::eValueTypeVector: + case Value::ValueType::Invalid: + return LLDB_INVALID_ADDRESS; + case Value::ValueType::Scalar: address = m_value.GetScalar().ULongLong(LLDB_INVALID_ADDRESS); break; - case Value::eValueTypeHostAddress: - case Value::eValueTypeLoadAddress: - case Value::eValueTypeFileAddress: { + case Value::ValueType::HostAddress: + case Value::ValueType::LoadAddress: + case Value::ValueType::FileAddress: { lldb::offset_t data_offset = 0; address = m_data.GetAddress(&data_offset); } break; @@ -1524,11 +1471,11 @@ bool ValueObject::SetValueFromCString(const char *value_str, Status &error) { uint64_t count = 0; const Encoding encoding = GetCompilerType().GetEncoding(count); - const size_t byte_size = GetByteSize(); + const size_t byte_size = GetByteSize().getValueOr(0); Value::ValueType value_type = m_value.GetValueType(); - if (value_type == Value::eValueTypeScalar) { + if (value_type == Value::ValueType::Scalar) { // If the value is already a scalar, then let the scalar change itself: m_value.GetScalar().SetValueFromCString(value_str, encoding, byte_size); } else if (byte_size <= 16) { @@ -1539,7 +1486,7 @@ bool ValueObject::SetValueFromCString(const char *value_str, Status &error) { error = new_scalar.SetValueFromCString(value_str, encoding, byte_size); if (error.Success()) { switch (value_type) { - case Value::eValueTypeLoadAddress: { + case Value::ValueType::LoadAddress: { // If it is a load address, then the scalar value is the storage // location of the data, and we have to shove this value down to that // load location. @@ -1558,7 +1505,7 @@ bool ValueObject::SetValueFromCString(const char *value_str, Status &error) { } } } break; - case Value::eValueTypeHostAddress: { + case Value::ValueType::HostAddress: { // If it is a host address, then we stuff the scalar as a DataBuffer // into the Value's data. DataExtractor new_data; @@ -1575,9 +1522,11 @@ bool ValueObject::SetValueFromCString(const char *value_str, Status &error) { m_value.GetScalar() = (uintptr_t)m_data.GetDataStart(); } break; - case Value::eValueTypeFileAddress: - case Value::eValueTypeScalar: - case Value::eValueTypeVector: + case Value::ValueType::Invalid: + error.SetErrorString("invalid location"); + return false; + case Value::ValueType::FileAddress: + case Value::ValueType::Scalar: break; } } else { @@ -1600,20 +1549,6 @@ bool ValueObject::GetDeclaration(Declaration &decl) { return false; } -ConstString ValueObject::GetTypeName() { - return GetCompilerType().GetTypeName(); -} - -ConstString ValueObject::GetDisplayTypeName() { return GetTypeName(); } - -ConstString ValueObject::GetQualifiedTypeName() { - return GetCompilerType().GetTypeName(); -} - -LanguageType ValueObject::GetObjectRuntimeLanguage() { - return GetCompilerType().GetMinimumLanguage(); -} - void ValueObject::AddSyntheticChild(ConstString key, ValueObject *valobj) { m_synthetic_children[key] = valobj; @@ -1628,27 +1563,6 @@ ValueObjectSP ValueObject::GetSyntheticChild(ConstString key) const { return synthetic_child_sp; } -uint32_t -ValueObject::GetTypeInfo(CompilerType *pointee_or_element_compiler_type) { - return GetCompilerType().GetTypeInfo(pointee_or_element_compiler_type); -} - -bool ValueObject::IsPointerType() { return GetCompilerType().IsPointerType(); } - -bool ValueObject::IsArrayType() { - return GetCompilerType().IsArrayType(nullptr, nullptr, nullptr); -} - -bool ValueObject::IsScalarType() { return GetCompilerType().IsScalarType(); } - -bool ValueObject::IsIntegerType(bool &is_signed) { - return GetCompilerType().IsIntegerType(is_signed); -} - -bool ValueObject::IsPointerOrReferenceType() { - return GetCompilerType().IsPointerOrReferenceType(); -} - bool ValueObject::IsPossibleDynamicType() { ExecutionContext exe_ctx(GetExecutionContextRef()); Process *process = exe_ctx.GetProcessPtr(); @@ -1663,7 +1577,7 @@ bool ValueObject::IsRuntimeSupportValue() { if (!process) return false; - // We trust the the compiler did the right thing and marked runtime support + // We trust that the compiler did the right thing and marked runtime support // values as artificial. if (!GetVariable() || !GetVariable()->IsArtificial()) return false; @@ -1702,8 +1616,7 @@ ValueObjectSP ValueObject::GetSyntheticArrayMember(size_t index, bool can_create) { ValueObjectSP synthetic_child_sp; if (IsPointerType() || IsArrayType()) { - char index_str[64]; - snprintf(index_str, sizeof(index_str), "[%" PRIu64 "]", (uint64_t)index); + std::string index_str = llvm::formatv("[{0}]", index); ConstString index_const_str(index_str); // Check if we have already created a synthetic array member in this valid // object. If we have we will re-use it. @@ -1719,7 +1632,7 @@ ValueObjectSP ValueObject::GetSyntheticArrayMember(size_t index, AddSyntheticChild(index_const_str, synthetic_child); synthetic_child_sp = synthetic_child->GetSP(); synthetic_child_sp->SetName(ConstString(index_str)); - synthetic_child_sp->m_is_array_item_for_pointer = true; + synthetic_child_sp->m_flags.m_is_array_item_for_pointer = true; } } } @@ -1730,8 +1643,7 @@ ValueObjectSP ValueObject::GetSyntheticBitFieldChild(uint32_t from, uint32_t to, bool can_create) { ValueObjectSP synthetic_child_sp; if (IsScalarType()) { - char index_str[64]; - snprintf(index_str, sizeof(index_str), "[%i-%i]", from, to); + std::string index_str = llvm::formatv("[{0}-{1}]", from, to); ConstString index_const_str(index_str); // Check if we have already created a synthetic array member in this valid // object. If we have we will re-use it. @@ -1741,20 +1653,20 @@ ValueObjectSP ValueObject::GetSyntheticBitFieldChild(uint32_t from, uint32_t to, uint32_t bit_field_offset = from; if (GetDataExtractor().GetByteOrder() == eByteOrderBig) bit_field_offset = - GetByteSize() * 8 - bit_field_size - bit_field_offset; + GetByteSize().getValueOr(0) * 8 - bit_field_size - bit_field_offset; // We haven't made a synthetic array member for INDEX yet, so lets make // one and cache it for any future reference. ValueObjectChild *synthetic_child = new ValueObjectChild( - *this, GetCompilerType(), index_const_str, GetByteSize(), 0, - bit_field_size, bit_field_offset, false, false, eAddressTypeInvalid, - 0); + *this, GetCompilerType(), index_const_str, + GetByteSize().getValueOr(0), 0, bit_field_size, bit_field_offset, + false, false, eAddressTypeInvalid, 0); // Cache the value if we got one back... if (synthetic_child) { AddSyntheticChild(index_const_str, synthetic_child); synthetic_child_sp = synthetic_child->GetSP(); synthetic_child_sp->SetName(ConstString(index_str)); - synthetic_child_sp->m_is_bitfield_for_scalar = true; + synthetic_child_sp->m_flags.m_is_bitfield_for_scalar = true; } } } @@ -1768,9 +1680,7 @@ ValueObjectSP ValueObject::GetSyntheticChildAtOffset( ValueObjectSP synthetic_child_sp; if (name_const_str.IsEmpty()) { - char name_str[64]; - snprintf(name_str, sizeof(name_str), "@%i", offset); - name_const_str.SetCString(name_str); + name_const_str.SetString("@" + std::to_string(offset)); } // Check if we have already created a synthetic array member in this valid @@ -1795,7 +1705,7 @@ ValueObjectSP ValueObject::GetSyntheticChildAtOffset( AddSyntheticChild(name_const_str, synthetic_child); synthetic_child_sp = synthetic_child->GetSP(); synthetic_child_sp->SetName(name_const_str); - synthetic_child_sp->m_is_child_at_offset = true; + synthetic_child_sp->m_flags.m_is_child_at_offset = true; } return synthetic_child_sp; } @@ -1932,10 +1842,6 @@ ValueObjectSP ValueObject::GetDynamicValue(DynamicValueType use_dynamic) { return ValueObjectSP(); } -ValueObjectSP ValueObject::GetStaticValue() { return GetSP(); } - -lldb::ValueObjectSP ValueObject::GetNonSyntheticValue() { return GetSP(); } - ValueObjectSP ValueObject::GetSyntheticValue() { CalculateSyntheticValue(); @@ -1987,10 +1893,10 @@ void ValueObject::GetExpressionPath(Stream &s, // sometimes they are consed up in ways that don't make sense from an // underlying language/API standpoint. So, use a special code path here to // return something that can hopefully be used in expression - if (m_is_synthetic_children_generated) { + if (m_flags.m_is_synthetic_children_generated) { UpdateValueIfNeeded(); - if (m_value.GetValueType() == Value::eValueTypeLoadAddress) { + if (m_value.GetValueType() == Value::ValueType::LoadAddress) { if (IsPointerOrReferenceType()) { s.Printf("((%s)0x%" PRIx64 ")", GetTypeName().AsCString("void"), GetValueAsUnsigned(0)); @@ -2035,7 +1941,7 @@ void ValueObject::GetExpressionPath(Stream &s, // if we are a deref_of_parent just because we are synthetic array members // made up to allow ptr[%d] syntax to work in variable printing, then add our // name ([%d]) to the expression path - if (m_is_array_item_for_pointer && + if (m_flags.m_is_array_item_for_pointer && epformat == eGetExpressionPathFormatHonorPointers) s.PutCString(m_name.GetStringRef()); @@ -2650,21 +2556,6 @@ ValueObjectSP ValueObject::GetValueForExpressionPath_Impl( } } -void ValueObject::LogValueObject(Log *log) { - if (log) - return LogValueObject(log, DumpValueObjectOptions(*this)); -} - -void ValueObject::LogValueObject(Log *log, - const DumpValueObjectOptions &options) { - if (log) { - StreamString s; - Dump(s, options); - if (s.GetSize()) - log->PutCString(s.GetData()); - } -} - void ValueObject::Dump(Stream &s) { Dump(s, DumpValueObjectOptions(*this)); } void ValueObject::Dump(Stream &s, const DumpValueObjectOptions &options) { @@ -2905,8 +2796,7 @@ ValueObjectSP ValueObject::CastPointerType(const char *name, TypeSP &type_sp) { return valobj_sp; } -ValueObject::EvaluationPoint::EvaluationPoint() - : m_mod_id(), m_exe_ctx_ref(), m_needs_update(true) {} +ValueObject::EvaluationPoint::EvaluationPoint() : m_mod_id(), m_exe_ctx_ref() {} ValueObject::EvaluationPoint::EvaluationPoint(ExecutionContextScope *exe_scope, bool use_selected) @@ -2949,7 +2839,7 @@ ValueObject::EvaluationPoint::EvaluationPoint( const ValueObject::EvaluationPoint &rhs) : m_mod_id(), m_exe_ctx_ref(rhs.m_exe_ctx_ref), m_needs_update(true) {} -ValueObject::EvaluationPoint::~EvaluationPoint() {} +ValueObject::EvaluationPoint::~EvaluationPoint() = default; // This function checks the EvaluationPoint against the current process state. // If the current state matches the evaluation point, or the evaluation point @@ -3103,7 +2993,7 @@ lldb::ValueObjectSP ValueObject::CreateValueObjectFromAddress( exe_ctx.GetAddressByteSize())); if (ptr_result_valobj_sp) { ptr_result_valobj_sp->GetValue().SetValueType( - Value::eValueTypeLoadAddress); + Value::ValueType::LoadAddress); Status err; ptr_result_valobj_sp = ptr_result_valobj_sp->Dereference(err); if (ptr_result_valobj_sp && !name.empty()) @@ -3202,10 +3092,6 @@ lldb::LanguageType ValueObject::GetPreferredDisplayLanguage() { return (m_preferred_display_language = type); // only compute it once } -void ValueObject::SetPreferredDisplayLanguage(lldb::LanguageType lt) { - m_preferred_display_language = lt; -} - void ValueObject::SetPreferredDisplayLanguageIfNeeded(lldb::LanguageType lt) { if (m_preferred_display_language == lldb::eLanguageTypeUnknown) SetPreferredDisplayLanguage(lt); @@ -3215,11 +3101,11 @@ bool ValueObject::CanProvideValue() { // we need to support invalid types as providers of values because some bare- // board debugging scenarios have no notion of types, but still manage to // have raw numeric values for things like registers. sigh. - const CompilerType &type(GetCompilerType()); + CompilerType type = GetCompilerType(); return (!type.IsValid()) || (0 != (type.GetTypeInfo() & eTypeHasValue)); } -bool ValueObject::IsChecksumEmpty() { return m_value_checksum.empty(); } + ValueObjectSP ValueObject::Persist() { if (!UpdateValueIfNeeded()) @@ -3248,109 +3134,3 @@ ValueObjectSP ValueObject::Persist() { return persistent_var_sp->GetValueObject(); } - -bool ValueObject::IsSyntheticChildrenGenerated() { - return m_is_synthetic_children_generated; -} - -void ValueObject::SetSyntheticChildrenGenerated(bool b) { - m_is_synthetic_children_generated = b; -} - -uint64_t ValueObject::GetLanguageFlags() { return m_language_flags; } - -void ValueObject::SetLanguageFlags(uint64_t flags) { m_language_flags = flags; } - -ValueObjectManager::ValueObjectManager(lldb::ValueObjectSP in_valobj_sp, - lldb::DynamicValueType use_dynamic, - bool use_synthetic) : m_root_valobj_sp(), - m_user_valobj_sp(), m_use_dynamic(use_dynamic), m_stop_id(UINT32_MAX), - m_use_synthetic(use_synthetic) { - if (!in_valobj_sp) - return; - // If the user passes in a value object that is dynamic or synthetic, then - // water it down to the static type. - m_root_valobj_sp = in_valobj_sp->GetQualifiedRepresentationIfAvailable(lldb::eNoDynamicValues, false); -} - -bool ValueObjectManager::IsValid() const { - if (!m_root_valobj_sp) - return false; - lldb::TargetSP target_sp = GetTargetSP(); - if (target_sp) - return target_sp->IsValid(); - return false; -} - -lldb::ValueObjectSP ValueObjectManager::GetSP() { - lldb::ProcessSP process_sp = GetProcessSP(); - if (!process_sp) - return lldb::ValueObjectSP(); - - const uint32_t current_stop_id = process_sp->GetLastNaturalStopID(); - if (current_stop_id == m_stop_id) - return m_user_valobj_sp; - - m_stop_id = current_stop_id; - - if (!m_root_valobj_sp) { - m_user_valobj_sp.reset(); - return m_root_valobj_sp; - } - - m_user_valobj_sp = m_root_valobj_sp; - - if (m_use_dynamic != lldb::eNoDynamicValues) { - lldb::ValueObjectSP dynamic_sp = m_user_valobj_sp->GetDynamicValue(m_use_dynamic); - if (dynamic_sp) - m_user_valobj_sp = dynamic_sp; - } - - if (m_use_synthetic) { - lldb::ValueObjectSP synthetic_sp = m_user_valobj_sp->GetSyntheticValue(); - if (synthetic_sp) - m_user_valobj_sp = synthetic_sp; - } - - return m_user_valobj_sp; -} - -void ValueObjectManager::SetUseDynamic(lldb::DynamicValueType use_dynamic) { - if (use_dynamic != m_use_dynamic) { - m_use_dynamic = use_dynamic; - m_user_valobj_sp.reset(); - m_stop_id = UINT32_MAX; - } -} - -void ValueObjectManager::SetUseSynthetic(bool use_synthetic) { - if (m_use_synthetic != use_synthetic) { - m_use_synthetic = use_synthetic; - m_user_valobj_sp.reset(); - m_stop_id = UINT32_MAX; - } -} - -lldb::TargetSP ValueObjectManager::GetTargetSP() const { - if (!m_root_valobj_sp) - return m_root_valobj_sp->GetTargetSP(); - return lldb::TargetSP(); -} - -lldb::ProcessSP ValueObjectManager::GetProcessSP() const { - if (m_root_valobj_sp) - return m_root_valobj_sp->GetProcessSP(); - return lldb::ProcessSP(); -} - -lldb::ThreadSP ValueObjectManager::GetThreadSP() const { - if (m_root_valobj_sp) - return m_root_valobj_sp->GetThreadSP(); - return lldb::ThreadSP(); -} - -lldb::StackFrameSP ValueObjectManager::GetFrameSP() const { - if (m_root_valobj_sp) - return m_root_valobj_sp->GetFrameSP(); - return lldb::StackFrameSP(); -} diff --git a/gnu/llvm/lldb/source/Core/ValueObjectCast.cpp b/gnu/llvm/lldb/source/Core/ValueObjectCast.cpp index 22e856be539..9f803912d0c 100644 --- a/gnu/llvm/lldb/source/Core/ValueObjectCast.cpp +++ b/gnu/llvm/lldb/source/Core/ValueObjectCast.cpp @@ -36,7 +36,7 @@ ValueObjectCast::ValueObjectCast(ValueObject &parent, ConstString name, m_value.SetCompilerType(cast_type); } -ValueObjectCast::~ValueObjectCast() {} +ValueObjectCast::~ValueObjectCast() = default; CompilerType ValueObjectCast::GetCompilerTypeImpl() { return m_cast_type; } @@ -47,7 +47,7 @@ size_t ValueObjectCast::CalculateNumChildren(uint32_t max) { return children_count <= max ? children_count : max; } -uint64_t ValueObjectCast::GetByteSize() { +llvm::Optional ValueObjectCast::GetByteSize() { ExecutionContext exe_ctx(GetExecutionContextRef()); return m_value.GetValueByteSize(nullptr, &exe_ctx); } diff --git a/gnu/llvm/lldb/source/Core/ValueObjectChild.cpp b/gnu/llvm/lldb/source/Core/ValueObjectChild.cpp index 6205ed32c61..a2beeb0bcde 100644 --- a/gnu/llvm/lldb/source/Core/ValueObjectChild.cpp +++ b/gnu/llvm/lldb/source/Core/ValueObjectChild.cpp @@ -21,8 +21,8 @@ #include #include -#include -#include +#include +#include using namespace lldb_private; @@ -43,7 +43,7 @@ ValueObjectChild::ValueObjectChild( SetLanguageFlags(language_flags); } -ValueObjectChild::~ValueObjectChild() {} +ValueObjectChild::~ValueObjectChild() = default; lldb::ValueType ValueObjectChild::GetValueType() const { return m_parent->GetValueType(); @@ -57,15 +57,8 @@ size_t ValueObjectChild::CalculateNumChildren(uint32_t max) { static void AdjustForBitfieldness(ConstString &name, uint8_t bitfield_bit_size) { - if (name && bitfield_bit_size) { - const char *compiler_type_name = name.AsCString(); - if (compiler_type_name) { - std::vector bitfield_type_name(strlen(compiler_type_name) + 32, 0); - ::snprintf(&bitfield_type_name.front(), bitfield_type_name.size(), - "%s:%u", compiler_type_name, bitfield_bit_size); - name.SetCString(&bitfield_type_name.front()); - } - } + if (name && bitfield_bit_size) + name.SetString(llvm::formatv("{0}:{1}", name, bitfield_bit_size).str()); } ConstString ValueObjectChild::GetTypeName() { @@ -118,8 +111,7 @@ bool ValueObjectChild::UpdateValue() { CompilerType parent_type(parent->GetCompilerType()); // Copy the parent scalar value and the scalar value type m_value.GetScalar() = parent->GetValue().GetScalar(); - Value::ValueType value_type = parent->GetValue().GetValueType(); - m_value.SetValueType(value_type); + m_value.SetValueType(parent->GetValue().GetValueType()); Flags parent_type_flags(parent_type.GetTypeInfo()); const bool is_instance_ptr_base = @@ -127,97 +119,79 @@ bool ValueObjectChild::UpdateValue() { (parent_type_flags.AnySet(lldb::eTypeInstanceIsPointer))); if (parent->GetCompilerType().ShouldTreatScalarValueAsAddress()) { - lldb::addr_t addr = parent->GetPointerValue(); - m_value.GetScalar() = addr; - + m_value.GetScalar() = parent->GetPointerValue(); + + switch (parent->GetAddressTypeOfChildren()) { + case eAddressTypeFile: { + lldb::ProcessSP process_sp(GetProcessSP()); + if (process_sp && process_sp->IsAlive()) + m_value.SetValueType(Value::ValueType::LoadAddress); + else + m_value.SetValueType(Value::ValueType::FileAddress); + } break; + case eAddressTypeLoad: + m_value.SetValueType(is_instance_ptr_base + ? Value::ValueType::Scalar + : Value::ValueType::LoadAddress); + break; + case eAddressTypeHost: + m_value.SetValueType(Value::ValueType::HostAddress); + break; + case eAddressTypeInvalid: + // TODO: does this make sense? + m_value.SetValueType(Value::ValueType::Scalar); + break; + } + } + switch (m_value.GetValueType()) { + case Value::ValueType::Invalid: + break; + case Value::ValueType::LoadAddress: + case Value::ValueType::FileAddress: + case Value::ValueType::HostAddress: { + lldb::addr_t addr = m_value.GetScalar().ULongLong(LLDB_INVALID_ADDRESS); if (addr == LLDB_INVALID_ADDRESS) { m_error.SetErrorString("parent address is invalid."); } else if (addr == 0) { m_error.SetErrorString("parent is NULL"); } else { - m_value.GetScalar() += m_byte_offset; - AddressType addr_type = parent->GetAddressTypeOfChildren(); - - switch (addr_type) { - case eAddressTypeFile: { - lldb::ProcessSP process_sp(GetProcessSP()); - if (process_sp && process_sp->IsAlive()) - m_value.SetValueType(Value::eValueTypeLoadAddress); - else - m_value.SetValueType(Value::eValueTypeFileAddress); - } break; - case eAddressTypeLoad: - m_value.SetValueType(is_instance_ptr_base - ? Value::eValueTypeScalar - : Value::eValueTypeLoadAddress); - break; - case eAddressTypeHost: - m_value.SetValueType(Value::eValueTypeHostAddress); - break; - case eAddressTypeInvalid: - // TODO: does this make sense? - m_value.SetValueType(Value::eValueTypeScalar); - break; - } - } - } else { - switch (value_type) { - case Value::eValueTypeLoadAddress: - case Value::eValueTypeFileAddress: - case Value::eValueTypeHostAddress: { - lldb::addr_t addr = - m_value.GetScalar().ULongLong(LLDB_INVALID_ADDRESS); - if (addr == LLDB_INVALID_ADDRESS) { - m_error.SetErrorString("parent address is invalid."); - } else if (addr == 0) { - m_error.SetErrorString("parent is NULL"); - } else { - // Set this object's scalar value to the address of its value by - // adding its byte offset to the parent address - m_value.GetScalar() += GetByteOffset(); - - // If a bitfield doesn't fit into the child_byte_size'd - // window at child_byte_offset, move the window forward - // until it fits. The problem here is that Value has no - // notion of bitfields and thus the Value's DataExtractor - // is sized like the bitfields CompilerType; a sequence of - // bitfields, however, can be larger than their underlying - // type. - if (m_bitfield_bit_offset) { - const bool thread_and_frame_only_if_stopped = true; - ExecutionContext exe_ctx(GetExecutionContextRef().Lock( - thread_and_frame_only_if_stopped)); - if (auto type_bit_size = GetCompilerType().GetBitSize( - exe_ctx.GetBestExecutionContextScope())) { - uint64_t bitfield_end = - m_bitfield_bit_size + m_bitfield_bit_offset; - if (bitfield_end > *type_bit_size) { - uint64_t overhang_bytes = - (bitfield_end - *type_bit_size + 7) / 8; - m_value.GetScalar() += overhang_bytes; - m_bitfield_bit_offset -= overhang_bytes * 8; - } + // If a bitfield doesn't fit into the child_byte_size'd window at + // child_byte_offset, move the window forward until it fits. The + // problem here is that Value has no notion of bitfields and thus the + // Value's DataExtractor is sized like the bitfields CompilerType; a + // sequence of bitfields, however, can be larger than their underlying + // type. + if (m_bitfield_bit_offset) { + const bool thread_and_frame_only_if_stopped = true; + ExecutionContext exe_ctx(GetExecutionContextRef().Lock( + thread_and_frame_only_if_stopped)); + if (auto type_bit_size = GetCompilerType().GetBitSize( + exe_ctx.GetBestExecutionContextScope())) { + uint64_t bitfield_end = + m_bitfield_bit_size + m_bitfield_bit_offset; + if (bitfield_end > *type_bit_size) { + uint64_t overhang_bytes = + (bitfield_end - *type_bit_size + 7) / 8; + m_byte_offset += overhang_bytes; + m_bitfield_bit_offset -= overhang_bytes * 8; } } } - } break; - case Value::eValueTypeScalar: - // try to extract the child value from the parent's scalar value - { - Scalar scalar(m_value.GetScalar()); - if (m_bitfield_bit_size) - scalar.ExtractBitfield(m_bitfield_bit_size, - m_bitfield_bit_offset); - else - scalar.ExtractBitfield(8 * m_byte_size, 8 * m_byte_offset); - m_value.GetScalar() = scalar; - } - break; - default: - m_error.SetErrorString("parent has invalid value."); - break; + // Set this object's scalar value to the address of its value by + // adding its byte offset to the parent address + m_value.GetScalar() += m_byte_offset; + } + } break; + + case Value::ValueType::Scalar: + // try to extract the child value from the parent's scalar value + { + Scalar scalar(m_value.GetScalar()); + scalar.ExtractBitfield(8 * m_byte_size, 8 * m_byte_offset); + m_value.GetScalar() = scalar; } + break; } if (m_error.Success()) { diff --git a/gnu/llvm/lldb/source/Core/ValueObjectConstResult.cpp b/gnu/llvm/lldb/source/Core/ValueObjectConstResult.cpp index 8d84f8e62cc..174b9359d52 100644 --- a/gnu/llvm/lldb/source/Core/ValueObjectConstResult.cpp +++ b/gnu/llvm/lldb/source/Core/ValueObjectConstResult.cpp @@ -40,8 +40,7 @@ ValueObjectConstResult::ValueObjectConstResult(ExecutionContextScope *exe_scope, ByteOrder byte_order, uint32_t addr_byte_size, lldb::addr_t address) - : ValueObject(exe_scope, manager), m_type_name(), m_byte_size(0), - m_impl(this, address) { + : ValueObject(exe_scope, manager), m_impl(this, address) { SetIsConstant(); SetValueIsValid(true); m_data.SetByteOrder(byte_order); @@ -64,8 +63,7 @@ ValueObjectConstResult::ValueObjectConstResult( ExecutionContextScope *exe_scope, ValueObjectManager &manager, const CompilerType &compiler_type, ConstString name, const DataExtractor &data, lldb::addr_t address) - : ValueObject(exe_scope, manager), m_type_name(), m_byte_size(0), - m_impl(this, address) { + : ValueObject(exe_scope, manager), m_impl(this, address) { m_data = data; if (!m_data.GetSharedDataBuffer()) { @@ -75,7 +73,7 @@ ValueObjectConstResult::ValueObjectConstResult( } m_value.GetScalar() = (uintptr_t)m_data.GetDataStart(); - m_value.SetValueType(Value::eValueTypeHostAddress); + m_value.SetValueType(Value::ValueType::HostAddress); m_value.SetCompilerType(compiler_type); m_name = name; SetIsConstant(); @@ -112,13 +110,12 @@ ValueObjectConstResult::ValueObjectConstResult( const CompilerType &compiler_type, ConstString name, const lldb::DataBufferSP &data_sp, lldb::ByteOrder data_byte_order, uint32_t data_addr_size, lldb::addr_t address) - : ValueObject(exe_scope, manager), m_type_name(), m_byte_size(0), - m_impl(this, address) { + : ValueObject(exe_scope, manager), m_impl(this, address) { m_data.SetByteOrder(data_byte_order); m_data.SetAddressByteSize(data_addr_size); m_data.SetData(data_sp); m_value.GetScalar() = (uintptr_t)data_sp->GetBytes(); - m_value.SetValueType(Value::eValueTypeHostAddress); + m_value.SetValueType(Value::ValueType::HostAddress); m_value.SetCompilerType(compiler_type); m_name = name; SetIsConstant(); @@ -143,24 +140,24 @@ ValueObjectConstResult::ValueObjectConstResult( ExecutionContextScope *exe_scope, ValueObjectManager &manager, const CompilerType &compiler_type, ConstString name, lldb::addr_t address, AddressType address_type, uint32_t addr_byte_size) - : ValueObject(exe_scope, manager), m_type_name(), m_byte_size(0), + : ValueObject(exe_scope, manager), m_type_name(), m_impl(this, address) { m_value.GetScalar() = address; m_data.SetAddressByteSize(addr_byte_size); m_value.GetScalar().GetData(m_data, addr_byte_size); - // m_value.SetValueType(Value::eValueTypeHostAddress); + // m_value.SetValueType(Value::ValueType::HostAddress); switch (address_type) { case eAddressTypeInvalid: - m_value.SetValueType(Value::eValueTypeScalar); + m_value.SetValueType(Value::ValueType::Scalar); break; case eAddressTypeFile: - m_value.SetValueType(Value::eValueTypeFileAddress); + m_value.SetValueType(Value::ValueType::FileAddress); break; case eAddressTypeLoad: - m_value.SetValueType(Value::eValueTypeLoadAddress); + m_value.SetValueType(Value::ValueType::LoadAddress); break; case eAddressTypeHost: - m_value.SetValueType(Value::eValueTypeHostAddress); + m_value.SetValueType(Value::ValueType::HostAddress); break; } m_value.SetCompilerType(compiler_type); @@ -179,8 +176,7 @@ ValueObjectSP ValueObjectConstResult::Create(ExecutionContextScope *exe_scope, ValueObjectConstResult::ValueObjectConstResult(ExecutionContextScope *exe_scope, ValueObjectManager &manager, const Status &error) - : ValueObject(exe_scope, manager), m_type_name(), m_byte_size(0), - m_impl(this) { + : ValueObject(exe_scope, manager), m_impl(this) { m_error = error; SetIsConstant(); } @@ -189,8 +185,7 @@ ValueObjectConstResult::ValueObjectConstResult(ExecutionContextScope *exe_scope, ValueObjectManager &manager, const Value &value, ConstString name, Module *module) - : ValueObject(exe_scope, manager), m_type_name(), m_byte_size(0), - m_impl(this) { + : ValueObject(exe_scope, manager), m_impl(this) { m_value = value; m_name = name; ExecutionContext exe_ctx; @@ -198,7 +193,7 @@ ValueObjectConstResult::ValueObjectConstResult(ExecutionContextScope *exe_scope, m_error = m_value.GetValueAsData(&exe_ctx, m_data, module); } -ValueObjectConstResult::~ValueObjectConstResult() {} +ValueObjectConstResult::~ValueObjectConstResult() = default; CompilerType ValueObjectConstResult::GetCompilerTypeImpl() { return m_value.GetCompilerType(); @@ -208,9 +203,9 @@ lldb::ValueType ValueObjectConstResult::GetValueType() const { return eValueTypeConstResult; } -uint64_t ValueObjectConstResult::GetByteSize() { +llvm::Optional ValueObjectConstResult::GetByteSize() { ExecutionContext exe_ctx(GetExecutionContextRef()); - if (m_byte_size == 0) { + if (!m_byte_size) { if (auto size = GetCompilerType().GetByteSize(exe_ctx.GetBestExecutionContextScope())) SetByteSize(*size); diff --git a/gnu/llvm/lldb/source/Core/ValueObjectConstResultCast.cpp b/gnu/llvm/lldb/source/Core/ValueObjectConstResultCast.cpp index 53ec9db4554..e70d055ac57 100644 --- a/gnu/llvm/lldb/source/Core/ValueObjectConstResultCast.cpp +++ b/gnu/llvm/lldb/source/Core/ValueObjectConstResultCast.cpp @@ -27,7 +27,7 @@ ValueObjectConstResultCast::ValueObjectConstResultCast( m_name = name; } -ValueObjectConstResultCast::~ValueObjectConstResultCast() {} +ValueObjectConstResultCast::~ValueObjectConstResultCast() = default; lldb::ValueObjectSP ValueObjectConstResultCast::Dereference(Status &error) { return m_impl.Dereference(error); diff --git a/gnu/llvm/lldb/source/Core/ValueObjectConstResultChild.cpp b/gnu/llvm/lldb/source/Core/ValueObjectConstResultChild.cpp index 13c8393d808..0fd81410ae5 100644 --- a/gnu/llvm/lldb/source/Core/ValueObjectConstResultChild.cpp +++ b/gnu/llvm/lldb/source/Core/ValueObjectConstResultChild.cpp @@ -34,7 +34,7 @@ ValueObjectConstResultChild::ValueObjectConstResultChild( m_name = name; } -ValueObjectConstResultChild::~ValueObjectConstResultChild() {} +ValueObjectConstResultChild::~ValueObjectConstResultChild() = default; lldb::ValueObjectSP ValueObjectConstResultChild::Dereference(Status &error) { return m_impl.Dereference(error); diff --git a/gnu/llvm/lldb/source/Core/ValueObjectConstResultImpl.cpp b/gnu/llvm/lldb/source/Core/ValueObjectConstResultImpl.cpp index e4cbbec849e..980cea049f6 100644 --- a/gnu/llvm/lldb/source/Core/ValueObjectConstResultImpl.cpp +++ b/gnu/llvm/lldb/source/Core/ValueObjectConstResultImpl.cpp @@ -132,7 +132,7 @@ lldb::ValueObjectSP ValueObjectConstResultImpl::AddressOf(Status &error) { ConstString(new_name.c_str()), buffer, endian::InlHostByteOrder(), exe_ctx.GetAddressByteSize()); - m_address_of_backend->GetValue().SetValueType(Value::eValueTypeScalar); + m_address_of_backend->GetValue().SetValueType(Value::ValueType::Scalar); m_address_of_backend->GetValue().GetScalar() = m_live_address; return m_address_of_backend; diff --git a/gnu/llvm/lldb/source/Core/ValueObjectDynamicValue.cpp b/gnu/llvm/lldb/source/Core/ValueObjectDynamicValue.cpp index ca66740cb55..d7750949650 100644 --- a/gnu/llvm/lldb/source/Core/ValueObjectDynamicValue.cpp +++ b/gnu/llvm/lldb/source/Core/ValueObjectDynamicValue.cpp @@ -22,7 +22,7 @@ #include "lldb/Utility/Status.h" #include "lldb/lldb-types.h" -#include +#include namespace lldb_private { class Declaration; } @@ -98,7 +98,7 @@ size_t ValueObjectDynamicValue::CalculateNumChildren(uint32_t max) { return m_parent->GetNumChildren(max); } -uint64_t ValueObjectDynamicValue::GetByteSize() { +llvm::Optional ValueObjectDynamicValue::GetByteSize() { const bool success = UpdateValueIfNeeded(false); if (success && m_dynamic_type_info.HasType()) { ExecutionContext exe_ctx(GetExecutionContextRef()); diff --git a/gnu/llvm/lldb/source/Core/ValueObjectMemory.cpp b/gnu/llvm/lldb/source/Core/ValueObjectMemory.cpp index 91b2c608492..af039ee4040 100644 --- a/gnu/llvm/lldb/source/Core/ValueObjectMemory.cpp +++ b/gnu/llvm/lldb/source/Core/ValueObjectMemory.cpp @@ -18,7 +18,7 @@ #include "lldb/lldb-types.h" #include "llvm/Support/ErrorHandling.h" -#include +#include #include namespace lldb_private { @@ -57,20 +57,20 @@ ValueObjectMemory::ValueObjectMemory(ExecutionContextScope *exe_scope, // Do not attempt to construct one of these objects with no variable! assert(m_type_sp.get() != nullptr); SetName(ConstString(name)); - m_value.SetContext(Value::eContextTypeLLDBType, m_type_sp.get()); + m_value.SetContext(Value::ContextType::LLDBType, m_type_sp.get()); TargetSP target_sp(GetTargetSP()); lldb::addr_t load_address = m_address.GetLoadAddress(target_sp.get()); if (load_address != LLDB_INVALID_ADDRESS) { - m_value.SetValueType(Value::eValueTypeLoadAddress); + m_value.SetValueType(Value::ValueType::LoadAddress); m_value.GetScalar() = load_address; } else { lldb::addr_t file_address = m_address.GetFileAddress(); if (file_address != LLDB_INVALID_ADDRESS) { - m_value.SetValueType(Value::eValueTypeFileAddress); + m_value.SetValueType(Value::ValueType::FileAddress); m_value.GetScalar() = file_address; } else { m_value.GetScalar() = m_address.GetOffset(); - m_value.SetValueType(Value::eValueTypeScalar); + m_value.SetValueType(Value::ValueType::Scalar); } } } @@ -92,21 +92,21 @@ ValueObjectMemory::ValueObjectMemory(ExecutionContextScope *exe_scope, m_value.SetCompilerType(m_compiler_type); lldb::addr_t load_address = m_address.GetLoadAddress(target_sp.get()); if (load_address != LLDB_INVALID_ADDRESS) { - m_value.SetValueType(Value::eValueTypeLoadAddress); + m_value.SetValueType(Value::ValueType::LoadAddress); m_value.GetScalar() = load_address; } else { lldb::addr_t file_address = m_address.GetFileAddress(); if (file_address != LLDB_INVALID_ADDRESS) { - m_value.SetValueType(Value::eValueTypeFileAddress); + m_value.SetValueType(Value::ValueType::FileAddress); m_value.GetScalar() = file_address; } else { m_value.GetScalar() = m_address.GetOffset(); - m_value.SetValueType(Value::eValueTypeScalar); + m_value.SetValueType(Value::ValueType::Scalar); } } } -ValueObjectMemory::~ValueObjectMemory() {} +ValueObjectMemory::~ValueObjectMemory() = default; CompilerType ValueObjectMemory::GetCompilerTypeImpl() { if (m_type_sp) @@ -139,10 +139,11 @@ size_t ValueObjectMemory::CalculateNumChildren(uint32_t max) { return child_count <= max ? child_count : max; } -uint64_t ValueObjectMemory::GetByteSize() { +llvm::Optional ValueObjectMemory::GetByteSize() { + ExecutionContext exe_ctx(GetExecutionContextRef()); if (m_type_sp) - return m_type_sp->GetByteSize().getValueOr(0); - return m_compiler_type.GetByteSize(nullptr).getValueOr(0); + return m_type_sp->GetByteSize(exe_ctx.GetBestExecutionContextScope()); + return m_compiler_type.GetByteSize(exe_ctx.GetBestExecutionContextScope()); } lldb::ValueType ValueObjectMemory::GetValueType() const { @@ -167,18 +168,18 @@ bool ValueObjectMemory::UpdateValue() { Value::ValueType value_type = m_value.GetValueType(); switch (value_type) { - default: - llvm_unreachable("Unhandled expression result value kind..."); - - case Value::eValueTypeScalar: + case Value::ValueType::Invalid: + m_error.SetErrorString("Invalid value"); + return false; + case Value::ValueType::Scalar: // The variable value is in the Scalar value inside the m_value. We can // point our m_data right to it. m_error = m_value.GetValueAsData(&exe_ctx, m_data, GetModule().get()); break; - case Value::eValueTypeFileAddress: - case Value::eValueTypeLoadAddress: - case Value::eValueTypeHostAddress: + case Value::ValueType::FileAddress: + case Value::ValueType::LoadAddress: + case Value::ValueType::HostAddress: // The DWARF expression result was an address in the inferior process. If // this variable is an aggregate type, we just need the address as the // main value as all child variable objects will rely upon this location @@ -187,11 +188,11 @@ bool ValueObjectMemory::UpdateValue() { // sure this type has a value before we try and read it // If we have a file address, convert it to a load address if we can. - if (value_type == Value::eValueTypeFileAddress && + if (value_type == Value::ValueType::FileAddress && exe_ctx.GetProcessPtr()) { lldb::addr_t load_addr = m_address.GetLoadAddress(target); if (load_addr != LLDB_INVALID_ADDRESS) { - m_value.SetValueType(Value::eValueTypeLoadAddress); + m_value.SetValueType(Value::ValueType::LoadAddress); m_value.GetScalar() = load_addr; } } @@ -207,7 +208,7 @@ bool ValueObjectMemory::UpdateValue() { // extract read its value into m_data appropriately Value value(m_value); if (m_type_sp) - value.SetContext(Value::eContextTypeLLDBType, m_type_sp.get()); + value.SetContext(Value::ContextType::LLDBType, m_type_sp.get()); else { value.SetCompilerType(m_compiler_type); } diff --git a/gnu/llvm/lldb/source/Core/ValueObjectRegister.cpp b/gnu/llvm/lldb/source/Core/ValueObjectRegister.cpp index ec87c38fb36..089fd766708 100644 --- a/gnu/llvm/lldb/source/Core/ValueObjectRegister.cpp +++ b/gnu/llvm/lldb/source/Core/ValueObjectRegister.cpp @@ -25,7 +25,7 @@ #include "llvm/ADT/StringRef.h" -#include +#include #include namespace lldb_private { @@ -60,7 +60,7 @@ ValueObjectRegisterSet::ValueObjectRegisterSet(ExecutionContextScope *exe_scope, } } -ValueObjectRegisterSet::~ValueObjectRegisterSet() {} +ValueObjectRegisterSet::~ValueObjectRegisterSet() = default; CompilerType ValueObjectRegisterSet::GetCompilerTypeImpl() { return CompilerType(); @@ -81,7 +81,7 @@ size_t ValueObjectRegisterSet::CalculateNumChildren(uint32_t max) { return 0; } -uint64_t ValueObjectRegisterSet::GetByteSize() { return 0; } +llvm::Optional ValueObjectRegisterSet::GetByteSize() { return 0; } bool ValueObjectRegisterSet::UpdateValue() { m_error.Clear(); @@ -193,7 +193,7 @@ ValueObjectRegister::ValueObjectRegister(ExecutionContextScope *exe_scope, ConstructObject(reg_num); } -ValueObjectRegister::~ValueObjectRegister() {} +ValueObjectRegister::~ValueObjectRegister() = default; CompilerType ValueObjectRegister::GetCompilerTypeImpl() { if (!m_compiler_type.IsValid()) { @@ -229,7 +229,9 @@ size_t ValueObjectRegister::CalculateNumChildren(uint32_t max) { return children_count <= max ? children_count : max; } -uint64_t ValueObjectRegister::GetByteSize() { return m_reg_info.byte_size; } +llvm::Optional ValueObjectRegister::GetByteSize() { + return m_reg_info.byte_size; +} bool ValueObjectRegister::UpdateValue() { m_error.Clear(); @@ -247,9 +249,9 @@ bool ValueObjectRegister::UpdateValue() { Process *process = exe_ctx.GetProcessPtr(); if (process) m_data.SetAddressByteSize(process->GetAddressByteSize()); - m_value.SetContext(Value::eContextTypeRegisterInfo, + m_value.SetContext(Value::ContextType::RegisterInfo, (void *)&m_reg_info); - m_value.SetValueType(Value::eValueTypeHostAddress); + m_value.SetValueType(Value::ValueType::HostAddress); m_value.GetScalar() = (uintptr_t)m_data.GetDataStart(); SetValueIsValid(true); SetValueDidChange(!(m_old_reg_value == m_reg_value)); diff --git a/gnu/llvm/lldb/source/Core/ValueObjectSyntheticFilter.cpp b/gnu/llvm/lldb/source/Core/ValueObjectSyntheticFilter.cpp index 32d1e6ab836..aa55e396570 100644 --- a/gnu/llvm/lldb/source/Core/ValueObjectSyntheticFilter.cpp +++ b/gnu/llvm/lldb/source/Core/ValueObjectSyntheticFilter.cpp @@ -46,7 +46,7 @@ public: ValueObjectSynthetic::ValueObjectSynthetic(ValueObject &parent, lldb::SyntheticChildrenSP filter) - : ValueObject(parent), m_synth_sp(filter), m_children_byindex(), + : ValueObject(parent), m_synth_sp(std::move(filter)), m_children_byindex(), m_name_toindex(), m_synthetic_children_cache(), m_synthetic_children_count(UINT32_MAX), m_parent_type_name(parent.GetTypeName()), @@ -121,7 +121,9 @@ bool ValueObjectSynthetic::MightHaveChildren() { return (m_might_have_children != eLazyBoolNo); } -uint64_t ValueObjectSynthetic::GetByteSize() { return m_parent->GetByteSize(); } +llvm::Optional ValueObjectSynthetic::GetByteSize() { + return m_parent->GetByteSize(); +} lldb::ValueType ValueObjectSynthetic::GetValueType() const { return m_parent->GetValueType(); @@ -188,7 +190,7 @@ bool ValueObjectSynthetic::UpdateValue() { // children count for a synthetic VO that might indeed happen, so we need // to tell the upper echelons that they need to come back to us asking for // children - m_children_count_valid = false; + m_flags.m_children_count_valid = false; { std::lock_guard guard(m_child_mutex); m_synthetic_children_cache.clear(); diff --git a/gnu/llvm/lldb/source/Core/ValueObjectUpdater.cpp b/gnu/llvm/lldb/source/Core/ValueObjectUpdater.cpp new file mode 100644 index 00000000000..af7f976a6d2 --- /dev/null +++ b/gnu/llvm/lldb/source/Core/ValueObjectUpdater.cpp @@ -0,0 +1,56 @@ +//===-- ValueObjectUpdater.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 "lldb/Core/ValueObjectUpdater.h" + +using namespace lldb_private; + +ValueObjectUpdater::ValueObjectUpdater(lldb::ValueObjectSP in_valobj_sp) { + if (!in_valobj_sp) + return; + // If the user passes in a value object that is dynamic or synthetic, then + // water it down to the static type. + m_root_valobj_sp = in_valobj_sp->GetQualifiedRepresentationIfAvailable( + lldb::eNoDynamicValues, false); +} + +lldb::ValueObjectSP ValueObjectUpdater::GetSP() { + lldb::ProcessSP process_sp = GetProcessSP(); + if (!process_sp) + return lldb::ValueObjectSP(); + + const uint32_t current_stop_id = process_sp->GetLastNaturalStopID(); + if (current_stop_id == m_stop_id) + return m_user_valobj_sp; + + m_stop_id = current_stop_id; + + if (!m_root_valobj_sp) { + m_user_valobj_sp.reset(); + return m_root_valobj_sp; + } + + m_user_valobj_sp = m_root_valobj_sp; + + lldb::ValueObjectSP dynamic_sp = + m_user_valobj_sp->GetDynamicValue(lldb::eDynamicDontRunTarget); + if (dynamic_sp) + m_user_valobj_sp = dynamic_sp; + + lldb::ValueObjectSP synthetic_sp = m_user_valobj_sp->GetSyntheticValue(); + if (synthetic_sp) + m_user_valobj_sp = synthetic_sp; + + return m_user_valobj_sp; +} + +lldb::ProcessSP ValueObjectUpdater::GetProcessSP() const { + if (m_root_valobj_sp) + return m_root_valobj_sp->GetProcessSP(); + return lldb::ProcessSP(); +} diff --git a/gnu/llvm/lldb/source/Core/ValueObjectVariable.cpp b/gnu/llvm/lldb/source/Core/ValueObjectVariable.cpp index 0d1e7b047a0..8e89503a8a7 100644 --- a/gnu/llvm/lldb/source/Core/ValueObjectVariable.cpp +++ b/gnu/llvm/lldb/source/Core/ValueObjectVariable.cpp @@ -10,10 +10,10 @@ #include "lldb/Core/Address.h" #include "lldb/Core/AddressRange.h" +#include "lldb/Core/Declaration.h" #include "lldb/Core/Module.h" #include "lldb/Core/Value.h" #include "lldb/Expression/DWARFExpression.h" -#include "lldb/Symbol/Declaration.h" #include "lldb/Symbol/Function.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Symbol/SymbolContext.h" @@ -33,7 +33,7 @@ #include "llvm/ADT/StringRef.h" -#include +#include #include namespace lldb_private { @@ -63,7 +63,7 @@ ValueObjectVariable::ValueObjectVariable(ExecutionContextScope *exe_scope, m_name = var_sp->GetName(); } -ValueObjectVariable::~ValueObjectVariable() {} +ValueObjectVariable::~ValueObjectVariable() = default; CompilerType ValueObjectVariable::GetCompilerTypeImpl() { Type *var_type = m_variable_sp->GetType(); @@ -105,15 +105,15 @@ size_t ValueObjectVariable::CalculateNumChildren(uint32_t max) { return child_count <= max ? child_count : max; } -uint64_t ValueObjectVariable::GetByteSize() { +llvm::Optional ValueObjectVariable::GetByteSize() { ExecutionContext exe_ctx(GetExecutionContextRef()); CompilerType type(GetCompilerType()); if (!type.IsValid()) - return 0; + return {}; - return type.GetByteSize(exe_ctx.GetBestExecutionContextScope()).getValueOr(0); + return type.GetByteSize(exe_ctx.GetBestExecutionContextScope()); } lldb::ValueType ValueObjectVariable::GetValueType() const { @@ -132,12 +132,15 @@ bool ValueObjectVariable::UpdateValue() { if (variable->GetLocationIsConstantValueData()) { // expr doesn't contain DWARF bytes, it contains the constant variable // value bytes themselves... - if (expr.GetExpressionData(m_data)) - m_value.SetContext(Value::eContextTypeVariable, variable); + if (expr.GetExpressionData(m_data)) { + if (m_data.GetDataStart() && m_data.GetByteSize()) + m_value.SetBytes(m_data.GetDataStart(), m_data.GetByteSize()); + m_value.SetContext(Value::ContextType::Variable, variable); + } else m_error.SetErrorString("empty constant data"); // constant bytes can't be edited - sorry - m_resolved_value.SetContext(Value::eContextTypeInvalid, nullptr); + m_resolved_value.SetContext(Value::ContextType::Invalid, nullptr); } else { lldb::addr_t loclist_base_load_addr = LLDB_INVALID_ADDRESS; ExecutionContext exe_ctx(GetExecutionContextRef()); @@ -160,7 +163,7 @@ bool ValueObjectVariable::UpdateValue() { if (expr.Evaluate(&exe_ctx, nullptr, loclist_base_load_addr, nullptr, nullptr, m_value, &m_error)) { m_resolved_value = m_value; - m_value.SetContext(Value::eContextTypeVariable, variable); + m_value.SetContext(Value::ContextType::Variable, variable); CompilerType compiler_type = GetCompilerType(); if (compiler_type.IsValid()) @@ -180,7 +183,7 @@ bool ValueObjectVariable::UpdateValue() { // // FIXME: When we grow m_value, we should represent the added bits as // undefined somehow instead of as 0's. - if (value_type == Value::eValueTypeHostAddress && + if (value_type == Value::ValueType::HostAddress && compiler_type.IsValid()) { if (size_t value_buf_size = m_value.GetBuffer().GetByteSize()) { size_t value_size = m_value.GetValueByteSize(&m_error, &exe_ctx); @@ -193,18 +196,19 @@ bool ValueObjectVariable::UpdateValue() { const bool process_is_alive = process && process->IsAlive(); switch (value_type) { - case Value::eValueTypeVector: - // fall through - case Value::eValueTypeScalar: + case Value::ValueType::Invalid: + m_error.SetErrorString("invalid value"); + break; + case Value::ValueType::Scalar: // The variable value is in the Scalar value inside the m_value. We can // point our m_data right to it. m_error = m_value.GetValueAsData(&exe_ctx, m_data, GetModule().get()); break; - case Value::eValueTypeFileAddress: - case Value::eValueTypeLoadAddress: - case Value::eValueTypeHostAddress: + case Value::ValueType::FileAddress: + case Value::ValueType::LoadAddress: + case Value::ValueType::HostAddress: // The DWARF expression result was an address in the inferior process. // If this variable is an aggregate type, we just need the address as // the main value as all child variable objects will rely upon this @@ -213,7 +217,7 @@ bool ValueObjectVariable::UpdateValue() { // m_data. Make sure this type has a value before we try and read it // If we have a file address, convert it to a load address if we can. - if (value_type == Value::eValueTypeFileAddress && process_is_alive) + if (value_type == Value::ValueType::FileAddress && process_is_alive) m_value.ConvertToLoadAddress(GetModule().get(), target); if (!CanProvideValue()) { @@ -226,7 +230,7 @@ bool ValueObjectVariable::UpdateValue() { // Copy the Value and set the context to use our Variable so it can // extract read its value into m_data appropriately Value value(m_value); - value.SetContext(Value::eContextTypeVariable, variable); + value.SetContext(Value::ContextType::Variable, variable); m_error = value.GetValueAsData(&exe_ctx, m_data, GetModule().get()); @@ -239,7 +243,7 @@ bool ValueObjectVariable::UpdateValue() { SetValueIsValid(m_error.Success()); } else { // could not find location, won't allow editing - m_resolved_value.SetContext(Value::eContextTypeInvalid, nullptr); + m_resolved_value.SetContext(Value::ContextType::Invalid, nullptr); } } @@ -256,7 +260,9 @@ void ValueObjectVariable::DoUpdateChildrenAddressType(ValueObject &valobj) { (type_info & (lldb::eTypeIsPointer | lldb::eTypeIsReference)) != 0; switch (value_type) { - case Value::eValueTypeFileAddress: + case Value::ValueType::Invalid: + break; + case Value::ValueType::FileAddress: // If this type is a pointer, then its children will be considered load // addresses if the pointer or reference is dereferenced, but only if // the process is alive. @@ -279,7 +285,7 @@ void ValueObjectVariable::DoUpdateChildrenAddressType(ValueObject &valobj) { else valobj.SetAddressTypeOfChildren(eAddressTypeFile); break; - case Value::eValueTypeHostAddress: + case Value::ValueType::HostAddress: // Same as above for load addresses, except children of pointer or refs // are always load addresses. Host addresses are used to store freeze // dried variables. If this type is a struct, the entire struct @@ -290,9 +296,8 @@ void ValueObjectVariable::DoUpdateChildrenAddressType(ValueObject &valobj) { else valobj.SetAddressTypeOfChildren(eAddressTypeHost); break; - case Value::eValueTypeLoadAddress: - case Value::eValueTypeScalar: - case Value::eValueTypeVector: + case Value::ValueType::LoadAddress: + case Value::ValueType::Scalar: valobj.SetAddressTypeOfChildren(eAddressTypeLoad); break; } @@ -343,7 +348,7 @@ bool ValueObjectVariable::GetDeclaration(Declaration &decl) { } const char *ValueObjectVariable::GetLocationAsCString() { - if (m_resolved_value.GetContextType() == Value::eContextTypeRegisterInfo) + if (m_resolved_value.GetContextType() == Value::ContextType::RegisterInfo) return GetLocationAsCStringImpl(m_resolved_value, m_data); else return ValueObject::GetLocationAsCString(); @@ -356,7 +361,7 @@ bool ValueObjectVariable::SetValueFromCString(const char *value_str, return false; } - if (m_resolved_value.GetContextType() == Value::eContextTypeRegisterInfo) { + if (m_resolved_value.GetContextType() == Value::ContextType::RegisterInfo) { RegisterInfo *reg_info = m_resolved_value.GetRegisterInfo(); ExecutionContext exe_ctx(GetExecutionContextRef()); RegisterContext *reg_ctx = exe_ctx.GetRegisterContext(); @@ -385,7 +390,7 @@ bool ValueObjectVariable::SetData(DataExtractor &data, Status &error) { return false; } - if (m_resolved_value.GetContextType() == Value::eContextTypeRegisterInfo) { + if (m_resolved_value.GetContextType() == Value::ContextType::RegisterInfo) { RegisterInfo *reg_info = m_resolved_value.GetRegisterInfo(); ExecutionContext exe_ctx(GetExecutionContextRef()); RegisterContext *reg_ctx = exe_ctx.GetRegisterContext(); diff --git a/gnu/llvm/lldb/source/DataFormatters/DataVisualization.cpp b/gnu/llvm/lldb/source/DataFormatters/DataVisualization.cpp index 450a5cbc3ef..ded8bbd9039 100644 --- a/gnu/llvm/lldb/source/DataFormatters/DataVisualization.cpp +++ b/gnu/llvm/lldb/source/DataFormatters/DataVisualization.cpp @@ -169,13 +169,12 @@ DataVisualization::Categories::GetCategoryAtIndex(size_t index) { bool DataVisualization::NamedSummaryFormats::GetSummaryFormat( ConstString type, lldb::TypeSummaryImplSP &entry) { - return GetFormatManager().GetNamedSummaryContainer().Get(type, entry); + return GetFormatManager().GetNamedSummaryContainer().GetExact(type, entry); } void DataVisualization::NamedSummaryFormats::Add( ConstString type, const lldb::TypeSummaryImplSP &entry) { - GetFormatManager().GetNamedSummaryContainer().Add( - FormatManager::GetValidTypeName(type), entry); + GetFormatManager().GetNamedSummaryContainer().Add(type, entry); } bool DataVisualization::NamedSummaryFormats::Delete(ConstString type) { @@ -187,7 +186,7 @@ void DataVisualization::NamedSummaryFormats::Clear() { } void DataVisualization::NamedSummaryFormats::ForEach( - std::function + std::function callback) { GetFormatManager().GetNamedSummaryContainer().ForEach(callback); } diff --git a/gnu/llvm/lldb/source/DataFormatters/FormatManager.cpp b/gnu/llvm/lldb/source/DataFormatters/FormatManager.cpp index ad02d37360b..6c824d1f772 100644 --- a/gnu/llvm/lldb/source/DataFormatters/FormatManager.cpp +++ b/gnu/llvm/lldb/source/DataFormatters/FormatManager.cpp @@ -237,7 +237,9 @@ void FormatManager::GetPossibleMatches( // stripped. uint64_t array_size; if (compiler_type.IsArrayType(nullptr, &array_size, nullptr)) { - CompilerType element_type = compiler_type.GetArrayElementType(); + ExecutionContext exe_ctx(valobj.GetExecutionContextRef()); + CompilerType element_type = compiler_type.GetArrayElementType( + exe_ctx.GetBestExecutionContextScope()); if (element_type.IsTypedefType()) { // Get the stripped element type and compute the stripped array type // from it. @@ -551,10 +553,6 @@ bool FormatManager::ShouldPrintAsOneLiner(ValueObject &valobj) { return true; } -ConstString FormatManager::GetValidTypeName(ConstString type) { - return ::GetValidTypeName_Impl(type); -} - ConstString FormatManager::GetTypeForCache(ValueObject &valobj, lldb::DynamicValueType use_dynamic) { ValueObjectSP valobj_sp = valobj.GetQualifiedRepresentationIfAvailable( diff --git a/gnu/llvm/lldb/source/DataFormatters/StringPrinter.cpp b/gnu/llvm/lldb/source/DataFormatters/StringPrinter.cpp index 139f1ec0554..0c6438f7dd8 100644 --- a/gnu/llvm/lldb/source/DataFormatters/StringPrinter.cpp +++ b/gnu/llvm/lldb/source/DataFormatters/StringPrinter.cpp @@ -18,7 +18,7 @@ #include "llvm/ADT/StringExtras.h" #include "llvm/Support/ConvertUTF.h" -#include +#include #include #include diff --git a/gnu/llvm/lldb/source/DataFormatters/TypeCategory.cpp b/gnu/llvm/lldb/source/DataFormatters/TypeCategory.cpp index 8368c91a57f..f1c6210edd1 100644 --- a/gnu/llvm/lldb/source/DataFormatters/TypeCategory.cpp +++ b/gnu/llvm/lldb/source/DataFormatters/TypeCategory.cpp @@ -15,11 +15,9 @@ using namespace lldb_private; TypeCategoryImpl::TypeCategoryImpl(IFormatChangeListener *clist, ConstString name) - : m_format_cont("format", "regex-format", clist), - m_summary_cont("summary", "regex-summary", clist), - m_filter_cont("filter", "regex-filter", clist), - m_synth_cont("synth", "regex-synth", clist), m_enabled(false), - m_change_listener(clist), m_mutex(), m_name(name), m_languages() {} + : m_format_cont(clist), m_summary_cont(clist), m_filter_cont(clist), + m_synth_cont(clist), m_enabled(false), m_change_listener(clist), + m_mutex(), m_name(name), m_languages() {} static bool IsApplicable(lldb::LanguageType category_lang, lldb::LanguageType valobj_lang) { diff --git a/gnu/llvm/lldb/source/DataFormatters/TypeFormat.cpp b/gnu/llvm/lldb/source/DataFormatters/TypeFormat.cpp index b9a9447c5f3..9c504668701 100644 --- a/gnu/llvm/lldb/source/DataFormatters/TypeFormat.cpp +++ b/gnu/llvm/lldb/source/DataFormatters/TypeFormat.cpp @@ -27,16 +27,15 @@ using namespace lldb; using namespace lldb_private; -TypeFormatImpl::TypeFormatImpl(const Flags &flags) - : m_flags(flags), m_my_revision(0) {} +TypeFormatImpl::TypeFormatImpl(const Flags &flags) : m_flags(flags) {} -TypeFormatImpl::~TypeFormatImpl() {} +TypeFormatImpl::~TypeFormatImpl() = default; TypeFormatImpl_Format::TypeFormatImpl_Format(lldb::Format f, const TypeFormatImpl::Flags &flags) : TypeFormatImpl(flags), m_format(f) {} -TypeFormatImpl_Format::~TypeFormatImpl_Format() {} +TypeFormatImpl_Format::~TypeFormatImpl_Format() = default; bool TypeFormatImpl_Format::FormatObject(ValueObject *valobj, std::string &dest) const { @@ -48,7 +47,7 @@ bool TypeFormatImpl_Format::FormatObject(ValueObject *valobj, ExecutionContext exe_ctx(valobj->GetExecutionContextRef()); DataExtractor data; - if (context_type == Value::eContextTypeRegisterInfo) { + if (context_type == Value::ContextType::RegisterInfo) { const RegisterInfo *reg_info = value.GetRegisterInfo(); if (reg_info) { Status error; @@ -135,7 +134,7 @@ TypeFormatImpl_EnumType::TypeFormatImpl_EnumType( ConstString type_name, const TypeFormatImpl::Flags &flags) : TypeFormatImpl(flags), m_enum_type(type_name), m_types() {} -TypeFormatImpl_EnumType::~TypeFormatImpl_EnumType() {} +TypeFormatImpl_EnumType::~TypeFormatImpl_EnumType() = default; bool TypeFormatImpl_EnumType::FormatObject(ValueObject *valobj, std::string &dest) const { diff --git a/gnu/llvm/lldb/source/DataFormatters/TypeSummary.cpp b/gnu/llvm/lldb/source/DataFormatters/TypeSummary.cpp index 5d4fe2e467f..c09ed31d033 100644 --- a/gnu/llvm/lldb/source/DataFormatters/TypeSummary.cpp +++ b/gnu/llvm/lldb/source/DataFormatters/TypeSummary.cpp @@ -26,8 +26,7 @@ using namespace lldb; using namespace lldb_private; -TypeSummaryOptions::TypeSummaryOptions() - : m_lang(eLanguageTypeUnknown), m_capping(eTypeSummaryCapped) {} +TypeSummaryOptions::TypeSummaryOptions() = default; lldb::LanguageType TypeSummaryOptions::GetLanguage() const { return m_lang; } diff --git a/gnu/llvm/lldb/source/DataFormatters/TypeSynthetic.cpp b/gnu/llvm/lldb/source/DataFormatters/TypeSynthetic.cpp index 75388a93cc6..2cca5d65f47 100644 --- a/gnu/llvm/lldb/source/DataFormatters/TypeSynthetic.cpp +++ b/gnu/llvm/lldb/source/DataFormatters/TypeSynthetic.cpp @@ -128,7 +128,7 @@ ScriptedSyntheticChildren::FrontEnd::FrontEnd(std::string pclass, ValueObject &backend) : SyntheticChildrenFrontEnd(backend), m_python_class(pclass), m_wrapper_sp(), m_interpreter(nullptr) { - if (backend == LLDB_INVALID_UID) + if (backend.GetID() == LLDB_INVALID_UID) return; TargetSP target_sp = backend.GetTargetSP(); @@ -143,7 +143,7 @@ ScriptedSyntheticChildren::FrontEnd::FrontEnd(std::string pclass, m_python_class.c_str(), backend.GetSP()); } -ScriptedSyntheticChildren::FrontEnd::~FrontEnd() {} +ScriptedSyntheticChildren::FrontEnd::~FrontEnd() = default; lldb::ValueObjectSP ScriptedSyntheticChildren::FrontEnd::GetChildAtIndex(size_t idx) { diff --git a/gnu/llvm/lldb/source/DataFormatters/ValueObjectPrinter.cpp b/gnu/llvm/lldb/source/DataFormatters/ValueObjectPrinter.cpp index c8a306334cf..082ad344d2d 100644 --- a/gnu/llvm/lldb/source/DataFormatters/ValueObjectPrinter.cpp +++ b/gnu/llvm/lldb/source/DataFormatters/ValueObjectPrinter.cpp @@ -355,22 +355,33 @@ void ValueObjectPrinter::GetValueSummaryError(std::string &value, if (err_cstr) error.assign(err_cstr); - if (ShouldPrintValueObject()) { - if (IsNil()) - summary.assign("nil"); - else if (IsUninitialized()) - summary.assign(""); - else if (m_options.m_omit_summary_depth == 0) { - TypeSummaryImpl *entry = GetSummaryFormatter(); - if (entry) - m_valobj->GetSummaryAsCString(entry, summary, - m_options.m_varformat_language); - else { - const char *sum_cstr = - m_valobj->GetSummaryAsCString(m_options.m_varformat_language); - if (sum_cstr) - summary.assign(sum_cstr); - } + if (!ShouldPrintValueObject()) + return; + + if (IsNil()) { + lldb::LanguageType lang_type = + (m_options.m_varformat_language == lldb::eLanguageTypeUnknown) + ? m_valobj->GetPreferredDisplayLanguage() + : m_options.m_varformat_language; + if (Language *lang_plugin = Language::FindPlugin(lang_type)) { + summary.assign(lang_plugin->GetNilReferenceSummaryString().str()); + } else { + // We treat C as the fallback language rather than as a separate Language + // plugin. + summary.assign("NULL"); + } + } else if (IsUninitialized()) { + summary.assign(""); + } else if (m_options.m_omit_summary_depth == 0) { + TypeSummaryImpl *entry = GetSummaryFormatter(); + if (entry) { + m_valobj->GetSummaryAsCString(entry, summary, + m_options.m_varformat_language); + } else { + const char *sum_cstr = + m_valobj->GetSummaryAsCString(m_options.m_varformat_language); + if (sum_cstr) + summary.assign(sum_cstr); } } } @@ -403,7 +414,9 @@ bool ValueObjectPrinter::PrintValueAndSummaryIfNeeded(bool &value_printed, // this thing is nil (but show the value if the user passes a format // explicitly) TypeSummaryImpl *entry = GetSummaryFormatter(); - if (!IsNil() && !IsUninitialized() && !m_value.empty() && + const bool has_nil_or_uninitialized_summary = + (IsNil() || IsUninitialized()) && !m_summary.empty(); + if (!has_nil_or_uninitialized_summary && !m_value.empty() && (entry == nullptr || (entry->DoesPrintValue(m_valobj) || m_options.m_format != eFormatDefault) || diff --git a/gnu/llvm/lldb/source/DataFormatters/VectorType.cpp b/gnu/llvm/lldb/source/DataFormatters/VectorType.cpp index fd1c0bc96cd..11371918830 100644 --- a/gnu/llvm/lldb/source/DataFormatters/VectorType.cpp +++ b/gnu/llvm/lldb/source/DataFormatters/VectorType.cpp @@ -219,21 +219,9 @@ public: m_parent_format = m_backend.GetFormat(); CompilerType parent_type(m_backend.GetCompilerType()); CompilerType element_type; - parent_type.IsVectorType(&element_type, nullptr); - TypeSystem *type_system = nullptr; - if (auto target_sp = m_backend.GetTargetSP()) { - auto type_system_or_err = - target_sp->GetScratchTypeSystemForLanguage(lldb::eLanguageTypeC); - if (auto err = type_system_or_err.takeError()) { - LLDB_LOG_ERROR( - lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DATAFORMATTERS), - std::move(err), "Unable to update from scratch TypeSystem"); - } else { - type_system = &type_system_or_err.get(); - } - } - m_child_type = - ::GetCompilerTypeForFormat(m_parent_format, element_type, type_system); + parent_type.IsVectorType(&element_type); + m_child_type = ::GetCompilerTypeForFormat(m_parent_format, element_type, + parent_type.GetTypeSystem()); m_num_children = ::CalculateNumChildren(parent_type, m_child_type); m_item_format = GetItemFormatForFormat(m_parent_format, m_child_type); return false; diff --git a/gnu/llvm/lldb/source/Expression/CMakeLists.txt b/gnu/llvm/lldb/source/Expression/CMakeLists.txt index 7e2f19ed5b0..bf94361dd6c 100644 --- a/gnu/llvm/lldb/source/Expression/CMakeLists.txt +++ b/gnu/llvm/lldb/source/Expression/CMakeLists.txt @@ -1,7 +1,3 @@ -if(NOT LLDB_BUILT_STANDALONE) - set(tablegen_deps intrinsics_gen) -endif() - add_lldb_library(lldbExpression DiagnosticManager.cpp DWARFExpression.cpp @@ -18,7 +14,7 @@ add_lldb_library(lldbExpression UtilityFunction.cpp DEPENDS - ${tablegen_deps} + intrinsics_gen LINK_LIBS lldbCore diff --git a/gnu/llvm/lldb/source/Expression/DWARFExpression.cpp b/gnu/llvm/lldb/source/Expression/DWARFExpression.cpp index 6050c192256..a10546c1dea 100644 --- a/gnu/llvm/lldb/source/Expression/DWARFExpression.cpp +++ b/gnu/llvm/lldb/source/Expression/DWARFExpression.cpp @@ -8,7 +8,7 @@ #include "lldb/Expression/DWARFExpression.h" -#include +#include #include @@ -55,9 +55,7 @@ ReadAddressFromDebugAddrSection(const DWARFUnit *dwarf_cu, } // DWARFExpression constructor -DWARFExpression::DWARFExpression() - : m_module_wp(), m_data(), m_dwarf_cu(nullptr), - m_reg_kind(eRegisterKindDWARF) {} +DWARFExpression::DWARFExpression() : m_module_wp(), m_data() {} DWARFExpression::DWARFExpression(lldb::ModuleSP module_sp, const DataExtractor &data, @@ -69,7 +67,7 @@ DWARFExpression::DWARFExpression(lldb::ModuleSP module_sp, } // Destructor -DWARFExpression::~DWARFExpression() {} +DWARFExpression::~DWARFExpression() = default; bool DWARFExpression::IsValid() const { return m_data.GetByteSize() > 0; } @@ -89,8 +87,8 @@ void DWARFExpression::DumpLocation(Stream *s, const DataExtractor &data, lldb::DescriptionLevel level, ABI *abi) const { llvm::DWARFExpression(data.GetAsLLVM(), data.GetAddressByteSize()) - .print(s->AsRawOstream(), abi ? &abi->GetMCRegisterInfo() : nullptr, - nullptr); + .print(s->AsRawOstream(), llvm::DIDumpOptions(), + abi ? &abi->GetMCRegisterInfo() : nullptr, nullptr); } void DWARFExpression::SetLocationListAddresses(addr_t cu_file_addr, @@ -158,7 +156,7 @@ static bool ReadRegisterValueAsScalar(RegisterContext *reg_ctx, Value &value) { if (reg_ctx == nullptr) { if (error_ptr) - error_ptr->SetErrorStringWithFormat("No register context in frame.\n"); + error_ptr->SetErrorString("No register context in frame.\n"); } else { uint32_t native_reg = reg_ctx->ConvertRegisterKindToRegisterNumber(reg_kind, reg_num); @@ -174,8 +172,8 @@ static bool ReadRegisterValueAsScalar(RegisterContext *reg_ctx, RegisterValue reg_value; if (reg_ctx->ReadRegister(reg_info, reg_value)) { if (reg_value.GetScalarValue(value.GetScalar())) { - value.SetValueType(Value::eValueTypeScalar); - value.SetContext(Value::eContextTypeRegisterInfo, + value.SetValueType(Value::ValueType::Scalar); + value.SetContext(Value::ContextType::RegisterInfo, const_cast(reg_info)); if (error_ptr) error_ptr->Clear(); @@ -904,6 +902,52 @@ bool DWARFExpression::Evaluate(ExecutionContext *exe_ctx, object_address_ptr, result, error_ptr); } +namespace { +/// The location description kinds described by the DWARF v5 +/// specification. Composite locations are handled out-of-band and +/// thus aren't part of the enum. +enum LocationDescriptionKind { + Empty, + Memory, + Register, + Implicit + /* Composite*/ +}; +/// Adjust value's ValueType according to the kind of location description. +void UpdateValueTypeFromLocationDescription(Log *log, const DWARFUnit *dwarf_cu, + LocationDescriptionKind kind, + Value *value = nullptr) { + // Note that this function is conflating DWARF expressions with + // DWARF location descriptions. Perhaps it would be better to define + // a wrapper for DWARFExpresssion::Eval() that deals with DWARF + // location descriptions (which consist of one or more DWARF + // expressions). But doing this would mean we'd also need factor the + // handling of DW_OP_(bit_)piece out of this function. + if (dwarf_cu && dwarf_cu->GetVersion() >= 4) { + const char *log_msg = "DWARF location description kind: %s"; + switch (kind) { + case Empty: + LLDB_LOGF(log, log_msg, "Empty"); + break; + case Memory: + LLDB_LOGF(log, log_msg, "Memory"); + if (value->GetValueType() == Value::ValueType::Scalar) + value->SetValueType(Value::ValueType::LoadAddress); + break; + case Register: + LLDB_LOGF(log, log_msg, "Register"); + value->SetValueType(Value::ValueType::Scalar); + break; + case Implicit: + LLDB_LOGF(log, log_msg, "Implicit"); + if (value->GetValueType() == Value::ValueType::LoadAddress) + value->SetValueType(Value::ValueType::Scalar); + break; + } + } +} +} // namespace + bool DWARFExpression::Evaluate( ExecutionContext *exe_ctx, RegisterContext *reg_ctx, lldb::ModuleSP module_sp, const DataExtractor &opcodes, @@ -941,6 +985,21 @@ bool DWARFExpression::Evaluate( Value pieces; // Used for DW_OP_piece Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); + // A generic type is "an integral type that has the size of an address and an + // unspecified signedness". For now, just use the signedness of the operand. + // TODO: Implement a real typed stack, and store the genericness of the value + // there. + auto to_generic = [&](auto v) { + bool is_signed = std::is_signed::value; + return Scalar(llvm::APSInt( + llvm::APInt(8 * opcodes.GetAddressByteSize(), v, is_signed), + !is_signed)); + }; + + // The default kind is a memory location. This is updated by any + // operation that changes this, such as DW_OP_stack_value, and reset + // by composition operations like DW_OP_piece. + LocationDescriptionKind dwarf4_location_description_kind = Memory; while (opcodes.ValidOffset(offset)) { const lldb::offset_t op_offset = offset; @@ -965,7 +1024,7 @@ bool DWARFExpression::Evaluate( // address and whose size is the size of an address on the target machine. case DW_OP_addr: stack.push_back(Scalar(opcodes.GetAddress(&offset))); - stack.back().SetValueType(Value::eValueTypeFileAddress); + stack.back().SetValueType(Value::ValueType::FileAddress); // Convert the file address to a load address, so subsequent // DWARF operators can operate on it. if (frame) @@ -1024,41 +1083,43 @@ bool DWARFExpression::Evaluate( } Value::ValueType value_type = stack.back().GetValueType(); switch (value_type) { - case Value::eValueTypeHostAddress: { + case Value::ValueType::HostAddress: { void *src = (void *)stack.back().GetScalar().ULongLong(); intptr_t ptr; ::memcpy(&ptr, src, sizeof(void *)); stack.back().GetScalar() = ptr; stack.back().ClearContext(); } break; - case Value::eValueTypeFileAddress: { + case Value::ValueType::FileAddress: { auto file_addr = stack.back().GetScalar().ULongLong( LLDB_INVALID_ADDRESS); if (!module_sp) { if (error_ptr) - error_ptr->SetErrorStringWithFormat( + error_ptr->SetErrorString( "need module to resolve file address for DW_OP_deref"); return false; } Address so_addr; if (!module_sp->ResolveFileAddress(file_addr, so_addr)) { if (error_ptr) - error_ptr->SetErrorStringWithFormat( + error_ptr->SetErrorString( "failed to resolve file address in module"); return false; } addr_t load_Addr = so_addr.GetLoadAddress(exe_ctx->GetTargetPtr()); if (load_Addr == LLDB_INVALID_ADDRESS) { if (error_ptr) - error_ptr->SetErrorStringWithFormat( - "failed to resolve load address"); + error_ptr->SetErrorString("failed to resolve load address"); return false; } stack.back().GetScalar() = load_Addr; - stack.back().SetValueType(Value::eValueTypeLoadAddress); - // Fall through to load address code below... + // Fall through to load address promotion code below. } LLVM_FALLTHROUGH; - case Value::eValueTypeLoadAddress: + case Value::ValueType::Scalar: + // Promote Scalar to LoadAddress and fall through. + stack.back().SetValueType(Value::ValueType::LoadAddress); + LLVM_FALLTHROUGH; + case Value::ValueType::LoadAddress: if (exe_ctx) { if (process) { lldb::addr_t pointer_addr = @@ -1067,6 +1128,8 @@ bool DWARFExpression::Evaluate( lldb::addr_t pointer_value = process->ReadPointerFromMemory(pointer_addr, error); if (pointer_value != LLDB_INVALID_ADDRESS) { + if (ABISP abi_sp = process->GetABI()) + pointer_value = abi_sp->FixCodeAddress(pointer_value); stack.back().GetScalar() = pointer_value; stack.back().ClearContext(); } else { @@ -1079,20 +1142,21 @@ bool DWARFExpression::Evaluate( } } else { if (error_ptr) - error_ptr->SetErrorStringWithFormat( - "NULL process for DW_OP_deref.\n"); + error_ptr->SetErrorString("NULL process for DW_OP_deref.\n"); return false; } } else { if (error_ptr) - error_ptr->SetErrorStringWithFormat( + error_ptr->SetErrorString( "NULL execution context for DW_OP_deref.\n"); return false; } break; - default: - break; + case Value::ValueType::Invalid: + if (error_ptr) + error_ptr->SetErrorString("Invalid value type for DW_OP_deref.\n"); + return false; } } break; @@ -1119,7 +1183,7 @@ bool DWARFExpression::Evaluate( uint8_t size = opcodes.GetU8(&offset); Value::ValueType value_type = stack.back().GetValueType(); switch (value_type) { - case Value::eValueTypeHostAddress: { + case Value::ValueType::HostAddress: { void *src = (void *)stack.back().GetScalar().ULongLong(); intptr_t ptr; ::memcpy(&ptr, src, sizeof(void *)); @@ -1159,7 +1223,8 @@ bool DWARFExpression::Evaluate( stack.back().GetScalar() = ptr; stack.back().ClearContext(); } break; - case Value::eValueTypeLoadAddress: + case Value::ValueType::Scalar: + case Value::ValueType::LoadAddress: if (exe_ctx) { if (process) { lldb::addr_t pointer_addr = @@ -1199,20 +1264,22 @@ bool DWARFExpression::Evaluate( } } else { if (error_ptr) - error_ptr->SetErrorStringWithFormat( - "NULL process for DW_OP_deref.\n"); + error_ptr->SetErrorString("NULL process for DW_OP_deref_size.\n"); return false; } } else { if (error_ptr) - error_ptr->SetErrorStringWithFormat( - "NULL execution context for DW_OP_deref.\n"); + error_ptr->SetErrorString( + "NULL execution context for DW_OP_deref_size.\n"); return false; } break; - default: - break; + case Value::ValueType::FileAddress: + case Value::ValueType::Invalid: + if (error_ptr) + error_ptr->SetErrorString("Invalid value for DW_OP_deref_size.\n"); + return false; } } break; @@ -1254,37 +1321,42 @@ bool DWARFExpression::Evaluate( // All DW_OP_constXXX opcodes have a single operand as noted below: // // Opcode Operand 1 - // DW_OP_const1u 1-byte unsigned integer constant DW_OP_const1s - // 1-byte signed integer constant DW_OP_const2u 2-byte unsigned integer - // constant DW_OP_const2s 2-byte signed integer constant DW_OP_const4u - // 4-byte unsigned integer constant DW_OP_const4s 4-byte signed integer - // constant DW_OP_const8u 8-byte unsigned integer constant DW_OP_const8s - // 8-byte signed integer constant DW_OP_constu unsigned LEB128 integer - // constant DW_OP_consts signed LEB128 integer constant + // DW_OP_const1u 1-byte unsigned integer constant + // DW_OP_const1s 1-byte signed integer constant + // DW_OP_const2u 2-byte unsigned integer constant + // DW_OP_const2s 2-byte signed integer constant + // DW_OP_const4u 4-byte unsigned integer constant + // DW_OP_const4s 4-byte signed integer constant + // DW_OP_const8u 8-byte unsigned integer constant + // DW_OP_const8s 8-byte signed integer constant + // DW_OP_constu unsigned LEB128 integer constant + // DW_OP_consts signed LEB128 integer constant case DW_OP_const1u: - stack.push_back(Scalar((uint8_t)opcodes.GetU8(&offset))); + stack.push_back(to_generic(opcodes.GetU8(&offset))); break; case DW_OP_const1s: - stack.push_back(Scalar((int8_t)opcodes.GetU8(&offset))); + stack.push_back(to_generic((int8_t)opcodes.GetU8(&offset))); break; case DW_OP_const2u: - stack.push_back(Scalar((uint16_t)opcodes.GetU16(&offset))); + stack.push_back(to_generic(opcodes.GetU16(&offset))); break; case DW_OP_const2s: - stack.push_back(Scalar((int16_t)opcodes.GetU16(&offset))); + stack.push_back(to_generic((int16_t)opcodes.GetU16(&offset))); break; case DW_OP_const4u: - stack.push_back(Scalar((uint32_t)opcodes.GetU32(&offset))); + stack.push_back(to_generic(opcodes.GetU32(&offset))); break; case DW_OP_const4s: - stack.push_back(Scalar((int32_t)opcodes.GetU32(&offset))); + stack.push_back(to_generic((int32_t)opcodes.GetU32(&offset))); break; case DW_OP_const8u: - stack.push_back(Scalar((uint64_t)opcodes.GetU64(&offset))); + stack.push_back(to_generic(opcodes.GetU64(&offset))); break; case DW_OP_const8s: - stack.push_back(Scalar((int64_t)opcodes.GetU64(&offset))); + stack.push_back(to_generic((int64_t)opcodes.GetU64(&offset))); break; + // These should also use to_generic, but we can't do that due to a + // producer-side bug in llvm. See llvm.org/pr48087. case DW_OP_constu: stack.push_back(Scalar(opcodes.GetULEB128(&offset))); break; @@ -1891,7 +1963,7 @@ bool DWARFExpression::Evaluate( case DW_OP_lit29: case DW_OP_lit30: case DW_OP_lit31: - stack.push_back(Scalar((uint64_t)(op - DW_OP_lit0))); + stack.push_back(to_generic(op - DW_OP_lit0)); break; // OPCODE: DW_OP_regN @@ -1929,6 +2001,7 @@ bool DWARFExpression::Evaluate( case DW_OP_reg29: case DW_OP_reg30: case DW_OP_reg31: { + dwarf4_location_description_kind = Register; reg_num = op - DW_OP_reg0; if (ReadRegisterValueAsScalar(reg_ctx, reg_kind, reg_num, error_ptr, tmp)) @@ -1941,6 +2014,7 @@ bool DWARFExpression::Evaluate( // ULEB128 literal operand that encodes the register. // DESCRIPTION: Push the value in register on the top of the stack. case DW_OP_regx: { + dwarf4_location_description_kind = Register; reg_num = opcodes.GetULEB128(&offset); if (ReadRegisterValueAsScalar(reg_ctx, reg_kind, reg_num, error_ptr, tmp)) stack.push_back(tmp); @@ -1993,7 +2067,7 @@ bool DWARFExpression::Evaluate( tmp.ResolveValue(exe_ctx) += (uint64_t)breg_offset; tmp.ClearContext(); stack.push_back(tmp); - stack.back().SetValueType(Value::eValueTypeLoadAddress); + stack.back().SetValueType(Value::ValueType::LoadAddress); } else return false; } break; @@ -2012,7 +2086,7 @@ bool DWARFExpression::Evaluate( tmp.ResolveValue(exe_ctx) += (uint64_t)breg_offset; tmp.ClearContext(); stack.push_back(tmp); - stack.back().SetValueType(Value::eValueTypeLoadAddress); + stack.back().SetValueType(Value::ValueType::LoadAddress); } else return false; } break; @@ -2025,7 +2099,7 @@ bool DWARFExpression::Evaluate( int64_t fbreg_offset = opcodes.GetSLEB128(&offset); value += fbreg_offset; stack.push_back(value); - stack.back().SetValueType(Value::eValueTypeLoadAddress); + stack.back().SetValueType(Value::ValueType::LoadAddress); } else return false; } else { @@ -2036,7 +2110,7 @@ bool DWARFExpression::Evaluate( } } else { if (error_ptr) - error_ptr->SetErrorStringWithFormat( + error_ptr->SetErrorString( "NULL execution context for DW_OP_fbreg.\n"); return false; } @@ -2064,12 +2138,18 @@ bool DWARFExpression::Evaluate( // provides a way of describing how large a part of a variable a particular // DWARF expression refers to. case DW_OP_piece: { + LocationDescriptionKind piece_locdesc = dwarf4_location_description_kind; + // Reset for the next piece. + dwarf4_location_description_kind = Memory; + const uint64_t piece_byte_size = opcodes.GetULEB128(&offset); if (piece_byte_size > 0) { Value curr_piece; if (stack.empty()) { + UpdateValueTypeFromLocationDescription( + log, dwarf_cu, LocationDescriptionKind::Empty); // In a multi-piece expression, this means that the current piece is // not available. Fill with zeros for now by resizing the data and // appending it @@ -2085,11 +2165,15 @@ bool DWARFExpression::Evaluate( // Extract the current piece into "curr_piece" Value curr_piece_source_value(stack.back()); stack.pop_back(); + UpdateValueTypeFromLocationDescription(log, dwarf_cu, piece_locdesc, + &curr_piece_source_value); const Value::ValueType curr_piece_source_value_type = curr_piece_source_value.GetValueType(); switch (curr_piece_source_value_type) { - case Value::eValueTypeLoadAddress: + case Value::ValueType::Invalid: + return false; + case Value::ValueType::LoadAddress: if (process) { if (curr_piece.ResizeData(piece_byte_size) == piece_byte_size) { lldb::addr_t load_addr = @@ -2116,8 +2200,8 @@ bool DWARFExpression::Evaluate( } break; - case Value::eValueTypeFileAddress: - case Value::eValueTypeHostAddress: + case Value::ValueType::FileAddress: + case Value::ValueType::HostAddress: if (error_ptr) { lldb::addr_t addr = curr_piece_source_value.GetScalar().ULongLong( LLDB_INVALID_ADDRESS); @@ -2125,14 +2209,14 @@ bool DWARFExpression::Evaluate( "failed to read memory DW_OP_piece(%" PRIu64 ") from %s address 0x%" PRIx64, piece_byte_size, curr_piece_source_value.GetValueType() == - Value::eValueTypeFileAddress + Value::ValueType::FileAddress ? "file" : "host", addr); } return false; - case Value::eValueTypeScalar: { + case Value::ValueType::Scalar: { uint32_t bit_size = piece_byte_size * 8; uint32_t bit_offset = 0; Scalar &scalar = curr_piece_source_value.GetScalar(); @@ -2156,20 +2240,6 @@ bool DWARFExpression::Evaluate( ap_int.getNumWords()}; curr_piece.GetScalar() = Scalar(llvm::APInt(bit_size, buf)); } break; - - case Value::eValueTypeVector: { - if (curr_piece_source_value.GetVector().length >= piece_byte_size) - curr_piece_source_value.GetVector().length = piece_byte_size; - else { - if (error_ptr) - error_ptr->SetErrorStringWithFormat( - "unable to extract %" PRIu64 " bytes from a %" PRIu64 - " byte vector value.", - piece_byte_size, - (uint64_t)curr_piece_source_value.GetVector().length); - return false; - } - } break; } // Check if this is the first piece? @@ -2207,15 +2277,25 @@ bool DWARFExpression::Evaluate( case DW_OP_bit_piece: // 0x9d ULEB128 bit size, ULEB128 bit offset (DWARF3); if (stack.size() < 1) { + UpdateValueTypeFromLocationDescription(log, dwarf_cu, + LocationDescriptionKind::Empty); + // Reset for the next piece. + dwarf4_location_description_kind = Memory; if (error_ptr) error_ptr->SetErrorString( "Expression stack needs at least 1 item for DW_OP_bit_piece."); return false; } else { + UpdateValueTypeFromLocationDescription( + log, dwarf_cu, dwarf4_location_description_kind, &stack.back()); + // Reset for the next piece. + dwarf4_location_description_kind = Memory; const uint64_t piece_bit_size = opcodes.GetULEB128(&offset); const uint64_t piece_bit_offset = opcodes.GetULEB128(&offset); switch (stack.back().GetValueType()) { - case Value::eValueTypeScalar: { + case Value::ValueType::Invalid: + return false; + case Value::ValueType::Scalar: { if (!stack.back().GetScalar().ExtractBitfield(piece_bit_size, piece_bit_offset)) { if (error_ptr) @@ -2228,9 +2308,9 @@ bool DWARFExpression::Evaluate( } } break; - case Value::eValueTypeFileAddress: - case Value::eValueTypeLoadAddress: - case Value::eValueTypeHostAddress: + case Value::ValueType::FileAddress: + case Value::ValueType::LoadAddress: + case Value::ValueType::HostAddress: if (error_ptr) { error_ptr->SetErrorStringWithFormat( "unable to extract DW_OP_bit_piece(bit_size = %" PRIu64 @@ -2238,19 +2318,41 @@ bool DWARFExpression::Evaluate( piece_bit_size, piece_bit_offset); } return false; - - case Value::eValueTypeVector: - if (error_ptr) { - error_ptr->SetErrorStringWithFormat( - "unable to extract DW_OP_bit_piece(bit_size = %" PRIu64 - ", bit_offset = %" PRIu64 ") from a vector value.", - piece_bit_size, piece_bit_offset); - } - return false; } } break; + // OPCODE: DW_OP_implicit_value + // OPERANDS: 2 + // ULEB128 size of the value block in bytes + // uint8_t* block bytes encoding value in target's memory + // representation + // DESCRIPTION: Value is immediately stored in block in the debug info with + // the memory representation of the target. + case DW_OP_implicit_value: { + dwarf4_location_description_kind = Implicit; + + const uint32_t len = opcodes.GetULEB128(&offset); + const void *data = opcodes.GetData(&offset, len); + + if (!data) { + LLDB_LOG(log, "Evaluate_DW_OP_implicit_value: could not be read data"); + LLDB_ERRORF(error_ptr, "Could not evaluate %s.", + DW_OP_value_to_name(op)); + return false; + } + + Value result(data, len); + stack.push_back(result); + break; + } + + case DW_OP_implicit_pointer: { + dwarf4_location_description_kind = Implicit; + LLDB_ERRORF(error_ptr, "Could not evaluate %s.", DW_OP_value_to_name(op)); + return false; + } + // OPCODE: DW_OP_push_object_address // OPERANDS: none // DESCRIPTION: Pushes the address of the object currently being @@ -2322,13 +2424,14 @@ bool DWARFExpression::Evaluate( // rather is a constant value. The value from the top of the stack is the // value to be used. This is the actual object value and not the location. case DW_OP_stack_value: + dwarf4_location_description_kind = Implicit; if (stack.empty()) { if (error_ptr) error_ptr->SetErrorString( "Expression stack needs at least 1 item for DW_OP_stack_value."); return false; } - stack.back().SetValueType(Value::eValueTypeScalar); + stack.back().SetValueType(Value::ValueType::Scalar); break; // OPCODE: DW_OP_convert @@ -2416,7 +2519,7 @@ bool DWARFExpression::Evaluate( addr_t cfa = id.GetCallFrameAddress(); if (cfa != LLDB_INVALID_ADDRESS) { stack.push_back(Scalar(cfa)); - stack.back().SetValueType(Value::eValueTypeLoadAddress); + stack.back().SetValueType(Value::ValueType::LoadAddress); } else if (error_ptr) error_ptr->SetErrorString("Stack frame does not include a canonical " "frame address for DW_OP_call_frame_cfa " @@ -2476,7 +2579,7 @@ bool DWARFExpression::Evaluate( } stack.back().GetScalar() = tls_load_addr; - stack.back().SetValueType(Value::eValueTypeLoadAddress); + stack.back().SetValueType(Value::ValueType::LoadAddress); } break; // OPCODE: DW_OP_addrx (DW_OP_GNU_addr_index is the legacy name.) @@ -2496,7 +2599,7 @@ bool DWARFExpression::Evaluate( uint64_t index = opcodes.GetULEB128(&offset); lldb::addr_t value = ReadAddressFromDebugAddrSection(dwarf_cu, index); stack.push_back(Scalar(value)); - stack.back().SetValueType(Value::eValueTypeFileAddress); + stack.back().SetValueType(Value::ValueType::FileAddress); } break; // OPCODE: DW_OP_GNU_const_index @@ -2542,25 +2645,28 @@ bool DWARFExpression::Evaluate( // or DW_OP_bit_piece opcodes if (pieces.GetBuffer().GetByteSize()) { result = pieces; - } else { - if (error_ptr) - error_ptr->SetErrorString("Stack empty after evaluation."); - return false; + return true; } - } else { - if (log && log->GetVerbose()) { - size_t count = stack.size(); - LLDB_LOGF(log, "Stack after operation has %" PRIu64 " values:", - (uint64_t)count); - for (size_t i = 0; i < count; ++i) { - StreamString new_value; - new_value.Printf("[%" PRIu64 "]", (uint64_t)i); - stack[i].Dump(&new_value); - LLDB_LOGF(log, " %s", new_value.GetData()); - } + if (error_ptr) + error_ptr->SetErrorString("Stack empty after evaluation."); + return false; + } + + UpdateValueTypeFromLocationDescription( + log, dwarf_cu, dwarf4_location_description_kind, &stack.back()); + + if (log && log->GetVerbose()) { + size_t count = stack.size(); + LLDB_LOGF(log, + "Stack after operation has %" PRIu64 " values:", (uint64_t)count); + for (size_t i = 0; i < count; ++i) { + StreamString new_value; + new_value.Printf("[%" PRIu64 "]", (uint64_t)i); + stack[i].Dump(&new_value); + LLDB_LOGF(log, " %s", new_value.GetData()); } - result = stack.back(); } + result = stack.back(); return true; // Return true on success } diff --git a/gnu/llvm/lldb/source/Expression/ExpressionVariable.cpp b/gnu/llvm/lldb/source/Expression/ExpressionVariable.cpp index d95f0745cf4..565a3d1a816 100644 --- a/gnu/llvm/lldb/source/Expression/ExpressionVariable.cpp +++ b/gnu/llvm/lldb/source/Expression/ExpressionVariable.cpp @@ -13,13 +13,13 @@ using namespace lldb_private; -ExpressionVariable::~ExpressionVariable() {} +ExpressionVariable::~ExpressionVariable() = default; uint8_t *ExpressionVariable::GetValueBytes() { - const size_t byte_size = m_frozen_sp->GetByteSize(); - if (byte_size > 0) { - if (m_frozen_sp->GetDataExtractor().GetByteSize() < byte_size) { - m_frozen_sp->GetValue().ResizeData(byte_size); + llvm::Optional byte_size = m_frozen_sp->GetByteSize(); + if (byte_size && *byte_size) { + if (m_frozen_sp->GetDataExtractor().GetByteSize() < *byte_size) { + m_frozen_sp->GetValue().ResizeData(*byte_size); m_frozen_sp->GetValue().GetData(m_frozen_sp->GetDataExtractor()); } return const_cast( @@ -28,7 +28,7 @@ uint8_t *ExpressionVariable::GetValueBytes() { return nullptr; } -PersistentExpressionState::~PersistentExpressionState() {} +PersistentExpressionState::~PersistentExpressionState() = default; lldb::addr_t PersistentExpressionState::LookupSymbol(ConstString name) { SymbolMap::iterator si = m_symbol_map.find(name.GetCString()); diff --git a/gnu/llvm/lldb/source/Expression/FunctionCaller.cpp b/gnu/llvm/lldb/source/Expression/FunctionCaller.cpp index 26ab4bfaff5..5f1eb24a905 100644 --- a/gnu/llvm/lldb/source/Expression/FunctionCaller.cpp +++ b/gnu/llvm/lldb/source/Expression/FunctionCaller.cpp @@ -193,8 +193,8 @@ bool FunctionCaller::WriteFunctionArguments( // Special case: if it's a pointer, don't do anything (the ABI supports // passing cstrings) - if (arg_value->GetValueType() == Value::eValueTypeHostAddress && - arg_value->GetContextType() == Value::eContextTypeInvalid && + if (arg_value->GetValueType() == Value::ValueType::HostAddress && + arg_value->GetContextType() == Value::ContextType::Invalid && arg_value->GetCompilerType().IsPointerType()) continue; @@ -295,7 +295,7 @@ bool FunctionCaller::FetchFunctionResults(ExecutionContext &exe_ctx, return false; ret_value.SetCompilerType(m_function_return_type); - ret_value.SetValueType(Value::eValueTypeScalar); + ret_value.SetValueType(Value::ValueType::Scalar); return true; } @@ -317,12 +317,16 @@ lldb::ExpressionResults FunctionCaller::ExecuteFunction( lldb::ExpressionResults return_value = lldb::eExpressionSetupError; // FunctionCaller::ExecuteFunction execution is always just to get the - // result. Do make sure we ignore breakpoints, unwind on error, and don't try - // to debug it. + // result. Unless explicitly asked for, ignore breakpoints and unwind on + // error. + const bool enable_debugging = + exe_ctx.GetTargetPtr() && + exe_ctx.GetTargetPtr()->GetDebugUtilityExpression(); EvaluateExpressionOptions real_options = options; - real_options.SetDebug(false); - real_options.SetUnwindOnError(true); - real_options.SetIgnoreBreakpoints(true); + real_options.SetDebug(false); // This halts the expression for debugging. + real_options.SetGenerateDebugInfo(enable_debugging); + real_options.SetUnwindOnError(!enable_debugging); + real_options.SetIgnoreBreakpoints(!enable_debugging); lldb::addr_t args_addr; diff --git a/gnu/llvm/lldb/source/Expression/IRExecutionUnit.cpp b/gnu/llvm/lldb/source/Expression/IRExecutionUnit.cpp index e3c9c1d7fdf..63184ba477a 100644 --- a/gnu/llvm/lldb/source/Expression/IRExecutionUnit.cpp +++ b/gnu/llvm/lldb/source/Expression/IRExecutionUnit.cpp @@ -9,6 +9,8 @@ #include "llvm/ExecutionEngine/ExecutionEngine.h" #include "llvm/ExecutionEngine/ObjectCache.h" #include "llvm/IR/Constants.h" +#include "llvm/IR/DiagnosticHandler.h" +#include "llvm/IR/DiagnosticInfo.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" #include "llvm/Support/SourceMgr.h" @@ -200,16 +202,26 @@ Status IRExecutionUnit::DisassembleFunction(Stream &stream, return ret; } -static void ReportInlineAsmError(const llvm::SMDiagnostic &diagnostic, - void *Context, unsigned LocCookie) { - Status *err = static_cast(Context); +namespace { +struct IRExecDiagnosticHandler : public llvm::DiagnosticHandler { + Status *err; + IRExecDiagnosticHandler(Status *err) : err(err) {} + bool handleDiagnostics(const llvm::DiagnosticInfo &DI) override { + if (DI.getKind() == llvm::DK_SrcMgr) { + const auto &DISM = llvm::cast(DI); + if (err && err->Success()) { + err->SetErrorToGenericError(); + err->SetErrorStringWithFormat( + "Inline assembly error: %s", + DISM.getSMDiag().getMessage().str().c_str()); + } + return true; + } - if (err && err->Success()) { - err->SetErrorToGenericError(); - err->SetErrorStringWithFormat("Inline assembly error: %s", - diagnostic.getMessage().str().c_str()); + return false; } -} +}; +} // namespace void IRExecutionUnit::ReportSymbolLookupError(ConstString name) { m_failed_lookups.push_back(name); @@ -257,8 +269,8 @@ void IRExecutionUnit::GetRunnableInfo(Status &error, lldb::addr_t &func_addr, LLDB_LOGF(log, "Module being sent to JIT: \n%s", s.c_str()); } - m_module_up->getContext().setInlineAsmDiagnosticHandler(ReportInlineAsmError, - &error); + m_module_up->getContext().setDiagnosticHandler( + std::make_unique(&error)); llvm::EngineBuilder builder(std::move(m_module_up)); llvm::Triple triple(m_module->getTargetTriple()); @@ -328,8 +340,7 @@ void IRExecutionUnit::GetRunnableInfo(Status &error, lldb::addr_t &func_addr, if (function.isDeclaration() || function.hasPrivateLinkage()) continue; - const bool external = - function.hasExternalLinkage() || function.hasLinkOnceODRLinkage(); + const bool external = !function.hasLocalLinkage(); void *fun_ptr = m_execution_engine_up->getPointerToFunction(&function); @@ -485,7 +496,7 @@ IRExecutionUnit::~IRExecutionUnit() { IRExecutionUnit::MemoryManager::MemoryManager(IRExecutionUnit &parent) : m_default_mm_up(new llvm::SectionMemoryManager()), m_parent(parent) {} -IRExecutionUnit::MemoryManager::~MemoryManager() {} +IRExecutionUnit::MemoryManager::~MemoryManager() = default; lldb::SectionType IRExecutionUnit::GetSectionTypeFromSectionName( const llvm::StringRef &name, IRExecutionUnit::AllocationKind alloc_kind) { diff --git a/gnu/llvm/lldb/source/Expression/IRInterpreter.cpp b/gnu/llvm/lldb/source/Expression/IRInterpreter.cpp index 4c7a6562659..788520d1f32 100644 --- a/gnu/llvm/lldb/source/Expression/IRInterpreter.cpp +++ b/gnu/llvm/lldb/source/Expression/IRInterpreter.cpp @@ -122,7 +122,7 @@ public: m_stack_pointer = stack_frame_top; } - ~InterpreterStackFrame() {} + ~InterpreterStackFrame() = default; void Jump(const BasicBlock *bb) { m_prev_bb = m_bb; @@ -1241,7 +1241,7 @@ bool IRInterpreter::Interpret(llvm::Module &module, llvm::Function &function, if (!write_error.Success()) { LLDB_LOGF(log, "Couldn't write to a region on behalf of a LoadInst"); error.SetErrorToGenericError(); - error.SetErrorString(memory_read_error); + error.SetErrorString(memory_write_error); return false; } @@ -1356,14 +1356,14 @@ bool IRInterpreter::Interpret(llvm::Module &module, llvm::Function &function, // Check we can actually get a thread if (exe_ctx.GetThreadPtr() == nullptr) { error.SetErrorToGenericError(); - error.SetErrorStringWithFormat("unable to acquire thread"); + error.SetErrorString("unable to acquire thread"); return false; } // Make sure we have a valid process if (!exe_ctx.GetProcessPtr()) { error.SetErrorToGenericError(); - error.SetErrorStringWithFormat("unable to get the process"); + error.SetErrorString("unable to get the process"); return false; } @@ -1404,7 +1404,7 @@ bool IRInterpreter::Interpret(llvm::Module &module, llvm::Function &function, static lldb_private::ABI::CallArgument rawArgs[16]; if (numArgs >= 16) { error.SetErrorToGenericError(); - error.SetErrorStringWithFormat("function takes too many arguments"); + error.SetErrorString("function takes too many arguments"); return false; } @@ -1490,7 +1490,7 @@ bool IRInterpreter::Interpret(llvm::Module &module, llvm::Function &function, // Check that the thread plan completed successfully if (res != lldb::ExpressionResults::eExpressionCompleted) { error.SetErrorToGenericError(); - error.SetErrorStringWithFormat("ThreadPlanCallFunctionUsingABI failed"); + error.SetErrorString("ThreadPlanCallFunctionUsingABI failed"); return false; } @@ -1511,7 +1511,7 @@ bool IRInterpreter::Interpret(llvm::Module &module, llvm::Function &function, // Check if the return value is valid if (vobj == nullptr || !retVal) { error.SetErrorToGenericError(); - error.SetErrorStringWithFormat("unable to get the return value"); + error.SetErrorString("unable to get the return value"); return false; } diff --git a/gnu/llvm/lldb/source/Expression/IRMemoryMap.cpp b/gnu/llvm/lldb/source/Expression/IRMemoryMap.cpp index 6b1e4c313a3..4ae2724d4dd 100644 --- a/gnu/llvm/lldb/source/Expression/IRMemoryMap.cpp +++ b/gnu/llvm/lldb/source/Expression/IRMemoryMap.cpp @@ -639,7 +639,7 @@ void IRMemoryMap::ReadMemory(uint8_t *bytes, lldb::addr_t process_address, if (target_sp) { Address absolute_address(process_address); - target_sp->ReadMemory(absolute_address, false, bytes, size, error); + target_sp->ReadMemory(absolute_address, bytes, size, error, true); return; } diff --git a/gnu/llvm/lldb/source/Expression/LLVMUserExpression.cpp b/gnu/llvm/lldb/source/Expression/LLVMUserExpression.cpp index 187b427e66a..527dff8bf60 100644 --- a/gnu/llvm/lldb/source/Expression/LLVMUserExpression.cpp +++ b/gnu/llvm/lldb/source/Expression/LLVMUserExpression.cpp @@ -188,9 +188,8 @@ LLVMUserExpression::DoExecute(DiagnosticManager &diagnostic_manager, execution_result == lldb::eExpressionHitBreakpoint) { const char *error_desc = nullptr; - if (call_plan_sp) { - lldb::StopInfoSP real_stop_info_sp = call_plan_sp->GetRealStopInfo(); - if (real_stop_info_sp) + if (user_expression_plan) { + if (auto real_stop_info_sp = user_expression_plan->GetRealStopInfo()) error_desc = real_stop_info_sp->GetDescription(); } if (error_desc) diff --git a/gnu/llvm/lldb/source/Expression/Materializer.cpp b/gnu/llvm/lldb/source/Expression/Materializer.cpp index f33462053f2..3945f3a70f7 100644 --- a/gnu/llvm/lldb/source/Expression/Materializer.cpp +++ b/gnu/llvm/lldb/source/Expression/Materializer.cpp @@ -67,7 +67,7 @@ public: const bool zero_memory = false; lldb::addr_t mem = map.Malloc( - m_persistent_variable_sp->GetByteSize(), 8, + m_persistent_variable_sp->GetByteSize().getValueOr(0), 8, lldb::ePermissionsReadable | lldb::ePermissionsWritable, IRMemoryMap::eAllocationPolicyMirror, zero_memory, allocate_error); @@ -106,7 +106,8 @@ public: Status write_error; map.WriteMemory(mem, m_persistent_variable_sp->GetValueBytes(), - m_persistent_variable_sp->GetByteSize(), write_error); + m_persistent_variable_sp->GetByteSize().getValueOr(0), + write_error); if (!write_error.Success()) { err.SetErrorStringWithFormat( @@ -234,7 +235,7 @@ public: map.GetBestExecutionContextScope(), m_persistent_variable_sp.get()->GetCompilerType(), m_persistent_variable_sp->GetName(), location, eAddressTypeLoad, - m_persistent_variable_sp->GetByteSize()); + m_persistent_variable_sp->GetByteSize().getValueOr(0)); if (frame_top != LLDB_INVALID_ADDRESS && frame_bottom != LLDB_INVALID_ADDRESS && location >= frame_bottom && @@ -279,7 +280,8 @@ public: LLDB_LOGF(log, "Dematerializing %s from 0x%" PRIx64 " (size = %llu)", m_persistent_variable_sp->GetName().GetCString(), (uint64_t)mem, - (unsigned long long)m_persistent_variable_sp->GetByteSize()); + (unsigned long long)m_persistent_variable_sp->GetByteSize() + .getValueOr(0)); // Read the contents of the spare memory area @@ -288,7 +290,7 @@ public: Status read_error; map.ReadMemory(m_persistent_variable_sp->GetValueBytes(), mem, - m_persistent_variable_sp->GetByteSize(), read_error); + m_persistent_variable_sp->GetByteSize().getValueOr(0), read_error); if (!read_error.Success()) { err.SetErrorStringWithFormat( @@ -369,10 +371,11 @@ public: if (!err.Success()) { dump_stream.Printf(" \n"); } else { - DataBufferHeap data(m_persistent_variable_sp->GetByteSize(), 0); + DataBufferHeap data( + m_persistent_variable_sp->GetByteSize().getValueOr(0), 0); map.ReadMemory(data.GetBytes(), target_address, - m_persistent_variable_sp->GetByteSize(), err); + m_persistent_variable_sp->GetByteSize().getValueOr(0), err); if (!err.Success()) { dump_stream.Printf(" \n"); @@ -514,7 +517,7 @@ public: return; } - if (data.GetByteSize() < m_variable_sp->GetType()->GetByteSize()) { + if (data.GetByteSize() < m_variable_sp->GetType()->GetByteSize(scope)) { if (data.GetByteSize() == 0 && !m_variable_sp->LocationExpression().IsValid()) { err.SetErrorStringWithFormat("the variable '%s' has no location, " @@ -525,7 +528,7 @@ public: "size of variable %s (%" PRIu64 ") is larger than the ValueObject's size (%" PRIu64 ")", m_variable_sp->GetName().AsCString(), - m_variable_sp->GetType()->GetByteSize().getValueOr(0), + m_variable_sp->GetType()->GetByteSize(scope).getValueOr(0), data.GetByteSize()); } return; @@ -621,8 +624,8 @@ public: Status extract_error; - map.GetMemoryData(data, m_temporary_allocation, valobj_sp->GetByteSize(), - extract_error); + map.GetMemoryData(data, m_temporary_allocation, + valobj_sp->GetByteSize().getValueOr(0), extract_error); if (!extract_error.Success()) { err.SetErrorStringWithFormat("couldn't get the data for variable %s", @@ -791,13 +794,15 @@ public: llvm::Optional byte_size = m_type.GetByteSize(exe_scope); if (!byte_size) { - err.SetErrorString("can't get size of type"); + err.SetErrorStringWithFormat("can't get size of type \"%s\"", + m_type.GetTypeName().AsCString()); return; } llvm::Optional opt_bit_align = m_type.GetTypeBitAlign(exe_scope); if (!opt_bit_align) { - err.SetErrorStringWithFormat("can't get the type alignment"); + err.SetErrorStringWithFormat("can't get the alignment of type \"%s\"", + m_type.GetTypeName().AsCString()); return; } @@ -919,7 +924,7 @@ public: ret->ValueUpdated(); - const size_t pvar_byte_size = ret->GetByteSize(); + const size_t pvar_byte_size = ret->GetByteSize().getValueOr(0); uint8_t *pvar_data = ret->GetValueBytes(); map.ReadMemory(pvar_data, address, pvar_byte_size, read_error); @@ -1279,9 +1284,8 @@ public: m_register_contents.reset(); - RegisterValue register_value( - const_cast(register_data.GetDataStart()), - register_data.GetByteSize(), register_data.GetByteOrder()); + RegisterValue register_value(register_data.GetData(), + register_data.GetByteOrder()); if (!reg_context_sp->WriteRegister(&m_register_info, register_value)) { err.SetErrorStringWithFormat("couldn't write the value of register %s", diff --git a/gnu/llvm/lldb/source/Expression/REPL.cpp b/gnu/llvm/lldb/source/Expression/REPL.cpp index fd7c3968692..c3d14960f74 100644 --- a/gnu/llvm/lldb/source/Expression/REPL.cpp +++ b/gnu/llvm/lldb/source/Expression/REPL.cpp @@ -123,10 +123,11 @@ const char *REPL::IOHandlerGetHelpPrologue() { "Valid statements, expressions, and declarations are immediately " "compiled and executed.\n\n" "The complete set of LLDB debugging commands are also available as " - "described below. Commands " + "described below.\n\nCommands " "must be prefixed with a colon at the REPL prompt (:quit for " "example.) Typing just a colon " - "followed by return will switch to the LLDB prompt.\n\n"; + "followed by return will switch to the LLDB prompt.\n\n" + "Type “< path” to read in code from a text file “path”.\n\n"; } bool REPL::IOHandlerIsInputComplete(IOHandler &io_handler, StringList &lines) { @@ -179,6 +180,36 @@ int REPL::IOHandlerFixIndentation(IOHandler &io_handler, return (int)desired_indent - actual_indent; } +static bool ReadCode(const std::string &path, std::string &code, + lldb::StreamFileSP &error_sp) { + auto &fs = FileSystem::Instance(); + llvm::Twine pathTwine(path); + if (!fs.Exists(pathTwine)) { + error_sp->Printf("no such file at path '%s'\n", path.c_str()); + return false; + } + if (!fs.Readable(pathTwine)) { + error_sp->Printf("could not read file at path '%s'\n", path.c_str()); + return false; + } + const size_t file_size = fs.GetByteSize(pathTwine); + const size_t max_size = code.max_size(); + if (file_size > max_size) { + error_sp->Printf("file at path '%s' too large: " + "file_size = %zu, max_size = %zu\n", + path.c_str(), file_size, max_size); + return false; + } + auto data_sp = fs.CreateDataBuffer(pathTwine); + if (data_sp == nullptr) { + error_sp->Printf("could not create buffer for file at path '%s'\n", + path.c_str()); + return false; + } + code.assign((const char *)data_sp->GetBytes(), data_sp->GetByteSize()); + return true; +} + void REPL::IOHandlerInputComplete(IOHandler &io_handler, std::string &code) { lldb::StreamFileSP output_sp(io_handler.GetOutputStreamFileSP()); lldb::StreamFileSP error_sp(io_handler.GetErrorStreamFileSP()); @@ -257,6 +288,15 @@ void REPL::IOHandlerInputComplete(IOHandler &io_handler, std::string &code) { } } } else { + if (code[0] == '<') { + // User wants to read code from a file. + // Interpret rest of line as a literal path. + auto path = llvm::StringRef(code.substr(1)).trim().str(); + if (!ReadCode(path, code, error_sp)) { + return; + } + } + // Unwind any expression we might have been running in case our REPL // expression crashed and the user was looking around if (m_dedicated_repl_mode) { diff --git a/gnu/llvm/lldb/source/Expression/UserExpression.cpp b/gnu/llvm/lldb/source/Expression/UserExpression.cpp index 47d13f052bf..eac89c24bc1 100644 --- a/gnu/llvm/lldb/source/Expression/UserExpression.cpp +++ b/gnu/llvm/lldb/source/Expression/UserExpression.cpp @@ -8,7 +8,7 @@ #include "lldb/Host/Config.h" -#include +#include #if HAVE_SYS_TYPES_H #include #endif @@ -57,7 +57,7 @@ UserExpression::UserExpression(ExecutionContextScope &exe_scope, m_expr_prefix(std::string(prefix)), m_language(language), m_desired_type(desired_type), m_options(options) {} -UserExpression::~UserExpression() {} +UserExpression::~UserExpression() = default; void UserExpression::InstallContext(ExecutionContext &exe_ctx) { m_jit_process_wp = exe_ctx.GetProcessSP(); @@ -187,7 +187,12 @@ UserExpression::Evaluate(ExecutionContext &exe_ctx, } } - if (process == nullptr || !process->CanJIT()) + // Explicitly force the IR interpreter to evaluate the expression when the + // there is no process that supports running the expression for us. Don't + // change the execution policy if we have the special top-level policy that + // doesn't contain any expression and there is nothing to interpret. + if (execution_policy != eExecutionPolicyTopLevel && + (process == nullptr || !process->CanJIT())) execution_policy = eExecutionPolicyNever; // We need to set the expression execution thread here, turns out parse can @@ -297,19 +302,19 @@ UserExpression::Evaluate(ExecutionContext &exe_ctx, } if (!parse_success) { - if (!fixed_expression->empty() && target->GetEnableNotifyAboutFixIts()) { - error.SetExpressionErrorWithFormat( - execution_results, - "expression failed to parse, fixed expression suggested:\n %s", - fixed_expression->c_str()); - } else { - if (!diagnostic_manager.Diagnostics().size()) - error.SetExpressionError(execution_results, - "expression failed to parse, unknown error"); + std::string msg; + { + llvm::raw_string_ostream os(msg); + os << "expression failed to parse:\n"; + if (!diagnostic_manager.Diagnostics().empty()) + os << diagnostic_manager.GetString(); else - error.SetExpressionError(execution_results, - diagnostic_manager.GetString().c_str()); + os << "unknown error"; + if (target->GetEnableNotifyAboutFixIts() && fixed_expression && + !fixed_expression->empty()) + os << "\nfixed expression suggested:\n " << *fixed_expression; } + error.SetExpressionError(execution_results, msg.c_str()); } } @@ -358,10 +363,11 @@ UserExpression::Evaluate(ExecutionContext &exe_ctx, } else { if (expr_result) { result_valobj_sp = expr_result->GetValueObject(); + result_valobj_sp->SetPreferredDisplayLanguage(language); LLDB_LOG(log, "== [UserExpression::Evaluate] Execution completed " - "normally with result %s ==", + "normally with result {0} ==", result_valobj_sp->GetValueAsCString()); } else { LLDB_LOG(log, "== [UserExpression::Evaluate] Execution completed " diff --git a/gnu/llvm/lldb/source/Expression/UtilityFunction.cpp b/gnu/llvm/lldb/source/Expression/UtilityFunction.cpp index 3de2ee2acbb..d7a89a8e144 100644 --- a/gnu/llvm/lldb/source/Expression/UtilityFunction.cpp +++ b/gnu/llvm/lldb/source/Expression/UtilityFunction.cpp @@ -8,7 +8,7 @@ #include "lldb/Host/Config.h" -#include +#include #if HAVE_SYS_TYPES_H #include #endif @@ -41,9 +41,10 @@ char UtilityFunction::ID; /// \param[in] name /// The name of the function, as used in the text. UtilityFunction::UtilityFunction(ExecutionContextScope &exe_scope, - const char *text, const char *name) + std::string text, std::string name, + bool enable_debugging) : Expression(exe_scope), m_execution_unit_sp(), m_jit_module_wp(), - m_function_text(), m_function_name(name) {} + m_function_text(std::move(text)), m_function_name(std::move(name)) {} UtilityFunction::~UtilityFunction() { lldb::ProcessSP process_sp(m_jit_process_wp.lock()); diff --git a/gnu/llvm/lldb/source/Host/CMakeLists.txt b/gnu/llvm/lldb/source/Host/CMakeLists.txt index add503a5f36..a018fd6c183 100644 --- a/gnu/llvm/lldb/source/Host/CMakeLists.txt +++ b/gnu/llvm/lldb/source/Host/CMakeLists.txt @@ -58,7 +58,6 @@ add_host_subdirectory(posix if (CMAKE_SYSTEM_NAME MATCHES "Windows") add_host_subdirectory(windows windows/ConnectionGenericFileWindows.cpp - windows/EditLineWin.cpp windows/FileSystem.cpp windows/Host.cpp windows/HostInfoWindows.cpp @@ -93,7 +92,7 @@ else() macosx/cfcpp/CFCMutableSet.cpp macosx/cfcpp/CFCString.cpp ) - if(IOS) + if(APPLE_EMBEDDED) set_property(SOURCE macosx/Host.mm APPEND PROPERTY COMPILE_DEFINITIONS "NO_XPC_SERVICES=1") endif() diff --git a/gnu/llvm/lldb/source/Host/android/LibcGlue.cpp b/gnu/llvm/lldb/source/Host/android/LibcGlue.cpp index f7e0bf3a99d..877d735823f 100644 --- a/gnu/llvm/lldb/source/Host/android/LibcGlue.cpp +++ b/gnu/llvm/lldb/source/Host/android/LibcGlue.cpp @@ -14,8 +14,8 @@ #if __ANDROID_API__ < 21 +#include #include -#include #include #include diff --git a/gnu/llvm/lldb/source/Host/common/Editline.cpp b/gnu/llvm/lldb/source/Host/common/Editline.cpp index 226e638aba2..a5598c387b8 100644 --- a/gnu/llvm/lldb/source/Host/common/Editline.cpp +++ b/gnu/llvm/lldb/source/Host/common/Editline.cpp @@ -6,11 +6,12 @@ // //===----------------------------------------------------------------------===// +#include #include -#include -#include "lldb/Host/ConnectionFileDescriptor.h" #include "lldb/Host/Editline.h" + +#include "lldb/Host/ConnectionFileDescriptor.h" #include "lldb/Host/FileSystem.h" #include "lldb/Host/Host.h" #include "lldb/Utility/CompletionRequest.h" @@ -48,9 +49,12 @@ int setupterm(char *term, int fildes, int *errret); // understand the relationship between DisplayInput(), MoveCursor(), // SetCurrentLine(), and SaveEditedLine() before making changes. +/// https://www.ecma-international.org/publications/files/ECMA-ST/Ecma-048.pdf #define ESCAPE "\x1b" +/// Faint, decreased intensity or second colour. #define ANSI_FAINT ESCAPE "[2m" -#define ANSI_UNFAINT ESCAPE "[22m" +/// Normal colour or normal intensity (neither bold nor faint). +#define ANSI_UNFAINT ESCAPE "[0m" #define ANSI_CLEAR_BELOW ESCAPE "[J" #define ANSI_CLEAR_RIGHT ESCAPE "[K" #define ANSI_SET_COLUMN_N ESCAPE "[%dG" @@ -149,6 +153,11 @@ std::vector SplitLines(const EditLineStringType &input) { result.push_back(input.substr(start, end - start)); start = end + 1; } + // Treat an empty history session as a single command of zero-length instead + // of returning an empty vector. + if (result.empty()) { + result.emplace_back(); + } return result; } @@ -207,7 +216,7 @@ private: // Compute the history path lazily. if (m_path.empty() && m_history && !m_prefix.empty()) { llvm::SmallString<128> lldb_history_file; - llvm::sys::path::home_directory(lldb_history_file); + FileSystem::Instance().GetHomeDirectory(lldb_history_file); llvm::sys::path::append(lldb_history_file, ".lldb"); // LLDB stores its history in ~/.lldb/. If for some reason this directory @@ -638,8 +647,7 @@ unsigned char Editline::BreakLineCommand(int ch) { lines.AppendString(new_line_fragment); #endif - int indent_correction = m_fix_indentation_callback( - this, lines, 0, m_fix_indentation_callback_baton); + int indent_correction = m_fix_indentation_callback(this, lines, 0); new_line_fragment = FixIndentation(new_line_fragment, indent_correction); m_revert_cursor_index = GetIndentation(new_line_fragment); } @@ -674,8 +682,7 @@ unsigned char Editline::EndOrAddLineCommand(int ch) { info->cursor == info->lastchar) { if (m_is_input_complete_callback) { auto lines = GetInputAsStringList(); - if (!m_is_input_complete_callback(this, lines, - m_is_input_complete_callback_baton)) { + if (!m_is_input_complete_callback(this, lines)) { return BreakLineCommand(ch); } @@ -808,8 +815,7 @@ unsigned char Editline::NextLineCommand(int ch) { if (m_fix_indentation_callback) { StringList lines = GetInputAsStringList(); lines.AppendString(""); - indentation = m_fix_indentation_callback( - this, lines, 0, m_fix_indentation_callback_baton); + indentation = m_fix_indentation_callback(this, lines, 0); } m_input_lines.insert( m_input_lines.end(), @@ -854,8 +860,8 @@ unsigned char Editline::FixIndentationCommand(int ch) { // Save the edits and determine the correct indentation level SaveEditedLine(); StringList lines = GetInputAsStringList(m_current_line_index + 1); - int indent_correction = m_fix_indentation_callback( - this, lines, cursor_position, m_fix_indentation_callback_baton); + int indent_correction = + m_fix_indentation_callback(this, lines, cursor_position); // If it is already correct no special work is needed if (indent_correction == 0) @@ -974,7 +980,7 @@ DisplayCompletions(::EditLine *editline, FILE *output_file, } unsigned char Editline::TabCommand(int ch) { - if (m_completion_callback == nullptr) + if (!m_completion_callback) return CC_ERROR; const LineInfo *line_info = el_line(m_editline); @@ -985,7 +991,7 @@ unsigned char Editline::TabCommand(int ch) { CompletionResult result; CompletionRequest request(line, cursor_index, result); - m_completion_callback(request, m_completion_callback_baton); + m_completion_callback(request); llvm::ArrayRef results = result.GetResults(); @@ -1001,11 +1007,15 @@ unsigned char Editline::TabCommand(int ch) { case CompletionMode::Normal: { std::string to_add = completion.GetCompletion(); to_add = to_add.substr(request.GetCursorArgumentPrefix().size()); - if (request.GetParsedArg().IsQuoted()) + // Terminate the current argument with a quote if it started with a quote. + if (!request.GetParsedLine().empty() && request.GetParsedArg().IsQuoted()) to_add.push_back(request.GetParsedArg().GetQuoteChar()); to_add.push_back(' '); el_insertstr(m_editline, to_add.c_str()); - break; + // Clear all the autosuggestion parts if the only single space can be completed. + if (to_add == " ") + return CC_REDISPLAY; + return CC_REFRESH; } case CompletionMode::Partial: { std::string to_add = completion.GetCompletion(); @@ -1039,6 +1049,74 @@ unsigned char Editline::TabCommand(int ch) { return CC_REDISPLAY; } +unsigned char Editline::ApplyAutosuggestCommand(int ch) { + if (!m_suggestion_callback) { + return CC_REDISPLAY; + } + + const LineInfo *line_info = el_line(m_editline); + llvm::StringRef line(line_info->buffer, + line_info->lastchar - line_info->buffer); + + if (llvm::Optional to_add = m_suggestion_callback(line)) + el_insertstr(m_editline, to_add->c_str()); + + return CC_REDISPLAY; +} + +unsigned char Editline::TypedCharacter(int ch) { + std::string typed = std::string(1, ch); + el_insertstr(m_editline, typed.c_str()); + + if (!m_suggestion_callback) { + return CC_REDISPLAY; + } + + const LineInfo *line_info = el_line(m_editline); + llvm::StringRef line(line_info->buffer, + line_info->lastchar - line_info->buffer); + + if (llvm::Optional to_add = m_suggestion_callback(line)) { + std::string to_add_color = ANSI_FAINT + to_add.getValue() + ANSI_UNFAINT; + fputs(typed.c_str(), m_output_file); + fputs(to_add_color.c_str(), m_output_file); + size_t new_autosuggestion_size = line.size() + to_add->length(); + // Print spaces to hide any remains of a previous longer autosuggestion. + if (new_autosuggestion_size < m_previous_autosuggestion_size) { + size_t spaces_to_print = + m_previous_autosuggestion_size - new_autosuggestion_size; + std::string spaces = std::string(spaces_to_print, ' '); + fputs(spaces.c_str(), m_output_file); + } + m_previous_autosuggestion_size = new_autosuggestion_size; + + int editline_cursor_position = + (int)((line_info->cursor - line_info->buffer) + GetPromptWidth()); + int editline_cursor_row = editline_cursor_position / m_terminal_width; + int toColumn = + editline_cursor_position - (editline_cursor_row * m_terminal_width); + fprintf(m_output_file, ANSI_SET_COLUMN_N, toColumn); + return CC_REFRESH; + } + + return CC_REDISPLAY; +} + +void Editline::AddFunctionToEditLine(const EditLineCharType *command, + const EditLineCharType *helptext, + EditlineCommandCallbackType callbackFn) { + el_wset(m_editline, EL_ADDFN, command, helptext, callbackFn); +} + +void Editline::SetEditLinePromptCallback( + EditlinePromptCallbackType callbackFn) { + el_set(m_editline, EL_PROMPT, callbackFn); +} + +void Editline::SetGetCharacterFunction(EditlineGetCharCallbackType callbackFn) { + el_wset(m_editline, EL_GETCFN, callbackFn); +} + void Editline::ConfigureEditor(bool multiline) { if (m_editline && m_multiline_enabled == multiline) return; @@ -1065,74 +1143,83 @@ void Editline::ConfigureEditor(bool multiline) { el_set(m_editline, EL_CLIENTDATA, this); el_set(m_editline, EL_SIGNAL, 0); el_set(m_editline, EL_EDITOR, "emacs"); - el_set(m_editline, EL_PROMPT, - (EditlinePromptCallbackType)([](EditLine *editline) { - return Editline::InstanceFor(editline)->Prompt(); - })); - el_wset(m_editline, EL_GETCFN, (EditlineGetCharCallbackType)([]( - EditLine *editline, EditLineGetCharType *c) { - return Editline::InstanceFor(editline)->GetCharacter(c); - })); + SetGetCharacterFunction([](EditLine *editline, EditLineGetCharType *c) { + return Editline::InstanceFor(editline)->GetCharacter(c); + }); + + SetEditLinePromptCallback([](EditLine *editline) { + return Editline::InstanceFor(editline)->Prompt(); + }); // Commands used for multiline support, registered whether or not they're // used - el_wset(m_editline, EL_ADDFN, EditLineConstString("lldb-break-line"), - EditLineConstString("Insert a line break"), - (EditlineCommandCallbackType)([](EditLine *editline, int ch) { - return Editline::InstanceFor(editline)->BreakLineCommand(ch); - })); - el_wset(m_editline, EL_ADDFN, EditLineConstString("lldb-end-or-add-line"), - EditLineConstString("End editing or continue when incomplete"), - (EditlineCommandCallbackType)([](EditLine *editline, int ch) { - return Editline::InstanceFor(editline)->EndOrAddLineCommand(ch); - })); - el_wset(m_editline, EL_ADDFN, EditLineConstString("lldb-delete-next-char"), - EditLineConstString("Delete next character"), - (EditlineCommandCallbackType)([](EditLine *editline, int ch) { - return Editline::InstanceFor(editline)->DeleteNextCharCommand(ch); - })); - el_wset( - m_editline, EL_ADDFN, EditLineConstString("lldb-delete-previous-char"), + AddFunctionToEditLine( + EditLineConstString("lldb-break-line"), + EditLineConstString("Insert a line break"), + [](EditLine *editline, int ch) { + return Editline::InstanceFor(editline)->BreakLineCommand(ch); + }); + + AddFunctionToEditLine( + EditLineConstString("lldb-end-or-add-line"), + EditLineConstString("End editing or continue when incomplete"), + [](EditLine *editline, int ch) { + return Editline::InstanceFor(editline)->EndOrAddLineCommand(ch); + }); + AddFunctionToEditLine( + EditLineConstString("lldb-delete-next-char"), + EditLineConstString("Delete next character"), + [](EditLine *editline, int ch) { + return Editline::InstanceFor(editline)->DeleteNextCharCommand(ch); + }); + AddFunctionToEditLine( + EditLineConstString("lldb-delete-previous-char"), EditLineConstString("Delete previous character"), - (EditlineCommandCallbackType)([](EditLine *editline, int ch) { + [](EditLine *editline, int ch) { return Editline::InstanceFor(editline)->DeletePreviousCharCommand(ch); - })); - el_wset(m_editline, EL_ADDFN, EditLineConstString("lldb-previous-line"), - EditLineConstString("Move to previous line"), - (EditlineCommandCallbackType)([](EditLine *editline, int ch) { - return Editline::InstanceFor(editline)->PreviousLineCommand(ch); - })); - el_wset(m_editline, EL_ADDFN, EditLineConstString("lldb-next-line"), - EditLineConstString("Move to next line"), - (EditlineCommandCallbackType)([](EditLine *editline, int ch) { - return Editline::InstanceFor(editline)->NextLineCommand(ch); - })); - el_wset(m_editline, EL_ADDFN, EditLineConstString("lldb-previous-history"), - EditLineConstString("Move to previous history"), - (EditlineCommandCallbackType)([](EditLine *editline, int ch) { - return Editline::InstanceFor(editline)->PreviousHistoryCommand(ch); - })); - el_wset(m_editline, EL_ADDFN, EditLineConstString("lldb-next-history"), - EditLineConstString("Move to next history"), - (EditlineCommandCallbackType)([](EditLine *editline, int ch) { - return Editline::InstanceFor(editline)->NextHistoryCommand(ch); - })); - el_wset(m_editline, EL_ADDFN, EditLineConstString("lldb-buffer-start"), - EditLineConstString("Move to start of buffer"), - (EditlineCommandCallbackType)([](EditLine *editline, int ch) { - return Editline::InstanceFor(editline)->BufferStartCommand(ch); - })); - el_wset(m_editline, EL_ADDFN, EditLineConstString("lldb-buffer-end"), - EditLineConstString("Move to end of buffer"), - (EditlineCommandCallbackType)([](EditLine *editline, int ch) { - return Editline::InstanceFor(editline)->BufferEndCommand(ch); - })); - el_wset(m_editline, EL_ADDFN, EditLineConstString("lldb-fix-indentation"), - EditLineConstString("Fix line indentation"), - (EditlineCommandCallbackType)([](EditLine *editline, int ch) { - return Editline::InstanceFor(editline)->FixIndentationCommand(ch); - })); + }); + AddFunctionToEditLine( + EditLineConstString("lldb-previous-line"), + EditLineConstString("Move to previous line"), + [](EditLine *editline, int ch) { + return Editline::InstanceFor(editline)->PreviousLineCommand(ch); + }); + AddFunctionToEditLine( + EditLineConstString("lldb-next-line"), + EditLineConstString("Move to next line"), [](EditLine *editline, int ch) { + return Editline::InstanceFor(editline)->NextLineCommand(ch); + }); + AddFunctionToEditLine( + EditLineConstString("lldb-previous-history"), + EditLineConstString("Move to previous history"), + [](EditLine *editline, int ch) { + return Editline::InstanceFor(editline)->PreviousHistoryCommand(ch); + }); + AddFunctionToEditLine( + EditLineConstString("lldb-next-history"), + EditLineConstString("Move to next history"), + [](EditLine *editline, int ch) { + return Editline::InstanceFor(editline)->NextHistoryCommand(ch); + }); + AddFunctionToEditLine( + EditLineConstString("lldb-buffer-start"), + EditLineConstString("Move to start of buffer"), + [](EditLine *editline, int ch) { + return Editline::InstanceFor(editline)->BufferStartCommand(ch); + }); + AddFunctionToEditLine( + EditLineConstString("lldb-buffer-end"), + EditLineConstString("Move to end of buffer"), + [](EditLine *editline, int ch) { + return Editline::InstanceFor(editline)->BufferEndCommand(ch); + }); + AddFunctionToEditLine( + EditLineConstString("lldb-fix-indentation"), + EditLineConstString("Fix line indentation"), + [](EditLine *editline, int ch) { + return Editline::InstanceFor(editline)->FixIndentationCommand(ch); + }); // Register the complete callback under two names for compatibility with // older clients using custom .editrc files (largely because libedit has a @@ -1143,16 +1230,50 @@ void Editline::ConfigureEditor(bool multiline) { int ch) { return Editline::InstanceFor(editline)->TabCommand(ch); }; - el_wset(m_editline, EL_ADDFN, EditLineConstString("lldb-complete"), - EditLineConstString("Invoke completion"), complete_callback); - el_wset(m_editline, EL_ADDFN, EditLineConstString("lldb_complete"), - EditLineConstString("Invoke completion"), complete_callback); + AddFunctionToEditLine(EditLineConstString("lldb-complete"), + EditLineConstString("Invoke completion"), + complete_callback); + AddFunctionToEditLine(EditLineConstString("lldb_complete"), + EditLineConstString("Invoke completion"), + complete_callback); // General bindings we don't mind being overridden if (!multiline) { el_set(m_editline, EL_BIND, "^r", "em-inc-search-prev", NULL); // Cycle through backwards search, entering string + + if (m_suggestion_callback) { + AddFunctionToEditLine( + EditLineConstString("lldb-apply-complete"), + EditLineConstString("Adopt autocompletion"), + [](EditLine *editline, int ch) { + return Editline::InstanceFor(editline)->ApplyAutosuggestCommand(ch); + }); + + el_set(m_editline, EL_BIND, "^f", "lldb-apply-complete", + NULL); // Apply a part that is suggested automatically + + AddFunctionToEditLine( + EditLineConstString("lldb-typed-character"), + EditLineConstString("Typed character"), + [](EditLine *editline, int ch) { + return Editline::InstanceFor(editline)->TypedCharacter(ch); + }); + + char bind_key[2] = {0, 0}; + llvm::StringRef ascii_chars = + "abcdefghijklmnopqrstuvwxzyABCDEFGHIJKLMNOPQRSTUVWXZY1234567890!\"#$%" + "&'()*+,./:;<=>?@[]_`{|}~ "; + for (char c : ascii_chars) { + bind_key[0] = c; + el_set(m_editline, EL_BIND, bind_key, "lldb-typed-character", NULL); + } + el_set(m_editline, EL_BIND, "\\-", "lldb-typed-character", NULL); + el_set(m_editline, EL_BIND, "\\^", "lldb-typed-character", NULL); + el_set(m_editline, EL_BIND, "\\\\", "lldb-typed-character", NULL); + } } + el_set(m_editline, EL_BIND, "^w", "ed-delete-prev-word", NULL); // Delete previous word, behave like bash in emacs mode el_set(m_editline, EL_BIND, "\t", "lldb-complete", @@ -1172,11 +1293,12 @@ void Editline::ConfigureEditor(bool multiline) { el_source(m_editline, nullptr); // Register an internal binding that external developers shouldn't use - el_wset(m_editline, EL_ADDFN, EditLineConstString("lldb-revert-line"), - EditLineConstString("Revert line to saved state"), - (EditlineCommandCallbackType)([](EditLine *editline, int ch) { - return Editline::InstanceFor(editline)->RevertLineCommand(ch); - })); + AddFunctionToEditLine( + EditLineConstString("lldb-revert-line"), + EditLineConstString("Revert line to saved state"), + [](EditLine *editline, int ch) { + return Editline::InstanceFor(editline)->RevertLineCommand(ch); + }); // Register keys that perform auto-indent correction if (m_fix_indentation_callback && m_fix_indentation_callback_chars) { @@ -1363,27 +1485,6 @@ bool Editline::Cancel() { return result; } -void Editline::SetAutoCompleteCallback(CompleteCallbackType callback, - void *baton) { - m_completion_callback = callback; - m_completion_callback_baton = baton; -} - -void Editline::SetIsInputCompleteCallback(IsInputCompleteCallbackType callback, - void *baton) { - m_is_input_complete_callback = callback; - m_is_input_complete_callback_baton = baton; -} - -bool Editline::SetFixIndentationCallback(FixIndentationCallbackType callback, - void *baton, - const char *indent_chars) { - m_fix_indentation_callback = callback; - m_fix_indentation_callback_baton = baton; - m_fix_indentation_callback_chars = indent_chars; - return false; -} - bool Editline::GetLine(std::string &line, bool &interrupted) { ConfigureEditor(false); m_input_lines = std::vector(); diff --git a/gnu/llvm/lldb/source/Host/common/File.cpp b/gnu/llvm/lldb/source/Host/common/File.cpp index a5b970907e6..e302e0a0de0 100644 --- a/gnu/llvm/lldb/source/Host/common/File.cpp +++ b/gnu/llvm/lldb/source/Host/common/File.cpp @@ -8,11 +8,11 @@ #include "lldb/Host/File.h" -#include +#include +#include +#include +#include #include -#include -#include -#include #ifdef _WIN32 #include "lldb/Host/windows/windows.h" diff --git a/gnu/llvm/lldb/source/Host/common/FileAction.cpp b/gnu/llvm/lldb/source/Host/common/FileAction.cpp index 8b4e7f4c220..e399c7ec47c 100644 --- a/gnu/llvm/lldb/source/Host/common/FileAction.cpp +++ b/gnu/llvm/lldb/source/Host/common/FileAction.cpp @@ -16,8 +16,7 @@ using namespace lldb_private; // FileAction member functions -FileAction::FileAction() - : m_action(eFileActionNone), m_fd(-1), m_arg(-1), m_file_spec() {} +FileAction::FileAction() : m_file_spec() {} void FileAction::Clear() { m_action = eFileActionNone; diff --git a/gnu/llvm/lldb/source/Host/common/FileSystem.cpp b/gnu/llvm/lldb/source/Host/common/FileSystem.cpp index 0fa27d131e1..a2c3b3556a6 100644 --- a/gnu/llvm/lldb/source/Host/common/FileSystem.cpp +++ b/gnu/llvm/lldb/source/Host/common/FileSystem.cpp @@ -19,11 +19,11 @@ #include "llvm/Support/Program.h" #include "llvm/Support/Threading.h" -#include +#include +#include +#include +#include #include -#include -#include -#include #ifdef _WIN32 #include "lldb/Host/windows/windows.h" @@ -49,7 +49,7 @@ void FileSystem::Initialize() { InstanceImpl().emplace(); } -void FileSystem::Initialize(std::shared_ptr collector) { +void FileSystem::Initialize(std::shared_ptr collector) { lldbassert(!InstanceImpl() && "Already initialized."); InstanceImpl().emplace(collector); } @@ -307,7 +307,7 @@ FileSystem::CreateDataBuffer(const llvm::Twine &path, uint64_t size, std::unique_ptr buffer; if (size == 0) { auto buffer_or_error = - llvm::WritableMemoryBuffer::getFile(*external_path, -1, is_volatile); + llvm::WritableMemoryBuffer::getFile(*external_path, is_volatile); if (!buffer_or_error) return nullptr; buffer = std::move(*buffer_or_error); @@ -360,6 +360,22 @@ bool FileSystem::ResolveExecutableLocation(FileSpec &file_spec) { return true; } +bool FileSystem::GetHomeDirectory(SmallVectorImpl &path) const { + if (!m_home_directory.empty()) { + path.assign(m_home_directory.begin(), m_home_directory.end()); + return true; + } + return llvm::sys::path::home_directory(path); +} + +bool FileSystem::GetHomeDirectory(FileSpec &file_spec) const { + SmallString<128> home_dir; + if (!GetHomeDirectory(home_dir)) + return false; + file_spec.SetPath(home_dir); + return true; +} + static int OpenWithFS(const FileSystem &fs, const char *path, int flags, int mode) { return const_cast(fs).Open(path, flags, mode); @@ -462,20 +478,18 @@ ErrorOr FileSystem::GetExternalPath(const llvm::Twine &path) { return path.str(); // If VFS mapped we know the underlying FS is a RedirectingFileSystem. - ErrorOr E = - static_cast(*m_fs).lookupPath(path); - if (!E) { - if (E.getError() == llvm::errc::no_such_file_or_directory) { + ErrorOr Result = + static_cast(*m_fs).lookupPath(path.str()); + if (!Result) { + if (Result.getError() == llvm::errc::no_such_file_or_directory) { return path.str(); } - return E.getError(); + return Result.getError(); } - auto *F = dyn_cast(*E); - if (!F) - return make_error_code(llvm::errc::not_supported); - - return F->getExternalContentsPath().str(); + if (Optional ExtRedirect = Result->getExternalRedirect()) + return std::string(*ExtRedirect); + return make_error_code(llvm::errc::not_supported); } ErrorOr FileSystem::GetExternalPath(const FileSpec &file_spec) { @@ -495,3 +509,7 @@ void FileSystem::Collect(const llvm::Twine &file) { else m_collector->addFile(file); } + +void FileSystem::SetHomeDirectory(std::string home_directory) { + m_home_directory = std::move(home_directory); +} diff --git a/gnu/llvm/lldb/source/Host/common/GetOptInc.cpp b/gnu/llvm/lldb/source/Host/common/GetOptInc.cpp index 62ce7428e8c..c2044b68732 100644 --- a/gnu/llvm/lldb/source/Host/common/GetOptInc.cpp +++ b/gnu/llvm/lldb/source/Host/common/GetOptInc.cpp @@ -12,9 +12,9 @@ defined(REPLACE_GETOPT_LONG_ONLY) // getopt.cpp -#include -#include -#include +#include +#include +#include #if defined(REPLACE_GETOPT) int opterr = 1; /* if error message should be printed */ diff --git a/gnu/llvm/lldb/source/Host/common/Host.cpp b/gnu/llvm/lldb/source/Host/common/Host.cpp index 4128fa19c14..d14ebe99fd1 100644 --- a/gnu/llvm/lldb/source/Host/common/Host.cpp +++ b/gnu/llvm/lldb/source/Host/common/Host.cpp @@ -7,9 +7,9 @@ //===----------------------------------------------------------------------===// // C includes -#include -#include -#include +#include +#include +#include #include #ifndef _WIN32 #include @@ -60,6 +60,7 @@ #include "lldb/Utility/FileSpec.h" #include "lldb/Utility/Log.h" #include "lldb/Utility/Predicate.h" +#include "lldb/Utility/ReproducerProvider.h" #include "lldb/Utility/Status.h" #include "lldb/lldb-private-forward.h" #include "llvm/ADT/SmallString.h" @@ -441,14 +442,12 @@ bool Host::FindProcessThreads(const lldb::pid_t pid, TidMap &tids_to_attach) { #endif struct ShellInfo { - ShellInfo() - : process_reaped(false), pid(LLDB_INVALID_PROCESS_ID), signo(-1), - status(-1) {} + ShellInfo() : process_reaped(false) {} lldb_private::Predicate process_reaped; - lldb::pid_t pid; - int signo; - int status; + lldb::pid_t pid = LLDB_INVALID_PROCESS_ID; + int signo = -1; + int status = -1; }; static bool @@ -466,14 +465,24 @@ MonitorShellCommand(std::shared_ptr shell_info, lldb::pid_t pid, return true; } -Status Host::RunShellCommand(const char *command, const FileSpec &working_dir, - int *status_ptr, int *signo_ptr, - std::string *command_output_ptr, +Status Host::RunShellCommand(llvm::StringRef command, + const FileSpec &working_dir, int *status_ptr, + int *signo_ptr, std::string *command_output_ptr, + const Timeout &timeout, + bool run_in_shell, bool hide_stderr) { + return RunShellCommand(llvm::StringRef(), Args(command), working_dir, + status_ptr, signo_ptr, command_output_ptr, timeout, + run_in_shell, hide_stderr); +} + +Status Host::RunShellCommand(llvm::StringRef shell_path, + llvm::StringRef command, + const FileSpec &working_dir, int *status_ptr, + int *signo_ptr, std::string *command_output_ptr, const Timeout &timeout, - bool run_in_default_shell, - bool hide_stderr) { - return RunShellCommand(Args(command), working_dir, status_ptr, signo_ptr, - command_output_ptr, timeout, run_in_default_shell, + bool run_in_shell, bool hide_stderr) { + return RunShellCommand(shell_path, Args(command), working_dir, status_ptr, + signo_ptr, command_output_ptr, timeout, run_in_shell, hide_stderr); } @@ -481,20 +490,32 @@ Status Host::RunShellCommand(const Args &args, const FileSpec &working_dir, int *status_ptr, int *signo_ptr, std::string *command_output_ptr, const Timeout &timeout, - bool run_in_default_shell, - bool hide_stderr) { + bool run_in_shell, bool hide_stderr) { + return RunShellCommand(llvm::StringRef(), args, working_dir, status_ptr, + signo_ptr, command_output_ptr, timeout, run_in_shell, + hide_stderr); +} + +Status Host::RunShellCommand(llvm::StringRef shell_path, const Args &args, + const FileSpec &working_dir, int *status_ptr, + int *signo_ptr, std::string *command_output_ptr, + const Timeout &timeout, + bool run_in_shell, bool hide_stderr) { Status error; ProcessLaunchInfo launch_info; launch_info.SetArchitecture(HostInfo::GetArchitecture()); - if (run_in_default_shell) { + if (run_in_shell) { // Run the command in a shell - launch_info.SetShell(HostInfo::GetDefaultShell()); + FileSpec shell = HostInfo::GetDefaultShell(); + if (!shell_path.empty()) + shell.SetPath(shell_path); + + launch_info.SetShell(shell); launch_info.GetArguments().AppendArguments(args); - const bool localhost = true; const bool will_debug = false; const bool first_arg_is_full_shell_command = false; launch_info.ConvertArgumentsForLaunchingInShell( - error, localhost, will_debug, first_arg_is_full_shell_command, 0); + error, will_debug, first_arg_is_full_shell_command, 0); } else { // No shell, just run it const bool first_arg_is_executable = true; diff --git a/gnu/llvm/lldb/source/Host/common/HostInfoBase.cpp b/gnu/llvm/lldb/source/Host/common/HostInfoBase.cpp index 333137a7fd2..a6239a3208b 100644 --- a/gnu/llvm/lldb/source/Host/common/HostInfoBase.cpp +++ b/gnu/llvm/lldb/source/Host/common/HostInfoBase.cpp @@ -31,12 +31,7 @@ using namespace lldb; using namespace lldb_private; namespace { -// The HostInfoBaseFields is a work around for windows not supporting static -// variables correctly in a thread safe way. Really each of the variables in -// HostInfoBaseFields should live in the functions in which they are used and -// each one should be static, but the work around is in place to avoid this -// restriction. Ick. - +/// Contains the state of the HostInfoBase plugin. struct HostInfoBaseFields { ~HostInfoBaseFields() { if (FileSystem::Instance().Exists(m_lldb_process_tmp_dir)) { @@ -71,13 +66,18 @@ struct HostInfoBaseFields { llvm::once_flag m_lldb_global_tmp_dir_once; FileSpec m_lldb_global_tmp_dir; }; +} // namespace -HostInfoBaseFields *g_fields = nullptr; -} +static HostInfoBaseFields *g_fields = nullptr; +static HostInfoBase::SharedLibraryDirectoryHelper *g_shlib_dir_helper = nullptr; -void HostInfoBase::Initialize() { g_fields = new HostInfoBaseFields(); } +void HostInfoBase::Initialize(SharedLibraryDirectoryHelper *helper) { + g_shlib_dir_helper = helper; + g_fields = new HostInfoBaseFields(); +} void HostInfoBase::Terminate() { + g_shlib_dir_helper = nullptr; delete g_fields; g_fields = nullptr; } @@ -249,9 +249,8 @@ bool HostInfoBase::ComputeSharedLibraryDirectory(FileSpec &file_spec) { reinterpret_cast( HostInfoBase::ComputeSharedLibraryDirectory))); - // This is necessary because when running the testsuite the shlib might be a - // symbolic link inside the Python resource dir. - FileSystem::Instance().ResolveSymbolicLink(lldb_file_spec, lldb_file_spec); + if (g_shlib_dir_helper) + g_shlib_dir_helper(lldb_file_spec); // Remove the filename so that this FileSpec only represents the directory. file_spec.GetDirectory() = lldb_file_spec.GetDirectory(); diff --git a/gnu/llvm/lldb/source/Host/common/HostNativeThreadBase.cpp b/gnu/llvm/lldb/source/Host/common/HostNativeThreadBase.cpp index a79431f61d8..b15160b143c 100644 --- a/gnu/llvm/lldb/source/Host/common/HostNativeThreadBase.cpp +++ b/gnu/llvm/lldb/source/Host/common/HostNativeThreadBase.cpp @@ -17,9 +17,6 @@ using namespace lldb; using namespace lldb_private; -HostNativeThreadBase::HostNativeThreadBase() - : m_thread(LLDB_INVALID_HOST_THREAD), m_result(0) {} - HostNativeThreadBase::HostNativeThreadBase(thread_t thread) : m_thread(thread), m_result(0) {} diff --git a/gnu/llvm/lldb/source/Host/common/HostProcess.cpp b/gnu/llvm/lldb/source/Host/common/HostProcess.cpp index 256a73bb671..06dd192013b 100644 --- a/gnu/llvm/lldb/source/Host/common/HostProcess.cpp +++ b/gnu/llvm/lldb/source/Host/common/HostProcess.cpp @@ -18,7 +18,7 @@ HostProcess::HostProcess() : m_native_process(new HostNativeProcess) {} HostProcess::HostProcess(lldb::process_t process) : m_native_process(new HostNativeProcess(process)) {} -HostProcess::~HostProcess() {} +HostProcess::~HostProcess() = default; Status HostProcess::Terminate() { return m_native_process->Terminate(); } diff --git a/gnu/llvm/lldb/source/Host/common/MainLoop.cpp b/gnu/llvm/lldb/source/Host/common/MainLoop.cpp index 02cabbc9355..d36587ce234 100644 --- a/gnu/llvm/lldb/source/Host/common/MainLoop.cpp +++ b/gnu/llvm/lldb/source/Host/common/MainLoop.cpp @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include // Multiplexing is implemented using kqueue on systems that support it (BSD @@ -302,13 +302,15 @@ MainLoop::RegisterSignal(int signo, const Callback &callback, Status &error) { error.SetErrorString("Signal polling is not supported on this platform."); return nullptr; #else - if (m_signals.find(signo) != m_signals.end()) { - error.SetErrorStringWithFormat("Signal %d already monitored.", signo); - return nullptr; + auto signal_it = m_signals.find(signo); + if (signal_it != m_signals.end()) { + auto callback_it = signal_it->second.callbacks.insert( + signal_it->second.callbacks.end(), callback); + return SignalHandleUP(new SignalHandle(*this, signo, callback_it)); } SignalInfo info; - info.callback = callback; + info.callbacks.push_back(callback); struct sigaction new_action; new_action.sa_sigaction = &SignalHandler; new_action.sa_flags = SA_SIGINFO; @@ -338,9 +340,10 @@ MainLoop::RegisterSignal(int signo, const Callback &callback, Status &error) { &new_action.sa_mask, &old_set); assert(ret == 0 && "pthread_sigmask failed"); info.was_blocked = sigismember(&old_set, signo); - m_signals.insert({signo, info}); + auto insert_ret = m_signals.insert({signo, info}); - return SignalHandleUP(new SignalHandle(*this, signo)); + return SignalHandleUP(new SignalHandle( + *this, signo, insert_ret.first->second.callbacks.begin())); #endif } @@ -350,13 +353,19 @@ void MainLoop::UnregisterReadObject(IOObject::WaitableHandle handle) { assert(erased); } -void MainLoop::UnregisterSignal(int signo) { +void MainLoop::UnregisterSignal(int signo, + std::list::iterator callback_it) { #if SIGNAL_POLLING_UNSUPPORTED Status("Signal polling is not supported on this platform."); #else auto it = m_signals.find(signo); assert(it != m_signals.end()); + it->second.callbacks.erase(callback_it); + // Do not remove the signal handler unless all callbacks have been erased. + if (!it->second.callbacks.empty()) + return; + sigaction(signo, &it->second.old_action, nullptr); sigset_t set; @@ -398,8 +407,14 @@ Status MainLoop::Run() { void MainLoop::ProcessSignal(int signo) { auto it = m_signals.find(signo); - if (it != m_signals.end()) - it->second.callback(*this); // Do the work + if (it != m_signals.end()) { + // The callback may actually register/unregister signal handlers, + // so we need to create a copy first. + llvm::SmallVector callbacks_to_run{ + it->second.callbacks.begin(), it->second.callbacks.end()}; + for (auto &x : callbacks_to_run) + x(*this); // Do the work + } } void MainLoop::ProcessReadObject(IOObject::WaitableHandle handle) { diff --git a/gnu/llvm/lldb/source/Host/common/NativeProcessProtocol.cpp b/gnu/llvm/lldb/source/Host/common/NativeProcessProtocol.cpp index a4d0b4181d5..ea80a05430f 100644 --- a/gnu/llvm/lldb/source/Host/common/NativeProcessProtocol.cpp +++ b/gnu/llvm/lldb/source/Host/common/NativeProcessProtocol.cpp @@ -25,10 +25,8 @@ using namespace lldb_private; NativeProcessProtocol::NativeProcessProtocol(lldb::pid_t pid, int terminal_fd, NativeDelegate &delegate) - : m_pid(pid), m_terminal_fd(terminal_fd) { - bool registered = RegisterNativeDelegate(delegate); - assert(registered); - (void)registered; + : m_pid(pid), m_delegate(delegate), m_terminal_fd(terminal_fd) { + delegate.InitializeDelegate(this); } lldb_private::Status NativeProcessProtocol::Interrupt() { @@ -54,6 +52,19 @@ NativeProcessProtocol::GetMemoryRegionInfo(lldb::addr_t load_addr, return Status("not implemented"); } +lldb_private::Status +NativeProcessProtocol::ReadMemoryTags(int32_t type, lldb::addr_t addr, + size_t len, std::vector &tags) { + return Status("not implemented"); +} + +lldb_private::Status +NativeProcessProtocol::WriteMemoryTags(int32_t type, lldb::addr_t addr, + size_t len, + const std::vector &tags) { + return Status("not implemented"); +} + llvm::Optional NativeProcessProtocol::GetExitStatus() { if (m_state == lldb::eStateExited) return m_exit_status; @@ -295,65 +306,21 @@ Status NativeProcessProtocol::RemoveHardwareBreakpoint(lldb::addr_t addr) { return error; } -bool NativeProcessProtocol::RegisterNativeDelegate( - NativeDelegate &native_delegate) { - std::lock_guard guard(m_delegates_mutex); - if (std::find(m_delegates.begin(), m_delegates.end(), &native_delegate) != - m_delegates.end()) - return false; - - m_delegates.push_back(&native_delegate); - native_delegate.InitializeDelegate(this); - return true; -} - -bool NativeProcessProtocol::UnregisterNativeDelegate( - NativeDelegate &native_delegate) { - std::lock_guard guard(m_delegates_mutex); - - const auto initial_size = m_delegates.size(); - m_delegates.erase( - remove(m_delegates.begin(), m_delegates.end(), &native_delegate), - m_delegates.end()); - - // We removed the delegate if the count of delegates shrank after removing - // all copies of the given native_delegate from the vector. - return m_delegates.size() < initial_size; -} - void NativeProcessProtocol::SynchronouslyNotifyProcessStateChanged( lldb::StateType state) { Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); - std::lock_guard guard(m_delegates_mutex); - for (auto native_delegate : m_delegates) - native_delegate->ProcessStateChanged(this, state); + m_delegate.ProcessStateChanged(this, state); - if (log) { - if (!m_delegates.empty()) { - LLDB_LOGF(log, - "NativeProcessProtocol::%s: sent state notification [%s] " - "from process %" PRIu64, - __FUNCTION__, lldb_private::StateAsCString(state), GetID()); - } else { - LLDB_LOGF(log, - "NativeProcessProtocol::%s: would send state notification " - "[%s] from process %" PRIu64 ", but no delegates", - __FUNCTION__, lldb_private::StateAsCString(state), GetID()); - } - } + LLDB_LOG(log, "sent state notification [{0}] from process {1}", state, + GetID()); } void NativeProcessProtocol::NotifyDidExec() { Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); - LLDB_LOGF(log, "NativeProcessProtocol::%s - preparing to call delegates", - __FUNCTION__); + LLDB_LOG(log, "process {0} exec()ed", GetID()); - { - std::lock_guard guard(m_delegates_mutex); - for (auto native_delegate : m_delegates) - native_delegate->DidExec(this); - } + m_delegate.DidExec(this); } Status NativeProcessProtocol::SetSoftwareBreakpoint(lldb::addr_t addr, @@ -523,7 +490,8 @@ NativeProcessProtocol::GetSoftwareBreakpointTrapOpcode(size_t size_hint) { static const uint8_t g_mips64_opcode[] = {0x00, 0x00, 0x00, 0x0d}; static const uint8_t g_mips64el_opcode[] = {0x0d, 0x00, 0x00, 0x00}; static const uint8_t g_s390x_opcode[] = {0x00, 0x01}; - static const uint8_t g_ppc64le_opcode[] = {0x08, 0x00, 0xe0, 0x7f}; // trap + static const uint8_t g_ppc_opcode[] = {0x7f, 0xe0, 0x00, 0x08}; // trap + static const uint8_t g_ppcle_opcode[] = {0x08, 0x00, 0xe0, 0x7f}; // trap switch (GetArchitecture().GetMachine()) { case llvm::Triple::aarch64: @@ -545,8 +513,12 @@ NativeProcessProtocol::GetSoftwareBreakpointTrapOpcode(size_t size_hint) { case llvm::Triple::systemz: return llvm::makeArrayRef(g_s390x_opcode); + case llvm::Triple::ppc: + case llvm::Triple::ppc64: + return llvm::makeArrayRef(g_ppc_opcode); + case llvm::Triple::ppc64le: - return llvm::makeArrayRef(g_ppc64le_opcode); + return llvm::makeArrayRef(g_ppcle_opcode); default: return llvm::createStringError(llvm::inconvertibleErrorCode(), @@ -569,6 +541,8 @@ size_t NativeProcessProtocol::GetSoftwareBreakpointPCOffset() { case llvm::Triple::mips64el: case llvm::Triple::mips: case llvm::Triple::mipsel: + case llvm::Triple::ppc: + case llvm::Triple::ppc64: case llvm::Triple::ppc64le: // On these architectures the PC doesn't get updated for breakpoint hits. return 0; diff --git a/gnu/llvm/lldb/source/Host/common/NativeRegisterContext.cpp b/gnu/llvm/lldb/source/Host/common/NativeRegisterContext.cpp index 47548f90491..04d10aba4e6 100644 --- a/gnu/llvm/lldb/source/Host/common/NativeRegisterContext.cpp +++ b/gnu/llvm/lldb/source/Host/common/NativeRegisterContext.cpp @@ -22,7 +22,7 @@ NativeRegisterContext::NativeRegisterContext(NativeThreadProtocol &thread) : m_thread(thread) {} // Destructor -NativeRegisterContext::~NativeRegisterContext() {} +NativeRegisterContext::~NativeRegisterContext() = default; // FIXME revisit invalidation, process stop ids, etc. Right now we don't // support caching in NativeRegisterContext. We can do this later by utilizing @@ -60,8 +60,8 @@ NativeRegisterContext::GetRegisterInfoByName(llvm::StringRef reg_name, for (uint32_t reg = start_idx; reg < num_registers; ++reg) { const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg); - if (reg_name.equals_lower(reg_info->name) || - reg_name.equals_lower(reg_info->alt_name)) + if (reg_name.equals_insensitive(reg_info->name) || + reg_name.equals_insensitive(reg_info->alt_name)) return reg_info; } return nullptr; @@ -266,6 +266,10 @@ bool NativeRegisterContext::ClearHardwareWatchpoint(uint32_t hw_index) { return false; } +Status NativeRegisterContext::ClearWatchpointHit(uint32_t hw_index) { + return Status("not implemented"); +} + Status NativeRegisterContext::ClearAllHardwareWatchpoints() { return Status("not implemented"); } @@ -420,3 +424,32 @@ NativeRegisterContext::ConvertRegisterKindToRegisterNumber(uint32_t kind, return LLDB_INVALID_REGNUM; } + +std::vector +NativeRegisterContext::GetExpeditedRegisters(ExpeditedRegs expType) const { + if (expType == ExpeditedRegs::Minimal) { + // Expedite only a minimum set of important generic registers. + static const uint32_t k_expedited_registers[] = { + LLDB_REGNUM_GENERIC_PC, LLDB_REGNUM_GENERIC_SP, LLDB_REGNUM_GENERIC_FP, + LLDB_REGNUM_GENERIC_RA}; + + std::vector expedited_reg_nums; + for (uint32_t gen_reg : k_expedited_registers) { + uint32_t reg_num = + ConvertRegisterKindToRegisterNumber(eRegisterKindGeneric, gen_reg); + if (reg_num == LLDB_INVALID_REGNUM) + continue; // Target does not support the given register. + else + expedited_reg_nums.push_back(reg_num); + } + + return expedited_reg_nums; + } + + if (GetRegisterSetCount() > 0 && expType == ExpeditedRegs::Full) + return std::vector(GetRegisterSet(0)->registers, + GetRegisterSet(0)->registers + + GetRegisterSet(0)->num_registers); + + return std::vector(); +} diff --git a/gnu/llvm/lldb/source/Host/common/OptionParser.cpp b/gnu/llvm/lldb/source/Host/common/OptionParser.cpp index b5c7ea66732..0274fdc4ac3 100644 --- a/gnu/llvm/lldb/source/Host/common/OptionParser.cpp +++ b/gnu/llvm/lldb/source/Host/common/OptionParser.cpp @@ -8,6 +8,7 @@ #include "lldb/Host/OptionParser.h" #include "lldb/Host/HostGetOpt.h" +#include "lldb/Utility/OptionDefinition.h" #include "lldb/lldb-private-types.h" #include diff --git a/gnu/llvm/lldb/source/Host/common/ProcessLaunchInfo.cpp b/gnu/llvm/lldb/source/Host/common/ProcessLaunchInfo.cpp index 4bc8cda7a00..8d281b80e8f 100644 --- a/gnu/llvm/lldb/source/Host/common/ProcessLaunchInfo.cpp +++ b/gnu/llvm/lldb/source/Host/common/ProcessLaunchInfo.cpp @@ -20,7 +20,7 @@ #include "llvm/Support/FileSystem.h" #if !defined(_WIN32) -#include +#include #endif using namespace lldb; @@ -30,9 +30,9 @@ using namespace lldb_private; ProcessLaunchInfo::ProcessLaunchInfo() : ProcessInfo(), m_working_dir(), m_plugin_name(), m_flags(0), - m_file_actions(), m_pty(new PseudoTerminal), m_resume_count(0), - m_monitor_callback(nullptr), m_monitor_callback_baton(nullptr), - m_monitor_signals(false), m_listener_sp(), m_hijack_listener_sp() {} + m_file_actions(), m_pty(new PseudoTerminal), m_monitor_callback(nullptr), + m_listener_sp(), m_hijack_listener_sp(), m_scripted_process_class_name(), + m_scripted_process_dictionary_sp() {} ProcessLaunchInfo::ProcessLaunchInfo(const FileSpec &stdin_file_spec, const FileSpec &stdout_file_spec, @@ -42,7 +42,8 @@ ProcessLaunchInfo::ProcessLaunchInfo(const FileSpec &stdin_file_spec, : ProcessInfo(), m_working_dir(), m_plugin_name(), m_flags(launch_flags), m_file_actions(), m_pty(new PseudoTerminal), m_resume_count(0), m_monitor_callback(nullptr), m_monitor_callback_baton(nullptr), - m_monitor_signals(false), m_listener_sp(), m_hijack_listener_sp() { + m_monitor_signals(false), m_listener_sp(), m_hijack_listener_sp(), + m_scripted_process_class_name(), m_scripted_process_dictionary_sp() { if (stdin_file_spec) { FileAction file_action; const bool read = true; @@ -171,6 +172,8 @@ void ProcessLaunchInfo::Clear() { m_resume_count = 0; m_listener_sp.reset(); m_hijack_listener_sp.reset(); + m_scripted_process_class_name.clear(); + m_scripted_process_dictionary_sp.reset(); } void ProcessLaunchInfo::SetMonitorProcessCallback( @@ -218,11 +221,10 @@ llvm::Error ProcessLaunchInfo::SetUpPtyRedirection() { // do for now. open_flags |= O_CLOEXEC; #endif - if (!m_pty->OpenFirstAvailablePrimary(open_flags, nullptr, 0)) { - return llvm::createStringError(llvm::inconvertibleErrorCode(), - "PTY::OpenFirstAvailablePrimary failed"); - } - const FileSpec secondary_file_spec(m_pty->GetSecondaryName(nullptr, 0)); + if (llvm::Error Err = m_pty->OpenFirstAvailablePrimary(open_flags)) + return Err; + + const FileSpec secondary_file_spec(m_pty->GetSecondaryName()); // Only use the secondary tty if we don't have anything specified for // input and don't have an action for stdin @@ -242,8 +244,8 @@ llvm::Error ProcessLaunchInfo::SetUpPtyRedirection() { } bool ProcessLaunchInfo::ConvertArgumentsForLaunchingInShell( - Status &error, bool localhost, bool will_debug, - bool first_arg_is_full_shell_command, int32_t num_resumes) { + Status &error, bool will_debug, bool first_arg_is_full_shell_command, + uint32_t num_resumes) { error.Clear(); if (GetFlags().Test(eLaunchFlagLaunchInShell)) { @@ -254,7 +256,6 @@ bool ProcessLaunchInfo::ConvertArgumentsForLaunchingInShell( if (argv == nullptr || argv[0] == nullptr) return false; Args shell_arguments; - std::string safe_arg; shell_arguments.AppendArgument(shell_executable); const llvm::Triple &triple = GetArchitecture().GetTriple(); if (triple.getOS() == llvm::Triple::Win32 && @@ -331,9 +332,10 @@ bool ProcessLaunchInfo::ConvertArgumentsForLaunchingInShell( return false; } else { for (size_t i = 0; argv[i] != nullptr; ++i) { - const char *arg = - Args::GetShellSafeArgument(m_shell, argv[i], safe_arg); - shell_command.Printf(" %s", arg); + std::string safe_arg = Args::GetShellSafeArgument(m_shell, argv[i]); + // Add a space to separate this arg from the previous one. + shell_command.PutCString(" "); + shell_command.PutCString(safe_arg); } } shell_arguments.AppendArgument(shell_command.GetString()); diff --git a/gnu/llvm/lldb/source/Host/common/ProcessRunLock.cpp b/gnu/llvm/lldb/source/Host/common/ProcessRunLock.cpp index 3b6f033d33a..aee15779d91 100644 --- a/gnu/llvm/lldb/source/Host/common/ProcessRunLock.cpp +++ b/gnu/llvm/lldb/source/Host/common/ProcessRunLock.cpp @@ -11,7 +11,7 @@ namespace lldb_private { -ProcessRunLock::ProcessRunLock() : m_running(false) { +ProcessRunLock::ProcessRunLock() { int err = ::pthread_rwlock_init(&m_rwlock, nullptr); (void)err; } diff --git a/gnu/llvm/lldb/source/Host/common/PseudoTerminal.cpp b/gnu/llvm/lldb/source/Host/common/PseudoTerminal.cpp index 72549f1c88a..dce4c5185c7 100644 --- a/gnu/llvm/lldb/source/Host/common/PseudoTerminal.cpp +++ b/gnu/llvm/lldb/source/Host/common/PseudoTerminal.cpp @@ -8,12 +8,14 @@ #include "lldb/Host/PseudoTerminal.h" #include "lldb/Host/Config.h" - +#include "llvm/Support/Errc.h" #include "llvm/Support/Errno.h" - -#include -#include -#include +#include +#include +#include +#include +#include +#include #if defined(TIOCSCTTY) #include #endif @@ -26,15 +28,8 @@ int posix_openpt(int flags); using namespace lldb_private; -// Write string describing error number -static void ErrnoToStr(char *error_str, size_t error_len) { - std::string strerror = llvm::sys::StrError(); - ::snprintf(error_str, error_len, "%s", strerror.c_str()); -} - // PseudoTerminal constructor -PseudoTerminal::PseudoTerminal() - : m_primary_fd(invalid_fd), m_secondary_fd(invalid_fd) {} +PseudoTerminal::PseudoTerminal() = default; // Destructor // @@ -63,190 +58,106 @@ void PseudoTerminal::CloseSecondaryFileDescriptor() { } } -// Open the first available pseudo terminal with OFLAG as the permissions. The -// file descriptor is stored in this object and can be accessed with the -// PrimaryFileDescriptor() accessor. The ownership of the primary file -// descriptor can be released using the ReleasePrimaryFileDescriptor() accessor. -// If this object has a valid primary files descriptor when its destructor is -// called, it will close the primary file descriptor, therefore clients must -// call ReleasePrimaryFileDescriptor() if they wish to use the primary file -// descriptor after this object is out of scope or destroyed. -// -// RETURNS: -// True when successful, false indicating an error occurred. -bool PseudoTerminal::OpenFirstAvailablePrimary(int oflag, char *error_str, - size_t error_len) { - if (error_str) - error_str[0] = '\0'; - +llvm::Error PseudoTerminal::OpenFirstAvailablePrimary(int oflag) { #if LLDB_ENABLE_POSIX // Open the primary side of a pseudo terminal m_primary_fd = ::posix_openpt(oflag); if (m_primary_fd < 0) { - if (error_str) - ErrnoToStr(error_str, error_len); - return false; + return llvm::errorCodeToError( + std::error_code(errno, std::generic_category())); } // Grant access to the secondary pseudo terminal if (::grantpt(m_primary_fd) < 0) { - if (error_str) - ErrnoToStr(error_str, error_len); + std::error_code EC(errno, std::generic_category()); ClosePrimaryFileDescriptor(); - return false; + return llvm::errorCodeToError(EC); } // Clear the lock flag on the secondary pseudo terminal if (::unlockpt(m_primary_fd) < 0) { - if (error_str) - ErrnoToStr(error_str, error_len); + std::error_code EC(errno, std::generic_category()); ClosePrimaryFileDescriptor(); - return false; + return llvm::errorCodeToError(EC); } - return true; + return llvm::Error::success(); #else - if (error_str) - ::snprintf(error_str, error_len, "%s", "pseudo terminal not supported"); - return false; + return llvm::errorCodeToError(llvm::errc::not_supported); #endif } -// Open the secondary pseudo terminal for the current primary pseudo terminal. A -// primary pseudo terminal should already be valid prior to calling this -// function (see OpenFirstAvailablePrimary()). The file descriptor is stored -// this object's member variables and can be accessed via the -// GetSecondaryFileDescriptor(), or released using the -// ReleaseSecondaryFileDescriptor() member function. -// -// RETURNS: -// True when successful, false indicating an error occurred. -bool PseudoTerminal::OpenSecondary(int oflag, char *error_str, - size_t error_len) { - if (error_str) - error_str[0] = '\0'; - +llvm::Error PseudoTerminal::OpenSecondary(int oflag) { CloseSecondaryFileDescriptor(); - // Open the primary side of a pseudo terminal - const char *secondary_name = GetSecondaryName(error_str, error_len); - - if (secondary_name == nullptr) - return false; - - m_secondary_fd = - llvm::sys::RetryAfterSignal(-1, ::open, secondary_name, oflag); - - if (m_secondary_fd < 0) { - if (error_str) - ErrnoToStr(error_str, error_len); - return false; - } + std::string name = GetSecondaryName(); + m_secondary_fd = llvm::sys::RetryAfterSignal(-1, ::open, name.c_str(), oflag); + if (m_secondary_fd >= 0) + return llvm::Error::success(); - return true; + return llvm::errorCodeToError( + std::error_code(errno, std::generic_category())); } -// Get the name of the secondary pseudo terminal. A primary pseudo terminal -// should already be valid prior to calling this function (see -// OpenFirstAvailablePrimary()). -// -// RETURNS: -// NULL if no valid primary pseudo terminal or if ptsname() fails. -// The name of the secondary pseudo terminal as a NULL terminated C string -// that comes from static memory, so a copy of the string should be -// made as subsequent calls can change this value. -const char *PseudoTerminal::GetSecondaryName(char *error_str, - size_t error_len) const { - if (error_str) - error_str[0] = '\0'; - - if (m_primary_fd < 0) { - if (error_str) - ::snprintf(error_str, error_len, "%s", - "primary file descriptor is invalid"); - return nullptr; - } - const char *secondary_name = ::ptsname(m_primary_fd); - - if (error_str && secondary_name == nullptr) - ErrnoToStr(error_str, error_len); - - return secondary_name; +std::string PseudoTerminal::GetSecondaryName() const { + assert(m_primary_fd >= 0); +#if HAVE_PTSNAME_R + char buf[PATH_MAX]; + buf[0] = '\0'; + int r = ptsname_r(m_primary_fd, buf, sizeof(buf)); + (void)r; + assert(r == 0); + return buf; +#else + static std::mutex mutex; + std::lock_guard guard(mutex); + const char *r = ptsname(m_primary_fd); + assert(r != nullptr); + return r; +#endif } -// Fork a child process and have its stdio routed to a pseudo terminal. -// -// In the parent process when a valid pid is returned, the primary file -// descriptor can be used as a read/write access to stdio of the child process. -// -// In the child process the stdin/stdout/stderr will already be routed to the -// secondary pseudo terminal and the primary file descriptor will be closed as -// it is no longer needed by the child process. -// -// This class will close the file descriptors for the primary/secondary when the -// destructor is called, so be sure to call ReleasePrimaryFileDescriptor() or -// ReleaseSecondaryFileDescriptor() if any file descriptors are going to be used -// past the lifespan of this object. -// -// RETURNS: -// in the parent process: the pid of the child, or -1 if fork fails -// in the child process: zero -lldb::pid_t PseudoTerminal::Fork(char *error_str, size_t error_len) { - if (error_str) - error_str[0] = '\0'; - pid_t pid = LLDB_INVALID_PROCESS_ID; +llvm::Expected PseudoTerminal::Fork() { #if LLDB_ENABLE_POSIX - int flags = O_RDWR; - flags |= O_CLOEXEC; - if (OpenFirstAvailablePrimary(flags, error_str, error_len)) { - // Successfully opened our primary pseudo terminal + if (llvm::Error Err = OpenFirstAvailablePrimary(O_RDWR | O_CLOEXEC)) + return std::move(Err); + + pid_t pid = ::fork(); + if (pid < 0) { + return llvm::errorCodeToError( + std::error_code(errno, std::generic_category())); + } + if (pid > 0) { + // Parent process. + return pid; + } - pid = ::fork(); - if (pid < 0) { - // Fork failed - if (error_str) - ErrnoToStr(error_str, error_len); - } else if (pid == 0) { - // Child Process - ::setsid(); + // Child Process + ::setsid(); - if (OpenSecondary(O_RDWR, error_str, error_len)) { - // Successfully opened secondary + if (llvm::Error Err = OpenSecondary(O_RDWR)) + return std::move(Err); - // Primary FD should have O_CLOEXEC set, but let's close it just in - // case... - ClosePrimaryFileDescriptor(); + // Primary FD should have O_CLOEXEC set, but let's close it just in + // case... + ClosePrimaryFileDescriptor(); #if defined(TIOCSCTTY) - // Acquire the controlling terminal - if (::ioctl(m_secondary_fd, TIOCSCTTY, (char *)0) < 0) { - if (error_str) - ErrnoToStr(error_str, error_len); - } + // Acquire the controlling terminal + if (::ioctl(m_secondary_fd, TIOCSCTTY, (char *)0) < 0) { + return llvm::errorCodeToError( + std::error_code(errno, std::generic_category())); + } #endif - // Duplicate all stdio file descriptors to the secondary pseudo terminal - if (::dup2(m_secondary_fd, STDIN_FILENO) != STDIN_FILENO) { - if (error_str && !error_str[0]) - ErrnoToStr(error_str, error_len); - } - - if (::dup2(m_secondary_fd, STDOUT_FILENO) != STDOUT_FILENO) { - if (error_str && !error_str[0]) - ErrnoToStr(error_str, error_len); - } - - if (::dup2(m_secondary_fd, STDERR_FILENO) != STDERR_FILENO) { - if (error_str && !error_str[0]) - ErrnoToStr(error_str, error_len); - } - } - } else { - // Parent Process - // Do nothing and let the pid get returned! + // Duplicate all stdio file descriptors to the secondary pseudo terminal + for (int fd : {STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO}) { + if (::dup2(m_secondary_fd, fd) != fd) { + return llvm::errorCodeToError( + std::error_code(errno, std::generic_category())); } } #endif - return pid; + return 0; } // The primary file descriptor accessor. This object retains ownership of the diff --git a/gnu/llvm/lldb/source/Host/common/Socket.cpp b/gnu/llvm/lldb/source/Host/common/Socket.cpp index 4bcf34a6b45..d1c327dcb79 100644 --- a/gnu/llvm/lldb/source/Host/common/Socket.cpp +++ b/gnu/llvm/lldb/source/Host/common/Socket.cpp @@ -41,9 +41,9 @@ #ifdef __ANDROID__ #include #include -#include -#include +#include #include +#include #include #include #endif // __ANDROID__ diff --git a/gnu/llvm/lldb/source/Host/common/StringConvert.cpp b/gnu/llvm/lldb/source/Host/common/StringConvert.cpp index e5f05e628c7..b4eb9275536 100644 --- a/gnu/llvm/lldb/source/Host/common/StringConvert.cpp +++ b/gnu/llvm/lldb/source/Host/common/StringConvert.cpp @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// -#include +#include #include "lldb/Host/StringConvert.h" diff --git a/gnu/llvm/lldb/source/Host/common/TCPSocket.cpp b/gnu/llvm/lldb/source/Host/common/TCPSocket.cpp index 047cb0e4c2b..ea7377edbd4 100644 --- a/gnu/llvm/lldb/source/Host/common/TCPSocket.cpp +++ b/gnu/llvm/lldb/source/Host/common/TCPSocket.cpp @@ -247,7 +247,7 @@ Status TCPSocket::Listen(llvm::StringRef name, int backlog) { void TCPSocket::CloseListenSockets() { for (auto socket : m_listen_sockets) - CLOSE_SOCKET(socket.first); + CLOSE_SOCKET(socket.first); m_listen_sockets.clear(); } diff --git a/gnu/llvm/lldb/source/Host/common/Terminal.cpp b/gnu/llvm/lldb/source/Host/common/Terminal.cpp index 9990dbf7435..2301abe9afb 100644 --- a/gnu/llvm/lldb/source/Host/common/Terminal.cpp +++ b/gnu/llvm/lldb/source/Host/common/Terminal.cpp @@ -12,8 +12,8 @@ #include "lldb/Host/PosixApi.h" #include "llvm/ADT/STLExtras.h" +#include #include -#include #if LLDB_ENABLE_TERMIOS #include @@ -83,15 +83,16 @@ bool Terminal::SetCanonical(bool enabled) { // Default constructor TerminalState::TerminalState() - : m_tty(), m_tflags(-1), + : m_tty() #if LLDB_ENABLE_TERMIOS - m_termios_up(), + , + m_termios_up() #endif - m_process_group(-1) { +{ } // Destructor -TerminalState::~TerminalState() {} +TerminalState::~TerminalState() = default; void TerminalState::Clear() { m_tty.Clear(); @@ -189,10 +190,10 @@ bool TerminalState::ProcessGroupIsValid() const { } // Constructor -TerminalStateSwitcher::TerminalStateSwitcher() : m_currentState(UINT32_MAX) {} +TerminalStateSwitcher::TerminalStateSwitcher() = default; // Destructor -TerminalStateSwitcher::~TerminalStateSwitcher() {} +TerminalStateSwitcher::~TerminalStateSwitcher() = default; // Returns the number of states that this switcher contains uint32_t TerminalStateSwitcher::GetNumberOfStates() const { diff --git a/gnu/llvm/lldb/source/Host/common/XML.cpp b/gnu/llvm/lldb/source/Host/common/XML.cpp index 456c879b014..c3225d3f443 100644 --- a/gnu/llvm/lldb/source/Host/common/XML.cpp +++ b/gnu/llvm/lldb/source/Host/common/XML.cpp @@ -17,7 +17,7 @@ using namespace lldb_private; #pragma mark-- XMLDocument -XMLDocument::XMLDocument() : m_document(nullptr) {} +XMLDocument::XMLDocument() = default; XMLDocument::~XMLDocument() { Clear(); } @@ -91,11 +91,11 @@ bool XMLDocument::XMLEnabled() { #pragma mark-- XMLNode -XMLNode::XMLNode() : m_node(nullptr) {} +XMLNode::XMLNode() = default; XMLNode::XMLNode(XMLNodeImpl node) : m_node(node) {} -XMLNode::~XMLNode() {} +XMLNode::~XMLNode() = default; void XMLNode::Clear() { m_node = nullptr; } @@ -398,7 +398,7 @@ ApplePropertyList::ApplePropertyList(const char *path) ParseFile(path); } -ApplePropertyList::~ApplePropertyList() {} +ApplePropertyList::~ApplePropertyList() = default; llvm::StringRef ApplePropertyList::GetErrors() const { return m_xml_doc.GetErrors(); diff --git a/gnu/llvm/lldb/source/Host/freebsd/Host.cpp b/gnu/llvm/lldb/source/Host/freebsd/Host.cpp index 09547e48afa..f9358165127 100644 --- a/gnu/llvm/lldb/source/Host/freebsd/Host.cpp +++ b/gnu/llvm/lldb/source/Host/freebsd/Host.cpp @@ -16,9 +16,9 @@ #include +#include #include #include -#include #include "lldb/Host/Host.h" #include "lldb/Host/HostInfo.h" @@ -83,6 +83,7 @@ GetFreeBSDProcessArgs(const ProcessInstanceInfoMatch *match_info_ptr, match_info_ptr->GetProcessInfo().GetName()))) return false; + process_info.SetArg0(cstr); Args &proc_args = process_info.GetArguments(); while (1) { const uint8_t *p = data.PeekData(offset, 1); @@ -175,6 +176,9 @@ uint32_t Host::FindProcessesImpl(const ProcessInstanceInfoMatch &match_info, const size_t actual_pid_count = (pid_data_size / sizeof(struct kinfo_proc)); + ProcessInstanceInfoMatch match_info_noname{match_info}; + match_info_noname.SetNameMatchType(NameMatch::Ignore); + for (size_t i = 0; i < actual_pid_count; i++) { const struct kinfo_proc &kinfo = kinfos[i]; @@ -212,7 +216,7 @@ uint32_t Host::FindProcessesImpl(const ProcessInstanceInfoMatch &match_info, process_info.SetEffectiveGroupID(kinfo.ki_svgid); // Make sure our info matches before we go fetch the name and cpu type - if (match_info.Matches(process_info) && + if (match_info_noname.Matches(process_info) && GetFreeBSDProcessArgs(&match_info, process_info)) { GetFreeBSDProcessCPUType(process_info); if (match_info.Matches(process_info)) diff --git a/gnu/llvm/lldb/source/Host/freebsd/HostInfoFreeBSD.cpp b/gnu/llvm/lldb/source/Host/freebsd/HostInfoFreeBSD.cpp index 2db97dbcd74..1b9e3ccaf18 100644 --- a/gnu/llvm/lldb/source/Host/freebsd/HostInfoFreeBSD.cpp +++ b/gnu/llvm/lldb/source/Host/freebsd/HostInfoFreeBSD.cpp @@ -8,8 +8,8 @@ #include "lldb/Host/freebsd/HostInfoFreeBSD.h" -#include -#include +#include +#include #include #include #include diff --git a/gnu/llvm/lldb/source/Host/linux/Host.cpp b/gnu/llvm/lldb/source/Host/linux/Host.cpp index 45973f5d214..dabebf50b52 100644 --- a/gnu/llvm/lldb/source/Host/linux/Host.cpp +++ b/gnu/llvm/lldb/source/Host/linux/Host.cpp @@ -6,16 +6,17 @@ // //===----------------------------------------------------------------------===// +#include +#include +#include #include -#include #include -#include -#include #include #include #include #include +#include "llvm/ADT/StringSwitch.h" #include "llvm/Object/ELF.h" #include "llvm/Support/ScopedPrinter.h" @@ -26,6 +27,7 @@ #include "lldb/Host/FileSystem.h" #include "lldb/Host/Host.h" #include "lldb/Host/HostInfo.h" +#include "lldb/Host/linux/Host.h" #include "lldb/Host/linux/Support.h" #include "lldb/Utility/DataExtractor.h" @@ -35,8 +37,11 @@ using namespace lldb_private; namespace { enum class ProcessState { Unknown, + Dead, DiskSleep, + Idle, Paging, + Parked, Running, Sleeping, TracedOrStopped, @@ -49,13 +54,16 @@ class ProcessLaunchInfo; } static bool GetStatusInfo(::pid_t Pid, ProcessInstanceInfo &ProcessInfo, - ProcessState &State, ::pid_t &TracerPid) { + ProcessState &State, ::pid_t &TracerPid, + ::pid_t &Tgid) { + Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); + auto BufferOrError = getProcFile(Pid, "status"); if (!BufferOrError) return false; llvm::StringRef Rest = BufferOrError.get()->getBuffer(); - while(!Rest.empty()) { + while (!Rest.empty()) { llvm::StringRef Line; std::tie(Line, Rest) = Rest.split('\n'); @@ -84,30 +92,26 @@ static bool GetStatusInfo(::pid_t Pid, ProcessInstanceInfo &ProcessInfo, Line.ltrim().consumeInteger(10, PPid); ProcessInfo.SetParentProcessID(PPid); } else if (Line.consume_front("State:")) { - char S = Line.ltrim().front(); - switch (S) { - case 'R': - State = ProcessState::Running; - break; - case 'S': - State = ProcessState::Sleeping; - break; - case 'D': - State = ProcessState::DiskSleep; - break; - case 'Z': - State = ProcessState::Zombie; - break; - case 'T': - State = ProcessState::TracedOrStopped; - break; - case 'W': - State = ProcessState::Paging; - break; + State = llvm::StringSwitch(Line.ltrim().take_front(1)) + .Case("D", ProcessState::DiskSleep) + .Case("I", ProcessState::Idle) + .Case("R", ProcessState::Running) + .Case("S", ProcessState::Sleeping) + .CaseLower("T", ProcessState::TracedOrStopped) + .Case("W", ProcessState::Paging) + .Case("P", ProcessState::Parked) + .Case("X", ProcessState::Dead) + .Case("Z", ProcessState::Zombie) + .Default(ProcessState::Unknown); + if (State == ProcessState::Unknown) { + LLDB_LOG(log, "Unknown process state {0}", Line); } } else if (Line.consume_front("TracerPid:")) { Line = Line.ltrim(); Line.consumeInteger(10, TracerPid); + } else if (Line.consume_front("Tgid:")) { + Line = Line.ltrim(); + Line.consumeInteger(10, Tgid); } } return true; @@ -205,6 +209,7 @@ static void GetProcessEnviron(::pid_t pid, ProcessInstanceInfo &process_info) { static bool GetProcessAndStatInfo(::pid_t pid, ProcessInstanceInfo &process_info, ProcessState &State, ::pid_t &tracerpid) { + ::pid_t tgid; tracerpid = 0; process_info.Clear(); @@ -215,7 +220,7 @@ static bool GetProcessAndStatInfo(::pid_t pid, GetProcessEnviron(pid, process_info); // Get User and Group IDs and get tracer pid. - if (!GetStatusInfo(pid, process_info, State, tracerpid)) + if (!GetStatusInfo(pid, process_info, State, tracerpid, tgid)) return false; return true; @@ -309,3 +314,14 @@ Environment Host::GetEnvironment() { return Environment(environ); } Status Host::ShellExpandArguments(ProcessLaunchInfo &launch_info) { return Status("unimplemented"); } + +llvm::Optional lldb_private::getPIDForTID(lldb::pid_t tid) { + ::pid_t tracerpid, tgid = LLDB_INVALID_PROCESS_ID; + ProcessInstanceInfo process_info; + ProcessState state; + + if (!GetStatusInfo(tid, process_info, state, tracerpid, tgid) || + tgid == LLDB_INVALID_PROCESS_ID) + return llvm::None; + return tgid; +} diff --git a/gnu/llvm/lldb/source/Host/linux/HostInfoLinux.cpp b/gnu/llvm/lldb/source/Host/linux/HostInfoLinux.cpp index a35e5ef9e97..6c37b97d7cc 100644 --- a/gnu/llvm/lldb/source/Host/linux/HostInfoLinux.cpp +++ b/gnu/llvm/lldb/source/Host/linux/HostInfoLinux.cpp @@ -13,9 +13,9 @@ #include "llvm/Support/Threading.h" -#include -#include -#include +#include +#include +#include #include #include @@ -26,22 +26,31 @@ using namespace lldb_private; namespace { struct HostInfoLinuxFields { + llvm::once_flag m_distribution_once_flag; std::string m_distribution_id; + llvm::once_flag m_os_version_once_flag; llvm::VersionTuple m_os_version; }; HostInfoLinuxFields *g_fields = nullptr; } -void HostInfoLinux::Initialize() { - HostInfoPosix::Initialize(); +void HostInfoLinux::Initialize(SharedLibraryDirectoryHelper *helper) { + HostInfoPosix::Initialize(helper); g_fields = new HostInfoLinuxFields(); } +void HostInfoLinux::Terminate() { + assert(g_fields && "Missing call to Initialize?"); + delete g_fields; + g_fields = nullptr; + HostInfoBase::Terminate(); +} + llvm::VersionTuple HostInfoLinux::GetOSVersion() { - static llvm::once_flag g_once_flag; - llvm::call_once(g_once_flag, []() { + assert(g_fields && "Missing call to Initialize?"); + llvm::call_once(g_fields->m_os_version_once_flag, []() { struct utsname un; if (uname(&un) != 0) return; @@ -82,10 +91,10 @@ bool HostInfoLinux::GetOSKernelDescription(std::string &s) { } llvm::StringRef HostInfoLinux::GetDistributionId() { + assert(g_fields && "Missing call to Initialize?"); // Try to run 'lbs_release -i', and use that response for the distribution // id. - static llvm::once_flag g_once_flag; - llvm::call_once(g_once_flag, []() { + llvm::call_once(g_fields->m_distribution_once_flag, []() { Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST)); LLDB_LOGF(log, "attempting to determine Linux distribution..."); diff --git a/gnu/llvm/lldb/source/Host/macosx/cfcpp/CFCBundle.cpp b/gnu/llvm/lldb/source/Host/macosx/cfcpp/CFCBundle.cpp index 1c268fa112d..9c13028803d 100644 --- a/gnu/llvm/lldb/source/Host/macosx/cfcpp/CFCBundle.cpp +++ b/gnu/llvm/lldb/source/Host/macosx/cfcpp/CFCBundle.cpp @@ -19,7 +19,7 @@ CFCBundle::CFCBundle(CFURLRef url) : CFCReleaser(url ? CFBundleCreate(NULL, url) : NULL) {} // Destructor -CFCBundle::~CFCBundle() {} +CFCBundle::~CFCBundle() = default; // Set the path for a bundle by supplying a bool CFCBundle::SetPath(const char *path) { diff --git a/gnu/llvm/lldb/source/Host/macosx/cfcpp/CFCData.cpp b/gnu/llvm/lldb/source/Host/macosx/cfcpp/CFCData.cpp index bfa213b860e..65b45aa0154 100644 --- a/gnu/llvm/lldb/source/Host/macosx/cfcpp/CFCData.cpp +++ b/gnu/llvm/lldb/source/Host/macosx/cfcpp/CFCData.cpp @@ -24,7 +24,7 @@ CFCData &CFCData::operator=(const CFCData &rhs) } // Destructor -CFCData::~CFCData() {} +CFCData::~CFCData() = default; CFIndex CFCData::GetLength() const { CFDataRef data = get(); diff --git a/gnu/llvm/lldb/source/Host/macosx/cfcpp/CFCMutableArray.cpp b/gnu/llvm/lldb/source/Host/macosx/cfcpp/CFCMutableArray.cpp index 64e90bdcce6..126e1f6f5f3 100644 --- a/gnu/llvm/lldb/source/Host/macosx/cfcpp/CFCMutableArray.cpp +++ b/gnu/llvm/lldb/source/Host/macosx/cfcpp/CFCMutableArray.cpp @@ -29,7 +29,7 @@ CFCMutableArray &CFCMutableArray::operator=(const CFCMutableArray &rhs) { } // Destructor -CFCMutableArray::~CFCMutableArray() {} +CFCMutableArray::~CFCMutableArray() = default; CFIndex CFCMutableArray::GetCount() const { CFMutableArrayRef array = get(); diff --git a/gnu/llvm/lldb/source/Host/macosx/cfcpp/CFCMutableDictionary.cpp b/gnu/llvm/lldb/source/Host/macosx/cfcpp/CFCMutableDictionary.cpp index 37391ccb970..ce003e349e0 100644 --- a/gnu/llvm/lldb/source/Host/macosx/cfcpp/CFCMutableDictionary.cpp +++ b/gnu/llvm/lldb/source/Host/macosx/cfcpp/CFCMutableDictionary.cpp @@ -25,7 +25,7 @@ operator=(const CFCMutableDictionary &rhs) { } // Destructor -CFCMutableDictionary::~CFCMutableDictionary() {} +CFCMutableDictionary::~CFCMutableDictionary() = default; CFIndex CFCMutableDictionary::GetCount() const { CFMutableDictionaryRef dict = get(); diff --git a/gnu/llvm/lldb/source/Host/macosx/cfcpp/CFCMutableSet.cpp b/gnu/llvm/lldb/source/Host/macosx/cfcpp/CFCMutableSet.cpp index 0852c8cfdff..ee5f6203f4f 100644 --- a/gnu/llvm/lldb/source/Host/macosx/cfcpp/CFCMutableSet.cpp +++ b/gnu/llvm/lldb/source/Host/macosx/cfcpp/CFCMutableSet.cpp @@ -25,7 +25,7 @@ const CFCMutableSet &CFCMutableSet::operator=(const CFCMutableSet &rhs) { } // Destructor -CFCMutableSet::~CFCMutableSet() {} +CFCMutableSet::~CFCMutableSet() = default; CFIndex CFCMutableSet::GetCount() const { CFMutableSetRef set = get(); diff --git a/gnu/llvm/lldb/source/Host/macosx/cfcpp/CFCReleaser.h b/gnu/llvm/lldb/source/Host/macosx/cfcpp/CFCReleaser.h index 23e6073cb80..cef7748a671 100644 --- a/gnu/llvm/lldb/source/Host/macosx/cfcpp/CFCReleaser.h +++ b/gnu/llvm/lldb/source/Host/macosx/cfcpp/CFCReleaser.h @@ -13,7 +13,7 @@ #ifdef __cplusplus -#include +#include // Templatized CF helper class that can own any CF pointer and will // call CFRelease() on any valid pointer it owns unless that pointer is diff --git a/gnu/llvm/lldb/source/Host/macosx/cfcpp/CFCString.cpp b/gnu/llvm/lldb/source/Host/macosx/cfcpp/CFCString.cpp index ae018cf5ae3..86498a19cdd 100644 --- a/gnu/llvm/lldb/source/Host/macosx/cfcpp/CFCString.cpp +++ b/gnu/llvm/lldb/source/Host/macosx/cfcpp/CFCString.cpp @@ -32,7 +32,7 @@ CFCString::CFCString(const char *cstr, CFStringEncoding cstr_encoding) } // Destructor -CFCString::~CFCString() {} +CFCString::~CFCString() = default; const char *CFCString::GetFileSystemRepresentation(std::string &s) { return CFCString::FileSystemRepresentation(get(), s); diff --git a/gnu/llvm/lldb/source/Host/macosx/objcxx/CMakeLists.txt b/gnu/llvm/lldb/source/Host/macosx/objcxx/CMakeLists.txt index e55b094c0c3..9db24f30641 100644 --- a/gnu/llvm/lldb/source/Host/macosx/objcxx/CMakeLists.txt +++ b/gnu/llvm/lldb/source/Host/macosx/objcxx/CMakeLists.txt @@ -14,3 +14,5 @@ add_lldb_library(lldbHostMacOSXObjCXX LINK_COMPONENTS Support ) + +target_compile_options(lldbHostMacOSXObjCXX PRIVATE -fno-objc-exceptions) diff --git a/gnu/llvm/lldb/source/Host/macosx/objcxx/Host.mm b/gnu/llvm/lldb/source/Host/macosx/objcxx/Host.mm index 1635132a154..7225979c092 100644 --- a/gnu/llvm/lldb/source/Host/macosx/objcxx/Host.mm +++ b/gnu/llvm/lldb/source/Host/macosx/objcxx/Host.mm @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "lldb/Host/Host.h" +#include "PosixSpawnResponsible.h" #include #include @@ -37,12 +38,13 @@ #include #include +#include +#include +#include #include #include #include #include -#include -#include #include #include #include @@ -1083,6 +1085,79 @@ static Status LaunchProcessPosixSpawn(const char *exe_path, return error; } + bool is_graphical = true; + +#if TARGET_OS_OSX + SecuritySessionId session_id; + SessionAttributeBits session_attributes; + OSStatus status = + SessionGetInfo(callerSecuritySession, &session_id, &session_attributes); + if (status == errSessionSuccess) + is_graphical = session_attributes & sessionHasGraphicAccess; +#endif + + // When lldb is ran through a graphical session, make the debuggee process + // responsible for its own TCC permissions instead of inheriting them from + // its parent. + if (is_graphical && launch_info.GetFlags().Test(eLaunchFlagDebug) && + !launch_info.GetFlags().Test(eLaunchFlagInheritTCCFromParent)) { + error.SetError(setup_posix_spawn_responsible_flag(&attr), eErrorTypePOSIX); + if (error.Fail()) { + LLDB_LOG(log, "error: {0}, setup_posix_spawn_responsible_flag(&attr)", + error); + return error; + } + } + + // Don't set the binpref if a shell was provided. After all, that's only + // going to affect what version of the shell is launched, not what fork of + // the binary is launched. We insert "arch --arch as part of the + // shell invocation to do that job on OSX. + if (launch_info.GetShell() == FileSpec()) { + const ArchSpec &arch_spec = launch_info.GetArchitecture(); + cpu_type_t cpu_type = arch_spec.GetMachOCPUType(); + cpu_type_t cpu_subtype = arch_spec.GetMachOCPUSubType(); + const bool set_cpu_type = + cpu_type != 0 && cpu_type != static_cast(UINT32_MAX) && + cpu_type != static_cast(LLDB_INVALID_CPUTYPE); + const bool set_cpu_subtype = + cpu_subtype != 0 && + cpu_subtype != static_cast(UINT32_MAX) && + cpu_subtype != CPU_SUBTYPE_X86_64_H; + if (set_cpu_type) { + size_t ocount = 0; + typedef int (*posix_spawnattr_setarchpref_np_t)( + posix_spawnattr_t *, size_t, cpu_type_t *, cpu_subtype_t *, size_t *); + posix_spawnattr_setarchpref_np_t posix_spawnattr_setarchpref_np_fn = + (posix_spawnattr_setarchpref_np_t)dlsym( + RTLD_DEFAULT, "posix_spawnattr_setarchpref_np"); + if (set_cpu_subtype && posix_spawnattr_setarchpref_np_fn) { + error.SetError((*posix_spawnattr_setarchpref_np_fn)( + &attr, 1, &cpu_type, &cpu_subtype, &ocount), + eErrorTypePOSIX); + if (error.Fail()) + LLDB_LOG(log, + "error: {0}, ::posix_spawnattr_setarchpref_np ( &attr, 1, " + "cpu_type = {1:x}, cpu_subtype = {1:x}, count => {2} )", + error, cpu_type, cpu_subtype, ocount); + + if (error.Fail() || ocount != 1) + return error; + } else { + error.SetError( + ::posix_spawnattr_setbinpref_np(&attr, 1, &cpu_type, &ocount), + eErrorTypePOSIX); + if (error.Fail()) + LLDB_LOG(log, + "error: {0}, ::posix_spawnattr_setbinpref_np ( &attr, 1, " + "cpu_type = {1:x}, count => {2} )", + error, cpu_type, ocount); + if (error.Fail() || ocount != 1) + return error; + } + } + } + const char *tmp_argv[2]; char *const *argv = const_cast( launch_info.GetArguments().GetConstArgumentVector()); @@ -1298,11 +1373,11 @@ Status Host::ShellExpandArguments(ProcessLaunchInfo &launch_info) { launch_info.SetWorkingDirectory(working_dir); } } - bool run_in_default_shell = true; + bool run_in_shell = true; bool hide_stderr = true; - Status e = RunShellCommand(expand_command, cwd, &status, nullptr, &output, - std::chrono::seconds(10), run_in_default_shell, - hide_stderr); + Status e = + RunShellCommand(expand_command, cwd, &status, nullptr, &output, + std::chrono::seconds(10), run_in_shell, hide_stderr); if (e.Fail()) return e; diff --git a/gnu/llvm/lldb/source/Host/macosx/objcxx/HostInfoMacOSX.mm b/gnu/llvm/lldb/source/Host/macosx/objcxx/HostInfoMacOSX.mm index 60eacb1e49b..a0706ec9ff6 100644 --- a/gnu/llvm/lldb/source/Host/macosx/objcxx/HostInfoMacOSX.mm +++ b/gnu/llvm/lldb/source/Host/macosx/objcxx/HostInfoMacOSX.mm @@ -6,14 +6,17 @@ // //===----------------------------------------------------------------------===// -#include "lldb/Host/macosx/HostInfoMacOSX.h" #include "lldb/Host/FileSystem.h" #include "lldb/Host/Host.h" #include "lldb/Host/HostInfo.h" +#include "lldb/Host/macosx/HostInfoMacOSX.h" #include "lldb/Utility/Args.h" #include "lldb/Utility/Log.h" +#include "lldb/Utility/Timer.h" +#include "Utility/UuidCompatibility.h" #include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringMap.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" #include "llvm/Support/raw_ostream.h" @@ -22,7 +25,7 @@ #include // C inclues -#include +#include #include #include #include @@ -136,7 +139,7 @@ bool HostInfoMacOSX::ComputeSupportExeDirectory(FileSpec &file_spec) { size_t framework_pos = raw_path.find("LLDB.framework"); if (framework_pos != std::string::npos) { framework_pos += strlen("LLDB.framework"); -#if TARGET_OS_EMBEDDED +#if TARGET_OS_IPHONE // Shallow bundle raw_path.resize(framework_pos); #else @@ -240,6 +243,12 @@ void HostInfoMacOSX::ComputeHostArchitectureSupport(ArchSpec &arch_32, len = sizeof(is_64_bit_capable); ::sysctlbyname("hw.cpu64bit_capable", &is_64_bit_capable, &len, NULL, 0); + if (cputype == CPU_TYPE_ARM64 && cpusubtype == CPU_SUBTYPE_ARM64E) { + // The arm64e architecture is a preview. Pretend the host architecture + // is arm64. + cpusubtype = CPU_SUBTYPE_ARM64_ALL; + } + if (is_64_bit_capable) { if (cputype & CPU_ARCH_ABI64) { // We have a 64 bit kernel on a 64 bit system @@ -371,27 +380,25 @@ lldb_private::FileSpec HostInfoMacOSX::GetXcodeDeveloperDirectory() { static std::string GetXcodeSDK(XcodeSDK sdk) { XcodeSDK::Info info = sdk.Parse(); std::string sdk_name = XcodeSDK::GetCanonicalName(info); - auto find_sdk = [](std::string sdk_name) -> std::string { - std::string xcrun_cmd; - std::string developer_dir = GetEnvDeveloperDir(); - if (developer_dir.empty()) - if (FileSpec fspec = HostInfo::GetShlibDir()) - if (FileSystem::Instance().Exists(fspec)) { - FileSpec path( - XcodeSDK::FindXcodeContentsDirectoryInPath(fspec.GetPath())); - if (path.RemoveLastPathComponent()) - developer_dir = path.GetPath(); - } - if (!developer_dir.empty()) - xcrun_cmd = "/usr/bin/env DEVELOPER_DIR=\"" + developer_dir + "\" "; - xcrun_cmd += "xcrun --show-sdk-path --sdk " + sdk_name; + + auto xcrun = [](const std::string &sdk, + llvm::StringRef developer_dir = "") -> std::string { + Args args; + if (!developer_dir.empty()) { + args.AppendArgument("/usr/bin/env"); + args.AppendArgument("DEVELOPER_DIR=" + developer_dir.str()); + } + args.AppendArgument("/usr/bin/xcrun"); + args.AppendArgument("--show-sdk-path"); + args.AppendArgument("--sdk"); + args.AppendArgument(sdk); int status = 0; int signo = 0; std::string output_str; lldb_private::Status error = - Host::RunShellCommand(xcrun_cmd.c_str(), FileSpec(), &status, &signo, - &output_str, std::chrono::seconds(15)); + Host::RunShellCommand(args, FileSpec(), &status, &signo, &output_str, + std::chrono::seconds(15)); // Check that xcrun return something useful. if (status != 0 || output_str.empty()) @@ -412,6 +419,33 @@ static std::string GetXcodeSDK(XcodeSDK sdk) { return output.str(); }; + auto find_sdk = [&xcrun](const std::string &sdk_name) -> std::string { + // Invoke xcrun with the developer dir specified in the environment. + std::string developer_dir = GetEnvDeveloperDir(); + if (!developer_dir.empty()) { + // Don't fallback if DEVELOPER_DIR was set. + return xcrun(sdk_name, developer_dir); + } + + // Invoke xcrun with the shlib dir. + if (FileSpec fspec = HostInfo::GetShlibDir()) { + if (FileSystem::Instance().Exists(fspec)) { + std::string contents_dir = + XcodeSDK::FindXcodeContentsDirectoryInPath(fspec.GetPath()); + llvm::StringRef shlib_developer_dir = + llvm::sys::path::parent_path(contents_dir); + if (!shlib_developer_dir.empty()) { + std::string sdk = xcrun(sdk_name, std::move(shlib_developer_dir)); + if (!sdk.empty()) + return sdk; + } + } + } + + // Invoke xcrun without a developer dir as a last resort. + return xcrun(sdk_name); + }; + std::string path = find_sdk(sdk_name); while (path.empty()) { // Try an alternate spelling of the name ("macosx10.9internal"). @@ -451,9 +485,72 @@ llvm::StringRef HostInfoMacOSX::GetXcodeSDKPath(XcodeSDK sdk) { static std::mutex g_sdk_path_mutex; std::lock_guard guard(g_sdk_path_mutex); + LLDB_SCOPED_TIMER(); + auto it = g_sdk_path.find(sdk.GetString()); if (it != g_sdk_path.end()) return it->second; auto it_new = g_sdk_path.insert({sdk.GetString(), GetXcodeSDK(sdk)}); return it_new.first->second; } + +namespace { +struct dyld_shared_cache_dylib_text_info { + uint64_t version; // current version 1 + // following fields all exist in version 1 + uint64_t loadAddressUnslid; + uint64_t textSegmentSize; + uuid_t dylibUuid; + const char *path; // pointer invalid at end of iterations + // following fields all exist in version 2 + uint64_t textSegmentOffset; // offset from start of cache +}; +typedef struct dyld_shared_cache_dylib_text_info + dyld_shared_cache_dylib_text_info; +} + +extern "C" int dyld_shared_cache_iterate_text( + const uuid_t cacheUuid, + void (^callback)(const dyld_shared_cache_dylib_text_info *info)); +extern "C" uint8_t *_dyld_get_shared_cache_range(size_t *length); +extern "C" bool _dyld_get_shared_cache_uuid(uuid_t uuid); + +namespace { +class SharedCacheInfo { +public: + const UUID &GetUUID() const { return m_uuid; } + const llvm::StringMap &GetImages() const { + return m_images; + } + + SharedCacheInfo(); + +private: + llvm::StringMap m_images; + UUID m_uuid; +}; +} + +SharedCacheInfo::SharedCacheInfo() { + size_t shared_cache_size; + uint8_t *shared_cache_start = + _dyld_get_shared_cache_range(&shared_cache_size); + uuid_t dsc_uuid; + _dyld_get_shared_cache_uuid(dsc_uuid); + m_uuid = UUID::fromData(dsc_uuid); + + dyld_shared_cache_iterate_text( + dsc_uuid, ^(const dyld_shared_cache_dylib_text_info *info) { + m_images[info->path] = SharedCacheImageInfo{ + UUID::fromData(info->dylibUuid, 16), + std::make_shared( + shared_cache_start + info->textSegmentOffset, + shared_cache_size - info->textSegmentOffset)}; + }); +} + +SharedCacheImageInfo +HostInfoMacOSX::GetSharedCacheImageInfo(llvm::StringRef image_name) { + static SharedCacheInfo g_shared_cache_info; + return g_shared_cache_info.GetImages().lookup(image_name); +} diff --git a/gnu/llvm/lldb/source/Host/macosx/objcxx/HostThreadMacOSX.mm b/gnu/llvm/lldb/source/Host/macosx/objcxx/HostThreadMacOSX.mm index 5c60caa33e6..0a1cfa94568 100644 --- a/gnu/llvm/lldb/source/Host/macosx/objcxx/HostThreadMacOSX.mm +++ b/gnu/llvm/lldb/source/Host/macosx/objcxx/HostThreadMacOSX.mm @@ -23,9 +23,7 @@ pthread_key_t g_thread_create_key = 0; class MacOSXDarwinThread { public: - MacOSXDarwinThread() : m_pool(nil) { - m_pool = [[NSAutoreleasePool alloc] init]; - } + MacOSXDarwinThread() { m_pool = [[NSAutoreleasePool alloc] init]; } ~MacOSXDarwinThread() { if (m_pool) { @@ -41,7 +39,7 @@ public: } protected: - NSAutoreleasePool *m_pool; + NSAutoreleasePool *m_pool = nil; private: MacOSXDarwinThread(const MacOSXDarwinThread &) = delete; diff --git a/gnu/llvm/lldb/source/Host/macosx/objcxx/PosixSpawnResponsible.h b/gnu/llvm/lldb/source/Host/macosx/objcxx/PosixSpawnResponsible.h new file mode 100644 index 00000000000..36fe09b5263 --- /dev/null +++ b/gnu/llvm/lldb/source/Host/macosx/objcxx/PosixSpawnResponsible.h @@ -0,0 +1,46 @@ +//===-- PosixSpawnResponsible.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_HOST_POSIXSPAWNRESPONSIBLE_H +#define LLDB_HOST_POSIXSPAWNRESPONSIBLE_H + +#include + +#if __has_include() +#include +#include +#include + +// Older SDKs have responsibility.h but not this particular function. Let's +// include the prototype here. +errno_t responsibility_spawnattrs_setdisclaim(posix_spawnattr_t *attrs, + bool disclaim); + +#endif + +static inline int setup_posix_spawn_responsible_flag(posix_spawnattr_t *attr) { + if (@available(macOS 10.14, *)) { +#if __has_include() + static __typeof__(responsibility_spawnattrs_setdisclaim) + *responsibility_spawnattrs_setdisclaim_ptr; + static dispatch_once_t pred; + dispatch_once(&pred, ^{ + responsibility_spawnattrs_setdisclaim_ptr = +#ifdef __cplusplus + reinterpret_cast<__typeof__(&responsibility_spawnattrs_setdisclaim)> +#endif + (dlsym(RTLD_DEFAULT, "responsibility_spawnattrs_setdisclaim")); + }); + if (responsibility_spawnattrs_setdisclaim_ptr) + return responsibility_spawnattrs_setdisclaim_ptr(attr, true); +#endif + } + return 0; +} + +#endif // LLDB_HOST_POSIXSPAWNRESPONSIBLE_H diff --git a/gnu/llvm/lldb/source/Host/netbsd/HostInfoNetBSD.cpp b/gnu/llvm/lldb/source/Host/netbsd/HostInfoNetBSD.cpp index cc01ec35a5b..bddd46cec3e 100644 --- a/gnu/llvm/lldb/source/Host/netbsd/HostInfoNetBSD.cpp +++ b/gnu/llvm/lldb/source/Host/netbsd/HostInfoNetBSD.cpp @@ -8,11 +8,11 @@ #include "lldb/Host/netbsd/HostInfoNetBSD.h" -#include -#include +#include +#include +#include +#include #include -#include -#include #include #include #include diff --git a/gnu/llvm/lldb/source/Host/netbsd/HostNetBSD.cpp b/gnu/llvm/lldb/source/Host/netbsd/HostNetBSD.cpp index 4708fb45dee..af31a11a20a 100644 --- a/gnu/llvm/lldb/source/Host/netbsd/HostNetBSD.cpp +++ b/gnu/llvm/lldb/source/Host/netbsd/HostNetBSD.cpp @@ -6,14 +6,14 @@ // //===----------------------------------------------------------------------===// +#include #include #include -#include #include #include #include -#include +#include #include #include @@ -200,6 +200,9 @@ uint32_t Host::FindProcessesImpl(const ProcessInstanceInfoMatch &match_info, return 0; } + ProcessInstanceInfoMatch match_info_noname{match_info}; + match_info_noname.SetNameMatchType(NameMatch::Ignore); + for (int i = 0; i < nproc; i++) { if (proc_kinfo[i].p_pid < 1) continue; /* not valid */ @@ -220,7 +223,7 @@ uint32_t Host::FindProcessesImpl(const ProcessInstanceInfoMatch &match_info, if (proc_kinfo[i].p_nlwps > 1) { bool already_registered = false; for (size_t pi = 0; pi < process_infos.size(); pi++) { - if (process_infos[pi].GetProcessID() == proc_kinfo[i].p_pid) { + if ((::pid_t)process_infos[pi].GetProcessID() == proc_kinfo[i].p_pid) { already_registered = true; break; } @@ -237,7 +240,7 @@ uint32_t Host::FindProcessesImpl(const ProcessInstanceInfoMatch &match_info, process_info.SetEffectiveUserID(proc_kinfo[i].p_uid); process_info.SetEffectiveGroupID(proc_kinfo[i].p_gid); // Make sure our info matches before we go fetch the name and cpu type - if (match_info.Matches(process_info) && + if (match_info_noname.Matches(process_info) && GetNetBSDProcessArgs(&match_info, process_info)) { GetNetBSDProcessCPUType(process_info); if (match_info.Matches(process_info)) diff --git a/gnu/llvm/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp b/gnu/llvm/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp index 3a547ce128d..2f4cc960f02 100644 --- a/gnu/llvm/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp +++ b/gnu/llvm/lldb/source/Host/posix/ConnectionFileDescriptorPosix.cpp @@ -20,10 +20,10 @@ #include "lldb/Utility/SelectHelper.h" #include "lldb/Utility/Timeout.h" -#include +#include +#include +#include #include -#include -#include #include #if LLDB_ENABLE_POSIX @@ -76,7 +76,7 @@ llvm::Optional GetURLAddress(llvm::StringRef url, ConnectionFileDescriptor::ConnectionFileDescriptor(bool child_processes_inherit) : Connection(), m_pipe(), m_mutex(), m_shutting_down(false), - m_waiting_for_accept(false), + m_child_processes_inherit(child_processes_inherit) { Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_CONNECTION | LIBLLDB_LOG_OBJECT)); diff --git a/gnu/llvm/lldb/source/Host/posix/HostInfoPosix.cpp b/gnu/llvm/lldb/source/Host/posix/HostInfoPosix.cpp index 7e110f07d7c..b633acf6fec 100644 --- a/gnu/llvm/lldb/source/Host/posix/HostInfoPosix.cpp +++ b/gnu/llvm/lldb/source/Host/posix/HostInfoPosix.cpp @@ -15,11 +15,11 @@ #include "llvm/Support/Path.h" #include "llvm/Support/raw_ostream.h" +#include +#include #include -#include #include #include -#include #include #include diff --git a/gnu/llvm/lldb/source/Host/posix/HostProcessPosix.cpp b/gnu/llvm/lldb/source/Host/posix/HostProcessPosix.cpp index 69a049bcf7a..f0142ec946b 100644 --- a/gnu/llvm/lldb/source/Host/posix/HostProcessPosix.cpp +++ b/gnu/llvm/lldb/source/Host/posix/HostProcessPosix.cpp @@ -12,8 +12,8 @@ #include "llvm/ADT/STLExtras.h" +#include #include -#include #include using namespace lldb_private; @@ -28,7 +28,7 @@ HostProcessPosix::HostProcessPosix() HostProcessPosix::HostProcessPosix(lldb::process_t process) : HostNativeProcessBase(process) {} -HostProcessPosix::~HostProcessPosix() {} +HostProcessPosix::~HostProcessPosix() = default; Status HostProcessPosix::Signal(int signo) const { if (m_process == kInvalidPosixProcess) { diff --git a/gnu/llvm/lldb/source/Host/posix/HostThreadPosix.cpp b/gnu/llvm/lldb/source/Host/posix/HostThreadPosix.cpp index 31c7c7f8e2f..4250e07e51c 100644 --- a/gnu/llvm/lldb/source/Host/posix/HostThreadPosix.cpp +++ b/gnu/llvm/lldb/source/Host/posix/HostThreadPosix.cpp @@ -9,18 +9,18 @@ #include "lldb/Host/posix/HostThreadPosix.h" #include "lldb/Utility/Status.h" -#include +#include #include using namespace lldb; using namespace lldb_private; -HostThreadPosix::HostThreadPosix() {} +HostThreadPosix::HostThreadPosix() = default; HostThreadPosix::HostThreadPosix(lldb::thread_t thread) : HostNativeThreadBase(thread) {} -HostThreadPosix::~HostThreadPosix() {} +HostThreadPosix::~HostThreadPosix() = default; Status HostThreadPosix::Join(lldb::thread_result_t *result) { Status error; diff --git a/gnu/llvm/lldb/source/Host/posix/ProcessLauncherPosixFork.cpp b/gnu/llvm/lldb/source/Host/posix/ProcessLauncherPosixFork.cpp index 35482341d3e..25dcf1e592c 100644 --- a/gnu/llvm/lldb/source/Host/posix/ProcessLauncherPosixFork.cpp +++ b/gnu/llvm/lldb/source/Host/posix/ProcessLauncherPosixFork.cpp @@ -15,7 +15,7 @@ #include "lldb/Utility/Log.h" #include "llvm/Support/Errno.h" -#include +#include #include #include #include diff --git a/gnu/llvm/lldb/source/Host/windows/Host.cpp b/gnu/llvm/lldb/source/Host/windows/Host.cpp index 50617a8c4bb..f663b35dded 100644 --- a/gnu/llvm/lldb/source/Host/windows/Host.cpp +++ b/gnu/llvm/lldb/source/Host/windows/Host.cpp @@ -8,7 +8,7 @@ #include "lldb/Host/windows/AutoHandle.h" #include "lldb/Host/windows/windows.h" -#include +#include #include "lldb/Host/FileSystem.h" #include "lldb/Host/Host.h" diff --git a/gnu/llvm/lldb/source/Host/windows/HostInfoWindows.cpp b/gnu/llvm/lldb/source/Host/windows/HostInfoWindows.cpp index ba170b68bbc..54a07b71b2c 100644 --- a/gnu/llvm/lldb/source/Host/windows/HostInfoWindows.cpp +++ b/gnu/llvm/lldb/source/Host/windows/HostInfoWindows.cpp @@ -39,9 +39,9 @@ protected: FileSpec HostInfoWindows::m_program_filespec; -void HostInfoWindows::Initialize() { +void HostInfoWindows::Initialize(SharedLibraryDirectoryHelper *helper) { ::CoInitializeEx(nullptr, COINIT_MULTITHREADED); - HostInfoBase::Initialize(); + HostInfoBase::Initialize(helper); } void HostInfoWindows::Terminate() { diff --git a/gnu/llvm/lldb/source/Host/windows/ProcessLauncherWindows.cpp b/gnu/llvm/lldb/source/Host/windows/ProcessLauncherWindows.cpp index 00470f558e9..fc8da143b99 100644 --- a/gnu/llvm/lldb/source/Host/windows/ProcessLauncherWindows.cpp +++ b/gnu/llvm/lldb/source/Host/windows/ProcessLauncherWindows.cpp @@ -42,7 +42,7 @@ void CreateEnvironmentBuffer(const Environment &env, buffer.push_back(0); } -bool GetFlattenedWindowsCommandString(Args args, std::string &command) { +bool GetFlattenedWindowsCommandString(Args args, std::wstring &command) { if (args.empty()) return false; @@ -50,7 +50,12 @@ bool GetFlattenedWindowsCommandString(Args args, std::string &command) { for (auto &entry : args.entries()) args_ref.push_back(entry.ref()); - command = llvm::sys::flattenWindowsCommandLine(args_ref); + llvm::ErrorOr result = + llvm::sys::flattenWindowsCommandLine(args_ref); + if (result.getError()) + return false; + + command = *result; return true; } } // namespace @@ -61,7 +66,6 @@ ProcessLauncherWindows::LaunchProcess(const ProcessLaunchInfo &launch_info, error.Clear(); std::string executable; - std::string commandLine; std::vector environment; STARTUPINFO startupinfo = {}; PROCESS_INFORMATION pi = {}; @@ -82,7 +86,7 @@ ProcessLauncherWindows::LaunchProcess(const ProcessLaunchInfo &launch_info, const char *hide_console_var = getenv("LLDB_LAUNCH_INFERIORS_WITHOUT_CONSOLE"); if (hide_console_var && - llvm::StringRef(hide_console_var).equals_lower("true")) { + llvm::StringRef(hide_console_var).equals_insensitive("true")) { startupinfo.dwFlags |= STARTF_USESHOWWINDOW; startupinfo.wShowWindow = SW_HIDE; } @@ -99,11 +103,11 @@ ProcessLauncherWindows::LaunchProcess(const ProcessLaunchInfo &launch_info, env_block = environment.data(); executable = launch_info.GetExecutableFile().GetPath(); - GetFlattenedWindowsCommandString(launch_info.GetArguments(), commandLine); + std::wstring wcommandLine; + GetFlattenedWindowsCommandString(launch_info.GetArguments(), wcommandLine); - std::wstring wexecutable, wcommandLine, wworkingDirectory; + std::wstring wexecutable, wworkingDirectory; llvm::ConvertUTF8toWide(executable, wexecutable); - llvm::ConvertUTF8toWide(commandLine, wcommandLine); llvm::ConvertUTF8toWide(launch_info.GetWorkingDirectory().GetCString(), wworkingDirectory); // If the command line is empty, it's best to pass a null pointer to tell diff --git a/gnu/llvm/lldb/source/Host/windows/Windows.cpp b/gnu/llvm/lldb/source/Host/windows/Windows.cpp index 32129bb6d1e..787f35930ba 100644 --- a/gnu/llvm/lldb/source/Host/windows/Windows.cpp +++ b/gnu/llvm/lldb/source/Host/windows/Windows.cpp @@ -13,34 +13,14 @@ #include "llvm/Support/ConvertUTF.h" -#include +#include +#include #include -#include +#include +#include +#include +#include #include -#include -#include -#include -#include - -namespace { -bool utf8ToWide(const char *utf8, wchar_t *buf, size_t bufSize) { - const llvm::UTF8 *sourceStart = reinterpret_cast(utf8); - size_t sourceLen = strlen(utf8) + 1 /* convert null too */; - llvm::UTF16 *target = reinterpret_cast(buf); - llvm::ConversionFlags flags = llvm::strictConversion; - return llvm::ConvertUTF8toUTF16(&sourceStart, sourceStart + sourceLen, &target, - target + bufSize, flags) == llvm::conversionOK; -} - -bool wideToUtf8(const wchar_t *wide, char *buf, size_t bufSize) { - const llvm::UTF16 *sourceStart = reinterpret_cast(wide); - size_t sourceLen = wcslen(wide) + 1 /* convert null too */; - llvm::UTF8 *target = reinterpret_cast(buf); - llvm::ConversionFlags flags = llvm::strictConversion; - return llvm::ConvertUTF16toUTF8(&sourceStart, sourceStart + sourceLen, &target, - target + bufSize, flags) == llvm::conversionOK; -} -} int vasprintf(char **ret, const char *fmt, va_list ap) { char *buf; @@ -82,89 +62,6 @@ char *strcasestr(const char *s, const char *find) { return const_cast(s); } -char *realpath(const char *name, char *resolved) { - char *retname = NULL; - - /* SUSv3 says we must set `errno = EINVAL', and return NULL, - * if `name' is passed as a NULL pointer. - */ - if (name == NULL) { - errno = EINVAL; - return NULL; - } - - /* Otherwise, `name' must refer to a readable filesystem object, - * if we are going to resolve its absolute path name. - */ - wchar_t wideNameBuffer[PATH_MAX]; - wchar_t *wideName = wideNameBuffer; - if (!utf8ToWide(name, wideName, PATH_MAX)) { - errno = EINVAL; - return NULL; - } - - if (_waccess(wideName, 4) != 0) - return NULL; - - /* If `name' didn't point to an existing entity, - * then we don't get to here; we simply fall past this block, - * returning NULL, with `errno' appropriately set by `access'. - * - * When we _do_ get to here, then we can use `_fullpath' to - * resolve the full path for `name' into `resolved', but first, - * check that we have a suitable buffer, in which to return it. - */ - - if ((retname = resolved) == NULL) { - /* Caller didn't give us a buffer, so we'll exercise the - * option granted by SUSv3, and allocate one. - * - * `_fullpath' would do this for us, but it uses `malloc', and - * Microsoft's implementation doesn't set `errno' on failure. - * If we don't do this explicitly ourselves, then we will not - * know if `_fullpath' fails on `malloc' failure, or for some - * other reason, and we want to set `errno = ENOMEM' for the - * `malloc' failure case. - */ - - retname = (char *)malloc(PATH_MAX); - if (retname == NULL) { - errno = ENOMEM; - return NULL; - } - } - - /* Otherwise, when we do have a valid buffer, - * `_fullpath' should only fail if the path name is too long. - */ - - wchar_t wideFullPathBuffer[PATH_MAX]; - wchar_t *wideFullPath; - if ((wideFullPath = _wfullpath(wideFullPathBuffer, wideName, PATH_MAX)) == - NULL) { - errno = ENAMETOOLONG; - return NULL; - } - - // Do a LongPath<->ShortPath roundtrip so that case is resolved by OS - // FIXME: Check for failure - size_t initialLength = wcslen(wideFullPath); - GetShortPathNameW(wideFullPath, wideNameBuffer, PATH_MAX); - GetLongPathNameW(wideNameBuffer, wideFullPathBuffer, initialLength + 1); - - // Convert back to UTF-8 - if (!wideToUtf8(wideFullPathBuffer, retname, PATH_MAX)) { - errno = EINVAL; - return NULL; - } - - // Force drive to be upper case - if (retname[1] == ':') - retname[0] = toupper(retname[0]); - - return retname; -} - #ifdef _MSC_VER char *basename(char *path) { diff --git a/gnu/llvm/lldb/source/Initialization/SystemInitializer.cpp b/gnu/llvm/lldb/source/Initialization/SystemInitializer.cpp index fc460c32650..823a905ebc4 100644 --- a/gnu/llvm/lldb/source/Initialization/SystemInitializer.cpp +++ b/gnu/llvm/lldb/source/Initialization/SystemInitializer.cpp @@ -10,6 +10,6 @@ using namespace lldb_private; -SystemInitializer::SystemInitializer() {} +SystemInitializer::SystemInitializer() = default; -SystemInitializer::~SystemInitializer() {} +SystemInitializer::~SystemInitializer() = default; diff --git a/gnu/llvm/lldb/source/Initialization/SystemLifetimeManager.cpp b/gnu/llvm/lldb/source/Initialization/SystemLifetimeManager.cpp index 00ab3198c36..f9de41a6753 100644 --- a/gnu/llvm/lldb/source/Initialization/SystemLifetimeManager.cpp +++ b/gnu/llvm/lldb/source/Initialization/SystemLifetimeManager.cpp @@ -15,8 +15,7 @@ using namespace lldb_private; -SystemLifetimeManager::SystemLifetimeManager() - : m_mutex(), m_initialized(false) {} +SystemLifetimeManager::SystemLifetimeManager() : m_mutex() {} SystemLifetimeManager::~SystemLifetimeManager() { assert(!m_initialized && diff --git a/gnu/llvm/lldb/source/Interpreter/CMakeLists.txt b/gnu/llvm/lldb/source/Interpreter/CMakeLists.txt index 0ed39869467..af9b0ce86f3 100644 --- a/gnu/llvm/lldb/source/Interpreter/CMakeLists.txt +++ b/gnu/llvm/lldb/source/Interpreter/CMakeLists.txt @@ -11,8 +11,6 @@ add_lldb_library(lldbInterpreter CommandHistory.cpp CommandInterpreter.cpp CommandObject.cpp - CommandObjectRegexCommand.cpp - CommandObjectScript.cpp CommandOptionValidators.cpp CommandReturnObject.cpp OptionArgParser.cpp @@ -35,6 +33,7 @@ add_lldb_library(lldbInterpreter OptionValueChar.cpp OptionValueDictionary.cpp OptionValueEnumeration.cpp + OptionValueFileColonLine.cpp OptionValueFileSpec.cpp OptionValueFileSpecList.cpp OptionValueFormat.cpp diff --git a/gnu/llvm/lldb/source/Interpreter/CommandAlias.cpp b/gnu/llvm/lldb/source/Interpreter/CommandAlias.cpp index a5e03393721..d55b3fdd44f 100644 --- a/gnu/llvm/lldb/source/Interpreter/CommandAlias.cpp +++ b/gnu/llvm/lldb/source/Interpreter/CommandAlias.cpp @@ -47,7 +47,6 @@ static bool ProcessAliasOptionsArgs(lldb::CommandObjectSP &cmd_obj_sp, if (!args_or) { result.AppendError(toString(args_or.takeError())); result.AppendError("Unable to create requested alias.\n"); - result.SetStatus(eReturnStatusFailed); return false; } args = std::move(*args_or); @@ -80,7 +79,7 @@ CommandAlias::CommandAlias(CommandInterpreter &interpreter, llvm::StringRef help, llvm::StringRef syntax, uint32_t flags) : CommandObject(interpreter, name, help, syntax, flags), - m_underlying_command_sp(), m_option_string(std::string(options_args)), + m_option_string(std::string(options_args)), m_option_args_sp(new OptionArgVector), m_is_dashdash_alias(eLazyBoolCalculate), m_did_set_help(false), m_did_set_help_long(false) { diff --git a/gnu/llvm/lldb/source/Interpreter/CommandHistory.cpp b/gnu/llvm/lldb/source/Interpreter/CommandHistory.cpp index 9c7919ecc41..8f399840b80 100644 --- a/gnu/llvm/lldb/source/Interpreter/CommandHistory.cpp +++ b/gnu/llvm/lldb/source/Interpreter/CommandHistory.cpp @@ -6,17 +6,13 @@ // //===----------------------------------------------------------------------===// -#include +#include #include "lldb/Interpreter/CommandHistory.h" using namespace lldb; using namespace lldb_private; -CommandHistory::CommandHistory() : m_mutex(), m_history() {} - -CommandHistory::~CommandHistory() {} - size_t CommandHistory::GetSize() const { std::lock_guard guard(m_mutex); return m_history.size(); diff --git a/gnu/llvm/lldb/source/Interpreter/CommandInterpreter.cpp b/gnu/llvm/lldb/source/Interpreter/CommandInterpreter.cpp index e55b2550017..00e9ccb762c 100644 --- a/gnu/llvm/lldb/source/Interpreter/CommandInterpreter.cpp +++ b/gnu/llvm/lldb/source/Interpreter/CommandInterpreter.cpp @@ -6,14 +6,12 @@ // //===----------------------------------------------------------------------===// +#include +#include #include -#include #include #include -#include "CommandObjectScript.h" -#include "lldb/Interpreter/CommandObjectRegexCommand.h" - #include "Commands/CommandObjectApropos.h" #include "Commands/CommandObjectBreakpoint.h" #include "Commands/CommandObjectCommands.h" @@ -29,13 +27,17 @@ #include "Commands/CommandObjectPlugin.h" #include "Commands/CommandObjectProcess.h" #include "Commands/CommandObjectQuit.h" +#include "Commands/CommandObjectRegexCommand.h" #include "Commands/CommandObjectRegister.h" #include "Commands/CommandObjectReproducer.h" +#include "Commands/CommandObjectScript.h" +#include "Commands/CommandObjectSession.h" #include "Commands/CommandObjectSettings.h" #include "Commands/CommandObjectSource.h" #include "Commands/CommandObjectStats.h" #include "Commands/CommandObjectTarget.h" #include "Commands/CommandObjectThread.h" +#include "Commands/CommandObjectTrace.h" #include "Commands/CommandObjectType.h" #include "Commands/CommandObjectVersion.h" #include "Commands/CommandObjectWatchpoint.h" @@ -44,6 +46,7 @@ #include "lldb/Core/PluginManager.h" #include "lldb/Core/StreamFile.h" #include "lldb/Utility/Log.h" +#include "lldb/Utility/Reproducer.h" #include "lldb/Utility/State.h" #include "lldb/Utility/Stream.h" #include "lldb/Utility/Timer.h" @@ -52,6 +55,8 @@ #if LLDB_ENABLE_LIBEDIT #include "lldb/Host/Editline.h" #endif +#include "lldb/Host/File.h" +#include "lldb/Host/FileCache.h" #include "lldb/Host/Host.h" #include "lldb/Host/HostInfo.h" @@ -63,6 +68,7 @@ #include "lldb/Interpreter/Property.h" #include "lldb/Utility/Args.h" +#include "lldb/Target/Language.h" #include "lldb/Target/Process.h" #include "lldb/Target/StopInfo.h" #include "lldb/Target/TargetList.h" @@ -70,10 +76,12 @@ #include "lldb/Target/UnixSignals.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/ScopeExit.h" #include "llvm/ADT/SmallString.h" #include "llvm/Support/FormatAdapters.h" #include "llvm/Support/Path.h" #include "llvm/Support/PrettyStackTrace.h" +#include "llvm/Support/ScopedPrinter.h" using namespace lldb; using namespace lldb_private; @@ -114,9 +122,8 @@ CommandInterpreter::CommandInterpreter(Debugger &debugger, IOHandlerDelegate(IOHandlerDelegate::Completion::LLDBCommand), m_debugger(debugger), m_synchronous_execution(true), m_skip_lldbinit_files(false), m_skip_app_init_files(false), - m_command_io_handler_sp(), m_comment_char('#'), - m_batch_command_mode(false), m_truncation_warning(eNoTruncation), - m_command_source_depth(0), m_result() { + m_comment_char('#'), m_batch_command_mode(false), + m_truncation_warning(eNoTruncation), m_command_source_depth(0) { SetEventName(eBroadcastBitThreadShouldExit, "thread-should-exit"); SetEventName(eBroadcastBitResetPrompt, "reset-prompt"); SetEventName(eBroadcastBitQuitCommandReceived, "quit"); @@ -142,6 +149,27 @@ void CommandInterpreter::SetPromptOnQuit(bool enable) { m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, enable); } +bool CommandInterpreter::GetSaveSessionOnQuit() const { + const uint32_t idx = ePropertySaveSessionOnQuit; + return m_collection_sp->GetPropertyAtIndexAsBoolean( + nullptr, idx, g_interpreter_properties[idx].default_uint_value != 0); +} + +void CommandInterpreter::SetSaveSessionOnQuit(bool enable) { + const uint32_t idx = ePropertySaveSessionOnQuit; + m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, enable); +} + +FileSpec CommandInterpreter::GetSaveSessionDirectory() const { + const uint32_t idx = ePropertySaveSessionDirectory; + return m_collection_sp->GetPropertyAtIndexAsFileSpec(nullptr, idx); +} + +void CommandInterpreter::SetSaveSessionDirectory(llvm::StringRef path) { + const uint32_t idx = ePropertySaveSessionDirectory; + m_collection_sp->SetPropertyAtIndexAsString(nullptr, idx, path); +} + bool CommandInterpreter::GetEchoCommands() const { const uint32_t idx = ePropertyEchoCommands; return m_collection_sp->GetPropertyAtIndexAsBoolean( @@ -205,9 +233,14 @@ bool CommandInterpreter::GetSpaceReplPrompts() const { nullptr, idx, g_interpreter_properties[idx].default_uint_value != 0); } +bool CommandInterpreter::GetRepeatPreviousCommand() const { + const uint32_t idx = ePropertyRepeatPreviousCommand; + return m_collection_sp->GetPropertyAtIndexAsBoolean( + nullptr, idx, g_interpreter_properties[idx].default_uint_value != 0); +} + void CommandInterpreter::Initialize() { - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer(func_cat, LLVM_PRETTY_FUNCTION); + LLDB_SCOPED_TIMER(); CommandReturnObject result(m_debugger.GetUseColor()); @@ -217,48 +250,48 @@ void CommandInterpreter::Initialize() { OptionArgVectorSP alias_arguments_vector_sp(new OptionArgVector); // Set up some initial aliases. - CommandObjectSP cmd_obj_sp = GetCommandSPExact("quit", false); + CommandObjectSP cmd_obj_sp = GetCommandSPExact("quit"); if (cmd_obj_sp) { AddAlias("q", cmd_obj_sp); AddAlias("exit", cmd_obj_sp); } - cmd_obj_sp = GetCommandSPExact("_regexp-attach", false); + cmd_obj_sp = GetCommandSPExact("_regexp-attach"); if (cmd_obj_sp) AddAlias("attach", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax()); - cmd_obj_sp = GetCommandSPExact("process detach", false); + cmd_obj_sp = GetCommandSPExact("process detach"); if (cmd_obj_sp) { AddAlias("detach", cmd_obj_sp); } - cmd_obj_sp = GetCommandSPExact("process continue", false); + cmd_obj_sp = GetCommandSPExact("process continue"); if (cmd_obj_sp) { AddAlias("c", cmd_obj_sp); AddAlias("continue", cmd_obj_sp); } - cmd_obj_sp = GetCommandSPExact("_regexp-break", false); + cmd_obj_sp = GetCommandSPExact("_regexp-break"); if (cmd_obj_sp) AddAlias("b", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax()); - cmd_obj_sp = GetCommandSPExact("_regexp-tbreak", false); + cmd_obj_sp = GetCommandSPExact("_regexp-tbreak"); if (cmd_obj_sp) AddAlias("tbreak", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax()); - cmd_obj_sp = GetCommandSPExact("thread step-inst", false); + cmd_obj_sp = GetCommandSPExact("thread step-inst"); if (cmd_obj_sp) { AddAlias("stepi", cmd_obj_sp); AddAlias("si", cmd_obj_sp); } - cmd_obj_sp = GetCommandSPExact("thread step-inst-over", false); + cmd_obj_sp = GetCommandSPExact("thread step-inst-over"); if (cmd_obj_sp) { AddAlias("nexti", cmd_obj_sp); AddAlias("ni", cmd_obj_sp); } - cmd_obj_sp = GetCommandSPExact("thread step-in", false); + cmd_obj_sp = GetCommandSPExact("thread step-in"); if (cmd_obj_sp) { AddAlias("s", cmd_obj_sp); AddAlias("step", cmd_obj_sp); @@ -272,86 +305,86 @@ void CommandInterpreter::Initialize() { } } - cmd_obj_sp = GetCommandSPExact("thread step-over", false); + cmd_obj_sp = GetCommandSPExact("thread step-over"); if (cmd_obj_sp) { AddAlias("n", cmd_obj_sp); AddAlias("next", cmd_obj_sp); } - cmd_obj_sp = GetCommandSPExact("thread step-out", false); + cmd_obj_sp = GetCommandSPExact("thread step-out"); if (cmd_obj_sp) { AddAlias("finish", cmd_obj_sp); } - cmd_obj_sp = GetCommandSPExact("frame select", false); + cmd_obj_sp = GetCommandSPExact("frame select"); if (cmd_obj_sp) { AddAlias("f", cmd_obj_sp); } - cmd_obj_sp = GetCommandSPExact("thread select", false); + cmd_obj_sp = GetCommandSPExact("thread select"); if (cmd_obj_sp) { AddAlias("t", cmd_obj_sp); } - cmd_obj_sp = GetCommandSPExact("_regexp-jump", false); + cmd_obj_sp = GetCommandSPExact("_regexp-jump"); if (cmd_obj_sp) { AddAlias("j", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax()); AddAlias("jump", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax()); } - cmd_obj_sp = GetCommandSPExact("_regexp-list", false); + cmd_obj_sp = GetCommandSPExact("_regexp-list"); if (cmd_obj_sp) { AddAlias("l", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax()); AddAlias("list", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax()); } - cmd_obj_sp = GetCommandSPExact("_regexp-env", false); + cmd_obj_sp = GetCommandSPExact("_regexp-env"); if (cmd_obj_sp) AddAlias("env", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax()); - cmd_obj_sp = GetCommandSPExact("memory read", false); + cmd_obj_sp = GetCommandSPExact("memory read"); if (cmd_obj_sp) AddAlias("x", cmd_obj_sp); - cmd_obj_sp = GetCommandSPExact("_regexp-up", false); + cmd_obj_sp = GetCommandSPExact("_regexp-up"); if (cmd_obj_sp) AddAlias("up", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax()); - cmd_obj_sp = GetCommandSPExact("_regexp-down", false); + cmd_obj_sp = GetCommandSPExact("_regexp-down"); if (cmd_obj_sp) AddAlias("down", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax()); - cmd_obj_sp = GetCommandSPExact("_regexp-display", false); + cmd_obj_sp = GetCommandSPExact("_regexp-display"); if (cmd_obj_sp) AddAlias("display", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax()); - cmd_obj_sp = GetCommandSPExact("disassemble", false); + cmd_obj_sp = GetCommandSPExact("disassemble"); if (cmd_obj_sp) AddAlias("dis", cmd_obj_sp); - cmd_obj_sp = GetCommandSPExact("disassemble", false); + cmd_obj_sp = GetCommandSPExact("disassemble"); if (cmd_obj_sp) AddAlias("di", cmd_obj_sp); - cmd_obj_sp = GetCommandSPExact("_regexp-undisplay", false); + cmd_obj_sp = GetCommandSPExact("_regexp-undisplay"); if (cmd_obj_sp) AddAlias("undisplay", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax()); - cmd_obj_sp = GetCommandSPExact("_regexp-bt", false); + cmd_obj_sp = GetCommandSPExact("_regexp-bt"); if (cmd_obj_sp) AddAlias("bt", cmd_obj_sp)->SetSyntax(cmd_obj_sp->GetSyntax()); - cmd_obj_sp = GetCommandSPExact("target create", false); + cmd_obj_sp = GetCommandSPExact("target create"); if (cmd_obj_sp) AddAlias("file", cmd_obj_sp); - cmd_obj_sp = GetCommandSPExact("target modules", false); + cmd_obj_sp = GetCommandSPExact("target modules"); if (cmd_obj_sp) AddAlias("image", cmd_obj_sp); alias_arguments_vector_sp = std::make_shared(); - cmd_obj_sp = GetCommandSPExact("expression", false); + cmd_obj_sp = GetCommandSPExact("expression"); if (cmd_obj_sp) { AddAlias("p", cmd_obj_sp, "--")->SetHelpLong(""); AddAlias("print", cmd_obj_sp, "--")->SetHelpLong(""); @@ -381,7 +414,7 @@ void CommandInterpreter::Initialize() { } } - cmd_obj_sp = GetCommandSPExact("platform shell", false); + cmd_obj_sp = GetCommandSPExact("platform shell"); if (cmd_obj_sp) { CommandAlias *shell_alias = AddAlias("shell", cmd_obj_sp, " --host --"); if (shell_alias) { @@ -391,56 +424,57 @@ void CommandInterpreter::Initialize() { } } - cmd_obj_sp = GetCommandSPExact("process kill", false); + cmd_obj_sp = GetCommandSPExact("process kill"); if (cmd_obj_sp) { AddAlias("kill", cmd_obj_sp); } - cmd_obj_sp = GetCommandSPExact("process launch", false); + cmd_obj_sp = GetCommandSPExact("process launch"); if (cmd_obj_sp) { alias_arguments_vector_sp = std::make_shared(); -#if defined(__arm__) || defined(__arm64__) || defined(__aarch64__) +#if defined(__APPLE__) +#if defined(TARGET_OS_IPHONE) AddAlias("r", cmd_obj_sp, "--"); AddAlias("run", cmd_obj_sp, "--"); #else -#if defined(__APPLE__) - std::string shell_option; - shell_option.append("--shell-expand-args"); - shell_option.append(" true"); - shell_option.append(" --"); AddAlias("r", cmd_obj_sp, "--shell-expand-args true --"); AddAlias("run", cmd_obj_sp, "--shell-expand-args true --"); +#endif #else StreamString defaultshell; defaultshell.Printf("--shell=%s --", HostInfo::GetDefaultShell().GetPath().c_str()); AddAlias("r", cmd_obj_sp, defaultshell.GetString()); AddAlias("run", cmd_obj_sp, defaultshell.GetString()); -#endif #endif } - cmd_obj_sp = GetCommandSPExact("target symbols add", false); + cmd_obj_sp = GetCommandSPExact("target symbols add"); if (cmd_obj_sp) { AddAlias("add-dsym", cmd_obj_sp); } - cmd_obj_sp = GetCommandSPExact("breakpoint set", false); + cmd_obj_sp = GetCommandSPExact("breakpoint set"); if (cmd_obj_sp) { AddAlias("rbreak", cmd_obj_sp, "--func-regex %1"); } - cmd_obj_sp = GetCommandSPExact("frame variable", false); + cmd_obj_sp = GetCommandSPExact("frame variable"); if (cmd_obj_sp) { AddAlias("v", cmd_obj_sp); AddAlias("var", cmd_obj_sp); AddAlias("vo", cmd_obj_sp, "--object-description"); } - cmd_obj_sp = GetCommandSPExact("register", false); + cmd_obj_sp = GetCommandSPExact("register"); if (cmd_obj_sp) { AddAlias("re", cmd_obj_sp); } + + cmd_obj_sp = GetCommandSPExact("session history"); + if (cmd_obj_sp) { + AddAlias("history", cmd_obj_sp); + } } void CommandInterpreter::Clear() { @@ -460,54 +494,40 @@ const char *CommandInterpreter::ProcessEmbeddedScriptCommands(const char *arg) { return arg; } +#define REGISTER_COMMAND_OBJECT(NAME, CLASS) \ + m_command_dict[NAME] = std::make_shared(*this); + void CommandInterpreter::LoadCommandDictionary() { - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer(func_cat, LLVM_PRETTY_FUNCTION); - - lldb::ScriptLanguage script_language = m_debugger.GetScriptLanguage(); - - m_command_dict["apropos"] = CommandObjectSP(new CommandObjectApropos(*this)); - m_command_dict["breakpoint"] = - CommandObjectSP(new CommandObjectMultiwordBreakpoint(*this)); - m_command_dict["command"] = - CommandObjectSP(new CommandObjectMultiwordCommands(*this)); - m_command_dict["disassemble"] = - CommandObjectSP(new CommandObjectDisassemble(*this)); - m_command_dict["expression"] = - CommandObjectSP(new CommandObjectExpression(*this)); - m_command_dict["frame"] = - CommandObjectSP(new CommandObjectMultiwordFrame(*this)); - m_command_dict["gui"] = CommandObjectSP(new CommandObjectGUI(*this)); - m_command_dict["help"] = CommandObjectSP(new CommandObjectHelp(*this)); - m_command_dict["log"] = CommandObjectSP(new CommandObjectLog(*this)); - m_command_dict["memory"] = CommandObjectSP(new CommandObjectMemory(*this)); - m_command_dict["platform"] = - CommandObjectSP(new CommandObjectPlatform(*this)); - m_command_dict["plugin"] = CommandObjectSP(new CommandObjectPlugin(*this)); - m_command_dict["process"] = - CommandObjectSP(new CommandObjectMultiwordProcess(*this)); - m_command_dict["quit"] = CommandObjectSP(new CommandObjectQuit(*this)); - m_command_dict["register"] = - CommandObjectSP(new CommandObjectRegister(*this)); - m_command_dict["reproducer"] = - CommandObjectSP(new CommandObjectReproducer(*this)); - m_command_dict["script"] = - CommandObjectSP(new CommandObjectScript(*this, script_language)); - m_command_dict["settings"] = - CommandObjectSP(new CommandObjectMultiwordSettings(*this)); - m_command_dict["source"] = - CommandObjectSP(new CommandObjectMultiwordSource(*this)); - m_command_dict["statistics"] = CommandObjectSP(new CommandObjectStats(*this)); - m_command_dict["target"] = - CommandObjectSP(new CommandObjectMultiwordTarget(*this)); - m_command_dict["thread"] = - CommandObjectSP(new CommandObjectMultiwordThread(*this)); - m_command_dict["type"] = CommandObjectSP(new CommandObjectType(*this)); - m_command_dict["version"] = CommandObjectSP(new CommandObjectVersion(*this)); - m_command_dict["watchpoint"] = - CommandObjectSP(new CommandObjectMultiwordWatchpoint(*this)); - m_command_dict["language"] = - CommandObjectSP(new CommandObjectLanguage(*this)); + LLDB_SCOPED_TIMER(); + + REGISTER_COMMAND_OBJECT("apropos", CommandObjectApropos); + REGISTER_COMMAND_OBJECT("breakpoint", CommandObjectMultiwordBreakpoint); + REGISTER_COMMAND_OBJECT("command", CommandObjectMultiwordCommands); + REGISTER_COMMAND_OBJECT("disassemble", CommandObjectDisassemble); + REGISTER_COMMAND_OBJECT("expression", CommandObjectExpression); + REGISTER_COMMAND_OBJECT("frame", CommandObjectMultiwordFrame); + REGISTER_COMMAND_OBJECT("gui", CommandObjectGUI); + REGISTER_COMMAND_OBJECT("help", CommandObjectHelp); + REGISTER_COMMAND_OBJECT("log", CommandObjectLog); + REGISTER_COMMAND_OBJECT("memory", CommandObjectMemory); + REGISTER_COMMAND_OBJECT("platform", CommandObjectPlatform); + REGISTER_COMMAND_OBJECT("plugin", CommandObjectPlugin); + REGISTER_COMMAND_OBJECT("process", CommandObjectMultiwordProcess); + REGISTER_COMMAND_OBJECT("quit", CommandObjectQuit); + REGISTER_COMMAND_OBJECT("register", CommandObjectRegister); + REGISTER_COMMAND_OBJECT("reproducer", CommandObjectReproducer); + REGISTER_COMMAND_OBJECT("script", CommandObjectScript); + REGISTER_COMMAND_OBJECT("settings", CommandObjectMultiwordSettings); + REGISTER_COMMAND_OBJECT("session", CommandObjectSession); + REGISTER_COMMAND_OBJECT("source", CommandObjectMultiwordSource); + REGISTER_COMMAND_OBJECT("statistics", CommandObjectStats); + REGISTER_COMMAND_OBJECT("target", CommandObjectMultiwordTarget); + REGISTER_COMMAND_OBJECT("thread", CommandObjectMultiwordThread); + REGISTER_COMMAND_OBJECT("trace", CommandObjectTrace); + REGISTER_COMMAND_OBJECT("type", CommandObjectType); + REGISTER_COMMAND_OBJECT("version", CommandObjectVersion); + REGISTER_COMMAND_OBJECT("watchpoint", CommandObjectMultiwordWatchpoint); + REGISTER_COMMAND_OBJECT("language", CommandObjectLanguage); // clang-format off const char *break_regexes[][2] = { @@ -624,15 +644,10 @@ void CommandInterpreter::LoadCommandDictionary() { if (tbreak_regex_cmd_up) { bool success = true; for (size_t i = 0; i < num_regexes; i++) { - // If you add a resultant command string longer than 1024 characters be - // sure to increase the size of this buffer. - char buffer[1024]; - int num_printed = - snprintf(buffer, 1024, "%s %s", break_regexes[i][1], "-o 1"); - lldbassert(num_printed < 1024); - UNUSED_IF_ASSERT_DISABLED(num_printed); + std::string command = break_regexes[i][1]; + command += " -o 1"; success = - tbreak_regex_cmd_up->AddRegexCommand(break_regexes[i][0], buffer); + tbreak_regex_cmd_up->AddRegexCommand(break_regexes[i][0], command); if (!success) break; } @@ -1034,47 +1049,46 @@ bool CommandInterpreter::AddUserCommand(llvm::StringRef name, return false; } -CommandObjectSP CommandInterpreter::GetCommandSPExact(llvm::StringRef cmd_str, - bool include_aliases) const { - Args cmd_words(cmd_str); // Break up the command string into words, in case - // it's a multi-word command. - CommandObjectSP ret_val; // Possibly empty return value. +CommandObjectSP +CommandInterpreter::GetCommandSPExact(llvm::StringRef cmd_str, + bool include_aliases) const { + // Break up the command string into words, in case it's a multi-word command. + Args cmd_words(cmd_str); if (cmd_str.empty()) - return ret_val; + return {}; if (cmd_words.GetArgumentCount() == 1) - return GetCommandSP(cmd_str, include_aliases, true, nullptr); - else { - // We have a multi-word command (seemingly), so we need to do more work. - // First, get the cmd_obj_sp for the first word in the command. - CommandObjectSP cmd_obj_sp = GetCommandSP(llvm::StringRef(cmd_words.GetArgumentAtIndex(0)), - include_aliases, true, nullptr); - if (cmd_obj_sp.get() != nullptr) { - // Loop through the rest of the words in the command (everything passed - // in was supposed to be part of a command name), and find the - // appropriate sub-command SP for each command word.... - size_t end = cmd_words.GetArgumentCount(); - for (size_t j = 1; j < end; ++j) { - if (cmd_obj_sp->IsMultiwordObject()) { - cmd_obj_sp = - cmd_obj_sp->GetSubcommandSP(cmd_words.GetArgumentAtIndex(j)); - if (cmd_obj_sp.get() == nullptr) - // The sub-command name was invalid. Fail and return the empty - // 'ret_val'. - return ret_val; - } else - // We have more words in the command name, but we don't have a - // multiword object. Fail and return empty 'ret_val'. - return ret_val; - } - // We successfully looped through all the command words and got valid - // command objects for them. Assign the last object retrieved to - // 'ret_val'. - ret_val = cmd_obj_sp; + return GetCommandSP(cmd_str, include_aliases, true); + + // We have a multi-word command (seemingly), so we need to do more work. + // First, get the cmd_obj_sp for the first word in the command. + CommandObjectSP cmd_obj_sp = + GetCommandSP(cmd_words.GetArgumentAtIndex(0), include_aliases, true); + if (!cmd_obj_sp) + return {}; + + // Loop through the rest of the words in the command (everything passed in + // was supposed to be part of a command name), and find the appropriate + // sub-command SP for each command word.... + size_t end = cmd_words.GetArgumentCount(); + for (size_t i = 1; i < end; ++i) { + if (!cmd_obj_sp->IsMultiwordObject()) { + // We have more words in the command name, but we don't have a + // multiword object. Fail and return. + return {}; + } + + cmd_obj_sp = cmd_obj_sp->GetSubcommandSP(cmd_words.GetArgumentAtIndex(i)); + if (!cmd_obj_sp) { + // The sub-command name was invalid. Fail and return. + return {}; } } - return ret_val; + + // We successfully looped through all the command words and got valid + // command objects for them. + return cmd_obj_sp; } CommandObject * @@ -1461,7 +1475,6 @@ CommandObject *CommandInterpreter::BuildAliasResult( "need at least %d arguments to use " "this alias.\n", index); - result.SetStatus(eReturnStatusFailed); return nullptr; } else { size_t strpos = raw_input_string.find(cmd_args.GetArgumentAtIndex(index)); @@ -1518,16 +1531,12 @@ Status CommandInterpreter::PreprocessCommand(std::string &command) { end_backtick - expr_content_start); ExecutionContext exe_ctx(GetExecutionContext()); - Target *target = exe_ctx.GetTargetPtr(); // Get a dummy target to allow for calculator mode while processing // backticks. This also helps break the infinite loop caused when target is // null. - if (!target) - target = m_debugger.GetDummyTarget(); - - if (!target) - continue; + Target *exe_target = exe_ctx.GetTargetPtr(); + Target &target = exe_target ? *exe_target : m_debugger.GetDummyTarget(); ValueObjectSP expr_result_valobj_sp; @@ -1540,8 +1549,8 @@ Status CommandInterpreter::PreprocessCommand(std::string &command) { options.SetTimeout(llvm::None); ExpressionResults expr_result = - target->EvaluateExpression(expr_str.c_str(), exe_ctx.GetFramePtr(), - expr_result_valobj_sp, options); + target.EvaluateExpression(expr_str.c_str(), exe_ctx.GetFramePtr(), + expr_result_valobj_sp, options); if (expr_result == eExpressionCompleted) { Scalar scalar; @@ -1633,12 +1642,18 @@ Status CommandInterpreter::PreprocessCommand(std::string &command) { bool CommandInterpreter::HandleCommand(const char *command_line, LazyBool lazy_add_to_history, - CommandReturnObject &result, - ExecutionContext *override_context, - bool repeat_on_empty_command, - bool no_context_switching) + const ExecutionContext &override_context, + CommandReturnObject &result) { -{ + OverrideExecutionContext(override_context); + bool status = HandleCommand(command_line, lazy_add_to_history, result); + RestoreExecutionContext(); + return status; +} + +bool CommandInterpreter::HandleCommand(const char *command_line, + LazyBool lazy_add_to_history, + CommandReturnObject &result) { std::string command_string(command_line); std::string original_command_string(command_line); @@ -1648,16 +1663,10 @@ bool CommandInterpreter::HandleCommand(const char *command_line, command_line); LLDB_LOGF(log, "Processing command: %s", command_line); - - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer(func_cat, "Handling command: %s.", command_line); - - if (!no_context_switching) - UpdateExecutionContext(override_context); + LLDB_SCOPED_TIMERF("Processing command: %s.", command_line); if (WasInterrupted()) { result.AppendError("interrupted"); - result.SetStatus(eReturnStatusFailed); return false; } @@ -1667,6 +1676,8 @@ bool CommandInterpreter::HandleCommand(const char *command_line, else add_to_history = (lazy_add_to_history == eLazyBoolYes); + m_transcript_stream << "(lldb) " << command_line << '\n'; + bool empty_command = false; bool comment_command = false; if (command_string.empty()) @@ -1691,33 +1702,31 @@ bool CommandInterpreter::HandleCommand(const char *command_line, } else { result.AppendErrorWithFormat("Could not find entry: %s in history", command_string.c_str()); - result.SetStatus(eReturnStatusFailed); return false; } } } if (empty_command) { - if (repeat_on_empty_command) { - if (m_command_history.IsEmpty()) { - result.AppendError("empty command"); - result.SetStatus(eReturnStatusFailed); - return false; - } else { - command_line = m_repeat_command.c_str(); - command_string = command_line; - original_command_string = command_line; - if (m_repeat_command.empty()) { - result.AppendErrorWithFormat("No auto repeat.\n"); - result.SetStatus(eReturnStatusFailed); - return false; - } - } - add_to_history = false; - } else { + if (!GetRepeatPreviousCommand()) { result.SetStatus(eReturnStatusSuccessFinishNoResult); return true; } + + if (m_command_history.IsEmpty()) { + result.AppendError("empty command"); + return false; + } + + command_line = m_repeat_command.c_str(); + command_string = command_line; + original_command_string = command_line; + if (m_repeat_command.empty()) { + result.AppendError("No auto repeat."); + return false; + } + + add_to_history = false; } else if (comment_command) { result.SetStatus(eReturnStatusSuccessFinishNoResult); return true; @@ -1727,7 +1736,6 @@ bool CommandInterpreter::HandleCommand(const char *command_line, if (error.Fail()) { result.AppendError(error.AsCString()); - result.SetStatus(eReturnStatusFailed); return false; } @@ -1799,6 +1807,9 @@ bool CommandInterpreter::HandleCommand(const char *command_line, LLDB_LOGF(log, "HandleCommand, command %s", (result.Succeeded() ? "succeeded" : "did not succeed")); + m_transcript_stream << result.GetOutputData(); + m_transcript_stream << result.GetErrorData(); + return result.Succeeded(); } @@ -1851,8 +1862,6 @@ void CommandInterpreter::HandleCompletionMatches(CompletionRequest &request) { void CommandInterpreter::HandleCompletion(CompletionRequest &request) { - UpdateExecutionContext(nullptr); - // Don't complete comments, and if the line we are completing is just the // history repeat character, substitute the appropriate history line. llvm::StringRef first_arg = request.GetParsedLine().GetArgumentAtIndex(0); @@ -1871,7 +1880,18 @@ void CommandInterpreter::HandleCompletion(CompletionRequest &request) { HandleCompletionMatches(request); } -CommandInterpreter::~CommandInterpreter() {} +llvm::Optional +CommandInterpreter::GetAutoSuggestionForCommand(llvm::StringRef line) { + if (line.empty()) + return llvm::None; + const size_t s = m_command_history.GetSize(); + for (int i = s - 1; i >= 0; --i) { + llvm::StringRef entry = m_command_history.GetStringAtIndex(i); + if (entry.consume_front(line)) + return entry.str(); + } + return llvm::None; +} void CommandInterpreter::UpdatePrompt(llvm::StringRef new_prompt) { EventSP prompt_change_event_sp( @@ -1975,10 +1995,7 @@ void CommandInterpreter::BuildAliasCommandArgs(CommandObject *alias_cmd_obj, if (value_type != OptionParser::eOptionalArgument) new_args.AppendArgument(value); else { - char buffer[255]; - ::snprintf(buffer, sizeof(buffer), "%s%s", option.c_str(), - value.c_str()); - new_args.AppendArgument(llvm::StringRef(buffer)); + new_args.AppendArgument(option + value); } } else if (static_cast(index) >= cmd_args.GetArgumentCount()) { @@ -1986,7 +2003,6 @@ void CommandInterpreter::BuildAliasCommandArgs(CommandObject *alias_cmd_obj, "need at least %d arguments to use " "this alias.\n", index); - result.SetStatus(eReturnStatusFailed); return; } else { // Find and remove cmd_args.GetArgumentAtIndex(i) from raw_input_string @@ -2000,10 +2016,7 @@ void CommandInterpreter::BuildAliasCommandArgs(CommandObject *alias_cmd_obj, if (value_type != OptionParser::eOptionalArgument) new_args.AppendArgument(cmd_args.GetArgumentAtIndex(index)); else { - char buffer[255]; - ::snprintf(buffer, sizeof(buffer), "%s%s", option.c_str(), - cmd_args.GetArgumentAtIndex(index)); - new_args.AppendArgument(buffer); + new_args.AppendArgument(option + cmd_args.GetArgumentAtIndex(index)); } used[index] = true; } @@ -2070,12 +2083,30 @@ static void GetHomeInitFile(llvm::SmallVectorImpl &init_file, init_file_name.append(suffix.str()); } - llvm::sys::path::home_directory(init_file); + FileSystem::Instance().GetHomeDirectory(init_file); llvm::sys::path::append(init_file, init_file_name); FileSystem::Instance().Resolve(init_file); } +static void GetHomeREPLInitFile(llvm::SmallVectorImpl &init_file) { + LanguageSet repl_languages = Language::GetLanguagesSupportingREPLs(); + LanguageType language = eLanguageTypeUnknown; + if (auto main_repl_language = repl_languages.GetSingularLanguage()) + language = *main_repl_language; + else + return; + + std::string init_file_name = + (llvm::Twine(".lldbinit-") + + llvm::Twine(Language::GetNameForLanguageType(language)) + + llvm::Twine("-repl")) + .str(); + FileSystem::Instance().GetHomeDirectory(init_file); + llvm::sys::path::append(init_file, init_file_name); + FileSystem::Instance().Resolve(init_file); +} + static void GetCwdInitFile(llvm::SmallVectorImpl &init_file) { llvm::StringRef s = ".lldbinit"; init_file.assign(s.begin(), s.end()); @@ -2102,13 +2133,12 @@ void CommandInterpreter::SourceInitFile(FileSpec file, // broadcasting of the commands back to any appropriate listener (see // CommandObjectSource::Execute for more details). const bool saved_batch = SetBatchCommandMode(true); - ExecutionContext *ctx = nullptr; CommandInterpreterRunOptions options; options.SetSilent(true); options.SetPrintErrors(true); options.SetStopOnError(false); options.SetStopOnContinue(true); - HandleCommandsFromFile(file, ctx, options, result); + HandleCommandsFromFile(file, options, result); SetBatchCommandMode(saved_batch); } @@ -2141,8 +2171,7 @@ void CommandInterpreter::SourceInitFileCwd(CommandReturnObject &result) { llvm::sys::path::parent_path(home_init_file)) { result.SetStatus(eReturnStatusSuccessFinishNoResult); } else { - result.AppendErrorWithFormat(InitFileWarning); - result.SetStatus(eReturnStatusFailed); + result.AppendError(InitFileWarning); } } } @@ -2150,15 +2179,22 @@ void CommandInterpreter::SourceInitFileCwd(CommandReturnObject &result) { /// We will first see if there is an application specific ".lldbinit" file /// whose name is "~/.lldbinit" followed by a "-" and the name of the program. -/// If this file doesn't exist, we fall back to just the "~/.lldbinit" file. -void CommandInterpreter::SourceInitFileHome(CommandReturnObject &result) { +/// If this file doesn't exist, we fall back to the REPL init file or the +/// default home init file in "~/.lldbinit". +void CommandInterpreter::SourceInitFileHome(CommandReturnObject &result, + bool is_repl) { if (m_skip_lldbinit_files) { result.SetStatus(eReturnStatusSuccessFinishNoResult); return; } llvm::SmallString<128> init_file; - GetHomeInitFile(init_file); + + if (is_repl) + GetHomeREPLInitFile(init_file); + + if (init_file.empty()) + GetHomeInitFile(init_file); if (!m_skip_app_init_files) { llvm::StringRef program_name = @@ -2192,7 +2228,8 @@ PlatformSP CommandInterpreter::GetPlatform(bool prefer_target_platform) { } bool CommandInterpreter::DidProcessStopAbnormally() const { - TargetSP target_sp = m_debugger.GetTargetList().GetSelectedTarget(); + auto exe_ctx = GetExecutionContext(); + TargetSP target_sp = exe_ctx.GetTargetSP(); if (!target_sp) return false; @@ -2209,7 +2246,9 @@ bool CommandInterpreter::DidProcessStopAbnormally() const { return false; const StopReason reason = stop_info->GetStopReason(); - if (reason == eStopReasonException || reason == eStopReasonInstrumentation) + if (reason == eStopReasonException || + reason == eStopReasonInstrumentation || + reason == eStopReasonProcessorTrace) return true; if (reason == eStopReasonSignal) { @@ -2230,9 +2269,19 @@ bool CommandInterpreter::DidProcessStopAbnormally() const { return false; } +void +CommandInterpreter::HandleCommands(const StringList &commands, + const ExecutionContext &override_context, + const CommandInterpreterRunOptions &options, + CommandReturnObject &result) { + + OverrideExecutionContext(override_context); + HandleCommands(commands, options, result); + RestoreExecutionContext(); +} + void CommandInterpreter::HandleCommands(const StringList &commands, - ExecutionContext *override_context, - CommandInterpreterRunOptions &options, + const CommandInterpreterRunOptions &options, CommandReturnObject &result) { size_t num_lines = commands.GetSize(); @@ -2242,13 +2291,6 @@ void CommandInterpreter::HandleCommands(const StringList &commands, bool old_async_execution = m_debugger.GetAsyncExecution(); - // If we've been given an execution context, set it at the start, but don't - // keep resetting it or we will cause series of commands that change the - // context, then do an operation that relies on that context to fail. - - if (override_context != nullptr) - UpdateExecutionContext(override_context); - if (!options.GetStopOnContinue()) { m_debugger.SetAsyncExecution(false); } @@ -2265,19 +2307,15 @@ void CommandInterpreter::HandleCommands(const StringList &commands, } CommandReturnObject tmp_result(m_debugger.GetUseColor()); - // If override_context is not NULL, pass no_context_switching = true for - // HandleCommand() since we updated our context already. + tmp_result.SetInteractive(result.GetInteractive()); + tmp_result.SetSuppressImmediateOutput(true); // We might call into a regex or alias command, in which case the // add_to_history will get lost. This m_command_source_depth dingus is the // way we turn off adding to the history in that case, so set it up here. if (!options.GetAddToHistory()) m_command_source_depth++; - bool success = - HandleCommand(cmd, options.m_add_to_history, tmp_result, - nullptr, /* override_context */ - true, /* repeat_on_empty_command */ - override_context != nullptr /* no_context_switching */); + bool success = HandleCommand(cmd, options.m_add_to_history, tmp_result); if (!options.GetAddToHistory()) m_command_source_depth--; @@ -2295,7 +2333,6 @@ void CommandInterpreter::HandleCommands(const StringList &commands, "Aborting reading of commands after command #%" PRIu64 ": '%s' failed with %s", (uint64_t)idx, cmd, error_msg.str().c_str()); - result.SetStatus(eReturnStatusFailed); m_debugger.SetAsyncExecution(old_async_execution); return; } else if (options.GetPrintResults()) { @@ -2378,13 +2415,19 @@ enum { }; void CommandInterpreter::HandleCommandsFromFile( - FileSpec &cmd_file, ExecutionContext *context, - CommandInterpreterRunOptions &options, CommandReturnObject &result) { + FileSpec &cmd_file, const ExecutionContext &context, + const CommandInterpreterRunOptions &options, CommandReturnObject &result) { + OverrideExecutionContext(context); + HandleCommandsFromFile(cmd_file, options, result); + RestoreExecutionContext(); +} + +void CommandInterpreter::HandleCommandsFromFile(FileSpec &cmd_file, + const CommandInterpreterRunOptions &options, CommandReturnObject &result) { if (!FileSystem::Instance().Exists(cmd_file)) { result.AppendErrorWithFormat( "Error reading commands from file %s - file not found.\n", cmd_file.GetFilename().AsCString("")); - result.SetStatus(eReturnStatusFailed); return; } @@ -2396,7 +2439,6 @@ void CommandInterpreter::HandleCommandsFromFile( result.AppendErrorWithFormatv( "error: an error occurred read file '{0}': {1}\n", cmd_file_path, llvm::fmt_consume(input_file_up.takeError())); - result.SetStatus(eReturnStatusFailed); return; } FileSP input_file_sp = FileSP(std::move(input_file_up.get())); @@ -2512,11 +2554,15 @@ void CommandInterpreter::HandleCommandsFromFile( debugger.SetAsyncExecution(false); m_command_source_depth++; + m_command_source_dirs.push_back(cmd_file.CopyByRemovingLastPathComponent()); debugger.RunIOHandlerSync(io_handler_sp); if (!m_command_source_flags.empty()) m_command_source_flags.pop_back(); + + m_command_source_dirs.pop_back(); m_command_source_depth--; + result.SetStatus(eReturnStatusSuccessFinishNoResult); debugger.SetAsyncExecution(old_async_execution); } @@ -2639,7 +2685,7 @@ void CommandInterpreter::FindCommandsForApropos( const bool search_long_help = false; const bool search_syntax = false; const bool search_options = false; - if (command_name.contains_lower(search_word) || + if (command_name.contains_insensitive(search_word) || cmd_obj->HelpTextContainsWord(search_word, search_short_help, search_long_help, search_syntax, search_options)) { @@ -2676,23 +2722,24 @@ void CommandInterpreter::FindCommandsForApropos(llvm::StringRef search_word, m_alias_dict); } -void CommandInterpreter::UpdateExecutionContext( - ExecutionContext *override_context) { - if (override_context != nullptr) { - m_exe_ctx_ref = *override_context; - } else { - const bool adopt_selected = true; - m_exe_ctx_ref.SetTargetPtr(m_debugger.GetSelectedTarget().get(), - adopt_selected); - } +ExecutionContext CommandInterpreter::GetExecutionContext() const { + return !m_overriden_exe_contexts.empty() + ? m_overriden_exe_contexts.top() + : m_debugger.GetSelectedExecutionContext(); } -void CommandInterpreter::GetProcessOutput() { - TargetSP target_sp(m_debugger.GetTargetList().GetSelectedTarget()); - if (!target_sp) - return; +void CommandInterpreter::OverrideExecutionContext( + const ExecutionContext &override_context) { + m_overriden_exe_contexts.push(override_context); +} - if (ProcessSP process_sp = target_sp->GetProcessSP()) +void CommandInterpreter::RestoreExecutionContext() { + if (!m_overriden_exe_contexts.empty()) + m_overriden_exe_contexts.pop(); +} + +void CommandInterpreter::GetProcessOutput() { + if (ProcessSP process_sp = GetExecutionContext().GetProcessSP()) m_debugger.FlushProcessOutput(*process_sp, /*flush_stdout*/ true, /*flush_stderr*/ true); } @@ -2792,6 +2839,11 @@ void CommandInterpreter::IOHandlerInputComplete(IOHandler &io_handler, StartHandlingCommand(); + OverrideExecutionContext(m_debugger.GetSelectedExecutionContext()); + auto finalize = llvm::make_scope_exit([this]() { + RestoreExecutionContext(); + }); + lldb_private::CommandReturnObject result(m_debugger.GetUseColor()); HandleCommand(line.c_str(), eLazyBoolCalculate, result); @@ -2877,15 +2929,73 @@ bool CommandInterpreter::IOHandlerInterrupt(IOHandler &io_handler) { return false; } +bool CommandInterpreter::SaveTranscript( + CommandReturnObject &result, llvm::Optional output_file) { + if (output_file == llvm::None || output_file->empty()) { + std::string now = llvm::to_string(std::chrono::system_clock::now()); + std::replace(now.begin(), now.end(), ' ', '_'); + const std::string file_name = "lldb_session_" + now + ".log"; + + FileSpec save_location = GetSaveSessionDirectory(); + + if (!save_location) + save_location = HostInfo::GetGlobalTempDir(); + + FileSystem::Instance().Resolve(save_location); + save_location.AppendPathComponent(file_name); + output_file = save_location.GetPath(); + } + + auto error_out = [&](llvm::StringRef error_message, std::string description) { + LLDB_LOG(GetLogIfAllCategoriesSet(LIBLLDB_LOG_COMMANDS), "{0} ({1}:{2})", + error_message, output_file, description); + result.AppendErrorWithFormatv( + "Failed to save session's transcripts to {0}!", *output_file); + return false; + }; + + File::OpenOptions flags = File::eOpenOptionWrite | + File::eOpenOptionCanCreate | + File::eOpenOptionTruncate; + + auto opened_file = FileSystem::Instance().Open(FileSpec(*output_file), flags); + + if (!opened_file) + return error_out("Unable to create file", + llvm::toString(opened_file.takeError())); + + FileUP file = std::move(opened_file.get()); + + size_t byte_size = m_transcript_stream.GetSize(); + + Status error = file->Write(m_transcript_stream.GetData(), byte_size); + + if (error.Fail() || byte_size != m_transcript_stream.GetSize()) + return error_out("Unable to write to destination file", + "Bytes written do not match transcript size."); + + result.SetStatus(eReturnStatusSuccessFinishNoResult); + result.AppendMessageWithFormat("Session's transcripts saved to %s\n", + output_file->c_str()); + + return true; +} + +FileSpec CommandInterpreter::GetCurrentSourceDir() { + if (m_command_source_dirs.empty()) + return {}; + return m_command_source_dirs.back(); +} + void CommandInterpreter::GetLLDBCommandsFromIOHandler( const char *prompt, IOHandlerDelegate &delegate, void *baton) { Debugger &debugger = GetDebugger(); IOHandlerSP io_handler_sp( new IOHandlerEditline(debugger, IOHandler::Type::CommandList, "lldb", // Name of input reader for history - llvm::StringRef::withNullAsEmpty(prompt), // Prompt - llvm::StringRef(), // Continuation prompt - true, // Get multiple lines + llvm::StringRef(prompt), // Prompt + llvm::StringRef(), // Continuation prompt + true, // Get multiple lines debugger.GetUseColor(), 0, // Don't show line numbers delegate, // IOHandlerDelegate @@ -2903,9 +3013,9 @@ void CommandInterpreter::GetPythonCommandsFromIOHandler( IOHandlerSP io_handler_sp( new IOHandlerEditline(debugger, IOHandler::Type::PythonCode, "lldb-python", // Name of input reader for history - llvm::StringRef::withNullAsEmpty(prompt), // Prompt - llvm::StringRef(), // Continuation prompt - true, // Get multiple lines + llvm::StringRef(prompt), // Prompt + llvm::StringRef(), // Continuation prompt + true, // Get multiple lines debugger.GetUseColor(), 0, // Don't show line numbers delegate, // IOHandlerDelegate @@ -2998,7 +3108,6 @@ CommandInterpreter::ResolveCommandImpl(std::string &command_line, CommandObject *cmd_obj = nullptr; StreamString revised_command_line; bool wants_raw_input = false; - size_t actual_cmd_name_len = 0; std::string next_word; StringList matches; bool done = false; @@ -3020,12 +3129,10 @@ CommandInterpreter::ResolveCommandImpl(std::string &command_line, revised_command_line.Printf("%s", alias_result.c_str()); if (cmd_obj) { wants_raw_input = cmd_obj->WantsRawCommandString(); - actual_cmd_name_len = cmd_obj->GetCommandName().size(); } } else { if (cmd_obj) { llvm::StringRef cmd_name = cmd_obj->GetCommandName(); - actual_cmd_name_len += cmd_name.size(); revised_command_line.Printf("%s", cmd_name.str().c_str()); wants_raw_input = cmd_obj->WantsRawCommandString(); } else { @@ -3040,7 +3147,6 @@ CommandInterpreter::ResolveCommandImpl(std::string &command_line, // The subcommand's name includes the parent command's name, so // restart rather than append to the revised_command_line. llvm::StringRef sub_cmd_name = sub_cmd_obj->GetCommandName(); - actual_cmd_name_len = sub_cmd_name.size() + 1; revised_command_line.Clear(); revised_command_line.Printf("%s", sub_cmd_name.str().c_str()); cmd_obj = sub_cmd_obj; @@ -3084,7 +3190,6 @@ CommandInterpreter::ResolveCommandImpl(std::string &command_line, result.AppendErrorWithFormat("'%s' is not a valid command.\n", next_word.c_str()); } - result.SetStatus(eReturnStatusFailed); return nullptr; } @@ -3096,7 +3201,6 @@ CommandInterpreter::ResolveCommandImpl(std::string &command_line, cmd_obj->GetCommandName().str().c_str(), next_word.empty() ? "" : next_word.c_str(), next_word.empty() ? " -- " : " ", suffix.c_str()); - result.SetStatus(eReturnStatusFailed); return nullptr; } } else { @@ -3132,7 +3236,6 @@ CommandInterpreter::ResolveCommandImpl(std::string &command_line, result.AppendErrorWithFormat( "the '%s' command doesn't support the --gdb-format option\n", cmd_obj->GetCommandName().str().c_str()); - result.SetStatus(eReturnStatusFailed); return nullptr; } } @@ -3141,7 +3244,6 @@ CommandInterpreter::ResolveCommandImpl(std::string &command_line, default: result.AppendErrorWithFormat( "unknown command shorthand suffix: '%s'\n", suffix.c_str()); - result.SetStatus(eReturnStatusFailed); return nullptr; } } diff --git a/gnu/llvm/lldb/source/Interpreter/CommandObject.cpp b/gnu/llvm/lldb/source/Interpreter/CommandObject.cpp index 538f7a1ba69..a7dcd568270 100644 --- a/gnu/llvm/lldb/source/Interpreter/CommandObject.cpp +++ b/gnu/llvm/lldb/source/Interpreter/CommandObject.cpp @@ -12,8 +12,8 @@ #include #include -#include -#include +#include +#include #include "lldb/Core/Address.h" #include "lldb/Interpreter/Options.h" @@ -42,15 +42,12 @@ CommandObject::CommandObject(CommandInterpreter &interpreter, llvm::StringRef name, llvm::StringRef help, llvm::StringRef syntax, uint32_t flags) : m_interpreter(interpreter), m_cmd_name(std::string(name)), - m_cmd_help_short(), m_cmd_help_long(), m_cmd_syntax(), m_flags(flags), - m_arguments(), m_deprecated_command_override_callback(nullptr), + m_flags(flags), m_deprecated_command_override_callback(nullptr), m_command_override_callback(nullptr), m_command_override_baton(nullptr) { m_cmd_help_short = std::string(help); m_cmd_syntax = std::string(syntax); } -CommandObject::~CommandObject() {} - Debugger &CommandObject::GetDebugger() { return m_interpreter.GetDebugger(); } llvm::StringRef CommandObject::GetHelp() { return m_cmd_help_short; } @@ -222,7 +219,6 @@ bool CommandObject::CheckRequirements(CommandReturnObject &result) { // A process that is not running is considered paused. if (GetFlags().Test(eCommandProcessMustBeLaunched)) { result.AppendError("Process must exist."); - result.SetStatus(eReturnStatusFailed); return false; } } else { @@ -242,7 +238,6 @@ bool CommandObject::CheckRequirements(CommandReturnObject &result) { case eStateUnloaded: if (GetFlags().Test(eCommandProcessMustBeLaunched)) { result.AppendError("Process must be launched."); - result.SetStatus(eReturnStatusFailed); return false; } break; @@ -252,12 +247,20 @@ bool CommandObject::CheckRequirements(CommandReturnObject &result) { if (GetFlags().Test(eCommandProcessMustBePaused)) { result.AppendError("Process is running. Use 'process interrupt' to " "pause execution."); - result.SetStatus(eReturnStatusFailed); return false; } } } } + + if (GetFlags().Test(eCommandProcessMustBeTraced)) { + Target *target = m_exe_ctx.GetTargetPtr(); + if (target && !target->GetTrace()) { + result.AppendError("Process is not being traced."); + return false; + } + } + return true; } @@ -313,11 +316,11 @@ bool CommandObject::HelpTextContainsWord(llvm::StringRef search_word, llvm::StringRef long_help = GetHelpLong(); llvm::StringRef syntax_help = GetSyntax(); - if (search_short_help && short_help.contains_lower(search_word)) + if (search_short_help && short_help.contains_insensitive(search_word)) found_word = true; - else if (search_long_help && long_help.contains_lower(search_word)) + else if (search_long_help && long_help.contains_insensitive(search_word)) found_word = true; - else if (search_syntax && syntax_help.contains_lower(search_word)) + else if (search_syntax && syntax_help.contains_insensitive(search_word)) found_word = true; if (!found_word && search_options && GetOptions() != nullptr) { @@ -327,7 +330,7 @@ bool CommandObject::HelpTextContainsWord(llvm::StringRef search_word, GetCommandInterpreter().GetDebugger().GetTerminalWidth()); if (!usage_help.Empty()) { llvm::StringRef usage_text = usage_help.GetString(); - if (usage_text.contains_lower(search_word)) + if (usage_text.contains_insensitive(search_word)) found_word = true; } } @@ -345,7 +348,6 @@ bool CommandObject::ParseOptionsAndNotify(Args &args, Status error(group_options.NotifyOptionParsingFinished(&exe_ctx)); if (error.Fail()) { result.AppendError(error.AsCString()); - result.SetStatus(eReturnStatusFailed); return false; } return true; @@ -930,11 +932,11 @@ const char *CommandObject::GetArgumentDescriptionAsCString( } Target &CommandObject::GetDummyTarget() { - return *m_interpreter.GetDebugger().GetDummyTarget(); + return m_interpreter.GetDebugger().GetDummyTarget(); } Target &CommandObject::GetSelectedOrDummyTarget(bool prefer_dummy) { - return *m_interpreter.GetDebugger().GetSelectedOrDummyTarget(prefer_dummy); + return m_interpreter.GetDebugger().GetSelectedOrDummyTarget(prefer_dummy); } Target &CommandObject::GetSelectedTarget() { @@ -1041,13 +1043,13 @@ CommandObject::ArgumentTableEntry CommandObject::g_arguments_data[] = { { eArgTypeBoolean, "boolean", CommandCompletions::eNoCompletion, { nullptr, false }, "A Boolean value: 'true' or 'false'" }, { eArgTypeBreakpointID, "breakpt-id", CommandCompletions::eNoCompletion, { BreakpointIDHelpTextCallback, false }, nullptr }, { eArgTypeBreakpointIDRange, "breakpt-id-list", CommandCompletions::eNoCompletion, { BreakpointIDRangeHelpTextCallback, false }, nullptr }, - { eArgTypeBreakpointName, "breakpoint-name", CommandCompletions::eNoCompletion, { BreakpointNameHelpTextCallback, false }, nullptr }, + { eArgTypeBreakpointName, "breakpoint-name", CommandCompletions::eBreakpointNameCompletion, { BreakpointNameHelpTextCallback, false }, nullptr }, { eArgTypeByteSize, "byte-size", CommandCompletions::eNoCompletion, { nullptr, false }, "Number of bytes to use." }, { eArgTypeClassName, "class-name", CommandCompletions::eNoCompletion, { nullptr, false }, "Then name of a class from the debug information in the program." }, { eArgTypeCommandName, "cmd-name", CommandCompletions::eNoCompletion, { nullptr, false }, "A debugger command (may be multiple words), without any options or arguments." }, { eArgTypeCount, "count", CommandCompletions::eNoCompletion, { nullptr, false }, "An unsigned integer." }, { eArgTypeDirectoryName, "directory", CommandCompletions::eDiskDirectoryCompletion, { nullptr, false }, "A directory name." }, - { eArgTypeDisassemblyFlavor, "disassembly-flavor", CommandCompletions::eNoCompletion, { nullptr, false }, "A disassembly flavor recognized by your disassembly plugin. Currently the only valid options are \"att\" and \"intel\" for Intel targets" }, + { eArgTypeDisassemblyFlavor, "disassembly-flavor", CommandCompletions::eDisassemblyFlavorCompletion, { nullptr, false }, "A disassembly flavor recognized by your disassembly plugin. Currently the only valid options are \"att\" and \"intel\" for Intel targets" }, { eArgTypeDescriptionVerbosity, "description-verbosity", CommandCompletions::eNoCompletion, { nullptr, false }, "How verbose the output of 'po' should be." }, { eArgTypeEndAddress, "end-address", CommandCompletions::eNoCompletion, { nullptr, false }, "Help text goes here." }, { eArgTypeExpression, "expr", CommandCompletions::eNoCompletion, { nullptr, false }, "Help text goes here." }, @@ -1055,19 +1057,20 @@ CommandObject::ArgumentTableEntry CommandObject::g_arguments_data[] = { { eArgTypeExprFormat, "expression-format", CommandCompletions::eNoCompletion, { nullptr, false }, "[ [bool|b] | [bin] | [char|c] | [oct|o] | [dec|i|d|u] | [hex|x] | [float|f] | [cstr|s] ]" }, { eArgTypeFilename, "filename", CommandCompletions::eDiskFileCompletion, { nullptr, false }, "The name of a file (can include path)." }, { eArgTypeFormat, "format", CommandCompletions::eNoCompletion, { FormatHelpTextCallback, true }, nullptr }, - { eArgTypeFrameIndex, "frame-index", CommandCompletions::eNoCompletion, { nullptr, false }, "Index into a thread's list of frames." }, + { eArgTypeFrameIndex, "frame-index", CommandCompletions::eFrameIndexCompletion, { nullptr, false }, "Index into a thread's list of frames." }, { eArgTypeFullName, "fullname", CommandCompletions::eNoCompletion, { nullptr, false }, "Help text goes here." }, { eArgTypeFunctionName, "function-name", CommandCompletions::eNoCompletion, { nullptr, false }, "The name of a function." }, { eArgTypeFunctionOrSymbol, "function-or-symbol", CommandCompletions::eNoCompletion, { nullptr, false }, "The name of a function or symbol." }, { eArgTypeGDBFormat, "gdb-format", CommandCompletions::eNoCompletion, { GDBFormatHelpTextCallback, true }, nullptr }, { eArgTypeHelpText, "help-text", CommandCompletions::eNoCompletion, { nullptr, false }, "Text to be used as help for some other entity in LLDB" }, { eArgTypeIndex, "index", CommandCompletions::eNoCompletion, { nullptr, false }, "An index into a list." }, - { eArgTypeLanguage, "source-language", CommandCompletions::eNoCompletion, { LanguageTypeHelpTextCallback, true }, nullptr }, + { eArgTypeLanguage, "source-language", CommandCompletions::eTypeLanguageCompletion, { LanguageTypeHelpTextCallback, true }, nullptr }, { eArgTypeLineNum, "linenum", CommandCompletions::eNoCompletion, { nullptr, false }, "Line number in a source file." }, + { eArgTypeFileLineColumn, "linespec", CommandCompletions::eNoCompletion, { nullptr, false }, "A source specifier in the form file:line[:column]" }, { eArgTypeLogCategory, "log-category", CommandCompletions::eNoCompletion, { nullptr, false }, "The name of a category within a log channel, e.g. all (try \"log list\" to see a list of all channels and their categories." }, { eArgTypeLogChannel, "log-channel", CommandCompletions::eNoCompletion, { nullptr, false }, "The name of a log channel, e.g. process.gdb-remote (try \"log list\" to see a list of all channels and their categories)." }, { eArgTypeMethod, "method", CommandCompletions::eNoCompletion, { nullptr, false }, "A C++ method name." }, - { eArgTypeName, "name", CommandCompletions::eNoCompletion, { nullptr, false }, "Help text goes here." }, + { eArgTypeName, "name", CommandCompletions::eTypeCategoryNameCompletion, { nullptr, false }, "Help text goes here." }, { eArgTypeNewPathPrefix, "new-path-prefix", CommandCompletions::eNoCompletion, { nullptr, false }, "Help text goes here." }, { eArgTypeNumLines, "num-lines", CommandCompletions::eNoCompletion, { nullptr, false }, "The number of lines to use." }, { eArgTypeNumberPerLine, "number-per-line", CommandCompletions::eNoCompletion, { nullptr, false }, "The number of items per line to display." }, @@ -1077,9 +1080,9 @@ CommandObject::ArgumentTableEntry CommandObject::g_arguments_data[] = { { eArgTypePath, "path", CommandCompletions::eDiskFileCompletion, { nullptr, false }, "Path." }, { eArgTypePermissionsNumber, "perms-numeric", CommandCompletions::eNoCompletion, { nullptr, false }, "Permissions given as an octal number (e.g. 755)." }, { eArgTypePermissionsString, "perms=string", CommandCompletions::eNoCompletion, { nullptr, false }, "Permissions given as a string value (e.g. rw-r-xr--)." }, - { eArgTypePid, "pid", CommandCompletions::eNoCompletion, { nullptr, false }, "The process ID number." }, + { eArgTypePid, "pid", CommandCompletions::eProcessIDCompletion, { nullptr, false }, "The process ID number." }, { eArgTypePlugin, "plugin", CommandCompletions::eProcessPluginCompletion, { nullptr, false }, "Help text goes here." }, - { eArgTypeProcessName, "process-name", CommandCompletions::eNoCompletion, { nullptr, false }, "The name of the process." }, + { eArgTypeProcessName, "process-name", CommandCompletions::eProcessNameCompletion, { nullptr, false }, "The name of the process." }, { eArgTypePythonClass, "python-class", CommandCompletions::eNoCompletion, { nullptr, false }, "The name of a Python class." }, { eArgTypePythonFunction, "python-function", CommandCompletions::eNoCompletion, { nullptr, false }, "The name of a Python function." }, { eArgTypePythonScript, "python-script", CommandCompletions::eNoCompletion, { nullptr, false }, "Source code written in Python." }, @@ -1118,7 +1121,9 @@ CommandObject::ArgumentTableEntry CommandObject::g_arguments_data[] = { { eArgTypeWatchType, "watch-type", CommandCompletions::eNoCompletion, { nullptr, false }, "Specify the type for a watchpoint." }, { eArgRawInput, "raw-input", CommandCompletions::eNoCompletion, { nullptr, false }, "Free-form text passed to a command without prior interpretation, allowing spaces without requiring quotes. To pass arguments and free form text put two dashes ' -- ' between the last argument and any raw input." }, { eArgTypeCommand, "command", CommandCompletions::eNoCompletion, { nullptr, false }, "An LLDB Command line command." }, - { eArgTypeColumnNum, "column", CommandCompletions::eNoCompletion, { nullptr, false }, "Column number in a source file." } + { eArgTypeColumnNum, "column", CommandCompletions::eNoCompletion, { nullptr, false }, "Column number in a source file." }, + { eArgTypeModuleUUID, "module-uuid", CommandCompletions::eModuleUUIDCompletion, { nullptr, false }, "A module UUID value." }, + { eArgTypeSaveCoreStyle, "corefile-style", CommandCompletions::eNoCompletion, { nullptr, false }, "The type of corefile that lldb will try to create, dependant on this target's capabilities." } // clang-format on }; diff --git a/gnu/llvm/lldb/source/Interpreter/CommandReturnObject.cpp b/gnu/llvm/lldb/source/Interpreter/CommandReturnObject.cpp index 6f3732e3507..506b0d6e7cd 100644 --- a/gnu/llvm/lldb/source/Interpreter/CommandReturnObject.cpp +++ b/gnu/llvm/lldb/source/Interpreter/CommandReturnObject.cpp @@ -41,13 +41,11 @@ static void DumpStringToStreamWithNewline(Stream &strm, const std::string &s) { } CommandReturnObject::CommandReturnObject(bool colors) - : m_out_stream(colors), m_err_stream(colors), - m_status(eReturnStatusStarted), m_did_change_process_state(false), - m_interactive(true) {} - -CommandReturnObject::~CommandReturnObject() {} + : m_out_stream(colors), m_err_stream(colors) {} void CommandReturnObject::AppendErrorWithFormat(const char *format, ...) { + SetStatus(eReturnStatusFailed); + if (!format) return; va_list args; @@ -90,52 +88,33 @@ void CommandReturnObject::AppendWarningWithFormat(const char *format, ...) { void CommandReturnObject::AppendMessage(llvm::StringRef in_string) { if (in_string.empty()) return; - GetOutputStream() << in_string << "\n"; + GetOutputStream() << in_string.rtrim() << '\n'; } void CommandReturnObject::AppendWarning(llvm::StringRef in_string) { if (in_string.empty()) return; - warning(GetErrorStream()) << in_string << '\n'; -} - -// Similar to AppendWarning, but do not prepend 'warning: ' to message, and -// don't append "\n" to the end of it. - -void CommandReturnObject::AppendRawWarning(llvm::StringRef in_string) { - if (in_string.empty()) - return; - GetErrorStream() << in_string; + warning(GetErrorStream()) << in_string.rtrim() << '\n'; } void CommandReturnObject::AppendError(llvm::StringRef in_string) { + SetStatus(eReturnStatusFailed); if (in_string.empty()) return; - error(GetErrorStream()) << in_string << '\n'; + error(GetErrorStream()) << in_string.rtrim() << '\n'; } void CommandReturnObject::SetError(const Status &error, const char *fallback_error_cstr) { - const char *error_cstr = error.AsCString(); - if (error_cstr == nullptr) - error_cstr = fallback_error_cstr; - SetError(error_cstr); -} - -void CommandReturnObject::SetError(llvm::StringRef error_str) { - if (error_str.empty()) - return; - - AppendError(error_str); - SetStatus(eReturnStatusFailed); + AppendError(error.AsCString(fallback_error_cstr)); } // Similar to AppendError, but do not prepend 'Status: ' to message, and don't // append "\n" to the end of it. void CommandReturnObject::AppendRawError(llvm::StringRef in_string) { - if (in_string.empty()) - return; + SetStatus(eReturnStatusFailed); + assert(!in_string.empty() && "Expected a non-empty error message"); GetErrorStream() << in_string; } @@ -162,6 +141,7 @@ void CommandReturnObject::Clear() { static_cast(stream_sp.get())->Clear(); m_status = eReturnStatusStarted; m_did_change_process_state = false; + m_suppress_immediate_output = false; m_interactive = true; } @@ -176,3 +156,11 @@ void CommandReturnObject::SetDidChangeProcessState(bool b) { bool CommandReturnObject::GetInteractive() const { return m_interactive; } void CommandReturnObject::SetInteractive(bool b) { m_interactive = b; } + +bool CommandReturnObject::GetSuppressImmediateOutput() const { + return m_suppress_immediate_output; +} + +void CommandReturnObject::SetSuppressImmediateOutput(bool b) { + m_suppress_immediate_output = b; +} diff --git a/gnu/llvm/lldb/source/Interpreter/InterpreterProperties.td b/gnu/llvm/lldb/source/Interpreter/InterpreterProperties.td index 600c1e3edb9..1c6f0206c48 100644 --- a/gnu/llvm/lldb/source/Interpreter/InterpreterProperties.td +++ b/gnu/llvm/lldb/source/Interpreter/InterpreterProperties.td @@ -9,6 +9,13 @@ let Definition = "interpreter" in { Global, DefaultTrue, Desc<"If true, LLDB will prompt you before quitting if there are any live processes being debugged. If false, LLDB will quit without asking in any case.">; + def SaveSessionOnQuit: Property<"save-session-on-quit", "Boolean">, + Global, + DefaultFalse, + Desc<"If true, LLDB will save the session's transcripts before quitting.">; + def SaveSessionDirectory: Property<"save-session-directory", "FileSpec">, + DefaultStringValue<"">, + Desc<"A path where LLDB will save the session's transcripts. This is particularly useful when you can't set the session file, for example when using `save-session-on-quit`.">; def StopCmdSourceOnError: Property<"stop-command-source-on-error", "Boolean">, Global, DefaultTrue, @@ -25,4 +32,8 @@ let Definition = "interpreter" in { Global, DefaultTrue, Desc<"If true, commands will be echoed even if they are pure comment lines.">; + def RepeatPreviousCommand: Property<"repeat-previous-command", "Boolean">, + Global, + DefaultTrue, + Desc<"If true, LLDB will repeat the previous command if no command was passed to the interpreter. If false, LLDB won't repeat the previous command but only return a new prompt.">; } diff --git a/gnu/llvm/lldb/source/Interpreter/OptionArgParser.cpp b/gnu/llvm/lldb/source/Interpreter/OptionArgParser.cpp index 3dcb30e846d..93b01abde4b 100644 --- a/gnu/llvm/lldb/source/Interpreter/OptionArgParser.cpp +++ b/gnu/llvm/lldb/source/Interpreter/OptionArgParser.cpp @@ -20,11 +20,11 @@ bool OptionArgParser::ToBoolean(llvm::StringRef ref, bool fail_value, if (success_ptr) *success_ptr = true; ref = ref.trim(); - if (ref.equals_lower("false") || ref.equals_lower("off") || - ref.equals_lower("no") || ref.equals_lower("0")) { + if (ref.equals_insensitive("false") || ref.equals_insensitive("off") || + ref.equals_insensitive("no") || ref.equals_insensitive("0")) { return false; - } else if (ref.equals_lower("true") || ref.equals_lower("on") || - ref.equals_lower("yes") || ref.equals_lower("1")) { + } else if (ref.equals_insensitive("true") || ref.equals_insensitive("on") || + ref.equals_insensitive("yes") || ref.equals_insensitive("1")) { return true; } if (success_ptr) @@ -125,13 +125,13 @@ lldb::ScriptLanguage OptionArgParser::ToScriptLanguage( if (success_ptr) *success_ptr = true; - if (s.equals_lower("python")) + if (s.equals_insensitive("python")) return eScriptLanguagePython; - if (s.equals_lower("lua")) + if (s.equals_insensitive("lua")) return eScriptLanguageLua; - if (s.equals_lower("default")) + if (s.equals_insensitive("default")) return eScriptLanguageDefault; - if (s.equals_lower("none")) + if (s.equals_insensitive("none")) return eScriptLanguageNone; if (success_ptr) diff --git a/gnu/llvm/lldb/source/Interpreter/OptionGroupArchitecture.cpp b/gnu/llvm/lldb/source/Interpreter/OptionGroupArchitecture.cpp index baca1c6e806..00541b7198d 100644 --- a/gnu/llvm/lldb/source/Interpreter/OptionGroupArchitecture.cpp +++ b/gnu/llvm/lldb/source/Interpreter/OptionGroupArchitecture.cpp @@ -13,10 +13,6 @@ using namespace lldb; using namespace lldb_private; -OptionGroupArchitecture::OptionGroupArchitecture() : m_arch_str() {} - -OptionGroupArchitecture::~OptionGroupArchitecture() {} - static constexpr OptionDefinition g_option_table[] = { {LLDB_OPT_SET_1, false, "arch", 'a', OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeArchitecture, diff --git a/gnu/llvm/lldb/source/Interpreter/OptionGroupBoolean.cpp b/gnu/llvm/lldb/source/Interpreter/OptionGroupBoolean.cpp index 3482e784ca0..3f73893fca9 100644 --- a/gnu/llvm/lldb/source/Interpreter/OptionGroupBoolean.cpp +++ b/gnu/llvm/lldb/source/Interpreter/OptionGroupBoolean.cpp @@ -33,8 +33,6 @@ OptionGroupBoolean::OptionGroupBoolean(uint32_t usage_mask, bool required, m_option_definition.usage_text = usage_text; } -OptionGroupBoolean::~OptionGroupBoolean() {} - Status OptionGroupBoolean::SetOptionValue(uint32_t option_idx, llvm::StringRef option_value, ExecutionContext *execution_context) { diff --git a/gnu/llvm/lldb/source/Interpreter/OptionGroupFile.cpp b/gnu/llvm/lldb/source/Interpreter/OptionGroupFile.cpp index 9d9be5b6f17..12ade185582 100644 --- a/gnu/llvm/lldb/source/Interpreter/OptionGroupFile.cpp +++ b/gnu/llvm/lldb/source/Interpreter/OptionGroupFile.cpp @@ -17,8 +17,7 @@ OptionGroupFile::OptionGroupFile(uint32_t usage_mask, bool required, const char *long_option, int short_option, uint32_t completion_type, lldb::CommandArgumentType argument_type, - const char *usage_text) - : m_file() { + const char *usage_text) { m_option_definition.usage_mask = usage_mask; m_option_definition.required = required; m_option_definition.long_option = long_option; @@ -31,8 +30,6 @@ OptionGroupFile::OptionGroupFile(uint32_t usage_mask, bool required, m_option_definition.usage_text = usage_text; } -OptionGroupFile::~OptionGroupFile() {} - Status OptionGroupFile::SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, ExecutionContext *execution_context) { @@ -62,7 +59,7 @@ OptionGroupFileList::OptionGroupFileList( m_option_definition.usage_text = usage_text; } -OptionGroupFileList::~OptionGroupFileList() {} +OptionGroupFileList::~OptionGroupFileList() = default; Status OptionGroupFileList::SetOptionValue(uint32_t option_idx, diff --git a/gnu/llvm/lldb/source/Interpreter/OptionGroupFormat.cpp b/gnu/llvm/lldb/source/Interpreter/OptionGroupFormat.cpp index 0052f72b055..1cc5e70282c 100644 --- a/gnu/llvm/lldb/source/Interpreter/OptionGroupFormat.cpp +++ b/gnu/llvm/lldb/source/Interpreter/OptionGroupFormat.cpp @@ -24,8 +24,6 @@ OptionGroupFormat::OptionGroupFormat(lldb::Format default_format, m_count(default_count, default_count), m_prev_gdb_format('x'), m_prev_gdb_size('w') {} -OptionGroupFormat::~OptionGroupFormat() {} - static constexpr OptionDefinition g_option_table[] = { {LLDB_OPT_SET_1, false, "format", 'f', OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeFormat, diff --git a/gnu/llvm/lldb/source/Interpreter/OptionGroupOutputFile.cpp b/gnu/llvm/lldb/source/Interpreter/OptionGroupOutputFile.cpp index 65105c3e018..6a626bd6301 100644 --- a/gnu/llvm/lldb/source/Interpreter/OptionGroupOutputFile.cpp +++ b/gnu/llvm/lldb/source/Interpreter/OptionGroupOutputFile.cpp @@ -13,10 +13,7 @@ using namespace lldb; using namespace lldb_private; -OptionGroupOutputFile::OptionGroupOutputFile() - : m_file(), m_append(false, false) {} - -OptionGroupOutputFile::~OptionGroupOutputFile() {} +OptionGroupOutputFile::OptionGroupOutputFile() : m_append(false, false) {} static const uint32_t SHORT_OPTION_APND = 0x61706e64; // 'apnd' diff --git a/gnu/llvm/lldb/source/Interpreter/OptionGroupPythonClassWithDict.cpp b/gnu/llvm/lldb/source/Interpreter/OptionGroupPythonClassWithDict.cpp index 217dab2ef63..a01c190266d 100644 --- a/gnu/llvm/lldb/source/Interpreter/OptionGroupPythonClassWithDict.cpp +++ b/gnu/llvm/lldb/source/Interpreter/OptionGroupPythonClassWithDict.cpp @@ -13,12 +13,10 @@ using namespace lldb; using namespace lldb_private; -OptionGroupPythonClassWithDict::OptionGroupPythonClassWithDict - (const char *class_use, - bool is_class, - int class_option, - int key_option, - int value_option) : OptionGroup(), m_is_class(is_class) { +OptionGroupPythonClassWithDict::OptionGroupPythonClassWithDict( + const char *class_use, bool is_class, int class_option, int key_option, + int value_option, uint16_t required_options) + : m_is_class(is_class), m_required_options(required_options) { m_key_usage_text.assign("The key for a key/value pair passed to the " "implementation of a "); m_key_usage_text.append(class_use); @@ -36,7 +34,7 @@ OptionGroupPythonClassWithDict::OptionGroupPythonClassWithDict m_class_usage_text.append("."); m_option_definition[0].usage_mask = LLDB_OPT_SET_1; - m_option_definition[0].required = true; + m_option_definition[0].required = m_required_options.Test(eScriptClass); m_option_definition[0].long_option = "script-class"; m_option_definition[0].short_option = class_option; m_option_definition[0].validator = nullptr; @@ -47,7 +45,7 @@ OptionGroupPythonClassWithDict::OptionGroupPythonClassWithDict m_option_definition[0].usage_text = m_class_usage_text.data(); m_option_definition[1].usage_mask = LLDB_OPT_SET_2; - m_option_definition[1].required = false; + m_option_definition[1].required = m_required_options.Test(eDictKey); m_option_definition[1].long_option = "structured-data-key"; m_option_definition[1].short_option = key_option; m_option_definition[1].validator = nullptr; @@ -58,7 +56,7 @@ OptionGroupPythonClassWithDict::OptionGroupPythonClassWithDict m_option_definition[1].usage_text = m_key_usage_text.data(); m_option_definition[2].usage_mask = LLDB_OPT_SET_2; - m_option_definition[2].required = false; + m_option_definition[2].required = m_required_options.Test(eDictValue); m_option_definition[2].long_option = "structured-data-value"; m_option_definition[2].short_option = value_option; m_option_definition[2].validator = nullptr; @@ -69,7 +67,7 @@ OptionGroupPythonClassWithDict::OptionGroupPythonClassWithDict m_option_definition[2].usage_text = m_value_usage_text.data(); m_option_definition[3].usage_mask = LLDB_OPT_SET_3; - m_option_definition[3].required = true; + m_option_definition[3].required = m_required_options.Test(ePythonFunction); m_option_definition[3].long_option = "python-function"; m_option_definition[3].short_option = class_option; m_option_definition[3].validator = nullptr; @@ -78,11 +76,8 @@ OptionGroupPythonClassWithDict::OptionGroupPythonClassWithDict m_option_definition[3].completion_type = 0; m_option_definition[3].argument_type = eArgTypePythonFunction; m_option_definition[3].usage_text = m_class_usage_text.data(); - } -OptionGroupPythonClassWithDict::~OptionGroupPythonClassWithDict() {} - Status OptionGroupPythonClassWithDict::SetOptionValue( uint32_t option_idx, llvm::StringRef option_arg, diff --git a/gnu/llvm/lldb/source/Interpreter/OptionGroupString.cpp b/gnu/llvm/lldb/source/Interpreter/OptionGroupString.cpp index c9f78eb953f..75faaac9f6d 100644 --- a/gnu/llvm/lldb/source/Interpreter/OptionGroupString.cpp +++ b/gnu/llvm/lldb/source/Interpreter/OptionGroupString.cpp @@ -32,8 +32,6 @@ OptionGroupString::OptionGroupString(uint32_t usage_mask, bool required, m_option_definition.usage_text = usage_text; } -OptionGroupString::~OptionGroupString() {} - Status OptionGroupString::SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, ExecutionContext *execution_context) { diff --git a/gnu/llvm/lldb/source/Interpreter/OptionGroupUInt64.cpp b/gnu/llvm/lldb/source/Interpreter/OptionGroupUInt64.cpp index 309855d4718..486941a7555 100644 --- a/gnu/llvm/lldb/source/Interpreter/OptionGroupUInt64.cpp +++ b/gnu/llvm/lldb/source/Interpreter/OptionGroupUInt64.cpp @@ -32,8 +32,6 @@ OptionGroupUInt64::OptionGroupUInt64(uint32_t usage_mask, bool required, m_option_definition.usage_text = usage_text; } -OptionGroupUInt64::~OptionGroupUInt64() {} - Status OptionGroupUInt64::SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, ExecutionContext *execution_context) { diff --git a/gnu/llvm/lldb/source/Interpreter/OptionGroupUUID.cpp b/gnu/llvm/lldb/source/Interpreter/OptionGroupUUID.cpp index 46f2ff75225..5b4c24a0a32 100644 --- a/gnu/llvm/lldb/source/Interpreter/OptionGroupUUID.cpp +++ b/gnu/llvm/lldb/source/Interpreter/OptionGroupUUID.cpp @@ -13,13 +13,9 @@ using namespace lldb; using namespace lldb_private; -OptionGroupUUID::OptionGroupUUID() : m_uuid() {} - -OptionGroupUUID::~OptionGroupUUID() {} - static constexpr OptionDefinition g_option_table[] = { {LLDB_OPT_SET_1, false, "uuid", 'u', OptionParser::eRequiredArgument, - nullptr, {}, 0, eArgTypeNone, "A module UUID value."}, + nullptr, {}, 0, eArgTypeModuleUUID, "A module UUID value."}, }; llvm::ArrayRef OptionGroupUUID::GetDefinitions() { diff --git a/gnu/llvm/lldb/source/Interpreter/OptionGroupValueObjectDisplay.cpp b/gnu/llvm/lldb/source/Interpreter/OptionGroupValueObjectDisplay.cpp index e0401f8987a..04861b53965 100644 --- a/gnu/llvm/lldb/source/Interpreter/OptionGroupValueObjectDisplay.cpp +++ b/gnu/llvm/lldb/source/Interpreter/OptionGroupValueObjectDisplay.cpp @@ -19,10 +19,6 @@ using namespace lldb; using namespace lldb_private; -OptionGroupValueObjectDisplay::OptionGroupValueObjectDisplay() {} - -OptionGroupValueObjectDisplay::~OptionGroupValueObjectDisplay() {} - static const OptionDefinition g_option_table[] = { {LLDB_OPT_SET_1, false, "dynamic-type", 'd', OptionParser::eRequiredArgument, nullptr, GetDynamicValueTypes(), 0, diff --git a/gnu/llvm/lldb/source/Interpreter/OptionGroupVariable.cpp b/gnu/llvm/lldb/source/Interpreter/OptionGroupVariable.cpp index 9f57dbbd073..20a521b8e44 100644 --- a/gnu/llvm/lldb/source/Interpreter/OptionGroupVariable.cpp +++ b/gnu/llvm/lldb/source/Interpreter/OptionGroupVariable.cpp @@ -67,10 +67,8 @@ static Status ValidateSummaryString(const char *str, void *) { } OptionGroupVariable::OptionGroupVariable(bool show_frame_options) - : OptionGroup(), include_frame_options(show_frame_options), - summary(ValidateNamedSummary), summary_string(ValidateSummaryString) {} - -OptionGroupVariable::~OptionGroupVariable() {} + : include_frame_options(show_frame_options), summary(ValidateNamedSummary), + summary_string(ValidateSummaryString) {} Status OptionGroupVariable::SetOptionValue(uint32_t option_idx, diff --git a/gnu/llvm/lldb/source/Interpreter/OptionGroupWatchpoint.cpp b/gnu/llvm/lldb/source/Interpreter/OptionGroupWatchpoint.cpp index 07013b5b78f..eb9842add28 100644 --- a/gnu/llvm/lldb/source/Interpreter/OptionGroupWatchpoint.cpp +++ b/gnu/llvm/lldb/source/Interpreter/OptionGroupWatchpoint.cpp @@ -74,10 +74,6 @@ bool OptionGroupWatchpoint::IsWatchSizeSupported(uint32_t watch_size) { return false; } -OptionGroupWatchpoint::OptionGroupWatchpoint() : OptionGroup() {} - -OptionGroupWatchpoint::~OptionGroupWatchpoint() {} - Status OptionGroupWatchpoint::SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, diff --git a/gnu/llvm/lldb/source/Interpreter/OptionValue.cpp b/gnu/llvm/lldb/source/Interpreter/OptionValue.cpp index 198be85a7b4..79bdf74b6fd 100644 --- a/gnu/llvm/lldb/source/Interpreter/OptionValue.cpp +++ b/gnu/llvm/lldb/source/Interpreter/OptionValue.cpp @@ -39,7 +39,7 @@ Status OptionValue::SetSubValue(const ExecutionContext *exe_ctx, VarSetOperationType op, llvm::StringRef name, llvm::StringRef value) { Status error; - error.SetErrorStringWithFormat("SetSubValue is not supported"); + error.SetErrorString("SetSubValue is not supported"); return error; } @@ -471,6 +471,8 @@ const char *OptionValue::GetBuiltinTypeAsCString(Type t) { return "dictionary"; case eTypeEnum: return "enum"; + case eTypeFileLineColumn: + return "file:line:column specifier"; case eTypeFileSpec: return "file"; case eTypeFileSpecList: @@ -541,8 +543,7 @@ lldb::OptionValueSP OptionValue::CreateValueFromCStringForTypeMask( } if (value_sp) - error = value_sp->SetValueFromString( - llvm::StringRef::withNullAsEmpty(value_cstr), eVarSetOperationAssign); + error = value_sp->SetValueFromString(value_cstr, eVarSetOperationAssign); else error.SetErrorString("unsupported type mask"); return value_sp; @@ -566,6 +567,12 @@ bool OptionValue::DumpQualifiedName(Stream &strm) const { return dumped_something; } +OptionValueSP OptionValue::DeepCopy(const OptionValueSP &new_parent) const { + auto clone = Clone(); + clone->SetParent(new_parent); + return clone; +} + void OptionValue::AutoComplete(CommandInterpreter &interpreter, CompletionRequest &request) {} diff --git a/gnu/llvm/lldb/source/Interpreter/OptionValueArch.cpp b/gnu/llvm/lldb/source/Interpreter/OptionValueArch.cpp index ac78ee64a9d..4d1e2c7869f 100644 --- a/gnu/llvm/lldb/source/Interpreter/OptionValueArch.cpp +++ b/gnu/llvm/lldb/source/Interpreter/OptionValueArch.cpp @@ -64,10 +64,6 @@ Status OptionValueArch::SetValueFromString(llvm::StringRef value, return error; } -lldb::OptionValueSP OptionValueArch::DeepCopy() const { - return OptionValueSP(new OptionValueArch(*this)); -} - void OptionValueArch::AutoComplete(CommandInterpreter &interpreter, CompletionRequest &request) { CommandCompletions::InvokeCommonCompletionCallbacks( diff --git a/gnu/llvm/lldb/source/Interpreter/OptionValueArgs.cpp b/gnu/llvm/lldb/source/Interpreter/OptionValueArgs.cpp index 9e7774a231c..bdb5f486835 100644 --- a/gnu/llvm/lldb/source/Interpreter/OptionValueArgs.cpp +++ b/gnu/llvm/lldb/source/Interpreter/OptionValueArgs.cpp @@ -13,9 +13,9 @@ using namespace lldb; using namespace lldb_private; -size_t OptionValueArgs::GetArgs(Args &args) { +size_t OptionValueArgs::GetArgs(Args &args) const { args.Clear(); - for (auto value : m_values) { + for (const auto &value : m_values) { llvm::StringRef string_value = value->GetStringValue(); if (!string_value.empty()) args.AppendArgument(string_value); diff --git a/gnu/llvm/lldb/source/Interpreter/OptionValueArray.cpp b/gnu/llvm/lldb/source/Interpreter/OptionValueArray.cpp index 9be11e32e2d..b1545bdebf1 100644 --- a/gnu/llvm/lldb/source/Interpreter/OptionValueArray.cpp +++ b/gnu/llvm/lldb/source/Interpreter/OptionValueArray.cpp @@ -52,6 +52,7 @@ void OptionValueArray::DumpValue(const ExecutionContext *exe_ctx, Stream &strm, case eTypeChar: case eTypeEnum: case eTypeFileSpec: + case eTypeFileLineColumn: case eTypeFormat: case eTypeSInt64: case eTypeString: @@ -302,15 +303,16 @@ Status OptionValueArray::SetArgs(const Args &args, VarSetOperationType op) { return error; } -lldb::OptionValueSP OptionValueArray::DeepCopy() const { - OptionValueArray *copied_array = - new OptionValueArray(m_type_mask, m_raw_value_dump); - lldb::OptionValueSP copied_value_sp(copied_array); - *static_cast(copied_array) = *this; - copied_array->m_callback = m_callback; - const uint32_t size = m_values.size(); - for (uint32_t i = 0; i < size; ++i) { - copied_array->AppendValue(m_values[i]->DeepCopy()); - } - return copied_value_sp; +OptionValueSP +OptionValueArray::DeepCopy(const OptionValueSP &new_parent) const { + auto copy_sp = OptionValue::DeepCopy(new_parent); + // copy_sp->GetAsArray cannot be used here as it doesn't work for derived + // types that override GetType returning a different value. + auto *array_value_ptr = static_cast(copy_sp.get()); + lldbassert(array_value_ptr); + + for (auto &value : array_value_ptr->m_values) + value = value->DeepCopy(copy_sp); + + return copy_sp; } diff --git a/gnu/llvm/lldb/source/Interpreter/OptionValueBoolean.cpp b/gnu/llvm/lldb/source/Interpreter/OptionValueBoolean.cpp index 24ae3f673bf..62845c14bd1 100644 --- a/gnu/llvm/lldb/source/Interpreter/OptionValueBoolean.cpp +++ b/gnu/llvm/lldb/source/Interpreter/OptionValueBoolean.cpp @@ -67,10 +67,6 @@ Status OptionValueBoolean::SetValueFromString(llvm::StringRef value_str, return error; } -lldb::OptionValueSP OptionValueBoolean::DeepCopy() const { - return OptionValueSP(new OptionValueBoolean(*this)); -} - void OptionValueBoolean::AutoComplete(CommandInterpreter &interpreter, CompletionRequest &request) { llvm::StringRef autocomplete_entries[] = {"true", "false", "on", "off", diff --git a/gnu/llvm/lldb/source/Interpreter/OptionValueChar.cpp b/gnu/llvm/lldb/source/Interpreter/OptionValueChar.cpp index af9a371f46d..7fe72c9aa22 100644 --- a/gnu/llvm/lldb/source/Interpreter/OptionValueChar.cpp +++ b/gnu/llvm/lldb/source/Interpreter/OptionValueChar.cpp @@ -57,7 +57,3 @@ Status OptionValueChar::SetValueFromString(llvm::StringRef value, } return error; } - -lldb::OptionValueSP OptionValueChar::DeepCopy() const { - return OptionValueSP(new OptionValueChar(*this)); -} diff --git a/gnu/llvm/lldb/source/Interpreter/OptionValueDictionary.cpp b/gnu/llvm/lldb/source/Interpreter/OptionValueDictionary.cpp index caadccd0423..26fed4a987e 100644 --- a/gnu/llvm/lldb/source/Interpreter/OptionValueDictionary.cpp +++ b/gnu/llvm/lldb/source/Interpreter/OptionValueDictionary.cpp @@ -62,6 +62,7 @@ void OptionValueDictionary::DumpValue(const ExecutionContext *exe_ctx, case eTypeBoolean: case eTypeChar: case eTypeEnum: + case eTypeFileLineColumn: case eTypeFileSpec: case eTypeFormat: case eTypeSInt64: @@ -310,15 +311,16 @@ bool OptionValueDictionary::DeleteValueForKey(ConstString key) { return false; } -lldb::OptionValueSP OptionValueDictionary::DeepCopy() const { - OptionValueDictionary *copied_dict = - new OptionValueDictionary(m_type_mask, m_raw_value_dump); - lldb::OptionValueSP copied_value_sp(copied_dict); - collection::const_iterator pos, end = m_values.end(); - for (pos = m_values.begin(); pos != end; ++pos) { - StreamString strm; - strm.Printf("%s=", pos->first.GetCString()); - copied_dict->SetValueForKey(pos->first, pos->second->DeepCopy(), true); - } - return copied_value_sp; +OptionValueSP +OptionValueDictionary::DeepCopy(const OptionValueSP &new_parent) const { + auto copy_sp = OptionValue::DeepCopy(new_parent); + // copy_sp->GetAsDictionary cannot be used here as it doesn't work for derived + // types that override GetType returning a different value. + auto *dict_value_ptr = static_cast(copy_sp.get()); + lldbassert(dict_value_ptr); + + for (auto &value : dict_value_ptr->m_values) + value.second = value.second->DeepCopy(copy_sp); + + return copy_sp; } diff --git a/gnu/llvm/lldb/source/Interpreter/OptionValueEnumeration.cpp b/gnu/llvm/lldb/source/Interpreter/OptionValueEnumeration.cpp index 9a1e08d4fba..f75519c577c 100644 --- a/gnu/llvm/lldb/source/Interpreter/OptionValueEnumeration.cpp +++ b/gnu/llvm/lldb/source/Interpreter/OptionValueEnumeration.cpp @@ -15,13 +15,10 @@ using namespace lldb_private; OptionValueEnumeration::OptionValueEnumeration( const OptionEnumValues &enumerators, enum_type value) - : OptionValue(), m_current_value(value), m_default_value(value), - m_enumerations() { + : m_current_value(value), m_default_value(value) { SetEnumerations(enumerators); } -OptionValueEnumeration::~OptionValueEnumeration() {} - void OptionValueEnumeration::DumpValue(const ExecutionContext *exe_ctx, Stream &strm, uint32_t dump_mask) { if (dump_mask & eDumpOptionType) @@ -98,10 +95,6 @@ void OptionValueEnumeration::SetEnumerations( m_enumerations.Sort(); } -lldb::OptionValueSP OptionValueEnumeration::DeepCopy() const { - return OptionValueSP(new OptionValueEnumeration(*this)); -} - void OptionValueEnumeration::AutoComplete(CommandInterpreter &interpreter, CompletionRequest &request) { const uint32_t num_enumerators = m_enumerations.GetSize(); diff --git a/gnu/llvm/lldb/source/Interpreter/OptionValueFileColonLine.cpp b/gnu/llvm/lldb/source/Interpreter/OptionValueFileColonLine.cpp new file mode 100644 index 00000000000..fb0b516c861 --- /dev/null +++ b/gnu/llvm/lldb/source/Interpreter/OptionValueFileColonLine.cpp @@ -0,0 +1,138 @@ +//===-- OptionValueFileColonLine.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 "lldb/Interpreter/OptionValueFileColonLine.h" + +#include "lldb/DataFormatters/FormatManager.h" +#include "lldb/Interpreter/CommandCompletions.h" +#include "lldb/Interpreter/CommandInterpreter.h" +#include "lldb/Utility/Args.h" +#include "lldb/Utility/State.h" + +using namespace lldb; +using namespace lldb_private; + +// This is an OptionValue for parsing file:line:column specifications. +// I set the completer to "source file" which isn't quite right, but we can +// only usefully complete in the file name part of it so it should be good +// enough. +OptionValueFileColonLine::OptionValueFileColonLine() = default; + +OptionValueFileColonLine::OptionValueFileColonLine(llvm::StringRef input) + : m_line_number(LLDB_INVALID_LINE_NUMBER), + m_column_number(LLDB_INVALID_COLUMN_NUMBER), + m_completion_mask(CommandCompletions::eSourceFileCompletion) { + SetValueFromString(input, eVarSetOperationAssign); +} + +void OptionValueFileColonLine::DumpValue(const ExecutionContext *exe_ctx, + Stream &strm, uint32_t dump_mask) { + if (dump_mask & eDumpOptionType) + strm.Printf("(%s)", GetTypeAsCString()); + if (dump_mask & eDumpOptionValue) { + if (dump_mask & eDumpOptionType) + strm.PutCString(" = "); + + if (m_file_spec) + strm << '"' << m_file_spec.GetPath().c_str() << '"'; + if (m_line_number != LLDB_INVALID_LINE_NUMBER) + strm.Printf(":%d", m_line_number); + if (m_column_number != LLDB_INVALID_COLUMN_NUMBER) + strm.Printf(":%d", m_column_number); + } +} + +Status OptionValueFileColonLine::SetValueFromString(llvm::StringRef value, + VarSetOperationType op) { + Status error; + switch (op) { + case eVarSetOperationClear: + Clear(); + NotifyValueChanged(); + break; + + case eVarSetOperationReplace: + case eVarSetOperationAssign: + if (value.size() > 0) { + // This is in the form filename:linenumber:column. + // I wish we could use filename:linenumber.column, that would make the + // parsing unambiguous and so much easier... + // But clang & gcc both print the output with two : so we're stuck with + // the two colons. Practically, the only actual ambiguity this introduces + // is with files like "foo:10", which doesn't seem terribly likely. + + // Providing the column is optional, so the input value might have one or + // two colons. First pick off the last colon separated piece. + // It has to be there, since the line number is required: + llvm::StringRef last_piece; + llvm::StringRef left_of_last_piece; + + std::tie(left_of_last_piece, last_piece) = value.rsplit(':'); + if (last_piece.empty()) { + error.SetErrorStringWithFormat("Line specifier must include file and " + "line: '%s'", + value.str().c_str()); + return error; + } + + // Now see if there's another colon and if so pull out the middle piece: + // Then check whether the middle piece is an integer. If it is, then it + // was the line number, and if it isn't we're going to assume that there + // was a colon in the filename (see note at the beginning of the function) + // and ignore it. + llvm::StringRef file_name; + llvm::StringRef middle_piece; + + std::tie(file_name, middle_piece) = left_of_last_piece.rsplit(':'); + if (middle_piece.empty() || + !llvm::to_integer(middle_piece, m_line_number)) { + // The middle piece was empty or not an integer, so there were only two + // legit pieces; our original division was right. Reassign the file + // name and pull out the line number: + file_name = left_of_last_piece; + if (!llvm::to_integer(last_piece, m_line_number)) { + error.SetErrorStringWithFormat("Bad line number value '%s' in: '%s'", + last_piece.str().c_str(), + value.str().c_str()); + return error; + } + } else { + // There were three pieces, and we've got the line number. So now + // we just need to check the column number which was the last peice. + if (!llvm::to_integer(last_piece, m_column_number)) { + error.SetErrorStringWithFormat("Bad column value '%s' in: '%s'", + last_piece.str().c_str(), + value.str().c_str()); + return error; + } + } + + m_value_was_set = true; + m_file_spec.SetFile(file_name, FileSpec::Style::native); + NotifyValueChanged(); + } else { + error.SetErrorString("invalid value string"); + } + break; + + case eVarSetOperationInsertBefore: + case eVarSetOperationInsertAfter: + case eVarSetOperationRemove: + case eVarSetOperationAppend: + case eVarSetOperationInvalid: + error = OptionValue::SetValueFromString(value, op); + break; + } + return error; +} + +void OptionValueFileColonLine::AutoComplete(CommandInterpreter &interpreter, + CompletionRequest &request) { + CommandCompletions::InvokeCommonCompletionCallbacks( + interpreter, m_completion_mask, request, nullptr); +} diff --git a/gnu/llvm/lldb/source/Interpreter/OptionValueFileSpec.cpp b/gnu/llvm/lldb/source/Interpreter/OptionValueFileSpec.cpp index 15acb7e5e5b..3987a36b1b6 100644 --- a/gnu/llvm/lldb/source/Interpreter/OptionValueFileSpec.cpp +++ b/gnu/llvm/lldb/source/Interpreter/OptionValueFileSpec.cpp @@ -18,23 +18,17 @@ using namespace lldb; using namespace lldb_private; -OptionValueFileSpec::OptionValueFileSpec(bool resolve) - : OptionValue(), m_current_value(), m_default_value(), m_data_sp(), - m_data_mod_time(), - m_completion_mask(CommandCompletions::eDiskFileCompletion), - m_resolve(resolve) {} +OptionValueFileSpec::OptionValueFileSpec(bool resolve) : m_resolve(resolve) {} OptionValueFileSpec::OptionValueFileSpec(const FileSpec &value, bool resolve) - : OptionValue(), m_current_value(value), m_default_value(value), - m_data_sp(), m_data_mod_time(), + : m_current_value(value), m_default_value(value), m_completion_mask(CommandCompletions::eDiskFileCompletion), m_resolve(resolve) {} OptionValueFileSpec::OptionValueFileSpec(const FileSpec ¤t_value, const FileSpec &default_value, bool resolve) - : OptionValue(), m_current_value(current_value), - m_default_value(default_value), m_data_sp(), m_data_mod_time(), + : m_current_value(current_value), m_default_value(default_value), m_completion_mask(CommandCompletions::eDiskFileCompletion), m_resolve(resolve) {} @@ -64,13 +58,6 @@ Status OptionValueFileSpec::SetValueFromString(llvm::StringRef value, case eVarSetOperationReplace: case eVarSetOperationAssign: if (value.size() > 0) { - // The setting value may have whitespace, double-quotes, or single-quotes - // around the file path to indicate that internal spaces are not word - // breaks. Strip off any ws & quotes from the start and end of the file - // path - we aren't doing any word // breaking here so the quoting is - // unnecessary. NB this will cause a problem if someone tries to specify - // a file path that legitimately begins or ends with a " or ' character, - // or whitespace. value = value.trim("\"' \t"); m_value_was_set = true; m_current_value.SetFile(value.str(), FileSpec::Style::native); @@ -95,10 +82,6 @@ Status OptionValueFileSpec::SetValueFromString(llvm::StringRef value, return error; } -lldb::OptionValueSP OptionValueFileSpec::DeepCopy() const { - return OptionValueSP(new OptionValueFileSpec(*this)); -} - void OptionValueFileSpec::AutoComplete(CommandInterpreter &interpreter, CompletionRequest &request) { CommandCompletions::InvokeCommonCompletionCallbacks( diff --git a/gnu/llvm/lldb/source/Interpreter/OptionValueFileSpecList.cpp b/gnu/llvm/lldb/source/Interpreter/OptionValueFileSpecList.cpp index f2367b1941c..2160fd61d42 100644 --- a/gnu/llvm/lldb/source/Interpreter/OptionValueFileSpecList.cpp +++ b/gnu/llvm/lldb/source/Interpreter/OptionValueFileSpecList.cpp @@ -164,7 +164,7 @@ Status OptionValueFileSpecList::SetValueFromString(llvm::StringRef value, return error; } -lldb::OptionValueSP OptionValueFileSpecList::DeepCopy() const { +OptionValueSP OptionValueFileSpecList::Clone() const { std::lock_guard lock(m_mutex); - return OptionValueSP(new OptionValueFileSpecList(m_current_value)); + return Cloneable::Clone(); } diff --git a/gnu/llvm/lldb/source/Interpreter/OptionValueFormat.cpp b/gnu/llvm/lldb/source/Interpreter/OptionValueFormat.cpp index b676bed50e6..76a446d1c3b 100644 --- a/gnu/llvm/lldb/source/Interpreter/OptionValueFormat.cpp +++ b/gnu/llvm/lldb/source/Interpreter/OptionValueFormat.cpp @@ -56,7 +56,3 @@ Status OptionValueFormat::SetValueFromString(llvm::StringRef value, } return error; } - -lldb::OptionValueSP OptionValueFormat::DeepCopy() const { - return OptionValueSP(new OptionValueFormat(*this)); -} diff --git a/gnu/llvm/lldb/source/Interpreter/OptionValueFormatEntity.cpp b/gnu/llvm/lldb/source/Interpreter/OptionValueFormatEntity.cpp index 6b36bd57518..64fcaf2cbc8 100644 --- a/gnu/llvm/lldb/source/Interpreter/OptionValueFormatEntity.cpp +++ b/gnu/llvm/lldb/source/Interpreter/OptionValueFormatEntity.cpp @@ -15,9 +15,7 @@ using namespace lldb; using namespace lldb_private; -OptionValueFormatEntity::OptionValueFormatEntity(const char *default_format) - : OptionValue(), m_current_format(), m_default_format(), m_current_entry(), - m_default_entry() { +OptionValueFormatEntity::OptionValueFormatEntity(const char *default_format) { if (default_format && default_format[0]) { llvm::StringRef default_format_str(default_format); Status error = FormatEntity::Parse(default_format_str, m_default_entry); @@ -29,11 +27,10 @@ OptionValueFormatEntity::OptionValueFormatEntity(const char *default_format) } } -bool OptionValueFormatEntity::Clear() { +void OptionValueFormatEntity::Clear() { m_current_entry = m_default_entry; m_current_format = m_default_format; m_value_was_set = false; - return true; } static void EscapeBackticks(llvm::StringRef str, std::string &dst) { @@ -85,7 +82,7 @@ Status OptionValueFormatEntity::SetValueFromString(llvm::StringRef value_str, if (first_char == '"' || first_char == '\'') { const size_t trimmed_len = trimmed_value_str.size(); if (trimmed_len == 1 || value_str[trimmed_len - 1] != first_char) { - error.SetErrorStringWithFormat("mismatched quotes"); + error.SetErrorString("mismatched quotes"); return error; } value_str = trimmed_value_str.substr(1, trimmed_len - 2); @@ -112,10 +109,6 @@ Status OptionValueFormatEntity::SetValueFromString(llvm::StringRef value_str, return error; } -lldb::OptionValueSP OptionValueFormatEntity::DeepCopy() const { - return OptionValueSP(new OptionValueFormatEntity(*this)); -} - void OptionValueFormatEntity::AutoComplete(CommandInterpreter &interpreter, CompletionRequest &request) { FormatEntity::AutoComplete(request); diff --git a/gnu/llvm/lldb/source/Interpreter/OptionValueLanguage.cpp b/gnu/llvm/lldb/source/Interpreter/OptionValueLanguage.cpp index 5b310782a1b..d2fbe248300 100644 --- a/gnu/llvm/lldb/source/Interpreter/OptionValueLanguage.cpp +++ b/gnu/llvm/lldb/source/Interpreter/OptionValueLanguage.cpp @@ -69,7 +69,3 @@ Status OptionValueLanguage::SetValueFromString(llvm::StringRef value, } return error; } - -lldb::OptionValueSP OptionValueLanguage::DeepCopy() const { - return OptionValueSP(new OptionValueLanguage(*this)); -} diff --git a/gnu/llvm/lldb/source/Interpreter/OptionValuePathMappings.cpp b/gnu/llvm/lldb/source/Interpreter/OptionValuePathMappings.cpp index 3b3f43d0729..4dceb563271 100644 --- a/gnu/llvm/lldb/source/Interpreter/OptionValuePathMappings.cpp +++ b/gnu/llvm/lldb/source/Interpreter/OptionValuePathMappings.cpp @@ -196,7 +196,3 @@ Status OptionValuePathMappings::SetValueFromString(llvm::StringRef value, } return error; } - -lldb::OptionValueSP OptionValuePathMappings::DeepCopy() const { - return OptionValueSP(new OptionValuePathMappings(*this)); -} diff --git a/gnu/llvm/lldb/source/Interpreter/OptionValueProperties.cpp b/gnu/llvm/lldb/source/Interpreter/OptionValueProperties.cpp index 24cda056977..ae073798ca1 100644 --- a/gnu/llvm/lldb/source/Interpreter/OptionValueProperties.cpp +++ b/gnu/llvm/lldb/source/Interpreter/OptionValueProperties.cpp @@ -20,29 +20,7 @@ using namespace lldb; using namespace lldb_private; -OptionValueProperties::OptionValueProperties(ConstString name) - : OptionValue(), m_name(name), m_properties(), m_name_to_index() {} - -OptionValueProperties::OptionValueProperties( - const OptionValueProperties &global_properties) - : OptionValue(global_properties), - std::enable_shared_from_this(), - m_name(global_properties.m_name), - m_properties(global_properties.m_properties), - m_name_to_index(global_properties.m_name_to_index) { - // We now have an exact copy of "global_properties". We need to now find all - // non-global settings and copy the property values so that all non-global - // settings get new OptionValue instances created for them. - const size_t num_properties = m_properties.size(); - for (size_t i = 0; i < num_properties; ++i) { - // Duplicate any values that are not global when constructing properties - // from a global copy - if (!m_properties[i].IsGlobal()) { - lldb::OptionValueSP new_value_sp(m_properties[i].GetValue()->DeepCopy()); - m_properties[i].SetOptionValue(new_value_sp); - } - } -} +OptionValueProperties::OptionValueProperties(ConstString name) : m_name(name) {} size_t OptionValueProperties::GetNumProperties() const { return m_properties.size(); @@ -147,38 +125,6 @@ OptionValueProperties::GetSubValue(const ExecutionContext *exe_ctx, } return return_val_sp; } - case '{': - // Predicate matching for predicates like - // "{}" - // strings are parsed by the current OptionValueProperties subclass to mean - // whatever they want to. For instance a subclass of OptionValueProperties - // for a lldb_private::Target might implement: "target.run- - // args{arch==i386}" -- only set run args if the arch is i386 "target - // .run-args{path=/tmp/a/b/c/a.out}" -- only set run args if the path - // matches "target.run-args{basename==test&&arch==x86_64}" -- only set run - // args if executable basename is "test" and arch is "x86_64" - if (sub_name[1]) { - llvm::StringRef predicate_start = sub_name.drop_front(); - size_t pos = predicate_start.find('}'); - if (pos != llvm::StringRef::npos) { - auto predicate = predicate_start.take_front(pos); - auto rest = predicate_start.drop_front(pos); - if (PredicateMatches(exe_ctx, predicate)) { - if (!rest.empty()) { - // Still more subvalue string to evaluate - return value_sp->GetSubValue(exe_ctx, rest, - will_modify, error); - } else { - // We have a match! - break; - } - } - } - } - // Predicate didn't match or wasn't correctly formed - value_sp.reset(); - break; - case '[': // Array or dictionary access for subvalues like: "[12]" -- access // 12th array element "['hello']" -- dictionary access of key named hello @@ -282,38 +228,50 @@ OptionValueProperties::GetPropertyAtIndexAsOptionValueLanguage( bool OptionValueProperties::GetPropertyAtIndexAsArgs( const ExecutionContext *exe_ctx, uint32_t idx, Args &args) const { const Property *property = GetPropertyAtIndex(exe_ctx, false, idx); - if (property) { - OptionValue *value = property->GetValue().get(); - if (value) { - const OptionValueArray *array = value->GetAsArray(); - if (array) - return array->GetArgs(args); - else { - const OptionValueDictionary *dict = value->GetAsDictionary(); - if (dict) - return dict->GetArgs(args); - } - } - } + if (!property) + return false; + + OptionValue *value = property->GetValue().get(); + if (!value) + return false; + + const OptionValueArgs *arguments = value->GetAsArgs(); + if (arguments) + return arguments->GetArgs(args); + + const OptionValueArray *array = value->GetAsArray(); + if (array) + return array->GetArgs(args); + + const OptionValueDictionary *dict = value->GetAsDictionary(); + if (dict) + return dict->GetArgs(args); + return false; } bool OptionValueProperties::SetPropertyAtIndexFromArgs( const ExecutionContext *exe_ctx, uint32_t idx, const Args &args) { const Property *property = GetPropertyAtIndex(exe_ctx, true, idx); - if (property) { - OptionValue *value = property->GetValue().get(); - if (value) { - OptionValueArray *array = value->GetAsArray(); - if (array) - return array->SetArgs(args, eVarSetOperationAssign).Success(); - else { - OptionValueDictionary *dict = value->GetAsDictionary(); - if (dict) - return dict->SetArgs(args, eVarSetOperationAssign).Success(); - } - } - } + if (!property) + return false; + + OptionValue *value = property->GetValue().get(); + if (!value) + return false; + + OptionValueArgs *arguments = value->GetAsArgs(); + if (arguments) + return arguments->SetArgs(args, eVarSetOperationAssign).Success(); + + OptionValueArray *array = value->GetAsArray(); + if (array) + return array->SetArgs(args, eVarSetOperationAssign).Success(); + + OptionValueDictionary *dict = value->GetAsDictionary(); + if (dict) + return dict->SetArgs(args, eVarSetOperationAssign).Success(); + return false; } @@ -517,11 +475,10 @@ bool OptionValueProperties::SetPropertyAtIndexAsUInt64( return false; } -bool OptionValueProperties::Clear() { +void OptionValueProperties::Clear() { const size_t num_properties = m_properties.size(); for (size_t i = 0; i < num_properties; ++i) m_properties[i].GetValue()->Clear(); - return true; } Status OptionValueProperties::SetValueFromString(llvm::StringRef value, @@ -585,8 +542,32 @@ Status OptionValueProperties::DumpPropertyValue(const ExecutionContext *exe_ctx, return error; } -lldb::OptionValueSP OptionValueProperties::DeepCopy() const { - llvm_unreachable("this shouldn't happen"); +OptionValuePropertiesSP +OptionValueProperties::CreateLocalCopy(const Properties &global_properties) { + auto global_props_sp = global_properties.GetValueProperties(); + lldbassert(global_props_sp); + + auto copy_sp = global_props_sp->DeepCopy(global_props_sp->GetParent()); + return std::static_pointer_cast(copy_sp); +} + +OptionValueSP +OptionValueProperties::DeepCopy(const OptionValueSP &new_parent) const { + auto copy_sp = OptionValue::DeepCopy(new_parent); + // copy_sp->GetAsProperties cannot be used here as it doesn't work for derived + // types that override GetType returning a different value. + auto *props_value_ptr = static_cast(copy_sp.get()); + lldbassert(props_value_ptr); + + for (auto &property : props_value_ptr->m_properties) { + // Duplicate any values that are not global when constructing properties + // from a global copy. + if (!property.IsGlobal()) { + auto value_sp = property.GetValue()->DeepCopy(copy_sp); + property.SetOptionValue(value_sp); + } + } + return copy_sp; } const Property *OptionValueProperties::GetPropertyAtPath( @@ -649,11 +630,11 @@ void OptionValueProperties::Apropos( } else { bool match = false; llvm::StringRef name = property->GetName(); - if (name.contains_lower(keyword)) + if (name.contains_insensitive(keyword)) match = true; else { llvm::StringRef desc = property->GetDescription(); - if (desc.contains_lower(keyword)) + if (desc.contains_insensitive(keyword)) match = true; } if (match) { diff --git a/gnu/llvm/lldb/source/Interpreter/OptionValueRegex.cpp b/gnu/llvm/lldb/source/Interpreter/OptionValueRegex.cpp index bec3942d9cb..bbeca8da771 100644 --- a/gnu/llvm/lldb/source/Interpreter/OptionValueRegex.cpp +++ b/gnu/llvm/lldb/source/Interpreter/OptionValueRegex.cpp @@ -59,7 +59,3 @@ Status OptionValueRegex::SetValueFromString(llvm::StringRef value, } return error; } - -lldb::OptionValueSP OptionValueRegex::DeepCopy() const { - return OptionValueSP(new OptionValueRegex(m_regex.GetText().str().c_str())); -} diff --git a/gnu/llvm/lldb/source/Interpreter/OptionValueSInt64.cpp b/gnu/llvm/lldb/source/Interpreter/OptionValueSInt64.cpp index ada20b2139a..b875ba8e353 100644 --- a/gnu/llvm/lldb/source/Interpreter/OptionValueSInt64.cpp +++ b/gnu/llvm/lldb/source/Interpreter/OptionValueSInt64.cpp @@ -70,7 +70,3 @@ Status OptionValueSInt64::SetValueFromString(llvm::StringRef value_ref, } return error; } - -lldb::OptionValueSP OptionValueSInt64::DeepCopy() const { - return OptionValueSP(new OptionValueSInt64(*this)); -} diff --git a/gnu/llvm/lldb/source/Interpreter/OptionValueString.cpp b/gnu/llvm/lldb/source/Interpreter/OptionValueString.cpp index 22f5d08bf83..b4fec91bc33 100644 --- a/gnu/llvm/lldb/source/Interpreter/OptionValueString.cpp +++ b/gnu/llvm/lldb/source/Interpreter/OptionValueString.cpp @@ -117,10 +117,6 @@ Status OptionValueString::SetValueFromString(llvm::StringRef value, return error; } -lldb::OptionValueSP OptionValueString::DeepCopy() const { - return OptionValueSP(new OptionValueString(*this)); -} - Status OptionValueString::SetCurrentValue(llvm::StringRef value) { if (m_validator) { Status error(m_validator(value.str().c_str(), m_validator_baton)); diff --git a/gnu/llvm/lldb/source/Interpreter/OptionValueUInt64.cpp b/gnu/llvm/lldb/source/Interpreter/OptionValueUInt64.cpp index 98ef016e5f7..a2751a4d02e 100644 --- a/gnu/llvm/lldb/source/Interpreter/OptionValueUInt64.cpp +++ b/gnu/llvm/lldb/source/Interpreter/OptionValueUInt64.cpp @@ -68,7 +68,3 @@ Status OptionValueUInt64::SetValueFromString(llvm::StringRef value_ref, } return error; } - -lldb::OptionValueSP OptionValueUInt64::DeepCopy() const { - return OptionValueSP(new OptionValueUInt64(*this)); -} diff --git a/gnu/llvm/lldb/source/Interpreter/OptionValueUUID.cpp b/gnu/llvm/lldb/source/Interpreter/OptionValueUUID.cpp index 2bd74977355..283f9c1b67b 100644 --- a/gnu/llvm/lldb/source/Interpreter/OptionValueUUID.cpp +++ b/gnu/llvm/lldb/source/Interpreter/OptionValueUUID.cpp @@ -58,10 +58,6 @@ Status OptionValueUUID::SetValueFromString(llvm::StringRef value, return error; } -lldb::OptionValueSP OptionValueUUID::DeepCopy() const { - return OptionValueSP(new OptionValueUUID(*this)); -} - void OptionValueUUID::AutoComplete(CommandInterpreter &interpreter, CompletionRequest &request) { ExecutionContext exe_ctx(interpreter.GetExecutionContext()); diff --git a/gnu/llvm/lldb/source/Interpreter/Options.cpp b/gnu/llvm/lldb/source/Interpreter/Options.cpp index c14b6b6ce66..4aa298f0382 100644 --- a/gnu/llvm/lldb/source/Interpreter/Options.cpp +++ b/gnu/llvm/lldb/source/Interpreter/Options.cpp @@ -25,9 +25,9 @@ using namespace lldb; using namespace lldb_private; // Options -Options::Options() : m_getopt_table() { BuildValidOptionSets(); } +Options::Options() { BuildValidOptionSets(); } -Options::~Options() {} +Options::~Options() = default; void Options::NotifyOptionParsingStarting(ExecutionContext *execution_context) { m_seen_options.clear(); @@ -137,7 +137,6 @@ bool Options::VerifyOptions(CommandReturnObject &result) { result.SetStatus(eReturnStatusSuccessFinishNoResult); } else { result.AppendError("invalid combination of options for the given command"); - result.SetStatus(eReturnStatusFailed); } return options_are_valid; @@ -223,7 +222,7 @@ Option *Options::GetLongOptions() { std::map::const_iterator pos = option_seen.find(short_opt); StreamString strm; - if (isprint8(short_opt)) + if (defs[i].HasShortOption()) Host::SystemLog(Host::eSystemLogError, "option[%u] --%s has a short option -%c that " "conflicts with option[%u] --%s, short option won't " @@ -355,9 +354,7 @@ enum OptionDisplayType { static bool PrintOption(const OptionDefinition &opt_def, OptionDisplayType display_type, const char *header, const char *footer, bool show_optional, Stream &strm) { - const bool has_short_option = isprint8(opt_def.short_option) != 0; - - if (display_type == eDisplayShortOption && !has_short_option) + if (display_type == eDisplayShortOption && !opt_def.HasShortOption()) return false; if (header && header[0]) @@ -366,7 +363,7 @@ static bool PrintOption(const OptionDefinition &opt_def, if (show_optional && !opt_def.required) strm.PutChar('['); const bool show_short_option = - has_short_option && display_type != eDisplayLongOption; + opt_def.HasShortOption() && display_type != eDisplayLongOption; if (show_short_option) strm.Printf("-%c", opt_def.short_option); else @@ -445,7 +442,7 @@ void Options::GenerateOptionUsage(Stream &strm, CommandObject *cmd, std::set options; std::set::const_iterator options_pos, options_end; for (auto &def : opt_defs) { - if (def.usage_mask & opt_set_mask && isprint8(def.short_option)) { + if (def.usage_mask & opt_set_mask && def.HasShortOption()) { // Add current option to the end of out_stream. if (def.required && def.option_has_arg == OptionParser::eNoArgument) { @@ -470,7 +467,7 @@ void Options::GenerateOptionUsage(Stream &strm, CommandObject *cmd, options.clear(); for (auto &def : opt_defs) { - if (def.usage_mask & opt_set_mask && isprint8(def.short_option)) { + if (def.usage_mask & opt_set_mask && def.HasShortOption()) { // Add current option to the end of out_stream. if (!def.required && @@ -498,7 +495,7 @@ void Options::GenerateOptionUsage(Stream &strm, CommandObject *cmd, // First go through and print the required options (list them up front). for (auto &def : opt_defs) { - if (def.usage_mask & opt_set_mask && isprint8(def.short_option)) { + if (def.usage_mask & opt_set_mask && def.HasShortOption()) { if (def.required && def.option_has_arg != OptionParser::eNoArgument) PrintOption(def, eDisplayBestOption, " ", nullptr, true, strm); } @@ -579,7 +576,7 @@ void Options::GenerateOptionUsage(Stream &strm, CommandObject *cmd, arg_name_str.Printf("<%s>", CommandObject::GetArgumentName(arg_type)); strm.Indent(); - if (opt_defs[i].short_option && isprint8(opt_defs[i].short_option)) { + if (opt_defs[i].short_option && opt_defs[i].HasShortOption()) { PrintOption(opt_defs[i], eDisplayShortOption, nullptr, nullptr, false, strm); PrintOption(opt_defs[i], eDisplayLongOption, " ( ", " )", false, strm); @@ -1308,7 +1305,7 @@ llvm::Expected Options::Parse(const Args &args, &long_options_index); if (val == ':') { - error.SetErrorStringWithFormat("last option requires an argument"); + error.SetErrorString("last option requires an argument"); break; } @@ -1317,7 +1314,7 @@ llvm::Expected Options::Parse(const Args &args, // Did we get an error? if (val == '?') { - error.SetErrorStringWithFormat("unknown or ambiguous option"); + error.SetErrorString("unknown or ambiguous option"); break; } // The option auto-set itself diff --git a/gnu/llvm/lldb/source/Interpreter/Property.cpp b/gnu/llvm/lldb/source/Interpreter/Property.cpp index 92381124985..55400a2bc42 100644 --- a/gnu/llvm/lldb/source/Interpreter/Property.cpp +++ b/gnu/llvm/lldb/source/Interpreter/Property.cpp @@ -22,7 +22,7 @@ using namespace lldb_private; Property::Property(const PropertyDefinition &definition) : m_name(definition.name), m_description(definition.description), - m_value_sp(), m_is_global(definition.global) { + m_is_global(definition.global) { switch (definition.type) { case OptionValue::eTypeInvalid: case OptionValue::eTypeProperties: @@ -99,6 +99,12 @@ Property::Property(const PropertyDefinition &definition) } break; + case OptionValue::eTypeFileLineColumn: + // "definition.default_uint_value" is not used for a + // OptionValue::eTypeFileSpecList + m_value_sp = std::make_shared(); + break; + case OptionValue::eTypeFileSpec: { // "definition.default_uint_value" represents if the // "definition.default_cstr_value" should be resolved or not diff --git a/gnu/llvm/lldb/source/Interpreter/ScriptInterpreter.cpp b/gnu/llvm/lldb/source/Interpreter/ScriptInterpreter.cpp index 86620449f2f..f26474836a6 100644 --- a/gnu/llvm/lldb/source/Interpreter/ScriptInterpreter.cpp +++ b/gnu/llvm/lldb/source/Interpreter/ScriptInterpreter.cpp @@ -18,38 +18,39 @@ #if defined(_WIN32) #include "lldb/Host/windows/ConnectionGenericFileWindows.h" #endif +#include +#include #include -#include -#include #include using namespace lldb; using namespace lldb_private; -ScriptInterpreter::ScriptInterpreter(Debugger &debugger, - lldb::ScriptLanguage script_lang) - : m_debugger(debugger), m_script_lang(script_lang) {} - -ScriptInterpreter::~ScriptInterpreter() {} +ScriptInterpreter::ScriptInterpreter( + Debugger &debugger, lldb::ScriptLanguage script_lang, + lldb::ScriptedProcessInterfaceUP scripted_process_interface_up) + : m_debugger(debugger), m_script_lang(script_lang), + m_scripted_process_interface_up( + std::move(scripted_process_interface_up)) {} void ScriptInterpreter::CollectDataForBreakpointCommandCallback( - std::vector &bp_options_vec, + std::vector> &bp_options_vec, CommandReturnObject &result) { - result.SetStatus(eReturnStatusFailed); result.AppendError( "This script interpreter does not support breakpoint callbacks."); } void ScriptInterpreter::CollectDataForWatchpointCommandCallback( WatchpointOptions *bp_options, CommandReturnObject &result) { - result.SetStatus(eReturnStatusFailed); result.AppendError( "This script interpreter does not support watchpoint callbacks."); } -bool ScriptInterpreter::LoadScriptingModule( - const char *filename, bool init_session, lldb_private::Status &error, - StructuredData::ObjectSP *module_sp) { +bool ScriptInterpreter::LoadScriptingModule(const char *filename, + const LoadScriptOptions &options, + lldb_private::Status &error, + StructuredData::ObjectSP *module_sp, + FileSpec extra_search_dir) { error.SetErrorString( "This script interpreter does not support importing modules."); return false; @@ -69,22 +70,35 @@ std::string ScriptInterpreter::LanguageToString(lldb::ScriptLanguage language) { llvm_unreachable("Unhandled ScriptInterpreter!"); } +lldb::DataExtractorSP +ScriptInterpreter::GetDataExtractorFromSBData(const lldb::SBData &data) const { + return data.m_opaque_sp; +} + +Status +ScriptInterpreter::GetStatusFromSBError(const lldb::SBError &error) const { + if (error.m_opaque_up) + return *error.m_opaque_up.get(); + + return Status(); +} + lldb::ScriptLanguage ScriptInterpreter::StringToLanguage(const llvm::StringRef &language) { - if (language.equals_lower(LanguageToString(eScriptLanguageNone))) + if (language.equals_insensitive(LanguageToString(eScriptLanguageNone))) return eScriptLanguageNone; - if (language.equals_lower(LanguageToString(eScriptLanguagePython))) + if (language.equals_insensitive(LanguageToString(eScriptLanguagePython))) return eScriptLanguagePython; - if (language.equals_lower(LanguageToString(eScriptLanguageLua))) + if (language.equals_insensitive(LanguageToString(eScriptLanguageLua))) return eScriptLanguageLua; return eScriptLanguageUnknown; } Status ScriptInterpreter::SetBreakpointCommandCallback( - std::vector &bp_options_vec, + std::vector> &bp_options_vec, const char *callback_text) { Status return_error; - for (BreakpointOptions *bp_options : bp_options_vec) { + for (BreakpointOptions &bp_options : bp_options_vec) { return_error = SetBreakpointCommandCallback(bp_options, callback_text); if (return_error.Success()) break; @@ -93,10 +107,10 @@ Status ScriptInterpreter::SetBreakpointCommandCallback( } Status ScriptInterpreter::SetBreakpointCommandCallbackFunction( - std::vector &bp_options_vec, const char *function_name, - StructuredData::ObjectSP extra_args_sp) { + std::vector> &bp_options_vec, + const char *function_name, StructuredData::ObjectSP extra_args_sp) { Status error; - for (BreakpointOptions *bp_options : bp_options_vec) { + for (BreakpointOptions &bp_options : bp_options_vec) { error = SetBreakpointCommandCallbackFunction(bp_options, function_name, extra_args_sp); if (!error.Success()) diff --git a/gnu/llvm/lldb/source/Plugins/ABI/AArch64/ABIAArch64.cpp b/gnu/llvm/lldb/source/Plugins/ABI/AArch64/ABIAArch64.cpp index 5cf9fb4ad37..42d73ce39ed 100644 --- a/gnu/llvm/lldb/source/Plugins/ABI/AArch64/ABIAArch64.cpp +++ b/gnu/llvm/lldb/source/Plugins/ABI/AArch64/ABIAArch64.cpp @@ -11,6 +11,7 @@ #include "ABISysV_arm64.h" #include "Utility/ARM64_DWARF_Registers.h" #include "lldb/Core/PluginManager.h" +#include "lldb/Target/Process.h" LLDB_PLUGIN_DEFINE(ABIAArch64) @@ -24,6 +25,18 @@ void ABIAArch64::Terminate() { ABIMacOSX_arm64::Terminate(); } +lldb::addr_t ABIAArch64::FixCodeAddress(lldb::addr_t pc) { + if (lldb::ProcessSP process_sp = GetProcessSP()) + return FixAddress(pc, process_sp->GetCodeAddressMask()); + return pc; +} + +lldb::addr_t ABIAArch64::FixDataAddress(lldb::addr_t pc) { + if (lldb::ProcessSP process_sp = GetProcessSP()) + return FixAddress(pc, process_sp->GetDataAddressMask()); + return pc; +} + std::pair ABIAArch64::GetEHAndDWARFNums(llvm::StringRef name) { if (name == "pc") @@ -33,6 +46,12 @@ ABIAArch64::GetEHAndDWARFNums(llvm::StringRef name) { return MCBasedABI::GetEHAndDWARFNums(name); } +std::string ABIAArch64::GetMCName(std::string reg) { + MapRegisterName(reg, "v", "q"); + MapRegisterName(reg, "x29", "fp"); + MapRegisterName(reg, "x30", "lr"); + return reg; +} uint32_t ABIAArch64::GetGenericNum(llvm::StringRef name) { return llvm::StringSwitch(name) .Case("pc", LLDB_REGNUM_GENERIC_PC) diff --git a/gnu/llvm/lldb/source/Plugins/ABI/AArch64/ABIAArch64.h b/gnu/llvm/lldb/source/Plugins/ABI/AArch64/ABIAArch64.h index 981145e2017..41bbf5cfdeb 100644 --- a/gnu/llvm/lldb/source/Plugins/ABI/AArch64/ABIAArch64.h +++ b/gnu/llvm/lldb/source/Plugins/ABI/AArch64/ABIAArch64.h @@ -16,14 +16,18 @@ public: static void Initialize(); static void Terminate(); + virtual lldb::addr_t FixCodeAddress(lldb::addr_t pc) override; + virtual lldb::addr_t FixDataAddress(lldb::addr_t pc) override; + protected: + virtual lldb::addr_t FixAddress(lldb::addr_t pc, lldb::addr_t mask) { + return pc; + } + std::pair GetEHAndDWARFNums(llvm::StringRef name) override; - std::string GetMCName(std::string reg) override { - MapRegisterName(reg, "v", "q"); - return reg; - } + std::string GetMCName(std::string reg) override; uint32_t GetGenericNum(llvm::StringRef name) override; diff --git a/gnu/llvm/lldb/source/Plugins/ABI/AArch64/ABIMacOSX_arm64.cpp b/gnu/llvm/lldb/source/Plugins/ABI/AArch64/ABIMacOSX_arm64.cpp index 983da26a2a6..348a081cfe1 100644 --- a/gnu/llvm/lldb/source/Plugins/ABI/AArch64/ABIMacOSX_arm64.cpp +++ b/gnu/llvm/lldb/source/Plugins/ABI/AArch64/ABIMacOSX_arm64.cpp @@ -66,7 +66,7 @@ bool ABIMacOSX_arm64::PrepareTrivialCall( if (log) { StreamString s; - s.Printf("ABISysV_x86_64::PrepareTrivialCall (tid = 0x%" PRIx64 + s.Printf("ABIMacOSX_arm64::PrepareTrivialCall (tid = 0x%" PRIx64 ", sp = 0x%" PRIx64 ", func_addr = 0x%" PRIx64 ", return_addr = 0x%" PRIx64, thread.GetID(), (uint64_t)sp, (uint64_t)func_addr, @@ -86,7 +86,7 @@ bool ABIMacOSX_arm64::PrepareTrivialCall( eRegisterKindGeneric, LLDB_REGNUM_GENERIC_RA); // x0 - x7 contain first 8 simple args - if (args.size() > 8) // TODO handle more than 6 arguments + if (args.size() > 8) // TODO handle more than 8 arguments return false; for (size_t i = 0; i < args.size(); ++i) { @@ -384,6 +384,7 @@ bool ABIMacOSX_arm64::CreateDefaultUnwindPlan(UnwindPlan &unwind_plan) { row->GetCFAValue().SetIsRegisterPlusOffset(fp_reg_num, 2 * ptr_size); row->SetOffset(0); + row->SetUnspecifiedRegistersAreUndefined(true); row->SetRegisterLocationToAtCFAPlusOffset(fp_reg_num, ptr_size * -2, true); row->SetRegisterLocationToAtCFAPlusOffset(pc_reg_num, ptr_size * -1, true); @@ -492,7 +493,8 @@ static bool LoadValueFromConsecutiveGPRRegisters( uint32_t &NGRN, // NGRN (see ABI documentation) uint32_t &NSRN, // NSRN (see ABI documentation) DataExtractor &data) { - llvm::Optional byte_size = value_type.GetByteSize(nullptr); + llvm::Optional byte_size = + value_type.GetByteSize(exe_ctx.GetBestExecutionContextScope()); if (!byte_size || *byte_size == 0) return false; @@ -509,7 +511,8 @@ static bool LoadValueFromConsecutiveGPRRegisters( if (NSRN < 8 && (8 - NSRN) >= homogeneous_count) { if (!base_type) return false; - llvm::Optional base_byte_size = base_type.GetByteSize(nullptr); + llvm::Optional base_byte_size = + base_type.GetByteSize(exe_ctx.GetBestExecutionContextScope()); if (!base_byte_size) return false; uint32_t data_offset = 0; @@ -646,13 +649,13 @@ ValueObjectSP ABIMacOSX_arm64::GetReturnValueObjectImpl( return return_valobj_sp; llvm::Optional byte_size = - return_compiler_type.GetByteSize(nullptr); + return_compiler_type.GetByteSize(&thread); if (!byte_size) return return_valobj_sp; const uint32_t type_flags = return_compiler_type.GetTypeInfo(nullptr); if (type_flags & eTypeIsScalar || type_flags & eTypeIsPointer) { - value.SetValueType(Value::eValueTypeScalar); + value.SetValueType(Value::ValueType::Scalar); bool success = false; if (type_flags & eTypeIsInteger || type_flags & eTypeIsPointer) { @@ -812,6 +815,11 @@ ValueObjectSP ABIMacOSX_arm64::GetReturnValueObjectImpl( return return_valobj_sp; } +lldb::addr_t ABIMacOSX_arm64::FixAddress(addr_t pc, addr_t mask) { + lldb::addr_t pac_sign_extension = 0x0080000000000000ULL; + return (pc & pac_sign_extension) ? pc | mask : pc & (~mask); +} + void ABIMacOSX_arm64::Initialize() { PluginManager::RegisterPlugin(GetPluginNameStatic(), pluginDesc, CreateInstance); diff --git a/gnu/llvm/lldb/source/Plugins/ABI/AArch64/ABIMacOSX_arm64.h b/gnu/llvm/lldb/source/Plugins/ABI/AArch64/ABIMacOSX_arm64.h index fc8ccee92e7..dc3ab35115f 100644 --- a/gnu/llvm/lldb/source/Plugins/ABI/AArch64/ABIMacOSX_arm64.h +++ b/gnu/llvm/lldb/source/Plugins/ABI/AArch64/ABIMacOSX_arm64.h @@ -62,6 +62,8 @@ public: return true; } + lldb::addr_t FixAddress(lldb::addr_t pc, lldb::addr_t mask) override; + // Static Functions static void Initialize(); diff --git a/gnu/llvm/lldb/source/Plugins/ABI/AArch64/ABISysV_arm64.cpp b/gnu/llvm/lldb/source/Plugins/ABI/AArch64/ABISysV_arm64.cpp index 831c8aa0d76..16fb38e107c 100644 --- a/gnu/llvm/lldb/source/Plugins/ABI/AArch64/ABISysV_arm64.cpp +++ b/gnu/llvm/lldb/source/Plugins/ABI/AArch64/ABISysV_arm64.cpp @@ -356,6 +356,7 @@ bool ABISysV_arm64::CreateDefaultUnwindPlan(UnwindPlan &unwind_plan) { row->GetCFAValue().SetIsRegisterPlusOffset(fp_reg_num, 2 * ptr_size); row->SetOffset(0); + row->SetUnspecifiedRegistersAreUndefined(true); row->SetRegisterLocationToAtCFAPlusOffset(fp_reg_num, ptr_size * -2, true); row->SetRegisterLocationToAtCFAPlusOffset(pc_reg_num, ptr_size * -1, true); @@ -466,7 +467,8 @@ static bool LoadValueFromConsecutiveGPRRegisters( uint32_t &NGRN, // NGRN (see ABI documentation) uint32_t &NSRN, // NSRN (see ABI documentation) DataExtractor &data) { - llvm::Optional byte_size = value_type.GetByteSize(nullptr); + llvm::Optional byte_size = + value_type.GetByteSize(exe_ctx.GetBestExecutionContextScope()); if (byte_size || *byte_size == 0) return false; @@ -484,7 +486,8 @@ static bool LoadValueFromConsecutiveGPRRegisters( if (NSRN < 8 && (8 - NSRN) >= homogeneous_count) { if (!base_type) return false; - llvm::Optional base_byte_size = base_type.GetByteSize(nullptr); + llvm::Optional base_byte_size = + base_type.GetByteSize(exe_ctx.GetBestExecutionContextScope()); if (!base_byte_size) return false; uint32_t data_offset = 0; @@ -614,13 +617,13 @@ ValueObjectSP ABISysV_arm64::GetReturnValueObjectImpl( return return_valobj_sp; llvm::Optional byte_size = - return_compiler_type.GetByteSize(nullptr); + return_compiler_type.GetByteSize(&thread); if (!byte_size) return return_valobj_sp; const uint32_t type_flags = return_compiler_type.GetTypeInfo(nullptr); if (type_flags & eTypeIsScalar || type_flags & eTypeIsPointer) { - value.SetValueType(Value::eValueTypeScalar); + value.SetValueType(Value::ValueType::Scalar); bool success = false; if (type_flags & eTypeIsInteger || type_flags & eTypeIsPointer) { @@ -779,6 +782,61 @@ ValueObjectSP ABISysV_arm64::GetReturnValueObjectImpl( return return_valobj_sp; } +lldb::addr_t ABISysV_arm64::FixAddress(addr_t pc, addr_t mask) { + lldb::addr_t pac_sign_extension = 0x0080000000000000ULL; + return (pc & pac_sign_extension) ? pc | mask : pc & (~mask); +} + +// Reads code or data address mask for the current Linux process. +static lldb::addr_t ReadLinuxProcessAddressMask(lldb::ProcessSP process_sp, + llvm::StringRef reg_name) { + // Linux configures user-space virtual addresses with top byte ignored. + // We set default value of mask such that top byte is masked out. + uint64_t address_mask = ~((1ULL << 56) - 1); + // If Pointer Authentication feature is enabled then Linux exposes + // PAC data and code mask register. Try reading relevant register + // below and merge it with default address mask calculated above. + lldb::ThreadSP thread_sp = process_sp->GetThreadList().GetSelectedThread(); + if (thread_sp) { + lldb::RegisterContextSP reg_ctx_sp = thread_sp->GetRegisterContext(); + if (reg_ctx_sp) { + const RegisterInfo *reg_info = + reg_ctx_sp->GetRegisterInfoByName(reg_name, 0); + if (reg_info) { + lldb::addr_t mask_reg_val = reg_ctx_sp->ReadRegisterAsUnsigned( + reg_info->kinds[eRegisterKindLLDB], LLDB_INVALID_ADDRESS); + if (mask_reg_val != LLDB_INVALID_ADDRESS) + address_mask |= mask_reg_val; + } + } + } + return address_mask; +} + +lldb::addr_t ABISysV_arm64::FixCodeAddress(lldb::addr_t pc) { + if (lldb::ProcessSP process_sp = GetProcessSP()) { + if (process_sp->GetTarget().GetArchitecture().GetTriple().isOSLinux() && + !process_sp->GetCodeAddressMask()) + process_sp->SetCodeAddressMask( + ReadLinuxProcessAddressMask(process_sp, "code_mask")); + + return FixAddress(pc, process_sp->GetCodeAddressMask()); + } + return pc; +} + +lldb::addr_t ABISysV_arm64::FixDataAddress(lldb::addr_t pc) { + if (lldb::ProcessSP process_sp = GetProcessSP()) { + if (process_sp->GetTarget().GetArchitecture().GetTriple().isOSLinux() && + !process_sp->GetDataAddressMask()) + process_sp->SetDataAddressMask( + ReadLinuxProcessAddressMask(process_sp, "data_mask")); + + return FixAddress(pc, process_sp->GetDataAddressMask()); + } + return pc; +} + void ABISysV_arm64::Initialize() { PluginManager::RegisterPlugin(GetPluginNameStatic(), "SysV ABI for AArch64 targets", CreateInstance); diff --git a/gnu/llvm/lldb/source/Plugins/ABI/AArch64/ABISysV_arm64.h b/gnu/llvm/lldb/source/Plugins/ABI/AArch64/ABISysV_arm64.h index aeb74acc38b..3428a7ad941 100644 --- a/gnu/llvm/lldb/source/Plugins/ABI/AArch64/ABISysV_arm64.h +++ b/gnu/llvm/lldb/source/Plugins/ABI/AArch64/ABISysV_arm64.h @@ -67,6 +67,8 @@ public: bool GetPointerReturnRegister(const char *&name) override; + lldb::addr_t FixAddress(lldb::addr_t pc, lldb::addr_t mask) override; + // Static Functions static void Initialize(); @@ -83,6 +85,9 @@ public: uint32_t GetPluginVersion() override; + lldb::addr_t FixCodeAddress(lldb::addr_t pc) override; + lldb::addr_t FixDataAddress(lldb::addr_t pc) override; + protected: lldb::ValueObjectSP GetReturnValueObjectImpl(lldb_private::Thread &thread, diff --git a/gnu/llvm/lldb/source/Plugins/ABI/ARC/ABISysV_arc.cpp b/gnu/llvm/lldb/source/Plugins/ABI/ARC/ABISysV_arc.cpp index a212eef2ab8..60cdbc53411 100644 --- a/gnu/llvm/lldb/source/Plugins/ABI/ARC/ABISysV_arc.cpp +++ b/gnu/llvm/lldb/source/Plugins/ABI/ARC/ABISysV_arc.cpp @@ -272,7 +272,8 @@ bool ABISysV_arc::PrepareTrivialCall(Thread &thread, addr_t sp, addr_t pc, reg_value[byte_index++] = 0; } - RegisterValue reg_val_obj(reg_value, reg_size, eByteOrderLittle); + RegisterValue reg_val_obj(llvm::makeArrayRef(reg_value, reg_size), + eByteOrderLittle); if (!reg_ctx->WriteRegister( reg_ctx->GetRegisterInfo(eRegisterKindGeneric, reg_index), reg_val_obj)) @@ -458,14 +459,14 @@ ABISysV_arc::GetReturnValueObjectSimple(Thread &thread, const uint32_t type_flags = compiler_type.GetTypeInfo(); // Integer return type. if (type_flags & eTypeIsInteger) { - const size_t byte_size = compiler_type.GetByteSize(nullptr).getValueOr(0); + const size_t byte_size = compiler_type.GetByteSize(&thread).getValueOr(0); auto raw_value = ReadRawValue(reg_ctx, byte_size); const bool is_signed = (type_flags & eTypeIsSigned) != 0; if (!SetSizedInteger(value.GetScalar(), raw_value, byte_size, is_signed)) return ValueObjectSP(); - value.SetValueType(Value::eValueTypeScalar); + value.SetValueType(Value::ValueType::Scalar); } // Pointer return type. else if (type_flags & eTypeIsPointer) { @@ -473,7 +474,7 @@ ABISysV_arc::GetReturnValueObjectSimple(Thread &thread, LLDB_REGNUM_GENERIC_ARG1); value.GetScalar() = reg_ctx->ReadRegisterAsUnsigned(reg_info_r0, 0); - value.SetValueType(Value::eValueTypeScalar); + value.SetValueType(Value::ValueType::Scalar); } // Floating point return type. else if (type_flags & eTypeIsFloat) { @@ -482,7 +483,7 @@ ABISysV_arc::GetReturnValueObjectSimple(Thread &thread, if (compiler_type.IsFloatingPointType(float_count, is_complex) && 1 == float_count && !is_complex) { - const size_t byte_size = compiler_type.GetByteSize(nullptr).getValueOr(0); + const size_t byte_size = compiler_type.GetByteSize(&thread).getValueOr(0); auto raw_value = ReadRawValue(reg_ctx, byte_size); if (!SetSizedFloat(value.GetScalar(), raw_value, byte_size)) @@ -536,7 +537,7 @@ ValueObjectSP ABISysV_arc::GetReturnValueObjectImpl(Thread &thread, auto reg_info_r0 = reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1); value.GetScalar() = reg_ctx->ReadRegisterAsUnsigned(reg_info_r0, 0); - value.SetValueType(Value::eValueTypeScalar); + value.SetValueType(Value::ValueType::Scalar); } // Floating point return type. else if (retType.isFloatingPointTy()) { diff --git a/gnu/llvm/lldb/source/Plugins/ABI/ARM/ABIMacOSX_arm.cpp b/gnu/llvm/lldb/source/Plugins/ABI/ARM/ABIMacOSX_arm.cpp index ef500cb198a..e429f3ee0cc 100644 --- a/gnu/llvm/lldb/source/Plugins/ABI/ARM/ABIMacOSX_arm.cpp +++ b/gnu/llvm/lldb/source/Plugins/ABI/ARM/ABIMacOSX_arm.cpp @@ -34,7 +34,7 @@ using namespace lldb; using namespace lldb_private; -static RegisterInfo g_register_infos[] = { +static const RegisterInfo g_register_infos[] = { // NAME ALT SZ OFF ENCODING FORMAT EH_FRAME // DWARF GENERIC PROCESS PLUGIN // LLDB NATIVE @@ -1292,24 +1292,9 @@ static RegisterInfo g_register_infos[] = { static const uint32_t k_num_register_infos = llvm::array_lengthof(g_register_infos); -static bool g_register_info_names_constified = false; const lldb_private::RegisterInfo * ABIMacOSX_arm::GetRegisterInfoArray(uint32_t &count) { - // Make the C-string names and alt_names for the register infos into const - // C-string values by having the ConstString unique the names in the global - // constant C-string pool. - if (!g_register_info_names_constified) { - g_register_info_names_constified = true; - for (uint32_t i = 0; i < k_num_register_infos; ++i) { - if (g_register_infos[i].name) - g_register_infos[i].name = - ConstString(g_register_infos[i].name).GetCString(); - if (g_register_infos[i].alt_name) - g_register_infos[i].alt_name = - ConstString(g_register_infos[i].alt_name).GetCString(); - } - } count = k_num_register_infos; return g_register_infos; } @@ -1839,6 +1824,7 @@ bool ABIMacOSX_arm::CreateDefaultUnwindPlan(UnwindPlan &unwind_plan) { row->GetCFAValue().SetIsRegisterPlusOffset(fp_reg_num, 2 * ptr_size); row->SetOffset(0); + row->SetUnspecifiedRegistersAreUndefined(true); row->SetRegisterLocationToAtCFAPlusOffset(fp_reg_num, ptr_size * -2, true); row->SetRegisterLocationToAtCFAPlusOffset(pc_reg_num, ptr_size * -1, true); diff --git a/gnu/llvm/lldb/source/Plugins/ABI/ARM/ABISysV_arm.cpp b/gnu/llvm/lldb/source/Plugins/ABI/ARM/ABISysV_arm.cpp index 1a93bac564f..3e544e0483a 100644 --- a/gnu/llvm/lldb/source/Plugins/ABI/ARM/ABISysV_arm.cpp +++ b/gnu/llvm/lldb/source/Plugins/ABI/ARM/ABISysV_arm.cpp @@ -36,7 +36,7 @@ using namespace lldb_private; LLDB_PLUGIN_DEFINE(ABISysV_arm) -static RegisterInfo g_register_infos[] = { +static const RegisterInfo g_register_infos[] = { // NAME ALT SZ OFF ENCODING FORMAT EH_FRAME // DWARF GENERIC PROCESS PLUGIN // LLDB NATIVE VALUE REGS INVALIDATE REGS @@ -1295,24 +1295,9 @@ static RegisterInfo g_register_infos[] = { static const uint32_t k_num_register_infos = llvm::array_lengthof(g_register_infos); -static bool g_register_info_names_constified = false; const lldb_private::RegisterInfo * ABISysV_arm::GetRegisterInfoArray(uint32_t &count) { - // Make the C-string names and alt_names for the register infos into const - // C-string values by having the ConstString unique the names in the global - // constant C-string pool. - if (!g_register_info_names_constified) { - g_register_info_names_constified = true; - for (uint32_t i = 0; i < k_num_register_infos; ++i) { - if (g_register_infos[i].name) - g_register_infos[i].name = - ConstString(g_register_infos[i].name).GetCString(); - if (g_register_infos[i].alt_name) - g_register_infos[i].alt_name = - ConstString(g_register_infos[i].alt_name).GetCString(); - } - } count = k_num_register_infos; return g_register_infos; } @@ -1632,7 +1617,7 @@ ValueObjectSP ABISysV_arm::GetReturnValueObjectImpl( thread.GetRegisterContext()->ReadRegisterAsUnsigned(r0_reg_info, 0) & UINT32_MAX; value.GetScalar() = ptr; - } else if (compiler_type.IsVectorType(nullptr, nullptr)) { + } else if (compiler_type.IsVectorType()) { if (IsArmHardFloat(thread) && (*byte_size == 8 || *byte_size == 16)) { is_vfp_candidate = true; vfp_byte_size = 8; @@ -1718,8 +1703,8 @@ ValueObjectSP ABISysV_arm::GetReturnValueObjectImpl( if (homogeneous_count > 0 && homogeneous_count <= 4) { llvm::Optional base_byte_size = - base_type.GetByteSize(nullptr); - if (base_type.IsVectorType(nullptr, nullptr)) { + base_type.GetByteSize(&thread); + if (base_type.IsVectorType()) { if (base_byte_size && (*base_byte_size == 8 || *base_byte_size == 16)) { is_vfp_candidate = true; @@ -1747,7 +1732,7 @@ ValueObjectSP ABISysV_arm::GetReturnValueObjectImpl( if (base_type.IsFloatingPointType(float_count, is_complex)) { llvm::Optional base_byte_size = - base_type.GetByteSize(nullptr); + base_type.GetByteSize(&thread); if (float_count == 2 && is_complex) { if (index != 0 && base_byte_size && vfp_byte_size != *base_byte_size) @@ -1955,6 +1940,7 @@ bool ABISysV_arm::CreateDefaultUnwindPlan(UnwindPlan &unwind_plan) { row->GetCFAValue().SetIsRegisterPlusOffset(fp_reg_num, 2 * ptr_size); row->SetOffset(0); + row->SetUnspecifiedRegistersAreUndefined(true); row->SetRegisterLocationToAtCFAPlusOffset(fp_reg_num, ptr_size * -2, true); row->SetRegisterLocationToAtCFAPlusOffset(pc_reg_num, ptr_size * -1, true); diff --git a/gnu/llvm/lldb/source/Plugins/ABI/Hexagon/ABISysV_hexagon.cpp b/gnu/llvm/lldb/source/Plugins/ABI/Hexagon/ABISysV_hexagon.cpp index 32313d4cd81..6794f7d0721 100644 --- a/gnu/llvm/lldb/source/Plugins/ABI/Hexagon/ABISysV_hexagon.cpp +++ b/gnu/llvm/lldb/source/Plugins/ABI/Hexagon/ABISysV_hexagon.cpp @@ -34,7 +34,7 @@ using namespace lldb_private; LLDB_PLUGIN_DEFINE_ADV(ABISysV_hexagon, ABIHexagon) -static RegisterInfo g_register_infos[] = { +static const RegisterInfo g_register_infos[] = { // hexagon-core.xml {"r00", "", @@ -974,24 +974,9 @@ static RegisterInfo g_register_infos[] = { static const uint32_t k_num_register_infos = sizeof(g_register_infos) / sizeof(RegisterInfo); -static bool g_register_info_names_constified = false; const lldb_private::RegisterInfo * ABISysV_hexagon::GetRegisterInfoArray(uint32_t &count) { - // Make the C-string names and alt_names for the register infos into const - // C-string values by having the ConstString unique the names in the global - // constant C-string pool. - if (!g_register_info_names_constified) { - g_register_info_names_constified = true; - for (uint32_t i = 0; i < k_num_register_infos; ++i) { - if (g_register_infos[i].name) - g_register_infos[i].name = - ConstString(g_register_infos[i].name).GetCString(); - if (g_register_infos[i].alt_name) - g_register_infos[i].alt_name = - ConstString(g_register_infos[i].alt_name).GetCString(); - } - } count = k_num_register_infos; return g_register_infos; } @@ -1240,6 +1225,7 @@ bool ABISysV_hexagon::CreateDefaultUnwindPlan(UnwindPlan &unwind_plan) { UnwindPlan::RowSP row(new UnwindPlan::Row); + row->SetUnspecifiedRegistersAreUndefined(true); row->GetCFAValue().SetIsRegisterPlusOffset(LLDB_REGNUM_GENERIC_FP, 8); row->SetRegisterLocationToAtCFAPlusOffset(fp_reg_num, -8, true); diff --git a/gnu/llvm/lldb/source/Plugins/ABI/Mips/ABISysV_mips.cpp b/gnu/llvm/lldb/source/Plugins/ABI/Mips/ABISysV_mips.cpp index d66e0926ad9..538ec06c3b0 100644 --- a/gnu/llvm/lldb/source/Plugins/ABI/Mips/ABISysV_mips.cpp +++ b/gnu/llvm/lldb/source/Plugins/ABI/Mips/ABISysV_mips.cpp @@ -985,6 +985,7 @@ bool ABISysV_mips::CreateDefaultUnwindPlan(UnwindPlan &unwind_plan) { UnwindPlan::RowSP row(new UnwindPlan::Row); + row->SetUnspecifiedRegistersAreUndefined(true); row->GetCFAValue().SetIsRegisterPlusOffset(dwarf_r29, 0); row->SetRegisterLocationToRegister(dwarf_pc, dwarf_r31, true); diff --git a/gnu/llvm/lldb/source/Plugins/ABI/Mips/ABISysV_mips64.cpp b/gnu/llvm/lldb/source/Plugins/ABI/Mips/ABISysV_mips64.cpp index bb28a50e5f4..7220508c75f 100644 --- a/gnu/llvm/lldb/source/Plugins/ABI/Mips/ABISysV_mips64.cpp +++ b/gnu/llvm/lldb/source/Plugins/ABI/Mips/ABISysV_mips64.cpp @@ -753,7 +753,7 @@ ValueObjectSP ABISysV_mips64::GetReturnValueObjectImpl( const ArchSpec target_arch = target->GetArchitecture(); ByteOrder target_byte_order = target_arch.GetByteOrder(); llvm::Optional byte_size = - return_compiler_type.GetByteSize(nullptr); + return_compiler_type.GetByteSize(&thread); if (!byte_size) return return_valobj_sp; const uint32_t type_flags = return_compiler_type.GetTypeInfo(nullptr); @@ -764,7 +764,7 @@ ValueObjectSP ABISysV_mips64::GetReturnValueObjectImpl( const RegisterInfo *r3_info = reg_ctx->GetRegisterInfoByName("r3", 0); if (type_flags & eTypeIsScalar || type_flags & eTypeIsPointer) { - value.SetValueType(Value::eValueTypeScalar); + value.SetValueType(Value::ValueType::Scalar); bool success = false; if (type_flags & eTypeIsInteger || type_flags & eTypeIsPointer) { @@ -962,7 +962,7 @@ ValueObjectSP ABISysV_mips64::GetReturnValueObjectImpl( return_compiler_type.GetFieldAtIndex( idx, name, &field_bit_offset, nullptr, nullptr); llvm::Optional field_byte_width = - field_compiler_type.GetByteSize(nullptr); + field_compiler_type.GetByteSize(&thread); if (!field_byte_width) return return_valobj_sp; @@ -1034,7 +1034,7 @@ ValueObjectSP ABISysV_mips64::GetReturnValueObjectImpl( CompilerType field_compiler_type = return_compiler_type.GetFieldAtIndex( idx, name, &field_bit_offset, nullptr, nullptr); llvm::Optional field_byte_width = - field_compiler_type.GetByteSize(nullptr); + field_compiler_type.GetByteSize(&thread); // if we don't know the size of the field (e.g. invalid type), just // bail out @@ -1156,6 +1156,7 @@ bool ABISysV_mips64::CreateDefaultUnwindPlan(UnwindPlan &unwind_plan) { UnwindPlan::RowSP row(new UnwindPlan::Row); + row->SetUnspecifiedRegistersAreUndefined(true); row->GetCFAValue().SetIsRegisterPlusOffset(dwarf_r29, 0); row->SetRegisterLocationToRegister(dwarf_pc, dwarf_r31, true); diff --git a/gnu/llvm/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc.cpp b/gnu/llvm/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc.cpp index 6f5eded7b03..98a14b50cbf 100644 --- a/gnu/llvm/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc.cpp +++ b/gnu/llvm/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc.cpp @@ -520,14 +520,14 @@ ValueObjectSP ABISysV_ppc::GetReturnValueObjectSimple( const uint32_t type_flags = return_compiler_type.GetTypeInfo(); if (type_flags & eTypeIsScalar) { - value.SetValueType(Value::eValueTypeScalar); + value.SetValueType(Value::ValueType::Scalar); bool success = false; if (type_flags & eTypeIsInteger) { // Extract the register context so we can read arguments from registers llvm::Optional byte_size = - return_compiler_type.GetByteSize(nullptr); + return_compiler_type.GetByteSize(&thread); if (!byte_size) return return_valobj_sp; uint64_t raw_value = thread.GetRegisterContext()->ReadRegisterAsUnsigned( @@ -574,7 +574,7 @@ ValueObjectSP ABISysV_ppc::GetReturnValueObjectSimple( // Don't handle complex yet. } else { llvm::Optional byte_size = - return_compiler_type.GetByteSize(nullptr); + return_compiler_type.GetByteSize(&thread); if (byte_size && *byte_size <= sizeof(long double)) { const RegisterInfo *f1_info = reg_ctx->GetRegisterInfoByName("f1", 0); RegisterValue f1_value; @@ -603,12 +603,12 @@ ValueObjectSP ABISysV_ppc::GetReturnValueObjectSimple( reg_ctx->GetRegisterInfoByName("r3", 0)->kinds[eRegisterKindLLDB]; value.GetScalar() = (uint64_t)thread.GetRegisterContext()->ReadRegisterAsUnsigned(r3_id, 0); - value.SetValueType(Value::eValueTypeScalar); + value.SetValueType(Value::ValueType::Scalar); return_valobj_sp = ValueObjectConstResult::Create( thread.GetStackFrameAtIndex(0).get(), value, ConstString("")); } else if (type_flags & eTypeIsVector) { llvm::Optional byte_size = - return_compiler_type.GetByteSize(nullptr); + return_compiler_type.GetByteSize(&thread); if (byte_size && *byte_size > 0) { const RegisterInfo *altivec_reg = reg_ctx->GetRegisterInfoByName("v2", 0); if (altivec_reg) { @@ -683,8 +683,6 @@ ValueObjectSP ABISysV_ppc::GetReturnValueObjectImpl( r3_value.GetData(r3_data); rdx_value.GetData(rdx_data); - uint32_t fp_bytes = - 0; // Tracks how much of the xmm registers we've consumed so far uint32_t integer_bytes = 0; // Tracks how much of the r3/rds registers we've consumed so far @@ -751,7 +749,6 @@ ValueObjectSP ABISysV_ppc::GetReturnValueObjectImpl( break; } else if (*field_bit_width == 64) { copy_from_offset = 0; - fp_bytes += field_byte_width; } else if (*field_bit_width == 32) { // This one is kind of complicated. If we are in an "eightbyte" // with another float, we'll be stuffed into an xmm register with @@ -815,8 +812,6 @@ ValueObjectSP ABISysV_ppc::GetReturnValueObjectImpl( copy_from_offset = integer_bytes - 8; integer_bytes += field_byte_width; } - } else { - fp_bytes += field_byte_width; } } } @@ -900,6 +895,7 @@ bool ABISysV_ppc::CreateDefaultUnwindPlan(UnwindPlan &unwind_plan) { UnwindPlan::RowSP row(new UnwindPlan::Row); const int32_t ptr_size = 4; + row->SetUnspecifiedRegistersAreUndefined(true); row->GetCFAValue().SetIsRegisterDereferenced(sp_reg_num); row->SetRegisterLocationToAtCFAPlusOffset(pc_reg_num, ptr_size * 1, true); diff --git a/gnu/llvm/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc64.cpp b/gnu/llvm/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc64.cpp index 251ac972fd7..7cc9482e7c5 100644 --- a/gnu/llvm/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc64.cpp +++ b/gnu/llvm/lldb/source/Plugins/ABI/PowerPC/ABISysV_ppc64.cpp @@ -567,7 +567,7 @@ private: ReturnValueExtractor(Thread &thread, CompilerType &type, RegisterContext *reg_ctx, ProcessSP process_sp) : m_thread(thread), m_type(type), - m_byte_size(m_type.GetByteSize(nullptr).getValueOr(0)), + m_byte_size(m_type.GetByteSize(&thread).getValueOr(0)), m_data_up(new DataBufferHeap(m_byte_size, 0)), m_reg_ctx(reg_ctx), m_process_sp(process_sp), m_byte_order(process_sp->GetByteOrder()), m_addr_size( @@ -577,7 +577,7 @@ private: ValueSP NewScalarValue(CompilerType &type) { ValueSP value_sp(new Value); value_sp->SetCompilerType(type); - value_sp->SetValueType(Value::eValueTypeScalar); + value_sp->SetValueType(Value::ValueType::Scalar); return value_sp; } @@ -643,7 +643,7 @@ private: DataExtractor de(&raw_data, sizeof(raw_data), m_byte_order, m_addr_size); offset_t offset = 0; - llvm::Optional byte_size = type.GetByteSize(nullptr); + llvm::Optional byte_size = type.GetByteSize(m_process_sp.get()); if (!byte_size) return {}; switch (*byte_size) { @@ -777,7 +777,8 @@ private: CompilerType elem_type; if (m_type.IsHomogeneousAggregate(&elem_type)) { uint32_t type_flags = elem_type.GetTypeInfo(); - llvm::Optional elem_size = elem_type.GetByteSize(nullptr); + llvm::Optional elem_size = + elem_type.GetByteSize(m_process_sp.get()); if (!elem_size) return {}; if (type_flags & eTypeIsComplex || !(type_flags & eTypeIsFloat)) { @@ -1002,6 +1003,7 @@ bool ABISysV_ppc64::CreateDefaultUnwindPlan(UnwindPlan &unwind_plan) { UnwindPlan::RowSP row(new UnwindPlan::Row); const int32_t ptr_size = 8; + row->SetUnspecifiedRegistersAreUndefined(true); row->GetCFAValue().SetIsRegisterDereferenced(sp_reg_num); row->SetRegisterLocationToAtCFAPlusOffset(pc_reg_num, ptr_size * 2, true); diff --git a/gnu/llvm/lldb/source/Plugins/ABI/SystemZ/ABISysV_s390x.cpp b/gnu/llvm/lldb/source/Plugins/ABI/SystemZ/ABISysV_s390x.cpp index eced2adc759..88e85111d87 100644 --- a/gnu/llvm/lldb/source/Plugins/ABI/SystemZ/ABISysV_s390x.cpp +++ b/gnu/llvm/lldb/source/Plugins/ABI/SystemZ/ABISysV_s390x.cpp @@ -118,7 +118,7 @@ enum dwarf_regnums { nullptr, nullptr, nullptr, 0 \ } -static RegisterInfo g_register_infos[] = { +static const RegisterInfo g_register_infos[] = { DEFINE_REG(r0, 8, nullptr, LLDB_INVALID_REGNUM), DEFINE_REG(r1, 8, nullptr, LLDB_INVALID_REGNUM), DEFINE_REG(r2, 8, "arg1", LLDB_REGNUM_GENERIC_ARG1), @@ -173,24 +173,9 @@ static RegisterInfo g_register_infos[] = { static const uint32_t k_num_register_infos = llvm::array_lengthof(g_register_infos); -static bool g_register_info_names_constified = false; const lldb_private::RegisterInfo * ABISysV_s390x::GetRegisterInfoArray(uint32_t &count) { - // Make the C-string names and alt_names for the register infos into const - // C-string values by having the ConstString unique the names in the global - // constant C-string pool. - if (!g_register_info_names_constified) { - g_register_info_names_constified = true; - for (uint32_t i = 0; i < k_num_register_infos; ++i) { - if (g_register_infos[i].name) - g_register_infos[i].name = - ConstString(g_register_infos[i].name).GetCString(); - if (g_register_infos[i].alt_name) - g_register_infos[i].alt_name = - ConstString(g_register_infos[i].alt_name).GetCString(); - } - } count = k_num_register_infos; return g_register_infos; } @@ -502,13 +487,13 @@ ValueObjectSP ABISysV_s390x::GetReturnValueObjectSimple( const uint32_t type_flags = return_compiler_type.GetTypeInfo(); if (type_flags & eTypeIsScalar) { - value.SetValueType(Value::eValueTypeScalar); + value.SetValueType(Value::ValueType::Scalar); bool success = false; if (type_flags & eTypeIsInteger) { // Extract the register context so we can read arguments from registers. llvm::Optional byte_size = - return_compiler_type.GetByteSize(nullptr); + return_compiler_type.GetByteSize(&thread); if (!byte_size) return return_valobj_sp; uint64_t raw_value = thread.GetRegisterContext()->ReadRegisterAsUnsigned( @@ -555,7 +540,7 @@ ValueObjectSP ABISysV_s390x::GetReturnValueObjectSimple( // Don't handle complex yet. } else { llvm::Optional byte_size = - return_compiler_type.GetByteSize(nullptr); + return_compiler_type.GetByteSize(&thread); if (byte_size && *byte_size <= sizeof(long double)) { const RegisterInfo *f0_info = reg_ctx->GetRegisterInfoByName("f0", 0); RegisterValue f0_value; @@ -586,7 +571,7 @@ ValueObjectSP ABISysV_s390x::GetReturnValueObjectSimple( reg_ctx->GetRegisterInfoByName("r2", 0)->kinds[eRegisterKindLLDB]; value.GetScalar() = (uint64_t)thread.GetRegisterContext()->ReadRegisterAsUnsigned(r2_id, 0); - value.SetValueType(Value::eValueTypeScalar); + value.SetValueType(Value::ValueType::Scalar); return_valobj_sp = ValueObjectConstResult::Create( thread.GetStackFrameAtIndex(0).get(), value, ConstString("")); } diff --git a/gnu/llvm/lldb/source/Plugins/ABI/X86/ABIMacOSX_i386.cpp b/gnu/llvm/lldb/source/Plugins/ABI/X86/ABIMacOSX_i386.cpp index 89112deb2c4..461e4af599d 100644 --- a/gnu/llvm/lldb/source/Plugins/ABI/X86/ABIMacOSX_i386.cpp +++ b/gnu/llvm/lldb/source/Plugins/ABI/X86/ABIMacOSX_i386.cpp @@ -389,6 +389,7 @@ bool ABIMacOSX_i386::CreateDefaultUnwindPlan(UnwindPlan &unwind_plan) { row->GetCFAValue().SetIsRegisterPlusOffset(fp_reg_num, 2 * ptr_size); row->SetOffset(0); + row->SetUnspecifiedRegistersAreUndefined(true); row->SetRegisterLocationToAtCFAPlusOffset(fp_reg_num, ptr_size * -2, true); row->SetRegisterLocationToAtCFAPlusOffset(pc_reg_num, ptr_size * -1, true); diff --git a/gnu/llvm/lldb/source/Plugins/ABI/X86/ABISysV_i386.cpp b/gnu/llvm/lldb/source/Plugins/ABI/X86/ABISysV_i386.cpp index 2ac87d1512e..7d2f0a64d67 100644 --- a/gnu/llvm/lldb/source/Plugins/ABI/X86/ABISysV_i386.cpp +++ b/gnu/llvm/lldb/source/Plugins/ABI/X86/ABISysV_i386.cpp @@ -378,16 +378,16 @@ ValueObjectSP ABISysV_i386::GetReturnValueObjectSimple( uint32_t ptr = thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) & 0xffffffff; - value.SetValueType(Value::eValueTypeScalar); + value.SetValueType(Value::ValueType::Scalar); value.GetScalar() = ptr; return_valobj_sp = ValueObjectConstResult::Create( thread.GetStackFrameAtIndex(0).get(), value, ConstString("")); } else if ((type_flags & eTypeIsScalar) || (type_flags & eTypeIsEnumeration)) //'Integral' + 'Floating Point' { - value.SetValueType(Value::eValueTypeScalar); + value.SetValueType(Value::ValueType::Scalar); llvm::Optional byte_size = - return_compiler_type.GetByteSize(nullptr); + return_compiler_type.GetByteSize(&thread); if (!byte_size) return return_valobj_sp; bool success = false; @@ -453,7 +453,7 @@ ValueObjectSP ABISysV_i386::GetReturnValueObjectSimple( uint32_t enm = thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) & 0xffffffff; - value.SetValueType(Value::eValueTypeScalar); + value.SetValueType(Value::ValueType::Scalar); value.GetScalar() = enm; return_valobj_sp = ValueObjectConstResult::Create( thread.GetStackFrameAtIndex(0).get(), value, ConstString("")); @@ -512,7 +512,7 @@ ValueObjectSP ABISysV_i386::GetReturnValueObjectSimple( } else if (type_flags & eTypeIsVector) // 'Packed' { llvm::Optional byte_size = - return_compiler_type.GetByteSize(nullptr); + return_compiler_type.GetByteSize(&thread); if (byte_size && *byte_size > 0) { const RegisterInfo *vec_reg = reg_ctx->GetRegisterInfoByName("xmm0", 0); if (vec_reg == nullptr) @@ -652,6 +652,7 @@ bool ABISysV_i386::CreateDefaultUnwindPlan(UnwindPlan &unwind_plan) { row->GetCFAValue().SetIsRegisterPlusOffset(fp_reg_num, 2 * ptr_size); row->SetOffset(0); + row->SetUnspecifiedRegistersAreUndefined(true); row->SetRegisterLocationToAtCFAPlusOffset(fp_reg_num, ptr_size * -2, true); row->SetRegisterLocationToAtCFAPlusOffset(pc_reg_num, ptr_size * -1, true); diff --git a/gnu/llvm/lldb/source/Plugins/ABI/X86/ABISysV_x86_64.cpp b/gnu/llvm/lldb/source/Plugins/ABI/X86/ABISysV_x86_64.cpp index 7729e58f858..196b45b3b6d 100644 --- a/gnu/llvm/lldb/source/Plugins/ABI/X86/ABISysV_x86_64.cpp +++ b/gnu/llvm/lldb/source/Plugins/ABI/X86/ABISysV_x86_64.cpp @@ -399,14 +399,14 @@ ValueObjectSP ABISysV_x86_64::GetReturnValueObjectSimple( const uint32_t type_flags = return_compiler_type.GetTypeInfo(); if (type_flags & eTypeIsScalar) { - value.SetValueType(Value::eValueTypeScalar); + value.SetValueType(Value::ValueType::Scalar); bool success = false; if (type_flags & eTypeIsInteger) { // Extract the register context so we can read arguments from registers llvm::Optional byte_size = - return_compiler_type.GetByteSize(nullptr); + return_compiler_type.GetByteSize(&thread); if (!byte_size) return return_valobj_sp; uint64_t raw_value = thread.GetRegisterContext()->ReadRegisterAsUnsigned( @@ -453,7 +453,7 @@ ValueObjectSP ABISysV_x86_64::GetReturnValueObjectSimple( // Don't handle complex yet. } else { llvm::Optional byte_size = - return_compiler_type.GetByteSize(nullptr); + return_compiler_type.GetByteSize(&thread); if (byte_size && *byte_size <= sizeof(long double)) { const RegisterInfo *xmm0_info = reg_ctx->GetRegisterInfoByName("xmm0", 0); @@ -487,12 +487,12 @@ ValueObjectSP ABISysV_x86_64::GetReturnValueObjectSimple( value.GetScalar() = (uint64_t)thread.GetRegisterContext()->ReadRegisterAsUnsigned(rax_id, 0); - value.SetValueType(Value::eValueTypeScalar); + value.SetValueType(Value::ValueType::Scalar); return_valobj_sp = ValueObjectConstResult::Create( thread.GetStackFrameAtIndex(0).get(), value, ConstString("")); } else if (type_flags & eTypeIsVector) { llvm::Optional byte_size = - return_compiler_type.GetByteSize(nullptr); + return_compiler_type.GetByteSize(&thread); if (byte_size && *byte_size > 0) { const RegisterInfo *altivec_reg = reg_ctx->GetRegisterInfoByName("xmm0", 0); @@ -887,6 +887,7 @@ bool ABISysV_x86_64::CreateDefaultUnwindPlan(UnwindPlan &unwind_plan) { const int32_t ptr_size = 8; row->GetCFAValue().SetIsRegisterPlusOffset(dwarf_rbp, 2 * ptr_size); row->SetOffset(0); + row->SetUnspecifiedRegistersAreUndefined(true); row->SetRegisterLocationToAtCFAPlusOffset(fp_reg_num, ptr_size * -2, true); row->SetRegisterLocationToAtCFAPlusOffset(pc_reg_num, ptr_size * -1, true); diff --git a/gnu/llvm/lldb/source/Plugins/ABI/X86/ABIWindows_x86_64.cpp b/gnu/llvm/lldb/source/Plugins/ABI/X86/ABIWindows_x86_64.cpp index 63b670b0727..6c473c652c5 100644 --- a/gnu/llvm/lldb/source/Plugins/ABI/X86/ABIWindows_x86_64.cpp +++ b/gnu/llvm/lldb/source/Plugins/ABI/X86/ABIWindows_x86_64.cpp @@ -408,13 +408,13 @@ ValueObjectSP ABIWindows_x86_64::GetReturnValueObjectSimple( const uint32_t type_flags = return_compiler_type.GetTypeInfo(); if (type_flags & eTypeIsScalar) { - value.SetValueType(Value::eValueTypeScalar); + value.SetValueType(Value::ValueType::Scalar); bool success = false; if (type_flags & eTypeIsInteger) { // Extract the register context so we can read arguments from registers llvm::Optional byte_size = - return_compiler_type.GetByteSize(nullptr); + return_compiler_type.GetByteSize(&thread); if (!byte_size) return return_valobj_sp; uint64_t raw_value = thread.GetRegisterContext()->ReadRegisterAsUnsigned( @@ -461,7 +461,7 @@ ValueObjectSP ABIWindows_x86_64::GetReturnValueObjectSimple( // Don't handle complex yet. } else { llvm::Optional byte_size = - return_compiler_type.GetByteSize(nullptr); + return_compiler_type.GetByteSize(&thread); if (byte_size && *byte_size <= sizeof(long double)) { const RegisterInfo *xmm0_info = reg_ctx->GetRegisterInfoByName("xmm0", 0); @@ -494,12 +494,12 @@ ValueObjectSP ABIWindows_x86_64::GetReturnValueObjectSimple( value.GetScalar() = (uint64_t)thread.GetRegisterContext()->ReadRegisterAsUnsigned(rax_id, 0); - value.SetValueType(Value::eValueTypeScalar); + value.SetValueType(Value::ValueType::Scalar); return_valobj_sp = ValueObjectConstResult::Create( thread.GetStackFrameAtIndex(0).get(), value, ConstString("")); } else if (type_flags & eTypeIsVector) { llvm::Optional byte_size = - return_compiler_type.GetByteSize(nullptr); + return_compiler_type.GetByteSize(&thread); if (byte_size && *byte_size > 0) { const RegisterInfo *xmm_reg = reg_ctx->GetRegisterInfoByName("xmm0", 0); @@ -767,6 +767,7 @@ bool ABIWindows_x86_64::CreateDefaultUnwindPlan(UnwindPlan &unwind_plan) { const int32_t ptr_size = 8; row->GetCFAValue().SetIsRegisterPlusOffset(dwarf_rbp, 2 * ptr_size); row->SetOffset(0); + row->SetUnspecifiedRegistersAreUndefined(true); row->SetRegisterLocationToAtCFAPlusOffset(fp_reg_num, ptr_size * -2, true); row->SetRegisterLocationToAtCFAPlusOffset(pc_reg_num, ptr_size * -1, true); diff --git a/gnu/llvm/lldb/source/Plugins/Architecture/AArch64/ArchitectureAArch64.cpp b/gnu/llvm/lldb/source/Plugins/Architecture/AArch64/ArchitectureAArch64.cpp new file mode 100644 index 00000000000..9994cc293d6 --- /dev/null +++ b/gnu/llvm/lldb/source/Plugins/Architecture/AArch64/ArchitectureAArch64.cpp @@ -0,0 +1,45 @@ +//===-- ArchitectureAArch64.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 "Plugins/Architecture/AArch64/ArchitectureAArch64.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Utility/ArchSpec.h" + +using namespace lldb_private; +using namespace lldb; + +LLDB_PLUGIN_DEFINE(ArchitectureAArch64) + +ConstString ArchitectureAArch64::GetPluginNameStatic() { + return ConstString("aarch64"); +} + +void ArchitectureAArch64::Initialize() { + PluginManager::RegisterPlugin(GetPluginNameStatic(), + "AArch64-specific algorithms", + &ArchitectureAArch64::Create); +} + +void ArchitectureAArch64::Terminate() { + PluginManager::UnregisterPlugin(&ArchitectureAArch64::Create); +} + +std::unique_ptr +ArchitectureAArch64::Create(const ArchSpec &arch) { + auto machine = arch.GetMachine(); + if (machine != llvm::Triple::aarch64 && machine != llvm::Triple::aarch64_be && + machine != llvm::Triple::aarch64_32) { + return nullptr; + } + return std::unique_ptr(new ArchitectureAArch64()); +} + +ConstString ArchitectureAArch64::GetPluginName() { + return GetPluginNameStatic(); +} +uint32_t ArchitectureAArch64::GetPluginVersion() { return 1; } diff --git a/gnu/llvm/lldb/source/Plugins/Architecture/AArch64/ArchitectureAArch64.h b/gnu/llvm/lldb/source/Plugins/Architecture/AArch64/ArchitectureAArch64.h new file mode 100644 index 00000000000..775478cc933 --- /dev/null +++ b/gnu/llvm/lldb/source/Plugins/Architecture/AArch64/ArchitectureAArch64.h @@ -0,0 +1,40 @@ +//===-- ArchitectureAArch64.h -----------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SOURCE_PLUGINS_ARCHITECTURE_AARCH64_ARCHITECTUREAARCH64_H +#define LLDB_SOURCE_PLUGINS_ARCHITECTURE_AARCH64_ARCHITECTUREAARCH64_H + +#include "Plugins/Process/Utility/MemoryTagManagerAArch64MTE.h" +#include "lldb/Core/Architecture.h" + +namespace lldb_private { + +class ArchitectureAArch64 : public Architecture { +public: + static ConstString GetPluginNameStatic(); + static void Initialize(); + static void Terminate(); + + ConstString GetPluginName() override; + uint32_t GetPluginVersion() override; + + void OverrideStopInfo(Thread &thread) const override{}; + + const MemoryTagManager *GetMemoryTagManager() const override { + return &m_memory_tag_manager; + } + +private: + static std::unique_ptr Create(const ArchSpec &arch); + ArchitectureAArch64() = default; + MemoryTagManagerAArch64MTE m_memory_tag_manager; +}; + +} // namespace lldb_private + +#endif // LLDB_SOURCE_PLUGINS_ARCHITECTURE_AARCH64_ARCHITECTUREAARCH64_H diff --git a/gnu/llvm/lldb/source/Plugins/Architecture/AArch64/CMakeLists.txt b/gnu/llvm/lldb/source/Plugins/Architecture/AArch64/CMakeLists.txt new file mode 100644 index 00000000000..9bcf9931862 --- /dev/null +++ b/gnu/llvm/lldb/source/Plugins/Architecture/AArch64/CMakeLists.txt @@ -0,0 +1,11 @@ +add_lldb_library(lldbPluginArchitectureAArch64 PLUGIN + ArchitectureAArch64.cpp + + LINK_LIBS + lldbPluginProcessUtility + lldbCore + lldbTarget + lldbUtility + LINK_COMPONENTS + Support + ) diff --git a/gnu/llvm/lldb/source/Plugins/Architecture/CMakeLists.txt b/gnu/llvm/lldb/source/Plugins/Architecture/CMakeLists.txt index 14ad9164459..9ed8edf70af 100644 --- a/gnu/llvm/lldb/source/Plugins/Architecture/CMakeLists.txt +++ b/gnu/llvm/lldb/source/Plugins/Architecture/CMakeLists.txt @@ -1,3 +1,4 @@ add_subdirectory(Arm) add_subdirectory(Mips) add_subdirectory(PPC64) +add_subdirectory(AArch64) diff --git a/gnu/llvm/lldb/source/Plugins/Architecture/Mips/ArchitectureMips.cpp b/gnu/llvm/lldb/source/Plugins/Architecture/Mips/ArchitectureMips.cpp index 22508969cee..757c9157000 100644 --- a/gnu/llvm/lldb/source/Plugins/Architecture/Mips/ArchitectureMips.cpp +++ b/gnu/llvm/lldb/source/Plugins/Architecture/Mips/ArchitectureMips.cpp @@ -160,7 +160,6 @@ Instruction *ArchitectureMips::GetInstructionAtAddress( InstructionList instruction_list; InstructionSP prev_insn; - bool prefer_file_cache = true; // Read from file uint32_t inst_to_choose = 0; Address addr = resolved_addr; @@ -171,8 +170,7 @@ Instruction *ArchitectureMips::GetInstructionAtAddress( uint32_t insn_size = 0; disasm_sp->ParseInstructions(target, addr, - {Disassembler::Limit::Bytes, i * 2}, nullptr, - prefer_file_cache); + {Disassembler::Limit::Bytes, i * 2}, nullptr); uint32_t num_insns = disasm_sp->GetInstructionList().GetSize(); if (num_insns) { diff --git a/gnu/llvm/lldb/source/Plugins/CMakeLists.txt b/gnu/llvm/lldb/source/Plugins/CMakeLists.txt index d91ba749f86..9181a4e4767 100644 --- a/gnu/llvm/lldb/source/Plugins/CMakeLists.txt +++ b/gnu/llvm/lldb/source/Plugins/CMakeLists.txt @@ -19,6 +19,8 @@ add_subdirectory(StructuredData) add_subdirectory(SymbolFile) add_subdirectory(SystemRuntime) add_subdirectory(SymbolVendor) +add_subdirectory(Trace) +add_subdirectory(TraceExporter) add_subdirectory(TypeSystem) add_subdirectory(UnwindAssembly) diff --git a/gnu/llvm/lldb/source/Plugins/Disassembler/LLVMC/DisassemblerLLVMC.cpp b/gnu/llvm/lldb/source/Plugins/Disassembler/LLVMC/DisassemblerLLVMC.cpp index 6427d8d176c..7cd505d0ed2 100644 --- a/gnu/llvm/lldb/source/Plugins/Disassembler/LLVMC/DisassemblerLLVMC.cpp +++ b/gnu/llvm/lldb/source/Plugins/Disassembler/LLVMC/DisassemblerLLVMC.cpp @@ -905,7 +905,8 @@ DisassemblerLLVMC::MCDisasmInstance::Create(const char *triple, const char *cpu, return Instance(); std::unique_ptr context_up( - new llvm::MCContext(asm_info_up.get(), reg_info_up.get(), nullptr)); + new llvm::MCContext(llvm::Triple(triple), asm_info_up.get(), + reg_info_up.get(), subtarget_info_up.get())); if (!context_up) return Instance(); @@ -1056,7 +1057,7 @@ DisassemblerLLVMC::DisassemblerLLVMC(const ArchSpec &arch, thumb_arch_name.erase(0, 3); thumb_arch_name.insert(0, "thumb"); } else { - thumb_arch_name = "thumbv8.2a"; + thumb_arch_name = "thumbv8.7a"; } thumb_arch.GetTriple().setArchName(llvm::StringRef(thumb_arch_name)); } @@ -1068,7 +1069,7 @@ DisassemblerLLVMC::DisassemblerLLVMC(const ArchSpec &arch, // specified) if (triple.getArch() == llvm::Triple::arm && triple.getSubArch() == llvm::Triple::NoSubArch) - triple.setArchName("armv8.2a"); + triple.setArchName("armv8.7a"); std::string features_str = ""; const char *triple_str = triple.getTriple().c_str(); @@ -1137,16 +1138,13 @@ DisassemblerLLVMC::DisassemblerLLVMC(const ArchSpec &arch, features_str += "+dspr2,"; } - // If any AArch64 variant, enable the ARMv8.5 ISA with SVE extensions so we - // can disassemble newer instructions. - if (triple.getArch() == llvm::Triple::aarch64 || - triple.getArch() == llvm::Triple::aarch64_32) - features_str += "+v8.5a,+sve2"; + // If any AArch64 variant, enable latest ISA with any optional + // extensions like SVE. + if (triple.isAArch64()) { + features_str += "+v8.7a,+sve2,+mte"; - if ((triple.getArch() == llvm::Triple::aarch64 || - triple.getArch() == llvm::Triple::aarch64_32) - && triple.getVendor() == llvm::Triple::Apple) { - cpu = "apple-latest"; + if (triple.getVendor() == llvm::Triple::Apple) + cpu = "apple-latest"; } // We use m_disasm_up.get() to tell whether we are valid or not, so if this diff --git a/gnu/llvm/lldb/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp b/gnu/llvm/lldb/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp index 68a0335682d..07b3da01e14 100644 --- a/gnu/llvm/lldb/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp +++ b/gnu/llvm/lldb/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.cpp @@ -35,7 +35,7 @@ //#define ENABLE_DEBUG_PRINTF // COMMENT THIS LINE OUT PRIOR TO CHECKIN #ifdef ENABLE_DEBUG_PRINTF -#include +#include #define DEBUG_PRINTF(fmt, ...) printf(fmt, ##__VA_ARGS__) #else #define DEBUG_PRINTF(fmt, ...) @@ -107,7 +107,7 @@ public: m_collection_sp->Initialize(g_dynamicloaderdarwinkernel_properties); } - ~DynamicLoaderDarwinKernelProperties() override {} + ~DynamicLoaderDarwinKernelProperties() override = default; bool GetLoadKexts() const { const uint32_t idx = ePropertyLoadKexts; @@ -400,7 +400,7 @@ DynamicLoaderDarwinKernel::ReadMachHeader(addr_t addr, Process *process, llvm::M *read_error = false; // Read the mach header and see whether it looks like a kernel - if (process->DoReadMemory (addr, &header, sizeof(header), error) != + if (process->ReadMemory(addr, &header, sizeof(header), error) != sizeof(header)) { if (read_error) *read_error = true; @@ -517,12 +517,8 @@ DynamicLoaderDarwinKernel::DynamicLoaderDarwinKernel(Process *process, Status error; PlatformSP platform_sp( Platform::Create(PlatformDarwinKernel::GetPluginNameStatic(), error)); - // Only select the darwin-kernel Platform if we've been asked to load kexts. - // It can take some time to scan over all of the kext info.plists and that - // shouldn't be done if kext loading is explicitly disabled. - if (platform_sp.get() && GetGlobalProperties()->GetLoadKexts()) { + if (platform_sp.get()) process->GetTarget().SetPlatform(platform_sp); - } } // Destructor @@ -794,7 +790,7 @@ bool DynamicLoaderDarwinKernel::KextImageInfo::LoadImageUsingMemoryModule( // For the kernel, we really do need an on-disk file copy of the binary // to do anything useful. This will force a call to dsymForUUID if it - // exists, instead of depending on the DebugSymbols preferences being + // exists, instead of depending on the DebugSymbols preferences being // set. if (IsKernel()) { if (Symbols::DownloadObjectAndSymbolFile(module_spec, true)) { @@ -1097,16 +1093,16 @@ bool DynamicLoaderDarwinKernel::ReadKextSummaryHeader() { uint8_t buf[24]; DataExtractor data(buf, sizeof(buf), byte_order, addr_size); const size_t count = 4 * sizeof(uint32_t) + addr_size; - const bool prefer_file_cache = false; + const bool force_live_memory = true; if (m_process->GetTarget().ReadPointerFromMemory( - m_kext_summary_header_ptr_addr, prefer_file_cache, error, - m_kext_summary_header_addr)) { + m_kext_summary_header_ptr_addr, error, + m_kext_summary_header_addr, force_live_memory)) { // We got a valid address for our kext summary header and make sure it // isn't NULL if (m_kext_summary_header_addr.IsValid() && m_kext_summary_header_addr.GetFileAddress() != 0) { const size_t bytes_read = m_process->GetTarget().ReadMemory( - m_kext_summary_header_addr, prefer_file_cache, buf, count, error); + m_kext_summary_header_addr, buf, count, error, force_live_memory); if (bytes_read == count) { lldb::offset_t offset = 0; m_kext_summary_header.version = data.GetU32(&offset); @@ -1377,10 +1373,9 @@ uint32_t DynamicLoaderDarwinKernel::ReadKextSummaries( DataBufferHeap data(count, 0); Status error; - const bool prefer_file_cache = false; + const bool force_live_memory = true; const size_t bytes_read = m_process->GetTarget().ReadMemory( - kext_summary_addr, prefer_file_cache, data.GetBytes(), data.GetByteSize(), - error); + kext_summary_addr, data.GetBytes(), data.GetByteSize(), error, force_live_memory); if (bytes_read == count) { DataExtractor extractor(data.GetBytes(), data.GetByteSize(), endian, diff --git a/gnu/llvm/lldb/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.h b/gnu/llvm/lldb/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.h index 8659cd575bc..225d06992ac 100644 --- a/gnu/llvm/lldb/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.h +++ b/gnu/llvm/lldb/source/Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.h @@ -125,11 +125,7 @@ protected: class KextImageInfo { public: - KextImageInfo() - : m_name(), m_module_sp(), m_memory_module_sp(), - m_load_process_stop_id(UINT32_MAX), m_uuid(), - m_load_address(LLDB_INVALID_ADDRESS), m_size(0), - m_kernel_image(false) {} + KextImageInfo() : m_name(), m_module_sp(), m_memory_module_sp(), m_uuid() {} void Clear() { m_load_address = LLDB_INVALID_ADDRESS; @@ -201,24 +197,24 @@ protected: std::string m_name; lldb::ModuleSP m_module_sp; lldb::ModuleSP m_memory_module_sp; - uint32_t m_load_process_stop_id; // the stop-id when this module was added - // to the Target + uint32_t m_load_process_stop_id = + UINT32_MAX; // the stop-id when this module was added + // to the Target lldb_private::UUID m_uuid; // UUID for this dylib if it has one, else all zeros - lldb::addr_t m_load_address; - uint64_t m_size; - bool m_kernel_image; // true if this is the kernel, false if this is a kext + lldb::addr_t m_load_address = LLDB_INVALID_ADDRESS; + uint64_t m_size = 0; + bool m_kernel_image = + false; // true if this is the kernel, false if this is a kext }; struct OSKextLoadedKextSummaryHeader { - uint32_t version; - uint32_t entry_size; - uint32_t entry_count; - lldb::addr_t image_infos_addr; - - OSKextLoadedKextSummaryHeader() - : version(0), entry_size(0), entry_count(0), - image_infos_addr(LLDB_INVALID_ADDRESS) {} + uint32_t version = 0; + uint32_t entry_size = 0; + uint32_t entry_count = 0; + lldb::addr_t image_infos_addr = LLDB_INVALID_ADDRESS; + + OSKextLoadedKextSummaryHeader() = default; uint32_t GetSize() { switch (version) { diff --git a/gnu/llvm/lldb/source/Plugins/DynamicLoader/Hexagon-DYLD/DynamicLoaderHexagonDYLD.h b/gnu/llvm/lldb/source/Plugins/DynamicLoader/Hexagon-DYLD/DynamicLoaderHexagonDYLD.h index 2d39ce06a8d..2570e003fd6 100644 --- a/gnu/llvm/lldb/source/Plugins/DynamicLoader/Hexagon-DYLD/DynamicLoaderHexagonDYLD.h +++ b/gnu/llvm/lldb/source/Plugins/DynamicLoader/Hexagon-DYLD/DynamicLoaderHexagonDYLD.h @@ -131,10 +131,6 @@ protected: private: const lldb_private::SectionList * GetSectionListFromModule(const lldb::ModuleSP module) const; - - DynamicLoaderHexagonDYLD(const DynamicLoaderHexagonDYLD &) = delete; - const DynamicLoaderHexagonDYLD & - operator=(const DynamicLoaderHexagonDYLD &) = delete; }; #endif // LLDB_SOURCE_PLUGINS_DYNAMICLOADER_HEXAGON_DYLD_DYNAMICLOADERHEXAGONDYLD_H diff --git a/gnu/llvm/lldb/source/Plugins/DynamicLoader/Hexagon-DYLD/HexagonDYLDRendezvous.cpp b/gnu/llvm/lldb/source/Plugins/DynamicLoader/Hexagon-DYLD/HexagonDYLDRendezvous.cpp index af76056af68..5e2a866adb2 100644 --- a/gnu/llvm/lldb/source/Plugins/DynamicLoader/Hexagon-DYLD/HexagonDYLDRendezvous.cpp +++ b/gnu/llvm/lldb/source/Plugins/DynamicLoader/Hexagon-DYLD/HexagonDYLDRendezvous.cpp @@ -246,7 +246,7 @@ std::string HexagonDYLDRendezvous::ReadStringFromMemory(addr_t addr) { return std::string(); for (;;) { - size = m_process->DoReadMemory(addr, &c, 1, error); + size = m_process->ReadMemory(addr, &c, 1, error); if (size != 1 || error.Fail()) return std::string(); if (c == 0) diff --git a/gnu/llvm/lldb/source/Plugins/DynamicLoader/Hexagon-DYLD/HexagonDYLDRendezvous.h b/gnu/llvm/lldb/source/Plugins/DynamicLoader/Hexagon-DYLD/HexagonDYLDRendezvous.h index 5707f8858f6..c34e02ed567 100644 --- a/gnu/llvm/lldb/source/Plugins/DynamicLoader/Hexagon-DYLD/HexagonDYLDRendezvous.h +++ b/gnu/llvm/lldb/source/Plugins/DynamicLoader/Hexagon-DYLD/HexagonDYLDRendezvous.h @@ -35,15 +35,13 @@ class HexagonDYLDRendezvous { // the layout of this struct is not binary compatible, it is simply large // enough to hold the information on both 32 and 64 bit platforms. struct Rendezvous { - uint64_t version; - lldb::addr_t map_addr; - lldb::addr_t brk; - uint64_t state; - lldb::addr_t ldbase; - - Rendezvous() - : version(0), map_addr(LLDB_INVALID_ADDRESS), brk(LLDB_INVALID_ADDRESS), - state(0), ldbase(0) {} + uint64_t version = 0; + lldb::addr_t map_addr = LLDB_INVALID_ADDRESS; + lldb::addr_t brk = LLDB_INVALID_ADDRESS; + uint64_t state = 0; + lldb::addr_t ldbase = 0; + + Rendezvous() = default; }; public: diff --git a/gnu/llvm/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp b/gnu/llvm/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp index 7b0d6f343c0..95bd3988aaf 100644 --- a/gnu/llvm/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp +++ b/gnu/llvm/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp @@ -16,6 +16,7 @@ #include "lldb/Core/Section.h" #include "lldb/Expression/DiagnosticManager.h" #include "lldb/Host/FileSystem.h" +#include "lldb/Host/HostInfo.h" #include "lldb/Symbol/Function.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Target/ABI.h" @@ -35,7 +36,7 @@ //#define ENABLE_DEBUG_PRINTF // COMMENT THIS LINE OUT PRIOR TO CHECKIN #ifdef ENABLE_DEBUG_PRINTF -#include +#include #define DEBUG_PRINTF(fmt, ...) printf(fmt, ##__VA_ARGS__) #else #define DEBUG_PRINTF(fmt, ...) @@ -59,7 +60,7 @@ DynamicLoaderDarwin::DynamicLoaderDarwin(Process *process) m_dyld_image_infos_stop_id(UINT32_MAX), m_dyld(), m_mutex() {} // Destructor -DynamicLoaderDarwin::~DynamicLoaderDarwin() {} +DynamicLoaderDarwin::~DynamicLoaderDarwin() = default; /// Called after attaching a process. /// @@ -123,19 +124,39 @@ ModuleSP DynamicLoaderDarwin::FindTargetModuleForImageInfo( module_sp.reset(); } - if (!module_sp) { - if (can_create) { - // We'll call Target::ModulesDidLoad after all the modules have been - // added to the target, don't let it be called for every one. - module_sp = target.GetOrCreateModule(module_spec, false /* notify */); - if (!module_sp || module_sp->GetObjectFile() == nullptr) - module_sp = m_process->ReadModuleFromMemory(image_info.file_spec, - image_info.address); - - if (did_create_ptr) - *did_create_ptr = (bool)module_sp; + if (module_sp || !can_create) + return module_sp; + + if (HostInfo::GetArchitecture().IsCompatibleMatch(target.GetArchitecture())) { + // When debugging on the host, we are most likely using the same shared + // cache as our inferior. The dylibs from the shared cache might not + // exist on the filesystem, so let's use the images in our own memory + // to create the modules. + // Check if the requested image is in our shared cache. + SharedCacheImageInfo image_info = + HostInfo::GetSharedCacheImageInfo(module_spec.GetFileSpec().GetPath()); + + // If we found it and it has the correct UUID, let's proceed with + // creating a module from the memory contents. + if (image_info.uuid && + (!module_spec.GetUUID() || module_spec.GetUUID() == image_info.uuid)) { + ModuleSpec shared_cache_spec(module_spec.GetFileSpec(), image_info.uuid, + image_info.data_sp); + module_sp = + target.GetOrCreateModule(shared_cache_spec, false /* notify */); } } + // We'll call Target::ModulesDidLoad after all the modules have been + // added to the target, don't let it be called for every one. + if (!module_sp) + module_sp = target.GetOrCreateModule(module_spec, false /* notify */); + if (!module_sp || module_sp->GetObjectFile() == nullptr) + module_sp = m_process->ReadModuleFromMemory(image_info.file_spec, + image_info.address); + + if (did_create_ptr) + *did_create_ptr = (bool)module_sp; + return module_sp; } @@ -195,15 +216,11 @@ void DynamicLoaderDarwin::UnloadAllImages() { const ModuleList &target_modules = target.GetImages(); std::lock_guard guard(target_modules.GetMutex()); - size_t num_modules = target_modules.GetSize(); ModuleSP dyld_sp(GetDYLDModule()); - - for (size_t i = 0; i < num_modules; i++) { - ModuleSP module_sp = target_modules.GetModuleAtIndexUnlocked(i); - + for (ModuleSP module_sp : target_modules.Modules()) { // Don't remove dyld - else we'll lose our breakpoint notifying us about // libraries being re-loaded... - if (module_sp.get() != nullptr && module_sp.get() != dyld_sp.get()) { + if (module_sp && module_sp != dyld_sp) { UnloadSections(module_sp); unloaded_modules_list.Append(module_sp); } @@ -556,7 +573,8 @@ void DynamicLoaderDarwin::UpdateSpecialBinariesFromNewImageInfos( } } - if (exe_idx != UINT32_MAX) { + // Set the target executable if we haven't found one so far. + if (exe_idx != UINT32_MAX && !target.GetExecutableModule()) { const bool can_create = true; ModuleSP exe_module_sp(FindTargetModuleForImageInfo(image_infos[exe_idx], can_create, nullptr)); @@ -1068,7 +1086,7 @@ DynamicLoaderDarwin::GetThreadLocalData(const lldb::ModuleSP module_sp, Status error; const size_t tsl_data_size = addr_size * 3; Target &target = m_process->GetTarget(); - if (target.ReadMemory(tls_addr, false, buf, tsl_data_size, error) == + if (target.ReadMemory(tls_addr, buf, tsl_data_size, error, true) == tsl_data_size) { const ByteOrder byte_order = m_process->GetByteOrder(); DataExtractor data(buf, sizeof(buf), byte_order, addr_size); @@ -1091,7 +1109,7 @@ DynamicLoaderDarwin::GetThreadLocalData(const lldb::ModuleSP module_sp, StackFrameSP frame_sp = thread_sp->GetStackFrameAtIndex(0); if (frame_sp) { TypeSystemClang *clang_ast_context = - TypeSystemClang::GetScratch(target); + ScratchTypeSystemClang::GetForTarget(target); if (!clang_ast_context) return LLDB_INVALID_ADDRESS; diff --git a/gnu/llvm/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.h b/gnu/llvm/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.h index 4c9a27f0853..1b705e94446 100644 --- a/gnu/llvm/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.h +++ b/gnu/llvm/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.h @@ -73,19 +73,17 @@ protected: class Segment { public: - Segment() - : name(), vmaddr(LLDB_INVALID_ADDRESS), vmsize(0), fileoff(0), - filesize(0), maxprot(0), initprot(0), nsects(0), flags(0) {} + Segment() : name() {} lldb_private::ConstString name; - lldb::addr_t vmaddr; - lldb::addr_t vmsize; - lldb::addr_t fileoff; - lldb::addr_t filesize; - uint32_t maxprot; - uint32_t initprot; - uint32_t nsects; - uint32_t flags; + lldb::addr_t vmaddr = LLDB_INVALID_ADDRESS; + lldb::addr_t vmsize = 0; + lldb::addr_t fileoff = 0; + lldb::addr_t filesize = 0; + uint32_t maxprot = 0; + uint32_t initprot = 0; + uint32_t nsects = 0; + uint32_t flags = 0; bool operator==(const Segment &rhs) const { return name == rhs.name && vmaddr == rhs.vmaddr && vmsize == rhs.vmsize; diff --git a/gnu/llvm/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOS.cpp b/gnu/llvm/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOS.cpp index 7bc14061ffe..cad8a43d925 100644 --- a/gnu/llvm/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOS.cpp +++ b/gnu/llvm/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOS.cpp @@ -224,7 +224,7 @@ bool DynamicLoaderMacOS::NotifyBreakpointHit(void *baton, // get the values from the ABI: TypeSystemClang *clang_ast_context = - TypeSystemClang::GetScratch(process->GetTarget()); + ScratchTypeSystemClang::GetForTarget(process->GetTarget()); if (!clang_ast_context) return false; @@ -244,18 +244,18 @@ bool DynamicLoaderMacOS::NotifyBreakpointHit(void *baton, clang_ast_context->GetBuiltinTypeForEncodingAndBitSize( lldb::eEncodingUint, 32); - mode_value.SetValueType(Value::eValueTypeScalar); + mode_value.SetValueType(Value::ValueType::Scalar); mode_value.SetCompilerType(clang_uint32_type); if (process->GetTarget().GetArchitecture().GetAddressByteSize() == 4) { - count_value.SetValueType(Value::eValueTypeScalar); + count_value.SetValueType(Value::ValueType::Scalar); count_value.SetCompilerType(clang_uint32_type); } else { - count_value.SetValueType(Value::eValueTypeScalar); + count_value.SetValueType(Value::ValueType::Scalar); count_value.SetCompilerType(clang_uint64_type); } - headers_value.SetValueType(Value::eValueTypeScalar); + headers_value.SetValueType(Value::ValueType::Scalar); headers_value.SetCompilerType(clang_void_ptr_type); argument_values.PushValue(mode_value); @@ -343,29 +343,26 @@ void DynamicLoaderMacOS::PutToLog(Log *log) const { bool DynamicLoaderMacOS::SetNotificationBreakpoint() { if (m_break_id == LLDB_INVALID_BREAK_ID) { - ConstString g_symbol_name("_dyld_debugger_notification"); - const Symbol *symbol = nullptr; ModuleSP dyld_sp(GetDYLDModule()); if (dyld_sp) { - symbol = dyld_sp->FindFirstSymbolWithNameAndType(g_symbol_name, - eSymbolTypeCode); - } - if (symbol && - (symbol->ValueIsAddress() || symbol->GetAddressRef().IsValid())) { - addr_t symbol_address = - symbol->GetAddressRef().GetOpcodeLoadAddress(&m_process->GetTarget()); - if (symbol_address != LLDB_INVALID_ADDRESS) { - bool internal = true; - bool hardware = false; - Breakpoint *breakpoint = - m_process->GetTarget() - .CreateBreakpoint(symbol_address, internal, hardware) - .get(); - breakpoint->SetCallback(DynamicLoaderMacOS::NotifyBreakpointHit, this, - true); - breakpoint->SetBreakpointKind("shared-library-event"); - m_break_id = breakpoint->GetID(); - } + bool internal = true; + bool hardware = false; + LazyBool skip_prologue = eLazyBoolNo; + FileSpecList *source_files = nullptr; + FileSpecList dyld_filelist; + dyld_filelist.Append(dyld_sp->GetObjectFile()->GetFileSpec()); + + Breakpoint *breakpoint = + m_process->GetTarget() + .CreateBreakpoint(&dyld_filelist, source_files, + "_dyld_debugger_notification", + eFunctionNameTypeFull, eLanguageTypeC, 0, + skip_prologue, internal, hardware) + .get(); + breakpoint->SetCallback(DynamicLoaderMacOS::NotifyBreakpointHit, this, + true); + breakpoint->SetBreakpointKind("shared-library-event"); + m_break_id = breakpoint->GetID(); } } return m_break_id != LLDB_INVALID_BREAK_ID; @@ -401,18 +398,16 @@ DynamicLoaderMacOS::GetDyldLockVariableAddressFromModule(Module *module) { Status DynamicLoaderMacOS::CanLoadImage() { Status error; addr_t symbol_address = LLDB_INVALID_ADDRESS; + ConstString g_libdyld_name("libdyld.dylib"); Target &target = m_process->GetTarget(); const ModuleList &target_modules = target.GetImages(); std::lock_guard guard(target_modules.GetMutex()); - const size_t num_modules = target_modules.GetSize(); - ConstString g_libdyld_name("libdyld.dylib"); // Find any modules named "libdyld.dylib" and look for the symbol there first - for (size_t i = 0; i < num_modules; i++) { - Module *module_pointer = target_modules.GetModulePointerAtIndexUnlocked(i); - if (module_pointer) { - if (module_pointer->GetFileSpec().GetFilename() == g_libdyld_name) { - symbol_address = GetDyldLockVariableAddressFromModule(module_pointer); + for (ModuleSP module_sp : target.GetImages().ModulesNoLocking()) { + if (module_sp) { + if (module_sp->GetFileSpec().GetFilename() == g_libdyld_name) { + symbol_address = GetDyldLockVariableAddressFromModule(module_sp.get()); if (symbol_address != LLDB_INVALID_ADDRESS) break; } @@ -421,12 +416,10 @@ Status DynamicLoaderMacOS::CanLoadImage() { // Search through all modules looking for the symbol in them if (symbol_address == LLDB_INVALID_ADDRESS) { - for (size_t i = 0; i < num_modules; i++) { - Module *module_pointer = - target_modules.GetModulePointerAtIndexUnlocked(i); - if (module_pointer) { + for (ModuleSP module_sp : target.GetImages().Modules()) { + if (module_sp) { addr_t symbol_address = - GetDyldLockVariableAddressFromModule(module_pointer); + GetDyldLockVariableAddressFromModule(module_sp.get()); if (symbol_address != LLDB_INVALID_ADDRESS) break; } @@ -451,9 +444,9 @@ Status DynamicLoaderMacOS::CanLoadImage() { // _dyld_start) - so we should not allow dlopen calls. But if we found more // than one module then we are clearly past _dyld_start so in that case // we'll default to "it's safe". - if (num_modules <= 1) - error.SetErrorString("could not find the dyld library or " - "the dyld lock symbol"); + if (target.GetImages().GetSize() <= 1) + error.SetErrorString("could not find the dyld library or " + "the dyld lock symbol"); } return error; } diff --git a/gnu/llvm/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOS.h b/gnu/llvm/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOS.h index 12e294e89e8..4f4a84946b6 100644 --- a/gnu/llvm/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOS.h +++ b/gnu/llvm/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOS.h @@ -103,10 +103,6 @@ protected: // exec's when talking to // debugservers that don't support // the "reason:exec" annotation. - -private: - DynamicLoaderMacOS(const DynamicLoaderMacOS &) = delete; - const DynamicLoaderMacOS &operator=(const DynamicLoaderMacOS &) = delete; }; #endif // LLDB_SOURCE_PLUGINS_DYNAMICLOADER_MACOSX_DYLD_DYNAMICLOADERMACOS_H diff --git a/gnu/llvm/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.cpp b/gnu/llvm/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.cpp index d425b358723..91b1682ad00 100644 --- a/gnu/llvm/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.cpp +++ b/gnu/llvm/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.cpp @@ -32,7 +32,7 @@ //#define ENABLE_DEBUG_PRINTF // COMMENT THIS LINE OUT PRIOR TO CHECKIN #ifdef ENABLE_DEBUG_PRINTF -#include +#include #define DEBUG_PRINTF(fmt, ...) printf(fmt, ##__VA_ARGS__) #else #define DEBUG_PRINTF(fmt, ...) @@ -343,7 +343,7 @@ bool DynamicLoaderMacOSXDYLD::NotifyBreakpointHit( // get the values from the ABI: TypeSystemClang *clang_ast_context = - TypeSystemClang::GetScratch(process->GetTarget()); + ScratchTypeSystemClang::GetForTarget(process->GetTarget()); if (!clang_ast_context) return false; @@ -355,7 +355,7 @@ bool DynamicLoaderMacOSXDYLD::NotifyBreakpointHit( CompilerType clang_uint32_type = clang_ast_context->GetBuiltinTypeForEncodingAndBitSize( lldb::eEncodingUint, 32); - input_value.SetValueType(Value::eValueTypeScalar); + input_value.SetValueType(Value::ValueType::Scalar); input_value.SetCompilerType(clang_uint32_type); // input_value.SetContext (Value::eContextTypeClangType, // clang_uint32_type); @@ -728,13 +728,8 @@ bool DynamicLoaderMacOSXDYLD::InitializeFromAllImageInfos() { // DYLD_*_PATH pointed to an equivalent version. We don't want it to stay // in the target's module list or it will confuse us, so unload it here. Target &target = m_process->GetTarget(); - const ModuleList &target_modules = target.GetImages(); ModuleList not_loaded_modules; - std::lock_guard guard(target_modules.GetMutex()); - - size_t num_modules = target_modules.GetSize(); - for (size_t i = 0; i < num_modules; i++) { - ModuleSP module_sp = target_modules.GetModuleAtIndexUnlocked(i); + for (ModuleSP module_sp : target.GetImages().Modules()) { if (!module_sp->IsLoadedInTarget(&target)) { if (log) { StreamString s; @@ -1119,6 +1114,12 @@ bool DynamicLoaderMacOSXDYLD::GetSharedCacheInformation( return false; } +bool DynamicLoaderMacOSXDYLD::IsFullyInitialized() { + if (ReadAllImageInfosStructure()) + return m_dyld_all_image_infos.libSystemInitialized; + return false; +} + void DynamicLoaderMacOSXDYLD::Initialize() { PluginManager::RegisterPlugin(GetPluginNameStatic(), GetPluginDescriptionStatic(), CreateInstance); diff --git a/gnu/llvm/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.h b/gnu/llvm/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.h index 21bf5875dc1..4b337d1f2d7 100644 --- a/gnu/llvm/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.h +++ b/gnu/llvm/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.h @@ -68,6 +68,8 @@ public: uint32_t GetPluginVersion() override; + bool IsFullyInitialized() override; + protected: void PutToLog(lldb_private::Log *log) const; @@ -96,20 +98,15 @@ protected: lldb_private::FileSpec *lc_id_dylinker); struct DYLDAllImageInfos { - uint32_t version; - uint32_t dylib_info_count; // Version >= 1 - lldb::addr_t dylib_info_addr; // Version >= 1 - lldb::addr_t notification; // Version >= 1 - bool processDetachedFromSharedRegion; // Version >= 1 - bool libSystemInitialized; // Version >= 2 - lldb::addr_t dyldImageLoadAddress; // Version >= 2 - - DYLDAllImageInfos() - : version(0), dylib_info_count(0), - dylib_info_addr(LLDB_INVALID_ADDRESS), - notification(LLDB_INVALID_ADDRESS), - processDetachedFromSharedRegion(false), libSystemInitialized(false), - dyldImageLoadAddress(LLDB_INVALID_ADDRESS) {} + uint32_t version = 0; + uint32_t dylib_info_count = 0; // Version >= 1 + lldb::addr_t dylib_info_addr = LLDB_INVALID_ADDRESS; // Version >= 1 + lldb::addr_t notification = LLDB_INVALID_ADDRESS; // Version >= 1 + bool processDetachedFromSharedRegion = false; // Version >= 1 + bool libSystemInitialized = false; // Version >= 2 + lldb::addr_t dyldImageLoadAddress = LLDB_INVALID_ADDRESS; // Version >= 2 + + DYLDAllImageInfos() = default; void Clear() { version = 0; diff --git a/gnu/llvm/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.h b/gnu/llvm/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.h index b028120eb0d..5775f5a730c 100644 --- a/gnu/llvm/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.h +++ b/gnu/llvm/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.h @@ -38,13 +38,13 @@ class DYLDRendezvous { // the layout of this struct is not binary compatible, it is simply large // enough to hold the information on both 32 and 64 bit platforms. struct Rendezvous { - uint64_t version; - lldb::addr_t map_addr; - lldb::addr_t brk; - uint64_t state; - lldb::addr_t ldbase; + uint64_t version = 0; + lldb::addr_t map_addr = 0; + lldb::addr_t brk = 0; + uint64_t state = 0; + lldb::addr_t ldbase = 0; - Rendezvous() : version(0), map_addr(0), brk(0), state(0), ldbase(0) {} + Rendezvous() = default; }; public: @@ -60,6 +60,9 @@ public: DYLDRendezvous(lldb_private::Process *process); + /// Update the cached executable path. + void UpdateExecutablePath(); + /// Update the internal snapshot of runtime linker rendezvous and recompute /// the currently loaded modules. /// diff --git a/gnu/llvm/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h b/gnu/llvm/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h index a7fcdfbadea..61567801fdd 100644 --- a/gnu/llvm/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h +++ b/gnu/llvm/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h @@ -81,6 +81,9 @@ protected: /// mapped to the address space lldb::addr_t m_interpreter_base; + /// Contains the pointer to the interpret module, if loaded. + std::weak_ptr m_interpreter_module; + /// Loaded module list. (link map for each module) std::map> m_loaded_modules; @@ -95,6 +98,9 @@ protected: void *baton, lldb_private::StoppointCallbackContext *context, lldb::user_id_t break_id, lldb::user_id_t break_loc_id); + /// Indicates whether the initial set of modules was reported added. + bool m_initial_modules_added; + /// Helper method for RendezvousBreakpointHit. Updates LLDB's current set /// of loaded modules. void RefreshModules(); diff --git a/gnu/llvm/lldb/source/Plugins/DynamicLoader/Static/DynamicLoaderStatic.cpp b/gnu/llvm/lldb/source/Plugins/DynamicLoader/Static/DynamicLoaderStatic.cpp index 48762fe6e0c..8a5528f1e47 100644 --- a/gnu/llvm/lldb/source/Plugins/DynamicLoader/Static/DynamicLoaderStatic.cpp +++ b/gnu/llvm/lldb/source/Plugins/DynamicLoader/Static/DynamicLoaderStatic.cpp @@ -10,6 +10,7 @@ #include "lldb/Core/PluginManager.h" #include "lldb/Core/Section.h" #include "lldb/Symbol/ObjectFile.h" +#include "lldb/Target/SectionLoadList.h" #include "lldb/Target/Target.h" #include "DynamicLoaderStatic.h" @@ -63,9 +64,6 @@ DynamicLoader *DynamicLoaderStatic::CreateInstance(Process *process, DynamicLoaderStatic::DynamicLoaderStatic(Process *process) : DynamicLoader(process) {} -// Destructor -DynamicLoaderStatic::~DynamicLoaderStatic() {} - /// Called after attaching a process. /// /// Allow DynamicLoader plug-ins to execute some code after @@ -86,11 +84,7 @@ void DynamicLoaderStatic::LoadAllImagesAtFileAddresses() { // Disable JIT for static dynamic loader targets m_process->SetCanJIT(false); - std::lock_guard guard(module_list.GetMutex()); - - const size_t num_modules = module_list.GetSize(); - for (uint32_t idx = 0; idx < num_modules; ++idx) { - ModuleSP module_sp(module_list.GetModuleAtIndexUnlocked(idx)); + for (ModuleSP module_sp : module_list.Modules()) { if (module_sp) { bool changed = false; ObjectFile *image_object_file = module_sp->GetObjectFile(); @@ -112,6 +106,15 @@ void DynamicLoaderStatic::LoadAllImagesAtFileAddresses() { // the file... SectionSP section_sp(section_list->GetSectionAtIndex(sect_idx)); if (section_sp) { + // If this section already has a load address set in the target, + // don't re-set it to the file address. Something may have + // set it to a more correct value already. + if (m_process->GetTarget() + .GetSectionLoadList() + .GetSectionLoadAddress(section_sp) != + LLDB_INVALID_ADDRESS) { + continue; + } if (m_process->GetTarget().SetSectionLoadAddress( section_sp, section_sp->GetFileAddress())) changed = true; diff --git a/gnu/llvm/lldb/source/Plugins/DynamicLoader/Static/DynamicLoaderStatic.h b/gnu/llvm/lldb/source/Plugins/DynamicLoader/Static/DynamicLoaderStatic.h index ce78804f9a9..1a36c7851c2 100644 --- a/gnu/llvm/lldb/source/Plugins/DynamicLoader/Static/DynamicLoaderStatic.h +++ b/gnu/llvm/lldb/source/Plugins/DynamicLoader/Static/DynamicLoaderStatic.h @@ -18,8 +18,6 @@ class DynamicLoaderStatic : public lldb_private::DynamicLoader { public: DynamicLoaderStatic(lldb_private::Process *process); - ~DynamicLoaderStatic() override; - // Static Functions static void Initialize(); @@ -52,9 +50,6 @@ public: private: void LoadAllImagesAtFileAddresses(); - - DynamicLoaderStatic(const DynamicLoaderStatic &) = delete; - const DynamicLoaderStatic &operator=(const DynamicLoaderStatic &) = delete; }; #endif // LLDB_SOURCE_PLUGINS_DYNAMICLOADER_STATIC_DYNAMICLOADERSTATIC_H diff --git a/gnu/llvm/lldb/source/Plugins/DynamicLoader/Windows-DYLD/DynamicLoaderWindowsDYLD.cpp b/gnu/llvm/lldb/source/Plugins/DynamicLoader/Windows-DYLD/DynamicLoaderWindowsDYLD.cpp index 7f9504b9b3a..54dfa3e9d6f 100644 --- a/gnu/llvm/lldb/source/Plugins/DynamicLoader/Windows-DYLD/DynamicLoaderWindowsDYLD.cpp +++ b/gnu/llvm/lldb/source/Plugins/DynamicLoader/Windows-DYLD/DynamicLoaderWindowsDYLD.cpp @@ -28,7 +28,7 @@ LLDB_PLUGIN_DEFINE(DynamicLoaderWindowsDYLD) DynamicLoaderWindowsDYLD::DynamicLoaderWindowsDYLD(Process *process) : DynamicLoader(process) {} -DynamicLoaderWindowsDYLD::~DynamicLoaderWindowsDYLD() {} +DynamicLoaderWindowsDYLD::~DynamicLoaderWindowsDYLD() = default; void DynamicLoaderWindowsDYLD::Initialize() { PluginManager::RegisterPlugin(GetPluginNameStatic(), @@ -193,7 +193,7 @@ DynamicLoaderWindowsDYLD::GetStepThroughTrampolinePlan(Thread &thread, AddressRange range(pc, 2 * 15); DisassemblerSP disassembler_sp = Disassembler::DisassembleRange( - arch, nullptr, nullptr, m_process->GetTarget(), range, true); + arch, nullptr, nullptr, m_process->GetTarget(), range); if (!disassembler_sp) { return ThreadPlanSP(); } diff --git a/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.cpp b/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.cpp index 39ba5f4e9e4..85e2fcfc838 100644 --- a/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.cpp +++ b/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.cpp @@ -15,7 +15,6 @@ #include "lldb/Target/Target.h" #include "lldb/Utility/LLDBAssert.h" #include "lldb/Utility/Log.h" -#include "stdlib.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" @@ -27,6 +26,7 @@ #include "clang/Sema/SemaDiagnostic.h" #include "llvm/Support/Casting.h" #include "llvm/Support/raw_ostream.h" +#include using namespace llvm; using namespace clang; @@ -43,7 +43,7 @@ ASTResultSynthesizer::ASTResultSynthesizer(ASTConsumer *passthrough, m_passthrough_sema = dyn_cast(passthrough); } -ASTResultSynthesizer::~ASTResultSynthesizer() {} +ASTResultSynthesizer::~ASTResultSynthesizer() = default; void ASTResultSynthesizer::Initialize(ASTContext &Context) { m_ast_context = &Context; @@ -443,7 +443,9 @@ void ASTResultSynthesizer::CommitPersistentDecls() { return; auto *persistent_vars = llvm::cast(state); - TypeSystemClang *scratch_ctx = TypeSystemClang::GetScratch(m_target); + + TypeSystemClang *scratch_ctx = ScratchTypeSystemClang::GetForTarget( + m_target, m_ast_context->getLangOpts()); for (clang::NamedDecl *decl : m_decls) { StringRef name = decl->getName(); diff --git a/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/ASTStructExtractor.cpp b/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/ASTStructExtractor.cpp index 40f0de40da5..a2722db5d24 100644 --- a/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/ASTStructExtractor.cpp +++ b/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/ASTStructExtractor.cpp @@ -9,7 +9,6 @@ #include "ASTStructExtractor.h" #include "lldb/Utility/Log.h" -#include "stdlib.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" @@ -21,6 +20,7 @@ #include "clang/Sema/Sema.h" #include "llvm/Support/Casting.h" #include "llvm/Support/raw_ostream.h" +#include using namespace llvm; using namespace clang; @@ -38,7 +38,7 @@ ASTStructExtractor::ASTStructExtractor(ASTConsumer *passthrough, m_passthrough_sema = dyn_cast(passthrough); } -ASTStructExtractor::~ASTStructExtractor() {} +ASTStructExtractor::~ASTStructExtractor() = default; void ASTStructExtractor::Initialize(ASTContext &Context) { m_ast_context = &Context; diff --git a/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/ASTUtils.cpp b/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/ASTUtils.cpp index 1e438ed9d73..a95fce1c5aa 100644 --- a/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/ASTUtils.cpp +++ b/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/ASTUtils.cpp @@ -8,17 +8,17 @@ #include "ASTUtils.h" -lldb_private::ExternalASTSourceWrapper::~ExternalASTSourceWrapper() {} +lldb_private::ExternalASTSourceWrapper::~ExternalASTSourceWrapper() = default; void lldb_private::ExternalASTSourceWrapper::PrintStats() { m_Source->PrintStats(); } -lldb_private::ASTConsumerForwarder::~ASTConsumerForwarder() {} +lldb_private::ASTConsumerForwarder::~ASTConsumerForwarder() = default; void lldb_private::ASTConsumerForwarder::PrintStats() { m_c->PrintStats(); } -lldb_private::SemaSourceWithPriorities::~SemaSourceWithPriorities() {} +lldb_private::SemaSourceWithPriorities::~SemaSourceWithPriorities() = default; void lldb_private::SemaSourceWithPriorities::PrintStats() { for (size_t i = 0; i < Sources.size(); ++i) diff --git a/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/ASTUtils.h b/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/ASTUtils.h index 3787c572d45..b70ec223df4 100644 --- a/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/ASTUtils.h +++ b/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/ASTUtils.h @@ -359,15 +359,12 @@ public: } void CompleteType(clang::TagDecl *Tag) override { - while (!Tag->isCompleteDefinition()) - for (size_t i = 0; i < Sources.size(); ++i) { - // FIXME: We are technically supposed to loop here too until - // Tag->isCompleteDefinition() is true, but if our low quality source - // is failing to complete the tag this code will deadlock. - Sources[i]->CompleteType(Tag); - if (Tag->isCompleteDefinition()) - break; - } + for (clang::ExternalSemaSource *S : Sources) { + S->CompleteType(Tag); + // Stop after the first source completed the type. + if (Tag->isCompleteDefinition()) + break; + } } void CompleteType(clang::ObjCInterfaceDecl *Class) override { @@ -404,13 +401,6 @@ public: return nullptr; } - bool DeclIsFromPCHWithObjectFile(const clang::Decl *D) override { - for (auto *S : Sources) - if (S->DeclIsFromPCHWithObjectFile(D)) - return true; - return false; - } - bool layoutRecordType( const clang::RecordDecl *Record, uint64_t &Size, uint64_t &Alignment, llvm::DenseMap &FieldOffsets, diff --git a/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/CMakeLists.txt b/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/CMakeLists.txt index 69696b9aa76..04f6cdf9d9b 100644 --- a/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/CMakeLists.txt +++ b/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/CMakeLists.txt @@ -1,7 +1,3 @@ -if(NOT LLDB_BUILT_STANDALONE) - set(tablegen_deps intrinsics_gen) -endif() - add_lldb_library(lldbPluginExpressionParserClang ASTResultSynthesizer.cpp ASTStructExtractor.cpp @@ -29,7 +25,7 @@ add_lldb_library(lldbPluginExpressionParserClang NameSearchContext.cpp DEPENDS - ${tablegen_deps} + intrinsics_gen LINK_LIBS lldbCore diff --git a/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp b/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp index ac16738933a..94647b0ef97 100644 --- a/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp +++ b/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp @@ -184,7 +184,7 @@ private: } public: - DeclContextOverride() {} + DeclContextOverride() = default; void OverrideAllDeclsFromContainingFunction(clang::Decl *decl) { for (DeclContext *decl_context = decl->getLexicalDeclContext(); @@ -216,7 +216,12 @@ namespace { /// imported while completing the original Decls). class CompleteTagDeclsScope : public ClangASTImporter::NewDeclListener { ClangASTImporter::ImporterDelegateSP m_delegate; - llvm::SmallVector m_decls_to_complete; + /// List of declarations in the target context that need to be completed. + /// Every declaration should only be completed once and therefore should only + /// be once in this list. + llvm::SetVector m_decls_to_complete; + /// Set of declarations that already were successfully completed (not just + /// added to m_decls_to_complete). llvm::SmallPtrSet m_decls_already_completed; clang::ASTContext *m_dst_ctx; clang::ASTContext *m_src_ctx; @@ -244,10 +249,13 @@ public: NamedDecl *decl = m_decls_to_complete.pop_back_val(); m_decls_already_completed.insert(decl); + // The decl that should be completed has to be imported into the target + // context from some other context. + assert(to_context_md->hasOrigin(decl)); // We should only complete decls coming from the source context. - assert(to_context_md->m_origins[decl].ctx == m_src_ctx); + assert(to_context_md->getOrigin(decl).ctx == m_src_ctx); - Decl *original_decl = to_context_md->m_origins[decl].decl; + Decl *original_decl = to_context_md->getOrigin(decl).decl; // Complete the decl now. TypeSystemClang::GetCompleteDecl(m_src_ctx, original_decl); @@ -266,7 +274,7 @@ public: container_decl->setHasExternalVisibleStorage(false); } - to_context_md->m_origins.erase(decl); + to_context_md->removeOrigin(decl); } // Stop listening to imported decls. We do this after clearing the @@ -287,7 +295,8 @@ public: // Check if we already completed this type. if (m_decls_already_completed.count(to_named_decl) != 0) return; - m_decls_to_complete.push_back(to_named_decl); + // Queue this type to be completed. + m_decls_to_complete.insert(to_named_decl); } }; } // namespace @@ -350,9 +359,6 @@ bool ClangASTImporter::CanImport(const CompilerType &type) { if (!ClangUtil::IsClangType(type)) return false; - // TODO: remove external completion BOOL - // CompleteAndFetchChildren should get the Decl out and check for the - clang::QualType qual_type( ClangUtil::GetCanonicalQualType(ClangUtil::RemoveFastQualifiers(type))); @@ -426,8 +432,6 @@ bool ClangASTImporter::CanImport(const CompilerType &type) { bool ClangASTImporter::Import(const CompilerType &type) { if (!ClangUtil::IsClangType(type)) return false; - // TODO: remove external completion BOOL - // CompleteAndFetchChildren should get the Decl out and check for the clang::QualType qual_type( ClangUtil::GetCanonicalQualType(ClangUtil::RemoveFastQualifiers(type))); @@ -581,10 +585,7 @@ bool ClangASTImporter::CompleteTagDeclWithOrigin(clang::TagDecl *decl, ASTContextMetadataSP context_md = GetContextMetadata(&decl->getASTContext()); - OriginMap &origins = context_md->m_origins; - - origins[decl] = DeclOrigin(origin_ast_ctx, origin_decl); - + context_md->setOrigin(decl, DeclOrigin(origin_ast_ctx, origin_decl)); return true; } @@ -721,29 +722,14 @@ ClangASTImporter::DeclOrigin ClangASTImporter::GetDeclOrigin(const clang::Decl *decl) { ASTContextMetadataSP context_md = GetContextMetadata(&decl->getASTContext()); - OriginMap &origins = context_md->m_origins; - - OriginMap::iterator iter = origins.find(decl); - - if (iter != origins.end()) - return iter->second; - return DeclOrigin(); + return context_md->getOrigin(decl); } void ClangASTImporter::SetDeclOrigin(const clang::Decl *decl, clang::Decl *original_decl) { ASTContextMetadataSP context_md = GetContextMetadata(&decl->getASTContext()); - - OriginMap &origins = context_md->m_origins; - - OriginMap::iterator iter = origins.find(decl); - - if (iter != origins.end()) { - iter->second.decl = original_decl; - iter->second.ctx = &original_decl->getASTContext(); - return; - } - origins[decl] = DeclOrigin(&original_decl->getASTContext(), original_decl); + context_md->setOrigin( + decl, DeclOrigin(&original_decl->getASTContext(), original_decl)); } void ClangASTImporter::RegisterNamespaceMap(const clang::NamespaceDecl *decl, @@ -817,14 +803,7 @@ void ClangASTImporter::ForgetSource(clang::ASTContext *dst_ast, return; md->m_delegates.erase(src_ast); - - for (OriginMap::iterator iter = md->m_origins.begin(); - iter != md->m_origins.end();) { - if (iter->second.ctx == src_ast) - md->m_origins.erase(iter++); - else - ++iter; - } + md->removeOriginsWithContext(src_ast); } ClangASTImporter::MapCompleter::~MapCompleter() { return; } @@ -846,6 +825,10 @@ ClangASTImporter::ASTImporterDelegate::ImportImpl(Decl *From) { // Check which ASTContext this declaration originally came from. DeclOrigin origin = m_master.GetDeclOrigin(From); + + // Prevent infinite recursion when the origin tracking contains a cycle. + assert(origin.decl != From && "Origin points to itself?"); + // If it originally came from the target ASTContext then we can just // pretend that the original is the one we imported. This can happen for // example when inspecting a persistent declaration from the scratch @@ -895,13 +878,45 @@ ClangASTImporter::ASTImporterDelegate::ImportImpl(Decl *From) { return dn_or_err.takeError(); DeclContext *dc = *dc_or_err; DeclContext::lookup_result lr = dc->lookup(*dn_or_err); - if (lr.size()) { - clang::Decl *lookup_found = lr.front(); - RegisterImportedDecl(From, lookup_found); - m_decls_to_ignore.insert(lookup_found); - return lookup_found; - } else - LLDB_LOG(log, "[ClangASTImporter] Complete definition not found"); + for (clang::Decl *candidate : lr) { + if (candidate->getKind() == From->getKind()) { + RegisterImportedDecl(From, candidate); + m_decls_to_ignore.insert(candidate); + return candidate; + } + } + LLDB_LOG(log, "[ClangASTImporter] Complete definition not found"); + } + + // Disable the minimal import for fields that have record types. There is + // no point in minimally importing the record behind their type as Clang + // will anyway request their definition when the FieldDecl is added to the + // RecordDecl (as Clang will query the FieldDecl's type for things such + // as a deleted constexpr destructor). + // By importing the type ahead of time we avoid some corner cases where + // the FieldDecl's record is importing in the middle of Clang's + // `DeclContext::addDecl` logic. + if (clang::FieldDecl *fd = dyn_cast(From)) { + // This is only necessary because we do the 'minimal import'. Remove this + // once LLDB stopped using that mode. + assert(isMinimalImport() && "Only necessary for minimal import"); + QualType field_type = fd->getType(); + if (field_type->isRecordType()) { + // First get the underlying record and minimally import it. + clang::TagDecl *record_decl = field_type->getAsTagDecl(); + llvm::Expected imported = Import(record_decl); + if (!imported) + return imported.takeError(); + // Check how/if the import got redirected to a different AST. Now + // import the definition of what was actually imported. If there is no + // origin then that means the record was imported by just picking a + // compatible type in the target AST (in which case there is no more + // importing to do). + if (clang::Decl *origin = m_master.GetDeclOrigin(*imported).decl) { + if (llvm::Error def_err = ImportDefinition(record_decl)) + return std::move(def_err); + } + } } return ASTImporter::ImportImpl(From); @@ -919,16 +934,6 @@ void ClangASTImporter::ASTImporterDelegate::ImportDefinitionTo( MapImported(from, to); ASTImporter::Imported(from, to); - /* - if (to_objc_interface) - to_objc_interface->startDefinition(); - - CXXRecordDecl *to_cxx_record = dyn_cast(to); - - if (to_cxx_record) - to_cxx_record->startDefinition(); - */ - Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS); if (llvm::Error err = ImportDefinition(from)) { @@ -1100,37 +1105,32 @@ void ClangASTImporter::ASTImporterDelegate::Imported(clang::Decl *from, m_master.MaybeGetContextMetadata(m_source_ctx); if (from_context_md) { - OriginMap &origins = from_context_md->m_origins; - - OriginMap::iterator origin_iter = origins.find(from); + DeclOrigin origin = from_context_md->getOrigin(from); - if (origin_iter != origins.end()) { - if (to_context_md->m_origins.find(to) == to_context_md->m_origins.end() || - user_id != LLDB_INVALID_UID) { - if (origin_iter->second.ctx != &to->getASTContext()) - to_context_md->m_origins[to] = origin_iter->second; - } + if (origin.Valid()) { + if (origin.ctx != &to->getASTContext()) { + if (!to_context_md->hasOrigin(to) || user_id != LLDB_INVALID_UID) + to_context_md->setOrigin(to, origin); - ImporterDelegateSP direct_completer = - m_master.GetDelegate(&to->getASTContext(), origin_iter->second.ctx); + ImporterDelegateSP direct_completer = + m_master.GetDelegate(&to->getASTContext(), origin.ctx); - if (direct_completer.get() != this) - direct_completer->ASTImporter::Imported(origin_iter->second.decl, to); + if (direct_completer.get() != this) + direct_completer->ASTImporter::Imported(origin.decl, to); - LLDB_LOG(log, - " [ClangASTImporter] Propagated origin " - "(Decl*){0}/(ASTContext*){1} from (ASTContext*){2} to " - "(ASTContext*){3}", - origin_iter->second.decl, origin_iter->second.ctx, - &from->getASTContext(), &to->getASTContext()); + LLDB_LOG(log, + " [ClangASTImporter] Propagated origin " + "(Decl*){0}/(ASTContext*){1} from (ASTContext*){2} to " + "(ASTContext*){3}", + origin.decl, origin.ctx, &from->getASTContext(), + &to->getASTContext()); + } } else { if (m_new_decl_listener) m_new_decl_listener->NewDeclImported(from, to); - if (to_context_md->m_origins.find(to) == to_context_md->m_origins.end() || - user_id != LLDB_INVALID_UID) { - to_context_md->m_origins[to] = DeclOrigin(m_source_ctx, from); - } + if (!to_context_md->hasOrigin(to) || user_id != LLDB_INVALID_UID) + to_context_md->setOrigin(to, DeclOrigin(m_source_ctx, from)); LLDB_LOG(log, " [ClangASTImporter] Decl has no origin information in " @@ -1151,7 +1151,7 @@ void ClangASTImporter::ASTImporterDelegate::Imported(clang::Decl *from, namespace_map_iter->second; } } else { - to_context_md->m_origins[to] = DeclOrigin(m_source_ctx, from); + to_context_md->setOrigin(to, DeclOrigin(m_source_ctx, from)); LLDB_LOG(log, " [ClangASTImporter] Sourced origin " diff --git a/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.h b/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.h index 6ceec774914..4f589d34aa4 100644 --- a/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.h +++ b/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.h @@ -23,6 +23,7 @@ #include "lldb/Host/FileSystem.h" #include "lldb/Symbol/CompilerDeclContext.h" +#include "lldb/Utility/LLDBAssert.h" #include "lldb/lldb-types.h" #include "Plugins/ExpressionParser/Clang/CxxModuleHandler.h" @@ -34,6 +35,32 @@ namespace lldb_private { class ClangASTMetadata; class TypeSystemClang; +/// Manages and observes all Clang AST node importing in LLDB. +/// +/// The ClangASTImporter takes care of two things: +/// +/// 1. Keeps track of all ASTImporter instances in LLDB. +/// +/// Clang's ASTImporter takes care of importing types from one ASTContext to +/// another. This class expands this concept by allowing copying from several +/// ASTContext instances to several other ASTContext instances. Instead of +/// constructing a new ASTImporter manually to copy over a type/decl, this class +/// can be asked to do this. It will construct a ASTImporter for the caller (and +/// will cache the ASTImporter instance for later use) and then perform the +/// import. +/// +/// This mainly prevents that a caller might construct several ASTImporter +/// instances for the same source/target ASTContext combination. As the +/// ASTImporter has an internal state that keeps track of already imported +/// declarations and so on, using only one ASTImporter instance is more +/// efficient and less error-prone than using multiple. +/// +/// 2. Keeps track of from where declarations were imported (origin-tracking). +/// The ASTImporter instances in this class usually only performa a minimal +/// import, i.e., only a shallow copy is made that is filled out on demand +/// when more information is requested later on. This requires record-keeping +/// of where any shallow clone originally came from so that the right original +/// declaration can be found and used as the source of any missing information. class ClangASTImporter { public: struct LayoutInfo { @@ -52,12 +79,34 @@ public: : m_file_manager(clang::FileSystemOptions(), FileSystem::Instance().GetVirtualFileSystem()) {} + /// Copies the given type and the respective declarations to the destination + /// type system. + /// + /// This function does a shallow copy and requires that the target AST + /// has an ExternalASTSource which queries this ClangASTImporter instance + /// for any additional information that is maybe lacking in the shallow copy. + /// This also means that the type system of src_type can *not* be deleted + /// after this function has been called. If you need to delete the source + /// type system you either need to delete the destination type system first + /// or use \ref ClangASTImporter::DeportType. + /// + /// \see ClangASTImporter::DeportType CompilerType CopyType(TypeSystemClang &dst, const CompilerType &src_type); + /// \see ClangASTImporter::CopyType clang::Decl *CopyDecl(clang::ASTContext *dst_ctx, clang::Decl *decl); + /// Copies the given type and the respective declarations to the destination + /// type system. + /// + /// Unlike CopyType this function ensures that types/declarations which are + /// originally from the AST of src_type are fully copied over. The type + /// system of src_type can safely be deleted after calling this function. + /// \see ClangASTImporter::CopyType CompilerType DeportType(TypeSystemClang &dst, const CompilerType &src_type); + /// Copies the given decl to the destination type system. + /// \see ClangASTImporter::DeportType clang::Decl *DeportDecl(clang::ASTContext *dst_ctx, clang::Decl *decl); /// Sets the layout for the given RecordDecl. The layout will later be @@ -78,8 +127,22 @@ public: llvm::DenseMap &vbase_offsets); + /// Returns true iff the given type was copied from another TypeSystemClang + /// and the original type in this other TypeSystemClang might contain + /// additional information (e.g., the definition of a 'class' type) that could + /// be imported. + /// + /// \see ClangASTImporter::Import bool CanImport(const CompilerType &type); + /// If the given type was copied from another TypeSystemClang then copy over + /// all missing information (e.g., the definition of a 'class' type). + /// + /// \return True iff an original type in another TypeSystemClang was found. + /// Note: Does *not* return false if an original type was found but + /// no information was imported over. + /// + /// \see ClangASTImporter::Import bool Import(const CompilerType &type); bool CompleteType(const CompilerType &compiler_type); @@ -94,6 +157,14 @@ public: bool RequireCompleteType(clang::QualType type); + /// Updates the internal origin-tracking information so that the given + /// 'original' decl is from now on used to import additional information + /// into the given decl. + /// + /// Usually the origin-tracking in the ClangASTImporter is automatically + /// updated when a declaration is imported, so the only valid reason to ever + /// call this is if there is a 'better' original decl and the target decl + /// is only a shallow clone that lacks any contents. void SetDeclOrigin(const clang::Decl *decl, clang::Decl *original_decl); ClangASTMetadata *GetDeclMetadata(const clang::Decl *decl); @@ -145,10 +216,13 @@ public: void ForgetSource(clang::ASTContext *dst_ctx, clang::ASTContext *src_ctx); struct DeclOrigin { - DeclOrigin() : ctx(nullptr), decl(nullptr) {} + DeclOrigin() = default; DeclOrigin(clang::ASTContext *_ctx, clang::Decl *_decl) - : ctx(_ctx), decl(_decl) {} + : ctx(_ctx), decl(_decl) { + // The decl has to be in its associated ASTContext. + assert(_decl == nullptr || &_decl->getASTContext() == _ctx); + } DeclOrigin(const DeclOrigin &rhs) { ctx = rhs.ctx; @@ -160,14 +234,12 @@ public: decl = rhs.decl; } - bool Valid() { return (ctx != nullptr || decl != nullptr); } + bool Valid() const { return (ctx != nullptr || decl != nullptr); } - clang::ASTContext *ctx; - clang::Decl *decl; + clang::ASTContext *ctx = nullptr; + clang::Decl *decl = nullptr; }; - typedef llvm::DenseMap OriginMap; - /// Listener interface used by the ASTImporterDelegate to inform other code /// about decls that have been imported the first time. struct NewDeclListener { @@ -192,6 +264,16 @@ public: : clang::ASTImporter(*target_ctx, master.m_file_manager, *source_ctx, master.m_file_manager, true /*minimal*/), m_master(master), m_source_ctx(source_ctx) { + // Target and source ASTContext shouldn't be identical. Importing AST + // nodes within the same AST doesn't make any sense as the whole idea + // is to import them to a different AST. + lldbassert(target_ctx != source_ctx && "Can't import into itself"); + // This is always doing a minimal import of any declarations. This means + // that there has to be an ExternalASTSource in the target ASTContext + // (that should implement the callbacks that complete any declarations + // on demand). Without an ExternalASTSource, this ASTImporter will just + // do a minimal import and the imported declarations won't be completed. + assert(target_ctx->getExternalSource() && "Missing ExternalSource"); setODRHandling(clang::ASTImporter::ODRHandlingType::Liberal); } @@ -259,17 +341,68 @@ public: typedef llvm::DenseMap NamespaceMetaMap; - struct ASTContextMetadata { - ASTContextMetadata(clang::ASTContext *dst_ctx) - : m_dst_ctx(dst_ctx), m_delegates(), m_origins(), m_namespace_maps(), - m_map_completer(nullptr) {} + class ASTContextMetadata { + typedef llvm::DenseMap OriginMap; + + public: + ASTContextMetadata(clang::ASTContext *dst_ctx) : m_dst_ctx(dst_ctx) {} clang::ASTContext *m_dst_ctx; DelegateMap m_delegates; - OriginMap m_origins; NamespaceMetaMap m_namespace_maps; - MapCompleter *m_map_completer; + MapCompleter *m_map_completer = nullptr; + + /// Sets the DeclOrigin for the given Decl and overwrites any existing + /// DeclOrigin. + void setOrigin(const clang::Decl *decl, DeclOrigin origin) { + // Setting the origin of any decl to itself (or to a different decl + // in the same ASTContext) doesn't make any sense. It will also cause + // ASTImporterDelegate::ImportImpl to infinite recurse when trying to find + // the 'original' Decl when importing code. + assert(&decl->getASTContext() != origin.ctx && + "Trying to set decl origin to its own ASTContext?"); + assert(decl != origin.decl && "Trying to set decl origin to itself?"); + m_origins[decl] = origin; + } + + /// Removes any tracked DeclOrigin for the given decl. + void removeOrigin(const clang::Decl *decl) { m_origins.erase(decl); } + + /// Remove all DeclOrigin entries that point to the given ASTContext. + /// Useful when an ASTContext is about to be deleted and all the dangling + /// pointers to it need to be removed. + void removeOriginsWithContext(clang::ASTContext *ctx) { + for (OriginMap::iterator iter = m_origins.begin(); + iter != m_origins.end();) { + if (iter->second.ctx == ctx) + m_origins.erase(iter++); + else + ++iter; + } + } + + /// Returns the DeclOrigin for the given Decl or an invalid DeclOrigin + /// instance if there no known DeclOrigin for the given Decl. + DeclOrigin getOrigin(const clang::Decl *decl) const { + auto iter = m_origins.find(decl); + if (iter == m_origins.end()) + return DeclOrigin(); + return iter->second; + } + + /// Returns true there is a known DeclOrigin for the given Decl. + bool hasOrigin(const clang::Decl *decl) const { + return getOrigin(decl).Valid(); + } + + private: + /// Maps declarations to the ASTContext/Decl from which they were imported + /// from. If a declaration is from an ASTContext which has been deleted + /// since the declaration was imported or the declaration wasn't created by + /// the ASTImporter, then it doesn't have a DeclOrigin and will not be + /// tracked here. + OriginMap m_origins; }; typedef std::shared_ptr ASTContextMetadataSP; diff --git a/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp b/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp index 6fe85a1298f..b43423707ae 100644 --- a/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp +++ b/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp @@ -71,20 +71,22 @@ ClangASTSource::~ClangASTSource() { if (!m_target) return; - // We are in the process of destruction, don't create clang ast context on - // demand by passing false to - // Target::GetScratchTypeSystemClang(create_on_demand). - TypeSystemClang *scratch_clang_ast_context = - TypeSystemClang::GetScratch(*m_target, false); - if (!scratch_clang_ast_context) - return; + // Unregister the current ASTContext as a source for all scratch + // ASTContexts in the ClangASTImporter. Without this the scratch AST might + // query the deleted ASTContext for additional type information. + // We unregister from *all* scratch ASTContexts in case a type got exported + // to a scratch AST that isn't the best fitting scratch ASTContext. + TypeSystemClang *scratch_ast = ScratchTypeSystemClang::GetForTarget( + *m_target, ScratchTypeSystemClang::DefaultAST, false); - clang::ASTContext &scratch_ast_context = - scratch_clang_ast_context->getASTContext(); + if (!scratch_ast) + return; - if (m_ast_context != &scratch_ast_context && m_ast_importer_sp) - m_ast_importer_sp->ForgetSource(&scratch_ast_context, m_ast_context); + ScratchTypeSystemClang *default_scratch_ast = + llvm::cast(scratch_ast); + // Unregister from the default scratch AST (and all sub-ASTs). + default_scratch_ast->ForgetSource(m_ast_context, *m_ast_importer_sp); } void ClangASTSource::StartTranslationUnit(ASTConsumer *Consumer) { @@ -477,16 +479,16 @@ void ClangASTSource::FindExternalLexicalDecls( decl->getDeclKindName(), ast_dump); } - Decl *copied_decl = CopyDecl(decl); - - if (!copied_decl) - continue; + CopyDecl(decl); - if (FieldDecl *copied_field = dyn_cast(copied_decl)) { - QualType copied_field_type = copied_field->getType(); - - m_ast_importer_sp->RequireCompleteType(copied_field_type); - } + // FIXME: We should add the copied decl to the 'decls' list. This would + // add the copied Decl into the DeclContext and make sure that we + // correctly propagate that we added some Decls back to Clang. + // By leaving 'decls' empty we incorrectly return false from + // DeclContext::LoadLexicalDeclsFromExternalStorage which might cause + // lookup issues later on. + // We can't just add them for now as the ASTImporter already added the + // decl into the DeclContext and this would add it twice. } else { SkippedDecls = true; } @@ -679,12 +681,7 @@ void ClangASTSource::FillNamespaceMap( return; } - const ModuleList &target_images = m_target->GetImages(); - std::lock_guard guard(target_images.GetMutex()); - - for (size_t i = 0, e = target_images.GetSize(); i < e; ++i) { - lldb::ModuleSP image = target_images.GetModuleAtIndexUnlocked(i); - + for (lldb::ModuleSP image : m_target->GetImages().Modules()) { if (!image) continue; @@ -844,8 +841,8 @@ void ClangASTSource::FindDeclInModules(NameSearchContext &context, ConstString name) { Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); - ClangModulesDeclVendor *modules_decl_vendor = - m_target->GetClangModulesDeclVendor(); + std::shared_ptr modules_decl_vendor = + GetClangModulesDeclVendor(); if (!modules_decl_vendor) return; @@ -1137,8 +1134,8 @@ void ClangASTSource::FindObjCMethodDecls(NameSearchContext &context) { // Check the modules only if the debug information didn't have a complete // interface. - if (ClangModulesDeclVendor *modules_decl_vendor = - m_target->GetClangModulesDeclVendor()) { + if (std::shared_ptr modules_decl_vendor = + GetClangModulesDeclVendor()) { ConstString interface_name(interface_decl->getNameAsString().c_str()); bool append = false; uint32_t max_matches = 1; @@ -1307,8 +1304,8 @@ void ClangASTSource::FindObjCPropertyAndIvarDecls(NameSearchContext &context) { // Check the modules only if the debug information didn't have a complete // interface. - ClangModulesDeclVendor *modules_decl_vendor = - m_target->GetClangModulesDeclVendor(); + std::shared_ptr modules_decl_vendor = + GetClangModulesDeclVendor(); if (!modules_decl_vendor) break; @@ -1564,10 +1561,10 @@ bool ClangASTSource::layoutRecordType(const RecordDecl *record, uint64_t &size, if (log) { LLDB_LOG(log, "LRT returned:"); - LLDB_LOG(log, "LRT Original = (RecordDecl*)%p", + LLDB_LOG(log, "LRT Original = (RecordDecl*){0}", static_cast(origin_record.decl)); - LLDB_LOG(log, "LRT Size = %" PRId64, size); - LLDB_LOG(log, "LRT Alignment = %" PRId64, alignment); + LLDB_LOG(log, "LRT Size = {0}", size); + LLDB_LOG(log, "LRT Alignment = {0}", alignment); LLDB_LOG(log, "LRT Fields:"); for (RecordDecl::field_iterator fi = record->field_begin(), fe = record->field_end(); @@ -1656,14 +1653,8 @@ void ClangASTSource::CompleteNamespaceMap( module_sp->GetFileSpec().GetFilename()); } } else { - const ModuleList &target_images = m_target->GetImages(); - std::lock_guard guard(target_images.GetMutex()); - CompilerDeclContext null_namespace_decl; - - for (size_t i = 0, e = target_images.GetSize(); i < e; ++i) { - lldb::ModuleSP image = target_images.GetModuleAtIndexUnlocked(i); - + for (lldb::ModuleSP image : m_target->GetImages().Modules()) { if (!image) continue; @@ -1750,3 +1741,10 @@ CompilerType ClangASTSource::GuardedCopyType(const CompilerType &src_type) { return m_clang_ast_context->GetType(copied_qual_type); } + +std::shared_ptr +ClangASTSource::GetClangModulesDeclVendor() { + auto persistent_vars = llvm::cast( + m_target->GetPersistentExpressionStateForLanguage(lldb::eLanguageTypeC)); + return persistent_vars->GetClangModulesDeclVendor(); +} diff --git a/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.h b/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.h index 14761fbeb26..3afd1fd5f2d 100644 --- a/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.h +++ b/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.h @@ -314,6 +314,8 @@ protected: /// The imported type. CompilerType GuardedCopyType(const CompilerType &src_type); + std::shared_ptr GetClangModulesDeclVendor(); + public: /// Returns true if a name should be ignored by name lookup. /// diff --git a/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/ClangDeclVendor.h b/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/ClangDeclVendor.h index bf52bec4b1f..6313117c08d 100644 --- a/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/ClangDeclVendor.h +++ b/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/ClangDeclVendor.h @@ -22,7 +22,7 @@ class ClangDeclVendor : public DeclVendor { public: ClangDeclVendor(DeclVendorKind kind) : DeclVendor(kind) {} - virtual ~ClangDeclVendor() {} + virtual ~ClangDeclVendor() = default; using DeclVendor::FindDecls; diff --git a/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp b/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp index 8c49898e1d6..731b81c61a6 100644 --- a/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp +++ b/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp @@ -19,6 +19,7 @@ #include "lldb/Core/ModuleSpec.h" #include "lldb/Core/ValueObjectConstResult.h" #include "lldb/Core/ValueObjectVariable.h" +#include "lldb/Expression/DiagnosticManager.h" #include "lldb/Expression/Materializer.h" #include "lldb/Symbol/CompileUnit.h" #include "lldb/Symbol/CompilerDecl.h" @@ -109,7 +110,7 @@ bool ClangExpressionDeclMap::WillParse(ExecutionContext &exe_ctx, m_parser_vars->m_persistent_vars = llvm::cast( target->GetPersistentExpressionStateForLanguage(eLanguageTypeC)); - if (!TypeSystemClang::GetScratch(*target)) + if (!ScratchTypeSystemClang::GetForTarget(*target)) return false; } @@ -125,6 +126,12 @@ void ClangExpressionDeclMap::InstallCodeGenerator( m_parser_vars->m_code_gen = code_gen; } +void ClangExpressionDeclMap::InstallDiagnosticManager( + DiagnosticManager &diag_manager) { + assert(m_parser_vars); + m_parser_vars->m_diagnostics = &diag_manager; +} + void ClangExpressionDeclMap::DidParse() { if (m_parser_vars && m_parser_vars->m_persistent_vars) { for (size_t entity_index = 0, num_entities = m_found_entities.GetSize(); @@ -177,7 +184,7 @@ ClangExpressionDeclMap::TargetInfo ClangExpressionDeclMap::GetTargetInfo() { TypeFromUser ClangExpressionDeclMap::DeportType(TypeSystemClang &target, TypeSystemClang &source, TypeFromParser parser_type) { - assert(&target == TypeSystemClang::GetScratch(*m_target)); + assert(&target == GetScratchContext(*m_target)); assert((TypeSystem *)&source == parser_type.GetTypeSystem()); assert(&source.getASTContext() == m_ast_context); @@ -196,6 +203,17 @@ bool ClangExpressionDeclMap::AddPersistentVariable(const NamedDecl *decl, if (ast == nullptr) return false; + // Check if we already declared a persistent variable with the same name. + if (lldb::ExpressionVariableSP conflicting_var = + m_parser_vars->m_persistent_vars->GetVariable(name)) { + std::string msg = llvm::formatv("redefinition of persistent variable '{0}'", + name).str(); + m_parser_vars->m_diagnostics->AddDiagnostic( + msg, DiagnosticSeverity::eDiagnosticSeverityError, + DiagnosticOrigin::eDiagnosticOriginLLDB); + return false; + } + if (m_parser_vars->m_materializer && is_result) { Status err; @@ -204,7 +222,7 @@ bool ClangExpressionDeclMap::AddPersistentVariable(const NamedDecl *decl, if (target == nullptr) return false; - auto *clang_ast_context = TypeSystemClang::GetScratch(*target); + auto *clang_ast_context = GetScratchContext(*target); if (!clang_ast_context) return false; @@ -242,7 +260,7 @@ bool ClangExpressionDeclMap::AddPersistentVariable(const NamedDecl *decl, if (target == nullptr) return false; - TypeSystemClang *context = TypeSystemClang::GetScratch(*target); + TypeSystemClang *context = GetScratchContext(*target); if (!context) return false; @@ -332,7 +350,7 @@ bool ClangExpressionDeclMap::AddValueToStruct(const NamedDecl *decl, if (!var) return false; - LLDB_LOG(log, "Adding value for (NamedDecl*)%p [%s - %s] to the structure", + LLDB_LOG(log, "Adding value for (NamedDecl*){0} [{1} - {2}] to the structure", decl, name, var->GetName()); // We know entity->m_parser_vars is valid because we used a parser variable @@ -703,7 +721,7 @@ clang::NamedDecl *ClangExpressionDeclMap::GetPersistentDecl(ConstString name) { if (!target) return nullptr; - TypeSystemClang::GetScratch(*target); + ScratchTypeSystemClang::GetForTarget(*target); if (!m_parser_vars->m_persistent_vars) return nullptr; @@ -734,7 +752,7 @@ void ClangExpressionDeclMap::SearchPersistenDecls(NameSearchContext &context, MaybeRegisterFunctionBody(parser_function_decl); } - LLDB_LOG(log, " CEDM::FEVD Found persistent decl %s", name); + LLDB_LOG(log, " CEDM::FEVD Found persistent decl {0}", name); context.AddNamedDecl(parser_named_decl); } @@ -1003,7 +1021,8 @@ void ClangExpressionDeclMap::LookupInModulesDeclVendor( if (!m_target) return; - auto *modules_decl_vendor = m_target->GetClangModulesDeclVendor(); + std::shared_ptr modules_decl_vendor = + GetClangModulesDeclVendor(); if (!modules_decl_vendor) return; @@ -1195,8 +1214,8 @@ void ClangExpressionDeclMap::LookupFunction( std::vector decls_from_modules; if (target) { - if (ClangModulesDeclVendor *decl_vendor = - target->GetClangModulesDeclVendor()) { + if (std::shared_ptr decl_vendor = + GetClangModulesDeclVendor()) { decl_vendor->FindDecls(name, false, UINT32_MAX, decls_from_modules); } } @@ -1475,7 +1494,7 @@ bool ClangExpressionDeclMap::GetVariableValue(VariableSP &var, if (var_location_expr.GetExpressionData(const_value_extractor)) { var_location = Value(const_value_extractor.GetDataStart(), const_value_extractor.GetByteSize()); - var_location.SetValueType(Value::eValueTypeHostAddress); + var_location.SetValueType(Value::ValueType::HostAddress); } else { LLDB_LOG(log, "Error evaluating constant variable: {0}", err.AsCString()); return false; @@ -1494,10 +1513,10 @@ bool ClangExpressionDeclMap::GetVariableValue(VariableSP &var, if (parser_type) *parser_type = TypeFromParser(type_to_use); - if (var_location.GetContextType() == Value::eContextTypeInvalid) + if (var_location.GetContextType() == Value::ContextType::Invalid) var_location.SetCompilerType(type_to_use); - if (var_location.GetValueType() == Value::eValueTypeFileAddress) { + if (var_location.GetValueType() == Value::ValueType::FileAddress) { SymbolContext var_sc; var->CalculateSymbolContext(&var_sc); @@ -1511,7 +1530,7 @@ bool ClangExpressionDeclMap::GetVariableValue(VariableSP &var, if (load_addr != LLDB_INVALID_ADDRESS) { var_location.GetScalar() = load_addr; - var_location.SetValueType(Value::eValueTypeLoadAddress); + var_location.SetValueType(Value::ValueType::LoadAddress); } } @@ -1620,7 +1639,7 @@ void ClangExpressionDeclMap::AddOneGenericVariable(NameSearchContext &context, if (target == nullptr) return; - TypeSystemClang *scratch_ast_context = TypeSystemClang::GetScratch(*target); + TypeSystemClang *scratch_ast_context = GetScratchContext(*target); if (!scratch_ast_context) return; @@ -1647,11 +1666,11 @@ void ClangExpressionDeclMap::AddOneGenericVariable(NameSearchContext &context, const Address symbol_address = symbol.GetAddress(); lldb::addr_t symbol_load_addr = symbol_address.GetLoadAddress(target); - // parser_vars->m_lldb_value.SetContext(Value::eContextTypeClangType, + // parser_vars->m_lldb_value.SetContext(Value::ContextType::ClangType, // user_type.GetOpaqueQualType()); parser_vars->m_lldb_value.SetCompilerType(user_type); parser_vars->m_lldb_value.GetScalar() = symbol_load_addr; - parser_vars->m_lldb_value.SetValueType(Value::eValueTypeLoadAddress); + parser_vars->m_lldb_value.SetValueType(Value::ValueType::LoadAddress); parser_vars->m_named_decl = var_decl; parser_vars->m_llvm_value = nullptr; @@ -1842,14 +1861,14 @@ void ClangExpressionDeclMap::AddOneFunction(NameSearchContext &context, entity->GetParserVars(GetParserID()); if (load_addr != LLDB_INVALID_ADDRESS) { - parser_vars->m_lldb_value.SetValueType(Value::eValueTypeLoadAddress); + parser_vars->m_lldb_value.SetValueType(Value::ValueType::LoadAddress); parser_vars->m_lldb_value.GetScalar() = load_addr; } else { // We have to try finding a file address. lldb::addr_t file_addr = fun_address.GetFileAddress(); - parser_vars->m_lldb_value.SetValueType(Value::eValueTypeFileAddress); + parser_vars->m_lldb_value.SetValueType(Value::ValueType::FileAddress); parser_vars->m_lldb_value.GetScalar() = file_addr; } diff --git a/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h b/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h index 6974535a899..e39dc587bc4 100644 --- a/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h +++ b/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h @@ -9,8 +9,8 @@ #ifndef LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGEXPRESSIONDECLMAP_H #define LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGEXPRESSIONDECLMAP_H -#include -#include +#include +#include #include @@ -102,6 +102,8 @@ public: void InstallCodeGenerator(clang::ASTConsumer *code_gen); + void InstallDiagnosticManager(DiagnosticManager &diag_manager); + /// Disable the state needed for parsing and IR transformation. void DidParse(); @@ -246,10 +248,10 @@ public: lldb::SymbolType symbol_type); struct TargetInfo { - lldb::ByteOrder byte_order; - size_t address_byte_size; + lldb::ByteOrder byte_order = lldb::eByteOrderInvalid; + size_t address_byte_size = 0; - TargetInfo() : byte_order(lldb::eByteOrderInvalid), address_byte_size(0) {} + TargetInfo() = default; bool IsValid() { return (byte_order != lldb::eByteOrderInvalid && address_byte_size != 0); @@ -306,7 +308,7 @@ private: /// The following values should not live beyond parsing class ParserVars { public: - ParserVars() {} + ParserVars() = default; Target *GetTarget() { if (m_exe_ctx.GetTargetPtr()) @@ -330,6 +332,8 @@ private: clang::ASTConsumer *m_code_gen = nullptr; ///< If non-NULL, a code generator ///that receives new top-level ///functions. + DiagnosticManager *m_diagnostics = nullptr; + private: ParserVars(const ParserVars &) = delete; const ParserVars &operator=(const ParserVars &) = delete; @@ -349,16 +353,15 @@ private: /// The following values contain layout information for the materialized /// struct, but are not specific to a single materialization struct StructVars { - StructVars() - : m_struct_alignment(0), m_struct_size(0), m_struct_laid_out(false), - m_result_name(), m_object_pointer_type(nullptr, nullptr) {} - - lldb::offset_t - m_struct_alignment; ///< The alignment of the struct in bytes. - size_t m_struct_size; ///< The size of the struct in bytes. - bool m_struct_laid_out; ///< True if the struct has been laid out and the - ///layout is valid (that is, no new fields have been - ///added since). + StructVars() : m_result_name(), m_object_pointer_type(nullptr, nullptr) {} + + lldb::offset_t m_struct_alignment = + 0; ///< The alignment of the struct in bytes. + size_t m_struct_size = 0; ///< The size of the struct in bytes. + bool m_struct_laid_out = + false; ///< True if the struct has been laid out and the + /// layout is valid (that is, no new fields have been + /// added since). ConstString m_result_name; ///< The name of the result variable ($1, for example) TypeFromUser m_object_pointer_type; ///< The type of the "this" variable, if @@ -376,6 +379,11 @@ private: /// Deallocate struct variables void DisableStructVars() { m_struct_vars.reset(); } + TypeSystemClang *GetScratchContext(Target &target) { + return ScratchTypeSystemClang::GetForTarget(target, + m_ast_context->getLangOpts()); + } + /// Get this parser's ID for use in extracting parser- and JIT-specific data /// from persistent variables. uint64_t GetParserID() { return (uint64_t) this; } diff --git a/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionHelper.h b/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionHelper.h index e33e5df2223..37bcaf000cf 100644 --- a/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionHelper.h +++ b/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionHelper.h @@ -38,7 +38,7 @@ public: ExpressionTypeSystemHelper::LLVMCastKind::eKindClangHelper) {} /// Destructor - virtual ~ClangExpressionHelper() {} + virtual ~ClangExpressionHelper() = default; /// Return the object that the parser should use when resolving external /// values. May be NULL if everything should be self-contained. diff --git a/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp b/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp index 6ff028cf698..0b5e1ab059d 100644 --- a/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp +++ b/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp @@ -85,7 +85,7 @@ #include "lldb/Utility/DataBufferHeap.h" #include "lldb/Utility/LLDBAssert.h" #include "lldb/Utility/Log.h" -#include "lldb/Utility/Reproducer.h" +#include "lldb/Utility/ReproducerProvider.h" #include "lldb/Utility/Stream.h" #include "lldb/Utility/StreamString.h" #include "lldb/Utility/StringList.h" @@ -302,6 +302,56 @@ static void SetupModuleHeaderPaths(CompilerInstance *compiler, search_opts.ImplicitModuleMaps = true; } +/// Iff the given identifier is a C++ keyword, remove it from the +/// identifier table (i.e., make the token a normal identifier). +static void RemoveCppKeyword(IdentifierTable &idents, llvm::StringRef token) { + // FIXME: 'using' is used by LLDB for local variables, so we can't remove + // this keyword without breaking this functionality. + if (token == "using") + return; + // GCC's '__null' is used by LLDB to define NULL/Nil/nil. + if (token == "__null") + return; + + LangOptions cpp_lang_opts; + cpp_lang_opts.CPlusPlus = true; + cpp_lang_opts.CPlusPlus11 = true; + cpp_lang_opts.CPlusPlus20 = true; + + clang::IdentifierInfo &ii = idents.get(token); + // The identifier has to be a C++-exclusive keyword. if not, then there is + // nothing to do. + if (!ii.isCPlusPlusKeyword(cpp_lang_opts)) + return; + // If the token is already an identifier, then there is nothing to do. + if (ii.getTokenID() == clang::tok::identifier) + return; + // Otherwise the token is a C++ keyword, so turn it back into a normal + // identifier. + ii.revertTokenIDToIdentifier(); +} + +/// Remove all C++ keywords from the given identifier table. +static void RemoveAllCppKeywords(IdentifierTable &idents) { +#define KEYWORD(NAME, FLAGS) RemoveCppKeyword(idents, llvm::StringRef(#NAME)); +#include "clang/Basic/TokenKinds.def" +} + +/// Configures Clang diagnostics for the expression parser. +static void SetupDefaultClangDiagnostics(CompilerInstance &compiler) { + // List of Clang warning groups that are not useful when parsing expressions. + const std::vector groupsToIgnore = { + "unused-value", + "odr", + "unused-getter-return-value", + }; + for (const char *group : groupsToIgnore) { + compiler.getDiagnostics().setSeverityForGroup( + clang::diag::Flavor::WarningOrError, group, + clang::diag::Severity::Ignored, SourceLocation()); + } +} + //===----------------------------------------------------------------------===// // Implementation of ClangExpressionParser //===----------------------------------------------------------------------===// @@ -454,13 +504,17 @@ ClangExpressionParser::ClangExpressionParser( // 4. Create and install the target on the compiler. m_compiler->createDiagnostics(); + // Limit the number of error diagnostics we emit. + // A value of 0 means no limit for both LLDB and Clang. + m_compiler->getDiagnostics().setErrorLimit(target_sp->GetExprErrorLimit()); + auto target_info = TargetInfo::CreateTargetInfo( m_compiler->getDiagnostics(), m_compiler->getInvocation().TargetOpts); if (log) { LLDB_LOGF(log, "Using SIMD alignment: %d", target_info->getSimdDefaultAlign()); LLDB_LOGF(log, "Target datalayout string: '%s'", - target_info->getDataLayout().getStringRepresentation().c_str()); + target_info->getDataLayoutString()); LLDB_LOGF(log, "Target ABI: '%s'", target_info->getABI().str().c_str()); LLDB_LOGF(log, "Target vector alignment: %d", target_info->getMaxVectorAlign()); @@ -598,18 +652,14 @@ ClangExpressionParser::ClangExpressionParser( m_compiler->getCodeGenOpts().setDebugInfo(codegenoptions::NoDebugInfo); // Disable some warnings. - m_compiler->getDiagnostics().setSeverityForGroup( - clang::diag::Flavor::WarningOrError, "unused-value", - clang::diag::Severity::Ignored, SourceLocation()); - m_compiler->getDiagnostics().setSeverityForGroup( - clang::diag::Flavor::WarningOrError, "odr", - clang::diag::Severity::Ignored, SourceLocation()); + SetupDefaultClangDiagnostics(*m_compiler); // Inform the target of the language options // // FIXME: We shouldn't need to do this, the target should be immutable once // created. This complexity should be lifted elsewhere. - m_compiler->getTarget().adjust(m_compiler->getLangOpts()); + m_compiler->getTarget().adjust(m_compiler->getDiagnostics(), + m_compiler->getLangOpts()); // 6. Set up the diagnostic buffer for reporting errors @@ -623,11 +673,26 @@ ClangExpressionParser::ClangExpressionParser( m_compiler->createSourceManager(m_compiler->getFileManager()); m_compiler->createPreprocessor(TU_Complete); - if (ClangModulesDeclVendor *decl_vendor = - target_sp->GetClangModulesDeclVendor()) { - if (auto *clang_persistent_vars = llvm::cast( - target_sp->GetPersistentExpressionStateForLanguage( - lldb::eLanguageTypeC))) { + switch (language) { + case lldb::eLanguageTypeC: + case lldb::eLanguageTypeC89: + case lldb::eLanguageTypeC99: + case lldb::eLanguageTypeC11: + case lldb::eLanguageTypeObjC: + // This is not a C++ expression but we enabled C++ as explained above. + // Remove all C++ keywords from the PP so that the user can still use + // variables that have C++ keywords as names (e.g. 'int template;'). + RemoveAllCppKeywords(m_compiler->getPreprocessor().getIdentifierTable()); + break; + default: + break; + } + + if (auto *clang_persistent_vars = llvm::cast( + target_sp->GetPersistentExpressionStateForLanguage( + lldb::eLanguageTypeC))) { + if (std::shared_ptr decl_vendor = + clang_persistent_vars->GetClangModulesDeclVendor()) { std::unique_ptr pp_callbacks( new LLDBPreprocessorCallbacks(*decl_vendor, *clang_persistent_vars, m_compiler->getSourceManager())); @@ -660,7 +725,7 @@ ClangExpressionParser::ClangExpressionParser( m_compiler->getCodeGenOpts(), *m_llvm_context)); } -ClangExpressionParser::~ClangExpressionParser() {} +ClangExpressionParser::~ClangExpressionParser() = default; namespace { @@ -1010,8 +1075,8 @@ ClangExpressionParser::ParseInternal(DiagnosticManager &diagnostic_manager, if (file.Write(expr_text, bytes_written).Success()) { if (bytes_written == expr_text_len) { file.Close(); - if (auto fileEntry = - m_compiler->getFileManager().getFile(result_path)) { + if (auto fileEntry = m_compiler->getFileManager().getOptionalFileRef( + result_path)) { source_mgr.setMainFileID(source_mgr.createFileID( *fileEntry, SourceLocation(), SrcMgr::C_User)); @@ -1074,6 +1139,7 @@ ClangExpressionParser::ParseInternal(DiagnosticManager &diagnostic_manager, ClangExpressionDeclMap *decl_map = type_system_helper->DeclMap(); if (decl_map) { decl_map->InstallCodeGenerator(&m_compiler->getASTConsumer()); + decl_map->InstallDiagnosticManager(diagnostic_manager); clang::ExternalASTSource *ast_source = decl_map->CreateProxy(); diff --git a/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp b/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp index a429963277d..31707f81a27 100644 --- a/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp +++ b/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp @@ -31,6 +31,7 @@ using namespace lldb_private; #define PREFIX_NAME "" +#define SUFFIX_NAME "" const llvm::StringRef ClangExpressionSourceCode::g_prefix_file_name = PREFIX_NAME; @@ -73,6 +74,9 @@ extern "C" } )"; +const char *ClangExpressionSourceCode::g_expression_suffix = + "\n;\n#line 1 \"" SUFFIX_NAME "\"\n"; + namespace { class AddMacroState { @@ -180,7 +184,7 @@ lldb_private::ClangExpressionSourceCode::ClangExpressionSourceCode( // containing only the user expression. This will hide our wrapper code // from the user when we render diagnostics with Clang. m_start_marker = "#line 1 \"" + filename.str() + "\"\n"; - m_end_marker = "\n;\n#line 1 \"\"\n"; + m_end_marker = g_expression_suffix; } namespace { @@ -221,7 +225,7 @@ TokenVerifier::TokenVerifier(std::string body) { clang::SourceManager SM(diags, file_mgr); auto buf = llvm::MemoryBuffer::getMemBuffer(body); - FileID FID = SM.createFileID(clang::SourceManager::Unowned, buf.get()); + FileID FID = SM.createFileID(buf->getMemBufferRef()); // Let's just enable the latest ObjC and C++ which should get most tokens // right. @@ -231,7 +235,7 @@ TokenVerifier::TokenVerifier(std::string body) { Opts.CPlusPlus17 = true; Opts.LineComment = true; - Lexer lex(FID, buf.get(), SM, Opts); + Lexer lex(FID, buf->getMemBufferRef(), SM, Opts); Token token; bool exit = false; @@ -297,6 +301,7 @@ bool ClangExpressionSourceCode::GetText( bool force_add_all_locals, llvm::ArrayRef modules) const { const char *target_specific_defines = "typedef signed char BOOL;\n"; std::string module_macros; + llvm::raw_string_ostream module_macros_stream(module_macros); Target *target = exe_ctx.GetTargetPtr(); if (target) { @@ -313,10 +318,11 @@ bool ClangExpressionSourceCode::GetText( } } - ClangModulesDeclVendor *decl_vendor = target->GetClangModulesDeclVendor(); auto *persistent_vars = llvm::cast( target->GetPersistentExpressionStateForLanguage(lldb::eLanguageTypeC)); - if (decl_vendor && persistent_vars) { + std::shared_ptr decl_vendor = + persistent_vars->GetClangModulesDeclVendor(); + if (decl_vendor) { const ClangModulesDeclVendor::ModuleVector &hand_imported_modules = persistent_vars->GetHandLoadedClangModules(); ClangModulesDeclVendor::ModuleVector modules_for_macros; @@ -344,9 +350,13 @@ bool ClangExpressionSourceCode::GetText( decl_vendor->ForEachMacro( modules_for_macros, - [&module_macros](const std::string &expansion) -> bool { - module_macros.append(expansion); - module_macros.append("\n"); + [&module_macros_stream](llvm::StringRef token, + llvm::StringRef expansion) -> bool { + // Check if the macro hasn't already been defined in the + // g_expression_prefix (which defines a few builtin macros). + module_macros_stream << "#ifndef " << token << "\n"; + module_macros_stream << expansion << "\n"; + module_macros_stream << "#endif\n"; return false; }); } @@ -387,8 +397,8 @@ bool ClangExpressionSourceCode::GetText( StreamString wrap_stream; - wrap_stream.Printf("%s\n%s\n%s\n%s\n%s\n", module_macros.c_str(), - debug_macros_stream.GetData(), g_expression_prefix, + wrap_stream.Printf("%s\n%s\n%s\n%s\n%s\n", g_expression_prefix, + module_macros.c_str(), debug_macros_stream.GetData(), target_specific_defines, m_prefix.c_str()); // First construct a tagged form of the user expression so we can find it diff --git a/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.h b/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.h index 9a54f0e3ad8..54ae837fb30 100644 --- a/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.h +++ b/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.h @@ -27,6 +27,7 @@ public: /// the user expression. static const llvm::StringRef g_prefix_file_name; static const char *g_expression_prefix; + static const char *g_expression_suffix; /// The possible ways an expression can be wrapped. enum class WrapKind { diff --git a/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionVariable.h b/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionVariable.h index 58d589962ab..7bb68e78373 100644 --- a/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionVariable.h +++ b/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionVariable.h @@ -9,9 +9,9 @@ #ifndef LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGEXPRESSIONVARIABLE_H #define LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGEXPRESSIONVARIABLE_H -#include -#include -#include +#include +#include +#include #include #include @@ -116,19 +116,19 @@ public: /// The following values should not live beyond parsing class ParserVars { public: - ParserVars() - : m_named_decl(nullptr), m_llvm_value(nullptr), - m_lldb_value(), m_lldb_var(), m_lldb_sym(nullptr) {} - - const clang::NamedDecl - *m_named_decl; ///< The Decl corresponding to this variable - llvm::Value *m_llvm_value; ///< The IR value corresponding to this variable; - ///usually a GlobalValue + ParserVars() : m_lldb_value(), m_lldb_var() {} + + const clang::NamedDecl *m_named_decl = + nullptr; ///< The Decl corresponding to this variable + llvm::Value *m_llvm_value = + nullptr; ///< The IR value corresponding to this variable; + /// usually a GlobalValue lldb_private::Value m_lldb_value; ///< The value found in LLDB for this variable lldb::VariableSP m_lldb_var; ///< The original variable for this variable - const lldb_private::Symbol *m_lldb_sym; ///< The original symbol for this - ///variable, if it was a symbol + const lldb_private::Symbol *m_lldb_sym = + nullptr; ///< The original symbol for this + /// variable, if it was a symbol }; private: @@ -157,13 +157,13 @@ public: /// The following values are valid if the variable is used by JIT code struct JITVars { - JITVars() : m_alignment(0), m_size(0), m_offset(0) {} + JITVars() = default; - lldb::offset_t - m_alignment; ///< The required alignment of the variable, in bytes - size_t m_size; ///< The space required for the variable, in bytes - lldb::offset_t - m_offset; ///< The offset of the variable in the struct, in bytes + lldb::offset_t m_alignment = + 0; ///< The required alignment of the variable, in bytes + size_t m_size = 0; ///< The space required for the variable, in bytes + lldb::offset_t m_offset = + 0; ///< The offset of the variable in the struct, in bytes }; private: diff --git a/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.cpp b/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.cpp index 0c9ad202103..2cfa9a4c9cc 100644 --- a/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.cpp +++ b/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/ClangFunctionCaller.cpp @@ -59,7 +59,7 @@ ClangFunctionCaller::ClangFunctionCaller(ExecutionContextScope &exe_scope, } // Destructor -ClangFunctionCaller::~ClangFunctionCaller() {} +ClangFunctionCaller::~ClangFunctionCaller() = default; unsigned diff --git a/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/ClangHost.cpp b/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/ClangHost.cpp index 8abb7e42057..b76fa6fbf69 100644 --- a/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/ClangHost.cpp +++ b/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/ClangHost.cpp @@ -137,14 +137,12 @@ bool lldb_private::ComputeClangResourceDirectory(FileSpec &lldb_shlib_spec, FileSystem::Instance().Resolve(file_spec); return true; } - raw_path = lldb_shlib_spec.GetPath(); } - raw_path.resize(rev_it - r_end); - } else { - raw_path.resize(rev_it - r_end); } // Fall back to the Clang resource directory inside the framework. + raw_path = lldb_shlib_spec.GetPath(); + raw_path.resize(rev_it - r_end); raw_path.append("LLDB.framework/Resources/Clang"); file_spec.GetDirectory().SetString(raw_path.c_str()); FileSystem::Instance().Resolve(file_spec); diff --git a/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp b/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp index 95acb883774..336058a5abb 100644 --- a/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp +++ b/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp @@ -33,7 +33,7 @@ #include "lldb/Utility/FileSpec.h" #include "lldb/Utility/LLDBAssert.h" #include "lldb/Utility/Log.h" -#include "lldb/Utility/Reproducer.h" +#include "lldb/Utility/ReproducerProvider.h" #include "lldb/Utility/StreamString.h" #include @@ -42,9 +42,9 @@ using namespace lldb_private; namespace { -// Any Clang compiler requires a consumer for diagnostics. This one stores -// them as strings so we can provide them to the user in case a module failed -// to load. +/// Any Clang compiler requires a consumer for diagnostics. This one stores +/// them as strings so we can provide them to the user in case a module failed +/// to load. class StoringDiagnosticConsumer : public clang::DiagnosticConsumer { public: StoringDiagnosticConsumer(); @@ -74,8 +74,8 @@ private: Log *m_log; }; -// The private implementation of our ClangModulesDeclVendor. Contains all the -// Clang state required to load modules. +/// The private implementation of our ClangModulesDeclVendor. Contains all the +/// Clang state required to load modules. class ClangModulesDeclVendorImpl : public ClangModulesDeclVendor { public: ClangModulesDeclVendorImpl( @@ -95,12 +95,14 @@ public: uint32_t FindDecls(ConstString name, bool append, uint32_t max_matches, std::vector &decls) override; - void ForEachMacro(const ModuleVector &modules, - std::function handler) override; + void ForEachMacro( + const ModuleVector &modules, + std::function handler) override; + private: - void - ReportModuleExportsHelper(std::set &exports, - clang::Module *module); + typedef llvm::DenseSet ExportedModuleSet; + void ReportModuleExportsHelper(ExportedModuleSet &exports, + clang::Module *module); void ReportModuleExports(ModuleVector &exports, clang::Module *module); @@ -118,7 +120,7 @@ private: typedef std::vector ImportedModule; typedef std::map ImportedModuleMap; - typedef std::set ImportedModuleSet; + typedef llvm::DenseSet ImportedModuleSet; ImportedModuleMap m_imported_modules; ImportedModuleSet m_user_imported_modules; // We assume that every ASTContext has an TypeSystemClang, so we also store @@ -174,7 +176,7 @@ void StoringDiagnosticConsumer::EndSourceFile() { ClangModulesDeclVendor::ClangModulesDeclVendor() : ClangDeclVendor(eClangModuleDeclVendor) {} -ClangModulesDeclVendor::~ClangModulesDeclVendor() {} +ClangModulesDeclVendor::~ClangModulesDeclVendor() = default; ClangModulesDeclVendorImpl::ClangModulesDeclVendorImpl( llvm::IntrusiveRefCntPtr diagnostics_engine, @@ -193,8 +195,7 @@ ClangModulesDeclVendorImpl::ClangModulesDeclVendorImpl( } void ClangModulesDeclVendorImpl::ReportModuleExportsHelper( - std::set &exports, - clang::Module *module) { + ExportedModuleSet &exports, clang::Module *module) { if (exports.count(reinterpret_cast(module))) return; @@ -204,20 +205,18 @@ void ClangModulesDeclVendorImpl::ReportModuleExportsHelper( module->getExportedModules(sub_exports); - for (clang::Module *module : sub_exports) { + for (clang::Module *module : sub_exports) ReportModuleExportsHelper(exports, module); - } } void ClangModulesDeclVendorImpl::ReportModuleExports( ClangModulesDeclVendor::ModuleVector &exports, clang::Module *module) { - std::set exports_set; + ExportedModuleSet exports_set; ReportModuleExportsHelper(exports_set, module); - for (ModuleID module : exports_set) { + for (ModuleID module : exports_set) exports.push_back(module); - } } bool ClangModulesDeclVendorImpl::AddModule(const SourceModule &module, @@ -235,17 +234,15 @@ bool ClangModulesDeclVendorImpl::AddModule(const SourceModule &module, std::vector imported_module; - for (ConstString path_component : module.path) { + for (ConstString path_component : module.path) imported_module.push_back(path_component); - } { ImportedModuleMap::iterator mi = m_imported_modules.find(imported_module); if (mi != m_imported_modules.end()) { - if (exported_modules) { + if (exported_modules) ReportModuleExports(*exported_modules, mi->second); - } return true; } } @@ -336,9 +333,8 @@ bool ClangModulesDeclVendorImpl::AddModule(const SourceModule &module, clang::Module *requested_module = DoGetModule(clang_path, true); if (requested_module != nullptr) { - if (exported_modules) { + if (exported_modules) ReportModuleExports(*exported_modules, requested_module); - } m_imported_modules[imported_module] = requested_module; @@ -386,9 +382,8 @@ uint32_t ClangModulesDeclVendorImpl::FindDecls(ConstString name, bool append, uint32_t max_matches, std::vector &decls) { - if (!m_enabled) { + if (!m_enabled) return 0; - } if (!append) decls.clear(); @@ -420,19 +415,17 @@ ClangModulesDeclVendorImpl::FindDecls(ConstString name, bool append, void ClangModulesDeclVendorImpl::ForEachMacro( const ClangModulesDeclVendor::ModuleVector &modules, - std::function handler) { - if (!m_enabled) { + std::function handler) { + if (!m_enabled) return; - } typedef std::map ModulePriorityMap; ModulePriorityMap module_priorities; ssize_t priority = 0; - for (ModuleID module : modules) { + for (ModuleID module : modules) module_priorities[module] = priority++; - } if (m_compiler_instance->getPreprocessor().getExternalSource()) { m_compiler_instance->getPreprocessor() @@ -453,9 +446,8 @@ void ClangModulesDeclVendorImpl::ForEachMacro( .getExternalIdentifierLookup()) { lookup->get(mi->first->getName()); } - if (!ii) { + if (!ii) ii = mi->first; - } } ssize_t found_priority = -1; @@ -490,7 +482,8 @@ void ClangModulesDeclVendorImpl::ForEachMacro( if (macro_info) { std::string macro_expansion = "#define "; - macro_expansion.append(mi->first->getName().str()); + llvm::StringRef macro_identifier = mi->first->getName(); + macro_expansion.append(macro_identifier.str()); { if (macro_info->isFunctionLike()) { @@ -501,24 +494,21 @@ void ClangModulesDeclVendorImpl::ForEachMacro( for (auto pi = macro_info->param_begin(), pe = macro_info->param_end(); pi != pe; ++pi) { - if (!first_arg) { + if (!first_arg) macro_expansion.append(", "); - } else { + else first_arg = false; - } macro_expansion.append((*pi)->getName().str()); } if (macro_info->isC99Varargs()) { - if (first_arg) { + if (first_arg) macro_expansion.append("..."); - } else { + else macro_expansion.append(", ..."); - } - } else if (macro_info->isGNUVarargs()) { + } else if (macro_info->isGNUVarargs()) macro_expansion.append("..."); - } macro_expansion.append(")"); } @@ -530,11 +520,10 @@ void ClangModulesDeclVendorImpl::ForEachMacro( for (clang::MacroInfo::tokens_iterator ti = macro_info->tokens_begin(), te = macro_info->tokens_end(); ti != te; ++ti) { - if (!first_token) { + if (!first_token) macro_expansion.append(" "); - } else { + else first_token = false; - } if (ti->isLiteral()) { if (const char *literal_data = ti->getLiteralData()) { @@ -575,7 +564,7 @@ void ClangModulesDeclVendorImpl::ForEachMacro( } } - if (handler(macro_expansion)) { + if (handler(macro_identifier, macro_expansion)) { return; } } @@ -715,7 +704,7 @@ ClangModulesDeclVendor::Create(Target &target) { if (!instance->hasTarget()) return nullptr; - instance->getTarget().adjust(instance->getLangOpts()); + instance->getTarget().adjust(*diagnostics_engine, instance->getLangOpts()); if (!action->BeginSourceFile(*instance, instance->getFrontendOpts().Inputs[0])) diff --git a/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.h b/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.h index f04d1b07f03..d820552a291 100644 --- a/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.h +++ b/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.h @@ -90,13 +90,13 @@ public: /// if module A #defines a macro and module B #undefs it. /// /// \param[in] handler - /// A function to call with the text of each #define (including the - /// #define directive). #undef directives are not included; we simply - /// elide any corresponding #define. If this function returns true, - /// we stop the iteration immediately. - virtual void - ForEachMacro(const ModuleVector &modules, - std::function handler) = 0; + /// A function to call with the identifier of this macro and the text of + /// each #define (including the #define directive). #undef directives are + /// not included; we simply elide any corresponding #define. If this + /// function returns true, we stop the iteration immediately. + virtual void ForEachMacro( + const ModuleVector &modules, + std::function handler) = 0; /// Query whether Clang supports modules for a particular language. /// LLDB uses this to decide whether to try to find the modules loaded diff --git a/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.cpp b/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.cpp index 42afac9edb0..13d6a37113b 100644 --- a/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.cpp +++ b/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.cpp @@ -8,6 +8,7 @@ #include "ClangPersistentVariables.h" #include "ClangASTImporter.h" +#include "ClangModulesDeclVendor.h" #include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/Value.h" @@ -23,8 +24,10 @@ using namespace lldb; using namespace lldb_private; -ClangPersistentVariables::ClangPersistentVariables() - : lldb_private::PersistentExpressionState(LLVMCastKind::eKindClang) {} +ClangPersistentVariables::ClangPersistentVariables( + std::shared_ptr target_sp) + : lldb_private::PersistentExpressionState(LLVMCastKind::eKindClang), + m_target_sp(target_sp) {} ExpressionVariableSP ClangPersistentVariables::CreatePersistentVariable( const lldb::ValueObjectSP &valobj_sp) { @@ -109,6 +112,15 @@ ClangPersistentVariables::GetClangASTImporter() { return m_ast_importer_sp; } +std::shared_ptr +ClangPersistentVariables::GetClangModulesDeclVendor() { + if (!m_modules_decl_vendor_sp) { + m_modules_decl_vendor_sp.reset( + ClangModulesDeclVendor::Create(*m_target_sp.get())); + } + return m_modules_decl_vendor_sp; +} + ConstString ClangPersistentVariables::GetNextPersistentVariableName(bool is_error) { llvm::SmallString<64> name; diff --git a/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.h b/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.h index f888b2d56e6..b8a359d05f7 100644 --- a/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.h +++ b/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/ClangPersistentVariables.h @@ -19,6 +19,8 @@ namespace lldb_private { class ClangASTImporter; +class ClangModulesDeclVendor; +class Target; class TypeSystemClang; /// \class ClangPersistentVariables ClangPersistentVariables.h @@ -30,7 +32,7 @@ class TypeSystemClang; /// 0-based counter for naming result variables. class ClangPersistentVariables : public PersistentExpressionState { public: - ClangPersistentVariables(); + ClangPersistentVariables(std::shared_ptr target_sp); ~ClangPersistentVariables() override = default; @@ -40,6 +42,7 @@ public: } std::shared_ptr GetClangASTImporter(); + std::shared_ptr GetClangModulesDeclVendor(); lldb::ExpressionVariableSP CreatePersistentVariable(const lldb::ValueObjectSP &valobj_sp) override; @@ -106,6 +109,8 @@ private: ///these are the highest- ///< priority source for macros. std::shared_ptr m_ast_importer_sp; + std::shared_ptr m_modules_decl_vendor_sp; + std::shared_ptr m_target_sp; }; } // namespace lldb_private diff --git a/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp b/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp index a28b4a7fb42..1b205b13113 100644 --- a/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp +++ b/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp @@ -8,7 +8,7 @@ #include "lldb/Host/Config.h" -#include +#include #if HAVE_SYS_TYPES_H #include #endif @@ -90,7 +90,7 @@ ClangUserExpression::ClangUserExpression( } } -ClangUserExpression::~ClangUserExpression() {} +ClangUserExpression::~ClangUserExpression() = default; void ClangUserExpression::ScanContext(ExecutionContext &exe_ctx, Status &err) { Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); @@ -349,10 +349,6 @@ bool ClangUserExpression::SetupPersistentState(DiagnosticManager &diagnostic_man static void SetupDeclVendor(ExecutionContext &exe_ctx, Target *target, DiagnosticManager &diagnostic_manager) { - ClangModulesDeclVendor *decl_vendor = target->GetClangModulesDeclVendor(); - if (!decl_vendor) - return; - if (!target->GetEnableAutoImportClangModules()) return; @@ -361,6 +357,11 @@ static void SetupDeclVendor(ExecutionContext &exe_ctx, Target *target, if (!persistent_state) return; + std::shared_ptr decl_vendor = + persistent_state->GetClangModulesDeclVendor(); + if (!decl_vendor) + return; + StackFrame *frame = exe_ctx.GetFramePtr(); if (!frame) return; @@ -417,7 +418,6 @@ void ClangUserExpression::CreateSourceCode( DiagnosticManager &diagnostic_manager, ExecutionContext &exe_ctx, std::vector modules_to_import, bool for_completion) { - m_filename = m_clang_state->GetNextExprFileName(); std::string prefix = m_expr_prefix; if (m_options.GetExecutionPolicy() == eExecutionPolicyTopLevel) { @@ -477,9 +477,6 @@ CppModuleConfiguration GetModuleConfig(lldb::LanguageType language, if (!target) return LogConfigError("No target"); - if (!target->GetEnableImportStdModule()) - return LogConfigError("Importing std module not enabled in settings"); - StackFrame *frame = exe_ctx.GetFramePtr(); if (!frame) return LogConfigError("No frame"); @@ -529,8 +526,6 @@ CppModuleConfiguration GetModuleConfig(lldb::LanguageType language, bool ClangUserExpression::PrepareForParsing( DiagnosticManager &diagnostic_manager, ExecutionContext &exe_ctx, bool for_completion) { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); - InstallContext(exe_ctx); if (!SetupPersistentState(diagnostic_manager, exe_ctx)) @@ -551,50 +546,20 @@ bool ClangUserExpression::PrepareForParsing( SetupDeclVendor(exe_ctx, m_target, diagnostic_manager); - CppModuleConfiguration module_config = GetModuleConfig(m_language, exe_ctx); - llvm::ArrayRef imported_modules = - module_config.GetImportedModules(); - m_imported_cpp_modules = !imported_modules.empty(); - m_include_directories = module_config.GetIncludeDirs(); + m_filename = m_clang_state->GetNextExprFileName(); - LLDB_LOG(log, "List of imported modules in expression: {0}", - llvm::make_range(imported_modules.begin(), imported_modules.end())); - LLDB_LOG(log, "List of include directories gathered for modules: {0}", - llvm::make_range(m_include_directories.begin(), - m_include_directories.end())); + if (m_target->GetImportStdModule() == eImportStdModuleTrue) + SetupCppModuleImports(exe_ctx); - CreateSourceCode(diagnostic_manager, exe_ctx, imported_modules, + CreateSourceCode(diagnostic_manager, exe_ctx, m_imported_cpp_modules, for_completion); return true; } -bool ClangUserExpression::Parse(DiagnosticManager &diagnostic_manager, - ExecutionContext &exe_ctx, - lldb_private::ExecutionPolicy execution_policy, - bool keep_result_in_memory, - bool generate_debug_info) { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); - - if (!PrepareForParsing(diagnostic_manager, exe_ctx, /*for_completion*/ false)) - return false; - - LLDB_LOGF(log, "Parsing the following code:\n%s", m_transformed_text.c_str()); - - //////////////////////////////////// - // Set up the target and compiler - // - - Target *target = exe_ctx.GetTargetPtr(); - - if (!target) { - diagnostic_manager.PutString(eDiagnosticSeverityError, "invalid target"); - return false; - } - - ////////////////////////// - // Parse the expression - // - +bool ClangUserExpression::TryParse( + DiagnosticManager &diagnostic_manager, ExecutionContextScope *exe_scope, + ExecutionContext &exe_ctx, lldb_private::ExecutionPolicy execution_policy, + bool keep_result_in_memory, bool generate_debug_info) { m_materializer_up = std::make_unique(); ResetDeclMap(exe_ctx, m_result_delegate, keep_result_in_memory); @@ -612,26 +577,16 @@ bool ClangUserExpression::Parse(DiagnosticManager &diagnostic_manager, DeclMap()->SetLookupsEnabled(true); } - Process *process = exe_ctx.GetProcessPtr(); - ExecutionContextScope *exe_scope = process; + m_parser = std::make_unique( + exe_scope, *this, generate_debug_info, m_include_directories, m_filename); - if (!exe_scope) - exe_scope = exe_ctx.GetTargetPtr(); - - // We use a shared pointer here so we can use the original parser - if it - // succeeds or the rewrite parser we might make if it fails. But the - // parser_sp will never be empty. - - ClangExpressionParser parser(exe_scope, *this, generate_debug_info, - m_include_directories, m_filename); - - unsigned num_errors = parser.Parse(diagnostic_manager); + unsigned num_errors = m_parser->Parse(diagnostic_manager); // Check here for FixItHints. If there are any try to apply the fixits and // set the fixed text in m_fixed_text before returning an error. if (num_errors) { if (diagnostic_manager.HasFixIts()) { - if (parser.RewriteExpression(diagnostic_manager)) { + if (m_parser->RewriteExpression(diagnostic_manager)) { size_t fixed_start; size_t fixed_end; m_fixed_text = diagnostic_manager.GetFixedExpression(); @@ -652,7 +607,7 @@ bool ClangUserExpression::Parse(DiagnosticManager &diagnostic_manager, // { - Status jit_error = parser.PrepareForExecution( + Status jit_error = m_parser->PrepareForExecution( m_jit_start_addr, m_jit_end_addr, m_execution_unit_sp, exe_ctx, m_can_interpret, execution_policy); @@ -666,10 +621,91 @@ bool ClangUserExpression::Parse(DiagnosticManager &diagnostic_manager, return false; } } + return true; +} + +void ClangUserExpression::SetupCppModuleImports(ExecutionContext &exe_ctx) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); + + CppModuleConfiguration module_config = GetModuleConfig(m_language, exe_ctx); + m_imported_cpp_modules = module_config.GetImportedModules(); + m_include_directories = module_config.GetIncludeDirs(); + + LLDB_LOG(log, "List of imported modules in expression: {0}", + llvm::make_range(m_imported_cpp_modules.begin(), + m_imported_cpp_modules.end())); + LLDB_LOG(log, "List of include directories gathered for modules: {0}", + llvm::make_range(m_include_directories.begin(), + m_include_directories.end())); +} + +static bool shouldRetryWithCppModule(Target &target, ExecutionPolicy exe_policy) { + // Top-level expression don't yet support importing C++ modules. + if (exe_policy == ExecutionPolicy::eExecutionPolicyTopLevel) + return false; + return target.GetImportStdModule() == eImportStdModuleFallback; +} + +bool ClangUserExpression::Parse(DiagnosticManager &diagnostic_manager, + ExecutionContext &exe_ctx, + lldb_private::ExecutionPolicy execution_policy, + bool keep_result_in_memory, + bool generate_debug_info) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); + + if (!PrepareForParsing(diagnostic_manager, exe_ctx, /*for_completion*/ false)) + return false; + + LLDB_LOGF(log, "Parsing the following code:\n%s", m_transformed_text.c_str()); + + //////////////////////////////////// + // Set up the target and compiler + // + + Target *target = exe_ctx.GetTargetPtr(); + + if (!target) { + diagnostic_manager.PutString(eDiagnosticSeverityError, "invalid target"); + return false; + } + + ////////////////////////// + // Parse the expression + // + + Process *process = exe_ctx.GetProcessPtr(); + ExecutionContextScope *exe_scope = process; + + if (!exe_scope) + exe_scope = exe_ctx.GetTargetPtr(); + + bool parse_success = TryParse(diagnostic_manager, exe_scope, exe_ctx, + execution_policy, keep_result_in_memory, + generate_debug_info); + // If the expression failed to parse, check if retrying parsing with a loaded + // C++ module is possible. + if (!parse_success && shouldRetryWithCppModule(*target, execution_policy)) { + // Load the loaded C++ modules. + SetupCppModuleImports(exe_ctx); + // If we did load any modules, then retry parsing. + if (!m_imported_cpp_modules.empty()) { + // The module imports are injected into the source code wrapper, + // so recreate those. + CreateSourceCode(diagnostic_manager, exe_ctx, m_imported_cpp_modules, + /*for_completion*/ false); + // Clear the error diagnostics from the previous parse attempt. + diagnostic_manager.Clear(); + parse_success = TryParse(diagnostic_manager, exe_scope, exe_ctx, + execution_policy, keep_result_in_memory, + generate_debug_info); + } + } + if (!parse_success) + return false; if (exe_ctx.GetProcessPtr() && execution_policy == eExecutionPolicyTopLevel) { Status static_init_error = - parser.RunStaticInitializers(m_execution_unit_sp, exe_ctx); + m_parser->RunStaticInitializers(m_execution_unit_sp, exe_ctx); if (!static_init_error.Success()) { const char *error_cstr = static_init_error.AsCString(); diff --git a/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h b/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h index f734069655e..b628f6debf6 100644 --- a/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h +++ b/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h @@ -168,12 +168,23 @@ public: lldb::ExpressionVariableSP GetResultAfterDematerialization(ExecutionContextScope *exe_scope) override; - bool DidImportCxxModules() const { return m_imported_cpp_modules; } + /// Returns true iff this expression is using any imported C++ modules. + bool DidImportCxxModules() const { return !m_imported_cpp_modules.empty(); } private: /// Populate m_in_cplusplus_method and m_in_objectivec_method based on the /// environment. + /// Contains the actual parsing implementation. + /// The parameter have the same meaning as in ClangUserExpression::Parse. + /// \see ClangUserExpression::Parse + bool TryParse(DiagnosticManager &diagnostic_manager, + ExecutionContextScope *exe_scope, ExecutionContext &exe_ctx, + lldb_private::ExecutionPolicy execution_policy, bool keep_result_in_memory, + bool generate_debug_info); + + void SetupCppModuleImports(ExecutionContext &exe_ctx); + void ScanContext(ExecutionContext &exe_ctx, lldb_private::Status &err) override; @@ -219,6 +230,8 @@ private: ResultDelegate m_result_delegate; ClangPersistentVariables *m_clang_state; std::unique_ptr m_source_code; + /// The parser instance we used to parse the expression. + std::unique_ptr m_parser; /// File name used for the expression. std::string m_filename; @@ -226,8 +239,9 @@ private: /// See the comment to `UserExpression::Evaluate` for details. ValueObject *m_ctx_obj; - /// True iff this expression explicitly imported C++ modules. - bool m_imported_cpp_modules = false; + /// A list of module names that should be imported when parsing. + /// \see CppModuleConfiguration::GetImportedModules + std::vector m_imported_cpp_modules; /// True if the expression parser should enforce the presence of a valid class /// pointer in order to generate the expression as a method. diff --git a/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.cpp b/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.cpp index 25ec982220a..a78116352c2 100644 --- a/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.cpp +++ b/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.cpp @@ -14,7 +14,7 @@ #include "ClangExpressionSourceCode.h" #include "ClangPersistentVariables.h" -#include +#include #if HAVE_SYS_TYPES_H #include #endif @@ -34,22 +34,38 @@ using namespace lldb_private; char ClangUtilityFunction::ID; -/// Constructor -/// -/// \param[in] text -/// The text of the function. Must be a full translation unit. -/// -/// \param[in] name -/// The name of the function, as used in the text. ClangUtilityFunction::ClangUtilityFunction(ExecutionContextScope &exe_scope, - const char *text, const char *name) - : UtilityFunction(exe_scope, text, name) { - m_function_text.assign(ClangExpressionSourceCode::g_expression_prefix); - if (text && text[0]) - m_function_text.append(text); + std::string text, std::string name, + bool enable_debugging) + : UtilityFunction( + exe_scope, + std::string(ClangExpressionSourceCode::g_expression_prefix) + text + + std::string(ClangExpressionSourceCode::g_expression_suffix), + std::move(name), enable_debugging) { + // Write the source code to a file so that LLDB's source manager can display + // it when debugging the code. + if (enable_debugging) { + int temp_fd = -1; + llvm::SmallString<128> result_path; + llvm::sys::fs::createTemporaryFile("lldb", "expr", temp_fd, result_path); + if (temp_fd != -1) { + lldb_private::NativeFile file(temp_fd, File::eOpenOptionWrite, true); + text = "#line 1 \"" + std::string(result_path) + "\"\n" + text; + size_t bytes_written = text.size(); + file.Write(text.c_str(), bytes_written); + if (bytes_written == text.size()) { + // If we successfully wrote the source to a temporary file, replace the + // function text with the next text containing the line directive. + m_function_text = + std::string(ClangExpressionSourceCode::g_expression_prefix) + text + + std::string(ClangExpressionSourceCode::g_expression_suffix); + } + file.Close(); + } + } } -ClangUtilityFunction::~ClangUtilityFunction() {} +ClangUtilityFunction::~ClangUtilityFunction() = default; /// Install the utility function into a process /// diff --git a/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.h b/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.h index 1f2dd5fdbec..b8a154b3bae 100644 --- a/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.h +++ b/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.h @@ -41,11 +41,42 @@ public: } static bool classof(const Expression *obj) { return obj->isA(&ID); } + /// Constructor + /// + /// \param[in] text + /// The text of the function. Must be a full translation unit. + /// + /// \param[in] name + /// The name of the function, as used in the text. + /// + /// \param[in] enable_debugging + /// Enable debugging of this function. + ClangUtilityFunction(ExecutionContextScope &exe_scope, std::string text, + std::string name, bool enable_debugging); + + ~ClangUtilityFunction() override; + + ExpressionTypeSystemHelper *GetTypeSystemHelper() override { + return &m_type_system_helper; + } + + ClangExpressionDeclMap *DeclMap() { return m_type_system_helper.DeclMap(); } + + void ResetDeclMap() { m_type_system_helper.ResetDeclMap(); } + + void ResetDeclMap(ExecutionContext &exe_ctx, bool keep_result_in_memory) { + m_type_system_helper.ResetDeclMap(exe_ctx, keep_result_in_memory); + } + + bool Install(DiagnosticManager &diagnostic_manager, + ExecutionContext &exe_ctx) override; + +private: class ClangUtilityFunctionHelper : public ClangExpressionHelper { public: - ClangUtilityFunctionHelper() {} + ClangUtilityFunctionHelper() = default; - ~ClangUtilityFunctionHelper() override {} + ~ClangUtilityFunctionHelper() override = default; /// Return the object that the parser should use when resolving external /// values. May be NULL if everything should be self-contained. @@ -58,7 +89,7 @@ public: void ResetDeclMap(ExecutionContext &exe_ctx, bool keep_result_in_memory); /// Return the object that the parser should allow to access ASTs. May be - /// NULL if the ASTs do not need to be transformed. + /// nullptr if the ASTs do not need to be transformed. /// /// \param[in] passthrough /// The ASTConsumer that the returned transformer should send @@ -71,37 +102,9 @@ public: private: std::unique_ptr m_expr_decl_map_up; }; - /// Constructor - /// - /// \param[in] text - /// The text of the function. Must be a full translation unit. - /// - /// \param[in] name - /// The name of the function, as used in the text. - ClangUtilityFunction(ExecutionContextScope &exe_scope, const char *text, - const char *name); - - ~ClangUtilityFunction() override; - - ExpressionTypeSystemHelper *GetTypeSystemHelper() override { - return &m_type_system_helper; - } - - ClangExpressionDeclMap *DeclMap() { return m_type_system_helper.DeclMap(); } - void ResetDeclMap() { m_type_system_helper.ResetDeclMap(); } - - void ResetDeclMap(ExecutionContext &exe_ctx, bool keep_result_in_memory) { - m_type_system_helper.ResetDeclMap(exe_ctx, keep_result_in_memory); - } - - bool Install(DiagnosticManager &diagnostic_manager, - ExecutionContext &exe_ctx) override; - -private: - ClangUtilityFunctionHelper m_type_system_helper; ///< The map to use when - ///parsing and materializing - ///the expression. + /// The map to use when parsing and materializing the expression. + ClangUtilityFunctionHelper m_type_system_helper; }; } // namespace lldb_private diff --git a/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/CppModuleConfiguration.cpp b/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/CppModuleConfiguration.cpp index f1272c67d20..ffab16b1682 100644 --- a/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/CppModuleConfiguration.cpp +++ b/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/CppModuleConfiguration.cpp @@ -38,9 +38,11 @@ bool CppModuleConfiguration::analyzeFile(const FileSpec &f) { // Check for /c++/vX/ that is used by libc++. static llvm::Regex libcpp_regex(R"regex(/c[+][+]/v[0-9]/)regex"); - if (libcpp_regex.match(f.GetPath())) { - // Strip away libc++'s /experimental directory if there is one. - posix_dir.consume_back("/experimental"); + // If the path is in the libc++ include directory use it as the found libc++ + // path. Ignore subdirectories such as /c++/v1/experimental as those don't + // need to be specified in the header search. + if (libcpp_regex.match(f.GetPath()) && + parent_path(posix_dir, Style::posix).endswith("c++")) { return m_std_inc.TrySet(posix_dir); } @@ -55,9 +57,38 @@ bool CppModuleConfiguration::analyzeFile(const FileSpec &f) { return true; } +/// Utility function for just appending two paths. +static std::string MakePath(llvm::StringRef lhs, llvm::StringRef rhs) { + llvm::SmallString<256> result(lhs); + llvm::sys::path::append(result, rhs); + return std::string(result); +} + bool CppModuleConfiguration::hasValidConfig() { - // We all these include directories to have a valid usable configuration. - return m_c_inc.Valid() && m_std_inc.Valid(); + // We need to have a C and C++ include dir for a valid configuration. + if (!m_c_inc.Valid() || !m_std_inc.Valid()) + return false; + + // Do some basic sanity checks on the directories that we don't activate + // the module when it's clear that it's not usable. + const std::vector files_to_check = { + // * Check that the C library contains at least one random C standard + // library header. + MakePath(m_c_inc.Get(), "stdio.h"), + // * Without a libc++ modulemap file we can't have a 'std' module that + // could be imported. + MakePath(m_std_inc.Get(), "module.modulemap"), + // * Check for a random libc++ header (vector in this case) that has to + // exist in a working libc++ setup. + MakePath(m_std_inc.Get(), "vector"), + }; + + for (llvm::StringRef file_to_check : files_to_check) { + if (!FileSystem::Instance().Exists(file_to_check)) + return false; + } + + return true; } CppModuleConfiguration::CppModuleConfiguration( @@ -76,7 +107,8 @@ CppModuleConfiguration::CppModuleConfiguration( m_resource_inc = std::string(resource_dir.str()); // This order matches the way Clang orders these directories. - m_include_dirs = {m_std_inc.Get(), m_resource_inc, m_c_inc.Get()}; + m_include_dirs = {m_std_inc.Get().str(), m_resource_inc, + m_c_inc.Get().str()}; m_imported_modules = {"std"}; } } diff --git a/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/CppModuleConfiguration.h b/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/CppModuleConfiguration.h index 235ac2bd090..425106bba0a 100644 --- a/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/CppModuleConfiguration.h +++ b/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/CppModuleConfiguration.h @@ -32,7 +32,7 @@ class CppModuleConfiguration { /// the path was already set. LLVM_NODISCARD bool TrySet(llvm::StringRef path); /// Return the path if there is one. - std::string Get() const { + llvm::StringRef Get() const { assert(m_valid && "Called Get() on an invalid SetOncePath?"); return m_path; } @@ -57,12 +57,9 @@ class CppModuleConfiguration { public: /// Creates a configuration by analyzing the given list of used source files. - /// - /// Currently only looks at the used paths and doesn't actually access the - /// files on the disk. explicit CppModuleConfiguration(const FileSpecList &support_files); /// Creates an empty and invalid configuration. - CppModuleConfiguration() {} + CppModuleConfiguration() = default; /// Returns true iff this is a valid configuration that can be used to /// load and compile modules. diff --git a/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/CxxModuleHandler.cpp b/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/CxxModuleHandler.cpp index 2f8cf1846ee..74dd04600b4 100644 --- a/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/CxxModuleHandler.cpp +++ b/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/CxxModuleHandler.cpp @@ -22,6 +22,7 @@ CxxModuleHandler::CxxModuleHandler(ASTImporter &importer, ASTContext *target) std::initializer_list supported_names = { // containers + "array", "deque", "forward_list", "list", @@ -32,8 +33,12 @@ CxxModuleHandler::CxxModuleHandler(ASTImporter &importer, ASTContext *target) "shared_ptr", "unique_ptr", "weak_ptr", + // iterator + "move_iterator", + "__wrap_iter", // utility "allocator", + "pair", }; m_supported_templates.insert(supported_names.begin(), supported_names.end()); } @@ -180,21 +185,21 @@ llvm::Optional CxxModuleHandler::tryInstantiateStdTemplate(Decl *d) { // If we don't have a template to instiantiate, then there is nothing to do. auto td = dyn_cast(d); if (!td) - return {}; + return llvm::None; // We only care about templates in the std namespace. if (!td->getDeclContext()->isStdNamespace()) - return {}; + return llvm::None; // We have a list of supported template names. - if (m_supported_templates.find(td->getName()) == m_supported_templates.end()) - return {}; + if (!m_supported_templates.contains(td->getName())) + return llvm::None; // Early check if we even support instantiating this template. We do this // before we import anything into the target AST. auto &foreign_args = td->getTemplateInstantiationArgs(); if (!templateArgsAreSupported(foreign_args.asArray())) - return {}; + return llvm::None; // Find the local DeclContext that corresponds to the DeclContext of our // decl we want to import. @@ -205,7 +210,7 @@ llvm::Optional CxxModuleHandler::tryInstantiateStdTemplate(Decl *d) { "Got error while searching equal local DeclContext for decl " "'{1}':\n{0}", td->getName()); - return {}; + return llvm::None; } // Look up the template in our local context. @@ -218,7 +223,7 @@ llvm::Optional CxxModuleHandler::tryInstantiateStdTemplate(Decl *d) { break; } if (!new_class_template) - return {}; + return llvm::None; // Import the foreign template arguments. llvm::SmallVector imported_args; @@ -230,7 +235,7 @@ llvm::Optional CxxModuleHandler::tryInstantiateStdTemplate(Decl *d) { llvm::Expected type = m_importer->Import(arg.getAsType()); if (!type) { LLDB_LOG_ERROR(log, type.takeError(), "Couldn't import type: {0}"); - return {}; + return llvm::None; } imported_args.push_back(TemplateArgument(*type)); break; @@ -241,7 +246,7 @@ llvm::Optional CxxModuleHandler::tryInstantiateStdTemplate(Decl *d) { m_importer->Import(arg.getIntegralType()); if (!type) { LLDB_LOG_ERROR(log, type.takeError(), "Couldn't import type: {0}"); - return {}; + return llvm::None; } imported_args.push_back( TemplateArgument(d->getASTContext(), integral, *type)); diff --git a/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/IRDynamicChecks.cpp b/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/IRDynamicChecks.cpp index b92f00ec2b6..a6e36d81b95 100644 --- a/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/IRDynamicChecks.cpp +++ b/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/IRDynamicChecks.cpp @@ -48,29 +48,27 @@ ClangDynamicCheckerFunctions::~ClangDynamicCheckerFunctions() = default; bool ClangDynamicCheckerFunctions::Install( DiagnosticManager &diagnostic_manager, ExecutionContext &exe_ctx) { - Status error; - m_valid_pointer_check.reset( - exe_ctx.GetTargetRef().GetUtilityFunctionForLanguage( - g_valid_pointer_check_text, lldb::eLanguageTypeC, - VALID_POINTER_CHECK_NAME, error)); - if (error.Fail()) + auto utility_fn_or_error = exe_ctx.GetTargetRef().CreateUtilityFunction( + g_valid_pointer_check_text, VALID_POINTER_CHECK_NAME, + lldb::eLanguageTypeC, exe_ctx); + if (!utility_fn_or_error) { + llvm::consumeError(utility_fn_or_error.takeError()); return false; + } + m_valid_pointer_check = std::move(*utility_fn_or_error); - if (!m_valid_pointer_check->Install(diagnostic_manager, exe_ctx)) - return false; - - Process *process = exe_ctx.GetProcessPtr(); - - if (process) { + if (Process *process = exe_ctx.GetProcessPtr()) { ObjCLanguageRuntime *objc_language_runtime = ObjCLanguageRuntime::Get(*process); if (objc_language_runtime) { - m_objc_object_check.reset(objc_language_runtime->CreateObjectChecker( - VALID_OBJC_OBJECT_CHECK_NAME)); - - if (!m_objc_object_check->Install(diagnostic_manager, exe_ctx)) + auto utility_fn_or_error = objc_language_runtime->CreateObjectChecker( + VALID_OBJC_OBJECT_CHECK_NAME, exe_ctx); + if (!utility_fn_or_error) { + llvm::consumeError(utility_fn_or_error.takeError()); return false; + } + m_objc_object_check = std::move(*utility_fn_or_error); } } diff --git a/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/IRForTarget.cpp b/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/IRForTarget.cpp index 8511e554509..5655d548ee3 100644 --- a/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/IRForTarget.cpp +++ b/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/IRForTarget.cpp @@ -14,6 +14,7 @@ #include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DataLayout.h" +#include "llvm/IR/Operator.h" #include "llvm/IR/InstrTypes.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/Intrinsics.h" @@ -41,14 +42,12 @@ using namespace llvm; -static char ID; - typedef SmallVector InstrList; IRForTarget::FunctionValueCache::FunctionValueCache(Maker const &maker) : m_maker(maker), m_values() {} -IRForTarget::FunctionValueCache::~FunctionValueCache() {} +IRForTarget::FunctionValueCache::~FunctionValueCache() = default; llvm::Value * IRForTarget::FunctionValueCache::GetValue(llvm::Function *function) { @@ -72,13 +71,9 @@ IRForTarget::IRForTarget(lldb_private::ClangExpressionDeclMap *decl_map, lldb_private::IRExecutionUnit &execution_unit, lldb_private::Stream &error_stream, const char *func_name) - : ModulePass(ID), m_resolve_vars(resolve_vars), m_func_name(func_name), - m_module(nullptr), m_decl_map(decl_map), - m_CFStringCreateWithBytes(nullptr), m_sel_registerName(nullptr), - m_objc_getClass(nullptr), m_intptr_ty(nullptr), - m_error_stream(error_stream), m_execution_unit(execution_unit), - m_result_store(nullptr), m_result_is_pointer(false), - m_reloc_placeholder(nullptr), + : m_resolve_vars(resolve_vars), m_func_name(func_name), + m_decl_map(decl_map), m_error_stream(error_stream), + m_execution_unit(execution_unit), m_entry_instruction_finder(FindEntryInstruction) {} /* Handy utility functions used at several places in the code */ @@ -105,8 +100,6 @@ static std::string PrintType(const llvm::Type *type, bool truncate = false) { return s; } -IRForTarget::~IRForTarget() {} - bool IRForTarget::FixFunctionLinkage(llvm::Function &llvm_function) { llvm_function.setLinkage(GlobalValue::ExternalLinkage); @@ -305,9 +298,7 @@ bool IRForTarget::CreateResultVariable(llvm::Function &llvm_function) { } lldb::TargetSP target_sp(m_execution_unit.GetTarget()); - lldb_private::ExecutionContext exe_ctx(target_sp, true); - llvm::Optional bit_size = - m_result_type.GetBitSize(exe_ctx.GetBestExecutionContextScope()); + llvm::Optional bit_size = m_result_type.GetBitSize(target_sp.get()); if (!bit_size) { lldb_private::StreamString type_desc_stream; m_result_type.DumpTypeDescription(&type_desc_stream); @@ -330,7 +321,8 @@ bool IRForTarget::CreateResultVariable(llvm::Function &llvm_function) { m_result_name = lldb_private::ConstString("$RESULT_NAME"); LLDB_LOG(log, "Creating a new result global: \"{0}\" with size {1}", - m_result_name, m_result_type.GetByteSize(nullptr).getValueOr(0)); + m_result_name, + m_result_type.GetByteSize(target_sp.get()).getValueOr(0)); // Construct a new result global and set up its metadata @@ -1242,10 +1234,12 @@ bool IRForTarget::MaybeHandleVariable(Value *llvm_value_ptr) { value_type = global_variable->getType(); } - llvm::Optional value_size = compiler_type.GetByteSize(nullptr); + auto *target = m_execution_unit.GetTarget().get(); + llvm::Optional value_size = compiler_type.GetByteSize(target); if (!value_size) return false; - llvm::Optional opt_alignment = compiler_type.GetTypeBitAlign(nullptr); + llvm::Optional opt_alignment = + compiler_type.GetTypeBitAlign(target); if (!opt_alignment) return false; lldb::offset_t value_alignment = (*opt_alignment + 7ull) / 8ull; @@ -1581,20 +1575,14 @@ bool IRForTarget::UnfoldConstant(Constant *old_constant, FunctionValueCache get_element_pointer_maker( [&value_maker, &entry_instruction_finder, old_constant, constant_expr](llvm::Function *function) -> llvm::Value * { - Value *ptr = constant_expr->getOperand(0); + auto *gep = cast(constant_expr); + Value *ptr = gep->getPointerOperand(); if (ptr == old_constant) ptr = value_maker.GetValue(function); std::vector index_vector; - - unsigned operand_index; - unsigned num_operands = constant_expr->getNumOperands(); - - for (operand_index = 1; operand_index < num_operands; - ++operand_index) { - Value *operand = constant_expr->getOperand(operand_index); - + for (Value *operand : gep->indices()) { if (operand == old_constant) operand = value_maker.GetValue(function); @@ -1604,7 +1592,7 @@ bool IRForTarget::UnfoldConstant(Constant *old_constant, ArrayRef indices(index_vector); return GetElementPtrInst::Create( - nullptr, ptr, indices, "", + gep->getSourceElementType(), ptr, indices, "", llvm::cast( entry_instruction_finder.GetValue(function))); }); @@ -1787,7 +1775,8 @@ bool IRForTarget::ReplaceVariables(Function &llvm_function) { ConstantInt *offset_int( ConstantInt::get(offset_type, offset, true)); GetElementPtrInst *get_element_ptr = GetElementPtrInst::Create( - nullptr, argument, offset_int, "", entry_instruction); + argument->getType()->getPointerElementType(), argument, + offset_int, "", entry_instruction); if (name == m_result_name && !m_result_is_pointer) { BitCastInst *bit_cast = new BitCastInst( @@ -2021,10 +2010,3 @@ bool IRForTarget::runOnModule(Module &llvm_module) { return true; } - -void IRForTarget::assignPassManager(PMStack &pass_mgr_stack, - PassManagerType pass_mgr_type) {} - -PassManagerType IRForTarget::getPotentialPassManagerType() const { - return PMT_ModulePassManager; -} diff --git a/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/IRForTarget.h b/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/IRForTarget.h index ebfc0cae626..5f212fa8f91 100644 --- a/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/IRForTarget.h +++ b/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/IRForTarget.h @@ -58,7 +58,7 @@ class IRMemoryMap; /// transformations to the IR which make it relocatable. These /// transformations are discussed in more detail next to their relevant /// functions. -class IRForTarget : public llvm::ModulePass { +class IRForTarget { public: enum class LookupResult { Success, Fail, Ignore }; @@ -87,9 +87,6 @@ public: lldb_private::Stream &error_stream, const char *func_name = "$__lldb_expr"); - /// Destructor - ~IRForTarget() override; - /// Run this IR transformer on a single module /// /// Implementation of the llvm::ModulePass::runOnModule() function. @@ -101,20 +98,7 @@ public: /// /// \return /// True on success; false otherwise - bool runOnModule(llvm::Module &llvm_module) override; - - /// Interface stub - /// - /// Implementation of the llvm::ModulePass::assignPassManager() function. - void assignPassManager(llvm::PMStack &pass_mgr_stack, - llvm::PassManagerType pass_mgr_type = - llvm::PMT_ModulePassManager) override; - - /// Returns PMT_ModulePassManager - /// - /// Implementation of the llvm::ModulePass::getPotentialPassManagerType() - /// function. - llvm::PassManagerType getPotentialPassManagerType() const override; + bool runOnModule(llvm::Module &llvm_module); private: /// Ensures that the current function's linkage is set to external. @@ -419,51 +403,46 @@ private: /// True on success; false otherwise bool ReplaceVariables(llvm::Function &llvm_function); - /// Flags - bool m_resolve_vars; ///< True if external variable references and persistent - ///variable references should be resolved - lldb_private::ConstString - m_func_name; ///< The name of the function to translate - lldb_private::ConstString - m_result_name; ///< The name of the result variable ($0, $1, ...) - lldb_private::TypeFromParser - m_result_type; ///< The type of the result variable. - llvm::Module *m_module; ///< The module being processed, or NULL if that has - ///not been determined yet. - std::unique_ptr m_target_data; ///< The target data for the - ///module being processed, or - ///NULL if there is no - ///module. - lldb_private::ClangExpressionDeclMap - *m_decl_map; ///< The DeclMap containing the Decls - llvm::FunctionCallee - m_CFStringCreateWithBytes; ///< The address of the function - /// CFStringCreateWithBytes, cast to the - /// appropriate function pointer type - llvm::FunctionCallee m_sel_registerName; ///< The address of the function - /// sel_registerName, cast to the - /// appropriate function pointer type - llvm::FunctionCallee m_objc_getClass; ///< The address of the function - /// objc_getClass, cast to the - /// appropriate function pointer type - llvm::IntegerType - *m_intptr_ty; ///< The type of an integer large enough to hold a pointer. - lldb_private::Stream - &m_error_stream; ///< The stream on which errors should be printed - lldb_private::IRExecutionUnit & - m_execution_unit; ///< The execution unit containing the IR being created. - - llvm::StoreInst *m_result_store; ///< If non-NULL, the store instruction that - ///writes to the result variable. If - /// m_has_side_effects is true, this is - /// NULL. - bool m_result_is_pointer; ///< True if the function's result in the AST is a - ///pointer (see comments in - /// ASTResultSynthesizer::SynthesizeBodyResult) - + /// True if external variable references and persistent variable references + /// should be resolved + bool m_resolve_vars; + /// The name of the function to translate + lldb_private::ConstString m_func_name; + /// The name of the result variable ($0, $1, ...) + lldb_private::ConstString m_result_name; + /// The type of the result variable. + lldb_private::TypeFromParser m_result_type; + /// The module being processed, or NULL if that has not been determined yet. + llvm::Module *m_module = nullptr; + /// The target data for the module being processed, or NULL if there is no + /// module. + std::unique_ptr m_target_data; + /// The DeclMap containing the Decls + lldb_private::ClangExpressionDeclMap *m_decl_map; + /// The address of the function CFStringCreateWithBytes, cast to the + /// appropriate function pointer type + llvm::FunctionCallee m_CFStringCreateWithBytes; + /// The address of the function sel_registerName, cast to the appropriate + /// function pointer type. + llvm::FunctionCallee m_sel_registerName; + /// The address of the function objc_getClass, cast to the appropriate + /// function pointer type. + llvm::FunctionCallee m_objc_getClass; + /// The type of an integer large enough to hold a pointer. + llvm::IntegerType *m_intptr_ty = nullptr; + /// The stream on which errors should be printed. + lldb_private::Stream &m_error_stream; + /// The execution unit containing the IR being created. + lldb_private::IRExecutionUnit &m_execution_unit; + /// If non-NULL, the store instruction that writes to the result variable. If + /// m_has_side_effects is true, this is NULL. + llvm::StoreInst *m_result_store = nullptr; + /// True if the function's result in the AST is a pointer (see comments in + /// ASTResultSynthesizer::SynthesizeBodyResult) + bool m_result_is_pointer = false; /// A placeholder that will be replaced by a pointer to the final location of /// the static allocation. - llvm::GlobalVariable *m_reloc_placeholder; + llvm::GlobalVariable *m_reloc_placeholder = nullptr; class FunctionValueCache { public: diff --git a/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/ModuleDependencyCollector.h b/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/ModuleDependencyCollector.h index b7b6640c481..4fe727460fd 100644 --- a/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/ModuleDependencyCollector.h +++ b/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/ModuleDependencyCollector.h @@ -18,7 +18,7 @@ class ModuleDependencyCollectorAdaptor : public clang::ModuleDependencyCollector { public: ModuleDependencyCollectorAdaptor( - std::shared_ptr file_collector) + std::shared_ptr file_collector) : clang::ModuleDependencyCollector(""), m_file_collector(file_collector) { } @@ -33,7 +33,7 @@ public: void writeFileMap() override {} private: - std::shared_ptr m_file_collector; + std::shared_ptr m_file_collector; }; } // namespace lldb_private diff --git a/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/NameSearchContext.cpp b/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/NameSearchContext.cpp index c1f88889f1d..829afa5ffce 100644 --- a/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/NameSearchContext.cpp +++ b/gnu/llvm/lldb/source/Plugins/ExpressionParser/Clang/NameSearchContext.cpp @@ -78,7 +78,8 @@ clang::NamedDecl *NameSearchContext::AddFunDecl(const CompilerType &type, clang::FunctionDecl *func_decl = FunctionDecl::Create( ast, context, SourceLocation(), SourceLocation(), decl_name, qual_type, nullptr, SC_Extern, isInlineSpecified, hasWrittenPrototype, - isConstexprSpecified ? CSK_constexpr : CSK_unspecified); + isConstexprSpecified ? ConstexprSpecKind::Constexpr + : ConstexprSpecKind::Unspecified); // We have to do more than just synthesize the FunctionDecl. We have to // synthesize ParmVarDecls for all of the FunctionDecl's arguments. To do diff --git a/gnu/llvm/lldb/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp b/gnu/llvm/lldb/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp index 555912780df..bf0bbdab740 100644 --- a/gnu/llvm/lldb/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp +++ b/gnu/llvm/lldb/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// -#include +#include #include "EmulateInstructionARM.h" #include "EmulationStateARM.h" diff --git a/gnu/llvm/lldb/source/Plugins/Instruction/ARM/EmulateInstructionARM.h b/gnu/llvm/lldb/source/Plugins/Instruction/ARM/EmulateInstructionARM.h index d15d80c97e3..dfd7c926dab 100644 --- a/gnu/llvm/lldb/source/Plugins/Instruction/ARM/EmulateInstructionARM.h +++ b/gnu/llvm/lldb/source/Plugins/Instruction/ARM/EmulateInstructionARM.h @@ -19,8 +19,8 @@ namespace lldb_private { // ITSession - Keep track of the IT Block progression. class ITSession { public: - ITSession() : ITCounter(0), ITState(0) {} - ~ITSession() {} + ITSession() = default; + ~ITSession() = default; // InitIT - Initializes ITCounter/ITState. bool InitIT(uint32_t bits7_0); @@ -39,8 +39,8 @@ public: uint32_t GetCond(); private: - uint32_t ITCounter; // Possible values: 0, 1, 2, 3, 4. - uint32_t ITState; // A2.5.2 Consists of IT[7:5] and IT[4:0] initially. + uint32_t ITCounter = 0; // Possible values: 0, 1, 2, 3, 4. + uint32_t ITState = 0; // A2.5.2 Consists of IT[7:5] and IT[4:0] initially. }; class EmulateInstructionARM : public EmulateInstruction { diff --git a/gnu/llvm/lldb/source/Plugins/Instruction/ARM/EmulationStateARM.cpp b/gnu/llvm/lldb/source/Plugins/Instruction/ARM/EmulationStateARM.cpp index aef08baa8ae..569482c7b23 100644 --- a/gnu/llvm/lldb/source/Plugins/Instruction/ARM/EmulationStateARM.cpp +++ b/gnu/llvm/lldb/source/Plugins/Instruction/ARM/EmulationStateARM.cpp @@ -20,11 +20,11 @@ using namespace lldb; using namespace lldb_private; -EmulationStateARM::EmulationStateARM() : m_gpr(), m_vfp_regs(), m_memory() { +EmulationStateARM::EmulationStateARM() : m_vfp_regs(), m_memory() { ClearPseudoRegisters(); } -EmulationStateARM::~EmulationStateARM() {} +EmulationStateARM::~EmulationStateARM() = default; bool EmulationStateARM::LoadPseudoRegistersFromFrame(StackFrame &frame) { RegisterContext *reg_ctx = frame.GetRegisterContext().get(); diff --git a/gnu/llvm/lldb/source/Plugins/Instruction/ARM/EmulationStateARM.h b/gnu/llvm/lldb/source/Plugins/Instruction/ARM/EmulationStateARM.h index 955c7c64205..28bc5d98649 100644 --- a/gnu/llvm/lldb/source/Plugins/Instruction/ARM/EmulationStateARM.h +++ b/gnu/llvm/lldb/source/Plugins/Instruction/ARM/EmulationStateARM.h @@ -61,7 +61,7 @@ public: const lldb_private::RegisterValue ®_value); private: - uint32_t m_gpr[17]; + uint32_t m_gpr[17] = {0}; struct _sd_regs { uint32_t s_regs[32]; // sregs 0 - 31 & dregs 0 - 15 diff --git a/gnu/llvm/lldb/source/Plugins/Instruction/MIPS/EmulateInstructionMIPS.cpp b/gnu/llvm/lldb/source/Plugins/Instruction/MIPS/EmulateInstructionMIPS.cpp index d4cb726fc7e..a1a93c0b5a5 100644 --- a/gnu/llvm/lldb/source/Plugins/Instruction/MIPS/EmulateInstructionMIPS.cpp +++ b/gnu/llvm/lldb/source/Plugins/Instruction/MIPS/EmulateInstructionMIPS.cpp @@ -8,7 +8,7 @@ #include "EmulateInstructionMIPS.h" -#include +#include #include "lldb/Core/Address.h" #include "lldb/Core/Opcode.h" @@ -159,8 +159,8 @@ EmulateInstructionMIPS::EmulateInstructionMIPS( target->createMCSubtargetInfo(triple.getTriple(), cpu, features)); assert(m_asm_info.get() && m_subtype_info.get()); - m_context = std::make_unique(m_asm_info.get(), - m_reg_info.get(), nullptr); + m_context = std::make_unique( + triple, m_asm_info.get(), m_reg_info.get(), m_subtype_info.get()); assert(m_context.get()); m_disasm.reset(target->createMCDisassembler(*m_subtype_info, *m_context)); @@ -1018,8 +1018,9 @@ bool EmulateInstructionMIPS::SetInstruction(const Opcode &insn_opcode, const size_t bytes_read = target->ReadMemory(next_addr, /* Address of next instruction */ - true, /* prefer_file_cache */ - buf, sizeof(uint32_t), error, &load_addr); + buf, sizeof(uint32_t), error, + false, /* force_live_memory */ + &load_addr); if (bytes_read == 0) return true; diff --git a/gnu/llvm/lldb/source/Plugins/Instruction/MIPS64/EmulateInstructionMIPS64.cpp b/gnu/llvm/lldb/source/Plugins/Instruction/MIPS64/EmulateInstructionMIPS64.cpp index 4ccaf0de075..6044d00c0cb 100644 --- a/gnu/llvm/lldb/source/Plugins/Instruction/MIPS64/EmulateInstructionMIPS64.cpp +++ b/gnu/llvm/lldb/source/Plugins/Instruction/MIPS64/EmulateInstructionMIPS64.cpp @@ -8,7 +8,7 @@ #include "EmulateInstructionMIPS64.h" -#include +#include #include "lldb/Core/Address.h" #include "lldb/Core/Opcode.h" @@ -163,8 +163,8 @@ EmulateInstructionMIPS64::EmulateInstructionMIPS64( target->createMCSubtargetInfo(triple.getTriple(), cpu, features)); assert(m_asm_info.get() && m_subtype_info.get()); - m_context = std::make_unique(m_asm_info.get(), - m_reg_info.get(), nullptr); + m_context = std::make_unique( + triple, m_asm_info.get(), m_reg_info.get(), m_subtype_info.get()); assert(m_context.get()); m_disasm.reset(target->createMCDisassembler(*m_subtype_info, *m_context)); diff --git a/gnu/llvm/lldb/source/Plugins/Instruction/PPC64/EmulateInstructionPPC64.cpp b/gnu/llvm/lldb/source/Plugins/Instruction/PPC64/EmulateInstructionPPC64.cpp index 5d97513c0be..4e78c369c12 100644 --- a/gnu/llvm/lldb/source/Plugins/Instruction/PPC64/EmulateInstructionPPC64.cpp +++ b/gnu/llvm/lldb/source/Plugins/Instruction/PPC64/EmulateInstructionPPC64.cpp @@ -8,7 +8,7 @@ #include "EmulateInstructionPPC64.h" -#include +#include #include "lldb/Core/PluginManager.h" #include "lldb/Symbol/UnwindPlan.h" diff --git a/gnu/llvm/lldb/source/Plugins/InstrumentationRuntime/MainThreadChecker/InstrumentationRuntimeMainThreadChecker.cpp b/gnu/llvm/lldb/source/Plugins/InstrumentationRuntime/MainThreadChecker/InstrumentationRuntimeMainThreadChecker.cpp index 72d28c34745..9a88b343878 100644 --- a/gnu/llvm/lldb/source/Plugins/InstrumentationRuntime/MainThreadChecker/InstrumentationRuntimeMainThreadChecker.cpp +++ b/gnu/llvm/lldb/source/Plugins/InstrumentationRuntime/MainThreadChecker/InstrumentationRuntimeMainThreadChecker.cpp @@ -114,7 +114,7 @@ InstrumentationRuntimeMainThreadChecker::RetrieveReportData( std::string className = ""; std::string selector = ""; if (apiName.substr(0, 2) == "-[") { - size_t spacePos = apiName.find(" "); + size_t spacePos = apiName.find(' '); if (spacePos != std::string::npos) { className = apiName.substr(2, spacePos - 2); selector = apiName.substr(spacePos + 1, apiName.length() - spacePos - 2); @@ -127,7 +127,7 @@ InstrumentationRuntimeMainThreadChecker::RetrieveReportData( StackFrameSP responsible_frame; for (unsigned I = 0; I < thread_sp->GetStackFrameCount(); ++I) { StackFrameSP frame = thread_sp->GetStackFrameAtIndex(I); - Address addr = frame->GetFrameCodeAddress(); + Address addr = frame->GetFrameCodeAddressForSymbolication(); if (addr.GetModule() == runtime_module_sp) // Skip PCs from the runtime. continue; @@ -135,11 +135,6 @@ InstrumentationRuntimeMainThreadChecker::RetrieveReportData( if (!responsible_frame) responsible_frame = frame; - // First frame in stacktrace should point to a real PC, not return address. - if (I != 0 && trace->GetSize() == 0) { - addr.Slide(-1); - } - lldb::addr_t PC = addr.GetLoadAddress(&target); trace->AddItem(StructuredData::ObjectSP(new StructuredData::Integer(PC))); } @@ -271,8 +266,11 @@ InstrumentationRuntimeMainThreadChecker::GetBacktracesFromExtendedStopInfo( info->GetObjectForDotSeparatedPath("tid"); tid_t tid = thread_id_obj ? thread_id_obj->GetIntegerValue() : 0; - HistoryThread *history_thread = new HistoryThread(*process_sp, tid, PCs); - ThreadSP new_thread_sp(history_thread); + // We gather symbolication addresses above, so no need for HistoryThread to + // try to infer the call addresses. + bool pcs_are_call_addresses = true; + ThreadSP new_thread_sp = std::make_shared( + *process_sp, tid, PCs, pcs_are_call_addresses); // Save this in the Process' ExtendedThreadList so a strong pointer retains // the object diff --git a/gnu/llvm/lldb/source/Plugins/InstrumentationRuntime/TSan/InstrumentationRuntimeTSan.cpp b/gnu/llvm/lldb/source/Plugins/InstrumentationRuntime/TSan/InstrumentationRuntimeTSan.cpp index 50f0faefa0f..a2954f556b1 100644 --- a/gnu/llvm/lldb/source/Plugins/InstrumentationRuntime/TSan/InstrumentationRuntimeTSan.cpp +++ b/gnu/llvm/lldb/source/Plugins/InstrumentationRuntime/TSan/InstrumentationRuntimeTSan.cpp @@ -809,7 +809,9 @@ bool InstrumentationRuntimeTSan::NotifyBreakpointHit( StructuredData::ObjectSP report = instance->RetrieveReportData(context->exe_ctx_ref); - std::string stop_reason_description; + std::string stop_reason_description = + "unknown thread sanitizer fault (unable to extract thread sanitizer " + "report)"; if (report) { std::string issue_description = instance->FormatDescription(report); report->GetAsDictionary()->AddStringItem("description", issue_description); diff --git a/gnu/llvm/lldb/source/Plugins/InstrumentationRuntime/UBSan/InstrumentationRuntimeUBSan.cpp b/gnu/llvm/lldb/source/Plugins/InstrumentationRuntime/UBSan/InstrumentationRuntimeUBSan.cpp index b60eb53f3d4..58bc38a551f 100644 --- a/gnu/llvm/lldb/source/Plugins/InstrumentationRuntime/UBSan/InstrumentationRuntimeUBSan.cpp +++ b/gnu/llvm/lldb/source/Plugins/InstrumentationRuntime/UBSan/InstrumentationRuntimeUBSan.cpp @@ -29,7 +29,7 @@ #include "lldb/Target/Thread.h" #include "lldb/Utility/RegularExpression.h" #include "lldb/Utility/Stream.h" -#include +#include #include @@ -150,8 +150,8 @@ StructuredData::ObjectSP InstrumentationRuntimeUBSan::RetrieveReportData( StructuredData::Array *trace = new StructuredData::Array(); auto trace_sp = StructuredData::ObjectSP(trace); for (unsigned I = 0; I < thread_sp->GetStackFrameCount(); ++I) { - const Address FCA = - thread_sp->GetStackFrameAtIndex(I)->GetFrameCodeAddress(); + const Address FCA = thread_sp->GetStackFrameAtIndex(I) + ->GetFrameCodeAddressForSymbolication(); if (FCA.GetModule() == runtime_module_sp) // Skip PCs from the runtime. continue; @@ -324,8 +324,11 @@ InstrumentationRuntimeUBSan::GetBacktracesFromExtendedStopInfo( info->GetObjectForDotSeparatedPath("tid"); tid_t tid = thread_id_obj ? thread_id_obj->GetIntegerValue() : 0; - HistoryThread *history_thread = new HistoryThread(*process_sp, tid, PCs); - ThreadSP new_thread_sp(history_thread); + // We gather symbolication addresses above, so no need for HistoryThread to + // try to infer the call addresses. + bool pcs_are_call_addresses = true; + ThreadSP new_thread_sp = std::make_shared( + *process_sp, tid, PCs, pcs_are_call_addresses); std::string stop_reason_description = GetStopReasonDescription(info); new_thread_sp->SetName(stop_reason_description.c_str()); diff --git a/gnu/llvm/lldb/source/Plugins/JITLoader/GDB/JITLoaderGDB.cpp b/gnu/llvm/lldb/source/Plugins/JITLoader/GDB/JITLoaderGDB.cpp index cbeef600ba9..16c474fdbf3 100644 --- a/gnu/llvm/lldb/source/Plugins/JITLoader/GDB/JITLoaderGDB.cpp +++ b/gnu/llvm/lldb/source/Plugins/JITLoader/GDB/JITLoaderGDB.cpp @@ -291,8 +291,8 @@ bool JITLoaderGDB::ReadJITDescriptorImpl(bool all_entries) { jit_descriptor jit_desc; const size_t jit_desc_size = sizeof(jit_desc); Status error; - size_t bytes_read = m_process->DoReadMemory(m_jit_descriptor_addr, &jit_desc, - jit_desc_size, error); + size_t bytes_read = m_process->ReadMemory(m_jit_descriptor_addr, &jit_desc, + jit_desc_size, error); if (bytes_read != jit_desc_size || !error.Success()) { LLDB_LOGF(log, "JITLoaderGDB::%s failed to read JIT descriptor", __FUNCTION__); diff --git a/gnu/llvm/lldb/source/Plugins/Language/CPlusPlus/BlockPointer.cpp b/gnu/llvm/lldb/source/Plugins/Language/CPlusPlus/BlockPointer.cpp index 42f6bd9ffb7..1c498a2ddc1 100644 --- a/gnu/llvm/lldb/source/Plugins/Language/CPlusPlus/BlockPointer.cpp +++ b/gnu/llvm/lldb/source/Plugins/Language/CPlusPlus/BlockPointer.cpp @@ -50,11 +50,7 @@ public: } TypeSystemClang *clang_ast_context = - llvm::dyn_cast(&type_system_or_err.get()); - - if (!clang_ast_context) { - return; - } + llvm::cast(block_pointer_type.GetTypeSystem()); std::shared_ptr clang_ast_importer; auto *state = target_sp->GetPersistentExpressionStateForLanguage( @@ -78,14 +74,12 @@ public: const CompilerType reserved_type = clang_ast_context->GetBasicType(lldb::eBasicTypeInt); const char *const FuncPtr_name("__FuncPtr"); - const CompilerType FuncPtr_type = - clang_ast_importer->CopyType(*clang_ast_context, function_pointer_type); m_block_struct_type = clang_ast_context->CreateStructForIdentifier( ConstString(), {{isa_name, isa_type}, {flags_name, flags_type}, {reserved_name, reserved_type}, - {FuncPtr_name, FuncPtr_type}}); + {FuncPtr_name, function_pointer_type}}); } ~BlockPointerSyntheticFrontEnd() override = default; diff --git a/gnu/llvm/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp b/gnu/llvm/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp index 08e43ae6b3e..895fd55f499 100644 --- a/gnu/llvm/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp +++ b/gnu/llvm/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp @@ -59,6 +59,11 @@ lldb_private::ConstString CPlusPlusLanguage::GetPluginNameStatic() { return g_name; } +bool CPlusPlusLanguage::SymbolNameFitsToLanguage(Mangled mangled) const { + const char *mangled_name = mangled.GetMangledName().GetCString(); + return mangled_name && CPlusPlusLanguage::IsCPPMangledName(mangled_name); +} + // PluginInterface protocol lldb_private::ConstString CPlusPlusLanguage::GetPluginName() { @@ -601,8 +606,7 @@ static void LoadLibCxxFormatters(lldb::TypeCategoryImplSP cpp_category_sp) { ConstString("^std::__[[:alnum:]]+::atomic<.+>$"), stl_synth_flags, true); cpp_category_sp->GetRegexTypeSyntheticsContainer()->Add( - RegularExpression( - llvm::StringRef("^(std::__[[:alnum:]]+::)deque<.+>(( )?&)?$")), + RegularExpression("^(std::__[[:alnum:]]+::)deque<.+>(( )?&)?$"), SyntheticChildrenSP(new ScriptedSyntheticChildren( stl_synth_flags, "lldb.formatters.cpp.libcxx.stddeque_SynthProvider"))); @@ -823,32 +827,32 @@ static void LoadLibStdcppFormatters(lldb::TypeCategoryImplSP cpp_category_sp) { false); cpp_category_sp->GetRegexTypeSyntheticsContainer()->Add( - RegularExpression(llvm::StringRef("^std::vector<.+>(( )?&)?$")), + RegularExpression("^std::vector<.+>(( )?&)?$"), SyntheticChildrenSP(new ScriptedSyntheticChildren( stl_synth_flags, "lldb.formatters.cpp.gnu_libstdcpp.StdVectorSynthProvider"))); cpp_category_sp->GetRegexTypeSyntheticsContainer()->Add( - RegularExpression(llvm::StringRef("^std::map<.+> >(( )?&)?$")), + RegularExpression("^std::map<.+> >(( )?&)?$"), SyntheticChildrenSP(new ScriptedSyntheticChildren( stl_synth_flags, "lldb.formatters.cpp.gnu_libstdcpp.StdMapSynthProvider"))); cpp_category_sp->GetRegexTypeSyntheticsContainer()->Add( - RegularExpression(llvm::StringRef("^std::(__cxx11::)?list<.+>(( )?&)?$")), + RegularExpression("^std::(__cxx11::)?list<.+>(( )?&)?$"), SyntheticChildrenSP(new ScriptedSyntheticChildren( stl_synth_flags, "lldb.formatters.cpp.gnu_libstdcpp.StdListSynthProvider"))); stl_summary_flags.SetDontShowChildren(false); stl_summary_flags.SetSkipPointers(true); cpp_category_sp->GetRegexTypeSummariesContainer()->Add( - RegularExpression(llvm::StringRef("^std::vector<.+>(( )?&)?$")), + RegularExpression("^std::vector<.+>(( )?&)?$"), TypeSummaryImplSP( new StringSummaryFormat(stl_summary_flags, "size=${svar%#}"))); cpp_category_sp->GetRegexTypeSummariesContainer()->Add( - RegularExpression(llvm::StringRef("^std::map<.+> >(( )?&)?$")), + RegularExpression("^std::map<.+> >(( )?&)?$"), TypeSummaryImplSP( new StringSummaryFormat(stl_summary_flags, "size=${svar%#}"))); cpp_category_sp->GetRegexTypeSummariesContainer()->Add( - RegularExpression(llvm::StringRef("^std::(__cxx11::)?list<.+>(( )?&)?$")), + RegularExpression("^std::(__cxx11::)?list<.+>(( )?&)?$"), TypeSummaryImplSP( new StringSummaryFormat(stl_summary_flags, "size=${svar%#}"))); @@ -1055,7 +1059,7 @@ CPlusPlusLanguage::GetHardcodedSummaries() { .SetSkipReferences(false), lldb_private::formatters::VectorTypeSummaryProvider, "vector_type pointer summary provider")); - if (valobj.GetCompilerType().IsVectorType(nullptr, nullptr)) { + if (valobj.GetCompilerType().IsVectorType()) { if (fmt_mgr.GetCategory(g_vectortypes)->IsEnabled()) return formatter_sp; } @@ -1075,7 +1079,7 @@ CPlusPlusLanguage::GetHardcodedSummaries() { .SetSkipReferences(false), lldb_private::formatters::BlockPointerSummaryProvider, "block pointer summary provider")); - if (valobj.GetCompilerType().IsBlockPointerType(nullptr)) { + if (valobj.GetCompilerType().IsBlockPointerType()) { return formatter_sp; } return nullptr; @@ -1105,7 +1109,7 @@ CPlusPlusLanguage::GetHardcodedSynthetics() { .SetNonCacheable(true), "vector_type synthetic children", lldb_private::formatters::VectorTypeSyntheticFrontEndCreator)); - if (valobj.GetCompilerType().IsVectorType(nullptr, nullptr)) { + if (valobj.GetCompilerType().IsVectorType()) { if (fmt_mgr.GetCategory(g_vectortypes)->IsEnabled()) return formatter_sp; } @@ -1124,7 +1128,7 @@ CPlusPlusLanguage::GetHardcodedSynthetics() { .SetNonCacheable(true), "block pointer synthetic children", lldb_private::formatters::BlockPointerSyntheticFrontEndCreator)); - if (valobj.GetCompilerType().IsBlockPointerType(nullptr)) { + if (valobj.GetCompilerType().IsBlockPointerType()) { return formatter_sp; } return nullptr; @@ -1135,11 +1139,20 @@ CPlusPlusLanguage::GetHardcodedSynthetics() { return g_formatters; } +bool CPlusPlusLanguage::IsNilReference(ValueObject &valobj) { + if (!Language::LanguageIsCPlusPlus(valobj.GetObjectRuntimeLanguage()) || + !valobj.IsPointerType()) + return false; + bool canReadValue = true; + bool isZero = valobj.GetValueAsUnsigned(0, &canReadValue) == 0; + return canReadValue && isZero; +} + bool CPlusPlusLanguage::IsSourceFile(llvm::StringRef file_path) const { const auto suffixes = {".cpp", ".cxx", ".c++", ".cc", ".c", ".h", ".hh", ".hpp", ".hxx", ".h++"}; for (auto suffix : suffixes) { - if (file_path.endswith_lower(suffix)) + if (file_path.endswith_insensitive(suffix)) return true; } diff --git a/gnu/llvm/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h b/gnu/llvm/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h index 89dea08a2c5..9163be4807e 100644 --- a/gnu/llvm/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h +++ b/gnu/llvm/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.h @@ -28,8 +28,7 @@ public: class MethodName { public: MethodName() - : m_full(), m_basename(), m_context(), m_arguments(), m_qualifiers(), - m_parsed(false), m_parse_error(false) {} + : m_full(), m_basename(), m_context(), m_arguments(), m_qualifiers() {} MethodName(ConstString s) : m_full(s), m_basename(), m_context(), m_arguments(), m_qualifiers(), @@ -68,8 +67,8 @@ public: llvm::StringRef m_context; // Decl context: "lldb::SBTarget" llvm::StringRef m_arguments; // Arguments: "(unsigned int)" llvm::StringRef m_qualifiers; // Qualifiers: "const" - bool m_parsed; - bool m_parse_error; + bool m_parsed = false; + bool m_parse_error = false; }; CPlusPlusLanguage() = default; @@ -88,6 +87,10 @@ public: HardcodedFormatters::HardcodedSyntheticFinder GetHardcodedSynthetics() override; + bool IsNilReference(ValueObject &valobj) override; + + llvm::StringRef GetNilReferenceSummaryString() override { return "nullptr"; } + bool IsSourceFile(llvm::StringRef file_path) const override; const Highlighter *GetHighlighter() const override { return &m_highlighter; } @@ -101,6 +104,8 @@ public: static lldb_private::ConstString GetPluginNameStatic(); + bool SymbolNameFitsToLanguage(Mangled mangled) const override; + static bool IsCPPMangledName(llvm::StringRef name); // Extract C++ context and identifier from a string using heuristic matching diff --git a/gnu/llvm/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.h b/gnu/llvm/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.h index 6fe6b12725b..426434c4860 100644 --- a/gnu/llvm/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.h +++ b/gnu/llvm/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusNameParser.h @@ -69,7 +69,7 @@ private: size_t begin_index = 0; size_t end_index = 0; - Range() {} + Range() = default; Range(size_t begin, size_t end) : begin_index(begin), end_index(end) { assert(end >= begin); } diff --git a/gnu/llvm/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp b/gnu/llvm/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp index 84dd09a47d8..8eda422f314 100644 --- a/gnu/llvm/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp +++ b/gnu/llvm/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp @@ -379,8 +379,7 @@ lldb_private::formatters::LibCxxVectorIteratorSyntheticFrontEndCreator( lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd:: LibcxxSharedPtrSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp) - : SyntheticChildrenFrontEnd(*valobj_sp), m_cntrl(nullptr), m_count_sp(), - m_weak_count_sp(), m_ptr_size(0), m_byte_order(lldb::eByteOrderInvalid) { + : SyntheticChildrenFrontEnd(*valobj_sp), m_cntrl(nullptr) { if (valobj_sp) Update(); } @@ -403,42 +402,23 @@ lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd::GetChildAtIndex( if (idx == 0) return valobj_sp->GetChildMemberWithName(ConstString("__ptr_"), true); - if (idx > 2) - return lldb::ValueObjectSP(); - if (idx == 1) { - if (!m_count_sp) { - ValueObjectSP shared_owners_sp(m_cntrl->GetChildMemberWithName( - ConstString("__shared_owners_"), true)); - if (!shared_owners_sp) - return lldb::ValueObjectSP(); - uint64_t count = 1 + shared_owners_sp->GetValueAsUnsigned(0); - DataExtractor data(&count, 8, m_byte_order, m_ptr_size); - m_count_sp = CreateValueObjectFromData( - "count", data, valobj_sp->GetExecutionContextRef(), - shared_owners_sp->GetCompilerType()); - } - return m_count_sp; - } else /* if (idx == 2) */ - { - if (!m_weak_count_sp) { - ValueObjectSP shared_weak_owners_sp(m_cntrl->GetChildMemberWithName( - ConstString("__shared_weak_owners_"), true)); - if (!shared_weak_owners_sp) - return lldb::ValueObjectSP(); - uint64_t count = 1 + shared_weak_owners_sp->GetValueAsUnsigned(0); - DataExtractor data(&count, 8, m_byte_order, m_ptr_size); - m_weak_count_sp = CreateValueObjectFromData( - "count", data, valobj_sp->GetExecutionContextRef(), - shared_weak_owners_sp->GetCompilerType()); + if (auto ptr_sp = + valobj_sp->GetChildMemberWithName(ConstString("__ptr_"), true)) { + Status status; + auto value_sp = ptr_sp->Dereference(status); + if (status.Success()) { + auto value_type_sp = + valobj_sp->GetCompilerType().GetTypeTemplateArgument(0); + return value_sp->Cast(value_type_sp); + } } - return m_weak_count_sp; } + + return lldb::ValueObjectSP(); } bool lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd::Update() { - m_count_sp.reset(); - m_weak_count_sp.reset(); m_cntrl = nullptr; ValueObjectSP valobj_sp = m_backend.GetSP(); @@ -449,9 +429,6 @@ bool lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd::Update() { if (!target_sp) return false; - m_byte_order = target_sp->GetArchitecture().GetByteOrder(); - m_ptr_size = target_sp->GetArchitecture().GetAddressByteSize(); - lldb::ValueObjectSP cntrl_sp( valobj_sp->GetChildMemberWithName(ConstString("__cntrl_"), true)); @@ -469,10 +446,8 @@ size_t lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd:: GetIndexOfChildWithName(ConstString name) { if (name == "__ptr_") return 0; - if (name == "count") + if (name == "$$dereference$$") return 1; - if (name == "weak_count") - return 2; return UINT32_MAX; } @@ -488,7 +463,7 @@ lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEndCreator( lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd:: LibcxxUniquePtrSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp) - : SyntheticChildrenFrontEnd(*valobj_sp), m_compressed_pair_sp() { + : SyntheticChildrenFrontEnd(*valobj_sp) { if (valobj_sp) Update(); } @@ -505,19 +480,27 @@ lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEndCreator( size_t lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd:: CalculateNumChildren() { - return (m_compressed_pair_sp ? 1 : 0); + return (m_value_ptr_sp ? 1 : 0); } lldb::ValueObjectSP lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd::GetChildAtIndex( size_t idx) { - if (!m_compressed_pair_sp) + if (!m_value_ptr_sp) return lldb::ValueObjectSP(); - if (idx != 0) - return lldb::ValueObjectSP(); + if (idx == 0) + return m_value_ptr_sp; - return m_compressed_pair_sp; + if (idx == 1) { + Status status; + auto value_sp = m_value_ptr_sp->Dereference(status); + if (status.Success()) { + return value_sp; + } + } + + return lldb::ValueObjectSP(); } bool lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd::Update() { @@ -530,7 +513,7 @@ bool lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd::Update() { if (!ptr_sp) return false; - m_compressed_pair_sp = GetValueOfLibCXXCompressedPair(*ptr_sp); + m_value_ptr_sp = GetValueOfLibCXXCompressedPair(*ptr_sp); return false; } @@ -544,6 +527,8 @@ size_t lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd:: GetIndexOfChildWithName(ConstString name) { if (name == "__value_") return 0; + if (name == "$$dereference$$") + return 1; return UINT32_MAX; } @@ -692,7 +677,7 @@ bool lldb_private::formatters::LibcxxWStringSummaryProvider( // std::wstring::size() is measured in 'characters', not bytes TypeSystemClang *ast_context = - TypeSystemClang::GetScratch(*valobj.GetTargetSP()); + ScratchTypeSystemClang::GetForTarget(*valobj.GetTargetSP()); if (!ast_context) return false; diff --git a/gnu/llvm/lldb/source/Plugins/Language/CPlusPlus/LibCxx.h b/gnu/llvm/lldb/source/Plugins/Language/CPlusPlus/LibCxx.h index ea5a7c17817..99e20654319 100644 --- a/gnu/llvm/lldb/source/Plugins/Language/CPlusPlus/LibCxx.h +++ b/gnu/llvm/lldb/source/Plugins/Language/CPlusPlus/LibCxx.h @@ -105,10 +105,6 @@ public: private: ValueObject *m_cntrl; - lldb::ValueObjectSP m_count_sp; - lldb::ValueObjectSP m_weak_count_sp; - uint8_t m_ptr_size; - lldb::ByteOrder m_byte_order; }; class LibcxxUniquePtrSyntheticFrontEnd : public SyntheticChildrenFrontEnd { @@ -128,7 +124,7 @@ public: ~LibcxxUniquePtrSyntheticFrontEnd() override; private: - lldb::ValueObjectSP m_compressed_pair_sp; + lldb::ValueObjectSP m_value_ptr_sp; }; SyntheticChildrenFrontEnd * diff --git a/gnu/llvm/lldb/source/Plugins/Language/CPlusPlus/LibCxxBitset.cpp b/gnu/llvm/lldb/source/Plugins/Language/CPlusPlus/LibCxxBitset.cpp index 6de4637a6a4..e5b868fc0fc 100644 --- a/gnu/llvm/lldb/source/Plugins/Language/CPlusPlus/LibCxxBitset.cpp +++ b/gnu/llvm/lldb/source/Plugins/Language/CPlusPlus/LibCxxBitset.cpp @@ -85,7 +85,7 @@ ValueObjectSP BitsetFrontEnd::GetChildAtIndex(size_t idx) { CompilerType type; ValueObjectSP chunk; // For small bitsets __first_ is not an array, but a plain size_t. - if (m_first->GetCompilerType().IsArrayType(&type, nullptr, nullptr)) { + if (m_first->GetCompilerType().IsArrayType(&type)) { llvm::Optional bit_size = type.GetBitSize(ctx.GetBestExecutionContextScope()); if (!bit_size || *bit_size == 0) diff --git a/gnu/llvm/lldb/source/Plugins/Language/CPlusPlus/LibCxxList.cpp b/gnu/llvm/lldb/source/Plugins/Language/CPlusPlus/LibCxxList.cpp index 0d5ae16a0b2..47c6634ed65 100644 --- a/gnu/llvm/lldb/source/Plugins/Language/CPlusPlus/LibCxxList.cpp +++ b/gnu/llvm/lldb/source/Plugins/Language/CPlusPlus/LibCxxList.cpp @@ -27,8 +27,7 @@ namespace { class ListEntry { public: ListEntry() = default; - ListEntry(ValueObjectSP entry_sp) : m_entry_sp(entry_sp) {} - ListEntry(const ListEntry &rhs) = default; + ListEntry(ValueObjectSP entry_sp) : m_entry_sp(std::move(entry_sp)) {} ListEntry(ValueObject *entry) : m_entry_sp(entry ? entry->GetSP() : ValueObjectSP()) {} @@ -73,9 +72,8 @@ private: class ListIterator { public: ListIterator() = default; - ListIterator(ListEntry entry) : m_entry(entry) {} - ListIterator(ValueObjectSP entry) : m_entry(entry) {} - ListIterator(const ListIterator &rhs) = default; + ListIterator(ListEntry entry) : m_entry(std::move(entry)) {} + ListIterator(ValueObjectSP entry) : m_entry(std::move(entry)) {} ListIterator(ValueObject *entry) : m_entry(entry) {} ValueObjectSP value() { return m_entry.GetEntry(); } diff --git a/gnu/llvm/lldb/source/Plugins/Language/CPlusPlus/LibCxxMap.cpp b/gnu/llvm/lldb/source/Plugins/Language/CPlusPlus/LibCxxMap.cpp index 64a199e24e4..25c2bfd9387 100644 --- a/gnu/llvm/lldb/source/Plugins/Language/CPlusPlus/LibCxxMap.cpp +++ b/gnu/llvm/lldb/source/Plugins/Language/CPlusPlus/LibCxxMap.cpp @@ -26,7 +26,6 @@ class MapEntry { public: MapEntry() = default; explicit MapEntry(ValueObjectSP entry_sp) : m_entry_sp(entry_sp) {} - MapEntry(const MapEntry &rhs) = default; explicit MapEntry(ValueObject *entry) : m_entry_sp(entry ? entry->GetSP() : ValueObjectSP()) {} @@ -86,9 +85,9 @@ class MapIterator { public: MapIterator() = default; MapIterator(MapEntry entry, size_t depth = 0) - : m_entry(entry), m_max_depth(depth), m_error(false) {} + : m_entry(std::move(entry)), m_max_depth(depth), m_error(false) {} MapIterator(ValueObjectSP entry, size_t depth = 0) - : m_entry(entry), m_max_depth(depth), m_error(false) {} + : m_entry(std::move(entry)), m_max_depth(depth), m_error(false) {} MapIterator(const MapIterator &rhs) : m_entry(rhs.m_entry), m_max_depth(rhs.m_max_depth), m_error(false) {} MapIterator(ValueObject *entry, size_t depth = 0) @@ -138,7 +137,7 @@ protected: } private: - MapEntry tree_min(MapEntry &&x) { + MapEntry tree_min(MapEntry x) { if (x.null()) return MapEntry(); MapEntry left(x.left()); diff --git a/gnu/llvm/lldb/source/Plugins/Language/CPlusPlus/LibStdcppUniquePointer.cpp b/gnu/llvm/lldb/source/Plugins/Language/CPlusPlus/LibStdcppUniquePointer.cpp index 0b34b4e2fc8..79e864a2cbd 100644 --- a/gnu/llvm/lldb/source/Plugins/Language/CPlusPlus/LibStdcppUniquePointer.cpp +++ b/gnu/llvm/lldb/source/Plugins/Language/CPlusPlus/LibStdcppUniquePointer.cpp @@ -99,9 +99,17 @@ bool LibStdcppUniquePtrSyntheticFrontEnd::Update() { if (ptr_obj) m_ptr_obj = ptr_obj->Clone(ConstString("pointer")).get(); - ValueObjectSP del_obj = tuple_frontend->GetChildAtIndex(1); - if (del_obj) - m_del_obj = del_obj->Clone(ConstString("deleter")).get(); + // Add a 'deleter' child if there was a non-empty deleter type specified. + // + // The object might have size=1 in the TypeSystem but occupies no dedicated + // storage due to no_unique_address, so infer the actual size from the total + // size of the unique_ptr class. If sizeof(unique_ptr) == sizeof(void*) then + // the deleter is empty and should be hidden. + if (tuple_sp->GetByteSize() > ptr_obj->GetByteSize()) { + ValueObjectSP del_obj = tuple_frontend->GetChildAtIndex(1); + if (del_obj) + m_del_obj = del_obj->Clone(ConstString("deleter")).get(); + } if (m_ptr_obj) { Status error; diff --git a/gnu/llvm/lldb/source/Plugins/Language/ClangCommon/ClangHighlighter.cpp b/gnu/llvm/lldb/source/Plugins/Language/ClangCommon/ClangHighlighter.cpp index aaf578c6f72..fe6eeea54e4 100644 --- a/gnu/llvm/lldb/source/Plugins/Language/ClangCommon/ClangHighlighter.cpp +++ b/gnu/llvm/lldb/source/Plugins/Language/ClangCommon/ClangHighlighter.cpp @@ -168,7 +168,7 @@ void ClangHighlighter::Highlight(const HighlightStyle &options, clang::SourceManager SM(diags, file_mgr); auto buf = llvm::MemoryBuffer::getMemBuffer(full_source); - FileID FID = SM.createFileID(clang::SourceManager::Unowned, buf.get()); + FileID FID = SM.createFileID(buf->getMemBufferRef()); // Let's just enable the latest ObjC and C++ which should get most tokens // right. @@ -178,7 +178,7 @@ void ClangHighlighter::Highlight(const HighlightStyle &options, Opts.CPlusPlus17 = true; Opts.LineComment = true; - Lexer lex(FID, buf.get(), SM, Opts); + Lexer lex(FID, buf->getMemBufferRef(), SM, Opts); // The lexer should keep whitespace around. lex.SetKeepWhitespaceMode(true); diff --git a/gnu/llvm/lldb/source/Plugins/Language/ObjC/Cocoa.cpp b/gnu/llvm/lldb/source/Plugins/Language/ObjC/Cocoa.cpp index 648fc4adf24..1479f4f0c15 100644 --- a/gnu/llvm/lldb/source/Plugins/Language/ObjC/Cocoa.cpp +++ b/gnu/llvm/lldb/source/Plugins/Language/ObjC/Cocoa.cpp @@ -72,6 +72,9 @@ bool lldb_private::formatters::NSBundleSummaryProvider( valobj.GetCompilerType().GetBasicTypeFromAST(lldb::eBasicTypeObjCID), true)); + if (!text) + return false; + StreamString summary_stream; bool was_nsstring_ok = NSStringSummaryProvider(*text, summary_stream, options); @@ -117,6 +120,10 @@ bool lldb_private::formatters::NSTimeZoneSummaryProvider( uint64_t offset = ptr_size; ValueObjectSP text(valobj.GetSyntheticChildAtOffset( offset, valobj.GetCompilerType(), true)); + + if (!text) + return false; + StreamString summary_stream; bool was_nsstring_ok = NSStringSummaryProvider(*text, summary_stream, options); @@ -162,6 +169,10 @@ bool lldb_private::formatters::NSNotificationSummaryProvider( uint64_t offset = ptr_size; ValueObjectSP text(valobj.GetSyntheticChildAtOffset( offset, valobj.GetCompilerType(), true)); + + if (!text) + return false; + StreamString summary_stream; bool was_nsstring_ok = NSStringSummaryProvider(*text, summary_stream, options); @@ -340,7 +351,7 @@ static void NSNumber_FormatInt(ValueObject &valobj, Stream &stream, int value, } static void NSNumber_FormatLong(ValueObject &valobj, Stream &stream, - uint64_t value, lldb::LanguageType lang) { + int64_t value, lldb::LanguageType lang) { static ConstString g_TypeHint("NSNumber:long"); std::string prefix, suffix; @@ -356,10 +367,10 @@ static void NSNumber_FormatLong(ValueObject &valobj, Stream &stream, } static void NSNumber_FormatInt128(ValueObject &valobj, Stream &stream, - const llvm::APInt &value, - lldb::LanguageType lang) { + const llvm::APInt &value, + lldb::LanguageType lang) { static ConstString g_TypeHint("NSNumber:int128_t"); - + std::string prefix, suffix; if (Language *language = Language::FindPlugin(lang)) { if (!language->GetFormatterPrefixSuffix(valobj, g_TypeHint, prefix, @@ -368,11 +379,11 @@ static void NSNumber_FormatInt128(ValueObject &valobj, Stream &stream, suffix.clear(); } } - + stream.PutCString(prefix.c_str()); const int radix = 10; const bool isSigned = true; - std::string str = value.toString(radix, isSigned); + std::string str = llvm::toString(value, radix, isSigned); stream.PutCString(str.c_str()); stream.PutCString(suffix.c_str()); } @@ -415,6 +426,7 @@ bool lldb_private::formatters::NSNumberSummaryProvider( if (!process_sp) return false; + Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_DATAFORMATTERS); ObjCLanguageRuntime *runtime = ObjCLanguageRuntime::Get(*process_sp); if (!runtime) @@ -445,9 +457,18 @@ bool lldb_private::formatters::NSNumberSummaryProvider( return NSDecimalNumberSummaryProvider(valobj, stream, options); if (class_name == "NSNumber" || class_name == "__NSCFNumber") { - uint64_t value = 0; + int64_t value = 0; uint64_t i_bits = 0; - if (descriptor->GetTaggedPointerInfo(&i_bits, &value)) { + if (descriptor->GetTaggedPointerInfoSigned(&i_bits, &value)) { + // Check for "preserved" numbers. We still don't support them yet. + if (i_bits & 0x8) { + if (log) + log->Printf( + "Unsupported (preserved) NSNumber tagged pointer 0x%" PRIu64, + valobj_addr); + return false; + } + switch (i_bits) { case 0: NSNumber_FormatChar(valobj, stream, (char)value, options.GetLanguage()); @@ -487,49 +508,66 @@ bool lldb_private::formatters::NSNumberSummaryProvider( f64 = 0x5, sint128 = 0x6 }; - + uint64_t data_location = valobj_addr + 2 * ptr_size; TypeCodes type_code; - + if (new_format) { - uint64_t cfinfoa = - process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, - ptr_size, 0, error); - + uint64_t cfinfoa = process_sp->ReadUnsignedIntegerFromMemory( + valobj_addr + ptr_size, ptr_size, 0, error); + if (error.Fail()) return false; bool is_preserved_number = cfinfoa & 0x8; if (is_preserved_number) { - lldbassert(!static_cast("We should handle preserved numbers!")); + if (log) + log->Printf( + "Unsupported preserved NSNumber tagged pointer 0x%" PRIu64, + valobj_addr); return false; } type_code = static_cast(cfinfoa & 0x7); } else { - uint8_t data_type = - process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, 1, - 0, error) & 0x1F; - + uint8_t data_type = process_sp->ReadUnsignedIntegerFromMemory( + valobj_addr + ptr_size, 1, 0, error) & + 0x1F; + if (error.Fail()) return false; - + switch (data_type) { - case 1: type_code = TypeCodes::sint8; break; - case 2: type_code = TypeCodes::sint16; break; - case 3: type_code = TypeCodes::sint32; break; - case 17: data_location += 8; LLVM_FALLTHROUGH; - case 4: type_code = TypeCodes::sint64; break; - case 5: type_code = TypeCodes::f32; break; - case 6: type_code = TypeCodes::f64; break; - default: return false; + case 1: + type_code = TypeCodes::sint8; + break; + case 2: + type_code = TypeCodes::sint16; + break; + case 3: + type_code = TypeCodes::sint32; + break; + case 17: + data_location += 8; + LLVM_FALLTHROUGH; + case 4: + type_code = TypeCodes::sint64; + break; + case 5: + type_code = TypeCodes::f32; + break; + case 6: + type_code = TypeCodes::f64; + break; + default: + return false; } } - + uint64_t value = 0; bool success = false; switch (type_code) { - case TypeCodes::sint8: + case TypeCodes::sint8: value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 1, 0, error); if (error.Fail()) @@ -537,7 +575,7 @@ bool lldb_private::formatters::NSNumberSummaryProvider( NSNumber_FormatChar(valobj, stream, (char)value, options.GetLanguage()); success = true; break; - case TypeCodes::sint16: + case TypeCodes::sint16: value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 2, 0, error); if (error.Fail()) @@ -562,8 +600,7 @@ bool lldb_private::formatters::NSNumberSummaryProvider( NSNumber_FormatLong(valobj, stream, value, options.GetLanguage()); success = true; break; - case TypeCodes::f32: - { + case TypeCodes::f32: { uint32_t flt_as_int = process_sp->ReadUnsignedIntegerFromMemory( data_location, 4, 0, error); if (error.Fail()) @@ -574,8 +611,7 @@ bool lldb_private::formatters::NSNumberSummaryProvider( success = true; break; } - case TypeCodes::f64: - { + case TypeCodes::f64: { uint64_t dbl_as_lng = process_sp->ReadUnsignedIntegerFromMemory( data_location, 8, 0, error); if (error.Fail()) @@ -589,16 +625,17 @@ bool lldb_private::formatters::NSNumberSummaryProvider( case TypeCodes::sint128: // internally, this is the same { uint64_t words[2]; - words[1] = process_sp->ReadUnsignedIntegerFromMemory( - data_location, 8, 0, error); + words[1] = process_sp->ReadUnsignedIntegerFromMemory(data_location, 8, + 0, error); if (error.Fail()) return false; - words[0] = process_sp->ReadUnsignedIntegerFromMemory( - data_location + 8, 8, 0, error); + words[0] = process_sp->ReadUnsignedIntegerFromMemory(data_location + 8, + 8, 0, error); if (error.Fail()) return false; llvm::APInt i128_value(128, words); - NSNumber_FormatInt128(valobj, stream, i128_value, options.GetLanguage()); + NSNumber_FormatInt128(valobj, stream, i128_value, + options.GetLanguage()); success = true; break; } @@ -1024,7 +1061,7 @@ bool lldb_private::formatters::ObjCBOOLSummaryProvider( if (!real_guy_sp) return false; } - uint8_t value = (real_guy_sp->GetValueAsUnsigned(0) & 0xFF); + int8_t value = (real_guy_sp->GetValueAsSigned(0) & 0xFF); switch (value) { case 0: stream.Printf("NO"); @@ -1033,7 +1070,7 @@ bool lldb_private::formatters::ObjCBOOLSummaryProvider( stream.Printf("YES"); break; default: - stream.Printf("%u", value); + stream.Printf("%d", value); break; } return true; diff --git a/gnu/llvm/lldb/source/Plugins/Language/ObjC/CoreMedia.cpp b/gnu/llvm/lldb/source/Plugins/Language/ObjC/CoreMedia.cpp index ac2f45b8354..a862da55181 100644 --- a/gnu/llvm/lldb/source/Plugins/Language/ObjC/CoreMedia.cpp +++ b/gnu/llvm/lldb/source/Plugins/Language/ObjC/CoreMedia.cpp @@ -13,7 +13,7 @@ #include "lldb/Symbol/TypeSystem.h" #include "lldb/Target/Target.h" -#include +#include using namespace lldb; using namespace lldb_private; @@ -25,21 +25,12 @@ bool lldb_private::formatters::CMTimeSummaryProvider( if (!type.IsValid()) return false; - auto type_system_or_err = - valobj.GetExecutionContextRef() - .GetTargetSP() - ->GetScratchTypeSystemForLanguage(lldb::eLanguageTypeC); - if (auto err = type_system_or_err.takeError()) { - LLDB_LOG_ERROR( - lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DATAFORMATTERS), - std::move(err), "Failed to get scratch type system"); - return false; - } + TypeSystem *type_system = type.GetTypeSystem(); // fetch children by offset to compensate for potential lack of debug info - auto int64_ty = type_system_or_err->GetBuiltinTypeForEncodingAndBitSize( - eEncodingSint, 64); - auto int32_ty = type_system_or_err->GetBuiltinTypeForEncodingAndBitSize( - eEncodingSint, 32); + auto int64_ty = + type_system->GetBuiltinTypeForEncodingAndBitSize(eEncodingSint, 64); + auto int32_ty = + type_system->GetBuiltinTypeForEncodingAndBitSize(eEncodingSint, 32); auto value_sp(valobj.GetSyntheticChildAtOffset(0, int64_ty, true)); auto timescale_sp(valobj.GetSyntheticChildAtOffset(8, int32_ty, true)); diff --git a/gnu/llvm/lldb/source/Plugins/Language/ObjC/NSArray.cpp b/gnu/llvm/lldb/source/Plugins/Language/ObjC/NSArray.cpp index 8d648d8a086..b0398dd19c0 100644 --- a/gnu/llvm/lldb/source/Plugins/Language/ObjC/NSArray.cpp +++ b/gnu/llvm/lldb/source/Plugins/Language/ObjC/NSArray.cpp @@ -96,7 +96,7 @@ private: D32 *m_data_32; D64 *m_data_64; }; - + namespace Foundation1010 { namespace { struct DataDescriptor_32 { @@ -107,7 +107,7 @@ namespace Foundation1010 { uint32_t _priv2; uint32_t _data; }; - + struct DataDescriptor_64 { uint64_t _used; uint64_t _offset; @@ -117,11 +117,11 @@ namespace Foundation1010 { uint64_t _data; }; } - + using NSArrayMSyntheticFrontEnd = GenericNSArrayMSyntheticFrontEnd; } - + namespace Foundation1428 { namespace { struct DataDescriptor_32 { @@ -130,7 +130,7 @@ namespace Foundation1428 { uint32_t _size; uint32_t _data; }; - + struct DataDescriptor_64 { uint64_t _used; uint64_t _offset; @@ -138,11 +138,11 @@ namespace Foundation1428 { uint64_t _data; }; } - + using NSArrayMSyntheticFrontEnd = GenericNSArrayMSyntheticFrontEnd; } - + namespace Foundation1437 { template struct DataDescriptor { @@ -154,11 +154,11 @@ namespace Foundation1437 { uint32_t _muts; uint32_t _used; }; - + using NSArrayMSyntheticFrontEnd = GenericNSArrayMSyntheticFrontEnd< DataDescriptor, DataDescriptor>; - + template uint64_t __NSArrayMSize_Impl(lldb_private::Process &process, @@ -173,7 +173,7 @@ namespace Foundation1437 { } return descriptor._used; } - + uint64_t __NSArrayMSize(lldb_private::Process &process, lldb::addr_t valobj_addr, Status &error) { @@ -227,23 +227,23 @@ public: private: ExecutionContextRef m_exe_ctx_ref; uint8_t m_ptr_size; - + D32 *m_data_32; D64 *m_data_64; CompilerType m_id_type; }; - + namespace Foundation1300 { struct IDD32 { uint32_t used; uint32_t list; }; - + struct IDD64 { uint64_t used; uint64_t list; }; - + using NSArrayISyntheticFrontEnd = GenericNSArrayISyntheticFrontEnd; } @@ -258,18 +258,18 @@ namespace Foundation1436 { uint32_t used; uint32_t list; // in Inline cases, this is the first element }; - + struct IDD64 { uint64_t used; uint64_t list; // in Inline cases, this is the first element }; - + using NSArrayI_TransferSyntheticFrontEnd = GenericNSArrayISyntheticFrontEnd; using NSArrayISyntheticFrontEnd = GenericNSArrayISyntheticFrontEnd; - + using NSFrozenArrayMSyntheticFrontEnd = Foundation1437::NSArrayMSyntheticFrontEnd; @@ -441,7 +441,7 @@ lldb_private::formatters::NSArrayMSyntheticFrontEndBase::NSArrayMSyntheticFrontE : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_ptr_size(8), m_id_type() { if (valobj_sp) { - auto *clang_ast_context = TypeSystemClang::GetScratch( + auto *clang_ast_context = ScratchTypeSystemClang::GetForTarget( *valobj_sp->GetExecutionContextRef().GetTargetSP()); if (clang_ast_context) m_id_type = CompilerType( @@ -589,7 +589,7 @@ lldb_private::formatters::GenericNSArrayISyntheticFrontEnd:: if (valobj_sp) { CompilerType type = valobj_sp->GetCompilerType(); if (type) { - auto *clang_ast_context = TypeSystemClang::GetScratch( + auto *clang_ast_context = ScratchTypeSystemClang::GetForTarget( *valobj_sp->GetExecutionContextRef().GetTargetSP()); if (clang_ast_context) m_id_type = clang_ast_context->GetType( @@ -758,7 +758,7 @@ lldb_private::formatters::NSArray1SyntheticFrontEnd::GetChildAtIndex( if (idx == 0) { auto *clang_ast_context = - TypeSystemClang::GetScratch(*m_backend.GetTargetSP()); + ScratchTypeSystemClang::GetForTarget(*m_backend.GetTargetSP()); if (clang_ast_context) { CompilerType id_type( clang_ast_context->GetBasicType(lldb::eBasicTypeObjCID)); @@ -820,11 +820,9 @@ lldb_private::formatters::NSArraySyntheticFrontEndCreator( return (new Foundation1436::NSArrayISyntheticFrontEnd(valobj_sp)); if (runtime->GetFoundationVersion() >= 1430) return (new Foundation1430::NSArrayISyntheticFrontEnd(valobj_sp)); - else - return (new Foundation1300::NSArrayISyntheticFrontEnd(valobj_sp)); + return (new Foundation1300::NSArrayISyntheticFrontEnd(valobj_sp)); } else if (class_name == g_NSArrayI_Transfer) { return (new Foundation1436::NSArrayI_TransferSyntheticFrontEnd(valobj_sp)); - } else if (class_name == g_NSArray0) { } else if (class_name == g_NSFrozenArrayM) { return (new Foundation1436::NSFrozenArrayMSyntheticFrontEnd(valobj_sp)); } else if (class_name == g_NSArray0) { diff --git a/gnu/llvm/lldb/source/Plugins/Language/ObjC/NSDictionary.cpp b/gnu/llvm/lldb/source/Plugins/Language/ObjC/NSDictionary.cpp index 3dc07678f92..326f47a1066 100644 --- a/gnu/llvm/lldb/source/Plugins/Language/ObjC/NSDictionary.cpp +++ b/gnu/llvm/lldb/source/Plugins/Language/ObjC/NSDictionary.cpp @@ -66,7 +66,8 @@ NSDictionary_Additionals::GetAdditionalSynthetics() { static CompilerType GetLLDBNSPairType(TargetSP target_sp) { CompilerType compiler_type; - TypeSystemClang *target_ast_context = TypeSystemClang::GetScratch(*target_sp); + TypeSystemClang *target_ast_context = + ScratchTypeSystemClang::GetForTarget(*target_sp); if (target_ast_context) { ConstString g___lldb_autogen_nspair("__lldb_autogen_nspair"); @@ -388,7 +389,7 @@ bool lldb_private::formatters::NSDictionarySummaryProvider( return false; ObjCLanguageRuntime::ClassDescriptorSP descriptor( - runtime->GetClassDescriptor(valobj)); + runtime->GetNonKVOClassDescriptor(valobj)); if (!descriptor || !descriptor->IsValid()) return false; @@ -409,6 +410,7 @@ bool lldb_private::formatters::NSDictionarySummaryProvider( static const ConstString g_DictionaryM("__NSDictionaryM"); static const ConstString g_DictionaryMLegacy("__NSDictionaryM_Legacy"); static const ConstString g_DictionaryMImmutable("__NSDictionaryM_Immutable"); + static const ConstString g_DictionaryMFrozen("__NSFrozenDictionaryM"); static const ConstString g_Dictionary1("__NSSingleEntryDictionaryI"); static const ConstString g_Dictionary0("__NSDictionary0"); static const ConstString g_DictionaryCF("__CFDictionary"); @@ -426,7 +428,8 @@ bool lldb_private::formatters::NSDictionarySummaryProvider( return false; value &= (is_64bit ? ~0xFC00000000000000UL : ~0xFC000000U); - } else if (class_name == g_DictionaryM || class_name == g_DictionaryMLegacy) { + } else if (class_name == g_DictionaryM || class_name == g_DictionaryMLegacy + || class_name == g_DictionaryMFrozen) { AppleObjCRuntime *apple_runtime = llvm::dyn_cast_or_null(runtime); Status error; @@ -508,6 +511,7 @@ lldb_private::formatters::NSDictionarySyntheticFrontEndCreator( static const ConstString g_DictionaryM("__NSDictionaryM"); static const ConstString g_Dictionary1("__NSSingleEntryDictionaryI"); static const ConstString g_DictionaryImmutable("__NSDictionaryM_Immutable"); + static const ConstString g_DictionaryMFrozen("__NSFrozenDictionaryM"); static const ConstString g_DictionaryMLegacy("__NSDictionaryM_Legacy"); static const ConstString g_Dictionary0("__NSDictionary0"); static const ConstString g_DictionaryCF("__CFDictionary"); @@ -519,7 +523,7 @@ lldb_private::formatters::NSDictionarySyntheticFrontEndCreator( if (class_name == g_DictionaryI) { return (new NSDictionaryISyntheticFrontEnd(valobj_sp)); - } else if (class_name == g_DictionaryM) { + } else if (class_name == g_DictionaryM || class_name == g_DictionaryMFrozen) { if (runtime->GetFoundationVersion() >= 1437) { return (new Foundation1437::NSDictionaryMSyntheticFrontEnd(valobj_sp)); } else if (runtime->GetFoundationVersion() >= 1428) { diff --git a/gnu/llvm/lldb/source/Plugins/Language/ObjC/NSError.cpp b/gnu/llvm/lldb/source/Plugins/Language/ObjC/NSError.cpp index aa1103cb342..4ffa072f9f5 100644 --- a/gnu/llvm/lldb/source/Plugins/Language/ObjC/NSError.cpp +++ b/gnu/llvm/lldb/source/Plugins/Language/ObjC/NSError.cpp @@ -87,7 +87,7 @@ bool lldb_private::formatters::NSError_SummaryProvider( ValueObjectSP domain_str_sp = ValueObject::CreateValueObjectFromData( "domain_str", isw.GetAsData(process_sp->GetByteOrder()), valobj.GetExecutionContextRef(), - TypeSystemClang::GetScratch(process_sp->GetTarget()) + ScratchTypeSystemClang::GetForTarget(process_sp->GetTarget()) ->GetBasicType(lldb::eBasicTypeVoid) .GetPointerType()); @@ -156,7 +156,7 @@ public: m_child_sp = CreateValueObjectFromData( "_userInfo", isw.GetAsData(process_sp->GetByteOrder()), m_backend.GetExecutionContextRef(), - TypeSystemClang::GetScratch(process_sp->GetTarget()) + ScratchTypeSystemClang::GetForTarget(process_sp->GetTarget()) ->GetBasicType(lldb::eBasicTypeObjCID)); return false; } diff --git a/gnu/llvm/lldb/source/Plugins/Language/ObjC/NSException.cpp b/gnu/llvm/lldb/source/Plugins/Language/ObjC/NSException.cpp index c6bae5e1c00..7360abb8fdd 100644 --- a/gnu/llvm/lldb/source/Plugins/Language/ObjC/NSException.cpp +++ b/gnu/llvm/lldb/source/Plugins/Language/ObjC/NSException.cpp @@ -69,7 +69,8 @@ static bool ExtractFields(ValueObject &valobj, ValueObjectSP *name_sp, InferiorSizedWord userinfo_isw(userinfo, *process_sp); InferiorSizedWord reserved_isw(reserved, *process_sp); - auto *clang_ast_context = TypeSystemClang::GetScratch(process_sp->GetTarget()); + auto *clang_ast_context = + ScratchTypeSystemClang::GetForTarget(process_sp->GetTarget()); if (!clang_ast_context) return false; diff --git a/gnu/llvm/lldb/source/Plugins/Language/ObjC/NSIndexPath.cpp b/gnu/llvm/lldb/source/Plugins/Language/ObjC/NSIndexPath.cpp index d962f39611b..068bca9e7b9 100644 --- a/gnu/llvm/lldb/source/Plugins/Language/ObjC/NSIndexPath.cpp +++ b/gnu/llvm/lldb/source/Plugins/Language/ObjC/NSIndexPath.cpp @@ -53,7 +53,7 @@ public: if (!type_system) return false; - TypeSystemClang *ast = TypeSystemClang::GetScratch( + TypeSystemClang *ast = ScratchTypeSystemClang::GetForTarget( *m_backend.GetExecutionContextRef().GetTargetSP()); if (!ast) return false; @@ -209,14 +209,13 @@ protected: m_process = nullptr; } - InlinedIndexes() - : m_indexes(0), m_count(0), m_ptr_size(0), m_process(nullptr) {} + InlinedIndexes() {} private: - uint64_t m_indexes; - size_t m_count; - uint32_t m_ptr_size; - Process *m_process; + uint64_t m_indexes = 0; + size_t m_count = 0; + uint32_t m_ptr_size = 0; + Process *m_process = nullptr; // cfr. Foundation for the details of this code size_t _lengthForInlinePayload(uint32_t ptr_size) { @@ -271,10 +270,10 @@ protected: m_count = 0; } - OutsourcedIndexes() : m_indexes(nullptr), m_count(0) {} + OutsourcedIndexes() {} - ValueObject *m_indexes; - size_t m_count; + ValueObject *m_indexes = nullptr; + size_t m_count = 0; }; union { @@ -288,9 +287,9 @@ protected: m_outsourced.Clear(); } - Impl() : m_mode(Mode::Invalid) {} + Impl() {} - Mode m_mode; + Mode m_mode = Mode::Invalid; } m_impl; uint32_t m_ptr_size; diff --git a/gnu/llvm/lldb/source/Plugins/Language/ObjC/NSSet.cpp b/gnu/llvm/lldb/source/Plugins/Language/ObjC/NSSet.cpp index 4dbbe6fbddf..43ef7b694bb 100644 --- a/gnu/llvm/lldb/source/Plugins/Language/ObjC/NSSet.cpp +++ b/gnu/llvm/lldb/source/Plugins/Language/ObjC/NSSet.cpp @@ -444,18 +444,12 @@ bool lldb_private::formatters::NSSetISyntheticFrontEnd::Update() { if (!valobj_sp) return false; m_exe_ctx_ref = valobj_sp->GetExecutionContextRef(); - Status error; - if (valobj_sp->IsPointerType()) { - valobj_sp = valobj_sp->Dereference(error); - if (error.Fail() || !valobj_sp) - return false; - } - error.Clear(); lldb::ProcessSP process_sp(valobj_sp->GetProcessSP()); if (!process_sp) return false; m_ptr_size = process_sp->GetAddressByteSize(); - uint64_t data_location = valobj_sp->GetAddressOf() + m_ptr_size; + uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size; + Status error; if (m_ptr_size == 4) { m_data_32 = new DataDescriptor_32(); process_sp->ReadMemory(data_location, m_data_32, sizeof(DataDescriptor_32), @@ -728,18 +722,12 @@ lldb_private::formatters:: if (!valobj_sp) return false; m_exe_ctx_ref = valobj_sp->GetExecutionContextRef(); - Status error; - if (valobj_sp->IsPointerType()) { - valobj_sp = valobj_sp->Dereference(error); - if (error.Fail() || !valobj_sp) - return false; - } - error.Clear(); lldb::ProcessSP process_sp(valobj_sp->GetProcessSP()); if (!process_sp) return false; m_ptr_size = process_sp->GetAddressByteSize(); - uint64_t data_location = valobj_sp->GetAddressOf() + m_ptr_size; + uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size; + Status error; if (m_ptr_size == 4) { m_data_32 = new D32(); process_sp->ReadMemory(data_location, m_data_32, sizeof(D32), diff --git a/gnu/llvm/lldb/source/Plugins/Language/ObjC/NSString.cpp b/gnu/llvm/lldb/source/Plugins/Language/ObjC/NSString.cpp index b9d0d73cbc2..85922992eb2 100644 --- a/gnu/llvm/lldb/source/Plugins/Language/ObjC/NSString.cpp +++ b/gnu/llvm/lldb/source/Plugins/Language/ObjC/NSString.cpp @@ -34,7 +34,7 @@ NSString_Additionals::GetAdditionalSummaries() { static CompilerType GetNSPathStore2Type(Target &target) { static ConstString g_type_name("__lldb_autogen_nspathstore2"); - TypeSystemClang *ast_ctx = TypeSystemClang::GetScratch(target); + TypeSystemClang *ast_ctx = ScratchTypeSystemClang::GetForTarget(target); if (!ast_ctx) return CompilerType(); diff --git a/gnu/llvm/lldb/source/Plugins/Language/ObjC/ObjCLanguage.cpp b/gnu/llvm/lldb/source/Plugins/Language/ObjC/ObjCLanguage.cpp index 29391daaab9..379c53432b7 100644 --- a/gnu/llvm/lldb/source/Plugins/Language/ObjC/ObjCLanguage.cpp +++ b/gnu/llvm/lldb/source/Plugins/Language/ObjC/ObjCLanguage.cpp @@ -225,14 +225,17 @@ ConstString ObjCLanguage::MethodName::GetFullNameWithoutCategory( return ConstString(); } -std::vector +std::vector ObjCLanguage::GetMethodNameVariants(ConstString method_name) const { - std::vector variant_names; + std::vector variant_names; ObjCLanguage::MethodName objc_method(method_name.GetCString(), false); if (!objc_method.IsValid(false)) { return variant_names; } + variant_names.emplace_back(objc_method.GetSelector(), + lldb::eFunctionNameTypeSelector); + const bool is_class_method = objc_method.GetType() == MethodName::eTypeClassMethod; const bool is_instance_method = @@ -242,31 +245,43 @@ ObjCLanguage::GetMethodNameVariants(ConstString method_name) const { if (is_class_method || is_instance_method) { if (name_sans_category) - variant_names.emplace_back(name_sans_category); + variant_names.emplace_back(name_sans_category, + lldb::eFunctionNameTypeFull); } else { StreamString strm; strm.Printf("+%s", objc_method.GetFullName().GetCString()); - variant_names.emplace_back(strm.GetString()); + variant_names.emplace_back(ConstString(strm.GetString()), + lldb::eFunctionNameTypeFull); strm.Clear(); strm.Printf("-%s", objc_method.GetFullName().GetCString()); - variant_names.emplace_back(strm.GetString()); + variant_names.emplace_back(ConstString(strm.GetString()), + lldb::eFunctionNameTypeFull); strm.Clear(); if (name_sans_category) { strm.Printf("+%s", name_sans_category.GetCString()); - variant_names.emplace_back(strm.GetString()); + variant_names.emplace_back(ConstString(strm.GetString()), + lldb::eFunctionNameTypeFull); strm.Clear(); strm.Printf("-%s", name_sans_category.GetCString()); - variant_names.emplace_back(strm.GetString()); + variant_names.emplace_back(ConstString(strm.GetString()), + lldb::eFunctionNameTypeFull); } } return variant_names; } +bool ObjCLanguage::SymbolNameFitsToLanguage(Mangled mangled) const { + ConstString demangled_name = mangled.GetDemangledName(); + if (!demangled_name) + return false; + return ObjCLanguage::IsPossibleObjCMethodName(demangled_name.GetCString()); +} + static void LoadObjCFormatters(TypeCategoryImplSP objc_category_sp) { if (!objc_category_sp) return; @@ -990,8 +1005,11 @@ std::unique_ptr ObjCLanguage::GetTypeScavenger() { bool result = false; if (auto *target = exe_scope->CalculateTarget().get()) { - if (auto *clang_modules_decl_vendor = - target->GetClangModulesDeclVendor()) { + auto *persistent_vars = llvm::cast( + target->GetPersistentExpressionStateForLanguage( + lldb::eLanguageTypeC)); + if (std::shared_ptr clang_modules_decl_vendor = + persistent_vars->GetClangModulesDeclVendor()) { ConstString key_cs(key); auto types = clang_modules_decl_vendor->FindTypes( key_cs, /*max_matches*/ UINT32_MAX); @@ -1116,7 +1134,7 @@ bool ObjCLanguage::IsNilReference(ValueObject &valobj) { bool ObjCLanguage::IsSourceFile(llvm::StringRef file_path) const { const auto suffixes = {".h", ".m", ".M"}; for (auto suffix : suffixes) { - if (file_path.endswith_lower(suffix)) + if (file_path.endswith_insensitive(suffix)) return true; } return false; diff --git a/gnu/llvm/lldb/source/Plugins/Language/ObjC/ObjCLanguage.h b/gnu/llvm/lldb/source/Plugins/Language/ObjC/ObjCLanguage.h index bed62a5c447..691c51883c8 100644 --- a/gnu/llvm/lldb/source/Plugins/Language/ObjC/ObjCLanguage.h +++ b/gnu/llvm/lldb/source/Plugins/Language/ObjC/ObjCLanguage.h @@ -27,9 +27,7 @@ public: public: enum Type { eTypeUnspecified, eTypeClassMethod, eTypeInstanceMethod }; - MethodName() - : m_full(), m_class(), m_category(), m_selector(), - m_type(eTypeUnspecified), m_category_is_valid(false) {} + MethodName() : m_full(), m_class(), m_category(), m_selector() {} MethodName(const char *name, bool strict) : m_full(), m_class(), m_category(), m_selector(), @@ -81,8 +79,8 @@ public: m_class_category; // Class with category: "NSString(my_additions)" ConstString m_category; // Category: "my_additions" ConstString m_selector; // Selector: "myStringWithCString:" - Type m_type; - bool m_category_is_valid; + Type m_type = eTypeUnspecified; + bool m_category_is_valid = false; }; ObjCLanguage() = default; @@ -102,9 +100,12 @@ public: // variant_names[1] => "-[NSString(my_additions) myStringWithCString:]" // variant_names[2] => "+[NSString myStringWithCString:]" // variant_names[3] => "-[NSString myStringWithCString:]" - std::vector + // Also returns the FunctionNameType of each possible name. + std::vector GetMethodNameVariants(ConstString method_name) const override; + bool SymbolNameFitsToLanguage(Mangled mangled) const override; + lldb::TypeCategoryImplSP GetFormatters() override; std::vector @@ -119,6 +120,8 @@ public: bool IsNilReference(ValueObject &valobj) override; + llvm::StringRef GetNilReferenceSummaryString() override { return "nil"; } + bool IsSourceFile(llvm::StringRef file_path) const override; const Highlighter *GetHighlighter() const override { return &m_highlighter; } diff --git a/gnu/llvm/lldb/source/Plugins/Language/ObjCPlusPlus/ObjCPlusPlusLanguage.cpp b/gnu/llvm/lldb/source/Plugins/Language/ObjCPlusPlus/ObjCPlusPlusLanguage.cpp index 0a4017eda43..35997855321 100644 --- a/gnu/llvm/lldb/source/Plugins/Language/ObjCPlusPlus/ObjCPlusPlusLanguage.cpp +++ b/gnu/llvm/lldb/source/Plugins/Language/ObjCPlusPlus/ObjCPlusPlusLanguage.cpp @@ -19,7 +19,7 @@ LLDB_PLUGIN_DEFINE(ObjCPlusPlusLanguage) bool ObjCPlusPlusLanguage::IsSourceFile(llvm::StringRef file_path) const { const auto suffixes = {".h", ".mm"}; for (auto suffix : suffixes) { - if (file_path.endswith_lower(suffix)) + if (file_path.endswith_insensitive(suffix)) return true; } return false; diff --git a/gnu/llvm/lldb/source/Plugins/Language/ObjCPlusPlus/ObjCPlusPlusLanguage.h b/gnu/llvm/lldb/source/Plugins/Language/ObjCPlusPlus/ObjCPlusPlusLanguage.h index 4b3d2365334..233fd5c00a7 100644 --- a/gnu/llvm/lldb/source/Plugins/Language/ObjCPlusPlus/ObjCPlusPlusLanguage.h +++ b/gnu/llvm/lldb/source/Plugins/Language/ObjCPlusPlus/ObjCPlusPlusLanguage.h @@ -27,6 +27,8 @@ public: return lldb::eLanguageTypeObjC_plus_plus; } + llvm::StringRef GetNilReferenceSummaryString() override { return "nil"; } + bool IsSourceFile(llvm::StringRef file_path) const override; const Highlighter *GetHighlighter() const override { return &m_highlighter; } diff --git a/gnu/llvm/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp b/gnu/llvm/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp index 8aa803a8553..bed2a98067e 100644 --- a/gnu/llvm/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp +++ b/gnu/llvm/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// -#include +#include #include @@ -37,9 +37,6 @@ static ConstString g_this = ConstString("this"); char CPPLanguageRuntime::ID = 0; -// Destructor -CPPLanguageRuntime::~CPPLanguageRuntime() {} - CPPLanguageRuntime::CPPLanguageRuntime(Process *process) : LanguageRuntime(process) {} @@ -102,9 +99,7 @@ line_entry_helper(Target &target, const SymbolContext &sc, Symbol *symbol, CPPLanguageRuntime::LibCppStdFunctionCallableInfo CPPLanguageRuntime::FindLibCppStdFunctionCallableInfo( lldb::ValueObjectSP &valobj_sp) { - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer(func_cat, - "CPPLanguageRuntime::FindLibCppStdFunctionCallableInfo"); + LLDB_SCOPED_TIMER(); LibCppStdFunctionCallableInfo optional_info; @@ -154,6 +149,9 @@ CPPLanguageRuntime::FindLibCppStdFunctionCallableInfo( member__f_ = sub_member__f_; } + if (!member__f_) + return optional_info; + lldb::addr_t member__f_pointer_value = member__f_->GetValueAsUnsigned(0); optional_info.member__f_pointer_value = member__f_pointer_value; @@ -324,6 +322,9 @@ CPPLanguageRuntime::FindLibCppStdFunctionCallableInfo( } } + if (symbol == nullptr) + return optional_info; + // Case 1 or 3 if (scl.GetSize() >= 1) { optional_info = line_entry_helper(target, scl[0], symbol, @@ -399,8 +400,8 @@ CPPLanguageRuntime::GetStepThroughTrampolinePlan(Thread &thread, // We create a ThreadPlan to keep stepping through using the address range // of the current function. ret_plan_sp = std::make_shared( - thread, range_of_curr_func, sc, eOnlyThisThread, eLazyBoolYes, - eLazyBoolYes); + thread, range_of_curr_func, sc, nullptr, eOnlyThisThread, + eLazyBoolYes, eLazyBoolYes); return ret_plan_sp; } } diff --git a/gnu/llvm/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.h b/gnu/llvm/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.h index 5b00590e630..3f5b9935187 100644 --- a/gnu/llvm/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.h +++ b/gnu/llvm/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.h @@ -40,8 +40,6 @@ public: LibCppStdFunctionCallableInfo FindLibCppStdFunctionCallableInfo(lldb::ValueObjectSP &valobj_sp); - ~CPPLanguageRuntime() override; - static char ID; bool isA(const void *ClassID) const override { @@ -89,9 +87,6 @@ private: llvm::StringMap; OperatorStringToCallableInfoMap CallableLookupCache; - - CPPLanguageRuntime(const CPPLanguageRuntime &) = delete; - const CPPLanguageRuntime &operator=(const CPPLanguageRuntime &) = delete; }; } // namespace lldb_private diff --git a/gnu/llvm/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp b/gnu/llvm/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp index 3ab32641d9c..f5b587c5196 100644 --- a/gnu/llvm/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp +++ b/gnu/llvm/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp @@ -196,7 +196,7 @@ bool ItaniumABILanguageRuntime::GetDynamicTypeAndAddress( // class_type_or_name.Clear(); - value_type = Value::ValueType::eValueTypeScalar; + value_type = Value::ValueType::Scalar; // Only a pointer or reference type can have a different dynamic and static // type: @@ -536,7 +536,7 @@ ValueObjectSP ItaniumABILanguageRuntime::GetExceptionObjectForThread( return {}; TypeSystemClang *clang_ast_context = - TypeSystemClang::GetScratch(m_process->GetTarget()); + ScratchTypeSystemClang::GetForTarget(m_process->GetTarget()); if (!clang_ast_context) return {}; diff --git a/gnu/llvm/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.cpp b/gnu/llvm/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.cpp index bdd5c29db84..405b8a6f16b 100644 --- a/gnu/llvm/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.cpp +++ b/gnu/llvm/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.cpp @@ -252,6 +252,7 @@ bool ClassDescriptorV2::method_list_t::Read(Process *process, } bool ClassDescriptorV2::method_t::Read(Process *process, lldb::addr_t addr, + lldb::addr_t relative_selector_base_addr, bool is_small, bool has_direct_sel) { size_t ptr_size = process->GetAddressByteSize(); size_t size = GetSize(process, is_small); @@ -281,6 +282,8 @@ bool ClassDescriptorV2::method_t::Read(Process *process, lldb::addr_t addr, 0, error); if (!error.Success()) return false; + } else if (relative_selector_base_addr != LLDB_INVALID_ADDRESS) { + m_name_ptr = relative_selector_base_addr + nameref_offset; } m_types_ptr = addr + 4 + types_offset; m_imp_ptr = addr + 8 + imp_offset; @@ -389,14 +392,14 @@ bool ClassDescriptorV2::Describe( if (base_method_list->m_entsize != method_t::GetSize(process, is_small)) return false; - std::unique_ptr method; - method = std::make_unique(); - + std::unique_ptr method = std::make_unique(); + lldb::addr_t relative_selector_base_addr = + m_runtime.GetRelativeSelectorBaseAddr(); for (uint32_t i = 0, e = base_method_list->m_count; i < e; ++i) { method->Read(process, base_method_list->m_first_ptr + (i * base_method_list->m_entsize), - is_small, has_direct_selector); + relative_selector_base_addr, is_small, has_direct_selector); if (instance_method_func(method->m_name.c_str(), method->m_types.c_str())) break; @@ -514,8 +517,7 @@ uint64_t ClassDescriptorV2::GetInstanceSize() { return 0; } -ClassDescriptorV2::iVarsStorage::iVarsStorage() - : m_filled(false), m_ivars(), m_mutex() {} +ClassDescriptorV2::iVarsStorage::iVarsStorage() : m_ivars(), m_mutex() {} size_t ClassDescriptorV2::iVarsStorage::size() { return m_ivars.size(); } diff --git a/gnu/llvm/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.h b/gnu/llvm/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.h index 9ef21c6e720..7ba957940ae 100644 --- a/gnu/llvm/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.h +++ b/gnu/llvm/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.h @@ -41,6 +41,12 @@ public: return false; } + bool GetTaggedPointerInfoSigned(uint64_t *info_bits = nullptr, + int64_t *value_bits = nullptr, + uint64_t *payload = nullptr) override { + return false; + } + uint64_t GetInstanceSize() override; ObjCLanguageRuntime::ObjCISA GetISA() override { return m_objc_class_ptr; } @@ -71,16 +77,14 @@ private: static const uint32_t RW_REALIZED = (1 << 31); struct objc_class_t { - ObjCLanguageRuntime::ObjCISA m_isa; // The class's metaclass. - ObjCLanguageRuntime::ObjCISA m_superclass; - lldb::addr_t m_cache_ptr; - lldb::addr_t m_vtable_ptr; - lldb::addr_t m_data_ptr; - uint8_t m_flags; + ObjCLanguageRuntime::ObjCISA m_isa = 0; // The class's metaclass. + ObjCLanguageRuntime::ObjCISA m_superclass = 0; + lldb::addr_t m_cache_ptr = 0; + lldb::addr_t m_vtable_ptr = 0; + lldb::addr_t m_data_ptr = 0; + uint8_t m_flags = 0; - objc_class_t() - : m_isa(0), m_superclass(0), m_cache_ptr(0), m_vtable_ptr(0), - m_data_ptr(0), m_flags(0) {} + objc_class_t() = default; void Clear() { m_isa = 0; @@ -162,7 +166,8 @@ private: + field_size; // IMP imp; } - bool Read(Process *process, lldb::addr_t addr, bool, bool); + bool Read(Process *process, lldb::addr_t addr, + lldb::addr_t relative_method_lists_base_addr, bool, bool); }; struct ivar_list_t { @@ -207,7 +212,7 @@ private: void fill(AppleObjCRuntimeV2 &runtime, ClassDescriptorV2 &descriptor); private: - bool m_filled; + bool m_filled = false; std::vector m_ivars; std::recursive_mutex m_mutex; }; @@ -253,7 +258,7 @@ public: ClassDescriptorV2Tagged( ObjCLanguageRuntime::ClassDescriptorSP actual_class_sp, - uint64_t payload) { + uint64_t u_payload, int64_t s_payload) { if (!actual_class_sp) { m_valid = false; return; @@ -264,9 +269,10 @@ public: return; } m_valid = true; - m_payload = payload; + m_payload = u_payload; m_info_bits = (m_payload & 0x0FULL); m_value_bits = (m_payload & ~0x0FULL) >> 4; + m_value_bits_signed = (s_payload & ~0x0FLL) >> 4; } ~ClassDescriptorV2Tagged() override = default; @@ -308,6 +314,18 @@ public: return true; } + bool GetTaggedPointerInfoSigned(uint64_t *info_bits = nullptr, + int64_t *value_bits = nullptr, + uint64_t *payload = nullptr) override { + if (info_bits) + *info_bits = GetInfoBits(); + if (value_bits) + *value_bits = GetValueBitsSigned(); + if (payload) + *payload = GetPayload(); + return true; + } + uint64_t GetInstanceSize() override { return (IsValid() ? m_pointer_size : 0); } @@ -319,6 +337,10 @@ public: // these calls are not part of any formal tagged pointers specification virtual uint64_t GetValueBits() { return (IsValid() ? m_value_bits : 0); } + virtual int64_t GetValueBitsSigned() { + return (IsValid() ? m_value_bits_signed : 0); + } + virtual uint64_t GetInfoBits() { return (IsValid() ? m_info_bits : 0); } virtual uint64_t GetPayload() { return (IsValid() ? m_payload : 0); } @@ -329,6 +351,7 @@ private: bool m_valid; uint64_t m_info_bits; uint64_t m_value_bits; + int64_t m_value_bits_signed; uint64_t m_payload; }; diff --git a/gnu/llvm/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCDeclVendor.cpp b/gnu/llvm/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCDeclVendor.cpp index 7b331307c0f..9bc40c16e5d 100644 --- a/gnu/llvm/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCDeclVendor.cpp +++ b/gnu/llvm/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCDeclVendor.cpp @@ -59,7 +59,7 @@ public: clang::DeclContext::lookup_result result = non_const_interface_decl->lookup(name); - return (result.size() != 0); + return (!result.empty()); } while (false); SetNoExternalVisibleDeclsForName(decl_ctx, name); @@ -555,7 +555,7 @@ uint32_t AppleObjCDeclVendor::FindDecls(ConstString name, bool append, if (!lookup_result.empty()) { if (clang::ObjCInterfaceDecl *result_iface_decl = - llvm::dyn_cast(lookup_result[0])) { + llvm::dyn_cast(*lookup_result.begin())) { if (log) { clang::QualType result_iface_type = ast_ctx.getObjCInterfaceType(result_iface_decl); diff --git a/gnu/llvm/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp b/gnu/llvm/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp index 22ea83a57be..88e86c51fe4 100644 --- a/gnu/llvm/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp +++ b/gnu/llvm/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp @@ -48,7 +48,7 @@ LLDB_PLUGIN_DEFINE(AppleObjCRuntime) char AppleObjCRuntime::ID = 0; -AppleObjCRuntime::~AppleObjCRuntime() {} +AppleObjCRuntime::~AppleObjCRuntime() = default; AppleObjCRuntime::AppleObjCRuntime(Process *process) : ObjCLanguageRuntime(process), m_read_objc_library(false), @@ -122,7 +122,8 @@ bool AppleObjCRuntime::GetObjectDescription(Stream &strm, Value &value, } } else { // If it is not a pointer, see if we can make it into a pointer. - TypeSystemClang *ast_context = TypeSystemClang::GetScratch(*target); + TypeSystemClang *ast_context = + ScratchTypeSystemClang::GetForTarget(*target); if (!ast_context) return false; @@ -137,7 +138,7 @@ bool AppleObjCRuntime::GetObjectDescription(Stream &strm, Value &value, arg_value_list.PushValue(value); // This is the return value: - TypeSystemClang *ast_context = TypeSystemClang::GetScratch(*target); + TypeSystemClang *ast_context = ScratchTypeSystemClang::GetForTarget(*target); if (!ast_context) return false; @@ -376,12 +377,7 @@ AppleObjCRuntime::GetObjCVersion(Process *process, ModuleSP &objc_module_sp) { llvm::Triple::VendorType::Apple) return ObjCRuntimeVersions::eObjC_VersionUnknown; - const ModuleList &target_modules = target.GetImages(); - std::lock_guard gaurd(target_modules.GetMutex()); - - size_t num_images = target_modules.GetSize(); - for (size_t i = 0; i < num_images; i++) { - ModuleSP module_sp = target_modules.GetModuleAtIndexUnlocked(i); + for (ModuleSP module_sp : target.GetImages().Modules()) { // One tricky bit here is that we might get called as part of the initial // module loading, but before all the pre-run libraries get winnowed from // the module list. So there might actually be an old and incorrect ObjC @@ -525,7 +521,7 @@ ThreadSP AppleObjCRuntime::GetBacktraceThreadFromException( return FailExceptionParsing("Failed to get synthetic value."); TypeSystemClang *clang_ast_context = - TypeSystemClang::GetScratch(*exception_sp->GetTargetSP()); + ScratchTypeSystemClang::GetForTarget(*exception_sp->GetTargetSP()); if (!clang_ast_context) return FailExceptionParsing("Failed to get scratch AST."); CompilerType objc_id = diff --git a/gnu/llvm/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.cpp b/gnu/llvm/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.cpp index 8202686597a..98d0e9cf991 100644 --- a/gnu/llvm/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.cpp +++ b/gnu/llvm/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.cpp @@ -49,7 +49,7 @@ bool AppleObjCRuntimeV1::GetDynamicTypeAndAddress( TypeAndOrName &class_type_or_name, Address &address, Value::ValueType &value_type) { class_type_or_name.Clear(); - value_type = Value::ValueType::eValueTypeScalar; + value_type = Value::ValueType::Scalar; if (CouldHaveDynamicValue(in_value)) { auto class_descriptor(GetClassDescriptor(in_value)); if (class_descriptor && class_descriptor->IsValid() && @@ -122,58 +122,60 @@ struct BufStruct { char contents[2048]; }; -UtilityFunction *AppleObjCRuntimeV1::CreateObjectChecker(const char *name) { +llvm::Expected> +AppleObjCRuntimeV1::CreateObjectChecker(std::string name, + ExecutionContext &exe_ctx) { std::unique_ptr buf(new BufStruct); - int strformatsize = snprintf(&buf->contents[0], sizeof(buf->contents), - "struct __objc_class " - " \n" - "{ " - " \n" - " struct __objc_class *isa; " - " \n" - " struct __objc_class *super_class; " - " \n" - " const char *name; " - " \n" - " // rest of struct elided because unused " - " \n" - "}; " - " \n" - " " - " \n" - "struct __objc_object " - " \n" - "{ " - " \n" - " struct __objc_class *isa; " - " \n" - "}; " - " \n" - " " - " \n" - "extern \"C\" void " - " \n" - "%s(void *$__lldb_arg_obj, void *$__lldb_arg_selector) " - " \n" - "{ " - " \n" - " struct __objc_object *obj = (struct " - "__objc_object*)$__lldb_arg_obj; \n" - " if ($__lldb_arg_obj == (void *)0) " - " \n" - " return; // nil is ok " - " (int)strlen(obj->isa->name); " - " \n" - "} " - " \n", - name); + int strformatsize = + snprintf(&buf->contents[0], sizeof(buf->contents), + "struct __objc_class " + " \n" + "{ " + " \n" + " struct __objc_class *isa; " + " \n" + " struct __objc_class *super_class; " + " \n" + " const char *name; " + " \n" + " // rest of struct elided because unused " + " \n" + "}; " + " \n" + " " + " \n" + "struct __objc_object " + " \n" + "{ " + " \n" + " struct __objc_class *isa; " + " \n" + "}; " + " \n" + " " + " \n" + "extern \"C\" void " + " \n" + "%s(void *$__lldb_arg_obj, void *$__lldb_arg_selector) " + " \n" + "{ " + " \n" + " struct __objc_object *obj = (struct " + "__objc_object*)$__lldb_arg_obj; \n" + " if ($__lldb_arg_obj == (void *)0) " + " \n" + " return; // nil is ok " + " (int)strlen(obj->isa->name); " + " \n" + "} " + " \n", + name.c_str()); assert(strformatsize < (int)sizeof(buf->contents)); (void)strformatsize; - Status error; - return GetTargetRef().GetUtilityFunctionForLanguage( - buf->contents, eLanguageTypeObjC, name, error); + return GetTargetRef().CreateUtilityFunction(buf->contents, std::move(name), + eLanguageTypeC, exe_ctx); } AppleObjCRuntimeV1::ClassDescriptorV1::ClassDescriptorV1( @@ -337,8 +339,6 @@ void AppleObjCRuntimeV1::UpdateISAToDescriptorMapIfNeeded() { if (!objc_module_sp) return; - uint32_t isa_count = 0; - lldb::addr_t hash_table_ptr = GetISAHashTablePointer(); if (hash_table_ptr != LLDB_INVALID_ADDRESS) { // Read the NXHashTable struct: @@ -381,8 +381,6 @@ void AppleObjCRuntimeV1::UpdateISAToDescriptorMapIfNeeded() { if (bucket_isa_count == 0) continue; - isa_count += bucket_isa_count; - ObjCISA isa; if (bucket_isa_count == 1) { // When we only have one entry in the bucket, the bucket data diff --git a/gnu/llvm/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.h b/gnu/llvm/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.h index d8725d0f57c..12ee2cc5363 100644 --- a/gnu/llvm/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.h +++ b/gnu/llvm/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.h @@ -64,6 +64,12 @@ public: return false; } + bool GetTaggedPointerInfoSigned(uint64_t *info_bits = nullptr, + int64_t *value_bits = nullptr, + uint64_t *payload = nullptr) override { + return false; + } + uint64_t GetInstanceSize() override { return m_instance_size; } ObjCISA GetISA() override { return m_isa; } @@ -97,7 +103,8 @@ public: Address &address, Value::ValueType &value_type) override; - UtilityFunction *CreateObjectChecker(const char *) override; + llvm::Expected> + CreateObjectChecker(std::string, ExecutionContext &exe_ctx) override; // PluginInterface protocol ConstString GetPluginName() override; @@ -119,8 +126,7 @@ protected: class HashTableSignature { public: - HashTableSignature() - : m_count(0), m_num_buckets(0), m_buckets_ptr(LLDB_INVALID_ADDRESS) {} + HashTableSignature() = default; bool NeedsUpdate(uint32_t count, uint32_t num_buckets, lldb::addr_t buckets_ptr) { @@ -136,9 +142,9 @@ protected: } protected: - uint32_t m_count; - uint32_t m_num_buckets; - lldb::addr_t m_buckets_ptr; + uint32_t m_count = 0; + uint32_t m_num_buckets = 0; + lldb::addr_t m_buckets_ptr = LLDB_INVALID_ADDRESS; }; lldb::addr_t GetISAHashTablePointer(); diff --git a/gnu/llvm/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp b/gnu/llvm/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp index ac9a0939402..10512a97ad6 100644 --- a/gnu/llvm/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp +++ b/gnu/llvm/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// -#include +#include #include #include @@ -39,6 +39,7 @@ #include "lldb/Symbol/TypeList.h" #include "lldb/Symbol/VariableList.h" #include "lldb/Target/ABI.h" +#include "lldb/Target/DynamicLoader.h" #include "lldb/Target/ExecutionContext.h" #include "lldb/Target/Platform.h" #include "lldb/Target/Process.h" @@ -75,8 +76,7 @@ char AppleObjCRuntimeV2::ID = 0; static const char *g_get_dynamic_class_info_name = "__lldb_apple_objc_v2_get_dynamic_class_info"; -// Testing using the new C++11 raw string literals. If this breaks GCC then we -// will need to revert to the code above... + static const char *g_get_dynamic_class_info_body = R"( extern "C" @@ -121,14 +121,20 @@ __lldb_apple_objc_v2_get_dynamic_class_info (void *gdb_objc_realized_classes_ptr if (grc) { const unsigned num_classes = grc->num_classes; + DEBUG_PRINTF ("num_classes = %u\n", grc->num_classes); if (class_infos_ptr) { + const unsigned num_buckets_minus_one = grc->num_buckets_minus_one; + DEBUG_PRINTF ("num_buckets_minus_one = %u\n", num_buckets_minus_one); + const size_t max_class_infos = class_infos_byte_size/sizeof(ClassInfo); + DEBUG_PRINTF ("max_class_infos = %u\n", max_class_infos); + ClassInfo *class_infos = (ClassInfo *)class_infos_ptr; BucketInfo *buckets = (BucketInfo *)grc->buckets; - + uint32_t idx = 0; - for (unsigned i=0; i<=grc->num_buckets_minus_one; ++i) + for (unsigned i=0; i<=num_buckets_minus_one; ++i) { if (buckets[i].name_ptr != NX_MAPNOTAKEY) { @@ -140,6 +146,7 @@ __lldb_apple_objc_v2_get_dynamic_class_info (void *gdb_objc_realized_classes_ptr h = ((h << 5) + h) + c; class_infos[idx].hash = h; class_infos[idx].isa = buckets[i].isa; + DEBUG_PRINTF ("[%u] isa = %8p %s\n", idx, class_infos[idx].isa, buckets[i].name_ptr); } ++idx; } @@ -157,6 +164,75 @@ __lldb_apple_objc_v2_get_dynamic_class_info (void *gdb_objc_realized_classes_ptr )"; +static const char *g_get_dynamic_class_info2_name = + "__lldb_apple_objc_v2_get_dynamic_class_info2"; + +static const char *g_get_dynamic_class_info2_body = R"( + +extern "C" { + int printf(const char * format, ...); + void free(void *ptr); + Class* objc_copyRealizedClassList_nolock(unsigned int *outCount); + const char* objc_debug_class_getNameRaw(Class cls); +} + +#define DEBUG_PRINTF(fmt, ...) if (should_log) printf(fmt, ## __VA_ARGS__) + +struct ClassInfo +{ + Class isa; + uint32_t hash; +} __attribute__((__packed__)); + +uint32_t +__lldb_apple_objc_v2_get_dynamic_class_info2(void *gdb_objc_realized_classes_ptr, + void *class_infos_ptr, + uint32_t class_infos_byte_size, + uint32_t should_log) +{ + DEBUG_PRINTF ("class_infos_ptr = %p\n", class_infos_ptr); + DEBUG_PRINTF ("class_infos_byte_size = %u\n", class_infos_byte_size); + + const size_t max_class_infos = class_infos_byte_size/sizeof(ClassInfo); + DEBUG_PRINTF ("max_class_infos = %u\n", max_class_infos); + + ClassInfo *class_infos = (ClassInfo *)class_infos_ptr; + + uint32_t count = 0; + Class* realized_class_list = objc_copyRealizedClassList_nolock(&count); + DEBUG_PRINTF ("count = %u\n", count); + + uint32_t idx = 0; + for (uint32_t i=0; i<=count; ++i) + { + if (idx < max_class_infos) + { + Class isa = realized_class_list[i]; + const char *name_ptr = objc_debug_class_getNameRaw(isa); + if (name_ptr == NULL) + continue; + const char *s = name_ptr; + uint32_t h = 5381; + for (unsigned char c = *s; c; c = *++s) + h = ((h << 5) + h) + c; + class_infos[idx].hash = h; + class_infos[idx].isa = isa; + DEBUG_PRINTF ("[%u] isa = %8p %s\n", idx, class_infos[idx].isa, name_ptr); + } + idx++; + } + + if (idx < max_class_infos) + { + class_infos[idx].isa = NULL; + class_infos[idx].hash = 0; + } + + free(realized_class_list); + return count; +} +)"; + // We'll substitute in class_getName or class_getNameRaw depending // on which is present. static const char *g_shared_cache_class_name_funcptr = R"( @@ -169,8 +245,7 @@ extern "C" static const char *g_get_shared_cache_class_info_name = "__lldb_apple_objc_v2_get_shared_cache_class_info"; -// Testing using the new C++11 raw string literals. If this breaks GCC then we -// will need to revert to the code above... + static const char *g_get_shared_cache_class_info_body = R"( extern "C" @@ -188,6 +263,12 @@ struct objc_classheader_t { int32_t hiOffset; }; +struct objc_classheader_v16_t { + uint64_t isDuplicate : 1, + objectCacheOffset : 47, // Offset from the shared cache base + dylibObjCIndex : 16; +}; + struct objc_clsopt_t { uint32_t capacity; uint32_t occupied; @@ -205,6 +286,22 @@ struct objc_clsopt_t { // objc_classheader_t duplicateOffsets[duplicateCount]; }; +struct objc_clsopt_v16_t { + uint32_t version; + uint32_t capacity; + uint32_t occupied; + uint32_t shift; + uint32_t mask; + uint64_t salt; + uint32_t scramble[256]; + uint8_t tab[0]; // tab[mask+1] + // uint8_t checkbytes[capacity]; + // int32_t offset[capacity]; + // objc_classheader_t clsOffsets[capacity]; + // uint32_t duplicateCount; + // objc_classheader_t duplicateOffsets[duplicateCount]; +}; + struct objc_opt_t { uint32_t version; int32_t selopt_offset; @@ -220,6 +317,20 @@ struct objc_opt_v14_t { int32_t clsopt_offset; }; +struct objc_opt_v16_t { + uint32_t version; + uint32_t flags; + int32_t selopt_offset; + int32_t headeropt_ro_offset; + int32_t unused_clsopt_offset; + int32_t unused_protocolopt_offset; + int32_t headeropt_rw_offset; + int32_t unused_protocolopt2_offset; + int32_t largeSharedCachesClassOffset; + int32_t largeSharedCachesProtocolOffset; + uint64_t relativeMethodSelectorBaseAddressCacheOffset; +}; + struct ClassInfo { Class isa; @@ -228,20 +339,33 @@ struct ClassInfo uint32_t __lldb_apple_objc_v2_get_shared_cache_class_info (void *objc_opt_ro_ptr, + void *shared_cache_base_ptr, void *class_infos_ptr, + uint64_t *relative_selector_offset, uint32_t class_infos_byte_size, uint32_t should_log) { + *relative_selector_offset = 0; uint32_t idx = 0; DEBUG_PRINTF ("objc_opt_ro_ptr = %p\n", objc_opt_ro_ptr); + DEBUG_PRINTF ("shared_cache_base_ptr = %p\n", shared_cache_base_ptr); DEBUG_PRINTF ("class_infos_ptr = %p\n", class_infos_ptr); DEBUG_PRINTF ("class_infos_byte_size = %u (%llu class infos)\n", class_infos_byte_size, (uint64_t)(class_infos_byte_size/sizeof(ClassInfo))); if (objc_opt_ro_ptr) { const objc_opt_t *objc_opt = (objc_opt_t *)objc_opt_ro_ptr; const objc_opt_v14_t* objc_opt_v14 = (objc_opt_v14_t*)objc_opt_ro_ptr; - const bool is_v14_format = objc_opt->version >= 14; - if (is_v14_format) + const objc_opt_v16_t* objc_opt_v16 = (objc_opt_v16_t*)objc_opt_ro_ptr; + if (objc_opt->version >= 16) + { + *relative_selector_offset = objc_opt_v16->relativeMethodSelectorBaseAddressCacheOffset; + DEBUG_PRINTF ("objc_opt->version = %u\n", objc_opt_v16->version); + DEBUG_PRINTF ("objc_opt->flags = %u\n", objc_opt_v16->flags); + DEBUG_PRINTF ("objc_opt->selopt_offset = %d\n", objc_opt_v16->selopt_offset); + DEBUG_PRINTF ("objc_opt->headeropt_ro_offset = %d\n", objc_opt_v16->headeropt_ro_offset); + DEBUG_PRINTF ("objc_opt->relativeMethodSelectorBaseAddressCacheOffset = %d\n", *relative_selector_offset); + } + else if (objc_opt->version >= 14) { DEBUG_PRINTF ("objc_opt->version = %u\n", objc_opt_v14->version); DEBUG_PRINTF ("objc_opt->flags = %u\n", objc_opt_v14->flags); @@ -256,10 +380,126 @@ __lldb_apple_objc_v2_get_shared_cache_class_info (void *objc_opt_ro_ptr, DEBUG_PRINTF ("objc_opt->headeropt_offset = %d\n", objc_opt->headeropt_offset); DEBUG_PRINTF ("objc_opt->clsopt_offset = %d\n", objc_opt->clsopt_offset); } - if (objc_opt->version == 12 || objc_opt->version == 13 || objc_opt->version == 14 || objc_opt->version == 15) + + if (objc_opt->version == 16) + { + const objc_clsopt_v16_t* clsopt = (const objc_clsopt_v16_t*)((uint8_t *)objc_opt + objc_opt_v16->largeSharedCachesClassOffset); + const size_t max_class_infos = class_infos_byte_size/sizeof(ClassInfo); + + DEBUG_PRINTF("max_class_infos = %llu\n", (uint64_t)max_class_infos); + + ClassInfo *class_infos = (ClassInfo *)class_infos_ptr; + + const uint8_t *checkbytes = &clsopt->tab[clsopt->mask+1]; + const int32_t *offsets = (const int32_t *)(checkbytes + clsopt->capacity); + const objc_classheader_v16_t *classOffsets = (const objc_classheader_v16_t *)(offsets + clsopt->capacity); + + DEBUG_PRINTF ("clsopt->capacity = %u\n", clsopt->capacity); + DEBUG_PRINTF ("clsopt->mask = 0x%8.8x\n", clsopt->mask); + DEBUG_PRINTF ("classOffsets = %p\n", classOffsets); + + for (uint32_t i=0; icapacity; ++i) + { + const uint64_t objectCacheOffset = classOffsets[i].objectCacheOffset; + DEBUG_PRINTF("objectCacheOffset[%u] = %u\n", i, objectCacheOffset); + + if (classOffsets[i].isDuplicate) { + DEBUG_PRINTF("isDuplicate = true\n"); + continue; // duplicate + } + + if (objectCacheOffset == 0) { + DEBUG_PRINTF("objectCacheOffset == invalidEntryOffset\n"); + continue; // invalid offset + } + + if (class_infos && idx < max_class_infos) + { + class_infos[idx].isa = (Class)((uint8_t *)shared_cache_base_ptr + objectCacheOffset); + + // Lookup the class name. + const char *name = class_name_lookup_func(class_infos[idx].isa); + DEBUG_PRINTF("[%u] isa = %8p %s\n", idx, class_infos[idx].isa, name); + + // Hash the class name so we don't have to read it. + const char *s = name; + uint32_t h = 5381; + for (unsigned char c = *s; c; c = *++s) + { + // class_getName demangles swift names and the hash must + // be calculated on the mangled name. hash==0 means lldb + // will fetch the mangled name and compute the hash in + // ParseClassInfoArray. + if (c == '.') + { + h = 0; + break; + } + h = ((h << 5) + h) + c; + } + class_infos[idx].hash = h; + } + else + { + DEBUG_PRINTF("not(class_infos && idx < max_class_infos)\n"); + } + ++idx; + } + + const uint32_t *duplicate_count_ptr = (uint32_t *)&classOffsets[clsopt->capacity]; + const uint32_t duplicate_count = *duplicate_count_ptr; + const objc_classheader_v16_t *duplicateClassOffsets = (const objc_classheader_v16_t *)(&duplicate_count_ptr[1]); + + DEBUG_PRINTF ("duplicate_count = %u\n", duplicate_count); + DEBUG_PRINTF ("duplicateClassOffsets = %p\n", duplicateClassOffsets); + + for (uint32_t i=0; iversion >= 12 && objc_opt->version <= 15) { const objc_clsopt_t* clsopt = NULL; - if (is_v14_format) + if (objc_opt->version >= 14) clsopt = (const objc_clsopt_t*)((uint8_t *)objc_opt_v14 + objc_opt_v14->clsopt_offset); else clsopt = (const objc_clsopt_t*)((uint8_t *)objc_opt + objc_opt->clsopt_offset); @@ -291,7 +531,7 @@ __lldb_apple_objc_v2_get_shared_cache_class_info (void *objc_opt_ro_ptr, DEBUG_PRINTF("clsOffset == invalidEntryOffset\n"); continue; // invalid offset } - + if (class_infos && idx < max_class_infos) { class_infos[idx].isa = (Class)((uint8_t *)clsopt + clsOffset); @@ -321,7 +561,7 @@ __lldb_apple_objc_v2_get_shared_cache_class_info (void *objc_opt_ro_ptr, } ++idx; } - + const uint32_t *duplicate_count_ptr = (uint32_t *)&classOffsets[clsopt->capacity]; const uint32_t duplicate_count = *duplicate_count_ptr; const objc_classheader_t *duplicateClassOffsets = (const objc_classheader_t *)(&duplicate_count_ptr[1]); @@ -334,7 +574,7 @@ __lldb_apple_objc_v2_get_shared_cache_class_info (void *objc_opt_ro_ptr, continue; // duplicate else if (clsOffset == invalidEntryOffset) continue; // invalid offset - + if (class_infos && idx < max_class_infos) { class_infos[idx].isa = (Class)((uint8_t *)clsopt + clsOffset); @@ -353,7 +593,7 @@ __lldb_apple_objc_v2_get_shared_cache_class_info (void *objc_opt_ro_ptr, { h = 0; break; - } + } h = ((h << 5) + h) + c; } class_infos[idx].hash = h; @@ -380,56 +620,58 @@ ExtractRuntimeGlobalSymbol(Process *process, ConstString name, error.SetErrorString("no process"); return default_value; } + if (!module_sp) { error.SetErrorString("no module"); return default_value; } + if (!byte_size) byte_size = process->GetAddressByteSize(); const Symbol *symbol = module_sp->FindFirstSymbolWithNameAndType(name, lldb::eSymbolTypeData); - if (symbol && symbol->ValueIsAddress()) { - lldb::addr_t symbol_load_addr = - symbol->GetAddressRef().GetLoadAddress(&process->GetTarget()); - if (symbol_load_addr != LLDB_INVALID_ADDRESS) { - if (read_value) - return process->ReadUnsignedIntegerFromMemory( - symbol_load_addr, byte_size, default_value, error); - else - return symbol_load_addr; - } else { - error.SetErrorString("symbol address invalid"); - return default_value; - } - } else { + + if (!symbol || !symbol->ValueIsAddress()) { error.SetErrorString("no symbol"); return default_value; } + + lldb::addr_t symbol_load_addr = + symbol->GetAddressRef().GetLoadAddress(&process->GetTarget()); + if (symbol_load_addr == LLDB_INVALID_ADDRESS) { + error.SetErrorString("symbol address invalid"); + return default_value; + } + + if (read_value) + return process->ReadUnsignedIntegerFromMemory(symbol_load_addr, byte_size, + default_value, error); + return symbol_load_addr; } -static void RegisterObjCExceptionRecognizer(); +static void RegisterObjCExceptionRecognizer(Process *process); AppleObjCRuntimeV2::AppleObjCRuntimeV2(Process *process, const ModuleSP &objc_module_sp) - : AppleObjCRuntime(process), m_get_class_info_code(), - m_get_class_info_args(LLDB_INVALID_ADDRESS), - m_get_class_info_args_mutex(), m_get_shared_cache_class_info_code(), - m_get_shared_cache_class_info_args(LLDB_INVALID_ADDRESS), - m_get_shared_cache_class_info_args_mutex(), m_decl_vendor_up(), + : AppleObjCRuntime(process), m_objc_module_sp(objc_module_sp), + m_dynamic_class_info_extractor(*this), + m_shared_cache_class_info_extractor(*this), m_decl_vendor_up(), m_tagged_pointer_obfuscator(LLDB_INVALID_ADDRESS), - m_isa_hash_table_ptr(LLDB_INVALID_ADDRESS), m_hash_signature(), - m_has_object_getClass(false), m_loaded_objc_opt(false), - m_non_pointer_isa_cache_up( - NonPointerISACache::CreateInstance(*this, objc_module_sp)), + m_isa_hash_table_ptr(LLDB_INVALID_ADDRESS), + m_relative_selector_base(LLDB_INVALID_ADDRESS), m_hash_signature(), + m_has_object_getClass(false), m_has_objc_copyRealizedClassList(false), + m_loaded_objc_opt(false), m_non_pointer_isa_cache_up(), m_tagged_pointer_vendor_up( TaggedPointerVendorV2::CreateInstance(*this, objc_module_sp)), m_encoding_to_type_sp(), m_noclasses_warning_emitted(false), - m_CFBoolean_values() { + m_CFBoolean_values(), m_realized_class_generation_count(0) { static const ConstString g_gdb_object_getClass("gdb_object_getClass"); - m_has_object_getClass = - (objc_module_sp->FindFirstSymbolWithNameAndType( - g_gdb_object_getClass, eSymbolTypeCode) != nullptr); - RegisterObjCExceptionRecognizer(); + m_has_object_getClass = HasSymbol(g_gdb_object_getClass); + static const ConstString g_objc_copyRealizedClassList( + "_ZL33objc_copyRealizedClassList_nolockPj"); + m_has_objc_copyRealizedClassList = HasSymbol(g_objc_copyRealizedClassList); + + RegisterObjCExceptionRecognizer(process); } bool AppleObjCRuntimeV2::GetDynamicTypeAndAddress( @@ -451,7 +693,7 @@ bool AppleObjCRuntimeV2::GetDynamicTypeAndAddress( assert(in_value.GetTargetSP().get() == m_process->CalculateTarget().get()); class_type_or_name.Clear(); - value_type = Value::ValueType::eValueTypeScalar; + value_type = Value::ValueType::Scalar; // Make sure we can have a dynamic value before starting... if (CouldHaveDynamicValue(in_value)) { @@ -498,15 +740,21 @@ LanguageRuntime *AppleObjCRuntimeV2::CreateInstance(Process *process, if (AppleObjCRuntime::GetObjCVersion(process, objc_module_sp) == ObjCRuntimeVersions::eAppleObjC_V2) return new AppleObjCRuntimeV2(process, objc_module_sp); - else - return nullptr; - } else return nullptr; + } + return nullptr; } static constexpr OptionDefinition g_objc_classtable_dump_options[] = { - {LLDB_OPT_SET_ALL, false, "verbose", 'v', OptionParser::eNoArgument, - nullptr, {}, 0, eArgTypeNone, + {LLDB_OPT_SET_ALL, + false, + "verbose", + 'v', + OptionParser::eNoArgument, + nullptr, + {}, + 0, + eArgTypeNone, "Print ivar and method information in detail"}}; class CommandObjectObjC_ClassTable_Dump : public CommandObjectParsed { @@ -548,12 +796,13 @@ public: }; CommandObjectObjC_ClassTable_Dump(CommandInterpreter &interpreter) - : CommandObjectParsed( - interpreter, "dump", "Dump information on Objective-C classes " - "known to the current process.", - "language objc class-table dump", - eCommandRequiresProcess | eCommandProcessMustBeLaunched | - eCommandProcessMustBePaused), + : CommandObjectParsed(interpreter, "dump", + "Dump information on Objective-C classes " + "known to the current process.", + "language objc class-table dump", + eCommandRequiresProcess | + eCommandProcessMustBeLaunched | + eCommandProcessMustBePaused), m_options() { CommandArgumentEntry arg; CommandArgumentData index_arg; @@ -581,8 +830,8 @@ protected: case 0: break; case 1: { - regex_up = std::make_unique( - llvm::StringRef::withNullAsEmpty(command.GetArgumentAtIndex(0))); + regex_up = + std::make_unique(command.GetArgumentAtIndex(0)); if (!regex_up->IsValid()) { result.AppendError( "invalid argument - please provide a valid regular expression"); @@ -632,6 +881,7 @@ protected: ivar.m_type.GetDisplayTypeName().AsCString(""), ivar.m_size, ivar.m_offset); } + iterator->second->Describe( nullptr, [&std_out](const char *name, const char *type) -> bool { @@ -655,11 +905,10 @@ protected: } result.SetStatus(lldb::eReturnStatusSuccessFinishResult); return true; - } else { - result.AppendError("current process has no Objective-C runtime loaded"); - result.SetStatus(lldb::eReturnStatusFailed); - return false; } + result.AppendError("current process has no Objective-C runtime loaded"); + result.SetStatus(lldb::eReturnStatusFailed); + return false; } CommandOptions m_options; @@ -741,11 +990,10 @@ protected: } result.SetStatus(lldb::eReturnStatusSuccessFinishResult); return true; - } else { - result.AppendError("current process has no Objective-C runtime loaded"); - result.SetStatus(lldb::eReturnStatusFailed); - return false; } + result.AppendError("current process has no Objective-C runtime loaded"); + result.SetStatus(lldb::eReturnStatusFailed); + return false; } }; @@ -840,7 +1088,9 @@ AppleObjCRuntimeV2::CreateExceptionResolver(const BreakpointSP &bkpt, return resolver_sp; } -UtilityFunction *AppleObjCRuntimeV2::CreateObjectChecker(const char *name) { +llvm::Expected> +AppleObjCRuntimeV2::CreateObjectChecker(std::string name, + ExecutionContext &exe_ctx) { char check_function_code[2048]; int len = 0; @@ -861,7 +1111,8 @@ UtilityFunction *AppleObjCRuntimeV2::CreateObjectChecker(const char *name) { if ($responds == (signed char) 0) *((volatile int *)0) = 'ocgc'; } - })", name); + })", + name.c_str()); } else { len = ::snprintf(check_function_code, sizeof(check_function_code), R"( extern "C" void *gdb_class_getClass(void *); @@ -881,15 +1132,15 @@ UtilityFunction *AppleObjCRuntimeV2::CreateObjectChecker(const char *name) { if ($responds == (signed char) 0) *((volatile int *)0) = 'ocgc'; } - })", name); + })", + name.c_str()); } assert(len < (int)sizeof(check_function_code)); UNUSED_IF_ASSERT_DISABLED(len); - Status error; - return GetTargetRef().GetUtilityFunctionForLanguage( - check_function_code, eLanguageTypeObjC, name, error); + return GetTargetRef().CreateUtilityFunction(check_function_code, name, + eLanguageTypeC, exe_ctx); } size_t AppleObjCRuntimeV2::GetByteOffsetForIvar(CompilerType &parent_ast_type, @@ -948,11 +1199,7 @@ bool AppleObjCRuntimeV2::IsTaggedPointer(addr_t ptr) { class RemoteNXMapTable { public: - RemoteNXMapTable() - : m_count(0), m_num_buckets_minus_one(0), - m_buckets_ptr(LLDB_INVALID_ADDRESS), m_process(nullptr), - m_end_iterator(*this, -1), m_load_addr(LLDB_INVALID_ADDRESS), - m_map_pair_size(0), m_invalid_key(0) {} + RemoteNXMapTable() : m_end_iterator(*this, -1) {} void Dump() { printf("RemoteNXMapTable.m_load_addr = 0x%" PRIx64 "\n", m_load_addr); @@ -1126,18 +1373,17 @@ public: private: // contents of _NXMapTable struct - uint32_t m_count; - uint32_t m_num_buckets_minus_one; - lldb::addr_t m_buckets_ptr; - lldb_private::Process *m_process; + uint32_t m_count = 0; + uint32_t m_num_buckets_minus_one = 0; + lldb::addr_t m_buckets_ptr = LLDB_INVALID_ADDRESS; + lldb_private::Process *m_process = nullptr; const_iterator m_end_iterator; - lldb::addr_t m_load_addr; - size_t m_map_pair_size; - lldb::addr_t m_invalid_key; + lldb::addr_t m_load_addr = LLDB_INVALID_ADDRESS; + size_t m_map_pair_size = 0; + lldb::addr_t m_invalid_key = 0; }; -AppleObjCRuntimeV2::HashTableSignature::HashTableSignature() - : m_count(0), m_num_buckets(0), m_buckets_ptr(0) {} +AppleObjCRuntimeV2::HashTableSignature::HashTableSignature() = default; void AppleObjCRuntimeV2::HashTableSignature::UpdateSignature( const RemoteNXMapTable &hash_table) { @@ -1168,35 +1414,13 @@ bool AppleObjCRuntimeV2::HashTableSignature::NeedsUpdate( ObjCLanguageRuntime::ClassDescriptorSP AppleObjCRuntimeV2::GetClassDescriptorFromISA(ObjCISA isa) { ObjCLanguageRuntime::ClassDescriptorSP class_descriptor_sp; - if (m_non_pointer_isa_cache_up) - class_descriptor_sp = m_non_pointer_isa_cache_up->GetClassDescriptor(isa); + if (auto *non_pointer_isa_cache = GetNonPointerIsaCache()) + class_descriptor_sp = non_pointer_isa_cache->GetClassDescriptor(isa); if (!class_descriptor_sp) class_descriptor_sp = ObjCLanguageRuntime::GetClassDescriptorFromISA(isa); return class_descriptor_sp; } -static std::pair ObjCGetClassNameRaw( - AppleObjCRuntime::ObjCISA isa, - Process *process) { - StreamString expr_string; - std::string input = std::to_string(isa); - expr_string.Printf("(const char *)objc_debug_class_getNameRaw(%s)", - input.c_str()); - - ValueObjectSP result_sp; - EvaluateExpressionOptions eval_options; - eval_options.SetLanguage(lldb::eLanguageTypeObjC); - eval_options.SetResultIsInternal(true); - eval_options.SetGenerateDebugInfo(true); - eval_options.SetTimeout(process->GetUtilityExpressionTimeout()); - auto eval_result = process->GetTarget().EvaluateExpression( - expr_string.GetData(), - process->GetThreadList().GetSelectedThread()->GetSelectedFrame().get(), - result_sp, eval_options); - ConstString type_name(result_sp->GetSummaryAsCString()); - return std::make_pair(eval_result == eExpressionCompleted, type_name); -} - ObjCLanguageRuntime::ClassDescriptorSP AppleObjCRuntimeV2::GetClassDescriptor(ValueObject &valobj) { ClassDescriptorSP objc_class_sp; @@ -1232,25 +1456,13 @@ AppleObjCRuntimeV2::GetClassDescriptor(ValueObject &valobj) { return objc_class_sp; objc_class_sp = GetClassDescriptorFromISA(isa); - - if (objc_class_sp) - return objc_class_sp; - else { - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS | - LIBLLDB_LOG_TYPES)); + if (isa && !objc_class_sp) { + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_TYPES)); LLDB_LOGF(log, - "0x%" PRIx64 - ": AppleObjCRuntimeV2::GetClassDescriptor() ISA was " + "0x%" PRIx64 ": AppleObjCRuntimeV2::GetClassDescriptor() ISA was " "not in class descriptor cache 0x%" PRIx64, isa_pointer, isa); } - - ClassDescriptorSP descriptor_sp(new ClassDescriptorV2(*this, isa, nullptr)); - auto resolved = ObjCGetClassNameRaw(isa, process); - if (resolved.first == true) { - AddClass(isa, descriptor_sp, resolved.second.AsCString()); - objc_class_sp = descriptor_sp; - } return objc_class_sp; } @@ -1258,28 +1470,29 @@ lldb::addr_t AppleObjCRuntimeV2::GetTaggedPointerObfuscator() { if (m_tagged_pointer_obfuscator != LLDB_INVALID_ADDRESS) return m_tagged_pointer_obfuscator; - Process *process = GetProcess(); ModuleSP objc_module_sp(GetObjCModule()); if (!objc_module_sp) return LLDB_INVALID_ADDRESS; - static ConstString g_gdb_objc_obfuscator("objc_debug_taggedpointer_obfuscator"); + static ConstString g_gdb_objc_obfuscator( + "objc_debug_taggedpointer_obfuscator"); const Symbol *symbol = objc_module_sp->FindFirstSymbolWithNameAndType( - g_gdb_objc_obfuscator, lldb::eSymbolTypeAny); + g_gdb_objc_obfuscator, lldb::eSymbolTypeAny); if (symbol) { lldb::addr_t g_gdb_obj_obfuscator_ptr = - symbol->GetLoadAddress(&process->GetTarget()); + symbol->GetLoadAddress(&process->GetTarget()); if (g_gdb_obj_obfuscator_ptr != LLDB_INVALID_ADDRESS) { Status error; - m_tagged_pointer_obfuscator = process->ReadPointerFromMemory( - g_gdb_obj_obfuscator_ptr, error); + m_tagged_pointer_obfuscator = + process->ReadPointerFromMemory(g_gdb_obj_obfuscator_ptr, error); } } - // If we don't have a correct value at this point, there must be no obfuscation. + // If we don't have a correct value at this point, there must be no + // obfuscation. if (m_tagged_pointer_obfuscator == LLDB_INVALID_ADDRESS) m_tagged_pointer_obfuscator = 0; @@ -1313,11 +1526,212 @@ lldb::addr_t AppleObjCRuntimeV2::GetISAHashTablePointer() { return m_isa_hash_table_ptr; } +std::unique_ptr +AppleObjCRuntimeV2::DynamicClassInfoExtractor::GetClassInfoUtilityFunctionImpl( + ExecutionContext &exe_ctx, std::string code, std::string name) { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_TYPES)); + + LLDB_LOG(log, "Creating utility function {0}", name); + + TypeSystemClang *ast = + ScratchTypeSystemClang::GetForTarget(exe_ctx.GetTargetRef()); + if (!ast) + return {}; + + auto utility_fn_or_error = exe_ctx.GetTargetRef().CreateUtilityFunction( + std::move(code), std::move(name), eLanguageTypeC, exe_ctx); + if (!utility_fn_or_error) { + LLDB_LOG_ERROR( + log, utility_fn_or_error.takeError(), + "Failed to get utility function for implementation lookup: {0}"); + return {}; + } + + // Make some types for our arguments. + CompilerType clang_uint32_t_type = + ast->GetBuiltinTypeForEncodingAndBitSize(eEncodingUint, 32); + CompilerType clang_void_pointer_type = + ast->GetBasicType(eBasicTypeVoid).GetPointerType(); + + // Make the runner function for our implementation utility function. + ValueList arguments; + Value value; + value.SetValueType(Value::ValueType::Scalar); + value.SetCompilerType(clang_void_pointer_type); + arguments.PushValue(value); + arguments.PushValue(value); + value.SetValueType(Value::ValueType::Scalar); + value.SetCompilerType(clang_uint32_t_type); + arguments.PushValue(value); + arguments.PushValue(value); + + std::unique_ptr utility_fn = std::move(*utility_fn_or_error); + + Status error; + utility_fn->MakeFunctionCaller(clang_uint32_t_type, arguments, + exe_ctx.GetThreadSP(), error); + + if (error.Fail()) { + LLDB_LOG(log, + "Failed to make function caller for implementation lookup: {0}.", + error.AsCString()); + return {}; + } + + return utility_fn; +} + +UtilityFunction * +AppleObjCRuntimeV2::DynamicClassInfoExtractor::GetClassInfoUtilityFunction( + ExecutionContext &exe_ctx, Helper helper) { + switch (helper) { + case gdb_objc_realized_classes: { + if (!m_gdb_objc_realized_classes_helper.utility_function) + m_gdb_objc_realized_classes_helper.utility_function = + GetClassInfoUtilityFunctionImpl(exe_ctx, + g_get_dynamic_class_info_body, + g_get_dynamic_class_info_name); + return m_gdb_objc_realized_classes_helper.utility_function.get(); + } + case objc_copyRealizedClassList: { + if (!m_objc_copyRealizedClassList_helper.utility_function) + m_objc_copyRealizedClassList_helper.utility_function = + GetClassInfoUtilityFunctionImpl(exe_ctx, + g_get_dynamic_class_info2_body, + g_get_dynamic_class_info2_name); + return m_objc_copyRealizedClassList_helper.utility_function.get(); + } + } + llvm_unreachable("Unexpected helper"); +} + +lldb::addr_t & +AppleObjCRuntimeV2::DynamicClassInfoExtractor::GetClassInfoArgs(Helper helper) { + switch (helper) { + case gdb_objc_realized_classes: + return m_gdb_objc_realized_classes_helper.args; + case objc_copyRealizedClassList: + return m_objc_copyRealizedClassList_helper.args; + } + llvm_unreachable("Unexpected helper"); +} + +AppleObjCRuntimeV2::DynamicClassInfoExtractor::Helper +AppleObjCRuntimeV2::DynamicClassInfoExtractor::ComputeHelper() const { + if (!m_runtime.m_has_objc_copyRealizedClassList) + return DynamicClassInfoExtractor::gdb_objc_realized_classes; + + if (Process *process = m_runtime.GetProcess()) { + if (DynamicLoader *loader = process->GetDynamicLoader()) { + if (loader->IsFullyInitialized()) + return DynamicClassInfoExtractor::objc_copyRealizedClassList; + } + } + + return DynamicClassInfoExtractor::gdb_objc_realized_classes; +} + +std::unique_ptr +AppleObjCRuntimeV2::SharedCacheClassInfoExtractor:: + GetClassInfoUtilityFunctionImpl(ExecutionContext &exe_ctx) { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_TYPES)); + + LLDB_LOG(log, "Creating utility function {0}", + g_get_shared_cache_class_info_name); + + TypeSystemClang *ast = + ScratchTypeSystemClang::GetForTarget(exe_ctx.GetTargetRef()); + if (!ast) + return {}; + + // If the inferior objc.dylib has the class_getNameRaw function, use that in + // our jitted expression. Else fall back to the old class_getName. + static ConstString g_class_getName_symbol_name("class_getName"); + static ConstString g_class_getNameRaw_symbol_name( + "objc_debug_class_getNameRaw"); + + ConstString class_name_getter_function_name = + m_runtime.HasSymbol(g_class_getNameRaw_symbol_name) + ? g_class_getNameRaw_symbol_name + : g_class_getName_symbol_name; + + // Substitute in the correct class_getName / class_getNameRaw function name, + // concatenate the two parts of our expression text. The format string has + // two %s's, so provide the name twice. + std::string shared_class_expression; + llvm::raw_string_ostream(shared_class_expression) + << llvm::format(g_shared_cache_class_name_funcptr, + class_name_getter_function_name.AsCString(), + class_name_getter_function_name.AsCString()); + + shared_class_expression += g_get_shared_cache_class_info_body; + + auto utility_fn_or_error = exe_ctx.GetTargetRef().CreateUtilityFunction( + std::move(shared_class_expression), g_get_shared_cache_class_info_name, + eLanguageTypeC, exe_ctx); + + if (!utility_fn_or_error) { + LLDB_LOG_ERROR( + log, utility_fn_or_error.takeError(), + "Failed to get utility function for implementation lookup: {0}"); + return nullptr; + } + + // Make some types for our arguments. + CompilerType clang_uint32_t_type = + ast->GetBuiltinTypeForEncodingAndBitSize(eEncodingUint, 32); + CompilerType clang_void_pointer_type = + ast->GetBasicType(eBasicTypeVoid).GetPointerType(); + CompilerType clang_uint64_t_pointer_type = + ast->GetBuiltinTypeForEncodingAndBitSize(eEncodingUint, 64) + .GetPointerType(); + + // Next make the function caller for our implementation utility function. + ValueList arguments; + Value value; + value.SetValueType(Value::ValueType::Scalar); + value.SetCompilerType(clang_void_pointer_type); + arguments.PushValue(value); + arguments.PushValue(value); + arguments.PushValue(value); + + value.SetValueType(Value::ValueType::Scalar); + value.SetCompilerType(clang_uint64_t_pointer_type); + arguments.PushValue(value); + + value.SetValueType(Value::ValueType::Scalar); + value.SetCompilerType(clang_uint32_t_type); + arguments.PushValue(value); + arguments.PushValue(value); + + std::unique_ptr utility_fn = std::move(*utility_fn_or_error); + + Status error; + utility_fn->MakeFunctionCaller(clang_uint32_t_type, arguments, + exe_ctx.GetThreadSP(), error); + + if (error.Fail()) { + LLDB_LOG(log, + "Failed to make function caller for implementation lookup: {0}.", + error.AsCString()); + return {}; + } + + return utility_fn; +} + +UtilityFunction * +AppleObjCRuntimeV2::SharedCacheClassInfoExtractor::GetClassInfoUtilityFunction( + ExecutionContext &exe_ctx) { + if (!m_utility_function) + m_utility_function = GetClassInfoUtilityFunctionImpl(exe_ctx); + return m_utility_function.get(); +} + AppleObjCRuntimeV2::DescriptorMapUpdateResult -AppleObjCRuntimeV2::UpdateISAToDescriptorMapDynamic( +AppleObjCRuntimeV2::DynamicClassInfoExtractor::UpdateISAToDescriptorMap( RemoteNXMapTable &hash_table) { - Process *process = GetProcess(); - + Process *process = m_runtime.GetProcess(); if (process == nullptr) return DescriptorMapUpdateResult::Fail(); @@ -1333,94 +1747,49 @@ AppleObjCRuntimeV2::UpdateISAToDescriptorMapDynamic( return DescriptorMapUpdateResult::Fail(); thread_sp->CalculateExecutionContext(exe_ctx); - TypeSystemClang *ast = TypeSystemClang::GetScratch(process->GetTarget()); + TypeSystemClang *ast = + ScratchTypeSystemClang::GetForTarget(process->GetTarget()); if (!ast) return DescriptorMapUpdateResult::Fail(); Address function_address; - DiagnosticManager diagnostics; - const uint32_t addr_size = process->GetAddressByteSize(); Status err; + // Compute which helper we're going to use for this update. + const DynamicClassInfoExtractor::Helper helper = ComputeHelper(); + // Read the total number of classes from the hash table - const uint32_t num_classes = hash_table.GetCount(); + const uint32_t num_classes = + helper == DynamicClassInfoExtractor::gdb_objc_realized_classes + ? hash_table.GetCount() + : m_runtime.m_realized_class_generation_count; if (num_classes == 0) { - LLDB_LOGF(log, "No dynamic classes found in gdb_objc_realized_classes."); + LLDB_LOGF(log, "No dynamic classes found."); return DescriptorMapUpdateResult::Success(0); } - // Make some types for our arguments - CompilerType clang_uint32_t_type = - ast->GetBuiltinTypeForEncodingAndBitSize(eEncodingUint, 32); - CompilerType clang_void_pointer_type = - ast->GetBasicType(eBasicTypeVoid).GetPointerType(); - - ValueList arguments; - FunctionCaller *get_class_info_function = nullptr; - - if (!m_get_class_info_code) { - Status error; - m_get_class_info_code.reset(GetTargetRef().GetUtilityFunctionForLanguage( - g_get_dynamic_class_info_body, eLanguageTypeObjC, - g_get_dynamic_class_info_name, error)); - if (error.Fail()) { - LLDB_LOGF(log, - "Failed to get Utility Function for implementation lookup: %s", - error.AsCString()); - m_get_class_info_code.reset(); - } else { - diagnostics.Clear(); - - if (!m_get_class_info_code->Install(diagnostics, exe_ctx)) { - if (log) { - LLDB_LOGF(log, "Failed to install implementation lookup"); - diagnostics.Dump(log); - } - m_get_class_info_code.reset(); - } - } - if (!m_get_class_info_code) - return DescriptorMapUpdateResult::Fail(); - - // Next make the runner function for our implementation utility function. - Value value; - value.SetValueType(Value::eValueTypeScalar); - value.SetCompilerType(clang_void_pointer_type); - arguments.PushValue(value); - arguments.PushValue(value); - - value.SetValueType(Value::eValueTypeScalar); - value.SetCompilerType(clang_uint32_t_type); - arguments.PushValue(value); - arguments.PushValue(value); - - get_class_info_function = m_get_class_info_code->MakeFunctionCaller( - clang_uint32_t_type, arguments, thread_sp, error); + UtilityFunction *get_class_info_code = + GetClassInfoUtilityFunction(exe_ctx, helper); + if (!get_class_info_code) { + // The callee will have already logged a useful error message. + return DescriptorMapUpdateResult::Fail(); + } - if (error.Fail()) { - LLDB_LOGF(log, - "Failed to make function caller for implementation lookup: %s.", - error.AsCString()); - return DescriptorMapUpdateResult::Fail(); - } - } else { - get_class_info_function = m_get_class_info_code->GetFunctionCaller(); - if (!get_class_info_function) { - if (log) { - LLDB_LOGF(log, "Failed to get implementation lookup function caller."); - diagnostics.Dump(log); - } + FunctionCaller *get_class_info_function = + get_class_info_code->GetFunctionCaller(); - return DescriptorMapUpdateResult::Fail(); - } - arguments = get_class_info_function->GetArgumentValues(); + if (!get_class_info_function) { + LLDB_LOGF(log, "Failed to get implementation lookup function caller."); + return DescriptorMapUpdateResult::Fail(); } - diagnostics.Clear(); + ValueList arguments = get_class_info_function->GetArgumentValues(); + + DiagnosticManager diagnostics; const uint32_t class_info_byte_size = addr_size + 4; const uint32_t class_infos_byte_size = num_classes * class_info_byte_size; @@ -1435,18 +1804,18 @@ AppleObjCRuntimeV2::UpdateISAToDescriptorMapDynamic( return DescriptorMapUpdateResult::Fail(); } - std::lock_guard guard(m_get_class_info_args_mutex); + std::lock_guard guard(m_mutex); // Fill in our function argument values arguments.GetValueAtIndex(0)->GetScalar() = hash_table.GetTableLoadAddress(); arguments.GetValueAtIndex(1)->GetScalar() = class_infos_addr; arguments.GetValueAtIndex(2)->GetScalar() = class_infos_byte_size; - + // Only dump the runtime classes from the expression evaluation if the log is // verbose: Log *type_log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_TYPES); bool dump_log = type_log && type_log->GetVerbose(); - + arguments.GetValueAtIndex(3)->GetScalar() = dump_log ? 1 : 0; bool success = false; @@ -1455,7 +1824,7 @@ AppleObjCRuntimeV2::UpdateISAToDescriptorMapDynamic( // Write our function arguments into the process so we can run our function if (get_class_info_function->WriteFunctionArguments( - exe_ctx, m_get_class_info_args, arguments, diagnostics)) { + exe_ctx, GetClassInfoArgs(helper), arguments, diagnostics)) { EvaluateExpressionOptions options; options.SetUnwindOnError(true); options.SetTryAllThreads(false); @@ -1464,8 +1833,11 @@ AppleObjCRuntimeV2::UpdateISAToDescriptorMapDynamic( options.SetTimeout(process->GetUtilityExpressionTimeout()); options.SetIsForUtilityExpr(true); + CompilerType clang_uint32_t_type = + ast->GetBuiltinTypeForEncodingAndBitSize(eEncodingUint, 32); + Value return_value; - return_value.SetValueType(Value::eValueTypeScalar); + return_value.SetValueType(Value::ValueType::Scalar); return_value.SetCompilerType(clang_uint32_t_type); return_value.GetScalar() = 0; @@ -1473,12 +1845,12 @@ AppleObjCRuntimeV2::UpdateISAToDescriptorMapDynamic( // Run the function ExpressionResults results = get_class_info_function->ExecuteFunction( - exe_ctx, &m_get_class_info_args, options, diagnostics, return_value); + exe_ctx, &GetClassInfoArgs(helper), options, diagnostics, return_value); if (results == eExpressionCompleted) { // The result is the number of ClassInfo structures that were filled in num_class_infos = return_value.GetScalar().ULong(); - LLDB_LOGF(log, "Discovered %u ObjC classes\n", num_class_infos); + LLDB_LOG(log, "Discovered {0} Objective-C classes", num_class_infos); if (num_class_infos > 0) { // Read the ClassInfo structures DataBufferHeap buffer(num_class_infos * class_info_byte_size, 0); @@ -1488,7 +1860,7 @@ AppleObjCRuntimeV2::UpdateISAToDescriptorMapDynamic( DataExtractor class_infos_data(buffer.GetBytes(), buffer.GetByteSize(), process->GetByteOrder(), addr_size); - ParseClassInfoArray(class_infos_data, num_class_infos); + m_runtime.ParseClassInfoArray(class_infos_data, num_class_infos); } } success = true; @@ -1552,15 +1924,16 @@ uint32_t AppleObjCRuntimeV2::ParseClassInfoArray(const DataExtractor &data, ClassDescriptorSP descriptor_sp( new ClassDescriptorV2(*this, isa, nullptr)); - // The code in g_get_shared_cache_class_info_body sets the value of the hash - // to 0 to signal a demangled symbol. We use class_getName() in that code to - // find the class name, but this returns a demangled name for Swift symbols. - // For those symbols, recompute the hash here by reading their name from the - // runtime. + // The code in g_get_shared_cache_class_info_body sets the value of the + // hash to 0 to signal a demangled symbol. We use class_getName() in that + // code to find the class name, but this returns a demangled name for + // Swift symbols. For those symbols, recompute the hash here by reading + // their name from the runtime. if (name_hash) AddClass(isa, descriptor_sp, name_hash); else - AddClass(isa, descriptor_sp, descriptor_sp->GetClassName().AsCString(nullptr)); + AddClass(isa, descriptor_sp, + descriptor_sp->GetClassName().AsCString(nullptr)); num_parsed++; if (should_log) LLDB_LOGF(log, @@ -1576,10 +1949,20 @@ uint32_t AppleObjCRuntimeV2::ParseClassInfoArray(const DataExtractor &data, return num_parsed; } -AppleObjCRuntimeV2::DescriptorMapUpdateResult -AppleObjCRuntimeV2::UpdateISAToDescriptorMapSharedCache() { - Process *process = GetProcess(); +bool AppleObjCRuntimeV2::HasSymbol(ConstString Name) { + if (!m_objc_module_sp) + return false; + if (const Symbol *symbol = m_objc_module_sp->FindFirstSymbolWithNameAndType( + Name, lldb::eSymbolTypeCode)) { + if (symbol->ValueIsAddress() || symbol->GetAddressRef().IsValid()) + return true; + } + return false; +} +AppleObjCRuntimeV2::DescriptorMapUpdateResult +AppleObjCRuntimeV2::SharedCacheClassInfoExtractor::UpdateISAToDescriptorMap() { + Process *process = m_runtime.GetProcess(); if (process == nullptr) return DescriptorMapUpdateResult::Fail(); @@ -1593,133 +1976,52 @@ AppleObjCRuntimeV2::UpdateISAToDescriptorMapSharedCache() { return DescriptorMapUpdateResult::Fail(); thread_sp->CalculateExecutionContext(exe_ctx); - TypeSystemClang *ast = TypeSystemClang::GetScratch(process->GetTarget()); + TypeSystemClang *ast = + ScratchTypeSystemClang::GetForTarget(process->GetTarget()); if (!ast) return DescriptorMapUpdateResult::Fail(); Address function_address; - DiagnosticManager diagnostics; - const uint32_t addr_size = process->GetAddressByteSize(); Status err; uint32_t num_class_infos = 0; - const lldb::addr_t objc_opt_ptr = GetSharedCacheReadOnlyAddress(); + const lldb::addr_t objc_opt_ptr = m_runtime.GetSharedCacheReadOnlyAddress(); + const lldb::addr_t shared_cache_base_addr = + m_runtime.GetSharedCacheBaseAddress(); - if (objc_opt_ptr == LLDB_INVALID_ADDRESS) + if (objc_opt_ptr == LLDB_INVALID_ADDRESS || + shared_cache_base_addr == LLDB_INVALID_ADDRESS) return DescriptorMapUpdateResult::Fail(); const uint32_t num_classes = 128 * 1024; - // Make some types for our arguments - CompilerType clang_uint32_t_type = - ast->GetBuiltinTypeForEncodingAndBitSize(eEncodingUint, 32); - CompilerType clang_void_pointer_type = - ast->GetBasicType(eBasicTypeVoid).GetPointerType(); - - ValueList arguments; - FunctionCaller *get_shared_cache_class_info_function = nullptr; - - if (!m_get_shared_cache_class_info_code) { - Status error; - - // If the inferior objc.dylib has the class_getNameRaw function, - // use that in our jitted expression. Else fall back to the old - // class_getName. - static ConstString g_class_getName_symbol_name("class_getName"); - static ConstString g_class_getNameRaw_symbol_name("objc_debug_class_getNameRaw"); - ConstString class_name_getter_function_name = g_class_getName_symbol_name; - - ObjCLanguageRuntime *objc_runtime = ObjCLanguageRuntime::Get(*process); - if (objc_runtime) { - const ModuleList &images = process->GetTarget().GetImages(); - std::lock_guard guard(images.GetMutex()); - for (size_t i = 0; i < images.GetSize(); ++i) { - lldb::ModuleSP mod_sp = images.GetModuleAtIndexUnlocked(i); - if (objc_runtime->IsModuleObjCLibrary(mod_sp)) { - const Symbol *symbol = - mod_sp->FindFirstSymbolWithNameAndType(g_class_getNameRaw_symbol_name, - lldb::eSymbolTypeCode); - if (symbol && - (symbol->ValueIsAddress() || symbol->GetAddressRef().IsValid())) { - class_name_getter_function_name = g_class_getNameRaw_symbol_name; - } - } - } - } - - // Substitute in the correct class_getName / class_getNameRaw function name, - // concatenate the two parts of our expression text. The format string - // has two %s's, so provide the name twice. - std::string shared_class_expression; - llvm::raw_string_ostream(shared_class_expression) << llvm::format( - g_shared_cache_class_name_funcptr, - class_name_getter_function_name.AsCString(), - class_name_getter_function_name.AsCString()); - - shared_class_expression += g_get_shared_cache_class_info_body; - - m_get_shared_cache_class_info_code.reset( - GetTargetRef().GetUtilityFunctionForLanguage( - shared_class_expression.c_str(), eLanguageTypeObjC, - g_get_shared_cache_class_info_name, error)); - if (error.Fail()) { - LLDB_LOGF(log, - "Failed to get Utility function for implementation lookup: %s.", - error.AsCString()); - m_get_shared_cache_class_info_code.reset(); - } else { - diagnostics.Clear(); - - if (!m_get_shared_cache_class_info_code->Install(diagnostics, exe_ctx)) { - if (log) { - LLDB_LOGF(log, "Failed to install implementation lookup."); - diagnostics.Dump(log); - } - m_get_shared_cache_class_info_code.reset(); - } - } + UtilityFunction *get_class_info_code = GetClassInfoUtilityFunction(exe_ctx); + FunctionCaller *get_shared_cache_class_info_function = + get_class_info_code->GetFunctionCaller(); - if (!m_get_shared_cache_class_info_code) - return DescriptorMapUpdateResult::Fail(); - - // Next make the function caller for our implementation utility function. - Value value; - value.SetValueType(Value::eValueTypeScalar); - value.SetCompilerType(clang_void_pointer_type); - arguments.PushValue(value); - arguments.PushValue(value); - - value.SetValueType(Value::eValueTypeScalar); - value.SetCompilerType(clang_uint32_t_type); - arguments.PushValue(value); - arguments.PushValue(value); - - get_shared_cache_class_info_function = - m_get_shared_cache_class_info_code->MakeFunctionCaller( - clang_uint32_t_type, arguments, thread_sp, error); - - if (get_shared_cache_class_info_function == nullptr) - return DescriptorMapUpdateResult::Fail(); - - } else { - get_shared_cache_class_info_function = - m_get_shared_cache_class_info_code->GetFunctionCaller(); - if (get_shared_cache_class_info_function == nullptr) - return DescriptorMapUpdateResult::Fail(); - arguments = get_shared_cache_class_info_function->GetArgumentValues(); + if (!get_shared_cache_class_info_function) { + LLDB_LOGF(log, "Failed to get implementation lookup function caller."); + return DescriptorMapUpdateResult::Fail(); } - diagnostics.Clear(); + ValueList arguments = + get_shared_cache_class_info_function->GetArgumentValues(); + + DiagnosticManager diagnostics; const uint32_t class_info_byte_size = addr_size + 4; const uint32_t class_infos_byte_size = num_classes * class_info_byte_size; lldb::addr_t class_infos_addr = process->AllocateMemory( class_infos_byte_size, ePermissionsReadable | ePermissionsWritable, err); + const uint32_t relative_selector_offset_addr_size = 64; + lldb::addr_t relative_selector_offset_addr = + process->AllocateMemory(relative_selector_offset_addr_size, + ePermissionsReadable | ePermissionsWritable, err); if (class_infos_addr == LLDB_INVALID_ADDRESS) { LLDB_LOGF(log, @@ -1729,18 +2031,20 @@ AppleObjCRuntimeV2::UpdateISAToDescriptorMapSharedCache() { return DescriptorMapUpdateResult::Fail(); } - std::lock_guard guard(m_get_shared_cache_class_info_args_mutex); + std::lock_guard guard(m_mutex); // Fill in our function argument values arguments.GetValueAtIndex(0)->GetScalar() = objc_opt_ptr; - arguments.GetValueAtIndex(1)->GetScalar() = class_infos_addr; - arguments.GetValueAtIndex(2)->GetScalar() = class_infos_byte_size; + arguments.GetValueAtIndex(1)->GetScalar() = shared_cache_base_addr; + arguments.GetValueAtIndex(2)->GetScalar() = class_infos_addr; + arguments.GetValueAtIndex(3)->GetScalar() = relative_selector_offset_addr; + arguments.GetValueAtIndex(4)->GetScalar() = class_infos_byte_size; // Only dump the runtime classes from the expression evaluation if the log is // verbose: Log *type_log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_TYPES); bool dump_log = type_log && type_log->GetVerbose(); - - arguments.GetValueAtIndex(3)->GetScalar() = dump_log ? 1 : 0; + + arguments.GetValueAtIndex(5)->GetScalar() = dump_log ? 1 : 0; bool success = false; @@ -1748,8 +2052,7 @@ AppleObjCRuntimeV2::UpdateISAToDescriptorMapSharedCache() { // Write our function arguments into the process so we can run our function if (get_shared_cache_class_info_function->WriteFunctionArguments( - exe_ctx, m_get_shared_cache_class_info_args, arguments, - diagnostics)) { + exe_ctx, m_args, arguments, diagnostics)) { EvaluateExpressionOptions options; options.SetUnwindOnError(true); options.SetTryAllThreads(false); @@ -1758,8 +2061,11 @@ AppleObjCRuntimeV2::UpdateISAToDescriptorMapSharedCache() { options.SetTimeout(process->GetUtilityExpressionTimeout()); options.SetIsForUtilityExpr(true); + CompilerType clang_uint32_t_type = + ast->GetBuiltinTypeForEncodingAndBitSize(eEncodingUint, 32); + Value return_value; - return_value.SetValueType(Value::eValueTypeScalar); + return_value.SetValueType(Value::ValueType::Scalar); return_value.SetCompilerType(clang_uint32_t_type); return_value.GetScalar() = 0; @@ -1768,14 +2074,13 @@ AppleObjCRuntimeV2::UpdateISAToDescriptorMapSharedCache() { // Run the function ExpressionResults results = get_shared_cache_class_info_function->ExecuteFunction( - exe_ctx, &m_get_shared_cache_class_info_args, options, diagnostics, - return_value); + exe_ctx, &m_args, options, diagnostics, return_value); if (results == eExpressionCompleted) { // The result is the number of ClassInfo structures that were filled in num_class_infos = return_value.GetScalar().ULong(); - LLDB_LOGF(log, "Discovered %u ObjC classes in shared cache\n", - num_class_infos); + LLDB_LOG(log, "Discovered {0} Objective-C classes in the shared cache", + num_class_infos); assert(num_class_infos <= num_classes); if (num_class_infos > 0) { if (num_class_infos > num_classes) { @@ -1786,16 +2091,38 @@ AppleObjCRuntimeV2::UpdateISAToDescriptorMapSharedCache() { success = true; } + // Read the relative selector offset. + DataBufferHeap relative_selector_offset_buffer(64, 0); + if (process->ReadMemory(relative_selector_offset_addr, + relative_selector_offset_buffer.GetBytes(), + relative_selector_offset_buffer.GetByteSize(), + err) == + relative_selector_offset_buffer.GetByteSize()) { + DataExtractor relative_selector_offset_data( + relative_selector_offset_buffer.GetBytes(), + relative_selector_offset_buffer.GetByteSize(), + process->GetByteOrder(), addr_size); + lldb::offset_t offset = 0; + uint64_t relative_selector_offset = + relative_selector_offset_data.GetU64(&offset); + if (relative_selector_offset > 0) { + // The offset is relative to the objc_opt struct. + m_runtime.SetRelativeSelectorBaseAddr(objc_opt_ptr + + relative_selector_offset); + } + } + // Read the ClassInfo structures - DataBufferHeap buffer(num_class_infos * class_info_byte_size, 0); - if (process->ReadMemory(class_infos_addr, buffer.GetBytes(), - buffer.GetByteSize(), - err) == buffer.GetByteSize()) { - DataExtractor class_infos_data(buffer.GetBytes(), - buffer.GetByteSize(), + DataBufferHeap class_infos_buffer( + num_class_infos * class_info_byte_size, 0); + if (process->ReadMemory(class_infos_addr, class_infos_buffer.GetBytes(), + class_infos_buffer.GetByteSize(), + err) == class_infos_buffer.GetByteSize()) { + DataExtractor class_infos_data(class_infos_buffer.GetBytes(), + class_infos_buffer.GetByteSize(), process->GetByteOrder(), addr_size); - ParseClassInfoArray(class_infos_data, num_class_infos); + m_runtime.ParseClassInfoArray(class_infos_data, num_class_infos); } } else { success = true; @@ -1819,42 +2146,6 @@ AppleObjCRuntimeV2::UpdateISAToDescriptorMapSharedCache() { return DescriptorMapUpdateResult(success, num_class_infos); } -bool AppleObjCRuntimeV2::UpdateISAToDescriptorMapFromMemory( - RemoteNXMapTable &hash_table) { - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_TYPES)); - - Process *process = GetProcess(); - - if (process == nullptr) - return false; - - uint32_t num_map_table_isas = 0; - - ModuleSP objc_module_sp(GetObjCModule()); - - if (objc_module_sp) { - for (RemoteNXMapTable::element elt : hash_table) { - ++num_map_table_isas; - - if (ISAIsCached(elt.second)) - continue; - - ClassDescriptorSP descriptor_sp = ClassDescriptorSP( - new ClassDescriptorV2(*this, elt.second, elt.first.AsCString())); - - if (log && log->GetVerbose()) - LLDB_LOGF(log, - "AppleObjCRuntimeV2 added (ObjCISA)0x%" PRIx64 - " (%s) from dynamic table to isa->descriptor cache", - elt.second, elt.first.AsCString()); - - AddClass(elt.second, descriptor_sp, elt.first.AsCString()); - } - } - - return num_map_table_isas > 0; -} - lldb::addr_t AppleObjCRuntimeV2::GetSharedCacheReadOnlyAddress() { Process *process = GetProcess(); @@ -1888,11 +2179,23 @@ lldb::addr_t AppleObjCRuntimeV2::GetSharedCacheReadOnlyAddress() { return LLDB_INVALID_ADDRESS; } +lldb::addr_t AppleObjCRuntimeV2::GetSharedCacheBaseAddress() { + StructuredData::ObjectSP info = m_process->GetSharedCacheInfo(); + if (!info) + return LLDB_INVALID_ADDRESS; + + StructuredData::Dictionary *info_dict = info->GetAsDictionary(); + if (!info_dict) + return LLDB_INVALID_ADDRESS; + + return info_dict->GetValueForKey("shared_cache_base_address") + ->GetIntegerValue(LLDB_INVALID_ADDRESS); +} + void AppleObjCRuntimeV2::UpdateISAToDescriptorMapIfNeeded() { - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_TYPES)); + LLDB_SCOPED_TIMER(); - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer(func_cat, LLVM_PRETTY_FUNCTION); + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_TYPES)); // Else we need to check with our process to see when the map was updated. Process *process = GetProcess(); @@ -1904,14 +2207,19 @@ void AppleObjCRuntimeV2::UpdateISAToDescriptorMapIfNeeded() { // map, whether it was successful or not. m_isa_to_descriptor_stop_id = process->GetStopID(); - if (!m_hash_signature.NeedsUpdate(process, this, hash_table)) + // Ask the runtime is the realized class generation count changed. Unlike + // the hash table, this accounts for lazily named classes. + const bool class_count_changed = RealizedClassGenerationCountChanged(); + + if (!m_hash_signature.NeedsUpdate(process, this, hash_table) && + !class_count_changed) return; m_hash_signature.UpdateSignature(hash_table); - // Grab the dynamically loaded objc classes from the hash table in memory + // Grab the dynamically loaded Objective-C classes from memory. DescriptorMapUpdateResult dynamic_update_result = - UpdateISAToDescriptorMapDynamic(hash_table); + m_dynamic_class_info_extractor.UpdateISAToDescriptorMap(hash_table); // Now get the objc classes that are baked into the Objective-C runtime in // the shared cache, but only once per process as this data never changes @@ -1927,7 +2235,7 @@ void AppleObjCRuntimeV2::UpdateISAToDescriptorMapIfNeeded() { const uint32_t num_classes_to_warn_at = 500; DescriptorMapUpdateResult shared_cache_update_result = - UpdateISAToDescriptorMapSharedCache(); + m_shared_cache_class_info_extractor.UpdateISAToDescriptorMap(); LLDB_LOGF(log, "attempted to read objc class data - results: " @@ -1957,6 +2265,35 @@ void AppleObjCRuntimeV2::UpdateISAToDescriptorMapIfNeeded() { } } +bool AppleObjCRuntimeV2::RealizedClassGenerationCountChanged() { + Process *process = GetProcess(); + if (!process) + return false; + + Status error; + uint64_t objc_debug_realized_class_generation_count = + ExtractRuntimeGlobalSymbol( + process, ConstString("objc_debug_realized_class_generation_count"), + GetObjCModule(), error); + if (error.Fail()) + return false; + + if (m_realized_class_generation_count == + objc_debug_realized_class_generation_count) + return false; + + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_TYPES)); + LLDB_LOG(log, + "objc_debug_realized_class_generation_count changed from {0} to {1}", + m_realized_class_generation_count, + objc_debug_realized_class_generation_count); + + m_realized_class_generation_count = + objc_debug_realized_class_generation_count; + + return true; +} + static bool DoesProcessHaveSharedCache(Process &process) { PlatformSP platform_sp = process.GetTarget().GetPlatform(); if (!platform_sp) @@ -2037,9 +2374,10 @@ lldb::addr_t AppleObjCRuntimeV2::LookupRuntimeSymbol(ConstString name) { const ConstString ivar_name_cs(class_and_ivar.second); const char *ivar_name_cstr = ivar_name_cs.AsCString(); - auto ivar_func = [&ret, ivar_name_cstr]( - const char *name, const char *type, lldb::addr_t offset_addr, - uint64_t size) -> lldb::addr_t { + auto ivar_func = [&ret, + ivar_name_cstr](const char *name, const char *type, + lldb::addr_t offset_addr, + uint64_t size) -> lldb::addr_t { if (!strcmp(name, ivar_name_cstr)) { ret = offset_addr; return true; @@ -2341,7 +2679,6 @@ ObjCLanguageRuntime::ClassDescriptorSP AppleObjCRuntimeV2::TaggedPointerVendorRuntimeAssisted::GetClassDescriptor( lldb::addr_t ptr) { ClassDescriptorSP actual_class_descriptor_sp; - uint64_t data_payload; uint64_t unobfuscated = (ptr) ^ m_runtime.GetTaggedPointerObfuscator(); if (!IsPossibleTaggedPointer(unobfuscated)) @@ -2369,12 +2706,15 @@ AppleObjCRuntimeV2::TaggedPointerVendorRuntimeAssisted::GetClassDescriptor( m_cache[slot] = actual_class_descriptor_sp; } - data_payload = + uint64_t data_payload = (((uint64_t)unobfuscated << m_objc_debug_taggedpointer_payload_lshift) >> m_objc_debug_taggedpointer_payload_rshift); - - return ClassDescriptorSP( - new ClassDescriptorV2Tagged(actual_class_descriptor_sp, data_payload)); + int64_t data_payload_signed = + ((int64_t)((int64_t)unobfuscated + << m_objc_debug_taggedpointer_payload_lshift) >> + m_objc_debug_taggedpointer_payload_rshift); + return ClassDescriptorSP(new ClassDescriptorV2Tagged( + actual_class_descriptor_sp, data_payload, data_payload_signed)); } AppleObjCRuntimeV2::TaggedPointerVendorExtended::TaggedPointerVendorExtended( @@ -2426,7 +2766,6 @@ ObjCLanguageRuntime::ClassDescriptorSP AppleObjCRuntimeV2::TaggedPointerVendorExtended::GetClassDescriptor( lldb::addr_t ptr) { ClassDescriptorSP actual_class_descriptor_sp; - uint64_t data_payload; uint64_t unobfuscated = (ptr) ^ m_runtime.GetTaggedPointerObfuscator(); if (!IsPossibleTaggedPointer(unobfuscated)) @@ -2457,12 +2796,16 @@ AppleObjCRuntimeV2::TaggedPointerVendorExtended::GetClassDescriptor( m_ext_cache[slot] = actual_class_descriptor_sp; } - data_payload = - (((uint64_t)unobfuscated << m_objc_debug_taggedpointer_ext_payload_lshift) >> + uint64_t data_payload = (((uint64_t)unobfuscated + << m_objc_debug_taggedpointer_ext_payload_lshift) >> + m_objc_debug_taggedpointer_ext_payload_rshift); + int64_t data_payload_signed = + ((int64_t)((int64_t)unobfuscated + << m_objc_debug_taggedpointer_ext_payload_lshift) >> m_objc_debug_taggedpointer_ext_payload_rshift); - return ClassDescriptorSP( - new ClassDescriptorV2Tagged(actual_class_descriptor_sp, data_payload)); + return ClassDescriptorSP(new ClassDescriptorV2Tagged( + actual_class_descriptor_sp, data_payload, data_payload_signed)); } AppleObjCRuntimeV2::NonPointerISACache::NonPointerISACache( @@ -2614,8 +2957,8 @@ lldb_private::AppleObjCRuntime::ObjCISA AppleObjCRuntimeV2::GetPointerISA(ObjCISA isa) { ObjCISA ret = isa; - if (m_non_pointer_isa_cache_up) - m_non_pointer_isa_cache_up->EvaluateNonPointerISA(isa, ret); + if (auto *non_pointer_isa_cache = GetNonPointerIsaCache()) + non_pointer_isa_cache->EvaluateNonPointerISA(isa, ret); return ret; } @@ -2660,16 +3003,17 @@ void AppleObjCRuntimeV2::GetValuesForGlobalCFBooleans(lldb::addr_t &cf_true, #pragma mark Frame recognizers class ObjCExceptionRecognizedStackFrame : public RecognizedStackFrame { - public: +public: ObjCExceptionRecognizedStackFrame(StackFrameSP frame_sp) { ThreadSP thread_sp = frame_sp->GetThread(); ProcessSP process_sp = thread_sp->GetProcess(); const lldb::ABISP &abi = process_sp->GetABI(); - if (!abi) return; + if (!abi) + return; TypeSystemClang *clang_ast_context = - TypeSystemClang::GetScratch(process_sp->GetTarget()); + ScratchTypeSystemClang::GetForTarget(process_sp->GetTarget()); if (!clang_ast_context) return; CompilerType voidstar = @@ -2680,7 +3024,8 @@ class ObjCExceptionRecognizedStackFrame : public RecognizedStackFrame { input_value.SetCompilerType(voidstar); args.PushValue(input_value); - if (!abi->GetArgumentValues(*thread_sp, args)) return; + if (!abi->GetArgumentValues(*thread_sp, args)) + return; addr_t exception_addr = args.GetValueAtIndex(0)->GetScalar().ULongLong(); @@ -2709,18 +3054,19 @@ class ObjCExceptionThrowFrameRecognizer : public StackFrameRecognizer { return lldb::RecognizedStackFrameSP( new ObjCExceptionRecognizedStackFrame(frame)); }; + std::string GetName() override { + return "ObjC Exception Throw StackFrame Recognizer"; + } }; -static void RegisterObjCExceptionRecognizer() { - static llvm::once_flag g_once_flag; - llvm::call_once(g_once_flag, []() { - FileSpec module; - ConstString function; - std::tie(module, function) = AppleObjCRuntime::GetExceptionThrowLocation(); - std::vector symbols = {function}; - StackFrameRecognizerManager::AddRecognizer( - StackFrameRecognizerSP(new ObjCExceptionThrowFrameRecognizer()), - module.GetFilename(), symbols, - /*first_instruction_only*/ true); - }); +static void RegisterObjCExceptionRecognizer(Process *process) { + FileSpec module; + ConstString function; + std::tie(module, function) = AppleObjCRuntime::GetExceptionThrowLocation(); + std::vector symbols = {function}; + + process->GetTarget().GetFrameRecognizerManager().AddRecognizer( + StackFrameRecognizerSP(new ObjCExceptionThrowFrameRecognizer()), + module.GetFilename(), symbols, + /*first_instruction_only*/ true); } diff --git a/gnu/llvm/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h b/gnu/llvm/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h index 99264d556da..d0caa296911 100644 --- a/gnu/llvm/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h +++ b/gnu/llvm/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h @@ -26,7 +26,6 @@ class AppleObjCRuntimeV2 : public AppleObjCRuntime { public: ~AppleObjCRuntimeV2() override = default; - // Static Functions static void Initialize(); static void Terminate(); @@ -46,16 +45,15 @@ public: return runtime->isA(&ID); } - // These are generic runtime functions: bool GetDynamicTypeAndAddress(ValueObject &in_value, lldb::DynamicValueType use_dynamic, TypeAndOrName &class_type_or_name, Address &address, Value::ValueType &value_type) override; - UtilityFunction *CreateObjectChecker(const char *) override; + llvm::Expected> + CreateObjectChecker(std::string name, ExecutionContext &exe_ctx) override; - // PluginInterface protocol ConstString GetPluginName() override; uint32_t GetPluginVersion() override; @@ -87,6 +85,15 @@ public: lldb::addr_t GetTaggedPointerObfuscator(); + /// Returns the base address for relative method list selector strings. + lldb::addr_t GetRelativeSelectorBaseAddr() { + return m_relative_selector_base; + } + + void SetRelativeSelectorBaseAddr(lldb::addr_t relative_selector_base) { + m_relative_selector_base = relative_selector_base; + } + void GetValuesForGlobalCFBooleans(lldb::addr_t &cf_true, lldb::addr_t &cf_false) override; @@ -104,8 +111,8 @@ public: protected: lldb::BreakpointResolverSP - CreateExceptionResolver(const lldb::BreakpointSP &bkpt, - bool catch_bp, bool throw_bp) override; + CreateExceptionResolver(const lldb::BreakpointSP &bkpt, bool catch_bp, + bool throw_bp) override; private: class HashTableSignature { @@ -118,9 +125,9 @@ private: void UpdateSignature(const RemoteNXMapTable &hash_table); protected: - uint32_t m_count; - uint32_t m_num_buckets; - lldb::addr_t m_buckets_ptr; + uint32_t m_count = 0; + uint32_t m_num_buckets = 0; + lldb::addr_t m_buckets_ptr = 0; }; class NonPointerISACache { @@ -295,22 +302,99 @@ private: } }; + /// Abstraction to read the Objective-C class info. + class ClassInfoExtractor { + public: + ClassInfoExtractor(AppleObjCRuntimeV2 &runtime) : m_runtime(runtime) {} + std::mutex &GetMutex() { return m_mutex; } + + protected: + /// The lifetime of this object is tied to that of the runtime. + AppleObjCRuntimeV2 &m_runtime; + std::mutex m_mutex; + }; + + /// We can read the class info from the Objective-C runtime using + /// gdb_objc_realized_classes or objc_copyRealizedClassList. The latter is + /// preferred because it includes lazily named classes, but it's not always + /// available or safe to call. + /// + /// We potentially need both for the same process, because we may need to use + /// gdb_objc_realized_classes until dyld is initialized and then switch over + /// to objc_copyRealizedClassList for lazily named classes. + class DynamicClassInfoExtractor : public ClassInfoExtractor { + public: + DynamicClassInfoExtractor(AppleObjCRuntimeV2 &runtime) + : ClassInfoExtractor(runtime) {} + + DescriptorMapUpdateResult + UpdateISAToDescriptorMap(RemoteNXMapTable &hash_table); + + private: + enum Helper { gdb_objc_realized_classes, objc_copyRealizedClassList }; + + /// Compute which helper to use. Prefer objc_copyRealizedClassList if it's + /// available and it's safe to call (i.e. dyld is fully initialized). Use + /// gdb_objc_realized_classes otherwise. + Helper ComputeHelper() const; + + UtilityFunction *GetClassInfoUtilityFunction(ExecutionContext &exe_ctx, + Helper helper); + lldb::addr_t &GetClassInfoArgs(Helper helper); + + std::unique_ptr + GetClassInfoUtilityFunctionImpl(ExecutionContext &exe_ctx, std::string code, + std::string name); + + /// Helper to read class info using the gdb_objc_realized_classes. + struct gdb_objc_realized_classes_helper { + std::unique_ptr utility_function; + lldb::addr_t args = LLDB_INVALID_ADDRESS; + }; + + /// Helper to read class info using objc_copyRealizedClassList. + struct objc_copyRealizedClassList_helper { + std::unique_ptr utility_function; + lldb::addr_t args = LLDB_INVALID_ADDRESS; + }; + + gdb_objc_realized_classes_helper m_gdb_objc_realized_classes_helper; + objc_copyRealizedClassList_helper m_objc_copyRealizedClassList_helper; + }; + + /// Abstraction to read the Objective-C class info from the shared cache. + class SharedCacheClassInfoExtractor : public ClassInfoExtractor { + public: + SharedCacheClassInfoExtractor(AppleObjCRuntimeV2 &runtime) + : ClassInfoExtractor(runtime) {} + + DescriptorMapUpdateResult UpdateISAToDescriptorMap(); + + private: + UtilityFunction *GetClassInfoUtilityFunction(ExecutionContext &exe_ctx); + + std::unique_ptr + GetClassInfoUtilityFunctionImpl(ExecutionContext &exe_ctx); + + std::unique_ptr m_utility_function; + lldb::addr_t m_args = LLDB_INVALID_ADDRESS; + }; + AppleObjCRuntimeV2(Process *process, const lldb::ModuleSP &objc_module_sp); ObjCISA GetPointerISA(ObjCISA isa); lldb::addr_t GetISAHashTablePointer(); - bool UpdateISAToDescriptorMapFromMemory(RemoteNXMapTable &hash_table); - - DescriptorMapUpdateResult - UpdateISAToDescriptorMapDynamic(RemoteNXMapTable &hash_table); + /// Update the generation count of realized classes. This is not an exact + /// count but rather a value that is incremented when new classes are realized + /// or destroyed. Unlike the count in gdb_objc_realized_classes, it will + /// change when lazily named classes get realized. + bool RealizedClassGenerationCountChanged(); uint32_t ParseClassInfoArray(const lldb_private::DataExtractor &data, uint32_t num_class_infos); - DescriptorMapUpdateResult UpdateISAToDescriptorMapSharedCache(); - enum class SharedCacheWarningReason { eExpressionExecutionFailure, eNotEnoughClassesRead @@ -319,30 +403,40 @@ private: void WarnIfNoClassesCached(SharedCacheWarningReason reason); lldb::addr_t GetSharedCacheReadOnlyAddress(); + lldb::addr_t GetSharedCacheBaseAddress(); bool GetCFBooleanValuesIfNeeded(); + bool HasSymbol(ConstString Name); + + NonPointerISACache *GetNonPointerIsaCache() { + if (!m_non_pointer_isa_cache_up) + m_non_pointer_isa_cache_up.reset( + NonPointerISACache::CreateInstance(*this, m_objc_module_sp)); + return m_non_pointer_isa_cache_up.get(); + } + friend class ClassDescriptorV2; - std::unique_ptr m_get_class_info_code; - lldb::addr_t m_get_class_info_args; - std::mutex m_get_class_info_args_mutex; + lldb::ModuleSP m_objc_module_sp; - std::unique_ptr m_get_shared_cache_class_info_code; - lldb::addr_t m_get_shared_cache_class_info_args; - std::mutex m_get_shared_cache_class_info_args_mutex; + DynamicClassInfoExtractor m_dynamic_class_info_extractor; + SharedCacheClassInfoExtractor m_shared_cache_class_info_extractor; std::unique_ptr m_decl_vendor_up; lldb::addr_t m_tagged_pointer_obfuscator; lldb::addr_t m_isa_hash_table_ptr; + lldb::addr_t m_relative_selector_base; HashTableSignature m_hash_signature; bool m_has_object_getClass; + bool m_has_objc_copyRealizedClassList; bool m_loaded_objc_opt; std::unique_ptr m_non_pointer_isa_cache_up; std::unique_ptr m_tagged_pointer_vendor_up; EncodingToTypeSP m_encoding_to_type_sp; bool m_noclasses_warning_emitted; llvm::Optional> m_CFBoolean_values; + uint64_t m_realized_class_generation_count; }; } // namespace lldb_private diff --git a/gnu/llvm/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.cpp b/gnu/llvm/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.cpp index c96768c9f58..aa6306bef8b 100644 --- a/gnu/llvm/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.cpp +++ b/gnu/llvm/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.cpp @@ -285,7 +285,7 @@ AppleObjCTrampolineHandler::AppleObjCVTables::VTableRegion::VTableRegion( SetUpRegion(); } -AppleObjCTrampolineHandler::~AppleObjCTrampolineHandler() {} +AppleObjCTrampolineHandler::~AppleObjCTrampolineHandler() = default; void AppleObjCTrampolineHandler::AppleObjCVTables::VTableRegion::SetUpRegion() { // The header looks like: @@ -452,15 +452,11 @@ bool AppleObjCTrampolineHandler::AppleObjCVTables::InitializeVTableSymbols() { if (process_sp) { Target &target = process_sp->GetTarget(); - const ModuleList &target_modules = target.GetImages(); - std::lock_guard guard(target_modules.GetMutex()); - size_t num_modules = target_modules.GetSize(); if (!m_objc_module_sp) { - for (size_t i = 0; i < num_modules; i++) { + for (ModuleSP module_sp : target.GetImages().Modules()) { if (ObjCLanguageRuntime::Get(*process_sp) - ->IsModuleObjCLibrary( - target_modules.GetModuleAtIndexUnlocked(i))) { - m_objc_module_sp = target_modules.GetModuleAtIndexUnlocked(i); + ->IsModuleObjCLibrary(module_sp)) { + m_objc_module_sp = module_sp; break; } } @@ -521,7 +517,7 @@ bool AppleObjCTrampolineHandler::AppleObjCVTables::RefreshTrampolines( const ABI *abi = process->GetABI().get(); TypeSystemClang *clang_ast_context = - TypeSystemClang::GetScratch(process->GetTarget()); + ScratchTypeSystemClang::GetForTarget(process->GetTarget()); if (!clang_ast_context) return false; @@ -530,7 +526,7 @@ bool AppleObjCTrampolineHandler::AppleObjCVTables::RefreshTrampolines( CompilerType clang_void_ptr_type = clang_ast_context->GetBasicType(eBasicTypeVoid).GetPointerType(); - input_value.SetValueType(Value::eValueTypeScalar); + input_value.SetValueType(Value::ValueType::Scalar); // input_value.SetContext (Value::eContextTypeClangType, // clang_void_ptr_type); input_value.SetCompilerType(clang_void_ptr_type); @@ -798,7 +794,6 @@ AppleObjCTrampolineHandler::SetupDispatchFunction(Thread &thread, ValueList &dispatch_values) { ThreadSP thread_sp(thread.shared_from_this()); ExecutionContext exe_ctx(thread_sp); - DiagnosticManager diagnostics; Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); lldb::addr_t args_addr = LLDB_INVALID_ADDRESS; @@ -812,35 +807,24 @@ AppleObjCTrampolineHandler::SetupDispatchFunction(Thread &thread, if (!m_impl_code) { if (m_lookup_implementation_function_code != nullptr) { - Status error; - m_impl_code.reset(exe_ctx.GetTargetRef().GetUtilityFunctionForLanguage( - m_lookup_implementation_function_code, eLanguageTypeObjC, - g_lookup_implementation_function_name, error)); - if (error.Fail()) { - LLDB_LOGF( - log, - "Failed to get Utility Function for implementation lookup: %s.", - error.AsCString()); - m_impl_code.reset(); - return args_addr; - } - - if (!m_impl_code->Install(diagnostics, exe_ctx)) { - if (log) { - LLDB_LOGF(log, "Failed to install implementation lookup."); - diagnostics.Dump(log); - } - m_impl_code.reset(); + auto utility_fn_or_error = exe_ctx.GetTargetRef().CreateUtilityFunction( + m_lookup_implementation_function_code, + g_lookup_implementation_function_name, eLanguageTypeC, exe_ctx); + if (!utility_fn_or_error) { + LLDB_LOG_ERROR( + log, utility_fn_or_error.takeError(), + "Failed to get Utility Function for implementation lookup: {0}."); return args_addr; } + m_impl_code = std::move(*utility_fn_or_error); } else { LLDB_LOGF(log, "No method lookup implementation code."); return LLDB_INVALID_ADDRESS; } // Next make the runner function for our implementation utility function. - TypeSystemClang *clang_ast_context = - TypeSystemClang::GetScratch(thread.GetProcess()->GetTarget()); + TypeSystemClang *clang_ast_context = ScratchTypeSystemClang::GetForTarget( + thread.GetProcess()->GetTarget()); if (!clang_ast_context) return LLDB_INVALID_ADDRESS; @@ -861,14 +845,13 @@ AppleObjCTrampolineHandler::SetupDispatchFunction(Thread &thread, } } - diagnostics.Clear(); - // Now write down the argument values for this particular call. // This looks like it might be a race condition if other threads // were calling into here, but actually it isn't because we allocate // a new args structure for this call by passing args_addr = // LLDB_INVALID_ADDRESS... + DiagnosticManager diagnostics; if (!impl_function_caller->WriteFunctionArguments( exe_ctx, args_addr, dispatch_values, diagnostics)) { if (log) { @@ -944,7 +927,8 @@ AppleObjCTrampolineHandler::GetStepThroughDispatchPlan(Thread &thread, TargetSP target_sp(thread.CalculateTarget()); - TypeSystemClang *clang_ast_context = TypeSystemClang::GetScratch(*target_sp); + TypeSystemClang *clang_ast_context = + ScratchTypeSystemClang::GetForTarget(*target_sp); if (!clang_ast_context) return ret_plan_sp; @@ -952,7 +936,7 @@ AppleObjCTrampolineHandler::GetStepThroughDispatchPlan(Thread &thread, Value void_ptr_value; CompilerType clang_void_ptr_type = clang_ast_context->GetBasicType(eBasicTypeVoid).GetPointerType(); - void_ptr_value.SetValueType(Value::eValueTypeScalar); + void_ptr_value.SetValueType(Value::ValueType::Scalar); // void_ptr_value.SetContext (Value::eContextTypeClangType, // clang_void_ptr_type); void_ptr_value.SetCompilerType(clang_void_ptr_type); @@ -1064,7 +1048,7 @@ AppleObjCTrampolineHandler::GetStepThroughDispatchPlan(Thread &thread, Value isa_value(*(argument_values.GetValueAtIndex(obj_index))); - isa_value.SetValueType(Value::eValueTypeLoadAddress); + isa_value.SetValueType(Value::ValueType::LoadAddress); isa_value.ResolveValue(&exe_ctx); if (isa_value.GetScalar().IsValid()) { isa_addr = isa_value.GetScalar().ULongLong(); @@ -1126,7 +1110,7 @@ AppleObjCTrampolineHandler::GetStepThroughDispatchPlan(Thread &thread, CompilerType clang_int_type = clang_ast_context->GetBuiltinTypeForEncodingAndBitSize( lldb::eEncodingSint, 32); - flag_value.SetValueType(Value::eValueTypeScalar); + flag_value.SetValueType(Value::ValueType::Scalar); // flag_value.SetContext (Value::eContextTypeClangType, clang_int_type); flag_value.SetCompilerType(clang_int_type); @@ -1173,13 +1157,8 @@ AppleObjCTrampolineHandler::GetStepThroughDispatchPlan(Thread &thread, flag_value.GetScalar() = 0; // FIXME - Set to 0 when debugging is done. dispatch_values.PushValue(flag_value); - // The step through code might have to fill in the cache, so it - // is not safe to run only one thread. So we override the - // stop_others value passed in to us here: - const bool trampoline_stop_others = false; ret_plan_sp = std::make_shared( - thread, *this, dispatch_values, isa_addr, sel_addr, - trampoline_stop_others); + thread, *this, dispatch_values, isa_addr, sel_addr); if (log) { StreamString s; ret_plan_sp->GetDescription(&s, eDescriptionLevelFull); @@ -1198,13 +1177,9 @@ AppleObjCTrampolineHandler::GetStepThroughDispatchPlan(Thread &thread, MsgsendMap::iterator pos; pos = m_opt_dispatch_map.find(curr_pc); if (pos != m_opt_dispatch_map.end()) { - const char *opt_name = g_opt_dispatch_names[(*pos).second]; - - bool trampoline_stop_others = false; - LazyBool step_in_should_stop = eLazyBoolCalculate; - ret_plan_sp = std::make_shared ( - thread, *this, opt_name, trampoline_stop_others, step_in_should_stop); + ret_plan_sp = std::make_shared( + thread, *this, opt_name); } } diff --git a/gnu/llvm/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.h b/gnu/llvm/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.h index 27aebd8594d..546b500b452 100644 --- a/gnu/llvm/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.h +++ b/gnu/llvm/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.h @@ -76,10 +76,7 @@ private: class VTableRegion { public: - VTableRegion() - : m_valid(false), m_owner(nullptr), - m_header_addr(LLDB_INVALID_ADDRESS), m_code_start_addr(0), - m_code_end_addr(0), m_next_region(0) {} + VTableRegion() = default; VTableRegion(AppleObjCVTables *owner, lldb::addr_t header_addr); @@ -99,13 +96,13 @@ private: void Dump(Stream &s); - bool m_valid; - AppleObjCVTables *m_owner; - lldb::addr_t m_header_addr; - lldb::addr_t m_code_start_addr; - lldb::addr_t m_code_end_addr; + bool m_valid = false; + AppleObjCVTables *m_owner = nullptr; + lldb::addr_t m_header_addr = LLDB_INVALID_ADDRESS; + lldb::addr_t m_code_start_addr = 0; + lldb::addr_t m_code_end_addr = 0; std::vector m_descriptors; - lldb::addr_t m_next_region; + lldb::addr_t m_next_region = 0; }; public: diff --git a/gnu/llvm/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTypeEncodingParser.cpp b/gnu/llvm/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTypeEncodingParser.cpp index b19d3d90d4b..7b0121503bc 100644 --- a/gnu/llvm/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTypeEncodingParser.cpp +++ b/gnu/llvm/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTypeEncodingParser.cpp @@ -59,7 +59,7 @@ uint32_t AppleObjCTypeEncodingParser::ReadNumber(StringLexer &type) { // "{CGRect=\"origin\"{CGPoint=\"x\"d\"y\"d}\"size\"{CGSize=\"width\"d\"height\"d}}" AppleObjCTypeEncodingParser::StructElement::StructElement() - : name(""), type(clang::QualType()), bitfield(0) {} + : name(""), type(clang::QualType()) {} AppleObjCTypeEncodingParser::StructElement AppleObjCTypeEncodingParser::ReadStructElement(TypeSystemClang &ast_ctx, diff --git a/gnu/llvm/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTypeEncodingParser.h b/gnu/llvm/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTypeEncodingParser.h index 9a108967e1a..6e533b591ec 100644 --- a/gnu/llvm/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTypeEncodingParser.h +++ b/gnu/llvm/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTypeEncodingParser.h @@ -29,7 +29,7 @@ private: struct StructElement { std::string name; clang::QualType type; - uint32_t bitfield; + uint32_t bitfield = 0; StructElement(); ~StructElement() = default; diff --git a/gnu/llvm/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.cpp b/gnu/llvm/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.cpp index 653e007c7b5..1dc8034c537 100644 --- a/gnu/llvm/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.cpp +++ b/gnu/llvm/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.cpp @@ -30,19 +30,17 @@ using namespace lldb_private; AppleThreadPlanStepThroughObjCTrampoline:: AppleThreadPlanStepThroughObjCTrampoline( Thread &thread, AppleObjCTrampolineHandler &trampoline_handler, - ValueList &input_values, lldb::addr_t isa_addr, lldb::addr_t sel_addr, - bool stop_others) + ValueList &input_values, lldb::addr_t isa_addr, lldb::addr_t sel_addr) : ThreadPlan(ThreadPlan::eKindGeneric, "MacOSX Step through ObjC Trampoline", thread, eVoteNoOpinion, eVoteNoOpinion), m_trampoline_handler(trampoline_handler), m_args_addr(LLDB_INVALID_ADDRESS), m_input_values(input_values), - m_isa_addr(isa_addr), m_sel_addr(sel_addr), m_impl_function(nullptr), - m_stop_others(stop_others) {} + m_isa_addr(isa_addr), m_sel_addr(sel_addr), m_impl_function(nullptr) {} // Destructor AppleThreadPlanStepThroughObjCTrampoline:: - ~AppleThreadPlanStepThroughObjCTrampoline() {} + ~AppleThreadPlanStepThroughObjCTrampoline() = default; void AppleThreadPlanStepThroughObjCTrampoline::DidPush() { // Setting up the memory space for the called function text might require @@ -66,7 +64,7 @@ bool AppleThreadPlanStepThroughObjCTrampoline::InitializeFunctionCaller() { EvaluateExpressionOptions options; options.SetUnwindOnError(true); options.SetIgnoreBreakpoints(true); - options.SetStopOthers(m_stop_others); + options.SetStopOthers(false); GetThread().CalculateExecutionContext(exc_ctx); m_func_sp = m_impl_function->GetThreadPlanToCallFunction( exc_ctx, m_args_addr, options, diagnostics); @@ -157,7 +155,7 @@ bool AppleThreadPlanStepThroughObjCTrampoline::ShouldStop(Event *event_ptr) { const bool first_insn = true; const uint32_t frame_idx = 0; m_run_to_sp = GetThread().QueueThreadPlanForStepOutNoShouldStop( - abort_other_plans, &sc, first_insn, m_stop_others, eVoteNoOpinion, + abort_other_plans, &sc, first_insn, false, eVoteNoOpinion, eVoteNoOpinion, frame_idx, status); if (m_run_to_sp && status.Success()) m_run_to_sp->SetPrivate(true); @@ -179,7 +177,7 @@ bool AppleThreadPlanStepThroughObjCTrampoline::ShouldStop(Event *event_ptr) { // Extract the target address from the value: m_run_to_sp = std::make_shared( - GetThread(), target_so_addr, m_stop_others); + GetThread(), target_so_addr, false); PushPlan(m_run_to_sp); return false; } else if (GetThread().IsThreadPlanDone(m_run_to_sp.get())) { @@ -222,10 +220,9 @@ bool AppleThreadPlanStepThroughObjCTrampoline::WillStop() { return true; } AppleThreadPlanStepThroughDirectDispatch :: AppleThreadPlanStepThroughDirectDispatch( Thread &thread, AppleObjCTrampolineHandler &handler, - llvm::StringRef dispatch_func_name, bool stop_others, - LazyBool step_in_avoids_code_without_debug_info) - : ThreadPlanStepOut(thread, nullptr, true /* first instruction */, - stop_others, eVoteNoOpinion, eVoteNoOpinion, + llvm::StringRef dispatch_func_name) + : ThreadPlanStepOut(thread, nullptr, true /* first instruction */, false, + eVoteNoOpinion, eVoteNoOpinion, 0 /* Step out of zeroth frame */, eLazyBoolNo /* Our parent plan will decide this when we are done */ @@ -234,7 +231,7 @@ AppleThreadPlanStepThroughDirectDispatch :: false /* Don't gather the return value */), m_trampoline_handler(handler), m_dispatch_func_name(std::string(dispatch_func_name)), - m_at_msg_send(false), m_stop_others(stop_others) { + m_at_msg_send(false) { // Set breakpoints on the dispatch functions: auto bkpt_callback = [&] (lldb::addr_t addr, const AppleObjCTrampolineHandler @@ -249,20 +246,7 @@ AppleThreadPlanStepThroughDirectDispatch :: // We'll set the step-out plan in the DidPush so it gets queued in the right // order. - bool avoid_nodebug = true; - - switch (step_in_avoids_code_without_debug_info) { - case eLazyBoolYes: - avoid_nodebug = true; - break; - case eLazyBoolNo: - avoid_nodebug = false; - break; - case eLazyBoolCalculate: - avoid_nodebug = GetThread().GetStepInAvoidsNoDebug(); - break; - } - if (avoid_nodebug) + if (GetThread().GetStepInAvoidsNoDebug()) GetFlags().Set(ThreadPlanShouldStopHere::eStepInAvoidNoDebug); else GetFlags().Clear(ThreadPlanShouldStopHere::eStepInAvoidNoDebug); @@ -398,8 +382,8 @@ bool AppleThreadPlanStepThroughDirectDispatch::ShouldStop(Event *event_ptr) { // There's no way we could have gotten here without an ObjC language // runtime. assert(objc_runtime); - m_objc_step_through_sp - = objc_runtime->GetStepThroughTrampolinePlan(GetThread(), m_stop_others); + m_objc_step_through_sp = + objc_runtime->GetStepThroughTrampolinePlan(GetThread(), false); // If we failed to find the target for this dispatch, just keep going and // let the step out complete. if (!m_objc_step_through_sp) { diff --git a/gnu/llvm/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.h b/gnu/llvm/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.h index 89aed89f1ab..b5b45079094 100644 --- a/gnu/llvm/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.h +++ b/gnu/llvm/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleThreadPlanStepThroughObjCTrampoline.h @@ -24,8 +24,7 @@ class AppleThreadPlanStepThroughObjCTrampoline : public ThreadPlan { public: AppleThreadPlanStepThroughObjCTrampoline( Thread &thread, AppleObjCTrampolineHandler &trampoline_handler, - ValueList &values, lldb::addr_t isa_addr, lldb::addr_t sel_addr, - bool stop_others); + ValueList &values, lldb::addr_t isa_addr, lldb::addr_t sel_addr); ~AppleThreadPlanStepThroughObjCTrampoline() override; @@ -39,7 +38,9 @@ public: bool ShouldStop(Event *event_ptr) override; - bool StopOthers() override { return m_stop_others; } + // The step through code might have to fill in the cache, so it is not safe + // to run only one thread. + bool StopOthers() override { return false; } // The base class MischiefManaged does some cleanup - so you have to call it // in your MischiefManaged derived class. @@ -69,15 +70,13 @@ private: FunctionCaller *m_impl_function; /// This is a pointer to a impl function that /// is owned by the client that pushes this /// plan. - bool m_stop_others; /// Whether we should stop other threads. }; class AppleThreadPlanStepThroughDirectDispatch: public ThreadPlanStepOut { public: - AppleThreadPlanStepThroughDirectDispatch( - Thread &thread, AppleObjCTrampolineHandler &handler, - llvm::StringRef dispatch_func_name, bool stop_others, - LazyBool step_in_avoids_code_without_debug_info); + AppleThreadPlanStepThroughDirectDispatch(Thread &thread, + AppleObjCTrampolineHandler &handler, + llvm::StringRef dispatch_func_name); ~AppleThreadPlanStepThroughDirectDispatch() override; @@ -85,7 +84,7 @@ public: bool ShouldStop(Event *event_ptr) override; - bool StopOthers() override { return m_stop_others; } + bool StopOthers() override { return false; } bool MischiefManaged() override; @@ -107,7 +106,6 @@ protected: std::vector m_msgSend_bkpts; /// Breakpoints on the objc /// dispatch functions. bool m_at_msg_send; /// Are we currently handling an msg_send - bool m_stop_others; /// Whether we should stop other threads. }; diff --git a/gnu/llvm/lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.cpp b/gnu/llvm/lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.cpp index 2ccf9b33f9d..65bf3e6af62 100644 --- a/gnu/llvm/lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.cpp +++ b/gnu/llvm/lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.cpp @@ -32,7 +32,7 @@ using namespace lldb_private; char ObjCLanguageRuntime::ID = 0; // Destructor -ObjCLanguageRuntime::~ObjCLanguageRuntime() {} +ObjCLanguageRuntime::~ObjCLanguageRuntime() = default; ObjCLanguageRuntime::ObjCLanguageRuntime(Process *process) : LanguageRuntime(process), m_impl_cache(), @@ -305,7 +305,7 @@ ObjCLanguageRuntime::EncodingToType::RealizeType(const char *name, return CompilerType(); } -ObjCLanguageRuntime::EncodingToType::~EncodingToType() {} +ObjCLanguageRuntime::EncodingToType::~EncodingToType() = default; ObjCLanguageRuntime::EncodingToTypeSP ObjCLanguageRuntime::GetEncodingToType() { return nullptr; @@ -363,7 +363,8 @@ void ObjCLanguageRuntime::ObjCExceptionPrecondition::AddClassName( m_class_names.insert(class_name); } -ObjCLanguageRuntime::ObjCExceptionPrecondition::ObjCExceptionPrecondition() {} +ObjCLanguageRuntime::ObjCExceptionPrecondition::ObjCExceptionPrecondition() = + default; bool ObjCLanguageRuntime::ObjCExceptionPrecondition::EvaluatePrecondition( StoppointCallbackContext &context) { diff --git a/gnu/llvm/lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h b/gnu/llvm/lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h index c43acf54bbc..15fce04ea46 100644 --- a/gnu/llvm/lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h +++ b/gnu/llvm/lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h @@ -49,9 +49,7 @@ public: // implementations of the runtime, and more might come class ClassDescriptor { public: - ClassDescriptor() - : m_is_kvo(eLazyBoolCalculate), m_is_cf(eLazyBoolCalculate), - m_type_wp() {} + ClassDescriptor() : m_type_wp() {} virtual ~ClassDescriptor() = default; @@ -87,10 +85,20 @@ public: virtual bool IsValid() = 0; + /// There are two routines in the ObjC runtime that tagged pointer clients + /// can call to get the value from their tagged pointer, one that retrieves + /// it as an unsigned value and one a signed value. These two + /// GetTaggedPointerInfo methods mirror those two ObjC runtime calls. + /// @{ virtual bool GetTaggedPointerInfo(uint64_t *info_bits = nullptr, uint64_t *value_bits = nullptr, uint64_t *payload = nullptr) = 0; + virtual bool GetTaggedPointerInfoSigned(uint64_t *info_bits = nullptr, + int64_t *value_bits = nullptr, + uint64_t *payload = nullptr) = 0; + /// @} + virtual uint64_t GetInstanceSize() = 0; // use to implement version-specific additional constraints on pointers @@ -135,8 +143,8 @@ public: bool check_version_specific = false) const; private: - LazyBool m_is_kvo; - LazyBool m_is_cf; + LazyBool m_is_kvo = eLazyBoolCalculate; + LazyBool m_is_cf = eLazyBoolCalculate; lldb::TypeWP m_type_wp; }; @@ -251,7 +259,8 @@ public: llvm::Optional GetRuntimeType(CompilerType base_type) override; - virtual UtilityFunction *CreateObjectChecker(const char *) = 0; + virtual llvm::Expected> + CreateObjectChecker(std::string name, ExecutionContext &exe_ctx) = 0; virtual ObjCRuntimeVersions GetRuntimeVersion() const { return ObjCRuntimeVersions::eObjC_VersionUnknown; diff --git a/gnu/llvm/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/CMakeLists.txt b/gnu/llvm/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/CMakeLists.txt index c122e09e8fe..9efb2c44d84 100644 --- a/gnu/llvm/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/CMakeLists.txt +++ b/gnu/llvm/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/CMakeLists.txt @@ -1,8 +1,3 @@ -if(NOT LLDB_BUILT_STANDALONE) - set(tablegen_deps intrinsics_gen) -endif() - - add_lldb_library(lldbPluginRenderScriptRuntime PLUGIN RenderScriptRuntime.cpp RenderScriptExpressionOpts.cpp @@ -10,7 +5,7 @@ add_lldb_library(lldbPluginRenderScriptRuntime PLUGIN RenderScriptScriptGroup.cpp DEPENDS - ${tablegen_deps} + intrinsics_gen LINK_LIBS lldbBreakpoint diff --git a/gnu/llvm/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptExpressionOpts.cpp b/gnu/llvm/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptExpressionOpts.cpp index 6858c7134d3..08a752eaa88 100644 --- a/gnu/llvm/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptExpressionOpts.cpp +++ b/gnu/llvm/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptExpressionOpts.cpp @@ -185,7 +185,7 @@ RSIRPasses::RSIRPasses(Process *process) { EarlyPasses->add(new RenderScriptRuntimeModulePass(process)); } -RSIRPasses::~RSIRPasses() {} +RSIRPasses::~RSIRPasses() = default; } // namespace lldb_renderscript } // namespace lldb_private diff --git a/gnu/llvm/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.cpp b/gnu/llvm/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.cpp index dd9312234d8..10ff5aa72b5 100644 --- a/gnu/llvm/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.cpp +++ b/gnu/llvm/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.cpp @@ -61,7 +61,7 @@ namespace { template class empirical_type { public: // Ctor. Contents is invalid when constructed. - empirical_type() : valid(false) {} + empirical_type() = default; // Return true and copy contents to out if valid, else return false. bool get(type_t &out) const { @@ -99,7 +99,7 @@ public: } protected: - bool valid; + bool valid = false; type_t data; }; @@ -2228,7 +2228,7 @@ bool RenderScriptRuntime::RefreshAllocation(AllocationDetails *alloc, return JITAllocationSize(alloc, frame_ptr); } -// Function attempts to set the type_name member of the paramaterised Element +// Function attempts to set the type_name member of the parameterised Element // object. This string should be the name of the struct type the Element // represents. We need this string for pretty printing the Element to users. void RenderScriptRuntime::FindStructTypeName(Element &elem, @@ -4087,9 +4087,7 @@ public: class CommandOptions : public Options { public: - CommandOptions() - : Options(), - m_kernel_types(RSReduceBreakpointResolver::eKernelTypeAll) {} + CommandOptions() : Options() {} ~CommandOptions() override = default; @@ -4175,7 +4173,7 @@ public: return true; } - int m_kernel_types; + int m_kernel_types = RSReduceBreakpointResolver::eKernelTypeAll; llvm::StringRef m_reduce_name; RSCoordinate m_coord; bool m_have_coord; @@ -4189,7 +4187,6 @@ public: result.AppendErrorWithFormat("'%s' takes 1 argument of reduction name, " "and an optional kernel type list", m_cmd_name.c_str()); - result.SetStatus(eReturnStatusFailed); return false; } @@ -4203,7 +4200,6 @@ public: auto coord = m_options.m_have_coord ? &m_options.m_coord : nullptr; if (!runtime->PlaceBreakpointOnReduction(target, outstream, name, coord, m_options.m_kernel_types)) { - result.SetStatus(eReturnStatusFailed); result.AppendError("Error: unable to place breakpoint on reduction"); return false; } @@ -4291,7 +4287,6 @@ public: result.AppendErrorWithFormat( "'%s' takes 1 argument of kernel name, and an optional coordinate.", m_cmd_name.c_str()); - result.SetStatus(eReturnStatusFailed); return false; } @@ -4304,7 +4299,6 @@ public: auto name = command.GetArgumentAtIndex(0); auto coord = m_options.m_have_coord ? &m_options.m_coord : nullptr; if (!runtime->PlaceBreakpointOnKernel(target, outstream, name, coord)) { - result.SetStatus(eReturnStatusFailed); result.AppendErrorWithFormat( "Error: unable to set breakpoint on kernel '%s'", name); return false; @@ -4342,7 +4336,6 @@ public: if (argc != 1) { result.AppendErrorWithFormat( "'%s' takes 1 argument of 'enable' or 'disable'", m_cmd_name.c_str()); - result.SetStatus(eReturnStatusFailed); return false; } @@ -4361,7 +4354,6 @@ public: } else { result.AppendErrorWithFormat( "Argument must be either 'enable' or 'disable'"); - result.SetStatus(eReturnStatusFailed); return false; } @@ -4568,7 +4560,6 @@ public: result.AppendErrorWithFormat("'%s' takes 1 argument, an allocation ID. " "As well as an optional -f argument", m_cmd_name.c_str()); - result.SetStatus(eReturnStatusFailed); return false; } @@ -4583,7 +4574,6 @@ public: if (!success) { result.AppendErrorWithFormat("invalid allocation id argument '%s'", id_cstr); - result.SetStatus(eReturnStatusFailed); return false; } @@ -4608,7 +4598,6 @@ public: std::string error = llvm::toString(file.takeError()); result.AppendErrorWithFormat("Couldn't open file '%s': %s", path.c_str(), error.c_str()); - result.SetStatus(eReturnStatusFailed); return false; } } else @@ -4653,7 +4642,7 @@ public: class CommandOptions : public Options { public: - CommandOptions() : Options(), m_id(0) {} + CommandOptions() : Options() {} ~CommandOptions() override = default; @@ -4681,7 +4670,7 @@ public: return llvm::makeArrayRef(g_renderscript_runtime_alloc_list_options); } - uint32_t m_id; + uint32_t m_id = 0; }; bool DoExecute(Args &command, CommandReturnObject &result) override { @@ -4717,7 +4706,6 @@ public: result.AppendErrorWithFormat( "'%s' takes 2 arguments, an allocation ID and filename to read from.", m_cmd_name.c_str()); - result.SetStatus(eReturnStatusFailed); return false; } @@ -4732,7 +4720,6 @@ public: if (!success) { result.AppendErrorWithFormat("invalid allocation id argument '%s'", id_cstr); - result.SetStatus(eReturnStatusFailed); return false; } @@ -4768,7 +4755,6 @@ public: result.AppendErrorWithFormat( "'%s' takes 2 arguments, an allocation ID and filename to read from.", m_cmd_name.c_str()); - result.SetStatus(eReturnStatusFailed); return false; } @@ -4783,7 +4769,6 @@ public: if (!success) { result.AppendErrorWithFormat("invalid allocation id argument '%s'", id_cstr); - result.SetStatus(eReturnStatusFailed); return false; } diff --git a/gnu/llvm/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.h b/gnu/llvm/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.h index 5e372654836..2785c3b0812 100644 --- a/gnu/llvm/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.h +++ b/gnu/llvm/lldb/source/Plugins/LanguageRuntime/RenderScript/RenderScriptRuntime/RenderScriptRuntime.h @@ -44,9 +44,9 @@ typedef std::shared_ptr RSKernelDescriptorSP; typedef std::shared_ptr RSScriptGroupDescriptorSP; struct RSCoordinate { - uint32_t x, y, z; + uint32_t x = 0, y = 0, z = 0; - RSCoordinate() : x(), y(), z(){}; + RSCoordinate() = default; bool operator==(const lldb_renderscript::RSCoordinate &rhs) { return x == rhs.x && y == rhs.y && z == rhs.z; diff --git a/gnu/llvm/lldb/source/Plugins/MemoryHistory/asan/MemoryHistoryASan.cpp b/gnu/llvm/lldb/source/Plugins/MemoryHistory/asan/MemoryHistoryASan.cpp index 333113a0b17..7d997628519 100644 --- a/gnu/llvm/lldb/source/Plugins/MemoryHistory/asan/MemoryHistoryASan.cpp +++ b/gnu/llvm/lldb/source/Plugins/MemoryHistory/asan/MemoryHistoryASan.cpp @@ -36,13 +36,8 @@ MemoryHistorySP MemoryHistoryASan::CreateInstance(const ProcessSP &process_sp) { Target &target = process_sp->GetTarget(); - const ModuleList &target_modules = target.GetImages(); - std::lock_guard guard(target_modules.GetMutex()); - const size_t num_modules = target_modules.GetSize(); - for (size_t i = 0; i < num_modules; ++i) { - Module *module_pointer = target_modules.GetModulePointerAtIndexUnlocked(i); - - const Symbol *symbol = module_pointer->FindFirstSymbolWithNameAndType( + for (ModuleSP module_sp : target.GetImages().Modules()) { + const Symbol *symbol = module_sp->FindFirstSymbolWithNameAndType( ConstString("__asan_get_alloc_stack"), lldb::eSymbolTypeAny); if (symbol != nullptr) diff --git a/gnu/llvm/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp b/gnu/llvm/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp index 83cf9f8bd26..7ff917518b6 100644 --- a/gnu/llvm/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp +++ b/gnu/llvm/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp @@ -42,9 +42,7 @@ using namespace lldb_private; LLDB_PLUGIN_DEFINE(ObjectContainerBSDArchive) -ObjectContainerBSDArchive::Object::Object() - : ar_name(), modification_time(0), uid(0), gid(0), mode(0), size(0), - file_offset(0), file_size(0) {} +ObjectContainerBSDArchive::Object::Object() : ar_name() {} void ObjectContainerBSDArchive::Object::Clear() { ar_name.Clear(); @@ -142,7 +140,7 @@ ObjectContainerBSDArchive::Archive::Archive(const lldb_private::ArchSpec &arch, : m_arch(arch), m_modification_time(time), m_file_offset(file_offset), m_objects(), m_data(data) {} -ObjectContainerBSDArchive::Archive::~Archive() {} +ObjectContainerBSDArchive::Archive::~Archive() = default; size_t ObjectContainerBSDArchive::Archive::ParseObjects() { DataExtractor &data = m_data; @@ -300,9 +298,7 @@ ObjectContainer *ObjectContainerBSDArchive::CreateInstance( DataExtractor data; data.SetData(data_sp, data_offset, length); if (file && data_sp && ObjectContainerBSDArchive::MagicBytesMatch(data)) { - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer( - func_cat, + LLDB_SCOPED_TIMERF( "ObjectContainerBSDArchive::CreateInstance (module = %s, file = " "%p, file_offset = 0x%8.8" PRIx64 ", file_size = 0x%8.8" PRIx64 ")", module_sp->GetFileSpec().GetPath().c_str(), @@ -377,7 +373,7 @@ void ObjectContainerBSDArchive::SetArchive(Archive::shared_ptr &archive_sp) { m_archive_sp = archive_sp; } -ObjectContainerBSDArchive::~ObjectContainerBSDArchive() {} +ObjectContainerBSDArchive::~ObjectContainerBSDArchive() = default; bool ObjectContainerBSDArchive::ParseHeader() { if (m_archive_sp.get() == nullptr) { diff --git a/gnu/llvm/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.h b/gnu/llvm/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.h index f6862afff8a..9830e9b5d1b 100644 --- a/gnu/llvm/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.h +++ b/gnu/llvm/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.h @@ -84,25 +84,25 @@ protected: lldb_private::ConstString ar_name; /// Object modification time in the archive. - uint32_t modification_time; + uint32_t modification_time = 0; /// Object user id in the archive. - uint16_t uid; + uint16_t uid = 0; /// Object group id in the archive. - uint16_t gid; + uint16_t gid = 0; /// Object octal file permissions in the archive. - uint16_t mode; + uint16_t mode = 0; /// Object size in bytes in the archive. - uint32_t size; + uint32_t size = 0; /// File offset in bytes from the beginning of the file of the object data. - lldb::offset_t file_offset; + lldb::offset_t file_offset = 0; /// Length of the object data. - lldb::offset_t file_size; + lldb::offset_t file_size = 0; }; class Archive { diff --git a/gnu/llvm/lldb/source/Plugins/ObjectContainer/Universal-Mach-O/ObjectContainerUniversalMachO.cpp b/gnu/llvm/lldb/source/Plugins/ObjectContainer/Universal-Mach-O/ObjectContainerUniversalMachO.cpp index bb56379ed1e..d0a493d4511 100644 --- a/gnu/llvm/lldb/source/Plugins/ObjectContainer/Universal-Mach-O/ObjectContainerUniversalMachO.cpp +++ b/gnu/llvm/lldb/source/Plugins/ObjectContainer/Universal-Mach-O/ObjectContainerUniversalMachO.cpp @@ -79,7 +79,7 @@ ObjectContainerUniversalMachO::ObjectContainerUniversalMachO( memset(&m_header, 0, sizeof(m_header)); } -ObjectContainerUniversalMachO::~ObjectContainerUniversalMachO() {} +ObjectContainerUniversalMachO::~ObjectContainerUniversalMachO() = default; bool ObjectContainerUniversalMachO::ParseHeader() { bool success = ParseHeader(m_data, m_header, m_fat_archs); diff --git a/gnu/llvm/lldb/source/Plugins/ObjectFile/CMakeLists.txt b/gnu/llvm/lldb/source/Plugins/ObjectFile/CMakeLists.txt index 76f6d7ad0d7..3b2cc6177d3 100644 --- a/gnu/llvm/lldb/source/Plugins/ObjectFile/CMakeLists.txt +++ b/gnu/llvm/lldb/source/Plugins/ObjectFile/CMakeLists.txt @@ -1,6 +1,7 @@ add_subdirectory(Breakpad) add_subdirectory(ELF) add_subdirectory(Mach-O) +add_subdirectory(PDB) add_subdirectory(PECOFF) add_subdirectory(JIT) -add_subdirectory(wasm) \ No newline at end of file +add_subdirectory(wasm) diff --git a/gnu/llvm/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.h b/gnu/llvm/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.h index 062271f1caf..e678c2f5f01 100644 --- a/gnu/llvm/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.h +++ b/gnu/llvm/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.h @@ -9,7 +9,7 @@ #ifndef LLDB_SOURCE_PLUGINS_OBJECTFILE_ELF_OBJECTFILEELF_H #define LLDB_SOURCE_PLUGINS_OBJECTFILE_ELF_OBJECTFILEELF_H -#include +#include #include @@ -22,13 +22,13 @@ #include "ELFHeader.h" struct ELFNote { - elf::elf_word n_namesz; - elf::elf_word n_descsz; - elf::elf_word n_type; + elf::elf_word n_namesz = 0; + elf::elf_word n_descsz = 0; + elf::elf_word n_type = 0; std::string n_name; - ELFNote() : n_namesz(0), n_descsz(0), n_type(0) {} + ELFNote() = default; /// Parse an ELFNote entry from the given DataExtractor starting at position /// \p offset. diff --git a/gnu/llvm/lldb/source/Plugins/ObjectFile/JIT/ObjectFileJIT.cpp b/gnu/llvm/lldb/source/Plugins/ObjectFile/JIT/ObjectFileJIT.cpp index 93c2c9f945f..f93ac9261af 100644 --- a/gnu/llvm/lldb/source/Plugins/ObjectFile/JIT/ObjectFileJIT.cpp +++ b/gnu/llvm/lldb/source/Plugins/ObjectFile/JIT/ObjectFileJIT.cpp @@ -100,7 +100,7 @@ ObjectFileJIT::ObjectFileJIT(const lldb::ModuleSP &module_sp, } } -ObjectFileJIT::~ObjectFileJIT() {} +ObjectFileJIT::~ObjectFileJIT() = default; bool ObjectFileJIT::ParseHeader() { // JIT code is never in a file, nor is it required to have any header diff --git a/gnu/llvm/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp b/gnu/llvm/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp index 2bb4b21adea..fd1a23d5024 100644 --- a/gnu/llvm/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp +++ b/gnu/llvm/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp @@ -17,10 +17,13 @@ #include "lldb/Core/Module.h" #include "lldb/Core/ModuleSpec.h" #include "lldb/Core/PluginManager.h" +#include "lldb/Core/Progress.h" #include "lldb/Core/Section.h" #include "lldb/Core/StreamFile.h" #include "lldb/Host/Host.h" +#include "lldb/Host/SafeMachO.h" #include "lldb/Symbol/DWARFCallFrameInfo.h" +#include "lldb/Symbol/LocateSymbolFile.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Target/DynamicLoader.h" #include "lldb/Target/MemoryRegionInfo.h" @@ -41,14 +44,14 @@ #include "lldb/Utility/Timer.h" #include "lldb/Utility/UUID.h" -#include "lldb/Host/SafeMachO.h" - +#include "llvm/ADT/DenseSet.h" +#include "llvm/Support/FormatVariadic.h" #include "llvm/Support/MemoryBuffer.h" #include "ObjectFileMachO.h" -#if defined(__APPLE__) && \ - (defined(__arm__) || defined(__arm64__) || defined(__aarch64__)) +#if defined(__APPLE__) +#include // GetLLDBSharedCacheUUID() needs to call dlsym() #include #endif @@ -59,8 +62,54 @@ #include #endif +#include #include +#if LLVM_SUPPORT_XCODE_SIGNPOSTS +// Unfortunately the signpost header pulls in the system MachO header, too. +#undef CPU_TYPE_ARM +#undef CPU_TYPE_ARM64 +#undef CPU_TYPE_ARM64_32 +#undef CPU_TYPE_I386 +#undef CPU_TYPE_X86_64 +#undef MH_BINDATLOAD +#undef MH_BUNDLE +#undef MH_CIGAM +#undef MH_CIGAM_64 +#undef MH_CORE +#undef MH_DSYM +#undef MH_DYLDLINK +#undef MH_DYLIB +#undef MH_DYLIB_STUB +#undef MH_DYLINKER +#undef MH_DYLINKER +#undef MH_EXECUTE +#undef MH_FVMLIB +#undef MH_INCRLINK +#undef MH_KEXT_BUNDLE +#undef MH_MAGIC +#undef MH_MAGIC_64 +#undef MH_NOUNDEFS +#undef MH_OBJECT +#undef MH_OBJECT +#undef MH_PRELOAD + +#undef LC_BUILD_VERSION +#undef LC_VERSION_MIN_MACOSX +#undef LC_VERSION_MIN_IPHONEOS +#undef LC_VERSION_MIN_TVOS +#undef LC_VERSION_MIN_WATCHOS + +#undef PLATFORM_MACOS +#undef PLATFORM_MACCATALYST +#undef PLATFORM_IOS +#undef PLATFORM_IOSSIMULATOR +#undef PLATFORM_TVOS +#undef PLATFORM_TVOSSIMULATOR +#undef PLATFORM_WATCHOS +#undef PLATFORM_WATCHOSSIMULATOR +#endif + #define THUMB_ADDRESS_BIT_MASK 0xfffffffffffffffeull using namespace lldb; using namespace lldb_private; @@ -738,11 +787,11 @@ static uint32_t MachHeaderSizeFromMagic(uint32_t magic) { switch (magic) { case MH_MAGIC: case MH_CIGAM: - return sizeof(struct mach_header); + return sizeof(struct llvm::MachO::mach_header); case MH_MAGIC_64: case MH_CIGAM_64: - return sizeof(struct mach_header_64); + return sizeof(struct llvm::MachO::mach_header_64); break; default: @@ -1061,7 +1110,7 @@ bool ObjectFileMachO::ParseHeader() { // None found. return false; } else { - memset(&m_header, 0, sizeof(struct mach_header)); + memset(&m_header, 0, sizeof(struct llvm::MachO::mach_header)); } return false; } @@ -1271,7 +1320,7 @@ bool ObjectFileMachO::IsStripped() { for (uint32_t i = 0; i < m_header.ncmds; ++i) { const lldb::offset_t load_cmd_offset = offset; - load_command lc; + llvm::MachO::load_command lc; if (m_data.GetU32(&offset, &lc.cmd, 2) == nullptr) break; if (lc.cmd == LC_DYSYMTAB) { @@ -1298,7 +1347,7 @@ ObjectFileMachO::EncryptedFileRanges ObjectFileMachO::GetEncryptedFileRanges() { EncryptedFileRanges result; lldb::offset_t offset = MachHeaderSizeFromMagic(m_header.magic); - encryption_info_command encryption_cmd; + llvm::MachO::encryption_info_command encryption_cmd; for (uint32_t i = 0; i < m_header.ncmds; ++i) { const lldb::offset_t load_cmd_offset = offset; if (m_data.GetU32(&offset, &encryption_cmd, 2) == nullptr) @@ -1323,11 +1372,24 @@ ObjectFileMachO::EncryptedFileRanges ObjectFileMachO::GetEncryptedFileRanges() { return result; } -void ObjectFileMachO::SanitizeSegmentCommand(segment_command_64 &seg_cmd, - uint32_t cmd_idx) { +void ObjectFileMachO::SanitizeSegmentCommand( + llvm::MachO::segment_command_64 &seg_cmd, uint32_t cmd_idx) { if (m_length == 0 || seg_cmd.filesize == 0) return; + if ((m_header.flags & MH_DYLIB_IN_CACHE) && !IsInMemory()) { + // In shared cache images, the load commands are relative to the + // shared cache file, and not the specific image we are + // examining. Let's fix this up so that it looks like a normal + // image. + if (strncmp(seg_cmd.segname, "__TEXT", sizeof(seg_cmd.segname)) == 0) + m_text_address = seg_cmd.vmaddr; + if (strncmp(seg_cmd.segname, "__LINKEDIT", sizeof(seg_cmd.segname)) == 0) + m_linkedit_original_offset = seg_cmd.fileoff; + + seg_cmd.fileoff = seg_cmd.vmaddr - m_text_address; + } + if (seg_cmd.fileoff > m_length) { // We have a load command that says it extends past the end of the file. // This is likely a corrupt file. We don't have any way to return an error @@ -1367,7 +1429,8 @@ void ObjectFileMachO::SanitizeSegmentCommand(segment_command_64 &seg_cmd, } } -static uint32_t GetSegmentPermissions(const segment_command_64 &seg_cmd) { +static uint32_t +GetSegmentPermissions(const llvm::MachO::segment_command_64 &seg_cmd) { uint32_t result = 0; if (seg_cmd.initprot & VM_PROT_READ) result |= ePermissionsReadable; @@ -1535,11 +1598,10 @@ struct ObjectFileMachO::SegmentParsingContext { : EncryptedRanges(std::move(EncryptedRanges)), UnifiedList(UnifiedList) {} }; -void ObjectFileMachO::ProcessSegmentCommand(const load_command &load_cmd_, - lldb::offset_t offset, - uint32_t cmd_idx, - SegmentParsingContext &context) { - segment_command_64 load_cmd; +void ObjectFileMachO::ProcessSegmentCommand( + const llvm::MachO::load_command &load_cmd_, lldb::offset_t offset, + uint32_t cmd_idx, SegmentParsingContext &context) { + llvm::MachO::segment_command_64 load_cmd; memcpy(&load_cmd, &load_cmd_, sizeof(load_cmd_)); if (!m_data.GetU8(&offset, (uint8_t *)load_cmd.segname, 16)) @@ -1615,7 +1677,7 @@ void ObjectFileMachO::ProcessSegmentCommand(const load_command &load_cmd_, } else if (unified_section_sp) { if (is_dsym && unified_section_sp->GetFileAddress() != load_cmd.vmaddr) { // Check to see if the module was read from memory? - if (module_sp->GetObjectFile()->GetBaseAddress().IsValid()) { + if (module_sp->GetObjectFile()->IsInMemory()) { // We have a module that is in memory and needs to have its file // address adjusted. We need to do this because when we load a file // from memory, its addresses will be slid already, yet the addresses @@ -1640,7 +1702,7 @@ void ObjectFileMachO::ProcessSegmentCommand(const load_command &load_cmd_, m_sections_up->AddSection(unified_section_sp); } - struct section_64 sect64; + llvm::MachO::section_64 sect64; ::memset(§64, 0, sizeof(sect64)); // Push a section into our mach sections for the section at index zero // (NO_SECT) if we don't have any mach sections yet... @@ -1664,6 +1726,10 @@ void ObjectFileMachO::ProcessSegmentCommand(const load_command &load_cmd_, if (m_data.GetU32(&offset, §64.offset, num_u32s) == nullptr) break; + if ((m_header.flags & MH_DYLIB_IN_CACHE) && !IsInMemory()) { + sect64.offset = sect64.addr - m_text_address; + } + // Keep a list of mach sections around in case we need to get at data that // isn't stored in the abstracted Sections. m_mach_sections.push_back(sect64); @@ -1808,8 +1874,8 @@ void ObjectFileMachO::ProcessSegmentCommand(const load_command &load_cmd_, } } -void ObjectFileMachO::ProcessDysymtabCommand(const load_command &load_cmd, - lldb::offset_t offset) { +void ObjectFileMachO::ProcessDysymtabCommand( + const llvm::MachO::load_command &load_cmd, lldb::offset_t offset) { m_dysymtab.cmd = load_cmd.cmd; m_dysymtab.cmdsize = load_cmd.cmdsize; m_data.GetU32(&offset, &m_dysymtab.ilocalsym, @@ -1829,7 +1895,7 @@ void ObjectFileMachO::CreateSections(SectionList &unified_section_list) { offset = MachHeaderSizeFromMagic(m_header.magic); SegmentParsingContext context(GetEncryptedFileRanges(), unified_section_list); - struct load_command load_cmd; + llvm::MachO::load_command load_cmd; for (uint32_t i = 0; i < m_header.ncmds; ++i) { const lldb::offset_t load_cmd_offset = offset; if (m_data.GetU32(&offset, &load_cmd, 2) == nullptr) @@ -1870,15 +1936,15 @@ public: m_section_infos[n_sect].vm_range.SetByteSize( section_sp->GetByteSize()); } else { - const char *filename = ""; + std::string filename = ""; SectionSP first_section_sp(m_section_list->GetSectionAtIndex(0)); if (first_section_sp) - filename = first_section_sp->GetObjectFile()->GetFileSpec().GetPath().c_str(); + filename = first_section_sp->GetObjectFile()->GetFileSpec().GetPath(); Host::SystemLog(Host::eSystemLogError, - "error: unable to find section %d for a symbol in %s, corrupt file?\n", - n_sect, - filename); + "error: unable to find section %d for a symbol in " + "%s, corrupt file?\n", + n_sect, filename.c_str()); } } if (m_section_infos[n_sect].vm_range.Contains(file_addr)) { @@ -1973,6 +2039,8 @@ static bool ParseTrieEntries(DataExtractor &data, lldb::offset_t offset, if (e.entry.flags & EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER) { e.entry.other = data.GetULEB128(&offset); uint64_t resolver_addr = e.entry.other; + if (text_seg_base_addr != LLDB_INVALID_ADDRESS) + resolver_addr += text_seg_base_addr; if (is_arm) resolver_addr &= THUMB_ADDRESS_BIT_MASK; resolver_addresses.insert(resolver_addr); @@ -2142,16 +2210,18 @@ ParseNList(DataExtractor &nlist_data, lldb::offset_t &nlist_data_offset, enum { DebugSymbols = true, NonDebugSymbols = false }; size_t ObjectFileMachO::ParseSymtab() { - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer(func_cat, "ObjectFileMachO::ParseSymtab () module = %s", + LLDB_SCOPED_TIMERF("ObjectFileMachO::ParseSymtab () module = %s", m_file.GetFilename().AsCString("")); ModuleSP module_sp(GetModule()); if (!module_sp) return 0; - struct symtab_command symtab_load_command = {0, 0, 0, 0, 0, 0}; - struct linkedit_data_command function_starts_load_command = {0, 0, 0, 0}; - struct dyld_info_command dyld_info = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + Progress progress(llvm::formatv("Parsing symbol table for {0}", + m_file.GetFilename().AsCString(""))); + + llvm::MachO::symtab_command symtab_load_command = {0, 0, 0, 0, 0, 0}; + llvm::MachO::linkedit_data_command function_starts_load_command = {0, 0, 0, 0}; + llvm::MachO::dyld_info_command dyld_info = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; // The data element of type bool indicates that this entry is thumb // code. typedef AddressDataArray FunctionStarts; @@ -2160,7 +2230,16 @@ size_t ObjectFileMachO::ParseSymtab() { // We add symbols to the table in the order of most information (nlist // records) to least (function starts), and avoid duplicating symbols // via this set. - std::set symbols_added; + llvm::DenseSet symbols_added; + + // We are using a llvm::DenseSet for "symbols_added" so we must be sure we + // do not add the tombstone or empty keys to the set. + auto add_symbol_addr = [&symbols_added](lldb::addr_t file_addr) { + // Don't add the tombstone or empty keys. + if (file_addr == UINT64_MAX || file_addr == UINT64_MAX - 1) + return; + symbols_added.insert(file_addr); + }; FunctionStarts function_starts; lldb::offset_t offset = MachHeaderSizeFromMagic(m_header.magic); uint32_t i; @@ -2173,7 +2252,7 @@ size_t ObjectFileMachO::ParseSymtab() { for (i = 0; i < m_header.ncmds; ++i) { const lldb::offset_t cmd_offset = offset; // Read in the load command and load command size - struct load_command lc; + llvm::MachO::load_command lc; if (m_data.GetU32(&offset, &lc, 2) == nullptr) break; // Watch for the symbol table load command @@ -2264,14 +2343,17 @@ size_t ObjectFileMachO::ParseSymtab() { Process *process = process_sp.get(); uint32_t memory_module_load_level = eMemoryModuleLoadLevelComplete; + bool is_shared_cache_image = m_header.flags & MH_DYLIB_IN_CACHE; + bool is_local_shared_cache_image = is_shared_cache_image && !IsInMemory(); + SectionSP linkedit_section_sp( + section_list->FindSectionByName(GetSegmentNameLINKEDIT())); - if (process && m_header.filetype != llvm::MachO::MH_OBJECT) { + if (process && m_header.filetype != llvm::MachO::MH_OBJECT && + !is_local_shared_cache_image) { Target &target = process->GetTarget(); memory_module_load_level = target.GetMemoryModuleLoadLevel(); - SectionSP linkedit_section_sp( - section_list->FindSectionByName(GetSegmentNameLINKEDIT())); // Reading mach file from memory in a process or core file... if (linkedit_section_sp) { @@ -2293,62 +2375,6 @@ size_t ObjectFileMachO::ParseSymtab() { strtab_addr = linkedit_load_addr + symtab_load_command.stroff - linkedit_file_offset; - bool data_was_read = false; - -#if defined(__APPLE__) && \ - (defined(__arm__) || defined(__arm64__) || defined(__aarch64__)) - if (m_header.flags & MH_DYLIB_IN_CACHE && - process->GetAddressByteSize() == sizeof(void *)) { - // This mach-o memory file is in the dyld shared cache. If this - // program is not remote and this is iOS, then this process will - // share the same shared cache as the process we are debugging and we - // can read the entire __LINKEDIT from the address space in this - // process. This is a needed optimization that is used for local iOS - // debugging only since all shared libraries in the shared cache do - // not have corresponding files that exist in the file system of the - // device. They have been combined into a single file. This means we - // always have to load these files from memory. All of the symbol and - // string tables from all of the __LINKEDIT sections from the shared - // libraries in the shared cache have been merged into a single large - // symbol and string table. Reading all of this symbol and string - // table data across can slow down debug launch times, so we optimize - // this by reading the memory for the __LINKEDIT section from this - // process. - - UUID lldb_shared_cache; - addr_t lldb_shared_cache_addr; - GetLLDBSharedCacheUUID(lldb_shared_cache_addr, lldb_shared_cache); - UUID process_shared_cache; - addr_t process_shared_cache_addr; - GetProcessSharedCacheUUID(process, process_shared_cache_addr, - process_shared_cache); - bool use_lldb_cache = true; - if (lldb_shared_cache.IsValid() && process_shared_cache.IsValid() && - (lldb_shared_cache != process_shared_cache || - process_shared_cache_addr != lldb_shared_cache_addr)) { - use_lldb_cache = false; - } - - PlatformSP platform_sp(target.GetPlatform()); - if (platform_sp && platform_sp->IsHost() && use_lldb_cache) { - data_was_read = true; - nlist_data.SetData((void *)symoff_addr, nlist_data_byte_size, - eByteOrderLittle); - strtab_data.SetData((void *)strtab_addr, strtab_data_byte_size, - eByteOrderLittle); - if (function_starts_load_command.cmd) { - const addr_t func_start_addr = - linkedit_load_addr + function_starts_load_command.dataoff - - linkedit_file_offset; - function_starts_data.SetData((void *)func_start_addr, - function_starts_load_command.datasize, - eByteOrderLittle); - } - } - } -#endif - - if (!data_was_read) { // Always load dyld - the dynamic linker - from memory if we didn't // find a binary anywhere else. lldb will not register // dylib/framework/bundle loads/unloads if we don't have the dyld @@ -2379,7 +2405,7 @@ size_t ObjectFileMachO::ParseSymtab() { // problem. For binaries outside the shared cache, it's faster to // read the entire strtab at once instead of piece-by-piece as we // process the nlist records. - if ((m_header.flags & MH_DYLIB_IN_CACHE) == 0) { + if (!is_shared_cache_image) { DataBufferSP strtab_data_sp( ReadMemory(process_sp, strtab_addr, strtab_data_byte_size)); if (strtab_data_sp) { @@ -2388,7 +2414,6 @@ size_t ObjectFileMachO::ParseSymtab() { } } } - } if (memory_module_load_level >= eMemoryModuleLoadLevelPartial) { if (function_starts_load_command.cmd) { const addr_t func_start_addr = @@ -2405,6 +2430,24 @@ size_t ObjectFileMachO::ParseSymtab() { } } } else { + if (is_local_shared_cache_image) { + // The load commands in shared cache images are relative to the + // beginning of the shared cache, not the library image. The + // data we get handed when creating the ObjectFileMachO starts + // at the beginning of a specific library and spans to the end + // of the cache to be able to reach the shared LINKEDIT + // segments. We need to convert the load command offsets to be + // relative to the beginning of our specific image. + lldb::addr_t linkedit_offset = linkedit_section_sp->GetFileOffset(); + lldb::offset_t linkedit_slide = + linkedit_offset - m_linkedit_original_offset; + symtab_load_command.symoff += linkedit_slide; + symtab_load_command.stroff += linkedit_slide; + dyld_info.export_off += linkedit_slide; + m_dysymtab.indirectsymoff += linkedit_slide; + function_starts_load_command.dataoff += linkedit_slide; + } + nlist_data.SetData(m_data, symtab_load_command.symoff, nlist_data_byte_size); strtab_data.SetData(m_data, symtab_load_command.stroff, @@ -2596,7 +2639,7 @@ size_t ObjectFileMachO::ParseSymtab() { typedef std::set IndirectSymbols; IndirectSymbols indirect_symbol_names; -#if defined(__APPLE__) && TARGET_OS_EMBEDDED +#if TARGET_OS_IPHONE // Some recent builds of the dyld_shared_cache (hereafter: DSC) have been // optimized by moving LOCAL symbols out of the memory mapped portion of @@ -3049,12 +3092,10 @@ size_t ObjectFileMachO::ParseSymtab() { // contains just the filename, so here we combine // it with the first one if we are minimizing the // symbol table - const char *so_path = - sym[sym_idx - 1] - .GetMangled() - .GetDemangledName( - lldb::eLanguageTypeUnknown) - .AsCString(); + const char *so_path = sym[sym_idx - 1] + .GetMangled() + .GetDemangledName() + .AsCString(); if (so_path && so_path[0]) { std::string full_so_path(so_path); const size_t double_slash_pos = @@ -3489,8 +3530,7 @@ size_t ObjectFileMachO::ParseSymtab() { const char *gsym_name = sym[sym_idx] .GetMangled() - .GetName(lldb::eLanguageTypeUnknown, - Mangled::ePreferMangled) + .GetName(Mangled::ePreferMangled) .GetCString(); if (gsym_name) N_GSYM_name_to_sym_idx[gsym_name] = sym_idx; @@ -3572,10 +3612,8 @@ size_t ObjectFileMachO::ParseSymtab() { for (auto pos = range.first; pos != range.second; ++pos) { if (sym[sym_idx].GetMangled().GetName( - lldb::eLanguageTypeUnknown, Mangled::ePreferMangled) == sym[pos->second].GetMangled().GetName( - lldb::eLanguageTypeUnknown, Mangled::ePreferMangled)) { m_nlist_idx_to_sym_idx[nlist_idx] = pos->second; // We just need the flags from the linker @@ -3617,10 +3655,8 @@ size_t ObjectFileMachO::ParseSymtab() { for (auto pos = range.first; pos != range.second; ++pos) { if (sym[sym_idx].GetMangled().GetName( - lldb::eLanguageTypeUnknown, Mangled::ePreferMangled) == sym[pos->second].GetMangled().GetName( - lldb::eLanguageTypeUnknown, Mangled::ePreferMangled)) { m_nlist_idx_to_sym_idx[nlist_idx] = pos->second; // We just need the flags from the linker @@ -3642,8 +3678,7 @@ size_t ObjectFileMachO::ParseSymtab() { const char *gsym_name = sym[sym_idx] .GetMangled() - .GetName(lldb::eLanguageTypeUnknown, - Mangled::ePreferMangled) + .GetName(Mangled::ePreferMangled) .GetCString(); if (gsym_name) { // Combine N_GSYM stab entries with the non @@ -3661,9 +3696,9 @@ size_t ObjectFileMachO::ParseSymtab() { symbol_section); sym[GSYM_sym_idx].GetAddressRef().SetOffset( symbol_value); - symbols_added.insert(sym[GSYM_sym_idx] - .GetAddress() - .GetFileAddress()); + add_symbol_addr(sym[GSYM_sym_idx] + .GetAddress() + .GetFileAddress()); // We just need the flags from the linker // symbol, so put these flags // into the N_GSYM flags to avoid duplicate @@ -3683,7 +3718,7 @@ size_t ObjectFileMachO::ParseSymtab() { if (set_value) { sym[sym_idx].GetAddressRef().SetSection(symbol_section); sym[sym_idx].GetAddressRef().SetOffset(symbol_value); - symbols_added.insert( + add_symbol_addr( sym[sym_idx].GetAddress().GetFileAddress()); } sym[sym_idx].SetFlags(nlist.n_type << 16 | nlist.n_desc); @@ -4496,7 +4531,7 @@ size_t ObjectFileMachO::ParseSymtab() { // invalid address of zero when the global is a common symbol. sym[GSYM_sym_idx].GetAddressRef().SetSection(symbol_section); sym[GSYM_sym_idx].GetAddressRef().SetOffset(symbol_value); - symbols_added.insert( + add_symbol_addr( sym[GSYM_sym_idx].GetAddress().GetFileAddress()); // We just need the flags from the linker symbol, so put these // flags into the N_GSYM flags to avoid duplicate symbols in @@ -4515,7 +4550,8 @@ size_t ObjectFileMachO::ParseSymtab() { if (set_value) { sym[sym_idx].GetAddressRef().SetSection(symbol_section); sym[sym_idx].GetAddressRef().SetOffset(symbol_value); - symbols_added.insert(sym[sym_idx].GetAddress().GetFileAddress()); + if (symbol_section) + add_symbol_addr(sym[sym_idx].GetAddress().GetFileAddress()); } sym[sym_idx].SetFlags(nlist.n_type << 16 | nlist.n_desc); if (nlist.n_desc & N_WEAK_REF) @@ -4611,7 +4647,7 @@ size_t ObjectFileMachO::ParseSymtab() { sym[sym_idx].SetIsSynthetic(true); sym[sym_idx].SetExternal(true); sym[sym_idx].GetAddressRef() = symbol_addr; - symbols_added.insert(symbol_addr.GetFileAddress()); + add_symbol_addr(symbol_addr.GetFileAddress()); if (e.entry.flags & TRIE_SYMBOL_IS_THUMB) sym[sym_idx].SetFlags(MACHO_NLIST_ARM_SYMBOL_IS_THUMB); ++sym_idx; @@ -4661,12 +4697,14 @@ size_t ObjectFileMachO::ParseSymtab() { symbol_byte_size = section_end_file_addr - symbol_file_addr; } sym[sym_idx].SetID(synthetic_sym_id++); - sym[sym_idx].GetMangled().SetDemangledName( - GetNextSyntheticSymbolName()); + // Don't set the name for any synthetic symbols, the Symbol + // object will generate one if needed when the name is accessed + // via accessors. + sym[sym_idx].GetMangled().SetDemangledName(ConstString()); sym[sym_idx].SetType(eSymbolTypeCode); sym[sym_idx].SetIsSynthetic(true); sym[sym_idx].GetAddressRef() = symbol_addr; - symbols_added.insert(symbol_addr.GetFileAddress()); + add_symbol_addr(symbol_addr.GetFileAddress()); if (symbol_flags) sym[sym_idx].SetFlags(symbol_flags); if (symbol_byte_size) @@ -4767,7 +4805,7 @@ size_t ObjectFileMachO::ParseSymtab() { sym[sym_idx].SetType(eSymbolTypeResolver); sym[sym_idx].SetIsSynthetic(true); sym[sym_idx].GetAddressRef() = so_addr; - symbols_added.insert(so_addr.GetFileAddress()); + add_symbol_addr(so_addr.GetFileAddress()); sym[sym_idx].SetByteSize(symbol_stub_byte_size); ++sym_idx; } @@ -4864,7 +4902,7 @@ UUID ObjectFileMachO::GetUUID(const llvm::MachO::mach_header &header, const lldb_private::DataExtractor &data, lldb::offset_t lc_offset) { uint32_t i; - struct uuid_command load_cmd; + llvm::MachO::uuid_command load_cmd; lldb::offset_t offset = lc_offset; for (i = 0; i < header.ncmds; ++i) { @@ -5012,7 +5050,7 @@ void ObjectFileMachO::GetAllArchSpecs(const llvm::MachO::mach_header &header, return add_triple(base_triple); } - struct load_command load_cmd; + llvm::MachO::load_command load_cmd; // See if there is an LC_VERSION_MIN_* load command that can give // us the OS type. @@ -5022,10 +5060,10 @@ void ObjectFileMachO::GetAllArchSpecs(const llvm::MachO::mach_header &header, if (data.GetU32(&offset, &load_cmd, 2) == NULL) break; - struct version_min_command version_min; + llvm::MachO::version_min_command version_min; switch (load_cmd.cmd) { - case llvm::MachO::LC_VERSION_MIN_IPHONEOS: case llvm::MachO::LC_VERSION_MIN_MACOSX: + case llvm::MachO::LC_VERSION_MIN_IPHONEOS: case llvm::MachO::LC_VERSION_MIN_TVOS: case llvm::MachO::LC_VERSION_MIN_WATCHOS: { if (load_cmd.cmdsize != sizeof(version_min)) @@ -5041,7 +5079,19 @@ void ObjectFileMachO::GetAllArchSpecs(const llvm::MachO::mach_header &header, auto triple = base_triple; triple.setOSName(os.str()); - os_name.clear(); + + // Disambiguate legacy simulator platforms. + if (load_cmd.cmd != llvm::MachO::LC_VERSION_MIN_MACOSX && + (base_triple.getArch() == llvm::Triple::x86_64 || + base_triple.getArch() == llvm::Triple::x86)) { + // The combination of legacy LC_VERSION_MIN load command and + // x86 architecture always indicates a simulator environment. + // The combination of LC_VERSION_MIN and arm architecture only + // appears for native binaries. Back-deploying simulator + // binaries on Apple Silicon Macs use the modern unambigous + // LC_BUILD_VERSION load commands; no special handling required. + triple.setEnvironment(llvm::Triple::Simulator); + } add_triple(triple); break; } @@ -5062,7 +5112,7 @@ void ObjectFileMachO::GetAllArchSpecs(const llvm::MachO::mach_header &header, do { if (load_cmd.cmd == llvm::MachO::LC_BUILD_VERSION) { - struct build_version_command build_version; + llvm::MachO::build_version_command build_version; if (load_cmd.cmdsize < sizeof(build_version)) { // Malformed load command. break; @@ -5143,7 +5193,7 @@ uint32_t ObjectFileMachO::GetDependentModules(FileSpecList &files) { ModuleSP module_sp(GetModule()); if (module_sp) { std::lock_guard guard(module_sp->GetMutex()); - struct load_command load_cmd; + llvm::MachO::load_command load_cmd; lldb::offset_t offset = MachHeaderSizeFromMagic(m_header.magic); std::vector rpath_paths; std::vector rpath_relative_paths; @@ -5279,7 +5329,7 @@ lldb_private::Address ObjectFileMachO::GetEntryPointAddress() { ModuleSP module_sp(GetModule()); if (module_sp) { std::lock_guard guard(module_sp->GetMutex()); - struct load_command load_cmd; + llvm::MachO::load_command load_cmd; lldb::offset_t offset = MachHeaderSizeFromMagic(m_header.magic); uint32_t i; lldb::addr_t start_address = LLDB_INVALID_ADDRESS; @@ -5436,7 +5486,7 @@ uint32_t ObjectFileMachO::GetNumThreadContexts() { m_thread_context_offsets_valid = true; lldb::offset_t offset = MachHeaderSizeFromMagic(m_header.magic); FileRangeArray::Entry file_range; - thread_command thread_cmd; + llvm::MachO::thread_command thread_cmd; for (uint32_t i = 0; i < m_header.ncmds; ++i) { const uint32_t cmd_offset = offset; if (m_data.GetU32(&offset, &thread_cmd, 2) == nullptr) @@ -5465,7 +5515,7 @@ std::string ObjectFileMachO::GetIdentifierString() { lldb::offset_t offset = MachHeaderSizeFromMagic(m_header.magic); for (uint32_t i = 0; i < m_header.ncmds; ++i) { const uint32_t cmd_offset = offset; - load_command lc; + llvm::MachO::load_command lc; if (m_data.GetU32(&offset, &lc.cmd, 2) == nullptr) break; if (lc.cmd == LC_NOTE) { @@ -5505,7 +5555,7 @@ std::string ObjectFileMachO::GetIdentifierString() { offset = MachHeaderSizeFromMagic(m_header.magic); for (uint32_t i = 0; i < m_header.ncmds; ++i) { const uint32_t cmd_offset = offset; - struct ident_command ident_command; + llvm::MachO::ident_command ident_command; if (m_data.GetU32(&offset, &ident_command, 2) == nullptr) break; if (ident_command.cmd == LC_IDENT && ident_command.cmdsize != 0) { @@ -5524,7 +5574,48 @@ std::string ObjectFileMachO::GetIdentifierString() { return result; } -bool ObjectFileMachO::GetCorefileMainBinaryInfo(addr_t &address, UUID &uuid) { +addr_t ObjectFileMachO::GetAddressMask() { + addr_t mask = 0; + ModuleSP module_sp(GetModule()); + if (module_sp) { + std::lock_guard guard(module_sp->GetMutex()); + lldb::offset_t offset = MachHeaderSizeFromMagic(m_header.magic); + for (uint32_t i = 0; i < m_header.ncmds; ++i) { + const uint32_t cmd_offset = offset; + llvm::MachO::load_command lc; + if (m_data.GetU32(&offset, &lc.cmd, 2) == nullptr) + break; + if (lc.cmd == LC_NOTE) { + char data_owner[17]; + m_data.CopyData(offset, 16, data_owner); + data_owner[16] = '\0'; + offset += 16; + uint64_t fileoff = m_data.GetU64_unchecked(&offset); + + // "addrable bits" has a uint32_t version and a uint32_t + // number of bits used in addressing. + if (strcmp("addrable bits", data_owner) == 0) { + offset = fileoff; + uint32_t version; + if (m_data.GetU32(&offset, &version, 1) != nullptr) { + if (version == 3) { + uint32_t num_addr_bits = m_data.GetU32_unchecked(&offset); + if (num_addr_bits != 0) { + mask = ~((1ULL << num_addr_bits) - 1); + } + break; + } + } + } + } + offset = cmd_offset + lc.cmdsize; + } + } + return mask; +} + +bool ObjectFileMachO::GetCorefileMainBinaryInfo(addr_t &address, UUID &uuid, + ObjectFile::BinaryType &type) { address = LLDB_INVALID_ADDRESS; uuid.Clear(); ModuleSP module_sp(GetModule()); @@ -5533,7 +5624,7 @@ bool ObjectFileMachO::GetCorefileMainBinaryInfo(addr_t &address, UUID &uuid) { lldb::offset_t offset = MachHeaderSizeFromMagic(m_header.magic); for (uint32_t i = 0; i < m_header.ncmds; ++i) { const uint32_t cmd_offset = offset; - load_command lc; + llvm::MachO::load_command lc; if (m_data.GetU32(&offset, &lc.cmd, 2) == nullptr) break; if (lc.cmd == LC_NOTE) { @@ -5547,24 +5638,43 @@ bool ObjectFileMachO::GetCorefileMainBinaryInfo(addr_t &address, UUID &uuid) { // "main bin spec" (main binary specification) data payload is // formatted: // uint32_t version [currently 1] - // uint32_t type [0 == unspecified, 1 == kernel, 2 == user - // process] uint64_t address [ UINT64_MAX if address not - // specified ] uuid_t uuid [ all zero's if uuid not - // specified ] uint32_t log2_pagesize [ process page size in log base - // 2, e.g. 4k pages are 12. 0 for unspecified ] + // uint32_t type [0 == unspecified, 1 == kernel, + // 2 == user process, 3 == firmware ] + // uint64_t address [ UINT64_MAX if address not specified ] + // uuid_t uuid [ all zero's if uuid not specified ] + // uint32_t log2_pagesize [ process page size in log base + // 2, e.g. 4k pages are 12. + // 0 for unspecified ] + // uint32_t unused [ for alignment ] if (strcmp("main bin spec", data_owner) == 0 && size >= 32) { offset = fileoff; uint32_t version; if (m_data.GetU32(&offset, &version, 1) != nullptr && version == 1) { - uint32_t type = 0; + uint32_t binspec_type = 0; uuid_t raw_uuid; memset(raw_uuid, 0, sizeof(uuid_t)); - if (m_data.GetU32(&offset, &type, 1) && + if (m_data.GetU32(&offset, &binspec_type, 1) && m_data.GetU64(&offset, &address, 1) && m_data.CopyData(offset, sizeof(uuid_t), raw_uuid) != 0) { uuid = UUID::fromOptionalData(raw_uuid, sizeof(uuid_t)); + // convert the "main bin spec" type into our + // ObjectFile::BinaryType enum + switch (binspec_type) { + case 0: + type = eBinaryTypeUnknown; + break; + case 1: + type = eBinaryTypeKernel; + break; + case 2: + type = eBinaryTypeUser; + break; + case 3: + type = eBinaryTypeStandalone; + break; + } return true; } } @@ -5724,7 +5834,7 @@ llvm::VersionTuple ObjectFileMachO::GetVersion() { ModuleSP module_sp(GetModule()); if (module_sp) { std::lock_guard guard(module_sp->GetMutex()); - struct dylib_command load_cmd; + llvm::MachO::dylib_command load_cmd; lldb::offset_t offset = MachHeaderSizeFromMagic(m_header.magic); uint32_t version_cmd = 0; uint64_t version = 0; @@ -5807,8 +5917,7 @@ void ObjectFileMachO::GetLLDBSharedCacheUUID(addr_t &base_addr, UUID &uuid) { uuid.Clear(); base_addr = LLDB_INVALID_ADDRESS; -#if defined(__APPLE__) && \ - (defined(__arm__) || defined(__arm64__) || defined(__aarch64__)) +#if defined(__APPLE__) uint8_t *(*dyld_get_all_image_infos)(void); dyld_get_all_image_infos = (uint8_t * (*)()) dlsym(RTLD_DEFAULT, "_dyld_get_all_image_infos"); @@ -5892,7 +6001,7 @@ llvm::VersionTuple ObjectFileMachO::GetMinimumOSVersion() { for (uint32_t i = 0; i < m_header.ncmds; ++i) { const lldb::offset_t load_cmd_offset = offset; - version_min_command lc; + llvm::MachO::version_min_command lc; if (m_data.GetU32(&offset, &lc.cmd, 2) == nullptr) break; if (lc.cmd == llvm::MachO::LC_VERSION_MIN_MACOSX || @@ -5953,7 +6062,7 @@ llvm::VersionTuple ObjectFileMachO::GetSDKVersion() { for (uint32_t i = 0; i < m_header.ncmds; ++i) { const lldb::offset_t load_cmd_offset = offset; - version_min_command lc; + llvm::MachO::version_min_command lc; if (m_data.GetU32(&offset, &lc.cmd, 2) == nullptr) break; if (lc.cmd == llvm::MachO::LC_VERSION_MIN_MACOSX || @@ -5982,7 +6091,7 @@ llvm::VersionTuple ObjectFileMachO::GetSDKVersion() { for (uint32_t i = 0; i < m_header.ncmds; ++i) { const lldb::offset_t load_cmd_offset = offset; - version_min_command lc; + llvm::MachO::version_min_command lc; if (m_data.GetU32(&offset, &lc.cmd, 2) == nullptr) break; if (lc.cmd == llvm::MachO::LC_BUILD_VERSION) { @@ -6139,11 +6248,257 @@ bool ObjectFileMachO::SetLoadAddress(Target &target, lldb::addr_t value, return num_loaded_sections > 0; } +struct all_image_infos_header { + uint32_t version; // currently 1 + uint32_t imgcount; // number of binary images + uint64_t entries_fileoff; // file offset in the corefile of where the array of + // struct entry's begin. + uint32_t entries_size; // size of 'struct entry'. + uint32_t unused; +}; + +struct image_entry { + uint64_t filepath_offset; // offset in corefile to c-string of the file path, + // UINT64_MAX if unavailable. + uuid_t uuid; // uint8_t[16]. should be set to all zeroes if + // uuid is unknown. + uint64_t load_address; // UINT64_MAX if unknown. + uint64_t seg_addrs_offset; // offset to the array of struct segment_vmaddr's. + uint32_t segment_count; // The number of segments for this binary. + uint32_t unused; + + image_entry() { + filepath_offset = UINT64_MAX; + memset(&uuid, 0, sizeof(uuid_t)); + segment_count = 0; + load_address = UINT64_MAX; + seg_addrs_offset = UINT64_MAX; + unused = 0; + } + image_entry(const image_entry &rhs) { + filepath_offset = rhs.filepath_offset; + memcpy(&uuid, &rhs.uuid, sizeof(uuid_t)); + segment_count = rhs.segment_count; + seg_addrs_offset = rhs.seg_addrs_offset; + load_address = rhs.load_address; + unused = rhs.unused; + } +}; + +struct segment_vmaddr { + char segname[16]; + uint64_t vmaddr; + uint64_t unused; + + segment_vmaddr() { + memset(&segname, 0, 16); + vmaddr = UINT64_MAX; + unused = 0; + } + segment_vmaddr(const segment_vmaddr &rhs) { + memcpy(&segname, &rhs.segname, 16); + vmaddr = rhs.vmaddr; + unused = rhs.unused; + } +}; + +// Write the payload for the "all image infos" LC_NOTE into +// the supplied all_image_infos_payload, assuming that this +// will be written into the corefile starting at +// initial_file_offset. +// +// The placement of this payload is a little tricky. We're +// laying this out as +// +// 1. header (struct all_image_info_header) +// 2. Array of fixed-size (struct image_entry)'s, one +// per binary image present in the process. +// 3. Arrays of (struct segment_vmaddr)'s, a varying number +// for each binary image. +// 4. Variable length c-strings of binary image filepaths, +// one per binary. +// +// To compute where everything will be laid out in the +// payload, we need to iterate over the images and calculate +// how many segment_vmaddr structures each image will need, +// and how long each image's filepath c-string is. There +// are some multiple passes over the image list while calculating +// everything. + +static offset_t +CreateAllImageInfosPayload(const lldb::ProcessSP &process_sp, + offset_t initial_file_offset, + StreamString &all_image_infos_payload) { + Target &target = process_sp->GetTarget(); + const ModuleList &modules = target.GetImages(); + size_t modules_count = modules.GetSize(); + + std::set executing_uuids; + ThreadList &thread_list(process_sp->GetThreadList()); + for (uint32_t i = 0; i < thread_list.GetSize(); i++) { + ThreadSP thread_sp = thread_list.GetThreadAtIndex(i); + uint32_t stack_frame_count = thread_sp->GetStackFrameCount(); + for (uint32_t j = 0; j < stack_frame_count; j++) { + StackFrameSP stack_frame_sp = thread_sp->GetStackFrameAtIndex(j); + Address pc = stack_frame_sp->GetFrameCodeAddress(); + ModuleSP module_sp = pc.GetModule(); + if (module_sp) { + UUID uuid = module_sp->GetUUID(); + if (uuid.IsValid()) { + executing_uuids.insert(uuid.GetAsString()); + } + } + } + } + + struct all_image_infos_header infos; + infos.version = 1; + infos.imgcount = modules_count; + infos.entries_size = sizeof(image_entry); + infos.entries_fileoff = initial_file_offset + sizeof(all_image_infos_header); + infos.unused = 0; + + all_image_infos_payload.PutHex32(infos.version); + all_image_infos_payload.PutHex32(infos.imgcount); + all_image_infos_payload.PutHex64(infos.entries_fileoff); + all_image_infos_payload.PutHex32(infos.entries_size); + all_image_infos_payload.PutHex32(infos.unused); + + // First create the structures for all of the segment name+vmaddr vectors + // for each module, so we will know the size of them as we add the + // module entries. + std::vector> modules_segment_vmaddrs; + for (size_t i = 0; i < modules_count; i++) { + ModuleSP module = modules.GetModuleAtIndex(i); + + SectionList *sections = module->GetSectionList(); + size_t sections_count = sections->GetSize(); + std::vector segment_vmaddrs; + for (size_t j = 0; j < sections_count; j++) { + SectionSP section = sections->GetSectionAtIndex(j); + if (!section->GetParent().get()) { + addr_t vmaddr = section->GetLoadBaseAddress(&target); + if (vmaddr == LLDB_INVALID_ADDRESS) + continue; + ConstString name = section->GetName(); + segment_vmaddr seg_vmaddr; + strncpy(seg_vmaddr.segname, name.AsCString(), + sizeof(seg_vmaddr.segname)); + seg_vmaddr.vmaddr = vmaddr; + seg_vmaddr.unused = 0; + segment_vmaddrs.push_back(seg_vmaddr); + } + } + modules_segment_vmaddrs.push_back(segment_vmaddrs); + } + + offset_t size_of_vmaddr_structs = 0; + for (size_t i = 0; i < modules_segment_vmaddrs.size(); i++) { + size_of_vmaddr_structs += + modules_segment_vmaddrs[i].size() * sizeof(segment_vmaddr); + } + + offset_t size_of_filepath_cstrings = 0; + for (size_t i = 0; i < modules_count; i++) { + ModuleSP module_sp = modules.GetModuleAtIndex(i); + size_of_filepath_cstrings += module_sp->GetFileSpec().GetPath().size() + 1; + } + + // Calculate the file offsets of our "all image infos" payload in the + // corefile. initial_file_offset the original value passed in to this method. + + offset_t start_of_entries = + initial_file_offset + sizeof(all_image_infos_header); + offset_t start_of_seg_vmaddrs = + start_of_entries + sizeof(image_entry) * modules_count; + offset_t start_of_filenames = start_of_seg_vmaddrs + size_of_vmaddr_structs; + + offset_t final_file_offset = start_of_filenames + size_of_filepath_cstrings; + + // Now write the one-per-module 'struct image_entry' into the + // StringStream; keep track of where the struct segment_vmaddr + // entries for each module will end up in the corefile. + + offset_t current_string_offset = start_of_filenames; + offset_t current_segaddrs_offset = start_of_seg_vmaddrs; + std::vector image_entries; + for (size_t i = 0; i < modules_count; i++) { + ModuleSP module_sp = modules.GetModuleAtIndex(i); + + struct image_entry ent; + memcpy(&ent.uuid, module_sp->GetUUID().GetBytes().data(), sizeof(ent.uuid)); + if (modules_segment_vmaddrs[i].size() > 0) { + ent.segment_count = modules_segment_vmaddrs[i].size(); + ent.seg_addrs_offset = current_segaddrs_offset; + } + ent.filepath_offset = current_string_offset; + ObjectFile *objfile = module_sp->GetObjectFile(); + if (objfile) { + Address base_addr(objfile->GetBaseAddress()); + if (base_addr.IsValid()) { + ent.load_address = base_addr.GetLoadAddress(&target); + } + } + + all_image_infos_payload.PutHex64(ent.filepath_offset); + all_image_infos_payload.PutRawBytes(ent.uuid, sizeof(ent.uuid)); + all_image_infos_payload.PutHex64(ent.load_address); + all_image_infos_payload.PutHex64(ent.seg_addrs_offset); + all_image_infos_payload.PutHex32(ent.segment_count); + + if (executing_uuids.find(module_sp->GetUUID().GetAsString()) != + executing_uuids.end()) + all_image_infos_payload.PutHex32(1); + else + all_image_infos_payload.PutHex32(0); + + current_segaddrs_offset += ent.segment_count * sizeof(segment_vmaddr); + current_string_offset += module_sp->GetFileSpec().GetPath().size() + 1; + } + + // Now write the struct segment_vmaddr entries into the StringStream. + + for (size_t i = 0; i < modules_segment_vmaddrs.size(); i++) { + if (modules_segment_vmaddrs[i].size() == 0) + continue; + for (struct segment_vmaddr segvm : modules_segment_vmaddrs[i]) { + all_image_infos_payload.PutRawBytes(segvm.segname, sizeof(segvm.segname)); + all_image_infos_payload.PutHex64(segvm.vmaddr); + all_image_infos_payload.PutHex64(segvm.unused); + } + } + + for (size_t i = 0; i < modules_count; i++) { + ModuleSP module_sp = modules.GetModuleAtIndex(i); + std::string filepath = module_sp->GetFileSpec().GetPath(); + all_image_infos_payload.PutRawBytes(filepath.data(), filepath.size() + 1); + } + + return final_file_offset; +} + +// Temp struct used to combine contiguous memory regions with +// identical permissions. +struct page_object { + addr_t addr; + addr_t size; + uint32_t prot; +}; + bool ObjectFileMachO::SaveCore(const lldb::ProcessSP &process_sp, - const FileSpec &outfile, Status &error) { + const FileSpec &outfile, + lldb::SaveCoreStyle &core_style, Status &error) { if (!process_sp) return false; + // For Mach-O, we can only create full corefiles or dirty-page-only + // corefiles. The default is dirty-page-only. + if (core_style != SaveCoreStyle::eSaveCoreFull) { + core_style = SaveCoreStyle::eSaveCoreDirtyOnly; + } else { + core_style = SaveCoreStyle::eSaveCoreFull; + } + Target &target = process_sp->GetTarget(); const ArchSpec target_arch = target.GetArchitecture(); const llvm::Triple &target_triple = target_arch.GetTriple(); @@ -6171,20 +6526,16 @@ bool ObjectFileMachO::SaveCore(const lldb::ProcessSP &process_sp, } if (make_core) { - std::vector segment_load_commands; + std::vector segment_load_commands; // uint32_t range_info_idx = 0; MemoryRegionInfo range_info; Status range_error = process_sp->GetMemoryRegionInfo(0, range_info); const uint32_t addr_byte_size = target_arch.GetAddressByteSize(); const ByteOrder byte_order = target_arch.GetByteOrder(); + std::vector pages_to_copy; + if (range_error.Success()) { while (range_info.GetRange().GetRangeBase() != LLDB_INVALID_ADDRESS) { - const addr_t addr = range_info.GetRange().GetRangeBase(); - const addr_t size = range_info.GetRange().GetByteSize(); - - if (size == 0) - break; - // Calculate correct protections uint32_t prot = 0; if (range_info.GetReadable() == MemoryRegionInfo::eYes) @@ -6194,32 +6545,33 @@ bool ObjectFileMachO::SaveCore(const lldb::ProcessSP &process_sp, if (range_info.GetExecutable() == MemoryRegionInfo::eYes) prot |= VM_PROT_EXECUTE; + const addr_t addr = range_info.GetRange().GetRangeBase(); + const addr_t size = range_info.GetRange().GetByteSize(); + + if (size == 0) + break; + if (prot != 0) { - uint32_t cmd_type = LC_SEGMENT_64; - uint32_t segment_size = sizeof(segment_command_64); - if (addr_byte_size == 4) { - cmd_type = LC_SEGMENT; - segment_size = sizeof(segment_command); + addr_t pagesize = range_info.GetPageSize(); + const llvm::Optional> &dirty_page_list = + range_info.GetDirtyPageList(); + if (core_style == SaveCoreStyle::eSaveCoreDirtyOnly && + dirty_page_list.hasValue()) { + core_style = SaveCoreStyle::eSaveCoreDirtyOnly; + for (addr_t dirtypage : dirty_page_list.getValue()) { + page_object obj; + obj.addr = dirtypage; + obj.size = pagesize; + obj.prot = prot; + pages_to_copy.push_back(obj); + } + } else { + page_object obj; + obj.addr = addr; + obj.size = size; + obj.prot = prot; + pages_to_copy.push_back(obj); } - segment_command_64 segment = { - cmd_type, // uint32_t cmd; - segment_size, // uint32_t cmdsize; - {0}, // char segname[16]; - addr, // uint64_t vmaddr; // uint32_t for 32-bit Mach-O - size, // uint64_t vmsize; // uint32_t for 32-bit Mach-O - 0, // uint64_t fileoff; // uint32_t for 32-bit Mach-O - size, // uint64_t filesize; // uint32_t for 32-bit Mach-O - prot, // uint32_t maxprot; - prot, // uint32_t initprot; - 0, // uint32_t nsects; - 0}; // uint32_t flags; - segment_load_commands.push_back(segment); - } else { - // No protections and a size of 1 used to be returned from old - // debugservers when we asked about a region that was past the - // last memory region and it indicates the end... - if (size == 1) - break; } range_error = process_sp->GetMemoryRegionInfo( @@ -6228,9 +6580,54 @@ bool ObjectFileMachO::SaveCore(const lldb::ProcessSP &process_sp, break; } + // Combine contiguous entries that have the same + // protections so we don't have an excess of + // load commands. + std::vector combined_page_objects; + page_object last_obj; + last_obj.addr = LLDB_INVALID_ADDRESS; + for (page_object obj : pages_to_copy) { + if (last_obj.addr == LLDB_INVALID_ADDRESS) { + last_obj = obj; + continue; + } + if (last_obj.addr + last_obj.size == obj.addr && + last_obj.prot == obj.prot) { + last_obj.size += obj.size; + continue; + } + combined_page_objects.push_back(last_obj); + last_obj = obj; + } + + for (page_object obj : combined_page_objects) { + uint32_t cmd_type = LC_SEGMENT_64; + uint32_t segment_size = sizeof(llvm::MachO::segment_command_64); + if (addr_byte_size == 4) { + cmd_type = LC_SEGMENT; + segment_size = sizeof(llvm::MachO::segment_command); + } + llvm::MachO::segment_command_64 segment = { + cmd_type, // uint32_t cmd; + segment_size, // uint32_t cmdsize; + {0}, // char segname[16]; + obj.addr, // uint64_t vmaddr; // uint32_t for 32-bit + // Mach-O + obj.size, // uint64_t vmsize; // uint32_t for 32-bit + // Mach-O + 0, // uint64_t fileoff; // uint32_t for 32-bit Mach-O + obj.size, // uint64_t filesize; // uint32_t for 32-bit + // Mach-O + obj.prot, // uint32_t maxprot; + obj.prot, // uint32_t initprot; + 0, // uint32_t nsects; + 0}; // uint32_t flags; + segment_load_commands.push_back(segment); + } + StreamString buffer(Stream::eBinary, addr_byte_size, byte_order); - mach_header_64 mach_header; + llvm::MachO::mach_header_64 mach_header; if (addr_byte_size == 8) { mach_header.magic = MH_MAGIC_64; } else { @@ -6285,11 +6682,11 @@ bool ObjectFileMachO::SaveCore(const lldb::ProcessSP &process_sp, // The size of the load command is the size of the segments... if (addr_byte_size == 8) { - mach_header.sizeofcmds = - segment_load_commands.size() * sizeof(struct segment_command_64); + mach_header.sizeofcmds = segment_load_commands.size() * + sizeof(llvm::MachO::segment_command_64); } else { - mach_header.sizeofcmds = - segment_load_commands.size() * sizeof(struct segment_command); + mach_header.sizeofcmds = segment_load_commands.size() * + sizeof(llvm::MachO::segment_command); } // and the size of all LC_THREAD load command @@ -6298,6 +6695,19 @@ bool ObjectFileMachO::SaveCore(const lldb::ProcessSP &process_sp, mach_header.sizeofcmds += 8 + LC_THREAD_data.GetSize(); } + // Bits will be set to indicate which bits are NOT used in + // addressing in this process or 0 for unknown. + uint64_t address_mask = process_sp->GetCodeAddressMask(); + if (address_mask != 0) { + // LC_NOTE "addrable bits" + mach_header.ncmds++; + mach_header.sizeofcmds += sizeof(llvm::MachO::note_command); + } + + // LC_NOTE "all image infos" + mach_header.ncmds++; + mach_header.sizeofcmds += sizeof(llvm::MachO::note_command); + // Write the mach header buffer.PutHex32(mach_header.magic); buffer.PutHex32(mach_header.cputype); @@ -6313,11 +6723,54 @@ bool ObjectFileMachO::SaveCore(const lldb::ProcessSP &process_sp, // Skip the mach header and all load commands and align to the next // 0x1000 byte boundary addr_t file_offset = buffer.GetSize() + mach_header.sizeofcmds; - if (file_offset & 0x00000fff) { - file_offset += 0x00001000ull; - file_offset &= (~0x00001000ull + 1); + + file_offset = llvm::alignTo(file_offset, 16); + std::vector> lc_notes; + + // Add "addrable bits" LC_NOTE when an address mask is available + if (address_mask != 0) { + std::unique_ptr addrable_bits_lcnote_up( + new LCNoteEntry(addr_byte_size, byte_order)); + addrable_bits_lcnote_up->name = "addrable bits"; + addrable_bits_lcnote_up->payload_file_offset = file_offset; + int bits = std::bitset<64>(~address_mask).count(); + addrable_bits_lcnote_up->payload.PutHex32(3); // version + addrable_bits_lcnote_up->payload.PutHex32( + bits); // # of bits used for addressing + addrable_bits_lcnote_up->payload.PutHex64(0); // unused + + file_offset += addrable_bits_lcnote_up->payload.GetSize(); + + lc_notes.push_back(std::move(addrable_bits_lcnote_up)); + } + + // Add "all image infos" LC_NOTE + std::unique_ptr all_image_infos_lcnote_up( + new LCNoteEntry(addr_byte_size, byte_order)); + all_image_infos_lcnote_up->name = "all image infos"; + all_image_infos_lcnote_up->payload_file_offset = file_offset; + file_offset = CreateAllImageInfosPayload( + process_sp, file_offset, all_image_infos_lcnote_up->payload); + lc_notes.push_back(std::move(all_image_infos_lcnote_up)); + + // Add LC_NOTE load commands + for (auto &lcnote : lc_notes) { + // Add the LC_NOTE load command to the file. + buffer.PutHex32(LC_NOTE); + buffer.PutHex32(sizeof(llvm::MachO::note_command)); + char namebuf[16]; + memset(namebuf, 0, sizeof(namebuf)); + // this is the uncommon case where strncpy is exactly + // the right one, doesn't need to be nul terminated. + strncpy(namebuf, lcnote->name.c_str(), sizeof(namebuf)); + buffer.PutRawBytes(namebuf, sizeof(namebuf)); + buffer.PutHex64(lcnote->payload_file_offset); + buffer.PutHex64(lcnote->payload.GetSize()); } + // Align to 4096-byte page boundary for the LC_SEGMENTs. + file_offset = llvm::alignTo(file_offset, 4096); + for (auto &segment : segment_load_commands) { segment.fileoff = file_offset; file_offset += segment.filesize; @@ -6333,14 +6786,6 @@ bool ObjectFileMachO::SaveCore(const lldb::ProcessSP &process_sp, // Write out all of the segment load commands for (const auto &segment : segment_load_commands) { - printf("0x%8.8x 0x%8.8x [0x%16.16" PRIx64 " - 0x%16.16" PRIx64 - ") [0x%16.16" PRIx64 " 0x%16.16" PRIx64 - ") 0x%8.8x 0x%8.8x 0x%8.8x 0x%8.8x]\n", - segment.cmd, segment.cmdsize, segment.vmaddr, - segment.vmaddr + segment.vmsize, segment.fileoff, - segment.filesize, segment.maxprot, segment.initprot, - segment.nsects, segment.flags); - buffer.PutHex32(segment.cmd); buffer.PutHex32(segment.cmdsize); buffer.PutRawBytes(segment.segname, sizeof(segment.segname)); @@ -6375,6 +6820,22 @@ bool ObjectFileMachO::SaveCore(const lldb::ProcessSP &process_sp, error = core_file.get()->Write(buffer.GetString().data(), bytes_written); if (error.Success()) { + + for (auto &lcnote : lc_notes) { + if (core_file.get()->SeekFromStart(lcnote->payload_file_offset) == + -1) { + error.SetErrorStringWithFormat("Unable to seek to corefile pos " + "to write '%s' LC_NOTE payload", + lcnote->name.c_str()); + return false; + } + bytes_written = lcnote->payload.GetSize(); + error = core_file.get()->Write(lcnote->payload.GetData(), + bytes_written); + if (!error.Success()) + return false; + } + // Now write the file data for all memory segments in the process for (const auto &segment : segment_load_commands) { if (core_file.get()->SeekFromStart(segment.fileoff) == -1) { @@ -6384,9 +6845,10 @@ bool ObjectFileMachO::SaveCore(const lldb::ProcessSP &process_sp, break; } - printf("Saving %" PRId64 - " bytes of data for memory region at 0x%" PRIx64 "\n", - segment.vmsize, segment.vmaddr); + target.GetDebugger().GetAsyncOutputStream()->Printf( + "Saving %" PRId64 + " bytes of data for memory region at 0x%" PRIx64 "\n", + segment.vmsize, segment.vmaddr); addr_t bytes_left = segment.vmsize; addr_t addr = segment.vmaddr; Status memory_read_error; @@ -6428,3 +6890,121 @@ bool ObjectFileMachO::SaveCore(const lldb::ProcessSP &process_sp, } return false; } + +ObjectFileMachO::MachOCorefileAllImageInfos +ObjectFileMachO::GetCorefileAllImageInfos() { + MachOCorefileAllImageInfos image_infos; + + // Look for an "all image infos" LC_NOTE. + lldb::offset_t offset = MachHeaderSizeFromMagic(m_header.magic); + for (uint32_t i = 0; i < m_header.ncmds; ++i) { + const uint32_t cmd_offset = offset; + llvm::MachO::load_command lc; + if (m_data.GetU32(&offset, &lc.cmd, 2) == nullptr) + break; + if (lc.cmd == LC_NOTE) { + char data_owner[17]; + m_data.CopyData(offset, 16, data_owner); + data_owner[16] = '\0'; + offset += 16; + uint64_t fileoff = m_data.GetU64_unchecked(&offset); + offset += 4; /* size unused */ + + if (strcmp("all image infos", data_owner) == 0) { + offset = fileoff; + // Read the struct all_image_infos_header. + uint32_t version = m_data.GetU32(&offset); + if (version != 1) { + return image_infos; + } + uint32_t imgcount = m_data.GetU32(&offset); + uint64_t entries_fileoff = m_data.GetU64(&offset); + offset += 4; // uint32_t entries_size; + offset += 4; // uint32_t unused; + + offset = entries_fileoff; + for (uint32_t i = 0; i < imgcount; i++) { + // Read the struct image_entry. + offset_t filepath_offset = m_data.GetU64(&offset); + uuid_t uuid; + memcpy(&uuid, m_data.GetData(&offset, sizeof(uuid_t)), + sizeof(uuid_t)); + uint64_t load_address = m_data.GetU64(&offset); + offset_t seg_addrs_offset = m_data.GetU64(&offset); + uint32_t segment_count = m_data.GetU32(&offset); + uint32_t currently_executing = m_data.GetU32(&offset); + + MachOCorefileImageEntry image_entry; + image_entry.filename = (const char *)m_data.GetCStr(&filepath_offset); + image_entry.uuid = UUID::fromData(uuid, sizeof(uuid_t)); + image_entry.load_address = load_address; + image_entry.currently_executing = currently_executing; + + offset_t seg_vmaddrs_offset = seg_addrs_offset; + for (uint32_t j = 0; j < segment_count; j++) { + char segname[17]; + m_data.CopyData(seg_vmaddrs_offset, 16, segname); + segname[16] = '\0'; + seg_vmaddrs_offset += 16; + uint64_t vmaddr = m_data.GetU64(&seg_vmaddrs_offset); + seg_vmaddrs_offset += 8; /* unused */ + + std::tuple new_seg{ConstString(segname), + vmaddr}; + image_entry.segment_load_addresses.push_back(new_seg); + } + image_infos.all_image_infos.push_back(image_entry); + } + } + } + offset = cmd_offset + lc.cmdsize; + } + + return image_infos; +} + +bool ObjectFileMachO::LoadCoreFileImages(lldb_private::Process &process) { + MachOCorefileAllImageInfos image_infos = GetCorefileAllImageInfos(); + bool added_images = false; + if (image_infos.IsValid()) { + for (const MachOCorefileImageEntry &image : image_infos.all_image_infos) { + ModuleSpec module_spec; + module_spec.GetUUID() = image.uuid; + module_spec.GetFileSpec() = FileSpec(image.filename.c_str()); + if (image.currently_executing) { + Symbols::DownloadObjectAndSymbolFile(module_spec, true); + if (FileSystem::Instance().Exists(module_spec.GetFileSpec())) { + process.GetTarget().GetOrCreateModule(module_spec, false); + } + } + Status error; + ModuleSP module_sp = + process.GetTarget().GetOrCreateModule(module_spec, false, &error); + if (!module_sp.get() || !module_sp->GetObjectFile()) { + if (image.load_address != LLDB_INVALID_ADDRESS) { + module_sp = process.ReadModuleFromMemory(module_spec.GetFileSpec(), + image.load_address); + } + } + if (module_sp.get() && module_sp->GetObjectFile()) { + added_images = true; + if (module_sp->GetObjectFile()->GetType() == + ObjectFile::eTypeExecutable) { + process.GetTarget().SetExecutableModule(module_sp, eLoadDependentsNo); + } + for (auto name_vmaddr_tuple : image.segment_load_addresses) { + SectionList *sectlist = module_sp->GetObjectFile()->GetSectionList(); + if (sectlist) { + SectionSP sect_sp = + sectlist->FindSectionByName(std::get<0>(name_vmaddr_tuple)); + if (sect_sp) { + process.GetTarget().SetSectionLoadAddress( + sect_sp, std::get<1>(name_vmaddr_tuple)); + } + } + } + } + } + } + return added_images; +} diff --git a/gnu/llvm/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h b/gnu/llvm/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h index 979e637ef6f..3e8c84f55e9 100644 --- a/gnu/llvm/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h +++ b/gnu/llvm/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h @@ -15,6 +15,7 @@ #include "lldb/Symbol/ObjectFile.h" #include "lldb/Utility/FileSpec.h" #include "lldb/Utility/RangeMap.h" +#include "lldb/Utility/StreamString.h" #include "lldb/Utility/UUID.h" // This class needs to be hidden as eventually belongs in a plugin that @@ -58,6 +59,7 @@ public: static bool SaveCore(const lldb::ProcessSP &process_sp, const lldb_private::FileSpec &outfile, + lldb::SaveCoreStyle &core_style, lldb_private::Status &error); static bool MagicBytesMatch(lldb::DataBufferSP &data_sp, lldb::addr_t offset, @@ -112,7 +114,13 @@ public: std::string GetIdentifierString() override; - bool GetCorefileMainBinaryInfo (lldb::addr_t &address, lldb_private::UUID &uuid) override; + lldb::addr_t GetAddressMask() override; + + bool GetCorefileMainBinaryInfo(lldb::addr_t &address, + lldb_private::UUID &uuid, + ObjectFile::BinaryType &type) override; + + bool LoadCoreFileImages(lldb_private::Process &process) override; lldb::RegisterContextSP GetThreadContextAtIndex(uint32_t idx, lldb_private::Thread &thread) override; @@ -207,6 +215,40 @@ protected: bool SectionIsLoadable(const lldb_private::Section *section); + /// A corefile may include metadata about all of the binaries that were + /// present in the process when the corefile was taken. This is only + /// implemented for Mach-O files for now; we'll generalize it when we + /// have other systems that can include the same. + struct MachOCorefileImageEntry { + std::string filename; + lldb_private::UUID uuid; + lldb::addr_t load_address = LLDB_INVALID_ADDRESS; + bool currently_executing; + std::vector> + segment_load_addresses; + }; + + struct LCNoteEntry { + LCNoteEntry(uint32_t addr_byte_size, lldb::ByteOrder byte_order) + : payload(lldb_private::Stream::eBinary, addr_byte_size, byte_order) {} + + std::string name; + lldb::addr_t payload_file_offset = 0; + lldb_private::StreamString payload; + }; + + struct MachOCorefileAllImageInfos { + std::vector all_image_infos; + bool IsValid() { return all_image_infos.size() > 0; } + }; + + /// Get the list of binary images that were present in the process + /// when the corefile was produced. + /// \return + /// The MachOCorefileAllImageInfos object returned will have + /// IsValid() == false if the information is unavailable. + MachOCorefileAllImageInfos GetCorefileAllImageInfos(); + llvm::MachO::mach_header m_header; static lldb_private::ConstString GetSegmentNameTEXT(); static lldb_private::ConstString GetSegmentNameDATA(); @@ -225,6 +267,8 @@ protected: typedef lldb_private::RangeVector FileRangeArray; lldb_private::Address m_entry_point_address; FileRangeArray m_thread_context_offsets; + lldb::offset_t m_linkedit_original_offset; + lldb::addr_t m_text_address; bool m_thread_context_offsets_valid; lldb_private::FileSpecList m_reexported_dylibs; bool m_allow_assembly_emulation_unwind_plans; diff --git a/gnu/llvm/lldb/source/Plugins/ObjectFile/PDB/CMakeLists.txt b/gnu/llvm/lldb/source/Plugins/ObjectFile/PDB/CMakeLists.txt new file mode 100644 index 00000000000..d5ade2b93ad --- /dev/null +++ b/gnu/llvm/lldb/source/Plugins/ObjectFile/PDB/CMakeLists.txt @@ -0,0 +1,10 @@ +add_lldb_library(lldbPluginObjectFilePDB PLUGIN + ObjectFilePDB.cpp + + LINK_LIBS + lldbCore + lldbSymbol + lldbUtility + LINK_COMPONENTS + Support + ) diff --git a/gnu/llvm/lldb/source/Plugins/ObjectFile/PDB/ObjectFilePDB.cpp b/gnu/llvm/lldb/source/Plugins/ObjectFile/PDB/ObjectFilePDB.cpp new file mode 100644 index 00000000000..cb7bbeeca05 --- /dev/null +++ b/gnu/llvm/lldb/source/Plugins/ObjectFile/PDB/ObjectFilePDB.cpp @@ -0,0 +1,197 @@ +//===-- ObjectFilePDB.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 "ObjectFilePDB.h" +#include "lldb/Core/Module.h" +#include "lldb/Core/ModuleSpec.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Core/Section.h" +#include "lldb/Utility/StreamString.h" +#include "llvm/BinaryFormat/Magic.h" +#include "llvm/DebugInfo/PDB/Native/DbiStream.h" +#include "llvm/DebugInfo/PDB/Native/InfoStream.h" +#include "llvm/DebugInfo/PDB/Native/NativeSession.h" +#include "llvm/DebugInfo/PDB/Native/PDBFile.h" +#include "llvm/DebugInfo/PDB/PDB.h" +#include "llvm/Support/BinaryByteStream.h" + +using namespace lldb; +using namespace lldb_private; +using namespace llvm::pdb; +using namespace llvm::codeview; + +LLDB_PLUGIN_DEFINE(ObjectFilePDB) + +static UUID GetPDBUUID(InfoStream &IS) { + UUID::CvRecordPdb70 debug_info; + memcpy(&debug_info.Uuid, IS.getGuid().Guid, sizeof(debug_info.Uuid)); + debug_info.Age = IS.getAge(); + return UUID::fromCvRecord(debug_info); +} + +char ObjectFilePDB::ID; + +void ObjectFilePDB::Initialize() { + PluginManager::RegisterPlugin(GetPluginNameStatic(), + GetPluginDescriptionStatic(), CreateInstance, + CreateMemoryInstance, GetModuleSpecifications); +} + +void ObjectFilePDB::Terminate() { + PluginManager::UnregisterPlugin(CreateInstance); +} + +ConstString ObjectFilePDB::GetPluginNameStatic() { + static ConstString g_name("pdb"); + return g_name; +} + +ArchSpec ObjectFilePDB::GetArchitecture() { + auto dbi_stream = m_file_up->getPDBDbiStream(); + if (!dbi_stream) { + llvm::consumeError(dbi_stream.takeError()); + return ArchSpec(); + } + + PDB_Machine machine = dbi_stream->getMachineType(); + switch (machine) { + default: + break; + case PDB_Machine::Amd64: + case PDB_Machine::x86: + case PDB_Machine::PowerPC: + case PDB_Machine::PowerPCFP: + case PDB_Machine::Arm: + case PDB_Machine::ArmNT: + case PDB_Machine::Thumb: + case PDB_Machine::Arm64: + ArchSpec arch; + arch.SetArchitecture(eArchTypeCOFF, static_cast(machine), + LLDB_INVALID_CPUTYPE); + return arch; + } + return ArchSpec(); +} + +bool ObjectFilePDB::initPDBFile() { + m_file_up = loadPDBFile(m_file.GetPath(), m_allocator); + if (!m_file_up) + return false; + auto info_stream = m_file_up->getPDBInfoStream(); + if (!info_stream) { + llvm::consumeError(info_stream.takeError()); + return false; + } + m_uuid = GetPDBUUID(*info_stream); + return true; +} + +ObjectFile * +ObjectFilePDB::CreateInstance(const ModuleSP &module_sp, DataBufferSP &data_sp, + offset_t data_offset, const FileSpec *file, + offset_t file_offset, offset_t length) { + auto objfile_up = std::make_unique( + module_sp, data_sp, data_offset, file, file_offset, length); + if (!objfile_up->initPDBFile()) + return nullptr; + return objfile_up.release(); +} + +ObjectFile *ObjectFilePDB::CreateMemoryInstance(const ModuleSP &module_sp, + DataBufferSP &data_sp, + const ProcessSP &process_sp, + addr_t header_addr) { + return nullptr; +} + +size_t ObjectFilePDB::GetModuleSpecifications( + const FileSpec &file, DataBufferSP &data_sp, offset_t data_offset, + offset_t file_offset, offset_t length, ModuleSpecList &specs) { + const size_t initial_count = specs.GetSize(); + ModuleSpec module_spec(file); + llvm::BumpPtrAllocator allocator; + std::unique_ptr pdb_file = loadPDBFile(file.GetPath(), allocator); + if (!pdb_file) + return initial_count; + + auto info_stream = pdb_file->getPDBInfoStream(); + if (!info_stream) { + llvm::consumeError(info_stream.takeError()); + return initial_count; + } + auto dbi_stream = pdb_file->getPDBDbiStream(); + if (!dbi_stream) { + llvm::consumeError(dbi_stream.takeError()); + return initial_count; + } + + lldb_private::UUID &uuid = module_spec.GetUUID(); + uuid = GetPDBUUID(*info_stream); + + ArchSpec &module_arch = module_spec.GetArchitecture(); + switch (dbi_stream->getMachineType()) { + case PDB_Machine::Amd64: + module_arch.SetTriple("x86_64-pc-windows"); + specs.Append(module_spec); + break; + case PDB_Machine::x86: + module_arch.SetTriple("i386-pc-windows"); + specs.Append(module_spec); + module_arch.SetTriple("i686-pc-windows"); + specs.Append(module_spec); + break; + case PDB_Machine::ArmNT: + module_arch.SetTriple("armv7-pc-windows"); + specs.Append(module_spec); + break; + case PDB_Machine::Arm64: + module_arch.SetTriple("aarch64-pc-windows"); + specs.Append(module_spec); + break; + default: + break; + } + + return specs.GetSize() - initial_count; +} + +ObjectFilePDB::ObjectFilePDB(const ModuleSP &module_sp, DataBufferSP &data_sp, + offset_t data_offset, const FileSpec *file, + offset_t offset, offset_t length) + : ObjectFile(module_sp, file, offset, length, data_sp, data_offset) {} + +std::unique_ptr +ObjectFilePDB::loadPDBFile(std::string PdbPath, + llvm::BumpPtrAllocator &Allocator) { + llvm::file_magic magic; + auto ec = llvm::identify_magic(PdbPath, magic); + if (ec || magic != llvm::file_magic::pdb) + return nullptr; + llvm::ErrorOr> ErrorOrBuffer = + llvm::MemoryBuffer::getFile(PdbPath, /*IsText=*/false, + /*RequiresNullTerminator=*/false); + if (!ErrorOrBuffer) + return nullptr; + std::unique_ptr Buffer = std::move(*ErrorOrBuffer); + + llvm::StringRef Path = Buffer->getBufferIdentifier(); + auto Stream = std::make_unique( + std::move(Buffer), llvm::support::little); + + auto File = std::make_unique(Path, std::move(Stream), Allocator); + if (auto EC = File->parseFileHeaders()) { + llvm::consumeError(std::move(EC)); + return nullptr; + } + if (auto EC = File->parseStreamData()) { + llvm::consumeError(std::move(EC)); + return nullptr; + } + + return File; +} diff --git a/gnu/llvm/lldb/source/Plugins/ObjectFile/PDB/ObjectFilePDB.h b/gnu/llvm/lldb/source/Plugins/ObjectFile/PDB/ObjectFilePDB.h new file mode 100644 index 00000000000..19dd46b3140 --- /dev/null +++ b/gnu/llvm/lldb/source/Plugins/ObjectFile/PDB/ObjectFilePDB.h @@ -0,0 +1,107 @@ +//===-- ObjectFilePDB.h --------------------------------------- -*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SOURCE_PLUGINS_OBJECTFILE_PDB_OBJECTFILEPDB_H +#define LLDB_SOURCE_PLUGINS_OBJECTFILE_PDB_OBJECTFILEPDB_H + +#include "lldb/Symbol/ObjectFile.h" +#include "lldb/Utility/ArchSpec.h" +#include "llvm/DebugInfo/PDB/Native/NativeSession.h" +#include "llvm/DebugInfo/PDB/PDBTypes.h" + +namespace lldb_private { + +class ObjectFilePDB : public ObjectFile { +public: + // Static Functions + static void Initialize(); + static void Terminate(); + + static ConstString GetPluginNameStatic(); + static const char *GetPluginDescriptionStatic() { + return "PDB object file reader."; + } + + static std::unique_ptr + loadPDBFile(std::string PdbPath, llvm::BumpPtrAllocator &Allocator); + + static ObjectFile * + CreateInstance(const lldb::ModuleSP &module_sp, lldb::DataBufferSP &data_sp, + lldb::offset_t data_offset, const FileSpec *file, + lldb::offset_t file_offset, lldb::offset_t length); + + static ObjectFile *CreateMemoryInstance(const lldb::ModuleSP &module_sp, + lldb::DataBufferSP &data_sp, + const lldb::ProcessSP &process_sp, + lldb::addr_t header_addr); + + static size_t GetModuleSpecifications(const FileSpec &file, + lldb::DataBufferSP &data_sp, + lldb::offset_t data_offset, + lldb::offset_t file_offset, + lldb::offset_t length, + ModuleSpecList &specs); + + // PluginInterface protocol + ConstString GetPluginName() override { return GetPluginNameStatic(); } + + uint32_t GetPluginVersion() override { return 1; } + + // LLVM RTTI support + static char ID; + bool isA(const void *ClassID) const override { + return ClassID == &ID || ObjectFile::isA(ClassID); + } + static bool classof(const ObjectFile *obj) { return obj->isA(&ID); } + + // ObjectFile Protocol. + uint32_t GetAddressByteSize() const override { return 8; } + + lldb::ByteOrder GetByteOrder() const override { + return lldb::eByteOrderLittle; + } + + bool ParseHeader() override { return true; } + + bool IsExecutable() const override { return false; } + + Symtab *GetSymtab() override { return nullptr; } + + bool IsStripped() override { return false; } + + // No section in PDB file. + void CreateSections(SectionList &unified_section_list) override {} + + void Dump(Stream *s) override {} + + ArchSpec GetArchitecture() override; + + UUID GetUUID() override { return m_uuid; } + + uint32_t GetDependentModules(FileSpecList &files) override { return 0; } + + Type CalculateType() override { return eTypeDebugInfo; } + + Strata CalculateStrata() override { return eStrataUser; } + + llvm::pdb::PDBFile &GetPDBFile() { return *m_file_up; } + + ObjectFilePDB(const lldb::ModuleSP &module_sp, lldb::DataBufferSP &data_sp, + lldb::offset_t data_offset, const FileSpec *file, + lldb::offset_t offset, lldb::offset_t length); + +private: + UUID m_uuid; + llvm::BumpPtrAllocator m_allocator; + std::unique_ptr m_file_up; + + bool initPDBFile(); +}; + +} // namespace lldb_private +#endif // LLDB_PLUGINS_OBJECTFILE_PDB_OBJECTFILEPDB_H diff --git a/gnu/llvm/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp b/gnu/llvm/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp index dac2c496423..9eb1c25d240 100644 --- a/gnu/llvm/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp +++ b/gnu/llvm/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp @@ -43,45 +43,16 @@ using namespace lldb_private; LLDB_PLUGIN_DEFINE(ObjectFilePECOFF) -struct CVInfoPdb70 { - // 16-byte GUID - struct _Guid { - llvm::support::ulittle32_t Data1; - llvm::support::ulittle16_t Data2; - llvm::support::ulittle16_t Data3; - uint8_t Data4[8]; - } Guid; - - llvm::support::ulittle32_t Age; -}; - static UUID GetCoffUUID(llvm::object::COFFObjectFile &coff_obj) { const llvm::codeview::DebugInfo *pdb_info = nullptr; llvm::StringRef pdb_file; - // This part is similar with what has done in minidump parser. if (!coff_obj.getDebugPDBInfo(pdb_info, pdb_file) && pdb_info) { if (pdb_info->PDB70.CVSignature == llvm::OMF::Signature::PDB70) { - using llvm::support::endian::read16be; - using llvm::support::endian::read32be; - - const uint8_t *sig = pdb_info->PDB70.Signature; - struct CVInfoPdb70 info; - info.Guid.Data1 = read32be(sig); - sig += 4; - info.Guid.Data2 = read16be(sig); - sig += 2; - info.Guid.Data3 = read16be(sig); - sig += 2; - memcpy(info.Guid.Data4, sig, 8); - - // Return 20-byte UUID if the Age is not zero - if (pdb_info->PDB70.Age) { - info.Age = read32be(&pdb_info->PDB70.Age); - return UUID::fromOptionalData(&info, sizeof(info)); - } - // Otherwise return 16-byte GUID - return UUID::fromOptionalData(&info.Guid, sizeof(info.Guid)); + UUID::CvRecordPdb70 info; + memcpy(&info.Uuid, pdb_info->PDB70.Signature, sizeof(info.Uuid)); + info.Age = pdb_info->PDB70.Age; + return UUID::fromCvRecord(info); } } @@ -142,7 +113,6 @@ ObjectFile *ObjectFilePECOFF::CreateInstance(const lldb::ModuleSP &module_sp, // Cache coff binary. if (!objfile_up->CreateBinary()) return nullptr; - return objfile_up.release(); } @@ -219,7 +189,9 @@ size_t ObjectFilePECOFF::GetModuleSpecifications( bool ObjectFilePECOFF::SaveCore(const lldb::ProcessSP &process_sp, const lldb_private::FileSpec &outfile, + lldb::SaveCoreStyle &core_style, lldb_private::Status &error) { + core_style = eSaveCoreFull; return SaveMiniDump(process_sp, outfile, error); } @@ -291,7 +263,7 @@ ObjectFilePECOFF::ObjectFilePECOFF(const lldb::ModuleSP &module_sp, ::memset(&m_coff_header, 0, sizeof(m_coff_header)); } -ObjectFilePECOFF::~ObjectFilePECOFF() {} +ObjectFilePECOFF::~ObjectFilePECOFF() = default; bool ObjectFilePECOFF::ParseHeader() { ModuleSP module_sp(GetModule()); @@ -543,12 +515,6 @@ DataExtractor ObjectFilePECOFF::ReadImageData(uint32_t offset, size_t size) { if (m_data.ValidOffsetForDataOfSize(offset, size)) return DataExtractor(m_data, offset, size); - if (m_file) { - // A bit of a hack, but we intend to write to this buffer, so we can't - // mmap it. - auto buffer_sp = MapFileData(m_file, size, offset); - return DataExtractor(buffer_sp, GetByteOrder(), GetAddressByteSize()); - } ProcessSP process_sp(m_process_wp.lock()); DataExtractor data; if (process_sp) { @@ -652,12 +618,6 @@ Symtab *ObjectFilePECOFF::GetSymtab() { DataExtractor strtab_data = ReadImageData( m_coff_header.symoff + symbol_data_size, strtab_size); - // First 4 bytes should be zeroed after strtab_size has been read, - // because it is used as offset 0 to encode a NULL string. - uint32_t *strtab_data_start = const_cast( - reinterpret_cast(strtab_data.GetDataStart())); - ::memset(&strtab_data_start[0], 0, sizeof(uint32_t)); - offset = 0; std::string symbol_name; Symbol *symbols = m_symtab_up->Resize(num_syms); @@ -864,7 +824,6 @@ void ObjectFilePECOFF::CreateSections(SectionList &unified_section_list) { if (m_sections_up) return; m_sections_up = std::make_unique(); - ModuleSP module_sp(GetModule()); if (module_sp) { std::lock_guard guard(module_sp->GetMutex()); diff --git a/gnu/llvm/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.h b/gnu/llvm/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.h index fdcacbeab1e..9fe4a1349ae 100644 --- a/gnu/llvm/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.h +++ b/gnu/llvm/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.h @@ -79,6 +79,7 @@ public: static bool SaveCore(const lldb::ProcessSP &process_sp, const lldb_private::FileSpec &outfile, + lldb::SaveCoreStyle &core_style, lldb_private::Status &error); static bool MagicBytesMatch(lldb::DataBufferSP &data_sp); diff --git a/gnu/llvm/lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.cpp b/gnu/llvm/lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.cpp index 91150fa02eb..5272da9ab33 100644 --- a/gnu/llvm/lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.cpp +++ b/gnu/llvm/lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.cpp @@ -196,7 +196,7 @@ bool ObjectFileWasm::DecodeNextSection(lldb::offset_t *offset_ptr) { m_sect_infos.push_back(section_info{*offset_ptr + c.tell(), section_length, section_id, *sect_name}); *offset_ptr += (c.tell() + section_length); - } else if (section_id <= llvm::wasm::WASM_SEC_EVENT) { + } else if (section_id <= llvm::wasm::WASM_SEC_TAG) { m_sect_infos.push_back(section_info{*offset_ptr + c.tell(), static_cast(payload_len), section_id, ConstString()}); @@ -253,6 +253,43 @@ bool ObjectFileWasm::ParseHeader() { Symtab *ObjectFileWasm::GetSymtab() { return nullptr; } +static SectionType GetSectionTypeFromName(llvm::StringRef Name) { + if (Name.consume_front(".debug_") || Name.consume_front(".zdebug_")) { + return llvm::StringSwitch(Name) + .Case("abbrev", eSectionTypeDWARFDebugAbbrev) + .Case("abbrev.dwo", eSectionTypeDWARFDebugAbbrevDwo) + .Case("addr", eSectionTypeDWARFDebugAddr) + .Case("aranges", eSectionTypeDWARFDebugAranges) + .Case("cu_index", eSectionTypeDWARFDebugCuIndex) + .Case("frame", eSectionTypeDWARFDebugFrame) + .Case("info", eSectionTypeDWARFDebugInfo) + .Case("info.dwo", eSectionTypeDWARFDebugInfoDwo) + .Cases("line", "line.dwo", eSectionTypeDWARFDebugLine) + .Cases("line_str", "line_str.dwo", eSectionTypeDWARFDebugLineStr) + .Case("loc", eSectionTypeDWARFDebugLoc) + .Case("loc.dwo", eSectionTypeDWARFDebugLocDwo) + .Case("loclists", eSectionTypeDWARFDebugLocLists) + .Case("loclists.dwo", eSectionTypeDWARFDebugLocListsDwo) + .Case("macinfo", eSectionTypeDWARFDebugMacInfo) + .Cases("macro", "macro.dwo", eSectionTypeDWARFDebugMacro) + .Case("names", eSectionTypeDWARFDebugNames) + .Case("pubnames", eSectionTypeDWARFDebugPubNames) + .Case("pubtypes", eSectionTypeDWARFDebugPubTypes) + .Case("ranges", eSectionTypeDWARFDebugRanges) + .Case("rnglists", eSectionTypeDWARFDebugRngLists) + .Case("rnglists.dwo", eSectionTypeDWARFDebugRngListsDwo) + .Case("str", eSectionTypeDWARFDebugStr) + .Case("str.dwo", eSectionTypeDWARFDebugStrDwo) + .Case("str_offsets", eSectionTypeDWARFDebugStrOffsets) + .Case("str_offsets.dwo", eSectionTypeDWARFDebugStrOffsetsDwo) + .Case("tu_index", eSectionTypeDWARFDebugTuIndex) + .Case("types", eSectionTypeDWARFDebugTypes) + .Case("types.dwo", eSectionTypeDWARFDebugTypesDwo) + .Default(eSectionTypeOther); + } + return eSectionTypeOther; +} + void ObjectFileWasm::CreateSections(SectionList &unified_section_list) { if (m_sections_up) return; @@ -280,29 +317,7 @@ void ObjectFileWasm::CreateSections(SectionList &unified_section_list) { // Code section. vm_addr = 0; } else { - section_type = - llvm::StringSwitch(sect_info.name.GetStringRef()) - .Case(".debug_abbrev", eSectionTypeDWARFDebugAbbrev) - .Case(".debug_addr", eSectionTypeDWARFDebugAddr) - .Case(".debug_aranges", eSectionTypeDWARFDebugAranges) - .Case(".debug_cu_index", eSectionTypeDWARFDebugCuIndex) - .Case(".debug_frame", eSectionTypeDWARFDebugFrame) - .Case(".debug_info", eSectionTypeDWARFDebugInfo) - .Case(".debug_line", eSectionTypeDWARFDebugLine) - .Case(".debug_line_str", eSectionTypeDWARFDebugLineStr) - .Case(".debug_loc", eSectionTypeDWARFDebugLoc) - .Case(".debug_loclists", eSectionTypeDWARFDebugLocLists) - .Case(".debug_macinfo", eSectionTypeDWARFDebugMacInfo) - .Case(".debug_macro", eSectionTypeDWARFDebugMacro) - .Case(".debug_names", eSectionTypeDWARFDebugNames) - .Case(".debug_pubnames", eSectionTypeDWARFDebugPubNames) - .Case(".debug_pubtypes", eSectionTypeDWARFDebugPubTypes) - .Case(".debug_ranges", eSectionTypeDWARFDebugRanges) - .Case(".debug_rnglists", eSectionTypeDWARFDebugRngLists) - .Case(".debug_str", eSectionTypeDWARFDebugStr) - .Case(".debug_str_offsets", eSectionTypeDWARFDebugStrOffsets) - .Case(".debug_types", eSectionTypeDWARFDebugTypes) - .Default(eSectionTypeOther); + section_type = GetSectionTypeFromName(sect_info.name.GetStringRef()); if (section_type == eSectionTypeOther) continue; section_name = sect_info.name; diff --git a/gnu/llvm/lldb/source/Plugins/OperatingSystem/Python/OperatingSystemPython.cpp b/gnu/llvm/lldb/source/Plugins/OperatingSystem/Python/OperatingSystemPython.cpp index 417aa2e2143..730c88f96e1 100644 --- a/gnu/llvm/lldb/source/Plugins/OperatingSystem/Python/OperatingSystemPython.cpp +++ b/gnu/llvm/lldb/source/Plugins/OperatingSystem/Python/OperatingSystemPython.cpp @@ -91,13 +91,13 @@ OperatingSystemPython::OperatingSystemPython(lldb_private::Process *process, std::string os_plugin_class_name( python_module_path.GetFilename().AsCString("")); if (!os_plugin_class_name.empty()) { - const bool init_session = false; + LoadScriptOptions options; char python_module_path_cstr[PATH_MAX]; python_module_path.GetPath(python_module_path_cstr, sizeof(python_module_path_cstr)); Status error; - if (m_interpreter->LoadScriptingModule(python_module_path_cstr, - init_session, error)) { + if (m_interpreter->LoadScriptingModule(python_module_path_cstr, options, + error)) { // Strip the ".py" extension if there is one size_t py_extension_pos = os_plugin_class_name.rfind(".py"); if (py_extension_pos != std::string::npos) @@ -115,7 +115,7 @@ OperatingSystemPython::OperatingSystemPython(lldb_private::Process *process, } } -OperatingSystemPython::~OperatingSystemPython() {} +OperatingSystemPython::~OperatingSystemPython() = default; DynamicRegisterInfo *OperatingSystemPython::GetDynamicRegisterInfo() { if (m_register_info_up == nullptr) { @@ -133,8 +133,8 @@ DynamicRegisterInfo *OperatingSystemPython::GetDynamicRegisterInfo() { if (!dictionary) return nullptr; - m_register_info_up.reset(new DynamicRegisterInfo( - *dictionary, m_process->GetTarget().GetArchitecture())); + m_register_info_up = std::make_unique( + *dictionary, m_process->GetTarget().GetArchitecture()); assert(m_register_info_up->GetNumRegisters() > 0); assert(m_register_info_up->GetNumRegisterSets() > 0); } diff --git a/gnu/llvm/lldb/source/Plugins/Platform/Android/AdbClient.cpp b/gnu/llvm/lldb/source/Plugins/Platform/Android/AdbClient.cpp index ffccd6d628a..ed2d56fb3fd 100644 --- a/gnu/llvm/lldb/source/Plugins/Platform/Android/AdbClient.cpp +++ b/gnu/llvm/lldb/source/Plugins/Platform/Android/AdbClient.cpp @@ -24,7 +24,7 @@ #include "lldb/Utility/StreamString.h" #include "lldb/Utility/Timeout.h" -#include +#include #include #include @@ -118,11 +118,11 @@ Status AdbClient::CreateByDeviceID(const std::string &device_id, return error; } -AdbClient::AdbClient() {} +AdbClient::AdbClient() = default; AdbClient::AdbClient(const std::string &device_id) : m_device_id(device_id) {} -AdbClient::~AdbClient() {} +AdbClient::~AdbClient() = default; void AdbClient::SetDeviceID(const std::string &device_id) { m_device_id = device_id; @@ -583,7 +583,7 @@ AdbClient::SyncService::executeCommand(const std::function &cmd) { return error; } -AdbClient::SyncService::~SyncService() {} +AdbClient::SyncService::~SyncService() = default; Status AdbClient::SyncService::SendSyncRequest(const char *request_id, const uint32_t data_len, diff --git a/gnu/llvm/lldb/source/Plugins/Platform/Android/PlatformAndroid.cpp b/gnu/llvm/lldb/source/Plugins/Platform/Android/PlatformAndroid.cpp index 9949fbf18fa..2cd4abbf14a 100644 --- a/gnu/llvm/lldb/source/Plugins/Platform/Android/PlatformAndroid.cpp +++ b/gnu/llvm/lldb/source/Plugins/Platform/Android/PlatformAndroid.cpp @@ -130,8 +130,6 @@ PlatformSP PlatformAndroid::CreateInstance(bool force, const ArchSpec *arch) { PlatformAndroid::PlatformAndroid(bool is_host) : PlatformLinux(is_host), m_sdk_version(0) {} -PlatformAndroid::~PlatformAndroid() {} - ConstString PlatformAndroid::GetPluginNameStatic(bool is_host) { if (is_host) { static ConstString g_host_name(Platform::GetHostPlatformName()); diff --git a/gnu/llvm/lldb/source/Plugins/Platform/Android/PlatformAndroid.h b/gnu/llvm/lldb/source/Plugins/Platform/Android/PlatformAndroid.h index 2ea1c0f4618..990e1d09940 100644 --- a/gnu/llvm/lldb/source/Plugins/Platform/Android/PlatformAndroid.h +++ b/gnu/llvm/lldb/source/Plugins/Platform/Android/PlatformAndroid.h @@ -23,8 +23,6 @@ class PlatformAndroid : public platform_linux::PlatformLinux { public: PlatformAndroid(bool is_host); - ~PlatformAndroid() override; - static void Initialize(); static void Terminate(); @@ -76,9 +74,6 @@ private: std::unique_ptr m_adb_sync_svc; std::string m_device_id; uint32_t m_sdk_version; - - PlatformAndroid(const PlatformAndroid &) = delete; - const PlatformAndroid &operator=(const PlatformAndroid &) = delete; }; } // namespace platofor_android diff --git a/gnu/llvm/lldb/source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.cpp b/gnu/llvm/lldb/source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.cpp index 6dd5306a93e..77690b4efab 100644 --- a/gnu/llvm/lldb/source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.cpp +++ b/gnu/llvm/lldb/source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.cpp @@ -73,7 +73,7 @@ static Status FindUnusedPort(uint16_t &port) { return error; } -PlatformAndroidRemoteGDBServer::PlatformAndroidRemoteGDBServer() {} +PlatformAndroidRemoteGDBServer::PlatformAndroidRemoteGDBServer() = default; PlatformAndroidRemoteGDBServer::~PlatformAndroidRemoteGDBServer() { for (const auto &it : m_port_forwards) diff --git a/gnu/llvm/lldb/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp b/gnu/llvm/lldb/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp index 97c2f22b505..7b3d8a375bf 100644 --- a/gnu/llvm/lldb/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp +++ b/gnu/llvm/lldb/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp @@ -9,7 +9,7 @@ #include "PlatformFreeBSD.h" #include "lldb/Host/Config.h" -#include +#include #if LLDB_ENABLE_POSIX #include #endif @@ -27,6 +27,9 @@ #include "lldb/Utility/Status.h" #include "lldb/Utility/StreamString.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Support/Host.h" + // Define these constants from FreeBSD mman.h for use when targeting remote // FreeBSD systems even when host has different values. #define MAP_PRIVATE 0x0002 @@ -125,8 +128,6 @@ PlatformFreeBSD::PlatformFreeBSD(bool is_host) : PlatformPOSIX(is_host) // This is the local host platform {} -PlatformFreeBSD::~PlatformFreeBSD() = default; - bool PlatformFreeBSD::GetSupportedArchitectureAtIndex(uint32_t idx, ArchSpec &arch) { if (IsHost()) { @@ -213,92 +214,13 @@ void PlatformFreeBSD::GetStatus(Stream &strm) { #endif } -size_t -PlatformFreeBSD::GetSoftwareBreakpointTrapOpcode(Target &target, - BreakpointSite *bp_site) { - switch (target.GetArchitecture().GetMachine()) { - case llvm::Triple::arm: { - lldb::BreakpointLocationSP bp_loc_sp(bp_site->GetOwnerAtIndex(0)); - AddressClass addr_class = AddressClass::eUnknown; - - if (bp_loc_sp) { - addr_class = bp_loc_sp->GetAddress().GetAddressClass(); - if (addr_class == AddressClass::eUnknown && - (bp_loc_sp->GetAddress().GetFileAddress() & 1)) - addr_class = AddressClass::eCodeAlternateISA; - } - - if (addr_class == AddressClass::eCodeAlternateISA) { - // TODO: Enable when FreeBSD supports thumb breakpoints. - // FreeBSD kernel as of 10.x, does not support thumb breakpoints - return 0; - } - - static const uint8_t g_arm_breakpoint_opcode[] = {0xFE, 0xDE, 0xFF, 0xE7}; - size_t trap_opcode_size = sizeof(g_arm_breakpoint_opcode); - assert(bp_site); - if (bp_site->SetTrapOpcode(g_arm_breakpoint_opcode, trap_opcode_size)) - return trap_opcode_size; - } - LLVM_FALLTHROUGH; - default: - return Platform::GetSoftwareBreakpointTrapOpcode(target, bp_site); - } -} - -Status PlatformFreeBSD::LaunchProcess(ProcessLaunchInfo &launch_info) { - Status error; - if (IsHost()) { - error = Platform::LaunchProcess(launch_info); - } else { - if (m_remote_platform_sp) - error = m_remote_platform_sp->LaunchProcess(launch_info); - else - error.SetErrorString("the platform is not currently connected"); - } - return error; -} - -lldb::ProcessSP PlatformFreeBSD::Attach(ProcessAttachInfo &attach_info, - Debugger &debugger, Target *target, - Status &error) { - lldb::ProcessSP process_sp; +bool PlatformFreeBSD::CanDebugProcess() { if (IsHost()) { - if (target == nullptr) { - TargetSP new_target_sp; - ArchSpec emptyArchSpec; - - error = debugger.GetTargetList().CreateTarget( - debugger, "", emptyArchSpec, eLoadDependentsNo, m_remote_platform_sp, - new_target_sp); - target = new_target_sp.get(); - } else - error.Clear(); - - if (target && error.Success()) { - debugger.GetTargetList().SetSelectedTarget(target); - // The freebsd always currently uses the GDB remote debugger plug-in so - // even when debugging locally we are debugging remotely! Just like the - // darwin plugin. - process_sp = target->CreateProcess( - attach_info.GetListenerForProcess(debugger), "gdb-remote", nullptr); - - if (process_sp) - error = process_sp->Attach(attach_info); - } + return true; } else { - if (m_remote_platform_sp) - process_sp = - m_remote_platform_sp->Attach(attach_info, debugger, target, error); - else - error.SetErrorString("the platform is not currently connected"); + // If we're connected, we can debug. + return IsConnected(); } - return process_sp; -} - -// FreeBSD processes cannot yet be launched by spawning and attaching. -bool PlatformFreeBSD::CanDebugProcess() { - return false; } void PlatformFreeBSD::CalculateTrapHandlerSymbolNames() { diff --git a/gnu/llvm/lldb/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.h b/gnu/llvm/lldb/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.h index 56f2f2771d1..4fd10fb1be7 100644 --- a/gnu/llvm/lldb/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.h +++ b/gnu/llvm/lldb/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.h @@ -18,8 +18,6 @@ class PlatformFreeBSD : public PlatformPOSIX { public: PlatformFreeBSD(bool is_host); - ~PlatformFreeBSD() override; - static void Initialize(); static void Terminate(); @@ -46,24 +44,12 @@ public: bool CanDebugProcess() override; - size_t GetSoftwareBreakpointTrapOpcode(Target &target, - BreakpointSite *bp_site) override; - - Status LaunchProcess(ProcessLaunchInfo &launch_info) override; - - lldb::ProcessSP Attach(ProcessAttachInfo &attach_info, Debugger &debugger, - Target *target, Status &error) override; - void CalculateTrapHandlerSymbolNames() override; MmapArgList GetMmapArgumentList(const ArchSpec &arch, lldb::addr_t addr, lldb::addr_t length, unsigned prot, unsigned flags, lldb::addr_t fd, lldb::addr_t offset) override; - -private: - PlatformFreeBSD(const PlatformFreeBSD &) = delete; - const PlatformFreeBSD &operator=(const PlatformFreeBSD &) = delete; }; } // namespace platform_freebsd diff --git a/gnu/llvm/lldb/source/Plugins/Platform/Linux/PlatformLinux.cpp b/gnu/llvm/lldb/source/Plugins/Platform/Linux/PlatformLinux.cpp index 577aa77c2ec..314730c562f 100644 --- a/gnu/llvm/lldb/source/Plugins/Platform/Linux/PlatformLinux.cpp +++ b/gnu/llvm/lldb/source/Plugins/Platform/Linux/PlatformLinux.cpp @@ -9,7 +9,7 @@ #include "PlatformLinux.h" #include "lldb/Host/Config.h" -#include +#include #if LLDB_ENABLE_POSIX #include #endif @@ -124,8 +124,6 @@ PlatformLinux::PlatformLinux(bool is_host) : PlatformPOSIX(is_host) // This is the local host platform {} -PlatformLinux::~PlatformLinux() = default; - bool PlatformLinux::GetSupportedArchitectureAtIndex(uint32_t idx, ArchSpec &arch) { if (IsHost()) { @@ -218,9 +216,9 @@ void PlatformLinux::GetStatus(Stream &strm) { #endif } -int32_t +uint32_t PlatformLinux::GetResumeCountForLaunchInfo(ProcessLaunchInfo &launch_info) { - int32_t resume_count = 0; + uint32_t resume_count = 0; // Always resume past the initial stop when we use eLaunchFlagDebug if (launch_info.GetFlags().Test(eLaunchFlagDebug)) { @@ -262,121 +260,6 @@ bool PlatformLinux::CanDebugProcess() { } } -// For local debugging, Linux will override the debug logic to use llgs-launch -// rather than lldb-launch, llgs-attach. This differs from current lldb- -// launch, debugserver-attach approach on MacOSX. -lldb::ProcessSP -PlatformLinux::DebugProcess(ProcessLaunchInfo &launch_info, Debugger &debugger, - Target *target, // Can be NULL, if NULL create a new - // target, else use existing one - Status &error) { - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM)); - LLDB_LOG(log, "target {0}", target); - - // If we're a remote host, use standard behavior from parent class. - if (!IsHost()) - return PlatformPOSIX::DebugProcess(launch_info, debugger, target, error); - - // - // For local debugging, we'll insist on having ProcessGDBRemote create the - // process. - // - - ProcessSP process_sp; - - // Make sure we stop at the entry point - launch_info.GetFlags().Set(eLaunchFlagDebug); - - // We always launch the process we are going to debug in a separate process - // group, since then we can handle ^C interrupts ourselves w/o having to - // worry about the target getting them as well. - launch_info.SetLaunchInSeparateProcessGroup(true); - - // Ensure we have a target. - if (target == nullptr) { - LLDB_LOG(log, "creating new target"); - TargetSP new_target_sp; - error = debugger.GetTargetList().CreateTarget( - debugger, "", "", eLoadDependentsNo, nullptr, new_target_sp); - if (error.Fail()) { - LLDB_LOG(log, "failed to create new target: {0}", error); - return process_sp; - } - - target = new_target_sp.get(); - if (!target) { - error.SetErrorString("CreateTarget() returned nullptr"); - LLDB_LOG(log, "error: {0}", error); - return process_sp; - } - } - - // Mark target as currently selected target. - debugger.GetTargetList().SetSelectedTarget(target); - - // Now create the gdb-remote process. - LLDB_LOG(log, "having target create process with gdb-remote plugin"); - process_sp = - target->CreateProcess(launch_info.GetListener(), "gdb-remote", nullptr); - - if (!process_sp) { - error.SetErrorString("CreateProcess() failed for gdb-remote process"); - LLDB_LOG(log, "error: {0}", error); - return process_sp; - } - - LLDB_LOG(log, "successfully created process"); - // Adjust launch for a hijacker. - ListenerSP listener_sp; - if (!launch_info.GetHijackListener()) { - LLDB_LOG(log, "setting up hijacker"); - listener_sp = - Listener::MakeListener("lldb.PlatformLinux.DebugProcess.hijack"); - launch_info.SetHijackListener(listener_sp); - process_sp->HijackProcessEvents(listener_sp); - } - - // Log file actions. - if (log) { - LLDB_LOG(log, "launching process with the following file actions:"); - StreamString stream; - size_t i = 0; - const FileAction *file_action; - while ((file_action = launch_info.GetFileActionAtIndex(i++)) != nullptr) { - file_action->Dump(stream); - LLDB_LOG(log, "{0}", stream.GetData()); - stream.Clear(); - } - } - - // Do the launch. - error = process_sp->Launch(launch_info); - if (error.Success()) { - // Handle the hijacking of process events. - if (listener_sp) { - const StateType state = process_sp->WaitForProcessToStop( - llvm::None, nullptr, false, listener_sp); - - LLDB_LOG(log, "pid {0} state {0}", process_sp->GetID(), state); - } - - // Hook up process PTY if we have one (which we should for local debugging - // with llgs). - int pty_fd = launch_info.GetPTY().ReleasePrimaryFileDescriptor(); - if (pty_fd != PseudoTerminal::invalid_fd) { - process_sp->SetSTDIOFileDescriptor(pty_fd); - LLDB_LOG(log, "hooked up STDIO pty to process"); - } else - LLDB_LOG(log, "not using process STDIO pty"); - } else { - LLDB_LOG(log, "{0}", error); - // FIXME figure out appropriate cleanup here. Do we delete the target? Do - // we delete the process? Does our caller do that? - } - - return process_sp; -} - void PlatformLinux::CalculateTrapHandlerSymbolNames() { m_trap_handlers.push_back(ConstString("_sigtramp")); m_trap_handlers.push_back(ConstString("__kernel_rt_sigreturn")); diff --git a/gnu/llvm/lldb/source/Plugins/Platform/Linux/PlatformLinux.h b/gnu/llvm/lldb/source/Plugins/Platform/Linux/PlatformLinux.h index 765a0a86a4e..cbbd226c13a 100644 --- a/gnu/llvm/lldb/source/Plugins/Platform/Linux/PlatformLinux.h +++ b/gnu/llvm/lldb/source/Plugins/Platform/Linux/PlatformLinux.h @@ -18,8 +18,6 @@ class PlatformLinux : public PlatformPOSIX { public: PlatformLinux(bool is_host); - ~PlatformLinux() override; - static void Initialize(); static void Terminate(); @@ -44,24 +42,16 @@ public: bool GetSupportedArchitectureAtIndex(uint32_t idx, ArchSpec &arch) override; - int32_t GetResumeCountForLaunchInfo(ProcessLaunchInfo &launch_info) override; + uint32_t GetResumeCountForLaunchInfo(ProcessLaunchInfo &launch_info) override; bool CanDebugProcess() override; - lldb::ProcessSP DebugProcess(ProcessLaunchInfo &launch_info, - Debugger &debugger, Target *target, - Status &error) override; - void CalculateTrapHandlerSymbolNames() override; MmapArgList GetMmapArgumentList(const ArchSpec &arch, lldb::addr_t addr, lldb::addr_t length, unsigned prot, unsigned flags, lldb::addr_t fd, lldb::addr_t offset) override; - -private: - PlatformLinux(const PlatformLinux &) = delete; - const PlatformLinux &operator=(const PlatformLinux &) = delete; }; } // namespace platform_linux diff --git a/gnu/llvm/lldb/source/Plugins/Platform/MacOSX/CMakeLists.txt b/gnu/llvm/lldb/source/Plugins/Platform/MacOSX/CMakeLists.txt index 44707971205..bd9343773b3 100644 --- a/gnu/llvm/lldb/source/Plugins/Platform/MacOSX/CMakeLists.txt +++ b/gnu/llvm/lldb/source/Plugins/Platform/MacOSX/CMakeLists.txt @@ -10,18 +10,16 @@ list(APPEND PLUGIN_PLATFORM_MACOSX_SOURCES PlatformDarwin.cpp PlatformDarwinKernel.cpp PlatformMacOSX.cpp - PlatformRemoteiOS.cpp + PlatformRemoteAppleBridge.cpp PlatformRemoteAppleTV.cpp PlatformRemoteAppleWatch.cpp PlatformRemoteDarwinDevice.cpp - PlatformRemoteAppleBridge.cpp + PlatformRemoteMacOSX.cpp + PlatformRemoteiOS.cpp ) list(APPEND PLUGIN_PLATFORM_MACOSX_DARWIN_ONLY_SOURCES PlatformAppleSimulator.cpp - PlatformiOSSimulator.cpp - PlatformAppleTVSimulator.cpp - PlatformAppleWatchSimulator.cpp ) if(CMAKE_SYSTEM_NAME MATCHES "Darwin") diff --git a/gnu/llvm/lldb/source/Plugins/Platform/MacOSX/PlatformAppleSimulator.cpp b/gnu/llvm/lldb/source/Plugins/Platform/MacOSX/PlatformAppleSimulator.cpp index bd0a231303b..925a3d110b1 100644 --- a/gnu/llvm/lldb/source/Plugins/Platform/MacOSX/PlatformAppleSimulator.cpp +++ b/gnu/llvm/lldb/source/Plugins/Platform/MacOSX/PlatformAppleSimulator.cpp @@ -12,16 +12,21 @@ #include #endif -#include -#include -#include "lldb/Host/PseudoTerminal.h" +#include "lldb/Core/Module.h" +#include "lldb/Core/PluginManager.h" #include "lldb/Host/HostInfo.h" +#include "lldb/Host/PseudoTerminal.h" #include "lldb/Target/Process.h" #include "lldb/Utility/LLDBAssert.h" +#include "lldb/Utility/Log.h" #include "lldb/Utility/Status.h" #include "lldb/Utility/StreamString.h" + #include "llvm/Support/Threading.h" +#include +#include + using namespace lldb; using namespace lldb_private; @@ -29,21 +34,23 @@ using namespace lldb_private; #define UNSUPPORTED_ERROR ("Apple simulators aren't supported on this platform") #endif -// Static Functions -void PlatformAppleSimulator::Initialize() { PlatformDarwin::Initialize(); } - -void PlatformAppleSimulator::Terminate() { PlatformDarwin::Terminate(); } - /// Default Constructor PlatformAppleSimulator::PlatformAppleSimulator( + const char *class_name, const char *description, ConstString plugin_name, + llvm::Triple::OSType preferred_os, + llvm::SmallVector supported_triples, + llvm::StringRef sdk, lldb_private::XcodeSDK::Type sdk_type, CoreSimulatorSupport::DeviceType::ProductFamilyID kind) - : PlatformDarwin(true), m_kind(kind) {} + : PlatformDarwin(true), m_class_name(class_name), + m_description(description), m_plugin_name(plugin_name), m_kind(kind), + m_os_type(preferred_os), m_supported_triples(supported_triples), + m_sdk(sdk), m_sdk_type(sdk_type) {} /// Destructor. /// /// The destructor is virtual since this class is designed to be /// inherited from by the plug-in instance. -PlatformAppleSimulator::~PlatformAppleSimulator() {} +PlatformAppleSimulator::~PlatformAppleSimulator() = default; lldb_private::Status PlatformAppleSimulator::LaunchProcess( lldb_private::ProcessLaunchInfo &launch_info) { @@ -73,6 +80,12 @@ lldb_private::Status PlatformAppleSimulator::LaunchProcess( } void PlatformAppleSimulator::GetStatus(Stream &strm) { + Platform::GetStatus(strm); + if (!m_sdk.empty()) + strm << " SDK Path: \"" << m_sdk << "\"\n"; + else + strm << " SDK Path: error: unable to locate SDK\n"; + #if defined(__APPLE__) // This will get called by subclasses, so just output status on the current // simulator @@ -87,31 +100,30 @@ void PlatformAppleSimulator::GetStatus(Stream &strm) { strm.Printf("Available devices:\n"); for (size_t i = 0; i < num_devices; ++i) { CoreSimulatorSupport::Device device = devices.GetDeviceAtIndex(i); - strm.Printf(" %s: %s\n", device.GetUDID().c_str(), - device.GetName().c_str()); + strm << " " << device.GetUDID() << ": " << device.GetName() << "\n"; } if (m_device.hasValue() && m_device->operator bool()) { - strm.Printf("Current device: %s: %s", m_device->GetUDID().c_str(), - m_device->GetName().c_str()); + strm << "Current device: " << m_device->GetUDID() << ": " + << m_device->GetName(); if (m_device->GetState() == CoreSimulatorSupport::Device::State::Booted) { - strm.Printf(" state = booted"); + strm << " state = booted"; } - strm.Printf("\nType \"platform connect \" where is a device " - "UDID or a device name to disconnect and connect to a " - "different device.\n"); + strm << "\nType \"platform connect \" where is a device " + "UDID or a device name to disconnect and connect to a " + "different device.\n"; } else { - strm.Printf("No current device is selected, \"platform connect \" " - "where is a device UDID or a device name to connect to " - "a specific device.\n"); + strm << "No current device is selected, \"platform connect \" " + "where is a device UDID or a device name to connect to " + "a specific device.\n"; } } else { - strm.Printf("No devices are available.\n"); + strm << "No devices are available.\n"; } #else - strm.Printf(UNSUPPORTED_ERROR); + strm << UNSUPPORTED_ERROR; #endif } @@ -253,3 +265,418 @@ CoreSimulatorSupport::Device PlatformAppleSimulator::GetSimulatorDevice() { return CoreSimulatorSupport::Device(); } #endif + +bool PlatformAppleSimulator::GetSupportedArchitectureAtIndex(uint32_t idx, + ArchSpec &arch) { + if (idx >= m_supported_triples.size()) + return false; + arch = ArchSpec(m_supported_triples[idx]); + return true; +} + +PlatformSP PlatformAppleSimulator::CreateInstance( + const char *class_name, const char *description, ConstString plugin_name, + llvm::SmallVector supported_arch, + llvm::Triple::OSType preferred_os, + llvm::SmallVector supported_os, + llvm::SmallVector supported_triples, + llvm::StringRef sdk, lldb_private::XcodeSDK::Type sdk_type, + CoreSimulatorSupport::DeviceType::ProductFamilyID kind, bool force, + const ArchSpec *arch) { + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM)); + if (log) { + const char *arch_name; + if (arch && arch->GetArchitectureName()) + arch_name = arch->GetArchitectureName(); + else + arch_name = ""; + + const char *triple_cstr = + arch ? arch->GetTriple().getTriple().c_str() : ""; + + LLDB_LOGF(log, "%s::%s(force=%s, arch={%s,%s})", class_name, __FUNCTION__, + force ? "true" : "false", arch_name, triple_cstr); + } + + bool create = force; + if (!create && arch && arch->IsValid()) { + if (std::count(supported_arch.begin(), supported_arch.end(), + arch->GetMachine())) { + const llvm::Triple &triple = arch->GetTriple(); + switch (triple.getVendor()) { + case llvm::Triple::Apple: + create = true; + break; + +#if defined(__APPLE__) + // Only accept "unknown" for the vendor if the host is Apple and if + // "unknown" wasn't specified (it was just returned because it was NOT + // specified) + case llvm::Triple::UnknownVendor: + create = !arch->TripleVendorWasSpecified(); + break; +#endif + default: + break; + } + + if (create) { + if (std::count(supported_os.begin(), supported_os.end(), triple.getOS())) + create = true; +#if defined(__APPLE__) + // Only accept "unknown" for the OS if the host is Apple and it + // "unknown" wasn't specified (it was just returned because it was NOT + // specified) + else if (triple.getOS() == llvm::Triple::UnknownOS) + create = !arch->TripleOSWasSpecified(); +#endif + else + create = false; + } + } + } + if (create) { + LLDB_LOGF(log, "%s::%s() creating platform", class_name, __FUNCTION__); + + return PlatformSP(new PlatformAppleSimulator( + class_name, description, plugin_name, preferred_os, supported_triples, + sdk, sdk_type, kind)); + } + + LLDB_LOGF(log, "%s::%s() aborting creation of platform", class_name, + __FUNCTION__); + + return PlatformSP(); +} + +Status PlatformAppleSimulator::ResolveExecutable( + const ModuleSpec &module_spec, lldb::ModuleSP &exe_module_sp, + const FileSpecList *module_search_paths_ptr) { + Status error; + // Nothing special to do here, just use the actual file and architecture + + ModuleSpec resolved_module_spec(module_spec); + + // If we have "ls" as the exe_file, resolve the executable loation based on + // the current path variables + // TODO: resolve bare executables in the Platform SDK + // if (!resolved_exe_file.Exists()) + // resolved_exe_file.ResolveExecutableLocation (); + + // Resolve any executable within a bundle on MacOSX + // TODO: verify that this handles shallow bundles, if not then implement one + // ourselves + Host::ResolveExecutableInBundle(resolved_module_spec.GetFileSpec()); + + if (FileSystem::Instance().Exists(resolved_module_spec.GetFileSpec())) { + if (resolved_module_spec.GetArchitecture().IsValid()) { + error = ModuleList::GetSharedModule(resolved_module_spec, exe_module_sp, + NULL, NULL, NULL); + + if (exe_module_sp && exe_module_sp->GetObjectFile()) + return error; + exe_module_sp.reset(); + } + // No valid architecture was specified or the exact ARM slice wasn't found + // so ask the platform for the architectures that we should be using (in + // the correct order) and see if we can find a match that way + StreamString arch_names; + ArchSpec platform_arch; + for (uint32_t idx = 0; GetSupportedArchitectureAtIndex( + idx, resolved_module_spec.GetArchitecture()); + ++idx) { + // Only match x86 with x86 and x86_64 with x86_64... + if (!module_spec.GetArchitecture().IsValid() || + module_spec.GetArchitecture().GetCore() == + resolved_module_spec.GetArchitecture().GetCore()) { + error = ModuleList::GetSharedModule(resolved_module_spec, exe_module_sp, + NULL, NULL, NULL); + // Did we find an executable using one of the + if (error.Success()) { + if (exe_module_sp && exe_module_sp->GetObjectFile()) + break; + else + error.SetErrorToGenericError(); + } + + if (idx > 0) + arch_names.PutCString(", "); + arch_names.PutCString(platform_arch.GetArchitectureName()); + } + } + + if (error.Fail() || !exe_module_sp) { + if (FileSystem::Instance().Readable(resolved_module_spec.GetFileSpec())) { + error.SetErrorStringWithFormat( + "'%s' doesn't contain any '%s' platform architectures: %s", + resolved_module_spec.GetFileSpec().GetPath().c_str(), + GetPluginName().GetCString(), arch_names.GetString().str().c_str()); + } else { + error.SetErrorStringWithFormat( + "'%s' is not readable", + resolved_module_spec.GetFileSpec().GetPath().c_str()); + } + } + } else { + error.SetErrorStringWithFormat("'%s' does not exist", + module_spec.GetFileSpec().GetPath().c_str()); + } + + return error; +} + +Status PlatformAppleSimulator::GetSymbolFile(const FileSpec &platform_file, + const UUID *uuid_ptr, + FileSpec &local_file) { + Status error; + char platform_file_path[PATH_MAX]; + if (platform_file.GetPath(platform_file_path, sizeof(platform_file_path))) { + char resolved_path[PATH_MAX]; + + if (!m_sdk.empty()) { + ::snprintf(resolved_path, sizeof(resolved_path), "%s/%s", + m_sdk.str().c_str(), platform_file_path); + + // First try in the SDK and see if the file is in there + local_file.SetFile(resolved_path, FileSpec::Style::native); + FileSystem::Instance().Resolve(local_file); + if (FileSystem::Instance().Exists(local_file)) + return error; + + // Else fall back to the actual path itself + local_file.SetFile(platform_file_path, FileSpec::Style::native); + FileSystem::Instance().Resolve(local_file); + if (FileSystem::Instance().Exists(local_file)) + return error; + } + error.SetErrorStringWithFormat( + "unable to locate a platform file for '%s' in platform '%s'", + platform_file_path, GetPluginName().GetCString()); + } else { + error.SetErrorString("invalid platform file argument"); + } + return error; +} + +Status PlatformAppleSimulator::GetSharedModule( + const ModuleSpec &module_spec, Process *process, ModuleSP &module_sp, + const FileSpecList *module_search_paths_ptr, + llvm::SmallVectorImpl *old_modules, bool *did_create_ptr) { + // For iOS/tvOS/watchOS, the SDK files are all cached locally on the + // host system. So first we ask for the file in the cached SDK, then + // we attempt to get a shared module for the right architecture with + // the right UUID. + Status error; + ModuleSpec platform_module_spec(module_spec); + const FileSpec &platform_file = module_spec.GetFileSpec(); + error = GetSymbolFile(platform_file, module_spec.GetUUIDPtr(), + platform_module_spec.GetFileSpec()); + if (error.Success()) { + error = ResolveExecutable(platform_module_spec, module_sp, + module_search_paths_ptr); + } else { + const bool always_create = false; + error = ModuleList::GetSharedModule(module_spec, module_sp, + module_search_paths_ptr, old_modules, + did_create_ptr, always_create); + } + if (module_sp) + module_sp->SetPlatformFileSpec(platform_file); + + return error; +} + +uint32_t PlatformAppleSimulator::FindProcesses( + const ProcessInstanceInfoMatch &match_info, + ProcessInstanceInfoList &process_infos) { + ProcessInstanceInfoList all_osx_process_infos; + // First we get all OSX processes + const uint32_t n = Host::FindProcesses(match_info, all_osx_process_infos); + + // Now we filter them down to only the matching triples. + for (uint32_t i = 0; i < n; ++i) { + const ProcessInstanceInfo &proc_info = all_osx_process_infos[i]; + const llvm::Triple &triple = proc_info.GetArchitecture().GetTriple(); + if (triple.getOS() == m_os_type && + triple.getEnvironment() == llvm::Triple::Simulator) { + process_infos.push_back(proc_info); + } + } + return process_infos.size(); +} + +/// Whether to skip creating a simulator platform. +static bool shouldSkipSimulatorPlatform(bool force, const ArchSpec *arch) { + // If the arch is known not to specify a simulator environment, skip creating + // the simulator platform (we can create it later if there's a matching arch). + // This avoids very slow xcrun queries for non-simulator archs (the slowness + // is due to xcrun not caching negative queries (rdar://74882205)). + return !force && arch && arch->IsValid() && + !arch->TripleEnvironmentWasSpecified(); +} + +static llvm::StringRef GetXcodeSDKDir(std::string preferred, + std::string secondary) { + llvm::StringRef sdk; + sdk = HostInfo::GetXcodeSDKPath(XcodeSDK(std::move(preferred))); + if (sdk.empty()) + sdk = HostInfo::GetXcodeSDKPath(XcodeSDK(std::move(secondary))); + return sdk; +} + +static const char *g_ios_plugin_name = "ios-simulator"; +static const char *g_ios_description = "iPhone simulator platform plug-in."; + +/// IPhone Simulator Plugin. +struct PlatformiOSSimulator { + static void Initialize() { + PluginManager::RegisterPlugin(ConstString(g_ios_plugin_name), + g_ios_description, + PlatformiOSSimulator::CreateInstance); + } + + static void Terminate() { + PluginManager::UnregisterPlugin(PlatformiOSSimulator::CreateInstance); + } + + static PlatformSP CreateInstance(bool force, const ArchSpec *arch) { + if (shouldSkipSimulatorPlatform(force, arch)) + return nullptr; + llvm::StringRef sdk; + sdk = HostInfo::GetXcodeSDKPath(XcodeSDK("iPhoneSimulator.Internal.sdk")); + if (sdk.empty()) + sdk = HostInfo::GetXcodeSDKPath(XcodeSDK("iPhoneSimulator.sdk")); + + return PlatformAppleSimulator::CreateInstance( + "PlatformiOSSimulator", g_ios_description, + ConstString(g_ios_plugin_name), + {llvm::Triple::aarch64, llvm::Triple::x86_64, llvm::Triple::x86}, + llvm::Triple::IOS, + {// Deprecated, but still support Darwin for historical reasons. + llvm::Triple::Darwin, llvm::Triple::MacOSX, + // IOS is not used for simulator triples, but accept it just in + // case. + llvm::Triple::IOS}, + { +#ifdef __APPLE__ +#if __arm64__ + "arm64e-apple-ios-simulator", "arm64-apple-ios-simulator", + "x86_64-apple-ios-simulator", "x86_64h-apple-ios-simulator", +#else + "x86_64h-apple-ios-simulator", "x86_64-apple-ios-simulator", + "i386-apple-ios-simulator", +#endif +#endif + }, + GetXcodeSDKDir("iPhoneSimulator.Internal.sdk", "iPhoneSimulator.sdk"), + XcodeSDK::Type::iPhoneSimulator, + CoreSimulatorSupport::DeviceType::ProductFamilyID::iPhone, force, arch); + } +}; + +static const char *g_tvos_plugin_name = "tvos-simulator"; +static const char *g_tvos_description = "tvOS simulator platform plug-in."; + +/// Apple TV Simulator Plugin. +struct PlatformAppleTVSimulator { + static void Initialize() { + PluginManager::RegisterPlugin(ConstString(g_tvos_plugin_name), + g_tvos_description, + PlatformAppleTVSimulator::CreateInstance); + } + + static void Terminate() { + PluginManager::UnregisterPlugin(PlatformAppleTVSimulator::CreateInstance); + } + + static PlatformSP CreateInstance(bool force, const ArchSpec *arch) { + if (shouldSkipSimulatorPlatform(force, arch)) + return nullptr; + return PlatformAppleSimulator::CreateInstance( + "PlatformAppleTVSimulator", g_tvos_description, + ConstString(g_tvos_plugin_name), + {llvm::Triple::aarch64, llvm::Triple::x86_64}, llvm::Triple::TvOS, + {llvm::Triple::TvOS}, + { +#ifdef __APPLE__ +#if __arm64__ + "arm64e-apple-tvos-simulator", "arm64-apple-tvos-simulator", + "x86_64h-apple-tvos-simulator", "x86_64-apple-tvos-simulator", +#else + "x86_64h-apple-tvos-simulator", "x86_64-apple-tvos-simulator", +#endif +#endif + }, + GetXcodeSDKDir("AppleTVSimulator.Internal.sdk", "AppleTVSimulator.sdk"), + XcodeSDK::Type::AppleTVSimulator, + CoreSimulatorSupport::DeviceType::ProductFamilyID::appleTV, force, + arch); + } +}; + + +static const char *g_watchos_plugin_name = "watchos-simulator"; +static const char *g_watchos_description = + "Apple Watch simulator platform plug-in."; + +/// Apple Watch Simulator Plugin. +struct PlatformAppleWatchSimulator { + static void Initialize() { + PluginManager::RegisterPlugin(ConstString(g_watchos_plugin_name), + g_watchos_description, + PlatformAppleWatchSimulator::CreateInstance); + } + + static void Terminate() { + PluginManager::UnregisterPlugin( + PlatformAppleWatchSimulator::CreateInstance); + } + + static PlatformSP CreateInstance(bool force, const ArchSpec *arch) { + if (shouldSkipSimulatorPlatform(force, arch)) + return nullptr; + return PlatformAppleSimulator::CreateInstance( + "PlatformAppleWatchSimulator", g_watchos_description, + ConstString(g_watchos_plugin_name), + {llvm::Triple::aarch64, llvm::Triple::x86_64, llvm::Triple::x86}, + llvm::Triple::WatchOS, {llvm::Triple::WatchOS}, + { +#ifdef __APPLE__ +#if __arm64__ + "arm64e-apple-watchos-simulator", "arm64-apple-watchos-simulator", +#else + "x86_64-apple-watchos-simulator", "x86_64h-apple-watchos-simulator", + "i386-apple-watchos-simulator", +#endif +#endif + }, + GetXcodeSDKDir("WatchSimulator.Internal.sdk", "WatchSimulator.sdk"), + XcodeSDK::Type::WatchSimulator, + CoreSimulatorSupport::DeviceType::ProductFamilyID::appleWatch, force, + arch); + } +}; + + +static unsigned g_initialize_count = 0; + +// Static Functions +void PlatformAppleSimulator::Initialize() { + if (g_initialize_count++ == 0) { + PlatformDarwin::Initialize(); + PlatformiOSSimulator::Initialize(); + PlatformAppleTVSimulator::Initialize(); + PlatformAppleWatchSimulator::Initialize(); + } +} + +void PlatformAppleSimulator::Terminate() { + if (g_initialize_count > 0) + if (--g_initialize_count == 0) { + PlatformAppleWatchSimulator::Terminate(); + PlatformAppleTVSimulator::Terminate(); + PlatformiOSSimulator::Terminate(); + PlatformDarwin::Terminate(); + } +} + diff --git a/gnu/llvm/lldb/source/Plugins/Platform/MacOSX/PlatformAppleSimulator.h b/gnu/llvm/lldb/source/Plugins/Platform/MacOSX/PlatformAppleSimulator.h index 8c0174f2946..4a5f762b61e 100644 --- a/gnu/llvm/lldb/source/Plugins/Platform/MacOSX/PlatformAppleSimulator.h +++ b/gnu/llvm/lldb/source/Plugins/Platform/MacOSX/PlatformAppleSimulator.h @@ -13,6 +13,7 @@ #include "Plugins/Platform/MacOSX/PlatformDarwin.h" #include "Plugins/Platform/MacOSX/objcxx/PlatformiOSSimulatorCoreSimulatorSupport.h" +#include "lldb/Utility/ConstString.h" #include "lldb/Utility/FileSpec.h" #include "llvm/ADT/Optional.h" @@ -26,10 +27,29 @@ public: // Class Methods PlatformAppleSimulator( + const char *class_name, const char *description, + lldb_private::ConstString plugin_name, llvm::Triple::OSType preferred_os, + llvm::SmallVector supported_triples, + llvm::StringRef sdk, lldb_private::XcodeSDK::Type sdk_type, CoreSimulatorSupport::DeviceType::ProductFamilyID kind); + static lldb::PlatformSP + CreateInstance(const char *class_name, const char *description, + lldb_private::ConstString plugin_name, + llvm::SmallVector supported_arch, + llvm::Triple::OSType preferred_os, + llvm::SmallVector supported_os, + llvm::SmallVector supported_triples, + llvm::StringRef sdk, lldb_private::XcodeSDK::Type sdk_type, + CoreSimulatorSupport::DeviceType::ProductFamilyID kind, + bool force, const lldb_private::ArchSpec *arch); + virtual ~PlatformAppleSimulator(); + lldb_private::ConstString GetPluginName() override { return m_plugin_name; } + const char *GetDescription() override { return m_description; } + uint32_t GetPluginVersion() override { return 1; } + lldb_private::Status LaunchProcess(lldb_private::ProcessLaunchInfo &launch_info) override; @@ -44,7 +64,35 @@ public: lldb_private::Target *target, lldb_private::Status &error) override; + bool GetSupportedArchitectureAtIndex(uint32_t idx, + lldb_private::ArchSpec &arch) override; + + lldb_private::Status ResolveExecutable( + const lldb_private::ModuleSpec &module_spec, lldb::ModuleSP &module_sp, + const lldb_private::FileSpecList *module_search_paths_ptr) override; + + lldb_private::Status + GetSharedModule(const lldb_private::ModuleSpec &module_spec, + lldb_private::Process *process, lldb::ModuleSP &module_sp, + const lldb_private::FileSpecList *module_search_paths_ptr, + llvm::SmallVectorImpl *old_modules, + bool *did_create_ptr) override; + + uint32_t + FindProcesses(const lldb_private::ProcessInstanceInfoMatch &match_info, + lldb_private::ProcessInstanceInfoList &process_infos) override; + + void + AddClangModuleCompilationOptions(lldb_private::Target *target, + std::vector &options) override { + return PlatformDarwin::AddClangModuleCompilationOptionsForSDKType( + target, options, m_sdk_type); + } + protected: + const char *m_class_name; + const char *m_description; + lldb_private::ConstString m_plugin_name; std::mutex m_core_sim_path_mutex; llvm::Optional m_core_simulator_framework_path; llvm::Optional m_device; @@ -52,6 +100,11 @@ protected: lldb_private::FileSpec GetCoreSimulatorPath(); + llvm::Triple::OSType m_os_type = llvm::Triple::UnknownOS; + llvm::SmallVector m_supported_triples = {}; + llvm::StringRef m_sdk; + lldb_private::XcodeSDK::Type m_sdk_type; + void LoadCoreSimulator(); #if defined(__APPLE__) @@ -62,6 +115,11 @@ private: PlatformAppleSimulator(const PlatformAppleSimulator &) = delete; const PlatformAppleSimulator & operator=(const PlatformAppleSimulator &) = delete; + lldb_private::Status + + GetSymbolFile(const lldb_private::FileSpec &platform_file, + const lldb_private::UUID *uuid_ptr, + lldb_private::FileSpec &local_file); }; #endif // LLDB_SOURCE_PLUGINS_PLATFORM_MACOSX_PLATFORMAPPLESIMULATOR_H diff --git a/gnu/llvm/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp b/gnu/llvm/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp index 133eda93219..51ff2a6ce12 100644 --- a/gnu/llvm/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp +++ b/gnu/llvm/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp @@ -8,7 +8,7 @@ #include "PlatformDarwin.h" -#include +#include #include #include @@ -54,7 +54,7 @@ PlatformDarwin::PlatformDarwin(bool is_host) : PlatformPOSIX(is_host) {} /// /// The destructor is virtual since this class is designed to be /// inherited from by the plug-in instance. -PlatformDarwin::~PlatformDarwin() {} +PlatformDarwin::~PlatformDarwin() = default; lldb_private::Status PlatformDarwin::PutFile(const lldb_private::FileSpec &source, @@ -237,6 +237,30 @@ lldb_private::Status PlatformDarwin::GetSharedModuleWithLocalCache( Status err; + if (IsHost()) { + // When debugging on the host, we are most likely using the same shared + // cache as our inferior. The dylibs from the shared cache might not + // exist on the filesystem, so let's use the images in our own memory + // to create the modules. + + // Check if the requested image is in our shared cache. + SharedCacheImageInfo image_info = + HostInfo::GetSharedCacheImageInfo(module_spec.GetFileSpec().GetPath()); + + // If we found it and it has the correct UUID, let's proceed with + // creating a module from the memory contents. + if (image_info.uuid && + (!module_spec.GetUUID() || module_spec.GetUUID() == image_info.uuid)) { + ModuleSpec shared_cache_spec(module_spec.GetFileSpec(), image_info.uuid, + image_info.data_sp); + err = ModuleList::GetSharedModule(shared_cache_spec, module_sp, + module_search_paths_ptr, old_modules, + did_create_ptr); + if (module_sp) + return err; + } + } + err = ModuleList::GetSharedModule(module_spec, module_sp, module_search_paths_ptr, old_modules, did_create_ptr); @@ -546,12 +570,23 @@ bool PlatformDarwin::ARMGetSupportedArchitectureAtIndex(uint32_t idx, #define OSNAME "watchos" #elif defined(TARGET_OS_BRIDGE) && TARGET_OS_BRIDGE == 1 #define OSNAME "bridgeos" -#elif defined(TARGET_OS_OSX) && TARGET_OS_OSX == 1 -#define OSNAME "macosx" #else #define OSNAME "ios" #endif +#if TARGET_OS_OSX + if (IsHost()) { + if (idx == 0) { + arch.SetTriple("arm64e-apple-macosx"); + return true; + } else if (idx == 1) { + arch.SetTriple("arm64-apple-macosx"); + return true; + } + return false; + } +#endif + const ArchSpec::Core system_core = system_arch.GetCore(); switch (system_core) { default: @@ -1162,7 +1197,7 @@ BreakpointSP PlatformDarwin::SetThreadCreationBreakpoint(Target &target) { return bp_sp; } -int32_t +uint32_t PlatformDarwin::GetResumeCountForLaunchInfo(ProcessLaunchInfo &launch_info) { const FileSpec &shell = launch_info.GetShell(); if (!shell) @@ -1191,6 +1226,33 @@ PlatformDarwin::GetResumeCountForLaunchInfo(ProcessLaunchInfo &launch_info) { return 1; } +lldb::ProcessSP +PlatformDarwin::DebugProcess(ProcessLaunchInfo &launch_info, Debugger &debugger, + Target *target, // Can be NULL, if NULL create + // a new target, else use existing + // one + Status &error) { + ProcessSP process_sp; + + if (IsHost()) { + // We are going to hand this process off to debugserver which will be in + // charge of setting the exit status. However, we still need to reap it + // from lldb. So, make sure we use a exit callback which does not set exit + // status. + const bool monitor_signals = false; + launch_info.SetMonitorProcessCallback( + &ProcessLaunchInfo::NoOpMonitorCallback, monitor_signals); + process_sp = Platform::DebugProcess(launch_info, debugger, target, error); + } else { + if (m_remote_platform_sp) + process_sp = m_remote_platform_sp->DebugProcess(launch_info, debugger, + target, error); + else + error.SetErrorString("the platform is not currently connected"); + } + return process_sp; +} + void PlatformDarwin::CalculateTrapHandlerSymbolNames() { m_trap_handlers.push_back(ConstString("_sigtramp")); } @@ -1263,6 +1325,12 @@ FileSpec PlatformDarwin::GetSDKDirectoryForModules(XcodeSDK::Type sdk_type) { case XcodeSDK::Type::iPhoneOS: sdks_spec.AppendPathComponent("iPhoneOS.platform"); break; + case XcodeSDK::Type::WatchSimulator: + sdks_spec.AppendPathComponent("WatchSimulator.platform"); + break; + case XcodeSDK::Type::AppleTVSimulator: + sdks_spec.AppendPathComponent("AppleTVSimulator.platform"); + break; default: llvm_unreachable("unsupported sdk"); } @@ -1453,25 +1521,20 @@ void PlatformDarwin::AddClangModuleCompilationOptionsForSDKType( StreamString minimum_version_option; bool use_current_os_version = false; + // If the SDK type is for the host OS, use its version number. + auto get_host_os = []() { return HostInfo::GetTargetTriple().getOS(); }; switch (sdk_type) { + case XcodeSDK::Type::MacOSX: + use_current_os_version = get_host_os() == llvm::Triple::MacOSX; + break; case XcodeSDK::Type::iPhoneOS: -#if defined(__arm__) || defined(__arm64__) || defined(__aarch64__) - use_current_os_version = true; -#else - use_current_os_version = false; -#endif + use_current_os_version = get_host_os() == llvm::Triple::IOS; break; - - case XcodeSDK::Type::iPhoneSimulator: - use_current_os_version = false; + case XcodeSDK::Type::AppleTVOS: + use_current_os_version = get_host_os() == llvm::Triple::TvOS; break; - - case XcodeSDK::Type::MacOSX: -#if defined(__i386__) || defined(__x86_64__) - use_current_os_version = true; -#else - use_current_os_version = false; -#endif + case XcodeSDK::Type::watchOS: + use_current_os_version = get_host_os() == llvm::Triple::WatchOS; break; default: break; @@ -1491,24 +1554,49 @@ void PlatformDarwin::AddClangModuleCompilationOptionsForSDKType( } } // Only add the version-min options if we got a version from somewhere - if (!version.empty()) { + if (!version.empty() && sdk_type != XcodeSDK::Type::Linux) { +#define OPTION(PREFIX, NAME, VAR, ...) \ + const char *opt_##VAR = NAME; \ + (void)opt_##VAR; +#include "clang/Driver/Options.inc" +#undef OPTION + minimum_version_option << '-'; switch (sdk_type) { - case XcodeSDK::Type::iPhoneOS: - minimum_version_option.PutCString("-mios-version-min="); - minimum_version_option.PutCString(version.getAsString()); + case XcodeSDK::Type::MacOSX: + minimum_version_option << opt_mmacosx_version_min_EQ; break; case XcodeSDK::Type::iPhoneSimulator: - minimum_version_option.PutCString("-mios-simulator-version-min="); - minimum_version_option.PutCString(version.getAsString()); + minimum_version_option << opt_mios_simulator_version_min_EQ; break; - case XcodeSDK::Type::MacOSX: - minimum_version_option.PutCString("-mmacosx-version-min="); - minimum_version_option.PutCString(version.getAsString()); + case XcodeSDK::Type::iPhoneOS: + minimum_version_option << opt_mios_version_min_EQ; break; - default: - llvm_unreachable("unsupported sdk"); + case XcodeSDK::Type::AppleTVSimulator: + minimum_version_option << opt_mtvos_simulator_version_min_EQ; + break; + case XcodeSDK::Type::AppleTVOS: + minimum_version_option << opt_mtvos_version_min_EQ; + break; + case XcodeSDK::Type::WatchSimulator: + minimum_version_option << opt_mwatchos_simulator_version_min_EQ; + break; + case XcodeSDK::Type::watchOS: + minimum_version_option << opt_mwatchos_version_min_EQ; + break; + case XcodeSDK::Type::bridgeOS: + case XcodeSDK::Type::Linux: + case XcodeSDK::Type::unknown: + if (lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST)) { + XcodeSDK::Info info; + info.type = sdk_type; + LLDB_LOGF(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST), + "Clang modules on %s are not supported", + XcodeSDK::GetCanonicalName(info).c_str()); + } + return; } - options.push_back(std::string(minimum_version_option.GetString())); + minimum_version_option << version.getAsString(); + options.emplace_back(std::string(minimum_version_option.GetString())); } FileSpec sysroot_spec; diff --git a/gnu/llvm/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.h b/gnu/llvm/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.h index 4e9a9495893..22f7ad4ff82 100644 --- a/gnu/llvm/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.h +++ b/gnu/llvm/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.h @@ -11,6 +11,7 @@ #include "Plugins/Platform/POSIX/PlatformPOSIX.h" #include "lldb/Host/FileSystem.h" +#include "lldb/Host/ProcessLaunchInfo.h" #include "lldb/Utility/ConstString.h" #include "lldb/Utility/FileSpec.h" #include "lldb/Utility/StructuredData.h" @@ -65,9 +66,14 @@ public: bool x86GetSupportedArchitectureAtIndex(uint32_t idx, lldb_private::ArchSpec &arch); - int32_t GetResumeCountForLaunchInfo( + uint32_t GetResumeCountForLaunchInfo( lldb_private::ProcessLaunchInfo &launch_info) override; + lldb::ProcessSP DebugProcess(lldb_private::ProcessLaunchInfo &launch_info, + lldb_private::Debugger &debugger, + lldb_private::Target *target, + lldb_private::Status &error) override; + void CalculateTrapHandlerSymbolNames() override; llvm::VersionTuple diff --git a/gnu/llvm/lldb/source/Plugins/Platform/MacOSX/PlatformDarwinKernel.cpp b/gnu/llvm/lldb/source/Plugins/Platform/MacOSX/PlatformDarwinKernel.cpp index 6d1cf804a0a..ee8850f8cb5 100644 --- a/gnu/llvm/lldb/source/Plugins/Platform/MacOSX/PlatformDarwinKernel.cpp +++ b/gnu/llvm/lldb/source/Plugins/Platform/MacOSX/PlatformDarwinKernel.cpp @@ -197,14 +197,7 @@ public: m_collection_sp->Initialize(g_platformdarwinkernel_properties); } - virtual ~PlatformDarwinKernelProperties() {} - - bool GetSearchForKexts() const { - const uint32_t idx = ePropertySearchForKexts; - return m_collection_sp->GetPropertyAtIndexAsBoolean( - NULL, idx, - g_platformdarwinkernel_properties[idx].default_uint_value != 0); - } + virtual ~PlatformDarwinKernelProperties() = default; FileSpecList GetKextDirectories() const { const uint32_t idx = ePropertyKextDirectories; @@ -245,21 +238,19 @@ PlatformDarwinKernel::PlatformDarwinKernel( m_name_to_kext_path_map_with_dsyms(), m_name_to_kext_path_map_without_dsyms(), m_search_directories(), m_search_directories_no_recursing(), m_kernel_binaries_with_dsyms(), - m_kernel_binaries_without_dsyms(), - m_ios_debug_session(is_ios_debug_session) + m_kernel_binaries_without_dsyms(), m_kernel_dsyms_no_binaries(), + m_kernel_dsyms_yaas(), m_ios_debug_session(is_ios_debug_session) { - if (GetGlobalProperties()->GetSearchForKexts()) { - CollectKextAndKernelDirectories(); - SearchForKextsAndKernelsRecursively(); - } + CollectKextAndKernelDirectories(); + SearchForKextsAndKernelsRecursively(); } /// Destructor. /// /// The destructor is virtual since this class is designed to be /// inherited from by the plug-in instance. -PlatformDarwinKernel::~PlatformDarwinKernel() {} +PlatformDarwinKernel::~PlatformDarwinKernel() = default; void PlatformDarwinKernel::GetStatus(Stream &strm) { Platform::GetStatus(strm); @@ -293,6 +284,10 @@ void PlatformDarwinKernel::GetStatus(Stream &strm) { (int)m_kernel_binaries_with_dsyms.size()); strm.Printf(" Number of Kernel binaries without dSYMs indexed: %d\n", (int)m_kernel_binaries_without_dsyms.size()); + strm.Printf(" Number of Kernel dSYMs with no binaries indexed: %d\n", + (int)m_kernel_dsyms_no_binaries.size()); + strm.Printf(" Number of Kernel dSYM.yaa's indexed: %d\n", + (int)m_kernel_dsyms_yaas.size()); Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM)); if (log) { @@ -305,14 +300,22 @@ void PlatformDarwinKernel::GetStatus(Stream &strm) { for (auto pos : m_name_to_kext_path_map_without_dsyms) { LLDB_LOGF(log, "%s", pos.second.GetPath().c_str()); } - LLDB_LOGF(log, "\nkernels with dSYMS"); + LLDB_LOGF(log, "\nkernel binaries with dSYMS"); for (auto fs : m_kernel_binaries_with_dsyms) { LLDB_LOGF(log, "%s", fs.GetPath().c_str()); } - LLDB_LOGF(log, "\nkernels without dSYMS"); + LLDB_LOGF(log, "\nkernel binaries without dSYMS"); for (auto fs : m_kernel_binaries_without_dsyms) { LLDB_LOGF(log, "%s", fs.GetPath().c_str()); } + LLDB_LOGF(log, "\nkernel dSYMS with no binaries"); + for (auto fs : m_kernel_dsyms_no_binaries) { + LLDB_LOGF(log, "%s", fs.GetPath().c_str()); + } + LLDB_LOGF(log, "\nkernels .dSYM.yaa's"); + for (auto fs : m_kernel_dsyms_yaas) { + LLDB_LOGF(log, "%s", fs.GetPath().c_str()); + } LLDB_LOGF(log, "\n"); } } @@ -497,56 +500,79 @@ PlatformDarwinKernel::GetKernelsAndKextsInDirectoryHelper( file_spec.GetPath().c_str()); PlatformDarwinKernel *thisp = (PlatformDarwinKernel *)baton; + + llvm::StringRef filename = file_spec.GetFilename().GetStringRef(); + bool is_kernel_filename = + filename.startswith("kernel") || filename.startswith("mach"); + bool is_dsym_yaa = filename.endswith(".dSYM.yaa"); + if (ft == llvm::sys::fs::file_type::regular_file || ft == llvm::sys::fs::file_type::symlink_file) { - ConstString filename = file_spec.GetFilename(); - if ((strncmp(filename.GetCString(), "kernel", 6) == 0 || - strncmp(filename.GetCString(), "mach", 4) == 0) && - file_spec_extension != g_dsym_suffix) { - if (KernelHasdSYMSibling(file_spec)) - { - LLDB_LOGF(log, - "PlatformDarwinKernel registering kernel binary '%s' with " - "dSYM sibling", - file_spec.GetPath().c_str()); - thisp->m_kernel_binaries_with_dsyms.push_back(file_spec); + if (is_kernel_filename) { + if (file_spec_extension != g_dsym_suffix && !is_dsym_yaa) { + if (KernelHasdSYMSibling(file_spec)) { + LLDB_LOGF(log, + "PlatformDarwinKernel registering kernel binary '%s' with " + "dSYM sibling", + file_spec.GetPath().c_str()); + thisp->m_kernel_binaries_with_dsyms.push_back(file_spec); + } else { + LLDB_LOGF( + log, + "PlatformDarwinKernel registering kernel binary '%s', no dSYM", + file_spec.GetPath().c_str()); + thisp->m_kernel_binaries_without_dsyms.push_back(file_spec); + } } - else - { - LLDB_LOGF( - log, "PlatformDarwinKernel registering kernel binary '%s', no dSYM", - file_spec.GetPath().c_str()); - thisp->m_kernel_binaries_without_dsyms.push_back(file_spec); + if (is_dsym_yaa) { + LLDB_LOGF(log, "PlatformDarwinKernel registering kernel .dSYM.yaa '%s'", + file_spec.GetPath().c_str()); + thisp->m_kernel_dsyms_yaas.push_back(file_spec); } return FileSystem::eEnumerateDirectoryResultNext; } - } else if (ft == llvm::sys::fs::file_type::directory_file && - file_spec_extension == g_kext_suffix) { - AddKextToMap(thisp, file_spec); - // Look to see if there is a PlugIns subdir with more kexts - FileSpec contents_plugins(file_spec.GetPath() + "/Contents/PlugIns"); - std::string search_here_too; - if (FileSystem::Instance().IsDirectory(contents_plugins)) { - search_here_too = contents_plugins.GetPath(); - } else { - FileSpec plugins(file_spec.GetPath() + "/PlugIns"); - if (FileSystem::Instance().IsDirectory(plugins)) { - search_here_too = plugins.GetPath(); - } - } + } else { + if (ft == llvm::sys::fs::file_type::directory_file) { + if (file_spec_extension == g_kext_suffix) { + AddKextToMap(thisp, file_spec); + // Look to see if there is a PlugIns subdir with more kexts + FileSpec contents_plugins(file_spec.GetPath() + "/Contents/PlugIns"); + std::string search_here_too; + if (FileSystem::Instance().IsDirectory(contents_plugins)) { + search_here_too = contents_plugins.GetPath(); + } else { + FileSpec plugins(file_spec.GetPath() + "/PlugIns"); + if (FileSystem::Instance().IsDirectory(plugins)) { + search_here_too = plugins.GetPath(); + } + } - if (!search_here_too.empty()) { - const bool find_directories = true; - const bool find_files = false; - const bool find_other = false; - FileSystem::Instance().EnumerateDirectory( - search_here_too.c_str(), find_directories, find_files, find_other, - recurse ? GetKernelsAndKextsInDirectoryWithRecursion - : GetKernelsAndKextsInDirectoryNoRecursion, - baton); + if (!search_here_too.empty()) { + const bool find_directories = true; + const bool find_files = false; + const bool find_other = false; + FileSystem::Instance().EnumerateDirectory( + search_here_too.c_str(), find_directories, find_files, find_other, + recurse ? GetKernelsAndKextsInDirectoryWithRecursion + : GetKernelsAndKextsInDirectoryNoRecursion, + baton); + } + return FileSystem::eEnumerateDirectoryResultNext; + } + // Do we have a kernel dSYM with no kernel binary? + if (is_kernel_filename && file_spec_extension == g_dsym_suffix) { + if (KerneldSYMHasNoSiblingBinary(file_spec)) { + LLDB_LOGF(log, + "PlatformDarwinKernel registering kernel dSYM '%s' with " + "no binary sibling", + file_spec.GetPath().c_str()); + thisp->m_kernel_dsyms_no_binaries.push_back(file_spec); + return FileSystem::eEnumerateDirectoryResultNext; + } + } } - return FileSystem::eEnumerateDirectoryResultNext; } + // Don't recurse into dSYM/kext/bundle directories if (recurse && file_spec_extension != g_dsym_suffix && file_spec_extension != g_kext_suffix && @@ -642,6 +668,63 @@ bool PlatformDarwinKernel::KernelHasdSYMSibling(const FileSpec &kernel_binary) { return FileSystem::Instance().IsDirectory(kernel_dsym); } +// Given a FileSpec of /dir/dir/mach.development.t7004.dSYM +// Return true if only the dSYM exists, no binary next to it. +// /dir/dir/mach.development.t7004.dSYM +// but no +// /dir/dir/mach.development.t7004 +bool PlatformDarwinKernel::KerneldSYMHasNoSiblingBinary( + const FileSpec &kernel_dsym) { + static ConstString g_dsym_suffix = ConstString(".dSYM"); + std::string possible_path = kernel_dsym.GetPath(); + if (kernel_dsym.GetFileNameExtension() != g_dsym_suffix) + return false; + + FileSpec binary_filespec = kernel_dsym; + // Chop off the '.dSYM' extension on the filename + binary_filespec.GetFilename() = + binary_filespec.GetFileNameStrippingExtension(); + + // Is there a binary next to this this? Then return false. + if (FileSystem::Instance().Exists(binary_filespec)) + return false; + + // If we have at least one binary in the DWARF subdir, then + // this is a properly formed dSYM and it has no binary next + // to it. + if (GetDWARFBinaryInDSYMBundle(kernel_dsym).size() > 0) + return true; + + return false; +} + +// TODO: This method returns a vector of FileSpec's because a +// dSYM bundle may contain multiple DWARF binaries, but it +// only implements returning the base name binary for now; +// it should iterate over every binary in the DWARF subdir +// and return them all. +std::vector +PlatformDarwinKernel::GetDWARFBinaryInDSYMBundle(FileSpec dsym_bundle) { + std::vector results; + static ConstString g_dsym_suffix = ConstString(".dSYM"); + if (dsym_bundle.GetFileNameExtension() != g_dsym_suffix) { + return results; + } + // Drop the '.dSYM' from the filename + std::string filename = + dsym_bundle.GetFileNameStrippingExtension().GetCString(); + std::string dirname = dsym_bundle.GetDirectory().GetCString(); + + std::string binary_filepath = dsym_bundle.GetPath(); + binary_filepath += "/Contents/Resources/DWARF/"; + binary_filepath += filename; + + FileSpec binary_fspec(binary_filepath); + if (FileSystem::Instance().Exists(binary_fspec)) + results.push_back(binary_fspec); + return results; +} + Status PlatformDarwinKernel::GetSharedModule( const ModuleSpec &module_spec, Process *process, ModuleSP &module_sp, const FileSpecList *module_search_paths_ptr, @@ -653,116 +736,139 @@ Status PlatformDarwinKernel::GetSharedModule( // Treat the file's path as a kext bundle ID (e.g. // "com.apple.driver.AppleIRController") and search our kext index. std::string kext_bundle_id = platform_file.GetPath(); - if (!kext_bundle_id.empty()) { - ConstString kext_bundle_cs(kext_bundle_id.c_str()); - - // First look through the kext bundles that had a dsym next to them - if (m_name_to_kext_path_map_with_dsyms.count(kext_bundle_cs) > 0) { - for (BundleIDToKextIterator it = - m_name_to_kext_path_map_with_dsyms.begin(); - it != m_name_to_kext_path_map_with_dsyms.end(); ++it) { - if (it->first == kext_bundle_cs) { - error = ExamineKextForMatchingUUID(it->second, module_spec.GetUUID(), - module_spec.GetArchitecture(), - module_sp); - if (module_sp.get()) { - return error; - } - } - } - } + if (!kext_bundle_id.empty() && module_spec.GetUUID().IsValid()) { + if (kext_bundle_id == "mach_kernel") { + return GetSharedModuleKernel(module_spec, process, module_sp, + module_search_paths_ptr, old_modules, + did_create_ptr); + } else { + return GetSharedModuleKext(module_spec, process, module_sp, + module_search_paths_ptr, old_modules, + did_create_ptr); + } + } else { // Give the generic methods, including possibly calling into DebugSymbols // framework on macOS systems, a chance. - error = PlatformDarwin::GetSharedModule(module_spec, process, module_sp, - module_search_paths_ptr, - old_modules, did_create_ptr); - if (error.Success() && module_sp.get()) { - return error; - } + return PlatformDarwin::GetSharedModule(module_spec, process, module_sp, + module_search_paths_ptr, old_modules, + did_create_ptr); + } +} - // Lastly, look through the kext binarys without dSYMs - if (m_name_to_kext_path_map_without_dsyms.count(kext_bundle_cs) > 0) { - for (BundleIDToKextIterator it = - m_name_to_kext_path_map_without_dsyms.begin(); - it != m_name_to_kext_path_map_without_dsyms.end(); ++it) { - if (it->first == kext_bundle_cs) { - error = ExamineKextForMatchingUUID(it->second, module_spec.GetUUID(), - module_spec.GetArchitecture(), - module_sp); - if (module_sp.get()) { - return error; - } +Status PlatformDarwinKernel::GetSharedModuleKext( + const ModuleSpec &module_spec, Process *process, ModuleSP &module_sp, + const FileSpecList *module_search_paths_ptr, + llvm::SmallVectorImpl *old_modules, bool *did_create_ptr) { + Status error; + module_sp.reset(); + const FileSpec &platform_file = module_spec.GetFileSpec(); + + // Treat the file's path as a kext bundle ID (e.g. + // "com.apple.driver.AppleIRController") and search our kext index. + ConstString kext_bundle(platform_file.GetPath().c_str()); + // First look through the kext bundles that had a dsym next to them + if (m_name_to_kext_path_map_with_dsyms.count(kext_bundle) > 0) { + for (BundleIDToKextIterator it = m_name_to_kext_path_map_with_dsyms.begin(); + it != m_name_to_kext_path_map_with_dsyms.end(); ++it) { + if (it->first == kext_bundle) { + error = ExamineKextForMatchingUUID(it->second, module_spec.GetUUID(), + module_spec.GetArchitecture(), + module_sp); + if (module_sp.get()) { + return error; } } } } - if (kext_bundle_id == "mach_kernel" && module_spec.GetUUID().IsValid()) { - // First try all kernel binaries that have a dSYM next to them - for (auto possible_kernel : m_kernel_binaries_with_dsyms) { - if (FileSystem::Instance().Exists(possible_kernel)) { - ModuleSpec kern_spec(possible_kernel); - kern_spec.GetUUID() = module_spec.GetUUID(); - ModuleSP module_sp(new Module(kern_spec)); - if (module_sp && module_sp->GetObjectFile() && - module_sp->MatchesModuleSpec(kern_spec)) { - // module_sp is an actual kernel binary we want to add. - if (process) { - process->GetTarget().GetImages().AppendIfNeeded(module_sp); - error.Clear(); + // Give the generic methods, including possibly calling into DebugSymbols + // framework on macOS systems, a chance. + error = PlatformDarwin::GetSharedModule(module_spec, process, module_sp, + module_search_paths_ptr, old_modules, + did_create_ptr); + if (error.Success() && module_sp.get()) { + return error; + } + + return error; +} + +Status PlatformDarwinKernel::GetSharedModuleKernel( + const ModuleSpec &module_spec, Process *process, ModuleSP &module_sp, + const FileSpecList *module_search_paths_ptr, + llvm::SmallVectorImpl *old_modules, bool *did_create_ptr) { + Status error; + module_sp.reset(); + + // First try all kernel binaries that have a dSYM next to them + for (auto possible_kernel : m_kernel_binaries_with_dsyms) { + if (FileSystem::Instance().Exists(possible_kernel)) { + ModuleSpec kern_spec(possible_kernel); + kern_spec.GetUUID() = module_spec.GetUUID(); + module_sp.reset(new Module(kern_spec)); + if (module_sp && module_sp->GetObjectFile() && + module_sp->MatchesModuleSpec(kern_spec)) { + // module_sp is an actual kernel binary we want to add. + if (process) { + process->GetTarget().GetImages().AppendIfNeeded(module_sp); + error.Clear(); + return error; + } else { + error = ModuleList::GetSharedModule(kern_spec, module_sp, nullptr, + nullptr, nullptr); + if (module_sp && module_sp->GetObjectFile() && + module_sp->GetObjectFile()->GetType() != + ObjectFile::Type::eTypeCoreFile) { return error; - } else { - error = ModuleList::GetSharedModule(kern_spec, module_sp, NULL, - NULL, NULL); - if (module_sp && module_sp->GetObjectFile() && - module_sp->GetObjectFile()->GetType() != - ObjectFile::Type::eTypeCoreFile) { - return error; - } - module_sp.reset(); } + module_sp.reset(); } } } + } - // Give the generic methods, including possibly calling into DebugSymbols - // framework on macOS systems, a chance. - error = PlatformDarwin::GetSharedModule(module_spec, process, module_sp, - module_search_paths_ptr, - old_modules, did_create_ptr); - if (error.Success() && module_sp.get()) { - return error; - } + // Next try all dSYMs that have no kernel binary next to them (load + // the kernel DWARF stub as the main binary) + for (auto possible_kernel_dsym : m_kernel_dsyms_no_binaries) { + std::vector objfile_names = + GetDWARFBinaryInDSYMBundle(possible_kernel_dsym); + for (FileSpec objfile : objfile_names) { + ModuleSpec kern_spec(objfile); + kern_spec.GetUUID() = module_spec.GetUUID(); + kern_spec.GetSymbolFileSpec() = possible_kernel_dsym; - // Next try all kernel binaries that don't have a dSYM - for (auto possible_kernel : m_kernel_binaries_without_dsyms) { - if (FileSystem::Instance().Exists(possible_kernel)) { - ModuleSpec kern_spec(possible_kernel); - kern_spec.GetUUID() = module_spec.GetUUID(); - ModuleSP module_sp(new Module(kern_spec)); - if (module_sp && module_sp->GetObjectFile() && - module_sp->MatchesModuleSpec(kern_spec)) { - // module_sp is an actual kernel binary we want to add. - if (process) { - process->GetTarget().GetImages().AppendIfNeeded(module_sp); - error.Clear(); + module_sp.reset(new Module(kern_spec)); + if (module_sp && module_sp->GetObjectFile() && + module_sp->MatchesModuleSpec(kern_spec)) { + // module_sp is an actual kernel binary we want to add. + if (process) { + process->GetTarget().GetImages().AppendIfNeeded(module_sp); + error.Clear(); + return error; + } else { + error = ModuleList::GetSharedModule(kern_spec, module_sp, nullptr, + nullptr, nullptr); + if (module_sp && module_sp->GetObjectFile() && + module_sp->GetObjectFile()->GetType() != + ObjectFile::Type::eTypeCoreFile) { return error; - } else { - error = ModuleList::GetSharedModule(kern_spec, module_sp, NULL, - NULL, NULL); - if (module_sp && module_sp->GetObjectFile() && - module_sp->GetObjectFile()->GetType() != - ObjectFile::Type::eTypeCoreFile) { - return error; - } - module_sp.reset(); } + module_sp.reset(); } } } } + // Give the generic methods, including possibly calling into DebugSymbols + // framework on macOS systems, a chance. + error = PlatformDarwin::GetSharedModule(module_spec, process, module_sp, + module_search_paths_ptr, old_modules, + did_create_ptr); + if (error.Success() && module_sp.get()) { + return error; + } + return error; } diff --git a/gnu/llvm/lldb/source/Plugins/Platform/MacOSX/PlatformDarwinKernel.h b/gnu/llvm/lldb/source/Plugins/Platform/MacOSX/PlatformDarwinKernel.h index 203bfb5e606..8fe9410feea 100644 --- a/gnu/llvm/lldb/source/Plugins/Platform/MacOSX/PlatformDarwinKernel.h +++ b/gnu/llvm/lldb/source/Plugins/Platform/MacOSX/PlatformDarwinKernel.h @@ -126,7 +126,31 @@ protected: // Returns true if there is a .dSYM bundle next to the kernel static bool - KernelHasdSYMSibling(const lldb_private::FileSpec &kext_bundle_filepath); + KernelHasdSYMSibling(const lldb_private::FileSpec &kernel_filepath); + + // Returns true if there is a .dSYM bundle with NO kernel binary next to it + static bool KerneldSYMHasNoSiblingBinary( + const lldb_private::FileSpec &kernel_dsym_filepath); + + // Given a dsym_bundle argument ('.../foo.dSYM'), return a FileSpec + // with the binary inside it ('.../foo.dSYM/Contents/Resources/DWARF/foo'). + // A dSYM bundle may have multiple DWARF binaries in them, so a vector + // of matches is returned. + static std::vector + GetDWARFBinaryInDSYMBundle(lldb_private::FileSpec dsym_bundle); + + lldb_private::Status + GetSharedModuleKext(const lldb_private::ModuleSpec &module_spec, + lldb_private::Process *process, lldb::ModuleSP &module_sp, + const lldb_private::FileSpecList *module_search_paths_ptr, + llvm::SmallVectorImpl *old_modules, + bool *did_create_ptr); + + lldb_private::Status GetSharedModuleKernel( + const lldb_private::ModuleSpec &module_spec, + lldb_private::Process *process, lldb::ModuleSP &module_sp, + const lldb_private::FileSpecList *module_search_paths_ptr, + llvm::SmallVectorImpl *old_modules, bool *did_create_ptr); lldb_private::Status ExamineKextForMatchingUUID(const lldb_private::FileSpec &kext_bundle_path, @@ -170,6 +194,13 @@ public: // on local // filesystem, with // dSYMs next to them + KernelBinaryCollection m_kernel_dsyms_no_binaries; // list of kernel + // dsyms with no + // binaries next to + // them + KernelBinaryCollection m_kernel_dsyms_yaas; // list of kernel + // .dSYM.yaa files + lldb_private::LazyBool m_ios_debug_session; PlatformDarwinKernel(const PlatformDarwinKernel &) = delete; diff --git a/gnu/llvm/lldb/source/Plugins/Platform/MacOSX/PlatformMacOSX.cpp b/gnu/llvm/lldb/source/Plugins/Platform/MacOSX/PlatformMacOSX.cpp index cbdd2cde662..24df03e18dd 100644 --- a/gnu/llvm/lldb/source/Plugins/Platform/MacOSX/PlatformMacOSX.cpp +++ b/gnu/llvm/lldb/source/Plugins/Platform/MacOSX/PlatformMacOSX.cpp @@ -7,15 +7,14 @@ //===----------------------------------------------------------------------===// #include "PlatformMacOSX.h" +#include "PlatformRemoteMacOSX.h" #include "PlatformRemoteiOS.h" #if defined(__APPLE__) -#include "PlatformAppleTVSimulator.h" -#include "PlatformAppleWatchSimulator.h" +#include "PlatformAppleSimulator.h" #include "PlatformDarwinKernel.h" #include "PlatformRemoteAppleBridge.h" #include "PlatformRemoteAppleTV.h" #include "PlatformRemoteAppleWatch.h" -#include "PlatformiOSSimulator.h" #endif #include "lldb/Breakpoint/BreakpointLocation.h" #include "lldb/Core/Module.h" @@ -46,11 +45,10 @@ static uint32_t g_initialize_count = 0; void PlatformMacOSX::Initialize() { PlatformDarwin::Initialize(); PlatformRemoteiOS::Initialize(); + PlatformRemoteMacOSX::Initialize(); #if defined(__APPLE__) - PlatformiOSSimulator::Initialize(); + PlatformAppleSimulator::Initialize(); PlatformDarwinKernel::Initialize(); - PlatformAppleTVSimulator::Initialize(); - PlatformAppleWatchSimulator::Initialize(); PlatformRemoteAppleTV::Initialize(); PlatformRemoteAppleWatch::Initialize(); PlatformRemoteAppleBridge::Initialize(); @@ -58,12 +56,12 @@ void PlatformMacOSX::Initialize() { if (g_initialize_count++ == 0) { #if defined(__APPLE__) - PlatformSP default_platform_sp(new PlatformMacOSX(true)); + PlatformSP default_platform_sp(new PlatformMacOSX()); default_platform_sp->SetSystemArchitecture(HostInfo::GetArchitecture()); Platform::SetHostPlatform(default_platform_sp); #endif - PluginManager::RegisterPlugin(PlatformMacOSX::GetPluginNameStatic(false), - PlatformMacOSX::GetDescriptionStatic(false), + PluginManager::RegisterPlugin(PlatformMacOSX::GetPluginNameStatic(), + PlatformMacOSX::GetDescriptionStatic(), PlatformMacOSX::CreateInstance); } } @@ -79,109 +77,31 @@ void PlatformMacOSX::Terminate() { PlatformRemoteAppleBridge::Terminate(); PlatformRemoteAppleWatch::Terminate(); PlatformRemoteAppleTV::Terminate(); - PlatformAppleWatchSimulator::Terminate(); - PlatformAppleTVSimulator::Terminate(); PlatformDarwinKernel::Terminate(); - PlatformiOSSimulator::Terminate(); + PlatformAppleSimulator::Terminate(); #endif + PlatformRemoteMacOSX::Initialize(); PlatformRemoteiOS::Terminate(); PlatformDarwin::Terminate(); } -PlatformSP PlatformMacOSX::CreateInstance(bool force, const ArchSpec *arch) { - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM)); - if (log) { - const char *arch_name; - if (arch && arch->GetArchitectureName()) - arch_name = arch->GetArchitectureName(); - else - arch_name = ""; - - const char *triple_cstr = - arch ? arch->GetTriple().getTriple().c_str() : ""; - - LLDB_LOGF(log, "PlatformMacOSX::%s(force=%s, arch={%s,%s})", __FUNCTION__, - force ? "true" : "false", arch_name, triple_cstr); - } - - // The only time we create an instance is when we are creating a remote - // macosx platform - const bool is_host = false; - - bool create = force; - if (!create && arch && arch->IsValid()) { - const llvm::Triple &triple = arch->GetTriple(); - switch (triple.getVendor()) { - case llvm::Triple::Apple: - create = true; - break; - -#if defined(__APPLE__) - // Only accept "unknown" for vendor if the host is Apple and it "unknown" - // wasn't specified (it was just returned because it was NOT specified) - case llvm::Triple::UnknownVendor: - create = !arch->TripleVendorWasSpecified(); - break; -#endif - default: - break; - } - - if (create) { - switch (triple.getOS()) { - case llvm::Triple::Darwin: // Deprecated, but still support Darwin for - // historical reasons - case llvm::Triple::MacOSX: - break; -#if defined(__APPLE__) - // Only accept "vendor" for vendor if the host is Apple and it "unknown" - // wasn't specified (it was just returned because it was NOT specified) - case llvm::Triple::UnknownOS: - create = !arch->TripleOSWasSpecified(); - break; -#endif - default: - create = false; - break; - } - } - } - if (create) { - LLDB_LOGF(log, "PlatformMacOSX::%s() creating platform", __FUNCTION__); - return PlatformSP(new PlatformMacOSX(is_host)); - } - - LLDB_LOGF(log, "PlatformMacOSX::%s() aborting creation of platform", - __FUNCTION__); - - return PlatformSP(); +lldb_private::ConstString PlatformMacOSX::GetPluginNameStatic() { + static ConstString g_host_name(Platform::GetHostPlatformName()); + return g_host_name; } -lldb_private::ConstString PlatformMacOSX::GetPluginNameStatic(bool is_host) { - if (is_host) { - static ConstString g_host_name(Platform::GetHostPlatformName()); - return g_host_name; - } else { - static ConstString g_remote_name("remote-macosx"); - return g_remote_name; - } +const char *PlatformMacOSX::GetDescriptionStatic() { + return "Local Mac OS X user platform plug-in."; } -const char *PlatformMacOSX::GetDescriptionStatic(bool is_host) { - if (is_host) - return "Local Mac OS X user platform plug-in."; - else - return "Remote Mac OS X user platform plug-in."; +PlatformSP PlatformMacOSX::CreateInstance(bool force, const ArchSpec *arch) { + // The only time we create an instance is when we are creating a remote + // macosx platform which is handled by PlatformRemoteMacOSX. + return PlatformSP(); } /// Default Constructor -PlatformMacOSX::PlatformMacOSX(bool is_host) : PlatformDarwin(is_host) {} - -/// Destructor. -/// -/// The destructor is virtual since this class is designed to be -/// inherited from by the plug-in instance. -PlatformMacOSX::~PlatformMacOSX() {} +PlatformMacOSX::PlatformMacOSX() : PlatformDarwin(true) {} ConstString PlatformMacOSX::GetSDKDirectory(lldb_private::Target &target) { ModuleSP exe_module_sp(target.GetExecutableModule()); @@ -218,71 +138,36 @@ ConstString PlatformMacOSX::GetSDKDirectory(lldb_private::Target &target) { return {}; } -Status PlatformMacOSX::GetSymbolFile(const FileSpec &platform_file, - const UUID *uuid_ptr, - FileSpec &local_file) { - if (IsRemote()) { - if (m_remote_platform_sp) - return m_remote_platform_sp->GetFileWithUUID(platform_file, uuid_ptr, - local_file); +bool PlatformMacOSX::GetSupportedArchitectureAtIndex(uint32_t idx, + ArchSpec &arch) { +#if defined(__arm__) || defined(__arm64__) || defined(__aarch64__) + // macOS for ARM64 support both native and translated x86_64 processes + if (!m_num_arm_arches || idx < m_num_arm_arches) { + bool res = ARMGetSupportedArchitectureAtIndex(idx, arch); + if (res) + return true; + if (!m_num_arm_arches) + m_num_arm_arches = idx; } - // Default to the local case - local_file = platform_file; - return Status(); -} - -lldb_private::Status -PlatformMacOSX::GetFileWithUUID(const lldb_private::FileSpec &platform_file, - const lldb_private::UUID *uuid_ptr, - lldb_private::FileSpec &local_file) { - if (IsRemote() && m_remote_platform_sp) { - std::string local_os_build; -#if !defined(__linux__) - HostInfo::GetOSBuildString(local_os_build); -#endif - std::string remote_os_build; - m_remote_platform_sp->GetOSBuildString(remote_os_build); - if (local_os_build == remote_os_build) { - // same OS version: the local file is good enough - local_file = platform_file; - return Status(); - } else { - // try to find the file in the cache - std::string cache_path(GetLocalCacheDirectory()); - std::string module_path(platform_file.GetPath()); - cache_path.append(module_path); - FileSpec module_cache_spec(cache_path); - if (FileSystem::Instance().Exists(module_cache_spec)) { - local_file = module_cache_spec; - return Status(); - } - // bring in the remote module file - FileSpec module_cache_folder = - module_cache_spec.CopyByRemovingLastPathComponent(); - // try to make the local directory first - Status err( - llvm::sys::fs::create_directory(module_cache_folder.GetPath())); - if (err.Fail()) - return err; - err = GetFile(platform_file, module_cache_spec); - if (err.Fail()) - return err; - if (FileSystem::Instance().Exists(module_cache_spec)) { - local_file = module_cache_spec; - return Status(); - } else - return Status("unable to obtain valid module file"); - } + // We can't use x86GetSupportedArchitectureAtIndex() because it uses + // the system architecture for some of its return values and also + // has a 32bits variant. + if (idx == m_num_arm_arches) { + arch.SetTriple("x86_64-apple-macosx"); + return true; + } else if (idx == m_num_arm_arches + 1) { + arch.SetTriple("x86_64-apple-ios-macabi"); + return true; + } else if (idx == m_num_arm_arches + 2) { + arch.SetTriple("arm64-apple-ios"); + return true; + } else if (idx == m_num_arm_arches + 3) { + arch.SetTriple("arm64e-apple-ios"); + return true; } - local_file = platform_file; - return Status(); -} -bool PlatformMacOSX::GetSupportedArchitectureAtIndex(uint32_t idx, - ArchSpec &arch) { -#if defined(__arm__) || defined(__arm64__) || defined(__aarch64__) - return ARMGetSupportedArchitectureAtIndex(idx, arch); + return false; #else return x86GetSupportedArchitectureAtIndex(idx, arch); #endif diff --git a/gnu/llvm/lldb/source/Plugins/Platform/MacOSX/PlatformMacOSX.h b/gnu/llvm/lldb/source/Plugins/Platform/MacOSX/PlatformMacOSX.h index deca3f06ab7..ea7f2b0d25e 100644 --- a/gnu/llvm/lldb/source/Plugins/Platform/MacOSX/PlatformMacOSX.h +++ b/gnu/llvm/lldb/source/Plugins/Platform/MacOSX/PlatformMacOSX.h @@ -13,9 +13,7 @@ class PlatformMacOSX : public PlatformDarwin { public: - PlatformMacOSX(bool is_host); - - ~PlatformMacOSX() override; + PlatformMacOSX(); // Class functions static lldb::PlatformSP CreateInstance(bool force, @@ -25,13 +23,13 @@ public: static void Terminate(); - static lldb_private::ConstString GetPluginNameStatic(bool is_host); + static lldb_private::ConstString GetPluginNameStatic(); - static const char *GetDescriptionStatic(bool is_host); + static const char *GetDescriptionStatic(); // lldb_private::PluginInterface functions lldb_private::ConstString GetPluginName() override { - return GetPluginNameStatic(IsHost()); + return GetPluginNameStatic(); } uint32_t GetPluginVersion() override { return 1; } @@ -43,14 +41,7 @@ public: llvm::SmallVectorImpl *old_modules, bool *did_create_ptr) override; - const char *GetDescription() override { - return GetDescriptionStatic(IsHost()); - } - - lldb_private::Status - GetSymbolFile(const lldb_private::FileSpec &platform_file, - const lldb_private::UUID *uuid_ptr, - lldb_private::FileSpec &local_file); + const char *GetDescription() override { return GetDescriptionStatic(); } lldb_private::Status GetFile(const lldb_private::FileSpec &source, @@ -58,11 +49,6 @@ public: return PlatformDarwin::GetFile(source, destination); } - lldb_private::Status - GetFileWithUUID(const lldb_private::FileSpec &platform_file, - const lldb_private::UUID *uuid_ptr, - lldb_private::FileSpec &local_file) override; - bool GetSupportedArchitectureAtIndex(uint32_t idx, lldb_private::ArchSpec &arch) override; @@ -77,8 +63,9 @@ public: } private: - PlatformMacOSX(const PlatformMacOSX &) = delete; - const PlatformMacOSX &operator=(const PlatformMacOSX &) = delete; +#if defined(__arm__) || defined(__arm64__) || defined(__aarch64__) + uint32_t m_num_arm_arches = 0; +#endif }; #endif // LLDB_SOURCE_PLUGINS_PLATFORM_MACOSX_PLATFORMMACOSX_H diff --git a/gnu/llvm/lldb/source/Plugins/Platform/MacOSX/PlatformMacOSXProperties.td b/gnu/llvm/lldb/source/Plugins/Platform/MacOSX/PlatformMacOSXProperties.td index 07e4e3e81d8..39e9641daae 100644 --- a/gnu/llvm/lldb/source/Plugins/Platform/MacOSX/PlatformMacOSXProperties.td +++ b/gnu/llvm/lldb/source/Plugins/Platform/MacOSX/PlatformMacOSXProperties.td @@ -1,10 +1,6 @@ include "../../../../include/lldb/Core/PropertiesBase.td" let Definition = "platformdarwinkernel" in { - def SearchForKexts: Property<"search-locally-for-kexts", "Boolean">, - Global, - DefaultTrue, - Desc<"Automatically search for kexts on the local system when doing kernel debugging.">; def KextDirectories: Property<"kext-directories", "FileSpecList">, DefaultStringValue<"">, Desc<"Directories/KDKs to search for kexts in when starting a kernel debug session.">; diff --git a/gnu/llvm/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteAppleBridge.cpp b/gnu/llvm/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteAppleBridge.cpp index eb25a061de4..f3ee92a9d27 100644 --- a/gnu/llvm/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteAppleBridge.cpp +++ b/gnu/llvm/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteAppleBridge.cpp @@ -96,14 +96,22 @@ PlatformSP PlatformRemoteAppleBridge::CreateInstance(bool force, break; } if (create) { +// Suppress warning "switch statement contains 'default' but no 'case' labels". +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4065) +#endif switch (triple.getOS()) { - // NEED_BRIDGEOS_TRIPLE case llvm::Triple::BridgeOS: - break; + // NEED_BRIDGEOS_TRIPLE case llvm::Triple::BridgeOS: + // break; default: create = false; break; } +#ifdef _MSC_VER +#pragma warning(pop) +#endif } } break; default: @@ -164,15 +172,10 @@ bool PlatformRemoteAppleBridge::GetSupportedArchitectureAtIndex(uint32_t idx, return false; } - -void PlatformRemoteAppleBridge::GetDeviceSupportDirectoryNames (std::vector &dirnames) -{ - dirnames.clear(); - dirnames.push_back("BridgeOS DeviceSupport"); +llvm::StringRef PlatformRemoteAppleBridge::GetDeviceSupportDirectoryName() { + return "BridgeOS DeviceSupport"; } -std::string PlatformRemoteAppleBridge::GetPlatformName () -{ - return "BridgeOS.platform"; +llvm::StringRef PlatformRemoteAppleBridge::GetPlatformName() { + return "BridgeOS.platform"; } - diff --git a/gnu/llvm/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteAppleBridge.h b/gnu/llvm/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteAppleBridge.h index b255fa37ed1..2d574894a28 100644 --- a/gnu/llvm/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteAppleBridge.h +++ b/gnu/llvm/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteAppleBridge.h @@ -21,8 +21,6 @@ class PlatformRemoteAppleBridge : public PlatformRemoteDarwinDevice { public: PlatformRemoteAppleBridge(); - ~PlatformRemoteAppleBridge() override = default; - // Class Functions static lldb::PlatformSP CreateInstance(bool force, const lldb_private::ArchSpec *arch); @@ -50,17 +48,8 @@ public: lldb_private::ArchSpec &arch) override; protected: - - // lldb_private::PlatformRemoteDarwinDevice functions - - void GetDeviceSupportDirectoryNames (std::vector &dirnames) override; - - std::string GetPlatformName () override; - -private: - PlatformRemoteAppleBridge(const PlatformRemoteAppleBridge &) = delete; - const PlatformRemoteAppleBridge & - operator=(const PlatformRemoteAppleBridge &) = delete; + llvm::StringRef GetDeviceSupportDirectoryName() override; + llvm::StringRef GetPlatformName() override; }; #endif // LLDB_SOURCE_PLUGINS_PLATFORM_MACOSX_PLATFORMREMOTEAPPLEBRIDGE_H diff --git a/gnu/llvm/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteAppleTV.cpp b/gnu/llvm/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteAppleTV.cpp index 082ddcc0f56..15e91b239a3 100644 --- a/gnu/llvm/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteAppleTV.cpp +++ b/gnu/llvm/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteAppleTV.cpp @@ -223,15 +223,10 @@ bool PlatformRemoteAppleTV::GetSupportedArchitectureAtIndex(uint32_t idx, return false; } - -void PlatformRemoteAppleTV::GetDeviceSupportDirectoryNames (std::vector &dirnames) -{ - dirnames.clear(); - dirnames.push_back("tvOS DeviceSupport"); +llvm::StringRef PlatformRemoteAppleTV::GetDeviceSupportDirectoryName() { + return "tvOS DeviceSupport"; } -std::string PlatformRemoteAppleTV::GetPlatformName () -{ - return "AppleTVOS.platform"; +llvm::StringRef PlatformRemoteAppleTV::GetPlatformName() { + return "AppleTVOS.platform"; } - diff --git a/gnu/llvm/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteAppleTV.h b/gnu/llvm/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteAppleTV.h index f5b554d2f66..15be923cca4 100644 --- a/gnu/llvm/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteAppleTV.h +++ b/gnu/llvm/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteAppleTV.h @@ -21,8 +21,6 @@ class PlatformRemoteAppleTV : public PlatformRemoteDarwinDevice { public: PlatformRemoteAppleTV(); - ~PlatformRemoteAppleTV() override = default; - // Class Functions static lldb::PlatformSP CreateInstance(bool force, const lldb_private::ArchSpec *arch); @@ -50,17 +48,8 @@ public: lldb_private::ArchSpec &arch) override; protected: - - // lldb_private::PlatformRemoteDarwinDevice functions - - void GetDeviceSupportDirectoryNames (std::vector &dirnames) override; - - std::string GetPlatformName () override; - -private: - PlatformRemoteAppleTV(const PlatformRemoteAppleTV &) = delete; - const PlatformRemoteAppleTV & - operator=(const PlatformRemoteAppleTV &) = delete; + llvm::StringRef GetDeviceSupportDirectoryName() override; + llvm::StringRef GetPlatformName() override; }; #endif // LLDB_SOURCE_PLUGINS_PLATFORM_MACOSX_PLATFORMREMOTEAPPLETV_H diff --git a/gnu/llvm/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteAppleWatch.cpp b/gnu/llvm/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteAppleWatch.cpp index 6b40393ba5b..29162e11ec5 100644 --- a/gnu/llvm/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteAppleWatch.cpp +++ b/gnu/llvm/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteAppleWatch.cpp @@ -298,13 +298,10 @@ bool PlatformRemoteAppleWatch::GetSupportedArchitectureAtIndex(uint32_t idx, return false; } -void PlatformRemoteAppleWatch::GetDeviceSupportDirectoryNames (std::vector &dirnames) -{ - dirnames.clear(); - dirnames.push_back("watchOS DeviceSupport"); +llvm::StringRef PlatformRemoteAppleWatch::GetDeviceSupportDirectoryName() { + return "watchOS DeviceSupport"; } -std::string PlatformRemoteAppleWatch::GetPlatformName () -{ - return "WatchOS.platform"; +llvm::StringRef PlatformRemoteAppleWatch::GetPlatformName() { + return "WatchOS.platform"; } diff --git a/gnu/llvm/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteAppleWatch.h b/gnu/llvm/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteAppleWatch.h index 712693f6c41..43be3317d9c 100644 --- a/gnu/llvm/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteAppleWatch.h +++ b/gnu/llvm/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteAppleWatch.h @@ -22,8 +22,6 @@ class PlatformRemoteAppleWatch : public PlatformRemoteDarwinDevice { public: PlatformRemoteAppleWatch(); - ~PlatformRemoteAppleWatch() override = default; - // Class Functions static lldb::PlatformSP CreateInstance(bool force, const lldb_private::ArchSpec *arch); @@ -53,17 +51,8 @@ public: lldb_private::ArchSpec &arch) override; protected: - - // lldb_private::PlatformRemoteDarwinDevice functions - - void GetDeviceSupportDirectoryNames (std::vector &dirnames) override; - - std::string GetPlatformName () override; - -private: - PlatformRemoteAppleWatch(const PlatformRemoteAppleWatch &) = delete; - const PlatformRemoteAppleWatch & - operator=(const PlatformRemoteAppleWatch &) = delete; + llvm::StringRef GetDeviceSupportDirectoryName() override; + llvm::StringRef GetPlatformName() override; }; #endif // LLDB_SOURCE_PLUGINS_PLATFORM_MACOSX_PLATFORMREMOTEAPPLEWATCH_H diff --git a/gnu/llvm/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteDarwinDevice.cpp b/gnu/llvm/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteDarwinDevice.cpp index 065eefa48fe..79cbd1c1f91 100644 --- a/gnu/llvm/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteDarwinDevice.cpp +++ b/gnu/llvm/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteDarwinDevice.cpp @@ -39,15 +39,13 @@ PlatformRemoteDarwinDevice::SDKDirectoryInfo::SDKDirectoryInfo( PlatformRemoteDarwinDevice::PlatformRemoteDarwinDevice() : PlatformDarwin(false), // This is a remote platform m_sdk_directory_infos(), m_device_support_directory(), - m_device_support_directory_for_os_version(), m_build_update(), - m_last_module_sdk_idx(UINT32_MAX), - m_connected_module_sdk_idx(UINT32_MAX) {} + m_device_support_directory_for_os_version(), m_build_update() {} /// Destructor. /// /// The destructor is virtual since this class is designed to be /// inherited from by the plug-in instance. -PlatformRemoteDarwinDevice::~PlatformRemoteDarwinDevice() {} +PlatformRemoteDarwinDevice::~PlatformRemoteDarwinDevice() = default; void PlatformRemoteDarwinDevice::GetStatus(Stream &strm) { Platform::GetStatus(strm); @@ -197,42 +195,36 @@ bool PlatformRemoteDarwinDevice::UpdateSDKDirectoryInfosIfNeeded() { } } - std::vector device_support_dirnames; - GetDeviceSupportDirectoryNames (device_support_dirnames); - - for (std::string &dirname : device_support_dirnames) - { - const uint32_t num_installed = m_sdk_directory_infos.size(); - std::string local_sdk_cache_str = "~/Library/Developer/Xcode/"; - local_sdk_cache_str += dirname; - FileSpec local_sdk_cache(local_sdk_cache_str.c_str()); - FileSystem::Instance().Resolve(local_sdk_cache); - if (FileSystem::Instance().Exists(local_sdk_cache)) { - if (log) { - LLDB_LOGF( - log, - "PlatformRemoteDarwinDevice::UpdateSDKDirectoryInfosIfNeeded " - "searching %s for additional SDKs", - local_sdk_cache.GetPath().c_str()); - } - char path[PATH_MAX]; - if (local_sdk_cache.GetPath(path, sizeof(path))) { - FileSystem::Instance().EnumerateDirectory( - path, find_directories, find_files, find_other, - GetContainedFilesIntoVectorOfStringsCallback, - &m_sdk_directory_infos); - const uint32_t num_sdk_infos = m_sdk_directory_infos.size(); - // First try for an exact match of major, minor and update - for (uint32_t i = num_installed; i < num_sdk_infos; ++i) { - m_sdk_directory_infos[i].user_cached = true; - if (log) { - LLDB_LOGF( - log, - "PlatformRemoteDarwinDevice::" - "UpdateSDKDirectoryInfosIfNeeded " - "user SDK directory %s", - m_sdk_directory_infos[i].directory.GetPath().c_str()); - } + const uint32_t num_installed = m_sdk_directory_infos.size(); + llvm::StringRef dirname = GetDeviceSupportDirectoryName(); + std::string local_sdk_cache_str = "~/Library/Developer/Xcode/"; + local_sdk_cache_str += std::string(dirname); + FileSpec local_sdk_cache(local_sdk_cache_str.c_str()); + FileSystem::Instance().Resolve(local_sdk_cache); + if (FileSystem::Instance().Exists(local_sdk_cache)) { + if (log) { + LLDB_LOGF( + log, + "PlatformRemoteDarwinDevice::UpdateSDKDirectoryInfosIfNeeded " + "searching %s for additional SDKs", + local_sdk_cache.GetPath().c_str()); + } + char path[PATH_MAX]; + if (local_sdk_cache.GetPath(path, sizeof(path))) { + FileSystem::Instance().EnumerateDirectory( + path, find_directories, find_files, find_other, + GetContainedFilesIntoVectorOfStringsCallback, + &m_sdk_directory_infos); + const uint32_t num_sdk_infos = m_sdk_directory_infos.size(); + // First try for an exact match of major, minor and update + for (uint32_t i = num_installed; i < num_sdk_infos; ++i) { + m_sdk_directory_infos[i].user_cached = true; + if (log) { + LLDB_LOGF(log, + "PlatformRemoteDarwinDevice::" + "UpdateSDKDirectoryInfosIfNeeded " + "user SDK directory %s", + m_sdk_directory_infos[i].directory.GetPath().c_str()); } } } @@ -341,7 +333,8 @@ PlatformRemoteDarwinDevice::GetSDKDirectoryForLatestOSVersion() { } const char *PlatformRemoteDarwinDevice::GetDeviceSupportDirectory() { - std::string platform_dir = "/Platforms/" + GetPlatformName() + "/DeviceSupport"; + std::string platform_dir = + ("/Platforms/" + GetPlatformName() + "/DeviceSupport").str(); if (m_device_support_directory.empty()) { if (FileSpec fspec = HostInfo::GetXcodeDeveloperDirectory()) { m_device_support_directory = fspec.GetPath(); diff --git a/gnu/llvm/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteDarwinDevice.h b/gnu/llvm/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteDarwinDevice.h index cc5f286f3b2..3b578a3fe91 100644 --- a/gnu/llvm/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteDarwinDevice.h +++ b/gnu/llvm/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteDarwinDevice.h @@ -64,8 +64,8 @@ protected: std::string m_device_support_directory; std::string m_device_support_directory_for_os_version; std::string m_build_update; - uint32_t m_last_module_sdk_idx; - uint32_t m_connected_module_sdk_idx; + uint32_t m_last_module_sdk_idx = UINT32_MAX; + uint32_t m_connected_module_sdk_idx = UINT32_MAX; bool UpdateSDKDirectoryInfosIfNeeded(); @@ -97,10 +97,8 @@ protected: // UINT32_MAX if that SDK not found. uint32_t GetSDKIndexBySDKDirectoryInfo(const SDKDirectoryInfo *sdk_info); - - virtual void GetDeviceSupportDirectoryNames (std::vector &dirnames) = 0; - - virtual std::string GetPlatformName () = 0; + virtual llvm::StringRef GetDeviceSupportDirectoryName() = 0; + virtual llvm::StringRef GetPlatformName() = 0; private: PlatformRemoteDarwinDevice(const PlatformRemoteDarwinDevice &) = delete; diff --git a/gnu/llvm/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteMacOSX.cpp b/gnu/llvm/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteMacOSX.cpp new file mode 100644 index 00000000000..3e31b127459 --- /dev/null +++ b/gnu/llvm/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteMacOSX.cpp @@ -0,0 +1,219 @@ +//===-- PlatformRemoteMacOSX.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 +#include +#include + +#include "PlatformRemoteMacOSX.h" + +#include "lldb/Breakpoint/BreakpointLocation.h" +#include "lldb/Core/Module.h" +#include "lldb/Core/ModuleList.h" +#include "lldb/Core/ModuleSpec.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Host/Host.h" +#include "lldb/Host/HostInfo.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/Target.h" +#include "lldb/Utility/ArchSpec.h" +#include "lldb/Utility/FileSpec.h" +#include "lldb/Utility/Log.h" +#include "lldb/Utility/StreamString.h" + +using namespace lldb; +using namespace lldb_private; + +/// Default Constructor +PlatformRemoteMacOSX::PlatformRemoteMacOSX() : PlatformRemoteDarwinDevice() {} + +// Static Variables +static uint32_t g_initialize_count = 0; + +// Static Functions +void PlatformRemoteMacOSX::Initialize() { + PlatformDarwin::Initialize(); + + if (g_initialize_count++ == 0) { + PluginManager::RegisterPlugin(PlatformRemoteMacOSX::GetPluginNameStatic(), + PlatformRemoteMacOSX::GetDescriptionStatic(), + PlatformRemoteMacOSX::CreateInstance); + } +} + +void PlatformRemoteMacOSX::Terminate() { + if (g_initialize_count > 0) { + if (--g_initialize_count == 0) { + PluginManager::UnregisterPlugin(PlatformRemoteMacOSX::CreateInstance); + } + } + + PlatformDarwin::Terminate(); +} + +PlatformSP PlatformRemoteMacOSX::CreateInstance(bool force, + const ArchSpec *arch) { + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM)); + if (log) { + const char *arch_name; + if (arch && arch->GetArchitectureName()) + arch_name = arch->GetArchitectureName(); + else + arch_name = ""; + + const char *triple_cstr = + arch ? arch->GetTriple().getTriple().c_str() : ""; + + LLDB_LOGF(log, "PlatformMacOSX::%s(force=%s, arch={%s,%s})", __FUNCTION__, + force ? "true" : "false", arch_name, triple_cstr); + } + + bool create = force; + if (!create && arch && arch->IsValid()) { + const llvm::Triple &triple = arch->GetTriple(); + switch (triple.getVendor()) { + case llvm::Triple::Apple: + create = true; + break; + +#if defined(__APPLE__) + // Only accept "unknown" for vendor if the host is Apple and it "unknown" + // wasn't specified (it was just returned because it was NOT specified) + case llvm::Triple::UnknownVendor: + create = !arch->TripleVendorWasSpecified(); + break; +#endif + default: + break; + } + + if (create) { + switch (triple.getOS()) { + case llvm::Triple::Darwin: // Deprecated, but still support Darwin for + // historical reasons + case llvm::Triple::MacOSX: + break; +#if defined(__APPLE__) + // Only accept "vendor" for vendor if the host is Apple and it "unknown" + // wasn't specified (it was just returned because it was NOT specified) + case llvm::Triple::UnknownOS: + create = !arch->TripleOSWasSpecified(); + break; +#endif + default: + create = false; + break; + } + } + } + + if (create) { + LLDB_LOGF(log, "PlatformRemoteMacOSX::%s() creating platform", + __FUNCTION__); + return std::make_shared(); + } + + LLDB_LOGF(log, "PlatformRemoteMacOSX::%s() aborting creation of platform", + __FUNCTION__); + + return PlatformSP(); +} + +bool PlatformRemoteMacOSX::GetSupportedArchitectureAtIndex(uint32_t idx, + ArchSpec &arch) { + // macOS for ARM64 support both native and translated x86_64 processes + if (!m_num_arm_arches || idx < m_num_arm_arches) { + bool res = ARMGetSupportedArchitectureAtIndex(idx, arch); + if (res) + return true; + if (!m_num_arm_arches) + m_num_arm_arches = idx; + } + + // We can't use x86GetSupportedArchitectureAtIndex() because it uses + // the system architecture for some of its return values and also + // has a 32bits variant. + if (idx == m_num_arm_arches) { + arch.SetTriple("x86_64-apple-macosx"); + return true; + } else if (idx == m_num_arm_arches + 1) { + arch.SetTriple("x86_64-apple-ios-macabi"); + return true; + } else if (idx == m_num_arm_arches + 2) { + arch.SetTriple("arm64-apple-ios"); + return true; + } else if (idx == m_num_arm_arches + 3) { + arch.SetTriple("arm64e-apple-ios"); + return true; + } + + return false; +} + +lldb_private::Status PlatformRemoteMacOSX::GetFileWithUUID( + const lldb_private::FileSpec &platform_file, + const lldb_private::UUID *uuid_ptr, lldb_private::FileSpec &local_file) { + if (m_remote_platform_sp) { + std::string local_os_build; +#if !defined(__linux__) + HostInfo::GetOSBuildString(local_os_build); +#endif + std::string remote_os_build; + m_remote_platform_sp->GetOSBuildString(remote_os_build); + if (local_os_build == remote_os_build) { + // same OS version: the local file is good enough + local_file = platform_file; + return Status(); + } else { + // try to find the file in the cache + std::string cache_path(GetLocalCacheDirectory()); + std::string module_path(platform_file.GetPath()); + cache_path.append(module_path); + FileSpec module_cache_spec(cache_path); + if (FileSystem::Instance().Exists(module_cache_spec)) { + local_file = module_cache_spec; + return Status(); + } + // bring in the remote module file + FileSpec module_cache_folder = + module_cache_spec.CopyByRemovingLastPathComponent(); + // try to make the local directory first + Status err( + llvm::sys::fs::create_directory(module_cache_folder.GetPath())); + if (err.Fail()) + return err; + err = GetFile(platform_file, module_cache_spec); + if (err.Fail()) + return err; + if (FileSystem::Instance().Exists(module_cache_spec)) { + local_file = module_cache_spec; + return Status(); + } else + return Status("unable to obtain valid module file"); + } + } + local_file = platform_file; + return Status(); +} + +lldb_private::ConstString PlatformRemoteMacOSX::GetPluginNameStatic() { + static ConstString g_name("remote-macosx"); + return g_name; +} + +const char *PlatformRemoteMacOSX::GetDescriptionStatic() { + return "Remote Mac OS X user platform plug-in."; +} + +llvm::StringRef PlatformRemoteMacOSX::GetDeviceSupportDirectoryName() { + return "macOS DeviceSupport"; +} + +llvm::StringRef PlatformRemoteMacOSX::GetPlatformName() { + return "MacOSX.platform"; +} diff --git a/gnu/llvm/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteMacOSX.h b/gnu/llvm/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteMacOSX.h new file mode 100644 index 00000000000..9a3ca51912d --- /dev/null +++ b/gnu/llvm/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteMacOSX.h @@ -0,0 +1,60 @@ +//===-- PlatformRemoteMacOSX.h ---------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SOURCE_PLUGINS_PLATFORM_MACOSX_PLATFORMREMOTEMACOSX_H +#define LLDB_SOURCE_PLUGINS_PLATFORM_MACOSX_PLATFORMREMOTEMACOSX_H + +#include + +#include "lldb/Utility/FileSpec.h" + +#include "llvm/Support/FileSystem.h" + +#include "PlatformMacOSX.h" +#include "PlatformRemoteDarwinDevice.h" + +class PlatformRemoteMacOSX : public virtual PlatformRemoteDarwinDevice { +public: + PlatformRemoteMacOSX(); + + static lldb::PlatformSP CreateInstance(bool force, + const lldb_private::ArchSpec *arch); + + static void Initialize(); + + static void Terminate(); + + static lldb_private::ConstString GetPluginNameStatic(); + + static const char *GetDescriptionStatic(); + + lldb_private::ConstString GetPluginName() override { + return GetPluginNameStatic(); + } + + uint32_t GetPluginVersion() override { return 1; } + + const char *GetDescription() override { return GetDescriptionStatic(); } + + lldb_private::Status + GetFileWithUUID(const lldb_private::FileSpec &platform_file, + const lldb_private::UUID *uuid_ptr, + lldb_private::FileSpec &local_file) override; + + bool GetSupportedArchitectureAtIndex(uint32_t idx, + lldb_private::ArchSpec &arch) override; + +protected: + llvm::StringRef GetDeviceSupportDirectoryName() override; + llvm::StringRef GetPlatformName() override; + +private: + uint32_t m_num_arm_arches = 0; +}; + +#endif // LLDB_SOURCE_PLUGINS_PLATFORM_MACOSX_PLATFORMREMOTEMACOSX_H diff --git a/gnu/llvm/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteiOS.cpp b/gnu/llvm/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteiOS.cpp index b37cdecd38c..3269345f354 100644 --- a/gnu/llvm/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteiOS.cpp +++ b/gnu/llvm/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteiOS.cpp @@ -143,14 +143,10 @@ bool PlatformRemoteiOS::GetSupportedArchitectureAtIndex(uint32_t idx, return ARMGetSupportedArchitectureAtIndex(idx, arch); } - -void PlatformRemoteiOS::GetDeviceSupportDirectoryNames (std::vector &dirnames) -{ - dirnames.clear(); - dirnames.push_back("iOS DeviceSupport"); +llvm::StringRef PlatformRemoteiOS::GetDeviceSupportDirectoryName() { + return "iOS DeviceSupport"; } -std::string PlatformRemoteiOS::GetPlatformName () -{ - return "iPhoneOS.platform"; +llvm::StringRef PlatformRemoteiOS::GetPlatformName() { + return "iPhoneOS.platform"; } diff --git a/gnu/llvm/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteiOS.h b/gnu/llvm/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteiOS.h index 4f38128bfb0..b6cf4d63f30 100644 --- a/gnu/llvm/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteiOS.h +++ b/gnu/llvm/lldb/source/Plugins/Platform/MacOSX/PlatformRemoteiOS.h @@ -20,8 +20,6 @@ class PlatformRemoteiOS : public PlatformRemoteDarwinDevice { public: PlatformRemoteiOS(); - ~PlatformRemoteiOS() override = default; - // Class Functions static lldb::PlatformSP CreateInstance(bool force, const lldb_private::ArchSpec *arch); @@ -49,16 +47,8 @@ public: lldb_private::ArchSpec &arch) override; protected: - - // lldb_private::PlatformRemoteDarwinDevice functions - - void GetDeviceSupportDirectoryNames (std::vector &dirnames) override; - - std::string GetPlatformName () override; - -private: - PlatformRemoteiOS(const PlatformRemoteiOS &) = delete; - const PlatformRemoteiOS &operator=(const PlatformRemoteiOS &) = delete; + llvm::StringRef GetDeviceSupportDirectoryName() override; + llvm::StringRef GetPlatformName() override; }; #endif // LLDB_SOURCE_PLUGINS_PLATFORM_MACOSX_PLATFORMREMOTEIOS_H diff --git a/gnu/llvm/lldb/source/Plugins/Platform/MacOSX/objcxx/CMakeLists.txt b/gnu/llvm/lldb/source/Plugins/Platform/MacOSX/objcxx/CMakeLists.txt index 946ff0a64c2..7d094a5865c 100644 --- a/gnu/llvm/lldb/source/Plugins/Platform/MacOSX/objcxx/CMakeLists.txt +++ b/gnu/llvm/lldb/source/Plugins/Platform/MacOSX/objcxx/CMakeLists.txt @@ -15,3 +15,6 @@ add_lldb_library(lldbPluginPlatformMacOSXObjCXX Object Support ) + + +target_compile_options(lldbPluginPlatformMacOSXObjCXX PRIVATE -fno-objc-exceptions) diff --git a/gnu/llvm/lldb/source/Plugins/Platform/MacOSX/objcxx/PlatformiOSSimulatorCoreSimulatorSupport.h b/gnu/llvm/lldb/source/Plugins/Platform/MacOSX/objcxx/PlatformiOSSimulatorCoreSimulatorSupport.h index 5104e488189..a35efd53f31 100644 --- a/gnu/llvm/lldb/source/Plugins/Platform/MacOSX/objcxx/PlatformiOSSimulatorCoreSimulatorSupport.h +++ b/gnu/llvm/lldb/source/Plugins/Platform/MacOSX/objcxx/PlatformiOSSimulatorCoreSimulatorSupport.h @@ -93,7 +93,7 @@ public: ProductFamilyID GetProductFamilyID(); private: - id m_dev; + id m_dev = nullptr; llvm::Optional m_model_identifier; }; @@ -129,7 +129,7 @@ public: bool IsAvailable(); private: - id m_dev; + id m_dev = nullptr; llvm::Optional m_os_version; }; @@ -169,7 +169,7 @@ public: Process Spawn(lldb_private::ProcessLaunchInfo &launch_info); private: - id m_dev; + id m_dev = nullptr; llvm::Optional m_dev_type; llvm::Optional m_dev_runtime; diff --git a/gnu/llvm/lldb/source/Plugins/Platform/MacOSX/objcxx/PlatformiOSSimulatorCoreSimulatorSupport.mm b/gnu/llvm/lldb/source/Plugins/Platform/MacOSX/objcxx/PlatformiOSSimulatorCoreSimulatorSupport.mm index 8f36640a66a..91d6252aa0b 100644 --- a/gnu/llvm/lldb/source/Plugins/Platform/MacOSX/objcxx/PlatformiOSSimulatorCoreSimulatorSupport.mm +++ b/gnu/llvm/lldb/source/Plugins/Platform/MacOSX/objcxx/PlatformiOSSimulatorCoreSimulatorSupport.mm @@ -66,8 +66,7 @@ CoreSimulatorSupport::Process::Process(Status error) CoreSimulatorSupport::Process::Process(lldb::pid_t p, Status error) : m_pid(p), m_error(error) {} -CoreSimulatorSupport::DeviceType::DeviceType() - : m_dev(nil), m_model_identifier() {} +CoreSimulatorSupport::DeviceType::DeviceType() : m_model_identifier() {} CoreSimulatorSupport::DeviceType::DeviceType(id d) : m_dev(d), m_model_identifier() {} @@ -87,8 +86,7 @@ CoreSimulatorSupport::DeviceType::GetProductFamilyID() { return ProductFamilyID([m_dev productFamilyID]); } -CoreSimulatorSupport::DeviceRuntime::DeviceRuntime() - : m_dev(nil), m_os_version() {} +CoreSimulatorSupport::DeviceRuntime::DeviceRuntime() : m_os_version() {} CoreSimulatorSupport::DeviceRuntime::DeviceRuntime(id d) : m_dev(d), m_os_version() {} @@ -99,8 +97,7 @@ bool CoreSimulatorSupport::DeviceRuntime::IsAvailable() { return [m_dev available]; } -CoreSimulatorSupport::Device::Device() - : m_dev(nil), m_dev_type(), m_dev_runtime() {} +CoreSimulatorSupport::Device::Device() : m_dev_type(), m_dev_runtime() {} CoreSimulatorSupport::Device::Device(id d) : m_dev(d), m_dev_type(), m_dev_runtime() {} @@ -407,25 +404,19 @@ static Status HandleFileAction(ProcessLaunchInfo &launch_info, const int master_fd = launch_info.GetPTY().GetPrimaryFileDescriptor(); if (master_fd != PseudoTerminal::invalid_fd) { // Check in case our file action open wants to open the secondary - const char *secondary_path = - launch_info.GetPTY().GetSecondaryName(NULL, 0); - if (secondary_path) { - FileSpec secondary_spec(secondary_path); - if (file_spec == secondary_spec) { - int secondary_fd = - launch_info.GetPTY().GetSecondaryFileDescriptor(); - if (secondary_fd == PseudoTerminal::invalid_fd) - secondary_fd = - launch_info.GetPTY().OpenSecondary(O_RDWR, nullptr, 0); - if (secondary_fd == PseudoTerminal::invalid_fd) { - error.SetErrorStringWithFormat( - "unable to open secondary pty '%s'", secondary_path); - return error; // Failure - } - [options setValue:[NSNumber numberWithInteger:secondary_fd] - forKey:key]; - return error; // Success + FileSpec secondary_spec(launch_info.GetPTY().GetSecondaryName()); + if (file_spec == secondary_spec) { + int secondary_fd = + launch_info.GetPTY().GetSecondaryFileDescriptor(); + if (secondary_fd == PseudoTerminal::invalid_fd) { + if (llvm::Error Err = launch_info.GetPTY().OpenSecondary(O_RDWR)) + return Status(std::move(Err)); } + secondary_fd = launch_info.GetPTY().GetSecondaryFileDescriptor(); + assert(secondary_fd != PseudoTerminal::invalid_fd); + [options setValue:[NSNumber numberWithInteger:secondary_fd] + forKey:key]; + return error; // Success } } Status posix_error; diff --git a/gnu/llvm/lldb/source/Plugins/Platform/NetBSD/PlatformNetBSD.cpp b/gnu/llvm/lldb/source/Plugins/Platform/NetBSD/PlatformNetBSD.cpp index caebd79c853..e3682b44e14 100644 --- a/gnu/llvm/lldb/source/Plugins/Platform/NetBSD/PlatformNetBSD.cpp +++ b/gnu/llvm/lldb/source/Plugins/Platform/NetBSD/PlatformNetBSD.cpp @@ -9,7 +9,7 @@ #include "PlatformNetBSD.h" #include "lldb/Host/Config.h" -#include +#include #if LLDB_ENABLE_POSIX #include #endif @@ -117,8 +117,6 @@ PlatformNetBSD::PlatformNetBSD(bool is_host) : PlatformPOSIX(is_host) // This is the local host platform {} -PlatformNetBSD::~PlatformNetBSD() = default; - bool PlatformNetBSD::GetSupportedArchitectureAtIndex(uint32_t idx, ArchSpec &arch) { if (IsHost()) { @@ -187,9 +185,9 @@ void PlatformNetBSD::GetStatus(Stream &strm) { #endif } -int32_t +uint32_t PlatformNetBSD::GetResumeCountForLaunchInfo(ProcessLaunchInfo &launch_info) { - int32_t resume_count = 0; + uint32_t resume_count = 0; // Always resume past the initial stop when we use eLaunchFlagDebug if (launch_info.GetFlags().Test(eLaunchFlagDebug)) { @@ -231,121 +229,6 @@ bool PlatformNetBSD::CanDebugProcess() { } } -// For local debugging, NetBSD will override the debug logic to use llgs-launch -// rather than lldb-launch, llgs-attach. This differs from current lldb- -// launch, debugserver-attach approach on MacOSX. -lldb::ProcessSP -PlatformNetBSD::DebugProcess(ProcessLaunchInfo &launch_info, Debugger &debugger, - Target *target, // Can be NULL, if NULL create a new - // target, else use existing one - Status &error) { - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM)); - LLDB_LOG(log, "target {0}", target); - - // If we're a remote host, use standard behavior from parent class. - if (!IsHost()) - return PlatformPOSIX::DebugProcess(launch_info, debugger, target, error); - - // - // For local debugging, we'll insist on having ProcessGDBRemote create the - // process. - // - - ProcessSP process_sp; - - // Make sure we stop at the entry point - launch_info.GetFlags().Set(eLaunchFlagDebug); - - // We always launch the process we are going to debug in a separate process - // group, since then we can handle ^C interrupts ourselves w/o having to - // worry about the target getting them as well. - launch_info.SetLaunchInSeparateProcessGroup(true); - - // Ensure we have a target. - if (target == nullptr) { - LLDB_LOG(log, "creating new target"); - TargetSP new_target_sp; - error = debugger.GetTargetList().CreateTarget( - debugger, "", "", eLoadDependentsNo, nullptr, new_target_sp); - if (error.Fail()) { - LLDB_LOG(log, "failed to create new target: {0}", error); - return process_sp; - } - - target = new_target_sp.get(); - if (!target) { - error.SetErrorString("CreateTarget() returned nullptr"); - LLDB_LOG(log, "error: {0}", error); - return process_sp; - } - } - - // Mark target as currently selected target. - debugger.GetTargetList().SetSelectedTarget(target); - - // Now create the gdb-remote process. - LLDB_LOG(log, "having target create process with gdb-remote plugin"); - process_sp = - target->CreateProcess(launch_info.GetListener(), "gdb-remote", nullptr); - - if (!process_sp) { - error.SetErrorString("CreateProcess() failed for gdb-remote process"); - LLDB_LOG(log, "error: {0}", error); - return process_sp; - } - - LLDB_LOG(log, "successfully created process"); - // Adjust launch for a hijacker. - ListenerSP listener_sp; - if (!launch_info.GetHijackListener()) { - LLDB_LOG(log, "setting up hijacker"); - listener_sp = - Listener::MakeListener("lldb.PlatformNetBSD.DebugProcess.hijack"); - launch_info.SetHijackListener(listener_sp); - process_sp->HijackProcessEvents(listener_sp); - } - - // Log file actions. - if (log) { - LLDB_LOG(log, "launching process with the following file actions:"); - StreamString stream; - size_t i = 0; - const FileAction *file_action; - while ((file_action = launch_info.GetFileActionAtIndex(i++)) != nullptr) { - file_action->Dump(stream); - LLDB_LOG(log, "{0}", stream.GetData()); - stream.Clear(); - } - } - - // Do the launch. - error = process_sp->Launch(launch_info); - if (error.Success()) { - // Handle the hijacking of process events. - if (listener_sp) { - const StateType state = process_sp->WaitForProcessToStop( - llvm::None, nullptr, false, listener_sp); - - LLDB_LOG(log, "pid {0} state {0}", process_sp->GetID(), state); - } - - // Hook up process PTY if we have one (which we should for local debugging - // with llgs). - int pty_fd = launch_info.GetPTY().ReleasePrimaryFileDescriptor(); - if (pty_fd != PseudoTerminal::invalid_fd) { - process_sp->SetSTDIOFileDescriptor(pty_fd); - LLDB_LOG(log, "hooked up STDIO pty to process"); - } else - LLDB_LOG(log, "not using process STDIO pty"); - } else { - LLDB_LOG(log, "{0}", error); - // FIXME figure out appropriate cleanup here. Do we delete the target? Do - // we delete the process? Does our caller do that? - } - - return process_sp; -} - void PlatformNetBSD::CalculateTrapHandlerSymbolNames() { m_trap_handlers.push_back(ConstString("_sigtramp")); } diff --git a/gnu/llvm/lldb/source/Plugins/Platform/NetBSD/PlatformNetBSD.h b/gnu/llvm/lldb/source/Plugins/Platform/NetBSD/PlatformNetBSD.h index d53e5841888..e664f518112 100644 --- a/gnu/llvm/lldb/source/Plugins/Platform/NetBSD/PlatformNetBSD.h +++ b/gnu/llvm/lldb/source/Plugins/Platform/NetBSD/PlatformNetBSD.h @@ -18,8 +18,6 @@ class PlatformNetBSD : public PlatformPOSIX { public: PlatformNetBSD(bool is_host); - ~PlatformNetBSD() override; - static void Initialize(); static void Terminate(); @@ -44,24 +42,16 @@ public: bool GetSupportedArchitectureAtIndex(uint32_t idx, ArchSpec &arch) override; - int32_t GetResumeCountForLaunchInfo(ProcessLaunchInfo &launch_info) override; + uint32_t GetResumeCountForLaunchInfo(ProcessLaunchInfo &launch_info) override; bool CanDebugProcess() override; - lldb::ProcessSP DebugProcess(ProcessLaunchInfo &launch_info, - Debugger &debugger, Target *target, - Status &error) override; - void CalculateTrapHandlerSymbolNames() override; MmapArgList GetMmapArgumentList(const ArchSpec &arch, lldb::addr_t addr, lldb::addr_t length, unsigned prot, unsigned flags, lldb::addr_t fd, lldb::addr_t offset) override; - -private: - PlatformNetBSD(const PlatformNetBSD &) = delete; - const PlatformNetBSD &operator=(const PlatformNetBSD &) = delete; }; } // namespace platform_netbsd diff --git a/gnu/llvm/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp b/gnu/llvm/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp index 180ea1d2cfd..7353132cd96 100644 --- a/gnu/llvm/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp +++ b/gnu/llvm/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp @@ -46,7 +46,7 @@ PlatformPOSIX::PlatformPOSIX(bool is_host) /// /// The destructor is virtual since this class is designed to be /// inherited from by the plug-in instance. -PlatformPOSIX::~PlatformPOSIX() {} +PlatformPOSIX::~PlatformPOSIX() = default; lldb_private::OptionGroupOptions *PlatformPOSIX::GetConnectionOptions( lldb_private::CommandInterpreter &interpreter) { @@ -377,7 +377,6 @@ lldb::ProcessSP PlatformPOSIX::Attach(ProcessAttachInfo &attach_info, } if (target && error.Success()) { - debugger.GetTargetList().SetSelectedTarget(target); if (log) { ModuleSP exe_module_sp = target->GetExecutableModule(); LLDB_LOGF(log, "PlatformPOSIX::%s set selected target to %p %s", @@ -388,7 +387,7 @@ lldb::ProcessSP PlatformPOSIX::Attach(ProcessAttachInfo &attach_info, process_sp = target->CreateProcess(attach_info.GetListenerForProcess(debugger), - attach_info.GetProcessPluginName(), nullptr); + "gdb-remote", nullptr, true); if (process_sp) { ListenerSP listener_sp = attach_info.GetHijackListener(); @@ -416,24 +415,113 @@ PlatformPOSIX::DebugProcess(ProcessLaunchInfo &launch_info, Debugger &debugger, Target *target, // Can be NULL, if NULL create a new // target, else use existing one Status &error) { + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM)); + LLDB_LOG(log, "target {0}", target); + ProcessSP process_sp; - if (IsHost()) { - // We are going to hand this process off to debugserver which will be in - // charge of setting the exit status. However, we still need to reap it - // from lldb. So, make sure we use a exit callback which does not set exit - // status. - const bool monitor_signals = false; - launch_info.SetMonitorProcessCallback( - &ProcessLaunchInfo::NoOpMonitorCallback, monitor_signals); - process_sp = Platform::DebugProcess(launch_info, debugger, target, error); - } else { + if (!IsHost()) { if (m_remote_platform_sp) process_sp = m_remote_platform_sp->DebugProcess(launch_info, debugger, target, error); else error.SetErrorString("the platform is not currently connected"); + return process_sp; + } + + // + // For local debugging, we'll insist on having ProcessGDBRemote create the + // process. + // + + // Make sure we stop at the entry point + launch_info.GetFlags().Set(eLaunchFlagDebug); + + // We always launch the process we are going to debug in a separate process + // group, since then we can handle ^C interrupts ourselves w/o having to + // worry about the target getting them as well. + launch_info.SetLaunchInSeparateProcessGroup(true); + + // Ensure we have a target. + if (target == nullptr) { + LLDB_LOG(log, "creating new target"); + TargetSP new_target_sp; + error = debugger.GetTargetList().CreateTarget( + debugger, "", "", eLoadDependentsNo, nullptr, new_target_sp); + if (error.Fail()) { + LLDB_LOG(log, "failed to create new target: {0}", error); + return process_sp; + } + + target = new_target_sp.get(); + if (!target) { + error.SetErrorString("CreateTarget() returned nullptr"); + LLDB_LOG(log, "error: {0}", error); + return process_sp; + } + } + + // Now create the gdb-remote process. + LLDB_LOG(log, "having target create process with gdb-remote plugin"); + process_sp = + target->CreateProcess(launch_info.GetListener(), "gdb-remote", nullptr, + true); + + if (!process_sp) { + error.SetErrorString("CreateProcess() failed for gdb-remote process"); + LLDB_LOG(log, "error: {0}", error); + return process_sp; + } + + LLDB_LOG(log, "successfully created process"); + // Adjust launch for a hijacker. + ListenerSP listener_sp; + if (!launch_info.GetHijackListener()) { + LLDB_LOG(log, "setting up hijacker"); + listener_sp = + Listener::MakeListener("lldb.PlatformLinux.DebugProcess.hijack"); + launch_info.SetHijackListener(listener_sp); + process_sp->HijackProcessEvents(listener_sp); + } + + // Log file actions. + if (log) { + LLDB_LOG(log, "launching process with the following file actions:"); + StreamString stream; + size_t i = 0; + const FileAction *file_action; + while ((file_action = launch_info.GetFileActionAtIndex(i++)) != nullptr) { + file_action->Dump(stream); + LLDB_LOG(log, "{0}", stream.GetData()); + stream.Clear(); + } } + + // Do the launch. + error = process_sp->Launch(launch_info); + if (error.Success()) { + // Handle the hijacking of process events. + if (listener_sp) { + const StateType state = process_sp->WaitForProcessToStop( + llvm::None, nullptr, false, listener_sp); + + LLDB_LOG(log, "pid {0} state {0}", process_sp->GetID(), state); + } + + // Hook up process PTY if we have one (which we should for local debugging + // with llgs). + int pty_fd = launch_info.GetPTY().ReleasePrimaryFileDescriptor(); + if (pty_fd != PseudoTerminal::invalid_fd) { + process_sp->SetSTDIOFileDescriptor(pty_fd); + LLDB_LOG(log, "hooked up STDIO pty to process"); + } else + LLDB_LOG(log, "not using process STDIO pty"); + } else { + LLDB_LOG(log, "{0}", error); + // FIXME figure out appropriate cleanup here. Do we delete the target? Do + // we delete the process? Does our caller do that? + } + return process_sp; } @@ -490,7 +578,19 @@ PlatformPOSIX::MakeLoadImageUtilityFunction(ExecutionContext &exe_ctx, // __lldb_dlopen_result for consistency. The wrapper returns a void * but // doesn't use it because UtilityFunctions don't work with void returns at // present. + // + // Use lazy binding so as to not make dlopen()'s success conditional on + // forcing every symbol in the library. + // + // In general, the debugger should allow programs to load & run with + // libraries as far as they can, instead of defaulting to being super-picky + // about unavailable symbols. + // + // The value "1" appears to imply lazy binding (RTLD_LAZY) on both Darwin + // and other POSIX OSes. static const char *dlopen_wrapper_code = R"( + const int RTLD_LAZY = 1; + struct __lldb_dlopen_result { void *image_ptr; const char *error_str; @@ -507,7 +607,7 @@ PlatformPOSIX::MakeLoadImageUtilityFunction(ExecutionContext &exe_ctx, { // This is the case where the name is the full path: if (!path_strings) { - result_ptr->image_ptr = dlopen(name, 2); + result_ptr->image_ptr = dlopen(name, RTLD_LAZY); if (result_ptr->image_ptr) result_ptr->error_str = nullptr; return nullptr; @@ -521,7 +621,7 @@ PlatformPOSIX::MakeLoadImageUtilityFunction(ExecutionContext &exe_ctx, buffer[path_len] = '/'; char *target_ptr = buffer+path_len+1; memcpy((void *) target_ptr, (void *) name, name_len + 1); - result_ptr->image_ptr = dlopen(buffer, 2); + result_ptr->image_ptr = dlopen(buffer, RTLD_LAZY); if (result_ptr->image_ptr) { result_ptr->error_str = nullptr; break; @@ -540,30 +640,26 @@ PlatformPOSIX::MakeLoadImageUtilityFunction(ExecutionContext &exe_ctx, expr.append(dlopen_wrapper_code); Status utility_error; DiagnosticManager diagnostics; - - std::unique_ptr dlopen_utility_func_up(process - ->GetTarget().GetUtilityFunctionForLanguage(expr.c_str(), - eLanguageTypeObjC, - dlopen_wrapper_name, - utility_error)); - if (utility_error.Fail()) { - error.SetErrorStringWithFormat("dlopen error: could not make utility" - "function: %s", utility_error.AsCString()); - return nullptr; - } - if (!dlopen_utility_func_up->Install(diagnostics, exe_ctx)) { - error.SetErrorStringWithFormat("dlopen error: could not install utility" - "function: %s", - diagnostics.GetString().c_str()); + + auto utility_fn_or_error = process->GetTarget().CreateUtilityFunction( + std::move(expr), dlopen_wrapper_name, eLanguageTypeObjC, exe_ctx); + if (!utility_fn_or_error) { + std::string error_str = llvm::toString(utility_fn_or_error.takeError()); + error.SetErrorStringWithFormat("dlopen error: could not create utility" + "function: %s", + error_str.c_str()); return nullptr; } + std::unique_ptr dlopen_utility_func_up = + std::move(*utility_fn_or_error); Value value; ValueList arguments; FunctionCaller *do_dlopen_function = nullptr; // Fetch the clang types we will need: - TypeSystemClang *ast = TypeSystemClang::GetScratch(process->GetTarget()); + TypeSystemClang *ast = + ScratchTypeSystemClang::GetForTarget(process->GetTarget()); if (!ast) return nullptr; @@ -575,7 +671,7 @@ PlatformPOSIX::MakeLoadImageUtilityFunction(ExecutionContext &exe_ctx, // We are passing four arguments, the basename, the list of places to look, // a buffer big enough for all the path + name combos, and // a pointer to the storage we've made for the result: - value.SetValueType(Value::eValueTypeScalar); + value.SetValueType(Value::ValueType::Scalar); value.SetCompilerType(clang_void_pointer_type); arguments.PushValue(value); value.SetCompilerType(clang_char_pointer_type); @@ -807,7 +903,8 @@ uint32_t PlatformPOSIX::DoLoadImage(lldb_private::Process *process, Value return_value; // Fetch the clang types we will need: - TypeSystemClang *ast = TypeSystemClang::GetScratch(process->GetTarget()); + TypeSystemClang *ast = + ScratchTypeSystemClang::GetForTarget(process->GetTarget()); if (!ast) { error.SetErrorString("dlopen error: Unable to get TypeSystemClang"); return LLDB_INVALID_IMAGE_TOKEN; @@ -909,13 +1006,6 @@ PlatformPOSIX::GetLibdlFunctionDeclarations(lldb_private::Process *process) { )"; } -size_t PlatformPOSIX::ConnectToWaitingProcesses(Debugger &debugger, - Status &error) { - if (m_remote_platform_sp) - return m_remote_platform_sp->ConnectToWaitingProcesses(debugger, error); - return Platform::ConnectToWaitingProcesses(debugger, error); -} - ConstString PlatformPOSIX::GetFullNameForDylib(ConstString basename) { if (basename.IsEmpty()) return basename; diff --git a/gnu/llvm/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.h b/gnu/llvm/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.h index 72c54f4147c..1cba4c5eb2e 100644 --- a/gnu/llvm/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.h +++ b/gnu/llvm/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.h @@ -71,9 +71,6 @@ public: lldb_private::Status UnloadImage(lldb_private::Process *process, uint32_t image_token) override; - size_t ConnectToWaitingProcesses(lldb_private::Debugger &debugger, - lldb_private::Status &error) override; - lldb_private::ConstString GetFullNameForDylib(lldb_private::ConstString basename) override; protected: diff --git a/gnu/llvm/lldb/source/Plugins/Platform/Windows/PlatformWindows.cpp b/gnu/llvm/lldb/source/Plugins/Platform/Windows/PlatformWindows.cpp index f7f5cf16619..fd28eec6380 100644 --- a/gnu/llvm/lldb/source/Plugins/Platform/Windows/PlatformWindows.cpp +++ b/gnu/llvm/lldb/source/Plugins/Platform/Windows/PlatformWindows.cpp @@ -8,7 +8,7 @@ #include "PlatformWindows.h" -#include +#include #if defined(_WIN32) #include "lldb/Host/windows/windows.h" #include @@ -151,12 +151,6 @@ void PlatformWindows::Terminate() { /// Default Constructor PlatformWindows::PlatformWindows(bool is_host) : RemoteAwarePlatform(is_host) {} -/// Destructor. -/// -/// The destructor is virtual since this class is designed to be -/// inherited from by the plug-in instance. -PlatformWindows::~PlatformWindows() = default; - Status PlatformWindows::ConnectRemote(Args &args) { Status error; if (IsHost()) { @@ -239,7 +233,8 @@ ProcessSP PlatformWindows::DebugProcess(ProcessLaunchInfo &launch_info, return Attach(attach_info, debugger, target, error); } else { ProcessSP process_sp = target->CreateProcess( - launch_info.GetListener(), launch_info.GetProcessPluginName(), nullptr); + launch_info.GetListener(), launch_info.GetProcessPluginName(), nullptr, + false); // We need to launch and attach to the process. launch_info.GetFlags().Set(eLaunchFlagDebug); @@ -277,11 +272,9 @@ lldb::ProcessSP PlatformWindows::Attach(ProcessAttachInfo &attach_info, if (!target || error.Fail()) return process_sp; - debugger.GetTargetList().SetSelectedTarget(target); - const char *plugin_name = attach_info.GetProcessPluginName(); process_sp = target->CreateProcess( - attach_info.GetListenerForProcess(debugger), plugin_name, nullptr); + attach_info.GetListenerForProcess(debugger), plugin_name, nullptr, false); process_sp->HijackProcessEvents(attach_info.GetHijackListener()); if (process_sp) diff --git a/gnu/llvm/lldb/source/Plugins/Platform/Windows/PlatformWindows.h b/gnu/llvm/lldb/source/Plugins/Platform/Windows/PlatformWindows.h index d8b2cd8a26a..e45a0e98d02 100644 --- a/gnu/llvm/lldb/source/Plugins/Platform/Windows/PlatformWindows.h +++ b/gnu/llvm/lldb/source/Plugins/Platform/Windows/PlatformWindows.h @@ -17,8 +17,6 @@ class PlatformWindows : public RemoteAwarePlatform { public: PlatformWindows(bool is_host); - ~PlatformWindows() override; - static void Initialize(); static void Terminate(); @@ -65,10 +63,6 @@ public: void CalculateTrapHandlerSymbolNames() override {} ConstString GetFullNameForDylib(ConstString basename) override; - -private: - PlatformWindows(const PlatformWindows &) = delete; - const PlatformWindows &operator=(const PlatformWindows &) = delete; }; } // namespace lldb_private diff --git a/gnu/llvm/lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp b/gnu/llvm/lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp index 21bf7f4ac46..528208665a4 100644 --- a/gnu/llvm/lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp +++ b/gnu/llvm/lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp @@ -30,6 +30,7 @@ #include "lldb/Utility/UriParser.h" #include "Plugins/Process/Utility/GDBRemoteSignals.h" +#include "Plugins/Process/gdb-remote/ProcessGDBRemote.h" using namespace lldb; using namespace lldb_private; @@ -202,13 +203,16 @@ Status PlatformRemoteGDBServer::GetFileWithUUID(const FileSpec &platform_file, /// Default Constructor PlatformRemoteGDBServer::PlatformRemoteGDBServer() : Platform(false), // This is a remote platform - m_gdb_client() {} + m_gdb_client() { + m_gdb_client.SetPacketTimeout( + process_gdb_remote::ProcessGDBRemote::GetPacketTimeout()); +} /// Destructor. /// /// The destructor is virtual since this class is designed to be /// inherited from by the plug-in instance. -PlatformRemoteGDBServer::~PlatformRemoteGDBServer() {} +PlatformRemoteGDBServer::~PlatformRemoteGDBServer() = default; bool PlatformRemoteGDBServer::GetSupportedArchitectureAtIndex(uint32_t idx, ArchSpec &arch) { @@ -495,12 +499,10 @@ lldb::ProcessSP PlatformRemoteGDBServer::DebugProcess( error.Clear(); if (target && error.Success()) { - debugger.GetTargetList().SetSelectedTarget(target); - // The darwin always currently uses the GDB remote debugger plug-in // so even when debugging locally we are debugging remotely! process_sp = target->CreateProcess(launch_info.GetListener(), - "gdb-remote", nullptr); + "gdb-remote", nullptr, true); if (process_sp) { error = process_sp->ConnectRemote(connect_url.c_str()); @@ -581,13 +583,11 @@ lldb::ProcessSP PlatformRemoteGDBServer::Attach( error.Clear(); if (target && error.Success()) { - debugger.GetTargetList().SetSelectedTarget(target); - // The darwin always currently uses the GDB remote debugger plug-in // so even when debugging locally we are debugging remotely! process_sp = target->CreateProcess(attach_info.GetListenerForProcess(debugger), - "gdb-remote", nullptr); + "gdb-remote", nullptr, true); if (process_sp) { error = process_sp->ConnectRemote(connect_url.c_str()); if (error.Success()) { @@ -661,6 +661,11 @@ PlatformRemoteGDBServer::GetFileSize(const FileSpec &file_spec) { return m_gdb_client.GetFileSize(file_spec); } +void PlatformRemoteGDBServer::AutoCompleteDiskFileOrDirectory( + CompletionRequest &request, bool only_dir) { + m_gdb_client.AutoCompleteDiskFileOrDirectory(request, only_dir); +} + uint64_t PlatformRemoteGDBServer::ReadFile(lldb::user_id_t fd, uint64_t offset, void *dst, uint64_t dst_len, Status &error) { @@ -706,7 +711,7 @@ bool PlatformRemoteGDBServer::GetFileExists(const FileSpec &file_spec) { } Status PlatformRemoteGDBServer::RunShellCommand( - const char *command, // Shouldn't be NULL + llvm::StringRef shell, llvm::StringRef command, const FileSpec & working_dir, // Pass empty FileSpec to use the current working directory int *status_ptr, // Pass NULL if you don't want the process exit status @@ -735,8 +740,8 @@ const UnixSignalsSP &PlatformRemoteGDBServer::GetRemoteUnixSignals() { m_remote_signals_sp = UnixSignals::Create(GetRemoteSystemArchitecture()); StringExtractorGDBRemote response; - auto result = m_gdb_client.SendPacketAndWaitForResponse("jSignalsInfo", - response, false); + auto result = + m_gdb_client.SendPacketAndWaitForResponse("jSignalsInfo", response); if (result != decltype(result)::Success || response.GetResponseType() != response.eResponse) @@ -824,7 +829,7 @@ std::string PlatformRemoteGDBServer::MakeUrl(const char *scheme, const char *hostname, uint16_t port, const char *path) { StreamString result; - result.Printf("%s://%s", scheme, hostname); + result.Printf("%s://[%s]", scheme, hostname); if (port != 0) result.Printf(":%u", port); if (path) @@ -832,25 +837,13 @@ std::string PlatformRemoteGDBServer::MakeUrl(const char *scheme, return std::string(result.GetString()); } -lldb::ProcessSP PlatformRemoteGDBServer::ConnectProcess( - llvm::StringRef connect_url, llvm::StringRef plugin_name, - lldb_private::Debugger &debugger, lldb_private::Target *target, - lldb_private::Status &error) { - if (!IsRemote() || !IsConnected()) { - error.SetErrorString("Not connected to remote gdb server"); - return nullptr; - } - return Platform::ConnectProcess(connect_url, plugin_name, debugger, target, - error); -} - size_t PlatformRemoteGDBServer::ConnectToWaitingProcesses(Debugger &debugger, Status &error) { std::vector connection_urls; GetPendingGdbServerList(connection_urls); for (size_t i = 0; i < connection_urls.size(); ++i) { - ConnectProcess(connection_urls[i].c_str(), "", debugger, nullptr, error); + ConnectProcess(connection_urls[i].c_str(), "gdb-remote", debugger, nullptr, error); if (error.Fail()) return i; // We already connected to i process succsessfully } diff --git a/gnu/llvm/lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h b/gnu/llvm/lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h index 0602be1fa37..e43cd0e55c6 100644 --- a/gnu/llvm/lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h +++ b/gnu/llvm/lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h @@ -127,6 +127,9 @@ public: lldb::user_id_t GetFileSize(const FileSpec &file_spec) override; + void AutoCompleteDiskFileOrDirectory(CompletionRequest &request, + bool only_dir) override; + Status PutFile(const FileSpec &source, const FileSpec &destination, uint32_t uid = UINT32_MAX, uint32_t gid = UINT32_MAX) override; @@ -137,7 +140,7 @@ public: Status Unlink(const FileSpec &path) override; Status RunShellCommand( - const char *command, // Shouldn't be NULL + llvm::StringRef shell, llvm::StringRef command, const FileSpec &working_dir, // Pass empty FileSpec to use the current // working directory int *status_ptr, // Pass NULL if you don't want the process exit status @@ -151,12 +154,6 @@ public: const lldb::UnixSignalsSP &GetRemoteUnixSignals() override; - lldb::ProcessSP ConnectProcess(llvm::StringRef connect_url, - llvm::StringRef plugin_name, - lldb_private::Debugger &debugger, - lldb_private::Target *target, - lldb_private::Status &error) override; - size_t ConnectToWaitingProcesses(lldb_private::Debugger &debugger, lldb_private::Status &error) override; diff --git a/gnu/llvm/lldb/source/Plugins/Process/FreeBSD/CMakeLists.txt b/gnu/llvm/lldb/source/Plugins/Process/FreeBSD/CMakeLists.txt index c8301f350e0..598911ce8c9 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/FreeBSD/CMakeLists.txt +++ b/gnu/llvm/lldb/source/Plugins/Process/FreeBSD/CMakeLists.txt @@ -1,24 +1,20 @@ -add_lldb_library(lldbPluginProcessFreeBSD PLUGIN - ProcessFreeBSD.cpp - FreeBSDThread.cpp - ProcessMonitor.cpp - - POSIXStopInfo.cpp - RegisterContextPOSIXProcessMonitor_arm.cpp - RegisterContextPOSIXProcessMonitor_arm64.cpp - RegisterContextPOSIXProcessMonitor_powerpc.cpp - RegisterContextPOSIXProcessMonitor_x86.cpp - RegisterContextPOSIXProcessMonitor_mips64.cpp +add_lldb_library(lldbPluginProcessFreeBSD + NativeProcessFreeBSD.cpp + NativeRegisterContextFreeBSD.cpp + NativeRegisterContextFreeBSD_arm.cpp + NativeRegisterContextFreeBSD_arm64.cpp + NativeRegisterContextFreeBSD_mips64.cpp + NativeRegisterContextFreeBSD_powerpc.cpp + NativeRegisterContextFreeBSD_x86_64.cpp + NativeThreadFreeBSD.cpp LINK_LIBS - lldbBreakpoint - lldbCore lldbHost lldbSymbol lldbTarget lldbUtility - lldbPluginProcessUtility lldbPluginProcessPOSIX + lldbPluginProcessUtility LINK_COMPONENTS Support ) diff --git a/gnu/llvm/lldb/source/Plugins/Process/FreeBSD/NativeProcessFreeBSD.cpp b/gnu/llvm/lldb/source/Plugins/Process/FreeBSD/NativeProcessFreeBSD.cpp new file mode 100644 index 00000000000..d6426b3d236 --- /dev/null +++ b/gnu/llvm/lldb/source/Plugins/Process/FreeBSD/NativeProcessFreeBSD.cpp @@ -0,0 +1,1011 @@ +//===-- NativeProcessFreeBSD.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 "NativeProcessFreeBSD.h" + +// clang-format off +#include +#include +#include +#include +#include +#include +// clang-format on + +#include "Plugins/Process/POSIX/ProcessPOSIXLog.h" +#include "lldb/Host/HostProcess.h" +#include "lldb/Host/posix/ProcessLauncherPosixFork.h" +#include "lldb/Target/Process.h" +#include "lldb/Utility/State.h" +#include "llvm/Support/Errno.h" + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::process_freebsd; +using namespace llvm; + +// Simple helper function to ensure flags are enabled on the given file +// descriptor. +static Status EnsureFDFlags(int fd, int flags) { + Status error; + + int status = fcntl(fd, F_GETFL); + if (status == -1) { + error.SetErrorToErrno(); + return error; + } + + if (fcntl(fd, F_SETFL, status | flags) == -1) { + error.SetErrorToErrno(); + return error; + } + + return error; +} + +// Public Static Methods + +llvm::Expected> +NativeProcessFreeBSD::Factory::Launch(ProcessLaunchInfo &launch_info, + NativeDelegate &native_delegate, + MainLoop &mainloop) const { + Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); + + Status status; + ::pid_t pid = ProcessLauncherPosixFork() + .LaunchProcess(launch_info, status) + .GetProcessId(); + LLDB_LOG(log, "pid = {0:x}", pid); + if (status.Fail()) { + LLDB_LOG(log, "failed to launch process: {0}", status); + return status.ToError(); + } + + // Wait for the child process to trap on its call to execve. + int wstatus; + ::pid_t wpid = llvm::sys::RetryAfterSignal(-1, ::waitpid, pid, &wstatus, 0); + assert(wpid == pid); + (void)wpid; + if (!WIFSTOPPED(wstatus)) { + LLDB_LOG(log, "Could not sync with inferior process: wstatus={1}", + WaitStatus::Decode(wstatus)); + return llvm::make_error("Could not sync with inferior process", + llvm::inconvertibleErrorCode()); + } + LLDB_LOG(log, "inferior started, now in stopped state"); + + ProcessInstanceInfo Info; + if (!Host::GetProcessInfo(pid, Info)) { + return llvm::make_error("Cannot get process architecture", + llvm::inconvertibleErrorCode()); + } + + // Set the architecture to the exe architecture. + LLDB_LOG(log, "pid = {0:x}, detected architecture {1}", pid, + Info.GetArchitecture().GetArchitectureName()); + + std::unique_ptr process_up(new NativeProcessFreeBSD( + pid, launch_info.GetPTY().ReleasePrimaryFileDescriptor(), native_delegate, + Info.GetArchitecture(), mainloop)); + + status = process_up->SetupTrace(); + if (status.Fail()) + return status.ToError(); + + for (const auto &thread : process_up->m_threads) + static_cast(*thread).SetStoppedBySignal(SIGSTOP); + process_up->SetState(StateType::eStateStopped, false); + + return std::move(process_up); +} + +llvm::Expected> +NativeProcessFreeBSD::Factory::Attach( + lldb::pid_t pid, NativeProcessProtocol::NativeDelegate &native_delegate, + MainLoop &mainloop) const { + Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); + LLDB_LOG(log, "pid = {0:x}", pid); + + // Retrieve the architecture for the running process. + ProcessInstanceInfo Info; + if (!Host::GetProcessInfo(pid, Info)) { + return llvm::make_error("Cannot get process architecture", + llvm::inconvertibleErrorCode()); + } + + std::unique_ptr process_up(new NativeProcessFreeBSD( + pid, -1, native_delegate, Info.GetArchitecture(), mainloop)); + + Status status = process_up->Attach(); + if (!status.Success()) + return status.ToError(); + + return std::move(process_up); +} + +NativeProcessFreeBSD::Extension +NativeProcessFreeBSD::Factory::GetSupportedExtensions() const { + return Extension::multiprocess | Extension::fork | Extension::vfork | + Extension::pass_signals | Extension::auxv | Extension::libraries_svr4; +} + +// Public Instance Methods + +NativeProcessFreeBSD::NativeProcessFreeBSD(::pid_t pid, int terminal_fd, + NativeDelegate &delegate, + const ArchSpec &arch, + MainLoop &mainloop) + : NativeProcessELF(pid, terminal_fd, delegate), m_arch(arch), + m_main_loop(mainloop) { + if (m_terminal_fd != -1) { + Status status = EnsureFDFlags(m_terminal_fd, O_NONBLOCK); + assert(status.Success()); + } + + Status status; + m_sigchld_handle = mainloop.RegisterSignal( + SIGCHLD, [this](MainLoopBase &) { SigchldHandler(); }, status); + assert(m_sigchld_handle && status.Success()); +} + +// Handles all waitpid events from the inferior process. +void NativeProcessFreeBSD::MonitorCallback(lldb::pid_t pid, int signal) { + switch (signal) { + case SIGTRAP: + return MonitorSIGTRAP(pid); + case SIGSTOP: + return MonitorSIGSTOP(pid); + default: + return MonitorSignal(pid, signal); + } +} + +void NativeProcessFreeBSD::MonitorExited(lldb::pid_t pid, WaitStatus status) { + Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); + + LLDB_LOG(log, "got exit signal({0}) , pid = {1}", status, pid); + + /* Stop Tracking All Threads attached to Process */ + m_threads.clear(); + + SetExitStatus(status, true); + + // Notify delegate that our process has exited. + SetState(StateType::eStateExited, true); +} + +void NativeProcessFreeBSD::MonitorSIGSTOP(lldb::pid_t pid) { + /* Stop all Threads attached to Process */ + for (const auto &thread : m_threads) { + static_cast(*thread).SetStoppedBySignal(SIGSTOP, + nullptr); + } + SetState(StateType::eStateStopped, true); +} + +void NativeProcessFreeBSD::MonitorSIGTRAP(lldb::pid_t pid) { + Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); + struct ptrace_lwpinfo info; + + const auto siginfo_err = PtraceWrapper(PT_LWPINFO, pid, &info, sizeof(info)); + if (siginfo_err.Fail()) { + LLDB_LOG(log, "PT_LWPINFO failed {0}", siginfo_err); + return; + } + assert(info.pl_event == PL_EVENT_SIGNAL); + + LLDB_LOG(log, "got SIGTRAP, pid = {0}, lwpid = {1}, flags = {2:x}", pid, + info.pl_lwpid, info.pl_flags); + NativeThreadFreeBSD *thread = nullptr; + + if (info.pl_flags & (PL_FLAG_BORN | PL_FLAG_EXITED)) { + if (info.pl_flags & PL_FLAG_BORN) { + LLDB_LOG(log, "monitoring new thread, tid = {0}", info.pl_lwpid); + NativeThreadFreeBSD &t = AddThread(info.pl_lwpid); + + // Technically, the FreeBSD kernel copies the debug registers to new + // threads. However, there is a non-negligible delay between acquiring + // the DR values and reporting the new thread during which the user may + // establish a new watchpoint. In order to ensure that watchpoints + // established during this period are propagated to new threads, + // explicitly copy the DR value at the time the new thread is reported. + // + // See also: https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=250954 + + llvm::Error error = t.CopyWatchpointsFrom( + static_cast(*GetCurrentThread())); + if (error) { + LLDB_LOG_ERROR(log, std::move(error), + "failed to copy watchpoints to new thread {1}: {0}", + info.pl_lwpid); + SetState(StateType::eStateInvalid); + return; + } + } else /*if (info.pl_flags & PL_FLAG_EXITED)*/ { + LLDB_LOG(log, "thread exited, tid = {0}", info.pl_lwpid); + RemoveThread(info.pl_lwpid); + } + + Status error = + PtraceWrapper(PT_CONTINUE, pid, reinterpret_cast(1), 0); + if (error.Fail()) + SetState(StateType::eStateInvalid); + return; + } + + if (info.pl_flags & PL_FLAG_EXEC) { + Status error = ReinitializeThreads(); + if (error.Fail()) { + SetState(StateType::eStateInvalid); + return; + } + + // Let our delegate know we have just exec'd. + NotifyDidExec(); + + for (const auto &thread : m_threads) + static_cast(*thread).SetStoppedByExec(); + SetState(StateType::eStateStopped, true); + return; + } + + if (info.pl_lwpid > 0) { + for (const auto &t : m_threads) { + if (t->GetID() == static_cast(info.pl_lwpid)) + thread = static_cast(t.get()); + static_cast(t.get())->SetStoppedWithNoReason(); + } + if (!thread) + LLDB_LOG(log, "thread not found in m_threads, pid = {0}, LWP = {1}", pid, + info.pl_lwpid); + } + + if (info.pl_flags & PL_FLAG_FORKED) { + assert(thread); + MonitorClone(info.pl_child_pid, info.pl_flags & PL_FLAG_VFORKED, *thread); + return; + } + + if (info.pl_flags & PL_FLAG_VFORK_DONE) { + assert(thread); + if ((m_enabled_extensions & Extension::vfork) == Extension::vfork) { + thread->SetStoppedByVForkDone(); + SetState(StateType::eStateStopped, true); + } else { + Status error = + PtraceWrapper(PT_CONTINUE, pid, reinterpret_cast(1), 0); + if (error.Fail()) + SetState(StateType::eStateInvalid); + } + return; + } + + if (info.pl_flags & PL_FLAG_SI) { + assert(info.pl_siginfo.si_signo == SIGTRAP); + LLDB_LOG(log, "SIGTRAP siginfo: si_code = {0}, pid = {1}", + info.pl_siginfo.si_code, info.pl_siginfo.si_pid); + + switch (info.pl_siginfo.si_code) { + case TRAP_BRKPT: + LLDB_LOG(log, "SIGTRAP/TRAP_BRKPT: si_addr: {0}", + info.pl_siginfo.si_addr); + + if (thread) { + auto thread_info = + m_threads_stepping_with_breakpoint.find(thread->GetID()); + if (thread_info != m_threads_stepping_with_breakpoint.end()) { + thread->SetStoppedByTrace(); + Status brkpt_error = RemoveBreakpoint(thread_info->second); + if (brkpt_error.Fail()) + LLDB_LOG(log, "pid = {0} remove stepping breakpoint: {1}", + thread_info->first, brkpt_error); + m_threads_stepping_with_breakpoint.erase(thread_info); + } else + thread->SetStoppedByBreakpoint(); + FixupBreakpointPCAsNeeded(*thread); + } + SetState(StateType::eStateStopped, true); + return; + case TRAP_TRACE: + LLDB_LOG(log, "SIGTRAP/TRAP_TRACE: si_addr: {0}", + info.pl_siginfo.si_addr); + + if (thread) { + auto ®ctx = static_cast( + thread->GetRegisterContext()); + uint32_t wp_index = LLDB_INVALID_INDEX32; + Status error = regctx.GetWatchpointHitIndex( + wp_index, reinterpret_cast(info.pl_siginfo.si_addr)); + if (error.Fail()) + LLDB_LOG(log, + "received error while checking for watchpoint hits, pid = " + "{0}, LWP = {1}, error = {2}", + pid, info.pl_lwpid, error); + if (wp_index != LLDB_INVALID_INDEX32) { + regctx.ClearWatchpointHit(wp_index); + thread->SetStoppedByWatchpoint(wp_index); + SetState(StateType::eStateStopped, true); + break; + } + + thread->SetStoppedByTrace(); + } + + SetState(StateType::eStateStopped, true); + return; + } + } + + // Either user-generated SIGTRAP or an unknown event that would + // otherwise leave the debugger hanging. + LLDB_LOG(log, "unknown SIGTRAP, passing to generic handler"); + MonitorSignal(pid, SIGTRAP); +} + +void NativeProcessFreeBSD::MonitorSignal(lldb::pid_t pid, int signal) { + Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); + struct ptrace_lwpinfo info; + + const auto siginfo_err = PtraceWrapper(PT_LWPINFO, pid, &info, sizeof(info)); + if (siginfo_err.Fail()) { + LLDB_LOG(log, "PT_LWPINFO failed {0}", siginfo_err); + return; + } + assert(info.pl_event == PL_EVENT_SIGNAL); + // TODO: do we need to handle !PL_FLAG_SI? + assert(info.pl_flags & PL_FLAG_SI); + assert(info.pl_siginfo.si_signo == signal); + + for (const auto &abs_thread : m_threads) { + NativeThreadFreeBSD &thread = + static_cast(*abs_thread); + assert(info.pl_lwpid >= 0); + if (info.pl_lwpid == 0 || + static_cast(info.pl_lwpid) == thread.GetID()) + thread.SetStoppedBySignal(info.pl_siginfo.si_signo, &info.pl_siginfo); + else + thread.SetStoppedWithNoReason(); + } + SetState(StateType::eStateStopped, true); +} + +Status NativeProcessFreeBSD::PtraceWrapper(int req, lldb::pid_t pid, void *addr, + int data, int *result) { + Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PTRACE)); + Status error; + int ret; + + errno = 0; + ret = + ptrace(req, static_cast<::pid_t>(pid), static_cast(addr), data); + + if (ret == -1) + error.SetErrorToErrno(); + + if (result) + *result = ret; + + LLDB_LOG(log, "ptrace({0}, {1}, {2}, {3})={4:x}", req, pid, addr, data, ret); + + if (error.Fail()) + LLDB_LOG(log, "ptrace() failed: {0}", error); + + return error; +} + +llvm::Expected> +NativeProcessFreeBSD::GetSoftwareBreakpointTrapOpcode(size_t size_hint) { + static const uint8_t g_arm_opcode[] = {0xfe, 0xde, 0xff, 0xe7}; + static const uint8_t g_thumb_opcode[] = {0x01, 0xde}; + + switch (GetArchitecture().GetMachine()) { + case llvm::Triple::arm: + switch (size_hint) { + case 2: + return llvm::makeArrayRef(g_thumb_opcode); + case 4: + return llvm::makeArrayRef(g_arm_opcode); + default: + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "Unrecognised trap opcode size hint!"); + } + default: + return NativeProcessProtocol::GetSoftwareBreakpointTrapOpcode(size_hint); + } +} + +Status NativeProcessFreeBSD::Resume(const ResumeActionList &resume_actions) { + Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); + LLDB_LOG(log, "pid {0}", GetID()); + + Status ret; + + int signal = 0; + for (const auto &abs_thread : m_threads) { + assert(abs_thread && "thread list should not contain NULL threads"); + NativeThreadFreeBSD &thread = + static_cast(*abs_thread); + + const ResumeAction *action = + resume_actions.GetActionForThread(thread.GetID(), true); + // we need to explicit issue suspend requests, so it is simpler to map it + // into proper action + ResumeAction suspend_action{thread.GetID(), eStateSuspended, + LLDB_INVALID_SIGNAL_NUMBER}; + + if (action == nullptr) { + LLDB_LOG(log, "no action specified for pid {0} tid {1}", GetID(), + thread.GetID()); + action = &suspend_action; + } + + LLDB_LOG( + log, + "processing resume action state {0} signal {1} for pid {2} tid {3}", + action->state, action->signal, GetID(), thread.GetID()); + + switch (action->state) { + case eStateRunning: + ret = thread.Resume(); + break; + case eStateStepping: + ret = thread.SingleStep(); + break; + case eStateSuspended: + case eStateStopped: + if (action->signal != LLDB_INVALID_SIGNAL_NUMBER) + return Status("Passing signal to suspended thread unsupported"); + + ret = thread.Suspend(); + break; + + default: + return Status( + "NativeProcessFreeBSD::%s (): unexpected state %s specified " + "for pid %" PRIu64 ", tid %" PRIu64, + __FUNCTION__, StateAsCString(action->state), GetID(), thread.GetID()); + } + + if (!ret.Success()) + return ret; + if (action->signal != LLDB_INVALID_SIGNAL_NUMBER) + signal = action->signal; + } + + ret = + PtraceWrapper(PT_CONTINUE, GetID(), reinterpret_cast(1), signal); + if (ret.Success()) + SetState(eStateRunning, true); + return ret; +} + +Status NativeProcessFreeBSD::Halt() { + Status error; + + if (kill(GetID(), SIGSTOP) != 0) + error.SetErrorToErrno(); + return error; +} + +Status NativeProcessFreeBSD::Detach() { + Status error; + + // Stop monitoring the inferior. + m_sigchld_handle.reset(); + + // Tell ptrace to detach from the process. + if (GetID() == LLDB_INVALID_PROCESS_ID) + return error; + + return PtraceWrapper(PT_DETACH, GetID()); +} + +Status NativeProcessFreeBSD::Signal(int signo) { + Status error; + + if (kill(GetID(), signo)) + error.SetErrorToErrno(); + + return error; +} + +Status NativeProcessFreeBSD::Interrupt() { return Halt(); } + +Status NativeProcessFreeBSD::Kill() { + Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); + LLDB_LOG(log, "pid {0}", GetID()); + + Status error; + + switch (m_state) { + case StateType::eStateInvalid: + case StateType::eStateExited: + case StateType::eStateCrashed: + case StateType::eStateDetached: + case StateType::eStateUnloaded: + // Nothing to do - the process is already dead. + LLDB_LOG(log, "ignored for PID {0} due to current state: {1}", GetID(), + StateAsCString(m_state)); + return error; + + case StateType::eStateConnected: + case StateType::eStateAttaching: + case StateType::eStateLaunching: + case StateType::eStateStopped: + case StateType::eStateRunning: + case StateType::eStateStepping: + case StateType::eStateSuspended: + // We can try to kill a process in these states. + break; + } + + return PtraceWrapper(PT_KILL, m_pid); +} + +Status NativeProcessFreeBSD::GetMemoryRegionInfo(lldb::addr_t load_addr, + MemoryRegionInfo &range_info) { + + if (m_supports_mem_region == LazyBool::eLazyBoolNo) { + // We're done. + return Status("unsupported"); + } + + Status error = PopulateMemoryRegionCache(); + if (error.Fail()) { + return error; + } + + lldb::addr_t prev_base_address = 0; + // FIXME start by finding the last region that is <= target address using + // binary search. Data is sorted. + // There can be a ton of regions on pthreads apps with lots of threads. + for (auto it = m_mem_region_cache.begin(); it != m_mem_region_cache.end(); + ++it) { + MemoryRegionInfo &proc_entry_info = it->first; + // Sanity check assumption that memory map entries are ascending. + assert((proc_entry_info.GetRange().GetRangeBase() >= prev_base_address) && + "descending memory map entries detected, unexpected"); + prev_base_address = proc_entry_info.GetRange().GetRangeBase(); + UNUSED_IF_ASSERT_DISABLED(prev_base_address); + // If the target address comes before this entry, indicate distance to next + // region. + if (load_addr < proc_entry_info.GetRange().GetRangeBase()) { + range_info.GetRange().SetRangeBase(load_addr); + range_info.GetRange().SetByteSize( + proc_entry_info.GetRange().GetRangeBase() - load_addr); + range_info.SetReadable(MemoryRegionInfo::OptionalBool::eNo); + range_info.SetWritable(MemoryRegionInfo::OptionalBool::eNo); + range_info.SetExecutable(MemoryRegionInfo::OptionalBool::eNo); + range_info.SetMapped(MemoryRegionInfo::OptionalBool::eNo); + return error; + } else if (proc_entry_info.GetRange().Contains(load_addr)) { + // The target address is within the memory region we're processing here. + range_info = proc_entry_info; + return error; + } + // The target memory address comes somewhere after the region we just + // parsed. + } + // If we made it here, we didn't find an entry that contained the given + // address. Return the load_addr as start and the amount of bytes betwwen + // load address and the end of the memory as size. + range_info.GetRange().SetRangeBase(load_addr); + range_info.GetRange().SetRangeEnd(LLDB_INVALID_ADDRESS); + range_info.SetReadable(MemoryRegionInfo::OptionalBool::eNo); + range_info.SetWritable(MemoryRegionInfo::OptionalBool::eNo); + range_info.SetExecutable(MemoryRegionInfo::OptionalBool::eNo); + range_info.SetMapped(MemoryRegionInfo::OptionalBool::eNo); + return error; +} + +Status NativeProcessFreeBSD::PopulateMemoryRegionCache() { + Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); + // If our cache is empty, pull the latest. There should always be at least + // one memory region if memory region handling is supported. + if (!m_mem_region_cache.empty()) { + LLDB_LOG(log, "reusing {0} cached memory region entries", + m_mem_region_cache.size()); + return Status(); + } + + int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_VMMAP, static_cast(m_pid)}; + int ret; + size_t len; + + ret = ::sysctl(mib, 4, nullptr, &len, nullptr, 0); + if (ret != 0) { + m_supports_mem_region = LazyBool::eLazyBoolNo; + return Status("sysctl() for KERN_PROC_VMMAP failed"); + } + + std::unique_ptr buf = + llvm::WritableMemoryBuffer::getNewMemBuffer(len); + ret = ::sysctl(mib, 4, buf->getBufferStart(), &len, nullptr, 0); + if (ret != 0) { + m_supports_mem_region = LazyBool::eLazyBoolNo; + return Status("sysctl() for KERN_PROC_VMMAP failed"); + } + + char *bp = buf->getBufferStart(); + char *end = bp + len; + while (bp < end) { + auto *kv = reinterpret_cast(bp); + if (kv->kve_structsize == 0) + break; + bp += kv->kve_structsize; + + MemoryRegionInfo info; + info.Clear(); + info.GetRange().SetRangeBase(kv->kve_start); + info.GetRange().SetRangeEnd(kv->kve_end); + info.SetMapped(MemoryRegionInfo::OptionalBool::eYes); + + if (kv->kve_protection & VM_PROT_READ) + info.SetReadable(MemoryRegionInfo::OptionalBool::eYes); + else + info.SetReadable(MemoryRegionInfo::OptionalBool::eNo); + + if (kv->kve_protection & VM_PROT_WRITE) + info.SetWritable(MemoryRegionInfo::OptionalBool::eYes); + else + info.SetWritable(MemoryRegionInfo::OptionalBool::eNo); + + if (kv->kve_protection & VM_PROT_EXECUTE) + info.SetExecutable(MemoryRegionInfo::OptionalBool::eYes); + else + info.SetExecutable(MemoryRegionInfo::OptionalBool::eNo); + + if (kv->kve_path[0]) + info.SetName(kv->kve_path); + + m_mem_region_cache.emplace_back(info, + FileSpec(info.GetName().GetCString())); + } + + if (m_mem_region_cache.empty()) { + // No entries after attempting to read them. This shouldn't happen. Assume + // we don't support map entries. + LLDB_LOG(log, "failed to find any vmmap entries, assuming no support " + "for memory region metadata retrieval"); + m_supports_mem_region = LazyBool::eLazyBoolNo; + return Status("not supported"); + } + LLDB_LOG(log, "read {0} memory region entries from process {1}", + m_mem_region_cache.size(), GetID()); + // We support memory retrieval, remember that. + m_supports_mem_region = LazyBool::eLazyBoolYes; + + return Status(); +} + +size_t NativeProcessFreeBSD::UpdateThreads() { return m_threads.size(); } + +Status NativeProcessFreeBSD::SetBreakpoint(lldb::addr_t addr, uint32_t size, + bool hardware) { + if (hardware) + return SetHardwareBreakpoint(addr, size); + return SetSoftwareBreakpoint(addr, size); +} + +Status NativeProcessFreeBSD::GetLoadedModuleFileSpec(const char *module_path, + FileSpec &file_spec) { + Status error = PopulateMemoryRegionCache(); + if (error.Fail()) + return error; + + FileSpec module_file_spec(module_path); + FileSystem::Instance().Resolve(module_file_spec); + + file_spec.Clear(); + for (const auto &it : m_mem_region_cache) { + if (it.second.GetFilename() == module_file_spec.GetFilename()) { + file_spec = it.second; + return Status(); + } + } + return Status("Module file (%s) not found in process' memory map!", + module_file_spec.GetFilename().AsCString()); +} + +Status +NativeProcessFreeBSD::GetFileLoadAddress(const llvm::StringRef &file_name, + lldb::addr_t &load_addr) { + load_addr = LLDB_INVALID_ADDRESS; + Status error = PopulateMemoryRegionCache(); + if (error.Fail()) + return error; + + FileSpec file(file_name); + for (const auto &it : m_mem_region_cache) { + if (it.second == file) { + load_addr = it.first.GetRange().GetRangeBase(); + return Status(); + } + } + return Status("No load address found for file %s.", file_name.str().c_str()); +} + +void NativeProcessFreeBSD::SigchldHandler() { + Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); + int status; + ::pid_t wait_pid = + llvm::sys::RetryAfterSignal(-1, waitpid, GetID(), &status, WNOHANG); + + if (wait_pid == 0) + return; + + if (wait_pid == -1) { + Status error(errno, eErrorTypePOSIX); + LLDB_LOG(log, "waitpid ({0}, &status, _) failed: {1}", GetID(), error); + return; + } + + WaitStatus wait_status = WaitStatus::Decode(status); + bool exited = wait_status.type == WaitStatus::Exit || + (wait_status.type == WaitStatus::Signal && + wait_pid == static_cast<::pid_t>(GetID())); + + LLDB_LOG(log, + "waitpid ({0}, &status, _) => pid = {1}, status = {2}, exited = {3}", + GetID(), wait_pid, status, exited); + + if (exited) + MonitorExited(wait_pid, wait_status); + else { + assert(wait_status.type == WaitStatus::Stop); + MonitorCallback(wait_pid, wait_status.status); + } +} + +bool NativeProcessFreeBSD::HasThreadNoLock(lldb::tid_t thread_id) { + for (const auto &thread : m_threads) { + assert(thread && "thread list should not contain NULL threads"); + if (thread->GetID() == thread_id) { + // We have this thread. + return true; + } + } + + // We don't have this thread. + return false; +} + +NativeThreadFreeBSD &NativeProcessFreeBSD::AddThread(lldb::tid_t thread_id) { + Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD)); + LLDB_LOG(log, "pid {0} adding thread with tid {1}", GetID(), thread_id); + + assert(thread_id > 0); + assert(!HasThreadNoLock(thread_id) && + "attempted to add a thread by id that already exists"); + + // If this is the first thread, save it as the current thread + if (m_threads.empty()) + SetCurrentThreadID(thread_id); + + m_threads.push_back(std::make_unique(*this, thread_id)); + return static_cast(*m_threads.back()); +} + +void NativeProcessFreeBSD::RemoveThread(lldb::tid_t thread_id) { + Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD)); + LLDB_LOG(log, "pid {0} removing thread with tid {1}", GetID(), thread_id); + + assert(thread_id > 0); + assert(HasThreadNoLock(thread_id) && + "attempted to remove a thread that does not exist"); + + for (auto it = m_threads.begin(); it != m_threads.end(); ++it) { + if ((*it)->GetID() == thread_id) { + m_threads.erase(it); + break; + } + } +} + +Status NativeProcessFreeBSD::Attach() { + // Attach to the requested process. + // An attach will cause the thread to stop with a SIGSTOP. + Status status = PtraceWrapper(PT_ATTACH, m_pid); + if (status.Fail()) + return status; + + int wstatus; + // Need to use WALLSIG otherwise we receive an error with errno=ECHLD At this + // point we should have a thread stopped if waitpid succeeds. + if ((wstatus = llvm::sys::RetryAfterSignal(-1, waitpid, m_pid, nullptr, 0)) < + 0) + return Status(errno, eErrorTypePOSIX); + + // Initialize threads and tracing status + // NB: this needs to be called before we set thread state + status = SetupTrace(); + if (status.Fail()) + return status; + + for (const auto &thread : m_threads) + static_cast(*thread).SetStoppedBySignal(SIGSTOP); + + // Let our process instance know the thread has stopped. + SetCurrentThreadID(m_threads.front()->GetID()); + SetState(StateType::eStateStopped, false); + return Status(); +} + +Status NativeProcessFreeBSD::ReadMemory(lldb::addr_t addr, void *buf, + size_t size, size_t &bytes_read) { + unsigned char *dst = static_cast(buf); + struct ptrace_io_desc io; + + Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_MEMORY)); + LLDB_LOG(log, "addr = {0}, buf = {1}, size = {2}", addr, buf, size); + + bytes_read = 0; + io.piod_op = PIOD_READ_D; + io.piod_len = size; + + do { + io.piod_offs = (void *)(addr + bytes_read); + io.piod_addr = dst + bytes_read; + + Status error = NativeProcessFreeBSD::PtraceWrapper(PT_IO, GetID(), &io); + if (error.Fail() || io.piod_len == 0) + return error; + + bytes_read += io.piod_len; + io.piod_len = size - bytes_read; + } while (bytes_read < size); + + return Status(); +} + +Status NativeProcessFreeBSD::WriteMemory(lldb::addr_t addr, const void *buf, + size_t size, size_t &bytes_written) { + const unsigned char *src = static_cast(buf); + Status error; + struct ptrace_io_desc io; + + Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_MEMORY)); + LLDB_LOG(log, "addr = {0}, buf = {1}, size = {2}", addr, buf, size); + + bytes_written = 0; + io.piod_op = PIOD_WRITE_D; + io.piod_len = size; + + do { + io.piod_addr = + const_cast(static_cast(src + bytes_written)); + io.piod_offs = (void *)(addr + bytes_written); + + Status error = NativeProcessFreeBSD::PtraceWrapper(PT_IO, GetID(), &io); + if (error.Fail() || io.piod_len == 0) + return error; + + bytes_written += io.piod_len; + io.piod_len = size - bytes_written; + } while (bytes_written < size); + + return error; +} + +llvm::ErrorOr> +NativeProcessFreeBSD::GetAuxvData() const { + int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_AUXV, static_cast(GetID())}; + size_t auxv_size = AT_COUNT * sizeof(Elf_Auxinfo); + std::unique_ptr buf = + llvm::WritableMemoryBuffer::getNewMemBuffer(auxv_size); + + if (::sysctl(mib, 4, buf->getBufferStart(), &auxv_size, nullptr, 0) != 0) + return std::error_code(errno, std::generic_category()); + + return buf; +} + +Status NativeProcessFreeBSD::SetupTrace() { + // Enable event reporting + int events; + Status status = + PtraceWrapper(PT_GET_EVENT_MASK, GetID(), &events, sizeof(events)); + if (status.Fail()) + return status; + events |= PTRACE_LWP | PTRACE_FORK | PTRACE_VFORK; + status = PtraceWrapper(PT_SET_EVENT_MASK, GetID(), &events, sizeof(events)); + if (status.Fail()) + return status; + + return ReinitializeThreads(); +} + +Status NativeProcessFreeBSD::ReinitializeThreads() { + // Clear old threads + m_threads.clear(); + + int num_lwps; + Status error = PtraceWrapper(PT_GETNUMLWPS, GetID(), nullptr, 0, &num_lwps); + if (error.Fail()) + return error; + + std::vector lwp_ids; + lwp_ids.resize(num_lwps); + error = PtraceWrapper(PT_GETLWPLIST, GetID(), lwp_ids.data(), + lwp_ids.size() * sizeof(lwpid_t), &num_lwps); + if (error.Fail()) + return error; + + // Reinitialize from scratch threads and register them in process + for (lwpid_t lwp : lwp_ids) + AddThread(lwp); + + return error; +} + +bool NativeProcessFreeBSD::SupportHardwareSingleStepping() const { + return !m_arch.IsMIPS(); +} + +void NativeProcessFreeBSD::MonitorClone(::pid_t child_pid, bool is_vfork, + NativeThreadFreeBSD &parent_thread) { + Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); + LLDB_LOG(log, "fork, child_pid={0}", child_pid); + + int status; + ::pid_t wait_pid = + llvm::sys::RetryAfterSignal(-1, ::waitpid, child_pid, &status, 0); + if (wait_pid != child_pid) { + LLDB_LOG(log, + "waiting for pid {0} failed. Assuming the pid has " + "disappeared in the meantime", + child_pid); + return; + } + if (WIFEXITED(status)) { + LLDB_LOG(log, + "waiting for pid {0} returned an 'exited' event. Not " + "tracking it.", + child_pid); + return; + } + + struct ptrace_lwpinfo info; + const auto siginfo_err = PtraceWrapper(PT_LWPINFO, child_pid, &info, sizeof(info)); + if (siginfo_err.Fail()) { + LLDB_LOG(log, "PT_LWPINFO failed {0}", siginfo_err); + return; + } + assert(info.pl_event == PL_EVENT_SIGNAL); + lldb::tid_t child_tid = info.pl_lwpid; + + std::unique_ptr child_process{ + new NativeProcessFreeBSD(static_cast<::pid_t>(child_pid), m_terminal_fd, + m_delegate, m_arch, m_main_loop)}; + if (!is_vfork) + child_process->m_software_breakpoints = m_software_breakpoints; + + Extension expected_ext = is_vfork ? Extension::vfork : Extension::fork; + if ((m_enabled_extensions & expected_ext) == expected_ext) { + child_process->SetupTrace(); + for (const auto &thread : child_process->m_threads) + static_cast(*thread).SetStoppedBySignal(SIGSTOP); + child_process->SetState(StateType::eStateStopped, false); + + m_delegate.NewSubprocess(this, std::move(child_process)); + if (is_vfork) + parent_thread.SetStoppedByVFork(child_pid, child_tid); + else + parent_thread.SetStoppedByFork(child_pid, child_tid); + SetState(StateType::eStateStopped, true); + } else { + child_process->Detach(); + Status pt_error = + PtraceWrapper(PT_CONTINUE, GetID(), reinterpret_cast(1), 0); + if (pt_error.Fail()) { + LLDB_LOG_ERROR(log, pt_error.ToError(), + "unable to resume parent process {1}: {0}", GetID()); + SetState(StateType::eStateInvalid); + } + } +} diff --git a/gnu/llvm/lldb/source/Plugins/Process/FreeBSD/NativeProcessFreeBSD.h b/gnu/llvm/lldb/source/Plugins/Process/FreeBSD/NativeProcessFreeBSD.h new file mode 100644 index 00000000000..7ec9d17d4cf --- /dev/null +++ b/gnu/llvm/lldb/source/Plugins/Process/FreeBSD/NativeProcessFreeBSD.h @@ -0,0 +1,133 @@ +//===-- NativeProcessFreeBSD.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 liblldb_NativeProcessFreeBSD_H_ +#define liblldb_NativeProcessFreeBSD_H_ + +#include "Plugins/Process/POSIX/NativeProcessELF.h" +#include "Plugins/Process/Utility/NativeProcessSoftwareSingleStep.h" + +#include "lldb/Target/MemoryRegionInfo.h" +#include "lldb/Utility/ArchSpec.h" +#include "lldb/Utility/FileSpec.h" + +#include "NativeThreadFreeBSD.h" + +namespace lldb_private { +namespace process_freebsd { +/// \class NativeProcessFreeBSD +/// Manages communication with the inferior (debugee) process. +/// +/// Upon construction, this class prepares and launches an inferior process +/// for debugging. +/// +/// Changes in the inferior process state are broadcasted. +class NativeProcessFreeBSD : public NativeProcessELF, + private NativeProcessSoftwareSingleStep { +public: + class Factory : public NativeProcessProtocol::Factory { + public: + llvm::Expected> + Launch(ProcessLaunchInfo &launch_info, NativeDelegate &native_delegate, + MainLoop &mainloop) const override; + + llvm::Expected> + Attach(lldb::pid_t pid, NativeDelegate &native_delegate, + MainLoop &mainloop) const override; + + Extension GetSupportedExtensions() const override; + }; + + // NativeProcessProtocol Interface + Status Resume(const ResumeActionList &resume_actions) override; + + Status Halt() override; + + Status Detach() override; + + Status Signal(int signo) override; + + Status Interrupt() override; + + Status Kill() override; + + Status GetMemoryRegionInfo(lldb::addr_t load_addr, + MemoryRegionInfo &range_info) override; + + Status ReadMemory(lldb::addr_t addr, void *buf, size_t size, + size_t &bytes_read) override; + + Status WriteMemory(lldb::addr_t addr, const void *buf, size_t size, + size_t &bytes_written) override; + + size_t UpdateThreads() override; + + const ArchSpec &GetArchitecture() const override { return m_arch; } + + Status SetBreakpoint(lldb::addr_t addr, uint32_t size, + bool hardware) override; + + // The two following methods are probably not necessary and probably + // will never be called. Nevertheless, we implement them right now + // to reduce the differences between different platforms and reduce + // the risk of the lack of implementation actually breaking something, + // at least for the time being. + Status GetLoadedModuleFileSpec(const char *module_path, + FileSpec &file_spec) override; + Status GetFileLoadAddress(const llvm::StringRef &file_name, + lldb::addr_t &load_addr) override; + + llvm::ErrorOr> + GetAuxvData() const override; + + // Interface used by NativeRegisterContext-derived classes. + static Status PtraceWrapper(int req, lldb::pid_t pid, void *addr = nullptr, + int data = 0, int *result = nullptr); + + bool SupportHardwareSingleStepping() const; + +protected: + llvm::Expected> + GetSoftwareBreakpointTrapOpcode(size_t size_hint) override; + +private: + MainLoop::SignalHandleUP m_sigchld_handle; + ArchSpec m_arch; + MainLoop& m_main_loop; + LazyBool m_supports_mem_region = eLazyBoolCalculate; + std::vector> m_mem_region_cache; + + // Private Instance Methods + NativeProcessFreeBSD(::pid_t pid, int terminal_fd, NativeDelegate &delegate, + const ArchSpec &arch, MainLoop &mainloop); + + bool HasThreadNoLock(lldb::tid_t thread_id); + + NativeThreadFreeBSD &AddThread(lldb::tid_t thread_id); + void RemoveThread(lldb::tid_t thread_id); + + void MonitorCallback(lldb::pid_t pid, int signal); + void MonitorExited(lldb::pid_t pid, WaitStatus status); + void MonitorSIGSTOP(lldb::pid_t pid); + void MonitorSIGTRAP(lldb::pid_t pid); + void MonitorSignal(lldb::pid_t pid, int signal); + void MonitorClone(::pid_t child_pid, bool is_vfork, + NativeThreadFreeBSD &parent_thread); + + Status PopulateMemoryRegionCache(); + void SigchldHandler(); + + Status Attach(); + Status SetupTrace(); + Status ReinitializeThreads(); +}; + +} // namespace process_freebsd +} // namespace lldb_private + +#endif // #ifndef liblldb_NativeProcessFreeBSD_H_ diff --git a/gnu/llvm/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD.cpp b/gnu/llvm/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD.cpp new file mode 100644 index 00000000000..3d744f773a2 --- /dev/null +++ b/gnu/llvm/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD.cpp @@ -0,0 +1,29 @@ +//===-- NativeRegisterContextFreeBSD.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 "NativeRegisterContextFreeBSD.h" + +#include "Plugins/Process/FreeBSD/NativeProcessFreeBSD.h" + +#include "lldb/Host/common/NativeProcessProtocol.h" + +using namespace lldb_private; +using namespace lldb_private::process_freebsd; + +// clang-format off +#include +#include +// clang-format on + +NativeProcessFreeBSD &NativeRegisterContextFreeBSD::GetProcess() { + return static_cast(m_thread.GetProcess()); +} + +::pid_t NativeRegisterContextFreeBSD::GetProcessPid() { + return GetProcess().GetID(); +} diff --git a/gnu/llvm/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD.h b/gnu/llvm/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD.h new file mode 100644 index 00000000000..0000484beac --- /dev/null +++ b/gnu/llvm/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD.h @@ -0,0 +1,43 @@ +//===-- NativeRegisterContextFreeBSD.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_NativeRegisterContextFreeBSD_h +#define lldb_NativeRegisterContextFreeBSD_h + +#include "lldb/Host/common/NativeThreadProtocol.h" + +#include "Plugins/Process/Utility/NativeRegisterContextRegisterInfo.h" + +namespace lldb_private { +namespace process_freebsd { + +class NativeProcessFreeBSD; + +class NativeRegisterContextFreeBSD + : public virtual NativeRegisterContextRegisterInfo { +public: + // This function is implemented in the NativeRegisterContextFreeBSD_* + // subclasses to create a new instance of the host specific + // NativeRegisterContextFreeBSD. The implementations can't collide as only one + // NativeRegisterContextFreeBSD_* variant should be compiled into the final + // executable. + static NativeRegisterContextFreeBSD * + CreateHostNativeRegisterContextFreeBSD(const ArchSpec &target_arch, + NativeThreadProtocol &native_thread); + virtual llvm::Error + CopyHardwareWatchpointsFrom(NativeRegisterContextFreeBSD &source) = 0; + +protected: + virtual NativeProcessFreeBSD &GetProcess(); + virtual ::pid_t GetProcessPid(); +}; + +} // namespace process_freebsd +} // namespace lldb_private + +#endif // #ifndef lldb_NativeRegisterContextFreeBSD_h diff --git a/gnu/llvm/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_arm.cpp b/gnu/llvm/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_arm.cpp new file mode 100644 index 00000000000..c4ee3773eae --- /dev/null +++ b/gnu/llvm/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_arm.cpp @@ -0,0 +1,202 @@ +//===-- NativeRegisterContextFreeBSD_arm.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(__arm__) + +#include "NativeRegisterContextFreeBSD_arm.h" + +#include "lldb/Utility/DataBufferHeap.h" +#include "lldb/Utility/RegisterValue.h" +#include "lldb/Utility/Status.h" + +#include "Plugins/Process/FreeBSD/NativeProcessFreeBSD.h" +#include "Plugins/Process/Utility/RegisterInfoPOSIX_arm.h" + +// clang-format off +#include +#include +#include +// clang-format on + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::process_freebsd; + +NativeRegisterContextFreeBSD * +NativeRegisterContextFreeBSD::CreateHostNativeRegisterContextFreeBSD( + const ArchSpec &target_arch, NativeThreadProtocol &native_thread) { + return new NativeRegisterContextFreeBSD_arm(target_arch, native_thread); +} + +NativeRegisterContextFreeBSD_arm::NativeRegisterContextFreeBSD_arm( + const ArchSpec &target_arch, NativeThreadProtocol &native_thread) + : NativeRegisterContextRegisterInfo( + native_thread, new RegisterInfoPOSIX_arm(target_arch)) {} + +RegisterInfoPOSIX_arm & +NativeRegisterContextFreeBSD_arm::GetRegisterInfo() const { + return static_cast(*m_register_info_interface_up); +} + +uint32_t NativeRegisterContextFreeBSD_arm::GetRegisterSetCount() const { + return GetRegisterInfo().GetRegisterSetCount(); +} + +const RegisterSet * +NativeRegisterContextFreeBSD_arm::GetRegisterSet(uint32_t set_index) const { + return GetRegisterInfo().GetRegisterSet(set_index); +} + +uint32_t NativeRegisterContextFreeBSD_arm::GetUserRegisterCount() const { + uint32_t count = 0; + for (uint32_t set_index = 0; set_index < GetRegisterSetCount(); ++set_index) + count += GetRegisterSet(set_index)->num_registers; + return count; +} + +Status NativeRegisterContextFreeBSD_arm::ReadRegisterSet(uint32_t set) { + switch (set) { + case RegisterInfoPOSIX_arm::GPRegSet: + return NativeProcessFreeBSD::PtraceWrapper(PT_GETREGS, m_thread.GetID(), + m_reg_data.data()); + case RegisterInfoPOSIX_arm::FPRegSet: + return NativeProcessFreeBSD::PtraceWrapper( + PT_GETVFPREGS, m_thread.GetID(), + m_reg_data.data() + sizeof(RegisterInfoPOSIX_arm::GPR)); + } + llvm_unreachable("NativeRegisterContextFreeBSD_arm::ReadRegisterSet"); +} + +Status NativeRegisterContextFreeBSD_arm::WriteRegisterSet(uint32_t set) { + switch (set) { + case RegisterInfoPOSIX_arm::GPRegSet: + return NativeProcessFreeBSD::PtraceWrapper(PT_SETREGS, m_thread.GetID(), + m_reg_data.data()); + case RegisterInfoPOSIX_arm::FPRegSet: + return NativeProcessFreeBSD::PtraceWrapper( + PT_SETVFPREGS, m_thread.GetID(), + m_reg_data.data() + sizeof(RegisterInfoPOSIX_arm::GPR)); + } + llvm_unreachable("NativeRegisterContextFreeBSD_arm::WriteRegisterSet"); +} + +Status +NativeRegisterContextFreeBSD_arm::ReadRegister(const RegisterInfo *reg_info, + RegisterValue ®_value) { + Status error; + + if (!reg_info) { + error.SetErrorString("reg_info NULL"); + return error; + } + + const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; + + if (reg == LLDB_INVALID_REGNUM) + return Status("no lldb regnum for %s", reg_info && reg_info->name + ? reg_info->name + : ""); + + uint32_t set = GetRegisterInfo().GetRegisterSetFromRegisterIndex(reg); + error = ReadRegisterSet(set); + if (error.Fail()) + return error; + + assert(reg_info->byte_offset + reg_info->byte_size <= m_reg_data.size()); + reg_value.SetBytes(m_reg_data.data() + reg_info->byte_offset, + reg_info->byte_size, endian::InlHostByteOrder()); + return error; +} + +Status NativeRegisterContextFreeBSD_arm::WriteRegister( + const RegisterInfo *reg_info, const RegisterValue ®_value) { + Status error; + + if (!reg_info) + return Status("reg_info NULL"); + + const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; + + if (reg == LLDB_INVALID_REGNUM) + return Status("no lldb regnum for %s", reg_info && reg_info->name + ? reg_info->name + : ""); + + uint32_t set = GetRegisterInfo().GetRegisterSetFromRegisterIndex(reg); + error = ReadRegisterSet(set); + if (error.Fail()) + return error; + + assert(reg_info->byte_offset + reg_info->byte_size <= m_reg_data.size()); + ::memcpy(m_reg_data.data() + reg_info->byte_offset, reg_value.GetBytes(), + reg_info->byte_size); + + return WriteRegisterSet(set); +} + +Status NativeRegisterContextFreeBSD_arm::ReadAllRegisterValues( + lldb::DataBufferSP &data_sp) { + Status error; + + error = ReadRegisterSet(RegisterInfoPOSIX_arm::GPRegSet); + if (error.Fail()) + return error; + + error = ReadRegisterSet(RegisterInfoPOSIX_arm::FPRegSet); + if (error.Fail()) + return error; + + data_sp.reset(new DataBufferHeap(m_reg_data.size(), 0)); + uint8_t *dst = data_sp->GetBytes(); + ::memcpy(dst, m_reg_data.data(), m_reg_data.size()); + + return error; +} + +Status NativeRegisterContextFreeBSD_arm::WriteAllRegisterValues( + const lldb::DataBufferSP &data_sp) { + Status error; + + if (!data_sp) { + error.SetErrorStringWithFormat( + "NativeRegisterContextFreeBSD_arm::%s invalid data_sp provided", + __FUNCTION__); + return error; + } + + if (data_sp->GetByteSize() != m_reg_data.size()) { + error.SetErrorStringWithFormat( + "NativeRegisterContextFreeBSD_arm::%s data_sp contained mismatched " + "data size, expected %" PRIu64 ", actual %" PRIu64, + __FUNCTION__, m_reg_data.size(), data_sp->GetByteSize()); + return error; + } + + uint8_t *src = data_sp->GetBytes(); + if (src == nullptr) { + error.SetErrorStringWithFormat("NativeRegisterContextFreeBSD_arm::%s " + "DataBuffer::GetBytes() returned a null " + "pointer", + __FUNCTION__); + return error; + } + ::memcpy(m_reg_data.data(), src, m_reg_data.size()); + + error = WriteRegisterSet(RegisterInfoPOSIX_arm::GPRegSet); + if (error.Fail()) + return error; + + return WriteRegisterSet(RegisterInfoPOSIX_arm::FPRegSet); +} + +llvm::Error NativeRegisterContextFreeBSD_arm::CopyHardwareWatchpointsFrom( + NativeRegisterContextFreeBSD &source) { + return llvm::Error::success(); +} + +#endif // defined (__arm__) diff --git a/gnu/llvm/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_arm.h b/gnu/llvm/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_arm.h new file mode 100644 index 00000000000..4be75b958fc --- /dev/null +++ b/gnu/llvm/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_arm.h @@ -0,0 +1,68 @@ +//===-- NativeRegisterContextFreeBSD_arm.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 +// +//===----------------------------------------------------------------------===// + +#if defined(__arm__) + +#ifndef lldb_NativeRegisterContextFreeBSD_arm_h +#define lldb_NativeRegisterContextFreeBSD_arm_h + +// clang-format off +#include +#include +#include +// clang-format on + +#include "Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD.h" +#include "Plugins/Process/Utility/RegisterInfoPOSIX_arm.h" + +#include + +namespace lldb_private { +namespace process_freebsd { + +class NativeProcessFreeBSD; + +class NativeRegisterContextFreeBSD_arm : public NativeRegisterContextFreeBSD { +public: + NativeRegisterContextFreeBSD_arm(const ArchSpec &target_arch, + NativeThreadProtocol &native_thread); + + uint32_t GetRegisterSetCount() const override; + + uint32_t GetUserRegisterCount() const override; + + const RegisterSet *GetRegisterSet(uint32_t set_index) const override; + + Status ReadRegister(const RegisterInfo *reg_info, + RegisterValue ®_value) override; + + Status WriteRegister(const RegisterInfo *reg_info, + const RegisterValue ®_value) override; + + Status ReadAllRegisterValues(lldb::DataBufferSP &data_sp) override; + + Status WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override; + + llvm::Error + CopyHardwareWatchpointsFrom(NativeRegisterContextFreeBSD &source) override; + +private: + std::array m_reg_data; + + Status ReadRegisterSet(uint32_t set); + Status WriteRegisterSet(uint32_t set); + + RegisterInfoPOSIX_arm &GetRegisterInfo() const; +}; + +} // namespace process_freebsd +} // namespace lldb_private + +#endif // #ifndef lldb_NativeRegisterContextFreeBSD_arm_h + +#endif // defined (__arm__) diff --git a/gnu/llvm/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_arm64.cpp b/gnu/llvm/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_arm64.cpp new file mode 100644 index 00000000000..4578138a89b --- /dev/null +++ b/gnu/llvm/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_arm64.cpp @@ -0,0 +1,282 @@ +//===-- NativeRegisterContextFreeBSD_arm64.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(__aarch64__) + +#include "NativeRegisterContextFreeBSD_arm64.h" + +#include "lldb/Utility/DataBufferHeap.h" +#include "lldb/Utility/RegisterValue.h" +#include "lldb/Utility/Status.h" + +#include "Plugins/Process/FreeBSD/NativeProcessFreeBSD.h" +#include "Plugins/Process/POSIX/ProcessPOSIXLog.h" +#include "Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h" + +// clang-format off +#include +#include +#include +// clang-format on + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::process_freebsd; + +NativeRegisterContextFreeBSD * +NativeRegisterContextFreeBSD::CreateHostNativeRegisterContextFreeBSD( + const ArchSpec &target_arch, NativeThreadProtocol &native_thread) { + return new NativeRegisterContextFreeBSD_arm64(target_arch, native_thread); +} + +NativeRegisterContextFreeBSD_arm64::NativeRegisterContextFreeBSD_arm64( + const ArchSpec &target_arch, NativeThreadProtocol &native_thread) + : NativeRegisterContextRegisterInfo( + native_thread, new RegisterInfoPOSIX_arm64(target_arch, 0)) +#ifdef LLDB_HAS_FREEBSD_WATCHPOINT + , + m_read_dbreg(false) +#endif +{ + ::memset(&m_hwp_regs, 0, sizeof(m_hwp_regs)); + ::memset(&m_hbp_regs, 0, sizeof(m_hbp_regs)); +} + +RegisterInfoPOSIX_arm64 & +NativeRegisterContextFreeBSD_arm64::GetRegisterInfo() const { + return static_cast(*m_register_info_interface_up); +} + +uint32_t NativeRegisterContextFreeBSD_arm64::GetRegisterSetCount() const { + return GetRegisterInfo().GetRegisterSetCount(); +} + +const RegisterSet * +NativeRegisterContextFreeBSD_arm64::GetRegisterSet(uint32_t set_index) const { + return GetRegisterInfo().GetRegisterSet(set_index); +} + +uint32_t NativeRegisterContextFreeBSD_arm64::GetUserRegisterCount() const { + uint32_t count = 0; + for (uint32_t set_index = 0; set_index < GetRegisterSetCount(); ++set_index) + count += GetRegisterSet(set_index)->num_registers; + return count; +} + +Status NativeRegisterContextFreeBSD_arm64::ReadRegisterSet(uint32_t set) { + switch (set) { + case RegisterInfoPOSIX_arm64::GPRegSet: + return NativeProcessFreeBSD::PtraceWrapper(PT_GETREGS, m_thread.GetID(), + m_reg_data.data()); + case RegisterInfoPOSIX_arm64::FPRegSet: + return NativeProcessFreeBSD::PtraceWrapper( + PT_GETFPREGS, m_thread.GetID(), + m_reg_data.data() + sizeof(RegisterInfoPOSIX_arm64::GPR)); + } + llvm_unreachable("NativeRegisterContextFreeBSD_arm64::ReadRegisterSet"); +} + +Status NativeRegisterContextFreeBSD_arm64::WriteRegisterSet(uint32_t set) { + switch (set) { + case RegisterInfoPOSIX_arm64::GPRegSet: + return NativeProcessFreeBSD::PtraceWrapper(PT_SETREGS, m_thread.GetID(), + m_reg_data.data()); + case RegisterInfoPOSIX_arm64::FPRegSet: + return NativeProcessFreeBSD::PtraceWrapper( + PT_SETFPREGS, m_thread.GetID(), + m_reg_data.data() + sizeof(RegisterInfoPOSIX_arm64::GPR)); + } + llvm_unreachable("NativeRegisterContextFreeBSD_arm64::WriteRegisterSet"); +} + +Status +NativeRegisterContextFreeBSD_arm64::ReadRegister(const RegisterInfo *reg_info, + RegisterValue ®_value) { + Status error; + + if (!reg_info) { + error.SetErrorString("reg_info NULL"); + return error; + } + + const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; + + if (reg == LLDB_INVALID_REGNUM) + return Status("no lldb regnum for %s", reg_info && reg_info->name + ? reg_info->name + : ""); + + uint32_t set = GetRegisterInfo().GetRegisterSetFromRegisterIndex(reg); + error = ReadRegisterSet(set); + if (error.Fail()) + return error; + + assert(reg_info->byte_offset + reg_info->byte_size <= m_reg_data.size()); + reg_value.SetBytes(m_reg_data.data() + reg_info->byte_offset, + reg_info->byte_size, endian::InlHostByteOrder()); + return error; +} + +Status NativeRegisterContextFreeBSD_arm64::WriteRegister( + const RegisterInfo *reg_info, const RegisterValue ®_value) { + Status error; + + if (!reg_info) + return Status("reg_info NULL"); + + const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; + + if (reg == LLDB_INVALID_REGNUM) + return Status("no lldb regnum for %s", reg_info && reg_info->name + ? reg_info->name + : ""); + + uint32_t set = GetRegisterInfo().GetRegisterSetFromRegisterIndex(reg); + error = ReadRegisterSet(set); + if (error.Fail()) + return error; + + assert(reg_info->byte_offset + reg_info->byte_size <= m_reg_data.size()); + ::memcpy(m_reg_data.data() + reg_info->byte_offset, reg_value.GetBytes(), + reg_info->byte_size); + + return WriteRegisterSet(set); +} + +Status NativeRegisterContextFreeBSD_arm64::ReadAllRegisterValues( + lldb::DataBufferSP &data_sp) { + Status error; + + error = ReadRegisterSet(RegisterInfoPOSIX_arm64::GPRegSet); + if (error.Fail()) + return error; + + error = ReadRegisterSet(RegisterInfoPOSIX_arm64::FPRegSet); + if (error.Fail()) + return error; + + data_sp.reset(new DataBufferHeap(m_reg_data.size(), 0)); + uint8_t *dst = data_sp->GetBytes(); + ::memcpy(dst, m_reg_data.data(), m_reg_data.size()); + + return error; +} + +Status NativeRegisterContextFreeBSD_arm64::WriteAllRegisterValues( + const lldb::DataBufferSP &data_sp) { + Status error; + + if (!data_sp) { + error.SetErrorStringWithFormat( + "NativeRegisterContextFreeBSD_arm64::%s invalid data_sp provided", + __FUNCTION__); + return error; + } + + if (data_sp->GetByteSize() != m_reg_data.size()) { + error.SetErrorStringWithFormat( + "NativeRegisterContextFreeBSD_arm64::%s data_sp contained mismatched " + "data size, expected %" PRIu64 ", actual %" PRIu64, + __FUNCTION__, m_reg_data.size(), data_sp->GetByteSize()); + return error; + } + + uint8_t *src = data_sp->GetBytes(); + if (src == nullptr) { + error.SetErrorStringWithFormat("NativeRegisterContextFreeBSD_arm64::%s " + "DataBuffer::GetBytes() returned a null " + "pointer", + __FUNCTION__); + return error; + } + ::memcpy(m_reg_data.data(), src, m_reg_data.size()); + + error = WriteRegisterSet(RegisterInfoPOSIX_arm64::GPRegSet); + if (error.Fail()) + return error; + + return WriteRegisterSet(RegisterInfoPOSIX_arm64::FPRegSet); +} + +llvm::Error NativeRegisterContextFreeBSD_arm64::CopyHardwareWatchpointsFrom( + NativeRegisterContextFreeBSD &source) { +#ifdef LLDB_HAS_FREEBSD_WATCHPOINT + auto &r_source = static_cast(source); + llvm::Error error = r_source.ReadHardwareDebugInfo(); + if (error) + return error; + + m_dbreg = r_source.m_dbreg; + m_hbp_regs = r_source.m_hbp_regs; + m_hwp_regs = r_source.m_hwp_regs; + m_max_hbp_supported = r_source.m_max_hbp_supported; + m_max_hwp_supported = r_source.m_max_hwp_supported; + m_read_dbreg = true; + + // on FreeBSD this writes both breakpoints and watchpoints + return WriteHardwareDebugRegs(eDREGTypeWATCH); +#else + return llvm::Error::success(); +#endif +} + +llvm::Error NativeRegisterContextFreeBSD_arm64::ReadHardwareDebugInfo() { +#ifdef LLDB_HAS_FREEBSD_WATCHPOINT + Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_REGISTERS)); + + // we're fully stateful, so no need to reread control registers ever + if (m_read_dbreg) + return llvm::Error::success(); + + Status res = NativeProcessFreeBSD::PtraceWrapper(PT_GETDBREGS, + m_thread.GetID(), &m_dbreg); + if (res.Fail()) + return res.ToError(); + + LLDB_LOG(log, "m_dbreg read: debug_ver={0}, nbkpts={1}, nwtpts={2}", + m_dbreg.db_debug_ver, m_dbreg.db_nbkpts, m_dbreg.db_nwtpts); + m_max_hbp_supported = m_dbreg.db_nbkpts; + m_max_hwp_supported = m_dbreg.db_nwtpts; + assert(m_max_hbp_supported <= m_hbp_regs.size()); + assert(m_max_hwp_supported <= m_hwp_regs.size()); + + m_read_dbreg = true; + return llvm::Error::success(); +#else + return llvm::createStringError( + llvm::inconvertibleErrorCode(), + "Hardware breakpoints/watchpoints require FreeBSD 14.0"); +#endif +} + +llvm::Error +NativeRegisterContextFreeBSD_arm64::WriteHardwareDebugRegs(DREGType) { +#ifdef LLDB_HAS_FREEBSD_WATCHPOINT + assert(m_read_dbreg && "dbregs must be read before writing them back"); + + // copy data from m_*_regs to m_dbreg before writing it back + for (uint32_t i = 0; i < m_max_hbp_supported; i++) { + m_dbreg.db_breakregs[i].dbr_addr = m_hbp_regs[i].address; + m_dbreg.db_breakregs[i].dbr_ctrl = m_hbp_regs[i].control; + } + for (uint32_t i = 0; i < m_max_hwp_supported; i++) { + m_dbreg.db_watchregs[i].dbw_addr = m_hwp_regs[i].address; + m_dbreg.db_watchregs[i].dbw_ctrl = m_hwp_regs[i].control; + } + + return NativeProcessFreeBSD::PtraceWrapper(PT_SETDBREGS, m_thread.GetID(), + &m_dbreg) + .ToError(); +#else + return llvm::createStringError( + llvm::inconvertibleErrorCode(), + "Hardware breakpoints/watchpoints require FreeBSD 14.0"); +#endif +} + +#endif // defined (__aarch64__) diff --git a/gnu/llvm/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_arm64.h b/gnu/llvm/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_arm64.h new file mode 100644 index 00000000000..a230f8fed48 --- /dev/null +++ b/gnu/llvm/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_arm64.h @@ -0,0 +1,86 @@ +//===-- NativeRegisterContextFreeBSD_arm64.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 +// +//===----------------------------------------------------------------------===// + +#if defined(__aarch64__) + +#ifndef lldb_NativeRegisterContextFreeBSD_arm64_h +#define lldb_NativeRegisterContextFreeBSD_arm64_h + +// clang-format off +#include +#include +#include +// clang-format on + +#include "Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD.h" +#include "Plugins/Process/Utility/NativeRegisterContextDBReg_arm64.h" +#include "Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h" + +#include + +#if __FreeBSD_version >= 1300139 +# define LLDB_HAS_FREEBSD_WATCHPOINT 1 +#endif + +namespace lldb_private { +namespace process_freebsd { + +class NativeProcessFreeBSD; + +class NativeRegisterContextFreeBSD_arm64 + : public NativeRegisterContextFreeBSD, + public NativeRegisterContextDBReg_arm64 { +public: + NativeRegisterContextFreeBSD_arm64(const ArchSpec &target_arch, + NativeThreadProtocol &native_thread); + + uint32_t GetRegisterSetCount() const override; + + uint32_t GetUserRegisterCount() const override; + + const RegisterSet *GetRegisterSet(uint32_t set_index) const override; + + Status ReadRegister(const RegisterInfo *reg_info, + RegisterValue ®_value) override; + + Status WriteRegister(const RegisterInfo *reg_info, + const RegisterValue ®_value) override; + + Status ReadAllRegisterValues(lldb::DataBufferSP &data_sp) override; + + Status WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override; + + llvm::Error + CopyHardwareWatchpointsFrom(NativeRegisterContextFreeBSD &source) override; + +private: + // Due to alignment, FreeBSD reg/fpreg are a few bytes larger than + // LLDB's GPR/FPU structs. However, all fields have matching offsets + // and sizes, so we do not have to worry about these (and we have + // a unittest to assert that). + std::array m_reg_data; +#ifdef LLDB_HAS_FREEBSD_WATCHPOINT + dbreg m_dbreg; + bool m_read_dbreg; +#endif + + Status ReadRegisterSet(uint32_t set); + Status WriteRegisterSet(uint32_t set); + + llvm::Error ReadHardwareDebugInfo() override; + llvm::Error WriteHardwareDebugRegs(DREGType hwbType) override; + + RegisterInfoPOSIX_arm64 &GetRegisterInfo() const; +}; + +} // namespace process_freebsd +} // namespace lldb_private + +#endif // #ifndef lldb_NativeRegisterContextFreeBSD_arm64_h + +#endif // defined (__aarch64__) diff --git a/gnu/llvm/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_mips64.cpp b/gnu/llvm/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_mips64.cpp new file mode 100644 index 00000000000..8e722c09314 --- /dev/null +++ b/gnu/llvm/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_mips64.cpp @@ -0,0 +1,186 @@ +//===-- NativeRegisterContextFreeBSD_mips64.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(__mips64__) + +#include "NativeRegisterContextFreeBSD_mips64.h" + +#include "lldb/Utility/DataBufferHeap.h" +#include "lldb/Utility/RegisterValue.h" +#include "lldb/Utility/Status.h" + +#include "Plugins/Process/FreeBSD/NativeProcessFreeBSD.h" + +// clang-format off +#include +#include +#include +// clang-format on + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::process_freebsd; + +NativeRegisterContextFreeBSD * +NativeRegisterContextFreeBSD::CreateHostNativeRegisterContextFreeBSD( + const ArchSpec &target_arch, NativeThreadProtocol &native_thread) { + return new NativeRegisterContextFreeBSD_mips64(target_arch, native_thread); +} + +NativeRegisterContextFreeBSD_mips64::NativeRegisterContextFreeBSD_mips64( + const ArchSpec &target_arch, NativeThreadProtocol &native_thread) + : NativeRegisterContextRegisterInfo( + native_thread, new RegisterContextFreeBSD_mips64(target_arch)) {} + +RegisterContextFreeBSD_mips64 & +NativeRegisterContextFreeBSD_mips64::GetRegisterInfo() const { + return static_cast( + *m_register_info_interface_up); +} + +uint32_t NativeRegisterContextFreeBSD_mips64::GetRegisterSetCount() const { + return GetRegisterInfo().GetRegisterSetCount(); +} + +const RegisterSet * +NativeRegisterContextFreeBSD_mips64::GetRegisterSet(uint32_t set_index) const { + return GetRegisterInfo().GetRegisterSet(set_index); +} + +uint32_t NativeRegisterContextFreeBSD_mips64::GetUserRegisterCount() const { + uint32_t count = 0; + for (uint32_t set_index = 0; set_index < GetRegisterSetCount(); ++set_index) + count += GetRegisterSet(set_index)->num_registers; + return count; +} + +Status NativeRegisterContextFreeBSD_mips64::ReadRegisterSet(RegSetKind set) { + switch (set) { + case GPRegSet: + return NativeProcessFreeBSD::PtraceWrapper(PT_GETREGS, m_thread.GetID(), + m_reg_data.data()); + } + llvm_unreachable("NativeRegisterContextFreeBSD_mips64::ReadRegisterSet"); +} + +Status NativeRegisterContextFreeBSD_mips64::WriteRegisterSet(RegSetKind set) { + switch (set) { + case GPRegSet: + return NativeProcessFreeBSD::PtraceWrapper(PT_SETREGS, m_thread.GetID(), + m_reg_data.data()); + } + llvm_unreachable("NativeRegisterContextFreeBSD_mips64::WriteRegisterSet"); +} + +Status +NativeRegisterContextFreeBSD_mips64::ReadRegister(const RegisterInfo *reg_info, + RegisterValue ®_value) { + Status error; + + if (!reg_info) { + error.SetErrorString("reg_info NULL"); + return error; + } + + const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; + + if (reg == LLDB_INVALID_REGNUM) + return Status("no lldb regnum for %s", reg_info && reg_info->name + ? reg_info->name + : ""); + + RegSetKind set = GPRegSet; + error = ReadRegisterSet(set); + if (error.Fail()) + return error; + + assert(reg_info->byte_offset + reg_info->byte_size <= m_reg_data.size()); + reg_value.SetBytes(m_reg_data.data() + reg_info->byte_offset, + reg_info->byte_size, endian::InlHostByteOrder()); + return error; +} + +Status NativeRegisterContextFreeBSD_mips64::WriteRegister( + const RegisterInfo *reg_info, const RegisterValue ®_value) { + Status error; + + if (!reg_info) + return Status("reg_info NULL"); + + const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; + + if (reg == LLDB_INVALID_REGNUM) + return Status("no lldb regnum for %s", reg_info && reg_info->name + ? reg_info->name + : ""); + + RegSetKind set = GPRegSet; + error = ReadRegisterSet(set); + if (error.Fail()) + return error; + + assert(reg_info->byte_offset + reg_info->byte_size <= m_reg_data.size()); + ::memcpy(m_reg_data.data() + reg_info->byte_offset, reg_value.GetBytes(), + reg_info->byte_size); + + return WriteRegisterSet(set); +} + +Status NativeRegisterContextFreeBSD_mips64::ReadAllRegisterValues( + lldb::DataBufferSP &data_sp) { + Status error; + + error = ReadRegisterSet(GPRegSet); + if (error.Fail()) + return error; + + data_sp.reset(new DataBufferHeap(m_reg_data.size(), 0)); + uint8_t *dst = data_sp->GetBytes(); + ::memcpy(dst, m_reg_data.data(), m_reg_data.size()); + + return error; +} + +Status NativeRegisterContextFreeBSD_mips64::WriteAllRegisterValues( + const lldb::DataBufferSP &data_sp) { + Status error; + + if (!data_sp) { + error.SetErrorStringWithFormat( + "NativeRegisterContextFreeBSD_mips64::%s invalid data_sp provided", + __FUNCTION__); + return error; + } + + if (data_sp->GetByteSize() != m_reg_data.size()) { + error.SetErrorStringWithFormat( + "NativeRegisterContextFreeBSD_mips64::%s data_sp contained mismatched " + "data size, expected %" PRIu64 ", actual %" PRIu64, + __FUNCTION__, m_reg_data.size(), data_sp->GetByteSize()); + return error; + } + + uint8_t *src = data_sp->GetBytes(); + if (src == nullptr) { + error.SetErrorStringWithFormat("NativeRegisterContextFreeBSD_mips64::%s " + "DataBuffer::GetBytes() returned a null " + "pointer", + __FUNCTION__); + return error; + } + ::memcpy(m_reg_data.data(), src, m_reg_data.size()); + + return WriteRegisterSet(GPRegSet); +} + +llvm::Error NativeRegisterContextFreeBSD_mips64::CopyHardwareWatchpointsFrom( + NativeRegisterContextFreeBSD &source) { + return llvm::Error::success(); +} + +#endif // defined (__mips64__) diff --git a/gnu/llvm/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_mips64.h b/gnu/llvm/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_mips64.h new file mode 100644 index 00000000000..6a3eb86a923 --- /dev/null +++ b/gnu/llvm/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_mips64.h @@ -0,0 +1,71 @@ +//===-- NativeRegisterContextFreeBSD_mips64.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 +// +//===----------------------------------------------------------------------===// + +#if defined(__mips64__) + +#ifndef lldb_NativeRegisterContextFreeBSD_mips64_h +#define lldb_NativeRegisterContextFreeBSD_mips64_h + +// clang-format off +#include +#include +// clang-format on + +#include "Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD.h" +#include "Plugins/Process/Utility/RegisterContextFreeBSD_mips64.h" + +#include + +namespace lldb_private { +namespace process_freebsd { + +class NativeProcessFreeBSD; + +class NativeRegisterContextFreeBSD_mips64 + : public NativeRegisterContextFreeBSD { +public: + NativeRegisterContextFreeBSD_mips64(const ArchSpec &target_arch, + NativeThreadProtocol &native_thread); + + uint32_t GetRegisterSetCount() const override; + + uint32_t GetUserRegisterCount() const override; + + const RegisterSet *GetRegisterSet(uint32_t set_index) const override; + + Status ReadRegister(const RegisterInfo *reg_info, + RegisterValue ®_value) override; + + Status WriteRegister(const RegisterInfo *reg_info, + const RegisterValue ®_value) override; + + Status ReadAllRegisterValues(lldb::DataBufferSP &data_sp) override; + + Status WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override; + + llvm::Error + CopyHardwareWatchpointsFrom(NativeRegisterContextFreeBSD &source) override; + +private: + enum RegSetKind { + GPRegSet, + }; + std::array m_reg_data; + + Status ReadRegisterSet(RegSetKind set); + Status WriteRegisterSet(RegSetKind set); + + RegisterContextFreeBSD_mips64 &GetRegisterInfo() const; +}; + +} // namespace process_freebsd +} // namespace lldb_private + +#endif // #ifndef lldb_NativeRegisterContextFreeBSD_mips64_h + +#endif // defined (__mips64__) diff --git a/gnu/llvm/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_powerpc.cpp b/gnu/llvm/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_powerpc.cpp new file mode 100644 index 00000000000..5b5d44a308b --- /dev/null +++ b/gnu/llvm/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_powerpc.cpp @@ -0,0 +1,289 @@ +//===-- NativeRegisterContextFreeBSD_powerpc.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(__powerpc__) + +#include "NativeRegisterContextFreeBSD_powerpc.h" + +#include "lldb/Host/HostInfo.h" +#include "lldb/Utility/DataBufferHeap.h" +#include "lldb/Utility/RegisterValue.h" +#include "lldb/Utility/Status.h" + +#include "Plugins/Process/FreeBSD/NativeProcessFreeBSD.h" +// for register enum definitions +#include "Plugins/Process/Utility/RegisterContextPOSIX_powerpc.h" + +// clang-format off +#include +#include +#include +// clang-format on + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::process_freebsd; + +static const uint32_t g_gpr_regnums[] = { + gpr_r0_powerpc, gpr_r1_powerpc, gpr_r2_powerpc, gpr_r3_powerpc, + gpr_r4_powerpc, gpr_r5_powerpc, gpr_r6_powerpc, gpr_r7_powerpc, + gpr_r8_powerpc, gpr_r9_powerpc, gpr_r10_powerpc, gpr_r11_powerpc, + gpr_r12_powerpc, gpr_r13_powerpc, gpr_r14_powerpc, gpr_r15_powerpc, + gpr_r16_powerpc, gpr_r17_powerpc, gpr_r18_powerpc, gpr_r19_powerpc, + gpr_r20_powerpc, gpr_r21_powerpc, gpr_r22_powerpc, gpr_r23_powerpc, + gpr_r24_powerpc, gpr_r25_powerpc, gpr_r26_powerpc, gpr_r27_powerpc, + gpr_r28_powerpc, gpr_r29_powerpc, gpr_r30_powerpc, gpr_r31_powerpc, + gpr_lr_powerpc, gpr_cr_powerpc, gpr_xer_powerpc, gpr_ctr_powerpc, + gpr_pc_powerpc, +}; + +static const uint32_t g_fpr_regnums[] = { + fpr_f0_powerpc, fpr_f1_powerpc, fpr_f2_powerpc, fpr_f3_powerpc, + fpr_f4_powerpc, fpr_f5_powerpc, fpr_f6_powerpc, fpr_f7_powerpc, + fpr_f8_powerpc, fpr_f9_powerpc, fpr_f10_powerpc, fpr_f11_powerpc, + fpr_f12_powerpc, fpr_f13_powerpc, fpr_f14_powerpc, fpr_f15_powerpc, + fpr_f16_powerpc, fpr_f17_powerpc, fpr_f18_powerpc, fpr_f19_powerpc, + fpr_f20_powerpc, fpr_f21_powerpc, fpr_f22_powerpc, fpr_f23_powerpc, + fpr_f24_powerpc, fpr_f25_powerpc, fpr_f26_powerpc, fpr_f27_powerpc, + fpr_f28_powerpc, fpr_f29_powerpc, fpr_f30_powerpc, fpr_f31_powerpc, + fpr_fpscr_powerpc, +}; + +// Number of register sets provided by this context. +enum { k_num_register_sets = 2 }; + +static const RegisterSet g_reg_sets_powerpc[k_num_register_sets] = { + {"General Purpose Registers", "gpr", k_num_gpr_registers_powerpc, + g_gpr_regnums}, + {"Floating Point Registers", "fpr", k_num_fpr_registers_powerpc, + g_fpr_regnums}, +}; + +NativeRegisterContextFreeBSD * +NativeRegisterContextFreeBSD::CreateHostNativeRegisterContextFreeBSD( + const ArchSpec &target_arch, NativeThreadProtocol &native_thread) { + return new NativeRegisterContextFreeBSD_powerpc(target_arch, native_thread); +} + +static RegisterInfoInterface * +CreateRegisterInfoInterface(const ArchSpec &target_arch) { + if (HostInfo::GetArchitecture().GetAddressByteSize() == 4) { + return new RegisterContextFreeBSD_powerpc32(target_arch); + } else { + assert((HostInfo::GetArchitecture().GetAddressByteSize() == 8) && + "Register setting path assumes this is a 64-bit host"); + return new RegisterContextFreeBSD_powerpc64(target_arch); + } +} + +NativeRegisterContextFreeBSD_powerpc::NativeRegisterContextFreeBSD_powerpc( + const ArchSpec &target_arch, NativeThreadProtocol &native_thread) + : NativeRegisterContextRegisterInfo( + native_thread, CreateRegisterInfoInterface(target_arch)) {} + +RegisterContextFreeBSD_powerpc & +NativeRegisterContextFreeBSD_powerpc::GetRegisterInfo() const { + return static_cast( + *m_register_info_interface_up); +} + +uint32_t NativeRegisterContextFreeBSD_powerpc::GetRegisterSetCount() const { + return k_num_register_sets; +} + +const RegisterSet * +NativeRegisterContextFreeBSD_powerpc::GetRegisterSet(uint32_t set_index) const { + switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) { + case llvm::Triple::ppc: + return &g_reg_sets_powerpc[set_index]; + default: + llvm_unreachable("Unhandled target architecture."); + } +} + +llvm::Optional +NativeRegisterContextFreeBSD_powerpc::GetSetForNativeRegNum( + uint32_t reg_num) const { + switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) { + case llvm::Triple::ppc: + if (reg_num >= k_first_gpr_powerpc && reg_num <= k_last_gpr_powerpc) + return GPRegSet; + if (reg_num >= k_first_fpr && reg_num <= k_last_fpr) + return FPRegSet; + break; + default: + llvm_unreachable("Unhandled target architecture."); + } + + llvm_unreachable("Register does not belong to any register set"); +} + +uint32_t NativeRegisterContextFreeBSD_powerpc::GetUserRegisterCount() const { + uint32_t count = 0; + for (uint32_t set_index = 0; set_index < GetRegisterSetCount(); ++set_index) + count += GetRegisterSet(set_index)->num_registers; + return count; +} + +Status NativeRegisterContextFreeBSD_powerpc::ReadRegisterSet(RegSetKind set) { + switch (set) { + case GPRegSet: + return NativeProcessFreeBSD::PtraceWrapper(PT_GETREGS, m_thread.GetID(), + m_reg_data.data()); + case FPRegSet: + return NativeProcessFreeBSD::PtraceWrapper(PT_GETFPREGS, m_thread.GetID(), + m_reg_data.data() + sizeof(reg)); + } + llvm_unreachable("NativeRegisterContextFreeBSD_powerpc::ReadRegisterSet"); +} + +Status NativeRegisterContextFreeBSD_powerpc::WriteRegisterSet(RegSetKind set) { + switch (set) { + case GPRegSet: + return NativeProcessFreeBSD::PtraceWrapper(PT_SETREGS, m_thread.GetID(), + m_reg_data.data()); + case FPRegSet: + return NativeProcessFreeBSD::PtraceWrapper(PT_SETFPREGS, m_thread.GetID(), + m_reg_data.data() + sizeof(reg)); + } + llvm_unreachable("NativeRegisterContextFreeBSD_powerpc::WriteRegisterSet"); +} + +Status +NativeRegisterContextFreeBSD_powerpc::ReadRegister(const RegisterInfo *reg_info, + RegisterValue ®_value) { + Status error; + + if (!reg_info) { + error.SetErrorString("reg_info NULL"); + return error; + } + + const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; + + if (reg == LLDB_INVALID_REGNUM) + return Status("no lldb regnum for %s", reg_info && reg_info->name + ? reg_info->name + : ""); + + llvm::Optional opt_set = GetSetForNativeRegNum(reg); + if (!opt_set) { + // This is likely an internal register for lldb use only and should not be + // directly queried. + error.SetErrorStringWithFormat("register \"%s\" is in unrecognized set", + reg_info->name); + return error; + } + + RegSetKind set = opt_set.getValue(); + error = ReadRegisterSet(set); + if (error.Fail()) + return error; + + assert(reg_info->byte_offset + reg_info->byte_size <= m_reg_data.size()); + reg_value.SetBytes(m_reg_data.data() + reg_info->byte_offset, + reg_info->byte_size, endian::InlHostByteOrder()); + return error; +} + +Status NativeRegisterContextFreeBSD_powerpc::WriteRegister( + const RegisterInfo *reg_info, const RegisterValue ®_value) { + Status error; + + if (!reg_info) + return Status("reg_info NULL"); + + const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; + + if (reg == LLDB_INVALID_REGNUM) + return Status("no lldb regnum for %s", reg_info && reg_info->name + ? reg_info->name + : ""); + + llvm::Optional opt_set = GetSetForNativeRegNum(reg); + if (!opt_set) { + // This is likely an internal register for lldb use only and should not be + // directly queried. + error.SetErrorStringWithFormat("register \"%s\" is in unrecognized set", + reg_info->name); + return error; + } + + RegSetKind set = opt_set.getValue(); + error = ReadRegisterSet(set); + if (error.Fail()) + return error; + + assert(reg_info->byte_offset + reg_info->byte_size <= m_reg_data.size()); + ::memcpy(m_reg_data.data() + reg_info->byte_offset, reg_value.GetBytes(), + reg_info->byte_size); + + return WriteRegisterSet(set); +} + +Status NativeRegisterContextFreeBSD_powerpc::ReadAllRegisterValues( + lldb::DataBufferSP &data_sp) { + Status error; + + error = ReadRegisterSet(GPRegSet); + if (error.Fail()) + return error; + + error = ReadRegisterSet(FPRegSet); + if (error.Fail()) + return error; + + data_sp.reset(new DataBufferHeap(m_reg_data.size(), 0)); + uint8_t *dst = data_sp->GetBytes(); + ::memcpy(dst, m_reg_data.data(), m_reg_data.size()); + + return error; +} + +Status NativeRegisterContextFreeBSD_powerpc::WriteAllRegisterValues( + const lldb::DataBufferSP &data_sp) { + Status error; + + if (!data_sp) { + error.SetErrorStringWithFormat( + "NativeRegisterContextFreeBSD_powerpc::%s invalid data_sp provided", + __FUNCTION__); + return error; + } + + if (data_sp->GetByteSize() != m_reg_data.size()) { + error.SetErrorStringWithFormat( + "NativeRegisterContextFreeBSD_powerpc::%s data_sp contained mismatched " + "data size, expected %zu, actual %" PRIu64, + __FUNCTION__, m_reg_data.size(), data_sp->GetByteSize()); + return error; + } + + uint8_t *src = data_sp->GetBytes(); + if (src == nullptr) { + error.SetErrorStringWithFormat("NativeRegisterContextFreeBSD_powerpc::%s " + "DataBuffer::GetBytes() returned a null " + "pointer", + __FUNCTION__); + return error; + } + ::memcpy(m_reg_data.data(), src, m_reg_data.size()); + + error = WriteRegisterSet(GPRegSet); + if (error.Fail()) + return error; + + return WriteRegisterSet(FPRegSet); +} + +llvm::Error NativeRegisterContextFreeBSD_powerpc::CopyHardwareWatchpointsFrom( + NativeRegisterContextFreeBSD &source) { + return llvm::Error::success(); +} + +#endif // defined (__powerpc__) diff --git a/gnu/llvm/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_powerpc.h b/gnu/llvm/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_powerpc.h new file mode 100644 index 00000000000..884c25988ce --- /dev/null +++ b/gnu/llvm/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_powerpc.h @@ -0,0 +1,74 @@ +//===-- NativeRegisterContextFreeBSD_powerpc.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 +// +//===----------------------------------------------------------------------===// + +#if defined(__powerpc__) + +#ifndef lldb_NativeRegisterContextFreeBSD_powerpc_h +#define lldb_NativeRegisterContextFreeBSD_powerpc_h + +// clang-format off +#include +#include +// clang-format on + +#include "Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD.h" +#include "Plugins/Process/Utility/RegisterContextFreeBSD_powerpc.h" + +#include + +namespace lldb_private { +namespace process_freebsd { + +class NativeProcessFreeBSD; + +class NativeRegisterContextFreeBSD_powerpc + : public NativeRegisterContextFreeBSD { +public: + NativeRegisterContextFreeBSD_powerpc(const ArchSpec &target_arch, + NativeThreadProtocol &native_thread); + + uint32_t GetRegisterSetCount() const override; + + uint32_t GetUserRegisterCount() const override; + + const RegisterSet *GetRegisterSet(uint32_t set_index) const override; + + Status ReadRegister(const RegisterInfo *reg_info, + RegisterValue ®_value) override; + + Status WriteRegister(const RegisterInfo *reg_info, + const RegisterValue ®_value) override; + + Status ReadAllRegisterValues(lldb::DataBufferSP &data_sp) override; + + Status WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override; + + llvm::Error + CopyHardwareWatchpointsFrom(NativeRegisterContextFreeBSD &source) override; + +private: + enum RegSetKind { + GPRegSet, + FPRegSet, + }; + std::array m_reg_data; + + llvm::Optional GetSetForNativeRegNum(uint32_t reg_num) const; + + Status ReadRegisterSet(RegSetKind set); + Status WriteRegisterSet(RegSetKind set); + + RegisterContextFreeBSD_powerpc &GetRegisterInfo() const; +}; + +} // namespace process_freebsd +} // namespace lldb_private + +#endif // #ifndef lldb_NativeRegisterContextFreeBSD_powerpc_h + +#endif // defined (__powerpc__) diff --git a/gnu/llvm/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_x86_64.cpp b/gnu/llvm/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_x86_64.cpp new file mode 100644 index 00000000000..9328d606ad2 --- /dev/null +++ b/gnu/llvm/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_x86_64.cpp @@ -0,0 +1,656 @@ +//===-- NativeRegisterContextFreeBSD_x86_64.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(__i386__) || defined(__x86_64__) + +#include "NativeRegisterContextFreeBSD_x86_64.h" + +// clang-format off +#include +#include +#include +// clang-format on + +#include "lldb/Host/HostInfo.h" +#include "lldb/Utility/DataBufferHeap.h" +#include "lldb/Utility/Log.h" +#include "lldb/Utility/RegisterValue.h" +#include "lldb/Utility/Status.h" + +#include "NativeProcessFreeBSD.h" +#include "Plugins/Process/Utility/RegisterContextFreeBSD_i386.h" +#include "Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.h" + +using namespace lldb_private; +using namespace lldb_private::process_freebsd; + +// x86 64-bit general purpose registers. +static const uint32_t g_gpr_regnums_x86_64[] = { + lldb_rax_x86_64, lldb_rbx_x86_64, lldb_rcx_x86_64, lldb_rdx_x86_64, + lldb_rdi_x86_64, lldb_rsi_x86_64, lldb_rbp_x86_64, lldb_rsp_x86_64, + lldb_r8_x86_64, lldb_r9_x86_64, lldb_r10_x86_64, lldb_r11_x86_64, + lldb_r12_x86_64, lldb_r13_x86_64, lldb_r14_x86_64, lldb_r15_x86_64, + lldb_rip_x86_64, lldb_rflags_x86_64, lldb_cs_x86_64, lldb_fs_x86_64, + lldb_gs_x86_64, lldb_ss_x86_64, lldb_ds_x86_64, lldb_es_x86_64, + lldb_eax_x86_64, lldb_ebx_x86_64, lldb_ecx_x86_64, lldb_edx_x86_64, + lldb_edi_x86_64, lldb_esi_x86_64, lldb_ebp_x86_64, lldb_esp_x86_64, + lldb_r8d_x86_64, // Low 32 bits or r8 + lldb_r9d_x86_64, // Low 32 bits or r9 + lldb_r10d_x86_64, // Low 32 bits or r10 + lldb_r11d_x86_64, // Low 32 bits or r11 + lldb_r12d_x86_64, // Low 32 bits or r12 + lldb_r13d_x86_64, // Low 32 bits or r13 + lldb_r14d_x86_64, // Low 32 bits or r14 + lldb_r15d_x86_64, // Low 32 bits or r15 + lldb_ax_x86_64, lldb_bx_x86_64, lldb_cx_x86_64, lldb_dx_x86_64, + lldb_di_x86_64, lldb_si_x86_64, lldb_bp_x86_64, lldb_sp_x86_64, + lldb_r8w_x86_64, // Low 16 bits or r8 + lldb_r9w_x86_64, // Low 16 bits or r9 + lldb_r10w_x86_64, // Low 16 bits or r10 + lldb_r11w_x86_64, // Low 16 bits or r11 + lldb_r12w_x86_64, // Low 16 bits or r12 + lldb_r13w_x86_64, // Low 16 bits or r13 + lldb_r14w_x86_64, // Low 16 bits or r14 + lldb_r15w_x86_64, // Low 16 bits or r15 + lldb_ah_x86_64, lldb_bh_x86_64, lldb_ch_x86_64, lldb_dh_x86_64, + lldb_al_x86_64, lldb_bl_x86_64, lldb_cl_x86_64, lldb_dl_x86_64, + lldb_dil_x86_64, lldb_sil_x86_64, lldb_bpl_x86_64, lldb_spl_x86_64, + lldb_r8l_x86_64, // Low 8 bits or r8 + lldb_r9l_x86_64, // Low 8 bits or r9 + lldb_r10l_x86_64, // Low 8 bits or r10 + lldb_r11l_x86_64, // Low 8 bits or r11 + lldb_r12l_x86_64, // Low 8 bits or r12 + lldb_r13l_x86_64, // Low 8 bits or r13 + lldb_r14l_x86_64, // Low 8 bits or r14 + lldb_r15l_x86_64, // Low 8 bits or r15 + LLDB_INVALID_REGNUM // register sets need to end with this flag +}; +static_assert((sizeof(g_gpr_regnums_x86_64) / sizeof(g_gpr_regnums_x86_64[0])) - + 1 == + k_num_gpr_registers_x86_64, + "g_gpr_regnums_x86_64 has wrong number of register infos"); + +// x86 64-bit floating point registers. +static const uint32_t g_fpu_regnums_x86_64[] = { + lldb_fctrl_x86_64, lldb_fstat_x86_64, lldb_ftag_x86_64, + lldb_fop_x86_64, lldb_fiseg_x86_64, lldb_fioff_x86_64, + lldb_fip_x86_64, lldb_foseg_x86_64, lldb_fooff_x86_64, + lldb_fdp_x86_64, lldb_mxcsr_x86_64, lldb_mxcsrmask_x86_64, + lldb_st0_x86_64, lldb_st1_x86_64, lldb_st2_x86_64, + lldb_st3_x86_64, lldb_st4_x86_64, lldb_st5_x86_64, + lldb_st6_x86_64, lldb_st7_x86_64, lldb_mm0_x86_64, + lldb_mm1_x86_64, lldb_mm2_x86_64, lldb_mm3_x86_64, + lldb_mm4_x86_64, lldb_mm5_x86_64, lldb_mm6_x86_64, + lldb_mm7_x86_64, lldb_xmm0_x86_64, lldb_xmm1_x86_64, + lldb_xmm2_x86_64, lldb_xmm3_x86_64, lldb_xmm4_x86_64, + lldb_xmm5_x86_64, lldb_xmm6_x86_64, lldb_xmm7_x86_64, + lldb_xmm8_x86_64, lldb_xmm9_x86_64, lldb_xmm10_x86_64, + lldb_xmm11_x86_64, lldb_xmm12_x86_64, lldb_xmm13_x86_64, + lldb_xmm14_x86_64, lldb_xmm15_x86_64, + LLDB_INVALID_REGNUM // register sets need to end with this flag +}; +static_assert((sizeof(g_fpu_regnums_x86_64) / sizeof(g_fpu_regnums_x86_64[0])) - + 1 == + k_num_fpr_registers_x86_64, + "g_fpu_regnums_x86_64 has wrong number of register infos"); + +static const uint32_t g_avx_regnums_x86_64[] = { + lldb_ymm0_x86_64, lldb_ymm1_x86_64, lldb_ymm2_x86_64, lldb_ymm3_x86_64, + lldb_ymm4_x86_64, lldb_ymm5_x86_64, lldb_ymm6_x86_64, lldb_ymm7_x86_64, + lldb_ymm8_x86_64, lldb_ymm9_x86_64, lldb_ymm10_x86_64, lldb_ymm11_x86_64, + lldb_ymm12_x86_64, lldb_ymm13_x86_64, lldb_ymm14_x86_64, lldb_ymm15_x86_64, + LLDB_INVALID_REGNUM // register sets need to end with this flag +}; +static_assert((sizeof(g_avx_regnums_x86_64) / sizeof(g_avx_regnums_x86_64[0])) - + 1 == + k_num_avx_registers_x86_64, + "g_avx_regnums_x86_64 has wrong number of register infos"); + +static const uint32_t g_mpx_regnums_x86_64[] = { + // Note: we currently do not provide them but this is needed to avoid + // unnamed groups in SBFrame::GetRegisterContext(). + lldb_bnd0_x86_64, lldb_bnd1_x86_64, lldb_bnd2_x86_64, + lldb_bnd3_x86_64, lldb_bndcfgu_x86_64, lldb_bndstatus_x86_64, + LLDB_INVALID_REGNUM // register sets need to end with this flag +}; +static_assert((sizeof(g_mpx_regnums_x86_64) / sizeof(g_mpx_regnums_x86_64[0])) - + 1 == + k_num_mpx_registers_x86_64, + "g_mpx_regnums_x86_64 has wrong number of register infos"); + +// x86 debug registers. +static const uint32_t g_dbr_regnums_x86_64[] = { + lldb_dr0_x86_64, lldb_dr1_x86_64, lldb_dr2_x86_64, lldb_dr3_x86_64, + lldb_dr4_x86_64, lldb_dr5_x86_64, lldb_dr6_x86_64, lldb_dr7_x86_64, + LLDB_INVALID_REGNUM // register sets need to end with this flag +}; +static_assert((sizeof(g_dbr_regnums_x86_64) / sizeof(g_dbr_regnums_x86_64[0])) - + 1 == + k_num_dbr_registers_x86_64, + "g_dbr_regnums_x86_64 has wrong number of register infos"); + +// x86 32-bit general purpose registers. +static const uint32_t g_gpr_regnums_i386[] = { + lldb_eax_i386, lldb_ebx_i386, lldb_ecx_i386, lldb_edx_i386, + lldb_edi_i386, lldb_esi_i386, lldb_ebp_i386, lldb_esp_i386, + lldb_eip_i386, lldb_eflags_i386, lldb_cs_i386, lldb_fs_i386, + lldb_gs_i386, lldb_ss_i386, lldb_ds_i386, lldb_es_i386, + lldb_ax_i386, lldb_bx_i386, lldb_cx_i386, lldb_dx_i386, + lldb_di_i386, lldb_si_i386, lldb_bp_i386, lldb_sp_i386, + lldb_ah_i386, lldb_bh_i386, lldb_ch_i386, lldb_dh_i386, + lldb_al_i386, lldb_bl_i386, lldb_cl_i386, lldb_dl_i386, + LLDB_INVALID_REGNUM // register sets need to end with this flag +}; +static_assert((sizeof(g_gpr_regnums_i386) / sizeof(g_gpr_regnums_i386[0])) - + 1 == + k_num_gpr_registers_i386, + "g_gpr_regnums_i386 has wrong number of register infos"); + +// x86 32-bit floating point registers. +static const uint32_t g_fpu_regnums_i386[] = { + lldb_fctrl_i386, lldb_fstat_i386, lldb_ftag_i386, lldb_fop_i386, + lldb_fiseg_i386, lldb_fioff_i386, lldb_foseg_i386, lldb_fooff_i386, + lldb_mxcsr_i386, lldb_mxcsrmask_i386, lldb_st0_i386, lldb_st1_i386, + lldb_st2_i386, lldb_st3_i386, lldb_st4_i386, lldb_st5_i386, + lldb_st6_i386, lldb_st7_i386, lldb_mm0_i386, lldb_mm1_i386, + lldb_mm2_i386, lldb_mm3_i386, lldb_mm4_i386, lldb_mm5_i386, + lldb_mm6_i386, lldb_mm7_i386, lldb_xmm0_i386, lldb_xmm1_i386, + lldb_xmm2_i386, lldb_xmm3_i386, lldb_xmm4_i386, lldb_xmm5_i386, + lldb_xmm6_i386, lldb_xmm7_i386, + LLDB_INVALID_REGNUM // register sets need to end with this flag +}; +static_assert((sizeof(g_fpu_regnums_i386) / sizeof(g_fpu_regnums_i386[0])) - + 1 == + k_num_fpr_registers_i386, + "g_fpu_regnums_i386 has wrong number of register infos"); + +static const uint32_t g_avx_regnums_i386[] = { + lldb_ymm0_i386, lldb_ymm1_i386, lldb_ymm2_i386, lldb_ymm3_i386, + lldb_ymm4_i386, lldb_ymm5_i386, lldb_ymm6_i386, lldb_ymm7_i386, + LLDB_INVALID_REGNUM // register sets need to end with this flag +}; +static_assert((sizeof(g_avx_regnums_i386) / sizeof(g_avx_regnums_i386[0])) - + 1 == + k_num_avx_registers_i386, + "g_avx_regnums_i386 has wrong number of register infos"); + +static const uint32_t g_mpx_regnums_i386[] = { + // Note: we currently do not provide them but this is needed to avoid + // unnamed groups in SBFrame::GetRegisterContext(). + lldb_bnd0_i386, lldb_bnd1_i386, lldb_bnd2_i386, + lldb_bnd3_i386, lldb_bndcfgu_i386, lldb_bndstatus_i386, + LLDB_INVALID_REGNUM // register sets need to end with this flag +}; +static_assert((sizeof(g_mpx_regnums_i386) / sizeof(g_mpx_regnums_i386[0])) - + 1 == + k_num_mpx_registers_i386, + "g_mpx_regnums_i386 has wrong number of register infos"); + +// x86 debug registers. +static const uint32_t g_dbr_regnums_i386[] = { + lldb_dr0_i386, lldb_dr1_i386, lldb_dr2_i386, lldb_dr3_i386, + lldb_dr4_i386, lldb_dr5_i386, lldb_dr6_i386, lldb_dr7_i386, + LLDB_INVALID_REGNUM // register sets need to end with this flag +}; +static_assert((sizeof(g_dbr_regnums_i386) / sizeof(g_dbr_regnums_i386[0])) - + 1 == + k_num_dbr_registers_i386, + "g_dbr_regnums_i386 has wrong number of register infos"); + +// Number of register sets provided by this context. +enum { k_num_register_sets = 5 }; + +// Register sets for x86 32-bit. +static const RegisterSet g_reg_sets_i386[k_num_register_sets] = { + {"General Purpose Registers", "gpr", k_num_gpr_registers_i386, + g_gpr_regnums_i386}, + {"Floating Point Registers", "fpu", k_num_fpr_registers_i386, + g_fpu_regnums_i386}, + {"Debug Registers", "dbr", k_num_dbr_registers_i386, g_dbr_regnums_i386}, + {"Advanced Vector Extensions", "avx", k_num_avx_registers_i386, + g_avx_regnums_i386}, + {"Memory Protection Extensions", "mpx", k_num_mpx_registers_i386, + g_mpx_regnums_i386}, +}; + +// Register sets for x86 64-bit. +static const RegisterSet g_reg_sets_x86_64[k_num_register_sets] = { + {"General Purpose Registers", "gpr", k_num_gpr_registers_x86_64, + g_gpr_regnums_x86_64}, + {"Floating Point Registers", "fpu", k_num_fpr_registers_x86_64, + g_fpu_regnums_x86_64}, + {"Debug Registers", "dbr", k_num_dbr_registers_x86_64, + g_dbr_regnums_x86_64}, + {"Advanced Vector Extensions", "avx", k_num_avx_registers_x86_64, + g_avx_regnums_x86_64}, + {"Memory Protection Extensions", "mpx", k_num_mpx_registers_x86_64, + g_mpx_regnums_x86_64}, +}; + +#define REG_CONTEXT_SIZE (GetRegisterInfoInterface().GetGPRSize()) + +NativeRegisterContextFreeBSD * +NativeRegisterContextFreeBSD::CreateHostNativeRegisterContextFreeBSD( + const ArchSpec &target_arch, NativeThreadProtocol &native_thread) { + return new NativeRegisterContextFreeBSD_x86_64(target_arch, native_thread); +} + +// NativeRegisterContextFreeBSD_x86_64 members. + +static RegisterInfoInterface * +CreateRegisterInfoInterface(const ArchSpec &target_arch) { + if (HostInfo::GetArchitecture().GetAddressByteSize() == 4) { + // 32-bit hosts run with a RegisterContextFreeBSD_i386 context. + return new RegisterContextFreeBSD_i386(target_arch); + } else { + assert((HostInfo::GetArchitecture().GetAddressByteSize() == 8) && + "Register setting path assumes this is a 64-bit host"); + // X86_64 hosts know how to work with 64-bit and 32-bit EXEs using the + // x86_64 register context. + return new RegisterContextFreeBSD_x86_64(target_arch); + } +} + +NativeRegisterContextFreeBSD_x86_64::NativeRegisterContextFreeBSD_x86_64( + const ArchSpec &target_arch, NativeThreadProtocol &native_thread) + : NativeRegisterContextRegisterInfo( + native_thread, CreateRegisterInfoInterface(target_arch)), + NativeRegisterContextDBReg_x86(native_thread), m_regset_offsets({0}) { + assert(m_gpr.size() == GetRegisterInfoInterface().GetGPRSize()); + std::array first_regnos; + + switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) { + case llvm::Triple::x86: + first_regnos[FPRegSet] = lldb_fctrl_i386; + first_regnos[DBRegSet] = lldb_dr0_i386; + break; + case llvm::Triple::x86_64: + first_regnos[FPRegSet] = lldb_fctrl_x86_64; + first_regnos[DBRegSet] = lldb_dr0_x86_64; + break; + default: + llvm_unreachable("Unhandled target architecture."); + } + + for (int i : {FPRegSet, DBRegSet}) + m_regset_offsets[i] = GetRegisterInfoInterface() + .GetRegisterInfo()[first_regnos[i]] + .byte_offset; +} + +uint32_t NativeRegisterContextFreeBSD_x86_64::GetRegisterSetCount() const { + return k_num_register_sets; +} + +const RegisterSet * +NativeRegisterContextFreeBSD_x86_64::GetRegisterSet(uint32_t set_index) const { + switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) { + case llvm::Triple::x86: + return &g_reg_sets_i386[set_index]; + case llvm::Triple::x86_64: + return &g_reg_sets_x86_64[set_index]; + default: + llvm_unreachable("Unhandled target architecture."); + } +} + +llvm::Optional +NativeRegisterContextFreeBSD_x86_64::GetSetForNativeRegNum( + uint32_t reg_num) const { + switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) { + case llvm::Triple::x86: + if (reg_num >= k_first_gpr_i386 && reg_num <= k_last_gpr_i386) + return GPRegSet; + if (reg_num >= k_first_fpr_i386 && reg_num <= k_last_fpr_i386) + return FPRegSet; + if (reg_num >= k_first_avx_i386 && reg_num <= k_last_avx_i386) + return YMMRegSet; + if (reg_num >= k_first_mpxr_i386 && reg_num <= k_last_mpxr_i386) + return llvm::None; // MPXR + if (reg_num >= k_first_mpxc_i386 && reg_num <= k_last_mpxc_i386) + return llvm::None; // MPXC + if (reg_num >= k_first_dbr_i386 && reg_num <= k_last_dbr_i386) + return DBRegSet; // DBR + break; + case llvm::Triple::x86_64: + if (reg_num >= k_first_gpr_x86_64 && reg_num <= k_last_gpr_x86_64) + return GPRegSet; + if (reg_num >= k_first_fpr_x86_64 && reg_num <= k_last_fpr_x86_64) + return FPRegSet; + if (reg_num >= k_first_avx_x86_64 && reg_num <= k_last_avx_x86_64) + return YMMRegSet; + if (reg_num >= k_first_mpxr_x86_64 && reg_num <= k_last_mpxr_x86_64) + return llvm::None; // MPXR + if (reg_num >= k_first_mpxc_x86_64 && reg_num <= k_last_mpxc_x86_64) + return llvm::None; // MPXC + if (reg_num >= k_first_dbr_x86_64 && reg_num <= k_last_dbr_x86_64) + return DBRegSet; // DBR + break; + default: + llvm_unreachable("Unhandled target architecture."); + } + + llvm_unreachable("Register does not belong to any register set"); +} + +Status NativeRegisterContextFreeBSD_x86_64::ReadRegisterSet(RegSetKind set) { + switch (set) { + case GPRegSet: + return NativeProcessFreeBSD::PtraceWrapper(PT_GETREGS, m_thread.GetID(), + m_gpr.data()); + case FPRegSet: +#if defined(__x86_64__) + return NativeProcessFreeBSD::PtraceWrapper(PT_GETFPREGS, m_thread.GetID(), + m_fpr.data()); +#else + return NativeProcessFreeBSD::PtraceWrapper(PT_GETXMMREGS, m_thread.GetID(), + m_fpr.data()); +#endif + case DBRegSet: + return NativeProcessFreeBSD::PtraceWrapper(PT_GETDBREGS, m_thread.GetID(), + m_dbr.data()); + case YMMRegSet: + case MPXRegSet: { + struct ptrace_xstate_info info; + Status ret = NativeProcessFreeBSD::PtraceWrapper( + PT_GETXSTATE_INFO, GetProcessPid(), &info, sizeof(info)); + if (!ret.Success()) + return ret; + + assert(info.xsave_mask & XFEATURE_ENABLED_X87); + assert(info.xsave_mask & XFEATURE_ENABLED_SSE); + + m_xsave_offsets[YMMRegSet] = LLDB_INVALID_XSAVE_OFFSET; + if (info.xsave_mask & XFEATURE_ENABLED_YMM_HI128) { + uint32_t eax, ecx, edx; + __get_cpuid_count(0x0D, 2, &eax, &m_xsave_offsets[YMMRegSet], &ecx, &edx); + } + + m_xsave.resize(info.xsave_len); + return NativeProcessFreeBSD::PtraceWrapper(PT_GETXSTATE, GetProcessPid(), + m_xsave.data(), m_xsave.size()); + } + } + llvm_unreachable("NativeRegisterContextFreeBSD_x86_64::ReadRegisterSet"); +} + +Status NativeRegisterContextFreeBSD_x86_64::WriteRegisterSet(RegSetKind set) { + switch (set) { + case GPRegSet: + return NativeProcessFreeBSD::PtraceWrapper(PT_SETREGS, m_thread.GetID(), + m_gpr.data()); + case FPRegSet: +#if defined(__x86_64__) + return NativeProcessFreeBSD::PtraceWrapper(PT_SETFPREGS, m_thread.GetID(), + m_fpr.data()); +#else + return NativeProcessFreeBSD::PtraceWrapper(PT_SETXMMREGS, m_thread.GetID(), + m_fpr.data()); +#endif + case DBRegSet: + return NativeProcessFreeBSD::PtraceWrapper(PT_SETDBREGS, m_thread.GetID(), + m_dbr.data()); + case YMMRegSet: + case MPXRegSet: + // ReadRegisterSet() must always be called before WriteRegisterSet(). + assert(m_xsave.size() > 0); + return NativeProcessFreeBSD::PtraceWrapper(PT_SETXSTATE, GetProcessPid(), + m_xsave.data(), m_xsave.size()); + } + llvm_unreachable("NativeRegisterContextFreeBSD_x86_64::WriteRegisterSet"); +} + +Status +NativeRegisterContextFreeBSD_x86_64::ReadRegister(const RegisterInfo *reg_info, + RegisterValue ®_value) { + Status error; + + if (!reg_info) { + error.SetErrorString("reg_info NULL"); + return error; + } + + uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; + if (reg == LLDB_INVALID_REGNUM) { + // This is likely an internal register for lldb use only and should not be + // directly queried. + error.SetErrorStringWithFormat("register \"%s\" is an internal-only lldb " + "register, cannot read directly", + reg_info->name); + return error; + } + + llvm::Optional opt_set = GetSetForNativeRegNum(reg); + if (!opt_set) { + // This is likely an internal register for lldb use only and should not be + // directly queried. + error.SetErrorStringWithFormat("register \"%s\" is in unrecognized set", + reg_info->name); + return error; + } + + RegSetKind set = opt_set.getValue(); + error = ReadRegisterSet(set); + if (error.Fail()) + return error; + + switch (set) { + case GPRegSet: + case FPRegSet: + case DBRegSet: { + void *data = GetOffsetRegSetData(set, reg_info->byte_offset); + FXSAVE *fpr = reinterpret_cast(m_fpr.data()); + if (data == &fpr->ftag) // ftag + reg_value.SetUInt16( + AbridgedToFullTagWord(fpr->ftag, fpr->fstat, fpr->stmm)); + else + reg_value.SetBytes(data, reg_info->byte_size, endian::InlHostByteOrder()); + break; + } + case YMMRegSet: { + llvm::Optional ymm_reg = GetYMMSplitReg(reg); + if (!ymm_reg) { + error.SetErrorStringWithFormat( + "register \"%s\" not supported by CPU/kernel", reg_info->name); + } else { + YMMReg ymm = XStateToYMM(ymm_reg->xmm, ymm_reg->ymm_hi); + reg_value.SetBytes(ymm.bytes, reg_info->byte_size, + endian::InlHostByteOrder()); + } + break; + } + case MPXRegSet: + llvm_unreachable("MPX regset should have returned error"); + } + + return error; +} + +Status NativeRegisterContextFreeBSD_x86_64::WriteRegister( + const RegisterInfo *reg_info, const RegisterValue ®_value) { + + Status error; + + if (!reg_info) { + error.SetErrorString("reg_info NULL"); + return error; + } + + uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; + if (reg == LLDB_INVALID_REGNUM) { + // This is likely an internal register for lldb use only and should not be + // directly queried. + error.SetErrorStringWithFormat("register \"%s\" is an internal-only lldb " + "register, cannot read directly", + reg_info->name); + return error; + } + + llvm::Optional opt_set = GetSetForNativeRegNum(reg); + if (!opt_set) { + // This is likely an internal register for lldb use only and should not be + // directly queried. + error.SetErrorStringWithFormat("register \"%s\" is in unrecognized set", + reg_info->name); + return error; + } + + RegSetKind set = opt_set.getValue(); + error = ReadRegisterSet(set); + if (error.Fail()) + return error; + + switch (set) { + case GPRegSet: + case FPRegSet: + case DBRegSet: { + void *data = GetOffsetRegSetData(set, reg_info->byte_offset); + FXSAVE *fpr = reinterpret_cast(m_fpr.data()); + if (data == &fpr->ftag) // ftag + fpr->ftag = FullToAbridgedTagWord(reg_value.GetAsUInt16()); + else + ::memcpy(data, reg_value.GetBytes(), reg_value.GetByteSize()); + break; + } + case YMMRegSet: { + llvm::Optional ymm_reg = GetYMMSplitReg(reg); + if (!ymm_reg) { + error.SetErrorStringWithFormat( + "register \"%s\" not supported by CPU/kernel", reg_info->name); + } else { + YMMReg ymm; + ::memcpy(ymm.bytes, reg_value.GetBytes(), reg_value.GetByteSize()); + YMMToXState(ymm, ymm_reg->xmm, ymm_reg->ymm_hi); + } + break; + } + case MPXRegSet: + llvm_unreachable("MPX regset should have returned error"); + } + + return WriteRegisterSet(set); +} + +Status NativeRegisterContextFreeBSD_x86_64::ReadAllRegisterValues( + lldb::DataBufferSP &data_sp) { + Status error; + + data_sp.reset(new DataBufferHeap(REG_CONTEXT_SIZE, 0)); + error = ReadRegisterSet(GPRegSet); + if (error.Fail()) + return error; + + uint8_t *dst = data_sp->GetBytes(); + ::memcpy(dst, m_gpr.data(), GetRegisterInfoInterface().GetGPRSize()); + dst += GetRegisterInfoInterface().GetGPRSize(); + + return error; +} + +Status NativeRegisterContextFreeBSD_x86_64::WriteAllRegisterValues( + const lldb::DataBufferSP &data_sp) { + Status error; + + if (!data_sp) { + error.SetErrorStringWithFormat( + "NativeRegisterContextFreeBSD_x86_64::%s invalid data_sp provided", + __FUNCTION__); + return error; + } + + if (data_sp->GetByteSize() != REG_CONTEXT_SIZE) { + error.SetErrorStringWithFormat( + "NativeRegisterContextFreeBSD_x86_64::%s data_sp contained mismatched " + "data size, expected %zu, actual %" PRIu64, + __FUNCTION__, REG_CONTEXT_SIZE, data_sp->GetByteSize()); + return error; + } + + uint8_t *src = data_sp->GetBytes(); + if (src == nullptr) { + error.SetErrorStringWithFormat("NativeRegisterContextFreeBSD_x86_64::%s " + "DataBuffer::GetBytes() returned a null " + "pointer", + __FUNCTION__); + return error; + } + ::memcpy(m_gpr.data(), src, GetRegisterInfoInterface().GetGPRSize()); + + error = WriteRegisterSet(GPRegSet); + if (error.Fail()) + return error; + src += GetRegisterInfoInterface().GetGPRSize(); + + return error; +} + +llvm::Error NativeRegisterContextFreeBSD_x86_64::CopyHardwareWatchpointsFrom( + NativeRegisterContextFreeBSD &source) { + auto &r_source = static_cast(source); + // NB: This implicitly reads the whole dbreg set. + RegisterValue dr7; + Status res = r_source.ReadRegister(GetDR(7), dr7); + if (!res.Fail()) { + // copy dbregs only if any watchpoints were set + if ((dr7.GetAsUInt64() & 0xFF) == 0) + return llvm::Error::success(); + + m_dbr = r_source.m_dbr; + res = WriteRegisterSet(DBRegSet); + } + return res.ToError(); +} + +uint8_t * +NativeRegisterContextFreeBSD_x86_64::GetOffsetRegSetData(RegSetKind set, + size_t reg_offset) { + uint8_t *base; + switch (set) { + case GPRegSet: + base = m_gpr.data(); + break; + case FPRegSet: + base = m_fpr.data(); + break; + case DBRegSet: + base = m_dbr.data(); + break; + case YMMRegSet: + llvm_unreachable("GetRegSetData() is unsuitable for this regset."); + case MPXRegSet: + llvm_unreachable("MPX regset should have returned error"); + } + assert(reg_offset >= m_regset_offsets[set]); + return base + (reg_offset - m_regset_offsets[set]); +} + +llvm::Optional +NativeRegisterContextFreeBSD_x86_64::GetYMMSplitReg(uint32_t reg) { + uint32_t offset = m_xsave_offsets[YMMRegSet]; + if (offset == LLDB_INVALID_XSAVE_OFFSET) + return llvm::None; + + uint32_t reg_index; + switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) { + case llvm::Triple::x86: + reg_index = reg - lldb_ymm0_i386; + break; + case llvm::Triple::x86_64: + reg_index = reg - lldb_ymm0_x86_64; + break; + default: + llvm_unreachable("Unhandled target architecture."); + } + + auto *fpreg = reinterpret_cast(m_xsave.data()); + auto *ymmreg = reinterpret_cast(m_xsave.data() + offset); + + return YMMSplitPtr{&fpreg->sv_xmm[reg_index], &ymmreg[reg_index]}; +} + +#endif // defined(__x86_64__) diff --git a/gnu/llvm/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_x86_64.h b/gnu/llvm/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_x86_64.h new file mode 100644 index 00000000000..efd0f91f77b --- /dev/null +++ b/gnu/llvm/lldb/source/Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD_x86_64.h @@ -0,0 +1,96 @@ +//===-- NativeRegisterContextFreeBSD_x86_64.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 +// +//===----------------------------------------------------------------------===// + +#if defined(__i386__) || defined(__x86_64__) + +#ifndef lldb_NativeRegisterContextFreeBSD_x86_64_h +#define lldb_NativeRegisterContextFreeBSD_x86_64_h + +// clang-format off +#include +#include +#include +#include +// clang-format on + +#include + +#include "Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD.h" +#include "Plugins/Process/Utility/RegisterContext_x86.h" +#include "Plugins/Process/Utility/NativeRegisterContextDBReg_x86.h" +#include "Plugins/Process/Utility/lldb-x86-register-enums.h" + +#define LLDB_INVALID_XSAVE_OFFSET UINT32_MAX + +namespace lldb_private { +namespace process_freebsd { + +class NativeProcessFreeBSD; + +class NativeRegisterContextFreeBSD_x86_64 + : public NativeRegisterContextFreeBSD, + public NativeRegisterContextDBReg_x86 { +public: + NativeRegisterContextFreeBSD_x86_64(const ArchSpec &target_arch, + NativeThreadProtocol &native_thread); + uint32_t GetRegisterSetCount() const override; + + const RegisterSet *GetRegisterSet(uint32_t set_index) const override; + + Status ReadRegister(const RegisterInfo *reg_info, + RegisterValue ®_value) override; + + Status WriteRegister(const RegisterInfo *reg_info, + const RegisterValue ®_value) override; + + Status ReadAllRegisterValues(lldb::DataBufferSP &data_sp) override; + + Status WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override; + + llvm::Error + CopyHardwareWatchpointsFrom(NativeRegisterContextFreeBSD &source) override; + +private: + // Private member types. + enum RegSetKind { + GPRegSet, + FPRegSet, + DBRegSet, + YMMRegSet, + MPXRegSet, + MaxRegSet = MPXRegSet, + }; + + // Private member variables. + std::array m_gpr; + std::array m_fpr; // FXSAVE + std::array m_dbr; + std::vector m_xsave; + std::array m_xsave_offsets; + std::array m_regset_offsets; + + llvm::Optional GetSetForNativeRegNum(uint32_t reg_num) const; + + Status ReadRegisterSet(RegSetKind set); + Status WriteRegisterSet(RegSetKind set); + + uint8_t *GetOffsetRegSetData(RegSetKind set, size_t reg_offset); + + struct YMMSplitPtr { + void *xmm; + void *ymm_hi; + }; + llvm::Optional GetYMMSplitReg(uint32_t reg); +}; + +} // namespace process_freebsd +} // namespace lldb_private + +#endif // #ifndef lldb_NativeRegisterContextFreeBSD_x86_64_h + +#endif // defined(__x86_64__) diff --git a/gnu/llvm/lldb/source/Plugins/Process/FreeBSD/NativeThreadFreeBSD.cpp b/gnu/llvm/lldb/source/Plugins/Process/FreeBSD/NativeThreadFreeBSD.cpp new file mode 100644 index 00000000000..80b3527aebc --- /dev/null +++ b/gnu/llvm/lldb/source/Plugins/Process/FreeBSD/NativeThreadFreeBSD.cpp @@ -0,0 +1,315 @@ +//===-- NativeThreadFreeBSD.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 "NativeThreadFreeBSD.h" +#include "NativeRegisterContextFreeBSD.h" + +#include "NativeProcessFreeBSD.h" + +#include "Plugins/Process/POSIX/CrashReason.h" +#include "Plugins/Process/POSIX/ProcessPOSIXLog.h" +#include "lldb/Utility/LLDBAssert.h" +#include "lldb/Utility/RegisterValue.h" +#include "lldb/Utility/State.h" +#include "llvm/Support/Errno.h" + +// clang-format off +#include +#include +#include +#include +// clang-format on + +#include +#include + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::process_freebsd; + +NativeThreadFreeBSD::NativeThreadFreeBSD(NativeProcessFreeBSD &process, + lldb::tid_t tid) + : NativeThreadProtocol(process, tid), m_state(StateType::eStateInvalid), + m_stop_info(), + m_reg_context_up( + NativeRegisterContextFreeBSD::CreateHostNativeRegisterContextFreeBSD( + process.GetArchitecture(), *this)), + m_stop_description() {} + +Status NativeThreadFreeBSD::Resume() { + Status ret = NativeProcessFreeBSD::PtraceWrapper(PT_RESUME, GetID()); + if (!ret.Success()) + return ret; + ret = NativeProcessFreeBSD::PtraceWrapper(PT_CLEARSTEP, GetID()); + // we can get EINVAL if the architecture in question does not support + // hardware single-stepping -- that's fine, we have nothing to clear + // then + if (ret.GetError() == EINVAL) + ret.Clear(); + if (ret.Success()) + SetRunning(); + return ret; +} + +Status NativeThreadFreeBSD::SingleStep() { + Status ret = NativeProcessFreeBSD::PtraceWrapper(PT_RESUME, GetID()); + if (!ret.Success()) + return ret; + ret = NativeProcessFreeBSD::PtraceWrapper(PT_SETSTEP, GetID()); + if (ret.Success()) + SetStepping(); + return ret; +} + +Status NativeThreadFreeBSD::Suspend() { + Status ret = NativeProcessFreeBSD::PtraceWrapper(PT_SUSPEND, GetID()); + if (ret.Success()) + SetStopped(); + return ret; +} + +void NativeThreadFreeBSD::SetStoppedBySignal(uint32_t signo, + const siginfo_t *info) { + Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD)); + LLDB_LOG(log, "tid = {0} in called with signal {1}", GetID(), signo); + + SetStopped(); + + m_stop_info.reason = StopReason::eStopReasonSignal; + m_stop_info.details.signal.signo = signo; + + m_stop_description.clear(); + if (info) { + switch (signo) { + case SIGSEGV: + case SIGBUS: + case SIGFPE: + case SIGILL: + const auto reason = GetCrashReason(*info); + m_stop_description = GetCrashReasonString(reason, *info); + break; + } + } +} + +void NativeThreadFreeBSD::SetStoppedByBreakpoint() { + SetStopped(); + m_stop_info.reason = StopReason::eStopReasonBreakpoint; + m_stop_info.details.signal.signo = SIGTRAP; +} + +void NativeThreadFreeBSD::SetStoppedByTrace() { + SetStopped(); + m_stop_info.reason = StopReason::eStopReasonTrace; + m_stop_info.details.signal.signo = SIGTRAP; +} + +void NativeThreadFreeBSD::SetStoppedByExec() { + SetStopped(); + m_stop_info.reason = StopReason::eStopReasonExec; + m_stop_info.details.signal.signo = SIGTRAP; +} + +void NativeThreadFreeBSD::SetStoppedByWatchpoint(uint32_t wp_index) { + lldbassert(wp_index != LLDB_INVALID_INDEX32 && "wp_index cannot be invalid"); + + std::ostringstream ostr; + ostr << GetRegisterContext().GetWatchpointAddress(wp_index) << " "; + ostr << wp_index; + + ostr << " " << GetRegisterContext().GetWatchpointHitAddress(wp_index); + + SetStopped(); + m_stop_description = ostr.str(); + m_stop_info.reason = StopReason::eStopReasonWatchpoint; + m_stop_info.details.signal.signo = SIGTRAP; +} + +void NativeThreadFreeBSD::SetStoppedByFork(lldb::pid_t child_pid, + lldb::tid_t child_tid) { + SetStopped(); + + m_stop_info.reason = StopReason::eStopReasonFork; + m_stop_info.details.fork.child_pid = child_pid; + m_stop_info.details.fork.child_tid = child_tid; +} + +void NativeThreadFreeBSD::SetStoppedByVFork(lldb::pid_t child_pid, + lldb::tid_t child_tid) { + SetStopped(); + + m_stop_info.reason = StopReason::eStopReasonVFork; + m_stop_info.details.fork.child_pid = child_pid; + m_stop_info.details.fork.child_tid = child_tid; +} + +void NativeThreadFreeBSD::SetStoppedByVForkDone() { + SetStopped(); + + m_stop_info.reason = StopReason::eStopReasonVForkDone; +} + +void NativeThreadFreeBSD::SetStoppedWithNoReason() { + SetStopped(); + + m_stop_info.reason = StopReason::eStopReasonNone; + m_stop_info.details.signal.signo = 0; +} + +void NativeThreadFreeBSD::SetStopped() { + const StateType new_state = StateType::eStateStopped; + m_state = new_state; + m_stop_description.clear(); +} + +void NativeThreadFreeBSD::SetRunning() { + m_state = StateType::eStateRunning; + m_stop_info.reason = StopReason::eStopReasonNone; +} + +void NativeThreadFreeBSD::SetStepping() { + m_state = StateType::eStateStepping; + m_stop_info.reason = StopReason::eStopReasonNone; +} + +std::string NativeThreadFreeBSD::GetName() { + Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD)); + + std::vector kp; + int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PID | KERN_PROC_INC_THREAD, + static_cast(GetProcess().GetID())}; + + while (1) { + size_t len = kp.size() * sizeof(struct kinfo_proc); + void *ptr = len == 0 ? nullptr : kp.data(); + int error = ::sysctl(mib, 4, ptr, &len, nullptr, 0); + if (ptr == nullptr || (error != 0 && errno == ENOMEM)) { + kp.resize(len / sizeof(struct kinfo_proc)); + continue; + } + if (error != 0) { + len = 0; + LLDB_LOG(log, "tid = {0} in state {1} failed to get thread name: {2}", + GetID(), m_state, strerror(errno)); + } + kp.resize(len / sizeof(struct kinfo_proc)); + break; + } + + for (auto &procinfo : kp) { + if (procinfo.ki_tid == static_cast(GetID())) + return procinfo.ki_tdname; + } + + return ""; +} + +lldb::StateType NativeThreadFreeBSD::GetState() { return m_state; } + +bool NativeThreadFreeBSD::GetStopReason(ThreadStopInfo &stop_info, + std::string &description) { + Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD)); + description.clear(); + + switch (m_state) { + case eStateStopped: + case eStateCrashed: + case eStateExited: + case eStateSuspended: + case eStateUnloaded: + stop_info = m_stop_info; + description = m_stop_description; + + return true; + + case eStateInvalid: + case eStateConnected: + case eStateAttaching: + case eStateLaunching: + case eStateRunning: + case eStateStepping: + case eStateDetached: + LLDB_LOG(log, "tid = {0} in state {1} cannot answer stop reason", GetID(), + StateAsCString(m_state)); + return false; + } + llvm_unreachable("unhandled StateType!"); +} + +NativeRegisterContextFreeBSD &NativeThreadFreeBSD::GetRegisterContext() { + assert(m_reg_context_up); + return *m_reg_context_up; +} + +Status NativeThreadFreeBSD::SetWatchpoint(lldb::addr_t addr, size_t size, + uint32_t watch_flags, bool hardware) { + assert(m_state == eStateStopped); + if (!hardware) + return Status("not implemented"); + Status error = RemoveWatchpoint(addr); + if (error.Fail()) + return error; + uint32_t wp_index = + GetRegisterContext().SetHardwareWatchpoint(addr, size, watch_flags); + if (wp_index == LLDB_INVALID_INDEX32) + return Status("Setting hardware watchpoint failed."); + m_watchpoint_index_map.insert({addr, wp_index}); + return Status(); +} + +Status NativeThreadFreeBSD::RemoveWatchpoint(lldb::addr_t addr) { + auto wp = m_watchpoint_index_map.find(addr); + if (wp == m_watchpoint_index_map.end()) + return Status(); + uint32_t wp_index = wp->second; + m_watchpoint_index_map.erase(wp); + if (GetRegisterContext().ClearHardwareWatchpoint(wp_index)) + return Status(); + return Status("Clearing hardware watchpoint failed."); +} + +Status NativeThreadFreeBSD::SetHardwareBreakpoint(lldb::addr_t addr, + size_t size) { + assert(m_state == eStateStopped); + Status error = RemoveHardwareBreakpoint(addr); + if (error.Fail()) + return error; + + uint32_t bp_index = GetRegisterContext().SetHardwareBreakpoint(addr, size); + + if (bp_index == LLDB_INVALID_INDEX32) + return Status("Setting hardware breakpoint failed."); + + m_hw_break_index_map.insert({addr, bp_index}); + return Status(); +} + +Status NativeThreadFreeBSD::RemoveHardwareBreakpoint(lldb::addr_t addr) { + auto bp = m_hw_break_index_map.find(addr); + if (bp == m_hw_break_index_map.end()) + return Status(); + + uint32_t bp_index = bp->second; + if (GetRegisterContext().ClearHardwareBreakpoint(bp_index)) { + m_hw_break_index_map.erase(bp); + return Status(); + } + + return Status("Clearing hardware breakpoint failed."); +} + +llvm::Error +NativeThreadFreeBSD::CopyWatchpointsFrom(NativeThreadFreeBSD &source) { + llvm::Error s = GetRegisterContext().CopyHardwareWatchpointsFrom( + source.GetRegisterContext()); + if (!s) { + m_watchpoint_index_map = source.m_watchpoint_index_map; + m_hw_break_index_map = source.m_hw_break_index_map; + } + return s; +} diff --git a/gnu/llvm/lldb/source/Plugins/Process/FreeBSD/NativeThreadFreeBSD.h b/gnu/llvm/lldb/source/Plugins/Process/FreeBSD/NativeThreadFreeBSD.h new file mode 100644 index 00000000000..3ec6daa409e --- /dev/null +++ b/gnu/llvm/lldb/source/Plugins/Process/FreeBSD/NativeThreadFreeBSD.h @@ -0,0 +1,86 @@ +//===-- NativeThreadFreeBSD.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 liblldb_NativeThreadFreeBSD_H_ +#define liblldb_NativeThreadFreeBSD_H_ + +#include "lldb/Host/common/NativeThreadProtocol.h" + +#include "Plugins/Process/FreeBSD/NativeRegisterContextFreeBSD.h" + +#include +#include +#include + +namespace lldb_private { +namespace process_freebsd { + +class NativeProcessFreeBSD; + +class NativeThreadFreeBSD : public NativeThreadProtocol { + friend class NativeProcessFreeBSD; + +public: + NativeThreadFreeBSD(NativeProcessFreeBSD &process, lldb::tid_t tid); + + // NativeThreadProtocol Interface + std::string GetName() override; + + lldb::StateType GetState() override; + + bool GetStopReason(ThreadStopInfo &stop_info, + std::string &description) override; + + NativeRegisterContextFreeBSD &GetRegisterContext() override; + + Status SetWatchpoint(lldb::addr_t addr, size_t size, uint32_t watch_flags, + bool hardware) override; + + Status RemoveWatchpoint(lldb::addr_t addr) override; + + Status SetHardwareBreakpoint(lldb::addr_t addr, size_t size) override; + + Status RemoveHardwareBreakpoint(lldb::addr_t addr) override; + +private: + // Interface for friend classes + + Status Resume(); + Status SingleStep(); + Status Suspend(); + + void SetStoppedBySignal(uint32_t signo, const siginfo_t *info = nullptr); + void SetStoppedByBreakpoint(); + void SetStoppedByTrace(); + void SetStoppedByExec(); + void SetStoppedByWatchpoint(uint32_t wp_index); + void SetStoppedByFork(lldb::pid_t child_pid, lldb::tid_t child_tid); + void SetStoppedByVFork(lldb::pid_t child_pid, lldb::tid_t child_tid); + void SetStoppedByVForkDone(); + void SetStoppedWithNoReason(); + void SetStopped(); + void SetRunning(); + void SetStepping(); + + llvm::Error CopyWatchpointsFrom(NativeThreadFreeBSD &source); + + // Member Variables + lldb::StateType m_state; + ThreadStopInfo m_stop_info; + std::unique_ptr m_reg_context_up; + std::string m_stop_description; + using WatchpointIndexMap = std::map; + WatchpointIndexMap m_watchpoint_index_map; + WatchpointIndexMap m_hw_break_index_map; +}; + +typedef std::shared_ptr NativeThreadFreeBSDSP; +} // namespace process_freebsd +} // namespace lldb_private + +#endif // #ifndef liblldb_NativeThreadFreeBSD_H_ diff --git a/gnu/llvm/lldb/source/Plugins/Process/Linux/CMakeLists.txt b/gnu/llvm/lldb/source/Plugins/Process/Linux/CMakeLists.txt index dd2a88957f4..c4edc57a8a2 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/Linux/CMakeLists.txt +++ b/gnu/llvm/lldb/source/Plugins/Process/Linux/CMakeLists.txt @@ -1,14 +1,13 @@ add_lldb_library(lldbPluginProcessLinux + IntelPTManager.cpp NativeProcessLinux.cpp NativeRegisterContextLinux.cpp NativeRegisterContextLinux_arm.cpp NativeRegisterContextLinux_arm64.cpp - NativeRegisterContextLinux_mips64.cpp NativeRegisterContextLinux_ppc64le.cpp NativeRegisterContextLinux_s390x.cpp NativeRegisterContextLinux_x86_64.cpp NativeThreadLinux.cpp - ProcessorTrace.cpp SingleStepCheck.cpp LINK_LIBS diff --git a/gnu/llvm/lldb/source/Plugins/Process/Linux/IntelPTManager.cpp b/gnu/llvm/lldb/source/Plugins/Process/Linux/IntelPTManager.cpp new file mode 100644 index 00000000000..0bd48933d4d --- /dev/null +++ b/gnu/llvm/lldb/source/Plugins/Process/Linux/IntelPTManager.cpp @@ -0,0 +1,685 @@ +//===-- IntelPTManager.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 +#include +#include + +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/MathExtras.h" + +#include "IntelPTManager.h" +#include "Plugins/Process/POSIX/ProcessPOSIXLog.h" +#include "lldb/Host/linux/Support.h" +#include "lldb/Utility/StreamString.h" + +#include +#include + +using namespace lldb; +using namespace lldb_private; +using namespace process_linux; +using namespace llvm; + +const char *kOSEventIntelPTTypeFile = + "/sys/bus/event_source/devices/intel_pt/type"; + +const char *kPSBPeriodCapFile = + "/sys/bus/event_source/devices/intel_pt/caps/psb_cyc"; + +const char *kPSBPeriodValidValuesFile = + "/sys/bus/event_source/devices/intel_pt/caps/psb_periods"; + +const char *kTSCBitOffsetFile = + "/sys/bus/event_source/devices/intel_pt/format/tsc"; + +const char *kPSBPeriodBitOffsetFile = + "/sys/bus/event_source/devices/intel_pt/format/psb_period"; + +enum IntelPTConfigFileType { + Hex = 0, + // 0 or 1 + ZeroOne, + Decimal, + // a bit index file always starts with the prefix config: following by an int, + // which represents the offset of the perf_event_attr.config value where to + // store a given configuration. + BitOffset +}; + +static Expected ReadIntelPTConfigFile(const char *file, + IntelPTConfigFileType type) { + ErrorOr> stream = + MemoryBuffer::getFileAsStream(file); + + if (!stream) + return createStringError(inconvertibleErrorCode(), + "Can't open the file '%s'", file); + + uint32_t value = 0; + StringRef text_buffer = stream.get()->getBuffer(); + + if (type == BitOffset) { + const char *prefix = "config:"; + if (!text_buffer.startswith(prefix)) + return createStringError(inconvertibleErrorCode(), + "The file '%s' contents doesn't start with '%s'", + file, prefix); + text_buffer = text_buffer.substr(strlen(prefix)); + } + + auto getRadix = [&]() { + switch (type) { + case Hex: + return 16; + case ZeroOne: + case Decimal: + case BitOffset: + return 10; + } + }; + + auto createError = [&](const char *expected_value_message) { + return createStringError( + inconvertibleErrorCode(), + "The file '%s' has an invalid value. It should be %s.", file, + expected_value_message); + }; + + if (text_buffer.trim().consumeInteger(getRadix(), value) || + (type == ZeroOne && value != 0 && value != 1)) { + switch (type) { + case Hex: + return createError("an unsigned hexadecimal int"); + case ZeroOne: + return createError("0 or 1"); + case Decimal: + case BitOffset: + return createError("an unsigned decimal int"); + } + } + return value; +} +/// Return the Linux perf event type for Intel PT. +static Expected GetOSEventType() { + return ReadIntelPTConfigFile(kOSEventIntelPTTypeFile, + IntelPTConfigFileType::Decimal); +} + +static Error CheckPsbPeriod(size_t psb_period) { + Expected cap = + ReadIntelPTConfigFile(kPSBPeriodCapFile, IntelPTConfigFileType::ZeroOne); + if (!cap) + return cap.takeError(); + if (*cap == 0) + return createStringError(inconvertibleErrorCode(), + "psb_period is unsupported in the system."); + + Expected valid_values = ReadIntelPTConfigFile( + kPSBPeriodValidValuesFile, IntelPTConfigFileType::Hex); + if (!valid_values) + return valid_values.takeError(); + + if (valid_values.get() & (1 << psb_period)) + return Error::success(); + + std::ostringstream error; + // 0 is always a valid value + error << "Invalid psb_period. Valid values are: 0"; + uint32_t mask = valid_values.get(); + while (mask) { + int index = __builtin_ctz(mask); + if (index > 0) + error << ", " << index; + // clear the lowest bit + mask &= mask - 1; + } + error << "."; + return createStringError(inconvertibleErrorCode(), error.str().c_str()); +} + +size_t IntelPTThreadTrace::GetTraceBufferSize() const { + return m_mmap_meta->aux_size; +} + +static Expected +GeneratePerfEventConfigValue(bool enable_tsc, Optional psb_period) { + uint64_t config = 0; + // tsc is always supported + if (enable_tsc) { + if (Expected offset = ReadIntelPTConfigFile( + kTSCBitOffsetFile, IntelPTConfigFileType::BitOffset)) + config |= 1 << *offset; + else + return offset.takeError(); + } + if (psb_period) { + if (Error error = CheckPsbPeriod(*psb_period)) + return std::move(error); + + if (Expected offset = ReadIntelPTConfigFile( + kPSBPeriodBitOffsetFile, IntelPTConfigFileType::BitOffset)) + config |= *psb_period << *offset; + else + return offset.takeError(); + } + return config; +} + +Error IntelPTThreadTrace::StartTrace(lldb::pid_t pid, lldb::tid_t tid, + uint64_t buffer_size, bool enable_tsc, + Optional psb_period) { +#ifndef PERF_ATTR_SIZE_VER5 + llvm_unreachable("Intel PT Linux perf event not supported"); +#else + Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PTRACE)); + + m_tid = tid; + LLDB_LOG(log, "called thread id {0}", tid); + uint64_t page_size = getpagesize(); + + if (__builtin_popcount(buffer_size) != 1 || buffer_size < 4096) { + return createStringError( + inconvertibleErrorCode(), + "The trace buffer size must be a power of 2 greater than or equal to " + "4096 (2^12) bytes. It was %" PRIu64 ".", + buffer_size); + } + uint64_t numpages = static_cast( + llvm::PowerOf2Floor((buffer_size + page_size - 1) / page_size)); + numpages = std::max(1, numpages); + buffer_size = page_size * numpages; + + perf_event_attr attr; + memset(&attr, 0, sizeof(attr)); + attr.size = sizeof(attr); + attr.exclude_kernel = 1; + attr.sample_type = PERF_SAMPLE_TIME; + attr.sample_id_all = 1; + attr.exclude_hv = 1; + attr.exclude_idle = 1; + attr.mmap = 1; + + if (Expected config_value = + GeneratePerfEventConfigValue(enable_tsc, psb_period)) { + attr.config = *config_value; + LLDB_LOG(log, "intel pt config {0}", attr.config); + } else { + return config_value.takeError(); + } + + if (Expected intel_pt_type = GetOSEventType()) { + attr.type = *intel_pt_type; + LLDB_LOG(log, "intel pt type {0}", attr.type); + } else { + return intel_pt_type.takeError(); + } + + LLDB_LOG(log, "buffer size {0} ", buffer_size); + + errno = 0; + auto fd = + syscall(SYS_perf_event_open, &attr, static_cast<::tid_t>(tid), -1, -1, 0); + if (fd == -1) { + LLDB_LOG(log, "syscall error {0}", errno); + return createStringError(inconvertibleErrorCode(), + "perf event syscall failed"); + } + + m_fd = std::unique_ptr(new int(fd), file_close()); + + errno = 0; + auto base = + mmap(nullptr, (buffer_size + page_size), PROT_WRITE, MAP_SHARED, fd, 0); + + if (base == MAP_FAILED) { + LLDB_LOG(log, "mmap base error {0}", errno); + return createStringError(inconvertibleErrorCode(), + "Meta buffer allocation failed"); + } + + m_mmap_meta = std::unique_ptr( + reinterpret_cast(base), + munmap_delete(buffer_size + page_size)); + + m_mmap_meta->aux_offset = m_mmap_meta->data_offset + m_mmap_meta->data_size; + m_mmap_meta->aux_size = buffer_size; + + errno = 0; + auto mmap_aux = mmap(nullptr, buffer_size, PROT_READ, MAP_SHARED, fd, + static_cast(m_mmap_meta->aux_offset)); + + if (mmap_aux == MAP_FAILED) { + LLDB_LOG(log, "second mmap done {0}", errno); + return createStringError(inconvertibleErrorCode(), + "Trace buffer allocation failed"); + } + m_mmap_aux = std::unique_ptr( + reinterpret_cast(mmap_aux), munmap_delete(buffer_size)); + return Error::success(); +#endif +} + +llvm::MutableArrayRef IntelPTThreadTrace::GetDataBuffer() const { +#ifndef PERF_ATTR_SIZE_VER5 + llvm_unreachable("Intel PT Linux perf event not supported"); +#else + return MutableArrayRef( + (reinterpret_cast(m_mmap_meta.get()) + + m_mmap_meta->data_offset), + m_mmap_meta->data_size); +#endif +} + +llvm::MutableArrayRef IntelPTThreadTrace::GetAuxBuffer() const { +#ifndef PERF_ATTR_SIZE_VER5 + llvm_unreachable("Intel PT Linux perf event not supported"); +#else + return MutableArrayRef(m_mmap_aux.get(), m_mmap_meta->aux_size); +#endif +} + +Expected> IntelPTThreadTrace::GetCPUInfo() { + static llvm::Optional> cpu_info; + if (!cpu_info) { + auto buffer_or_error = getProcFile("cpuinfo"); + if (!buffer_or_error) + return Status(buffer_or_error.getError()).ToError(); + MemoryBuffer &buffer = **buffer_or_error; + cpu_info = std::vector( + reinterpret_cast(buffer.getBufferStart()), + reinterpret_cast(buffer.getBufferEnd())); + } + return *cpu_info; +} + +llvm::Expected +IntelPTThreadTrace::Create(lldb::pid_t pid, lldb::tid_t tid, size_t buffer_size, + bool enable_tsc, Optional psb_period) { + IntelPTThreadTraceUP thread_trace_up(new IntelPTThreadTrace()); + + if (llvm::Error err = thread_trace_up->StartTrace(pid, tid, buffer_size, + enable_tsc, psb_period)) + return std::move(err); + + return std::move(thread_trace_up); +} + +Expected> +IntelPTThreadTrace::GetIntelPTBuffer(size_t offset, size_t size) const { + std::vector data(size, 0); + MutableArrayRef buffer_ref(data); + Status error = ReadPerfTraceAux(buffer_ref, 0); + if (error.Fail()) + return error.ToError(); + return data; +} + +Status +IntelPTThreadTrace::ReadPerfTraceAux(llvm::MutableArrayRef &buffer, + size_t offset) const { +#ifndef PERF_ATTR_SIZE_VER5 + llvm_unreachable("perf event not supported"); +#else + // Disable the perf event to force a flush out of the CPU's internal buffer. + // Besides, we can guarantee that the CPU won't override any data as we are + // reading the buffer. + // + // The Intel documentation says: + // + // Packets are first buffered internally and then written out asynchronously. + // To collect packet output for postprocessing, a collector needs first to + // ensure that all packet data has been flushed from internal buffers. + // Software can ensure this by stopping packet generation by clearing + // IA32_RTIT_CTL.TraceEn (see “Disabling Packet Generation” in + // Section 35.2.7.2). + // + // This is achieved by the PERF_EVENT_IOC_DISABLE ioctl request, as mentioned + // in the man page of perf_event_open. + ioctl(*m_fd, PERF_EVENT_IOC_DISABLE); + + Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PTRACE)); + Status error; + uint64_t head = m_mmap_meta->aux_head; + + LLDB_LOG(log, "Aux size -{0} , Head - {1}", m_mmap_meta->aux_size, head); + + /** + * When configured as ring buffer, the aux buffer keeps wrapping around + * the buffer and its not possible to detect how many times the buffer + * wrapped. Initially the buffer is filled with zeros,as shown below + * so in order to get complete buffer we first copy firstpartsize, followed + * by any left over part from beginning to aux_head + * + * aux_offset [d,d,d,d,d,d,d,d,0,0,0,0,0,0,0,0,0,0,0] aux_size + * aux_head->||<- firstpartsize ->| + * + * */ + + ReadCyclicBuffer(buffer, GetAuxBuffer(), static_cast(head), offset); + LLDB_LOG(log, "ReadCyclic BUffer Done"); + + // Reenable tracing now we have read the buffer + ioctl(*m_fd, PERF_EVENT_IOC_ENABLE); + return error; +#endif +} + +Status +IntelPTThreadTrace::ReadPerfTraceData(llvm::MutableArrayRef &buffer, + size_t offset) const { +#ifndef PERF_ATTR_SIZE_VER5 + llvm_unreachable("perf event not supported"); +#else + Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PTRACE)); + uint64_t bytes_remaining = buffer.size(); + Status error; + + uint64_t head = m_mmap_meta->data_head; + + /* + * The data buffer and aux buffer have different implementations + * with respect to their definition of head pointer. In the case + * of Aux data buffer the head always wraps around the aux buffer + * and we don't need to care about it, whereas the data_head keeps + * increasing and needs to be wrapped by modulus operator + */ + + LLDB_LOG(log, "bytes_remaining - {0}", bytes_remaining); + + auto data_buffer = GetDataBuffer(); + + if (head > data_buffer.size()) { + head = head % data_buffer.size(); + LLDB_LOG(log, "Data size -{0} Head - {1}", m_mmap_meta->data_size, head); + + ReadCyclicBuffer(buffer, data_buffer, static_cast(head), offset); + bytes_remaining -= buffer.size(); + } else { + LLDB_LOG(log, "Head - {0}", head); + if (offset >= head) { + LLDB_LOG(log, "Invalid Offset "); + error.SetErrorString("invalid offset"); + buffer = buffer.slice(buffer.size()); + return error; + } + + auto data = data_buffer.slice(offset, (head - offset)); + auto remaining = std::copy(data.begin(), data.end(), buffer.begin()); + bytes_remaining -= (remaining - buffer.begin()); + } + buffer = buffer.drop_back(bytes_remaining); + return error; +#endif +} + +void IntelPTThreadTrace::ReadCyclicBuffer(llvm::MutableArrayRef &dst, + llvm::MutableArrayRef src, + size_t src_cyc_index, size_t offset) { + + Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PTRACE)); + + if (dst.empty() || src.empty()) { + dst = dst.drop_back(dst.size()); + return; + } + + if (dst.data() == nullptr || src.data() == nullptr) { + dst = dst.drop_back(dst.size()); + return; + } + + if (src_cyc_index > src.size()) { + dst = dst.drop_back(dst.size()); + return; + } + + if (offset >= src.size()) { + LLDB_LOG(log, "Too Big offset "); + dst = dst.drop_back(dst.size()); + return; + } + + llvm::SmallVector, 2> parts = { + src.slice(src_cyc_index), src.take_front(src_cyc_index)}; + + if (offset > parts[0].size()) { + parts[1] = parts[1].slice(offset - parts[0].size()); + parts[0] = parts[0].drop_back(parts[0].size()); + } else if (offset == parts[0].size()) { + parts[0] = parts[0].drop_back(parts[0].size()); + } else { + parts[0] = parts[0].slice(offset); + } + auto next = dst.begin(); + auto bytes_left = dst.size(); + for (auto part : parts) { + size_t chunk_size = std::min(part.size(), bytes_left); + next = std::copy_n(part.begin(), chunk_size, next); + bytes_left -= chunk_size; + } + dst = dst.drop_back(bytes_left); +} + +TraceThreadState IntelPTThreadTrace::GetState() const { + return {static_cast(m_tid), + {TraceBinaryData{"threadTraceBuffer", + static_cast(GetTraceBufferSize())}}}; +} + +/// IntelPTThreadTraceCollection + +bool IntelPTThreadTraceCollection::TracesThread(lldb::tid_t tid) const { + return m_thread_traces.count(tid); +} + +Error IntelPTThreadTraceCollection::TraceStop(lldb::tid_t tid) { + auto it = m_thread_traces.find(tid); + if (it == m_thread_traces.end()) + return createStringError(inconvertibleErrorCode(), + "Thread %" PRIu64 " not currently traced", tid); + m_total_buffer_size -= it->second->GetTraceBufferSize(); + m_thread_traces.erase(tid); + return Error::success(); +} + +Error IntelPTThreadTraceCollection::TraceStart( + lldb::tid_t tid, const TraceIntelPTStartRequest &request) { + if (TracesThread(tid)) + return createStringError(inconvertibleErrorCode(), + "Thread %" PRIu64 " already traced", tid); + + Expected trace_up = IntelPTThreadTrace::Create( + m_pid, tid, request.threadBufferSize, request.enableTsc, + request.psbPeriod.map([](int64_t period) { return (size_t)period; })); + if (!trace_up) + return trace_up.takeError(); + + m_total_buffer_size += (*trace_up)->GetTraceBufferSize(); + m_thread_traces.try_emplace(tid, std::move(*trace_up)); + return Error::success(); +} + +size_t IntelPTThreadTraceCollection::GetTotalBufferSize() const { + return m_total_buffer_size; +} + +std::vector +IntelPTThreadTraceCollection::GetThreadStates() const { + std::vector states; + for (const auto &it : m_thread_traces) + states.push_back(it.second->GetState()); + return states; +} + +Expected +IntelPTThreadTraceCollection::GetTracedThread(lldb::tid_t tid) const { + auto it = m_thread_traces.find(tid); + if (it == m_thread_traces.end()) + return createStringError(inconvertibleErrorCode(), + "Thread %" PRIu64 " not currently traced", tid); + return *it->second.get(); +} + +void IntelPTThreadTraceCollection::Clear() { + m_thread_traces.clear(); + m_total_buffer_size = 0; +} + +/// IntelPTProcessTrace + +bool IntelPTProcessTrace::TracesThread(lldb::tid_t tid) const { + return m_thread_traces.TracesThread(tid); +} + +Error IntelPTProcessTrace::TraceStop(lldb::tid_t tid) { + return m_thread_traces.TraceStop(tid); +} + +Error IntelPTProcessTrace::TraceStart(lldb::tid_t tid) { + if (m_thread_traces.GetTotalBufferSize() + m_tracing_params.threadBufferSize > + static_cast(*m_tracing_params.processBufferSizeLimit)) + return createStringError( + inconvertibleErrorCode(), + "Thread %" PRIu64 " can't be traced as the process trace size limit " + "has been reached. Consider retracing with a higher " + "limit.", + tid); + + return m_thread_traces.TraceStart(tid, m_tracing_params); +} + +const IntelPTThreadTraceCollection & +IntelPTProcessTrace::GetThreadTraces() const { + return m_thread_traces; +} + +/// IntelPTManager + +Error IntelPTManager::TraceStop(lldb::tid_t tid) { + if (IsProcessTracingEnabled() && m_process_trace->TracesThread(tid)) + return m_process_trace->TraceStop(tid); + return m_thread_traces.TraceStop(tid); +} + +Error IntelPTManager::TraceStop(const TraceStopRequest &request) { + if (request.IsProcessTracing()) { + Clear(); + return Error::success(); + } else { + Error error = Error::success(); + for (int64_t tid : *request.tids) + error = joinErrors(std::move(error), + TraceStop(static_cast(tid))); + return error; + } +} + +Error IntelPTManager::TraceStart( + const TraceIntelPTStartRequest &request, + const std::vector &process_threads) { + if (request.IsProcessTracing()) { + if (IsProcessTracingEnabled()) { + return createStringError( + inconvertibleErrorCode(), + "Process currently traced. Stop process tracing first"); + } + m_process_trace = IntelPTProcessTrace(m_pid, request); + + Error error = Error::success(); + for (lldb::tid_t tid : process_threads) + error = joinErrors(std::move(error), m_process_trace->TraceStart(tid)); + return error; + } else { + Error error = Error::success(); + for (int64_t tid : *request.tids) + error = joinErrors(std::move(error), + m_thread_traces.TraceStart(tid, request)); + return error; + } +} + +Error IntelPTManager::OnThreadCreated(lldb::tid_t tid) { + if (!IsProcessTracingEnabled()) + return Error::success(); + return m_process_trace->TraceStart(tid); +} + +Error IntelPTManager::OnThreadDestroyed(lldb::tid_t tid) { + if (IsProcessTracingEnabled() && m_process_trace->TracesThread(tid)) + return m_process_trace->TraceStop(tid); + else if (m_thread_traces.TracesThread(tid)) + return m_thread_traces.TraceStop(tid); + return Error::success(); +} + +Expected IntelPTManager::GetState() const { + Expected> cpu_info = IntelPTThreadTrace::GetCPUInfo(); + if (!cpu_info) + return cpu_info.takeError(); + + TraceGetStateResponse state; + state.processBinaryData.push_back( + {"cpuInfo", static_cast(cpu_info->size())}); + + std::vector thread_states = + m_thread_traces.GetThreadStates(); + state.tracedThreads.insert(state.tracedThreads.end(), thread_states.begin(), + thread_states.end()); + + if (IsProcessTracingEnabled()) { + thread_states = m_process_trace->GetThreadTraces().GetThreadStates(); + state.tracedThreads.insert(state.tracedThreads.end(), thread_states.begin(), + thread_states.end()); + } + return toJSON(state); +} + +Expected +IntelPTManager::GetTracedThread(lldb::tid_t tid) const { + if (IsProcessTracingEnabled() && m_process_trace->TracesThread(tid)) + return m_process_trace->GetThreadTraces().GetTracedThread(tid); + return m_thread_traces.GetTracedThread(tid); +} + +Expected> +IntelPTManager::GetBinaryData(const TraceGetBinaryDataRequest &request) const { + if (request.kind == "threadTraceBuffer") { + if (Expected trace = + GetTracedThread(*request.tid)) + return trace->GetIntelPTBuffer(request.offset, request.size); + else + return trace.takeError(); + } else if (request.kind == "cpuInfo") { + return IntelPTThreadTrace::GetCPUInfo(); + } + return createStringError(inconvertibleErrorCode(), + "Unsuported trace binary data kind: %s", + request.kind.c_str()); +} + +void IntelPTManager::ClearProcessTracing() { m_process_trace = None; } + +bool IntelPTManager::IsSupported() { + Expected intel_pt_type = GetOSEventType(); + if (!intel_pt_type) { + llvm::consumeError(intel_pt_type.takeError()); + return false; + } + return true; +} + +bool IntelPTManager::IsProcessTracingEnabled() const { + return (bool)m_process_trace; +} + +void IntelPTManager::Clear() { + ClearProcessTracing(); + m_thread_traces.Clear(); +} diff --git a/gnu/llvm/lldb/source/Plugins/Process/Linux/IntelPTManager.h b/gnu/llvm/lldb/source/Plugins/Process/Linux/IntelPTManager.h new file mode 100644 index 00000000000..38566a22107 --- /dev/null +++ b/gnu/llvm/lldb/source/Plugins/Process/Linux/IntelPTManager.h @@ -0,0 +1,263 @@ +//===-- IntelPTManager.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 liblldb_IntelPTManager_H_ +#define liblldb_IntelPTManager_H_ + +#include "lldb/Utility/Status.h" +#include "lldb/Utility/TraceIntelPTGDBRemotePackets.h" +#include "lldb/lldb-types.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/DenseSet.h" + +#include +#include +#include + +namespace lldb_private { + +namespace process_linux { + +/// This class keeps track of one tracing instance of +/// Intel(R) Processor Trace on Linux OS at thread level. +/// +/// The kernel interface for us is the perf_event_open. +class IntelPTThreadTrace; +typedef std::unique_ptr IntelPTThreadTraceUP; + +class IntelPTThreadTrace { + + class munmap_delete { + size_t m_length; + + public: + munmap_delete(size_t length) : m_length(length) {} + void operator()(void *ptr) { + if (m_length) + munmap(ptr, m_length); + } + }; + + class file_close { + + public: + file_close() = default; + void operator()(int *ptr) { + if (ptr == nullptr) + return; + if (*ptr == -1) + return; + close(*ptr); + std::default_delete()(ptr); + } + }; + + std::unique_ptr m_mmap_meta; + std::unique_ptr m_mmap_aux; + std::unique_ptr m_fd; + lldb::tid_t m_tid; + + /// Start tracing a thread + /// + /// \param[in] pid + /// The pid of the process whose thread will be traced. + /// + /// \param[in] buffer_size + /// Size of the thread buffer in bytes. + /// + /// \param[in] enable_tsc + /// Whether to use enable TSC timestamps or not. + /// More information in TraceIntelPT::GetStartConfigurationHelp(). + /// + /// \param[in] psb_period + /// This value defines the period in which PSB packets will be generated. + /// More information in TraceIntelPT::GetStartConfigurationHelp(). + /// + /// \return + /// \a llvm::Error::success if tracing was successful, or an + /// \a llvm::Error otherwise. + llvm::Error StartTrace(lldb::pid_t pid, lldb::tid_t tid, uint64_t buffer_size, + bool enable_tsc, llvm::Optional psb_period); + + llvm::MutableArrayRef GetAuxBuffer() const; + llvm::MutableArrayRef GetDataBuffer() const; + + IntelPTThreadTrace() + : m_mmap_meta(nullptr, munmap_delete(0)), + m_mmap_aux(nullptr, munmap_delete(0)), m_fd(nullptr, file_close()) {} + +public: + /// Get the content of /proc/cpuinfo that can be later used to decode traces. + static llvm::Expected> GetCPUInfo(); + + /// Start tracing a thread. + /// + /// See \a StartTrace. + /// + /// \return + /// A \a IntelPTThreadTrace instance if tracing was successful, or + /// an \a llvm::Error otherwise. + static llvm::Expected + Create(lldb::pid_t pid, lldb::tid_t tid, size_t buffer_size, bool enable_tsc, + llvm::Optional psb_period); + + /// Read the trace buffer of the currently traced thread. + /// + /// \param[in] offset + /// Offset of the data to read. + /// + /// \param[in] size + /// Number of bytes to read. + /// + /// \return + /// A vector with the requested binary data. The vector will have the + /// size of the requested \a size. Non-available positions will be + /// filled with zeroes. + llvm::Expected> GetIntelPTBuffer(size_t offset, + size_t size) const; + + Status ReadPerfTraceAux(llvm::MutableArrayRef &buffer, + size_t offset = 0) const; + + Status ReadPerfTraceData(llvm::MutableArrayRef &buffer, + size_t offset = 0) const; + + /// Get the size in bytes of the aux section of the thread or process traced + /// by this object. + size_t GetTraceBufferSize() const; + + /// Read data from a cyclic buffer + /// + /// \param[in] [out] buf + /// Destination buffer, the buffer will be truncated to written size. + /// + /// \param[in] src + /// Source buffer which must be a cyclic buffer. + /// + /// \param[in] src_cyc_index + /// The index pointer (start of the valid data in the cyclic + /// buffer). + /// + /// \param[in] offset + /// The offset to begin reading the data in the cyclic buffer. + static void ReadCyclicBuffer(llvm::MutableArrayRef &dst, + llvm::MutableArrayRef src, + size_t src_cyc_index, size_t offset); + + /// Return the thread-specific part of the jLLDBTraceGetState packet. + TraceThreadState GetState() const; +}; + +/// Manages a list of thread traces. +class IntelPTThreadTraceCollection { +public: + IntelPTThreadTraceCollection(lldb::pid_t pid) : m_pid(pid) {} + + /// Dispose of all traces + void Clear(); + + bool TracesThread(lldb::tid_t tid) const; + + size_t GetTotalBufferSize() const; + + std::vector GetThreadStates() const; + + llvm::Expected + GetTracedThread(lldb::tid_t tid) const; + + llvm::Error TraceStart(lldb::tid_t tid, + const TraceIntelPTStartRequest &request); + + llvm::Error TraceStop(lldb::tid_t tid); + +private: + lldb::pid_t m_pid; + llvm::DenseMap m_thread_traces; + /// Total actual thread buffer size in bytes + size_t m_total_buffer_size = 0; +}; + +/// Manages a "process trace" instance. +class IntelPTProcessTrace { +public: + IntelPTProcessTrace(lldb::pid_t pid, const TraceIntelPTStartRequest &request) + : m_thread_traces(pid), m_tracing_params(request) {} + + bool TracesThread(lldb::tid_t tid) const; + + const IntelPTThreadTraceCollection &GetThreadTraces() const; + + llvm::Error TraceStart(lldb::tid_t tid); + + llvm::Error TraceStop(lldb::tid_t tid); + +private: + IntelPTThreadTraceCollection m_thread_traces; + /// Params used to trace threads when the user started "process tracing". + TraceIntelPTStartRequest m_tracing_params; +}; + +/// Main class that manages intel-pt process and thread tracing. +class IntelPTManager { +public: + IntelPTManager(lldb::pid_t pid) : m_pid(pid), m_thread_traces(pid) {} + + static bool IsSupported(); + + /// If "process tracing" is enabled, then trace the given thread. + llvm::Error OnThreadCreated(lldb::tid_t tid); + + /// Stops tracing a tracing upon a destroy event. + llvm::Error OnThreadDestroyed(lldb::tid_t tid); + + /// Implementation of the jLLDBTraceStop packet + llvm::Error TraceStop(const TraceStopRequest &request); + + /// Implementation of the jLLDBTraceStart packet + /// + /// \param[in] process_threads + /// A list of all threads owned by the process. + llvm::Error TraceStart(const TraceIntelPTStartRequest &request, + const std::vector &process_threads); + + /// Implementation of the jLLDBTraceGetState packet + llvm::Expected GetState() const; + + /// Implementation of the jLLDBTraceGetBinaryData packet + llvm::Expected> + GetBinaryData(const TraceGetBinaryDataRequest &request) const; + + /// Dispose of all traces + void Clear(); + +private: + llvm::Error TraceStop(lldb::tid_t tid); + + /// Start tracing a specific thread. + llvm::Error TraceStart(lldb::tid_t tid, + const TraceIntelPTStartRequest &request); + + llvm::Expected + GetTracedThread(lldb::tid_t tid) const; + + bool IsProcessTracingEnabled() const; + + void ClearProcessTracing(); + + lldb::pid_t m_pid; + /// Threads traced due to "thread tracing" + IntelPTThreadTraceCollection m_thread_traces; + /// Threads traced due to "process tracing". Only one active "process tracing" + /// instance is assumed for a single process. + llvm::Optional m_process_trace; +}; + +} // namespace process_linux +} // namespace lldb_private + +#endif // liblldb_IntelPTManager_H_ diff --git a/gnu/llvm/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp b/gnu/llvm/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp index 79d803de158..8c45796ae0b 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp +++ b/gnu/llvm/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp @@ -8,9 +8,9 @@ #include "NativeProcessLinux.h" -#include -#include -#include +#include +#include +#include #include #include @@ -19,7 +19,10 @@ #include #include -#include "lldb/Core/EmulateInstruction.h" +#include "NativeThreadLinux.h" +#include "Plugins/Process/POSIX/ProcessPOSIXLog.h" +#include "Plugins/Process/Utility/LinuxProcMaps.h" +#include "Procfs.h" #include "lldb/Core/ModuleSpec.h" #include "lldb/Host/Host.h" #include "lldb/Host/HostProcess.h" @@ -27,6 +30,7 @@ #include "lldb/Host/PseudoTerminal.h" #include "lldb/Host/ThreadLauncher.h" #include "lldb/Host/common/NativeRegisterContext.h" +#include "lldb/Host/linux/Host.h" #include "lldb/Host/linux/Ptrace.h" #include "lldb/Host/linux/Uio.h" #include "lldb/Host/posix/ProcessLauncherPosixFork.h" @@ -34,19 +38,14 @@ #include "lldb/Target/Process.h" #include "lldb/Target/Target.h" #include "lldb/Utility/LLDBAssert.h" -#include "lldb/Utility/RegisterValue.h" #include "lldb/Utility/State.h" #include "lldb/Utility/Status.h" #include "lldb/Utility/StringExtractor.h" +#include "llvm/ADT/ScopeExit.h" #include "llvm/Support/Errno.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Threading.h" -#include "NativeThreadLinux.h" -#include "Plugins/Process/POSIX/ProcessPOSIXLog.h" -#include "Plugins/Process/Utility/LinuxProcMaps.h" -#include "Procfs.h" - #include #include #include @@ -54,11 +53,20 @@ #include #include +#ifdef __aarch64__ +#include +#include +#endif + // Support hardware breakpoints in case it has not been defined #ifndef TRAP_HWBKPT #define TRAP_HWBKPT 4 #endif +#ifndef HWCAP2_MTE +#define HWCAP2_MTE (1 << 18) +#endif + using namespace lldb; using namespace lldb_private; using namespace lldb_private::process_linux; @@ -282,13 +290,29 @@ NativeProcessLinux::Factory::Attach( pid, -1, native_delegate, Info.GetArchitecture(), mainloop, *tids_or)); } +NativeProcessLinux::Extension +NativeProcessLinux::Factory::GetSupportedExtensions() const { + NativeProcessLinux::Extension supported = + Extension::multiprocess | Extension::fork | Extension::vfork | + Extension::pass_signals | Extension::auxv | Extension::libraries_svr4; + +#ifdef __aarch64__ + // At this point we do not have a process so read auxv directly. + if ((getauxval(AT_HWCAP2) & HWCAP2_MTE)) + supported |= Extension::memory_tagging; +#endif + + return supported; +} + // Public Instance Methods NativeProcessLinux::NativeProcessLinux(::pid_t pid, int terminal_fd, NativeDelegate &delegate, const ArchSpec &arch, MainLoop &mainloop, llvm::ArrayRef<::pid_t> tids) - : NativeProcessELF(pid, terminal_fd, delegate), m_arch(arch) { + : NativeProcessELF(pid, terminal_fd, delegate), m_arch(arch), + m_main_loop(mainloop), m_intel_pt_manager(pid) { if (m_terminal_fd != -1) { Status status = EnsureFDFlags(m_terminal_fd, O_NONBLOCK); assert(status.Success()); @@ -300,8 +324,7 @@ NativeProcessLinux::NativeProcessLinux(::pid_t pid, int terminal_fd, assert(m_sigchld_handle && status.Success()); for (const auto &tid : tids) { - NativeThreadLinux &thread = AddThread(tid); - thread.SetStoppedBySignal(SIGSTOP); + NativeThreadLinux &thread = AddThread(tid, /*resume*/ false); ThreadWasCreated(thread); } @@ -385,14 +408,22 @@ Status NativeProcessLinux::SetDefaultPtraceOpts(lldb::pid_t pid) { ptrace_opts |= PTRACE_O_TRACEEXIT; // Have the tracer trace threads which spawn in the inferior process. - // TODO: if we want to support tracing the inferiors' child, add the - // appropriate ptrace flags here (PTRACE_O_TRACEFORK, PTRACE_O_TRACEVFORK) ptrace_opts |= PTRACE_O_TRACECLONE; // Have the tracer notify us before execve returns (needed to disable legacy // SIGTRAP generation) ptrace_opts |= PTRACE_O_TRACEEXEC; + // Have the tracer trace forked children. + ptrace_opts |= PTRACE_O_TRACEFORK; + + // Have the tracer trace vforks. + ptrace_opts |= PTRACE_O_TRACEVFORK; + + // Have the tracer trace vfork-done in order to restore breakpoints after + // the child finishes sharing memory. + ptrace_opts |= PTRACE_O_TRACEVFORKDONE; + return PtraceWrapper(PTRACE_SETOPTIONS, pid, nullptr, (void *)ptrace_opts); } @@ -446,11 +477,7 @@ void NativeProcessLinux::MonitorCallback(lldb::pid_t pid, bool exited, LLDB_LOG(log, "tid {0}, si_code: {1}, si_pid: {2}", pid, info.si_code, info.si_pid); - NativeThreadLinux &thread = AddThread(pid); - - // Resume the newly created thread. - ResumeThread(thread, eStateRunning, LLDB_INVALID_SIGNAL_NUMBER); - ThreadWasCreated(thread); + MonitorClone(pid, llvm::None); return; } @@ -514,29 +541,24 @@ void NativeProcessLinux::MonitorCallback(lldb::pid_t pid, bool exited, } } -void NativeProcessLinux::WaitForNewThread(::pid_t tid) { +void NativeProcessLinux::WaitForCloneNotification(::pid_t pid) { Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); - if (GetThreadByID(tid)) { - // We are already tracking the thread - we got the event on the new thread - // (see MonitorSignal) before this one. We are done. - return; - } - - // The thread is not tracked yet, let's wait for it to appear. + // The PID is not tracked yet, let's wait for it to appear. int status = -1; LLDB_LOG(log, - "received thread creation event for tid {0}. tid not tracked " - "yet, waiting for thread to appear...", - tid); - ::pid_t wait_pid = llvm::sys::RetryAfterSignal(-1, ::waitpid, tid, &status, __WALL); - // Since we are waiting on a specific tid, this must be the creation event. + "received clone event for pid {0}. pid not tracked yet, " + "waiting for it to appear...", + pid); + ::pid_t wait_pid = + llvm::sys::RetryAfterSignal(-1, ::waitpid, pid, &status, __WALL); + // Since we are waiting on a specific pid, this must be the creation event. // But let's do some checks just in case. - if (wait_pid != tid) { + if (wait_pid != pid) { LLDB_LOG(log, - "waiting for tid {0} failed. Assuming the thread has " + "waiting for pid {0} failed. Assuming the pid has " "disappeared in the meantime", - tid); + pid); // The only way I know of this could happen is if the whole process was // SIGKILLed in the mean time. In any case, we can't do anything about that // now. @@ -544,18 +566,15 @@ void NativeProcessLinux::WaitForNewThread(::pid_t tid) { } if (WIFEXITED(status)) { LLDB_LOG(log, - "waiting for tid {0} returned an 'exited' event. Not " - "tracking the thread.", - tid); + "waiting for pid {0} returned an 'exited' event. Not " + "tracking it.", + pid); // Also a very improbable event. + m_pending_pid_map.erase(pid); return; } - LLDB_LOG(log, "pid = {0}: tracking new thread tid {1}", GetID(), tid); - NativeThreadLinux &new_thread = AddThread(tid); - - ResumeThread(new_thread, eStateRunning, LLDB_INVALID_SIGNAL_NUMBER); - ThreadWasCreated(new_thread); + MonitorClone(pid, llvm::None); } void NativeProcessLinux::MonitorSIGTRAP(const siginfo_t &info, @@ -566,26 +585,26 @@ void NativeProcessLinux::MonitorSIGTRAP(const siginfo_t &info, assert(info.si_signo == SIGTRAP && "Unexpected child signal!"); switch (info.si_code) { - // TODO: these two cases are required if we want to support tracing of the - // inferiors' children. We'd need this to debug a monitor. case (SIGTRAP | - // (PTRACE_EVENT_FORK << 8)): case (SIGTRAP | (PTRACE_EVENT_VFORK << 8)): - + case (SIGTRAP | (PTRACE_EVENT_FORK << 8)): + case (SIGTRAP | (PTRACE_EVENT_VFORK << 8)): case (SIGTRAP | (PTRACE_EVENT_CLONE << 8)): { - // This is the notification on the parent thread which informs us of new - // thread creation. We don't want to do anything with the parent thread so - // we just resume it. In case we want to implement "break on thread - // creation" functionality, we would need to stop here. + // This can either mean a new thread or a new process spawned via + // clone(2) without SIGCHLD or CLONE_VFORK flag. Note that clone(2) + // can also cause PTRACE_EVENT_FORK and PTRACE_EVENT_VFORK if one + // of these flags are passed. unsigned long event_message = 0; if (GetEventMessage(thread.GetID(), &event_message).Fail()) { LLDB_LOG(log, - "pid {0} received thread creation event but " - "GetEventMessage failed so we don't know the new tid", + "pid {0} received clone() event but GetEventMessage failed " + "so we don't know the new pid/tid", thread.GetID()); - } else - WaitForNewThread(event_message); + ResumeThread(thread, thread.GetState(), LLDB_INVALID_SIGNAL_NUMBER); + } else { + if (!MonitorClone(event_message, {{(info.si_code >> 8), thread.GetID()}})) + WaitForCloneNotification(event_message); + } - ResumeThread(thread, thread.GetState(), LLDB_INVALID_SIGNAL_NUMBER); break; } @@ -651,6 +670,16 @@ void NativeProcessLinux::MonitorSIGTRAP(const siginfo_t &info, break; } + case (SIGTRAP | (PTRACE_EVENT_VFORK_DONE << 8)): { + if (bool(m_enabled_extensions & Extension::vfork)) { + thread.SetStoppedByVForkDone(); + StopRunningThreads(thread.GetID()); + } + else + ResumeThread(thread, thread.GetState(), LLDB_INVALID_SIGNAL_NUMBER); + break; + } + case 0: case TRAP_TRACE: // We receive this on single stepping. case TRAP_HWBKPT: // We receive this on watchpoint hit @@ -860,167 +889,83 @@ void NativeProcessLinux::MonitorSignal(const siginfo_t &info, StopRunningThreads(thread.GetID()); } -namespace { - -struct EmulatorBaton { - NativeProcessLinux &m_process; - NativeRegisterContext &m_reg_context; - - // eRegisterKindDWARF -> RegsiterValue - std::unordered_map m_register_values; - - EmulatorBaton(NativeProcessLinux &process, NativeRegisterContext ®_context) - : m_process(process), m_reg_context(reg_context) {} -}; - -} // anonymous namespace - -static size_t ReadMemoryCallback(EmulateInstruction *instruction, void *baton, - const EmulateInstruction::Context &context, - lldb::addr_t addr, void *dst, size_t length) { - EmulatorBaton *emulator_baton = static_cast(baton); - - size_t bytes_read; - emulator_baton->m_process.ReadMemory(addr, dst, length, bytes_read); - return bytes_read; -} +bool NativeProcessLinux::MonitorClone( + lldb::pid_t child_pid, + llvm::Optional clone_info) { + Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); + LLDB_LOG(log, "clone, child_pid={0}, clone info?={1}", child_pid, + clone_info.hasValue()); -static bool ReadRegisterCallback(EmulateInstruction *instruction, void *baton, - const RegisterInfo *reg_info, - RegisterValue ®_value) { - EmulatorBaton *emulator_baton = static_cast(baton); + auto find_it = m_pending_pid_map.find(child_pid); + if (find_it == m_pending_pid_map.end()) { + // not in the map, so this is the first signal for the PID + m_pending_pid_map.insert({child_pid, clone_info}); + return false; + } + m_pending_pid_map.erase(find_it); - auto it = emulator_baton->m_register_values.find( - reg_info->kinds[eRegisterKindDWARF]); - if (it != emulator_baton->m_register_values.end()) { - reg_value = it->second; - return true; + // second signal for the pid + assert(clone_info.hasValue() != find_it->second.hasValue()); + if (!clone_info) { + // child signal does not indicate the event, so grab the one stored + // earlier + clone_info = find_it->second; } - // The emulator only fill in the dwarf regsiter numbers (and in some case the - // generic register numbers). Get the full register info from the register - // context based on the dwarf register numbers. - const RegisterInfo *full_reg_info = - emulator_baton->m_reg_context.GetRegisterInfo( - eRegisterKindDWARF, reg_info->kinds[eRegisterKindDWARF]); + LLDB_LOG(log, "second signal for child_pid={0}, parent_tid={1}, event={2}", + child_pid, clone_info->parent_tid, clone_info->event); - Status error = - emulator_baton->m_reg_context.ReadRegister(full_reg_info, reg_value); - if (error.Success()) - return true; + auto *parent_thread = GetThreadByID(clone_info->parent_tid); + assert(parent_thread); - return false; -} + switch (clone_info->event) { + case PTRACE_EVENT_CLONE: { + // PTRACE_EVENT_CLONE can either mean a new thread or a new process. + // Try to grab the new process' PGID to figure out which one it is. + // If PGID is the same as the PID, then it's a new process. Otherwise, + // it's a thread. + auto tgid_ret = getPIDForTID(child_pid); + if (tgid_ret != child_pid) { + // A new thread should have PGID matching our process' PID. + assert(!tgid_ret || tgid_ret.getValue() == GetID()); -static bool WriteRegisterCallback(EmulateInstruction *instruction, void *baton, - const EmulateInstruction::Context &context, - const RegisterInfo *reg_info, - const RegisterValue ®_value) { - EmulatorBaton *emulator_baton = static_cast(baton); - emulator_baton->m_register_values[reg_info->kinds[eRegisterKindDWARF]] = - reg_value; - return true; -} + NativeThreadLinux &child_thread = AddThread(child_pid, /*resume*/ true); + ThreadWasCreated(child_thread); -static size_t WriteMemoryCallback(EmulateInstruction *instruction, void *baton, - const EmulateInstruction::Context &context, - lldb::addr_t addr, const void *dst, - size_t length) { - return length; -} - -static lldb::addr_t ReadFlags(NativeRegisterContext ®siter_context) { - const RegisterInfo *flags_info = regsiter_context.GetRegisterInfo( - eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS); - return regsiter_context.ReadRegisterAsUnsigned(flags_info, - LLDB_INVALID_ADDRESS); -} - -Status -NativeProcessLinux::SetupSoftwareSingleStepping(NativeThreadLinux &thread) { - Status error; - NativeRegisterContext& register_context = thread.GetRegisterContext(); - - std::unique_ptr emulator_up( - EmulateInstruction::FindPlugin(m_arch, eInstructionTypePCModifying, - nullptr)); - - if (emulator_up == nullptr) - return Status("Instruction emulator not found!"); - - EmulatorBaton baton(*this, register_context); - emulator_up->SetBaton(&baton); - emulator_up->SetReadMemCallback(&ReadMemoryCallback); - emulator_up->SetReadRegCallback(&ReadRegisterCallback); - emulator_up->SetWriteMemCallback(&WriteMemoryCallback); - emulator_up->SetWriteRegCallback(&WriteRegisterCallback); - - if (!emulator_up->ReadInstruction()) - return Status("Read instruction failed!"); - - bool emulation_result = - emulator_up->EvaluateInstruction(eEmulateInstructionOptionAutoAdvancePC); - - const RegisterInfo *reg_info_pc = register_context.GetRegisterInfo( - eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC); - const RegisterInfo *reg_info_flags = register_context.GetRegisterInfo( - eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS); - - auto pc_it = - baton.m_register_values.find(reg_info_pc->kinds[eRegisterKindDWARF]); - auto flags_it = - baton.m_register_values.find(reg_info_flags->kinds[eRegisterKindDWARF]); - - lldb::addr_t next_pc; - lldb::addr_t next_flags; - if (emulation_result) { - assert(pc_it != baton.m_register_values.end() && - "Emulation was successfull but PC wasn't updated"); - next_pc = pc_it->second.GetAsUInt64(); - - if (flags_it != baton.m_register_values.end()) - next_flags = flags_it->second.GetAsUInt64(); - else - next_flags = ReadFlags(register_context); - } else if (pc_it == baton.m_register_values.end()) { - // Emulate instruction failed and it haven't changed PC. Advance PC with - // the size of the current opcode because the emulation of all - // PC modifying instruction should be successful. The failure most - // likely caused by a not supported instruction which don't modify PC. - next_pc = register_context.GetPC() + emulator_up->GetOpcode().GetByteSize(); - next_flags = ReadFlags(register_context); - } else { - // The instruction emulation failed after it modified the PC. It is an - // unknown error where we can't continue because the next instruction is - // modifying the PC but we don't know how. - return Status("Instruction emulation failed unexpectedly."); + // Resume the parent. + ResumeThread(*parent_thread, parent_thread->GetState(), + LLDB_INVALID_SIGNAL_NUMBER); + break; + } } - - if (m_arch.GetMachine() == llvm::Triple::arm) { - if (next_flags & 0x20) { - // Thumb mode - error = SetSoftwareBreakpoint(next_pc, 2); + LLVM_FALLTHROUGH; + case PTRACE_EVENT_FORK: + case PTRACE_EVENT_VFORK: { + bool is_vfork = clone_info->event == PTRACE_EVENT_VFORK; + std::unique_ptr child_process{new NativeProcessLinux( + static_cast<::pid_t>(child_pid), m_terminal_fd, m_delegate, m_arch, + m_main_loop, {static_cast<::pid_t>(child_pid)})}; + if (!is_vfork) + child_process->m_software_breakpoints = m_software_breakpoints; + + Extension expected_ext = is_vfork ? Extension::vfork : Extension::fork; + if (bool(m_enabled_extensions & expected_ext)) { + m_delegate.NewSubprocess(this, std::move(child_process)); + // NB: non-vfork clone() is reported as fork + parent_thread->SetStoppedByFork(is_vfork, child_pid); + StopRunningThreads(parent_thread->GetID()); } else { - // Arm mode - error = SetSoftwareBreakpoint(next_pc, 4); + child_process->Detach(); + ResumeThread(*parent_thread, parent_thread->GetState(), + LLDB_INVALID_SIGNAL_NUMBER); } - } else if (m_arch.IsMIPS() || m_arch.GetTriple().isPPC64()) - error = SetSoftwareBreakpoint(next_pc, 4); - else { - // No size hint is given for the next breakpoint - error = SetSoftwareBreakpoint(next_pc, 0); + break; + } + default: + llvm_unreachable("unknown clone_info.event"); } - // If setting the breakpoint fails because next_pc is out of the address - // space, ignore it and let the debugee segfault. - if (error.GetError() == EIO || error.GetError() == EFAULT) { - return Status(); - } else if (error.Fail()) - return error; - - m_threads_stepping_with_breakpoint.insert({thread.GetID(), next_pc}); - - return Status(); + return true; } bool NativeProcessLinux::SupportHardwareSingleStepping() const { @@ -1119,8 +1064,7 @@ Status NativeProcessLinux::Detach() { e; // Save the error, but still attempt to detach from other threads. } - m_processor_trace_monitor.clear(); - m_pt_proces_trace_id = LLDB_INVALID_UID; + m_intel_pt_manager.Clear(); return error; } @@ -1297,26 +1241,36 @@ Status NativeProcessLinux::PopulateMemoryRegionCache() { return Status(); } - auto BufferOrError = getProcFile(GetID(), "maps"); - if (!BufferOrError) { + Status Result; + LinuxMapCallback callback = [&](llvm::Expected Info) { + if (Info) { + FileSpec file_spec(Info->GetName().GetCString()); + FileSystem::Instance().Resolve(file_spec); + m_mem_region_cache.emplace_back(*Info, file_spec); + return true; + } + + Result = Info.takeError(); m_supports_mem_region = LazyBool::eLazyBoolNo; - return BufferOrError.getError(); + LLDB_LOG(log, "failed to parse proc maps: {0}", Result); + return false; + }; + + // Linux kernel since 2.6.14 has /proc/{pid}/smaps + // if CONFIG_PROC_PAGE_MONITOR is enabled + auto BufferOrError = getProcFile(GetID(), "smaps"); + if (BufferOrError) + ParseLinuxSMapRegions(BufferOrError.get()->getBuffer(), callback); + else { + BufferOrError = getProcFile(GetID(), "maps"); + if (!BufferOrError) { + m_supports_mem_region = LazyBool::eLazyBoolNo; + return BufferOrError.getError(); + } + + ParseLinuxMapRegions(BufferOrError.get()->getBuffer(), callback); } - Status Result; - ParseLinuxMapRegions(BufferOrError.get()->getBuffer(), - [&](const MemoryRegionInfo &Info, const Status &ST) { - if (ST.Success()) { - FileSpec file_spec(Info.GetName().GetCString()); - FileSystem::Instance().Resolve(file_spec); - m_mem_region_cache.emplace_back(Info, file_spec); - return true; - } else { - m_supports_mem_region = LazyBool::eLazyBoolNo; - LLDB_LOG(log, "failed to parse proc maps: {0}", ST); - Result = ST; - return false; - } - }); + if (Result.Fail()) return Result; @@ -1347,43 +1301,260 @@ void NativeProcessLinux::DoStopIDBumped(uint32_t newBumpId) { m_mem_region_cache.clear(); } -Status NativeProcessLinux::AllocateMemory(size_t size, uint32_t permissions, - lldb::addr_t &addr) { -// FIXME implementing this requires the equivalent of -// InferiorCallPOSIX::InferiorCallMmap, which depends on functional ThreadPlans -// working with Native*Protocol. -#if 1 - return Status("not implemented yet"); -#else - addr = LLDB_INVALID_ADDRESS; - - unsigned prot = 0; - if (permissions & lldb::ePermissionsReadable) - prot |= eMmapProtRead; - if (permissions & lldb::ePermissionsWritable) - prot |= eMmapProtWrite; - if (permissions & lldb::ePermissionsExecutable) - prot |= eMmapProtExec; - - // TODO implement this directly in NativeProcessLinux - // (and lift to NativeProcessPOSIX if/when that class is refactored out). - if (InferiorCallMmap(this, addr, 0, size, prot, - eMmapFlagsAnon | eMmapFlagsPrivate, -1, 0)) { - m_addr_to_mmap_size[addr] = size; +llvm::Expected +NativeProcessLinux::Syscall(llvm::ArrayRef args) { + PopulateMemoryRegionCache(); + auto region_it = llvm::find_if(m_mem_region_cache, [](const auto &pair) { + return pair.first.GetExecutable() == MemoryRegionInfo::eYes; + }); + if (region_it == m_mem_region_cache.end()) + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "No executable memory region found!"); + + addr_t exe_addr = region_it->first.GetRange().GetRangeBase(); + + NativeThreadLinux &thread = *GetThreadByID(GetID()); + assert(thread.GetState() == eStateStopped); + NativeRegisterContextLinux ®_ctx = thread.GetRegisterContext(); + + NativeRegisterContextLinux::SyscallData syscall_data = + *reg_ctx.GetSyscallData(); + + DataBufferSP registers_sp; + if (llvm::Error Err = reg_ctx.ReadAllRegisterValues(registers_sp).ToError()) + return std::move(Err); + auto restore_regs = llvm::make_scope_exit( + [&] { reg_ctx.WriteAllRegisterValues(registers_sp); }); + + llvm::SmallVector memory(syscall_data.Insn.size()); + size_t bytes_read; + if (llvm::Error Err = + ReadMemory(exe_addr, memory.data(), memory.size(), bytes_read) + .ToError()) { + return std::move(Err); + } + + auto restore_mem = llvm::make_scope_exit( + [&] { WriteMemory(exe_addr, memory.data(), memory.size(), bytes_read); }); + + if (llvm::Error Err = reg_ctx.SetPC(exe_addr).ToError()) + return std::move(Err); + + for (const auto &zip : llvm::zip_first(args, syscall_data.Args)) { + if (llvm::Error Err = + reg_ctx + .WriteRegisterFromUnsigned(std::get<1>(zip), std::get<0>(zip)) + .ToError()) { + return std::move(Err); + } + } + if (llvm::Error Err = WriteMemory(exe_addr, syscall_data.Insn.data(), + syscall_data.Insn.size(), bytes_read) + .ToError()) + return std::move(Err); + + m_mem_region_cache.clear(); + + // With software single stepping the syscall insn buffer must also include a + // trap instruction to stop the process. + int req = SupportHardwareSingleStepping() ? PTRACE_SINGLESTEP : PTRACE_CONT; + if (llvm::Error Err = + PtraceWrapper(req, thread.GetID(), nullptr, nullptr).ToError()) + return std::move(Err); + + int status; + ::pid_t wait_pid = llvm::sys::RetryAfterSignal(-1, ::waitpid, thread.GetID(), + &status, __WALL); + if (wait_pid == -1) { + return llvm::errorCodeToError( + std::error_code(errno, std::generic_category())); + } + assert((unsigned)wait_pid == thread.GetID()); + + uint64_t result = reg_ctx.ReadRegisterAsUnsigned(syscall_data.Result, -ESRCH); + + // Values larger than this are actually negative errno numbers. + uint64_t errno_threshold = + (uint64_t(-1) >> (64 - 8 * m_arch.GetAddressByteSize())) - 0x1000; + if (result > errno_threshold) { + return llvm::errorCodeToError( + std::error_code(-result & 0xfff, std::generic_category())); + } + + return result; +} + +llvm::Expected +NativeProcessLinux::AllocateMemory(size_t size, uint32_t permissions) { + + llvm::Optional mmap_data = + GetCurrentThread()->GetRegisterContext().GetMmapData(); + if (!mmap_data) + return llvm::make_error(); + + unsigned prot = PROT_NONE; + assert((permissions & (ePermissionsReadable | ePermissionsWritable | + ePermissionsExecutable)) == permissions && + "Unknown permission!"); + if (permissions & ePermissionsReadable) + prot |= PROT_READ; + if (permissions & ePermissionsWritable) + prot |= PROT_WRITE; + if (permissions & ePermissionsExecutable) + prot |= PROT_EXEC; + + llvm::Expected Result = + Syscall({mmap_data->SysMmap, 0, size, prot, MAP_ANONYMOUS | MAP_PRIVATE, + uint64_t(-1), 0}); + if (Result) + m_allocated_memory.try_emplace(*Result, size); + return Result; +} + +llvm::Error NativeProcessLinux::DeallocateMemory(lldb::addr_t addr) { + llvm::Optional mmap_data = + GetCurrentThread()->GetRegisterContext().GetMmapData(); + if (!mmap_data) + return llvm::make_error(); + + auto it = m_allocated_memory.find(addr); + if (it == m_allocated_memory.end()) + return llvm::createStringError(llvm::errc::invalid_argument, + "Memory not allocated by the debugger."); + + llvm::Expected Result = + Syscall({mmap_data->SysMunmap, addr, it->second}); + if (!Result) + return Result.takeError(); + + m_allocated_memory.erase(it); + return llvm::Error::success(); +} + +Status NativeProcessLinux::ReadMemoryTags(int32_t type, lldb::addr_t addr, + size_t len, + std::vector &tags) { + llvm::Expected details = + GetCurrentThread()->GetRegisterContext().GetMemoryTaggingDetails(type); + if (!details) + return Status(details.takeError()); + + // Ignore 0 length read + if (!len) return Status(); - } else { - addr = LLDB_INVALID_ADDRESS; - return Status("unable to allocate %" PRIu64 - " bytes of memory with permissions %s", - size, GetPermissionsAsCString(permissions)); + + // lldb will align the range it requests but it is not required to by + // the protocol so we'll do it again just in case. + // Remove non address bits too. Ptrace calls may work regardless but that + // is not a guarantee. + MemoryTagManager::TagRange range(details->manager->RemoveNonAddressBits(addr), + len); + range = details->manager->ExpandToGranule(range); + + // Allocate enough space for all tags to be read + size_t num_tags = range.GetByteSize() / details->manager->GetGranuleSize(); + tags.resize(num_tags * details->manager->GetTagSizeInBytes()); + + struct iovec tags_iovec; + uint8_t *dest = tags.data(); + lldb::addr_t read_addr = range.GetRangeBase(); + + // This call can return partial data so loop until we error or + // get all tags back. + while (num_tags) { + tags_iovec.iov_base = dest; + tags_iovec.iov_len = num_tags; + + Status error = NativeProcessLinux::PtraceWrapper( + details->ptrace_read_req, GetID(), reinterpret_cast(read_addr), + static_cast(&tags_iovec), 0, nullptr); + + if (error.Fail()) { + // Discard partial reads + tags.resize(0); + return error; + } + + size_t tags_read = tags_iovec.iov_len; + assert(tags_read && (tags_read <= num_tags)); + + dest += tags_read * details->manager->GetTagSizeInBytes(); + read_addr += details->manager->GetGranuleSize() * tags_read; + num_tags -= tags_read; } -#endif + + return Status(); } -Status NativeProcessLinux::DeallocateMemory(lldb::addr_t addr) { - // FIXME see comments in AllocateMemory - required lower-level - // bits not in place yet (ThreadPlans) - return Status("not implemented"); +Status NativeProcessLinux::WriteMemoryTags(int32_t type, lldb::addr_t addr, + size_t len, + const std::vector &tags) { + llvm::Expected details = + GetCurrentThread()->GetRegisterContext().GetMemoryTaggingDetails(type); + if (!details) + return Status(details.takeError()); + + // Ignore 0 length write + if (!len) + return Status(); + + // lldb will align the range it requests but it is not required to by + // the protocol so we'll do it again just in case. + // Remove non address bits too. Ptrace calls may work regardless but that + // is not a guarantee. + MemoryTagManager::TagRange range(details->manager->RemoveNonAddressBits(addr), + len); + range = details->manager->ExpandToGranule(range); + + // Not checking number of tags here, we may repeat them below + llvm::Expected> unpacked_tags_or_err = + details->manager->UnpackTagsData(tags); + if (!unpacked_tags_or_err) + return Status(unpacked_tags_or_err.takeError()); + + llvm::Expected> repeated_tags_or_err = + details->manager->RepeatTagsForRange(*unpacked_tags_or_err, range); + if (!repeated_tags_or_err) + return Status(repeated_tags_or_err.takeError()); + + // Repack them for ptrace to use + llvm::Expected> final_tag_data = + details->manager->PackTags(*repeated_tags_or_err); + if (!final_tag_data) + return Status(final_tag_data.takeError()); + + struct iovec tags_vec; + uint8_t *src = final_tag_data->data(); + lldb::addr_t write_addr = range.GetRangeBase(); + // unpacked tags size because the number of bytes per tag might not be 1 + size_t num_tags = repeated_tags_or_err->size(); + + // This call can partially write tags, so we loop until we + // error or all tags have been written. + while (num_tags > 0) { + tags_vec.iov_base = src; + tags_vec.iov_len = num_tags; + + Status error = NativeProcessLinux::PtraceWrapper( + details->ptrace_write_req, GetID(), + reinterpret_cast(write_addr), static_cast(&tags_vec), 0, + nullptr); + + if (error.Fail()) { + // Don't attempt to restore the original values in the case of a partial + // write + return error; + } + + size_t tags_written = tags_vec.iov_len; + assert(tags_written && (tags_written <= num_tags)); + + src += tags_written * details->manager->GetTagSizeInBytes(); + write_addr += details->manager->GetGranuleSize() * tags_written; + num_tags -= tags_written; + } + + return Status(); } size_t NativeProcessLinux::UpdateThreads() { @@ -1575,12 +1746,33 @@ bool NativeProcessLinux::StopTrackingThread(lldb::tid_t thread_id) { } if (found) - StopTracingForThread(thread_id); + NotifyTracersOfThreadDestroyed(thread_id); + SignalIfAllThreadsStopped(); return found; } -NativeThreadLinux &NativeProcessLinux::AddThread(lldb::tid_t thread_id) { +Status NativeProcessLinux::NotifyTracersOfNewThread(lldb::tid_t tid) { + Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD)); + Status error(m_intel_pt_manager.OnThreadCreated(tid)); + if (error.Fail()) + LLDB_LOG(log, "Failed to trace a new thread with intel-pt, tid = {0}. {1}", + tid, error.AsCString()); + return error; +} + +Status NativeProcessLinux::NotifyTracersOfThreadDestroyed(lldb::tid_t tid) { + Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD)); + Status error(m_intel_pt_manager.OnThreadDestroyed(tid)); + if (error.Fail()) + LLDB_LOG(log, + "Failed to stop a destroyed thread with intel-pt, tid = {0}. {1}", + tid, error.AsCString()); + return error; +} + +NativeThreadLinux &NativeProcessLinux::AddThread(lldb::tid_t thread_id, + bool resume) { Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD)); LLDB_LOG(log, "pid {0} adding thread with tid {1}", GetID(), thread_id); @@ -1592,22 +1784,19 @@ NativeThreadLinux &NativeProcessLinux::AddThread(lldb::tid_t thread_id) { SetCurrentThreadID(thread_id); m_threads.push_back(std::make_unique(*this, thread_id)); + NativeThreadLinux &thread = + static_cast(*m_threads.back()); + + Status tracing_error = NotifyTracersOfNewThread(thread.GetID()); + if (tracing_error.Fail()) { + thread.SetStoppedByProcessorTrace(tracing_error.AsCString()); + StopRunningThreads(thread.GetID()); + } else if (resume) + ResumeThread(thread, eStateRunning, LLDB_INVALID_SIGNAL_NUMBER); + else + thread.SetStoppedBySignal(SIGSTOP); - if (m_pt_proces_trace_id != LLDB_INVALID_UID) { - auto traceMonitor = ProcessorTraceMonitor::Create( - GetID(), thread_id, m_pt_process_trace_config, true); - if (traceMonitor) { - m_pt_traced_thread_group.insert(thread_id); - m_processor_trace_monitor.insert( - std::make_pair(thread_id, std::move(*traceMonitor))); - } else { - LLDB_LOG(log, "failed to start trace on thread {0}", thread_id); - Status error(traceMonitor.takeError()); - LLDB_LOG(log, "error {0}", error); - } - } - - return static_cast(*m_threads.back()); + return thread; } Status NativeProcessLinux::GetLoadedModuleFileSpec(const char *module_path, @@ -1652,6 +1841,11 @@ NativeThreadLinux *NativeProcessLinux::GetThreadByID(lldb::tid_t tid) { NativeProcessProtocol::GetThreadByID(tid)); } +NativeThreadLinux *NativeProcessLinux::GetCurrentThread() { + return static_cast( + NativeProcessProtocol::GetCurrentThread()); +} + Status NativeProcessLinux::ResumeThread(NativeThreadLinux &thread, lldb::StateType state, int signo) { Log *const log = ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD); @@ -1820,257 +2014,43 @@ Status NativeProcessLinux::PtraceWrapper(int req, lldb::pid_t pid, void *addr, return error; } -llvm::Expected -NativeProcessLinux::LookupProcessorTraceInstance(lldb::user_id_t traceid, - lldb::tid_t thread) { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PTRACE)); - if (thread == LLDB_INVALID_THREAD_ID && traceid == m_pt_proces_trace_id) { - LLDB_LOG(log, "thread not specified: {0}", traceid); - return Status("tracing not active thread not specified").ToError(); - } - - for (auto& iter : m_processor_trace_monitor) { - if (traceid == iter.second->GetTraceID() && - (thread == iter.first || thread == LLDB_INVALID_THREAD_ID)) - return *(iter.second); - } - - LLDB_LOG(log, "traceid not being traced: {0}", traceid); - return Status("tracing not active for this thread").ToError(); -} - -Status NativeProcessLinux::GetMetaData(lldb::user_id_t traceid, - lldb::tid_t thread, - llvm::MutableArrayRef &buffer, - size_t offset) { - TraceOptions trace_options; - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PTRACE)); - Status error; - - LLDB_LOG(log, "traceid {0}", traceid); - - auto perf_monitor = LookupProcessorTraceInstance(traceid, thread); - if (!perf_monitor) { - LLDB_LOG(log, "traceid not being traced: {0}", traceid); - buffer = buffer.slice(buffer.size()); - error = perf_monitor.takeError(); - return error; - } - return (*perf_monitor).ReadPerfTraceData(buffer, offset); +llvm::Expected NativeProcessLinux::TraceSupported() { + if (IntelPTManager::IsSupported()) + return TraceSupportedResponse{"intel-pt", "Intel Processor Trace"}; + return NativeProcessProtocol::TraceSupported(); } -Status NativeProcessLinux::GetData(lldb::user_id_t traceid, lldb::tid_t thread, - llvm::MutableArrayRef &buffer, - size_t offset) { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PTRACE)); - Status error; - - LLDB_LOG(log, "traceid {0}", traceid); - - auto perf_monitor = LookupProcessorTraceInstance(traceid, thread); - if (!perf_monitor) { - LLDB_LOG(log, "traceid not being traced: {0}", traceid); - buffer = buffer.slice(buffer.size()); - error = perf_monitor.takeError(); - return error; - } - return (*perf_monitor).ReadPerfTraceAux(buffer, offset); -} - -Status NativeProcessLinux::GetTraceConfig(lldb::user_id_t traceid, - TraceOptions &config) { - Status error; - if (config.getThreadID() == LLDB_INVALID_THREAD_ID && - m_pt_proces_trace_id == traceid) { - if (m_pt_proces_trace_id == LLDB_INVALID_UID) { - error.SetErrorString("tracing not active for this process"); - return error; - } - config = m_pt_process_trace_config; - } else { - auto perf_monitor = - LookupProcessorTraceInstance(traceid, config.getThreadID()); - if (!perf_monitor) { - error = perf_monitor.takeError(); - return error; - } - error = (*perf_monitor).GetTraceConfig(config); - } - return error; -} - -lldb::user_id_t -NativeProcessLinux::StartTraceGroup(const TraceOptions &config, - Status &error) { - - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PTRACE)); - if (config.getType() != TraceType::eTraceTypeProcessorTrace) - return LLDB_INVALID_UID; - - if (m_pt_proces_trace_id != LLDB_INVALID_UID) { - error.SetErrorString("tracing already active on this process"); - return m_pt_proces_trace_id; - } - - for (const auto &thread_sp : m_threads) { - if (auto traceInstance = ProcessorTraceMonitor::Create( - GetID(), thread_sp->GetID(), config, true)) { - m_pt_traced_thread_group.insert(thread_sp->GetID()); - m_processor_trace_monitor.insert( - std::make_pair(thread_sp->GetID(), std::move(*traceInstance))); - } - } - - m_pt_process_trace_config = config; - error = ProcessorTraceMonitor::GetCPUType(m_pt_process_trace_config); - - // Trace on Complete process will have traceid of 0 - m_pt_proces_trace_id = 0; - - LLDB_LOG(log, "Process Trace ID {0}", m_pt_proces_trace_id); - return m_pt_proces_trace_id; -} - -lldb::user_id_t NativeProcessLinux::StartTrace(const TraceOptions &config, - Status &error) { - if (config.getType() != TraceType::eTraceTypeProcessorTrace) - return NativeProcessProtocol::StartTrace(config, error); - - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PTRACE)); - - lldb::tid_t threadid = config.getThreadID(); - - if (threadid == LLDB_INVALID_THREAD_ID) - return StartTraceGroup(config, error); - - auto thread_sp = GetThreadByID(threadid); - if (!thread_sp) { - // Thread not tracked by lldb so don't trace. - error.SetErrorString("invalid thread id"); - return LLDB_INVALID_UID; - } - - const auto &iter = m_processor_trace_monitor.find(threadid); - if (iter != m_processor_trace_monitor.end()) { - LLDB_LOG(log, "Thread already being traced"); - error.SetErrorString("tracing already active on this thread"); - return LLDB_INVALID_UID; - } - - auto traceMonitor = - ProcessorTraceMonitor::Create(GetID(), threadid, config, false); - if (!traceMonitor) { - error = traceMonitor.takeError(); - LLDB_LOG(log, "error {0}", error); - return LLDB_INVALID_UID; - } - lldb::user_id_t ret_trace_id = (*traceMonitor)->GetTraceID(); - m_processor_trace_monitor.insert( - std::make_pair(threadid, std::move(*traceMonitor))); - return ret_trace_id; -} - -Status NativeProcessLinux::StopTracingForThread(lldb::tid_t thread) { - Status error; - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PTRACE)); - LLDB_LOG(log, "Thread {0}", thread); - - const auto& iter = m_processor_trace_monitor.find(thread); - if (iter == m_processor_trace_monitor.end()) { - error.SetErrorString("tracing not active for this thread"); - return error; - } - - if (iter->second->GetTraceID() == m_pt_proces_trace_id) { - // traceid maps to the whole process so we have to erase it from the thread - // group. - LLDB_LOG(log, "traceid maps to process"); - m_pt_traced_thread_group.erase(thread); +Error NativeProcessLinux::TraceStart(StringRef json_request, StringRef type) { + if (type == "intel-pt") { + if (Expected request = + json::parse(json_request, + "TraceIntelPTStartRequest")) { + std::vector process_threads; + for (auto &thread : m_threads) + process_threads.push_back(thread->GetID()); + return m_intel_pt_manager.TraceStart(*request, process_threads); + } else + return request.takeError(); } - m_processor_trace_monitor.erase(iter); - return error; + return NativeProcessProtocol::TraceStart(json_request, type); } -Status NativeProcessLinux::StopTrace(lldb::user_id_t traceid, - lldb::tid_t thread) { - Status error; - - TraceOptions trace_options; - trace_options.setThreadID(thread); - error = NativeProcessLinux::GetTraceConfig(traceid, trace_options); - - if (error.Fail()) - return error; - - switch (trace_options.getType()) { - case lldb::TraceType::eTraceTypeProcessorTrace: - if (traceid == m_pt_proces_trace_id && - thread == LLDB_INVALID_THREAD_ID) - StopProcessorTracingOnProcess(); - else - error = StopProcessorTracingOnThread(traceid, thread); - break; - default: - error.SetErrorString("trace not supported"); - break; - } - - return error; +Error NativeProcessLinux::TraceStop(const TraceStopRequest &request) { + if (request.type == "intel-pt") + return m_intel_pt_manager.TraceStop(request); + return NativeProcessProtocol::TraceStop(request); } -void NativeProcessLinux::StopProcessorTracingOnProcess() { - for (auto thread_id_iter : m_pt_traced_thread_group) - m_processor_trace_monitor.erase(thread_id_iter); - m_pt_traced_thread_group.clear(); - m_pt_proces_trace_id = LLDB_INVALID_UID; +Expected NativeProcessLinux::TraceGetState(StringRef type) { + if (type == "intel-pt") + return m_intel_pt_manager.GetState(); + return NativeProcessProtocol::TraceGetState(type); } -Status NativeProcessLinux::StopProcessorTracingOnThread(lldb::user_id_t traceid, - lldb::tid_t thread) { - Status error; - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PTRACE)); - - if (thread == LLDB_INVALID_THREAD_ID) { - for (auto& iter : m_processor_trace_monitor) { - if (iter.second->GetTraceID() == traceid) { - // Stopping a trace instance for an individual thread hence there will - // only be one traceid that can match. - m_processor_trace_monitor.erase(iter.first); - return error; - } - LLDB_LOG(log, "Trace ID {0}", iter.second->GetTraceID()); - } - - LLDB_LOG(log, "Invalid TraceID"); - error.SetErrorString("invalid trace id"); - return error; - } - - // thread is specified so we can use find function on the map. - const auto& iter = m_processor_trace_monitor.find(thread); - if (iter == m_processor_trace_monitor.end()) { - // thread not found in our map. - LLDB_LOG(log, "thread not being traced"); - error.SetErrorString("tracing not active for this thread"); - return error; - } - if (iter->second->GetTraceID() != traceid) { - // traceid did not match so it has to be invalid. - LLDB_LOG(log, "Invalid TraceID"); - error.SetErrorString("invalid trace id"); - return error; - } - - LLDB_LOG(log, "UID - {0} , Thread -{1}", traceid, thread); - - if (traceid == m_pt_proces_trace_id) { - // traceid maps to the whole process so we have to erase it from the thread - // group. - LLDB_LOG(log, "traceid maps to process"); - m_pt_traced_thread_group.erase(thread); - } - m_processor_trace_monitor.erase(iter); - - return error; +Expected> NativeProcessLinux::TraceGetBinaryData( + const TraceGetBinaryDataRequest &request) { + if (request.type == "intel-pt") + return m_intel_pt_manager.GetBinaryData(request); + return NativeProcessProtocol::TraceGetBinaryData(request); } diff --git a/gnu/llvm/lldb/source/Plugins/Process/Linux/NativeProcessLinux.h b/gnu/llvm/lldb/source/Plugins/Process/Linux/NativeProcessLinux.h index 1366f0b1fe3..902afb6aa98 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/Linux/NativeProcessLinux.h +++ b/gnu/llvm/lldb/source/Plugins/Process/Linux/NativeProcessLinux.h @@ -20,9 +20,10 @@ #include "lldb/Utility/FileSpec.h" #include "lldb/lldb-types.h" +#include "IntelPTManager.h" #include "NativeThreadLinux.h" #include "Plugins/Process/POSIX/NativeProcessELF.h" -#include "ProcessorTrace.h" +#include "Plugins/Process/Utility/NativeProcessSoftwareSingleStep.h" namespace lldb_private { class Status; @@ -36,7 +37,8 @@ namespace process_linux { /// for debugging. /// /// Changes in the inferior process state are broadcasted. -class NativeProcessLinux : public NativeProcessELF { +class NativeProcessLinux : public NativeProcessELF, + private NativeProcessSoftwareSingleStep { public: class Factory : public NativeProcessProtocol::Factory { public: @@ -47,6 +49,8 @@ public: llvm::Expected> Attach(lldb::pid_t pid, NativeDelegate &native_delegate, MainLoop &mainloop) const override; + + Extension GetSupportedExtensions() const override; }; // NativeProcessProtocol Interface @@ -71,10 +75,16 @@ public: Status WriteMemory(lldb::addr_t addr, const void *buf, size_t size, size_t &bytes_written) override; - Status AllocateMemory(size_t size, uint32_t permissions, - lldb::addr_t &addr) override; + llvm::Expected AllocateMemory(size_t size, + uint32_t permissions) override; + + llvm::Error DeallocateMemory(lldb::addr_t addr) override; + + Status ReadMemoryTags(int32_t type, lldb::addr_t addr, size_t len, + std::vector &tags) override; - Status DeallocateMemory(lldb::addr_t addr) override; + Status WriteMemoryTags(int32_t type, lldb::addr_t addr, size_t len, + const std::vector &tags) override; size_t UpdateThreads() override; @@ -94,27 +104,29 @@ public: lldb::addr_t &load_addr) override; NativeThreadLinux *GetThreadByID(lldb::tid_t id); + NativeThreadLinux *GetCurrentThread(); llvm::ErrorOr> GetAuxvData() const override { return getProcFile(GetID(), "auxv"); } - lldb::user_id_t StartTrace(const TraceOptions &config, - Status &error) override; + /// Tracing + /// These methods implement the jLLDBTrace packets + /// \{ + llvm::Error TraceStart(llvm::StringRef json_request, + llvm::StringRef type) override; - Status StopTrace(lldb::user_id_t traceid, - lldb::tid_t thread) override; + llvm::Error TraceStop(const TraceStopRequest &request) override; - Status GetData(lldb::user_id_t traceid, lldb::tid_t thread, - llvm::MutableArrayRef &buffer, - size_t offset = 0) override; + llvm::Expected + TraceGetState(llvm::StringRef type) override; - Status GetMetaData(lldb::user_id_t traceid, lldb::tid_t thread, - llvm::MutableArrayRef &buffer, - size_t offset = 0) override; + llvm::Expected> + TraceGetBinaryData(const TraceGetBinaryDataRequest &request) override; - Status GetTraceConfig(lldb::user_id_t traceid, TraceOptions &config) override; + llvm::Expected TraceSupported() override; + /// } // Interface used by NativeRegisterContext-derived classes. static Status PtraceWrapper(int req, lldb::pid_t pid, void *addr = nullptr, @@ -127,18 +139,20 @@ protected: llvm::Expected> GetSoftwareBreakpointTrapOpcode(size_t size_hint) override; + llvm::Expected Syscall(llvm::ArrayRef args); + private: MainLoop::SignalHandleUP m_sigchld_handle; ArchSpec m_arch; + MainLoop& m_main_loop; LazyBool m_supports_mem_region = eLazyBoolCalculate; std::vector> m_mem_region_cache; lldb::tid_t m_pending_notification_tid = LLDB_INVALID_THREAD_ID; - // List of thread ids stepping with a breakpoint with the address of - // the relevan breakpoint - std::map m_threads_stepping_with_breakpoint; + /// Inferior memory (allocated by us) and its size. + llvm::DenseMap m_allocated_memory; // Private Instance Methods NativeProcessLinux(::pid_t pid, int terminal_fd, NativeDelegate &delegate, @@ -152,7 +166,7 @@ private: void MonitorCallback(lldb::pid_t pid, bool exited, WaitStatus status); - void WaitForNewThread(::pid_t tid); + void WaitForCloneNotification(::pid_t pid); void MonitorSIGTRAP(const siginfo_t &info, NativeThreadLinux &thread); @@ -165,13 +179,32 @@ private: void MonitorSignal(const siginfo_t &info, NativeThreadLinux &thread, bool exited); - Status SetupSoftwareSingleStepping(NativeThreadLinux &thread); - bool HasThreadNoLock(lldb::tid_t thread_id); bool StopTrackingThread(lldb::tid_t thread_id); - NativeThreadLinux &AddThread(lldb::tid_t thread_id); + /// Create a new thread. + /// + /// If process tracing is enabled and the thread can't be traced, then the + /// thread is left stopped with a \a eStopReasonProcessorTrace status, and + /// then the process is stopped. + /// + /// \param[in] resume + /// If a tracing error didn't happen, then resume the thread after + /// creation if \b true, or leave it stopped with SIGSTOP if \b false. + NativeThreadLinux &AddThread(lldb::tid_t thread_id, bool resume); + + /// Start tracing a new thread if process tracing is enabled. + /// + /// Trace mechanisms should modify this method to provide automatic tracing + /// for new threads. + Status NotifyTracersOfNewThread(lldb::tid_t tid); + + /// Stop tracing threads upon a destroy event. + /// + /// Trace mechanisms should modify this method to provide automatic trace + /// stopping for threads being destroyed. + Status NotifyTracersOfThreadDestroyed(lldb::tid_t tid); /// Writes a siginfo_t structure corresponding to the given thread ID to the /// memory region pointed to by \p siginfo. @@ -208,42 +241,23 @@ private: Status PopulateMemoryRegionCache(); - lldb::user_id_t StartTraceGroup(const TraceOptions &config, - Status &error); - - // This function is intended to be used to stop tracing - // on a thread that exited. - Status StopTracingForThread(lldb::tid_t thread); - - // The below function as the name suggests, looks up a ProcessorTrace - // instance from the m_processor_trace_monitor map. In the case of - // process tracing where the traceid passed would map to the complete - // process, it is mandatory to provide a threadid to obtain a trace - // instance (since ProcessorTrace is tied to a thread). In the other - // scenario that an individual thread is being traced, just the traceid - // is sufficient to obtain the actual ProcessorTrace instance. - llvm::Expected - LookupProcessorTraceInstance(lldb::user_id_t traceid, lldb::tid_t thread); - - // Stops tracing on individual threads being traced. Not intended - // to be used to stop tracing on complete process. - Status StopProcessorTracingOnThread(lldb::user_id_t traceid, - lldb::tid_t thread); - - // Intended to stop tracing on complete process. - // Should not be used for stopping trace on - // individual threads. - void StopProcessorTracingOnProcess(); - - llvm::DenseMap - m_processor_trace_monitor; - - // Set for tracking threads being traced under - // same process user id. - llvm::DenseSet m_pt_traced_thread_group; - - lldb::user_id_t m_pt_proces_trace_id = LLDB_INVALID_UID; - TraceOptions m_pt_process_trace_config; + /// Manages Intel PT process and thread traces. + IntelPTManager m_intel_pt_manager; + + struct CloneInfo { + int event; + lldb::tid_t parent_tid; + }; + + // Map of child processes that have been signaled once, and we are + // waiting for the second signal. + llvm::DenseMap> m_pending_pid_map; + + // Handle a clone()-like event. If received by parent, clone_info contains + // additional info. Returns true if the event is handled, or false if it + // is pending second notification. + bool MonitorClone(lldb::pid_t child_pid, + llvm::Optional clone_info); }; } // namespace process_linux diff --git a/gnu/llvm/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux.cpp b/gnu/llvm/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux.cpp index 1b9e067639c..90a6d8dcba0 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux.cpp +++ b/gnu/llvm/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux.cpp @@ -19,11 +19,6 @@ using namespace lldb_private; using namespace lldb_private::process_linux; -NativeRegisterContextLinux::NativeRegisterContextLinux( - NativeThreadProtocol &native_thread, - RegisterInfoInterface *reg_info_interface_p) - : NativeRegisterContextRegisterInfo(native_thread, reg_info_interface_p) {} - lldb::ByteOrder NativeRegisterContextLinux::GetByteOrder() const { return m_thread.GetProcess().GetByteOrder(); } diff --git a/gnu/llvm/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux.h b/gnu/llvm/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux.h index da7a762419f..b66f6907d8a 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux.h +++ b/gnu/llvm/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux.h @@ -11,27 +11,77 @@ #include "Plugins/Process/Utility/NativeRegisterContextRegisterInfo.h" #include "lldb/Host/common/NativeThreadProtocol.h" +#include "lldb/Target/MemoryTagManager.h" +#include "llvm/Support/Error.h" namespace lldb_private { namespace process_linux { -class NativeRegisterContextLinux : public NativeRegisterContextRegisterInfo { -public: - NativeRegisterContextLinux(NativeThreadProtocol &native_thread, - RegisterInfoInterface *reg_info_interface_p); +class NativeThreadLinux; +class NativeRegisterContextLinux + : public virtual NativeRegisterContextRegisterInfo { +public: // This function is implemented in the NativeRegisterContextLinux_* subclasses // to create a new instance of the host specific NativeRegisterContextLinux. // The implementations can't collide as only one NativeRegisterContextLinux_* // variant should be compiled into the final executable. static std::unique_ptr CreateHostNativeRegisterContextLinux(const ArchSpec &target_arch, - NativeThreadProtocol &native_thread); + NativeThreadLinux &native_thread); // Invalidates cached values in register context data structures virtual void InvalidateAllRegisters(){} + struct SyscallData { + /// The syscall instruction. If the architecture uses software + /// single-stepping, the instruction should also be followed by a trap to + /// ensure the process is stopped after the syscall. + llvm::ArrayRef Insn; + + /// Registers used for syscall arguments. The first register is used to + /// store the syscall number. + llvm::ArrayRef Args; + + uint32_t Result; ///< Register containing the syscall result. + }; + /// Return architecture-specific data needed to make inferior syscalls, if + /// they are supported. + virtual llvm::Optional GetSyscallData() { return llvm::None; } + + struct MmapData { + // Syscall numbers can be found (e.g.) in /usr/include/asm/unistd.h for the + // relevant architecture. + unsigned SysMmap; ///< mmap syscall number. + unsigned SysMunmap; ///< munmap syscall number + }; + /// Return the architecture-specific data needed to make mmap syscalls, if + /// they are supported. + virtual llvm::Optional GetMmapData() { return llvm::None; } + + struct MemoryTaggingDetails { + /// Object with tag handling utilities. If the function below returns + /// a valid structure, you can assume that this pointer is valid. + std::unique_ptr manager; + int ptrace_read_req; /// ptrace operation number for memory tag read + int ptrace_write_req; /// ptrace operation number for memory tag write + }; + /// Return architecture specific data needed to use memory tags, + /// if they are supported. + virtual llvm::Expected + GetMemoryTaggingDetails(int32_t type) { + return llvm::createStringError( + llvm::inconvertibleErrorCode(), + "Architecture does not support memory tagging"); + } + protected: + // NB: This constructor is here only because gcc<=6.5 requires a virtual base + // class initializer on abstract class (even though it is never used). It can + // be deleted once we move to gcc>=7.0. + NativeRegisterContextLinux(NativeThreadProtocol &thread) + : NativeRegisterContextRegisterInfo(thread, nullptr) {} + lldb::ByteOrder GetByteOrder() const; virtual Status ReadRegisterRaw(uint32_t reg_index, RegisterValue ®_value); diff --git a/gnu/llvm/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.cpp b/gnu/llvm/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.cpp index a83491e6d89..91f88280145 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.cpp +++ b/gnu/llvm/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.cpp @@ -43,60 +43,11 @@ using namespace lldb; using namespace lldb_private; using namespace lldb_private::process_linux; -// arm general purpose registers. -static const uint32_t g_gpr_regnums_arm[] = { - gpr_r0_arm, gpr_r1_arm, gpr_r2_arm, gpr_r3_arm, gpr_r4_arm, - gpr_r5_arm, gpr_r6_arm, gpr_r7_arm, gpr_r8_arm, gpr_r9_arm, - gpr_r10_arm, gpr_r11_arm, gpr_r12_arm, gpr_sp_arm, gpr_lr_arm, - gpr_pc_arm, gpr_cpsr_arm, - LLDB_INVALID_REGNUM // register sets need to end with this flag -}; -static_assert(((sizeof g_gpr_regnums_arm / sizeof g_gpr_regnums_arm[0]) - 1) == - k_num_gpr_registers_arm, - "g_gpr_regnums_arm has wrong number of register infos"); - -// arm floating point registers. -static const uint32_t g_fpu_regnums_arm[] = { - fpu_s0_arm, fpu_s1_arm, fpu_s2_arm, fpu_s3_arm, fpu_s4_arm, - fpu_s5_arm, fpu_s6_arm, fpu_s7_arm, fpu_s8_arm, fpu_s9_arm, - fpu_s10_arm, fpu_s11_arm, fpu_s12_arm, fpu_s13_arm, fpu_s14_arm, - fpu_s15_arm, fpu_s16_arm, fpu_s17_arm, fpu_s18_arm, fpu_s19_arm, - fpu_s20_arm, fpu_s21_arm, fpu_s22_arm, fpu_s23_arm, fpu_s24_arm, - fpu_s25_arm, fpu_s26_arm, fpu_s27_arm, fpu_s28_arm, fpu_s29_arm, - fpu_s30_arm, fpu_s31_arm, fpu_fpscr_arm, fpu_d0_arm, fpu_d1_arm, - fpu_d2_arm, fpu_d3_arm, fpu_d4_arm, fpu_d5_arm, fpu_d6_arm, - fpu_d7_arm, fpu_d8_arm, fpu_d9_arm, fpu_d10_arm, fpu_d11_arm, - fpu_d12_arm, fpu_d13_arm, fpu_d14_arm, fpu_d15_arm, fpu_d16_arm, - fpu_d17_arm, fpu_d18_arm, fpu_d19_arm, fpu_d20_arm, fpu_d21_arm, - fpu_d22_arm, fpu_d23_arm, fpu_d24_arm, fpu_d25_arm, fpu_d26_arm, - fpu_d27_arm, fpu_d28_arm, fpu_d29_arm, fpu_d30_arm, fpu_d31_arm, - fpu_q0_arm, fpu_q1_arm, fpu_q2_arm, fpu_q3_arm, fpu_q4_arm, - fpu_q5_arm, fpu_q6_arm, fpu_q7_arm, fpu_q8_arm, fpu_q9_arm, - fpu_q10_arm, fpu_q11_arm, fpu_q12_arm, fpu_q13_arm, fpu_q14_arm, - fpu_q15_arm, - LLDB_INVALID_REGNUM // register sets need to end with this flag -}; -static_assert(((sizeof g_fpu_regnums_arm / sizeof g_fpu_regnums_arm[0]) - 1) == - k_num_fpr_registers_arm, - "g_fpu_regnums_arm has wrong number of register infos"); - -namespace { -// Number of register sets provided by this context. -enum { k_num_register_sets = 2 }; -} - -// Register sets for arm. -static const RegisterSet g_reg_sets_arm[k_num_register_sets] = { - {"General Purpose Registers", "gpr", k_num_gpr_registers_arm, - g_gpr_regnums_arm}, - {"Floating Point Registers", "fpu", k_num_fpr_registers_arm, - g_fpu_regnums_arm}}; - #if defined(__arm__) std::unique_ptr NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux( - const ArchSpec &target_arch, NativeThreadProtocol &native_thread) { + const ArchSpec &target_arch, NativeThreadLinux &native_thread) { return std::make_unique(target_arch, native_thread); } @@ -105,24 +56,10 @@ NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux( NativeRegisterContextLinux_arm::NativeRegisterContextLinux_arm( const ArchSpec &target_arch, NativeThreadProtocol &native_thread) - : NativeRegisterContextLinux(native_thread, - new RegisterInfoPOSIX_arm(target_arch)) { - switch (target_arch.GetMachine()) { - case llvm::Triple::arm: - m_reg_info.num_registers = k_num_registers_arm; - m_reg_info.num_gpr_registers = k_num_gpr_registers_arm; - m_reg_info.num_fpr_registers = k_num_fpr_registers_arm; - m_reg_info.last_gpr = k_last_gpr_arm; - m_reg_info.first_fpr = k_first_fpr_arm; - m_reg_info.last_fpr = k_last_fpr_arm; - m_reg_info.first_fpr_v = fpu_s0_arm; - m_reg_info.last_fpr_v = fpu_s31_arm; - m_reg_info.gpr_flags = gpr_cpsr_arm; - break; - default: - assert(false && "Unhandled target architecture."); - break; - } + : NativeRegisterContextRegisterInfo(native_thread, + new RegisterInfoPOSIX_arm(target_arch)), + NativeRegisterContextLinux(native_thread) { + assert(target_arch.GetMachine() == llvm::Triple::arm); ::memset(&m_fpr, 0, sizeof(m_fpr)); ::memset(&m_gpr_arm, 0, sizeof(m_gpr_arm)); @@ -135,23 +72,24 @@ NativeRegisterContextLinux_arm::NativeRegisterContextLinux_arm( m_refresh_hwdebug_info = true; } +RegisterInfoPOSIX_arm &NativeRegisterContextLinux_arm::GetRegisterInfo() const { + return static_cast(*m_register_info_interface_up); +} + uint32_t NativeRegisterContextLinux_arm::GetRegisterSetCount() const { - return k_num_register_sets; + return GetRegisterInfo().GetRegisterSetCount(); } uint32_t NativeRegisterContextLinux_arm::GetUserRegisterCount() const { uint32_t count = 0; - for (uint32_t set_index = 0; set_index < k_num_register_sets; ++set_index) - count += g_reg_sets_arm[set_index].num_registers; + for (uint32_t set_index = 0; set_index < GetRegisterSetCount(); ++set_index) + count += GetRegisterSet(set_index)->num_registers; return count; } const RegisterSet * NativeRegisterContextLinux_arm::GetRegisterSet(uint32_t set_index) const { - if (set_index < k_num_register_sets) - return &g_reg_sets_arm[set_index]; - - return nullptr; + return GetRegisterInfo().GetRegisterSet(set_index); } Status @@ -336,11 +274,17 @@ Status NativeRegisterContextLinux_arm::WriteAllRegisterValues( } bool NativeRegisterContextLinux_arm::IsGPR(unsigned reg) const { - return reg <= m_reg_info.last_gpr; // GPR's come first. + if (GetRegisterInfo().GetRegisterSetFromRegisterIndex(reg) == + RegisterInfoPOSIX_arm::GPRegSet) + return true; + return false; } bool NativeRegisterContextLinux_arm::IsFPR(unsigned reg) const { - return (m_reg_info.first_fpr <= reg && reg <= m_reg_info.last_fpr); + if (GetRegisterInfo().GetRegisterSetFromRegisterIndex(reg) == + RegisterInfoPOSIX_arm::FPRegSet) + return true; + return false; } uint32_t NativeRegisterContextLinux_arm::NumSupportedHardwareBreakpoints() { @@ -851,8 +795,7 @@ Status NativeRegisterContextLinux_arm::WriteHardwareDebugRegs(int hwbType, uint32_t NativeRegisterContextLinux_arm::CalculateFprOffset( const RegisterInfo *reg_info) const { - return reg_info->byte_offset - - GetRegisterInfoAtIndex(m_reg_info.first_fpr)->byte_offset; + return reg_info->byte_offset - GetGPRSize(); } Status NativeRegisterContextLinux_arm::DoReadRegisterValue( diff --git a/gnu/llvm/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.h b/gnu/llvm/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.h index 6bd4db573c6..4ce3797e7bd 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm.h +++ b/gnu/llvm/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/RegisterInfoPOSIX_arm.h" #include "Plugins/Process/Utility/lldb-arm-register-enums.h" namespace lldb_private { @@ -98,37 +99,8 @@ protected: size_t GetFPRSize() override { return sizeof(m_fpr); } private: - struct RegInfo { - uint32_t num_registers; - uint32_t num_gpr_registers; - uint32_t num_fpr_registers; - - uint32_t last_gpr; - uint32_t first_fpr; - uint32_t last_fpr; - - uint32_t first_fpr_v; - uint32_t last_fpr_v; - - uint32_t gpr_flags; - }; - - struct QReg { - uint8_t bytes[16]; - }; - - struct FPU { - union { - uint32_t s[32]; - uint64_t d[32]; - QReg q[16]; // the 128-bit NEON registers - } floats; - uint32_t fpscr; - }; - uint32_t m_gpr_arm[k_num_gpr_registers_arm]; - RegInfo m_reg_info; - FPU m_fpr; + RegisterInfoPOSIX_arm::FPU m_fpr; // Debug register info for hardware breakpoints and watchpoints management. struct DREG { @@ -156,6 +128,8 @@ private: Status WriteHardwareDebugRegs(int hwbType, int hwb_index); uint32_t CalculateFprOffset(const RegisterInfo *reg_info) const; + + RegisterInfoPOSIX_arm &GetRegisterInfo() const; }; } // namespace process_linux diff --git a/gnu/llvm/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp b/gnu/llvm/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp index beae3aef7c0..23693e4484a 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp +++ b/gnu/llvm/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.cpp @@ -13,6 +13,7 @@ #include "lldb/Host/common/NativeProcessProtocol.h" +#include "lldb/Host/linux/Ptrace.h" #include "lldb/Utility/DataBufferHeap.h" #include "lldb/Utility/Log.h" #include "lldb/Utility/RegisterValue.h" @@ -21,16 +22,29 @@ #include "Plugins/Process/Linux/NativeProcessLinux.h" #include "Plugins/Process/Linux/Procfs.h" #include "Plugins/Process/POSIX/ProcessPOSIXLog.h" +#include "Plugins/Process/Utility/MemoryTagManagerAArch64MTE.h" +#include "Plugins/Process/Utility/RegisterInfoPOSIX_arm64.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 // NT_PRSTATUS and NT_FPREGSET definition #include -// user_hwdebug_state definition -#include -#define REG_CONTEXT_SIZE (GetGPRSize() + GetFPRSize()) +#ifndef NT_ARM_SVE +#define NT_ARM_SVE 0x405 /* ARM Scalable Vector Extension */ +#endif + +#ifndef NT_ARM_PAC_MASK +#define NT_ARM_PAC_MASK 0x406 /* Pointer authentication code masks */ +#endif + +#ifndef NT_ARM_TAGGED_ADDR_CTRL +#define NT_ARM_TAGGED_ADDR_CTRL 0x409 /* Tagged address control register */ +#endif + +#define HWCAP_PACA (1 << 30) +#define HWCAP2_MTE (1 << 18) using namespace lldb; using namespace lldb_private; @@ -38,35 +52,81 @@ using namespace lldb_private::process_linux; std::unique_ptr NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux( - const ArchSpec &target_arch, NativeThreadProtocol &native_thread) { + const ArchSpec &target_arch, NativeThreadLinux &native_thread) { switch (target_arch.GetMachine()) { case llvm::Triple::arm: return std::make_unique(target_arch, - native_thread); - case llvm::Triple::aarch64: - return std::make_unique(target_arch, - native_thread); + native_thread); + case llvm::Triple::aarch64: { + // Configure register sets supported by this AArch64 target. + // Read SVE header to check for SVE support. + struct user_sve_header sve_header; + struct iovec ioVec; + ioVec.iov_base = &sve_header; + ioVec.iov_len = sizeof(sve_header); + unsigned int regset = NT_ARM_SVE; + + Flags opt_regsets; + if (NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, + native_thread.GetID(), ®set, + &ioVec, sizeof(sve_header)) + .Success()) + opt_regsets.Set(RegisterInfoPOSIX_arm64::eRegsetMaskSVE); + + NativeProcessLinux &process = native_thread.GetProcess(); + + llvm::Optional auxv_at_hwcap = + process.GetAuxValue(AuxVector::AUXV_AT_HWCAP); + if (auxv_at_hwcap && (*auxv_at_hwcap & HWCAP_PACA)) + opt_regsets.Set(RegisterInfoPOSIX_arm64::eRegsetMaskPAuth); + + llvm::Optional auxv_at_hwcap2 = + process.GetAuxValue(AuxVector::AUXV_AT_HWCAP2); + if (auxv_at_hwcap2 && (*auxv_at_hwcap2 & HWCAP2_MTE)) + opt_regsets.Set(RegisterInfoPOSIX_arm64::eRegsetMaskMTE); + + auto register_info_up = + std::make_unique(target_arch, opt_regsets); + return std::make_unique( + target_arch, native_thread, std::move(register_info_up)); + } default: llvm_unreachable("have no register context for architecture"); } } NativeRegisterContextLinux_arm64::NativeRegisterContextLinux_arm64( - const ArchSpec &target_arch, NativeThreadProtocol &native_thread) - : NativeRegisterContextLinux(native_thread, - new RegisterInfoPOSIX_arm64(target_arch)) { + const ArchSpec &target_arch, NativeThreadProtocol &native_thread, + std::unique_ptr register_info_up) + : NativeRegisterContextRegisterInfo(native_thread, + register_info_up.release()), + NativeRegisterContextLinux(native_thread) { ::memset(&m_fpr, 0, sizeof(m_fpr)); ::memset(&m_gpr_arm64, 0, sizeof(m_gpr_arm64)); ::memset(&m_hwp_regs, 0, sizeof(m_hwp_regs)); - ::memset(&m_hbr_regs, 0, sizeof(m_hbr_regs)); + ::memset(&m_hbp_regs, 0, sizeof(m_hbp_regs)); + ::memset(&m_sve_header, 0, sizeof(m_sve_header)); + ::memset(&m_pac_mask, 0, sizeof(m_pac_mask)); + + m_mte_ctrl_reg = 0; // 16 is just a maximum value, query hardware for actual watchpoint count m_max_hwp_supported = 16; m_max_hbp_supported = 16; + m_refresh_hwdebug_info = true; m_gpr_is_valid = false; m_fpu_is_valid = false; + m_sve_buffer_is_valid = false; + m_sve_header_is_valid = false; + m_pac_mask_is_valid = false; + m_mte_ctrl_is_valid = false; + + if (GetRegisterInfo().IsSVEEnabled()) + m_sve_state = SVEState::Unknown; + else + m_sve_state = SVEState::Disabled; } RegisterInfoPOSIX_arm64 & @@ -108,29 +168,112 @@ NativeRegisterContextLinux_arm64::ReadRegister(const RegisterInfo *reg_info, : ""); uint8_t *src; - uint32_t offset; + uint32_t offset = LLDB_INVALID_INDEX32; + uint64_t sve_vg; + std::vector sve_reg_non_live; if (IsGPR(reg)) { - if (!m_gpr_is_valid) { - error = ReadGPR(); - if (error.Fail()) - return error; - } + error = ReadGPR(); + if (error.Fail()) + return error; offset = reg_info->byte_offset; assert(offset < GetGPRSize()); src = (uint8_t *)GetGPRBuffer() + offset; } else if (IsFPR(reg)) { - if (!m_fpu_is_valid) { - + if (m_sve_state == SVEState::Disabled) { + // SVE is disabled take legacy route for FPU register access error = ReadFPR(); if (error.Fail()) return error; + + offset = CalculateFprOffset(reg_info); + assert(offset < GetFPRSize()); + src = (uint8_t *)GetFPRBuffer() + offset; + } else { + // SVE enabled, we will read and cache SVE ptrace data + error = ReadAllSVE(); + if (error.Fail()) + return error; + + // FPSR and FPCR will be located right after Z registers in + // SVEState::FPSIMD while in SVEState::Full they will be located at the + // end of register data after an alignment correction based on currently + // selected vector length. + uint32_t sve_reg_num = LLDB_INVALID_REGNUM; + if (reg == GetRegisterInfo().GetRegNumFPSR()) { + sve_reg_num = reg; + if (m_sve_state == SVEState::Full) + offset = sve::PTraceFPSROffset(sve::vq_from_vl(m_sve_header.vl)); + else if (m_sve_state == SVEState::FPSIMD) + offset = sve::ptrace_fpsimd_offset + (32 * 16); + } else if (reg == GetRegisterInfo().GetRegNumFPCR()) { + sve_reg_num = reg; + if (m_sve_state == SVEState::Full) + offset = sve::PTraceFPCROffset(sve::vq_from_vl(m_sve_header.vl)); + else if (m_sve_state == SVEState::FPSIMD) + offset = sve::ptrace_fpsimd_offset + (32 * 16) + 4; + } else { + // Extract SVE Z register value register number for this reg_info + if (reg_info->value_regs && + reg_info->value_regs[0] != LLDB_INVALID_REGNUM) + sve_reg_num = reg_info->value_regs[0]; + offset = CalculateSVEOffset(GetRegisterInfoAtIndex(sve_reg_num)); + } + + assert(offset < GetSVEBufferSize()); + src = (uint8_t *)GetSVEBuffer() + offset; + } + } else if (IsSVE(reg)) { + + if (m_sve_state == SVEState::Disabled || m_sve_state == SVEState::Unknown) + return Status("SVE disabled or not supported"); + + if (GetRegisterInfo().IsSVERegVG(reg)) { + sve_vg = GetSVERegVG(); + src = (uint8_t *)&sve_vg; + } else { + // SVE enabled, we will read and cache SVE ptrace data + error = ReadAllSVE(); + if (error.Fail()) + return error; + + if (m_sve_state == SVEState::FPSIMD) { + // In FPSIMD state SVE payload mirrors legacy fpsimd struct and so + // just copy 16 bytes of v register to the start of z register. All + // other SVE register will be set to zero. + sve_reg_non_live.resize(reg_info->byte_size, 0); + src = sve_reg_non_live.data(); + + if (GetRegisterInfo().IsSVEZReg(reg)) { + offset = CalculateSVEOffset(reg_info); + assert(offset < GetSVEBufferSize()); + ::memcpy(sve_reg_non_live.data(), (uint8_t *)GetSVEBuffer() + offset, + 16); + } + } else { + offset = CalculateSVEOffset(reg_info); + assert(offset < GetSVEBufferSize()); + src = (uint8_t *)GetSVEBuffer() + offset; + } } - offset = CalculateFprOffset(reg_info); - assert(offset < GetFPRSize()); - src = (uint8_t *)GetFPRBuffer() + offset; + } else if (IsPAuth(reg)) { + error = ReadPAuthMask(); + if (error.Fail()) + return error; + + offset = reg_info->byte_offset - GetRegisterInfo().GetPAuthOffset(); + assert(offset < GetPACMaskSize()); + src = (uint8_t *)GetPACMask() + offset; + } else if (IsMTE(reg)) { + error = ReadMTEControl(); + if (error.Fail()) + return error; + + offset = reg_info->byte_offset - GetRegisterInfo().GetMTEOffset(); + assert(offset < GetMTEControlSize()); + src = (uint8_t *)GetMTEControl() + offset; } else return Status("failed - register wasn't recognized to be a GPR or an FPR, " "write strategy unknown"); @@ -156,83 +299,231 @@ Status NativeRegisterContextLinux_arm64::WriteRegister( : ""); uint8_t *dst; - uint32_t offset; + uint32_t offset = LLDB_INVALID_INDEX32; + std::vector sve_reg_non_live; if (IsGPR(reg)) { - if (!m_gpr_is_valid) { - error = ReadGPR(); - if (error.Fail()) - return error; - } - - offset = reg_info->byte_offset; - assert(offset < GetGPRSize()); - dst = (uint8_t *)GetGPRBuffer() + offset; + error = ReadGPR(); + if (error.Fail()) + return error; + assert(reg_info->byte_offset < GetGPRSize()); + dst = (uint8_t *)GetGPRBuffer() + reg_info->byte_offset; ::memcpy(dst, reg_value.GetBytes(), reg_info->byte_size); return WriteGPR(); } else if (IsFPR(reg)) { - if (!m_fpu_is_valid) { + if (m_sve_state == SVEState::Disabled) { + // SVE is disabled take legacy route for FPU register access error = ReadFPR(); if (error.Fail()) return error; + + offset = CalculateFprOffset(reg_info); + assert(offset < GetFPRSize()); + dst = (uint8_t *)GetFPRBuffer() + offset; + ::memcpy(dst, reg_value.GetBytes(), reg_info->byte_size); + + return WriteFPR(); + } else { + // SVE enabled, we will read and cache SVE ptrace data + error = ReadAllSVE(); + if (error.Fail()) + return error; + + // FPSR and FPCR will be located right after Z registers in + // SVEState::FPSIMD while in SVEState::Full they will be located at the + // end of register data after an alignment correction based on currently + // selected vector length. + uint32_t sve_reg_num = LLDB_INVALID_REGNUM; + if (reg == GetRegisterInfo().GetRegNumFPSR()) { + sve_reg_num = reg; + if (m_sve_state == SVEState::Full) + offset = sve::PTraceFPSROffset(sve::vq_from_vl(m_sve_header.vl)); + else if (m_sve_state == SVEState::FPSIMD) + offset = sve::ptrace_fpsimd_offset + (32 * 16); + } else if (reg == GetRegisterInfo().GetRegNumFPCR()) { + sve_reg_num = reg; + if (m_sve_state == SVEState::Full) + offset = sve::PTraceFPCROffset(sve::vq_from_vl(m_sve_header.vl)); + else if (m_sve_state == SVEState::FPSIMD) + offset = sve::ptrace_fpsimd_offset + (32 * 16) + 4; + } else { + // Extract SVE Z register value register number for this reg_info + if (reg_info->value_regs && + reg_info->value_regs[0] != LLDB_INVALID_REGNUM) + sve_reg_num = reg_info->value_regs[0]; + offset = CalculateSVEOffset(GetRegisterInfoAtIndex(sve_reg_num)); + } + + assert(offset < GetSVEBufferSize()); + dst = (uint8_t *)GetSVEBuffer() + offset; + ::memcpy(dst, reg_value.GetBytes(), reg_info->byte_size); + return WriteAllSVE(); } - offset = CalculateFprOffset(reg_info); - assert(offset < GetFPRSize()); - dst = (uint8_t *)GetFPRBuffer() + offset; + } else if (IsSVE(reg)) { + if (m_sve_state == SVEState::Disabled || m_sve_state == SVEState::Unknown) + return Status("SVE disabled or not supported"); + else { + // Target has SVE enabled, we will read and cache SVE ptrace data + error = ReadAllSVE(); + if (error.Fail()) + return error; + if (GetRegisterInfo().IsSVERegVG(reg)) { + uint64_t vg_value = reg_value.GetAsUInt64(); + + if (sve_vl_valid(vg_value * 8)) { + if (m_sve_header_is_valid && vg_value == GetSVERegVG()) + return error; + + SetSVERegVG(vg_value); + + error = WriteSVEHeader(); + if (error.Success()) + ConfigureRegisterContext(); + + if (m_sve_header_is_valid && vg_value == GetSVERegVG()) + return error; + } + + return Status("SVE vector length update failed."); + } + + // If target supports SVE but currently in FPSIMD mode. + if (m_sve_state == SVEState::FPSIMD) { + // Here we will check if writing this SVE register enables + // SVEState::Full + bool set_sve_state_full = false; + const uint8_t *reg_bytes = (const uint8_t *)reg_value.GetBytes(); + if (GetRegisterInfo().IsSVEZReg(reg)) { + for (uint32_t i = 16; i < reg_info->byte_size; i++) { + if (reg_bytes[i]) { + set_sve_state_full = true; + break; + } + } + } else if (GetRegisterInfo().IsSVEPReg(reg) || + reg == GetRegisterInfo().GetRegNumSVEFFR()) { + for (uint32_t i = 0; i < reg_info->byte_size; i++) { + if (reg_bytes[i]) { + set_sve_state_full = true; + break; + } + } + } + + if (!set_sve_state_full && GetRegisterInfo().IsSVEZReg(reg)) { + // We are writing a Z register which is zero beyond 16 bytes so copy + // first 16 bytes only as SVE payload mirrors legacy fpsimd structure + offset = CalculateSVEOffset(reg_info); + assert(offset < GetSVEBufferSize()); + dst = (uint8_t *)GetSVEBuffer() + offset; + ::memcpy(dst, reg_value.GetBytes(), 16); + + return WriteAllSVE(); + } else + return Status("SVE state change operation not supported"); + } else { + offset = CalculateSVEOffset(reg_info); + assert(offset < GetSVEBufferSize()); + dst = (uint8_t *)GetSVEBuffer() + offset; + ::memcpy(dst, reg_value.GetBytes(), reg_info->byte_size); + return WriteAllSVE(); + } + } + } else if (IsMTE(reg)) { + error = ReadMTEControl(); + if (error.Fail()) + return error; + + offset = reg_info->byte_offset - GetRegisterInfo().GetMTEOffset(); + assert(offset < GetMTEControlSize()); + dst = (uint8_t *)GetMTEControl() + offset; ::memcpy(dst, reg_value.GetBytes(), reg_info->byte_size); - return WriteFPR(); + return WriteMTEControl(); } - return error; + return Status("Failed to write register value"); } Status NativeRegisterContextLinux_arm64::ReadAllRegisterValues( lldb::DataBufferSP &data_sp) { + // AArch64 register data must contain GPRs, either FPR or SVE registers + // and optional MTE register. Pointer Authentication (PAC) registers are + // read-only and will be skiped. + + // In order to create register data checkpoint we first read all register + // values if not done already and calculate total size of register set data. + // We store all register values in data_sp by copying full PTrace data that + // corresponds to register sets enabled by current register context. + Status error; + uint32_t reg_data_byte_size = GetGPRBufferSize(); + error = ReadGPR(); + if (error.Fail()) + return error; - data_sp.reset(new DataBufferHeap(REG_CONTEXT_SIZE, 0)); - if (!m_gpr_is_valid) { - error = ReadGPR(); - if (error.Fail()) - return error; + // If SVE is enabled we need not copy FPR separately. + if (GetRegisterInfo().IsSVEEnabled()) { + reg_data_byte_size += GetSVEBufferSize(); + error = ReadAllSVE(); + } else { + reg_data_byte_size += GetFPRSize(); + error = ReadFPR(); } + if (error.Fail()) + return error; - if (!m_fpu_is_valid) { - error = ReadFPR(); + if (GetRegisterInfo().IsMTEEnabled()) { + reg_data_byte_size += GetMTEControlSize(); + error = ReadMTEControl(); if (error.Fail()) return error; } + + data_sp.reset(new DataBufferHeap(reg_data_byte_size, 0)); uint8_t *dst = data_sp->GetBytes(); - ::memcpy(dst, GetGPRBuffer(), GetGPRSize()); - dst += GetGPRSize(); - ::memcpy(dst, GetFPRBuffer(), GetFPRSize()); + + ::memcpy(dst, GetGPRBuffer(), GetGPRBufferSize()); + dst += GetGPRBufferSize(); + + if (GetRegisterInfo().IsSVEEnabled()) { + ::memcpy(dst, GetSVEBuffer(), GetSVEBufferSize()); + dst += GetSVEBufferSize(); + } else { + ::memcpy(dst, GetFPRBuffer(), GetFPRSize()); + dst += GetFPRSize(); + } + + if (GetRegisterInfo().IsMTEEnabled()) + ::memcpy(dst, GetMTEControl(), GetMTEControlSize()); return error; } Status NativeRegisterContextLinux_arm64::WriteAllRegisterValues( const lldb::DataBufferSP &data_sp) { - Status error; + // AArch64 register data must contain GPRs, either FPR or SVE registers + // and optional MTE register. Pointer Authentication (PAC) registers are + // read-only and will be skiped. + // We store all register values in data_sp by copying full PTrace data that + // corresponds to register sets enabled by current register context. In order + // to restore from register data checkpoint we will first restore GPRs, based + // on size of remaining register data either SVE or FPRs should be restored + // next. SVE is not enabled if we have register data size less than or equal + // to size of GPR + FPR + MTE. + + Status error; if (!data_sp) { error.SetErrorStringWithFormat( - "NativeRegisterContextLinux_x86_64::%s invalid data_sp provided", + "NativeRegisterContextLinux_arm64::%s invalid data_sp provided", __FUNCTION__); return error; } - if (data_sp->GetByteSize() != REG_CONTEXT_SIZE) { - error.SetErrorStringWithFormat( - "NativeRegisterContextLinux_x86_64::%s data_sp contained mismatched " - "data size, expected %" PRIu64 ", actual %" PRIu64, - __FUNCTION__, REG_CONTEXT_SIZE, data_sp->GetByteSize()); - return error; - } - uint8_t *src = data_sp->GetBytes(); if (src == nullptr) { error.SetErrorStringWithFormat("NativeRegisterContextLinux_x86_64::%s " @@ -241,19 +532,79 @@ Status NativeRegisterContextLinux_arm64::WriteAllRegisterValues( __FUNCTION__); return error; } - ::memcpy(GetGPRBuffer(), src, GetRegisterInfoInterface().GetGPRSize()); + + uint64_t reg_data_min_size = GetGPRBufferSize() + GetFPRSize(); + if (data_sp->GetByteSize() < reg_data_min_size) { + error.SetErrorStringWithFormat( + "NativeRegisterContextLinux_arm64::%s data_sp contained insufficient " + "register data bytes, expected at least %" PRIu64 ", actual %" PRIu64, + __FUNCTION__, reg_data_min_size, data_sp->GetByteSize()); + return error; + } + + // Register data starts with GPRs + ::memcpy(GetGPRBuffer(), src, GetGPRBufferSize()); + m_gpr_is_valid = true; error = WriteGPR(); if (error.Fail()) return error; - src += GetRegisterInfoInterface().GetGPRSize(); - ::memcpy(GetFPRBuffer(), src, GetFPRSize()); + src += GetGPRBufferSize(); + + // Verify if register data may contain SVE register values. + bool contains_sve_reg_data = + (data_sp->GetByteSize() > (reg_data_min_size + GetSVEHeaderSize())); + + if (contains_sve_reg_data) { + // We have SVE register data first write SVE header. + ::memcpy(GetSVEHeader(), src, GetSVEHeaderSize()); + if (!sve_vl_valid(m_sve_header.vl)) { + m_sve_header_is_valid = false; + error.SetErrorStringWithFormat("NativeRegisterContextLinux_arm64::%s " + "Invalid SVE header in data_sp", + __FUNCTION__); + return error; + } + m_sve_header_is_valid = true; + error = WriteSVEHeader(); + if (error.Fail()) + return error; + + // SVE header has been written configure SVE vector length if needed. + ConfigureRegisterContext(); + + // Make sure data_sp contains sufficient data to write all SVE registers. + reg_data_min_size = GetGPRBufferSize() + GetSVEBufferSize(); + if (data_sp->GetByteSize() < reg_data_min_size) { + error.SetErrorStringWithFormat( + "NativeRegisterContextLinux_arm64::%s data_sp contained insufficient " + "register data bytes, expected %" PRIu64 ", actual %" PRIu64, + __FUNCTION__, reg_data_min_size, data_sp->GetByteSize()); + return error; + } + + ::memcpy(GetSVEBuffer(), src, GetSVEBufferSize()); + m_sve_buffer_is_valid = true; + error = WriteAllSVE(); + src += GetSVEBufferSize(); + } else { + ::memcpy(GetFPRBuffer(), src, GetFPRSize()); + m_fpu_is_valid = true; + error = WriteFPR(); + src += GetFPRSize(); + } - error = WriteFPR(); if (error.Fail()) return error; + if (GetRegisterInfo().IsMTEEnabled() && + data_sp->GetByteSize() > reg_data_min_size) { + ::memcpy(GetMTEControl(), src, GetMTEControlSize()); + m_mte_ctrl_is_valid = true; + error = WriteMTEControl(); + } + return error; } @@ -271,556 +622,375 @@ bool NativeRegisterContextLinux_arm64::IsFPR(unsigned reg) const { return false; } -uint32_t NativeRegisterContextLinux_arm64::NumSupportedHardwareBreakpoints() { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_BREAKPOINTS)); - - LLDB_LOGF(log, "NativeRegisterContextLinux_arm64::%s()", __FUNCTION__); - - Status error; - - // Read hardware breakpoint and watchpoint information. - error = ReadHardwareDebugInfo(); - - if (error.Fail()) - return 0; - - return m_max_hbp_supported; +bool NativeRegisterContextLinux_arm64::IsSVE(unsigned reg) const { + return GetRegisterInfo().IsSVEReg(reg); } -uint32_t -NativeRegisterContextLinux_arm64::SetHardwareBreakpoint(lldb::addr_t addr, - size_t size) { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_BREAKPOINTS)); - LLDB_LOG(log, "addr: {0:x}, size: {1:x}", addr, size); - - // Read hardware breakpoint and watchpoint information. - Status error = ReadHardwareDebugInfo(); - - if (error.Fail()) - return LLDB_INVALID_INDEX32; - - uint32_t control_value = 0, bp_index = 0; - - // Check if size has a valid hardware breakpoint length. - if (size != 4) - return LLDB_INVALID_INDEX32; // Invalid size for a AArch64 hardware - // breakpoint - - // Check 4-byte alignment for hardware breakpoint target address. - if (addr & 0x03) - return LLDB_INVALID_INDEX32; // Invalid address, should be 4-byte aligned. - - // Setup control value - control_value = 0; - control_value |= ((1 << size) - 1) << 5; - control_value |= (2 << 1) | 1; - - // Iterate over stored breakpoints and find a free bp_index - bp_index = LLDB_INVALID_INDEX32; - for (uint32_t i = 0; i < m_max_hbp_supported; i++) { - if ((m_hbr_regs[i].control & 1) == 0) { - bp_index = i; // Mark last free slot - } else if (m_hbr_regs[i].address == addr) { - return LLDB_INVALID_INDEX32; // We do not support duplicate breakpoints. - } - } - - if (bp_index == LLDB_INVALID_INDEX32) - return LLDB_INVALID_INDEX32; - - // Update breakpoint in local cache - m_hbr_regs[bp_index].real_addr = addr; - m_hbr_regs[bp_index].address = addr; - m_hbr_regs[bp_index].control = control_value; - - // PTRACE call to set corresponding hardware breakpoint register. - error = WriteHardwareDebugRegs(eDREGTypeBREAK); +bool NativeRegisterContextLinux_arm64::IsPAuth(unsigned reg) const { + return GetRegisterInfo().IsPAuthReg(reg); +} - if (error.Fail()) { - m_hbr_regs[bp_index].address = 0; - m_hbr_regs[bp_index].control &= ~1; +bool NativeRegisterContextLinux_arm64::IsMTE(unsigned reg) const { + return GetRegisterInfo().IsMTEReg(reg); +} - return LLDB_INVALID_INDEX32; +llvm::Error NativeRegisterContextLinux_arm64::ReadHardwareDebugInfo() { + if (!m_refresh_hwdebug_info) { + return llvm::Error::success(); } - return bp_index; -} + ::pid_t tid = m_thread.GetID(); -bool NativeRegisterContextLinux_arm64::ClearHardwareBreakpoint( - uint32_t hw_idx) { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_BREAKPOINTS)); - LLDB_LOG(log, "hw_idx: {0}", hw_idx); + int regset = NT_ARM_HW_WATCH; + struct iovec ioVec; + struct user_hwdebug_state dreg_state; + Status error; - // Read hardware breakpoint and watchpoint information. - Status error = ReadHardwareDebugInfo(); + 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 false; - - if (hw_idx >= m_max_hbp_supported) - return false; - - // Create a backup we can revert to in case of failure. - lldb::addr_t tempAddr = m_hbr_regs[hw_idx].address; - uint32_t tempControl = m_hbr_regs[hw_idx].control; + return error.ToError(); - m_hbr_regs[hw_idx].control &= ~1; - m_hbr_regs[hw_idx].address = 0; + m_max_hwp_supported = dreg_state.dbg_info & 0xff; - // PTRACE call to clear corresponding hardware breakpoint register. - error = WriteHardwareDebugRegs(eDREGTypeBREAK); + regset = NT_ARM_HW_BREAK; + error = NativeProcessLinux::PtraceWrapper(PTRACE_GETREGSET, tid, ®set, + &ioVec, ioVec.iov_len); - if (error.Fail()) { - m_hbr_regs[hw_idx].control = tempControl; - m_hbr_regs[hw_idx].address = tempAddr; + if (error.Fail()) + return error.ToError(); - return false; - } + m_max_hbp_supported = dreg_state.dbg_info & 0xff; + m_refresh_hwdebug_info = false; - return true; + return llvm::Error::success(); } -Status NativeRegisterContextLinux_arm64::GetHardwareBreakHitIndex( - uint32_t &bp_index, lldb::addr_t trap_addr) { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_BREAKPOINTS)); +llvm::Error +NativeRegisterContextLinux_arm64::WriteHardwareDebugRegs(DREGType hwbType) { + struct iovec ioVec; + struct user_hwdebug_state dreg_state; + int regset; - LLDB_LOGF(log, "NativeRegisterContextLinux_arm64::%s()", __FUNCTION__); + memset(&dreg_state, 0, sizeof(dreg_state)); + ioVec.iov_base = &dreg_state; - lldb::addr_t break_addr; + 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 (bp_index = 0; bp_index < m_max_hbp_supported; ++bp_index) { - break_addr = m_hbr_regs[bp_index].address; + 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); - if ((m_hbr_regs[bp_index].control & 0x1) && (trap_addr == break_addr)) { - m_hbr_regs[bp_index].hit_addr = trap_addr; - return Status(); + 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; } - bp_index = LLDB_INVALID_INDEX32; - return Status(); + return NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, m_thread.GetID(), + ®set, &ioVec, ioVec.iov_len) + .ToError(); } -Status NativeRegisterContextLinux_arm64::ClearAllHardwareBreakpoints() { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_BREAKPOINTS)); - - LLDB_LOGF(log, "NativeRegisterContextLinux_arm64::%s()", __FUNCTION__); - +Status NativeRegisterContextLinux_arm64::ReadGPR() { Status error; - // Read hardware breakpoint and watchpoint information. - error = ReadHardwareDebugInfo(); - - if (error.Fail()) + if (m_gpr_is_valid) return error; - lldb::addr_t tempAddr = 0; - uint32_t tempControl = 0; - - for (uint32_t i = 0; i < m_max_hbp_supported; i++) { - if (m_hbr_regs[i].control & 0x01) { - // Create a backup we can revert to in case of failure. - tempAddr = m_hbr_regs[i].address; - tempControl = m_hbr_regs[i].control; - - // Clear watchpoints in local cache - m_hbr_regs[i].control &= ~1; - m_hbr_regs[i].address = 0; - - // Ptrace call to update hardware debug registers - error = WriteHardwareDebugRegs(eDREGTypeBREAK); - - if (error.Fail()) { - m_hbr_regs[i].control = tempControl; - m_hbr_regs[i].address = tempAddr; - - return error; - } - } - } - - return Status(); -} - -uint32_t NativeRegisterContextLinux_arm64::NumSupportedHardwareWatchpoints() { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS)); + struct iovec ioVec; + ioVec.iov_base = GetGPRBuffer(); + ioVec.iov_len = GetGPRBufferSize(); - // Read hardware breakpoint and watchpoint information. - Status error = ReadHardwareDebugInfo(); + error = ReadRegisterSet(&ioVec, GetGPRBufferSize(), NT_PRSTATUS); - if (error.Fail()) - return 0; + if (error.Success()) + m_gpr_is_valid = true; - LLDB_LOG(log, "{0}", m_max_hwp_supported); - return m_max_hwp_supported; + return error; } -uint32_t NativeRegisterContextLinux_arm64::SetHardwareWatchpoint( - lldb::addr_t addr, size_t size, uint32_t watch_flags) { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS)); - LLDB_LOG(log, "addr: {0:x}, size: {1:x} watch_flags: {2:x}", addr, size, - watch_flags); - - // Read hardware breakpoint and watchpoint information. - Status error = ReadHardwareDebugInfo(); - +Status NativeRegisterContextLinux_arm64::WriteGPR() { + Status error = ReadGPR(); if (error.Fail()) - return LLDB_INVALID_INDEX32; - - uint32_t control_value = 0, wp_index = 0; - lldb::addr_t real_addr = addr; + return error; - // Check if we are setting watchpoint other than read/write/access Also - // update watchpoint flag to match AArch64 write-read bit configuration. - switch (watch_flags) { - case 1: - watch_flags = 2; - break; - case 2: - watch_flags = 1; - break; - case 3: - break; - default: - return LLDB_INVALID_INDEX32; - } + struct iovec ioVec; + ioVec.iov_base = GetGPRBuffer(); + ioVec.iov_len = GetGPRBufferSize(); - // Check if size has a valid hardware watchpoint length. - if (size != 1 && size != 2 && size != 4 && size != 8) - return LLDB_INVALID_INDEX32; - - // Check 8-byte alignment for hardware watchpoint target address. Below is a - // hack to recalculate address and size in order to make sure we can watch - // non 8-byte aligned addresses as well. - if (addr & 0x07) { - uint8_t watch_mask = (addr & 0x07) + size; - - if (watch_mask > 0x08) - return LLDB_INVALID_INDEX32; - else if (watch_mask <= 0x02) - size = 2; - else if (watch_mask <= 0x04) - size = 4; - else - size = 8; - - addr = addr & (~0x07); - } + m_gpr_is_valid = false; - // Setup control value - control_value = watch_flags << 3; - control_value |= ((1 << size) - 1) << 5; - control_value |= (2 << 1) | 1; - - // Iterate over stored watchpoints and find a free wp_index - wp_index = LLDB_INVALID_INDEX32; - for (uint32_t i = 0; i < m_max_hwp_supported; i++) { - if ((m_hwp_regs[i].control & 1) == 0) { - wp_index = i; // Mark last free slot - } else if (m_hwp_regs[i].address == addr) { - return LLDB_INVALID_INDEX32; // We do not support duplicate watchpoints. - } - } + return WriteRegisterSet(&ioVec, GetGPRBufferSize(), NT_PRSTATUS); +} - if (wp_index == LLDB_INVALID_INDEX32) - return LLDB_INVALID_INDEX32; +Status NativeRegisterContextLinux_arm64::ReadFPR() { + Status error; - // Update watchpoint in local cache - m_hwp_regs[wp_index].real_addr = real_addr; - m_hwp_regs[wp_index].address = addr; - m_hwp_regs[wp_index].control = control_value; + if (m_fpu_is_valid) + return error; - // PTRACE call to set corresponding watchpoint register. - error = WriteHardwareDebugRegs(eDREGTypeWATCH); + struct iovec ioVec; + ioVec.iov_base = GetFPRBuffer(); + ioVec.iov_len = GetFPRSize(); - if (error.Fail()) { - m_hwp_regs[wp_index].address = 0; - m_hwp_regs[wp_index].control &= ~1; + error = ReadRegisterSet(&ioVec, GetFPRSize(), NT_FPREGSET); - return LLDB_INVALID_INDEX32; - } + if (error.Success()) + m_fpu_is_valid = true; - return wp_index; + return error; } -bool NativeRegisterContextLinux_arm64::ClearHardwareWatchpoint( - uint32_t wp_index) { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS)); - LLDB_LOG(log, "wp_index: {0}", wp_index); - - // Read hardware breakpoint and watchpoint information. - Status error = ReadHardwareDebugInfo(); - +Status NativeRegisterContextLinux_arm64::WriteFPR() { + Status error = ReadFPR(); if (error.Fail()) - return false; - - if (wp_index >= m_max_hwp_supported) - return false; - - // Create a backup we can revert to in case of failure. - lldb::addr_t tempAddr = m_hwp_regs[wp_index].address; - uint32_t tempControl = m_hwp_regs[wp_index].control; + return error; - // Update watchpoint in local cache - m_hwp_regs[wp_index].control &= ~1; - m_hwp_regs[wp_index].address = 0; + struct iovec ioVec; + ioVec.iov_base = GetFPRBuffer(); + ioVec.iov_len = GetFPRSize(); - // Ptrace call to update hardware debug registers - error = WriteHardwareDebugRegs(eDREGTypeWATCH); + m_fpu_is_valid = false; - if (error.Fail()) { - m_hwp_regs[wp_index].control = tempControl; - m_hwp_regs[wp_index].address = tempAddr; + return WriteRegisterSet(&ioVec, GetFPRSize(), NT_FPREGSET); +} - return false; - } +void NativeRegisterContextLinux_arm64::InvalidateAllRegisters() { + m_gpr_is_valid = false; + m_fpu_is_valid = false; + m_sve_buffer_is_valid = false; + m_sve_header_is_valid = false; + m_pac_mask_is_valid = false; + m_mte_ctrl_is_valid = false; - return true; + // Update SVE registers in case there is change in configuration. + ConfigureRegisterContext(); } -Status NativeRegisterContextLinux_arm64::ClearAllHardwareWatchpoints() { - // Read hardware breakpoint and watchpoint information. - Status error = ReadHardwareDebugInfo(); +Status NativeRegisterContextLinux_arm64::ReadSVEHeader() { + Status error; - if (error.Fail()) + if (m_sve_header_is_valid) return error; - lldb::addr_t tempAddr = 0; - uint32_t tempControl = 0; - - for (uint32_t i = 0; i < m_max_hwp_supported; i++) { - if (m_hwp_regs[i].control & 0x01) { - // Create a backup we can revert to in case of failure. - tempAddr = m_hwp_regs[i].address; - tempControl = m_hwp_regs[i].control; - - // Clear watchpoints in local cache - m_hwp_regs[i].control &= ~1; - m_hwp_regs[i].address = 0; - - // Ptrace call to update hardware debug registers - error = WriteHardwareDebugRegs(eDREGTypeWATCH); - - if (error.Fail()) { - m_hwp_regs[i].control = tempControl; - m_hwp_regs[i].address = tempAddr; - - return error; - } - } - } + struct iovec ioVec; + ioVec.iov_base = GetSVEHeader(); + ioVec.iov_len = GetSVEHeaderSize(); - return Status(); -} + error = ReadRegisterSet(&ioVec, GetSVEHeaderSize(), NT_ARM_SVE); -uint32_t -NativeRegisterContextLinux_arm64::GetWatchpointSize(uint32_t wp_index) { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS)); - LLDB_LOG(log, "wp_index: {0}", wp_index); + if (error.Success()) + m_sve_header_is_valid = true; - switch ((m_hwp_regs[wp_index].control >> 5) & 0xff) { - case 0x01: - return 1; - case 0x03: - return 2; - case 0x0f: - return 4; - case 0xff: - return 8; - default: - return 0; - } + return error; } -bool NativeRegisterContextLinux_arm64::WatchpointIsEnabled(uint32_t wp_index) { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS)); - LLDB_LOG(log, "wp_index: {0}", wp_index); - if ((m_hwp_regs[wp_index].control & 0x1) == 0x1) - return true; - else - return false; -} +Status NativeRegisterContextLinux_arm64::ReadPAuthMask() { + Status error; -Status NativeRegisterContextLinux_arm64::GetWatchpointHitIndex( - uint32_t &wp_index, lldb::addr_t trap_addr) { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS)); - LLDB_LOG(log, "wp_index: {0}, trap_addr: {1:x}", wp_index, trap_addr); + if (m_pac_mask_is_valid) + return error; - uint32_t watch_size; - lldb::addr_t watch_addr; + struct iovec ioVec; + ioVec.iov_base = GetPACMask(); + ioVec.iov_len = GetPACMaskSize(); - for (wp_index = 0; wp_index < m_max_hwp_supported; ++wp_index) { - watch_size = GetWatchpointSize(wp_index); - watch_addr = m_hwp_regs[wp_index].address; + error = ReadRegisterSet(&ioVec, GetPACMaskSize(), NT_ARM_PAC_MASK); - if (WatchpointIsEnabled(wp_index) && trap_addr >= watch_addr && - trap_addr < watch_addr + watch_size) { - m_hwp_regs[wp_index].hit_addr = trap_addr; - return Status(); - } - } + if (error.Success()) + m_pac_mask_is_valid = true; - wp_index = LLDB_INVALID_INDEX32; - return Status(); + return error; } -lldb::addr_t -NativeRegisterContextLinux_arm64::GetWatchpointAddress(uint32_t wp_index) { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS)); - LLDB_LOG(log, "wp_index: {0}", wp_index); - - if (wp_index >= m_max_hwp_supported) - return LLDB_INVALID_ADDRESS; +Status NativeRegisterContextLinux_arm64::WriteSVEHeader() { + Status error; - if (WatchpointIsEnabled(wp_index)) - return m_hwp_regs[wp_index].real_addr; - else - return LLDB_INVALID_ADDRESS; -} + error = ReadSVEHeader(); + if (error.Fail()) + return error; -lldb::addr_t -NativeRegisterContextLinux_arm64::GetWatchpointHitAddress(uint32_t wp_index) { - Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS)); - LLDB_LOG(log, "wp_index: {0}", wp_index); + struct iovec ioVec; + ioVec.iov_base = GetSVEHeader(); + ioVec.iov_len = GetSVEHeaderSize(); - if (wp_index >= m_max_hwp_supported) - return LLDB_INVALID_ADDRESS; + m_sve_buffer_is_valid = false; + m_sve_header_is_valid = false; + m_fpu_is_valid = false; - if (WatchpointIsEnabled(wp_index)) - return m_hwp_regs[wp_index].hit_addr; - else - return LLDB_INVALID_ADDRESS; + return WriteRegisterSet(&ioVec, GetSVEHeaderSize(), NT_ARM_SVE); } -Status NativeRegisterContextLinux_arm64::ReadHardwareDebugInfo() { - if (!m_refresh_hwdebug_info) { - return Status(); - } - - ::pid_t tid = m_thread.GetID(); - - int regset = NT_ARM_HW_WATCH; - struct iovec ioVec; - struct user_hwdebug_state dreg_state; +Status NativeRegisterContextLinux_arm64::ReadAllSVE() { 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()) + if (m_sve_buffer_is_valid) return error; - 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); + struct iovec ioVec; + ioVec.iov_base = GetSVEBuffer(); + ioVec.iov_len = GetSVEBufferSize(); - if (error.Fail()) - return error; + error = ReadRegisterSet(&ioVec, GetSVEBufferSize(), NT_ARM_SVE); - m_max_hbp_supported = dreg_state.dbg_info & 0xff; - m_refresh_hwdebug_info = false; + if (error.Success()) + m_sve_buffer_is_valid = true; return error; } -Status NativeRegisterContextLinux_arm64::WriteHardwareDebugRegs(int hwbType) { - struct iovec ioVec; - struct user_hwdebug_state dreg_state; +Status NativeRegisterContextLinux_arm64::WriteAllSVE() { Status error; - memset(&dreg_state, 0, sizeof(dreg_state)); - ioVec.iov_base = &dreg_state; + error = ReadAllSVE(); + if (error.Fail()) + return error; - if (hwbType == eDREGTypeWATCH) { - hwbType = 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); + struct iovec ioVec; - 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; - } - } else { - hwbType = 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); + ioVec.iov_base = GetSVEBuffer(); + ioVec.iov_len = GetSVEBufferSize(); - for (uint32_t i = 0; i < m_max_hbp_supported; i++) { - dreg_state.dbg_regs[i].addr = m_hbr_regs[i].address; - dreg_state.dbg_regs[i].ctrl = m_hbr_regs[i].control; - } - } + m_sve_buffer_is_valid = false; + m_sve_header_is_valid = false; + m_fpu_is_valid = false; - return NativeProcessLinux::PtraceWrapper(PTRACE_SETREGSET, m_thread.GetID(), - &hwbType, &ioVec, ioVec.iov_len); + return WriteRegisterSet(&ioVec, GetSVEBufferSize(), NT_ARM_SVE); } -Status NativeRegisterContextLinux_arm64::ReadGPR() { +Status NativeRegisterContextLinux_arm64::ReadMTEControl() { Status error; - struct iovec ioVec; + if (m_mte_ctrl_is_valid) + return error; - ioVec.iov_base = GetGPRBuffer(); - ioVec.iov_len = GetGPRSize(); + struct iovec ioVec; + ioVec.iov_base = GetMTEControl(); + ioVec.iov_len = GetMTEControlSize(); - error = ReadRegisterSet(&ioVec, GetGPRSize(), NT_PRSTATUS); + error = ReadRegisterSet(&ioVec, GetMTEControlSize(), NT_ARM_TAGGED_ADDR_CTRL); if (error.Success()) - m_gpr_is_valid = true; + m_mte_ctrl_is_valid = true; return error; } -Status NativeRegisterContextLinux_arm64::WriteGPR() { - struct iovec ioVec; - - m_gpr_is_valid = false; - - ioVec.iov_base = GetGPRBuffer(); - ioVec.iov_len = GetGPRSize(); - - return WriteRegisterSet(&ioVec, GetGPRSize(), NT_PRSTATUS); -} - -Status NativeRegisterContextLinux_arm64::ReadFPR() { +Status NativeRegisterContextLinux_arm64::WriteMTEControl() { Status error; - struct iovec ioVec; - - ioVec.iov_base = GetFPRBuffer(); - ioVec.iov_len = GetFPRSize(); + error = ReadMTEControl(); + if (error.Fail()) + return error; - error = ReadRegisterSet(&ioVec, GetFPRSize(), NT_FPREGSET); + struct iovec ioVec; + ioVec.iov_base = GetMTEControl(); + ioVec.iov_len = GetMTEControlSize(); + + m_mte_ctrl_is_valid = false; + + return WriteRegisterSet(&ioVec, GetMTEControlSize(), NT_ARM_TAGGED_ADDR_CTRL); +} + +void NativeRegisterContextLinux_arm64::ConfigureRegisterContext() { + // ConfigureRegisterContext gets called from InvalidateAllRegisters + // on every stop and configures SVE vector length. + // If m_sve_state is set to SVEState::Disabled on first stop, code below will + // be deemed non operational for the lifetime of current process. + if (!m_sve_header_is_valid && m_sve_state != SVEState::Disabled) { + Status error = ReadSVEHeader(); + if (error.Success()) { + // If SVE is enabled thread can switch between SVEState::FPSIMD and + // SVEState::Full on every stop. + if ((m_sve_header.flags & sve::ptrace_regs_mask) == + sve::ptrace_regs_fpsimd) + m_sve_state = SVEState::FPSIMD; + else if ((m_sve_header.flags & sve::ptrace_regs_mask) == + sve::ptrace_regs_sve) + m_sve_state = SVEState::Full; + + // On every stop we configure SVE vector length by calling + // ConfigureVectorLength regardless of current SVEState of this thread. + uint32_t vq = RegisterInfoPOSIX_arm64::eVectorQuadwordAArch64SVE; + if (sve_vl_valid(m_sve_header.vl)) + vq = sve::vq_from_vl(m_sve_header.vl); + + GetRegisterInfo().ConfigureVectorLength(vq); + m_sve_ptrace_payload.resize(sve::PTraceSize(vq, sve::ptrace_regs_sve)); + } + } +} - if (error.Success()) - m_fpu_is_valid = true; +uint32_t NativeRegisterContextLinux_arm64::CalculateFprOffset( + const RegisterInfo *reg_info) const { + return reg_info->byte_offset - GetGPRSize(); +} - return error; +uint32_t NativeRegisterContextLinux_arm64::CalculateSVEOffset( + const RegisterInfo *reg_info) const { + // Start of Z0 data is after GPRs plus 8 bytes of vg register + uint32_t sve_reg_offset = LLDB_INVALID_INDEX32; + if (m_sve_state == SVEState::FPSIMD) { + const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; + sve_reg_offset = sve::ptrace_fpsimd_offset + + (reg - GetRegisterInfo().GetRegNumSVEZ0()) * 16; + } else if (m_sve_state == SVEState::Full) { + uint32_t sve_z0_offset = GetGPRSize() + 16; + sve_reg_offset = + sve::SigRegsOffset() + reg_info->byte_offset - sve_z0_offset; + } + return sve_reg_offset; } -Status NativeRegisterContextLinux_arm64::WriteFPR() { - struct iovec ioVec; +std::vector NativeRegisterContextLinux_arm64::GetExpeditedRegisters( + ExpeditedRegs expType) const { + std::vector expedited_reg_nums = + NativeRegisterContext::GetExpeditedRegisters(expType); + if (m_sve_state == SVEState::FPSIMD || m_sve_state == SVEState::Full) + expedited_reg_nums.push_back(GetRegisterInfo().GetRegNumSVEVG()); - m_fpu_is_valid = false; + return expedited_reg_nums; +} - ioVec.iov_base = GetFPRBuffer(); - ioVec.iov_len = GetFPRSize(); +llvm::Expected +NativeRegisterContextLinux_arm64::GetMemoryTaggingDetails(int32_t type) { + if (type == MemoryTagManagerAArch64MTE::eMTE_allocation) { + return MemoryTaggingDetails{std::make_unique(), + PTRACE_PEEKMTETAGS, PTRACE_POKEMTETAGS}; + } - return WriteRegisterSet(&ioVec, GetFPRSize(), NT_FPREGSET); + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "Unknown AArch64 memory tag type %d", type); } -void NativeRegisterContextLinux_arm64::InvalidateAllRegisters() { - m_gpr_is_valid = false; - m_fpu_is_valid = false; -} +lldb::addr_t NativeRegisterContextLinux_arm64::FixWatchpointHitAddress( + lldb::addr_t hit_addr) { + // Linux configures user-space virtual addresses with top byte ignored. + // We set default value of mask such that top byte is masked out. + lldb::addr_t mask = ~((1ULL << 56) - 1); -uint32_t NativeRegisterContextLinux_arm64::CalculateFprOffset( - const RegisterInfo *reg_info) const { - return reg_info->byte_offset - GetGPRSize(); + // Try to read pointer authentication data_mask register and calculate a + // consolidated data address mask after ignoring the top byte. + if (ReadPAuthMask().Success()) + mask |= m_pac_mask.data_mask; + + return hit_addr & ~mask; + ; } #endif // defined (__arm64__) || defined (__aarch64__) diff --git a/gnu/llvm/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.h b/gnu/llvm/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.h index 0fbbea51d21..2f8a4a60118 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.h +++ b/gnu/llvm/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.h @@ -12,17 +12,24 @@ #define lldb_NativeRegisterContextLinux_arm64_h #include "Plugins/Process/Linux/NativeRegisterContextLinux.h" +#include "Plugins/Process/Utility/LinuxPTraceDefines_arm64sve.h" +#include "Plugins/Process/Utility/NativeRegisterContextDBReg_arm64.h" #include "Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h" +#include + namespace lldb_private { namespace process_linux { class NativeProcessLinux; -class NativeRegisterContextLinux_arm64 : public NativeRegisterContextLinux { +class NativeRegisterContextLinux_arm64 + : public NativeRegisterContextLinux, + public NativeRegisterContextDBReg_arm64 { public: - NativeRegisterContextLinux_arm64(const ArchSpec &target_arch, - NativeThreadProtocol &native_thread); + NativeRegisterContextLinux_arm64( + const ArchSpec &target_arch, NativeThreadProtocol &native_thread, + std::unique_ptr register_info_up); uint32_t GetRegisterSetCount() const override; @@ -42,44 +49,15 @@ public: void InvalidateAllRegisters() override; - // Hardware breakpoints/watchpoint management functions - - uint32_t NumSupportedHardwareBreakpoints() override; - - uint32_t SetHardwareBreakpoint(lldb::addr_t addr, size_t size) override; - - bool ClearHardwareBreakpoint(uint32_t hw_idx) override; - - Status ClearAllHardwareBreakpoints() override; - - Status GetHardwareBreakHitIndex(uint32_t &bp_index, - lldb::addr_t trap_addr) override; - - uint32_t NumSupportedHardwareWatchpoints() override; - - uint32_t SetHardwareWatchpoint(lldb::addr_t addr, size_t size, - uint32_t watch_flags) override; - - bool ClearHardwareWatchpoint(uint32_t hw_index) override; - - Status ClearAllHardwareWatchpoints() override; - - Status GetWatchpointHitIndex(uint32_t &wp_index, - lldb::addr_t trap_addr) override; + std::vector + GetExpeditedRegisters(ExpeditedRegs expType) const override; - lldb::addr_t GetWatchpointHitAddress(uint32_t wp_index) override; + bool RegisterOffsetIsDynamic() const override { return true; } - lldb::addr_t GetWatchpointAddress(uint32_t wp_index) override; - - uint32_t GetWatchpointSize(uint32_t wp_index); - - bool WatchpointIsEnabled(uint32_t wp_index); - - // Debug register type select - enum DREGType { eDREGTypeWATCH = 0, eDREGTypeBREAK }; + llvm::Expected + GetMemoryTaggingDetails(int32_t type) override; protected: - Status ReadGPR() override; Status WriteGPR() override; @@ -90,46 +68,98 @@ protected: void *GetGPRBuffer() override { return &m_gpr_arm64; } + // GetGPRBufferSize returns sizeof arm64 GPR ptrace buffer, it is different + // from GetGPRSize which returns sizeof RegisterInfoPOSIX_arm64::GPR. + size_t GetGPRBufferSize() { return sizeof(m_gpr_arm64); } + void *GetFPRBuffer() override { return &m_fpr; } size_t GetFPRSize() override { return sizeof(m_fpr); } + lldb::addr_t FixWatchpointHitAddress(lldb::addr_t hit_addr) override; + private: bool m_gpr_is_valid; bool m_fpu_is_valid; + bool m_sve_buffer_is_valid; + bool m_mte_ctrl_is_valid; - RegisterInfoPOSIX_arm64::GPR m_gpr_arm64; // 64-bit general purpose registers. + bool m_sve_header_is_valid; + bool m_pac_mask_is_valid; + + struct user_pt_regs m_gpr_arm64; // 64-bit general purpose registers. RegisterInfoPOSIX_arm64::FPU m_fpr; // floating-point registers including extended register sets. - // 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 + SVEState m_sve_state; + struct sve::user_sve_header m_sve_header; + std::vector m_sve_ptrace_payload; - uint32_t m_max_hwp_supported; - uint32_t m_max_hbp_supported; bool m_refresh_hwdebug_info; + struct user_pac_mask { + uint64_t data_mask; + uint64_t insn_mask; + }; + + struct user_pac_mask m_pac_mask; + + uint64_t m_mte_ctrl_reg; + bool IsGPR(unsigned reg) const; bool IsFPR(unsigned reg) const; - Status ReadHardwareDebugInfo(); + Status ReadAllSVE(); + + Status WriteAllSVE(); + + Status ReadSVEHeader(); + + Status WriteSVEHeader(); + + Status ReadPAuthMask(); + + Status ReadMTEControl(); + + Status WriteMTEControl(); + + bool IsSVE(unsigned reg) const; + bool IsPAuth(unsigned reg) const; + bool IsMTE(unsigned reg) const; + + uint64_t GetSVERegVG() { return m_sve_header.vl / 8; } + + void SetSVERegVG(uint64_t vg) { m_sve_header.vl = vg * 8; } + + void *GetSVEHeader() { return &m_sve_header; } - Status WriteHardwareDebugRegs(int hwbType); + void *GetPACMask() { return &m_pac_mask; } + + void *GetMTEControl() { return &m_mte_ctrl_reg; } + + void *GetSVEBuffer() { return m_sve_ptrace_payload.data(); }; + + size_t GetSVEHeaderSize() { return sizeof(m_sve_header); } + + size_t GetPACMaskSize() { return sizeof(m_pac_mask); } + + size_t GetSVEBufferSize() { return m_sve_ptrace_payload.size(); } + + size_t GetMTEControlSize() { return sizeof(m_mte_ctrl_reg); } + + llvm::Error ReadHardwareDebugInfo() override; + + llvm::Error WriteHardwareDebugRegs(DREGType hwbType) override; uint32_t CalculateFprOffset(const RegisterInfo *reg_info) const; RegisterInfoPOSIX_arm64 &GetRegisterInfo() const; + + void ConfigureRegisterContext(); + + uint32_t CalculateSVEOffset(const RegisterInfo *reg_info) const; }; } // namespace process_linux diff --git a/gnu/llvm/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_ppc64le.cpp b/gnu/llvm/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_ppc64le.cpp index 6d1a15a0b70..60582e4cc61 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_ppc64le.cpp +++ b/gnu/llvm/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_ppc64le.cpp @@ -115,7 +115,7 @@ static const RegisterSet g_reg_sets_ppc64le[k_num_register_sets] = { std::unique_ptr NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux( - const ArchSpec &target_arch, NativeThreadProtocol &native_thread) { + const ArchSpec &target_arch, NativeThreadLinux &native_thread) { switch (target_arch.GetMachine()) { case llvm::Triple::ppc64le: return std::make_unique(target_arch, @@ -127,8 +127,9 @@ NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux( NativeRegisterContextLinux_ppc64le::NativeRegisterContextLinux_ppc64le( const ArchSpec &target_arch, NativeThreadProtocol &native_thread) - : NativeRegisterContextLinux(native_thread, - new RegisterInfoPOSIX_ppc64le(target_arch)) { + : NativeRegisterContextRegisterInfo( + native_thread, new RegisterInfoPOSIX_ppc64le(target_arch)), + NativeRegisterContextLinux(native_thread) { if (target_arch.GetMachine() != llvm::Triple::ppc64le) { llvm_unreachable("Unhandled target architecture."); } diff --git a/gnu/llvm/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_s390x.cpp b/gnu/llvm/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_s390x.cpp index c72b89a519f..3c0916499f7 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_s390x.cpp +++ b/gnu/llvm/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_s390x.cpp @@ -93,7 +93,7 @@ static const RegisterSet g_reg_sets_s390x[k_num_register_sets] = { std::unique_ptr NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux( - const ArchSpec &target_arch, NativeThreadProtocol &native_thread) { + const ArchSpec &target_arch, NativeThreadLinux &native_thread) { return std::make_unique(target_arch, native_thread); } @@ -109,8 +109,9 @@ CreateRegisterInfoInterface(const ArchSpec &target_arch) { NativeRegisterContextLinux_s390x::NativeRegisterContextLinux_s390x( const ArchSpec &target_arch, NativeThreadProtocol &native_thread) - : NativeRegisterContextLinux(native_thread, - CreateRegisterInfoInterface(target_arch)) { + : NativeRegisterContextRegisterInfo( + native_thread, CreateRegisterInfoInterface(target_arch)), + NativeRegisterContextLinux(native_thread) { // Set up data about ranges of valid registers. switch (target_arch.GetMachine()) { case llvm::Triple::systemz: diff --git a/gnu/llvm/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.cpp b/gnu/llvm/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.cpp index f9a3c221227..bd4b168f496 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.cpp +++ b/gnu/llvm/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.cpp @@ -10,14 +10,14 @@ #include "NativeRegisterContextLinux_x86_64.h" +#include "Plugins/Process/Linux/NativeThreadLinux.h" +#include "Plugins/Process/Utility/RegisterContextLinux_i386.h" +#include "Plugins/Process/Utility/RegisterContextLinux_x86_64.h" #include "lldb/Host/HostInfo.h" #include "lldb/Utility/DataBufferHeap.h" #include "lldb/Utility/Log.h" #include "lldb/Utility/RegisterValue.h" #include "lldb/Utility/Status.h" - -#include "Plugins/Process/Utility/RegisterContextLinux_i386.h" -#include "Plugins/Process/Utility/RegisterContextLinux_x86_64.h" #include #include @@ -41,11 +41,8 @@ static inline int get_cpuid_count(unsigned int __leaf, using namespace lldb_private; using namespace lldb_private::process_linux; -// Private namespace. - -namespace { // x86 32-bit general purpose registers. -const uint32_t g_gpr_regnums_i386[] = { +static const uint32_t g_gpr_regnums_i386[] = { lldb_eax_i386, lldb_ebx_i386, lldb_ecx_i386, lldb_edx_i386, lldb_edi_i386, lldb_esi_i386, lldb_ebp_i386, lldb_esp_i386, lldb_eip_i386, lldb_eflags_i386, lldb_cs_i386, lldb_fs_i386, @@ -62,7 +59,7 @@ static_assert((sizeof(g_gpr_regnums_i386) / sizeof(g_gpr_regnums_i386[0])) - "g_gpr_regnums_i386 has wrong number of register infos"); // x86 32-bit floating point registers. -const uint32_t g_fpu_regnums_i386[] = { +static const uint32_t g_fpu_regnums_i386[] = { lldb_fctrl_i386, lldb_fstat_i386, lldb_ftag_i386, lldb_fop_i386, lldb_fiseg_i386, lldb_fioff_i386, lldb_foseg_i386, lldb_fooff_i386, lldb_mxcsr_i386, lldb_mxcsrmask_i386, lldb_st0_i386, lldb_st1_i386, @@ -80,7 +77,7 @@ static_assert((sizeof(g_fpu_regnums_i386) / sizeof(g_fpu_regnums_i386[0])) - "g_fpu_regnums_i386 has wrong number of register infos"); // x86 32-bit AVX registers. -const uint32_t g_avx_regnums_i386[] = { +static const uint32_t g_avx_regnums_i386[] = { lldb_ymm0_i386, lldb_ymm1_i386, lldb_ymm2_i386, lldb_ymm3_i386, lldb_ymm4_i386, lldb_ymm5_i386, lldb_ymm6_i386, lldb_ymm7_i386, LLDB_INVALID_REGNUM // register sets need to end with this flag @@ -149,20 +146,21 @@ static_assert((sizeof(g_gpr_regnums_x86_64) / sizeof(g_gpr_regnums_x86_64[0])) - // x86 64-bit floating point registers. static const uint32_t g_fpu_regnums_x86_64[] = { - lldb_fctrl_x86_64, lldb_fstat_x86_64, lldb_ftag_x86_64, - lldb_fop_x86_64, lldb_fiseg_x86_64, lldb_fioff_x86_64, - lldb_foseg_x86_64, lldb_fooff_x86_64, lldb_mxcsr_x86_64, - lldb_mxcsrmask_x86_64, lldb_st0_x86_64, lldb_st1_x86_64, - lldb_st2_x86_64, lldb_st3_x86_64, lldb_st4_x86_64, - lldb_st5_x86_64, lldb_st6_x86_64, lldb_st7_x86_64, - lldb_mm0_x86_64, lldb_mm1_x86_64, lldb_mm2_x86_64, - lldb_mm3_x86_64, lldb_mm4_x86_64, lldb_mm5_x86_64, - lldb_mm6_x86_64, lldb_mm7_x86_64, lldb_xmm0_x86_64, - lldb_xmm1_x86_64, lldb_xmm2_x86_64, lldb_xmm3_x86_64, - lldb_xmm4_x86_64, lldb_xmm5_x86_64, lldb_xmm6_x86_64, - lldb_xmm7_x86_64, lldb_xmm8_x86_64, lldb_xmm9_x86_64, - lldb_xmm10_x86_64, lldb_xmm11_x86_64, lldb_xmm12_x86_64, - lldb_xmm13_x86_64, lldb_xmm14_x86_64, lldb_xmm15_x86_64, + lldb_fctrl_x86_64, lldb_fstat_x86_64, lldb_ftag_x86_64, + lldb_fop_x86_64, lldb_fiseg_x86_64, lldb_fioff_x86_64, + lldb_fip_x86_64, lldb_foseg_x86_64, lldb_fooff_x86_64, + lldb_fdp_x86_64, lldb_mxcsr_x86_64, lldb_mxcsrmask_x86_64, + lldb_st0_x86_64, lldb_st1_x86_64, lldb_st2_x86_64, + lldb_st3_x86_64, lldb_st4_x86_64, lldb_st5_x86_64, + lldb_st6_x86_64, lldb_st7_x86_64, lldb_mm0_x86_64, + lldb_mm1_x86_64, lldb_mm2_x86_64, lldb_mm3_x86_64, + lldb_mm4_x86_64, lldb_mm5_x86_64, lldb_mm6_x86_64, + lldb_mm7_x86_64, lldb_xmm0_x86_64, lldb_xmm1_x86_64, + lldb_xmm2_x86_64, lldb_xmm3_x86_64, lldb_xmm4_x86_64, + lldb_xmm5_x86_64, lldb_xmm6_x86_64, lldb_xmm7_x86_64, + lldb_xmm8_x86_64, lldb_xmm9_x86_64, lldb_xmm10_x86_64, + lldb_xmm11_x86_64, lldb_xmm12_x86_64, lldb_xmm13_x86_64, + lldb_xmm14_x86_64, lldb_xmm15_x86_64, LLDB_INVALID_REGNUM // register sets need to end with this flag }; static_assert((sizeof(g_fpu_regnums_x86_64) / sizeof(g_fpu_regnums_x86_64[0])) - @@ -195,7 +193,7 @@ static_assert((sizeof(g_mpx_regnums_x86_64) / sizeof(g_mpx_regnums_x86_64[0])) - "g_mpx_regnums_x86_64 has wrong number of register infos"); // Number of register sets provided by this context. -enum { k_num_extended_register_sets = 2, k_num_register_sets = 4 }; +constexpr unsigned k_num_extended_register_sets = 2, k_num_register_sets = 4; // Register sets for x86 32-bit. static const RegisterSet g_reg_sets_i386[k_num_register_sets] = { @@ -218,7 +216,6 @@ static const RegisterSet g_reg_sets_x86_64[k_num_register_sets] = { g_avx_regnums_x86_64}, { "Memory Protection Extensions", "mpx", k_num_mpx_registers_x86_64, g_mpx_regnums_x86_64}}; -} #define REG_CONTEXT_SIZE (GetRegisterInfoInterface().GetGPRSize() + sizeof(FPR)) @@ -253,7 +250,7 @@ static inline unsigned int fxsr_regset(const ArchSpec &arch) { std::unique_ptr NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux( - const ArchSpec &target_arch, NativeThreadProtocol &native_thread) { + const ArchSpec &target_arch, NativeThreadLinux &native_thread) { return std::unique_ptr( new NativeRegisterContextLinux_x86_64(target_arch, native_thread)); } @@ -293,8 +290,10 @@ static std::size_t GetXSTATESize() { NativeRegisterContextLinux_x86_64::NativeRegisterContextLinux_x86_64( const ArchSpec &target_arch, NativeThreadProtocol &native_thread) - : NativeRegisterContextLinux(native_thread, - CreateRegisterInfoInterface(target_arch)), + : NativeRegisterContextRegisterInfo( + native_thread, CreateRegisterInfoInterface(target_arch)), + NativeRegisterContextLinux(native_thread), + NativeRegisterContextDBReg_x86(native_thread), m_xstate_type(XStateType::Invalid), m_ymm_set(), m_mpx_set(), m_reg_info(), m_gpr_x86_64() { // Set up data about ranges of valid registers. @@ -321,6 +320,7 @@ NativeRegisterContextLinux_x86_64::NativeRegisterContextLinux_x86_64( m_reg_info.first_mpxc = lldb_bndcfgu_i386; m_reg_info.last_mpxc = lldb_bndstatus_i386; m_reg_info.first_dr = lldb_dr0_i386; + m_reg_info.last_dr = lldb_dr7_i386; m_reg_info.gpr_flags = lldb_eflags_i386; break; case llvm::Triple::x86_64: @@ -345,6 +345,7 @@ NativeRegisterContextLinux_x86_64::NativeRegisterContextLinux_x86_64( m_reg_info.first_mpxc = lldb_bndcfgu_x86_64; m_reg_info.last_mpxc = lldb_bndstatus_x86_64; m_reg_info.first_dr = lldb_dr0_x86_64; + m_reg_info.last_dr = lldb_dr7_x86_64; m_reg_info.gpr_flags = lldb_rflags_x86_64; break; default: @@ -527,6 +528,13 @@ NativeRegisterContextLinux_x86_64::ReadRegister(const RegisterInfo *reg_info, assert((reg_info->byte_offset - m_fctrl_offset_in_userarea) < sizeof(FPR)); uint8_t *src = (uint8_t *)m_xstate.get() + reg_info->byte_offset - m_fctrl_offset_in_userarea; + + if (src == reinterpret_cast(&m_xstate->fxsave.ftag)) { + reg_value.SetUInt16(AbridgedToFullTagWord( + m_xstate->fxsave.ftag, m_xstate->fxsave.fstat, m_xstate->fxsave.stmm)); + return error; + } + switch (reg_info->byte_size) { case 1: reg_value.SetUInt8(*(uint8_t *)src); @@ -578,7 +586,7 @@ Status NativeRegisterContextLinux_x86_64::WriteRegister( UpdateXSTATEforWrite(reg_index); - if (IsGPR(reg_index)) + if (IsGPR(reg_index) || IsDR(reg_index)) return WriteRegisterRaw(reg_index, reg_value); if (IsFPR(reg_index) || IsAVX(reg_index) || IsMPX(reg_index)) { @@ -636,23 +644,28 @@ Status NativeRegisterContextLinux_x86_64::WriteRegister( sizeof(FPR)); uint8_t *dst = (uint8_t *)m_xstate.get() + reg_info->byte_offset - m_fctrl_offset_in_userarea; - switch (reg_info->byte_size) { - case 1: - *(uint8_t *)dst = reg_value.GetAsUInt8(); - break; - case 2: - *(uint16_t *)dst = reg_value.GetAsUInt16(); - break; - case 4: - *(uint32_t *)dst = reg_value.GetAsUInt32(); - break; - case 8: - *(uint64_t *)dst = reg_value.GetAsUInt64(); - break; - default: - assert(false && "Unhandled data size."); - return Status("unhandled register data size %" PRIu32, - reg_info->byte_size); + + if (dst == reinterpret_cast(&m_xstate->fxsave.ftag)) + m_xstate->fxsave.ftag = FullToAbridgedTagWord(reg_value.GetAsUInt16()); + else { + switch (reg_info->byte_size) { + case 1: + *(uint8_t *)dst = reg_value.GetAsUInt8(); + break; + case 2: + *(uint16_t *)dst = reg_value.GetAsUInt16(); + break; + case 4: + *(uint32_t *)dst = reg_value.GetAsUInt32(); + break; + case 8: + *(uint64_t *)dst = reg_value.GetAsUInt64(); + break; + default: + assert(false && "Unhandled data size."); + return Status("unhandled register data size %" PRIu32, + reg_info->byte_size); + } } } @@ -877,6 +890,11 @@ bool NativeRegisterContextLinux_x86_64::IsFPR(uint32_t reg_index) const { reg_index <= m_reg_info.last_fpr); } +bool NativeRegisterContextLinux_x86_64::IsDR(uint32_t reg_index) const { + return (m_reg_info.first_dr <= reg_index && + reg_index <= m_reg_info.last_dr); +} + Status NativeRegisterContextLinux_x86_64::WriteFPR() { switch (m_xstate_type) { case XStateType::FXSAVE: @@ -1009,215 +1027,45 @@ bool NativeRegisterContextLinux_x86_64::CopyMPXtoXSTATE(uint32_t reg) { return true; } -Status NativeRegisterContextLinux_x86_64::IsWatchpointHit(uint32_t wp_index, - bool &is_hit) { - if (wp_index >= NumSupportedHardwareWatchpoints()) - return Status("Watchpoint index out of range"); - - RegisterValue reg_value; - Status error = ReadRegisterRaw(m_reg_info.first_dr + 6, reg_value); - if (error.Fail()) { - is_hit = false; - return error; - } - - uint64_t status_bits = reg_value.GetAsUInt64(); - - is_hit = status_bits & (1 << wp_index); - - return error; +uint32_t +NativeRegisterContextLinux_x86_64::GetPtraceOffset(uint32_t reg_index) { + // If register is MPX, remove extra factor from gdb offset + return GetRegisterInfoAtIndex(reg_index)->byte_offset - + (IsMPX(reg_index) ? 128 : 0); } -Status NativeRegisterContextLinux_x86_64::GetWatchpointHitIndex( - uint32_t &wp_index, lldb::addr_t trap_addr) { - uint32_t num_hw_wps = NumSupportedHardwareWatchpoints(); - for (wp_index = 0; wp_index < num_hw_wps; ++wp_index) { - bool is_hit; - Status error = IsWatchpointHit(wp_index, is_hit); - if (error.Fail()) { - wp_index = LLDB_INVALID_INDEX32; - return error; - } else if (is_hit) { - return error; - } +llvm::Optional +NativeRegisterContextLinux_x86_64::GetSyscallData() { + switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) { + case llvm::Triple::x86: { + static const uint8_t Int80[] = {0xcd, 0x80}; + static const uint32_t Args[] = {lldb_eax_i386, lldb_ebx_i386, lldb_ecx_i386, + lldb_edx_i386, lldb_esi_i386, lldb_edi_i386, + lldb_ebp_i386}; + return SyscallData{Int80, Args, lldb_eax_i386}; } - wp_index = LLDB_INVALID_INDEX32; - return Status(); -} - -Status NativeRegisterContextLinux_x86_64::IsWatchpointVacant(uint32_t wp_index, - bool &is_vacant) { - if (wp_index >= NumSupportedHardwareWatchpoints()) - return Status("Watchpoint index out of range"); - - RegisterValue reg_value; - Status error = ReadRegisterRaw(m_reg_info.first_dr + 7, reg_value); - if (error.Fail()) { - is_vacant = false; - return error; + case llvm::Triple::x86_64: { + static const uint8_t Syscall[] = {0x0f, 0x05}; + static const uint32_t Args[] = { + lldb_rax_x86_64, lldb_rdi_x86_64, lldb_rsi_x86_64, lldb_rdx_x86_64, + lldb_r10_x86_64, lldb_r8_x86_64, lldb_r9_x86_64}; + return SyscallData{Syscall, Args, lldb_rax_x86_64}; } - - uint64_t control_bits = reg_value.GetAsUInt64(); - - is_vacant = !(control_bits & (1 << (2 * wp_index))); - - return error; -} - -Status NativeRegisterContextLinux_x86_64::SetHardwareWatchpointWithIndex( - lldb::addr_t addr, size_t size, uint32_t watch_flags, uint32_t wp_index) { - - if (wp_index >= NumSupportedHardwareWatchpoints()) - return Status("Watchpoint index out of range"); - - // Read only watchpoints aren't supported on x86_64. Fall back to read/write - // waitchpoints instead. - // TODO: Add logic to detect when a write happens and ignore that watchpoint - // hit. - if (watch_flags == 0x2) - watch_flags = 0x3; - - if (watch_flags != 0x1 && watch_flags != 0x3) - return Status("Invalid read/write bits for watchpoint"); - - if (size != 1 && size != 2 && size != 4 && size != 8) - return Status("Invalid size for watchpoint"); - - bool is_vacant; - Status error = IsWatchpointVacant(wp_index, is_vacant); - if (error.Fail()) - return error; - if (!is_vacant) - return Status("Watchpoint index not vacant"); - - RegisterValue reg_value; - error = ReadRegisterRaw(m_reg_info.first_dr + 7, reg_value); - if (error.Fail()) - return error; - - // for watchpoints 0, 1, 2, or 3, respectively, set bits 1, 3, 5, or 7 - uint64_t enable_bit = 1 << (2 * wp_index); - - // set bits 16-17, 20-21, 24-25, or 28-29 - // with 0b01 for write, and 0b11 for read/write - uint64_t rw_bits = watch_flags << (16 + 4 * wp_index); - - // set bits 18-19, 22-23, 26-27, or 30-31 - // with 0b00, 0b01, 0b10, or 0b11 - // for 1, 2, 8 (if supported), or 4 bytes, respectively - uint64_t size_bits = (size == 8 ? 0x2 : size - 1) << (18 + 4 * wp_index); - - uint64_t bit_mask = (0x3 << (2 * wp_index)) | (0xF << (16 + 4 * wp_index)); - - uint64_t control_bits = reg_value.GetAsUInt64() & ~bit_mask; - - control_bits |= enable_bit | rw_bits | size_bits; - - error = WriteRegisterRaw(m_reg_info.first_dr + wp_index, RegisterValue(addr)); - if (error.Fail()) - return error; - - error = - WriteRegisterRaw(m_reg_info.first_dr + 7, RegisterValue(control_bits)); - if (error.Fail()) - return error; - - error.Clear(); - return error; -} - -bool NativeRegisterContextLinux_x86_64::ClearHardwareWatchpoint( - uint32_t wp_index) { - if (wp_index >= NumSupportedHardwareWatchpoints()) - return false; - - RegisterValue reg_value; - - // for watchpoints 0, 1, 2, or 3, respectively, clear bits 0, 1, 2, or 3 of - // the debug status register (DR6) - Status error = ReadRegisterRaw(m_reg_info.first_dr + 6, reg_value); - if (error.Fail()) - return false; - uint64_t bit_mask = 1 << wp_index; - uint64_t status_bits = reg_value.GetAsUInt64() & ~bit_mask; - error = WriteRegisterRaw(m_reg_info.first_dr + 6, RegisterValue(status_bits)); - if (error.Fail()) - return false; - - // for watchpoints 0, 1, 2, or 3, respectively, clear bits {0-1,16-19}, - // {2-3,20-23}, {4-5,24-27}, or {6-7,28-31} of the debug control register - // (DR7) - error = ReadRegisterRaw(m_reg_info.first_dr + 7, reg_value); - if (error.Fail()) - return false; - bit_mask = (0x3 << (2 * wp_index)) | (0xF << (16 + 4 * wp_index)); - uint64_t control_bits = reg_value.GetAsUInt64() & ~bit_mask; - return WriteRegisterRaw(m_reg_info.first_dr + 7, RegisterValue(control_bits)) - .Success(); -} - -Status NativeRegisterContextLinux_x86_64::ClearAllHardwareWatchpoints() { - RegisterValue reg_value; - - // clear bits {0-4} of the debug status register (DR6) - Status error = ReadRegisterRaw(m_reg_info.first_dr + 6, reg_value); - if (error.Fail()) - return error; - uint64_t bit_mask = 0xF; - uint64_t status_bits = reg_value.GetAsUInt64() & ~bit_mask; - error = WriteRegisterRaw(m_reg_info.first_dr + 6, RegisterValue(status_bits)); - if (error.Fail()) - return error; - - // clear bits {0-7,16-31} of the debug control register (DR7) - error = ReadRegisterRaw(m_reg_info.first_dr + 7, reg_value); - if (error.Fail()) - return error; - bit_mask = 0xFF | (0xFFFF << 16); - uint64_t control_bits = reg_value.GetAsUInt64() & ~bit_mask; - return WriteRegisterRaw(m_reg_info.first_dr + 7, RegisterValue(control_bits)); -} - -uint32_t NativeRegisterContextLinux_x86_64::SetHardwareWatchpoint( - lldb::addr_t addr, size_t size, uint32_t watch_flags) { - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS)); - const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints(); - for (uint32_t wp_index = 0; wp_index < num_hw_watchpoints; ++wp_index) { - bool is_vacant; - Status error = IsWatchpointVacant(wp_index, is_vacant); - if (is_vacant) { - error = SetHardwareWatchpointWithIndex(addr, size, watch_flags, wp_index); - if (error.Success()) - return wp_index; - } - if (error.Fail() && log) { - LLDB_LOGF(log, "NativeRegisterContextLinux_x86_64::%s Error: %s", - __FUNCTION__, error.AsCString()); - } + default: + llvm_unreachable("Unhandled architecture!"); } - return LLDB_INVALID_INDEX32; -} - -lldb::addr_t -NativeRegisterContextLinux_x86_64::GetWatchpointAddress(uint32_t wp_index) { - if (wp_index >= NumSupportedHardwareWatchpoints()) - return LLDB_INVALID_ADDRESS; - RegisterValue reg_value; - if (ReadRegisterRaw(m_reg_info.first_dr + wp_index, reg_value).Fail()) - return LLDB_INVALID_ADDRESS; - return reg_value.GetAsUInt64(); -} - -uint32_t NativeRegisterContextLinux_x86_64::NumSupportedHardwareWatchpoints() { - // Available debug address registers: dr0, dr1, dr2, dr3 - return 4; } -uint32_t -NativeRegisterContextLinux_x86_64::GetPtraceOffset(uint32_t reg_index) { - // If register is MPX, remove extra factor from gdb offset - return GetRegisterInfoAtIndex(reg_index)->byte_offset - - (IsMPX(reg_index) ? 128 : 0); +llvm::Optional +NativeRegisterContextLinux_x86_64::GetMmapData() { + switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) { + case llvm::Triple::x86: + return MmapData{192, 91}; + case llvm::Triple::x86_64: + return MmapData{9, 11}; + default: + llvm_unreachable("Unhandled architecture!"); + } } #endif // defined(__i386__) || defined(__x86_64__) diff --git a/gnu/llvm/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.h b/gnu/llvm/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.h index 58b749025c5..8287e4967d3 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.h +++ b/gnu/llvm/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.h @@ -12,6 +12,7 @@ #define lldb_NativeRegisterContextLinux_x86_64_h #include "Plugins/Process/Linux/NativeRegisterContextLinux.h" +#include "Plugins/Process/Utility/NativeRegisterContextDBReg_x86.h" #include "Plugins/Process/Utility/RegisterContext_x86.h" #include "Plugins/Process/Utility/lldb-x86-register-enums.h" #include @@ -21,7 +22,9 @@ namespace process_linux { class NativeProcessLinux; -class NativeRegisterContextLinux_x86_64 : public NativeRegisterContextLinux { +class NativeRegisterContextLinux_x86_64 + : public NativeRegisterContextLinux, + public NativeRegisterContextDBReg_x86 { public: NativeRegisterContextLinux_x86_64(const ArchSpec &target_arch, NativeThreadProtocol &native_thread); @@ -42,27 +45,9 @@ public: Status WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override; - Status IsWatchpointHit(uint32_t wp_index, bool &is_hit) override; + llvm::Optional GetSyscallData() override; - Status GetWatchpointHitIndex(uint32_t &wp_index, - lldb::addr_t trap_addr) override; - - Status IsWatchpointVacant(uint32_t wp_index, bool &is_vacant) override; - - bool ClearHardwareWatchpoint(uint32_t wp_index) override; - - Status ClearAllHardwareWatchpoints() override; - - Status SetHardwareWatchpointWithIndex(lldb::addr_t addr, size_t size, - uint32_t watch_flags, - uint32_t wp_index); - - uint32_t SetHardwareWatchpoint(lldb::addr_t addr, size_t size, - uint32_t watch_flags) override; - - lldb::addr_t GetWatchpointAddress(uint32_t wp_index) override; - - uint32_t NumSupportedHardwareWatchpoints() override; + llvm::Optional GetMmapData() override; protected: void *GetGPRBuffer() override { return &m_gpr_x86_64; } @@ -105,6 +90,7 @@ private: uint32_t first_mpxc; uint32_t last_mpxc; uint32_t first_dr; + uint32_t last_dr; uint32_t gpr_flags; }; @@ -128,6 +114,8 @@ private: bool IsFPR(uint32_t reg_index) const; + bool IsDR(uint32_t reg_index) const; + bool CopyXSTATEtoYMM(uint32_t reg_index, lldb::ByteOrder byte_order); bool CopyYMMtoXSTATE(uint32_t reg, lldb::ByteOrder byte_order); diff --git a/gnu/llvm/lldb/source/Plugins/Process/Linux/NativeThreadLinux.cpp b/gnu/llvm/lldb/source/Plugins/Process/Linux/NativeThreadLinux.cpp index 14eea2df381..a7e4e9b13ff 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/Linux/NativeThreadLinux.cpp +++ b/gnu/llvm/lldb/source/Plugins/Process/Linux/NativeThreadLinux.cpp @@ -8,7 +8,7 @@ #include "NativeThreadLinux.h" -#include +#include #include #include "NativeProcessLinux.h" @@ -26,6 +26,7 @@ #include "llvm/ADT/SmallString.h" #include "Plugins/Process/POSIX/CrashReason.h" +#include "Plugins/Process/Utility/MemoryTagManagerAArch64MTE.h" #include // Try to define a macro to encapsulate the tgkill syscall @@ -77,6 +78,9 @@ void LogThreadStopInfo(Log &log, const ThreadStopInfo &stop_info, case eStopReasonInstrumentation: log.Printf("%s: %s instrumentation", __FUNCTION__, header); return; + case eStopReasonProcessorTrace: + log.Printf("%s: %s processor trace", __FUNCTION__, header); + return; default: log.Printf("%s: %s invalid stop reason %" PRIu32, __FUNCTION__, header, static_cast(stop_info.reason)); @@ -241,9 +245,6 @@ Status NativeThreadLinux::Resume(uint32_t signo) { if (signo != LLDB_INVALID_SIGNAL_NUMBER) data = signo; - // Before thread resumes, clear any cached register data structures - GetRegisterContext().InvalidateAllRegisters(); - return NativeProcessLinux::PtraceWrapper(PTRACE_CONT, GetID(), nullptr, reinterpret_cast(data)); } @@ -265,9 +266,6 @@ Status NativeThreadLinux::SingleStep(uint32_t signo) { if (signo != LLDB_INVALID_SIGNAL_NUMBER) data = signo; - // Before thread resumes, clear any cached register data structures - GetRegisterContext().InvalidateAllRegisters(); - // If hardware single-stepping is not supported, we just do a continue. The // breakpoint on the next instruction has been setup in // NativeProcessLinux::Resume. @@ -302,11 +300,69 @@ void NativeThreadLinux::SetStoppedBySignal(uint32_t signo, ? CrashReason::eInvalidAddress : GetCrashReason(*info); m_stop_description = GetCrashReasonString(reason, *info); + + if (reason == CrashReason::eSyncTagCheckFault) { + AnnotateSyncTagCheckFault(info); + } + break; } } } +void NativeThreadLinux::AnnotateSyncTagCheckFault(const siginfo_t *info) { + int32_t allocation_tag_type = 0; + switch (GetProcess().GetArchitecture().GetMachine()) { + // aarch64_32 deliberately not here because there's no 32 bit MTE + case llvm::Triple::aarch64: + case llvm::Triple::aarch64_be: + allocation_tag_type = MemoryTagManagerAArch64MTE::eMTE_allocation; + break; + default: + return; + } + + auto details = + GetRegisterContext().GetMemoryTaggingDetails(allocation_tag_type); + if (!details) { + llvm::consumeError(details.takeError()); + return; + } + + // We assume that the stop description is currently: + // signal SIGSEGV: sync tag check fault (fault address: ) + // Remove the closing ) + m_stop_description.pop_back(); + + std::stringstream ss; + lldb::addr_t fault_addr = reinterpret_cast(info->si_addr); + std::unique_ptr manager(std::move(details->manager)); + + ss << " logical tag: 0x" << std::hex << manager->GetLogicalTag(fault_addr); + + std::vector allocation_tag_data; + // The fault address may not be granule aligned. ReadMemoryTags will granule + // align any range you give it, potentially making it larger. + // To prevent this set len to 1. This always results in a range that is at + // most 1 granule in size and includes fault_addr. + Status status = GetProcess().ReadMemoryTags(allocation_tag_type, fault_addr, + 1, allocation_tag_data); + + if (status.Success()) { + llvm::Expected> allocation_tag = + manager->UnpackTagsData(allocation_tag_data, 1); + if (allocation_tag) { + ss << " allocation tag: 0x" << std::hex << allocation_tag->front() << ")"; + } else { + llvm::consumeError(allocation_tag.takeError()); + ss << ")"; + } + } else + ss << ")"; + + m_stop_description += ss.str(); +} + bool NativeThreadLinux::IsStopped(int *signo) { if (!StateIsStoppedState(m_state, false)) return false; @@ -325,6 +381,9 @@ void NativeThreadLinux::SetStopped() { if (m_state == StateType::eStateStepping) m_step_workaround.reset(); + // On every stop, clear any cached register data structures + GetRegisterContext().InvalidateAllRegisters(); + const StateType new_state = StateType::eStateStopped; MaybeLogStateChange(new_state); m_state = new_state; @@ -394,6 +453,21 @@ void NativeThreadLinux::SetStoppedByTrace() { m_stop_info.details.signal.signo = SIGTRAP; } +void NativeThreadLinux::SetStoppedByFork(bool is_vfork, lldb::pid_t child_pid) { + SetStopped(); + + m_stop_info.reason = + is_vfork ? StopReason::eStopReasonVFork : StopReason::eStopReasonFork; + m_stop_info.details.fork.child_pid = child_pid; + m_stop_info.details.fork.child_tid = child_pid; +} + +void NativeThreadLinux::SetStoppedByVForkDone() { + SetStopped(); + + m_stop_info.reason = StopReason::eStopReasonVForkDone; +} + void NativeThreadLinux::SetStoppedWithNoReason() { SetStopped(); @@ -401,6 +475,15 @@ void NativeThreadLinux::SetStoppedWithNoReason() { m_stop_info.details.signal.signo = 0; } +void NativeThreadLinux::SetStoppedByProcessorTrace( + llvm::StringRef description) { + SetStopped(); + + m_stop_info.reason = StopReason::eStopReasonProcessorTrace; + m_stop_info.details.signal.signo = 0; + m_stop_description = description.str(); +} + void NativeThreadLinux::SetExited() { const StateType new_state = StateType::eStateExited; MaybeLogStateChange(new_state); diff --git a/gnu/llvm/lldb/source/Plugins/Process/Linux/NativeThreadLinux.h b/gnu/llvm/lldb/source/Plugins/Process/Linux/NativeThreadLinux.h index fd43c89489f..c18665b0107 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/Linux/NativeThreadLinux.h +++ b/gnu/llvm/lldb/source/Plugins/Process/Linux/NativeThreadLinux.h @@ -14,6 +14,8 @@ #include "lldb/Host/common/NativeThreadProtocol.h" #include "lldb/lldb-private-forward.h" +#include "llvm/ADT/StringRef.h" + #include #include #include @@ -51,6 +53,8 @@ public: Status RemoveHardwareBreakpoint(lldb::addr_t addr) override; + NativeProcessLinux &GetProcess(); + private: // Interface for friend classes @@ -81,8 +85,14 @@ private: void SetStoppedByTrace(); + void SetStoppedByFork(bool is_vfork, lldb::pid_t child_pid); + + void SetStoppedByVForkDone(); + void SetStoppedWithNoReason(); + void SetStoppedByProcessorTrace(llvm::StringRef description); + void SetExited(); Status RequestStop(); @@ -90,10 +100,13 @@ private: // Private interface void MaybeLogStateChange(lldb::StateType new_state); - NativeProcessLinux &GetProcess(); - void SetStopped(); + /// Extend m_stop_description with logical and allocation tag values. + /// If there is an error along the way just add the information we were able + /// to get. + void AnnotateSyncTagCheckFault(const siginfo_t *info); + // Member Variables lldb::StateType m_state; ThreadStopInfo m_stop_info; diff --git a/gnu/llvm/lldb/source/Plugins/Process/Linux/SingleStepCheck.cpp b/gnu/llvm/lldb/source/Plugins/Process/Linux/SingleStepCheck.cpp index f0c6bdc6cf8..5b337f1974e 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/Linux/SingleStepCheck.cpp +++ b/gnu/llvm/lldb/source/Plugins/Process/Linux/SingleStepCheck.cpp @@ -8,8 +8,8 @@ #include "SingleStepCheck.h" +#include #include -#include #include #include diff --git a/gnu/llvm/lldb/source/Plugins/Process/MacOSX-Kernel/CommunicationKDP.cpp b/gnu/llvm/lldb/source/Plugins/Process/MacOSX-Kernel/CommunicationKDP.cpp index 06190d0c036..d397d168763 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/MacOSX-Kernel/CommunicationKDP.cpp +++ b/gnu/llvm/lldb/source/Plugins/Process/MacOSX-Kernel/CommunicationKDP.cpp @@ -8,10 +8,9 @@ #include "CommunicationKDP.h" -#include -#include -#include - +#include +#include +#include #include "lldb/Core/DumpDataExtractor.h" #include "lldb/Host/Host.h" @@ -194,12 +193,11 @@ size_t CommunicationKDP::WaitForPacketWithTimeoutMicroSecondsNoLock( : std::chrono::microseconds(timeout_usec), status, &error); - LLDB_LOGV(log, - "Read (buffer, sizeof(buffer), timeout_usec = 0x{0:x}, " - "status = {1}, error = {2}) => bytes_read = {4}", - timeout_usec, - Communication::ConnectionStatusAsCString(status), - error, bytes_read); + LLDB_LOGV(log, + "Read (buffer, sizeof(buffer), timeout_usec = 0x{0:x}, " + "status = {1}, error = {2}) => bytes_read = {4}", + timeout_usec, Communication::ConnectionStatusAsString(status), + error, bytes_read); if (bytes_read > 0) { if (CheckForPacket(buffer, bytes_read, packet)) @@ -239,6 +237,7 @@ bool CommunicationKDP::CheckForPacket(const uint8_t *src, size_t src_len, if (log && log->GetVerbose()) { PacketStreamType log_strm; DumpHexBytes(&log_strm, src, src_len, UINT32_MAX, LLDB_INVALID_ADDRESS); + log_strm.PutChar('\0'); LLDB_LOGF(log, "CommunicationKDP::%s adding %u bytes: %s", __FUNCTION__, (uint32_t)src_len, log_strm.GetData()); } diff --git a/gnu/llvm/lldb/source/Plugins/Process/MacOSX-Kernel/CommunicationKDP.h b/gnu/llvm/lldb/source/Plugins/Process/MacOSX-Kernel/CommunicationKDP.h index d04765f9d86..4981b42008d 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/MacOSX-Kernel/CommunicationKDP.h +++ b/gnu/llvm/lldb/source/Plugins/Process/MacOSX-Kernel/CommunicationKDP.h @@ -25,7 +25,7 @@ public: const static uint32_t kMaxPacketSize = 1200; const static uint32_t kMaxDataSize = 1024; - typedef lldb_private::StreamBuffer<1024> PacketStreamType; + typedef lldb_private::StreamBuffer<4096> PacketStreamType; enum CommandType { KDP_CONNECT = 0u, KDP_DISCONNECT, diff --git a/gnu/llvm/lldb/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.cpp b/gnu/llvm/lldb/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.cpp index 2f4a8917a78..47b2f8d4f5c 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.cpp +++ b/gnu/llvm/lldb/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.cpp @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#include -#include +#include +#include #include #include @@ -73,7 +73,7 @@ public: m_collection_sp->Initialize(g_processkdp_properties); } - virtual ~PluginProperties() {} + virtual ~PluginProperties() = default; uint64_t GetPacketTimeout() { const uint32_t idx = ePropertyKDPPacketTimeout; @@ -111,7 +111,8 @@ void ProcessKDP::Terminate() { lldb::ProcessSP ProcessKDP::CreateInstance(TargetSP target_sp, ListenerSP listener_sp, - const FileSpec *crash_file_path) { + const FileSpec *crash_file_path, + bool can_connect) { lldb::ProcessSP process_sp; if (crash_file_path == NULL) process_sp = std::make_shared(target_sp, listener_sp); @@ -507,8 +508,8 @@ lldb::ThreadSP ProcessKDP::GetKernelThread() { return thread_sp; } -bool ProcessKDP::UpdateThreadList(ThreadList &old_thread_list, - ThreadList &new_thread_list) { +bool ProcessKDP::DoUpdateThreadList(ThreadList &old_thread_list, + ThreadList &new_thread_list) { // locker will keep a mutex locked until it goes out of scope Log *log(ProcessKDPLog::GetLogIfAllCategoriesSet(KDP_LOG_THREAD)); LLDB_LOGV(log, "pid = {0}", GetID()); @@ -644,6 +645,9 @@ Status ProcessKDP::DoDeallocateMemory(lldb::addr_t addr) { } Status ProcessKDP::EnableBreakpointSite(BreakpointSite *bp_site) { + if (bp_site->HardwareRequired()) + return Status("Hardware breakpoints are not supported."); + if (m_comm.LocalBreakpointsAreSupported()) { Status error; if (!bp_site->IsEnabled()) { @@ -873,7 +877,7 @@ private: OptionGroupUInt64 m_command_byte; OptionGroupString m_packet_data; - virtual Options *GetOptions() { return &m_option_group; } + Options *GetOptions() override { return &m_option_group; } public: CommandObjectProcessKDPPacketSend(CommandInterpreter &interpreter) @@ -898,15 +902,14 @@ public: m_option_group.Finalize(); } - ~CommandObjectProcessKDPPacketSend() {} + ~CommandObjectProcessKDPPacketSend() = default; - bool DoExecute(Args &command, CommandReturnObject &result) { + bool DoExecute(Args &command, CommandReturnObject &result) override { const size_t argc = command.GetArgumentCount(); if (argc == 0) { if (!m_command_byte.GetOptionValue().OptionWasSet()) { result.AppendError( "the --command option must be set to a valid command byte"); - result.SetStatus(eReturnStatusFailed); } else { const uint64_t command_byte = m_command_byte.GetOptionValue().GetUInt64Value(0); @@ -929,7 +932,6 @@ public: "even number of ASCII hex " "characters: '%s'", ascii_hex_bytes_cstr); - result.SetStatus(eReturnStatusFailed); return false; } payload_bytes.resize(ascii_hex_bytes_cstr_len / 2); @@ -939,7 +941,6 @@ public: "ASCII hex characters (no " "spaces or hex prefixes): '%s'", ascii_hex_bytes_cstr); - result.SetStatus(eReturnStatusFailed); return false; } } @@ -966,30 +967,25 @@ public: else result.AppendErrorWithFormat("unknown error 0x%8.8x", error.GetError()); - result.SetStatus(eReturnStatusFailed); return false; } } else { result.AppendErrorWithFormat("process must be stopped in order " "to send KDP packets, state is %s", StateAsCString(state)); - result.SetStatus(eReturnStatusFailed); } } else { result.AppendError("invalid process"); - result.SetStatus(eReturnStatusFailed); } } else { result.AppendErrorWithFormat("invalid command byte 0x%" PRIx64 ", valid values are 1 - 255", command_byte); - result.SetStatus(eReturnStatusFailed); } } } else { result.AppendErrorWithFormat("'%s' takes no arguments, only options.", m_cmd_name.c_str()); - result.SetStatus(eReturnStatusFailed); } return false; } @@ -1007,7 +1003,7 @@ public: CommandObjectSP(new CommandObjectProcessKDPPacketSend(interpreter))); } - ~CommandObjectProcessKDPPacket() {} + ~CommandObjectProcessKDPPacket() = default; }; class CommandObjectMultiwordProcessKDP : public CommandObjectMultiword { @@ -1021,7 +1017,7 @@ public: interpreter))); } - ~CommandObjectMultiwordProcessKDP() {} + ~CommandObjectMultiwordProcessKDP() = default; }; CommandObject *ProcessKDP::GetPluginCommandObject() { diff --git a/gnu/llvm/lldb/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.h b/gnu/llvm/lldb/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.h index 52af5613440..6b1cf46b431 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.h +++ b/gnu/llvm/lldb/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.h @@ -32,7 +32,8 @@ public: // Constructors and Destructors static lldb::ProcessSP CreateInstance(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp, - const lldb_private::FileSpec *crash_file_path); + const lldb_private::FileSpec *crash_file_path, + bool can_connect); static void Initialize(); @@ -157,8 +158,8 @@ protected: void Clear(); - bool UpdateThreadList(lldb_private::ThreadList &old_thread_list, - lldb_private::ThreadList &new_thread_list) override; + bool DoUpdateThreadList(lldb_private::ThreadList &old_thread_list, + lldb_private::ThreadList &new_thread_list) override; enum { eBroadcastBitAsyncContinue = (1 << 0), diff --git a/gnu/llvm/lldb/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm.cpp b/gnu/llvm/lldb/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm.cpp index 81b602a2b7a..64f0caac75f 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm.cpp +++ b/gnu/llvm/lldb/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm.cpp @@ -19,7 +19,7 @@ RegisterContextKDP_arm::RegisterContextKDP_arm(ThreadKDP &thread, : RegisterContextDarwin_arm(thread, concrete_frame_idx), m_kdp_thread(thread) {} -RegisterContextKDP_arm::~RegisterContextKDP_arm() {} +RegisterContextKDP_arm::~RegisterContextKDP_arm() = default; int RegisterContextKDP_arm::DoReadGPR(lldb::tid_t tid, int flavor, GPR &gpr) { ProcessSP process_sp(CalculateProcess()); diff --git a/gnu/llvm/lldb/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm.h b/gnu/llvm/lldb/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm.h index 616aff8afda..35ae0d03e2b 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm.h +++ b/gnu/llvm/lldb/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm.h @@ -20,21 +20,21 @@ public: virtual ~RegisterContextKDP_arm(); protected: - virtual int DoReadGPR(lldb::tid_t tid, int flavor, GPR &gpr); + int DoReadGPR(lldb::tid_t tid, int flavor, GPR &gpr) override; - int DoReadFPU(lldb::tid_t tid, int flavor, FPU &fpu); + int DoReadFPU(lldb::tid_t tid, int flavor, FPU &fpu) override; - int DoReadEXC(lldb::tid_t tid, int flavor, EXC &exc); + int DoReadEXC(lldb::tid_t tid, int flavor, EXC &exc) override; - int DoReadDBG(lldb::tid_t tid, int flavor, DBG &dbg); + int DoReadDBG(lldb::tid_t tid, int flavor, DBG &dbg) override; - int DoWriteGPR(lldb::tid_t tid, int flavor, const GPR &gpr); + int DoWriteGPR(lldb::tid_t tid, int flavor, const GPR &gpr) override; - int DoWriteFPU(lldb::tid_t tid, int flavor, const FPU &fpu); + int DoWriteFPU(lldb::tid_t tid, int flavor, const FPU &fpu) override; - int DoWriteEXC(lldb::tid_t tid, int flavor, const EXC &exc); + int DoWriteEXC(lldb::tid_t tid, int flavor, const EXC &exc) override; - int DoWriteDBG(lldb::tid_t tid, int flavor, const DBG &dbg); + int DoWriteDBG(lldb::tid_t tid, int flavor, const DBG &dbg) override; ThreadKDP &m_kdp_thread; }; diff --git a/gnu/llvm/lldb/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm64.cpp b/gnu/llvm/lldb/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm64.cpp index c5e710968c3..c56356d3bf4 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm64.cpp +++ b/gnu/llvm/lldb/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm64.cpp @@ -19,7 +19,7 @@ RegisterContextKDP_arm64::RegisterContextKDP_arm64(ThreadKDP &thread, : RegisterContextDarwin_arm64(thread, concrete_frame_idx), m_kdp_thread(thread) {} -RegisterContextKDP_arm64::~RegisterContextKDP_arm64() {} +RegisterContextKDP_arm64::~RegisterContextKDP_arm64() = default; int RegisterContextKDP_arm64::DoReadGPR(lldb::tid_t tid, int flavor, GPR &gpr) { ProcessSP process_sp(CalculateProcess()); diff --git a/gnu/llvm/lldb/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm64.h b/gnu/llvm/lldb/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm64.h index 998a78a6b8a..be387d69c6b 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm64.h +++ b/gnu/llvm/lldb/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_arm64.h @@ -21,21 +21,21 @@ public: virtual ~RegisterContextKDP_arm64(); protected: - virtual int DoReadGPR(lldb::tid_t tid, int flavor, GPR &gpr); + int DoReadGPR(lldb::tid_t tid, int flavor, GPR &gpr) override; - int DoReadFPU(lldb::tid_t tid, int flavor, FPU &fpu); + int DoReadFPU(lldb::tid_t tid, int flavor, FPU &fpu) override; - int DoReadEXC(lldb::tid_t tid, int flavor, EXC &exc); + int DoReadEXC(lldb::tid_t tid, int flavor, EXC &exc) override; - int DoReadDBG(lldb::tid_t tid, int flavor, DBG &dbg); + int DoReadDBG(lldb::tid_t tid, int flavor, DBG &dbg) override; - int DoWriteGPR(lldb::tid_t tid, int flavor, const GPR &gpr); + int DoWriteGPR(lldb::tid_t tid, int flavor, const GPR &gpr) override; - int DoWriteFPU(lldb::tid_t tid, int flavor, const FPU &fpu); + int DoWriteFPU(lldb::tid_t tid, int flavor, const FPU &fpu) override; - int DoWriteEXC(lldb::tid_t tid, int flavor, const EXC &exc); + int DoWriteEXC(lldb::tid_t tid, int flavor, const EXC &exc) override; - int DoWriteDBG(lldb::tid_t tid, int flavor, const DBG &dbg); + int DoWriteDBG(lldb::tid_t tid, int flavor, const DBG &dbg) override; ThreadKDP &m_kdp_thread; }; diff --git a/gnu/llvm/lldb/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_i386.cpp b/gnu/llvm/lldb/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_i386.cpp index aa46e466804..61dfeae6ddf 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_i386.cpp +++ b/gnu/llvm/lldb/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_i386.cpp @@ -18,7 +18,7 @@ RegisterContextKDP_i386::RegisterContextKDP_i386(ThreadKDP &thread, : RegisterContextDarwin_i386(thread, concrete_frame_idx), m_kdp_thread(thread) {} -RegisterContextKDP_i386::~RegisterContextKDP_i386() {} +RegisterContextKDP_i386::~RegisterContextKDP_i386() = default; int RegisterContextKDP_i386::DoReadGPR(lldb::tid_t tid, int flavor, GPR &gpr) { ProcessSP process_sp(CalculateProcess()); diff --git a/gnu/llvm/lldb/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_i386.h b/gnu/llvm/lldb/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_i386.h index f32c88e6cfc..9ee6af7cc57 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_i386.h +++ b/gnu/llvm/lldb/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_i386.h @@ -20,17 +20,17 @@ public: virtual ~RegisterContextKDP_i386(); protected: - virtual int DoReadGPR(lldb::tid_t tid, int flavor, GPR &gpr); + int DoReadGPR(lldb::tid_t tid, int flavor, GPR &gpr) override; - int DoReadFPU(lldb::tid_t tid, int flavor, FPU &fpu); + int DoReadFPU(lldb::tid_t tid, int flavor, FPU &fpu) override; - int DoReadEXC(lldb::tid_t tid, int flavor, EXC &exc); + int DoReadEXC(lldb::tid_t tid, int flavor, EXC &exc) override; - int DoWriteGPR(lldb::tid_t tid, int flavor, const GPR &gpr); + int DoWriteGPR(lldb::tid_t tid, int flavor, const GPR &gpr) override; - int DoWriteFPU(lldb::tid_t tid, int flavor, const FPU &fpu); + int DoWriteFPU(lldb::tid_t tid, int flavor, const FPU &fpu) override; - int DoWriteEXC(lldb::tid_t tid, int flavor, const EXC &exc); + int DoWriteEXC(lldb::tid_t tid, int flavor, const EXC &exc) override; ThreadKDP &m_kdp_thread; }; diff --git a/gnu/llvm/lldb/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_x86_64.cpp b/gnu/llvm/lldb/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_x86_64.cpp index 565dd1c73f6..9c47c22608b 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_x86_64.cpp +++ b/gnu/llvm/lldb/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_x86_64.cpp @@ -18,7 +18,7 @@ RegisterContextKDP_x86_64::RegisterContextKDP_x86_64( : RegisterContextDarwin_x86_64(thread, concrete_frame_idx), m_kdp_thread(thread) {} -RegisterContextKDP_x86_64::~RegisterContextKDP_x86_64() {} +RegisterContextKDP_x86_64::~RegisterContextKDP_x86_64() = default; int RegisterContextKDP_x86_64::DoReadGPR(lldb::tid_t tid, int flavor, GPR &gpr) { diff --git a/gnu/llvm/lldb/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_x86_64.h b/gnu/llvm/lldb/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_x86_64.h index c4aad972ab5..3d5139d0b61 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_x86_64.h +++ b/gnu/llvm/lldb/source/Plugins/Process/MacOSX-Kernel/RegisterContextKDP_x86_64.h @@ -20,17 +20,17 @@ public: virtual ~RegisterContextKDP_x86_64(); protected: - virtual int DoReadGPR(lldb::tid_t tid, int flavor, GPR &gpr); + int DoReadGPR(lldb::tid_t tid, int flavor, GPR &gpr) override; - int DoReadFPU(lldb::tid_t tid, int flavor, FPU &fpu); + int DoReadFPU(lldb::tid_t tid, int flavor, FPU &fpu) override; - int DoReadEXC(lldb::tid_t tid, int flavor, EXC &exc); + int DoReadEXC(lldb::tid_t tid, int flavor, EXC &exc) override; - int DoWriteGPR(lldb::tid_t tid, int flavor, const GPR &gpr); + int DoWriteGPR(lldb::tid_t tid, int flavor, const GPR &gpr) override; - int DoWriteFPU(lldb::tid_t tid, int flavor, const FPU &fpu); + int DoWriteFPU(lldb::tid_t tid, int flavor, const FPU &fpu) override; - int DoWriteEXC(lldb::tid_t tid, int flavor, const EXC &exc); + int DoWriteEXC(lldb::tid_t tid, int flavor, const EXC &exc) override; ThreadKDP &m_kdp_thread; }; diff --git a/gnu/llvm/lldb/source/Plugins/Process/MacOSX-Kernel/ThreadKDP.h b/gnu/llvm/lldb/source/Plugins/Process/MacOSX-Kernel/ThreadKDP.h index c75540a7730..7f13fcbeb4a 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/MacOSX-Kernel/ThreadKDP.h +++ b/gnu/llvm/lldb/source/Plugins/Process/MacOSX-Kernel/ThreadKDP.h @@ -22,16 +22,16 @@ public: virtual ~ThreadKDP(); - virtual void RefreshStateAfterStop(); + void RefreshStateAfterStop() override; - virtual const char *GetName(); + const char *GetName() override; - virtual const char *GetQueueName(); + const char *GetQueueName() override; - virtual lldb::RegisterContextSP GetRegisterContext(); + lldb::RegisterContextSP GetRegisterContext() override; - virtual lldb::RegisterContextSP - CreateRegisterContextForFrame(lldb_private::StackFrame *frame); + lldb::RegisterContextSP + CreateRegisterContextForFrame(lldb_private::StackFrame *frame) override; void Dump(lldb_private::Log *log, uint32_t index); @@ -41,7 +41,7 @@ public: const char *GetBasicInfoAsString(); - void SetName(const char *name) { + void SetName(const char *name) override { if (name && name[0]) m_thread_name.assign(name); else @@ -66,7 +66,7 @@ protected: lldb::addr_t m_thread_dispatch_qaddr; lldb::StopInfoSP m_cached_stop_info_sp; // Protected member functions. - virtual bool CalculateStopInfo(); + bool CalculateStopInfo() override; }; #endif // LLDB_SOURCE_PLUGINS_PROCESS_MACOSX_KERNEL_THREADKDP_H diff --git a/gnu/llvm/lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.cpp b/gnu/llvm/lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.cpp index 5109022d80d..9ea1a16b878 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.cpp +++ b/gnu/llvm/lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.cpp @@ -98,18 +98,7 @@ NativeProcessNetBSD::Factory::Launch(ProcessLaunchInfo &launch_info, pid, launch_info.GetPTY().ReleasePrimaryFileDescriptor(), native_delegate, Info.GetArchitecture(), mainloop)); - // Enable event reporting - ptrace_event_t events; - status = PtraceWrapper(PT_GET_EVENT_MASK, pid, &events, sizeof(events)); - if (status.Fail()) - return status.ToError(); - // TODO: PTRACE_FORK | PTRACE_VFORK | PTRACE_POSIX_SPAWN? - events.pe_set_event |= PTRACE_LWP_CREATE | PTRACE_LWP_EXIT; - status = PtraceWrapper(PT_SET_EVENT_MASK, pid, &events, sizeof(events)); - if (status.Fail()) - return status.ToError(); - - status = process_up->ReinitializeThreads(); + status = process_up->SetupTrace(); if (status.Fail()) return status.ToError(); @@ -144,13 +133,20 @@ NativeProcessNetBSD::Factory::Attach( return std::move(process_up); } +NativeProcessNetBSD::Extension +NativeProcessNetBSD::Factory::GetSupportedExtensions() const { + return Extension::multiprocess | Extension::fork | Extension::vfork | + Extension::pass_signals | Extension::auxv | Extension::libraries_svr4; +} + // Public Instance Methods NativeProcessNetBSD::NativeProcessNetBSD(::pid_t pid, int terminal_fd, NativeDelegate &delegate, const ArchSpec &arch, MainLoop &mainloop) - : NativeProcessELF(pid, terminal_fd, delegate), m_arch(arch) { + : NativeProcessELF(pid, terminal_fd, delegate), m_arch(arch), + m_main_loop(mainloop) { if (m_terminal_fd != -1) { Status status = EnsureFDFlags(m_terminal_fd, O_NONBLOCK); assert(status.Success()); @@ -218,10 +214,14 @@ void NativeProcessNetBSD::MonitorSIGTRAP(lldb::pid_t pid) { // Get details on the signal raised. if (siginfo_err.Fail()) { + LLDB_LOG(log, "PT_GET_SIGINFO failed {0}", siginfo_err); return; } - NativeThreadNetBSD* thread = nullptr; + LLDB_LOG(log, "got SIGTRAP, pid = {0}, lwpid = {1}, si_code = {2}", pid, + info.psi_lwpid, info.psi_siginfo.si_code); + NativeThreadNetBSD *thread = nullptr; + if (info.psi_lwpid > 0) { for (const auto &t : m_threads) { if (t->GetID() == static_cast(info.psi_lwpid)) { @@ -231,8 +231,7 @@ void NativeProcessNetBSD::MonitorSIGTRAP(lldb::pid_t pid) { static_cast(t.get())->SetStoppedWithNoReason(); } if (!thread) - LLDB_LOG(log, - "thread not found in m_threads, pid = {0}, LWP = {1}", pid, + LLDB_LOG(log, "thread not found in m_threads, pid = {0}, LWP = {1}", pid, info.psi_lwpid); } @@ -243,12 +242,12 @@ void NativeProcessNetBSD::MonitorSIGTRAP(lldb::pid_t pid) { FixupBreakpointPCAsNeeded(*thread); } SetState(StateType::eStateStopped, true); - break; + return; case TRAP_TRACE: if (thread) thread->SetStoppedByTrace(); SetState(StateType::eStateStopped, true); - break; + return; case TRAP_EXEC: { Status error = ReinitializeThreads(); if (error.Fail()) { @@ -262,8 +261,9 @@ void NativeProcessNetBSD::MonitorSIGTRAP(lldb::pid_t pid) { for (const auto &thread : m_threads) static_cast(*thread).SetStoppedByExec(); SetState(StateType::eStateStopped, true); - } break; - case TRAP_LWP: { + return; + } + case TRAP_CHLD: { ptrace_state_t pst; Status error = PtraceWrapper(PT_GET_PROCESS_STATE, pid, &pst, sizeof(pst)); if (error.Fail()) { @@ -271,36 +271,59 @@ void NativeProcessNetBSD::MonitorSIGTRAP(lldb::pid_t pid) { return; } - switch (pst.pe_report_event) { - case PTRACE_LWP_CREATE: { - LLDB_LOG(log, - "monitoring new thread, pid = {0}, LWP = {1}", pid, - pst.pe_lwp); - NativeThreadNetBSD& t = AddThread(pst.pe_lwp); - error = t.CopyWatchpointsFrom( - static_cast(*GetCurrentThread())); - if (error.Fail()) { - LLDB_LOG(log, - "failed to copy watchpoints to new thread {0}: {1}", - pst.pe_lwp, error); + assert(thread); + if (pst.pe_report_event == PTRACE_VFORK_DONE) { + if ((m_enabled_extensions & Extension::vfork) == Extension::vfork) { + thread->SetStoppedByVForkDone(); + SetState(StateType::eStateStopped, true); + } else { + Status error = + PtraceWrapper(PT_CONTINUE, pid, reinterpret_cast(1), 0); + if (error.Fail()) SetState(StateType::eStateInvalid); - return; - } - } break; - case PTRACE_LWP_EXIT: - LLDB_LOG(log, - "removing exited thread, pid = {0}, LWP = {1}", pid, - pst.pe_lwp); - RemoveThread(pst.pe_lwp); - break; + } + } else { + assert(pst.pe_report_event == PTRACE_FORK || + pst.pe_report_event == PTRACE_VFORK); + MonitorClone(pst.pe_other_pid, pst.pe_report_event == PTRACE_VFORK, + *thread); } - - error = PtraceWrapper(PT_CONTINUE, pid, reinterpret_cast(1), 0); + return; + } + case TRAP_LWP: { + ptrace_state_t pst; + Status error = PtraceWrapper(PT_GET_PROCESS_STATE, pid, &pst, sizeof(pst)); if (error.Fail()) { SetState(StateType::eStateInvalid); return; } - } break; + + switch (pst.pe_report_event) { + case PTRACE_LWP_CREATE: { + LLDB_LOG(log, "monitoring new thread, pid = {0}, LWP = {1}", pid, + pst.pe_lwp); + NativeThreadNetBSD &t = AddThread(pst.pe_lwp); + error = t.CopyWatchpointsFrom( + static_cast(*GetCurrentThread())); + if (error.Fail()) { + LLDB_LOG(log, "failed to copy watchpoints to new thread {0}: {1}", + pst.pe_lwp, error); + SetState(StateType::eStateInvalid); + return; + } + } break; + case PTRACE_LWP_EXIT: + LLDB_LOG(log, "removing exited thread, pid = {0}, LWP = {1}", pid, + pst.pe_lwp); + RemoveThread(pst.pe_lwp); + break; + } + + error = PtraceWrapper(PT_CONTINUE, pid, reinterpret_cast(1), 0); + if (error.Fail()) + SetState(StateType::eStateInvalid); + return; + } case TRAP_DBREG: { if (!thread) break; @@ -308,29 +331,42 @@ void NativeProcessNetBSD::MonitorSIGTRAP(lldb::pid_t pid) { auto ®ctx = static_cast( thread->GetRegisterContext()); uint32_t wp_index = LLDB_INVALID_INDEX32; - Status error = regctx.GetWatchpointHitIndex(wp_index, - (uintptr_t)info.psi_siginfo.si_addr); + Status error = regctx.GetWatchpointHitIndex( + wp_index, (uintptr_t)info.psi_siginfo.si_addr); if (error.Fail()) LLDB_LOG(log, "received error while checking for watchpoint hits, pid = " - "{0}, LWP = {1}, error = {2}", pid, info.psi_lwpid, error); + "{0}, LWP = {1}, error = {2}", + pid, info.psi_lwpid, error); if (wp_index != LLDB_INVALID_INDEX32) { thread->SetStoppedByWatchpoint(wp_index); regctx.ClearWatchpointHit(wp_index); SetState(StateType::eStateStopped, true); - break; + return; } thread->SetStoppedByTrace(); SetState(StateType::eStateStopped, true); - } break; + return; + } } + + // Either user-generated SIGTRAP or an unknown event that would + // otherwise leave the debugger hanging. + LLDB_LOG(log, "unknown SIGTRAP, passing to generic handler"); + MonitorSignal(pid, SIGTRAP); } void NativeProcessNetBSD::MonitorSignal(lldb::pid_t pid, int signal) { + Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); ptrace_siginfo_t info; + const auto siginfo_err = PtraceWrapper(PT_GET_SIGINFO, pid, &info, sizeof(info)); + if (siginfo_err.Fail()) { + LLDB_LOG(log, "PT_LWPINFO failed {0}", siginfo_err); + return; + } for (const auto &abs_thread : m_threads) { NativeThreadNetBSD &thread = static_cast(*abs_thread); @@ -489,16 +525,14 @@ Status NativeProcessNetBSD::Resume(const ResumeActionList &resume_actions) { signal = siginfo->psi_siginfo.si_signo; } - ret = PtraceWrapper(PT_CONTINUE, GetID(), reinterpret_cast(1), - signal); + ret = + PtraceWrapper(PT_CONTINUE, GetID(), reinterpret_cast(1), signal); if (ret.Success()) SetState(eStateRunning, true); return ret; } -Status NativeProcessNetBSD::Halt() { - return PtraceWrapper(PT_STOP, GetID()); -} +Status NativeProcessNetBSD::Halt() { return PtraceWrapper(PT_STOP, GetID()); } Status NativeProcessNetBSD::Detach() { Status error; @@ -510,7 +544,7 @@ Status NativeProcessNetBSD::Detach() { if (GetID() == LLDB_INVALID_PROCESS_ID) return error; - return PtraceWrapper(PT_DETACH, GetID()); + return PtraceWrapper(PT_DETACH, GetID(), reinterpret_cast(1)); } Status NativeProcessNetBSD::Signal(int signo) { @@ -662,8 +696,8 @@ Status NativeProcessNetBSD::PopulateMemoryRegionCache() { if (vm[i].kve_path[0]) info.SetName(vm[i].kve_path); - m_mem_region_cache.emplace_back( - info, FileSpec(info.GetName().GetCString())); + m_mem_region_cache.emplace_back(info, + FileSpec(info.GetName().GetCString())); } free(vm); @@ -684,15 +718,6 @@ Status NativeProcessNetBSD::PopulateMemoryRegionCache() { return Status(); } -Status NativeProcessNetBSD::AllocateMemory(size_t size, uint32_t permissions, - lldb::addr_t &addr) { - return Status("Unimplemented"); -} - -Status NativeProcessNetBSD::DeallocateMemory(lldb::addr_t addr) { - return Status("Unimplemented"); -} - lldb::addr_t NativeProcessNetBSD::GetSharedLibraryInfoAddress() { // punt on this for now return LLDB_INVALID_ADDRESS; @@ -710,28 +735,54 @@ Status NativeProcessNetBSD::SetBreakpoint(lldb::addr_t addr, uint32_t size, Status NativeProcessNetBSD::GetLoadedModuleFileSpec(const char *module_path, FileSpec &file_spec) { - return Status("Unimplemented"); + Status error = PopulateMemoryRegionCache(); + if (error.Fail()) + return error; + + FileSpec module_file_spec(module_path); + FileSystem::Instance().Resolve(module_file_spec); + + file_spec.Clear(); + for (const auto &it : m_mem_region_cache) { + if (it.second.GetFilename() == module_file_spec.GetFilename()) { + file_spec = it.second; + return Status(); + } + } + return Status("Module file (%s) not found in process' memory map!", + module_file_spec.GetFilename().AsCString()); } Status NativeProcessNetBSD::GetFileLoadAddress(const llvm::StringRef &file_name, lldb::addr_t &load_addr) { load_addr = LLDB_INVALID_ADDRESS; - return Status(); + Status error = PopulateMemoryRegionCache(); + if (error.Fail()) + return error; + + FileSpec file(file_name); + for (const auto &it : m_mem_region_cache) { + if (it.second == file) { + load_addr = it.first.GetRange().GetRangeBase(); + return Status(); + } + } + return Status("No load address found for file %s.", file_name.str().c_str()); } void NativeProcessNetBSD::SigchldHandler() { Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); - // Process all pending waitpid notifications. int status; - ::pid_t wait_pid = - llvm::sys::RetryAfterSignal(-1, waitpid, GetID(), &status, WALLSIG | WNOHANG); + ::pid_t wait_pid = llvm::sys::RetryAfterSignal(-1, waitpid, GetID(), &status, + WALLSIG | WNOHANG); if (wait_pid == 0) - return; // We are done. + return; if (wait_pid == -1) { Status error(errno, eErrorTypePOSIX); LLDB_LOG(log, "waitpid ({0}, &status, _) failed: {1}", GetID(), error); + return; } WaitStatus wait_status = WaitStatus::Decode(status); @@ -806,12 +857,13 @@ Status NativeProcessNetBSD::Attach() { int wstatus; // Need to use WALLSIG otherwise we receive an error with errno=ECHLD At this // point we should have a thread stopped if waitpid succeeds. - if ((wstatus = llvm::sys::RetryAfterSignal(-1, waitpid, - m_pid, nullptr, WALLSIG)) < 0) + if ((wstatus = llvm::sys::RetryAfterSignal(-1, waitpid, m_pid, nullptr, + WALLSIG)) < 0) return Status(errno, eErrorTypePOSIX); - /* Initialize threads */ - status = ReinitializeThreads(); + // Initialize threads and tracing status + // NB: this needs to be called before we set thread state + status = SetupTrace(); if (status.Fail()) return status; @@ -819,7 +871,8 @@ Status NativeProcessNetBSD::Attach() { static_cast(*thread).SetStoppedBySignal(SIGSTOP); // Let our process instance know the thread has stopped. - SetState(StateType::eStateStopped); + SetCurrentThreadID(m_threads.front()->GetID()); + SetState(StateType::eStateStopped, false); return Status(); } @@ -864,7 +917,8 @@ Status NativeProcessNetBSD::WriteMemory(lldb::addr_t addr, const void *buf, io.piod_len = size; do { - io.piod_addr = const_cast(static_cast(src + bytes_written)); + io.piod_addr = + const_cast(static_cast(src + bytes_written)); io.piod_offs = (void *)(addr + bytes_written); Status error = NativeProcessNetBSD::PtraceWrapper(PT_IO, GetID(), &io); @@ -909,6 +963,23 @@ NativeProcessNetBSD::GetAuxvData() const { return std::move(buf); } +Status NativeProcessNetBSD::SetupTrace() { + // Enable event reporting + ptrace_event_t events; + Status status = + PtraceWrapper(PT_GET_EVENT_MASK, GetID(), &events, sizeof(events)); + if (status.Fail()) + return status; + // TODO: PTRACE_POSIX_SPAWN? + events.pe_set_event |= PTRACE_LWP_CREATE | PTRACE_LWP_EXIT | PTRACE_FORK | + PTRACE_VFORK | PTRACE_VFORK_DONE; + status = PtraceWrapper(PT_SET_EVENT_MASK, GetID(), &events, sizeof(events)); + if (status.Fail()) + return status; + + return ReinitializeThreads(); +} + Status NativeProcessNetBSD::ReinitializeThreads() { // Clear old threads m_threads.clear(); @@ -938,3 +1009,67 @@ Status NativeProcessNetBSD::ReinitializeThreads() { return error; } + +void NativeProcessNetBSD::MonitorClone(::pid_t child_pid, bool is_vfork, + NativeThreadNetBSD &parent_thread) { + Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); + LLDB_LOG(log, "clone, child_pid={0}", child_pid); + + int status; + ::pid_t wait_pid = + llvm::sys::RetryAfterSignal(-1, ::waitpid, child_pid, &status, 0); + if (wait_pid != child_pid) { + LLDB_LOG(log, + "waiting for pid {0} failed. Assuming the pid has " + "disappeared in the meantime", + child_pid); + return; + } + if (WIFEXITED(status)) { + LLDB_LOG(log, + "waiting for pid {0} returned an 'exited' event. Not " + "tracking it.", + child_pid); + return; + } + + ptrace_siginfo_t info; + const auto siginfo_err = + PtraceWrapper(PT_GET_SIGINFO, child_pid, &info, sizeof(info)); + if (siginfo_err.Fail()) { + LLDB_LOG(log, "PT_GET_SIGINFO failed {0}", siginfo_err); + return; + } + assert(info.psi_lwpid >= 0); + lldb::tid_t child_tid = info.psi_lwpid; + + std::unique_ptr child_process{ + new NativeProcessNetBSD(static_cast<::pid_t>(child_pid), m_terminal_fd, + m_delegate, m_arch, m_main_loop)}; + if (!is_vfork) + child_process->m_software_breakpoints = m_software_breakpoints; + + Extension expected_ext = is_vfork ? Extension::vfork : Extension::fork; + if ((m_enabled_extensions & expected_ext) == expected_ext) { + child_process->SetupTrace(); + for (const auto &thread : child_process->m_threads) + static_cast(*thread).SetStoppedBySignal(SIGSTOP); + child_process->SetState(StateType::eStateStopped, false); + + m_delegate.NewSubprocess(this, std::move(child_process)); + if (is_vfork) + parent_thread.SetStoppedByVFork(child_pid, child_tid); + else + parent_thread.SetStoppedByFork(child_pid, child_tid); + SetState(StateType::eStateStopped, true); + } else { + child_process->Detach(); + Status pt_error = + PtraceWrapper(PT_CONTINUE, GetID(), reinterpret_cast(1), 0); + if (pt_error.Fail()) { + LLDB_LOG_ERROR(log, std::move(pt_error.ToError()), + "unable to resume parent process {1}: {0}", GetID()); + SetState(StateType::eStateInvalid); + } + } +} diff --git a/gnu/llvm/lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.h b/gnu/llvm/lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.h index 6a06773f40a..90d32aa6069 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.h +++ b/gnu/llvm/lldb/source/Plugins/Process/NetBSD/NativeProcessNetBSD.h @@ -36,6 +36,8 @@ public: llvm::Expected> Attach(lldb::pid_t pid, NativeDelegate &native_delegate, MainLoop &mainloop) const override; + + Extension GetSupportedExtensions() const override; }; // NativeProcessProtocol Interface @@ -60,11 +62,6 @@ public: Status WriteMemory(lldb::addr_t addr, const void *buf, size_t size, size_t &bytes_written) override; - Status AllocateMemory(size_t size, uint32_t permissions, - lldb::addr_t &addr) override; - - Status DeallocateMemory(lldb::addr_t addr) override; - lldb::addr_t GetSharedLibraryInfoAddress() override; size_t UpdateThreads() override; @@ -74,9 +71,13 @@ public: Status SetBreakpoint(lldb::addr_t addr, uint32_t size, bool hardware) override; + // The two following methods are probably not necessary and probably + // will never be called. Nevertheless, we implement them right now + // to reduce the differences between different platforms and reduce + // the risk of the lack of implementation actually breaking something, + // at least for the time being. Status GetLoadedModuleFileSpec(const char *module_path, FileSpec &file_spec) override; - Status GetFileLoadAddress(const llvm::StringRef &file_name, lldb::addr_t &load_addr) override; @@ -90,6 +91,7 @@ public: private: MainLoop::SignalHandleUP m_sigchld_handle; ArchSpec m_arch; + MainLoop& m_main_loop; LazyBool m_supports_mem_region = eLazyBoolCalculate; std::vector> m_mem_region_cache; @@ -107,11 +109,14 @@ private: void MonitorSIGSTOP(lldb::pid_t pid); void MonitorSIGTRAP(lldb::pid_t pid); void MonitorSignal(lldb::pid_t pid, int signal); + void MonitorClone(::pid_t child_pid, bool is_vfork, + NativeThreadNetBSD &parent_thread); Status PopulateMemoryRegionCache(); void SigchldHandler(); Status Attach(); + Status SetupTrace(); Status ReinitializeThreads(); }; diff --git a/gnu/llvm/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD.cpp b/gnu/llvm/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD.cpp index 03b505c1989..4755dab0b07 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD.cpp +++ b/gnu/llvm/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD.cpp @@ -20,12 +20,6 @@ using namespace lldb_private::process_netbsd; #include // clang-format on -NativeRegisterContextNetBSD::NativeRegisterContextNetBSD( - NativeThreadProtocol &native_thread, - RegisterInfoInterface *reg_info_interface_p) - : NativeRegisterContextRegisterInfo(native_thread, - reg_info_interface_p) {} - Status NativeRegisterContextNetBSD::DoRegisterSet(int ptrace_req, void *buf) { return NativeProcessNetBSD::PtraceWrapper(ptrace_req, GetProcessPid(), buf, m_thread.GetID()); diff --git a/gnu/llvm/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD.h b/gnu/llvm/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD.h index 13e023d856d..08490aad9e0 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD.h +++ b/gnu/llvm/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD.h @@ -18,11 +18,9 @@ namespace process_netbsd { class NativeProcessNetBSD; -class NativeRegisterContextNetBSD : public NativeRegisterContextRegisterInfo { +class NativeRegisterContextNetBSD + : public virtual NativeRegisterContextRegisterInfo { public: - NativeRegisterContextNetBSD(NativeThreadProtocol &native_thread, - RegisterInfoInterface *reg_info_interface_p); - // This function is implemented in the NativeRegisterContextNetBSD_* // subclasses to create a new instance of the host specific // NativeRegisterContextNetBSD. The implementations can't collide as only one @@ -31,11 +29,9 @@ public: static NativeRegisterContextNetBSD * CreateHostNativeRegisterContextNetBSD(const ArchSpec &target_arch, NativeThreadProtocol &native_thread); - virtual Status + virtual llvm::Error CopyHardwareWatchpointsFrom(NativeRegisterContextNetBSD &source) = 0; - virtual Status ClearWatchpointHit(uint32_t wp_index) = 0; - protected: Status DoRegisterSet(int req, void *buf); virtual NativeProcessNetBSD &GetProcess(); diff --git a/gnu/llvm/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.cpp b/gnu/llvm/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.cpp index ca4706a6565..3d164eadbea 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.cpp +++ b/gnu/llvm/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.cpp @@ -29,16 +29,13 @@ #include #include #include -#include -#include +#include +#include // clang-format on using namespace lldb_private; using namespace lldb_private::process_netbsd; -// Private namespace. - -namespace { // x86 64-bit general purpose registers. static const uint32_t g_gpr_regnums_x86_64[] = { lldb_rax_x86_64, lldb_rbx_x86_64, lldb_rcx_x86_64, lldb_rdx_x86_64, @@ -87,20 +84,21 @@ static_assert((sizeof(g_gpr_regnums_x86_64) / sizeof(g_gpr_regnums_x86_64[0])) - // x86 64-bit floating point registers. static const uint32_t g_fpu_regnums_x86_64[] = { - lldb_fctrl_x86_64, lldb_fstat_x86_64, lldb_ftag_x86_64, - lldb_fop_x86_64, lldb_fiseg_x86_64, lldb_fioff_x86_64, - lldb_foseg_x86_64, lldb_fooff_x86_64, lldb_mxcsr_x86_64, - lldb_mxcsrmask_x86_64, lldb_st0_x86_64, lldb_st1_x86_64, - lldb_st2_x86_64, lldb_st3_x86_64, lldb_st4_x86_64, - lldb_st5_x86_64, lldb_st6_x86_64, lldb_st7_x86_64, - lldb_mm0_x86_64, lldb_mm1_x86_64, lldb_mm2_x86_64, - lldb_mm3_x86_64, lldb_mm4_x86_64, lldb_mm5_x86_64, - lldb_mm6_x86_64, lldb_mm7_x86_64, lldb_xmm0_x86_64, - lldb_xmm1_x86_64, lldb_xmm2_x86_64, lldb_xmm3_x86_64, - lldb_xmm4_x86_64, lldb_xmm5_x86_64, lldb_xmm6_x86_64, - lldb_xmm7_x86_64, lldb_xmm8_x86_64, lldb_xmm9_x86_64, - lldb_xmm10_x86_64, lldb_xmm11_x86_64, lldb_xmm12_x86_64, - lldb_xmm13_x86_64, lldb_xmm14_x86_64, lldb_xmm15_x86_64, + lldb_fctrl_x86_64, lldb_fstat_x86_64, lldb_ftag_x86_64, + lldb_fop_x86_64, lldb_fiseg_x86_64, lldb_fioff_x86_64, + lldb_fip_x86_64, lldb_foseg_x86_64, lldb_fooff_x86_64, + lldb_fdp_x86_64, lldb_mxcsr_x86_64, lldb_mxcsrmask_x86_64, + lldb_st0_x86_64, lldb_st1_x86_64, lldb_st2_x86_64, + lldb_st3_x86_64, lldb_st4_x86_64, lldb_st5_x86_64, + lldb_st6_x86_64, lldb_st7_x86_64, lldb_mm0_x86_64, + lldb_mm1_x86_64, lldb_mm2_x86_64, lldb_mm3_x86_64, + lldb_mm4_x86_64, lldb_mm5_x86_64, lldb_mm6_x86_64, + lldb_mm7_x86_64, lldb_xmm0_x86_64, lldb_xmm1_x86_64, + lldb_xmm2_x86_64, lldb_xmm3_x86_64, lldb_xmm4_x86_64, + lldb_xmm5_x86_64, lldb_xmm6_x86_64, lldb_xmm7_x86_64, + lldb_xmm8_x86_64, lldb_xmm9_x86_64, lldb_xmm10_x86_64, + lldb_xmm11_x86_64, lldb_xmm12_x86_64, lldb_xmm13_x86_64, + lldb_xmm14_x86_64, lldb_xmm15_x86_64, LLDB_INVALID_REGNUM // register sets need to end with this flag }; static_assert((sizeof(g_fpu_regnums_x86_64) / sizeof(g_fpu_regnums_x86_64[0])) - @@ -108,27 +106,34 @@ static_assert((sizeof(g_fpu_regnums_x86_64) / sizeof(g_fpu_regnums_x86_64[0])) - k_num_fpr_registers_x86_64, "g_fpu_regnums_x86_64 has wrong number of register infos"); -// x86 64-bit registers available via XState. -static const uint32_t g_xstate_regnums_x86_64[] = { +static const uint32_t g_avx_regnums_x86_64[] = { lldb_ymm0_x86_64, lldb_ymm1_x86_64, lldb_ymm2_x86_64, lldb_ymm3_x86_64, lldb_ymm4_x86_64, lldb_ymm5_x86_64, lldb_ymm6_x86_64, lldb_ymm7_x86_64, lldb_ymm8_x86_64, lldb_ymm9_x86_64, lldb_ymm10_x86_64, lldb_ymm11_x86_64, lldb_ymm12_x86_64, lldb_ymm13_x86_64, lldb_ymm14_x86_64, lldb_ymm15_x86_64, + LLDB_INVALID_REGNUM // register sets need to end with this flag +}; +static_assert((sizeof(g_avx_regnums_x86_64) / sizeof(g_avx_regnums_x86_64[0])) - + 1 == + k_num_avx_registers_x86_64, + "g_avx_regnums_x86_64 has wrong number of register infos"); + +static const uint32_t g_mpx_regnums_x86_64[] = { // Note: we currently do not provide them but this is needed to avoid // unnamed groups in SBFrame::GetRegisterContext(). - lldb_bnd0_x86_64, lldb_bnd1_x86_64, lldb_bnd2_x86_64, - lldb_bnd3_x86_64, lldb_bndcfgu_x86_64, lldb_bndstatus_x86_64, + lldb_bnd0_x86_64, lldb_bnd1_x86_64, lldb_bnd2_x86_64, + lldb_bnd3_x86_64, lldb_bndcfgu_x86_64, lldb_bndstatus_x86_64, LLDB_INVALID_REGNUM // register sets need to end with this flag }; -static_assert((sizeof(g_xstate_regnums_x86_64) / sizeof(g_xstate_regnums_x86_64[0])) - +static_assert((sizeof(g_mpx_regnums_x86_64) / sizeof(g_mpx_regnums_x86_64[0])) - 1 == - k_num_avx_registers_x86_64 + k_num_mpx_registers_x86_64, - "g_xstate_regnums_x86_64 has wrong number of register infos"); + k_num_mpx_registers_x86_64, + "g_mpx_regnums_x86_64 has wrong number of register infos"); // x86 debug registers. static const uint32_t g_dbr_regnums_x86_64[] = { - lldb_dr0_x86_64, lldb_dr1_x86_64, lldb_dr2_x86_64, lldb_dr3_x86_64, - lldb_dr4_x86_64, lldb_dr5_x86_64, lldb_dr6_x86_64, lldb_dr7_x86_64, + lldb_dr0_x86_64, lldb_dr1_x86_64, lldb_dr2_x86_64, lldb_dr3_x86_64, + lldb_dr4_x86_64, lldb_dr5_x86_64, lldb_dr6_x86_64, lldb_dr7_x86_64, LLDB_INVALID_REGNUM // register sets need to end with this flag }; static_assert((sizeof(g_dbr_regnums_x86_64) / sizeof(g_dbr_regnums_x86_64[0])) - @@ -137,7 +142,7 @@ static_assert((sizeof(g_dbr_regnums_x86_64) / sizeof(g_dbr_regnums_x86_64[0])) - "g_dbr_regnums_x86_64 has wrong number of register infos"); // x86 32-bit general purpose registers. -const uint32_t g_gpr_regnums_i386[] = { +static const uint32_t g_gpr_regnums_i386[] = { lldb_eax_i386, lldb_ebx_i386, lldb_ecx_i386, lldb_edx_i386, lldb_edi_i386, lldb_esi_i386, lldb_ebp_i386, lldb_esp_i386, lldb_eip_i386, lldb_eflags_i386, lldb_cs_i386, lldb_fs_i386, @@ -154,7 +159,7 @@ static_assert((sizeof(g_gpr_regnums_i386) / sizeof(g_gpr_regnums_i386[0])) - "g_gpr_regnums_i386 has wrong number of register infos"); // x86 32-bit floating point registers. -const uint32_t g_fpu_regnums_i386[] = { +static const uint32_t g_fpu_regnums_i386[] = { lldb_fctrl_i386, lldb_fstat_i386, lldb_ftag_i386, lldb_fop_i386, lldb_fiseg_i386, lldb_fioff_i386, lldb_foseg_i386, lldb_fooff_i386, lldb_mxcsr_i386, lldb_mxcsrmask_i386, lldb_st0_i386, lldb_st1_i386, @@ -171,25 +176,32 @@ static_assert((sizeof(g_fpu_regnums_i386) / sizeof(g_fpu_regnums_i386[0])) - k_num_fpr_registers_i386, "g_fpu_regnums_i386 has wrong number of register infos"); -// x86 64-bit registers available via XState. -static const uint32_t g_xstate_regnums_i386[] = { - lldb_ymm0_i386, lldb_ymm1_i386, lldb_ymm2_i386, lldb_ymm3_i386, - lldb_ymm4_i386, lldb_ymm5_i386, lldb_ymm6_i386, lldb_ymm7_i386, +static const uint32_t g_avx_regnums_i386[] = { + lldb_ymm0_i386, lldb_ymm1_i386, lldb_ymm2_i386, lldb_ymm3_i386, + lldb_ymm4_i386, lldb_ymm5_i386, lldb_ymm6_i386, lldb_ymm7_i386, + LLDB_INVALID_REGNUM // register sets need to end with this flag +}; +static_assert((sizeof(g_avx_regnums_i386) / sizeof(g_avx_regnums_i386[0])) - + 1 == + k_num_avx_registers_i386, + "g_avx_regnums_i386 has wrong number of register infos"); + +static const uint32_t g_mpx_regnums_i386[] = { // Note: we currently do not provide them but this is needed to avoid // unnamed groups in SBFrame::GetRegisterContext(). - lldb_bnd0_i386, lldb_bnd1_i386, lldb_bnd2_i386, - lldb_bnd3_i386, lldb_bndcfgu_i386, lldb_bndstatus_i386, + lldb_bnd0_i386, lldb_bnd1_i386, lldb_bnd2_i386, + lldb_bnd3_i386, lldb_bndcfgu_i386, lldb_bndstatus_i386, LLDB_INVALID_REGNUM // register sets need to end with this flag }; -static_assert((sizeof(g_xstate_regnums_i386) / sizeof(g_xstate_regnums_i386[0])) - +static_assert((sizeof(g_mpx_regnums_i386) / sizeof(g_mpx_regnums_i386[0])) - 1 == - k_num_avx_registers_i386 + k_num_mpx_registers_i386, - "g_xstate_regnums_i386 has wrong number of register infos"); + k_num_mpx_registers_i386, + "g_mpx_regnums_i386 has wrong number of register infos"); // x86 debug registers. static const uint32_t g_dbr_regnums_i386[] = { - lldb_dr0_i386, lldb_dr1_i386, lldb_dr2_i386, lldb_dr3_i386, - lldb_dr4_i386, lldb_dr5_i386, lldb_dr6_i386, lldb_dr7_i386, + lldb_dr0_i386, lldb_dr1_i386, lldb_dr2_i386, lldb_dr3_i386, + lldb_dr4_i386, lldb_dr5_i386, lldb_dr6_i386, lldb_dr7_i386, LLDB_INVALID_REGNUM // register sets need to end with this flag }; static_assert((sizeof(g_dbr_regnums_i386) / sizeof(g_dbr_regnums_i386[0])) - @@ -197,9 +209,8 @@ static_assert((sizeof(g_dbr_regnums_i386) / sizeof(g_dbr_regnums_i386[0])) - k_num_dbr_registers_i386, "g_dbr_regnums_i386 has wrong number of register infos"); - // Number of register sets provided by this context. -enum { k_num_register_sets = 4 }; +enum { k_num_register_sets = 5 }; // Register sets for x86 32-bit. static const RegisterSet g_reg_sets_i386[k_num_register_sets] = { @@ -207,11 +218,11 @@ static const RegisterSet g_reg_sets_i386[k_num_register_sets] = { g_gpr_regnums_i386}, {"Floating Point Registers", "fpu", k_num_fpr_registers_i386, g_fpu_regnums_i386}, - {"Extended State Registers", "xstate", - k_num_avx_registers_i386 + k_num_mpx_registers_i386, - g_xstate_regnums_i386}, - {"Debug Registers", "dbr", k_num_dbr_registers_i386, - g_dbr_regnums_i386}, + {"Debug Registers", "dbr", k_num_dbr_registers_i386, g_dbr_regnums_i386}, + {"Advanced Vector Extensions", "avx", k_num_avx_registers_i386, + g_avx_regnums_i386}, + {"Memory Protection Extensions", "mpx", k_num_mpx_registers_i386, + g_mpx_regnums_i386}, }; // Register sets for x86 64-bit. @@ -220,15 +231,15 @@ static const RegisterSet g_reg_sets_x86_64[k_num_register_sets] = { g_gpr_regnums_x86_64}, {"Floating Point Registers", "fpu", k_num_fpr_registers_x86_64, g_fpu_regnums_x86_64}, - {"Extended State Registers", "xstate", - k_num_avx_registers_x86_64 + k_num_mpx_registers_x86_64, - g_xstate_regnums_x86_64}, {"Debug Registers", "dbr", k_num_dbr_registers_x86_64, g_dbr_regnums_x86_64}, + {"Advanced Vector Extensions", "avx", k_num_avx_registers_x86_64, + g_avx_regnums_x86_64}, + {"Memory Protection Extensions", "mpx", k_num_mpx_registers_x86_64, + g_mpx_regnums_x86_64}, }; #define REG_CONTEXT_SIZE (GetRegisterInfoInterface().GetGPRSize()) -} // namespace NativeRegisterContextNetBSD * NativeRegisterContextNetBSD::CreateHostNativeRegisterContextNetBSD( @@ -246,28 +257,41 @@ CreateRegisterInfoInterface(const ArchSpec &target_arch) { } else { assert((HostInfo::GetArchitecture().GetAddressByteSize() == 8) && "Register setting path assumes this is a 64-bit host"); - // X86_64 hosts know how to work with 64-bit and 32-bit EXEs using the x86_64 - // register context. + // X86_64 hosts know how to work with 64-bit and 32-bit EXEs using the + // x86_64 register context. return new RegisterContextNetBSD_x86_64(target_arch); } } NativeRegisterContextNetBSD_x86_64::NativeRegisterContextNetBSD_x86_64( const ArchSpec &target_arch, NativeThreadProtocol &native_thread) - : NativeRegisterContextNetBSD(native_thread, - CreateRegisterInfoInterface(target_arch)), - m_gpr(), m_fpr(), m_dbr() {} + : NativeRegisterContextRegisterInfo( + native_thread, CreateRegisterInfoInterface(target_arch)), + NativeRegisterContextDBReg_x86(native_thread), m_regset_offsets({0}) { + assert(m_gpr.size() == GetRegisterInfoInterface().GetGPRSize()); + std::array first_regnos; -// CONSIDER after local and llgs debugging are merged, register set support can -// be moved into a base x86-64 class with IsRegisterSetAvailable made virtual. -uint32_t NativeRegisterContextNetBSD_x86_64::GetRegisterSetCount() const { - uint32_t sets = 0; - for (uint32_t set_index = 0; set_index < k_num_register_sets; ++set_index) { - if (GetSetForNativeRegNum(set_index) != -1) - ++sets; + switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) { + case llvm::Triple::x86: + first_regnos[FPRegSet] = lldb_fctrl_i386; + first_regnos[DBRegSet] = lldb_dr0_i386; + break; + case llvm::Triple::x86_64: + first_regnos[FPRegSet] = lldb_fctrl_x86_64; + first_regnos[DBRegSet] = lldb_dr0_x86_64; + break; + default: + llvm_unreachable("Unhandled target architecture."); } - return sets; + for (int i : {FPRegSet, DBRegSet}) + m_regset_offsets[i] = GetRegisterInfoInterface() + .GetRegisterInfo()[first_regnos[i]] + .byte_offset; +} + +uint32_t NativeRegisterContextNetBSD_x86_64::GetRegisterSetCount() const { + return k_num_register_sets; } const RegisterSet * @@ -278,199 +302,79 @@ NativeRegisterContextNetBSD_x86_64::GetRegisterSet(uint32_t set_index) const { case llvm::Triple::x86_64: return &g_reg_sets_x86_64[set_index]; default: - assert(false && "Unhandled target architecture."); - return nullptr; + llvm_unreachable("Unhandled target architecture."); } - - return nullptr; } -static constexpr int RegNumX86ToX86_64(int regnum) { - switch (regnum) { - case lldb_eax_i386: - return lldb_rax_x86_64; - case lldb_ebx_i386: - return lldb_rbx_x86_64; - case lldb_ecx_i386: - return lldb_rcx_x86_64; - case lldb_edx_i386: - return lldb_rdx_x86_64; - case lldb_edi_i386: - return lldb_rdi_x86_64; - case lldb_esi_i386: - return lldb_rsi_x86_64; - case lldb_ebp_i386: - return lldb_rbp_x86_64; - case lldb_esp_i386: - return lldb_rsp_x86_64; - case lldb_eip_i386: - return lldb_rip_x86_64; - case lldb_eflags_i386: - return lldb_rflags_x86_64; - case lldb_cs_i386: - return lldb_cs_x86_64; - case lldb_fs_i386: - return lldb_fs_x86_64; - case lldb_gs_i386: - return lldb_gs_x86_64; - case lldb_ss_i386: - return lldb_ss_x86_64; - case lldb_ds_i386: - return lldb_ds_x86_64; - case lldb_es_i386: - return lldb_es_x86_64; - case lldb_fctrl_i386: - return lldb_fctrl_x86_64; - case lldb_fstat_i386: - return lldb_fstat_x86_64; - case lldb_ftag_i386: - return lldb_fstat_x86_64; - case lldb_fop_i386: - return lldb_fop_x86_64; - case lldb_fiseg_i386: - return lldb_fiseg_x86_64; - case lldb_fioff_i386: - return lldb_fioff_x86_64; - case lldb_foseg_i386: - return lldb_foseg_x86_64; - case lldb_fooff_i386: - return lldb_fooff_x86_64; - case lldb_mxcsr_i386: - return lldb_mxcsr_x86_64; - case lldb_mxcsrmask_i386: - return lldb_mxcsrmask_x86_64; - case lldb_st0_i386: - case lldb_st1_i386: - case lldb_st2_i386: - case lldb_st3_i386: - case lldb_st4_i386: - case lldb_st5_i386: - case lldb_st6_i386: - case lldb_st7_i386: - return lldb_st0_x86_64 + regnum - lldb_st0_i386; - case lldb_mm0_i386: - case lldb_mm1_i386: - case lldb_mm2_i386: - case lldb_mm3_i386: - case lldb_mm4_i386: - case lldb_mm5_i386: - case lldb_mm6_i386: - case lldb_mm7_i386: - return lldb_mm0_x86_64 + regnum - lldb_mm0_i386; - case lldb_xmm0_i386: - case lldb_xmm1_i386: - case lldb_xmm2_i386: - case lldb_xmm3_i386: - case lldb_xmm4_i386: - case lldb_xmm5_i386: - case lldb_xmm6_i386: - case lldb_xmm7_i386: - return lldb_xmm0_x86_64 + regnum - lldb_xmm0_i386; - case lldb_ymm0_i386: - case lldb_ymm1_i386: - case lldb_ymm2_i386: - case lldb_ymm3_i386: - case lldb_ymm4_i386: - case lldb_ymm5_i386: - case lldb_ymm6_i386: - case lldb_ymm7_i386: - return lldb_ymm0_x86_64 + regnum - lldb_ymm0_i386; - case lldb_dr0_i386: - case lldb_dr1_i386: - case lldb_dr2_i386: - case lldb_dr3_i386: - case lldb_dr4_i386: - case lldb_dr5_i386: - case lldb_dr6_i386: - case lldb_dr7_i386: - return lldb_dr0_x86_64 + regnum - lldb_dr0_i386; - default: - assert(false && "Unhandled i386 register."); - return 0; - } -} - -int NativeRegisterContextNetBSD_x86_64::GetSetForNativeRegNum( - int reg_num) const { +llvm::Optional +NativeRegisterContextNetBSD_x86_64::GetSetForNativeRegNum( + uint32_t reg_num) const { switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) { case llvm::Triple::x86: - if (reg_num <= k_last_gpr_i386) + if (reg_num >= k_first_gpr_i386 && reg_num <= k_last_gpr_i386) return GPRegSet; - else if (reg_num <= k_last_fpr_i386) + if (reg_num >= k_first_fpr_i386 && reg_num <= k_last_fpr_i386) return FPRegSet; - else if (reg_num <= k_last_avx_i386) - return XStateRegSet; // AVX - else if (reg_num <= lldb_dr7_i386) + if (reg_num >= k_first_avx_i386 && reg_num <= k_last_avx_i386) + return YMMRegSet; + if (reg_num >= k_first_mpxr_i386 && reg_num <= k_last_mpxr_i386) + return llvm::None; // MPXR + if (reg_num >= k_first_mpxc_i386 && reg_num <= k_last_mpxc_i386) + return llvm::None; // MPXC + if (reg_num >= k_first_dbr_i386 && reg_num <= k_last_dbr_i386) return DBRegSet; // DBR - else - return -1; + break; case llvm::Triple::x86_64: - if (reg_num <= k_last_gpr_x86_64) + if (reg_num >= k_first_gpr_x86_64 && reg_num <= k_last_gpr_x86_64) return GPRegSet; - else if (reg_num <= k_last_fpr_x86_64) + if (reg_num >= k_first_fpr_x86_64 && reg_num <= k_last_fpr_x86_64) return FPRegSet; - else if (reg_num <= k_last_avx_x86_64) - return XStateRegSet; // AVX - else if (reg_num <= k_last_mpxr_x86_64) - return -1; // MPXR - else if (reg_num <= k_last_mpxc_x86_64) - return -1; // MPXC - else if (reg_num <= lldb_dr7_x86_64) + if (reg_num >= k_first_avx_x86_64 && reg_num <= k_last_avx_x86_64) + return YMMRegSet; + if (reg_num >= k_first_mpxr_x86_64 && reg_num <= k_last_mpxr_x86_64) + return llvm::None; // MPXR + if (reg_num >= k_first_mpxc_x86_64 && reg_num <= k_last_mpxc_x86_64) + return llvm::None; // MPXC + if (reg_num >= k_first_dbr_x86_64 && reg_num <= k_last_dbr_x86_64) return DBRegSet; // DBR - else - return -1; + break; default: - assert(false && "Unhandled target architecture."); - return -1; + llvm_unreachable("Unhandled target architecture."); } + + llvm_unreachable("Register does not belong to any register set"); } -Status NativeRegisterContextNetBSD_x86_64::ReadRegisterSet(uint32_t set) { +Status NativeRegisterContextNetBSD_x86_64::ReadRegisterSet(RegSetKind set) { switch (set) { case GPRegSet: - return DoRegisterSet(PT_GETREGS, &m_gpr); - case FPRegSet: -#if defined(__x86_64__) - return DoRegisterSet(PT_GETFPREGS, &m_fpr); -#else - return DoRegisterSet(PT_GETXMMREGS, &m_fpr); -#endif + return DoRegisterSet(PT_GETREGS, m_gpr.data()); case DBRegSet: - return DoRegisterSet(PT_GETDBREGS, &m_dbr); - case XStateRegSet: -#ifdef HAVE_XSTATE - { - struct iovec iov = {&m_xstate, sizeof(m_xstate)}; - return DoRegisterSet(PT_GETXSTATE, &iov); - } -#else - return Status("XState is not supported by the kernel"); -#endif + return DoRegisterSet(PT_GETDBREGS, m_dbr.data()); + case FPRegSet: + case YMMRegSet: + case MPXRegSet: { + struct iovec iov = {m_xstate.data(), m_xstate.size()}; + Status ret = DoRegisterSet(PT_GETXSTATE, &iov); + assert(reinterpret_cast(m_xstate.data())->xs_rfbm & XCR0_X87); + return ret; + } } llvm_unreachable("NativeRegisterContextNetBSD_x86_64::ReadRegisterSet"); } -Status NativeRegisterContextNetBSD_x86_64::WriteRegisterSet(uint32_t set) { +Status NativeRegisterContextNetBSD_x86_64::WriteRegisterSet(RegSetKind set) { switch (set) { case GPRegSet: - return DoRegisterSet(PT_SETREGS, &m_gpr); - case FPRegSet: -#if defined(__x86_64__) - return DoRegisterSet(PT_SETFPREGS, &m_fpr); -#else - return DoRegisterSet(PT_SETXMMREGS, &m_fpr); -#endif + return DoRegisterSet(PT_SETREGS, m_gpr.data()); case DBRegSet: - return DoRegisterSet(PT_SETDBREGS, &m_dbr); - case XStateRegSet: -#ifdef HAVE_XSTATE - { - struct iovec iov = {&m_xstate, sizeof(m_xstate)}; - return DoRegisterSet(PT_SETXSTATE, &iov); - } -#else - return Status("XState is not supported by the kernel"); -#endif + return DoRegisterSet(PT_SETDBREGS, m_dbr.data()); + case FPRegSet: + case YMMRegSet: + case MPXRegSet: { + struct iovec iov = {&m_xstate, sizeof(m_xstate)}; + return DoRegisterSet(PT_SETXSTATE, &iov); + } } llvm_unreachable("NativeRegisterContextNetBSD_x86_64::WriteRegisterSet"); } @@ -495,8 +399,8 @@ NativeRegisterContextNetBSD_x86_64::ReadRegister(const RegisterInfo *reg_info, return error; } - int set = GetSetForNativeRegNum(reg); - if (set == -1) { + llvm::Optional opt_set = GetSetForNativeRegNum(reg); + if (!opt_set) { // This is likely an internal register for lldb use only and should not be // directly queried. error.SetErrorStringWithFormat("register \"%s\" is in unrecognized set", @@ -504,261 +408,40 @@ NativeRegisterContextNetBSD_x86_64::ReadRegister(const RegisterInfo *reg_info, return error; } - switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) { - case llvm::Triple::x86_64: - break; - case llvm::Triple::x86: - reg = RegNumX86ToX86_64(reg); - break; - default: - assert(false && "Unhandled target architecture."); - error.SetErrorString("Unhandled target architecture."); - return error; - } - + RegSetKind set = opt_set.getValue(); error = ReadRegisterSet(set); if (error.Fail()) return error; - switch (reg) { -#if defined(__x86_64__) - case lldb_rax_x86_64: - reg_value = (uint64_t)m_gpr.regs[_REG_RAX]; - break; - case lldb_rbx_x86_64: - reg_value = (uint64_t)m_gpr.regs[_REG_RBX]; - break; - case lldb_rcx_x86_64: - reg_value = (uint64_t)m_gpr.regs[_REG_RCX]; - break; - case lldb_rdx_x86_64: - reg_value = (uint64_t)m_gpr.regs[_REG_RDX]; - break; - case lldb_rdi_x86_64: - reg_value = (uint64_t)m_gpr.regs[_REG_RDI]; - break; - case lldb_rsi_x86_64: - reg_value = (uint64_t)m_gpr.regs[_REG_RSI]; - break; - case lldb_rbp_x86_64: - reg_value = (uint64_t)m_gpr.regs[_REG_RBP]; - break; - case lldb_rsp_x86_64: - reg_value = (uint64_t)m_gpr.regs[_REG_RSP]; - break; - case lldb_r8_x86_64: - reg_value = (uint64_t)m_gpr.regs[_REG_R8]; - break; - case lldb_r9_x86_64: - reg_value = (uint64_t)m_gpr.regs[_REG_R9]; - break; - case lldb_r10_x86_64: - reg_value = (uint64_t)m_gpr.regs[_REG_R10]; - break; - case lldb_r11_x86_64: - reg_value = (uint64_t)m_gpr.regs[_REG_R11]; - break; - case lldb_r12_x86_64: - reg_value = (uint64_t)m_gpr.regs[_REG_R12]; - break; - case lldb_r13_x86_64: - reg_value = (uint64_t)m_gpr.regs[_REG_R13]; - break; - case lldb_r14_x86_64: - reg_value = (uint64_t)m_gpr.regs[_REG_R14]; - break; - case lldb_r15_x86_64: - reg_value = (uint64_t)m_gpr.regs[_REG_R15]; - break; - case lldb_rip_x86_64: - reg_value = (uint64_t)m_gpr.regs[_REG_RIP]; - break; - case lldb_rflags_x86_64: - reg_value = (uint64_t)m_gpr.regs[_REG_RFLAGS]; - break; - case lldb_cs_x86_64: - reg_value = (uint64_t)m_gpr.regs[_REG_CS]; - break; - case lldb_fs_x86_64: - reg_value = (uint64_t)m_gpr.regs[_REG_FS]; - break; - case lldb_gs_x86_64: - reg_value = (uint64_t)m_gpr.regs[_REG_GS]; - break; - case lldb_ss_x86_64: - reg_value = (uint64_t)m_gpr.regs[_REG_SS]; - break; - case lldb_ds_x86_64: - reg_value = (uint64_t)m_gpr.regs[_REG_DS]; - break; - case lldb_es_x86_64: - reg_value = (uint64_t)m_gpr.regs[_REG_ES]; - break; -#else - case lldb_rax_x86_64: - reg_value = (uint32_t)m_gpr.r_eax; - break; - case lldb_rbx_x86_64: - reg_value = (uint32_t)m_gpr.r_ebx; - break; - case lldb_rcx_x86_64: - reg_value = (uint32_t)m_gpr.r_ecx; - break; - case lldb_rdx_x86_64: - reg_value = (uint32_t)m_gpr.r_edx; - break; - case lldb_rdi_x86_64: - reg_value = (uint32_t)m_gpr.r_edi; - break; - case lldb_rsi_x86_64: - reg_value = (uint32_t)m_gpr.r_esi; - break; - case lldb_rsp_x86_64: - reg_value = (uint32_t)m_gpr.r_esp; - break; - case lldb_rbp_x86_64: - reg_value = (uint32_t)m_gpr.r_ebp; - break; - case lldb_rip_x86_64: - reg_value = (uint32_t)m_gpr.r_eip; - break; - case lldb_rflags_x86_64: - reg_value = (uint32_t)m_gpr.r_eflags; - break; - case lldb_cs_x86_64: - reg_value = (uint32_t)m_gpr.r_cs; - break; - case lldb_fs_x86_64: - reg_value = (uint32_t)m_gpr.r_fs; - break; - case lldb_gs_x86_64: - reg_value = (uint32_t)m_gpr.r_gs; - break; - case lldb_ss_x86_64: - reg_value = (uint32_t)m_gpr.r_ss; - break; - case lldb_ds_x86_64: - reg_value = (uint32_t)m_gpr.r_ds; - break; - case lldb_es_x86_64: - reg_value = (uint32_t)m_gpr.r_es; - break; -#endif - case lldb_fctrl_x86_64: - reg_value = (uint16_t)m_fpr.fxstate.fx_cw; - break; - case lldb_fstat_x86_64: - reg_value = (uint16_t)m_fpr.fxstate.fx_sw; - break; - case lldb_ftag_x86_64: - reg_value = (uint8_t)m_fpr.fxstate.fx_tw; - break; - case lldb_fop_x86_64: - reg_value = (uint64_t)m_fpr.fxstate.fx_opcode; - break; - case lldb_fiseg_x86_64: - reg_value = (uint64_t)m_fpr.fxstate.fx_ip.fa_64; - break; - case lldb_fioff_x86_64: - reg_value = (uint32_t)m_fpr.fxstate.fx_ip.fa_32.fa_off; - break; - case lldb_foseg_x86_64: - reg_value = (uint64_t)m_fpr.fxstate.fx_dp.fa_64; - break; - case lldb_fooff_x86_64: - reg_value = (uint32_t)m_fpr.fxstate.fx_dp.fa_32.fa_off; - break; - case lldb_mxcsr_x86_64: - reg_value = (uint32_t)m_fpr.fxstate.fx_mxcsr; - break; - case lldb_mxcsrmask_x86_64: - reg_value = (uint32_t)m_fpr.fxstate.fx_mxcsr_mask; - break; - case lldb_st0_x86_64: - case lldb_st1_x86_64: - case lldb_st2_x86_64: - case lldb_st3_x86_64: - case lldb_st4_x86_64: - case lldb_st5_x86_64: - case lldb_st6_x86_64: - case lldb_st7_x86_64: - reg_value.SetBytes(&m_fpr.fxstate.fx_87_ac[reg - lldb_st0_x86_64], - reg_info->byte_size, endian::InlHostByteOrder()); - break; - case lldb_mm0_x86_64: - case lldb_mm1_x86_64: - case lldb_mm2_x86_64: - case lldb_mm3_x86_64: - case lldb_mm4_x86_64: - case lldb_mm5_x86_64: - case lldb_mm6_x86_64: - case lldb_mm7_x86_64: - reg_value.SetBytes(&m_fpr.fxstate.fx_87_ac[reg - lldb_mm0_x86_64], - reg_info->byte_size, endian::InlHostByteOrder()); - break; - case lldb_xmm0_x86_64: - case lldb_xmm1_x86_64: - case lldb_xmm2_x86_64: - case lldb_xmm3_x86_64: - case lldb_xmm4_x86_64: - case lldb_xmm5_x86_64: - case lldb_xmm6_x86_64: - case lldb_xmm7_x86_64: - case lldb_xmm8_x86_64: - case lldb_xmm9_x86_64: - case lldb_xmm10_x86_64: - case lldb_xmm11_x86_64: - case lldb_xmm12_x86_64: - case lldb_xmm13_x86_64: - case lldb_xmm14_x86_64: - case lldb_xmm15_x86_64: - reg_value.SetBytes(&m_fpr.fxstate.fx_xmm[reg - lldb_xmm0_x86_64], - reg_info->byte_size, endian::InlHostByteOrder()); + switch (set) { + case GPRegSet: + case FPRegSet: + case DBRegSet: { + void *data = GetOffsetRegSetData(set, reg_info->byte_offset); + FXSAVE *fpr = reinterpret_cast(m_xstate.data() + + offsetof(xstate, xs_fxsave)); + if (data == &fpr->ftag) // ftag + reg_value.SetUInt16( + AbridgedToFullTagWord(fpr->ftag, fpr->fstat, fpr->stmm)); + else + reg_value.SetBytes(data, reg_info->byte_size, endian::InlHostByteOrder()); break; - case lldb_ymm0_x86_64: - case lldb_ymm1_x86_64: - case lldb_ymm2_x86_64: - case lldb_ymm3_x86_64: - case lldb_ymm4_x86_64: - case lldb_ymm5_x86_64: - case lldb_ymm6_x86_64: - case lldb_ymm7_x86_64: - case lldb_ymm8_x86_64: - case lldb_ymm9_x86_64: - case lldb_ymm10_x86_64: - case lldb_ymm11_x86_64: - case lldb_ymm12_x86_64: - case lldb_ymm13_x86_64: - case lldb_ymm14_x86_64: - case lldb_ymm15_x86_64: -#ifdef HAVE_XSTATE - if (!(m_xstate.xs_rfbm & XCR0_SSE) || - !(m_xstate.xs_rfbm & XCR0_YMM_Hi128)) { - error.SetErrorStringWithFormat("register \"%s\" not supported by CPU/kernel", - reg_info->name); + } + case YMMRegSet: { + llvm::Optional ymm_reg = GetYMMSplitReg(reg); + if (!ymm_reg) { + error.SetErrorStringWithFormat( + "register \"%s\" not supported by CPU/kernel", reg_info->name); } else { - uint32_t reg_index = reg - lldb_ymm0_x86_64; - YMMReg ymm = XStateToYMM( - m_xstate.xs_fxsave.fx_xmm[reg_index].xmm_bytes, - m_xstate.xs_ymm_hi128.xs_ymm[reg_index].ymm_bytes); + YMMReg ymm = XStateToYMM(ymm_reg->xmm, ymm_reg->ymm_hi); reg_value.SetBytes(ymm.bytes, reg_info->byte_size, endian::InlHostByteOrder()); } -#else - error.SetErrorString("XState queries not supported by the kernel"); -#endif - break; - case lldb_dr0_x86_64: - case lldb_dr1_x86_64: - case lldb_dr2_x86_64: - case lldb_dr3_x86_64: - case lldb_dr4_x86_64: - case lldb_dr5_x86_64: - case lldb_dr6_x86_64: - case lldb_dr7_x86_64: - reg_value = (uint64_t)m_dbr.dr[reg - lldb_dr0_x86_64]; break; } + case MPXRegSet: + llvm_unreachable("MPX regset should have returned error"); + } return error; } @@ -783,8 +466,8 @@ Status NativeRegisterContextNetBSD_x86_64::WriteRegister( return error; } - int set = GetSetForNativeRegNum(reg); - if (set == -1) { + llvm::Optional opt_set = GetSetForNativeRegNum(reg); + if (!opt_set) { // This is likely an internal register for lldb use only and should not be // directly queried. error.SetErrorStringWithFormat("register \"%s\" is in unrecognized set", @@ -792,262 +475,54 @@ Status NativeRegisterContextNetBSD_x86_64::WriteRegister( return error; } - switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) { - case llvm::Triple::x86_64: - break; - case llvm::Triple::x86: - reg = RegNumX86ToX86_64(reg); - break; - default: - assert(false && "Unhandled target architecture."); - error.SetErrorString("Unhandled target architecture."); - return error; - } + RegSetKind set = opt_set.getValue(); + uint64_t new_xstate_bv = 0; error = ReadRegisterSet(set); if (error.Fail()) return error; - switch (reg) { -#if defined(__x86_64__) - case lldb_rax_x86_64: - m_gpr.regs[_REG_RAX] = reg_value.GetAsUInt64(); - break; - case lldb_rbx_x86_64: - m_gpr.regs[_REG_RBX] = reg_value.GetAsUInt64(); - break; - case lldb_rcx_x86_64: - m_gpr.regs[_REG_RCX] = reg_value.GetAsUInt64(); - break; - case lldb_rdx_x86_64: - m_gpr.regs[_REG_RDX] = reg_value.GetAsUInt64(); - break; - case lldb_rdi_x86_64: - m_gpr.regs[_REG_RDI] = reg_value.GetAsUInt64(); - break; - case lldb_rsi_x86_64: - m_gpr.regs[_REG_RSI] = reg_value.GetAsUInt64(); - break; - case lldb_rbp_x86_64: - m_gpr.regs[_REG_RBP] = reg_value.GetAsUInt64(); - break; - case lldb_rsp_x86_64: - m_gpr.regs[_REG_RSP] = reg_value.GetAsUInt64(); - break; - case lldb_r8_x86_64: - m_gpr.regs[_REG_R8] = reg_value.GetAsUInt64(); - break; - case lldb_r9_x86_64: - m_gpr.regs[_REG_R9] = reg_value.GetAsUInt64(); - break; - case lldb_r10_x86_64: - m_gpr.regs[_REG_R10] = reg_value.GetAsUInt64(); - break; - case lldb_r11_x86_64: - m_gpr.regs[_REG_R11] = reg_value.GetAsUInt64(); - break; - case lldb_r12_x86_64: - m_gpr.regs[_REG_R12] = reg_value.GetAsUInt64(); - break; - case lldb_r13_x86_64: - m_gpr.regs[_REG_R13] = reg_value.GetAsUInt64(); - break; - case lldb_r14_x86_64: - m_gpr.regs[_REG_R14] = reg_value.GetAsUInt64(); - break; - case lldb_r15_x86_64: - m_gpr.regs[_REG_R15] = reg_value.GetAsUInt64(); - break; - case lldb_rip_x86_64: - m_gpr.regs[_REG_RIP] = reg_value.GetAsUInt64(); - break; - case lldb_rflags_x86_64: - m_gpr.regs[_REG_RFLAGS] = reg_value.GetAsUInt64(); - break; - case lldb_cs_x86_64: - m_gpr.regs[_REG_CS] = reg_value.GetAsUInt64(); - break; - case lldb_fs_x86_64: - m_gpr.regs[_REG_FS] = reg_value.GetAsUInt64(); - break; - case lldb_gs_x86_64: - m_gpr.regs[_REG_GS] = reg_value.GetAsUInt64(); - break; - case lldb_ss_x86_64: - m_gpr.regs[_REG_SS] = reg_value.GetAsUInt64(); - break; - case lldb_ds_x86_64: - m_gpr.regs[_REG_DS] = reg_value.GetAsUInt64(); - break; - case lldb_es_x86_64: - m_gpr.regs[_REG_ES] = reg_value.GetAsUInt64(); - break; -#else - case lldb_rax_x86_64: - m_gpr.r_eax = reg_value.GetAsUInt32(); - break; - case lldb_rbx_x86_64: - m_gpr.r_ebx = reg_value.GetAsUInt32(); - break; - case lldb_rcx_x86_64: - m_gpr.r_ecx = reg_value.GetAsUInt32(); - break; - case lldb_rdx_x86_64: - m_gpr.r_edx = reg_value.GetAsUInt32(); - break; - case lldb_rdi_x86_64: - m_gpr.r_edi = reg_value.GetAsUInt32(); - break; - case lldb_rsi_x86_64: - m_gpr.r_esi = reg_value.GetAsUInt32(); - break; - case lldb_rsp_x86_64: - m_gpr.r_esp = reg_value.GetAsUInt32(); - break; - case lldb_rbp_x86_64: - m_gpr.r_ebp = reg_value.GetAsUInt32(); - break; - case lldb_rip_x86_64: - m_gpr.r_eip = reg_value.GetAsUInt32(); - break; - case lldb_rflags_x86_64: - m_gpr.r_eflags = reg_value.GetAsUInt32(); - break; - case lldb_cs_x86_64: - m_gpr.r_cs = reg_value.GetAsUInt32(); - break; - case lldb_fs_x86_64: - m_gpr.r_fs = reg_value.GetAsUInt32(); - break; - case lldb_gs_x86_64: - m_gpr.r_gs = reg_value.GetAsUInt32(); - break; - case lldb_ss_x86_64: - m_gpr.r_ss = reg_value.GetAsUInt32(); - break; - case lldb_ds_x86_64: - m_gpr.r_ds = reg_value.GetAsUInt32(); - break; - case lldb_es_x86_64: - m_gpr.r_es = reg_value.GetAsUInt32(); - break; -#endif - case lldb_fctrl_x86_64: - m_fpr.fxstate.fx_cw = reg_value.GetAsUInt16(); - break; - case lldb_fstat_x86_64: - m_fpr.fxstate.fx_sw = reg_value.GetAsUInt16(); - break; - case lldb_ftag_x86_64: - m_fpr.fxstate.fx_tw = reg_value.GetAsUInt8(); - break; - case lldb_fop_x86_64: - m_fpr.fxstate.fx_opcode = reg_value.GetAsUInt16(); - break; - case lldb_fiseg_x86_64: - m_fpr.fxstate.fx_ip.fa_64 = reg_value.GetAsUInt64(); - break; - case lldb_fioff_x86_64: - m_fpr.fxstate.fx_ip.fa_32.fa_off = reg_value.GetAsUInt32(); - break; - case lldb_foseg_x86_64: - m_fpr.fxstate.fx_dp.fa_64 = reg_value.GetAsUInt64(); - break; - case lldb_fooff_x86_64: - m_fpr.fxstate.fx_dp.fa_32.fa_off = reg_value.GetAsUInt32(); - break; - case lldb_mxcsr_x86_64: - m_fpr.fxstate.fx_mxcsr = reg_value.GetAsUInt32(); - break; - case lldb_mxcsrmask_x86_64: - m_fpr.fxstate.fx_mxcsr_mask = reg_value.GetAsUInt32(); - break; - case lldb_st0_x86_64: - case lldb_st1_x86_64: - case lldb_st2_x86_64: - case lldb_st3_x86_64: - case lldb_st4_x86_64: - case lldb_st5_x86_64: - case lldb_st6_x86_64: - case lldb_st7_x86_64: - ::memcpy(&m_fpr.fxstate.fx_87_ac[reg - lldb_st0_x86_64], - reg_value.GetBytes(), reg_value.GetByteSize()); - break; - case lldb_mm0_x86_64: - case lldb_mm1_x86_64: - case lldb_mm2_x86_64: - case lldb_mm3_x86_64: - case lldb_mm4_x86_64: - case lldb_mm5_x86_64: - case lldb_mm6_x86_64: - case lldb_mm7_x86_64: - ::memcpy(&m_fpr.fxstate.fx_87_ac[reg - lldb_mm0_x86_64], + switch (set) { + case GPRegSet: + case DBRegSet: + ::memcpy(GetOffsetRegSetData(set, reg_info->byte_offset), reg_value.GetBytes(), reg_value.GetByteSize()); break; - case lldb_xmm0_x86_64: - case lldb_xmm1_x86_64: - case lldb_xmm2_x86_64: - case lldb_xmm3_x86_64: - case lldb_xmm4_x86_64: - case lldb_xmm5_x86_64: - case lldb_xmm6_x86_64: - case lldb_xmm7_x86_64: - case lldb_xmm8_x86_64: - case lldb_xmm9_x86_64: - case lldb_xmm10_x86_64: - case lldb_xmm11_x86_64: - case lldb_xmm12_x86_64: - case lldb_xmm13_x86_64: - case lldb_xmm14_x86_64: - case lldb_xmm15_x86_64: - ::memcpy(&m_fpr.fxstate.fx_xmm[reg - lldb_xmm0_x86_64], - reg_value.GetBytes(), reg_value.GetByteSize()); + case FPRegSet: { + void *data = GetOffsetRegSetData(set, reg_info->byte_offset); + FXSAVE *fpr = reinterpret_cast(m_xstate.data() + + offsetof(xstate, xs_fxsave)); + if (data == &fpr->ftag) // ftag + fpr->ftag = FullToAbridgedTagWord(reg_value.GetAsUInt16()); + else + ::memcpy(data, reg_value.GetBytes(), reg_value.GetByteSize()); + if (data >= &fpr->xmm) + new_xstate_bv |= XCR0_SSE; + else if (data >= &fpr->mxcsr && data < &fpr->stmm) + new_xstate_bv |= XCR0_SSE; + else + new_xstate_bv |= XCR0_X87; break; - case lldb_ymm0_x86_64: - case lldb_ymm1_x86_64: - case lldb_ymm2_x86_64: - case lldb_ymm3_x86_64: - case lldb_ymm4_x86_64: - case lldb_ymm5_x86_64: - case lldb_ymm6_x86_64: - case lldb_ymm7_x86_64: - case lldb_ymm8_x86_64: - case lldb_ymm9_x86_64: - case lldb_ymm10_x86_64: - case lldb_ymm11_x86_64: - case lldb_ymm12_x86_64: - case lldb_ymm13_x86_64: - case lldb_ymm14_x86_64: - case lldb_ymm15_x86_64: -#ifdef HAVE_XSTATE - if (!(m_xstate.xs_rfbm & XCR0_SSE) || - !(m_xstate.xs_rfbm & XCR0_YMM_Hi128)) { - error.SetErrorStringWithFormat("register \"%s\" not supported by CPU/kernel", - reg_info->name); + } + case YMMRegSet: { + llvm::Optional ymm_reg = GetYMMSplitReg(reg); + if (!ymm_reg) { + error.SetErrorStringWithFormat( + "register \"%s\" not supported by CPU/kernel", reg_info->name); } else { - uint32_t reg_index = reg - lldb_ymm0_x86_64; YMMReg ymm; ::memcpy(ymm.bytes, reg_value.GetBytes(), reg_value.GetByteSize()); - YMMToXState(ymm, - m_xstate.xs_fxsave.fx_xmm[reg_index].xmm_bytes, - m_xstate.xs_ymm_hi128.xs_ymm[reg_index].ymm_bytes); + YMMToXState(ymm, ymm_reg->xmm, ymm_reg->ymm_hi); + new_xstate_bv |= XCR0_SSE | XCR0_YMM_Hi128; } -#else - error.SetErrorString("XState not supported by the kernel"); -#endif - break; - case lldb_dr0_x86_64: - case lldb_dr1_x86_64: - case lldb_dr2_x86_64: - case lldb_dr3_x86_64: - case lldb_dr4_x86_64: - case lldb_dr5_x86_64: - case lldb_dr6_x86_64: - case lldb_dr7_x86_64: - m_dbr.dr[reg - lldb_dr0_x86_64] = reg_value.GetAsUInt64(); break; } + case MPXRegSet: + llvm_unreachable("MPX regset should have returned error"); + } + if (new_xstate_bv != 0) + reinterpret_cast(m_xstate.data())->xs_xstate_bv |= new_xstate_bv; return WriteRegisterSet(set); } @@ -1061,7 +536,7 @@ Status NativeRegisterContextNetBSD_x86_64::ReadAllRegisterValues( return error; uint8_t *dst = data_sp->GetBytes(); - ::memcpy(dst, &m_gpr, GetRegisterInfoInterface().GetGPRSize()); + ::memcpy(dst, m_gpr.data(), GetRegisterInfoInterface().GetGPRSize()); dst += GetRegisterInfoInterface().GetGPRSize(); return error; @@ -1094,7 +569,7 @@ Status NativeRegisterContextNetBSD_x86_64::WriteAllRegisterValues( __FUNCTION__); return error; } - ::memcpy(&m_gpr, src, GetRegisterInfoInterface().GetGPRSize()); + ::memcpy(m_gpr.data(), src, GetRegisterInfoInterface().GetGPRSize()); error = WriteRegisterSet(GPRegSet); if (error.Fail()) @@ -1104,260 +579,66 @@ Status NativeRegisterContextNetBSD_x86_64::WriteAllRegisterValues( return error; } -int NativeRegisterContextNetBSD_x86_64::GetDR(int num) const { - assert(num >= 0 && num <= 7); - switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) { - case llvm::Triple::x86: - return lldb_dr0_i386 + num; - case llvm::Triple::x86_64: - return lldb_dr0_x86_64 + num; - default: - return -1; - } -} - -Status NativeRegisterContextNetBSD_x86_64::IsWatchpointHit(uint32_t wp_index, - bool &is_hit) { - if (wp_index >= NumSupportedHardwareWatchpoints()) - return Status("Watchpoint index out of range"); - - RegisterValue reg_value; - const RegisterInfo *const reg_info = GetRegisterInfoAtIndex(GetDR(6)); - Status error = ReadRegister(reg_info, reg_value); - if (error.Fail()) { - is_hit = false; - return error; - } - - uint64_t status_bits = reg_value.GetAsUInt64(); - - is_hit = status_bits & (1 << wp_index); - - return error; -} - -Status NativeRegisterContextNetBSD_x86_64::GetWatchpointHitIndex( - uint32_t &wp_index, lldb::addr_t trap_addr) { - uint32_t num_hw_wps = NumSupportedHardwareWatchpoints(); - for (wp_index = 0; wp_index < num_hw_wps; ++wp_index) { - bool is_hit; - Status error = IsWatchpointHit(wp_index, is_hit); - if (error.Fail()) { - wp_index = LLDB_INVALID_INDEX32; - return error; - } else if (is_hit) { - return error; - } - } - wp_index = LLDB_INVALID_INDEX32; - return Status(); -} - -Status NativeRegisterContextNetBSD_x86_64::IsWatchpointVacant(uint32_t wp_index, - bool &is_vacant) { - if (wp_index >= NumSupportedHardwareWatchpoints()) - return Status("Watchpoint index out of range"); +llvm::Error NativeRegisterContextNetBSD_x86_64::CopyHardwareWatchpointsFrom( + NativeRegisterContextNetBSD &source) { + auto &r_source = static_cast(source); + // NB: This implicitly reads the whole dbreg set. + RegisterValue dr7; + Status res = r_source.ReadRegister(GetDR(7), dr7); + if (!res.Fail()) { + // copy dbregs only if any watchpoints were set + if ((dr7.GetAsUInt64() & 0xFF) == 0) + return llvm::Error::success(); - RegisterValue reg_value; - const RegisterInfo *const reg_info = GetRegisterInfoAtIndex(GetDR(7)); - Status error = ReadRegister(reg_info, reg_value); - if (error.Fail()) { - is_vacant = false; - return error; + m_dbr = r_source.m_dbr; + res = WriteRegisterSet(DBRegSet); } - - uint64_t control_bits = reg_value.GetAsUInt64(); - - is_vacant = !(control_bits & (1 << (2 * wp_index + 1))); - - return error; + return res.ToError(); } -Status NativeRegisterContextNetBSD_x86_64::SetHardwareWatchpointWithIndex( - lldb::addr_t addr, size_t size, uint32_t watch_flags, uint32_t wp_index) { - - if (wp_index >= NumSupportedHardwareWatchpoints()) - return Status("Watchpoint index out of range"); - - // Read only watchpoints aren't supported on x86_64. Fall back to read/write - // waitchpoints instead. - // TODO: Add logic to detect when a write happens and ignore that watchpoint - // hit. - if (watch_flags == 0x2) - watch_flags = 0x3; - - if (watch_flags != 0x1 && watch_flags != 0x3) - return Status("Invalid read/write bits for watchpoint"); - - if (size != 1 && size != 2 && size != 4 && size != 8) - return Status("Invalid size for watchpoint"); - - bool is_vacant; - Status error = IsWatchpointVacant(wp_index, is_vacant); - if (error.Fail()) - return error; - if (!is_vacant) - return Status("Watchpoint index not vacant"); - - const RegisterInfo *const reg_info_dr7 = GetRegisterInfoAtIndex(GetDR(7)); - RegisterValue dr7_value; - error = ReadRegister(reg_info_dr7, dr7_value); - if (error.Fail()) - return error; - - // for watchpoints 0, 1, 2, or 3, respectively, set bits 1, 3, 5, or 7 - uint64_t enable_bit = 1 << (2 * wp_index + 1); - - // set bits 16-17, 20-21, 24-25, or 28-29 - // with 0b01 for write, and 0b11 for read/write - uint64_t rw_bits = watch_flags << (16 + 4 * wp_index); - - // set bits 18-19, 22-23, 26-27, or 30-31 - // with 0b00, 0b01, 0b10, or 0b11 - // for 1, 2, 8 (if supported), or 4 bytes, respectively - uint64_t size_bits = (size == 8 ? 0x2 : size - 1) << (18 + 4 * wp_index); - - uint64_t bit_mask = (0x3 << (2 * wp_index)) | (0xF << (16 + 4 * wp_index)); - - uint64_t control_bits = dr7_value.GetAsUInt64() & ~bit_mask; - - control_bits |= enable_bit | rw_bits | size_bits; - - const RegisterInfo *const reg_info_drN = - GetRegisterInfoAtIndex(GetDR(wp_index)); - RegisterValue drN_value; - error = ReadRegister(reg_info_drN, drN_value); - if (error.Fail()) - return error; - - // clear dr6 if address or bits changed (i.e. we're not reenabling the same - // watchpoint) - if (drN_value.GetAsUInt64() != addr || - (dr7_value.GetAsUInt64() & bit_mask) != (rw_bits | size_bits)) { - ClearWatchpointHit(wp_index); - - error = WriteRegister(reg_info_drN, RegisterValue(addr)); - if (error.Fail()) - return error; +uint8_t * +NativeRegisterContextNetBSD_x86_64::GetOffsetRegSetData(RegSetKind set, + size_t reg_offset) { + uint8_t *base; + switch (set) { + case GPRegSet: + base = m_gpr.data(); + break; + case FPRegSet: + base = m_xstate.data() + offsetof(xstate, xs_fxsave); + break; + case DBRegSet: + base = m_dbr.data(); + break; + case YMMRegSet: + llvm_unreachable("GetRegSetData() is unsuitable for this regset."); + case MPXRegSet: + llvm_unreachable("MPX regset should have returned error"); } - - error = WriteRegister(reg_info_dr7, RegisterValue(control_bits)); - if (error.Fail()) - return error; - - error.Clear(); - return error; -} - -bool NativeRegisterContextNetBSD_x86_64::ClearHardwareWatchpoint( - uint32_t wp_index) { - if (wp_index >= NumSupportedHardwareWatchpoints()) - return false; - - // for watchpoints 0, 1, 2, or 3, respectively, clear bits 0-1, 2-3, 4-5 - // or 6-7 of the debug control register (DR7) - const RegisterInfo *const reg_info_dr7 = GetRegisterInfoAtIndex(GetDR(7)); - RegisterValue reg_value; - Status error = ReadRegister(reg_info_dr7, reg_value); - if (error.Fail()) - return false; - uint64_t bit_mask = 0x3 << (2 * wp_index); - uint64_t control_bits = reg_value.GetAsUInt64() & ~bit_mask; - - return WriteRegister(reg_info_dr7, RegisterValue(control_bits)).Success(); + assert(reg_offset >= m_regset_offsets[set]); + return base + (reg_offset - m_regset_offsets[set]); } -Status NativeRegisterContextNetBSD_x86_64::ClearWatchpointHit(uint32_t wp_index) { - if (wp_index >= NumSupportedHardwareWatchpoints()) - return Status("Watchpoint index out of range"); +llvm::Optional +NativeRegisterContextNetBSD_x86_64::GetYMMSplitReg(uint32_t reg) { + auto xst = reinterpret_cast(m_xstate.data()); + if (!(xst->xs_rfbm & XCR0_SSE) || !(xst->xs_rfbm & XCR0_YMM_Hi128)) + return llvm::None; - // for watchpoints 0, 1, 2, or 3, respectively, check bits 0, 1, 2, or 3 of - // the debug status register (DR6) - const RegisterInfo *const reg_info_dr6 = GetRegisterInfoAtIndex(GetDR(6)); - RegisterValue reg_value; - Status error = ReadRegister(reg_info_dr6, reg_value); - if (error.Fail()) - return error; - - uint64_t bit_mask = 1 << wp_index; - uint64_t status_bits = reg_value.GetAsUInt64() & ~bit_mask; - return WriteRegister(reg_info_dr6, RegisterValue(status_bits)); -} - -Status NativeRegisterContextNetBSD_x86_64::ClearAllHardwareWatchpoints() { - RegisterValue reg_value; - - // clear bits {0-4} of the debug status register (DR6) - const RegisterInfo *const reg_info_dr6 = GetRegisterInfoAtIndex(GetDR(6)); - Status error = ReadRegister(reg_info_dr6, reg_value); - if (error.Fail()) - return error; - uint64_t bit_mask = 0xF; - uint64_t status_bits = reg_value.GetAsUInt64() & ~bit_mask; - error = WriteRegister(reg_info_dr6, RegisterValue(status_bits)); - if (error.Fail()) - return error; - - // clear bits {0-7,16-31} of the debug control register (DR7) - const RegisterInfo *const reg_info_dr7 = GetRegisterInfoAtIndex(GetDR(7)); - error = ReadRegister(reg_info_dr7, reg_value); - if (error.Fail()) - return error; - bit_mask = 0xFF | (0xFFFF << 16); - uint64_t control_bits = reg_value.GetAsUInt64() & ~bit_mask; - return WriteRegister(reg_info_dr7, RegisterValue(control_bits)); -} - -uint32_t NativeRegisterContextNetBSD_x86_64::SetHardwareWatchpoint( - lldb::addr_t addr, size_t size, uint32_t watch_flags) { - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS)); - const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints(); - for (uint32_t wp_index = 0; wp_index < num_hw_watchpoints; ++wp_index) { - bool is_vacant; - Status error = IsWatchpointVacant(wp_index, is_vacant); - if (is_vacant) { - error = SetHardwareWatchpointWithIndex(addr, size, watch_flags, wp_index); - if (error.Success()) - return wp_index; - } - if (error.Fail() && log) { - LLDB_LOGF(log, "NativeRegisterContextNetBSD_x86_64::%s Error: %s", - __FUNCTION__, error.AsCString()); - } + uint32_t reg_index; + switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) { + case llvm::Triple::x86: + reg_index = reg - lldb_ymm0_i386; + break; + case llvm::Triple::x86_64: + reg_index = reg - lldb_ymm0_x86_64; + break; + default: + llvm_unreachable("Unhandled target architecture."); } - return LLDB_INVALID_INDEX32; -} - -lldb::addr_t -NativeRegisterContextNetBSD_x86_64::GetWatchpointAddress(uint32_t wp_index) { - if (wp_index >= NumSupportedHardwareWatchpoints()) - return LLDB_INVALID_ADDRESS; - RegisterValue reg_value; - const RegisterInfo *const reg_info_drN = - GetRegisterInfoAtIndex(GetDR(wp_index)); - if (ReadRegister(reg_info_drN, reg_value).Fail()) - return LLDB_INVALID_ADDRESS; - return reg_value.GetAsUInt64(); -} -uint32_t NativeRegisterContextNetBSD_x86_64::NumSupportedHardwareWatchpoints() { - // Available debug address registers: dr0, dr1, dr2, dr3 - return 4; -} - -Status NativeRegisterContextNetBSD_x86_64::CopyHardwareWatchpointsFrom( - NativeRegisterContextNetBSD &source) { - auto &r_source = static_cast(source); - Status res = r_source.ReadRegisterSet(DBRegSet); - if (!res.Fail()) { - // copy dbregs only if any watchpoints were set - if ((r_source.m_dbr.dr[7] & 0xFF) == 0) - return res; - - m_dbr = r_source.m_dbr; - res = WriteRegisterSet(DBRegSet); - } - return res; + return YMMSplitPtr{&xst->xs_fxsave.fx_xmm[reg_index], + &xst->xs_ymm_hi128.xs_ymm[reg_index]}; } #endif // defined(__x86_64__) diff --git a/gnu/llvm/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.h b/gnu/llvm/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.h index 6c0632f3bce..31005952dd7 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.h +++ b/gnu/llvm/lldb/source/Plugins/Process/NetBSD/NativeRegisterContextNetBSD_x86_64.h @@ -18,20 +18,21 @@ #include // clang-format on +#include + #include "Plugins/Process/NetBSD/NativeRegisterContextNetBSD.h" #include "Plugins/Process/Utility/RegisterContext_x86.h" +#include "Plugins/Process/Utility/NativeRegisterContextDBReg_x86.h" #include "Plugins/Process/Utility/lldb-x86-register-enums.h" -#if defined(PT_GETXSTATE) && defined(PT_SETXSTATE) -#define HAVE_XSTATE -#endif - namespace lldb_private { namespace process_netbsd { class NativeProcessNetBSD; -class NativeRegisterContextNetBSD_x86_64 : public NativeRegisterContextNetBSD { +class NativeRegisterContextNetBSD_x86_64 + : public NativeRegisterContextNetBSD, + public NativeRegisterContextDBReg_x86 { public: NativeRegisterContextNetBSD_x86_64(const ArchSpec &target_arch, NativeThreadProtocol &native_thread); @@ -49,54 +50,39 @@ public: Status WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override; - Status IsWatchpointHit(uint32_t wp_index, bool &is_hit) override; - - Status GetWatchpointHitIndex(uint32_t &wp_index, - lldb::addr_t trap_addr) override; - - Status IsWatchpointVacant(uint32_t wp_index, bool &is_vacant) override; - - bool ClearHardwareWatchpoint(uint32_t wp_index) override; - - Status ClearWatchpointHit(uint32_t wp_index) override; - - Status ClearAllHardwareWatchpoints() override; - - Status SetHardwareWatchpointWithIndex(lldb::addr_t addr, size_t size, - uint32_t watch_flags, - uint32_t wp_index); - - uint32_t SetHardwareWatchpoint(lldb::addr_t addr, size_t size, - uint32_t watch_flags) override; - - lldb::addr_t GetWatchpointAddress(uint32_t wp_index) override; - - uint32_t NumSupportedHardwareWatchpoints() override; - - Status + llvm::Error CopyHardwareWatchpointsFrom(NativeRegisterContextNetBSD &source) override; private: // Private member types. - enum { GPRegSet, FPRegSet, XStateRegSet, DBRegSet }; + enum RegSetKind { + GPRegSet, + FPRegSet, + DBRegSet, + MaxRegularRegSet = DBRegSet, + YMMRegSet, + MPXRegSet, + MaxRegSet = MPXRegSet, + }; // Private member variables. - struct reg m_gpr; -#if defined(__x86_64__) - struct fpreg m_fpr; -#else - struct xmmregs m_fpr; -#endif - struct dbreg m_dbr; -#ifdef HAVE_XSTATE - struct xstate m_xstate; -#endif - - int GetSetForNativeRegNum(int reg_num) const; - int GetDR(int num) const; - - Status ReadRegisterSet(uint32_t set); - Status WriteRegisterSet(uint32_t set); + std::array m_gpr; + std::array m_xstate; + std::array m_dbr; + std::array m_regset_offsets; + + llvm::Optional GetSetForNativeRegNum(uint32_t reg_num) const; + + Status ReadRegisterSet(RegSetKind set); + Status WriteRegisterSet(RegSetKind set); + + uint8_t *GetOffsetRegSetData(RegSetKind set, size_t reg_offset); + + struct YMMSplitPtr { + void *xmm; + void *ymm_hi; + }; + llvm::Optional GetYMMSplitReg(uint32_t reg); }; } // namespace process_netbsd diff --git a/gnu/llvm/lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.cpp b/gnu/llvm/lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.cpp index fe76fb40e0b..400b89a5fdd 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.cpp +++ b/gnu/llvm/lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.cpp @@ -116,8 +116,6 @@ void NativeThreadNetBSD::SetStoppedByExec() { } void NativeThreadNetBSD::SetStoppedByWatchpoint(uint32_t wp_index) { - SetStopped(); - lldbassert(wp_index != LLDB_INVALID_INDEX32 && "wp_index cannot be invalid"); std::ostringstream ostr; @@ -126,12 +124,36 @@ void NativeThreadNetBSD::SetStoppedByWatchpoint(uint32_t wp_index) { ostr << " " << GetRegisterContext().GetWatchpointHitAddress(wp_index); + SetStopped(); m_stop_description = ostr.str(); - m_stop_info.reason = StopReason::eStopReasonWatchpoint; m_stop_info.details.signal.signo = SIGTRAP; } +void NativeThreadNetBSD::SetStoppedByFork(lldb::pid_t child_pid, + lldb::tid_t child_tid) { + SetStopped(); + + m_stop_info.reason = StopReason::eStopReasonFork; + m_stop_info.details.fork.child_pid = child_pid; + m_stop_info.details.fork.child_tid = child_tid; +} + +void NativeThreadNetBSD::SetStoppedByVFork(lldb::pid_t child_pid, + lldb::tid_t child_tid) { + SetStopped(); + + m_stop_info.reason = StopReason::eStopReasonVFork; + m_stop_info.details.fork.child_pid = child_pid; + m_stop_info.details.fork.child_tid = child_tid; +} + +void NativeThreadNetBSD::SetStoppedByVForkDone() { + SetStopped(); + + m_stop_info.reason = StopReason::eStopReasonVForkDone; +} + void NativeThreadNetBSD::SetStoppedWithNoReason() { SetStopped(); @@ -204,7 +226,6 @@ lldb::StateType NativeThreadNetBSD::GetState() { return m_state; } bool NativeThreadNetBSD::GetStopReason(ThreadStopInfo &stop_info, std::string &description) { Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD)); - description.clear(); switch (m_state) { @@ -239,14 +260,14 @@ NativeRegisterContextNetBSD &NativeThreadNetBSD::GetRegisterContext() { Status NativeThreadNetBSD::SetWatchpoint(lldb::addr_t addr, size_t size, uint32_t watch_flags, bool hardware) { + assert(m_state == eStateStopped); if (!hardware) return Status("not implemented"); - if (m_state == eStateLaunching) - return Status(); Status error = RemoveWatchpoint(addr); if (error.Fail()) return error; - uint32_t wp_index = GetRegisterContext().SetHardwareWatchpoint(addr, size, watch_flags); + uint32_t wp_index = + GetRegisterContext().SetHardwareWatchpoint(addr, size, watch_flags); if (wp_index == LLDB_INVALID_INDEX32) return Status("Setting hardware watchpoint failed."); m_watchpoint_index_map.insert({addr, wp_index}); @@ -266,9 +287,7 @@ Status NativeThreadNetBSD::RemoveWatchpoint(lldb::addr_t addr) { Status NativeThreadNetBSD::SetHardwareBreakpoint(lldb::addr_t addr, size_t size) { - if (m_state == eStateLaunching) - return Status(); - + assert(m_state == eStateStopped); Status error = RemoveHardwareBreakpoint(addr); if (error.Fail()) return error; @@ -296,10 +315,11 @@ Status NativeThreadNetBSD::RemoveHardwareBreakpoint(lldb::addr_t addr) { return Status("Clearing hardware breakpoint failed."); } -Status NativeThreadNetBSD::CopyWatchpointsFrom(NativeThreadNetBSD &source) { - Status s = GetRegisterContext().CopyHardwareWatchpointsFrom( +llvm::Error +NativeThreadNetBSD::CopyWatchpointsFrom(NativeThreadNetBSD &source) { + llvm::Error s = GetRegisterContext().CopyHardwareWatchpointsFrom( source.GetRegisterContext()); - if (!s.Fail()) { + if (!s) { m_watchpoint_index_map = source.m_watchpoint_index_map; m_hw_break_index_map = source.m_hw_break_index_map; } diff --git a/gnu/llvm/lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.h b/gnu/llvm/lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.h index 89b61ef8672..ee9305337fd 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.h +++ b/gnu/llvm/lldb/source/Plugins/Process/NetBSD/NativeThreadNetBSD.h @@ -59,12 +59,15 @@ private: void SetStoppedByTrace(); void SetStoppedByExec(); void SetStoppedByWatchpoint(uint32_t wp_index); + void SetStoppedByFork(lldb::pid_t child_pid, lldb::tid_t child_tid); + void SetStoppedByVFork(lldb::pid_t child_pid, lldb::tid_t child_tid); + void SetStoppedByVForkDone(); void SetStoppedWithNoReason(); void SetStopped(); void SetRunning(); void SetStepping(); - Status CopyWatchpointsFrom(NativeThreadNetBSD& source); + llvm::Error CopyWatchpointsFrom(NativeThreadNetBSD& source); // Member Variables lldb::StateType m_state; diff --git a/gnu/llvm/lldb/source/Plugins/Process/POSIX/CrashReason.cpp b/gnu/llvm/lldb/source/Plugins/Process/POSIX/CrashReason.cpp index 579077b45bf..c6ede61cfe1 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/POSIX/CrashReason.cpp +++ b/gnu/llvm/lldb/source/Plugins/Process/POSIX/CrashReason.cpp @@ -58,6 +58,18 @@ CrashReason GetCrashReasonForSIGSEGV(const siginfo_t &info) { #endif case SEGV_BNDERR: return CrashReason::eBoundViolation; +#ifdef __linux__ +#ifndef SEGV_MTEAERR +#define SEGV_MTEAERR 8 +#endif + case SEGV_MTEAERR: + return CrashReason::eAsyncTagCheckFault; +#ifndef SEGV_MTESERR +#define SEGV_MTESERR 9 +#endif + case SEGV_MTESERR: + return CrashReason::eSyncTagCheckFault; +#endif // __linux__ } return CrashReason::eInvalidCrashReason; @@ -166,6 +178,13 @@ std::string GetCrashReasonString(CrashReason reason, lldb::addr_t fault_addr) { case CrashReason::eBoundViolation: str = "signal SIGSEGV: bound violation"; break; + case CrashReason::eAsyncTagCheckFault: + str = "signal SIGSEGV: async tag check fault"; + break; + case CrashReason::eSyncTagCheckFault: + str = "signal SIGSEGV: sync tag check fault"; + AppendFaultAddr(str, fault_addr); + break; case CrashReason::eIllegalOpcode: str = "signal SIGILL: illegal instruction"; break; @@ -246,6 +265,12 @@ const char *CrashReasonAsString(CrashReason reason) { case CrashReason::eBoundViolation: str = "eBoundViolation"; break; + case CrashReason::eAsyncTagCheckFault: + str = "eAsyncTagCheckFault"; + break; + case CrashReason::eSyncTagCheckFault: + str = "eSyncTagCheckFault"; + break; // SIGILL crash reasons. case CrashReason::eIllegalOpcode: diff --git a/gnu/llvm/lldb/source/Plugins/Process/POSIX/CrashReason.h b/gnu/llvm/lldb/source/Plugins/Process/POSIX/CrashReason.h index 9b4784a1e68..24acdc08e90 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/POSIX/CrashReason.h +++ b/gnu/llvm/lldb/source/Plugins/Process/POSIX/CrashReason.h @@ -11,7 +11,7 @@ #include "lldb/lldb-types.h" -#include +#include #include @@ -22,6 +22,8 @@ enum class CrashReason { eInvalidAddress, ePrivilegedAddress, eBoundViolation, + eAsyncTagCheckFault, + eSyncTagCheckFault, // SIGILL crash reasons. eIllegalOpcode, diff --git a/gnu/llvm/lldb/source/Plugins/Process/POSIX/NativeProcessELF.h b/gnu/llvm/lldb/source/Plugins/Process/POSIX/NativeProcessELF.h index dcfa9290ff5..c01409940da 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/POSIX/NativeProcessELF.h +++ b/gnu/llvm/lldb/source/Plugins/Process/POSIX/NativeProcessELF.h @@ -21,6 +21,9 @@ namespace lldb_private { class NativeProcessELF : public NativeProcessProtocol { using NativeProcessProtocol::NativeProcessProtocol; +public: + llvm::Optional GetAuxValue(enum AuxVector::EntryType type); + protected: template struct ELFLinkMap { T l_addr; @@ -30,8 +33,6 @@ protected: T l_prev; }; - llvm::Optional GetAuxValue(enum AuxVector::EntryType type); - lldb::addr_t GetSharedLibraryInfoAddress() override; template diff --git a/gnu/llvm/lldb/source/Plugins/Process/Utility/AuxVector.cpp b/gnu/llvm/lldb/source/Plugins/Process/Utility/AuxVector.cpp index 685d9d0824f..c4f45f759a3 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/Utility/AuxVector.cpp +++ b/gnu/llvm/lldb/source/Plugins/Process/Utility/AuxVector.cpp @@ -82,6 +82,7 @@ const char *AuxVector::GetEntryName(EntryType type) const { case ENTRY_NAME(AUXV_AT_SECURE); break; 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_EXECFN); break; case ENTRY_NAME(AUXV_AT_SYSINFO); break; case ENTRY_NAME(AUXV_AT_SYSINFO_EHDR); break; diff --git a/gnu/llvm/lldb/source/Plugins/Process/Utility/AuxVector.h b/gnu/llvm/lldb/source/Plugins/Process/Utility/AuxVector.h index c8c8b124941..07a0010e198 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/Utility/AuxVector.h +++ b/gnu/llvm/lldb/source/Plugins/Process/Utility/AuxVector.h @@ -50,6 +50,7 @@ public: AUXV_AT_SECURE = 23, ///< Boolean, was exec setuid-like? 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_EXECFN = 31, ///< Filename of executable. AUXV_AT_SYSINFO = 32, ///< Pointer to the global system page used for system /// calls and other nice things. diff --git a/gnu/llvm/lldb/source/Plugins/Process/Utility/DynamicRegisterInfo.cpp b/gnu/llvm/lldb/source/Plugins/Process/Utility/DynamicRegisterInfo.cpp index 443638aa39f..a85d7bd6f52 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/Utility/DynamicRegisterInfo.cpp +++ b/gnu/llvm/lldb/source/Plugins/Process/Utility/DynamicRegisterInfo.cpp @@ -151,10 +151,8 @@ DynamicRegisterInfo::SetRegisterInfo(const StructuredData::Dictionary &dict, const uint32_t msbyte = msbit / 8; const uint32_t lsbyte = lsbit / 8; - ConstString containing_reg_name(reg_name_str); - const RegisterInfo *containing_reg_info = - GetRegisterInfo(containing_reg_name); + GetRegisterInfo(reg_name_str); if (containing_reg_info) { const uint32_t max_bit = containing_reg_info->byte_size * 8; if (msbit < max_bit && lsbit < max_bit) { @@ -189,7 +187,7 @@ DynamicRegisterInfo::SetRegisterInfo(const StructuredData::Dictionary &dict, } } else { printf("error: invalid concrete register \"%s\"\n", - containing_reg_name.GetCString()); + reg_name_str.c_str()); } } else { printf("error: msbit (%u) must be greater than lsbit (%u)\n", @@ -217,7 +215,7 @@ DynamicRegisterInfo::SetRegisterInfo(const StructuredData::Dictionary &dict, if (composite_reg_list->GetItemAtIndexAsString( composite_idx, composite_reg_name, nullptr)) { const RegisterInfo *composite_reg_info = - GetRegisterInfo(composite_reg_name); + GetRegisterInfo(composite_reg_name.GetStringRef()); if (composite_reg_info) { composite_offset = std::min(composite_offset, composite_reg_info->byte_offset); @@ -357,7 +355,7 @@ DynamicRegisterInfo::SetRegisterInfo(const StructuredData::Dictionary &dict, if (invalidate_reg_list->GetItemAtIndexAsString( idx, invalidate_reg_name)) { const RegisterInfo *invalidate_reg_info = - GetRegisterInfo(invalidate_reg_name); + GetRegisterInfo(invalidate_reg_name.GetStringRef()); if (invalidate_reg_info) { m_invalidate_regs_map[i].push_back( invalidate_reg_info->kinds[eRegisterKindLLDB]); @@ -430,9 +428,6 @@ void DynamicRegisterInfo::AddRegister(RegisterInfo ®_info, assert(set < m_set_reg_nums.size()); assert(set < m_set_names.size()); m_set_reg_nums[set].push_back(reg_num); - size_t end_reg_offset = reg_info.byte_offset + reg_info.byte_size; - if (m_reg_data_byte_size < end_reg_offset) - m_reg_data_byte_size = end_reg_offset; } void DynamicRegisterInfo::Finalize(const ArchSpec &arch) { @@ -617,8 +612,70 @@ void DynamicRegisterInfo::Finalize(const ArchSpec &arch) { break; } } + + // At this stage call ConfigureOffsets to calculate register offsets for + // targets supporting dynamic offset calculation. It also calculates + // total byte size of register data. + ConfigureOffsets(); + + // Check if register info is reconfigurable + // AArch64 SVE register set has configurable register sizes + if (arch.GetTriple().isAArch64()) { + for (const auto ® : m_regs) { + if (strcmp(reg.name, "vg") == 0) { + m_is_reconfigurable = true; + break; + } + } + } +} + +void DynamicRegisterInfo::ConfigureOffsets() { + // We are going to create a map between remote (eRegisterKindProcessPlugin) + // and local (eRegisterKindLLDB) register numbers. This map will give us + // remote register numbers in increasing order for offset calculation. + std::map remote_to_local_regnum_map; + for (const auto ® : m_regs) + remote_to_local_regnum_map[reg.kinds[eRegisterKindProcessPlugin]] = + reg.kinds[eRegisterKindLLDB]; + + // At this stage we manually calculate g/G packet offsets of all primary + // registers, only if target XML or qRegisterInfo packet did not send + // an offset explicitly. + uint32_t reg_offset = 0; + for (auto const ®num_pair : remote_to_local_regnum_map) { + if (m_regs[regnum_pair.second].byte_offset == LLDB_INVALID_INDEX32 && + m_regs[regnum_pair.second].value_regs == nullptr) { + m_regs[regnum_pair.second].byte_offset = reg_offset; + + reg_offset = m_regs[regnum_pair.second].byte_offset + + m_regs[regnum_pair.second].byte_size; + } + } + + // Now update all value_regs with each register info as needed + for (auto ® : m_regs) { + if (reg.value_regs != nullptr) { + // Assign a valid offset to all pseudo registers if not assigned by stub. + // Pseudo registers with value_regs list populated will share same offset + // as that of their corresponding primary register in value_regs list. + if (reg.byte_offset == LLDB_INVALID_INDEX32) { + uint32_t value_regnum = reg.value_regs[0]; + if (value_regnum != LLDB_INVALID_INDEX32) + reg.byte_offset = + GetRegisterInfoAtIndex(remote_to_local_regnum_map[value_regnum]) + ->byte_offset; + } + } + + reg_offset = reg.byte_offset + reg.byte_size; + if (m_reg_data_byte_size < reg_offset) + m_reg_data_byte_size = reg_offset; + } } +bool DynamicRegisterInfo::IsReconfigurable() { return m_is_reconfigurable; } + size_t DynamicRegisterInfo::GetNumRegisters() const { return m_regs.size(); } size_t DynamicRegisterInfo::GetNumRegisterSets() const { return m_sets.size(); } @@ -640,6 +697,14 @@ RegisterInfo *DynamicRegisterInfo::GetRegisterInfoAtIndex(uint32_t i) { return nullptr; } +const RegisterInfo *DynamicRegisterInfo::GetRegisterInfo(uint32_t kind, + uint32_t num) const { + uint32_t reg_index = ConvertRegisterKindToRegisterNumber(kind, num); + if (reg_index != LLDB_INVALID_REGNUM) + return &m_regs[reg_index]; + return nullptr; +} + const RegisterSet *DynamicRegisterInfo::GetRegisterSet(uint32_t i) const { if (i < m_sets.size()) return &m_sets[i]; @@ -737,16 +802,10 @@ void DynamicRegisterInfo::Dump() const { } } -const lldb_private::RegisterInfo *DynamicRegisterInfo::GetRegisterInfo( - lldb_private::ConstString reg_name) const { - for (auto ®_info : m_regs) { - // We can use pointer comparison since we used a ConstString to set the - // "name" member in AddRegister() - assert(ConstString(reg_info.name).GetCString() == reg_info.name && - "reg_info.name not from a ConstString?"); - if (reg_info.name == reg_name.GetCString()) { +const lldb_private::RegisterInfo * +DynamicRegisterInfo::GetRegisterInfo(llvm::StringRef reg_name) const { + for (auto ®_info : m_regs) + if (reg_info.name == reg_name) return ®_info; - } - } return nullptr; } diff --git a/gnu/llvm/lldb/source/Plugins/Process/Utility/DynamicRegisterInfo.h b/gnu/llvm/lldb/source/Plugins/Process/Utility/DynamicRegisterInfo.h index 48939375a50..7e90454c6d9 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/Utility/DynamicRegisterInfo.h +++ b/gnu/llvm/lldb/source/Plugins/Process/Utility/DynamicRegisterInfo.h @@ -17,6 +17,10 @@ #include "lldb/lldb-private.h" class DynamicRegisterInfo { +protected: + DynamicRegisterInfo(DynamicRegisterInfo &) = default; + DynamicRegisterInfo &operator=(DynamicRegisterInfo &) = default; + public: DynamicRegisterInfo() = default; @@ -25,9 +29,6 @@ public: virtual ~DynamicRegisterInfo() = default; - DynamicRegisterInfo(DynamicRegisterInfo &) = delete; - void operator=(DynamicRegisterInfo &) = delete; - DynamicRegisterInfo(DynamicRegisterInfo &&info); DynamicRegisterInfo &operator=(DynamicRegisterInfo &&info); @@ -59,10 +60,18 @@ public: uint32_t ConvertRegisterKindToRegisterNumber(uint32_t kind, uint32_t num) const; + const lldb_private::RegisterInfo *GetRegisterInfo(uint32_t kind, + uint32_t num) const; + void Dump() const; void Clear(); + bool IsReconfigurable(); + + const lldb_private::RegisterInfo * + GetRegisterInfo(llvm::StringRef reg_name) const; + protected: // Classes that inherit from DynamicRegisterInfo can see and modify these typedef std::vector reg_collection; @@ -74,11 +83,10 @@ protected: typedef std::vector dwarf_opcode; typedef std::map dynamic_reg_size_map; - const lldb_private::RegisterInfo * - GetRegisterInfo(lldb_private::ConstString reg_name) const; - void MoveFrom(DynamicRegisterInfo &&info); + void ConfigureOffsets(); + reg_collection m_regs; set_collection m_sets; set_reg_num_collection m_set_reg_nums; @@ -89,5 +97,6 @@ protected: size_t m_reg_data_byte_size = 0u; // The number of bytes required to store // all registers bool m_finalized = false; + bool m_is_reconfigurable = false; }; #endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_DYNAMICREGISTERINFO_H diff --git a/gnu/llvm/lldb/source/Plugins/Process/Utility/HistoryUnwind.cpp b/gnu/llvm/lldb/source/Plugins/Process/Utility/HistoryUnwind.cpp index 9b9522955de..7749dc6f5d5 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/Utility/HistoryUnwind.cpp +++ b/gnu/llvm/lldb/source/Plugins/Process/Utility/HistoryUnwind.cpp @@ -30,7 +30,7 @@ HistoryUnwind::HistoryUnwind(Thread &thread, std::vector pcs, // Destructor -HistoryUnwind::~HistoryUnwind() {} +HistoryUnwind::~HistoryUnwind() = default; void HistoryUnwind::DoClear() { std::lock_guard guard(m_unwind_mutex); diff --git a/gnu/llvm/lldb/source/Plugins/Process/Utility/LinuxPTraceDefines_arm64sve.h b/gnu/llvm/lldb/source/Plugins/Process/Utility/LinuxPTraceDefines_arm64sve.h new file mode 100644 index 00000000000..817dca336de --- /dev/null +++ b/gnu/llvm/lldb/source/Plugins/Process/Utility/LinuxPTraceDefines_arm64sve.h @@ -0,0 +1,291 @@ +//===-- LinuxPTraceDefines_arm64sve.h ------------------------- -*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_LINUXPTRACEDEFINES_ARM64SVE_H +#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_LINUXPTRACEDEFINES_ARM64SVE_H + +#include + +namespace lldb_private { +namespace sve { + +/* + * The SVE architecture leaves space for future expansion of the + * vector length beyond its initial architectural limit of 2048 bits + * (16 quadwords). + * + * See /Documentation/arm64/sve.rst for a description + * of the vl/vq terminology. + */ + +const uint16_t vq_bytes = 16; /* number of bytes per quadword */ + +const uint16_t vq_min = 1; +const uint16_t vq_max = 512; + +const uint16_t vl_min = vq_min * vq_bytes; +const uint16_t vl_max = vq_max * vq_bytes; + +const uint16_t num_of_zregs = 32; +const uint16_t num_of_pregs = 16; + +inline uint16_t vl_valid(uint16_t vl) { + return (vl % vq_bytes == 0 && vl >= vl_min && vl <= vl_max); +} + +inline uint16_t vq_from_vl(uint16_t vl) { return vl / vq_bytes; } +inline uint16_t vl_from_vq(uint16_t vq) { return vq * vq_bytes; } + +/* A new signal frame record sve_context encodes the SVE Registers on signal + * delivery. sve_context struct definition may be included in asm/sigcontext.h. + * We define sve_context_size which will be used by LLDB sve helper functions. + * More information on sve_context can be found in Linux kernel source tree at + * Documentation/arm64/sve.rst. + */ + +const uint16_t sve_context_size = 16; + +/* + * If the SVE registers are currently live for the thread at signal delivery, + * sve_context.head.size >= + * SigContextSize(vq_from_vl(sve_context.vl)) + * and the register data may be accessed using the Sig*() functions. + * + * If sve_context.head.size < + * SigContextSize(vq_from_vl(sve_context.vl)), + * the SVE registers were not live for the thread and no register data + * is included: in this case, the Sig*() functions should not be + * used except for this check. + * + * The same convention applies when returning from a signal: a caller + * will need to remove or resize the sve_context block if it wants to + * make the SVE registers live when they were previously non-live or + * vice-versa. This may require the caller to allocate fresh + * memory and/or move other context blocks in the signal frame. + * + * Changing the vector length during signal return is not permitted: + * sve_context.vl must equal the thread's current vector length when + * doing a sigreturn. + * + * + * Note: for all these functions, the "vq" argument denotes the SVE + * vector length in quadwords (i.e., units of 128 bits). + * + * The correct way to obtain vq is to use vq_from_vl(vl). The + * result is valid if and only if vl_valid(vl) is true. This is + * guaranteed for a struct sve_context written by the kernel. + * + * + * Additional functions describe the contents and layout of the payload. + * For each, Sig*Offset(args) is the start offset relative to + * the start of struct sve_context, and Sig*Size(args) is the + * size in bytes: + * + * x type description + * - ---- ----------- + * REGS the entire SVE context + * + * ZREGS __uint128_t[num_of_zregs][vq] all Z-registers + * ZREG __uint128_t[vq] individual Z-register Zn + * + * PREGS uint16_t[num_of_pregs][vq] all P-registers + * PREG uint16_t[vq] individual P-register Pn + * + * FFR uint16_t[vq] first-fault status register + * + * Additional data might be appended in the future. + */ + +inline uint16_t SigZRegSize(uint16_t vq) { return vq * vq_bytes; } +inline uint16_t SigPRegSize(uint16_t vq) { return vq * vq_bytes / 8; } +inline uint16_t SigFFRSize(uint16_t vq) { return SigPRegSize(vq); } + +inline uint32_t SigRegsOffset() { + return (sve_context_size + vq_bytes - 1) / vq_bytes * vq_bytes; +} + +inline uint32_t SigZRegsOffset() { return SigRegsOffset(); } + +inline uint32_t SigZRegOffset(uint16_t vq, uint16_t n) { + return SigRegsOffset() + SigZRegSize(vq) * n; +} + +inline uint32_t SigZRegsSize(uint16_t vq) { + return SigZRegOffset(vq, num_of_zregs) - SigRegsOffset(); +} + +inline uint32_t SigPRegsOffset(uint16_t vq) { + return SigRegsOffset() + SigZRegsSize(vq); +} + +inline uint32_t SigPRegOffset(uint16_t vq, uint16_t n) { + return SigPRegsOffset(vq) + SigPRegSize(vq) * n; +} + +inline uint32_t SigpRegsSize(uint16_t vq) { + return SigPRegOffset(vq, num_of_pregs) - SigPRegsOffset(vq); +} + +inline uint32_t SigFFROffset(uint16_t vq) { + return SigPRegsOffset(vq) + SigpRegsSize(vq); +} + +inline uint32_t SigRegsSize(uint16_t vq) { + return SigFFROffset(vq) + SigFFRSize(vq) - SigRegsOffset(); +} + +inline uint32_t SVESigContextSize(uint16_t vq) { + return SigRegsOffset() + SigRegsSize(vq); +} + +struct user_sve_header { + uint32_t size; /* total meaningful regset content in bytes */ + uint32_t max_size; /* maxmium possible size for this thread */ + uint16_t vl; /* current vector length */ + uint16_t max_vl; /* maximum possible vector length */ + uint16_t flags; + uint16_t reserved; +}; + +/* Definitions for user_sve_header.flags: */ +const uint16_t ptrace_regs_mask = 1 << 0; +const uint16_t ptrace_regs_fpsimd = 0; +const uint16_t ptrace_regs_sve = ptrace_regs_mask; + +/* + * The remainder of the SVE state follows struct user_sve_header. The + * total size of the SVE state (including header) depends on the + * metadata in the header: PTraceSize(vq, flags) gives the total size + * of the state in bytes, including the header. + * + * Refer to for details of how to pass the correct + * "vq" argument to these macros. + */ + +/* Offset from the start of struct user_sve_header to the register data */ +inline uint16_t PTraceRegsOffset() { + return (sizeof(struct user_sve_header) + vq_bytes - 1) / vq_bytes * vq_bytes; +} + +/* + * The register data content and layout depends on the value of the + * flags field. + */ + +/* + * (flags & ptrace_regs_mask) == ptrace_regs_fpsimd case: + * + * The payload starts at offset PTraceFPSIMDOffset, and is of type + * struct user_fpsimd_state. Additional data might be appended in the + * future: use PTraceFPSIMDSize(vq, flags) to compute the total size. + * PTraceFPSIMDSize(vq, flags) will never be less than + * sizeof(struct user_fpsimd_state). + */ + +const uint32_t ptrace_fpsimd_offset = PTraceRegsOffset(); + +/* Return size of struct user_fpsimd_state from asm/ptrace.h */ +inline uint32_t PTraceFPSIMDSize(uint16_t vq, uint16_t flags) { return 528; } + +/* + * (flags & ptrace_regs_mask) == ptrace_regs_sve case: + * + * The payload starts at offset PTraceSVEOffset, and is of size + * PTraceSVESize(vq, flags). + * + * Additional functions describe the contents and layout of the payload. + * For each, PTrace*X*Offset(args) is the start offset relative to + * the start of struct user_sve_header, and PTrace*X*Size(args) is + * the size in bytes: + * + * x type description + * - ---- ----------- + * ZREGS \ + * ZREG | + * PREGS | refer to + * PREG | + * FFR / + * + * FPSR uint32_t FPSR + * FPCR uint32_t FPCR + * + * Additional data might be appended in the future. + */ + +inline uint32_t PTraceZRegSize(uint16_t vq) { return SigZRegSize(vq); } + +inline uint32_t PTracePRegSize(uint16_t vq) { return SigPRegSize(vq); } + +inline uint32_t PTraceFFRSize(uint16_t vq) { return SigFFRSize(vq); } + +const uint32_t fpsr_size = sizeof(uint32_t); +const uint32_t fpcr_size = sizeof(uint32_t); + +inline uint32_t SigToPTrace(uint32_t offset) { + return offset - SigRegsOffset() + PTraceRegsOffset(); +} + +const uint32_t ptrace_sve_offset = PTraceRegsOffset(); + +inline uint32_t PTraceZRegsOffset(uint16_t vq) { + return SigToPTrace(SigZRegsOffset()); +} + +inline uint32_t PTraceZRegOffset(uint16_t vq, uint16_t n) { + return SigToPTrace(SigZRegOffset(vq, n)); +} + +inline uint32_t PTraceZRegsSize(uint16_t vq) { + return PTraceZRegOffset(vq, num_of_zregs) - SigToPTrace(SigRegsOffset()); +} + +inline uint32_t PTracePRegsOffset(uint16_t vq) { + return SigToPTrace(SigPRegsOffset(vq)); +} + +inline uint32_t PTracePRegOffset(uint16_t vq, uint16_t n) { + return SigToPTrace(SigPRegOffset(vq, n)); +} + +inline uint32_t PTracePRegsSize(uint16_t vq) { + return PTracePRegOffset(vq, num_of_pregs) - PTracePRegsOffset(vq); +} + +inline uint32_t PTraceFFROffset(uint16_t vq) { + return SigToPTrace(SigFFROffset(vq)); +} + +inline uint32_t PTraceFPSROffset(uint16_t vq) { + return (PTraceFFROffset(vq) + PTraceFFRSize(vq) + (vq_bytes - 1)) / vq_bytes * + vq_bytes; +} + +inline uint32_t PTraceFPCROffset(uint16_t vq) { + return PTraceFPSROffset(vq) + fpsr_size; +} + +/* + * Any future extension appended after FPCR must be aligned to the next + * 128-bit boundary. + */ + +inline uint32_t PTraceSVESize(uint16_t vq, uint16_t flags) { + return (PTraceFPCROffset(vq) + fpcr_size - ptrace_sve_offset + vq_bytes - 1) / + vq_bytes * vq_bytes; +} + +inline uint32_t PTraceSize(uint16_t vq, uint16_t flags) { + return (flags & ptrace_regs_mask) == ptrace_regs_sve + ? ptrace_sve_offset + PTraceSVESize(vq, flags) + : ptrace_fpsimd_offset + PTraceFPSIMDSize(vq, flags); +} + +} // namespace SVE +} // namespace lldb_private + +#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_LINUXPTRACEDEFINES_ARM64SVE_H diff --git a/gnu/llvm/lldb/source/Plugins/Process/Utility/LinuxProcMaps.cpp b/gnu/llvm/lldb/source/Plugins/Process/Utility/LinuxProcMaps.cpp index 0c7d9ddc5ac..947b970edf6 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/Utility/LinuxProcMaps.cpp +++ b/gnu/llvm/lldb/source/Plugins/Process/Utility/LinuxProcMaps.cpp @@ -7,80 +7,93 @@ //===----------------------------------------------------------------------===// #include "LinuxProcMaps.h" -#include "llvm/ADT/StringRef.h" #include "lldb/Target/MemoryRegionInfo.h" #include "lldb/Utility/Status.h" #include "lldb/Utility/StringExtractor.h" +#include "llvm/ADT/StringRef.h" using namespace lldb_private; -static Status +enum class MapsKind { Maps, SMaps }; + +static llvm::Expected ProcMapError(const char *msg, + MapsKind kind) { + return llvm::createStringError(llvm::inconvertibleErrorCode(), msg, + kind == MapsKind::Maps ? "maps" : "smaps"); +} + +static llvm::Expected ParseMemoryRegionInfoFromProcMapsLine(llvm::StringRef maps_line, - MemoryRegionInfo &memory_region_info) { - memory_region_info.Clear(); - + MapsKind maps_kind) { + MemoryRegionInfo region; StringExtractor line_extractor(maps_line); - + // Format: {address_start_hex}-{address_end_hex} perms offset dev inode // pathname perms: rwxp (letter is present if set, '-' if not, final // character is p=private, s=shared). - + // Parse out the starting address lldb::addr_t start_address = line_extractor.GetHexMaxU64(false, 0); - + // Parse out hyphen separating start and end address from range. if (!line_extractor.GetBytesLeft() || (line_extractor.GetChar() != '-')) - return Status( - "malformed /proc/{pid}/maps entry, missing dash between address range"); - + return ProcMapError( + "malformed /proc/{pid}/%s entry, missing dash between address range", + maps_kind); + // Parse out the ending address lldb::addr_t end_address = line_extractor.GetHexMaxU64(false, start_address); - + // Parse out the space after the address. if (!line_extractor.GetBytesLeft() || (line_extractor.GetChar() != ' ')) - return Status( - "malformed /proc/{pid}/maps entry, missing space after range"); - + return ProcMapError( + "malformed /proc/{pid}/%s entry, missing space after range", maps_kind); + // Save the range. - memory_region_info.GetRange().SetRangeBase(start_address); - memory_region_info.GetRange().SetRangeEnd(end_address); - - // Any memory region in /proc/{pid}/maps is by definition mapped into the - // process. - memory_region_info.SetMapped(MemoryRegionInfo::OptionalBool::eYes); - + region.GetRange().SetRangeBase(start_address); + region.GetRange().SetRangeEnd(end_address); + + // Any memory region in /proc/{pid}/(maps|smaps) is by definition mapped + // into the process. + region.SetMapped(MemoryRegionInfo::OptionalBool::eYes); + // Parse out each permission entry. if (line_extractor.GetBytesLeft() < 4) - return Status("malformed /proc/{pid}/maps entry, missing some portion of " - "permissions"); - + return ProcMapError( + "malformed /proc/{pid}/%s entry, missing some portion of " + "permissions", + maps_kind); + // Handle read permission. const char read_perm_char = line_extractor.GetChar(); if (read_perm_char == 'r') - memory_region_info.SetReadable(MemoryRegionInfo::OptionalBool::eYes); + region.SetReadable(MemoryRegionInfo::OptionalBool::eYes); else if (read_perm_char == '-') - memory_region_info.SetReadable(MemoryRegionInfo::OptionalBool::eNo); + region.SetReadable(MemoryRegionInfo::OptionalBool::eNo); else - return Status("unexpected /proc/{pid}/maps read permission char"); - + return ProcMapError("unexpected /proc/{pid}/%s read permission char", + maps_kind); + // Handle write permission. const char write_perm_char = line_extractor.GetChar(); if (write_perm_char == 'w') - memory_region_info.SetWritable(MemoryRegionInfo::OptionalBool::eYes); + region.SetWritable(MemoryRegionInfo::OptionalBool::eYes); else if (write_perm_char == '-') - memory_region_info.SetWritable(MemoryRegionInfo::OptionalBool::eNo); + region.SetWritable(MemoryRegionInfo::OptionalBool::eNo); else - return Status("unexpected /proc/{pid}/maps write permission char"); - + return ProcMapError("unexpected /proc/{pid}/%s write permission char", + maps_kind); + // Handle execute permission. const char exec_perm_char = line_extractor.GetChar(); if (exec_perm_char == 'x') - memory_region_info.SetExecutable(MemoryRegionInfo::OptionalBool::eYes); + region.SetExecutable(MemoryRegionInfo::OptionalBool::eYes); else if (exec_perm_char == '-') - memory_region_info.SetExecutable(MemoryRegionInfo::OptionalBool::eNo); + region.SetExecutable(MemoryRegionInfo::OptionalBool::eNo); else - return Status("unexpected /proc/{pid}/maps exec permission char"); - + return ProcMapError("unexpected /proc/{pid}/%s exec permission char", + maps_kind); + line_extractor.GetChar(); // Read the private bit line_extractor.SkipSpaces(); // Skip the separator line_extractor.GetHexMaxU64(false, 0); // Read the offset @@ -89,13 +102,13 @@ ParseMemoryRegionInfoFromProcMapsLine(llvm::StringRef maps_line, line_extractor.GetHexMaxU64(false, 0); // Read the major device number line_extractor.SkipSpaces(); // Skip the separator line_extractor.GetU64(0, 10); // Read the inode number - + line_extractor.SkipSpaces(); const char *name = line_extractor.Peek(); if (name) - memory_region_info.SetName(name); - - return Status(); + region.SetName(name); + + return region; } void lldb_private::ParseLinuxMapRegions(llvm::StringRef linux_map, @@ -104,9 +117,80 @@ void lldb_private::ParseLinuxMapRegions(llvm::StringRef linux_map, llvm::StringRef line; while (!lines.empty()) { std::tie(line, lines) = lines.split('\n'); - MemoryRegionInfo region; - Status error = ParseMemoryRegionInfoFromProcMapsLine(line, region); - if (!callback(region, error)) + if (!callback(ParseMemoryRegionInfoFromProcMapsLine(line, MapsKind::Maps))) break; } } + +void lldb_private::ParseLinuxSMapRegions(llvm::StringRef linux_smap, + LinuxMapCallback const &callback) { + // Entries in /smaps look like: + // 00400000-0048a000 r-xp 00000000 fd:03 960637 + // Size: 552 kB + // Rss: 460 kB + // <...> + // VmFlags: rd ex mr mw me dw + // 00500000-0058a000 rwxp 00000000 fd:03 960637 + // <...> + // + // Where the first line is identical to the /maps format + // and VmFlags is only printed for kernels >= 3.8. + + llvm::StringRef lines(linux_smap); + llvm::StringRef line; + llvm::Optional region; + + while (lines.size()) { + std::tie(line, lines) = lines.split('\n'); + + // A property line looks like: + // : + // (no spaces on the left hand side) + // A header will have a ':' but the LHS will contain spaces + llvm::StringRef name; + llvm::StringRef value; + std::tie(name, value) = line.split(':'); + + // If this line is a property line + if (!name.contains(' ')) { + if (region) { + if (name == "VmFlags") { + if (value.contains("mt")) + region->SetMemoryTagged(MemoryRegionInfo::eYes); + else + region->SetMemoryTagged(MemoryRegionInfo::eNo); + } + // Ignore anything else + } else { + // Orphaned settings line + callback(ProcMapError( + "Found a property line without a corresponding mapping " + "in /proc/{pid}/%s", + MapsKind::SMaps)); + return; + } + } else { + // Must be a new region header + if (region) { + // Save current region + callback(*region); + region.reset(); + } + + // Try to start a new region + llvm::Expected new_region = + ParseMemoryRegionInfoFromProcMapsLine(line, MapsKind::SMaps); + if (new_region) { + region = *new_region; + } else { + // Stop at first invalid region header + callback(new_region.takeError()); + return; + } + } + } + + // Catch last region + if (region) + callback(*region); +} diff --git a/gnu/llvm/lldb/source/Plugins/Process/Utility/LinuxProcMaps.h b/gnu/llvm/lldb/source/Plugins/Process/Utility/LinuxProcMaps.h index 363f248fd41..02f78d55c29 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/Utility/LinuxProcMaps.h +++ b/gnu/llvm/lldb/source/Plugins/Process/Utility/LinuxProcMaps.h @@ -11,16 +11,16 @@ #include "lldb/lldb-forward.h" #include "llvm/ADT/StringRef.h" -#include - +#include "llvm/Support/Error.h" namespace lldb_private { -typedef std::function LinuxMapCallback; +typedef std::function)> LinuxMapCallback; void ParseLinuxMapRegions(llvm::StringRef linux_map, LinuxMapCallback const &callback); +void ParseLinuxSMapRegions(llvm::StringRef linux_smap, + LinuxMapCallback const &callback); } // namespace lldb_private diff --git a/gnu/llvm/lldb/source/Plugins/Process/Utility/LinuxSignals.cpp b/gnu/llvm/lldb/source/Plugins/Process/Utility/LinuxSignals.cpp index 4dd619e3bad..d4b0f4039da 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/Utility/LinuxSignals.cpp +++ b/gnu/llvm/lldb/source/Plugins/Process/Utility/LinuxSignals.cpp @@ -14,79 +14,72 @@ LinuxSignals::LinuxSignals() : UnixSignals() { Reset(); } void LinuxSignals::Reset() { m_signals.clear(); - // SIGNO NAME SUPPRESS STOP NOTIFY DESCRIPTION ALIAS - // ===== =========== ======== ===== ====== - // ====================================== ====== - AddSignal(1, "SIGHUP", false, true, true, "hangup"); - AddSignal(2, "SIGINT", true, true, true, "interrupt"); - AddSignal(3, "SIGQUIT", false, true, true, "quit"); - AddSignal(4, "SIGILL", false, true, true, "illegal instruction"); - AddSignal(5, "SIGTRAP", true, true, true, - "trace trap (not reset when caught)"); - AddSignal(6, "SIGABRT", false, true, true, "abort()/IOT trap", "SIGIOT"); - AddSignal(7, "SIGBUS", false, true, true, "bus error"); - AddSignal(8, "SIGFPE", false, true, true, "floating point exception"); - AddSignal(9, "SIGKILL", false, true, true, "kill"); - AddSignal(10, "SIGUSR1", false, true, true, "user defined signal 1"); - AddSignal(11, "SIGSEGV", false, true, true, "segmentation violation"); - AddSignal(12, "SIGUSR2", false, true, true, "user defined signal 2"); - AddSignal(13, "SIGPIPE", false, true, true, - "write to pipe with reading end closed"); - AddSignal(14, "SIGALRM", false, false, false, "alarm"); - AddSignal(15, "SIGTERM", false, true, true, "termination requested"); - AddSignal(16, "SIGSTKFLT", false, true, true, "stack fault"); - AddSignal(17, "SIGCHLD", false, false, true, "child status has changed", - "SIGCLD"); - AddSignal(18, "SIGCONT", false, true, true, "process continue"); - AddSignal(19, "SIGSTOP", true, true, true, "process stop"); - AddSignal(20, "SIGTSTP", false, true, true, "tty stop"); - AddSignal(21, "SIGTTIN", false, true, true, "background tty read"); - AddSignal(22, "SIGTTOU", false, true, true, "background tty write"); - AddSignal(23, "SIGURG", false, true, true, "urgent data on socket"); - AddSignal(24, "SIGXCPU", false, true, true, "CPU resource exceeded"); - AddSignal(25, "SIGXFSZ", false, true, true, "file size limit exceeded"); - AddSignal(26, "SIGVTALRM", false, true, true, "virtual time alarm"); - AddSignal(27, "SIGPROF", false, false, false, "profiling time alarm"); - AddSignal(28, "SIGWINCH", false, true, true, "window size changes"); - AddSignal(29, "SIGIO", false, true, true, "input/output ready/Pollable event", - "SIGPOLL"); - AddSignal(30, "SIGPWR", false, true, true, "power failure"); - AddSignal(31, "SIGSYS", false, true, true, "invalid system call"); - AddSignal(32, "SIG32", false, false, false, - "threading library internal signal 1"); - AddSignal(33, "SIG33", false, false, false, - "threading library internal signal 2"); - AddSignal(34, "SIGRTMIN", false, false, false, "real time signal 0"); - AddSignal(35, "SIGRTMIN+1", false, false, false, "real time signal 1"); - AddSignal(36, "SIGRTMIN+2", false, false, false, "real time signal 2"); - AddSignal(37, "SIGRTMIN+3", false, false, false, "real time signal 3"); - AddSignal(38, "SIGRTMIN+4", false, false, false, "real time signal 4"); - AddSignal(39, "SIGRTMIN+5", false, false, false, "real time signal 5"); - AddSignal(40, "SIGRTMIN+6", false, false, false, "real time signal 6"); - AddSignal(41, "SIGRTMIN+7", false, false, false, "real time signal 7"); - AddSignal(42, "SIGRTMIN+8", false, false, false, "real time signal 8"); - AddSignal(43, "SIGRTMIN+9", false, false, false, "real time signal 9"); - AddSignal(44, "SIGRTMIN+10", false, false, false, "real time signal 10"); - AddSignal(45, "SIGRTMIN+11", false, false, false, "real time signal 11"); - AddSignal(46, "SIGRTMIN+12", false, false, false, "real time signal 12"); - AddSignal(47, "SIGRTMIN+13", false, false, false, "real time signal 13"); - AddSignal(48, "SIGRTMIN+14", false, false, false, "real time signal 14"); - AddSignal(49, "SIGRTMIN+15", false, false, false, "real time signal 15"); - AddSignal(50, "SIGRTMAX-14", false, false, false, - "real time signal 16"); // switching to SIGRTMAX-xxx to match "kill - // -l" output - AddSignal(51, "SIGRTMAX-13", false, false, false, "real time signal 17"); - AddSignal(52, "SIGRTMAX-12", false, false, false, "real time signal 18"); - AddSignal(53, "SIGRTMAX-11", false, false, false, "real time signal 19"); - AddSignal(54, "SIGRTMAX-10", false, false, false, "real time signal 20"); - AddSignal(55, "SIGRTMAX-9", false, false, false, "real time signal 21"); - AddSignal(56, "SIGRTMAX-8", false, false, false, "real time signal 22"); - AddSignal(57, "SIGRTMAX-7", false, false, false, "real time signal 23"); - AddSignal(58, "SIGRTMAX-6", false, false, false, "real time signal 24"); - AddSignal(59, "SIGRTMAX-5", false, false, false, "real time signal 25"); - AddSignal(60, "SIGRTMAX-4", false, false, false, "real time signal 26"); - AddSignal(61, "SIGRTMAX-3", false, false, false, "real time signal 27"); - AddSignal(62, "SIGRTMAX-2", false, false, false, "real time signal 28"); - AddSignal(63, "SIGRTMAX-1", false, false, false, "real time signal 29"); - AddSignal(64, "SIGRTMAX", false, false, false, "real time signal 30"); + // clang-format off + // SIGNO NAME SUPPRESS STOP NOTIFY DESCRIPTION + // ====== ============== ======== ====== ====== =================================================== + AddSignal(1, "SIGHUP", false, true, true, "hangup"); + AddSignal(2, "SIGINT", true, true, true, "interrupt"); + AddSignal(3, "SIGQUIT", false, true, true, "quit"); + AddSignal(4, "SIGILL", false, true, true, "illegal instruction"); + AddSignal(5, "SIGTRAP", true, true, true, "trace trap (not reset when caught)"); + AddSignal(6, "SIGABRT", false, true, true, "abort()/IOT trap", "SIGIOT"); + AddSignal(7, "SIGBUS", false, true, true, "bus error"); + AddSignal(8, "SIGFPE", false, true, true, "floating point exception"); + AddSignal(9, "SIGKILL", false, true, true, "kill"); + AddSignal(10, "SIGUSR1", false, true, true, "user defined signal 1"); + AddSignal(11, "SIGSEGV", false, true, true, "segmentation violation"); + AddSignal(12, "SIGUSR2", false, true, true, "user defined signal 2"); + AddSignal(13, "SIGPIPE", false, true, true, "write to pipe with reading end closed"); + AddSignal(14, "SIGALRM", false, false, false, "alarm"); + AddSignal(15, "SIGTERM", false, true, true, "termination requested"); + AddSignal(16, "SIGSTKFLT", false, true, true, "stack fault"); + AddSignal(17, "SIGCHLD", false, false, true, "child status has changed", "SIGCLD"); + AddSignal(18, "SIGCONT", false, false, true, "process continue"); + AddSignal(19, "SIGSTOP", true, true, true, "process stop"); + AddSignal(20, "SIGTSTP", false, true, true, "tty stop"); + AddSignal(21, "SIGTTIN", false, true, true, "background tty read"); + AddSignal(22, "SIGTTOU", false, true, true, "background tty write"); + AddSignal(23, "SIGURG", false, true, true, "urgent data on socket"); + AddSignal(24, "SIGXCPU", false, true, true, "CPU resource exceeded"); + AddSignal(25, "SIGXFSZ", false, true, true, "file size limit exceeded"); + AddSignal(26, "SIGVTALRM", false, true, true, "virtual time alarm"); + AddSignal(27, "SIGPROF", false, false, false, "profiling time alarm"); + AddSignal(28, "SIGWINCH", false, true, true, "window size changes"); + AddSignal(29, "SIGIO", false, true, true, "input/output ready/Pollable event", "SIGPOLL"); + AddSignal(30, "SIGPWR", false, true, true, "power failure"); + AddSignal(31, "SIGSYS", false, true, true, "invalid system call"); + AddSignal(32, "SIG32", false, false, false, "threading library internal signal 1"); + AddSignal(33, "SIG33", false, false, false, "threading library internal signal 2"); + AddSignal(34, "SIGRTMIN", false, false, false, "real time signal 0"); + AddSignal(35, "SIGRTMIN+1", false, false, false, "real time signal 1"); + AddSignal(36, "SIGRTMIN+2", false, false, false, "real time signal 2"); + AddSignal(37, "SIGRTMIN+3", false, false, false, "real time signal 3"); + AddSignal(38, "SIGRTMIN+4", false, false, false, "real time signal 4"); + AddSignal(39, "SIGRTMIN+5", false, false, false, "real time signal 5"); + AddSignal(40, "SIGRTMIN+6", false, false, false, "real time signal 6"); + AddSignal(41, "SIGRTMIN+7", false, false, false, "real time signal 7"); + AddSignal(42, "SIGRTMIN+8", false, false, false, "real time signal 8"); + AddSignal(43, "SIGRTMIN+9", false, false, false, "real time signal 9"); + AddSignal(44, "SIGRTMIN+10", false, false, false, "real time signal 10"); + AddSignal(45, "SIGRTMIN+11", false, false, false, "real time signal 11"); + AddSignal(46, "SIGRTMIN+12", false, false, false, "real time signal 12"); + AddSignal(47, "SIGRTMIN+13", false, false, false, "real time signal 13"); + AddSignal(48, "SIGRTMIN+14", false, false, false, "real time signal 14"); + AddSignal(49, "SIGRTMIN+15", false, false, false, "real time signal 15"); + AddSignal(50, "SIGRTMAX-14", false, false, false, "real time signal 16"); // switching to SIGRTMAX-xxx to match "kill -l" output + AddSignal(51, "SIGRTMAX-13", false, false, false, "real time signal 17"); + AddSignal(52, "SIGRTMAX-12", false, false, false, "real time signal 18"); + AddSignal(53, "SIGRTMAX-11", false, false, false, "real time signal 19"); + AddSignal(54, "SIGRTMAX-10", false, false, false, "real time signal 20"); + AddSignal(55, "SIGRTMAX-9", false, false, false, "real time signal 21"); + AddSignal(56, "SIGRTMAX-8", false, false, false, "real time signal 22"); + AddSignal(57, "SIGRTMAX-7", false, false, false, "real time signal 23"); + AddSignal(58, "SIGRTMAX-6", false, false, false, "real time signal 24"); + AddSignal(59, "SIGRTMAX-5", false, false, false, "real time signal 25"); + AddSignal(60, "SIGRTMAX-4", false, false, false, "real time signal 26"); + AddSignal(61, "SIGRTMAX-3", false, false, false, "real time signal 27"); + AddSignal(62, "SIGRTMAX-2", false, false, false, "real time signal 28"); + AddSignal(63, "SIGRTMAX-1", false, false, false, "real time signal 29"); + AddSignal(64, "SIGRTMAX", false, false, false, "real time signal 30"); + // clang-format on } diff --git a/gnu/llvm/lldb/source/Plugins/Process/Utility/MemoryTagManagerAArch64MTE.cpp b/gnu/llvm/lldb/source/Plugins/Process/Utility/MemoryTagManagerAArch64MTE.cpp new file mode 100644 index 00000000000..d74b66b58af --- /dev/null +++ b/gnu/llvm/lldb/source/Plugins/Process/Utility/MemoryTagManagerAArch64MTE.cpp @@ -0,0 +1,200 @@ +//===-- MemoryTagManagerAArch64MTE.cpp --------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#include "MemoryTagManagerAArch64MTE.h" + +using namespace lldb_private; + +static const unsigned MTE_START_BIT = 56; +static const unsigned MTE_TAG_MAX = 0xf; +static const unsigned MTE_GRANULE_SIZE = 16; + +lldb::addr_t +MemoryTagManagerAArch64MTE::GetLogicalTag(lldb::addr_t addr) const { + return (addr >> MTE_START_BIT) & MTE_TAG_MAX; +} + +lldb::addr_t +MemoryTagManagerAArch64MTE::RemoveNonAddressBits(lldb::addr_t addr) const { + // Here we're ignoring the whole top byte. If you've got MTE + // you must also have TBI (top byte ignore). + // The other 4 bits could contain other extension bits or + // user metadata. + return addr & ~((lldb::addr_t)0xFF << MTE_START_BIT); +} + +ptrdiff_t MemoryTagManagerAArch64MTE::AddressDiff(lldb::addr_t addr1, + lldb::addr_t addr2) const { + return RemoveNonAddressBits(addr1) - RemoveNonAddressBits(addr2); +} + +lldb::addr_t MemoryTagManagerAArch64MTE::GetGranuleSize() const { + return MTE_GRANULE_SIZE; +} + +int32_t MemoryTagManagerAArch64MTE::GetAllocationTagType() const { + return eMTE_allocation; +} + +size_t MemoryTagManagerAArch64MTE::GetTagSizeInBytes() const { return 1; } + +MemoryTagManagerAArch64MTE::TagRange +MemoryTagManagerAArch64MTE::ExpandToGranule(TagRange range) const { + // Ignore reading a length of 0 + if (!range.IsValid()) + return range; + + const size_t granule = GetGranuleSize(); + + // Align start down to granule start + lldb::addr_t new_start = range.GetRangeBase(); + lldb::addr_t align_down_amount = new_start % granule; + new_start -= align_down_amount; + + // Account for the distance we moved the start above + size_t new_len = range.GetByteSize() + align_down_amount; + // Then align up to the end of the granule + size_t align_up_amount = granule - (new_len % granule); + if (align_up_amount != granule) + new_len += align_up_amount; + + return TagRange(new_start, new_len); +} + +llvm::Expected +MemoryTagManagerAArch64MTE::MakeTaggedRange( + lldb::addr_t addr, lldb::addr_t end_addr, + const lldb_private::MemoryRegionInfos &memory_regions) const { + // First check that the range is not inverted. + // We must remove tags here otherwise an address with a higher + // tag value will always be > the other. + ptrdiff_t len = AddressDiff(end_addr, addr); + if (len <= 0) { + return llvm::createStringError( + llvm::inconvertibleErrorCode(), + "End address (0x%" PRIx64 + ") must be greater than the start address (0x%" PRIx64 ")", + end_addr, addr); + } + + // Region addresses will not have memory tags. So when searching + // we must use an untagged address. + MemoryRegionInfo::RangeType tag_range(RemoveNonAddressBits(addr), len); + tag_range = ExpandToGranule(tag_range); + + // Make a copy so we can use the original for errors and the final return. + MemoryRegionInfo::RangeType remaining_range(tag_range); + + // While there are parts of the range that don't have a matching tagged memory + // region + while (remaining_range.IsValid()) { + // Search for a region that contains the start of the range + MemoryRegionInfos::const_iterator region = std::find_if( + memory_regions.cbegin(), memory_regions.cend(), + [&remaining_range](const MemoryRegionInfo ®ion) { + return region.GetRange().Contains(remaining_range.GetRangeBase()); + }); + + if (region == memory_regions.cend() || + region->GetMemoryTagged() != MemoryRegionInfo::eYes) { + // Some part of this range is untagged (or unmapped) so error + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "Address range 0x%" PRIx64 ":0x%" PRIx64 + " is not in a memory tagged region", + tag_range.GetRangeBase(), + tag_range.GetRangeEnd()); + } + + // We've found some part of the range so remove that part and continue + // searching for the rest. Moving the base "slides" the range so we need to + // save/restore the original end. If old_end is less than the new base, the + // range will be set to have 0 size and we'll exit the while. + lldb::addr_t old_end = remaining_range.GetRangeEnd(); + remaining_range.SetRangeBase(region->GetRange().GetRangeEnd()); + remaining_range.SetRangeEnd(old_end); + } + + // Every part of the range is contained within a tagged memory region. + return tag_range; +} + +llvm::Expected> +MemoryTagManagerAArch64MTE::UnpackTagsData(const std::vector &tags, + size_t granules /*=0*/) const { + // 0 means don't check the number of tags before unpacking + if (granules) { + size_t num_tags = tags.size() / GetTagSizeInBytes(); + if (num_tags != granules) { + return llvm::createStringError( + llvm::inconvertibleErrorCode(), + "Packed tag data size does not match expected number of tags. " + "Expected %zu tag(s) for %zu granule(s), got %zu tag(s).", + granules, granules, num_tags); + } + } + + // (if bytes per tag was not 1, we would reconstruct them here) + + std::vector unpacked; + unpacked.reserve(tags.size()); + for (auto it = tags.begin(); it != tags.end(); ++it) { + // Check all tags are in range + if (*it > MTE_TAG_MAX) { + return llvm::createStringError( + llvm::inconvertibleErrorCode(), + "Found tag 0x%x which is > max MTE tag value of 0x%x.", *it, + MTE_TAG_MAX); + } + unpacked.push_back(*it); + } + + return unpacked; +} + +llvm::Expected> MemoryTagManagerAArch64MTE::PackTags( + const std::vector &tags) const { + std::vector packed; + packed.reserve(tags.size() * GetTagSizeInBytes()); + + for (auto tag : tags) { + if (tag > MTE_TAG_MAX) { + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "Found tag 0x%" PRIx64 + " which is > max MTE tag value of 0x%x.", + tag, MTE_TAG_MAX); + } + packed.push_back(static_cast(tag)); + } + + return packed; +} + +llvm::Expected> +MemoryTagManagerAArch64MTE::RepeatTagsForRange( + const std::vector &tags, TagRange range) const { + std::vector new_tags; + + // If the range is not empty + if (range.IsValid()) { + if (tags.empty()) { + return llvm::createStringError( + llvm::inconvertibleErrorCode(), + "Expected some tags to cover given range, got zero."); + } + + // We assume that this range has already been expanded/aligned to granules + size_t granules = range.GetByteSize() / GetGranuleSize(); + new_tags.reserve(granules); + for (size_t to_copy = 0; granules > 0; granules -= to_copy) { + to_copy = granules > tags.size() ? tags.size() : granules; + new_tags.insert(new_tags.end(), tags.begin(), tags.begin() + to_copy); + } + } + + return new_tags; +} diff --git a/gnu/llvm/lldb/source/Plugins/Process/Utility/MemoryTagManagerAArch64MTE.h b/gnu/llvm/lldb/source/Plugins/Process/Utility/MemoryTagManagerAArch64MTE.h new file mode 100644 index 00000000000..d4e8249da93 --- /dev/null +++ b/gnu/llvm/lldb/source/Plugins/Process/Utility/MemoryTagManagerAArch64MTE.h @@ -0,0 +1,53 @@ +//===-- MemoryTagManagerAArch64MTE.h ----------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_MEMORYTAGMANAGERAARCH64MTE_H +#define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_MEMORYTAGMANAGERAARCH64MTE_H + +#include "lldb/Target/MemoryTagManager.h" + +namespace lldb_private { + +class MemoryTagManagerAArch64MTE : public MemoryTagManager { +public: + // This enum is supposed to be shared for all of AArch64 but until + // there are more tag types than MTE, it will live here. + enum MTETagTypes { + eMTE_logical = 0, + eMTE_allocation = 1, + }; + + lldb::addr_t GetGranuleSize() const override; + int32_t GetAllocationTagType() const override; + size_t GetTagSizeInBytes() const override; + + lldb::addr_t GetLogicalTag(lldb::addr_t addr) const override; + lldb::addr_t RemoveNonAddressBits(lldb::addr_t addr) const override; + ptrdiff_t AddressDiff(lldb::addr_t addr1, lldb::addr_t addr2) const override; + + TagRange ExpandToGranule(TagRange range) const override; + + llvm::Expected MakeTaggedRange( + lldb::addr_t addr, lldb::addr_t end_addr, + const lldb_private::MemoryRegionInfos &memory_regions) const override; + + llvm::Expected> + UnpackTagsData(const std::vector &tags, + size_t granules = 0) const override; + + llvm::Expected> + PackTags(const std::vector &tags) const override; + + llvm::Expected> + RepeatTagsForRange(const std::vector &tags, + TagRange range) const override; +}; + +} // namespace lldb_private + +#endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_MEMORYTAGMANAGERAARCH64MTE_H diff --git a/gnu/llvm/lldb/source/Plugins/Process/Utility/MipsLinuxSignals.cpp b/gnu/llvm/lldb/source/Plugins/Process/Utility/MipsLinuxSignals.cpp index 8f75844277c..fb51c56953f 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/Utility/MipsLinuxSignals.cpp +++ b/gnu/llvm/lldb/source/Plugins/Process/Utility/MipsLinuxSignals.cpp @@ -14,79 +14,72 @@ MipsLinuxSignals::MipsLinuxSignals() : UnixSignals() { Reset(); } void MipsLinuxSignals::Reset() { m_signals.clear(); - // SIGNO NAME SUPPRESS STOP NOTIFY DESCRIPTION ALIAS - // ===== =========== ======== ===== ====== - // ====================================== ======== - AddSignal(1, "SIGHUP", false, true, true, "hangup"); - AddSignal(2, "SIGINT", true, true, true, "interrupt"); - AddSignal(3, "SIGQUIT", false, true, true, "quit"); - AddSignal(4, "SIGILL", false, true, true, "illegal instruction"); - AddSignal(5, "SIGTRAP", true, true, true, - "trace trap (not reset when caught)"); - AddSignal(6, "SIGABRT", false, true, true, "abort()/IOT trap", "SIGIOT"); - AddSignal(7, "SIGEMT", false, true, true, "terminate process with core dump"); - AddSignal(8, "SIGFPE", false, true, true, "floating point exception"); - AddSignal(9, "SIGKILL", false, true, true, "kill"); - AddSignal(10, "SIGBUS", false, true, true, "bus error"); - AddSignal(11, "SIGSEGV", false, true, true, "segmentation violation"); - AddSignal(12, "SIGSYS", false, true, true, "invalid system call"); - AddSignal(13, "SIGPIPE", false, true, true, - "write to pipe with reading end closed"); - AddSignal(14, "SIGALRM", false, false, false, "alarm"); - AddSignal(15, "SIGTERM", false, true, true, "termination requested"); - AddSignal(16, "SIGUSR1", false, true, true, "user defined signal 1"); - AddSignal(17, "SIGUSR2", false, true, true, "user defined signal 2"); - AddSignal(18, "SIGCHLD", false, false, true, "child status has changed", - "SIGCLD"); - AddSignal(19, "SIGPWR", false, true, true, "power failure"); - AddSignal(20, "SIGWINCH", false, true, true, "window size changes"); - AddSignal(21, "SIGURG", false, true, true, "urgent data on socket"); - AddSignal(22, "SIGIO", false, true, true, "input/output ready/Pollable event", - "SIGPOLL"); - AddSignal(23, "SIGSTOP", true, true, true, "process stop"); - AddSignal(24, "SIGTSTP", false, true, true, "tty stop"); - AddSignal(25, "SIGCONT", false, true, true, "process continue"); - AddSignal(26, "SIGTTIN", false, true, true, "background tty read"); - AddSignal(27, "SIGTTOU", false, true, true, "background tty write"); - AddSignal(28, "SIGVTALRM", false, true, true, "virtual time alarm"); - AddSignal(29, "SIGPROF", false, false, false, "profiling time alarm"); - AddSignal(30, "SIGXCPU", false, true, true, "CPU resource exceeded"); - AddSignal(31, "SIGXFSZ", false, true, true, "file size limit exceeded"); - AddSignal(32, "SIG32", false, false, false, - "threading library internal signal 1"); - AddSignal(33, "SIG33", false, false, false, - "threading library internal signal 2"); - AddSignal(34, "SIGRTMIN", false, false, false, "real time signal 0"); - AddSignal(35, "SIGRTMIN+1", false, false, false, "real time signal 1"); - AddSignal(36, "SIGRTMIN+2", false, false, false, "real time signal 2"); - AddSignal(37, "SIGRTMIN+3", false, false, false, "real time signal 3"); - AddSignal(38, "SIGRTMIN+4", false, false, false, "real time signal 4"); - AddSignal(39, "SIGRTMIN+5", false, false, false, "real time signal 5"); - AddSignal(40, "SIGRTMIN+6", false, false, false, "real time signal 6"); - AddSignal(41, "SIGRTMIN+7", false, false, false, "real time signal 7"); - AddSignal(42, "SIGRTMIN+8", false, false, false, "real time signal 8"); - AddSignal(43, "SIGRTMIN+9", false, false, false, "real time signal 9"); - AddSignal(44, "SIGRTMIN+10", false, false, false, "real time signal 10"); - AddSignal(45, "SIGRTMIN+11", false, false, false, "real time signal 11"); - AddSignal(46, "SIGRTMIN+12", false, false, false, "real time signal 12"); - AddSignal(47, "SIGRTMIN+13", false, false, false, "real time signal 13"); - AddSignal(48, "SIGRTMIN+14", false, false, false, "real time signal 14"); - AddSignal(49, "SIGRTMIN+15", false, false, false, "real time signal 15"); - AddSignal(50, "SIGRTMAX-14", false, false, false, - "real time signal 16"); // switching to SIGRTMAX-xxx to match "kill - // -l" output - AddSignal(51, "SIGRTMAX-13", false, false, false, "real time signal 17"); - AddSignal(52, "SIGRTMAX-12", false, false, false, "real time signal 18"); - AddSignal(53, "SIGRTMAX-11", false, false, false, "real time signal 19"); - AddSignal(54, "SIGRTMAX-10", false, false, false, "real time signal 20"); - AddSignal(55, "SIGRTMAX-9", false, false, false, "real time signal 21"); - AddSignal(56, "SIGRTMAX-8", false, false, false, "real time signal 22"); - AddSignal(57, "SIGRTMAX-7", false, false, false, "real time signal 23"); - AddSignal(58, "SIGRTMAX-6", false, false, false, "real time signal 24"); - AddSignal(59, "SIGRTMAX-5", false, false, false, "real time signal 25"); - AddSignal(60, "SIGRTMAX-4", false, false, false, "real time signal 26"); - AddSignal(61, "SIGRTMAX-3", false, false, false, "real time signal 27"); - AddSignal(62, "SIGRTMAX-2", false, false, false, "real time signal 28"); - AddSignal(63, "SIGRTMAX-1", false, false, false, "real time signal 29"); - AddSignal(64, "SIGRTMAX", false, false, false, "real time signal 30"); + // clang-format off + // SIGNO NAME SUPPRESS STOP NOTIFY DESCRIPTION + // ====== ============== ======== ====== ====== =================================================== + AddSignal(1, "SIGHUP", false, true, true, "hangup"); + AddSignal(2, "SIGINT", true, true, true, "interrupt"); + AddSignal(3, "SIGQUIT", false, true, true, "quit"); + AddSignal(4, "SIGILL", false, true, true, "illegal instruction"); + AddSignal(5, "SIGTRAP", true, true, true, "trace trap (not reset when caught)"); + AddSignal(6, "SIGABRT", false, true, true, "abort()/IOT trap", "SIGIOT"); + AddSignal(7, "SIGEMT", false, true, true, "terminate process with core dump"); + AddSignal(8, "SIGFPE", false, true, true, "floating point exception"); + AddSignal(9, "SIGKILL", false, true, true, "kill"); + AddSignal(10, "SIGBUS", false, true, true, "bus error"); + AddSignal(11, "SIGSEGV", false, true, true, "segmentation violation"); + AddSignal(12, "SIGSYS", false, true, true, "invalid system call"); + AddSignal(13, "SIGPIPE", false, true, true, "write to pipe with reading end closed"); + AddSignal(14, "SIGALRM", false, false, false, "alarm"); + AddSignal(15, "SIGTERM", false, true, true, "termination requested"); + AddSignal(16, "SIGUSR1", false, true, true, "user defined signal 1"); + AddSignal(17, "SIGUSR2", false, true, true, "user defined signal 2"); + AddSignal(18, "SIGCHLD", false, false, true, "child status has changed", "SIGCLD"); + AddSignal(19, "SIGPWR", false, true, true, "power failure"); + AddSignal(20, "SIGWINCH", false, true, true, "window size changes"); + AddSignal(21, "SIGURG", false, true, true, "urgent data on socket"); + AddSignal(22, "SIGIO", false, true, true, "input/output ready/Pollable event", "SIGPOLL"); + AddSignal(23, "SIGSTOP", true, true, true, "process stop"); + AddSignal(24, "SIGTSTP", false, true, true, "tty stop"); + AddSignal(25, "SIGCONT", false, false, true, "process continue"); + AddSignal(26, "SIGTTIN", false, true, true, "background tty read"); + AddSignal(27, "SIGTTOU", false, true, true, "background tty write"); + AddSignal(28, "SIGVTALRM", false, true, true, "virtual time alarm"); + AddSignal(29, "SIGPROF", false, false, false, "profiling time alarm"); + AddSignal(30, "SIGXCPU", false, true, true, "CPU resource exceeded"); + AddSignal(31, "SIGXFSZ", false, true, true, "file size limit exceeded"); + AddSignal(32, "SIG32", false, false, false, "threading library internal signal 1"); + AddSignal(33, "SIG33", false, false, false, "threading library internal signal 2"); + AddSignal(34, "SIGRTMIN", false, false, false, "real time signal 0"); + AddSignal(35, "SIGRTMIN+1", false, false, false, "real time signal 1"); + AddSignal(36, "SIGRTMIN+2", false, false, false, "real time signal 2"); + AddSignal(37, "SIGRTMIN+3", false, false, false, "real time signal 3"); + AddSignal(38, "SIGRTMIN+4", false, false, false, "real time signal 4"); + AddSignal(39, "SIGRTMIN+5", false, false, false, "real time signal 5"); + AddSignal(40, "SIGRTMIN+6", false, false, false, "real time signal 6"); + AddSignal(41, "SIGRTMIN+7", false, false, false, "real time signal 7"); + AddSignal(42, "SIGRTMIN+8", false, false, false, "real time signal 8"); + AddSignal(43, "SIGRTMIN+9", false, false, false, "real time signal 9"); + AddSignal(44, "SIGRTMIN+10", false, false, false, "real time signal 10"); + AddSignal(45, "SIGRTMIN+11", false, false, false, "real time signal 11"); + AddSignal(46, "SIGRTMIN+12", false, false, false, "real time signal 12"); + AddSignal(47, "SIGRTMIN+13", false, false, false, "real time signal 13"); + AddSignal(48, "SIGRTMIN+14", false, false, false, "real time signal 14"); + AddSignal(49, "SIGRTMIN+15", false, false, false, "real time signal 15"); + AddSignal(50, "SIGRTMAX-14", false, false, false, "real time signal 16"); // switching to SIGRTMAX-xxx to match "kill -l" output + AddSignal(51, "SIGRTMAX-13", false, false, false, "real time signal 17"); + AddSignal(52, "SIGRTMAX-12", false, false, false, "real time signal 18"); + AddSignal(53, "SIGRTMAX-11", false, false, false, "real time signal 19"); + AddSignal(54, "SIGRTMAX-10", false, false, false, "real time signal 20"); + AddSignal(55, "SIGRTMAX-9", false, false, false, "real time signal 21"); + AddSignal(56, "SIGRTMAX-8", false, false, false, "real time signal 22"); + AddSignal(57, "SIGRTMAX-7", false, false, false, "real time signal 23"); + AddSignal(58, "SIGRTMAX-6", false, false, false, "real time signal 24"); + AddSignal(59, "SIGRTMAX-5", false, false, false, "real time signal 25"); + AddSignal(60, "SIGRTMAX-4", false, false, false, "real time signal 26"); + AddSignal(61, "SIGRTMAX-3", false, false, false, "real time signal 27"); + AddSignal(62, "SIGRTMAX-2", false, false, false, "real time signal 28"); + AddSignal(63, "SIGRTMAX-1", false, false, false, "real time signal 29"); + AddSignal(64, "SIGRTMAX", false, false, false, "real time signal 30"); + // clang-format on } diff --git a/gnu/llvm/lldb/source/Plugins/Process/Utility/NativeProcessSoftwareSingleStep.cpp b/gnu/llvm/lldb/source/Plugins/Process/Utility/NativeProcessSoftwareSingleStep.cpp new file mode 100644 index 00000000000..ee5295bf656 --- /dev/null +++ b/gnu/llvm/lldb/source/Plugins/Process/Utility/NativeProcessSoftwareSingleStep.cpp @@ -0,0 +1,182 @@ +//===-- NativeProcessSoftwareSingleStep.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 "NativeProcessSoftwareSingleStep.h" + +#include "lldb/Core/EmulateInstruction.h" +#include "lldb/Host/common/NativeRegisterContext.h" +#include "lldb/Utility/RegisterValue.h" + +#include + +using namespace lldb; +using namespace lldb_private; + +namespace { + +struct EmulatorBaton { + NativeProcessProtocol &m_process; + NativeRegisterContext &m_reg_context; + + // eRegisterKindDWARF -> RegsiterValue + std::unordered_map m_register_values; + + EmulatorBaton(NativeProcessProtocol &process, + NativeRegisterContext ®_context) + : m_process(process), m_reg_context(reg_context) {} +}; + +} // anonymous namespace + +static size_t ReadMemoryCallback(EmulateInstruction *instruction, void *baton, + const EmulateInstruction::Context &context, + lldb::addr_t addr, void *dst, size_t length) { + EmulatorBaton *emulator_baton = static_cast(baton); + + size_t bytes_read; + emulator_baton->m_process.ReadMemory(addr, dst, length, bytes_read); + return bytes_read; +} + +static bool ReadRegisterCallback(EmulateInstruction *instruction, void *baton, + const RegisterInfo *reg_info, + RegisterValue ®_value) { + EmulatorBaton *emulator_baton = static_cast(baton); + + auto it = emulator_baton->m_register_values.find( + reg_info->kinds[eRegisterKindDWARF]); + if (it != emulator_baton->m_register_values.end()) { + reg_value = it->second; + return true; + } + + // The emulator only fill in the dwarf regsiter numbers (and in some case the + // generic register numbers). Get the full register info from the register + // context based on the dwarf register numbers. + const RegisterInfo *full_reg_info = + emulator_baton->m_reg_context.GetRegisterInfo( + eRegisterKindDWARF, reg_info->kinds[eRegisterKindDWARF]); + + Status error = + emulator_baton->m_reg_context.ReadRegister(full_reg_info, reg_value); + if (error.Success()) + return true; + + return false; +} + +static bool WriteRegisterCallback(EmulateInstruction *instruction, void *baton, + const EmulateInstruction::Context &context, + const RegisterInfo *reg_info, + const RegisterValue ®_value) { + EmulatorBaton *emulator_baton = static_cast(baton); + emulator_baton->m_register_values[reg_info->kinds[eRegisterKindDWARF]] = + reg_value; + return true; +} + +static size_t WriteMemoryCallback(EmulateInstruction *instruction, void *baton, + const EmulateInstruction::Context &context, + lldb::addr_t addr, const void *dst, + size_t length) { + return length; +} + +static lldb::addr_t ReadFlags(NativeRegisterContext ®siter_context) { + const RegisterInfo *flags_info = regsiter_context.GetRegisterInfo( + eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS); + return regsiter_context.ReadRegisterAsUnsigned(flags_info, + LLDB_INVALID_ADDRESS); +} + +Status NativeProcessSoftwareSingleStep::SetupSoftwareSingleStepping( + NativeThreadProtocol &thread) { + Status error; + NativeProcessProtocol &process = thread.GetProcess(); + NativeRegisterContext ®ister_context = thread.GetRegisterContext(); + const ArchSpec &arch = process.GetArchitecture(); + + std::unique_ptr emulator_up( + EmulateInstruction::FindPlugin(arch, eInstructionTypePCModifying, + nullptr)); + + if (emulator_up == nullptr) + return Status("Instruction emulator not found!"); + + EmulatorBaton baton(process, register_context); + emulator_up->SetBaton(&baton); + emulator_up->SetReadMemCallback(&ReadMemoryCallback); + emulator_up->SetReadRegCallback(&ReadRegisterCallback); + emulator_up->SetWriteMemCallback(&WriteMemoryCallback); + emulator_up->SetWriteRegCallback(&WriteRegisterCallback); + + if (!emulator_up->ReadInstruction()) + return Status("Read instruction failed!"); + + bool emulation_result = + emulator_up->EvaluateInstruction(eEmulateInstructionOptionAutoAdvancePC); + + const RegisterInfo *reg_info_pc = register_context.GetRegisterInfo( + eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC); + const RegisterInfo *reg_info_flags = register_context.GetRegisterInfo( + eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS); + + auto pc_it = + baton.m_register_values.find(reg_info_pc->kinds[eRegisterKindDWARF]); + auto flags_it = + baton.m_register_values.find(reg_info_flags->kinds[eRegisterKindDWARF]); + + lldb::addr_t next_pc; + lldb::addr_t next_flags; + if (emulation_result) { + assert(pc_it != baton.m_register_values.end() && + "Emulation was successfull but PC wasn't updated"); + next_pc = pc_it->second.GetAsUInt64(); + + if (flags_it != baton.m_register_values.end()) + next_flags = flags_it->second.GetAsUInt64(); + else + next_flags = ReadFlags(register_context); + } else if (pc_it == baton.m_register_values.end()) { + // Emulate instruction failed and it haven't changed PC. Advance PC with + // the size of the current opcode because the emulation of all + // PC modifying instruction should be successful. The failure most + // likely caused by a not supported instruction which don't modify PC. + next_pc = register_context.GetPC() + emulator_up->GetOpcode().GetByteSize(); + next_flags = ReadFlags(register_context); + } else { + // The instruction emulation failed after it modified the PC. It is an + // unknown error where we can't continue because the next instruction is + // modifying the PC but we don't know how. + return Status("Instruction emulation failed unexpectedly."); + } + + int size_hint = 0; + if (arch.GetMachine() == llvm::Triple::arm) { + if (next_flags & 0x20) { + // Thumb mode + size_hint = 2; + } else { + // Arm mode + size_hint = 4; + } + } else if (arch.IsMIPS() || arch.GetTriple().isPPC64()) + size_hint = 4; + error = process.SetBreakpoint(next_pc, size_hint, /*hardware=*/false); + + // If setting the breakpoint fails because next_pc is out of the address + // space, ignore it and let the debugee segfault. + if (error.GetError() == EIO || error.GetError() == EFAULT) { + return Status(); + } else if (error.Fail()) + return error; + + m_threads_stepping_with_breakpoint.insert({thread.GetID(), next_pc}); + + return Status(); +} diff --git a/gnu/llvm/lldb/source/Plugins/Process/Utility/NativeProcessSoftwareSingleStep.h b/gnu/llvm/lldb/source/Plugins/Process/Utility/NativeProcessSoftwareSingleStep.h new file mode 100644 index 00000000000..f9435b7a84b --- /dev/null +++ b/gnu/llvm/lldb/source/Plugins/Process/Utility/NativeProcessSoftwareSingleStep.h @@ -0,0 +1,31 @@ +//===-- NativeProcessSoftwareSingleStep.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_NativeProcessSoftwareSingleStep_h +#define lldb_NativeProcessSoftwareSingleStep_h + +#include "lldb/Host/common/NativeProcessProtocol.h" +#include "lldb/Host/common/NativeThreadProtocol.h" + +#include + +namespace lldb_private { + +class NativeProcessSoftwareSingleStep { +public: + Status SetupSoftwareSingleStepping(NativeThreadProtocol &thread); + +protected: + // List of thread ids stepping with a breakpoint with the address of + // the relevan breakpoint + std::map m_threads_stepping_with_breakpoint; +}; + +} // namespace lldb_private + +#endif // #ifndef lldb_NativeProcessSoftwareSingleStep_h diff --git a/gnu/llvm/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_arm64.cpp b/gnu/llvm/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_arm64.cpp new file mode 100644 index 00000000000..feee857cfe5 --- /dev/null +++ b/gnu/llvm/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_arm64.cpp @@ -0,0 +1,469 @@ +//===-- NativeRegisterContextDBReg_arm64.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 "NativeRegisterContextDBReg_arm64.h" + +#include "lldb/Utility/Log.h" +#include "lldb/Utility/RegisterValue.h" + +using namespace lldb_private; + +// E (bit 0), used to enable breakpoint/watchpoint +constexpr uint32_t g_enable_bit = 1; +// PAC (bits 2:1): 0b10 +constexpr uint32_t g_pac_bits = (2 << 1); + +// Returns appropriate control register bits for the specified size +static constexpr inline uint64_t GetSizeBits(int size) { + // BAS (bits 12:5) hold a bit-mask of addresses to watch + // e.g. 0b00000001 means 1 byte at address + // 0b00000011 means 2 bytes (addr..addr+1) + // ... + // 0b11111111 means 8 bytes (addr..addr+7) + return ((1 << size) - 1) << 5; +} + +uint32_t NativeRegisterContextDBReg_arm64::NumSupportedHardwareBreakpoints() { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_BREAKPOINTS)); + llvm::Error error = ReadHardwareDebugInfo(); + if (error) { + LLDB_LOG_ERROR(log, std::move(error), + "failed to read debug registers: {0}"); + return 0; + } + + return m_max_hbp_supported; +} + +uint32_t +NativeRegisterContextDBReg_arm64::SetHardwareBreakpoint(lldb::addr_t addr, + size_t size) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_BREAKPOINTS)); + LLDB_LOG(log, "addr: {0:x}, size: {1:x}", addr, size); + + // Read hardware breakpoint and watchpoint information. + llvm::Error error = ReadHardwareDebugInfo(); + if (error) { + LLDB_LOG_ERROR( + log, std::move(error), + "unable to set breakpoint: failed to read debug registers: {0}"); + return LLDB_INVALID_INDEX32; + } + + uint32_t control_value = 0, bp_index = 0; + + // Check if size has a valid hardware breakpoint length. + if (size != 4) + return LLDB_INVALID_INDEX32; // Invalid size for a AArch64 hardware + // breakpoint + + // Check 4-byte alignment for hardware breakpoint target address. + if (addr & 0x03) + return LLDB_INVALID_INDEX32; // Invalid address, should be 4-byte aligned. + + // Setup control value + control_value = g_enable_bit | g_pac_bits | GetSizeBits(size); + + // Iterate over stored breakpoints and find a free bp_index + bp_index = LLDB_INVALID_INDEX32; + for (uint32_t i = 0; i < m_max_hbp_supported; i++) { + if (!BreakpointIsEnabled(i)) + bp_index = i; // Mark last free slot + else if (m_hbp_regs[i].address == addr) + return LLDB_INVALID_INDEX32; // We do not support duplicate breakpoints. + } + + if (bp_index == LLDB_INVALID_INDEX32) + return LLDB_INVALID_INDEX32; + + // Update breakpoint in local cache + m_hbp_regs[bp_index].real_addr = addr; + m_hbp_regs[bp_index].address = addr; + m_hbp_regs[bp_index].control = control_value; + + // PTRACE call to set corresponding hardware breakpoint register. + error = WriteHardwareDebugRegs(eDREGTypeBREAK); + + if (error) { + m_hbp_regs[bp_index].address = 0; + m_hbp_regs[bp_index].control &= ~1; + + LLDB_LOG_ERROR( + log, std::move(error), + "unable to set breakpoint: failed to write debug registers: {0}"); + return LLDB_INVALID_INDEX32; + } + + return bp_index; +} + +bool NativeRegisterContextDBReg_arm64::ClearHardwareBreakpoint( + uint32_t hw_idx) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_BREAKPOINTS)); + LLDB_LOG(log, "hw_idx: {0}", hw_idx); + + // Read hardware breakpoint and watchpoint information. + llvm::Error error = ReadHardwareDebugInfo(); + if (error) { + LLDB_LOG_ERROR( + log, std::move(error), + "unable to clear breakpoint: failed to read debug registers: {0}"); + return false; + } + + if (hw_idx >= m_max_hbp_supported) + return false; + + // Create a backup we can revert to in case of failure. + lldb::addr_t tempAddr = m_hbp_regs[hw_idx].address; + uint32_t tempControl = m_hbp_regs[hw_idx].control; + + m_hbp_regs[hw_idx].control &= ~g_enable_bit; + m_hbp_regs[hw_idx].address = 0; + + // PTRACE call to clear corresponding hardware breakpoint register. + error = WriteHardwareDebugRegs(eDREGTypeBREAK); + + if (error) { + m_hbp_regs[hw_idx].control = tempControl; + m_hbp_regs[hw_idx].address = tempAddr; + + LLDB_LOG_ERROR( + log, std::move(error), + "unable to clear breakpoint: failed to write debug registers: {0}"); + return false; + } + + return true; +} + +Status NativeRegisterContextDBReg_arm64::GetHardwareBreakHitIndex( + uint32_t &bp_index, lldb::addr_t trap_addr) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_BREAKPOINTS)); + + LLDB_LOGF(log, "NativeRegisterContextDBReg_arm64::%s()", __FUNCTION__); + + lldb::addr_t break_addr; + + for (bp_index = 0; bp_index < m_max_hbp_supported; ++bp_index) { + break_addr = m_hbp_regs[bp_index].address; + + if (BreakpointIsEnabled(bp_index) && trap_addr == break_addr) { + m_hbp_regs[bp_index].hit_addr = trap_addr; + return Status(); + } + } + + bp_index = LLDB_INVALID_INDEX32; + return Status(); +} + +Status NativeRegisterContextDBReg_arm64::ClearAllHardwareBreakpoints() { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_BREAKPOINTS)); + + LLDB_LOGF(log, "NativeRegisterContextDBReg_arm64::%s()", __FUNCTION__); + + // Read hardware breakpoint and watchpoint information. + llvm::Error error = ReadHardwareDebugInfo(); + if (error) + return Status(std::move(error)); + + for (uint32_t i = 0; i < m_max_hbp_supported; i++) { + if (BreakpointIsEnabled(i)) { + // Create a backup we can revert to in case of failure. + lldb::addr_t tempAddr = m_hbp_regs[i].address; + uint32_t tempControl = m_hbp_regs[i].control; + + // Clear watchpoints in local cache + m_hbp_regs[i].control &= ~g_enable_bit; + m_hbp_regs[i].address = 0; + + // Ptrace call to update hardware debug registers + error = WriteHardwareDebugRegs(eDREGTypeBREAK); + + if (error) { + m_hbp_regs[i].control = tempControl; + m_hbp_regs[i].address = tempAddr; + + return Status(std::move(error)); + } + } + } + + return Status(); +} + +bool NativeRegisterContextDBReg_arm64::BreakpointIsEnabled(uint32_t bp_index) { + if ((m_hbp_regs[bp_index].control & g_enable_bit) != 0) + return true; + else + return false; +} + +uint32_t NativeRegisterContextDBReg_arm64::NumSupportedHardwareWatchpoints() { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS)); + llvm::Error error = ReadHardwareDebugInfo(); + if (error) { + LLDB_LOG_ERROR(log, std::move(error), + "failed to read debug registers: {0}"); + return 0; + } + + return m_max_hwp_supported; +} + +uint32_t NativeRegisterContextDBReg_arm64::SetHardwareWatchpoint( + lldb::addr_t addr, size_t size, uint32_t watch_flags) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS)); + LLDB_LOG(log, "addr: {0:x}, size: {1:x} watch_flags: {2:x}", addr, size, + watch_flags); + + // Read hardware breakpoint and watchpoint information. + llvm::Error error = ReadHardwareDebugInfo(); + if (error) { + LLDB_LOG_ERROR( + log, std::move(error), + "unable to set watchpoint: failed to read debug registers: {0}"); + return LLDB_INVALID_INDEX32; + } + + uint32_t control_value = 0, wp_index = 0; + lldb::addr_t real_addr = addr; + + // Check if we are setting watchpoint other than read/write/access Also + // update watchpoint flag to match AArch64 write-read bit configuration. + switch (watch_flags) { + case 1: + watch_flags = 2; + break; + case 2: + watch_flags = 1; + break; + case 3: + break; + default: + return LLDB_INVALID_INDEX32; + } + + // Check if size has a valid hardware watchpoint length. + if (size != 1 && size != 2 && size != 4 && size != 8) + return LLDB_INVALID_INDEX32; + + // Check 8-byte alignment for hardware watchpoint target address. Below is a + // hack to recalculate address and size in order to make sure we can watch + // non 8-byte aligned addresses as well. + if (addr & 0x07) { + uint8_t watch_mask = (addr & 0x07) + size; + + if (watch_mask > 0x08) + return LLDB_INVALID_INDEX32; + else if (watch_mask <= 0x02) + size = 2; + else if (watch_mask <= 0x04) + size = 4; + else + size = 8; + + addr = addr & (~0x07); + } + + // Setup control value + control_value = g_enable_bit | g_pac_bits | GetSizeBits(size); + control_value |= watch_flags << 3; + + // Iterate over stored watchpoints and find a free wp_index + wp_index = LLDB_INVALID_INDEX32; + for (uint32_t i = 0; i < m_max_hwp_supported; i++) { + if (!WatchpointIsEnabled(i)) + wp_index = i; // Mark last free slot + else if (m_hwp_regs[i].address == addr) { + return LLDB_INVALID_INDEX32; // We do not support duplicate watchpoints. + } + } + + if (wp_index == LLDB_INVALID_INDEX32) + return LLDB_INVALID_INDEX32; + + // Update watchpoint in local cache + m_hwp_regs[wp_index].real_addr = real_addr; + m_hwp_regs[wp_index].address = addr; + m_hwp_regs[wp_index].control = control_value; + + // PTRACE call to set corresponding watchpoint register. + error = WriteHardwareDebugRegs(eDREGTypeWATCH); + + if (error) { + m_hwp_regs[wp_index].address = 0; + m_hwp_regs[wp_index].control &= ~g_enable_bit; + + LLDB_LOG_ERROR( + log, std::move(error), + "unable to set watchpoint: failed to write debug registers: {0}"); + return LLDB_INVALID_INDEX32; + } + + return wp_index; +} + +bool NativeRegisterContextDBReg_arm64::ClearHardwareWatchpoint( + uint32_t wp_index) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS)); + LLDB_LOG(log, "wp_index: {0}", wp_index); + + // Read hardware breakpoint and watchpoint information. + llvm::Error error = ReadHardwareDebugInfo(); + if (error) { + LLDB_LOG_ERROR( + log, std::move(error), + "unable to clear watchpoint: failed to read debug registers: {0}"); + return false; + } + + if (wp_index >= m_max_hwp_supported) + return false; + + // Create a backup we can revert to in case of failure. + lldb::addr_t tempAddr = m_hwp_regs[wp_index].address; + uint32_t tempControl = m_hwp_regs[wp_index].control; + + // Update watchpoint in local cache + m_hwp_regs[wp_index].control &= ~g_enable_bit; + m_hwp_regs[wp_index].address = 0; + + // Ptrace call to update hardware debug registers + error = WriteHardwareDebugRegs(eDREGTypeWATCH); + + if (error) { + m_hwp_regs[wp_index].control = tempControl; + m_hwp_regs[wp_index].address = tempAddr; + + LLDB_LOG_ERROR( + log, std::move(error), + "unable to clear watchpoint: failed to write debug registers: {0}"); + return false; + } + + return true; +} + +Status NativeRegisterContextDBReg_arm64::ClearAllHardwareWatchpoints() { + // Read hardware breakpoint and watchpoint information. + llvm::Error error = ReadHardwareDebugInfo(); + if (error) + return Status(std::move(error)); + + for (uint32_t i = 0; i < m_max_hwp_supported; i++) { + if (WatchpointIsEnabled(i)) { + // Create a backup we can revert to in case of failure. + lldb::addr_t tempAddr = m_hwp_regs[i].address; + uint32_t tempControl = m_hwp_regs[i].control; + + // Clear watchpoints in local cache + m_hwp_regs[i].control &= ~g_enable_bit; + m_hwp_regs[i].address = 0; + + // Ptrace call to update hardware debug registers + error = WriteHardwareDebugRegs(eDREGTypeWATCH); + + if (error) { + m_hwp_regs[i].control = tempControl; + m_hwp_regs[i].address = tempAddr; + + return Status(std::move(error)); + } + } + } + + return Status(); +} + +uint32_t +NativeRegisterContextDBReg_arm64::GetWatchpointSize(uint32_t wp_index) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS)); + LLDB_LOG(log, "wp_index: {0}", wp_index); + + switch ((m_hwp_regs[wp_index].control >> 5) & 0xff) { + case 0x01: + return 1; + case 0x03: + return 2; + case 0x0f: + return 4; + case 0xff: + return 8; + default: + return 0; + } +} + +bool NativeRegisterContextDBReg_arm64::WatchpointIsEnabled(uint32_t wp_index) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS)); + LLDB_LOG(log, "wp_index: {0}", wp_index); + + if ((m_hwp_regs[wp_index].control & g_enable_bit) != 0) + return true; + else + return false; +} + +Status NativeRegisterContextDBReg_arm64::GetWatchpointHitIndex( + uint32_t &wp_index, lldb::addr_t trap_addr) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS)); + LLDB_LOG(log, "wp_index: {0}, trap_addr: {1:x}", wp_index, trap_addr); + + // Read hardware breakpoint and watchpoint information. + llvm::Error error = ReadHardwareDebugInfo(); + if (error) + return Status(std::move(error)); + + // Mask off ignored bits from watchpoint trap address. + trap_addr = FixWatchpointHitAddress(trap_addr); + + uint32_t watch_size; + lldb::addr_t watch_addr; + + for (wp_index = 0; wp_index < m_max_hwp_supported; ++wp_index) { + watch_size = GetWatchpointSize(wp_index); + watch_addr = m_hwp_regs[wp_index].address; + + if (WatchpointIsEnabled(wp_index) && trap_addr >= watch_addr && + trap_addr < watch_addr + watch_size) { + m_hwp_regs[wp_index].hit_addr = trap_addr; + return Status(); + } + } + + wp_index = LLDB_INVALID_INDEX32; + return Status(); +} + +lldb::addr_t +NativeRegisterContextDBReg_arm64::GetWatchpointAddress(uint32_t wp_index) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS)); + LLDB_LOG(log, "wp_index: {0}", wp_index); + + if (wp_index >= m_max_hwp_supported) + return LLDB_INVALID_ADDRESS; + + if (WatchpointIsEnabled(wp_index)) + return m_hwp_regs[wp_index].real_addr; + return LLDB_INVALID_ADDRESS; +} + +lldb::addr_t +NativeRegisterContextDBReg_arm64::GetWatchpointHitAddress(uint32_t wp_index) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS)); + LLDB_LOG(log, "wp_index: {0}", wp_index); + + if (wp_index >= m_max_hwp_supported) + return LLDB_INVALID_ADDRESS; + + if (WatchpointIsEnabled(wp_index)) + return m_hwp_regs[wp_index].hit_addr; + return LLDB_INVALID_ADDRESS; +} diff --git a/gnu/llvm/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_arm64.h b/gnu/llvm/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_arm64.h new file mode 100644 index 00000000000..3da0b0407ce --- /dev/null +++ b/gnu/llvm/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_arm64.h @@ -0,0 +1,82 @@ +//===-- NativeRegisterContextDBReg_arm64.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_NativeRegisterContextDBReg_arm64_h +#define lldb_NativeRegisterContextDBReg_arm64_h + +#include "Plugins/Process/Utility/NativeRegisterContextRegisterInfo.h" + +#include + +namespace lldb_private { + +class NativeRegisterContextDBReg_arm64 + : public virtual NativeRegisterContextRegisterInfo { +public: + uint32_t NumSupportedHardwareBreakpoints() override; + + uint32_t SetHardwareBreakpoint(lldb::addr_t addr, size_t size) override; + + bool ClearHardwareBreakpoint(uint32_t hw_idx) override; + + Status ClearAllHardwareBreakpoints() override; + + Status GetHardwareBreakHitIndex(uint32_t &bp_index, + lldb::addr_t trap_addr) override; + + bool BreakpointIsEnabled(uint32_t bp_index); + + uint32_t NumSupportedHardwareWatchpoints() override; + + uint32_t SetHardwareWatchpoint(lldb::addr_t addr, size_t size, + uint32_t watch_flags) override; + + bool ClearHardwareWatchpoint(uint32_t hw_index) override; + + Status ClearAllHardwareWatchpoints() override; + + Status GetWatchpointHitIndex(uint32_t &wp_index, + lldb::addr_t trap_addr) override; + + lldb::addr_t GetWatchpointHitAddress(uint32_t wp_index) override; + + lldb::addr_t GetWatchpointAddress(uint32_t wp_index) override; + + uint32_t GetWatchpointSize(uint32_t wp_index); + + bool WatchpointIsEnabled(uint32_t wp_index); + + // Debug register type select + enum DREGType { eDREGTypeWATCH = 0, eDREGTypeBREAK }; + +protected: + // 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. + }; + + std::array m_hbp_regs; // hardware breakpoints + std::array m_hwp_regs; // hardware watchpoints + + uint32_t m_max_hbp_supported; + uint32_t m_max_hwp_supported; + + virtual llvm::Error ReadHardwareDebugInfo() = 0; + virtual llvm::Error WriteHardwareDebugRegs(DREGType hwbType) = 0; + virtual lldb::addr_t FixWatchpointHitAddress(lldb::addr_t hit_addr) { + return hit_addr; + } +}; + +} // namespace lldb_private + +#endif // #ifndef lldb_NativeRegisterContextDBReg_arm64_h diff --git a/gnu/llvm/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_x86.cpp b/gnu/llvm/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_x86.cpp new file mode 100644 index 00000000000..56c1757ee89 --- /dev/null +++ b/gnu/llvm/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_x86.cpp @@ -0,0 +1,276 @@ +//===-- NativeRegisterContextDBReg_x86.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 "NativeRegisterContextDBReg_x86.h" + +#include "lldb/Utility/Log.h" +#include "lldb/Utility/RegisterValue.h" + +#include "Plugins/Process/Utility/lldb-x86-register-enums.h" + +using namespace lldb_private; + +// Returns mask/value for status bit of wp_index in DR6 +static inline uint64_t GetStatusBit(uint32_t wp_index) { + // DR6: ...BBBB + // 3210 <- status bits for bp./wp. i; 1 if hit + return 1 << wp_index; +} + +// Returns mask/value for global enable bit of wp_index in DR7 +static inline uint64_t GetEnableBit(uint32_t wp_index) { + // DR7: ...GLGLGLGL + // 33221100 <- global/local enable for bp./wp.; 1 if enabled + // we use global bits because NetBSD kernel does not preserve local + // bits reliably; Linux seems fine with either + return 1 << (2 * wp_index + 1); +} + +// Returns mask for both enable bits of wp_index in DR7 +static inline uint64_t GetBothEnableBitMask(uint32_t wp_index) { + // DR7: ...GLGLGLGL + // 33221100 <- global/local enable for bp./wp.; 1 if enabled + return 3 << (2 * wp_index + 1); +} + +// Returns value for type bits of wp_index in DR7 +static inline uint64_t GetWatchTypeBits(uint32_t watch_flags, + uint32_t wp_index) { + // DR7: + // bit: 3322222222221111... + // 1098765432109876... + // val: SSTTSSTTSSTTSSTT... + // wp.: 3333222211110000... + // + // where T - type is 01 for write, 11 for r/w + return watch_flags << (16 + 4 * wp_index); +} + +// Returns value for size bits of wp_index in DR7 +static inline uint64_t GetWatchSizeBits(uint32_t size, uint32_t wp_index) { + // DR7: + // bit: 3322222222221111... + // 1098765432109876... + // val: SSTTSSTTSSTTSSTT... + // wp.: 3333222211110000... + // + // where S - size is: + // 00 for 1 byte + // 01 for 2 bytes + // 10 for 8 bytes + // 11 for 4 bytes + return (size == 8 ? 0x2 : size - 1) << (18 + 4 * wp_index); +} + +// Returns bitmask for all bits controlling wp_index in DR7 +static inline uint64_t GetWatchControlBitmask(uint32_t wp_index) { + // DR7: + // bit: 33222222222211111111110000000000 + // 10987654321098765432109876543210 + // val: SSTTSSTTSSTTSSTTxxxxxxGLGLGLGLGL + // wp.: 3333222211110000xxxxxxEE33221100 + return GetBothEnableBitMask(wp_index) | (0xF << (16 + 4 * wp_index)); +} + +// Bit mask for control bits regarding all watchpoints. +static constexpr uint64_t watchpoint_all_control_bit_mask = 0xFFFF00FF; + +const RegisterInfo *NativeRegisterContextDBReg_x86::GetDR(int num) const { + assert(num >= 0 && num <= 7); + switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) { + case llvm::Triple::x86: + return GetRegisterInfoAtIndex(lldb_dr0_i386 + num); + case llvm::Triple::x86_64: + return GetRegisterInfoAtIndex(lldb_dr0_x86_64 + num); + default: + llvm_unreachable("Unhandled target architecture."); + } +} + +Status NativeRegisterContextDBReg_x86::IsWatchpointHit(uint32_t wp_index, + bool &is_hit) { + if (wp_index >= NumSupportedHardwareWatchpoints()) + return Status("Watchpoint index out of range"); + + RegisterValue dr6; + Status error = ReadRegister(GetDR(6), dr6); + if (error.Fail()) + is_hit = false; + else + is_hit = dr6.GetAsUInt64() & GetStatusBit(wp_index); + + return error; +} + +Status +NativeRegisterContextDBReg_x86::GetWatchpointHitIndex(uint32_t &wp_index, + lldb::addr_t trap_addr) { + uint32_t num_hw_wps = NumSupportedHardwareWatchpoints(); + for (wp_index = 0; wp_index < num_hw_wps; ++wp_index) { + bool is_hit; + Status error = IsWatchpointHit(wp_index, is_hit); + if (error.Fail()) { + wp_index = LLDB_INVALID_INDEX32; + return error; + } else if (is_hit) { + return error; + } + } + wp_index = LLDB_INVALID_INDEX32; + return Status(); +} + +Status NativeRegisterContextDBReg_x86::IsWatchpointVacant(uint32_t wp_index, + bool &is_vacant) { + if (wp_index >= NumSupportedHardwareWatchpoints()) + return Status("Watchpoint index out of range"); + + RegisterValue dr7; + Status error = ReadRegister(GetDR(7), dr7); + if (error.Fail()) + is_vacant = false; + else + is_vacant = !(dr7.GetAsUInt64() & GetEnableBit(wp_index)); + + return error; +} + +Status NativeRegisterContextDBReg_x86::SetHardwareWatchpointWithIndex( + lldb::addr_t addr, size_t size, uint32_t watch_flags, uint32_t wp_index) { + + if (wp_index >= NumSupportedHardwareWatchpoints()) + return Status("Watchpoint index out of range"); + + // Read only watchpoints aren't supported on x86_64. Fall back to read/write + // waitchpoints instead. + // TODO: Add logic to detect when a write happens and ignore that watchpoint + // hit. + if (watch_flags == 2) + watch_flags = 3; + + if (watch_flags != 1 && watch_flags != 3) + return Status("Invalid read/write bits for watchpoint"); + if (size != 1 && size != 2 && size != 4 && size != 8) + return Status("Invalid size for watchpoint"); + + bool is_vacant; + Status error = IsWatchpointVacant(wp_index, is_vacant); + if (error.Fail()) + return error; + if (!is_vacant) + return Status("Watchpoint index not vacant"); + + RegisterValue dr7, drN; + error = ReadRegister(GetDR(7), dr7); + if (error.Fail()) + return error; + error = ReadRegister(GetDR(wp_index), drN); + if (error.Fail()) + return error; + + uint64_t control_bits = dr7.GetAsUInt64() & ~GetWatchControlBitmask(wp_index); + control_bits |= GetEnableBit(wp_index) | + GetWatchTypeBits(watch_flags, wp_index) | + GetWatchSizeBits(size, wp_index); + + // Clear dr6 if address or bits changed (i.e. we're not reenabling the same + // watchpoint). This can not be done when clearing watchpoints since + // the gdb-remote protocol repeatedly clears and readds watchpoints on all + // program threads, effectively clearing pending events on NetBSD. + // NB: enable bits in dr7 are always 0 here since we're (re)adding it + if (drN.GetAsUInt64() != addr || + (dr7.GetAsUInt64() & GetWatchControlBitmask(wp_index)) != + (GetWatchTypeBits(watch_flags, wp_index) | + GetWatchSizeBits(size, wp_index))) { + ClearWatchpointHit(wp_index); + + // We skip update to drN if neither address nor mode changed. + error = WriteRegister(GetDR(wp_index), RegisterValue(addr)); + if (error.Fail()) + return error; + } + + error = WriteRegister(GetDR(7), RegisterValue(control_bits)); + if (error.Fail()) + return error; + + return error; +} + +bool NativeRegisterContextDBReg_x86::ClearHardwareWatchpoint( + uint32_t wp_index) { + if (wp_index >= NumSupportedHardwareWatchpoints()) + return false; + + RegisterValue dr7; + Status error = ReadRegister(GetDR(7), dr7); + if (error.Fail()) + return false; + + return WriteRegister(GetDR(7), RegisterValue(dr7.GetAsUInt64() & + ~GetBothEnableBitMask(wp_index))) + .Success(); +} + +Status NativeRegisterContextDBReg_x86::ClearWatchpointHit(uint32_t wp_index) { + if (wp_index >= NumSupportedHardwareWatchpoints()) + return Status("Watchpoint index out of range"); + + RegisterValue dr6; + Status error = ReadRegister(GetDR(6), dr6); + if (error.Fail()) + return error; + + return WriteRegister( + GetDR(6), RegisterValue(dr6.GetAsUInt64() & ~GetStatusBit(wp_index))); +} + +Status NativeRegisterContextDBReg_x86::ClearAllHardwareWatchpoints() { + RegisterValue dr7; + Status error = ReadRegister(GetDR(7), dr7); + if (error.Fail()) + return error; + return WriteRegister( + GetDR(7), + RegisterValue(dr7.GetAsUInt64() & ~watchpoint_all_control_bit_mask)); +} + +uint32_t NativeRegisterContextDBReg_x86::SetHardwareWatchpoint( + lldb::addr_t addr, size_t size, uint32_t watch_flags) { + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS)); + const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints(); + for (uint32_t wp_index = 0; wp_index < num_hw_watchpoints; ++wp_index) { + bool is_vacant; + Status error = IsWatchpointVacant(wp_index, is_vacant); + if (is_vacant) { + error = SetHardwareWatchpointWithIndex(addr, size, watch_flags, wp_index); + if (error.Success()) + return wp_index; + } + if (error.Fail() && log) { + LLDB_LOGF(log, "NativeRegisterContextDBReg_x86::%s Error: %s", + __FUNCTION__, error.AsCString()); + } + } + return LLDB_INVALID_INDEX32; +} + +lldb::addr_t +NativeRegisterContextDBReg_x86::GetWatchpointAddress(uint32_t wp_index) { + if (wp_index >= NumSupportedHardwareWatchpoints()) + return LLDB_INVALID_ADDRESS; + RegisterValue drN; + if (ReadRegister(GetDR(wp_index), drN).Fail()) + return LLDB_INVALID_ADDRESS; + return drN.GetAsUInt64(); +} + +uint32_t NativeRegisterContextDBReg_x86::NumSupportedHardwareWatchpoints() { + // Available debug address registers: dr0, dr1, dr2, dr3 + return 4; +} diff --git a/gnu/llvm/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_x86.h b/gnu/llvm/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_x86.h new file mode 100644 index 00000000000..a4ed8bfb97e --- /dev/null +++ b/gnu/llvm/lldb/source/Plugins/Process/Utility/NativeRegisterContextDBReg_x86.h @@ -0,0 +1,54 @@ +//===-- NativeRegisterContextDBReg_x86.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_NativeRegisterContextDBReg_x86_h +#define lldb_NativeRegisterContextDBReg_x86_h + +#include "Plugins/Process/Utility/NativeRegisterContextRegisterInfo.h" + +namespace lldb_private { + +class NativeRegisterContextDBReg_x86 + : public virtual NativeRegisterContextRegisterInfo { +public: + // NB: This constructor is here only because gcc<=6.5 requires a virtual base + // class initializer on abstract class (even though it is never used). It can + // be deleted once we move to gcc>=7.0. + NativeRegisterContextDBReg_x86(NativeThreadProtocol &thread) + : NativeRegisterContextRegisterInfo(thread, nullptr) {} + + Status IsWatchpointHit(uint32_t wp_index, bool &is_hit) override; + + Status GetWatchpointHitIndex(uint32_t &wp_index, + lldb::addr_t trap_addr) override; + + Status IsWatchpointVacant(uint32_t wp_index, bool &is_vacant) override; + + bool ClearHardwareWatchpoint(uint32_t wp_index) override; + + Status ClearWatchpointHit(uint32_t wp_index) override; + + Status ClearAllHardwareWatchpoints() override; + + Status SetHardwareWatchpointWithIndex(lldb::addr_t addr, size_t size, + uint32_t watch_flags, + uint32_t wp_index); + + uint32_t SetHardwareWatchpoint(lldb::addr_t addr, size_t size, + uint32_t watch_flags) override; + + lldb::addr_t GetWatchpointAddress(uint32_t wp_index) override; + + uint32_t NumSupportedHardwareWatchpoints() override; + + const RegisterInfo *GetDR(int num) const; +}; + +} // namespace lldb_private + +#endif // #ifndef lldb_NativeRegisterContextDBReg_x86_h diff --git a/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm.cpp b/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm.cpp index eef4541e7ed..7e38091738e 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm.cpp +++ b/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm.cpp @@ -922,7 +922,7 @@ RegisterContextDarwin_arm::RegisterContextDarwin_arm( } } -RegisterContextDarwin_arm::~RegisterContextDarwin_arm() {} +RegisterContextDarwin_arm::~RegisterContextDarwin_arm() = default; void RegisterContextDarwin_arm::InvalidateAllRegisters() { InvalidateAllRegisterStates(); diff --git a/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm64.cpp b/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm64.cpp index 9fc27527669..b98b2f35c23 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm64.cpp +++ b/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_arm64.cpp @@ -104,7 +104,7 @@ RegisterContextDarwin_arm64::RegisterContextDarwin_arm64( } } -RegisterContextDarwin_arm64::~RegisterContextDarwin_arm64() {} +RegisterContextDarwin_arm64::~RegisterContextDarwin_arm64() = default; void RegisterContextDarwin_arm64::InvalidateAllRegisters() { InvalidateAllRegisterStates(); diff --git a/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_i386.cpp b/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_i386.cpp index c5ebddc56b6..95f8132a990 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_i386.cpp +++ b/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_i386.cpp @@ -15,7 +15,7 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/Support/Compiler.h" -#include +#include #include @@ -405,7 +405,7 @@ RegisterContextDarwin_i386::RegisterContextDarwin_i386( } } -RegisterContextDarwin_i386::~RegisterContextDarwin_i386() {} +RegisterContextDarwin_i386::~RegisterContextDarwin_i386() = default; void RegisterContextDarwin_i386::InvalidateAllRegisters() { InvalidateAllRegisterStates(); diff --git a/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.cpp b/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.cpp index 38cd00aea9c..03e5ea424e3 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.cpp +++ b/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.cpp @@ -6,9 +6,9 @@ // //===----------------------------------------------------------------------===// -#include -#include -#include +#include +#include +#include #include @@ -467,7 +467,7 @@ RegisterContextDarwin_x86_64::RegisterContextDarwin_x86_64( } } -RegisterContextDarwin_x86_64::~RegisterContextDarwin_x86_64() {} +RegisterContextDarwin_x86_64::~RegisterContextDarwin_x86_64() = default; void RegisterContextDarwin_x86_64::InvalidateAllRegisters() { InvalidateAllRegisterStates(); diff --git a/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_i386.cpp b/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_i386.cpp index 10d346a3cb7..acebe9d5356 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_i386.cpp +++ b/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_i386.cpp @@ -35,7 +35,7 @@ struct GPR { uint32_t gs; }; -struct dbreg { +struct DBG { uint32_t dr[8]; /* debug registers */ /* Index 0-3: debug address registers */ /* Index 4-5: reserved */ @@ -48,10 +48,13 @@ using FPR_i386 = FXSAVE; struct UserArea { GPR gpr; FPR_i386 i387; + DBG dbg; }; #define DR_SIZE sizeof(uint32_t) -#define DR_OFFSET(reg_index) (LLVM_EXTENSION offsetof(dbreg, dr[reg_index])) +#define DR_OFFSET(reg_index) \ + (LLVM_EXTENSION offsetof(UserArea, dbg) + \ + LLVM_EXTENSION offsetof(DBG, dr[reg_index])) // Include RegisterInfos_i386 to declare our g_register_infos_i386 structure. #define DECLARE_REGISTER_INFOS_I386_STRUCT diff --git a/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_powerpc.cpp b/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_powerpc.cpp index 9fe6255d698..2991bd3c5f2 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_powerpc.cpp +++ b/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_powerpc.cpp @@ -178,7 +178,7 @@ RegisterContextFreeBSD_powerpc::RegisterContextFreeBSD_powerpc( const ArchSpec &target_arch) : RegisterInfoInterface(target_arch) {} -RegisterContextFreeBSD_powerpc::~RegisterContextFreeBSD_powerpc() {} +RegisterContextFreeBSD_powerpc::~RegisterContextFreeBSD_powerpc() = default; size_t RegisterContextFreeBSD_powerpc::GetGPRSize() const { // This is an 'abstract' base, so no GPR struct. @@ -197,7 +197,7 @@ RegisterContextFreeBSD_powerpc32::RegisterContextFreeBSD_powerpc32( const ArchSpec &target_arch) : RegisterContextFreeBSD_powerpc(target_arch) {} -RegisterContextFreeBSD_powerpc32::~RegisterContextFreeBSD_powerpc32() {} +RegisterContextFreeBSD_powerpc32::~RegisterContextFreeBSD_powerpc32() = default; size_t RegisterContextFreeBSD_powerpc32::GetGPRSize() const { return sizeof(GPR32); @@ -217,7 +217,7 @@ RegisterContextFreeBSD_powerpc64::RegisterContextFreeBSD_powerpc64( const ArchSpec &target_arch) : RegisterContextFreeBSD_powerpc(target_arch) {} -RegisterContextFreeBSD_powerpc64::~RegisterContextFreeBSD_powerpc64() {} +RegisterContextFreeBSD_powerpc64::~RegisterContextFreeBSD_powerpc64() = default; size_t RegisterContextFreeBSD_powerpc64::GetGPRSize() const { return sizeof(GPR64); diff --git a/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.cpp b/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.cpp index c1f390ade9b..e0f3971c6e2 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.cpp +++ b/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.cpp @@ -59,7 +59,9 @@ struct UserArea { DBG dbg; }; -#define DR_OFFSET(reg_index) (LLVM_EXTENSION offsetof(DBG, dr[reg_index])) +#define DR_OFFSET(reg_index) \ + (LLVM_EXTENSION offsetof(UserArea, dbg) + \ + LLVM_EXTENSION offsetof(DBG, dr[reg_index])) // Include RegisterInfos_x86_64 to declare our g_register_infos_x86_64 // structure. diff --git a/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextMach_arm.cpp b/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextMach_arm.cpp index 1394cb7f00a..067d1c3705e 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextMach_arm.cpp +++ b/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextMach_arm.cpp @@ -21,7 +21,7 @@ RegisterContextMach_arm::RegisterContextMach_arm(Thread &thread, uint32_t concrete_frame_idx) : RegisterContextDarwin_arm(thread, concrete_frame_idx) {} -RegisterContextMach_arm::~RegisterContextMach_arm() {} +RegisterContextMach_arm::~RegisterContextMach_arm() = default; int RegisterContextMach_arm::DoReadGPR(lldb::tid_t tid, int flavor, GPR &gpr) { mach_msg_type_number_t count = GPRWordCount; diff --git a/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextMach_arm.h b/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextMach_arm.h index e7c180dbdd2..1ceca65c97c 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextMach_arm.h +++ b/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextMach_arm.h @@ -19,21 +19,21 @@ public: virtual ~RegisterContextMach_arm(); protected: - virtual int DoReadGPR(lldb::tid_t tid, int flavor, GPR &gpr); + int DoReadGPR(lldb::tid_t tid, int flavor, GPR &gpr) override; - int DoReadFPU(lldb::tid_t tid, int flavor, FPU &fpu); + int DoReadFPU(lldb::tid_t tid, int flavor, FPU &fpu) override; - int DoReadEXC(lldb::tid_t tid, int flavor, EXC &exc); + int DoReadEXC(lldb::tid_t tid, int flavor, EXC &exc) override; - int DoReadDBG(lldb::tid_t tid, int flavor, DBG &dbg); + int DoReadDBG(lldb::tid_t tid, int flavor, DBG &dbg) override; - int DoWriteGPR(lldb::tid_t tid, int flavor, const GPR &gpr); + int DoWriteGPR(lldb::tid_t tid, int flavor, const GPR &gpr) override; - int DoWriteFPU(lldb::tid_t tid, int flavor, const FPU &fpu); + int DoWriteFPU(lldb::tid_t tid, int flavor, const FPU &fpu) override; - int DoWriteEXC(lldb::tid_t tid, int flavor, const EXC &exc); + int DoWriteEXC(lldb::tid_t tid, int flavor, const EXC &exc) override; - int DoWriteDBG(lldb::tid_t tid, int flavor, const DBG &dbg); + int DoWriteDBG(lldb::tid_t tid, int flavor, const DBG &dbg) override; }; #endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTMACH_ARM_H diff --git a/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextMach_i386.cpp b/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextMach_i386.cpp index b97166b6eeb..fe5cecef1b0 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextMach_i386.cpp +++ b/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextMach_i386.cpp @@ -19,7 +19,7 @@ RegisterContextMach_i386::RegisterContextMach_i386(Thread &thread, uint32_t concrete_frame_idx) : RegisterContextDarwin_i386(thread, concrete_frame_idx) {} -RegisterContextMach_i386::~RegisterContextMach_i386() {} +RegisterContextMach_i386::~RegisterContextMach_i386() = default; int RegisterContextMach_i386::DoReadGPR(lldb::tid_t tid, int flavor, GPR &gpr) { mach_msg_type_number_t count = GPRWordCount; diff --git a/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextMach_i386.h b/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextMach_i386.h index 09966be60c9..da5411eb2de 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextMach_i386.h +++ b/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextMach_i386.h @@ -19,17 +19,17 @@ public: virtual ~RegisterContextMach_i386(); protected: - virtual int DoReadGPR(lldb::tid_t tid, int flavor, GPR &gpr); + int DoReadGPR(lldb::tid_t tid, int flavor, GPR &gpr) override; - int DoReadFPU(lldb::tid_t tid, int flavor, FPU &fpu); + int DoReadFPU(lldb::tid_t tid, int flavor, FPU &fpu) override; - int DoReadEXC(lldb::tid_t tid, int flavor, EXC &exc); + int DoReadEXC(lldb::tid_t tid, int flavor, EXC &exc) override; - int DoWriteGPR(lldb::tid_t tid, int flavor, const GPR &gpr); + int DoWriteGPR(lldb::tid_t tid, int flavor, const GPR &gpr) override; - int DoWriteFPU(lldb::tid_t tid, int flavor, const FPU &fpu); + int DoWriteFPU(lldb::tid_t tid, int flavor, const FPU &fpu) override; - int DoWriteEXC(lldb::tid_t tid, int flavor, const EXC &exc); + int DoWriteEXC(lldb::tid_t tid, int flavor, const EXC &exc) override; }; #endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTMACH_I386_H diff --git a/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextMach_x86_64.cpp b/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextMach_x86_64.cpp index 8933f136789..a3d8c4f649d 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextMach_x86_64.cpp +++ b/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextMach_x86_64.cpp @@ -19,7 +19,7 @@ RegisterContextMach_x86_64::RegisterContextMach_x86_64( Thread &thread, uint32_t concrete_frame_idx) : RegisterContextDarwin_x86_64(thread, concrete_frame_idx) {} -RegisterContextMach_x86_64::~RegisterContextMach_x86_64() {} +RegisterContextMach_x86_64::~RegisterContextMach_x86_64() = default; int RegisterContextMach_x86_64::DoReadGPR(lldb::tid_t tid, int flavor, GPR &gpr) { diff --git a/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextMach_x86_64.h b/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextMach_x86_64.h index 2a8a2cca2f8..c131c8282bd 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextMach_x86_64.h +++ b/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextMach_x86_64.h @@ -20,17 +20,17 @@ public: virtual ~RegisterContextMach_x86_64(); protected: - virtual int DoReadGPR(lldb::tid_t tid, int flavor, GPR &gpr); + int DoReadGPR(lldb::tid_t tid, int flavor, GPR &gpr) override; - int DoReadFPU(lldb::tid_t tid, int flavor, FPU &fpu); + int DoReadFPU(lldb::tid_t tid, int flavor, FPU &fpu) override; - int DoReadEXC(lldb::tid_t tid, int flavor, EXC &exc); + int DoReadEXC(lldb::tid_t tid, int flavor, EXC &exc) override; - int DoWriteGPR(lldb::tid_t tid, int flavor, const GPR &gpr); + int DoWriteGPR(lldb::tid_t tid, int flavor, const GPR &gpr) override; - int DoWriteFPU(lldb::tid_t tid, int flavor, const FPU &fpu); + int DoWriteFPU(lldb::tid_t tid, int flavor, const FPU &fpu) override; - int DoWriteEXC(lldb::tid_t tid, int flavor, const EXC &exc); + int DoWriteEXC(lldb::tid_t tid, int flavor, const EXC &exc) override; }; #endif // LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTMACH_X86_64_H diff --git a/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextMemory.cpp b/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextMemory.cpp index f2d230b5405..c55ffebb03e 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextMemory.cpp +++ b/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextMemory.cpp @@ -39,7 +39,7 @@ RegisterContextMemory::RegisterContextMemory(Thread &thread, } // Destructor -RegisterContextMemory::~RegisterContextMemory() {} +RegisterContextMemory::~RegisterContextMemory() = default; void RegisterContextMemory::InvalidateAllRegisters() { if (m_reg_data_addr != LLDB_INVALID_ADDRESS) diff --git a/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm.cpp b/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm.cpp index 617893b6b3b..684176bccdf 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm.cpp +++ b/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm.cpp @@ -6,9 +6,9 @@ // //===----------------------------------------------------------------------===// +#include +#include #include -#include -#include #include "lldb/Target/Process.h" #include "lldb/Target/Target.h" @@ -25,109 +25,42 @@ using namespace lldb; using namespace lldb_private; -// arm general purpose registers. -const uint32_t g_gpr_regnums_arm[] = { - gpr_r0_arm, gpr_r1_arm, gpr_r2_arm, gpr_r3_arm, gpr_r4_arm, - gpr_r5_arm, gpr_r6_arm, gpr_r7_arm, gpr_r8_arm, gpr_r9_arm, - gpr_r10_arm, gpr_r11_arm, gpr_r12_arm, gpr_sp_arm, gpr_lr_arm, - gpr_pc_arm, gpr_cpsr_arm, - LLDB_INVALID_REGNUM // register sets need to end with this flag - -}; -static_assert(((sizeof g_gpr_regnums_arm / sizeof g_gpr_regnums_arm[0]) - 1) == - k_num_gpr_registers_arm, - "g_gpr_regnums_arm has wrong number of register infos"); - -// arm floating point registers. -static const uint32_t g_fpu_regnums_arm[] = { - fpu_s0_arm, fpu_s1_arm, fpu_s2_arm, fpu_s3_arm, fpu_s4_arm, - fpu_s5_arm, fpu_s6_arm, fpu_s7_arm, fpu_s8_arm, fpu_s9_arm, - fpu_s10_arm, fpu_s11_arm, fpu_s12_arm, fpu_s13_arm, fpu_s14_arm, - fpu_s15_arm, fpu_s16_arm, fpu_s17_arm, fpu_s18_arm, fpu_s19_arm, - fpu_s20_arm, fpu_s21_arm, fpu_s22_arm, fpu_s23_arm, fpu_s24_arm, - fpu_s25_arm, fpu_s26_arm, fpu_s27_arm, fpu_s28_arm, fpu_s29_arm, - fpu_s30_arm, fpu_s31_arm, fpu_fpscr_arm, fpu_d0_arm, fpu_d1_arm, - fpu_d2_arm, fpu_d3_arm, fpu_d4_arm, fpu_d5_arm, fpu_d6_arm, - fpu_d7_arm, fpu_d8_arm, fpu_d9_arm, fpu_d10_arm, fpu_d11_arm, - fpu_d12_arm, fpu_d13_arm, fpu_d14_arm, fpu_d15_arm, fpu_d16_arm, - fpu_d17_arm, fpu_d18_arm, fpu_d19_arm, fpu_d20_arm, fpu_d21_arm, - fpu_d22_arm, fpu_d23_arm, fpu_d24_arm, fpu_d25_arm, fpu_d26_arm, - fpu_d27_arm, fpu_d28_arm, fpu_d29_arm, fpu_d30_arm, fpu_d31_arm, - fpu_q0_arm, fpu_q1_arm, fpu_q2_arm, fpu_q3_arm, fpu_q4_arm, - fpu_q5_arm, fpu_q6_arm, fpu_q7_arm, fpu_q8_arm, fpu_q9_arm, - fpu_q10_arm, fpu_q11_arm, fpu_q12_arm, fpu_q13_arm, fpu_q14_arm, - fpu_q15_arm, - LLDB_INVALID_REGNUM // register sets need to end with this flag - -}; -static_assert(((sizeof g_fpu_regnums_arm / sizeof g_fpu_regnums_arm[0]) - 1) == - k_num_fpr_registers_arm, - "g_fpu_regnums_arm has wrong number of register infos"); - -// Number of register sets provided by this context. -enum { k_num_register_sets = 2 }; - -// Register sets for arm. -static const lldb_private::RegisterSet g_reg_sets_arm[k_num_register_sets] = { - {"General Purpose Registers", "gpr", k_num_gpr_registers_arm, - g_gpr_regnums_arm}, - {"Floating Point Registers", "fpu", k_num_fpr_registers_arm, - g_fpu_regnums_arm}}; - bool RegisterContextPOSIX_arm::IsGPR(unsigned reg) { - return reg <= m_reg_info.last_gpr; // GPR's come first. + if (m_register_info_up->GetRegisterSetFromRegisterIndex(reg) == + RegisterInfoPOSIX_arm::GPRegSet) + return true; + return false; } bool RegisterContextPOSIX_arm::IsFPR(unsigned reg) { - return (m_reg_info.first_fpr <= reg && reg <= m_reg_info.last_fpr); + if (m_register_info_up->GetRegisterSetFromRegisterIndex(reg) == + RegisterInfoPOSIX_arm::FPRegSet) + return true; + return false; } RegisterContextPOSIX_arm::RegisterContextPOSIX_arm( - lldb_private::Thread &thread, uint32_t concrete_frame_idx, - lldb_private::RegisterInfoInterface *register_info) - : lldb_private::RegisterContext(thread, concrete_frame_idx) { - m_register_info_up.reset(register_info); - - switch (register_info->m_target_arch.GetMachine()) { - case llvm::Triple::arm: - m_reg_info.num_registers = k_num_registers_arm; - m_reg_info.num_gpr_registers = k_num_gpr_registers_arm; - m_reg_info.num_fpr_registers = k_num_fpr_registers_arm; - m_reg_info.last_gpr = k_last_gpr_arm; - m_reg_info.first_fpr = k_first_fpr_arm; - m_reg_info.last_fpr = k_last_fpr_arm; - m_reg_info.first_fpr_v = fpu_s0_arm; - m_reg_info.last_fpr_v = fpu_s31_arm; - m_reg_info.gpr_flags = gpr_cpsr_arm; - break; - default: - assert(false && "Unhandled target architecture."); - break; - } - - ::memset(&m_fpr, 0, sizeof m_fpr); -} + lldb_private::Thread &thread, + std::unique_ptr register_info) + : lldb_private::RegisterContext(thread, 0), + m_register_info_up(std::move(register_info)) {} -RegisterContextPOSIX_arm::~RegisterContextPOSIX_arm() {} +RegisterContextPOSIX_arm::~RegisterContextPOSIX_arm() = default; void RegisterContextPOSIX_arm::Invalidate() {} void RegisterContextPOSIX_arm::InvalidateAllRegisters() {} unsigned RegisterContextPOSIX_arm::GetRegisterOffset(unsigned reg) { - assert(reg < m_reg_info.num_registers && "Invalid register number."); - return GetRegisterInfo()[reg].byte_offset; + return m_register_info_up->GetRegisterInfo()[reg].byte_offset; } unsigned RegisterContextPOSIX_arm::GetRegisterSize(unsigned reg) { - assert(reg < m_reg_info.num_registers && "Invalid register number."); - return GetRegisterInfo()[reg].byte_size; + return m_register_info_up->GetRegisterInfo()[reg].byte_size; } size_t RegisterContextPOSIX_arm::GetRegisterCount() { - size_t num_registers = - m_reg_info.num_gpr_registers + m_reg_info.num_fpr_registers; - return num_registers; + return m_register_info_up->GetRegisterCount(); } size_t RegisterContextPOSIX_arm::GetGPRSize() { @@ -143,41 +76,23 @@ const lldb_private::RegisterInfo *RegisterContextPOSIX_arm::GetRegisterInfo() { const lldb_private::RegisterInfo * RegisterContextPOSIX_arm::GetRegisterInfoAtIndex(size_t reg) { - if (reg < m_reg_info.num_registers) + if (reg < GetRegisterCount()) return &GetRegisterInfo()[reg]; - else - return nullptr; + + return nullptr; } size_t RegisterContextPOSIX_arm::GetRegisterSetCount() { - size_t sets = 0; - for (size_t set = 0; set < k_num_register_sets; ++set) { - if (IsRegisterSetAvailable(set)) - ++sets; - } - - return sets; + return m_register_info_up->GetRegisterSetCount(); } const lldb_private::RegisterSet * RegisterContextPOSIX_arm::GetRegisterSet(size_t set) { - if (IsRegisterSetAvailable(set)) { - switch (m_register_info_up->m_target_arch.GetMachine()) { - case llvm::Triple::arm: - return &g_reg_sets_arm[set]; - default: - assert(false && "Unhandled target architecture."); - return nullptr; - } - } - return nullptr; + return m_register_info_up->GetRegisterSet(set); } const char *RegisterContextPOSIX_arm::GetRegisterName(unsigned reg) { - assert(reg < m_reg_info.num_registers && "Invalid register offset."); - return GetRegisterInfo()[reg].name; -} - -bool RegisterContextPOSIX_arm::IsRegisterSetAvailable(size_t set_index) { - return set_index < k_num_register_sets; + if (reg < GetRegisterCount()) + return GetRegisterInfo()[reg].name; + return nullptr; } diff --git a/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm.h b/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm.h index d6967f05ed4..099c37d46f4 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm.h +++ b/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm.h @@ -10,17 +10,15 @@ #define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERCONTEXTPOSIX_ARM_H #include "RegisterInfoInterface.h" -#include "lldb-arm-register-enums.h" +#include "RegisterInfoPOSIX_arm.h" #include "lldb/Target/RegisterContext.h" #include "lldb/Utility/Log.h" -class ProcessMonitor; - class RegisterContextPOSIX_arm : public lldb_private::RegisterContext { public: - RegisterContextPOSIX_arm(lldb_private::Thread &thread, - uint32_t concrete_frame_idx, - lldb_private::RegisterInfoInterface *register_info); + RegisterContextPOSIX_arm( + lldb_private::Thread &thread, + std::unique_ptr register_info); ~RegisterContextPOSIX_arm() override; @@ -45,46 +43,7 @@ public: const char *GetRegisterName(unsigned reg); protected: - struct RegInfo { - uint32_t num_registers; - uint32_t num_gpr_registers; - uint32_t num_fpr_registers; - - uint32_t last_gpr; - uint32_t first_fpr; - uint32_t last_fpr; - - uint32_t first_fpr_v; - uint32_t last_fpr_v; - - uint32_t gpr_flags; - }; - - struct QReg { - uint8_t bytes[16]; - }; - - struct FPU { - union { - uint32_t s[32]; - uint64_t d[32]; - QReg q[16]; // the 128-bit NEON registers - } floats; - uint32_t fpscr; - }; - - uint32_t m_gpr_arm[lldb_private::k_num_gpr_registers_arm]; // 32-bit general - // purpose - // registers. - RegInfo m_reg_info; - struct RegisterContextPOSIX_arm::FPU - m_fpr; // floating-point registers including extended register sets. - std::unique_ptr - m_register_info_up; // Register Info Interface (FreeBSD or Linux) - - // Determines if an extended register set is supported on the processor - // running the inferior process. - virtual bool IsRegisterSetAvailable(size_t set_index); + std::unique_ptr m_register_info_up; virtual const lldb_private::RegisterInfo *GetRegisterInfo(); @@ -92,6 +51,8 @@ protected: bool IsFPR(unsigned reg); + size_t GetFPUSize() { return sizeof(RegisterInfoPOSIX_arm::FPU); } + virtual bool ReadGPR() = 0; virtual bool ReadFPR() = 0; virtual bool WriteGPR() = 0; diff --git a/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.cpp b/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.cpp index 8ef587f13e3..676e450c484 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.cpp +++ b/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.cpp @@ -6,9 +6,9 @@ // //===----------------------------------------------------------------------===// +#include +#include #include -#include -#include #include "lldb/Target/Process.h" #include "lldb/Target/Target.h" @@ -39,16 +39,21 @@ bool RegisterContextPOSIX_arm64::IsFPR(unsigned reg) { return false; } +bool RegisterContextPOSIX_arm64::IsSVE(unsigned reg) const { + return m_register_info_up->IsSVEReg(reg); +} + +bool RegisterContextPOSIX_arm64::IsPAuth(unsigned reg) const { + return m_register_info_up->IsPAuthReg(reg); +} + RegisterContextPOSIX_arm64::RegisterContextPOSIX_arm64( lldb_private::Thread &thread, std::unique_ptr register_info) : lldb_private::RegisterContext(thread, 0), - m_register_info_up(std::move(register_info)) { + m_register_info_up(std::move(register_info)) {} - ::memset(&m_fpr, 0, sizeof m_fpr); -} - -RegisterContextPOSIX_arm64::~RegisterContextPOSIX_arm64() {} +RegisterContextPOSIX_arm64::~RegisterContextPOSIX_arm64() = default; void RegisterContextPOSIX_arm64::Invalidate() {} @@ -82,8 +87,8 @@ const lldb_private::RegisterInfo * RegisterContextPOSIX_arm64::GetRegisterInfoAtIndex(size_t reg) { if (reg < GetRegisterCount()) return &GetRegisterInfo()[reg]; - else - return nullptr; + + return nullptr; } size_t RegisterContextPOSIX_arm64::GetRegisterSetCount() { diff --git a/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.h b/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.h index c2d5aee7f73..7c301599d3a 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.h +++ b/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_arm64.h @@ -11,12 +11,9 @@ #include "RegisterInfoInterface.h" #include "RegisterInfoPOSIX_arm64.h" -#include "lldb-arm64-register-enums.h" #include "lldb/Target/RegisterContext.h" #include "lldb/Utility/Log.h" -class ProcessMonitor; - class RegisterContextPOSIX_arm64 : public lldb_private::RegisterContext { public: RegisterContextPOSIX_arm64( @@ -46,13 +43,6 @@ public: const char *GetRegisterName(unsigned reg); protected: - uint64_t m_gpr_arm64[lldb_private::k_num_gpr_registers_arm64]; // 64-bit - // general - // purpose - // registers. - - struct RegisterInfoPOSIX_arm64::FPU - m_fpr; // floating-point registers including extended register sets. std::unique_ptr m_register_info_up; virtual const lldb_private::RegisterInfo *GetRegisterInfo(); @@ -63,6 +53,24 @@ protected: size_t GetFPUSize() { return sizeof(RegisterInfoPOSIX_arm64::FPU); } + bool IsSVE(unsigned reg) const; + bool IsPAuth(unsigned reg) const; + + bool IsSVEZ(unsigned reg) const { return m_register_info_up->IsSVEZReg(reg); } + bool IsSVEP(unsigned reg) const { return m_register_info_up->IsSVEPReg(reg); } + bool IsSVEVG(unsigned reg) const { + return m_register_info_up->IsSVERegVG(reg); + } + + uint32_t GetRegNumSVEZ0() const { + return m_register_info_up->GetRegNumSVEZ0(); + } + uint32_t GetRegNumSVEFFR() const { + return m_register_info_up->GetRegNumSVEFFR(); + } + uint32_t GetRegNumFPCR() const { return m_register_info_up->GetRegNumFPCR(); } + uint32_t GetRegNumFPSR() const { return m_register_info_up->GetRegNumFPSR(); } + virtual bool ReadGPR() = 0; virtual bool ReadFPR() = 0; virtual bool WriteGPR() = 0; diff --git a/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_mips64.cpp b/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_mips64.cpp index c41c4bd7a7e..9e05737d8e6 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_mips64.cpp +++ b/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_mips64.cpp @@ -6,9 +6,9 @@ // //===----------------------------------------------------------------------===// +#include +#include #include -#include -#include #include "lldb/Target/Process.h" #include "lldb/Target/Target.h" @@ -22,8 +22,6 @@ #include "RegisterContextPOSIX_mips64.h" #include "RegisterContextFreeBSD_mips64.h" -#include "RegisterContextLinux_mips64.h" -#include "RegisterContextLinux_mips.h" using namespace lldb_private; using namespace lldb; @@ -60,7 +58,7 @@ RegisterContextPOSIX_mips64::RegisterContextPOSIX_mips64( m_registers_count[msa_registers_count])); } -RegisterContextPOSIX_mips64::~RegisterContextPOSIX_mips64() {} +RegisterContextPOSIX_mips64::~RegisterContextPOSIX_mips64() = default; void RegisterContextPOSIX_mips64::Invalidate() {} @@ -102,17 +100,6 @@ RegisterContextPOSIX_mips64::GetRegisterInfoAtIndex(size_t reg) { size_t RegisterContextPOSIX_mips64::GetRegisterSetCount() { ArchSpec target_arch = m_register_info_up->GetTargetArchitecture(); switch (target_arch.GetTriple().getOS()) { - case llvm::Triple::Linux: { - if ((target_arch.GetMachine() == llvm::Triple::mipsel) || - (target_arch.GetMachine() == llvm::Triple::mips)) { - const auto *context = static_cast( - m_register_info_up.get()); - return context->GetRegisterSetCount(); - } - const auto *context = static_cast( - m_register_info_up.get()); - return context->GetRegisterSetCount(); - } default: { const auto *context = static_cast( m_register_info_up.get()); @@ -125,17 +112,6 @@ size_t RegisterContextPOSIX_mips64::GetRegisterSetCount() { const RegisterSet *RegisterContextPOSIX_mips64::GetRegisterSet(size_t set) { ArchSpec target_arch = m_register_info_up->GetTargetArchitecture(); switch (target_arch.GetTriple().getOS()) { - case llvm::Triple::Linux: { - if ((target_arch.GetMachine() == llvm::Triple::mipsel) || - (target_arch.GetMachine() == llvm::Triple::mips)) { - const auto *context = static_cast( - m_register_info_up.get()); - return context->GetRegisterSet(set); - } - const auto *context = static_cast( - m_register_info_up.get()); - return context->GetRegisterSet(set); - } default: { const auto *context = static_cast( m_register_info_up.get()); diff --git a/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_mips64.h b/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_mips64.h index 1843a2a6aff..b66dc3f4452 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_mips64.h +++ b/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_mips64.h @@ -14,10 +14,6 @@ #include "lldb/Target/RegisterContext.h" #include "lldb/Utility/Log.h" -using namespace lldb_private; - -class ProcessMonitor; - class RegisterContextPOSIX_mips64 : public lldb_private::RegisterContext { public: diff --git a/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_powerpc.cpp b/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_powerpc.cpp index cd65b96d373..cffd2865e38 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_powerpc.cpp +++ b/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_powerpc.cpp @@ -6,9 +6,9 @@ // //===----------------------------------------------------------------------===// +#include +#include #include -#include -#include #include "lldb/Target/Process.h" #include "lldb/Target/Target.h" @@ -95,7 +95,7 @@ RegisterContextPOSIX_powerpc::RegisterContextPOSIX_powerpc( m_register_info_up.reset(register_info); } -RegisterContextPOSIX_powerpc::~RegisterContextPOSIX_powerpc() {} +RegisterContextPOSIX_powerpc::~RegisterContextPOSIX_powerpc() = default; void RegisterContextPOSIX_powerpc::Invalidate() {} diff --git a/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_powerpc.h b/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_powerpc.h index e2c33461c8f..5dd8c890da6 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_powerpc.h +++ b/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_powerpc.h @@ -14,8 +14,6 @@ #include "lldb/Target/RegisterContext.h" #include "lldb/Utility/Log.h" -class ProcessMonitor; - // Internal codes for all powerpc registers. enum { k_first_gpr_powerpc, diff --git a/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_ppc64le.cpp b/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_ppc64le.cpp index f670be2ef3c..f70ddeba209 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_ppc64le.cpp +++ b/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_ppc64le.cpp @@ -6,9 +6,9 @@ // //===----------------------------------------------------------------------===// +#include +#include #include -#include -#include #include "lldb/Target/Process.h" #include "lldb/Target/Target.h" diff --git a/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_s390x.cpp b/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_s390x.cpp index e746ec642b3..21c8160e5b4 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_s390x.cpp +++ b/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_s390x.cpp @@ -6,9 +6,9 @@ // //===----------------------------------------------------------------------===// +#include +#include #include -#include -#include #include "lldb/Target/Process.h" #include "lldb/Target/Target.h" @@ -98,7 +98,7 @@ RegisterContextPOSIX_s390x::RegisterContextPOSIX_s390x( } } -RegisterContextPOSIX_s390x::~RegisterContextPOSIX_s390x() {} +RegisterContextPOSIX_s390x::~RegisterContextPOSIX_s390x() = default; void RegisterContextPOSIX_s390x::Invalidate() {} diff --git a/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_s390x.h b/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_s390x.h index 7df732d13ff..7027af04f0b 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_s390x.h +++ b/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_s390x.h @@ -15,8 +15,6 @@ #include "lldb/Target/RegisterContext.h" #include "lldb/Utility/Log.h" -class ProcessMonitor; - class RegisterContextPOSIX_s390x : public lldb_private::RegisterContext { public: RegisterContextPOSIX_s390x( diff --git a/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_x86.cpp b/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_x86.cpp index ac271a90d6a..67e03ff1ea3 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_x86.cpp +++ b/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_x86.cpp @@ -6,9 +6,9 @@ // //===----------------------------------------------------------------------===// +#include +#include #include -#include -#include #include "lldb/Target/Process.h" #include "lldb/Target/Target.h" @@ -119,20 +119,21 @@ static_assert((sizeof(g_gpr_regnums_x86_64) / sizeof(g_gpr_regnums_x86_64[0])) - "g_gpr_regnums_x86_64 has wrong number of register infos"); static const uint32_t g_lldb_regnums_x86_64[] = { - lldb_fctrl_x86_64, lldb_fstat_x86_64, lldb_ftag_x86_64, - lldb_fop_x86_64, lldb_fiseg_x86_64, lldb_fioff_x86_64, - lldb_foseg_x86_64, lldb_fooff_x86_64, lldb_mxcsr_x86_64, - lldb_mxcsrmask_x86_64, lldb_st0_x86_64, lldb_st1_x86_64, - lldb_st2_x86_64, lldb_st3_x86_64, lldb_st4_x86_64, - lldb_st5_x86_64, lldb_st6_x86_64, lldb_st7_x86_64, - lldb_mm0_x86_64, lldb_mm1_x86_64, lldb_mm2_x86_64, - lldb_mm3_x86_64, lldb_mm4_x86_64, lldb_mm5_x86_64, - lldb_mm6_x86_64, lldb_mm7_x86_64, lldb_xmm0_x86_64, - lldb_xmm1_x86_64, lldb_xmm2_x86_64, lldb_xmm3_x86_64, - lldb_xmm4_x86_64, lldb_xmm5_x86_64, lldb_xmm6_x86_64, - lldb_xmm7_x86_64, lldb_xmm8_x86_64, lldb_xmm9_x86_64, - lldb_xmm10_x86_64, lldb_xmm11_x86_64, lldb_xmm12_x86_64, - lldb_xmm13_x86_64, lldb_xmm14_x86_64, lldb_xmm15_x86_64, + lldb_fctrl_x86_64, lldb_fstat_x86_64, lldb_ftag_x86_64, + lldb_fop_x86_64, lldb_fiseg_x86_64, lldb_fioff_x86_64, + lldb_fip_x86_64, lldb_foseg_x86_64, lldb_fooff_x86_64, + lldb_fdp_x86_64, lldb_mxcsr_x86_64, lldb_mxcsrmask_x86_64, + lldb_st0_x86_64, lldb_st1_x86_64, lldb_st2_x86_64, + lldb_st3_x86_64, lldb_st4_x86_64, lldb_st5_x86_64, + lldb_st6_x86_64, lldb_st7_x86_64, lldb_mm0_x86_64, + lldb_mm1_x86_64, lldb_mm2_x86_64, lldb_mm3_x86_64, + lldb_mm4_x86_64, lldb_mm5_x86_64, lldb_mm6_x86_64, + lldb_mm7_x86_64, lldb_xmm0_x86_64, lldb_xmm1_x86_64, + lldb_xmm2_x86_64, lldb_xmm3_x86_64, lldb_xmm4_x86_64, + lldb_xmm5_x86_64, lldb_xmm6_x86_64, lldb_xmm7_x86_64, + lldb_xmm8_x86_64, lldb_xmm9_x86_64, lldb_xmm10_x86_64, + lldb_xmm11_x86_64, lldb_xmm12_x86_64, lldb_xmm13_x86_64, + lldb_xmm14_x86_64, lldb_xmm15_x86_64, LLDB_INVALID_REGNUM // Register sets must be terminated with // LLDB_INVALID_REGNUM. }; @@ -275,6 +276,84 @@ uint32_t RegisterContextPOSIX_x86::g_invalidate_r15[] = { lldb_r15_x86_64, lldb_r15d_x86_64, lldb_r15w_x86_64, lldb_r15l_x86_64, LLDB_INVALID_REGNUM}; +uint32_t RegisterContextPOSIX_x86::g_contained_fip[] = {lldb_fip_x86_64, + LLDB_INVALID_REGNUM}; +uint32_t RegisterContextPOSIX_x86::g_contained_fdp[] = {lldb_fdp_x86_64, + LLDB_INVALID_REGNUM}; + +uint32_t RegisterContextPOSIX_x86::g_invalidate_fip[] = { + lldb_fip_x86_64, lldb_fioff_x86_64, lldb_fiseg_x86_64, LLDB_INVALID_REGNUM}; +uint32_t RegisterContextPOSIX_x86::g_invalidate_fdp[] = { + lldb_fdp_x86_64, lldb_fooff_x86_64, lldb_foseg_x86_64, LLDB_INVALID_REGNUM}; + +uint32_t RegisterContextPOSIX_x86::g_contained_st0_32[] = {lldb_st0_i386, + LLDB_INVALID_REGNUM}; +uint32_t RegisterContextPOSIX_x86::g_contained_st1_32[] = {lldb_st1_i386, + LLDB_INVALID_REGNUM}; +uint32_t RegisterContextPOSIX_x86::g_contained_st2_32[] = {lldb_st2_i386, + LLDB_INVALID_REGNUM}; +uint32_t RegisterContextPOSIX_x86::g_contained_st3_32[] = {lldb_st3_i386, + LLDB_INVALID_REGNUM}; +uint32_t RegisterContextPOSIX_x86::g_contained_st4_32[] = {lldb_st4_i386, + LLDB_INVALID_REGNUM}; +uint32_t RegisterContextPOSIX_x86::g_contained_st5_32[] = {lldb_st5_i386, + LLDB_INVALID_REGNUM}; +uint32_t RegisterContextPOSIX_x86::g_contained_st6_32[] = {lldb_st6_i386, + LLDB_INVALID_REGNUM}; +uint32_t RegisterContextPOSIX_x86::g_contained_st7_32[] = {lldb_st7_i386, + LLDB_INVALID_REGNUM}; + +uint32_t RegisterContextPOSIX_x86::g_invalidate_st0_32[] = { + lldb_st0_i386, lldb_mm0_i386, LLDB_INVALID_REGNUM}; +uint32_t RegisterContextPOSIX_x86::g_invalidate_st1_32[] = { + lldb_st1_i386, lldb_mm1_i386, LLDB_INVALID_REGNUM}; +uint32_t RegisterContextPOSIX_x86::g_invalidate_st2_32[] = { + lldb_st2_i386, lldb_mm2_i386, LLDB_INVALID_REGNUM}; +uint32_t RegisterContextPOSIX_x86::g_invalidate_st3_32[] = { + lldb_st3_i386, lldb_mm3_i386, LLDB_INVALID_REGNUM}; +uint32_t RegisterContextPOSIX_x86::g_invalidate_st4_32[] = { + lldb_st4_i386, lldb_mm4_i386, LLDB_INVALID_REGNUM}; +uint32_t RegisterContextPOSIX_x86::g_invalidate_st5_32[] = { + lldb_st5_i386, lldb_mm5_i386, LLDB_INVALID_REGNUM}; +uint32_t RegisterContextPOSIX_x86::g_invalidate_st6_32[] = { + lldb_st6_i386, lldb_mm6_i386, LLDB_INVALID_REGNUM}; +uint32_t RegisterContextPOSIX_x86::g_invalidate_st7_32[] = { + lldb_st7_i386, lldb_mm7_i386, LLDB_INVALID_REGNUM}; + +uint32_t RegisterContextPOSIX_x86::g_contained_st0_64[] = {lldb_st0_x86_64, + LLDB_INVALID_REGNUM}; +uint32_t RegisterContextPOSIX_x86::g_contained_st1_64[] = {lldb_st1_x86_64, + LLDB_INVALID_REGNUM}; +uint32_t RegisterContextPOSIX_x86::g_contained_st2_64[] = {lldb_st2_x86_64, + LLDB_INVALID_REGNUM}; +uint32_t RegisterContextPOSIX_x86::g_contained_st3_64[] = {lldb_st3_x86_64, + LLDB_INVALID_REGNUM}; +uint32_t RegisterContextPOSIX_x86::g_contained_st4_64[] = {lldb_st4_x86_64, + LLDB_INVALID_REGNUM}; +uint32_t RegisterContextPOSIX_x86::g_contained_st5_64[] = {lldb_st5_x86_64, + LLDB_INVALID_REGNUM}; +uint32_t RegisterContextPOSIX_x86::g_contained_st6_64[] = {lldb_st6_x86_64, + LLDB_INVALID_REGNUM}; +uint32_t RegisterContextPOSIX_x86::g_contained_st7_64[] = {lldb_st7_x86_64, + LLDB_INVALID_REGNUM}; + +uint32_t RegisterContextPOSIX_x86::g_invalidate_st0_64[] = { + lldb_st0_x86_64, lldb_mm0_x86_64, LLDB_INVALID_REGNUM}; +uint32_t RegisterContextPOSIX_x86::g_invalidate_st1_64[] = { + lldb_st1_x86_64, lldb_mm1_x86_64, LLDB_INVALID_REGNUM}; +uint32_t RegisterContextPOSIX_x86::g_invalidate_st2_64[] = { + lldb_st2_x86_64, lldb_mm2_x86_64, LLDB_INVALID_REGNUM}; +uint32_t RegisterContextPOSIX_x86::g_invalidate_st3_64[] = { + lldb_st3_x86_64, lldb_mm3_x86_64, LLDB_INVALID_REGNUM}; +uint32_t RegisterContextPOSIX_x86::g_invalidate_st4_64[] = { + lldb_st4_x86_64, lldb_mm4_x86_64, LLDB_INVALID_REGNUM}; +uint32_t RegisterContextPOSIX_x86::g_invalidate_st5_64[] = { + lldb_st5_x86_64, lldb_mm5_x86_64, LLDB_INVALID_REGNUM}; +uint32_t RegisterContextPOSIX_x86::g_invalidate_st6_64[] = { + lldb_st6_x86_64, lldb_mm6_x86_64, LLDB_INVALID_REGNUM}; +uint32_t RegisterContextPOSIX_x86::g_invalidate_st7_64[] = { + lldb_st7_x86_64, lldb_mm7_x86_64, LLDB_INVALID_REGNUM}; + // Number of register sets provided by this context. enum { k_num_extended_register_sets = 1, k_num_register_sets = 3 }; @@ -369,7 +448,7 @@ RegisterContextPOSIX_x86::RegisterContextPOSIX_x86( m_fpr_type = eNotValid; } -RegisterContextPOSIX_x86::~RegisterContextPOSIX_x86() {} +RegisterContextPOSIX_x86::~RegisterContextPOSIX_x86() = default; RegisterContextPOSIX_x86::FPRType RegisterContextPOSIX_x86::GetFPRType() { if (m_fpr_type == eNotValid) { diff --git a/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_x86.h b/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_x86.h index c4886ae618a..d6672835b4a 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_x86.h +++ b/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextPOSIX_x86.h @@ -15,8 +15,6 @@ #include "lldb/Target/RegisterContext.h" #include "lldb/Utility/Log.h" -class ProcessMonitor; - class RegisterContextPOSIX_x86 : public lldb_private::RegisterContext { public: RegisterContextPOSIX_x86(lldb_private::Thread &thread, @@ -108,6 +106,48 @@ public: static uint32_t g_invalidate_r14[]; static uint32_t g_invalidate_r15[]; + static uint32_t g_contained_fip[]; + static uint32_t g_contained_fdp[]; + + static uint32_t g_invalidate_fip[]; + static uint32_t g_invalidate_fdp[]; + + static uint32_t g_contained_st0_32[]; + static uint32_t g_contained_st1_32[]; + static uint32_t g_contained_st2_32[]; + static uint32_t g_contained_st3_32[]; + static uint32_t g_contained_st4_32[]; + static uint32_t g_contained_st5_32[]; + static uint32_t g_contained_st6_32[]; + static uint32_t g_contained_st7_32[]; + + static uint32_t g_invalidate_st0_32[]; + static uint32_t g_invalidate_st1_32[]; + static uint32_t g_invalidate_st2_32[]; + static uint32_t g_invalidate_st3_32[]; + static uint32_t g_invalidate_st4_32[]; + static uint32_t g_invalidate_st5_32[]; + static uint32_t g_invalidate_st6_32[]; + static uint32_t g_invalidate_st7_32[]; + + static uint32_t g_contained_st0_64[]; + static uint32_t g_contained_st1_64[]; + static uint32_t g_contained_st2_64[]; + static uint32_t g_contained_st3_64[]; + static uint32_t g_contained_st4_64[]; + static uint32_t g_contained_st5_64[]; + static uint32_t g_contained_st6_64[]; + static uint32_t g_contained_st7_64[]; + + static uint32_t g_invalidate_st0_64[]; + static uint32_t g_invalidate_st1_64[]; + static uint32_t g_invalidate_st2_64[]; + static uint32_t g_invalidate_st3_64[]; + static uint32_t g_invalidate_st4_64[]; + static uint32_t g_invalidate_st5_64[]; + static uint32_t g_invalidate_st6_64[]; + static uint32_t g_invalidate_st7_64[]; + protected: struct RegInfo { uint32_t num_registers; diff --git a/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextThreadMemory.cpp b/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextThreadMemory.cpp index 31e2944084e..4866cbd235e 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextThreadMemory.cpp +++ b/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContextThreadMemory.cpp @@ -22,7 +22,7 @@ RegisterContextThreadMemory::RegisterContextThreadMemory( : RegisterContext(thread, 0), m_thread_wp(thread.shared_from_this()), m_reg_ctx_sp(), m_register_data_addr(register_data_addr), m_stop_id(0) {} -RegisterContextThreadMemory::~RegisterContextThreadMemory() {} +RegisterContextThreadMemory::~RegisterContextThreadMemory() = default; void RegisterContextThreadMemory::UpdateRegisterContext() { ThreadSP thread_sp(m_thread_wp.lock()); diff --git a/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContext_x86.cpp b/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContext_x86.cpp new file mode 100644 index 00000000000..b21c72bd962 --- /dev/null +++ b/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContext_x86.cpp @@ -0,0 +1,58 @@ +//===-- RegisterContext_x86.cpp ---------------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#include "RegisterContext_x86.h" + +using namespace lldb_private; + +// Convert the 8-bit abridged FPU Tag Word (as found in FXSAVE) to the full +// 16-bit FPU Tag Word (as found in FSAVE, and used by gdb protocol). This +// requires knowing the values of the ST(i) registers and the FPU Status Word. +uint16_t lldb_private::AbridgedToFullTagWord(uint8_t abridged_tw, uint16_t sw, + llvm::ArrayRef st_regs) { + // Tag word is using internal FPU register numbering rather than ST(i). + // Mapping to ST(i): i = FPU regno - TOP (Status Word, bits 11:13). + // Here we start with FPU reg 7 and go down. + int st = 7 - ((sw >> 11) & 7); + uint16_t tw = 0; + for (uint8_t mask = 0x80; mask != 0; mask >>= 1) { + tw <<= 2; + if (abridged_tw & mask) { + // The register is non-empty, so we need to check the value of ST(i). + uint16_t exp = + st_regs[st].comp.sign_exp & 0x7fff; // Discard the sign bit. + if (exp == 0) { + if (st_regs[st].comp.mantissa == 0) + tw |= 1; // Zero + else + tw |= 2; // Denormal + } else if (exp == 0x7fff) + tw |= 2; // Infinity or NaN + // 0 if normal number + } else + tw |= 3; // Empty register + + // Rotate ST down. + st = (st - 1) & 7; + } + + return tw; +} + +// Convert the 16-bit FPU Tag Word to the abridged 8-bit value, to be written +// into FXSAVE. +uint8_t lldb_private::FullToAbridgedTagWord(uint16_t tw) { + uint8_t abridged_tw = 0; + for (uint16_t mask = 0xc000; mask != 0; mask >>= 2) { + abridged_tw <<= 1; + // full TW uses 11 for empty registers, aTW uses 0 + if ((tw & mask) != mask) + abridged_tw |= 1; + } + return abridged_tw; +} diff --git a/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContext_x86.h b/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContext_x86.h index 27a1bad4d53..76e004ce0ce 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContext_x86.h +++ b/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterContext_x86.h @@ -12,6 +12,7 @@ #include #include +#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/BitmaskEnum.h" #include "llvm/Support/Compiler.h" @@ -239,10 +240,23 @@ enum { // Generic floating-point registers +LLVM_PACKED_START +struct MMSRegComp { + uint64_t mantissa; + uint16_t sign_exp; +}; + struct MMSReg { - uint8_t bytes[10]; + union { + uint8_t bytes[10]; + MMSRegComp comp; + }; uint8_t pad[6]; }; +LLVM_PACKED_END + +static_assert(sizeof(MMSRegComp) == 10, "MMSRegComp is not 10 bytes of size"); +static_assert(sizeof(MMSReg) == 16, "MMSReg is not 16 bytes of size"); struct XMMReg { uint8_t bytes[16]; // 128-bits for each XMM register @@ -369,6 +383,10 @@ inline void YMMToXState(const YMMReg& input, void* xmm_bytes, void* ymmh_bytes) ::memcpy(ymmh_bytes, input.bytes + sizeof(XMMReg), sizeof(YMMHReg)); } +uint16_t AbridgedToFullTagWord(uint8_t abridged_tw, uint16_t sw, + llvm::ArrayRef st_regs); +uint8_t FullToAbridgedTagWord(uint16_t tw); + } // namespace lldb_private #endif diff --git a/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterInfoInterface.h b/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterInfoInterface.h index 88c2ae7c501..c05438338c8 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterInfoInterface.h +++ b/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterInfoInterface.h @@ -22,7 +22,7 @@ class RegisterInfoInterface { public: RegisterInfoInterface(const lldb_private::ArchSpec &target_arch) : m_target_arch(target_arch) {} - virtual ~RegisterInfoInterface() {} + virtual ~RegisterInfoInterface() = default; virtual size_t GetGPRSize() const = 0; diff --git a/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm.cpp b/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm.cpp index 8fc4d5282b0..63461f7ab2d 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm.cpp +++ b/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm.cpp @@ -7,7 +7,7 @@ //===---------------------------------------------------------------------===// #include -#include +#include #include #include "lldb/lldb-defines.h" @@ -71,9 +71,87 @@ GetRegisterInfoCount(const lldb_private::ArchSpec &target_arch) { } } +// Number of register sets provided by this context. +enum { + k_num_gpr_registers = gpr_cpsr - gpr_r0 + 1, + k_num_fpr_registers = fpu_q15 - fpu_s0 + 1, + k_num_register_sets = 2 +}; + +// arm general purpose registers. +static const uint32_t g_gpr_regnums_arm[] = { + gpr_r0, gpr_r1, + gpr_r2, gpr_r3, + gpr_r4, gpr_r5, + gpr_r6, gpr_r7, + gpr_r8, gpr_r9, + gpr_r10, gpr_r11, + gpr_r12, gpr_sp, + gpr_lr, gpr_pc, + gpr_cpsr, LLDB_INVALID_REGNUM // register sets need to end with this flag +}; +static_assert(((sizeof g_gpr_regnums_arm / sizeof g_gpr_regnums_arm[0]) - 1) == + k_num_gpr_registers, + "g_gpr_regnums_arm has wrong number of register infos"); + +// arm floating point registers. +static const uint32_t g_fpu_regnums_arm[] = { + fpu_s0, fpu_s1, + fpu_s2, fpu_s3, + fpu_s4, fpu_s5, + fpu_s6, fpu_s7, + fpu_s8, fpu_s9, + fpu_s10, fpu_s11, + fpu_s12, fpu_s13, + fpu_s14, fpu_s15, + fpu_s16, fpu_s17, + fpu_s18, fpu_s19, + fpu_s20, fpu_s21, + fpu_s22, fpu_s23, + fpu_s24, fpu_s25, + fpu_s26, fpu_s27, + fpu_s28, fpu_s29, + fpu_s30, fpu_s31, + fpu_fpscr, fpu_d0, + fpu_d1, fpu_d2, + fpu_d3, fpu_d4, + fpu_d5, fpu_d6, + fpu_d7, fpu_d8, + fpu_d9, fpu_d10, + fpu_d11, fpu_d12, + fpu_d13, fpu_d14, + fpu_d15, fpu_d16, + fpu_d17, fpu_d18, + fpu_d19, fpu_d20, + fpu_d21, fpu_d22, + fpu_d23, fpu_d24, + fpu_d25, fpu_d26, + fpu_d27, fpu_d28, + fpu_d29, fpu_d30, + fpu_d31, fpu_q0, + fpu_q1, fpu_q2, + fpu_q3, fpu_q4, + fpu_q5, fpu_q6, + fpu_q7, fpu_q8, + fpu_q9, fpu_q10, + fpu_q11, fpu_q12, + fpu_q13, fpu_q14, + fpu_q15, LLDB_INVALID_REGNUM // register sets need to end with this flag +}; +static_assert(((sizeof g_fpu_regnums_arm / sizeof g_fpu_regnums_arm[0]) - 1) == + k_num_fpr_registers, + "g_fpu_regnums_arm has wrong number of register infos"); + +// Register sets for arm. +static const RegisterSet g_reg_sets_arm[k_num_register_sets] = { + {"General Purpose Registers", "gpr", k_num_gpr_registers, + g_gpr_regnums_arm}, + {"Floating Point Registers", "fpu", k_num_fpr_registers, + g_fpu_regnums_arm}}; + RegisterInfoPOSIX_arm::RegisterInfoPOSIX_arm( const lldb_private::ArchSpec &target_arch) - : lldb_private::RegisterInfoInterface(target_arch), + : lldb_private::RegisterInfoAndSetInterface(target_arch), m_register_info_p(GetRegisterInfoPtr(target_arch)), m_register_info_count(GetRegisterInfoCount(target_arch)) {} @@ -81,11 +159,35 @@ size_t RegisterInfoPOSIX_arm::GetGPRSize() const { return sizeof(struct RegisterInfoPOSIX_arm::GPR); } +size_t RegisterInfoPOSIX_arm::GetFPRSize() const { + return sizeof(struct RegisterInfoPOSIX_arm::FPU); +} + const lldb_private::RegisterInfo * RegisterInfoPOSIX_arm::GetRegisterInfo() const { return m_register_info_p; } +size_t RegisterInfoPOSIX_arm::GetRegisterSetCount() const { + return k_num_register_sets; +} + +size_t RegisterInfoPOSIX_arm::GetRegisterSetFromRegisterIndex( + uint32_t reg_index) const { + if (reg_index <= gpr_cpsr) + return GPRegSet; + if (reg_index <= fpu_q15) + return FPRegSet; + return LLDB_INVALID_REGNUM; +} + +const lldb_private::RegisterSet * +RegisterInfoPOSIX_arm::GetRegisterSet(size_t set_index) const { + if (set_index < GetRegisterSetCount()) + return &g_reg_sets_arm[set_index]; + return nullptr; +} + uint32_t RegisterInfoPOSIX_arm::GetRegisterCount() const { return m_register_info_count; } diff --git a/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm.h b/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm.h index 1cf896e3dec..db155d757ca 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm.h +++ b/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm.h @@ -9,12 +9,14 @@ #ifndef LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERINFOPOSIX_ARM_H #define LLDB_SOURCE_PLUGINS_PROCESS_UTILITY_REGISTERINFOPOSIX_ARM_H -#include "RegisterInfoInterface.h" +#include "RegisterInfoAndSetInterface.h" #include "lldb/Target/RegisterContext.h" #include "lldb/lldb-private.h" -class RegisterInfoPOSIX_arm : public lldb_private::RegisterInfoInterface { +class RegisterInfoPOSIX_arm : public lldb_private::RegisterInfoAndSetInterface { public: + enum { GPRegSet = 0, FPRegSet}; + struct GPR { uint32_t r[16]; // R0-R15 uint32_t cpsr; // CPSR @@ -49,10 +51,19 @@ public: size_t GetGPRSize() const override; + size_t GetFPRSize() const override; + const lldb_private::RegisterInfo *GetRegisterInfo() const override; uint32_t GetRegisterCount() const override; + const lldb_private::RegisterSet * + GetRegisterSet(size_t reg_set) const override; + + size_t GetRegisterSetCount() const override; + + size_t GetRegisterSetFromRegisterIndex(uint32_t reg_index) const override; + private: const lldb_private::RegisterInfo *m_register_info_p; uint32_t m_register_info_count; diff --git a/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.cpp b/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.cpp index 4537cee42ad..b878534b39d 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.cpp +++ b/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.cpp @@ -7,7 +7,7 @@ //===---------------------------------------------------------------------===// #include -#include +#include #include #include "lldb/lldb-defines.h" @@ -25,6 +25,24 @@ (LLVM_EXTENSION offsetof(RegisterInfoPOSIX_arm64::FPU, reg) + \ sizeof(RegisterInfoPOSIX_arm64::GPR)) +// This information is based on AArch64 with SVE architecture reference manual. +// AArch64 with SVE has 32 Z and 16 P vector registers. There is also an FFR +// (First Fault) register and a VG (Vector Granule) pseudo register. + +// SVE 16-byte quad word is the basic unit of expansion in vector length. +#define SVE_QUAD_WORD_BYTES 16 + +// Vector length is the multiplier which decides the no of quad words, +// (multiples of 128-bits or 16-bytes) present in a Z register. Vector length +// is decided during execution and can change at runtime. SVE AArch64 register +// infos have modes one for each valid value of vector length. A change in +// vector length requires register context to update sizes of SVE Z, P and FFR. +// Also register context needs to update byte offsets of all registers affected +// by the change in vector length. +#define SVE_REGS_DEFAULT_OFFSET_LINUX sizeof(RegisterInfoPOSIX_arm64::GPR) + +#define SVE_OFFSET_VG SVE_REGS_DEFAULT_OFFSET_LINUX + #define EXC_OFFSET_NAME(reg) \ (LLVM_EXTENSION offsetof(RegisterInfoPOSIX_arm64::EXC, reg) + \ sizeof(RegisterInfoPOSIX_arm64::GPR) + \ @@ -51,25 +69,18 @@ // Include RegisterInfos_arm64 to declare our g_register_infos_arm64 structure. #define DECLARE_REGISTER_INFOS_ARM64_STRUCT #include "RegisterInfos_arm64.h" +#include "RegisterInfos_arm64_sve.h" #undef DECLARE_REGISTER_INFOS_ARM64_STRUCT -static const lldb_private::RegisterInfo * -GetRegisterInfoPtr(const lldb_private::ArchSpec &target_arch) { - switch (target_arch.GetMachine()) { - case llvm::Triple::aarch64: - case llvm::Triple::aarch64_32: - return g_register_infos_arm64_le; - default: - assert(false && "Unhandled target architecture."); - return nullptr; - } -} - // Number of register sets provided by this context. enum { k_num_gpr_registers = gpr_w28 - gpr_x0 + 1, k_num_fpr_registers = fpu_fpcr - fpu_v0 + 1, - k_num_register_sets = 2 + k_num_sve_registers = sve_ffr - sve_vg + 1, + k_num_mte_register = 1, + k_num_pauth_register = 2, + k_num_register_sets_default = 2, + k_num_register_sets = 3 }; // ARM64 general purpose registers. @@ -133,51 +144,99 @@ static const uint32_t g_fpu_regnums_arm64[] = { static_assert(((sizeof g_fpu_regnums_arm64 / sizeof g_fpu_regnums_arm64[0]) - 1) == k_num_fpr_registers, "g_fpu_regnums_arm64 has wrong number of register infos"); -// clang-format on + +// ARM64 SVE registers. +static const uint32_t g_sve_regnums_arm64[] = { + sve_vg, sve_z0, sve_z1, + sve_z2, sve_z3, sve_z4, + sve_z5, sve_z6, sve_z7, + sve_z8, sve_z9, sve_z10, + sve_z11, sve_z12, sve_z13, + sve_z14, sve_z15, sve_z16, + sve_z17, sve_z18, sve_z19, + sve_z20, sve_z21, sve_z22, + sve_z23, sve_z24, sve_z25, + sve_z26, sve_z27, sve_z28, + sve_z29, sve_z30, sve_z31, + sve_p0, sve_p1, sve_p2, + sve_p3, sve_p4, sve_p5, + sve_p6, sve_p7, sve_p8, + sve_p9, sve_p10, sve_p11, + sve_p12, sve_p13, sve_p14, + sve_p15, sve_ffr, LLDB_INVALID_REGNUM}; +static_assert(((sizeof g_sve_regnums_arm64 / sizeof g_sve_regnums_arm64[0]) - + 1) == k_num_sve_registers, + "g_sve_regnums_arm64 has wrong number of register infos"); + // Register sets for ARM64. static const lldb_private::RegisterSet g_reg_sets_arm64[k_num_register_sets] = { {"General Purpose Registers", "gpr", k_num_gpr_registers, g_gpr_regnums_arm64}, {"Floating Point Registers", "fpu", k_num_fpr_registers, - g_fpu_regnums_arm64}}; + g_fpu_regnums_arm64}, + {"Scalable Vector Extension Registers", "sve", k_num_sve_registers, + g_sve_regnums_arm64}}; -static uint32_t -GetRegisterInfoCount(const lldb_private::ArchSpec &target_arch) { - switch (target_arch.GetMachine()) { - case llvm::Triple::aarch64: - case llvm::Triple::aarch64_32: - return static_cast(sizeof(g_register_infos_arm64_le) / - sizeof(g_register_infos_arm64_le[0])); - default: - assert(false && "Unhandled target architecture."); - return 0; - } -} +static const lldb_private::RegisterSet g_reg_set_pauth_arm64 = { + "Pointer Authentication Registers", "pauth", k_num_pauth_register, NULL}; + +static const lldb_private::RegisterSet g_reg_set_mte_arm64 = { + "MTE Control Register", "mte", k_num_mte_register, NULL}; RegisterInfoPOSIX_arm64::RegisterInfoPOSIX_arm64( - const lldb_private::ArchSpec &target_arch) + const lldb_private::ArchSpec &target_arch, lldb_private::Flags opt_regsets) : lldb_private::RegisterInfoAndSetInterface(target_arch), - m_register_info_p(GetRegisterInfoPtr(target_arch)), - m_register_info_count(GetRegisterInfoCount(target_arch)) { - + m_opt_regsets(opt_regsets) { switch (target_arch.GetMachine()) { case llvm::Triple::aarch64: - case llvm::Triple::aarch64_32: - num_registers = k_num_gpr_registers + k_num_fpr_registers; - num_gpr_registers = k_num_gpr_registers; - num_fpr_registers = k_num_fpr_registers; - last_gpr = gpr_w28; - first_fpr = fpu_v0; - last_fpr = fpu_fpcr; + case llvm::Triple::aarch64_32: { + m_register_set_p = g_reg_sets_arm64; + m_register_set_count = k_num_register_sets_default; + m_per_regset_regnum_range[GPRegSet] = std::make_pair(gpr_x0, gpr_w28 + 1); + m_per_regset_regnum_range[FPRegSet] = std::make_pair(fpu_v0, fpu_fpcr + 1); + + // Now configure register sets supported by current target. If we have a + // dynamic register set like MTE, Pointer Authentication regset then we need + // to create dynamic register infos and regset array. Push back all optional + // register infos and regset and calculate register offsets accordingly. + if (m_opt_regsets.AllSet(eRegsetMaskSVE)) { + m_register_info_p = g_register_infos_arm64_sve_le; + m_register_info_count = sve_ffr + 1; + m_per_regset_regnum_range[m_register_set_count++] = + std::make_pair(sve_vg, sve_ffr + 1); + } else { + m_register_info_p = g_register_infos_arm64_le; + m_register_info_count = fpu_fpcr + 1; + } + + if (m_opt_regsets.AnySet(eRegsetMaskDynamic)) { + llvm::ArrayRef reg_infos_ref = + llvm::makeArrayRef(m_register_info_p, m_register_info_count); + llvm::ArrayRef reg_sets_ref = + llvm::makeArrayRef(m_register_set_p, m_register_set_count); + llvm::copy(reg_infos_ref, std::back_inserter(m_dynamic_reg_infos)); + llvm::copy(reg_sets_ref, std::back_inserter(m_dynamic_reg_sets)); + + if (m_opt_regsets.AllSet(eRegsetMaskPAuth)) + AddRegSetPAuth(); + + if (m_opt_regsets.AllSet(eRegsetMaskMTE)) + AddRegSetMTE(); + + m_register_info_count = m_dynamic_reg_infos.size(); + m_register_info_p = m_dynamic_reg_infos.data(); + m_register_set_p = m_dynamic_reg_sets.data(); + m_register_set_count = m_dynamic_reg_sets.size(); + } break; + } default: assert(false && "Unhandled target architecture."); - break; } } uint32_t RegisterInfoPOSIX_arm64::GetRegisterCount() const { - return num_gpr_registers + num_fpr_registers; + return m_register_info_count; } size_t RegisterInfoPOSIX_arm64::GetGPRSize() const { @@ -194,22 +253,168 @@ RegisterInfoPOSIX_arm64::GetRegisterInfo() const { } size_t RegisterInfoPOSIX_arm64::GetRegisterSetCount() const { - return k_num_register_sets; + return m_register_set_count; } size_t RegisterInfoPOSIX_arm64::GetRegisterSetFromRegisterIndex( uint32_t reg_index) const { - if (reg_index <= last_gpr) - return GPRegSet; - else if (reg_index <= last_fpr) - return FPRegSet; + for (const auto ®set_range : m_per_regset_regnum_range) { + if (reg_index >= regset_range.second.first && + reg_index < regset_range.second.second) + return regset_range.first; + } return LLDB_INVALID_REGNUM; } const lldb_private::RegisterSet * RegisterInfoPOSIX_arm64::GetRegisterSet(size_t set_index) const { - if (set_index < k_num_register_sets) - return &g_reg_sets_arm64[set_index]; - + if (set_index < GetRegisterSetCount()) + return &m_register_set_p[set_index]; return nullptr; } + +void RegisterInfoPOSIX_arm64::AddRegSetPAuth() { + uint32_t pa_regnum = m_dynamic_reg_infos.size(); + for (uint32_t i = 0; i < k_num_pauth_register; i++) { + pauth_regnum_collection.push_back(pa_regnum + i); + m_dynamic_reg_infos.push_back(g_register_infos_pauth[i]); + m_dynamic_reg_infos[pa_regnum + i].byte_offset = + m_dynamic_reg_infos[pa_regnum + i - 1].byte_offset + + m_dynamic_reg_infos[pa_regnum + i - 1].byte_size; + m_dynamic_reg_infos[pa_regnum + i].kinds[lldb::eRegisterKindLLDB] = + pa_regnum + i; + } + + m_per_regset_regnum_range[m_register_set_count] = + std::make_pair(pa_regnum, m_dynamic_reg_infos.size()); + m_dynamic_reg_sets.push_back(g_reg_set_pauth_arm64); + m_dynamic_reg_sets.back().registers = pauth_regnum_collection.data(); +} + +void RegisterInfoPOSIX_arm64::AddRegSetMTE() { + uint32_t mte_regnum = m_dynamic_reg_infos.size(); + m_mte_regnum_collection.push_back(mte_regnum); + m_dynamic_reg_infos.push_back(g_register_infos_mte[0]); + m_dynamic_reg_infos[mte_regnum].byte_offset = + m_dynamic_reg_infos[mte_regnum - 1].byte_offset + + m_dynamic_reg_infos[mte_regnum - 1].byte_size; + m_dynamic_reg_infos[mte_regnum].kinds[lldb::eRegisterKindLLDB] = mte_regnum; + + m_per_regset_regnum_range[m_register_set_count] = + std::make_pair(mte_regnum, mte_regnum + 1); + m_dynamic_reg_sets.push_back(g_reg_set_mte_arm64); + m_dynamic_reg_sets.back().registers = m_mte_regnum_collection.data(); +} + +uint32_t RegisterInfoPOSIX_arm64::ConfigureVectorLength(uint32_t sve_vq) { + // sve_vq contains SVE Quad vector length in context of AArch64 SVE. + // SVE register infos if enabled cannot be disabled by selecting sve_vq = 0. + // Also if an invalid or previously set vector length is passed to this + // function then it will exit immediately with previously set vector length. + if (!VectorSizeIsValid(sve_vq) || m_vector_reg_vq == sve_vq) + return m_vector_reg_vq; + + // We cannot enable AArch64 only mode if SVE was enabled. + if (sve_vq == eVectorQuadwordAArch64 && + m_vector_reg_vq > eVectorQuadwordAArch64) + sve_vq = eVectorQuadwordAArch64SVE; + + m_vector_reg_vq = sve_vq; + + if (sve_vq == eVectorQuadwordAArch64) + return m_vector_reg_vq; + std::vector ®_info_ref = + m_per_vq_reg_infos[sve_vq]; + + if (reg_info_ref.empty()) { + reg_info_ref = llvm::makeArrayRef(m_register_info_p, m_register_info_count); + + uint32_t offset = SVE_REGS_DEFAULT_OFFSET_LINUX; + reg_info_ref[fpu_fpsr].byte_offset = offset; + reg_info_ref[fpu_fpcr].byte_offset = offset + 4; + reg_info_ref[sve_vg].byte_offset = offset + 8; + offset += 16; + + // Update Z registers size and offset + uint32_t s_reg_base = fpu_s0; + uint32_t d_reg_base = fpu_d0; + uint32_t v_reg_base = fpu_v0; + uint32_t z_reg_base = sve_z0; + + for (uint32_t index = 0; index < 32; index++) { + reg_info_ref[s_reg_base + index].byte_offset = offset; + reg_info_ref[d_reg_base + index].byte_offset = offset; + reg_info_ref[v_reg_base + index].byte_offset = offset; + reg_info_ref[z_reg_base + index].byte_offset = offset; + + reg_info_ref[z_reg_base + index].byte_size = sve_vq * SVE_QUAD_WORD_BYTES; + offset += reg_info_ref[z_reg_base + index].byte_size; + } + + // Update P registers and FFR size and offset + for (uint32_t it = sve_p0; it <= sve_ffr; it++) { + reg_info_ref[it].byte_offset = offset; + reg_info_ref[it].byte_size = sve_vq * SVE_QUAD_WORD_BYTES / 8; + offset += reg_info_ref[it].byte_size; + } + + for (uint32_t it = sve_ffr + 1; it < m_register_info_count; it++) { + reg_info_ref[it].byte_offset = offset; + offset += reg_info_ref[it].byte_size; + } + + m_per_vq_reg_infos[sve_vq] = reg_info_ref; + } + + m_register_info_p = m_per_vq_reg_infos[sve_vq].data(); + return m_vector_reg_vq; +} + +bool RegisterInfoPOSIX_arm64::IsSVEReg(unsigned reg) const { + if (m_vector_reg_vq > eVectorQuadwordAArch64) + return (sve_vg <= reg && reg <= sve_ffr); + else + return false; +} + +bool RegisterInfoPOSIX_arm64::IsSVEZReg(unsigned reg) const { + return (sve_z0 <= reg && reg <= sve_z31); +} + +bool RegisterInfoPOSIX_arm64::IsSVEPReg(unsigned reg) const { + return (sve_p0 <= reg && reg <= sve_p15); +} + +bool RegisterInfoPOSIX_arm64::IsSVERegVG(unsigned reg) const { + return sve_vg == reg; +} + +bool RegisterInfoPOSIX_arm64::IsPAuthReg(unsigned reg) const { + return std::find(pauth_regnum_collection.begin(), + pauth_regnum_collection.end(), + reg) != pauth_regnum_collection.end(); +} + +bool RegisterInfoPOSIX_arm64::IsMTEReg(unsigned reg) const { + return std::find(m_mte_regnum_collection.begin(), + m_mte_regnum_collection.end(), + reg) != m_mte_regnum_collection.end(); +} + +uint32_t RegisterInfoPOSIX_arm64::GetRegNumSVEZ0() const { return sve_z0; } + +uint32_t RegisterInfoPOSIX_arm64::GetRegNumSVEFFR() const { return sve_ffr; } + +uint32_t RegisterInfoPOSIX_arm64::GetRegNumFPCR() const { return fpu_fpcr; } + +uint32_t RegisterInfoPOSIX_arm64::GetRegNumFPSR() const { return fpu_fpsr; } + +uint32_t RegisterInfoPOSIX_arm64::GetRegNumSVEVG() const { return sve_vg; } + +uint32_t RegisterInfoPOSIX_arm64::GetPAuthOffset() const { + return m_register_info_p[pauth_regnum_collection[0]].byte_offset; +} + +uint32_t RegisterInfoPOSIX_arm64::GetMTEOffset() const { + return m_register_info_p[m_mte_regnum_collection[0]].byte_offset; +} diff --git a/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h b/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h index 2da6a531a6b..96cab49d5ac 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h +++ b/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h @@ -11,14 +11,35 @@ #include "RegisterInfoAndSetInterface.h" #include "lldb/Target/RegisterContext.h" +#include "lldb/Utility/Flags.h" #include "lldb/lldb-private.h" +#include + +enum class SVEState { Unknown, Disabled, FPSIMD, Full }; class RegisterInfoPOSIX_arm64 : public lldb_private::RegisterInfoAndSetInterface { public: enum { GPRegSet = 0, FPRegSet }; + // AArch64 register set mask value + enum { + eRegsetMaskDefault = 0, + eRegsetMaskSVE = 1, + eRegsetMaskPAuth = 2, + eRegsetMaskMTE = 4, + eRegsetMaskDynamic = ~1, + }; + + // AArch64 Register set FP/SIMD feature configuration + enum { + eVectorQuadwordAArch64, + eVectorQuadwordAArch64SVE, + eVectorQuadwordAArch64SVEMax = 256 + }; + // based on RegisterContextDarwin_arm64.h + LLVM_PACKED_START struct GPR { uint64_t x[29]; // x0-x28 uint64_t fp; // x29 @@ -27,6 +48,7 @@ public: uint64_t pc; // pc uint32_t cpsr; // cpsr }; + LLVM_PACKED_END // based on RegisterContextDarwin_arm64.h struct VReg { @@ -56,7 +78,8 @@ public: uint64_t mdscr_el1; }; - RegisterInfoPOSIX_arm64(const lldb_private::ArchSpec &target_arch); + RegisterInfoPOSIX_arm64(const lldb_private::ArchSpec &target_arch, + lldb_private::Flags opt_regsets); size_t GetGPRSize() const override; @@ -73,17 +96,62 @@ public: size_t GetRegisterSetFromRegisterIndex(uint32_t reg_index) const override; + void AddRegSetPAuth(); + + void AddRegSetMTE(); + + uint32_t ConfigureVectorLength(uint32_t sve_vq); + + bool VectorSizeIsValid(uint32_t vq) { + if (vq >= eVectorQuadwordAArch64 && vq <= eVectorQuadwordAArch64SVEMax) + return true; + return false; + } + + bool IsSVEEnabled() const { return m_opt_regsets.AnySet(eRegsetMaskSVE); } + bool IsPAuthEnabled() const { return m_opt_regsets.AnySet(eRegsetMaskPAuth); } + bool IsMTEEnabled() const { return m_opt_regsets.AnySet(eRegsetMaskMTE); } + + bool IsSVEReg(unsigned reg) const; + bool IsSVEZReg(unsigned reg) const; + bool IsSVEPReg(unsigned reg) const; + bool IsSVERegVG(unsigned reg) const; + bool IsPAuthReg(unsigned reg) const; + bool IsMTEReg(unsigned reg) const; + + uint32_t GetRegNumSVEZ0() const; + uint32_t GetRegNumSVEFFR() const; + uint32_t GetRegNumFPCR() const; + uint32_t GetRegNumFPSR() const; + uint32_t GetRegNumSVEVG() const; + uint32_t GetPAuthOffset() const; + uint32_t GetMTEOffset() const; + private: - uint32_t num_registers; - uint32_t num_gpr_registers; - uint32_t num_fpr_registers; + typedef std::map> + per_vq_register_infos; - uint32_t last_gpr; - uint32_t first_fpr; - uint32_t last_fpr; + per_vq_register_infos m_per_vq_reg_infos; + + uint32_t m_vector_reg_vq = eVectorQuadwordAArch64; const lldb_private::RegisterInfo *m_register_info_p; uint32_t m_register_info_count; + + const lldb_private::RegisterSet *m_register_set_p; + uint32_t m_register_set_count; + + // Contains pair of [start, end] register numbers of a register set with start + // and end included. + std::map> m_per_regset_regnum_range; + + lldb_private::Flags m_opt_regsets; + + std::vector m_dynamic_reg_infos; + std::vector m_dynamic_reg_sets; + + std::vector pauth_regnum_collection; + std::vector m_mte_regnum_collection; }; #endif diff --git a/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_ppc64le.cpp b/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_ppc64le.cpp index 3461d38a390..159fd285644 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_ppc64le.cpp +++ b/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterInfoPOSIX_ppc64le.cpp @@ -7,7 +7,7 @@ //===---------------------------------------------------------------------===// #include -#include +#include #include #include "lldb/lldb-defines.h" diff --git a/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterInfos_arm.h b/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterInfos_arm.h index 74b9e3b2db3..4af0069eb6f 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterInfos_arm.h +++ b/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterInfos_arm.h @@ -8,7 +8,7 @@ #ifdef DECLARE_REGISTER_INFOS_ARM_STRUCT -#include +#include #include "lldb/lldb-defines.h" #include "lldb/lldb-enumerations.h" diff --git a/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterInfos_arm64.h b/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterInfos_arm64.h index 4aee55e7afb..47cedc31bcd 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterInfos_arm64.h +++ b/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterInfos_arm64.h @@ -8,7 +8,7 @@ #ifdef DECLARE_REGISTER_INFOS_ARM64_STRUCT -#include +#include #include "lldb/lldb-defines.h" #include "lldb/lldb-enumerations.h" @@ -470,6 +470,13 @@ static uint32_t g_d31_invalidates[] = {fpu_v31, fpu_s31, LLDB_INVALID_REGNUM}; LLDB_INVALID_REGNUM, lldb_kind \ } +// Generates register kinds array for registers with only lldb kind +#define KIND_ALL_INVALID \ + { \ + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, \ + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM \ + } + // Generates register kinds array for vector registers #define GPR64_KIND(reg, generic_kind) MISC_KIND(reg, gpr, generic_kind) #define VREG_KIND(reg) MISC_KIND(reg, fpu, LLDB_INVALID_REGNUM) @@ -526,6 +533,13 @@ static uint32_t g_d31_invalidates[] = {fpu_v31, fpu_s31, LLDB_INVALID_REGNUM}; nullptr, 0 \ } +// Defines pointer authentication mask registers +#define DEFINE_EXTENSION_REG(reg) \ + { \ + #reg, nullptr, 8, 0, lldb::eEncodingUint, lldb::eFormatHex, \ + KIND_ALL_INVALID, nullptr, nullptr, nullptr, 0 \ + } + static lldb_private::RegisterInfo g_register_infos_arm64_le[] = { // DEFINE_GPR64(name, GENERIC KIND) DEFINE_GPR64(x0, LLDB_REGNUM_GENERIC_ARG1), @@ -772,7 +786,12 @@ static lldb_private::RegisterInfo g_register_infos_arm64_le[] = { {DEFINE_DBG(wcr, 13)}, {DEFINE_DBG(wcr, 14)}, {DEFINE_DBG(wcr, 15)} - // clang-format on }; +// clang-format on +static lldb_private::RegisterInfo g_register_infos_pauth[] = { + DEFINE_EXTENSION_REG(data_mask), DEFINE_EXTENSION_REG(code_mask)}; + +static lldb_private::RegisterInfo g_register_infos_mte[] = { + DEFINE_EXTENSION_REG(mte_ctrl)}; #endif // DECLARE_REGISTER_INFOS_ARM64_STRUCT diff --git a/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterInfos_arm64_sve.h b/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterInfos_arm64_sve.h new file mode 100644 index 00000000000..9551db7e8eb --- /dev/null +++ b/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterInfos_arm64_sve.h @@ -0,0 +1,572 @@ +//===-- RegisterInfos_arm64_sve.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 +// +//===----------------------------------------------------------------------===// + +#ifdef DECLARE_REGISTER_INFOS_ARM64_STRUCT + +enum { + sve_vg = exc_far, + + sve_z0, + sve_z1, + sve_z2, + sve_z3, + sve_z4, + sve_z5, + sve_z6, + sve_z7, + sve_z8, + sve_z9, + sve_z10, + sve_z11, + sve_z12, + sve_z13, + sve_z14, + sve_z15, + sve_z16, + sve_z17, + sve_z18, + sve_z19, + sve_z20, + sve_z21, + sve_z22, + sve_z23, + sve_z24, + sve_z25, + sve_z26, + sve_z27, + sve_z28, + sve_z29, + sve_z30, + sve_z31, + + sve_p0, + sve_p1, + sve_p2, + sve_p3, + sve_p4, + sve_p5, + sve_p6, + sve_p7, + sve_p8, + sve_p9, + sve_p10, + sve_p11, + sve_p12, + sve_p13, + sve_p14, + sve_p15, + + sve_ffr, +}; + +#ifndef SVE_OFFSET_VG +#error SVE_OFFSET_VG must be defined before including this header file +#endif + +static uint32_t g_sve_s0_invalidates[] = {sve_z0, fpu_v0, fpu_d0, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_s1_invalidates[] = {sve_z1, fpu_v1, fpu_d1, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_s2_invalidates[] = {sve_z2, fpu_v2, fpu_d2, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_s3_invalidates[] = {sve_z3, fpu_v3, fpu_d3, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_s4_invalidates[] = {sve_z4, fpu_v4, fpu_d4, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_s5_invalidates[] = {sve_z5, fpu_v5, fpu_d5, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_s6_invalidates[] = {sve_z6, fpu_v6, fpu_d6, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_s7_invalidates[] = {sve_z7, fpu_v7, fpu_d7, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_s8_invalidates[] = {sve_z8, fpu_v8, fpu_d8, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_s9_invalidates[] = {sve_z9, fpu_v9, fpu_d9, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_s10_invalidates[] = {sve_z10, fpu_v10, fpu_d10, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_s11_invalidates[] = {sve_z11, fpu_v11, fpu_d11, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_s12_invalidates[] = {sve_z12, fpu_v12, fpu_d12, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_s13_invalidates[] = {sve_z13, fpu_v13, fpu_d13, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_s14_invalidates[] = {sve_z14, fpu_v14, fpu_d14, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_s15_invalidates[] = {sve_z15, fpu_v15, fpu_d15, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_s16_invalidates[] = {sve_z16, fpu_v16, fpu_d16, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_s17_invalidates[] = {sve_z17, fpu_v17, fpu_d17, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_s18_invalidates[] = {sve_z18, fpu_v18, fpu_d18, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_s19_invalidates[] = {sve_z19, fpu_v19, fpu_d19, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_s20_invalidates[] = {sve_z20, fpu_v20, fpu_d20, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_s21_invalidates[] = {sve_z21, fpu_v21, fpu_d21, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_s22_invalidates[] = {sve_z22, fpu_v22, fpu_d22, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_s23_invalidates[] = {sve_z23, fpu_v23, fpu_d23, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_s24_invalidates[] = {sve_z24, fpu_v24, fpu_d24, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_s25_invalidates[] = {sve_z25, fpu_v25, fpu_d25, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_s26_invalidates[] = {sve_z26, fpu_v26, fpu_d26, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_s27_invalidates[] = {sve_z27, fpu_v27, fpu_d27, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_s28_invalidates[] = {sve_z28, fpu_v28, fpu_d28, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_s29_invalidates[] = {sve_z29, fpu_v29, fpu_d29, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_s30_invalidates[] = {sve_z30, fpu_v30, fpu_d30, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_s31_invalidates[] = {sve_z31, fpu_v31, fpu_d31, + LLDB_INVALID_REGNUM}; + +static uint32_t g_sve_d0_invalidates[] = {sve_z0, fpu_v0, fpu_s0, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_d1_invalidates[] = {sve_z1, fpu_v1, fpu_s1, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_d2_invalidates[] = {sve_z2, fpu_v2, fpu_s2, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_d3_invalidates[] = {sve_z3, fpu_v3, fpu_s3, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_d4_invalidates[] = {sve_z4, fpu_v4, fpu_s4, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_d5_invalidates[] = {sve_z5, fpu_v5, fpu_s5, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_d6_invalidates[] = {sve_z6, fpu_v6, fpu_s6, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_d7_invalidates[] = {sve_z7, fpu_v7, fpu_s7, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_d8_invalidates[] = {sve_z8, fpu_v8, fpu_s8, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_d9_invalidates[] = {sve_z9, fpu_v9, fpu_s9, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_d10_invalidates[] = {sve_z10, fpu_v10, fpu_s10, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_d11_invalidates[] = {sve_z11, fpu_v11, fpu_s11, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_d12_invalidates[] = {sve_z12, fpu_v12, fpu_s12, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_d13_invalidates[] = {sve_z13, fpu_v13, fpu_s13, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_d14_invalidates[] = {sve_z14, fpu_v14, fpu_s14, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_d15_invalidates[] = {sve_z15, fpu_v15, fpu_s15, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_d16_invalidates[] = {sve_z16, fpu_v16, fpu_s16, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_d17_invalidates[] = {sve_z17, fpu_v17, fpu_s17, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_d18_invalidates[] = {sve_z18, fpu_v18, fpu_s18, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_d19_invalidates[] = {sve_z19, fpu_v19, fpu_s19, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_d20_invalidates[] = {sve_z20, fpu_v20, fpu_s20, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_d21_invalidates[] = {sve_z21, fpu_v21, fpu_s21, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_d22_invalidates[] = {sve_z22, fpu_v22, fpu_s22, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_d23_invalidates[] = {sve_z23, fpu_v23, fpu_s23, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_d24_invalidates[] = {sve_z24, fpu_v24, fpu_s24, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_d25_invalidates[] = {sve_z25, fpu_v25, fpu_s25, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_d26_invalidates[] = {sve_z26, fpu_v26, fpu_s26, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_d27_invalidates[] = {sve_z27, fpu_v27, fpu_s27, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_d28_invalidates[] = {sve_z28, fpu_v28, fpu_s28, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_d29_invalidates[] = {sve_z29, fpu_v29, fpu_s29, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_d30_invalidates[] = {sve_z30, fpu_v30, fpu_s30, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_d31_invalidates[] = {sve_z31, fpu_v31, fpu_s31, + LLDB_INVALID_REGNUM}; + +static uint32_t g_sve_v0_invalidates[] = {sve_z0, fpu_d0, fpu_s0, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_v1_invalidates[] = {sve_z1, fpu_d1, fpu_s1, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_v2_invalidates[] = {sve_z2, fpu_d2, fpu_s2, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_v3_invalidates[] = {sve_z3, fpu_d3, fpu_s3, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_v4_invalidates[] = {sve_z4, fpu_d4, fpu_s4, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_v5_invalidates[] = {sve_z5, fpu_d5, fpu_s5, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_v6_invalidates[] = {sve_z6, fpu_d6, fpu_s6, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_v7_invalidates[] = {sve_z7, fpu_d7, fpu_s7, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_v8_invalidates[] = {sve_z8, fpu_d8, fpu_s8, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_v9_invalidates[] = {sve_z9, fpu_d9, fpu_s9, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_v10_invalidates[] = {sve_z10, fpu_d10, fpu_s10, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_v11_invalidates[] = {sve_z11, fpu_d11, fpu_s11, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_v12_invalidates[] = {sve_z12, fpu_d12, fpu_s12, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_v13_invalidates[] = {sve_z13, fpu_d13, fpu_s13, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_v14_invalidates[] = {sve_z14, fpu_d14, fpu_s14, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_v15_invalidates[] = {sve_z15, fpu_d15, fpu_s15, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_v16_invalidates[] = {sve_z16, fpu_d16, fpu_s16, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_v17_invalidates[] = {sve_z17, fpu_d17, fpu_s17, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_v18_invalidates[] = {sve_z18, fpu_d18, fpu_s18, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_v19_invalidates[] = {sve_z19, fpu_d19, fpu_s19, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_v20_invalidates[] = {sve_z20, fpu_d20, fpu_s20, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_v21_invalidates[] = {sve_z21, fpu_d21, fpu_s21, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_v22_invalidates[] = {sve_z22, fpu_d22, fpu_s22, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_v23_invalidates[] = {sve_z23, fpu_d23, fpu_s23, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_v24_invalidates[] = {sve_z24, fpu_d24, fpu_s24, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_v25_invalidates[] = {sve_z25, fpu_d25, fpu_s25, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_v26_invalidates[] = {sve_z26, fpu_d26, fpu_s26, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_v27_invalidates[] = {sve_z27, fpu_d27, fpu_s27, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_v28_invalidates[] = {sve_z28, fpu_d28, fpu_s28, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_v29_invalidates[] = {sve_z29, fpu_d29, fpu_s29, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_v30_invalidates[] = {sve_z30, fpu_d30, fpu_s30, + LLDB_INVALID_REGNUM}; +static uint32_t g_sve_v31_invalidates[] = {sve_z31, fpu_d31, fpu_s31, + LLDB_INVALID_REGNUM}; + +static uint32_t g_contained_z0[] = {sve_z0, LLDB_INVALID_REGNUM}; +static uint32_t g_contained_z1[] = {sve_z1, LLDB_INVALID_REGNUM}; +static uint32_t g_contained_z2[] = {sve_z2, LLDB_INVALID_REGNUM}; +static uint32_t g_contained_z3[] = {sve_z3, LLDB_INVALID_REGNUM}; +static uint32_t g_contained_z4[] = {sve_z4, LLDB_INVALID_REGNUM}; +static uint32_t g_contained_z5[] = {sve_z5, LLDB_INVALID_REGNUM}; +static uint32_t g_contained_z6[] = {sve_z6, LLDB_INVALID_REGNUM}; +static uint32_t g_contained_z7[] = {sve_z7, LLDB_INVALID_REGNUM}; +static uint32_t g_contained_z8[] = {sve_z8, LLDB_INVALID_REGNUM}; +static uint32_t g_contained_z9[] = {sve_z9, LLDB_INVALID_REGNUM}; +static uint32_t g_contained_z10[] = {sve_z10, LLDB_INVALID_REGNUM}; +static uint32_t g_contained_z11[] = {sve_z11, LLDB_INVALID_REGNUM}; +static uint32_t g_contained_z12[] = {sve_z12, LLDB_INVALID_REGNUM}; +static uint32_t g_contained_z13[] = {sve_z13, LLDB_INVALID_REGNUM}; +static uint32_t g_contained_z14[] = {sve_z14, LLDB_INVALID_REGNUM}; +static uint32_t g_contained_z15[] = {sve_z15, LLDB_INVALID_REGNUM}; +static uint32_t g_contained_z16[] = {sve_z16, LLDB_INVALID_REGNUM}; +static uint32_t g_contained_z17[] = {sve_z17, LLDB_INVALID_REGNUM}; +static uint32_t g_contained_z18[] = {sve_z18, LLDB_INVALID_REGNUM}; +static uint32_t g_contained_z19[] = {sve_z19, LLDB_INVALID_REGNUM}; +static uint32_t g_contained_z20[] = {sve_z20, LLDB_INVALID_REGNUM}; +static uint32_t g_contained_z21[] = {sve_z21, LLDB_INVALID_REGNUM}; +static uint32_t g_contained_z22[] = {sve_z22, LLDB_INVALID_REGNUM}; +static uint32_t g_contained_z23[] = {sve_z23, LLDB_INVALID_REGNUM}; +static uint32_t g_contained_z24[] = {sve_z24, LLDB_INVALID_REGNUM}; +static uint32_t g_contained_z25[] = {sve_z25, LLDB_INVALID_REGNUM}; +static uint32_t g_contained_z26[] = {sve_z26, LLDB_INVALID_REGNUM}; +static uint32_t g_contained_z27[] = {sve_z27, LLDB_INVALID_REGNUM}; +static uint32_t g_contained_z28[] = {sve_z28, LLDB_INVALID_REGNUM}; +static uint32_t g_contained_z29[] = {sve_z29, LLDB_INVALID_REGNUM}; +static uint32_t g_contained_z30[] = {sve_z30, LLDB_INVALID_REGNUM}; +static uint32_t g_contained_z31[] = {sve_z31, LLDB_INVALID_REGNUM}; + +#define VG_OFFSET_NAME(reg) SVE_OFFSET_VG + +#define SVE_REG_KIND(reg) MISC_KIND(reg, sve, LLDB_INVALID_REGNUM) +#define MISC_VG_KIND(lldb_kind) MISC_KIND(vg, sve, LLDB_INVALID_REGNUM) + +// Default offset SVE Z registers and all corresponding pseudo registers +// ( S, D and V registers) is zero and will be configured during execution. + +// Defines sve pseudo vector (V) register with 16-byte size +#define DEFINE_VREG_SVE(vreg, zreg) \ + { \ + #vreg, nullptr, 16, 0, lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, \ + VREG_KIND(vreg), g_contained_##zreg, g_sve_##vreg##_invalidates, \ + nullptr, 0 \ + } + +// Defines S and D pseudo registers mapping over corresponding vector register +#define DEFINE_FPU_PSEUDO_SVE(reg, size, zreg) \ + { \ + #reg, nullptr, size, 0, lldb::eEncodingIEEE754, lldb::eFormatFloat, \ + LLDB_KIND(fpu_##reg), g_contained_##zreg, g_sve_##reg##_invalidates, \ + nullptr, 0 \ + } + +// Defines a Z vector register with 16-byte default size +#define DEFINE_ZREG(reg) \ + { \ + #reg, nullptr, 16, 0, lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, \ + SVE_REG_KIND(reg), nullptr, nullptr, nullptr, 0 \ + } + +// Defines a P vector register with 2-byte default size +#define DEFINE_PREG(reg) \ + { \ + #reg, nullptr, 2, 0, lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, \ + SVE_REG_KIND(reg), nullptr, nullptr, nullptr, 0 \ + } + +static lldb_private::RegisterInfo g_register_infos_arm64_sve_le[] = { + // clang-format off + // DEFINE_GPR64(name, GENERIC KIND) + DEFINE_GPR64(x0, LLDB_REGNUM_GENERIC_ARG1), + DEFINE_GPR64(x1, LLDB_REGNUM_GENERIC_ARG2), + DEFINE_GPR64(x2, LLDB_REGNUM_GENERIC_ARG3), + DEFINE_GPR64(x3, LLDB_REGNUM_GENERIC_ARG4), + DEFINE_GPR64(x4, LLDB_REGNUM_GENERIC_ARG5), + DEFINE_GPR64(x5, LLDB_REGNUM_GENERIC_ARG6), + DEFINE_GPR64(x6, LLDB_REGNUM_GENERIC_ARG7), + DEFINE_GPR64(x7, LLDB_REGNUM_GENERIC_ARG8), + DEFINE_GPR64(x8, LLDB_INVALID_REGNUM), + DEFINE_GPR64(x9, LLDB_INVALID_REGNUM), + DEFINE_GPR64(x10, LLDB_INVALID_REGNUM), + DEFINE_GPR64(x11, LLDB_INVALID_REGNUM), + DEFINE_GPR64(x12, LLDB_INVALID_REGNUM), + DEFINE_GPR64(x13, LLDB_INVALID_REGNUM), + DEFINE_GPR64(x14, LLDB_INVALID_REGNUM), + DEFINE_GPR64(x15, LLDB_INVALID_REGNUM), + DEFINE_GPR64(x16, LLDB_INVALID_REGNUM), + DEFINE_GPR64(x17, LLDB_INVALID_REGNUM), + DEFINE_GPR64(x18, LLDB_INVALID_REGNUM), + DEFINE_GPR64(x19, LLDB_INVALID_REGNUM), + DEFINE_GPR64(x20, LLDB_INVALID_REGNUM), + DEFINE_GPR64(x21, LLDB_INVALID_REGNUM), + DEFINE_GPR64(x22, LLDB_INVALID_REGNUM), + DEFINE_GPR64(x23, LLDB_INVALID_REGNUM), + DEFINE_GPR64(x24, LLDB_INVALID_REGNUM), + DEFINE_GPR64(x25, LLDB_INVALID_REGNUM), + DEFINE_GPR64(x26, LLDB_INVALID_REGNUM), + DEFINE_GPR64(x27, LLDB_INVALID_REGNUM), + DEFINE_GPR64(x28, LLDB_INVALID_REGNUM), + // DEFINE_GPR64(name, GENERIC KIND) + DEFINE_GPR64_ALT(fp, x29, LLDB_REGNUM_GENERIC_FP), + DEFINE_GPR64_ALT(lr, x30, LLDB_REGNUM_GENERIC_RA), + DEFINE_GPR64_ALT(sp, x31, LLDB_REGNUM_GENERIC_SP), + DEFINE_GPR64(pc, LLDB_REGNUM_GENERIC_PC), + + // DEFINE_MISC_REGS(name, size, TYPE, lldb kind) + DEFINE_MISC_REGS(cpsr, 4, GPR, gpr_cpsr), + + // DEFINE_GPR32(name, parent name) + DEFINE_GPR32(w0, x0), + DEFINE_GPR32(w1, x1), + DEFINE_GPR32(w2, x2), + DEFINE_GPR32(w3, x3), + DEFINE_GPR32(w4, x4), + DEFINE_GPR32(w5, x5), + DEFINE_GPR32(w6, x6), + DEFINE_GPR32(w7, x7), + DEFINE_GPR32(w8, x8), + DEFINE_GPR32(w9, x9), + DEFINE_GPR32(w10, x10), + DEFINE_GPR32(w11, x11), + DEFINE_GPR32(w12, x12), + DEFINE_GPR32(w13, x13), + DEFINE_GPR32(w14, x14), + DEFINE_GPR32(w15, x15), + DEFINE_GPR32(w16, x16), + DEFINE_GPR32(w17, x17), + DEFINE_GPR32(w18, x18), + DEFINE_GPR32(w19, x19), + DEFINE_GPR32(w20, x20), + DEFINE_GPR32(w21, x21), + DEFINE_GPR32(w22, x22), + DEFINE_GPR32(w23, x23), + DEFINE_GPR32(w24, x24), + DEFINE_GPR32(w25, x25), + DEFINE_GPR32(w26, x26), + DEFINE_GPR32(w27, x27), + DEFINE_GPR32(w28, x28), + + // DEFINE_VREG_SVE(v register, z register) + DEFINE_VREG_SVE(v0, z0), + DEFINE_VREG_SVE(v1, z1), + DEFINE_VREG_SVE(v2, z2), + DEFINE_VREG_SVE(v3, z3), + DEFINE_VREG_SVE(v4, z4), + DEFINE_VREG_SVE(v5, z5), + DEFINE_VREG_SVE(v6, z6), + DEFINE_VREG_SVE(v7, z7), + DEFINE_VREG_SVE(v8, z8), + DEFINE_VREG_SVE(v9, z9), + DEFINE_VREG_SVE(v10, z10), + DEFINE_VREG_SVE(v11, z11), + DEFINE_VREG_SVE(v12, z12), + DEFINE_VREG_SVE(v13, z13), + DEFINE_VREG_SVE(v14, z14), + DEFINE_VREG_SVE(v15, z15), + DEFINE_VREG_SVE(v16, z16), + DEFINE_VREG_SVE(v17, z17), + DEFINE_VREG_SVE(v18, z18), + DEFINE_VREG_SVE(v19, z19), + DEFINE_VREG_SVE(v20, z20), + DEFINE_VREG_SVE(v21, z21), + DEFINE_VREG_SVE(v22, z22), + DEFINE_VREG_SVE(v23, z23), + DEFINE_VREG_SVE(v24, z24), + DEFINE_VREG_SVE(v25, z25), + DEFINE_VREG_SVE(v26, z26), + DEFINE_VREG_SVE(v27, z27), + DEFINE_VREG_SVE(v28, z28), + DEFINE_VREG_SVE(v29, z29), + DEFINE_VREG_SVE(v30, z30), + DEFINE_VREG_SVE(v31, z31), + + // DEFINE_FPU_PSEUDO(name, size, ENDIAN OFFSET, parent register) + DEFINE_FPU_PSEUDO_SVE(s0, 4, z0), + DEFINE_FPU_PSEUDO_SVE(s1, 4, z1), + DEFINE_FPU_PSEUDO_SVE(s2, 4, z2), + DEFINE_FPU_PSEUDO_SVE(s3, 4, z3), + DEFINE_FPU_PSEUDO_SVE(s4, 4, z4), + DEFINE_FPU_PSEUDO_SVE(s5, 4, z5), + DEFINE_FPU_PSEUDO_SVE(s6, 4, z6), + DEFINE_FPU_PSEUDO_SVE(s7, 4, z7), + DEFINE_FPU_PSEUDO_SVE(s8, 4, z8), + DEFINE_FPU_PSEUDO_SVE(s9, 4, z9), + DEFINE_FPU_PSEUDO_SVE(s10, 4, z10), + DEFINE_FPU_PSEUDO_SVE(s11, 4, z11), + DEFINE_FPU_PSEUDO_SVE(s12, 4, z12), + DEFINE_FPU_PSEUDO_SVE(s13, 4, z13), + DEFINE_FPU_PSEUDO_SVE(s14, 4, z14), + DEFINE_FPU_PSEUDO_SVE(s15, 4, z15), + DEFINE_FPU_PSEUDO_SVE(s16, 4, z16), + DEFINE_FPU_PSEUDO_SVE(s17, 4, z17), + DEFINE_FPU_PSEUDO_SVE(s18, 4, z18), + DEFINE_FPU_PSEUDO_SVE(s19, 4, z19), + DEFINE_FPU_PSEUDO_SVE(s20, 4, z20), + DEFINE_FPU_PSEUDO_SVE(s21, 4, z21), + DEFINE_FPU_PSEUDO_SVE(s22, 4, z22), + DEFINE_FPU_PSEUDO_SVE(s23, 4, z23), + DEFINE_FPU_PSEUDO_SVE(s24, 4, z24), + DEFINE_FPU_PSEUDO_SVE(s25, 4, z25), + DEFINE_FPU_PSEUDO_SVE(s26, 4, z26), + DEFINE_FPU_PSEUDO_SVE(s27, 4, z27), + DEFINE_FPU_PSEUDO_SVE(s28, 4, z28), + DEFINE_FPU_PSEUDO_SVE(s29, 4, z29), + DEFINE_FPU_PSEUDO_SVE(s30, 4, z30), + DEFINE_FPU_PSEUDO_SVE(s31, 4, z31), + + DEFINE_FPU_PSEUDO_SVE(d0, 8, z0), + DEFINE_FPU_PSEUDO_SVE(d1, 8, z1), + DEFINE_FPU_PSEUDO_SVE(d2, 8, z2), + DEFINE_FPU_PSEUDO_SVE(d3, 8, z3), + DEFINE_FPU_PSEUDO_SVE(d4, 8, z4), + DEFINE_FPU_PSEUDO_SVE(d5, 8, z5), + DEFINE_FPU_PSEUDO_SVE(d6, 8, z6), + DEFINE_FPU_PSEUDO_SVE(d7, 8, z7), + DEFINE_FPU_PSEUDO_SVE(d8, 8, z8), + DEFINE_FPU_PSEUDO_SVE(d9, 8, z9), + DEFINE_FPU_PSEUDO_SVE(d10, 8, z10), + DEFINE_FPU_PSEUDO_SVE(d11, 8, z11), + DEFINE_FPU_PSEUDO_SVE(d12, 8, z12), + DEFINE_FPU_PSEUDO_SVE(d13, 8, z13), + DEFINE_FPU_PSEUDO_SVE(d14, 8, z14), + DEFINE_FPU_PSEUDO_SVE(d15, 8, z15), + DEFINE_FPU_PSEUDO_SVE(d16, 8, z16), + DEFINE_FPU_PSEUDO_SVE(d17, 8, z17), + DEFINE_FPU_PSEUDO_SVE(d18, 8, z18), + DEFINE_FPU_PSEUDO_SVE(d19, 8, z19), + DEFINE_FPU_PSEUDO_SVE(d20, 8, z20), + DEFINE_FPU_PSEUDO_SVE(d21, 8, z21), + DEFINE_FPU_PSEUDO_SVE(d22, 8, z22), + DEFINE_FPU_PSEUDO_SVE(d23, 8, z23), + DEFINE_FPU_PSEUDO_SVE(d24, 8, z24), + DEFINE_FPU_PSEUDO_SVE(d25, 8, z25), + DEFINE_FPU_PSEUDO_SVE(d26, 8, z26), + DEFINE_FPU_PSEUDO_SVE(d27, 8, z27), + DEFINE_FPU_PSEUDO_SVE(d28, 8, z28), + DEFINE_FPU_PSEUDO_SVE(d29, 8, z29), + DEFINE_FPU_PSEUDO_SVE(d30, 8, z30), + DEFINE_FPU_PSEUDO_SVE(d31, 8, z31), + + // DEFINE_MISC_REGS(name, size, TYPE, lldb kind) + DEFINE_MISC_REGS(fpsr, 4, FPU, fpu_fpsr), + DEFINE_MISC_REGS(fpcr, 4, FPU, fpu_fpcr), + + DEFINE_MISC_REGS(vg, 8, VG, sve_vg), + // DEFINE_ZREG(name) + DEFINE_ZREG(z0), + DEFINE_ZREG(z1), + DEFINE_ZREG(z2), + DEFINE_ZREG(z3), + DEFINE_ZREG(z4), + DEFINE_ZREG(z5), + DEFINE_ZREG(z6), + DEFINE_ZREG(z7), + DEFINE_ZREG(z8), + DEFINE_ZREG(z9), + DEFINE_ZREG(z10), + DEFINE_ZREG(z11), + DEFINE_ZREG(z12), + DEFINE_ZREG(z13), + DEFINE_ZREG(z14), + DEFINE_ZREG(z15), + DEFINE_ZREG(z16), + DEFINE_ZREG(z17), + DEFINE_ZREG(z18), + DEFINE_ZREG(z19), + DEFINE_ZREG(z20), + DEFINE_ZREG(z21), + DEFINE_ZREG(z22), + DEFINE_ZREG(z23), + DEFINE_ZREG(z24), + DEFINE_ZREG(z25), + DEFINE_ZREG(z26), + DEFINE_ZREG(z27), + DEFINE_ZREG(z28), + DEFINE_ZREG(z29), + DEFINE_ZREG(z30), + DEFINE_ZREG(z31), + + // DEFINE_PREG(name) + DEFINE_PREG(p0), + DEFINE_PREG(p1), + DEFINE_PREG(p2), + DEFINE_PREG(p3), + DEFINE_PREG(p4), + DEFINE_PREG(p5), + DEFINE_PREG(p6), + DEFINE_PREG(p7), + DEFINE_PREG(p8), + DEFINE_PREG(p9), + DEFINE_PREG(p10), + DEFINE_PREG(p11), + DEFINE_PREG(p12), + DEFINE_PREG(p13), + DEFINE_PREG(p14), + DEFINE_PREG(p15), + + // DEFINE FFR + DEFINE_PREG(ffr) + // clang-format on +}; + +#endif // DECLARE_REGISTER_INFOS_ARM64_SVE_STRUCT diff --git a/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterInfos_i386.h b/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterInfos_i386.h index 343579cd265..15c7cac544a 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterInfos_i386.h +++ b/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterInfos_i386.h @@ -87,15 +87,14 @@ nullptr, nullptr, nullptr, 0 \ } -#define DEFINE_FP_MM(reg, i) \ +#define DEFINE_FP_MM(reg, i, streg) \ { \ - #reg #i, nullptr, sizeof(uint64_t), \ - LLVM_EXTENSION FPR_OFFSET( \ - stmm[i]), eEncodingUint, eFormatHex, \ - {ehframe_mm##i##_i386, dwarf_mm##i##_i386, \ - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, \ - lldb_mm##i##_i386 }, \ - nullptr, nullptr, nullptr, 0 \ + #reg #i, nullptr, sizeof(uint64_t), LLVM_EXTENSION FPR_OFFSET(stmm[i]), \ + eEncodingUint, eFormatHex, \ + {dwarf_mm##i##_i386, dwarf_mm##i##_i386, LLDB_INVALID_REGNUM, \ + LLDB_INVALID_REGNUM, lldb_mm##i##_i386 }, \ + RegisterContextPOSIX_x86::g_contained_##streg##_32, \ + RegisterContextPOSIX_x86::g_invalidate_##streg##_32, nullptr, 0 \ } #define DEFINE_XMM(reg, i) \ @@ -251,10 +250,12 @@ static RegisterInfo g_register_infos_i386[] = { // FP registers. DEFINE_FP_ST(st, 0), DEFINE_FP_ST(st, 1), DEFINE_FP_ST(st, 2), DEFINE_FP_ST(st, 3), DEFINE_FP_ST(st, 4), DEFINE_FP_ST(st, 5), - DEFINE_FP_ST(st, 6), DEFINE_FP_ST(st, 7), DEFINE_FP_MM(mm, 0), - DEFINE_FP_MM(mm, 1), DEFINE_FP_MM(mm, 2), DEFINE_FP_MM(mm, 3), - DEFINE_FP_MM(mm, 4), DEFINE_FP_MM(mm, 5), DEFINE_FP_MM(mm, 6), - DEFINE_FP_MM(mm, 7), + DEFINE_FP_ST(st, 6), DEFINE_FP_ST(st, 7), + + DEFINE_FP_MM(mm, 0, st0), DEFINE_FP_MM(mm, 1, st1), + DEFINE_FP_MM(mm, 2, st2), DEFINE_FP_MM(mm, 3, st3), + DEFINE_FP_MM(mm, 4, st4), DEFINE_FP_MM(mm, 5, st5), + DEFINE_FP_MM(mm, 6, st6), DEFINE_FP_MM(mm, 7, st7), // XMM registers DEFINE_XMM(xmm, 0), DEFINE_XMM(xmm, 1), DEFINE_XMM(xmm, 2), diff --git a/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterInfos_mips.h b/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterInfos_mips.h index 08201fd1191..93f93d56fda 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterInfos_mips.h +++ b/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterInfos_mips.h @@ -6,7 +6,7 @@ // //===---------------------------------------------------------------------===// -#include +#include #include "lldb/Core/dwarf.h" #include "llvm/Support/Compiler.h" diff --git a/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterInfos_mips64.h b/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterInfos_mips64.h index b6e218ea441..b28b91810e4 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterInfos_mips64.h +++ b/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterInfos_mips64.h @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// -#include +#include #include "lldb/Core/dwarf.h" #include "llvm/Support/Compiler.h" @@ -15,37 +15,11 @@ #ifdef DECLARE_REGISTER_INFOS_MIPS64_STRUCT // Computes the offset of the given GPR in the user data area. -#ifdef LINUX_MIPS64 -#define GPR_OFFSET(regname) \ - (LLVM_EXTENSION offsetof(UserArea, gpr) + \ - LLVM_EXTENSION offsetof(GPR_linux_mips, regname)) -#else #define GPR_OFFSET(regname) (LLVM_EXTENSION offsetof(GPR_freebsd_mips, regname)) -#endif - -// Computes the offset of the given FPR in the extended data area. -#define FPR_OFFSET(regname) \ - (LLVM_EXTENSION offsetof(UserArea, fpr) + \ - LLVM_EXTENSION offsetof(FPR_linux_mips, regname)) - -// Computes the offset of the given MSA in the extended data area. -#define MSA_OFFSET(regname) \ - (LLVM_EXTENSION offsetof(UserArea, msa) + \ - LLVM_EXTENSION offsetof(MSA_linux_mips, regname)) // RegisterKind: EHFrame, DWARF, Generic, Process Plugin, LLDB // Note that the size and offset will be updated by platform-specific classes. -#ifdef LINUX_MIPS64 -#define DEFINE_GPR(reg, alt, kind1, kind2, kind3) \ - { \ - #reg, alt, sizeof(((GPR_linux_mips *) 0)->reg), \ - GPR_OFFSET(reg), eEncodingUint, eFormatHex, \ - {kind1, kind2, kind3, ptrace_##reg##_mips, \ - gpr_##reg##_mips64 }, \ - NULL, NULL, NULL, 0 \ - } -#else #define DEFINE_GPR(reg, alt, kind1, kind2, kind3, kind4) \ { \ #reg, alt, sizeof(((GPR_freebsd_mips *) 0)->reg), \ @@ -54,63 +28,10 @@ gpr_##reg##_mips64 }, \ NULL, NULL, NULL, 0 \ } -#endif - -#define DEFINE_GPR_INFO(reg, alt, kind1, kind2, kind3) \ - { \ - #reg, alt, sizeof(((GPR_linux_mips *) 0)->reg) / 2, \ - GPR_OFFSET(reg), eEncodingUint, eFormatHex, \ - {kind1, kind2, kind3, ptrace_##reg##_mips, \ - gpr_##reg##_mips64 }, \ - NULL, NULL, NULL, 0 \ - } - -const uint8_t dwarf_opcode_mips64[] = { - llvm::dwarf::DW_OP_regx, dwarf_sr_mips64, llvm::dwarf::DW_OP_lit1, - llvm::dwarf::DW_OP_lit26, llvm::dwarf::DW_OP_shl, llvm::dwarf::DW_OP_and, - llvm::dwarf::DW_OP_lit26, llvm::dwarf::DW_OP_shr}; - -#define DEFINE_FPR(reg, alt, kind1, kind2, kind3) \ - { \ - #reg, alt, sizeof(((FPR_linux_mips *) 0)->reg), \ - FPR_OFFSET(reg), eEncodingIEEE754, eFormatFloat, \ - {kind1, kind2, kind3, ptrace_##reg##_mips, \ - fpr_##reg##_mips64 }, \ - NULL, NULL, dwarf_opcode_mips64, \ - sizeof(dwarf_opcode_mips64) \ - } - -#define DEFINE_FPR_INFO(reg, alt, kind1, kind2, kind3) \ - { \ - #reg, alt, sizeof(((FPR_linux_mips *) 0)->reg), \ - FPR_OFFSET(reg), eEncodingUint, eFormatHex, \ - {kind1, kind2, kind3, ptrace_##reg##_mips, \ - fpr_##reg##_mips64 }, \ - NULL, NULL, NULL, 0 \ - } - -#define DEFINE_MSA(reg, alt, kind1, kind2, kind3, kind4) \ - { \ - #reg, alt, sizeof(((MSA_linux_mips *) 0)->reg), \ - MSA_OFFSET(reg), eEncodingVector, eFormatVectorOfUInt8, \ - {kind1, kind2, kind3, kind4, \ - msa_##reg##_mips64 }, \ - NULL, NULL, NULL, 0 \ - } - -#define DEFINE_MSA_INFO(reg, alt, kind1, kind2, kind3, kind4) \ - { \ - #reg, alt, sizeof(((MSA_linux_mips *) 0)->reg), \ - MSA_OFFSET(reg), eEncodingUint, eFormatHex, \ - {kind1, kind2, kind3, kind4, \ - msa_##reg##_mips64 }, \ - NULL, NULL, NULL, 0 \ - } static RegisterInfo g_register_infos_mips64[] = { // General purpose registers. EH_Frame, DWARF, // Generic, Process Plugin -#ifndef LINUX_MIPS64 DEFINE_GPR(zero, "r0", dwarf_zero_mips64, dwarf_zero_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(r1, nullptr, dwarf_r1_mips64, dwarf_r1_mips64, @@ -191,231 +112,6 @@ static RegisterInfo g_register_infos_mips64[] = { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(dummy, nullptr, dwarf_dummy_mips64, dwarf_dummy_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), -#else - DEFINE_GPR(zero, "r0", dwarf_zero_mips64, dwarf_zero_mips64, - LLDB_INVALID_REGNUM), - DEFINE_GPR(r1, nullptr, dwarf_r1_mips64, dwarf_r1_mips64, - LLDB_INVALID_REGNUM), - DEFINE_GPR(r2, nullptr, dwarf_r2_mips64, dwarf_r2_mips64, - LLDB_INVALID_REGNUM), - DEFINE_GPR(r3, nullptr, dwarf_r3_mips64, dwarf_r3_mips64, - LLDB_INVALID_REGNUM), - DEFINE_GPR(r4, nullptr, dwarf_r4_mips64, dwarf_r4_mips64, - LLDB_REGNUM_GENERIC_ARG1), - DEFINE_GPR(r5, nullptr, dwarf_r5_mips64, dwarf_r5_mips64, - LLDB_REGNUM_GENERIC_ARG2), - DEFINE_GPR(r6, nullptr, dwarf_r6_mips64, dwarf_r6_mips64, - LLDB_REGNUM_GENERIC_ARG3), - DEFINE_GPR(r7, nullptr, dwarf_r7_mips64, dwarf_r7_mips64, - LLDB_REGNUM_GENERIC_ARG4), - DEFINE_GPR(r8, nullptr, dwarf_r8_mips64, dwarf_r8_mips64, - LLDB_REGNUM_GENERIC_ARG5), - DEFINE_GPR(r9, nullptr, dwarf_r9_mips64, dwarf_r9_mips64, - LLDB_REGNUM_GENERIC_ARG6), - DEFINE_GPR(r10, nullptr, dwarf_r10_mips64, dwarf_r10_mips64, - LLDB_REGNUM_GENERIC_ARG7), - DEFINE_GPR(r11, nullptr, dwarf_r11_mips64, dwarf_r11_mips64, - LLDB_REGNUM_GENERIC_ARG8), - DEFINE_GPR(r12, nullptr, dwarf_r12_mips64, dwarf_r12_mips64, - LLDB_INVALID_REGNUM), - DEFINE_GPR(r13, nullptr, dwarf_r13_mips64, dwarf_r13_mips64, - LLDB_INVALID_REGNUM), - DEFINE_GPR(r14, nullptr, dwarf_r14_mips64, dwarf_r14_mips64, - LLDB_INVALID_REGNUM), - DEFINE_GPR(r15, nullptr, dwarf_r15_mips64, dwarf_r15_mips64, - LLDB_INVALID_REGNUM), - DEFINE_GPR(r16, nullptr, dwarf_r16_mips64, dwarf_r16_mips64, - LLDB_INVALID_REGNUM), - DEFINE_GPR(r17, nullptr, dwarf_r17_mips64, dwarf_r17_mips64, - LLDB_INVALID_REGNUM), - DEFINE_GPR(r18, nullptr, dwarf_r18_mips64, dwarf_r18_mips64, - LLDB_INVALID_REGNUM), - DEFINE_GPR(r19, nullptr, dwarf_r19_mips64, dwarf_r19_mips64, - LLDB_INVALID_REGNUM), - DEFINE_GPR(r20, nullptr, dwarf_r20_mips64, dwarf_r20_mips64, - LLDB_INVALID_REGNUM), - DEFINE_GPR(r21, nullptr, dwarf_r21_mips64, dwarf_r21_mips64, - LLDB_INVALID_REGNUM), - DEFINE_GPR(r22, nullptr, dwarf_r22_mips64, dwarf_r22_mips64, - LLDB_INVALID_REGNUM), - DEFINE_GPR(r23, nullptr, dwarf_r23_mips64, dwarf_r23_mips64, - LLDB_INVALID_REGNUM), - DEFINE_GPR(r24, nullptr, dwarf_r24_mips64, dwarf_r24_mips64, - LLDB_INVALID_REGNUM), - DEFINE_GPR(r25, nullptr, dwarf_r25_mips64, dwarf_r25_mips64, - LLDB_INVALID_REGNUM), - DEFINE_GPR(r26, nullptr, dwarf_r26_mips64, dwarf_r26_mips64, - LLDB_INVALID_REGNUM), - DEFINE_GPR(r27, nullptr, dwarf_r27_mips64, dwarf_r27_mips64, - LLDB_INVALID_REGNUM), - DEFINE_GPR(gp, "r28", dwarf_gp_mips64, dwarf_gp_mips64, - LLDB_INVALID_REGNUM), - DEFINE_GPR(sp, "r29", dwarf_sp_mips64, dwarf_sp_mips64, - LLDB_REGNUM_GENERIC_SP), - DEFINE_GPR(r30, nullptr, dwarf_r30_mips64, dwarf_r30_mips64, - LLDB_REGNUM_GENERIC_FP), - DEFINE_GPR(ra, "r31", dwarf_ra_mips64, dwarf_ra_mips64, - LLDB_REGNUM_GENERIC_RA), - DEFINE_GPR_INFO(sr, nullptr, dwarf_sr_mips64, dwarf_sr_mips64, - LLDB_REGNUM_GENERIC_FLAGS), - DEFINE_GPR(mullo, nullptr, dwarf_lo_mips64, dwarf_lo_mips64, - LLDB_INVALID_REGNUM), - DEFINE_GPR(mulhi, nullptr, dwarf_hi_mips64, dwarf_hi_mips64, - LLDB_INVALID_REGNUM), - DEFINE_GPR(badvaddr, nullptr, dwarf_bad_mips64, dwarf_bad_mips64, - LLDB_INVALID_REGNUM), - DEFINE_GPR_INFO(cause, nullptr, dwarf_cause_mips64, dwarf_cause_mips64, - LLDB_INVALID_REGNUM), - DEFINE_GPR(pc, "pc", dwarf_pc_mips64, dwarf_pc_mips64, - LLDB_REGNUM_GENERIC_PC), - DEFINE_GPR_INFO(config5, nullptr, dwarf_config5_mips64, - dwarf_config5_mips64, LLDB_INVALID_REGNUM), - DEFINE_FPR(f0, nullptr, dwarf_f0_mips64, dwarf_f0_mips64, - LLDB_INVALID_REGNUM), - DEFINE_FPR(f1, nullptr, dwarf_f1_mips64, dwarf_f1_mips64, - LLDB_INVALID_REGNUM), - DEFINE_FPR(f2, nullptr, dwarf_f2_mips64, dwarf_f2_mips64, - LLDB_INVALID_REGNUM), - DEFINE_FPR(f3, nullptr, dwarf_f3_mips64, dwarf_f3_mips64, - LLDB_INVALID_REGNUM), - DEFINE_FPR(f4, nullptr, dwarf_f4_mips64, dwarf_f4_mips64, - LLDB_INVALID_REGNUM), - DEFINE_FPR(f5, nullptr, dwarf_f5_mips64, dwarf_f5_mips64, - LLDB_INVALID_REGNUM), - DEFINE_FPR(f6, nullptr, dwarf_f6_mips64, dwarf_f6_mips64, - LLDB_INVALID_REGNUM), - DEFINE_FPR(f7, nullptr, dwarf_f7_mips64, dwarf_f7_mips64, - LLDB_INVALID_REGNUM), - DEFINE_FPR(f8, nullptr, dwarf_f8_mips64, dwarf_f8_mips64, - LLDB_INVALID_REGNUM), - DEFINE_FPR(f9, nullptr, dwarf_f9_mips64, dwarf_f9_mips64, - LLDB_INVALID_REGNUM), - DEFINE_FPR(f10, nullptr, dwarf_f10_mips64, dwarf_f10_mips64, - LLDB_INVALID_REGNUM), - DEFINE_FPR(f11, nullptr, dwarf_f11_mips64, dwarf_f11_mips64, - LLDB_INVALID_REGNUM), - DEFINE_FPR(f12, nullptr, dwarf_f12_mips64, dwarf_f12_mips64, - LLDB_INVALID_REGNUM), - DEFINE_FPR(f13, nullptr, dwarf_f13_mips64, dwarf_f13_mips64, - LLDB_INVALID_REGNUM), - DEFINE_FPR(f14, nullptr, dwarf_f14_mips64, dwarf_f14_mips64, - LLDB_INVALID_REGNUM), - DEFINE_FPR(f15, nullptr, dwarf_f15_mips64, dwarf_f15_mips64, - LLDB_INVALID_REGNUM), - DEFINE_FPR(f16, nullptr, dwarf_f16_mips64, dwarf_f16_mips64, - LLDB_INVALID_REGNUM), - DEFINE_FPR(f17, nullptr, dwarf_f17_mips64, dwarf_f17_mips64, - LLDB_INVALID_REGNUM), - DEFINE_FPR(f18, nullptr, dwarf_f18_mips64, dwarf_f18_mips64, - LLDB_INVALID_REGNUM), - DEFINE_FPR(f19, nullptr, dwarf_f19_mips64, dwarf_f19_mips64, - LLDB_INVALID_REGNUM), - DEFINE_FPR(f20, nullptr, dwarf_f20_mips64, dwarf_f20_mips64, - LLDB_INVALID_REGNUM), - DEFINE_FPR(f21, nullptr, dwarf_f21_mips64, dwarf_f21_mips64, - LLDB_INVALID_REGNUM), - DEFINE_FPR(f22, nullptr, dwarf_f22_mips64, dwarf_f22_mips64, - LLDB_INVALID_REGNUM), - DEFINE_FPR(f23, nullptr, dwarf_f23_mips64, dwarf_f23_mips64, - LLDB_INVALID_REGNUM), - DEFINE_FPR(f24, nullptr, dwarf_f24_mips64, dwarf_f24_mips64, - LLDB_INVALID_REGNUM), - DEFINE_FPR(f25, nullptr, dwarf_f25_mips64, dwarf_f25_mips64, - LLDB_INVALID_REGNUM), - DEFINE_FPR(f26, nullptr, dwarf_f26_mips64, dwarf_f26_mips64, - LLDB_INVALID_REGNUM), - DEFINE_FPR(f27, nullptr, dwarf_f27_mips64, dwarf_f27_mips64, - LLDB_INVALID_REGNUM), - DEFINE_FPR(f28, nullptr, dwarf_f28_mips64, dwarf_f28_mips64, - LLDB_INVALID_REGNUM), - DEFINE_FPR(f29, nullptr, dwarf_f29_mips64, dwarf_f29_mips64, - LLDB_INVALID_REGNUM), - DEFINE_FPR(f30, nullptr, dwarf_f30_mips64, dwarf_f30_mips64, - LLDB_INVALID_REGNUM), - DEFINE_FPR(f31, nullptr, dwarf_f31_mips64, dwarf_f31_mips64, - LLDB_INVALID_REGNUM), - DEFINE_FPR_INFO(fcsr, nullptr, dwarf_fcsr_mips64, dwarf_fcsr_mips64, - LLDB_INVALID_REGNUM), - DEFINE_FPR_INFO(fir, nullptr, dwarf_fir_mips64, dwarf_fir_mips64, - LLDB_INVALID_REGNUM), - DEFINE_FPR_INFO(config5, nullptr, dwarf_config5_mips64, - dwarf_config5_mips64, LLDB_INVALID_REGNUM), - DEFINE_MSA(w0, nullptr, dwarf_w0_mips64, dwarf_w0_mips64, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_MSA(w1, nullptr, dwarf_w1_mips64, dwarf_w1_mips64, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_MSA(w2, nullptr, dwarf_w2_mips64, dwarf_w2_mips64, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_MSA(w3, nullptr, dwarf_w3_mips64, dwarf_w3_mips64, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_MSA(w4, nullptr, dwarf_w4_mips64, dwarf_w4_mips64, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_MSA(w5, nullptr, dwarf_w5_mips64, dwarf_w5_mips64, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_MSA(w6, nullptr, dwarf_w6_mips64, dwarf_w6_mips64, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_MSA(w7, nullptr, dwarf_w7_mips64, dwarf_w7_mips64, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_MSA(w8, nullptr, dwarf_w8_mips64, dwarf_w8_mips64, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_MSA(w9, nullptr, dwarf_w9_mips64, dwarf_w9_mips64, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_MSA(w10, nullptr, dwarf_w10_mips64, dwarf_w10_mips64, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_MSA(w11, nullptr, dwarf_w11_mips64, dwarf_w11_mips64, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_MSA(w12, nullptr, dwarf_w12_mips64, dwarf_w12_mips64, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_MSA(w13, nullptr, dwarf_w13_mips64, dwarf_w13_mips64, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_MSA(w14, nullptr, dwarf_w14_mips64, dwarf_w14_mips64, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_MSA(w15, nullptr, dwarf_w15_mips64, dwarf_w15_mips64, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_MSA(w16, nullptr, dwarf_w16_mips64, dwarf_w16_mips64, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_MSA(w17, nullptr, dwarf_w17_mips64, dwarf_w17_mips64, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_MSA(w18, nullptr, dwarf_w18_mips64, dwarf_w18_mips64, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_MSA(w19, nullptr, dwarf_w19_mips64, dwarf_w19_mips64, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_MSA(w20, nullptr, dwarf_w10_mips64, dwarf_w20_mips64, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_MSA(w21, nullptr, dwarf_w21_mips64, dwarf_w21_mips64, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_MSA(w22, nullptr, dwarf_w22_mips64, dwarf_w22_mips64, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_MSA(w23, nullptr, dwarf_w23_mips64, dwarf_w23_mips64, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_MSA(w24, nullptr, dwarf_w24_mips64, dwarf_w24_mips64, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_MSA(w25, nullptr, dwarf_w25_mips64, dwarf_w25_mips64, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_MSA(w26, nullptr, dwarf_w26_mips64, dwarf_w26_mips64, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_MSA(w27, nullptr, dwarf_w27_mips64, dwarf_w27_mips64, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_MSA(w28, nullptr, dwarf_w28_mips64, dwarf_w28_mips64, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_MSA(w29, nullptr, dwarf_w29_mips64, dwarf_w29_mips64, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_MSA(w30, nullptr, dwarf_w30_mips64, dwarf_w30_mips64, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_MSA(w31, nullptr, dwarf_w31_mips64, dwarf_w31_mips64, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_MSA_INFO(mcsr, nullptr, dwarf_mcsr_mips64, dwarf_mcsr_mips64, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_MSA_INFO(mir, nullptr, dwarf_mir_mips64, dwarf_mir_mips64, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_MSA_INFO(fcsr, nullptr, dwarf_fcsr_mips64, dwarf_fcsr_mips64, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_MSA_INFO(fir, nullptr, dwarf_fir_mips64, dwarf_fir_mips64, - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_MSA_INFO(config5, nullptr, dwarf_config5_mips64, - dwarf_config5_mips64, LLDB_INVALID_REGNUM, - LLDB_INVALID_REGNUM) -#endif }; static_assert((sizeof(g_register_infos_mips64) / diff --git a/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterInfos_powerpc.h b/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterInfos_powerpc.h index 51be31f8e02..04b4171b672 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterInfos_powerpc.h +++ b/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterInfos_powerpc.h @@ -6,12 +6,12 @@ // //===---------------------------------------------------------------------===// -#include +#include // Computes the offset of the given GPR in the user data area. #define GPR_OFFSET(regname) (offsetof(GPR, regname)) -#define FPR_OFFSET(regname) (offsetof(FPR, regname)) -#define VMX_OFFSET(regname) (offsetof(VMX, regname)) +#define FPR_OFFSET(regname) (sizeof(GPR) + offsetof(FPR, regname)) +#define VMX_OFFSET(regname) (sizeof(GPR) + sizeof(FPR) + offsetof(VMX, regname)) #define GPR_SIZE(regname) (sizeof(((GPR *)NULL)->regname)) #ifdef DECLARE_REGISTER_INFOS_POWERPC_STRUCT diff --git a/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterInfos_ppc64.h b/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterInfos_ppc64.h index 1086d3db0b0..059dba45f9b 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterInfos_ppc64.h +++ b/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterInfos_ppc64.h @@ -8,7 +8,7 @@ #ifdef DECLARE_REGISTER_INFOS_PPC64_STRUCT -#include +#include // Computes the offset of the given GPR_PPC64 in the user data area. #define GPR_PPC64_OFFSET(regname) (offsetof(GPR_PPC64, regname)) diff --git a/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterInfos_ppc64le.h b/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterInfos_ppc64le.h index 0b099a53d87..9937da2f305 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterInfos_ppc64le.h +++ b/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterInfos_ppc64le.h @@ -8,7 +8,7 @@ #ifdef DECLARE_REGISTER_INFOS_PPC64LE_STRUCT -#include +#include // Computes the offset of the given GPR in the user data area. #define GPR_OFFSET(regname) (offsetof(GPR, regname)) diff --git a/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterInfos_s390x.h b/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterInfos_s390x.h index 11344ff8ee7..d1df7c60620 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterInfos_s390x.h +++ b/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterInfos_s390x.h @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// -#include +#include #include "llvm/Support/Compiler.h" diff --git a/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterInfos_x86_64.h b/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterInfos_x86_64.h index af3027afa73..41c04b20f39 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterInfos_x86_64.h +++ b/gnu/llvm/lldb/source/Plugins/Process/Utility/RegisterInfos_x86_64.h @@ -88,15 +88,14 @@ nullptr, nullptr, nullptr, 0 \ } -#define DEFINE_FP_MM(reg, i) \ +#define DEFINE_FP_MM(reg, i, streg) \ { \ - #reg #i, nullptr, sizeof(uint64_t), \ - LLVM_EXTENSION FPR_OFFSET( \ - stmm[i]), eEncodingUint, eFormatHex, \ - {dwarf_mm##i##_x86_64, dwarf_mm##i##_x86_64, \ - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, \ - lldb_mm##i##_x86_64 }, \ - nullptr, nullptr, nullptr, 0 \ + #reg #i, nullptr, sizeof(uint64_t), LLVM_EXTENSION FPR_OFFSET(stmm[i]), \ + eEncodingUint, eFormatHex, \ + {dwarf_mm##i##_x86_64, dwarf_mm##i##_x86_64, LLDB_INVALID_REGNUM, \ + LLDB_INVALID_REGNUM, lldb_mm##i##_x86_64 }, \ + RegisterContextPOSIX_x86::g_contained_##streg##_64, \ + RegisterContextPOSIX_x86::g_invalidate_##streg##_64, nullptr, 0 \ } #define DEFINE_XMM(reg, i) \ @@ -195,6 +194,14 @@ RegisterContextPOSIX_x86::g_invalidate_##reg64, nullptr, 0 \ } +#define DEFINE_FPR_32(name, reg, kind1, kind2, kind3, kind4, reg64) \ + { \ + #name, nullptr, FPR_SIZE(reg), FPR_OFFSET(reg), eEncodingUint, eFormatHex, \ + {kind1, kind2, kind3, kind4, lldb_##name##_x86_64 }, \ + RegisterContextPOSIX_x86::g_contained_##reg64, \ + RegisterContextPOSIX_x86::g_invalidate_##reg64, nullptr, 0 \ + } + // clang-format off static RegisterInfo g_register_infos_x86_64[] = { // General purpose registers EH_Frame DWARF Generic Process Plugin @@ -251,26 +258,30 @@ static RegisterInfo g_register_infos_x86_64[] = { DEFINE_GPR_PSEUDO_8L(r12l, r12), DEFINE_GPR_PSEUDO_8L(r13l, r13), DEFINE_GPR_PSEUDO_8L(r14l, r14), DEFINE_GPR_PSEUDO_8L(r15l, r15), -// i387 Floating point registers. EH_frame DWARF Generic Process Plugin -// ====================================== =============== ================== =================== ==================== +// i387 Floating point registers. EH_frame DWARF Generic Process Plugin reg64 +// ====================================== =============== ================== =================== ==================== ===== DEFINE_FPR(fctrl, fctrl, dwarf_fctrl_x86_64, dwarf_fctrl_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_FPR(fstat, fstat, dwarf_fstat_x86_64, dwarf_fstat_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_FPR(ftag, ftag, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_FPR(fop, fop, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_FPR(fiseg, ptr.i386_.fiseg, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_FPR(fioff, ptr.i386_.fioff, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_FPR(foseg, ptr.i386_.foseg, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), - DEFINE_FPR(fooff, ptr.i386_.fooff, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_FPR_32(fiseg, ptr.i386_.fiseg, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fip), + DEFINE_FPR_32(fioff, ptr.i386_.fioff, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fip), + DEFINE_FPR(fip, ptr.x86_64.fip, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), + DEFINE_FPR_32(foseg, ptr.i386_.foseg, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fdp), + DEFINE_FPR_32(fooff, ptr.i386_.fooff, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fdp), + DEFINE_FPR(fdp, ptr.x86_64.fdp, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_FPR(mxcsr, mxcsr, dwarf_mxcsr_x86_64, dwarf_mxcsr_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_FPR(mxcsrmask, mxcsrmask, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), // FP registers. DEFINE_FP_ST(st, 0), DEFINE_FP_ST(st, 1), DEFINE_FP_ST(st, 2), DEFINE_FP_ST(st, 3), DEFINE_FP_ST(st, 4), DEFINE_FP_ST(st, 5), - DEFINE_FP_ST(st, 6), DEFINE_FP_ST(st, 7), DEFINE_FP_MM(mm, 0), - DEFINE_FP_MM(mm, 1), DEFINE_FP_MM(mm, 2), DEFINE_FP_MM(mm, 3), - DEFINE_FP_MM(mm, 4), DEFINE_FP_MM(mm, 5), DEFINE_FP_MM(mm, 6), - DEFINE_FP_MM(mm, 7), + DEFINE_FP_ST(st, 6), DEFINE_FP_ST(st, 7), + + DEFINE_FP_MM(mm, 0, st0), DEFINE_FP_MM(mm, 1, st1), + DEFINE_FP_MM(mm, 2, st2), DEFINE_FP_MM(mm, 3, st3), + DEFINE_FP_MM(mm, 4, st4), DEFINE_FP_MM(mm, 5, st5), + DEFINE_FP_MM(mm, 6, st6), DEFINE_FP_MM(mm, 7, st7), // XMM registers DEFINE_XMM(xmm, 0), DEFINE_XMM(xmm, 1), DEFINE_XMM(xmm, 2), diff --git a/gnu/llvm/lldb/source/Plugins/Process/Utility/StopInfoMachException.cpp b/gnu/llvm/lldb/source/Plugins/Process/Utility/StopInfoMachException.cpp index 2d8e8ef2161..85785a20354 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/Utility/StopInfoMachException.cpp +++ b/gnu/llvm/lldb/source/Plugins/Process/Utility/StopInfoMachException.cpp @@ -509,7 +509,7 @@ StopInfoSP StopInfoMachException::CreateStopReasonWithMachException( // operating system thread ID, so we can't make any assumptions about // the thread ID so we must always report the breakpoint regardless // of the thread. - if (bp_site_sp->ValidForThisThread(&thread) || + if (bp_site_sp->ValidForThisThread(thread) || thread.GetProcess()->GetOperatingSystem() != nullptr) return StopInfo::CreateStopReasonWithBreakpointSiteID( thread, bp_site_sp->GetID()); diff --git a/gnu/llvm/lldb/source/Plugins/Process/Utility/lldb-x86-register-enums.h b/gnu/llvm/lldb/source/Plugins/Process/Utility/lldb-x86-register-enums.h index 35f1a4075d0..4d10600f477 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/Utility/lldb-x86-register-enums.h +++ b/gnu/llvm/lldb/source/Plugins/Process/Utility/lldb-x86-register-enums.h @@ -106,7 +106,7 @@ enum { lldb_bnd1_i386, lldb_bnd2_i386, lldb_bnd3_i386, - k_last_mpxr = lldb_bnd3_i386, + k_last_mpxr_i386 = lldb_bnd3_i386, k_first_mpxc_i386, lldb_bndcfgu_i386 = k_first_mpxc_i386, @@ -228,8 +228,10 @@ enum { lldb_fop_x86_64, lldb_fiseg_x86_64, lldb_fioff_x86_64, + lldb_fip_x86_64, lldb_foseg_x86_64, lldb_fooff_x86_64, + lldb_fdp_x86_64, lldb_mxcsr_x86_64, lldb_mxcsrmask_x86_64, lldb_st0_x86_64, diff --git a/gnu/llvm/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp b/gnu/llvm/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp index beee3f58678..69a5cb20b90 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp +++ b/gnu/llvm/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.cpp @@ -217,13 +217,17 @@ Status NativeProcessWindows::WriteMemory(lldb::addr_t addr, const void *buf, return ProcessDebugger::WriteMemory(addr, buf, size, bytes_written); } -Status NativeProcessWindows::AllocateMemory(size_t size, uint32_t permissions, - lldb::addr_t &addr) { - return ProcessDebugger::AllocateMemory(size, permissions, addr); +llvm::Expected +NativeProcessWindows::AllocateMemory(size_t size, uint32_t permissions) { + lldb::addr_t addr; + Status ST = ProcessDebugger::AllocateMemory(size, permissions, addr); + if (ST.Success()) + return addr; + return ST.ToError(); } -Status NativeProcessWindows::DeallocateMemory(lldb::addr_t addr) { - return ProcessDebugger::DeallocateMemory(addr); +llvm::Error NativeProcessWindows::DeallocateMemory(lldb::addr_t addr) { + return ProcessDebugger::DeallocateMemory(addr).ToError(); } lldb::addr_t NativeProcessWindows::GetSharedLibraryInfoAddress() { return 0; } diff --git a/gnu/llvm/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.h b/gnu/llvm/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.h index 732273a54c1..150f7083e86 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.h +++ b/gnu/llvm/lldb/source/Plugins/Process/Windows/Common/NativeProcessWindows.h @@ -65,10 +65,10 @@ public: Status WriteMemory(lldb::addr_t addr, const void *buf, size_t size, size_t &bytes_written) override; - Status AllocateMemory(size_t size, uint32_t permissions, - lldb::addr_t &addr) override; + llvm::Expected AllocateMemory(size_t size, + uint32_t permissions) override; - Status DeallocateMemory(lldb::addr_t addr) override; + llvm::Error DeallocateMemory(lldb::addr_t addr) override; lldb::addr_t GetSharedLibraryInfoAddress() override; @@ -137,39 +137,41 @@ class NativeDebugDelegate : public IDebugDelegate { public: NativeDebugDelegate(NativeProcessWindows &process) : m_process(process) {} - void OnExitProcess(uint32_t exit_code) { m_process.OnExitProcess(exit_code); } + void OnExitProcess(uint32_t exit_code) override { + m_process.OnExitProcess(exit_code); + } - void OnDebuggerConnected(lldb::addr_t image_base) { + void OnDebuggerConnected(lldb::addr_t image_base) override { m_process.OnDebuggerConnected(image_base); } ExceptionResult OnDebugException(bool first_chance, - const ExceptionRecord &record) { + const ExceptionRecord &record) override { return m_process.OnDebugException(first_chance, record); } - void OnCreateThread(const HostThread &thread) { + void OnCreateThread(const HostThread &thread) override { m_process.OnCreateThread(thread); } - void OnExitThread(lldb::tid_t thread_id, uint32_t exit_code) { + void OnExitThread(lldb::tid_t thread_id, uint32_t exit_code) override { m_process.OnExitThread(thread_id, exit_code); } void OnLoadDll(const lldb_private::ModuleSpec &module_spec, - lldb::addr_t module_addr) { + lldb::addr_t module_addr) override { m_process.OnLoadDll(module_spec, module_addr); } - void OnUnloadDll(lldb::addr_t module_addr) { + void OnUnloadDll(lldb::addr_t module_addr) override { m_process.OnUnloadDll(module_addr); } - void OnDebugString(const std::string &string) { + void OnDebugString(const std::string &string) override { m_process.OnDebugString(string); } - void OnDebuggerError(const Status &error, uint32_t type) { + void OnDebuggerError(const Status &error, uint32_t type) override { return m_process.OnDebuggerError(error, type); } diff --git a/gnu/llvm/lldb/source/Plugins/Process/Windows/Common/NativeRegisterContextWindows_arm64.cpp b/gnu/llvm/lldb/source/Plugins/Process/Windows/Common/NativeRegisterContextWindows_arm64.cpp index 8205c8ec98d..1294928e09a 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/Windows/Common/NativeRegisterContextWindows_arm64.cpp +++ b/gnu/llvm/lldb/source/Plugins/Process/Windows/Common/NativeRegisterContextWindows_arm64.cpp @@ -98,7 +98,8 @@ static RegisterInfoInterface * CreateRegisterInfoInterface(const ArchSpec &target_arch) { assert((HostInfo::GetArchitecture().GetAddressByteSize() == 8) && "Register setting path assumes this is a 64-bit host"); - return new RegisterInfoPOSIX_arm64(target_arch); + return new RegisterInfoPOSIX_arm64( + target_arch, RegisterInfoPOSIX_arm64::eRegsetMaskDefault); } static Status GetThreadContextHelper(lldb::thread_t thread_handle, diff --git a/gnu/llvm/lldb/source/Plugins/Process/Windows/Common/ProcessDebugger.cpp b/gnu/llvm/lldb/source/Plugins/Process/Windows/Common/ProcessDebugger.cpp index 8a85c8ba6f4..91b3311dc85 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/Windows/Common/ProcessDebugger.cpp +++ b/gnu/llvm/lldb/source/Plugins/Process/Windows/Common/ProcessDebugger.cpp @@ -227,22 +227,20 @@ Status ProcessDebugger::DestroyProcess(const lldb::StateType state) { debugger_thread = m_session_data->m_debugger; } - Status error; - if (state != eStateExited && state != eStateDetached) { - LLDB_LOG( - log, "Shutting down process {0}.", - debugger_thread->GetProcess().GetNativeProcess().GetSystemHandle()); - error = debugger_thread->StopDebugging(true); - - // By the time StopDebugging returns, there is no more debugger thread, so - // we can be assured that no other thread will race for the session data. - m_session_data.reset(); - } else { - error.SetErrorStringWithFormat("cannot destroy process %" PRIx64 - " while state = %d", - GetDebuggedProcessId(), state); - LLDB_LOG(log, "error: {0}", error); + if (state == eStateExited || state == eStateDetached) { + LLDB_LOG(log, "warning: cannot destroy process {0} while state = {1}.", + GetDebuggedProcessId(), state); + return Status(); } + + LLDB_LOG(log, "Shutting down process {0}.", + debugger_thread->GetProcess().GetNativeProcess().GetSystemHandle()); + auto error = debugger_thread->StopDebugging(true); + + // By the time StopDebugging returns, there is no more debugger thread, so + // we can be assured that no other thread will race for the session data. + m_session_data.reset(); + return error; } @@ -407,7 +405,8 @@ Status ProcessDebugger::GetMemoryRegionInfo(lldb::addr_t vm_addr, MEMORY_BASIC_INFORMATION mem_info = {}; SIZE_T result = ::VirtualQueryEx(handle, addr, &mem_info, sizeof(mem_info)); if (result == 0) { - if (::GetLastError() == ERROR_INVALID_PARAMETER) { + DWORD last_error = ::GetLastError(); + if (last_error == ERROR_INVALID_PARAMETER) { // ERROR_INVALID_PARAMETER is returned if VirtualQueryEx is called with // an address past the highest accessible address. We should return a // range from the vm_addr to LLDB_INVALID_ADDRESS @@ -419,7 +418,7 @@ Status ProcessDebugger::GetMemoryRegionInfo(lldb::addr_t vm_addr, info.SetMapped(MemoryRegionInfo::eNo); return error; } else { - error.SetError(::GetLastError(), eErrorTypeWin32); + error.SetError(last_error, eErrorTypeWin32); LLDB_LOG(log, "VirtualQueryEx returned error {0} while getting memory " "region info for address {1:x}", @@ -462,7 +461,6 @@ Status ProcessDebugger::GetMemoryRegionInfo(lldb::addr_t vm_addr, info.SetMapped(MemoryRegionInfo::eNo); } - error.SetError(::GetLastError(), eErrorTypeWin32); LLDB_LOGV(log, "Memory region info for address {0}: readable={1}, " "executable={2}, writable={3}", diff --git a/gnu/llvm/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.cpp b/gnu/llvm/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.cpp index 7b020f55e99..379496ba0d5 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.cpp +++ b/gnu/llvm/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.cpp @@ -79,16 +79,17 @@ namespace lldb_private { ProcessSP ProcessWindows::CreateInstance(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp, - const FileSpec *) { + const FileSpec *, + bool can_connect) { return ProcessSP(new ProcessWindows(target_sp, listener_sp)); } static bool ShouldUseLLDBServer() { llvm::StringRef use_lldb_server = ::getenv("LLDB_USE_LLDB_SERVER"); - return use_lldb_server.equals_lower("on") || - use_lldb_server.equals_lower("yes") || - use_lldb_server.equals_lower("1") || - use_lldb_server.equals_lower("true"); + return use_lldb_server.equals_insensitive("on") || + use_lldb_server.equals_insensitive("yes") || + use_lldb_server.equals_insensitive("1") || + use_lldb_server.equals_insensitive("true"); } void ProcessWindows::Initialize() { @@ -150,6 +151,9 @@ lldb_private::ConstString ProcessWindows::GetPluginName() { uint32_t ProcessWindows::GetPluginVersion() { return 1; } Status ProcessWindows::EnableBreakpointSite(BreakpointSite *bp_site) { + if (bp_site->HardwareRequired()) + return Status("Hardware breakpoints are not supported."); + Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_BREAKPOINTS); LLDB_LOG(log, "bp_site = {0:x}, id={1}, addr={2:x}", bp_site, bp_site->GetID(), bp_site->GetLoadAddress()); @@ -390,7 +394,7 @@ void ProcessWindows::RefreshStateAfterStop() { RegisterContextSP register_context = stop_thread->GetRegisterContext(); const uint64_t pc = register_context->GetPC(); BreakpointSiteSP site(GetBreakpointSiteList().FindByAddress(pc)); - if (site && site->ValidForThisThread(stop_thread.get())) { + if (site && site->ValidForThisThread(*stop_thread)) { LLDB_LOG(log, "Single-stepped onto a breakpoint in process {0} at " "address {1:x} with breakpoint site {2}", @@ -445,7 +449,7 @@ void ProcessWindows::RefreshStateAfterStop() { m_session_data->m_debugger->GetProcess().GetProcessId(), pc, site->GetID()); - if (site->ValidForThisThread(stop_thread.get())) { + if (site->ValidForThisThread(*stop_thread)) { LLDB_LOG(log, "Breakpoint site {0} is valid for this thread ({1:x}), " "creating stop info.", @@ -506,8 +510,8 @@ bool ProcessWindows::CanDebug(lldb::TargetSP target_sp, return true; } -bool ProcessWindows::UpdateThreadList(ThreadList &old_thread_list, - ThreadList &new_thread_list) { +bool ProcessWindows::DoUpdateThreadList(ThreadList &old_thread_list, + ThreadList &new_thread_list) { Log *log = ProcessWindowsLog::GetLogIfAny(WINDOWS_LOG_THREAD); // Add all the threads that were previously running and for which we did not // detect a thread exited event. diff --git a/gnu/llvm/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.h b/gnu/llvm/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.h index a1085df022c..6fb2950b2de 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.h +++ b/gnu/llvm/lldb/source/Plugins/Process/Windows/Common/ProcessWindows.h @@ -25,7 +25,8 @@ public: // Static functions. static lldb::ProcessSP CreateInstance(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp, - const FileSpec *); + const FileSpec *, + bool can_connect); static void Initialize(); @@ -68,8 +69,8 @@ public: bool CanDebug(lldb::TargetSP target_sp, bool plugin_specified_by_name) override; bool DestroyRequiresHalt() override { return false; } - bool UpdateThreadList(ThreadList &old_thread_list, - ThreadList &new_thread_list) override; + bool DoUpdateThreadList(ThreadList &old_thread_list, + ThreadList &new_thread_list) override; bool IsAlive() override; size_t DoReadMemory(lldb::addr_t vm_addr, void *buf, size_t size, diff --git a/gnu/llvm/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp b/gnu/llvm/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp index aa95e92607a..12bc7390c72 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp +++ b/gnu/llvm/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// -#include +#include #include #include @@ -52,9 +52,10 @@ void ProcessElfCore::Terminate() { lldb::ProcessSP ProcessElfCore::CreateInstance(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp, - const FileSpec *crash_file) { + const FileSpec *crash_file, + bool can_connect) { lldb::ProcessSP process_sp; - if (crash_file) { + if (crash_file && !can_connect) { // Read enough data for a ELF32 header or ELF64 header Note: Here we care // about e_type field only, so it is safe to ignore possible presence of // the header extension. @@ -97,7 +98,7 @@ bool ProcessElfCore::CanDebug(lldb::TargetSP target_sp, ProcessElfCore::ProcessElfCore(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp, const FileSpec &core_file) - : Process(target_sp, listener_sp), m_core_file(core_file) {} + : PostMortemProcess(target_sp, listener_sp), m_core_file(core_file) {} // Destructor ProcessElfCore::~ProcessElfCore() { @@ -260,8 +261,8 @@ lldb_private::DynamicLoader *ProcessElfCore::GetDynamicLoader() { return m_dyld_up.get(); } -bool ProcessElfCore::UpdateThreadList(ThreadList &old_thread_list, - ThreadList &new_thread_list) { +bool ProcessElfCore::DoUpdateThreadList(ThreadList &old_thread_list, + ThreadList &new_thread_list) { const uint32_t num_threads = GetNumThreadContexts(); if (!m_thread_data_valid) return false; @@ -352,7 +353,6 @@ size_t ProcessElfCore::DoReadMemory(lldb::addr_t addr, void *buf, size_t size, const lldb::addr_t file_end = address_range->data.GetRangeEnd(); size_t bytes_to_read = size; // Number of bytes to read from the core file size_t bytes_copied = 0; // Number of bytes actually read from the core file - size_t zero_fill_size = 0; // Padding lldb::addr_t bytes_left = 0; // Number of bytes available in the core file from the given address @@ -366,24 +366,15 @@ size_t ProcessElfCore::DoReadMemory(lldb::addr_t addr, void *buf, size_t size, if (file_end > file_start + offset) bytes_left = file_end - (file_start + offset); - // Figure out how many bytes we need to zero-fill if we are reading more - // bytes than available in the on-disk segment - if (bytes_to_read > bytes_left) { - zero_fill_size = bytes_to_read - bytes_left; + if (bytes_to_read > bytes_left) bytes_to_read = bytes_left; - } // If there is data available on the core file read it if (bytes_to_read) bytes_copied = core_objfile->CopyData(offset + file_start, bytes_to_read, buf); - assert(zero_fill_size <= size); - // Pad remaining bytes - if (zero_fill_size) - memset(((char *)buf) + bytes_copied, 0, zero_fill_size); - - return bytes_copied + zero_fill_size; + return bytes_copied; } void ProcessElfCore::Clear() { @@ -413,12 +404,8 @@ lldb::addr_t ProcessElfCore::GetImageInfoAddress() { // Parse a FreeBSD NT_PRSTATUS note - see FreeBSD sys/procfs.h for details. static void ParseFreeBSDPrStatus(ThreadData &thread_data, const DataExtractor &data, - const ArchSpec &arch) { + bool lp64) { lldb::offset_t offset = 0; - bool lp64 = (arch.GetMachine() == llvm::Triple::aarch64 || - arch.GetMachine() == llvm::Triple::mips64 || - arch.GetMachine() == llvm::Triple::ppc64 || - arch.GetMachine() == llvm::Triple::x86_64); int pr_version = data.GetU32(&offset); Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); @@ -442,6 +429,27 @@ static void ParseFreeBSDPrStatus(ThreadData &thread_data, thread_data.gpregset = DataExtractor(data, offset, len); } +// Parse a FreeBSD NT_PRPSINFO note - see FreeBSD sys/procfs.h for details. +static void ParseFreeBSDPrPsInfo(ProcessElfCore &process, + const DataExtractor &data, + bool lp64) { + lldb::offset_t offset = 0; + int pr_version = data.GetU32(&offset); + + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); + if (log) { + if (pr_version > 1) + LLDB_LOGF(log, "FreeBSD PRPSINFO unexpected version %d", pr_version); + } + + // Skip pr_psinfosz, pr_fname, pr_psargs + offset += 108; + if (lp64) + offset += 4; + + process.SetID(data.GetU32(&offset)); // pr_pid +} + static llvm::Error ParseNetBSDProcInfo(const DataExtractor &data, uint32_t &cpi_nlwps, uint32_t &cpi_signo, @@ -521,6 +529,11 @@ ProcessElfCore::parseSegment(const DataExtractor &segment) { } llvm::Error ProcessElfCore::parseFreeBSDNotes(llvm::ArrayRef notes) { + ArchSpec arch = GetArchitecture(); + bool lp64 = (arch.GetMachine() == llvm::Triple::aarch64 || + arch.GetMachine() == llvm::Triple::mips64 || + arch.GetMachine() == llvm::Triple::ppc64 || + arch.GetMachine() == llvm::Triple::x86_64); bool have_prstatus = false; bool have_prpsinfo = false; ThreadData thread_data; @@ -541,10 +554,11 @@ llvm::Error ProcessElfCore::parseFreeBSDNotes(llvm::ArrayRef notes) { switch (note.info.n_type) { case ELF::NT_PRSTATUS: have_prstatus = true; - ParseFreeBSDPrStatus(thread_data, note.data, GetArchitecture()); + ParseFreeBSDPrStatus(thread_data, note.data, lp64); break; case ELF::NT_PRPSINFO: have_prpsinfo = true; + ParseFreeBSDPrPsInfo(*this, note.data, lp64); break; case ELF::NT_FREEBSD_THRMISC: { lldb::offset_t offset = 0; @@ -650,6 +664,32 @@ llvm::Error ProcessElfCore::parseNetBSDNotes(llvm::ArrayRef notes) { thread_data.notes.push_back(note); } } break; + case llvm::Triple::x86: { + // Assume order PT_GETREGS, PT_GETFPREGS + if (note.info.n_type == NETBSD::I386::NT_REGS) { + // If this is the next thread, push the previous one first. + if (had_nt_regs) { + m_thread_data.push_back(thread_data); + thread_data = ThreadData(); + had_nt_regs = false; + } + + thread_data.gpregset = note.data; + thread_data.tid = tid; + if (thread_data.gpregset.GetByteSize() == 0) + return llvm::make_error( + "Could not find general purpose registers note in core file.", + llvm::inconvertibleErrorCode()); + had_nt_regs = true; + } else if (note.info.n_type == NETBSD::I386::NT_FPREGS) { + if (!had_nt_regs || tid != thread_data.tid) + return llvm::make_error( + "Error parsing NetBSD core(5) notes: Unexpected order " + "of NOTEs PT_GETFPREG before PT_GETREG", + llvm::inconvertibleErrorCode()); + thread_data.notes.push_back(note); + } + } break; case llvm::Triple::x86_64: { // Assume order PT_GETREGS, PT_GETFPREGS if (note.info.n_type == NETBSD::AMD64::NT_REGS) { diff --git a/gnu/llvm/lldb/source/Plugins/Process/elf-core/ProcessElfCore.h b/gnu/llvm/lldb/source/Plugins/Process/elf-core/ProcessElfCore.h index 6f6309799f4..d8e3cc9ae3e 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/elf-core/ProcessElfCore.h +++ b/gnu/llvm/lldb/source/Plugins/Process/elf-core/ProcessElfCore.h @@ -19,7 +19,7 @@ #include #include -#include "lldb/Target/Process.h" +#include "lldb/Target/PostMortemProcess.h" #include "lldb/Utility/ConstString.h" #include "lldb/Utility/Status.h" @@ -28,12 +28,13 @@ struct ThreadData; -class ProcessElfCore : public lldb_private::Process { +class ProcessElfCore : public lldb_private::PostMortemProcess { public: // Constructors and Destructors static lldb::ProcessSP CreateInstance(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp, - const lldb_private::FileSpec *crash_file_path); + const lldb_private::FileSpec *crash_file_path, + bool can_connect); static void Initialize(); @@ -104,8 +105,8 @@ public: protected: void Clear(); - bool UpdateThreadList(lldb_private::ThreadList &old_thread_list, - lldb_private::ThreadList &new_thread_list) override; + bool DoUpdateThreadList(lldb_private::ThreadList &old_thread_list, + lldb_private::ThreadList &new_thread_list) override; private: struct NT_FILE_Entry { @@ -125,8 +126,6 @@ private: lldb::ModuleSP m_core_module_sp; lldb_private::FileSpec m_core_file; std::string m_dyld_plugin_name; - ProcessElfCore(const ProcessElfCore &) = delete; - const ProcessElfCore &operator=(const ProcessElfCore &) = delete; // True if m_thread_contexts contains valid entries bool m_thread_data_valid = false; diff --git a/gnu/llvm/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm.cpp b/gnu/llvm/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm.cpp index b76f26a584c..f0aee04b5f6 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm.cpp +++ b/gnu/llvm/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm.cpp @@ -16,16 +16,16 @@ using namespace lldb_private; RegisterContextCorePOSIX_arm::RegisterContextCorePOSIX_arm( - Thread &thread, RegisterInfoInterface *register_info, + Thread &thread, std::unique_ptr register_info, const DataExtractor &gpregset, llvm::ArrayRef notes) - : RegisterContextPOSIX_arm(thread, 0, register_info) { + : RegisterContextPOSIX_arm(thread, std::move(register_info)) { m_gpr_buffer = std::make_shared(gpregset.GetDataStart(), gpregset.GetByteSize()); m_gpr.SetData(m_gpr_buffer); m_gpr.SetByteOrder(gpregset.GetByteOrder()); } -RegisterContextCorePOSIX_arm::~RegisterContextCorePOSIX_arm() {} +RegisterContextCorePOSIX_arm::~RegisterContextCorePOSIX_arm() = default; bool RegisterContextCorePOSIX_arm::ReadGPR() { return true; } diff --git a/gnu/llvm/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm.h b/gnu/llvm/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm.h index f9ec08ed35f..de343f9001e 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm.h +++ b/gnu/llvm/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm.h @@ -18,7 +18,7 @@ class RegisterContextCorePOSIX_arm : public RegisterContextPOSIX_arm { public: RegisterContextCorePOSIX_arm( lldb_private::Thread &thread, - lldb_private::RegisterInfoInterface *register_info, + std::unique_ptr register_info, const lldb_private::DataExtractor &gpregset, llvm::ArrayRef notes); diff --git a/gnu/llvm/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.cpp b/gnu/llvm/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.cpp index 68556741698..e56aa88b57d 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.cpp +++ b/gnu/llvm/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "RegisterContextPOSIXCore_arm64.h" +#include "Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h" #include "Plugins/Process/elf-core/RegisterUtilities.h" #include "lldb/Target/Thread.h" @@ -16,20 +17,52 @@ using namespace lldb_private; +std::unique_ptr +RegisterContextCorePOSIX_arm64::Create(Thread &thread, const ArchSpec &arch, + const DataExtractor &gpregset, + llvm::ArrayRef notes) { + Flags opt_regsets = RegisterInfoPOSIX_arm64::eRegsetMaskDefault; + + DataExtractor sve_data = getRegset(notes, arch.GetTriple(), AARCH64_SVE_Desc); + if (sve_data.GetByteSize() > sizeof(sve::user_sve_header)) + opt_regsets.Set(RegisterInfoPOSIX_arm64::eRegsetMaskSVE); + + // Pointer Authentication register set data is based on struct + // user_pac_mask declared in ptrace.h. See reference implementation + // in Linux kernel source at arch/arm64/include/uapi/asm/ptrace.h. + DataExtractor pac_data = getRegset(notes, arch.GetTriple(), AARCH64_PAC_Desc); + if (pac_data.GetByteSize() >= sizeof(uint64_t) * 2) + opt_regsets.Set(RegisterInfoPOSIX_arm64::eRegsetMaskPAuth); + + auto register_info_up = + std::make_unique(arch, opt_regsets); + return std::unique_ptr( + new RegisterContextCorePOSIX_arm64(thread, std::move(register_info_up), + gpregset, notes)); +} + RegisterContextCorePOSIX_arm64::RegisterContextCorePOSIX_arm64( Thread &thread, std::unique_ptr register_info, const DataExtractor &gpregset, llvm::ArrayRef notes) : RegisterContextPOSIX_arm64(thread, std::move(register_info)) { - m_gpr_buffer = std::make_shared(gpregset.GetDataStart(), - gpregset.GetByteSize()); - m_gpr.SetData(m_gpr_buffer); - m_gpr.SetByteOrder(gpregset.GetByteOrder()); + m_gpr_data.SetData(std::make_shared(gpregset.GetDataStart(), + gpregset.GetByteSize())); + m_gpr_data.SetByteOrder(gpregset.GetByteOrder()); + + const llvm::Triple &target_triple = + m_register_info_up->GetTargetArchitecture().GetTriple(); + m_fpr_data = getRegset(notes, target_triple, FPR_Desc); - m_fpregset = getRegset( - notes, m_register_info_up->GetTargetArchitecture().GetTriple(), FPR_Desc); + if (m_register_info_up->IsSVEEnabled()) + m_sve_data = getRegset(notes, target_triple, AARCH64_SVE_Desc); + + if (m_register_info_up->IsPAuthEnabled()) + m_pac_data = getRegset(notes, target_triple, AARCH64_PAC_Desc); + + ConfigureRegisterContext(); } -RegisterContextCorePOSIX_arm64::~RegisterContextCorePOSIX_arm64() {} +RegisterContextCorePOSIX_arm64::~RegisterContextCorePOSIX_arm64() = default; bool RegisterContextCorePOSIX_arm64::ReadGPR() { return true; } @@ -45,11 +78,60 @@ bool RegisterContextCorePOSIX_arm64::WriteFPR() { return false; } +const uint8_t *RegisterContextCorePOSIX_arm64::GetSVEBuffer(uint64_t offset) { + return m_sve_data.GetDataStart() + offset; +} + +void RegisterContextCorePOSIX_arm64::ConfigureRegisterContext() { + if (m_sve_data.GetByteSize() > sizeof(sve::user_sve_header)) { + uint64_t sve_header_field_offset = 8; + m_sve_vector_length = m_sve_data.GetU16(&sve_header_field_offset); + sve_header_field_offset = 12; + uint16_t sve_header_flags_field = + m_sve_data.GetU16(&sve_header_field_offset); + if ((sve_header_flags_field & sve::ptrace_regs_mask) == + sve::ptrace_regs_fpsimd) + m_sve_state = SVEState::FPSIMD; + else if ((sve_header_flags_field & sve::ptrace_regs_mask) == + sve::ptrace_regs_sve) + m_sve_state = SVEState::Full; + + if (!sve::vl_valid(m_sve_vector_length)) { + m_sve_state = SVEState::Disabled; + m_sve_vector_length = 0; + } + } else + m_sve_state = SVEState::Disabled; + + if (m_sve_state != SVEState::Disabled) + m_register_info_up->ConfigureVectorLength( + sve::vq_from_vl(m_sve_vector_length)); +} + +uint32_t RegisterContextCorePOSIX_arm64::CalculateSVEOffset( + const RegisterInfo *reg_info) { + // Start of Z0 data is after GPRs plus 8 bytes of vg register + uint32_t sve_reg_offset = LLDB_INVALID_INDEX32; + if (m_sve_state == SVEState::FPSIMD) { + const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; + sve_reg_offset = sve::ptrace_fpsimd_offset + (reg - GetRegNumSVEZ0()) * 16; + } else if (m_sve_state == SVEState::Full) { + uint32_t sve_z0_offset = GetGPRSize() + 16; + sve_reg_offset = + sve::SigRegsOffset() + reg_info->byte_offset - sve_z0_offset; + } + + return sve_reg_offset; +} + bool RegisterContextCorePOSIX_arm64::ReadRegister(const RegisterInfo *reg_info, RegisterValue &value) { - lldb::offset_t offset = reg_info->byte_offset; + Status error; + lldb::offset_t offset; + + offset = reg_info->byte_offset; if (offset + reg_info->byte_size <= GetGPRSize()) { - uint64_t v = m_gpr.GetMaxU64(&offset, reg_info->byte_size); + uint64_t v = m_gpr_data.GetMaxU64(&offset, reg_info->byte_size); if (offset == reg_info->byte_offset + reg_info->byte_size) { value = v; return true; @@ -60,15 +142,91 @@ bool RegisterContextCorePOSIX_arm64::ReadRegister(const RegisterInfo *reg_info, if (reg == LLDB_INVALID_REGNUM) return false; - offset -= GetGPRSize(); - if (IsFPR(reg) && offset + reg_info->byte_size <= GetFPUSize()) { - Status error; - value.SetFromMemoryData(reg_info, m_fpregset.GetDataStart() + offset, + if (IsFPR(reg)) { + if (m_sve_state == SVEState::Disabled) { + // SVE is disabled take legacy route for FPU register access + offset -= GetGPRSize(); + if (offset < m_fpr_data.GetByteSize()) { + value.SetFromMemoryData(reg_info, m_fpr_data.GetDataStart() + offset, + reg_info->byte_size, lldb::eByteOrderLittle, + error); + return error.Success(); + } + } else { + // FPSR and FPCR will be located right after Z registers in + // SVEState::FPSIMD while in SVEState::Full they will be located at the + // end of register data after an alignment correction based on currently + // selected vector length. + uint32_t sve_reg_num = LLDB_INVALID_REGNUM; + if (reg == GetRegNumFPSR()) { + sve_reg_num = reg; + if (m_sve_state == SVEState::Full) + offset = sve::PTraceFPSROffset(sve::vq_from_vl(m_sve_vector_length)); + else if (m_sve_state == SVEState::FPSIMD) + offset = sve::ptrace_fpsimd_offset + (32 * 16); + } else if (reg == GetRegNumFPCR()) { + sve_reg_num = reg; + if (m_sve_state == SVEState::Full) + offset = sve::PTraceFPCROffset(sve::vq_from_vl(m_sve_vector_length)); + else if (m_sve_state == SVEState::FPSIMD) + offset = sve::ptrace_fpsimd_offset + (32 * 16) + 4; + } else { + // Extract SVE Z register value register number for this reg_info + if (reg_info->value_regs && + reg_info->value_regs[0] != LLDB_INVALID_REGNUM) + sve_reg_num = reg_info->value_regs[0]; + offset = CalculateSVEOffset(GetRegisterInfoAtIndex(sve_reg_num)); + } + + assert(sve_reg_num != LLDB_INVALID_REGNUM); + assert(offset < m_sve_data.GetByteSize()); + value.SetFromMemoryData(reg_info, GetSVEBuffer(offset), + reg_info->byte_size, lldb::eByteOrderLittle, + error); + } + } else if (IsSVE(reg)) { + if (IsSVEVG(reg)) { + value = GetSVERegVG(); + return true; + } + + switch (m_sve_state) { + case SVEState::FPSIMD: { + // In FPSIMD state SVE payload mirrors legacy fpsimd struct and so just + // copy 16 bytes of v register to the start of z register. All other + // SVE register will be set to zero. + uint64_t byte_size = 1; + uint8_t zeros = 0; + const uint8_t *src = &zeros; + if (IsSVEZ(reg)) { + byte_size = 16; + offset = CalculateSVEOffset(reg_info); + assert(offset < m_sve_data.GetByteSize()); + src = GetSVEBuffer(offset); + } + value.SetFromMemoryData(reg_info, src, byte_size, lldb::eByteOrderLittle, + error); + } break; + case SVEState::Full: + offset = CalculateSVEOffset(reg_info); + assert(offset < m_sve_data.GetByteSize()); + value.SetFromMemoryData(reg_info, GetSVEBuffer(offset), + reg_info->byte_size, lldb::eByteOrderLittle, + error); + break; + case SVEState::Disabled: + default: + return false; + } + } else if (IsPAuth(reg)) { + offset = reg_info->byte_offset - m_register_info_up->GetPAuthOffset(); + assert(offset < m_pac_data.GetByteSize()); + value.SetFromMemoryData(reg_info, m_pac_data.GetDataStart() + offset, reg_info->byte_size, lldb::eByteOrderLittle, error); - return error.Success(); - } + } else + return false; - return false; + return error.Success(); } bool RegisterContextCorePOSIX_arm64::ReadAllRegisterValues( diff --git a/gnu/llvm/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.h b/gnu/llvm/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.h index 830e0ff91e4..3988e3539b8 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.h +++ b/gnu/llvm/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_arm64.h @@ -9,18 +9,19 @@ #ifndef LLDB_SOURCE_PLUGINS_PROCESS_ELF_CORE_REGISTERCONTEXTPOSIXCORE_ARM64_H #define LLDB_SOURCE_PLUGINS_PROCESS_ELF_CORE_REGISTERCONTEXTPOSIXCORE_ARM64_H +#include "Plugins/Process/Utility/LinuxPTraceDefines_arm64sve.h" #include "Plugins/Process/Utility/RegisterContextPOSIX_arm64.h" + #include "Plugins/Process/elf-core/RegisterUtilities.h" #include "lldb/Utility/DataBufferHeap.h" #include "lldb/Utility/DataExtractor.h" class RegisterContextCorePOSIX_arm64 : public RegisterContextPOSIX_arm64 { public: - RegisterContextCorePOSIX_arm64( - lldb_private::Thread &thread, - std::unique_ptr register_info, - const lldb_private::DataExtractor &gpregset, - llvm::ArrayRef notes); + static std::unique_ptr + Create(lldb_private::Thread &thread, const lldb_private::ArchSpec &arch, + const lldb_private::DataExtractor &gpregset, + llvm::ArrayRef notes); ~RegisterContextCorePOSIX_arm64() override; @@ -37,6 +38,12 @@ public: bool HardwareSingleStep(bool enable) override; protected: + RegisterContextCorePOSIX_arm64( + lldb_private::Thread &thread, + std::unique_ptr register_info, + const lldb_private::DataExtractor &gpregset, + llvm::ArrayRef notes); + bool ReadGPR() override; bool ReadFPR() override; @@ -46,9 +53,21 @@ protected: bool WriteFPR() override; private: - lldb::DataBufferSP m_gpr_buffer; - lldb_private::DataExtractor m_gpr; - lldb_private::DataExtractor m_fpregset; + lldb_private::DataExtractor m_gpr_data; + lldb_private::DataExtractor m_fpr_data; + lldb_private::DataExtractor m_sve_data; + lldb_private::DataExtractor m_pac_data; + + SVEState m_sve_state; + uint16_t m_sve_vector_length = 0; + + const uint8_t *GetSVEBuffer(uint64_t offset = 0); + + void ConfigureRegisterContext(); + + uint32_t CalculateSVEOffset(const lldb_private::RegisterInfo *reg_info); + + uint64_t GetSVERegVG() { return m_sve_vector_length / 8; } }; #endif // LLDB_SOURCE_PLUGINS_PROCESS_ELF_CORE_REGISTERCONTEXTPOSIXCORE_ARM64_H diff --git a/gnu/llvm/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_mips64.cpp b/gnu/llvm/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_mips64.cpp index b5b83d899a4..5b1eb8b5437 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_mips64.cpp +++ b/gnu/llvm/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_mips64.cpp @@ -32,7 +32,7 @@ RegisterContextCorePOSIX_mips64::RegisterContextCorePOSIX_mips64( m_fpr.SetByteOrder(fpregset.GetByteOrder()); } -RegisterContextCorePOSIX_mips64::~RegisterContextCorePOSIX_mips64() {} +RegisterContextCorePOSIX_mips64::~RegisterContextCorePOSIX_mips64() = default; bool RegisterContextCorePOSIX_mips64::ReadGPR() { return true; } diff --git a/gnu/llvm/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_powerpc.cpp b/gnu/llvm/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_powerpc.cpp index e15cd47cd7d..8380731692a 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_powerpc.cpp +++ b/gnu/llvm/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_powerpc.cpp @@ -39,7 +39,7 @@ RegisterContextCorePOSIX_powerpc::RegisterContextCorePOSIX_powerpc( m_vec.SetByteOrder(vregset.GetByteOrder()); } -RegisterContextCorePOSIX_powerpc::~RegisterContextCorePOSIX_powerpc() {} +RegisterContextCorePOSIX_powerpc::~RegisterContextCorePOSIX_powerpc() = default; bool RegisterContextCorePOSIX_powerpc::ReadGPR() { return true; } diff --git a/gnu/llvm/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_s390x.cpp b/gnu/llvm/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_s390x.cpp index c3aa92c9f86..f1cd6897616 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_s390x.cpp +++ b/gnu/llvm/lldb/source/Plugins/Process/elf-core/RegisterContextPOSIXCore_s390x.cpp @@ -33,7 +33,7 @@ RegisterContextCorePOSIX_s390x::RegisterContextCorePOSIX_s390x( m_fpr.SetByteOrder(fpregset.GetByteOrder()); } -RegisterContextCorePOSIX_s390x::~RegisterContextCorePOSIX_s390x() {} +RegisterContextCorePOSIX_s390x::~RegisterContextCorePOSIX_s390x() = default; bool RegisterContextCorePOSIX_s390x::ReadGPR() { return true; } diff --git a/gnu/llvm/lldb/source/Plugins/Process/elf-core/RegisterUtilities.h b/gnu/llvm/lldb/source/Plugins/Process/elf-core/RegisterUtilities.h index 4e08aa28081..f6a2fbdcc93 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/elf-core/RegisterUtilities.h +++ b/gnu/llvm/lldb/source/Plugins/Process/elf-core/RegisterUtilities.h @@ -55,6 +55,10 @@ namespace AMD64 { enum { NT_REGS = 33, NT_FPREGS = 35 }; } +namespace I386 { +enum { NT_REGS = 33, NT_FPREGS = 35 }; +} + } // namespace NETBSD namespace OPENBSD { @@ -96,6 +100,9 @@ DataExtractor getRegset(llvm::ArrayRef Notes, llvm::ArrayRef RegsetDescs); constexpr RegsetDesc FPR_Desc[] = { + // FreeBSD/i386 core NT_FPREGSET is x87 FSAVE result but the XSAVE dump + // starts with FXSAVE struct, so use that instead if available. + {llvm::Triple::FreeBSD, llvm::Triple::x86, llvm::ELF::NT_X86_XSTATE}, {llvm::Triple::FreeBSD, llvm::Triple::UnknownArch, llvm::ELF::NT_FPREGSET}, // In a i386 core file NT_FPREGSET is present, but it's not the result // of the FXSAVE instruction like in 64 bit files. @@ -103,10 +110,19 @@ constexpr RegsetDesc FPR_Desc[] = { {llvm::Triple::Linux, llvm::Triple::x86, llvm::ELF::NT_PRXFPREG}, {llvm::Triple::Linux, llvm::Triple::UnknownArch, llvm::ELF::NT_FPREGSET}, {llvm::Triple::NetBSD, llvm::Triple::aarch64, NETBSD::AARCH64::NT_FPREGS}, + {llvm::Triple::NetBSD, llvm::Triple::x86, NETBSD::I386::NT_FPREGS}, {llvm::Triple::NetBSD, llvm::Triple::x86_64, NETBSD::AMD64::NT_FPREGS}, {llvm::Triple::OpenBSD, llvm::Triple::UnknownArch, OPENBSD::NT_FPREGS}, }; +constexpr RegsetDesc AARCH64_SVE_Desc[] = { + {llvm::Triple::Linux, llvm::Triple::aarch64, llvm::ELF::NT_ARM_SVE}, +}; + +constexpr RegsetDesc AARCH64_PAC_Desc[] = { + {llvm::Triple::Linux, llvm::Triple::aarch64, llvm::ELF::NT_ARM_PAC_MASK}, +}; + constexpr RegsetDesc PPC_VMX_Desc[] = { {llvm::Triple::FreeBSD, llvm::Triple::UnknownArch, llvm::ELF::NT_PPC_VMX}, {llvm::Triple::Linux, llvm::Triple::UnknownArch, llvm::ELF::NT_PPC_VMX}, diff --git a/gnu/llvm/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp b/gnu/llvm/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp index 6b5acfa4bc1..937d074869a 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp +++ b/gnu/llvm/lldb/source/Plugins/Process/elf-core/ThreadElfCore.cpp @@ -18,10 +18,9 @@ #include "Plugins/Process/Utility/RegisterContextFreeBSD_powerpc.h" #include "Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.h" #include "Plugins/Process/Utility/RegisterContextLinux_i386.h" -#include "Plugins/Process/Utility/RegisterContextLinux_mips.h" -#include "Plugins/Process/Utility/RegisterContextLinux_mips64.h" #include "Plugins/Process/Utility/RegisterContextLinux_s390x.h" #include "Plugins/Process/Utility/RegisterContextLinux_x86_64.h" +#include "Plugins/Process/Utility/RegisterContextNetBSD_i386.h" #include "Plugins/Process/Utility/RegisterContextNetBSD_x86_64.h" #include "Plugins/Process/Utility/RegisterContextOpenBSD_i386.h" #include "Plugins/Process/Utility/RegisterContextOpenBSD_x86_64.h" @@ -82,9 +81,7 @@ ThreadElfCore::CreateRegisterContextForFrame(StackFrame *frame) { case llvm::Triple::FreeBSD: { switch (arch.GetMachine()) { case llvm::Triple::aarch64: - break; case llvm::Triple::arm: - reg_interface = new RegisterInfoPOSIX_arm(arch); break; case llvm::Triple::ppc: reg_interface = new RegisterContextFreeBSD_powerpc32(arch); @@ -111,6 +108,9 @@ ThreadElfCore::CreateRegisterContextForFrame(StackFrame *frame) { switch (arch.GetMachine()) { case llvm::Triple::aarch64: break; + case llvm::Triple::x86: + reg_interface = new RegisterContextNetBSD_i386(arch); + break; case llvm::Triple::x86_64: reg_interface = new RegisterContextNetBSD_x86_64(arch); break; @@ -122,19 +122,8 @@ ThreadElfCore::CreateRegisterContextForFrame(StackFrame *frame) { case llvm::Triple::Linux: { switch (arch.GetMachine()) { - case llvm::Triple::arm: - reg_interface = new RegisterInfoPOSIX_arm(arch); - break; case llvm::Triple::aarch64: break; - case llvm::Triple::mipsel: - case llvm::Triple::mips: - reg_interface = new RegisterContextLinux_mips(arch); - break; - case llvm::Triple::mips64el: - case llvm::Triple::mips64: - reg_interface = new RegisterContextLinux_mips64(arch); - break; case llvm::Triple::ppc64le: reg_interface = new RegisterInfoPOSIX_ppc64le(arch); break; @@ -157,9 +146,6 @@ ThreadElfCore::CreateRegisterContextForFrame(StackFrame *frame) { switch (arch.GetMachine()) { case llvm::Triple::aarch64: break; - case llvm::Triple::arm: - reg_interface = new RegisterInfoPOSIX_arm(arch); - break; case llvm::Triple::x86: reg_interface = new RegisterContextOpenBSD_i386(arch); break; @@ -176,7 +162,8 @@ ThreadElfCore::CreateRegisterContextForFrame(StackFrame *frame) { break; } - if (!reg_interface && arch.GetMachine() != llvm::Triple::aarch64) { + if (!reg_interface && arch.GetMachine() != llvm::Triple::aarch64 && + arch.GetMachine() != llvm::Triple::arm) { LLDB_LOGF(log, "elf-core::%s:: Architecture(%d) or OS(%d) not supported", __FUNCTION__, arch.GetMachine(), arch.GetTriple().getOS()); assert(false && "Architecture or OS not supported"); @@ -184,13 +171,13 @@ ThreadElfCore::CreateRegisterContextForFrame(StackFrame *frame) { switch (arch.GetMachine()) { case llvm::Triple::aarch64: - m_thread_reg_ctx_sp = std::make_shared( - *this, std::make_unique(arch), - m_gpregset_data, m_notes); + m_thread_reg_ctx_sp = RegisterContextCorePOSIX_arm64::Create( + *this, arch, m_gpregset_data, m_notes); break; case llvm::Triple::arm: m_thread_reg_ctx_sp = std::make_shared( - *this, reg_interface, m_gpregset_data, m_notes); + *this, std::make_unique(arch), m_gpregset_data, + m_notes); break; case llvm::Triple::mipsel: case llvm::Triple::mips: diff --git a/gnu/llvm/lldb/source/Plugins/Process/gdb-remote/GDBRemoteClientBase.cpp b/gnu/llvm/lldb/source/Plugins/Process/gdb-remote/GDBRemoteClientBase.cpp index fdaa60e2df4..a4c71e864a7 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/gdb-remote/GDBRemoteClientBase.cpp +++ b/gnu/llvm/lldb/source/Plugins/Process/gdb-remote/GDBRemoteClientBase.cpp @@ -20,7 +20,10 @@ using namespace lldb_private; using namespace lldb_private::process_gdb_remote; using namespace std::chrono; -static const seconds kInterruptTimeout(5); +// When we've sent a continue packet and are waiting for the target to stop, +// we wake up the wait with this interval to make sure the stub hasn't gone +// away while we were waiting. +static const seconds kWakeupInterval(5); ///////////////////////// // GDBRemoteClientBase // @@ -35,7 +38,8 @@ GDBRemoteClientBase::GDBRemoteClientBase(const char *comm_name, StateType GDBRemoteClientBase::SendContinuePacketAndWaitForResponse( ContinueDelegate &delegate, const UnixSignals &signals, - llvm::StringRef payload, StringExtractorGDBRemote &response) { + llvm::StringRef payload, std::chrono::seconds interrupt_timeout, + StringExtractorGDBRemote &response) { Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); response.Clear(); @@ -48,16 +52,37 @@ StateType GDBRemoteClientBase::SendContinuePacketAndWaitForResponse( if (!cont_lock) return eStateInvalid; OnRunPacketSent(true); - + // The main ReadPacket loop wakes up at computed_timeout intervals, just to + // check that the connection hasn't dropped. When we wake up we also check + // whether there is an interrupt request that has reached its endpoint. + // If we want a shorter interrupt timeout that kWakeupInterval, we need to + // choose the shorter interval for the wake up as well. + std::chrono::seconds computed_timeout = std::min(interrupt_timeout, + kWakeupInterval); for (;;) { - PacketResult read_result = ReadPacket(response, kInterruptTimeout, false); + PacketResult read_result = ReadPacket(response, computed_timeout, false); + // Reset the computed_timeout to the default value in case we are going + // round again. + computed_timeout = std::min(interrupt_timeout, kWakeupInterval); switch (read_result) { case PacketResult::ErrorReplyTimeout: { std::lock_guard lock(m_mutex); - if (m_async_count == 0) + if (m_async_count == 0) { continue; - if (steady_clock::now() >= m_interrupt_time + kInterruptTimeout) + } + auto cur_time = steady_clock::now(); + if (cur_time >= m_interrupt_endpoint) return eStateInvalid; + else { + // We woke up and found an interrupt is in flight, but we haven't + // exceeded the interrupt wait time. So reset the wait time to the + // time left till the interrupt timeout. But don't wait longer + // than our wakeup timeout. + auto new_wait = m_interrupt_endpoint - cur_time; + computed_timeout = std::min(kWakeupInterval, + std::chrono::duration_cast(new_wait)); + continue; + } break; } case PacketResult::Success: @@ -133,8 +158,9 @@ StateType GDBRemoteClientBase::SendContinuePacketAndWaitForResponse( } } -bool GDBRemoteClientBase::SendAsyncSignal(int signo) { - Lock lock(*this, true); +bool GDBRemoteClientBase::SendAsyncSignal( + int signo, std::chrono::seconds interrupt_timeout) { + Lock lock(*this, interrupt_timeout); if (!lock || !lock.DidInterrupt()) return false; @@ -144,25 +170,26 @@ bool GDBRemoteClientBase::SendAsyncSignal(int signo) { return true; } -bool GDBRemoteClientBase::Interrupt() { - Lock lock(*this, true); +bool GDBRemoteClientBase::Interrupt(std::chrono::seconds interrupt_timeout) { + Lock lock(*this, interrupt_timeout); if (!lock.DidInterrupt()) return false; m_should_stop = true; return true; } + GDBRemoteCommunication::PacketResult GDBRemoteClientBase::SendPacketAndWaitForResponse( llvm::StringRef payload, StringExtractorGDBRemote &response, - bool send_async) { - Lock lock(*this, send_async); + std::chrono::seconds interrupt_timeout) { + Lock lock(*this, interrupt_timeout); if (!lock) { if (Log *log = ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)) LLDB_LOGF(log, "GDBRemoteClientBase::%s failed to get mutex, not sending " - "packet '%.*s' (send_async=%d)", - __FUNCTION__, int(payload.size()), payload.data(), send_async); + "packet '%.*s'", + __FUNCTION__, int(payload.size()), payload.data()); return PacketResult::ErrorSendFailed; } @@ -172,16 +199,16 @@ GDBRemoteClientBase::SendPacketAndWaitForResponse( GDBRemoteCommunication::PacketResult GDBRemoteClientBase::SendPacketAndReceiveResponseWithOutputSupport( llvm::StringRef payload, StringExtractorGDBRemote &response, - bool send_async, + std::chrono::seconds interrupt_timeout, llvm::function_ref output_callback) { - Lock lock(*this, send_async); + Lock lock(*this, interrupt_timeout); if (!lock) { if (Log *log = ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)) LLDB_LOGF(log, "GDBRemoteClientBase::%s failed to get mutex, not sending " - "packet '%.*s' (send_async=%d)", - __FUNCTION__, int(payload.size()), payload.data(), send_async); + "packet '%.*s'", + __FUNCTION__, int(payload.size()), payload.data()); return PacketResult::ErrorSendFailed; } @@ -222,13 +249,14 @@ GDBRemoteClientBase::SendPacketAndWaitForResponseNoLock( return packet_result; } -bool GDBRemoteClientBase::SendvContPacket(llvm::StringRef payload, - StringExtractorGDBRemote &response) { +bool GDBRemoteClientBase::SendvContPacket( + llvm::StringRef payload, std::chrono::seconds interrupt_timeout, + StringExtractorGDBRemote &response) { Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); LLDB_LOGF(log, "GDBRemoteCommunicationClient::%s ()", __FUNCTION__); // we want to lock down packet sending while we continue - Lock lock(*this, true); + Lock lock(*this, interrupt_timeout); LLDB_LOGF(log, "GDBRemoteCommunicationClient::%s () sending vCont packet: %.*s", @@ -336,18 +364,20 @@ GDBRemoteClientBase::ContinueLock::lock() { // GDBRemoteClientBase::Lock // /////////////////////////////// -GDBRemoteClientBase::Lock::Lock(GDBRemoteClientBase &comm, bool interrupt) +GDBRemoteClientBase::Lock::Lock(GDBRemoteClientBase &comm, + std::chrono::seconds interrupt_timeout) : m_async_lock(comm.m_async_mutex, std::defer_lock), m_comm(comm), - m_acquired(false), m_did_interrupt(false) { - SyncWithContinueThread(interrupt); + m_interrupt_timeout(interrupt_timeout), m_acquired(false), + m_did_interrupt(false) { + SyncWithContinueThread(); if (m_acquired) m_async_lock.lock(); } -void GDBRemoteClientBase::Lock::SyncWithContinueThread(bool interrupt) { +void GDBRemoteClientBase::Lock::SyncWithContinueThread() { Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); std::unique_lock lock(m_comm.m_mutex); - if (m_comm.m_is_running && !interrupt) + if (m_comm.m_is_running && m_interrupt_timeout == std::chrono::seconds(0)) return; // We were asked to avoid interrupting the sender. Lock is not // acquired. @@ -365,9 +395,9 @@ void GDBRemoteClientBase::Lock::SyncWithContinueThread(bool interrupt) { "interrupt packet"); return; } + m_comm.m_interrupt_endpoint = steady_clock::now() + m_interrupt_timeout; if (log) log->PutCString("GDBRemoteClientBase::Lock::Lock sent packet: \\x03"); - m_comm.m_interrupt_time = steady_clock::now(); } m_comm.m_cv.wait(lock, [this] { return !m_comm.m_is_running; }); m_did_interrupt = true; diff --git a/gnu/llvm/lldb/source/Plugins/Process/gdb-remote/GDBRemoteClientBase.h b/gnu/llvm/lldb/source/Plugins/Process/gdb-remote/GDBRemoteClientBase.h index cd9f6ebd764..518b81318b6 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/gdb-remote/GDBRemoteClientBase.h +++ b/gnu/llvm/lldb/source/Plugins/Process/gdb-remote/GDBRemoteClientBase.h @@ -33,29 +33,46 @@ public: GDBRemoteClientBase(const char *comm_name, const char *listener_name); - bool SendAsyncSignal(int signo); + bool SendAsyncSignal(int signo, std::chrono::seconds interrupt_timeout); - bool Interrupt(); + bool Interrupt(std::chrono::seconds interrupt_timeout); lldb::StateType SendContinuePacketAndWaitForResponse( ContinueDelegate &delegate, const UnixSignals &signals, - llvm::StringRef payload, StringExtractorGDBRemote &response); - - PacketResult SendPacketAndWaitForResponse(llvm::StringRef payload, - StringExtractorGDBRemote &response, - bool send_async); + llvm::StringRef payload, std::chrono::seconds interrupt_timeout, + StringExtractorGDBRemote &response); + + // If interrupt_timeout == 0 seconds, don't interrupt the target. + // Only send the packet if the target is stopped. + // If you want to use this mode, use the fact that the timeout is defaulted + // so it's clear from the call-site that you are using no-interrupt. + // If it is non-zero, interrupt the target if it is running, and + // send the packet. + // It the target doesn't respond within the given timeout, it returns + // ErrorReplyTimeout. + PacketResult SendPacketAndWaitForResponse( + llvm::StringRef payload, StringExtractorGDBRemote &response, + std::chrono::seconds interrupt_timeout = std::chrono::seconds(0)); PacketResult SendPacketAndReceiveResponseWithOutputSupport( llvm::StringRef payload, StringExtractorGDBRemote &response, - bool send_async, + std::chrono::seconds interrupt_timeout, llvm::function_ref output_callback); bool SendvContPacket(llvm::StringRef payload, + std::chrono::seconds interrupt_timeout, StringExtractorGDBRemote &response); class Lock { public: - Lock(GDBRemoteClientBase &comm, bool interrupt); + // If interrupt_timeout == 0 seconds, only take the lock if the target is + // not running. If using this option, use the fact that the + // interrupt_timeout is defaulted so it will be obvious at the call site + // that you are choosing this mode. If it is non-zero, interrupt the target + // if it is running, waiting for the given timeout for the interrupt to + // succeed. + Lock(GDBRemoteClientBase &comm, + std::chrono::seconds interrupt_timeout = std::chrono::seconds(0)); ~Lock(); explicit operator bool() { return m_acquired; } @@ -67,10 +84,11 @@ public: private: std::unique_lock m_async_lock; GDBRemoteClientBase &m_comm; + std::chrono::seconds m_interrupt_timeout; bool m_acquired; bool m_did_interrupt; - void SyncWithContinueThread(bool interrupt); + void SyncWithContinueThread(); }; protected: @@ -109,7 +127,7 @@ private: /// When was the interrupt packet sent. Used to make sure we time out if the /// stub does not respond to interrupt requests. - std::chrono::time_point m_interrupt_time; + std::chrono::time_point m_interrupt_endpoint; /// Number of threads interested in sending. uint32_t m_async_count; diff --git a/gnu/llvm/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp b/gnu/llvm/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp index bfacd41dc1a..013d407c0fc 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp +++ b/gnu/llvm/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp @@ -8,9 +8,9 @@ #include "GDBRemoteCommunication.h" +#include +#include #include -#include -#include #include #include "lldb/Core/StreamFile.h" @@ -50,7 +50,7 @@ #include #endif -#if defined(HAVE_LIBZ) +#if LLVM_ENABLE_ZLIB #include #endif @@ -284,7 +284,7 @@ GDBRemoteCommunication::WaitForPacketNoLock(StringExtractorGDBRemote &packet, LLDB_LOGV(log, "Read(buffer, sizeof(buffer), timeout = {0}, " "status = {1}, error = {2}) => bytes_read = {3}", - timeout, Communication::ConnectionStatusAsCString(status), error, + timeout, Communication::ConnectionStatusAsString(status), error, bytes_read); if (bytes_read > 0) { @@ -582,7 +582,7 @@ bool GDBRemoteCommunication::DecompressPacket() { } #endif -#if defined(HAVE_LIBZ) +#if LLVM_ENABLE_ZLIB if (decompressed_bytes == 0 && decompressed_bufsize != ULONG_MAX && decompressed_buffer != nullptr && m_compression_type == CompressionType::ZlibDeflate) { @@ -1234,7 +1234,7 @@ GDBRemoteCommunication::ConnectLocally(GDBRemoteCommunication &client, const int backlog = 5; TCPSocket listen_socket(true, child_processes_inherit); if (llvm::Error error = - listen_socket.Listen("127.0.0.1:0", backlog).ToError()) + listen_socket.Listen("localhost:0", backlog).ToError()) return error; Socket *accept_socket; @@ -1243,7 +1243,7 @@ GDBRemoteCommunication::ConnectLocally(GDBRemoteCommunication &client, llvm::SmallString<32> remote_addr; llvm::raw_svector_ostream(remote_addr) - << "connect://127.0.0.1:" << listen_socket.GetLocalPortNumber(); + << "connect://localhost:" << listen_socket.GetLocalPortNumber(); std::unique_ptr conn_up( new ConnectionFileDescriptor()); diff --git a/gnu/llvm/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/gnu/llvm/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp index c75d5e106cd..b16aed4f5c9 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp +++ b/gnu/llvm/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp @@ -8,7 +8,7 @@ #include "GDBRemoteCommunicationClient.h" -#include +#include #include #include @@ -16,6 +16,7 @@ #include "lldb/Core/ModuleSpec.h" #include "lldb/Host/HostInfo.h" +#include "lldb/Host/StringConvert.h" #include "lldb/Host/XML.h" #include "lldb/Symbol/Symbol.h" #include "lldb/Target/MemoryRegionInfo.h" @@ -55,40 +56,7 @@ llvm::raw_ostream &process_gdb_remote::operator<<(llvm::raw_ostream &os, // GDBRemoteCommunicationClient constructor GDBRemoteCommunicationClient::GDBRemoteCommunicationClient() : GDBRemoteClientBase("gdb-remote.client", "gdb-remote.client.rx_packet"), - m_supports_not_sending_acks(eLazyBoolCalculate), - m_supports_thread_suffix(eLazyBoolCalculate), - m_supports_threads_in_stop_reply(eLazyBoolCalculate), - m_supports_vCont_all(eLazyBoolCalculate), - m_supports_vCont_any(eLazyBoolCalculate), - m_supports_vCont_c(eLazyBoolCalculate), - m_supports_vCont_C(eLazyBoolCalculate), - m_supports_vCont_s(eLazyBoolCalculate), - m_supports_vCont_S(eLazyBoolCalculate), - m_qHostInfo_is_valid(eLazyBoolCalculate), - m_curr_pid_is_valid(eLazyBoolCalculate), - m_qProcessInfo_is_valid(eLazyBoolCalculate), - m_qGDBServerVersion_is_valid(eLazyBoolCalculate), - m_supports_alloc_dealloc_memory(eLazyBoolCalculate), - m_supports_memory_region_info(eLazyBoolCalculate), - m_supports_watchpoint_support_info(eLazyBoolCalculate), - m_supports_detach_stay_stopped(eLazyBoolCalculate), - m_watchpoints_trigger_after_instruction(eLazyBoolCalculate), - m_attach_or_wait_reply(eLazyBoolCalculate), - m_prepare_for_reg_writing_reply(eLazyBoolCalculate), - m_supports_p(eLazyBoolCalculate), m_supports_x(eLazyBoolCalculate), - m_avoid_g_packets(eLazyBoolCalculate), - m_supports_QSaveRegisterState(eLazyBoolCalculate), - m_supports_qXfer_auxv_read(eLazyBoolCalculate), - m_supports_qXfer_libraries_read(eLazyBoolCalculate), - m_supports_qXfer_libraries_svr4_read(eLazyBoolCalculate), - m_supports_qXfer_features_read(eLazyBoolCalculate), - m_supports_qXfer_memory_map_read(eLazyBoolCalculate), - m_supports_augmented_libraries_svr4_read(eLazyBoolCalculate), - m_supports_jThreadExtendedInfo(eLazyBoolCalculate), - m_supports_jLoadedDynamicLibrariesInfos(eLazyBoolCalculate), - m_supports_jGetSharedCacheInfo(eLazyBoolCalculate), - m_supports_QPassSignals(eLazyBoolCalculate), - m_supports_error_string_reply(eLazyBoolCalculate), + m_supports_qProcessInfoPID(true), m_supports_qfProcessInfo(true), m_supports_qUserName(true), m_supports_qGroupName(true), m_supports_qThreadStopInfo(true), m_supports_z0(true), @@ -97,15 +65,11 @@ GDBRemoteCommunicationClient::GDBRemoteCommunicationClient() m_supports_QEnvironmentHexEncoded(true), m_supports_qSymbol(true), m_qSymbol_requests_done(false), m_supports_qModuleInfo(true), m_supports_jThreadsInfo(true), m_supports_jModulesInfo(true), - m_curr_pid(LLDB_INVALID_PROCESS_ID), m_curr_tid(LLDB_INVALID_THREAD_ID), - m_curr_tid_run(LLDB_INVALID_THREAD_ID), - m_num_supported_hardware_watchpoints(0), m_host_arch(), m_process_arch(), - m_os_build(), m_os_kernel(), m_hostname(), m_gdb_server_name(), - m_gdb_server_version(UINT32_MAX), m_default_packet_timeout(0), - m_max_packet_size(0), m_qSupported_response(), - m_supported_async_json_packets_is_valid(false), - m_supported_async_json_packets_sp(), m_qXfer_memory_map(), - m_qXfer_memory_map_loaded(false) {} + + m_host_arch(), m_process_arch(), m_os_build(), m_os_kernel(), + m_hostname(), m_gdb_server_name(), m_default_packet_timeout(0), + m_qSupported_response(), m_supported_async_json_packets_sp(), + m_qXfer_memory_map() {} // Destructor GDBRemoteCommunicationClient::~GDBRemoteCommunicationClient() { @@ -218,7 +182,7 @@ bool GDBRemoteCommunicationClient::QueryNoAckModeSupported() { ScopedTimeout timeout(*this, std::max(GetPacketTimeout(), seconds(6))); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse("QStartNoAckMode", response, false) == + if (SendPacketAndWaitForResponse("QStartNoAckMode", response) == PacketResult::Success) { if (response.IsOKResponse()) { m_send_acks = false; @@ -235,8 +199,8 @@ void GDBRemoteCommunicationClient::GetListThreadsInStopReplySupported() { m_supports_threads_in_stop_reply = eLazyBoolNo; StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse("QListThreadsInStopReply", response, - false) == PacketResult::Success) { + if (SendPacketAndWaitForResponse("QListThreadsInStopReply", response) == + PacketResult::Success) { if (response.IsOKResponse()) m_supports_threads_in_stop_reply = eLazyBoolYes; } @@ -248,8 +212,8 @@ bool GDBRemoteCommunicationClient::GetVAttachOrWaitSupported() { m_attach_or_wait_reply = eLazyBoolNo; StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse("qVAttachOrWaitSupported", response, - false) == PacketResult::Success) { + if (SendPacketAndWaitForResponse("qVAttachOrWaitSupported", response) == + PacketResult::Success) { if (response.IsOKResponse()) m_attach_or_wait_reply = eLazyBoolYes; } @@ -262,8 +226,8 @@ bool GDBRemoteCommunicationClient::GetSyncThreadStateSupported() { m_prepare_for_reg_writing_reply = eLazyBoolNo; StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse("qSyncThreadStateSupported", response, - false) == PacketResult::Success) { + if (SendPacketAndWaitForResponse("qSyncThreadStateSupported", response) == + PacketResult::Success) { if (response.IsOKResponse()) m_prepare_for_reg_writing_reply = eLazyBoolYes; } @@ -292,6 +256,7 @@ void GDBRemoteCommunicationClient::ResetDiscoverableSettings(bool did_exec) { m_prepare_for_reg_writing_reply = eLazyBoolCalculate; m_attach_or_wait_reply = eLazyBoolCalculate; m_avoid_g_packets = eLazyBoolCalculate; + m_supports_multiprocess = eLazyBoolCalculate; m_supports_qXfer_auxv_read = eLazyBoolCalculate; m_supports_qXfer_libraries_read = eLazyBoolCalculate; m_supports_qXfer_libraries_svr4_read = eLazyBoolCalculate; @@ -321,6 +286,7 @@ void GDBRemoteCommunicationClient::ResetDiscoverableSettings(bool did_exec) { m_gdb_server_name.clear(); m_gdb_server_version = UINT32_MAX; m_default_packet_timeout = seconds(0); + m_target_vm_page_size = 0; m_max_packet_size = 0; m_qSupported_response.clear(); m_supported_async_json_packets_is_valid = false; @@ -342,11 +308,17 @@ void GDBRemoteCommunicationClient::GetRemoteQSupported() { m_supports_augmented_libraries_svr4_read = eLazyBoolNo; m_supports_qXfer_features_read = eLazyBoolNo; m_supports_qXfer_memory_map_read = eLazyBoolNo; + m_supports_multiprocess = eLazyBoolNo; + m_supports_qEcho = eLazyBoolNo; + m_supports_QPassSignals = eLazyBoolNo; + m_supports_memory_tagging = eLazyBoolNo; + m_max_packet_size = UINT64_MAX; // It's supposed to always be there, but if // not, we assume no limit // build the qSupported packet - std::vector features = {"xmlRegisters=i386,arm,mips,arc"}; + std::vector features = {"xmlRegisters=i386,arm,mips,arc", + "multiprocess+"}; StreamString packet; packet.PutCString("qSupported"); for (uint32_t i = 0; i < features.size(); ++i) { @@ -355,95 +327,55 @@ void GDBRemoteCommunicationClient::GetRemoteQSupported() { } StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse(packet.GetString(), response, - /*send_async=*/false) == + if (SendPacketAndWaitForResponse(packet.GetString(), response) == PacketResult::Success) { - const char *response_cstr = response.GetStringRef().data(); - // Hang on to the qSupported packet, so that platforms can do custom // configuration of the transport before attaching/launching the process. - m_qSupported_response = response_cstr; - - if (::strstr(response_cstr, "qXfer:auxv:read+")) - m_supports_qXfer_auxv_read = eLazyBoolYes; - if (::strstr(response_cstr, "qXfer:libraries-svr4:read+")) - m_supports_qXfer_libraries_svr4_read = eLazyBoolYes; - if (::strstr(response_cstr, "augmented-libraries-svr4-read")) { - m_supports_qXfer_libraries_svr4_read = eLazyBoolYes; // implied - m_supports_augmented_libraries_svr4_read = eLazyBoolYes; - } - if (::strstr(response_cstr, "qXfer:libraries:read+")) - m_supports_qXfer_libraries_read = eLazyBoolYes; - if (::strstr(response_cstr, "qXfer:features:read+")) - m_supports_qXfer_features_read = eLazyBoolYes; - if (::strstr(response_cstr, "qXfer:memory-map:read+")) - m_supports_qXfer_memory_map_read = eLazyBoolYes; - - // Look for a list of compressions in the features list e.g. - // qXfer:features:read+;PacketSize=20000;qEcho+;SupportedCompressions=zlib- - // deflate,lzma - const char *features_list = ::strstr(response_cstr, "qXfer:features:"); - if (features_list) { - const char *compressions = - ::strstr(features_list, "SupportedCompressions="); - if (compressions) { - std::vector supported_compressions; - compressions += sizeof("SupportedCompressions=") - 1; - const char *end_of_compressions = strchr(compressions, ';'); - if (end_of_compressions == nullptr) { - end_of_compressions = strchr(compressions, '\0'); - } - const char *current_compression = compressions; - while (current_compression < end_of_compressions) { - const char *next_compression_name = strchr(current_compression, ','); - const char *end_of_this_word = next_compression_name; - if (next_compression_name == nullptr || - end_of_compressions < next_compression_name) { - end_of_this_word = end_of_compressions; - } - - if (end_of_this_word) { - if (end_of_this_word == current_compression) { - current_compression++; - } else { - std::string this_compression( - current_compression, end_of_this_word - current_compression); - supported_compressions.push_back(this_compression); - current_compression = end_of_this_word + 1; - } - } else { - supported_compressions.push_back(current_compression); - current_compression = end_of_compressions; - } + m_qSupported_response = response.GetStringRef().str(); + + llvm::SmallVector server_features; + response.GetStringRef().split(server_features, ';'); + + for (llvm::StringRef x : server_features) { + if (x == "qXfer:auxv:read+") + m_supports_qXfer_auxv_read = eLazyBoolYes; + else if (x == "qXfer:libraries-svr4:read+") + m_supports_qXfer_libraries_svr4_read = eLazyBoolYes; + else if (x == "augmented-libraries-svr4-read") { + m_supports_qXfer_libraries_svr4_read = eLazyBoolYes; // implied + m_supports_augmented_libraries_svr4_read = eLazyBoolYes; + } else if (x == "qXfer:libraries:read+") + m_supports_qXfer_libraries_read = eLazyBoolYes; + else if (x == "qXfer:features:read+") + m_supports_qXfer_features_read = eLazyBoolYes; + else if (x == "qXfer:memory-map:read+") + m_supports_qXfer_memory_map_read = eLazyBoolYes; + else if (x == "qEcho") + m_supports_qEcho = eLazyBoolYes; + else if (x == "QPassSignals+") + m_supports_QPassSignals = eLazyBoolYes; + else if (x == "multiprocess+") + m_supports_multiprocess = eLazyBoolYes; + else if (x == "memory-tagging+") + m_supports_memory_tagging = eLazyBoolYes; + // Look for a list of compressions in the features list e.g. + // qXfer:features:read+;PacketSize=20000;qEcho+;SupportedCompressions=zlib- + // deflate,lzma + else if (x.consume_front("SupportedCompressions=")) { + llvm::SmallVector compressions; + x.split(compressions, ','); + if (!compressions.empty()) + MaybeEnableCompression(compressions); + } else if (x.consume_front("PacketSize=")) { + StringExtractorGDBRemote packet_response(x); + m_max_packet_size = + packet_response.GetHexMaxU64(/*little_endian=*/false, UINT64_MAX); + if (m_max_packet_size == 0) { + m_max_packet_size = UINT64_MAX; // Must have been a garbled response + Log *log( + ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); + LLDB_LOGF(log, "Garbled PacketSize spec in qSupported response"); } - - if (supported_compressions.size() > 0) { - MaybeEnableCompression(supported_compressions); - } - } - } - - if (::strstr(response_cstr, "qEcho")) - m_supports_qEcho = eLazyBoolYes; - else - m_supports_qEcho = eLazyBoolNo; - - if (::strstr(response_cstr, "QPassSignals+")) - m_supports_QPassSignals = eLazyBoolYes; - else - m_supports_QPassSignals = eLazyBoolNo; - - const char *packet_size_str = ::strstr(response_cstr, "PacketSize="); - if (packet_size_str) { - StringExtractorGDBRemote packet_response(packet_size_str + - strlen("PacketSize=")); - m_max_packet_size = - packet_response.GetHexMaxU64(/*little_endian=*/false, UINT64_MAX); - if (m_max_packet_size == 0) { - m_max_packet_size = UINT64_MAX; // Must have been a garbled response - Log *log( - ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); - LLDB_LOGF(log, "Garbled PacketSize spec in qSupported response"); } } } @@ -453,8 +385,8 @@ bool GDBRemoteCommunicationClient::GetThreadSuffixSupported() { if (m_supports_thread_suffix == eLazyBoolCalculate) { StringExtractorGDBRemote response; m_supports_thread_suffix = eLazyBoolNo; - if (SendPacketAndWaitForResponse("QThreadSuffixSupported", response, - false) == PacketResult::Success) { + if (SendPacketAndWaitForResponse("QThreadSuffixSupported", response) == + PacketResult::Success) { if (response.IsOKResponse()) m_supports_thread_suffix = eLazyBoolYes; } @@ -470,7 +402,7 @@ bool GDBRemoteCommunicationClient::GetVContSupported(char flavor) { m_supports_vCont_C = eLazyBoolNo; m_supports_vCont_s = eLazyBoolNo; m_supports_vCont_S = eLazyBoolNo; - if (SendPacketAndWaitForResponse("vCont?", response, false) == + if (SendPacketAndWaitForResponse("vCont?", response) == PacketResult::Success) { const char *response_cstr = response.GetStringRef().data(); if (::strstr(response_cstr, ";c")) @@ -522,9 +454,9 @@ bool GDBRemoteCommunicationClient::GetVContSupported(char flavor) { GDBRemoteCommunication::PacketResult GDBRemoteCommunicationClient::SendThreadSpecificPacketAndWaitForResponse( - lldb::tid_t tid, StreamString &&payload, StringExtractorGDBRemote &response, - bool send_async) { - Lock lock(*this, send_async); + lldb::tid_t tid, StreamString &&payload, + StringExtractorGDBRemote &response) { + Lock lock(*this); if (!lock) { if (Log *log = ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet( GDBR_LOG_PROCESS | GDBR_LOG_PACKETS)) @@ -561,7 +493,7 @@ LazyBool GDBRemoteCommunicationClient::GetThreadPacketSupported( payload.PutCString(packetStr); StringExtractorGDBRemote response; if (SendThreadSpecificPacketAndWaitForResponse( - tid, std::move(payload), response, false) == PacketResult::Success && + tid, std::move(payload), response) == PacketResult::Success && response.IsNormalResponse()) { return eLazyBoolYes; } @@ -575,7 +507,7 @@ StructuredData::ObjectSP GDBRemoteCommunicationClient::GetThreadsInfo() { if (m_supports_jThreadsInfo) { StringExtractorGDBRemote response; response.SetResponseValidatorToJSON(); - if (SendPacketAndWaitForResponse("jThreadsInfo", response, false) == + if (SendPacketAndWaitForResponse("jThreadsInfo", response) == PacketResult::Success) { if (response.IsUnsupportedResponse()) { m_supports_jThreadsInfo = false; @@ -592,7 +524,7 @@ bool GDBRemoteCommunicationClient::GetThreadExtendedInfoSupported() { if (m_supports_jThreadExtendedInfo == eLazyBoolCalculate) { StringExtractorGDBRemote response; m_supports_jThreadExtendedInfo = eLazyBoolNo; - if (SendPacketAndWaitForResponse("jThreadExtendedInfo:", response, false) == + if (SendPacketAndWaitForResponse("jThreadExtendedInfo:", response) == PacketResult::Success) { if (response.IsOKResponse()) { m_supports_jThreadExtendedInfo = eLazyBoolYes; @@ -608,7 +540,7 @@ void GDBRemoteCommunicationClient::EnableErrorStringInPacket() { // We try to enable error strings in remote packets but if we fail, we just // work in the older way. m_supports_error_string_reply = eLazyBoolNo; - if (SendPacketAndWaitForResponse("QEnableErrorStrings", response, false) == + if (SendPacketAndWaitForResponse("QEnableErrorStrings", response) == PacketResult::Success) { if (response.IsOKResponse()) { m_supports_error_string_reply = eLazyBoolYes; @@ -622,8 +554,7 @@ bool GDBRemoteCommunicationClient::GetLoadedDynamicLibrariesInfosSupported() { StringExtractorGDBRemote response; m_supports_jLoadedDynamicLibrariesInfos = eLazyBoolNo; if (SendPacketAndWaitForResponse("jGetLoadedDynamicLibrariesInfos:", - response, - false) == PacketResult::Success) { + response) == PacketResult::Success) { if (response.IsOKResponse()) { m_supports_jLoadedDynamicLibrariesInfos = eLazyBoolYes; } @@ -636,7 +567,7 @@ bool GDBRemoteCommunicationClient::GetSharedCacheInfoSupported() { if (m_supports_jGetSharedCacheInfo == eLazyBoolCalculate) { StringExtractorGDBRemote response; m_supports_jGetSharedCacheInfo = eLazyBoolNo; - if (SendPacketAndWaitForResponse("jGetSharedCacheInfo:", response, false) == + if (SendPacketAndWaitForResponse("jGetSharedCacheInfo:", response) == PacketResult::Success) { if (response.IsOKResponse()) { m_supports_jGetSharedCacheInfo = eLazyBoolYes; @@ -646,13 +577,82 @@ bool GDBRemoteCommunicationClient::GetSharedCacheInfoSupported() { return m_supports_jGetSharedCacheInfo; } +bool GDBRemoteCommunicationClient::GetMemoryTaggingSupported() { + if (m_supports_memory_tagging == eLazyBoolCalculate) { + GetRemoteQSupported(); + } + return m_supports_memory_tagging == eLazyBoolYes; +} + +DataBufferSP GDBRemoteCommunicationClient::ReadMemoryTags(lldb::addr_t addr, + size_t len, + int32_t type) { + StreamString packet; + packet.Printf("qMemTags:%" PRIx64 ",%zx:%" PRIx32, addr, len, type); + StringExtractorGDBRemote response; + + Log *log = ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet(GDBR_LOG_MEMORY); + + if (SendPacketAndWaitForResponse(packet.GetString(), response) != + PacketResult::Success || + !response.IsNormalResponse()) { + LLDB_LOGF(log, "GDBRemoteCommunicationClient::%s: qMemTags packet failed", + __FUNCTION__); + return nullptr; + } + + // We are expecting + // m + + if (response.GetChar() != 'm') { + LLDB_LOGF(log, + "GDBRemoteCommunicationClient::%s: qMemTags response did not " + "begin with \"m\"", + __FUNCTION__); + return nullptr; + } + + size_t expected_bytes = response.GetBytesLeft() / 2; + DataBufferSP buffer_sp(new DataBufferHeap(expected_bytes, 0)); + size_t got_bytes = response.GetHexBytesAvail(buffer_sp->GetData()); + // Check both because in some situations chars are consumed even + // if the decoding fails. + if (response.GetBytesLeft() || (expected_bytes != got_bytes)) { + LLDB_LOGF( + log, + "GDBRemoteCommunicationClient::%s: Invalid data in qMemTags response", + __FUNCTION__); + return nullptr; + } + + return buffer_sp; +} + +Status GDBRemoteCommunicationClient::WriteMemoryTags( + lldb::addr_t addr, size_t len, int32_t type, + const std::vector &tags) { + // Format QMemTags:address,length:type:tags + StreamString packet; + packet.Printf("QMemTags:%" PRIx64 ",%zx:%" PRIx32 ":", addr, len, type); + packet.PutBytesAsRawHex8(tags.data(), tags.size()); + + Status status; + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse(packet.GetString(), response) != + PacketResult::Success || + !response.IsOKResponse()) { + status.SetErrorString("QMemTags packet failed"); + } + return status; +} + bool GDBRemoteCommunicationClient::GetxPacketSupported() { if (m_supports_x == eLazyBoolCalculate) { StringExtractorGDBRemote response; m_supports_x = eLazyBoolNo; char packet[256]; snprintf(packet, sizeof(packet), "x0,0"); - if (SendPacketAndWaitForResponse(packet, response, false) == + if (SendPacketAndWaitForResponse(packet, response) == PacketResult::Success) { if (response.IsOKResponse()) m_supports_x = eLazyBoolYes; @@ -664,7 +664,7 @@ bool GDBRemoteCommunicationClient::GetxPacketSupported() { GDBRemoteCommunicationClient::PacketResult GDBRemoteCommunicationClient::SendPacketsAndConcatenateResponses( const char *payload_prefix, std::string &response_string) { - Lock lock(*this, false); + Lock lock(*this); if (!lock) { Log *log(ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet(GDBR_LOG_PROCESS | GDBR_LOG_PACKETS)); @@ -725,11 +725,11 @@ lldb::pid_t GDBRemoteCommunicationClient::GetCurrentProcessID(bool allow_lazy) { // the thread id, which newer debugserver and lldb-gdbserver stubs return // correctly. StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse("qC", response, false) == - PacketResult::Success) { + if (SendPacketAndWaitForResponse("qC", response) == PacketResult::Success) { if (response.GetChar() == 'Q') { if (response.GetChar() == 'C') { - m_curr_pid = response.GetHexMaxU32(false, LLDB_INVALID_PROCESS_ID); + m_curr_pid_run = m_curr_pid = + response.GetHexMaxU64(false, LLDB_INVALID_PROCESS_ID); if (m_curr_pid != LLDB_INVALID_PROCESS_ID) { m_curr_pid_is_valid = eLazyBoolYes; return m_curr_pid; @@ -741,12 +741,14 @@ lldb::pid_t GDBRemoteCommunicationClient::GetCurrentProcessID(bool allow_lazy) { // If we don't get a response for $qC, check if $qfThreadID gives us a // result. if (m_curr_pid == LLDB_INVALID_PROCESS_ID) { - std::vector thread_ids; bool sequence_mutex_unavailable; - size_t size; - size = GetCurrentThreadIDs(thread_ids, sequence_mutex_unavailable); - if (size && !sequence_mutex_unavailable) { - m_curr_pid = thread_ids.front(); + auto ids = GetCurrentProcessAndThreadIDs(sequence_mutex_unavailable); + if (!ids.empty() && !sequence_mutex_unavailable) { + // If server returned an explicit PID, use that. + m_curr_pid_run = m_curr_pid = ids.front().first; + // Otherwise, use the TID of the first thread (Linux hack). + if (m_curr_pid == LLDB_INVALID_PROCESS_ID) + m_curr_pid_run = m_curr_pid = ids.front().second; m_curr_pid_is_valid = eLazyBoolYes; return m_curr_pid; } @@ -759,7 +761,7 @@ lldb::pid_t GDBRemoteCommunicationClient::GetCurrentProcessID(bool allow_lazy) { bool GDBRemoteCommunicationClient::GetLaunchSuccess(std::string &error_str) { error_str.clear(); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse("qLaunchSuccess", response, false) == + if (SendPacketAndWaitForResponse("qLaunchSuccess", response) == PacketResult::Success) { if (response.IsOKResponse()) return true; @@ -813,7 +815,7 @@ int GDBRemoteCommunicationClient::SendArgumentsPacket( } StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse(packet.GetString(), response, false) == + if (SendPacketAndWaitForResponse(packet.GetString(), response) == PacketResult::Success) { if (response.IsOKResponse()) return 0; @@ -863,7 +865,7 @@ int GDBRemoteCommunicationClient::SendEnvironmentPacket( if (m_supports_QEnvironmentHexEncoded) { packet.PutCString("QEnvironmentHexEncoded:"); packet.PutBytesAsRawHex8(name_equal_value, strlen(name_equal_value)); - if (SendPacketAndWaitForResponse(packet.GetString(), response, false) == + if (SendPacketAndWaitForResponse(packet.GetString(), response) == PacketResult::Success) { if (response.IsOKResponse()) return 0; @@ -877,7 +879,7 @@ int GDBRemoteCommunicationClient::SendEnvironmentPacket( } else if (m_supports_QEnvironment) { packet.Printf("QEnvironment:%s", name_equal_value); - if (SendPacketAndWaitForResponse(packet.GetString(), response, false) == + if (SendPacketAndWaitForResponse(packet.GetString(), response) == PacketResult::Success) { if (response.IsOKResponse()) return 0; @@ -897,7 +899,7 @@ int GDBRemoteCommunicationClient::SendLaunchArchPacket(char const *arch) { StreamString packet; packet.Printf("QLaunchArch:%s", arch); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse(packet.GetString(), response, false) == + if (SendPacketAndWaitForResponse(packet.GetString(), response) == PacketResult::Success) { if (response.IsOKResponse()) return 0; @@ -915,7 +917,7 @@ int GDBRemoteCommunicationClient::SendLaunchEventDataPacket( StreamString packet; packet.Printf("QSetProcessEvent:%s", data); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse(packet.GetString(), response, false) == + if (SendPacketAndWaitForResponse(packet.GetString(), response) == PacketResult::Success) { if (response.IsOKResponse()) { if (was_supported) @@ -1000,7 +1002,7 @@ bool GDBRemoteCommunicationClient::GetGDBServerVersion() { m_qGDBServerVersion_is_valid = eLazyBoolNo; StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse("qGDBServerVersion", response, false) == + if (SendPacketAndWaitForResponse("qGDBServerVersion", response) == PacketResult::Success) { if (response.IsNormalResponse()) { llvm::StringRef name, value; @@ -1025,9 +1027,9 @@ bool GDBRemoteCommunicationClient::GetGDBServerVersion() { } void GDBRemoteCommunicationClient::MaybeEnableCompression( - std::vector supported_compressions) { + llvm::ArrayRef supported_compressions) { CompressionType avail_type = CompressionType::None; - std::string avail_name; + llvm::StringRef avail_name; #if defined(HAVE_LIBCOMPRESSION) if (avail_type == CompressionType::None) { @@ -1053,7 +1055,7 @@ void GDBRemoteCommunicationClient::MaybeEnableCompression( } #endif -#if defined(HAVE_LIBZ) +#if LLVM_ENABLE_ZLIB if (avail_type == CompressionType::None) { for (auto compression : supported_compressions) { if (compression == "zlib-deflate") { @@ -1091,8 +1093,8 @@ void GDBRemoteCommunicationClient::MaybeEnableCompression( if (avail_type != CompressionType::None) { StringExtractorGDBRemote response; - std::string packet = "QEnableCompression:type:" + avail_name + ";"; - if (SendPacketAndWaitForResponse(packet, response, false) != + llvm::Twine packet = "QEnableCompression:type:" + avail_name + ";"; + if (SendPacketAndWaitForResponse(packet.str(), response) != PacketResult::Success) return; @@ -1118,15 +1120,29 @@ uint32_t GDBRemoteCommunicationClient::GetGDBServerProgramVersion() { bool GDBRemoteCommunicationClient::GetDefaultThreadId(lldb::tid_t &tid) { StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse("qC", response, false) != - PacketResult::Success) + if (SendPacketAndWaitForResponse("qC", response) != PacketResult::Success) return false; if (!response.IsNormalResponse()) return false; - if (response.GetChar() == 'Q' && response.GetChar() == 'C') - tid = response.GetHexMaxU32(true, -1); + if (response.GetChar() == 'Q' && response.GetChar() == 'C') { + auto pid_tid = response.GetPidTid(0); + if (!pid_tid) + return false; + + lldb::pid_t pid = pid_tid->first; + // invalid + if (pid == StringExtractorGDBRemote::AllProcesses) + return false; + + // if we get pid as well, update m_curr_pid + if (pid != 0) { + m_curr_pid_run = m_curr_pid = pid; + m_curr_pid_is_valid = eLazyBoolYes; + } + tid = pid_tid->second; + } return true; } @@ -1154,7 +1170,7 @@ bool GDBRemoteCommunicationClient::GetHostInfo(bool force) { ScopedTimeout timeout(*this, seconds(10)); m_qHostInfo_is_valid = eLazyBoolNo; StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse("qHostInfo", response, false) == + if (SendPacketAndWaitForResponse("qHostInfo", response) == PacketResult::Success) { if (response.IsNormalResponse()) { llvm::StringRef name; @@ -1219,11 +1235,13 @@ bool GDBRemoteCommunicationClient::GetHostInfo(bool force) { } else if (name.equals("ptrsize")) { if (!value.getAsInteger(0, pointer_byte_size)) ++num_keys_decoded; + } else if (name.equals("addressing_bits")) { + if (!value.getAsInteger(0, m_addressing_bits)) + ++num_keys_decoded; } else if (name.equals("os_version") || - name.equals( - "version")) // Older debugserver binaries used the - // "version" key instead of - // "os_version"... + name.equals("version")) // Older debugserver binaries used + // the "version" key instead of + // "os_version"... { if (!m_os_version.tryParse(value)) ++num_keys_decoded; @@ -1245,6 +1263,12 @@ bool GDBRemoteCommunicationClient::GetHostInfo(bool force) { SetPacketTimeout(m_default_packet_timeout); ++num_keys_decoded; } + } else if (name.equals("vm-page-size")) { + int page_size; + if (!value.getAsInteger(0, page_size)) { + m_target_vm_page_size = page_size; + ++num_keys_decoded; + } } } @@ -1344,7 +1368,7 @@ int GDBRemoteCommunicationClient::SendAttach( ::snprintf(packet, sizeof(packet), "vAttach;%" PRIx64, pid); UNUSED_IF_ASSERT_DISABLED(packet_len); assert(packet_len < (int)sizeof(packet)); - if (SendPacketAndWaitForResponse(packet, response, false) == + if (SendPacketAndWaitForResponse(packet, response) == PacketResult::Success) { if (response.IsErrorResponse()) return response.GetError(); @@ -1360,7 +1384,7 @@ int GDBRemoteCommunicationClient::SendStdinNotification(const char *data, packet.PutCString("I"); packet.PutBytesAsRawHex8(data, data_len); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse(packet.GetString(), response, false) == + if (SendPacketAndWaitForResponse(packet.GetString(), response) == PacketResult::Success) { return 0; } @@ -1374,6 +1398,11 @@ GDBRemoteCommunicationClient::GetHostArchitecture() { return m_host_arch; } +uint32_t GDBRemoteCommunicationClient::GetAddressingBits() { + if (m_qHostInfo_is_valid == eLazyBoolCalculate) + GetHostInfo(); + return m_addressing_bits; +} seconds GDBRemoteCommunicationClient::GetHostDefaultPacketTimeout() { if (m_qHostInfo_is_valid == eLazyBoolCalculate) GetHostInfo(); @@ -1393,7 +1422,7 @@ addr_t GDBRemoteCommunicationClient::AllocateMemory(size_t size, assert(packet_len < (int)sizeof(packet)); UNUSED_IF_ASSERT_DISABLED(packet_len); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse(packet, response, false) == + if (SendPacketAndWaitForResponse(packet, response) == PacketResult::Success) { if (response.IsUnsupportedResponse()) m_supports_alloc_dealloc_memory = eLazyBoolNo; @@ -1415,7 +1444,7 @@ bool GDBRemoteCommunicationClient::DeallocateMemory(addr_t addr) { assert(packet_len < (int)sizeof(packet)); UNUSED_IF_ASSERT_DISABLED(packet_len); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse(packet, response, false) == + if (SendPacketAndWaitForResponse(packet, response) == PacketResult::Success) { if (response.IsUnsupportedResponse()) m_supports_alloc_dealloc_memory = eLazyBoolNo; @@ -1439,7 +1468,7 @@ Status GDBRemoteCommunicationClient::Detach(bool keep_stopped) { assert(packet_len < (int)sizeof(packet)); UNUSED_IF_ASSERT_DISABLED(packet_len); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse(packet, response, false) == + if (SendPacketAndWaitForResponse(packet, response) == PacketResult::Success && response.IsOKResponse()) { m_supports_detach_stay_stopped = eLazyBoolYes; @@ -1453,15 +1482,13 @@ Status GDBRemoteCommunicationClient::Detach(bool keep_stopped) { return error; } else { StringExtractorGDBRemote response; - PacketResult packet_result = - SendPacketAndWaitForResponse("D1", response, false); + PacketResult packet_result = SendPacketAndWaitForResponse("D1", response); if (packet_result != PacketResult::Success) error.SetErrorString("Sending extended disconnect packet failed."); } } else { StringExtractorGDBRemote response; - PacketResult packet_result = - SendPacketAndWaitForResponse("D", response, false); + PacketResult packet_result = SendPacketAndWaitForResponse("D", response); if (packet_result != PacketResult::Success) error.SetErrorString("Sending disconnect packet failed."); } @@ -1481,7 +1508,7 @@ Status GDBRemoteCommunicationClient::GetMemoryRegionInfo( assert(packet_len < (int)sizeof(packet)); UNUSED_IF_ASSERT_DISABLED(packet_len); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse(packet, response, false) == + if (SendPacketAndWaitForResponse(packet, response) == PacketResult::Success && response.GetResponseType() == StringExtractorGDBRemote::eResponse) { llvm::StringRef name; @@ -1529,15 +1556,52 @@ Status GDBRemoteCommunicationClient::GetMemoryRegionInfo( std::string name; name_extractor.GetHexByteString(name); region_info.SetName(name.c_str()); + } else if (name.equals("flags")) { + region_info.SetMemoryTagged(MemoryRegionInfo::eNo); + + llvm::StringRef flags = value; + llvm::StringRef flag; + while (flags.size()) { + flags = flags.ltrim(); + std::tie(flag, flags) = flags.split(' '); + // To account for trailing whitespace + if (flag.size()) { + if (flag == "mt") { + region_info.SetMemoryTagged(MemoryRegionInfo::eYes); + break; + } + } + } } else if (name.equals("error")) { StringExtractorGDBRemote error_extractor(value); std::string error_string; // Now convert the HEX bytes into a string value error_extractor.GetHexByteString(error_string); error.SetErrorString(error_string.c_str()); + } else if (name.equals("dirty-pages")) { + std::vector dirty_page_list; + std::string comma_sep_str = value.str(); + size_t comma_pos; + addr_t page; + while ((comma_pos = comma_sep_str.find(',')) != std::string::npos) { + comma_sep_str[comma_pos] = '\0'; + page = StringConvert::ToUInt64(comma_sep_str.c_str(), + LLDB_INVALID_ADDRESS, 16); + if (page != LLDB_INVALID_ADDRESS) + dirty_page_list.push_back(page); + comma_sep_str.erase(0, comma_pos + 1); + } + page = StringConvert::ToUInt64(comma_sep_str.c_str(), + LLDB_INVALID_ADDRESS, 16); + if (page != LLDB_INVALID_ADDRESS) + dirty_page_list.push_back(page); + region_info.SetDirtyPageList(dirty_page_list); } } + if (m_target_vm_page_size != 0) + region_info.SetPageSize(m_target_vm_page_size); + if (region_info.GetRange().IsValid()) { // We got a valid address range back but no permissions -- which means // this is an unmapped page @@ -1701,13 +1765,8 @@ Status GDBRemoteCommunicationClient::GetWatchpointSupportInfo(uint32_t &num) { // Set num to 0 first. num = 0; if (m_supports_watchpoint_support_info != eLazyBoolNo) { - char packet[64]; - const int packet_len = - ::snprintf(packet, sizeof(packet), "qWatchpointSupportInfo:"); - assert(packet_len < (int)sizeof(packet)); - UNUSED_IF_ASSERT_DISABLED(packet_len); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse(packet, response, false) == + if (SendPacketAndWaitForResponse("qWatchpointSupportInfo:", response) == PacketResult::Success) { m_supports_watchpoint_support_info = eLazyBoolYes; llvm::StringRef name; @@ -1776,7 +1835,7 @@ int GDBRemoteCommunicationClient::SetSTDIN(const FileSpec &file_spec) { packet.PutStringAsRawHex8(path); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse(packet.GetString(), response, false) == + if (SendPacketAndWaitForResponse(packet.GetString(), response) == PacketResult::Success) { if (response.IsOKResponse()) return 0; @@ -1796,7 +1855,7 @@ int GDBRemoteCommunicationClient::SetSTDOUT(const FileSpec &file_spec) { packet.PutStringAsRawHex8(path); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse(packet.GetString(), response, false) == + if (SendPacketAndWaitForResponse(packet.GetString(), response) == PacketResult::Success) { if (response.IsOKResponse()) return 0; @@ -1816,7 +1875,7 @@ int GDBRemoteCommunicationClient::SetSTDERR(const FileSpec &file_spec) { packet.PutStringAsRawHex8(path); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse(packet.GetString(), response, false) == + if (SendPacketAndWaitForResponse(packet.GetString(), response) == PacketResult::Success) { if (response.IsOKResponse()) return 0; @@ -1830,7 +1889,7 @@ int GDBRemoteCommunicationClient::SetSTDERR(const FileSpec &file_spec) { bool GDBRemoteCommunicationClient::GetWorkingDir(FileSpec &working_dir) { StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse("qGetWorkingDir", response, false) == + if (SendPacketAndWaitForResponse("qGetWorkingDir", response) == PacketResult::Success) { if (response.IsUnsupportedResponse()) return false; @@ -1852,7 +1911,7 @@ int GDBRemoteCommunicationClient::SetWorkingDir(const FileSpec &working_dir) { packet.PutStringAsRawHex8(path); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse(packet.GetString(), response, false) == + if (SendPacketAndWaitForResponse(packet.GetString(), response) == PacketResult::Success) { if (response.IsOKResponse()) return 0; @@ -1871,8 +1930,7 @@ int GDBRemoteCommunicationClient::SetDisableASLR(bool enable) { assert(packet_len < (int)sizeof(packet)); UNUSED_IF_ASSERT_DISABLED(packet_len); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse(packet, response, false) == - PacketResult::Success) { + if (SendPacketAndWaitForResponse(packet, response) == PacketResult::Success) { if (response.IsOKResponse()) return 0; uint8_t error = response.GetError(); @@ -1889,8 +1947,7 @@ int GDBRemoteCommunicationClient::SetDetachOnError(bool enable) { assert(packet_len < (int)sizeof(packet)); UNUSED_IF_ASSERT_DISABLED(packet_len); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse(packet, response, false) == - PacketResult::Success) { + if (SendPacketAndWaitForResponse(packet, response) == PacketResult::Success) { if (response.IsOKResponse()) return 0; uint8_t error = response.GetError(); @@ -2008,7 +2065,7 @@ bool GDBRemoteCommunicationClient::GetProcessInfo( assert(packet_len < (int)sizeof(packet)); UNUSED_IF_ASSERT_DISABLED(packet_len); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse(packet, response, false) == + if (SendPacketAndWaitForResponse(packet, response) == PacketResult::Success) { return DecodeProcessInfoResponse(response, process_info); } else { @@ -2033,7 +2090,7 @@ bool GDBRemoteCommunicationClient::GetCurrentProcessInfo(bool allow_lazy) { GetHostInfo(); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse("qProcessInfo", response, false) == + if (SendPacketAndWaitForResponse("qProcessInfo", response) == PacketResult::Success) { if (response.IsNormalResponse()) { llvm::StringRef name; @@ -2091,7 +2148,7 @@ bool GDBRemoteCommunicationClient::GetCurrentProcessInfo(bool allow_lazy) { m_qProcessInfo_is_valid = eLazyBoolYes; if (pid != LLDB_INVALID_PROCESS_ID) { m_curr_pid_is_valid = eLazyBoolYes; - m_curr_pid = pid; + m_curr_pid_run = m_curr_pid = pid; } // Set the ArchSpec from the triple if we have it. @@ -2120,6 +2177,7 @@ bool GDBRemoteCommunicationClient::GetCurrentProcessInfo(bool allow_lazy) { case llvm::Triple::COFF: m_process_arch.SetArchitecture(eArchTypeCOFF, cpu, sub); break; + case llvm::Triple::GOFF: case llvm::Triple::Wasm: case llvm::Triple::XCOFF: LLDB_LOGF(log, "error: not supported target architecture"); @@ -2228,7 +2286,7 @@ uint32_t GDBRemoteCommunicationClient::FindProcesses( // Increase timeout as the first qfProcessInfo packet takes a long time on // Android. The value of 1min was arrived at empirically. ScopedTimeout timeout(*this, minutes(1)); - if (SendPacketAndWaitForResponse(packet.GetString(), response, false) == + if (SendPacketAndWaitForResponse(packet.GetString(), response) == PacketResult::Success) { do { ProcessInstanceInfo process_info; @@ -2236,7 +2294,7 @@ uint32_t GDBRemoteCommunicationClient::FindProcesses( break; process_infos.push_back(process_info); response = StringExtractorGDBRemote(); - } while (SendPacketAndWaitForResponse("qsProcessInfo", response, false) == + } while (SendPacketAndWaitForResponse("qsProcessInfo", response) == PacketResult::Success); } else { m_supports_qfProcessInfo = false; @@ -2255,7 +2313,7 @@ bool GDBRemoteCommunicationClient::GetUserName(uint32_t uid, assert(packet_len < (int)sizeof(packet)); UNUSED_IF_ASSERT_DISABLED(packet_len); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse(packet, response, false) == + if (SendPacketAndWaitForResponse(packet, response) == PacketResult::Success) { if (response.IsNormalResponse()) { // Make sure we parsed the right number of characters. The response is @@ -2282,7 +2340,7 @@ bool GDBRemoteCommunicationClient::GetGroupName(uint32_t gid, assert(packet_len < (int)sizeof(packet)); UNUSED_IF_ASSERT_DISABLED(packet_len); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse(packet, response, false) == + if (SendPacketAndWaitForResponse(packet, response) == PacketResult::Success) { if (response.IsNormalResponse()) { // Make sure we parsed the right number of characters. The response is @@ -2310,8 +2368,7 @@ bool GDBRemoteCommunicationClient::SetNonStopMode(const bool enable) { StringExtractorGDBRemote response; // Send to target - if (SendPacketAndWaitForResponse(packet, response, false) == - PacketResult::Success) + if (SendPacketAndWaitForResponse(packet, response) == PacketResult::Success) if (response.IsOKResponse()) return true; @@ -2383,7 +2440,7 @@ void GDBRemoteCommunicationClient::TestPacketSpeed(const uint32_t num_packets, for (i = 0; i < num_packets; ++i) { const auto packet_start_time = steady_clock::now(); StringExtractorGDBRemote response; - SendPacketAndWaitForResponse(packet.GetString(), response, false); + SendPacketAndWaitForResponse(packet.GetString(), response); const auto packet_end_time = steady_clock::now(); packet_times.push_back(packet_end_time - packet_start_time); } @@ -2437,7 +2494,7 @@ void GDBRemoteCommunicationClient::TestPacketSpeed(const uint32_t num_packets, uint32_t packet_count = 0; while (bytes_read < recv_amount) { StringExtractorGDBRemote response; - SendPacketAndWaitForResponse(packet.GetString(), response, false); + SendPacketAndWaitForResponse(packet.GetString(), response); bytes_read += recv_size; ++packet_count; } @@ -2491,7 +2548,7 @@ bool GDBRemoteCommunicationClient::SendSpeedTestPacket(uint32_t send_size, } StringExtractorGDBRemote response; - return SendPacketAndWaitForResponse(packet.GetString(), response, false) == + return SendPacketAndWaitForResponse(packet.GetString(), response) == PacketResult::Success; } @@ -2521,7 +2578,7 @@ bool GDBRemoteCommunicationClient::LaunchGDBServer( // give the process a few seconds to startup ScopedTimeout timeout(*this, seconds(10)); - if (SendPacketAndWaitForResponse(stream.GetString(), response, false) == + if (SendPacketAndWaitForResponse(stream.GetString(), response) == PacketResult::Success) { llvm::StringRef name; llvm::StringRef value; @@ -2545,7 +2602,7 @@ size_t GDBRemoteCommunicationClient::QueryGDBServer( connection_urls.clear(); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse("qQueryGDBServer", response, false) != + if (SendPacketAndWaitForResponse("qQueryGDBServer", response) != PacketResult::Success) return 0; @@ -2584,7 +2641,7 @@ bool GDBRemoteCommunicationClient::KillSpawnedProcess(lldb::pid_t pid) { stream.Printf("qKillSpawnedProcess:%" PRId64, pid); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse(stream.GetString(), response, false) == + if (SendPacketAndWaitForResponse(stream.GetString(), response) == PacketResult::Success) { if (response.IsOKResponse()) return true; @@ -2592,25 +2649,27 @@ bool GDBRemoteCommunicationClient::KillSpawnedProcess(lldb::pid_t pid) { return false; } -bool GDBRemoteCommunicationClient::SetCurrentThread(uint64_t tid) { - if (m_curr_tid == tid) - return true; +llvm::Optional +GDBRemoteCommunicationClient::SendSetCurrentThreadPacket(uint64_t tid, + uint64_t pid, + char op) { + lldb_private::StreamString packet; + packet.PutChar('H'); + packet.PutChar(op); + + if (pid != LLDB_INVALID_PROCESS_ID) + packet.Printf("p%" PRIx64 ".", pid); - char packet[32]; - int packet_len; if (tid == UINT64_MAX) - packet_len = ::snprintf(packet, sizeof(packet), "Hg-1"); + packet.PutCString("-1"); else - packet_len = ::snprintf(packet, sizeof(packet), "Hg%" PRIx64, tid); - assert(packet_len + 1 < (int)sizeof(packet)); - UNUSED_IF_ASSERT_DISABLED(packet_len); + packet.Printf("%" PRIx64, tid); + StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse(packet, response, false) == - PacketResult::Success) { - if (response.IsOKResponse()) { - m_curr_tid = tid; - return true; - } + if (SendPacketAndWaitForResponse(packet.GetString(), response) + == PacketResult::Success) { + if (response.IsOKResponse()) + return {{pid, tid}}; /* * Connected bare-iron target (like YAMON gdb-stub) may not have support for @@ -2618,55 +2677,46 @@ bool GDBRemoteCommunicationClient::SetCurrentThread(uint64_t tid) { * The reply from '?' packet could be as simple as 'S05'. There is no packet * which can * give us pid and/or tid. Assume pid=tid=1 in such cases. - */ - if (response.IsUnsupportedResponse() && IsConnected()) { - m_curr_tid = 1; - return true; - } + */ + if (response.IsUnsupportedResponse() && IsConnected()) + return {{1, 1}}; } - return false; + return llvm::None; } -bool GDBRemoteCommunicationClient::SetCurrentThreadForRun(uint64_t tid) { - if (m_curr_tid_run == tid) +bool GDBRemoteCommunicationClient::SetCurrentThread(uint64_t tid, + uint64_t pid) { + if (m_curr_tid == tid && + (m_curr_pid == pid || LLDB_INVALID_PROCESS_ID == pid)) return true; - char packet[32]; - int packet_len; - if (tid == UINT64_MAX) - packet_len = ::snprintf(packet, sizeof(packet), "Hc-1"); - else - packet_len = ::snprintf(packet, sizeof(packet), "Hc%" PRIx64, tid); + llvm::Optional ret = SendSetCurrentThreadPacket(tid, pid, 'g'); + if (ret.hasValue()) { + if (ret->pid != LLDB_INVALID_PROCESS_ID) + m_curr_pid = ret->pid; + m_curr_tid = ret->tid; + } + return ret.hasValue(); +} - assert(packet_len + 1 < (int)sizeof(packet)); - UNUSED_IF_ASSERT_DISABLED(packet_len); - StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse(packet, response, false) == - PacketResult::Success) { - if (response.IsOKResponse()) { - m_curr_tid_run = tid; - return true; - } +bool GDBRemoteCommunicationClient::SetCurrentThreadForRun(uint64_t tid, + uint64_t pid) { + if (m_curr_tid_run == tid && + (m_curr_pid_run == pid || LLDB_INVALID_PROCESS_ID == pid)) + return true; - /* - * Connected bare-iron target (like YAMON gdb-stub) may not have support for - * Hc packet. - * The reply from '?' packet could be as simple as 'S05'. There is no packet - * which can - * give us pid and/or tid. Assume pid=tid=1 in such cases. - */ - if (response.IsUnsupportedResponse() && IsConnected()) { - m_curr_tid_run = 1; - return true; - } + llvm::Optional ret = SendSetCurrentThreadPacket(tid, pid, 'c'); + if (ret.hasValue()) { + if (ret->pid != LLDB_INVALID_PROCESS_ID) + m_curr_pid_run = ret->pid; + m_curr_tid_run = ret->tid; } - return false; + return ret.hasValue(); } bool GDBRemoteCommunicationClient::GetStopReply( StringExtractorGDBRemote &response) { - if (SendPacketAndWaitForResponse("?", response, false) == - PacketResult::Success) + if (SendPacketAndWaitForResponse("?", response) == PacketResult::Success) return response.IsNormalResponse(); return false; } @@ -2679,7 +2729,7 @@ bool GDBRemoteCommunicationClient::GetThreadStopInfo( ::snprintf(packet, sizeof(packet), "qThreadStopInfo%" PRIx64, tid); assert(packet_len < (int)sizeof(packet)); UNUSED_IF_ASSERT_DISABLED(packet_len); - if (SendPacketAndWaitForResponse(packet, response, false) == + if (SendPacketAndWaitForResponse(packet, response) == PacketResult::Success) { if (response.IsUnsupportedResponse()) m_supports_qThreadStopInfo = false; @@ -2695,7 +2745,8 @@ bool GDBRemoteCommunicationClient::GetThreadStopInfo( } uint8_t GDBRemoteCommunicationClient::SendGDBStoppointTypePacket( - GDBStoppointType type, bool insert, addr_t addr, uint32_t length) { + GDBStoppointType type, bool insert, addr_t addr, uint32_t length, + std::chrono::seconds timeout) { Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_BREAKPOINTS)); LLDB_LOGF(log, "GDBRemoteCommunicationClient::%s() %s at addr = 0x%" PRIx64, __FUNCTION__, insert ? "add" : "remove", addr); @@ -2716,7 +2767,7 @@ uint8_t GDBRemoteCommunicationClient::SendGDBStoppointTypePacket( // or "" (unsupported) response.SetResponseValidatorToOKErrorNotSupported(); // Try to send the breakpoint packet, and check that it was correctly sent - if (SendPacketAndWaitForResponse(packet, response, true) == + if (SendPacketAndWaitForResponse(packet, response, timeout) == PacketResult::Success) { // Receive and OK packet when the breakpoint successfully placed if (response.IsOKResponse()) @@ -2754,11 +2805,12 @@ uint8_t GDBRemoteCommunicationClient::SendGDBStoppointTypePacket( return UINT8_MAX; } -size_t GDBRemoteCommunicationClient::GetCurrentThreadIDs( - std::vector &thread_ids, bool &sequence_mutex_unavailable) { - thread_ids.clear(); +std::vector> +GDBRemoteCommunicationClient::GetCurrentProcessAndThreadIDs( + bool &sequence_mutex_unavailable) { + std::vector> ids; - Lock lock(*this, false); + Lock lock(*this); if (lock) { sequence_mutex_unavailable = false; StringExtractorGDBRemote response; @@ -2774,11 +2826,11 @@ size_t GDBRemoteCommunicationClient::GetCurrentThreadIDs( break; if (ch == 'm') { do { - tid_t tid = response.GetHexMaxU64(false, LLDB_INVALID_THREAD_ID); + auto pid_tid = response.GetPidTid(LLDB_INVALID_PROCESS_ID); + if (!pid_tid) + return {}; - if (tid != LLDB_INVALID_THREAD_ID) { - thread_ids.push_back(tid); - } + ids.push_back(pid_tid.getValue()); ch = response.GetChar(); // Skip the command separator } while (ch == ','); // Make sure we got a comma separator } @@ -2791,10 +2843,10 @@ size_t GDBRemoteCommunicationClient::GetCurrentThreadIDs( * be as simple as 'S05'. There is no packet which can give us pid and/or * tid. * Assume pid=tid=1 in such cases. - */ + */ if ((response.IsUnsupportedResponse() || response.IsNormalResponse()) && - thread_ids.size() == 0 && IsConnected()) { - thread_ids.push_back(1); + ids.size() == 0 && IsConnected()) { + ids.emplace_back(1, 1); } } else { Log *log(ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet(GDBR_LOG_PROCESS | @@ -2803,12 +2855,34 @@ size_t GDBRemoteCommunicationClient::GetCurrentThreadIDs( "packet 'qfThreadInfo'"); sequence_mutex_unavailable = true; } + + return ids; +} + +size_t GDBRemoteCommunicationClient::GetCurrentThreadIDs( + std::vector &thread_ids, bool &sequence_mutex_unavailable) { + lldb::pid_t pid = GetCurrentProcessID(); + thread_ids.clear(); + + auto ids = GetCurrentProcessAndThreadIDs(sequence_mutex_unavailable); + if (ids.empty() || sequence_mutex_unavailable) + return 0; + + for (auto id : ids) { + // skip threads that do not belong to the current process + if (id.first != LLDB_INVALID_PROCESS_ID && id.first != pid) + continue; + if (id.second != LLDB_INVALID_THREAD_ID && + id.second != StringExtractorGDBRemote::AllThreads) + thread_ids.push_back(id.second); + } + return thread_ids.size(); } lldb::addr_t GDBRemoteCommunicationClient::GetShlibInfoAddr() { StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse("qShlibInfoAddr", response, false) != + if (SendPacketAndWaitForResponse("qShlibInfoAddr", response) != PacketResult::Success || !response.IsNormalResponse()) return LLDB_INVALID_ADDRESS; @@ -2816,7 +2890,7 @@ lldb::addr_t GDBRemoteCommunicationClient::GetShlibInfoAddr() { } lldb_private::Status GDBRemoteCommunicationClient::RunShellCommand( - const char *command, // Shouldn't be NULL + llvm::StringRef command, const FileSpec & working_dir, // Pass empty FileSpec to use the current working directory int *status_ptr, // Pass NULL if you don't want the process exit status @@ -2827,7 +2901,7 @@ lldb_private::Status GDBRemoteCommunicationClient::RunShellCommand( const Timeout &timeout) { lldb_private::StreamString stream; stream.PutCString("qPlatform_shell:"); - stream.PutBytesAsRawHex8(command, strlen(command)); + stream.PutBytesAsRawHex8(command.data(), command.size()); stream.PutChar(','); uint32_t timeout_sec = UINT32_MAX; if (timeout) { @@ -2841,7 +2915,7 @@ lldb_private::Status GDBRemoteCommunicationClient::RunShellCommand( stream.PutStringAsRawHex8(path); } StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse(stream.GetString(), response, false) == + if (SendPacketAndWaitForResponse(stream.GetString(), response) == PacketResult::Success) { if (response.GetChar() != 'F') return Status("malformed reply"); @@ -2879,8 +2953,7 @@ Status GDBRemoteCommunicationClient::MakeDirectory(const FileSpec &file_spec, llvm::StringRef packet = stream.GetString(); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse(packet, response, false) != - PacketResult::Success) + if (SendPacketAndWaitForResponse(packet, response) != PacketResult::Success) return Status("failed to send '%s' packet", packet.str().c_str()); if (response.GetChar() != 'F') @@ -2901,8 +2974,7 @@ GDBRemoteCommunicationClient::SetFilePermissions(const FileSpec &file_spec, llvm::StringRef packet = stream.GetString(); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse(packet, response, false) != - PacketResult::Success) + if (SendPacketAndWaitForResponse(packet, response) != PacketResult::Success) return Status("failed to send '%s' packet", stream.GetData()); if (response.GetChar() != 'F') @@ -2944,7 +3016,7 @@ GDBRemoteCommunicationClient::OpenFile(const lldb_private::FileSpec &file_spec, stream.PutChar(','); stream.PutHex32(mode); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse(stream.GetString(), response, false) == + if (SendPacketAndWaitForResponse(stream.GetString(), response) == PacketResult::Success) { return ParseHostIOPacketResponse(response, UINT64_MAX, error); } @@ -2956,7 +3028,7 @@ bool GDBRemoteCommunicationClient::CloseFile(lldb::user_id_t fd, lldb_private::StreamString stream; stream.Printf("vFile:close:%i", (int)fd); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse(stream.GetString(), response, false) == + if (SendPacketAndWaitForResponse(stream.GetString(), response) == PacketResult::Success) { return ParseHostIOPacketResponse(response, -1, error) == 0; } @@ -2971,7 +3043,7 @@ lldb::user_id_t GDBRemoteCommunicationClient::GetFileSize( stream.PutCString("vFile:size:"); stream.PutStringAsRawHex8(path); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse(stream.GetString(), response, false) == + if (SendPacketAndWaitForResponse(stream.GetString(), response) == PacketResult::Success) { if (response.GetChar() != 'F') return UINT64_MAX; @@ -2981,6 +3053,31 @@ lldb::user_id_t GDBRemoteCommunicationClient::GetFileSize( return UINT64_MAX; } +void GDBRemoteCommunicationClient::AutoCompleteDiskFileOrDirectory( + CompletionRequest &request, bool only_dir) { + lldb_private::StreamString stream; + stream.PutCString("qPathComplete:"); + stream.PutHex32(only_dir ? 1 : 0); + stream.PutChar(','); + stream.PutStringAsRawHex8(request.GetCursorArgumentPrefix()); + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse(stream.GetString(), response) == + PacketResult::Success) { + StreamString strm; + char ch = response.GetChar(); + if (ch != 'M') + return; + while (response.Peek()) { + strm.Clear(); + while ((ch = response.GetHexU8(0, false)) != '\0') + strm.PutChar(ch); + request.AddCompletion(strm.GetString()); + if (response.GetChar() != ',') + break; + } + } +} + Status GDBRemoteCommunicationClient::GetFilePermissions(const FileSpec &file_spec, uint32_t &file_permissions) { @@ -2990,7 +3087,7 @@ GDBRemoteCommunicationClient::GetFilePermissions(const FileSpec &file_spec, stream.PutCString("vFile:mode:"); stream.PutStringAsRawHex8(path); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse(stream.GetString(), response, false) == + if (SendPacketAndWaitForResponse(stream.GetString(), response) == PacketResult::Success) { if (response.GetChar() != 'F') { error.SetErrorStringWithFormat("invalid response to '%s' packet", @@ -3025,7 +3122,7 @@ uint64_t GDBRemoteCommunicationClient::ReadFile(lldb::user_id_t fd, stream.Printf("vFile:pread:%i,%" PRId64 ",%" PRId64, (int)fd, dst_len, offset); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse(stream.GetString(), response, false) == + if (SendPacketAndWaitForResponse(stream.GetString(), response) == PacketResult::Success) { if (response.GetChar() != 'F') return 0; @@ -3059,7 +3156,7 @@ uint64_t GDBRemoteCommunicationClient::WriteFile(lldb::user_id_t fd, stream.Printf("vFile:pwrite:%i,%" PRId64 ",", (int)fd, offset); stream.PutEscapedBytes(src, src_len); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse(stream.GetString(), response, false) == + if (SendPacketAndWaitForResponse(stream.GetString(), response) == PacketResult::Success) { if (response.GetChar() != 'F') { error.SetErrorStringWithFormat("write file failed"); @@ -3094,7 +3191,7 @@ Status GDBRemoteCommunicationClient::CreateSymlink(const FileSpec &src, stream.PutChar(','); stream.PutStringAsRawHex8(src_path); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse(stream.GetString(), response, false) == + if (SendPacketAndWaitForResponse(stream.GetString(), response) == PacketResult::Success) { if (response.GetChar() == 'F') { uint32_t result = response.GetU32(UINT32_MAX); @@ -3125,7 +3222,7 @@ Status GDBRemoteCommunicationClient::Unlink(const FileSpec &file_spec) { // so we follow suit here stream.PutStringAsRawHex8(path); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse(stream.GetString(), response, false) == + if (SendPacketAndWaitForResponse(stream.GetString(), response) == PacketResult::Success) { if (response.GetChar() == 'F') { uint32_t result = response.GetU32(UINT32_MAX); @@ -3155,7 +3252,7 @@ bool GDBRemoteCommunicationClient::GetFileExists( stream.PutCString("vFile:exists:"); stream.PutStringAsRawHex8(path); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse(stream.GetString(), response, false) == + if (SendPacketAndWaitForResponse(stream.GetString(), response) == PacketResult::Success) { if (response.GetChar() != 'F') return false; @@ -3174,7 +3271,7 @@ bool GDBRemoteCommunicationClient::CalculateMD5( stream.PutCString("vFile:MD5:"); stream.PutStringAsRawHex8(path); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse(stream.GetString(), response, false) == + if (SendPacketAndWaitForResponse(stream.GetString(), response) == PacketResult::Success) { if (response.GetChar() != 'F') return false; @@ -3221,7 +3318,7 @@ DataBufferSP GDBRemoteCommunicationClient::ReadRegister(lldb::tid_t tid, payload.Printf("p%x", reg); StringExtractorGDBRemote response; if (SendThreadSpecificPacketAndWaitForResponse( - tid, std::move(payload), response, false) != PacketResult::Success || + tid, std::move(payload), response) != PacketResult::Success || !response.IsNormalResponse()) return nullptr; @@ -3236,7 +3333,7 @@ DataBufferSP GDBRemoteCommunicationClient::ReadAllRegisters(lldb::tid_t tid) { payload.PutChar('g'); StringExtractorGDBRemote response; if (SendThreadSpecificPacketAndWaitForResponse( - tid, std::move(payload), response, false) != PacketResult::Success || + tid, std::move(payload), response) != PacketResult::Success || !response.IsNormalResponse()) return nullptr; @@ -3255,9 +3352,8 @@ bool GDBRemoteCommunicationClient::WriteRegister(lldb::tid_t tid, endian::InlHostByteOrder(), endian::InlHostByteOrder()); StringExtractorGDBRemote response; - return SendThreadSpecificPacketAndWaitForResponse(tid, std::move(payload), - response, false) == - PacketResult::Success && + return SendThreadSpecificPacketAndWaitForResponse( + tid, std::move(payload), response) == PacketResult::Success && response.IsOKResponse(); } @@ -3269,9 +3365,8 @@ bool GDBRemoteCommunicationClient::WriteAllRegisters( endian::InlHostByteOrder(), endian::InlHostByteOrder()); StringExtractorGDBRemote response; - return SendThreadSpecificPacketAndWaitForResponse(tid, std::move(payload), - response, false) == - PacketResult::Success && + return SendThreadSpecificPacketAndWaitForResponse( + tid, std::move(payload), response) == PacketResult::Success && response.IsOKResponse(); } @@ -3286,7 +3381,7 @@ bool GDBRemoteCommunicationClient::SaveRegisterState(lldb::tid_t tid, payload.PutCString("QSaveRegisterState"); StringExtractorGDBRemote response; if (SendThreadSpecificPacketAndWaitForResponse( - tid, std::move(payload), response, false) != PacketResult::Success) + tid, std::move(payload), response) != PacketResult::Success) return false; if (response.IsUnsupportedResponse()) @@ -3312,7 +3407,7 @@ bool GDBRemoteCommunicationClient::RestoreRegisterState(lldb::tid_t tid, payload.Printf("QRestoreRegisterState:%u", save_id); StringExtractorGDBRemote response; if (SendThreadSpecificPacketAndWaitForResponse( - tid, std::move(payload), response, false) != PacketResult::Success) + tid, std::move(payload), response) != PacketResult::Success) return false; if (response.IsOKResponse()) @@ -3330,222 +3425,179 @@ bool GDBRemoteCommunicationClient::SyncThreadState(lldb::tid_t tid) { StreamString packet; StringExtractorGDBRemote response; packet.Printf("QSyncThreadState:%4.4" PRIx64 ";", tid); - return SendPacketAndWaitForResponse(packet.GetString(), response, false) == + return SendPacketAndWaitForResponse(packet.GetString(), response) == GDBRemoteCommunication::PacketResult::Success && response.IsOKResponse(); } -lldb::user_id_t -GDBRemoteCommunicationClient::SendStartTracePacket(const TraceOptions &options, - Status &error) { +llvm::Expected +GDBRemoteCommunicationClient::SendTraceSupported(std::chrono::seconds timeout) { Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); - lldb::user_id_t ret_uid = LLDB_INVALID_UID; StreamGDBRemote escaped_packet; - escaped_packet.PutCString("jTraceStart:"); - - StructuredData::Dictionary json_packet; - json_packet.AddIntegerItem("type", options.getType()); - json_packet.AddIntegerItem("buffersize", options.getTraceBufferSize()); - json_packet.AddIntegerItem("metabuffersize", options.getMetaDataBufferSize()); - - if (options.getThreadID() != LLDB_INVALID_THREAD_ID) - json_packet.AddIntegerItem("threadid", options.getThreadID()); - - StructuredData::DictionarySP custom_params = options.getTraceParams(); - if (custom_params) - json_packet.AddItem("params", custom_params); - - StreamString json_string; - json_packet.Dump(json_string, false); - escaped_packet.PutEscapedBytes(json_string.GetData(), json_string.GetSize()); + escaped_packet.PutCString("jLLDBTraceSupported"); StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse(escaped_packet.GetString(), response, - true) == + timeout) == GDBRemoteCommunication::PacketResult::Success) { - if (!response.IsNormalResponse()) { - error = response.GetStatus(); - LLDB_LOG(log, "Target does not support Tracing , error {0}", error); - } else { - ret_uid = response.GetHexMaxU64(false, LLDB_INVALID_UID); - } - } else { - LLDB_LOG(log, "failed to send packet"); - error.SetErrorStringWithFormat("failed to send packet: '%s'", - escaped_packet.GetData()); + if (response.IsErrorResponse()) + return response.GetStatus().ToError(); + if (response.IsUnsupportedResponse()) + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "jLLDBTraceSupported is unsupported"); + + return llvm::json::parse(response.Peek(), + "TraceSupportedResponse"); } - return ret_uid; + LLDB_LOG(log, "failed to send packet: jLLDBTraceSupported"); + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "failed to send packet: jLLDBTraceSupported"); } -Status -GDBRemoteCommunicationClient::SendStopTracePacket(lldb::user_id_t uid, - lldb::tid_t thread_id) { +llvm::Error +GDBRemoteCommunicationClient::SendTraceStop(const TraceStopRequest &request, + std::chrono::seconds timeout) { Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); - StringExtractorGDBRemote response; - Status error; - StructuredData::Dictionary json_packet; StreamGDBRemote escaped_packet; - StreamString json_string; - escaped_packet.PutCString("jTraceStop:"); - - json_packet.AddIntegerItem("traceid", uid); + escaped_packet.PutCString("jLLDBTraceStop:"); - if (thread_id != LLDB_INVALID_THREAD_ID) - json_packet.AddIntegerItem("threadid", thread_id); + std::string json_string; + llvm::raw_string_ostream os(json_string); + os << toJSON(request); + os.flush(); - json_packet.Dump(json_string, false); - - escaped_packet.PutEscapedBytes(json_string.GetData(), json_string.GetSize()); + escaped_packet.PutEscapedBytes(json_string.c_str(), json_string.size()); + StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse(escaped_packet.GetString(), response, - true) == + timeout) == GDBRemoteCommunication::PacketResult::Success) { - if (!response.IsOKResponse()) { - error = response.GetStatus(); - LLDB_LOG(log, "stop tracing failed"); - } - } else { - LLDB_LOG(log, "failed to send packet"); - error.SetErrorStringWithFormat( - "failed to send packet: '%s' with error '%d'", escaped_packet.GetData(), - response.GetError()); + if (response.IsErrorResponse()) + return response.GetStatus().ToError(); + if (response.IsUnsupportedResponse()) + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "jLLDBTraceStop is unsupported"); + if (response.IsOKResponse()) + return llvm::Error::success(); + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "Invalid jLLDBTraceStart response"); } - return error; + LLDB_LOG(log, "failed to send packet: jLLDBTraceStop"); + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "failed to send packet: jLLDBTraceStop '%s'", + escaped_packet.GetData()); } -Status GDBRemoteCommunicationClient::SendGetDataPacket( - lldb::user_id_t uid, lldb::tid_t thread_id, - llvm::MutableArrayRef &buffer, size_t offset) { +llvm::Error +GDBRemoteCommunicationClient::SendTraceStart(const llvm::json::Value ¶ms, + std::chrono::seconds timeout) { + Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); StreamGDBRemote escaped_packet; - escaped_packet.PutCString("jTraceBufferRead:"); - return SendGetTraceDataPacket(escaped_packet, uid, thread_id, buffer, offset); -} + escaped_packet.PutCString("jLLDBTraceStart:"); -Status GDBRemoteCommunicationClient::SendGetMetaDataPacket( - lldb::user_id_t uid, lldb::tid_t thread_id, - llvm::MutableArrayRef &buffer, size_t offset) { + std::string json_string; + llvm::raw_string_ostream os(json_string); + os << params; + os.flush(); - StreamGDBRemote escaped_packet; - escaped_packet.PutCString("jTraceMetaRead:"); - return SendGetTraceDataPacket(escaped_packet, uid, thread_id, buffer, offset); + escaped_packet.PutEscapedBytes(json_string.c_str(), json_string.size()); + + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse(escaped_packet.GetString(), response, + timeout) == + GDBRemoteCommunication::PacketResult::Success) { + if (response.IsErrorResponse()) + return response.GetStatus().ToError(); + if (response.IsUnsupportedResponse()) + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "jLLDBTraceStart is unsupported"); + if (response.IsOKResponse()) + return llvm::Error::success(); + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "Invalid jLLDBTraceStart response"); + } + LLDB_LOG(log, "failed to send packet: jLLDBTraceStart"); + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "failed to send packet: jLLDBTraceStart '%s'", + escaped_packet.GetData()); } -Status -GDBRemoteCommunicationClient::SendGetTraceConfigPacket(lldb::user_id_t uid, - TraceOptions &options) { +llvm::Expected +GDBRemoteCommunicationClient::SendTraceGetState(llvm::StringRef type, + std::chrono::seconds timeout) { Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); - StringExtractorGDBRemote response; - Status error; - StreamString json_string; StreamGDBRemote escaped_packet; - escaped_packet.PutCString("jTraceConfigRead:"); - - StructuredData::Dictionary json_packet; - json_packet.AddIntegerItem("traceid", uid); + escaped_packet.PutCString("jLLDBTraceGetState:"); - if (options.getThreadID() != LLDB_INVALID_THREAD_ID) - json_packet.AddIntegerItem("threadid", options.getThreadID()); + std::string json_string; + llvm::raw_string_ostream os(json_string); + os << toJSON(TraceGetStateRequest{type.str()}); + os.flush(); - json_packet.Dump(json_string, false); - escaped_packet.PutEscapedBytes(json_string.GetData(), json_string.GetSize()); + escaped_packet.PutEscapedBytes(json_string.c_str(), json_string.size()); + StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse(escaped_packet.GetString(), response, - true) == + timeout) == GDBRemoteCommunication::PacketResult::Success) { - if (response.IsNormalResponse()) { - uint64_t type = std::numeric_limits::max(); - uint64_t buffersize = std::numeric_limits::max(); - uint64_t metabuffersize = std::numeric_limits::max(); - - auto json_object = StructuredData::ParseJSON(response.Peek()); - - if (!json_object || - json_object->GetType() != lldb::eStructuredDataTypeDictionary) { - error.SetErrorString("Invalid Configuration obtained"); - return error; - } - - auto json_dict = json_object->GetAsDictionary(); - - json_dict->GetValueForKeyAsInteger("metabuffersize", - metabuffersize); - options.setMetaDataBufferSize(metabuffersize); - - json_dict->GetValueForKeyAsInteger("buffersize", buffersize); - options.setTraceBufferSize(buffersize); - - json_dict->GetValueForKeyAsInteger("type", type); - options.setType(static_cast(type)); - - StructuredData::ObjectSP custom_params_sp = - json_dict->GetValueForKey("params"); - if (custom_params_sp) { - if (custom_params_sp->GetType() != - lldb::eStructuredDataTypeDictionary) { - error.SetErrorString("Invalid Configuration obtained"); - return error; - } else - options.setTraceParams( - std::static_pointer_cast( - custom_params_sp)); - } - } else { - error = response.GetStatus(); - } - } else { - LLDB_LOG(log, "failed to send packet"); - error.SetErrorStringWithFormat("failed to send packet: '%s'", - escaped_packet.GetData()); + if (response.IsErrorResponse()) + return response.GetStatus().ToError(); + if (response.IsUnsupportedResponse()) + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "jLLDBTraceGetState is unsupported"); + return std::string(response.Peek()); } - return error; + + LLDB_LOG(log, "failed to send packet: jLLDBTraceGetState"); + return llvm::createStringError( + llvm::inconvertibleErrorCode(), + "failed to send packet: jLLDBTraceGetState '%s'", + escaped_packet.GetData()); } -Status GDBRemoteCommunicationClient::SendGetTraceDataPacket( - StreamGDBRemote &packet, lldb::user_id_t uid, lldb::tid_t thread_id, - llvm::MutableArrayRef &buffer, size_t offset) { +llvm::Expected> +GDBRemoteCommunicationClient::SendTraceGetBinaryData( + const TraceGetBinaryDataRequest &request, std::chrono::seconds timeout) { Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); - Status error; - - StructuredData::Dictionary json_packet; - json_packet.AddIntegerItem("traceid", uid); - json_packet.AddIntegerItem("offset", offset); - json_packet.AddIntegerItem("buffersize", buffer.size()); + StreamGDBRemote escaped_packet; + escaped_packet.PutCString("jLLDBTraceGetBinaryData:"); - if (thread_id != LLDB_INVALID_THREAD_ID) - json_packet.AddIntegerItem("threadid", thread_id); + std::string json_string; + llvm::raw_string_ostream os(json_string); + os << toJSON(request); + os.flush(); - StreamString json_string; - json_packet.Dump(json_string, false); + escaped_packet.PutEscapedBytes(json_string.c_str(), json_string.size()); - packet.PutEscapedBytes(json_string.GetData(), json_string.GetSize()); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse(packet.GetString(), response, true) == + if (SendPacketAndWaitForResponse(escaped_packet.GetString(), response, + timeout) == GDBRemoteCommunication::PacketResult::Success) { - if (response.IsNormalResponse()) { - size_t filled_size = response.GetHexBytesAvail(buffer); - buffer = llvm::MutableArrayRef(buffer.data(), filled_size); - } else { - error = response.GetStatus(); - buffer = buffer.slice(buffer.size()); - } - } else { - LLDB_LOG(log, "failed to send packet"); - error.SetErrorStringWithFormat("failed to send packet: '%s'", - packet.GetData()); - buffer = buffer.slice(buffer.size()); + if (response.IsErrorResponse()) + return response.GetStatus().ToError(); + if (response.IsUnsupportedResponse()) + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "jLLDBTraceGetBinaryData is unsupported"); + std::string data; + response.GetEscapedBinaryData(data); + return std::vector(data.begin(), data.end()); } - return error; + LLDB_LOG(log, "failed to send packet: jLLDBTraceGetBinaryData"); + return llvm::createStringError( + llvm::inconvertibleErrorCode(), + "failed to send packet: jLLDBTraceGetBinaryData '%s'", + escaped_packet.GetData()); } llvm::Optional GDBRemoteCommunicationClient::GetQOffsets() { StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse( - "qOffsets", response, /*send_async=*/false) != PacketResult::Success) + if (SendPacketAndWaitForResponse("qOffsets", response) != + PacketResult::Success) return llvm::None; if (!response.IsNormalResponse()) return llvm::None; @@ -3600,7 +3652,7 @@ bool GDBRemoteCommunicationClient::GetModuleInfo( packet.PutStringAsRawHex8(triple); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse(packet.GetString(), response, false) != + if (SendPacketAndWaitForResponse(packet.GetString(), response) != PacketResult::Success) return false; @@ -3707,7 +3759,7 @@ GDBRemoteCommunicationClient::GetModulesInfo( ScopedTimeout timeout(*this, std::chrono::seconds(10)); StringExtractorGDBRemote response; - if (SendPacketAndWaitForResponse(payload.GetString(), response, false) != + if (SendPacketAndWaitForResponse(payload.GetString(), response) != PacketResult::Success || response.IsErrorResponse()) return llvm::None; @@ -3766,7 +3818,7 @@ bool GDBRemoteCommunicationClient::ReadExtFeature( << "," << std::hex << size; GDBRemoteCommunication::PacketResult res = - SendPacketAndWaitForResponse(packet.str(), chunk, false); + SendPacketAndWaitForResponse(packet.str(), chunk); if (res != GDBRemoteCommunication::PacketResult::Success) { err.SetErrorString("Error sending $qXfer packet"); @@ -3855,7 +3907,7 @@ void GDBRemoteCommunicationClient::ServeSymbolLookups( bool first_qsymbol_query = true; if (m_supports_qSymbol && !m_qSymbol_requests_done) { - Lock lock(*this, false); + Lock lock(*this); if (lock) { StreamString packet; packet.PutCString("qSymbol::"); @@ -3983,9 +4035,8 @@ GDBRemoteCommunicationClient::GetSupportedStructuredDataPlugins() { // Poll it now. StringExtractorGDBRemote response; - const bool send_async = false; - if (SendPacketAndWaitForResponse("qStructuredDataPlugins", response, - send_async) == PacketResult::Success) { + if (SendPacketAndWaitForResponse("qStructuredDataPlugins", response) == + PacketResult::Success) { m_supported_async_json_packets_sp = StructuredData::ParseJSON(std::string(response.GetStringRef())); if (m_supported_async_json_packets_sp && @@ -4029,7 +4080,7 @@ Status GDBRemoteCommunicationClient::SendSignalsToIgnore( std::string packet = formatv("QPassSignals:{0:$[;]@(x-2)}", range).str(); StringExtractorGDBRemote response; - auto send_status = SendPacketAndWaitForResponse(packet, response, false); + auto send_status = SendPacketAndWaitForResponse(packet, response); if (send_status != GDBRemoteCommunication::PacketResult::Success) return Status("Sending QPassSignals packet failed"); @@ -4068,10 +4119,8 @@ Status GDBRemoteCommunicationClient::ConfigureRemoteStructuredData( stream.Flush(); // Send the packet. - const bool send_async = false; StringExtractorGDBRemote response; - auto result = - SendPacketAndWaitForResponse(stream.GetString(), response, send_async); + auto result = SendPacketAndWaitForResponse(stream.GetString(), response); if (result == PacketResult::Success) { // We failed if the config result comes back other than OK. if (strcmp(response.GetStringRef().data(), "OK") == 0) { diff --git a/gnu/llvm/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h b/gnu/llvm/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h index 8df08cbde73..1e1797c10df 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h +++ b/gnu/llvm/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h @@ -22,6 +22,7 @@ #include "lldb/Utility/GDBRemote.h" #include "lldb/Utility/ProcessInfo.h" #include "lldb/Utility/StructuredData.h" +#include "lldb/Utility/TraceGDBRemotePackets.h" #if defined(_WIN32) #include "lldb/Host/windows/PosixApi.h" #endif @@ -48,6 +49,12 @@ inline bool operator==(const QOffsets &a, const QOffsets &b) { } llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const QOffsets &offsets); +// A trivial struct used to return a pair of PID and TID. +struct PidTid { + uint64_t pid; + uint64_t tid; +}; + class GDBRemoteCommunicationClient : public GDBRemoteClientBase { public: GDBRemoteCommunicationClient(); @@ -274,6 +281,8 @@ public: ArchSpec GetSystemArchitecture(); + uint32_t GetAddressingBits(); + bool GetHostname(std::string &s); lldb::addr_t GetShlibInfoAddr(); @@ -318,7 +327,8 @@ public: GDBStoppointType type, // Type of breakpoint or watchpoint bool insert, // Insert or remove? lldb::addr_t addr, // Address of breakpoint or watchpoint - uint32_t length); // Byte Size of breakpoint or watchpoint + uint32_t length, // Byte Size of breakpoint or watchpoint + std::chrono::seconds interrupt_timeout); // Time to wait for an interrupt bool SetNonStopMode(const bool enable); @@ -333,9 +343,14 @@ public: // and response times. bool SendSpeedTestPacket(uint32_t send_size, uint32_t recv_size); - bool SetCurrentThread(uint64_t tid); + llvm::Optional + SendSetCurrentThreadPacket(uint64_t tid, uint64_t pid, char op); - bool SetCurrentThreadForRun(uint64_t tid); + bool SetCurrentThread(uint64_t tid, + lldb::pid_t pid = LLDB_INVALID_PROCESS_ID); + + bool SetCurrentThreadForRun(uint64_t tid, + lldb::pid_t pid = LLDB_INVALID_PROCESS_ID); bool GetQXferAuxvReadSupported(); @@ -365,6 +380,9 @@ public: return m_supports_alloc_dealloc_memory; } + std::vector> + GetCurrentProcessAndThreadIDs(bool &sequence_mutex_unavailable); + size_t GetCurrentThreadIDs(std::vector &thread_ids, bool &sequence_mutex_unavailable); @@ -375,6 +393,9 @@ public: lldb::user_id_t GetFileSize(const FileSpec &file_spec); + void AutoCompleteDiskFileOrDirectory(CompletionRequest &request, + bool only_dir); + Status GetFilePermissions(const FileSpec &file_spec, uint32_t &file_permissions); @@ -396,7 +417,7 @@ public: bool GetFileExists(const FileSpec &file_spec); Status RunShellCommand( - const char *command, // Shouldn't be nullptr + llvm::StringRef command, const FileSpec &working_dir, // Pass empty FileSpec to use the current // working directory int *status_ptr, // Pass nullptr if you don't want the process exit status @@ -442,6 +463,14 @@ public: bool GetSharedCacheInfoSupported(); + bool GetMemoryTaggingSupported(); + + lldb::DataBufferSP ReadMemoryTags(lldb::addr_t addr, size_t len, + int32_t type); + + Status WriteMemoryTags(lldb::addr_t addr, size_t len, int32_t type, + const std::vector &tags); + /// Use qOffsets to query the offset used when relocating the target /// executable. If successful, the returned structure will contain at least /// one value in the offsets field. @@ -501,57 +530,61 @@ public: ConfigureRemoteStructuredData(ConstString type_name, const StructuredData::ObjectSP &config_sp); - lldb::user_id_t SendStartTracePacket(const TraceOptions &options, - Status &error); + llvm::Expected + SendTraceSupported(std::chrono::seconds interrupt_timeout); - Status SendStopTracePacket(lldb::user_id_t uid, lldb::tid_t thread_id); + llvm::Error SendTraceStart(const llvm::json::Value &request, + std::chrono::seconds interrupt_timeout); - Status SendGetDataPacket(lldb::user_id_t uid, lldb::tid_t thread_id, - llvm::MutableArrayRef &buffer, - size_t offset = 0); + llvm::Error SendTraceStop(const TraceStopRequest &request, + std::chrono::seconds interrupt_timeout); - Status SendGetMetaDataPacket(lldb::user_id_t uid, lldb::tid_t thread_id, - llvm::MutableArrayRef &buffer, - size_t offset = 0); + llvm::Expected + SendTraceGetState(llvm::StringRef type, + std::chrono::seconds interrupt_timeout); - Status SendGetTraceConfigPacket(lldb::user_id_t uid, TraceOptions &options); + llvm::Expected> + SendTraceGetBinaryData(const TraceGetBinaryDataRequest &request, + std::chrono::seconds interrupt_timeout); protected: - LazyBool m_supports_not_sending_acks; - LazyBool m_supports_thread_suffix; - LazyBool m_supports_threads_in_stop_reply; - LazyBool m_supports_vCont_all; - LazyBool m_supports_vCont_any; - LazyBool m_supports_vCont_c; - LazyBool m_supports_vCont_C; - LazyBool m_supports_vCont_s; - LazyBool m_supports_vCont_S; - LazyBool m_qHostInfo_is_valid; - LazyBool m_curr_pid_is_valid; - LazyBool m_qProcessInfo_is_valid; - LazyBool m_qGDBServerVersion_is_valid; - LazyBool m_supports_alloc_dealloc_memory; - LazyBool m_supports_memory_region_info; - LazyBool m_supports_watchpoint_support_info; - LazyBool m_supports_detach_stay_stopped; - LazyBool m_watchpoints_trigger_after_instruction; - LazyBool m_attach_or_wait_reply; - LazyBool m_prepare_for_reg_writing_reply; - LazyBool m_supports_p; - LazyBool m_supports_x; - LazyBool m_avoid_g_packets; - LazyBool m_supports_QSaveRegisterState; - LazyBool m_supports_qXfer_auxv_read; - LazyBool m_supports_qXfer_libraries_read; - LazyBool m_supports_qXfer_libraries_svr4_read; - LazyBool m_supports_qXfer_features_read; - LazyBool m_supports_qXfer_memory_map_read; - LazyBool m_supports_augmented_libraries_svr4_read; - LazyBool m_supports_jThreadExtendedInfo; - LazyBool m_supports_jLoadedDynamicLibrariesInfos; - LazyBool m_supports_jGetSharedCacheInfo; - LazyBool m_supports_QPassSignals; - LazyBool m_supports_error_string_reply; + LazyBool m_supports_not_sending_acks = eLazyBoolCalculate; + LazyBool m_supports_thread_suffix = eLazyBoolCalculate; + LazyBool m_supports_threads_in_stop_reply = eLazyBoolCalculate; + LazyBool m_supports_vCont_all = eLazyBoolCalculate; + LazyBool m_supports_vCont_any = eLazyBoolCalculate; + LazyBool m_supports_vCont_c = eLazyBoolCalculate; + LazyBool m_supports_vCont_C = eLazyBoolCalculate; + LazyBool m_supports_vCont_s = eLazyBoolCalculate; + LazyBool m_supports_vCont_S = eLazyBoolCalculate; + LazyBool m_qHostInfo_is_valid = eLazyBoolCalculate; + LazyBool m_curr_pid_is_valid = eLazyBoolCalculate; + LazyBool m_qProcessInfo_is_valid = eLazyBoolCalculate; + LazyBool m_qGDBServerVersion_is_valid = eLazyBoolCalculate; + LazyBool m_supports_alloc_dealloc_memory = eLazyBoolCalculate; + LazyBool m_supports_memory_region_info = eLazyBoolCalculate; + LazyBool m_supports_watchpoint_support_info = eLazyBoolCalculate; + LazyBool m_supports_detach_stay_stopped = eLazyBoolCalculate; + LazyBool m_watchpoints_trigger_after_instruction = eLazyBoolCalculate; + LazyBool m_attach_or_wait_reply = eLazyBoolCalculate; + LazyBool m_prepare_for_reg_writing_reply = eLazyBoolCalculate; + LazyBool m_supports_p = eLazyBoolCalculate; + LazyBool m_supports_x = eLazyBoolCalculate; + LazyBool m_avoid_g_packets = eLazyBoolCalculate; + LazyBool m_supports_QSaveRegisterState = eLazyBoolCalculate; + LazyBool m_supports_qXfer_auxv_read = eLazyBoolCalculate; + LazyBool m_supports_qXfer_libraries_read = eLazyBoolCalculate; + LazyBool m_supports_qXfer_libraries_svr4_read = eLazyBoolCalculate; + LazyBool m_supports_qXfer_features_read = eLazyBoolCalculate; + LazyBool m_supports_qXfer_memory_map_read = eLazyBoolCalculate; + LazyBool m_supports_augmented_libraries_svr4_read = eLazyBoolCalculate; + LazyBool m_supports_jThreadExtendedInfo = eLazyBoolCalculate; + LazyBool m_supports_jLoadedDynamicLibrariesInfos = eLazyBoolCalculate; + LazyBool m_supports_jGetSharedCacheInfo = eLazyBoolCalculate; + LazyBool m_supports_QPassSignals = eLazyBoolCalculate; + LazyBool m_supports_error_string_reply = eLazyBoolCalculate; + LazyBool m_supports_multiprocess = eLazyBoolCalculate; + LazyBool m_supports_memory_tagging = eLazyBoolCalculate; bool m_supports_qProcessInfoPID : 1, m_supports_qfProcessInfo : 1, m_supports_qUserName : 1, m_supports_qGroupName : 1, @@ -562,13 +595,17 @@ protected: m_supports_qModuleInfo : 1, m_supports_jThreadsInfo : 1, m_supports_jModulesInfo : 1; - lldb::pid_t m_curr_pid; - lldb::tid_t m_curr_tid; // Current gdb remote protocol thread index for all - // other operations - lldb::tid_t m_curr_tid_run; // Current gdb remote protocol thread index for - // continue, step, etc + /// Current gdb remote protocol process identifier for all other operations + lldb::pid_t m_curr_pid = LLDB_INVALID_PROCESS_ID; + /// Current gdb remote protocol process identifier for continue, step, etc + lldb::pid_t m_curr_pid_run = LLDB_INVALID_PROCESS_ID; + /// Current gdb remote protocol thread identifier for all other operations + lldb::tid_t m_curr_tid = LLDB_INVALID_THREAD_ID; + /// Current gdb remote protocol thread identifier for continue, step, etc + lldb::tid_t m_curr_tid_run = LLDB_INVALID_THREAD_ID; - uint32_t m_num_supported_hardware_watchpoints; + uint32_t m_num_supported_hardware_watchpoints = 0; + uint32_t m_addressing_bits = 0; ArchSpec m_host_arch; ArchSpec m_process_arch; @@ -579,17 +616,19 @@ protected: std::string m_hostname; std::string m_gdb_server_name; // from reply to qGDBServerVersion, empty if // qGDBServerVersion is not supported - uint32_t m_gdb_server_version; // from reply to qGDBServerVersion, zero if - // qGDBServerVersion is not supported + uint32_t m_gdb_server_version = + UINT32_MAX; // from reply to qGDBServerVersion, zero if + // qGDBServerVersion is not supported std::chrono::seconds m_default_packet_timeout; - uint64_t m_max_packet_size; // as returned by qSupported + int m_target_vm_page_size = 0; // target system VM page size; 0 unspecified + uint64_t m_max_packet_size = 0; // as returned by qSupported std::string m_qSupported_response; // the complete response to qSupported - bool m_supported_async_json_packets_is_valid; + bool m_supported_async_json_packets_is_valid = false; lldb_private::StructuredData::ObjectSP m_supported_async_json_packets_sp; std::vector m_qXfer_memory_map; - bool m_qXfer_memory_map_loaded; + bool m_qXfer_memory_map_loaded = false; bool GetCurrentProcessInfo(bool allow_lazy_pid = true); @@ -597,7 +636,8 @@ protected: // Given the list of compression types that the remote debug stub can support, // possibly enable compression if we find an encoding we can handle. - void MaybeEnableCompression(std::vector supported_compressions); + void MaybeEnableCompression( + llvm::ArrayRef supported_compressions); bool DecodeProcessInfoResponse(StringExtractorGDBRemote &response, ProcessInstanceInfo &process_info); @@ -606,7 +646,7 @@ protected: PacketResult SendThreadSpecificPacketAndWaitForResponse( lldb::tid_t tid, StreamString &&payload, - StringExtractorGDBRemote &response, bool send_async); + StringExtractorGDBRemote &response); Status SendGetTraceDataPacket(StreamGDBRemote &packet, lldb::user_id_t uid, lldb::tid_t thread_id, diff --git a/gnu/llvm/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationHistory.cpp b/gnu/llvm/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationHistory.cpp index 3984a45c3da..d92c97e8165 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationHistory.cpp +++ b/gnu/llvm/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationHistory.cpp @@ -19,13 +19,12 @@ using namespace lldb_private; using namespace lldb_private::process_gdb_remote; GDBRemoteCommunicationHistory::GDBRemoteCommunicationHistory(uint32_t size) - : m_packets(), m_curr_idx(0), m_total_packet_count(0), - m_dumped_to_log(false) { + : m_packets() { if (size) m_packets.resize(size); } -GDBRemoteCommunicationHistory::~GDBRemoteCommunicationHistory() {} +GDBRemoteCommunicationHistory::~GDBRemoteCommunicationHistory() = default; void GDBRemoteCommunicationHistory::AddPacket(char packet_char, GDBRemotePacket::Type type, diff --git a/gnu/llvm/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationHistory.h b/gnu/llvm/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationHistory.h index e783e59c345..eda464a758e 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationHistory.h +++ b/gnu/llvm/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationHistory.h @@ -74,9 +74,9 @@ private: } std::vector m_packets; - uint32_t m_curr_idx; - uint32_t m_total_packet_count; - mutable bool m_dumped_to_log; + uint32_t m_curr_idx = 0; + uint32_t m_total_packet_count = 0; + mutable bool m_dumped_to_log = false; repro::PacketRecorder *m_recorder = nullptr; }; diff --git a/gnu/llvm/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationReplayServer.cpp b/gnu/llvm/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationReplayServer.cpp index 920327e7d0a..c91d7cb5ac3 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationReplayServer.cpp +++ b/gnu/llvm/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationReplayServer.cpp @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// -#include +#include #include "lldb/Host/Config.h" #include "llvm/ADT/ScopeExit.h" @@ -74,7 +74,7 @@ GDBRemoteCommunicationReplayServer::GDBRemoteCommunicationReplayServer() m_async_broadcaster(nullptr, "lldb.gdb-replay.async-broadcaster"), m_async_listener_sp( Listener::MakeListener("lldb.gdb-replay.async-listener")), - m_async_thread_state_mutex(), m_skip_acks(false) { + m_async_thread_state_mutex() { m_async_broadcaster.SetEventName(eBroadcastBitAsyncContinue, "async thread continue"); m_async_broadcaster.SetEventName(eBroadcastBitAsyncThreadShouldExit, diff --git a/gnu/llvm/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationReplayServer.h b/gnu/llvm/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationReplayServer.h index c13e5ee0bf9..2f8770d0acc 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationReplayServer.h +++ b/gnu/llvm/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationReplayServer.h @@ -73,7 +73,7 @@ protected: HostThread m_async_thread; std::recursive_mutex m_async_thread_state_mutex; - bool m_skip_acks; + bool m_skip_acks = false; private: GDBRemoteCommunicationReplayServer( diff --git a/gnu/llvm/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp b/gnu/llvm/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp index b78f0916b9b..11cac9fa3a4 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp +++ b/gnu/llvm/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp @@ -6,21 +6,23 @@ // //===----------------------------------------------------------------------===// -#include +#include #include "lldb/Host/Config.h" #include "GDBRemoteCommunicationServer.h" -#include - #include "ProcessGDBRemoteLog.h" #include "lldb/Utility/StreamString.h" #include "lldb/Utility/StringExtractorGDBRemote.h" +#include "lldb/Utility/UnimplementedError.h" +#include "llvm/Support/JSON.h" +#include using namespace lldb; using namespace lldb_private; using namespace lldb_private::process_gdb_remote; +using namespace llvm; GDBRemoteCommunicationServer::GDBRemoteCommunicationServer( const char *comm_name, const char *listener_name) @@ -31,7 +33,7 @@ GDBRemoteCommunicationServer::GDBRemoteCommunicationServer( bool &quit) { return this->Handle_QErrorStringEnable(packet); }); } -GDBRemoteCommunicationServer::~GDBRemoteCommunicationServer() {} +GDBRemoteCommunicationServer::~GDBRemoteCommunicationServer() = default; void GDBRemoteCommunicationServer::RegisterPacketHandler( StringExtractorGDBRemote::ServerPacketType packet_type, @@ -113,18 +115,17 @@ GDBRemoteCommunicationServer::SendErrorResponse(const Status &error) { GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServer::SendErrorResponse(llvm::Error error) { + assert(error); std::unique_ptr EIB; - std::unique_ptr PUE; + std::unique_ptr UE; llvm::handleAllErrors( std::move(error), - [&](std::unique_ptr E) { PUE = std::move(E); }, + [&](std::unique_ptr E) { UE = std::move(E); }, [&](std::unique_ptr E) { EIB = std::move(E); }); if (EIB) return SendErrorResponse(Status(llvm::Error(std::move(EIB)))); - if (PUE) - return SendUnimplementedResponse(PUE->message().c_str()); - return SendErrorResponse(Status("Unknown Error")); + return SendUnimplementedResponse(""); } GDBRemoteCommunication::PacketResult @@ -153,4 +154,20 @@ bool GDBRemoteCommunicationServer::HandshakeWithClient() { return GetAck() == PacketResult::Success; } -char PacketUnimplementedError::ID; +GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationServer::SendJSONResponse(const json::Value &value) { + std::string json_string; + raw_string_ostream os(json_string); + os << value; + os.flush(); + StreamGDBRemote escaped_response; + escaped_response.PutEscapedBytes(json_string.c_str(), json_string.size()); + return SendPacketNoLock(escaped_response.GetString()); +} + +GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationServer::SendJSONResponse(Expected value) { + if (!value) + return SendErrorResponse(value.takeError()); + return SendJSONResponse(*value); +} diff --git a/gnu/llvm/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h b/gnu/llvm/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h index a7c2ea47e3b..68448eae2b9 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h +++ b/gnu/llvm/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h @@ -27,7 +27,6 @@ class ProcessGDBRemote; class GDBRemoteCommunicationServer : public GDBRemoteCommunication { public: - using PortMap = std::map; using PacketHandler = std::function; @@ -73,24 +72,19 @@ protected: PacketResult SendOKResponse(); + /// Serialize and send a JSON object response. + PacketResult SendJSONResponse(const llvm::json::Value &value); + + /// Serialize and send a JSON object response, or respond with an error if the + /// input object is an \a llvm::Error. + PacketResult SendJSONResponse(llvm::Expected value); + private: GDBRemoteCommunicationServer(const GDBRemoteCommunicationServer &) = delete; const GDBRemoteCommunicationServer & operator=(const GDBRemoteCommunicationServer &) = delete; }; -class PacketUnimplementedError - : public llvm::ErrorInfo { -public: - static char ID; - using llvm::ErrorInfo::ErrorInfo; // inherit constructors - PacketUnimplementedError(const llvm::Twine &S) - : ErrorInfo(S, llvm::errc::not_supported) {} - - PacketUnimplementedError() : ErrorInfo(llvm::errc::not_supported) {} -}; - } // namespace process_gdb_remote } // namespace lldb_private diff --git a/gnu/llvm/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.h b/gnu/llvm/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.h index 0f933c09cbd..ecd80923fcf 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.h +++ b/gnu/llvm/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.h @@ -36,8 +36,6 @@ protected: Status m_process_launch_error; ProcessInstanceInfoList m_proc_infos; uint32_t m_proc_infos_index; - bool m_thread_suffix_supported; - bool m_list_threads_in_stop_reply; PacketResult Handle_A(StringExtractorGDBRemote &packet); @@ -91,10 +89,6 @@ protected: PacketResult Handle_qSupported(StringExtractorGDBRemote &packet); - PacketResult Handle_QThreadSuffixSupported(StringExtractorGDBRemote &packet); - - PacketResult Handle_QListThreadsInStopReply(StringExtractorGDBRemote &packet); - PacketResult Handle_QSetDetachOnError(StringExtractorGDBRemote &packet); PacketResult Handle_QStartNoAckMode(StringExtractorGDBRemote &packet); @@ -145,6 +139,11 @@ protected: virtual FileSpec FindModuleFile(const std::string &module_path, const ArchSpec &arch); + // Process client_features (qSupported) and return an array of server features + // to be returned in response. + virtual std::vector + HandleFeatures(llvm::ArrayRef client_features); + private: ModuleSpec GetModuleInfo(llvm::StringRef module_path, llvm::StringRef triple); }; diff --git a/gnu/llvm/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp b/gnu/llvm/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp index ae2f4bd041c..8e1f6bc29a6 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp +++ b/gnu/llvm/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp @@ -6,17 +6,17 @@ // //===----------------------------------------------------------------------===// -#include +#include #include "lldb/Host/Config.h" -#include "GDBRemoteCommunicationServerLLGS.h" -#include "lldb/Utility/GDBRemote.h" #include #include +#include #include +#include "GDBRemoteCommunicationServerLLGS.h" #include "lldb/Host/ConnectionFileDescriptor.h" #include "lldb/Host/Debug.h" #include "lldb/Host/File.h" @@ -32,11 +32,13 @@ #include "lldb/Utility/Args.h" #include "lldb/Utility/DataBuffer.h" #include "lldb/Utility/Endian.h" +#include "lldb/Utility/GDBRemote.h" #include "lldb/Utility/LLDBAssert.h" #include "lldb/Utility/Log.h" #include "lldb/Utility/RegisterValue.h" #include "lldb/Utility/State.h" #include "lldb/Utility/StreamString.h" +#include "lldb/Utility/UnimplementedError.h" #include "lldb/Utility/UriParser.h" #include "llvm/ADT/Triple.h" #include "llvm/Support/JSON.h" @@ -69,6 +71,7 @@ GDBRemoteCommunicationServerLLGS::GDBRemoteCommunicationServerLLGS( : GDBRemoteCommunicationServerCommon("gdb-remote.server", "gdb-remote.server.rx_packet"), m_mainloop(mainloop), m_process_factory(process_factory), + m_current_process(nullptr), m_continue_process(nullptr), m_stdio_communication("process.stdio") { RegisterPacketHandlers(); } @@ -92,6 +95,10 @@ void GDBRemoteCommunicationServerLLGS::RegisterPacketHandlers() { &GDBRemoteCommunicationServerLLGS::Handle_memory_read); RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_M, &GDBRemoteCommunicationServerLLGS::Handle_M); + RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType__M, + &GDBRemoteCommunicationServerLLGS::Handle__M); + RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType__m, + &GDBRemoteCommunicationServerLLGS::Handle__m); RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_p, &GDBRemoteCommunicationServerLLGS::Handle_p); RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_P, @@ -107,6 +114,12 @@ void GDBRemoteCommunicationServerLLGS::RegisterPacketHandlers() { RegisterMemberFunctionHandler( StringExtractorGDBRemote::eServerPacketType_qGetWorkingDir, &GDBRemoteCommunicationServerLLGS::Handle_qGetWorkingDir); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_QThreadSuffixSupported, + &GDBRemoteCommunicationServerLLGS::Handle_QThreadSuffixSupported); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_QListThreadsInStopReply, + &GDBRemoteCommunicationServerLLGS::Handle_QListThreadsInStopReply); RegisterMemberFunctionHandler( StringExtractorGDBRemote::eServerPacketType_qMemoryRegionInfo, &GDBRemoteCommunicationServerLLGS::Handle_qMemoryRegionInfo); @@ -154,6 +167,15 @@ void GDBRemoteCommunicationServerLLGS::RegisterPacketHandlers() { RegisterMemberFunctionHandler( StringExtractorGDBRemote::eServerPacketType_vAttach, &GDBRemoteCommunicationServerLLGS::Handle_vAttach); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_vAttachWait, + &GDBRemoteCommunicationServerLLGS::Handle_vAttachWait); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_qVAttachOrWaitSupported, + &GDBRemoteCommunicationServerLLGS::Handle_qVAttachOrWaitSupported); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_vAttachOrWait, + &GDBRemoteCommunicationServerLLGS::Handle_vAttachOrWait); RegisterMemberFunctionHandler( StringExtractorGDBRemote::eServerPacketType_vCont, &GDBRemoteCommunicationServerLLGS::Handle_vCont); @@ -172,24 +194,32 @@ void GDBRemoteCommunicationServerLLGS::RegisterPacketHandlers() { &GDBRemoteCommunicationServerLLGS::Handle_QPassSignals); RegisterMemberFunctionHandler( - StringExtractorGDBRemote::eServerPacketType_jTraceStart, - &GDBRemoteCommunicationServerLLGS::Handle_jTraceStart); + StringExtractorGDBRemote::eServerPacketType_jLLDBTraceSupported, + &GDBRemoteCommunicationServerLLGS::Handle_jLLDBTraceSupported); RegisterMemberFunctionHandler( - StringExtractorGDBRemote::eServerPacketType_jTraceBufferRead, - &GDBRemoteCommunicationServerLLGS::Handle_jTraceRead); + StringExtractorGDBRemote::eServerPacketType_jLLDBTraceStart, + &GDBRemoteCommunicationServerLLGS::Handle_jLLDBTraceStart); RegisterMemberFunctionHandler( - StringExtractorGDBRemote::eServerPacketType_jTraceMetaRead, - &GDBRemoteCommunicationServerLLGS::Handle_jTraceRead); + StringExtractorGDBRemote::eServerPacketType_jLLDBTraceStop, + &GDBRemoteCommunicationServerLLGS::Handle_jLLDBTraceStop); RegisterMemberFunctionHandler( - StringExtractorGDBRemote::eServerPacketType_jTraceStop, - &GDBRemoteCommunicationServerLLGS::Handle_jTraceStop); + StringExtractorGDBRemote::eServerPacketType_jLLDBTraceGetState, + &GDBRemoteCommunicationServerLLGS::Handle_jLLDBTraceGetState); RegisterMemberFunctionHandler( - StringExtractorGDBRemote::eServerPacketType_jTraceConfigRead, - &GDBRemoteCommunicationServerLLGS::Handle_jTraceConfigRead); + StringExtractorGDBRemote::eServerPacketType_jLLDBTraceGetBinaryData, + &GDBRemoteCommunicationServerLLGS::Handle_jLLDBTraceGetBinaryData); RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_g, &GDBRemoteCommunicationServerLLGS::Handle_g); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_qMemTags, + &GDBRemoteCommunicationServerLLGS::Handle_qMemTags); + + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_QMemTags, + &GDBRemoteCommunicationServerLLGS::Handle_QMemTags); + RegisterPacketHandler(StringExtractorGDBRemote::eServerPacketType_k, [this](StringExtractorGDBRemote packet, Status &error, bool &interrupt, bool &quit) { @@ -228,15 +258,18 @@ Status GDBRemoteCommunicationServerLLGS::LaunchProcess() { { std::lock_guard guard(m_debugged_process_mutex); - assert(!m_debugged_process_up && "lldb-server creating debugged " - "process but one already exists"); + assert(m_debugged_processes.empty() && "lldb-server creating debugged " + "process but one already exists"); auto process_or = m_process_factory.Launch(m_process_launch_info, *this, m_mainloop); if (!process_or) return Status(process_or.takeError()); - m_debugged_process_up = std::move(*process_or); + m_continue_process = m_current_process = process_or->get(); + m_debugged_processes[m_current_process->GetID()] = std::move(*process_or); } + SetEnabledExtensions(*m_current_process); + // Handle mirroring of inferior stdout/stderr over the gdb-remote protocol as // needed. llgs local-process debugging may specify PTY paths, which will // make these file actions non-null process launch -i/e/o will also make @@ -249,10 +282,10 @@ Status GDBRemoteCommunicationServerLLGS::LaunchProcess() { LLDB_LOG(log, "pid = {0}: setting up stdout/stderr redirection via $O " "gdb-remote commands", - m_debugged_process_up->GetID()); + m_current_process->GetID()); // Setup stdout/stderr mapping from inferior to $O - auto terminal_fd = m_debugged_process_up->GetTerminalFileDescriptor(); + auto terminal_fd = m_current_process->GetTerminalFileDescriptor(); if (terminal_fd >= 0) { LLDB_LOGF(log, "ProcessGDBRemoteCommunicationServerLLGS::%s setting " @@ -271,12 +304,12 @@ Status GDBRemoteCommunicationServerLLGS::LaunchProcess() { LLDB_LOG(log, "pid = {0} skipping stdout/stderr redirection via $O: inferior " "will communicate over client-provided file descriptors", - m_debugged_process_up->GetID()); + m_current_process->GetID()); } printf("Launched '%s' as process %" PRIu64 "...\n", m_process_launch_info.GetArguments().GetArgumentAtIndex(0), - m_debugged_process_up->GetID()); + m_current_process->GetID()); return Status(); } @@ -288,12 +321,11 @@ Status GDBRemoteCommunicationServerLLGS::AttachToProcess(lldb::pid_t pid) { // Before we try to attach, make sure we aren't already monitoring something // else. - if (m_debugged_process_up && - m_debugged_process_up->GetID() != LLDB_INVALID_PROCESS_ID) + if (!m_debugged_processes.empty()) return Status("cannot attach to process %" PRIu64 " when another process with pid %" PRIu64 " is being debugged.", - pid, m_debugged_process_up->GetID()); + pid, m_current_process->GetID()); // Try to attach. auto process_or = m_process_factory.Attach(pid, *this, m_mainloop); @@ -303,10 +335,12 @@ Status GDBRemoteCommunicationServerLLGS::AttachToProcess(lldb::pid_t pid) { status); return status; } - m_debugged_process_up = std::move(*process_or); + m_continue_process = m_current_process = process_or->get(); + m_debugged_processes[m_current_process->GetID()] = std::move(*process_or); + SetEnabledExtensions(*m_current_process); // Setup stdout/stderr mapping from inferior. - auto terminal_fd = m_debugged_process_up->GetTerminalFileDescriptor(); + auto terminal_fd = m_current_process->GetTerminalFileDescriptor(); if (terminal_fd >= 0) { LLDB_LOGF(log, "ProcessGDBRemoteCommunicationServerLLGS::%s setting " @@ -326,6 +360,75 @@ Status GDBRemoteCommunicationServerLLGS::AttachToProcess(lldb::pid_t pid) { return Status(); } +Status GDBRemoteCommunicationServerLLGS::AttachWaitProcess( + llvm::StringRef process_name, bool include_existing) { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + + std::chrono::milliseconds polling_interval = std::chrono::milliseconds(1); + + // Create the matcher used to search the process list. + ProcessInstanceInfoList exclusion_list; + ProcessInstanceInfoMatch match_info; + match_info.GetProcessInfo().GetExecutableFile().SetFile( + process_name, llvm::sys::path::Style::native); + match_info.SetNameMatchType(NameMatch::Equals); + + if (include_existing) { + LLDB_LOG(log, "including existing processes in search"); + } else { + // Create the excluded process list before polling begins. + Host::FindProcesses(match_info, exclusion_list); + LLDB_LOG(log, "placed '{0}' processes in the exclusion list.", + exclusion_list.size()); + } + + LLDB_LOG(log, "waiting for '{0}' to appear", process_name); + + auto is_in_exclusion_list = + [&exclusion_list](const ProcessInstanceInfo &info) { + for (auto &excluded : exclusion_list) { + if (excluded.GetProcessID() == info.GetProcessID()) + return true; + } + return false; + }; + + ProcessInstanceInfoList loop_process_list; + while (true) { + loop_process_list.clear(); + if (Host::FindProcesses(match_info, loop_process_list)) { + // Remove all the elements that are in the exclusion list. + llvm::erase_if(loop_process_list, is_in_exclusion_list); + + // One match! We found the desired process. + if (loop_process_list.size() == 1) { + auto matching_process_pid = loop_process_list[0].GetProcessID(); + LLDB_LOG(log, "found pid {0}", matching_process_pid); + return AttachToProcess(matching_process_pid); + } + + // Multiple matches! Return an error reporting the PIDs we found. + if (loop_process_list.size() > 1) { + StreamString error_stream; + error_stream.Format( + "Multiple executables with name: '{0}' found. Pids: ", + process_name); + for (size_t i = 0; i < loop_process_list.size() - 1; ++i) { + error_stream.Format("{0}, ", loop_process_list[i].GetProcessID()); + } + error_stream.Format("{0}.", loop_process_list.back().GetProcessID()); + + Status error; + error.SetErrorString(error_stream.GetString()); + return error; + } + } + // No matches, we have not found the process. Sleep until next poll. + LLDB_LOG(log, "sleep {0} seconds", polling_interval); + std::this_thread::sleep_for(polling_interval); + } +} + void GDBRemoteCommunicationServerLLGS::InitializeDelegate( NativeProcessProtocol *process) { assert(process && "process cannot be NULL"); @@ -495,7 +598,7 @@ static void WriteRegisterValueInHexFixedWidth( } } -static llvm::Expected +static llvm::Optional GetRegistersAsJSON(NativeThreadProtocol &thread) { Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD)); @@ -504,30 +607,16 @@ GetRegistersAsJSON(NativeThreadProtocol &thread) { json::Object register_object; #ifdef LLDB_JTHREADSINFO_FULL_REGISTER_SET - // Expedite all registers in the first register set (i.e. should be GPRs) - // that are not contained in other registers. - const RegisterSet *reg_set_p = reg_ctx_sp->GetRegisterSet(0); - if (!reg_set_p) - return llvm::make_error("failed to get registers", - llvm::inconvertibleErrorCode()); - for (const uint32_t *reg_num_p = reg_set_p->registers; - *reg_num_p != LLDB_INVALID_REGNUM; ++reg_num_p) { - uint32_t reg_num = *reg_num_p; + const auto expedited_regs = + reg_ctx.GetExpeditedRegisters(ExpeditedRegs::Full); #else - // Expedite only a couple of registers until we figure out why sending - // registers is expensive. - static const uint32_t k_expedited_registers[] = { - LLDB_REGNUM_GENERIC_PC, LLDB_REGNUM_GENERIC_SP, LLDB_REGNUM_GENERIC_FP, - LLDB_REGNUM_GENERIC_RA, LLDB_INVALID_REGNUM}; - - for (const uint32_t *generic_reg_p = k_expedited_registers; - *generic_reg_p != LLDB_INVALID_REGNUM; ++generic_reg_p) { - uint32_t reg_num = reg_ctx.ConvertRegisterKindToRegisterNumber( - eRegisterKindGeneric, *generic_reg_p); - if (reg_num == LLDB_INVALID_REGNUM) - continue; // Target does not support the given register. + const auto expedited_regs = + reg_ctx.GetExpeditedRegisters(ExpeditedRegs::Minimal); #endif + if (expedited_regs.empty()) + return llvm::None; + for (auto ®_num : expedited_regs) { const RegisterInfo *const reg_info_p = reg_ctx.GetRegisterInfoAtIndex(reg_num); if (reg_info_p == nullptr) { @@ -576,6 +665,14 @@ static const char *GetStopReasonString(StopReason stop_reason) { return "exception"; case eStopReasonExec: return "exec"; + case eStopReasonProcessorTrace: + return "processor trace"; + case eStopReasonFork: + return "fork"; + case eStopReasonVFork: + return "vfork"; + case eStopReasonVForkDone: + return "vforkdone"; case eStopReasonInstrumentation: case eStopReasonInvalid: case eStopReasonPlanComplete: @@ -620,12 +717,8 @@ GetJSONThreadsInfo(NativeProcessProtocol &process, bool abridged) { json::Object thread_obj; if (!abridged) { - if (llvm::Expected registers = - GetRegistersAsJSON(*thread)) { + if (llvm::Optional registers = GetRegistersAsJSON(*thread)) thread_obj.try_emplace("registers", std::move(*registers)); - } else { - return registers.takeError(); - } } thread_obj.try_emplace("tid", static_cast(tid)); @@ -668,15 +761,15 @@ GDBRemoteCommunicationServerLLGS::SendStopReplyPacketForThread( Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_THREAD)); // Ensure we have a debugged process. - if (!m_debugged_process_up || - (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID)) + if (!m_current_process || + (m_current_process->GetID() == LLDB_INVALID_PROCESS_ID)) return SendErrorResponse(50); LLDB_LOG(log, "preparing packet for pid {0} tid {1}", - m_debugged_process_up->GetID(), tid); + m_current_process->GetID(), tid); // Ensure we can get info on the given thread. - NativeThreadProtocol *thread = m_debugged_process_up->GetThreadByID(tid); + NativeThreadProtocol *thread = m_current_process->GetThreadByID(tid); if (!thread) return SendErrorResponse(51); @@ -699,7 +792,7 @@ GDBRemoteCommunicationServerLLGS::SendStopReplyPacketForThread( LLDB_LOG( log, "pid {0}, tid {1}, got signal signo = {2}, reason = {3}, exc_type = {4}", - m_debugged_process_up->GetID(), tid, signum, int(tid_stop_info.reason), + m_current_process->GetID(), tid, signum, int(tid_stop_info.reason), tid_stop_info.details.exception.type); // Print the signal number. @@ -737,9 +830,9 @@ GDBRemoteCommunicationServerLLGS::SendStopReplyPacketForThread( uint32_t thread_index = 0; NativeThreadProtocol *listed_thread; - for (listed_thread = m_debugged_process_up->GetThreadAtIndex(thread_index); + for (listed_thread = m_current_process->GetThreadAtIndex(thread_index); listed_thread; ++thread_index, - listed_thread = m_debugged_process_up->GetThreadAtIndex(thread_index)) { + listed_thread = m_current_process->GetThreadAtIndex(thread_index)) { if (thread_index > 0) response.PutChar(','); response.Printf("%" PRIx64, listed_thread->GetID()); @@ -754,7 +847,7 @@ GDBRemoteCommunicationServerLLGS::SendStopReplyPacketForThread( if (thread_index > 1) { const bool threads_with_valid_stop_info_only = true; llvm::Expected threads_info = GetJSONThreadsInfo( - *m_debugged_process_up, threads_with_valid_stop_info_only); + *m_current_process, threads_with_valid_stop_info_only); if (threads_info) { response.PutCString("jstopinfo:"); StreamString unescaped_response; @@ -764,7 +857,7 @@ GDBRemoteCommunicationServerLLGS::SendStopReplyPacketForThread( } else { LLDB_LOG_ERROR(log, threads_info.takeError(), "failed to prepare a jstopinfo field for pid {1}: {0}", - m_debugged_process_up->GetID()); + m_current_process->GetID()); } } @@ -772,8 +865,7 @@ GDBRemoteCommunicationServerLLGS::SendStopReplyPacketForThread( response.PutCString("thread-pcs"); char delimiter = ':'; for (NativeThreadProtocol *thread; - (thread = m_debugged_process_up->GetThreadAtIndex(i)) != nullptr; - ++i) { + (thread = m_current_process->GetThreadAtIndex(i)) != nullptr; ++i) { NativeRegisterContext& reg_ctx = thread->GetRegisterContext(); uint32_t reg_to_read = reg_ctx.ConvertRegisterKindToRegisterNumber( @@ -806,46 +898,27 @@ GDBRemoteCommunicationServerLLGS::SendStopReplyPacketForThread( // Grab the register context. NativeRegisterContext& reg_ctx = thread->GetRegisterContext(); - // Expedite all registers in the first register set (i.e. should be GPRs) - // that are not contained in other registers. - const RegisterSet *reg_set_p; - if (reg_ctx.GetRegisterSetCount() > 0 && - ((reg_set_p = reg_ctx.GetRegisterSet(0)) != nullptr)) { - LLDB_LOGF(log, - "GDBRemoteCommunicationServerLLGS::%s expediting registers " - "from set '%s' (registers set count: %zu)", - __FUNCTION__, reg_set_p->name ? reg_set_p->name : "", - reg_set_p->num_registers); + const auto expedited_regs = + reg_ctx.GetExpeditedRegisters(ExpeditedRegs::Full); - for (const uint32_t *reg_num_p = reg_set_p->registers; - *reg_num_p != LLDB_INVALID_REGNUM; ++reg_num_p) { - const RegisterInfo *const reg_info_p = - reg_ctx.GetRegisterInfoAtIndex(*reg_num_p); - if (reg_info_p == nullptr) { - LLDB_LOGF(log, - "GDBRemoteCommunicationServerLLGS::%s failed to get " - "register info for register set '%s', register index " - "%" PRIu32, + for (auto ®_num : expedited_regs) { + const RegisterInfo *const reg_info_p = + reg_ctx.GetRegisterInfoAtIndex(reg_num); + // Only expediate registers that are not contained in other registers. + if (reg_info_p != nullptr && reg_info_p->value_regs == nullptr) { + RegisterValue reg_value; + Status error = reg_ctx.ReadRegister(reg_info_p, reg_value); + if (error.Success()) { + response.Printf("%.02x:", reg_num); + WriteRegisterValueInHexFixedWidth(response, reg_ctx, *reg_info_p, + ®_value, lldb::eByteOrderBig); + response.PutChar(';'); + } else { + LLDB_LOGF(log, "GDBRemoteCommunicationServerLLGS::%s failed to read " + "register '%s' index %" PRIu32 ": %s", __FUNCTION__, - reg_set_p->name ? reg_set_p->name : "", - *reg_num_p); - } else if (reg_info_p->value_regs == nullptr) { - // Only expediate registers that are not contained in other registers. - RegisterValue reg_value; - Status error = reg_ctx.ReadRegister(reg_info_p, reg_value); - if (error.Success()) { - response.Printf("%.02x:", *reg_num_p); - WriteRegisterValueInHexFixedWidth(response, reg_ctx, *reg_info_p, - ®_value, lldb::eByteOrderBig); - response.PutChar(';'); - } else { - LLDB_LOGF(log, - "GDBRemoteCommunicationServerLLGS::%s failed to read " - "register '%s' index %" PRIu32 ": %s", - __FUNCTION__, - reg_info_p->name ? reg_info_p->name : "", - *reg_num_p, error.AsCString()); - } + reg_info_p->name ? reg_info_p->name : "", + reg_num, error.AsCString()); } } } @@ -875,6 +948,22 @@ GDBRemoteCommunicationServerLLGS::SendStopReplyPacketForThread( } } + // Include child process PID/TID for forks. + if (tid_stop_info.reason == eStopReasonFork || + tid_stop_info.reason == eStopReasonVFork) { + assert(bool(m_extensions_supported & + NativeProcessProtocol::Extension::multiprocess)); + if (tid_stop_info.reason == eStopReasonFork) + assert(bool(m_extensions_supported & + NativeProcessProtocol::Extension::fork)); + if (tid_stop_info.reason == eStopReasonVFork) + assert(bool(m_extensions_supported & + NativeProcessProtocol::Extension::vfork)); + response.Printf("%s:p%" PRIx64 ".%" PRIx64 ";", reason_str, + tid_stop_info.details.fork.child_pid, + tid_stop_info.details.fork.child_tid); + } + return SendPacketNoLock(response.GetString()); } @@ -979,6 +1068,15 @@ void GDBRemoteCommunicationServerLLGS::DidExec(NativeProcessProtocol *process) { ClearProcessSpecificData(); } +void GDBRemoteCommunicationServerLLGS::NewSubprocess( + NativeProcessProtocol *parent_process, + std::unique_ptr child_process) { + lldb::pid_t child_pid = child_process->GetID(); + assert(child_pid != LLDB_INVALID_PROCESS_ID); + assert(m_debugged_processes.find(child_pid) == m_debugged_processes.end()); + m_debugged_processes[child_pid] = std::move(child_process); +} + void GDBRemoteCommunicationServerLLGS::DataAvailableCallback() { Log *log(GetLogIfAnyCategoriesSet(GDBR_LOG_COMM)); @@ -1121,239 +1219,110 @@ void GDBRemoteCommunicationServerLLGS::SendProcessOutput() { } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerLLGS::Handle_jTraceStart( +GDBRemoteCommunicationServerLLGS::Handle_jLLDBTraceSupported( StringExtractorGDBRemote &packet) { - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); - // Fail if we don't have a current process. - if (!m_debugged_process_up || - (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID)) - return SendErrorResponse(68); - - if (!packet.ConsumeFront("jTraceStart:")) - return SendIllFormedResponse(packet, "jTraceStart: Ill formed packet "); - - TraceOptions options; - uint64_t type = std::numeric_limits::max(); - uint64_t buffersize = std::numeric_limits::max(); - lldb::tid_t tid = LLDB_INVALID_THREAD_ID; - uint64_t metabuffersize = std::numeric_limits::max(); - - auto json_object = StructuredData::ParseJSON(packet.Peek()); - - if (!json_object || - json_object->GetType() != lldb::eStructuredDataTypeDictionary) - return SendIllFormedResponse(packet, "jTraceStart: Ill formed packet "); - - auto json_dict = json_object->GetAsDictionary(); - - json_dict->GetValueForKeyAsInteger("metabuffersize", metabuffersize); - options.setMetaDataBufferSize(metabuffersize); - - json_dict->GetValueForKeyAsInteger("buffersize", buffersize); - options.setTraceBufferSize(buffersize); - - json_dict->GetValueForKeyAsInteger("type", type); - options.setType(static_cast(type)); - json_dict->GetValueForKeyAsInteger("threadid", tid); - options.setThreadID(tid); - - StructuredData::ObjectSP custom_params_sp = - json_dict->GetValueForKey("params"); - if (custom_params_sp && - custom_params_sp->GetType() != lldb::eStructuredDataTypeDictionary) - return SendIllFormedResponse(packet, "jTraceStart: Ill formed packet "); - - options.setTraceParams( - std::static_pointer_cast(custom_params_sp)); - - if (buffersize == std::numeric_limits::max() || - type != lldb::TraceType::eTraceTypeProcessorTrace) { - LLDB_LOG(log, "Ill formed packet buffersize = {0} type = {1}", buffersize, - type); - return SendIllFormedResponse(packet, "JTrace:start: Ill formed packet "); - } - - Status error; - lldb::user_id_t uid = LLDB_INVALID_UID; - uid = m_debugged_process_up->StartTrace(options, error); - LLDB_LOG(log, "uid is {0} , error is {1}", uid, error.GetError()); - if (error.Fail()) - return SendErrorResponse(error); + // Fail if we don't have a current process. + if (!m_current_process || + (m_current_process->GetID() == LLDB_INVALID_PROCESS_ID)) + return SendErrorResponse(Status("Process not running.")); - StreamGDBRemote response; - response.Printf("%" PRIx64, uid); - return SendPacketNoLock(response.GetString()); + return SendJSONResponse(m_current_process->TraceSupported()); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerLLGS::Handle_jTraceStop( +GDBRemoteCommunicationServerLLGS::Handle_jLLDBTraceStop( StringExtractorGDBRemote &packet) { // Fail if we don't have a current process. - if (!m_debugged_process_up || - (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID)) - return SendErrorResponse(68); - - if (!packet.ConsumeFront("jTraceStop:")) - return SendIllFormedResponse(packet, "jTraceStop: Ill formed packet "); - - lldb::user_id_t uid = LLDB_INVALID_UID; - lldb::tid_t tid = LLDB_INVALID_THREAD_ID; - - auto json_object = StructuredData::ParseJSON(packet.Peek()); + if (!m_current_process || + (m_current_process->GetID() == LLDB_INVALID_PROCESS_ID)) + return SendErrorResponse(Status("Process not running.")); - if (!json_object || - json_object->GetType() != lldb::eStructuredDataTypeDictionary) - return SendIllFormedResponse(packet, "jTraceStop: Ill formed packet "); + packet.ConsumeFront("jLLDBTraceStop:"); + Expected stop_request = + json::parse(packet.Peek(), "TraceStopRequest"); + if (!stop_request) + return SendErrorResponse(stop_request.takeError()); - auto json_dict = json_object->GetAsDictionary(); - - if (!json_dict->GetValueForKeyAsInteger("traceid", uid)) - return SendIllFormedResponse(packet, "jTraceStop: Ill formed packet "); - - json_dict->GetValueForKeyAsInteger("threadid", tid); - - Status error = m_debugged_process_up->StopTrace(uid, tid); - - if (error.Fail()) - return SendErrorResponse(error); + if (Error err = m_current_process->TraceStop(*stop_request)) + return SendErrorResponse(std::move(err)); return SendOKResponse(); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerLLGS::Handle_jTraceConfigRead( +GDBRemoteCommunicationServerLLGS::Handle_jLLDBTraceStart( StringExtractorGDBRemote &packet) { // Fail if we don't have a current process. - if (!m_debugged_process_up || - (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID)) - return SendErrorResponse(68); - - if (!packet.ConsumeFront("jTraceConfigRead:")) - return SendIllFormedResponse(packet, - "jTraceConfigRead: Ill formed packet "); - - lldb::user_id_t uid = LLDB_INVALID_UID; - lldb::tid_t threadid = LLDB_INVALID_THREAD_ID; + if (!m_current_process || + (m_current_process->GetID() == LLDB_INVALID_PROCESS_ID)) + return SendErrorResponse(Status("Process not running.")); - auto json_object = StructuredData::ParseJSON(packet.Peek()); + packet.ConsumeFront("jLLDBTraceStart:"); + Expected request = + json::parse(packet.Peek(), "TraceStartRequest"); + if (!request) + return SendErrorResponse(request.takeError()); - if (!json_object || - json_object->GetType() != lldb::eStructuredDataTypeDictionary) - return SendIllFormedResponse(packet, - "jTraceConfigRead: Ill formed packet "); + if (Error err = m_current_process->TraceStart(packet.Peek(), request->type)) + return SendErrorResponse(std::move(err)); - auto json_dict = json_object->GetAsDictionary(); - - if (!json_dict->GetValueForKeyAsInteger("traceid", uid)) - return SendIllFormedResponse(packet, - "jTraceConfigRead: Ill formed packet "); - - json_dict->GetValueForKeyAsInteger("threadid", threadid); - - TraceOptions options; - StreamGDBRemote response; - - options.setThreadID(threadid); - Status error = m_debugged_process_up->GetTraceConfig(uid, options); - - if (error.Fail()) - return SendErrorResponse(error); - - StreamGDBRemote escaped_response; - StructuredData::Dictionary json_packet; - - json_packet.AddIntegerItem("type", options.getType()); - json_packet.AddIntegerItem("buffersize", options.getTraceBufferSize()); - json_packet.AddIntegerItem("metabuffersize", options.getMetaDataBufferSize()); - - StructuredData::DictionarySP custom_params = options.getTraceParams(); - if (custom_params) - json_packet.AddItem("params", custom_params); - - StreamString json_string; - json_packet.Dump(json_string, false); - escaped_response.PutEscapedBytes(json_string.GetData(), - json_string.GetSize()); - return SendPacketNoLock(escaped_response.GetString()); + return SendOKResponse(); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerLLGS::Handle_jTraceRead( +GDBRemoteCommunicationServerLLGS::Handle_jLLDBTraceGetState( StringExtractorGDBRemote &packet) { // Fail if we don't have a current process. - if (!m_debugged_process_up || - (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID)) - return SendErrorResponse(68); - - enum PacketType { MetaData, BufferData }; - PacketType tracetype = MetaData; - - if (packet.ConsumeFront("jTraceBufferRead:")) - tracetype = BufferData; - else if (packet.ConsumeFront("jTraceMetaRead:")) - tracetype = MetaData; - else { - return SendIllFormedResponse(packet, "jTrace: Ill formed packet "); - } - - lldb::user_id_t uid = LLDB_INVALID_UID; - - uint64_t byte_count = std::numeric_limits::max(); - lldb::tid_t tid = LLDB_INVALID_THREAD_ID; - uint64_t offset = std::numeric_limits::max(); - - auto json_object = StructuredData::ParseJSON(packet.Peek()); - - if (!json_object || - json_object->GetType() != lldb::eStructuredDataTypeDictionary) - return SendIllFormedResponse(packet, "jTrace: Ill formed packet "); + if (!m_current_process || + (m_current_process->GetID() == LLDB_INVALID_PROCESS_ID)) + return SendErrorResponse(Status("Process not running.")); - auto json_dict = json_object->GetAsDictionary(); + packet.ConsumeFront("jLLDBTraceGetState:"); + Expected request = + json::parse(packet.Peek(), "TraceGetStateRequest"); + if (!request) + return SendErrorResponse(request.takeError()); - if (!json_dict->GetValueForKeyAsInteger("traceid", uid) || - !json_dict->GetValueForKeyAsInteger("offset", offset) || - !json_dict->GetValueForKeyAsInteger("buffersize", byte_count)) - return SendIllFormedResponse(packet, "jTrace: Ill formed packet "); - - json_dict->GetValueForKeyAsInteger("threadid", tid); - - // Allocate the response buffer. - std::unique_ptr buffer (new (std::nothrow) uint8_t[byte_count]); - if (!buffer) - return SendErrorResponse(0x78); - - StreamGDBRemote response; - Status error; - llvm::MutableArrayRef buf(buffer.get(), byte_count); - - if (tracetype == BufferData) - error = m_debugged_process_up->GetData(uid, tid, buf, offset); - else if (tracetype == MetaData) - error = m_debugged_process_up->GetMetaData(uid, tid, buf, offset); - - if (error.Fail()) - return SendErrorResponse(error); + return SendJSONResponse(m_current_process->TraceGetState(request->type)); +} - for (auto i : buf) - response.PutHex8(i); +GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationServerLLGS::Handle_jLLDBTraceGetBinaryData( + StringExtractorGDBRemote &packet) { - StreamGDBRemote escaped_response; - escaped_response.PutEscapedBytes(response.GetData(), response.GetSize()); - return SendPacketNoLock(escaped_response.GetString()); + // Fail if we don't have a current process. + if (!m_current_process || + (m_current_process->GetID() == LLDB_INVALID_PROCESS_ID)) + return SendErrorResponse(Status("Process not running.")); + + packet.ConsumeFront("jLLDBTraceGetBinaryData:"); + llvm::Expected request = + llvm::json::parse(packet.Peek(), + "TraceGetBinaryDataRequest"); + if (!request) + return SendErrorResponse(Status(request.takeError())); + + if (Expected> bytes = + m_current_process->TraceGetBinaryData(*request)) { + StreamGDBRemote response; + response.PutEscapedBytes(bytes->data(), bytes->size()); + return SendPacketNoLock(response.GetString()); + } else + return SendErrorResponse(bytes.takeError()); } GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_qProcessInfo( StringExtractorGDBRemote &packet) { // Fail if we don't have a current process. - if (!m_debugged_process_up || - (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID)) + if (!m_current_process || + (m_current_process->GetID() == LLDB_INVALID_PROCESS_ID)) return SendErrorResponse(68); - lldb::pid_t pid = m_debugged_process_up->GetID(); + lldb::pid_t pid = m_current_process->GetID(); if (pid == LLDB_INVALID_PROCESS_ID) return SendErrorResponse(1); @@ -1370,16 +1339,16 @@ GDBRemoteCommunicationServerLLGS::Handle_qProcessInfo( GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_qC(StringExtractorGDBRemote &packet) { // Fail if we don't have a current process. - if (!m_debugged_process_up || - (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID)) + if (!m_current_process || + (m_current_process->GetID() == LLDB_INVALID_PROCESS_ID)) return SendErrorResponse(68); // Make sure we set the current thread so g and p packets return the data the // gdb will expect. - lldb::tid_t tid = m_debugged_process_up->GetCurrentThreadID(); + lldb::tid_t tid = m_current_process->GetCurrentThreadID(); SetCurrentThreadID(tid); - NativeThreadProtocol *thread = m_debugged_process_up->GetCurrentThread(); + NativeThreadProtocol *thread = m_current_process->GetCurrentThread(); if (!thread) return SendErrorResponse(69); @@ -1395,15 +1364,15 @@ GDBRemoteCommunicationServerLLGS::Handle_k(StringExtractorGDBRemote &packet) { StopSTDIOForwarding(); - if (!m_debugged_process_up) { + if (!m_current_process) { LLDB_LOG(log, "No debugged process found."); return PacketResult::Success; } - Status error = m_debugged_process_up->Kill(); + Status error = m_current_process->Kill(); if (error.Fail()) LLDB_LOG(log, "Failed to kill debugged process {0}: {1}", - m_debugged_process_up->GetID(), error); + m_current_process->GetID(), error); // No OK response for kill packet. // return SendOKResponse (); @@ -1444,13 +1413,27 @@ GDBRemoteCommunicationServerLLGS::Handle_qGetWorkingDir( return SendErrorResponse(14); } +GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationServerLLGS::Handle_QThreadSuffixSupported( + StringExtractorGDBRemote &packet) { + m_thread_suffix_supported = true; + return SendOKResponse(); +} + +GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationServerLLGS::Handle_QListThreadsInStopReply( + StringExtractorGDBRemote &packet) { + m_list_threads_in_stop_reply = true; + return SendOKResponse(); +} + GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_C(StringExtractorGDBRemote &packet) { Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_THREAD)); LLDB_LOGF(log, "GDBRemoteCommunicationServerLLGS::%s called", __FUNCTION__); // Ensure we have a native process. - if (!m_debugged_process_up) { + if (!m_continue_process) { LLDB_LOGF(log, "GDBRemoteCommunicationServerLLGS::%s no debugged process " "shared pointer", @@ -1503,20 +1486,20 @@ GDBRemoteCommunicationServerLLGS::Handle_C(StringExtractorGDBRemote &packet) { } else { // Send the signal to the process since we weren't targeting a specific // continue thread with the signal. - error = m_debugged_process_up->Signal(signo); + error = m_continue_process->Signal(signo); if (error.Fail()) { LLDB_LOG(log, "failed to send signal for process {0}: {1}", - m_debugged_process_up->GetID(), error); + m_continue_process->GetID(), error); return SendErrorResponse(0x52); } } // Resume the threads. - error = m_debugged_process_up->Resume(resume_actions); + error = m_continue_process->Resume(resume_actions); if (error.Fail()) { LLDB_LOG(log, "failed to resume threads for process {0}: {1}", - m_debugged_process_up->GetID(), error); + m_continue_process->GetID(), error); return SendErrorResponse(0x38); } @@ -1541,7 +1524,7 @@ GDBRemoteCommunicationServerLLGS::Handle_c(StringExtractorGDBRemote &packet) { } // Ensure we have a native process. - if (!m_debugged_process_up) { + if (!m_continue_process) { LLDB_LOGF(log, "GDBRemoteCommunicationServerLLGS::%s no debugged process " "shared pointer", @@ -1553,14 +1536,14 @@ GDBRemoteCommunicationServerLLGS::Handle_c(StringExtractorGDBRemote &packet) { ResumeActionList actions(StateType::eStateRunning, LLDB_INVALID_SIGNAL_NUMBER); - Status error = m_debugged_process_up->Resume(actions); + Status error = m_continue_process->Resume(actions); if (error.Fail()) { - LLDB_LOG(log, "c failed for process {0}: {1}", - m_debugged_process_up->GetID(), error); + LLDB_LOG(log, "c failed for process {0}: {1}", m_continue_process->GetID(), + error); return SendErrorResponse(GDBRemoteServerError::eErrorResume); } - LLDB_LOG(log, "continued process {0}", m_debugged_process_up->GetID()); + LLDB_LOG(log, "continued process {0}", m_continue_process->GetID()); // No response required from continue. return PacketResult::Success; } @@ -1603,7 +1586,7 @@ GDBRemoteCommunicationServerLLGS::Handle_vCont( } // Ensure we have a native process. - if (!m_debugged_process_up) { + if (!m_continue_process) { LLDB_LOG(log, "no debugged process"); return SendErrorResponse(0x36); } @@ -1656,23 +1639,27 @@ GDBRemoteCommunicationServerLLGS::Handle_vCont( // Consume the separator. packet.GetChar(); - thread_action.tid = packet.GetHexMaxU32(false, LLDB_INVALID_THREAD_ID); - if (thread_action.tid == LLDB_INVALID_THREAD_ID) - return SendIllFormedResponse( - packet, "Could not parse thread number in vCont packet"); + llvm::Expected tid_ret = + ReadTid(packet, /*allow_all=*/true, m_continue_process->GetID()); + if (!tid_ret) + return SendErrorResponse(tid_ret.takeError()); + + thread_action.tid = tid_ret.get(); + if (thread_action.tid == StringExtractorGDBRemote::AllThreads) + thread_action.tid = LLDB_INVALID_THREAD_ID; } thread_actions.Append(thread_action); } - Status error = m_debugged_process_up->Resume(thread_actions); + Status error = m_continue_process->Resume(thread_actions); if (error.Fail()) { LLDB_LOG(log, "vCont failed for process {0}: {1}", - m_debugged_process_up->GetID(), error); + m_continue_process->GetID(), error); return SendErrorResponse(GDBRemoteServerError::eErrorResume); } - LLDB_LOG(log, "continued process {0}", m_debugged_process_up->GetID()); + LLDB_LOG(log, "continued process {0}", m_continue_process->GetID()); // No response required from vCont. return PacketResult::Success; } @@ -1682,8 +1669,8 @@ void GDBRemoteCommunicationServerLLGS::SetCurrentThreadID(lldb::tid_t tid) { LLDB_LOG(log, "setting current thread id to {0}", tid); m_current_tid = tid; - if (m_debugged_process_up) - m_debugged_process_up->SetCurrentThreadID(m_current_tid); + if (m_current_process) + m_current_process->SetCurrentThreadID(m_current_tid); } void GDBRemoteCommunicationServerLLGS::SetContinueThreadID(lldb::tid_t tid) { @@ -1699,10 +1686,10 @@ GDBRemoteCommunicationServerLLGS::Handle_stop_reason( // Handle the $? gdbremote command. // If no process, indicate error - if (!m_debugged_process_up) + if (!m_current_process) return SendErrorResponse(02); - return SendStopReasonForState(m_debugged_process_up->GetState()); + return SendStopReasonForState(m_current_process->GetState()); } GDBRemoteCommunication::PacketResult @@ -1723,7 +1710,8 @@ GDBRemoteCommunicationServerLLGS::SendStopReasonForState( case eStateSuspended: case eStateStopped: case eStateCrashed: { - lldb::tid_t tid = m_debugged_process_up->GetCurrentThreadID(); + assert(m_current_process != nullptr); + lldb::tid_t tid = m_current_process->GetCurrentThreadID(); // Make sure we set the current thread so g and p packets return the data // the gdb will expect. SetCurrentThreadID(tid); @@ -1733,11 +1721,11 @@ GDBRemoteCommunicationServerLLGS::SendStopReasonForState( case eStateInvalid: case eStateUnloaded: case eStateExited: - return SendWResponse(m_debugged_process_up.get()); + return SendWResponse(m_current_process); default: LLDB_LOG(log, "pid {0}, current state reporting not handled: {1}", - m_debugged_process_up->GetID(), process_state); + m_current_process->GetID(), process_state); break; } @@ -1748,12 +1736,12 @@ GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_qRegisterInfo( StringExtractorGDBRemote &packet) { // Fail if we don't have a current process. - if (!m_debugged_process_up || - (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID)) + if (!m_current_process || + (m_current_process->GetID() == LLDB_INVALID_PROCESS_ID)) return SendErrorResponse(68); // Ensure we have a thread. - NativeThreadProtocol *thread = m_debugged_process_up->GetThreadAtIndex(0); + NativeThreadProtocol *thread = m_current_process->GetThreadAtIndex(0); if (!thread) return SendErrorResponse(69); @@ -1789,8 +1777,10 @@ GDBRemoteCommunicationServerLLGS::Handle_qRegisterInfo( response.PutChar(';'); } - response.Printf("bitsize:%" PRIu32 ";offset:%" PRIu32 ";", - reg_info->byte_size * 8, reg_info->byte_offset); + response.Printf("bitsize:%" PRIu32 ";", reg_info->byte_size * 8); + + if (!reg_context.RegisterOffsetIsDynamic()) + response.Printf("offset:%" PRIu32 ";", reg_info->byte_offset); llvm::StringRef encoding = GetEncodingNameOrEmpty(*reg_info); if (!encoding.empty()) @@ -1846,11 +1836,11 @@ GDBRemoteCommunicationServerLLGS::Handle_qfThreadInfo( Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD)); // Fail if we don't have a current process. - if (!m_debugged_process_up || - (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID)) { + if (!m_current_process || + (m_current_process->GetID() == LLDB_INVALID_PROCESS_ID)) { LLDB_LOG(log, "no process ({0}), returning OK", - m_debugged_process_up ? "invalid process id" - : "null m_debugged_process_up"); + m_current_process ? "invalid process id" + : "null m_current_process"); return SendOKResponse(); } @@ -1861,9 +1851,9 @@ GDBRemoteCommunicationServerLLGS::Handle_qfThreadInfo( NativeThreadProtocol *thread; uint32_t thread_index; for (thread_index = 0, - thread = m_debugged_process_up->GetThreadAtIndex(thread_index); + thread = m_current_process->GetThreadAtIndex(thread_index); thread; ++thread_index, - thread = m_debugged_process_up->GetThreadAtIndex(thread_index)) { + thread = m_current_process->GetThreadAtIndex(thread_index)) { LLDB_LOG(log, "iterated thread {0}(tid={2})", thread_index, thread->GetID()); if (thread_index > 0) @@ -2084,9 +2074,8 @@ GDBRemoteCommunicationServerLLGS::Handle_P(StringExtractorGDBRemote &packet) { // Build the reginfos response. StreamGDBRemote response; - RegisterValue reg_value( - reg_bytes, reg_size, - m_debugged_process_up->GetArchitecture().GetByteOrder()); + RegisterValue reg_value(makeArrayRef(reg_bytes, reg_size), + m_current_process->GetArchitecture().GetByteOrder()); Status error = reg_context.WriteRegister(reg_info, reg_value); if (error.Fail()) { LLDB_LOGF(log, @@ -2103,16 +2092,6 @@ GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_H(StringExtractorGDBRemote &packet) { Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD)); - // Fail if we don't have a current process. - if (!m_debugged_process_up || - (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID)) { - LLDB_LOGF( - log, - "GDBRemoteCommunicationServerLLGS::%s failed, no process available", - __FUNCTION__); - return SendErrorResponse(0x15); - } - // Parse out which variant of $H is requested. packet.SetFilePos(strlen("H")); if (packet.GetBytesLeft() < 1) { @@ -2124,11 +2103,14 @@ GDBRemoteCommunicationServerLLGS::Handle_H(StringExtractorGDBRemote &packet) { } const char h_variant = packet.GetChar(); + NativeProcessProtocol *default_process; switch (h_variant) { case 'g': + default_process = m_current_process; break; case 'c': + default_process = m_continue_process; break; default: @@ -2141,14 +2123,32 @@ GDBRemoteCommunicationServerLLGS::Handle_H(StringExtractorGDBRemote &packet) { } // Parse out the thread number. - // FIXME return a parse success/fail value. All values are valid here. - const lldb::tid_t tid = - packet.GetHexMaxU64(false, std::numeric_limits::max()); + auto pid_tid = packet.GetPidTid(default_process ? default_process->GetID() + : LLDB_INVALID_PROCESS_ID); + if (!pid_tid) + return SendErrorResponse(llvm::make_error( + inconvertibleErrorCode(), "Malformed thread-id")); + + lldb::pid_t pid = pid_tid->first; + lldb::tid_t tid = pid_tid->second; + + if (pid == StringExtractorGDBRemote::AllProcesses) + return SendUnimplementedResponse("Selecting all processes not supported"); + if (pid == LLDB_INVALID_PROCESS_ID) + return SendErrorResponse(llvm::make_error( + inconvertibleErrorCode(), "No current process and no PID provided")); + + // Check the process ID and find respective process instance. + auto new_process_it = m_debugged_processes.find(pid); + if (new_process_it == m_debugged_processes.end()) + return SendErrorResponse(llvm::make_error( + inconvertibleErrorCode(), + llvm::formatv("No process with PID {0} debugged", pid))); // Ensure we have the given thread when not specifying -1 (all threads) or 0 // (any thread). if (tid != LLDB_INVALID_THREAD_ID && tid != 0) { - NativeThreadProtocol *thread = m_debugged_process_up->GetThreadByID(tid); + NativeThreadProtocol *thread = new_process_it->second->GetThreadByID(tid); if (!thread) { LLDB_LOGF(log, "GDBRemoteCommunicationServerLLGS::%s failed, tid %" PRIu64 @@ -2158,13 +2158,15 @@ GDBRemoteCommunicationServerLLGS::Handle_H(StringExtractorGDBRemote &packet) { } } - // Now switch the given thread type. + // Now switch the given process and thread type. switch (h_variant) { case 'g': + m_current_process = new_process_it->second.get(); SetCurrentThreadID(tid); break; case 'c': + m_continue_process = new_process_it->second.get(); SetContinueThreadID(tid); break; @@ -2182,8 +2184,8 @@ GDBRemoteCommunicationServerLLGS::Handle_I(StringExtractorGDBRemote &packet) { Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD)); // Fail if we don't have a current process. - if (!m_debugged_process_up || - (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID)) { + if (!m_current_process || + (m_current_process->GetID() == LLDB_INVALID_PROCESS_ID)) { LLDB_LOGF( log, "GDBRemoteCommunicationServerLLGS::%s failed, no process available", @@ -2218,21 +2220,21 @@ GDBRemoteCommunicationServerLLGS::Handle_interrupt( Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_THREAD)); // Fail if we don't have a current process. - if (!m_debugged_process_up || - (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID)) { + if (!m_current_process || + (m_current_process->GetID() == LLDB_INVALID_PROCESS_ID)) { LLDB_LOG(log, "failed, no process available"); return SendErrorResponse(0x15); } // Interrupt the process. - Status error = m_debugged_process_up->Interrupt(); + Status error = m_current_process->Interrupt(); if (error.Fail()) { - LLDB_LOG(log, "failed for process {0}: {1}", m_debugged_process_up->GetID(), + LLDB_LOG(log, "failed for process {0}: {1}", m_current_process->GetID(), error); return SendErrorResponse(GDBRemoteServerError::eErrorResume); } - LLDB_LOG(log, "stopped process {0}", m_debugged_process_up->GetID()); + LLDB_LOG(log, "stopped process {0}", m_current_process->GetID()); // No response required from stop all. return PacketResult::Success; @@ -2243,8 +2245,8 @@ GDBRemoteCommunicationServerLLGS::Handle_memory_read( StringExtractorGDBRemote &packet) { Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); - if (!m_debugged_process_up || - (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID)) { + if (!m_current_process || + (m_current_process->GetID() == LLDB_INVALID_PROCESS_ID)) { LLDB_LOGF( log, "GDBRemoteCommunicationServerLLGS::%s failed, no process available", @@ -2286,13 +2288,13 @@ GDBRemoteCommunicationServerLLGS::Handle_memory_read( // Retrieve the process memory. size_t bytes_read = 0; - Status error = m_debugged_process_up->ReadMemoryWithoutTrap( + Status error = m_current_process->ReadMemoryWithoutTrap( read_addr, &buf[0], byte_count, bytes_read); if (error.Fail()) { LLDB_LOGF(log, "GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 " mem 0x%" PRIx64 ": failed to read. Error: %s", - __FUNCTION__, m_debugged_process_up->GetID(), read_addr, + __FUNCTION__, m_current_process->GetID(), read_addr, error.AsCString()); return SendErrorResponse(0x08); } @@ -2301,8 +2303,7 @@ GDBRemoteCommunicationServerLLGS::Handle_memory_read( LLDB_LOGF(log, "GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 " mem 0x%" PRIx64 ": read 0 of %" PRIu64 " requested bytes", - __FUNCTION__, m_debugged_process_up->GetID(), read_addr, - byte_count); + __FUNCTION__, m_current_process->GetID(), read_addr, byte_count); return SendErrorResponse(0x08); } @@ -2320,12 +2321,89 @@ GDBRemoteCommunicationServerLLGS::Handle_memory_read( return SendPacketNoLock(response.GetString()); } +GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationServerLLGS::Handle__M(StringExtractorGDBRemote &packet) { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + + if (!m_current_process || + (m_current_process->GetID() == LLDB_INVALID_PROCESS_ID)) { + LLDB_LOGF( + log, + "GDBRemoteCommunicationServerLLGS::%s failed, no process available", + __FUNCTION__); + return SendErrorResponse(0x15); + } + + // Parse out the memory address. + packet.SetFilePos(strlen("_M")); + if (packet.GetBytesLeft() < 1) + return SendIllFormedResponse(packet, "Too short _M packet"); + + const lldb::addr_t size = packet.GetHexMaxU64(false, LLDB_INVALID_ADDRESS); + if (size == LLDB_INVALID_ADDRESS) + return SendIllFormedResponse(packet, "Address not valid"); + if (packet.GetChar() != ',') + return SendIllFormedResponse(packet, "Bad packet"); + Permissions perms = {}; + while (packet.GetBytesLeft() > 0) { + switch (packet.GetChar()) { + case 'r': + perms |= ePermissionsReadable; + break; + case 'w': + perms |= ePermissionsWritable; + break; + case 'x': + perms |= ePermissionsExecutable; + break; + default: + return SendIllFormedResponse(packet, "Bad permissions"); + } + } + + llvm::Expected addr = m_current_process->AllocateMemory(size, perms); + if (!addr) + return SendErrorResponse(addr.takeError()); + + StreamGDBRemote response; + response.PutHex64(*addr); + return SendPacketNoLock(response.GetString()); +} + +GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationServerLLGS::Handle__m(StringExtractorGDBRemote &packet) { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + + if (!m_current_process || + (m_current_process->GetID() == LLDB_INVALID_PROCESS_ID)) { + LLDB_LOGF( + log, + "GDBRemoteCommunicationServerLLGS::%s failed, no process available", + __FUNCTION__); + return SendErrorResponse(0x15); + } + + // Parse out the memory address. + packet.SetFilePos(strlen("_m")); + if (packet.GetBytesLeft() < 1) + return SendIllFormedResponse(packet, "Too short m packet"); + + const lldb::addr_t addr = packet.GetHexMaxU64(false, LLDB_INVALID_ADDRESS); + if (addr == LLDB_INVALID_ADDRESS) + return SendIllFormedResponse(packet, "Address not valid"); + + if (llvm::Error Err = m_current_process->DeallocateMemory(addr)) + return SendErrorResponse(std::move(Err)); + + return SendOKResponse(); +} + GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_M(StringExtractorGDBRemote &packet) { Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); - if (!m_debugged_process_up || - (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID)) { + if (!m_current_process || + (m_current_process->GetID() == LLDB_INVALID_PROCESS_ID)) { LLDB_LOGF( log, "GDBRemoteCommunicationServerLLGS::%s failed, no process available", @@ -2374,8 +2452,7 @@ GDBRemoteCommunicationServerLLGS::Handle_M(StringExtractorGDBRemote &packet) { LLDB_LOG(log, "pid {0} mem {1:x}: asked to write {2} bytes, but only found {3} " "to convert.", - m_debugged_process_up->GetID(), write_addr, byte_count, - convert_count); + m_current_process->GetID(), write_addr, byte_count, convert_count); return SendIllFormedResponse(packet, "M content byte length specified did " "not match hex-encoded content " "length"); @@ -2383,17 +2460,17 @@ GDBRemoteCommunicationServerLLGS::Handle_M(StringExtractorGDBRemote &packet) { // Write the process memory. size_t bytes_written = 0; - Status error = m_debugged_process_up->WriteMemory(write_addr, &buf[0], - byte_count, bytes_written); + Status error = m_current_process->WriteMemory(write_addr, &buf[0], byte_count, + bytes_written); if (error.Fail()) { LLDB_LOG(log, "pid {0} mem {1:x}: failed to write. Error: {2}", - m_debugged_process_up->GetID(), write_addr, error); + m_current_process->GetID(), write_addr, error); return SendErrorResponse(0x09); } if (bytes_written == 0) { LLDB_LOG(log, "pid {0} mem {1:x}: wrote 0 of {2} requested bytes", - m_debugged_process_up->GetID(), write_addr, byte_count); + m_current_process->GetID(), write_addr, byte_count); return SendErrorResponse(0x09); } @@ -2412,8 +2489,8 @@ GDBRemoteCommunicationServerLLGS::Handle_qMemoryRegionInfoSupported( // Ensure we have a process running; otherwise, we can't figure this out // since we won't have a NativeProcessProtocol. - if (!m_debugged_process_up || - (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID)) { + if (!m_current_process || + (m_current_process->GetID() == LLDB_INVALID_PROCESS_ID)) { LLDB_LOGF( log, "GDBRemoteCommunicationServerLLGS::%s failed, no process available", @@ -2423,8 +2500,7 @@ GDBRemoteCommunicationServerLLGS::Handle_qMemoryRegionInfoSupported( // Test if we can get any region back when asking for the region around NULL. MemoryRegionInfo region_info; - const Status error = - m_debugged_process_up->GetMemoryRegionInfo(0, region_info); + const Status error = m_current_process->GetMemoryRegionInfo(0, region_info); if (error.Fail()) { // We don't support memory region info collection for this // NativeProcessProtocol. @@ -2440,8 +2516,8 @@ GDBRemoteCommunicationServerLLGS::Handle_qMemoryRegionInfo( Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); // Ensure we have a process. - if (!m_debugged_process_up || - (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID)) { + if (!m_current_process || + (m_current_process->GetID() == LLDB_INVALID_PROCESS_ID)) { LLDB_LOGF( log, "GDBRemoteCommunicationServerLLGS::%s failed, no process available", @@ -2462,7 +2538,7 @@ GDBRemoteCommunicationServerLLGS::Handle_qMemoryRegionInfo( // Get the memory region info for the target address. MemoryRegionInfo region_info; const Status error = - m_debugged_process_up->GetMemoryRegionInfo(read_addr, region_info); + m_current_process->GetMemoryRegionInfo(read_addr, region_info); if (error.Fail()) { // Return the error message. @@ -2491,6 +2567,17 @@ GDBRemoteCommunicationServerLLGS::Handle_qMemoryRegionInfo( response.PutChar(';'); } + // Flags + MemoryRegionInfo::OptionalBool memory_tagged = + region_info.GetMemoryTagged(); + if (memory_tagged != MemoryRegionInfo::eDontKnow) { + response.PutCString("flags:"); + if (memory_tagged == MemoryRegionInfo::eYes) { + response.PutCString("mt"); + } + response.PutChar(';'); + } + // Name ConstString name = region_info.GetName(); if (name) { @@ -2506,8 +2593,8 @@ GDBRemoteCommunicationServerLLGS::Handle_qMemoryRegionInfo( GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_Z(StringExtractorGDBRemote &packet) { // Ensure we have a process. - if (!m_debugged_process_up || - (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID)) { + if (!m_current_process || + (m_current_process->GetID() == LLDB_INVALID_PROCESS_ID)) { Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); LLDB_LOG(log, "failed, no process available"); return SendErrorResponse(0x15); @@ -2577,22 +2664,22 @@ GDBRemoteCommunicationServerLLGS::Handle_Z(StringExtractorGDBRemote &packet) { if (want_breakpoint) { // Try to set the breakpoint. const Status error = - m_debugged_process_up->SetBreakpoint(addr, size, want_hardware); + m_current_process->SetBreakpoint(addr, size, want_hardware); if (error.Success()) return SendOKResponse(); Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_BREAKPOINTS)); LLDB_LOG(log, "pid {0} failed to set breakpoint: {1}", - m_debugged_process_up->GetID(), error); + m_current_process->GetID(), error); return SendErrorResponse(0x09); } else { // Try to set the watchpoint. - const Status error = m_debugged_process_up->SetWatchpoint( + const Status error = m_current_process->SetWatchpoint( addr, size, watch_flags, want_hardware); if (error.Success()) return SendOKResponse(); Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_WATCHPOINTS)); LLDB_LOG(log, "pid {0} failed to set watchpoint: {1}", - m_debugged_process_up->GetID(), error); + m_current_process->GetID(), error); return SendErrorResponse(0x09); } } @@ -2600,8 +2687,8 @@ GDBRemoteCommunicationServerLLGS::Handle_Z(StringExtractorGDBRemote &packet) { GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_z(StringExtractorGDBRemote &packet) { // Ensure we have a process. - if (!m_debugged_process_up || - (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID)) { + if (!m_current_process || + (m_current_process->GetID() == LLDB_INVALID_PROCESS_ID)) { Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); LLDB_LOG(log, "failed, no process available"); return SendErrorResponse(0x15); @@ -2665,21 +2752,21 @@ GDBRemoteCommunicationServerLLGS::Handle_z(StringExtractorGDBRemote &packet) { if (want_breakpoint) { // Try to clear the breakpoint. const Status error = - m_debugged_process_up->RemoveBreakpoint(addr, want_hardware); + m_current_process->RemoveBreakpoint(addr, want_hardware); if (error.Success()) return SendOKResponse(); Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_BREAKPOINTS)); LLDB_LOG(log, "pid {0} failed to remove breakpoint: {1}", - m_debugged_process_up->GetID(), error); + m_current_process->GetID(), error); return SendErrorResponse(0x09); } else { // Try to clear the watchpoint. - const Status error = m_debugged_process_up->RemoveWatchpoint(addr); + const Status error = m_current_process->RemoveWatchpoint(addr); if (error.Success()) return SendOKResponse(); Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_WATCHPOINTS)); LLDB_LOG(log, "pid {0} failed to remove watchpoint: {1}", - m_debugged_process_up->GetID(), error); + m_current_process->GetID(), error); return SendErrorResponse(0x09); } } @@ -2689,8 +2776,8 @@ GDBRemoteCommunicationServerLLGS::Handle_s(StringExtractorGDBRemote &packet) { Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_THREAD)); // Ensure we have a process. - if (!m_debugged_process_up || - (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID)) { + if (!m_continue_process || + (m_continue_process->GetID() == LLDB_INVALID_PROCESS_ID)) { LLDB_LOGF( log, "GDBRemoteCommunicationServerLLGS::%s failed, no process available", @@ -2708,7 +2795,7 @@ GDBRemoteCommunicationServerLLGS::Handle_s(StringExtractorGDBRemote &packet) { // Double check that we have such a thread. // TODO investigate: on MacOSX we might need to do an UpdateThreads () here. - NativeThreadProtocol *thread = m_debugged_process_up->GetThreadByID(tid); + NativeThreadProtocol *thread = m_continue_process->GetThreadByID(tid); if (!thread) return SendErrorResponse(0x33); @@ -2721,12 +2808,12 @@ GDBRemoteCommunicationServerLLGS::Handle_s(StringExtractorGDBRemote &packet) { // All other threads stop while we're single stepping a thread. actions.SetDefaultThreadActionIfNeeded(eStateStopped, 0); - Status error = m_debugged_process_up->Resume(actions); + Status error = m_continue_process->Resume(actions); if (error.Fail()) { LLDB_LOGF(log, "GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 " tid %" PRIu64 " Resume() failed with error: %s", - __FUNCTION__, m_debugged_process_up->GetID(), tid, + __FUNCTION__, m_continue_process->GetID(), tid, error.AsCString()); return SendErrorResponse(0x49); } @@ -2738,7 +2825,7 @@ GDBRemoteCommunicationServerLLGS::Handle_s(StringExtractorGDBRemote &packet) { llvm::Expected> GDBRemoteCommunicationServerLLGS::BuildTargetXml() { // Ensure we have a thread. - NativeThreadProtocol *thread = m_debugged_process_up->GetThreadAtIndex(0); + NativeThreadProtocol *thread = m_current_process->GetThreadAtIndex(0); if (!thread) return llvm::createStringError(llvm::inconvertibleErrorCode(), "No thread available"); @@ -2753,7 +2840,7 @@ GDBRemoteCommunicationServerLLGS::BuildTargetXml() { response.Printf(""); response.Printf("%s", - m_debugged_process_up->GetArchitecture() + m_current_process->GetArchitecture() .GetTriple() .getArchName() .str() @@ -2773,10 +2860,11 @@ GDBRemoteCommunicationServerLLGS::BuildTargetXml() { continue; } - response.Printf("name, reg_info->byte_size * 8, - reg_info->byte_offset, reg_index); + response.Printf("name, reg_info->byte_size * 8, reg_index); + + if (!reg_context.RegisterOffsetIsDynamic()) + response.Printf("offset=\"%" PRIu32 "\" ", reg_info->byte_offset); if (reg_info->alt_name && reg_info->alt_name[0]) response.Printf("altname=\"%s\" ", reg_info->alt_name); @@ -2841,22 +2929,22 @@ llvm::Expected> GDBRemoteCommunicationServerLLGS::ReadXferObject(llvm::StringRef object, llvm::StringRef annex) { // Make sure we have a valid process. - if (!m_debugged_process_up || - (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID)) { + if (!m_current_process || + (m_current_process->GetID() == LLDB_INVALID_PROCESS_ID)) { return llvm::createStringError(llvm::inconvertibleErrorCode(), "No process available"); } if (object == "auxv") { // Grab the auxv data. - auto buffer_or_error = m_debugged_process_up->GetAuxvData(); + auto buffer_or_error = m_current_process->GetAuxvData(); if (!buffer_or_error) return llvm::errorCodeToError(buffer_or_error.getError()); return std::move(*buffer_or_error); } if (object == "libraries-svr4") { - auto library_list = m_debugged_process_up->GetLoadedSVR4Libraries(); + auto library_list = m_current_process->GetLoadedSVR4Libraries(); if (!library_list) return library_list.takeError(); @@ -2876,8 +2964,7 @@ GDBRemoteCommunicationServerLLGS::ReadXferObject(llvm::StringRef object, if (object == "features" && annex == "target.xml") return BuildTargetXml(); - return llvm::make_error( - "Xfer object not supported"); + return llvm::make_error(); } GDBRemoteCommunication::PacketResult @@ -2980,7 +3067,7 @@ GDBRemoteCommunicationServerLLGS::Handle_QSaveRegisterState( Status error = reg_context.ReadAllRegisterValues(register_data_sp); if (error.Fail()) { LLDB_LOG(log, "pid {0} failed to save all register values: {1}", - m_debugged_process_up->GetID(), error); + m_current_process->GetID(), error); return SendErrorResponse(0x75); } @@ -3043,7 +3130,7 @@ GDBRemoteCommunicationServerLLGS::Handle_QRestoreRegisterState( if (it == m_saved_registers_map.end()) { LLDB_LOG(log, "pid {0} does not have a register set save buffer for id {1}", - m_debugged_process_up->GetID(), save_id); + m_current_process->GetID(), save_id); return SendErrorResponse(0x77); } register_data_sp = it->second; @@ -3055,7 +3142,7 @@ GDBRemoteCommunicationServerLLGS::Handle_QRestoreRegisterState( Status error = reg_context.WriteAllRegisterValues(register_data_sp); if (error.Fail()) { LLDB_LOG(log, "pid {0} failed to restore all register values: {1}", - m_debugged_process_up->GetID(), error); + m_current_process->GetID(), error); return SendErrorResponse(0x77); } @@ -3095,25 +3182,79 @@ GDBRemoteCommunicationServerLLGS::Handle_vAttach( } // Notify we attached by sending a stop packet. - return SendStopReasonForState(m_debugged_process_up->GetState()); + return SendStopReasonForState(m_current_process->GetState()); } GDBRemoteCommunication::PacketResult -GDBRemoteCommunicationServerLLGS::Handle_D(StringExtractorGDBRemote &packet) { +GDBRemoteCommunicationServerLLGS::Handle_vAttachWait( + StringExtractorGDBRemote &packet) { Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); - StopSTDIOForwarding(); + // Consume the ';' after the identifier. + packet.SetFilePos(strlen("vAttachWait")); - // Fail if we don't have a current process. - if (!m_debugged_process_up || - (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID)) { - LLDB_LOGF( - log, - "GDBRemoteCommunicationServerLLGS::%s failed, no process available", - __FUNCTION__); - return SendErrorResponse(0x15); + if (!packet.GetBytesLeft() || packet.GetChar() != ';') + return SendIllFormedResponse(packet, "vAttachWait missing expected ';'"); + + // Allocate the buffer for the process name from vAttachWait. + std::string process_name; + if (!packet.GetHexByteString(process_name)) + return SendIllFormedResponse(packet, + "vAttachWait failed to parse process name"); + + LLDB_LOG(log, "attempting to attach to process named '{0}'", process_name); + + Status error = AttachWaitProcess(process_name, false); + if (error.Fail()) { + LLDB_LOG(log, "failed to attach to process named '{0}': {1}", process_name, + error); + return SendErrorResponse(error); } + // Notify we attached by sending a stop packet. + return SendStopReasonForState(m_current_process->GetState()); +} + +GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationServerLLGS::Handle_qVAttachOrWaitSupported( + StringExtractorGDBRemote &packet) { + return SendOKResponse(); +} + +GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationServerLLGS::Handle_vAttachOrWait( + StringExtractorGDBRemote &packet) { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + + // Consume the ';' after the identifier. + packet.SetFilePos(strlen("vAttachOrWait")); + + if (!packet.GetBytesLeft() || packet.GetChar() != ';') + return SendIllFormedResponse(packet, "vAttachOrWait missing expected ';'"); + + // Allocate the buffer for the process name from vAttachWait. + std::string process_name; + if (!packet.GetHexByteString(process_name)) + return SendIllFormedResponse(packet, + "vAttachOrWait failed to parse process name"); + + LLDB_LOG(log, "attempting to attach to process named '{0}'", process_name); + + Status error = AttachWaitProcess(process_name, true); + if (error.Fail()) { + LLDB_LOG(log, "failed to attach to process named '{0}': {1}", process_name, + error); + return SendErrorResponse(error); + } + + // Notify we attached by sending a stop packet. + return SendStopReasonForState(m_current_process->GetState()); +} + +GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationServerLLGS::Handle_D(StringExtractorGDBRemote &packet) { + StopSTDIOForwarding(); + lldb::pid_t pid = LLDB_INVALID_PROCESS_ID; // Consume the ';' after D. @@ -3128,19 +3269,32 @@ GDBRemoteCommunicationServerLLGS::Handle_D(StringExtractorGDBRemote &packet) { return SendIllFormedResponse(packet, "D failed to parse the process id"); } - if (pid != LLDB_INVALID_PROCESS_ID && m_debugged_process_up->GetID() != pid) { - return SendIllFormedResponse(packet, "Invalid pid"); - } - - const Status error = m_debugged_process_up->Detach(); - if (error.Fail()) { - LLDB_LOGF(log, - "GDBRemoteCommunicationServerLLGS::%s failed to detach from " - "pid %" PRIu64 ": %s\n", - __FUNCTION__, m_debugged_process_up->GetID(), error.AsCString()); - return SendErrorResponse(0x01); + // Detach forked children if their PID was specified *or* no PID was requested + // (i.e. detach-all packet). + llvm::Error detach_error = llvm::Error::success(); + bool detached = false; + for (auto it = m_debugged_processes.begin(); + it != m_debugged_processes.end();) { + if (pid == LLDB_INVALID_PROCESS_ID || pid == it->first) { + if (llvm::Error e = it->second->Detach().ToError()) + detach_error = llvm::joinErrors(std::move(detach_error), std::move(e)); + else { + if (it->second.get() == m_current_process) + m_current_process = nullptr; + if (it->second.get() == m_continue_process) + m_continue_process = nullptr; + it = m_debugged_processes.erase(it); + detached = true; + continue; + } + } + ++it; } + if (detach_error) + return SendErrorResponse(std::move(detach_error)); + if (!detached) + return SendErrorResponse(Status("PID %" PRIu64 " not traced", pid)); return SendOKResponse(); } @@ -3150,7 +3304,7 @@ GDBRemoteCommunicationServerLLGS::Handle_qThreadStopInfo( Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD)); packet.SetFilePos(strlen("qThreadStopInfo")); - const lldb::tid_t tid = packet.GetHexMaxU32(false, LLDB_INVALID_THREAD_ID); + const lldb::tid_t tid = packet.GetHexMaxU64(false, LLDB_INVALID_THREAD_ID); if (tid == LLDB_INVALID_THREAD_ID) { LLDB_LOGF(log, "GDBRemoteCommunicationServerLLGS::%s failed, could not " @@ -3167,19 +3321,19 @@ GDBRemoteCommunicationServerLLGS::Handle_jThreadsInfo( Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_THREAD)); // Ensure we have a debugged process. - if (!m_debugged_process_up || - (m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID)) + if (!m_current_process || + (m_current_process->GetID() == LLDB_INVALID_PROCESS_ID)) return SendErrorResponse(50); - LLDB_LOG(log, "preparing packet for pid {0}", m_debugged_process_up->GetID()); + LLDB_LOG(log, "preparing packet for pid {0}", m_current_process->GetID()); StreamString response; const bool threads_with_valid_stop_info_only = false; - llvm::Expected threads_info = GetJSONThreadsInfo( - *m_debugged_process_up, threads_with_valid_stop_info_only); + llvm::Expected threads_info = + GetJSONThreadsInfo(*m_current_process, threads_with_valid_stop_info_only); if (!threads_info) { LLDB_LOG_ERROR(log, threads_info.takeError(), "failed to prepare a packet for pid {1}: {0}", - m_debugged_process_up->GetID()); + m_current_process->GetID()); return SendErrorResponse(52); } @@ -3193,8 +3347,8 @@ GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_qWatchpointSupportInfo( StringExtractorGDBRemote &packet) { // Fail if we don't have a current process. - if (!m_debugged_process_up || - m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID) + if (!m_current_process || + m_current_process->GetID() == LLDB_INVALID_PROCESS_ID) return SendErrorResponse(68); packet.SetFilePos(strlen("qWatchpointSupportInfo")); @@ -3203,7 +3357,7 @@ GDBRemoteCommunicationServerLLGS::Handle_qWatchpointSupportInfo( if (packet.GetChar() != ':') return SendErrorResponse(67); - auto hw_debug_cap = m_debugged_process_up->GetHardwareDebugSupportInfo(); + auto hw_debug_cap = m_current_process->GetHardwareDebugSupportInfo(); StreamGDBRemote response; if (hw_debug_cap == llvm::None) @@ -3218,8 +3372,8 @@ GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_qFileLoadAddress( StringExtractorGDBRemote &packet) { // Fail if we don't have a current process. - if (!m_debugged_process_up || - m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID) + if (!m_current_process || + m_current_process->GetID() == LLDB_INVALID_PROCESS_ID) return SendErrorResponse(67); packet.SetFilePos(strlen("qFileLoadAddress:")); @@ -3231,7 +3385,7 @@ GDBRemoteCommunicationServerLLGS::Handle_qFileLoadAddress( lldb::addr_t file_load_address = LLDB_INVALID_ADDRESS; Status error = - m_debugged_process_up->GetFileLoadAddress(file_name, file_load_address); + m_current_process->GetFileLoadAddress(file_name, file_load_address); if (error.Fail()) return SendErrorResponse(69); @@ -3267,16 +3421,189 @@ GDBRemoteCommunicationServerLLGS::Handle_QPassSignals( } // Fail if we don't have a current process. - if (!m_debugged_process_up) + if (!m_current_process) return SendErrorResponse(68); - Status error = m_debugged_process_up->IgnoreSignals(signals); + Status error = m_current_process->IgnoreSignals(signals); if (error.Fail()) return SendErrorResponse(69); return SendOKResponse(); } +GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationServerLLGS::Handle_qMemTags( + StringExtractorGDBRemote &packet) { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + + // Ensure we have a process. + if (!m_current_process || + (m_current_process->GetID() == LLDB_INVALID_PROCESS_ID)) { + LLDB_LOGF( + log, + "GDBRemoteCommunicationServerLLGS::%s failed, no process available", + __FUNCTION__); + return SendErrorResponse(1); + } + + // We are expecting + // qMemTags:,: + + // Address + packet.SetFilePos(strlen("qMemTags:")); + const char *current_char = packet.Peek(); + if (!current_char || *current_char == ',') + return SendIllFormedResponse(packet, "Missing address in qMemTags packet"); + const lldb::addr_t addr = packet.GetHexMaxU64(/*little_endian=*/false, 0); + + // Length + char previous_char = packet.GetChar(); + current_char = packet.Peek(); + // If we don't have a separator or the length field is empty + if (previous_char != ',' || (current_char && *current_char == ':')) + return SendIllFormedResponse(packet, + "Invalid addr,length pair in qMemTags packet"); + + if (packet.GetBytesLeft() < 1) + return SendIllFormedResponse( + packet, "Too short qMemtags: packet (looking for length)"); + const size_t length = packet.GetHexMaxU64(/*little_endian=*/false, 0); + + // Type + const char *invalid_type_err = "Invalid type field in qMemTags: packet"; + if (packet.GetBytesLeft() < 1 || packet.GetChar() != ':') + return SendIllFormedResponse(packet, invalid_type_err); + + // Type is a signed integer but packed into the packet as its raw bytes. + // However, our GetU64 uses strtoull which allows +/-. We do not want this. + const char *first_type_char = packet.Peek(); + if (first_type_char && (*first_type_char == '+' || *first_type_char == '-')) + return SendIllFormedResponse(packet, invalid_type_err); + + // Extract type as unsigned then cast to signed. + // Using a uint64_t here so that we have some value outside of the 32 bit + // range to use as the invalid return value. + uint64_t raw_type = + packet.GetU64(std::numeric_limits::max(), /*base=*/16); + + if ( // Make sure the cast below would be valid + raw_type > std::numeric_limits::max() || + // To catch inputs like "123aardvark" that will parse but clearly aren't + // valid in this case. + packet.GetBytesLeft()) { + return SendIllFormedResponse(packet, invalid_type_err); + } + + // First narrow to 32 bits otherwise the copy into type would take + // the wrong 4 bytes on big endian. + uint32_t raw_type_32 = raw_type; + int32_t type = reinterpret_cast(raw_type_32); + + StreamGDBRemote response; + std::vector tags; + Status error = m_current_process->ReadMemoryTags(type, addr, length, tags); + if (error.Fail()) + return SendErrorResponse(1); + + // This m is here in case we want to support multi part replies in the future. + // In the same manner as qfThreadInfo/qsThreadInfo. + response.PutChar('m'); + response.PutBytesAsRawHex8(tags.data(), tags.size()); + return SendPacketNoLock(response.GetString()); +} + +GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationServerLLGS::Handle_QMemTags( + StringExtractorGDBRemote &packet) { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + + // Ensure we have a process. + if (!m_current_process || + (m_current_process->GetID() == LLDB_INVALID_PROCESS_ID)) { + LLDB_LOGF( + log, + "GDBRemoteCommunicationServerLLGS::%s failed, no process available", + __FUNCTION__); + return SendErrorResponse(1); + } + + // We are expecting + // QMemTags:,:: + + // Address + packet.SetFilePos(strlen("QMemTags:")); + const char *current_char = packet.Peek(); + if (!current_char || *current_char == ',') + return SendIllFormedResponse(packet, "Missing address in QMemTags packet"); + const lldb::addr_t addr = packet.GetHexMaxU64(/*little_endian=*/false, 0); + + // Length + char previous_char = packet.GetChar(); + current_char = packet.Peek(); + // If we don't have a separator or the length field is empty + if (previous_char != ',' || (current_char && *current_char == ':')) + return SendIllFormedResponse(packet, + "Invalid addr,length pair in QMemTags packet"); + + if (packet.GetBytesLeft() < 1) + return SendIllFormedResponse( + packet, "Too short QMemtags: packet (looking for length)"); + const size_t length = packet.GetHexMaxU64(/*little_endian=*/false, 0); + + // Type + const char *invalid_type_err = "Invalid type field in QMemTags: packet"; + if (packet.GetBytesLeft() < 1 || packet.GetChar() != ':') + return SendIllFormedResponse(packet, invalid_type_err); + + // Our GetU64 uses strtoull which allows leading +/-, we don't want that. + const char *first_type_char = packet.Peek(); + if (first_type_char && (*first_type_char == '+' || *first_type_char == '-')) + return SendIllFormedResponse(packet, invalid_type_err); + + // The type is a signed integer but is in the packet as its raw bytes. + // So parse first as unsigned then cast to signed later. + // We extract to 64 bit, even though we only expect 32, so that we've + // got some invalid value we can check for. + uint64_t raw_type = + packet.GetU64(std::numeric_limits::max(), /*base=*/16); + if (raw_type > std::numeric_limits::max()) + return SendIllFormedResponse(packet, invalid_type_err); + + // First narrow to 32 bits. Otherwise the copy below would get the wrong + // 4 bytes on big endian. + uint32_t raw_type_32 = raw_type; + int32_t type = reinterpret_cast(raw_type_32); + + // Tag data + if (packet.GetBytesLeft() < 1 || packet.GetChar() != ':') + return SendIllFormedResponse(packet, + "Missing tag data in QMemTags: packet"); + + // Must be 2 chars per byte + const char *invalid_data_err = "Invalid tag data in QMemTags: packet"; + if (packet.GetBytesLeft() % 2) + return SendIllFormedResponse(packet, invalid_data_err); + + // This is bytes here and is unpacked into target specific tags later + // We cannot assume that number of bytes == length here because the server + // can repeat tags to fill a given range. + std::vector tag_data; + // Zero length writes will not have any tag data + // (but we pass them on because it will still check that tagging is enabled) + if (packet.GetBytesLeft()) { + size_t byte_count = packet.GetBytesLeft() / 2; + tag_data.resize(byte_count); + size_t converted_bytes = packet.GetHexBytes(tag_data, 0); + if (converted_bytes != byte_count) { + return SendIllFormedResponse(packet, invalid_data_err); + } + } + + Status status = + m_current_process->WriteMemoryTags(type, addr, length, tag_data); + return status.Success() ? SendOKResponse() : SendErrorResponse(1); +} + void GDBRemoteCommunicationServerLLGS::MaybeCloseInferiorTerminalConnection() { Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); @@ -3305,8 +3632,8 @@ void GDBRemoteCommunicationServerLLGS::MaybeCloseInferiorTerminalConnection() { NativeThreadProtocol *GDBRemoteCommunicationServerLLGS::GetThreadFromSuffix( StringExtractorGDBRemote &packet) { // We have no thread if we don't have a process. - if (!m_debugged_process_up || - m_debugged_process_up->GetID() == LLDB_INVALID_PROCESS_ID) + if (!m_current_process || + m_current_process->GetID() == LLDB_INVALID_PROCESS_ID) return nullptr; // If the client hasn't asked for thread suffix support, there will not be a @@ -3317,9 +3644,9 @@ NativeThreadProtocol *GDBRemoteCommunicationServerLLGS::GetThreadFromSuffix( return nullptr; else if (current_tid == 0) { // Pick a thread. - return m_debugged_process_up->GetThreadAtIndex(0); + return m_current_process->GetThreadAtIndex(0); } else - return m_debugged_process_up->GetThreadByID(current_tid); + return m_current_process->GetThreadByID(current_tid); } Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD)); @@ -3349,7 +3676,7 @@ NativeThreadProtocol *GDBRemoteCommunicationServerLLGS::GetThreadFromSuffix( packet.SetFilePos(packet.GetFilePos() + strlen("thread:")); const lldb::tid_t tid = packet.GetHexMaxU64(false, 0); if (tid != 0) - return m_debugged_process_up->GetThreadByID(tid); + return m_current_process->GetThreadByID(tid); return nullptr; } @@ -3359,9 +3686,9 @@ lldb::tid_t GDBRemoteCommunicationServerLLGS::GetCurrentThreadID() const { // Use whatever the debug process says is the current thread id since the // protocol either didn't specify or specified we want any/all threads // marked as the current thread. - if (!m_debugged_process_up) + if (!m_current_process) return LLDB_INVALID_THREAD_ID; - return m_debugged_process_up->GetCurrentThreadID(); + return m_current_process->GetCurrentThreadID(); } // Use the specific current thread id set by the gdb remote protocol. return m_current_tid; @@ -3382,9 +3709,9 @@ void GDBRemoteCommunicationServerLLGS::ClearProcessSpecificData() { FileSpec GDBRemoteCommunicationServerLLGS::FindModuleFile(const std::string &module_path, const ArchSpec &arch) { - if (m_debugged_process_up) { + if (m_current_process) { FileSpec file_spec; - if (m_debugged_process_up + if (m_current_process ->GetLoadedModuleFileSpec(module_path.c_str(), file_spec) .Success()) { if (FileSystem::Instance().Exists(file_spec)) @@ -3419,3 +3746,93 @@ std::string GDBRemoteCommunicationServerLLGS::XMLEncodeAttributeValue( } return result; } + +llvm::Expected GDBRemoteCommunicationServerLLGS::ReadTid( + StringExtractorGDBRemote &packet, bool allow_all, lldb::pid_t default_pid) { + assert(m_current_process); + assert(m_current_process->GetID() != LLDB_INVALID_PROCESS_ID); + + auto pid_tid = packet.GetPidTid(default_pid); + if (!pid_tid) + return llvm::make_error(inconvertibleErrorCode(), + "Malformed thread-id"); + + lldb::pid_t pid = pid_tid->first; + lldb::tid_t tid = pid_tid->second; + + if (!allow_all && pid == StringExtractorGDBRemote::AllProcesses) + return llvm::make_error( + inconvertibleErrorCode(), + llvm::formatv("PID value {0} not allowed", pid == 0 ? 0 : -1)); + + if (!allow_all && tid == StringExtractorGDBRemote::AllThreads) + return llvm::make_error( + inconvertibleErrorCode(), + llvm::formatv("TID value {0} not allowed", tid == 0 ? 0 : -1)); + + if (pid != StringExtractorGDBRemote::AllProcesses) { + if (pid != m_current_process->GetID()) + return llvm::make_error( + inconvertibleErrorCode(), llvm::formatv("PID {0} not debugged", pid)); + } + + return tid; +} + +std::vector GDBRemoteCommunicationServerLLGS::HandleFeatures( + const llvm::ArrayRef client_features) { + std::vector ret = + GDBRemoteCommunicationServerCommon::HandleFeatures(client_features); + ret.insert(ret.end(), { + "QThreadSuffixSupported+", + "QListThreadsInStopReply+", + "qXfer:features:read+", + }); + + // report server-only features + using Extension = NativeProcessProtocol::Extension; + Extension plugin_features = m_process_factory.GetSupportedExtensions(); + if (bool(plugin_features & Extension::pass_signals)) + ret.push_back("QPassSignals+"); + if (bool(plugin_features & Extension::auxv)) + ret.push_back("qXfer:auxv:read+"); + if (bool(plugin_features & Extension::libraries_svr4)) + ret.push_back("qXfer:libraries-svr4:read+"); + if (bool(plugin_features & Extension::memory_tagging)) + ret.push_back("memory-tagging+"); + + // check for client features + m_extensions_supported = {}; + for (llvm::StringRef x : client_features) + m_extensions_supported |= + llvm::StringSwitch(x) + .Case("multiprocess+", Extension::multiprocess) + .Case("fork-events+", Extension::fork) + .Case("vfork-events+", Extension::vfork) + .Default({}); + + m_extensions_supported &= plugin_features; + + // fork & vfork require multiprocess + if (!bool(m_extensions_supported & Extension::multiprocess)) + m_extensions_supported &= ~(Extension::fork | Extension::vfork); + + // report only if actually supported + if (bool(m_extensions_supported & Extension::multiprocess)) + ret.push_back("multiprocess+"); + if (bool(m_extensions_supported & Extension::fork)) + ret.push_back("fork-events+"); + if (bool(m_extensions_supported & Extension::vfork)) + ret.push_back("vfork-events+"); + + for (auto &x : m_debugged_processes) + SetEnabledExtensions(*x.second); + return ret; +} + +void GDBRemoteCommunicationServerLLGS::SetEnabledExtensions( + NativeProcessProtocol &process) { + NativeProcessProtocol::Extension flags = m_extensions_supported; + assert(!bool(flags & ~m_process_factory.GetSupportedExtensions())); + process.SetEnabledExtensions(flags); +} diff --git a/gnu/llvm/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h b/gnu/llvm/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h index 3ce285910c2..04d0605fe42 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h +++ b/gnu/llvm/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.h @@ -59,6 +59,17 @@ public: /// attach operation. Status AttachToProcess(lldb::pid_t pid); + /// Wait to attach to a process with a given name. + /// + /// This method supports waiting for the next instance of a process + /// with a given name and attaching llgs to that via the configured + /// Platform. + /// + /// \return + /// An Status object indicating the success or failure of the + /// attach operation. + Status AttachWaitProcess(llvm::StringRef process_name, bool include_existing); + // NativeProcessProtocol::NativeDelegate overrides void InitializeDelegate(NativeProcessProtocol *process) override; @@ -67,6 +78,10 @@ public: void DidExec(NativeProcessProtocol *process) override; + void + NewSubprocess(NativeProcessProtocol *parent_process, + std::unique_ptr child_process) override; + Status InitializeConnection(std::unique_ptr connection); protected: @@ -75,8 +90,11 @@ protected: const NativeProcessProtocol::Factory &m_process_factory; lldb::tid_t m_current_tid = LLDB_INVALID_THREAD_ID; lldb::tid_t m_continue_tid = LLDB_INVALID_THREAD_ID; + NativeProcessProtocol *m_current_process; + NativeProcessProtocol *m_continue_process; std::recursive_mutex m_debugged_process_mutex; - std::unique_ptr m_debugged_process_up; + std::unordered_map> + m_debugged_processes; Communication m_stdio_communication; MainLoop::ReadHandleUP m_stdio_handle_up; @@ -87,6 +105,10 @@ protected: std::unordered_map m_saved_registers_map; uint32_t m_next_saved_registers_id = 1; bool m_handshake_completed = false; + bool m_thread_suffix_supported = false; + bool m_list_threads_in_stop_reply = false; + + NativeProcessProtocol::Extension m_extensions_supported = {}; PacketResult SendONotification(const char *buffer, uint32_t len); @@ -108,6 +130,10 @@ protected: PacketResult Handle_qGetWorkingDir(StringExtractorGDBRemote &packet); + PacketResult Handle_QThreadSuffixSupported(StringExtractorGDBRemote &packet); + + PacketResult Handle_QListThreadsInStopReply(StringExtractorGDBRemote &packet); + PacketResult Handle_C(StringExtractorGDBRemote &packet); PacketResult Handle_c(StringExtractorGDBRemote &packet); @@ -138,6 +164,8 @@ protected: PacketResult Handle_memory_read(StringExtractorGDBRemote &packet); PacketResult Handle_M(StringExtractorGDBRemote &packet); + PacketResult Handle__M(StringExtractorGDBRemote &packet); + PacketResult Handle__m(StringExtractorGDBRemote &packet); PacketResult Handle_qMemoryRegionInfoSupported(StringExtractorGDBRemote &packet); @@ -154,18 +182,26 @@ protected: PacketResult Handle_QSaveRegisterState(StringExtractorGDBRemote &packet); - PacketResult Handle_jTraceStart(StringExtractorGDBRemote &packet); + PacketResult Handle_jLLDBTraceSupported(StringExtractorGDBRemote &packet); + + PacketResult Handle_jLLDBTraceStart(StringExtractorGDBRemote &packet); - PacketResult Handle_jTraceRead(StringExtractorGDBRemote &packet); + PacketResult Handle_jLLDBTraceStop(StringExtractorGDBRemote &packet); - PacketResult Handle_jTraceStop(StringExtractorGDBRemote &packet); + PacketResult Handle_jLLDBTraceGetState(StringExtractorGDBRemote &packet); - PacketResult Handle_jTraceConfigRead(StringExtractorGDBRemote &packet); + PacketResult Handle_jLLDBTraceGetBinaryData(StringExtractorGDBRemote &packet); PacketResult Handle_QRestoreRegisterState(StringExtractorGDBRemote &packet); PacketResult Handle_vAttach(StringExtractorGDBRemote &packet); + PacketResult Handle_vAttachWait(StringExtractorGDBRemote &packet); + + PacketResult Handle_qVAttachOrWaitSupported(StringExtractorGDBRemote &packet); + + PacketResult Handle_vAttachOrWait(StringExtractorGDBRemote &packet); + PacketResult Handle_D(StringExtractorGDBRemote &packet); PacketResult Handle_qThreadStopInfo(StringExtractorGDBRemote &packet); @@ -180,6 +216,10 @@ protected: PacketResult Handle_g(StringExtractorGDBRemote &packet); + PacketResult Handle_qMemTags(StringExtractorGDBRemote &packet); + + PacketResult Handle_QMemTags(StringExtractorGDBRemote &packet); + void SetCurrentThreadID(lldb::tid_t tid); lldb::tid_t GetCurrentThreadID() const; @@ -198,6 +238,9 @@ protected: static std::string XMLEncodeAttributeValue(llvm::StringRef value); + virtual std::vector HandleFeatures( + const llvm::ArrayRef client_features) override; + private: llvm::Expected> BuildTargetXml(); @@ -223,6 +266,18 @@ private: void StopSTDIOForwarding(); + // Read thread-id from packet. If the thread-id is correct, returns it. + // Otherwise, returns the error. + // + // If allow_all is true, then the pid/tid value of -1 ('all') will be allowed. + // In any case, the function assumes that exactly one inferior is being + // debugged and rejects pid values that do no match that inferior. + llvm::Expected ReadTid(StringExtractorGDBRemote &packet, + bool allow_all, lldb::pid_t default_pid); + + // Call SetEnabledExtensions() with appropriate flags on the process. + void SetEnabledExtensions(NativeProcessProtocol &process); + // For GDBRemoteCommunicationServerLLGS only GDBRemoteCommunicationServerLLGS(const GDBRemoteCommunicationServerLLGS &) = delete; diff --git a/gnu/llvm/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp b/gnu/llvm/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp index d14b79a03d1..7c2f80dc76b 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp +++ b/gnu/llvm/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp @@ -8,7 +8,7 @@ #include "GDBRemoteCommunicationServerPlatform.h" -#include +#include #include #include @@ -26,12 +26,14 @@ #include "lldb/Host/FileAction.h" #include "lldb/Host/Host.h" #include "lldb/Host/HostInfo.h" +#include "lldb/Interpreter/CommandCompletions.h" #include "lldb/Target/Platform.h" #include "lldb/Target/UnixSignals.h" #include "lldb/Utility/GDBRemote.h" #include "lldb/Utility/Log.h" #include "lldb/Utility/StreamString.h" #include "lldb/Utility/StructuredData.h" +#include "lldb/Utility/TildeExpressionResolver.h" #include "lldb/Utility/UriParser.h" #include "lldb/Utility/StringExtractorGDBRemote.h" @@ -40,6 +42,69 @@ using namespace lldb; using namespace lldb_private::process_gdb_remote; using namespace lldb_private; +GDBRemoteCommunicationServerPlatform::PortMap::PortMap(uint16_t min_port, + uint16_t max_port) { + for (; min_port < max_port; ++min_port) + m_port_map[min_port] = LLDB_INVALID_PROCESS_ID; +} + +void GDBRemoteCommunicationServerPlatform::PortMap::AllowPort(uint16_t port) { + // Do not modify existing mappings + m_port_map.insert({port, LLDB_INVALID_PROCESS_ID}); +} + +llvm::Expected +GDBRemoteCommunicationServerPlatform::PortMap::GetNextAvailablePort() { + if (m_port_map.empty()) + return 0; // Bind to port zero and get a port, we didn't have any + // limitations + + for (auto &pair : m_port_map) { + if (pair.second == LLDB_INVALID_PROCESS_ID) { + pair.second = ~(lldb::pid_t)LLDB_INVALID_PROCESS_ID; + return pair.first; + } + } + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "No free port found in port map"); +} + +bool GDBRemoteCommunicationServerPlatform::PortMap::AssociatePortWithProcess( + uint16_t port, lldb::pid_t pid) { + auto pos = m_port_map.find(port); + if (pos != m_port_map.end()) { + pos->second = pid; + return true; + } + return false; +} + +bool GDBRemoteCommunicationServerPlatform::PortMap::FreePort(uint16_t port) { + std::map::iterator pos = m_port_map.find(port); + if (pos != m_port_map.end()) { + pos->second = LLDB_INVALID_PROCESS_ID; + return true; + } + return false; +} + +bool GDBRemoteCommunicationServerPlatform::PortMap::FreePortForProcess( + lldb::pid_t pid) { + if (!m_port_map.empty()) { + for (auto &pair : m_port_map) { + if (pair.second == pid) { + pair.second = LLDB_INVALID_PROCESS_ID; + return true; + } + } + } + return false; +} + +bool GDBRemoteCommunicationServerPlatform::PortMap::empty() const { + return m_port_map.empty(); +} + // GDBRemoteCommunicationServerPlatform constructor GDBRemoteCommunicationServerPlatform::GDBRemoteCommunicationServerPlatform( const Socket::SocketProtocol socket_protocol, const char *socket_scheme) @@ -68,6 +133,9 @@ GDBRemoteCommunicationServerPlatform::GDBRemoteCommunicationServerPlatform( RegisterMemberFunctionHandler( StringExtractorGDBRemote::eServerPacketType_qProcessInfo, &GDBRemoteCommunicationServerPlatform::Handle_qProcessInfo); + RegisterMemberFunctionHandler( + StringExtractorGDBRemote::eServerPacketType_qPathComplete, + &GDBRemoteCommunicationServerPlatform::Handle_qPathComplete); RegisterMemberFunctionHandler( StringExtractorGDBRemote::eServerPacketType_QSetWorkingDir, &GDBRemoteCommunicationServerPlatform::Handle_QSetWorkingDir); @@ -85,13 +153,19 @@ GDBRemoteCommunicationServerPlatform::GDBRemoteCommunicationServerPlatform( } // Destructor -GDBRemoteCommunicationServerPlatform::~GDBRemoteCommunicationServerPlatform() {} +GDBRemoteCommunicationServerPlatform::~GDBRemoteCommunicationServerPlatform() = + default; Status GDBRemoteCommunicationServerPlatform::LaunchGDBServer( const lldb_private::Args &args, std::string hostname, lldb::pid_t &pid, - uint16_t &port, std::string &socket_name) { - if (port == UINT16_MAX) - port = GetNextAvailablePort(); + llvm::Optional &port, std::string &socket_name) { + if (!port) { + llvm::Expected available_port = m_port_map.GetNextAvailablePort(); + if (available_port) + port = *available_port; + else + return Status(available_port.takeError()); + } // Spawn a new thread to accept the port that gets bound after binding to // port 0 (zero). @@ -106,7 +180,7 @@ Status GDBRemoteCommunicationServerPlatform::LaunchGDBServer( Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM)); LLDB_LOGF(log, "Launching debugserver with: %s:%u...", hostname.c_str(), - port); + *port); // Do not run in a new session so that it can not linger after the platform // closes. @@ -121,7 +195,7 @@ Status GDBRemoteCommunicationServerPlatform::LaunchGDBServer( #if !defined(__APPLE__) url << m_socket_scheme << "://"; #endif - uint16_t *port_ptr = &port; + uint16_t *port_ptr = port.getPointer(); if (m_socket_protocol == Socket::ProtocolTcp) { llvm::StringRef platform_scheme; llvm::StringRef platform_ip; @@ -132,7 +206,7 @@ Status GDBRemoteCommunicationServerPlatform::LaunchGDBServer( platform_port, platform_path); UNUSED_IF_ASSERT_DISABLED(ok); assert(ok); - url << platform_ip.str() << ":" << port; + url << '[' << platform_ip.str() << "]:" << *port; } else { socket_name = GetDomainSocketPath("gdbserver").GetPath(); url << socket_name; @@ -146,11 +220,11 @@ Status GDBRemoteCommunicationServerPlatform::LaunchGDBServer( if (pid != LLDB_INVALID_PROCESS_ID) { std::lock_guard guard(m_spawned_pids_mutex); m_spawned_pids.insert(pid); - if (port > 0) - AssociatePortWithProcess(port, pid); + if (*port > 0) + m_port_map.AssociatePortWithProcess(*port, pid); } else { - if (port > 0) - FreePort(port); + if (*port > 0) + m_port_map.FreePort(*port); } return error; } @@ -170,12 +244,15 @@ GDBRemoteCommunicationServerPlatform::Handle_qLaunchGDBServer( packet.SetFilePos(::strlen("qLaunchGDBServer;")); llvm::StringRef name; llvm::StringRef value; - uint16_t port = UINT16_MAX; + llvm::Optional port; while (packet.GetNameColonValue(name, value)) { if (name.equals("host")) hostname = std::string(value); - else if (name.equals("port")) - value.getAsInteger(0, port); + else if (name.equals("port")) { + // Make the Optional valid so we can use its value + port = 0; + value.getAsInteger(0, port.getValue()); + } } lldb::pid_t debugserver_pid = LLDB_INVALID_PROCESS_ID; @@ -196,8 +273,9 @@ GDBRemoteCommunicationServerPlatform::Handle_qLaunchGDBServer( __FUNCTION__, debugserver_pid); StreamGDBRemote response; + assert(port); response.Printf("pid:%" PRIu64 ";port:%u;", debugserver_pid, - port + m_port_offset); + *port + m_port_offset); if (!socket_name.empty()) { response.PutCString("socket_name:"); response.PutStringAsRawHex8(socket_name); @@ -333,6 +411,38 @@ GDBRemoteCommunicationServerPlatform::Handle_qProcessInfo( return SendPacketNoLock(response.GetString()); } +GDBRemoteCommunication::PacketResult +GDBRemoteCommunicationServerPlatform::Handle_qPathComplete( + StringExtractorGDBRemote &packet) { + packet.SetFilePos(::strlen("qPathComplete:")); + const bool only_dir = (packet.GetHexMaxU32(false, 0) == 1); + if (packet.GetChar() != ',') + return SendErrorResponse(85); + std::string path; + packet.GetHexByteString(path); + + StringList matches; + StandardTildeExpressionResolver resolver; + if (only_dir) + CommandCompletions::DiskDirectories(path, matches, resolver); + else + CommandCompletions::DiskFiles(path, matches, resolver); + + StreamString response; + response.PutChar('M'); + llvm::StringRef separator; + std::sort(matches.begin(), matches.end()); + for (const auto &match : matches) { + response << separator; + separator = ","; + // encode result strings into hex bytes to avoid unexpected error caused by + // special characters like '$'. + response.PutStringAsRawHex8(match.c_str()); + } + + return SendPacketNoLock(response.GetString()); +} + GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerPlatform::Handle_qGetWorkingDir( StringExtractorGDBRemote &packet) { @@ -416,7 +526,7 @@ GDBRemoteCommunicationServerPlatform::Handle_jSignalsInfo( bool GDBRemoteCommunicationServerPlatform::DebugserverProcessReaped( lldb::pid_t pid) { std::lock_guard guard(m_spawned_pids_mutex); - FreePortForProcess(pid); + m_port_map.FreePortForProcess(pid); m_spawned_pids.erase(pid); return true; } @@ -462,51 +572,6 @@ void GDBRemoteCommunicationServerPlatform::SetPortMap(PortMap &&port_map) { m_port_map = port_map; } -uint16_t GDBRemoteCommunicationServerPlatform::GetNextAvailablePort() { - if (m_port_map.empty()) - return 0; // Bind to port zero and get a port, we didn't have any - // limitations - - for (auto &pair : m_port_map) { - if (pair.second == LLDB_INVALID_PROCESS_ID) { - pair.second = ~(lldb::pid_t)LLDB_INVALID_PROCESS_ID; - return pair.first; - } - } - return UINT16_MAX; -} - -bool GDBRemoteCommunicationServerPlatform::AssociatePortWithProcess( - uint16_t port, lldb::pid_t pid) { - PortMap::iterator pos = m_port_map.find(port); - if (pos != m_port_map.end()) { - pos->second = pid; - return true; - } - return false; -} - -bool GDBRemoteCommunicationServerPlatform::FreePort(uint16_t port) { - PortMap::iterator pos = m_port_map.find(port); - if (pos != m_port_map.end()) { - pos->second = LLDB_INVALID_PROCESS_ID; - return true; - } - return false; -} - -bool GDBRemoteCommunicationServerPlatform::FreePortForProcess(lldb::pid_t pid) { - if (!m_port_map.empty()) { - for (auto &pair : m_port_map) { - if (pair.second == pid) { - pair.second = LLDB_INVALID_PROCESS_ID; - return true; - } - } - } - return false; -} - const FileSpec &GDBRemoteCommunicationServerPlatform::GetDomainSocketDir() { static FileSpec g_domainsocket_dir; static llvm::once_flag g_once_flag; diff --git a/gnu/llvm/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h b/gnu/llvm/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h index a8cacea7883..6b964da4a27 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h +++ b/gnu/llvm/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h @@ -16,13 +16,61 @@ #include "GDBRemoteCommunicationServerCommon.h" #include "lldb/Host/Socket.h" +#include "llvm/ADT/Optional.h" +#include "llvm/Support/Error.h" + namespace lldb_private { namespace process_gdb_remote { class GDBRemoteCommunicationServerPlatform : public GDBRemoteCommunicationServerCommon { public: - typedef std::map PortMap; + class PortMap { + public: + // This class is used to restrict the range of ports that + // platform created debugserver/gdbserver processes will + // communicate on. + + // Construct an empty map, where empty means any port is allowed. + PortMap() = default; + + // Make a port map with a range of free ports + // from min_port to max_port-1. + PortMap(uint16_t min_port, uint16_t max_port); + + // Add a port to the map. If it is already in the map do not modify + // its mapping. (used ports remain used, new ports start as free) + void AllowPort(uint16_t port); + + // If we are using a port map where we can only use certain ports, + // get the next available port. + // + // If we are using a port map and we are out of ports, return an error. + // + // If we aren't using a port map, return 0 to indicate we should bind to + // port 0 and then figure out which port we used. + llvm::Expected GetNextAvailablePort(); + + // Tie a port to a process ID. Returns false if the port is not in the port + // map. If the port is already in use it will be moved to the given pid. + // FIXME: This is and GetNextAvailablePort make create a race condition if + // the portmap is shared between processes. + bool AssociatePortWithProcess(uint16_t port, lldb::pid_t pid); + + // Free the given port. Returns false if the port is not in the map. + bool FreePort(uint16_t port); + + // Free the port associated with the given pid. Returns false if there is + // no port associated with the pid. + bool FreePortForProcess(lldb::pid_t pid); + + // Returns true if there are no ports in the map, regardless of the state + // of those ports. Meaning a map with 1 used port is not empty. + bool empty() const; + + private: + std::map m_port_map; + }; GDBRemoteCommunicationServerPlatform( const Socket::SocketProtocol socket_protocol, const char *socket_scheme); @@ -35,27 +83,14 @@ public: // a port chosen by the OS. void SetPortMap(PortMap &&port_map); - // If we are using a port map where we can only use certain ports, - // get the next available port. - // - // If we are using a port map and we are out of ports, return UINT16_MAX - // - // If we aren't using a port map, return 0 to indicate we should bind to - // port 0 and then figure out which port we used. - uint16_t GetNextAvailablePort(); - - bool AssociatePortWithProcess(uint16_t port, lldb::pid_t pid); - - bool FreePort(uint16_t port); - - bool FreePortForProcess(lldb::pid_t pid); - void SetPortOffset(uint16_t port_offset); void SetInferiorArguments(const lldb_private::Args &args); + // Set port if you want to use a specific port number. + // Otherwise port will be set to the port that was chosen for you. Status LaunchGDBServer(const lldb_private::Args &args, std::string hostname, - lldb::pid_t &pid, uint16_t &port, + lldb::pid_t &pid, llvm::Optional &port, std::string &socket_name); void SetPendingGdbServer(lldb::pid_t pid, uint16_t port, @@ -81,6 +116,8 @@ protected: PacketResult Handle_qKillSpawnedProcess(StringExtractorGDBRemote &packet); + PacketResult Handle_qPathComplete(StringExtractorGDBRemote &packet); + PacketResult Handle_qProcessInfo(StringExtractorGDBRemote &packet); PacketResult Handle_qGetWorkingDir(StringExtractorGDBRemote &packet); diff --git a/gnu/llvm/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp b/gnu/llvm/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp index 1f31b45d0fa..65cf9fb2a83 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp +++ b/gnu/llvm/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp @@ -31,43 +31,45 @@ using namespace lldb_private::process_gdb_remote; // GDBRemoteRegisterContext constructor GDBRemoteRegisterContext::GDBRemoteRegisterContext( ThreadGDBRemote &thread, uint32_t concrete_frame_idx, - GDBRemoteDynamicRegisterInfo ®_info, bool read_all_at_once, + GDBRemoteDynamicRegisterInfoSP reg_info_sp, bool read_all_at_once, bool write_all_at_once) - : RegisterContext(thread, concrete_frame_idx), m_reg_info(reg_info), - m_reg_valid(), m_reg_data(), m_read_all_at_once(read_all_at_once), - m_write_all_at_once(write_all_at_once) { + : RegisterContext(thread, concrete_frame_idx), + m_reg_info_sp(std::move(reg_info_sp)), m_reg_valid(), m_reg_data(), + m_read_all_at_once(read_all_at_once), + m_write_all_at_once(write_all_at_once), m_gpacket_cached(false) { // Resize our vector of bools to contain one bool for every register. We will // use these boolean values to know when a register value is valid in // m_reg_data. - m_reg_valid.resize(reg_info.GetNumRegisters()); + m_reg_valid.resize(m_reg_info_sp->GetNumRegisters()); // Make a heap based buffer that is big enough to store all registers DataBufferSP reg_data_sp( - new DataBufferHeap(reg_info.GetRegisterDataByteSize(), 0)); + new DataBufferHeap(m_reg_info_sp->GetRegisterDataByteSize(), 0)); m_reg_data.SetData(reg_data_sp); m_reg_data.SetByteOrder(thread.GetProcess()->GetByteOrder()); } // Destructor -GDBRemoteRegisterContext::~GDBRemoteRegisterContext() {} +GDBRemoteRegisterContext::~GDBRemoteRegisterContext() = default; void GDBRemoteRegisterContext::InvalidateAllRegisters() { SetAllRegisterValid(false); } void GDBRemoteRegisterContext::SetAllRegisterValid(bool b) { + m_gpacket_cached = b; std::vector::iterator pos, end = m_reg_valid.end(); for (pos = m_reg_valid.begin(); pos != end; ++pos) *pos = b; } size_t GDBRemoteRegisterContext::GetRegisterCount() { - return m_reg_info.GetNumRegisters(); + return m_reg_info_sp->GetNumRegisters(); } const RegisterInfo * GDBRemoteRegisterContext::GetRegisterInfoAtIndex(size_t reg) { - RegisterInfo *reg_info = m_reg_info.GetRegisterInfoAtIndex(reg); + RegisterInfo *reg_info = m_reg_info_sp->GetRegisterInfoAtIndex(reg); if (reg_info && reg_info->dynamic_size_dwarf_expr_bytes) { const ArchSpec &arch = m_thread.GetProcess()->GetTarget().GetArchitecture(); @@ -78,11 +80,11 @@ GDBRemoteRegisterContext::GetRegisterInfoAtIndex(size_t reg) { } size_t GDBRemoteRegisterContext::GetRegisterSetCount() { - return m_reg_info.GetNumRegisterSets(); + return m_reg_info_sp->GetNumRegisterSets(); } const RegisterSet *GDBRemoteRegisterContext::GetRegisterSet(size_t reg_set) { - return m_reg_info.GetRegisterSet(reg_set); + return m_reg_info_sp->GetRegisterSet(reg_set); } bool GDBRemoteRegisterContext::ReadRegister(const RegisterInfo *reg_info, @@ -199,7 +201,7 @@ bool GDBRemoteRegisterContext::ReadRegisterBytes(const RegisterInfo *reg_info, const uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; if (!GetRegisterIsValid(reg)) { - if (m_read_all_at_once) { + if (m_read_all_at_once && !m_gpacket_cached) { if (DataBufferSP buffer_sp = gdb_comm.ReadAllRegisters(m_thread.GetProtocolID())) { memcpy(const_cast(m_reg_data.GetDataStart()), @@ -209,17 +211,21 @@ bool GDBRemoteRegisterContext::ReadRegisterBytes(const RegisterInfo *reg_info, SetAllRegisterValid(true); return true; } else if (buffer_sp->GetByteSize() > 0) { - const int regcount = m_reg_info.GetNumRegisters(); + const int regcount = m_reg_info_sp->GetNumRegisters(); for (int i = 0; i < regcount; i++) { - struct RegisterInfo *reginfo = m_reg_info.GetRegisterInfoAtIndex(i); - if (reginfo->byte_offset + reginfo->byte_size - <= buffer_sp->GetByteSize()) { + struct RegisterInfo *reginfo = + m_reg_info_sp->GetRegisterInfoAtIndex(i); + if (reginfo->byte_offset + reginfo->byte_size <= + buffer_sp->GetByteSize()) { m_reg_valid[i] = true; } else { m_reg_valid[i] = false; } } - return true; + + m_gpacket_cached = true; + if (GetRegisterIsValid(reg)) + return true; } else { Log *log(ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet(GDBR_LOG_THREAD | GDBR_LOG_PACKETS)); @@ -231,9 +237,9 @@ bool GDBRemoteRegisterContext::ReadRegisterBytes(const RegisterInfo *reg_info, " bytes " "but only got %" PRId64 " bytes.", m_reg_data.GetByteSize(), buffer_sp->GetByteSize()); + return false; } } - return false; } if (reg_info->value_regs) { // Process this composite register request by delegating to the @@ -247,7 +253,8 @@ bool GDBRemoteRegisterContext::ReadRegisterBytes(const RegisterInfo *reg_info, break; // We have a valid primordial register as our constituent. Grab the // corresponding register info. - const RegisterInfo *prim_reg_info = GetRegisterInfoAtIndex(prim_reg); + const RegisterInfo *prim_reg_info = + GetRegisterInfo(eRegisterKindProcessPlugin, prim_reg); if (prim_reg_info == nullptr) success = false; else { @@ -342,13 +349,22 @@ bool GDBRemoteRegisterContext::WriteRegisterBytes(const RegisterInfo *reg_info, if (dst == nullptr) return false; + // Code below is specific to AArch64 target in SVE state + // If vector granule (vg) register is being written then thread's + // register context reconfiguration is triggered on success. + bool do_reconfigure_arm64_sve = false; + const ArchSpec &arch = process->GetTarget().GetArchitecture(); + if (arch.IsValid() && arch.GetTriple().isAArch64()) + if (strcmp(reg_info->name, "vg") == 0) + do_reconfigure_arm64_sve = true; + if (data.CopyByteOrderedData(data_offset, // src offset reg_info->byte_size, // src length dst, // dst reg_info->byte_size, // dst length m_reg_data.GetByteOrder())) // dst byte order { - GDBRemoteClientBase::Lock lock(gdb_comm, false); + GDBRemoteClientBase::Lock lock(gdb_comm); if (lock) { if (m_write_all_at_once) { // Invalidate all register values @@ -361,6 +377,10 @@ bool GDBRemoteRegisterContext::WriteRegisterBytes(const RegisterInfo *reg_info, { SetAllRegisterValid(false); + + if (do_reconfigure_arm64_sve) + AArch64SVEReconfigure(); + return true; } } else { @@ -380,7 +400,8 @@ bool GDBRemoteRegisterContext::WriteRegisterBytes(const RegisterInfo *reg_info, break; // We have a valid primordial register as our constituent. Grab the // corresponding register info. - const RegisterInfo *value_reg_info = GetRegisterInfoAtIndex(reg); + const RegisterInfo *value_reg_info = + GetRegisterInfo(eRegisterKindProcessPlugin, reg); if (value_reg_info == nullptr) success = false; else @@ -389,6 +410,9 @@ bool GDBRemoteRegisterContext::WriteRegisterBytes(const RegisterInfo *reg_info, } else { // This is an actual register, write it success = SetPrimordialRegister(reg_info, gdb_comm); + + if (success && do_reconfigure_arm64_sve) + AArch64SVEReconfigure(); } // Check if writing this register will invalidate any other register @@ -396,9 +420,10 @@ bool GDBRemoteRegisterContext::WriteRegisterBytes(const RegisterInfo *reg_info, if (reg_info->invalidate_regs) { for (uint32_t idx = 0, reg = reg_info->invalidate_regs[0]; reg != LLDB_INVALID_REGNUM; - reg = reg_info->invalidate_regs[++idx]) { - SetRegisterIsValid(reg, false); - } + reg = reg_info->invalidate_regs[++idx]) + SetRegisterIsValid(ConvertRegisterKindToRegisterNumber( + eRegisterKindProcessPlugin, reg), + false); } return success; @@ -483,7 +508,7 @@ bool GDBRemoteRegisterContext::ReadAllRegisterValues( const bool use_g_packet = !gdb_comm.AvoidGPackets((ProcessGDBRemote *)process); - GDBRemoteClientBase::Lock lock(gdb_comm, false); + GDBRemoteClientBase::Lock lock(gdb_comm); if (lock) { if (gdb_comm.SyncThreadState(m_thread.GetProtocolID())) InvalidateAllRegisters(); @@ -506,7 +531,7 @@ bool GDBRemoteRegisterContext::ReadAllRegisterValues( // m_reg_data buffer } data_sp = std::make_shared( - m_reg_data.GetDataStart(), m_reg_info.GetRegisterDataByteSize()); + m_reg_data.GetDataStart(), m_reg_info_sp->GetRegisterDataByteSize()); return true; } else { @@ -549,7 +574,7 @@ bool GDBRemoteRegisterContext::WriteAllRegisterValues( const bool use_g_packet = !gdb_comm.AvoidGPackets((ProcessGDBRemote *)process); - GDBRemoteClientBase::Lock lock(gdb_comm, false); + GDBRemoteClientBase::Lock lock(gdb_comm); if (lock) { // The data_sp contains the G response packet. if (use_g_packet) { @@ -654,9 +679,8 @@ bool GDBRemoteRegisterContext::WriteAllRegisterValues( if (m_thread.GetProcess().get()) { const ArchSpec &arch = m_thread.GetProcess()->GetTarget().GetArchitecture(); - if (arch.IsValid() && - (arch.GetMachine() == llvm::Triple::aarch64 || - arch.GetMachine() == llvm::Triple::aarch64_32) && + if (arch.IsValid() && (arch.GetMachine() == llvm::Triple::aarch64 || + arch.GetMachine() == llvm::Triple::aarch64_32) && arch.GetTriple().getVendor() == llvm::Triple::Apple && arch.GetTriple().getOS() == llvm::Triple::IOS) { arm64_debugserver = true; @@ -708,7 +732,63 @@ bool GDBRemoteRegisterContext::WriteAllRegisterValues( uint32_t GDBRemoteRegisterContext::ConvertRegisterKindToRegisterNumber( lldb::RegisterKind kind, uint32_t num) { - return m_reg_info.ConvertRegisterKindToRegisterNumber(kind, num); + return m_reg_info_sp->ConvertRegisterKindToRegisterNumber(kind, num); +} + +bool GDBRemoteRegisterContext::AArch64SVEReconfigure() { + if (!m_reg_info_sp) + return false; + + const RegisterInfo *reg_info = m_reg_info_sp->GetRegisterInfo("vg"); + if (!reg_info) + return false; + + uint64_t fail_value = LLDB_INVALID_ADDRESS; + uint32_t vg_reg_num = reg_info->kinds[eRegisterKindLLDB]; + uint64_t vg_reg_value = ReadRegisterAsUnsigned(vg_reg_num, fail_value); + + if (vg_reg_value != fail_value && vg_reg_value <= 32) { + const RegisterInfo *reg_info = m_reg_info_sp->GetRegisterInfo("p0"); + if (!reg_info || vg_reg_value == reg_info->byte_size) + return false; + + if (m_reg_info_sp->UpdateARM64SVERegistersInfos(vg_reg_value)) { + // Make a heap based buffer that is big enough to store all registers + m_reg_data.SetData(std::make_shared( + m_reg_info_sp->GetRegisterDataByteSize(), 0)); + m_reg_data.SetByteOrder(GetByteOrder()); + + InvalidateAllRegisters(); + + return true; + } + } + + return false; +} + +bool GDBRemoteDynamicRegisterInfo::UpdateARM64SVERegistersInfos(uint64_t vg) { + // SVE Z register size is vg x 8 bytes. + uint32_t z_reg_byte_size = vg * 8; + + // SVE vector length has changed, accordingly set size of Z, P and FFR + // registers. Also invalidate register offsets it will be recalculated + // after SVE register size update. + for (auto ® : m_regs) { + if (reg.value_regs == nullptr) { + if (reg.name[0] == 'z' && isdigit(reg.name[1])) + reg.byte_size = z_reg_byte_size; + else if (reg.name[0] == 'p' && isdigit(reg.name[1])) + reg.byte_size = vg; + else if (strcmp(reg.name, "ffr") == 0) + reg.byte_size = vg; + } + reg.byte_offset = LLDB_INVALID_INDEX32; + } + + // Re-calculate register offsets + ConfigureOffsets(); + return true; } void GDBRemoteDynamicRegisterInfo::HardcodeARMRegisters(bool from_scratch) { diff --git a/gnu/llvm/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h b/gnu/llvm/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h index 01586258710..18fcb73b981 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h +++ b/gnu/llvm/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h @@ -27,20 +27,25 @@ namespace process_gdb_remote { class ThreadGDBRemote; class ProcessGDBRemote; +class GDBRemoteDynamicRegisterInfo; -class GDBRemoteDynamicRegisterInfo : public DynamicRegisterInfo { +typedef std::shared_ptr + GDBRemoteDynamicRegisterInfoSP; + +class GDBRemoteDynamicRegisterInfo final : public DynamicRegisterInfo { public: GDBRemoteDynamicRegisterInfo() : DynamicRegisterInfo() {} ~GDBRemoteDynamicRegisterInfo() override = default; void HardcodeARMRegisters(bool from_scratch); + bool UpdateARM64SVERegistersInfos(uint64_t vg); }; class GDBRemoteRegisterContext : public RegisterContext { public: GDBRemoteRegisterContext(ThreadGDBRemote &thread, uint32_t concrete_frame_idx, - GDBRemoteDynamicRegisterInfo ®_info, + GDBRemoteDynamicRegisterInfoSP reg_info_sp, bool read_all_at_once, bool write_all_at_once); ~GDBRemoteRegisterContext() override; @@ -73,6 +78,8 @@ public: uint32_t ConvertRegisterKindToRegisterNumber(lldb::RegisterKind kind, uint32_t num) override; + bool AArch64SVEReconfigure(); + protected: friend class ThreadGDBRemote; @@ -106,11 +113,12 @@ protected: m_reg_valid[reg] = valid; } - GDBRemoteDynamicRegisterInfo &m_reg_info; + GDBRemoteDynamicRegisterInfoSP m_reg_info_sp; std::vector m_reg_valid; DataExtractor m_reg_data; bool m_read_all_at_once; bool m_write_all_at_once; + bool m_gpacket_cached; private: // Helper function for ReadRegisterBytes(). diff --git a/gnu/llvm/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/gnu/llvm/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp index 1fed8e06426..6914b37348e 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp +++ b/gnu/llvm/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp @@ -8,8 +8,8 @@ #include "lldb/Host/Config.h" -#include -#include +#include +#include #if LLDB_ENABLE_POSIX #include #include @@ -20,8 +20,8 @@ #if defined(__APPLE__) #include #endif +#include #include -#include #include #include @@ -135,7 +135,7 @@ public: m_collection_sp->Initialize(g_processgdbremote_properties); } - ~PluginProperties() override {} + ~PluginProperties() override = default; uint64_t GetPacketTimeout() { const uint32_t idx = ePropertyPacketTimeout; @@ -205,13 +205,18 @@ void ProcessGDBRemote::Terminate() { lldb::ProcessSP ProcessGDBRemote::CreateInstance(lldb::TargetSP target_sp, ListenerSP listener_sp, - const FileSpec *crash_file_path) { + const FileSpec *crash_file_path, + bool can_connect) { lldb::ProcessSP process_sp; if (crash_file_path == nullptr) process_sp = std::make_shared(target_sp, listener_sp); return process_sp; } +std::chrono::seconds ProcessGDBRemote::GetPacketTimeout() { + return std::chrono::seconds(GetGlobalPluginProperties()->GetPacketTimeout()); +} + bool ProcessGDBRemote::CanDebug(lldb::TargetSP target_sp, bool plugin_specified_by_name) { if (plugin_specified_by_name) @@ -248,7 +253,7 @@ ProcessGDBRemote::ProcessGDBRemote(lldb::TargetSP target_sp, ListenerSP listener_sp) : Process(target_sp, listener_sp), m_debugserver_pid(LLDB_INVALID_PROCESS_ID), m_last_stop_packet_mutex(), - m_register_info(), + m_register_info_sp(nullptr), m_async_broadcaster(nullptr, "lldb.process.gdb-remote.async-broadcaster"), m_async_listener_sp( Listener::MakeListener("lldb.process.gdb-remote.async-listener")), @@ -367,8 +372,8 @@ bool ProcessGDBRemote::ParsePythonTargetDefinition( m_breakpoint_pc_offset = breakpoint_pc_int_value->GetValue(); } - if (m_register_info.SetRegisterInfo(*target_definition_sp, - GetTarget().GetArchitecture()) > 0) { + if (m_register_info_sp->SetRegisterInfo( + *target_definition_sp, GetTarget().GetArchitecture()) > 0) { return true; } } @@ -395,10 +400,10 @@ static size_t SplitCommaSeparatedRegisterNumberString( } void ProcessGDBRemote::BuildDynamicRegisterInfo(bool force) { - if (!force && m_register_info.GetNumRegisters() > 0) + if (!force && m_register_info_sp) return; - m_register_info.Clear(); + m_register_info_sp = std::make_shared(); // Check if qHostInfo specified a specific packet timeout for this // connection. If so then lets update our setting so the user knows what the @@ -450,7 +455,7 @@ void ProcessGDBRemote::BuildDynamicRegisterInfo(bool force) { return; char packet[128]; - uint32_t reg_offset = 0; + uint32_t reg_offset = LLDB_INVALID_INDEX32; uint32_t reg_num = 0; for (StringExtractorGDBRemote::ResponseType response_type = StringExtractorGDBRemote::eResponse; @@ -460,7 +465,7 @@ void ProcessGDBRemote::BuildDynamicRegisterInfo(bool force) { assert(packet_len < (int)sizeof(packet)); UNUSED_IF_ASSERT_DISABLED(packet_len); StringExtractorGDBRemote response; - if (m_gdb_comm.SendPacketAndWaitForResponse(packet, response, false) == + if (m_gdb_comm.SendPacketAndWaitForResponse(packet, response) == GDBRemoteCommunication::PacketResult::Success) { response_type = response.GetResponseType(); if (response_type == StringExtractorGDBRemote::eResponse) { @@ -563,7 +568,7 @@ void ProcessGDBRemote::BuildDynamicRegisterInfo(bool force) { reg_info.byte_offset = reg_offset; assert(reg_info.byte_size != 0); - reg_offset += reg_info.byte_size; + reg_offset = LLDB_INVALID_INDEX32; if (!value_regs.empty()) { value_regs.push_back(LLDB_INVALID_REGNUM); reg_info.value_regs = value_regs.data(); @@ -580,7 +585,7 @@ void ProcessGDBRemote::BuildDynamicRegisterInfo(bool force) { if (ABISP abi_sp = ABI::FindPlugin(shared_from_this(), arch_to_use)) abi_sp->AugmentRegisterInfo(reg_info); - m_register_info.AddRegister(reg_info, reg_name, alt_name, set_name); + m_register_info_sp->AddRegister(reg_info, reg_name, alt_name, set_name); } else { break; // ensure exit before reg_num is incremented } @@ -589,8 +594,8 @@ void ProcessGDBRemote::BuildDynamicRegisterInfo(bool force) { } } - if (m_register_info.GetNumRegisters() > 0) { - m_register_info.Finalize(GetTarget().GetArchitecture()); + if (m_register_info_sp->GetNumRegisters() > 0) { + m_register_info_sp->Finalize(GetTarget().GetArchitecture()); return; } @@ -599,21 +604,21 @@ void ProcessGDBRemote::BuildDynamicRegisterInfo(bool force) { // updated debugserver down on the devices. On the other hand, if the // accumulated reg_num is positive, see if we can add composite registers to // the existing primordial ones. - bool from_scratch = (m_register_info.GetNumRegisters() == 0); + bool from_scratch = (m_register_info_sp->GetNumRegisters() == 0); if (!target_arch.IsValid()) { if (arch_to_use.IsValid() && (arch_to_use.GetMachine() == llvm::Triple::arm || arch_to_use.GetMachine() == llvm::Triple::thumb) && arch_to_use.GetTriple().getVendor() == llvm::Triple::Apple) - m_register_info.HardcodeARMRegisters(from_scratch); + m_register_info_sp->HardcodeARMRegisters(from_scratch); } else if (target_arch.GetMachine() == llvm::Triple::arm || target_arch.GetMachine() == llvm::Triple::thumb) { - m_register_info.HardcodeARMRegisters(from_scratch); + m_register_info_sp->HardcodeARMRegisters(from_scratch); } // At this point, we can finalize our register info. - m_register_info.Finalize(GetTarget().GetArchitecture()); + m_register_info_sp->Finalize(GetTarget().GetArchitecture()); } Status ProcessGDBRemote::WillLaunch(lldb_private::Module *module) { @@ -817,8 +822,8 @@ Status ProcessGDBRemote::DoLaunch(lldb_private::Module *exe_module, // since 'O' packets can really slow down debugging if the inferior // does a lot of output. if ((!stdin_file_spec || !stdout_file_spec || !stderr_file_spec) && - pty.OpenFirstAvailablePrimary(O_RDWR | O_NOCTTY, nullptr, 0)) { - FileSpec secondary_name{pty.GetSecondaryName(nullptr, 0)}; + !errorToBool(pty.OpenFirstAvailablePrimary(O_RDWR | O_NOCTTY))) { + FileSpec secondary_name(pty.GetSecondaryName()); if (!stdin_file_spec) stdin_file_spec = secondary_name; @@ -1010,7 +1015,7 @@ Status ProcessGDBRemote::ConnectToDebugserver(llvm::StringRef connect_url) { for (size_t idx = 0; idx < num_cmds; idx++) { StringExtractorGDBRemote response; m_gdb_comm.SendPacketAndWaitForResponse( - GetExtraStartupCommands().GetArgumentAtIndex(idx), response, false); + GetExtraStartupCommands().GetArgumentAtIndex(idx), response); } return error; } @@ -1037,6 +1042,12 @@ void ProcessGDBRemote::DidLaunchOrAttach(ArchSpec &process_arch) { process_arch.GetTriple().getTriple()); } + if (int addresssable_bits = m_gdb_comm.GetAddressingBits()) { + lldb::addr_t address_mask = ~((1ULL << addresssable_bits) - 1); + SetCodeAddressMask(address_mask); + SetDataAddressMask(address_mask); + } + if (process_arch.IsValid()) { const ArchSpec &target_arch = GetTarget().GetArchitecture(); if (target_arch.IsValid()) { @@ -1198,30 +1209,26 @@ Status ProcessGDBRemote::DoAttachToProcessWithName( return error; } -lldb::user_id_t ProcessGDBRemote::StartTrace(const TraceOptions &options, - Status &error) { - return m_gdb_comm.SendStartTracePacket(options, error); +llvm::Expected ProcessGDBRemote::TraceSupported() { + return m_gdb_comm.SendTraceSupported(GetInterruptTimeout()); } -Status ProcessGDBRemote::StopTrace(lldb::user_id_t uid, lldb::tid_t thread_id) { - return m_gdb_comm.SendStopTracePacket(uid, thread_id); +llvm::Error ProcessGDBRemote::TraceStop(const TraceStopRequest &request) { + return m_gdb_comm.SendTraceStop(request, GetInterruptTimeout()); } -Status ProcessGDBRemote::GetData(lldb::user_id_t uid, lldb::tid_t thread_id, - llvm::MutableArrayRef &buffer, - size_t offset) { - return m_gdb_comm.SendGetDataPacket(uid, thread_id, buffer, offset); +llvm::Error ProcessGDBRemote::TraceStart(const llvm::json::Value &request) { + return m_gdb_comm.SendTraceStart(request, GetInterruptTimeout()); } -Status ProcessGDBRemote::GetMetaData(lldb::user_id_t uid, lldb::tid_t thread_id, - llvm::MutableArrayRef &buffer, - size_t offset) { - return m_gdb_comm.SendGetMetaDataPacket(uid, thread_id, buffer, offset); +llvm::Expected +ProcessGDBRemote::TraceGetState(llvm::StringRef type) { + return m_gdb_comm.SendTraceGetState(type, GetInterruptTimeout()); } -Status ProcessGDBRemote::GetTraceConfig(lldb::user_id_t uid, - TraceOptions &options) { - return m_gdb_comm.SendGetTraceConfigPacket(uid, options); +llvm::Expected> +ProcessGDBRemote::TraceGetBinaryData(const TraceGetBinaryDataRequest &request) { + return m_gdb_comm.SendTraceGetBinaryData(request, GetInterruptTimeout()); } void ProcessGDBRemote::DidExit() { @@ -1466,7 +1473,7 @@ void ProcessGDBRemote::HandleStopReplySequence() { while (true) { // Send vStopped StringExtractorGDBRemote response; - m_gdb_comm.SendPacketAndWaitForResponse("vStopped", response, false); + m_gdb_comm.SendPacketAndWaitForResponse("vStopped", response); // OK represents end of signal list if (response.IsOKResponse()) @@ -1486,22 +1493,22 @@ void ProcessGDBRemote::ClearThreadIDList() { m_thread_pcs.clear(); } -size_t -ProcessGDBRemote::UpdateThreadIDsFromStopReplyThreadsValue(std::string &value) { +size_t ProcessGDBRemote::UpdateThreadIDsFromStopReplyThreadsValue( + llvm::StringRef value) { m_thread_ids.clear(); - size_t comma_pos; - lldb::tid_t tid; - while ((comma_pos = value.find(',')) != std::string::npos) { - value[comma_pos] = '\0'; - // thread in big endian hex - tid = StringConvert::ToUInt64(value.c_str(), LLDB_INVALID_THREAD_ID, 16); - if (tid != LLDB_INVALID_THREAD_ID) - m_thread_ids.push_back(tid); - value.erase(0, comma_pos + 1); - } - tid = StringConvert::ToUInt64(value.c_str(), LLDB_INVALID_THREAD_ID, 16); - if (tid != LLDB_INVALID_THREAD_ID) - m_thread_ids.push_back(tid); + lldb::pid_t pid = m_gdb_comm.GetCurrentProcessID(); + StringExtractorGDBRemote thread_ids{value}; + + do { + auto pid_tid = thread_ids.GetPidTid(pid); + if (pid_tid && pid_tid->first == pid) { + lldb::tid_t tid = pid_tid->second; + if (tid != LLDB_INVALID_THREAD_ID && + tid != StringExtractorGDBRemote::AllProcesses) + m_thread_ids.push_back(tid); + } + } while (thread_ids.GetChar() == ','); + return m_thread_ids.size(); } @@ -1518,7 +1525,7 @@ ProcessGDBRemote::UpdateThreadPCsFromStopReplyThreadsValue(std::string &value) { value.erase(0, comma_pos + 1); } pc = StringConvert::ToUInt64(value.c_str(), LLDB_INVALID_ADDRESS, 16); - if (pc != LLDB_INVALID_THREAD_ID) + if (pc != LLDB_INVALID_ADDRESS) m_thread_pcs.push_back(pc); return m_thread_pcs.size(); } @@ -1597,8 +1604,8 @@ bool ProcessGDBRemote::UpdateThreadIDList() { return true; } -bool ProcessGDBRemote::UpdateThreadList(ThreadList &old_thread_list, - ThreadList &new_thread_list) { +bool ProcessGDBRemote::DoUpdateThreadList(ThreadList &old_thread_list, + ThreadList &new_thread_list) { // locker will keep a mutex locked until it goes out of scope Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_THREAD)); LLDB_LOGV(log, "pid = {0}", GetID()); @@ -1743,7 +1750,9 @@ ThreadSP ProcessGDBRemote::SetThreadStopInfo( if (thread_sp) { ThreadGDBRemote *gdb_thread = static_cast(thread_sp.get()); - gdb_thread->GetRegisterContext()->InvalidateIfNeeded(true); + RegisterContextSP gdb_reg_ctx_sp(gdb_thread->GetRegisterContext()); + + gdb_reg_ctx_sp->InvalidateIfNeeded(true); auto iter = std::find(m_thread_ids.begin(), m_thread_ids.end(), tid); if (iter != m_thread_ids.end()) { @@ -1755,7 +1764,23 @@ ThreadSP ProcessGDBRemote::SetThreadStopInfo( DataBufferSP buffer_sp(new DataBufferHeap( reg_value_extractor.GetStringRef().size() / 2, 0)); reg_value_extractor.GetHexBytes(buffer_sp->GetData(), '\xcc'); - gdb_thread->PrivateSetRegisterValue(pair.first, buffer_sp->GetData()); + uint32_t lldb_regnum = + gdb_reg_ctx_sp->ConvertRegisterKindToRegisterNumber( + eRegisterKindProcessPlugin, pair.first); + gdb_thread->PrivateSetRegisterValue(lldb_regnum, buffer_sp->GetData()); + } + + // AArch64 SVE specific code below calls AArch64SVEReconfigure to update + // SVE register sizes and offsets if value of VG register has changed + // since last stop. + const ArchSpec &arch = GetTarget().GetArchitecture(); + if (arch.IsValid() && arch.GetTriple().isAArch64()) { + GDBRemoteRegisterContext *reg_ctx_sp = + static_cast( + gdb_thread->GetRegisterContext().get()); + + if (reg_ctx_sp) + reg_ctx_sp->AArch64SVEReconfigure(); } thread_sp->SetName(thread_name.empty() ? nullptr : thread_name.c_str()); @@ -1807,8 +1832,7 @@ ThreadSP ProcessGDBRemote::SetThreadStopInfo( // If the current pc is a breakpoint site then the StopInfo // should be set to Breakpoint Otherwise, it will be set to // Trace. - if (bp_site_sp && - bp_site_sp->ValidForThisThread(thread_sp.get())) { + if (bp_site_sp && bp_site_sp->ValidForThisThread(*thread_sp)) { thread_sp->SetStopInfo( StopInfo::CreateStopReasonWithBreakpointSiteID( *thread_sp, bp_site_sp->GetID())); @@ -1828,7 +1852,7 @@ ThreadSP ProcessGDBRemote::SetThreadStopInfo( // breakpoint here, that will be taken care of when the thread // resumes and notices that there's a breakpoint under the pc. handled = true; - if (bp_site_sp->ValidForThisThread(thread_sp.get())) { + if (bp_site_sp->ValidForThisThread(*thread_sp)) { thread_sp->SetStopInfo( StopInfo::CreateStopReasonWithBreakpointSiteID( *thread_sp, bp_site_sp->GetID())); @@ -1879,6 +1903,9 @@ ThreadSP ProcessGDBRemote::SetThreadStopInfo( thread_sp->SetStopInfo( StopInfo::CreateStopReasonWithExec(*thread_sp)); handled = true; + } else if (reason == "processor trace") { + thread_sp->SetStopInfo(StopInfo::CreateStopReasonProcessorTrace( + *thread_sp, description.c_str())); } } else if (!signo) { addr_t pc = thread_sp->GetRegisterContext()->GetPC(); @@ -1891,7 +1918,7 @@ ThreadSP ProcessGDBRemote::SetThreadStopInfo( // as such. This can happen when the thread is involuntarily // interrupted (e.g. due to stops on other threads) just as it is // about to execute the breakpoint instruction. - if (bp_site_sp && bp_site_sp->ValidForThisThread(thread_sp.get())) { + if (bp_site_sp && bp_site_sp->ValidForThisThread(*thread_sp)) { thread_sp->SetStopInfo( StopInfo::CreateStopReasonWithBreakpointSiteID( *thread_sp, bp_site_sp->GetID())); @@ -1916,7 +1943,7 @@ ThreadSP ProcessGDBRemote::SetThreadStopInfo( // reason. We don't need to worry about stepping over the // breakpoint here, that will be taken care of when the thread // resumes and notices that there's a breakpoint under the pc. - if (bp_site_sp->ValidForThisThread(thread_sp.get())) { + if (bp_site_sp->ValidForThisThread(*thread_sp)) { if (m_breakpoint_pc_offset != 0) thread_sp->GetRegisterContext()->SetPC(pc); thread_sp->SetStopInfo( @@ -2119,6 +2146,7 @@ ProcessGDBRemote::SetThreadStopInfo(StructuredData::Dictionary *thread_dict) { } StateType ProcessGDBRemote::SetThreadStopInfo(StringExtractor &stop_packet) { + lldb::pid_t pid = m_gdb_comm.GetCurrentProcessID(); stop_packet.SetFilePos(0); const char stop_type = stop_packet.GetChar(); switch (stop_type) { @@ -2133,14 +2161,12 @@ StateType ProcessGDBRemote::SetThreadStopInfo(StringExtractor &stop_packet) { if (stop_id == 0) { // Our first stop, make sure we have a process ID, and also make sure we // know about our registers - if (GetID() == LLDB_INVALID_PROCESS_ID) { - lldb::pid_t pid = m_gdb_comm.GetCurrentProcessID(); - if (pid != LLDB_INVALID_PROCESS_ID) - SetID(pid); - } + if (GetID() == LLDB_INVALID_PROCESS_ID && pid != LLDB_INVALID_PROCESS_ID) + SetID(pid); BuildDynamicRegisterInfo(true); } // Stop with signal and thread info + lldb::pid_t stop_pid = LLDB_INVALID_PROCESS_ID; lldb::tid_t tid = LLDB_INVALID_THREAD_ID; const uint8_t signo = stop_packet.GetHexU8(); llvm::StringRef key; @@ -2169,24 +2195,18 @@ StateType ProcessGDBRemote::SetThreadStopInfo(StringExtractor &stop_packet) { value.getAsInteger(16, x); exc_data.push_back(x); } else if (key.compare("thread") == 0) { - // thread in big endian hex - if (value.getAsInteger(16, tid)) + // thread-id + StringExtractorGDBRemote thread_id{value}; + auto pid_tid = thread_id.GetPidTid(pid); + if (pid_tid) { + stop_pid = pid_tid->first; + tid = pid_tid->second; + } else tid = LLDB_INVALID_THREAD_ID; } else if (key.compare("threads") == 0) { std::lock_guard guard( m_thread_list_real.GetMutex()); - - m_thread_ids.clear(); - // A comma separated list of all threads in the current - // process that includes the thread for this stop reply packet - lldb::tid_t tid; - while (!value.empty()) { - llvm::StringRef tid_str; - std::tie(tid_str, value) = value.split(','); - if (tid_str.getAsInteger(16, tid)) - tid = LLDB_INVALID_THREAD_ID; - m_thread_ids.push_back(tid); - } + UpdateThreadIDsFromStopReplyThreadsValue(value); } else if (key.compare("thread-pcs") == 0) { m_thread_pcs.clear(); // A comma separated list of all threads in the current @@ -2299,6 +2319,14 @@ StateType ProcessGDBRemote::SetThreadStopInfo(StringExtractor &stop_packet) { } } + if (stop_pid != LLDB_INVALID_PROCESS_ID && stop_pid != pid) { + Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); + LLDB_LOG(log, + "Received stop for incorrect PID = {0} (inferior PID = {1})", + stop_pid, pid); + return eStateInvalid; + } + if (tid == LLDB_INVALID_THREAD_ID) { // A thread id may be invalid if the response is old style 'S' packet // which does not provide the @@ -2386,7 +2414,7 @@ Status ProcessGDBRemote::DoHalt(bool &caused_stop) { // file handle and debugserver will go away, and we can be done... m_gdb_comm.Disconnect(); } else - caused_stop = m_gdb_comm.Interrupt(); + caused_stop = m_gdb_comm.Interrupt(GetInterruptTimeout()); return error; } @@ -2535,11 +2563,11 @@ Status ProcessGDBRemote::DoDestroy() { if (m_gdb_comm.IsConnected()) { if (m_public_state.GetValue() != eStateAttaching) { StringExtractorGDBRemote response; - bool send_async = true; GDBRemoteCommunication::ScopedTimeout(m_gdb_comm, std::chrono::seconds(3)); - if (m_gdb_comm.SendPacketAndWaitForResponse("k", response, send_async) == + if (m_gdb_comm.SendPacketAndWaitForResponse("k", response, + GetInterruptTimeout()) == GDBRemoteCommunication::PacketResult::Success) { char packet_cmd = response.GetChar(0); @@ -2647,7 +2675,7 @@ addr_t ProcessGDBRemote::GetImageInfoAddress() { llvm::Expected list = GetLoadedModuleList(); if (!list) { Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); - LLDB_LOG_ERROR(log, list.takeError(), "Failed to read module list: {0}"); + LLDB_LOG_ERROR(log, list.takeError(), "Failed to read module list: {0}."); } else { addr = list->m_link_map; } @@ -2703,7 +2731,8 @@ size_t ProcessGDBRemote::DoReadMemory(addr_t addr, void *buf, size_t size, assert(packet_len + 1 < (int)sizeof(packet)); UNUSED_IF_ASSERT_DISABLED(packet_len); StringExtractorGDBRemote response; - if (m_gdb_comm.SendPacketAndWaitForResponse(packet, response, true) == + if (m_gdb_comm.SendPacketAndWaitForResponse(packet, response, + GetInterruptTimeout()) == GDBRemoteCommunication::PacketResult::Success) { if (response.IsNormalResponse()) { error.Clear(); @@ -2739,6 +2768,37 @@ size_t ProcessGDBRemote::DoReadMemory(addr_t addr, void *buf, size_t size, return 0; } +bool ProcessGDBRemote::SupportsMemoryTagging() { + return m_gdb_comm.GetMemoryTaggingSupported(); +} + +llvm::Expected> +ProcessGDBRemote::DoReadMemoryTags(lldb::addr_t addr, size_t len, + int32_t type) { + // By this point ReadMemoryTags has validated that tagging is enabled + // for this target/process/address. + DataBufferSP buffer_sp = m_gdb_comm.ReadMemoryTags(addr, len, type); + if (!buffer_sp) { + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "Error reading memory tags from remote"); + } + + // Return the raw tag data + llvm::ArrayRef tag_data = buffer_sp->GetData(); + std::vector got; + got.reserve(tag_data.size()); + std::copy(tag_data.begin(), tag_data.end(), std::back_inserter(got)); + return got; +} + +Status ProcessGDBRemote::DoWriteMemoryTags(lldb::addr_t addr, size_t len, + int32_t type, + const std::vector &tags) { + // By now WriteMemoryTags should have validated that tagging is enabled + // for this target/process. + return m_gdb_comm.WriteMemoryTags(addr, len, type, tags); +} + Status ProcessGDBRemote::WriteObjectFile( std::vector entries) { Status error; @@ -2829,7 +2889,7 @@ Status ProcessGDBRemote::FlashErase(lldb::addr_t addr, size_t size) { StringExtractorGDBRemote response; if (m_gdb_comm.SendPacketAndWaitForResponse(packet.GetString(), response, - true) == + GetInterruptTimeout()) == GDBRemoteCommunication::PacketResult::Success) { if (response.IsOKResponse()) { m_erased_flash_ranges.Insert(range, true); @@ -2858,7 +2918,8 @@ Status ProcessGDBRemote::FlashDone() { if (m_erased_flash_ranges.IsEmpty()) return status; StringExtractorGDBRemote response; - if (m_gdb_comm.SendPacketAndWaitForResponse("vFlashDone", response, true) == + if (m_gdb_comm.SendPacketAndWaitForResponse("vFlashDone", response, + GetInterruptTimeout()) == GDBRemoteCommunication::PacketResult::Success) { if (response.IsOKResponse()) { m_erased_flash_ranges.Clear(); @@ -2919,7 +2980,7 @@ size_t ProcessGDBRemote::DoWriteMemory(addr_t addr, const void *buf, } StringExtractorGDBRemote response; if (m_gdb_comm.SendPacketAndWaitForResponse(packet.GetString(), response, - true) == + GetInterruptTimeout()) == GDBRemoteCommunication::PacketResult::Success) { if (response.IsOKResponse()) { error.Clear(); @@ -3095,7 +3156,7 @@ Status ProcessGDBRemote::EnableBreakpointSite(BreakpointSite *bp_site) { (!bp_site->HardwareRequired())) { // Try to send off a software breakpoint packet ($Z0) uint8_t error_no = m_gdb_comm.SendGDBStoppointTypePacket( - eBreakpointSoftware, true, addr, bp_op_size); + eBreakpointSoftware, true, addr, bp_op_size, GetInterruptTimeout()); if (error_no == 0) { // The breakpoint was placed successfully bp_site->SetEnabled(true); @@ -3135,7 +3196,7 @@ Status ProcessGDBRemote::EnableBreakpointSite(BreakpointSite *bp_site) { if (m_gdb_comm.SupportsGDBStoppointPacket(eBreakpointHardware)) { // Try to send off a hardware breakpoint packet ($Z1) uint8_t error_no = m_gdb_comm.SendGDBStoppointTypePacket( - eBreakpointHardware, true, addr, bp_op_size); + eBreakpointHardware, true, addr, bp_op_size, GetInterruptTimeout()); if (error_no == 0) { // The breakpoint was placed successfully bp_site->SetEnabled(true); @@ -3199,19 +3260,15 @@ Status ProcessGDBRemote::DisableBreakpointSite(BreakpointSite *bp_site) { case BreakpointSite::eHardware: if (m_gdb_comm.SendGDBStoppointTypePacket(eBreakpointHardware, false, - addr, bp_op_size)) + addr, bp_op_size, + GetInterruptTimeout())) error.SetErrorToGenericError(); break; case BreakpointSite::eExternal: { - GDBStoppointType stoppoint_type; - if (bp_site->IsHardware()) - stoppoint_type = eBreakpointHardware; - else - stoppoint_type = eBreakpointSoftware; - - if (m_gdb_comm.SendGDBStoppointTypePacket(stoppoint_type, false, addr, - bp_op_size)) + if (m_gdb_comm.SendGDBStoppointTypePacket(eBreakpointSoftware, false, + addr, bp_op_size, + GetInterruptTimeout())) error.SetErrorToGenericError(); } break; } @@ -3267,7 +3324,8 @@ Status ProcessGDBRemote::EnableWatchpoint(Watchpoint *wp, bool notify) { // Pass down an appropriate z/Z packet... if (m_gdb_comm.SupportsGDBStoppointPacket(type)) { if (m_gdb_comm.SendGDBStoppointTypePacket(type, true, addr, - wp->GetByteSize()) == 0) { + wp->GetByteSize(), + GetInterruptTimeout()) == 0) { wp->SetEnabled(true, notify); return error; } else @@ -3313,7 +3371,8 @@ Status ProcessGDBRemote::DisableWatchpoint(Watchpoint *wp, bool notify) { GDBStoppointType type = GetGDBStoppointType(wp); // Pass down an appropriate z/Z packet... if (m_gdb_comm.SendGDBStoppointTypePacket(type, false, addr, - wp->GetByteSize()) == 0) { + wp->GetByteSize(), + GetInterruptTimeout()) == 0) { wp->SetEnabled(false, notify); return error; } else @@ -3338,7 +3397,7 @@ Status ProcessGDBRemote::DoSignal(int signo) { Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); LLDB_LOGF(log, "ProcessGDBRemote::DoSignal (signal = %d)", signo); - if (!m_gdb_comm.SendAsyncSignal(signo)) + if (!m_gdb_comm.SendAsyncSignal(signo, GetInterruptTimeout())) error.SetErrorStringWithFormat("failed to send signal %i", signo); return error; } @@ -3666,12 +3725,25 @@ thread_result_t ProcessGDBRemote::AsyncThread(void *arg) { __FUNCTION__, arg, process->GetID()); EventSP event_sp; + + // We need to ignore any packets that come in after we have + // have decided the process has exited. There are some + // situations, for instance when we try to interrupt a running + // process and the interrupt fails, where another packet might + // get delivered after we've decided to give up on the process. + // But once we've decided we are done with the process we will + // not be in a state to do anything useful with new packets. + // So it is safer to simply ignore any remaining packets by + // explicitly checking for eStateExited before reentering the + // fetch loop. + bool done = false; - while (!done) { + while (!done && process->GetPrivateState() != eStateExited) { LLDB_LOGF(log, "ProcessGDBRemote::%s (arg = %p, pid = %" PRIu64 ") listener.WaitForEvent (NULL, event_sp)...", __FUNCTION__, arg, process->GetID()); + if (process->m_async_listener_sp->GetEvent(event_sp, llvm::None)) { const uint32_t event_type = event_sp->GetType(); if (event_sp->BroadcasterIs(&process->m_async_broadcaster)) { @@ -3703,7 +3775,7 @@ thread_result_t ProcessGDBRemote::AsyncThread(void *arg) { // send the vCont packet if (!process->GetGDBRemote().SendvContPacket( llvm::StringRef(continue_cstr, continue_cstr_len), - response)) { + process->GetInterruptTimeout(), response)) { // Something went wrong done = true; break; @@ -3715,6 +3787,7 @@ thread_result_t ProcessGDBRemote::AsyncThread(void *arg) { process->GetGDBRemote().SendContinuePacketAndWaitForResponse( *process, *process->GetUnixSignals(), llvm::StringRef(continue_cstr, continue_cstr_len), + process->GetInterruptTimeout(), response); // We need to immediately clear the thread ID list so we are sure @@ -3770,6 +3843,7 @@ thread_result_t ProcessGDBRemote::AsyncThread(void *arg) { } else { process->SetExitStatus(-1, "lost connection"); } + done = true; break; } @@ -4008,8 +4082,7 @@ ProcessGDBRemote::GetExtendedInfoForThread(lldb::tid_t tid) { StringExtractorGDBRemote response; response.SetResponseValidatorToJSON(); - if (m_gdb_comm.SendPacketAndWaitForResponse(packet.GetString(), response, - false) == + if (m_gdb_comm.SendPacketAndWaitForResponse(packet.GetString(), response) == GDBRemoteCommunication::PacketResult::Success) { StringExtractorGDBRemote::ResponseType response_type = response.GetResponseType(); @@ -4081,8 +4154,7 @@ ProcessGDBRemote::GetLoadedDynamicLibrariesInfos_sender( StringExtractorGDBRemote response; response.SetResponseValidatorToJSON(); - if (m_gdb_comm.SendPacketAndWaitForResponse(packet.GetString(), response, - false) == + if (m_gdb_comm.SendPacketAndWaitForResponse(packet.GetString(), response) == GDBRemoteCommunication::PacketResult::Success) { StringExtractorGDBRemote::ResponseType response_type = response.GetResponseType(); @@ -4115,8 +4187,7 @@ StructuredData::ObjectSP ProcessGDBRemote::GetSharedCacheInfo() { StringExtractorGDBRemote response; response.SetResponseValidatorToJSON(); - if (m_gdb_comm.SendPacketAndWaitForResponse(packet.GetString(), response, - false) == + if (m_gdb_comm.SendPacketAndWaitForResponse(packet.GetString(), response) == GDBRemoteCommunication::PacketResult::Success) { StringExtractorGDBRemote::ResponseType response_type = response.GetResponseType(); @@ -4277,14 +4348,14 @@ struct GdbServerTargetInfo { bool ParseRegisters(XMLNode feature_node, GdbServerTargetInfo &target_info, GDBRemoteDynamicRegisterInfo &dyn_reg_info, ABISP abi_sp, - uint32_t &cur_reg_num, uint32_t ®_offset) { + uint32_t ®_num_remote, uint32_t ®_num_local) { if (!feature_node) return false; + uint32_t reg_offset = LLDB_INVALID_INDEX32; feature_node.ForEachChildElementWithName( - "reg", - [&target_info, &dyn_reg_info, &cur_reg_num, ®_offset, - &abi_sp](const XMLNode ®_node) -> bool { + "reg", [&target_info, &dyn_reg_info, ®_num_remote, ®_num_local, + ®_offset, &abi_sp](const XMLNode ®_node) -> bool { std::string gdb_group; std::string gdb_type; ConstString reg_name; @@ -4306,8 +4377,8 @@ bool ParseRegisters(XMLNode feature_node, GdbServerTargetInfo &target_info, LLDB_INVALID_REGNUM, // eh_frame reg num LLDB_INVALID_REGNUM, // DWARF reg num LLDB_INVALID_REGNUM, // generic reg num - cur_reg_num, // process plugin reg num - cur_reg_num // native register number + reg_num_remote, // process plugin reg num + reg_num_local // native register number }, nullptr, nullptr, @@ -4434,7 +4505,7 @@ bool ParseRegisters(XMLNode feature_node, GdbServerTargetInfo &target_info, reg_info.byte_offset = reg_offset; assert(reg_info.byte_size != 0); - reg_offset += reg_info.byte_size; + reg_offset = LLDB_INVALID_INDEX32; if (!value_regs.empty()) { value_regs.push_back(LLDB_INVALID_REGNUM); reg_info.value_regs = value_regs.data(); @@ -4444,7 +4515,8 @@ bool ParseRegisters(XMLNode feature_node, GdbServerTargetInfo &target_info, reg_info.invalidate_regs = invalidate_regs.data(); } - ++cur_reg_num; + reg_num_remote = reg_info.kinds[eRegisterKindProcessPlugin] + 1; + ++reg_num_local; reg_info.name = reg_name.AsCString(); if (abi_sp) abi_sp->AugmentRegisterInfo(reg_info); @@ -4463,8 +4535,8 @@ bool ParseRegisters(XMLNode feature_node, GdbServerTargetInfo &target_info, // for nested register definition files. It returns true if it was able // to fetch and parse an xml file. bool ProcessGDBRemote::GetGDBServerRegisterInfoXMLAndProcess( - ArchSpec &arch_to_use, std::string xml_filename, uint32_t &cur_reg_num, - uint32_t ®_offset) { + ArchSpec &arch_to_use, std::string xml_filename, uint32_t ®_num_remote, + uint32_t ®_num_local) { // request the target xml file std::string raw; lldb_private::Status lldberr; @@ -4567,13 +4639,13 @@ bool ProcessGDBRemote::GetGDBServerRegisterInfoXMLAndProcess( // ABI is also potentially incorrect. ABISP abi_to_use_sp = ABI::FindPlugin(shared_from_this(), arch_to_use); for (auto &feature_node : feature_nodes) { - ParseRegisters(feature_node, target_info, this->m_register_info, - abi_to_use_sp, cur_reg_num, reg_offset); + ParseRegisters(feature_node, target_info, *this->m_register_info_sp, + abi_to_use_sp, reg_num_remote, reg_num_local); } for (const auto &include : target_info.includes) { - GetGDBServerRegisterInfoXMLAndProcess(arch_to_use, include, cur_reg_num, - reg_offset); + GetGDBServerRegisterInfoXMLAndProcess(arch_to_use, include, + reg_num_remote, reg_num_local); } } } else { @@ -4593,12 +4665,13 @@ bool ProcessGDBRemote::GetGDBServerRegisterInfo(ArchSpec &arch_to_use) { if (!m_gdb_comm.GetQXferFeaturesReadSupported()) return false; - uint32_t cur_reg_num = 0; - uint32_t reg_offset = 0; - if (GetGDBServerRegisterInfoXMLAndProcess (arch_to_use, "target.xml", cur_reg_num, reg_offset)) - this->m_register_info.Finalize(arch_to_use); + uint32_t reg_num_remote = 0; + uint32_t reg_num_local = 0; + if (GetGDBServerRegisterInfoXMLAndProcess(arch_to_use, "target.xml", + reg_num_remote, reg_num_local)) + this->m_register_info_sp->Finalize(arch_to_use); - return m_register_info.GetNumRegisters() > 0; + return m_register_info_sp->GetNumRegisters() > 0; } llvm::Expected ProcessGDBRemote::GetLoadedModuleList() { @@ -4880,8 +4953,7 @@ Status ProcessGDBRemote::GetFileLoadAddress(const FileSpec &file, packet.PutStringAsRawHex8(file_path); StringExtractorGDBRemote response; - if (m_gdb_comm.SendPacketAndWaitForResponse(packet.GetString(), response, - false) != + if (m_gdb_comm.SendPacketAndWaitForResponse(packet.GetString(), response) != GDBRemoteCommunication::PacketResult::Success) return Status("Sending qFileLoadAddress packet failed"); @@ -5117,7 +5189,7 @@ public: m_option_group.Finalize(); } - ~CommandObjectProcessGDBRemoteSpeedTest() override {} + ~CommandObjectProcessGDBRemoteSpeedTest() override = default; Options *GetOptions() override { return &m_option_group; } @@ -5168,7 +5240,7 @@ public: : CommandObjectParsed(interpreter, "process plugin packet history", "Dumps the packet history buffer. ", nullptr) {} - ~CommandObjectProcessGDBRemotePacketHistory() override {} + ~CommandObjectProcessGDBRemotePacketHistory() override = default; bool DoExecute(Args &command, CommandReturnObject &result) override { const size_t argc = command.GetArgumentCount(); @@ -5199,7 +5271,7 @@ public: "Maximum size that lldb will try to read/write one one chunk.", nullptr) {} - ~CommandObjectProcessGDBRemotePacketXferSize() override {} + ~CommandObjectProcessGDBRemotePacketXferSize() override = default; bool DoExecute(Args &command, CommandReturnObject &result) override { const size_t argc = command.GetArgumentCount(); @@ -5208,7 +5280,6 @@ public: "amount to be transferred when " "reading/writing", m_cmd_name.c_str()); - result.SetStatus(eReturnStatusFailed); return false; } @@ -5241,7 +5312,7 @@ public: "stripped from the result.", nullptr) {} - ~CommandObjectProcessGDBRemotePacketSend() override {} + ~CommandObjectProcessGDBRemotePacketSend() override = default; bool DoExecute(Args &command, CommandReturnObject &result) override { const size_t argc = command.GetArgumentCount(); @@ -5249,7 +5320,6 @@ public: result.AppendErrorWithFormat( "'%s' takes a one or more packet content arguments", m_cmd_name.c_str()); - result.SetStatus(eReturnStatusFailed); return false; } @@ -5258,10 +5328,9 @@ public: if (process) { for (size_t i = 0; i < argc; ++i) { const char *packet_cstr = command.GetArgumentAtIndex(0); - bool send_async = true; StringExtractorGDBRemote response; process->GetGDBRemote().SendPacketAndWaitForResponse( - packet_cstr, response, send_async); + packet_cstr, response, process->GetInterruptTimeout()); result.SetStatus(eReturnStatusSuccessFinishResult); Stream &output_strm = result.GetOutputStream(); output_strm.Printf(" packet: %s\n", packet_cstr); @@ -5292,14 +5361,13 @@ public: "encoded into a valid 'qRcmd' packet, sent and the " "response will be printed.") {} - ~CommandObjectProcessGDBRemotePacketMonitor() override {} + ~CommandObjectProcessGDBRemotePacketMonitor() override = default; bool DoExecute(llvm::StringRef command, CommandReturnObject &result) override { if (command.empty()) { result.AppendErrorWithFormat("'%s' takes a command string argument", m_cmd_name.c_str()); - result.SetStatus(eReturnStatusFailed); return false; } @@ -5310,11 +5378,10 @@ public: packet.PutCString("qRcmd,"); packet.PutBytesAsRawHex8(command.data(), command.size()); - bool send_async = true; StringExtractorGDBRemote response; Stream &output_strm = result.GetOutputStream(); process->GetGDBRemote().SendPacketAndReceiveResponseWithOutputSupport( - packet.GetString(), response, send_async, + packet.GetString(), response, process->GetInterruptTimeout(), [&output_strm](llvm::StringRef output) { output_strm << output; }); result.SetStatus(eReturnStatusSuccessFinishResult); output_strm.Printf(" packet: %s\n", packet.GetData()); @@ -5356,7 +5423,7 @@ public: interpreter))); } - ~CommandObjectProcessGDBRemotePacket() override {} + ~CommandObjectProcessGDBRemotePacket() override = default; }; class CommandObjectMultiwordProcessGDBRemote : public CommandObjectMultiword { @@ -5371,7 +5438,7 @@ public: CommandObjectSP(new CommandObjectProcessGDBRemotePacket(interpreter))); } - ~CommandObjectMultiwordProcessGDBRemote() override {} + ~CommandObjectMultiwordProcessGDBRemote() override = default; }; CommandObject *ProcessGDBRemote::GetPluginCommandObject() { diff --git a/gnu/llvm/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h b/gnu/llvm/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h index ba967727ae3..fe04cdddd0f 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h +++ b/gnu/llvm/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h @@ -55,7 +55,8 @@ public: static lldb::ProcessSP CreateInstance(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp, - const FileSpec *crash_file_path); + const FileSpec *crash_file_path, + bool can_connect); static void Initialize(); @@ -67,6 +68,8 @@ public: static const char *GetPluginDescriptionStatic(); + static std::chrono::seconds GetPacketTimeout(); + // Check if a given Process bool CanDebug(lldb::TargetSP target_sp, bool plugin_specified_by_name) override; @@ -162,20 +165,16 @@ public: Status GetWatchpointSupportInfo(uint32_t &num) override; - lldb::user_id_t StartTrace(const TraceOptions &options, - Status &error) override; + llvm::Expected TraceSupported() override; - Status StopTrace(lldb::user_id_t uid, lldb::tid_t thread_id) override; + llvm::Error TraceStop(const TraceStopRequest &request) override; - Status GetData(lldb::user_id_t uid, lldb::tid_t thread_id, - llvm::MutableArrayRef &buffer, - size_t offset = 0) override; + llvm::Error TraceStart(const llvm::json::Value &request) override; - Status GetMetaData(lldb::user_id_t uid, lldb::tid_t thread_id, - llvm::MutableArrayRef &buffer, - size_t offset = 0) override; + llvm::Expected TraceGetState(llvm::StringRef type) override; - Status GetTraceConfig(lldb::user_id_t uid, TraceOptions &options) override; + llvm::Expected> + TraceGetBinaryData(const TraceGetBinaryDataRequest &request) override; Status GetWatchpointSupportInfo(uint32_t &num, bool &after) override; @@ -236,6 +235,8 @@ protected: friend class GDBRemoteCommunicationClient; friend class GDBRemoteRegisterContext; + bool SupportsMemoryTagging() override; + /// Broadcaster event bits definitions. enum { eBroadcastBitAsyncContinue = (1 << 0), @@ -251,7 +252,7 @@ protected: // the last stop // packet variable std::recursive_mutex m_last_stop_packet_mutex; - GDBRemoteDynamicRegisterInfo m_register_info; + GDBRemoteDynamicRegisterInfoSP m_register_info_sp; Broadcaster m_async_broadcaster; lldb::ListenerSP m_async_listener_sp; HostThread m_async_thread; @@ -309,8 +310,8 @@ protected: void Clear(); - bool UpdateThreadList(ThreadList &old_thread_list, - ThreadList &new_thread_list) override; + bool DoUpdateThreadList(ThreadList &old_thread_list, + ThreadList &new_thread_list) override; Status ConnectToReplayServer(); @@ -336,7 +337,7 @@ protected: size_t UpdateThreadPCsFromStopReplyThreadsValue(std::string &value); - size_t UpdateThreadIDsFromStopReplyThreadsValue(std::string &value); + size_t UpdateThreadIDsFromStopReplyThreadsValue(llvm::StringRef value); bool HandleNotifyPacket(StringExtractorGDBRemote &packet); @@ -388,8 +389,8 @@ protected: bool GetGDBServerRegisterInfoXMLAndProcess(ArchSpec &arch_to_use, std::string xml_filename, - uint32_t &cur_reg_num, - uint32_t ®_offset); + uint32_t &cur_reg_remote, + uint32_t &cur_reg_local); // Query remote GDBServer for register information bool GetGDBServerRegisterInfo(ArchSpec &arch); @@ -407,6 +408,12 @@ protected: bool HasErased(FlashRange range); + llvm::Expected> + DoReadMemoryTags(lldb::addr_t addr, size_t len, int32_t type) override; + + Status DoWriteMemoryTags(lldb::addr_t addr, size_t len, int32_t type, + const std::vector &tags) override; + private: // For ProcessGDBRemote only std::string m_partial_profile_data; diff --git a/gnu/llvm/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp b/gnu/llvm/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp index 6deabf8d5d7..2a9896e4108 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp +++ b/gnu/llvm/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp @@ -42,6 +42,14 @@ ThreadGDBRemote::ThreadGDBRemote(Process &process, lldb::tid_t tid) Log *log(GetLogIfAnyCategoriesSet(GDBR_LOG_THREAD)); LLDB_LOG(log, "this = {0}, pid = {1}, tid = {2}", this, process.GetID(), GetID()); + // At this point we can clone reg_info for architectures supporting + // run-time update to register sizes and offsets.. + auto &gdb_process = static_cast(process); + if (!gdb_process.m_register_info_sp->IsReconfigurable()) + m_reg_info_sp = gdb_process.m_register_info_sp; + else + m_reg_info_sp = std::make_shared( + *gdb_process.m_register_info_sp); } ThreadGDBRemote::~ThreadGDBRemote() { @@ -307,8 +315,8 @@ ThreadGDBRemote::CreateRegisterContextForFrame(StackFrame *frame) { !pSupported || gdb_process->m_use_g_packet_for_reading; bool write_all_registers_at_once = !pSupported; reg_ctx_sp = std::make_shared( - *this, concrete_frame_idx, gdb_process->m_register_info, - read_all_registers_at_once, write_all_registers_at_once); + *this, concrete_frame_idx, m_reg_info_sp, read_all_registers_at_once, + write_all_registers_at_once); } } else { reg_ctx_sp = GetUnwinder().CreateRegisterContextForFrame(frame); diff --git a/gnu/llvm/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h b/gnu/llvm/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h index 5ad11170fec..b7d75021c06 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h +++ b/gnu/llvm/lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h @@ -14,6 +14,8 @@ #include "lldb/Target/Thread.h" #include "lldb/Utility/StructuredData.h" +#include "GDBRemoteRegisterContext.h" + class StringExtractor; namespace lldb_private { @@ -101,6 +103,8 @@ protected: m_queue_serial_number; // Queue info from stop reply/stop info for thread lldb_private::LazyBool m_associated_with_libdispatch_queue; + GDBRemoteDynamicRegisterInfoSP m_reg_info_sp; + bool PrivateSetRegisterValue(uint32_t reg, llvm::ArrayRef data); bool PrivateSetRegisterValue(uint32_t reg, uint64_t regval); diff --git a/gnu/llvm/lldb/source/Plugins/Process/mach-core/ProcessMachCore.cpp b/gnu/llvm/lldb/source/Plugins/Process/mach-core/ProcessMachCore.cpp index b78276d345e..84548edb5ca 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/mach-core/ProcessMachCore.cpp +++ b/gnu/llvm/lldb/source/Plugins/Process/mach-core/ProcessMachCore.cpp @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#include -#include +#include +#include #include "llvm/Support/MathExtras.h" #include "llvm/Support/Threading.h" @@ -21,6 +21,7 @@ #include "lldb/Symbol/LocateSymbolFile.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Target/MemoryRegionInfo.h" +#include "lldb/Target/SectionLoadList.h" #include "lldb/Target/Target.h" #include "lldb/Target/Thread.h" #include "lldb/Utility/DataBuffer.h" @@ -36,6 +37,7 @@ #include "Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.h" #include "Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.h" +#include "Plugins/DynamicLoader/Static/DynamicLoaderStatic.h" #include "Plugins/ObjectFile/Mach-O/ObjectFileMachO.h" #include @@ -61,9 +63,10 @@ void ProcessMachCore::Terminate() { lldb::ProcessSP ProcessMachCore::CreateInstance(lldb::TargetSP target_sp, ListenerSP listener_sp, - const FileSpec *crash_file) { + const FileSpec *crash_file, + bool can_connect) { lldb::ProcessSP process_sp; - if (crash_file) { + if (crash_file && !can_connect) { const size_t header_size = sizeof(llvm::MachO::mach_header); auto data_sp = FileSystem::Instance().CreateDataBuffer( crash_file->GetPath(), header_size, 0); @@ -110,8 +113,8 @@ bool ProcessMachCore::CanDebug(lldb::TargetSP target_sp, ProcessMachCore::ProcessMachCore(lldb::TargetSP target_sp, ListenerSP listener_sp, const FileSpec &core_file) - : Process(target_sp, listener_sp), m_core_aranges(), m_core_range_infos(), - m_core_module_sp(), m_core_file(core_file), + : PostMortemProcess(target_sp, listener_sp), m_core_aranges(), + m_core_range_infos(), m_core_module_sp(), m_core_file(core_file), m_dyld_addr(LLDB_INVALID_ADDRESS), m_mach_kernel_addr(LLDB_INVALID_ADDRESS), m_dyld_plugin_name() {} @@ -187,6 +190,59 @@ bool ProcessMachCore::GetDynamicLoaderAddress(lldb::addr_t addr) { return false; } +// We have a hint about a binary -- a UUID, possibly a load address. +// Try to load a file with that UUID into lldb, and if we have a load +// address, set it correctly. Else assume that the binary was loaded +// with no slide. +static bool load_standalone_binary(UUID uuid, addr_t addr, Target &target) { + if (uuid.IsValid()) { + ModuleSpec module_spec; + module_spec.GetUUID() = uuid; + + // Look up UUID in global module cache before attempting + // dsymForUUID-like action. + ModuleSP module_sp; + Status error = ModuleList::GetSharedModule(module_spec, module_sp, nullptr, + nullptr, nullptr); + + if (!module_sp.get()) { + // Force a a dsymForUUID lookup, if that tool is available. + if (!module_spec.GetSymbolFileSpec()) + Symbols::DownloadObjectAndSymbolFile(module_spec, true); + + if (FileSystem::Instance().Exists(module_spec.GetFileSpec())) { + module_sp = std::make_shared(module_spec); + } + } + + if (module_sp.get() && module_sp->GetObjectFile()) { + target.SetArchitecture(module_sp->GetObjectFile()->GetArchitecture()); + target.GetImages().AppendIfNeeded(module_sp, false); + + Address base_addr = module_sp->GetObjectFile()->GetBaseAddress(); + addr_t slide = 0; + if (addr != LLDB_INVALID_ADDRESS && base_addr.IsValid()) { + addr_t file_load_addr = base_addr.GetFileAddress(); + slide = addr - file_load_addr; + } + bool changed = false; + module_sp->SetLoadAddress(target, slide, true, changed); + + ModuleList added_module; + added_module.Append(module_sp, false); + target.ModulesDidLoad(added_module); + + // Flush info in the process (stack frames, etc). + ProcessSP process_sp(target.GetProcessSP()); + if (process_sp) + process_sp->Flush(); + + return true; + } + } + return false; +} + // Process Control Status ProcessMachCore::DoLoadCore() { Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER | @@ -276,108 +332,93 @@ Status ProcessMachCore::DoLoadCore() { m_core_range_infos.Sort(); } - bool found_main_binary_definitively = false; addr_t objfile_binary_addr; UUID objfile_binary_uuid; - if (core_objfile->GetCorefileMainBinaryInfo (objfile_binary_addr, objfile_binary_uuid)) - { - if (objfile_binary_addr != LLDB_INVALID_ADDRESS) - { + ObjectFile::BinaryType type; + if (core_objfile->GetCorefileMainBinaryInfo(objfile_binary_addr, + objfile_binary_uuid, type)) { + if (log) { + log->Printf( + "ProcessMachCore::DoLoadCore: using binary hint from 'main bin spec' " + "LC_NOTE with UUID %s address 0x%" PRIx64 " and type %d", + objfile_binary_uuid.GetAsString().c_str(), objfile_binary_addr, type); + } + if (objfile_binary_addr != LLDB_INVALID_ADDRESS) { + if (type == ObjectFile::eBinaryTypeUser) { + m_dyld_addr = objfile_binary_addr; + m_dyld_plugin_name = DynamicLoaderMacOSXDYLD::GetPluginNameStatic(); + found_main_binary_definitively = true; + } + if (type == ObjectFile::eBinaryTypeKernel) { m_mach_kernel_addr = objfile_binary_addr; + m_dyld_plugin_name = DynamicLoaderDarwinKernel::GetPluginNameStatic(); found_main_binary_definitively = true; - LLDB_LOGF(log, - "ProcessMachCore::DoLoadCore: using kernel address 0x%" PRIx64 - " from LC_NOTE 'main bin spec' load command.", - m_mach_kernel_addr); + } + } + if (!found_main_binary_definitively) { + // ObjectFile::eBinaryTypeStandalone, undeclared types + if (load_standalone_binary(objfile_binary_uuid, objfile_binary_addr, + GetTarget())) { + found_main_binary_definitively = true; + m_dyld_plugin_name = DynamicLoaderStatic::GetPluginNameStatic(); + } } } - + // This checks for the presence of an LC_IDENT string in a core file; // LC_IDENT is very obsolete and should not be used in new code, but if the // load command is present, let's use the contents. - std::string corefile_identifier = core_objfile->GetIdentifierString(); - if (!found_main_binary_definitively && - corefile_identifier.find("Darwin Kernel") != std::string::npos) { - UUID uuid; - addr_t addr = LLDB_INVALID_ADDRESS; + UUID ident_uuid; + addr_t ident_binary_addr = LLDB_INVALID_ADDRESS; + if (!found_main_binary_definitively) { + std::string corefile_identifier = core_objfile->GetIdentifierString(); + + // Search for UUID= and stext= strings in the identifier str. if (corefile_identifier.find("UUID=") != std::string::npos) { size_t p = corefile_identifier.find("UUID=") + strlen("UUID="); std::string uuid_str = corefile_identifier.substr(p, 36); - uuid.SetFromStringRef(uuid_str); + ident_uuid.SetFromStringRef(uuid_str); + if (log) + log->Printf("Got a UUID from LC_IDENT/kern ver str LC_NOTE: %s", + ident_uuid.GetAsString().c_str()); } if (corefile_identifier.find("stext=") != std::string::npos) { size_t p = corefile_identifier.find("stext=") + strlen("stext="); if (corefile_identifier[p] == '0' && corefile_identifier[p + 1] == 'x') { - errno = 0; - addr = ::strtoul(corefile_identifier.c_str() + p, nullptr, 16); - if (errno != 0 || addr == 0) - addr = LLDB_INVALID_ADDRESS; + ident_binary_addr = + ::strtoul(corefile_identifier.c_str() + p, nullptr, 16); + if (log) + log->Printf("Got a load address from LC_IDENT/kern ver str " + "LC_NOTE: 0x%" PRIx64, + ident_binary_addr); } } - if (uuid.IsValid() && addr != LLDB_INVALID_ADDRESS) { - m_mach_kernel_addr = addr; + + // Search for a "Darwin Kernel" str indicating kernel; else treat as + // standalone + if (corefile_identifier.find("Darwin Kernel") != std::string::npos && + ident_uuid.IsValid() && ident_binary_addr != LLDB_INVALID_ADDRESS) { + if (log) + log->Printf("ProcessMachCore::DoLoadCore: Found kernel binary via " + "LC_IDENT/kern ver str LC_NOTE"); + m_mach_kernel_addr = ident_binary_addr; found_main_binary_definitively = true; - LLDB_LOGF( - log, - "ProcessMachCore::DoLoadCore: Using the kernel address 0x%" PRIx64 - " from LC_IDENT/LC_NOTE 'kern ver str' string: '%s'", - addr, corefile_identifier.c_str()); + } else if (ident_uuid.IsValid()) { + if (load_standalone_binary(ident_uuid, ident_binary_addr, GetTarget())) { + found_main_binary_definitively = true; + m_dyld_plugin_name = DynamicLoaderStatic::GetPluginNameStatic(); + } } } - if (found_main_binary_definitively == false - && corefile_identifier.find("EFI ") != std::string::npos) { - UUID uuid; - if (corefile_identifier.find("UUID=") != std::string::npos) { - size_t p = corefile_identifier.find("UUID=") + strlen("UUID="); - std::string uuid_str = corefile_identifier.substr(p, 36); - uuid.SetFromStringRef(uuid_str); - } - if (uuid.IsValid()) { - LLDB_LOGF(log, - "ProcessMachCore::DoLoadCore: Using the EFI " - "from LC_IDENT/LC_NOTE 'kern ver str' string: '%s'", - corefile_identifier.c_str()); - - // We're only given a UUID here, not a load address. - // But there are python scripts in the EFI binary's dSYM which - // know how to relocate the binary to the correct load address. - // lldb only needs to locate & load the binary + dSYM. - ModuleSpec module_spec; - module_spec.GetUUID() = uuid; - module_spec.GetArchitecture() = GetTarget().GetArchitecture(); - - // Lookup UUID locally, before attempting dsymForUUID like action - FileSpecList search_paths = Target::GetDefaultDebugFileSearchPaths(); - module_spec.GetSymbolFileSpec() = - Symbols::LocateExecutableSymbolFile(module_spec, search_paths); - if (module_spec.GetSymbolFileSpec()) { - ModuleSpec executable_module_spec = - Symbols::LocateExecutableObjectFile(module_spec); - if (FileSystem::Instance().Exists( - executable_module_spec.GetFileSpec())) { - module_spec.GetFileSpec() = executable_module_spec.GetFileSpec(); - } - } - - // Force a a dsymForUUID lookup, if that tool is available. - if (!module_spec.GetSymbolFileSpec()) - Symbols::DownloadObjectAndSymbolFile(module_spec, true); - - if (FileSystem::Instance().Exists(module_spec.GetFileSpec())) { - ModuleSP module_sp(new Module(module_spec)); - if (module_sp.get() && module_sp->GetObjectFile()) { - // Get the current target executable - ModuleSP exe_module_sp(GetTarget().GetExecutableModule()); - - // Make sure you don't already have the right module loaded - // and they will be uniqued - if (exe_module_sp.get() != module_sp.get()) - GetTarget().SetExecutableModule(module_sp, eLoadDependentsNo); - } - } - } + + // If we have a "all image infos" LC_NOTE, try to load all of the + // binaries listed, and set their Section load addresses in the Target. + if (found_main_binary_definitively == false && + core_objfile->LoadCoreFileImages(*this)) { + m_dyld_plugin_name = DynamicLoaderDarwinKernel::GetPluginNameStatic(); + found_main_binary_definitively = true; } if (!found_main_binary_definitively && @@ -440,35 +481,37 @@ Status ProcessMachCore::DoLoadCore() { } } - // If we found both a user-process dyld and a kernel binary, we need to - // decide which to prefer. - if (GetCorefilePreference() == eKernelCorefile) { - if (m_mach_kernel_addr != LLDB_INVALID_ADDRESS) { - LLDB_LOGF(log, - "ProcessMachCore::DoLoadCore: Using kernel corefile image " - "at 0x%" PRIx64, - m_mach_kernel_addr); - m_dyld_plugin_name = DynamicLoaderDarwinKernel::GetPluginNameStatic(); - } else if (m_dyld_addr != LLDB_INVALID_ADDRESS) { - LLDB_LOGF(log, - "ProcessMachCore::DoLoadCore: Using user process dyld " - "image at 0x%" PRIx64, - m_dyld_addr); - m_dyld_plugin_name = DynamicLoaderMacOSXDYLD::GetPluginNameStatic(); - } - } else { - if (m_dyld_addr != LLDB_INVALID_ADDRESS) { - LLDB_LOGF(log, - "ProcessMachCore::DoLoadCore: Using user process dyld " - "image at 0x%" PRIx64, - m_dyld_addr); - m_dyld_plugin_name = DynamicLoaderMacOSXDYLD::GetPluginNameStatic(); - } else if (m_mach_kernel_addr != LLDB_INVALID_ADDRESS) { - LLDB_LOGF(log, - "ProcessMachCore::DoLoadCore: Using kernel corefile image " - "at 0x%" PRIx64, - m_mach_kernel_addr); - m_dyld_plugin_name = DynamicLoaderDarwinKernel::GetPluginNameStatic(); + if (m_dyld_plugin_name.IsEmpty()) { + // If we found both a user-process dyld and a kernel binary, we need to + // decide which to prefer. + if (GetCorefilePreference() == eKernelCorefile) { + if (m_mach_kernel_addr != LLDB_INVALID_ADDRESS) { + LLDB_LOGF(log, + "ProcessMachCore::DoLoadCore: Using kernel corefile image " + "at 0x%" PRIx64, + m_mach_kernel_addr); + m_dyld_plugin_name = DynamicLoaderDarwinKernel::GetPluginNameStatic(); + } else if (m_dyld_addr != LLDB_INVALID_ADDRESS) { + LLDB_LOGF(log, + "ProcessMachCore::DoLoadCore: Using user process dyld " + "image at 0x%" PRIx64, + m_dyld_addr); + m_dyld_plugin_name = DynamicLoaderMacOSXDYLD::GetPluginNameStatic(); + } + } else { + if (m_dyld_addr != LLDB_INVALID_ADDRESS) { + LLDB_LOGF(log, + "ProcessMachCore::DoLoadCore: Using user process dyld " + "image at 0x%" PRIx64, + m_dyld_addr); + m_dyld_plugin_name = DynamicLoaderMacOSXDYLD::GetPluginNameStatic(); + } else if (m_mach_kernel_addr != LLDB_INVALID_ADDRESS) { + LLDB_LOGF(log, + "ProcessMachCore::DoLoadCore: Using kernel corefile image " + "at 0x%" PRIx64, + m_mach_kernel_addr); + m_dyld_plugin_name = DynamicLoaderDarwinKernel::GetPluginNameStatic(); + } } } @@ -498,6 +541,11 @@ Status ProcessMachCore::DoLoadCore() { if (arch.IsValid()) GetTarget().SetArchitecture(arch); + addr_t address_mask = core_objfile->GetAddressMask(); + if (address_mask != 0) { + SetCodeAddressMask(address_mask); + SetDataAddressMask(address_mask); + } return error; } @@ -509,8 +557,8 @@ lldb_private::DynamicLoader *ProcessMachCore::GetDynamicLoader() { return m_dyld_up.get(); } -bool ProcessMachCore::UpdateThreadList(ThreadList &old_thread_list, - ThreadList &new_thread_list) { +bool ProcessMachCore::DoUpdateThreadList(ThreadList &old_thread_list, + ThreadList &new_thread_list) { if (old_thread_list.GetSize(false) == 0) { // Make up the thread the first time this is called so we can setup our one // and only core thread state. diff --git a/gnu/llvm/lldb/source/Plugins/Process/mach-core/ProcessMachCore.h b/gnu/llvm/lldb/source/Plugins/Process/mach-core/ProcessMachCore.h index 30946410270..db77e96f107 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/mach-core/ProcessMachCore.h +++ b/gnu/llvm/lldb/source/Plugins/Process/mach-core/ProcessMachCore.h @@ -12,13 +12,13 @@ #include #include -#include "lldb/Target/Process.h" +#include "lldb/Target/PostMortemProcess.h" #include "lldb/Utility/ConstString.h" #include "lldb/Utility/Status.h" class ThreadKDP; -class ProcessMachCore : public lldb_private::Process { +class ProcessMachCore : public lldb_private::PostMortemProcess { public: // Constructors and Destructors ProcessMachCore(lldb::TargetSP target_sp, lldb::ListenerSP listener, @@ -28,7 +28,8 @@ public: static lldb::ProcessSP CreateInstance(lldb::TargetSP target_sp, lldb::ListenerSP listener, - const lldb_private::FileSpec *crash_file_path); + const lldb_private::FileSpec *crash_file_path, + bool can_connect); static void Initialize(); @@ -80,8 +81,8 @@ protected: void Clear(); - bool UpdateThreadList(lldb_private::ThreadList &old_thread_list, - lldb_private::ThreadList &new_thread_list) override; + bool DoUpdateThreadList(lldb_private::ThreadList &old_thread_list, + lldb_private::ThreadList &new_thread_list) override; lldb_private::ObjectFile *GetCoreObjectFile(); @@ -120,9 +121,6 @@ private: lldb::addr_t m_dyld_addr; lldb::addr_t m_mach_kernel_addr; lldb_private::ConstString m_dyld_plugin_name; - - ProcessMachCore(const ProcessMachCore &) = delete; - const ProcessMachCore &operator=(const ProcessMachCore &) = delete; }; #endif // LLDB_SOURCE_PLUGINS_PROCESS_MACH_CORE_PROCESSMACHCORE_H diff --git a/gnu/llvm/lldb/source/Plugins/Process/minidump/MinidumpParser.cpp b/gnu/llvm/lldb/source/Plugins/Process/minidump/MinidumpParser.cpp index 0c7f4cbbb85..61106ebcc43 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/minidump/MinidumpParser.cpp +++ b/gnu/llvm/lldb/source/Plugins/Process/minidump/MinidumpParser.cpp @@ -62,27 +62,17 @@ UUID MinidumpParser::GetModuleUUID(const minidump::Module *module) { static_cast(static_cast(*signature)); if (cv_signature == CvSignature::Pdb70) { - const CvRecordPdb70 *pdb70_uuid = nullptr; + const UUID::CvRecordPdb70 *pdb70_uuid = nullptr; Status error = consumeObject(cv_record, pdb70_uuid); if (error.Fail()) return UUID(); - - CvRecordPdb70 swapped; - if (!GetArchitecture().GetTriple().isOSBinFormatELF()) { - // LLDB's UUID class treats the data as a sequence of bytes, but breakpad - // interprets it as a sequence of little-endian fields, which it converts - // to big-endian when converting to text. Swap the bytes to big endian so - // that the string representation comes out right. - swapped = *pdb70_uuid; - llvm::sys::swapByteOrder(swapped.Uuid.Data1); - llvm::sys::swapByteOrder(swapped.Uuid.Data2); - llvm::sys::swapByteOrder(swapped.Uuid.Data3); - llvm::sys::swapByteOrder(swapped.Age); - pdb70_uuid = &swapped; + if (GetArchitecture().GetTriple().isOSBinFormatELF()) { + if (pdb70_uuid->Age != 0) + return UUID::fromOptionalData(pdb70_uuid, sizeof(*pdb70_uuid)); + return UUID::fromOptionalData(&pdb70_uuid->Uuid, + sizeof(pdb70_uuid->Uuid)); } - if (pdb70_uuid->Age != 0) - return UUID::fromOptionalData(pdb70_uuid, sizeof(*pdb70_uuid)); - return UUID::fromOptionalData(&pdb70_uuid->Uuid, sizeof(pdb70_uuid->Uuid)); + return UUID::fromCvRecord(*pdb70_uuid); } else if (cv_signature == CvSignature::ElfBuildId) return UUID::fromOptionalData(cv_record); @@ -267,6 +257,93 @@ llvm::ArrayRef MinidumpParser::GetModuleList() { return {}; } +static bool +CreateRegionsCacheFromLinuxMaps(MinidumpParser &parser, + std::vector ®ions) { + auto data = parser.GetStream(StreamType::LinuxMaps); + if (data.empty()) + return false; + + Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS); + ParseLinuxMapRegions( + llvm::toStringRef(data), + [®ions, &log](llvm::Expected region) -> bool { + if (region) + regions.push_back(*region); + else + LLDB_LOG_ERROR(log, region.takeError(), + "Reading memory region from minidump failed: {0}"); + return true; + }); + return !regions.empty(); +} + +/// Check for the memory regions starting at \a load_addr for a contiguous +/// section that has execute permissions that matches the module path. +/// +/// When we load a breakpad generated minidump file, we might have the +/// /proc//maps text for a process that details the memory map of the +/// process that the minidump is describing. This checks the sorted memory +/// regions for a section that has execute permissions. A sample maps files +/// might look like: +/// +/// 00400000-00401000 r--p 00000000 fd:01 2838574 /tmp/a.out +/// 00401000-00402000 r-xp 00001000 fd:01 2838574 /tmp/a.out +/// 00402000-00403000 r--p 00002000 fd:01 2838574 /tmp/a.out +/// 00403000-00404000 r--p 00002000 fd:01 2838574 /tmp/a.out +/// 00404000-00405000 rw-p 00003000 fd:01 2838574 /tmp/a.out +/// ... +/// +/// This function should return true when given 0x00400000 and "/tmp/a.out" +/// is passed in as the path since it has a consecutive memory region for +/// "/tmp/a.out" that has execute permissions at 0x00401000. This will help us +/// differentiate if a file has been memory mapped into a process for reading +/// and breakpad ends up saving a minidump file that has two module entries for +/// a given file: one that is read only for the entire file, and then one that +/// is the real executable that is loaded into memory for execution. For memory +/// mapped files they will typically show up and r--p permissions and a range +/// matcning the entire range of the file on disk: +/// +/// 00800000-00805000 r--p 00000000 fd:01 2838574 /tmp/a.out +/// 00805000-00806000 r-xp 00001000 fd:01 1234567 /usr/lib/libc.so +/// +/// This function should return false when asked about 0x00800000 with +/// "/tmp/a.out" as the path. +/// +/// \param[in] path +/// The path to the module to check for in the memory regions. Only sequential +/// memory regions whose paths match this path will be considered when looking +/// for execute permissions. +/// +/// \param[in] regions +/// A sorted list of memory regions obtained from a call to +/// CreateRegionsCacheFromLinuxMaps. +/// +/// \param[in] base_of_image +/// The load address of this module from BaseOfImage in the modules list. +/// +/// \return +/// True if a contiguous region of memory belonging to the module with a +/// matching path exists that has executable permissions. Returns false if +/// \a regions is empty or if there are no regions with execute permissions +/// that match \a path. + +static bool CheckForLinuxExecutable(ConstString path, + const MemoryRegionInfos ®ions, + lldb::addr_t base_of_image) { + if (regions.empty()) + return false; + lldb::addr_t addr = base_of_image; + MemoryRegionInfo region = MinidumpParser::GetMemoryRegionInfo(regions, addr); + while (region.GetName() == path) { + if (region.GetExecutable() == MemoryRegionInfo::eYes) + return true; + addr += region.GetRange().GetByteSize(); + region = MinidumpParser::GetMemoryRegionInfo(regions, addr); + } + return false; +} + std::vector MinidumpParser::GetFilteredModuleList() { Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_MODULES); auto ExpectedModules = GetMinidumpFile().getModuleList(); @@ -276,6 +353,15 @@ std::vector MinidumpParser::GetFilteredModuleList() { return {}; } + // Create memory regions from the linux maps only. We do this to avoid issues + // with breakpad generated minidumps where if someone has mmap'ed a shared + // library into memory to accesss its data in the object file, we can get a + // minidump with two mappings for a binary: one whose base image points to a + // memory region that is read + execute and one that is read only. + MemoryRegionInfos linux_regions; + if (CreateRegionsCacheFromLinuxMaps(*this, linux_regions)) + llvm::sort(linux_regions); + // map module_name -> filtered_modules index typedef llvm::StringMap MapType; MapType module_name_to_filtered_index; @@ -304,10 +390,29 @@ std::vector MinidumpParser::GetFilteredModuleList() { // "filtered_modules.size()" above. filtered_modules.push_back(&module); } else { + // We have a duplicate module entry. Check the linux regions to see if + // either module is not really a mapped executable. If one but not the + // other is a real mapped executable, prefer the executable one. This + // can happen when a process mmap's in the file for an executable in + // order to read bytes from the executable file. A memory region mapping + // will exist for the mmap'ed version and for the loaded executable, but + // only one will have a consecutive region that is executable in the + // memory regions. + auto dup_module = filtered_modules[iter->second]; + ConstString name(*ExpectedName); + bool is_executable = + CheckForLinuxExecutable(name, linux_regions, module.BaseOfImage); + bool dup_is_executable = + CheckForLinuxExecutable(name, linux_regions, dup_module->BaseOfImage); + + if (is_executable != dup_is_executable) { + if (is_executable) + filtered_modules[iter->second] = &module; + continue; + } // This module has been seen. Modules are sometimes mentioned multiple // times when they are mapped discontiguously, so find the module with // the lowest "base_of_image" and use that as the filtered module. - auto dup_module = filtered_modules[iter->second]; if (module.BaseOfImage < dup_module->BaseOfImage) filtered_modules[iter->second] = &module; } @@ -411,22 +516,6 @@ llvm::ArrayRef MinidumpParser::GetMemory(lldb::addr_t addr, return range->range_ref.slice(offset, overlap); } -static bool -CreateRegionsCacheFromLinuxMaps(MinidumpParser &parser, - std::vector ®ions) { - auto data = parser.GetStream(StreamType::LinuxMaps); - if (data.empty()) - return false; - ParseLinuxMapRegions(llvm::toStringRef(data), - [&](const lldb_private::MemoryRegionInfo ®ion, - const lldb_private::Status &status) -> bool { - if (status.Success()) - regions.push_back(region); - return true; - }); - return !regions.empty(); -} - static bool CreateRegionsCacheFromMemoryInfoList(MinidumpParser &parser, std::vector ®ions) { @@ -500,10 +589,10 @@ CreateRegionsCacheFromMemory64List(MinidumpParser &parser, uint64_t base_rva; std::tie(memory64_list, base_rva) = MinidumpMemoryDescriptor64::ParseMemory64List(data); - + if (memory64_list.empty()) return false; - + regions.reserve(memory64_list.size()); for (const auto &memory_desc : memory64_list) { if (memory_desc.data_size == 0) @@ -597,3 +686,30 @@ MinidumpParser::GetStreamTypeAsString(StreamType stream_type) { } return "unknown stream type"; } + +MemoryRegionInfo +MinidumpParser::GetMemoryRegionInfo(const MemoryRegionInfos ®ions, + lldb::addr_t load_addr) { + MemoryRegionInfo region; + auto pos = llvm::upper_bound(regions, load_addr); + if (pos != regions.begin() && + std::prev(pos)->GetRange().Contains(load_addr)) { + return *std::prev(pos); + } + + if (pos == regions.begin()) + region.GetRange().SetRangeBase(0); + else + region.GetRange().SetRangeBase(std::prev(pos)->GetRange().GetRangeEnd()); + + if (pos == regions.end()) + region.GetRange().SetRangeEnd(UINT64_MAX); + else + region.GetRange().SetRangeEnd(pos->GetRange().GetRangeBase()); + + region.SetReadable(MemoryRegionInfo::eNo); + region.SetWritable(MemoryRegionInfo::eNo); + region.SetExecutable(MemoryRegionInfo::eNo); + region.SetMapped(MemoryRegionInfo::eNo); + return region; +} diff --git a/gnu/llvm/lldb/source/Plugins/Process/minidump/MinidumpParser.h b/gnu/llvm/lldb/source/Plugins/Process/minidump/MinidumpParser.h index c4d7612b5f8..ff7134ff181 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/minidump/MinidumpParser.h +++ b/gnu/llvm/lldb/source/Plugins/Process/minidump/MinidumpParser.h @@ -96,6 +96,9 @@ public: llvm::object::MinidumpFile &GetMinidumpFile() { return *m_file; } + static MemoryRegionInfo GetMemoryRegionInfo(const MemoryRegionInfos ®ions, + lldb::addr_t load_addr); + private: MinidumpParser(lldb::DataBufferSP data_sp, std::unique_ptr file); diff --git a/gnu/llvm/lldb/source/Plugins/Process/minidump/MinidumpTypes.h b/gnu/llvm/lldb/source/Plugins/Process/minidump/MinidumpTypes.h index a7ac65120e2..c05fcfef05a 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/minidump/MinidumpTypes.h +++ b/gnu/llvm/lldb/source/Plugins/Process/minidump/MinidumpTypes.h @@ -40,21 +40,6 @@ enum class CvSignature : uint32_t { ElfBuildId = 0x4270454c, // BpEL (Breakpad/Crashpad minidumps) }; -// Reference: -// https://crashpad.chromium.org/doxygen/structcrashpad_1_1CodeViewRecordPDB70.html -struct CvRecordPdb70 { - struct { - llvm::support::ulittle32_t Data1; - llvm::support::ulittle16_t Data2; - llvm::support::ulittle16_t Data3; - uint8_t Data4[8]; - } Uuid; - llvm::support::ulittle32_t Age; - // char PDBFileName[]; -}; -static_assert(sizeof(CvRecordPdb70) == 20, - "sizeof CvRecordPdb70 is not correct!"); - enum class MinidumpMiscInfoFlags : uint32_t { ProcessID = (1 << 0), ProcessTimes = (1 << 1), diff --git a/gnu/llvm/lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp b/gnu/llvm/lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp index 1041f63aa2e..38555742275 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp +++ b/gnu/llvm/lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp @@ -138,10 +138,10 @@ private: /// /// \param[in] module_sp The module to grab the .text section from. /// -/// \param[in/out] breakpad_uuid A vector that will receive the calculated +/// \param[in,out] breakpad_uuid A vector that will receive the calculated /// breakpad .text hash. /// -/// \param[in/out] facebook_uuid A vector that will receive the calculated +/// \param[in,out] facebook_uuid A vector that will receive the calculated /// facebook .text hash. /// void HashElfTextSection(ModuleSP module_sp, std::vector &breakpad_uuid, @@ -200,8 +200,9 @@ const char *ProcessMinidump::GetPluginDescriptionStatic() { lldb::ProcessSP ProcessMinidump::CreateInstance(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp, - const FileSpec *crash_file) { - if (!crash_file) + const FileSpec *crash_file, + bool can_connect) { + if (!crash_file || can_connect) return nullptr; lldb::ProcessSP process_sp; @@ -234,7 +235,7 @@ ProcessMinidump::ProcessMinidump(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp, const FileSpec &core_file, DataBufferSP core_data) - : Process(target_sp, listener_sp), m_core_file(core_file), + : PostMortemProcess(target_sp, listener_sp), m_core_file(core_file), m_core_data(std::move(core_data)), m_is_wow64(false) {} ProcessMinidump::~ProcessMinidump() { @@ -404,32 +405,6 @@ ArchSpec ProcessMinidump::GetArchitecture() { return ArchSpec(triple); } -static MemoryRegionInfo GetMemoryRegionInfo(const MemoryRegionInfos ®ions, - lldb::addr_t load_addr) { - MemoryRegionInfo region; - auto pos = llvm::upper_bound(regions, load_addr); - if (pos != regions.begin() && - std::prev(pos)->GetRange().Contains(load_addr)) { - return *std::prev(pos); - } - - if (pos == regions.begin()) - region.GetRange().SetRangeBase(0); - else - region.GetRange().SetRangeBase(std::prev(pos)->GetRange().GetRangeEnd()); - - if (pos == regions.end()) - region.GetRange().SetRangeEnd(UINT64_MAX); - else - region.GetRange().SetRangeEnd(pos->GetRange().GetRangeBase()); - - region.SetReadable(MemoryRegionInfo::eNo); - region.SetWritable(MemoryRegionInfo::eNo); - region.SetExecutable(MemoryRegionInfo::eNo); - region.SetMapped(MemoryRegionInfo::eNo); - return region; -} - void ProcessMinidump::BuildMemoryRegions() { if (m_memory_regions) return; @@ -454,7 +429,7 @@ void ProcessMinidump::BuildMemoryRegions() { MemoryRegionInfo::RangeType section_range(load_addr, section_sp->GetByteSize()); MemoryRegionInfo region = - ::GetMemoryRegionInfo(*m_memory_regions, load_addr); + MinidumpParser::GetMemoryRegionInfo(*m_memory_regions, load_addr); if (region.GetMapped() != MemoryRegionInfo::eYes && region.GetRange().GetRangeBase() <= section_range.GetRangeBase() && section_range.GetRangeEnd() <= region.GetRange().GetRangeEnd()) { @@ -475,7 +450,7 @@ void ProcessMinidump::BuildMemoryRegions() { Status ProcessMinidump::GetMemoryRegionInfo(lldb::addr_t load_addr, MemoryRegionInfo ®ion) { BuildMemoryRegions(); - region = ::GetMemoryRegionInfo(*m_memory_regions, load_addr); + region = MinidumpParser::GetMemoryRegionInfo(*m_memory_regions, load_addr); return Status(); } @@ -487,8 +462,8 @@ Status ProcessMinidump::GetMemoryRegions(MemoryRegionInfos ®ion_list) { void ProcessMinidump::Clear() { Process::m_thread_list.Clear(); } -bool ProcessMinidump::UpdateThreadList(ThreadList &old_thread_list, - ThreadList &new_thread_list) { +bool ProcessMinidump::DoUpdateThreadList(ThreadList &old_thread_list, + ThreadList &new_thread_list) { for (const minidump::Thread &thread : m_thread_list) { LocationDescriptor context_location = thread.Context; @@ -573,7 +548,7 @@ void ProcessMinidump::ReadModuleList() { // check if the process is wow64 - a 32 bit windows process running on a // 64 bit windows - if (llvm::StringRef(name).endswith_lower("wow64.dll")) { + if (llvm::StringRef(name).endswith_insensitive("wow64.dll")) { m_is_wow64 = true; } @@ -896,7 +871,7 @@ public: m_option_group.Finalize(); } - ~CommandObjectProcessMinidumpDump() override {} + ~CommandObjectProcessMinidumpDump() override = default; Options *GetOptions() override { return &m_option_group; } @@ -905,7 +880,6 @@ public: if (argc > 0) { result.AppendErrorWithFormat("'%s' take no arguments, only options", m_cmd_name.c_str()); - result.SetStatus(eReturnStatusFailed); return false; } SetDefaultOptionsIfNoneAreSet(); @@ -1026,7 +1000,7 @@ public: CommandObjectSP(new CommandObjectProcessMinidumpDump(interpreter))); } - ~CommandObjectMultiwordProcessMinidump() override {} + ~CommandObjectMultiwordProcessMinidump() override = default; }; CommandObject *ProcessMinidump::GetPluginCommandObject() { diff --git a/gnu/llvm/lldb/source/Plugins/Process/minidump/ProcessMinidump.h b/gnu/llvm/lldb/source/Plugins/Process/minidump/ProcessMinidump.h index bfdace7ea33..27b0da0047a 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/minidump/ProcessMinidump.h +++ b/gnu/llvm/lldb/source/Plugins/Process/minidump/ProcessMinidump.h @@ -12,7 +12,7 @@ #include "MinidumpParser.h" #include "MinidumpTypes.h" -#include "lldb/Target/Process.h" +#include "lldb/Target/PostMortemProcess.h" #include "lldb/Target/StopInfo.h" #include "lldb/Target/Target.h" #include "lldb/Utility/ConstString.h" @@ -26,11 +26,12 @@ namespace lldb_private { namespace minidump { -class ProcessMinidump : public Process { +class ProcessMinidump : public PostMortemProcess { public: static lldb::ProcessSP CreateInstance(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp, - const FileSpec *crash_file_path); + const FileSpec *crash_file_path, + bool can_connect); static void Initialize(); @@ -97,8 +98,8 @@ public: protected: void Clear(); - bool UpdateThreadList(ThreadList &old_thread_list, - ThreadList &new_thread_list) override; + bool DoUpdateThreadList(ThreadList &old_thread_list, + ThreadList &new_thread_list) override; void ReadModuleList(); diff --git a/gnu/llvm/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_ARM.cpp b/gnu/llvm/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_ARM.cpp index eb48785263f..7e309e8322a 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_ARM.cpp +++ b/gnu/llvm/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_ARM.cpp @@ -16,7 +16,7 @@ #include "lldb/lldb-enumerations.h" // C includes -#include +#include // C++ includes diff --git a/gnu/llvm/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_ARM64.cpp b/gnu/llvm/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_ARM64.cpp index c7809c5f19b..e2b7c0e362a 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_ARM64.cpp +++ b/gnu/llvm/lldb/source/Plugins/Process/minidump/RegisterContextMinidump_ARM64.cpp @@ -14,7 +14,7 @@ #include "lldb/lldb-enumerations.h" // C includes -#include +#include // C++ includes diff --git a/gnu/llvm/lldb/source/Plugins/Process/minidump/ThreadMinidump.cpp b/gnu/llvm/lldb/source/Plugins/Process/minidump/ThreadMinidump.cpp index e146a1a1af9..1fbc5281523 100644 --- a/gnu/llvm/lldb/source/Plugins/Process/minidump/ThreadMinidump.cpp +++ b/gnu/llvm/lldb/source/Plugins/Process/minidump/ThreadMinidump.cpp @@ -38,7 +38,7 @@ ThreadMinidump::ThreadMinidump(Process &process, const minidump::Thread &td, : Thread(process, td.ThreadId), m_thread_reg_ctx_sp(), m_gpregset_data(gpregset_data) {} -ThreadMinidump::~ThreadMinidump() {} +ThreadMinidump::~ThreadMinidump() = default; void ThreadMinidump::RefreshStateAfterStop() {} diff --git a/gnu/llvm/lldb/source/Plugins/Process/scripted/CMakeLists.txt b/gnu/llvm/lldb/source/Plugins/Process/scripted/CMakeLists.txt new file mode 100644 index 00000000000..e2cfd058e27 --- /dev/null +++ b/gnu/llvm/lldb/source/Plugins/Process/scripted/CMakeLists.txt @@ -0,0 +1,13 @@ +add_lldb_library(lldbPluginScriptedProcess PLUGIN + ScriptedProcess.cpp + + LINK_LIBS + lldbCore + lldbTarget + lldbUtility + lldbPluginProcessUtility + LINK_COMPONENTS + BinaryFormat + Object + Support + ) diff --git a/gnu/llvm/lldb/source/Plugins/Process/scripted/ScriptedProcess.cpp b/gnu/llvm/lldb/source/Plugins/Process/scripted/ScriptedProcess.cpp new file mode 100644 index 00000000000..09e9375b6f6 --- /dev/null +++ b/gnu/llvm/lldb/source/Plugins/Process/scripted/ScriptedProcess.cpp @@ -0,0 +1,313 @@ +//===-- ScriptedProcess.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 "ScriptedProcess.h" + +#include "lldb/Core/Debugger.h" +#include "lldb/Core/Module.h" +#include "lldb/Core/PluginManager.h" + +#include "lldb/Host/OptionParser.h" +#include "lldb/Host/ThreadLauncher.h" +#include "lldb/Interpreter/CommandInterpreter.h" +#include "lldb/Interpreter/OptionArgParser.h" +#include "lldb/Interpreter/OptionGroupBoolean.h" +#include "lldb/Interpreter/ScriptInterpreter.h" +#include "lldb/Target/MemoryRegionInfo.h" +#include "lldb/Target/RegisterContext.h" + +#include "lldb/Utility/Log.h" +#include "lldb/Utility/Logging.h" +#include "lldb/Utility/State.h" + +#include + +LLDB_PLUGIN_DEFINE(ScriptedProcess) + +using namespace lldb; +using namespace lldb_private; + +ConstString ScriptedProcess::GetPluginNameStatic() { + static ConstString g_name("ScriptedProcess"); + return g_name; +} + +const char *ScriptedProcess::GetPluginDescriptionStatic() { + return "Scripted Process plug-in."; +} + +static constexpr lldb::ScriptLanguage g_supported_script_languages[] = { + ScriptLanguage::eScriptLanguagePython, +}; + +bool ScriptedProcess::IsScriptLanguageSupported(lldb::ScriptLanguage language) { + llvm::ArrayRef supported_languages = + llvm::makeArrayRef(g_supported_script_languages); + + return llvm::is_contained(supported_languages, language); +} + +void ScriptedProcess::CheckInterpreterAndScriptObject() const { + lldbassert(m_interpreter && "Invalid Script Interpreter."); + lldbassert(m_script_object_sp && "Invalid Script Object."); +} + +lldb::ProcessSP ScriptedProcess::CreateInstance(lldb::TargetSP target_sp, + lldb::ListenerSP listener_sp, + const FileSpec *file, + bool can_connect) { + if (!target_sp || + !IsScriptLanguageSupported(target_sp->GetDebugger().GetScriptLanguage())) + return nullptr; + + Status error; + ScriptedProcess::ScriptedProcessInfo scripted_process_info( + target_sp->GetProcessLaunchInfo()); + + auto process_sp = std::make_shared( + target_sp, listener_sp, scripted_process_info, error); + + if (error.Fail() || !process_sp || !process_sp->m_script_object_sp || + !process_sp->m_script_object_sp->IsValid()) { + LLDB_LOGF(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS), "%s", + error.AsCString()); + return nullptr; + } + + return process_sp; +} + +bool ScriptedProcess::CanDebug(lldb::TargetSP target_sp, + bool plugin_specified_by_name) { + return true; +} + +ScriptedProcess::ScriptedProcess( + lldb::TargetSP target_sp, lldb::ListenerSP listener_sp, + const ScriptedProcess::ScriptedProcessInfo &scripted_process_info, + Status &error) + : Process(target_sp, listener_sp), + m_scripted_process_info(scripted_process_info) { + + if (!target_sp) { + error.SetErrorStringWithFormat("ScriptedProcess::%s () - ERROR: %s", + __FUNCTION__, "Invalid target"); + return; + } + + m_interpreter = target_sp->GetDebugger().GetScriptInterpreter(); + + if (!m_interpreter) { + error.SetErrorStringWithFormat("ScriptedProcess::%s () - ERROR: %s", + __FUNCTION__, + "Debugger has no Script Interpreter"); + return; + } + + StructuredData::ObjectSP object_sp = GetInterface().CreatePluginObject( + m_scripted_process_info.GetClassName().c_str(), target_sp, + m_scripted_process_info.GetDictionarySP()); + + if (!object_sp || !object_sp->IsValid()) { + error.SetErrorStringWithFormat("ScriptedProcess::%s () - ERROR: %s", + __FUNCTION__, + "Failed to create valid script object"); + return; + } + + m_script_object_sp = object_sp; +} + +ScriptedProcess::~ScriptedProcess() { + Clear(); + // We need to call finalize on the process before destroying ourselves to + // make sure all of the broadcaster cleanup goes as planned. If we destruct + // this class, then Process::~Process() might have problems trying to fully + // destroy the broadcaster. + Finalize(); +} + +void ScriptedProcess::Initialize() { + static llvm::once_flag g_once_flag; + + llvm::call_once(g_once_flag, []() { + PluginManager::RegisterPlugin(GetPluginNameStatic(), + GetPluginDescriptionStatic(), CreateInstance); + }); +} + +void ScriptedProcess::Terminate() { + PluginManager::UnregisterPlugin(ScriptedProcess::CreateInstance); +} + +ConstString ScriptedProcess::GetPluginName() { return GetPluginNameStatic(); } + +uint32_t ScriptedProcess::GetPluginVersion() { return 1; } + +Status ScriptedProcess::DoLoadCore() { + ProcessLaunchInfo launch_info = GetTarget().GetProcessLaunchInfo(); + + return DoLaunch(nullptr, launch_info); +} + +Status ScriptedProcess::DoLaunch(Module *exe_module, + ProcessLaunchInfo &launch_info) { + CheckInterpreterAndScriptObject(); + + /* FIXME: This doesn't reflect how lldb actually launches a process. + In reality, it attaches to debugserver, then resume the process. */ + Status error = GetInterface().Launch(); + SetPrivateState(eStateRunning); + + if (error.Fail()) + return error; + + // TODO: Fetch next state from stopped event queue then send stop event + // const StateType state = SetThreadStopInfo(response); + // if (state != eStateInvalid) { + // SetPrivateState(state); + + SetPrivateState(eStateStopped); + + UpdateThreadListIfNeeded(); + GetThreadList(); + + return {}; +} + +void ScriptedProcess::DidLaunch() { + CheckInterpreterAndScriptObject(); + m_pid = GetInterface().GetProcessID(); +} + +Status ScriptedProcess::DoResume() { + CheckInterpreterAndScriptObject(); + + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); + // FIXME: Fetch data from thread. + const StateType thread_resume_state = eStateRunning; + LLDB_LOGF(log, "ScriptedProcess::%s thread_resume_state = %s", __FUNCTION__, + StateAsCString(thread_resume_state)); + + bool resume = (thread_resume_state == eStateRunning); + assert(thread_resume_state == eStateRunning && "invalid thread resume state"); + + Status error; + if (resume) { + LLDB_LOGF(log, "ScriptedProcess::%s sending resume", __FUNCTION__); + + SetPrivateState(eStateRunning); + SetPrivateState(eStateStopped); + error = GetInterface().Resume(); + } + + return error; +} + +Status ScriptedProcess::DoStop() { + CheckInterpreterAndScriptObject(); + + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); + + if (GetInterface().ShouldStop()) { + SetPrivateState(eStateStopped); + LLDB_LOGF(log, "ScriptedProcess::%s Immediate stop", __FUNCTION__); + return {}; + } + + LLDB_LOGF(log, "ScriptedProcess::%s Delayed stop", __FUNCTION__); + return GetInterface().Stop(); +} + +Status ScriptedProcess::DoDestroy() { return Status(); } + +bool ScriptedProcess::IsAlive() { + if (m_interpreter && m_script_object_sp) + return GetInterface().IsAlive(); + return false; +} + +size_t ScriptedProcess::DoReadMemory(lldb::addr_t addr, void *buf, size_t size, + Status &error) { + + auto error_with_message = [&error](llvm::StringRef message) { + error.SetErrorString(message); + return 0; + }; + + if (!m_interpreter) + return error_with_message("No interpreter."); + + lldb::DataExtractorSP data_extractor_sp = + GetInterface().ReadMemoryAtAddress(addr, size, error); + + if (!data_extractor_sp || error.Fail()) + return 0; + + offset_t bytes_copied = data_extractor_sp->CopyByteOrderedData( + 0, data_extractor_sp->GetByteSize(), buf, size, GetByteOrder()); + + if (!bytes_copied || bytes_copied == LLDB_INVALID_OFFSET) + return error_with_message("Failed to copy read memory to buffer."); + + return size; +} + +ArchSpec ScriptedProcess::GetArchitecture() { + return GetTarget().GetArchitecture(); +} + +Status ScriptedProcess::GetMemoryRegionInfo(lldb::addr_t load_addr, + MemoryRegionInfo ®ion) { + // TODO: Implement + return Status(); +} + +Status ScriptedProcess::GetMemoryRegions(MemoryRegionInfos ®ion_list) { + CheckInterpreterAndScriptObject(); + + lldb::addr_t address = 0; + lldb::MemoryRegionInfoSP mem_region_sp = nullptr; + + while ((mem_region_sp = + GetInterface().GetMemoryRegionContainingAddress(address))) { + auto range = mem_region_sp->GetRange(); + address += range.GetRangeBase() + range.GetByteSize(); + region_list.push_back(*mem_region_sp.get()); + } + + return {}; +} + +void ScriptedProcess::Clear() { Process::m_thread_list.Clear(); } + +bool ScriptedProcess::DoUpdateThreadList(ThreadList &old_thread_list, + ThreadList &new_thread_list) { + // TODO: Implement + // This is supposed to get the current set of threads, if any of them are in + // old_thread_list then they get copied to new_thread_list, and then any + // actually new threads will get added to new_thread_list. + return new_thread_list.GetSize(false) > 0; +} + +bool ScriptedProcess::GetProcessInfo(ProcessInstanceInfo &info) { + info.Clear(); + info.SetProcessID(GetID()); + info.SetArchitecture(GetArchitecture()); + lldb::ModuleSP module_sp = GetTarget().GetExecutableModule(); + if (module_sp) { + const bool add_exe_file_as_first_arg = false; + info.SetExecutableFile(GetTarget().GetExecutableModule()->GetFileSpec(), + add_exe_file_as_first_arg); + } + return true; +} + +ScriptedProcessInterface &ScriptedProcess::GetInterface() const { + return m_interpreter->GetScriptedProcessInterface(); +} diff --git a/gnu/llvm/lldb/source/Plugins/Process/scripted/ScriptedProcess.h b/gnu/llvm/lldb/source/Plugins/Process/scripted/ScriptedProcess.h new file mode 100644 index 00000000000..98c1a1ca4fe --- /dev/null +++ b/gnu/llvm/lldb/source/Plugins/Process/scripted/ScriptedProcess.h @@ -0,0 +1,119 @@ +//===-- ScriptedProcess.h ------------------------------------- -*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SOURCE_PLUGINS_SCRIPTED_PROCESS_H +#define LLDB_SOURCE_PLUGINS_SCRIPTED_PROCESS_H + +#include "lldb/Target/Process.h" +#include "lldb/Utility/ConstString.h" +#include "lldb/Utility/Status.h" + +#include + +namespace lldb_private { + +class ScriptedProcess : public Process { +protected: + class ScriptedProcessInfo { + public: + ScriptedProcessInfo(const ProcessLaunchInfo &launch_info) { + m_class_name = launch_info.GetScriptedProcessClassName(); + m_dictionary_sp = launch_info.GetScriptedProcessDictionarySP(); + } + + std::string GetClassName() const { return m_class_name; } + StructuredData::DictionarySP GetDictionarySP() const { + return m_dictionary_sp; + } + + private: + std::string m_class_name; + StructuredData::DictionarySP m_dictionary_sp; + }; + +public: + 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 Terminate(); + + static ConstString GetPluginNameStatic(); + + static const char *GetPluginDescriptionStatic(); + + ScriptedProcess(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp, + const ScriptedProcess::ScriptedProcessInfo &launch_info, + Status &error); + + ~ScriptedProcess() override; + + bool CanDebug(lldb::TargetSP target_sp, + bool plugin_specified_by_name) override; + + DynamicLoader *GetDynamicLoader() override { return nullptr; } + + ConstString GetPluginName() override; + + uint32_t GetPluginVersion() override; + + SystemRuntime *GetSystemRuntime() override { return nullptr; } + + Status DoLoadCore() override; + + Status DoLaunch(Module *exe_module, ProcessLaunchInfo &launch_info) override; + + void DidLaunch() override; + + Status DoResume() override; + + Status DoDestroy() override; + + void RefreshStateAfterStop() override{}; + + bool IsAlive() override; + + size_t DoReadMemory(lldb::addr_t addr, void *buf, size_t size, + Status &error) override; + + ArchSpec GetArchitecture(); + + Status GetMemoryRegionInfo(lldb::addr_t load_addr, + MemoryRegionInfo &range_info) override; + + Status + GetMemoryRegions(lldb_private::MemoryRegionInfos ®ion_list) override; + + bool GetProcessInfo(ProcessInstanceInfo &info) override; + +protected: + Status DoStop(); + + void Clear(); + + bool DoUpdateThreadList(ThreadList &old_thread_list, + ThreadList &new_thread_list) override; + +private: + void CheckInterpreterAndScriptObject() const; + ScriptedProcessInterface &GetInterface() const; + static bool IsScriptLanguageSupported(lldb::ScriptLanguage language); + + // Member variables. + const ScriptedProcessInfo m_scripted_process_info; + lldb_private::ScriptInterpreter *m_interpreter = nullptr; + lldb_private::StructuredData::ObjectSP m_script_object_sp = nullptr; + //@} +}; + +} // namespace lldb_private + +#endif // LLDB_SOURCE_PLUGINS_SCRIPTED_PROCESS_H diff --git a/gnu/llvm/lldb/source/Plugins/ScriptInterpreter/Lua/Lua.cpp b/gnu/llvm/lldb/source/Plugins/ScriptInterpreter/Lua/Lua.cpp index acd6128d84c..e99b7b88379 100644 --- a/gnu/llvm/lldb/source/Plugins/ScriptInterpreter/Lua/Lua.cpp +++ b/gnu/llvm/lldb/source/Plugins/ScriptInterpreter/Lua/Lua.cpp @@ -9,17 +9,147 @@ #include "Lua.h" #include "lldb/Host/FileSystem.h" #include "lldb/Utility/FileSpec.h" +#include "llvm/Support/Error.h" #include "llvm/Support/FormatVariadic.h" using namespace lldb_private; using namespace lldb; +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wreturn-type-c-linkage" + +// Disable warning C4190: 'LLDBSwigPythonBreakpointCallbackFunction' has +// C-linkage specified, but returns UDT 'llvm::Expected' which is +// incompatible with C +#if _MSC_VER +#pragma warning (push) +#pragma warning (disable : 4190) +#endif + +extern "C" llvm::Expected LLDBSwigLuaBreakpointCallbackFunction( + lua_State *L, lldb::StackFrameSP stop_frame_sp, + lldb::BreakpointLocationSP bp_loc_sp, StructuredDataImpl *extra_args_impl); + +extern "C" llvm::Expected LLDBSwigLuaWatchpointCallbackFunction( + lua_State *L, lldb::StackFrameSP stop_frame_sp, lldb::WatchpointSP wp_sp); + +#if _MSC_VER +#pragma warning (pop) +#endif + +#pragma clang diagnostic pop + +static int lldb_print(lua_State *L) { + int n = lua_gettop(L); + lua_getglobal(L, "io"); + lua_getfield(L, -1, "stdout"); + lua_getfield(L, -1, "write"); + for (int i = 1; i <= n; i++) { + lua_pushvalue(L, -1); // write() + lua_pushvalue(L, -3); // io.stdout + luaL_tolstring(L, i, nullptr); + lua_pushstring(L, i != n ? "\t" : "\n"); + lua_call(L, 3, 0); + } + return 0; +} + +Lua::Lua() : m_lua_state(luaL_newstate()) { + assert(m_lua_state); + luaL_openlibs(m_lua_state); + luaopen_lldb(m_lua_state); + lua_pushcfunction(m_lua_state, lldb_print); + lua_setglobal(m_lua_state, "print"); +} + +Lua::~Lua() { + assert(m_lua_state); + lua_close(m_lua_state); +} + llvm::Error Lua::Run(llvm::StringRef buffer) { int error = luaL_loadbuffer(m_lua_state, buffer.data(), buffer.size(), "buffer") || lua_pcall(m_lua_state, 0, 0, 0); - if (!error) + if (error == LUA_OK) + return llvm::Error::success(); + + llvm::Error e = llvm::make_error( + llvm::formatv("{0}\n", lua_tostring(m_lua_state, -1)), + llvm::inconvertibleErrorCode()); + // Pop error message from the stack. + lua_pop(m_lua_state, 1); + return e; +} + +llvm::Error Lua::RegisterBreakpointCallback(void *baton, const char *body) { + lua_pushlightuserdata(m_lua_state, baton); + const char *fmt_str = "return function(frame, bp_loc, ...) {0} end"; + std::string func_str = llvm::formatv(fmt_str, body).str(); + if (luaL_dostring(m_lua_state, func_str.c_str()) != LUA_OK) { + llvm::Error e = llvm::make_error( + llvm::formatv("{0}", lua_tostring(m_lua_state, -1)), + llvm::inconvertibleErrorCode()); + // Pop error message from the stack. + lua_pop(m_lua_state, 2); + return e; + } + lua_settable(m_lua_state, LUA_REGISTRYINDEX); + return llvm::Error::success(); +} + +llvm::Expected +Lua::CallBreakpointCallback(void *baton, lldb::StackFrameSP stop_frame_sp, + lldb::BreakpointLocationSP bp_loc_sp, + StructuredData::ObjectSP extra_args_sp) { + + lua_pushlightuserdata(m_lua_state, baton); + lua_gettable(m_lua_state, LUA_REGISTRYINDEX); + auto *extra_args_impl = [&]() -> StructuredDataImpl * { + if (extra_args_sp == nullptr) + return nullptr; + auto *extra_args_impl = new StructuredDataImpl(); + extra_args_impl->SetObjectSP(extra_args_sp); + return extra_args_impl; + }(); + return LLDBSwigLuaBreakpointCallbackFunction(m_lua_state, stop_frame_sp, + bp_loc_sp, extra_args_impl); +} + +llvm::Error Lua::RegisterWatchpointCallback(void *baton, const char *body) { + lua_pushlightuserdata(m_lua_state, baton); + const char *fmt_str = "return function(frame, wp, ...) {0} end"; + std::string func_str = llvm::formatv(fmt_str, body).str(); + if (luaL_dostring(m_lua_state, func_str.c_str()) != LUA_OK) { + llvm::Error e = llvm::make_error( + llvm::formatv("{0}", lua_tostring(m_lua_state, -1)), + llvm::inconvertibleErrorCode()); + // Pop error message from the stack. + lua_pop(m_lua_state, 2); + return e; + } + lua_settable(m_lua_state, LUA_REGISTRYINDEX); + return llvm::Error::success(); +} + +llvm::Expected +Lua::CallWatchpointCallback(void *baton, lldb::StackFrameSP stop_frame_sp, + lldb::WatchpointSP wp_sp) { + + lua_pushlightuserdata(m_lua_state, baton); + lua_gettable(m_lua_state, LUA_REGISTRYINDEX); + return LLDBSwigLuaWatchpointCallbackFunction(m_lua_state, stop_frame_sp, + wp_sp); +} + +llvm::Error Lua::CheckSyntax(llvm::StringRef buffer) { + int error = + luaL_loadbuffer(m_lua_state, buffer.data(), buffer.size(), "buffer"); + if (error == LUA_OK) { + // Pop buffer + lua_pop(m_lua_state, 1); return llvm::Error::success(); + } llvm::Error e = llvm::make_error( llvm::formatv("{0}\n", lua_tostring(m_lua_state, -1)), @@ -44,7 +174,7 @@ llvm::Error Lua::LoadModule(llvm::StringRef filename) { int error = luaL_loadfile(m_lua_state, filename.data()) || lua_pcall(m_lua_state, 0, 1, 0); - if (error) { + if (error != LUA_OK) { llvm::Error e = llvm::make_error( llvm::formatv("{0}\n", lua_tostring(m_lua_state, -1)), llvm::inconvertibleErrorCode()); diff --git a/gnu/llvm/lldb/source/Plugins/ScriptInterpreter/Lua/Lua.h b/gnu/llvm/lldb/source/Plugins/ScriptInterpreter/Lua/Lua.h index 300115aac8a..5daedf835b9 100644 --- a/gnu/llvm/lldb/source/Plugins/ScriptInterpreter/Lua/Lua.h +++ b/gnu/llvm/lldb/source/Plugins/ScriptInterpreter/Lua/Lua.h @@ -9,6 +9,9 @@ #ifndef liblldb_Lua_h_ #define liblldb_Lua_h_ +#include "lldb/API/SBBreakpointLocation.h" +#include "lldb/API/SBFrame.h" +#include "lldb/Core/StructuredDataImpl.h" #include "lldb/lldb-types.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Error.h" @@ -25,19 +28,21 @@ int luaopen_lldb(lua_State *L); class Lua { public: - Lua() : m_lua_state(luaL_newstate()) { - assert(m_lua_state); - luaL_openlibs(m_lua_state); - luaopen_lldb(m_lua_state); - } - - ~Lua() { - assert(m_lua_state); - luaL_openlibs(m_lua_state); - } + Lua(); + ~Lua(); llvm::Error Run(llvm::StringRef buffer); + llvm::Error RegisterBreakpointCallback(void *baton, const char *body); + llvm::Expected + CallBreakpointCallback(void *baton, lldb::StackFrameSP stop_frame_sp, + lldb::BreakpointLocationSP bp_loc_sp, + StructuredData::ObjectSP extra_args_sp); + llvm::Error RegisterWatchpointCallback(void *baton, const char *body); + llvm::Expected CallWatchpointCallback(void *baton, + lldb::StackFrameSP stop_frame_sp, + lldb::WatchpointSP wp_sp); llvm::Error LoadModule(llvm::StringRef filename); + llvm::Error CheckSyntax(llvm::StringRef buffer); llvm::Error ChangeIO(FILE *out, FILE *err); private: diff --git a/gnu/llvm/lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.cpp b/gnu/llvm/lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.cpp index 8cbeac4563c..ef46401c8b4 100644 --- a/gnu/llvm/lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.cpp +++ b/gnu/llvm/lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.cpp @@ -8,29 +8,42 @@ #include "ScriptInterpreterLua.h" #include "Lua.h" +#include "lldb/Breakpoint/StoppointCallbackContext.h" #include "lldb/Core/Debugger.h" #include "lldb/Core/PluginManager.h" #include "lldb/Core/StreamFile.h" #include "lldb/Interpreter/CommandReturnObject.h" +#include "lldb/Target/ExecutionContext.h" #include "lldb/Utility/Stream.h" #include "lldb/Utility/StringList.h" #include "lldb/Utility/Timer.h" +#include "llvm/ADT/StringRef.h" #include "llvm/Support/FormatAdapters.h" +#include +#include using namespace lldb; using namespace lldb_private; LLDB_PLUGIN_DEFINE(ScriptInterpreterLua) +enum ActiveIOHandler { + eIOHandlerNone, + eIOHandlerBreakpoint, + eIOHandlerWatchpoint +}; + class IOHandlerLuaInterpreter : public IOHandlerDelegate, public IOHandlerEditline { public: IOHandlerLuaInterpreter(Debugger &debugger, - ScriptInterpreterLua &script_interpreter) + ScriptInterpreterLua &script_interpreter, + ActiveIOHandler active_io_handler = eIOHandlerNone) : IOHandlerEditline(debugger, IOHandler::Type::LuaInterpreter, "lua", ">>> ", "..> ", true, debugger.GetUseColor(), 0, *this, nullptr), - m_script_interpreter(script_interpreter) { + m_script_interpreter(script_interpreter), + m_active_io_handler(active_io_handler) { llvm::cantFail(m_script_interpreter.GetLua().ChangeIO( debugger.GetOutputFile().GetStream(), debugger.GetErrorFile().GetStream())); @@ -41,27 +54,99 @@ public: llvm::cantFail(m_script_interpreter.LeaveSession()); } - void IOHandlerInputComplete(IOHandler &io_handler, - std::string &data) override { - if (llvm::StringRef(data).rtrim() == "quit") { - io_handler.SetIsDone(true); + void IOHandlerActivated(IOHandler &io_handler, bool interactive) override { + const char *instructions = nullptr; + switch (m_active_io_handler) { + case eIOHandlerNone: + break; + case eIOHandlerWatchpoint: + instructions = "Enter your Lua command(s). Type 'quit' to end.\n" + "The commands are compiled as the body of the following " + "Lua function\n" + "function (frame, wp) end\n"; + SetPrompt(llvm::StringRef("..> ")); + break; + case eIOHandlerBreakpoint: + instructions = "Enter your Lua command(s). Type 'quit' to end.\n" + "The commands are compiled as the body of the following " + "Lua function\n" + "function (frame, bp_loc, ...) end\n"; + SetPrompt(llvm::StringRef("..> ")); + break; + } + if (instructions == nullptr) return; + if (interactive) + *io_handler.GetOutputStreamFileSP() << instructions; + } + + bool IOHandlerIsInputComplete(IOHandler &io_handler, + StringList &lines) override { + size_t last = lines.GetSize() - 1; + if (IsQuitCommand(lines.GetStringAtIndex(last))) { + if (m_active_io_handler == eIOHandlerBreakpoint || + m_active_io_handler == eIOHandlerWatchpoint) + lines.DeleteStringAtIndex(last); + return true; + } + StreamString str; + lines.Join("\n", str); + if (llvm::Error E = + m_script_interpreter.GetLua().CheckSyntax(str.GetString())) { + std::string error_str = toString(std::move(E)); + // Lua always errors out to incomplete code with '' + return error_str.find("") == std::string::npos; } + // The breakpoint and watchpoint handler only exits with a explicit 'quit' + return m_active_io_handler != eIOHandlerBreakpoint && + m_active_io_handler != eIOHandlerWatchpoint; + } - if (llvm::Error error = m_script_interpreter.GetLua().Run(data)) { - *GetOutputStreamFileSP() << llvm::toString(std::move(error)); + void IOHandlerInputComplete(IOHandler &io_handler, + std::string &data) override { + switch (m_active_io_handler) { + case eIOHandlerBreakpoint: { + auto *bp_options_vec = + static_cast> *>( + io_handler.GetUserData()); + for (BreakpointOptions &bp_options : *bp_options_vec) { + Status error = m_script_interpreter.SetBreakpointCommandCallback( + bp_options, data.c_str()); + if (error.Fail()) + *io_handler.GetErrorStreamFileSP() << error.AsCString() << '\n'; + } + io_handler.SetIsDone(true); + } break; + case eIOHandlerWatchpoint: { + auto *wp_options = + static_cast(io_handler.GetUserData()); + m_script_interpreter.SetWatchpointCommandCallback(wp_options, + data.c_str()); + io_handler.SetIsDone(true); + } break; + case eIOHandlerNone: + if (IsQuitCommand(data)) { + io_handler.SetIsDone(true); + return; + } + if (llvm::Error error = m_script_interpreter.GetLua().Run(data)) + *io_handler.GetErrorStreamFileSP() << toString(std::move(error)); + break; } } private: ScriptInterpreterLua &m_script_interpreter; + ActiveIOHandler m_active_io_handler; + + bool IsQuitCommand(llvm::StringRef cmd) { return cmd.rtrim() == "quit"; } }; ScriptInterpreterLua::ScriptInterpreterLua(Debugger &debugger) : ScriptInterpreter(debugger, eScriptLanguageLua), m_lua(std::make_unique()) {} -ScriptInterpreterLua::~ScriptInterpreterLua() {} +ScriptInterpreterLua::~ScriptInterpreterLua() = default; bool ScriptInterpreterLua::ExecuteOneLine(llvm::StringRef command, CommandReturnObject *result, @@ -107,8 +192,7 @@ bool ScriptInterpreterLua::ExecuteOneLine(llvm::StringRef command, } void ScriptInterpreterLua::ExecuteInterpreterLoop() { - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer(func_cat, LLVM_PRETTY_FUNCTION); + LLDB_SCOPED_TIMER(); // At the moment, the only time the debugger does not have an input file // handle is when this is called directly from lua, in which case it is @@ -123,8 +207,9 @@ void ScriptInterpreterLua::ExecuteInterpreterLoop() { } bool ScriptInterpreterLua::LoadScriptingModule( - const char *filename, bool init_session, lldb_private::Status &error, - StructuredData::ObjectSP *module_sp) { + const char *filename, const LoadScriptOptions &options, + lldb_private::Status &error, StructuredData::ObjectSP *module_sp, + FileSpec extra_search_dir) { FileSystem::Instance().Collect(filename); if (llvm::Error e = m_lua->LoadModule(filename)) { @@ -174,6 +259,129 @@ llvm::Error ScriptInterpreterLua::LeaveSession() { return m_lua->Run(str); } +bool ScriptInterpreterLua::BreakpointCallbackFunction( + void *baton, StoppointCallbackContext *context, user_id_t break_id, + user_id_t break_loc_id) { + assert(context); + + ExecutionContext exe_ctx(context->exe_ctx_ref); + Target *target = exe_ctx.GetTargetPtr(); + if (target == nullptr) + return true; + + StackFrameSP stop_frame_sp(exe_ctx.GetFrameSP()); + BreakpointSP breakpoint_sp = target->GetBreakpointByID(break_id); + BreakpointLocationSP bp_loc_sp(breakpoint_sp->FindLocationByID(break_loc_id)); + + Debugger &debugger = target->GetDebugger(); + ScriptInterpreterLua *lua_interpreter = static_cast( + debugger.GetScriptInterpreter(true, eScriptLanguageLua)); + Lua &lua = lua_interpreter->GetLua(); + + CommandDataLua *bp_option_data = static_cast(baton); + llvm::Expected BoolOrErr = lua.CallBreakpointCallback( + baton, stop_frame_sp, bp_loc_sp, bp_option_data->m_extra_args_sp); + if (llvm::Error E = BoolOrErr.takeError()) { + debugger.GetErrorStream() << toString(std::move(E)); + return true; + } + + return *BoolOrErr; +} + +bool ScriptInterpreterLua::WatchpointCallbackFunction( + void *baton, StoppointCallbackContext *context, user_id_t watch_id) { + assert(context); + + ExecutionContext exe_ctx(context->exe_ctx_ref); + Target *target = exe_ctx.GetTargetPtr(); + if (target == nullptr) + return true; + + StackFrameSP stop_frame_sp(exe_ctx.GetFrameSP()); + WatchpointSP wp_sp = target->GetWatchpointList().FindByID(watch_id); + + Debugger &debugger = target->GetDebugger(); + ScriptInterpreterLua *lua_interpreter = static_cast( + debugger.GetScriptInterpreter(true, eScriptLanguageLua)); + Lua &lua = lua_interpreter->GetLua(); + + llvm::Expected BoolOrErr = + lua.CallWatchpointCallback(baton, stop_frame_sp, wp_sp); + if (llvm::Error E = BoolOrErr.takeError()) { + debugger.GetErrorStream() << toString(std::move(E)); + return true; + } + + return *BoolOrErr; +} + +void ScriptInterpreterLua::CollectDataForBreakpointCommandCallback( + std::vector> &bp_options_vec, + CommandReturnObject &result) { + IOHandlerSP io_handler_sp( + new IOHandlerLuaInterpreter(m_debugger, *this, eIOHandlerBreakpoint)); + io_handler_sp->SetUserData(&bp_options_vec); + m_debugger.RunIOHandlerAsync(io_handler_sp); +} + +void ScriptInterpreterLua::CollectDataForWatchpointCommandCallback( + WatchpointOptions *wp_options, CommandReturnObject &result) { + IOHandlerSP io_handler_sp( + new IOHandlerLuaInterpreter(m_debugger, *this, eIOHandlerWatchpoint)); + io_handler_sp->SetUserData(wp_options); + m_debugger.RunIOHandlerAsync(io_handler_sp); +} + +Status ScriptInterpreterLua::SetBreakpointCommandCallbackFunction( + BreakpointOptions &bp_options, const char *function_name, + StructuredData::ObjectSP extra_args_sp) { + const char *fmt_str = "return {0}(frame, bp_loc, ...)"; + std::string oneliner = llvm::formatv(fmt_str, function_name).str(); + return RegisterBreakpointCallback(bp_options, oneliner.c_str(), + extra_args_sp); +} + +Status ScriptInterpreterLua::SetBreakpointCommandCallback( + BreakpointOptions &bp_options, const char *command_body_text) { + return RegisterBreakpointCallback(bp_options, command_body_text, {}); +} + +Status ScriptInterpreterLua::RegisterBreakpointCallback( + BreakpointOptions &bp_options, const char *command_body_text, + StructuredData::ObjectSP extra_args_sp) { + Status error; + auto data_up = std::make_unique(extra_args_sp); + error = m_lua->RegisterBreakpointCallback(data_up.get(), command_body_text); + if (error.Fail()) + return error; + auto baton_sp = + std::make_shared(std::move(data_up)); + bp_options.SetCallback(ScriptInterpreterLua::BreakpointCallbackFunction, + baton_sp); + return error; +} + +void ScriptInterpreterLua::SetWatchpointCommandCallback( + WatchpointOptions *wp_options, const char *command_body_text) { + RegisterWatchpointCallback(wp_options, command_body_text, {}); +} + +Status ScriptInterpreterLua::RegisterWatchpointCallback( + WatchpointOptions *wp_options, const char *command_body_text, + StructuredData::ObjectSP extra_args_sp) { + Status error; + auto data_up = std::make_unique(); + error = m_lua->RegisterWatchpointCallback(data_up.get(), command_body_text); + if (error.Fail()) + return error; + auto baton_sp = + std::make_shared(std::move(data_up)); + wp_options->SetCallback(ScriptInterpreterLua::WatchpointCallbackFunction, + baton_sp); + return error; +} + lldb::ScriptInterpreterSP ScriptInterpreterLua::CreateInstance(Debugger &debugger) { return std::make_shared(debugger); diff --git a/gnu/llvm/lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.h b/gnu/llvm/lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.h index bcc6ab24f6d..808000b833e 100644 --- a/gnu/llvm/lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.h +++ b/gnu/llvm/lldb/source/Plugins/ScriptInterpreter/Lua/ScriptInterpreterLua.h @@ -9,12 +9,30 @@ #ifndef liblldb_ScriptInterpreterLua_h_ #define liblldb_ScriptInterpreterLua_h_ +#include + +#include "lldb/Breakpoint/WatchpointOptions.h" +#include "lldb/Core/StructuredDataImpl.h" #include "lldb/Interpreter/ScriptInterpreter.h" +#include "lldb/Utility/Status.h" +#include "lldb/lldb-enumerations.h" namespace lldb_private { class Lua; class ScriptInterpreterLua : public ScriptInterpreter { public: + class CommandDataLua : public BreakpointOptions::CommandData { + public: + CommandDataLua() : BreakpointOptions::CommandData() { + interpreter = lldb::eScriptLanguageLua; + } + CommandDataLua(StructuredData::ObjectSP extra_args_sp) + : BreakpointOptions::CommandData(), m_extra_args_sp(extra_args_sp) { + interpreter = lldb::eScriptLanguageLua; + } + StructuredData::ObjectSP m_extra_args_sp; + }; + ScriptInterpreterLua(Debugger &debugger); ~ScriptInterpreterLua() override; @@ -25,10 +43,11 @@ public: void ExecuteInterpreterLoop() override; - bool - LoadScriptingModule(const char *filename, bool init_session, - lldb_private::Status &error, - StructuredData::ObjectSP *module_sp = nullptr) override; + bool LoadScriptingModule(const char *filename, + const LoadScriptOptions &options, + lldb_private::Status &error, + StructuredData::ObjectSP *module_sp = nullptr, + FileSpec extra_search_dir = {}) override; // Static Functions static void Initialize(); @@ -41,6 +60,15 @@ public: static const char *GetPluginDescriptionStatic(); + static bool BreakpointCallbackFunction(void *baton, + StoppointCallbackContext *context, + lldb::user_id_t break_id, + lldb::user_id_t break_loc_id); + + static bool WatchpointCallbackFunction(void *baton, + StoppointCallbackContext *context, + lldb::user_id_t watch_id); + // PluginInterface protocol lldb_private::ConstString GetPluginName() override; @@ -51,9 +79,35 @@ public: llvm::Error EnterSession(lldb::user_id_t debugger_id); llvm::Error LeaveSession(); + void CollectDataForBreakpointCommandCallback( + std::vector> &bp_options_vec, + CommandReturnObject &result) override; + + void + CollectDataForWatchpointCommandCallback(WatchpointOptions *wp_options, + CommandReturnObject &result) override; + + Status SetBreakpointCommandCallback(BreakpointOptions &bp_options, + const char *command_body_text) override; + + void SetWatchpointCommandCallback(WatchpointOptions *wp_options, + const char *command_body_text) override; + + Status SetBreakpointCommandCallbackFunction( + BreakpointOptions &bp_options, const char *function_name, + StructuredData::ObjectSP extra_args_sp) override; + private: std::unique_ptr m_lua; bool m_session_is_active = false; + + Status RegisterBreakpointCallback(BreakpointOptions &bp_options, + const char *command_body_text, + StructuredData::ObjectSP extra_args_sp); + + Status RegisterWatchpointCallback(WatchpointOptions *wp_options, + const char *command_body_text, + StructuredData::ObjectSP extra_args_sp); }; } // namespace lldb_private diff --git a/gnu/llvm/lldb/source/Plugins/ScriptInterpreter/None/CMakeLists.txt b/gnu/llvm/lldb/source/Plugins/ScriptInterpreter/None/CMakeLists.txt index 7e7dd5896f7..ce4fb4f9c0a 100644 --- a/gnu/llvm/lldb/source/Plugins/ScriptInterpreter/None/CMakeLists.txt +++ b/gnu/llvm/lldb/source/Plugins/ScriptInterpreter/None/CMakeLists.txt @@ -4,4 +4,4 @@ add_lldb_library(lldbPluginScriptInterpreterNone PLUGIN LINK_LIBS lldbCore lldbInterpreter - ) \ No newline at end of file + ) diff --git a/gnu/llvm/lldb/source/Plugins/ScriptInterpreter/None/ScriptInterpreterNone.cpp b/gnu/llvm/lldb/source/Plugins/ScriptInterpreter/None/ScriptInterpreterNone.cpp index d9c32cc132d..f8a385240bd 100644 --- a/gnu/llvm/lldb/source/Plugins/ScriptInterpreter/None/ScriptInterpreterNone.cpp +++ b/gnu/llvm/lldb/source/Plugins/ScriptInterpreter/None/ScriptInterpreterNone.cpp @@ -25,7 +25,7 @@ LLDB_PLUGIN_DEFINE(ScriptInterpreterNone) ScriptInterpreterNone::ScriptInterpreterNone(Debugger &debugger) : ScriptInterpreter(debugger, eScriptLanguageNone) {} -ScriptInterpreterNone::~ScriptInterpreterNone() {} +ScriptInterpreterNone::~ScriptInterpreterNone() = default; bool ScriptInterpreterNone::ExecuteOneLine(llvm::StringRef command, CommandReturnObject *, diff --git a/gnu/llvm/lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt b/gnu/llvm/lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt index 761772f3a37..84115aae01a 100644 --- a/gnu/llvm/lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt +++ b/gnu/llvm/lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt @@ -11,6 +11,8 @@ add_lldb_library(lldbPluginScriptInterpreterPython PLUGIN PythonDataObjects.cpp PythonReadline.cpp ScriptInterpreterPython.cpp + ScriptedProcessPythonInterface.cpp + SWIGPythonBridge.cpp LINK_LIBS lldbBreakpoint @@ -19,7 +21,7 @@ add_lldb_library(lldbPluginScriptInterpreterPython PLUGIN lldbHost lldbInterpreter lldbTarget - ${PYTHON_LIBRARIES} + ${Python3_LIBRARIES} ${LLDB_LIBEDIT_LIBS} LINK_COMPONENTS diff --git a/gnu/llvm/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp b/gnu/llvm/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp index 6f040fdef09..f51d9b3a796 100644 --- a/gnu/llvm/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp +++ b/gnu/llvm/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp @@ -24,7 +24,7 @@ #include "llvm/Support/ConvertUTF.h" #include "llvm/Support/Errno.h" -#include +#include using namespace lldb_private; using namespace lldb; @@ -451,7 +451,11 @@ Expected PythonString::AsUTF8() const { size_t PythonString::GetSize() const { if (IsValid()) { #if PY_MAJOR_VERSION >= 3 +#if PY_MINOR_VERSION >= 3 + return PyUnicode_GetLength(m_py_obj); +#else return PyUnicode_GetSize(m_py_obj); +#endif #else return PyString_Size(m_py_obj); #endif diff --git a/gnu/llvm/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h b/gnu/llvm/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h index 22f6c67eb7a..4577253227c 100644 --- a/gnu/llvm/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h +++ b/gnu/llvm/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.h @@ -229,7 +229,7 @@ struct PythonFormat< class PythonObject { public: - PythonObject() : m_py_obj(nullptr) {} + PythonObject() = default; PythonObject(PyRefType type, PyObject *py_obj) { m_py_obj = py_obj; @@ -378,7 +378,7 @@ public: } protected: - PyObject *m_py_obj; + PyObject *m_py_obj = nullptr; }; @@ -421,7 +421,7 @@ public: Py_DECREF(py_obj); } - TypedPythonObject() {} + TypedPythonObject() = default; }; class PythonBytes : public TypedPythonObject { diff --git a/gnu/llvm/lldb/source/Plugins/ScriptInterpreter/Python/PythonReadline.cpp b/gnu/llvm/lldb/source/Plugins/ScriptInterpreter/Python/PythonReadline.cpp index 5f6429f5cd0..95a3365ed98 100644 --- a/gnu/llvm/lldb/source/Plugins/ScriptInterpreter/Python/PythonReadline.cpp +++ b/gnu/llvm/lldb/source/Plugins/ScriptInterpreter/Python/PythonReadline.cpp @@ -2,7 +2,7 @@ #ifdef LLDB_USE_LIBEDIT_READLINE_COMPAT_MODULE -#include +#include #include diff --git a/gnu/llvm/lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.cpp b/gnu/llvm/lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.cpp new file mode 100644 index 00000000000..7c7c5d73680 --- /dev/null +++ b/gnu/llvm/lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.cpp @@ -0,0 +1,48 @@ +//===-- SWIGPythonBridge.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 "lldb/Host/Config.h" +#include "lldb/lldb-enumerations.h" + +#if LLDB_ENABLE_PYTHON + +// LLDB Python header must be included first +#include "lldb-python.h" + +#include "SWIGPythonBridge.h" + +using namespace lldb; + +namespace lldb_private { + +template const char *GetPythonValueFormatString(T t); +template <> const char *GetPythonValueFormatString(char *) { return "s"; } +template <> const char *GetPythonValueFormatString(char) { return "b"; } +template <> const char *GetPythonValueFormatString(unsigned char) { + return "B"; +} +template <> const char *GetPythonValueFormatString(short) { return "h"; } +template <> const char *GetPythonValueFormatString(unsigned short) { + return "H"; +} +template <> const char *GetPythonValueFormatString(int) { return "i"; } +template <> const char *GetPythonValueFormatString(unsigned int) { return "I"; } +template <> const char *GetPythonValueFormatString(long) { return "l"; } +template <> const char *GetPythonValueFormatString(unsigned long) { + return "k"; +} +template <> const char *GetPythonValueFormatString(long long) { return "L"; } +template <> const char *GetPythonValueFormatString(unsigned long long) { + return "K"; +} +template <> const char *GetPythonValueFormatString(float) { return "f"; } +template <> const char *GetPythonValueFormatString(double) { return "d"; } + +} // namespace lldb_private + +#endif // LLDB_ENABLE_PYTHON diff --git a/gnu/llvm/lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h b/gnu/llvm/lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h new file mode 100644 index 00000000000..1ef792bcf30 --- /dev/null +++ b/gnu/llvm/lldb/source/Plugins/ScriptInterpreter/Python/SWIGPythonBridge.h @@ -0,0 +1,56 @@ +//===-- ScriptInterpreterPython.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_SWIGPYTHONBRIDGE_H +#define LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_SWIGPYTHONBRIDGE_H + +#include + +#include "lldb/Host/Config.h" + +#if LLDB_ENABLE_PYTHON + +#include "lldb/lldb-forward.h" +#include "lldb/lldb-types.h" + +namespace lldb_private { + +// GetPythonValueFormatString provides a system independent type safe way to +// convert a variable's type into a python value format. Python value formats +// are defined in terms of builtin C types and could change from system to as +// the underlying typedef for uint* types, size_t, off_t and other values +// change. + +template const char *GetPythonValueFormatString(T t); +template <> const char *GetPythonValueFormatString(char *); +template <> const char *GetPythonValueFormatString(char); +template <> const char *GetPythonValueFormatString(unsigned char); +template <> const char *GetPythonValueFormatString(short); +template <> const char *GetPythonValueFormatString(unsigned short); +template <> const char *GetPythonValueFormatString(int); +template <> const char *GetPythonValueFormatString(unsigned int); +template <> const char *GetPythonValueFormatString(long); +template <> const char *GetPythonValueFormatString(unsigned long); +template <> const char *GetPythonValueFormatString(long long); +template <> const char *GetPythonValueFormatString(unsigned long long); +template <> const char *GetPythonValueFormatString(float t); +template <> const char *GetPythonValueFormatString(double t); + +extern "C" void *LLDBSwigPythonCreateScriptedProcess( + const char *python_class_name, const char *session_dictionary_name, + const lldb::TargetSP &target_sp, StructuredDataImpl *args_impl, + std::string &error_string); + +extern "C" void *LLDBSWIGPython_CastPyObjectToSBData(void *data); +extern "C" void *LLDBSWIGPython_CastPyObjectToSBError(void *data); +extern "C" void *LLDBSWIGPython_CastPyObjectToSBValue(void *data); + +} // namespace lldb_private + +#endif // LLDB_ENABLE_PYTHON +#endif // LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_SWIGPYTHONBRIDGE_H diff --git a/gnu/llvm/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp b/gnu/llvm/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp index 9f56b4fa60a..7ad63722c31 100644 --- a/gnu/llvm/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp +++ b/gnu/llvm/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "lldb/Host/Config.h" +#include "lldb/lldb-enumerations.h" #if LLDB_ENABLE_PYTHON @@ -15,7 +16,11 @@ #include "PythonDataObjects.h" #include "PythonReadline.h" +#include "SWIGPythonBridge.h" #include "ScriptInterpreterPythonImpl.h" +#include "ScriptedProcessPythonInterface.h" + +#include "lldb/API/SBError.h" #include "lldb/API/SBFrame.h" #include "lldb/API/SBValue.h" #include "lldb/Breakpoint/StoppointCallbackContext.h" @@ -32,6 +37,7 @@ #include "lldb/Interpreter/CommandReturnObject.h" #include "lldb/Target/Thread.h" #include "lldb/Target/ThreadPlan.h" +#include "lldb/Utility/ReproducerInstrumentation.h" #include "lldb/Utility/Timer.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringRef.h" @@ -39,10 +45,10 @@ #include "llvm/Support/FileSystem.h" #include "llvm/Support/FormatAdapters.h" +#include +#include #include #include -#include -#include #include using namespace lldb; @@ -127,6 +133,16 @@ extern "C" unsigned int LLDBSwigPythonCallBreakpointResolver(void *implementor, const char *method_name, lldb_private::SymbolContext *sym_ctx); +extern "C" void *LLDBSwigPythonCreateScriptedStopHook( + TargetSP target_sp, const char *python_class_name, + const char *session_dictionary_name, lldb_private::StructuredDataImpl *args, + lldb_private::Status &error); + +extern "C" bool +LLDBSwigPythonStopHookCallHandleStop(void *implementor, + lldb::ExecutionContextRefSP exc_ctx, + lldb::StreamSP stream); + extern "C" size_t LLDBSwigPython_CalculateNumChildren(void *implementor, uint32_t max); @@ -136,8 +152,6 @@ extern "C" void *LLDBSwigPython_GetChildAtIndex(void *implementor, extern "C" int LLDBSwigPython_GetIndexOfChildWithName(void *implementor, const char *child_name); -extern "C" void *LLDBSWIGPython_CastPyObjectToSBValue(void *data); - extern lldb::ValueObjectSP LLDBSWIGPython_GetValueObjectSPFromSBValue(void *data); @@ -204,6 +218,12 @@ extern "C" void * LLDBSWIGPython_GetDynamicSetting(void *module, const char *setting, const lldb::TargetSP &target_sp); +static ScriptInterpreterPythonImpl *GetPythonInterpreter(Debugger &debugger) { + ScriptInterpreter *script_interpreter = + debugger.GetScriptInterpreter(true, lldb::eScriptLanguagePython); + return static_cast(script_interpreter); +} + static bool g_initialized = false; namespace { @@ -216,8 +236,7 @@ namespace { // save off initial state at the beginning, and restore it at the end struct InitializePythonRAII { public: - InitializePythonRAII() - : m_gil_state(PyGILState_UNLOCKED), m_was_already_initialized(false) { + InitializePythonRAII() { InitializePythonHome(); #ifdef LLDB_USE_LIBEDIT_READLINE_COMPAT_MODULE @@ -337,8 +356,8 @@ private: } TerminalState m_stdin_tty_state; - PyGILState_STATE m_gil_state; - bool m_was_already_initialized; + PyGILState_STATE m_gil_state = PyGILState_UNLOCKED; + bool m_was_already_initialized = false; }; } // namespace @@ -392,6 +411,32 @@ FileSpec ScriptInterpreterPython::GetPythonDir() { return g_spec; } +void ScriptInterpreterPython::SharedLibraryDirectoryHelper( + FileSpec &this_file) { + // When we're loaded from python, this_file will point to the file inside the + // python package directory. Replace it with the one in the lib directory. +#ifdef _WIN32 + // On windows, we need to manually back out of the python tree, and go into + // the bin directory. This is pretty much the inverse of what ComputePythonDir + // does. + if (this_file.GetFileNameExtension() == ConstString(".pyd")) { + this_file.RemoveLastPathComponent(); // _lldb.pyd or _lldb_d.pyd + this_file.RemoveLastPathComponent(); // lldb + llvm::StringRef libdir = LLDB_PYTHON_RELATIVE_LIBDIR; + for (auto it = llvm::sys::path::begin(libdir), + end = llvm::sys::path::end(libdir); + it != end; ++it) + this_file.RemoveLastPathComponent(); + this_file.AppendPathComponent("bin"); + this_file.AppendPathComponent("liblldb.dll"); + } +#else + // The python file is a symlink, so we can find the real library by resolving + // it. We can do this unconditionally. + FileSystem::Instance().ResolveSymbolicLink(this_file, this_file); +#endif +} + lldb_private::ConstString ScriptInterpreterPython::GetPluginNameStatic() { static ConstString g_name("script-python"); return g_name; @@ -420,6 +465,7 @@ ScriptInterpreterPythonImpl::Locker::Locker( : ScriptInterpreterLocker(), m_teardown_session((on_leave & TearDownSession) == TearDownSession), m_python_interpreter(py_interpreter) { + repro::Recorder::PrivateThread(); DoAcquireLock(); if ((on_entry & InitSession) == InitSession) { if (!DoInitSession(on_entry, in, out, err)) { @@ -487,6 +533,9 @@ ScriptInterpreterPythonImpl::ScriptInterpreterPythonImpl(Debugger &debugger) m_command_thread_state(nullptr) { InitializePrivate(); + m_scripted_process_interface_up = + std::make_unique(*this); + m_dictionary_name.append("_dict"); StreamString run_string; run_string.Printf("%s = dict()", m_dictionary_name.c_str()); @@ -586,11 +635,10 @@ void ScriptInterpreterPythonImpl::IOHandlerInputComplete(IOHandler &io_handler, case eIOHandlerNone: break; case eIOHandlerBreakpoint: { - std::vector *bp_options_vec = - (std::vector *)io_handler.GetUserData(); - for (auto bp_options : *bp_options_vec) { - if (!bp_options) - continue; + std::vector> *bp_options_vec = + (std::vector> *) + io_handler.GetUserData(); + for (BreakpointOptions &bp_options : *bp_options_vec) { auto data_up = std::make_unique(); if (!data_up) @@ -604,7 +652,7 @@ void ScriptInterpreterPythonImpl::IOHandlerInputComplete(IOHandler &io_handler, .Success()) { auto baton_sp = std::make_shared( std::move(data_up)); - bp_options->SetCallback( + bp_options.SetCallback( ScriptInterpreterPythonImpl::BreakpointCallbackFunction, baton_sp); } else if (!batch_mode) { StreamFileSP error_sp = io_handler.GetErrorStreamFileSP(); @@ -982,8 +1030,7 @@ bool ScriptInterpreterPythonImpl::ExecuteOneLine( } void ScriptInterpreterPythonImpl::ExecuteInterpreterLoop() { - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer(func_cat, LLVM_PRETTY_FUNCTION); + LLDB_SCOPED_TIMER(); Debugger &debugger = m_debugger; @@ -1030,11 +1077,24 @@ bool ScriptInterpreterPythonImpl::ExecuteOneLineWithReturn( llvm::StringRef in_string, ScriptInterpreter::ScriptReturnType return_type, void *ret_value, const ExecuteScriptOptions &options) { + llvm::Expected> + io_redirect_or_error = ScriptInterpreterIORedirect::Create( + options.GetEnableIO(), m_debugger, /*result=*/nullptr); + + if (!io_redirect_or_error) { + llvm::consumeError(io_redirect_or_error.takeError()); + return false; + } + + ScriptInterpreterIORedirect &io_redirect = **io_redirect_or_error; + Locker locker(this, Locker::AcquireLock | Locker::InitSession | (options.GetSetLLDBGlobals() ? Locker::InitGlobals : 0) | Locker::NoSTDIN, - Locker::FreeAcquiredLock | Locker::TearDownSession); + Locker::FreeAcquiredLock | Locker::TearDownSession, + io_redirect.GetInputFile(), io_redirect.GetOutputFile(), + io_redirect.GetErrorFile()); PythonModule &main_module = GetMainModule(); PythonDictionary globals = main_module.GetDictionary(); @@ -1143,11 +1203,22 @@ Status ScriptInterpreterPythonImpl::ExecuteMultipleLines( if (in_string == nullptr) return Status(); + llvm::Expected> + io_redirect_or_error = ScriptInterpreterIORedirect::Create( + options.GetEnableIO(), m_debugger, /*result=*/nullptr); + + if (!io_redirect_or_error) + return Status(io_redirect_or_error.takeError()); + + ScriptInterpreterIORedirect &io_redirect = **io_redirect_or_error; + Locker locker(this, Locker::AcquireLock | Locker::InitSession | (options.GetSetLLDBGlobals() ? Locker::InitGlobals : 0) | Locker::NoSTDIN, - Locker::FreeAcquiredLock | Locker::TearDownSession); + Locker::FreeAcquiredLock | Locker::TearDownSession, + io_redirect.GetInputFile(), io_redirect.GetOutputFile(), + io_redirect.GetErrorFile()); PythonModule &main_module = GetMainModule(); PythonDictionary globals = main_module.GetDictionary(); @@ -1178,7 +1249,7 @@ Status ScriptInterpreterPythonImpl::ExecuteMultipleLines( } void ScriptInterpreterPythonImpl::CollectDataForBreakpointCommandCallback( - std::vector &bp_options_vec, + std::vector> &bp_options_vec, CommandReturnObject &result) { m_active_io_handler = eIOHandlerBreakpoint; m_debugger.GetCommandInterpreter().GetPythonCommandsFromIOHandler( @@ -1193,7 +1264,7 @@ void ScriptInterpreterPythonImpl::CollectDataForWatchpointCommandCallback( } Status ScriptInterpreterPythonImpl::SetBreakpointCommandCallbackFunction( - BreakpointOptions *bp_options, const char *function_name, + BreakpointOptions &bp_options, const char *function_name, StructuredData::ObjectSP extra_args_sp) { Status error; // For now just cons up a oneliner that calls the provided function. @@ -1235,7 +1306,7 @@ Status ScriptInterpreterPythonImpl::SetBreakpointCommandCallbackFunction( } Status ScriptInterpreterPythonImpl::SetBreakpointCommandCallback( - BreakpointOptions *bp_options, + BreakpointOptions &bp_options, std::unique_ptr &cmd_data_up) { Status error; error = GenerateBreakpointCommandCallbackData(cmd_data_up->user_source, @@ -1246,21 +1317,20 @@ Status ScriptInterpreterPythonImpl::SetBreakpointCommandCallback( } auto baton_sp = std::make_shared(std::move(cmd_data_up)); - bp_options->SetCallback( + bp_options.SetCallback( ScriptInterpreterPythonImpl::BreakpointCallbackFunction, baton_sp); return error; } Status ScriptInterpreterPythonImpl::SetBreakpointCommandCallback( - BreakpointOptions *bp_options, const char *command_body_text) { + BreakpointOptions &bp_options, const char *command_body_text) { return SetBreakpointCommandCallback(bp_options, command_body_text, {},false); } // Set a Python one-liner as the callback for the breakpoint. Status ScriptInterpreterPythonImpl::SetBreakpointCommandCallback( - BreakpointOptions *bp_options, const char *command_body_text, - StructuredData::ObjectSP extra_args_sp, - bool uses_extra_args) { + BreakpointOptions &bp_options, const char *command_body_text, + StructuredData::ObjectSP extra_args_sp, bool uses_extra_args) { auto data_up = std::make_unique(extra_args_sp); // Split the command_body_text into lines, and pass that to // GenerateBreakpointCommandCallbackData. That will wrap the body in an @@ -1274,7 +1344,7 @@ Status ScriptInterpreterPythonImpl::SetBreakpointCommandCallback( if (error.Success()) { auto baton_sp = std::make_shared(std::move(data_up)); - bp_options->SetCallback( + bp_options.SetCallback( ScriptInterpreterPythonImpl::BreakpointCallbackFunction, baton_sp); return error; } @@ -1312,7 +1382,7 @@ Status ScriptInterpreterPythonImpl::ExportFunctionDefinitionToInterpreter( Status error = ExecuteMultipleLines( function_def_string.c_str(), - ScriptInterpreter::ExecuteScriptOptions().SetEnableIO(false)); + ExecuteScriptOptions().SetEnableIO(false)); return error; } @@ -1660,35 +1730,6 @@ StructuredData::ArraySP ScriptInterpreterPythonImpl::OSPlugin_ThreadsInfo( return StructuredData::ArraySP(); } -// GetPythonValueFormatString provides a system independent type safe way to -// convert a variable's type into a python value format. Python value formats -// are defined in terms of builtin C types and could change from system to as -// the underlying typedef for uint* types, size_t, off_t and other values -// change. - -template const char *GetPythonValueFormatString(T t); -template <> const char *GetPythonValueFormatString(char *) { return "s"; } -template <> const char *GetPythonValueFormatString(char) { return "b"; } -template <> const char *GetPythonValueFormatString(unsigned char) { - return "B"; -} -template <> const char *GetPythonValueFormatString(short) { return "h"; } -template <> const char *GetPythonValueFormatString(unsigned short) { - return "H"; -} -template <> const char *GetPythonValueFormatString(int) { return "i"; } -template <> const char *GetPythonValueFormatString(unsigned int) { return "I"; } -template <> const char *GetPythonValueFormatString(long) { return "l"; } -template <> const char *GetPythonValueFormatString(unsigned long) { - return "k"; -} -template <> const char *GetPythonValueFormatString(long long) { return "L"; } -template <> const char *GetPythonValueFormatString(unsigned long long) { - return "K"; -} -template <> const char *GetPythonValueFormatString(float t) { return "f"; } -template <> const char *GetPythonValueFormatString(double t) { return "d"; } - StructuredData::StringSP ScriptInterpreterPythonImpl::OSPlugin_RegisterContextData( StructuredData::ObjectSP os_plugin_object_sp, lldb::tid_t tid) { @@ -1815,11 +1856,10 @@ StructuredData::ObjectSP ScriptInterpreterPythonImpl::CreateScriptedThreadPlan( return {}; Debugger &debugger = thread_plan_sp->GetTarget().GetDebugger(); - ScriptInterpreter *script_interpreter = debugger.GetScriptInterpreter(); ScriptInterpreterPythonImpl *python_interpreter = - static_cast(script_interpreter); + GetPythonInterpreter(debugger); - if (!script_interpreter) + if (!python_interpreter) return {}; void *ret_val; @@ -1919,11 +1959,10 @@ ScriptInterpreterPythonImpl::CreateScriptedBreakpointResolver( return StructuredData::GenericSP(); Debugger &debugger = bkpt_sp->GetTarget().GetDebugger(); - ScriptInterpreter *script_interpreter = debugger.GetScriptInterpreter(); ScriptInterpreterPythonImpl *python_interpreter = - static_cast(script_interpreter); + GetPythonInterpreter(debugger); - if (!script_interpreter) + if (!python_interpreter) return StructuredData::GenericSP(); void *ret_val; @@ -1979,6 +2018,59 @@ ScriptInterpreterPythonImpl::ScriptedBreakpointResolverSearchDepth( return lldb::eSearchDepthModule; } +StructuredData::GenericSP ScriptInterpreterPythonImpl::CreateScriptedStopHook( + TargetSP target_sp, const char *class_name, StructuredDataImpl *args_data, + Status &error) { + + if (!target_sp) { + error.SetErrorString("No target for scripted stop-hook."); + return StructuredData::GenericSP(); + } + + if (class_name == nullptr || class_name[0] == '\0') { + error.SetErrorString("No class name for scripted stop-hook."); + return StructuredData::GenericSP(); + } + + ScriptInterpreterPythonImpl *python_interpreter = + GetPythonInterpreter(m_debugger); + + if (!python_interpreter) { + error.SetErrorString("No script interpreter for scripted stop-hook."); + return StructuredData::GenericSP(); + } + + void *ret_val; + + { + Locker py_lock(this, + Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); + + ret_val = LLDBSwigPythonCreateScriptedStopHook( + target_sp, class_name, python_interpreter->m_dictionary_name.c_str(), + args_data, error); + } + + return StructuredData::GenericSP(new StructuredPythonObject(ret_val)); +} + +bool ScriptInterpreterPythonImpl::ScriptedStopHookHandleStop( + StructuredData::GenericSP implementor_sp, ExecutionContext &exc_ctx, + lldb::StreamSP stream_sp) { + assert(implementor_sp && + "can't call a stop hook with an invalid implementor"); + assert(stream_sp && "can't call a stop hook with an invalid stream"); + + Locker py_lock(this, + Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); + + lldb::ExecutionContextRefSP exc_ctx_ref_sp(new ExecutionContextRef(exc_ctx)); + + bool ret_val = LLDBSwigPythonStopHookCallHandleStop( + implementor_sp->GetValue(), exc_ctx_ref_sp, stream_sp); + return ret_val; +} + StructuredData::ObjectSP ScriptInterpreterPythonImpl::LoadPluginModule(const FileSpec &file_spec, lldb_private::Status &error) { @@ -1989,7 +2081,10 @@ ScriptInterpreterPythonImpl::LoadPluginModule(const FileSpec &file_spec, StructuredData::ObjectSP module_sp; - if (LoadScriptingModule(file_spec.GetPath().c_str(), true, error, &module_sp)) + LoadScriptOptions load_script_options = + LoadScriptOptions().SetInitSession(true).SetSilent(false); + if (LoadScriptingModule(file_spec.GetPath().c_str(), load_script_options, + error, &module_sp)) return module_sp; return StructuredData::ObjectSP(); @@ -2039,11 +2134,10 @@ ScriptInterpreterPythonImpl::CreateSyntheticScriptedProvider( return StructuredData::ObjectSP(); Debugger &debugger = target->GetDebugger(); - ScriptInterpreter *script_interpreter = debugger.GetScriptInterpreter(); ScriptInterpreterPythonImpl *python_interpreter = - (ScriptInterpreterPythonImpl *)script_interpreter; + GetPythonInterpreter(debugger); - if (!script_interpreter) + if (!python_interpreter) return StructuredData::ObjectSP(); void *ret_val = nullptr; @@ -2151,8 +2245,7 @@ bool ScriptInterpreterPythonImpl::GetScriptedSummary( StructuredData::ObjectSP &callee_wrapper_sp, const TypeSummaryOptions &options, std::string &retval) { - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer(func_cat, LLVM_PRETTY_FUNCTION); + LLDB_SCOPED_TIMER(); if (!valobj.get()) { retval.assign(""); @@ -2210,11 +2303,10 @@ bool ScriptInterpreterPythonImpl::BreakpointCallbackFunction( return true; Debugger &debugger = target->GetDebugger(); - ScriptInterpreter *script_interpreter = debugger.GetScriptInterpreter(); ScriptInterpreterPythonImpl *python_interpreter = - (ScriptInterpreterPythonImpl *)script_interpreter; + GetPythonInterpreter(debugger); - if (!script_interpreter) + if (!python_interpreter) return true; if (python_function_name && python_function_name[0]) { @@ -2276,11 +2368,10 @@ bool ScriptInterpreterPythonImpl::WatchpointCallbackFunction( return true; Debugger &debugger = target->GetDebugger(); - ScriptInterpreter *script_interpreter = debugger.GetScriptInterpreter(); ScriptInterpreterPythonImpl *python_interpreter = - (ScriptInterpreterPythonImpl *)script_interpreter; + GetPythonInterpreter(debugger); - if (!script_interpreter) + if (!python_interpreter) return true; if (python_function_name && python_function_name[0]) { @@ -2668,33 +2759,82 @@ uint64_t replace_all(std::string &str, const std::string &oldStr, } bool ScriptInterpreterPythonImpl::LoadScriptingModule( - const char *pathname, bool init_session, lldb_private::Status &error, - StructuredData::ObjectSP *module_sp) { + const char *pathname, const LoadScriptOptions &options, + lldb_private::Status &error, StructuredData::ObjectSP *module_sp, + FileSpec extra_search_dir) { + namespace fs = llvm::sys::fs; + namespace path = llvm::sys::path; + + ExecuteScriptOptions exc_options = ExecuteScriptOptions() + .SetEnableIO(!options.GetSilent()) + .SetSetLLDBGlobals(false); + if (!pathname || !pathname[0]) { error.SetErrorString("invalid pathname"); return false; } + llvm::Expected> + io_redirect_or_error = ScriptInterpreterIORedirect::Create( + exc_options.GetEnableIO(), m_debugger, /*result=*/nullptr); + + if (!io_redirect_or_error) { + error = io_redirect_or_error.takeError(); + return false; + } + + ScriptInterpreterIORedirect &io_redirect = **io_redirect_or_error; lldb::DebuggerSP debugger_sp = m_debugger.shared_from_this(); - { - FileSpec target_file(pathname); - FileSystem::Instance().Resolve(target_file); - FileSystem::Instance().Collect(target_file); - std::string basename(target_file.GetFilename().GetCString()); + // Before executing Python code, lock the GIL. + Locker py_lock(this, + Locker::AcquireLock | + (options.GetInitSession() ? Locker::InitSession : 0) | + Locker::NoSTDIN, + Locker::FreeAcquiredLock | + (options.GetInitSession() ? Locker::TearDownSession : 0), + io_redirect.GetInputFile(), io_redirect.GetOutputFile(), + io_redirect.GetErrorFile()); + + auto ExtendSysPath = [&](std::string directory) -> llvm::Error { + if (directory.empty()) { + return llvm::make_error( + "invalid directory name", llvm::inconvertibleErrorCode()); + } + replace_all(directory, "\\", "\\\\"); + replace_all(directory, "'", "\\'"); + + // Make sure that Python has "directory" in the search path. StreamString command_stream; + command_stream.Printf("if not (sys.path.__contains__('%s')):\n " + "sys.path.insert(1,'%s');\n\n", + directory.c_str(), directory.c_str()); + bool syspath_retval = + ExecuteMultipleLines(command_stream.GetData(), exc_options).Success(); + if (!syspath_retval) { + return llvm::make_error( + "Python sys.path handling failed", llvm::inconvertibleErrorCode()); + } + + return llvm::Error::success(); + }; + + std::string module_name(pathname); + bool possible_package = false; + + if (extra_search_dir) { + if (llvm::Error e = ExtendSysPath(extra_search_dir.GetPath())) { + error = std::move(e); + return false; + } + } else { + FileSpec module_file(pathname); + FileSystem::Instance().Resolve(module_file); + FileSystem::Instance().Collect(module_file); - // Before executing Python code, lock the GIL. - Locker py_lock(this, - Locker::AcquireLock | - (init_session ? Locker::InitSession : 0) | - Locker::NoSTDIN, - Locker::FreeAcquiredLock | - (init_session ? Locker::TearDownSession : 0)); - namespace fs = llvm::sys::fs; fs::file_status st; - std::error_code ec = status(target_file.GetPath(), st); + std::error_code ec = status(module_file.GetPath(), st); if (ec || st.type() == fs::file_type::status_error || st.type() == fs::file_type::type_unknown || @@ -2705,113 +2845,101 @@ bool ScriptInterpreterPythonImpl::LoadScriptingModule( error.SetErrorString("invalid pathname"); return false; } - basename = pathname; // not a filename, probably a package of some sort, - // let it go through + // Not a filename, probably a package of some sort, let it go through. + possible_package = true; } else if (is_directory(st) || is_regular_file(st)) { - if (target_file.GetDirectory().IsEmpty()) { + if (module_file.GetDirectory().IsEmpty()) { error.SetErrorString("invalid directory name"); return false; } - - std::string directory = target_file.GetDirectory().GetCString(); - replace_all(directory, "\\", "\\\\"); - replace_all(directory, "'", "\\'"); - - // now make sure that Python has "directory" in the search path - StreamString command_stream; - command_stream.Printf("if not (sys.path.__contains__('%s')):\n " - "sys.path.insert(1,'%s');\n\n", - directory.c_str(), directory.c_str()); - bool syspath_retval = - ExecuteMultipleLines(command_stream.GetData(), - ScriptInterpreter::ExecuteScriptOptions() - .SetEnableIO(false) - .SetSetLLDBGlobals(false)) - .Success(); - if (!syspath_retval) { - error.SetErrorString("Python sys.path handling failed"); + if (llvm::Error e = + ExtendSysPath(module_file.GetDirectory().GetCString())) { + error = std::move(e); return false; } - - // strip .py or .pyc extension - ConstString extension = target_file.GetFileNameExtension(); - if (extension) { - if (llvm::StringRef(extension.GetCString()) == ".py") - basename.resize(basename.length() - 3); - else if (llvm::StringRef(extension.GetCString()) == ".pyc") - basename.resize(basename.length() - 4); - } + module_name = module_file.GetFilename().GetCString(); } else { error.SetErrorString("no known way to import this module specification"); return false; } + } - // check if the module is already import-ed - command_stream.Clear(); - command_stream.Printf("sys.modules.__contains__('%s')", basename.c_str()); - bool does_contain = false; - // this call will succeed if the module was ever imported in any Debugger - // in the lifetime of the process in which this LLDB framework is living - bool was_imported_globally = - (ExecuteOneLineWithReturn( - command_stream.GetData(), - ScriptInterpreterPythonImpl::eScriptReturnTypeBool, &does_contain, - ScriptInterpreter::ExecuteScriptOptions() - .SetEnableIO(false) - .SetSetLLDBGlobals(false)) && - does_contain); - // this call will fail if the module was not imported in this Debugger - // before - command_stream.Clear(); - command_stream.Printf("sys.getrefcount(%s)", basename.c_str()); - bool was_imported_locally = GetSessionDictionary() - .GetItemForKey(PythonString(basename)) - .IsAllocated(); - - bool was_imported = (was_imported_globally || was_imported_locally); + // Strip .py or .pyc extension + llvm::StringRef extension = llvm::sys::path::extension(module_name); + if (!extension.empty()) { + if (extension == ".py") + module_name.resize(module_name.length() - 3); + else if (extension == ".pyc") + module_name.resize(module_name.length() - 4); + } - // now actually do the import - command_stream.Clear(); + if (!possible_package && module_name.find('.') != llvm::StringRef::npos) { + error.SetErrorStringWithFormat( + "Python does not allow dots in module names: %s", module_name.c_str()); + return false; + } - if (was_imported) { - if (!was_imported_locally) - command_stream.Printf("import %s ; reload_module(%s)", basename.c_str(), - basename.c_str()); - else - command_stream.Printf("reload_module(%s)", basename.c_str()); - } else - command_stream.Printf("import %s", basename.c_str()); - - error = ExecuteMultipleLines(command_stream.GetData(), - ScriptInterpreter::ExecuteScriptOptions() - .SetEnableIO(false) - .SetSetLLDBGlobals(false)); - if (error.Fail()) - return false; + if (module_name.find('-') != llvm::StringRef::npos) { + error.SetErrorStringWithFormat( + "Python discourages dashes in module names: %s", module_name.c_str()); + return false; + } - // if we are here, everything worked - // call __lldb_init_module(debugger,dict) - if (!LLDBSwigPythonCallModuleInit(basename.c_str(), - m_dictionary_name.c_str(), debugger_sp)) { - error.SetErrorString("calling __lldb_init_module failed"); - return false; - } + // Check if the module is already imported. + StreamString command_stream; + command_stream.Clear(); + command_stream.Printf("sys.modules.__contains__('%s')", module_name.c_str()); + bool does_contain = false; + // This call will succeed if the module was ever imported in any Debugger in + // the lifetime of the process in which this LLDB framework is living. + const bool does_contain_executed = ExecuteOneLineWithReturn( + command_stream.GetData(), + ScriptInterpreterPythonImpl::eScriptReturnTypeBool, &does_contain, exc_options); + + const bool was_imported_globally = does_contain_executed && does_contain; + const bool was_imported_locally = + GetSessionDictionary() + .GetItemForKey(PythonString(module_name)) + .IsAllocated(); + + // now actually do the import + command_stream.Clear(); + + if (was_imported_globally || was_imported_locally) { + if (!was_imported_locally) + command_stream.Printf("import %s ; reload_module(%s)", + module_name.c_str(), module_name.c_str()); + else + command_stream.Printf("reload_module(%s)", module_name.c_str()); + } else + command_stream.Printf("import %s", module_name.c_str()); + + error = ExecuteMultipleLines(command_stream.GetData(), exc_options); + if (error.Fail()) + return false; - if (module_sp) { - // everything went just great, now set the module object - command_stream.Clear(); - command_stream.Printf("%s", basename.c_str()); - void *module_pyobj = nullptr; - if (ExecuteOneLineWithReturn( - command_stream.GetData(), - ScriptInterpreter::eScriptReturnTypeOpaqueObject, - &module_pyobj) && - module_pyobj) - *module_sp = std::make_shared(module_pyobj); - } + // if we are here, everything worked + // call __lldb_init_module(debugger,dict) + if (!LLDBSwigPythonCallModuleInit(module_name.c_str(), + m_dictionary_name.c_str(), debugger_sp)) { + error.SetErrorString("calling __lldb_init_module failed"); + return false; + } - return true; + if (module_sp) { + // everything went just great, now set the module object + command_stream.Clear(); + command_stream.Printf("%s", module_name.c_str()); + void *module_pyobj = nullptr; + if (ExecuteOneLineWithReturn( + command_stream.GetData(), + ScriptInterpreter::eScriptReturnTypeOpaqueObject, &module_pyobj, + exc_options) && + module_pyobj) + *module_sp = std::make_shared(module_pyobj); } + + return true; } bool ScriptInterpreterPythonImpl::IsReservedWord(const char *word) { @@ -2963,7 +3091,7 @@ bool ScriptInterpreterPythonImpl::GetDocumentationForItem(const char *item, if (ExecuteOneLineWithReturn( command, ScriptInterpreter::eScriptReturnTypeCharStrOrNone, &result_ptr, - ScriptInterpreter::ExecuteScriptOptions().SetEnableIO(false))) { + ExecuteScriptOptions().SetEnableIO(false))) { if (result_ptr) dest.assign(result_ptr); return true; @@ -3154,8 +3282,7 @@ void ScriptInterpreterPythonImpl::InitializePrivate() { g_initialized = true; - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer(func_cat, LLVM_PRETTY_FUNCTION); + LLDB_SCOPED_TIMER(); // RAII-based initialization which correctly handles multiple-initialization, // version- specific differences among Python 2 and Python 3, and saving and diff --git a/gnu/llvm/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h b/gnu/llvm/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h index e59fedbd097..b8b97811821 100644 --- a/gnu/llvm/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h +++ b/gnu/llvm/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h @@ -13,6 +13,8 @@ #if LLDB_ENABLE_PYTHON +#include "ScriptedProcessPythonInterface.h" + #include "lldb/Breakpoint/BreakpointOptions.h" #include "lldb/Core/IOHandler.h" #include "lldb/Core/StructuredDataImpl.h" @@ -51,6 +53,7 @@ public: static lldb_private::ConstString GetPluginNameStatic(); static const char *GetPluginDescriptionStatic(); static FileSpec GetPythonDir(); + static void SharedLibraryDirectoryHelper(FileSpec &this_file); protected: static void ComputePythonDirForApple(llvm::SmallVectorImpl &path); diff --git a/gnu/llvm/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h b/gnu/llvm/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h index 22b2c8152ea..d1b0b3fda1e 100644 --- a/gnu/llvm/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h +++ b/gnu/llvm/lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h @@ -6,6 +6,9 @@ // //===----------------------------------------------------------------------===// +#ifndef LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_SCRIPTINTERPRETERPYTHONIMPL_H +#define LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_SCRIPTINTERPRETERPYTHONIMPL_H + #include "lldb/Host/Config.h" #if LLDB_ENABLE_PYTHON @@ -105,6 +108,14 @@ public: lldb::SearchDepth ScriptedBreakpointResolverSearchDepth( StructuredData::GenericSP implementor_sp) override; + StructuredData::GenericSP + CreateScriptedStopHook(lldb::TargetSP target_sp, const char *class_name, + StructuredDataImpl *args_data, Status &error) override; + + bool ScriptedStopHookHandleStop(StructuredData::GenericSP implementor_sp, + ExecutionContext &exc_ctx, + lldb::StreamSP stream_sp) override; + StructuredData::GenericSP CreateFrameRecognizer(const char *class_name) override; @@ -223,17 +234,18 @@ public: bool RunScriptFormatKeyword(const char *impl_function, ValueObject *value, std::string &output, Status &error) override; - bool - LoadScriptingModule(const char *filename, bool init_session, - lldb_private::Status &error, - StructuredData::ObjectSP *module_sp = nullptr) override; + bool LoadScriptingModule(const char *filename, + const LoadScriptOptions &options, + lldb_private::Status &error, + StructuredData::ObjectSP *module_sp = nullptr, + FileSpec extra_search_dir = {}) override; bool IsReservedWord(const char *word) override; std::unique_ptr AcquireInterpreterLock() override; void CollectDataForBreakpointCommandCallback( - std::vector &bp_options_vec, + std::vector> &bp_options_vec, CommandReturnObject &result) override; void @@ -241,20 +253,19 @@ public: CommandReturnObject &result) override; /// Set the callback body text into the callback for the breakpoint. - Status SetBreakpointCommandCallback(BreakpointOptions *bp_options, + Status SetBreakpointCommandCallback(BreakpointOptions &bp_options, const char *callback_body) override; Status SetBreakpointCommandCallbackFunction( - BreakpointOptions *bp_options, - const char *function_name, + BreakpointOptions &bp_options, const char *function_name, StructuredData::ObjectSP extra_args_sp) override; /// This one is for deserialization: Status SetBreakpointCommandCallback( - BreakpointOptions *bp_options, + BreakpointOptions &bp_options, std::unique_ptr &data_up) override; - Status SetBreakpointCommandCallback(BreakpointOptions *bp_options, + Status SetBreakpointCommandCallback(BreakpointOptions &bp_options, const char *command_body_text, StructuredData::ObjectSP extra_args_sp, bool uses_extra_args); @@ -408,7 +419,7 @@ public: : IOHandler(debugger, IOHandler::Type::PythonInterpreter), m_python(python) {} - ~IOHandlerPythonInterpreter() override {} + ~IOHandlerPythonInterpreter() override = default; ConstString GetControlSequence(char ch) override { if (ch == 'd') @@ -475,4 +486,5 @@ protected: } // namespace lldb_private -#endif +#endif // LLDB_ENABLE_PYTHON +#endif // LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_SCRIPTINTERPRETERPYTHONIMPL_H diff --git a/gnu/llvm/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedProcessPythonInterface.cpp b/gnu/llvm/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedProcessPythonInterface.cpp new file mode 100644 index 00000000000..ce262c930f8 --- /dev/null +++ b/gnu/llvm/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedProcessPythonInterface.cpp @@ -0,0 +1,306 @@ +//===-- ScriptedProcessPythonInterface.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 "lldb/Host/Config.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 "ScriptedProcessPythonInterface.h" + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::python; +using Locker = ScriptInterpreterPythonImpl::Locker; + +StructuredData::GenericSP ScriptedProcessPythonInterface::CreatePluginObject( + const llvm::StringRef class_name, lldb::TargetSP target_sp, + StructuredData::DictionarySP args_sp) { + if (class_name.empty()) + return {}; + + std::string error_string; + StructuredDataImpl *args_impl = nullptr; + if (args_sp) { + args_impl = new StructuredDataImpl(); + args_impl->SetObjectSP(args_sp); + } + + void *ret_val; + + { + + Locker py_lock(&m_interpreter, Locker::AcquireLock | Locker::NoSTDIN, + Locker::FreeLock); + + ret_val = LLDBSwigPythonCreateScriptedProcess( + class_name.str().c_str(), m_interpreter.GetDictionaryName(), target_sp, + args_impl, error_string); + } + + m_object_instance_sp = + StructuredData::GenericSP(new StructuredPythonObject(ret_val)); + + return m_object_instance_sp; +} + +Status ScriptedProcessPythonInterface::Launch() { + return GetStatusFromMethod("launch"); +} + +Status ScriptedProcessPythonInterface::Resume() { + return GetStatusFromMethod("resume"); +} + +bool ScriptedProcessPythonInterface::ShouldStop() { + llvm::Optional should_stop = + GetGenericInteger("should_stop"); + + if (!should_stop) + return false; + + return static_cast(*should_stop); +} + +Status ScriptedProcessPythonInterface::Stop() { + return GetStatusFromMethod("stop"); +} + +Status ScriptedProcessPythonInterface::GetStatusFromMethod( + llvm::StringRef method_name) { + Locker py_lock(&m_interpreter, Locker::AcquireLock | Locker::NoSTDIN, + Locker::FreeLock); + + if (!m_object_instance_sp) + return Status("Python object ill-formed."); + + if (!m_object_instance_sp) + return Status("Cannot convert Python object to StructuredData::Generic."); + PythonObject implementor(PyRefType::Borrowed, + (PyObject *)m_object_instance_sp->GetValue()); + + if (!implementor.IsAllocated()) + return Status("Python implementor not allocated."); + + PythonObject pmeth( + PyRefType::Owned, + PyObject_GetAttrString(implementor.get(), method_name.str().c_str())); + + if (PyErr_Occurred()) + PyErr_Clear(); + + if (!pmeth.IsAllocated()) + return Status("Python method not allocated."); + + if (PyCallable_Check(pmeth.get()) == 0) { + if (PyErr_Occurred()) + PyErr_Clear(); + return Status("Python method not callable."); + } + + if (PyErr_Occurred()) + PyErr_Clear(); + + PythonObject py_return(PyRefType::Owned, + PyObject_CallMethod(implementor.get(), + method_name.str().c_str(), + nullptr)); + + if (PyErr_Occurred()) { + PyErr_Print(); + PyErr_Clear(); + return Status("Python method could not be called."); + } + + if (PyObject *py_ret_ptr = py_return.get()) { + lldb::SBError *sb_error = + (lldb::SBError *)LLDBSWIGPython_CastPyObjectToSBError(py_ret_ptr); + + if (!sb_error) + return Status("Couldn't cast lldb::SBError to lldb::Status."); + + Status status = m_interpreter.GetStatusFromSBError(*sb_error); + + if (status.Fail()) + return Status("error: %s", status.AsCString()); + + return status; + } + + return Status("Returned object is null."); +} + +llvm::Optional +ScriptedProcessPythonInterface::GetGenericInteger(llvm::StringRef method_name) { + Locker py_lock(&m_interpreter, Locker::AcquireLock | Locker::NoSTDIN, + Locker::FreeLock); + + if (!m_object_instance_sp) + return llvm::None; + + if (!m_object_instance_sp) + return llvm::None; + PythonObject implementor(PyRefType::Borrowed, + (PyObject *)m_object_instance_sp->GetValue()); + + if (!implementor.IsAllocated()) + return llvm::None; + + PythonObject pmeth( + PyRefType::Owned, + PyObject_GetAttrString(implementor.get(), method_name.str().c_str())); + + if (PyErr_Occurred()) + PyErr_Clear(); + + if (!pmeth.IsAllocated()) + return llvm::None; + + if (PyCallable_Check(pmeth.get()) == 0) { + if (PyErr_Occurred()) + PyErr_Clear(); + return llvm::None; + } + + if (PyErr_Occurred()) + PyErr_Clear(); + + PythonObject py_return(PyRefType::Owned, + PyObject_CallMethod(implementor.get(), + method_name.str().c_str(), + nullptr)); + + if (PyErr_Occurred()) { + PyErr_Print(); + PyErr_Clear(); + } + + if (!py_return.get()) + return llvm::None; + + llvm::Expected size = py_return.AsUnsignedLongLong(); + // FIXME: Handle error. + if (!size) + return llvm::None; + + return *size; +} + +lldb::MemoryRegionInfoSP +ScriptedProcessPythonInterface::GetMemoryRegionContainingAddress( + lldb::addr_t address) { + // TODO: Implement + return nullptr; +} + +StructuredData::DictionarySP +ScriptedProcessPythonInterface::GetThreadWithID(lldb::tid_t tid) { + // TODO: Implement + return nullptr; +} + +StructuredData::DictionarySP +ScriptedProcessPythonInterface::GetRegistersForThread(lldb::tid_t tid) { + // TODO: Implement + return nullptr; +} + +lldb::DataExtractorSP ScriptedProcessPythonInterface::ReadMemoryAtAddress( + lldb::addr_t address, size_t size, Status &error) { + Locker py_lock(&m_interpreter, Locker::AcquireLock | Locker::NoSTDIN, + Locker::FreeLock); + + auto error_with_message = [&error](llvm::StringRef message) { + error.SetErrorString(message); + return nullptr; + }; + + static char callee_name[] = "read_memory_at_address"; + std::string param_format = GetPythonValueFormatString(address); + param_format += GetPythonValueFormatString(size); + + if (!m_object_instance_sp) + return error_with_message("Python object ill-formed."); + + if (!m_object_instance_sp) + return error_with_message("Python method not callable."); + + PythonObject implementor(PyRefType::Borrowed, + (PyObject *)m_object_instance_sp->GetValue()); + + if (!implementor.IsAllocated()) + return error_with_message("Python implementor not allocated."); + + PythonObject pmeth(PyRefType::Owned, + PyObject_GetAttrString(implementor.get(), callee_name)); + + if (PyErr_Occurred()) + PyErr_Clear(); + + if (!pmeth.IsAllocated()) + return error_with_message("Python method not allocated."); + + if (PyCallable_Check(pmeth.get()) == 0) { + if (PyErr_Occurred()) + PyErr_Clear(); + return error_with_message("Python method not callable."); + } + + if (PyErr_Occurred()) + PyErr_Clear(); + + PythonObject py_return(PyRefType::Owned, + PyObject_CallMethod(implementor.get(), callee_name, + param_format.c_str(), address, + size)); + + if (PyErr_Occurred()) { + PyErr_Print(); + PyErr_Clear(); + return error_with_message("Python method could not be called."); + } + + if (PyObject *py_ret_ptr = py_return.get()) { + lldb::SBData *sb_data = + (lldb::SBData *)LLDBSWIGPython_CastPyObjectToSBData(py_ret_ptr); + + if (!sb_data) + return error_with_message( + "Couldn't cast lldb::SBData to lldb::DataExtractor."); + + return m_interpreter.GetDataExtractorFromSBData(*sb_data); + } + + return error_with_message("Returned object is null."); +} + +StructuredData::DictionarySP ScriptedProcessPythonInterface::GetLoadedImages() { + // TODO: Implement + return nullptr; +} + +lldb::pid_t ScriptedProcessPythonInterface::GetProcessID() { + llvm::Optional pid = GetGenericInteger("get_process_id"); + return (!pid) ? LLDB_INVALID_PROCESS_ID : *pid; +} + +bool ScriptedProcessPythonInterface::IsAlive() { + llvm::Optional is_alive = GetGenericInteger("is_alive"); + + if (!is_alive) + return false; + + return static_cast(*is_alive); +} + +#endif diff --git a/gnu/llvm/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedProcessPythonInterface.h b/gnu/llvm/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedProcessPythonInterface.h new file mode 100644 index 00000000000..30cb5a882af --- /dev/null +++ b/gnu/llvm/lldb/source/Plugins/ScriptInterpreter/Python/ScriptedProcessPythonInterface.h @@ -0,0 +1,66 @@ +//===-- ScriptedProcessPythonInterface.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_SCRIPTEDPROCESSPYTHONINTERFACE_H +#define LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_SCRIPTEDPROCESSPYTHONINTERFACE_H + +#include "lldb/Host/Config.h" + +#if LLDB_ENABLE_PYTHON + +#include "lldb/Interpreter/ScriptedProcessInterface.h" + +namespace lldb_private { +class ScriptInterpreterPythonImpl; +class ScriptedProcessPythonInterface : public ScriptedProcessInterface { +public: + ScriptedProcessPythonInterface(ScriptInterpreterPythonImpl &interpreter) + : ScriptedProcessInterface(), m_interpreter(interpreter) {} + + StructuredData::GenericSP + CreatePluginObject(const llvm::StringRef class_name, lldb::TargetSP target_sp, + StructuredData::DictionarySP args_sp) override; + + Status Launch() override; + + Status Resume() override; + + bool ShouldStop() override; + + Status Stop() override; + + lldb::MemoryRegionInfoSP + GetMemoryRegionContainingAddress(lldb::addr_t address) override; + + StructuredData::DictionarySP GetThreadWithID(lldb::tid_t tid) override; + + StructuredData::DictionarySP GetRegistersForThread(lldb::tid_t tid) override; + + lldb::DataExtractorSP ReadMemoryAtAddress(lldb::addr_t address, size_t size, + Status &error) override; + + StructuredData::DictionarySP GetLoadedImages() override; + + lldb::pid_t GetProcessID() override; + + bool IsAlive() override; + +protected: + llvm::Optional + GetGenericInteger(llvm::StringRef method_name); + Status GetStatusFromMethod(llvm::StringRef method_name); + +private: + // The lifetime is managed by the ScriptInterpreter + ScriptInterpreterPythonImpl &m_interpreter; + StructuredData::GenericSP m_object_instance_sp; +}; +} // namespace lldb_private + +#endif // LLDB_ENABLE_PYTHON +#endif // LLDB_PLUGINS_SCRIPTINTERPRETER_PYTHON_SCRIPTEDPROCESSPYTHONINTERFACE_H diff --git a/gnu/llvm/lldb/source/Plugins/StructuredData/DarwinLog/StructuredDataDarwinLog.cpp b/gnu/llvm/lldb/source/Plugins/StructuredData/DarwinLog/StructuredDataDarwinLog.cpp index 5ceaf886b81..87edf7789f0 100644 --- a/gnu/llvm/lldb/source/Plugins/StructuredData/DarwinLog/StructuredDataDarwinLog.cpp +++ b/gnu/llvm/lldb/source/Plugins/StructuredData/DarwinLog/StructuredDataDarwinLog.cpp @@ -8,7 +8,7 @@ #include "StructuredDataDarwinLog.h" -#include +#include #include #include @@ -126,7 +126,7 @@ public: m_collection_sp->Initialize(g_darwinlog_properties); } - ~StructuredDataDarwinLogProperties() override {} + ~StructuredDataDarwinLogProperties() override = default; bool GetEnableOnStartup() const { const uint32_t idx = ePropertyEnableOnStartup; @@ -181,7 +181,7 @@ using FilterRuleSP = std::shared_ptr; class FilterRule { public: - virtual ~FilterRule() {} + virtual ~FilterRule() = default; using OperationCreationFunc = std::function(plugin_sp.get()); @@ -837,7 +832,6 @@ protected: // Report results. if (!error.Success()) { result.AppendError(error.AsCString()); - result.SetStatus(eReturnStatusFailed); // Our configuration failed, so we're definitely disabled. plugin.SetEnabled(false); } else { diff --git a/gnu/llvm/lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.cpp b/gnu/llvm/lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.cpp index eeec7296747..b815ebb3c07 100644 --- a/gnu/llvm/lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.cpp +++ b/gnu/llvm/lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.cpp @@ -278,7 +278,7 @@ SymbolFileBreakpad::ResolveSymbolContext(const Address &so_addr, } uint32_t SymbolFileBreakpad::ResolveSymbolContext( - const FileSpec &file_spec, uint32_t line, bool check_inlines, + const SourceLocationSpec &src_location_spec, lldb::SymbolContextItem resolve_scope, SymbolContextList &sc_list) { std::lock_guard guard(GetModuleMutex()); if (!(resolve_scope & eSymbolContextCompUnit)) @@ -287,8 +287,7 @@ uint32_t SymbolFileBreakpad::ResolveSymbolContext( uint32_t old_size = sc_list.GetSize(); for (size_t i = 0, size = GetNumCompileUnits(); i < size; ++i) { CompileUnit &cu = *GetCompileUnitAtIndex(i); - cu.ResolveSymbolContext(file_spec, line, check_inlines, - /*exact*/ false, resolve_scope, sc_list); + cu.ResolveSymbolContext(src_location_spec, resolve_scope, sc_list); } return sc_list.GetSize() - old_size; } @@ -326,7 +325,8 @@ void SymbolFileBreakpad::AddSymbols(Symtab &symtab) { } const SectionList &list = *module.GetSectionList(); - llvm::DenseMap symbols; + llvm::DenseSet found_symbol_addresses; + std::vector symbols; auto add_symbol = [&](addr_t address, llvm::Optional size, llvm::StringRef name) { address += base; @@ -338,8 +338,12 @@ void SymbolFileBreakpad::AddSymbols(Symtab &symtab) { name, address); return; } - symbols.try_emplace( - address, /*symID*/ 0, Mangled(name), eSymbolTypeCode, + // Keep track of what addresses were already added so far and only add + // the symbol with the first address. + if (!found_symbol_addresses.insert(address).second) + return; + symbols.emplace_back( + /*symID*/ 0, Mangled(name), eSymbolTypeCode, /*is_global*/ true, /*is_debug*/ false, /*is_trampoline*/ false, /*is_artificial*/ false, AddressRange(section_sp, address - section_sp->GetFileAddress(), @@ -359,8 +363,8 @@ void SymbolFileBreakpad::AddSymbols(Symtab &symtab) { LLDB_LOG(log, "Failed to parse: {0}. Skipping record.", line); } - for (auto &KV : symbols) - symtab.AddSymbol(std::move(KV.second)); + for (Symbol &symbol : symbols) + symtab.AddSymbol(std::move(symbol)); symtab.CalculateSymbolSizes(); } @@ -711,10 +715,10 @@ void SymbolFileBreakpad::ParseLineTableAndSupportFiles(CompileUnit &cu, llvm::Optional next_addr; auto finish_sequence = [&]() { LineTable::AppendLineEntryToSequence( - line_seq_up.get(), *next_addr, /*line*/ 0, /*column*/ 0, - /*file_idx*/ 0, /*is_start_of_statement*/ false, - /*is_start_of_basic_block*/ false, /*is_prologue_end*/ false, - /*is_epilogue_begin*/ false, /*is_terminal_entry*/ true); + line_seq_up.get(), *next_addr, /*line=*/0, /*column=*/0, + /*file_idx=*/0, /*is_start_of_statement=*/false, + /*is_start_of_basic_block=*/false, /*is_prologue_end=*/false, + /*is_epilogue_begin=*/false, /*is_terminal_entry=*/true); sequences.push_back(std::move(line_seq_up)); line_seq_up = LineTable::CreateLineSequenceContainer(); }; @@ -734,10 +738,10 @@ void SymbolFileBreakpad::ParseLineTableAndSupportFiles(CompileUnit &cu, finish_sequence(); } LineTable::AppendLineEntryToSequence( - line_seq_up.get(), record->Address, record->LineNum, /*column*/ 0, - map[record->FileNum], /*is_start_of_statement*/ true, - /*is_start_of_basic_block*/ false, /*is_prologue_end*/ false, - /*is_epilogue_begin*/ false, /*is_terminal_entry*/ false); + line_seq_up.get(), record->Address, record->LineNum, /*column=*/0, + map[record->FileNum], /*is_start_of_statement=*/true, + /*is_start_of_basic_block=*/false, /*is_prologue_end=*/false, + /*is_epilogue_begin=*/false, /*is_terminal_entry=*/false); next_addr = record->Address + record->Size; } if (next_addr) diff --git a/gnu/llvm/lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.h b/gnu/llvm/lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.h index 90dbcc77627..b0a35fa11de 100644 --- a/gnu/llvm/lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.h +++ b/gnu/llvm/lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.h @@ -51,7 +51,7 @@ public: SymbolFileBreakpad(lldb::ObjectFileSP objfile_sp) : SymbolFile(std::move(objfile_sp)) {} - ~SymbolFileBreakpad() override {} + ~SymbolFileBreakpad() override = default; uint32_t CalculateAbilities() override; @@ -101,8 +101,7 @@ public: lldb::SymbolContextItem resolve_scope, SymbolContext &sc) override; - uint32_t ResolveSymbolContext(const FileSpec &file_spec, uint32_t line, - bool check_inlines, + uint32_t ResolveSymbolContext(const SourceLocationSpec &src_location_spec, lldb::SymbolContextItem resolve_scope, SymbolContextList &sc_list) override; diff --git a/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/AppleDWARFIndex.cpp b/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/AppleDWARFIndex.cpp index 33ab11a3ca4..60b6b726f6c 100644 --- a/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/AppleDWARFIndex.cpp +++ b/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/AppleDWARFIndex.cpp @@ -42,8 +42,8 @@ std::unique_ptr AppleDWARFIndex::Create( if (!apple_objc_table_up->IsValid()) apple_objc_table_up.reset(); - if (apple_names_table_up || apple_names_table_up || apple_types_table_up || - apple_objc_table_up) + if (apple_names_table_up || apple_namespaces_table_up || + apple_types_table_up || apple_objc_table_up) return std::make_unique( module, std::move(apple_names_table_up), std::move(apple_namespaces_table_up), std::move(apple_types_table_up), diff --git a/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParser.h b/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParser.h index 2e0a7fd3ecd..ffe24836955 100644 --- a/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParser.h +++ b/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParser.h @@ -24,7 +24,7 @@ class SymbolFileDWARF; class DWARFASTParser { public: - virtual ~DWARFASTParser() {} + virtual ~DWARFASTParser() = default; virtual lldb::TypeSP ParseTypeFromDWARF(const lldb_private::SymbolContext &sc, const DWARFDIE &die, diff --git a/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp index 2d1db66e7fd..46015f7b43b 100644 --- a/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp +++ b/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// -#include +#include #include "DWARFASTParserClang.h" #include "DWARFDebugInfo.h" @@ -49,7 +49,7 @@ //#define ENABLE_DEBUG_PRINTF // COMMENT OUT THIS LINE PRIOR TO CHECKIN #ifdef ENABLE_DEBUG_PRINTF -#include +#include #define DEBUG_PRINTF(fmt, ...) printf(fmt, __VA_ARGS__) #else #define DEBUG_PRINTF(fmt, ...) @@ -60,7 +60,7 @@ using namespace lldb_private; DWARFASTParserClang::DWARFASTParserClang(TypeSystemClang &ast) : m_ast(ast), m_die_to_decl_ctx(), m_decl_ctx_to_die() {} -DWARFASTParserClang::~DWARFASTParserClang() {} +DWARFASTParserClang::~DWARFASTParserClang() = default; static AccessType DW_ACCESS_to_AccessType(uint32_t dwarf_accessibility) { switch (dwarf_accessibility) { @@ -157,7 +157,7 @@ TypeSP DWARFASTParserClang::ParseTypeFromClangModule(const SymbolContext &sc, // The type in the Clang module must have the same language as the current CU. LanguageSet languages; - languages.Insert(SymbolFileDWARF::GetLanguage(*die.GetCU())); + languages.Insert(SymbolFileDWARF::GetLanguageFamily(*die.GetCU())); llvm::DenseSet searched_symbol_files; clang_module_sp->GetSymbolFile()->FindTypes(decl_context, languages, searched_symbol_files, pcm_types); @@ -209,11 +209,12 @@ TypeSP DWARFASTParserClang::ParseTypeFromClangModule(const SymbolContext &sc, GetClangASTImporter().RequireCompleteType(ClangUtil::GetQualType(type)); SymbolFileDWARF *dwarf = die.GetDWARF(); - TypeSP type_sp(new Type( - die.GetID(), dwarf, pcm_type_sp->GetName(), pcm_type_sp->GetByteSize(), - nullptr, LLDB_INVALID_UID, Type::eEncodingInvalid, - &pcm_type_sp->GetDeclaration(), type, Type::ResolveState::Forward, - TypePayloadClang(GetOwningClangModule(die)))); + TypeSP type_sp(new Type(die.GetID(), dwarf, pcm_type_sp->GetName(), + pcm_type_sp->GetByteSize(nullptr), nullptr, + LLDB_INVALID_UID, Type::eEncodingInvalid, + &pcm_type_sp->GetDeclaration(), type, + Type::ResolveState::Forward, + TypePayloadClang(GetOwningClangModule(die)))); dwarf->GetTypeList().Insert(type_sp); dwarf->GetDIEToType()[die.GetDIE()] = type_sp.get(); @@ -229,31 +230,73 @@ TypeSP DWARFASTParserClang::ParseTypeFromClangModule(const SymbolContext &sc, return type_sp; } -static void CompleteExternalTagDeclType(TypeSystemClang &ast, - ClangASTImporter &ast_importer, - clang::DeclContext *decl_ctx, - DWARFDIE die, - const char *type_name_cstr) { +static void ForcefullyCompleteType(CompilerType type) { + bool started = TypeSystemClang::StartTagDeclarationDefinition(type); + lldbassert(started && "Unable to start a class type definition."); + TypeSystemClang::CompleteTagDeclarationDefinition(type); + const clang::TagDecl *td = ClangUtil::GetAsTagDecl(type); + auto &ts = llvm::cast(*type.GetTypeSystem()); + ts.GetMetadata(td)->SetIsForcefullyCompleted(); +} + +/// Complete a type from debug info, or mark it as forcefully completed if +/// there is no definition of the type in the current Module. Call this function +/// in contexts where the usual C++ rules require a type to be complete (base +/// class, member, etc.). +static void RequireCompleteType(CompilerType type) { + // Technically, enums can be incomplete too, but we don't handle those as they + // are emitted even under -flimit-debug-info. + if (!TypeSystemClang::IsCXXClassType(type)) + return; + + if (type.GetCompleteType()) + return; + + // No complete definition in this module. Mark the class as complete to + // satisfy local ast invariants, but make a note of the fact that + // it is not _really_ complete so we can later search for a definition in a + // different module. + // Since we provide layout assistance, layouts of types containing this class + // will be correct even if we are not able to find the definition elsewhere. + ForcefullyCompleteType(type); +} + +/// This function serves a similar purpose as RequireCompleteType above, but it +/// avoids completing the type if it is not immediately necessary. It only +/// ensures we _can_ complete the type later. +static void PrepareContextToReceiveMembers(TypeSystemClang &ast, + ClangASTImporter &ast_importer, + clang::DeclContext *decl_ctx, + DWARFDIE die, + const char *type_name_cstr) { auto *tag_decl_ctx = clang::dyn_cast(decl_ctx); if (!tag_decl_ctx) + return; // Non-tag context are always ready. + + // We have already completed the type, or we have found its definition and are + // ready to complete it later (cf. ParseStructureLikeDIE). + if (tag_decl_ctx->isCompleteDefinition() || tag_decl_ctx->isBeingDefined()) return; + // We reach this point of the tag was present in the debug info as a + // declaration only. If it was imported from another AST context (in the + // gmodules case), we can complete the type by doing a full import. + // If this type was not imported from an external AST, there's nothing to do. CompilerType type = ast.GetTypeForDecl(tag_decl_ctx); - if (!type || !ast_importer.CanImport(type)) - return; - - auto qual_type = ClangUtil::GetQualType(type); - if (!ast_importer.RequireCompleteType(qual_type)) { + if (type && ast_importer.CanImport(type)) { + auto qual_type = ClangUtil::GetQualType(type); + if (ast_importer.RequireCompleteType(qual_type)) + return; die.GetDWARF()->GetObjectFile()->GetModule()->ReportError( "Unable to complete the Decl context for DIE '%s' at offset " "0x%8.8x.\nPlease file a bug report.", type_name_cstr ? type_name_cstr : "", die.GetOffset()); - // We need to make the type look complete otherwise, we might crash in - // Clang when adding children. - if (TypeSystemClang::StartTagDeclarationDefinition(type)) - TypeSystemClang::CompleteTagDeclarationDefinition(type); } + + // We don't have a type definition and/or the import failed. We must + // forcefully complete the type to avoid crashes. + ForcefullyCompleteType(type); } ParsedDWARFTypeAttributes::ParsedDWARFTypeAttributes(const DWARFDIE &die) { @@ -298,7 +341,9 @@ ParsedDWARFTypeAttributes::ParsedDWARFTypeAttributes(const DWARFDIE &die) { break; case DW_AT_decl_file: - decl.SetFile(die.GetCU()->GetFile(form_value.Unsigned())); + // die.GetCU() can differ if DW_AT_specification uses DW_FORM_ref_addr. + decl.SetFile( + attributes.CompileUnitAtIndex(i)->GetFile(form_value.Unsigned())); break; case DW_AT_decl_line: decl.SetLine(form_value.Unsigned()); @@ -513,42 +558,51 @@ DWARFASTParserClang::ParseTypeModifier(const SymbolContext &sc, TypeSP type_sp; CompilerType clang_type; - if (tag == DW_TAG_typedef && attrs.type.IsValid()) { - // Try to parse a typedef from the (DWARF embedded in the) Clang - // module file first as modules can contain typedef'ed - // structures that have no names like: - // - // typedef struct { int a; } Foo; - // - // In this case we will have a structure with no name and a - // typedef named "Foo" that points to this unnamed - // structure. The name in the typedef is the only identifier for - // the struct, so always try to get typedefs from Clang modules - // if possible. - // - // The type_sp returned will be empty if the typedef doesn't - // exist in a module file, so it is cheap to call this function - // just to check. - // - // If we don't do this we end up creating a TypeSP that says - // this is a typedef to type 0x123 (the DW_AT_type value would - // be 0x123 in the DW_TAG_typedef), and this is the unnamed - // structure type. We will have a hard time tracking down an - // unnammed structure type in the module debug info, so we make - // sure we don't get into this situation by always resolving - // typedefs from the module. - const DWARFDIE encoding_die = attrs.type.Reference(); - - // First make sure that the die that this is typedef'ed to _is_ - // just a declaration (DW_AT_declaration == 1), not a full - // definition since template types can't be represented in - // modules since only concrete instances of templates are ever - // emitted and modules won't contain those - if (encoding_die && - encoding_die.GetAttributeValueAsUnsigned(DW_AT_declaration, 0) == 1) { - type_sp = ParseTypeFromClangModule(sc, die, log); - if (type_sp) - return type_sp; + if (tag == DW_TAG_typedef) { + // DeclContext will be populated when the clang type is materialized in + // Type::ResolveCompilerType. + PrepareContextToReceiveMembers( + m_ast, GetClangASTImporter(), + GetClangDeclContextContainingDIE(die, nullptr), die, + attrs.name.GetCString()); + + if (attrs.type.IsValid()) { + // Try to parse a typedef from the (DWARF embedded in the) Clang + // module file first as modules can contain typedef'ed + // structures that have no names like: + // + // typedef struct { int a; } Foo; + // + // In this case we will have a structure with no name and a + // typedef named "Foo" that points to this unnamed + // structure. The name in the typedef is the only identifier for + // the struct, so always try to get typedefs from Clang modules + // if possible. + // + // The type_sp returned will be empty if the typedef doesn't + // exist in a module file, so it is cheap to call this function + // just to check. + // + // If we don't do this we end up creating a TypeSP that says + // this is a typedef to type 0x123 (the DW_AT_type value would + // be 0x123 in the DW_TAG_typedef), and this is the unnamed + // structure type. We will have a hard time tracking down an + // unnammed structure type in the module debug info, so we make + // sure we don't get into this situation by always resolving + // typedefs from the module. + const DWARFDIE encoding_die = attrs.type.Reference(); + + // First make sure that the die that this is typedef'ed to _is_ + // just a declaration (DW_AT_declaration == 1), not a full + // definition since template types can't be represented in + // modules since only concrete instances of templates are ever + // emitted and modules won't contain those + if (encoding_die && + encoding_die.GetAttributeValueAsUnsigned(DW_AT_declaration, 0) == 1) { + type_sp = ParseTypeFromClangModule(sc, die, log); + if (type_sp) + return type_sp; + } } } @@ -612,8 +666,7 @@ DWARFASTParserClang::ParseTypeModifier(const SymbolContext &sc, // Blocks have a __FuncPtr inside them which is a pointer to a // function of the proper type. - for (DWARFDIE child_die = target_die.GetFirstChild(); - child_die.IsValid(); child_die = child_die.GetSibling()) { + for (DWARFDIE child_die : target_die.children()) { if (!strcmp(child_die.GetAttributeValueAsString(DW_AT_name, ""), "__FuncPtr")) { DWARFDIE function_pointer_type = @@ -810,7 +863,7 @@ TypeSP DWARFASTParserClang::ParseEnum(const SymbolContext &sc, bool is_signed = false; enumerator_clang_type.IsIntegerType(is_signed); ParseChildEnumerators(clang_type, is_signed, - type_sp->GetByteSize().getValueOr(0), die); + type_sp->GetByteSize(nullptr).getValueOr(0), die); } TypeSystemClang::CompleteTagDeclarationDefinition(clang_type); } else { @@ -1172,15 +1225,18 @@ TypeSP DWARFASTParserClang::ParseSubroutine(const DWARFDIE &die, } if (!function_decl) { - const char *name = attrs.name.GetCString(); + char *name_buf = nullptr; + llvm::StringRef name = attrs.name.GetStringRef(); // We currently generate function templates with template parameters in // their name. In order to get closer to the AST that clang generates // we want to strip these from the name when creating the AST. if (attrs.mangled_name) { llvm::ItaniumPartialDemangler D; - if (!D.partialDemangle(attrs.mangled_name)) - name = D.getFunctionBaseName(nullptr, nullptr); + if (!D.partialDemangle(attrs.mangled_name)) { + name_buf = D.getFunctionBaseName(nullptr, nullptr); + name = name_buf; + } } // We just have a function that isn't part of a class @@ -1189,6 +1245,7 @@ TypeSP DWARFASTParserClang::ParseSubroutine(const DWARFDIE &die, : containing_decl_ctx, GetOwningClangModule(die), name, clang_type, attrs.storage, attrs.is_inline); + std::free(name_buf); if (has_template_params) { TypeSystemClang::TemplateParameterInfos template_param_infos; @@ -1196,12 +1253,12 @@ TypeSP DWARFASTParserClang::ParseSubroutine(const DWARFDIE &die, template_function_decl = m_ast.CreateFunctionDeclaration( ignore_containing_context ? m_ast.GetTranslationUnitDecl() : containing_decl_ctx, - GetOwningClangModule(die), attrs.name.GetCString(), clang_type, + GetOwningClangModule(die), attrs.name.GetStringRef(), clang_type, attrs.storage, attrs.is_inline); clang::FunctionTemplateDecl *func_template_decl = m_ast.CreateFunctionTemplateDecl( containing_decl_ctx, GetOwningClangModule(die), - template_function_decl, name, template_param_infos); + template_function_decl, template_param_infos); m_ast.CreateFunctionTemplateSpecializationInfo( template_function_decl, func_template_decl, template_param_infos); } @@ -1212,13 +1269,10 @@ TypeSP DWARFASTParserClang::ParseSubroutine(const DWARFDIE &die, LinkDeclContextToDIE(function_decl, die); if (!function_param_decls.empty()) { - m_ast.SetFunctionParameters(function_decl, - &function_param_decls.front(), - function_param_decls.size()); + m_ast.SetFunctionParameters(function_decl, function_param_decls); if (template_function_decl) m_ast.SetFunctionParameters(template_function_decl, - &function_param_decls.front(), - function_param_decls.size()); + function_param_decls); } ClangASTMetadata metadata; @@ -1261,9 +1315,9 @@ TypeSP DWARFASTParserClang::ParseArrayType(const DWARFDIE &die, attrs.bit_stride = array_info->bit_stride; } if (attrs.byte_stride == 0 && attrs.bit_stride == 0) - attrs.byte_stride = element_type->GetByteSize().getValueOr(0); + attrs.byte_stride = element_type->GetByteSize(nullptr).getValueOr(0); CompilerType array_element_type = element_type->GetForwardCompilerType(); - CompleteType(array_element_type); + RequireCompleteType(array_element_type); uint64_t array_element_bit_stride = attrs.byte_stride * 8 + attrs.bit_stride; @@ -1303,7 +1357,7 @@ TypeSP DWARFASTParserClang::ParsePointerToMemberType( dwarf->ResolveTypeUID(attrs.containing_type.Reference(), true); CompilerType pointee_clang_type = pointee_type->GetForwardCompilerType(); - CompilerType class_clang_type = class_type->GetLayoutCompilerType(); + CompilerType class_clang_type = class_type->GetForwardCompilerType(); CompilerType clang_type = TypeSystemClang::CreateMemberPointerType( class_clang_type, pointee_clang_type); @@ -1318,28 +1372,6 @@ TypeSP DWARFASTParserClang::ParsePointerToMemberType( return nullptr; } -void DWARFASTParserClang::CompleteType(CompilerType type) { - // Technically, enums can be incomplete too, but we don't handle those as they - // are emitted even under -flimit-debug-info. - if (!TypeSystemClang::IsCXXClassType(type)) - return; - - if (type.GetCompleteType()) - return; - - // No complete definition in this module. Mark the class as complete to - // satisfy local ast invariants, but make a note of the fact that - // it is not _really_ complete so we can later search for a definition in a - // different module. - // Since we provide layout assistance, layouts of types containing this class - // will be correct even if we are not able to find the definition elsewhere. - bool started = TypeSystemClang::StartTagDeclarationDefinition(type); - lldbassert(started && "Unable to start a class type definition."); - TypeSystemClang::CompleteTagDeclarationDefinition(type); - const clang::TagDecl *td = ClangUtil::GetAsTagDecl(type); - m_ast.GetMetadata(td)->SetIsForcefullyCompleted(); -} - TypeSP DWARFASTParserClang::UpdateSymbolContextScopeForType( const SymbolContext &sc, const DWARFDIE &die, TypeSP type_sp) { if (!type_sp) @@ -1559,13 +1591,8 @@ DWARFASTParserClang::ParseStructureLikeDIE(const SymbolContext &sc, clang::DeclContext *decl_ctx = GetClangDeclContextContainingDIE(die, nullptr); - // If your decl context is a record that was imported from another - // AST context (in the gmodules case), we need to make sure the type - // backing the Decl is complete before adding children to it. This is - // not an issue in the non-gmodules case because the debug info will - // always contain a full definition of parent types in that case. - CompleteExternalTagDeclType(m_ast, GetClangASTImporter(), decl_ctx, die, - attrs.name.GetCString()); + PrepareContextToReceiveMembers(m_ast, GetClangASTImporter(), decl_ctx, die, + attrs.name.GetCString()); if (attrs.accessibility == eAccessNone && decl_ctx) { // Check the decl context that contains this class/struct/union. If @@ -1640,33 +1667,6 @@ DWARFASTParserClang::ParseStructureLikeDIE(const SymbolContext &sc, dwarf->GetUniqueDWARFASTTypeMap().Insert(unique_typename, *unique_ast_entry_up); - if (attrs.is_forward_declaration && die.HasChildren()) { - // Check to see if the DIE actually has a definition, some version of - // GCC will - // emit DIEs with DW_AT_declaration set to true, but yet still have - // subprogram, members, or inheritance, so we can't trust it - DWARFDIE child_die = die.GetFirstChild(); - while (child_die) { - switch (child_die.Tag()) { - case DW_TAG_inheritance: - case DW_TAG_subprogram: - case DW_TAG_member: - case DW_TAG_APPLE_property: - case DW_TAG_class_type: - case DW_TAG_structure_type: - case DW_TAG_enumeration_type: - case DW_TAG_typedef: - case DW_TAG_union_type: - child_die.Clear(); - attrs.is_forward_declaration = false; - break; - default: - child_die = child_die.GetSibling(); - break; - } - } - } - if (!attrs.is_forward_declaration) { // Always start the definition for a class type so that if the class // has child classes or types that require the class to be created @@ -1684,14 +1684,18 @@ DWARFASTParserClang::ParseStructureLikeDIE(const SymbolContext &sc, die.GetOffset(), attrs.name.GetCString()); } - if (tag == DW_TAG_structure_type) // this only applies in C - { + // If the byte size of the record is specified then overwrite the size + // that would be computed by Clang. This is only needed as LLDB's + // TypeSystemClang is always in C++ mode, but some compilers such as + // GCC and Clang give empty structs a size of 0 in C mode (in contrast to + // the size of 1 for empty structs that would be computed in C++ mode). + if (attrs.byte_size) { clang::RecordDecl *record_decl = TypeSystemClang::GetAsRecordDecl(clang_type); - if (record_decl) { - GetClangASTImporter().SetRecordLayout( - record_decl, ClangASTImporter::LayoutInfo()); + ClangASTImporter::LayoutInfo layout; + layout.bit_size = *attrs.byte_size * 8; + GetClangASTImporter().SetRecordLayout(record_decl, layout); } } } else if (clang_type_was_created) { @@ -1822,8 +1826,7 @@ bool DWARFASTParserClang::ParseTemplateDIE( case DW_TAG_GNU_template_parameter_pack: { template_param_infos.packed_args = std::make_unique(); - for (DWARFDIE child_die = die.GetFirstChild(); child_die.IsValid(); - child_die = child_die.GetSibling()) { + for (DWARFDIE child_die : die.children()) { if (!ParseTemplateDIE(child_die, *template_param_infos.packed_args)) return false; } @@ -1928,8 +1931,7 @@ bool DWARFASTParserClang::ParseTemplateParameterInfos( if (!parent_die) return false; - for (DWARFDIE die = parent_die.GetFirstChild(); die.IsValid(); - die = die.GetSibling()) { + for (DWARFDIE die : parent_die.children()) { const dw_tag_t tag = die.Tag(); switch (tag) { @@ -1944,8 +1946,6 @@ bool DWARFASTParserClang::ParseTemplateParameterInfos( break; } } - if (template_param_infos.args.empty()) - return false; return template_param_infos.args.size() == template_param_infos.names.size(); } @@ -1980,15 +1980,12 @@ bool DWARFASTParserClang::CompleteRecordType(const DWARFDIE &die, } std::vector> bases; - std::vector member_accessibilities; - bool is_a_class = false; // Parse members and base classes first std::vector member_function_dies; DelayedPropertyList delayed_properties; - ParseChildMembers(die, clang_type, bases, member_accessibilities, - member_function_dies, delayed_properties, - default_accessibility, is_a_class, layout_info); + ParseChildMembers(die, clang_type, bases, member_function_dies, + delayed_properties, default_accessibility, layout_info); // Now parse any methods if there were any... for (const DWARFDIE &die : member_function_dies) @@ -2009,31 +2006,6 @@ bool DWARFASTParserClang::CompleteRecordType(const DWARFDIE &die, } } - // If we have a DW_TAG_structure_type instead of a DW_TAG_class_type we - // need to tell the clang type it is actually a class. - if (!type_is_objc_object_or_interface) { - if (is_a_class && tag_decl_kind != clang::TTK_Class) - m_ast.SetTagTypeKind(ClangUtil::GetQualType(clang_type), - clang::TTK_Class); - } - - // Since DW_TAG_structure_type gets used for both classes and - // structures, we may need to set any DW_TAG_member fields to have a - // "private" access if none was specified. When we parsed the child - // members we tracked that actual accessibility value for each - // DW_TAG_member in the "member_accessibilities" array. If the value - // for the member is zero, then it was set to the - // "default_accessibility" which for structs was "public". Below we - // correct this by setting any fields to "private" that weren't - // correctly set. - if (is_a_class && !member_accessibilities.empty()) { - // This is a class and all members that didn't have their access - // specified are private. - m_ast.SetDefaultAccessForRecordFields( - m_ast.GetAsRecordDecl(clang_type), eAccessPrivate, - &member_accessibilities.front(), member_accessibilities.size()); - } - if (!bases.empty()) { // Make sure all base classes refer to complete types and not forward // declarations. If we don't do this, clang will crash with an @@ -2042,7 +2014,7 @@ bool DWARFASTParserClang::CompleteRecordType(const DWARFDIE &die, clang::TypeSourceInfo *type_source_info = base_class->getTypeSourceInfo(); if (type_source_info) - CompleteType(m_ast.GetType(type_source_info->getType())); + RequireCompleteType(m_ast.GetType(type_source_info->getType())); } m_ast.TransferBaseClasses(clang_type.GetOpaqueQualType(), @@ -2057,7 +2029,7 @@ bool DWARFASTParserClang::CompleteRecordType(const DWARFDIE &die, if (!layout_info.field_offsets.empty() || !layout_info.base_offsets.empty() || !layout_info.vbase_offsets.empty()) { if (type) - layout_info.bit_size = type->GetByteSize().getValueOr(0) * 8; + layout_info.bit_size = type->GetByteSize(nullptr).getValueOr(0) * 8; if (layout_info.bit_size == 0) layout_info.bit_size = die.GetAttributeValueAsUnsigned(DW_AT_byte_size, 0) * 8; @@ -2079,7 +2051,7 @@ bool DWARFASTParserClang::CompleteEnumType(const DWARFDIE &die, bool is_signed = false; clang_type.IsIntegerType(is_signed); ParseChildEnumerators(clang_type, is_signed, - type->GetByteSize().getValueOr(0), die); + type->GetByteSize(nullptr).getValueOr(0), die); } TypeSystemClang::CompleteTagDeclarationDefinition(clang_type); } @@ -2133,8 +2105,7 @@ void DWARFASTParserClang::EnsureAllDIEsInDeclContextHaveBeenParsed( for (auto it = m_decl_ctx_to_die.find(opaque_decl_ctx); it != m_decl_ctx_to_die.end() && it->first == opaque_decl_ctx; it = m_decl_ctx_to_die.erase(it)) - for (DWARFDIE decl = it->second.GetFirstChild(); decl; - decl = decl.GetSibling()) + for (DWARFDIE decl : it->second.children()) GetClangDeclForDIE(decl); } @@ -2170,8 +2141,7 @@ size_t DWARFASTParserClang::ParseChildEnumerators( size_t enumerators_added = 0; - for (DWARFDIE die = parent_die.GetFirstChild(); die.IsValid(); - die = die.GetSibling()) { + for (DWARFDIE die : parent_die.children()) { const dw_tag_t tag = die.Tag(); if (tag == DW_TAG_enumerator) { DWARFAttributes attributes; @@ -2203,7 +2173,8 @@ size_t DWARFASTParserClang::ParseChildEnumerators( case DW_AT_description: default: case DW_AT_decl_file: - decl.SetFile(die.GetCU()->GetFile(form_value.Unsigned())); + decl.SetFile(attributes.CompileUnitAtIndex(i)->GetFile( + form_value.Unsigned())); break; case DW_AT_decl_line: decl.SetLine(form_value.Unsigned()); @@ -2345,7 +2316,6 @@ Function *DWARFASTParserClang::ParseFunctionFromDWARF(CompileUnit &comp_unit, void DWARFASTParserClang::ParseSingleMember( const DWARFDIE &die, const DWARFDIE &parent_die, const lldb_private::CompilerType &class_clang_type, - std::vector &member_accessibilities, lldb::AccessType default_accessibility, DelayedPropertyList &delayed_properties, lldb_private::ClangASTImporter::LayoutInfo &layout_info, @@ -2535,7 +2505,7 @@ void DWARFASTParserClang::ParseSingleMember( if (accessibility == eAccessNone) accessibility = eAccessPublic; TypeSystemClang::AddVariableToRecordType( - class_clang_type, name, var_type->GetLayoutCompilerType(), + class_clang_type, name, var_type->GetForwardCompilerType(), accessibility); } return; @@ -2553,7 +2523,6 @@ void DWARFASTParserClang::ParseSingleMember( if (accessibility == eAccessNone) accessibility = default_accessibility; - member_accessibilities.push_back(accessibility); uint64_t field_bit_offset = (member_byte_offset == UINT32_MAX ? 0 : (member_byte_offset * 8)); @@ -2567,7 +2536,7 @@ void DWARFASTParserClang::ParseSingleMember( this_field_info.bit_offset = data_bit_offset; } else { if (!byte_size) - byte_size = member_type->GetByteSize(); + byte_size = member_type->GetByteSize(nullptr); ObjectFile *objfile = die.GetDWARF()->GetObjectFile(); if (objfile->GetByteOrder() == eByteOrderLittle) { @@ -2578,10 +2547,18 @@ void DWARFASTParserClang::ParseSingleMember( } } - if ((this_field_info.bit_offset >= parent_bit_size) || - (last_field_info.IsBitfield() && - !last_field_info.NextBitfieldOffsetIsValid( - this_field_info.bit_offset))) { + // The ObjC runtime knows the byte offset but we still need to provide + // the bit-offset in the layout. It just means something different then + // what it does in C and C++. So we skip this check for ObjC types. + // + // We also skip this for fields of a union since they will all have a + // zero offset. + if (!TypeSystemClang::IsObjCObjectOrInterfaceType(class_clang_type) && + !(parent_die.Tag() == DW_TAG_union_type && this_field_info.bit_offset == 0) && + ((this_field_info.bit_offset >= parent_bit_size) || + (last_field_info.IsBitfield() && + !last_field_info.NextBitfieldOffsetIsValid( + this_field_info.bit_offset)))) { ObjectFile *objfile = die.GetDWARF()->GetObjectFile(); objfile->GetModule()->ReportWarning( "0x%8.8" PRIx64 ": %s bitfield named \"%s\" has invalid " @@ -2660,7 +2637,7 @@ void DWARFASTParserClang::ParseSingleMember( last_field_info.bit_offset = field_bit_offset; if (llvm::Optional clang_type_size = - member_clang_type.GetByteSize(nullptr)) { + member_type->GetByteSize(nullptr)) { last_field_info.bit_size = *clang_type_size * character_width; } @@ -2707,7 +2684,7 @@ void DWARFASTParserClang::ParseSingleMember( } } - CompleteType(member_clang_type); + RequireCompleteType(member_clang_type); field_decl = TypeSystemClang::AddFieldToRecordType( class_clang_type, name, member_clang_type, accessibility, @@ -2755,10 +2732,9 @@ void DWARFASTParserClang::ParseSingleMember( bool DWARFASTParserClang::ParseChildMembers( const DWARFDIE &parent_die, CompilerType &class_clang_type, std::vector> &base_classes, - std::vector &member_accessibilities, std::vector &member_function_dies, DelayedPropertyList &delayed_properties, AccessType &default_accessibility, - bool &is_a_class, ClangASTImporter::LayoutInfo &layout_info) { + ClangASTImporter::LayoutInfo &layout_info) { if (!parent_die) return false; @@ -2770,16 +2746,15 @@ bool DWARFASTParserClang::ParseChildMembers( if (ast == nullptr) return false; - for (DWARFDIE die = parent_die.GetFirstChild(); die.IsValid(); - die = die.GetSibling()) { + for (DWARFDIE die : parent_die.children()) { dw_tag_t tag = die.Tag(); switch (tag) { case DW_TAG_member: case DW_TAG_APPLE_property: ParseSingleMember(die, parent_die, class_clang_type, - member_accessibilities, default_accessibility, - delayed_properties, layout_info, last_field_info); + default_accessibility, delayed_properties, layout_info, + last_field_info); break; case DW_TAG_subprogram: @@ -2788,9 +2763,6 @@ bool DWARFASTParserClang::ParseChildMembers( break; case DW_TAG_inheritance: { - is_a_class = true; - if (default_accessibility == eAccessNone) - default_accessibility = eAccessPrivate; // TODO: implement DW_TAG_inheritance type parsing DWARFAttributes attributes; const size_t num_attributes = die.GetAttributes(attributes); @@ -2920,8 +2892,7 @@ size_t DWARFASTParserClang::ParseChildParameters( return 0; size_t arg_idx = 0; - for (DWARFDIE die = parent_die.GetFirstChild(); die.IsValid(); - die = die.GetSibling()) { + for (DWARFDIE die : parent_die.children()) { const dw_tag_t tag = die.Tag(); switch (tag) { case DW_TAG_formal_parameter: { @@ -3040,91 +3011,87 @@ DWARFASTParser::ParseChildArrayInfo(const DWARFDIE &parent_die, if (!parent_die) return llvm::None; - for (DWARFDIE die = parent_die.GetFirstChild(); die.IsValid(); - die = die.GetSibling()) { + for (DWARFDIE die : parent_die.children()) { const dw_tag_t tag = die.Tag(); - switch (tag) { - case DW_TAG_subrange_type: { - DWARFAttributes attributes; - const size_t num_child_attributes = die.GetAttributes(attributes); - if (num_child_attributes > 0) { - uint64_t num_elements = 0; - uint64_t lower_bound = 0; - uint64_t upper_bound = 0; - bool upper_bound_valid = false; - uint32_t i; - for (i = 0; i < num_child_attributes; ++i) { - const dw_attr_t attr = attributes.AttributeAtIndex(i); - DWARFFormValue form_value; - if (attributes.ExtractFormValueAtIndex(i, form_value)) { - switch (attr) { - case DW_AT_name: - break; + if (tag != DW_TAG_subrange_type) + continue; - case DW_AT_count: - if (DWARFDIE var_die = die.GetReferencedDIE(DW_AT_count)) { - if (var_die.Tag() == DW_TAG_variable) - if (exe_ctx) { - if (auto frame = exe_ctx->GetFrameSP()) { - Status error; - lldb::VariableSP var_sp; - auto valobj_sp = frame->GetValueForVariableExpressionPath( - var_die.GetName(), eNoDynamicValues, 0, var_sp, - error); - if (valobj_sp) { - num_elements = valobj_sp->GetValueAsUnsigned(0); - break; - } + DWARFAttributes attributes; + const size_t num_child_attributes = die.GetAttributes(attributes); + if (num_child_attributes > 0) { + uint64_t num_elements = 0; + uint64_t lower_bound = 0; + uint64_t upper_bound = 0; + bool upper_bound_valid = false; + uint32_t i; + for (i = 0; i < num_child_attributes; ++i) { + const dw_attr_t attr = attributes.AttributeAtIndex(i); + DWARFFormValue form_value; + if (attributes.ExtractFormValueAtIndex(i, form_value)) { + switch (attr) { + case DW_AT_name: + break; + + case DW_AT_count: + if (DWARFDIE var_die = die.GetReferencedDIE(DW_AT_count)) { + if (var_die.Tag() == DW_TAG_variable) + if (exe_ctx) { + if (auto frame = exe_ctx->GetFrameSP()) { + Status error; + lldb::VariableSP var_sp; + auto valobj_sp = frame->GetValueForVariableExpressionPath( + var_die.GetName(), eNoDynamicValues, 0, var_sp, + error); + if (valobj_sp) { + num_elements = valobj_sp->GetValueAsUnsigned(0); + break; } } - } else - num_elements = form_value.Unsigned(); - break; + } + } else + num_elements = form_value.Unsigned(); + break; - case DW_AT_bit_stride: - array_info.bit_stride = form_value.Unsigned(); - break; + case DW_AT_bit_stride: + array_info.bit_stride = form_value.Unsigned(); + break; - case DW_AT_byte_stride: - array_info.byte_stride = form_value.Unsigned(); - break; + case DW_AT_byte_stride: + array_info.byte_stride = form_value.Unsigned(); + break; - case DW_AT_lower_bound: - lower_bound = form_value.Unsigned(); - break; + case DW_AT_lower_bound: + lower_bound = form_value.Unsigned(); + break; - case DW_AT_upper_bound: - upper_bound_valid = true; - upper_bound = form_value.Unsigned(); - break; + case DW_AT_upper_bound: + upper_bound_valid = true; + upper_bound = form_value.Unsigned(); + break; - default: - case DW_AT_abstract_origin: - case DW_AT_accessibility: - case DW_AT_allocated: - case DW_AT_associated: - case DW_AT_data_location: - case DW_AT_declaration: - case DW_AT_description: - case DW_AT_sibling: - case DW_AT_threads_scaled: - case DW_AT_type: - case DW_AT_visibility: - break; - } + default: + case DW_AT_abstract_origin: + case DW_AT_accessibility: + case DW_AT_allocated: + case DW_AT_associated: + case DW_AT_data_location: + case DW_AT_declaration: + case DW_AT_description: + case DW_AT_sibling: + case DW_AT_threads_scaled: + case DW_AT_type: + case DW_AT_visibility: + break; } } + } - if (num_elements == 0) { - if (upper_bound_valid && upper_bound >= lower_bound) - num_elements = upper_bound - lower_bound + 1; - } - - array_info.element_orders.push_back(num_elements); + if (num_elements == 0) { + if (upper_bound_valid && upper_bound >= lower_bound) + num_elements = upper_bound - lower_bound + 1; } - } break; - default: - break; + + array_info.element_orders.push_back(num_elements); } } return array_info; @@ -3346,8 +3313,7 @@ static DWARFDIE GetContainingFunctionWithAbstractOrigin(const DWARFDIE &die) { } static DWARFDIE FindAnyChildWithAbstractOrigin(const DWARFDIE &context) { - for (DWARFDIE candidate = context.GetFirstChild(); candidate.IsValid(); - candidate = candidate.GetSibling()) { + for (DWARFDIE candidate : context.children()) { if (candidate.GetReferencedDIE(DW_AT_abstract_origin)) { return candidate; } @@ -3511,8 +3477,7 @@ bool DWARFASTParserClang::CopyUniqueClassMethodTypes( UniqueCStringMap dst_name_to_die; UniqueCStringMap src_name_to_die_artificial; UniqueCStringMap dst_name_to_die_artificial; - for (src_die = src_class_die.GetFirstChild(); src_die.IsValid(); - src_die = src_die.GetSibling()) { + for (DWARFDIE src_die : src_class_die.children()) { if (src_die.Tag() == DW_TAG_subprogram) { // Make sure this is a declaration and not a concrete instance by looking // for DW_AT_declaration set to 1. Sometimes concrete function instances @@ -3530,8 +3495,7 @@ bool DWARFASTParserClang::CopyUniqueClassMethodTypes( } } } - for (dst_die = dst_class_die.GetFirstChild(); dst_die.IsValid(); - dst_die = dst_die.GetSibling()) { + for (DWARFDIE dst_die : dst_class_die.children()) { if (dst_die.Tag() == DW_TAG_subprogram) { // Make sure this is a declaration and not a concrete instance by looking // for DW_AT_declaration set to 1. Sometimes concrete function instances diff --git a/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h b/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h index 2ef49abc1da..9bf6240b755 100644 --- a/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h +++ b/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h @@ -111,10 +111,9 @@ protected: bool ParseChildMembers( const DWARFDIE &die, lldb_private::CompilerType &class_compiler_type, std::vector> &base_classes, - std::vector &member_accessibilities, std::vector &member_function_dies, DelayedPropertyList &delayed_properties, - lldb::AccessType &default_accessibility, bool &is_a_class, + lldb::AccessType &default_accessibility, lldb_private::ClangASTImporter::LayoutInfo &layout_info); size_t @@ -194,7 +193,6 @@ private: void ParseSingleMember(const DWARFDIE &die, const DWARFDIE &parent_die, const lldb_private::CompilerType &class_clang_type, - std::vector &member_accessibilities, lldb::AccessType default_accessibility, DelayedPropertyList &delayed_properties, lldb_private::ClangASTImporter::LayoutInfo &layout_info, @@ -217,12 +215,6 @@ private: ParsedDWARFTypeAttributes &attrs); lldb::TypeSP ParsePointerToMemberType(const DWARFDIE &die, const ParsedDWARFTypeAttributes &attrs); - - /// Complete a type from debug info, or mark it as forcefully completed if - /// there is no of the type in the current Module. Call this function in - /// contexts where the usual C++ rules require a type to be complete (base - /// class, member, etc.). - void CompleteType(lldb_private::CompilerType type); }; /// Parsed form of all attributes that are relevant for type reconstruction. diff --git a/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.cpp b/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.cpp index 0e9370be15f..2f6b36c79b8 100644 --- a/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.cpp +++ b/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.cpp @@ -17,9 +17,7 @@ using namespace lldb_private; -DWARFAbbreviationDeclaration::DWARFAbbreviationDeclaration() - : m_code(InvalidCode), m_tag(llvm::dwarf::DW_TAG_null), m_has_children(0), - m_attributes() {} +DWARFAbbreviationDeclaration::DWARFAbbreviationDeclaration() : m_attributes() {} DWARFAbbreviationDeclaration::DWARFAbbreviationDeclaration(dw_tag_t tag, uint8_t has_children) @@ -58,7 +56,7 @@ DWARFAbbreviationDeclaration::extract(const DWARFDataExtractor &data, DWARFFormValue::ValueType val; if (form == DW_FORM_implicit_const) - val.value.sval = data.GetULEB128(offset_ptr); + val.value.sval = data.GetSLEB128(offset_ptr); m_attributes.push_back(DWARFAttribute(attr, form, val)); } @@ -82,9 +80,3 @@ DWARFAbbreviationDeclaration::FindAttributeIndex(dw_attr_t attr) const { } return DW_INVALID_INDEX; } - -bool DWARFAbbreviationDeclaration:: -operator==(const DWARFAbbreviationDeclaration &rhs) const { - return Tag() == rhs.Tag() && HasChildren() == rhs.HasChildren() && - m_attributes == rhs.m_attributes; -} diff --git a/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.h b/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.h index f70aa71a595..378ba888f4e 100644 --- a/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.h +++ b/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.h @@ -53,12 +53,11 @@ public: extract(const lldb_private::DWARFDataExtractor &data, lldb::offset_t *offset_ptr); bool IsValid(); - bool operator==(const DWARFAbbreviationDeclaration &rhs) const; protected: - dw_uleb128_t m_code; - dw_tag_t m_tag; - uint8_t m_has_children; + dw_uleb128_t m_code = InvalidCode; + dw_tag_t m_tag = llvm::dwarf::DW_TAG_null; + uint8_t m_has_children = 0; DWARFAttribute::collection m_attributes; }; diff --git a/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFAttribute.cpp b/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFAttribute.cpp index 6c72d9e2622..134f6b2bd11 100644 --- a/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFAttribute.cpp +++ b/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFAttribute.cpp @@ -12,7 +12,7 @@ DWARFAttributes::DWARFAttributes() : m_infos() {} -DWARFAttributes::~DWARFAttributes() {} +DWARFAttributes::~DWARFAttributes() = default; uint32_t DWARFAttributes::FindAttributeIndex(dw_attr_t attr) const { collection::const_iterator end = m_infos.end(); @@ -25,10 +25,11 @@ uint32_t DWARFAttributes::FindAttributeIndex(dw_attr_t attr) const { return UINT32_MAX; } -void DWARFAttributes::Append(const DWARFUnit *cu, dw_offset_t attr_die_offset, - dw_attr_t attr, dw_form_t form) { - AttributeValue attr_value = { - cu, attr_die_offset, {attr, form, DWARFFormValue::ValueType()}}; +void DWARFAttributes::Append(const DWARFFormValue &form_value, + dw_offset_t attr_die_offset, dw_attr_t attr) { + AttributeValue attr_value = {const_cast(form_value.GetUnit()), + attr_die_offset, + {attr, form_value.Form(), form_value.Value()}}; m_infos.push_back(attr_value); } @@ -37,6 +38,10 @@ bool DWARFAttributes::ExtractFormValueAtIndex( const DWARFUnit *cu = CompileUnitAtIndex(i); form_value.SetUnit(cu); form_value.SetForm(FormAtIndex(i)); + if (form_value.Form() == DW_FORM_implicit_const) { + form_value.SetValue(ValueAtIndex(i)); + return true; + } lldb::offset_t offset = DIEOffsetAtIndex(i); return form_value.ExtractValue(cu->GetData(), &offset); } diff --git a/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFAttribute.h b/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFAttribute.h index 9948969f108..a31ee861179 100644 --- a/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFAttribute.h +++ b/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFAttribute.h @@ -22,21 +22,15 @@ public: DWARFFormValue::ValueType value) : m_attr(attr), m_form(form), m_value(value) {} - void set(dw_attr_t attr, dw_form_t form) { - m_attr = attr; - m_form = form; - } dw_attr_t get_attr() const { return m_attr; } dw_form_t get_form() const { return m_form; } + DWARFFormValue::ValueType get_value() const { return m_value; } void get(dw_attr_t &attr, dw_form_t &form, DWARFFormValue::ValueType &val) const { attr = m_attr; form = m_form; val = m_value; } - bool operator==(const DWARFAttribute &rhs) const { - return m_attr == rhs.m_attr && m_form == rhs.m_form; - } typedef std::vector collection; typedef collection::iterator iterator; typedef collection::const_iterator const_iterator; @@ -52,11 +46,9 @@ public: DWARFAttributes(); ~DWARFAttributes(); - void Append(const DWARFUnit *cu, dw_offset_t attr_die_offset, - dw_attr_t attr, dw_form_t form); - const DWARFUnit *CompileUnitAtIndex(uint32_t i) const { - return m_infos[i].cu; - } + void Append(const DWARFFormValue &form_value, dw_offset_t attr_die_offset, + dw_attr_t attr); + DWARFUnit *CompileUnitAtIndex(uint32_t i) const { return m_infos[i].cu; } dw_offset_t DIEOffsetAtIndex(uint32_t i) const { return m_infos[i].die_offset; } @@ -64,6 +56,9 @@ public: return m_infos[i].attr.get_attr(); } dw_attr_t FormAtIndex(uint32_t i) const { return m_infos[i].attr.get_form(); } + DWARFFormValue::ValueType ValueAtIndex(uint32_t i) const { + return m_infos[i].attr.get_value(); + } bool ExtractFormValueAtIndex(uint32_t i, DWARFFormValue &form_value) const; DWARFDIE FormValueAsReferenceAtIndex(uint32_t i) const; DWARFDIE FormValueAsReference(dw_attr_t attr) const; @@ -73,8 +68,8 @@ public: protected: struct AttributeValue { - const DWARFUnit *cu; // Keep the compile unit with each attribute in - // case we have DW_FORM_ref_addr values + DWARFUnit *cu; // Keep the compile unit with each attribute in + // case we have DW_FORM_ref_addr values dw_offset_t die_offset; DWARFAttribute attr; }; diff --git a/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFBaseDIE.h b/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFBaseDIE.h index 059b84864be..36df980f6ef 100644 --- a/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFBaseDIE.h +++ b/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFBaseDIE.h @@ -24,7 +24,7 @@ class SymbolFileDWARF; class DWARFBaseDIE { public: - DWARFBaseDIE() : m_cu(nullptr), m_die(nullptr) {} + DWARFBaseDIE() = default; DWARFBaseDIE(DWARFUnit *cu, DWARFDebugInfoEntry *die) : m_cu(cu), m_die(die) {} @@ -115,8 +115,8 @@ public: Recurse recurse = Recurse::yes) const; protected: - DWARFUnit *m_cu; - DWARFDebugInfoEntry *m_die; + DWARFUnit *m_cu = nullptr; + DWARFDebugInfoEntry *m_die = nullptr; }; bool operator==(const DWARFBaseDIE &lhs, const DWARFBaseDIE &rhs); diff --git a/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp b/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp index f54fe0662aa..9ca160b474f 100644 --- a/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp +++ b/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp @@ -99,3 +99,18 @@ void DWARFCompileUnit::BuildAddressRangeTable( } } } + +DWARFCompileUnit &DWARFCompileUnit::GetNonSkeletonUnit() { + return llvm::cast(DWARFUnit::GetNonSkeletonUnit()); +} + +DWARFDIE DWARFCompileUnit::LookupAddress(const dw_addr_t address) { + if (DIE()) { + const DWARFDebugAranges &func_aranges = GetFunctionAranges(); + + // Re-check the aranges auto pointer contents in case it was created above + if (!func_aranges.IsEmpty()) + return GetDIE(func_aranges.FindAddress(address)); + } + return DWARFDIE(); +} diff --git a/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h b/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h index 3ec161f7dd5..ab3017ba0ff 100644 --- a/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h +++ b/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h @@ -20,6 +20,10 @@ public: static bool classof(const DWARFUnit *unit) { return !unit->IsTypeUnit(); } + DWARFCompileUnit &GetNonSkeletonUnit(); + + DWARFDIE LookupAddress(const dw_addr_t address); + private: DWARFCompileUnit(SymbolFileDWARF &dwarf, lldb::user_id_t uid, const DWARFUnitHeader &header, diff --git a/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp b/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp index 8e995e62797..dda691eecac 100644 --- a/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp +++ b/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp @@ -54,7 +54,7 @@ public: explicit ElaboratingDIEIterator(DWARFDIE d) : m_worklist(1, d) {} /// End marker - ElaboratingDIEIterator() {} + ElaboratingDIEIterator() = default; const DWARFDIE &operator*() const { return m_worklist.back(); } ElaboratingDIEIterator &operator++() { @@ -192,7 +192,7 @@ DWARFDIE::LookupDeepestBlock(lldb::addr_t address) const { } if (check_children) { - for (DWARFDIE child = GetFirstChild(); child; child = child.GetSibling()) { + for (DWARFDIE child : children()) { if (DWARFDIE child_result = child.LookupDeepestBlock(address)) return child_result; } diff --git a/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.h b/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.h index 13737280926..56154055c44 100644 --- a/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.h +++ b/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.h @@ -11,9 +11,11 @@ #include "DWARFBaseDIE.h" #include "llvm/ADT/SmallSet.h" +#include "llvm/ADT/iterator_range.h" class DWARFDIE : public DWARFBaseDIE { public: + class child_iterator; using DWARFBaseDIE::DWARFBaseDIE; // Tests @@ -88,6 +90,47 @@ public: int &decl_line, int &decl_column, int &call_file, int &call_line, int &call_column, lldb_private::DWARFExpression *frame_base) const; + /// The range of all the children of this DIE. + /// + /// This is a template just because child_iterator is not completely defined + /// at this point. + template + llvm::iterator_range children() const { + return llvm::make_range(T(*this), T()); + } +}; + +class DWARFDIE::child_iterator + : public llvm::iterator_facade_base { + /// The current child or an invalid DWARFDie. + DWARFDIE m_die; + +public: + child_iterator() = default; + child_iterator(const DWARFDIE &parent) : m_die(parent.GetFirstChild()) {} + bool operator==(const child_iterator &it) const { + // DWARFDIE's operator== differentiates between an invalid DWARFDIE that + // has a CU but no DIE and one that has neither CU nor DIE. The 'end' + // iterator could be default constructed, so explicitly allow + // (CU, (DIE)nullptr) == (nullptr, nullptr) -> true + if (!m_die.IsValid() && !it.m_die.IsValid()) + return true; + return m_die == it.m_die; + } + const DWARFDIE &operator*() const { + assert(m_die.IsValid() && "Derefencing invalid iterator?"); + return m_die; + } + DWARFDIE &operator*() { + assert(m_die.IsValid() && "Derefencing invalid iterator?"); + return m_die; + } + child_iterator &operator++() { + assert(m_die.IsValid() && "Incrementing invalid iterator?"); + m_die = m_die.GetSibling(); + return *this; + } }; #endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFDIE_H diff --git a/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAbbrev.h b/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAbbrev.h index 555864f4496..ec6b93ce0e7 100644 --- a/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAbbrev.h +++ b/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAbbrev.h @@ -26,8 +26,7 @@ typedef DWARFAbbreviationDeclarationColl::const_iterator class DWARFAbbreviationDeclarationSet { public: - DWARFAbbreviationDeclarationSet() - : m_offset(DW_INVALID_OFFSET), m_idx_offset(0), m_decls() {} + DWARFAbbreviationDeclarationSet() : m_offset(DW_INVALID_OFFSET), m_decls() {} DWARFAbbreviationDeclarationSet(dw_offset_t offset, uint32_t idx_offset) : m_offset(offset), m_idx_offset(idx_offset), m_decls() {} @@ -51,7 +50,7 @@ public: /// @} private: dw_offset_t m_offset; - uint32_t m_idx_offset; + uint32_t m_idx_offset = 0; std::vector m_decls; }; diff --git a/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugArangeSet.cpp b/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugArangeSet.cpp index 728cefe620a..ce514381ee3 100644 --- a/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugArangeSet.cpp +++ b/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugArangeSet.cpp @@ -8,22 +8,18 @@ #include "DWARFDebugArangeSet.h" #include "DWARFDataExtractor.h" +#include "LogChannelDWARF.h" #include "llvm/Object/Error.h" #include using namespace lldb_private; DWARFDebugArangeSet::DWARFDebugArangeSet() - : m_offset(DW_INVALID_OFFSET), m_header(), m_arange_descriptors() { - m_header.length = 0; - m_header.version = 0; - m_header.cu_offset = 0; - m_header.addr_size = 0; - m_header.seg_size = 0; -} + : m_offset(DW_INVALID_OFFSET), m_next_offset(DW_INVALID_OFFSET) {} void DWARFDebugArangeSet::Clear() { m_offset = DW_INVALID_OFFSET; + m_next_offset = DW_INVALID_OFFSET; m_header.length = 0; m_header.version = 0; m_header.cu_offset = 0; @@ -54,6 +50,12 @@ llvm::Error DWARFDebugArangeSet::extract(const DWARFDataExtractor &data, // consists of an address and a length, each in the size appropriate for an // address on the target architecture. m_header.length = data.GetDWARFInitialLength(offset_ptr); + // The length could be 4 bytes or 12 bytes, so use the current offset to + // determine the next offset correctly. + if (m_header.length > 0) + m_next_offset = *offset_ptr + m_header.length; + else + m_next_offset = DW_INVALID_OFFSET; m_header.version = data.GetU16(offset_ptr); m_header.cu_offset = data.GetDWARFOffset(offset_ptr); m_header.addr_size = data.GetU8(offset_ptr); @@ -105,17 +107,45 @@ llvm::Error DWARFDebugArangeSet::extract(const DWARFDataExtractor &data, "DWARFDebugArangeSet::Descriptor.address and " "DWARFDebugArangeSet::Descriptor.length must have same size"); - while (data.ValidOffset(*offset_ptr)) { + const lldb::offset_t next_offset = GetNextOffset(); + assert(next_offset != DW_INVALID_OFFSET); + uint32_t num_terminators = 0; + bool last_was_terminator = false; + while (*offset_ptr < next_offset) { arangeDescriptor.address = data.GetMaxU64(offset_ptr, m_header.addr_size); arangeDescriptor.length = data.GetMaxU64(offset_ptr, m_header.addr_size); // Each set of tuples is terminated by a 0 for the address and 0 for - // the length. - if (!arangeDescriptor.address && !arangeDescriptor.length) - return llvm::ErrorSuccess(); - - m_arange_descriptors.push_back(arangeDescriptor); + // the length. Some linkers can emit .debug_aranges with multiple + // terminator pair entries that are still withing the length of the + // DWARFDebugArangeSet. We want to be sure to parse all entries for + // this DWARFDebugArangeSet so that we don't stop parsing early and end up + // treating addresses as a header of the next DWARFDebugArangeSet. We also + // need to make sure we parse all valid address pairs so we don't omit them + // from the aranges result, so we can't stop at the first terminator entry + // we find. + if (arangeDescriptor.address == 0 && arangeDescriptor.length == 0) { + ++num_terminators; + last_was_terminator = true; + } else { + last_was_terminator = false; + // Only add .debug_aranges address entries that have a non zero size. + // Some linkers will zero out the length field for some .debug_aranges + // entries if they were stripped. We also could watch out for multiple + // entries at address zero and remove those as well. + if (arangeDescriptor.length > 0) + m_arange_descriptors.push_back(arangeDescriptor); + } + } + if (num_terminators > 1) { + Log *log = LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_INFO); + LLDB_LOG(log, + "warning: DWARFDebugArangeSet at %#" PRIx64 " contains %u " + "terminator entries", + m_offset, num_terminators); } + if (last_was_terminator) + return llvm::ErrorSuccess(); return llvm::make_error( "arange descriptors not terminated by null entry"); diff --git a/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugArangeSet.h b/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugArangeSet.h index 6b5b69a70a8..3c8633eaa3c 100644 --- a/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugArangeSet.h +++ b/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugArangeSet.h @@ -16,18 +16,21 @@ class DWARFDebugArangeSet { public: struct Header { - uint32_t length; // The total length of the entries for that set, not - // including the length field itself. - uint16_t version; // The DWARF version number - uint32_t cu_offset; // The offset from the beginning of the .debug_info - // section of the compilation unit entry referenced by - // the table. - uint8_t addr_size; // The size in bytes of an address on the target - // architecture. For segmented addressing, this is the - // size of the offset portion of the address - uint8_t seg_size; // The size in bytes of a segment descriptor on the target - // architecture. If the target system uses a flat address - // space, this value is 0. + /// The total length of the entries for that set, not including the length + /// field itself. + uint32_t length = 0; + /// The DWARF version number. + uint16_t version = 0; + /// The offset from the beginning of the .debug_info section of the + /// compilation unit entry referenced by the table. + uint32_t cu_offset = 0; + /// The size in bytes of an address on the target architecture. For + /// segmented addressing, this is the size of the offset portion of the + /// address. + uint8_t addr_size = 0; + /// The size in bytes of a segment descriptor on the target architecture. + /// If the target system uses a flat address space, this value is 0. + uint8_t seg_size = 0; }; struct Descriptor { @@ -44,7 +47,7 @@ public: dw_offset_t FindAddress(dw_addr_t address) const; size_t NumDescriptors() const { return m_arange_descriptors.size(); } const Header &GetHeader() const { return m_header; } - + dw_offset_t GetNextOffset() const { return m_next_offset; } const Descriptor &GetDescriptorRef(uint32_t i) const { return m_arange_descriptors[i]; } @@ -54,7 +57,8 @@ protected: typedef DescriptorColl::iterator DescriptorIter; typedef DescriptorColl::const_iterator DescriptorConstIter; - uint32_t m_offset; + dw_offset_t m_offset; + dw_offset_t m_next_offset; Header m_header; DescriptorColl m_arange_descriptors; }; diff --git a/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.cpp b/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.cpp index 7dc52c1e2df..65923cb4ad6 100644 --- a/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.cpp +++ b/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.cpp @@ -9,6 +9,7 @@ #include "DWARFDebugAranges.h" #include "DWARFDebugArangeSet.h" #include "DWARFUnit.h" +#include "LogChannelDWARF.h" #include "lldb/Utility/Log.h" #include "lldb/Utility/Timer.h" @@ -31,31 +32,40 @@ public: }; // Extract -llvm::Error -DWARFDebugAranges::extract(const DWARFDataExtractor &debug_aranges_data) { +void DWARFDebugAranges::extract(const DWARFDataExtractor &debug_aranges_data) { lldb::offset_t offset = 0; DWARFDebugArangeSet set; Range range; while (debug_aranges_data.ValidOffset(offset)) { - llvm::Error error = set.extract(debug_aranges_data, &offset); - if (!error) - return error; + const lldb::offset_t set_offset = offset; + if (llvm::Error error = set.extract(debug_aranges_data, &offset)) { + Log *log = LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_INFO); + LLDB_LOG_ERROR(log, std::move(error), + "DWARFDebugAranges::extract failed to extract " + ".debug_aranges set at offset %#" PRIx64, + set_offset); + } else { + const uint32_t num_descriptors = set.NumDescriptors(); + if (num_descriptors > 0) { + const dw_offset_t cu_offset = set.GetHeader().cu_offset; - const uint32_t num_descriptors = set.NumDescriptors(); - if (num_descriptors > 0) { - const dw_offset_t cu_offset = set.GetHeader().cu_offset; - - for (uint32_t i = 0; i < num_descriptors; ++i) { - const DWARFDebugArangeSet::Descriptor &descriptor = - set.GetDescriptorRef(i); - m_aranges.Append(RangeToDIE::Entry(descriptor.address, - descriptor.length, cu_offset)); + for (uint32_t i = 0; i < num_descriptors; ++i) { + const DWARFDebugArangeSet::Descriptor &descriptor = + set.GetDescriptorRef(i); + m_aranges.Append(RangeToDIE::Entry(descriptor.address, + descriptor.length, cu_offset)); + } } } + // Always use the previous DWARFDebugArangeSet's information to calculate + // the offset of the next DWARFDebugArangeSet in case we entouncter an + // error in the current DWARFDebugArangeSet and our offset position is + // still in the middle of the data. If we do this, we can parse all valid + // DWARFDebugArangeSet objects without returning invalid errors. + offset = set.GetNextOffset(); set.Clear(); } - return llvm::ErrorSuccess(); } void DWARFDebugAranges::Dump(Log *log) const { @@ -78,8 +88,7 @@ void DWARFDebugAranges::AppendRange(dw_offset_t offset, dw_addr_t low_pc, } void DWARFDebugAranges::Sort(bool minimize) { - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer(func_cat, "%s this = %p", LLVM_PRETTY_FUNCTION, + LLDB_SCOPED_TIMERF("%s this = %p", LLVM_PRETTY_FUNCTION, static_cast(this)); m_aranges.Sort(); diff --git a/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.h b/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.h index 96e82619f98..5ff37e400c8 100644 --- a/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.h +++ b/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.h @@ -26,8 +26,7 @@ public: void Clear() { m_aranges.Clear(); } - llvm::Error - extract(const lldb_private::DWARFDataExtractor &debug_aranges_data); + void extract(const lldb_private::DWARFDataExtractor &debug_aranges_data); // Use append range multiple times and then call sort void AppendRange(dw_offset_t cu_offset, dw_addr_t low_pc, dw_addr_t high_pc); diff --git a/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp b/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp index 874978bf139..e43afa10441 100644 --- a/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp +++ b/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp @@ -34,17 +34,18 @@ DWARFDebugInfo::DWARFDebugInfo(SymbolFileDWARF &dwarf, lldb_private::DWARFContext &context) : m_dwarf(dwarf), m_context(context), m_units(), m_cu_aranges_up() {} -llvm::Expected DWARFDebugInfo::GetCompileUnitAranges() { +const DWARFDebugAranges &DWARFDebugInfo::GetCompileUnitAranges() { if (m_cu_aranges_up) return *m_cu_aranges_up; m_cu_aranges_up = std::make_unique(); const DWARFDataExtractor &debug_aranges_data = m_context.getOrLoadArangesData(); - if (llvm::Error error = m_cu_aranges_up->extract(debug_aranges_data)) - return std::move(error); - // Make a list of all CUs represented by the arange data in the file. + // Extract what we can from the .debug_aranges first. + m_cu_aranges_up->extract(debug_aranges_data); + + // Make a list of all CUs represented by the .debug_aranges data. std::set cus_with_data; for (size_t n = 0; n < m_cu_aranges_up->GetNumRanges(); n++) { dw_offset_t offset = m_cu_aranges_up->OffsetAtIndex(n); @@ -52,8 +53,7 @@ llvm::Expected DWARFDebugInfo::GetCompileUnitAranges() { cus_with_data.insert(offset); } - // Manually build arange data for everything that wasn't in the - // .debug_aranges table. + // Manually build arange data for everything that wasn't in .debug_aranges. const size_t num_units = GetNumUnits(); for (size_t idx = 0; idx < num_units; ++idx) { DWARFUnit *cu = GetUnitAtIndex(idx); @@ -72,16 +72,10 @@ void DWARFDebugInfo::ParseUnitsFor(DIERef::Section section) { DWARFDataExtractor data = section == DIERef::Section::DebugTypes ? m_context.getOrLoadDebugTypesData() : m_context.getOrLoadDebugInfoData(); - const llvm::DWARFUnitIndex *index = nullptr; - if (m_context.isDwo()) - index = &llvm::getDWARFUnitIndex(m_context.GetAsLLVM(), - section == DIERef::Section::DebugTypes - ? llvm::DW_SECT_EXT_TYPES - : llvm::DW_SECT_INFO); lldb::offset_t offset = 0; while (data.ValidOffset(offset)) { llvm::Expected unit_sp = DWARFUnit::extract( - m_dwarf, m_units.size(), data, section, &offset, index); + m_dwarf, m_units.size(), data, section, &offset); if (!unit_sp) { // FIXME: Propagate this error up. @@ -199,4 +193,3 @@ DWARFDebugInfo::GetDIE(const DIERef &die_ref) { return cu->GetNonSkeletonUnit().GetDIE(die_ref.die_offset()); return DWARFDIE(); // Not found } - diff --git a/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h b/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h index bdc718a5c2f..46c04d749c4 100644 --- a/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h +++ b/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h @@ -54,7 +54,7 @@ public: (1 << 2) // Show all parent DIEs when dumping single DIEs }; - llvm::Expected GetCompileUnitAranges(); + const DWARFDebugAranges &GetCompileUnitAranges(); protected: typedef std::vector UnitColl; diff --git a/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp b/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp index f6425a889da..39915aa889f 100644 --- a/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp +++ b/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp @@ -8,7 +8,7 @@ #include "DWARFDebugInfoEntry.h" -#include +#include #include @@ -49,156 +49,159 @@ bool DWARFDebugInfoEntry::Extract(const DWARFDataExtractor &data, // assert (fixed_form_sizes); // For best performance this should be // specified! - if (m_abbr_idx) { - lldb::offset_t offset = *offset_ptr; - const auto *abbrevDecl = GetAbbreviationDeclarationPtr(cu); - if (abbrevDecl == nullptr) { - cu->GetSymbolFileDWARF().GetObjectFile()->GetModule()->ReportError( - "{0x%8.8x}: invalid abbreviation code %u, please file a bug and " - "attach the file at the start of this error message", - m_offset, (unsigned)abbr_idx); - // WE can't parse anymore if the DWARF is borked... - *offset_ptr = UINT32_MAX; - return false; - } - m_tag = abbrevDecl->Tag(); - m_has_children = abbrevDecl->HasChildren(); - // Skip all data in the .debug_info or .debug_types for the attributes - const uint32_t numAttributes = abbrevDecl->NumAttributes(); - uint32_t i; - dw_form_t form; - for (i = 0; i < numAttributes; ++i) { - form = abbrevDecl->GetFormByIndexUnchecked(i); - llvm::Optional fixed_skip_size = - DWARFFormValue::GetFixedSize(form, cu); - if (fixed_skip_size) - offset += *fixed_skip_size; - else { - bool form_is_indirect = false; - do { - form_is_indirect = false; - uint32_t form_size = 0; - switch (form) { - // Blocks if inlined data that have a length field and the data bytes - // inlined in the .debug_info/.debug_types - case DW_FORM_exprloc: - case DW_FORM_block: - form_size = data.GetULEB128(&offset); - break; - case DW_FORM_block1: - form_size = data.GetU8_unchecked(&offset); - break; - case DW_FORM_block2: - form_size = data.GetU16_unchecked(&offset); - break; - case DW_FORM_block4: - form_size = data.GetU32_unchecked(&offset); - break; - - // Inlined NULL terminated C-strings - case DW_FORM_string: - data.GetCStr(&offset); - break; - - // Compile unit address sized values - case DW_FORM_addr: - form_size = cu->GetAddressByteSize(); - break; - case DW_FORM_ref_addr: - if (cu->GetVersion() <= 2) - form_size = cu->GetAddressByteSize(); - else - form_size = 4; - break; - - // 0 sized form - case DW_FORM_flag_present: - form_size = 0; - break; - - // 1 byte values - case DW_FORM_addrx1: - case DW_FORM_data1: - case DW_FORM_flag: - case DW_FORM_ref1: - case DW_FORM_strx1: - form_size = 1; - break; - - // 2 byte values - case DW_FORM_addrx2: - case DW_FORM_data2: - case DW_FORM_ref2: - case DW_FORM_strx2: - form_size = 2; - break; - - // 3 byte values - case DW_FORM_addrx3: - case DW_FORM_strx3: - form_size = 3; - break; - - // 4 byte values - case DW_FORM_addrx4: - case DW_FORM_data4: - case DW_FORM_ref4: - case DW_FORM_strx4: - form_size = 4; - break; - - // 8 byte values - case DW_FORM_data8: - case DW_FORM_ref8: - case DW_FORM_ref_sig8: - form_size = 8; - break; - - // signed or unsigned LEB 128 values - case DW_FORM_addrx: - case DW_FORM_loclistx: - case DW_FORM_rnglistx: - case DW_FORM_sdata: - case DW_FORM_udata: - case DW_FORM_ref_udata: - case DW_FORM_GNU_addr_index: - case DW_FORM_GNU_str_index: - case DW_FORM_strx: - data.Skip_LEB128(&offset); - break; - - case DW_FORM_indirect: - form_is_indirect = true; - form = data.GetULEB128(&offset); - break; - - case DW_FORM_strp: - case DW_FORM_sec_offset: - data.GetU32(&offset); - break; - - case DW_FORM_implicit_const: - form_size = 0; - break; - - default: - *offset_ptr = m_offset; - return false; - } - offset += form_size; - - } while (form_is_indirect); - } - } - *offset_ptr = offset; - return true; - } else { + if (m_abbr_idx == 0) { m_tag = llvm::dwarf::DW_TAG_null; m_has_children = false; return true; // NULL debug tag entry } - return false; + lldb::offset_t offset = *offset_ptr; + const auto *abbrevDecl = GetAbbreviationDeclarationPtr(cu); + if (abbrevDecl == nullptr) { + cu->GetSymbolFileDWARF().GetObjectFile()->GetModule()->ReportError( + "{0x%8.8x}: invalid abbreviation code %u, please file a bug and " + "attach the file at the start of this error message", + m_offset, (unsigned)abbr_idx); + // WE can't parse anymore if the DWARF is borked... + *offset_ptr = UINT32_MAX; + return false; + } + m_tag = abbrevDecl->Tag(); + m_has_children = abbrevDecl->HasChildren(); + // Skip all data in the .debug_info or .debug_types for the attributes + const uint32_t numAttributes = abbrevDecl->NumAttributes(); + uint32_t i; + dw_form_t form; + for (i = 0; i < numAttributes; ++i) { + form = abbrevDecl->GetFormByIndexUnchecked(i); + llvm::Optional fixed_skip_size = + DWARFFormValue::GetFixedSize(form, cu); + if (fixed_skip_size) + offset += *fixed_skip_size; + else { + bool form_is_indirect = false; + do { + form_is_indirect = false; + uint32_t form_size = 0; + switch (form) { + // Blocks if inlined data that have a length field and the data bytes + // inlined in the .debug_info/.debug_types + case DW_FORM_exprloc: + case DW_FORM_block: + form_size = data.GetULEB128(&offset); + break; + case DW_FORM_block1: + form_size = data.GetU8_unchecked(&offset); + break; + case DW_FORM_block2: + form_size = data.GetU16_unchecked(&offset); + break; + case DW_FORM_block4: + form_size = data.GetU32_unchecked(&offset); + break; + + // Inlined NULL terminated C-strings + case DW_FORM_string: + data.GetCStr(&offset); + break; + + // Compile unit address sized values + case DW_FORM_addr: + form_size = cu->GetAddressByteSize(); + break; + case DW_FORM_ref_addr: + if (cu->GetVersion() <= 2) + form_size = cu->GetAddressByteSize(); + else + form_size = 4; + break; + + // 0 sized form + case DW_FORM_flag_present: + form_size = 0; + break; + + // 1 byte values + case DW_FORM_addrx1: + case DW_FORM_data1: + case DW_FORM_flag: + case DW_FORM_ref1: + case DW_FORM_strx1: + form_size = 1; + break; + + // 2 byte values + case DW_FORM_addrx2: + case DW_FORM_data2: + case DW_FORM_ref2: + case DW_FORM_strx2: + form_size = 2; + break; + + // 3 byte values + case DW_FORM_addrx3: + case DW_FORM_strx3: + form_size = 3; + break; + + // 4 byte values + case DW_FORM_addrx4: + case DW_FORM_data4: + case DW_FORM_ref4: + case DW_FORM_strx4: + form_size = 4; + break; + + // 8 byte values + case DW_FORM_data8: + case DW_FORM_ref8: + case DW_FORM_ref_sig8: + form_size = 8; + break; + + // signed or unsigned LEB 128 values + case DW_FORM_addrx: + case DW_FORM_loclistx: + case DW_FORM_rnglistx: + case DW_FORM_sdata: + case DW_FORM_udata: + case DW_FORM_ref_udata: + case DW_FORM_GNU_addr_index: + case DW_FORM_GNU_str_index: + case DW_FORM_strx: + data.Skip_LEB128(&offset); + break; + + case DW_FORM_indirect: + form_is_indirect = true; + form = data.GetULEB128(&offset); + break; + + case DW_FORM_strp: + case DW_FORM_line_strp: + case DW_FORM_sec_offset: + data.GetU32(&offset); + break; + + case DW_FORM_implicit_const: + form_size = 0; + break; + + default: + cu->GetSymbolFileDWARF().GetObjectFile()->GetModule()->ReportError( + "{0x%8.8x}: Unsupported DW_FORM_0x%x, please file a bug and " + "attach the file at the start of this error message", + m_offset, (unsigned)form); + *offset_ptr = m_offset; + return false; + } + offset += form_size; + + } while (form_is_indirect); + } + } + *offset_ptr = offset; + return true; } static DWARFRangeList GetRangesOrReportError(DWARFUnit &unit, @@ -211,11 +214,12 @@ static DWARFRangeList GetRangesOrReportError(DWARFUnit &unit, if (expected_ranges) return std::move(*expected_ranges); unit.GetSymbolFileDWARF().GetObjectFile()->GetModule()->ReportError( - "{0x%8.8x}: DIE has DW_AT_ranges(0x%" PRIx64 ") attribute, but " + "{0x%8.8x}: DIE has DW_AT_ranges(%s 0x%" PRIx64 ") attribute, but " "range extraction failed (%s), please file a bug " "and attach the file at the start of this error message", - die.GetOffset(), value.Unsigned(), - toString(expected_ranges.takeError()).c_str()); + die.GetOffset(), + llvm::dwarf::FormEncodingString(value.Form()).str().c_str(), + value.Unsigned(), toString(expected_ranges.takeError()).c_str()); return DWARFRangeList(); } @@ -399,7 +403,7 @@ bool DWARFDebugInfoEntry::GetDIENamesAndRanges( // specification or abstract origin attributes and including those in the // results. Any duplicate attributes will have the first instance take // precedence (this can happen for declaration attributes). -size_t DWARFDebugInfoEntry::GetAttributes(const DWARFUnit *cu, +size_t DWARFDebugInfoEntry::GetAttributes(DWARFUnit *cu, DWARFAttributes &attributes, Recurse recurse, uint32_t curr_depth) const { @@ -429,7 +433,7 @@ size_t DWARFDebugInfoEntry::GetAttributes(const DWARFUnit *cu, } LLVM_FALLTHROUGH; default: - attributes.Append(cu, offset, attr, form); + attributes.Append(form_value, offset, attr); break; } @@ -687,13 +691,15 @@ const char *DWARFDebugInfoEntry::GetPubname(const DWARFUnit *cu) const { /// table, except that the actual DIE offset for the function is placed in the /// table instead of the compile unit offset. void DWARFDebugInfoEntry::BuildFunctionAddressRangeTable( - const DWARFUnit *cu, DWARFDebugAranges *debug_aranges) const { + DWARFUnit *cu, DWARFDebugAranges *debug_aranges) const { if (m_tag) { if (m_tag == DW_TAG_subprogram) { - dw_addr_t lo_pc = LLDB_INVALID_ADDRESS; - dw_addr_t hi_pc = LLDB_INVALID_ADDRESS; - if (GetAttributeAddressRange(cu, lo_pc, hi_pc, LLDB_INVALID_ADDRESS)) { - debug_aranges->AppendRange(GetOffset(), lo_pc, hi_pc); + DWARFRangeList ranges; + GetAttributeAddressRanges(cu, ranges, + /*check_hi_lo_pc=*/true); + for (const auto &r : ranges) { + debug_aranges->AppendRange(GetOffset(), r.GetRangeBase(), + r.GetRangeEnd()); } } diff --git a/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h b/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h index 3019e1767f1..64e86c71ac0 100644 --- a/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h +++ b/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h @@ -35,21 +35,20 @@ public: typedef collection::const_iterator const_iterator; DWARFDebugInfoEntry() - : m_offset(DW_INVALID_OFFSET), m_parent_idx(0), m_sibling_idx(0), - m_has_children(false), m_abbr_idx(0), m_tag(llvm::dwarf::DW_TAG_null) {} + : m_offset(DW_INVALID_OFFSET), m_sibling_idx(0), m_has_children(false) {} explicit operator bool() const { return m_offset != DW_INVALID_OFFSET; } bool operator==(const DWARFDebugInfoEntry &rhs) const; bool operator!=(const DWARFDebugInfoEntry &rhs) const; - void BuildFunctionAddressRangeTable(const DWARFUnit *cu, + void BuildFunctionAddressRangeTable(DWARFUnit *cu, DWARFDebugAranges *debug_aranges) const; bool Extract(const lldb_private::DWARFDataExtractor &data, const DWARFUnit *cu, lldb::offset_t *offset_ptr); using Recurse = DWARFBaseDIE::Recurse; - size_t GetAttributes(const DWARFUnit *cu, DWARFAttributes &attrs, + size_t GetAttributes(DWARFUnit *cu, DWARFAttributes &attrs, Recurse recurse = Recurse::yes) const { return GetAttributes(cu, attrs, recurse, 0 /* curr_depth */); } @@ -167,21 +166,21 @@ protected: GetDWARFDeclContextStatic(const DWARFDebugInfoEntry *die, DWARFUnit *cu); dw_offset_t m_offset; // Offset within the .debug_info/.debug_types - uint32_t m_parent_idx; // How many to subtract from "this" to get the parent. - // If zero this die has no parent + uint32_t m_parent_idx = 0; // How many to subtract from "this" to get the + // parent. If zero this die has no parent uint32_t m_sibling_idx : 31, // How many to add to "this" to get the sibling. // If it is zero, then the DIE doesn't have children, or the // DWARF claimed it had children but the DIE only contained // a single NULL terminating child. m_has_children : 1; - uint16_t m_abbr_idx; + uint16_t m_abbr_idx = 0; /// A copy of the DW_TAG value so we don't have to go through the compile /// unit abbrev table dw_tag_t m_tag = llvm::dwarf::DW_TAG_null; private: - size_t GetAttributes(const DWARFUnit *cu, DWARFAttributes &attrs, - Recurse recurse, uint32_t curr_depth) const; + size_t GetAttributes(DWARFUnit *cu, DWARFAttributes &attrs, Recurse recurse, + uint32_t curr_depth) const; }; #endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFDEBUGINFOENTRY_H diff --git a/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.h b/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.h index 9072b2dc011..e4669440541 100644 --- a/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.h +++ b/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.h @@ -23,7 +23,7 @@ class DWARFDeclContext { public: struct Entry { - Entry() : tag(llvm::dwarf::DW_TAG_null), name(nullptr) {} + Entry() = default; Entry(dw_tag_t t, const char *n) : tag(t), name(n) {} bool NameMatches(const Entry &rhs) const { @@ -37,11 +37,11 @@ public: // Test operator explicit operator bool() const { return tag != 0; } - dw_tag_t tag; - const char *name; + dw_tag_t tag = llvm::dwarf::DW_TAG_null; + const char *name = nullptr; }; - DWARFDeclContext() : m_entries(), m_language(lldb::eLanguageTypeUnknown) {} + DWARFDeclContext() : m_entries() {} void AppendDeclContext(dw_tag_t tag, const char *name) { m_entries.push_back(Entry(tag, name)); @@ -83,7 +83,7 @@ protected: typedef std::vector collection; collection m_entries; mutable std::string m_qualified_name; - lldb::LanguageType m_language; + lldb::LanguageType m_language = lldb::eLanguageTypeUnknown; }; #endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFDECLCONTEXT_H diff --git a/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFDefines.h b/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFDefines.h index 1b7102cd7e3..2d0d5cad461 100644 --- a/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFDefines.h +++ b/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFDefines.h @@ -10,7 +10,7 @@ #define LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFDEFINES_H #include "lldb/Core/dwarf.h" -#include +#include namespace lldb_private { diff --git a/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp b/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp index 305f1cbd282..4c498705da4 100644 --- a/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp +++ b/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// -#include +#include #include "lldb/Core/Module.h" #include "lldb/Core/dwarf.h" @@ -150,40 +150,40 @@ struct FormSize { uint8_t valid:1, size:7; }; static FormSize g_form_sizes[] = { - {0,0}, // 0x00 unused - {0,0}, // 0x01 DW_FORM_addr - {0,0}, // 0x02 unused - {0,0}, // 0x03 DW_FORM_block2 - {0,0}, // 0x04 DW_FORM_block4 - {1,2}, // 0x05 DW_FORM_data2 - {1,4}, // 0x06 DW_FORM_data4 - {1,8}, // 0x07 DW_FORM_data8 - {0,0}, // 0x08 DW_FORM_string - {0,0}, // 0x09 DW_FORM_block - {0,0}, // 0x0a DW_FORM_block1 - {1,1}, // 0x0b DW_FORM_data1 - {1,1}, // 0x0c DW_FORM_flag - {0,0}, // 0x0d DW_FORM_sdata - {1,4}, // 0x0e DW_FORM_strp - {0,0}, // 0x0f DW_FORM_udata - {0,0}, // 0x10 DW_FORM_ref_addr (addr size for DWARF2 and earlier, 4 bytes for - // DWARF32, 8 bytes for DWARF32 in DWARF 3 and later - {1,1}, // 0x11 DW_FORM_ref1 - {1,2}, // 0x12 DW_FORM_ref2 - {1,4}, // 0x13 DW_FORM_ref4 - {1,8}, // 0x14 DW_FORM_ref8 - {0,0}, // 0x15 DW_FORM_ref_udata - {0,0}, // 0x16 DW_FORM_indirect - {1,4}, // 0x17 DW_FORM_sec_offset - {0,0}, // 0x18 DW_FORM_exprloc - {1,0}, // 0x19 DW_FORM_flag_present - {0,0}, // 0x1a - {0,0}, // 0x1b - {0,0}, // 0x1c - {0,0}, // 0x1d - {0,0}, // 0x1e - {0,0}, // 0x1f - {1,8}, // 0x20 DW_FORM_ref_sig8 + {0, 0}, // 0x00 unused + {0, 0}, // 0x01 DW_FORM_addr + {0, 0}, // 0x02 unused + {0, 0}, // 0x03 DW_FORM_block2 + {0, 0}, // 0x04 DW_FORM_block4 + {1, 2}, // 0x05 DW_FORM_data2 + {1, 4}, // 0x06 DW_FORM_data4 + {1, 8}, // 0x07 DW_FORM_data8 + {0, 0}, // 0x08 DW_FORM_string + {0, 0}, // 0x09 DW_FORM_block + {0, 0}, // 0x0a DW_FORM_block1 + {1, 1}, // 0x0b DW_FORM_data1 + {1, 1}, // 0x0c DW_FORM_flag + {0, 0}, // 0x0d DW_FORM_sdata + {1, 4}, // 0x0e DW_FORM_strp + {0, 0}, // 0x0f DW_FORM_udata + {0, 0}, // 0x10 DW_FORM_ref_addr (addr size for DWARF2 and earlier, 4 bytes + // for DWARF32, 8 bytes for DWARF32 in DWARF 3 and later + {1, 1}, // 0x11 DW_FORM_ref1 + {1, 2}, // 0x12 DW_FORM_ref2 + {1, 4}, // 0x13 DW_FORM_ref4 + {1, 8}, // 0x14 DW_FORM_ref8 + {0, 0}, // 0x15 DW_FORM_ref_udata + {0, 0}, // 0x16 DW_FORM_indirect + {1, 4}, // 0x17 DW_FORM_sec_offset + {0, 0}, // 0x18 DW_FORM_exprloc + {1, 0}, // 0x19 DW_FORM_flag_present + {0, 0}, // 0x1a DW_FORM_strx (ULEB128) + {0, 0}, // 0x1b DW_FORM_addrx (ULEB128) + {1, 4}, // 0x1c DW_FORM_ref_sup4 + {0, 0}, // 0x1d DW_FORM_strp_sup (4 bytes for DWARF32, 8 bytes for DWARF64) + {1, 16}, // 0x1e DW_FORM_data16 + {1, 4}, // 0x1f DW_FORM_line_strp + {1, 8}, // 0x20 DW_FORM_ref_sig8 }; llvm::Optional @@ -286,6 +286,7 @@ bool DWARFFormValue::SkipValue(dw_form_t form, // 32 bit for DWARF 32, 64 for DWARF 64 case DW_FORM_sec_offset: case DW_FORM_strp: + case DW_FORM_line_strp: *offset_ptr += 4; return true; @@ -398,7 +399,8 @@ void DWARFFormValue::Dump(Stream &s) const { case DW_FORM_udata: s.PutULEB128(uvalue); break; - case DW_FORM_strp: { + case DW_FORM_strp: + case DW_FORM_line_strp: { const char *dbg_str = AsCString(); if (dbg_str) { s.QuotedCString(dbg_str); @@ -606,6 +608,7 @@ bool DWARFFormValue::FormIsSupported(dw_form_t form) { case DW_FORM_flag: case DW_FORM_sdata: case DW_FORM_strp: + case DW_FORM_line_strp: case DW_FORM_strx: case DW_FORM_strx1: case DW_FORM_strx2: diff --git a/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.h b/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.h index b401352c693..9406bcf0c03 100644 --- a/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.h +++ b/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.h @@ -10,8 +10,8 @@ #define LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFFORMVALUE_H #include "DWARFDataExtractor.h" -#include #include "llvm/ADT/Optional.h" +#include class DWARFUnit; class SymbolFileDWARF; @@ -20,14 +20,14 @@ class DWARFDIE; class DWARFFormValue { public: typedef struct ValueTypeTag { - ValueTypeTag() : value(), data(nullptr) { value.uval = 0; } + ValueTypeTag() : value() { value.uval = 0; } union { uint64_t uval; int64_t sval; const char *cstr; } value; - const uint8_t *data; + const uint8_t *data = nullptr; } ValueType; enum { @@ -42,6 +42,7 @@ public: DWARFFormValue(const DWARFUnit *unit) : m_unit(unit) {} DWARFFormValue(const DWARFUnit *unit, dw_form_t form) : m_unit(unit), m_form(form) {} + const DWARFUnit *GetUnit() const { return m_unit; } void SetUnit(const DWARFUnit *unit) { m_unit = unit; } dw_form_t Form() const { return m_form; } dw_form_t& FormRef() { return m_form; } diff --git a/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp b/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp index dfa40759a7f..824e4387226 100644 --- a/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp +++ b/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp @@ -34,7 +34,8 @@ DWARFUnit::DWARFUnit(SymbolFileDWARF &dwarf, lldb::user_id_t uid, const DWARFAbbreviationDeclarationSet &abbrevs, DIERef::Section section, bool is_dwo) : UserID(uid), m_dwarf(dwarf), m_header(header), m_abbrevs(&abbrevs), - m_cancel_scopes(false), m_section(section), m_is_dwo(is_dwo) {} + m_cancel_scopes(false), m_section(section), m_is_dwo(is_dwo), + m_dwo_id(header.GetDWOId()) {} DWARFUnit::~DWARFUnit() = default; @@ -49,9 +50,7 @@ void DWARFUnit::ExtractUnitDIEIfNeeded() { if (m_first_die) return; // Already parsed - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer(func_cat, "%8.8x: DWARFUnit::ExtractUnitDIEIfNeeded()", - GetOffset()); + LLDB_SCOPED_TIMERF("%8.8x: DWARFUnit::ExtractUnitDIEIfNeeded()", GetOffset()); // Set the offset to that of the first DIE and calculate the start of the // next compilation unit header. @@ -145,9 +144,7 @@ DWARFUnit::ScopedExtractDIEs &DWARFUnit::ScopedExtractDIEs::operator=( void DWARFUnit::ExtractDIEsRWLocked() { llvm::sys::ScopedWriter first_die_lock(m_first_die_mutex); - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer(func_cat, "%8.8x: DWARFUnit::ExtractDIEsIfNeeded()", - GetOffset()); + LLDB_SCOPED_TIMERF("%8.8x: DWARFUnit::ExtractDIEsIfNeeded()", GetOffset()); // Set the offset to that of the first DIE and calculate the start of the // next compilation unit header. @@ -239,6 +236,11 @@ void DWARFUnit::ExtractDIEsRWLocked() { } if (!m_die_array.empty()) { + // The last die cannot have children (if it did, it wouldn't be the last one). + // This only makes a difference for malformed dwarf that does not have a + // terminating null die. + m_die_array.back().SetHasChildren(false); + if (m_first_die) { // Only needed for the assertion. m_first_die.SetHasChildren(m_die_array.front().HasChildren()); @@ -288,10 +290,14 @@ void DWARFUnit::SetDwoStrOffsetsBase() { SetStrOffsetsBase(baseOffset); } +uint64_t DWARFUnit::GetDWOId() { + ExtractUnitDIEIfNeeded(); + return m_dwo_id; +} + // m_die_array_mutex must be already held as read/write. void DWARFUnit::AddUnitDIE(const DWARFDebugInfoEntry &cu_die) { - llvm::Optional addr_base, gnu_addr_base, ranges_base, - gnu_ranges_base; + llvm::Optional addr_base, gnu_addr_base, gnu_ranges_base; DWARFAttributes attributes; size_t num_attributes = cu_die.GetAttributes(this, attributes); @@ -318,8 +324,7 @@ void DWARFUnit::AddUnitDIE(const DWARFDebugInfoEntry &cu_die) { SetLoclistsBase(form_value.Unsigned()); break; case DW_AT_rnglists_base: - ranges_base = form_value.Unsigned(); - SetRangesBase(*ranges_base); + SetRangesBase(form_value.Unsigned()); break; case DW_AT_str_offsets_base: SetStrOffsetsBase(form_value.Unsigned()); @@ -341,6 +346,9 @@ void DWARFUnit::AddUnitDIE(const DWARFDebugInfoEntry &cu_die) { case DW_AT_GNU_ranges_base: gnu_ranges_base = form_value.Unsigned(); break; + case DW_AT_GNU_dwo_id: + m_dwo_id = form_value.Unsigned(); + break; } } @@ -354,9 +362,8 @@ void DWARFUnit::AddUnitDIE(const DWARFDebugInfoEntry &cu_die) { if (!dwo_symbol_file) return; - uint64_t main_dwo_id = - cu_die.GetAttributeValueAsUnsigned(this, DW_AT_GNU_dwo_id, 0); - DWARFUnit *dwo_cu = dwo_symbol_file->GetDWOCompileUnitForHash(main_dwo_id); + DWARFUnit *dwo_cu = dwo_symbol_file->GetDWOCompileUnitForHash(m_dwo_id); + if (!dwo_cu) return; // Can't fetch the compile unit from the dwo file. dwo_cu->SetUserData(this); @@ -392,17 +399,6 @@ void DWARFUnit::AddUnitDIE(const DWARFDebugInfoEntry &cu_die) { m_dwo = std::shared_ptr(std::move(dwo_symbol_file), dwo_cu); } -DWARFDIE DWARFUnit::LookupAddress(const dw_addr_t address) { - if (DIE()) { - const DWARFDebugAranges &func_aranges = GetFunctionAranges(); - - // Re-check the aranges auto pointer contents in case it was created above - if (!func_aranges.IsEmpty()) - return GetDIE(func_aranges.FindAddress(address)); - } - return DWARFDIE(); -} - size_t DWARFUnit::GetDebugInfoSize() const { return GetLengthByteSize() + GetLength() - GetHeaderByteSize(); } @@ -489,19 +485,46 @@ DWARFDataExtractor DWARFUnit::GetLocationData() const { } void DWARFUnit::SetRangesBase(dw_addr_t ranges_base) { + lldbassert(!m_rnglist_table_done); + m_ranges_base = ranges_base; +} - if (GetVersion() < 5) - return; +const llvm::Optional & +DWARFUnit::GetRnglistTable() { + if (GetVersion() >= 5 && !m_rnglist_table_done) { + m_rnglist_table_done = true; + if (auto table_or_error = + ParseListTableHeader( + m_dwarf.GetDWARFContext().getOrLoadRngListsData().GetAsLLVM(), + m_ranges_base, DWARF32)) + m_rnglist_table = std::move(table_or_error.get()); + else + GetSymbolFileDWARF().GetObjectFile()->GetModule()->ReportError( + "Failed to extract range list table at offset 0x%" PRIx64 ": %s", + m_ranges_base, toString(table_or_error.takeError()).c_str()); + } + return m_rnglist_table; +} - if (auto table_or_error = ParseListTableHeader( - m_dwarf.GetDWARFContext().getOrLoadRngListsData().GetAsLLVM(), - ranges_base, DWARF32)) - m_rnglist_table = std::move(table_or_error.get()); - else - GetSymbolFileDWARF().GetObjectFile()->GetModule()->ReportError( - "Failed to extract range list table at offset 0x%" PRIx64 ": %s", - ranges_base, toString(table_or_error.takeError()).c_str()); +// This function is called only for DW_FORM_rnglistx. +llvm::Expected DWARFUnit::GetRnglistOffset(uint32_t Index) { + if (!GetRnglistTable()) + return llvm::createStringError(errc::invalid_argument, + "missing or invalid range list table"); + if (!m_ranges_base) + return llvm::createStringError(errc::invalid_argument, + "DW_FORM_rnglistx cannot be used without " + "DW_AT_rnglists_base for CU at 0x%8.8x", + GetOffset()); + if (llvm::Optional off = GetRnglistTable()->getOffsetEntry( + m_dwarf.GetDWARFContext().getOrLoadRngListsData().GetAsLLVM(), Index)) + return *off + m_ranges_base; + return llvm::createStringError( + errc::invalid_argument, + "invalid range list table index %u; OffsetEntryCount is %u, " + "DW_AT_rnglists_base is %" PRIu64, + Index, GetRnglistTable()->getOffsetEntryCount(), m_ranges_base); } void DWARFUnit::SetStrOffsetsBase(dw_offset_t str_offsets_base) { @@ -536,21 +559,23 @@ static bool CompareDIEOffset(const DWARFDebugInfoEntry &die, // DIE from this compile unit. Otherwise we grab the DIE from the DWARF file. DWARFDIE DWARFUnit::GetDIE(dw_offset_t die_offset) { - if (die_offset != DW_INVALID_OFFSET) { - if (ContainsDIEOffset(die_offset)) { - ExtractDIEsIfNeeded(); - DWARFDebugInfoEntry::const_iterator end = m_die_array.cend(); - DWARFDebugInfoEntry::const_iterator pos = - lower_bound(m_die_array.cbegin(), end, die_offset, CompareDIEOffset); - if (pos != end) { - if (die_offset == (*pos).GetOffset()) - return DWARFDIE(this, &(*pos)); - } - } else - GetSymbolFileDWARF().GetObjectFile()->GetModule()->ReportError( - "GetDIE for DIE 0x%" PRIx32 " is outside of its CU 0x%" PRIx32, - die_offset, GetOffset()); + if (die_offset == DW_INVALID_OFFSET) + return DWARFDIE(); // Not found + + if (!ContainsDIEOffset(die_offset)) { + GetSymbolFileDWARF().GetObjectFile()->GetModule()->ReportError( + "GetDIE for DIE 0x%" PRIx32 " is outside of its CU 0x%" PRIx32, + die_offset, GetOffset()); + return DWARFDIE(); // Not found } + + ExtractDIEsIfNeeded(); + DWARFDebugInfoEntry::const_iterator end = m_die_array.cend(); + DWARFDebugInfoEntry::const_iterator pos = + lower_bound(m_die_array.cbegin(), end, die_offset, CompareDIEOffset); + + if (pos != end && die_offset == (*pos).GetOffset()) + return DWARFDIE(this, &(*pos)); return DWARFDIE(); // Not found } @@ -789,19 +814,19 @@ const DWARFDebugAranges &DWARFUnit::GetFunctionAranges() { llvm::Expected DWARFUnitHeader::extract(const DWARFDataExtractor &data, - DIERef::Section section, lldb::offset_t *offset_ptr, - const llvm::DWARFUnitIndex *index) { + DIERef::Section section, + lldb_private::DWARFContext &context, + lldb::offset_t *offset_ptr) { DWARFUnitHeader header; header.m_offset = *offset_ptr; - if (index) - header.m_index_entry = index->getFromOffset(*offset_ptr); header.m_length = data.GetDWARFInitialLength(offset_ptr); header.m_version = data.GetU16(offset_ptr); if (header.m_version == 5) { header.m_unit_type = data.GetU8(offset_ptr); header.m_addr_size = data.GetU8(offset_ptr); header.m_abbr_offset = data.GetDWARFOffset(offset_ptr); - if (header.m_unit_type == llvm::dwarf::DW_UT_skeleton) + if (header.m_unit_type == llvm::dwarf::DW_UT_skeleton || + header.m_unit_type == llvm::dwarf::DW_UT_split_compile) header.m_dwo_id = data.GetU64(offset_ptr); } else { header.m_abbr_offset = data.GetDWARFOffset(offset_ptr); @@ -810,6 +835,16 @@ DWARFUnitHeader::extract(const DWARFDataExtractor &data, section == DIERef::Section::DebugTypes ? DW_UT_type : DW_UT_compile; } + if (context.isDwo()) { + if (header.IsTypeUnit()) { + header.m_index_entry = + context.GetAsLLVM().getTUIndex().getFromOffset(header.m_offset); + } else { + header.m_index_entry = + context.GetAsLLVM().getCUIndex().getFromOffset(header.m_offset); + } + } + if (header.m_index_entry) { if (header.m_abbr_offset) { return llvm::createStringError( @@ -860,12 +895,11 @@ DWARFUnitHeader::extract(const DWARFDataExtractor &data, llvm::Expected DWARFUnit::extract(SymbolFileDWARF &dwarf, user_id_t uid, const DWARFDataExtractor &debug_info, - DIERef::Section section, lldb::offset_t *offset_ptr, - const llvm::DWARFUnitIndex *index) { + DIERef::Section section, lldb::offset_t *offset_ptr) { assert(debug_info.ValidOffset(*offset_ptr)); - auto expected_header = - DWARFUnitHeader::extract(debug_info, section, offset_ptr, index); + auto expected_header = DWARFUnitHeader::extract( + debug_info, section, dwarf.GetDWARFContext(), offset_ptr); if (!expected_header) return expected_header.takeError(); @@ -934,11 +968,11 @@ DWARFUnit::FindRnglistFromOffset(dw_offset_t offset) { return ranges; } - if (!m_rnglist_table) + if (!GetRnglistTable()) return llvm::createStringError(errc::invalid_argument, "missing or invalid range list table"); - auto range_list_or_error = m_rnglist_table->findList( + auto range_list_or_error = GetRnglistTable()->findList( m_dwarf.GetDWARFContext().getOrLoadRngListsData().GetAsLLVM(), offset); if (!range_list_or_error) return range_list_or_error.takeError(); @@ -946,7 +980,7 @@ DWARFUnit::FindRnglistFromOffset(dw_offset_t offset) { llvm::Expected llvm_ranges = range_list_or_error->getAbsoluteRanges( llvm::object::SectionedAddress{GetBaseAddress()}, - [&](uint32_t index) { + GetAddressByteSize(), [&](uint32_t index) { uint32_t index_size = GetAddressByteSize(); dw_offset_t addr_base = GetAddrBase(); lldb::offset_t offset = addr_base + index * index_size; @@ -967,12 +1001,8 @@ DWARFUnit::FindRnglistFromOffset(dw_offset_t offset) { llvm::Expected DWARFUnit::FindRnglistFromIndex(uint32_t index) { - if (llvm::Optional offset = GetRnglistOffset(index)) - return FindRnglistFromOffset(*offset); - if (m_rnglist_table) - return llvm::createStringError(errc::invalid_argument, - "invalid range list table index %d", index); - - return llvm::createStringError(errc::invalid_argument, - "missing or invalid range list table"); + llvm::Expected maybe_offset = GetRnglistOffset(index); + if (!maybe_offset) + return maybe_offset.takeError(); + return FindRnglistFromOffset(*maybe_offset); } diff --git a/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h b/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h index affad286a49..da79a6aaf64 100644 --- a/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h +++ b/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h @@ -65,6 +65,7 @@ public: } uint64_t GetTypeHash() const { return m_type_hash; } dw_offset_t GetTypeOffset() const { return m_type_offset; } + uint64_t GetDWOId() const { return m_dwo_id; } bool IsTypeUnit() const { return m_unit_type == DW_UT_type || m_unit_type == DW_UT_split_type; } @@ -72,7 +73,8 @@ public: static llvm::Expected extract(const lldb_private::DWARFDataExtractor &data, DIERef::Section section, - lldb::offset_t *offset_ptr, const llvm::DWARFUnitIndex *index); + lldb_private::DWARFContext &dwarf_context, + lldb::offset_t *offset_ptr); }; class DWARFUnit : public lldb_private::UserID { @@ -83,11 +85,11 @@ public: static llvm::Expected extract(SymbolFileDWARF &dwarf2Data, lldb::user_id_t uid, const lldb_private::DWARFDataExtractor &debug_info, - DIERef::Section section, lldb::offset_t *offset_ptr, - const llvm::DWARFUnitIndex *index); + DIERef::Section section, lldb::offset_t *offset_ptr); virtual ~DWARFUnit(); bool IsDWOUnit() { return m_is_dwo; } + uint64_t GetDWOId(); void ExtractUnitDIEIfNeeded(); void ExtractDIEsIfNeeded(); @@ -105,7 +107,6 @@ public: }; ScopedExtractDIEs ExtractDIEsScoped(); - DWARFDIE LookupAddress(const dw_addr_t address); bool Verify(lldb_private::Stream *s) const; virtual void Dump(lldb_private::Stream *s) const = 0; /// Get the data that contains the DIE information for this unit. @@ -167,7 +168,7 @@ public: void SetBaseAddress(dw_addr_t base_addr); - DWARFBaseDIE GetUnitDIEOnly() { return DWARFDIE(this, GetUnitDIEPtrOnly()); } + DWARFBaseDIE GetUnitDIEOnly() { return {this, GetUnitDIEPtrOnly()}; } DWARFDIE DIE() { return DWARFDIE(this, DIEPtr()); } @@ -234,19 +235,14 @@ public: /// Return a rangelist's offset based on an index. The index designates /// an entry in the rangelist table's offset array and is supplied by /// DW_FORM_rnglistx. - llvm::Optional GetRnglistOffset(uint32_t Index) const { - if (!m_rnglist_table) - return llvm::None; - if (llvm::Optional off = m_rnglist_table->getOffsetEntry(Index)) - return *off + m_ranges_base; - return llvm::None; - } + llvm::Expected GetRnglistOffset(uint32_t Index); llvm::Optional GetLoclistOffset(uint32_t Index) { if (!m_loclist_table_header) return llvm::None; - llvm::Optional Offset = m_loclist_table_header->getOffsetEntry(Index); + llvm::Optional Offset = m_loclist_table_header->getOffsetEntry( + m_dwarf.GetDWARFContext().getOrLoadLocListsData().GetAsLLVM(), Index); if (!Offset) return llvm::None; return *Offset + m_loclists_base; @@ -287,6 +283,8 @@ protected: return &m_die_array[0]; } + const llvm::Optional &GetRnglistTable(); + SymbolFileDWARF &m_dwarf; std::shared_ptr m_dwo; DWARFUnitHeader m_header; @@ -327,10 +325,13 @@ protected: dw_offset_t m_str_offsets_base = 0; // Value of DW_AT_str_offsets_base. llvm::Optional m_rnglist_table; + bool m_rnglist_table_done = false; llvm::Optional m_loclist_table_header; const DIERef::Section m_section; bool m_is_dwo; + /// Value of DW_AT_GNU_dwo_id (v4) or dwo_id from CU header (v5). + uint64_t m_dwo_id; private: void ParseProducerInfo(); diff --git a/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/HashedNameToDIE.cpp b/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/HashedNameToDIE.cpp index d36f2a8bccf..ce71281db8b 100644 --- a/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/HashedNameToDIE.cpp +++ b/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/HashedNameToDIE.cpp @@ -130,8 +130,7 @@ DWARFMappedHash::DIEInfo::DIEInfo(dw_offset_t o, dw_tag_t t, uint32_t f, : die_offset(o), tag(t), type_flags(f), qualified_name_hash(h) {} DWARFMappedHash::Prologue::Prologue(dw_offset_t _die_base_offset) - : die_base_offset(_die_base_offset), atoms(), atom_mask(0), - min_hash_data_byte_size(0), hash_data_has_fixed_byte_size(true) { + : die_base_offset(_die_base_offset), atoms() { // Define an array of DIE offsets by first defining an array, and then define // the atom type for the array, in this case we have an array of DIE offsets. AppendAtom(eAtomTypeDIEOffset, DW_FORM_data4); diff --git a/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/HashedNameToDIE.h b/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/HashedNameToDIE.h index ad178fc6a98..efc08e47a28 100644 --- a/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/HashedNameToDIE.h +++ b/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/HashedNameToDIE.h @@ -101,9 +101,9 @@ public: /// DIE offset base so die offsets in hash_data can be CU relative. dw_offset_t die_base_offset; AtomArray atoms; - uint32_t atom_mask; - size_t min_hash_data_byte_size; - bool hash_data_has_fixed_byte_size; + uint32_t atom_mask = 0; + size_t min_hash_data_byte_size = 0; + bool hash_data_has_fixed_byte_size = true; }; class Header : public MappedHash::Header { diff --git a/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp b/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp index 7bf4b52bc78..1f40d880ea3 100644 --- a/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp +++ b/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp @@ -13,9 +13,11 @@ #include "Plugins/SymbolFile/DWARF/LogChannelDWARF.h" #include "Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.h" #include "lldb/Core/Module.h" +#include "lldb/Core/Progress.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Utility/Stream.h" #include "lldb/Utility/Timer.h" +#include "llvm/Support/FormatVariadic.h" #include "llvm/Support/ThreadPool.h" using namespace lldb_private; @@ -28,8 +30,7 @@ void ManualDWARFIndex::Index() { SymbolFileDWARF &main_dwarf = *m_dwarf; m_dwarf = nullptr; - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer(func_cat, "%p", static_cast(&main_dwarf)); + LLDB_SCOPED_TIMERF("%p", static_cast(&main_dwarf)); DWARFDebugInfo &main_info = main_dwarf.DebugInfo(); SymbolFileDWARFDwo *dwp_dwarf = main_dwarf.GetDwpSymbolFile().get(); @@ -57,6 +58,17 @@ void ManualDWARFIndex::Index() { if (units_to_index.empty()) return; + StreamString module_desc; + m_module.GetDescription(module_desc.AsRawOstream(), + lldb::eDescriptionLevelBrief); + + // Include 2 passes per unit to index for extracting DIEs from the unit and + // indexing the unit, and then 8 extra entries for finalizing each index set. + const uint64_t total_progress = units_to_index.size() * 2 + 8; + Progress progress( + llvm::formatv("Manually indexing DWARF for {0}", module_desc.GetData()), + total_progress); + std::vector sets(units_to_index.size()); // Keep memory down by clearing DIEs for any units if indexing @@ -65,15 +77,17 @@ void ManualDWARFIndex::Index() { units_to_index.size()); auto parser_fn = [&](size_t cu_idx) { IndexUnit(*units_to_index[cu_idx], dwp_dwarf, sets[cu_idx]); + progress.Increment(); }; - auto extract_fn = [&units_to_index, &clear_cu_dies](size_t cu_idx) { + auto extract_fn = [&](size_t cu_idx) { clear_cu_dies[cu_idx] = units_to_index[cu_idx]->ExtractDIEsScoped(); + progress.Increment(); }; // Share one thread pool across operations to avoid the overhead of // recreating the threads. - llvm::ThreadPool pool; + llvm::ThreadPool pool(llvm::optimal_concurrency(units_to_index.size())); // Create a task runner that extracts dies for each DWARF unit in a // separate thread. @@ -93,11 +107,12 @@ void ManualDWARFIndex::Index() { pool.async(parser_fn, i); pool.wait(); - auto finalize_fn = [this, &sets](NameToDIE(IndexSet::*index)) { + auto finalize_fn = [this, &sets, &progress](NameToDIE(IndexSet::*index)) { NameToDIE &result = m_set.*index; for (auto &set : sets) result.Append(set.*index); result.Finalize(); + progress.Increment(); }; pool.async(finalize_fn, &IndexSet::function_basenames); diff --git a/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/NameToDIE.h b/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/NameToDIE.h index 5aa841cf3d1..a6863f6c954 100644 --- a/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/NameToDIE.h +++ b/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/NameToDIE.h @@ -22,7 +22,7 @@ class NameToDIE { public: NameToDIE() : m_map() {} - ~NameToDIE() {} + ~NameToDIE() = default; void Dump(lldb_private::Stream *s); diff --git a/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp index 0b7e31ae2d1..ccaf31317d7 100644 --- a/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ b/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -16,6 +16,7 @@ #include "lldb/Core/ModuleList.h" #include "lldb/Core/ModuleSpec.h" #include "lldb/Core/PluginManager.h" +#include "lldb/Core/Progress.h" #include "lldb/Core/Section.h" #include "lldb/Core/StreamFile.h" #include "lldb/Core/Value.h" @@ -35,6 +36,7 @@ #include "lldb/Interpreter/OptionValueProperties.h" #include "Plugins/ExpressionParser/Clang/ClangUtil.h" +#include "Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h" #include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Symbol/Block.h" #include "lldb/Symbol/CompileUnit.h" @@ -73,18 +75,19 @@ #include "llvm/DebugInfo/DWARF/DWARFContext.h" #include "llvm/Support/FileSystem.h" +#include "llvm/Support/FormatVariadic.h" #include #include #include -#include -#include +#include +#include //#define ENABLE_DEBUG_PRINTF // COMMENT OUT THIS LINE PRIOR TO CHECKIN #ifdef ENABLE_DEBUG_PRINTF -#include +#include #define DEBUG_PRINTF(fmt, ...) printf(fmt, __VA_ARGS__) #else #define DEBUG_PRINTF(fmt, ...) @@ -237,9 +240,12 @@ ParseSupportFilesFromPrologue(const lldb::ModuleSP &module, const size_t number_of_files = prologue.FileNames.size(); for (size_t idx = first_file; idx <= number_of_files; ++idx) { std::string remapped_file; - if (auto file_path = GetFileByIndex(prologue, idx, compile_dir, style)) - if (!module->RemapSourceFile(llvm::StringRef(*file_path), remapped_file)) + if (auto file_path = GetFileByIndex(prologue, idx, compile_dir, style)) { + if (auto remapped = module->RemapSourceFile(llvm::StringRef(*file_path))) + remapped_file = *remapped; + else remapped_file = std::move(*file_path); + } // Unconditionally add an entry, so the indices match up. support_files.EmplaceBack(remapped_file, style); @@ -357,8 +363,7 @@ void SymbolFileDWARF::GetTypes(const DWARFDIE &die, dw_offset_t min_die_offset, } } - for (DWARFDIE child_die = die.GetFirstChild(); child_die.IsValid(); - child_die = child_die.GetSibling()) { + for (DWARFDIE child_die : die.children()) { GetTypes(child_die, min_die_offset, max_die_offset, type_mask, type_set); } } @@ -372,24 +377,23 @@ void SymbolFileDWARF::GetTypes(SymbolContextScope *sc_scope, TypeSet type_set; CompileUnit *comp_unit = nullptr; - DWARFUnit *dwarf_cu = nullptr; if (sc_scope) comp_unit = sc_scope->CalculateSymbolContextCompileUnit(); - if (comp_unit) { - dwarf_cu = GetDWARFCompileUnit(comp_unit); - if (!dwarf_cu) + const auto &get = [&](DWARFUnit *unit) { + if (!unit) return; - GetTypes(dwarf_cu->DIE(), dwarf_cu->GetOffset(), - dwarf_cu->GetNextUnitOffset(), type_mask, type_set); + unit = &unit->GetNonSkeletonUnit(); + GetTypes(unit->DIE(), unit->GetOffset(), unit->GetNextUnitOffset(), + type_mask, type_set); + }; + if (comp_unit) { + get(GetDWARFCompileUnit(comp_unit)); } else { DWARFDebugInfo &info = DebugInfo(); const size_t num_cus = info.GetNumUnits(); - for (size_t cu_idx = 0; cu_idx < num_cus; ++cu_idx) { - dwarf_cu = info.GetUnitAtIndex(cu_idx); - if (dwarf_cu) - GetTypes(dwarf_cu->DIE(), 0, UINT32_MAX, type_mask, type_set); - } + for (size_t cu_idx = 0; cu_idx < num_cus; ++cu_idx) + get(info.GetUnitAtIndex(cu_idx)); } std::set compiler_type_set; @@ -435,7 +439,7 @@ SymbolFileDWARF::SymbolFileDWARF(ObjectFileSP objfile_sp, m_fetched_external_modules(false), m_supports_DW_AT_APPLE_objc_complete_type(eLazyBoolCalculate) {} -SymbolFileDWARF::~SymbolFileDWARF() {} +SymbolFileDWARF::~SymbolFileDWARF() = default; static ConstString GetDWARFMachOSegmentName() { static ConstString g_dwarf_section_name("__DWARF"); @@ -467,22 +471,32 @@ void SymbolFileDWARF::InitializeObject() { Log *log = LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_INFO); if (!GetGlobalPluginProperties()->IgnoreFileIndexes()) { + StreamString module_desc; + GetObjectFile()->GetModule()->GetDescription(module_desc.AsRawOstream(), + lldb::eDescriptionLevelBrief); DWARFDataExtractor apple_names, apple_namespaces, apple_types, apple_objc; LoadSectionData(eSectionTypeDWARFAppleNames, apple_names); LoadSectionData(eSectionTypeDWARFAppleNamespaces, apple_namespaces); LoadSectionData(eSectionTypeDWARFAppleTypes, apple_types); LoadSectionData(eSectionTypeDWARFAppleObjC, apple_objc); - m_index = AppleDWARFIndex::Create( - *GetObjectFile()->GetModule(), apple_names, apple_namespaces, - apple_types, apple_objc, m_context.getOrLoadStrData()); + if (apple_names.GetByteSize() > 0 || apple_namespaces.GetByteSize() > 0 || + apple_types.GetByteSize() > 0 || apple_objc.GetByteSize() > 0) { + Progress progress(llvm::formatv("Loading Apple DWARF index for {0}", + module_desc.GetData())); + m_index = AppleDWARFIndex::Create( + *GetObjectFile()->GetModule(), apple_names, apple_namespaces, + apple_types, apple_objc, m_context.getOrLoadStrData()); - if (m_index) - return; + if (m_index) + return; + } DWARFDataExtractor debug_names; LoadSectionData(eSectionTypeDWARFDebugNames, debug_names); if (debug_names.GetByteSize() > 0) { + Progress progress( + llvm::formatv("Loading DWARF5 index for {0}", module_desc.GetData())); llvm::Expected> index_or = DebugNamesDWARFIndex::Create(*GetObjectFile()->GetModule(), debug_names, @@ -624,16 +638,14 @@ DWARFDebugAbbrev *SymbolFileDWARF::DebugAbbrev() { DWARFDebugInfo &SymbolFileDWARF::DebugInfo() { llvm::call_once(m_info_once_flag, [&] { - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer(func_cat, "%s this = %p", LLVM_PRETTY_FUNCTION, + LLDB_SCOPED_TIMERF("%s this = %p", LLVM_PRETTY_FUNCTION, static_cast(this)); m_info = std::make_unique(*this, m_context); }); return *m_info; } -DWARFUnit * -SymbolFileDWARF::GetDWARFCompileUnit(lldb_private::CompileUnit *comp_unit) { +DWARFCompileUnit *SymbolFileDWARF::GetDWARFCompileUnit(CompileUnit *comp_unit) { if (!comp_unit) return nullptr; @@ -641,13 +653,14 @@ SymbolFileDWARF::GetDWARFCompileUnit(lldb_private::CompileUnit *comp_unit) { DWARFUnit *dwarf_cu = DebugInfo().GetUnitAtIndex(comp_unit->GetID()); if (dwarf_cu && dwarf_cu->GetUserData() == nullptr) dwarf_cu->SetUserData(comp_unit); - return dwarf_cu; + + // It must be DWARFCompileUnit when it created a CompileUnit. + return llvm::cast_or_null(dwarf_cu); } DWARFDebugRanges *SymbolFileDWARF::GetDebugRanges() { if (!m_ranges) { - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer(func_cat, "%s this = %p", LLVM_PRETTY_FUNCTION, + LLDB_SCOPED_TIMERF("%s this = %p", LLVM_PRETTY_FUNCTION, static_cast(this)); if (m_context.getOrLoadRangesData().GetByteSize() > 0) @@ -670,9 +683,8 @@ static void MakeAbsoluteAndRemap(FileSpec &file_spec, DWARFUnit &dwarf_cu, // files are NFS mounted. file_spec.MakeAbsolute(dwarf_cu.GetCompilationDirectory()); - std::string remapped_file; - if (module_sp->RemapSourceFile(file_spec.GetPath(), remapped_file)) - file_spec.SetFile(remapped_file, FileSpec::Style::native); + if (auto remapped_file = module_sp->RemapSourceFile(file_spec.GetPath())) + file_spec.SetFile(*remapped_file, FileSpec::Style::native); } lldb::CompUnitSP SymbolFileDWARF::ParseCompileUnit(DWARFCompileUnit &dwarf_cu) { @@ -829,8 +841,7 @@ XcodeSDK SymbolFileDWARF::ParseXcodeSDK(CompileUnit &comp_unit) { } size_t SymbolFileDWARF::ParseFunctions(CompileUnit &comp_unit) { - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer(func_cat, "SymbolFileDWARF::ParseFunctions"); + LLDB_SCOPED_TIMER(); std::lock_guard guard(GetModuleMutex()); DWARFUnit *dwarf_cu = GetDWARFCompileUnit(&comp_unit); if (!dwarf_cu) @@ -975,8 +986,7 @@ bool SymbolFileDWARF::ParseImportedModules( if (!die) return false; - for (DWARFDIE child_die = die.GetFirstChild(); child_die; - child_die = child_die.GetSibling()) { + for (DWARFDIE child_die : die.children()) { if (child_die.Tag() != DW_TAG_imported_declaration) continue; @@ -1235,8 +1245,7 @@ size_t SymbolFileDWARF::ParseBlocksRecursive( bool SymbolFileDWARF::ClassOrStructIsVirtual(const DWARFDIE &parent_die) { if (parent_die) { - for (DWARFDIE die = parent_die.GetFirstChild(); die; - die = die.GetSibling()) { + for (DWARFDIE die : parent_die.children()) { dw_tag_t tag = die.Tag(); bool check_virtuality = false; switch (tag) { @@ -1267,9 +1276,10 @@ user_id_t SymbolFileDWARF::GetUID(DIERef ref) { if (GetDebugMapSymfile()) return GetID() | ref.die_offset(); - return user_id_t(GetDwoNum().getValueOr(0x7fffffff)) << 32 | - ref.die_offset() | - (lldb::user_id_t(ref.section() == DIERef::Section::DebugTypes) << 63); + lldbassert(GetDwoNum().getValueOr(0) <= 0x3fffffff); + return user_id_t(GetDwoNum().getValueOr(0)) << 32 | ref.die_offset() | + lldb::user_id_t(GetDwoNum().hasValue()) << 62 | + lldb::user_id_t(ref.section() == DIERef::Section::DebugTypes) << 63; } llvm::Optional @@ -1297,9 +1307,10 @@ SymbolFileDWARF::DecodeUID(lldb::user_id_t uid) { DIERef::Section section = uid >> 63 ? DIERef::Section::DebugTypes : DIERef::Section::DebugInfo; - llvm::Optional dwo_num = uid >> 32 & 0x7fffffff; - if (*dwo_num == 0x7fffffff) - dwo_num = llvm::None; + llvm::Optional dwo_num; + bool dwo_valid = uid >> 62 & 1; + if (dwo_valid) + dwo_num = uid >> 32 & 0x3fffffff; return DecodedUID{*this, {dwo_num, section, die_offset}}; } @@ -1599,8 +1610,7 @@ static uint64_t GetDWOId(DWARFCompileUnit &dwarf_cu, llvm::Optional SymbolFileDWARF::GetDWOId() { if (GetNumCompileUnits() == 1) { if (auto comp_unit = GetCompileUnitAtIndex(0)) - if (DWARFCompileUnit *cu = llvm::dyn_cast_or_null( - GetDWARFCompileUnit(comp_unit.get()))) + if (DWARFCompileUnit *cu = GetDWARFCompileUnit(comp_unit.get())) if (DWARFDebugInfoEntry *cu_die = cu->DIE().GetDIE()) if (uint64_t dwo_id = ::GetDWOId(*cu, *cu_die)) return dwo_id; @@ -1640,6 +1650,13 @@ SymbolFileDWARF::GetDwoSymbolFileForCompileUnit( return nullptr; dwo_file.SetFile(comp_dir, FileSpec::Style::native); + if (dwo_file.IsRelative()) { + // if DW_AT_comp_dir is relative, it should be relative to the location + // of the executable, not to the location from which the debugger was + // launched. + dwo_file.PrependPathComponent( + m_objfile_sp->GetFileSpec().GetDirectory().GetStringRef()); + } FileSystem::Instance().Resolve(dwo_file); dwo_file.AppendPathComponent(dwo_name); } @@ -1785,13 +1802,13 @@ SymbolFileDWARF::GlobalVariableMap &SymbolFileDWARF::GetGlobalAranges() { if (location.Evaluate(nullptr, LLDB_INVALID_ADDRESS, nullptr, nullptr, location_result, &error)) { if (location_result.GetValueType() == - Value::eValueTypeFileAddress) { + Value::ValueType::FileAddress) { lldb::addr_t file_addr = location_result.GetScalar().ULongLong(); lldb::addr_t byte_size = 1; if (var_sp->GetType()) byte_size = - var_sp->GetType()->GetByteSize().getValueOr(0); + var_sp->GetType()->GetByteSize(nullptr).getValueOr(0); m_global_aranges_up->Append(GlobalVariableMap::Entry( file_addr, byte_size, var_sp.get())); } @@ -1811,7 +1828,8 @@ void SymbolFileDWARF::ResolveFunctionAndBlock(lldb::addr_t file_vm_addr, bool lookup_block, SymbolContext &sc) { assert(sc.comp_unit); - DWARFUnit &cu = GetDWARFCompileUnit(sc.comp_unit)->GetNonSkeletonUnit(); + DWARFCompileUnit &cu = + GetDWARFCompileUnit(sc.comp_unit)->GetNonSkeletonUnit(); DWARFDIE function_die = cu.LookupAddress(file_vm_addr); DWARFDIE block_die; if (function_die) { @@ -1837,9 +1855,7 @@ uint32_t SymbolFileDWARF::ResolveSymbolContext(const Address &so_addr, SymbolContextItem resolve_scope, SymbolContext &sc) { std::lock_guard guard(GetModuleMutex()); - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer(func_cat, - "SymbolFileDWARF::" + LLDB_SCOPED_TIMERF("SymbolFileDWARF::" "ResolveSymbolContext (so_addr = { " "section = %p, offset = 0x%" PRIx64 " }, resolve_scope = 0x%8.8x)", @@ -1852,17 +1868,8 @@ uint32_t SymbolFileDWARF::ResolveSymbolContext(const Address &so_addr, lldb::addr_t file_vm_addr = so_addr.GetFileAddress(); DWARFDebugInfo &debug_info = DebugInfo(); - llvm::Expected aranges = - debug_info.GetCompileUnitAranges(); - if (!aranges) { - Log *log = LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_INFO); - LLDB_LOG_ERROR(log, aranges.takeError(), - "SymbolFileDWARF::ResolveSymbolContext failed to get cu " - "aranges. {0}"); - return 0; - } - - const dw_offset_t cu_offset = aranges->FindAddress(file_vm_addr); + const DWARFDebugAranges &aranges = debug_info.GetCompileUnitAranges(); + const dw_offset_t cu_offset = aranges.FindAddress(file_vm_addr); if (cu_offset == DW_INVALID_OFFSET) { // Global variables are not in the compile unit address ranges. The only // way to currently find global variables is to iterate over the @@ -1951,12 +1958,11 @@ uint32_t SymbolFileDWARF::ResolveSymbolContext(const Address &so_addr, return resolved; } -uint32_t SymbolFileDWARF::ResolveSymbolContext(const FileSpec &file_spec, - uint32_t line, - bool check_inlines, - SymbolContextItem resolve_scope, - SymbolContextList &sc_list) { +uint32_t SymbolFileDWARF::ResolveSymbolContext( + const SourceLocationSpec &src_location_spec, + SymbolContextItem resolve_scope, SymbolContextList &sc_list) { std::lock_guard guard(GetModuleMutex()); + const bool check_inlines = src_location_spec.GetCheckInlines(); const uint32_t prev_size = sc_list.GetSize(); if (resolve_scope & eSymbolContextCompUnit) { for (uint32_t cu_idx = 0, num_cus = GetNumCompileUnits(); cu_idx < num_cus; @@ -1965,69 +1971,10 @@ uint32_t SymbolFileDWARF::ResolveSymbolContext(const FileSpec &file_spec, if (!dc_cu) continue; - bool file_spec_matches_cu_file_spec = - FileSpec::Match(file_spec, dc_cu->GetPrimaryFile()); + bool file_spec_matches_cu_file_spec = FileSpec::Match( + src_location_spec.GetFileSpec(), dc_cu->GetPrimaryFile()); if (check_inlines || file_spec_matches_cu_file_spec) { - SymbolContext sc(m_objfile_sp->GetModule()); - sc.comp_unit = dc_cu; - uint32_t file_idx = UINT32_MAX; - - // If we are looking for inline functions only and we don't find it - // in the support files, we are done. - if (check_inlines) { - file_idx = - sc.comp_unit->GetSupportFiles().FindFileIndex(1, file_spec, true); - if (file_idx == UINT32_MAX) - continue; - } - - if (line != 0) { - LineTable *line_table = sc.comp_unit->GetLineTable(); - - if (line_table != nullptr && line != 0) { - // We will have already looked up the file index if we are - // searching for inline entries. - if (!check_inlines) - file_idx = sc.comp_unit->GetSupportFiles().FindFileIndex( - 1, file_spec, true); - - if (file_idx != UINT32_MAX) { - uint32_t found_line; - uint32_t line_idx = line_table->FindLineEntryIndexByFileIndex( - 0, file_idx, line, false, &sc.line_entry); - found_line = sc.line_entry.line; - - while (line_idx != UINT32_MAX) { - sc.function = nullptr; - sc.block = nullptr; - if (resolve_scope & - (eSymbolContextFunction | eSymbolContextBlock)) { - const lldb::addr_t file_vm_addr = - sc.line_entry.range.GetBaseAddress().GetFileAddress(); - if (file_vm_addr != LLDB_INVALID_ADDRESS) { - ResolveFunctionAndBlock( - file_vm_addr, resolve_scope & eSymbolContextBlock, sc); - } - } - - sc_list.Append(sc); - line_idx = line_table->FindLineEntryIndexByFileIndex( - line_idx + 1, file_idx, found_line, true, &sc.line_entry); - } - } - } else if (file_spec_matches_cu_file_spec && !check_inlines) { - // only append the context if we aren't looking for inline call - // sites by file and line and if the file spec matches that of - // the compile unit - sc_list.Append(sc); - } - } else if (file_spec_matches_cu_file_spec && !check_inlines) { - // only append the context if we aren't looking for inline call - // sites by file and line and if the file spec matches that of - // the compile unit - sc_list.Append(sc); - } - + dc_cu->ResolveSymbolContext(src_location_spec, resolve_scope, sc_list); if (!check_inlines) break; } @@ -2275,8 +2222,7 @@ void SymbolFileDWARF::FindFunctions(ConstString name, bool include_inlines, SymbolContextList &sc_list) { std::lock_guard guard(GetModuleMutex()); - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer(func_cat, "SymbolFileDWARF::FindFunctions (name = '%s')", + LLDB_SCOPED_TIMERF("SymbolFileDWARF::FindFunctions (name = '%s')", name.AsCString()); // eFunctionNameTypeAuto should be pre-resolved by a call to @@ -2330,8 +2276,7 @@ void SymbolFileDWARF::FindFunctions(const RegularExpression ®ex, bool include_inlines, SymbolContextList &sc_list) { std::lock_guard guard(GetModuleMutex()); - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer(func_cat, "SymbolFileDWARF::FindFunctions (regex = '%s')", + LLDB_SCOPED_TIMERF("SymbolFileDWARF::FindFunctions (regex = '%s')", regex.GetText().str().c_str()); Log *log(LogChannelDWARF::GetLogIfAll(DWARF_LOG_LOOKUPS)); @@ -2466,7 +2411,7 @@ void SymbolFileDWARF::FindTypes( return; m_index->GetTypes(name, [&](DWARFDIE die) { - if (!languages[GetLanguage(*die.GetCU())]) + if (!languages[GetLanguageFamily(*die.GetCU())]) return true; llvm::SmallVector die_context; @@ -3045,8 +2990,12 @@ size_t SymbolFileDWARF::ParseVariablesForContext(const SymbolContext &sc) { if (sc.function) { DWARFDIE function_die = GetDIE(sc.function->GetID()); - const dw_addr_t func_lo_pc = function_die.GetAttributeValueAsAddress( - DW_AT_low_pc, LLDB_INVALID_ADDRESS); + dw_addr_t func_lo_pc = LLDB_INVALID_ADDRESS; + DWARFRangeList ranges; + if (function_die.GetDIE()->GetAttributeAddressRanges( + function_die.GetCU(), ranges, + /*check_hi_lo_pc=*/true)) + func_lo_pc = ranges.GetMinRangeBase(0); if (func_lo_pc != LLDB_INVALID_ADDRESS) { const size_t num_variables = ParseVariables( sc, function_die.GetFirstChild(), func_lo_pc, true, true); @@ -3091,385 +3040,348 @@ VariableSP SymbolFileDWARF::ParseVariableDIE(const SymbolContext &sc, if (die.GetDWARF() != this) return die.GetDWARF()->ParseVariableDIE(sc, die, func_low_pc); - VariableSP var_sp; if (!die) - return var_sp; + return nullptr; - var_sp = GetDIEToVariable()[die.GetDIE()]; - if (var_sp) + if (VariableSP var_sp = GetDIEToVariable()[die.GetDIE()]) return var_sp; // Already been parsed! const dw_tag_t tag = die.Tag(); ModuleSP module = GetObjectFile()->GetModule(); - if ((tag == DW_TAG_variable) || (tag == DW_TAG_constant) || - (tag == DW_TAG_formal_parameter && sc.function)) { - DWARFAttributes attributes; - const size_t num_attributes = die.GetAttributes(attributes); - DWARFDIE spec_die; - if (num_attributes > 0) { - const char *name = nullptr; - const char *mangled = nullptr; - Declaration decl; - uint32_t i; - DWARFFormValue type_die_form; - DWARFExpression location; - bool is_external = false; - bool is_artificial = false; - bool location_is_const_value_data = false; - bool has_explicit_location = false; - DWARFFormValue const_value; - Variable::RangeList scope_ranges; - // AccessType accessibility = eAccessNone; - - for (i = 0; i < num_attributes; ++i) { - dw_attr_t attr = attributes.AttributeAtIndex(i); - DWARFFormValue form_value; - - if (attributes.ExtractFormValueAtIndex(i, form_value)) { - switch (attr) { - case DW_AT_decl_file: - decl.SetFile(sc.comp_unit->GetSupportFiles().GetFileSpecAtIndex( - form_value.Unsigned())); - break; - case DW_AT_decl_line: - decl.SetLine(form_value.Unsigned()); - break; - case DW_AT_decl_column: - decl.SetColumn(form_value.Unsigned()); - break; - case DW_AT_name: - name = form_value.AsCString(); - break; - case DW_AT_linkage_name: - case DW_AT_MIPS_linkage_name: - mangled = form_value.AsCString(); - break; - case DW_AT_type: - type_die_form = form_value; - break; - case DW_AT_external: - is_external = form_value.Boolean(); - break; - case DW_AT_const_value: - // If we have already found a DW_AT_location attribute, ignore this - // attribute. - if (!has_explicit_location) { - location_is_const_value_data = true; - // The constant value will be either a block, a data value or a - // string. - auto debug_info_data = die.GetData(); - if (DWARFFormValue::IsBlockForm(form_value.Form())) { - // Retrieve the value as a block expression. - uint32_t block_offset = - form_value.BlockData() - debug_info_data.GetDataStart(); - uint32_t block_length = form_value.Unsigned(); - location = DWARFExpression( - module, - DataExtractor(debug_info_data, block_offset, block_length), - die.GetCU()); - } else if (DWARFFormValue::IsDataForm(form_value.Form())) { - // Retrieve the value as a data expression. - uint32_t data_offset = attributes.DIEOffsetAtIndex(i); - if (auto data_length = form_value.GetFixedSize()) - location = DWARFExpression( - module, - DataExtractor(debug_info_data, data_offset, *data_length), - die.GetCU()); - else { - const uint8_t *data_pointer = form_value.BlockData(); - if (data_pointer) { - form_value.Unsigned(); - } else if (DWARFFormValue::IsDataForm(form_value.Form())) { - // we need to get the byte size of the type later after we - // create the variable - const_value = form_value; - } - } - } else { - // Retrieve the value as a string expression. - if (form_value.Form() == DW_FORM_strp) { - uint32_t data_offset = attributes.DIEOffsetAtIndex(i); - if (auto data_length = form_value.GetFixedSize()) - location = DWARFExpression(module, - DataExtractor(debug_info_data, - data_offset, - *data_length), - die.GetCU()); - } else { - const char *str = form_value.AsCString(); - uint32_t string_offset = - str - (const char *)debug_info_data.GetDataStart(); - uint32_t string_length = strlen(str) + 1; - location = DWARFExpression(module, - DataExtractor(debug_info_data, - string_offset, - string_length), - die.GetCU()); - } - } - } - break; - case DW_AT_location: { - location_is_const_value_data = false; - has_explicit_location = true; - if (DWARFFormValue::IsBlockForm(form_value.Form())) { - auto data = die.GetData(); - - uint32_t block_offset = - form_value.BlockData() - data.GetDataStart(); - uint32_t block_length = form_value.Unsigned(); - location = DWARFExpression( - module, DataExtractor(data, block_offset, block_length), - die.GetCU()); - } else { - DataExtractor data = die.GetCU()->GetLocationData(); - dw_offset_t offset = form_value.Unsigned(); - if (form_value.Form() == DW_FORM_loclistx) - offset = die.GetCU()->GetLoclistOffset(offset).getValueOr(-1); - if (data.ValidOffset(offset)) { - data = DataExtractor(data, offset, data.GetByteSize() - offset); - location = DWARFExpression(module, data, die.GetCU()); - assert(func_low_pc != LLDB_INVALID_ADDRESS); - location.SetLocationListAddresses( - attributes.CompileUnitAtIndex(i)->GetBaseAddress(), - func_low_pc); - } - } - } break; - case DW_AT_specification: - spec_die = form_value.Reference(); - break; - case DW_AT_start_scope: - // TODO: Implement this. - break; - case DW_AT_artificial: - is_artificial = form_value.Boolean(); - break; - case DW_AT_accessibility: - break; // accessibility = - // DW_ACCESS_to_AccessType(form_value.Unsigned()); break; - case DW_AT_declaration: - case DW_AT_description: - case DW_AT_endianity: - case DW_AT_segment: - case DW_AT_visibility: - default: - case DW_AT_abstract_origin: - case DW_AT_sibling: - break; - } - } - } + if (tag != DW_TAG_variable && tag != DW_TAG_constant && + (tag != DW_TAG_formal_parameter || !sc.function)) + return nullptr; - const DWARFDIE parent_context_die = GetDeclContextDIEContainingDIE(die); - const dw_tag_t parent_tag = die.GetParent().Tag(); - bool is_static_member = - (parent_tag == DW_TAG_compile_unit || - parent_tag == DW_TAG_partial_unit) && - (parent_context_die.Tag() == DW_TAG_class_type || - parent_context_die.Tag() == DW_TAG_structure_type); - - ValueType scope = eValueTypeInvalid; - - const DWARFDIE sc_parent_die = GetParentSymbolContextDIE(die); - SymbolContextScope *symbol_context_scope = nullptr; - - bool has_explicit_mangled = mangled != nullptr; - if (!mangled) { - // LLDB relies on the mangled name (DW_TAG_linkage_name or - // DW_AT_MIPS_linkage_name) to generate fully qualified names - // of global variables with commands like "frame var j". For - // example, if j were an int variable holding a value 4 and - // declared in a namespace B which in turn is contained in a - // namespace A, the command "frame var j" returns - // "(int) A::B::j = 4". - // If the compiler does not emit a linkage name, we should be - // able to generate a fully qualified name from the - // declaration context. - if ((parent_tag == DW_TAG_compile_unit || - parent_tag == DW_TAG_partial_unit) && - Language::LanguageIsCPlusPlus(GetLanguage(*die.GetCU()))) - mangled = GetDWARFDeclContext(die) - .GetQualifiedNameAsConstString() - .GetCString(); + DWARFAttributes attributes; + const size_t num_attributes = die.GetAttributes(attributes); + DWARFDIE spec_die; + VariableSP var_sp; + const char *name = nullptr; + const char *mangled = nullptr; + Declaration decl; + DWARFFormValue type_die_form; + DWARFExpression location; + bool is_external = false; + bool is_artificial = false; + DWARFFormValue const_value_form, location_form; + Variable::RangeList scope_ranges; + + for (size_t i = 0; i < num_attributes; ++i) { + dw_attr_t attr = attributes.AttributeAtIndex(i); + DWARFFormValue form_value; + + if (!attributes.ExtractFormValueAtIndex(i, form_value)) + continue; + switch (attr) { + case DW_AT_decl_file: + decl.SetFile( + attributes.CompileUnitAtIndex(i)->GetFile(form_value.Unsigned())); + break; + case DW_AT_decl_line: + decl.SetLine(form_value.Unsigned()); + break; + case DW_AT_decl_column: + decl.SetColumn(form_value.Unsigned()); + break; + case DW_AT_name: + name = form_value.AsCString(); + break; + case DW_AT_linkage_name: + case DW_AT_MIPS_linkage_name: + mangled = form_value.AsCString(); + break; + case DW_AT_type: + type_die_form = form_value; + break; + case DW_AT_external: + is_external = form_value.Boolean(); + break; + case DW_AT_const_value: + const_value_form = form_value; + break; + case DW_AT_location: + location_form = form_value; + break; + case DW_AT_specification: + spec_die = form_value.Reference(); + break; + case DW_AT_start_scope: + // TODO: Implement this. + break; + case DW_AT_artificial: + is_artificial = form_value.Boolean(); + break; + case DW_AT_declaration: + case DW_AT_description: + case DW_AT_endianity: + case DW_AT_segment: + case DW_AT_visibility: + default: + case DW_AT_abstract_origin: + case DW_AT_sibling: + break; + } + } + + // Prefer DW_AT_location over DW_AT_const_value. Both can be emitted e.g. + // for static constexpr member variables -- DW_AT_const_value will be + // present in the class declaration and DW_AT_location in the DIE defining + // the member. + bool location_is_const_value_data = false; + bool has_explicit_location = false; + bool use_type_size_for_value = false; + if (location_form.IsValid()) { + has_explicit_location = true; + if (DWARFFormValue::IsBlockForm(location_form.Form())) { + const DWARFDataExtractor &data = die.GetData(); + + uint32_t block_offset = location_form.BlockData() - data.GetDataStart(); + uint32_t block_length = location_form.Unsigned(); + location = DWARFExpression( + module, DataExtractor(data, block_offset, block_length), die.GetCU()); + } else { + DataExtractor data = die.GetCU()->GetLocationData(); + dw_offset_t offset = location_form.Unsigned(); + if (location_form.Form() == DW_FORM_loclistx) + offset = die.GetCU()->GetLoclistOffset(offset).getValueOr(-1); + if (data.ValidOffset(offset)) { + data = DataExtractor(data, offset, data.GetByteSize() - offset); + location = DWARFExpression(module, data, die.GetCU()); + assert(func_low_pc != LLDB_INVALID_ADDRESS); + location.SetLocationListAddresses( + location_form.GetUnit()->GetBaseAddress(), func_low_pc); } + } + } else if (const_value_form.IsValid()) { + location_is_const_value_data = true; + // The constant value will be either a block, a data value or a + // string. + const DWARFDataExtractor &debug_info_data = die.GetData(); + if (DWARFFormValue::IsBlockForm(const_value_form.Form())) { + // Retrieve the value as a block expression. + uint32_t block_offset = + const_value_form.BlockData() - debug_info_data.GetDataStart(); + uint32_t block_length = const_value_form.Unsigned(); + location = DWARFExpression( + module, DataExtractor(debug_info_data, block_offset, block_length), + die.GetCU()); + } else if (DWARFFormValue::IsDataForm(const_value_form.Form())) { + // Constant value size does not have to match the size of the + // variable. We will fetch the size of the type after we create + // it. + use_type_size_for_value = true; + } else if (const char *str = const_value_form.AsCString()) { + uint32_t string_length = strlen(str) + 1; + location = DWARFExpression( + module, + DataExtractor(str, string_length, die.GetCU()->GetByteOrder(), + die.GetCU()->GetAddressByteSize()), + die.GetCU()); + } + } - if (tag == DW_TAG_formal_parameter) - scope = eValueTypeVariableArgument; - else { - // DWARF doesn't specify if a DW_TAG_variable is a local, global - // or static variable, so we have to do a little digging: - // 1) DW_AT_linkage_name implies static lifetime (but may be missing) - // 2) An empty DW_AT_location is an (optimized-out) static lifetime var. - // 3) DW_AT_location containing a DW_OP_addr implies static lifetime. - // Clang likes to combine small global variables into the same symbol - // with locations like: DW_OP_addr(0x1000), DW_OP_constu(2), DW_OP_plus - // so we need to look through the whole expression. - bool is_static_lifetime = - has_explicit_mangled || - (has_explicit_location && !location.IsValid()); - // Check if the location has a DW_OP_addr with any address value... - lldb::addr_t location_DW_OP_addr = LLDB_INVALID_ADDRESS; - if (!location_is_const_value_data) { - bool op_error = false; - location_DW_OP_addr = location.GetLocation_DW_OP_addr(0, op_error); - if (op_error) { - StreamString strm; - location.DumpLocationForAddress(&strm, eDescriptionLevelFull, 0, 0, - nullptr); - GetObjectFile()->GetModule()->ReportError( - "0x%8.8x: %s has an invalid location: %s", die.GetOffset(), - die.GetTagAsCString(), strm.GetData()); - } - if (location_DW_OP_addr != LLDB_INVALID_ADDRESS) - is_static_lifetime = true; - } - SymbolFileDWARFDebugMap *debug_map_symfile = GetDebugMapSymfile(); - if (debug_map_symfile) - // Set the module of the expression to the linked module - // instead of the oject file so the relocated address can be - // found there. - location.SetModule(debug_map_symfile->GetObjectFile()->GetModule()); - - if (is_static_lifetime) { - if (is_external) - scope = eValueTypeVariableGlobal; - else - scope = eValueTypeVariableStatic; - - if (debug_map_symfile) { - // When leaving the DWARF in the .o files on darwin, when we have a - // global variable that wasn't initialized, the .o file might not - // have allocated a virtual address for the global variable. In - // this case it will have created a symbol for the global variable - // that is undefined/data and external and the value will be the - // byte size of the variable. When we do the address map in - // SymbolFileDWARFDebugMap we rely on having an address, we need to - // do some magic here so we can get the correct address for our - // global variable. The address for all of these entries will be - // zero, and there will be an undefined symbol in this object file, - // and the executable will have a matching symbol with a good - // address. So here we dig up the correct address and replace it in - // the location for the variable, and set the variable's symbol - // context scope to be that of the main executable so the file - // address will resolve correctly. - bool linked_oso_file_addr = false; - if (is_external && location_DW_OP_addr == 0) { - // we have a possible uninitialized extern global - ConstString const_name(mangled ? mangled : name); - ObjectFile *debug_map_objfile = - debug_map_symfile->GetObjectFile(); - if (debug_map_objfile) { - Symtab *debug_map_symtab = debug_map_objfile->GetSymtab(); - if (debug_map_symtab) { - Symbol *exe_symbol = - debug_map_symtab->FindFirstSymbolWithNameAndType( - const_name, eSymbolTypeData, Symtab::eDebugYes, - Symtab::eVisibilityExtern); - if (exe_symbol) { - if (exe_symbol->ValueIsAddress()) { - const addr_t exe_file_addr = - exe_symbol->GetAddressRef().GetFileAddress(); - if (exe_file_addr != LLDB_INVALID_ADDRESS) { - if (location.Update_DW_OP_addr(exe_file_addr)) { - linked_oso_file_addr = true; - symbol_context_scope = exe_symbol; - } - } + const DWARFDIE parent_context_die = GetDeclContextDIEContainingDIE(die); + const dw_tag_t parent_tag = die.GetParent().Tag(); + bool is_static_member = (parent_tag == DW_TAG_compile_unit || + parent_tag == DW_TAG_partial_unit) && + (parent_context_die.Tag() == DW_TAG_class_type || + parent_context_die.Tag() == DW_TAG_structure_type); + + ValueType scope = eValueTypeInvalid; + + const DWARFDIE sc_parent_die = GetParentSymbolContextDIE(die); + SymbolContextScope *symbol_context_scope = nullptr; + + bool has_explicit_mangled = mangled != nullptr; + if (!mangled) { + // LLDB relies on the mangled name (DW_TAG_linkage_name or + // DW_AT_MIPS_linkage_name) to generate fully qualified names + // of global variables with commands like "frame var j". For + // example, if j were an int variable holding a value 4 and + // declared in a namespace B which in turn is contained in a + // namespace A, the command "frame var j" returns + // "(int) A::B::j = 4". + // If the compiler does not emit a linkage name, we should be + // able to generate a fully qualified name from the + // declaration context. + if ((parent_tag == DW_TAG_compile_unit || + parent_tag == DW_TAG_partial_unit) && + Language::LanguageIsCPlusPlus(GetLanguage(*die.GetCU()))) + mangled = + GetDWARFDeclContext(die).GetQualifiedNameAsConstString().GetCString(); + } + + if (tag == DW_TAG_formal_parameter) + scope = eValueTypeVariableArgument; + else { + // DWARF doesn't specify if a DW_TAG_variable is a local, global + // or static variable, so we have to do a little digging: + // 1) DW_AT_linkage_name implies static lifetime (but may be missing) + // 2) An empty DW_AT_location is an (optimized-out) static lifetime var. + // 3) DW_AT_location containing a DW_OP_addr implies static lifetime. + // Clang likes to combine small global variables into the same symbol + // with locations like: DW_OP_addr(0x1000), DW_OP_constu(2), DW_OP_plus + // so we need to look through the whole expression. + bool is_static_lifetime = + has_explicit_mangled || (has_explicit_location && !location.IsValid()); + // Check if the location has a DW_OP_addr with any address value... + lldb::addr_t location_DW_OP_addr = LLDB_INVALID_ADDRESS; + if (!location_is_const_value_data) { + bool op_error = false; + location_DW_OP_addr = location.GetLocation_DW_OP_addr(0, op_error); + if (op_error) { + StreamString strm; + location.DumpLocationForAddress(&strm, eDescriptionLevelFull, 0, 0, + nullptr); + GetObjectFile()->GetModule()->ReportError( + "0x%8.8x: %s has an invalid location: %s", die.GetOffset(), + die.GetTagAsCString(), strm.GetData()); + } + if (location_DW_OP_addr != LLDB_INVALID_ADDRESS) + is_static_lifetime = true; + } + SymbolFileDWARFDebugMap *debug_map_symfile = GetDebugMapSymfile(); + if (debug_map_symfile) + // Set the module of the expression to the linked module + // instead of the oject file so the relocated address can be + // found there. + location.SetModule(debug_map_symfile->GetObjectFile()->GetModule()); + + if (is_static_lifetime) { + if (is_external) + scope = eValueTypeVariableGlobal; + else + scope = eValueTypeVariableStatic; + + if (debug_map_symfile) { + // When leaving the DWARF in the .o files on darwin, when we have a + // global variable that wasn't initialized, the .o file might not + // have allocated a virtual address for the global variable. In + // this case it will have created a symbol for the global variable + // that is undefined/data and external and the value will be the + // byte size of the variable. When we do the address map in + // SymbolFileDWARFDebugMap we rely on having an address, we need to + // do some magic here so we can get the correct address for our + // global variable. The address for all of these entries will be + // zero, and there will be an undefined symbol in this object file, + // and the executable will have a matching symbol with a good + // address. So here we dig up the correct address and replace it in + // the location for the variable, and set the variable's symbol + // context scope to be that of the main executable so the file + // address will resolve correctly. + bool linked_oso_file_addr = false; + if (is_external && location_DW_OP_addr == 0) { + // we have a possible uninitialized extern global + ConstString const_name(mangled ? mangled : name); + ObjectFile *debug_map_objfile = debug_map_symfile->GetObjectFile(); + if (debug_map_objfile) { + Symtab *debug_map_symtab = debug_map_objfile->GetSymtab(); + if (debug_map_symtab) { + Symbol *exe_symbol = + debug_map_symtab->FindFirstSymbolWithNameAndType( + const_name, eSymbolTypeData, Symtab::eDebugYes, + Symtab::eVisibilityExtern); + if (exe_symbol) { + if (exe_symbol->ValueIsAddress()) { + const addr_t exe_file_addr = + exe_symbol->GetAddressRef().GetFileAddress(); + if (exe_file_addr != LLDB_INVALID_ADDRESS) { + if (location.Update_DW_OP_addr(exe_file_addr)) { + linked_oso_file_addr = true; + symbol_context_scope = exe_symbol; } } } } } - - if (!linked_oso_file_addr) { - // The DW_OP_addr is not zero, but it contains a .o file address - // which needs to be linked up correctly. - const lldb::addr_t exe_file_addr = - debug_map_symfile->LinkOSOFileAddress(this, - location_DW_OP_addr); - if (exe_file_addr != LLDB_INVALID_ADDRESS) { - // Update the file address for this variable - location.Update_DW_OP_addr(exe_file_addr); - } else { - // Variable didn't make it into the final executable - return var_sp; - } - } } - } else { - if (location_is_const_value_data && - die.GetDIE()->IsGlobalOrStaticScopeVariable()) - scope = eValueTypeVariableStatic; - else { - scope = eValueTypeVariableLocal; - if (debug_map_symfile) { - // We need to check for TLS addresses that we need to fixup - if (location.ContainsThreadLocalStorage()) { - location.LinkThreadLocalStorage( - debug_map_symfile->GetObjectFile()->GetModule(), - [this, debug_map_symfile]( - lldb::addr_t unlinked_file_addr) -> lldb::addr_t { - return debug_map_symfile->LinkOSOFileAddress( - this, unlinked_file_addr); - }); - scope = eValueTypeVariableThreadLocal; - } - } + } + + if (!linked_oso_file_addr) { + // The DW_OP_addr is not zero, but it contains a .o file address + // which needs to be linked up correctly. + const lldb::addr_t exe_file_addr = + debug_map_symfile->LinkOSOFileAddress(this, location_DW_OP_addr); + if (exe_file_addr != LLDB_INVALID_ADDRESS) { + // Update the file address for this variable + location.Update_DW_OP_addr(exe_file_addr); + } else { + // Variable didn't make it into the final executable + return var_sp; } } } - - if (symbol_context_scope == nullptr) { - switch (parent_tag) { - case DW_TAG_subprogram: - case DW_TAG_inlined_subroutine: - case DW_TAG_lexical_block: - if (sc.function) { - symbol_context_scope = sc.function->GetBlock(true).FindBlockByID( - sc_parent_die.GetID()); - if (symbol_context_scope == nullptr) - symbol_context_scope = sc.function; + } else { + if (location_is_const_value_data && + die.GetDIE()->IsGlobalOrStaticScopeVariable()) + scope = eValueTypeVariableStatic; + else { + scope = eValueTypeVariableLocal; + if (debug_map_symfile) { + // We need to check for TLS addresses that we need to fixup + if (location.ContainsThreadLocalStorage()) { + location.LinkThreadLocalStorage( + debug_map_symfile->GetObjectFile()->GetModule(), + [this, debug_map_symfile]( + lldb::addr_t unlinked_file_addr) -> lldb::addr_t { + return debug_map_symfile->LinkOSOFileAddress( + this, unlinked_file_addr); + }); + scope = eValueTypeVariableThreadLocal; } - break; - - default: - symbol_context_scope = sc.comp_unit; - break; } } + } + } - if (symbol_context_scope) { - SymbolFileTypeSP type_sp( - new SymbolFileType(*this, GetUID(type_die_form.Reference()))); + if (symbol_context_scope == nullptr) { + switch (parent_tag) { + case DW_TAG_subprogram: + case DW_TAG_inlined_subroutine: + case DW_TAG_lexical_block: + if (sc.function) { + symbol_context_scope = + sc.function->GetBlock(true).FindBlockByID(sc_parent_die.GetID()); + if (symbol_context_scope == nullptr) + symbol_context_scope = sc.function; + } + break; - if (const_value.Form() && type_sp && type_sp->GetType()) - location.UpdateValue(const_value.Unsigned(), - type_sp->GetType()->GetByteSize().getValueOr(0), - die.GetCU()->GetAddressByteSize()); + default: + symbol_context_scope = sc.comp_unit; + break; + } + } - var_sp = std::make_shared( - die.GetID(), name, mangled, type_sp, scope, symbol_context_scope, - scope_ranges, &decl, location, is_external, is_artificial, - is_static_member); + if (symbol_context_scope) { + auto type_sp = std::make_shared( + *this, GetUID(type_die_form.Reference())); - var_sp->SetLocationIsConstantValueData(location_is_const_value_data); - } else { - // Not ready to parse this variable yet. It might be a global or static - // variable that is in a function scope and the function in the symbol - // context wasn't filled in yet - return var_sp; - } - } - // Cache var_sp even if NULL (the variable was just a specification or was - // missing vital information to be able to be displayed in the debugger - // (missing location due to optimization, etc)) so we don't re-parse this - // DIE over and over later... - GetDIEToVariable()[die.GetDIE()] = var_sp; - if (spec_die) - GetDIEToVariable()[spec_die.GetDIE()] = var_sp; + if (use_type_size_for_value && type_sp->GetType()) + location.UpdateValue( + const_value_form.Unsigned(), + type_sp->GetType()->GetByteSize(nullptr).getValueOr(0), + die.GetCU()->GetAddressByteSize()); + + var_sp = std::make_shared( + die.GetID(), name, mangled, type_sp, scope, symbol_context_scope, + scope_ranges, &decl, location, is_external, is_artificial, + location_is_const_value_data, is_static_member); + } else { + // Not ready to parse this variable yet. It might be a global or static + // variable that is in a function scope and the function in the symbol + // context wasn't filled in yet + return var_sp; } + // Cache var_sp even if NULL (the variable was just a specification or was + // missing vital information to be able to be displayed in the debugger + // (missing location due to optimization, etc)) so we don't re-parse this + // DIE over and over later... + GetDIEToVariable()[die.GetDIE()] = var_sp; + if (spec_die) + GetDIEToVariable()[spec_die.GetDIE()] = var_sp; + return var_sp; } @@ -3506,8 +3418,7 @@ SymbolFileDWARF::FindBlockContainingSpecification( // Give the concrete function die specified by "func_die_offset", find the // concrete block whose DW_AT_specification or DW_AT_abstract_origin points // to "spec_block_die_offset" - for (DWARFDIE child_die = die.GetFirstChild(); child_die; - child_die = child_die.GetSibling()) { + for (DWARFDIE child_die : die.children()) { DWARFDIE result_die = FindBlockContainingSpecification(child_die, spec_block_die_offset); if (result_die) @@ -3636,8 +3547,7 @@ size_t SymbolFileDWARF::ParseVariables(const SymbolContext &sc, static CallSiteParameterArray CollectCallSiteParameters(ModuleSP module, DWARFDIE call_site_die) { CallSiteParameterArray parameters; - for (DWARFDIE child = call_site_die.GetFirstChild(); child.IsValid(); - child = child.GetSibling()) { + for (DWARFDIE child : call_site_die.children()) { if (child.Tag() != DW_TAG_call_site_parameter && child.Tag() != DW_TAG_GNU_call_site_parameter) continue; @@ -3702,8 +3612,7 @@ SymbolFileDWARF::CollectCallEdges(ModuleSP module, DWARFDIE function_die) { // For now, assume that all entries are nested directly under the subprogram // (this is the kind of DWARF LLVM produces) and parse them eagerly. std::vector> call_edges; - for (DWARFDIE child = function_die.GetFirstChild(); child.IsValid(); - child = child.GetSibling()) { + for (DWARFDIE child : function_die.children()) { if (child.Tag() != DW_TAG_call_site && child.Tag() != DW_TAG_GNU_call_site) continue; @@ -3879,7 +3788,7 @@ void SymbolFileDWARF::DumpClangAST(Stream &s) { } SymbolFileDWARFDebugMap *SymbolFileDWARF::GetDebugMapSymfile() { - if (m_debug_map_symfile == nullptr && !m_debug_map_module_wp.expired()) { + if (m_debug_map_symfile == nullptr) { lldb::ModuleSP module_sp(m_debug_map_module_wp.lock()); if (module_sp) { m_debug_map_symfile = @@ -3973,3 +3882,10 @@ LanguageType SymbolFileDWARF::LanguageTypeFromDWARF(uint64_t val) { LanguageType SymbolFileDWARF::GetLanguage(DWARFUnit &unit) { return LanguageTypeFromDWARF(unit.GetDWARFLanguageType()); } + +LanguageType SymbolFileDWARF::GetLanguageFamily(DWARFUnit &unit) { + auto lang = (llvm::dwarf::SourceLanguage)unit.GetDWARFLanguageType(); + if (llvm::dwarf::isCPlusPlus(lang)) + lang = DW_LANG_C_plus_plus; + return LanguageTypeFromDWARF(lang); +} diff --git a/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h b/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h index 76ceb279c71..d9feeef549e 100644 --- a/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h +++ b/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h @@ -161,11 +161,10 @@ public: lldb::SymbolContextItem resolve_scope, lldb_private::SymbolContext &sc) override; - uint32_t - ResolveSymbolContext(const lldb_private::FileSpec &file_spec, uint32_t line, - bool check_inlines, - lldb::SymbolContextItem resolve_scope, - lldb_private::SymbolContextList &sc_list) override; + uint32_t ResolveSymbolContext( + const lldb_private::SourceLocationSpec &src_location_spec, + lldb::SymbolContextItem resolve_scope, + lldb_private::SymbolContextList &sc_list) override; void FindGlobalVariables(lldb_private::ConstString name, @@ -318,6 +317,8 @@ public: static lldb::LanguageType LanguageTypeFromDWARF(uint64_t val); static lldb::LanguageType GetLanguage(DWARFUnit &unit); + /// Same as GetLanguage() but reports all C++ versions as C++ (no version). + static lldb::LanguageType GetLanguageFamily(DWARFUnit &unit); protected: typedef llvm::DenseMap @@ -346,7 +347,7 @@ protected: lldb::CompUnitSP ParseCompileUnit(DWARFCompileUnit &dwarf_cu); - virtual DWARFUnit * + virtual DWARFCompileUnit * GetDWARFCompileUnit(lldb_private::CompileUnit *comp_unit); DWARFUnit *GetNextUnparsedDWARFCompileUnit(DWARFUnit *prev_cu); diff --git a/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp b/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp index 6515d78b8f2..4e2e5e16637 100644 --- a/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp +++ b/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp @@ -16,7 +16,6 @@ #include "lldb/Host/FileSystem.h" #include "lldb/Utility/RangeMap.h" #include "lldb/Utility/RegularExpression.h" -#include "lldb/Utility/Timer.h" //#define DEBUG_OSO_DMAP // DO NOT CHECKIN WITH THIS NOT COMMENTED OUT #if defined(DEBUG_OSO_DMAP) @@ -34,6 +33,9 @@ #include "LogChannelDWARF.h" #include "SymbolFileDWARF.h" +// Work around the fact that Timer.h pulls in the system Mach-O headers. +#include "lldb/Utility/Timer.h" + #include using namespace lldb; @@ -246,7 +248,7 @@ SymbolFileDWARFDebugMap::SymbolFileDWARFDebugMap(ObjectFileSP objfile_sp) m_func_indexes(), m_glob_indexes(), m_supports_DW_AT_APPLE_objc_complete_type(eLazyBoolCalculate) {} -SymbolFileDWARFDebugMap::~SymbolFileDWARFDebugMap() {} +SymbolFileDWARFDebugMap::~SymbolFileDWARFDebugMap() = default; void SymbolFileDWARFDebugMap::InitializeObject() {} @@ -806,7 +808,7 @@ SymbolFileDWARFDebugMap::ResolveSymbolContext(const Address &exe_so_addr, } uint32_t SymbolFileDWARFDebugMap::ResolveSymbolContext( - const FileSpec &file_spec, uint32_t line, bool check_inlines, + const SourceLocationSpec &src_location_spec, SymbolContextItem resolve_scope, SymbolContextList &sc_list) { std::lock_guard guard(GetModuleMutex()); const uint32_t initial = sc_list.GetSize(); @@ -815,18 +817,19 @@ uint32_t SymbolFileDWARFDebugMap::ResolveSymbolContext( for (uint32_t i = 0; i < cu_count; ++i) { // If we are checking for inlines, then we need to look through all compile // units no matter if "file_spec" matches. - bool resolve = check_inlines; + bool resolve = src_location_spec.GetCheckInlines(); if (!resolve) { FileSpec so_file_spec; if (GetFileSpecForSO(i, so_file_spec)) - resolve = FileSpec::Match(file_spec, so_file_spec); + resolve = + FileSpec::Match(src_location_spec.GetFileSpec(), so_file_spec); } if (resolve) { SymbolFileDWARF *oso_dwarf = GetSymbolFileByOSOIndex(i); if (oso_dwarf) - oso_dwarf->ResolveSymbolContext(file_spec, line, check_inlines, - resolve_scope, sc_list); + oso_dwarf->ResolveSymbolContext(src_location_spec, resolve_scope, + sc_list); } } return sc_list.GetSize() - initial; @@ -1013,9 +1016,7 @@ void SymbolFileDWARFDebugMap::FindFunctions( FunctionNameType name_type_mask, bool include_inlines, SymbolContextList &sc_list) { std::lock_guard guard(GetModuleMutex()); - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer(func_cat, - "SymbolFileDWARFDebugMap::FindFunctions (name = %s)", + LLDB_SCOPED_TIMERF("SymbolFileDWARFDebugMap::FindFunctions (name = %s)", name.GetCString()); ForEachSymbolFile([&](SymbolFileDWARF *oso_dwarf) -> bool { @@ -1034,9 +1035,7 @@ void SymbolFileDWARFDebugMap::FindFunctions(const RegularExpression ®ex, bool include_inlines, SymbolContextList &sc_list) { std::lock_guard guard(GetModuleMutex()); - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer(func_cat, - "SymbolFileDWARFDebugMap::FindFunctions (regex = '%s')", + LLDB_SCOPED_TIMERF("SymbolFileDWARFDebugMap::FindFunctions (regex = '%s')", regex.GetText().str().c_str()); ForEachSymbolFile([&](SymbolFileDWARF *oso_dwarf) -> bool { @@ -1055,9 +1054,7 @@ void SymbolFileDWARFDebugMap::GetTypes(SymbolContextScope *sc_scope, lldb::TypeClass type_mask, TypeList &type_list) { std::lock_guard guard(GetModuleMutex()); - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer(func_cat, - "SymbolFileDWARFDebugMap::GetTypes (type_mask = 0x%8.8x)", + LLDB_SCOPED_TIMERF("SymbolFileDWARFDebugMap::GetTypes (type_mask = 0x%8.8x)", type_mask); SymbolFileDWARF *oso_dwarf = nullptr; diff --git a/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h b/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h index 06f0d48c04c..8b6624e7086 100644 --- a/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h +++ b/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h @@ -97,11 +97,10 @@ public: uint32_t ResolveSymbolContext(const lldb_private::Address &so_addr, lldb::SymbolContextItem resolve_scope, lldb_private::SymbolContext &sc) override; - uint32_t - ResolveSymbolContext(const lldb_private::FileSpec &file_spec, uint32_t line, - bool check_inlines, - lldb::SymbolContextItem resolve_scope, - lldb_private::SymbolContextList &sc_list) override; + uint32_t ResolveSymbolContext( + const lldb_private::SourceLocationSpec &src_location_spec, + lldb::SymbolContextItem resolve_scope, + lldb_private::SymbolContextList &sc_list) override; void FindGlobalVariables(lldb_private::ConstString name, const lldb_private::CompilerDeclContext &parent_decl_ctx, @@ -171,18 +170,17 @@ protected: llvm::sys::TimePoint<> oso_mod_time; OSOInfoSP oso_sp; lldb::CompUnitSP compile_unit_sp; - uint32_t first_symbol_index; - uint32_t last_symbol_index; - uint32_t first_symbol_id; - uint32_t last_symbol_id; + uint32_t first_symbol_index = UINT32_MAX; + uint32_t last_symbol_index = UINT32_MAX; + uint32_t first_symbol_id = UINT32_MAX; + uint32_t last_symbol_id = UINT32_MAX; FileRangeMap file_range_map; - bool file_range_map_valid; + bool file_range_map_valid = false; CompileUnitInfo() : so_file(), oso_path(), oso_mod_time(), oso_sp(), compile_unit_sp(), - first_symbol_index(UINT32_MAX), last_symbol_index(UINT32_MAX), - first_symbol_id(UINT32_MAX), last_symbol_id(UINT32_MAX), - file_range_map(), file_range_map_valid(false) {} + + file_range_map() {} const FileRangeMap &GetFileRangeMap(SymbolFileDWARFDebugMap *exe_symfile); }; @@ -280,8 +278,7 @@ protected: // OSOEntry class OSOEntry { public: - OSOEntry() - : m_exe_sym_idx(UINT32_MAX), m_oso_file_addr(LLDB_INVALID_ADDRESS) {} + OSOEntry() = default; OSOEntry(uint32_t exe_sym_idx, lldb::addr_t oso_file_addr) : m_exe_sym_idx(exe_sym_idx), m_oso_file_addr(oso_file_addr) {} @@ -299,8 +296,8 @@ protected: } protected: - uint32_t m_exe_sym_idx; - lldb::addr_t m_oso_file_addr; + uint32_t m_exe_sym_idx = UINT32_MAX; + lldb::addr_t m_oso_file_addr = LLDB_INVALID_ADDRESS; }; typedef lldb_private::RangeDataVector diff --git a/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.cpp b/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.cpp index 3aaa7d330b8..fcb51dfa0e7 100644 --- a/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.cpp +++ b/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.cpp @@ -49,8 +49,7 @@ DWARFCompileUnit *SymbolFileDWARFDwo::GetDWOCompileUnitForHash(uint64_t hash) { DWARFCompileUnit *cu = FindSingleCompileUnit(); if (!cu) return nullptr; - if (hash != - cu->GetUnitDIEOnly().GetAttributeValueAsUnsigned(DW_AT_GNU_dwo_id, 0)) + if (hash != cu->GetDWOId()) return nullptr; return cu; } diff --git a/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/UniqueDWARFASTType.cpp b/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/UniqueDWARFASTType.cpp index 2181989cd37..34ff2366746 100644 --- a/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/UniqueDWARFASTType.cpp +++ b/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/UniqueDWARFASTType.cpp @@ -8,7 +8,7 @@ #include "UniqueDWARFASTType.h" -#include "lldb/Symbol/Declaration.h" +#include "lldb/Core/Declaration.h" bool UniqueDWARFASTTypeList::Find(const DWARFDIE &die, const lldb_private::Declaration &decl, diff --git a/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/UniqueDWARFASTType.h b/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/UniqueDWARFASTType.h index a1b1a300978..0947d1e581c 100644 --- a/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/UniqueDWARFASTType.h +++ b/gnu/llvm/lldb/source/Plugins/SymbolFile/DWARF/UniqueDWARFASTType.h @@ -14,16 +14,12 @@ #include "llvm/ADT/DenseMap.h" #include "DWARFDIE.h" -#include "lldb/Symbol/Declaration.h" +#include "lldb/Core/Declaration.h" class UniqueDWARFASTType { public: // Constructors and Destructors - UniqueDWARFASTType() - : m_type_sp(), m_die(), m_declaration(), - m_byte_size( - -1) // Set to negative value to make sure we have a valid value - {} + UniqueDWARFASTType() : m_type_sp(), m_die(), m_declaration() {} UniqueDWARFASTType(lldb::TypeSP &type_sp, const DWARFDIE &die, const lldb_private::Declaration &decl, int32_t byte_size) @@ -34,7 +30,7 @@ public: : m_type_sp(rhs.m_type_sp), m_die(rhs.m_die), m_declaration(rhs.m_declaration), m_byte_size(rhs.m_byte_size) {} - ~UniqueDWARFASTType() {} + ~UniqueDWARFASTType() = default; UniqueDWARFASTType &operator=(const UniqueDWARFASTType &rhs) { if (this != &rhs) { @@ -49,14 +45,14 @@ public: lldb::TypeSP m_type_sp; DWARFDIE m_die; lldb_private::Declaration m_declaration; - int32_t m_byte_size; + int32_t m_byte_size = -1; }; class UniqueDWARFASTTypeList { public: UniqueDWARFASTTypeList() : m_collection() {} - ~UniqueDWARFASTTypeList() {} + ~UniqueDWARFASTTypeList() = default; uint32_t GetSize() { return (uint32_t)m_collection.size(); } @@ -76,7 +72,7 @@ class UniqueDWARFASTTypeMap { public: UniqueDWARFASTTypeMap() : m_collection() {} - ~UniqueDWARFASTTypeMap() {} + ~UniqueDWARFASTTypeMap() = default; void Insert(lldb_private::ConstString name, const UniqueDWARFASTType &entry) { diff --git a/gnu/llvm/lldb/source/Plugins/SymbolFile/NativePDB/CMakeLists.txt b/gnu/llvm/lldb/source/Plugins/SymbolFile/NativePDB/CMakeLists.txt index 7dab9370e51..38a589d65b1 100644 --- a/gnu/llvm/lldb/source/Plugins/SymbolFile/NativePDB/CMakeLists.txt +++ b/gnu/llvm/lldb/source/Plugins/SymbolFile/NativePDB/CMakeLists.txt @@ -15,6 +15,7 @@ add_lldb_library(lldbPluginSymbolFileNativePDB lldbSymbol lldbUtility lldbPluginTypeSystemClang + lldbPluginObjectFilePDB CLANG_LIBS clangAST clangLex diff --git a/gnu/llvm/lldb/source/Plugins/SymbolFile/NativePDB/CompileUnitIndex.cpp b/gnu/llvm/lldb/source/Plugins/SymbolFile/NativePDB/CompileUnitIndex.cpp index f25dc84fb34..9f09c0accc8 100644 --- a/gnu/llvm/lldb/source/Plugins/SymbolFile/NativePDB/CompileUnitIndex.cpp +++ b/gnu/llvm/lldb/source/Plugins/SymbolFile/NativePDB/CompileUnitIndex.cpp @@ -43,7 +43,7 @@ static bool IsMainFile(llvm::StringRef main, llvm::StringRef other) { llvm::SmallString<64> normalized(other); llvm::sys::path::native(normalized); - return main.equals_lower(normalized); + return main.equals_insensitive(normalized); } static void ParseCompile3(const CVSymbol &sym, CompilandIndexItem &cci) { diff --git a/gnu/llvm/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp b/gnu/llvm/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp index 0acc77d7c67..43cf262016c 100644 --- a/gnu/llvm/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp +++ b/gnu/llvm/lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp @@ -881,8 +881,8 @@ PdbAstBuilder::GetOrCreateTypedefDecl(PdbGlobalSymId id) { std::string uname = std::string(DropNameScope(udt.Name)); - CompilerType ct = m_clang.CreateTypedefType(ToCompilerType(qt), uname.c_str(), - ToCompilerDeclContext(*scope), 0); + CompilerType ct = ToCompilerType(qt).CreateTypedef( + uname.c_str(), ToCompilerDeclContext(*scope), 0); clang::TypedefNameDecl *tnd = m_clang.GetAsTypedefDecl(ct); DeclStatus status; status.resolved = true; @@ -1015,8 +1015,7 @@ PdbAstBuilder::GetOrCreateFunctionDecl(PdbCompilandSymId func_id) { proc_name.consume_front("::"); clang::FunctionDecl *function_decl = m_clang.CreateFunctionDeclaration( - parent, OptionalClangModuleID(), proc_name.str().c_str(), func_ct, - storage, false); + parent, OptionalClangModuleID(), proc_name, func_ct, storage, false); lldbassert(m_uid_to_decl.count(toOpaqueUid(func_id)) == 0); m_uid_to_decl[toOpaqueUid(func_id)] = function_decl; @@ -1094,7 +1093,7 @@ void PdbAstBuilder::CreateFunctionParameters(PdbCompilandSymId func_id, } if (!params.empty()) - m_clang.SetFunctionParameters(&function_decl, params.data(), params.size()); + m_clang.SetFunctionParameters(&function_decl, params); } clang::QualType PdbAstBuilder::CreateEnumType(PdbTypeSymId id, diff --git a/gnu/llvm/lldb/source/Plugins/SymbolFile/NativePDB/PdbFPOProgramToDWARFExpression.cpp b/gnu/llvm/lldb/source/Plugins/SymbolFile/NativePDB/PdbFPOProgramToDWARFExpression.cpp index ecae767e446..4f570d5e678 100644 --- a/gnu/llvm/lldb/source/Plugins/SymbolFile/NativePDB/PdbFPOProgramToDWARFExpression.cpp +++ b/gnu/llvm/lldb/source/Plugins/SymbolFile/NativePDB/PdbFPOProgramToDWARFExpression.cpp @@ -41,7 +41,7 @@ static uint32_t ResolveLLDBRegisterNum(llvm::StringRef reg_name, llvm::Triple::A auto it = llvm::find_if( register_names, [®_name](const llvm::EnumEntry ®ister_entry) { - return reg_name.compare_lower(register_entry.Name) == 0; + return reg_name.compare_insensitive(register_entry.Name) == 0; }); if (it == register_names.end()) diff --git a/gnu/llvm/lldb/source/Plugins/SymbolFile/NativePDB/PdbIndex.cpp b/gnu/llvm/lldb/source/Plugins/SymbolFile/NativePDB/PdbIndex.cpp index 6ac6cc2da29..dc964f64a91 100644 --- a/gnu/llvm/lldb/source/Plugins/SymbolFile/NativePDB/PdbIndex.cpp +++ b/gnu/llvm/lldb/source/Plugins/SymbolFile/NativePDB/PdbIndex.cpp @@ -39,7 +39,7 @@ PdbIndex::PdbIndex() : m_cus(*this), m_va_to_modi(m_allocator) {} } llvm::Expected> -PdbIndex::create(std::unique_ptr file) { +PdbIndex::create(llvm::pdb::PDBFile *file) { lldbassert(file); std::unique_ptr result(new PdbIndex()); @@ -53,7 +53,7 @@ PdbIndex::create(std::unique_ptr file) { result->m_tpi->buildHashMap(); - result->m_file = std::move(file); + result->m_file = file; return std::move(result); } diff --git a/gnu/llvm/lldb/source/Plugins/SymbolFile/NativePDB/PdbIndex.h b/gnu/llvm/lldb/source/Plugins/SymbolFile/NativePDB/PdbIndex.h index ccc3cc2f453..1b382e5263c 100644 --- a/gnu/llvm/lldb/source/Plugins/SymbolFile/NativePDB/PdbIndex.h +++ b/gnu/llvm/lldb/source/Plugins/SymbolFile/NativePDB/PdbIndex.h @@ -48,7 +48,7 @@ struct SegmentOffset; class PdbIndex { /// The underlying PDB file. - std::unique_ptr m_file; + llvm::pdb::PDBFile *m_file = nullptr; /// The DBI stream. This contains general high level information about the /// features present in the PDB file, compile units (such as the information @@ -110,8 +110,7 @@ class PdbIndex { void BuildAddrToSymbolMap(CompilandIndexItem &cci); public: - static llvm::Expected> - create(std::unique_ptr); + static llvm::Expected> create(llvm::pdb::PDBFile *); void SetLoadAddress(lldb::addr_t addr) { m_load_address = addr; } lldb::addr_t GetLoadAddress() const { return m_load_address; } diff --git a/gnu/llvm/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp b/gnu/llvm/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp index cce06473d92..b9b075d83b6 100644 --- a/gnu/llvm/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp +++ b/gnu/llvm/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp @@ -16,6 +16,7 @@ #include "Plugins/ExpressionParser/Clang/ClangUtil.h" #include "Plugins/Language/CPlusPlus/MSVCUndecoratedNameParser.h" +#include "Plugins/ObjectFile/PDB/ObjectFilePDB.h" #include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/Module.h" #include "lldb/Core/PluginManager.h" @@ -42,9 +43,11 @@ #include "llvm/DebugInfo/PDB/Native/GlobalsStream.h" #include "llvm/DebugInfo/PDB/Native/InfoStream.h" #include "llvm/DebugInfo/PDB/Native/ModuleDebugStream.h" +#include "llvm/DebugInfo/PDB/Native/NativeSession.h" #include "llvm/DebugInfo/PDB/Native/PDBFile.h" #include "llvm/DebugInfo/PDB/Native/SymbolStream.h" #include "llvm/DebugInfo/PDB/Native/TpiStream.h" +#include "llvm/DebugInfo/PDB/PDB.h" #include "llvm/DebugInfo/PDB/PDBTypes.h" #include "llvm/Demangle/MicrosoftDemangle.h" #include "llvm/Object/COFF.h" @@ -81,32 +84,6 @@ static lldb::LanguageType TranslateLanguage(PDB_Lang lang) { } } -static std::unique_ptr loadPDBFile(std::string PdbPath, - llvm::BumpPtrAllocator &Allocator) { - llvm::ErrorOr> ErrorOrBuffer = - llvm::MemoryBuffer::getFile(PdbPath, /*FileSize=*/-1, - /*RequiresNullTerminator=*/false); - if (!ErrorOrBuffer) - return nullptr; - std::unique_ptr Buffer = std::move(*ErrorOrBuffer); - - llvm::StringRef Path = Buffer->getBufferIdentifier(); - auto Stream = std::make_unique( - std::move(Buffer), llvm::support::little); - - auto File = std::make_unique(Path, std::move(Stream), Allocator); - if (auto EC = File->parseFileHeaders()) { - llvm::consumeError(std::move(EC)); - return nullptr; - } - if (auto EC = File->parseStreamData()) { - llvm::consumeError(std::move(EC)); - return nullptr; - } - - return File; -} - static std::unique_ptr loadMatchingPDBFile(std::string exe_path, llvm::BumpPtrAllocator &allocator) { // Try to find a matching PDB for an EXE. @@ -134,13 +111,17 @@ loadMatchingPDBFile(std::string exe_path, llvm::BumpPtrAllocator &allocator) { return nullptr; } - // if the file doesn't exist, is not a pdb, or doesn't have a matching guid, - // fail. - llvm::file_magic magic; - auto ec = llvm::identify_magic(pdb_file, magic); - if (ec || magic != llvm::file_magic::pdb) - return nullptr; - std::unique_ptr pdb = loadPDBFile(std::string(pdb_file), allocator); + // If the file doesn't exist, perhaps the path specified at build time + // doesn't match the PDB's current location, so check the location of the + // executable. + if (!FileSystem::Instance().Exists(pdb_file)) { + const auto exe_dir = FileSpec(exe_path).CopyByRemovingLastPathComponent(); + const auto pdb_name = FileSpec(pdb_file).GetFilename().GetCString(); + pdb_file = exe_dir.CopyByAppendingPathComponent(pdb_name).GetCString(); + } + + // If the file is not a PDB or if it doesn't have a matching GUID, fail. + auto pdb = ObjectFilePDB::loadPDBFile(std::string(pdb_file), allocator); if (!pdb) return nullptr; @@ -275,7 +256,7 @@ SymbolFile *SymbolFileNativePDB::CreateInstance(ObjectFileSP objfile_sp) { SymbolFileNativePDB::SymbolFileNativePDB(ObjectFileSP objfile_sp) : SymbolFile(std::move(objfile_sp)) {} -SymbolFileNativePDB::~SymbolFileNativePDB() {} +SymbolFileNativePDB::~SymbolFileNativePDB() = default; uint32_t SymbolFileNativePDB::CalculateAbilities() { uint32_t abilities = 0; @@ -284,24 +265,19 @@ uint32_t SymbolFileNativePDB::CalculateAbilities() { if (!m_index) { // Lazily load and match the PDB file, but only do this once. - std::unique_ptr file_up = - loadMatchingPDBFile(m_objfile_sp->GetFileSpec().GetPath(), m_allocator); - - if (!file_up) { - auto module_sp = m_objfile_sp->GetModule(); - if (!module_sp) - return 0; - // See if any symbol file is specified through `--symfile` option. - FileSpec symfile = module_sp->GetSymbolFileFileSpec(); - if (!symfile) - return 0; - file_up = loadPDBFile(symfile.GetPath(), m_allocator); + PDBFile *pdb_file; + if (auto *pdb = llvm::dyn_cast(m_objfile_sp.get())) { + pdb_file = &pdb->GetPDBFile(); + } else { + m_file_up = loadMatchingPDBFile(m_objfile_sp->GetFileSpec().GetPath(), + m_allocator); + pdb_file = m_file_up.get(); } - if (!file_up) + if (!pdb_file) return 0; - auto expected_index = PdbIndex::create(std::move(file_up)); + auto expected_index = PdbIndex::create(pdb_file); if (!expected_index) { llvm::consumeError(expected_index.takeError()); return 0; @@ -321,7 +297,10 @@ uint32_t SymbolFileNativePDB::CalculateAbilities() { } void SymbolFileNativePDB::InitializeObject() { - m_obj_load_address = m_objfile_sp->GetBaseAddress().GetFileAddress(); + m_obj_load_address = m_objfile_sp->GetModule() + ->GetObjectFile() + ->GetBaseAddress() + .GetFileAddress(); m_index->SetLoadAddress(m_obj_load_address); m_index->ParseSectionContribs(); @@ -460,7 +439,7 @@ lldb::TypeSP SymbolFileNativePDB::CreateModifierType(PdbTypeSymId type_id, lldb::TypeSP modified_type = GetOrCreateType(mr.ModifiedType); return std::make_shared(toOpaqueUid(type_id), this, ConstString(name), - modified_type->GetByteSize(), nullptr, + modified_type->GetByteSize(nullptr), nullptr, LLDB_INVALID_UID, Type::eEncodingIsUID, decl, ct, Type::ResolveState::Full); } @@ -584,7 +563,7 @@ lldb::TypeSP SymbolFileNativePDB::CreateTagType(PdbTypeSymId type_id, return std::make_shared( toOpaqueUid(type_id), this, ConstString(uname), - underlying_type->GetByteSize(), nullptr, LLDB_INVALID_UID, + underlying_type->GetByteSize(nullptr), nullptr, LLDB_INVALID_UID, lldb_private::Type::eEncodingIsUID, decl, ct, lldb_private::Type::ResolveState::Forward); } @@ -809,11 +788,13 @@ VariableSP SymbolFileNativePDB::CreateGlobalVariable(PdbGlobalSymId var_id) { std::string global_name("::"); global_name += name; + bool artificial = false; + bool location_is_constant_data = false; + bool static_member = false; VariableSP var_sp = std::make_shared( toOpaqueUid(var_id), name.str().c_str(), global_name.c_str(), type_sp, - scope, comp_unit.get(), ranges, &decl, location, is_external, false, - false); - var_sp->SetLocationIsConstantValueData(false); + scope, comp_unit.get(), ranges, &decl, location, is_external, artificial, + location_is_constant_data, static_member); return var_sp; } @@ -837,11 +818,14 @@ SymbolFileNativePDB::CreateConstantSymbol(PdbGlobalSymId var_id, DWARFExpression location = MakeConstantLocationExpression( constant.Type, tpi, constant.Value, module); + bool external = false; + bool artificial = false; + bool location_is_constant_data = true; + bool static_member = false; VariableSP var_sp = std::make_shared( toOpaqueUid(var_id), constant.Name.str().c_str(), global_name.c_str(), type_sp, eValueTypeVariableGlobal, module.get(), ranges, &decl, location, - false, false, false); - var_sp->SetLocationIsConstantValueData(true); + external, artificial, location_is_constant_data, static_member); return var_sp; } @@ -1017,7 +1001,7 @@ uint32_t SymbolFileNativePDB::ResolveSymbolContext( } uint32_t SymbolFileNativePDB::ResolveSymbolContext( - const FileSpec &file_spec, uint32_t line, bool check_inlines, + const SourceLocationSpec &src_location_spec, lldb::SymbolContextItem resolve_scope, SymbolContextList &sc_list) { return 0; } @@ -1055,7 +1039,7 @@ static void TerminateLineSequence(LineTable &table, table.AppendLineEntryToSequence(seq.get(), base_addr + block.CodeSize, last_line, 0, file_number, false, false, false, false, true); - table.InsertSequence(seq.release()); + table.InsertSequence(seq.get()); } bool SymbolFileNativePDB::ParseLineTable(CompileUnit &comp_unit) { @@ -1343,10 +1327,14 @@ VariableSP SymbolFileNativePDB::CreateLocalVariable(PdbCompilandSymId scope_id, ValueType var_scope = is_param ? eValueTypeVariableArgument : eValueTypeVariableLocal; + bool external = false; + bool artificial = false; + bool location_is_constant_data = false; + bool static_member = false; VariableSP var_sp = std::make_shared( toOpaqueUid(var_id), name.c_str(), name.c_str(), sftype, var_scope, - comp_unit_sp.get(), *var_info.ranges, &decl, *var_info.location, false, - false, false); + comp_unit_sp.get(), *var_info.ranges, &decl, *var_info.location, external, + artificial, location_is_constant_data, static_member); if (!is_param) m_ast->GetOrCreateVariableDecl(scope_id, var_id); @@ -1376,9 +1364,10 @@ TypeSP SymbolFileNativePDB::CreateTypedef(PdbGlobalSymId id) { Declaration decl; return std::make_shared( - toOpaqueUid(id), this, ConstString(udt.Name), target_type->GetByteSize(), - nullptr, target_type->GetID(), lldb_private::Type::eEncodingIsTypedefUID, - decl, target_type->GetForwardCompilerType(), + toOpaqueUid(id), this, ConstString(udt.Name), + target_type->GetByteSize(nullptr), nullptr, target_type->GetID(), + lldb_private::Type::eEncodingIsTypedefUID, decl, + target_type->GetForwardCompilerType(), lldb_private::Type::ResolveState::Forward); } diff --git a/gnu/llvm/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h b/gnu/llvm/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h index bf5718e11a1..def0995065c 100644 --- a/gnu/llvm/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h +++ b/gnu/llvm/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h @@ -120,8 +120,7 @@ public: uint32_t ResolveSymbolContext(const Address &so_addr, lldb::SymbolContextItem resolve_scope, SymbolContext &sc) override; - uint32_t ResolveSymbolContext(const FileSpec &file_spec, uint32_t line, - bool check_inlines, + uint32_t ResolveSymbolContext(const SourceLocationSpec &src_location_spec, lldb::SymbolContextItem resolve_scope, SymbolContextList &sc_list) override; @@ -231,6 +230,7 @@ private: lldb::addr_t m_obj_load_address = 0; bool m_done_full_type_scan = false; + std::unique_ptr m_file_up; std::unique_ptr m_index; std::unique_ptr m_ast; diff --git a/gnu/llvm/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp b/gnu/llvm/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp index d87926a6588..78a0d09a681 100644 --- a/gnu/llvm/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp +++ b/gnu/llvm/lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp @@ -17,8 +17,8 @@ #include "Plugins/ExpressionParser/Clang/ClangASTMetadata.h" #include "Plugins/ExpressionParser/Clang/ClangUtil.h" #include "Plugins/TypeSystem/Clang/TypeSystemClang.h" +#include "lldb/Core/Declaration.h" #include "lldb/Core/Module.h" -#include "lldb/Symbol/Declaration.h" #include "lldb/Symbol/SymbolFile.h" #include "lldb/Symbol/TypeMap.h" #include "lldb/Symbol/TypeSystem.h" @@ -326,7 +326,7 @@ GetDeclFromContextByName(const clang::ASTContext &ast, if (result.empty()) return nullptr; - return result[0]; + return *result.begin(); } static bool IsAnonymousNamespaceName(llvm::StringRef name) { @@ -355,7 +355,7 @@ static clang::CallingConv TranslateCallingConvention(PDB_CallingConv pdb_cc) { PDBASTParser::PDBASTParser(lldb_private::TypeSystemClang &ast) : m_ast(ast) {} -PDBASTParser::~PDBASTParser() {} +PDBASTParser::~PDBASTParser() = default; // DebugInfoASTParser interface @@ -534,8 +534,12 @@ lldb::TypeSP PDBASTParser::CreateLLDBTypeFromPDBType(const PDBSymbol &type) { auto type_def = llvm::dyn_cast(&type); assert(type_def); + SymbolFile *symbol_file = m_ast.GetSymbolFile(); + if (!symbol_file) + return nullptr; + lldb_private::Type *target_type = - m_ast.GetSymbolFile()->ResolveTypeUID(type_def->getTypeId()); + symbol_file->ResolveTypeUID(type_def->getTypeId()); if (!target_type) return nullptr; @@ -550,8 +554,8 @@ lldb::TypeSP PDBASTParser::CreateLLDBTypeFromPDBType(const PDBSymbol &type) { if (!ast_typedef.IsValid()) { CompilerType target_ast_type = target_type->GetFullCompilerType(); - ast_typedef = m_ast.CreateTypedefType( - target_ast_type, name.c_str(), m_ast.CreateDeclContext(decl_ctx), 0); + ast_typedef = target_ast_type.CreateTypedef( + name.c_str(), m_ast.CreateDeclContext(decl_ctx), 0); if (!ast_typedef) return nullptr; @@ -609,8 +613,13 @@ lldb::TypeSP PDBASTParser::CreateLLDBTypeFromPDBType(const PDBSymbol &type) { auto arg = arg_enum->getChildAtIndex(arg_idx); if (!arg) break; + + SymbolFile *symbol_file = m_ast.GetSymbolFile(); + if (!symbol_file) + return nullptr; + lldb_private::Type *arg_type = - m_ast.GetSymbolFile()->ResolveTypeUID(arg->getSymIndexId()); + symbol_file->ResolveTypeUID(arg->getSymIndexId()); // If there's some error looking up one of the dependent types of this // function signature, bail. if (!arg_type) @@ -621,8 +630,12 @@ lldb::TypeSP PDBASTParser::CreateLLDBTypeFromPDBType(const PDBSymbol &type) { lldbassert(arg_list.size() <= num_args); auto pdb_return_type = func_sig->getReturnType(); + SymbolFile *symbol_file = m_ast.GetSymbolFile(); + if (!symbol_file) + return nullptr; + lldb_private::Type *return_type = - m_ast.GetSymbolFile()->ResolveTypeUID(pdb_return_type->getSymIndexId()); + symbol_file->ResolveTypeUID(pdb_return_type->getSymIndexId()); // If there's some error looking up one of the dependent types of this // function signature, bail. if (!return_type) @@ -654,10 +667,13 @@ lldb::TypeSP PDBASTParser::CreateLLDBTypeFromPDBType(const PDBSymbol &type) { if (uint64_t size = array_type->getLength()) bytes = size; + SymbolFile *symbol_file = m_ast.GetSymbolFile(); + if (!symbol_file) + return nullptr; + // If array rank > 0, PDB gives the element type at N=0. So element type // will parsed in the order N=0, N=1,..., N=rank sequentially. - lldb_private::Type *element_type = - m_ast.GetSymbolFile()->ResolveTypeUID(element_uid); + lldb_private::Type *element_type = symbol_file->ResolveTypeUID(element_uid); if (!element_type) return nullptr; @@ -711,7 +727,12 @@ lldb::TypeSP PDBASTParser::CreateLLDBTypeFromPDBType(const PDBSymbol &type) { case PDB_SymType::PointerType: { auto *pointer_type = llvm::dyn_cast(&type); assert(pointer_type); - Type *pointee_type = m_ast.GetSymbolFile()->ResolveTypeUID( + + SymbolFile *symbol_file = m_ast.GetSymbolFile(); + if (!symbol_file) + return nullptr; + + Type *pointee_type = symbol_file->ResolveTypeUID( pointer_type->getPointeeType()->getSymIndexId()); if (!pointee_type) return nullptr; @@ -719,8 +740,7 @@ lldb::TypeSP PDBASTParser::CreateLLDBTypeFromPDBType(const PDBSymbol &type) { if (pointer_type->isPointerToDataMember() || pointer_type->isPointerToMemberFunction()) { auto class_parent_uid = pointer_type->getRawSymbol().getClassParentId(); - auto class_parent_type = - m_ast.GetSymbolFile()->ResolveTypeUID(class_parent_uid); + auto class_parent_type = symbol_file->ResolveTypeUID(class_parent_uid); assert(class_parent_type); CompilerType pointer_ast_type; @@ -928,7 +948,7 @@ PDBASTParser::GetDeclForSymbol(const llvm::pdb::PDBSymbol &symbol) { : clang::StorageClass::SC_None; auto decl = m_ast.CreateFunctionDeclaration( - decl_context, OptionalClangModuleID(), name.c_str(), + decl_context, OptionalClangModuleID(), name, type->GetForwardCompilerType(), storage, func->hasInlineAttribute()); std::vector params; @@ -950,7 +970,7 @@ PDBASTParser::GetDeclForSymbol(const llvm::pdb::PDBSymbol &symbol) { } } if (params.size()) - m_ast.SetFunctionParameters(decl, params.data(), params.size()); + m_ast.SetFunctionParameters(decl, params); m_uid_to_decl[sym_id] = decl; diff --git a/gnu/llvm/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp b/gnu/llvm/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp index 1001514eded..6b30ad26dca 100644 --- a/gnu/llvm/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp +++ b/gnu/llvm/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp @@ -52,8 +52,6 @@ #include "Plugins/Language/CPlusPlus/MSVCUndecoratedNameParser.h" #include "Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h" -#include - using namespace lldb; using namespace lldb_private; using namespace llvm::pdb; @@ -86,8 +84,10 @@ bool ShouldAddLine(uint32_t requested_line, uint32_t actual_line, static bool ShouldUseNativeReader() { #if defined(_WIN32) llvm::StringRef use_native = ::getenv("LLDB_USE_NATIVE_PDB_READER"); - return use_native.equals_lower("on") || use_native.equals_lower("yes") || - use_native.equals_lower("1") || use_native.equals_lower("true"); + return use_native.equals_insensitive("on") || + use_native.equals_insensitive("yes") || + use_native.equals_insensitive("1") || + use_native.equals_insensitive("true"); #else return true; #endif @@ -130,7 +130,7 @@ SymbolFilePDB::CreateInstance(ObjectFileSP objfile_sp) { SymbolFilePDB::SymbolFilePDB(lldb::ObjectFileSP objfile_sp) : SymbolFile(std::move(objfile_sp)), m_session_up(), m_global_scope_up() {} -SymbolFilePDB::~SymbolFilePDB() {} +SymbolFilePDB::~SymbolFilePDB() = default; uint32_t SymbolFilePDB::CalculateAbilities() { uint32_t abilities = 0; @@ -786,10 +786,12 @@ SymbolFilePDB::ResolveSymbolContext(const lldb_private::Address &so_addr, } uint32_t SymbolFilePDB::ResolveSymbolContext( - const lldb_private::FileSpec &file_spec, uint32_t line, bool check_inlines, + const lldb_private::SourceLocationSpec &src_location_spec, SymbolContextItem resolve_scope, lldb_private::SymbolContextList &sc_list) { std::lock_guard guard(GetModuleMutex()); const size_t old_size = sc_list.GetSize(); + const FileSpec &file_spec = src_location_spec.GetFileSpec(); + const uint32_t line = src_location_spec.GetLine().getValueOr(0); if (resolve_scope & lldb::eSymbolContextCompUnit) { // Locate all compilation units with line numbers referencing the specified // file. For example, if `file_spec` is , then this should return @@ -808,7 +810,7 @@ uint32_t SymbolFilePDB::ResolveSymbolContext( // this file unless the FileSpec matches. For inline functions, we don't // have to match the FileSpec since they could be defined in headers // other than file specified in FileSpec. - if (!check_inlines) { + if (!src_location_spec.GetCheckInlines()) { std::string source_file = compiland->getSourceFileFullPath(); if (source_file.empty()) continue; @@ -1020,8 +1022,8 @@ VariableSP SymbolFilePDB::ParseVariableForPDBData( var_sp = std::make_shared( var_uid, var_name.c_str(), mangled_cstr, type_sp, scope, context_scope, - ranges, &decl, location, is_external, is_artificial, is_static_member); - var_sp->SetLocationIsConstantValueData(is_constant); + ranges, &decl, location, is_external, is_artificial, is_constant, + is_static_member); m_variables.insert(std::make_pair(var_uid, var_sp)); return var_sp; @@ -1815,7 +1817,7 @@ bool SymbolFilePDB::ParseCompileUnitLineTable(CompileUnit &comp_unit, sequence.get(), prev_addr + prev_length, prev_line, 0, prev_source_idx, false, false, false, false, true); - line_table->InsertSequence(sequence.release()); + line_table->InsertSequence(sequence.get()); sequence = line_table->CreateLineSequenceContainer(); } diff --git a/gnu/llvm/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.h b/gnu/llvm/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.h index 928cbffc5f6..2171b7f686c 100644 --- a/gnu/llvm/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.h +++ b/gnu/llvm/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.h @@ -104,11 +104,10 @@ public: lldb::SymbolContextItem resolve_scope, lldb_private::SymbolContext &sc) override; - uint32_t - ResolveSymbolContext(const lldb_private::FileSpec &file_spec, uint32_t line, - bool check_inlines, - lldb::SymbolContextItem resolve_scope, - lldb_private::SymbolContextList &sc_list) override; + uint32_t ResolveSymbolContext( + const lldb_private::SourceLocationSpec &src_location_spec, + lldb::SymbolContextItem resolve_scope, + lldb_private::SymbolContextList &sc_list) override; void FindGlobalVariables(lldb_private::ConstString name, diff --git a/gnu/llvm/lldb/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.cpp b/gnu/llvm/lldb/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.cpp index c4a0e609aa2..3a5e02d4fb8 100644 --- a/gnu/llvm/lldb/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.cpp +++ b/gnu/llvm/lldb/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.cpp @@ -59,8 +59,6 @@ SymbolFileSymtab::SymbolFileSymtab(ObjectFileSP objfile_sp) : SymbolFile(std::move(objfile_sp)), m_source_indexes(), m_func_indexes(), m_code_indexes(), m_objc_class_name_to_index() {} -SymbolFileSymtab::~SymbolFileSymtab() {} - uint32_t SymbolFileSymtab::CalculateAbilities() { uint32_t abilities = 0; if (m_objfile_sp) { diff --git a/gnu/llvm/lldb/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.h b/gnu/llvm/lldb/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.h index 9557ebbcb27..377c41e5077 100644 --- a/gnu/llvm/lldb/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.h +++ b/gnu/llvm/lldb/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.h @@ -31,8 +31,6 @@ public: // Constructors and Destructors SymbolFileSymtab(lldb::ObjectFileSP objfile_sp); - ~SymbolFileSymtab() override; - // Static Functions static void Initialize(); @@ -104,10 +102,6 @@ protected: lldb_private::Symtab::IndexCollection m_data_indexes; lldb_private::Symtab::NameToIndexMap m_objc_class_name_to_index; TypeMap m_objc_class_types; - -private: - SymbolFileSymtab(const SymbolFileSymtab &) = delete; - const SymbolFileSymtab &operator=(const SymbolFileSymtab &) = delete; }; #endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_SYMTAB_SYMBOLFILESYMTAB_H diff --git a/gnu/llvm/lldb/source/Plugins/SymbolVendor/ELF/SymbolVendorELF.cpp b/gnu/llvm/lldb/source/Plugins/SymbolVendor/ELF/SymbolVendorELF.cpp index 2e6fd436502..9130eed63e4 100644 --- a/gnu/llvm/lldb/source/Plugins/SymbolVendor/ELF/SymbolVendorELF.cpp +++ b/gnu/llvm/lldb/source/Plugins/SymbolVendor/ELF/SymbolVendorELF.cpp @@ -8,7 +8,7 @@ #include "SymbolVendorELF.h" -#include +#include #include "Plugins/ObjectFile/ELF/ObjectFileELF.h" #include "lldb/Core/Module.h" @@ -31,9 +31,6 @@ LLDB_PLUGIN_DEFINE(SymbolVendorELF) SymbolVendorELF::SymbolVendorELF(const lldb::ModuleSP &module_sp) : SymbolVendor(module_sp) {} -// Destructor -SymbolVendorELF::~SymbolVendorELF() {} - void SymbolVendorELF::Initialize() { PluginManager::RegisterPlugin(GetPluginNameStatic(), GetPluginDescriptionStatic(), CreateInstance); @@ -84,8 +81,7 @@ SymbolVendorELF::CreateInstance(const lldb::ModuleSP &module_sp, if (!fspec) fspec = obj_file->GetDebugLink().getValueOr(FileSpec()); - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer(func_cat, "SymbolVendorELF::CreateInstance (module = %s)", + LLDB_SCOPED_TIMERF("SymbolVendorELF::CreateInstance (module = %s)", module_sp->GetFileSpec().GetPath().c_str()); ModuleSpec module_spec; diff --git a/gnu/llvm/lldb/source/Plugins/SymbolVendor/ELF/SymbolVendorELF.h b/gnu/llvm/lldb/source/Plugins/SymbolVendor/ELF/SymbolVendorELF.h index 824906c0495..2080084a15b 100644 --- a/gnu/llvm/lldb/source/Plugins/SymbolVendor/ELF/SymbolVendorELF.h +++ b/gnu/llvm/lldb/source/Plugins/SymbolVendor/ELF/SymbolVendorELF.h @@ -17,8 +17,6 @@ public: // Constructors and Destructors SymbolVendorELF(const lldb::ModuleSP &module_sp); - ~SymbolVendorELF() override; - // Static Functions static void Initialize(); @@ -36,10 +34,6 @@ public: lldb_private::ConstString GetPluginName() override; uint32_t GetPluginVersion() override; - -private: - SymbolVendorELF(const SymbolVendorELF &) = delete; - const SymbolVendorELF &operator=(const SymbolVendorELF &) = delete; }; #endif // LLDB_SOURCE_PLUGINS_SYMBOLVENDOR_ELF_SYMBOLVENDORELF_H diff --git a/gnu/llvm/lldb/source/Plugins/SymbolVendor/MacOSX/SymbolVendorMacOSX.cpp b/gnu/llvm/lldb/source/Plugins/SymbolVendor/MacOSX/SymbolVendorMacOSX.cpp index fc426d1c9c3..cd1acebd680 100644 --- a/gnu/llvm/lldb/source/Plugins/SymbolVendor/MacOSX/SymbolVendorMacOSX.cpp +++ b/gnu/llvm/lldb/source/Plugins/SymbolVendor/MacOSX/SymbolVendorMacOSX.cpp @@ -8,7 +8,7 @@ #include "SymbolVendorMacOSX.h" -#include +#include #include "Plugins/ObjectFile/Mach-O/ObjectFileMachO.h" #include "lldb/Core/Module.h" @@ -20,7 +20,7 @@ #include "lldb/Symbol/LocateSymbolFile.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Target/Target.h" -#include "lldb/Utility/Reproducer.h" +#include "lldb/Utility/ReproducerProvider.h" #include "lldb/Utility/StreamString.h" #include "lldb/Utility/Timer.h" @@ -33,9 +33,6 @@ LLDB_PLUGIN_DEFINE(SymbolVendorMacOSX) SymbolVendorMacOSX::SymbolVendorMacOSX(const lldb::ModuleSP &module_sp) : SymbolVendor(module_sp) {} -// Destructor -SymbolVendorMacOSX::~SymbolVendorMacOSX() {} - static bool UUIDsMatch(Module *module, ObjectFile *ofile, lldb_private::Stream *feedback_strm) { if (module && ofile) { @@ -299,7 +296,7 @@ SymbolVendorMacOSX::CreateInstance(const lldb::ModuleSP &module_sp, if (repro::Generator *g = repro::Reproducer::Instance().GetGenerator()) { repro::FileProvider &fp = g->GetOrCreate(); - fp.recordInterestingDirectory(dsym_root); + fp.RecordInterestingDirectoryRecursive(dsym_root); } } return symbol_vendor; diff --git a/gnu/llvm/lldb/source/Plugins/SymbolVendor/MacOSX/SymbolVendorMacOSX.h b/gnu/llvm/lldb/source/Plugins/SymbolVendor/MacOSX/SymbolVendorMacOSX.h index 7d2de4ac29a..4324e24955e 100644 --- a/gnu/llvm/lldb/source/Plugins/SymbolVendor/MacOSX/SymbolVendorMacOSX.h +++ b/gnu/llvm/lldb/source/Plugins/SymbolVendor/MacOSX/SymbolVendorMacOSX.h @@ -30,16 +30,10 @@ public: // Constructors and Destructors SymbolVendorMacOSX(const lldb::ModuleSP &module_sp); - virtual ~SymbolVendorMacOSX(); - // PluginInterface protocol - virtual lldb_private::ConstString GetPluginName(); - - virtual uint32_t GetPluginVersion(); + lldb_private::ConstString GetPluginName() override; -private: - SymbolVendorMacOSX(const SymbolVendorMacOSX &) = delete; - const SymbolVendorMacOSX &operator=(const SymbolVendorMacOSX &) = delete; + uint32_t GetPluginVersion() override; }; #endif // LLDB_SOURCE_PLUGINS_SYMBOLVENDOR_MACOSX_SYMBOLVENDORMACOSX_H diff --git a/gnu/llvm/lldb/source/Plugins/SymbolVendor/wasm/SymbolVendorWasm.cpp b/gnu/llvm/lldb/source/Plugins/SymbolVendor/wasm/SymbolVendorWasm.cpp index 1c09dabc562..2b284079657 100644 --- a/gnu/llvm/lldb/source/Plugins/SymbolVendor/wasm/SymbolVendorWasm.cpp +++ b/gnu/llvm/lldb/source/Plugins/SymbolVendor/wasm/SymbolVendorWasm.cpp @@ -8,7 +8,7 @@ #include "SymbolVendorWasm.h" -#include +#include #include "Plugins/ObjectFile/wasm/ObjectFileWasm.h" #include "lldb/Core/Module.h" @@ -72,8 +72,7 @@ SymbolVendorWasm::CreateInstance(const lldb::ModuleSP &module_sp, lldb::eSectionTypeDWARFDebugInfo, true)) return nullptr; - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer(func_cat, "SymbolVendorWasm::CreateInstance (module = %s)", + LLDB_SCOPED_TIMERF("SymbolVendorWasm::CreateInstance (module = %s)", module_sp->GetFileSpec().GetPath().c_str()); ModuleSpec module_spec; diff --git a/gnu/llvm/lldb/source/Plugins/SymbolVendor/wasm/SymbolVendorWasm.h b/gnu/llvm/lldb/source/Plugins/SymbolVendor/wasm/SymbolVendorWasm.h index 96e737b1be9..b212337e054 100644 --- a/gnu/llvm/lldb/source/Plugins/SymbolVendor/wasm/SymbolVendorWasm.h +++ b/gnu/llvm/lldb/source/Plugins/SymbolVendor/wasm/SymbolVendorWasm.h @@ -33,10 +33,6 @@ public: lldb_private::ConstString GetPluginName() override; uint32_t GetPluginVersion() override; /// \} - -private: - SymbolVendorWasm(const SymbolVendorWasm &) = delete; - const SymbolVendorWasm &operator=(const SymbolVendorWasm &) = delete; }; } // namespace wasm diff --git a/gnu/llvm/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetItemInfoHandler.cpp b/gnu/llvm/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetItemInfoHandler.cpp index 7dfa759a7fb..7ece7f51842 100644 --- a/gnu/llvm/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetItemInfoHandler.cpp +++ b/gnu/llvm/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetItemInfoHandler.cpp @@ -98,7 +98,7 @@ AppleGetItemInfoHandler::AppleGetItemInfoHandler(Process *process) m_get_item_info_return_buffer_addr(LLDB_INVALID_ADDRESS), m_get_item_info_retbuffer_mutex() {} -AppleGetItemInfoHandler::~AppleGetItemInfoHandler() {} +AppleGetItemInfoHandler::~AppleGetItemInfoHandler() = default; void AppleGetItemInfoHandler::Detach() { @@ -142,25 +142,14 @@ lldb::addr_t AppleGetItemInfoHandler::SetupGetItemInfoFunction( if (!m_get_item_info_impl_code) { if (g_get_item_info_function_code != nullptr) { - Status error; - m_get_item_info_impl_code.reset( - exe_ctx.GetTargetRef().GetUtilityFunctionForLanguage( - g_get_item_info_function_code, eLanguageTypeObjC, - g_get_item_info_function_name, error)); - if (error.Fail()) { - LLDB_LOGF(log, "Failed to get utility function: %s.", - error.AsCString()); - return args_addr; - } - - if (!m_get_item_info_impl_code->Install(diagnostics, exe_ctx)) { - if (log) { - LLDB_LOGF(log, "Failed to install get-item-info introspection."); - diagnostics.Dump(log); - } - m_get_item_info_impl_code.reset(); - return args_addr; + auto utility_fn_or_error = exe_ctx.GetTargetRef().CreateUtilityFunction( + g_get_item_info_function_code, g_get_item_info_function_name, + eLanguageTypeObjC, exe_ctx); + if (!utility_fn_or_error) { + LLDB_LOG_ERROR(log, utility_fn_or_error.takeError(), + "Failed to create utility function: {0}."); } + m_get_item_info_impl_code = std::move(*utility_fn_or_error); } else { LLDB_LOGF(log, "No get-item-info introspection code found."); return LLDB_INVALID_ADDRESS; @@ -227,7 +216,8 @@ AppleGetItemInfoHandler::GetItemInfo(Thread &thread, uint64_t item, lldb::StackFrameSP thread_cur_frame = thread.GetStackFrameAtIndex(0); ProcessSP process_sp(thread.CalculateProcess()); TargetSP target_sp(thread.CalculateTarget()); - TypeSystemClang *clang_ast_context = TypeSystemClang::GetScratch(*target_sp); + TypeSystemClang *clang_ast_context = + ScratchTypeSystemClang::GetForTarget(*target_sp); Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_SYSTEM_RUNTIME)); GetItemInfoReturnInfo return_value; @@ -268,26 +258,26 @@ AppleGetItemInfoHandler::GetItemInfo(Thread &thread, uint64_t item, CompilerType clang_void_ptr_type = clang_ast_context->GetBasicType(eBasicTypeVoid).GetPointerType(); Value return_buffer_ptr_value; - return_buffer_ptr_value.SetValueType(Value::eValueTypeScalar); + return_buffer_ptr_value.SetValueType(Value::ValueType::Scalar); return_buffer_ptr_value.SetCompilerType(clang_void_ptr_type); CompilerType clang_int_type = clang_ast_context->GetBasicType(eBasicTypeInt); Value debug_value; - debug_value.SetValueType(Value::eValueTypeScalar); + debug_value.SetValueType(Value::ValueType::Scalar); debug_value.SetCompilerType(clang_int_type); CompilerType clang_uint64_type = clang_ast_context->GetBasicType(eBasicTypeUnsignedLongLong); Value item_value; - item_value.SetValueType(Value::eValueTypeScalar); + item_value.SetValueType(Value::ValueType::Scalar); item_value.SetCompilerType(clang_uint64_type); Value page_to_free_value; - page_to_free_value.SetValueType(Value::eValueTypeScalar); + page_to_free_value.SetValueType(Value::ValueType::Scalar); page_to_free_value.SetCompilerType(clang_void_ptr_type); Value page_to_free_size_value; - page_to_free_size_value.SetValueType(Value::eValueTypeScalar); + page_to_free_size_value.SetValueType(Value::ValueType::Scalar); page_to_free_size_value.SetCompilerType(clang_uint64_type); std::lock_guard guard(m_get_item_info_retbuffer_mutex); diff --git a/gnu/llvm/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetItemInfoHandler.h b/gnu/llvm/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetItemInfoHandler.h index f1119a9562e..04cfbaea421 100644 --- a/gnu/llvm/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetItemInfoHandler.h +++ b/gnu/llvm/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetItemInfoHandler.h @@ -46,13 +46,12 @@ public: ~AppleGetItemInfoHandler(); struct GetItemInfoReturnInfo { - lldb::addr_t item_buffer_ptr; /* the address of the item buffer from - libBacktraceRecording */ - lldb::addr_t item_buffer_size; /* the size of the item buffer from + lldb::addr_t item_buffer_ptr = LLDB_INVALID_ADDRESS; /* the address of the + item buffer from libBacktraceRecording */ + lldb::addr_t item_buffer_size = 0; /* the size of the item buffer from libBacktraceRecording */ - GetItemInfoReturnInfo() - : item_buffer_ptr(LLDB_INVALID_ADDRESS), item_buffer_size(0) {} + GetItemInfoReturnInfo() = default; }; /// Get the information about a work item by calling diff --git a/gnu/llvm/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetPendingItemsHandler.cpp b/gnu/llvm/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetPendingItemsHandler.cpp index ff57aa2afc9..82b71b8ab3b 100644 --- a/gnu/llvm/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetPendingItemsHandler.cpp +++ b/gnu/llvm/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetPendingItemsHandler.cpp @@ -102,7 +102,7 @@ AppleGetPendingItemsHandler::AppleGetPendingItemsHandler(Process *process) m_get_pending_items_return_buffer_addr(LLDB_INVALID_ADDRESS), m_get_pending_items_retbuffer_mutex() {} -AppleGetPendingItemsHandler::~AppleGetPendingItemsHandler() {} +AppleGetPendingItemsHandler::~AppleGetPendingItemsHandler() = default; void AppleGetPendingItemsHandler::Detach() { if (m_process && m_process->IsAlive() && @@ -146,27 +146,16 @@ lldb::addr_t AppleGetPendingItemsHandler::SetupGetPendingItemsFunction( if (!m_get_pending_items_impl_code) { if (g_get_pending_items_function_code != nullptr) { - Status error; - m_get_pending_items_impl_code.reset( - exe_ctx.GetTargetRef().GetUtilityFunctionForLanguage( - g_get_pending_items_function_code, eLanguageTypeObjC, - g_get_pending_items_function_name, error)); - if (error.Fail()) { - LLDB_LOGF(log, - "Failed to get UtilityFunction for pending-items " - "introspection: %s.", - error.AsCString()); - return args_addr; - } - - if (!m_get_pending_items_impl_code->Install(diagnostics, exe_ctx)) { - if (log) { - LLDB_LOGF(log, "Failed to install pending-items introspection."); - diagnostics.Dump(log); - } - m_get_pending_items_impl_code.reset(); + auto utility_fn_or_error = exe_ctx.GetTargetRef().CreateUtilityFunction( + g_get_pending_items_function_code, + g_get_pending_items_function_name, eLanguageTypeC, exe_ctx); + if (!utility_fn_or_error) { + LLDB_LOG_ERROR(log, utility_fn_or_error.takeError(), + "Failed to create UtilityFunction for pending-items " + "introspection: {0}."); return args_addr; } + m_get_pending_items_impl_code = std::move(*utility_fn_or_error); } else { LLDB_LOGF(log, "No pending-items introspection code found."); return LLDB_INVALID_ADDRESS; @@ -174,8 +163,8 @@ lldb::addr_t AppleGetPendingItemsHandler::SetupGetPendingItemsFunction( // Next make the runner function for our implementation utility function. Status error; - TypeSystemClang *clang_ast_context = - TypeSystemClang::GetScratch(thread.GetProcess()->GetTarget()); + TypeSystemClang *clang_ast_context = ScratchTypeSystemClang::GetForTarget( + thread.GetProcess()->GetTarget()); CompilerType get_pending_items_return_type = clang_ast_context->GetBasicType(eBasicTypeVoid).GetPointerType(); get_pending_items_caller = @@ -226,7 +215,8 @@ AppleGetPendingItemsHandler::GetPendingItems(Thread &thread, addr_t queue, lldb::StackFrameSP thread_cur_frame = thread.GetStackFrameAtIndex(0); ProcessSP process_sp(thread.CalculateProcess()); TargetSP target_sp(thread.CalculateTarget()); - TypeSystemClang *clang_ast_context = TypeSystemClang::GetScratch(*target_sp); + TypeSystemClang *clang_ast_context = + ScratchTypeSystemClang::GetForTarget(*target_sp); Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_SYSTEM_RUNTIME)); GetPendingItemsReturnInfo return_value; @@ -271,26 +261,26 @@ AppleGetPendingItemsHandler::GetPendingItems(Thread &thread, addr_t queue, CompilerType clang_void_ptr_type = clang_ast_context->GetBasicType(eBasicTypeVoid).GetPointerType(); Value return_buffer_ptr_value; - return_buffer_ptr_value.SetValueType(Value::eValueTypeScalar); + return_buffer_ptr_value.SetValueType(Value::ValueType::Scalar); return_buffer_ptr_value.SetCompilerType(clang_void_ptr_type); CompilerType clang_int_type = clang_ast_context->GetBasicType(eBasicTypeInt); Value debug_value; - debug_value.SetValueType(Value::eValueTypeScalar); + debug_value.SetValueType(Value::ValueType::Scalar); debug_value.SetCompilerType(clang_int_type); CompilerType clang_uint64_type = clang_ast_context->GetBasicType(eBasicTypeUnsignedLongLong); Value queue_value; - queue_value.SetValueType(Value::eValueTypeScalar); + queue_value.SetValueType(Value::ValueType::Scalar); queue_value.SetCompilerType(clang_uint64_type); Value page_to_free_value; - page_to_free_value.SetValueType(Value::eValueTypeScalar); + page_to_free_value.SetValueType(Value::ValueType::Scalar); page_to_free_value.SetCompilerType(clang_void_ptr_type); Value page_to_free_size_value; - page_to_free_size_value.SetValueType(Value::eValueTypeScalar); + page_to_free_size_value.SetValueType(Value::ValueType::Scalar); page_to_free_size_value.SetCompilerType(clang_uint64_type); std::lock_guard guard(m_get_pending_items_retbuffer_mutex); diff --git a/gnu/llvm/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetPendingItemsHandler.h b/gnu/llvm/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetPendingItemsHandler.h index 20895ca146c..fe025268a0d 100644 --- a/gnu/llvm/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetPendingItemsHandler.h +++ b/gnu/llvm/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetPendingItemsHandler.h @@ -48,16 +48,14 @@ public: ~AppleGetPendingItemsHandler(); struct GetPendingItemsReturnInfo { - lldb::addr_t items_buffer_ptr; /* the address of the pending items buffer - from libBacktraceRecording */ - lldb::addr_t - items_buffer_size; /* the size of the pending items buffer from - libBacktraceRecording */ - uint64_t count; /* the number of pending items included in the buffer */ - - GetPendingItemsReturnInfo() - : items_buffer_ptr(LLDB_INVALID_ADDRESS), items_buffer_size(0), - count(0) {} + lldb::addr_t items_buffer_ptr = + LLDB_INVALID_ADDRESS; /* the address of the pending items buffer + from libBacktraceRecording */ + lldb::addr_t items_buffer_size = 0; /* the size of the pending items buffer + from libBacktraceRecording */ + uint64_t count = 0; /* the number of pending items included in the buffer */ + + GetPendingItemsReturnInfo() = default; }; /// Get the list of pending items for a given queue via a call to diff --git a/gnu/llvm/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetQueuesHandler.cpp b/gnu/llvm/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetQueuesHandler.cpp index 632f18d6ea8..f471871dde2 100644 --- a/gnu/llvm/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetQueuesHandler.cpp +++ b/gnu/llvm/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetQueuesHandler.cpp @@ -99,7 +99,7 @@ AppleGetQueuesHandler::AppleGetQueuesHandler(Process *process) m_get_queues_return_buffer_addr(LLDB_INVALID_ADDRESS), m_get_queues_retbuffer_mutex() {} -AppleGetQueuesHandler::~AppleGetQueuesHandler() {} +AppleGetQueuesHandler::~AppleGetQueuesHandler() = default; void AppleGetQueuesHandler::Detach() { @@ -159,27 +159,16 @@ AppleGetQueuesHandler::SetupGetQueuesFunction(Thread &thread, if (!m_get_queues_impl_code_up) { if (g_get_current_queues_function_code != nullptr) { - Status error; - m_get_queues_impl_code_up.reset( - exe_ctx.GetTargetRef().GetUtilityFunctionForLanguage( - g_get_current_queues_function_code, eLanguageTypeC, - g_get_current_queues_function_name, error)); - if (error.Fail()) { - LLDB_LOGF( - log, - "Failed to get UtilityFunction for queues introspection: %s.", - error.AsCString()); - return args_addr; - } - - if (!m_get_queues_impl_code_up->Install(diagnostics, exe_ctx)) { - if (log) { - LLDB_LOGF(log, "Failed to install queues introspection"); - diagnostics.Dump(log); - } - m_get_queues_impl_code_up.reset(); + auto utility_fn_or_error = exe_ctx.GetTargetRef().CreateUtilityFunction( + g_get_current_queues_function_code, + g_get_current_queues_function_name, eLanguageTypeC, exe_ctx); + if (!utility_fn_or_error) { + LLDB_LOG_ERROR(log, utility_fn_or_error.takeError(), + "Failed to create UtilityFunction for queues " + "introspection: {0}."); return args_addr; } + m_get_queues_impl_code_up = std::move(*utility_fn_or_error); } else { if (log) { LLDB_LOGF(log, "No queues introspection code found."); @@ -191,7 +180,7 @@ AppleGetQueuesHandler::SetupGetQueuesFunction(Thread &thread, // Next make the runner function for our implementation utility function. TypeSystemClang *clang_ast_context = - TypeSystemClang::GetScratch(thread.GetProcess()->GetTarget()); + ScratchTypeSystemClang::GetForTarget(thread.GetProcess()->GetTarget()); CompilerType get_queues_return_type = clang_ast_context->GetBasicType(eBasicTypeVoid).GetPointerType(); Status error; @@ -231,7 +220,8 @@ AppleGetQueuesHandler::GetCurrentQueues(Thread &thread, addr_t page_to_free, lldb::StackFrameSP thread_cur_frame = thread.GetStackFrameAtIndex(0); ProcessSP process_sp(thread.CalculateProcess()); TargetSP target_sp(thread.CalculateTarget()); - TypeSystemClang *clang_ast_context = TypeSystemClang::GetScratch(*target_sp); + TypeSystemClang *clang_ast_context = + ScratchTypeSystemClang::GetForTarget(*target_sp); Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_SYSTEM_RUNTIME)); GetQueuesReturnInfo return_value; @@ -274,22 +264,22 @@ AppleGetQueuesHandler::GetCurrentQueues(Thread &thread, addr_t page_to_free, CompilerType clang_void_ptr_type = clang_ast_context->GetBasicType(eBasicTypeVoid).GetPointerType(); Value return_buffer_ptr_value; - return_buffer_ptr_value.SetValueType(Value::eValueTypeScalar); + return_buffer_ptr_value.SetValueType(Value::ValueType::Scalar); return_buffer_ptr_value.SetCompilerType(clang_void_ptr_type); CompilerType clang_int_type = clang_ast_context->GetBasicType(eBasicTypeInt); Value debug_value; - debug_value.SetValueType(Value::eValueTypeScalar); + debug_value.SetValueType(Value::ValueType::Scalar); debug_value.SetCompilerType(clang_int_type); Value page_to_free_value; - page_to_free_value.SetValueType(Value::eValueTypeScalar); + page_to_free_value.SetValueType(Value::ValueType::Scalar); page_to_free_value.SetCompilerType(clang_void_ptr_type); CompilerType clang_uint64_type = clang_ast_context->GetBasicType(eBasicTypeUnsignedLongLong); Value page_to_free_size_value; - page_to_free_size_value.SetValueType(Value::eValueTypeScalar); + page_to_free_size_value.SetValueType(Value::ValueType::Scalar); page_to_free_size_value.SetCompilerType(clang_uint64_type); std::lock_guard guard(m_get_queues_retbuffer_mutex); diff --git a/gnu/llvm/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetQueuesHandler.h b/gnu/llvm/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetQueuesHandler.h index 0c828d782a1..b33e6186146 100644 --- a/gnu/llvm/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetQueuesHandler.h +++ b/gnu/llvm/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetQueuesHandler.h @@ -45,15 +45,14 @@ public: ~AppleGetQueuesHandler(); struct GetQueuesReturnInfo { - lldb::addr_t queues_buffer_ptr; /* the address of the queues buffer from + lldb::addr_t queues_buffer_ptr = + LLDB_INVALID_ADDRESS; /* the address of the queues buffer from + libBacktraceRecording */ + lldb::addr_t queues_buffer_size = 0; /* the size of the queues buffer from libBacktraceRecording */ - lldb::addr_t queues_buffer_size; /* the size of the queues buffer from - libBacktraceRecording */ - uint64_t count; /* the number of queues included in the queues buffer */ + uint64_t count = 0; /* the number of queues included in the queues buffer */ - GetQueuesReturnInfo() - : queues_buffer_ptr(LLDB_INVALID_ADDRESS), queues_buffer_size(0), - count(0) {} + GetQueuesReturnInfo() = default; }; /// Get the list of queues that exist (with any active or pending items) via diff --git a/gnu/llvm/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetThreadItemInfoHandler.cpp b/gnu/llvm/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetThreadItemInfoHandler.cpp index 6bfdbaca27d..7837dca147d 100644 --- a/gnu/llvm/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetThreadItemInfoHandler.cpp +++ b/gnu/llvm/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetThreadItemInfoHandler.cpp @@ -107,7 +107,7 @@ AppleGetThreadItemInfoHandler::AppleGetThreadItemInfoHandler(Process *process) m_get_thread_item_info_return_buffer_addr(LLDB_INVALID_ADDRESS), m_get_thread_item_info_retbuffer_mutex() {} -AppleGetThreadItemInfoHandler::~AppleGetThreadItemInfoHandler() {} +AppleGetThreadItemInfoHandler::~AppleGetThreadItemInfoHandler() = default; void AppleGetThreadItemInfoHandler::Detach() { @@ -153,29 +153,16 @@ lldb::addr_t AppleGetThreadItemInfoHandler::SetupGetThreadItemInfoFunction( if (!m_get_thread_item_info_impl_code) { Status error; if (g_get_thread_item_info_function_code != nullptr) { - m_get_thread_item_info_impl_code.reset( - exe_ctx.GetTargetRef().GetUtilityFunctionForLanguage( - g_get_thread_item_info_function_code, eLanguageTypeC, - g_get_thread_item_info_function_name, error)); - if (error.Fail()) { - LLDB_LOGF(log, - "Failed to get UtilityFunction for " - "get-thread-item-info introspection: %s.", - error.AsCString()); - m_get_thread_item_info_impl_code.reset(); - return args_addr; - } - - if (!m_get_thread_item_info_impl_code->Install(diagnostics, exe_ctx)) { - if (log) { - LLDB_LOGF(log, - "Failed to install get-thread-item-info introspection."); - diagnostics.Dump(log); - } - - m_get_thread_item_info_impl_code.reset(); + auto utility_fn_or_error = exe_ctx.GetTargetRef().CreateUtilityFunction( + g_get_thread_item_info_function_code, + g_get_thread_item_info_function_name, eLanguageTypeC, exe_ctx); + if (!utility_fn_or_error) { + LLDB_LOG_ERROR(log, utility_fn_or_error.takeError(), + "Failed to get UtilityFunction for " + "get-thread-item-info introspection: {0}."); return args_addr; } + m_get_thread_item_info_impl_code = std::move(*utility_fn_or_error); } else { LLDB_LOGF(log, "No get-thread-item-info introspection code found."); return LLDB_INVALID_ADDRESS; @@ -183,8 +170,8 @@ lldb::addr_t AppleGetThreadItemInfoHandler::SetupGetThreadItemInfoFunction( // Also make the FunctionCaller for this UtilityFunction: - TypeSystemClang *clang_ast_context = - TypeSystemClang::GetScratch(thread.GetProcess()->GetTarget()); + TypeSystemClang *clang_ast_context = ScratchTypeSystemClang::GetForTarget( + thread.GetProcess()->GetTarget()); CompilerType get_thread_item_info_return_type = clang_ast_context->GetBasicType(eBasicTypeVoid).GetPointerType(); @@ -235,7 +222,8 @@ AppleGetThreadItemInfoHandler::GetThreadItemInfo(Thread &thread, lldb::StackFrameSP thread_cur_frame = thread.GetStackFrameAtIndex(0); ProcessSP process_sp(thread.CalculateProcess()); TargetSP target_sp(thread.CalculateTarget()); - TypeSystemClang *clang_ast_context = TypeSystemClang::GetScratch(*target_sp); + TypeSystemClang *clang_ast_context = + ScratchTypeSystemClang::GetForTarget(*target_sp); Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_SYSTEM_RUNTIME)); GetThreadItemInfoReturnInfo return_value; @@ -274,26 +262,26 @@ AppleGetThreadItemInfoHandler::GetThreadItemInfo(Thread &thread, CompilerType clang_void_ptr_type = clang_ast_context->GetBasicType(eBasicTypeVoid).GetPointerType(); Value return_buffer_ptr_value; - return_buffer_ptr_value.SetValueType(Value::eValueTypeScalar); + return_buffer_ptr_value.SetValueType(Value::ValueType::Scalar); return_buffer_ptr_value.SetCompilerType(clang_void_ptr_type); CompilerType clang_int_type = clang_ast_context->GetBasicType(eBasicTypeInt); Value debug_value; - debug_value.SetValueType(Value::eValueTypeScalar); + debug_value.SetValueType(Value::ValueType::Scalar); debug_value.SetCompilerType(clang_int_type); CompilerType clang_uint64_type = clang_ast_context->GetBasicType(eBasicTypeUnsignedLongLong); Value thread_id_value; - thread_id_value.SetValueType(Value::eValueTypeScalar); + thread_id_value.SetValueType(Value::ValueType::Scalar); thread_id_value.SetCompilerType(clang_uint64_type); Value page_to_free_value; - page_to_free_value.SetValueType(Value::eValueTypeScalar); + page_to_free_value.SetValueType(Value::ValueType::Scalar); page_to_free_value.SetCompilerType(clang_void_ptr_type); Value page_to_free_size_value; - page_to_free_size_value.SetValueType(Value::eValueTypeScalar); + page_to_free_size_value.SetValueType(Value::ValueType::Scalar); page_to_free_size_value.SetCompilerType(clang_uint64_type); std::lock_guard guard(m_get_thread_item_info_retbuffer_mutex); diff --git a/gnu/llvm/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetThreadItemInfoHandler.h b/gnu/llvm/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetThreadItemInfoHandler.h index 0f7201a0e81..9b2005f2b90 100644 --- a/gnu/llvm/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetThreadItemInfoHandler.h +++ b/gnu/llvm/lldb/source/Plugins/SystemRuntime/MacOSX/AppleGetThreadItemInfoHandler.h @@ -47,13 +47,12 @@ public: ~AppleGetThreadItemInfoHandler(); struct GetThreadItemInfoReturnInfo { - lldb::addr_t item_buffer_ptr; /* the address of the item buffer from - libBacktraceRecording */ - lldb::addr_t item_buffer_size; /* the size of the item buffer from + lldb::addr_t item_buffer_ptr = LLDB_INVALID_ADDRESS; /* the address of the + item buffer from libBacktraceRecording */ + lldb::addr_t item_buffer_size = 0; /* the size of the item buffer from libBacktraceRecording */ - GetThreadItemInfoReturnInfo() - : item_buffer_ptr(LLDB_INVALID_ADDRESS), item_buffer_size(0) {} + GetThreadItemInfoReturnInfo() = default; }; /// Get the information about a work item by calling diff --git a/gnu/llvm/lldb/source/Plugins/SystemRuntime/MacOSX/SystemRuntimeMacOSX.cpp b/gnu/llvm/lldb/source/Plugins/SystemRuntime/MacOSX/SystemRuntimeMacOSX.cpp index 33b1ed115e9..31c2a583db8 100644 --- a/gnu/llvm/lldb/source/Plugins/SystemRuntime/MacOSX/SystemRuntimeMacOSX.cpp +++ b/gnu/llvm/lldb/source/Plugins/SystemRuntime/MacOSX/SystemRuntimeMacOSX.cpp @@ -414,7 +414,7 @@ void SystemRuntimeMacOSX::ReadLibdispatchTSDIndexes() { #endif TypeSystemClang *ast_ctx = - TypeSystemClang::GetScratch(m_process->GetTarget()); + ScratchTypeSystemClang::GetForTarget(m_process->GetTarget()); if (m_dispatch_tsd_indexes_addr != LLDB_INVALID_ADDRESS) { CompilerType uint16 = ast_ctx->GetBuiltinTypeForEncodingAndBitSize(eEncodingUint, 16); diff --git a/gnu/llvm/lldb/source/Plugins/SystemRuntime/MacOSX/SystemRuntimeMacOSX.h b/gnu/llvm/lldb/source/Plugins/SystemRuntime/MacOSX/SystemRuntimeMacOSX.h index 844682e53ad..877a2ad2b5c 100644 --- a/gnu/llvm/lldb/source/Plugins/SystemRuntime/MacOSX/SystemRuntimeMacOSX.h +++ b/gnu/llvm/lldb/source/Plugins/SystemRuntime/MacOSX/SystemRuntimeMacOSX.h @@ -108,14 +108,12 @@ protected: private: struct libBacktraceRecording_info { - uint16_t queue_info_version; - uint16_t queue_info_data_offset; - uint16_t item_info_version; - uint16_t item_info_data_offset; - - libBacktraceRecording_info() - : queue_info_version(0), queue_info_data_offset(0), - item_info_version(0), item_info_data_offset(0) {} + uint16_t queue_info_version = 0; + uint16_t queue_info_data_offset = 0; + uint16_t item_info_version = 0; + uint16_t item_info_data_offset = 0; + + libBacktraceRecording_info() = default; }; // A structure which reflects the data recorded in the @@ -186,44 +184,35 @@ private: }; struct LibdispatchVoucherOffsets { - uint16_t vo_version; - uint16_t vo_activity_ids_count; - uint16_t vo_activity_ids_count_size; - uint16_t vo_activity_ids_array; - uint16_t vo_activity_ids_array_entry_size; - - LibdispatchVoucherOffsets() - : vo_version(UINT16_MAX), vo_activity_ids_count(UINT16_MAX), - vo_activity_ids_count_size(UINT16_MAX), - vo_activity_ids_array(UINT16_MAX), - vo_activity_ids_array_entry_size(UINT16_MAX) {} + uint16_t vo_version = UINT16_MAX; + uint16_t vo_activity_ids_count = UINT16_MAX; + uint16_t vo_activity_ids_count_size = UINT16_MAX; + uint16_t vo_activity_ids_array = UINT16_MAX; + uint16_t vo_activity_ids_array_entry_size = UINT16_MAX; + + LibdispatchVoucherOffsets() = default; bool IsValid() { return vo_version != UINT16_MAX; } }; struct LibdispatchTSDIndexes { - uint16_t dti_version; - uint64_t dti_queue_index; - uint64_t dti_voucher_index; - uint64_t dti_qos_class_index; + uint16_t dti_version = UINT16_MAX; + uint64_t dti_queue_index = UINT64_MAX; + uint64_t dti_voucher_index = UINT64_MAX; + uint64_t dti_qos_class_index = UINT64_MAX; - LibdispatchTSDIndexes() - : dti_version(UINT16_MAX), dti_queue_index(UINT64_MAX), - dti_voucher_index(UINT64_MAX), dti_qos_class_index(UINT64_MAX) {} + LibdispatchTSDIndexes() = default; bool IsValid() { return dti_version != UINT16_MAX; } }; struct LibpthreadOffsets { - uint16_t plo_version; - uint16_t plo_pthread_tsd_base_offset; - uint16_t plo_pthread_tsd_base_address_offset; - uint16_t plo_pthread_tsd_entry_size; - - LibpthreadOffsets() - : plo_version(UINT16_MAX), plo_pthread_tsd_base_offset(UINT16_MAX), - plo_pthread_tsd_base_address_offset(UINT16_MAX), - plo_pthread_tsd_entry_size(UINT16_MAX) {} + uint16_t plo_version = UINT16_MAX; + uint16_t plo_pthread_tsd_base_offset = UINT16_MAX; + uint16_t plo_pthread_tsd_base_address_offset = UINT16_MAX; + uint16_t plo_pthread_tsd_entry_size = UINT16_MAX; + + LibpthreadOffsets() = default; bool IsValid() { return plo_version != UINT16_MAX; } }; diff --git a/gnu/llvm/lldb/source/Plugins/Trace/CMakeLists.txt b/gnu/llvm/lldb/source/Plugins/Trace/CMakeLists.txt new file mode 100644 index 00000000000..955f88cec34 --- /dev/null +++ b/gnu/llvm/lldb/source/Plugins/Trace/CMakeLists.txt @@ -0,0 +1,7 @@ +option(LLDB_BUILD_INTEL_PT "Enable Building of Intel(R) Processor Trace Tool" OFF) + +add_subdirectory(common) + +if (LLDB_BUILD_INTEL_PT) + add_subdirectory(intel-pt) +endif() diff --git a/gnu/llvm/lldb/source/Plugins/Trace/common/CMakeLists.txt b/gnu/llvm/lldb/source/Plugins/Trace/common/CMakeLists.txt new file mode 100644 index 00000000000..604ddb6233d --- /dev/null +++ b/gnu/llvm/lldb/source/Plugins/Trace/common/CMakeLists.txt @@ -0,0 +1,8 @@ +add_lldb_library(lldbPluginTraceCommon + ThreadPostMortemTrace.cpp + TraceSessionFileParser.cpp + + LINK_LIBS + lldbCore + lldbTarget + ) diff --git a/gnu/llvm/lldb/source/Plugins/Trace/common/ThreadPostMortemTrace.cpp b/gnu/llvm/lldb/source/Plugins/Trace/common/ThreadPostMortemTrace.cpp new file mode 100644 index 00000000000..45d6f3b0e09 --- /dev/null +++ b/gnu/llvm/lldb/source/Plugins/Trace/common/ThreadPostMortemTrace.cpp @@ -0,0 +1,41 @@ +//===-- ThreadPostMortemTrace.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 "ThreadPostMortemTrace.h" + +#include + +#include "Plugins/Process/Utility/RegisterContextHistory.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/RegisterContext.h" + +using namespace lldb; +using namespace lldb_private; + +void ThreadPostMortemTrace::RefreshStateAfterStop() {} + +RegisterContextSP ThreadPostMortemTrace::GetRegisterContext() { + if (!m_reg_context_sp) + m_reg_context_sp = CreateRegisterContextForFrame(nullptr); + + return m_reg_context_sp; +} + +RegisterContextSP +ThreadPostMortemTrace::CreateRegisterContextForFrame(StackFrame *frame) { + // Eventually this will calculate the register context based on the current + // trace position. + return std::make_shared( + *this, 0, GetProcess()->GetAddressByteSize(), LLDB_INVALID_ADDRESS); +} + +bool ThreadPostMortemTrace::CalculateStopInfo() { return false; } + +const FileSpec &ThreadPostMortemTrace::GetTraceFile() const { + return m_trace_file; +} diff --git a/gnu/llvm/lldb/source/Plugins/Trace/common/ThreadPostMortemTrace.h b/gnu/llvm/lldb/source/Plugins/Trace/common/ThreadPostMortemTrace.h new file mode 100644 index 00000000000..9cfe754ae0e --- /dev/null +++ b/gnu/llvm/lldb/source/Plugins/Trace/common/ThreadPostMortemTrace.h @@ -0,0 +1,60 @@ +//===-- ThreadPostMortemTrace.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_TARGET_THREADPOSTMORTEMTRACE_H +#define LLDB_TARGET_THREADPOSTMORTEMTRACE_H + +#include "lldb/Target/Thread.h" + +namespace lldb_private { + +/// \class ThreadPostMortemTrace ThreadPostMortemTrace.h +/// +/// Thread implementation used for representing threads gotten from trace +/// session files, which are similar to threads from core files. +/// +/// See \a TraceSessionFileParser for more information regarding trace session +/// files. +class ThreadPostMortemTrace : public Thread { +public: + /// \param[in] process + /// The process who owns this thread. + /// + /// \param[in] tid + /// The tid of this thread. + /// + /// \param[in] trace_file + /// The file that contains the list of instructions that were traced when + /// this thread was being executed. + ThreadPostMortemTrace(Process &process, lldb::tid_t tid, + const FileSpec &trace_file) + : Thread(process, tid), m_trace_file(trace_file) {} + + void RefreshStateAfterStop() override; + + lldb::RegisterContextSP GetRegisterContext() override; + + lldb::RegisterContextSP + CreateRegisterContextForFrame(StackFrame *frame) override; + + /// \return + /// The trace file of this thread. + const FileSpec &GetTraceFile() const; + +protected: + bool CalculateStopInfo() override; + + lldb::RegisterContextSP m_thread_reg_ctx_sp; + +private: + FileSpec m_trace_file; +}; + +} // namespace lldb_private + +#endif // LLDB_TARGET_THREADPOSTMORTEMTRACE_H diff --git a/gnu/llvm/lldb/source/Plugins/Trace/common/TraceSessionFileParser.cpp b/gnu/llvm/lldb/source/Plugins/Trace/common/TraceSessionFileParser.cpp new file mode 100644 index 00000000000..c88ad9dc6a5 --- /dev/null +++ b/gnu/llvm/lldb/source/Plugins/Trace/common/TraceSessionFileParser.cpp @@ -0,0 +1,224 @@ +//===-- TraceSessionFileParser.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 "TraceSessionFileParser.h" +#include "ThreadPostMortemTrace.h" + +#include + +#include "lldb/Core/Debugger.h" +#include "lldb/Core/Module.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/Target.h" + +using namespace lldb; +using namespace lldb_private; +using namespace llvm; + +void TraceSessionFileParser::NormalizePath(lldb_private::FileSpec &file_spec) { + if (file_spec.IsRelative()) + file_spec.PrependPathComponent(m_session_file_dir); +} + +Error TraceSessionFileParser::ParseModule(lldb::TargetSP &target_sp, + const JSONModule &module) { + FileSpec system_file_spec(module.system_path); + NormalizePath(system_file_spec); + + FileSpec local_file_spec(module.file.hasValue() ? *module.file + : module.system_path); + NormalizePath(local_file_spec); + + ModuleSpec module_spec; + module_spec.GetFileSpec() = local_file_spec; + module_spec.GetPlatformFileSpec() = system_file_spec; + + if (module.uuid.hasValue()) + module_spec.GetUUID().SetFromStringRef(*module.uuid); + + Status error; + ModuleSP module_sp = + target_sp->GetOrCreateModule(module_spec, /*notify*/ false, &error); + + if (error.Fail()) + return error.ToError(); + + bool load_addr_changed = false; + module_sp->SetLoadAddress(*target_sp, module.load_address.value, false, + load_addr_changed); + return llvm::Error::success(); +} + +Error TraceSessionFileParser::CreateJSONError(json::Path::Root &root, + const json::Value &value) { + std::string err; + raw_string_ostream os(err); + root.printErrorContext(value, os); + return createStringError( + std::errc::invalid_argument, "%s\n\nContext:\n%s\n\nSchema:\n%s", + toString(root.getError()).c_str(), os.str().c_str(), m_schema.data()); +} + +std::string TraceSessionFileParser::BuildSchema(StringRef plugin_schema) { + std::ostringstream schema_builder; + schema_builder << "{\n \"trace\": "; + schema_builder << plugin_schema.data() << ","; + schema_builder << R"( + "processes": [ + { + "pid": integer, + "triple": string, // llvm-triple + "threads": [ + { + "tid": integer, + "traceFile": string + } + ], + "modules": [ + { + "systemPath": string, // original path of the module at runtime + "file"?: string, // copy of the file if not available at "systemPath" + "loadAddress": string, // string address in hex or decimal form + "uuid"?: string, + } + ] + } + ] + // Notes: + // All paths are either absolute or relative to the session file. +} +)"; + return schema_builder.str(); +} + +ThreadPostMortemTraceSP +TraceSessionFileParser::ParseThread(ProcessSP &process_sp, + const JSONThread &thread) { + lldb::tid_t tid = static_cast(thread.tid); + + FileSpec trace_file(thread.trace_file); + NormalizePath(trace_file); + + ThreadPostMortemTraceSP thread_sp = + std::make_shared(*process_sp, tid, trace_file); + process_sp->GetThreadList().AddThread(thread_sp); + return thread_sp; +} + +Expected +TraceSessionFileParser::ParseProcess(const JSONProcess &process) { + TargetSP target_sp; + Status error = m_debugger.GetTargetList().CreateTarget( + m_debugger, /*user_exe_path*/ StringRef(), process.triple, + eLoadDependentsNo, + /*platform_options*/ nullptr, target_sp); + + if (!target_sp) + return error.ToError(); + + ParsedProcess parsed_process; + parsed_process.target_sp = target_sp; + + ProcessSP process_sp = target_sp->CreateProcess( + /*listener*/ nullptr, "trace", + /*crash_file*/ nullptr, + /*can_connect*/ false); + + process_sp->SetID(static_cast(process.pid)); + + for (const JSONThread &thread : process.threads) + parsed_process.threads.push_back(ParseThread(process_sp, thread)); + + for (const JSONModule &module : process.modules) + if (Error err = ParseModule(target_sp, module)) + return std::move(err); + + if (!process.threads.empty()) + process_sp->GetThreadList().SetSelectedThreadByIndexID(0); + + // We invoke DidAttach to create a correct stopped state for the process and + // its threads. + ArchSpec process_arch; + process_sp->DidAttach(process_arch); + + return parsed_process; +} + +Expected> +TraceSessionFileParser::ParseCommonSessionFile( + const JSONTraceSessionBase &session) { + std::vector parsed_processes; + + auto onError = [&]() { + // Delete all targets that were created so far in case of failures + for (ParsedProcess &parsed_process : parsed_processes) + m_debugger.GetTargetList().DeleteTarget(parsed_process.target_sp); + }; + + for (const JSONProcess &process : session.processes) { + if (Expected parsed_process = ParseProcess(process)) + parsed_processes.push_back(std::move(*parsed_process)); + else { + onError(); + return parsed_process.takeError(); + } + } + return parsed_processes; +} + +namespace llvm { +namespace json { + +bool fromJSON(const Value &value, TraceSessionFileParser::JSONAddress &address, + Path path) { + Optional s = value.getAsString(); + if (s.hasValue() && !s->getAsInteger(0, address.value)) + return true; + + path.report("expected numeric string"); + return false; +} + +bool fromJSON(const Value &value, TraceSessionFileParser::JSONModule &module, + Path path) { + ObjectMapper o(value, path); + return o && o.map("systemPath", module.system_path) && + o.map("file", module.file) && + o.map("loadAddress", module.load_address) && + o.map("uuid", module.uuid); +} + +bool fromJSON(const Value &value, TraceSessionFileParser::JSONThread &thread, + Path path) { + ObjectMapper o(value, path); + return o && o.map("tid", thread.tid) && o.map("traceFile", thread.trace_file); +} + +bool fromJSON(const Value &value, TraceSessionFileParser::JSONProcess &process, + Path path) { + ObjectMapper o(value, path); + return o && o.map("pid", process.pid) && o.map("triple", process.triple) && + o.map("threads", process.threads) && o.map("modules", process.modules); +} + +bool fromJSON(const Value &value, + TraceSessionFileParser::JSONTracePluginSettings &plugin_settings, + Path path) { + ObjectMapper o(value, path); + return o && o.map("type", plugin_settings.type); +} + +bool fromJSON(const Value &value, + TraceSessionFileParser::JSONTraceSessionBase &session, + Path path) { + ObjectMapper o(value, path); + return o && o.map("processes", session.processes); +} + +} // namespace json +} // namespace llvm diff --git a/gnu/llvm/lldb/source/Plugins/Trace/common/TraceSessionFileParser.h b/gnu/llvm/lldb/source/Plugins/Trace/common/TraceSessionFileParser.h new file mode 100644 index 00000000000..6abaffcecd3 --- /dev/null +++ b/gnu/llvm/lldb/source/Plugins/Trace/common/TraceSessionFileParser.h @@ -0,0 +1,179 @@ +//===-- TraceSessionFileParser.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_TARGET_TRACESESSIONPARSER_H +#define LLDB_TARGET_TRACESESSIONPARSER_H + +#include "llvm/Support/JSON.h" + +#include "ThreadPostMortemTrace.h" + +namespace lldb_private { + +/// \class TraceSessionFileParser TraceSessionFileParser.h +/// +/// Base class for parsing the common information of JSON trace session files. +/// Contains the basic C++ structs that represent the JSON data, which include +/// \a JSONTraceSession as the root object. +/// +/// See \a Trace::FindPlugin for more information regarding these JSON files. +class TraceSessionFileParser { +public: + /// C++ structs representing the JSON trace session. + /// \{ + struct JSONAddress { + lldb::addr_t value; + }; + + struct JSONModule { + std::string system_path; + llvm::Optional file; + JSONAddress load_address; + llvm::Optional uuid; + }; + + struct JSONThread { + int64_t tid; + std::string trace_file; + }; + + struct JSONProcess { + int64_t pid; + std::string triple; + std::vector threads; + std::vector modules; + }; + + struct JSONTracePluginSettings { + std::string type; + }; + + struct JSONTraceSessionBase { + std::vector processes; + }; + + /// The trace plug-in implementation should provide its own TPluginSettings, + /// which corresponds to the "trace" section of the schema. + template + struct JSONTraceSession : JSONTraceSessionBase { + TPluginSettings trace; + }; + /// \} + + /// Helper struct holding the objects created when parsing a process + struct ParsedProcess { + lldb::TargetSP target_sp; + std::vector threads; + }; + + TraceSessionFileParser(Debugger &debugger, llvm::StringRef session_file_dir, + llvm::StringRef schema) + : m_debugger(debugger), m_session_file_dir(session_file_dir), + m_schema(schema) {} + + /// Build the full schema for a Trace plug-in. + /// + /// \param[in] plugin_schema + /// The subschema that corresponds to the "trace" section of the schema. + /// + /// \return + /// The full schema containing the common attributes and the plug-in + /// specific attributes. + static std::string BuildSchema(llvm::StringRef plugin_schema); + + /// Parse the fields common to all trace session schemas. + /// + /// \param[in] session + /// The session json objects already deserialized. + /// + /// \return + /// A list of \a ParsedProcess containing all threads and targets created + /// during the parsing, or an error in case of failures. In case of + /// errors, no side effects are produced. + llvm::Expected> + ParseCommonSessionFile(const JSONTraceSessionBase &session); + +protected: + /// Resolve non-absolute paths relative to the session file folder. It + /// modifies the given file_spec. + void NormalizePath(lldb_private::FileSpec &file_spec); + + lldb::ThreadPostMortemTraceSP ParseThread(lldb::ProcessSP &process_sp, + const JSONThread &thread); + + llvm::Expected ParseProcess(const JSONProcess &process); + + llvm::Error ParseModule(lldb::TargetSP &target_sp, const JSONModule &module); + + /// Create a user-friendly error message upon a JSON-parsing failure using the + /// \a json::ObjectMapper functionality. + /// + /// \param[in] root + /// The \a llvm::json::Path::Root used to parse the JSON \a value. + /// + /// \param[in] value + /// The json value that failed to parse. + /// + /// \return + /// An \a llvm::Error containing the user-friendly error message. + llvm::Error CreateJSONError(llvm::json::Path::Root &root, + const llvm::json::Value &value); + + Debugger &m_debugger; + std::string m_session_file_dir; + llvm::StringRef m_schema; +}; +} // namespace lldb_private + +namespace llvm { +namespace json { + +bool fromJSON(const Value &value, + lldb_private::TraceSessionFileParser::JSONAddress &address, + Path path); + +bool fromJSON(const Value &value, + lldb_private::TraceSessionFileParser::JSONModule &module, + Path path); + +bool fromJSON(const Value &value, + lldb_private::TraceSessionFileParser::JSONThread &thread, + Path path); + +bool fromJSON(const Value &value, + lldb_private::TraceSessionFileParser::JSONProcess &process, + Path path); + +bool fromJSON(const Value &value, + lldb_private::TraceSessionFileParser::JSONTracePluginSettings + &plugin_settings, + Path path); + +bool fromJSON( + const Value &value, + lldb_private::TraceSessionFileParser::JSONTraceSessionBase &session, + Path path); + +template +bool fromJSON( + const Value &value, + lldb_private::TraceSessionFileParser::JSONTraceSession + &session, + Path path) { + ObjectMapper o(value, path); + return o && o.map("trace", session.trace) && + fromJSON(value, + (lldb_private::TraceSessionFileParser::JSONTraceSessionBase &) + session, + path); +} + +} // namespace json +} // namespace llvm + +#endif // LLDB_TARGET_TRACESESSIONPARSER_H diff --git a/gnu/llvm/lldb/source/Plugins/Trace/intel-pt/CMakeLists.txt b/gnu/llvm/lldb/source/Plugins/Trace/intel-pt/CMakeLists.txt new file mode 100644 index 00000000000..7ecc9b77780 --- /dev/null +++ b/gnu/llvm/lldb/source/Plugins/Trace/intel-pt/CMakeLists.txt @@ -0,0 +1,35 @@ +if (NOT LIBIPT_INCLUDE_PATH) + message (FATAL_ERROR "libipt include path not provided") +endif() + +if (NOT EXISTS "${LIBIPT_INCLUDE_PATH}") + message (FATAL_ERROR "invalid libipt include path provided") +endif() +include_directories(${LIBIPT_INCLUDE_PATH}) + +find_library(LIBIPT_LIBRARY ipt PATHS ${LIBIPT_LIBRARY_PATH} REQUIRED) + +lldb_tablegen(TraceIntelPTCommandOptions.inc -gen-lldb-option-defs + SOURCE TraceIntelPTOptions.td + TARGET TraceIntelPTOptionsGen) + +add_lldb_library(lldbPluginTraceIntelPT PLUGIN + CommandObjectTraceStartIntelPT.cpp + DecodedThread.cpp + IntelPTDecoder.cpp + TraceCursorIntelPT.cpp + TraceIntelPT.cpp + TraceIntelPTSessionFileParser.cpp + + LINK_LIBS + lldbCore + lldbSymbol + lldbTarget + lldbPluginTraceCommon + ${LIBIPT_LIBRARY} + LINK_COMPONENTS + Support + ) + + +add_dependencies(lldbPluginTraceIntelPT TraceIntelPTOptionsGen) diff --git a/gnu/llvm/lldb/source/Plugins/Trace/intel-pt/CommandObjectTraceStartIntelPT.cpp b/gnu/llvm/lldb/source/Plugins/Trace/intel-pt/CommandObjectTraceStartIntelPT.cpp new file mode 100644 index 00000000000..5650af657c5 --- /dev/null +++ b/gnu/llvm/lldb/source/Plugins/Trace/intel-pt/CommandObjectTraceStartIntelPT.cpp @@ -0,0 +1,164 @@ +//===-- CommandObjectTraceStartIntelPT.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 "CommandObjectTraceStartIntelPT.h" + +#include "TraceIntelPT.h" +#include "TraceIntelPTConstants.h" +#include "lldb/Host/OptionParser.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/Trace.h" + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::trace_intel_pt; +using namespace llvm; + +// CommandObjectThreadTraceStartIntelPT + +#define LLDB_OPTIONS_thread_trace_start_intel_pt +#include "TraceIntelPTCommandOptions.inc" + +Status CommandObjectThreadTraceStartIntelPT::CommandOptions::SetOptionValue( + uint32_t option_idx, llvm::StringRef option_arg, + ExecutionContext *execution_context) { + Status error; + const int short_option = m_getopt_table[option_idx].val; + + switch (short_option) { + case 's': { + int64_t thread_buffer_size; + if (option_arg.empty() || option_arg.getAsInteger(0, thread_buffer_size) || + thread_buffer_size < 0) + error.SetErrorStringWithFormat("invalid integer value for option '%s'", + option_arg.str().c_str()); + else + m_thread_buffer_size = thread_buffer_size; + break; + } + case 't': { + m_enable_tsc = true; + break; + } + case 'p': { + int64_t psb_period; + if (option_arg.empty() || option_arg.getAsInteger(0, psb_period) || + psb_period < 0) + error.SetErrorStringWithFormat("invalid integer value for option '%s'", + option_arg.str().c_str()); + else + m_psb_period = psb_period; + break; + } + default: + llvm_unreachable("Unimplemented option"); + } + return error; +} + +void CommandObjectThreadTraceStartIntelPT::CommandOptions:: + OptionParsingStarting(ExecutionContext *execution_context) { + m_thread_buffer_size = kDefaultThreadBufferSize; + m_enable_tsc = kDefaultEnableTscValue; + m_psb_period = kDefaultPsbPeriod; +} + +llvm::ArrayRef +CommandObjectThreadTraceStartIntelPT::CommandOptions::GetDefinitions() { + return llvm::makeArrayRef(g_thread_trace_start_intel_pt_options); +} + +bool CommandObjectThreadTraceStartIntelPT::DoExecuteOnThreads( + Args &command, CommandReturnObject &result, + llvm::ArrayRef tids) { + if (Error err = m_trace.Start(tids, m_options.m_thread_buffer_size, + m_options.m_enable_tsc, m_options.m_psb_period)) + result.SetError(Status(std::move(err))); + else + result.SetStatus(eReturnStatusSuccessFinishResult); + + return result.Succeeded(); +} + +/// CommandObjectProcessTraceStartIntelPT + +#define LLDB_OPTIONS_process_trace_start_intel_pt +#include "TraceIntelPTCommandOptions.inc" + +Status CommandObjectProcessTraceStartIntelPT::CommandOptions::SetOptionValue( + uint32_t option_idx, llvm::StringRef option_arg, + ExecutionContext *execution_context) { + Status error; + const int short_option = m_getopt_table[option_idx].val; + + switch (short_option) { + case 's': { + int64_t thread_buffer_size; + if (option_arg.empty() || option_arg.getAsInteger(0, thread_buffer_size) || + thread_buffer_size < 0) + error.SetErrorStringWithFormat("invalid integer value for option '%s'", + option_arg.str().c_str()); + else + m_thread_buffer_size = thread_buffer_size; + break; + } + case 'l': { + int64_t process_buffer_size_limit; + if (option_arg.empty() || + option_arg.getAsInteger(0, process_buffer_size_limit) || + process_buffer_size_limit < 0) + error.SetErrorStringWithFormat("invalid integer value for option '%s'", + option_arg.str().c_str()); + else + m_process_buffer_size_limit = process_buffer_size_limit; + break; + } + case 't': { + m_enable_tsc = true; + break; + } + case 'p': { + int64_t psb_period; + if (option_arg.empty() || option_arg.getAsInteger(0, psb_period) || + psb_period < 0) + error.SetErrorStringWithFormat("invalid integer value for option '%s'", + option_arg.str().c_str()); + else + m_psb_period = psb_period; + break; + } + default: + llvm_unreachable("Unimplemented option"); + } + return error; +} + +void CommandObjectProcessTraceStartIntelPT::CommandOptions:: + OptionParsingStarting(ExecutionContext *execution_context) { + m_thread_buffer_size = kDefaultThreadBufferSize; + m_process_buffer_size_limit = kDefaultProcessBufferSizeLimit; + m_enable_tsc = kDefaultEnableTscValue; + m_psb_period = kDefaultPsbPeriod; +} + +llvm::ArrayRef +CommandObjectProcessTraceStartIntelPT::CommandOptions::GetDefinitions() { + return llvm::makeArrayRef(g_process_trace_start_intel_pt_options); +} + +bool CommandObjectProcessTraceStartIntelPT::DoExecute( + Args &command, CommandReturnObject &result) { + if (Error err = m_trace.Start(m_options.m_thread_buffer_size, + m_options.m_process_buffer_size_limit, + m_options.m_enable_tsc, m_options.m_psb_period)) + result.SetError(Status(std::move(err))); + else + result.SetStatus(eReturnStatusSuccessFinishResult); + + return result.Succeeded(); +} diff --git a/gnu/llvm/lldb/source/Plugins/Trace/intel-pt/CommandObjectTraceStartIntelPT.h b/gnu/llvm/lldb/source/Plugins/Trace/intel-pt/CommandObjectTraceStartIntelPT.h new file mode 100644 index 00000000000..2f3d53a8640 --- /dev/null +++ b/gnu/llvm/lldb/source/Plugins/Trace/intel-pt/CommandObjectTraceStartIntelPT.h @@ -0,0 +1,110 @@ +//===-- CommandObjectTraceStartIntelPT.h ----------------------*- C++ //-*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_COMMANDOBJECTTRACESTARTINTELPT_H +#define LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_COMMANDOBJECTTRACESTARTINTELPT_H + +#include "../../../../source/Commands/CommandObjectTrace.h" +#include "TraceIntelPT.h" +#include "lldb/Interpreter/CommandInterpreter.h" +#include "lldb/Interpreter/CommandReturnObject.h" + +namespace lldb_private { +namespace trace_intel_pt { + +class CommandObjectThreadTraceStartIntelPT + : public CommandObjectMultipleThreads { +public: + class CommandOptions : public Options { + public: + CommandOptions() : Options() { OptionParsingStarting(nullptr); } + + Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, + ExecutionContext *execution_context) override; + + void OptionParsingStarting(ExecutionContext *execution_context) override; + + llvm::ArrayRef GetDefinitions() override; + + size_t m_thread_buffer_size; + bool m_enable_tsc; + llvm::Optional m_psb_period; + }; + + CommandObjectThreadTraceStartIntelPT(TraceIntelPT &trace, + CommandInterpreter &interpreter) + : CommandObjectMultipleThreads( + interpreter, "thread trace start", + "Start tracing one or more threads with intel-pt. " + "Defaults to the current thread. Thread indices can be " + "specified as arguments.\n Use the thread-index \"all\" to trace " + "all threads including future threads.", + "thread trace start [ ...] " + "[]", + lldb::eCommandRequiresProcess | lldb::eCommandTryTargetAPILock | + lldb::eCommandProcessMustBeLaunched | + lldb::eCommandProcessMustBePaused), + m_trace(trace), m_options() {} + + Options *GetOptions() override { return &m_options; } + +protected: + bool DoExecuteOnThreads(Args &command, CommandReturnObject &result, + llvm::ArrayRef tids) override; + + TraceIntelPT &m_trace; + CommandOptions m_options; +}; + +class CommandObjectProcessTraceStartIntelPT : public CommandObjectParsed { +public: + class CommandOptions : public Options { + public: + CommandOptions() : Options() { OptionParsingStarting(nullptr); } + + Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, + ExecutionContext *execution_context) override; + + void OptionParsingStarting(ExecutionContext *execution_context) override; + + llvm::ArrayRef GetDefinitions() override; + + size_t m_thread_buffer_size; + size_t m_process_buffer_size_limit; + bool m_enable_tsc; + llvm::Optional m_psb_period; + }; + + CommandObjectProcessTraceStartIntelPT(TraceIntelPT &trace, + CommandInterpreter &interpreter) + : CommandObjectParsed( + interpreter, "process trace start", + "Start tracing this process with intel-pt, including future " + "threads. " + "This is implemented by tracing each thread independently. " + "Threads traced with the \"thread trace start\" command are left " + "unaffected ant not retraced.", + "process trace start []", + lldb::eCommandRequiresProcess | lldb::eCommandTryTargetAPILock | + lldb::eCommandProcessMustBeLaunched | + lldb::eCommandProcessMustBePaused), + m_trace(trace), m_options() {} + + Options *GetOptions() override { return &m_options; } + +protected: + bool DoExecute(Args &command, CommandReturnObject &result) override; + + TraceIntelPT &m_trace; + CommandOptions m_options; +}; + +} // namespace trace_intel_pt +} // namespace lldb_private + +#endif // LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_COMMANDOBJECTTRACESTARTINTELPT_H diff --git a/gnu/llvm/lldb/source/Plugins/Trace/intel-pt/DecodedThread.cpp b/gnu/llvm/lldb/source/Plugins/Trace/intel-pt/DecodedThread.cpp new file mode 100644 index 00000000000..4822a786c68 --- /dev/null +++ b/gnu/llvm/lldb/source/Plugins/Trace/intel-pt/DecodedThread.cpp @@ -0,0 +1,118 @@ +//===-- DecodedThread.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 "DecodedThread.h" + +#include +#include + +#include "TraceCursorIntelPT.h" +#include "lldb/Utility/StreamString.h" + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::trace_intel_pt; +using namespace llvm; + +char IntelPTError::ID; + +IntelPTError::IntelPTError(int libipt_error_code, lldb::addr_t address) + : m_libipt_error_code(libipt_error_code), m_address(address) { + assert(libipt_error_code < 0); +} + +void IntelPTError::log(llvm::raw_ostream &OS) const { + const char *libipt_error_message = pt_errstr(pt_errcode(m_libipt_error_code)); + if (m_address != LLDB_INVALID_ADDRESS && m_address > 0) { + write_hex(OS, m_address, HexPrintStyle::PrefixLower, 18); + OS << " "; + } + OS << "error: " << libipt_error_message; +} + +IntelPTInstruction::IntelPTInstruction(llvm::Error err) { + llvm::handleAllErrors(std::move(err), + [&](std::unique_ptr info) { + m_error = std::move(info); + }); + m_pt_insn.ip = LLDB_INVALID_ADDRESS; + m_pt_insn.iclass = ptic_error; +} + +bool IntelPTInstruction::IsError() const { return (bool)m_error; } + +lldb::addr_t IntelPTInstruction::GetLoadAddress() const { return m_pt_insn.ip; } + +Optional IntelPTInstruction::GetTimestampCounter() const { + return m_timestamp; +} + +Error IntelPTInstruction::ToError() const { + if (!IsError()) + return Error::success(); + + if (m_error->isA()) + return make_error(static_cast(*m_error)); + return make_error(m_error->message(), + m_error->convertToErrorCode()); +} +size_t DecodedThread::GetRawTraceSize() const { return m_raw_trace_size; } + +TraceInstructionControlFlowType +IntelPTInstruction::GetControlFlowType(lldb::addr_t next_load_address) const { + if (IsError()) + return (TraceInstructionControlFlowType)0; + + TraceInstructionControlFlowType mask = + eTraceInstructionControlFlowTypeInstruction; + + switch (m_pt_insn.iclass) { + case ptic_cond_jump: + case ptic_jump: + case ptic_far_jump: + mask |= eTraceInstructionControlFlowTypeBranch; + if (m_pt_insn.ip + m_pt_insn.size != next_load_address) + mask |= eTraceInstructionControlFlowTypeTakenBranch; + break; + case ptic_return: + case ptic_far_return: + mask |= eTraceInstructionControlFlowTypeReturn; + break; + case ptic_call: + case ptic_far_call: + mask |= eTraceInstructionControlFlowTypeCall; + break; + default: + break; + } + + return mask; +} + +ArrayRef DecodedThread::GetInstructions() const { + return makeArrayRef(m_instructions); +} + +DecodedThread::DecodedThread(ThreadSP thread_sp, Error error) + : m_thread_sp(thread_sp) { + m_instructions.emplace_back(std::move(error)); +} + +DecodedThread::DecodedThread(ThreadSP thread_sp, + std::vector &&instructions, + size_t raw_trace_size) + : m_thread_sp(thread_sp), m_instructions(std::move(instructions)), + m_raw_trace_size(raw_trace_size) { + if (m_instructions.empty()) + m_instructions.emplace_back( + createStringError(inconvertibleErrorCode(), "empty trace")); +} + +lldb::TraceCursorUP DecodedThread::GetCursor() { + return std::make_unique(m_thread_sp, shared_from_this()); +} diff --git a/gnu/llvm/lldb/source/Plugins/Trace/intel-pt/DecodedThread.h b/gnu/llvm/lldb/source/Plugins/Trace/intel-pt/DecodedThread.h new file mode 100644 index 00000000000..592c402cd0e --- /dev/null +++ b/gnu/llvm/lldb/source/Plugins/Trace/intel-pt/DecodedThread.h @@ -0,0 +1,164 @@ +//===-- DecodedThread.h -----------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_DECODEDTHREAD_H +#define LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_DECODEDTHREAD_H + +#include + +#include "llvm/Support/Errc.h" +#include "llvm/Support/Error.h" + +#include "lldb/Target/Trace.h" +#include "lldb/Utility/TraceIntelPTGDBRemotePackets.h" + +#include "intel-pt.h" + +namespace lldb_private { +namespace trace_intel_pt { + +/// Class for representing a libipt decoding error. +class IntelPTError : public llvm::ErrorInfo { +public: + static char ID; + + /// \param[in] libipt_error_code + /// Negative number returned by libipt when decoding the trace and + /// signaling errors. + /// + /// \param[in] address + /// Optional instruction address. When decoding an individual instruction, + /// its address might be available in the \a pt_insn object, and should be + /// passed to this constructor. Other errors don't have an associated + /// address. + IntelPTError(int libipt_error_code, + lldb::addr_t address = LLDB_INVALID_ADDRESS); + + std::error_code convertToErrorCode() const override { + return llvm::errc::not_supported; + } + + void log(llvm::raw_ostream &OS) const override; + +private: + int m_libipt_error_code; + lldb::addr_t m_address; +}; + +/// \class IntelPTInstruction +/// An instruction obtained from decoding a trace. It is either an actual +/// instruction or an error indicating a gap in the trace. +/// +/// Gaps in the trace can come in a few flavors: +/// - tracing gaps (e.g. tracing was paused and then resumed) +/// - tracing errors (e.g. buffer overflow) +/// - decoding errors (e.g. some memory region couldn't be decoded) +/// As mentioned, any gap is represented as an error in this class. +class IntelPTInstruction { +public: + IntelPTInstruction(const pt_insn &pt_insn, uint64_t timestamp) + : m_pt_insn(pt_insn), m_timestamp(timestamp) {} + + IntelPTInstruction(const pt_insn &pt_insn) : m_pt_insn(pt_insn) {} + + /// Error constructor + /// + /// libipt errors should use the underlying \a IntelPTError class. + IntelPTInstruction(llvm::Error err); + + /// Check if this object represents an error (i.e. a gap). + /// + /// \return + /// Whether this object represents an error. + bool IsError() const; + + /// \return + /// The instruction pointer address, or \a LLDB_INVALID_ADDRESS if it is + /// an error. + lldb::addr_t GetLoadAddress() const; + + /// \return + /// An \a llvm::Error object if this class corresponds to an Error, or an + /// \a llvm::Error::success otherwise. + llvm::Error ToError() const; + + /// Get the timestamp associated with the current instruction. The timestamp + /// is similar to what a rdtsc instruction would return. + /// + /// \return + /// The timestamp or \b llvm::None if not available. + llvm::Optional GetTimestampCounter() const; + + /// Get the \a lldb::TraceInstructionControlFlowType categories of the + /// instruction. + /// + /// \param[in] next_load_address + /// The address of the next instruction in the trace or \b + /// LLDB_INVALID_ADDRESS if not available. + /// + /// \return + /// The control flow categories, or \b 0 if the instruction is an error. + lldb::TraceInstructionControlFlowType + GetControlFlowType(lldb::addr_t next_load_address) const; + + IntelPTInstruction(IntelPTInstruction &&other) = default; + +private: + IntelPTInstruction(const IntelPTInstruction &other) = delete; + const IntelPTInstruction &operator=(const IntelPTInstruction &other) = delete; + + pt_insn m_pt_insn; + llvm::Optional m_timestamp; + std::unique_ptr m_error; +}; + +/// \class DecodedThread +/// Class holding the instructions and function call hierarchy obtained from +/// decoding a trace, as well as a position cursor used when reverse debugging +/// the trace. +/// +/// Each decoded thread contains a cursor to the current position the user is +/// stopped at. See \a Trace::GetCursorPosition for more information. +class DecodedThread : public std::enable_shared_from_this { +public: + DecodedThread(lldb::ThreadSP thread_sp, + std::vector &&instructions, + size_t raw_trace_size); + + /// Constructor with a single error signaling a complete failure of the + /// decoding process. + DecodedThread(lldb::ThreadSP thread_sp, llvm::Error error); + + /// Get the instructions from the decoded trace. Some of them might indicate + /// errors (i.e. gaps) in the trace. + /// + /// \return + /// The instructions of the trace. + llvm::ArrayRef GetInstructions() const; + + /// Get a new cursor for the decoded thread. + lldb::TraceCursorUP GetCursor(); + + /// Get the size in bytes of the corresponding Intel PT raw trace + /// + /// \return + /// The size of the trace. + size_t GetRawTraceSize() const; + +private: + lldb::ThreadSP m_thread_sp; + std::vector m_instructions; + size_t m_raw_trace_size; +}; + +using DecodedThreadSP = std::shared_ptr; + +} // namespace trace_intel_pt +} // namespace lldb_private + +#endif // LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_DECODEDTHREAD_H diff --git a/gnu/llvm/lldb/source/Plugins/Trace/intel-pt/IntelPTDecoder.cpp b/gnu/llvm/lldb/source/Plugins/Trace/intel-pt/IntelPTDecoder.cpp new file mode 100644 index 00000000000..3827881454c --- /dev/null +++ b/gnu/llvm/lldb/source/Plugins/Trace/intel-pt/IntelPTDecoder.cpp @@ -0,0 +1,279 @@ +//===-- IntelPTDecoder.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 "IntelPTDecoder.h" + +#include "llvm/Support/MemoryBuffer.h" + +#include "../common/ThreadPostMortemTrace.h" +#include "DecodedThread.h" +#include "TraceIntelPT.h" +#include "lldb/Core/Module.h" +#include "lldb/Core/Section.h" +#include "lldb/Target/Target.h" +#include "lldb/Utility/StringExtractor.h" + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::trace_intel_pt; +using namespace llvm; + +/// Move the decoder forward to the next synchronization point (i.e. next PSB +/// packet). +/// +/// Once the decoder is at that sync. point, it can start decoding instructions. +/// +/// \return +/// A negative number with the libipt error if we couldn't synchronize. +/// Otherwise, a positive number with the synchronization status will be +/// returned. +static int FindNextSynchronizationPoint(pt_insn_decoder &decoder) { + // Try to sync the decoder. If it fails, then get + // the decoder_offset and try to sync again from + // the next synchronization point. If the + // new_decoder_offset is same as decoder_offset + // then we can't move to the next synchronization + // point. Otherwise, keep resyncing until either + // end of trace stream (eos) is reached or + // pt_insn_sync_forward() passes. + int errcode = pt_insn_sync_forward(&decoder); + + if (errcode != -pte_eos && errcode < 0) { + uint64_t decoder_offset = 0; + int errcode_off = pt_insn_get_offset(&decoder, &decoder_offset); + if (errcode_off >= 0) { // we could get the offset + while (true) { + errcode = pt_insn_sync_forward(&decoder); + if (errcode >= 0 || errcode == -pte_eos) + break; + + uint64_t new_decoder_offset = 0; + errcode_off = pt_insn_get_offset(&decoder, &new_decoder_offset); + if (errcode_off < 0) + break; // We can't further synchronize. + else if (new_decoder_offset <= decoder_offset) { + // We tried resyncing the decoder and + // decoder didn't make any progress because + // the offset didn't change. We will not + // make any progress further. Hence, + // stopping in this situation. + break; + } + // We'll try again starting from a new offset. + decoder_offset = new_decoder_offset; + } + } + } + + return errcode; +} + +/// Before querying instructions, we need to query the events associated that +/// instruction e.g. timing events like ptev_tick, or paging events like +/// ptev_paging. +/// +/// \return +/// 0 if there were no errors processing the events, or a negative libipt +/// error code in case of errors. +static int ProcessPTEvents(pt_insn_decoder &decoder, int errcode) { + while (errcode & pts_event_pending) { + pt_event event; + errcode = pt_insn_event(&decoder, &event, sizeof(event)); + if (errcode < 0) + return errcode; + } + return 0; +} + +/// Decode all the instructions from a configured decoder. +/// The decoding flow is based on +/// https://github.com/intel/libipt/blob/master/doc/howto_libipt.md#the-instruction-flow-decode-loop +/// but with some relaxation to allow for gaps in the trace. +/// +/// Error codes returned by libipt while decoding are: +/// - negative: actual errors +/// - positive or zero: not an error, but a list of bits signaling the status of +/// the decoder +/// +/// \param[in] decoder +/// A configured libipt \a pt_insn_decoder. +/// +/// \return +/// The decoded instructions. +static std::vector +DecodeInstructions(pt_insn_decoder &decoder) { + std::vector instructions; + + while (true) { + int errcode = FindNextSynchronizationPoint(decoder); + if (errcode == -pte_eos) + break; + + if (errcode < 0) { + instructions.emplace_back(make_error(errcode)); + break; + } + + // We have synchronized, so we can start decoding + // instructions and events. + while (true) { + errcode = ProcessPTEvents(decoder, errcode); + if (errcode < 0) { + instructions.emplace_back(make_error(errcode)); + break; + } + pt_insn insn; + + errcode = pt_insn_next(&decoder, &insn, sizeof(insn)); + if (errcode == -pte_eos) + break; + + if (errcode < 0) { + instructions.emplace_back(make_error(errcode, insn.ip)); + break; + } + + uint64_t time; + int time_error = pt_insn_time(&decoder, &time, nullptr, nullptr); + if (time_error == -pte_invalid) { + // This happens if we invoke the pt_insn_time method incorrectly, + // but the instruction is good though. + instructions.emplace_back( + make_error(time_error, insn.ip)); + instructions.emplace_back(insn); + break; + } + if (time_error == -pte_no_time) { + // We simply don't have time information, i.e. None of TSC, MTC or CYC + // was enabled. + instructions.emplace_back(insn); + } else { + instructions.emplace_back(insn, time); + } + } + } + + return instructions; +} + +/// Callback used by libipt for reading the process memory. +/// +/// More information can be found in +/// https://github.com/intel/libipt/blob/master/doc/man/pt_image_set_callback.3.md +static int ReadProcessMemory(uint8_t *buffer, size_t size, + const pt_asid * /* unused */, uint64_t pc, + void *context) { + Process *process = static_cast(context); + + Status error; + int bytes_read = process->ReadMemory(pc, buffer, size, error); + if (error.Fail()) + return -pte_nomap; + return bytes_read; +} + +static Expected> +DecodeInMemoryTrace(Process &process, TraceIntelPT &trace_intel_pt, + MutableArrayRef buffer) { + Expected cpu_info = trace_intel_pt.GetCPUInfo(); + if (!cpu_info) + return cpu_info.takeError(); + + pt_config config; + pt_config_init(&config); + config.cpu = *cpu_info; + + if (int errcode = pt_cpu_errata(&config.errata, &config.cpu)) + return make_error(errcode); + + config.begin = buffer.data(); + config.end = buffer.data() + buffer.size(); + + pt_insn_decoder *decoder = pt_insn_alloc_decoder(&config); + if (!decoder) + return make_error(-pte_nomem); + + pt_image *image = pt_insn_get_image(decoder); + + int errcode = pt_image_set_callback(image, ReadProcessMemory, &process); + assert(errcode == 0); + (void)errcode; + + std::vector instructions = DecodeInstructions(*decoder); + + pt_insn_free_decoder(decoder); + return instructions; +} + +static Expected> +DecodeTraceFile(Process &process, TraceIntelPT &trace_intel_pt, + const FileSpec &trace_file, size_t &raw_trace_size) { + ErrorOr> trace_or_error = + MemoryBuffer::getFile(trace_file.GetPath()); + if (std::error_code err = trace_or_error.getError()) + return errorCodeToError(err); + + MemoryBuffer &trace = **trace_or_error; + MutableArrayRef trace_data( + // The libipt library does not modify the trace buffer, hence the + // following cast is safe. + reinterpret_cast(const_cast(trace.getBufferStart())), + trace.getBufferSize()); + raw_trace_size = trace_data.size(); + return DecodeInMemoryTrace(process, trace_intel_pt, trace_data); +} + +static Expected> +DecodeLiveThread(Thread &thread, TraceIntelPT &trace, size_t &raw_trace_size) { + Expected> buffer = + trace.GetLiveThreadBuffer(thread.GetID()); + if (!buffer) + return buffer.takeError(); + raw_trace_size = buffer->size(); + if (Expected cpu_info = trace.GetCPUInfo()) + return DecodeInMemoryTrace(*thread.GetProcess(), trace, + MutableArrayRef(*buffer)); + else + return cpu_info.takeError(); +} + +DecodedThreadSP ThreadDecoder::Decode() { + if (!m_decoded_thread.hasValue()) + m_decoded_thread = DoDecode(); + return *m_decoded_thread; +} + +PostMortemThreadDecoder::PostMortemThreadDecoder( + const lldb::ThreadPostMortemTraceSP &trace_thread, TraceIntelPT &trace) + : m_trace_thread(trace_thread), m_trace(trace) {} + +DecodedThreadSP PostMortemThreadDecoder::DoDecode() { + size_t raw_trace_size = 0; + if (Expected> instructions = + DecodeTraceFile(*m_trace_thread->GetProcess(), m_trace, + m_trace_thread->GetTraceFile(), raw_trace_size)) + return std::make_shared(m_trace_thread->shared_from_this(), + std::move(*instructions), + raw_trace_size); + else + return std::make_shared(m_trace_thread->shared_from_this(), + instructions.takeError()); +} + +LiveThreadDecoder::LiveThreadDecoder(Thread &thread, TraceIntelPT &trace) + : m_thread_sp(thread.shared_from_this()), m_trace(trace) {} + +DecodedThreadSP LiveThreadDecoder::DoDecode() { + size_t raw_trace_size = 0; + if (Expected> instructions = + DecodeLiveThread(*m_thread_sp, m_trace, raw_trace_size)) + return std::make_shared( + m_thread_sp, std::move(*instructions), raw_trace_size); + else + return std::make_shared(m_thread_sp, + instructions.takeError()); +} diff --git a/gnu/llvm/lldb/source/Plugins/Trace/intel-pt/IntelPTDecoder.h b/gnu/llvm/lldb/source/Plugins/Trace/intel-pt/IntelPTDecoder.h new file mode 100644 index 00000000000..e969db579e5 --- /dev/null +++ b/gnu/llvm/lldb/source/Plugins/Trace/intel-pt/IntelPTDecoder.h @@ -0,0 +1,87 @@ +//===-- IntelPTDecoder.h --======--------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_DECODER_H +#define LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_DECODER_H + +#include "intel-pt.h" + +#include "DecodedThread.h" +#include "forward-declarations.h" +#include "lldb/Target/Process.h" +#include "lldb/Utility/FileSpec.h" + +namespace lldb_private { +namespace trace_intel_pt { + +/// Base class that handles the decoding of a thread and caches the result. +class ThreadDecoder { +public: + virtual ~ThreadDecoder() = default; + + ThreadDecoder() = default; + + /// Decode the thread and store the result internally, to avoid + /// recomputations. + /// + /// \return + /// A \a DecodedThread instance. + DecodedThreadSP Decode(); + + ThreadDecoder(const ThreadDecoder &other) = delete; + ThreadDecoder &operator=(const ThreadDecoder &other) = delete; + +protected: + /// Decode the thread. + /// + /// \return + /// A \a DecodedThread instance. + virtual DecodedThreadSP DoDecode() = 0; + + llvm::Optional m_decoded_thread; +}; + +/// Decoder implementation for \a lldb_private::ThreadPostMortemTrace, which are +/// non-live processes that come trace session files. +class PostMortemThreadDecoder : public ThreadDecoder { +public: + /// \param[in] trace_thread + /// The thread whose trace file will be decoded. + /// + /// \param[in] trace + /// The main Trace object who owns this decoder and its data. + PostMortemThreadDecoder(const lldb::ThreadPostMortemTraceSP &trace_thread, + TraceIntelPT &trace); + +private: + DecodedThreadSP DoDecode() override; + + lldb::ThreadPostMortemTraceSP m_trace_thread; + TraceIntelPT &m_trace; +}; + +class LiveThreadDecoder : public ThreadDecoder { +public: + /// \param[in] thread + /// The thread whose traces will be decoded. + /// + /// \param[in] trace + /// The main Trace object who owns this decoder and its data. + LiveThreadDecoder(Thread &thread, TraceIntelPT &trace); + +private: + DecodedThreadSP DoDecode() override; + + lldb::ThreadSP m_thread_sp; + TraceIntelPT &m_trace; +}; + +} // namespace trace_intel_pt +} // namespace lldb_private + +#endif // LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_DECODER_H diff --git a/gnu/llvm/lldb/source/Plugins/Trace/intel-pt/TraceCursorIntelPT.cpp b/gnu/llvm/lldb/source/Plugins/Trace/intel-pt/TraceCursorIntelPT.cpp new file mode 100644 index 00000000000..edefdd0d348 --- /dev/null +++ b/gnu/llvm/lldb/source/Plugins/Trace/intel-pt/TraceCursorIntelPT.cpp @@ -0,0 +1,100 @@ +//===-- TraceCursorIntelPT.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 "TraceCursorIntelPT.h" +#include "DecodedThread.h" +#include "TraceIntelPT.h" + +#include + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::trace_intel_pt; +using namespace llvm; + +TraceCursorIntelPT::TraceCursorIntelPT(ThreadSP thread_sp, + DecodedThreadSP decoded_thread_sp) + : TraceCursor(thread_sp), m_decoded_thread_sp(decoded_thread_sp) { + assert(!m_decoded_thread_sp->GetInstructions().empty() && + "a trace should have at least one instruction or error"); + m_pos = m_decoded_thread_sp->GetInstructions().size() - 1; +} + +size_t TraceCursorIntelPT::GetInternalInstructionSize() { + return m_decoded_thread_sp->GetInstructions().size(); +} + +bool TraceCursorIntelPT::Next() { + auto canMoveOne = [&]() { + if (IsForwards()) + return m_pos + 1 < GetInternalInstructionSize(); + return m_pos > 0; + }; + + size_t initial_pos = m_pos; + + while (canMoveOne()) { + m_pos += IsForwards() ? 1 : -1; + if (!m_ignore_errors && IsError()) + return true; + if (GetInstructionControlFlowType() & m_granularity) + return true; + } + + // Didn't find any matching instructions + m_pos = initial_pos; + return false; +} + +size_t TraceCursorIntelPT::Seek(int64_t offset, SeekType origin) { + int64_t last_index = GetInternalInstructionSize() - 1; + + auto fitPosToBounds = [&](int64_t raw_pos) -> int64_t { + return std::min(std::max((int64_t)0, raw_pos), last_index); + }; + + switch (origin) { + case TraceCursor::SeekType::Set: + m_pos = fitPosToBounds(offset); + return m_pos; + case TraceCursor::SeekType::End: + m_pos = fitPosToBounds(offset + last_index); + return last_index - m_pos; + case TraceCursor::SeekType::Current: + int64_t new_pos = fitPosToBounds(offset + m_pos); + int64_t dist = m_pos - new_pos; + m_pos = new_pos; + return std::abs(dist); + } +} + +bool TraceCursorIntelPT::IsError() { + return m_decoded_thread_sp->GetInstructions()[m_pos].IsError(); +} + +Error TraceCursorIntelPT::GetError() { + return m_decoded_thread_sp->GetInstructions()[m_pos].ToError(); +} + +lldb::addr_t TraceCursorIntelPT::GetLoadAddress() { + return m_decoded_thread_sp->GetInstructions()[m_pos].GetLoadAddress(); +} + +Optional TraceCursorIntelPT::GetTimestampCounter() { + return m_decoded_thread_sp->GetInstructions()[m_pos].GetTimestampCounter(); +} + +TraceInstructionControlFlowType +TraceCursorIntelPT::GetInstructionControlFlowType() { + lldb::addr_t next_load_address = + m_pos + 1 < GetInternalInstructionSize() + ? m_decoded_thread_sp->GetInstructions()[m_pos + 1].GetLoadAddress() + : LLDB_INVALID_ADDRESS; + return m_decoded_thread_sp->GetInstructions()[m_pos].GetControlFlowType( + next_load_address); +} diff --git a/gnu/llvm/lldb/source/Plugins/Trace/intel-pt/TraceCursorIntelPT.h b/gnu/llvm/lldb/source/Plugins/Trace/intel-pt/TraceCursorIntelPT.h new file mode 100644 index 00000000000..29d3792bb48 --- /dev/null +++ b/gnu/llvm/lldb/source/Plugins/Trace/intel-pt/TraceCursorIntelPT.h @@ -0,0 +1,50 @@ +//===-- TraceCursorIntelPT.h ------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_TRACECURSORINTELPT_H +#define LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_TRACECURSORINTELPT_H + +#include "IntelPTDecoder.h" +#include "TraceIntelPTSessionFileParser.h" + +namespace lldb_private { +namespace trace_intel_pt { + +class TraceCursorIntelPT : public TraceCursor { +public: + TraceCursorIntelPT(lldb::ThreadSP thread_sp, + DecodedThreadSP decoded_thread_sp); + + size_t Seek(int64_t offset, SeekType origin) override; + + virtual bool Next() override; + + llvm::Error GetError() override; + + lldb::addr_t GetLoadAddress() override; + + llvm::Optional GetTimestampCounter() override; + + lldb::TraceInstructionControlFlowType + GetInstructionControlFlowType() override; + + bool IsError() override; + +private: + size_t GetInternalInstructionSize(); + + /// Storage of the actual instructions + DecodedThreadSP m_decoded_thread_sp; + /// Internal instruction index currently pointing at. + size_t m_pos; +}; + +} // namespace trace_intel_pt +} // namespace lldb_private + +#endif // LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_TRACECURSORINTELPT_H diff --git a/gnu/llvm/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp b/gnu/llvm/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp new file mode 100644 index 00000000000..c12bcd3523e --- /dev/null +++ b/gnu/llvm/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp @@ -0,0 +1,343 @@ +//===-- TraceIntelPT.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 "TraceIntelPT.h" + +#include "../common/ThreadPostMortemTrace.h" +#include "CommandObjectTraceStartIntelPT.h" +#include "DecodedThread.h" +#include "TraceIntelPTConstants.h" +#include "TraceIntelPTSessionFileParser.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/Target.h" + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::trace_intel_pt; +using namespace llvm; + +LLDB_PLUGIN_DEFINE(TraceIntelPT) + +lldb::CommandObjectSP +TraceIntelPT::GetProcessTraceStartCommand(CommandInterpreter &interpreter) { + return CommandObjectSP( + new CommandObjectProcessTraceStartIntelPT(*this, interpreter)); +} + +lldb::CommandObjectSP +TraceIntelPT::GetThreadTraceStartCommand(CommandInterpreter &interpreter) { + return CommandObjectSP( + new CommandObjectThreadTraceStartIntelPT(*this, interpreter)); +} + +void TraceIntelPT::Initialize() { + PluginManager::RegisterPlugin(GetPluginNameStatic(), "Intel Processor Trace", + CreateInstanceForSessionFile, + CreateInstanceForLiveProcess, + TraceIntelPTSessionFileParser::GetSchema()); +} + +void TraceIntelPT::Terminate() { + PluginManager::UnregisterPlugin(CreateInstanceForSessionFile); +} + +ConstString TraceIntelPT::GetPluginNameStatic() { + static ConstString g_name("intel-pt"); + return g_name; +} + +StringRef TraceIntelPT::GetSchema() { + return TraceIntelPTSessionFileParser::GetSchema(); +} + +//------------------------------------------------------------------ +// PluginInterface protocol +//------------------------------------------------------------------ + +ConstString TraceIntelPT::GetPluginName() { return GetPluginNameStatic(); } + +uint32_t TraceIntelPT::GetPluginVersion() { return 1; } + +void TraceIntelPT::Dump(Stream *s) const {} + +Expected TraceIntelPT::CreateInstanceForSessionFile( + const json::Value &trace_session_file, StringRef session_file_dir, + Debugger &debugger) { + return TraceIntelPTSessionFileParser(debugger, trace_session_file, + session_file_dir) + .Parse(); +} + +Expected TraceIntelPT::CreateInstanceForLiveProcess(Process &process) { + TraceSP instance(new TraceIntelPT(process)); + process.GetTarget().SetTrace(instance); + return instance; +} + +TraceIntelPT::TraceIntelPT( + const pt_cpu &cpu_info, + const std::vector &traced_threads) + : m_cpu_info(cpu_info) { + for (const ThreadPostMortemTraceSP &thread : traced_threads) + m_thread_decoders.emplace( + thread.get(), std::make_unique(thread, *this)); +} + +DecodedThreadSP TraceIntelPT::Decode(Thread &thread) { + RefreshLiveProcessState(); + if (m_live_refresh_error.hasValue()) + return std::make_shared( + thread.shared_from_this(), + createStringError(inconvertibleErrorCode(), *m_live_refresh_error)); + + auto it = m_thread_decoders.find(&thread); + if (it == m_thread_decoders.end()) + return std::make_shared( + thread.shared_from_this(), + createStringError(inconvertibleErrorCode(), "thread not traced")); + return it->second->Decode(); +} + +lldb::TraceCursorUP TraceIntelPT::GetCursor(Thread &thread) { + return Decode(thread)->GetCursor(); +} + +void TraceIntelPT::DumpTraceInfo(Thread &thread, Stream &s, bool verbose) { + Optional raw_size = GetRawTraceSize(thread); + s.Printf("\nthread #%u: tid = %" PRIu64, thread.GetIndexID(), thread.GetID()); + if (!raw_size) { + s.Printf(", not traced\n"); + return; + } + s.Printf("\n Raw trace size: %zu bytes\n", *raw_size); + return; +} + +Optional TraceIntelPT::GetRawTraceSize(Thread &thread) { + if (IsTraced(thread)) + return Decode(thread)->GetRawTraceSize(); + else + return None; +} + +Expected TraceIntelPT::GetCPUInfoForLiveProcess() { + Expected> cpu_info = GetLiveProcessBinaryData("cpuInfo"); + if (!cpu_info) + return cpu_info.takeError(); + + int64_t cpu_family = -1; + int64_t model = -1; + int64_t stepping = -1; + std::string vendor_id; + + StringRef rest(reinterpret_cast(cpu_info->data()), + cpu_info->size()); + while (!rest.empty()) { + StringRef line; + std::tie(line, rest) = rest.split('\n'); + + SmallVector columns; + line.split(columns, StringRef(":"), -1, false); + + if (columns.size() < 2) + continue; // continue searching + + columns[1] = columns[1].trim(" "); + if (columns[0].contains("cpu family") && + columns[1].getAsInteger(10, cpu_family)) + continue; + + else if (columns[0].contains("model") && columns[1].getAsInteger(10, model)) + continue; + + else if (columns[0].contains("stepping") && + columns[1].getAsInteger(10, stepping)) + continue; + + else if (columns[0].contains("vendor_id")) { + vendor_id = columns[1].str(); + if (!vendor_id.empty()) + continue; + } + + if ((cpu_family != -1) && (model != -1) && (stepping != -1) && + (!vendor_id.empty())) { + return pt_cpu{vendor_id == "GenuineIntel" ? pcv_intel : pcv_unknown, + static_cast(cpu_family), + static_cast(model), + static_cast(stepping)}; + } + } + return createStringError(inconvertibleErrorCode(), + "Failed parsing the target's /proc/cpuinfo file"); +} + +Expected TraceIntelPT::GetCPUInfo() { + if (!m_cpu_info) { + if (llvm::Expected cpu_info = GetCPUInfoForLiveProcess()) + m_cpu_info = *cpu_info; + else + return cpu_info.takeError(); + } + return *m_cpu_info; +} + +void TraceIntelPT::DoRefreshLiveProcessState( + Expected state) { + m_thread_decoders.clear(); + + if (!state) { + m_live_refresh_error = toString(state.takeError()); + return; + } + + for (const TraceThreadState &thread_state : state->tracedThreads) { + Thread &thread = + *m_live_process->GetThreadList().FindThreadByID(thread_state.tid); + m_thread_decoders.emplace( + &thread, std::make_unique(thread, *this)); + } +} + +bool TraceIntelPT::IsTraced(const Thread &thread) { + RefreshLiveProcessState(); + return m_thread_decoders.count(&thread); +} + +// The information here should match the description of the intel-pt section +// of the jLLDBTraceStart packet in the lldb/docs/lldb-gdb-remote.txt +// documentation file. Similarly, it should match the CLI help messages of the +// TraceIntelPTOptions.td file. +const char *TraceIntelPT::GetStartConfigurationHelp() { + return R"(Parameters: + + Note: If a parameter is not specified, a default value will be used. + + - int threadBufferSize (defaults to 4096 bytes): + [process and thread tracing] + Trace size in bytes per thread. It must be a power of 2 greater + than or equal to 4096 (2^12). The trace is circular keeping the + the most recent data. + + - boolean enableTsc (default to false): + [process and thread tracing] + Whether to use enable TSC timestamps or not. This is supported on + all devices that support intel-pt. + + - psbPeriod (defaults to null): + [process and thread tracing] + This value defines the period in which PSB packets will be generated. + A PSB packet is a synchronization packet that contains a TSC + timestamp and the current absolute instruction pointer. + + This parameter can only be used if + + /sys/bus/event_source/devices/intel_pt/caps/psb_cyc + + is 1. Otherwise, the PSB period will be defined by the processor. + + If supported, valid values for this period can be found in + + /sys/bus/event_source/devices/intel_pt/caps/psb_periods + + which contains a hexadecimal number, whose bits represent + valid values e.g. if bit 2 is set, then value 2 is valid. + + The psb_period value is converted to the approximate number of + raw trace bytes between PSB packets as: + + 2 ^ (value + 11) + + e.g. value 3 means 16KiB between PSB packets. Defaults to 0 if + supported. + + - int processBufferSizeLimit (defaults to 500 MB): + [process tracing only] + Maximum total trace size per process in bytes. This limit applies + to the sum of the sizes of all thread traces of this process, + excluding the ones created explicitly with "thread tracing". + Whenever a thread is attempted to be traced due to this command + and the limit would be reached, the process is stopped with a + "processor trace" reason, so that the user can retrace the process + if needed.)"; +} + +Error TraceIntelPT::Start(size_t thread_buffer_size, + size_t total_buffer_size_limit, bool enable_tsc, + Optional psb_period) { + TraceIntelPTStartRequest request; + request.threadBufferSize = thread_buffer_size; + request.processBufferSizeLimit = total_buffer_size_limit; + request.enableTsc = enable_tsc; + request.psbPeriod = psb_period.map([](size_t val) { return (int64_t)val; }); + request.type = GetPluginName().AsCString(); + return Trace::Start(toJSON(request)); +} + +Error TraceIntelPT::Start(StructuredData::ObjectSP configuration) { + size_t thread_buffer_size = kDefaultThreadBufferSize; + size_t process_buffer_size_limit = kDefaultProcessBufferSizeLimit; + bool enable_tsc = kDefaultEnableTscValue; + Optional psb_period = kDefaultPsbPeriod; + + if (configuration) { + if (StructuredData::Dictionary *dict = configuration->GetAsDictionary()) { + dict->GetValueForKeyAsInteger("threadBufferSize", thread_buffer_size); + dict->GetValueForKeyAsInteger("processBufferSizeLimit", + process_buffer_size_limit); + dict->GetValueForKeyAsBoolean("enableTsc", enable_tsc); + dict->GetValueForKeyAsInteger("psbPeriod", psb_period); + } else { + return createStringError(inconvertibleErrorCode(), + "configuration object is not a dictionary"); + } + } + + return Start(thread_buffer_size, process_buffer_size_limit, enable_tsc, + psb_period); +} + +llvm::Error TraceIntelPT::Start(llvm::ArrayRef tids, + size_t thread_buffer_size, bool enable_tsc, + Optional psb_period) { + TraceIntelPTStartRequest request; + request.threadBufferSize = thread_buffer_size; + request.enableTsc = enable_tsc; + request.psbPeriod = psb_period.map([](size_t val) { return (int64_t)val; }); + request.type = GetPluginName().AsCString(); + request.tids.emplace(); + for (lldb::tid_t tid : tids) + request.tids->push_back(tid); + return Trace::Start(toJSON(request)); +} + +Error TraceIntelPT::Start(llvm::ArrayRef tids, + StructuredData::ObjectSP configuration) { + size_t thread_buffer_size = kDefaultThreadBufferSize; + bool enable_tsc = kDefaultEnableTscValue; + Optional psb_period = kDefaultPsbPeriod; + + if (configuration) { + if (StructuredData::Dictionary *dict = configuration->GetAsDictionary()) { + dict->GetValueForKeyAsInteger("threadBufferSize", thread_buffer_size); + dict->GetValueForKeyAsBoolean("enableTsc", enable_tsc); + dict->GetValueForKeyAsInteger("psbPeriod", psb_period); + } else { + return createStringError(inconvertibleErrorCode(), + "configuration object is not a dictionary"); + } + } + + return Start(tids, thread_buffer_size, enable_tsc, psb_period); +} + +Expected> +TraceIntelPT::GetLiveThreadBuffer(lldb::tid_t tid) { + return Trace::GetLiveThreadBinaryData(tid, "threadTraceBuffer"); +} diff --git a/gnu/llvm/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.h b/gnu/llvm/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.h new file mode 100644 index 00000000000..e3b247112ae --- /dev/null +++ b/gnu/llvm/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.h @@ -0,0 +1,181 @@ +//===-- TraceIntelPT.h ------------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_TRACEINTELPT_H +#define LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_TRACEINTELPT_H + +#include "IntelPTDecoder.h" +#include "TraceIntelPTSessionFileParser.h" + +namespace lldb_private { +namespace trace_intel_pt { + +class TraceIntelPT : public Trace { +public: + void Dump(Stream *s) const override; + + ~TraceIntelPT() override = default; + + /// PluginInterface protocol + /// \{ + ConstString GetPluginName() override; + + static void Initialize(); + + static void Terminate(); + + /// Create an instance of this class. + /// + /// \param[in] trace_session_file + /// The contents of the trace session file. See \a Trace::FindPlugin. + /// + /// \param[in] session_file_dir + /// The path to the directory that contains the session file. It's used to + /// resolved relative paths in the session file. + /// + /// \param[in] debugger + /// The debugger instance where new Targets will be created as part of the + /// JSON data parsing. + /// + /// \return + /// A trace instance or an error in case of failures. + static llvm::Expected + CreateInstanceForSessionFile(const llvm::json::Value &trace_session_file, + llvm::StringRef session_file_dir, + Debugger &debugger); + + static llvm::Expected + CreateInstanceForLiveProcess(Process &process); + + static ConstString GetPluginNameStatic(); + + uint32_t GetPluginVersion() override; + /// \} + + lldb::CommandObjectSP + GetProcessTraceStartCommand(CommandInterpreter &interpreter) override; + + lldb::CommandObjectSP + GetThreadTraceStartCommand(CommandInterpreter &interpreter) override; + + llvm::StringRef GetSchema() override; + + lldb::TraceCursorUP GetCursor(Thread &thread) override; + + void DumpTraceInfo(Thread &thread, Stream &s, bool verbose) override; + + llvm::Optional GetRawTraceSize(Thread &thread); + + void DoRefreshLiveProcessState( + llvm::Expected state) override; + + bool IsTraced(const Thread &thread) override; + + const char *GetStartConfigurationHelp() override; + + /// Start tracing a live process. + /// + /// \param[in] thread_buffer_size + /// Trace size per thread in bytes. + /// + /// \param[in] total_buffer_size_limit + /// Maximum total trace size per process in bytes. + /// More information in TraceIntelPT::GetStartConfigurationHelp(). + /// + /// \param[in] enable_tsc + /// Whether to use enable TSC timestamps or not. + /// More information in TraceIntelPT::GetStartConfigurationHelp(). + /// + /// \param[in] psb_period + /// + /// This value defines the period in which PSB packets will be generated. + /// More information in TraceIntelPT::GetStartConfigurationHelp(); + /// + /// \return + /// \a llvm::Error::success if the operation was successful, or + /// \a llvm::Error otherwise. + llvm::Error Start(size_t thread_buffer_size, size_t total_buffer_size_limit, + bool enable_tsc, llvm::Optional psb_period); + + /// \copydoc Trace::Start + llvm::Error Start(StructuredData::ObjectSP configuration = + StructuredData::ObjectSP()) override; + + /// Start tracing live threads. + /// + /// \param[in] tids + /// Threads to trace. + /// + /// \param[in] thread_buffer_size + /// Trace size per thread in bytes. + /// + /// \param[in] enable_tsc + /// Whether to use enable TSC timestamps or not. + /// More information in TraceIntelPT::GetStartConfigurationHelp(). + /// + /// \param[in] psb_period + /// + /// This value defines the period in which PSB packets will be generated. + /// More information in TraceIntelPT::GetStartConfigurationHelp(). + /// + /// \return + /// \a llvm::Error::success if the operation was successful, or + /// \a llvm::Error otherwise. + llvm::Error Start(llvm::ArrayRef tids, size_t thread_buffer_size, + bool enable_tsc, llvm::Optional psb_period); + + /// \copydoc Trace::Start + llvm::Error Start(llvm::ArrayRef tids, + StructuredData::ObjectSP configuration = + StructuredData::ObjectSP()) override; + + /// Get the thread buffer content for a live thread + llvm::Expected> GetLiveThreadBuffer(lldb::tid_t tid); + + llvm::Expected GetCPUInfo(); + +private: + friend class TraceIntelPTSessionFileParser; + + llvm::Expected GetCPUInfoForLiveProcess(); + + /// \param[in] trace_threads + /// ThreadTrace instances, which are not live-processes and whose trace + /// files are fixed. + TraceIntelPT( + const pt_cpu &cpu_info, + const std::vector &traced_threads); + + /// Constructor for live processes + TraceIntelPT(Process &live_process) + : Trace(live_process), m_thread_decoders(){}; + + /// Decode the trace of the given thread that, i.e. recontruct the traced + /// instructions. + /// + /// \param[in] thread + /// If \a thread is a \a ThreadTrace, then its internal trace file will be + /// decoded. Live threads are not currently supported. + /// + /// \return + /// A \a DecodedThread shared pointer with the decoded instructions. Any + /// errors are embedded in the instruction list. + DecodedThreadSP Decode(Thread &thread); + + /// It is provided by either a session file or a live process' "cpuInfo" + /// binary data. + llvm::Optional m_cpu_info; + std::map> m_thread_decoders; + /// Error gotten after a failed live process update, if any. + llvm::Optional m_live_refresh_error; +}; + +} // namespace trace_intel_pt +} // namespace lldb_private + +#endif // LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_TRACEINTELPT_H diff --git a/gnu/llvm/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTConstants.h b/gnu/llvm/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTConstants.h new file mode 100644 index 00000000000..c2bc1b57b2b --- /dev/null +++ b/gnu/llvm/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTConstants.h @@ -0,0 +1,27 @@ +//===-- TraceIntelPTConstants.h ---------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_CONSTANTS_H +#define LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_CONSTANTS_H + +#include + +#include + +namespace lldb_private { +namespace trace_intel_pt { + +const size_t kDefaultThreadBufferSize = 4 * 1024; // 4KB +const size_t kDefaultProcessBufferSizeLimit = 5 * 1024 * 1024; // 500MB +const bool kDefaultEnableTscValue = false; +const llvm::Optional kDefaultPsbPeriod = llvm::None; + +} // namespace trace_intel_pt +} // namespace lldb_private + +#endif // LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_CONSTANTS_H diff --git a/gnu/llvm/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTOptions.td b/gnu/llvm/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTOptions.td new file mode 100644 index 00000000000..9e8cab1ee5c --- /dev/null +++ b/gnu/llvm/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTOptions.td @@ -0,0 +1,74 @@ +include "../../../../source/Commands/OptionsBase.td" + +// The information of the start commands here should match the description of +// the intel-pt section of the jLLDBTraceStart packet in the +// lldb/docs/lldb-gdb-remote.txt documentation file. Similarly, it should match +// the API help message of TraceIntelPT::GetStartConfigurationHelp(). + +let Command = "thread trace start intel pt" in { + def thread_trace_start_intel_pt_size: Option<"size", "s">, + Group<1>, + Arg<"Value">, + Desc<"Trace size in bytes per thread. It must be a power of 2 greater " + "than or equal to 4096 (2^12). The trace is circular keeping " + "the most recent data. Defaults to 4096 bytes.">; + def thread_trace_start_intel_pt_tsc: Option<"tsc", "t">, + Group<1>, + Desc<"Enable the use of TSC timestamps. This is supported on all devices " + "that support intel-pt.">; + def thread_trace_start_intel_pt_psb_period: Option<"psb-period", "p">, + Group<1>, + Arg<"Value">, + Desc<"This value defines the period in which PSB packets will be " + "generated. A PSB packet is a synchronization packet that contains a " + "TSC timestamp and the current absolute instruction pointer. " + "This parameter can only be used if " + "/sys/bus/event_source/devices/intel_pt/caps/psb_cyc is 1. Otherwise, " + "the PSB period will be defined by the processor. If supported, valid " + "values for this period can be found in " + "/sys/bus/event_source/devices/intel_pt/caps/psb_periods which " + "contains a hexadecimal number, whose bits represent valid values " + "e.g. if bit 2 is set, then value 2 is valid. The psb_period value is " + "converted to the approximate number of raw trace bytes between PSB " + "packets as: 2 ^ (value + 11), e.g. value 3 means 16KiB between PSB " + "packets. Defaults to 0 if supported.">; +} + +let Command = "process trace start intel pt" in { + def process_trace_start_intel_pt_thread_size: Option<"thread-size", "s">, + Group<1>, + Arg<"Value">, + Desc<"Trace size in bytes per thread. It must be a power of 2 greater " + "than or equal to 4096 (2^12). The trace is circular keeping " + "the most recent data. Defaults to 4096 bytes.">; + def process_trace_start_intel_pt_process_size_limit: Option<"total-size-limit", "l">, + Group<1>, + Arg<"Value">, + Desc<"Maximum total trace size per process in bytes. This limit applies to " + "the sum of the sizes of all thread traces of this process, excluding " + "the ones created with the \"thread trace start\" command. " + "Whenever a thread is attempted to be traced due to this command and " + "the limit would be reached, the process is stopped with a " + "\"processor trace\" reason, so that the user can retrace the process " + "if needed. Defaults to 500MB.">; + def process_trace_start_intel_pt_tsc: Option<"tsc", "t">, + Group<1>, + Desc<"Enable the use of TSC timestamps. This is supported on all devices " + "that support intel-pt.">; + def process_trace_start_intel_pt_psb_period: Option<"psb-period", "p">, + Group<1>, + Arg<"Value">, + Desc<"This value defines the period in which PSB packets will be " + "generated. A PSB packet is a synchronization packet that contains a " + "TSC timestamp and the current absolute instruction pointer. " + "This parameter can only be used if " + "/sys/bus/event_source/devices/intel_pt/caps/psb_cyc is 1. Otherwise, " + "the PSB period will be defined by the processor. If supported, valid " + "values for this period can be found in " + "/sys/bus/event_source/devices/intel_pt/caps/psb_periods which " + "contains a hexadecimal number, whose bits represent valid values " + "e.g. if bit 2 is set, then value 2 is valid. The psb_period value is " + "converted to the approximate number of raw trace bytes between PSB " + "packets as: 2 ^ (value + 11), e.g. value 3 means 16KiB between PSB " + "packets. Defaults to 0 if supported.">; +} diff --git a/gnu/llvm/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTSessionFileParser.cpp b/gnu/llvm/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTSessionFileParser.cpp new file mode 100644 index 00000000000..5af7c269d0c --- /dev/null +++ b/gnu/llvm/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTSessionFileParser.cpp @@ -0,0 +1,107 @@ +//===-- TraceIntelPTSessionFileParser.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 "TraceIntelPTSessionFileParser.h" + +#include "../common/ThreadPostMortemTrace.h" +#include "lldb/Core/Debugger.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/Target.h" +#include "lldb/Target/ThreadList.h" + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::trace_intel_pt; +using namespace llvm; + +StringRef TraceIntelPTSessionFileParser::GetSchema() { + static std::string schema; + if (schema.empty()) { + schema = TraceSessionFileParser::BuildSchema(R"({ + "type": "intel-pt", + "cpuInfo": { + "vendor": "intel" | "unknown", + "family": integer, + "model": integer, + "stepping": integer + } + })"); + } + return schema; +} + +pt_cpu TraceIntelPTSessionFileParser::ParsePTCPU( + const JSONTraceIntelPTCPUInfo &cpu_info) { + return {cpu_info.vendor.compare("intel") == 0 ? pcv_intel : pcv_unknown, + static_cast(cpu_info.family), + static_cast(cpu_info.model), + static_cast(cpu_info.stepping)}; +} + +TraceSP TraceIntelPTSessionFileParser::CreateTraceIntelPTInstance( + const pt_cpu &cpu_info, std::vector &parsed_processes) { + std::vector threads; + for (const ParsedProcess &parsed_process : parsed_processes) + threads.insert(threads.end(), parsed_process.threads.begin(), + parsed_process.threads.end()); + + TraceSP trace_instance(new TraceIntelPT(cpu_info, threads)); + for (const ParsedProcess &parsed_process : parsed_processes) + parsed_process.target_sp->SetTrace(trace_instance); + + return trace_instance; +} + +Expected TraceIntelPTSessionFileParser::Parse() { + json::Path::Root root("traceSession"); + TraceSessionFileParser::JSONTraceSession session; + if (!json::fromJSON(m_trace_session_file, session, root)) + return CreateJSONError(root, m_trace_session_file); + + if (Expected> parsed_processes = + ParseCommonSessionFile(session)) + return CreateTraceIntelPTInstance(ParsePTCPU(session.trace.cpuInfo), + *parsed_processes); + else + return parsed_processes.takeError(); +} + +namespace llvm { +namespace json { + +bool fromJSON( + const Value &value, + TraceIntelPTSessionFileParser::JSONTraceIntelPTSettings &plugin_settings, + Path path) { + ObjectMapper o(value, path); + return o && o.map("cpuInfo", plugin_settings.cpuInfo) && + fromJSON( + value, + (TraceSessionFileParser::JSONTracePluginSettings &)plugin_settings, + path); +} + +bool fromJSON(const json::Value &value, + TraceIntelPTSessionFileParser::JSONTraceIntelPTCPUInfo &cpu_info, + Path path) { + ObjectMapper o(value, path); + return o && o.map("vendor", cpu_info.vendor) && + o.map("family", cpu_info.family) && o.map("model", cpu_info.model) && + o.map("stepping", cpu_info.stepping); +} + +Value toJSON( + const TraceIntelPTSessionFileParser::JSONTraceIntelPTCPUInfo &cpu_info) { + return Value(Object{{"family", cpu_info.family}, + {"model", cpu_info.model}, + {"stepping", cpu_info.stepping}, + {"vendor", cpu_info.vendor}}); +} + +} // namespace json +} // namespace llvm diff --git a/gnu/llvm/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTSessionFileParser.h b/gnu/llvm/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTSessionFileParser.h new file mode 100644 index 00000000000..b2667a88222 --- /dev/null +++ b/gnu/llvm/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTSessionFileParser.h @@ -0,0 +1,88 @@ +//===-- TraceIntelPTSessionFileParser.h -----------------------*- C++ //-*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_TRACEINTELPTSESSIONFILEPARSER_H +#define LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_TRACEINTELPTSESSIONFILEPARSER_H + +#include "TraceIntelPT.h" + +#include "../common/TraceSessionFileParser.h" + +namespace lldb_private { +namespace trace_intel_pt { + +class TraceIntelPT; + +class TraceIntelPTSessionFileParser : public TraceSessionFileParser { +public: + struct JSONTraceIntelPTCPUInfo { + int64_t family; + int64_t model; + int64_t stepping; + std::string vendor; + }; + + struct JSONTraceIntelPTSettings + : TraceSessionFileParser::JSONTracePluginSettings { + JSONTraceIntelPTCPUInfo cpuInfo; + }; + + /// See \a TraceSessionFileParser::TraceSessionFileParser for the description + /// of these fields. + TraceIntelPTSessionFileParser(Debugger &debugger, + const llvm::json::Value &trace_session_file, + llvm::StringRef session_file_dir) + : TraceSessionFileParser(debugger, session_file_dir, GetSchema()), + m_trace_session_file(trace_session_file) {} + + /// \return + /// The JSON schema for the session data. + static llvm::StringRef GetSchema(); + + /// Parse the structured data trace session and create the corresponding \a + /// Target objects. In case of an error, no targets are created. + /// + /// \return + /// A \a lldb::TraceSP instance with the trace session data. In case of + /// errors, return a null pointer. + llvm::Expected Parse(); + + lldb::TraceSP + CreateTraceIntelPTInstance(const pt_cpu &cpu_info, + std::vector &parsed_processes); + +private: + static pt_cpu ParsePTCPU(const JSONTraceIntelPTCPUInfo &cpu_info); + + const llvm::json::Value &m_trace_session_file; +}; + +} // namespace trace_intel_pt +} // namespace lldb_private + +namespace llvm { +namespace json { + +bool fromJSON(const Value &value, + lldb_private::trace_intel_pt::TraceIntelPTSessionFileParser:: + JSONTraceIntelPTSettings &plugin_settings, + Path path); + +bool fromJSON(const llvm::json::Value &value, + lldb_private::trace_intel_pt::TraceIntelPTSessionFileParser:: + JSONTraceIntelPTCPUInfo &packet, + llvm::json::Path path); + +llvm::json::Value +toJSON(const lldb_private::trace_intel_pt::TraceIntelPTSessionFileParser:: + JSONTraceIntelPTCPUInfo &packet); + +} // namespace json +} // namespace llvm + +#endif // LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_TRACEINTELPTSESSIONFILEPARSER_H diff --git a/gnu/llvm/lldb/source/Plugins/Trace/intel-pt/forward-declarations.h b/gnu/llvm/lldb/source/Plugins/Trace/intel-pt/forward-declarations.h new file mode 100644 index 00000000000..3c5f811acc1 --- /dev/null +++ b/gnu/llvm/lldb/source/Plugins/Trace/intel-pt/forward-declarations.h @@ -0,0 +1,20 @@ +//===-- forward-declarations.h ----------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_FORWARD_DECLARATIONS_H +#define LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_FORWARD_DECLARATIONS_H + +namespace lldb_private { +namespace trace_intel_pt { + +class TraceIntelPT; +class ThreadDecoder; + +} // namespace trace_intel_pt +} // namespace lldb_private +#endif // LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_FORWARD_DECLARATIONS_H diff --git a/gnu/llvm/lldb/source/Plugins/TraceExporter/CMakeLists.txt b/gnu/llvm/lldb/source/Plugins/TraceExporter/CMakeLists.txt new file mode 100644 index 00000000000..7c4019186c9 --- /dev/null +++ b/gnu/llvm/lldb/source/Plugins/TraceExporter/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(ctf) diff --git a/gnu/llvm/lldb/source/Plugins/TraceExporter/ctf/CMakeLists.txt b/gnu/llvm/lldb/source/Plugins/TraceExporter/ctf/CMakeLists.txt new file mode 100644 index 00000000000..766cc18b919 --- /dev/null +++ b/gnu/llvm/lldb/source/Plugins/TraceExporter/ctf/CMakeLists.txt @@ -0,0 +1,17 @@ +lldb_tablegen(TraceExporterCTFCommandOptions.inc -gen-lldb-option-defs + SOURCE TraceExporterCTFOptions.td + TARGET TraceExporterCTFOptionsGen) + +add_lldb_library(lldbPluginTraceExporterCTF PLUGIN +CommandObjectThreadTraceExportCTF.cpp + TraceExporterCTF.cpp + + LINK_LIBS + lldbCore + lldbSymbol + lldbTarget + LINK_COMPONENTS + Support + ) + +add_dependencies(lldbPluginTraceExporterCTF TraceExporterCTFOptionsGen) diff --git a/gnu/llvm/lldb/source/Plugins/TraceExporter/ctf/CommandObjectThreadTraceExportCTF.cpp b/gnu/llvm/lldb/source/Plugins/TraceExporter/ctf/CommandObjectThreadTraceExportCTF.cpp new file mode 100644 index 00000000000..3dd4c89e277 --- /dev/null +++ b/gnu/llvm/lldb/source/Plugins/TraceExporter/ctf/CommandObjectThreadTraceExportCTF.cpp @@ -0,0 +1,66 @@ +//===-- CommandObjectThreadTraceExportCTF.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 "CommandObjectThreadTraceExportCTF.h" + +#include "lldb/Host/OptionParser.h" + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::ctf; +using namespace llvm; + +// CommandObjectThreadTraceExportCTF + +#define LLDB_OPTIONS_thread_trace_export_ctf +#include "TraceExporterCTFCommandOptions.inc" + +Status CommandObjectThreadTraceExportCTF::CommandOptions::SetOptionValue( + uint32_t option_idx, llvm::StringRef option_arg, + ExecutionContext *execution_context) { + Status error; + const int short_option = m_getopt_table[option_idx].val; + + switch (short_option) { + case 't': { + int64_t thread_index; + if (option_arg.empty() || option_arg.getAsInteger(0, thread_index) || + thread_index < 0) + error.SetErrorStringWithFormat("invalid integer value for option '%s'", + option_arg.str().c_str()); + else + m_thread_index = thread_index; + break; + } + default: + llvm_unreachable("Unimplemented option"); + } + return error; +} + +void CommandObjectThreadTraceExportCTF::CommandOptions::OptionParsingStarting( + ExecutionContext *execution_context) { + m_thread_index = None; +} + +llvm::ArrayRef +CommandObjectThreadTraceExportCTF::CommandOptions::GetDefinitions() { + return llvm::makeArrayRef(g_thread_trace_export_ctf_options); +} + +bool CommandObjectThreadTraceExportCTF::DoExecute(Args &command, + CommandReturnObject &result) { + Stream &s = result.GetOutputStream(); + // TODO: create an actual instance of the exporter and invoke it + if (m_options.m_thread_index) + s.Printf("got thread index %d\n", (int)m_options.m_thread_index.getValue()); + else + s.Printf("didn't get a thread index\n"); + + return result.Succeeded(); +} diff --git a/gnu/llvm/lldb/source/Plugins/TraceExporter/ctf/CommandObjectThreadTraceExportCTF.h b/gnu/llvm/lldb/source/Plugins/TraceExporter/ctf/CommandObjectThreadTraceExportCTF.h new file mode 100644 index 00000000000..26b068a8f8c --- /dev/null +++ b/gnu/llvm/lldb/source/Plugins/TraceExporter/ctf/CommandObjectThreadTraceExportCTF.h @@ -0,0 +1,56 @@ +//===-- CommandObjectThreadTraceExportCTF.h -------------------*- C++ //-*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_COMMANDOBJECTTHREADTRACEEXPORTCTF_H +#define LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_COMMANDOBJECTTHREADTRACEEXPORTCTF_H + +#include "TraceExporterCTF.h" +#include "lldb/Interpreter/CommandInterpreter.h" +#include "lldb/Interpreter/CommandReturnObject.h" + +namespace lldb_private { +namespace ctf { + +class CommandObjectThreadTraceExportCTF : public CommandObjectParsed { +public: + class CommandOptions : public Options { + public: + CommandOptions() : Options() { OptionParsingStarting(nullptr); } + + Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, + ExecutionContext *execution_context) override; + + void OptionParsingStarting(ExecutionContext *execution_context) override; + + llvm::ArrayRef GetDefinitions() override; + + llvm::Optional m_thread_index; + }; + + CommandObjectThreadTraceExportCTF(CommandInterpreter &interpreter) + : CommandObjectParsed( + interpreter, "thread trace export ctf", + "Export a given thread's trace to Chrome Trace Format", + "thread trace export ctf []", + lldb::eCommandRequiresProcess | lldb::eCommandTryTargetAPILock | + lldb::eCommandProcessMustBeLaunched | + lldb::eCommandProcessMustBePaused), + m_options() {} + + Options *GetOptions() override { return &m_options; } + +protected: + bool DoExecute(Args &command, CommandReturnObject &result) override; + + CommandOptions m_options; +}; + +} // namespace ctf +} // namespace lldb_private + +#endif // LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_COMMANDOBJECTTHREADTRACEEXPORTCTF_H diff --git a/gnu/llvm/lldb/source/Plugins/TraceExporter/ctf/TraceExporterCTF.cpp b/gnu/llvm/lldb/source/Plugins/TraceExporter/ctf/TraceExporterCTF.cpp new file mode 100644 index 00000000000..08bc03d7830 --- /dev/null +++ b/gnu/llvm/lldb/source/Plugins/TraceExporter/ctf/TraceExporterCTF.cpp @@ -0,0 +1,53 @@ +//===-- TraceExporterCTF.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 "TraceExporterCTF.h" + +#include + +#include "CommandObjectThreadTraceExportCTF.h" +#include "lldb/Core/PluginManager.h" + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::ctf; +using namespace llvm; + +LLDB_PLUGIN_DEFINE(TraceExporterCTF) + +//------------------------------------------------------------------ +// PluginInterface protocol +//------------------------------------------------------------------ + +static CommandObjectSP +GetThreadTraceExportCommand(CommandInterpreter &interpreter) { + return std::make_shared(interpreter); +} + +void TraceExporterCTF::Initialize() { + PluginManager::RegisterPlugin(GetPluginNameStatic(), + "Chrome Trace Format Exporter", CreateInstance, + GetThreadTraceExportCommand); +} + +void TraceExporterCTF::Terminate() { + PluginManager::UnregisterPlugin(CreateInstance); +} + +ConstString TraceExporterCTF::GetPluginNameStatic() { + static ConstString g_name("ctf"); + return g_name; +} + +ConstString TraceExporterCTF::GetPluginName() { return GetPluginNameStatic(); } + +uint32_t TraceExporterCTF::GetPluginVersion() { return 1; } + +Expected TraceExporterCTF::CreateInstance() { + return std::make_unique(); +} diff --git a/gnu/llvm/lldb/source/Plugins/TraceExporter/ctf/TraceExporterCTF.h b/gnu/llvm/lldb/source/Plugins/TraceExporter/ctf/TraceExporterCTF.h new file mode 100644 index 00000000000..8f9e354ab0d --- /dev/null +++ b/gnu/llvm/lldb/source/Plugins/TraceExporter/ctf/TraceExporterCTF.h @@ -0,0 +1,42 @@ +//===-- TraceExporterCTF.h --------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SOURCE_PLUGINS_TRACE_EXPORTER_CTF_H +#define LLDB_SOURCE_PLUGINS_TRACE_EXPORTER_CTF_H + +#include "lldb/Target/TraceExporter.h" + +namespace lldb_private { +namespace ctf { + +/// Trace Exporter Plugin that can produce traces in Chrome Trace Format. +/// Still in development. +class TraceExporterCTF : public TraceExporter { +public: + ~TraceExporterCTF() override = default; + + /// PluginInterface protocol + /// \{ + static llvm::Expected CreateInstance(); + + ConstString GetPluginName() override; + + static void Initialize(); + + static void Terminate(); + + static ConstString GetPluginNameStatic(); + + uint32_t GetPluginVersion() override; + /// \} +}; + +} // namespace ctf +} // namespace lldb_private + +#endif // LLDB_SOURCE_PLUGINS_TRACE_EXPORTER_CTF_H diff --git a/gnu/llvm/lldb/source/Plugins/TraceExporter/ctf/TraceExporterCTFOptions.td b/gnu/llvm/lldb/source/Plugins/TraceExporter/ctf/TraceExporterCTFOptions.td new file mode 100644 index 00000000000..ce751f148d9 --- /dev/null +++ b/gnu/llvm/lldb/source/Plugins/TraceExporter/ctf/TraceExporterCTFOptions.td @@ -0,0 +1,9 @@ +include "../../../../source/Commands/OptionsBase.td" + +let Command = "thread trace export ctf" in { + def thread_trace_export_ctf: Option<"tid", "t">, + Group<1>, + Arg<"ThreadIndex">, + Desc<"Export the trace for the specified thread index. Otherwise, the " + "currently selected thread will be used.">; +} diff --git a/gnu/llvm/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp b/gnu/llvm/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp index bc06ea8164d..7150fdc7847 100644 --- a/gnu/llvm/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp +++ b/gnu/llvm/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp @@ -75,7 +75,7 @@ #include "Plugins/SymbolFile/DWARF/DWARFASTParserClang.h" #include "Plugins/SymbolFile/PDB/PDBASTParser.h" -#include +#include #include @@ -148,10 +148,11 @@ void addOverridesForMethod(clang::CXXMethodDecl *decl) { return; clang::CXXBasePaths paths; + llvm::SmallVector decls; auto find_overridden_methods = - [decl](const clang::CXXBaseSpecifier *specifier, - clang::CXXBasePath &path) { + [&decls, decl](const clang::CXXBaseSpecifier *specifier, + clang::CXXBasePath &path) { if (auto *base_record = llvm::dyn_cast( specifier->getType()->getAs()->getDecl())) { @@ -162,19 +163,19 @@ void addOverridesForMethod(clang::CXXMethodDecl *decl) { if (name.getNameKind() == clang::DeclarationName::CXXDestructorName) if (auto *baseDtorDecl = base_record->getDestructor()) { if (baseDtorDecl->isVirtual()) { - path.Decls = baseDtorDecl; + decls.push_back(baseDtorDecl); return true; } else return false; } // Otherwise, search for name in the base class. - for (path.Decls = base_record->lookup(name); !path.Decls.empty(); - path.Decls = path.Decls.slice(1)) { + for (path.Decls = base_record->lookup(name).begin(); + path.Decls != path.Decls.end(); ++path.Decls) { if (auto *method_decl = - llvm::dyn_cast(path.Decls.front())) + llvm::dyn_cast(*path.Decls)) if (method_decl->isVirtual() && !isOverload(decl, method_decl)) { - path.Decls = method_decl; + decls.push_back(method_decl); return true; } } @@ -184,7 +185,7 @@ void addOverridesForMethod(clang::CXXMethodDecl *decl) { }; if (decl->getParent()->lookupInBases(find_overridden_methods, paths)) { - for (auto *overridden_decl : paths.found_decls()) + for (auto *overridden_decl : decls) decl->addOverriddenMethod( llvm::cast(overridden_decl)); } @@ -476,6 +477,9 @@ static void ParseLangArgs(LangOptions &Opts, InputKind IK, const char *triple) { case clang::Language::OpenCL: LangStd = LangStandard::lang_opencl10; break; + case clang::Language::OpenCLCXX: + LangStd = LangStandard::lang_openclcpp; + break; case clang::Language::CUDA: LangStd = LangStandard::lang_cuda; break; @@ -610,7 +614,7 @@ lldb::TypeSystemSP TypeSystemClang::CreateInstance(lldb::LanguageType language, "ASTContext for '" + module->GetFileSpec().GetPath() + "'"; return std::make_shared(ast_name, triple); } else if (target && target->IsValid()) - return std::make_shared(*target, triple); + return std::make_shared(*target, triple); return lldb::TypeSystemSP(); } @@ -683,8 +687,8 @@ void TypeSystemClang::SetTargetTriple(llvm::StringRef target_triple) { void TypeSystemClang::SetExternalSource( llvm::IntrusiveRefCntPtr &ast_source_up) { ASTContext &ast = getASTContext(); - ast.setExternalSource(ast_source_up); ast.getTranslationUnitDecl()->setHasExternalLexicalStorage(true); + ast.setExternalSource(ast_source_up); } ASTContext &TypeSystemClang::getASTContext() { @@ -742,7 +746,7 @@ void TypeSystemClang::CreateASTContext() { *m_diagnostics_engine_up, *m_file_manager_up); m_ast_up = std::make_unique( *m_language_options_up, *m_source_manager_up, *m_identifier_table_up, - *m_selector_table_up, *m_builtins_up); + *m_selector_table_up, *m_builtins_up, TU_Complete); m_diagnostic_consumer_up = std::make_unique(); m_ast_up->getDiagnostics().setClient(m_diagnostic_consumer_up.get(), false); @@ -1353,9 +1357,11 @@ CompilerType TypeSystemClang::CreateRecordType( } namespace { - bool IsValueParam(const clang::TemplateArgument &argument) { - return argument.getKind() == TemplateArgument::Integral; - } +/// Returns true iff the given TemplateArgument should be represented as an +/// NonTypeTemplateParmDecl in the AST. +bool IsValueParam(const clang::TemplateArgument &argument) { + return argument.getKind() == TemplateArgument::Integral; +} } static TemplateParameterList *CreateTemplateParameterList( @@ -1419,7 +1425,7 @@ static TemplateParameterList *CreateTemplateParameterList( clang::FunctionTemplateDecl *TypeSystemClang::CreateFunctionTemplateDecl( clang::DeclContext *decl_ctx, OptionalClangModuleID owning_module, - clang::FunctionDecl *func_decl, const char *name, + clang::FunctionDecl *func_decl, const TemplateParameterInfos &template_param_infos) { // /// Create a function template node. ASTContext &ast = getASTContext(); @@ -1459,6 +1465,99 @@ void TypeSystemClang::CreateFunctionTemplateSpecializationInfo( template_args_ptr, nullptr); } +/// Returns true if the given template parameter can represent the given value. +/// For example, `typename T` can represent `int` but not integral values such +/// as `int I = 3`. +static bool TemplateParameterAllowsValue(NamedDecl *param, + const TemplateArgument &value) { + if (auto *type_param = llvm::dyn_cast(param)) { + // Compare the argument kind, i.e. ensure that != . + if (value.getKind() != TemplateArgument::Type) + return false; + } else if (auto *type_param = + llvm::dyn_cast(param)) { + // Compare the argument kind, i.e. ensure that != . + if (!IsValueParam(value)) + return false; + // Compare the integral type, i.e. ensure that != . + if (type_param->getType() != value.getIntegralType()) + return false; + } else { + // There is no way to create other parameter decls at the moment, so we + // can't reach this case during normal LLDB usage. Log that this happened + // and assert. + Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS); + LLDB_LOG(log, + "Don't know how to compare template parameter to passed" + " value. Decl kind of parameter is: {0}", + param->getDeclKindName()); + lldbassert(false && "Can't compare this TemplateParmDecl subclass"); + // In release builds just fall back to marking the parameter as not + // accepting the value so that we don't try to fit an instantiation to a + // template that doesn't fit. E.g., avoid that `S<1>` is being connected to + // `template struct S;`. + return false; + } + return true; +} + +/// Returns true if the given class template declaration could produce an +/// instantiation with the specified values. +/// For example, `` allows the arguments `float`, but not for +/// example `bool, float` or `3` (as an integer parameter value). +static bool ClassTemplateAllowsToInstantiationArgs( + ClassTemplateDecl *class_template_decl, + const TypeSystemClang::TemplateParameterInfos &instantiation_values) { + + TemplateParameterList ¶ms = *class_template_decl->getTemplateParameters(); + + // Save some work by iterating only once over the found parameters and + // calculate the information related to parameter packs. + + // Contains the first pack parameter (or non if there are none). + llvm::Optional pack_parameter; + // Contains the number of non-pack parameters. + size_t non_pack_params = params.size(); + for (size_t i = 0; i < params.size(); ++i) { + NamedDecl *param = params.getParam(i); + if (param->isParameterPack()) { + pack_parameter = param; + non_pack_params = i; + break; + } + } + + // The found template needs to have compatible non-pack template arguments. + // E.g., ensure that != . + // The pack parameters are compared later. + if (non_pack_params != instantiation_values.args.size()) + return false; + + // Ensure that != . + if (pack_parameter.hasValue() != instantiation_values.hasParameterPack()) + return false; + + // Compare the first pack parameter that was found with the first pack + // parameter value. The special case of having an empty parameter pack value + // always fits to a pack parameter. + // E.g., ensure that != . + if (pack_parameter && !instantiation_values.packed_args->args.empty() && + !TemplateParameterAllowsValue( + *pack_parameter, instantiation_values.packed_args->args.front())) + return false; + + // Compare all the non-pack parameters now. + // E.g., ensure that != . + for (const auto pair : llvm::zip_first(instantiation_values.args, params)) { + const TemplateArgument &passed_arg = std::get<0>(pair); + NamedDecl *found_param = std::get<1>(pair); + if (!TemplateParameterAllowsValue(found_param, passed_arg)) + return false; + } + + return class_template_decl; +} + ClassTemplateDecl *TypeSystemClang::CreateClassTemplateDecl( DeclContext *decl_ctx, OptionalClangModuleID owning_module, lldb::AccessType access_type, const char *class_name, int kind, @@ -1472,12 +1571,22 @@ ClassTemplateDecl *TypeSystemClang::CreateClassTemplateDecl( IdentifierInfo &identifier_info = ast.Idents.get(class_name); DeclarationName decl_name(&identifier_info); + // Search the AST for an existing ClassTemplateDecl that could be reused. clang::DeclContext::lookup_result result = decl_ctx->lookup(decl_name); - for (NamedDecl *decl : result) { class_template_decl = dyn_cast(decl); - if (class_template_decl) - return class_template_decl; + if (!class_template_decl) + continue; + // The class template has to be able to represents the instantiation + // values we received. Without this we might end up putting an instantiation + // with arguments such as to a template such as: + // template struct S; + // Connecting the instantiation to an incompatible template could cause + // problems later on. + if (!ClassTemplateAllowsToInstantiationArgs(class_template_decl, + template_param_infos)) + continue; + return class_template_decl; } llvm::SmallVector template_param_decls; @@ -1657,9 +1766,9 @@ bool TypeSystemClang::FieldIsBitfield(FieldDecl *field, if (field->isBitField()) { Expr *bit_width_expr = field->getBitWidth(); if (bit_width_expr) { - llvm::APSInt bit_width_apsint; - if (bit_width_expr->isIntegerConstantExpr(bit_width_apsint, ast)) { - bitfield_bit_size = bit_width_apsint.getLimitedValue(UINT32_MAX); + if (Optional bit_width_apsint = + bit_width_expr->getIntegerConstantExpr(ast)) { + bitfield_bit_size = bit_width_apsint->getLimitedValue(UINT32_MAX); return true; } } @@ -1863,8 +1972,8 @@ TypeSystemClang::CreateUsingDeclaration(clang::DeclContext *current_decl_ctx, clang::NestedNameSpecifierLoc(), clang::DeclarationNameInfo(), false); SetOwningModule(using_decl, owning_module); clang::UsingShadowDecl *shadow_decl = clang::UsingShadowDecl::Create( - getASTContext(), current_decl_ctx, clang::SourceLocation(), using_decl, - target); + getASTContext(), current_decl_ctx, clang::SourceLocation(), + target->getDeclName(), using_decl, target); SetOwningModule(shadow_decl, owning_module); using_decl->addShadowDecl(shadow_decl); current_decl_ctx->addDecl(using_decl); @@ -1965,11 +2074,8 @@ TypeSystemClang::GetOpaqueCompilerType(clang::ASTContext *ast, #pragma mark Function Types clang::DeclarationName -TypeSystemClang::GetDeclarationName(const char *name, +TypeSystemClang::GetDeclarationName(llvm::StringRef name, const CompilerType &function_clang_type) { - if (!name || !name[0]) - return clang::DeclarationName(); - clang::OverloadedOperatorKind op_kind = clang::NUM_OVERLOADED_OPERATORS; if (!IsOperator(name, op_kind) || op_kind == clang::NUM_OVERLOADED_OPERATORS) return DeclarationName(&getASTContext().Idents.get( @@ -1994,10 +2100,40 @@ TypeSystemClang::GetDeclarationName(const char *name, return getASTContext().DeclarationNames.getCXXOperatorName(op_kind); } +PrintingPolicy TypeSystemClang::GetTypePrintingPolicy() { + clang::PrintingPolicy printing_policy(getASTContext().getPrintingPolicy()); + printing_policy.SuppressTagKeyword = true; + // Inline namespaces are important for some type formatters (e.g., libc++ + // and libstdc++ are differentiated by their inline namespaces). + printing_policy.SuppressInlineNamespace = false; + printing_policy.SuppressUnwrittenScope = false; + // Default arguments are also always important for type formatters. Otherwise + // we would need to always specify two type names for the setups where we do + // know the default arguments and where we don't know default arguments. + // + // For example, without this we would need to have formatters for both: + // std::basic_string + // and + // std::basic_string, std::allocator > + // to support setups where LLDB was able to reconstruct default arguments + // (and we then would have suppressed them from the type name) and also setups + // where LLDB wasn't able to reconstruct the default arguments. + printing_policy.SuppressDefaultTemplateArgs = false; + return printing_policy; +} + +std::string TypeSystemClang::GetTypeNameForDecl(const NamedDecl *named_decl) { + clang::PrintingPolicy printing_policy = GetTypePrintingPolicy(); + std::string result; + llvm::raw_string_ostream os(result); + named_decl->printQualifiedName(os, printing_policy); + return result; +} + FunctionDecl *TypeSystemClang::CreateFunctionDeclaration( clang::DeclContext *decl_ctx, OptionalClangModuleID owning_module, - const char *name, const CompilerType &function_clang_type, int storage, - bool is_inline) { + llvm::StringRef name, const CompilerType &function_clang_type, + clang::StorageClass storage, bool is_inline) { FunctionDecl *func_decl = nullptr; ASTContext &ast = getASTContext(); if (!decl_ctx) @@ -2012,11 +2148,12 @@ FunctionDecl *TypeSystemClang::CreateFunctionDeclaration( func_decl->setDeclContext(decl_ctx); func_decl->setDeclName(declarationName); func_decl->setType(ClangUtil::GetQualType(function_clang_type)); - func_decl->setStorageClass(static_cast(storage)); + func_decl->setStorageClass(storage); func_decl->setInlineSpecified(is_inline); func_decl->setHasWrittenPrototype(hasWrittenPrototype); - func_decl->setConstexprKind(isConstexprSpecified ? CSK_constexpr - : CSK_unspecified); + func_decl->setConstexprKind(isConstexprSpecified + ? ConstexprSpecKind::Constexpr + : ConstexprSpecKind::Unspecified); SetOwningModule(func_decl, owning_module); if (func_decl) decl_ctx->addDecl(func_decl); @@ -2083,11 +2220,10 @@ ParmVarDecl *TypeSystemClang::CreateParameterDeclaration( return decl; } -void TypeSystemClang::SetFunctionParameters(FunctionDecl *function_decl, - ParmVarDecl **params, - unsigned num_params) { +void TypeSystemClang::SetFunctionParameters( + FunctionDecl *function_decl, llvm::ArrayRef params) { if (function_decl) - function_decl->setParams(ArrayRef(params, num_params)); + function_decl->setParams(params); } CompilerType @@ -2439,42 +2575,6 @@ ClangASTMetadata *TypeSystemClang::GetMetadata(const clang::Type *object) { return nullptr; } -bool TypeSystemClang::SetTagTypeKind(clang::QualType tag_qual_type, - int kind) const { - const clang::Type *clang_type = tag_qual_type.getTypePtr(); - if (clang_type) { - const clang::TagType *tag_type = llvm::dyn_cast(clang_type); - if (tag_type) { - clang::TagDecl *tag_decl = - llvm::dyn_cast(tag_type->getDecl()); - if (tag_decl) { - tag_decl->setTagKind((clang::TagDecl::TagKind)kind); - return true; - } - } - } - return false; -} - -bool TypeSystemClang::SetDefaultAccessForRecordFields( - clang::RecordDecl *record_decl, int default_accessibility, - int *assigned_accessibilities, size_t num_assigned_accessibilities) { - if (record_decl) { - uint32_t field_idx; - clang::RecordDecl::field_iterator field, field_end; - for (field = record_decl->field_begin(), - field_end = record_decl->field_end(), field_idx = 0; - field != field_end; ++field, ++field_idx) { - // If no accessibility was assigned, assign the correct one - if (field_idx < num_assigned_accessibilities && - assigned_accessibilities[field_idx] == clang::AS_none) - field->setAccess((clang::AccessSpecifier)default_accessibility); - } - return true; - } - return false; -} - clang::DeclContext * TypeSystemClang::GetDeclContextForType(const CompilerType &type) { return GetDeclContextForType(ClangUtil::GetQualType(type)); @@ -2499,6 +2599,8 @@ RemoveWrappingTypes(QualType type, ArrayRef mask = {}) { case clang::Type::Decltype: case clang::Type::Elaborated: case clang::Type::Paren: + case clang::Type::SubstTemplateTypeParm: + case clang::Type::TemplateSpecialization: case clang::Type::Typedef: case clang::Type::TypeOf: case clang::Type::TypeOfExpr: @@ -2882,20 +2984,11 @@ bool TypeSystemClang::IsCStringType(lldb::opaque_compiler_type_t type, return false; } -bool TypeSystemClang::IsFunctionType(lldb::opaque_compiler_type_t type, - bool *is_variadic_ptr) { +bool TypeSystemClang::IsFunctionType(lldb::opaque_compiler_type_t type) { if (type) { clang::QualType qual_type = RemoveWrappingTypes(GetCanonicalQualType(type)); if (qual_type->isFunctionType()) { - if (is_variadic_ptr) { - const clang::FunctionProtoType *function_proto_type = - llvm::dyn_cast(qual_type.getTypePtr()); - if (function_proto_type) - *is_variadic_ptr = function_proto_type->isVariadic(); - else - *is_variadic_ptr = false; - } return true; } @@ -2908,8 +3001,8 @@ bool TypeSystemClang::IsFunctionType(lldb::opaque_compiler_type_t type, const clang::ReferenceType *reference_type = llvm::cast(qual_type.getTypePtr()); if (reference_type) - return IsFunctionType(reference_type->getPointeeType().getAsOpaquePtr(), - nullptr); + return IsFunctionType( + reference_type->getPointeeType().getAsOpaquePtr()); } break; } } @@ -3123,6 +3216,20 @@ bool TypeSystemClang::IsEnumerationType(lldb::opaque_compiler_type_t type, return false; } +bool TypeSystemClang::IsScopedEnumerationType( + lldb::opaque_compiler_type_t type) { + if (type) { + const clang::EnumType *enum_type = llvm::dyn_cast( + GetCanonicalQualType(type)->getCanonicalTypeInternal()); + + if (enum_type) { + return enum_type->isScopedEnumeralType(); + } + } + + return false; +} + bool TypeSystemClang::IsPointerType(lldb::opaque_compiler_type_t type, CompilerType *pointee_type) { if (type) { @@ -3640,15 +3747,23 @@ ConstString TypeSystemClang::GetTypeName(lldb::opaque_compiler_type_t type) { clang::QualType qual_type(GetQualType(type)); + // Remove certain type sugar from the name. Sugar such as elaborated types + // or template types which only serve to improve diagnostics shouldn't + // act as their own types from the user's perspective (e.g., formatter + // shouldn't format a variable differently depending on how the ser has + // specified the type. '::Type' and 'Type' should behave the same). + // Typedefs and atomic derived types are not removed as they are actually + // useful for identifiying specific types. + qual_type = RemoveWrappingTypes(qual_type, + {clang::Type::Typedef, clang::Type::Atomic}); + // For a typedef just return the qualified name. if (const auto *typedef_type = qual_type->getAs()) { const clang::TypedefNameDecl *typedef_decl = typedef_type->getDecl(); - return ConstString(typedef_decl->getQualifiedNameAsString()); + return ConstString(GetTypeNameForDecl(typedef_decl)); } - clang::PrintingPolicy printing_policy(getASTContext().getPrintingPolicy()); - printing_policy.SuppressTagKeyword = true; - return ConstString(qual_type.getAsString(printing_policy)); + return ConstString(qual_type.getAsString(GetTypePrintingPolicy())); } ConstString @@ -3661,6 +3776,7 @@ TypeSystemClang::GetDisplayTypeName(lldb::opaque_compiler_type_t type) { printing_policy.SuppressTagKeyword = true; printing_policy.SuppressScope = false; printing_policy.SuppressUnwrittenScope = true; + printing_policy.SuppressInlineNamespace = true; return ConstString(qual_type.getAsString(printing_policy)); } @@ -4088,7 +4204,7 @@ unsigned TypeSystemClang::GetTypeQualifiers(lldb::opaque_compiler_type_t type) { CompilerType TypeSystemClang::GetArrayElementType(lldb::opaque_compiler_type_t type, - uint64_t *stride) { + ExecutionContextScope *exe_scope) { if (type) { clang::QualType qual_type(GetQualType(type)); @@ -4098,14 +4214,7 @@ TypeSystemClang::GetArrayElementType(lldb::opaque_compiler_type_t type, if (!array_eletype) return CompilerType(); - CompilerType element_type = GetType(clang::QualType(array_eletype, 0)); - - // TODO: the real stride will be >= this value.. find the real one! - if (stride) - if (Optional size = element_type.GetByteSize(nullptr)) - *stride = *size; - - return element_type; + return GetType(clang::QualType(array_eletype, 0)); } return CompilerType(); } @@ -4155,6 +4264,13 @@ TypeSystemClang::GetFullyUnqualifiedType(lldb::opaque_compiler_type_t type) { return CompilerType(); } +CompilerType +TypeSystemClang::GetEnumerationIntegerType(lldb::opaque_compiler_type_t type) { + if (type) + return GetEnumerationIntegerType(GetType(GetCanonicalQualType(type))); + return CompilerType(); +} + int TypeSystemClang::GetFunctionArgumentCount( lldb::opaque_compiler_type_t type) { if (type) { @@ -4376,39 +4492,6 @@ TypeSystemClang::GetNonReferenceType(lldb::opaque_compiler_type_t type) { return CompilerType(); } -CompilerType TypeSystemClang::CreateTypedefType( - const CompilerType &type, const char *typedef_name, - const CompilerDeclContext &compiler_decl_ctx, uint32_t payload) { - if (type && typedef_name && typedef_name[0]) { - TypeSystemClang *ast = - llvm::dyn_cast(type.GetTypeSystem()); - if (!ast) - return CompilerType(); - clang::ASTContext &clang_ast = ast->getASTContext(); - clang::QualType qual_type(ClangUtil::GetQualType(type)); - - clang::DeclContext *decl_ctx = - TypeSystemClang::DeclContextGetAsDeclContext(compiler_decl_ctx); - if (!decl_ctx) - decl_ctx = ast->getASTContext().getTranslationUnitDecl(); - - clang::TypedefDecl *decl = - clang::TypedefDecl::CreateDeserialized(clang_ast, 0); - decl->setDeclContext(decl_ctx); - decl->setDeclName(&clang_ast.Idents.get(typedef_name)); - decl->setTypeSourceInfo(clang_ast.getTrivialTypeSourceInfo(qual_type)); - - SetOwningModule(decl, TypePayloadClang(payload).GetOwningModule()); - decl->setAccess(clang::AS_public); // TODO respect proper access specifier - - decl_ctx->addDecl(decl); - - // Get a uniqued clang::QualType for the typedef decl type - return ast->GetType(clang_ast.getTypedefType(decl)); - } - return CompilerType(); -} - CompilerType TypeSystemClang::GetPointeeType(lldb::opaque_compiler_type_t type) { if (type) { @@ -4490,7 +4573,7 @@ TypeSystemClang::AddRestrictModifier(lldb::opaque_compiler_type_t type) { CompilerType TypeSystemClang::CreateTypedef( lldb::opaque_compiler_type_t type, const char *typedef_name, const CompilerDeclContext &compiler_decl_ctx, uint32_t payload) { - if (type) { + if (type && typedef_name && typedef_name[0]) { clang::ASTContext &clang_ast = getASTContext(); clang::QualType qual_type(GetQualType(type)); @@ -4499,10 +4582,12 @@ CompilerType TypeSystemClang::CreateTypedef( if (!decl_ctx) decl_ctx = getASTContext().getTranslationUnitDecl(); - clang::TypedefDecl *decl = clang::TypedefDecl::Create( - clang_ast, decl_ctx, clang::SourceLocation(), clang::SourceLocation(), - &clang_ast.Idents.get(typedef_name), - clang_ast.getTrivialTypeSourceInfo(qual_type)); + clang::TypedefDecl *decl = + clang::TypedefDecl::CreateDeserialized(clang_ast, 0); + decl->setDeclContext(decl_ctx); + decl->setDeclName(&clang_ast.Idents.get(typedef_name)); + decl->setTypeSourceInfo(clang_ast.getTrivialTypeSourceInfo(qual_type)); + decl_ctx->addDecl(decl); SetOwningModule(decl, TypePayloadClang(payload).GetOwningModule()); clang::TagDecl *tdecl = nullptr; @@ -4681,7 +4766,6 @@ lldb::Encoding TypeSystemClang::GetEncoding(lldb::opaque_compiler_type_t type, case clang::BuiltinType::Void: break; - case clang::BuiltinType::Bool: case clang::BuiltinType::Char_S: case clang::BuiltinType::SChar: case clang::BuiltinType::WChar_S: @@ -4692,6 +4776,7 @@ lldb::Encoding TypeSystemClang::GetEncoding(lldb::opaque_compiler_type_t type, case clang::BuiltinType::Int128: return lldb::eEncodingSint; + case clang::BuiltinType::Bool: case clang::BuiltinType::Char_U: case clang::BuiltinType::UChar: case clang::BuiltinType::WChar_U: @@ -4816,6 +4901,12 @@ lldb::Encoding TypeSystemClang::GetEncoding(lldb::opaque_compiler_type_t type, case clang::BuiltinType::OCLIntelSubgroupAVCImeDualRefStreamin: break; + // PowerPC -- Matrix Multiply Assist + case clang::BuiltinType::VectorPair: + case clang::BuiltinType::VectorQuad: + break; + + // ARM -- Scalable Vector Extension case clang::BuiltinType::SveBool: case clang::BuiltinType::SveInt8: case clang::BuiltinType::SveInt8x2: @@ -4867,6 +4958,75 @@ lldb::Encoding TypeSystemClang::GetEncoding(lldb::opaque_compiler_type_t type, case clang::BuiltinType::SveFloat64x4: break; + // RISC-V V builtin types. + case clang::BuiltinType::RvvInt8mf8: + case clang::BuiltinType::RvvInt8mf4: + case clang::BuiltinType::RvvInt8mf2: + case clang::BuiltinType::RvvInt8m1: + case clang::BuiltinType::RvvInt8m2: + case clang::BuiltinType::RvvInt8m4: + case clang::BuiltinType::RvvInt8m8: + case clang::BuiltinType::RvvUint8mf8: + case clang::BuiltinType::RvvUint8mf4: + case clang::BuiltinType::RvvUint8mf2: + case clang::BuiltinType::RvvUint8m1: + case clang::BuiltinType::RvvUint8m2: + case clang::BuiltinType::RvvUint8m4: + case clang::BuiltinType::RvvUint8m8: + case clang::BuiltinType::RvvInt16mf4: + case clang::BuiltinType::RvvInt16mf2: + case clang::BuiltinType::RvvInt16m1: + case clang::BuiltinType::RvvInt16m2: + case clang::BuiltinType::RvvInt16m4: + case clang::BuiltinType::RvvInt16m8: + case clang::BuiltinType::RvvUint16mf4: + case clang::BuiltinType::RvvUint16mf2: + case clang::BuiltinType::RvvUint16m1: + case clang::BuiltinType::RvvUint16m2: + case clang::BuiltinType::RvvUint16m4: + case clang::BuiltinType::RvvUint16m8: + case clang::BuiltinType::RvvInt32mf2: + case clang::BuiltinType::RvvInt32m1: + case clang::BuiltinType::RvvInt32m2: + case clang::BuiltinType::RvvInt32m4: + case clang::BuiltinType::RvvInt32m8: + case clang::BuiltinType::RvvUint32mf2: + case clang::BuiltinType::RvvUint32m1: + case clang::BuiltinType::RvvUint32m2: + case clang::BuiltinType::RvvUint32m4: + case clang::BuiltinType::RvvUint32m8: + case clang::BuiltinType::RvvInt64m1: + case clang::BuiltinType::RvvInt64m2: + case clang::BuiltinType::RvvInt64m4: + case clang::BuiltinType::RvvInt64m8: + case clang::BuiltinType::RvvUint64m1: + case clang::BuiltinType::RvvUint64m2: + case clang::BuiltinType::RvvUint64m4: + case clang::BuiltinType::RvvUint64m8: + case clang::BuiltinType::RvvFloat16mf4: + case clang::BuiltinType::RvvFloat16mf2: + case clang::BuiltinType::RvvFloat16m1: + case clang::BuiltinType::RvvFloat16m2: + case clang::BuiltinType::RvvFloat16m4: + case clang::BuiltinType::RvvFloat16m8: + case clang::BuiltinType::RvvFloat32mf2: + case clang::BuiltinType::RvvFloat32m1: + case clang::BuiltinType::RvvFloat32m2: + case clang::BuiltinType::RvvFloat32m4: + case clang::BuiltinType::RvvFloat32m8: + case clang::BuiltinType::RvvFloat64m1: + case clang::BuiltinType::RvvFloat64m2: + case clang::BuiltinType::RvvFloat64m4: + case clang::BuiltinType::RvvFloat64m8: + case clang::BuiltinType::RvvBool1: + case clang::BuiltinType::RvvBool2: + case clang::BuiltinType::RvvBool4: + case clang::BuiltinType::RvvBool8: + case clang::BuiltinType::RvvBool16: + case clang::BuiltinType::RvvBool32: + case clang::BuiltinType::RvvBool64: + break; + case clang::BuiltinType::IncompleteMatrixIdx: break; } @@ -6343,7 +6503,7 @@ CompilerType TypeSystemClang::GetChildCompilerTypeAtIndex( case clang::Type::RValueReference: if (idx_is_valid) { const clang::ReferenceType *reference_type = - llvm::cast(parent_qual_type.getTypePtr()); + llvm::cast(GetQualType(type).getTypePtr()); CompilerType pointee_clang_type = GetType(reference_type->getPointeeType()); if (transparent_pointers && pointee_clang_type.IsAggregateType()) { @@ -6514,8 +6674,11 @@ size_t TypeSystemClang::GetIndexOfChildMemberWithName( if (cxx_record_decl->lookupInBases( [decl_name](const clang::CXXBaseSpecifier *specifier, clang::CXXBasePath &path) { - return clang::CXXRecordDecl::FindOrdinaryMember( - specifier, path, decl_name); + CXXRecordDecl *record = + specifier->getType()->getAsCXXRecordDecl(); + auto r = record->lookup(decl_name); + path.Decls = r.begin(); + return !r.empty(); }, paths)) { clang::CXXBasePaths::const_paths_iterator path, @@ -6538,9 +6701,10 @@ size_t TypeSystemClang::GetIndexOfChildMemberWithName( ->getDecl()); } } - for (clang::NamedDecl *path_decl : path->Decls) { + for (clang::DeclContext::lookup_iterator I = path->Decls, E; + I != E; ++I) { child_idx = GetIndexForRecordChild( - parent_record_decl, path_decl, omit_empty_base_classes); + parent_record_decl, *I, omit_empty_base_classes); if (child_idx == UINT32_MAX) { child_indexes.clear(); return 0; @@ -7399,7 +7563,7 @@ clang::CXXMethodDecl *TypeSystemClang::AddMethodToCXXRecordType( cxx_dtor_decl->setType(method_qual_type); cxx_dtor_decl->setImplicit(is_artificial); cxx_dtor_decl->setInlineSpecified(is_inline); - cxx_dtor_decl->setConstexprKind(CSK_unspecified); + cxx_dtor_decl->setConstexprKind(ConstexprSpecKind::Unspecified); cxx_method_decl = cxx_dtor_decl; } else if (decl_name == cxx_record_decl->getDeclName()) { cxx_ctor_decl = clang::CXXConstructorDecl::CreateDeserialized( @@ -7411,7 +7575,7 @@ clang::CXXMethodDecl *TypeSystemClang::AddMethodToCXXRecordType( cxx_ctor_decl->setType(method_qual_type); cxx_ctor_decl->setImplicit(is_artificial); cxx_ctor_decl->setInlineSpecified(is_inline); - cxx_ctor_decl->setConstexprKind(CSK_unspecified); + cxx_ctor_decl->setConstexprKind(ConstexprSpecKind::Unspecified); cxx_ctor_decl->setNumCtorInitializers(0); cxx_ctor_decl->setExplicitSpecifier(explicit_spec); cxx_method_decl = cxx_ctor_decl; @@ -7437,7 +7601,7 @@ clang::CXXMethodDecl *TypeSystemClang::AddMethodToCXXRecordType( cxx_method_decl->setType(method_qual_type); cxx_method_decl->setStorageClass(SC); cxx_method_decl->setInlineSpecified(is_inline); - cxx_method_decl->setConstexprKind(CSK_unspecified); + cxx_method_decl->setConstexprKind(ConstexprSpecKind::Unspecified); } else if (num_params == 0) { // Conversion operators don't take params... auto *cxx_conversion_decl = @@ -7450,7 +7614,7 @@ clang::CXXMethodDecl *TypeSystemClang::AddMethodToCXXRecordType( cxx_conversion_decl->setType(method_qual_type); cxx_conversion_decl->setInlineSpecified(is_inline); cxx_conversion_decl->setExplicitSpecifier(explicit_spec); - cxx_conversion_decl->setConstexprKind(CSK_unspecified); + cxx_conversion_decl->setConstexprKind(ConstexprSpecKind::Unspecified); cxx_method_decl = cxx_conversion_decl; } } @@ -7463,7 +7627,7 @@ clang::CXXMethodDecl *TypeSystemClang::AddMethodToCXXRecordType( cxx_method_decl->setType(method_qual_type); cxx_method_decl->setInlineSpecified(is_inline); cxx_method_decl->setStorageClass(SC); - cxx_method_decl->setConstexprKind(CSK_unspecified); + cxx_method_decl->setConstexprKind(ConstexprSpecKind::Unspecified); } } SetMemberOwningModule(cxx_method_decl, cxx_record_decl); @@ -8925,8 +9089,7 @@ void TypeSystemClang::DumpTypeDescription(lldb::opaque_compiler_type_t type, if (level == eDescriptionLevelVerbose) typedef_decl->dump(llvm_ostrm); else { - std::string clang_typedef_name( - typedef_decl->getQualifiedNameAsString()); + std::string clang_typedef_name(GetTypeNameForDecl(typedef_decl)); if (!clang_typedef_name.empty()) { s->PutCString("typedef "); s->PutCString(clang_typedef_name); @@ -9211,11 +9374,11 @@ CompilerType TypeSystemClang::DeclGetFunctionArgumentType(void *opaque_decl, std::vector TypeSystemClang::DeclContextFindDeclByName( void *opaque_decl_ctx, ConstString name, const bool ignore_using_decls) { std::vector found_decls; - if (opaque_decl_ctx) { + SymbolFile *symbol_file = GetSymbolFile(); + if (opaque_decl_ctx && symbol_file) { DeclContext *root_decl_ctx = (DeclContext *)opaque_decl_ctx; std::set searched; std::multimap search_queue; - SymbolFile *symbol_file = GetSymbolFile(); for (clang::DeclContext *decl_context = root_decl_ctx; decl_context != nullptr && found_decls.empty(); @@ -9309,10 +9472,10 @@ uint32_t TypeSystemClang::CountDeclLevels(clang::DeclContext *frame_decl_ctx, clang::DeclContext *child_decl_ctx, ConstString *child_name, CompilerType *child_type) { - if (frame_decl_ctx) { + SymbolFile *symbol_file = GetSymbolFile(); + if (frame_decl_ctx && symbol_file) { std::set searched; std::multimap search_queue; - SymbolFile *symbol_file = GetSymbolFile(); // Get the lookup scope for the decl we're trying to find. clang::DeclContext *parent_decl_ctx = child_decl_ctx->getParent(); @@ -9403,8 +9566,7 @@ TypeSystemClang::DeclContextGetScopeQualifiedName(void *opaque_decl_ctx) { clang::NamedDecl *named_decl = llvm::dyn_cast((clang::DeclContext *)opaque_decl_ctx); if (named_decl) - return ConstString( - llvm::StringRef(named_decl->getQualifiedNameAsString())); + return ConstString(GetTypeNameForDecl(named_decl)); } return ConstString(); } @@ -9525,29 +9687,78 @@ TypeSystemClang::DeclContextGetTypeSystemClang(const CompilerDeclContext &dc) { return nullptr; } -TypeSystemClangForExpressions::TypeSystemClangForExpressions( - Target &target, llvm::Triple triple) - : TypeSystemClang("scratch ASTContext", triple), +namespace { +/// A specialized scratch AST used within ScratchTypeSystemClang. +/// These are the ASTs backing the different IsolatedASTKinds. They behave +/// like a normal ScratchTypeSystemClang but they don't own their own +/// persistent storage or target reference. +class SpecializedScratchAST : public TypeSystemClang { +public: + /// \param name The display name of the TypeSystemClang instance. + /// \param triple The triple used for the TypeSystemClang instance. + /// \param ast_source The ClangASTSource that should be used to complete + /// type information. + SpecializedScratchAST(llvm::StringRef name, llvm::Triple triple, + std::unique_ptr ast_source) + : TypeSystemClang(name, triple), + m_scratch_ast_source_up(std::move(ast_source)) { + // Setup the ClangASTSource to complete this AST. + m_scratch_ast_source_up->InstallASTContext(*this); + llvm::IntrusiveRefCntPtr proxy_ast_source( + m_scratch_ast_source_up->CreateProxy()); + SetExternalSource(proxy_ast_source); + } + + /// The ExternalASTSource that performs lookups and completes types. + std::unique_ptr m_scratch_ast_source_up; +}; +} // namespace + +char ScratchTypeSystemClang::ID; +const llvm::NoneType ScratchTypeSystemClang::DefaultAST = llvm::None; + +ScratchTypeSystemClang::ScratchTypeSystemClang(Target &target, + llvm::Triple triple) + : TypeSystemClang("scratch ASTContext", triple), m_triple(triple), m_target_wp(target.shared_from_this()), - m_persistent_variables(new ClangPersistentVariables) { - m_scratch_ast_source_up = std::make_unique( - target.shared_from_this(), m_persistent_variables->GetClangASTImporter()); + m_persistent_variables( + new ClangPersistentVariables(target.shared_from_this())) { + m_scratch_ast_source_up = CreateASTSource(); m_scratch_ast_source_up->InstallASTContext(*this); llvm::IntrusiveRefCntPtr proxy_ast_source( m_scratch_ast_source_up->CreateProxy()); SetExternalSource(proxy_ast_source); } -void TypeSystemClangForExpressions::Finalize() { +void ScratchTypeSystemClang::Finalize() { TypeSystemClang::Finalize(); m_scratch_ast_source_up.reset(); } -UserExpression *TypeSystemClangForExpressions::GetUserExpression( +TypeSystemClang * +ScratchTypeSystemClang::GetForTarget(Target &target, + llvm::Optional ast_kind, + bool create_on_demand) { + auto type_system_or_err = target.GetScratchTypeSystemForLanguage( + lldb::eLanguageTypeC, create_on_demand); + if (auto err = type_system_or_err.takeError()) { + LLDB_LOG_ERROR(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_TARGET), + std::move(err), "Couldn't get scratch TypeSystemClang"); + return nullptr; + } + ScratchTypeSystemClang &scratch_ast = + llvm::cast(type_system_or_err.get()); + // If no dedicated sub-AST was requested, just return the main AST. + if (ast_kind == DefaultAST) + return &scratch_ast; + // Search the sub-ASTs. + return &scratch_ast.GetIsolatedAST(*ast_kind); +} + +UserExpression *ScratchTypeSystemClang::GetUserExpression( llvm::StringRef expr, llvm::StringRef prefix, lldb::LanguageType language, Expression::ResultType desired_type, - const EvaluateExpressionOptions &options, - ValueObject *ctx_obj) { + const EvaluateExpressionOptions &options, ValueObject *ctx_obj) { TargetSP target_sp = m_target_wp.lock(); if (!target_sp) return nullptr; @@ -9556,7 +9767,7 @@ UserExpression *TypeSystemClangForExpressions::GetUserExpression( desired_type, options, ctx_obj); } -FunctionCaller *TypeSystemClangForExpressions::GetFunctionCaller( +FunctionCaller *ScratchTypeSystemClang::GetFunctionCaller( const CompilerType &return_type, const Address &function_address, const ValueList &arg_value_list, const char *name) { TargetSP target_sp = m_target_wp.lock(); @@ -9571,17 +9782,57 @@ FunctionCaller *TypeSystemClangForExpressions::GetFunctionCaller( arg_value_list, name); } -UtilityFunction * -TypeSystemClangForExpressions::GetUtilityFunction(const char *text, - const char *name) { +std::unique_ptr +ScratchTypeSystemClang::CreateUtilityFunction(std::string text, + std::string name) { TargetSP target_sp = m_target_wp.lock(); if (!target_sp) - return nullptr; + return {}; - return new ClangUtilityFunction(*target_sp.get(), text, name); + return std::make_unique( + *target_sp.get(), std::move(text), std::move(name), + target_sp->GetDebugUtilityExpression()); } PersistentExpressionState * -TypeSystemClangForExpressions::GetPersistentExpressionState() { +ScratchTypeSystemClang::GetPersistentExpressionState() { return m_persistent_variables.get(); } + +void ScratchTypeSystemClang::ForgetSource(ASTContext *src_ctx, + ClangASTImporter &importer) { + // Remove it as a source from the main AST. + importer.ForgetSource(&getASTContext(), src_ctx); + // Remove it as a source from all created sub-ASTs. + for (const auto &a : m_isolated_asts) + importer.ForgetSource(&a.second->getASTContext(), src_ctx); +} + +std::unique_ptr ScratchTypeSystemClang::CreateASTSource() { + return std::make_unique( + m_target_wp.lock()->shared_from_this(), + m_persistent_variables->GetClangASTImporter()); +} + +static llvm::StringRef +GetSpecializedASTName(ScratchTypeSystemClang::IsolatedASTKind feature) { + switch (feature) { + case ScratchTypeSystemClang::IsolatedASTKind::CppModules: + return "scratch ASTContext for C++ module types"; + } + llvm_unreachable("Unimplemented ASTFeature kind?"); +} + +TypeSystemClang &ScratchTypeSystemClang::GetIsolatedAST( + ScratchTypeSystemClang::IsolatedASTKind feature) { + auto found_ast = m_isolated_asts.find(feature); + if (found_ast != m_isolated_asts.end()) + return *found_ast->second; + + // Couldn't find the requested sub-AST, so create it now. + std::unique_ptr new_ast; + new_ast.reset(new SpecializedScratchAST(GetSpecializedASTName(feature), + m_triple, CreateASTSource())); + m_isolated_asts[feature] = std::move(new_ast); + return *m_isolated_asts[feature]; +} diff --git a/gnu/llvm/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h b/gnu/llvm/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h index 9475e4d9f44..701e4ca42e3 100644 --- a/gnu/llvm/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h +++ b/gnu/llvm/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h @@ -9,7 +9,7 @@ #ifndef LLDB_SOURCE_PLUGINS_TYPESYSTEM_CLANG_TYPESYSTEMCLANG_H #define LLDB_SOURCE_PLUGINS_TYPESYSTEM_CLANG_TYPESYSTEMCLANG_H -#include +#include #include #include @@ -156,18 +156,6 @@ public: static TypeSystemClang *GetASTContext(clang::ASTContext *ast_ctx); - static TypeSystemClang *GetScratch(Target &target, - bool create_on_demand = true) { - auto type_system_or_err = target.GetScratchTypeSystemForLanguage( - lldb::eLanguageTypeC, create_on_demand); - if (auto err = type_system_or_err.takeError()) { - LLDB_LOG_ERROR(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_TARGET), - std::move(err), "Couldn't get scratch TypeSystemClang"); - return nullptr; - } - return llvm::dyn_cast(&type_system_or_err.get()); - } - /// Returns the display name of this TypeSystemClang that indicates what /// purpose it serves in LLDB. Used for example in logs. llvm::StringRef getDisplayName() const { return m_display_name; } @@ -277,7 +265,7 @@ public: clang::DeclContext::lookup_result result = decl_context->lookup(myName); if (!result.empty()) { - clang::NamedDecl *named_decl = result[0]; + clang::NamedDecl *named_decl = *result.begin(); if (const RecordDeclType *record_decl = llvm::dyn_cast(named_decl)) compiler_type.SetCompilerType( @@ -332,13 +320,16 @@ public: class TemplateParameterInfos { public: bool IsValid() const { - if (args.empty()) + // Having a pack name but no packed args doesn't make sense, so mark + // these template parameters as invalid. + if (pack_name && !packed_args) return false; return args.size() == names.size() && - ((bool)pack_name == (bool)packed_args) && (!packed_args || !packed_args->packed_args); } + bool hasParameterPack() const { return static_cast(packed_args); } + llvm::SmallVector names; llvm::SmallVector args; @@ -346,11 +337,9 @@ public: std::unique_ptr packed_args; }; - clang::FunctionTemplateDecl * - CreateFunctionTemplateDecl(clang::DeclContext *decl_ctx, - OptionalClangModuleID owning_module, - clang::FunctionDecl *func_decl, const char *name, - const TemplateParameterInfos &infos); + clang::FunctionTemplateDecl *CreateFunctionTemplateDecl( + clang::DeclContext *decl_ctx, OptionalClangModuleID owning_module, + clang::FunctionDecl *func_decl, const TemplateParameterInfos &infos); void CreateFunctionTemplateSpecializationInfo( clang::FunctionDecl *func_decl, clang::FunctionTemplateDecl *Template, @@ -391,13 +380,6 @@ public: bool isForwardDecl, bool isInternal, ClangASTMetadata *metadata = nullptr); - bool SetTagTypeKind(clang::QualType type, int kind) const; - - bool SetDefaultAccessForRecordFields(clang::RecordDecl *record_decl, - int default_accessibility, - int *assigned_accessibilities, - size_t num_assigned_accessibilities); - // Returns a mask containing bits from the TypeSystemClang::eTypeXXX // enumerations @@ -410,11 +392,10 @@ public: // Function Types - clang::FunctionDecl * - CreateFunctionDeclaration(clang::DeclContext *decl_ctx, - OptionalClangModuleID owning_module, - const char *name, const CompilerType &function_Type, - int storage, bool is_inline); + clang::FunctionDecl *CreateFunctionDeclaration( + clang::DeclContext *decl_ctx, OptionalClangModuleID owning_module, + llvm::StringRef name, const CompilerType &function_Type, + clang::StorageClass storage, bool is_inline); CompilerType CreateFunctionType(const CompilerType &result_type, const CompilerType *args, unsigned num_args, @@ -435,7 +416,7 @@ public: int storage, bool add_decl = false); void SetFunctionParameters(clang::FunctionDecl *function_decl, - clang::ParmVarDecl **params, unsigned num_params); + llvm::ArrayRef params); CompilerType CreateBlockPointerType(const CompilerType &function_type); @@ -592,8 +573,7 @@ public: bool IsFloatingPointType(lldb::opaque_compiler_type_t type, uint32_t &count, bool &is_complex) override; - bool IsFunctionType(lldb::opaque_compiler_type_t type, - bool *is_variadic_ptr) override; + bool IsFunctionType(lldb::opaque_compiler_type_t type) override; uint32_t IsHomogeneousAggregate(lldb::opaque_compiler_type_t type, CompilerType *base_type_ptr) override; @@ -615,6 +595,8 @@ public: bool IsEnumerationType(lldb::opaque_compiler_type_t type, bool &is_signed) override; + bool IsScopedEnumerationType(lldb::opaque_compiler_type_t type) override; + static bool IsObjCClassType(const CompilerType &type); static bool IsObjCClassTypeAndHasIVars(const CompilerType &type, @@ -680,16 +662,8 @@ public: // Creating related types - /// Using the current type, create a new typedef to that type using - /// "typedef_name" as the name and "decl_ctx" as the decl context. - /// \param payload is an opaque TypePayloadClang. - static CompilerType - CreateTypedefType(const CompilerType &type, const char *typedef_name, - const CompilerDeclContext &compiler_decl_ctx, - uint32_t opaque_payload); - CompilerType GetArrayElementType(lldb::opaque_compiler_type_t type, - uint64_t *stride) override; + ExecutionContextScope *exe_scope) override; CompilerType GetArrayType(lldb::opaque_compiler_type_t type, uint64_t size) override; @@ -699,6 +673,9 @@ public: CompilerType GetFullyUnqualifiedType(lldb::opaque_compiler_type_t type) override; + CompilerType + GetEnumerationIntegerType(lldb::opaque_compiler_type_t type) override; + // Returns -1 if this isn't a function of if the function doesn't have a // prototype Returns a value >= 0 if there is a prototype. int GetFunctionArgumentCount(lldb::opaque_compiler_type_t type) override; @@ -735,6 +712,9 @@ public: CompilerType AddRestrictModifier(lldb::opaque_compiler_type_t type) override; + /// Using the current type, create a new typedef to that type using + /// "typedef_name" as the name and "decl_ctx" as the decl context. + /// \param opaque_payload is an opaque TypePayloadClang. CompilerType CreateTypedef(lldb::opaque_compiler_type_t type, const char *name, const CompilerDeclContext &decl_ctx, @@ -1055,7 +1035,8 @@ public: } clang::DeclarationName - GetDeclarationName(const char *name, const CompilerType &function_clang_type); + GetDeclarationName(llvm::StringRef name, + const CompilerType &function_clang_type); clang::LangOptions *GetLangOpts() const { return m_language_options_up.get(); @@ -1065,6 +1046,13 @@ public: } private: + /// Returns the PrintingPolicy used when generating the internal type names. + /// These type names are mostly used for the formatter selection. + clang::PrintingPolicy GetTypePrintingPolicy(); + /// Returns the internal type name for the given NamedDecl using the + /// type printing policy. + std::string GetTypeNameForDecl(const clang::NamedDecl *named_decl); + const clang::ClassTemplateSpecializationDecl * GetAsTemplateSpecialization(lldb::opaque_compiler_type_t type); @@ -1116,14 +1104,71 @@ private: /// The TypeSystemClang instance used for the scratch ASTContext in a /// lldb::Target. -class TypeSystemClangForExpressions : public TypeSystemClang { +class ScratchTypeSystemClang : public TypeSystemClang { + /// LLVM RTTI support + static char ID; + public: - TypeSystemClangForExpressions(Target &target, llvm::Triple triple); + ScratchTypeSystemClang(Target &target, llvm::Triple triple); - ~TypeSystemClangForExpressions() override = default; + ~ScratchTypeSystemClang() override = default; void Finalize() override; + /// The different kinds of isolated ASTs within the scratch TypeSystem. + /// + /// These ASTs are isolated from the main scratch AST and are each + /// dedicated to a special language option/feature that makes the contained + /// AST nodes incompatible with other AST nodes. + enum IsolatedASTKind { + /// The isolated AST for declarations/types from expressions that imported + /// type information from a C++ module. The templates from a C++ module + /// often conflict with the templates we generate from debug information, + /// so we put these types in their own AST. + CppModules + }; + + /// Alias for requesting the default scratch TypeSystemClang in GetForTarget. + // This isn't constexpr as gtest/llvm::Optional comparison logic is trying + // to get the address of this for pretty-printing. + static const llvm::NoneType DefaultAST; + + /// Infers the appropriate sub-AST from Clang's LangOptions. + static llvm::Optional + InferIsolatedASTKindFromLangOpts(const clang::LangOptions &l) { + // If modules are activated we want the dedicated C++ module AST. + // See IsolatedASTKind::CppModules for more info. + if (l.Modules) + return IsolatedASTKind::CppModules; + return DefaultAST; + } + + /// Returns the scratch TypeSystemClang for the given target. + /// \param target The Target which scratch TypeSystemClang should be returned. + /// \param ast_kind Allows requesting a specific sub-AST instead of the + /// default scratch AST. See also `IsolatedASTKind`. + /// \param create_on_demand If the scratch TypeSystemClang instance can be + /// created by this call if it doesn't exist yet. If it doesn't exist yet and + /// this parameter is false, this function returns a nullptr. + /// \return The scratch type system of the target or a nullptr in case an + /// error occurred. + static TypeSystemClang * + GetForTarget(Target &target, + llvm::Optional ast_kind = DefaultAST, + bool create_on_demand = true); + + /// Returns the scratch TypeSystemClang for the given target. The returned + /// TypeSystemClang will be the scratch AST or a sub-AST, depending on which + /// fits best to the passed LangOptions. + /// \param target The Target which scratch TypeSystemClang should be returned. + /// \param lang_opts The LangOptions of a clang ASTContext that the caller + /// wants to export type information from. This is used to + /// find the best matching sub-AST that will be returned. + static TypeSystemClang *GetForTarget(Target &target, + const clang::LangOptions &lang_opts) { + return GetForTarget(target, InferIsolatedASTKindFromLangOpts(lang_opts)); + } + UserExpression * GetUserExpression(llvm::StringRef expr, llvm::StringRef prefix, lldb::LanguageType language, @@ -1136,16 +1181,48 @@ public: const ValueList &arg_value_list, const char *name) override; - UtilityFunction *GetUtilityFunction(const char *text, - const char *name) override; + std::unique_ptr + CreateUtilityFunction(std::string text, std::string name) override; PersistentExpressionState *GetPersistentExpressionState() override; + + /// Unregisters the given ASTContext as a source from the scratch AST (and + /// all sub-ASTs). + /// \see ClangASTImporter::ForgetSource + void ForgetSource(clang::ASTContext *src_ctx, ClangASTImporter &importer); + + // llvm casting support + bool isA(const void *ClassID) const override { + return ClassID == &ID || TypeSystemClang::isA(ClassID); + } + static bool classof(const TypeSystem *ts) { return ts->isA(&ID); } + private: + std::unique_ptr CreateASTSource(); + /// Returns the requested sub-AST. + /// Will lazily create the sub-AST if it hasn't been created before. + TypeSystemClang &GetIsolatedAST(IsolatedASTKind feature); + + /// The target triple. + /// This was potentially adjusted and might not be identical to the triple + /// of `m_target_wp`. + llvm::Triple m_triple; lldb::TargetWP m_target_wp; - std::unique_ptr - m_persistent_variables; // These are the persistent variables associated - // with this process for the expression parser + /// The persistent variables associated with this process for the expression + /// parser. + std::unique_ptr m_persistent_variables; + /// The ExternalASTSource that performs lookups and completes minimally + /// imported types. std::unique_ptr m_scratch_ast_source_up; + + // FIXME: GCC 5.x doesn't support enum as map keys. + typedef int IsolatedASTKey; + + /// Map from IsolatedASTKind to their actual TypeSystemClang instance. + /// This map is lazily filled with sub-ASTs and should be accessed via + /// `GetSubAST` (which lazily fills this map). + std::unordered_map> + m_isolated_asts; }; } // namespace lldb_private diff --git a/gnu/llvm/lldb/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp b/gnu/llvm/lldb/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp index 1bc071c2b16..65947c5f833 100644 --- a/gnu/llvm/lldb/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp +++ b/gnu/llvm/lldb/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp @@ -38,10 +38,10 @@ bool UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly( ProcessSP process_sp(thread.GetProcess()); if (process_sp) { Status error; - const bool prefer_file_cache = true; + const bool force_live_memory = true; if (process_sp->GetTarget().ReadMemory( - range.GetBaseAddress(), prefer_file_cache, function_text.data(), - range.GetByteSize(), error) != range.GetByteSize()) { + range.GetBaseAddress(), function_text.data(), range.GetByteSize(), + error, force_live_memory) != range.GetByteSize()) { return false; } } diff --git a/gnu/llvm/lldb/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp b/gnu/llvm/lldb/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp index fe1275d5b0c..402a70cd025 100644 --- a/gnu/llvm/lldb/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp +++ b/gnu/llvm/lldb/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp @@ -51,12 +51,11 @@ bool UnwindAssembly_x86::GetNonCallSiteUnwindPlanFromAssembly( ProcessSP process_sp(thread.GetProcess()); if (process_sp.get() == nullptr) return false; - const bool prefer_file_cache = true; std::vector function_text(func.GetByteSize()); Status error; if (process_sp->GetTarget().ReadMemory( - func.GetBaseAddress(), prefer_file_cache, function_text.data(), - func.GetByteSize(), error) == func.GetByteSize()) { + func.GetBaseAddress(), function_text.data(), func.GetByteSize(), + error) == func.GetByteSize()) { RegisterContextSP reg_ctx(thread.GetRegisterContext()); m_assembly_inspection_engine->Initialize(reg_ctx); return m_assembly_inspection_engine->GetNonCallSiteUnwindPlanFromAssembly( @@ -153,12 +152,11 @@ bool UnwindAssembly_x86::AugmentUnwindPlanFromCallSite( return false; if (m_assembly_inspection_engine == nullptr) return false; - const bool prefer_file_cache = true; std::vector function_text(func.GetByteSize()); Status error; if (process_sp->GetTarget().ReadMemory( - func.GetBaseAddress(), prefer_file_cache, function_text.data(), - func.GetByteSize(), error) == func.GetByteSize()) { + func.GetBaseAddress(), function_text.data(), func.GetByteSize(), + error) == func.GetByteSize()) { RegisterContextSP reg_ctx(thread.GetRegisterContext()); m_assembly_inspection_engine->Initialize(reg_ctx); return m_assembly_inspection_engine->AugmentUnwindPlanFromCallSite( @@ -185,10 +183,9 @@ bool UnwindAssembly_x86::GetFastUnwindPlan(AddressRange &func, Thread &thread, ProcessSP process_sp = thread.GetProcess(); if (process_sp) { Target &target(process_sp->GetTarget()); - const bool prefer_file_cache = true; Status error; - if (target.ReadMemory(func.GetBaseAddress(), prefer_file_cache, - opcode_data.data(), 4, error) == 4) { + if (target.ReadMemory(func.GetBaseAddress(), opcode_data.data(), 4, + error) == 4) { uint8_t i386_push_mov[] = {0x55, 0x89, 0xe5}; uint8_t x86_64_push_mov[] = {0x55, 0x48, 0x89, 0xe5}; @@ -220,12 +217,10 @@ bool UnwindAssembly_x86::FirstNonPrologueInsn( if (m_assembly_inspection_engine == nullptr) return false; - const bool prefer_file_cache = true; std::vector function_text(func.GetByteSize()); Status error; - if (target->ReadMemory(func.GetBaseAddress(), prefer_file_cache, - function_text.data(), func.GetByteSize(), - error) == func.GetByteSize()) { + if (target->ReadMemory(func.GetBaseAddress(), function_text.data(), + func.GetByteSize(), error) == func.GetByteSize()) { size_t offset; if (m_assembly_inspection_engine->FindFirstNonPrologueInstruction( function_text.data(), func.GetByteSize(), offset)) { diff --git a/gnu/llvm/lldb/source/Symbol/ArmUnwindInfo.cpp b/gnu/llvm/lldb/source/Symbol/ArmUnwindInfo.cpp index f2887035e5c..07852485f44 100644 --- a/gnu/llvm/lldb/source/Symbol/ArmUnwindInfo.cpp +++ b/gnu/llvm/lldb/source/Symbol/ArmUnwindInfo.cpp @@ -68,7 +68,7 @@ ArmUnwindInfo::ArmUnwindInfo(ObjectFile &objfile, SectionSP &arm_exidx, llvm::sort(m_exidx_entries.begin(), m_exidx_entries.end()); } -ArmUnwindInfo::~ArmUnwindInfo() {} +ArmUnwindInfo::~ArmUnwindInfo() = default; // Read a byte from the unwind instruction stream with the given offset. Custom // function is required because have to red in order of significance within diff --git a/gnu/llvm/lldb/source/Symbol/Block.cpp b/gnu/llvm/lldb/source/Symbol/Block.cpp index afcdf3e21e1..fc246ac8575 100644 --- a/gnu/llvm/lldb/source/Symbol/Block.cpp +++ b/gnu/llvm/lldb/source/Symbol/Block.cpp @@ -25,7 +25,7 @@ Block::Block(lldb::user_id_t uid) m_inlineInfoSP(), m_variable_list_sp(), m_parsed_block_info(false), m_parsed_block_variables(false), m_parsed_child_blocks(false) {} -Block::~Block() {} +Block::~Block() = default; void Block::GetDescription(Stream *s, Function *function, lldb::DescriptionLevel level, Target *target) const { diff --git a/gnu/llvm/lldb/source/Symbol/CMakeLists.txt b/gnu/llvm/lldb/source/Symbol/CMakeLists.txt index 95bf156ff53..c983ceb519c 100644 --- a/gnu/llvm/lldb/source/Symbol/CMakeLists.txt +++ b/gnu/llvm/lldb/source/Symbol/CMakeLists.txt @@ -14,7 +14,6 @@ add_lldb_library(lldbSymbol CompilerType.cpp DWARFCallFrameInfo.cpp DebugMacros.cpp - Declaration.cpp DeclVendor.cpp FuncUnwinders.cpp Function.cpp @@ -45,7 +44,6 @@ add_lldb_library(lldbSymbol lldbHost lldbTarget lldbUtility - lldbPluginObjCLanguage LINK_COMPONENTS Support diff --git a/gnu/llvm/lldb/source/Symbol/CompactUnwindInfo.cpp b/gnu/llvm/lldb/source/Symbol/CompactUnwindInfo.cpp index 1bb7cd1fc05..830fe5546c1 100644 --- a/gnu/llvm/lldb/source/Symbol/CompactUnwindInfo.cpp +++ b/gnu/llvm/lldb/source/Symbol/CompactUnwindInfo.cpp @@ -167,7 +167,7 @@ CompactUnwindInfo::CompactUnwindInfo(ObjectFile &objfile, SectionSP §ion_sp) // destructor -CompactUnwindInfo::~CompactUnwindInfo() {} +CompactUnwindInfo::~CompactUnwindInfo() = default; bool CompactUnwindInfo::GetUnwindPlan(Target &target, Address addr, UnwindPlan &unwind_plan) { diff --git a/gnu/llvm/lldb/source/Symbol/CompileUnit.cpp b/gnu/llvm/lldb/source/Symbol/CompileUnit.cpp index 0c67bf5b702..588ed4976d6 100644 --- a/gnu/llvm/lldb/source/Symbol/CompileUnit.cpp +++ b/gnu/llvm/lldb/source/Symbol/CompileUnit.cpp @@ -75,8 +75,7 @@ void CompileUnit::ForeachFunction( lldb::FunctionSP CompileUnit::FindFunction( llvm::function_ref matching_lambda) { - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer(func_cat, "CompileUnit::FindFunction"); + LLDB_SCOPED_TIMER(); lldb::ModuleSP module = CalculateSymbolContextModule(); @@ -225,18 +224,24 @@ uint32_t CompileUnit::FindLineEntry(uint32_t start_idx, uint32_t line, if (file_indexes.empty()) return UINT32_MAX; + // TODO: Handle SourceLocationSpec column information + SourceLocationSpec location_spec(*file_spec_ptr, line, /*column=*/llvm::None, + /*check_inlines=*/false, exact); + LineTable *line_table = GetLineTable(); if (line_table) return line_table->FindLineEntryIndexByFileIndex( - start_idx, file_indexes, line, exact, line_entry_ptr); + start_idx, file_indexes, location_spec, line_entry_ptr); return UINT32_MAX; } -void CompileUnit::ResolveSymbolContext(const FileSpec &file_spec, - uint32_t line, bool check_inlines, - bool exact, - SymbolContextItem resolve_scope, - SymbolContextList &sc_list) { +void CompileUnit::ResolveSymbolContext( + const SourceLocationSpec &src_location_spec, + SymbolContextItem resolve_scope, SymbolContextList &sc_list) { + const FileSpec file_spec = src_location_spec.GetFileSpec(); + const uint32_t line = src_location_spec.GetLine().getValueOr(0); + const bool check_inlines = src_location_spec.GetCheckInlines(); + // First find all of the file indexes that match our "file_spec". If // "file_spec" has an empty directory, then only compare the basenames when // finding file indexes @@ -249,6 +254,18 @@ void CompileUnit::ResolveSymbolContext(const FileSpec &file_spec, if (!file_spec_matches_cu_file_spec && !check_inlines) return; + SymbolContext sc(GetModule()); + sc.comp_unit = this; + + if (line == 0) { + if (file_spec_matches_cu_file_spec && !check_inlines) { + // only append the context if we aren't looking for inline call sites by + // file and line and if the file spec matches that of the compile unit + sc_list.Append(sc); + } + return; + } + uint32_t file_idx = GetSupportFiles().FindFileIndex(0, file_spec, true); while (file_idx != UINT32_MAX) { @@ -260,23 +277,15 @@ void CompileUnit::ResolveSymbolContext(const FileSpec &file_spec, if (num_file_indexes == 0) return; - SymbolContext sc(GetModule()); - sc.comp_unit = this; + LineTable *line_table = sc.comp_unit->GetLineTable(); - if (line == 0) { + if (line_table == nullptr) { if (file_spec_matches_cu_file_spec && !check_inlines) { - // only append the context if we aren't looking for inline call sites by - // file and line and if the file spec matches that of the compile unit sc_list.Append(sc); } return; } - LineTable *line_table = sc.comp_unit->GetLineTable(); - - if (line_table == nullptr) - return; - uint32_t line_idx; LineEntry line_entry; @@ -285,21 +294,24 @@ void CompileUnit::ResolveSymbolContext(const FileSpec &file_spec, // table function that searches for a line entries that match a single // support file index line_idx = line_table->FindLineEntryIndexByFileIndex( - 0, file_indexes.front(), line, exact, &line_entry); + 0, file_indexes.front(), src_location_spec, &line_entry); } else { // We found multiple support files that match "file_spec" so use the // line table function that searches for a line entries that match a // multiple support file indexes. - line_idx = line_table->FindLineEntryIndexByFileIndex(0, file_indexes, line, - exact, &line_entry); + line_idx = line_table->FindLineEntryIndexByFileIndex( + 0, file_indexes, src_location_spec, &line_entry); } // If "exact == true", then "found_line" will be the same as "line". If // "exact == false", the "found_line" will be the closest line entry // with a line number greater than "line" and we will use this for our // subsequent line exact matches below. - uint32_t found_line = line_entry.line; - + const bool inlines = false; + const bool exact = true; + SourceLocationSpec found_entry(line_entry.file, line_entry.line, + line_entry.column, inlines, exact); + while (line_idx != UINT32_MAX) { // If they only asked for the line entry, then we're done, we can // just copy that over. But if they wanted more than just the line @@ -314,10 +326,10 @@ void CompileUnit::ResolveSymbolContext(const FileSpec &file_spec, sc_list.Append(sc); if (num_file_indexes == 1) line_idx = line_table->FindLineEntryIndexByFileIndex( - line_idx + 1, file_indexes.front(), found_line, true, &line_entry); + line_idx + 1, file_indexes.front(), found_entry, &line_entry); else line_idx = line_table->FindLineEntryIndexByFileIndex( - line_idx + 1, file_indexes, found_line, true, &line_entry); + line_idx + 1, file_indexes, found_entry, &line_entry); } } diff --git a/gnu/llvm/lldb/source/Symbol/CompilerType.cpp b/gnu/llvm/lldb/source/Symbol/CompilerType.cpp index f819c9f8ce2..ac98352c235 100644 --- a/gnu/llvm/lldb/source/Symbol/CompilerType.cpp +++ b/gnu/llvm/lldb/source/Symbol/CompilerType.cpp @@ -40,6 +40,12 @@ bool CompilerType::IsAnonymousType() const { return false; } +bool CompilerType::IsScopedEnumerationType() const { + if (IsValid()) + return m_type_system->IsScopedEnumerationType(m_type); + return false; +} + bool CompilerType::IsArrayType(CompilerType *element_type_ptr, uint64_t *size, bool *is_incomplete) const { if (IsValid()) @@ -92,9 +98,9 @@ bool CompilerType::IsCStringType(uint32_t &length) const { return false; } -bool CompilerType::IsFunctionType(bool *is_variadic_ptr) const { +bool CompilerType::IsFunctionType() const { if (IsValid()) - return m_type_system->IsFunctionType(m_type, is_variadic_ptr); + return m_type_system->IsFunctionType(m_type); return false; } @@ -242,7 +248,7 @@ bool CompilerType::IsPointerToScalarType() const { bool CompilerType::IsArrayOfScalarType() const { CompilerType element_type; - if (IsArrayType(&element_type, nullptr, nullptr)) + if (IsArrayType(&element_type)) return element_type.IsScalarType(); return false; } @@ -317,9 +323,10 @@ unsigned CompilerType::GetTypeQualifiers() const { // Creating related types -CompilerType CompilerType::GetArrayElementType(uint64_t *stride) const { +CompilerType +CompilerType::GetArrayElementType(ExecutionContextScope *exe_scope) const { if (IsValid()) { - return m_type_system->GetArrayElementType(m_type, stride); + return m_type_system->GetArrayElementType(m_type, exe_scope); } return CompilerType(); } @@ -343,6 +350,12 @@ CompilerType CompilerType::GetFullyUnqualifiedType() const { return CompilerType(); } +CompilerType CompilerType::GetEnumerationIntegerType() const { + if (IsValid()) + return m_type_system->GetEnumerationIntegerType(m_type); + return CompilerType(); +} + int CompilerType::GetFunctionArgumentCount() const { if (IsValid()) { return m_type_system->GetFunctionArgumentCount(m_type); @@ -766,8 +779,8 @@ LLVM_DUMP_METHOD void CompilerType::dump() const { bool CompilerType::GetValueAsScalar(const lldb_private::DataExtractor &data, lldb::offset_t data_byte_offset, - size_t data_byte_size, - Scalar &value) const { + size_t data_byte_size, Scalar &value, + ExecutionContextScope *exe_scope) const { if (!IsValid()) return false; @@ -780,7 +793,7 @@ bool CompilerType::GetValueAsScalar(const lldb_private::DataExtractor &data, if (encoding == lldb::eEncodingInvalid || count != 1) return false; - llvm::Optional byte_size = GetByteSize(nullptr); + llvm::Optional byte_size = GetByteSize(exe_scope); if (!byte_size) return false; lldb::offset_t offset = data_byte_offset; diff --git a/gnu/llvm/lldb/source/Symbol/DWARFCallFrameInfo.cpp b/gnu/llvm/lldb/source/Symbol/DWARFCallFrameInfo.cpp index 3111c33c710..f0dce8f4793 100644 --- a/gnu/llvm/lldb/source/Symbol/DWARFCallFrameInfo.cpp +++ b/gnu/llvm/lldb/source/Symbol/DWARFCallFrameInfo.cpp @@ -419,8 +419,7 @@ void DWARFCallFrameInfo::GetFDEIndex() { if (m_fde_index_initialized) // if two threads hit the locker return; - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer(func_cat, "%s - %s", LLVM_PRETTY_FUNCTION, + LLDB_SCOPED_TIMERF("%s - %s", LLVM_PRETTY_FUNCTION, m_objfile.GetFileSpec().GetFilename().AsCString("")); bool clear_address_zeroth_bit = false; diff --git a/gnu/llvm/lldb/source/Symbol/FuncUnwinders.cpp b/gnu/llvm/lldb/source/Symbol/FuncUnwinders.cpp index 30266120d05..d67c0a828eb 100644 --- a/gnu/llvm/lldb/source/Symbol/FuncUnwinders.cpp +++ b/gnu/llvm/lldb/source/Symbol/FuncUnwinders.cpp @@ -55,7 +55,7 @@ FuncUnwinders::FuncUnwinders(UnwindTable &unwind_table, AddressRange range) /// destructor -FuncUnwinders::~FuncUnwinders() {} +FuncUnwinders::~FuncUnwinders() = default; UnwindPlanSP FuncUnwinders::GetUnwindPlanAtCallSite(Target &target, Thread &thread) { @@ -183,11 +183,11 @@ class RegisterContextToInfo: public SymbolFile::RegisterInfoResolver { public: RegisterContextToInfo(RegisterContext &ctx) : m_ctx(ctx) {} - const RegisterInfo *ResolveName(llvm::StringRef name) const { + const RegisterInfo *ResolveName(llvm::StringRef name) const override { return m_ctx.GetRegisterInfoByName(name); } const RegisterInfo *ResolveNumber(lldb::RegisterKind kind, - uint32_t number) const { + uint32_t number) const override { return m_ctx.GetRegisterInfo(kind, number); } diff --git a/gnu/llvm/lldb/source/Symbol/Function.cpp b/gnu/llvm/lldb/source/Symbol/Function.cpp index 67013f6dd8b..37479651fb4 100644 --- a/gnu/llvm/lldb/source/Symbol/Function.cpp +++ b/gnu/llvm/lldb/source/Symbol/Function.cpp @@ -32,7 +32,7 @@ FunctionInfo::FunctionInfo(const char *name, const Declaration *decl_ptr) FunctionInfo::FunctionInfo(ConstString name, const Declaration *decl_ptr) : m_name(name), m_declaration(decl_ptr) {} -FunctionInfo::~FunctionInfo() {} +FunctionInfo::~FunctionInfo() = default; void FunctionInfo::Dump(Stream *s, bool show_fullpaths) const { if (m_name) @@ -74,7 +74,7 @@ InlineFunctionInfo::InlineFunctionInfo(ConstString name, : FunctionInfo(name, decl_ptr), m_mangled(mangled), m_call_decl(call_decl_ptr) {} -InlineFunctionInfo::~InlineFunctionInfo() {} +InlineFunctionInfo::~InlineFunctionInfo() = default; void InlineFunctionInfo::Dump(Stream *s, bool show_fullpaths) const { FunctionInfo::Dump(s, show_fullpaths); @@ -238,7 +238,7 @@ Function::Function(CompileUnit *comp_unit, lldb::user_id_t func_uid, assert(comp_unit != nullptr); } -Function::~Function() {} +Function::~Function() = default; void Function::GetStartLineSourceInfo(FileSpec &source_file, uint32_t &line_no) { @@ -426,17 +426,16 @@ lldb::DisassemblerSP Function::GetInstructions(const ExecutionContext &exe_ctx, bool prefer_file_cache) { ModuleSP module_sp(GetAddressRange().GetBaseAddress().GetModule()); if (module_sp && exe_ctx.HasTargetScope()) { - const bool prefer_file_cache = false; return Disassembler::DisassembleRange(module_sp->GetArchitecture(), nullptr, flavor, exe_ctx.GetTargetRef(), - GetAddressRange(), prefer_file_cache); + GetAddressRange(), !prefer_file_cache); } return lldb::DisassemblerSP(); } bool Function::GetDisassembly(const ExecutionContext &exe_ctx, - const char *flavor, bool prefer_file_cache, - Stream &strm) { + const char *flavor, Stream &strm, + bool prefer_file_cache) { lldb::DisassemblerSP disassembler_sp = GetInstructions(exe_ctx, flavor, prefer_file_cache); if (disassembler_sp) { diff --git a/gnu/llvm/lldb/source/Symbol/LineEntry.cpp b/gnu/llvm/lldb/source/Symbol/LineEntry.cpp index a3907f4dd9c..1b2801cd036 100644 --- a/gnu/llvm/lldb/source/Symbol/LineEntry.cpp +++ b/gnu/llvm/lldb/source/Symbol/LineEntry.cpp @@ -14,9 +14,8 @@ using namespace lldb_private; LineEntry::LineEntry() - : range(), file(), line(LLDB_INVALID_LINE_NUMBER), column(0), - is_start_of_statement(0), is_start_of_basic_block(0), is_prologue_end(0), - is_epilogue_begin(0), is_terminal_entry(0) {} + : range(), file(), is_start_of_statement(0), is_start_of_basic_block(0), + is_prologue_end(0), is_epilogue_begin(0), is_terminal_entry(0) {} LineEntry::LineEntry(const lldb::SectionSP §ion_sp, lldb::addr_t section_offset, lldb::addr_t byte_size, @@ -253,9 +252,9 @@ AddressRange LineEntry::GetSameLineContiguousAddressRange( void LineEntry::ApplyFileMappings(lldb::TargetSP target_sp) { if (target_sp) { - // Apply any file remappings to our file - FileSpec new_file_spec; - if (target_sp->GetSourcePathMap().FindFile(original_file, new_file_spec)) - file = new_file_spec; + // Apply any file remappings to our file. + if (auto new_file_spec = + target_sp->GetSourcePathMap().FindFile(original_file)) + file = *new_file_spec; } } diff --git a/gnu/llvm/lldb/source/Symbol/LineTable.cpp b/gnu/llvm/lldb/source/Symbol/LineTable.cpp index 19c39bd0aeb..cd8d520ada7 100644 --- a/gnu/llvm/lldb/source/Symbol/LineTable.cpp +++ b/gnu/llvm/lldb/source/Symbol/LineTable.cpp @@ -34,7 +34,7 @@ LineTable::LineTable(CompileUnit *comp_unit, } // Destructor -LineTable::~LineTable() {} +LineTable::~LineTable() = default; void LineTable::InsertLineEntry(lldb::addr_t file_addr, uint32_t line, uint16_t column, uint16_t file_idx, @@ -58,7 +58,7 @@ void LineTable::InsertLineEntry(lldb::addr_t file_addr, uint32_t line, // Dump (&s, Address::DumpStyleFileAddress); } -LineSequence::LineSequence() {} +LineSequence::LineSequence() = default; void LineTable::LineSequenceImpl::Clear() { m_entries.clear(); } @@ -303,91 +303,26 @@ bool LineTable::ConvertEntryAtIndexToLineEntry(uint32_t idx, } uint32_t LineTable::FindLineEntryIndexByFileIndex( - uint32_t start_idx, const std::vector &file_indexes, - uint32_t line, bool exact, LineEntry *line_entry_ptr) { - - const size_t count = m_entries.size(); - size_t best_match = UINT32_MAX; - - for (size_t idx = start_idx; idx < count; ++idx) { - // Skip line table rows that terminate the previous row (is_terminal_entry - // is non-zero) - if (m_entries[idx].is_terminal_entry) - continue; - - if (llvm::find(file_indexes, m_entries[idx].file_idx) == file_indexes.end()) - continue; - - // Exact match always wins. Otherwise try to find the closest line > the - // desired line. - // FIXME: Maybe want to find the line closest before and the line closest - // after and - // if they're not in the same function, don't return a match. - - if (m_entries[idx].line < line) { - continue; - } else if (m_entries[idx].line == line) { - if (line_entry_ptr) - ConvertEntryAtIndexToLineEntry(idx, *line_entry_ptr); - return idx; - } else if (!exact) { - if (best_match == UINT32_MAX) - best_match = idx; - else if (m_entries[idx].line < m_entries[best_match].line) - best_match = idx; - } - } - - if (best_match != UINT32_MAX) { - if (line_entry_ptr) - ConvertEntryAtIndexToLineEntry(best_match, *line_entry_ptr); - return best_match; - } - return UINT32_MAX; + uint32_t start_idx, uint32_t file_idx, + const SourceLocationSpec &src_location_spec, LineEntry *line_entry_ptr) { + auto file_idx_matcher = [](uint32_t file_index, uint16_t entry_file_idx) { + return file_index == entry_file_idx; + }; + return FindLineEntryIndexByFileIndexImpl( + + start_idx, file_idx, src_location_spec, line_entry_ptr, file_idx_matcher); } -uint32_t LineTable::FindLineEntryIndexByFileIndex(uint32_t start_idx, - uint32_t file_idx, - uint32_t line, bool exact, - LineEntry *line_entry_ptr) { - const size_t count = m_entries.size(); - size_t best_match = UINT32_MAX; - - for (size_t idx = start_idx; idx < count; ++idx) { - // Skip line table rows that terminate the previous row (is_terminal_entry - // is non-zero) - if (m_entries[idx].is_terminal_entry) - continue; - - if (m_entries[idx].file_idx != file_idx) - continue; - - // Exact match always wins. Otherwise try to find the closest line > the - // desired line. - // FIXME: Maybe want to find the line closest before and the line closest - // after and - // if they're not in the same function, don't return a match. - - if (m_entries[idx].line < line) { - continue; - } else if (m_entries[idx].line == line) { - if (line_entry_ptr) - ConvertEntryAtIndexToLineEntry(idx, *line_entry_ptr); - return idx; - } else if (!exact) { - if (best_match == UINT32_MAX) - best_match = idx; - else if (m_entries[idx].line < m_entries[best_match].line) - best_match = idx; - } - } - - if (best_match != UINT32_MAX) { - if (line_entry_ptr) - ConvertEntryAtIndexToLineEntry(best_match, *line_entry_ptr); - return best_match; - } - return UINT32_MAX; +uint32_t LineTable::FindLineEntryIndexByFileIndex( + uint32_t start_idx, const std::vector &file_idx, + const SourceLocationSpec &src_location_spec, LineEntry *line_entry_ptr) { + auto file_idx_matcher = [](const std::vector &file_indexes, + uint16_t entry_file_idx) { + return llvm::is_contained(file_indexes, entry_file_idx); + }; + + return FindLineEntryIndexByFileIndexImpl>( + start_idx, file_idx, src_location_spec, line_entry_ptr, file_idx_matcher); } size_t LineTable::FineLineEntriesForFileIndex(uint32_t file_idx, bool append, diff --git a/gnu/llvm/lldb/source/Symbol/LocateSymbolFile.cpp b/gnu/llvm/lldb/source/Symbol/LocateSymbolFile.cpp index 95ae2ca7917..ba79bf661cd 100644 --- a/gnu/llvm/lldb/source/Symbol/LocateSymbolFile.cpp +++ b/gnu/llvm/lldb/source/Symbol/LocateSymbolFile.cpp @@ -16,6 +16,7 @@ #include "lldb/Utility/DataBuffer.h" #include "lldb/Utility/DataExtractor.h" #include "lldb/Utility/Log.h" +#include "lldb/Utility/Reproducer.h" #include "lldb/Utility/StreamString.h" #include "lldb/Utility/Timer.h" #include "lldb/Utility/UUID.h" @@ -208,9 +209,7 @@ static FileSpec LocateExecutableSymbolFileDsym(const ModuleSpec &module_spec) { const ArchSpec *arch = module_spec.GetArchitecturePtr(); const UUID *uuid = module_spec.GetUUIDPtr(); - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer( - func_cat, + LLDB_SCOPED_TIMERF( "LocateExecutableSymbolFileDsym (file = %s, arch = %s, uuid = %p)", exec_fspec ? exec_fspec->GetFilename().AsCString("") : "", arch ? arch->GetArchitectureName() : "", (const void *)uuid); @@ -225,6 +224,7 @@ static FileSpec LocateExecutableSymbolFileDsym(const ModuleSpec &module_spec) { } else { dsym_module_spec.GetSymbolFileSpec() = symbol_fspec; } + return dsym_module_spec.GetSymbolFileSpec(); } @@ -233,9 +233,8 @@ ModuleSpec Symbols::LocateExecutableObjectFile(const ModuleSpec &module_spec) { const FileSpec &exec_fspec = module_spec.GetFileSpec(); const ArchSpec *arch = module_spec.GetArchitecturePtr(); const UUID *uuid = module_spec.GetUUIDPtr(); - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer( - func_cat, "LocateExecutableObjectFile (file = %s, arch = %s, uuid = %p)", + LLDB_SCOPED_TIMERF( + "LocateExecutableObjectFile (file = %s, arch = %s, uuid = %p)", exec_fspec ? exec_fspec.GetFilename().AsCString("") : "", arch ? arch->GetArchitectureName() : "", (const void *)uuid); @@ -248,6 +247,7 @@ ModuleSpec Symbols::LocateExecutableObjectFile(const ModuleSpec &module_spec) { } else { LocateMacOSXFilesUsingDebugSymbols(module_spec, result); } + return result; } diff --git a/gnu/llvm/lldb/source/Symbol/LocateSymbolFileMacOSX.cpp b/gnu/llvm/lldb/source/Symbol/LocateSymbolFileMacOSX.cpp index 251605085c5..2655e4de906 100644 --- a/gnu/llvm/lldb/source/Symbol/LocateSymbolFileMacOSX.cpp +++ b/gnu/llvm/lldb/source/Symbol/LocateSymbolFileMacOSX.cpp @@ -27,6 +27,7 @@ #include "lldb/Utility/DataExtractor.h" #include "lldb/Utility/Endian.h" #include "lldb/Utility/Log.h" +#include "lldb/Utility/ReproducerProvider.h" #include "lldb/Utility/StreamString.h" #include "lldb/Utility/Timer.h" #include "lldb/Utility/UUID.h" @@ -53,6 +54,17 @@ int LocateMacOSXFilesUsingDebugSymbols(const ModuleSpec &module_spec, return_module_spec.GetFileSpec().Clear(); return_module_spec.GetSymbolFileSpec().Clear(); + const UUID *uuid = module_spec.GetUUIDPtr(); + const ArchSpec *arch = module_spec.GetArchitecturePtr(); + + if (repro::Loader *l = repro::Reproducer::Instance().GetLoader()) { + static repro::SymbolFileLoader symbol_file_loader(l); + std::pair paths = symbol_file_loader.GetPaths(uuid); + return_module_spec.GetFileSpec() = paths.first; + return_module_spec.GetSymbolFileSpec() = paths.second; + return 1; + } + int items_found = 0; if (g_dlsym_DBGCopyFullDSYMURLForUUID == nullptr || @@ -69,9 +81,6 @@ int LocateMacOSXFilesUsingDebugSymbols(const ModuleSpec &module_spec, return items_found; } - const UUID *uuid = module_spec.GetUUIDPtr(); - const ArchSpec *arch = module_spec.GetArchitecturePtr(); - if (uuid && uuid->IsValid()) { // Try and locate the dSYM file using DebugSymbols first llvm::ArrayRef module_uuid = uuid->GetBytes(); @@ -247,6 +256,12 @@ int LocateMacOSXFilesUsingDebugSymbols(const ModuleSpec &module_spec, } } + if (repro::Generator *g = repro::Reproducer::Instance().GetGenerator()) { + g->GetOrCreate().AddSymbolFile( + uuid, return_module_spec.GetFileSpec(), + return_module_spec.GetSymbolFileSpec()); + } + return items_found; } @@ -327,13 +342,6 @@ static bool GetModuleSpecInfoFromUUIDDictionary(CFDictionaryRef uuid_dict, } } - cf_str = (CFStringRef)CFDictionaryGetValue((CFDictionaryRef)uuid_dict, - CFSTR("DBGArchitecture")); - if (cf_str && CFGetTypeID(cf_str) == CFStringGetTypeID()) { - if (CFCString::FileSystemRepresentation(cf_str, str)) - module_spec.GetArchitecture().SetTriple(str.c_str()); - } - std::string DBGBuildSourcePath; std::string DBGSourcePath; @@ -464,6 +472,25 @@ bool Symbols::DownloadObjectAndSymbolFile(ModuleSpec &module_spec, const UUID *uuid_ptr = module_spec.GetUUIDPtr(); const FileSpec *file_spec_ptr = module_spec.GetFileSpecPtr(); + if (repro::Loader *l = repro::Reproducer::Instance().GetLoader()) { + static repro::SymbolFileLoader symbol_file_loader(l); + std::pair paths = symbol_file_loader.GetPaths(uuid_ptr); + if (paths.first) + module_spec.GetFileSpec() = paths.first; + if (paths.second) + module_spec.GetSymbolFileSpec() = paths.second; + return true; + } + + // Lambda to capture the state of module_spec before returning from this + // function. + auto RecordResult = [&]() { + if (repro::Generator *g = repro::Reproducer::Instance().GetGenerator()) { + g->GetOrCreate().AddSymbolFile( + uuid_ptr, module_spec.GetFileSpec(), module_spec.GetSymbolFileSpec()); + } + }; + // It's expensive to check for the DBGShellCommands defaults setting, only do // it once per lldb run and cache the result. static bool g_have_checked_for_dbgshell_command = false; @@ -489,6 +516,7 @@ bool Symbols::DownloadObjectAndSymbolFile(ModuleSpec &module_spec, // When g_dbgshell_command is NULL, the user has not enabled the use of an // external program to find the symbols, don't run it for them. if (!force_lookup && g_dbgshell_command == NULL) { + RecordResult(); return false; } @@ -586,7 +614,7 @@ bool Symbols::DownloadObjectAndSymbolFile(ModuleSpec &module_spec, &signo, // Signal int * &command_output, // Command output std::chrono::seconds( - 120), // Large timeout to allow for long dsym download times + 640), // Large timeout to allow for long dsym download times false); // Don't run in a shell (we don't need shell expansion) if (error.Success() && exit_status == 0 && !command_output.empty()) { CFCData data(CFDataCreateWithBytesNoCopy( @@ -613,8 +641,10 @@ bool Symbols::DownloadObjectAndSymbolFile(ModuleSpec &module_spec, ::CFDictionaryGetKeysAndValues(plist.get(), NULL, (const void **)&values[0]); if (num_values == 1) { - return GetModuleSpecInfoFromUUIDDictionary(values[0], - module_spec); + success = GetModuleSpecInfoFromUUIDDictionary(values[0], + module_spec); + RecordResult(); + return success; } else { for (CFIndex i = 0; i < num_values; ++i) { ModuleSpec curr_module_spec; @@ -623,6 +653,7 @@ bool Symbols::DownloadObjectAndSymbolFile(ModuleSpec &module_spec, if (module_spec.GetArchitecture().IsCompatibleMatch( curr_module_spec.GetArchitecture())) { module_spec = curr_module_spec; + RecordResult(); return true; } } @@ -644,5 +675,6 @@ bool Symbols::DownloadObjectAndSymbolFile(ModuleSpec &module_spec, } } } + RecordResult(); return success; } diff --git a/gnu/llvm/lldb/source/Symbol/ObjectFile.cpp b/gnu/llvm/lldb/source/Symbol/ObjectFile.cpp index 6b552dd0c19..101af01341a 100644 --- a/gnu/llvm/lldb/source/Symbol/ObjectFile.cpp +++ b/gnu/llvm/lldb/source/Symbol/ObjectFile.cpp @@ -28,143 +28,121 @@ using namespace lldb_private; char ObjectFile::ID; +static ObjectFileSP +CreateObjectFromContainer(const lldb::ModuleSP &module_sp, const FileSpec *file, + lldb::offset_t file_offset, lldb::offset_t file_size, + DataBufferSP &data_sp, lldb::offset_t &data_offset) { + ObjectContainerCreateInstance callback; + for (uint32_t idx = 0; + (callback = PluginManager::GetObjectContainerCreateCallbackAtIndex( + idx)) != nullptr; + ++idx) { + std::unique_ptr object_container_up(callback( + module_sp, data_sp, data_offset, file, file_offset, file_size)); + if (object_container_up) + return object_container_up->GetObjectFile(file); + } + return {}; +} + ObjectFileSP ObjectFile::FindPlugin(const lldb::ModuleSP &module_sp, const FileSpec *file, lldb::offset_t file_offset, lldb::offset_t file_size, DataBufferSP &data_sp, lldb::offset_t &data_offset) { - ObjectFileSP object_file_sp; - - if (module_sp) { - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer( - func_cat, - "ObjectFile::FindPlugin (module = %s, file = %p, file_offset = " - "0x%8.8" PRIx64 ", file_size = 0x%8.8" PRIx64 ")", - module_sp->GetFileSpec().GetPath().c_str(), - static_cast(file), static_cast(file_offset), - static_cast(file_size)); - if (file) { - FileSpec archive_file; - ObjectContainerCreateInstance create_object_container_callback; - - if (!data_sp) { - const bool file_exists = FileSystem::Instance().Exists(*file); - // We have an object name which most likely means we have a .o file in - // a static archive (.a file). Try and see if we have a cached archive - // first without reading any data first - if (file_exists && module_sp->GetObjectName()) { - for (uint32_t idx = 0; - (create_object_container_callback = - PluginManager::GetObjectContainerCreateCallbackAtIndex( - idx)) != nullptr; - ++idx) { - std::unique_ptr object_container_up( - create_object_container_callback(module_sp, data_sp, - data_offset, file, file_offset, - file_size)); - - if (object_container_up) - object_file_sp = object_container_up->GetObjectFile(file); - - if (object_file_sp.get()) - return object_file_sp; - } - } - // Ok, we didn't find any containers that have a named object, now lets - // read the first 512 bytes from the file so the object file and object - // container plug-ins can use these bytes to see if they can parse this - // file. - if (file_size > 0) { - data_sp = FileSystem::Instance().CreateDataBuffer(file->GetPath(), - 512, file_offset); - data_offset = 0; - } - } + LLDB_SCOPED_TIMERF( + "ObjectFile::FindPlugin (module = %s, file = %p, file_offset = " + "0x%8.8" PRIx64 ", file_size = 0x%8.8" PRIx64 ")", + module_sp->GetFileSpec().GetPath().c_str(), + static_cast(file), static_cast(file_offset), + static_cast(file_size)); + + if (!module_sp) + return {}; + + if (!file) + return {}; + + if (!data_sp) { + const bool file_exists = FileSystem::Instance().Exists(*file); + // We have an object name which most likely means we have a .o file in + // a static archive (.a file). Try and see if we have a cached archive + // first without reading any data first + if (file_exists && module_sp->GetObjectName()) { + ObjectFileSP object_file_sp = CreateObjectFromContainer( + module_sp, file, file_offset, file_size, data_sp, data_offset); + if (object_file_sp) + return object_file_sp; + } + // Ok, we didn't find any containers that have a named object, now lets + // read the first 512 bytes from the file so the object file and object + // container plug-ins can use these bytes to see if they can parse this + // file. + if (file_size > 0) { + data_sp = FileSystem::Instance().CreateDataBuffer(file->GetPath(), 512, + file_offset); + data_offset = 0; + } + } - if (!data_sp || data_sp->GetByteSize() == 0) { - // Check for archive file with format "/path/to/archive.a(object.o)" - llvm::SmallString<256> path_with_object; - module_sp->GetFileSpec().GetPath(path_with_object); - - ConstString archive_object; - const bool must_exist = true; - if (ObjectFile::SplitArchivePathWithObject( - path_with_object, archive_file, archive_object, must_exist)) { - file_size = FileSystem::Instance().GetByteSize(archive_file); - if (file_size > 0) { - file = &archive_file; - module_sp->SetFileSpecAndObjectName(archive_file, archive_object); - // Check if this is a object container by iterating through all - // object container plugin instances and then trying to get an - // object file from the container plugins since we had a name. - // Also, don't read - // ANY data in case there is data cached in the container plug-ins - // (like BSD archives caching the contained objects within an - // file). - for (uint32_t idx = 0; - (create_object_container_callback = - PluginManager::GetObjectContainerCreateCallbackAtIndex( - idx)) != nullptr; - ++idx) { - std::unique_ptr object_container_up( - create_object_container_callback(module_sp, data_sp, - data_offset, file, - file_offset, file_size)); - - if (object_container_up) - object_file_sp = object_container_up->GetObjectFile(file); - - if (object_file_sp.get()) - return object_file_sp; - } - // We failed to find any cached object files in the container plug- - // ins, so lets read the first 512 bytes and try again below... - data_sp = FileSystem::Instance().CreateDataBuffer( - archive_file.GetPath(), 512, file_offset); - } - } + if (!data_sp || data_sp->GetByteSize() == 0) { + // Check for archive file with format "/path/to/archive.a(object.o)" + llvm::SmallString<256> path_with_object; + module_sp->GetFileSpec().GetPath(path_with_object); + + FileSpec archive_file; + ConstString archive_object; + const bool must_exist = true; + if (ObjectFile::SplitArchivePathWithObject(path_with_object, archive_file, + archive_object, must_exist)) { + file_size = FileSystem::Instance().GetByteSize(archive_file); + if (file_size > 0) { + file = &archive_file; + module_sp->SetFileSpecAndObjectName(archive_file, archive_object); + // Check if this is a object container by iterating through all + // object container plugin instances and then trying to get an + // object file from the container plugins since we had a name. + // Also, don't read + // ANY data in case there is data cached in the container plug-ins + // (like BSD archives caching the contained objects within an + // file). + ObjectFileSP object_file_sp = CreateObjectFromContainer( + module_sp, file, file_offset, file_size, data_sp, data_offset); + if (object_file_sp) + return object_file_sp; + // We failed to find any cached object files in the container plug- + // ins, so lets read the first 512 bytes and try again below... + data_sp = FileSystem::Instance().CreateDataBuffer( + archive_file.GetPath(), 512, file_offset); } + } + } - if (data_sp && data_sp->GetByteSize() > 0) { - // Check if this is a normal object file by iterating through all - // object file plugin instances. - ObjectFileCreateInstance create_object_file_callback; - for (uint32_t idx = 0; - (create_object_file_callback = - PluginManager::GetObjectFileCreateCallbackAtIndex(idx)) != - nullptr; - ++idx) { - object_file_sp.reset(create_object_file_callback( - module_sp, data_sp, data_offset, file, file_offset, file_size)); - if (object_file_sp.get()) - return object_file_sp; - } - - // Check if this is a object container by iterating through all object - // container plugin instances and then trying to get an object file - // from the container. - for (uint32_t idx = 0; - (create_object_container_callback = - PluginManager::GetObjectContainerCreateCallbackAtIndex( - idx)) != nullptr; - ++idx) { - std::unique_ptr object_container_up( - create_object_container_callback(module_sp, data_sp, data_offset, - file, file_offset, file_size)); - - if (object_container_up) - object_file_sp = object_container_up->GetObjectFile(file); - - if (object_file_sp.get()) - return object_file_sp; - } - } + if (data_sp && data_sp->GetByteSize() > 0) { + // Check if this is a normal object file by iterating through all + // object file plugin instances. + ObjectFileCreateInstance callback; + for (uint32_t idx = 0; + (callback = PluginManager::GetObjectFileCreateCallbackAtIndex(idx)) != + nullptr; + ++idx) { + ObjectFileSP object_file_sp(callback(module_sp, data_sp, data_offset, + file, file_offset, file_size)); + if (object_file_sp.get()) + return object_file_sp; } + + // Check if this is a object container by iterating through all object + // container plugin instances and then trying to get an object file + // from the container. + ObjectFileSP object_file_sp = CreateObjectFromContainer( + module_sp, file, file_offset, file_size, data_sp, data_offset); + if (object_file_sp) + return object_file_sp; } + // We didn't find it, so clear our shared pointer in case it contains // anything and return an empty shared pointer - object_file_sp.reset(); - return object_file_sp; + return {}; } ObjectFileSP ObjectFile::FindPlugin(const lldb::ModuleSP &module_sp, @@ -174,9 +152,7 @@ ObjectFileSP ObjectFile::FindPlugin(const lldb::ModuleSP &module_sp, ObjectFileSP object_file_sp; if (module_sp) { - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer(func_cat, - "ObjectFile::FindPlugin (module = " + LLDB_SCOPED_TIMERF("ObjectFile::FindPlugin (module = " "%s, process = %p, header_addr = " "0x%" PRIx64 ")", module_sp->GetFileSpec().GetPath().c_str(), @@ -503,6 +479,9 @@ size_t ObjectFile::ReadSectionData(Section *section, return section->GetObjectFile()->ReadSectionData(section, section_offset, dst, dst_len); + if (!section->IsRelocated()) + RelocateSection(section); + if (IsInMemory()) { ProcessSP process_sp(m_process_wp.lock()); if (process_sp) { @@ -514,9 +493,6 @@ size_t ObjectFile::ReadSectionData(Section *section, dst_len, error); } } else { - if (!section->IsRelocated()) - RelocateSection(section); - const lldb::offset_t section_file_size = section->GetFileSize(); if (section_offset < section_file_size) { const size_t section_bytes_left = section_file_size - section_offset; @@ -547,6 +523,9 @@ size_t ObjectFile::ReadSectionData(Section *section, if (section->GetObjectFile() != this) return section->GetObjectFile()->ReadSectionData(section, section_data); + if (!section->IsRelocated()) + RelocateSection(section); + if (IsInMemory()) { ProcessSP process_sp(m_process_wp.lock()); if (process_sp) { @@ -563,17 +542,12 @@ size_t ObjectFile::ReadSectionData(Section *section, } } } - return GetData(section->GetFileOffset(), section->GetFileSize(), - section_data); - } else { - // The object file now contains a full mmap'ed copy of the object file - // data, so just use this - if (!section->IsRelocated()) - RelocateSection(section); - - return GetData(section->GetFileOffset(), section->GetFileSize(), - section_data); } + + // The object file now contains a full mmap'ed copy of the object file + // data, so just use this + return GetData(section->GetFileOffset(), section->GetFileSize(), + section_data); } bool ObjectFile::SplitArchivePathWithObject(llvm::StringRef path_with_object, @@ -642,14 +616,6 @@ ObjectFile::GetSymbolTypeFromName(llvm::StringRef name, return symbol_type_hint; } -ConstString ObjectFile::GetNextSyntheticSymbolName() { - StreamString ss; - ConstString file_name = GetModule()->GetFileSpec().GetFilename(); - ss.Printf("___lldb_unnamed_symbol%u$$%s", ++m_synthetic_symbol_idx, - file_name.GetCString()); - return ConstString(ss.GetString()); -} - std::vector ObjectFile::GetLoadableData(Target &target) { std::vector loadables; diff --git a/gnu/llvm/lldb/source/Symbol/Symbol.cpp b/gnu/llvm/lldb/source/Symbol/Symbol.cpp index 8d099e0cc7e..251f9104ad5 100644 --- a/gnu/llvm/lldb/source/Symbol/Symbol.cpp +++ b/gnu/llvm/lldb/source/Symbol/Symbol.cpp @@ -23,13 +23,12 @@ using namespace lldb; using namespace lldb_private; Symbol::Symbol() - : SymbolContextScope(), m_uid(UINT32_MAX), m_type_data(0), - m_type_data_resolved(false), m_is_synthetic(false), m_is_debug(false), - m_is_external(false), m_size_is_sibling(false), + : SymbolContextScope(), m_type_data_resolved(false), m_is_synthetic(false), + m_is_debug(false), m_is_external(false), m_size_is_sibling(false), m_size_is_synthesized(false), m_size_is_valid(false), m_demangled_is_synthesized(false), m_contains_linker_annotations(false), - m_is_weak(false), m_type(eSymbolTypeInvalid), m_mangled(), m_addr_range(), - m_flags() {} + m_is_weak(false), m_type(eSymbolTypeInvalid), m_mangled(), + m_addr_range() {} Symbol::Symbol(uint32_t symID, llvm::StringRef name, SymbolType type, bool external, bool is_debug, bool is_trampoline, bool is_artificial, @@ -57,8 +56,8 @@ Symbol::Symbol(uint32_t symID, const Mangled &mangled, SymbolType type, m_size_is_synthesized(false), m_size_is_valid(size_is_valid || range.GetByteSize() > 0), m_demangled_is_synthesized(false), - m_contains_linker_annotations(contains_linker_annotations), - m_is_weak(false), m_type(type), m_mangled(mangled), m_addr_range(range), + m_contains_linker_annotations(contains_linker_annotations), + m_is_weak(false), m_type(type), m_mangled(mangled), m_addr_range(range), m_flags(flags) {} Symbol::Symbol(const Symbol &rhs) @@ -120,7 +119,7 @@ bool Symbol::ValueIsAddress() const { } ConstString Symbol::GetDisplayName() const { - return m_mangled.GetDisplayDemangledName(); + return GetMangled().GetDisplayDemangledName(); } ConstString Symbol::GetReExportedSymbolName() const { @@ -203,7 +202,7 @@ void Symbol::GetDescription(Stream *s, lldb::DescriptionLevel level, s->Printf(", value = 0x%16.16" PRIx64, m_addr_range.GetBaseAddress().GetOffset()); } - ConstString demangled = m_mangled.GetDemangledName(); + ConstString demangled = GetMangled().GetDemangledName(); if (demangled) s->Printf(", name=\"%s\"", demangled.AsCString()); if (m_mangled.GetMangledName()) @@ -219,7 +218,7 @@ void Symbol::Dump(Stream *s, Target *target, uint32_t index, // Make sure the size of the symbol is up to date before dumping GetByteSize(); - ConstString name = m_mangled.GetName(name_preference); + ConstString name = GetMangled().GetName(name_preference); if (ValueIsAddress()) { if (!m_addr_range.GetBaseAddress().Dump(s, nullptr, Address::DumpStyleFileAddress)) @@ -331,9 +330,11 @@ uint32_t Symbol::GetPrologueByteSize() { } bool Symbol::Compare(ConstString name, SymbolType type) const { - if (type == eSymbolTypeAny || m_type == type) - return m_mangled.GetMangledName() == name || - m_mangled.GetDemangledName() == name; + if (type == eSymbolTypeAny || m_type == type) { + const Mangled &mangled = GetMangled(); + return mangled.GetMangledName() == name || + mangled.GetDemangledName() == name; + } return false; } @@ -496,10 +497,10 @@ lldb::addr_t Symbol::GetLoadAddress(Target *target) const { return LLDB_INVALID_ADDRESS; } -ConstString Symbol::GetName() const { return m_mangled.GetName(); } +ConstString Symbol::GetName() const { return GetMangled().GetName(); } ConstString Symbol::GetNameNoArguments() const { - return m_mangled.GetName(Mangled::ePreferDemangledWithoutArguments); + return GetMangled().GetName(Mangled::ePreferDemangledWithoutArguments); } lldb::addr_t Symbol::ResolveCallableAddress(Target &target) const { @@ -542,10 +543,9 @@ lldb::DisassemblerSP Symbol::GetInstructions(const ExecutionContext &exe_ctx, bool prefer_file_cache) { ModuleSP module_sp(m_addr_range.GetBaseAddress().GetModule()); if (module_sp && exe_ctx.HasTargetScope()) { - const bool prefer_file_cache = false; return Disassembler::DisassembleRange(module_sp->GetArchitecture(), nullptr, flavor, exe_ctx.GetTargetRef(), - m_addr_range, prefer_file_cache); + m_addr_range, !prefer_file_cache); } return lldb::DisassemblerSP(); } @@ -567,3 +567,30 @@ bool Symbol::GetDisassembly(const ExecutionContext &exe_ctx, const char *flavor, bool Symbol::ContainsFileAddress(lldb::addr_t file_addr) const { return m_addr_range.ContainsFileAddress(file_addr); } + +bool Symbol::IsSyntheticWithAutoGeneratedName() const { + if (!IsSynthetic()) + return false; + if (!m_mangled) + return true; + ConstString demangled = m_mangled.GetDemangledName(); + return demangled.GetStringRef().startswith(GetSyntheticSymbolPrefix()); +} + +void Symbol::SynthesizeNameIfNeeded() const { + if (m_is_synthetic && !m_mangled) { + // Synthetic symbol names don't mean anything, but they do uniquely + // identify individual symbols so we give them a unique name. The name + // starts with the synthetic symbol prefix, followed by a unique number. + // Typically the UserID of a real symbol is the symbol table index of the + // symbol in the object file's symbol table(s), so it will be the same + // every time you read in the object file. We want the same persistence for + // synthetic symbols so that users can identify them across multiple debug + // sessions, to understand crashes in those symbols and to reliably set + // breakpoints on them. + llvm::SmallString<256> name; + llvm::raw_svector_ostream os(name); + os << GetSyntheticSymbolPrefix() << GetID(); + m_mangled.SetDemangledName(ConstString(os.str())); + } +} diff --git a/gnu/llvm/lldb/source/Symbol/SymbolContext.cpp b/gnu/llvm/lldb/source/Symbol/SymbolContext.cpp index 12c2077154b..2e8fe1cec30 100644 --- a/gnu/llvm/lldb/source/Symbol/SymbolContext.cpp +++ b/gnu/llvm/lldb/source/Symbol/SymbolContext.cpp @@ -26,9 +26,7 @@ using namespace lldb; using namespace lldb_private; -SymbolContext::SymbolContext() - : target_sp(), module_sp(), comp_unit(nullptr), function(nullptr), - block(nullptr), line_entry(), symbol(nullptr), variable(nullptr) {} +SymbolContext::SymbolContext() : target_sp(), module_sp(), line_entry() {} SymbolContext::SymbolContext(const ModuleSP &m, CompileUnit *cu, Function *f, Block *b, LineEntry *le, Symbol *s) @@ -53,7 +51,7 @@ SymbolContext::SymbolContext(SymbolContextScope *sc_scope) sc_scope->CalculateSymbolContext(this); } -SymbolContext::~SymbolContext() {} +SymbolContext::~SymbolContext() = default; void SymbolContext::Clear(bool clear_target) { if (clear_target) @@ -127,11 +125,18 @@ bool SymbolContext::DumpStopContext(Stream *s, ExecutionContextScope *exe_scope, s->Printf(" + %" PRIu64, inlined_function_offset); } } - const Declaration &call_site = inlined_block_info->GetCallSite(); - if (call_site.IsValid()) { + // "line_entry" will always be valid as GetParentOfInlinedScope(...) will + // fill it in correctly with the calling file and line. Previous code + // was extracting the calling file and line from inlined_block_info and + // using it right away which is not correct. On the first call to this + // function "line_entry" will contain the actual line table entry. On + // susequent calls "line_entry" will contain the calling file and line + // from the previous inline info. + if (line_entry.IsValid()) { s->PutCString(" at "); - call_site.DumpStopContext(s, show_fullpaths); + line_entry.DumpStopContext(s, show_fullpaths); } + if (show_inlined_frames) { s->EOL(); s->Indent(); @@ -204,7 +209,7 @@ void SymbolContext::GetDescription(Stream *s, lldb::DescriptionLevel level, Type *func_type = function->GetType(); if (func_type) { s->Indent(" FuncType: "); - func_type->GetDescription(s, level, false); + func_type->GetDescription(s, level, false, target); s->EOL(); } } @@ -921,7 +926,7 @@ SymbolContextSpecifier::SymbolContextSpecifier(const TargetSP &target_sp) m_start_line(0), m_end_line(0), m_function_spec(), m_class_name(), m_address_range_up(), m_type(eNothingSpecified) {} -SymbolContextSpecifier::~SymbolContextSpecifier() {} +SymbolContextSpecifier::~SymbolContextSpecifier() = default; bool SymbolContextSpecifier::AddLineSpecification(uint32_t line_no, SpecificationType type) { @@ -1010,11 +1015,15 @@ void SymbolContextSpecifier::Clear() { m_type = eNothingSpecified; } -bool SymbolContextSpecifier::SymbolContextMatches(SymbolContext &sc) { +bool SymbolContextSpecifier::SymbolContextMatches(const SymbolContext &sc) { if (m_type == eNothingSpecified) return true; - if (m_target_sp.get() != sc.target_sp.get()) + // Only compare targets if this specifier has one and it's not the Dummy + // target. Otherwise if a specifier gets made in the dummy target and + // copied over we'll artificially fail the comparision. + if (m_target_sp && !m_target_sp->IsDummyTarget() && + m_target_sp != sc.target_sp) return false; if (m_type & eModuleSpecified) { @@ -1177,7 +1186,7 @@ void SymbolContextSpecifier::GetDescription( SymbolContextList::SymbolContextList() : m_symbol_contexts() {} -SymbolContextList::~SymbolContextList() {} +SymbolContextList::~SymbolContextList() = default; void SymbolContextList::Append(const SymbolContext &sc) { m_symbol_contexts.push_back(sc); diff --git a/gnu/llvm/lldb/source/Symbol/SymbolFile.cpp b/gnu/llvm/lldb/source/Symbol/SymbolFile.cpp index 3f9cdefc8d4..152bbe8de6c 100644 --- a/gnu/llvm/lldb/source/Symbol/SymbolFile.cpp +++ b/gnu/llvm/lldb/source/Symbol/SymbolFile.cpp @@ -97,10 +97,10 @@ SymbolFile::GetTypeSystemForLanguage(lldb::LanguageType language) { return type_system_or_err; } -uint32_t SymbolFile::ResolveSymbolContext(const FileSpec &file_spec, - uint32_t line, bool check_inlines, - lldb::SymbolContextItem resolve_scope, - SymbolContextList &sc_list) { +uint32_t +SymbolFile::ResolveSymbolContext(const SourceLocationSpec &src_location_spec, + lldb::SymbolContextItem resolve_scope, + SymbolContextList &sc_list) { return 0; } diff --git a/gnu/llvm/lldb/source/Symbol/SymbolVendor.cpp b/gnu/llvm/lldb/source/Symbol/SymbolVendor.cpp index 0a5acbc48eb..0ef332a5813 100644 --- a/gnu/llvm/lldb/source/Symbol/SymbolVendor.cpp +++ b/gnu/llvm/lldb/source/Symbol/SymbolVendor.cpp @@ -60,9 +60,6 @@ SymbolVendor *SymbolVendor::FindPlugin(const lldb::ModuleSP &module_sp, SymbolVendor::SymbolVendor(const lldb::ModuleSP &module_sp) : ModuleChild(module_sp), m_sym_file_up() {} -// Destructor -SymbolVendor::~SymbolVendor() {} - // Add a representation given an object file. void SymbolVendor::AddSymbolFileRepresentation(const ObjectFileSP &objfile_sp) { ModuleSP module_sp(GetModule()); diff --git a/gnu/llvm/lldb/source/Symbol/Symtab.cpp b/gnu/llvm/lldb/source/Symbol/Symtab.cpp index 3f697e6076b..313b451601a 100644 --- a/gnu/llvm/lldb/source/Symbol/Symtab.cpp +++ b/gnu/llvm/lldb/source/Symbol/Symtab.cpp @@ -9,8 +9,6 @@ #include #include -#include "Plugins/Language/ObjC/ObjCLanguage.h" - #include "lldb/Core/Module.h" #include "lldb/Core/RichManglingContext.h" #include "lldb/Core/Section.h" @@ -18,6 +16,7 @@ #include "lldb/Symbol/Symbol.h" #include "lldb/Symbol/SymbolContext.h" #include "lldb/Symbol/Symtab.h" +#include "lldb/Target/Language.h" #include "lldb/Utility/RegularExpression.h" #include "lldb/Utility/Stream.h" #include "lldb/Utility/Timer.h" @@ -29,10 +28,19 @@ using namespace lldb_private; Symtab::Symtab(ObjectFile *objfile) : m_objfile(objfile), m_symbols(), m_file_addr_to_index(*this), - m_name_to_index(), m_mutex(), m_file_addr_to_index_computed(false), - m_name_indexes_computed(false) {} + m_name_to_symbol_indices(), m_mutex(), + m_file_addr_to_index_computed(false), m_name_indexes_computed(false) { + m_name_to_symbol_indices.emplace(std::make_pair( + lldb::eFunctionNameTypeNone, UniqueCStringMap())); + m_name_to_symbol_indices.emplace(std::make_pair( + lldb::eFunctionNameTypeBase, UniqueCStringMap())); + m_name_to_symbol_indices.emplace(std::make_pair( + lldb::eFunctionNameTypeMethod, UniqueCStringMap())); + m_name_to_symbol_indices.emplace(std::make_pair( + lldb::eFunctionNameTypeSelector, UniqueCStringMap())); +} -Symtab::~Symtab() {} +Symtab::~Symtab() = default; void Symtab::Reserve(size_t count) { // Clients should grab the mutex from this symbol table and lock it manually @@ -51,7 +59,8 @@ uint32_t Symtab::AddSymbol(const Symbol &symbol) { // Clients should grab the mutex from this symbol table and lock it manually // when calling this function to avoid performance issues. uint32_t symbol_idx = m_symbols.size(); - m_name_to_index.Clear(); + auto &name_to_index = GetNameToSymbolIndexMap(lldb::eFunctionNameTypeNone); + name_to_index.Clear(); m_file_addr_to_index.Clear(); m_symbols.push_back(symbol); m_file_addr_to_index_computed = false; @@ -65,7 +74,8 @@ size_t Symtab::GetNumSymbols() const { } void Symtab::SectionFileAddressesChanged() { - m_name_to_index.Clear(); + auto &name_to_index = GetNameToSymbolIndexMap(lldb::eFunctionNameTypeNone); + name_to_index.Clear(); m_file_addr_to_index_computed = false; } @@ -240,6 +250,10 @@ static bool lldb_skip_name(llvm::StringRef mangled, case Mangled::eManglingSchemeMSVC: return false; + // No filters for this scheme yet. Include all names in indexing. + case Mangled::eManglingSchemeRustV0: + return false; + // Don't try and demangle things we can't categorize. case Mangled::eManglingSchemeNone: return true; @@ -251,11 +265,25 @@ void Symtab::InitNameIndexes() { // Protected function, no need to lock mutex... if (!m_name_indexes_computed) { m_name_indexes_computed = true; - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer(func_cat, "%s", LLVM_PRETTY_FUNCTION); + LLDB_SCOPED_TIMER(); + + // Collect all loaded language plugins. + std::vector languages; + Language::ForEach([&languages](Language *l) { + languages.push_back(l); + return true; + }); + + auto &name_to_index = GetNameToSymbolIndexMap(lldb::eFunctionNameTypeNone); + auto &basename_to_index = + GetNameToSymbolIndexMap(lldb::eFunctionNameTypeBase); + auto &method_to_index = + GetNameToSymbolIndexMap(lldb::eFunctionNameTypeMethod); + auto &selector_to_index = + GetNameToSymbolIndexMap(lldb::eFunctionNameTypeSelector); // Create the name index vector to be able to quickly search by name const size_t num_symbols = m_symbols.size(); - m_name_to_index.Reserve(num_symbols); + name_to_index.Reserve(num_symbols); // The "const char *" in "class_contexts" and backlog::value_type::second // must come from a ConstString::GetCString() @@ -272,22 +300,24 @@ void Symtab::InitNameIndexes() { // Don't let trampolines get into the lookup by name map If we ever need // the trampoline symbols to be searchable by name we can remove this and // then possibly add a new bool to any of the Symtab functions that - // lookup symbols by name to indicate if they want trampolines. - if (symbol->IsTrampoline()) + // lookup symbols by name to indicate if they want trampolines. We also + // don't want any synthetic symbols with auto generated names in the + // name lookups. + if (symbol->IsTrampoline() || symbol->IsSyntheticWithAutoGeneratedName()) continue; // If the symbol's name string matched a Mangled::ManglingScheme, it is // stored in the mangled field. Mangled &mangled = symbol->GetMangled(); if (ConstString name = mangled.GetMangledName()) { - m_name_to_index.Append(name, value); + name_to_index.Append(name, value); if (symbol->ContainsLinkerAnnotations()) { // If the symbol has linker annotations, also add the version without // the annotations. ConstString stripped = ConstString( m_objfile->StripLinkerSymbolAnnotations(name.GetStringRef())); - m_name_to_index.Append(stripped, value); + name_to_index.Append(stripped, value); } const SymbolType type = symbol->GetType(); @@ -300,25 +330,29 @@ void Symtab::InitNameIndexes() { // Symbol name strings that didn't match a Mangled::ManglingScheme, are // stored in the demangled field. if (ConstString name = mangled.GetDemangledName()) { - m_name_to_index.Append(name, value); + name_to_index.Append(name, value); if (symbol->ContainsLinkerAnnotations()) { // If the symbol has linker annotations, also add the version without // the annotations. name = ConstString( m_objfile->StripLinkerSymbolAnnotations(name.GetStringRef())); - m_name_to_index.Append(name, value); + name_to_index.Append(name, value); } // If the demangled name turns out to be an ObjC name, and is a category // name, add the version without categories to the index too. - ObjCLanguage::MethodName objc_method(name.GetStringRef(), true); - if (objc_method.IsValid(true)) { - m_selector_to_index.Append(objc_method.GetSelector(), value); - - if (ConstString objc_method_no_category = - objc_method.GetFullNameWithoutCategory(true)) - m_name_to_index.Append(objc_method_no_category, value); + for (Language *lang : languages) { + for (auto variant : lang->GetMethodNameVariants(name)) { + if (variant.GetType() & lldb::eFunctionNameTypeSelector) + selector_to_index.Append(variant.GetName(), value); + else if (variant.GetType() & lldb::eFunctionNameTypeFull) + name_to_index.Append(variant.GetName(), value); + else if (variant.GetType() & lldb::eFunctionNameTypeMethod) + method_to_index.Append(variant.GetName(), value); + else if (variant.GetType() & lldb::eFunctionNameTypeBase) + basename_to_index.Append(variant.GetName(), value); + } } } } @@ -327,14 +361,14 @@ void Symtab::InitNameIndexes() { RegisterBacklogEntry(record.first, record.second, class_contexts); } - m_name_to_index.Sort(); - m_name_to_index.SizeToFit(); - m_selector_to_index.Sort(); - m_selector_to_index.SizeToFit(); - m_basename_to_index.Sort(); - m_basename_to_index.SizeToFit(); - m_method_to_index.Sort(); - m_method_to_index.SizeToFit(); + name_to_index.Sort(); + name_to_index.SizeToFit(); + selector_to_index.Sort(); + selector_to_index.SizeToFit(); + basename_to_index.Sort(); + basename_to_index.SizeToFit(); + method_to_index.Sort(); + method_to_index.SizeToFit(); } } @@ -357,10 +391,13 @@ void Symtab::RegisterMangledNameEntry( // Register functions with no context. if (decl_context.empty()) { // This has to be a basename - m_basename_to_index.Append(entry); + auto &basename_to_index = + GetNameToSymbolIndexMap(lldb::eFunctionNameTypeBase); + basename_to_index.Append(entry); // If there is no context (no namespaces or class scopes that come before // the function name) then this also could be a fullname. - m_name_to_index.Append(entry); + auto &name_to_index = GetNameToSymbolIndexMap(lldb::eFunctionNameTypeNone); + name_to_index.Append(entry); return; } @@ -369,10 +406,12 @@ void Symtab::RegisterMangledNameEntry( const char *decl_context_ccstr = ConstString(decl_context).GetCString(); auto it = class_contexts.find(decl_context_ccstr); + auto &method_to_index = + GetNameToSymbolIndexMap(lldb::eFunctionNameTypeMethod); // Register constructors and destructors. They are methods and create // declaration contexts. if (rmc.IsCtorOrDtor()) { - m_method_to_index.Append(entry); + method_to_index.Append(entry); if (it == class_contexts.end()) class_contexts.insert(it, decl_context_ccstr); return; @@ -380,7 +419,7 @@ void Symtab::RegisterMangledNameEntry( // Register regular methods with a known declaration context. if (it != class_contexts.end()) { - m_method_to_index.Append(entry); + method_to_index.Append(entry); return; } @@ -392,14 +431,18 @@ void Symtab::RegisterMangledNameEntry( void Symtab::RegisterBacklogEntry( const NameToIndexMap::Entry &entry, const char *decl_context, const std::set &class_contexts) { + auto &method_to_index = + GetNameToSymbolIndexMap(lldb::eFunctionNameTypeMethod); auto it = class_contexts.find(decl_context); if (it != class_contexts.end()) { - m_method_to_index.Append(entry); + method_to_index.Append(entry); } else { // If we got here, we have something that had a context (was inside // a namespace or class) yet we don't know the entry - m_method_to_index.Append(entry); - m_basename_to_index.Append(entry); + method_to_index.Append(entry); + auto &basename_to_index = + GetNameToSymbolIndexMap(lldb::eFunctionNameTypeBase); + basename_to_index.Append(entry); } } @@ -411,9 +454,8 @@ void Symtab::PreloadSymbols() { void Symtab::AppendSymbolNamesToMap(const IndexCollection &indexes, bool add_demangled, bool add_mangled, NameToIndexMap &name_to_index_map) const { + LLDB_SCOPED_TIMER(); if (add_demangled || add_mangled) { - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer(func_cat, "%s", LLVM_PRETTY_FUNCTION); std::lock_guard guard(m_mutex); // Create the name index vector to be able to quickly search by name @@ -566,9 +608,7 @@ struct SymbolIndexComparator { void Symtab::SortSymbolIndexesByValue(std::vector &indexes, bool remove_duplicates) const { std::lock_guard guard(m_mutex); - - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer(func_cat, LLVM_PRETTY_FUNCTION); + LLDB_SCOPED_TIMER(); // No need to sort if we have zero or one items... if (indexes.size() <= 1) return; @@ -590,17 +630,46 @@ void Symtab::SortSymbolIndexesByValue(std::vector &indexes, } } +uint32_t Symtab::GetNameIndexes(ConstString symbol_name, + std::vector &indexes) { + auto &name_to_index = GetNameToSymbolIndexMap(lldb::eFunctionNameTypeNone); + const uint32_t count = name_to_index.GetValues(symbol_name, indexes); + if (count) + return count; + // Synthetic symbol names are not added to the name indexes, but they start + // with a prefix and end with a the symbol UserID. This allows users to find + // these symbols without having to add them to the name indexes. These + // queries will not happen very often since the names don't mean anything, so + // performance is not paramount in this case. + llvm::StringRef name = symbol_name.GetStringRef(); + // String the synthetic prefix if the name starts with it. + if (!name.consume_front(Symbol::GetSyntheticSymbolPrefix())) + return 0; // Not a synthetic symbol name + + // Extract the user ID from the symbol name + unsigned long long uid = 0; + if (getAsUnsignedInteger(name, /*Radix=*/10, uid)) + return 0; // Failed to extract the user ID as an integer + Symbol *symbol = FindSymbolByID(uid); + if (symbol == nullptr) + return 0; + const uint32_t symbol_idx = GetIndexForSymbol(symbol); + if (symbol_idx == UINT32_MAX) + return 0; + indexes.push_back(symbol_idx); + return 1; +} + uint32_t Symtab::AppendSymbolIndexesWithName(ConstString symbol_name, std::vector &indexes) { std::lock_guard guard(m_mutex); - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer(func_cat, "%s", LLVM_PRETTY_FUNCTION); + LLDB_SCOPED_TIMER(); if (symbol_name) { if (!m_name_indexes_computed) InitNameIndexes(); - return m_name_to_index.GetValues(symbol_name, indexes); + return GetNameIndexes(symbol_name, indexes); } return 0; } @@ -611,8 +680,7 @@ uint32_t Symtab::AppendSymbolIndexesWithName(ConstString symbol_name, std::vector &indexes) { std::lock_guard guard(m_mutex); - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer(func_cat, "%s", LLVM_PRETTY_FUNCTION); + LLDB_SCOPED_TIMER(); if (symbol_name) { const size_t old_size = indexes.size(); if (!m_name_indexes_computed) @@ -620,7 +688,7 @@ uint32_t Symtab::AppendSymbolIndexesWithName(ConstString symbol_name, std::vector all_name_indexes; const size_t name_match_count = - m_name_to_index.GetValues(symbol_name, all_name_indexes); + GetNameIndexes(symbol_name, all_name_indexes); for (size_t i = 0; i < name_match_count; ++i) { if (CheckSymbolAtIndex(all_name_indexes[i], symbol_debug_type, symbol_visibility)) @@ -741,8 +809,7 @@ Symtab::FindAllSymbolsWithNameAndType(ConstString name, std::vector &symbol_indexes) { std::lock_guard guard(m_mutex); - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer(func_cat, "%s", LLVM_PRETTY_FUNCTION); + LLDB_SCOPED_TIMER(); // Initialize all of the lookup by name indexes before converting NAME to a // uniqued string NAME_STR below. if (!m_name_indexes_computed) @@ -760,8 +827,7 @@ void Symtab::FindAllSymbolsWithNameAndType( Visibility symbol_visibility, std::vector &symbol_indexes) { std::lock_guard guard(m_mutex); - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer(func_cat, "%s", LLVM_PRETTY_FUNCTION); + LLDB_SCOPED_TIMER(); // Initialize all of the lookup by name indexes before converting NAME to a // uniqued string NAME_STR below. if (!m_name_indexes_computed) @@ -790,9 +856,7 @@ Symbol *Symtab::FindFirstSymbolWithNameAndType(ConstString name, Debug symbol_debug_type, Visibility symbol_visibility) { std::lock_guard guard(m_mutex); - - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer(func_cat, "%s", LLVM_PRETTY_FUNCTION); + LLDB_SCOPED_TIMER(); if (!m_name_indexes_computed) InitNameIndexes(); @@ -1045,45 +1109,18 @@ void Symtab::FindFunctionSymbols(ConstString name, uint32_t name_type_mask, } } - if (name_type_mask & eFunctionNameTypeBase) { - // From mangled names we can't tell what is a basename and what is a method - // name, so we just treat them the same - if (!m_name_indexes_computed) - InitNameIndexes(); - - if (!m_basename_to_index.IsEmpty()) { - const UniqueCStringMap::Entry *match; - for (match = m_basename_to_index.FindFirstValueForName(name); - match != nullptr; - match = m_basename_to_index.FindNextValueForName(match)) { - symbol_indexes.push_back(match->value); - } - } - } - - if (name_type_mask & eFunctionNameTypeMethod) { - if (!m_name_indexes_computed) - InitNameIndexes(); - - if (!m_method_to_index.IsEmpty()) { - const UniqueCStringMap::Entry *match; - for (match = m_method_to_index.FindFirstValueForName(name); - match != nullptr; - match = m_method_to_index.FindNextValueForName(match)) { - symbol_indexes.push_back(match->value); - } - } - } + if (!m_name_indexes_computed) + InitNameIndexes(); - if (name_type_mask & eFunctionNameTypeSelector) { - if (!m_name_indexes_computed) - InitNameIndexes(); + for (lldb::FunctionNameType type : + {lldb::eFunctionNameTypeBase, lldb::eFunctionNameTypeMethod, + lldb::eFunctionNameTypeSelector}) { + if (name_type_mask & type) { + auto map = GetNameToSymbolIndexMap(type); - if (!m_selector_to_index.IsEmpty()) { const UniqueCStringMap::Entry *match; - for (match = m_selector_to_index.FindFirstValueForName(name); - match != nullptr; - match = m_selector_to_index.FindNextValueForName(match)) { + for (match = map.FindFirstValueForName(name); match != nullptr; + match = map.FindNextValueForName(match)) { symbol_indexes.push_back(match->value); } } diff --git a/gnu/llvm/lldb/source/Symbol/Type.cpp b/gnu/llvm/lldb/source/Symbol/Type.cpp index 307e99ac84b..5b4169d256d 100644 --- a/gnu/llvm/lldb/source/Symbol/Type.cpp +++ b/gnu/llvm/lldb/source/Symbol/Type.cpp @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// -#include +#include #include "lldb/Core/Module.h" #include "lldb/Utility/DataBufferHeap.h" @@ -161,16 +161,14 @@ Type::Type(lldb::user_id_t uid, SymbolFile *symbol_file, ConstString name, } Type::Type() - : std::enable_shared_from_this(), UserID(0), m_name(""), - m_symbol_file(nullptr), m_context(nullptr), m_encoding_type(nullptr), - m_encoding_uid(LLDB_INVALID_UID), m_encoding_uid_type(eEncodingInvalid), - m_compiler_type_resolve_state(ResolveState::Unresolved) { + : std::enable_shared_from_this(), UserID(0), + m_name("") { m_byte_size = 0; m_byte_size_has_value = false; } void Type::GetDescription(Stream *s, lldb::DescriptionLevel level, - bool show_name) { + bool show_name, ExecutionContextScope *exe_scope) { *s << "id = " << (const UserID &)*this; // Call the name accessor to make sure we resolve the type name @@ -186,7 +184,7 @@ void Type::GetDescription(Stream *s, lldb::DescriptionLevel level, } // Call the get byte size accesor so we resolve our byte size - if (GetByteSize()) + if (GetByteSize(exe_scope)) s->Printf(", byte-size = %" PRIu64, m_byte_size); bool show_fullpaths = (level == lldb::eDescriptionLevelVerbose); m_decl.Dump(s, show_fullpaths); @@ -323,7 +321,9 @@ void Type::DumpValue(ExecutionContext *exe_ctx, Stream *s, GetForwardCompilerType().DumpValue( exe_ctx, s, format == lldb::eFormatDefault ? GetFormat() : format, data, - data_byte_offset, GetByteSize().getValueOr(0), + data_byte_offset, + GetByteSize(exe_ctx ? exe_ctx->GetBestExecutionContextScope() : nullptr) + .getValueOr(0), 0, // Bitfield bit size 0, // Bitfield bit offset show_types, show_summary, verbose, 0); @@ -336,7 +336,7 @@ Type *Type::GetEncodingType() { return m_encoding_type; } -llvm::Optional Type::GetByteSize() { +llvm::Optional Type::GetByteSize(ExecutionContextScope *exe_scope) { if (m_byte_size_has_value) return m_byte_size; @@ -352,14 +352,14 @@ llvm::Optional Type::GetByteSize() { case eEncodingIsTypedefUID: { Type *encoding_type = GetEncodingType(); if (encoding_type) - if (llvm::Optional size = encoding_type->GetByteSize()) { + if (llvm::Optional size = encoding_type->GetByteSize(exe_scope)) { m_byte_size = *size; m_byte_size_has_value = true; return m_byte_size; } if (llvm::Optional size = - GetLayoutCompilerType().GetByteSize(nullptr)) { + GetLayoutCompilerType().GetByteSize(exe_scope)) { m_byte_size = *size; m_byte_size_has_value = true; return m_byte_size; @@ -373,6 +373,7 @@ llvm::Optional Type::GetByteSize() { if (ArchSpec arch = m_symbol_file->GetObjectFile()->GetArchitecture()) { m_byte_size = arch.GetAddressByteSize(); m_byte_size_has_value = true; + return m_byte_size; } } break; } @@ -430,7 +431,9 @@ bool Type::ReadFromMemory(ExecutionContext *exe_ctx, lldb::addr_t addr, return false; } - const uint64_t byte_size = GetByteSize().getValueOr(0); + const uint64_t byte_size = + GetByteSize(exe_ctx ? exe_ctx->GetBestExecutionContextScope() : nullptr) + .getValueOr(0); if (data.GetByteSize() < byte_size) { lldb::DataBufferSP data_sp(new DataBufferHeap(byte_size, '\0')); data.SetData(data_sp); @@ -722,6 +725,15 @@ ModuleSP Type::GetModule() { return ModuleSP(); } +ModuleSP Type::GetExeModule() { + if (m_compiler_type) { + SymbolFile *symbol_file = m_compiler_type.GetTypeSystem()->GetSymbolFile(); + if (symbol_file) + return symbol_file->GetObjectFile()->GetModule(); + } + return ModuleSP(); +} + TypeAndOrName::TypeAndOrName(TypeSP &in_type_sp) { if (in_type_sp) { m_compiler_type = in_type_sp->GetForwardCompilerType(); @@ -816,6 +828,7 @@ TypeImpl::TypeImpl(const CompilerType &static_type, void TypeImpl::SetType(const lldb::TypeSP &type_sp) { if (type_sp) { m_static_type = type_sp->GetForwardCompilerType(); + m_exe_module_wp = type_sp->GetExeModule(); m_module_wp = type_sp->GetModule(); } else { m_static_type.Clear(); @@ -842,6 +855,15 @@ void TypeImpl::SetType(const CompilerType &compiler_type, } bool TypeImpl::CheckModule(lldb::ModuleSP &module_sp) const { + return CheckModuleCommon(m_module_wp, module_sp); +} + +bool TypeImpl::CheckExeModule(lldb::ModuleSP &module_sp) const { + return CheckModuleCommon(m_exe_module_wp, module_sp); +} + +bool TypeImpl::CheckModuleCommon(const lldb::ModuleWP &input_module_wp, + lldb::ModuleSP &module_sp) const { // Check if we have a module for this type. If we do and the shared pointer // is can be successfully initialized with m_module_wp, return true. Else // return false if we didn't have a module, or if we had a module and it has @@ -850,7 +872,7 @@ bool TypeImpl::CheckModule(lldb::ModuleSP &module_sp) const { // this function returns true. If we have a module, the "module_sp" will be // filled in with a strong reference to the module so that the module will at // least stay around long enough for the type query to succeed. - module_sp = m_module_wp.lock(); + module_sp = input_module_wp.lock(); if (!module_sp) { lldb::ModuleWP empty_module_wp; // If either call to "std::weak_ptr::owner_before(...) value returns true, @@ -858,9 +880,9 @@ bool TypeImpl::CheckModule(lldb::ModuleSP &module_sp) const { // reference to a valid shared pointer. This helps us know if we had a // valid reference to a section which is now invalid because the module it // was in was deleted - if (empty_module_wp.owner_before(m_module_wp) || - m_module_wp.owner_before(empty_module_wp)) { - // m_module_wp had a valid reference to a module, but all strong + if (empty_module_wp.owner_before(input_module_wp) || + input_module_wp.owner_before(empty_module_wp)) { + // input_module_wp had a valid reference to a module, but all strong // references have been released and the module has been deleted return false; } @@ -894,6 +916,13 @@ void TypeImpl::Clear() { m_dynamic_type.Clear(); } +ModuleSP TypeImpl::GetModule() const { + lldb::ModuleSP module_sp; + if (CheckExeModule(module_sp)) + return module_sp; + return nullptr; +} + ConstString TypeImpl::GetName() const { ModuleSP module_sp; if (CheckModule(module_sp)) { diff --git a/gnu/llvm/lldb/source/Symbol/TypeList.cpp b/gnu/llvm/lldb/source/Symbol/TypeList.cpp index f0506c7c5bf..ace715d933e 100644 --- a/gnu/llvm/lldb/source/Symbol/TypeList.cpp +++ b/gnu/llvm/lldb/source/Symbol/TypeList.cpp @@ -22,7 +22,7 @@ using namespace lldb_private; TypeList::TypeList() : m_types() {} // Destructor -TypeList::~TypeList() {} +TypeList::~TypeList() = default; void TypeList::Insert(const TypeSP &type_sp) { // Just push each type on the back for now. We will worry about uniquing diff --git a/gnu/llvm/lldb/source/Symbol/TypeMap.cpp b/gnu/llvm/lldb/source/Symbol/TypeMap.cpp index e810d302007..2cda9b6c27d 100644 --- a/gnu/llvm/lldb/source/Symbol/TypeMap.cpp +++ b/gnu/llvm/lldb/source/Symbol/TypeMap.cpp @@ -22,7 +22,7 @@ using namespace lldb_private; TypeMap::TypeMap() : m_types() {} // Destructor -TypeMap::~TypeMap() {} +TypeMap::~TypeMap() = default; void TypeMap::Insert(const TypeSP &type_sp) { // Just push each type on the back for now. We will worry about uniquing diff --git a/gnu/llvm/lldb/source/Symbol/TypeSystem.cpp b/gnu/llvm/lldb/source/Symbol/TypeSystem.cpp index 5e57813c28b..0b3f7e4f3bd 100644 --- a/gnu/llvm/lldb/source/Symbol/TypeSystem.cpp +++ b/gnu/llvm/lldb/source/Symbol/TypeSystem.cpp @@ -6,22 +6,14 @@ // //===----------------------------------------------------------------------===// -// -// TypeSystem.cpp -// lldb -// -// Created by Ryan Brown on 3/29/15. -// -// - #include "lldb/Symbol/TypeSystem.h" - -#include - #include "lldb/Core/PluginManager.h" +#include "lldb/Expression/UtilityFunction.h" #include "lldb/Symbol/CompilerType.h" #include "lldb/Target/Language.h" +#include + using namespace lldb_private; using namespace lldb; @@ -43,7 +35,7 @@ size_t LanguageSet::Size() const { return bitvector.count(); } bool LanguageSet::Empty() const { return bitvector.none(); } bool LanguageSet::operator[](unsigned i) const { return bitvector[i]; } -TypeSystem::~TypeSystem() {} +TypeSystem::~TypeSystem() = default; static lldb::TypeSystemSP CreateInstanceHelper(lldb::LanguageType language, Module *module, Target *target) { @@ -179,12 +171,16 @@ TypeSystem::DeclContextFindDeclByName(void *opaque_decl_ctx, ConstString name, return std::vector(); } +std::unique_ptr +TypeSystem::CreateUtilityFunction(std::string text, std::string name) { + return {}; +} + #pragma mark TypeSystemMap -TypeSystemMap::TypeSystemMap() - : m_mutex(), m_map(), m_clear_in_progress(false) {} +TypeSystemMap::TypeSystemMap() : m_mutex(), m_map() {} -TypeSystemMap::~TypeSystemMap() {} +TypeSystemMap::~TypeSystemMap() = default; void TypeSystemMap::Clear() { collection map; @@ -224,65 +220,35 @@ void TypeSystemMap::ForEach(std::function const &callback) { } } -llvm::Expected -TypeSystemMap::GetTypeSystemForLanguage(lldb::LanguageType language, - Module *module, bool can_create) { - llvm::Error error = llvm::Error::success(); - assert(!error); // Check the success value when assertions are enabled +llvm::Expected TypeSystemMap::GetTypeSystemForLanguage( + lldb::LanguageType language, + llvm::Optional create_callback) { std::lock_guard guard(m_mutex); - if (m_clear_in_progress) { - error = llvm::make_error( + if (m_clear_in_progress) + return llvm::make_error( "Unable to get TypeSystem because TypeSystemMap is being cleared", llvm::inconvertibleErrorCode()); - } else { - collection::iterator pos = m_map.find(language); - if (pos != m_map.end()) { - auto *type_system = pos->second.get(); - if (type_system) { - llvm::consumeError(std::move(error)); - return *type_system; - } - error = llvm::make_error( - "TypeSystem for language " + - llvm::StringRef(Language::GetNameForLanguageType(language)) + - " doesn't exist", - llvm::inconvertibleErrorCode()); - return std::move(error); - } - for (const auto &pair : m_map) { - if (pair.second && pair.second->SupportsLanguage(language)) { - // Add a new mapping for "language" to point to an already existing - // TypeSystem that supports this language - m_map[language] = pair.second; - if (pair.second.get()) { - llvm::consumeError(std::move(error)); - return *pair.second.get(); - } - error = llvm::make_error( - "TypeSystem for language " + - llvm::StringRef(Language::GetNameForLanguageType(language)) + - " doesn't exist", - llvm::inconvertibleErrorCode()); - return std::move(error); - } - } + collection::iterator pos = m_map.find(language); + if (pos != m_map.end()) { + auto *type_system = pos->second.get(); + if (type_system) + return *type_system; + return llvm::make_error( + "TypeSystem for language " + + llvm::StringRef(Language::GetNameForLanguageType(language)) + + " doesn't exist", + llvm::inconvertibleErrorCode()); + } - if (!can_create) { - error = llvm::make_error( - "Unable to find type system for language " + - llvm::StringRef(Language::GetNameForLanguageType(language)), - llvm::inconvertibleErrorCode()); - } else { - // Cache even if we get a shared pointer that contains a null type system - // back - auto type_system_sp = TypeSystem::CreateInstance(language, module); - m_map[language] = type_system_sp; - if (type_system_sp.get()) { - llvm::consumeError(std::move(error)); - return *type_system_sp.get(); - } - error = llvm::make_error( + for (const auto &pair : m_map) { + if (pair.second && pair.second->SupportsLanguage(language)) { + // Add a new mapping for "language" to point to an already existing + // TypeSystem that supports this language + m_map[language] = pair.second; + if (pair.second.get()) + return *pair.second.get(); + return llvm::make_error( "TypeSystem for language " + llvm::StringRef(Language::GetNameForLanguageType(language)) + " doesn't exist", @@ -290,74 +256,45 @@ TypeSystemMap::GetTypeSystemForLanguage(lldb::LanguageType language, } } - return std::move(error); + if (!create_callback) + return llvm::make_error( + "Unable to find type system for language " + + llvm::StringRef(Language::GetNameForLanguageType(language)), + llvm::inconvertibleErrorCode()); + + // Cache even if we get a shared pointer that contains a null type system + // back + TypeSystemSP type_system_sp = (*create_callback)(); + m_map[language] = type_system_sp; + if (type_system_sp.get()) + return *type_system_sp.get(); + return llvm::make_error( + "TypeSystem for language " + + llvm::StringRef(Language::GetNameForLanguageType(language)) + + " doesn't exist", + llvm::inconvertibleErrorCode()); } llvm::Expected TypeSystemMap::GetTypeSystemForLanguage(lldb::LanguageType language, - Target *target, bool can_create) { - llvm::Error error = llvm::Error::success(); - assert(!error); // Check the success value when assertions are enabled - std::lock_guard guard(m_mutex); - if (m_clear_in_progress) { - error = llvm::make_error( - "Unable to get TypeSystem because TypeSystemMap is being cleared", - llvm::inconvertibleErrorCode()); - } else { - collection::iterator pos = m_map.find(language); - if (pos != m_map.end()) { - auto *type_system = pos->second.get(); - if (type_system) { - llvm::consumeError(std::move(error)); - return *type_system; - } - error = llvm::make_error( - "TypeSystem for language " + - llvm::StringRef(Language::GetNameForLanguageType(language)) + - " doesn't exist", - llvm::inconvertibleErrorCode()); - return std::move(error); - } - - for (const auto &pair : m_map) { - if (pair.second && pair.second->SupportsLanguage(language)) { - // Add a new mapping for "language" to point to an already existing - // TypeSystem that supports this language - m_map[language] = pair.second; - if (pair.second.get()) { - llvm::consumeError(std::move(error)); - return *pair.second.get(); - } - error = llvm::make_error( - "TypeSystem for language " + - llvm::StringRef(Language::GetNameForLanguageType(language)) + - " doesn't exist", - llvm::inconvertibleErrorCode()); - return std::move(error); - } - } - - if (!can_create) { - error = llvm::make_error( - "Unable to find type system for language " + - llvm::StringRef(Language::GetNameForLanguageType(language)), - llvm::inconvertibleErrorCode()); - } else { - // Cache even if we get a shared pointer that contains a null type system - // back - auto type_system_sp = TypeSystem::CreateInstance(language, target); - m_map[language] = type_system_sp; - if (type_system_sp.get()) { - llvm::consumeError(std::move(error)); - return *type_system_sp.get(); - } - error = llvm::make_error( - "TypeSystem for language " + - llvm::StringRef(Language::GetNameForLanguageType(language)) + - " doesn't exist", - llvm::inconvertibleErrorCode()); - } + Module *module, bool can_create) { + if (can_create) { + return GetTypeSystemForLanguage( + language, llvm::Optional([language, module]() { + return TypeSystem::CreateInstance(language, module); + })); } + return GetTypeSystemForLanguage(language); +} - return std::move(error); +llvm::Expected +TypeSystemMap::GetTypeSystemForLanguage(lldb::LanguageType language, + Target *target, bool can_create) { + if (can_create) { + return GetTypeSystemForLanguage( + language, llvm::Optional([language, target]() { + return TypeSystem::CreateInstance(language, target); + })); + } + return GetTypeSystemForLanguage(language); } diff --git a/gnu/llvm/lldb/source/Symbol/UnwindPlan.cpp b/gnu/llvm/lldb/source/Symbol/UnwindPlan.cpp index e8906f38e2f..41bd8cd46ad 100644 --- a/gnu/llvm/lldb/source/Symbol/UnwindPlan.cpp +++ b/gnu/llvm/lldb/source/Symbol/UnwindPlan.cpp @@ -83,7 +83,7 @@ static void DumpDWARFExpr(Stream &s, llvm::ArrayRef expr, Thread *threa llvm::DataExtractor data(expr, order_and_width->first == eByteOrderLittle, order_and_width->second); llvm::DWARFExpression(data, order_and_width->second, llvm::dwarf::DWARF32) - .print(s.AsRawOstream(), nullptr, nullptr); + .print(s.AsRawOstream(), llvm::DIDumpOptions(), nullptr, nullptr); } else s.PutCString("dwarf-expr"); } @@ -217,6 +217,7 @@ void UnwindPlan::Row::Clear() { m_cfa_value.SetUnspecified(); m_afa_value.SetUnspecified(); m_offset = 0; + m_unspecified_registers_are_undefined = false; m_register_locations.clear(); } @@ -242,11 +243,9 @@ void UnwindPlan::Row::Dump(Stream &s, const UnwindPlan *unwind_plan, idx->second.Dump(s, unwind_plan, this, thread, verbose); s.PutChar(' '); } - s.EOL(); } -UnwindPlan::Row::Row() - : m_offset(0), m_cfa_value(), m_afa_value(), m_register_locations() {} +UnwindPlan::Row::Row() : m_cfa_value(), m_afa_value(), m_register_locations() {} bool UnwindPlan::Row::GetRegisterInfo( uint32_t reg_num, @@ -256,6 +255,10 @@ bool UnwindPlan::Row::GetRegisterInfo( register_location = pos->second; return true; } + if (m_unspecified_registers_are_undefined) { + register_location.SetUndefined(); + return true; + } return false; } @@ -348,10 +351,11 @@ bool UnwindPlan::Row::SetRegisterLocationToSame(uint32_t reg_num, } bool UnwindPlan::Row::operator==(const UnwindPlan::Row &rhs) const { - return m_offset == rhs.m_offset && - m_cfa_value == rhs.m_cfa_value && - m_afa_value == rhs.m_afa_value && - m_register_locations == rhs.m_register_locations; + return m_offset == rhs.m_offset && m_cfa_value == rhs.m_cfa_value && + m_afa_value == rhs.m_afa_value && + m_unspecified_registers_are_undefined == + rhs.m_unspecified_registers_are_undefined && + m_register_locations == rhs.m_register_locations; } void UnwindPlan::AppendRow(const UnwindPlan::RowSP &row_sp) { @@ -527,6 +531,18 @@ void UnwindPlan::Dump(Stream &s, Thread *thread, lldb::addr_t base_addr) const { s.Printf("not specified.\n"); break; } + s.Printf("This UnwindPlan is for a trap handler function: "); + switch (m_plan_is_for_signal_trap) { + case eLazyBoolYes: + s.Printf("yes.\n"); + break; + case eLazyBoolNo: + s.Printf("no.\n"); + break; + case eLazyBoolCalculate: + s.Printf("not specified.\n"); + break; + } if (m_plan_valid_address_range.GetBaseAddress().IsValid() && m_plan_valid_address_range.GetByteSize() > 0) { s.PutCString("Address range of this UnwindPlan: "); @@ -540,6 +556,7 @@ void UnwindPlan::Dump(Stream &s, Thread *thread, lldb::addr_t base_addr) const { for (pos = begin; pos != end; ++pos) { s.Printf("row[%u]: ", (uint32_t)std::distance(begin, pos)); (*pos)->Dump(s, this, thread, base_addr); + s.Printf("\n"); } } diff --git a/gnu/llvm/lldb/source/Symbol/UnwindTable.cpp b/gnu/llvm/lldb/source/Symbol/UnwindTable.cpp index 3faa528a339..fe69e41b363 100644 --- a/gnu/llvm/lldb/source/Symbol/UnwindTable.cpp +++ b/gnu/llvm/lldb/source/Symbol/UnwindTable.cpp @@ -8,7 +8,7 @@ #include "lldb/Symbol/UnwindTable.h" -#include +#include #include "lldb/Core/Module.h" #include "lldb/Core/Section.h" @@ -83,7 +83,7 @@ void UnwindTable::Initialize() { } } -UnwindTable::~UnwindTable() {} +UnwindTable::~UnwindTable() = default; llvm::Optional UnwindTable::GetAddressRange(const Address &addr, SymbolContext &sc) { diff --git a/gnu/llvm/lldb/source/Symbol/Variable.cpp b/gnu/llvm/lldb/source/Symbol/Variable.cpp index 6c18ef15e1a..89682fc3914 100644 --- a/gnu/llvm/lldb/source/Symbol/Variable.cpp +++ b/gnu/llvm/lldb/source/Symbol/Variable.cpp @@ -40,15 +40,16 @@ Variable::Variable(lldb::user_id_t uid, const char *name, const char *mangled, ValueType scope, SymbolContextScope *context, const RangeList &scope_range, Declaration *decl_ptr, const DWARFExpression &location, bool external, - bool artificial, bool static_member) + bool artificial, bool location_is_constant_data, + bool static_member) : UserID(uid), m_name(name), m_mangled(ConstString(mangled)), m_symfile_type_sp(symfile_type_sp), m_scope(scope), m_owner_scope(context), m_scope_range(scope_range), m_declaration(decl_ptr), m_location(location), m_external(external), - m_artificial(artificial), m_loc_is_const_data(false), + m_artificial(artificial), m_loc_is_const_data(location_is_constant_data), m_static_member(static_member) {} -Variable::~Variable() {} +Variable::~Variable() = default; lldb::LanguageType Variable::GetLanguage() const { lldb::LanguageType lang = m_mangled.GuessLanguage(); diff --git a/gnu/llvm/lldb/source/Symbol/VariableList.cpp b/gnu/llvm/lldb/source/Symbol/VariableList.cpp index f7a441472bc..b7a396edd70 100644 --- a/gnu/llvm/lldb/source/Symbol/VariableList.cpp +++ b/gnu/llvm/lldb/source/Symbol/VariableList.cpp @@ -20,7 +20,7 @@ using namespace lldb_private; VariableList::VariableList() : m_variables() {} // Destructor -VariableList::~VariableList() {} +VariableList::~VariableList() = default; void VariableList::AddVariable(const VariableSP &var_sp) { m_variables.push_back(var_sp); diff --git a/gnu/llvm/lldb/source/Target/ABI.cpp b/gnu/llvm/lldb/source/Target/ABI.cpp index 4320eb93adf..c3342caf874 100644 --- a/gnu/llvm/lldb/source/Target/ABI.cpp +++ b/gnu/llvm/lldb/source/Target/ABI.cpp @@ -42,27 +42,22 @@ ABI::FindPlugin(lldb::ProcessSP process_sp, const ArchSpec &arch) { ABI::~ABI() = default; -bool RegInfoBasedABI::GetRegisterInfoByName(ConstString name, RegisterInfo &info) { +bool RegInfoBasedABI::GetRegisterInfoByName(llvm::StringRef name, + RegisterInfo &info) { uint32_t count = 0; const RegisterInfo *register_info_array = GetRegisterInfoArray(count); if (register_info_array) { - const char *unique_name_cstr = name.GetCString(); uint32_t i; for (i = 0; i < count; ++i) { const char *reg_name = register_info_array[i].name; - assert(ConstString(reg_name).GetCString() == reg_name && - "register_info_array[i].name not from a ConstString?"); - if (reg_name == unique_name_cstr) { + if (reg_name == name) { info = register_info_array[i]; return true; } } for (i = 0; i < count; ++i) { const char *reg_alt_name = register_info_array[i].alt_name; - assert((reg_alt_name == nullptr || - ConstString(reg_alt_name).GetCString() == reg_alt_name) && - "register_info_array[i].alt_name not from a ConstString?"); - if (reg_alt_name == unique_name_cstr) { + if (reg_alt_name == name) { info = register_info_array[i]; return true; } @@ -125,12 +120,13 @@ ValueObjectSP ABI::GetReturnValueObject(Thread &thread, CompilerType &ast_type, const Value &result_value = live_valobj_sp->GetValue(); switch (result_value.GetValueType()) { - case Value::eValueTypeHostAddress: - case Value::eValueTypeFileAddress: - // we don't do anything with these for now + case Value::ValueType::Invalid: + return {}; + case Value::ValueType::HostAddress: + case Value::ValueType::FileAddress: + // we odon't do anything with these for now break; - case Value::eValueTypeScalar: - case Value::eValueTypeVector: + case Value::ValueType::Scalar: expr_variable_sp->m_flags |= ExpressionVariable::EVIsFreezeDried; expr_variable_sp->m_flags |= @@ -138,7 +134,7 @@ ValueObjectSP ABI::GetReturnValueObject(Thread &thread, CompilerType &ast_type, expr_variable_sp->m_flags |= ExpressionVariable::EVNeedsAllocation; break; - case Value::eValueTypeLoadAddress: + case Value::ValueType::LoadAddress: expr_variable_sp->m_live_sp = live_valobj_sp; expr_variable_sp->m_flags |= ExpressionVariable::EVIsProgramReference; @@ -224,7 +220,7 @@ void RegInfoBasedABI::AugmentRegisterInfo(RegisterInfo &info) { return; RegisterInfo abi_info; - if (!GetRegisterInfoByName(ConstString(info.name), abi_info)) + if (!GetRegisterInfoByName(info.name, abi_info)) return; if (info.kinds[eRegisterKindEHFrame] == LLDB_INVALID_REGNUM) diff --git a/gnu/llvm/lldb/source/Target/AssertFrameRecognizer.cpp b/gnu/llvm/lldb/source/Target/AssertFrameRecognizer.cpp index d87459ac2fd..a2315b6d63c 100644 --- a/gnu/llvm/lldb/source/Target/AssertFrameRecognizer.cpp +++ b/gnu/llvm/lldb/source/Target/AssertFrameRecognizer.cpp @@ -22,6 +22,10 @@ namespace lldb_private { struct SymbolLocation { FileSpec module_spec; std::vector symbols; + + // The symbols are regular expressions. In such case all symbols are matched + // with their trailing @VER symbol version stripped. + bool symbols_are_regex = false; }; /// Fetches the abort frame location depending on the current platform. @@ -45,6 +49,8 @@ bool GetAbortLocation(llvm::Triple::OSType os, SymbolLocation &location) { location.symbols.push_back(ConstString("raise")); location.symbols.push_back(ConstString("__GI_raise")); location.symbols.push_back(ConstString("gsignal")); + location.symbols.push_back(ConstString("pthread_kill")); + location.symbols_are_regex = true; break; default: Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND)); @@ -86,20 +92,41 @@ bool GetAssertLocation(llvm::Triple::OSType os, SymbolLocation &location) { } void RegisterAssertFrameRecognizer(Process *process) { - static llvm::once_flag g_once_flag; - llvm::call_once(g_once_flag, [process]() { - Target &target = process->GetTarget(); - llvm::Triple::OSType os = target.GetArchitecture().GetTriple().getOS(); - SymbolLocation location; + Target &target = process->GetTarget(); + llvm::Triple::OSType os = target.GetArchitecture().GetTriple().getOS(); + SymbolLocation location; - if (!GetAbortLocation(os, location)) - return; + if (!GetAbortLocation(os, location)) + return; - StackFrameRecognizerManager::AddRecognizer( - StackFrameRecognizerSP(new AssertFrameRecognizer()), + if (!location.symbols_are_regex) { + target.GetFrameRecognizerManager().AddRecognizer( + std::make_shared(), location.module_spec.GetFilename(), location.symbols, /*first_instruction_only*/ false); - }); + return; + } + std::string module_re = "^"; + for (char c : location.module_spec.GetFilename().GetStringRef()) { + if (c == '.') + module_re += '\\'; + module_re += c; + } + module_re += '$'; + std::string symbol_re = "^("; + for (auto it = location.symbols.cbegin(); it != location.symbols.cend(); + ++it) { + if (it != location.symbols.cbegin()) + symbol_re += '|'; + symbol_re += it->GetStringRef(); + } + // Strip the trailing @VER symbol version. + symbol_re += ")(@.*)?$"; + target.GetFrameRecognizerManager().AddRecognizer( + std::make_shared(), + std::make_shared(std::move(module_re)), + std::make_shared(std::move(symbol_re)), + /*first_instruction_only*/ false); } } // namespace lldb_private @@ -115,7 +142,7 @@ AssertFrameRecognizer::RecognizeFrame(lldb::StackFrameSP frame_sp) { if (!GetAssertLocation(os, location)) return RecognizedStackFrameSP(); - const uint32_t frames_to_fetch = 5; + const uint32_t frames_to_fetch = 6; const uint32_t last_frame_index = frames_to_fetch - 1; StackFrameSP prev_frame_sp = nullptr; @@ -133,7 +160,8 @@ AssertFrameRecognizer::RecognizeFrame(lldb::StackFrameSP frame_sp) { SymbolContext sym_ctx = prev_frame_sp->GetSymbolContext(eSymbolContextEverything); - if (!sym_ctx.module_sp->GetFileSpec().FileEquals(location.module_spec)) + if (!sym_ctx.module_sp || + !sym_ctx.module_sp->GetFileSpec().FileEquals(location.module_spec)) continue; ConstString func_name = sym_ctx.GetFunctionName(); diff --git a/gnu/llvm/lldb/source/Target/CMakeLists.txt b/gnu/llvm/lldb/source/Target/CMakeLists.txt index ca80b5b6477..2405258bc41 100644 --- a/gnu/llvm/lldb/source/Target/CMakeLists.txt +++ b/gnu/llvm/lldb/source/Target/CMakeLists.txt @@ -24,6 +24,7 @@ add_lldb_library(lldbTarget PathMappingList.cpp Platform.cpp Process.cpp + ProcessTrace.cpp Queue.cpp QueueItem.cpp QueueList.cpp @@ -65,6 +66,10 @@ add_lldb_library(lldbTarget ThreadPlanTracer.cpp ThreadPlanStack.cpp ThreadSpec.cpp + Trace.cpp + TraceCursor.cpp + TraceExporter.cpp + TraceInstructionDumper.cpp UnixSignals.cpp UnwindAssembly.cpp UnwindLLDB.cpp @@ -77,7 +82,6 @@ add_lldb_library(lldbTarget lldbInterpreter lldbSymbol lldbUtility - lldbPluginExpressionParserClang lldbPluginProcessUtility LINK_COMPONENTS diff --git a/gnu/llvm/lldb/source/Target/ExecutionContext.cpp b/gnu/llvm/lldb/source/Target/ExecutionContext.cpp index 20932ee63dc..b5cf13582af 100644 --- a/gnu/llvm/lldb/source/Target/ExecutionContext.cpp +++ b/gnu/llvm/lldb/source/Target/ExecutionContext.cpp @@ -395,8 +395,7 @@ bool ExecutionContext::HasFrameScope() const { } ExecutionContextRef::ExecutionContextRef() - : m_target_wp(), m_process_wp(), m_thread_wp(), - m_tid(LLDB_INVALID_THREAD_ID), m_stack_id() {} + : m_target_wp(), m_process_wp(), m_thread_wp(), m_stack_id() {} ExecutionContextRef::ExecutionContextRef(const ExecutionContext *exe_ctx) : m_target_wp(), m_process_wp(), m_thread_wp(), diff --git a/gnu/llvm/lldb/source/Target/JITLoaderList.cpp b/gnu/llvm/lldb/source/Target/JITLoaderList.cpp index f5a90d58d58..92e841b5c94 100644 --- a/gnu/llvm/lldb/source/Target/JITLoaderList.cpp +++ b/gnu/llvm/lldb/source/Target/JITLoaderList.cpp @@ -15,7 +15,7 @@ using namespace lldb_private; JITLoaderList::JITLoaderList() : m_jit_loaders_vec(), m_jit_loaders_mutex() {} -JITLoaderList::~JITLoaderList() {} +JITLoaderList::~JITLoaderList() = default; void JITLoaderList::Append(const JITLoaderSP &jit_loader_sp) { std::lock_guard guard(m_jit_loaders_mutex); diff --git a/gnu/llvm/lldb/source/Target/Language.cpp b/gnu/llvm/lldb/source/Target/Language.cpp index b1a8a9517f3..7b35da5028a 100644 --- a/gnu/llvm/lldb/source/Target/Language.cpp +++ b/gnu/llvm/lldb/source/Target/Language.cpp @@ -184,7 +184,7 @@ struct language_name_pair language_names[] = { {"fortran03", eLanguageTypeFortran03}, {"fortran08", eLanguageTypeFortran08}, // Vendor Extensions - {"mipsassem", eLanguageTypeMipsAssembler}, + {"assembler", eLanguageTypeMipsAssembler}, {"renderscript", eLanguageTypeExtRenderScript}, // Now synonyms, in arbitrary order {"objc", eLanguageTypeObjC}, @@ -196,7 +196,7 @@ static uint32_t num_languages = LanguageType Language::GetLanguageTypeFromString(llvm::StringRef string) { for (const auto &L : language_names) { - if (string.equals_lower(L.name)) + if (string.equals_insensitive(L.name)) return static_cast(L.type); } @@ -448,7 +448,7 @@ void Language::GetDefaultExceptionResolverDescription(bool catch_on, catch_on ? "on" : "off", throw_on ? "on" : "off"); } // Constructor -Language::Language() {} +Language::Language() = default; // Destructor -Language::~Language() {} +Language::~Language() = default; diff --git a/gnu/llvm/lldb/source/Target/LanguageRuntime.cpp b/gnu/llvm/lldb/source/Target/LanguageRuntime.cpp index 58ad70c2b90..be878d69fa0 100644 --- a/gnu/llvm/lldb/source/Target/LanguageRuntime.cpp +++ b/gnu/llvm/lldb/source/Target/LanguageRuntime.cpp @@ -202,26 +202,19 @@ protected: LanguageRuntime *LanguageRuntime::FindPlugin(Process *process, lldb::LanguageType language) { - std::unique_ptr language_runtime_up; LanguageRuntimeCreateInstance create_callback; - for (uint32_t idx = 0; (create_callback = PluginManager::GetLanguageRuntimeCreateCallbackAtIndex(idx)) != nullptr; ++idx) { - language_runtime_up.reset(create_callback(process, language)); - - if (language_runtime_up) - return language_runtime_up.release(); + if (LanguageRuntime *runtime = create_callback(process, language)) + return runtime; } - return nullptr; } -LanguageRuntime::LanguageRuntime(Process *process) : m_process(process) {} - -LanguageRuntime::~LanguageRuntime() = default; +LanguageRuntime::LanguageRuntime(Process *process) : Runtime(process) {} BreakpointPreconditionSP LanguageRuntime::GetExceptionPrecondition(LanguageType language, @@ -266,6 +259,25 @@ BreakpointSP LanguageRuntime::CreateExceptionBreakpoint( return exc_breakpt_sp; } +UnwindPlanSP +LanguageRuntime::GetRuntimeUnwindPlan(Thread &thread, RegisterContext *regctx, + bool &behaves_like_zeroth_frame) { + ProcessSP process_sp = thread.GetProcess(); + if (!process_sp.get()) + return UnwindPlanSP(); + if (process_sp->GetDisableLangRuntimeUnwindPlans() == true) + return UnwindPlanSP(); + for (const lldb::LanguageType lang_type : Language::GetSupportedLanguages()) { + if (LanguageRuntime *runtime = process_sp->GetLanguageRuntime(lang_type)) { + UnwindPlanSP plan_sp = runtime->GetRuntimeUnwindPlan( + process_sp, regctx, behaves_like_zeroth_frame); + if (plan_sp.get()) + return plan_sp; + } + } + return UnwindPlanSP(); +} + void LanguageRuntime::InitializeCommands(CommandObject *parent) { if (!parent) return; diff --git a/gnu/llvm/lldb/source/Target/Memory.cpp b/gnu/llvm/lldb/source/Target/Memory.cpp index a7ed1a3d97b..806e92aa4ed 100644 --- a/gnu/llvm/lldb/source/Target/Memory.cpp +++ b/gnu/llvm/lldb/source/Target/Memory.cpp @@ -26,7 +26,7 @@ MemoryCache::MemoryCache(Process &process) m_L2_cache_line_byte_size(process.GetMemoryCacheLineSize()) {} // Destructor -MemoryCache::~MemoryCache() {} +MemoryCache::~MemoryCache() = default; void MemoryCache::Clear(bool clear_invalid_ranges) { std::lock_guard guard(m_mutex); @@ -259,7 +259,7 @@ AllocatedBlock::AllocatedBlock(lldb::addr_t addr, uint32_t byte_size, assert(byte_size > chunk_size); } -AllocatedBlock::~AllocatedBlock() {} +AllocatedBlock::~AllocatedBlock() = default; lldb::addr_t AllocatedBlock::ReserveBlock(uint32_t size) { // We must return something valid for zero bytes. @@ -329,7 +329,7 @@ bool AllocatedBlock::FreeBlock(addr_t addr) { AllocatedMemoryCache::AllocatedMemoryCache(Process &process) : m_process(process), m_mutex(), m_memory_map() {} -AllocatedMemoryCache::~AllocatedMemoryCache() {} +AllocatedMemoryCache::~AllocatedMemoryCache() = default; void AllocatedMemoryCache::Clear() { std::lock_guard guard(m_mutex); diff --git a/gnu/llvm/lldb/source/Target/MemoryRegionInfo.cpp b/gnu/llvm/lldb/source/Target/MemoryRegionInfo.cpp index c7fb349ee1c..0d5ebbdbe23 100644 --- a/gnu/llvm/lldb/source/Target/MemoryRegionInfo.cpp +++ b/gnu/llvm/lldb/source/Target/MemoryRegionInfo.cpp @@ -13,12 +13,12 @@ using namespace lldb_private; llvm::raw_ostream &lldb_private::operator<<(llvm::raw_ostream &OS, const MemoryRegionInfo &Info) { return OS << llvm::formatv("MemoryRegionInfo([{0}, {1}), {2:r}{3:w}{4:x}, " - "{5}, `{6}`, {7}, {8})", + "{5}, `{6}`, {7}, {8}, {9})", Info.GetRange().GetRangeBase(), Info.GetRange().GetRangeEnd(), Info.GetReadable(), Info.GetWritable(), Info.GetExecutable(), Info.GetMapped(), Info.GetName(), Info.GetFlash(), - Info.GetBlocksize()); + Info.GetBlocksize(), Info.GetMemoryTagged()); } void llvm::format_provider::format( diff --git a/gnu/llvm/lldb/source/Target/ModuleCache.cpp b/gnu/llvm/lldb/source/Target/ModuleCache.cpp index 20661a7b7a2..dcdc0772b31 100644 --- a/gnu/llvm/lldb/source/Target/ModuleCache.cpp +++ b/gnu/llvm/lldb/source/Target/ModuleCache.cpp @@ -17,7 +17,7 @@ #include "llvm/Support/FileSystem.h" #include "llvm/Support/FileUtilities.h" -#include +#include #include diff --git a/gnu/llvm/lldb/source/Target/OperatingSystem.cpp b/gnu/llvm/lldb/source/Target/OperatingSystem.cpp index ddffab4553c..033a806460d 100644 --- a/gnu/llvm/lldb/source/Target/OperatingSystem.cpp +++ b/gnu/llvm/lldb/source/Target/OperatingSystem.cpp @@ -44,8 +44,6 @@ OperatingSystem *OperatingSystem::FindPlugin(Process *process, OperatingSystem::OperatingSystem(Process *process) : m_process(process) {} -OperatingSystem::~OperatingSystem() = default; - bool OperatingSystem::IsOperatingSystemPluginThread( const lldb::ThreadSP &thread_sp) { if (thread_sp) diff --git a/gnu/llvm/lldb/source/Target/PathMappingList.cpp b/gnu/llvm/lldb/source/Target/PathMappingList.cpp index b22673f5547..b660c310ef3 100644 --- a/gnu/llvm/lldb/source/Target/PathMappingList.cpp +++ b/gnu/llvm/lldb/source/Target/PathMappingList.cpp @@ -37,8 +37,7 @@ namespace { } } // PathMappingList constructor -PathMappingList::PathMappingList() - : m_pairs(), m_callback(nullptr), m_callback_baton(nullptr), m_mod_id(0) {} +PathMappingList::PathMappingList() : m_pairs() {} PathMappingList::PathMappingList(ChangedCallback callback, void *callback_baton) : m_pairs(), m_callback(callback), m_callback_baton(callback_baton), @@ -146,21 +145,37 @@ void PathMappingList::Clear(bool notify) { bool PathMappingList::RemapPath(ConstString path, ConstString &new_path) const { - std::string remapped; - if (RemapPath(path.GetStringRef(), remapped)) { - new_path.SetString(remapped); + if (llvm::Optional remapped = RemapPath(path.GetStringRef())) { + new_path.SetString(remapped->GetPath()); return true; } return false; } -bool PathMappingList::RemapPath(llvm::StringRef path, - std::string &new_path) const { - if (m_pairs.empty() || path.empty()) - return false; +/// Append components to path, applying style. +static void AppendPathComponents(FileSpec &path, llvm::StringRef components, + llvm::sys::path::Style style) { + auto component = llvm::sys::path::begin(components, style); + auto e = llvm::sys::path::end(components); + while (component != e && + llvm::sys::path::is_separator(*component->data(), style)) + ++component; + for (; component != e; ++component) + path.AppendPathComponent(*component); +} + +llvm::Optional +PathMappingList::RemapPath(llvm::StringRef mapping_path, + bool only_if_exists) const { + if (m_pairs.empty() || mapping_path.empty()) + return {}; LazyBool path_is_relative = eLazyBoolCalculate; + for (const auto &it : m_pairs) { - auto prefix = it.first.GetStringRef(); + llvm::StringRef prefix = it.first.GetStringRef(); + // We create a copy of mapping_path because StringRef::consume_from + // effectively modifies the instance itself. + llvm::StringRef path = mapping_path; if (!path.consume_front(prefix)) { // Relative paths won't have a leading "./" in them unless "." is the // only thing in the relative path so we need to work around "." @@ -177,11 +192,13 @@ bool PathMappingList::RemapPath(llvm::StringRef path, continue; } FileSpec remapped(it.second.GetStringRef()); - remapped.AppendPathComponent(path); - new_path = remapped.GetPath(); - return true; + auto orig_style = FileSpec::GuessPathStyle(prefix).getValueOr( + llvm::sys::path::Style::native); + AppendPathComponents(remapped, path, orig_style); + if (!only_if_exists || FileSystem::Instance().Exists(remapped)) + return remapped; } - return false; + return {}; } bool PathMappingList::ReverseRemapPath(const FileSpec &file, FileSpec &fixed) const { @@ -190,56 +207,21 @@ bool PathMappingList::ReverseRemapPath(const FileSpec &file, FileSpec &fixed) co for (const auto &it : m_pairs) { if (!path_ref.consume_front(it.second.GetStringRef())) continue; - fixed.SetFile(it.first.GetStringRef(), FileSpec::Style::native); - fixed.AppendPathComponent(path_ref); + auto orig_file = it.first.GetStringRef(); + auto orig_style = FileSpec::GuessPathStyle(orig_file).getValueOr( + llvm::sys::path::Style::native); + fixed.SetFile(orig_file, orig_style); + AppendPathComponents(fixed, path_ref, orig_style); return true; } return false; } -bool PathMappingList::FindFile(const FileSpec &orig_spec, - FileSpec &new_spec) const { - if (m_pairs.empty()) - return false; - - std::string orig_path = orig_spec.GetPath(); - - if (orig_path.empty()) - return false; - - bool orig_is_relative = orig_spec.IsRelative(); +llvm::Optional PathMappingList::FindFile(const FileSpec &orig_spec) const { + if (auto remapped = RemapPath(orig_spec.GetPath(), /*only_if_exists=*/true)) + return remapped; - for (auto entry : m_pairs) { - llvm::StringRef orig_ref(orig_path); - llvm::StringRef prefix_ref = entry.first.GetStringRef(); - if (orig_ref.size() < prefix_ref.size()) - continue; - // We consider a relative prefix or one of just "." to - // mean "only apply to relative paths". - bool prefix_is_relative = false; - - if (prefix_ref == ".") { - prefix_is_relative = true; - // Remove the "." since it will have been removed from the - // FileSpec paths already. - prefix_ref = prefix_ref.drop_front(); - } else { - FileSpec prefix_spec(prefix_ref, FileSpec::Style::native); - prefix_is_relative = prefix_spec.IsRelative(); - } - if (prefix_is_relative != orig_is_relative) - continue; - - if (orig_ref.consume_front(prefix_ref)) { - new_spec.SetFile(entry.second.GetCString(), FileSpec::Style::native); - new_spec.AppendPathComponent(orig_ref); - if (FileSystem::Instance().Exists(new_spec)) - return true; - } - } - - new_spec.Clear(); - return false; + return {}; } bool PathMappingList::Replace(ConstString path, diff --git a/gnu/llvm/lldb/source/Target/Platform.cpp b/gnu/llvm/lldb/source/Target/Platform.cpp index e5afb4c7b8d..a77ecddfbab 100644 --- a/gnu/llvm/lldb/source/Target/Platform.cpp +++ b/gnu/llvm/lldb/source/Target/Platform.cpp @@ -85,7 +85,7 @@ PlatformProperties::PlatformProperties() { return; llvm::SmallString<64> user_home_dir; - if (!llvm::sys::path::home_directory(user_home_dir)) + if (!FileSystem::Instance().GetHomeDirectory(user_home_dir)) return; module_cache_dir = FileSpec(user_home_dir.c_str()); @@ -1020,7 +1020,6 @@ Status Platform::LaunchProcess(ProcessLaunchInfo &launch_info) { launch_info.GetFlags().Set(eLaunchFlagLaunchInTTY); if (launch_info.GetFlags().Test(eLaunchFlagLaunchInShell)) { - const bool is_localhost = true; const bool will_debug = launch_info.GetFlags().Test(eLaunchFlagDebug); const bool first_arg_is_full_shell_command = false; uint32_t num_resumes = GetResumeCountForLaunchInfo(launch_info); @@ -1034,8 +1033,7 @@ Status Platform::LaunchProcess(ProcessLaunchInfo &launch_info) { } if (!launch_info.ConvertArgumentsForLaunchingInShell( - error, is_localhost, will_debug, first_arg_is_full_shell_command, - num_resumes)) + error, will_debug, first_arg_is_full_shell_command, num_resumes)) return error; } else if (launch_info.GetFlags().Test(eLaunchFlagShellExpandArguments)) { error = ShellExpandArguments(launch_info); @@ -1318,7 +1316,23 @@ MmapArgList Platform::GetMmapArgumentList(const ArchSpec &arch, addr_t addr, } lldb_private::Status Platform::RunShellCommand( - const char *command, // Shouldn't be nullptr + llvm::StringRef command, + const FileSpec & + working_dir, // Pass empty FileSpec to use the current working directory + int *status_ptr, // Pass nullptr if you don't want the process exit status + int *signo_ptr, // Pass nullptr if you don't want the signal that caused the + // process to exit + std::string + *command_output, // Pass nullptr if you don't want the command output + const Timeout &timeout) { + return RunShellCommand(llvm::StringRef(), command, working_dir, status_ptr, + signo_ptr, command_output, timeout); +} + +lldb_private::Status Platform::RunShellCommand( + llvm::StringRef shell, // Pass empty if you want to use the default + // shell interpreter + llvm::StringRef command, // Shouldn't be empty const FileSpec & working_dir, // Pass empty FileSpec to use the current working directory int *status_ptr, // Pass nullptr if you don't want the process exit status @@ -1328,8 +1342,8 @@ lldb_private::Status Platform::RunShellCommand( *command_output, // Pass nullptr if you don't want the command output const Timeout &timeout) { if (IsHost()) - return Host::RunShellCommand(command, working_dir, status_ptr, signo_ptr, - command_output, timeout); + return Host::RunShellCommand(shell, command, working_dir, status_ptr, + signo_ptr, command_output, timeout); else return Status("unimplemented"); } @@ -1817,10 +1831,8 @@ lldb::ProcessSP Platform::DoConnectProcess(llvm::StringRef connect_url, if (!target || error.Fail()) return nullptr; - debugger.GetTargetList().SetSelectedTarget(target); - lldb::ProcessSP process_sp = - target->CreateProcess(debugger.GetListener(), plugin_name, nullptr); + target->CreateProcess(debugger.GetListener(), plugin_name, nullptr, true); if (!process_sp) return nullptr; diff --git a/gnu/llvm/lldb/source/Target/Process.cpp b/gnu/llvm/lldb/source/Target/Process.cpp index d777a271391..8ecc66b592e 100644 --- a/gnu/llvm/lldb/source/Target/Process.cpp +++ b/gnu/llvm/lldb/source/Target/Process.cpp @@ -10,6 +10,7 @@ #include #include +#include "llvm/ADT/ScopeExit.h" #include "llvm/Support/ScopedPrinter.h" #include "llvm/Support/Threading.h" @@ -68,6 +69,7 @@ #include "lldb/Utility/ProcessInfo.h" #include "lldb/Utility/SelectHelper.h" #include "lldb/Utility/State.h" +#include "lldb/Utility/Timer.h" using namespace lldb; using namespace lldb_private; @@ -83,16 +85,10 @@ using namespace std::chrono; #define DISABLE_MEM_CACHE_DEFAULT true #endif -class ProcessOptionValueProperties : public OptionValueProperties { +class ProcessOptionValueProperties + : public Cloneable { public: - ProcessOptionValueProperties(ConstString name) - : OptionValueProperties(name) {} - - // This constructor is used when creating ProcessOptionValueProperties when - // it is part of a new lldb_private::Process instance. It will copy all - // current global property values as needed - ProcessOptionValueProperties(ProcessProperties *global_properties) - : OptionValueProperties(*global_properties->GetValueProperties()) {} + ProcessOptionValueProperties(ConstString name) : Cloneable(name) {} const Property *GetPropertyAtIndex(const ExecutionContext *exe_ctx, bool will_modify, @@ -131,10 +127,12 @@ enum { #include "TargetPropertiesEnum.inc" }; -class ProcessExperimentalOptionValueProperties : public OptionValueProperties { +class ProcessExperimentalOptionValueProperties + : public Cloneable { public: ProcessExperimentalOptionValueProperties() - : OptionValueProperties( + : Cloneable( ConstString(Properties::GetExperimentalSettingsName())) {} }; @@ -157,8 +155,8 @@ ProcessProperties::ProcessProperties(lldb_private::Process *process) ConstString("thread"), ConstString("Settings specific to threads."), true, Thread::GetGlobalProperties()->GetValueProperties()); } else { - m_collection_sp = std::make_shared( - Process::GetGlobalProperties().get()); + m_collection_sp = + OptionValueProperties::CreateLocalCopy(*Process::GetGlobalProperties()); m_collection_sp->SetValueChangedCallback( ePropertyPythonOSPluginPath, [this] { m_process->LoadOperatingSystemPlugin(true); }); @@ -204,6 +202,16 @@ FileSpec ProcessProperties::GetPythonOSPluginPath() const { return m_collection_sp->GetPropertyAtIndexAsFileSpec(nullptr, idx); } +uint32_t ProcessProperties::GetVirtualAddressableBits() const { + const uint32_t idx = ePropertyVirtualAddressableBits; + return m_collection_sp->GetPropertyAtIndexAsUInt64( + nullptr, idx, g_process_properties[idx].default_uint_value); +} + +void ProcessProperties::SetVirtualAddressableBits(uint32_t bits) { + const uint32_t idx = ePropertyVirtualAddressableBits; + m_collection_sp->SetPropertyAtIndexAsUInt64(nullptr, idx, bits); +} void ProcessProperties::SetPythonOSPluginPath(const FileSpec &file) { const uint32_t idx = ePropertyPythonOSPluginPath; m_collection_sp->SetPropertyAtIndexAsFileSpec(nullptr, idx, file); @@ -242,6 +250,18 @@ void ProcessProperties::SetStopOnSharedLibraryEvents(bool stop) { m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, stop); } +bool ProcessProperties::GetDisableLangRuntimeUnwindPlans() const { + const uint32_t idx = ePropertyDisableLangRuntimeUnwindPlans; + return m_collection_sp->GetPropertyAtIndexAsBoolean( + nullptr, idx, g_process_properties[idx].default_uint_value != 0); +} + +void ProcessProperties::SetDisableLangRuntimeUnwindPlans(bool disable) { + const uint32_t idx = ePropertyDisableLangRuntimeUnwindPlans; + m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, disable); + m_process->Flush(); +} + bool ProcessProperties::GetDetachKeepsStopped() const { const uint32_t idx = ePropertyDetachKeepsStopped; return m_collection_sp->GetPropertyAtIndexAsBoolean( @@ -278,6 +298,19 @@ std::chrono::seconds ProcessProperties::GetUtilityExpressionTimeout() const { return std::chrono::seconds(value); } +std::chrono::seconds ProcessProperties::GetInterruptTimeout() const { + const uint32_t idx = ePropertyInterruptTimeout; + uint64_t value = m_collection_sp->GetPropertyAtIndexAsUInt64( + nullptr, idx, g_process_properties[idx].default_uint_value); + return std::chrono::seconds(value); +} + +bool ProcessProperties::GetSteppingRunsAllThreads() const { + const uint32_t idx = ePropertySteppingRunsAllThreads; + return m_collection_sp->GetPropertyAtIndexAsBoolean( + nullptr, idx, g_process_properties[idx].default_uint_value != 0); +} + bool ProcessProperties::GetOSPluginReportsAllThreads() const { const bool fail_value = true; const Property *exp_property = @@ -301,179 +334,11 @@ void ProcessProperties::SetOSPluginReportsAllThreads(bool does_report) { nullptr, ePropertyOSPluginReportsAllThreads, does_report); } -Status ProcessLaunchCommandOptions::SetOptionValue( - uint32_t option_idx, llvm::StringRef option_arg, - ExecutionContext *execution_context) { - Status error; - const int short_option = m_getopt_table[option_idx].val; - - switch (short_option) { - case 's': // Stop at program entry point - launch_info.GetFlags().Set(eLaunchFlagStopAtEntry); - break; - - case 'i': // STDIN for read only - { - FileAction action; - if (action.Open(STDIN_FILENO, FileSpec(option_arg), true, false)) - launch_info.AppendFileAction(action); - break; - } - - case 'o': // Open STDOUT for write only - { - FileAction action; - if (action.Open(STDOUT_FILENO, FileSpec(option_arg), false, true)) - launch_info.AppendFileAction(action); - break; - } - - case 'e': // STDERR for write only - { - FileAction action; - if (action.Open(STDERR_FILENO, FileSpec(option_arg), false, true)) - launch_info.AppendFileAction(action); - break; - } - - case 'p': // Process plug-in name - launch_info.SetProcessPluginName(option_arg); - break; - - case 'n': // Disable STDIO - { - FileAction action; - const FileSpec dev_null(FileSystem::DEV_NULL); - if (action.Open(STDIN_FILENO, dev_null, true, false)) - launch_info.AppendFileAction(action); - if (action.Open(STDOUT_FILENO, dev_null, false, true)) - launch_info.AppendFileAction(action); - if (action.Open(STDERR_FILENO, dev_null, false, true)) - launch_info.AppendFileAction(action); - break; - } - - case 'w': - launch_info.SetWorkingDirectory(FileSpec(option_arg)); - break; - - case 't': // Open process in new terminal window - launch_info.GetFlags().Set(eLaunchFlagLaunchInTTY); - break; - - case 'a': { - TargetSP target_sp = - execution_context ? execution_context->GetTargetSP() : TargetSP(); - PlatformSP platform_sp = - target_sp ? target_sp->GetPlatform() : PlatformSP(); - launch_info.GetArchitecture() = - Platform::GetAugmentedArchSpec(platform_sp.get(), option_arg); - } break; - - case 'A': // Disable ASLR. - { - bool success; - const bool disable_aslr_arg = - OptionArgParser::ToBoolean(option_arg, true, &success); - if (success) - disable_aslr = disable_aslr_arg ? eLazyBoolYes : eLazyBoolNo; - else - error.SetErrorStringWithFormat( - "Invalid boolean value for disable-aslr option: '%s'", - option_arg.empty() ? "" : option_arg.str().c_str()); - break; - } - - case 'X': // shell expand args. - { - bool success; - const bool expand_args = - OptionArgParser::ToBoolean(option_arg, true, &success); - if (success) - launch_info.SetShellExpandArguments(expand_args); - else - error.SetErrorStringWithFormat( - "Invalid boolean value for shell-expand-args option: '%s'", - option_arg.empty() ? "" : option_arg.str().c_str()); - break; - } - - case 'c': - if (!option_arg.empty()) - launch_info.SetShell(FileSpec(option_arg)); - else - launch_info.SetShell(HostInfo::GetDefaultShell()); - break; - - case 'v': - launch_info.GetEnvironment().insert(option_arg); - break; - - default: - error.SetErrorStringWithFormat("unrecognized short option character '%c'", - short_option); - break; - } - return error; -} - -static constexpr OptionDefinition g_process_launch_options[] = { - {LLDB_OPT_SET_ALL, false, "stop-at-entry", 's', OptionParser::eNoArgument, - nullptr, {}, 0, eArgTypeNone, - "Stop at the entry point of the program when launching a process."}, - {LLDB_OPT_SET_ALL, false, "disable-aslr", 'A', - OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeBoolean, - "Set whether to disable address space layout randomization when launching " - "a process."}, - {LLDB_OPT_SET_ALL, false, "plugin", 'p', OptionParser::eRequiredArgument, - nullptr, {}, 0, eArgTypePlugin, - "Name of the process plugin you want to use."}, - {LLDB_OPT_SET_ALL, false, "working-dir", 'w', - OptionParser::eRequiredArgument, nullptr, {}, 0, - eArgTypeDirectoryName, - "Set the current working directory to when running the inferior."}, - {LLDB_OPT_SET_ALL, false, "arch", 'a', OptionParser::eRequiredArgument, - nullptr, {}, 0, eArgTypeArchitecture, - "Set the architecture for the process to launch when ambiguous."}, - {LLDB_OPT_SET_ALL, false, "environment", 'v', - OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeNone, - "Specify an environment variable name/value string (--environment " - "NAME=VALUE). Can be specified multiple times for subsequent environment " - "entries."}, - {LLDB_OPT_SET_1 | LLDB_OPT_SET_2 | LLDB_OPT_SET_3, false, "shell", 'c', - OptionParser::eOptionalArgument, nullptr, {}, 0, eArgTypeFilename, - "Run the process in a shell (not supported on all platforms)."}, - - {LLDB_OPT_SET_1, false, "stdin", 'i', OptionParser::eRequiredArgument, - nullptr, {}, 0, eArgTypeFilename, - "Redirect stdin for the process to ."}, - {LLDB_OPT_SET_1, false, "stdout", 'o', OptionParser::eRequiredArgument, - nullptr, {}, 0, eArgTypeFilename, - "Redirect stdout for the process to ."}, - {LLDB_OPT_SET_1, false, "stderr", 'e', OptionParser::eRequiredArgument, - nullptr, {}, 0, eArgTypeFilename, - "Redirect stderr for the process to ."}, - - {LLDB_OPT_SET_2, false, "tty", 't', OptionParser::eNoArgument, nullptr, - {}, 0, eArgTypeNone, - "Start the process in a terminal (not supported on all platforms)."}, - - {LLDB_OPT_SET_3, false, "no-stdio", 'n', OptionParser::eNoArgument, nullptr, - {}, 0, eArgTypeNone, - "Do not set up for terminal I/O to go to running process."}, - {LLDB_OPT_SET_4, false, "shell-expand-args", 'X', - OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeBoolean, - "Set whether to shell expand arguments to the process when launching."}, -}; - -llvm::ArrayRef ProcessLaunchCommandOptions::GetDefinitions() { - return llvm::makeArrayRef(g_process_launch_options); -} - ProcessSP Process::FindPlugin(lldb::TargetSP target_sp, llvm::StringRef plugin_name, ListenerSP listener_sp, - const FileSpec *crash_file_path) { + const FileSpec *crash_file_path, + bool can_connect) { static uint32_t g_process_unique_id = 0; ProcessSP process_sp; @@ -483,7 +348,8 @@ ProcessSP Process::FindPlugin(lldb::TargetSP target_sp, create_callback = PluginManager::GetProcessCreateCallbackForPluginName(const_plugin_name); if (create_callback) { - process_sp = create_callback(target_sp, listener_sp, crash_file_path); + process_sp = create_callback(target_sp, listener_sp, crash_file_path, + can_connect); if (process_sp) { if (process_sp->CanDebug(target_sp, true)) { process_sp->m_process_unique_id = ++g_process_unique_id; @@ -496,7 +362,8 @@ ProcessSP Process::FindPlugin(lldb::TargetSP target_sp, (create_callback = PluginManager::GetProcessCreateCallbackAtIndex(idx)) != nullptr; ++idx) { - process_sp = create_callback(target_sp, listener_sp, crash_file_path); + process_sp = create_callback(target_sp, listener_sp, crash_file_path, + can_connect); if (process_sp) { if (process_sp->CanDebug(target_sp, false)) { process_sp->m_process_unique_id = ++g_process_unique_id; @@ -523,7 +390,7 @@ Process::Process(lldb::TargetSP target_sp, ListenerSP listener_sp) Process::Process(lldb::TargetSP target_sp, ListenerSP listener_sp, const UnixSignalsSP &unix_signals_sp) - : ProcessProperties(this), UserID(LLDB_INVALID_PROCESS_ID), + : ProcessProperties(this), Broadcaster((target_sp->GetDebugger().GetBroadcasterManager()), Process::GetStaticBroadcasterClass().AsCString()), m_target_wp(target_sp), m_public_state(eStateUnloaded), @@ -547,7 +414,7 @@ Process::Process(lldb::TargetSP target_sp, ListenerSP listener_sp, m_profile_data_comm_mutex(), m_profile_data(), m_iohandler_sync(0), m_memory_cache(*this), m_allocated_memory_cache(*this), m_should_detach(false), m_next_event_action_up(), m_public_run_lock(), - m_private_run_lock(), m_finalizing(false), m_finalize_called(false), + m_private_run_lock(), m_finalizing(false), m_clear_thread_plans_on_stop(false), m_force_next_event_delivery(false), m_last_broadcast_state(eStateInvalid), m_destroy_in_process(false), m_can_interpret_function_calls(false), m_warnings_issued(), @@ -623,27 +490,12 @@ const ProcessPropertiesSP &Process::GetGlobalProperties() { } void Process::Finalize() { - m_finalizing = true; - - // Destroy this process if needed - switch (GetPrivateState()) { - case eStateConnected: - case eStateAttaching: - case eStateLaunching: - case eStateStopped: - case eStateRunning: - case eStateStepping: - case eStateCrashed: - case eStateSuspended: - Destroy(false); - break; + if (m_finalizing.exchange(true)) + return; - case eStateInvalid: - case eStateUnloaded: - case eStateDetached: - case eStateExited: - break; - } + // Destroy the process. This will call the virtual function DoDestroy under + // the hood, giving our derived class a chance to do the ncessary tear down. + DestroyImpl(false); // Clear our broadcaster before we proceed with destroying Broadcaster::Clear(); @@ -698,7 +550,6 @@ void Process::Finalize() { m_private_run_lock.TrySetRunning(); // This will do nothing if already locked m_private_run_lock.SetStopped(); m_structured_data_plugin_map.clear(); - m_finalize_called = true; } void Process::RegisterNotificationCallbacks(const Notifications &callbacks) { @@ -926,13 +777,30 @@ bool Process::HandleProcessStateChangedEvent(const EventSP &event_sp, ThreadSP curr_thread(thread_list.GetSelectedThread()); ThreadSP thread; StopReason curr_thread_stop_reason = eStopReasonInvalid; - if (curr_thread) { + bool prefer_curr_thread = false; + if (curr_thread && curr_thread->IsValid()) { curr_thread_stop_reason = curr_thread->GetStopReason(); + switch (curr_thread_stop_reason) { + case eStopReasonNone: + case eStopReasonInvalid: + // Don't prefer the current thread if it didn't stop for a reason. + break; + case eStopReasonSignal: { + // We need to do the same computation we do for other threads + // below in case the current thread happens to be the one that + // stopped for the no-stop signal. + uint64_t signo = curr_thread->GetStopInfo()->GetValue(); + if (process_sp->GetUnixSignals()->GetShouldStop(signo)) + prefer_curr_thread = true; + } break; + default: + prefer_curr_thread = true; + break; + } curr_thread_stop_info_sp = curr_thread->GetStopInfo(); } - if (!curr_thread || !curr_thread->IsValid() || - curr_thread_stop_reason == eStopReasonInvalid || - curr_thread_stop_reason == eStopReasonNone) { + + if (!prefer_curr_thread) { // Prefer a thread that has just completed its plan over another // thread as current thread. ThreadSP plan_thread; @@ -964,8 +832,12 @@ bool Process::HandleProcessStateChangedEvent(const EventSP &event_sp, case eStopReasonWatchpoint: case eStopReasonException: case eStopReasonExec: + case eStopReasonFork: + case eStopReasonVFork: + case eStopReasonVForkDone: case eStopReasonThreadExiting: case eStopReasonInstrumentation: + case eStopReasonProcessorTrace: if (!other_thread) other_thread = thread; break; @@ -1239,6 +1111,12 @@ bool Process::SetProcessExitStatus( return false; } +bool Process::UpdateThreadList(ThreadList &old_thread_list, + ThreadList &new_thread_list) { + m_thread_plans.ClearThreadCache(); + return DoUpdateThreadList(old_thread_list, new_thread_list); +} + void Process::UpdateThreadListIfNeeded() { const uint32_t stop_id = GetStopID(); if (m_thread_list.GetSize(false) == 0 || @@ -1465,8 +1343,8 @@ Status Process::ResumeSynchronous(Stream *stream) { Status error = PrivateResume(); if (error.Success()) { - StateType state = - WaitForProcessToStop(llvm::None, nullptr, true, listener_sp, stream); + StateType state = WaitForProcessToStop(llvm::None, nullptr, true, + listener_sp, stream); const bool must_be_alive = false; // eStateExited is ok, so this must be false if (!StateIsStoppedState(state, must_be_alive)) @@ -1507,11 +1385,11 @@ bool Process::StateChangedIsHijackedForSynchronousResume() { StateType Process::GetPrivateState() { return m_private_state.GetValue(); } void Process::SetPrivateState(StateType new_state) { - if (m_finalize_called) + if (m_finalizing) return; - Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_STATE | - LIBLLDB_LOG_PROCESS)); + Log *log(lldb_private::GetLogIfAnyCategoriesSet( + LIBLLDB_LOG_STATE | LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_UNWIND)); bool state_changed = false; LLDB_LOGF(log, "Process::SetPrivateState (%s)", StateAsCString(new_state)); @@ -1557,11 +1435,7 @@ void Process::SetPrivateState(StateType new_state) { StateAsCString(new_state), m_mod_id.GetStopID()); } - // Use our target to get a shared pointer to ourselves... - if (m_finalize_called && !PrivateStateThreadIsValid()) - BroadcastEvent(event_sp); - else - m_private_state_broadcaster.BroadcastEvent(event_sp); + m_private_state_broadcaster.BroadcastEvent(event_sp); } else { LLDB_LOGF(log, "Process::SetPrivateState (%s) state didn't change. Ignoring...", @@ -2180,6 +2054,8 @@ size_t Process::ReadCStringFromMemory(addr_t addr, char *dst, size_t Process::ReadMemoryFromInferior(addr_t addr, void *buf, size_t size, Status &error) { + LLDB_SCOPED_TIMER(); + if (buf == nullptr || size == 0) return 0; @@ -2291,6 +2167,9 @@ size_t Process::WriteMemory(addr_t addr, const void *buf, size_t size, if (error.Fail()) return; + if (bp->GetType() != BreakpointSite::eSoftware) + return; + addr_t intersect_addr; size_t intersect_size; size_t opcode_offset; @@ -2603,6 +2482,11 @@ Status Process::Launch(ProcessLaunchInfo &launch_info) { if (error.Fail()) return error; + // Listen and queue events that are broadcasted during the process launch. + ListenerSP listener_sp(Listener::MakeListener("LaunchEventHijack")); + HijackProcessEvents(listener_sp); + auto on_exit = llvm::make_scope_exit([this]() { RestoreProcessEvents(); }); + if (PrivateStateThreadIsValid()) PausePrivateStateThread(); @@ -3011,8 +2895,10 @@ void Process::CompleteAttach() { ProcessInstanceInfo process_info; GetProcessInfo(process_info); const ArchSpec &process_arch = process_info.GetArchitecture(); + const ArchSpec &target_arch = GetTarget().GetArchitecture(); if (process_arch.IsValid() && - !GetTarget().GetArchitecture().IsExactMatch(process_arch)) { + target_arch.IsCompatibleMatch(process_arch) && + !target_arch.IsExactMatch(process_arch)) { GetTarget().SetArchitecture(process_arch); LLDB_LOGF(log, "Process::%s switching architecture to %s based on info " @@ -3068,13 +2954,8 @@ void Process::CompleteAttach() { } } // Figure out which one is the executable, and set that in our target: - const ModuleList &target_modules = GetTarget().GetImages(); - std::lock_guard guard(target_modules.GetMutex()); - size_t num_modules = target_modules.GetSize(); ModuleSP new_executable_module_sp; - - for (size_t i = 0; i < num_modules; i++) { - ModuleSP module_sp(target_modules.GetModuleAtIndexUnlocked(i)); + for (ModuleSP module_sp : GetTarget().GetImages().Modules()) { if (module_sp && module_sp->IsExecutable()) { if (GetTarget().GetExecutableModulePointer() != module_sp.get()) new_executable_module_sp = module_sp; @@ -3154,7 +3035,7 @@ Status Process::PrivateResume() { if (m_thread_list.WillResume()) { // Last thing, do the PreResumeActions. if (!RunPreResumeActions()) { - error.SetErrorStringWithFormat( + error.SetErrorString( "Process::PrivateResume PreResumeActions failed, not resuming."); } else { m_mod_id.BumpResumeID(); @@ -3210,9 +3091,10 @@ Status Process::Halt(bool clear_thread_plans, bool use_run_lock) { return Status(); } - // Wait for 10 second for the process to stop. - StateType state = WaitForProcessToStop( - seconds(10), &event_sp, true, halt_listener_sp, nullptr, use_run_lock); + // Wait for the process halt timeout seconds for the process to stop. + StateType state = + WaitForProcessToStop(GetInterruptTimeout(), &event_sp, true, + halt_listener_sp, nullptr, use_run_lock); RestoreProcessEvents(); if (state == eStateInvalid || !event_sp) { @@ -3243,8 +3125,8 @@ Status Process::StopForDestroyOrDetach(lldb::EventSP &exit_event_sp) { SendAsyncInterrupt(); // Consume the interrupt event. - StateType state = - WaitForProcessToStop(seconds(10), &exit_event_sp, true, listener_sp); + StateType state = WaitForProcessToStop(GetInterruptTimeout(), + &exit_event_sp, true, listener_sp); RestoreProcessEvents(); @@ -3333,9 +3215,12 @@ Status Process::Detach(bool keep_stopped) { Status Process::Destroy(bool force_kill) { // If we've already called Process::Finalize then there's nothing useful to // be done here. Finalize has actually called Destroy already. - if (m_finalize_called) + if (m_finalizing) return {}; + return DestroyImpl(force_kill); +} +Status Process::DestroyImpl(bool force_kill) { // Tell ourselves we are in the process of destroying the process, so that we // don't do any unnecessary work that might hinder the destruction. Remember // to set this back to false when we are done. That way if the attempt @@ -3360,7 +3245,7 @@ Status Process::Destroy(bool force_kill) { error = StopForDestroyOrDetach(exit_event_sp); } - if (m_public_state.GetValue() != eStateRunning) { + if (m_public_state.GetValue() == eStateStopped) { // Ditch all thread plans, and remove all our breakpoints: in case we // have to restart the target to kill it, we don't want it hitting a // breakpoint... Only do this if we've stopped, however, since if we @@ -3531,14 +3416,14 @@ bool Process::ShouldBroadcastEvent(Event *event_ptr) { should_resume = !m_thread_list.ShouldStop(event_ptr); if (was_restarted || should_resume || m_resume_requested) { - Vote stop_vote = m_thread_list.ShouldReportStop(event_ptr); + Vote report_stop_vote = m_thread_list.ShouldReportStop(event_ptr); LLDB_LOGF(log, "Process::ShouldBroadcastEvent: should_resume: %i state: " - "%s was_restarted: %i stop_vote: %d.", + "%s was_restarted: %i report_stop_vote: %d.", should_resume, StateAsCString(state), was_restarted, - stop_vote); + report_stop_vote); - switch (stop_vote) { + switch (report_stop_vote) { case eVoteYes: return_value = true; break; @@ -3976,9 +3861,7 @@ thread_result_t Process::RunPrivateStateThread(bool is_secondary_thread) { // Process Event Data -Process::ProcessEventData::ProcessEventData() - : EventData(), m_process_wp(), m_state(eStateInvalid), m_restarted(false), - m_update_state(0), m_interrupted(false) {} +Process::ProcessEventData::ProcessEventData() : EventData(), m_process_wp() {} Process::ProcessEventData::ProcessEventData(const ProcessSP &process_sp, StateType state) @@ -4169,8 +4052,7 @@ void Process::ProcessEventData::DoOnRemoval(Event *event_ptr) { // public (or SyncResume) broadcasters. StopHooks are just for // real public stops. They might also restart the target, // so watch for that. - process_sp->GetTarget().RunStopHooks(); - if (process_sp->GetPrivateState() == eStateRunning) + if (process_sp->GetTarget().RunStopHooks()) SetRestarted(true); } } @@ -5694,6 +5576,26 @@ void Process::Flush() { m_queue_list_stop_id = 0; } +lldb::addr_t Process::GetCodeAddressMask() { + if (m_code_address_mask == 0) { + if (uint32_t number_of_addressable_bits = GetVirtualAddressableBits()) { + lldb::addr_t address_mask = ~((1ULL << number_of_addressable_bits) - 1); + SetCodeAddressMask(address_mask); + } + } + return m_code_address_mask; +} + +lldb::addr_t Process::GetDataAddressMask() { + if (m_data_address_mask == 0) { + if (uint32_t number_of_addressable_bits = GetVirtualAddressableBits()) { + lldb::addr_t address_mask = ~((1ULL << number_of_addressable_bits) - 1); + SetDataAddressMask(address_mask); + } + } + return m_data_address_mask; +} + void Process::DidExec() { Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); LLDB_LOGF(log, "Process::%s()", __FUNCTION__); @@ -5749,6 +5651,8 @@ addr_t Process::ResolveIndirectFunction(const Address *address, Status &error) { symbol ? symbol->GetName().AsCString() : ""); function_addr = LLDB_INVALID_ADDRESS; } else { + if (ABISP abi_sp = GetABI()) + function_addr = abi_sp->FixCodeAddress(function_addr); m_resolved_indirect_addresses.insert( std::pair(addr, function_addr)); } @@ -5757,41 +5661,25 @@ addr_t Process::ResolveIndirectFunction(const Address *address, Status &error) { } void Process::ModulesDidLoad(ModuleList &module_list) { + // Inform the system runtime of the modified modules. SystemRuntime *sys_runtime = GetSystemRuntime(); - if (sys_runtime) { + if (sys_runtime) sys_runtime->ModulesDidLoad(module_list); - } GetJITLoaders().ModulesDidLoad(module_list); - // Give runtimes a chance to be created. + // Give the instrumentation runtimes a chance to be created before informing + // them of the modified modules. InstrumentationRuntime::ModulesDidLoad(module_list, this, m_instrumentation_runtimes); + for (auto &runtime : m_instrumentation_runtimes) + runtime.second->ModulesDidLoad(module_list); - // Tell runtimes about new modules. - for (auto pos = m_instrumentation_runtimes.begin(); - pos != m_instrumentation_runtimes.end(); ++pos) { - InstrumentationRuntimeSP runtime = pos->second; - runtime->ModulesDidLoad(module_list); - } - - // Let any language runtimes we have already created know about the modules - // that loaded. - - // Iterate over a copy of this language runtime list in case the language - // runtime ModulesDidLoad somehow causes the language runtime to be - // unloaded. - { - std::lock_guard guard(m_language_runtimes_mutex); - LanguageRuntimeCollection language_runtimes(m_language_runtimes); - for (const auto &pair : language_runtimes) { - // We must check language_runtime_sp to make sure it is not nullptr as we - // might cache the fact that we didn't have a language runtime for a - // language. - LanguageRuntimeSP language_runtime_sp = pair.second; - if (language_runtime_sp) - language_runtime_sp->ModulesDidLoad(module_list); - } + // Give the language runtimes a chance to be created before informing them of + // the modified modules. + for (const lldb::LanguageType lang_type : Language::GetSupportedLanguages()) { + if (LanguageRuntime *runtime = GetLanguageRuntime(lang_type)) + runtime->ModulesDidLoad(module_list); } // If we don't have an operating system plug-in, try to load one since @@ -5799,7 +5687,7 @@ void Process::ModulesDidLoad(ModuleList &module_list) { if (!m_os_up) LoadOperatingSystemPlugin(false); - // Give structured-data plugins a chance to see the modified modules. + // Inform the structured-data plugins of the modified modules. for (auto pair : m_structured_data_plugin_map) { if (pair.second) pair.second->ModulesDidLoad(*this, module_list); @@ -5858,12 +5746,12 @@ void Process::PrintWarningUnsupportedLanguage(const SymbolContext &sc) { LanguageType language = sc.GetLanguage(); if (language == eLanguageTypeUnknown) return; - auto type_system_or_err = sc.module_sp->GetTypeSystemForLanguage(language); - if (auto err = type_system_or_err.takeError()) { - llvm::consumeError(std::move(err)); + LanguageSet plugins = + PluginManager::GetAllTypeSystemSupportedLanguagesForTypes(); + if (!plugins[language]) { PrintWarning(Process::Warnings::eWarningsUnsupportedLanguage, sc.module_sp.get(), - "This version of LLDB has no plugin for the %s language. " + "This version of LLDB has no plugin for the language \"%s\". " "Inspection of frame variables will be limited.\n", Language::GetNameForLanguageType(language)); } @@ -5943,10 +5831,8 @@ Process::AdvanceAddressToNextBranchInstruction(Address default_stop_addr, const char *plugin_name = nullptr; const char *flavor = nullptr; - const bool prefer_file_cache = true; disassembler_sp = Disassembler::DisassembleRange( - target.GetArchitecture(), plugin_name, flavor, GetTarget(), range_bounds, - prefer_file_cache); + target.GetArchitecture(), plugin_name, flavor, GetTarget(), range_bounds); if (disassembler_sp) insn_list = &disassembler_sp->GetInstructionList(); @@ -5960,10 +5846,8 @@ Process::AdvanceAddressToNextBranchInstruction(Address default_stop_addr, return retval; } - uint32_t branch_index = - insn_list->GetIndexOfNextBranchInstruction(insn_offset, target, - false /* ignore_calls*/, - nullptr); + uint32_t branch_index = insn_list->GetIndexOfNextBranchInstruction( + insn_offset, false /* ignore_calls*/, nullptr); if (branch_index == UINT32_MAX) { return retval; } @@ -6138,6 +6022,13 @@ UtilityFunction *Process::GetLoadImageUtilityFunction( return m_dlopen_utility_func_up.get(); } +llvm::Expected Process::TraceSupported() { + if (!IsLiveDebugSession()) + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "Can't trace a non-live process."); + return llvm::make_error(); +} + bool Process::CallVoidArgVoidPtrReturn(const Address *address, addr_t &returned_func, bool trap_exceptions) { @@ -6192,3 +6083,57 @@ bool Process::CallVoidArgVoidPtrReturn(const Address *address, return false; } + +llvm::Expected Process::GetMemoryTagManager() { + Architecture *arch = GetTarget().GetArchitecturePlugin(); + const MemoryTagManager *tag_manager = + arch ? arch->GetMemoryTagManager() : nullptr; + if (!arch || !tag_manager) { + return llvm::createStringError( + llvm::inconvertibleErrorCode(), + "This architecture does not support memory tagging", + GetPluginName().GetCString()); + } + + if (!SupportsMemoryTagging()) { + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "Process does not support memory tagging"); + } + + return tag_manager; +} + +llvm::Expected> +Process::ReadMemoryTags(lldb::addr_t addr, size_t len) { + llvm::Expected tag_manager_or_err = + GetMemoryTagManager(); + if (!tag_manager_or_err) + return tag_manager_or_err.takeError(); + + const MemoryTagManager *tag_manager = *tag_manager_or_err; + llvm::Expected> tag_data = + DoReadMemoryTags(addr, len, tag_manager->GetAllocationTagType()); + if (!tag_data) + return tag_data.takeError(); + + return tag_manager->UnpackTagsData(*tag_data, + len / tag_manager->GetGranuleSize()); +} + +Status Process::WriteMemoryTags(lldb::addr_t addr, size_t len, + const std::vector &tags) { + llvm::Expected tag_manager_or_err = + GetMemoryTagManager(); + if (!tag_manager_or_err) + return Status(tag_manager_or_err.takeError()); + + const MemoryTagManager *tag_manager = *tag_manager_or_err; + llvm::Expected> packed_tags = + tag_manager->PackTags(tags); + if (!packed_tags) { + return Status(packed_tags.takeError()); + } + + return DoWriteMemoryTags(addr, len, tag_manager->GetAllocationTagType(), + *packed_tags); +} diff --git a/gnu/llvm/lldb/source/Target/ProcessTrace.cpp b/gnu/llvm/lldb/source/Target/ProcessTrace.cpp new file mode 100644 index 00000000000..c878a2ac4eb --- /dev/null +++ b/gnu/llvm/lldb/source/Target/ProcessTrace.cpp @@ -0,0 +1,132 @@ +//===-- ProcessTrace.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 "lldb/Target/ProcessTrace.h" + +#include + +#include "lldb/Core/Module.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Core/Section.h" +#include "lldb/Target/SectionLoadList.h" +#include "lldb/Target/Target.h" + +using namespace lldb; +using namespace lldb_private; + +ConstString ProcessTrace::GetPluginNameStatic() { + static ConstString g_name("trace"); + return g_name; +} + +const char *ProcessTrace::GetPluginDescriptionStatic() { + return "Trace process plug-in."; +} + +void ProcessTrace::Terminate() { + PluginManager::UnregisterPlugin(ProcessTrace::CreateInstance); +} + +ProcessSP ProcessTrace::CreateInstance(TargetSP target_sp, + ListenerSP listener_sp, + const FileSpec *crash_file, + bool can_connect) { + if (can_connect) + return nullptr; + return std::make_shared(target_sp, listener_sp); +} + +bool ProcessTrace::CanDebug(TargetSP target_sp, bool plugin_specified_by_name) { + return plugin_specified_by_name; +} + +ProcessTrace::ProcessTrace(TargetSP target_sp, ListenerSP listener_sp) + : PostMortemProcess(target_sp, listener_sp) {} + +ProcessTrace::~ProcessTrace() { + Clear(); + // We need to call finalize on the process before destroying ourselves to + // make sure all of the broadcaster cleanup goes as planned. If we destruct + // this class, then Process::~Process() might have problems trying to fully + // destroy the broadcaster. + Finalize(); +} + +ConstString ProcessTrace::GetPluginName() { return GetPluginNameStatic(); } + +uint32_t ProcessTrace::GetPluginVersion() { return 1; } + +void ProcessTrace::DidAttach(ArchSpec &process_arch) { + ListenerSP listener_sp( + Listener::MakeListener("lldb.process_trace.did_attach_listener")); + HijackProcessEvents(listener_sp); + + SetCanJIT(false); + StartPrivateStateThread(); + SetPrivateState(eStateStopped); + + EventSP event_sp; + WaitForProcessToStop(llvm::None, &event_sp, true, listener_sp); + + RestoreProcessEvents(); + + Process::DidAttach(process_arch); +} + +bool ProcessTrace::DoUpdateThreadList(ThreadList &old_thread_list, + ThreadList &new_thread_list) { + return false; +} + +void ProcessTrace::RefreshStateAfterStop() {} + +Status ProcessTrace::DoDestroy() { return Status(); } + +size_t ProcessTrace::ReadMemory(addr_t addr, void *buf, size_t size, + Status &error) { + // Don't allow the caching that lldb_private::Process::ReadMemory does since + // we have it all cached in the trace files. + return DoReadMemory(addr, buf, size, error); +} + +void ProcessTrace::Clear() { m_thread_list.Clear(); } + +void ProcessTrace::Initialize() { + static llvm::once_flag g_once_flag; + + llvm::call_once(g_once_flag, []() { + PluginManager::RegisterPlugin(GetPluginNameStatic(), + GetPluginDescriptionStatic(), CreateInstance); + }); +} + +ArchSpec ProcessTrace::GetArchitecture() { + return GetTarget().GetArchitecture(); +} + +bool ProcessTrace::GetProcessInfo(ProcessInstanceInfo &info) { + info.Clear(); + info.SetProcessID(GetID()); + info.SetArchitecture(GetArchitecture()); + ModuleSP module_sp = GetTarget().GetExecutableModule(); + if (module_sp) { + const bool add_exe_file_as_first_arg = false; + info.SetExecutableFile(GetTarget().GetExecutableModule()->GetFileSpec(), + add_exe_file_as_first_arg); + } + return true; +} + +size_t ProcessTrace::DoReadMemory(addr_t addr, void *buf, size_t size, + Status &error) { + Address resolved_address; + GetTarget().GetSectionLoadList().ResolveLoadAddress(addr, resolved_address); + + return GetTarget().ReadMemoryFromFileCache(resolved_address, buf, size, + error); +} diff --git a/gnu/llvm/lldb/source/Target/QueueItem.cpp b/gnu/llvm/lldb/source/Target/QueueItem.cpp index 740b2a6771a..7070812a10b 100644 --- a/gnu/llvm/lldb/source/Target/QueueItem.cpp +++ b/gnu/llvm/lldb/source/Target/QueueItem.cpp @@ -27,7 +27,7 @@ QueueItem::QueueItem(QueueSP queue_sp, ProcessSP process_sp, m_process_wp = process_sp; } -QueueItem::~QueueItem() {} +QueueItem::~QueueItem() = default; QueueItemKind QueueItem::GetKind() { FetchEntireItem(); diff --git a/gnu/llvm/lldb/source/Target/RegisterContext.cpp b/gnu/llvm/lldb/source/Target/RegisterContext.cpp index cdc7653cea6..bd50a9486ef 100644 --- a/gnu/llvm/lldb/source/Target/RegisterContext.cpp +++ b/gnu/llvm/lldb/source/Target/RegisterContext.cpp @@ -58,8 +58,8 @@ RegisterContext::GetRegisterInfoByName(llvm::StringRef reg_name, for (uint32_t reg = start_idx; reg < num_registers; ++reg) { const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg); - if (reg_name.equals_lower(reg_info->name) || - reg_name.equals_lower(reg_info->alt_name)) + if (reg_name.equals_insensitive(reg_info->name) || + reg_name.equals_insensitive(reg_info->alt_name)) return reg_info; } return nullptr; @@ -150,6 +150,20 @@ bool RegisterContext::SetPC(uint64_t pc) { return success; } +bool RegisterContext::GetPCForSymbolication(Address &address) { + addr_t pc = GetPC(LLDB_INVALID_ADDRESS); + if (pc == LLDB_INVALID_ADDRESS) + return false; + TargetSP target_sp = m_thread.CalculateTarget(); + if (!target_sp.get()) + return false; + + if (!BehavesLikeZerothFrame() && pc != 0) + pc--; + address.SetLoadAddress(pc, target_sp.get()); + return true; +} + bool RegisterContext::SetPC(Address addr) { TargetSP target_sp = m_thread.CalculateTarget(); Target *target = target_sp.get(); diff --git a/gnu/llvm/lldb/source/Target/RegisterContextUnwind.cpp b/gnu/llvm/lldb/source/Target/RegisterContextUnwind.cpp index f33f4180be2..1ce21e6306e 100644 --- a/gnu/llvm/lldb/source/Target/RegisterContextUnwind.cpp +++ b/gnu/llvm/lldb/source/Target/RegisterContextUnwind.cpp @@ -24,6 +24,7 @@ #include "lldb/Target/ABI.h" #include "lldb/Target/DynamicLoader.h" #include "lldb/Target/ExecutionContext.h" +#include "lldb/Target/LanguageRuntime.h" #include "lldb/Target/Platform.h" #include "lldb/Target/Process.h" #include "lldb/Target/SectionLoadList.h" @@ -57,10 +58,11 @@ RegisterContextUnwind::RegisterContextUnwind(Thread &thread, m_fast_unwind_plan_sp(), m_full_unwind_plan_sp(), m_fallback_unwind_plan_sp(), m_all_registers_available(false), m_frame_type(-1), m_cfa(LLDB_INVALID_ADDRESS), - m_afa(LLDB_INVALID_ADDRESS), m_start_pc(), - m_current_pc(), m_current_offset(0), m_current_offset_backed_up_one(0), - m_sym_ctx(sym_ctx), m_sym_ctx_valid(false), m_frame_number(frame_number), - m_registers(), m_parent_unwind(unwind_lldb) { + m_afa(LLDB_INVALID_ADDRESS), m_start_pc(), m_current_pc(), + m_current_offset(0), m_current_offset_backed_up_one(0), + m_behaves_like_zeroth_frame(false), m_sym_ctx(sym_ctx), + m_sym_ctx_valid(false), m_frame_number(frame_number), m_registers(), + m_parent_unwind(unwind_lldb) { m_sym_ctx.Clear(false); m_sym_ctx_valid = false; @@ -139,6 +141,12 @@ void RegisterContextUnwind::InitializeZerothFrame() { if (abi) current_pc = abi->FixCodeAddress(current_pc); + UnwindPlanSP lang_runtime_plan_sp = LanguageRuntime::GetRuntimeUnwindPlan( + m_thread, this, m_behaves_like_zeroth_frame); + if (lang_runtime_plan_sp.get()) { + UnwindLogMsg("This is an async frame"); + } + // Initialize m_current_pc, an Address object, based on current_pc, an // addr_t. m_current_pc.SetLoadAddress(current_pc, &process->GetTarget()); @@ -202,6 +210,38 @@ void RegisterContextUnwind::InitializeZerothFrame() { UnwindPlan::RowSP active_row; lldb::RegisterKind row_register_kind = eRegisterKindGeneric; + + // If we have LanguageRuntime UnwindPlan for this unwind, use those + // rules to find the caller frame instead of the function's normal + // UnwindPlans. The full unwind plan for this frame will be + // the LanguageRuntime-provided unwind plan, and there will not be a + // fast unwind plan. + if (lang_runtime_plan_sp.get()) { + active_row = + lang_runtime_plan_sp->GetRowForFunctionOffset(m_current_offset); + row_register_kind = lang_runtime_plan_sp->GetRegisterKind(); + if (!ReadFrameAddress(row_register_kind, active_row->GetCFAValue(), + m_cfa)) { + UnwindLogMsg("Cannot set cfa"); + } else { + m_full_unwind_plan_sp = lang_runtime_plan_sp; + if (log) { + StreamString active_row_strm; + active_row->Dump(active_row_strm, lang_runtime_plan_sp.get(), &m_thread, + m_start_pc.GetLoadAddress(exe_ctx.GetTargetPtr())); + UnwindLogMsg("async active row: %s", active_row_strm.GetData()); + } + UnwindLogMsg("m_cfa = 0x%" PRIx64 " m_afa = 0x%" PRIx64, m_cfa, m_afa); + UnwindLogMsg( + "initialized async frame current pc is 0x%" PRIx64 + " cfa is 0x%" PRIx64 " afa is 0x%" PRIx64, + (uint64_t)m_current_pc.GetLoadAddress(exe_ctx.GetTargetPtr()), + (uint64_t)m_cfa, (uint64_t)m_afa); + + return; + } + } + if (m_full_unwind_plan_sp && m_full_unwind_plan_sp->PlanValidAtAddress(m_current_pc)) { active_row = @@ -283,6 +323,22 @@ void RegisterContextUnwind::InitializeNonZerothFrame() { return; } + ExecutionContext exe_ctx(m_thread.shared_from_this()); + Process *process = exe_ctx.GetProcessPtr(); + + // Some languages may have a logical parent stack frame which is + // not a real stack frame, but the programmer would consider it to + // be the caller of the frame, e.g. Swift asynchronous frames. + // + // A LanguageRuntime may provide an UnwindPlan that is used in this + // stack trace base on the RegisterContext contents, intsead + // of the normal UnwindPlans we would use for the return-pc. + UnwindPlanSP lang_runtime_plan_sp = LanguageRuntime::GetRuntimeUnwindPlan( + m_thread, this, m_behaves_like_zeroth_frame); + if (lang_runtime_plan_sp.get()) { + UnwindLogMsg("This is an async frame"); + } + addr_t pc; if (!ReadGPRValue(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, pc)) { UnwindLogMsg("could not get pc value"); @@ -290,8 +346,6 @@ void RegisterContextUnwind::InitializeNonZerothFrame() { return; } - ExecutionContext exe_ctx(m_thread.shared_from_this()); - Process *process = exe_ctx.GetProcessPtr(); // Let ABIs fixup code addresses to make sure they are valid. In ARM ABIs // this will strip bit zero in case we read a PC from memory or from the LR. ABI *abi = process->GetABI().get(); @@ -468,6 +522,8 @@ void RegisterContextUnwind::InitializeNonZerothFrame() { // so do not decrement and recompute if the symbol we already found is a trap // handler. decr_pc_and_recompute_addr_range = false; + } else if (m_behaves_like_zeroth_frame) { + decr_pc_and_recompute_addr_range = false; } else { // Decrement to find the function containing the call. decr_pc_and_recompute_addr_range = true; @@ -522,12 +578,43 @@ void RegisterContextUnwind::InitializeNonZerothFrame() { } } - // We've set m_frame_type and m_sym_ctx before this call. - m_fast_unwind_plan_sp = GetFastUnwindPlanForFrame(); - UnwindPlan::RowSP active_row; RegisterKind row_register_kind = eRegisterKindGeneric; + // If we have LanguageRuntime UnwindPlan for this unwind, use those + // rules to find the caller frame instead of the function's normal + // UnwindPlans. The full unwind plan for this frame will be + // the LanguageRuntime-provided unwind plan, and there will not be a + // fast unwind plan. + if (lang_runtime_plan_sp.get()) { + active_row = + lang_runtime_plan_sp->GetRowForFunctionOffset(m_current_offset); + row_register_kind = lang_runtime_plan_sp->GetRegisterKind(); + if (!ReadFrameAddress(row_register_kind, active_row->GetCFAValue(), + m_cfa)) { + UnwindLogMsg("Cannot set cfa"); + } else { + m_full_unwind_plan_sp = lang_runtime_plan_sp; + if (log) { + StreamString active_row_strm; + active_row->Dump(active_row_strm, lang_runtime_plan_sp.get(), &m_thread, + m_start_pc.GetLoadAddress(exe_ctx.GetTargetPtr())); + UnwindLogMsg("async active row: %s", active_row_strm.GetData()); + } + UnwindLogMsg("m_cfa = 0x%" PRIx64 " m_afa = 0x%" PRIx64, m_cfa, m_afa); + UnwindLogMsg( + "initialized async frame current pc is 0x%" PRIx64 + " cfa is 0x%" PRIx64 " afa is 0x%" PRIx64, + (uint64_t)m_current_pc.GetLoadAddress(exe_ctx.GetTargetPtr()), + (uint64_t)m_cfa, (uint64_t)m_afa); + + return; + } + } + + // We've set m_frame_type and m_sym_ctx before this call. + m_fast_unwind_plan_sp = GetFastUnwindPlanForFrame(); + // Try to get by with just the fast UnwindPlan if possible - the full // UnwindPlan may be expensive to get (e.g. if we have to parse the entire // eh_frame section of an ObjectFile for the first time.) @@ -542,6 +629,8 @@ void RegisterContextUnwind::InitializeNonZerothFrame() { StreamString active_row_strm; active_row->Dump(active_row_strm, m_fast_unwind_plan_sp.get(), &m_thread, m_start_pc.GetLoadAddress(exe_ctx.GetTargetPtr())); + UnwindLogMsg("Using fast unwind plan '%s'", + m_fast_unwind_plan_sp->GetSourceName().AsCString()); UnwindLogMsg("active row: %s", active_row_strm.GetData()); } } else { @@ -556,6 +645,8 @@ void RegisterContextUnwind::InitializeNonZerothFrame() { active_row->Dump(active_row_strm, m_full_unwind_plan_sp.get(), &m_thread, m_start_pc.GetLoadAddress(exe_ctx.GetTargetPtr())); + UnwindLogMsg("Using full unwind plan '%s'", + m_full_unwind_plan_sp->GetSourceName().AsCString()); UnwindLogMsg("active row: %s", active_row_strm.GetData()); } } @@ -625,6 +716,14 @@ bool RegisterContextUnwind::CheckIfLoopingStack() { bool RegisterContextUnwind::IsFrameZero() const { return m_frame_number == 0; } +bool RegisterContextUnwind::BehavesLikeZerothFrame() const { + if (m_frame_number == 0) + return true; + if (m_behaves_like_zeroth_frame) + return true; + return false; +} + // Find a fast unwind plan for this frame, if possible. // // On entry to this method, @@ -662,13 +761,6 @@ UnwindPlanSP RegisterContextUnwind::GetFastUnwindPlanForFrame() { *m_thread.CalculateTarget(), m_thread); if (unwind_plan_sp) { if (unwind_plan_sp->PlanValidAtAddress(m_current_pc)) { - Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND)); - if (log && log->GetVerbose()) { - if (m_fast_unwind_plan_sp) - UnwindLogMsgVerbose("frame, and has a fast UnwindPlan"); - else - UnwindLogMsgVerbose("frame"); - } m_frame_type = eNormalFrame; return unwind_plan_sp; } else { @@ -702,10 +794,9 @@ UnwindPlanSP RegisterContextUnwind::GetFullUnwindPlanForFrame() { "unable to get architectural default UnwindPlan from ABI plugin"); } - bool behaves_like_zeroth_frame = false; if (IsFrameZero() || GetNextFrame()->m_frame_type == eTrapHandlerFrame || GetNextFrame()->m_frame_type == eDebuggerFrame) { - behaves_like_zeroth_frame = true; + m_behaves_like_zeroth_frame = true; // If this frame behaves like a 0th frame (currently executing or // interrupted asynchronously), all registers can be retrieved. m_all_registers_available = true; @@ -721,7 +812,7 @@ UnwindPlanSP RegisterContextUnwind::GetFullUnwindPlanForFrame() { if ((!m_sym_ctx_valid || (m_sym_ctx.function == nullptr && m_sym_ctx.symbol == nullptr)) && - behaves_like_zeroth_frame && m_current_pc.IsValid()) { + m_behaves_like_zeroth_frame && m_current_pc.IsValid()) { uint32_t permissions; addr_t current_pc_addr = m_current_pc.GetLoadAddress(exe_ctx.GetTargetPtr()); @@ -849,7 +940,7 @@ UnwindPlanSP RegisterContextUnwind::GetFullUnwindPlanForFrame() { // Typically the NonCallSite UnwindPlan is the unwind created by inspecting // the assembly language instructions - if (behaves_like_zeroth_frame && process) { + if (m_behaves_like_zeroth_frame && process) { unwind_plan_sp = func_unwinders_sp->GetUnwindPlanAtNonCallSite( process->GetTarget(), m_thread); if (unwind_plan_sp && unwind_plan_sp->PlanValidAtAddress(m_current_pc)) { @@ -1147,6 +1238,7 @@ enum UnwindLLDB::RegisterSearchResult RegisterContextUnwind::SavedLocationForRegister( uint32_t lldb_regnum, lldb_private::UnwindLLDB::RegisterLocation ®loc) { RegisterNumber regnum(m_thread, eRegisterKindLLDB, lldb_regnum); + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_UNWIND)); // Have we already found this register location? if (!m_registers.empty()) { @@ -1179,8 +1271,17 @@ RegisterContextUnwind::SavedLocationForRegister( (int)unwindplan_registerkind); return UnwindLLDB::RegisterSearchResult::eRegisterNotFound; } + // The architecture default unwind plan marks unknown registers as + // Undefined so that we don't forward them up the stack when a + // jitted stack frame may have overwritten them. But when the + // arch default unwind plan is used as the Fast Unwind Plan, we + // need to recognize this & switch over to the Full Unwind Plan + // to see what unwind rule that (more knoweldgeable, probably) + // UnwindPlan has. If the full UnwindPlan says the register + // location is Undefined, then it really is. if (active_row->GetRegisterInfo(regnum.GetAsKind(unwindplan_registerkind), - unwindplan_regloc)) { + unwindplan_regloc) && + !unwindplan_regloc.IsUndefined()) { UnwindLogMsg( "supplying caller's saved %s (%d)'s location using FastUnwindPlan", regnum.GetName(), regnum.GetAsKind(eRegisterKindLLDB)); @@ -1191,8 +1292,11 @@ RegisterContextUnwind::SavedLocationForRegister( if (!have_unwindplan_regloc) { // m_full_unwind_plan_sp being NULL means that we haven't tried to find a // full UnwindPlan yet - if (!m_full_unwind_plan_sp) + bool got_new_full_unwindplan = false; + if (!m_full_unwind_plan_sp) { m_full_unwind_plan_sp = GetFullUnwindPlanForFrame(); + got_new_full_unwindplan = true; + } if (m_full_unwind_plan_sp) { RegisterNumber pc_regnum(m_thread, eRegisterKindGeneric, @@ -1202,6 +1306,16 @@ RegisterContextUnwind::SavedLocationForRegister( m_full_unwind_plan_sp->GetRowForFunctionOffset(m_current_offset); unwindplan_registerkind = m_full_unwind_plan_sp->GetRegisterKind(); + if (got_new_full_unwindplan && active_row.get() && log) { + StreamString active_row_strm; + ExecutionContext exe_ctx(m_thread.shared_from_this()); + active_row->Dump(active_row_strm, m_full_unwind_plan_sp.get(), + &m_thread, + m_start_pc.GetLoadAddress(exe_ctx.GetTargetPtr())); + UnwindLogMsg("Using full unwind plan '%s'", + m_full_unwind_plan_sp->GetSourceName().AsCString()); + UnwindLogMsg("active row: %s", active_row_strm.GetData()); + } RegisterNumber return_address_reg; // If we're fetching the saved pc and this UnwindPlan defines a @@ -1521,7 +1635,7 @@ RegisterContextUnwind::SavedLocationForRegister( DWARFExpression dwarfexpr(opcode_ctx, dwarfdata, nullptr); dwarfexpr.SetRegisterKind(unwindplan_registerkind); Value cfa_val = Scalar(m_cfa); - cfa_val.SetValueType(Value::eValueTypeLoadAddress); + cfa_val.SetValueType(Value::ValueType::LoadAddress); Value result; Status error; if (dwarfexpr.Evaluate(&exe_ctx, this, 0, &cfa_val, nullptr, result, @@ -1616,6 +1730,10 @@ bool RegisterContextUnwind::TryFallbackUnwindPlan() { RegisterValue reg_value; if (ReadRegisterValueFromRegisterLocation(regloc, reg_info, reg_value)) { old_caller_pc_value = reg_value.GetAsUInt64(); + if (ProcessSP process_sp = m_thread.GetProcess()) { + if (ABISP abi = process_sp->GetABI()) + old_caller_pc_value = abi->FixCodeAddress(old_caller_pc_value); + } } } } @@ -1671,6 +1789,10 @@ bool RegisterContextUnwind::TryFallbackUnwindPlan() { if (ReadRegisterValueFromRegisterLocation(regloc, reg_info, reg_value)) { new_caller_pc_value = reg_value.GetAsUInt64(); + if (ProcessSP process_sp = m_thread.GetProcess()) { + if (ABISP abi = process_sp->GetABI()) + new_caller_pc_value = abi->FixCodeAddress(new_caller_pc_value); + } } } } @@ -1824,6 +1946,8 @@ bool RegisterContextUnwind::ReadFrameAddress( reg_info, cfa_reg_contents, reg_info->byte_size, reg_value); if (error.Success()) { address = reg_value.GetAsUInt64(); + if (ABISP abi_sp = m_thread.GetProcess()->GetABI()) + address = abi_sp->FixCodeAddress(address); UnwindLogMsg( "CFA value via dereferencing reg %s (%d): reg has val 0x%" PRIx64 ", CFA value is 0x%" PRIx64, @@ -1878,6 +2002,8 @@ bool RegisterContextUnwind::ReadFrameAddress( if (dwarfexpr.Evaluate(&exe_ctx, this, 0, nullptr, nullptr, result, &error)) { address = result.GetScalar().ULongLong(); + if (ABISP abi_sp = m_thread.GetProcess()->GetABI()) + address = abi_sp->FixCodeAddress(address); UnwindLogMsg("CFA value set by DWARF expression is 0x%" PRIx64, address); @@ -2007,6 +2133,12 @@ bool RegisterContextUnwind::ReadGPRValue(lldb::RegisterKind register_kind, } if (ReadRegisterValueFromRegisterLocation(regloc, reg_info, reg_value)) { value = reg_value.GetAsUInt64(); + if (pc_register) { + if (ProcessSP process_sp = m_thread.GetProcess()) { + if (ABISP abi = process_sp->GetABI()) + value = abi->FixCodeAddress(value); + } + } return true; } return false; @@ -2048,7 +2180,19 @@ bool RegisterContextUnwind::ReadRegister(const RegisterInfo *reg_info, lldb_regnum, regloc, m_frame_number - 1, is_pc_regnum)) return false; - return ReadRegisterValueFromRegisterLocation(regloc, reg_info, value); + bool result = ReadRegisterValueFromRegisterLocation(regloc, reg_info, value); + if (result) { + if (is_pc_regnum && value.GetType() == RegisterValue::eTypeUInt64) { + addr_t reg_value = value.GetAsUInt64(LLDB_INVALID_ADDRESS); + if (reg_value != LLDB_INVALID_ADDRESS) { + if(ProcessSP process_sp = m_thread.GetProcess()) { + if (ABISP abi = process_sp->GetABI()) + value = abi->FixCodeAddress(reg_value); + } + } + } + } + return result; } bool RegisterContextUnwind::WriteRegister(const RegisterInfo *reg_info, diff --git a/gnu/llvm/lldb/source/Target/RegisterNumber.cpp b/gnu/llvm/lldb/source/Target/RegisterNumber.cpp index 0ea9f212c69..e5610bf5885 100644 --- a/gnu/llvm/lldb/source/Target/RegisterNumber.cpp +++ b/gnu/llvm/lldb/source/Target/RegisterNumber.cpp @@ -26,9 +26,7 @@ RegisterNumber::RegisterNumber(lldb_private::Thread &thread, } } -RegisterNumber::RegisterNumber() - : m_reg_ctx_sp(), m_regnum(LLDB_INVALID_REGNUM), - m_kind(lldb::kNumRegisterKinds), m_kind_regnum_map(), m_name(nullptr) {} +RegisterNumber::RegisterNumber() : m_reg_ctx_sp(), m_kind_regnum_map() {} void RegisterNumber::init(lldb_private::Thread &thread, lldb::RegisterKind kind, uint32_t num) { diff --git a/gnu/llvm/lldb/source/Target/RemoteAwarePlatform.cpp b/gnu/llvm/lldb/source/Target/RemoteAwarePlatform.cpp index f53158b06b8..b0c43ffa839 100644 --- a/gnu/llvm/lldb/source/Target/RemoteAwarePlatform.cpp +++ b/gnu/llvm/lldb/source/Target/RemoteAwarePlatform.cpp @@ -171,15 +171,24 @@ Status RemoteAwarePlatform::ResolveExecutable( } Status RemoteAwarePlatform::RunShellCommand( - const char *command, const FileSpec &working_dir, int *status_ptr, + llvm::StringRef command, const FileSpec &working_dir, int *status_ptr, int *signo_ptr, std::string *command_output, const Timeout &timeout) { + return RunShellCommand(llvm::StringRef(), command, working_dir, status_ptr, + signo_ptr, command_output, timeout); +} + +Status RemoteAwarePlatform::RunShellCommand( + llvm::StringRef shell, llvm::StringRef command, const FileSpec &working_dir, + int *status_ptr, int *signo_ptr, std::string *command_output, + const Timeout &timeout) { if (IsHost()) - return Host::RunShellCommand(command, working_dir, status_ptr, signo_ptr, - command_output, timeout); + return Host::RunShellCommand(shell, command, working_dir, status_ptr, + signo_ptr, command_output, timeout); if (m_remote_platform_sp) - return m_remote_platform_sp->RunShellCommand( - command, working_dir, status_ptr, signo_ptr, command_output, timeout); + return m_remote_platform_sp->RunShellCommand(shell, command, working_dir, + status_ptr, signo_ptr, + command_output, timeout); return Status("unable to run a remote command without a platform"); } @@ -428,3 +437,10 @@ Status RemoteAwarePlatform::KillProcess(const lldb::pid_t pid) { return m_remote_platform_sp->KillProcess(pid); return Status("the platform is not currently connected"); } + +size_t RemoteAwarePlatform::ConnectToWaitingProcesses(Debugger &debugger, + Status &error) { + if (m_remote_platform_sp) + return m_remote_platform_sp->ConnectToWaitingProcesses(debugger, error); + return Platform::ConnectToWaitingProcesses(debugger, error); +} diff --git a/gnu/llvm/lldb/source/Target/StackFrame.cpp b/gnu/llvm/lldb/source/Target/StackFrame.cpp index 3d6cc5dc90b..cba51d266c5 100644 --- a/gnu/llvm/lldb/source/Target/StackFrame.cpp +++ b/gnu/llvm/lldb/source/Target/StackFrame.cpp @@ -213,6 +213,35 @@ const Address &StackFrame::GetFrameCodeAddress() { return m_frame_code_addr; } +// This can't be rewritten into a call to +// RegisterContext::GetPCForSymbolication because this +// StackFrame may have been constructed with a special pc, +// e.g. tail-call artificial frames. +Address StackFrame::GetFrameCodeAddressForSymbolication() { + Address lookup_addr(GetFrameCodeAddress()); + if (!lookup_addr.IsValid()) + return lookup_addr; + if (m_behaves_like_zeroth_frame) + return lookup_addr; + + addr_t offset = lookup_addr.GetOffset(); + if (offset > 0) { + lookup_addr.SetOffset(offset - 1); + } else { + // lookup_addr is the start of a section. We need do the math on the + // actual load address and re-compute the section. We're working with + // a 'noreturn' function at the end of a section. + TargetSP target_sp = CalculateTarget(); + if (target_sp) { + addr_t addr_minus_one = lookup_addr.GetOpcodeLoadAddress( + target_sp.get(), AddressClass::eCode) - + 1; + lookup_addr.SetOpcodeLoadAddress(addr_minus_one, target_sp.get()); + } + } + return lookup_addr; +} + bool StackFrame::ChangePC(addr_t pc) { std::lock_guard guard(m_mutex); // We can't change the pc value of a history stack frame - it is immutable. @@ -229,21 +258,16 @@ bool StackFrame::ChangePC(addr_t pc) { const char *StackFrame::Disassemble() { std::lock_guard guard(m_mutex); - if (m_disassembly.Empty()) { - ExecutionContext exe_ctx(shared_from_this()); - Target *target = exe_ctx.GetTargetPtr(); - if (target) { - const char *plugin_name = nullptr; - const char *flavor = nullptr; - Disassembler::Disassemble(target->GetDebugger(), - target->GetArchitecture(), plugin_name, flavor, - exe_ctx, 0, false, 0, 0, m_disassembly); - } - if (m_disassembly.Empty()) - return nullptr; + if (!m_disassembly.Empty()) + return m_disassembly.GetData(); + + ExecutionContext exe_ctx(shared_from_this()); + if (Target *target = exe_ctx.GetTargetPtr()) { + Disassembler::Disassemble(target->GetDebugger(), target->GetArchitecture(), + *this, m_disassembly); } - return m_disassembly.GetData(); + return m_disassembly.Empty() ? nullptr : m_disassembly.GetData(); } Block *StackFrame::GetFrameBlock() { @@ -293,30 +317,7 @@ StackFrame::GetSymbolContext(SymbolContextItem resolve_scope) { // If this is not frame zero, then we need to subtract 1 from the PC value // when doing address lookups since the PC will be on the instruction // following the function call instruction... - - Address lookup_addr(GetFrameCodeAddress()); - if (!m_behaves_like_zeroth_frame && lookup_addr.IsValid()) { - addr_t offset = lookup_addr.GetOffset(); - if (offset > 0) { - lookup_addr.SetOffset(offset - 1); - - } else { - // lookup_addr is the start of a section. We need do the math on the - // actual load address and re-compute the section. We're working with - // a 'noreturn' function at the end of a section. - ThreadSP thread_sp(GetThread()); - if (thread_sp) { - TargetSP target_sp(thread_sp->CalculateTarget()); - if (target_sp) { - addr_t addr_minus_one = - lookup_addr.GetLoadAddress(target_sp.get()) - 1; - lookup_addr.SetLoadAddress(addr_minus_one, target_sp.get()); - } else { - lookup_addr.SetOffset(offset - 1); - } - } - } - } + Address lookup_addr(GetFrameCodeAddressForSymbolication()); if (m_sc.module_sp) { // We have something in our stack frame symbol context, lets check if we @@ -1165,31 +1166,6 @@ StackFrame::GetValueObjectForFrameVariable(const VariableSP &variable_sp, return valobj_sp; } -ValueObjectSP StackFrame::TrackGlobalVariable(const VariableSP &variable_sp, - DynamicValueType use_dynamic) { - std::lock_guard guard(m_mutex); - if (IsHistorical()) - return ValueObjectSP(); - - // Check to make sure we aren't already tracking this variable? - ValueObjectSP valobj_sp( - GetValueObjectForFrameVariable(variable_sp, use_dynamic)); - if (!valobj_sp) { - // We aren't already tracking this global - VariableList *var_list = GetVariableList(true); - // If this frame has no variables, create a new list - if (var_list == nullptr) - m_variable_list_sp = std::make_shared(); - - // Add the global/static variable to this frame - m_variable_list_sp->AddVariable(variable_sp); - - // Now make a value object for it so we can track its changes - valobj_sp = GetValueObjectForFrameVariable(variable_sp, use_dynamic); - } - return valobj_sp; -} - bool StackFrame::IsInlined() { if (m_sc.block == nullptr) GetSymbolContext(eSymbolContextBlock); @@ -1318,11 +1294,11 @@ lldb::ValueObjectSP StackFrame::GuessValueForAddress(lldb::addr_t addr) { const char *plugin_name = nullptr; const char *flavor = nullptr; - const bool prefer_file_cache = false; + const bool force_live_memory = true; DisassemblerSP disassembler_sp = Disassembler::DisassembleRange(target_arch, plugin_name, flavor, - *target_sp, pc_range, prefer_file_cache); + *target_sp, pc_range, force_live_memory); if (!disassembler_sp || !disassembler_sp->GetInstructionList().GetSize()) { return ValueObjectSP(); @@ -1408,7 +1384,7 @@ ValueObjectSP GetValueForOffset(StackFrame &frame, ValueObjectSP &parent, } int64_t child_offset = child_sp->GetByteOffset(); - int64_t child_size = child_sp->GetByteSize(); + int64_t child_size = child_sp->GetByteSize().getValueOr(0); if (offset >= child_offset && offset < (child_offset + child_size)) { return GetValueForOffset(frame, child_sp, offset - child_offset); @@ -1441,8 +1417,8 @@ ValueObjectSP GetValueForDereferincingOffset(StackFrame &frame, } if (offset >= 0 && uint64_t(offset) >= pointee->GetByteSize()) { - int64_t index = offset / pointee->GetByteSize(); - offset = offset % pointee->GetByteSize(); + int64_t index = offset / pointee->GetByteSize().getValueOr(1); + offset = offset % pointee->GetByteSize().getValueOr(1); const bool can_create = true; pointee = base->GetSyntheticArrayMember(index, can_create); } @@ -1698,10 +1674,10 @@ lldb::ValueObjectSP StackFrame::GuessValueForRegisterAndOffset(ConstString reg, const char *plugin_name = nullptr; const char *flavor = nullptr; - const bool prefer_file_cache = false; + const bool force_live_memory = true; DisassemblerSP disassembler_sp = Disassembler::DisassembleRange(target_arch, plugin_name, flavor, - *target_sp, pc_range, prefer_file_cache); + *target_sp, pc_range, force_live_memory); if (!disassembler_sp || !disassembler_sp->GetInstructionList().GetSize()) { return ValueObjectSP(); @@ -1956,8 +1932,11 @@ bool StackFrame::GetStatus(Stream &strm, bool show_frame_info, bool show_source, RecognizedStackFrameSP StackFrame::GetRecognizedFrame() { if (!m_recognized_frame_sp) { - m_recognized_frame_sp = - StackFrameRecognizerManager::RecognizeFrame(CalculateStackFrame()); + m_recognized_frame_sp = GetThread() + ->GetProcess() + ->GetTarget() + .GetFrameRecognizerManager() + .RecognizeFrame(CalculateStackFrame()); } return m_recognized_frame_sp; } diff --git a/gnu/llvm/lldb/source/Target/StackFrameList.cpp b/gnu/llvm/lldb/source/Target/StackFrameList.cpp index e4f5d302836..061500152a4 100644 --- a/gnu/llvm/lldb/source/Target/StackFrameList.cpp +++ b/gnu/llvm/lldb/source/Target/StackFrameList.cpp @@ -131,6 +131,9 @@ void StackFrameList::ResetCurrentInlinedDepth() { case eStopReasonWatchpoint: case eStopReasonException: case eStopReasonExec: + case eStopReasonFork: + case eStopReasonVFork: + case eStopReasonVForkDone: case eStopReasonSignal: // In all these cases we want to stop in the deepest frame. m_current_inlined_pc = curr_pc; @@ -522,27 +525,10 @@ void StackFrameList::GetFramesUpTo(uint32_t end_idx) { SymbolContext unwind_sc = unwind_frame_sp->GetSymbolContext( eSymbolContextBlock | eSymbolContextFunction); Block *unwind_block = unwind_sc.block; + TargetSP target_sp = m_thread.CalculateTarget(); if (unwind_block) { - Address curr_frame_address(unwind_frame_sp->GetFrameCodeAddress()); - TargetSP target_sp = m_thread.CalculateTarget(); - // Be sure to adjust the frame address to match the address that was - // used to lookup the symbol context above. If we are in the first - // concrete frame, then we lookup using the current address, else we - // decrement the address by one to get the correct location. - if (idx > 0) { - if (curr_frame_address.GetOffset() == 0) { - // If curr_frame_address points to the first address in a section - // then after adjustment it will point to an other section. In that - // case resolve the address again to the correct section plus - // offset form. - addr_t load_addr = curr_frame_address.GetOpcodeLoadAddress( - target_sp.get(), AddressClass::eCode); - curr_frame_address.SetOpcodeLoadAddress( - load_addr - 1, target_sp.get(), AddressClass::eCode); - } else { - curr_frame_address.Slide(-1); - } - } + Address curr_frame_address( + unwind_frame_sp->GetFrameCodeAddressForSymbolication()); SymbolContext next_frame_sc; Address next_frame_address; @@ -840,105 +826,6 @@ void StackFrameList::Clear() { m_concrete_frames_fetched = 0; } -void StackFrameList::Merge(std::unique_ptr &curr_up, - lldb::StackFrameListSP &prev_sp) { - std::unique_lock current_lock, previous_lock; - if (curr_up) - current_lock = std::unique_lock(curr_up->m_mutex); - if (prev_sp) - previous_lock = std::unique_lock(prev_sp->m_mutex); - -#if defined(DEBUG_STACK_FRAMES) - StreamFile s(stdout, false); - s.PutCString("\n\nStackFrameList::Merge():\nPrev:\n"); - if (prev_sp) - prev_sp->Dump(&s); - else - s.PutCString("NULL"); - s.PutCString("\nCurr:\n"); - if (curr_up) - curr_up->Dump(&s); - else - s.PutCString("NULL"); - s.EOL(); -#endif - - if (!curr_up || curr_up->GetNumFrames(false) == 0) { -#if defined(DEBUG_STACK_FRAMES) - s.PutCString("No current frames, leave previous frames alone...\n"); -#endif - curr_up.release(); - return; - } - - if (!prev_sp || prev_sp->GetNumFrames(false) == 0) { -#if defined(DEBUG_STACK_FRAMES) - s.PutCString("No previous frames, so use current frames...\n"); -#endif - // We either don't have any previous frames, or since we have more than one - // current frames it means we have all the frames and can safely replace - // our previous frames. - prev_sp.reset(curr_up.release()); - return; - } - - const uint32_t num_curr_frames = curr_up->GetNumFrames(false); - - if (num_curr_frames > 1) { -#if defined(DEBUG_STACK_FRAMES) - s.PutCString( - "We have more than one current frame, so use current frames...\n"); -#endif - // We have more than one current frames it means we have all the frames and - // can safely replace our previous frames. - prev_sp.reset(curr_up.release()); - -#if defined(DEBUG_STACK_FRAMES) - s.PutCString("\nMerged:\n"); - prev_sp->Dump(&s); -#endif - return; - } - - StackFrameSP prev_frame_zero_sp(prev_sp->GetFrameAtIndex(0)); - StackFrameSP curr_frame_zero_sp(curr_up->GetFrameAtIndex(0)); - StackID curr_stack_id(curr_frame_zero_sp->GetStackID()); - StackID prev_stack_id(prev_frame_zero_sp->GetStackID()); - -#if defined(DEBUG_STACK_FRAMES) - const uint32_t num_prev_frames = prev_sp->GetNumFrames(false); - s.Printf("\n%u previous frames with one current frame\n", num_prev_frames); -#endif - - // We have only a single current frame - // Our previous stack frames only had a single frame as well... - if (curr_stack_id == prev_stack_id) { -#if defined(DEBUG_STACK_FRAMES) - s.Printf("\nPrevious frame #0 is same as current frame #0, merge the " - "cached data\n"); -#endif - - curr_frame_zero_sp->UpdateCurrentFrameFromPreviousFrame( - *prev_frame_zero_sp); - // prev_frame_zero_sp->UpdatePreviousFrameFromCurrentFrame - // (*curr_frame_zero_sp); - // prev_sp->SetFrameAtIndex (0, prev_frame_zero_sp); - } else if (curr_stack_id < prev_stack_id) { -#if defined(DEBUG_STACK_FRAMES) - s.Printf("\nCurrent frame #0 has a stack ID that is less than the previous " - "frame #0, insert current frame zero in front of previous\n"); -#endif - prev_sp->m_frames.insert(prev_sp->m_frames.begin(), curr_frame_zero_sp); - } - - curr_up.release(); - -#if defined(DEBUG_STACK_FRAMES) - s.PutCString("\nMerged:\n"); - prev_sp->Dump(&s); -#endif -} - lldb::StackFrameSP StackFrameList::GetStackFrameSPForStackFramePtr(StackFrame *stack_frame_ptr) { const_iterator pos; diff --git a/gnu/llvm/lldb/source/Target/StackFrameRecognizer.cpp b/gnu/llvm/lldb/source/Target/StackFrameRecognizer.cpp index 7dc6e9d1e49..73d22d5bb4e 100644 --- a/gnu/llvm/lldb/source/Target/StackFrameRecognizer.cpp +++ b/gnu/llvm/lldb/source/Target/StackFrameRecognizer.cpp @@ -6,12 +6,11 @@ // //===----------------------------------------------------------------------===// -#include +#include "lldb/Target/StackFrameRecognizer.h" #include "lldb/Core/Module.h" #include "lldb/Interpreter/ScriptInterpreter.h" #include "lldb/Symbol/Symbol.h" #include "lldb/Target/StackFrame.h" -#include "lldb/Target/StackFrameRecognizer.h" #include "lldb/Utility/RegularExpression.h" using namespace lldb; @@ -48,158 +47,108 @@ ScriptedStackFrameRecognizer::RecognizeFrame(lldb::StackFrameSP frame) { new ScriptedRecognizedStackFrame(args_synthesized)); } -class StackFrameRecognizerManagerImpl { -public: - void AddRecognizer(StackFrameRecognizerSP recognizer, ConstString module, - llvm::ArrayRef symbols, - bool first_instruction_only) { - m_recognizers.push_front({(uint32_t)m_recognizers.size(), false, recognizer, - false, module, RegularExpressionSP(), symbols, - RegularExpressionSP(), first_instruction_only}); - } - - void AddRecognizer(StackFrameRecognizerSP recognizer, - RegularExpressionSP module, RegularExpressionSP symbol, - bool first_instruction_only) { - m_recognizers.push_front( - {(uint32_t)m_recognizers.size(), false, recognizer, true, ConstString(), - module, std::vector(), symbol, first_instruction_only}); - } - - void ForEach(std::function< - void(uint32_t recognized_id, std::string recognizer_name, - std::string module, llvm::ArrayRef symbols, - bool regexp)> const &callback) { - for (auto entry : m_recognizers) { - if (entry.is_regexp) { - std::string module_name; - std::string symbol_name; - - if (entry.module_regexp) - module_name = entry.module_regexp->GetText().str(); - if (entry.symbol_regexp) - symbol_name = entry.symbol_regexp->GetText().str(); - - callback(entry.recognizer_id, entry.recognizer->GetName(), module_name, - llvm::makeArrayRef(ConstString(symbol_name)), true); - - } else { - callback(entry.recognizer_id, entry.recognizer->GetName(), - entry.module.GetCString(), entry.symbols, false); - } - } - } - - bool RemoveRecognizerWithID(uint32_t recognizer_id) { - if (recognizer_id >= m_recognizers.size()) return false; - if (m_recognizers[recognizer_id].deleted) return false; - m_recognizers[recognizer_id].deleted = true; - return true; - } +void StackFrameRecognizerManager::AddRecognizer( + StackFrameRecognizerSP recognizer, ConstString module, + llvm::ArrayRef symbols, bool first_instruction_only) { + m_recognizers.push_front({(uint32_t)m_recognizers.size(), recognizer, false, + module, RegularExpressionSP(), symbols, + RegularExpressionSP(), first_instruction_only}); +} - void RemoveAllRecognizers() { - m_recognizers.clear(); - } +void StackFrameRecognizerManager::AddRecognizer( + StackFrameRecognizerSP recognizer, RegularExpressionSP module, + RegularExpressionSP symbol, bool first_instruction_only) { + m_recognizers.push_front({(uint32_t)m_recognizers.size(), recognizer, true, + ConstString(), module, std::vector(), + symbol, first_instruction_only}); +} - StackFrameRecognizerSP GetRecognizerForFrame(StackFrameSP frame) { - const SymbolContext &symctx = frame->GetSymbolContext( - eSymbolContextModule | eSymbolContextFunction | eSymbolContextSymbol); - ConstString function_name = symctx.GetFunctionName(); - ModuleSP module_sp = symctx.module_sp; - if (!module_sp) return StackFrameRecognizerSP(); - ConstString module_name = module_sp->GetFileSpec().GetFilename(); - Symbol *symbol = symctx.symbol; - if (!symbol) return StackFrameRecognizerSP(); - Address start_addr = symbol->GetAddress(); - Address current_addr = frame->GetFrameCodeAddress(); - - for (auto entry : m_recognizers) { - if (entry.deleted) continue; - if (entry.module) - if (entry.module != module_name) continue; +void StackFrameRecognizerManager::ForEach( + const std::function, bool)> &callback) { + for (auto entry : m_recognizers) { + if (entry.is_regexp) { + std::string module_name; + std::string symbol_name; if (entry.module_regexp) - if (!entry.module_regexp->Execute(module_name.GetStringRef())) continue; - - if (!entry.symbols.empty()) - if (!llvm::is_contained(entry.symbols, function_name)) - continue; - + module_name = entry.module_regexp->GetText().str(); if (entry.symbol_regexp) - if (!entry.symbol_regexp->Execute(function_name.GetStringRef())) - continue; + symbol_name = entry.symbol_regexp->GetText().str(); - if (entry.first_instruction_only) - if (start_addr != current_addr) continue; + callback(entry.recognizer_id, entry.recognizer->GetName(), module_name, + llvm::makeArrayRef(ConstString(symbol_name)), true); - return entry.recognizer; + } else { + callback(entry.recognizer_id, entry.recognizer->GetName(), + entry.module.GetCString(), entry.symbols, false); } - return StackFrameRecognizerSP(); } - - RecognizedStackFrameSP RecognizeFrame(StackFrameSP frame) { - auto recognizer = GetRecognizerForFrame(frame); - if (!recognizer) return RecognizedStackFrameSP(); - return recognizer->RecognizeFrame(frame); - } - - private: - struct RegisteredEntry { - uint32_t recognizer_id; - bool deleted; - StackFrameRecognizerSP recognizer; - bool is_regexp; - ConstString module; - RegularExpressionSP module_regexp; - std::vector symbols; - RegularExpressionSP symbol_regexp; - bool first_instruction_only; - }; - - std::deque m_recognizers; -}; - -StackFrameRecognizerManagerImpl &GetStackFrameRecognizerManagerImpl() { - static StackFrameRecognizerManagerImpl instance = - StackFrameRecognizerManagerImpl(); - return instance; } -void StackFrameRecognizerManager::AddRecognizer( - StackFrameRecognizerSP recognizer, ConstString module, - llvm::ArrayRef symbols, bool first_instruction_only) { - GetStackFrameRecognizerManagerImpl().AddRecognizer( - recognizer, module, symbols, first_instruction_only); +bool StackFrameRecognizerManager::RemoveRecognizerWithID( + uint32_t recognizer_id) { + if (recognizer_id >= m_recognizers.size()) + return false; + auto found = + llvm::find_if(m_recognizers, [recognizer_id](const RegisteredEntry &e) { + return e.recognizer_id == recognizer_id; + }); + if (found == m_recognizers.end()) + return false; + m_recognizers.erase(found); + return true; } -void StackFrameRecognizerManager::AddRecognizer( - StackFrameRecognizerSP recognizer, RegularExpressionSP module, - RegularExpressionSP symbol, bool first_instruction_only) { - GetStackFrameRecognizerManagerImpl().AddRecognizer(recognizer, module, symbol, - first_instruction_only); +void StackFrameRecognizerManager::RemoveAllRecognizers() { + m_recognizers.clear(); } -void StackFrameRecognizerManager::ForEach( - std::function symbols, - bool regexp)> const &callback) { - GetStackFrameRecognizerManagerImpl().ForEach(callback); -} +StackFrameRecognizerSP +StackFrameRecognizerManager::GetRecognizerForFrame(StackFrameSP frame) { + const SymbolContext &symctx = frame->GetSymbolContext( + eSymbolContextModule | eSymbolContextFunction | eSymbolContextSymbol); + ConstString function_name = symctx.GetFunctionName(); + ModuleSP module_sp = symctx.module_sp; + if (!module_sp) + return StackFrameRecognizerSP(); + ConstString module_name = module_sp->GetFileSpec().GetFilename(); + Symbol *symbol = symctx.symbol; + if (!symbol) + return StackFrameRecognizerSP(); + Address start_addr = symbol->GetAddress(); + Address current_addr = frame->GetFrameCodeAddress(); -void StackFrameRecognizerManager::RemoveAllRecognizers() { - GetStackFrameRecognizerManagerImpl().RemoveAllRecognizers(); -} + for (auto entry : m_recognizers) { + if (entry.module) + if (entry.module != module_name) + continue; -bool StackFrameRecognizerManager::RemoveRecognizerWithID(uint32_t recognizer_id) { - return GetStackFrameRecognizerManagerImpl().RemoveRecognizerWithID(recognizer_id); -} + if (entry.module_regexp) + if (!entry.module_regexp->Execute(module_name.GetStringRef())) + continue; -RecognizedStackFrameSP StackFrameRecognizerManager::RecognizeFrame( - StackFrameSP frame) { - return GetStackFrameRecognizerManagerImpl().RecognizeFrame(frame); + if (!entry.symbols.empty()) + if (!llvm::is_contained(entry.symbols, function_name)) + continue; + + if (entry.symbol_regexp) + if (!entry.symbol_regexp->Execute(function_name.GetStringRef())) + continue; + + if (entry.first_instruction_only) + if (start_addr != current_addr) + continue; + + return entry.recognizer; + } + return StackFrameRecognizerSP(); } -StackFrameRecognizerSP StackFrameRecognizerManager::GetRecognizerForFrame( - lldb::StackFrameSP frame) { - return GetStackFrameRecognizerManagerImpl().GetRecognizerForFrame(frame); +RecognizedStackFrameSP +StackFrameRecognizerManager::RecognizeFrame(StackFrameSP frame) { + auto recognizer = GetRecognizerForFrame(frame); + if (!recognizer) + return RecognizedStackFrameSP(); + return recognizer->RecognizeFrame(frame); } diff --git a/gnu/llvm/lldb/source/Target/StopInfo.cpp b/gnu/llvm/lldb/source/Target/StopInfo.cpp index 7e830c6e2be..aeb97f1919e 100644 --- a/gnu/llvm/lldb/source/Target/StopInfo.cpp +++ b/gnu/llvm/lldb/source/Target/StopInfo.cpp @@ -125,7 +125,7 @@ public: BreakpointSiteSP bp_site_sp( process_sp->GetBreakpointSiteList().FindByID(m_value)); if (bp_site_sp) - return bp_site_sp->ValidForThisThread(&thread); + return bp_site_sp->ValidForThisThread(thread); } return false; } @@ -305,6 +305,20 @@ protected: // location said we should stop. But that's better than not running // all the callbacks. + // There's one other complication here. We may have run an async + // breakpoint callback that said we should stop. We only want to + // override that if another breakpoint action says we shouldn't + // stop. If nobody else has an opinion, then we should stop if the + // async callback says we should. An example of this is the async + // shared library load notification breakpoint and the setting + // stop-on-sharedlibrary-events. + // We'll keep the async value in async_should_stop, and track whether + // anyone said we should NOT stop in actually_said_continue. + bool async_should_stop = false; + if (m_should_stop_is_valid) + async_should_stop = m_should_stop; + bool actually_said_continue = false; + m_should_stop = false; // We don't select threads as we go through them testing breakpoint @@ -399,7 +413,7 @@ protected: // The breakpoint site may have many locations associated with it, // not all of them valid for this thread. Skip the ones that // aren't: - if (!bp_loc_sp->ValidForThisThread(thread_sp.get())) { + if (!bp_loc_sp->ValidForThisThread(*thread_sp)) { if (log) { LLDB_LOGF(log, "Breakpoint %s hit on thread 0x%llx but it was not " @@ -422,9 +436,10 @@ protected: bool precondition_result = bp_loc_sp->GetBreakpoint().EvaluatePrecondition(context); - if (!precondition_result) + if (!precondition_result) { + actually_said_continue = true; continue; - + } // Next run the condition for the breakpoint. If that says we // should stop, then we'll run the callback for the breakpoint. If // the callback says we shouldn't stop that will win. @@ -462,11 +477,21 @@ protected: // the condition fails. We've already bumped it by the time // we get here, so undo the bump: bp_loc_sp->UndoBumpHitCount(); + actually_said_continue = true; continue; } } } + // We've done all the checks whose failure means "we consider lldb + // not to have hit the breakpoint". Now we're going to check for + // conditions that might continue after hitting. Start with the + // ignore count: + if (!bp_loc_sp->IgnoreCountShouldStop()) { + actually_said_continue = true; + continue; + } + // Check the auto-continue bit on the location, do this before the // callback since it may change this, but that would be for the // NEXT hit. Note, you might think you could check auto-continue @@ -494,16 +519,22 @@ protected: // When we figure out how to nest breakpoint hits then this will // change. - Debugger &debugger = thread_sp->CalculateTarget()->GetDebugger(); - bool old_async = debugger.GetAsyncExecution(); - debugger.SetAsyncExecution(true); + // Don't run async callbacks in PerformAction. They have already + // been taken into account with async_should_stop. + if (!bp_loc_sp->IsCallbackSynchronous()) { + Debugger &debugger = thread_sp->CalculateTarget()->GetDebugger(); + bool old_async = debugger.GetAsyncExecution(); + debugger.SetAsyncExecution(true); - callback_says_stop = bp_loc_sp->InvokeCallback(&context); + callback_says_stop = bp_loc_sp->InvokeCallback(&context); - debugger.SetAsyncExecution(old_async); + debugger.SetAsyncExecution(old_async); - if (callback_says_stop && auto_continue_says_stop) - m_should_stop = true; + if (callback_says_stop && auto_continue_says_stop) + m_should_stop = true; + else + actually_said_continue = true; + } // If we are going to stop for this breakpoint, then remove the // breakpoint. @@ -517,9 +548,15 @@ protected: // here. if (HasTargetRunSinceMe()) { m_should_stop = false; + actually_said_continue = true; break; } } + // At this point if nobody actually told us to continue, we should + // give the async breakpoint callback a chance to weigh in: + if (!actually_said_continue && !m_should_stop) { + m_should_stop = async_should_stop; + } } // We've figured out what this stop wants to do, so mark it as valid so // we don't compute it again. @@ -1016,6 +1053,30 @@ public: } }; +// StopInfoProcessorTrace + +class StopInfoProcessorTrace : public StopInfo { +public: + StopInfoProcessorTrace(Thread &thread, const char *description) + : StopInfo(thread, LLDB_INVALID_UID) { + if (description) + SetDescription(description); + } + + ~StopInfoProcessorTrace() override = default; + + StopReason GetStopReason() const override { + return eStopReasonProcessorTrace; + } + + const char *GetDescription() override { + if (m_description.empty()) + return "processor trace event"; + else + return m_description.c_str(); + } +}; + // StopInfoThreadPlan class StopInfoThreadPlan : public StopInfo { @@ -1133,6 +1194,11 @@ StopInfoSP StopInfo::CreateStopReasonWithException(Thread &thread, return StopInfoSP(new StopInfoException(thread, description)); } +StopInfoSP StopInfo::CreateStopReasonProcessorTrace(Thread &thread, + const char *description) { + return StopInfoSP(new StopInfoProcessorTrace(thread, description)); +} + StopInfoSP StopInfo::CreateStopReasonWithExec(Thread &thread) { return StopInfoSP(new StopInfoExec(thread)); } diff --git a/gnu/llvm/lldb/source/Target/StructuredDataPlugin.cpp b/gnu/llvm/lldb/source/Target/StructuredDataPlugin.cpp index bd899d2f768..20ed26a1a99 100644 --- a/gnu/llvm/lldb/source/Target/StructuredDataPlugin.cpp +++ b/gnu/llvm/lldb/source/Target/StructuredDataPlugin.cpp @@ -23,14 +23,14 @@ public: "Parent for per-plugin structured data commands", "plugin structured-data ") {} - ~CommandStructuredData() override {} + ~CommandStructuredData() override = default; }; } StructuredDataPlugin::StructuredDataPlugin(const ProcessWP &process_wp) : PluginInterface(), m_process_wp(process_wp) {} -StructuredDataPlugin::~StructuredDataPlugin() {} +StructuredDataPlugin::~StructuredDataPlugin() = default; bool StructuredDataPlugin::GetEnabled(ConstString type_name) const { // By default, plugins are always enabled. Plugin authors should override diff --git a/gnu/llvm/lldb/source/Target/SystemRuntime.cpp b/gnu/llvm/lldb/source/Target/SystemRuntime.cpp index cd3d8ba2c7b..6d8a2ef5522 100644 --- a/gnu/llvm/lldb/source/Target/SystemRuntime.cpp +++ b/gnu/llvm/lldb/source/Target/SystemRuntime.cpp @@ -27,9 +27,7 @@ SystemRuntime *SystemRuntime::FindPlugin(Process *process) { return nullptr; } -// SystemRuntime constructor -SystemRuntime::SystemRuntime(Process *process) - : m_process(process), m_types() {} +SystemRuntime::SystemRuntime(Process *process) : Runtime(process), m_types() {} SystemRuntime::~SystemRuntime() = default; @@ -39,7 +37,7 @@ void SystemRuntime::DidLaunch() {} void SystemRuntime::Detach() {} -void SystemRuntime::ModulesDidLoad(ModuleList &module_list) {} +void SystemRuntime::ModulesDidLoad(const ModuleList &module_list) {} const std::vector &SystemRuntime::GetExtendedBacktraceTypes() { return m_types; diff --git a/gnu/llvm/lldb/source/Target/Target.cpp b/gnu/llvm/lldb/source/Target/Target.cpp index 19d0c3d477e..1f8e8c54fa9 100644 --- a/gnu/llvm/lldb/source/Target/Target.cpp +++ b/gnu/llvm/lldb/source/Target/Target.cpp @@ -7,7 +7,6 @@ //===----------------------------------------------------------------------===// #include "lldb/Target/Target.h" -#include "Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.h" #include "lldb/Breakpoint/BreakpointIDList.h" #include "lldb/Breakpoint/BreakpointPrecondition.h" #include "lldb/Breakpoint/BreakpointResolver.h" @@ -27,9 +26,11 @@ #include "lldb/Core/StreamFile.h" #include "lldb/Core/StructuredDataImpl.h" #include "lldb/Core/ValueObject.h" +#include "lldb/Expression/DiagnosticManager.h" #include "lldb/Expression/ExpressionVariable.h" #include "lldb/Expression/REPL.h" #include "lldb/Expression/UserExpression.h" +#include "lldb/Expression/UtilityFunction.h" #include "lldb/Host/Host.h" #include "lldb/Host/PosixApi.h" #include "lldb/Interpreter/CommandInterpreter.h" @@ -40,11 +41,13 @@ #include "lldb/Symbol/Function.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Symbol/Symbol.h" +#include "lldb/Target/ABI.h" #include "lldb/Target/Language.h" #include "lldb/Target/LanguageRuntime.h" #include "lldb/Target/Process.h" #include "lldb/Target/SectionLoadList.h" #include "lldb/Target/StackFrame.h" +#include "lldb/Target/StackFrameRecognizer.h" #include "lldb/Target/SystemRuntime.h" #include "lldb/Target/Thread.h" #include "lldb/Target/ThreadSpec.h" @@ -92,8 +95,11 @@ Target::Target(Debugger &debugger, const ArchSpec &target_arch, m_watchpoint_list(), m_process_sp(), m_search_filter_sp(), m_image_search_paths(ImageSearchPathsChanged, this), m_source_manager_up(), m_stop_hooks(), m_stop_hook_next_id(0), + m_latest_stop_hook_id(0), m_valid(true), m_suppress_stop_hooks(false), m_is_dummy_target(is_dummy_target), + m_frame_recognizer_manager_up( + std::make_unique()), m_stats_storage(static_cast(StatisticKind::StatisticMax)) { @@ -123,13 +129,10 @@ Target::~Target() { DeleteCurrentProcess(); } -void Target::PrimeFromDummyTarget(Target *target) { - if (!target) - return; - - m_stop_hooks = target->m_stop_hooks; +void Target::PrimeFromDummyTarget(Target &target) { + m_stop_hooks = target.m_stop_hooks; - for (const auto &breakpoint_sp : target->m_breakpoint_list.Breakpoints()) { + for (const auto &breakpoint_sp : target.m_breakpoint_list.Breakpoints()) { if (breakpoint_sp->IsInternal()) continue; @@ -138,11 +141,14 @@ void Target::PrimeFromDummyTarget(Target *target) { AddBreakpoint(std::move(new_bp), false); } - for (auto bp_name_entry : target->m_breakpoint_names) { + for (auto bp_name_entry : target.m_breakpoint_names) { BreakpointName *new_bp_name = new BreakpointName(*bp_name_entry.second); AddBreakpointName(new_bp_name); } + + m_frame_recognizer_manager_up = std::make_unique( + *target.m_frame_recognizer_manager_up); } void Target::Dump(Stream *s, lldb::DescriptionLevel description_level) { @@ -176,6 +182,7 @@ void Target::CleanupProcess() { DisableAllWatchpoints(false); ClearAllWatchpointHitCounts(); ClearAllWatchpointHistoricValues(); + m_latest_stop_hook_id = 0; } void Target::DeleteCurrentProcess() { @@ -194,12 +201,13 @@ void Target::DeleteCurrentProcess() { const lldb::ProcessSP &Target::CreateProcess(ListenerSP listener_sp, llvm::StringRef plugin_name, - const FileSpec *crash_file) { + const FileSpec *crash_file, + bool can_connect) { if (!listener_sp) listener_sp = GetDebugger().GetListener(); DeleteCurrentProcess(); m_process_sp = Process::FindPlugin(shared_from_this(), plugin_name, - listener_sp, crash_file); + listener_sp, crash_file, can_connect); return m_process_sp; } @@ -365,9 +373,14 @@ BreakpointSP Target::CreateBreakpoint(const FileSpecList *containingModules, if (move_to_nearest_code == eLazyBoolCalculate) move_to_nearest_code = GetMoveToNearestCode() ? eLazyBoolYes : eLazyBoolNo; + SourceLocationSpec location_spec(remapped_file, line_no, column, + check_inlines, + !static_cast(move_to_nearest_code)); + if (!location_spec) + return nullptr; + BreakpointResolverSP resolver_sp(new BreakpointResolverFileLine( - nullptr, remapped_file, line_no, column, offset, check_inlines, - skip_prologue, !static_cast(move_to_nearest_code))); + nullptr, offset, skip_prologue, location_spec)); return CreateBreakpoint(filter_sp, resolver_sp, internal, hardware, true); } @@ -813,6 +826,11 @@ WatchpointSP Target::CreateWatchpoint(lldb::addr_t addr, size_t size, // Grab the list mutex while doing operations. const bool notify = false; // Don't notify about all the state changes we do // on creating the watchpoint. + + // Mask off ignored bits from watchpoint address. + if (ABISP abi = m_process_sp->GetABI()) + addr = abi->FixDataAddress(addr); + std::unique_lock lock; this->GetWatchpointList().GetListMutex(lock); WatchpointSP matched_sp = m_watchpoint_list.FindByAddress(addr); @@ -1143,9 +1161,7 @@ bool Target::RemoveAllWatchpoints(bool end_to_end) { if (!ProcessIsValid()) return false; - size_t num_watchpoints = m_watchpoint_list.GetSize(); - for (size_t i = 0; i < num_watchpoints; ++i) { - WatchpointSP wp_sp = m_watchpoint_list.GetByIndex(i); + for (WatchpointSP wp_sp : m_watchpoint_list.Watchpoints()) { if (!wp_sp) return false; @@ -1174,9 +1190,7 @@ bool Target::DisableAllWatchpoints(bool end_to_end) { if (!ProcessIsValid()) return false; - size_t num_watchpoints = m_watchpoint_list.GetSize(); - for (size_t i = 0; i < num_watchpoints; ++i) { - WatchpointSP wp_sp = m_watchpoint_list.GetByIndex(i); + for (WatchpointSP wp_sp : m_watchpoint_list.Watchpoints()) { if (!wp_sp) return false; @@ -1203,9 +1217,7 @@ bool Target::EnableAllWatchpoints(bool end_to_end) { if (!ProcessIsValid()) return false; - size_t num_watchpoints = m_watchpoint_list.GetSize(); - for (size_t i = 0; i < num_watchpoints; ++i) { - WatchpointSP wp_sp = m_watchpoint_list.GetByIndex(i); + for (WatchpointSP wp_sp : m_watchpoint_list.Watchpoints()) { if (!wp_sp) return false; @@ -1221,9 +1233,7 @@ bool Target::ClearAllWatchpointHitCounts() { Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS)); LLDB_LOGF(log, "Target::%s\n", __FUNCTION__); - size_t num_watchpoints = m_watchpoint_list.GetSize(); - for (size_t i = 0; i < num_watchpoints; ++i) { - WatchpointSP wp_sp = m_watchpoint_list.GetByIndex(i); + for (WatchpointSP wp_sp : m_watchpoint_list.Watchpoints()) { if (!wp_sp) return false; @@ -1237,9 +1247,7 @@ bool Target::ClearAllWatchpointHistoricValues() { Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS)); LLDB_LOGF(log, "Target::%s\n", __FUNCTION__); - size_t num_watchpoints = m_watchpoint_list.GetSize(); - for (size_t i = 0; i < num_watchpoints; ++i) { - WatchpointSP wp_sp = m_watchpoint_list.GetByIndex(i); + for (WatchpointSP wp_sp : m_watchpoint_list.Watchpoints()) { if (!wp_sp) return false; @@ -1257,9 +1265,7 @@ bool Target::IgnoreAllWatchpoints(uint32_t ignore_count) { if (!ProcessIsValid()) return false; - size_t num_watchpoints = m_watchpoint_list.GetSize(); - for (size_t i = 0; i < num_watchpoints; ++i) { - WatchpointSP wp_sp = m_watchpoint_list.GetByIndex(i); + for (WatchpointSP wp_sp : m_watchpoint_list.Watchpoints()) { if (!wp_sp) return false; @@ -1394,9 +1400,7 @@ void Target::SetExecutableModule(ModuleSP &executable_sp, ClearModules(false); if (executable_sp) { - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer(func_cat, - "Target::SetExecutableModule (executable = '%s')", + LLDB_SCOPED_TIMERF("Target::SetExecutableModule (executable = '%s')", executable_sp->GetFileSpec().GetPath().c_str()); const bool notify = true; @@ -1683,6 +1687,7 @@ bool Target::ModuleIsExcludedForUnconstrainedSearches( size_t Target::ReadMemoryFromFileCache(const Address &addr, void *dst, size_t dst_len, Status &error) { + LLDB_SCOPED_TIMER(); SectionSP section_sp(addr.GetSection()); if (section_sp) { // If the contents of this section are encrypted, the on-disk file is @@ -1713,8 +1718,8 @@ size_t Target::ReadMemoryFromFileCache(const Address &addr, void *dst, return 0; } -size_t Target::ReadMemory(const Address &addr, bool prefer_file_cache, - void *dst, size_t dst_len, Status &error, +size_t Target::ReadMemory(const Address &addr, void *dst, size_t dst_len, + Status &error, bool force_live_memory, lldb::addr_t *load_addr_ptr) { error.Clear(); @@ -1749,10 +1754,31 @@ size_t Target::ReadMemory(const Address &addr, bool prefer_file_cache, if (!resolved_addr.IsValid()) resolved_addr = addr; - if (prefer_file_cache) { - bytes_read = ReadMemoryFromFileCache(resolved_addr, dst, dst_len, error); - if (bytes_read > 0) - return bytes_read; + // If we read from the file cache but can't get as many bytes as requested, + // we keep the result around in this buffer, in case this result is the + // best we can do. + std::unique_ptr file_cache_read_buffer; + size_t file_cache_bytes_read = 0; + + // Read from file cache if read-only section. + if (!force_live_memory && resolved_addr.IsSectionOffset()) { + SectionSP section_sp(resolved_addr.GetSection()); + if (section_sp) { + auto permissions = Flags(section_sp->GetPermissions()); + bool is_readonly = !permissions.Test(ePermissionsWritable) && + permissions.Test(ePermissionsReadable); + if (is_readonly) { + file_cache_bytes_read = + ReadMemoryFromFileCache(resolved_addr, dst, dst_len, error); + if (file_cache_bytes_read == dst_len) + return file_cache_bytes_read; + else if (file_cache_bytes_read > 0) { + file_cache_read_buffer = + std::make_unique(file_cache_bytes_read); + std::memcpy(file_cache_read_buffer.get(), dst, file_cache_bytes_read); + } + } + } } if (ProcessIsValid()) { @@ -1787,17 +1813,17 @@ size_t Target::ReadMemory(const Address &addr, bool prefer_file_cache, *load_addr_ptr = load_addr; return bytes_read; } - // If the address is not section offset we have an address that doesn't - // resolve to any address in any currently loaded shared libraries and we - // failed to read memory so there isn't anything more we can do. If it is - // section offset, we might be able to read cached memory from the object - // file. - if (!resolved_addr.IsSectionOffset()) - return 0; } } - if (!prefer_file_cache && resolved_addr.IsSectionOffset()) { + if (file_cache_read_buffer && file_cache_bytes_read > 0) { + // Reading from the process failed. If we've previously succeeded in reading + // something from the file cache, then copy that over and return that. + std::memcpy(dst, file_cache_read_buffer.get(), file_cache_bytes_read); + return file_cache_bytes_read; + } + + if (!file_cache_read_buffer && resolved_addr.IsSectionOffset()) { // If we didn't already try and read from the object file cache, then try // it after failing to read from the process. return ReadMemoryFromFileCache(resolved_addr, dst, dst_len, error); @@ -1852,7 +1878,7 @@ size_t Target::ReadCStringFromMemory(const Address &addr, char *dst, addr_t bytes_to_read = std::min(bytes_left, cache_line_bytes_left); size_t bytes_read = - ReadMemory(address, false, curr_dst, bytes_to_read, error); + ReadMemory(address, curr_dst, bytes_to_read, error, true); if (bytes_read == 0) { result_error = error; @@ -1880,15 +1906,15 @@ size_t Target::ReadCStringFromMemory(const Address &addr, char *dst, return total_cstr_len; } -size_t Target::ReadScalarIntegerFromMemory(const Address &addr, - bool prefer_file_cache, - uint32_t byte_size, bool is_signed, - Scalar &scalar, Status &error) { +size_t Target::ReadScalarIntegerFromMemory(const Address &addr, uint32_t byte_size, + bool is_signed, Scalar &scalar, + Status &error, + bool force_live_memory) { uint64_t uval; if (byte_size <= sizeof(uval)) { size_t bytes_read = - ReadMemory(addr, prefer_file_cache, &uval, byte_size, error); + ReadMemory(addr, &uval, byte_size, error, force_live_memory); if (bytes_read == byte_size) { DataExtractor data(&uval, sizeof(uval), m_arch.GetSpec().GetByteOrder(), m_arch.GetSpec().GetAddressByteSize()); @@ -1910,23 +1936,22 @@ size_t Target::ReadScalarIntegerFromMemory(const Address &addr, } uint64_t Target::ReadUnsignedIntegerFromMemory(const Address &addr, - bool prefer_file_cache, size_t integer_byte_size, - uint64_t fail_value, - Status &error) { + uint64_t fail_value, Status &error, + bool force_live_memory) { Scalar scalar; - if (ReadScalarIntegerFromMemory(addr, prefer_file_cache, integer_byte_size, - false, scalar, error)) + if (ReadScalarIntegerFromMemory(addr, integer_byte_size, false, scalar, error, + force_live_memory)) return scalar.ULongLong(fail_value); return fail_value; } -bool Target::ReadPointerFromMemory(const Address &addr, bool prefer_file_cache, - Status &error, Address &pointer_addr) { +bool Target::ReadPointerFromMemory(const Address &addr, Status &error, + Address &pointer_addr, + bool force_live_memory) { Scalar scalar; - if (ReadScalarIntegerFromMemory(addr, prefer_file_cache, - m_arch.GetSpec().GetAddressByteSize(), false, - scalar, error)) { + if (ReadScalarIntegerFromMemory(addr, m_arch.GetSpec().GetAddressByteSize(), + false, scalar, error, force_live_memory)) { addr_t pointer_vm_addr = scalar.ULongLong(LLDB_INVALID_ADDRESS); if (pointer_vm_addr != LLDB_INVALID_ADDRESS) { SectionLoadList §ion_load_list = GetSectionLoadList(); @@ -2290,27 +2315,29 @@ FunctionCaller *Target::GetFunctionCallerForLanguage( return persistent_fn; } -UtilityFunction * -Target::GetUtilityFunctionForLanguage(const char *text, - lldb::LanguageType language, - const char *name, Status &error) { +llvm::Expected> +Target::CreateUtilityFunction(std::string expression, std::string name, + lldb::LanguageType language, + ExecutionContext &exe_ctx) { auto type_system_or_err = GetScratchTypeSystemForLanguage(language); + if (!type_system_or_err) + return type_system_or_err.takeError(); - if (auto err = type_system_or_err.takeError()) { - error.SetErrorStringWithFormat( - "Could not find type system for language %s: %s", - Language::GetNameForLanguageType(language), - llvm::toString(std::move(err)).c_str()); - return nullptr; - } - - auto *utility_fn = type_system_or_err->GetUtilityFunction(text, name); + std::unique_ptr utility_fn = + type_system_or_err->CreateUtilityFunction(std::move(expression), + std::move(name)); if (!utility_fn) - error.SetErrorStringWithFormat( - "Could not create an expression for language %s", - Language::GetNameForLanguageType(language)); + return llvm::make_error( + llvm::StringRef("Could not create an expression for language") + + Language::GetNameForLanguageType(language), + llvm::inconvertibleErrorCode()); + + DiagnosticManager diagnostics; + if (!utility_fn->Install(diagnostics, exe_ctx)) + return llvm::make_error(diagnostics.GetString(), + llvm::inconvertibleErrorCode()); - return utility_fn; + return std::move(utility_fn); } void Target::SettingsInitialize() { Process::SettingsInitialize(); } @@ -2515,30 +2542,28 @@ SourceManager &Target::GetSourceManager() { return *m_source_manager_up; } -ClangModulesDeclVendor *Target::GetClangModulesDeclVendor() { - static std::mutex s_clang_modules_decl_vendor_mutex; // If this is contended - // we can make it - // per-target - - { - std::lock_guard guard(s_clang_modules_decl_vendor_mutex); - - if (!m_clang_modules_decl_vendor_up) { - m_clang_modules_decl_vendor_up.reset( - ClangModulesDeclVendor::Create(*this)); - } - } - - return m_clang_modules_decl_vendor_up.get(); -} - -Target::StopHookSP Target::CreateStopHook() { +Target::StopHookSP Target::CreateStopHook(StopHook::StopHookKind kind) { lldb::user_id_t new_uid = ++m_stop_hook_next_id; - Target::StopHookSP stop_hook_sp(new StopHook(shared_from_this(), new_uid)); + Target::StopHookSP stop_hook_sp; + switch (kind) { + case StopHook::StopHookKind::CommandBased: + stop_hook_sp.reset(new StopHookCommandLine(shared_from_this(), new_uid)); + break; + case StopHook::StopHookKind::ScriptBased: + stop_hook_sp.reset(new StopHookScripted(shared_from_this(), new_uid)); + break; + } m_stop_hooks[new_uid] = stop_hook_sp; return stop_hook_sp; } +void Target::UndoCreateStopHook(lldb::user_id_t user_id) { + if (!RemoveStopHookByID(user_id)) + return; + if (user_id == m_stop_hook_next_id) + m_stop_hook_next_id--; +} + bool Target::RemoveStopHookByID(lldb::user_id_t user_id) { size_t num_removed = m_stop_hooks.erase(user_id); return (num_removed != 0); @@ -2574,45 +2599,45 @@ void Target::SetAllStopHooksActiveState(bool active_state) { } } -void Target::RunStopHooks() { +bool Target::RunStopHooks() { if (m_suppress_stop_hooks) - return; + return false; if (!m_process_sp) - return; + return false; // Somebody might have restarted the process: + // Still return false, the return value is about US restarting the target. if (m_process_sp->GetState() != eStateStopped) - return; - - // make sure we check that we are not stopped - // because of us running a user expression since in that case we do not want - // to run the stop-hooks - if (m_process_sp->GetModIDRef().IsLastResumeForUserExpression()) - return; + return false; if (m_stop_hooks.empty()) - return; - - StopHookCollection::iterator pos, end = m_stop_hooks.end(); + return false; // If there aren't any active stop hooks, don't bother either. - // Also see if any of the active hooks want to auto-continue. bool any_active_hooks = false; - bool auto_continue = false; for (auto hook : m_stop_hooks) { if (hook.second->IsActive()) { any_active_hooks = true; - auto_continue |= hook.second->GetAutoContinue(); + break; } } if (!any_active_hooks) - return; + return false; - CommandReturnObject result(m_debugger.GetUseColor()); + // make sure we check that we are not stopped + // because of us running a user expression since in that case we do not want + // to run the stop-hooks. Note, you can't just check whether the last stop + // was for a User Expression, because breakpoint commands get run before + // stop hooks, and one of them might have run an expression. You have + // to ensure you run the stop hooks once per natural stop. + uint32_t last_natural_stop = m_process_sp->GetModIDRef().GetLastNaturalStopID(); + if (last_natural_stop != 0 && m_latest_stop_hook_id == last_natural_stop) + return false; + + m_latest_stop_hook_id = last_natural_stop; std::vector exc_ctx_with_reasons; - std::vector sym_ctx_with_reasons; ThreadList &cur_threadlist = m_process_sp->GetThreadList(); size_t num_threads = cur_threadlist.GetSize(); @@ -2620,103 +2645,127 @@ void Target::RunStopHooks() { lldb::ThreadSP cur_thread_sp = cur_threadlist.GetThreadAtIndex(i); if (cur_thread_sp->ThreadStoppedForAReason()) { lldb::StackFrameSP cur_frame_sp = cur_thread_sp->GetStackFrameAtIndex(0); - exc_ctx_with_reasons.push_back(ExecutionContext( - m_process_sp.get(), cur_thread_sp.get(), cur_frame_sp.get())); - sym_ctx_with_reasons.push_back( - cur_frame_sp->GetSymbolContext(eSymbolContextEverything)); + exc_ctx_with_reasons.emplace_back(m_process_sp.get(), cur_thread_sp.get(), + cur_frame_sp.get()); } } // If no threads stopped for a reason, don't run the stop-hooks. size_t num_exe_ctx = exc_ctx_with_reasons.size(); if (num_exe_ctx == 0) - return; + return false; - result.SetImmediateOutputStream(m_debugger.GetAsyncOutputStream()); - result.SetImmediateErrorStream(m_debugger.GetAsyncErrorStream()); + StreamSP output_sp = m_debugger.GetAsyncOutputStream(); - bool keep_going = true; + bool auto_continue = false; bool hooks_ran = false; bool print_hook_header = (m_stop_hooks.size() != 1); bool print_thread_header = (num_exe_ctx != 1); - bool did_restart = false; + bool should_stop = false; + bool somebody_restarted = false; - for (pos = m_stop_hooks.begin(); keep_going && pos != end; pos++) { - // result.Clear(); - StopHookSP cur_hook_sp = (*pos).second; + for (auto stop_entry : m_stop_hooks) { + StopHookSP cur_hook_sp = stop_entry.second; if (!cur_hook_sp->IsActive()) continue; bool any_thread_matched = false; - for (size_t i = 0; keep_going && i < num_exe_ctx; i++) { - if ((cur_hook_sp->GetSpecifier() == nullptr || - cur_hook_sp->GetSpecifier()->SymbolContextMatches( - sym_ctx_with_reasons[i])) && - (cur_hook_sp->GetThreadSpecifier() == nullptr || - cur_hook_sp->GetThreadSpecifier()->ThreadPassesBasicTests( - exc_ctx_with_reasons[i].GetThreadRef()))) { - if (!hooks_ran) { - hooks_ran = true; - } - if (print_hook_header && !any_thread_matched) { - const char *cmd = - (cur_hook_sp->GetCommands().GetSize() == 1 - ? cur_hook_sp->GetCommands().GetStringAtIndex(0) - : nullptr); - if (cmd) - result.AppendMessageWithFormat("\n- Hook %" PRIu64 " (%s)\n", - cur_hook_sp->GetID(), cmd); - else - result.AppendMessageWithFormat("\n- Hook %" PRIu64 "\n", - cur_hook_sp->GetID()); - any_thread_matched = true; - } + for (auto exc_ctx : exc_ctx_with_reasons) { + // We detect somebody restarted in the stop-hook loop, and broke out of + // that loop back to here. So break out of here too. + if (somebody_restarted) + break; - if (print_thread_header) - result.AppendMessageWithFormat( - "-- Thread %d\n", - exc_ctx_with_reasons[i].GetThreadPtr()->GetIndexID()); - - CommandInterpreterRunOptions options; - options.SetStopOnContinue(true); - options.SetStopOnError(true); - options.SetEchoCommands(false); - options.SetPrintResults(true); - options.SetPrintErrors(true); - options.SetAddToHistory(false); - - // Force Async: - bool old_async = GetDebugger().GetAsyncExecution(); - GetDebugger().SetAsyncExecution(true); - GetDebugger().GetCommandInterpreter().HandleCommands( - cur_hook_sp->GetCommands(), &exc_ctx_with_reasons[i], options, - result); - GetDebugger().SetAsyncExecution(old_async); - // If the command started the target going again, we should bag out of - // running the stop hooks. - if ((result.GetStatus() == eReturnStatusSuccessContinuingNoResult) || - (result.GetStatus() == eReturnStatusSuccessContinuingResult)) { - // But only complain if there were more stop hooks to do: - StopHookCollection::iterator tmp = pos; - if (++tmp != end) - result.AppendMessageWithFormat( - "\nAborting stop hooks, hook %" PRIu64 - " set the program running.\n" - " Consider using '-G true' to make " - "stop hooks auto-continue.\n", - cur_hook_sp->GetID()); - keep_going = false; - did_restart = true; - } + if (!cur_hook_sp->ExecutionContextPasses(exc_ctx)) + continue; + + // We only consult the auto-continue for a stop hook if it matched the + // specifier. + auto_continue |= cur_hook_sp->GetAutoContinue(); + + if (!hooks_ran) + hooks_ran = true; + + if (print_hook_header && !any_thread_matched) { + StreamString s; + cur_hook_sp->GetDescription(&s, eDescriptionLevelBrief); + if (s.GetSize() != 0) + output_sp->Printf("\n- Hook %" PRIu64 " (%s)\n", cur_hook_sp->GetID(), + s.GetData()); + else + output_sp->Printf("\n- Hook %" PRIu64 "\n", cur_hook_sp->GetID()); + any_thread_matched = true; + } + + if (print_thread_header) + output_sp->Printf("-- Thread %d\n", + exc_ctx.GetThreadPtr()->GetIndexID()); + + StopHook::StopHookResult this_result = + cur_hook_sp->HandleStop(exc_ctx, output_sp); + bool this_should_stop = true; + + switch (this_result) { + case StopHook::StopHookResult::KeepStopped: + // If this hook is set to auto-continue that should override the + // HandleStop result... + if (cur_hook_sp->GetAutoContinue()) + this_should_stop = false; + else + this_should_stop = true; + + break; + case StopHook::StopHookResult::RequestContinue: + this_should_stop = false; + break; + case StopHook::StopHookResult::AlreadyContinued: + // We don't have a good way to prohibit people from restarting the + // target willy nilly in a stop hook. If the hook did so, give a + // gentle suggestion here and bag out if the hook processing. + output_sp->Printf("\nAborting stop hooks, hook %" PRIu64 + " set the program running.\n" + " Consider using '-G true' to make " + "stop hooks auto-continue.\n", + cur_hook_sp->GetID()); + somebody_restarted = true; + break; } + // If we're already restarted, stop processing stop hooks. + // FIXME: if we are doing non-stop mode for real, we would have to + // check that OUR thread was restarted, otherwise we should keep + // processing stop hooks. + if (somebody_restarted) + break; + + // If anybody wanted to stop, we should all stop. + if (!should_stop) + should_stop = this_should_stop; } } + + output_sp->Flush(); + + // If one of the commands in the stop hook already restarted the target, + // report that fact. + if (somebody_restarted) + return true; + // Finally, if auto-continue was requested, do it now: - if (!did_restart && auto_continue) - m_process_sp->PrivateResume(); + // We only compute should_stop against the hook results if a hook got to run + // which is why we have to do this conjoint test. + if ((hooks_ran && !should_stop) || auto_continue) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); + Status error = m_process_sp->PrivateResume(); + if (error.Success()) { + LLDB_LOG(log, "Resuming from RunStopHooks"); + return true; + } else { + LLDB_LOG(log, "Resuming from RunStopHooks failed: {0}", error); + return false; + } + } - result.GetImmediateOutputStream()->Flush(); - result.GetImmediateErrorStream()->Flush(); + return false; } const TargetPropertiesSP &Target::GetGlobalProperties() { @@ -2886,6 +2935,28 @@ Status Target::Launch(ProcessLaunchInfo &launch_info, Stream *stream) { launch_info.GetFlags().Set(eLaunchFlagDebug); + if (launch_info.IsScriptedProcess()) { + TargetPropertiesSP properties_sp = GetGlobalProperties(); + + if (!properties_sp) { + LLDB_LOGF(log, "Target::%s Couldn't fetch target global properties.", + __FUNCTION__); + return error; + } + + // Only copy scripted process launch options. + ProcessLaunchInfo &default_launch_info = + const_cast(properties_sp->GetProcessLaunchInfo()); + + default_launch_info.SetProcessPluginName("ScriptedProcess"); + default_launch_info.SetScriptedProcessClassName( + launch_info.GetScriptedProcessClassName()); + default_launch_info.SetScriptedProcessDictionarySP( + launch_info.GetScriptedProcessDictionarySP()); + + SetProcessLaunchInfo(launch_info); + } + // Get the value of synchronous execution here. If you wait till after you // have started to run, then you could have hit a breakpoint, whose command // might switch the value, and then you'll pick up that incorrect value. @@ -2911,7 +2982,7 @@ Status Target::Launch(ProcessLaunchInfo &launch_info, Stream *stream) { // If we're not already connected to the process, and if we have a platform // that can launch a process for debugging, go ahead and do that here. if (state != eStateConnected && platform_sp && - platform_sp->CanDebugProcess()) { + platform_sp->CanDebugProcess() && !launch_info.IsScriptedProcess()) { LLDB_LOGF(log, "Target::%s asking the platform to debug the process", __FUNCTION__); @@ -2935,7 +3006,7 @@ Status Target::Launch(ProcessLaunchInfo &launch_info, Stream *stream) { } else { // Use a Process plugin to construct the process. const char *plugin_name = launch_info.GetProcessPluginName(); - CreateProcess(launch_info.GetListener(), plugin_name, nullptr); + CreateProcess(launch_info.GetListener(), plugin_name, nullptr, false); } // Since we didn't have a platform launch the process, launch it here. @@ -2943,80 +3014,110 @@ Status Target::Launch(ProcessLaunchInfo &launch_info, Stream *stream) { error = m_process_sp->Launch(launch_info); } - if (!m_process_sp) { - if (error.Success()) - error.SetErrorString("failed to launch or debug process"); + if (!m_process_sp && error.Success()) + error.SetErrorString("failed to launch or debug process"); + + if (!error.Success()) return error; - } - if (error.Success()) { - if (synchronous_execution || - !launch_info.GetFlags().Test(eLaunchFlagStopAtEntry)) { - ListenerSP hijack_listener_sp(launch_info.GetHijackListener()); - if (!hijack_listener_sp) { - hijack_listener_sp = - Listener::MakeListener("lldb.Target.Launch.hijack"); - launch_info.SetHijackListener(hijack_listener_sp); - m_process_sp->HijackProcessEvents(hijack_listener_sp); - } + auto at_exit = + llvm::make_scope_exit([&]() { m_process_sp->RestoreProcessEvents(); }); - StateType state = m_process_sp->WaitForProcessToStop( - llvm::None, nullptr, false, hijack_listener_sp, nullptr); - - if (state == eStateStopped) { - if (!launch_info.GetFlags().Test(eLaunchFlagStopAtEntry)) { - if (synchronous_execution) { - // Now we have handled the stop-from-attach, and we are just - // switching to a synchronous resume. So we should switch to the - // SyncResume hijacker. - m_process_sp->RestoreProcessEvents(); - m_process_sp->ResumeSynchronous(stream); - } else { - m_process_sp->RestoreProcessEvents(); - error = m_process_sp->PrivateResume(); - } - if (!error.Success()) { - Status error2; - error2.SetErrorStringWithFormat( - "process resume at entry point failed: %s", error.AsCString()); - error = error2; - } - } - } else if (state == eStateExited) { - bool with_shell = !!launch_info.GetShell(); - const int exit_status = m_process_sp->GetExitStatus(); - const char *exit_desc = m_process_sp->GetExitDescription(); -#define LAUNCH_SHELL_MESSAGE \ - "\n'r' and 'run' are aliases that default to launching through a " \ - "shell.\nTry launching without going through a shell by using 'process " \ - "launch'." - if (exit_desc && exit_desc[0]) { - if (with_shell) - error.SetErrorStringWithFormat( - "process exited with status %i (%s)" LAUNCH_SHELL_MESSAGE, - exit_status, exit_desc); - else - error.SetErrorStringWithFormat("process exited with status %i (%s)", - exit_status, exit_desc); - } else { - if (with_shell) - error.SetErrorStringWithFormat( - "process exited with status %i" LAUNCH_SHELL_MESSAGE, - exit_status); - else - error.SetErrorStringWithFormat("process exited with status %i", - exit_status); - } - } else { - error.SetErrorStringWithFormat( - "initial process state wasn't stopped: %s", StateAsCString(state)); - } + if (!synchronous_execution && + launch_info.GetFlags().Test(eLaunchFlagStopAtEntry)) + return error; + + ListenerSP hijack_listener_sp(launch_info.GetHijackListener()); + if (!hijack_listener_sp) { + hijack_listener_sp = Listener::MakeListener("lldb.Target.Launch.hijack"); + launch_info.SetHijackListener(hijack_listener_sp); + m_process_sp->HijackProcessEvents(hijack_listener_sp); + } + + switch (m_process_sp->WaitForProcessToStop(llvm::None, nullptr, false, + hijack_listener_sp, nullptr)) { + case eStateStopped: { + if (launch_info.GetFlags().Test(eLaunchFlagStopAtEntry)) + break; + if (synchronous_execution) { + // Now we have handled the stop-from-attach, and we are just + // switching to a synchronous resume. So we should switch to the + // SyncResume hijacker. + m_process_sp->RestoreProcessEvents(); + m_process_sp->ResumeSynchronous(stream); + } else { + m_process_sp->RestoreProcessEvents(); + error = m_process_sp->PrivateResume(); } - m_process_sp->RestoreProcessEvents(); + if (!error.Success()) { + Status error2; + error2.SetErrorStringWithFormat( + "process resume at entry point failed: %s", error.AsCString()); + error = error2; + } + } break; + case eStateExited: { + bool with_shell = !!launch_info.GetShell(); + const int exit_status = m_process_sp->GetExitStatus(); + const char *exit_desc = m_process_sp->GetExitDescription(); + std::string desc; + if (exit_desc && exit_desc[0]) + desc = " (" + std::string(exit_desc) + ')'; + if (with_shell) + error.SetErrorStringWithFormat( + "process exited with status %i%s\n" + "'r' and 'run' are aliases that default to launching through a " + "shell.\n" + "Try launching without going through a shell by using " + "'process launch'.", + exit_status, desc.c_str()); + else + error.SetErrorStringWithFormat("process exited with status %i%s", + exit_status, desc.c_str()); + } break; + default: + error.SetErrorStringWithFormat("initial process state wasn't stopped: %s", + StateAsCString(state)); + break; } return error; } +void Target::SetTrace(const TraceSP &trace_sp) { m_trace_sp = trace_sp; } + +TraceSP Target::GetTrace() { return m_trace_sp; } + +llvm::Expected Target::CreateTrace() { + if (!m_process_sp) + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "A process is required for tracing"); + if (m_trace_sp) + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "A trace already exists for the target"); + + llvm::Expected trace_type = + m_process_sp->TraceSupported(); + if (!trace_type) + return llvm::createStringError( + llvm::inconvertibleErrorCode(), "Tracing is not supported. %s", + llvm::toString(trace_type.takeError()).c_str()); + if (llvm::Expected trace_sp = + Trace::FindPluginForLiveProcess(trace_type->name, *m_process_sp)) + m_trace_sp = *trace_sp; + else + return llvm::createStringError( + llvm::inconvertibleErrorCode(), + "Couldn't create a Trace object for the process. %s", + llvm::toString(trace_sp.takeError()).c_str()); + return m_trace_sp; +} + +llvm::Expected Target::GetTraceOrCreate() { + if (m_trace_sp) + return m_trace_sp; + return CreateTrace(); +} + Status Target::Attach(ProcessAttachInfo &attach_info, Stream *stream) { auto state = eStateInvalid; auto process_sp = GetProcessSP(); @@ -3064,7 +3165,7 @@ Status Target::Attach(ProcessAttachInfo &attach_info, Stream *stream) { const char *plugin_name = attach_info.GetProcessPluginName(); process_sp = CreateProcess(attach_info.GetListenerForProcess(GetDebugger()), - plugin_name, nullptr); + plugin_name, nullptr, false); if (process_sp == nullptr) { error.SetErrorStringWithFormat( "failed to create process using plugin %s", @@ -3181,20 +3282,17 @@ void Target::FinalizeFileActions(ProcessLaunchInfo &info) { // Target::StopHook Target::StopHook::StopHook(lldb::TargetSP target_sp, lldb::user_id_t uid) - : UserID(uid), m_target_sp(target_sp), m_commands(), m_specifier_sp(), + : UserID(uid), m_target_sp(target_sp), m_specifier_sp(), m_thread_spec_up() {} Target::StopHook::StopHook(const StopHook &rhs) : UserID(rhs.GetID()), m_target_sp(rhs.m_target_sp), - m_commands(rhs.m_commands), m_specifier_sp(rhs.m_specifier_sp), - m_thread_spec_up(), m_active(rhs.m_active), - m_auto_continue(rhs.m_auto_continue) { + m_specifier_sp(rhs.m_specifier_sp), m_thread_spec_up(), + m_active(rhs.m_active), m_auto_continue(rhs.m_auto_continue) { if (rhs.m_thread_spec_up) m_thread_spec_up = std::make_unique(*rhs.m_thread_spec_up); } -Target::StopHook::~StopHook() = default; - void Target::StopHook::SetSpecifier(SymbolContextSpecifier *specifier) { m_specifier_sp.reset(specifier); } @@ -3203,8 +3301,31 @@ void Target::StopHook::SetThreadSpecifier(ThreadSpec *specifier) { m_thread_spec_up.reset(specifier); } +bool Target::StopHook::ExecutionContextPasses(const ExecutionContext &exc_ctx) { + SymbolContextSpecifier *specifier = GetSpecifier(); + if (!specifier) + return true; + + bool will_run = true; + if (exc_ctx.GetFramePtr()) + will_run = GetSpecifier()->SymbolContextMatches( + exc_ctx.GetFramePtr()->GetSymbolContext(eSymbolContextEverything)); + if (will_run && GetThreadSpecifier() != nullptr) + will_run = + GetThreadSpecifier()->ThreadPassesBasicTests(exc_ctx.GetThreadRef()); + + return will_run; +} + void Target::StopHook::GetDescription(Stream *s, lldb::DescriptionLevel level) const { + + // For brief descriptions, only print the subclass description: + if (level == eDescriptionLevelBrief) { + GetSubclassDescription(s, level); + return; + } + unsigned indent_level = s->GetIndentLevel(); s->SetIndentLevel(indent_level + 2); @@ -3235,15 +3356,155 @@ void Target::StopHook::GetDescription(Stream *s, s->PutCString("\n"); s->SetIndentLevel(indent_level + 2); } + GetSubclassDescription(s, level); +} +void Target::StopHookCommandLine::GetSubclassDescription( + Stream *s, lldb::DescriptionLevel level) const { + // The brief description just prints the first command. + if (level == eDescriptionLevelBrief) { + if (m_commands.GetSize() == 1) + s->PutCString(m_commands.GetStringAtIndex(0)); + return; + } s->Indent("Commands: \n"); - s->SetIndentLevel(indent_level + 4); + s->SetIndentLevel(s->GetIndentLevel() + 4); uint32_t num_commands = m_commands.GetSize(); for (uint32_t i = 0; i < num_commands; i++) { s->Indent(m_commands.GetStringAtIndex(i)); s->PutCString("\n"); } - s->SetIndentLevel(indent_level); + s->SetIndentLevel(s->GetIndentLevel() - 4); +} + +// Target::StopHookCommandLine +void Target::StopHookCommandLine::SetActionFromString(const std::string &string) { + GetCommands().SplitIntoLines(string); +} + +void Target::StopHookCommandLine::SetActionFromStrings( + const std::vector &strings) { + for (auto string : strings) + GetCommands().AppendString(string.c_str()); +} + +Target::StopHook::StopHookResult +Target::StopHookCommandLine::HandleStop(ExecutionContext &exc_ctx, + StreamSP output_sp) { + assert(exc_ctx.GetTargetPtr() && "Can't call PerformAction on a context " + "with no target"); + + if (!m_commands.GetSize()) + return StopHookResult::KeepStopped; + + CommandReturnObject result(false); + result.SetImmediateOutputStream(output_sp); + result.SetInteractive(false); + Debugger &debugger = exc_ctx.GetTargetPtr()->GetDebugger(); + CommandInterpreterRunOptions options; + options.SetStopOnContinue(true); + options.SetStopOnError(true); + options.SetEchoCommands(false); + options.SetPrintResults(true); + options.SetPrintErrors(true); + options.SetAddToHistory(false); + + // Force Async: + bool old_async = debugger.GetAsyncExecution(); + debugger.SetAsyncExecution(true); + debugger.GetCommandInterpreter().HandleCommands(GetCommands(), exc_ctx, + options, result); + debugger.SetAsyncExecution(old_async); + lldb::ReturnStatus status = result.GetStatus(); + if (status == eReturnStatusSuccessContinuingNoResult || + status == eReturnStatusSuccessContinuingResult) + return StopHookResult::AlreadyContinued; + return StopHookResult::KeepStopped; +} + +// Target::StopHookScripted +Status Target::StopHookScripted::SetScriptCallback( + std::string class_name, StructuredData::ObjectSP extra_args_sp) { + Status error; + + ScriptInterpreter *script_interp = + GetTarget()->GetDebugger().GetScriptInterpreter(); + if (!script_interp) { + error.SetErrorString("No script interpreter installed."); + return error; + } + + m_class_name = class_name; + + m_extra_args = new StructuredDataImpl(); + + if (extra_args_sp) + m_extra_args->SetObjectSP(extra_args_sp); + + m_implementation_sp = script_interp->CreateScriptedStopHook( + GetTarget(), m_class_name.c_str(), m_extra_args, error); + + return error; +} + +Target::StopHook::StopHookResult +Target::StopHookScripted::HandleStop(ExecutionContext &exc_ctx, + StreamSP output_sp) { + assert(exc_ctx.GetTargetPtr() && "Can't call HandleStop on a context " + "with no target"); + + ScriptInterpreter *script_interp = + GetTarget()->GetDebugger().GetScriptInterpreter(); + if (!script_interp) + return StopHookResult::KeepStopped; + + bool should_stop = script_interp->ScriptedStopHookHandleStop( + m_implementation_sp, exc_ctx, output_sp); + + return should_stop ? StopHookResult::KeepStopped + : StopHookResult::RequestContinue; +} + +void Target::StopHookScripted::GetSubclassDescription( + Stream *s, lldb::DescriptionLevel level) const { + if (level == eDescriptionLevelBrief) { + s->PutCString(m_class_name); + return; + } + s->Indent("Class:"); + s->Printf("%s\n", m_class_name.c_str()); + + // Now print the extra args: + // FIXME: We should use StructuredData.GetDescription on the m_extra_args + // but that seems to rely on some printing plugin that doesn't exist. + if (!m_extra_args->IsValid()) + return; + StructuredData::ObjectSP object_sp = m_extra_args->GetObjectSP(); + if (!object_sp || !object_sp->IsValid()) + return; + + StructuredData::Dictionary *as_dict = object_sp->GetAsDictionary(); + if (!as_dict || !as_dict->IsValid()) + return; + + uint32_t num_keys = as_dict->GetSize(); + if (num_keys == 0) + return; + + s->Indent("Args:\n"); + s->SetIndentLevel(s->GetIndentLevel() + 4); + + auto print_one_element = [&s](ConstString key, + StructuredData::Object *object) { + s->Indent(); + s->Printf("%s : %s\n", key.GetCString(), + object->GetStringValue().str().c_str()); + return true; + }; + + as_dict->ForEach(print_one_element); + + s->SetIndentLevel(s->GetIndentLevel() - 4); } static constexpr OptionEnumValueElement g_dynamic_value_types[] = { @@ -3316,6 +3577,28 @@ static constexpr OptionEnumValueElement g_x86_dis_flavor_value_types[] = { }, }; +static constexpr OptionEnumValueElement g_import_std_module_value_types[] = { + { + eImportStdModuleFalse, + "false", + "Never import the 'std' C++ module in the expression parser.", + }, + { + eImportStdModuleFallback, + "fallback", + "Retry evaluating expressions with an imported 'std' C++ module if they" + " failed to parse without the module. This allows evaluating more " + "complex expressions involving C++ standard library types." + }, + { + eImportStdModuleTrue, + "true", + "Always import the 'std' C++ module. This allows evaluating more " + "complex expressions involving C++ standard library types. This feature" + " is experimental." + }, +}; + static constexpr OptionEnumValueElement g_hex_immediate_style_values[] = { { Disassembler::eHexStyleC, @@ -3395,15 +3678,10 @@ enum { ePropertyExperimental, }; -class TargetOptionValueProperties : public OptionValueProperties { +class TargetOptionValueProperties + : public Cloneable { public: - TargetOptionValueProperties(ConstString name) : OptionValueProperties(name) {} - - // This constructor is used when creating TargetOptionValueProperties when it - // is part of a new lldb_private::Target instance. It will copy all current - // global property values as needed - TargetOptionValueProperties(const TargetPropertiesSP &target_properties_sp) - : OptionValueProperties(*target_properties_sp->GetValueProperties()) {} + TargetOptionValueProperties(ConstString name) : Cloneable(name) {} const Property *GetPropertyAtIndex(const ExecutionContext *exe_ctx, bool will_modify, @@ -3434,11 +3712,12 @@ enum { #include "TargetPropertiesEnum.inc" }; -class TargetExperimentalOptionValueProperties : public OptionValueProperties { +class TargetExperimentalOptionValueProperties + : public Cloneable { public: TargetExperimentalOptionValueProperties() - : OptionValueProperties( - ConstString(Properties::GetExperimentalSettingsName())) {} + : Cloneable(ConstString(Properties::GetExperimentalSettingsName())) {} }; TargetExperimentalProperties::TargetExperimentalProperties() @@ -3451,8 +3730,8 @@ TargetExperimentalProperties::TargetExperimentalProperties() TargetProperties::TargetProperties(Target *target) : Properties(), m_launch_info(), m_target(target) { if (target) { - m_collection_sp = std::make_shared( - Target::GetGlobalProperties()); + m_collection_sp = + OptionValueProperties::CreateLocalCopy(*Target::GetGlobalProperties()); // Set callbacks to update launch_info whenever "settins set" updated any // of these properties @@ -3477,6 +3756,8 @@ TargetProperties::TargetProperties(Target *target) }); m_collection_sp->SetValueChangedCallback( ePropertyDisableASLR, [this] { DisableASLRValueChangedCallback(); }); + m_collection_sp->SetValueChangedCallback( + ePropertyInheritTCC, [this] { InheritTCCValueChangedCallback(); }); m_collection_sp->SetValueChangedCallback( ePropertyDisableSTDIO, [this] { DisableSTDIOValueChangedCallback(); }); @@ -3515,6 +3796,7 @@ void TargetProperties::UpdateLaunchInfoFromProperties() { ErrorPathValueChangedCallback(); DetachOnErrorValueChangedCallback(); DisableASLRValueChangedCallback(); + InheritTCCValueChangedCallback(); DisableSTDIOValueChangedCallback(); } @@ -3597,6 +3879,17 @@ void TargetProperties::SetDisableASLR(bool b) { m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, b); } +bool TargetProperties::GetInheritTCC() const { + const uint32_t idx = ePropertyInheritTCC; + return m_collection_sp->GetPropertyAtIndexAsBoolean( + nullptr, idx, g_target_properties[idx].default_uint_value != 0); +} + +void TargetProperties::SetInheritTCC(bool b) { + const uint32_t idx = ePropertyInheritTCC; + m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, b); +} + bool TargetProperties::GetDetachOnError() const { const uint32_t idx = ePropertyDetachOnError; return m_collection_sp->GetPropertyAtIndexAsBoolean( @@ -3755,10 +4048,10 @@ bool TargetProperties::GetEnableAutoImportClangModules() const { nullptr, idx, g_target_properties[idx].default_uint_value != 0); } -bool TargetProperties::GetEnableImportStdModule() const { +ImportStdModule TargetProperties::GetImportStdModule() const { const uint32_t idx = ePropertyImportStdModule; - return m_collection_sp->GetPropertyAtIndexAsBoolean( - nullptr, idx, g_target_properties[idx].default_uint_value != 0); + return (ImportStdModule)m_collection_sp->GetPropertyAtIndexAsEnumeration( + nullptr, idx, g_target_properties[idx].default_uint_value); } bool TargetProperties::GetEnableAutoApplyFixIts() const { @@ -3869,6 +4162,12 @@ llvm::StringRef TargetProperties::GetExpressionPrefixContents() { return ""; } +uint64_t TargetProperties::GetExprErrorLimit() const { + const uint32_t idx = ePropertyExprErrorLimit; + return m_collection_sp->GetPropertyAtIndexAsUInt64( + nullptr, idx, g_target_properties[idx].default_uint_value); +} + bool TargetProperties::GetBreakpointsConsultPlatformAvoidList() { const uint32_t idx = ePropertyBreakpointUseAvoidList; return m_collection_sp->GetPropertyAtIndexAsBoolean( @@ -3960,8 +4259,7 @@ void TargetProperties::SetNonStopModeEnabled(bool b) { m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, b); } -const ProcessLaunchInfo &TargetProperties::GetProcessLaunchInfo() { - m_launch_info.SetArg0(GetArg0()); // FIXME: Arg0 callback doesn't work +const ProcessLaunchInfo &TargetProperties::GetProcessLaunchInfo() const { return m_launch_info; } @@ -3988,6 +4286,8 @@ void TargetProperties::SetProcessLaunchInfo( } SetDetachOnError(launch_info.GetFlags().Test(lldb::eLaunchFlagDetachOnError)); SetDisableASLR(launch_info.GetFlags().Test(lldb::eLaunchFlagDisableASLR)); + SetInheritTCC( + launch_info.GetFlags().Test(lldb::eLaunchFlagInheritTCCFromParent)); SetDisableSTDIO(launch_info.GetFlags().Test(lldb::eLaunchFlagDisableSTDIO)); } @@ -4051,6 +4351,13 @@ void TargetProperties::DisableASLRValueChangedCallback() { m_launch_info.GetFlags().Clear(lldb::eLaunchFlagDisableASLR); } +void TargetProperties::InheritTCCValueChangedCallback() { + if (GetInheritTCC()) + m_launch_info.GetFlags().Set(lldb::eLaunchFlagInheritTCCFromParent); + else + m_launch_info.GetFlags().Clear(lldb::eLaunchFlagInheritTCCFromParent); +} + void TargetProperties::DisableSTDIOValueChangedCallback() { if (GetDisableSTDIO()) m_launch_info.GetFlags().Set(lldb::eLaunchFlagDisableSTDIO); @@ -4058,6 +4365,17 @@ void TargetProperties::DisableSTDIOValueChangedCallback() { m_launch_info.GetFlags().Clear(lldb::eLaunchFlagDisableSTDIO); } +bool TargetProperties::GetDebugUtilityExpression() const { + const uint32_t idx = ePropertyDebugUtilityExpression; + return m_collection_sp->GetPropertyAtIndexAsBoolean( + nullptr, idx, g_target_properties[idx].default_uint_value != 0); +} + +void TargetProperties::SetDebugUtilityExpression(bool debug) { + const uint32_t idx = ePropertyDebugUtilityExpression; + m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, debug); +} + // Target::TargetEventData Target::TargetEventData::TargetEventData(const lldb::TargetSP &target_sp) diff --git a/gnu/llvm/lldb/source/Target/TargetList.cpp b/gnu/llvm/lldb/source/Target/TargetList.cpp index 3974cb5de41..595799cfc92 100644 --- a/gnu/llvm/lldb/source/Target/TargetList.cpp +++ b/gnu/llvm/lldb/source/Target/TargetList.cpp @@ -42,21 +42,20 @@ TargetList::TargetList(Debugger &debugger) CheckInWithManager(); } -// Destructor -TargetList::~TargetList() { - std::lock_guard guard(m_target_list_mutex); - m_target_list.clear(); -} - Status TargetList::CreateTarget(Debugger &debugger, llvm::StringRef user_exe_path, llvm::StringRef triple_str, LoadDependentFiles load_dependent_files, const OptionGroupPlatform *platform_options, TargetSP &target_sp) { - return CreateTargetInternal(debugger, user_exe_path, triple_str, - load_dependent_files, platform_options, target_sp, - false); + std::lock_guard guard(m_target_list_mutex); + auto result = TargetList::CreateTargetInternal( + debugger, user_exe_path, triple_str, load_dependent_files, + platform_options, target_sp); + + if (target_sp && result.Success()) + AddTargetInternal(target_sp, /*do_select*/ true); + return result; } Status TargetList::CreateTarget(Debugger &debugger, @@ -64,66 +63,73 @@ Status TargetList::CreateTarget(Debugger &debugger, const ArchSpec &specified_arch, LoadDependentFiles load_dependent_files, PlatformSP &platform_sp, TargetSP &target_sp) { - return CreateTargetInternal(debugger, user_exe_path, specified_arch, - load_dependent_files, platform_sp, target_sp, - false); + std::lock_guard guard(m_target_list_mutex); + auto result = TargetList::CreateTargetInternal( + debugger, user_exe_path, specified_arch, load_dependent_files, + platform_sp, target_sp); + + if (target_sp && result.Success()) + AddTargetInternal(target_sp, /*do_select*/ true); + return result; } Status TargetList::CreateTargetInternal( Debugger &debugger, llvm::StringRef user_exe_path, llvm::StringRef triple_str, LoadDependentFiles load_dependent_files, - const OptionGroupPlatform *platform_options, TargetSP &target_sp, - bool is_dummy_target) { + const OptionGroupPlatform *platform_options, TargetSP &target_sp) { Status error; - PlatformSP platform_sp; - // This is purposely left empty unless it is specified by triple_cstr. If not - // initialized via triple_cstr, then the currently selected platform will set - // the architecture correctly. + // Let's start by looking at the selected platform. + PlatformSP platform_sp = debugger.GetPlatformList().GetSelectedPlatform(); + + // This variable corresponds to the architecture specified by the triple + // string. If that string was empty the currently selected platform will + // determine the architecture. const ArchSpec arch(triple_str); - if (!triple_str.empty()) { - if (!arch.IsValid()) { - error.SetErrorStringWithFormat("invalid triple '%s'", - triple_str.str().c_str()); - return error; - } + if (!triple_str.empty() && !arch.IsValid()) { + error.SetErrorStringWithFormat("invalid triple '%s'", + triple_str.str().c_str()); + return error; } ArchSpec platform_arch(arch); - bool prefer_platform_arch = false; - - CommandInterpreter &interpreter = debugger.GetCommandInterpreter(); - - // let's see if there is already an existing platform before we go creating - // another... - platform_sp = debugger.GetPlatformList().GetSelectedPlatform(); + // Create a new platform if a platform was specified in the platform options + // and doesn't match the selected platform. + if (platform_options && platform_options->PlatformWasSpecified() && + !platform_options->PlatformMatches(platform_sp)) { + const bool select_platform = true; + platform_sp = platform_options->CreatePlatformWithOptions( + debugger.GetCommandInterpreter(), arch, select_platform, error, + platform_arch); + if (!platform_sp) + return error; + } - if (platform_options && platform_options->PlatformWasSpecified()) { - // Create a new platform if it doesn't match the selected platform - if (!platform_options->PlatformMatches(platform_sp)) { - const bool select_platform = true; - platform_sp = platform_options->CreatePlatformWithOptions( - interpreter, arch, select_platform, error, platform_arch); - if (!platform_sp) - return error; + bool prefer_platform_arch = false; + auto update_platform_arch = [&](const ArchSpec &module_arch) { + // If the OS or vendor weren't specified, then adopt the module's + // architecture so that the platform matching can be more accurate. + if (!platform_arch.TripleOSWasSpecified() || + !platform_arch.TripleVendorWasSpecified()) { + prefer_platform_arch = true; + platform_arch = module_arch; } - } + }; if (!user_exe_path.empty()) { - ModuleSpecList module_specs; - ModuleSpec module_spec; - module_spec.GetFileSpec().SetFile(user_exe_path, FileSpec::Style::native); + ModuleSpec module_spec(FileSpec(user_exe_path, FileSpec::Style::native)); FileSystem::Instance().Resolve(module_spec.GetFileSpec()); - // Resolve the executable in case we are given a path to a application - // bundle like a .app bundle on MacOSX + // bundle like a .app bundle on MacOSX. Host::ResolveExecutableInBundle(module_spec.GetFileSpec()); lldb::offset_t file_offset = 0; lldb::offset_t file_size = 0; + ModuleSpecList module_specs; const size_t num_specs = ObjectFile::GetModuleSpecifications( module_spec.GetFileSpec(), file_offset, file_size, module_specs); + if (num_specs > 0) { ModuleSpec matching_module_spec; @@ -134,12 +140,8 @@ Status TargetList::CreateTargetInternal( matching_module_spec.GetArchitecture())) { // If the OS or vendor weren't specified, then adopt the module's // architecture so that the platform matching can be more - // accurate - if (!platform_arch.TripleOSWasSpecified() || - !platform_arch.TripleVendorWasSpecified()) { - prefer_platform_arch = true; - platform_arch = matching_module_spec.GetArchitecture(); - } + // accurate. + update_platform_arch(matching_module_spec.GetArchitecture()); } else { StreamString platform_arch_strm; StreamString module_arch_strm; @@ -155,128 +157,119 @@ Status TargetList::CreateTargetInternal( return error; } } else { - // Only one arch and none was specified + // Only one arch and none was specified. prefer_platform_arch = true; platform_arch = matching_module_spec.GetArchitecture(); } } + } else if (arch.IsValid()) { + // Fat binary. A (valid) architecture was specified. + module_spec.GetArchitecture() = arch; + if (module_specs.FindMatchingModuleSpec(module_spec, + matching_module_spec)) + update_platform_arch(matching_module_spec.GetArchitecture()); } else { - if (arch.IsValid()) { - module_spec.GetArchitecture() = arch; - if (module_specs.FindMatchingModuleSpec(module_spec, - matching_module_spec)) { - prefer_platform_arch = true; - platform_arch = matching_module_spec.GetArchitecture(); - } - } else { - // No architecture specified, check if there is only one platform for - // all of the architectures. - - typedef std::vector PlatformList; - PlatformList platforms; - PlatformSP host_platform_sp = Platform::GetHostPlatform(); - for (size_t i = 0; i < num_specs; ++i) { - ModuleSpec module_spec; - if (module_specs.GetModuleSpecAtIndex(i, module_spec)) { - // See if there was a selected platform and check that first - // since the user may have specified it. - if (platform_sp) { - if (platform_sp->IsCompatibleArchitecture( - module_spec.GetArchitecture(), false, nullptr)) { - platforms.push_back(platform_sp); - continue; - } - } - - // Next check the host platform it if wasn't already checked - // above - if (host_platform_sp && - (!platform_sp || - host_platform_sp->GetName() != platform_sp->GetName())) { - if (host_platform_sp->IsCompatibleArchitecture( - module_spec.GetArchitecture(), false, nullptr)) { - platforms.push_back(host_platform_sp); - continue; - } + // Fat binary. No architecture specified, check if there is + // only one platform for all of the architectures. + PlatformSP host_platform_sp = Platform::GetHostPlatform(); + std::vector platforms; + for (size_t i = 0; i < num_specs; ++i) { + ModuleSpec module_spec; + if (module_specs.GetModuleSpecAtIndex(i, module_spec)) { + // First consider the platform specified by the user, if any, and + // the selected platform otherwise. + if (platform_sp) { + if (platform_sp->IsCompatibleArchitecture( + module_spec.GetArchitecture(), false, nullptr)) { + platforms.push_back(platform_sp); + continue; } + } - // Just find a platform that matches the architecture in the - // executable file - PlatformSP fallback_platform_sp( - Platform::GetPlatformForArchitecture( - module_spec.GetArchitecture(), nullptr)); - if (fallback_platform_sp) { - platforms.push_back(fallback_platform_sp); + // Now consider the host platform if it is different from the + // specified/selected platform. + if (host_platform_sp && + (!platform_sp || + host_platform_sp->GetName() != platform_sp->GetName())) { + if (host_platform_sp->IsCompatibleArchitecture( + module_spec.GetArchitecture(), false, nullptr)) { + platforms.push_back(host_platform_sp); + continue; } } - } - Platform *platform_ptr = nullptr; - bool more_than_one_platforms = false; - for (const auto &the_platform_sp : platforms) { - if (platform_ptr) { - if (platform_ptr->GetName() != the_platform_sp->GetName()) { - more_than_one_platforms = true; - platform_ptr = nullptr; - break; - } - } else { - platform_ptr = the_platform_sp.get(); + // Finally find a platform that matches the architecture in the + // executable file. + PlatformSP fallback_platform_sp( + Platform::GetPlatformForArchitecture( + module_spec.GetArchitecture(), nullptr)); + if (fallback_platform_sp) { + platforms.push_back(fallback_platform_sp); } } + } + Platform *platform_ptr = nullptr; + bool more_than_one_platforms = false; + for (const auto &the_platform_sp : platforms) { if (platform_ptr) { - // All platforms for all modules in the executable match, so we can - // select this platform - platform_sp = platforms.front(); - } else if (!more_than_one_platforms) { - // No platforms claim to support this file - error.SetErrorString("No matching platforms found for this file, " - "specify one with the --platform option"); - return error; + if (platform_ptr->GetName() != the_platform_sp->GetName()) { + more_than_one_platforms = true; + platform_ptr = nullptr; + break; + } } else { - // More than one platform claims to support this file, so the - // --platform option must be specified - StreamString error_strm; - std::set platform_set; - error_strm.Printf( - "more than one platform supports this executable ("); - for (const auto &the_platform_sp : platforms) { - if (platform_set.find(the_platform_sp.get()) == - platform_set.end()) { - if (!platform_set.empty()) - error_strm.PutCString(", "); - error_strm.PutCString(the_platform_sp->GetName().GetCString()); - platform_set.insert(the_platform_sp.get()); - } + platform_ptr = the_platform_sp.get(); + } + } + + if (platform_ptr) { + // All platforms for all modules in the executable match, so we can + // select this platform. + platform_sp = platforms.front(); + } else if (!more_than_one_platforms) { + // No platforms claim to support this file. + error.SetErrorString("no matching platforms found for this file"); + return error; + } else { + // More than one platform claims to support this file. + StreamString error_strm; + std::set platform_set; + error_strm.Printf( + "more than one platform supports this executable ("); + for (const auto &the_platform_sp : platforms) { + if (platform_set.find(the_platform_sp.get()) == + platform_set.end()) { + if (!platform_set.empty()) + error_strm.PutCString(", "); + error_strm.PutCString(the_platform_sp->GetName().GetCString()); + platform_set.insert(the_platform_sp.get()); } - error_strm.Printf( - "), use the --platform option to specify a platform"); - error.SetErrorString(error_strm.GetString()); - return error; } + error_strm.Printf("), specify an architecture to disambiguate"); + error.SetErrorString(error_strm.GetString()); + return error; } } } } // If we have a valid architecture, make sure the current platform is - // compatible with that architecture + // compatible with that architecture. if (!prefer_platform_arch && arch.IsValid()) { - if (!platform_sp->IsCompatibleArchitecture(arch, false, &platform_arch)) { + if (!platform_sp->IsCompatibleArchitecture(arch, false, nullptr)) { platform_sp = Platform::GetPlatformForArchitecture(arch, &platform_arch); - if (!is_dummy_target && platform_sp) + if (platform_sp) debugger.GetPlatformList().SetSelectedPlatform(platform_sp); } } else if (platform_arch.IsValid()) { - // if "arch" isn't valid, yet "platform_arch" is, it means we have an - // executable file with a single architecture which should be used + // If "arch" isn't valid, yet "platform_arch" is, it means we have an + // executable file with a single architecture which should be used. ArchSpec fixed_platform_arch; - if (!platform_sp->IsCompatibleArchitecture(platform_arch, false, - &fixed_platform_arch)) { + if (!platform_sp->IsCompatibleArchitecture(platform_arch, false, nullptr)) { platform_sp = Platform::GetPlatformForArchitecture(platform_arch, &fixed_platform_arch); - if (!is_dummy_target && platform_sp) + if (platform_sp) debugger.GetPlatformList().SetSelectedPlatform(platform_sp); } } @@ -284,32 +277,9 @@ Status TargetList::CreateTargetInternal( if (!platform_arch.IsValid()) platform_arch = arch; - error = TargetList::CreateTargetInternal( - debugger, user_exe_path, platform_arch, load_dependent_files, platform_sp, - target_sp, is_dummy_target); - return error; -} - -lldb::TargetSP TargetList::GetDummyTarget(lldb_private::Debugger &debugger) { - // FIXME: Maybe the dummy target should be per-Debugger - if (!m_dummy_target_sp || !m_dummy_target_sp->IsValid()) { - ArchSpec arch(Target::GetDefaultArchitecture()); - if (!arch.IsValid()) - arch = HostInfo::GetArchitecture(); - Status err = CreateDummyTarget( - debugger, arch.GetTriple().getTriple().c_str(), m_dummy_target_sp); - } - - return m_dummy_target_sp; -} - -Status TargetList::CreateDummyTarget(Debugger &debugger, - llvm::StringRef specified_arch_name, - lldb::TargetSP &target_sp) { - PlatformSP host_platform_sp(Platform::GetHostPlatform()); - return CreateTargetInternal( - debugger, (const char *)nullptr, specified_arch_name, eLoadDependentsNo, - (const OptionGroupPlatform *)nullptr, target_sp, true); + return TargetList::CreateTargetInternal(debugger, user_exe_path, + platform_arch, load_dependent_files, + platform_sp, target_sp); } Status TargetList::CreateTargetInternal(Debugger &debugger, @@ -317,13 +287,12 @@ Status TargetList::CreateTargetInternal(Debugger &debugger, const ArchSpec &specified_arch, LoadDependentFiles load_dependent_files, lldb::PlatformSP &platform_sp, - lldb::TargetSP &target_sp, - bool is_dummy_target) { - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer( - func_cat, "TargetList::CreateTarget (file = '%s', arch = '%s')", - user_exe_path.str().c_str(), specified_arch.GetArchitectureName()); + lldb::TargetSP &target_sp) { + LLDB_SCOPED_TIMERF("TargetList::CreateTarget (file = '%s', arch = '%s')", + user_exe_path.str().c_str(), + specified_arch.GetArchitectureName()); Status error; + const bool is_dummy_target = false; ArchSpec arch(specified_arch); @@ -407,117 +376,106 @@ Status TargetList::CreateTargetInternal(Debugger &debugger, target_sp.reset(new Target(debugger, arch, platform_sp, is_dummy_target)); } - if (target_sp) { - // Set argv0 with what the user typed, unless the user specified a - // directory. If the user specified a directory, then it is probably a - // bundle that was resolved and we need to use the resolved bundle path - if (!user_exe_path.empty()) { - // Use exactly what the user typed as the first argument when we exec or - // posix_spawn - if (user_exe_path_is_bundle && resolved_bundle_exe_path[0]) { - target_sp->SetArg0(resolved_bundle_exe_path); - } else { - // Use resolved path - target_sp->SetArg0(file.GetPath().c_str()); - } - } - if (file.GetDirectory()) { - FileSpec file_dir; - file_dir.GetDirectory() = file.GetDirectory(); - target_sp->AppendExecutableSearchPaths(file_dir); - } + if (!target_sp) + return error; - // Don't put the dummy target in the target list, it's held separately. - if (!is_dummy_target) { - std::lock_guard guard(m_target_list_mutex); - m_selected_target_idx = m_target_list.size(); - m_target_list.push_back(target_sp); - // Now prime this from the dummy target: - target_sp->PrimeFromDummyTarget(debugger.GetDummyTarget()); + // Set argv0 with what the user typed, unless the user specified a + // directory. If the user specified a directory, then it is probably a + // bundle that was resolved and we need to use the resolved bundle path + if (!user_exe_path.empty()) { + // Use exactly what the user typed as the first argument when we exec or + // posix_spawn + if (user_exe_path_is_bundle && resolved_bundle_exe_path[0]) { + target_sp->SetArg0(resolved_bundle_exe_path); } else { - m_dummy_target_sp = target_sp; + // Use resolved path + target_sp->SetArg0(file.GetPath().c_str()); } } + if (file.GetDirectory()) { + FileSpec file_dir; + file_dir.GetDirectory() = file.GetDirectory(); + target_sp->AppendExecutableSearchPaths(file_dir); + } + + // Now prime this from the dummy target: + target_sp->PrimeFromDummyTarget(debugger.GetDummyTarget()); return error; } bool TargetList::DeleteTarget(TargetSP &target_sp) { std::lock_guard guard(m_target_list_mutex); - collection::iterator pos, end = m_target_list.end(); + auto it = std::find(m_target_list.begin(), m_target_list.end(), target_sp); + if (it == m_target_list.end()) + return false; - for (pos = m_target_list.begin(); pos != end; ++pos) { - if (pos->get() == target_sp.get()) { - m_target_list.erase(pos); - return true; - } - } - return false; + m_target_list.erase(it); + return true; } TargetSP TargetList::FindTargetWithExecutableAndArchitecture( const FileSpec &exe_file_spec, const ArchSpec *exe_arch_ptr) const { std::lock_guard guard(m_target_list_mutex); - TargetSP target_sp; - collection::const_iterator pos, end = m_target_list.end(); - for (pos = m_target_list.begin(); pos != end; ++pos) { - Module *exe_module = (*pos)->GetExecutableModulePointer(); - - if (exe_module) { - if (FileSpec::Match(exe_file_spec, exe_module->GetFileSpec())) { - if (exe_arch_ptr) { - if (!exe_arch_ptr->IsCompatibleMatch(exe_module->GetArchitecture())) - continue; - } - target_sp = *pos; - break; - } - } - } - return target_sp; + auto it = std::find_if(m_target_list.begin(), m_target_list.end(), + [&exe_file_spec, exe_arch_ptr](const TargetSP &item) { + Module *exe_module = item->GetExecutableModulePointer(); + if (!exe_module || + !FileSpec::Match(exe_file_spec, exe_module->GetFileSpec())) + return false; + + return !exe_arch_ptr || + exe_arch_ptr->IsCompatibleMatch(exe_module->GetArchitecture()); + }); + + if (it != m_target_list.end()) + return *it; + + return TargetSP(); } TargetSP TargetList::FindTargetWithProcessID(lldb::pid_t pid) const { std::lock_guard guard(m_target_list_mutex); - TargetSP target_sp; - collection::const_iterator pos, end = m_target_list.end(); - for (pos = m_target_list.begin(); pos != end; ++pos) { - Process *process = (*pos)->GetProcessSP().get(); - if (process && process->GetID() == pid) { - target_sp = *pos; - break; - } - } - return target_sp; + auto it = std::find_if(m_target_list.begin(), m_target_list.end(), + [pid](const TargetSP &item) { + auto *process_ptr = item->GetProcessSP().get(); + return process_ptr && (process_ptr->GetID() == pid); + }); + + if (it != m_target_list.end()) + return *it; + + return TargetSP(); } TargetSP TargetList::FindTargetWithProcess(Process *process) const { TargetSP target_sp; - if (process) { - std::lock_guard guard(m_target_list_mutex); - collection::const_iterator pos, end = m_target_list.end(); - for (pos = m_target_list.begin(); pos != end; ++pos) { - if (process == (*pos)->GetProcessSP().get()) { - target_sp = *pos; - break; - } - } - } + if (!process) + return target_sp; + + std::lock_guard guard(m_target_list_mutex); + auto it = std::find_if(m_target_list.begin(), m_target_list.end(), + [process](const TargetSP &item) { + return item->GetProcessSP().get() == process; + }); + + if (it != m_target_list.end()) + target_sp = *it; + return target_sp; } TargetSP TargetList::GetTargetSP(Target *target) const { TargetSP target_sp; - if (target) { - std::lock_guard guard(m_target_list_mutex); - collection::const_iterator pos, end = m_target_list.end(); - for (pos = m_target_list.begin(); pos != end; ++pos) { - if (target == (*pos).get()) { - target_sp = *pos; - break; - } - } - } + if (!target) + return target_sp; + + std::lock_guard guard(m_target_list_mutex); + auto it = std::find_if(m_target_list.begin(), m_target_list.end(), + [target](const TargetSP &item) { return item.get() == target; }); + if (it != m_target_list.end()) + target_sp = *it; + return target_sp; } @@ -548,14 +506,11 @@ uint32_t TargetList::SignalIfRunning(lldb::pid_t pid, int signo) { if (pid == LLDB_INVALID_PROCESS_ID) { // Signal all processes with signal std::lock_guard guard(m_target_list_mutex); - collection::iterator pos, end = m_target_list.end(); - for (pos = m_target_list.begin(); pos != end; ++pos) { - process = (*pos)->GetProcessSP().get(); - if (process) { - if (process->IsAlive()) { - ++num_signals_sent; - process->Signal(signo); - } + for (const auto &target_sp : m_target_list) { + process = target_sp->GetProcessSP().get(); + if (process && process->IsAlive()) { + ++num_signals_sent; + process->Signal(signo); } } } else { @@ -563,11 +518,9 @@ uint32_t TargetList::SignalIfRunning(lldb::pid_t pid, int signo) { TargetSP target_sp(FindTargetWithProcessID(pid)); if (target_sp) { process = target_sp->GetProcessSP().get(); - if (process) { - if (process->IsAlive()) { - ++num_signals_sent; - process->Signal(signo); - } + if (process && process->IsAlive()) { + ++num_signals_sent; + process->Signal(signo); } } } @@ -589,26 +542,35 @@ lldb::TargetSP TargetList::GetTargetAtIndex(uint32_t idx) const { uint32_t TargetList::GetIndexOfTarget(lldb::TargetSP target_sp) const { std::lock_guard guard(m_target_list_mutex); - size_t num_targets = m_target_list.size(); - for (size_t idx = 0; idx < num_targets; idx++) { - if (target_sp == m_target_list[idx]) - return idx; - } + auto it = std::find(m_target_list.begin(), m_target_list.end(), target_sp); + if (it != m_target_list.end()) + return std::distance(m_target_list.begin(), it); return UINT32_MAX; } -uint32_t TargetList::SetSelectedTarget(Target *target) { +void TargetList::AddTargetInternal(TargetSP target_sp, bool do_select) { + lldbassert(std::find(m_target_list.begin(), m_target_list.end(), target_sp) == + m_target_list.end() && + "target already exists it the list"); + m_target_list.push_back(std::move(target_sp)); + if (do_select) + SetSelectedTargetInternal(m_target_list.size() - 1); +} + +void TargetList::SetSelectedTargetInternal(uint32_t index) { + lldbassert(!m_target_list.empty()); + m_selected_target_idx = index < m_target_list.size() ? index : 0; +} + +void TargetList::SetSelectedTarget(uint32_t index) { std::lock_guard guard(m_target_list_mutex); - collection::const_iterator pos, begin = m_target_list.begin(), - end = m_target_list.end(); - for (pos = begin; pos != end; ++pos) { - if (pos->get() == target) { - m_selected_target_idx = std::distance(begin, pos); - return m_selected_target_idx; - } - } - m_selected_target_idx = 0; - return m_selected_target_idx; + SetSelectedTargetInternal(index); +} + +void TargetList::SetSelectedTarget(const TargetSP &target_sp) { + std::lock_guard guard(m_target_list_mutex); + auto it = std::find(m_target_list.begin(), m_target_list.end(), target_sp); + SetSelectedTargetInternal(std::distance(m_target_list.begin(), it)); } lldb::TargetSP TargetList::GetSelectedTarget() { diff --git a/gnu/llvm/lldb/source/Target/TargetProperties.td b/gnu/llvm/lldb/source/Target/TargetProperties.td index ae3abe35485..8f627ad0f1a 100644 --- a/gnu/llvm/lldb/source/Target/TargetProperties.td +++ b/gnu/llvm/lldb/source/Target/TargetProperties.td @@ -20,6 +20,10 @@ let Definition = "target" in { def ExprPrefix: Property<"expr-prefix", "FileSpec">, DefaultStringValue<"">, Desc<"Path to a file containing expressions to be prepended to all expressions.">; + def ExprErrorLimit: Property<"expr-error-limit", "UInt64">, + DefaultUnsignedValue<5>, + Desc<"The maximum amount of errors to emit while parsing an expression. " + "A value of 0 means to always continue parsing if possible.">; def PreferDynamic: Property<"prefer-dynamic-value", "Enum">, DefaultEnumValue<"eDynamicDontRunTarget">, EnumValues<"OptionEnumValues(g_dynamic_value_types)">, @@ -32,7 +36,7 @@ let Definition = "target" in { Desc<"Skip function prologues when setting breakpoints by name.">; def SourceMap: Property<"source-map", "PathMap">, DefaultStringValue<"">, - Desc<"Source path remappings are used to track the change of location between a source file when built, and where it exists on the current system. It consists of an array of duples, the first element of each duple is some part (starting at the root) of the path to the file when it was built, and the second is where the remainder of the original build hierarchy is rooted on the local system. Each element of the array is checked in order and the first one that results in a match wins.">; + Desc<"Source path remappings apply substitutions to the paths of source files, typically needed to debug from a different host than the one that built the target. The source-map property consists of an array of pairs, the first element is a path prefix, and the second is its replacement. The syntax is `prefix1 replacement1 prefix2 replacement2...`. The pairs are checked in order, the first prefix that matches is used, and that prefix is substituted with the replacement. A common pattern is to use source-map in conjunction with the clang -fdebug-prefix-map flag. In the build, use `-fdebug-prefix-map=/path/to/build_dir=.` to rewrite the host specific build directory to `.`. Then for debugging, use `settings set target.source-map . /path/to/local_dir` to convert `.` to a valid local path.">; def ExecutableSearchPaths: Property<"exec-search-paths", "FileSpecList">, DefaultStringValue<"">, Desc<"Executable search paths to use when locating executable files whose paths don't match the local file system.">; @@ -45,9 +49,11 @@ let Definition = "target" in { def AutoImportClangModules: Property<"auto-import-clang-modules", "Boolean">, DefaultTrue, Desc<"Automatically load Clang modules referred to by the program.">; - def ImportStdModule: Property<"import-std-module", "Boolean">, - DefaultFalse, - Desc<"Import the C++ std module to improve debugging STL containers.">; + def ImportStdModule: Property<"import-std-module", "Enum">, + DefaultEnumValue<"eImportStdModuleFalse">, + EnumValues<"OptionEnumValues(g_import_std_module_value_types)">, + Desc<"Import the 'std' C++ module to improve expression parsing involving " + " C++ standard library types.">; def AutoApplyFixIts: Property<"auto-apply-fixits", "Boolean">, DefaultTrue, Desc<"Automatically apply fix-it hints to expressions.">; @@ -111,6 +117,9 @@ let Definition = "target" in { def DisableSTDIO: Property<"disable-stdio", "Boolean">, DefaultFalse, Desc<"Disable stdin/stdout for process (e.g. for a GUI application)">; + def InheritTCC: Property<"inherit-tcc", "Boolean">, + DefaultFalse, + Desc<"Inherit the TCC permissions from the inferior's parent instead of making the process itself responsible.">; def InlineStrategy: Property<"inline-breakpoint-strategy", "Enum">, DefaultEnumValue<"eInlineBreakpointsAlways">, EnumValues<"OptionEnumValues(g_inline_breakpoint_enums)">, @@ -163,6 +172,9 @@ let Definition = "target" in { def AutoInstallMainExecutable: Property<"auto-install-main-executable", "Boolean">, DefaultTrue, Desc<"Always install the main executable when connected to a remote platform.">; + def DebugUtilityExpression: Property<"debug-utility-expression", "Boolean">, + DefaultFalse, + Desc<"Enable debugging of LLDB-internal utility expressions.">; } let Definition = "process_experimental" in { @@ -194,6 +206,10 @@ let Definition = "process" in { Global, DefaultFalse, Desc<"If true, stop when a shared library is loaded or unloaded.">; + def DisableLangRuntimeUnwindPlans: Property<"disable-language-runtime-unwindplans", "Boolean">, + Global, + DefaultFalse, + Desc<"If true, LanguageRuntime plugins' UnwindPlans will not be used when backtracing.">; def DetachKeepsStopped: Property<"detach-keeps-stopped", "Boolean">, Global, DefaultFalse, @@ -214,6 +230,15 @@ let Definition = "process" in { def UtilityExpressionTimeout: Property<"utility-expression-timeout", "UInt64">, DefaultUnsignedValue<15>, Desc<"The time in seconds to wait for LLDB-internal utility expressions.">; + def InterruptTimeout: Property<"interrupt-timeout", "UInt64">, + DefaultUnsignedValue<20>, + Desc<"The time in seconds to wait for an interrupt succeed in stopping the target.">; + def SteppingRunsAllThreads: Property<"run-all-threads", "Boolean">, + DefaultFalse, + Desc<"If true, stepping operations will run all threads. This is equivalent to setting the run-mode option to 'all-threads'.">; + def VirtualAddressableBits: Property<"virtual-addressable-bits", "UInt64">, + DefaultUnsignedValue<0>, + Desc<"The number of bits used for addressing. If the value is 39, then bits 0..38 are used for addressing. The default value of 0 means unspecified.">; } let Definition = "platform" in { diff --git a/gnu/llvm/lldb/source/Target/Thread.cpp b/gnu/llvm/lldb/source/Target/Thread.cpp index 24cf4bf3ee1..b423f1b5f1f 100644 --- a/gnu/llvm/lldb/source/Target/Thread.cpp +++ b/gnu/llvm/lldb/source/Target/Thread.cpp @@ -71,16 +71,10 @@ enum { #include "TargetPropertiesEnum.inc" }; -class ThreadOptionValueProperties : public OptionValueProperties { +class ThreadOptionValueProperties + : public Cloneable { public: - ThreadOptionValueProperties(ConstString name) - : OptionValueProperties(name) {} - - // This constructor is used when creating ThreadOptionValueProperties when it - // is part of a new lldb_private::Thread instance. It will copy all current - // global property values as needed - ThreadOptionValueProperties(ThreadProperties *global_properties) - : OptionValueProperties(*global_properties->GetValueProperties()) {} + ThreadOptionValueProperties(ConstString name) : Cloneable(name) {} const Property *GetPropertyAtIndex(const ExecutionContext *exe_ctx, bool will_modify, @@ -108,8 +102,8 @@ ThreadProperties::ThreadProperties(bool is_global) : Properties() { std::make_shared(ConstString("thread")); m_collection_sp->Initialize(g_thread_properties); } else - m_collection_sp = std::make_shared( - Thread::GetGlobalProperties().get()); + m_collection_sp = + OptionValueProperties::CreateLocalCopy(*Thread::GetGlobalProperties()); } ThreadProperties::~ThreadProperties() = default; @@ -530,7 +524,7 @@ bool Thread::RestoreRegisterStateFromCheckpoint( return false; } -bool Thread::RestoreThreadStateFromCheckpoint( +void Thread::RestoreThreadStateFromCheckpoint( ThreadStateCheckpoint &saved_state) { if (saved_state.stop_info_sp) saved_state.stop_info_sp->MakeStopInfoValid(); @@ -539,7 +533,6 @@ bool Thread::RestoreThreadStateFromCheckpoint( saved_state.current_inlined_depth); GetPlans().RestoreCompletedPlanCheckpoint( saved_state.m_completed_plan_checkpoint); - return true; } StateType Thread::GetState() const { @@ -830,6 +823,8 @@ bool Thread::ShouldStop(Event *event_ptr) { ThreadPlan *plan_ptr = current_plan; while ((plan_ptr = GetPreviousPlan(plan_ptr)) != nullptr) { if (plan_ptr->PlanExplainsStop(event_ptr)) { + LLDB_LOGF(log, "Plan %s explains stop.", plan_ptr->GetName()); + should_stop = plan_ptr->ShouldStop(event_ptr); // plan_ptr explains the stop, next check whether plan_ptr is done, @@ -861,10 +856,7 @@ bool Thread::ShouldStop(Event *event_ptr) { } if (!done_processing_current_plan) { - bool over_ride_stop = current_plan->ShouldAutoContinue(event_ptr); - - LLDB_LOGF(log, "Plan %s explains stop, auto-continue %i.", - current_plan->GetName(), over_ride_stop); + bool override_stop = false; // We're starting from the base plan, so just let it decide; if (current_plan->IsBasePlan()) { @@ -885,20 +877,24 @@ bool Thread::ShouldStop(Event *event_ptr) { if (should_stop) current_plan->WillStop(); - // If a Master Plan wants to stop, and wants to stick on the stack, - // we let it. Otherwise, see if the plan's parent wants to stop. + if (current_plan->ShouldAutoContinue(event_ptr)) { + override_stop = true; + LLDB_LOGF(log, "Plan %s auto-continue: true.", + current_plan->GetName()); + } + + // If a Master Plan wants to stop, we let it. Otherwise, see if the + // plan's parent wants to stop. + PopPlan(); if (should_stop && current_plan->IsMasterPlan() && !current_plan->OkayToDiscard()) { - PopPlan(); break; - } else { - PopPlan(); + } - current_plan = GetCurrentPlan(); - if (current_plan == nullptr) { - break; - } + current_plan = GetCurrentPlan(); + if (current_plan == nullptr) { + break; } } else { break; @@ -906,7 +902,7 @@ bool Thread::ShouldStop(Event *event_ptr) { } } - if (over_ride_stop) + if (override_stop) should_stop = false; } @@ -1103,6 +1099,22 @@ void Thread::DiscardPlan() { discarded_plan_sp->GetThread().GetID()); } +void Thread::AutoCompleteThreadPlans(CompletionRequest &request) const { + const ThreadPlanStack &plans = GetPlans(); + if (!plans.AnyPlans()) + return; + + // Iterate from the second plan (index: 1) to skip the base plan. + ThreadPlanSP p; + uint32_t i = 1; + while ((p = plans.GetPlanByIndex(i, false))) { + StreamString strm; + p->GetDescription(&strm, eDescriptionLevelInitial); + request.TryCompleteCurrentArg(std::to_string(i), strm.GetString()); + i++; + } +} + ThreadPlan *Thread::GetCurrentPlan() const { return GetPlans().GetCurrentPlan().get(); } @@ -1165,14 +1177,6 @@ Status Thread::QueueThreadPlan(ThreadPlanSP &thread_plan_sp, return status; } -void Thread::EnableTracer(bool value, bool single_stepping) { - GetPlans().EnableTracer(value, single_stepping); -} - -void Thread::SetTracer(lldb::ThreadPlanTracerSP &tracer_sp) { - GetPlans().SetTracer(tracer_sp); -} - bool Thread::DiscardUserThreadPlansUpToIndex(uint32_t plan_index) { // Count the user thread plans from the back end to get the number of the one // we want to discard: @@ -1225,7 +1229,7 @@ Status Thread::UnwindInnermostExpression() { return error; } -ThreadPlanSP Thread::QueueFundamentalPlan(bool abort_other_plans) { +ThreadPlanSP Thread::QueueBasePlan(bool abort_other_plans) { ThreadPlanSP thread_plan_sp(new ThreadPlanBase(*this)); QueueThreadPlan(thread_plan_sp, abort_other_plans); return thread_plan_sp; @@ -1273,16 +1277,10 @@ ThreadPlanSP Thread::QueueThreadPlanForStepInRange( lldb::RunMode stop_other_threads, Status &status, LazyBool step_in_avoids_code_without_debug_info, LazyBool step_out_avoids_code_without_debug_info) { - ThreadPlanSP thread_plan_sp( - new ThreadPlanStepInRange(*this, range, addr_context, stop_other_threads, - step_in_avoids_code_without_debug_info, - step_out_avoids_code_without_debug_info)); - ThreadPlanStepInRange *plan = - static_cast(thread_plan_sp.get()); - - if (step_in_target) - plan->SetStepInTarget(step_in_target); - + ThreadPlanSP thread_plan_sp(new ThreadPlanStepInRange( + *this, range, addr_context, step_in_target, stop_other_threads, + step_in_avoids_code_without_debug_info, + step_out_avoids_code_without_debug_info)); status = QueueThreadPlan(thread_plan_sp, abort_other_plans); return thread_plan_sp; } @@ -1305,11 +1303,12 @@ ThreadPlanSP Thread::QueueThreadPlanForStepInRange( ThreadPlanSP Thread::QueueThreadPlanForStepOut( bool abort_other_plans, SymbolContext *addr_context, bool first_insn, - bool stop_other_threads, Vote stop_vote, Vote run_vote, uint32_t frame_idx, - Status &status, LazyBool step_out_avoids_code_without_debug_info) { + bool stop_other_threads, Vote report_stop_vote, Vote report_run_vote, + uint32_t frame_idx, Status &status, + LazyBool step_out_avoids_code_without_debug_info) { ThreadPlanSP thread_plan_sp(new ThreadPlanStepOut( - *this, addr_context, first_insn, stop_other_threads, stop_vote, run_vote, - frame_idx, step_out_avoids_code_without_debug_info)); + *this, addr_context, first_insn, stop_other_threads, report_stop_vote, + report_run_vote, frame_idx, step_out_avoids_code_without_debug_info)); status = QueueThreadPlan(thread_plan_sp, abort_other_plans); return thread_plan_sp; @@ -1317,13 +1316,14 @@ ThreadPlanSP Thread::QueueThreadPlanForStepOut( ThreadPlanSP Thread::QueueThreadPlanForStepOutNoShouldStop( bool abort_other_plans, SymbolContext *addr_context, bool first_insn, - bool stop_other_threads, Vote stop_vote, Vote run_vote, uint32_t frame_idx, - Status &status, bool continue_to_next_branch) { + bool stop_other_threads, Vote report_stop_vote, Vote report_run_vote, + uint32_t frame_idx, Status &status, bool continue_to_next_branch) { const bool calculate_return_value = false; // No need to calculate the return value here. ThreadPlanSP thread_plan_sp(new ThreadPlanStepOut( - *this, addr_context, first_insn, stop_other_threads, stop_vote, run_vote, - frame_idx, eLazyBoolNo, continue_to_next_branch, calculate_return_value)); + *this, addr_context, first_insn, stop_other_threads, report_stop_vote, + report_run_vote, frame_idx, eLazyBoolNo, continue_to_next_branch, + calculate_return_value)); ThreadPlanStepOut *new_plan = static_cast(thread_plan_sp.get()); @@ -1380,7 +1380,7 @@ lldb::ThreadPlanSP Thread::QueueThreadPlanForStepScripted( ThreadPlanSP thread_plan_sp(new ThreadPlanPython(*this, class_name, extra_args_impl)); - + thread_plan_sp->SetStopOthers(stop_other_threads); status = QueueThreadPlan(thread_plan_sp, abort_other_plans); return thread_plan_sp; } @@ -1661,7 +1661,7 @@ Thread::GetStackFrameSPForStackFramePtr(StackFrame *stack_frame_ptr) { return GetStackFrameList()->GetStackFrameSPForStackFramePtr(stack_frame_ptr); } -const char *Thread::StopReasonAsCString(lldb::StopReason reason) { +std::string Thread::StopReasonAsString(lldb::StopReason reason) { switch (reason) { case eStopReasonInvalid: return "invalid"; @@ -1679,21 +1679,26 @@ const char *Thread::StopReasonAsCString(lldb::StopReason reason) { return "exception"; case eStopReasonExec: return "exec"; + case eStopReasonFork: + return "fork"; + case eStopReasonVFork: + return "vfork"; + case eStopReasonVForkDone: + return "vfork done"; case eStopReasonPlanComplete: return "plan complete"; case eStopReasonThreadExiting: return "thread exiting"; case eStopReasonInstrumentation: return "instrumentation break"; + case eStopReasonProcessorTrace: + return "processor trace"; } - static char unknown_state_string[64]; - snprintf(unknown_state_string, sizeof(unknown_state_string), - "StopReason = %i", reason); - return unknown_state_string; + return "StopReason = " + std::to_string(reason); } -const char *Thread::RunModeAsCString(lldb::RunMode mode) { +std::string Thread::RunModeAsString(lldb::RunMode mode) { switch (mode) { case eOnlyThisThread: return "only this thread"; @@ -1703,10 +1708,7 @@ const char *Thread::RunModeAsCString(lldb::RunMode mode) { return "only during stepping"; } - static char unknown_state_string[64]; - snprintf(unknown_state_string, sizeof(unknown_state_string), "RunMode = %i", - mode); - return unknown_state_string; + return "RunMode = " + std::to_string(mode); } size_t Thread::GetStatus(Stream &strm, uint32_t start_frame, diff --git a/gnu/llvm/lldb/source/Target/ThreadCollection.cpp b/gnu/llvm/lldb/source/Target/ThreadCollection.cpp index 05b041c20dd..8c2309795a4 100644 --- a/gnu/llvm/lldb/source/Target/ThreadCollection.cpp +++ b/gnu/llvm/lldb/source/Target/ThreadCollection.cpp @@ -5,7 +5,7 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// -#include +#include #include #include diff --git a/gnu/llvm/lldb/source/Target/ThreadList.cpp b/gnu/llvm/lldb/source/Target/ThreadList.cpp index 032dcc9e5fb..df2cc8ef632 100644 --- a/gnu/llvm/lldb/source/Target/ThreadList.cpp +++ b/gnu/llvm/lldb/source/Target/ThreadList.cpp @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// -#include +#include #include diff --git a/gnu/llvm/lldb/source/Target/ThreadPlan.cpp b/gnu/llvm/lldb/source/Target/ThreadPlan.cpp index d8e92b8fd0d..6b55f3912d1 100644 --- a/gnu/llvm/lldb/source/Target/ThreadPlan.cpp +++ b/gnu/llvm/lldb/source/Target/ThreadPlan.cpp @@ -20,9 +20,9 @@ using namespace lldb_private; // ThreadPlan constructor ThreadPlan::ThreadPlan(ThreadPlanKind kind, const char *name, Thread &thread, - Vote stop_vote, Vote run_vote) + Vote report_stop_vote, Vote report_run_vote) : m_process(*thread.GetProcess().get()), m_tid(thread.GetID()), - m_stop_vote(stop_vote), m_run_vote(run_vote), + m_report_stop_vote(report_stop_vote), m_report_run_vote(report_run_vote), m_takes_iteration_count(false), m_could_not_resolve_hw_bp(false), m_thread(&thread), m_kind(kind), m_name(name), m_plan_complete_mutex(), m_cached_plan_explains_stop(eLazyBoolCalculate), m_plan_complete(false), @@ -50,7 +50,7 @@ Thread &ThreadPlan::GetThread() { bool ThreadPlan::PlanExplainsStop(Event *event_ptr) { if (m_cached_plan_explains_stop == eLazyBoolCalculate) { bool actual_value = DoPlanExplainsStop(event_ptr); - m_cached_plan_explains_stop = actual_value ? eLazyBoolYes : eLazyBoolNo; + CachePlanExplainsStop(actual_value); return actual_value; } else { return m_cached_plan_explains_stop == eLazyBoolYes; @@ -78,7 +78,7 @@ bool ThreadPlan::MischiefManaged() { Vote ThreadPlan::ShouldReportStop(Event *event_ptr) { Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); - if (m_stop_vote == eVoteNoOpinion) { + if (m_report_stop_vote == eVoteNoOpinion) { ThreadPlan *prev_plan = GetPreviousPlan(); if (prev_plan) { Vote prev_vote = prev_plan->ShouldReportStop(event_ptr); @@ -86,19 +86,21 @@ Vote ThreadPlan::ShouldReportStop(Event *event_ptr) { return prev_vote; } } - LLDB_LOG(log, "Returning vote: {0}", m_stop_vote); - return m_stop_vote; + LLDB_LOG(log, "Returning vote: {0}", m_report_stop_vote); + return m_report_stop_vote; } Vote ThreadPlan::ShouldReportRun(Event *event_ptr) { - if (m_run_vote == eVoteNoOpinion) { + if (m_report_run_vote == eVoteNoOpinion) { ThreadPlan *prev_plan = GetPreviousPlan(); if (prev_plan) return prev_plan->ShouldReportRun(event_ptr); } - return m_run_vote; + return m_report_run_vote; } +void ThreadPlan::ClearThreadCache() { m_thread = nullptr; } + bool ThreadPlan::StopOthers() { ThreadPlan *prev_plan; prev_plan = GetPreviousPlan(); @@ -134,7 +136,7 @@ bool ThreadPlan::WillResume(StateType resume_state, bool current_plan) { } } bool success = DoWillResume(resume_state, current_plan); - m_thread = nullptr; // We don't cache the thread pointer over resumes. This + ClearThreadCache(); // We don't cache the thread pointer over resumes. This // Thread might go away, and another Thread represent // the same underlying object on a later stop. return success; @@ -154,8 +156,7 @@ bool ThreadPlan::OkayToDiscard() { } lldb::StateType ThreadPlan::RunState() { - if (m_tracer_sp && m_tracer_sp->TracingEnabled() && - m_tracer_sp->SingleStepEnabled()) + if (m_tracer_sp && m_tracer_sp->TracingEnabled()) return eStateStepping; else return GetPlanRunState(); diff --git a/gnu/llvm/lldb/source/Target/ThreadPlanBase.cpp b/gnu/llvm/lldb/source/Target/ThreadPlanBase.cpp index 650393d678e..c6c4d97c165 100644 --- a/gnu/llvm/lldb/source/Target/ThreadPlanBase.cpp +++ b/gnu/llvm/lldb/source/Target/ThreadPlanBase.cpp @@ -43,7 +43,7 @@ ThreadPlanBase::ThreadPlanBase(Thread &thread) SetIsMasterPlan(true); } -ThreadPlanBase::~ThreadPlanBase() {} +ThreadPlanBase::~ThreadPlanBase() = default; void ThreadPlanBase::GetDescription(Stream *s, lldb::DescriptionLevel level) { s->Printf("Base thread plan."); @@ -70,8 +70,8 @@ Vote ThreadPlanBase::ShouldReportStop(Event *event_ptr) { } bool ThreadPlanBase::ShouldStop(Event *event_ptr) { - m_stop_vote = eVoteYes; - m_run_vote = eVoteYes; + m_report_stop_vote = eVoteYes; + m_report_run_vote = eVoteYes; Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); @@ -82,8 +82,8 @@ bool ThreadPlanBase::ShouldStop(Event *event_ptr) { case eStopReasonInvalid: case eStopReasonNone: // This - m_run_vote = eVoteNoOpinion; - m_stop_vote = eVoteNo; + m_report_run_vote = eVoteNoOpinion; + m_report_stop_vote = eVoteNo; return false; case eStopReasonBreakpoint: @@ -106,11 +106,11 @@ bool ThreadPlanBase::ShouldStop(Event *event_ptr) { // with "restarted" so the UI will know to wait and expect the consequent // "running". if (stop_info_sp->ShouldNotify(event_ptr)) { - m_stop_vote = eVoteYes; - m_run_vote = eVoteYes; + m_report_stop_vote = eVoteYes; + m_report_run_vote = eVoteYes; } else { - m_stop_vote = eVoteNo; - m_run_vote = eVoteNo; + m_report_stop_vote = eVoteNo; + m_report_run_vote = eVoteNo; } return false; @@ -156,9 +156,9 @@ bool ThreadPlanBase::ShouldStop(Event *event_ptr) { // We're not going to stop, but while we are here, let's figure out // whether to report this. if (stop_info_sp->ShouldNotify(event_ptr)) - m_stop_vote = eVoteYes; + m_report_stop_vote = eVoteYes; else - m_stop_vote = eVoteNo; + m_report_stop_vote = eVoteNo; } return false; @@ -167,8 +167,8 @@ bool ThreadPlanBase::ShouldStop(Event *event_ptr) { } } else { - m_run_vote = eVoteNoOpinion; - m_stop_vote = eVoteNo; + m_report_run_vote = eVoteNoOpinion; + m_report_stop_vote = eVoteNo; } // If there's no explicit reason to stop, then we will continue. @@ -185,8 +185,8 @@ bool ThreadPlanBase::DoWillResume(lldb::StateType resume_state, bool current_plan) { // Reset these to the default values so we don't set them wrong, then not get // asked for a while, then return the wrong answer. - m_run_vote = eVoteNoOpinion; - m_stop_vote = eVoteNo; + m_report_run_vote = eVoteNoOpinion; + m_report_stop_vote = eVoteNo; return true; } diff --git a/gnu/llvm/lldb/source/Target/ThreadPlanCallFunction.cpp b/gnu/llvm/lldb/source/Target/ThreadPlanCallFunction.cpp index dbe26f42c9b..3699a507d05 100644 --- a/gnu/llvm/lldb/source/Target/ThreadPlanCallFunction.cpp +++ b/gnu/llvm/lldb/source/Target/ThreadPlanCallFunction.cpp @@ -260,9 +260,9 @@ bool ThreadPlanCallFunction::DoPlanExplainsStop(Event *event_ptr) { stop_reason = eStopReasonNone; else stop_reason = m_real_stop_info_sp->GetStopReason(); - LLDB_LOGF(log, - "ThreadPlanCallFunction::PlanExplainsStop: Got stop reason - %s.", - Thread::StopReasonAsCString(stop_reason)); + LLDB_LOG(log, + "ThreadPlanCallFunction::PlanExplainsStop: Got stop reason - {0}.", + Thread::StopReasonAsString(stop_reason)); if (stop_reason == eStopReasonBreakpoint && BreakpointsExplainStop()) return true; @@ -454,8 +454,8 @@ void ThreadPlanCallFunction::SetStopOthers(bool new_value) { m_subplan_sp->SetStopOthers(new_value); } -bool ThreadPlanCallFunction::RestoreThreadState() { - return GetThread().RestoreThreadStateFromCheckpoint(m_stored_thread_state); +void ThreadPlanCallFunction::RestoreThreadState() { + GetThread().RestoreThreadStateFromCheckpoint(m_stored_thread_state); } void ThreadPlanCallFunction::SetReturnValue() { diff --git a/gnu/llvm/lldb/source/Target/ThreadPlanCallUserExpression.cpp b/gnu/llvm/lldb/source/Target/ThreadPlanCallUserExpression.cpp index 00b01c76d90..9dddd850b6a 100644 --- a/gnu/llvm/lldb/source/Target/ThreadPlanCallUserExpression.cpp +++ b/gnu/llvm/lldb/source/Target/ThreadPlanCallUserExpression.cpp @@ -43,7 +43,7 @@ ThreadPlanCallUserExpression::ThreadPlanCallUserExpression( SetOkayToDiscard(false); } -ThreadPlanCallUserExpression::~ThreadPlanCallUserExpression() {} +ThreadPlanCallUserExpression::~ThreadPlanCallUserExpression() = default; void ThreadPlanCallUserExpression::GetDescription( Stream *s, lldb::DescriptionLevel level) { diff --git a/gnu/llvm/lldb/source/Target/ThreadPlanPython.cpp b/gnu/llvm/lldb/source/Target/ThreadPlanPython.cpp index 8171186319f..e83f0e9e715 100644 --- a/gnu/llvm/lldb/source/Target/ThreadPlanPython.cpp +++ b/gnu/llvm/lldb/source/Target/ThreadPlanPython.cpp @@ -25,11 +25,12 @@ using namespace lldb_private; // ThreadPlanPython -ThreadPlanPython::ThreadPlanPython(Thread &thread, const char *class_name, +ThreadPlanPython::ThreadPlanPython(Thread &thread, const char *class_name, StructuredDataImpl *args_data) : ThreadPlan(ThreadPlan::eKindPython, "Python based Thread Plan", thread, eVoteNoOpinion, eVoteNoOpinion), - m_class_name(class_name), m_args_data(args_data), m_did_push(false) { + m_class_name(class_name), m_args_data(args_data), m_did_push(false), + m_stop_others(false) { SetIsMasterPlan(true); SetOkayToDiscard(true); SetPrivate(false); @@ -162,13 +163,6 @@ lldb::StateType ThreadPlanPython::GetPlanRunState() { } // The ones below are not currently exported to Python. - -bool ThreadPlanPython::StopOthers() { - // For now Python plans run all threads, but we should add some controls for - // this. - return false; -} - void ThreadPlanPython::GetDescription(Stream *s, lldb::DescriptionLevel level) { s->Printf("Python thread plan implemented by class %s.", m_class_name.c_str()); diff --git a/gnu/llvm/lldb/source/Target/ThreadPlanStack.cpp b/gnu/llvm/lldb/source/Target/ThreadPlanStack.cpp index 1cfc41dcd39..d25602d25b9 100644 --- a/gnu/llvm/lldb/source/Target/ThreadPlanStack.cpp +++ b/gnu/llvm/lldb/source/Target/ThreadPlanStack.cpp @@ -39,6 +39,7 @@ ThreadPlanStack::ThreadPlanStack(const Thread &thread, bool make_null) { void ThreadPlanStack::DumpThreadPlans(Stream &s, lldb::DescriptionLevel desc_level, bool include_internal) const { + std::lock_guard guard(m_stack_mutex); s.IndentMore(); PrintOneStack(s, "Active plan stack", m_plans, desc_level, include_internal); PrintOneStack(s, "Completed plan stack", m_completed_plans, desc_level, @@ -52,6 +53,7 @@ void ThreadPlanStack::PrintOneStack(Stream &s, llvm::StringRef stack_name, const PlanStack &stack, lldb::DescriptionLevel desc_level, bool include_internal) const { + std::lock_guard guard(m_stack_mutex); // If the stack is empty, just exit: if (stack.empty()) return; @@ -80,6 +82,7 @@ void ThreadPlanStack::PrintOneStack(Stream &s, llvm::StringRef stack_name, } size_t ThreadPlanStack::CheckpointCompletedPlans() { + std::lock_guard guard(m_stack_mutex); m_completed_plan_checkpoint++; m_completed_plan_store.insert( std::make_pair(m_completed_plan_checkpoint, m_completed_plans)); @@ -87,6 +90,7 @@ size_t ThreadPlanStack::CheckpointCompletedPlans() { } void ThreadPlanStack::RestoreCompletedPlanCheckpoint(size_t checkpoint) { + std::lock_guard guard(m_stack_mutex); auto result = m_completed_plan_store.find(checkpoint); assert(result != m_completed_plan_store.end() && "Asked for a checkpoint that didn't exist"); @@ -95,11 +99,13 @@ void ThreadPlanStack::RestoreCompletedPlanCheckpoint(size_t checkpoint) { } void ThreadPlanStack::DiscardCompletedPlanCheckpoint(size_t checkpoint) { + std::lock_guard guard(m_stack_mutex); m_completed_plan_store.erase(checkpoint); } void ThreadPlanStack::ThreadDestroyed(Thread *thread) { // Tell the plan stacks that this thread is going away: + std::lock_guard guard(m_stack_mutex); for (ThreadPlanSP plan : m_plans) plan->ThreadDestroyed(); @@ -124,24 +130,11 @@ void ThreadPlanStack::ThreadDestroyed(Thread *thread) { } } -void ThreadPlanStack::EnableTracer(bool value, bool single_stepping) { - for (ThreadPlanSP plan : m_plans) { - if (plan->GetThreadPlanTracer()) { - plan->GetThreadPlanTracer()->EnableTracing(value); - plan->GetThreadPlanTracer()->EnableSingleStep(single_stepping); - } - } -} - -void ThreadPlanStack::SetTracer(lldb::ThreadPlanTracerSP &tracer_sp) { - for (ThreadPlanSP plan : m_plans) - plan->SetThreadPlanTracer(tracer_sp); -} - void ThreadPlanStack::PushPlan(lldb::ThreadPlanSP new_plan_sp) { // If the thread plan doesn't already have a tracer, give it its parent's // tracer: // The first plan has to be a base plan: + std::lock_guard guard(m_stack_mutex); assert((m_plans.size() > 0 || new_plan_sp->IsBasePlan()) && "Zeroth plan must be a base plan"); @@ -154,6 +147,7 @@ void ThreadPlanStack::PushPlan(lldb::ThreadPlanSP new_plan_sp) { } lldb::ThreadPlanSP ThreadPlanStack::PopPlan() { + std::lock_guard guard(m_stack_mutex); assert(m_plans.size() > 1 && "Can't pop the base thread plan"); lldb::ThreadPlanSP plan_sp = std::move(m_plans.back()); @@ -164,6 +158,7 @@ lldb::ThreadPlanSP ThreadPlanStack::PopPlan() { } lldb::ThreadPlanSP ThreadPlanStack::DiscardPlan() { + std::lock_guard guard(m_stack_mutex); assert(m_plans.size() > 1 && "Can't discard the base thread plan"); lldb::ThreadPlanSP plan_sp = std::move(m_plans.back()); @@ -176,6 +171,7 @@ lldb::ThreadPlanSP ThreadPlanStack::DiscardPlan() { // If the input plan is nullptr, discard all plans. Otherwise make sure this // plan is in the stack, and if so discard up to and including it. void ThreadPlanStack::DiscardPlansUpToPlan(ThreadPlan *up_to_plan_ptr) { + std::lock_guard guard(m_stack_mutex); int stack_size = m_plans.size(); if (up_to_plan_ptr == nullptr) { @@ -203,6 +199,7 @@ void ThreadPlanStack::DiscardPlansUpToPlan(ThreadPlan *up_to_plan_ptr) { } void ThreadPlanStack::DiscardAllPlans() { + std::lock_guard guard(m_stack_mutex); int stack_size = m_plans.size(); for (int i = stack_size - 1; i > 0; i--) { DiscardPlan(); @@ -211,6 +208,7 @@ void ThreadPlanStack::DiscardAllPlans() { } void ThreadPlanStack::DiscardConsultingMasterPlans() { + std::lock_guard guard(m_stack_mutex); while (true) { int master_plan_idx; bool discard = true; @@ -244,11 +242,13 @@ void ThreadPlanStack::DiscardConsultingMasterPlans() { } lldb::ThreadPlanSP ThreadPlanStack::GetCurrentPlan() const { + std::lock_guard guard(m_stack_mutex); assert(m_plans.size() != 0 && "There will always be a base plan."); return m_plans.back(); } lldb::ThreadPlanSP ThreadPlanStack::GetCompletedPlan(bool skip_private) const { + std::lock_guard guard(m_stack_mutex); if (m_completed_plans.empty()) return {}; @@ -266,6 +266,7 @@ lldb::ThreadPlanSP ThreadPlanStack::GetCompletedPlan(bool skip_private) const { lldb::ThreadPlanSP ThreadPlanStack::GetPlanByIndex(uint32_t plan_idx, bool skip_private) const { + std::lock_guard guard(m_stack_mutex); uint32_t idx = 0; for (lldb::ThreadPlanSP plan_sp : m_plans) { @@ -279,6 +280,7 @@ lldb::ThreadPlanSP ThreadPlanStack::GetPlanByIndex(uint32_t plan_idx, } lldb::ValueObjectSP ThreadPlanStack::GetReturnValueObject() const { + std::lock_guard guard(m_stack_mutex); if (m_completed_plans.empty()) return {}; @@ -292,6 +294,7 @@ lldb::ValueObjectSP ThreadPlanStack::GetReturnValueObject() const { } lldb::ExpressionVariableSP ThreadPlanStack::GetExpressionVariable() const { + std::lock_guard guard(m_stack_mutex); if (m_completed_plans.empty()) return {}; @@ -304,19 +307,23 @@ lldb::ExpressionVariableSP ThreadPlanStack::GetExpressionVariable() const { return {}; } bool ThreadPlanStack::AnyPlans() const { + std::lock_guard guard(m_stack_mutex); // There is always a base plan... return m_plans.size() > 1; } bool ThreadPlanStack::AnyCompletedPlans() const { + std::lock_guard guard(m_stack_mutex); return !m_completed_plans.empty(); } bool ThreadPlanStack::AnyDiscardedPlans() const { + std::lock_guard guard(m_stack_mutex); return !m_discarded_plans.empty(); } bool ThreadPlanStack::IsPlanDone(ThreadPlan *in_plan) const { + std::lock_guard guard(m_stack_mutex); for (auto plan : m_completed_plans) { if (plan.get() == in_plan) return true; @@ -325,6 +332,7 @@ bool ThreadPlanStack::IsPlanDone(ThreadPlan *in_plan) const { } bool ThreadPlanStack::WasPlanDiscarded(ThreadPlan *in_plan) const { + std::lock_guard guard(m_stack_mutex); for (auto plan : m_discarded_plans) { if (plan.get() == in_plan) return true; @@ -333,6 +341,7 @@ bool ThreadPlanStack::WasPlanDiscarded(ThreadPlan *in_plan) const { } ThreadPlan *ThreadPlanStack::GetPreviousPlan(ThreadPlan *current_plan) const { + std::lock_guard guard(m_stack_mutex); if (current_plan == nullptr) return nullptr; @@ -360,6 +369,7 @@ ThreadPlan *ThreadPlanStack::GetPreviousPlan(ThreadPlan *current_plan) const { } ThreadPlan *ThreadPlanStack::GetInnermostExpression() const { + std::lock_guard guard(m_stack_mutex); int stack_size = m_plans.size(); for (int i = stack_size - 1; i > 0; i--) { @@ -369,24 +379,18 @@ ThreadPlan *ThreadPlanStack::GetInnermostExpression() const { return nullptr; } +void ThreadPlanStack::ClearThreadCache() { + std::lock_guard guard(m_stack_mutex); + for (lldb::ThreadPlanSP thread_plan_sp : m_plans) + thread_plan_sp->ClearThreadCache(); +} + void ThreadPlanStack::WillResume() { + std::lock_guard guard(m_stack_mutex); m_completed_plans.clear(); m_discarded_plans.clear(); } -const ThreadPlanStack::PlanStack & -ThreadPlanStack::GetStackOfKind(ThreadPlanStack::StackKind kind) const { - switch (kind) { - case ePlans: - return m_plans; - case eCompletedPlans: - return m_completed_plans; - case eDiscardedPlans: - return m_discarded_plans; - } - llvm_unreachable("Invalid StackKind value"); -} - void ThreadPlanStackMap::Update(ThreadList ¤t_threads, bool delete_missing, bool check_for_new) { @@ -397,7 +401,7 @@ void ThreadPlanStackMap::Update(ThreadList ¤t_threads, lldb::tid_t cur_tid = thread->GetID(); if (!Find(cur_tid)) { AddThread(*thread.get()); - thread->QueueFundamentalPlan(true); + thread->QueueBasePlan(true); } } } @@ -410,7 +414,7 @@ void ThreadPlanStackMap::Update(ThreadList ¤t_threads, std::vector missing_threads; // If we are going to delete plans from the plan stack, // then scan for absent TID's: - for (auto thread_plans : m_plans_list) { + for (auto &thread_plans : m_plans_list) { lldb::tid_t cur_tid = thread_plans.first; ThreadSP thread_sp = current_threads.FindThreadByID(cur_tid); if (!thread_sp) @@ -425,7 +429,7 @@ void ThreadPlanStackMap::DumpPlans(Stream &strm, lldb::DescriptionLevel desc_level, bool internal, bool condense_if_trivial, bool skip_unreported) { - for (auto elem : m_plans_list) { + for (auto &elem : m_plans_list) { lldb::tid_t tid = elem.first; uint32_t index_id = 0; ThreadSP thread_sp = m_process.GetThreadList().FindThreadByID(tid); diff --git a/gnu/llvm/lldb/source/Target/ThreadPlanStepInRange.cpp b/gnu/llvm/lldb/source/Target/ThreadPlanStepInRange.cpp index c5f81d6665a..69b4b918d46 100644 --- a/gnu/llvm/lldb/source/Target/ThreadPlanStepInRange.cpp +++ b/gnu/llvm/lldb/source/Target/ThreadPlanStepInRange.cpp @@ -31,22 +31,6 @@ uint32_t ThreadPlanStepInRange::s_default_flag_values = // ThreadPlanStepInRange: Step through a stack range, either stepping over or // into based on the value of \a type. -ThreadPlanStepInRange::ThreadPlanStepInRange( - Thread &thread, const AddressRange &range, - const SymbolContext &addr_context, lldb::RunMode stop_others, - LazyBool step_in_avoids_code_without_debug_info, - LazyBool step_out_avoids_code_without_debug_info) - : ThreadPlanStepRange(ThreadPlan::eKindStepInRange, - "Step Range stepping in", thread, range, addr_context, - stop_others), - ThreadPlanShouldStopHere(this), m_step_past_prologue(true), - m_virtual_step(false) { - SetCallbacks(); - SetFlagsToDefault(); - SetupAvoidNoDebug(step_in_avoids_code_without_debug_info, - step_out_avoids_code_without_debug_info); -} - ThreadPlanStepInRange::ThreadPlanStepInRange( Thread &thread, const AddressRange &range, const SymbolContext &addr_context, const char *step_into_target, @@ -307,11 +291,10 @@ bool ThreadPlanStepInRange::ShouldStop(Event *event_ptr) { } void ThreadPlanStepInRange::SetAvoidRegexp(const char *name) { - auto name_ref = llvm::StringRef::withNullAsEmpty(name); if (m_avoid_regexp_up) - *m_avoid_regexp_up = RegularExpression(name_ref); + *m_avoid_regexp_up = RegularExpression(name); else - m_avoid_regexp_up = std::make_unique(name_ref); + m_avoid_regexp_up = std::make_unique(name); } void ThreadPlanStepInRange::SetDefaultFlagValue(uint32_t new_value) { diff --git a/gnu/llvm/lldb/source/Target/ThreadPlanStepInstruction.cpp b/gnu/llvm/lldb/source/Target/ThreadPlanStepInstruction.cpp index c0da735c44b..e34e41e8bce 100644 --- a/gnu/llvm/lldb/source/Target/ThreadPlanStepInstruction.cpp +++ b/gnu/llvm/lldb/source/Target/ThreadPlanStepInstruction.cpp @@ -23,10 +23,11 @@ using namespace lldb_private; ThreadPlanStepInstruction::ThreadPlanStepInstruction(Thread &thread, bool step_over, bool stop_other_threads, - Vote stop_vote, - Vote run_vote) + Vote report_stop_vote, + Vote report_run_vote) : ThreadPlan(ThreadPlan::eKindStepInstruction, - "Step over single instruction", thread, stop_vote, run_vote), + "Step over single instruction", thread, report_stop_vote, + report_run_vote), m_instruction_addr(0), m_stop_other_threads(stop_other_threads), m_step_over(step_over) { m_takes_iteration_count = true; diff --git a/gnu/llvm/lldb/source/Target/ThreadPlanStepOut.cpp b/gnu/llvm/lldb/source/Target/ThreadPlanStepOut.cpp index 9f0749c0fdb..86ccac2ec49 100644 --- a/gnu/llvm/lldb/source/Target/ThreadPlanStepOut.cpp +++ b/gnu/llvm/lldb/source/Target/ThreadPlanStepOut.cpp @@ -33,11 +33,11 @@ uint32_t ThreadPlanStepOut::s_default_flag_values = 0; // ThreadPlanStepOut: Step out of the current frame ThreadPlanStepOut::ThreadPlanStepOut( Thread &thread, SymbolContext *context, bool first_insn, bool stop_others, - Vote stop_vote, Vote run_vote, uint32_t frame_idx, + Vote report_stop_vote, Vote report_run_vote, uint32_t frame_idx, LazyBool step_out_avoids_code_without_debug_info, bool continue_to_next_branch, bool gather_return_value) - : ThreadPlan(ThreadPlan::eKindStepOut, "Step out", thread, stop_vote, - run_vote), + : ThreadPlan(ThreadPlan::eKindStepOut, "Step out", thread, report_stop_vote, + report_run_vote), ThreadPlanShouldStopHere(this), m_step_from_insn(LLDB_INVALID_ADDRESS), m_return_bp_id(LLDB_INVALID_BREAK_ID), m_return_addr(LLDB_INVALID_ADDRESS), m_stop_others(stop_others), diff --git a/gnu/llvm/lldb/source/Target/ThreadPlanStepOverBreakpoint.cpp b/gnu/llvm/lldb/source/Target/ThreadPlanStepOverBreakpoint.cpp index f3d35a91fcb..965a7b3a996 100644 --- a/gnu/llvm/lldb/source/Target/ThreadPlanStepOverBreakpoint.cpp +++ b/gnu/llvm/lldb/source/Target/ThreadPlanStepOverBreakpoint.cpp @@ -36,7 +36,7 @@ ThreadPlanStepOverBreakpoint::ThreadPlanStepOverBreakpoint(Thread &thread) m_breakpoint_addr); } -ThreadPlanStepOverBreakpoint::~ThreadPlanStepOverBreakpoint() {} +ThreadPlanStepOverBreakpoint::~ThreadPlanStepOverBreakpoint() = default; void ThreadPlanStepOverBreakpoint::GetDescription( Stream *s, lldb::DescriptionLevel level) { @@ -49,21 +49,11 @@ bool ThreadPlanStepOverBreakpoint::ValidatePlan(Stream *error) { return true; } bool ThreadPlanStepOverBreakpoint::DoPlanExplainsStop(Event *event_ptr) { StopInfoSP stop_info_sp = GetPrivateStopInfo(); if (stop_info_sp) { - // It's a little surprising that we stop here for a breakpoint hit. - // However, when you single step ONTO a breakpoint we still want to call - // that a breakpoint hit, and trigger the actions, etc. Otherwise you - // would see the - // PC at the breakpoint without having triggered the actions, then you'd - // continue, the PC wouldn't change, - // and you'd see the breakpoint hit, which would be odd. So the lower - // levels fake "step onto breakpoint address" and return that as a - // breakpoint. So our trace step COULD appear as a breakpoint hit if the - // next instruction also contained a breakpoint. StopReason reason = stop_info_sp->GetStopReason(); Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); - LLDB_LOGF(log, "Step over breakpoint stopped for reason: %s.", - Thread::StopReasonAsCString(reason)); + LLDB_LOG(log, "Step over breakpoint stopped for reason: {0}.", + Thread::StopReasonAsString(reason)); switch (reason) { case eStopReasonTrace: diff --git a/gnu/llvm/lldb/source/Target/ThreadPlanStepRange.cpp b/gnu/llvm/lldb/source/Target/ThreadPlanStepRange.cpp index f4b2ee3d08a..896e647bbb5 100644 --- a/gnu/llvm/lldb/source/Target/ThreadPlanStepRange.cpp +++ b/gnu/llvm/lldb/source/Target/ThreadPlanStepRange.cpp @@ -264,10 +264,9 @@ InstructionList *ThreadPlanStepRange::GetInstructionsForAddress( // Disassemble the address range given: const char *plugin_name = nullptr; const char *flavor = nullptr; - const bool prefer_file_cache = true; m_instruction_ranges[i] = Disassembler::DisassembleRange( GetTarget().GetArchitecture(), plugin_name, flavor, GetTarget(), - m_address_ranges[i], prefer_file_cache); + m_address_ranges[i]); } if (!m_instruction_ranges[i]) return nullptr; @@ -327,13 +326,9 @@ bool ThreadPlanStepRange::SetNextBranchBreakpoint() { if (instructions == nullptr) return false; else { - Target &target = GetThread().GetProcess()->GetTarget(); const bool ignore_calls = GetKind() == eKindStepOverRange; - uint32_t branch_index = - instructions->GetIndexOfNextBranchInstruction(pc_index, target, - ignore_calls, - &m_found_calls); - + uint32_t branch_index = instructions->GetIndexOfNextBranchInstruction( + pc_index, ignore_calls, &m_found_calls); Address run_to_address; // If we didn't find a branch, run to the end of the range. diff --git a/gnu/llvm/lldb/source/Target/ThreadPlanStepThrough.cpp b/gnu/llvm/lldb/source/Target/ThreadPlanStepThrough.cpp index 06b626935ab..6fc0312222f 100644 --- a/gnu/llvm/lldb/source/Target/ThreadPlanStepThrough.cpp +++ b/gnu/llvm/lldb/source/Target/ThreadPlanStepThrough.cpp @@ -22,7 +22,6 @@ using namespace lldb_private; // ThreadPlanStepThrough: If the current instruction is a trampoline, step // through it If it is the beginning of the prologue of a function, step // through that as well. -// FIXME: At present only handles DYLD trampolines. ThreadPlanStepThrough::ThreadPlanStepThrough(Thread &thread, StackID &m_stack_id, diff --git a/gnu/llvm/lldb/source/Target/ThreadPlanTracer.cpp b/gnu/llvm/lldb/source/Target/ThreadPlanTracer.cpp index c00415f3c1e..754ce655729 100644 --- a/gnu/llvm/lldb/source/Target/ThreadPlanTracer.cpp +++ b/gnu/llvm/lldb/source/Target/ThreadPlanTracer.cpp @@ -35,11 +35,11 @@ using namespace lldb_private; ThreadPlanTracer::ThreadPlanTracer(Thread &thread, lldb::StreamSP &stream_sp) : m_process(*thread.GetProcess().get()), m_tid(thread.GetID()), - m_single_step(true), m_enabled(false), m_stream_sp(stream_sp) {} + m_enabled(false), m_stream_sp(stream_sp) {} ThreadPlanTracer::ThreadPlanTracer(Thread &thread) : m_process(*thread.GetProcess().get()), m_tid(thread.GetID()), - m_single_step(true), m_enabled(false), m_stream_sp() {} + m_enabled(false), m_stream_sp() {} Stream *ThreadPlanTracer::GetLogStream() { if (m_stream_sp) @@ -75,7 +75,7 @@ void ThreadPlanTracer::Log() { } bool ThreadPlanTracer::TracerExplainsStop() { - if (m_enabled && m_single_step) { + if (m_enabled) { lldb::StopInfoSP stop_info = GetThread().GetStopInfo(); return (stop_info->GetStopReason() == eStopReasonTrace); } else @@ -191,7 +191,7 @@ void ThreadPlanAssemblyTracer::Log() { for (int arg_index = 0; arg_index < num_args; ++arg_index) { Value value; - value.SetValueType(Value::eValueTypeScalar); + value.SetValueType(Value::ValueType::Scalar); value.SetCompilerType(intptr_type); value_list.PushValue(value); } diff --git a/gnu/llvm/lldb/source/Target/ThreadSpec.cpp b/gnu/llvm/lldb/source/Target/ThreadSpec.cpp index 1f6639379c4..ba4c3aa8945 100644 --- a/gnu/llvm/lldb/source/Target/ThreadSpec.cpp +++ b/gnu/llvm/lldb/source/Target/ThreadSpec.cpp @@ -17,9 +17,7 @@ const char *ThreadSpec::g_option_names[static_cast( ThreadSpec::OptionNames::LastOptionName)]{"Index", "ID", "Name", "QueueName"}; -ThreadSpec::ThreadSpec() - : m_index(UINT32_MAX), m_tid(LLDB_INVALID_THREAD_ID), m_name(), - m_queue_name() {} +ThreadSpec::ThreadSpec() : m_name(), m_queue_name() {} std::unique_ptr ThreadSpec::CreateFromStructuredData( const StructuredData::Dictionary &spec_dict, Status &error) { diff --git a/gnu/llvm/lldb/source/Target/Trace.cpp b/gnu/llvm/lldb/source/Target/Trace.cpp new file mode 100644 index 00000000000..827f3264c09 --- /dev/null +++ b/gnu/llvm/lldb/source/Target/Trace.cpp @@ -0,0 +1,221 @@ +//===-- Trace.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 "lldb/Target/Trace.h" + +#include "llvm/Support/Format.h" + +#include "lldb/Core/Module.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Symbol/Function.h" +#include "lldb/Target/ExecutionContext.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/SectionLoadList.h" +#include "lldb/Target/Thread.h" +#include "lldb/Utility/Stream.h" + +using namespace lldb; +using namespace lldb_private; +using namespace llvm; + +// Helper structs used to extract the type of a trace session json without +// having to parse the entire object. + +struct JSONSimplePluginSettings { + std::string type; +}; + +struct JSONSimpleTraceSession { + JSONSimplePluginSettings trace; +}; + +namespace llvm { +namespace json { + +bool fromJSON(const Value &value, JSONSimplePluginSettings &plugin_settings, + Path path) { + json::ObjectMapper o(value, path); + return o && o.map("type", plugin_settings.type); +} + +bool fromJSON(const Value &value, JSONSimpleTraceSession &session, Path path) { + json::ObjectMapper o(value, path); + return o && o.map("trace", session.trace); +} + +} // namespace json +} // namespace llvm + +static Error createInvalidPlugInError(StringRef plugin_name) { + return createStringError( + std::errc::invalid_argument, + "no trace plug-in matches the specified type: \"%s\"", + plugin_name.data()); +} + +Expected +Trace::FindPluginForPostMortemProcess(Debugger &debugger, + const json::Value &trace_session_file, + StringRef session_file_dir) { + JSONSimpleTraceSession json_session; + json::Path::Root root("traceSession"); + if (!json::fromJSON(trace_session_file, json_session, root)) + return root.getError(); + + ConstString plugin_name(json_session.trace.type); + if (auto create_callback = PluginManager::GetTraceCreateCallback(plugin_name)) + return create_callback(trace_session_file, session_file_dir, debugger); + + return createInvalidPlugInError(json_session.trace.type); +} + +Expected +Trace::FindPluginForLiveProcess(llvm::StringRef plugin_name, Process &process) { + if (!process.IsLiveDebugSession()) + return createStringError(inconvertibleErrorCode(), + "Can't trace non-live processes"); + + ConstString name(plugin_name); + if (auto create_callback = + PluginManager::GetTraceCreateCallbackForLiveProcess(name)) + return create_callback(process); + + return createInvalidPlugInError(plugin_name); +} + +Expected Trace::FindPluginSchema(StringRef name) { + ConstString plugin_name(name); + StringRef schema = PluginManager::GetTraceSchema(plugin_name); + if (!schema.empty()) + return schema; + + return createInvalidPlugInError(name); +} + +Error Trace::Start(const llvm::json::Value &request) { + if (!m_live_process) + return createStringError(inconvertibleErrorCode(), + "Tracing requires a live process."); + return m_live_process->TraceStart(request); +} + +Error Trace::Stop() { + if (!m_live_process) + return createStringError(inconvertibleErrorCode(), + "Tracing requires a live process."); + return m_live_process->TraceStop( + TraceStopRequest(GetPluginName().AsCString())); +} + +Error Trace::Stop(llvm::ArrayRef tids) { + if (!m_live_process) + return createStringError(inconvertibleErrorCode(), + "Tracing requires a live process."); + return m_live_process->TraceStop( + TraceStopRequest(GetPluginName().AsCString(), tids)); +} + +Expected Trace::GetLiveProcessState() { + if (!m_live_process) + return createStringError(inconvertibleErrorCode(), + "Tracing requires a live process."); + return m_live_process->TraceGetState(GetPluginName().AsCString()); +} + +Optional Trace::GetLiveThreadBinaryDataSize(lldb::tid_t tid, + llvm::StringRef kind) { + auto it = m_live_thread_data.find(tid); + if (it == m_live_thread_data.end()) + return None; + std::unordered_map &single_thread_data = it->second; + auto single_thread_data_it = single_thread_data.find(kind.str()); + if (single_thread_data_it == single_thread_data.end()) + return None; + return single_thread_data_it->second; +} + +Optional Trace::GetLiveProcessBinaryDataSize(llvm::StringRef kind) { + auto data_it = m_live_process_data.find(kind.str()); + if (data_it == m_live_process_data.end()) + return None; + return data_it->second; +} + +Expected> +Trace::GetLiveThreadBinaryData(lldb::tid_t tid, llvm::StringRef kind) { + if (!m_live_process) + return createStringError(inconvertibleErrorCode(), + "Tracing requires a live process."); + llvm::Optional size = GetLiveThreadBinaryDataSize(tid, kind); + if (!size) + return createStringError( + inconvertibleErrorCode(), + "Tracing data \"%s\" is not available for thread %" PRIu64 ".", + kind.data(), tid); + + TraceGetBinaryDataRequest request{GetPluginName().AsCString(), kind.str(), + static_cast(tid), 0, + static_cast(*size)}; + return m_live_process->TraceGetBinaryData(request); +} + +Expected> +Trace::GetLiveProcessBinaryData(llvm::StringRef kind) { + if (!m_live_process) + return createStringError(inconvertibleErrorCode(), + "Tracing requires a live process."); + llvm::Optional size = GetLiveProcessBinaryDataSize(kind); + if (!size) + return createStringError( + inconvertibleErrorCode(), + "Tracing data \"%s\" is not available for the process.", kind.data()); + + TraceGetBinaryDataRequest request{GetPluginName().AsCString(), kind.str(), + None, 0, static_cast(*size)}; + return m_live_process->TraceGetBinaryData(request); +} + +void Trace::RefreshLiveProcessState() { + if (!m_live_process) + return; + + uint32_t new_stop_id = m_live_process->GetStopID(); + if (new_stop_id == m_stop_id) + return; + + m_stop_id = new_stop_id; + m_live_thread_data.clear(); + + Expected json_string = GetLiveProcessState(); + if (!json_string) { + DoRefreshLiveProcessState(json_string.takeError()); + return; + } + Expected live_process_state = + json::parse(*json_string, "TraceGetStateResponse"); + if (!live_process_state) { + DoRefreshLiveProcessState(live_process_state.takeError()); + return; + } + + for (const TraceThreadState &thread_state : + live_process_state->tracedThreads) { + for (const TraceBinaryData &item : thread_state.binaryData) + m_live_thread_data[thread_state.tid][item.kind] = item.size; + } + + for (const TraceBinaryData &item : live_process_state->processBinaryData) + m_live_process_data[item.kind] = item.size; + + DoRefreshLiveProcessState(std::move(live_process_state)); +} + +uint32_t Trace::GetStopID() { + RefreshLiveProcessState(); + return m_stop_id; +} diff --git a/gnu/llvm/lldb/source/Target/TraceCursor.cpp b/gnu/llvm/lldb/source/Target/TraceCursor.cpp new file mode 100644 index 00000000000..d0f69642cb9 --- /dev/null +++ b/gnu/llvm/lldb/source/Target/TraceCursor.cpp @@ -0,0 +1,35 @@ +//===-- TraceCursor.cpp -----------------------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#include "lldb/Target/TraceCursor.h" + +#include "lldb/Target/ExecutionContext.h" + +using namespace lldb; +using namespace lldb_private; +using namespace llvm; + +TraceCursor::TraceCursor(lldb::ThreadSP thread_sp) + : m_exe_ctx_ref(ExecutionContext(thread_sp)) {} + +ExecutionContextRef &TraceCursor::GetExecutionContextRef() { + return m_exe_ctx_ref; +} + +void TraceCursor::SetGranularity( + lldb::TraceInstructionControlFlowType granularity) { + m_granularity = granularity; +} + +void TraceCursor::SetIgnoreErrors(bool ignore_errors) { + m_ignore_errors = ignore_errors; +} + +void TraceCursor::SetForwards(bool forwards) { m_forwards = forwards; } + +bool TraceCursor::IsForwards() const { return m_forwards; } diff --git a/gnu/llvm/lldb/source/Target/TraceExporter.cpp b/gnu/llvm/lldb/source/Target/TraceExporter.cpp new file mode 100644 index 00000000000..1a6571dba4a --- /dev/null +++ b/gnu/llvm/lldb/source/Target/TraceExporter.cpp @@ -0,0 +1,32 @@ +//===-- TraceExporter.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 "lldb/Target/TraceExporter.h" + +#include "lldb/Core/PluginManager.h" + +using namespace lldb; +using namespace lldb_private; +using namespace llvm; + +static Error createInvalidPlugInError(StringRef plugin_name) { + return createStringError( + std::errc::invalid_argument, + "no trace expoter plug-in matches the specified type: \"%s\"", + plugin_name.data()); +} + +Expected +TraceExporter::FindPlugin(llvm::StringRef plugin_name) { + ConstString name(plugin_name); + if (auto create_callback = + PluginManager::GetTraceExporterCreateCallback(name)) + return create_callback(); + + return createInvalidPlugInError(plugin_name); +} diff --git a/gnu/llvm/lldb/source/Target/TraceInstructionDumper.cpp b/gnu/llvm/lldb/source/Target/TraceInstructionDumper.cpp new file mode 100644 index 00000000000..dc1e86481c3 --- /dev/null +++ b/gnu/llvm/lldb/source/Target/TraceInstructionDumper.cpp @@ -0,0 +1,292 @@ +//===-- TraceInstructionDumper.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 "lldb/Target/TraceInstructionDumper.h" + +#include "lldb/Core/Module.h" +#include "lldb/Symbol/Function.h" +#include "lldb/Target/ExecutionContext.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/SectionLoadList.h" + +using namespace lldb; +using namespace lldb_private; +using namespace llvm; + +TraceInstructionDumper::TraceInstructionDumper(lldb::TraceCursorUP &&cursor_up, + int initial_index, bool raw, + bool show_tsc) + : m_cursor_up(std::move(cursor_up)), m_index(initial_index), m_raw(raw), + m_show_tsc(show_tsc) {} + +/// \return +/// Return \b true if the cursor could move one step. +bool TraceInstructionDumper::TryMoveOneStep() { + if (!m_cursor_up->Next()) { + SetNoMoreData(); + return false; + } + m_index += m_cursor_up->IsForwards() ? 1 : -1; + return true; +} + +/// \return +/// The number of characters that would be needed to print the given +/// integer. +static int GetNumberOfChars(int num) { + if (num == 0) + return 1; + return (num < 0 ? 1 : 0) + static_cast(log10(abs(num))) + 1; +} + +/// Helper struct that holds symbol, disassembly and address information of an +/// instruction. +struct InstructionSymbolInfo { + SymbolContext sc; + Address address; + lldb::addr_t load_address; + lldb::DisassemblerSP disassembler; + lldb::InstructionSP instruction; + lldb_private::ExecutionContext exe_ctx; +}; + +// This custom LineEntry validator is neded because some line_entries have +// 0 as line, which is meaningless. Notice that LineEntry::IsValid only +// checks that line is not LLDB_INVALID_LINE_NUMBER, i.e. UINT32_MAX. +static bool IsLineEntryValid(const LineEntry &line_entry) { + return line_entry.IsValid() && line_entry.line > 0; +} + +/// \return +/// \b true if the provided line entries match line, column and source file. +/// This function assumes that the line entries are valid. +static bool FileLineAndColumnMatches(const LineEntry &a, const LineEntry &b) { + if (a.line != b.line) + return false; + if (a.column != b.column) + return false; + return a.file == b.file; +} + +/// Compare the symbol contexts of the provided \a InstructionSymbolInfo +/// objects. +/// +/// \return +/// \a true if both instructions belong to the same scope level analized +/// in the following order: +/// - module +/// - symbol +/// - function +/// - line +static bool +IsSameInstructionSymbolContext(const InstructionSymbolInfo &prev_insn, + const InstructionSymbolInfo &insn) { + // module checks + if (insn.sc.module_sp != prev_insn.sc.module_sp) + return false; + + // symbol checks + if (insn.sc.symbol != prev_insn.sc.symbol) + return false; + + // function checks + if (!insn.sc.function && !prev_insn.sc.function) + return true; + else if (insn.sc.function != prev_insn.sc.function) + return false; + + // line entry checks + const bool curr_line_valid = IsLineEntryValid(insn.sc.line_entry); + const bool prev_line_valid = IsLineEntryValid(prev_insn.sc.line_entry); + if (curr_line_valid && prev_line_valid) + return FileLineAndColumnMatches(insn.sc.line_entry, + prev_insn.sc.line_entry); + return curr_line_valid == prev_line_valid; +} + +/// Dump the symbol context of the given instruction address if it's different +/// from the symbol context of the previous instruction in the trace. +/// +/// \param[in] prev_sc +/// The symbol context of the previous instruction in the trace. +/// +/// \param[in] address +/// The address whose symbol information will be dumped. +/// +/// \return +/// The symbol context of the current address, which might differ from the +/// previous one. +static void +DumpInstructionSymbolContext(Stream &s, + Optional prev_insn, + InstructionSymbolInfo &insn) { + if (prev_insn && IsSameInstructionSymbolContext(*prev_insn, insn)) + return; + + s.Printf(" "); + + if (!insn.sc.module_sp) + s.Printf("(none)"); + else if (!insn.sc.function && !insn.sc.symbol) + s.Printf("%s`(none)", + insn.sc.module_sp->GetFileSpec().GetFilename().AsCString()); + else + insn.sc.DumpStopContext(&s, insn.exe_ctx.GetTargetPtr(), insn.address, + /*show_fullpath=*/false, + /*show_module=*/true, /*show_inlined_frames=*/false, + /*show_function_arguments=*/true, + /*show_function_name=*/true); + s.Printf("\n"); +} + +static void DumpInstructionDisassembly(Stream &s, InstructionSymbolInfo &insn) { + if (!insn.instruction) + return; + s.Printf(" "); + insn.instruction->Dump(&s, /*show_address=*/false, /*show_bytes=*/false, + /*max_opcode_byte_size=*/0, &insn.exe_ctx, &insn.sc, + /*prev_sym_ctx=*/nullptr, + /*disassembly_addr_format=*/nullptr, + /*max_address_text_size=*/0); +} + +void TraceInstructionDumper::SetNoMoreData() { m_no_more_data = true; } + +bool TraceInstructionDumper::HasMoreData() { return !m_no_more_data; } + +void TraceInstructionDumper::DumpInstructions(Stream &s, size_t count) { + ThreadSP thread_sp = m_cursor_up->GetExecutionContextRef().GetThreadSP(); + if (!thread_sp) { + s.Printf("invalid thread"); + return; + } + + s.Printf("thread #%u: tid = %" PRIu64 "\n", thread_sp->GetIndexID(), + thread_sp->GetID()); + + int digits_count = GetNumberOfChars( + m_cursor_up->IsForwards() ? m_index + count - 1 : m_index - count + 1); + bool was_prev_instruction_an_error = false; + + auto printMissingInstructionsMessage = [&]() { + s.Printf(" ...missing instructions\n"); + }; + + auto printInstructionIndex = [&]() { + s.Printf(" [%*d] ", digits_count, m_index); + + if (m_show_tsc) { + s.Printf("[tsc="); + + if (Optional timestamp = m_cursor_up->GetTimestampCounter()) + s.Printf("0x%016" PRIx64, *timestamp); + else + s.Printf("unavailable"); + + s.Printf("] "); + } + }; + + InstructionSymbolInfo prev_insn_info; + + Target &target = thread_sp->GetProcess()->GetTarget(); + ExecutionContext exe_ctx; + target.CalculateExecutionContext(exe_ctx); + const ArchSpec &arch = target.GetArchitecture(); + + // Find the symbol context for the given address reusing the previous + // instruction's symbol context when possible. + auto calculateSymbolContext = [&](const Address &address) { + AddressRange range; + if (prev_insn_info.sc.GetAddressRange(eSymbolContextEverything, 0, + /*inline_block_range*/ false, + range) && + range.Contains(address)) + return prev_insn_info.sc; + + SymbolContext sc; + address.CalculateSymbolContext(&sc, eSymbolContextEverything); + return sc; + }; + + // Find the disassembler for the given address reusing the previous + // instruction's disassembler when possible. + auto calculateDisass = [&](const Address &address, const SymbolContext &sc) { + if (prev_insn_info.disassembler) { + if (InstructionSP instruction = + prev_insn_info.disassembler->GetInstructionList() + .GetInstructionAtAddress(address)) + return std::make_tuple(prev_insn_info.disassembler, instruction); + } + + if (sc.function) { + if (DisassemblerSP disassembler = + sc.function->GetInstructions(exe_ctx, nullptr)) { + if (InstructionSP instruction = + disassembler->GetInstructionList().GetInstructionAtAddress( + address)) + return std::make_tuple(disassembler, instruction); + } + } + // We fallback to a single instruction disassembler + AddressRange range(address, arch.GetMaximumOpcodeByteSize()); + DisassemblerSP disassembler = + Disassembler::DisassembleRange(arch, /*plugin_name*/ nullptr, + /*flavor*/ nullptr, target, range); + return std::make_tuple(disassembler, + disassembler ? disassembler->GetInstructionList() + .GetInstructionAtAddress(address) + : InstructionSP()); + }; + + for (size_t i = 0; i < count; i++) { + if (!HasMoreData()) { + s.Printf(" no more data\n"); + break; + } + + if (Error err = m_cursor_up->GetError()) { + if (!m_cursor_up->IsForwards() && !was_prev_instruction_an_error) + printMissingInstructionsMessage(); + + was_prev_instruction_an_error = true; + + printInstructionIndex(); + s << toString(std::move(err)); + } else { + if (m_cursor_up->IsForwards() && was_prev_instruction_an_error) + printMissingInstructionsMessage(); + + was_prev_instruction_an_error = false; + + InstructionSymbolInfo insn_info; + + if (!m_raw) { + insn_info.load_address = m_cursor_up->GetLoadAddress(); + insn_info.exe_ctx = exe_ctx; + insn_info.address.SetLoadAddress(insn_info.load_address, &target); + insn_info.sc = calculateSymbolContext(insn_info.address); + std::tie(insn_info.disassembler, insn_info.instruction) = + calculateDisass(insn_info.address, insn_info.sc); + + DumpInstructionSymbolContext(s, prev_insn_info, insn_info); + } + + printInstructionIndex(); + s.Printf("0x%016" PRIx64, m_cursor_up->GetLoadAddress()); + + if (!m_raw) + DumpInstructionDisassembly(s, insn_info); + + prev_insn_info = insn_info; + } + + s.Printf("\n"); + TryMoveOneStep(); + } +} diff --git a/gnu/llvm/lldb/source/Target/UnwindAssembly.cpp b/gnu/llvm/lldb/source/Target/UnwindAssembly.cpp index 3a87e3da5bc..75f2b328cef 100644 --- a/gnu/llvm/lldb/source/Target/UnwindAssembly.cpp +++ b/gnu/llvm/lldb/source/Target/UnwindAssembly.cpp @@ -29,5 +29,3 @@ UnwindAssemblySP UnwindAssembly::FindPlugin(const ArchSpec &arch) { } UnwindAssembly::UnwindAssembly(const ArchSpec &arch) : m_arch(arch) {} - -UnwindAssembly::~UnwindAssembly() = default; diff --git a/gnu/llvm/lldb/source/Target/UnwindLLDB.cpp b/gnu/llvm/lldb/source/Target/UnwindLLDB.cpp index 980ad4d2e34..047147112f3 100644 --- a/gnu/llvm/lldb/source/Target/UnwindLLDB.cpp +++ b/gnu/llvm/lldb/source/Target/UnwindLLDB.cpp @@ -420,6 +420,8 @@ bool UnwindLLDB::DoGetFrameInfoAtIndex(uint32_t idx, addr_t &cfa, addr_t &pc, // too behaves like the zeroth frame (i.e. the pc might not // be pointing just past a call in it) behaves_like_zeroth_frame = true; + } else if (m_frames[idx]->reg_ctx_lldb_sp->BehavesLikeZerothFrame()) { + behaves_like_zeroth_frame = true; } else { behaves_like_zeroth_frame = false; } diff --git a/gnu/llvm/lldb/source/Utility/Args.cpp b/gnu/llvm/lldb/source/Utility/Args.cpp index f718c6f9ff1..0334659ab7d 100644 --- a/gnu/llvm/lldb/source/Utility/Args.cpp +++ b/gnu/llvm/lldb/source/Utility/Args.cpp @@ -175,6 +175,11 @@ Args::Args(const StringList &list) : Args() { AppendArgument(arg); } +Args::Args(llvm::ArrayRef args) : Args() { + for (llvm::StringRef arg : args) + AppendArgument(arg); +} + Args &Args::operator=(const Args &rhs) { Clear(); @@ -189,7 +194,7 @@ Args &Args::operator=(const Args &rhs) { } // Destructor -Args::~Args() {} +Args::~Args() = default; void Args::Dump(Stream &s, const char *label_name) const { if (!label_name) @@ -251,8 +256,6 @@ void Args::SetCommandString(llvm::StringRef command) { m_argv.push_back(nullptr); } -size_t Args::GetArgumentCount() const { return m_entries.size(); } - const char *Args::GetArgumentAtIndex(size_t idx) const { if (idx < m_argv.size()) return m_argv[idx]; @@ -374,20 +377,20 @@ void Args::Clear() { m_argv.push_back(nullptr); } -const char *Args::GetShellSafeArgument(const FileSpec &shell, - const char *unsafe_arg, - std::string &safe_arg) { +std::string Args::GetShellSafeArgument(const FileSpec &shell, + llvm::StringRef unsafe_arg) { struct ShellDescriptor { ConstString m_basename; - const char *m_escapables; + llvm::StringRef m_escapables; }; static ShellDescriptor g_Shells[] = {{ConstString("bash"), " '\"<>()&"}, {ConstString("tcsh"), " '\"<>()&$"}, + {ConstString("zsh"), " '\"<>()&;\\|"}, {ConstString("sh"), " '\"<>()&"}}; // safe minimal set - const char *escapables = " '\""; + llvm::StringRef escapables = " '\""; if (auto basename = shell.GetFilename()) { for (const auto &Shell : g_Shells) { @@ -398,18 +401,15 @@ const char *Args::GetShellSafeArgument(const FileSpec &shell, } } - safe_arg.assign(unsafe_arg); - size_t prev_pos = 0; - while (prev_pos < safe_arg.size()) { - // Escape spaces and quotes - size_t pos = safe_arg.find_first_of(escapables, prev_pos); - if (pos != std::string::npos) { - safe_arg.insert(pos, 1, '\\'); - prev_pos = pos + 2; - } else - break; + std::string safe_arg; + safe_arg.reserve(unsafe_arg.size()); + // Add a \ before every character that needs to be escaped. + for (char c : unsafe_arg) { + if (escapables.contains(c)) + safe_arg.push_back('\\'); + safe_arg.push_back(c); } - return safe_arg.c_str(); + return safe_arg; } lldb::Encoding Args::StringToEncoding(llvm::StringRef s, @@ -640,7 +640,6 @@ void OptionsWithRaw::SetFromString(llvm::StringRef arg_string) { } bool found_suffix = false; - while (!arg_string.empty()) { // The length of the prefix before parsing. std::size_t prev_prefix_length = original_args.size() - arg_string.size(); @@ -679,10 +678,8 @@ void OptionsWithRaw::SetFromString(llvm::StringRef arg_string) { } // If we didn't find a suffix delimiter, the whole string is the raw suffix. - if (!found_suffix) { - found_suffix = true; + if (!found_suffix) m_suffix = std::string(original_args); - } } void llvm::yaml::MappingTraits::mapping(IO &io, diff --git a/gnu/llvm/lldb/source/Utility/Broadcaster.cpp b/gnu/llvm/lldb/source/Utility/Broadcaster.cpp index 342548c0b0e..6e067249632 100644 --- a/gnu/llvm/lldb/source/Utility/Broadcaster.cpp +++ b/gnu/llvm/lldb/source/Utility/Broadcaster.cpp @@ -19,8 +19,8 @@ #include #include -#include -#include +#include +#include using namespace lldb; using namespace lldb_private; diff --git a/gnu/llvm/lldb/source/Utility/CMakeLists.txt b/gnu/llvm/lldb/source/Utility/CMakeLists.txt index c89d4f9e007..6790e47d69f 100644 --- a/gnu/llvm/lldb/source/Utility/CMakeLists.txt +++ b/gnu/llvm/lldb/source/Utility/CMakeLists.txt @@ -50,6 +50,7 @@ add_lldb_library(lldbUtility RegularExpression.cpp Reproducer.cpp ReproducerInstrumentation.cpp + ReproducerProvider.cpp Scalar.cpp SelectHelper.cpp State.cpp @@ -64,6 +65,9 @@ add_lldb_library(lldbUtility StructuredData.cpp TildeExpressionResolver.cpp Timer.cpp + TraceGDBRemotePackets.cpp + TraceIntelPTGDBRemotePackets.cpp + UnimplementedError.cpp UUID.cpp UriParser.cpp UserID.cpp diff --git a/gnu/llvm/lldb/source/Utility/ConstString.cpp b/gnu/llvm/lldb/source/Utility/ConstString.cpp index 62f79b3df7a..e5e1b2387e6 100644 --- a/gnu/llvm/lldb/source/Utility/ConstString.cpp +++ b/gnu/llvm/lldb/source/Utility/ConstString.cpp @@ -21,9 +21,9 @@ #include #include -#include -#include -#include +#include +#include +#include using namespace lldb_private; @@ -253,7 +253,7 @@ bool ConstString::Equals(ConstString lhs, ConstString rhs, // perform case insensitive equality test llvm::StringRef lhs_string_ref(lhs.GetStringRef()); llvm::StringRef rhs_string_ref(rhs.GetStringRef()); - return lhs_string_ref.equals_lower(rhs_string_ref); + return lhs_string_ref.equals_insensitive(rhs_string_ref); } int ConstString::Compare(ConstString lhs, ConstString rhs, @@ -270,7 +270,7 @@ int ConstString::Compare(ConstString lhs, ConstString rhs, if (case_sensitive) { return lhs_string_ref.compare(rhs_string_ref); } else { - return lhs_string_ref.compare_lower(rhs_string_ref); + return lhs_string_ref.compare_insensitive(rhs_string_ref); } } @@ -308,7 +308,7 @@ void ConstString::SetString(const llvm::StringRef &s) { } void ConstString::SetStringWithMangledCounterpart(llvm::StringRef demangled, - ConstString mangled) { + ConstString mangled) { m_string = StringPool().GetConstCStringAndSetMangledCounterPart( demangled, mangled.m_string); } diff --git a/gnu/llvm/lldb/source/Utility/DataBufferLLVM.cpp b/gnu/llvm/lldb/source/Utility/DataBufferLLVM.cpp index 235123a31ce..c5aeddd683f 100644 --- a/gnu/llvm/lldb/source/Utility/DataBufferLLVM.cpp +++ b/gnu/llvm/lldb/source/Utility/DataBufferLLVM.cpp @@ -10,7 +10,7 @@ #include "llvm/Support/MemoryBuffer.h" -#include +#include using namespace lldb_private; @@ -21,7 +21,7 @@ DataBufferLLVM::DataBufferLLVM( "Cannot construct a DataBufferLLVM with a null buffer"); } -DataBufferLLVM::~DataBufferLLVM() {} +DataBufferLLVM::~DataBufferLLVM() = default; uint8_t *DataBufferLLVM::GetBytes() { return reinterpret_cast(Buffer->getBufferStart()); diff --git a/gnu/llvm/lldb/source/Utility/DataEncoder.cpp b/gnu/llvm/lldb/source/Utility/DataEncoder.cpp index 7532ac1fdca..e88cd23c1d8 100644 --- a/gnu/llvm/lldb/source/Utility/DataEncoder.cpp +++ b/gnu/llvm/lldb/source/Utility/DataEncoder.cpp @@ -16,7 +16,7 @@ #include -#include +#include using namespace lldb; using namespace lldb_private; @@ -24,8 +24,7 @@ using namespace llvm::support::endian; // Default constructor. DataEncoder::DataEncoder() - : m_start(nullptr), m_end(nullptr), - m_byte_order(endian::InlHostByteOrder()), m_addr_size(sizeof(void *)), + : m_byte_order(endian::InlHostByteOrder()), m_addr_size(sizeof(void *)), m_data_sp() {} // This constructor allows us to use data that is owned by someone else. The diff --git a/gnu/llvm/lldb/source/Utility/DataExtractor.cpp b/gnu/llvm/lldb/source/Utility/DataExtractor.cpp index 64b878d7dee..bdd79fd9b41 100644 --- a/gnu/llvm/lldb/source/Utility/DataExtractor.cpp +++ b/gnu/llvm/lldb/source/Utility/DataExtractor.cpp @@ -33,9 +33,9 @@ #include #include -#include -#include -#include +#include +#include +#include using namespace lldb; using namespace lldb_private; @@ -120,9 +120,8 @@ static inline uint64_t ReadMaxInt64(const uint8_t *data, size_t byte_size, } DataExtractor::DataExtractor() - : m_start(nullptr), m_end(nullptr), - m_byte_order(endian::InlHostByteOrder()), m_addr_size(sizeof(void *)), - m_data_sp(), m_target_byte_size(1) {} + : m_byte_order(endian::InlHostByteOrder()), m_addr_size(sizeof(void *)), + m_data_sp() {} // This constructor allows us to use data that is owned by someone else. The // data must stay around as long as this object is valid. diff --git a/gnu/llvm/lldb/source/Utility/Event.cpp b/gnu/llvm/lldb/source/Utility/Event.cpp index 50cc7f061dc..4c07293c92d 100644 --- a/gnu/llvm/lldb/source/Utility/Event.cpp +++ b/gnu/llvm/lldb/source/Utility/Event.cpp @@ -17,7 +17,7 @@ #include -#include +#include using namespace lldb; using namespace lldb_private; @@ -198,7 +198,7 @@ EventDataStructuredData::EventDataStructuredData( : EventData(), m_process_sp(process_sp), m_object_sp(object_sp), m_plugin_sp(plugin_sp) {} -EventDataStructuredData::~EventDataStructuredData() {} +EventDataStructuredData::~EventDataStructuredData() = default; // EventDataStructuredData member functions diff --git a/gnu/llvm/lldb/source/Utility/FileSpec.cpp b/gnu/llvm/lldb/source/Utility/FileSpec.cpp index 1ec5d60e278..bea3c6d6268 100644 --- a/gnu/llvm/lldb/source/Utility/FileSpec.cpp +++ b/gnu/llvm/lldb/source/Utility/FileSpec.cpp @@ -24,10 +24,10 @@ #include #include -#include -#include -#include -#include +#include +#include +#include +#include using namespace lldb; using namespace lldb_private; @@ -499,9 +499,9 @@ void FileSpec::MakeAbsolute(const FileSpec &dir) { void llvm::format_provider::format(const FileSpec &F, raw_ostream &Stream, StringRef Style) { - assert( - (Style.empty() || Style.equals_lower("F") || Style.equals_lower("D")) && - "Invalid FileSpec style!"); + assert((Style.empty() || Style.equals_insensitive("F") || + Style.equals_insensitive("D")) && + "Invalid FileSpec style!"); StringRef dir = F.GetDirectory().GetStringRef(); StringRef file = F.GetFilename().GetStringRef(); @@ -511,7 +511,7 @@ void llvm::format_provider::format(const FileSpec &F, return; } - if (Style.equals_lower("F")) { + if (Style.equals_insensitive("F")) { Stream << (file.empty() ? "(empty)" : file); return; } @@ -527,7 +527,7 @@ void llvm::format_provider::format(const FileSpec &F, Stream << GetPreferredPathSeparator(F.GetPathStyle()); } - if (Style.equals_lower("D")) { + if (Style.equals_insensitive("D")) { // We only want to print the directory, so now just exit. if (dir.empty()) Stream << "(empty)"; diff --git a/gnu/llvm/lldb/source/Utility/GDBRemote.cpp b/gnu/llvm/lldb/source/Utility/GDBRemote.cpp index f267d00fc97..91f94de4dc0 100644 --- a/gnu/llvm/lldb/source/Utility/GDBRemote.cpp +++ b/gnu/llvm/lldb/source/Utility/GDBRemote.cpp @@ -11,7 +11,7 @@ #include "lldb/Utility/Flags.h" #include "lldb/Utility/Stream.h" -#include +#include using namespace lldb; using namespace lldb_private::repro; @@ -24,7 +24,7 @@ StreamGDBRemote::StreamGDBRemote(uint32_t flags, uint32_t addr_size, ByteOrder byte_order) : StreamString(flags, addr_size, byte_order) {} -StreamGDBRemote::~StreamGDBRemote() {} +StreamGDBRemote::~StreamGDBRemote() = default; int StreamGDBRemote::PutEscapedBytes(const void *s, size_t src_len) { int bytes_written = 0; @@ -104,7 +104,7 @@ void GDBRemoteProvider::Keep() { FileSpec file = GetRoot().CopyByAppendingPathComponent(Info::file); std::error_code ec; - llvm::raw_fd_ostream os(file.GetPath(), ec, llvm::sys::fs::OF_Text); + llvm::raw_fd_ostream os(file.GetPath(), ec, llvm::sys::fs::OF_TextWithCRLF); if (ec) return; yaml::Output yout(os); @@ -150,8 +150,8 @@ llvm::raw_ostream *GDBRemoteProvider::GetHistoryStream() { FileSpec history_file = GetRoot().CopyByAppendingPathComponent(Info::file); std::error_code EC; - m_stream_up = std::make_unique(history_file.GetPath(), EC, - sys::fs::OpenFlags::OF_Text); + m_stream_up = std::make_unique( + history_file.GetPath(), EC, sys::fs::OpenFlags::OF_TextWithCRLF); return m_stream_up.get(); } diff --git a/gnu/llvm/lldb/source/Utility/LLDBAssert.cpp b/gnu/llvm/lldb/source/Utility/LLDBAssert.cpp index 6ae0ee50ef1..a8d8ef65a94 100644 --- a/gnu/llvm/lldb/source/Utility/LLDBAssert.cpp +++ b/gnu/llvm/lldb/source/Utility/LLDBAssert.cpp @@ -7,11 +7,15 @@ //===----------------------------------------------------------------------===// #include "lldb/Utility/LLDBAssert.h" - +#include "llvm/Config/llvm-config.h" #include "llvm/Support/Format.h" #include "llvm/Support/Signals.h" #include "llvm/Support/raw_ostream.h" +#if LLVM_SUPPORT_XCODE_SIGNPOSTS +#include +#endif + using namespace llvm; using namespace lldb_private; @@ -24,6 +28,14 @@ void lldb_private::lldb_assert(bool expression, const char *expr_text, // If asserts are enabled abort here. assert(false && "lldb_assert failed"); +#if LLVM_SUPPORT_XCODE_SIGNPOSTS + if (__builtin_available(macos 10.12, iOS 10, tvOS 10, watchOS 3, *)) { + os_log_fault(OS_LOG_DEFAULT, + "Assertion failed: (%s), function %s, file %s, line %u\n", + expr_text, func, file, line); + } +#endif + // In a release configuration it will print a warning and encourage the user // to file a bug report, similar to LLVM’s crash handler, and then return // execution. diff --git a/gnu/llvm/lldb/source/Utility/Log.cpp b/gnu/llvm/lldb/source/Utility/Log.cpp index 4df82f2bf4d..ff654ec93e7 100644 --- a/gnu/llvm/lldb/source/Utility/Log.cpp +++ b/gnu/llvm/lldb/source/Utility/Log.cpp @@ -25,7 +25,7 @@ #include #include -#include +#include #if defined(_WIN32) #include #else @@ -60,17 +60,18 @@ uint32_t Log::GetFlags(llvm::raw_ostream &stream, const ChannelMap::value_type & bool list_categories = false; uint32_t flags = 0; for (const char *category : categories) { - if (llvm::StringRef("all").equals_lower(category)) { + if (llvm::StringRef("all").equals_insensitive(category)) { flags |= UINT32_MAX; continue; } - if (llvm::StringRef("default").equals_lower(category)) { + if (llvm::StringRef("default").equals_insensitive(category)) { flags |= entry.second.m_channel.default_flags; continue; } - auto cat = llvm::find_if( - entry.second.m_channel.categories, - [&](const Log::Category &c) { return c.name.equals_lower(category); }); + auto cat = llvm::find_if(entry.second.m_channel.categories, + [&](const Log::Category &c) { + return c.name.equals_insensitive(category); + }); if (cat != entry.second.m_channel.categories.end()) { flags |= cat->flag; continue; diff --git a/gnu/llvm/lldb/source/Utility/Logging.cpp b/gnu/llvm/lldb/source/Utility/Logging.cpp index 435017e9d74..4648bec502c 100644 --- a/gnu/llvm/lldb/source/Utility/Logging.cpp +++ b/gnu/llvm/lldb/source/Utility/Logging.cpp @@ -11,7 +11,7 @@ #include "llvm/ADT/ArrayRef.h" -#include +#include using namespace lldb_private; diff --git a/gnu/llvm/lldb/source/Utility/ProcessInfo.cpp b/gnu/llvm/lldb/source/Utility/ProcessInfo.cpp index aae48d6a487..c9759bbe513 100644 --- a/gnu/llvm/lldb/source/Utility/ProcessInfo.cpp +++ b/gnu/llvm/lldb/source/Utility/ProcessInfo.cpp @@ -9,6 +9,7 @@ #include "lldb/Utility/ProcessInfo.h" #include "lldb/Utility/ArchSpec.h" +#include "lldb/Utility/ReproducerProvider.h" #include "lldb/Utility/Stream.h" #include "lldb/Utility/StreamString.h" #include "lldb/Utility/UserIDResolver.h" @@ -21,8 +22,7 @@ using namespace lldb_private; using namespace lldb_private::repro; ProcessInfo::ProcessInfo() - : m_executable(), m_arguments(), m_environment(), m_uid(UINT32_MAX), - m_gid(UINT32_MAX), m_arch(), m_pid(LLDB_INVALID_PROCESS_ID) {} + : m_executable(), m_arguments(), m_environment(), m_arch() {} ProcessInfo::ProcessInfo(const char *name, const ArchSpec &arch, lldb::pid_t pid) @@ -347,57 +347,6 @@ void llvm::yaml::MappingTraits::mapping( io.mapRequired("parent-pid", Info.m_parent_pid); } -llvm::Expected> -ProcessInfoRecorder::Create(const FileSpec &filename) { - std::error_code ec; - auto recorder = - std::make_unique(std::move(filename), ec); - if (ec) - return llvm::errorCodeToError(ec); - return std::move(recorder); -} - -void ProcessInfoProvider::Keep() { - std::vector files; - for (auto &recorder : m_process_info_recorders) { - recorder->Stop(); - files.push_back(recorder->GetFilename().GetPath()); - } - - FileSpec file = GetRoot().CopyByAppendingPathComponent(Info::file); - std::error_code ec; - llvm::raw_fd_ostream os(file.GetPath(), ec, llvm::sys::fs::OF_Text); - if (ec) - return; - llvm::yaml::Output yout(os); - yout << files; -} - -void ProcessInfoProvider::Discard() { m_process_info_recorders.clear(); } - -ProcessInfoRecorder *ProcessInfoProvider::GetNewProcessInfoRecorder() { - std::size_t i = m_process_info_recorders.size() + 1; - std::string filename = (llvm::Twine(Info::name) + llvm::Twine("-") + - llvm::Twine(i) + llvm::Twine(".yaml")) - .str(); - auto recorder_or_error = ProcessInfoRecorder::Create( - GetRoot().CopyByAppendingPathComponent(filename)); - if (!recorder_or_error) { - llvm::consumeError(recorder_or_error.takeError()); - return nullptr; - } - - m_process_info_recorders.push_back(std::move(*recorder_or_error)); - return m_process_info_recorders.back().get(); -} - -void ProcessInfoRecorder::Record(const ProcessInstanceInfoList &process_infos) { - if (!m_record) - return; - llvm::yaml::Output yout(m_os); - yout << const_cast(process_infos); - m_os.flush(); -} llvm::Optional repro::GetReplayProcessInstanceInfoList() { @@ -425,7 +374,3 @@ repro::GetReplayProcessInstanceInfoList() { return infos; } - -char ProcessInfoProvider::ID = 0; -const char *ProcessInfoProvider::Info::file = "process-info.yaml"; -const char *ProcessInfoProvider::Info::name = "process-info"; diff --git a/gnu/llvm/lldb/source/Utility/RegisterValue.cpp b/gnu/llvm/lldb/source/Utility/RegisterValue.cpp index 7f545c214a4..a298c70d370 100644 --- a/gnu/llvm/lldb/source/Utility/RegisterValue.cpp +++ b/gnu/llvm/lldb/source/Utility/RegisterValue.cpp @@ -24,9 +24,9 @@ #include #include -#include -#include -#include +#include +#include +#include using namespace lldb; using namespace lldb_private; @@ -138,36 +138,10 @@ bool RegisterValue::GetScalarValue(Scalar &scalar) const { case eTypeInvalid: break; case eTypeBytes: { - switch (buffer.length) { - default: - break; - case 1: - scalar = *(const uint8_t *)buffer.bytes; - return true; - case 2: - scalar = *reinterpret_cast(buffer.bytes); - return true; - case 4: - scalar = *reinterpret_cast(buffer.bytes); + DataExtractor data(buffer.bytes, buffer.length, buffer.byte_order, 1); + if (scalar.SetValueFromData(data, lldb::eEncodingUint, + buffer.length).Success()) return true; - case 8: - scalar = *reinterpret_cast(buffer.bytes); - return true; - case 16: - case 32: - case 64: - if (buffer.length % sizeof(uint64_t) == 0) { - const auto length_in_bits = buffer.length * 8; - const auto length_in_uint64 = buffer.length / sizeof(uint64_t); - scalar = - llvm::APInt(length_in_bits, - llvm::ArrayRef( - reinterpret_cast(buffer.bytes), - length_in_uint64)); - return true; - } - break; - } } break; case eTypeUInt8: case eTypeUInt16: diff --git a/gnu/llvm/lldb/source/Utility/Reproducer.cpp b/gnu/llvm/lldb/source/Utility/Reproducer.cpp index 7620ab2c389..b63863c535f 100644 --- a/gnu/llvm/lldb/source/Utility/Reproducer.cpp +++ b/gnu/llvm/lldb/source/Utility/Reproducer.cpp @@ -8,6 +8,8 @@ #include "lldb/Utility/Reproducer.h" #include "lldb/Utility/LLDBAssert.h" +#include "lldb/Utility/ReproducerProvider.h" +#include "lldb/Utility/Timer.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Threading.h" @@ -18,15 +20,6 @@ using namespace lldb_private::repro; using namespace llvm; using namespace llvm::yaml; -static llvm::Optional GetEnv(const char *var) { - std::string val = llvm::StringRef(getenv(var)).lower(); - if (val == "0" || val == "off") - return false; - if (val == "1" || val == "on") - return true; - return {}; -} - Reproducer &Reproducer::Instance() { return *InstanceImpl(); } llvm::Error Reproducer::Initialize(ReproducerMode mode, @@ -34,16 +27,6 @@ llvm::Error Reproducer::Initialize(ReproducerMode mode, lldbassert(!InstanceImpl() && "Already initialized."); InstanceImpl().emplace(); - // The environment can override the capture mode. - if (mode != ReproducerMode::Replay) { - if (llvm::Optional override = GetEnv("LLDB_CAPTURE_REPRODUCER")) { - if (*override) - mode = ReproducerMode::Capture; - else - mode = ReproducerMode::Off; - } - } - switch (mode) { case ReproducerMode::Capture: { if (!root) { @@ -72,6 +55,10 @@ llvm::Error Reproducer::Initialize(ReproducerMode mode, return Error::success(); } +void Reproducer::Initialize() { + llvm::cantFail(Initialize(repro::ReproducerMode::Off, llvm::None)); +} + bool Reproducer::Initialized() { return InstanceImpl().operator bool(); } void Reproducer::Terminate() { @@ -157,7 +144,7 @@ FileSpec Reproducer::GetReproducerPath() const { return {}; } -static FileSpec MakeAbsolute(FileSpec file_spec) { +static FileSpec MakeAbsolute(const FileSpec &file_spec) { SmallString<128> path; file_spec.GetPath(path, false); llvm::sys::fs::make_absolute(path); @@ -166,14 +153,17 @@ static FileSpec MakeAbsolute(FileSpec file_spec) { Generator::Generator(FileSpec root) : m_root(MakeAbsolute(std::move(root))) { GetOrCreate(); + GetOrCreate(); } Generator::~Generator() { if (!m_done) { - if (m_auto_generate) + if (m_auto_generate) { Keep(); - else + llvm::cantFail(Finalize(GetRoot())); + } else { Discard(); + } } } @@ -186,6 +176,7 @@ ProviderBase *Generator::Register(std::unique_ptr provider) { } void Generator::Keep() { + LLDB_SCOPED_TIMER(); assert(!m_done); m_done = true; @@ -196,6 +187,7 @@ void Generator::Keep() { } void Generator::Discard() { + LLDB_SCOPED_TIMER(); assert(!m_done); m_done = true; @@ -263,58 +255,148 @@ bool Loader::HasFile(StringRef file) { return (it != m_files.end()) && (*it == file); } -llvm::Expected> -DataRecorder::Create(const FileSpec &filename) { - std::error_code ec; - auto recorder = std::make_unique(std::move(filename), ec); - if (ec) - return llvm::errorCodeToError(ec); - return std::move(recorder); -} +void Verifier::Verify( + llvm::function_ref error_callback, + llvm::function_ref warning_callback, + llvm::function_ref note_callack) const { + if (!m_loader) { + error_callback("invalid loader"); + return; + } -llvm::Expected> -YamlRecorder::Create(const FileSpec &filename) { - std::error_code ec; - auto recorder = std::make_unique(std::move(filename), ec); - if (ec) - return llvm::errorCodeToError(ec); - return std::move(recorder); -} + FileSpec vfs_mapping = m_loader->GetFile(); + ErrorOr> buffer = + vfs::getRealFileSystem()->getBufferForFile(vfs_mapping.GetPath()); + if (!buffer) { + error_callback("unable to read files: " + buffer.getError().message()); + return; + } -void VersionProvider::Keep() { - FileSpec file = GetRoot().CopyByAppendingPathComponent(Info::file); - std::error_code ec; - llvm::raw_fd_ostream os(file.GetPath(), ec, llvm::sys::fs::OF_Text); - if (ec) + IntrusiveRefCntPtr vfs = vfs::getVFSFromYAML( + std::move(buffer.get()), nullptr, vfs_mapping.GetPath()); + if (!vfs) { + error_callback("unable to initialize the virtual file system"); return; - os << m_version << "\n"; + } + + auto &redirecting_vfs = static_cast(*vfs); + redirecting_vfs.setFallthrough(false); + + { + llvm::Expected working_dir = + GetDirectoryFrom(m_loader); + if (working_dir) { + if (!vfs->exists(*working_dir)) + warning_callback("working directory '" + *working_dir + "' not in VFS"); + vfs->setCurrentWorkingDirectory(*working_dir); + } else { + warning_callback("no working directory in reproducer: " + + toString(working_dir.takeError())); + } + } + + { + llvm::Expected home_dir = + GetDirectoryFrom(m_loader); + if (home_dir) { + if (!vfs->exists(*home_dir)) + warning_callback("home directory '" + *home_dir + "' not in VFS"); + } else { + warning_callback("no home directory in reproducer: " + + toString(home_dir.takeError())); + } + } + + { + Expected symbol_files = + m_loader->LoadBuffer(); + if (symbol_files) { + std::vector entries; + llvm::yaml::Input yin(*symbol_files); + yin >> entries; + for (const auto &entry : entries) { + if (!entry.module_path.empty() && !vfs->exists(entry.module_path)) { + warning_callback("'" + entry.module_path + "': module path for " + + entry.uuid + " not in VFS"); + } + if (!entry.symbol_path.empty() && !vfs->exists(entry.symbol_path)) { + warning_callback("'" + entry.symbol_path + "': symbol path for " + + entry.uuid + " not in VFS"); + } + } + } else { + llvm::consumeError(symbol_files.takeError()); + } + } + + // Missing files in the VFS are notes rather than warnings. Because the VFS + // is a snapshot, temporary files could have been removed between when they + // were recorded and when the reproducer was generated. + std::vector roots = redirecting_vfs.getRoots(); + for (llvm::StringRef root : roots) { + std::error_code ec; + vfs::recursive_directory_iterator iter(*vfs, root, ec); + vfs::recursive_directory_iterator end; + for (; iter != end && !ec; iter.increment(ec)) { + ErrorOr status = vfs->status(iter->path()); + if (!status) + note_callack("'" + iter->path().str() + + "': " + status.getError().message()); + } + } } -void WorkingDirectoryProvider::Keep() { - FileSpec file = GetRoot().CopyByAppendingPathComponent(Info::file); - std::error_code ec; - llvm::raw_fd_ostream os(file.GetPath(), ec, llvm::sys::fs::OF_Text); - if (ec) - return; - os << m_cwd << "\n"; +static llvm::Error addPaths(StringRef path, + function_ref callback) { + auto buffer = llvm::MemoryBuffer::getFile(path); + if (!buffer) + return errorCodeToError(buffer.getError()); + + SmallVector paths; + (*buffer)->getBuffer().split(paths, '\0'); + for (StringRef p : paths) { + if (!p.empty() && llvm::sys::fs::exists(p)) + callback(p); + } + + return errorCodeToError(llvm::sys::fs::remove(path)); } -void FileProvider::recordInterestingDirectory(const llvm::Twine &dir) { - if (m_collector) - m_collector->addDirectory(dir); +llvm::Error repro::Finalize(Loader *loader) { + if (!loader) + return make_error("invalid loader", + llvm::inconvertibleErrorCode()); + + FileSpec reproducer_root = loader->GetRoot(); + std::string files_path = + reproducer_root.CopyByAppendingPathComponent("files.txt").GetPath(); + std::string dirs_path = + reproducer_root.CopyByAppendingPathComponent("dirs.txt").GetPath(); + + FileCollector collector( + reproducer_root.CopyByAppendingPathComponent("root").GetPath(), + reproducer_root.GetPath()); + + if (Error e = + addPaths(files_path, [&](StringRef p) { collector.addFile(p); })) + return e; + + if (Error e = + addPaths(dirs_path, [&](StringRef p) { collector.addDirectory(p); })) + return e; + + FileSpec mapping = + reproducer_root.CopyByAppendingPathComponent(FileProvider::Info::file); + if (auto ec = collector.copyFiles(/*stop_on_error=*/false)) + return errorCodeToError(ec); + collector.writeMapping(mapping.GetPath()); + + return llvm::Error::success(); } -void ProviderBase::anchor() {} -char CommandProvider::ID = 0; -char FileProvider::ID = 0; -char ProviderBase::ID = 0; -char VersionProvider::ID = 0; -char WorkingDirectoryProvider::ID = 0; -const char *CommandProvider::Info::file = "command-interpreter.yaml"; -const char *CommandProvider::Info::name = "command-interpreter"; -const char *FileProvider::Info::file = "files.yaml"; -const char *FileProvider::Info::name = "files"; -const char *VersionProvider::Info::file = "version.txt"; -const char *VersionProvider::Info::name = "version"; -const char *WorkingDirectoryProvider::Info::file = "cwd.txt"; -const char *WorkingDirectoryProvider::Info::name = "cwd"; +llvm::Error repro::Finalize(const FileSpec &root) { + Loader loader(root); + if (Error e = loader.LoadIndex()) + return e; + return Finalize(&loader); +} diff --git a/gnu/llvm/lldb/source/Utility/ReproducerInstrumentation.cpp b/gnu/llvm/lldb/source/Utility/ReproducerInstrumentation.cpp index 09aea69d831..e5bd2ba4b62 100644 --- a/gnu/llvm/lldb/source/Utility/ReproducerInstrumentation.cpp +++ b/gnu/llvm/lldb/source/Utility/ReproducerInstrumentation.cpp @@ -8,8 +8,9 @@ #include "lldb/Utility/ReproducerInstrumentation.h" #include "lldb/Utility/Reproducer.h" -#include -#include +#include +#include +#include #include using namespace lldb_private; @@ -84,6 +85,16 @@ template <> const char **Deserializer::Deserialize() { return r; } +void Deserializer::CheckSequence(unsigned sequence) { + if (m_expected_sequence && *m_expected_sequence != sequence) + llvm::report_fatal_error( + "The result does not match the preceding " + "function. This is probably the result of concurrent " + "use of the SB API during capture, which is currently not " + "supported."); + m_expected_sequence.reset(); +} + bool Registry::Replay(const FileSpec &file) { auto error_or_file = llvm::MemoryBuffer::getFile(file.GetPath()); if (auto err = error_or_file.getError()) @@ -107,6 +118,7 @@ bool Registry::Replay(Deserializer &deserializer) { setvbuf(stdout, nullptr, _IONBF, 0); while (deserializer.HasData(1)) { + unsigned sequence = deserializer.Deserialize(); unsigned id = deserializer.Deserialize(); #ifndef LLDB_REPRO_INSTR_TRACE @@ -115,6 +127,7 @@ bool Registry::Replay(Deserializer &deserializer) { llvm::errs() << "Replaying " << id << ": " << GetSignature(id) << "\n"; #endif + deserializer.SetExpectedSequence(sequence); GetReplayer(id)->operator()(deserializer); } @@ -180,22 +193,25 @@ unsigned ObjectToIndex::GetIndexForObjectImpl(const void *object) { } Recorder::Recorder() - : m_serializer(nullptr), m_pretty_func(), m_pretty_args(), - m_local_boundary(false), m_result_recorded(true) { + : m_pretty_func(), m_pretty_args(), + + m_sequence(std::numeric_limits::max()) { if (!g_global_boundary) { g_global_boundary = true; m_local_boundary = true; + m_sequence = GetNextSequenceNumber(); } } Recorder::Recorder(llvm::StringRef pretty_func, std::string &&pretty_args) : m_serializer(nullptr), m_pretty_func(pretty_func), m_pretty_args(pretty_args), m_local_boundary(false), - m_result_recorded(true) { + m_result_recorded(true), + m_sequence(std::numeric_limits::max()) { if (!g_global_boundary) { g_global_boundary = true; m_local_boundary = true; - + m_sequence = GetNextSequenceNumber(); LLDB_LOG(GetLogIfAllCategoriesSet(LIBLLDB_LOG_API), "{0} ({1})", m_pretty_func, m_pretty_args); } @@ -206,6 +222,11 @@ Recorder::~Recorder() { UpdateBoundary(); } +unsigned Recorder::GetSequenceNumber() const { + assert(m_sequence != std::numeric_limits::max()); + return m_sequence; +} + void InstrumentationData::Initialize(Serializer &serializer, Registry ®istry) { InstanceImpl().emplace(serializer, registry); @@ -227,4 +248,6 @@ llvm::Optional &InstrumentationData::InstanceImpl() { return g_instrumentation_data; } -bool lldb_private::repro::Recorder::g_global_boundary; +thread_local bool lldb_private::repro::Recorder::g_global_boundary = false; +std::atomic lldb_private::repro::Recorder::g_sequence; +std::mutex lldb_private::repro::Recorder::g_mutex; diff --git a/gnu/llvm/lldb/source/Utility/ReproducerProvider.cpp b/gnu/llvm/lldb/source/Utility/ReproducerProvider.cpp new file mode 100644 index 00000000000..5145819b717 --- /dev/null +++ b/gnu/llvm/lldb/source/Utility/ReproducerProvider.cpp @@ -0,0 +1,221 @@ +//===-- Reproducer.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 "lldb/Utility/ReproducerProvider.h" +#include "lldb/Utility/ProcessInfo.h" +#include "llvm/ADT/ScopeExit.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/WithColor.h" +#include "llvm/Support/raw_ostream.h" + +using namespace lldb_private; +using namespace lldb_private::repro; +using namespace llvm; +using namespace llvm::yaml; + +llvm::Expected> +DataRecorder::Create(const FileSpec &filename) { + std::error_code ec; + auto recorder = std::make_unique(std::move(filename), ec); + if (ec) + return llvm::errorCodeToError(ec); + return std::move(recorder); +} + +llvm::Expected> +YamlRecorder::Create(const FileSpec &filename) { + std::error_code ec; + auto recorder = std::make_unique(std::move(filename), ec); + if (ec) + return llvm::errorCodeToError(ec); + return std::move(recorder); +} + +void VersionProvider::Keep() { + FileSpec file = GetRoot().CopyByAppendingPathComponent(Info::file); + std::error_code ec; + llvm::raw_fd_ostream os(file.GetPath(), ec, llvm::sys::fs::OF_TextWithCRLF); + if (ec) + return; + os << m_version << "\n"; +} + +FlushingFileCollector::FlushingFileCollector(llvm::StringRef files_path, + llvm::StringRef dirs_path, + std::error_code &ec) { + auto clear = llvm::make_scope_exit([this]() { + m_files_os.reset(); + m_dirs_os.reset(); + }); + m_files_os.emplace(files_path, ec, llvm::sys::fs::OF_Append); + if (ec) + return; + m_dirs_os.emplace(dirs_path, ec, llvm::sys::fs::OF_Append); + if (ec) + return; + clear.release(); +} + +void FlushingFileCollector::addFileImpl(StringRef file) { + if (m_files_os) { + *m_files_os << file << '\0'; + m_files_os->flush(); + } +} + +llvm::vfs::directory_iterator +FlushingFileCollector::addDirectoryImpl(const Twine &dir, + IntrusiveRefCntPtr vfs, + std::error_code &dir_ec) { + if (m_dirs_os) { + *m_dirs_os << dir << '\0'; + m_dirs_os->flush(); + } + return vfs->dir_begin(dir, dir_ec); +} + +void FileProvider::RecordInterestingDirectory(const llvm::Twine &dir) { + if (m_collector) + m_collector->addFile(dir); +} + +void FileProvider::RecordInterestingDirectoryRecursive(const llvm::Twine &dir) { + if (m_collector) + m_collector->addDirectory(dir); +} + +llvm::Expected> +ProcessInfoRecorder::Create(const FileSpec &filename) { + std::error_code ec; + auto recorder = + std::make_unique(std::move(filename), ec); + if (ec) + return llvm::errorCodeToError(ec); + return std::move(recorder); +} + +void ProcessInfoProvider::Keep() { + std::vector files; + for (auto &recorder : m_process_info_recorders) { + recorder->Stop(); + files.push_back(recorder->GetFilename().GetPath()); + } + + FileSpec file = GetRoot().CopyByAppendingPathComponent(Info::file); + std::error_code ec; + llvm::raw_fd_ostream os(file.GetPath(), ec, llvm::sys::fs::OF_TextWithCRLF); + if (ec) + return; + llvm::yaml::Output yout(os); + yout << files; +} + +void ProcessInfoProvider::Discard() { m_process_info_recorders.clear(); } + +ProcessInfoRecorder *ProcessInfoProvider::GetNewProcessInfoRecorder() { + std::size_t i = m_process_info_recorders.size() + 1; + std::string filename = (llvm::Twine(Info::name) + llvm::Twine("-") + + llvm::Twine(i) + llvm::Twine(".yaml")) + .str(); + auto recorder_or_error = ProcessInfoRecorder::Create( + GetRoot().CopyByAppendingPathComponent(filename)); + if (!recorder_or_error) { + llvm::consumeError(recorder_or_error.takeError()); + return nullptr; + } + + m_process_info_recorders.push_back(std::move(*recorder_or_error)); + return m_process_info_recorders.back().get(); +} + +void ProcessInfoRecorder::Record(const ProcessInstanceInfoList &process_infos) { + if (!m_record) + return; + llvm::yaml::Output yout(m_os); + yout << const_cast(process_infos); + m_os.flush(); +} + +void SymbolFileProvider::AddSymbolFile(const UUID *uuid, + const FileSpec &module_file, + const FileSpec &symbol_file) { + if (!uuid || (!module_file && !symbol_file)) + return; + m_symbol_files.emplace_back(uuid->GetAsString(), module_file.GetPath(), + symbol_file.GetPath()); +} + +void SymbolFileProvider::Keep() { + FileSpec file = this->GetRoot().CopyByAppendingPathComponent(Info::file); + std::error_code ec; + llvm::raw_fd_ostream os(file.GetPath(), ec, llvm::sys::fs::OF_TextWithCRLF); + if (ec) + return; + + // Remove duplicates. + llvm::sort(m_symbol_files.begin(), m_symbol_files.end()); + m_symbol_files.erase( + std::unique(m_symbol_files.begin(), m_symbol_files.end()), + m_symbol_files.end()); + + llvm::yaml::Output yout(os); + yout << m_symbol_files; +} + +SymbolFileLoader::SymbolFileLoader(Loader *loader) { + if (!loader) + return; + + FileSpec file = loader->GetFile(); + if (!file) + return; + + auto error_or_file = llvm::MemoryBuffer::getFile(file.GetPath()); + if (auto err = error_or_file.getError()) + return; + + llvm::yaml::Input yin((*error_or_file)->getBuffer()); + yin >> m_symbol_files; +} + +std::pair +SymbolFileLoader::GetPaths(const UUID *uuid) const { + if (!uuid) + return {}; + + auto it = std::lower_bound(m_symbol_files.begin(), m_symbol_files.end(), + SymbolFileProvider::Entry(uuid->GetAsString())); + if (it == m_symbol_files.end()) + return {}; + return std::make_pair(FileSpec(it->module_path), + FileSpec(it->symbol_path)); +} + +void ProviderBase::anchor() {} +char CommandProvider::ID = 0; +char FileProvider::ID = 0; +char ProviderBase::ID = 0; +char VersionProvider::ID = 0; +char WorkingDirectoryProvider::ID = 0; +char HomeDirectoryProvider::ID = 0; +char ProcessInfoProvider::ID = 0; +char SymbolFileProvider::ID = 0; +const char *CommandProvider::Info::file = "command-interpreter.yaml"; +const char *CommandProvider::Info::name = "command-interpreter"; +const char *FileProvider::Info::file = "files.yaml"; +const char *FileProvider::Info::name = "files"; +const char *VersionProvider::Info::file = "version.txt"; +const char *VersionProvider::Info::name = "version"; +const char *WorkingDirectoryProvider::Info::file = "cwd.txt"; +const char *WorkingDirectoryProvider::Info::name = "cwd"; +const char *HomeDirectoryProvider::Info::file = "home.txt"; +const char *HomeDirectoryProvider::Info::name = "home"; +const char *ProcessInfoProvider::Info::file = "process-info.yaml"; +const char *ProcessInfoProvider::Info::name = "process-info"; +const char *SymbolFileProvider::Info::file = "symbol-files.yaml"; +const char *SymbolFileProvider::Info::name = "symbol-files"; diff --git a/gnu/llvm/lldb/source/Utility/Scalar.cpp b/gnu/llvm/lldb/source/Utility/Scalar.cpp index 6c48bbde532..e0b26e89f3c 100644 --- a/gnu/llvm/lldb/source/Utility/Scalar.cpp +++ b/gnu/llvm/lldb/source/Utility/Scalar.cpp @@ -25,109 +25,62 @@ using namespace lldb_private; using llvm::APFloat; using llvm::APInt; +using llvm::APSInt; -namespace { -enum class Category { Void, Integral, Float }; -} - -static Category GetCategory(Scalar::Type type) { - switch (type) { - case Scalar::e_void: - return Category::Void; - case Scalar::e_float: - case Scalar::e_double: - case Scalar::e_long_double: - return Category::Float; - case Scalar::e_sint: - case Scalar::e_slong: - case Scalar::e_slonglong: - case Scalar::e_sint128: - case Scalar::e_sint256: - case Scalar::e_sint512: - case Scalar::e_uint: - case Scalar::e_ulong: - case Scalar::e_ulonglong: - case Scalar::e_uint128: - case Scalar::e_uint256: - case Scalar::e_uint512: - return Category::Integral; +Scalar::PromotionKey Scalar::GetPromoKey() const { + switch (m_type) { + case e_void: + return PromotionKey{e_void, 0, false}; + case e_int: + return PromotionKey{e_int, m_integer.getBitWidth(), m_integer.isUnsigned()}; + case e_float: + return GetFloatPromoKey(m_float.getSemantics()); } - llvm_unreachable("Unhandled type!"); + llvm_unreachable("Unhandled category!"); } -static bool IsSigned(Scalar::Type type) { - switch (type) { - case Scalar::e_void: - case Scalar::e_uint: - case Scalar::e_ulong: - case Scalar::e_ulonglong: - case Scalar::e_uint128: - case Scalar::e_uint256: - case Scalar::e_uint512: - return false; - case Scalar::e_sint: - case Scalar::e_slong: - case Scalar::e_slonglong: - case Scalar::e_sint128: - case Scalar::e_sint256: - case Scalar::e_sint512: - case Scalar::e_float: - case Scalar::e_double: - case Scalar::e_long_double: - return true; +Scalar::PromotionKey Scalar::GetFloatPromoKey(const llvm::fltSemantics &sem) { + static const llvm::fltSemantics *const order[] = { + &APFloat::IEEEsingle(), &APFloat::IEEEdouble(), + &APFloat::x87DoubleExtended()}; + for (const auto &entry : llvm::enumerate(order)) { + if (entry.value() == &sem) + return PromotionKey{e_float, entry.index(), false}; } - llvm_unreachable("Unhandled type!"); + llvm_unreachable("Unsupported semantics!"); } - // Promote to max type currently follows the ANSI C rule for type promotion in // expressions. -static Scalar::Type PromoteToMaxType( - const Scalar &lhs, // The const left hand side object - const Scalar &rhs, // The const right hand side object - Scalar &temp_value, // A modifiable temp value than can be used to hold - // either the promoted lhs or rhs object - const Scalar *&promoted_lhs_ptr, // Pointer to the resulting possibly - // promoted value of lhs (at most one of - // lhs/rhs will get promoted) - const Scalar *&promoted_rhs_ptr // Pointer to the resulting possibly - // promoted value of rhs (at most one of - // lhs/rhs will get promoted) -) { - Scalar result; - // Initialize the promoted values for both the right and left hand side - // values to be the objects themselves. If no promotion is needed (both right - // and left have the same type), then the temp_value will not get used. - promoted_lhs_ptr = &lhs; - promoted_rhs_ptr = &rhs; - // Extract the types of both the right and left hand side values - Scalar::Type lhs_type = lhs.GetType(); - Scalar::Type rhs_type = rhs.GetType(); - - if (lhs_type > rhs_type) { - // Right hand side need to be promoted - temp_value = rhs; // Copy right hand side into the temp value - if (temp_value.Promote(lhs_type)) // Promote it - promoted_rhs_ptr = - &temp_value; // Update the pointer for the promoted right hand side - } else if (lhs_type < rhs_type) { - // Left hand side need to be promoted - temp_value = lhs; // Copy left hand side value into the temp value - if (temp_value.Promote(rhs_type)) // Promote it - promoted_lhs_ptr = - &temp_value; // Update the pointer for the promoted left hand side - } +Scalar::Type Scalar::PromoteToMaxType(Scalar &lhs, Scalar &rhs) { + const auto &Promote = [](Scalar &a, const Scalar &b) { + switch (b.GetType()) { + case e_void: + break; + case e_int: + a.IntegralPromote(b.m_integer.getBitWidth(), b.m_integer.isSigned()); + break; + case e_float: + a.FloatPromote(b.m_float.getSemantics()); + } + }; + + PromotionKey lhs_key = lhs.GetPromoKey(); + PromotionKey rhs_key = rhs.GetPromoKey(); + + if (lhs_key > rhs_key) + Promote(rhs, lhs); + else if (rhs_key > lhs_key) + Promote(lhs, rhs); // Make sure our type promotion worked as expected - if (promoted_lhs_ptr->GetType() == promoted_rhs_ptr->GetType()) - return promoted_lhs_ptr->GetType(); // Return the resulting max type + if (lhs.GetPromoKey() == rhs.GetPromoKey()) + return lhs.GetType(); // Return the resulting type // Return the void type (zero) if we fail to promote either of the values. return Scalar::e_void; } -Scalar::Scalar() : m_type(e_void), m_float(static_cast(0)) {} - bool Scalar::GetData(DataExtractor &data, size_t limit_byte_size) const { size_t byte_size = GetByteSize(); if (byte_size == 0) { @@ -160,16 +113,16 @@ bool Scalar::GetData(DataExtractor &data, size_t limit_byte_size) const { void Scalar::GetBytes(llvm::MutableArrayRef storage) const { assert(storage.size() >= GetByteSize()); - const auto &store = [&](const llvm::APInt val) { + const auto &store = [&](const llvm::APInt &val) { StoreIntToMemory(val, storage.data(), (val.getBitWidth() + 7) / 8); }; - switch (GetCategory(m_type)) { - case Category::Void: + switch (m_type) { + case e_void: break; - case Category::Integral: + case e_int: store(m_integer); break; - case Category::Float: + case e_float: store(m_float.bitcastToAPInt()); break; } @@ -179,36 +132,21 @@ size_t Scalar::GetByteSize() const { switch (m_type) { case e_void: break; - case e_sint: - case e_uint: - case e_slong: - case e_ulong: - case e_slonglong: - case e_ulonglong: - case e_sint128: - case e_uint128: - case e_sint256: - case e_uint256: - case e_sint512: - case e_uint512: + case e_int: return (m_integer.getBitWidth() / 8); case e_float: - return sizeof(float_t); - case e_double: - return sizeof(double_t); - case e_long_double: - return sizeof(long_double_t); + return m_float.bitcastToAPInt().getBitWidth() / 8; } return 0; } bool Scalar::IsZero() const { - switch (GetCategory(m_type)) { - case Category::Void: + switch (m_type) { + case e_void: break; - case Category::Integral: + case e_int: return m_integer.isNullValue(); - case Category::Float: + case e_float: return m_float.isZero(); } return false; @@ -218,13 +156,13 @@ void Scalar::GetValue(Stream *s, bool show_type) const { if (show_type) s->Printf("(%s) ", GetTypeAsCString()); - switch (GetCategory(m_type)) { - case Category::Void: + switch (m_type) { + case e_void: break; - case Category::Integral: - s->PutCString(m_integer.toString(10, IsSigned(m_type))); + case e_int: + s->PutCString(llvm::toString(m_integer, 10)); break; - case Category::Float: + case e_float: llvm::SmallString<24> string; m_float.toString(string); s->PutCString(string); @@ -232,137 +170,47 @@ void Scalar::GetValue(Stream *s, bool show_type) const { } } -Scalar::~Scalar() = default; - -Scalar::Type Scalar::GetBestTypeForBitSize(size_t bit_size, bool sign) { - // Scalar types are always host types, hence the sizeof(). - if (sign) { - if (bit_size <= sizeof(int)*8) return Scalar::e_sint; - if (bit_size <= sizeof(long)*8) return Scalar::e_slong; - if (bit_size <= sizeof(long long)*8) return Scalar::e_slonglong; - if (bit_size <= 128) return Scalar::e_sint128; - if (bit_size <= 256) return Scalar::e_sint256; - if (bit_size <= 512) return Scalar::e_sint512; - } else { - if (bit_size <= sizeof(unsigned int)*8) return Scalar::e_uint; - if (bit_size <= sizeof(unsigned long)*8) return Scalar::e_ulong; - if (bit_size <= sizeof(unsigned long long)*8) return Scalar::e_ulonglong; - if (bit_size <= 128) return Scalar::e_uint128; - if (bit_size <= 256) return Scalar::e_uint256; - if (bit_size <= 512) return Scalar::e_uint512; - } - return Scalar::e_void; -} - void Scalar::TruncOrExtendTo(uint16_t bits, bool sign) { - m_integer = sign ? m_integer.sextOrTrunc(bits) : m_integer.zextOrTrunc(bits); - m_type = GetBestTypeForBitSize(bits, sign); -} - -static size_t GetBitSize(Scalar::Type type) { - switch (type) { - case Scalar::e_void: - return 0; - case Scalar::e_sint: - return 8 * sizeof(int); - case Scalar::e_uint: - return 8 * sizeof(unsigned int); - case Scalar::e_slong: - return 8 * sizeof(long); - case Scalar::e_ulong: - return 8 * sizeof(unsigned long); - case Scalar::e_slonglong: - return 8 * sizeof(long long); - case Scalar::e_ulonglong: - return 8 * sizeof(unsigned long long); - case Scalar::e_sint128: - case Scalar::e_uint128: - return BITWIDTH_INT128; - case Scalar::e_sint256: - case Scalar::e_uint256: - return BITWIDTH_INT256; - case Scalar::e_sint512: - case Scalar::e_uint512: - return BITWIDTH_INT512; - case Scalar::e_float: - return 8 * sizeof(float); - case Scalar::e_double: - return 8 * sizeof(double); - case Scalar::e_long_double: - return 8 * sizeof(long double); - } - llvm_unreachable("Unhandled type!"); + m_integer.setIsSigned(sign); + m_integer = m_integer.extOrTrunc(bits); } -static const llvm::fltSemantics &GetFltSemantics(Scalar::Type type) { - switch (type) { - case Scalar::e_void: - case Scalar::e_sint: - case Scalar::e_slong: - case Scalar::e_slonglong: - case Scalar::e_sint128: - case Scalar::e_sint256: - case Scalar::e_sint512: - case Scalar::e_uint: - case Scalar::e_ulong: - case Scalar::e_ulonglong: - case Scalar::e_uint128: - case Scalar::e_uint256: - case Scalar::e_uint512: - llvm_unreachable("Only floating point types supported!"); - case Scalar::e_float: - return llvm::APFloat::IEEEsingle(); - case Scalar::e_double: - return llvm::APFloat::IEEEdouble(); - case Scalar::e_long_double: - return llvm::APFloat::x87DoubleExtended(); +bool Scalar::IntegralPromote(uint16_t bits, bool sign) { + switch (m_type) { + case e_void: + case e_float: + break; + case e_int: + if (GetPromoKey() > PromotionKey(e_int, bits, !sign)) + break; + m_integer = m_integer.extOrTrunc(bits); + m_integer.setIsSigned(sign); + return true; } - llvm_unreachable("Unhandled type!"); + return false; } -bool Scalar::Promote(Scalar::Type type) { +bool Scalar::FloatPromote(const llvm::fltSemantics &semantics) { bool success = false; - switch (GetCategory(m_type)) { - case Category::Void: + switch (m_type) { + case e_void: break; - case Category::Integral: - switch (GetCategory(type)) { - case Category::Void: - break; - case Category::Integral: - if (type < m_type) - break; - success = true; - if (IsSigned(m_type)) - m_integer = m_integer.sextOrTrunc(GetBitSize(type)); - else - m_integer = m_integer.zextOrTrunc(GetBitSize(type)); - break; - case Category::Float: - m_float = llvm::APFloat(GetFltSemantics(type)); - m_float.convertFromAPInt(m_integer, IsSigned(m_type), - llvm::APFloat::rmNearestTiesToEven); - success = true; - break; - } + case e_int: + m_float = llvm::APFloat(semantics); + m_float.convertFromAPInt(m_integer, m_integer.isSigned(), + llvm::APFloat::rmNearestTiesToEven); + success = true; break; - case Category::Float: - switch (GetCategory(type)) { - case Category::Void: - case Category::Integral: + case e_float: + if (GetFloatPromoKey(semantics) < GetFloatPromoKey(m_float.getSemantics())) break; - case Category::Float: - if (type < m_type) - break; - bool ignore; - success = true; - m_float.convert(GetFltSemantics(type), llvm::APFloat::rmNearestTiesToEven, - &ignore); - } + bool ignore; + success = true; + m_float.convert(semantics, llvm::APFloat::rmNearestTiesToEven, &ignore); } if (success) - m_type = type; + m_type = e_float; return success; } @@ -370,70 +218,24 @@ const char *Scalar::GetValueTypeAsCString(Scalar::Type type) { switch (type) { case e_void: return "void"; - case e_sint: + case e_int: return "int"; - case e_uint: - return "unsigned int"; - case e_slong: - return "long"; - case e_ulong: - return "unsigned long"; - case e_slonglong: - return "long long"; - case e_ulonglong: - return "unsigned long long"; case e_float: return "float"; - case e_double: - return "double"; - case e_long_double: - return "long double"; - case e_sint128: - return "int128_t"; - case e_uint128: - return "uint128_t"; - case e_sint256: - return "int256_t"; - case e_uint256: - return "uint256_t"; - case e_sint512: - return "int512_t"; - case e_uint512: - return "uint512_t"; } return "???"; } -Scalar::Type -Scalar::GetValueTypeForSignedIntegerWithByteSize(size_t byte_size) { - if (byte_size <= sizeof(sint_t)) - return e_sint; - if (byte_size <= sizeof(slong_t)) - return e_slong; - if (byte_size <= sizeof(slonglong_t)) - return e_slonglong; - return e_void; -} - -Scalar::Type -Scalar::GetValueTypeForUnsignedIntegerWithByteSize(size_t byte_size) { - if (byte_size <= sizeof(uint_t)) - return e_uint; - if (byte_size <= sizeof(ulong_t)) - return e_ulong; - if (byte_size <= sizeof(ulonglong_t)) - return e_ulonglong; - return e_void; -} - -Scalar::Type Scalar::GetValueTypeForFloatWithByteSize(size_t byte_size) { - if (byte_size == sizeof(float_t)) - return e_float; - if (byte_size == sizeof(double_t)) - return e_double; - if (byte_size == sizeof(long_double_t)) - return e_long_double; - return e_void; +bool Scalar::IsSigned() const { + switch (m_type) { + case e_void: + return false; + case e_int: + return m_integer.isSigned(); + case e_float: + return true; + } + llvm_unreachable("Unrecognized type!"); } bool Scalar::MakeSigned() { @@ -442,57 +244,13 @@ bool Scalar::MakeSigned() { switch (m_type) { case e_void: break; - case e_sint: - success = true; - break; - case e_uint: - m_type = e_sint; - success = true; - break; - case e_slong: - success = true; - break; - case e_ulong: - m_type = e_slong; - success = true; - break; - case e_slonglong: - success = true; - break; - case e_ulonglong: - m_type = e_slonglong; - success = true; - break; - case e_sint128: - success = true; - break; - case e_uint128: - m_type = e_sint128; - success = true; - break; - case e_sint256: - success = true; - break; - case e_uint256: - m_type = e_sint256; - success = true; - break; - case e_sint512: - success = true; - break; - case e_uint512: - m_type = e_sint512; + case e_int: + m_integer.setIsSigned(true); success = true; break; case e_float: success = true; break; - case e_double: - success = true; - break; - case e_long_double: - success = true; - break; } return success; @@ -504,57 +262,13 @@ bool Scalar::MakeUnsigned() { switch (m_type) { case e_void: break; - case e_sint: - m_type = e_uint; - success = true; - break; - case e_uint: - success = true; - break; - case e_slong: - m_type = e_ulong; - success = true; - break; - case e_ulong: - success = true; - break; - case e_slonglong: - m_type = e_ulonglong; - success = true; - break; - case e_ulonglong: - success = true; - break; - case e_sint128: - m_type = e_uint128; - success = true; - break; - case e_uint128: - success = true; - break; - case e_sint256: - m_type = e_uint256; - success = true; - break; - case e_uint256: - success = true; - break; - case e_sint512: - m_type = e_uint512; - success = true; - break; - case e_uint512: + case e_int: + m_integer.setIsUnsigned(true); success = true; break; case e_float: success = true; break; - case e_double: - success = true; - break; - case e_long_double: - success = true; - break; } return success; @@ -569,14 +283,16 @@ static llvm::APInt ToAPInt(const llvm::APFloat &f, unsigned bits, } template T Scalar::GetAs(T fail_value) const { - switch (GetCategory(m_type)) { - case Category::Void: + switch (m_type) { + case e_void: break; - case Category::Integral: - if (IsSigned(m_type)) - return m_integer.sextOrTrunc(sizeof(T) * 8).getSExtValue(); - return m_integer.zextOrTrunc(sizeof(T) * 8).getZExtValue(); - case Category::Float: + case e_int: { + APSInt ext = m_integer.extOrTrunc(sizeof(T) * 8); + if (ext.isSigned()) + return ext.getSExtValue(); + return ext.getZExtValue(); + } + case e_float: return ToAPInt(m_float, sizeof(T) * 8, std::is_unsigned::value) .getSExtValue(); } @@ -620,39 +336,39 @@ unsigned long long Scalar::ULongLong(unsigned long long fail_value) const { } llvm::APInt Scalar::SInt128(const llvm::APInt &fail_value) const { - switch (GetCategory(m_type)) { - case Category::Void: + switch (m_type) { + case e_void: break; - case Category::Integral: + case e_int: return m_integer; - case Category::Float: + case e_float: return ToAPInt(m_float, 128, /*is_unsigned=*/false); } return fail_value; } llvm::APInt Scalar::UInt128(const llvm::APInt &fail_value) const { - switch (GetCategory(m_type)) { - case Category::Void: + switch (m_type) { + case e_void: break; - case Category::Integral: + case e_int: return m_integer; - case Category::Float: + case e_float: return ToAPInt(m_float, 128, /*is_unsigned=*/true); } return fail_value; } float Scalar::Float(float fail_value) const { - switch (GetCategory(m_type)) { - case Category::Void: + switch (m_type) { + case e_void: break; - case Category::Integral: - if (IsSigned(m_type)) + case e_int: + if (m_integer.isSigned()) return llvm::APIntOps::RoundSignedAPIntToFloat(m_integer); return llvm::APIntOps::RoundAPIntToFloat(m_integer); - case Category::Float: { + case e_float: { APFloat result = m_float; bool losesInfo; result.convert(APFloat::IEEEsingle(), APFloat::rmNearestTiesToEven, @@ -664,15 +380,15 @@ float Scalar::Float(float fail_value) const { } double Scalar::Double(double fail_value) const { - switch (GetCategory(m_type)) { - case Category::Void: + switch (m_type) { + case e_void: break; - case Category::Integral: - if (IsSigned(m_type)) + case e_int: + if (m_integer.isSigned()) return llvm::APIntOps::RoundSignedAPIntToDouble(m_integer); return llvm::APIntOps::RoundAPIntToDouble(m_integer); - case Category::Float: { + case e_float: { APFloat result = m_float; bool losesInfo; result.convert(APFloat::IEEEdouble(), APFloat::rmNearestTiesToEven, @@ -688,21 +404,18 @@ long double Scalar::LongDouble(long double fail_value) const { return static_cast(Double(fail_value)); } -Scalar &Scalar::operator+=(const Scalar &rhs) { - Scalar temp_value; - const Scalar *a; - const Scalar *b; - if ((m_type = PromoteToMaxType(*this, rhs, temp_value, a, b)) != - Scalar::e_void) { - switch (GetCategory(m_type)) { - case Category::Void: +Scalar &Scalar::operator+=(Scalar rhs) { + Scalar copy = *this; + if ((m_type = PromoteToMaxType(copy, rhs)) != Scalar::e_void) { + switch (m_type) { + case e_void: break; - case Category::Integral: - m_integer = a->m_integer + b->m_integer; + case e_int: + m_integer = copy.m_integer + rhs.m_integer; break; - case Category::Float: - m_float = a->m_float + b->m_float; + case e_float: + m_float = copy.m_float + rhs.m_float; break; } } @@ -710,17 +423,15 @@ Scalar &Scalar::operator+=(const Scalar &rhs) { } Scalar &Scalar::operator<<=(const Scalar &rhs) { - if (GetCategory(m_type) == Category::Integral && - GetCategory(rhs.m_type) == Category::Integral) - m_integer <<= rhs.m_integer; + if (m_type == e_int && rhs.m_type == e_int) + static_cast(m_integer) <<= rhs.m_integer; else m_type = e_void; return *this; } bool Scalar::ShiftRightLogical(const Scalar &rhs) { - if (GetCategory(m_type) == Category::Integral && - GetCategory(rhs.m_type) == Category::Integral) { + if (m_type == e_int && rhs.m_type == e_int) { m_integer = m_integer.lshr(rhs.m_integer); return true; } @@ -732,42 +443,16 @@ Scalar &Scalar::operator>>=(const Scalar &rhs) { switch (m_type) { case e_void: case e_float: - case e_double: - case e_long_double: m_type = e_void; break; - case e_sint: - case e_uint: - case e_slong: - case e_ulong: - case e_slonglong: - case e_ulonglong: - case e_sint128: - case e_uint128: - case e_sint256: - case e_uint256: - case e_sint512: - case e_uint512: + case e_int: switch (rhs.m_type) { case e_void: case e_float: - case e_double: - case e_long_double: m_type = e_void; break; - case e_sint: - case e_uint: - case e_slong: - case e_ulong: - case e_slonglong: - case e_ulonglong: - case e_sint128: - case e_uint128: - case e_sint256: - case e_uint256: - case e_sint512: - case e_uint512: + case e_int: m_integer = m_integer.ashr(rhs.m_integer); break; } @@ -777,8 +462,7 @@ Scalar &Scalar::operator>>=(const Scalar &rhs) { } Scalar &Scalar::operator&=(const Scalar &rhs) { - if (GetCategory(m_type) == Category::Integral && - GetCategory(rhs.m_type) == Category::Integral) + if (m_type == e_int && rhs.m_type == e_int) m_integer &= rhs.m_integer; else m_type = e_void; @@ -790,26 +474,12 @@ bool Scalar::AbsoluteValue() { case e_void: break; - case e_sint: - case e_slong: - case e_slonglong: - case e_sint128: - case e_sint256: - case e_sint512: + case e_int: if (m_integer.isNegative()) m_integer = -m_integer; return true; - case e_uint: - case e_ulong: - case e_ulonglong: - return true; - case e_uint128: - case e_uint256: - case e_uint512: case e_float: - case e_double: - case e_long_double: m_float.clearSign(); return true; } @@ -817,13 +487,13 @@ bool Scalar::AbsoluteValue() { } bool Scalar::UnaryNegate() { - switch (GetCategory(m_type)) { - case Category::Void: + switch (m_type) { + case e_void: break; - case Category::Integral: + case e_int: m_integer = -m_integer; return true; - case Category::Float: + case e_float: m_float.changeSign(); return true; } @@ -831,7 +501,7 @@ bool Scalar::UnaryNegate() { } bool Scalar::OnesComplement() { - if (GetCategory(m_type) == Category::Integral) { + if (m_type == e_int) { m_integer = ~m_integer; return true; } @@ -845,46 +515,35 @@ const Scalar lldb_private::operator+(const Scalar &lhs, const Scalar &rhs) { return result; } -const Scalar lldb_private::operator-(const Scalar &lhs, const Scalar &rhs) { +const Scalar lldb_private::operator-(Scalar lhs, Scalar rhs) { Scalar result; - Scalar temp_value; - const Scalar *a; - const Scalar *b; - if ((result.m_type = PromoteToMaxType(lhs, rhs, temp_value, a, b)) != - Scalar::e_void) { - switch (GetCategory(result.m_type)) { - case Category::Void: + if ((result.m_type = Scalar::PromoteToMaxType(lhs, rhs)) != Scalar::e_void) { + switch (result.m_type) { + case Scalar::e_void: break; - case Category::Integral: - result.m_integer = a->m_integer - b->m_integer; + case Scalar::e_int: + result.m_integer = lhs.m_integer - rhs.m_integer; break; - case Category::Float: - result.m_float = a->m_float - b->m_float; + case Scalar::e_float: + result.m_float = lhs.m_float - rhs.m_float; break; } } return result; } -const Scalar lldb_private::operator/(const Scalar &lhs, const Scalar &rhs) { +const Scalar lldb_private::operator/(Scalar lhs, Scalar rhs) { Scalar result; - Scalar temp_value; - const Scalar *a; - const Scalar *b; - if ((result.m_type = PromoteToMaxType(lhs, rhs, temp_value, a, b)) != - Scalar::e_void && - !b->IsZero()) { - switch (GetCategory(result.m_type)) { - case Category::Void: + if ((result.m_type = Scalar::PromoteToMaxType(lhs, rhs)) != Scalar::e_void && + !rhs.IsZero()) { + switch (result.m_type) { + case Scalar::e_void: break; - case Category::Integral: - if (IsSigned(result.m_type)) - result.m_integer = a->m_integer.sdiv(b->m_integer); - else - result.m_integer = a->m_integer.udiv(b->m_integer); + case Scalar::e_int: + result.m_integer = lhs.m_integer / rhs.m_integer; return result; - case Category::Float: - result.m_float = a->m_float / b->m_float; + case Scalar::e_float: + result.m_float = lhs.m_float / rhs.m_float; return result; } } @@ -894,69 +553,50 @@ const Scalar lldb_private::operator/(const Scalar &lhs, const Scalar &rhs) { return result; } -const Scalar lldb_private::operator*(const Scalar &lhs, const Scalar &rhs) { +const Scalar lldb_private::operator*(Scalar lhs, Scalar rhs) { Scalar result; - Scalar temp_value; - const Scalar *a; - const Scalar *b; - if ((result.m_type = PromoteToMaxType(lhs, rhs, temp_value, a, b)) != - Scalar::e_void) { - switch (GetCategory(result.m_type)) { - case Category::Void: + if ((result.m_type = Scalar::PromoteToMaxType(lhs, rhs)) != Scalar::e_void) { + switch (result.m_type) { + case Scalar::e_void: break; - case Category::Integral: - result.m_integer = a->m_integer * b->m_integer; + case Scalar::e_int: + result.m_integer = lhs.m_integer * rhs.m_integer; break; - case Category::Float: - result.m_float = a->m_float * b->m_float; + case Scalar::e_float: + result.m_float = lhs.m_float * rhs.m_float; break; } } return result; } -const Scalar lldb_private::operator&(const Scalar &lhs, const Scalar &rhs) { +const Scalar lldb_private::operator&(Scalar lhs, Scalar rhs) { Scalar result; - Scalar temp_value; - const Scalar *a; - const Scalar *b; - if ((result.m_type = PromoteToMaxType(lhs, rhs, temp_value, a, b)) != - Scalar::e_void) { - if (GetCategory(result.m_type) == Category::Integral) - result.m_integer = a->m_integer & b->m_integer; + if ((result.m_type = Scalar::PromoteToMaxType(lhs, rhs)) != Scalar::e_void) { + if (result.m_type == Scalar::e_int) + result.m_integer = lhs.m_integer & rhs.m_integer; else result.m_type = Scalar::e_void; } return result; } -const Scalar lldb_private::operator|(const Scalar &lhs, const Scalar &rhs) { +const Scalar lldb_private::operator|(Scalar lhs, Scalar rhs) { Scalar result; - Scalar temp_value; - const Scalar *a; - const Scalar *b; - if ((result.m_type = PromoteToMaxType(lhs, rhs, temp_value, a, b)) != - Scalar::e_void) { - if (GetCategory(result.m_type) == Category::Integral) - result.m_integer = a->m_integer | b->m_integer; + if ((result.m_type = Scalar::PromoteToMaxType(lhs, rhs)) != Scalar::e_void) { + if (result.m_type == Scalar::e_int) + result.m_integer = lhs.m_integer | rhs.m_integer; else result.m_type = Scalar::e_void; } return result; } -const Scalar lldb_private::operator%(const Scalar &lhs, const Scalar &rhs) { +const Scalar lldb_private::operator%(Scalar lhs, Scalar rhs) { Scalar result; - Scalar temp_value; - const Scalar *a; - const Scalar *b; - if ((result.m_type = PromoteToMaxType(lhs, rhs, temp_value, a, b)) != - Scalar::e_void) { - if (!b->IsZero() && GetCategory(result.m_type) == Category::Integral) { - if (IsSigned(result.m_type)) - result.m_integer = a->m_integer.srem(b->m_integer); - else - result.m_integer = a->m_integer.urem(b->m_integer); + if ((result.m_type = Scalar::PromoteToMaxType(lhs, rhs)) != Scalar::e_void) { + if (!rhs.IsZero() && result.m_type == Scalar::e_int) { + result.m_integer = lhs.m_integer % rhs.m_integer; return result; } } @@ -964,15 +604,11 @@ const Scalar lldb_private::operator%(const Scalar &lhs, const Scalar &rhs) { return result; } -const Scalar lldb_private::operator^(const Scalar &lhs, const Scalar &rhs) { +const Scalar lldb_private::operator^(Scalar lhs, Scalar rhs) { Scalar result; - Scalar temp_value; - const Scalar *a; - const Scalar *b; - if ((result.m_type = PromoteToMaxType(lhs, rhs, temp_value, a, b)) != - Scalar::e_void) { - if (GetCategory(result.m_type) == Category::Integral) - result.m_integer = a->m_integer ^ b->m_integer; + if ((result.m_type = Scalar::PromoteToMaxType(lhs, rhs)) != Scalar::e_void) { + if (result.m_type == Scalar::e_int) + result.m_integer = lhs.m_integer ^ rhs.m_integer; else result.m_type = Scalar::e_void; } @@ -1028,30 +664,24 @@ Status Scalar::SetValueFromCString(const char *value_str, Encoding encoding, value_str, byte_size); break; } - m_type = GetBestTypeForBitSize(8 * byte_size, is_signed); - if (m_type == e_void) { - error.SetErrorStringWithFormatv("unsupported integer byte size: {0}", - byte_size); - break; - } - if (is_signed) - m_integer = integer.sextOrTrunc(GetBitSize(m_type)); - else - m_integer = integer.zextOrTrunc(GetBitSize(m_type)); + m_type = e_int; + m_integer = + APSInt(std::move(integer), !is_signed).extOrTrunc(8 * byte_size); break; } case eEncodingIEEE754: { - Type type = GetValueTypeForFloatWithByteSize(byte_size); - if (type == e_void) { - error.SetErrorStringWithFormatv("unsupported float byte size: {0}", - byte_size); - break; - } - APFloat f(GetFltSemantics(type)); + // FIXME: It's not possible to unambiguously map a byte size to a floating + // point type. This function should be refactored to take an explicit + // semantics argument. + const llvm::fltSemantics &sem = + byte_size <= 4 ? APFloat::IEEEsingle() + : byte_size <= 8 ? APFloat::IEEEdouble() + : APFloat::x87DoubleExtended(); + APFloat f(sem); if (llvm::Expected op = f.convertFromString(value_str, APFloat::rmNearestTiesToEven)) { - m_type = type; + m_type = e_float; m_float = std::move(f); } else error = op.takeError(); @@ -1068,12 +698,9 @@ Status Scalar::SetValueFromCString(const char *value_str, Encoding encoding, return error; } -Status Scalar::SetValueFromData(DataExtractor &data, lldb::Encoding encoding, - size_t byte_size) { +Status Scalar::SetValueFromData(const DataExtractor &data, + lldb::Encoding encoding, size_t byte_size) { Status error; - - type128 int128; - type256 int256; switch (encoding) { case lldb::eEncodingInvalid: error.SetErrorString("invalid encoding"); @@ -1081,100 +708,22 @@ Status Scalar::SetValueFromData(DataExtractor &data, lldb::Encoding encoding, case lldb::eEncodingVector: error.SetErrorString("vector encoding unsupported"); break; - case lldb::eEncodingUint: { - lldb::offset_t offset = 0; - - switch (byte_size) { - case 1: - operator=(data.GetU8(&offset)); - break; - case 2: - operator=(data.GetU16(&offset)); - break; - case 4: - operator=(data.GetU32(&offset)); - break; - case 8: - operator=(data.GetU64(&offset)); - break; - case 16: - if (data.GetByteOrder() == eByteOrderBig) { - int128.x[1] = data.GetU64(&offset); - int128.x[0] = data.GetU64(&offset); - } else { - int128.x[0] = data.GetU64(&offset); - int128.x[1] = data.GetU64(&offset); - } - operator=(llvm::APInt(BITWIDTH_INT128, NUM_OF_WORDS_INT128, int128.x)); - break; - case 32: - if (data.GetByteOrder() == eByteOrderBig) { - int256.x[3] = data.GetU64(&offset); - int256.x[2] = data.GetU64(&offset); - int256.x[1] = data.GetU64(&offset); - int256.x[0] = data.GetU64(&offset); - } else { - int256.x[0] = data.GetU64(&offset); - int256.x[1] = data.GetU64(&offset); - int256.x[2] = data.GetU64(&offset); - int256.x[3] = data.GetU64(&offset); - } - operator=(llvm::APInt(BITWIDTH_INT256, NUM_OF_WORDS_INT256, int256.x)); - break; - default: - error.SetErrorStringWithFormat( - "unsupported unsigned integer byte size: %" PRIu64 "", - static_cast(byte_size)); - break; - } - } break; + case lldb::eEncodingUint: case lldb::eEncodingSint: { - lldb::offset_t offset = 0; - - switch (byte_size) { - case 1: - operator=(static_cast(data.GetU8(&offset))); - break; - case 2: - operator=(static_cast(data.GetU16(&offset))); - break; - case 4: - operator=(static_cast(data.GetU32(&offset))); - break; - case 8: - operator=(static_cast(data.GetU64(&offset))); - break; - case 16: - if (data.GetByteOrder() == eByteOrderBig) { - int128.x[1] = data.GetU64(&offset); - int128.x[0] = data.GetU64(&offset); - } else { - int128.x[0] = data.GetU64(&offset); - int128.x[1] = data.GetU64(&offset); - } - operator=(llvm::APInt(BITWIDTH_INT128, NUM_OF_WORDS_INT128, int128.x)); - break; - case 32: - if (data.GetByteOrder() == eByteOrderBig) { - int256.x[3] = data.GetU64(&offset); - int256.x[2] = data.GetU64(&offset); - int256.x[1] = data.GetU64(&offset); - int256.x[0] = data.GetU64(&offset); - } else { - int256.x[0] = data.GetU64(&offset); - int256.x[1] = data.GetU64(&offset); - int256.x[2] = data.GetU64(&offset); - int256.x[3] = data.GetU64(&offset); - } - operator=(llvm::APInt(BITWIDTH_INT256, NUM_OF_WORDS_INT256, int256.x)); - break; - default: - error.SetErrorStringWithFormat( - "unsupported signed integer byte size: %" PRIu64 "", - static_cast(byte_size)); - break; + if (data.GetByteSize() < byte_size) + return Status("insufficient data"); + m_type = e_int; + m_integer = + APSInt(APInt::getNullValue(8 * byte_size), encoding == eEncodingUint); + if (data.GetByteOrder() == endian::InlHostByteOrder()) { + llvm::LoadIntFromMemory(m_integer, data.GetDataStart(), byte_size); + } else { + std::vector buffer(byte_size); + std::copy_n(data.GetDataStart(), byte_size, buffer.rbegin()); + llvm::LoadIntFromMemory(m_integer, buffer.data(), byte_size); } - } break; + break; + } case lldb::eEncodingIEEE754: { lldb::offset_t offset = 0; @@ -1200,31 +749,18 @@ bool Scalar::SignExtend(uint32_t sign_bit_pos) { switch (m_type) { case Scalar::e_void: case Scalar::e_float: - case Scalar::e_double: - case Scalar::e_long_double: return false; - case Scalar::e_sint: - case Scalar::e_uint: - case Scalar::e_slong: - case Scalar::e_ulong: - case Scalar::e_slonglong: - case Scalar::e_ulonglong: - case Scalar::e_sint128: - case Scalar::e_uint128: - case Scalar::e_sint256: - case Scalar::e_uint256: - case Scalar::e_sint512: - case Scalar::e_uint512: + case Scalar::e_int: if (max_bit_pos == sign_bit_pos) return true; else if (sign_bit_pos < (max_bit_pos - 1)) { llvm::APInt sign_bit = llvm::APInt::getSignMask(sign_bit_pos + 1); llvm::APInt bitwize_and = m_integer & sign_bit; if (bitwize_and.getBoolValue()) { - const llvm::APInt mask = + llvm::APInt mask = ~(sign_bit) + llvm::APInt(m_integer.getBitWidth(), 1); - m_integer |= mask; + m_integer |= APSInt(std::move(mask), m_integer.isUnsigned()); } return true; } @@ -1266,64 +802,29 @@ bool Scalar::ExtractBitfield(uint32_t bit_size, uint32_t bit_offset) { switch (m_type) { case Scalar::e_void: case Scalar::e_float: - case Scalar::e_double: - case Scalar::e_long_double: break; - case Scalar::e_sint: - case Scalar::e_slong: - case Scalar::e_slonglong: - case Scalar::e_sint128: - case Scalar::e_sint256: - case Scalar::e_sint512: - m_integer = m_integer.ashr(bit_offset) - .sextOrTrunc(bit_size) - .sextOrSelf(8 * GetByteSize()); - return true; - - case Scalar::e_uint: - case Scalar::e_ulong: - case Scalar::e_ulonglong: - case Scalar::e_uint128: - case Scalar::e_uint256: - case Scalar::e_uint512: - m_integer = m_integer.lshr(bit_offset) - .zextOrTrunc(bit_size) - .zextOrSelf(8 * GetByteSize()); + case Scalar::e_int: + m_integer >>= bit_offset; + m_integer = m_integer.extOrTrunc(bit_size).extOrTrunc(8 * GetByteSize()); return true; } return false; } -bool lldb_private::operator==(const Scalar &lhs, const Scalar &rhs) { +bool lldb_private::operator==(Scalar lhs, Scalar rhs) { // If either entry is void then we can just compare the types if (lhs.m_type == Scalar::e_void || rhs.m_type == Scalar::e_void) return lhs.m_type == rhs.m_type; - Scalar temp_value; - const Scalar *a; - const Scalar *b; llvm::APFloat::cmpResult result; - switch (PromoteToMaxType(lhs, rhs, temp_value, a, b)) { + switch (Scalar::PromoteToMaxType(lhs, rhs)) { case Scalar::e_void: break; - case Scalar::e_sint: - case Scalar::e_uint: - case Scalar::e_slong: - case Scalar::e_ulong: - case Scalar::e_slonglong: - case Scalar::e_ulonglong: - case Scalar::e_sint128: - case Scalar::e_uint128: - case Scalar::e_sint256: - case Scalar::e_uint256: - case Scalar::e_sint512: - case Scalar::e_uint512: - return a->m_integer == b->m_integer; + case Scalar::e_int: + return lhs.m_integer == rhs.m_integer; case Scalar::e_float: - case Scalar::e_double: - case Scalar::e_long_double: - result = a->m_float.compare(b->m_float); + result = lhs.m_float.compare(rhs.m_float); if (result == llvm::APFloat::cmpEqual) return true; } @@ -1334,35 +835,18 @@ bool lldb_private::operator!=(const Scalar &lhs, const Scalar &rhs) { return !(lhs == rhs); } -bool lldb_private::operator<(const Scalar &lhs, const Scalar &rhs) { +bool lldb_private::operator<(Scalar lhs, Scalar rhs) { if (lhs.m_type == Scalar::e_void || rhs.m_type == Scalar::e_void) return false; - Scalar temp_value; - const Scalar *a; - const Scalar *b; llvm::APFloat::cmpResult result; - switch (PromoteToMaxType(lhs, rhs, temp_value, a, b)) { + switch (Scalar::PromoteToMaxType(lhs, rhs)) { case Scalar::e_void: break; - case Scalar::e_sint: - case Scalar::e_slong: - case Scalar::e_slonglong: - case Scalar::e_sint128: - case Scalar::e_sint256: - case Scalar::e_sint512: - case Scalar::e_uint512: - return a->m_integer.slt(b->m_integer); - case Scalar::e_uint: - case Scalar::e_ulong: - case Scalar::e_ulonglong: - case Scalar::e_uint128: - case Scalar::e_uint256: - return a->m_integer.ult(b->m_integer); + case Scalar::e_int: + return lhs.m_integer < rhs.m_integer; case Scalar::e_float: - case Scalar::e_double: - case Scalar::e_long_double: - result = a->m_float.compare(b->m_float); + result = lhs.m_float.compare(rhs.m_float); if (result == llvm::APFloat::cmpLessThan) return true; } @@ -1385,23 +869,10 @@ bool Scalar::ClearBit(uint32_t bit) { switch (m_type) { case e_void: break; - case e_sint: - case e_uint: - case e_slong: - case e_ulong: - case e_slonglong: - case e_ulonglong: - case e_sint128: - case e_uint128: - case e_sint256: - case e_uint256: - case e_sint512: - case e_uint512: + case e_int: m_integer.clearBit(bit); return true; case e_float: - case e_double: - case e_long_double: break; } return false; @@ -1411,23 +882,10 @@ bool Scalar::SetBit(uint32_t bit) { switch (m_type) { case e_void: break; - case e_sint: - case e_uint: - case e_slong: - case e_ulong: - case e_slonglong: - case e_ulonglong: - case e_sint128: - case e_uint128: - case e_sint256: - case e_uint256: - case e_sint512: - case e_uint512: + case e_int: m_integer.setBit(bit); return true; case e_float: - case e_double: - case e_long_double: break; } return false; diff --git a/gnu/llvm/lldb/source/Utility/SelectHelper.cpp b/gnu/llvm/lldb/source/Utility/SelectHelper.cpp index 40c85bee607..059f810e219 100644 --- a/gnu/llvm/lldb/source/Utility/SelectHelper.cpp +++ b/gnu/llvm/lldb/source/Utility/SelectHelper.cpp @@ -25,7 +25,7 @@ #include #include -#include +#include #if defined(_WIN32) // Define NOMINMAX to avoid macros that conflict with std::min and std::max #define NOMINMAX diff --git a/gnu/llvm/lldb/source/Utility/Status.cpp b/gnu/llvm/lldb/source/Utility/Status.cpp index e3c4284a8e8..72fd087decc 100644 --- a/gnu/llvm/lldb/source/Utility/Status.cpp +++ b/gnu/llvm/lldb/source/Utility/Status.cpp @@ -28,7 +28,7 @@ #ifdef _WIN32 #include #endif -#include +#include namespace llvm { class raw_ostream; @@ -37,7 +37,7 @@ class raw_ostream; using namespace lldb; using namespace lldb_private; -Status::Status() : m_code(0), m_type(eErrorTypeInvalid), m_string() {} +Status::Status() : m_string() {} Status::Status(ValueType err, ErrorType type) : m_code(err), m_type(type), m_string() {} diff --git a/gnu/llvm/lldb/source/Utility/Stream.cpp b/gnu/llvm/lldb/source/Utility/Stream.cpp index a0623bfa6e5..a1e2de9da4d 100644 --- a/gnu/llvm/lldb/source/Utility/Stream.cpp +++ b/gnu/llvm/lldb/source/Utility/Stream.cpp @@ -16,8 +16,8 @@ #include -#include -#include +#include +#include using namespace lldb; using namespace lldb_private; @@ -28,11 +28,11 @@ Stream::Stream(uint32_t flags, uint32_t addr_size, ByteOrder byte_order, m_indent_level(0), m_forwarder(*this, colors) {} Stream::Stream(bool colors) - : m_flags(0), m_addr_size(4), m_byte_order(endian::InlHostByteOrder()), - m_indent_level(0), m_forwarder(*this, colors) {} + : m_flags(0), m_byte_order(endian::InlHostByteOrder()), + m_forwarder(*this, colors) {} // Destructor -Stream::~Stream() {} +Stream::~Stream() = default; ByteOrder Stream::SetByteOrder(ByteOrder byte_order) { ByteOrder old_byte_order = m_byte_order; diff --git a/gnu/llvm/lldb/source/Utility/StreamString.cpp b/gnu/llvm/lldb/source/Utility/StreamString.cpp index 190be588e88..745a85b7576 100644 --- a/gnu/llvm/lldb/source/Utility/StreamString.cpp +++ b/gnu/llvm/lldb/source/Utility/StreamString.cpp @@ -17,7 +17,7 @@ StreamString::StreamString(uint32_t flags, uint32_t addr_size, ByteOrder byte_order) : Stream(flags, addr_size, byte_order), m_packet() {} -StreamString::~StreamString() {} +StreamString::~StreamString() = default; void StreamString::Flush() { // Nothing to do when flushing a buffer based stream... diff --git a/gnu/llvm/lldb/source/Utility/StringExtractor.cpp b/gnu/llvm/lldb/source/Utility/StringExtractor.cpp index 0553a63a021..d082c86f846 100644 --- a/gnu/llvm/lldb/source/Utility/StringExtractor.cpp +++ b/gnu/llvm/lldb/source/Utility/StringExtractor.cpp @@ -11,9 +11,9 @@ #include -#include -#include -#include +#include +#include +#include static inline int xdigit_to_sint(char ch) { if (ch >= 'a' && ch <= 'f') @@ -26,7 +26,7 @@ static inline int xdigit_to_sint(char ch) { } // StringExtractor constructor -StringExtractor::StringExtractor() : m_packet(), m_index(0) {} +StringExtractor::StringExtractor() : m_packet() {} StringExtractor::StringExtractor(llvm::StringRef packet_str) : m_packet(), m_index(0) { @@ -40,7 +40,7 @@ StringExtractor::StringExtractor(const char *packet_cstr) } // Destructor -StringExtractor::~StringExtractor() {} +StringExtractor::~StringExtractor() = default; char StringExtractor::GetChar(char fail_value) { if (m_index < m_packet.size()) { diff --git a/gnu/llvm/lldb/source/Utility/StringExtractorGDBRemote.cpp b/gnu/llvm/lldb/source/Utility/StringExtractorGDBRemote.cpp index cfe7577e486..29cf585bea5 100644 --- a/gnu/llvm/lldb/source/Utility/StringExtractorGDBRemote.cpp +++ b/gnu/llvm/lldb/source/Utility/StringExtractorGDBRemote.cpp @@ -8,8 +8,11 @@ #include "lldb/Utility/StringExtractorGDBRemote.h" -#include -#include +#include +#include + +constexpr lldb::pid_t StringExtractorGDBRemote::AllProcesses; +constexpr lldb::tid_t StringExtractorGDBRemote::AllThreads; StringExtractorGDBRemote::ResponseType StringExtractorGDBRemote::GetResponseType() const { @@ -140,6 +143,11 @@ StringExtractorGDBRemote::GetServerPacketType() const { return eServerPacketType_QListThreadsInStopReply; break; + case 'M': + if (PACKET_STARTS_WITH("QMemTags")) + return eServerPacketType_QMemTags; + break; + case 'R': if (PACKET_STARTS_WITH("QRestoreRegisterState:")) return eServerPacketType_QRestoreRegisterState; @@ -220,6 +228,8 @@ StringExtractorGDBRemote::GetServerPacketType() const { return eServerPacketType_qMemoryRegionInfoSupported; if (PACKET_STARTS_WITH("qModuleInfo:")) return eServerPacketType_qModuleInfo; + if (PACKET_STARTS_WITH("qMemTags:")) + return eServerPacketType_qMemTags; break; case 'P': @@ -233,6 +243,8 @@ StringExtractorGDBRemote::GetServerPacketType() const { return eServerPacketType_qPlatform_chmod; if (PACKET_MATCHES("qProcessInfo")) return eServerPacketType_qProcessInfo; + if (PACKET_STARTS_WITH("qPathComplete:")) + return eServerPacketType_qPathComplete; break; case 'Q': @@ -298,16 +310,17 @@ StringExtractorGDBRemote::GetServerPacketType() const { return eServerPacketType_jSignalsInfo; if (PACKET_MATCHES("jThreadsInfo")) return eServerPacketType_jThreadsInfo; - if (PACKET_STARTS_WITH("jTraceBufferRead:")) - return eServerPacketType_jTraceBufferRead; - if (PACKET_STARTS_WITH("jTraceConfigRead:")) - return eServerPacketType_jTraceConfigRead; - if (PACKET_STARTS_WITH("jTraceMetaRead:")) - return eServerPacketType_jTraceMetaRead; - if (PACKET_STARTS_WITH("jTraceStart:")) - return eServerPacketType_jTraceStart; - if (PACKET_STARTS_WITH("jTraceStop:")) - return eServerPacketType_jTraceStop; + + if (PACKET_MATCHES("jLLDBTraceSupported")) + return eServerPacketType_jLLDBTraceSupported; + if (PACKET_STARTS_WITH("jLLDBTraceStop:")) + return eServerPacketType_jLLDBTraceStop; + if (PACKET_STARTS_WITH("jLLDBTraceStart:")) + return eServerPacketType_jLLDBTraceStart; + if (PACKET_STARTS_WITH("jLLDBTraceGetState:")) + return eServerPacketType_jLLDBTraceGetState; + if (PACKET_STARTS_WITH("jLLDBTraceGetBinaryData:")) + return eServerPacketType_jLLDBTraceGetBinaryData; break; case 'v': @@ -372,9 +385,7 @@ StringExtractorGDBRemote::GetServerPacketType() const { return eServerPacketType_C; case 'D': - if (packet_size == 1) - return eServerPacketType_D; - break; + return eServerPacketType_D; case 'g': return eServerPacketType_g; @@ -602,3 +613,46 @@ bool StringExtractorGDBRemote::ValidateResponse() const { else return true; // No validator, so response is valid } + +llvm::Optional> +StringExtractorGDBRemote::GetPidTid(lldb::pid_t default_pid) { + llvm::StringRef view = llvm::StringRef(m_packet).substr(m_index); + size_t initial_length = view.size(); + lldb::pid_t pid = default_pid; + lldb::tid_t tid; + + if (view.consume_front("p")) { + // process identifier + if (view.consume_front("-1")) { + // -1 is a special case + pid = AllProcesses; + } else if (view.consumeInteger(16, pid) || pid == 0) { + // not a valid hex integer OR unsupported pid 0 + m_index = UINT64_MAX; + return llvm::None; + } + + // "." must follow if we expect TID too; otherwise, we assume -1 + if (!view.consume_front(".")) { + // update m_index + m_index += initial_length - view.size(); + + return {{pid, AllThreads}}; + } + } + + // thread identifier + if (view.consume_front("-1")) { + // -1 is a special case + tid = AllThreads; + } else if (view.consumeInteger(16, tid) || tid == 0 || pid == AllProcesses) { + // not a valid hex integer OR tid 0 OR pid -1 + a specific tid + m_index = UINT64_MAX; + return llvm::None; + } + + // update m_index + m_index += initial_length - view.size(); + + return {{pid, tid}}; +} diff --git a/gnu/llvm/lldb/source/Utility/StringLexer.cpp b/gnu/llvm/lldb/source/Utility/StringLexer.cpp index 947472a014e..bda6e25ce7a 100644 --- a/gnu/llvm/lldb/source/Utility/StringLexer.cpp +++ b/gnu/llvm/lldb/source/Utility/StringLexer.cpp @@ -9,11 +9,12 @@ #include "lldb/Utility/StringLexer.h" #include -#include +#include +#include using namespace lldb_private; -StringLexer::StringLexer(std::string s) : m_data(s), m_position(0) {} +StringLexer::StringLexer(std::string s) : m_data(std::move(s)), m_position(0) {} StringLexer::Character StringLexer::Peek() { return m_data[m_position]; } diff --git a/gnu/llvm/lldb/source/Utility/StringList.cpp b/gnu/llvm/lldb/source/Utility/StringList.cpp index 809c5a02acf..baff34ae3a5 100644 --- a/gnu/llvm/lldb/source/Utility/StringList.cpp +++ b/gnu/llvm/lldb/source/Utility/StringList.cpp @@ -14,8 +14,8 @@ #include "llvm/ADT/ArrayRef.h" #include -#include -#include +#include +#include using namespace lldb_private; @@ -33,7 +33,7 @@ StringList::StringList(const char **strv, int strc) : m_strings() { } } -StringList::~StringList() {} +StringList::~StringList() = default; void StringList::AppendString(const char *str) { if (str) @@ -212,7 +212,7 @@ StringList &StringList::operator<<(const std::string &str) { return *this; } -StringList &StringList::operator<<(StringList strings) { +StringList &StringList::operator<<(const StringList &strings) { AppendList(strings); return *this; } diff --git a/gnu/llvm/lldb/source/Utility/StructuredData.cpp b/gnu/llvm/lldb/source/Utility/StructuredData.cpp index df1b35618e4..fc10fa539e9 100644 --- a/gnu/llvm/lldb/source/Utility/StructuredData.cpp +++ b/gnu/llvm/lldb/source/Utility/StructuredData.cpp @@ -11,8 +11,8 @@ #include "lldb/Utility/Status.h" #include "llvm/Support/MemoryBuffer.h" #include +#include #include -#include using namespace lldb_private; using namespace llvm; @@ -21,7 +21,8 @@ static StructuredData::ObjectSP ParseJSONValue(json::Value &value); static StructuredData::ObjectSP ParseJSONObject(json::Object *object); static StructuredData::ObjectSP ParseJSONArray(json::Array *array); -StructuredData::ObjectSP StructuredData::ParseJSON(std::string json_text) { +StructuredData::ObjectSP +StructuredData::ParseJSON(const std::string &json_text) { llvm::Expected value = json::parse(json_text); if (!value) { llvm::consumeError(value.takeError()); @@ -41,7 +42,12 @@ StructuredData::ParseJSONFromFile(const FileSpec &input_spec, Status &error) { buffer_or_error.getError().message()); return return_sp; } - return ParseJSON(buffer_or_error.get()->getBuffer().str()); + llvm::Expected value = + json::parse(buffer_or_error.get()->getBuffer().str()); + if (value) + return ParseJSONValue(*value); + error.SetErrorString(toString(value.takeError())); + return StructuredData::ObjectSP(); } static StructuredData::ObjectSP ParseJSONValue(json::Value &value) { @@ -51,21 +57,17 @@ static StructuredData::ObjectSP ParseJSONValue(json::Value &value) { if (json::Array *A = value.getAsArray()) return ParseJSONArray(A); - std::string s; - if (json::fromJSON(value, s)) - return std::make_shared(s); + if (auto s = value.getAsString()) + return std::make_shared(*s); - bool b; - if (json::fromJSON(value, b)) - return std::make_shared(b); + if (auto b = value.getAsBoolean()) + return std::make_shared(*b); - int64_t i; - if (json::fromJSON(value, i)) - return std::make_shared(i); + if (auto i = value.getAsInteger()) + return std::make_shared(*i); - double d; - if (json::fromJSON(value, d)) - return std::make_shared(d); + if (auto d = value.getAsNumber()) + return std::make_shared(*d); return StructuredData::ObjectSP(); } diff --git a/gnu/llvm/lldb/source/Utility/TildeExpressionResolver.cpp b/gnu/llvm/lldb/source/Utility/TildeExpressionResolver.cpp index c8a0800cb80..6311ae062f1 100644 --- a/gnu/llvm/lldb/source/Utility/TildeExpressionResolver.cpp +++ b/gnu/llvm/lldb/source/Utility/TildeExpressionResolver.cpp @@ -8,7 +8,7 @@ #include "lldb/Utility/TildeExpressionResolver.h" -#include +#include #include #include "llvm/ADT/STLExtras.h" @@ -27,7 +27,7 @@ using namespace llvm; namespace fs = llvm::sys::fs; namespace path = llvm::sys::path; -TildeExpressionResolver::~TildeExpressionResolver() {} +TildeExpressionResolver::~TildeExpressionResolver() = default; bool StandardTildeExpressionResolver::ResolveExact( StringRef Expr, SmallVectorImpl &Output) { @@ -75,9 +75,8 @@ bool StandardTildeExpressionResolver::ResolvePartial(StringRef Expr, bool TildeExpressionResolver::ResolveFullPath( StringRef Expr, llvm::SmallVectorImpl &Output) { - Output.clear(); if (!Expr.startswith("~")) { - Output.append(Expr.begin(), Expr.end()); + Output.assign(Expr.begin(), Expr.end()); return false; } @@ -85,8 +84,10 @@ bool TildeExpressionResolver::ResolveFullPath( StringRef Left = Expr.take_until([](char c) { return path::is_separator(c); }); - if (!ResolveExact(Left, Output)) + if (!ResolveExact(Left, Output)) { + Output.assign(Expr.begin(), Expr.end()); return false; + } Output.append(Expr.begin() + Left.size(), Expr.end()); return true; diff --git a/gnu/llvm/lldb/source/Utility/Timer.cpp b/gnu/llvm/lldb/source/Utility/Timer.cpp index d55c9863117..b59ce3b9f55 100644 --- a/gnu/llvm/lldb/source/Utility/Timer.cpp +++ b/gnu/llvm/lldb/source/Utility/Timer.cpp @@ -7,6 +7,8 @@ //===----------------------------------------------------------------------===// #include "lldb/Utility/Timer.h" #include "lldb/Utility/Stream.h" +#include "llvm/Support/ManagedStatic.h" +#include "llvm/Support/Signposts.h" #include #include @@ -14,10 +16,10 @@ #include #include -#include -#include -#include -#include +#include +#include +#include +#include using namespace lldb_private; @@ -28,6 +30,11 @@ typedef std::vector TimerStack; static std::atomic g_categories; } // end of anonymous namespace +/// Allows llvm::Timer to emit signposts when supported. +static llvm::ManagedStatic Signposts; + +llvm::SignpostEmitter &lldb_private::GetSignposts() { return *Signposts; } + std::atomic Timer::g_quiet(true); std::atomic Timer::g_display_depth(0); static std::mutex &GetFileMutex() { diff --git a/gnu/llvm/lldb/source/Utility/TraceGDBRemotePackets.cpp b/gnu/llvm/lldb/source/Utility/TraceGDBRemotePackets.cpp new file mode 100644 index 00000000000..5c1326a5f35 --- /dev/null +++ b/gnu/llvm/lldb/source/Utility/TraceGDBRemotePackets.cpp @@ -0,0 +1,130 @@ +//===-- TraceGDBRemotePackets.cpp -------------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#include "lldb/Utility/TraceGDBRemotePackets.h" + +using namespace llvm; +using namespace llvm::json; + +namespace lldb_private { +/// jLLDBTraceSupported +/// \{ +bool fromJSON(const json::Value &value, TraceSupportedResponse &packet, + Path path) { + ObjectMapper o(value, path); + return o && o.map("description", packet.description) && + o.map("name", packet.name); +} + +json::Value toJSON(const TraceSupportedResponse &packet) { + return json::Value( + Object{{"description", packet.description}, {"name", packet.name}}); +} +/// \} + +/// jLLDBTraceStart +/// \{ +bool TraceStartRequest::IsProcessTracing() const { return !(bool)tids; } + +bool fromJSON(const json::Value &value, TraceStartRequest &packet, Path path) { + ObjectMapper o(value, path); + return o && o.map("type", packet.type) && o.map("tids", packet.tids); +} + +json::Value toJSON(const TraceStartRequest &packet) { + return json::Value(Object{{"tids", packet.tids}, {"type", packet.type}}); +} +/// \} + +/// jLLDBTraceStop +/// \{ +TraceStopRequest::TraceStopRequest(llvm::StringRef type, + const std::vector &tids_) + : type(type) { + tids.emplace(); + for (lldb::tid_t tid : tids_) + tids->push_back(static_cast(tid)); +} + +bool TraceStopRequest::IsProcessTracing() const { return !(bool)tids; } + +bool fromJSON(const json::Value &value, TraceStopRequest &packet, Path path) { + ObjectMapper o(value, path); + return o && o.map("type", packet.type) && o.map("tids", packet.tids); +} + +json::Value toJSON(const TraceStopRequest &packet) { + return json::Value(Object{{"type", packet.type}, {"tids", packet.tids}}); +} +/// \} + +/// jLLDBTraceGetState +/// \{ +bool fromJSON(const json::Value &value, TraceGetStateRequest &packet, + Path path) { + ObjectMapper o(value, path); + return o && o.map("type", packet.type); +} + +json::Value toJSON(const TraceGetStateRequest &packet) { + return json::Value(Object{{"type", packet.type}}); +} + +bool fromJSON(const json::Value &value, TraceBinaryData &packet, Path path) { + ObjectMapper o(value, path); + return o && o.map("kind", packet.kind) && o.map("size", packet.size); +} + +json::Value toJSON(const TraceBinaryData &packet) { + return json::Value(Object{{"kind", packet.kind}, {"size", packet.size}}); +} + +bool fromJSON(const json::Value &value, TraceThreadState &packet, Path path) { + ObjectMapper o(value, path); + return o && o.map("tid", packet.tid) && + o.map("binaryData", packet.binaryData); +} + +json::Value toJSON(const TraceThreadState &packet) { + return json::Value( + Object{{"tid", packet.tid}, {"binaryData", packet.binaryData}}); +} + +bool fromJSON(const json::Value &value, TraceGetStateResponse &packet, + Path path) { + ObjectMapper o(value, path); + return o && o.map("tracedThreads", packet.tracedThreads) && + o.map("processBinaryData", packet.processBinaryData); +} + +json::Value toJSON(const TraceGetStateResponse &packet) { + return json::Value(Object{{"tracedThreads", packet.tracedThreads}, + {"processBinaryData", packet.processBinaryData}}); +} +/// \} + +/// jLLDBTraceGetBinaryData +/// \{ +json::Value toJSON(const TraceGetBinaryDataRequest &packet) { + return json::Value(Object{{"type", packet.type}, + {"kind", packet.kind}, + {"offset", packet.offset}, + {"tid", packet.tid}, + {"size", packet.size}}); +} + +bool fromJSON(const json::Value &value, TraceGetBinaryDataRequest &packet, + Path path) { + ObjectMapper o(value, path); + return o && o.map("type", packet.type) && o.map("kind", packet.kind) && + o.map("tid", packet.tid) && o.map("offset", packet.offset) && + o.map("size", packet.size); +} +/// \} + +} // namespace lldb_private diff --git a/gnu/llvm/lldb/source/Utility/TraceIntelPTGDBRemotePackets.cpp b/gnu/llvm/lldb/source/Utility/TraceIntelPTGDBRemotePackets.cpp new file mode 100644 index 00000000000..dbb93d8d1c5 --- /dev/null +++ b/gnu/llvm/lldb/source/Utility/TraceIntelPTGDBRemotePackets.cpp @@ -0,0 +1,46 @@ +//===-- TraceIntelPTGDBRemotePackets.cpp ------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#include "lldb/Utility/TraceIntelPTGDBRemotePackets.h" + +using namespace llvm; +using namespace llvm::json; + +namespace lldb_private { + +bool fromJSON(const json::Value &value, TraceIntelPTStartRequest &packet, + Path path) { + ObjectMapper o(value, path); + if (!o || !fromJSON(value, (TraceStartRequest &)packet, path) || + !o.map("enableTsc", packet.enableTsc) || + !o.map("psbPeriod", packet.psbPeriod) || + !o.map("threadBufferSize", packet.threadBufferSize) || + !o.map("processBufferSizeLimit", packet.processBufferSizeLimit)) + return false; + if (packet.tids && packet.processBufferSizeLimit) { + path.report("processBufferSizeLimit must be provided"); + return false; + } + if (!packet.tids && !packet.processBufferSizeLimit) { + path.report("processBufferSizeLimit must not be provided"); + return false; + } + return true; +} + +json::Value toJSON(const TraceIntelPTStartRequest &packet) { + json::Value base = toJSON((const TraceStartRequest &)packet); + base.getAsObject()->try_emplace("threadBufferSize", packet.threadBufferSize); + base.getAsObject()->try_emplace("processBufferSizeLimit", + packet.processBufferSizeLimit); + base.getAsObject()->try_emplace("psbPeriod", packet.psbPeriod); + base.getAsObject()->try_emplace("enableTsc", packet.enableTsc); + return base; +} + +} // namespace lldb_private diff --git a/gnu/llvm/lldb/source/Utility/UUID.cpp b/gnu/llvm/lldb/source/Utility/UUID.cpp index 4177b43de81..0adeb06e4c0 100644 --- a/gnu/llvm/lldb/source/Utility/UUID.cpp +++ b/gnu/llvm/lldb/source/Utility/UUID.cpp @@ -12,9 +12,9 @@ #include "llvm/ADT/StringRef.h" #include "llvm/Support/Format.h" -#include -#include -#include +#include +#include +#include using namespace lldb_private; @@ -35,6 +35,16 @@ static inline bool separate(size_t count) { } } +UUID UUID::fromCvRecord(UUID::CvRecordPdb70 debug_info) { + llvm::sys::swapByteOrder(debug_info.Uuid.Data1); + llvm::sys::swapByteOrder(debug_info.Uuid.Data2); + llvm::sys::swapByteOrder(debug_info.Uuid.Data3); + llvm::sys::swapByteOrder(debug_info.Age); + if (debug_info.Age) + return UUID::fromOptionalData(&debug_info, sizeof(debug_info)); + return UUID::fromOptionalData(&debug_info.Uuid, sizeof(debug_info.Uuid)); +} + std::string UUID::GetAsString(llvm::StringRef separator) const { std::string result; llvm::raw_string_ostream os(result); diff --git a/gnu/llvm/lldb/source/Utility/UnimplementedError.cpp b/gnu/llvm/lldb/source/Utility/UnimplementedError.cpp new file mode 100644 index 00000000000..034ad5b17b6 --- /dev/null +++ b/gnu/llvm/lldb/source/Utility/UnimplementedError.cpp @@ -0,0 +1,11 @@ +//===-- UnimplementedError.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 "lldb/Utility/UnimplementedError.h" + +char lldb_private::UnimplementedError::ID; diff --git a/gnu/llvm/lldb/source/Utility/UriParser.cpp b/gnu/llvm/lldb/source/Utility/UriParser.cpp index 8169b0eee12..c6ed2498589 100644 --- a/gnu/llvm/lldb/source/Utility/UriParser.cpp +++ b/gnu/llvm/lldb/source/Utility/UriParser.cpp @@ -10,7 +10,7 @@ #include -#include +#include #include using namespace lldb_private; diff --git a/gnu/llvm/lldb/source/Utility/UserID.cpp b/gnu/llvm/lldb/source/Utility/UserID.cpp index 8e0146b9349..5bae91a9128 100644 --- a/gnu/llvm/lldb/source/Utility/UserID.cpp +++ b/gnu/llvm/lldb/source/Utility/UserID.cpp @@ -9,7 +9,7 @@ #include "lldb/Utility/UserID.h" #include "lldb/Utility/Stream.h" -#include +#include using namespace lldb; using namespace lldb_private; diff --git a/gnu/llvm/lldb/source/Utility/VASprintf.cpp b/gnu/llvm/lldb/source/Utility/VASprintf.cpp index aea68dfff9f..5d361edf06e 100644 --- a/gnu/llvm/lldb/source/Utility/VASprintf.cpp +++ b/gnu/llvm/lldb/source/Utility/VASprintf.cpp @@ -12,9 +12,9 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" -#include -#include -#include +#include +#include +#include bool lldb_private::VASprintf(llvm::SmallVectorImpl &buf, const char *fmt, va_list args) { diff --git a/gnu/llvm/lldb/source/Utility/VMRange.cpp b/gnu/llvm/lldb/source/Utility/VMRange.cpp index 16c50d6e81b..184531b4bb2 100644 --- a/gnu/llvm/lldb/source/Utility/VMRange.cpp +++ b/gnu/llvm/lldb/source/Utility/VMRange.cpp @@ -15,8 +15,8 @@ #include #include -#include -#include +#include +#include using namespace lldb; using namespace lldb_private; diff --git a/gnu/llvm/lldb/source/Utility/XcodeSDK.cpp b/gnu/llvm/lldb/source/Utility/XcodeSDK.cpp index 066bf457966..4f64042e364 100644 --- a/gnu/llvm/lldb/source/Utility/XcodeSDK.cpp +++ b/gnu/llvm/lldb/source/Utility/XcodeSDK.cpp @@ -54,12 +54,12 @@ XcodeSDK::XcodeSDK(XcodeSDK::Info info) : m_name(GetName(info.type).str()) { } } -XcodeSDK &XcodeSDK::operator=(XcodeSDK other) { +XcodeSDK &XcodeSDK::operator=(const XcodeSDK &other) { m_name = other.m_name; return *this; } -bool XcodeSDK::operator==(XcodeSDK other) { +bool XcodeSDK::operator==(const XcodeSDK &other) { return m_name == other.m_name; } @@ -147,7 +147,7 @@ bool XcodeSDK::Info::operator==(const Info &other) const { std::tie(other.type, other.version, other.internal); } -void XcodeSDK::Merge(XcodeSDK other) { +void XcodeSDK::Merge(const XcodeSDK &other) { // The "bigger" SDK always wins. auto l = Parse(); auto r = other.Parse(); diff --git a/gnu/llvm/lldb/source/lldb.cpp b/gnu/llvm/lldb/source/lldb.cpp index 6d4ed66074d..371902f6c1b 100644 --- a/gnu/llvm/lldb/source/lldb.cpp +++ b/gnu/llvm/lldb/source/lldb.cpp @@ -6,16 +6,25 @@ // //===----------------------------------------------------------------------===// +#include "VCSVersion.inc" #include "lldb/lldb-private.h" +#include "clang/Basic/Version.h" using namespace lldb; using namespace lldb_private; -#include "clang/Basic/Version.h" +// LLDB_VERSION_STRING is set through a define so unlike the other defines +// expanded with CMake, it lacks the double quotes. +#define QUOTE(str) #str +#define EXPAND_AND_QUOTE(str) QUOTE(str) -#ifdef HAVE_VCS_VERSION_INC -#include "VCSVersion.inc" +static const char *GetLLDBVersion() { +#ifdef LLDB_VERSION_STRING + return EXPAND_AND_QUOTE(LLDB_VERSION_STRING); +#else + return "lldb version " CLANG_VERSION_STRING; #endif +} static const char *GetLLDBRevision() { #ifdef LLDB_REVISION @@ -33,19 +42,13 @@ static const char *GetLLDBRepository() { #endif } -#define QUOTE(str) #str -#define EXPAND_AND_QUOTE(str) QUOTE(str) - const char *lldb_private::GetVersion() { - // On platforms other than Darwin, report a version number in the same style - // as the clang tool. static std::string g_version_str; if (g_version_str.empty()) { - g_version_str += "lldb version "; - g_version_str += CLANG_VERSION_STRING; - + const char *lldb_version = GetLLDBVersion(); const char *lldb_repo = GetLLDBRepository(); const char *lldb_rev = GetLLDBRevision(); + g_version_str += lldb_version; if (lldb_repo || lldb_rev) { g_version_str += " ("; if (lldb_repo) diff --git a/gnu/llvm/lldb/third_party/Python/module/pexpect-4.6/.gitignore b/gnu/llvm/lldb/third_party/Python/module/pexpect-4.6/.gitignore new file mode 100644 index 00000000000..22cd4785f71 --- /dev/null +++ b/gnu/llvm/lldb/third_party/Python/module/pexpect-4.6/.gitignore @@ -0,0 +1,11 @@ +*.pyc +doc/_build +tests/log +build/ +dist/ +MANIFEST +*~ +.coverage* +htmlcov +*.egg-info/ +.cache/ diff --git a/gnu/llvm/lldb/third_party/Python/module/progress/progress.py b/gnu/llvm/lldb/third_party/Python/module/progress/progress.py index 3397cf04301..e4bd9d5fd5b 100644 --- a/gnu/llvm/lldb/third_party/Python/module/progress/progress.py +++ b/gnu/llvm/lldb/third_party/Python/module/progress/progress.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python from __future__ import print_function diff --git a/gnu/llvm/lldb/third_party/Python/module/ptyprocess-0.6.0/.gitignore b/gnu/llvm/lldb/third_party/Python/module/ptyprocess-0.6.0/.gitignore new file mode 100644 index 00000000000..4b46c269a4c --- /dev/null +++ b/gnu/llvm/lldb/third_party/Python/module/ptyprocess-0.6.0/.gitignore @@ -0,0 +1,7 @@ +__pycache__ +*.pyc + +/build/ +/dist/ +MANIFEST +docs/_build/ diff --git a/gnu/llvm/lldb/tools/argdumper/CMakeLists.txt b/gnu/llvm/lldb/tools/argdumper/CMakeLists.txt index 92494632519..29a2186af3c 100644 --- a/gnu/llvm/lldb/tools/argdumper/CMakeLists.txt +++ b/gnu/llvm/lldb/tools/argdumper/CMakeLists.txt @@ -4,3 +4,5 @@ add_lldb_tool(lldb-argdumper ADD_TO_FRAMEWORK LINK_COMPONENTS Support ) + +add_dependencies(liblldb lldb-argdumper) diff --git a/gnu/llvm/lldb/tools/darwin-debug/darwin-debug.cpp b/gnu/llvm/lldb/tools/darwin-debug/darwin-debug.cpp index b184cb5a652..435a3d11424 100644 --- a/gnu/llvm/lldb/tools/darwin-debug/darwin-debug.cpp +++ b/gnu/llvm/lldb/tools/darwin-debug/darwin-debug.cpp @@ -21,15 +21,15 @@ // on other systems. #if defined(__APPLE__) +#include #include +#include +#include +#include +#include #include -#include #include -#include #include -#include -#include -#include #include #include #include diff --git a/gnu/llvm/lldb/tools/debugserver/CMakeLists.txt b/gnu/llvm/lldb/tools/debugserver/CMakeLists.txt index fc23cf3c7e2..eba5c414913 100644 --- a/gnu/llvm/lldb/tools/debugserver/CMakeLists.txt +++ b/gnu/llvm/lldb/tools/debugserver/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.4.3) +cmake_minimum_required(VERSION 3.13.4) project(Debugserver LANGUAGES C CXX ASM-ATT) diff --git a/gnu/llvm/lldb/tools/debugserver/debugserver.xcodeproj/project.pbxproj b/gnu/llvm/lldb/tools/debugserver/debugserver.xcodeproj/project.pbxproj index 1c7a55f7108..df466d0c98d 100644 --- a/gnu/llvm/lldb/tools/debugserver/debugserver.xcodeproj/project.pbxproj +++ b/gnu/llvm/lldb/tools/debugserver/debugserver.xcodeproj/project.pbxproj @@ -9,24 +9,8 @@ /* Begin PBXBuildFile section */ 23043C9D1D35DBEC00FC25CA /* JSON.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 233B4EA51D2DB54300E98261 /* JSON.cpp */; }; 23043C9E1D35DBFA00FC25CA /* StringConvert.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 233B4EA81D2DB96A00E98261 /* StringConvert.cpp */; }; - 2307CCCB1D4A5D630016ABC0 /* LogFilterExactMatch.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 237821AE1D4917D20028B7A1 /* LogFilterExactMatch.cpp */; }; 233B4EA71D2DB54300E98261 /* JSON.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 233B4EA51D2DB54300E98261 /* JSON.cpp */; }; 233B4EA91D2DB96A00E98261 /* StringConvert.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 233B4EA81D2DB96A00E98261 /* StringConvert.cpp */; }; - 23562ED21D3424DF00AB2BD4 /* LogMessageOsLog.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 23562ED01D3424DF00AB2BD4 /* LogMessageOsLog.cpp */; }; - 23562ED31D3424DF00AB2BD4 /* LogMessageOsLog.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 23562ED01D3424DF00AB2BD4 /* LogMessageOsLog.cpp */; }; - 23562ED61D342A5A00AB2BD4 /* ActivityStore.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 23562ED51D342A5A00AB2BD4 /* ActivityStore.cpp */; }; - 23562ED71D342A5A00AB2BD4 /* ActivityStore.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 23562ED51D342A5A00AB2BD4 /* ActivityStore.cpp */; }; - 23562ED91D342B0000AB2BD4 /* LogMessage.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 23562ED81D342B0000AB2BD4 /* LogMessage.cpp */; }; - 23562EDA1D342B0000AB2BD4 /* LogMessage.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 23562ED81D342B0000AB2BD4 /* LogMessage.cpp */; }; - 237821B01D4917D20028B7A1 /* LogFilterExactMatch.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 237821AE1D4917D20028B7A1 /* LogFilterExactMatch.cpp */; }; - 23AC04C61D2F41A00072351D /* LogFilter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 23AC04C41D2F41A00072351D /* LogFilter.cpp */; }; - 23AC04C71D2F41A00072351D /* LogFilter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 23AC04C41D2F41A00072351D /* LogFilter.cpp */; }; - 23AC04CA1D2F42250072351D /* LogFilterChain.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 23AC04C81D2F42250072351D /* LogFilterChain.cpp */; }; - 23AC04CB1D2F42250072351D /* LogFilterChain.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 23AC04C81D2F42250072351D /* LogFilterChain.cpp */; }; - 23AC04CF1D2F58AF0072351D /* LogFilterRegex.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 23AC04CD1D2F58AF0072351D /* LogFilterRegex.cpp */; }; - 23AC04D01D2F58AF0072351D /* LogFilterRegex.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 23AC04CD1D2F58AF0072351D /* LogFilterRegex.cpp */; }; - 23AE72E41D25DECF00945BCE /* DarwinLogCollector.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 23AE72E21D25DECF00945BCE /* DarwinLogCollector.cpp */; }; - 23AE72E51D25DEE100945BCE /* DarwinLogCollector.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 23AE72E21D25DECF00945BCE /* DarwinLogCollector.cpp */; }; 23D1B0291D497E8B00FF831B /* OsLogger.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 23D1B0271D497E8B00FF831B /* OsLogger.cpp */; }; 23D1B02A1D497E8B00FF831B /* OsLogger.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 23D1B0271D497E8B00FF831B /* OsLogger.cpp */; }; 264D5D581293835600ED4C01 /* DNBArch.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 264D5D571293835600ED4C01 /* DNBArch.cpp */; }; @@ -108,27 +92,6 @@ 233B4EA51D2DB54300E98261 /* JSON.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSON.cpp; sourceTree = ""; }; 233B4EA61D2DB54300E98261 /* JSON.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSON.h; sourceTree = ""; }; 233B4EA81D2DB96A00E98261 /* StringConvert.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = StringConvert.cpp; path = ../../../source/Host/common/StringConvert.cpp; sourceTree = ""; }; - 23562ECF1D34110D00AB2BD4 /* DarwinLogTypes.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DarwinLogTypes.h; sourceTree = ""; }; - 23562ED01D3424DF00AB2BD4 /* LogMessageOsLog.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LogMessageOsLog.cpp; sourceTree = ""; }; - 23562ED11D3424DF00AB2BD4 /* LogMessageOsLog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LogMessageOsLog.h; sourceTree = ""; }; - 23562ED41D3426DD00AB2BD4 /* ActivityStore.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ActivityStore.h; sourceTree = ""; }; - 23562ED51D342A5A00AB2BD4 /* ActivityStore.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ActivityStore.cpp; sourceTree = ""; }; - 23562ED81D342B0000AB2BD4 /* LogMessage.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LogMessage.cpp; sourceTree = ""; }; - 237821AD1D4917D20028B7A1 /* CMakeLists.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = CMakeLists.txt; sourceTree = ""; }; - 237821AE1D4917D20028B7A1 /* LogFilterExactMatch.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LogFilterExactMatch.cpp; sourceTree = ""; }; - 237821AF1D4917D20028B7A1 /* LogFilterExactMatch.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LogFilterExactMatch.h; sourceTree = ""; }; - 23AC04C41D2F41A00072351D /* LogFilter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LogFilter.cpp; sourceTree = ""; }; - 23AC04C51D2F41A00072351D /* LogFilter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LogFilter.h; sourceTree = ""; }; - 23AC04C81D2F42250072351D /* LogFilterChain.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LogFilterChain.cpp; sourceTree = ""; }; - 23AC04C91D2F42250072351D /* LogFilterChain.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LogFilterChain.h; sourceTree = ""; }; - 23AC04CC1D2F42F10072351D /* DarwinLogInterfaces.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DarwinLogInterfaces.h; sourceTree = ""; }; - 23AC04CD1D2F58AF0072351D /* LogFilterRegex.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LogFilterRegex.cpp; sourceTree = ""; }; - 23AC04CE1D2F58AF0072351D /* LogFilterRegex.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LogFilterRegex.h; sourceTree = ""; }; - 23AC04D11D2F60130072351D /* LogMessage.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LogMessage.h; sourceTree = ""; }; - 23AE72E21D25DECF00945BCE /* DarwinLogCollector.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DarwinLogCollector.cpp; sourceTree = ""; }; - 23AE72E31D25DECF00945BCE /* DarwinLogCollector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DarwinLogCollector.h; sourceTree = ""; }; - 23AE72E61D25DEFB00945BCE /* ActivityStreamSPI.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ActivityStreamSPI.h; sourceTree = ""; }; - 23CF6F5E1D28A3760088ADC9 /* DarwinLogEvent.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DarwinLogEvent.h; sourceTree = ""; }; 23D1B0271D497E8B00FF831B /* OsLogger.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = OsLogger.cpp; sourceTree = ""; }; 23D1B0281D497E8B00FF831B /* OsLogger.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OsLogger.h; sourceTree = ""; }; 260828DE0CBAF7F400F95054 /* DNBRuntimeAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DNBRuntimeAction.h; sourceTree = ""; }; @@ -267,34 +230,6 @@ name = Products; sourceTree = ""; }; - 23AC04C31D2F3E9A0072351D /* DarwinLog */ = { - isa = PBXGroup; - children = ( - 237821AD1D4917D20028B7A1 /* CMakeLists.txt */, - 23562ED41D3426DD00AB2BD4 /* ActivityStore.h */, - 23562ED51D342A5A00AB2BD4 /* ActivityStore.cpp */, - 23AE72E61D25DEFB00945BCE /* ActivityStreamSPI.h */, - 23AE72E31D25DECF00945BCE /* DarwinLogCollector.h */, - 23AE72E21D25DECF00945BCE /* DarwinLogCollector.cpp */, - 23CF6F5E1D28A3760088ADC9 /* DarwinLogEvent.h */, - 23AC04CC1D2F42F10072351D /* DarwinLogInterfaces.h */, - 23562ECF1D34110D00AB2BD4 /* DarwinLogTypes.h */, - 23AC04C51D2F41A00072351D /* LogFilter.h */, - 23AC04C41D2F41A00072351D /* LogFilter.cpp */, - 23AC04C91D2F42250072351D /* LogFilterChain.h */, - 23AC04C81D2F42250072351D /* LogFilterChain.cpp */, - 237821AF1D4917D20028B7A1 /* LogFilterExactMatch.h */, - 237821AE1D4917D20028B7A1 /* LogFilterExactMatch.cpp */, - 23AC04CE1D2F58AF0072351D /* LogFilterRegex.h */, - 23AC04CD1D2F58AF0072351D /* LogFilterRegex.cpp */, - 23AC04D11D2F60130072351D /* LogMessage.h */, - 23562ED81D342B0000AB2BD4 /* LogMessage.cpp */, - 23562ED11D3424DF00AB2BD4 /* LogMessageOsLog.h */, - 23562ED01D3424DF00AB2BD4 /* LogMessageOsLog.cpp */, - ); - path = DarwinLog; - sourceTree = ""; - }; 266B5ECE1460A68200E43F0A /* arm64 */ = { isa = PBXGroup; children = ( @@ -395,7 +330,6 @@ 26C637E60C71334A0024798E /* MacOSX */ = { isa = PBXGroup; children = ( - 23AC04C31D2F3E9A0072351D /* DarwinLog */, 2695DD920D3EBFF6007E4CA2 /* CFBundle.h */, 2695DD910D3EBFF6007E4CA2 /* CFBundle.cpp */, 2695DD9A0D3EC160007E4CA2 /* CFString.h */, @@ -586,29 +520,21 @@ 26CE05B6115C36390022F371 /* MachTask.mm in Sources */, 26CE05B7115C363B0022F371 /* DNB.cpp in Sources */, AFEC3364194A8B0B00FF05C6 /* Genealogy.cpp in Sources */, - 23AC04CF1D2F58AF0072351D /* LogFilterRegex.cpp in Sources */, 233B4EA91D2DB96A00E98261 /* StringConvert.cpp in Sources */, - 23562ED21D3424DF00AB2BD4 /* LogMessageOsLog.cpp in Sources */, 26CE05B8115C363C0022F371 /* DNBBreakpoint.cpp in Sources */, 26CE05B9115C363D0022F371 /* DNBDataRef.cpp in Sources */, - 23AC04CA1D2F42250072351D /* LogFilterChain.cpp in Sources */, - 23562ED61D342A5A00AB2BD4 /* ActivityStore.cpp in Sources */, 26CE05BA115C363E0022F371 /* DNBLog.cpp in Sources */, - 23AC04C61D2F41A00072351D /* LogFilter.cpp in Sources */, 26CE05BB115C363F0022F371 /* DNBRegisterInfo.cpp in Sources */, 26CE05BC115C36420022F371 /* PThreadEvent.cpp in Sources */, 26CE05BD115C36430022F371 /* PThreadMutex.cpp in Sources */, 26CE05BE115C36440022F371 /* SysSignal.cpp in Sources */, - 23AE72E41D25DECF00945BCE /* DarwinLogCollector.cpp in Sources */, 26CE05BF115C364D0022F371 /* DNBArchImplX86_64.cpp in Sources */, 26CE05C0115C364F0022F371 /* DNBArchImplI386.cpp in Sources */, 26CE05C1115C36510022F371 /* DNBArchImpl.cpp in Sources */, 26CE05C5115C36590022F371 /* CFBundle.cpp in Sources */, 26CE05C3115C36580022F371 /* CFString.cpp in Sources */, - 23562ED91D342B0000AB2BD4 /* LogMessage.cpp in Sources */, 26CE05F1115C387C0022F371 /* PseudoTerminal.cpp in Sources */, 264D5D581293835600ED4C01 /* DNBArch.cpp in Sources */, - 237821B01D4917D20028B7A1 /* LogFilterExactMatch.cpp in Sources */, 266B5ED11460A68200E43F0A /* DNBArchImplARM64.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -629,38 +555,30 @@ 456F674D1AD46CE9002850C2 /* dbgnub-mig.defs in Sources */, 456F674E1AD46CE9002850C2 /* MachException.cpp in Sources */, 456F674F1AD46CE9002850C2 /* MachProcess.mm in Sources */, - 2307CCCB1D4A5D630016ABC0 /* LogFilterExactMatch.cpp in Sources */, 456F67501AD46CE9002850C2 /* MachThread.cpp in Sources */, 456F67511AD46CE9002850C2 /* MachThreadList.cpp in Sources */, 456F67521AD46CE9002850C2 /* MachVMMemory.cpp in Sources */, 456F67531AD46CE9002850C2 /* MachVMRegion.cpp in Sources */, - 23562ED71D342A5A00AB2BD4 /* ActivityStore.cpp in Sources */, 456F67541AD46CE9002850C2 /* MachTask.mm in Sources */, 456F67551AD46CE9002850C2 /* DNB.cpp in Sources */, 456F67561AD46CE9002850C2 /* Genealogy.cpp in Sources */, 456F67571AD46CE9002850C2 /* DNBBreakpoint.cpp in Sources */, 456F67581AD46CE9002850C2 /* DNBDataRef.cpp in Sources */, 456F67591AD46CE9002850C2 /* DNBLog.cpp in Sources */, - 23562ED31D3424DF00AB2BD4 /* LogMessageOsLog.cpp in Sources */, 456F675A1AD46CE9002850C2 /* DNBRegisterInfo.cpp in Sources */, 456F675B1AD46CE9002850C2 /* PThreadEvent.cpp in Sources */, 456F675C1AD46CE9002850C2 /* PThreadMutex.cpp in Sources */, 456F675D1AD46CE9002850C2 /* SysSignal.cpp in Sources */, - 23AE72E51D25DEE100945BCE /* DarwinLogCollector.cpp in Sources */, 456F675E1AD46CE9002850C2 /* DNBArchImplX86_64.cpp in Sources */, - 23562EDA1D342B0000AB2BD4 /* LogMessage.cpp in Sources */, 456F675F1AD46CE9002850C2 /* DNBArchImplI386.cpp in Sources */, 456F67601AD46CE9002850C2 /* DNBArchImpl.cpp in Sources */, - 23AC04C71D2F41A00072351D /* LogFilter.cpp in Sources */, 23043C9E1D35DBFA00FC25CA /* StringConvert.cpp in Sources */, AF588449206077BD00A0CB5A /* SocketAddress.cpp in Sources */, 456F67621AD46CE9002850C2 /* CFString.cpp in Sources */, - 23AC04CB1D2F42250072351D /* LogFilterChain.cpp in Sources */, AF48558D1D75127500D19C07 /* StdStringExtractor.cpp in Sources */, 456F67641AD46CE9002850C2 /* CFBundle.cpp in Sources */, 456F67651AD46CE9002850C2 /* PseudoTerminal.cpp in Sources */, 456F67671AD46CE9002850C2 /* DNBArch.cpp in Sources */, - 23AC04D01D2F58AF0072351D /* LogFilterRegex.cpp in Sources */, 456F67691AD46CE9002850C2 /* DNBArchImplARM64.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -743,54 +661,17 @@ }; name = Release; }; - 262419A11198A93E00067686 /* BuildAndIntegration */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - "ARCHS[sdk=iphoneos*]" = arm64; - "ARCHS[sdk=macosx*]" = "$(ARCHS_STANDARD_64_BIT)"; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - CURRENT_PROJECT_VERSION = 360.99.0; - DEAD_CODE_STRIPPING = YES; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_NO_COMMON_BLOCKS = YES; - GCC_VERSION = com.apple.compilers.llvm.clang.1_0; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - LLDB_COMPRESSION_LDFLAGS = "-lcompression"; - LLDB_OS_LOG_CFLAGS = "-DLLDB_USE_OS_LOG=$(LLDB_USE_OS_LOG)"; - LLDB_USE_OS_LOG = 1; - OTHER_CFLAGS = ""; - STRIPFLAGS = "-x"; - STRIP_STYLE = debugging; - VERSIONING_SYSTEM = "apple-generic"; - VERSION_INFO_BUILDER = "$(USER)"; - }; - name = BuildAndIntegration; - }; - 262419A21198A93E00067686 /* BuildAndIntegration */ = { + 26CE0596115C31C30022F371 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; CLANG_CXX_LIBRARY = "libc++"; "CODE_SIGN_ENTITLEMENTS[sdk=*]" = "source/debugserver-entitlements.plist"; "CODE_SIGN_ENTITLEMENTS[sdk=macosx*]" = "source/debugserver-macosx-entitlements.plist"; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "-"; - "CODE_SIGN_IDENTITY[sdk=macosx*]" = "-"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; + "CODE_SIGN_IDENTITY[sdk=macosx*]" = ""; COPY_PHASE_STRIP = YES; CURRENT_PROJECT_VERSION = 360.99.0; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; FRAMEWORK_SEARCH_PATHS = $SDKROOT/System/Library/PrivateFrameworks; "FRAMEWORK_SEARCH_PATHS[sdk=iphoneos*][arch=*]" = ( "$(SDKROOT)/System/Library/PrivateFrameworks", @@ -798,11 +679,11 @@ ); "FRAMEWORK_SEARCH_PATHS[sdk=macosx*][arch=*]" = "$(SDKROOT)/System/Library/PrivateFrameworks"; GCC_C_LANGUAGE_STANDARD = c99; - GCC_PREPROCESSOR_DEFINITIONS = LLDB_DEBUGSERVER_BUILDANDINTEGRATION; + GCC_DYNAMIC_NO_PIC = NO; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = LLDB_DEBUGSERVER_DEBUG; GCC_VERSION = com.apple.compilers.llvm.clang.1_0; - HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders; INSTALL_PATH = /usr/bin; - "INSTALL_PATH[sdk=iphoneos*]" = /Developer/usr/bin/; LLDB_COMPRESSION_LDFLAGS = "-lcompression"; LLDB_DEBUGSERVER = 1; LLDB_ENERGY_CFLAGS = ""; @@ -810,15 +691,15 @@ LLDB_ENERGY_LDFLAGS = "-lpmenergy -lpmsample"; OTHER_CFLAGS = ( "-Wparentheses", - "$(LLDB_ENERGY_CFLAGS)", "-DDT_VARIANT_$(DT_VARIANT)", + "$(LLDB_ENERGY_CFLAGS)", "$(LLDB_OS_LOG_CFLAGS)", ); - "OTHER_CFLAGS[sdk=iphoneos*]" = ( + "OTHER_CFLAGS[sdk=iphoneos*][arch=*]" = ( "-Wparentheses", "-DWITH_LOCKDOWN", - "-DWITH_FBS", "-DWITH_BKS", + "-DWITH_FBS", "-DOS_OBJECT_USE_OBJC=0", "$(LLDB_ENERGY_CFLAGS)", "$(LLDB_OS_LOG_CFLAGS)", @@ -826,6 +707,10 @@ "$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders", ); "OTHER_CPLUSPLUSFLAGS[sdk=iphoneos*][arch=*]" = "$(OTHER_CFLAGS)"; + "OTHER_CPLUSPLUSFLAGS[sdk=watchos*]" = ( + "$(OTHER_CFLAGS)", + "-DWITH_CAROUSEL=1", + ); OTHER_LDFLAGS = ""; "OTHER_LDFLAGS[sdk=iphoneos*][arch=*]" = ( "-framework", @@ -850,65 +735,7 @@ "-framework", Security, ); - OTHER_MIGFLAGS = "-I$(DERIVED_FILE_DIR)"; - PRODUCT_NAME = debugserver; - SDKROOT = macosx; - SKIP_INSTALL = YES; - "SKIP_INSTALL[sdk=iphoneos*]" = NO; - STRIP_INSTALLED_PRODUCT = YES; - USER_HEADER_SEARCH_PATHS = "./source ../../source $(DERIVED_SOURCES_DIR) ../../include"; - ZERO_LINK = NO; - }; - name = BuildAndIntegration; - }; - 26CE0596115C31C30022F371 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; - CLANG_CXX_LIBRARY = "libc++"; - "CODE_SIGN_ENTITLEMENTS[sdk=*]" = "source/debugserver-entitlements.plist"; - "CODE_SIGN_ENTITLEMENTS[sdk=macosx*]" = "source/debugserver-macosx-entitlements.plist"; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; - "CODE_SIGN_IDENTITY[sdk=macosx*]" = ""; - COPY_PHASE_STRIP = YES; - CURRENT_PROJECT_VERSION = 360.99.0; - FRAMEWORK_SEARCH_PATHS = $SDKROOT/System/Library/PrivateFrameworks; - "FRAMEWORK_SEARCH_PATHS[sdk=iphoneos*][arch=*]" = ( - "$(SDKROOT)/System/Library/PrivateFrameworks", - "$(SDKROOT)/Developer/Library/PrivateFrameworks", - ); - "FRAMEWORK_SEARCH_PATHS[sdk=macosx*][arch=*]" = "$(SDKROOT)/System/Library/PrivateFrameworks"; - GCC_C_LANGUAGE_STANDARD = c99; - GCC_DYNAMIC_NO_PIC = NO; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = LLDB_DEBUGSERVER_DEBUG; - GCC_VERSION = com.apple.compilers.llvm.clang.1_0; - INSTALL_PATH = /usr/bin; - LLDB_COMPRESSION_LDFLAGS = "-lcompression"; - LLDB_DEBUGSERVER = 1; - LLDB_ENERGY_CFLAGS = ""; - "LLDB_ENERGY_CFLAGS[sdk=*internal]" = "-DLLDB_ENERGY"; - LLDB_ENERGY_LDFLAGS = "-lpmenergy -lpmsample"; - OTHER_CFLAGS = ( - "-Wparentheses", - "-DDT_VARIANT_$(DT_VARIANT)", - "$(LLDB_ENERGY_CFLAGS)", - "$(LLDB_OS_LOG_CFLAGS)", - ); - "OTHER_CFLAGS[sdk=iphoneos*][arch=*]" = ( - "-Wparentheses", - "-DWITH_LOCKDOWN", - "-DWITH_BKS", - "-DWITH_FBS", - "-DOS_OBJECT_USE_OBJC=0", - "$(LLDB_ENERGY_CFLAGS)", - "$(LLDB_OS_LOG_CFLAGS)", - "-isystem", - "$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders", - ); - "OTHER_CPLUSPLUSFLAGS[sdk=iphoneos*][arch=*]" = "$(OTHER_CFLAGS)"; - OTHER_LDFLAGS = ""; - "OTHER_LDFLAGS[sdk=iphoneos*][arch=*]" = ( + "OTHER_LDFLAGS[sdk=watchos*]" = ( "-framework", SpringBoardServices, "-framework", @@ -920,16 +747,8 @@ MobileCoreServices, "$(LLDB_ENERGY_LDFLAGS)", "$(LLDB_COMPRESSION_LDFLAGS)", - ); - "OTHER_LDFLAGS[sdk=macosx*]" = ( - "-sectcreate", - __TEXT, - __info_plist, - "$(PROJECT_DIR)/resources/lldb-debugserver-Info.plist", - "$(LLDB_ENERGY_LDFLAGS)", - "$(LLDB_COMPRESSION_LDFLAGS)", "-framework", - Security, + CarouselServices, ); OTHER_MIGFLAGS = "-I$(DERIVED_FILE_DIR)"; PRODUCT_NAME = debugserver; @@ -987,6 +806,10 @@ "$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders", ); "OTHER_CPLUSPLUSFLAGS[sdk=iphoneos*][arch=*]" = "$(OTHER_CFLAGS)"; + "OTHER_CPLUSPLUSFLAGS[sdk=watchos*]" = ( + "$(OTHER_CFLAGS)", + "-DWITH_CAROUSEL=1", + ); OTHER_LDFLAGS = ""; "OTHER_LDFLAGS[sdk=iphoneos*][arch=*]" = ( "-framework", @@ -1011,6 +834,21 @@ "-framework", Security, ); + "OTHER_LDFLAGS[sdk=watchos*]" = ( + "-framework", + SpringBoardServices, + "-framework", + BackBoardServices, + "-llockdown", + "-framework", + FrontBoardServices, + "-framework", + MobileCoreServices, + "$(LLDB_ENERGY_LDFLAGS)", + "$(LLDB_COMPRESSION_LDFLAGS)", + "-framework", + CarouselServices, + ); OTHER_MIGFLAGS = "-I$(DERIVED_FILE_DIR)"; PRODUCT_NAME = debugserver; "PROVISIONING_PROFILE[sdk=iphoneos*]" = ""; @@ -1110,67 +948,6 @@ }; name = Debug; }; - 456F676F1AD46CE9002850C2 /* DebugClang */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; - CLANG_CXX_LIBRARY = "libc++"; - "CODE_SIGN_ENTITLEMENTS[sdk=*]" = "source/debugserver-entitlements.plist"; - "CODE_SIGN_ENTITLEMENTS[sdk=macosx*]" = "source/debugserver-macosx-entitlements.plist"; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; - "CODE_SIGN_IDENTITY[sdk=macosx*]" = ""; - COPY_PHASE_STRIP = YES; - CURRENT_PROJECT_VERSION = 360.99.0; - FRAMEWORK_SEARCH_PATHS = $SDKROOT/System/Library/PrivateFrameworks; - "FRAMEWORK_SEARCH_PATHS[sdk=iphoneos*][arch=*]" = ( - "$(SDKROOT)/System/Library/PrivateFrameworks", - "$(SDKROOT)/Developer/Library/PrivateFrameworks", - ); - "FRAMEWORK_SEARCH_PATHS[sdk=macosx*][arch=*]" = "$(SDKROOT)/System/Library/PrivateFrameworks"; - GCC_C_LANGUAGE_STANDARD = c99; - GCC_DYNAMIC_NO_PIC = NO; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = LLDB_DEBUGSERVER_DEBUG; - GCC_VERSION = com.apple.compilers.llvm.clang.1_0; - INSTALL_PATH = /usr/local/bin; - LLDB_DEBUGSERVER = 1; - LLDB_ENERGY_CFLAGS = ""; - "LLDB_ENERGY_CFLAGS[sdk=*.internal]" = "-DLLDB_ENERGY"; - LLDB_ENERGY_LDFLAGS = "-lpmenergy -lpmsample"; - OTHER_CFLAGS = "$(LLDB_ENERGY_CFLAGS)"; - "OTHER_CFLAGS[sdk=iphoneos*][arch=*]" = ( - "-Wparentheses", - "-DOS_OBJECT_USE_OBJC=0", - "-DDEBUGSERVER_PROGRAM_SYMBOL=debugserver_nonui", - "$(LLDB_OS_LOG_CFLAGS)", - ); - "OTHER_CPLUSPLUSFLAGS[sdk=iphoneos*][arch=*]" = "$(OTHER_CFLAGS)"; - OTHER_LDFLAGS = ""; - "OTHER_LDFLAGS[sdk=iphoneos*][arch=*]" = ( - "-framework", - Foundation, - "$(LLDB_ENERGY_LDFLAGS)", - "$(LLDB_COMPRESSION_LDFLAGS)", - ); - "OTHER_LDFLAGS[sdk=macosx*]" = ( - "-sectcreate", - __TEXT, - __info_plist, - "$(PROJECT_DIR)/resources/lldb-debugserver-Info.plist", - "$(LLDB_ENERGY_LDFLAGS)", - "$(LLDB_COMPRESSION_LDFLAGS)", - ); - OTHER_MIGFLAGS = "-I$(DERIVED_FILE_DIR)"; - PRODUCT_NAME = "debugserver-nonui"; - "PROVISIONING_PROFILE[sdk=iphoneos*]" = ""; - "PROVISIONING_PROFILE[sdk=macosx*]" = ""; - SDKROOT = macosx; - SKIP_INSTALL = YES; - USER_HEADER_SEARCH_PATHS = "./source ../../source $(DERIVED_SOURCES_DIR) ../../include"; - ZERO_LINK = NO; - }; - name = DebugClang; - }; 456F67701AD46CE9002850C2 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { @@ -1238,606 +1015,6 @@ }; name = Release; }; - 456F67711AD46CE9002850C2 /* BuildAndIntegration */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; - CLANG_CXX_LIBRARY = "libc++"; - "CODE_SIGN_ENTITLEMENTS[sdk=*]" = "source/debugserver-entitlements.plist"; - "CODE_SIGN_ENTITLEMENTS[sdk=macosx*]" = "source/debugserver-macosx-entitlements.plist"; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "-"; - "CODE_SIGN_IDENTITY[sdk=macosx*]" = "-"; - COPY_PHASE_STRIP = YES; - CURRENT_PROJECT_VERSION = 360.99.0; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - FRAMEWORK_SEARCH_PATHS = $SDKROOT/System/Library/PrivateFrameworks; - "FRAMEWORK_SEARCH_PATHS[sdk=iphoneos*][arch=*]" = ( - "$(SDKROOT)/System/Library/PrivateFrameworks", - "$(SDKROOT)/Developer/Library/PrivateFrameworks", - ); - "FRAMEWORK_SEARCH_PATHS[sdk=macosx*][arch=*]" = "$(SDKROOT)/System/Library/PrivateFrameworks"; - GCC_C_LANGUAGE_STANDARD = c99; - GCC_PREPROCESSOR_DEFINITIONS = LLDB_DEBUGSERVER_BUILDANDINTEGRATION; - GCC_VERSION = com.apple.compilers.llvm.clang.1_0; - HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders; - INSTALL_PATH = /usr/local/bin; - "INSTALL_PATH[sdk=iphoneos*]" = /usr/local/bin; - LLDB_DEBUGSERVER = 1; - LLDB_ENERGY_CFLAGS = ""; - "LLDB_ENERGY_CFLAGS[sdk=*.internal]" = "-DLLDB_ENERGY"; - LLDB_ENERGY_LDFLAGS = "-lpmenergy -lpmsample"; - OTHER_CFLAGS = ( - "-Wparentheses", - "$(LLDB_ENERGY_CFLAGS)", - "-DDEBUGSERVER_PROGRAM_SYMBOL=debugserver_nonui", - "$(LLDB_OS_LOG_CFLAGS)", - ); - "OTHER_CFLAGS[sdk=iphoneos*]" = ( - "-Wparentheses", - "-DOS_OBJECT_USE_OBJC=0", - "-DDEBUGSERVER_PROGRAM_SYMBOL=debugserver_nonui", - "$(LLDB_OS_LOG_CFLAGS)", - ); - OTHER_CPLUSPLUSFLAGS = "$(OTHER_CFLAGS)"; - "OTHER_CPLUSPLUSFLAGS[sdk=iphoneos*][arch=*]" = "$(OTHER_CFLAGS)"; - "OTHER_LDFLAGS[sdk=iphoneos*][arch=*]" = ( - "-framework", - Foundation, - ); - "OTHER_LDFLAGS[sdk=macosx*]" = ( - "-sectcreate", - __TEXT, - __info_plist, - "$(PROJECT_DIR)/resources/lldb-debugserver-Info.plist", - "$(LLDB_ENERGY_LDFLAGS)", - ); - OTHER_MIGFLAGS = "-I$(DERIVED_FILE_DIR)"; - PRODUCT_NAME = "debugserver-nonui"; - SDKROOT = macosx; - SKIP_INSTALL = YES; - "SKIP_INSTALL[sdk=iphoneos*]" = NO; - STRIP_INSTALLED_PRODUCT = YES; - USER_HEADER_SEARCH_PATHS = "./source ../../source $(DERIVED_SOURCES_DIR) ../../include"; - ZERO_LINK = NO; - }; - name = BuildAndIntegration; - }; - 4968B7A916657FAE00741ABB /* DebugClang */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - "ARCHS[sdk=iphoneos*]" = arm64; - "ARCHS[sdk=macosx*]" = "$(ARCHS_STANDARD_64_BIT)"; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - CODE_SIGN_IDENTITY = ""; - COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 360.99.0; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_NO_COMMON_BLOCKS = YES; - GCC_VERSION = com.apple.compilers.llvm.clang.1_0; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - LLDB_COMPRESSION_LDFLAGS = "-lcompression"; - LLDB_OS_LOG_CFLAGS = "-DLLDB_USE_OS_LOG=$(LLDB_USE_OS_LOG)"; - LLDB_USE_OS_LOG = 0; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = macosx; - STRIP_INSTALLED_PRODUCT = NO; - VERSIONING_SYSTEM = "apple-generic"; - VERSION_INFO_BUILDER = "$(USER)"; - }; - name = DebugClang; - }; - 4968B7AA16657FAE00741ABB /* DebugClang */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; - CLANG_CXX_LIBRARY = "libc++"; - "CODE_SIGN_ENTITLEMENTS[sdk=*]" = "source/debugserver-entitlements.plist"; - "CODE_SIGN_ENTITLEMENTS[sdk=macosx*]" = "source/debugserver-macosx-entitlements.plist"; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; - "CODE_SIGN_IDENTITY[sdk=macosx*]" = ""; - COPY_PHASE_STRIP = YES; - CURRENT_PROJECT_VERSION = 360.99.0; - FRAMEWORK_SEARCH_PATHS = $SDKROOT/System/Library/PrivateFrameworks; - "FRAMEWORK_SEARCH_PATHS[sdk=iphoneos*][arch=*]" = ( - "$(SDKROOT)/System/Library/PrivateFrameworks", - "$(SDKROOT)/Developer/Library/PrivateFrameworks", - ); - "FRAMEWORK_SEARCH_PATHS[sdk=macosx*][arch=*]" = "$(SDKROOT)/System/Library/PrivateFrameworks"; - GCC_C_LANGUAGE_STANDARD = c99; - GCC_DYNAMIC_NO_PIC = NO; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = LLDB_DEBUGSERVER_DEBUG; - GCC_VERSION = com.apple.compilers.llvm.clang.1_0; - INSTALL_PATH = /usr/bin; - LLDB_COMPRESSION_LDFLAGS = "-lcompression"; - LLDB_DEBUGSERVER = 1; - LLDB_ENERGY_CFLAGS = ""; - "LLDB_ENERGY_CFLAGS[sdk=*.internal]" = "-DLLDB_ENERGY"; - LLDB_ENERGY_LDFLAGS = "-lpmenergy -lpmsample"; - OTHER_CFLAGS = ( - "-Wparentheses", - "-DDT_VARIANT_$(DT_VARIANT)", - "$(LLDB_ENERGY_CFLAGS)", - "$(LLDB_OS_LOG_CFLAGS)", - ); - "OTHER_CFLAGS[sdk=iphoneos*][arch=*]" = ( - "-Wparentheses", - "-DWITH_LOCKDOWN", - "-DWITH_FBS", - "-DWITH_BKS", - "-DOS_OBJECT_USE_OBJC=0", - "$(LLDB_ENERGY_CFLAGS)", - "$(LLDB_OS_LOG_CFLAGS)", - "-isystem", - "$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders", - ); - "OTHER_CPLUSPLUSFLAGS[sdk=iphoneos*][arch=*]" = "$(OTHER_CFLAGS)"; - "OTHER_LDFLAGS[sdk=iphoneos*][arch=*]" = ( - "-framework", - SpringBoardServices, - "-framework", - BackBoardServices, - "-llockdown", - "-framework", - FrontBoardServices, - "-framework", - MobileCoreServices, - "$(LLDB_ENERGY_LDFLAGS)", - "$(LLDB_COMPRESSION_LDFLAGS)", - ); - "OTHER_LDFLAGS[sdk=macosx*]" = ( - "-sectcreate", - __TEXT, - __info_plist, - "$(PROJECT_DIR)/resources/lldb-debugserver-Info.plist", - "$(LLDB_ENERGY_LDFLAGS)", - "$(LLDB_COMPRESSION_LDFLAGS)", - ); - OTHER_MIGFLAGS = "-I$(DERIVED_FILE_DIR)"; - PRODUCT_NAME = debugserver; - "PROVISIONING_PROFILE[sdk=iphoneos*]" = ""; - "PROVISIONING_PROFILE[sdk=macosx*]" = ""; - SDKROOT = macosx; - SKIP_INSTALL = YES; - USER_HEADER_SEARCH_PATHS = "./source ../../source $(DERIVED_SOURCES_DIR) ../../include"; - ZERO_LINK = NO; - }; - name = DebugClang; - }; - 940AD5251B1FE3B10051E88F /* DebugPresubmission */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - "ARCHS[sdk=iphoneos*]" = arm64; - "ARCHS[sdk=macosx*]" = "$(ARCHS_STANDARD_64_BIT)"; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - CODE_SIGN_IDENTITY = ""; - COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 360.99.0; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_NO_COMMON_BLOCKS = YES; - GCC_VERSION = com.apple.compilers.llvm.clang.1_0; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - LLDB_COMPRESSION_LDFLAGS = "-lcompression"; - LLDB_OS_LOG_CFLAGS = "-DLLDB_USE_OS_LOG=$(LLDB_USE_OS_LOG)"; - LLDB_USE_OS_LOG = 0; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = macosx; - STRIP_INSTALLED_PRODUCT = NO; - VERSIONING_SYSTEM = "apple-generic"; - VERSION_INFO_BUILDER = "$(USER)"; - }; - name = DebugPresubmission; - }; - 940AD5261B1FE3B10051E88F /* DebugPresubmission */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; - CLANG_CXX_LIBRARY = "libc++"; - "CODE_SIGN_ENTITLEMENTS[sdk=*]" = "source/debugserver-entitlements.plist"; - "CODE_SIGN_ENTITLEMENTS[sdk=macosx*]" = "source/debugserver-macosx-entitlements.plist"; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; - "CODE_SIGN_IDENTITY[sdk=macosx*]" = ""; - COPY_PHASE_STRIP = YES; - CURRENT_PROJECT_VERSION = 360.99.0; - FRAMEWORK_SEARCH_PATHS = $SDKROOT/System/Library/PrivateFrameworks; - "FRAMEWORK_SEARCH_PATHS[sdk=iphoneos*][arch=*]" = ( - "$(SDKROOT)/System/Library/PrivateFrameworks", - "$(SDKROOT)/Developer/Library/PrivateFrameworks", - ); - "FRAMEWORK_SEARCH_PATHS[sdk=macosx*][arch=*]" = "$(SDKROOT)/System/Library/PrivateFrameworks"; - GCC_C_LANGUAGE_STANDARD = c99; - GCC_DYNAMIC_NO_PIC = NO; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = LLDB_DEBUGSERVER_DEBUG; - GCC_VERSION = com.apple.compilers.llvm.clang.1_0; - INSTALL_PATH = /usr/bin; - LLDB_COMPRESSION_LDFLAGS = "-lcompression"; - LLDB_DEBUGSERVER = 1; - LLDB_ENERGY_CFLAGS = ""; - "LLDB_ENERGY_CFLAGS[sdk=*.internal]" = "-DLLDB_ENERGY"; - LLDB_ENERGY_LDFLAGS = "-lpmenergy -lpmsample"; - OTHER_CFLAGS = ( - "-Wparentheses", - "$(LLDB_ENERGY_CFLAGS)", - "$(LLDB_OS_LOG_CFLAGS)", - ); - "OTHER_CFLAGS[sdk=iphoneos*][arch=*]" = ( - "-Wparentheses", - "-DWITH_LOCKDOWN", - "-DWITH_FBS", - "-DWITH_BKS", - "-DOS_OBJECT_USE_OBJC=0", - "$(LLDB_ENERGY_CFLAGS)", - "$(LLDB_OS_LOG_CFLAGS)", - "-isystem", - "$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders", - ); - "OTHER_CPLUSPLUSFLAGS[sdk=iphoneos*][arch=*]" = "$(OTHER_CFLAGS)"; - "OTHER_LDFLAGS[sdk=iphoneos*][arch=*]" = ( - "-framework", - SpringBoardServices, - "-framework", - BackBoardServices, - "-llockdown", - "-framework", - FrontBoardServices, - "-framework", - MobileCoreServices, - "$(LLDB_ENERGY_LDFLAGS)", - "$(LLDB_COMPRESSION_LDFLAGS)", - ); - "OTHER_LDFLAGS[sdk=macosx*]" = ( - "-sectcreate", - __TEXT, - __info_plist, - "$(PROJECT_DIR)/resources/lldb-debugserver-Info.plist", - "$(LLDB_ENERGY_LDFLAGS)", - "$(LLDB_COMPRESSION_LDFLAGS)", - ); - OTHER_MIGFLAGS = "-I$(DERIVED_FILE_DIR)"; - PRODUCT_NAME = debugserver; - "PROVISIONING_PROFILE[sdk=iphoneos*]" = ""; - "PROVISIONING_PROFILE[sdk=macosx*]" = ""; - SDKROOT = macosx; - SKIP_INSTALL = YES; - USER_HEADER_SEARCH_PATHS = "./source ../../source $(DERIVED_SOURCES_DIR) ../../include"; - ZERO_LINK = NO; - }; - name = DebugPresubmission; - }; - 940AD5271B1FE3B10051E88F /* DebugPresubmission */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; - CLANG_CXX_LIBRARY = "libc++"; - "CODE_SIGN_ENTITLEMENTS[sdk=*]" = "source/debugserver-entitlements.plist"; - "CODE_SIGN_ENTITLEMENTS[sdk=macosx*]" = "source/debugserver-macosx-entitlements.plist"; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; - "CODE_SIGN_IDENTITY[sdk=macosx*]" = ""; - COPY_PHASE_STRIP = YES; - CURRENT_PROJECT_VERSION = 360.99.0; - FRAMEWORK_SEARCH_PATHS = $SDKROOT/System/Library/PrivateFrameworks; - "FRAMEWORK_SEARCH_PATHS[sdk=iphoneos*][arch=*]" = ( - "$(SDKROOT)/System/Library/PrivateFrameworks", - "$(SDKROOT)/Developer/Library/PrivateFrameworks", - ); - "FRAMEWORK_SEARCH_PATHS[sdk=macosx*][arch=*]" = "$(SDKROOT)/System/Library/PrivateFrameworks"; - GCC_C_LANGUAGE_STANDARD = c99; - GCC_DYNAMIC_NO_PIC = NO; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = LLDB_DEBUGSERVER_DEBUG; - GCC_VERSION = com.apple.compilers.llvm.clang.1_0; - INSTALL_PATH = /usr/local/bin; - LLDB_DEBUGSERVER = 1; - LLDB_ENERGY_CFLAGS = ""; - "LLDB_ENERGY_CFLAGS[sdk=*.internal]" = "-DLLDB_ENERGY"; - LLDB_ENERGY_LDFLAGS = "-lpmenergy -lpmsample"; - OTHER_CFLAGS = ( - "-Wparentheses", - "$(LLDB_ENERGY_CFLAGS)", - "-DDEBUGSERVER_PROGRAM_SYMBOL=debugserver_nonui", - "$(LLDB_OS_LOG_CFLAGS)", - ); - "OTHER_CFLAGS[sdk=iphoneos*][arch=*]" = ( - "-Wparentheses", - "-DOS_OBJECT_USE_OBJC=0", - "-DDEBUGSERVER_PROGRAM_SYMBOL=debugserver_nonui", - "$(LLDB_OS_LOG_CFLAGS)", - ); - "OTHER_CPLUSPLUSFLAGS[sdk=iphoneos*][arch=*]" = "$(OTHER_CFLAGS)"; - "OTHER_LDFLAGS[sdk=iphoneos*][arch=*]" = ( - "-framework", - Foundation, - ); - "OTHER_LDFLAGS[sdk=macosx*]" = ( - "-sectcreate", - __TEXT, - __info_plist, - "$(PROJECT_DIR)/resources/lldb-debugserver-Info.plist", - "$(LLDB_ENERGY_LDFLAGS)", - ); - OTHER_MIGFLAGS = "-I$(DERIVED_FILE_DIR)"; - PRODUCT_NAME = "debugserver-nonui"; - "PROVISIONING_PROFILE[sdk=iphoneos*]" = ""; - "PROVISIONING_PROFILE[sdk=macosx*]" = ""; - SDKROOT = macosx; - SKIP_INSTALL = YES; - USER_HEADER_SEARCH_PATHS = "./source ../../source $(DERIVED_SOURCES_DIR) ../../include"; - ZERO_LINK = NO; - }; - name = DebugPresubmission; - }; - 94BA9B361B1A7C5700035A23 /* CustomSwift-Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - PRODUCT_NAME = "lldb-debugserver-nonui"; - }; - name = "CustomSwift-Debug"; - }; - 94BA9B371B1A7C5700035A23 /* CustomSwift-Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - PRODUCT_NAME = "lldb-debugserver-nonui"; - }; - name = "CustomSwift-Release"; - }; - 94D72C871ADF10AA00A3F718 /* CustomSwift-Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - "ARCHS[sdk=iphoneos*]" = arm64; - "ARCHS[sdk=macosx*]" = "$(ARCHS_STANDARD_64_BIT)"; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - CODE_SIGN_IDENTITY = ""; - COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 360.99.0; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_NO_COMMON_BLOCKS = YES; - GCC_VERSION = com.apple.compilers.llvm.clang.1_0; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - LLDB_COMPRESSION_LDFLAGS = "-lcompression"; - LLDB_OS_LOG_CFLAGS = "-DLLDB_USE_OS_LOG=$(LLDB_USE_OS_LOG)"; - LLDB_USE_OS_LOG = 0; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = macosx; - STRIP_INSTALLED_PRODUCT = NO; - VERSIONING_SYSTEM = "apple-generic"; - VERSION_INFO_BUILDER = "$(USER)"; - }; - name = "CustomSwift-Debug"; - }; - 94D72C881ADF10AA00A3F718 /* CustomSwift-Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; - CLANG_CXX_LIBRARY = "libc++"; - "CODE_SIGN_ENTITLEMENTS[sdk=*]" = "source/debugserver-entitlements.plist"; - "CODE_SIGN_ENTITLEMENTS[sdk=macosx*]" = "source/debugserver-macosx-entitlements.plist"; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; - "CODE_SIGN_IDENTITY[sdk=macosx*]" = ""; - COPY_PHASE_STRIP = YES; - CURRENT_PROJECT_VERSION = 360.99.0; - FRAMEWORK_SEARCH_PATHS = $SDKROOT/System/Library/PrivateFrameworks; - "FRAMEWORK_SEARCH_PATHS[sdk=iphoneos*][arch=*]" = ( - "$(SDKROOT)/System/Library/PrivateFrameworks", - "$(SDKROOT)/Developer/Library/PrivateFrameworks", - ); - "FRAMEWORK_SEARCH_PATHS[sdk=macosx*][arch=*]" = "$(SDKROOT)/System/Library/PrivateFrameworks"; - GCC_C_LANGUAGE_STANDARD = c99; - GCC_DYNAMIC_NO_PIC = NO; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = LLDB_DEBUGSERVER_DEBUG; - GCC_VERSION = com.apple.compilers.llvm.clang.1_0; - INSTALL_PATH = /usr/bin; - LLDB_COMPRESSION_LDFLAGS = "-lcompression"; - LLDB_DEBUGSERVER = 1; - LLDB_ENERGY_CFLAGS = ""; - "LLDB_ENERGY_CFLAGS[sdk=*.internal]" = "-DLLDB_ENERGY"; - LLDB_ENERGY_LDFLAGS = "-lpmenergy -lpmsample"; - OTHER_CFLAGS = ( - "-Wparentheses", - "-DDT_VARIANT_$(DT_VARIANT)", - "$(LLDB_ENERGY_CFLAGS)", - "$(LLDB_OS_LOG_CFLAGS)", - ); - "OTHER_CFLAGS[sdk=iphoneos*][arch=*]" = ( - "-Wparentheses", - "-DWITH_LOCKDOWN", - "-DWITH_BKS", - "-DWITH_FBS", - "-DOS_OBJECT_USE_OBJC=0", - "$(LLDB_ENERGY_CFLAGS)", - "$(LLDB_OS_LOG_CFLAGS)", - "-isystem", - "$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders", - ); - "OTHER_CPLUSPLUSFLAGS[sdk=iphoneos*][arch=*]" = "$(OTHER_CFLAGS)"; - OTHER_LDFLAGS = ""; - "OTHER_LDFLAGS[sdk=iphoneos*][arch=*]" = ( - "-framework", - SpringBoardServices, - "-framework", - BackBoardServices, - "-llockdown", - "-framework", - FrontBoardServices, - "-framework", - MobileCoreServices, - "$(LLDB_ENERGY_LDFLAGS)", - "$(LLDB_COMPRESSION_LDFLAGS)", - ); - "OTHER_LDFLAGS[sdk=macosx*]" = ( - "-sectcreate", - __TEXT, - __info_plist, - "$(PROJECT_DIR)/resources/lldb-debugserver-Info.plist", - "$(LLDB_ENERGY_LDFLAGS)", - "$(LLDB_COMPRESSION_LDFLAGS)", - ); - OTHER_MIGFLAGS = "-I$(DERIVED_FILE_DIR)"; - PRODUCT_NAME = debugserver; - "PROVISIONING_PROFILE[sdk=iphoneos*]" = ""; - "PROVISIONING_PROFILE[sdk=macosx*]" = ""; - SDKROOT = macosx; - SKIP_INSTALL = YES; - USER_HEADER_SEARCH_PATHS = "./source ../../source $(DERIVED_SOURCES_DIR) ../../include"; - ZERO_LINK = NO; - }; - name = "CustomSwift-Debug"; - }; - 94D72C891ADF10B000A3F718 /* CustomSwift-Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - "ARCHS[sdk=iphoneos*]" = arm64; - "ARCHS[sdk=macosx*]" = "$(ARCHS_STANDARD_64_BIT)"; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - CURRENT_PROJECT_VERSION = 360.99.0; - DEAD_CODE_STRIPPING = YES; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_NO_COMMON_BLOCKS = YES; - GCC_VERSION = com.apple.compilers.llvm.clang.1_0; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - LLDB_COMPRESSION_LDFLAGS = "-lcompression"; - LLDB_OS_LOG_CFLAGS = "-DLLDB_USE_OS_LOG=$(LLDB_USE_OS_LOG)"; - LLDB_USE_OS_LOG = 0; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = macosx; - STRIPFLAGS = "-x"; - STRIP_STYLE = debugging; - VERSIONING_SYSTEM = "apple-generic"; - VERSION_INFO_BUILDER = "$(USER)"; - }; - name = "CustomSwift-Release"; - }; - 94D72C8A1ADF10B000A3F718 /* CustomSwift-Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - CLANG_CXX_LANGUAGE_STANDARD = "c++0x"; - CLANG_CXX_LIBRARY = "libc++"; - "CODE_SIGN_ENTITLEMENTS[sdk=*]" = "source/debugserver-entitlements.plist"; - "CODE_SIGN_ENTITLEMENTS[sdk=macosx*]" = "source/debugserver-macosx-entitlements.plist"; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; - "CODE_SIGN_IDENTITY[sdk=macosx*]" = ""; - COPY_PHASE_STRIP = YES; - CURRENT_PROJECT_VERSION = 360.99.0; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - FRAMEWORK_SEARCH_PATHS = $SDKROOT/System/Library/PrivateFrameworks; - "FRAMEWORK_SEARCH_PATHS[sdk=iphoneos*][arch=*]" = ( - "$(SDKROOT)/System/Library/PrivateFrameworks", - "$(SDKROOT)/Developer/Library/PrivateFrameworks", - ); - "FRAMEWORK_SEARCH_PATHS[sdk=macosx*][arch=*]" = "$(SDKROOT)/System/Library/PrivateFrameworks"; - GCC_C_LANGUAGE_STANDARD = c99; - GCC_PREPROCESSOR_DEFINITIONS = LLDB_DEBUGSERVER_RELEASE; - GCC_VERSION = com.apple.compilers.llvm.clang.1_0; - HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders; - INSTALL_PATH = /usr/bin; - LLDB_COMPRESSION_LDFLAGS = "-lcompression"; - LLDB_DEBUGSERVER = 1; - LLDB_ENERGY_CFLAGS = ""; - "LLDB_ENERGY_CFLAGS[sdk=*.internal]" = "-DLLDB_ENERGY"; - LLDB_ENERGY_LDFLAGS = "-lpmenergy -lpmsample"; - OTHER_CFLAGS = ( - "-Wparentheses", - "-DDT_VARIANT_$(DT_VARIANT)", - "$(LLDB_ENERGY_CFLAGS)", - "$(LLDB_OS_LOG_CFLAGS)", - ); - "OTHER_CFLAGS[sdk=iphoneos*][arch=*]" = ( - "-Wparentheses", - "-DWITH_LOCKDOWN", - "-DWITH_FBS", - "-DWITH_BKS", - "-DOS_OBJECT_USE_OBJC=0", - "$(LLDB_ENERGY_CFLAGS)", - "$(LLDB_OS_LOG_CFLAGS)", - "-isystem", - "$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders", - ); - "OTHER_CPLUSPLUSFLAGS[sdk=iphoneos*][arch=*]" = "$(OTHER_CFLAGS)"; - "OTHER_LDFLAGS[sdk=iphoneos*][arch=*]" = ( - "-framework", - SpringBoardServices, - "-framework", - BackBoardServices, - "-llockdown", - "-framework", - FrontBoardServices, - "-framework", - MobileCoreServices, - "$(LLDB_ENERGY_LDFLAGS)", - "$(LLDB_COMPRESSION_LDFLAGS)", - ); - "OTHER_LDFLAGS[sdk=macosx*]" = ( - "-sectcreate", - __TEXT, - __info_plist, - "$(PROJECT_DIR)/resources/lldb-debugserver-Info.plist", - "$(LLDB_ENERGY_LDFLAGS)", - "$(LLDB_COMPRESSION_LDFLAGS)", - ); - OTHER_MIGFLAGS = "-I$(DERIVED_FILE_DIR)"; - PRODUCT_NAME = debugserver; - "PROVISIONING_PROFILE[sdk=iphoneos*]" = ""; - "PROVISIONING_PROFILE[sdk=macosx*]" = ""; - SDKROOT = macosx; - SKIP_INSTALL = YES; - USER_HEADER_SEARCH_PATHS = "./source ../../source $(DERIVED_SOURCES_DIR) ../../include"; - ZERO_LINK = NO; - }; - name = "CustomSwift-Release"; - }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ @@ -1845,43 +1022,28 @@ isa = XCConfigurationList; buildConfigurations = ( 1DEB914F08733D8E0010E9CD /* Debug */, - 94D72C871ADF10AA00A3F718 /* CustomSwift-Debug */, - 4968B7A916657FAE00741ABB /* DebugClang */, - 940AD5251B1FE3B10051E88F /* DebugPresubmission */, 1DEB915008733D8E0010E9CD /* Release */, - 94D72C891ADF10B000A3F718 /* CustomSwift-Release */, - 262419A11198A93E00067686 /* BuildAndIntegration */, ); defaultConfigurationIsVisible = 0; - defaultConfigurationName = BuildAndIntegration; + defaultConfigurationName = Debug; }; 26CE05A4115C31ED0022F371 /* Build configuration list for PBXNativeTarget "debugserver" */ = { isa = XCConfigurationList; buildConfigurations = ( 26CE0596115C31C30022F371 /* Debug */, - 94D72C881ADF10AA00A3F718 /* CustomSwift-Debug */, - 4968B7AA16657FAE00741ABB /* DebugClang */, - 940AD5261B1FE3B10051E88F /* DebugPresubmission */, 26CE0597115C31C30022F371 /* Release */, - 94D72C8A1ADF10B000A3F718 /* CustomSwift-Release */, - 262419A21198A93E00067686 /* BuildAndIntegration */, ); defaultConfigurationIsVisible = 0; - defaultConfigurationName = BuildAndIntegration; + defaultConfigurationName = Debug; }; 456F676D1AD46CE9002850C2 /* Build configuration list for PBXNativeTarget "debugserver-mini" */ = { isa = XCConfigurationList; buildConfigurations = ( 456F676E1AD46CE9002850C2 /* Debug */, - 456F676F1AD46CE9002850C2 /* DebugClang */, - 940AD5271B1FE3B10051E88F /* DebugPresubmission */, 456F67701AD46CE9002850C2 /* Release */, - 456F67711AD46CE9002850C2 /* BuildAndIntegration */, - 94BA9B361B1A7C5700035A23 /* CustomSwift-Debug */, - 94BA9B371B1A7C5700035A23 /* CustomSwift-Release */, ); defaultConfigurationIsVisible = 0; - defaultConfigurationName = BuildAndIntegration; + defaultConfigurationName = Debug; }; /* End XCConfigurationList section */ }; diff --git a/gnu/llvm/lldb/tools/debugserver/resources/debugserver-entitlements.plist b/gnu/llvm/lldb/tools/debugserver/resources/debugserver-entitlements.plist new file mode 100644 index 00000000000..1798610305d --- /dev/null +++ b/gnu/llvm/lldb/tools/debugserver/resources/debugserver-entitlements.plist @@ -0,0 +1,30 @@ + + + + + com.apple.springboard.debugapplications + + com.apple.backboardd.launchapplications + + com.apple.backboardd.debugapplications + + com.apple.frontboard.launchapplications + + com.apple.frontboard.debugapplications + + seatbelt-profiles + + debugserver + + com.apple.private.logging.diagnostic + + com.apple.security.network.server + + com.apple.security.network.client + + com.apple.private.memorystatus + + com.apple.private.cs.debugger + + + diff --git a/gnu/llvm/lldb/tools/debugserver/resources/debugserver-macosx-entitlements.plist b/gnu/llvm/lldb/tools/debugserver/resources/debugserver-macosx-entitlements.plist new file mode 100644 index 00000000000..3d60e8bd0b9 --- /dev/null +++ b/gnu/llvm/lldb/tools/debugserver/resources/debugserver-macosx-entitlements.plist @@ -0,0 +1,8 @@ + + + + + com.apple.security.cs.debugger + + + diff --git a/gnu/llvm/lldb/tools/debugserver/resources/debugserver-macosx-private-entitlements.plist b/gnu/llvm/lldb/tools/debugserver/resources/debugserver-macosx-private-entitlements.plist new file mode 100644 index 00000000000..d09bd924bf2 --- /dev/null +++ b/gnu/llvm/lldb/tools/debugserver/resources/debugserver-macosx-private-entitlements.plist @@ -0,0 +1,10 @@ + + + + + com.apple.private.logging.diagnostic + + com.apple.private.cs.debugger + + + diff --git a/gnu/llvm/lldb/tools/debugserver/source/CMakeLists.txt b/gnu/llvm/lldb/tools/debugserver/source/CMakeLists.txt index b29b3ddc305..98c79d9f734 100644 --- a/gnu/llvm/lldb/tools/debugserver/source/CMakeLists.txt +++ b/gnu/llvm/lldb/tools/debugserver/source/CMakeLists.txt @@ -2,7 +2,6 @@ include(CheckCXXCompilerFlag) include(CheckLibraryExists) include_directories(${CMAKE_CURRENT_BINARY_DIR}/..) include_directories(${LLDB_SOURCE_DIR}/source) -include_directories(MacOSX/DarwinLog) include_directories(MacOSX) @@ -60,7 +59,10 @@ endfunction() # llvm dependencies in the current scope to the empty set. set(LLVM_COMMON_DEPENDS) -set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -stdlib=libc++ -Wl,-sectcreate,__TEXT,__info_plist,${CMAKE_CURRENT_SOURCE_DIR}/../resources/lldb-debugserver-Info.plist") +set(DEBUGSERVER_RESOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../resources") +set(DEBUGSERVER_INFO_PLIST "${DEBUGSERVER_RESOURCE_DIR}/lldb-debugserver-Info.plist") + +set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -stdlib=libc++ -Wl,-sectcreate,__TEXT,__info_plist,${DEBUGSERVER_INFO_PLIST}") check_cxx_compiler_flag("-Wno-gnu-zero-variadic-macro-arguments" CXX_SUPPORTS_NO_GNU_ZERO_VARIADIC_MACRO_ARGUMENTS) @@ -80,6 +82,30 @@ if (CXX_SUPPORTS_NO_EXTENDED_OFFSETOF) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-extended-offsetof") endif () +# When compiling for arm, build debugserver 2 way fat with an arm64 and arm64e +# slice. You can only debug arm64e processes using an arm64e debugserver. +include(CheckCSourceCompiles) +check_c_source_compiles( + " + #include + #if TARGET_CPU_ARM + #if TARGET_OS_OSX + #warning Building for macOS + #else + #error Not building for macOS + #endif + #else + #error Not building for ARM + #endif + int main() { return 0; } + " + BUILDING_FOR_ARM_OSX +) + +if (BUILDING_FOR_ARM_OSX) + set(CMAKE_OSX_ARCHITECTURES "arm64;arm64e") +endif () + check_library_exists(compression compression_encode_buffer "" HAVE_LIBCOMPRESSION) find_library(SECURITY_LIBRARY Security) @@ -99,7 +125,7 @@ set_property(GLOBAL PROPERTY LLDB_DEBUGSERVER_CODESIGN_IDENTITY ${debugserver_codesign_identity}) if(APPLE) - if(IOS) + if(APPLE_EMBEDDED) find_library(BACKBOARD_LIBRARY BackBoardServices PATHS ${CMAKE_OSX_SYSROOT}/System/Library/PrivateFrameworks) find_library(FRONTBOARD_LIBRARY FrontBoardServices @@ -109,6 +135,10 @@ if(APPLE) find_library(MOBILESERVICES_LIBRARY MobileCoreServices PATHS ${CMAKE_OSX_SYSROOT}/System/Library/PrivateFrameworks) find_library(LOCKDOWN_LIBRARY lockdown) + if (APPLE_EMBEDDED STREQUAL "watchos") + find_library(CAROUSELSERVICES_LIBRARY CarouselServices + PATHS ${CMAKE_OSX_SYSROOT}/System/Library/PrivateFrameworks) + endif() if(NOT BACKBOARD_LIBRARY) set(SKIP_TEST_DEBUGSERVER ON CACHE BOOL "" FORCE) @@ -121,14 +151,19 @@ if(HAVE_LIBCOMPRESSION) endif() if(LLDB_USE_ENTITLEMENTS) - if(IOS) - set(entitlements ${CMAKE_CURRENT_SOURCE_DIR}/debugserver-entitlements.plist) + if(APPLE_EMBEDDED) + set(entitlements ${DEBUGSERVER_RESOURCE_DIR}/debugserver-entitlements.plist) else() - # Same entitlements file as used for lldb-server - set(entitlements ${LLDB_SOURCE_DIR}/resources/debugserver-macosx-entitlements.plist) + if (LLDB_USE_PRIVATE_ENTITLEMENTS) + set(entitlements ${DEBUGSERVER_RESOURCE_DIR}/debugserver-macosx-private-entitlements.plist) + else() + set(entitlements ${DEBUGSERVER_RESOURCE_DIR}/debugserver-macosx-entitlements.plist) + endif() endif() endif() +add_definitions(-DLLDB_USE_OS_LOG) + if(${CMAKE_OSX_SYSROOT} MATCHES ".Internal.sdk$") message(STATUS "LLDB debugserver energy support is enabled") add_definitions(-DLLDB_ENERGY) @@ -200,7 +235,12 @@ set(lldbDebugserverCommonSources ${generated_mach_interfaces} ${DEBUGSERVER_VERS_GENERATED_FILE}) -add_library(lldbDebugserverCommon ${lldbDebugserverCommonSources}) +# Tell LLVM not to complain about these source files. +set(LLVM_OPTIONAL_SOURCES + ${lldbDebugserverCommonSources} + debugserver.cpp) + +add_lldb_library(lldbDebugserverCommon ${lldbDebugserverCommonSources}) set_target_properties(lldbDebugserverCommon PROPERTIES FOLDER "lldb libraries/debugserver") target_link_libraries(lldbDebugserverCommon @@ -212,8 +252,8 @@ target_link_libraries(lldbDebugserverCommon ${SPRINGBOARD_LIBRARY} ${MOBILESERVICES_LIBRARY} ${LOCKDOWN_LIBRARY} + ${CAROUSELSERVICES_LIBRARY} lldbDebugserverArchSupport - lldbDebugserverDarwin_DarwinLog ${FOUNDATION_LIBRARY} ${SECURITY_LIBRARY} ${LIBCOMPRESSION} @@ -222,7 +262,6 @@ if(HAVE_LIBCOMPRESSION) set_property(TARGET lldbDebugserverCommon APPEND PROPERTY COMPILE_DEFINITIONS HAVE_LIBCOMPRESSION) endif() -set(LLVM_OPTIONAL_SOURCES ${lldbDebugserverCommonSources}) add_lldb_tool(debugserver ADD_TO_FRAMEWORK debugserver.cpp LINK_LIBS lldbDebugserverCommon @@ -258,12 +297,17 @@ endif() set_target_properties(debugserver PROPERTIES FOLDER "lldb libraries/debugserver") -if(IOS) +if(APPLE_EMBEDDED) set_property(TARGET lldbDebugserverCommon APPEND PROPERTY COMPILE_DEFINITIONS WITH_LOCKDOWN WITH_FBS WITH_BKS ) + if(CAROUSELSERVICES_LIBRARY) + set_property(TARGET lldbDebugserverCommon APPEND PROPERTY COMPILE_DEFINITIONS + WITH_CAROUSEL + ) + endif() set_property(TARGET debugserver APPEND PROPERTY COMPILE_DEFINITIONS WITH_LOCKDOWN WITH_FBS @@ -273,13 +317,12 @@ if(IOS) -F${CMAKE_OSX_SYSROOT}/System/Library/PrivateFrameworks ) - add_library(lldbDebugserverCommon_NonUI ${lldbDebugserverCommonSources}) + add_lldb_library(lldbDebugserverCommon_NonUI ${lldbDebugserverCommonSources}) target_link_libraries(lldbDebugserverCommon_NonUI INTERFACE ${COCOA_LIBRARY} ${CORE_FOUNDATION_LIBRARY} ${FOUNDATION_LIBRARY} lldbDebugserverArchSupport - lldbDebugserverDarwin_DarwinLog ${SECURITY_LIBRARY} ${LIBCOMPRESSION}) if(HAVE_LIBCOMPRESSION) diff --git a/gnu/llvm/lldb/tools/debugserver/source/DNB.cpp b/gnu/llvm/lldb/tools/debugserver/source/DNB.cpp index af13a8f8208..59bb91b82c3 100644 --- a/gnu/llvm/lldb/tools/debugserver/source/DNB.cpp +++ b/gnu/llvm/lldb/tools/debugserver/source/DNB.cpp @@ -11,12 +11,12 @@ //===----------------------------------------------------------------------===// #include "DNB.h" -#include +#include +#include +#include +#include #include #include -#include -#include -#include #include #include #include @@ -46,7 +46,6 @@ #include "DNBLog.h" #include "DNBThreadResumeActions.h" #include "DNBTimer.h" -#include "MacOSX/DarwinLog/DarwinLogCollector.h" #include "MacOSX/Genealogy.h" #include "MacOSX/MachProcess.h" #include "MacOSX/MachTask.h" @@ -319,20 +318,21 @@ static bool spawn_waitpid_thread(pid_t pid) { } nub_process_t DNBProcessLaunch( - const char *path, char const *argv[], const char *envp[], + RNBContext *ctx, const char *path, char const *argv[], const char *envp[], const char *working_directory, // NULL => don't change, non-NULL => set // working directory for inferior to this const char *stdin_path, const char *stdout_path, const char *stderr_path, - bool no_stdio, nub_launch_flavor_t launch_flavor, int disable_aslr, - const char *event_data, char *err_str, size_t err_len) { - DNBLogThreadedIf(LOG_PROCESS, "%s ( path='%s', argv = %p, envp = %p, " - "working_dir=%s, stdin=%s, stdout=%s, " - "stderr=%s, no-stdio=%i, launch_flavor = %u, " - "disable_aslr = %d, err = %p, err_len = " - "%llu) called...", + bool no_stdio, int disable_aslr, const char *event_data, char *err_str, + size_t err_len) { + DNBLogThreadedIf(LOG_PROCESS, + "%s ( path='%s', argv = %p, envp = %p, " + "working_dir=%s, stdin=%s, stdout=%s, " + "stderr=%s, no-stdio=%i, launch_flavor = %u, " + "disable_aslr = %d, err = %p, err_len = " + "%llu) called...", __FUNCTION__, path, static_cast(argv), static_cast(envp), working_directory, stdin_path, - stdout_path, stderr_path, no_stdio, launch_flavor, + stdout_path, stderr_path, no_stdio, ctx->LaunchFlavor(), disable_aslr, static_cast(err_str), static_cast(err_len)); @@ -349,10 +349,10 @@ nub_process_t DNBProcessLaunch( MachProcessSP processSP(new MachProcess); if (processSP.get()) { DNBError launch_err; - pid_t pid = processSP->LaunchForDebug(path, argv, envp, working_directory, - stdin_path, stdout_path, stderr_path, - no_stdio, launch_flavor, disable_aslr, - event_data, launch_err); + pid_t pid = processSP->LaunchForDebug( + path, argv, envp, working_directory, stdin_path, stdout_path, + stderr_path, no_stdio, ctx->LaunchFlavor(), disable_aslr, event_data, + ctx->GetUnmaskSignals(), launch_err); if (err_str) { *err_str = '\0'; if (launch_err.Fail()) { @@ -412,7 +412,8 @@ nub_process_t DNBProcessGetPIDByName(const char *name) { } nub_process_t DNBProcessAttachByName(const char *name, struct timespec *timeout, - char *err_str, size_t err_len) { + bool unmask_signals, char *err_str, + size_t err_len) { if (err_str && err_len > 0) err_str[0] = '\0'; std::vector matching_proc_infos; @@ -433,21 +434,56 @@ nub_process_t DNBProcessAttachByName(const char *name, struct timespec *timeout, } return DNBProcessAttach(matching_proc_infos[0].kp_proc.p_pid, timeout, - err_str, err_len); + unmask_signals, err_str, err_len); } nub_process_t DNBProcessAttach(nub_process_t attach_pid, - struct timespec *timeout, char *err_str, - size_t err_len) { + struct timespec *timeout, bool unmask_signals, + char *err_str, size_t err_len) { if (err_str && err_len > 0) err_str[0] = '\0'; + if (getenv("LLDB_DEBUGSERVER_PATH") == NULL) { + int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, + static_cast(attach_pid)}; + struct kinfo_proc processInfo; + size_t bufsize = sizeof(processInfo); + if (sysctl(mib, (unsigned)(sizeof(mib) / sizeof(int)), &processInfo, + &bufsize, NULL, 0) == 0 && + bufsize > 0) { + + if ((processInfo.kp_proc.p_flag & P_TRANSLATED) == P_TRANSLATED) { + const char *translated_debugserver = + "/Library/Apple/usr/libexec/oah/debugserver"; + char fdstr[16]; + char pidstr[16]; + extern int communication_fd; + + if (communication_fd == -1) { + fprintf(stderr, "Trying to attach to a translated process with the " + "native debugserver, exiting...\n"); + exit(1); + } + + snprintf(fdstr, sizeof(fdstr), "--fd=%d", communication_fd); + snprintf(pidstr, sizeof(pidstr), "--attach=%d", attach_pid); + execl(translated_debugserver, translated_debugserver, "--native-regs", + "--setsid", fdstr, "--handoff-attach-from-native", pidstr, + (char *)0); + DNBLogThreadedIf(LOG_PROCESS, "Failed to launch debugserver for " + "translated process: ", errno, strerror(errno)); + __builtin_trap(); + } + } + } + pid_t pid = INVALID_NUB_PROCESS; MachProcessSP processSP(new MachProcess); if (processSP.get()) { DNBLogThreadedIf(LOG_PROCESS, "(DebugNub) attaching to pid %d...", attach_pid); - pid = processSP->AttachForDebug(attach_pid, err_str, err_len); + pid = + processSP->AttachForDebug(attach_pid, unmask_signals, err_str, err_len); if (pid != INVALID_NUB_PROCESS) { bool res = AddProcessToMap(pid, processSP); @@ -634,15 +670,18 @@ GetAllInfosMatchingName(const char *full_process_name, return matching_proc_infos.size(); } -nub_process_t DNBProcessAttachWait( - const char *waitfor_process_name, nub_launch_flavor_t launch_flavor, - bool ignore_existing, struct timespec *timeout_abstime, - useconds_t waitfor_interval, char *err_str, size_t err_len, - DNBShouldCancelCallback should_cancel_callback, void *callback_data) { +nub_process_t +DNBProcessAttachWait(RNBContext *ctx, const char *waitfor_process_name, + bool ignore_existing, struct timespec *timeout_abstime, + useconds_t waitfor_interval, char *err_str, size_t err_len, + DNBShouldCancelCallback should_cancel_callback, + void *callback_data) { DNBError prepare_error; std::vector exclude_proc_infos; size_t num_exclude_proc_infos; + nub_launch_flavor_t launch_flavor = ctx->LaunchFlavor(); + // If the PrepareForAttach returns a valid token, use MachProcess to check // for the process, otherwise scan the process table. @@ -738,8 +777,8 @@ nub_process_t DNBProcessAttachWait( if (waitfor_pid != INVALID_NUB_PROCESS) { DNBLogThreadedIf(LOG_PROCESS, "Attaching to %s with pid %i...\n", waitfor_process_name, waitfor_pid); - waitfor_pid = - DNBProcessAttach(waitfor_pid, timeout_abstime, err_str, err_len); + waitfor_pid = DNBProcessAttach(waitfor_pid, timeout_abstime, + ctx->GetUnmaskSignals(), err_str, err_len); } bool success = waitfor_pid != INVALID_NUB_PROCESS; @@ -1385,16 +1424,20 @@ nub_bool_t DNBProcessSharedLibrariesUpdated(nub_process_t pid) { return false; } -const char *DNBGetDeploymentInfo(nub_process_t pid, - const struct load_command& lc, +const char *DNBGetDeploymentInfo(nub_process_t pid, bool is_executable, + const struct load_command &lc, uint64_t load_command_address, - uint32_t& major_version, - uint32_t& minor_version, - uint32_t& patch_version) { + uint32_t &major_version, + uint32_t &minor_version, + uint32_t &patch_version) { MachProcessSP procSP; if (GetProcessSP(pid, procSP)) { - // FIXME: This doesn't correct for older ios simulator and macCatalyst. - auto info = procSP->GetDeploymentInfo(lc, load_command_address); + // FIXME: This doesn't return the correct result when xctest (a + // macOS binary) is loaded with the macCatalyst dyld platform + // override. The image info corrects for this, but qProcessInfo + // will return what is in the binary. + auto info = + procSP->GetDeploymentInfo(lc, load_command_address, is_executable); major_version = info.major_version; minor_version = info.minor_version; patch_version = info.patch_version; @@ -1403,7 +1446,6 @@ const char *DNBGetDeploymentInfo(nub_process_t pid, return nullptr; } - // Get the current shared library information for a process. Only return // the shared libraries that have changed since the last shared library // state changed event if only_changed is non-zero. @@ -1617,10 +1659,6 @@ nub_size_t DNBProcessGetAvailableProfileData(nub_process_t pid, char *buf, return 0; } -DarwinLogEventVector DNBProcessGetAvailableDarwinLogEvents(nub_process_t pid) { - return DarwinLogCollector::GetEventsForProcess(pid); -} - nub_size_t DNBProcessGetStopCount(nub_process_t pid) { MachProcessSP procSP; if (GetProcessSP(pid, procSP)) @@ -1720,19 +1758,60 @@ nub_bool_t DNBSetArchitecture(const char *arch) { if (arch && arch[0]) { if (strcasecmp(arch, "i386") == 0) return DNBArchProtocol::SetArchitecture(CPU_TYPE_I386); - else if ((strcasecmp(arch, "x86_64") == 0) || - (strcasecmp(arch, "x86_64h") == 0)) - return DNBArchProtocol::SetArchitecture(CPU_TYPE_X86_64); - else if (strstr(arch, "arm64_32") == arch || + else if (strcasecmp(arch, "x86_64") == 0) + return DNBArchProtocol::SetArchitecture(CPU_TYPE_X86_64, + CPU_SUBTYPE_X86_64_ALL); + else if (strcasecmp(arch, "x86_64h") == 0) + return DNBArchProtocol::SetArchitecture(CPU_TYPE_X86_64, + CPU_SUBTYPE_X86_64_H); + else if (strstr(arch, "arm64_32") == arch || strstr(arch, "aarch64_32") == arch) return DNBArchProtocol::SetArchitecture(CPU_TYPE_ARM64_32); else if (strstr(arch, "arm64e") == arch) - return DNBArchProtocol::SetArchitecture(CPU_TYPE_ARM64); - else if (strstr(arch, "arm64") == arch || strstr(arch, "armv8") == arch || - strstr(arch, "aarch64") == arch) - return DNBArchProtocol::SetArchitecture(CPU_TYPE_ARM64); + return DNBArchProtocol::SetArchitecture(CPU_TYPE_ARM64, + CPU_SUBTYPE_ARM64E); + else if (strstr(arch, "arm64") == arch || strstr(arch, "aarch64") == arch) + return DNBArchProtocol::SetArchitecture(CPU_TYPE_ARM64, + CPU_SUBTYPE_ARM64_ALL); + else if (strstr(arch, "armv8") == arch) + return DNBArchProtocol::SetArchitecture(CPU_TYPE_ARM64, + CPU_SUBTYPE_ARM64_V8); + else if (strstr(arch, "armv7em") == arch) + return DNBArchProtocol::SetArchitecture(CPU_TYPE_ARM, + CPU_SUBTYPE_ARM_V7EM); + else if (strstr(arch, "armv7m") == arch) + return DNBArchProtocol::SetArchitecture(CPU_TYPE_ARM, + CPU_SUBTYPE_ARM_V7M); + else if (strstr(arch, "armv7k") == arch) + return DNBArchProtocol::SetArchitecture(CPU_TYPE_ARM, + CPU_SUBTYPE_ARM_V7K); + else if (strstr(arch, "armv7s") == arch) + return DNBArchProtocol::SetArchitecture(CPU_TYPE_ARM, + CPU_SUBTYPE_ARM_V7S); + else if (strstr(arch, "armv7") == arch) + return DNBArchProtocol::SetArchitecture(CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V7); + else if (strstr(arch, "armv6m") == arch) + return DNBArchProtocol::SetArchitecture(CPU_TYPE_ARM, + CPU_SUBTYPE_ARM_V6M); + else if (strstr(arch, "armv6") == arch) + return DNBArchProtocol::SetArchitecture(CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V6); + else if (strstr(arch, "armv5") == arch) + return DNBArchProtocol::SetArchitecture(CPU_TYPE_ARM, + CPU_SUBTYPE_ARM_V5TEJ); + else if (strstr(arch, "armv4t") == arch) + return DNBArchProtocol::SetArchitecture(CPU_TYPE_ARM, + CPU_SUBTYPE_ARM_V4T); else if (strstr(arch, "arm") == arch) - return DNBArchProtocol::SetArchitecture(CPU_TYPE_ARM); + return DNBArchProtocol::SetArchitecture(CPU_TYPE_ARM, + CPU_SUBTYPE_ARM_ALL); } return false; } + +bool DNBDebugserverIsTranslated() { + int ret = 0; + size_t size = sizeof(ret); + if (sysctlbyname("sysctl.proc_translated", &ret, &size, NULL, 0) == -1) + return false; + return ret == 1; +} diff --git a/gnu/llvm/lldb/tools/debugserver/source/DNB.h b/gnu/llvm/lldb/tools/debugserver/source/DNB.h index e0e1cdd6d8b..c04249d6726 100644 --- a/gnu/llvm/lldb/tools/debugserver/source/DNB.h +++ b/gnu/llvm/lldb/tools/debugserver/source/DNB.h @@ -15,13 +15,13 @@ #include "DNBDefs.h" #include "JSONGenerator.h" -#include "MacOSX/DarwinLog/DarwinLogEvent.h" #include "MacOSX/Genealogy.h" #include "MacOSX/ThreadInfo.h" -#include -#include +#include "RNBContext.h" #include #include +#include +#include #define DNB_EXPORT __attribute__((visibility("default"))) @@ -42,24 +42,27 @@ nub_bool_t DNBSetArchitecture(const char *arch); // Process control nub_process_t DNBProcessLaunch( - const char *path, char const *argv[], const char *envp[], + RNBContext *ctx, const char *path, char const *argv[], const char *envp[], const char *working_directory, // NULL => don't change, non-NULL => set // working directory for inferior to this const char *stdin_path, const char *stdout_path, const char *stderr_path, - bool no_stdio, nub_launch_flavor_t launch_flavor, int disable_aslr, - const char *event_data, char *err_str, size_t err_len); + bool no_stdio, int disable_aslr, const char *event_data, char *err_str, + size_t err_len); nub_process_t DNBProcessGetPIDByName(const char *name); nub_process_t DNBProcessAttach(nub_process_t pid, struct timespec *timeout, - char *err_str, size_t err_len); + bool unmask_signals, char *err_str, + size_t err_len); nub_process_t DNBProcessAttachByName(const char *name, struct timespec *timeout, - char *err_str, size_t err_len); -nub_process_t -DNBProcessAttachWait(const char *wait_name, nub_launch_flavor_t launch_flavor, - bool ignore_existing, struct timespec *timeout, - useconds_t interval, char *err_str, size_t err_len, - DNBShouldCancelCallback should_cancel = NULL, - void *callback_data = NULL); + bool unmask_signals, char *err_str, + size_t err_len); +nub_process_t DNBProcessAttachWait(RNBContext *ctx, const char *wait_name, + bool ignore_existing, + struct timespec *timeout, + useconds_t interval, char *err_str, + size_t err_len, + DNBShouldCancelCallback should_cancel = NULL, + void *callback_data = NULL); // Resume a process with exact instructions on what to do with each thread: // - If no thread actions are supplied (actions is NULL or num_actions is zero), // then all threads are continued. @@ -104,7 +107,6 @@ nub_bool_t DNBProcessSetEnableAsyncProfiling(nub_process_t pid, nub_bool_t enable, uint64_t interval_usec, DNBProfileDataScanType scan_type) DNB_EXPORT; -DarwinLogEventVector DNBProcessGetAvailableDarwinLogEvents(nub_process_t pid); // Process status nub_bool_t DNBProcessIsAlive(nub_process_t pid) DNB_EXPORT; @@ -128,12 +130,12 @@ nub_bool_t DNBProcessSharedLibrariesUpdated(nub_process_t pid) DNB_EXPORT; nub_size_t DNBProcessGetSharedLibraryInfo(nub_process_t pid, nub_bool_t only_changed, DNBExecutableImageInfo **image_infos) DNB_EXPORT; -const char *DNBGetDeploymentInfo(nub_process_t pid, - const struct load_command& lc, +const char *DNBGetDeploymentInfo(nub_process_t pid, bool is_executable, + const struct load_command &lc, uint64_t load_command_address, - uint32_t& major_version, - uint32_t& minor_version, - uint32_t& patch_version); + uint32_t &major_version, + uint32_t &minor_version, + uint32_t &patch_version); nub_bool_t DNBProcessSetNameToAddressCallback(nub_process_t pid, DNBCallbackNameToAddress callback, void *baton) DNB_EXPORT; @@ -235,4 +237,8 @@ nub_bool_t DNBResolveExecutablePath(const char *path, char *resolved_path, bool DNBGetOSVersionNumbers(uint64_t *major, uint64_t *minor, uint64_t *patch); /// \return the iOSSupportVersion of the host OS. std::string DNBGetMacCatalystVersionString(); + +/// \return true if debugserver is running in translation +/// (is an x86_64 process on arm64) +bool DNBDebugserverIsTranslated(); #endif diff --git a/gnu/llvm/lldb/tools/debugserver/source/DNBArch.cpp b/gnu/llvm/lldb/tools/debugserver/source/DNBArch.cpp index 931d623647f..54a055def9b 100644 --- a/gnu/llvm/lldb/tools/debugserver/source/DNBArch.cpp +++ b/gnu/llvm/lldb/tools/debugserver/source/DNBArch.cpp @@ -11,7 +11,7 @@ //===----------------------------------------------------------------------===// #include "DNBArch.h" -#include +#include #include #include @@ -21,6 +21,7 @@ typedef std::map CPUPluginInfoMap; static uint32_t g_current_cpu_type = 0; +static uint32_t g_current_cpu_subtype = 0; CPUPluginInfoMap g_arch_plugins; static const DNBArchPluginInfo *GetArchInfo() { @@ -31,15 +32,17 @@ static const DNBArchPluginInfo *GetArchInfo() { return NULL; } -uint32_t DNBArchProtocol::GetArchitecture() { return g_current_cpu_type; } +uint32_t DNBArchProtocol::GetCPUType() { return g_current_cpu_type; } +uint32_t DNBArchProtocol::GetCPUSubType() { return g_current_cpu_subtype; } -bool DNBArchProtocol::SetArchitecture(uint32_t cpu_type) { +bool DNBArchProtocol::SetArchitecture(uint32_t cpu_type, uint32_t cpu_subtype) { g_current_cpu_type = cpu_type; + g_current_cpu_subtype = cpu_subtype; bool result = g_arch_plugins.find(g_current_cpu_type) != g_arch_plugins.end(); - DNBLogThreadedIf( - LOG_PROCESS, - "DNBArchProtocol::SetDefaultArchitecture (cpu_type=0x%8.8x) => %i", - cpu_type, result); + DNBLogThreadedIf(LOG_PROCESS, + "DNBArchProtocol::SetDefaultArchitecture (cpu_type=0x%8.8x, " + "cpu_subtype=0x%8.8x) => %i", + cpu_type, cpu_subtype, result); return result; } diff --git a/gnu/llvm/lldb/tools/debugserver/source/DNBArch.h b/gnu/llvm/lldb/tools/debugserver/source/DNBArch.h index 0f65df75a38..b673e403feb 100644 --- a/gnu/llvm/lldb/tools/debugserver/source/DNBArch.h +++ b/gnu/llvm/lldb/tools/debugserver/source/DNBArch.h @@ -16,8 +16,8 @@ #include "DNBDefs.h" #include "MacOSX/MachException.h" +#include #include -#include struct DNBRegisterValue; struct DNBRegisterSetInfo; @@ -49,9 +49,10 @@ public: static void RegisterArchPlugin(const DNBArchPluginInfo &arch_info); - static uint32_t GetArchitecture(); + static uint32_t GetCPUType(); + static uint32_t GetCPUSubType(); - static bool SetArchitecture(uint32_t cpu_type); + static bool SetArchitecture(uint32_t cpu_type, uint32_t cpu_subtype = 0); DNBArchProtocol() : m_save_id(0) {} diff --git a/gnu/llvm/lldb/tools/debugserver/source/DNBBreakpoint.cpp b/gnu/llvm/lldb/tools/debugserver/source/DNBBreakpoint.cpp index 890bde024bf..9f402b4f0b1 100644 --- a/gnu/llvm/lldb/tools/debugserver/source/DNBBreakpoint.cpp +++ b/gnu/llvm/lldb/tools/debugserver/source/DNBBreakpoint.cpp @@ -14,8 +14,8 @@ #include "DNBLog.h" #include "MachProcess.h" #include -#include -#include +#include +#include #pragma mark-- DNBBreakpoint DNBBreakpoint::DNBBreakpoint(nub_addr_t addr, nub_size_t byte_size, diff --git a/gnu/llvm/lldb/tools/debugserver/source/DNBDataRef.cpp b/gnu/llvm/lldb/tools/debugserver/source/DNBDataRef.cpp index f19c913f65d..c6355f167dc 100644 --- a/gnu/llvm/lldb/tools/debugserver/source/DNBDataRef.cpp +++ b/gnu/llvm/lldb/tools/debugserver/source/DNBDataRef.cpp @@ -12,8 +12,8 @@ #include "DNBDataRef.h" #include "DNBLog.h" -#include -#include +#include +#include #include // Constructor diff --git a/gnu/llvm/lldb/tools/debugserver/source/DNBDataRef.h b/gnu/llvm/lldb/tools/debugserver/source/DNBDataRef.h index 4a79dc442be..c8688eb6a1d 100644 --- a/gnu/llvm/lldb/tools/debugserver/source/DNBDataRef.h +++ b/gnu/llvm/lldb/tools/debugserver/source/DNBDataRef.h @@ -23,10 +23,10 @@ #define LLDB_TOOLS_DEBUGSERVER_SOURCE_DNBDATAREF_H #include "DNBDefs.h" -#include -#include -#include -#include +#include +#include +#include +#include class DNBDataRef { public: diff --git a/gnu/llvm/lldb/tools/debugserver/source/DNBDefs.h b/gnu/llvm/lldb/tools/debugserver/source/DNBDefs.h index 49f8d6decb3..739d453c10d 100644 --- a/gnu/llvm/lldb/tools/debugserver/source/DNBDefs.h +++ b/gnu/llvm/lldb/tools/debugserver/source/DNBDefs.h @@ -13,11 +13,12 @@ #ifndef LLDB_TOOLS_DEBUGSERVER_SOURCE_DNBDEFS_H #define LLDB_TOOLS_DEBUGSERVER_SOURCE_DNBDEFS_H -#include -#include -#include +#include +#include +#include #include #include +#include // Define nub_addr_t and the invalid address value from the architecture #if defined(__x86_64__) || defined(__arm64__) || defined(__aarch64__) @@ -316,9 +317,12 @@ struct DNBExecutableImageInfo { }; struct DNBRegionInfo { +public: + DNBRegionInfo() : addr(0), size(0), permissions(0), dirty_pages() {} nub_addr_t addr; nub_addr_t size; uint32_t permissions; + std::vector dirty_pages; }; enum DNBProfileDataScanType { diff --git a/gnu/llvm/lldb/tools/debugserver/source/DNBError.h b/gnu/llvm/lldb/tools/debugserver/source/DNBError.h index 8da3f6c1e3a..9b6b0c7bcaf 100644 --- a/gnu/llvm/lldb/tools/debugserver/source/DNBError.h +++ b/gnu/llvm/lldb/tools/debugserver/source/DNBError.h @@ -13,9 +13,9 @@ #ifndef LLDB_TOOLS_DEBUGSERVER_SOURCE_DNBERROR_H #define LLDB_TOOLS_DEBUGSERVER_SOURCE_DNBERROR_H -#include +#include +#include #include -#include #include class DNBError { diff --git a/gnu/llvm/lldb/tools/debugserver/source/DNBLog.cpp b/gnu/llvm/lldb/tools/debugserver/source/DNBLog.cpp index 11b2d0a04b7..d3045ace16f 100644 --- a/gnu/llvm/lldb/tools/debugserver/source/DNBLog.cpp +++ b/gnu/llvm/lldb/tools/debugserver/source/DNBLog.cpp @@ -18,11 +18,11 @@ static int g_verbose = 0; #if defined(DNBLOG_ENABLED) #include "PThreadMutex.h" +#include +#include +#include #include #include -#include -#include -#include #include #include diff --git a/gnu/llvm/lldb/tools/debugserver/source/DNBLog.h b/gnu/llvm/lldb/tools/debugserver/source/DNBLog.h index 6a3e34c1383..3b17b46eebf 100644 --- a/gnu/llvm/lldb/tools/debugserver/source/DNBLog.h +++ b/gnu/llvm/lldb/tools/debugserver/source/DNBLog.h @@ -14,8 +14,8 @@ #define LLDB_TOOLS_DEBUGSERVER_SOURCE_DNBLOG_H #include "DNBDefs.h" -#include -#include +#include +#include #ifdef __cplusplus extern "C" { diff --git a/gnu/llvm/lldb/tools/debugserver/source/DNBRegisterInfo.cpp b/gnu/llvm/lldb/tools/debugserver/source/DNBRegisterInfo.cpp index c224fc7056d..e6b8e1b6426 100644 --- a/gnu/llvm/lldb/tools/debugserver/source/DNBRegisterInfo.cpp +++ b/gnu/llvm/lldb/tools/debugserver/source/DNBRegisterInfo.cpp @@ -12,7 +12,7 @@ #include "DNBRegisterInfo.h" #include "DNBLog.h" -#include +#include DNBRegisterValueClass::DNBRegisterValueClass(const DNBRegisterInfo *regInfo) { Clear(); diff --git a/gnu/llvm/lldb/tools/debugserver/source/DNBRegisterInfo.h b/gnu/llvm/lldb/tools/debugserver/source/DNBRegisterInfo.h index c17ce3a7e18..05992b9f15d 100644 --- a/gnu/llvm/lldb/tools/debugserver/source/DNBRegisterInfo.h +++ b/gnu/llvm/lldb/tools/debugserver/source/DNBRegisterInfo.h @@ -14,8 +14,8 @@ #define LLDB_TOOLS_DEBUGSERVER_SOURCE_DNBREGISTERINFO_H #include "DNBDefs.h" -#include -#include +#include +#include struct DNBRegisterValueClass : public DNBRegisterValue { #ifdef __cplusplus diff --git a/gnu/llvm/lldb/tools/debugserver/source/DNBTimer.h b/gnu/llvm/lldb/tools/debugserver/source/DNBTimer.h index 80232494b5f..a6570b2e8ea 100644 --- a/gnu/llvm/lldb/tools/debugserver/source/DNBTimer.h +++ b/gnu/llvm/lldb/tools/debugserver/source/DNBTimer.h @@ -15,8 +15,8 @@ #include "DNBDefs.h" #include "PThreadMutex.h" +#include #include -#include #include class DNBTimer { diff --git a/gnu/llvm/lldb/tools/debugserver/source/JSON.cpp b/gnu/llvm/lldb/tools/debugserver/source/JSON.cpp index 12d96d4ed4d..5eff683a080 100644 --- a/gnu/llvm/lldb/tools/debugserver/source/JSON.cpp +++ b/gnu/llvm/lldb/tools/debugserver/source/JSON.cpp @@ -9,8 +9,8 @@ #include "JSON.h" // C includes -#include -#include +#include +#include // C++ includes #include "lldb/Host/StringConvert.h" diff --git a/gnu/llvm/lldb/tools/debugserver/source/JSON.h b/gnu/llvm/lldb/tools/debugserver/source/JSON.h index 5bcc67c18b9..b2214d43e42 100644 --- a/gnu/llvm/lldb/tools/debugserver/source/JSON.h +++ b/gnu/llvm/lldb/tools/debugserver/source/JSON.h @@ -12,8 +12,8 @@ #include "StdStringExtractor.h" // C includes -#include -#include +#include +#include // C++ includes #include diff --git a/gnu/llvm/lldb/tools/debugserver/source/MacOSX/CMakeLists.txt b/gnu/llvm/lldb/tools/debugserver/source/MacOSX/CMakeLists.txt index 001f861d271..ea4593fcf45 100644 --- a/gnu/llvm/lldb/tools/debugserver/source/MacOSX/CMakeLists.txt +++ b/gnu/llvm/lldb/tools/debugserver/source/MacOSX/CMakeLists.txt @@ -26,8 +26,6 @@ if(NOT LLDB_DEBUGSERVER_ARCH OR "${LLDB_DEBUGSERVER_ARCH}" MATCHES ".*86.*") include_directories(${CURRENT_SOURCE_DIR}/i386 ${CURRENT_SOURCE_DIR}/x86_64) endif() -add_subdirectory(DarwinLog) - include_directories(..) include_directories(${LLDB_SOURCE_DIR}/tools/debugserver/source) diff --git a/gnu/llvm/lldb/tools/debugserver/source/MacOSX/MachException.cpp b/gnu/llvm/lldb/tools/debugserver/source/MacOSX/MachException.cpp index 8690960e4cd..db154d160b4 100644 --- a/gnu/llvm/lldb/tools/debugserver/source/MacOSX/MachException.cpp +++ b/gnu/llvm/lldb/tools/debugserver/source/MacOSX/MachException.cpp @@ -17,7 +17,7 @@ #include "MachProcess.h" #include "PThreadMutex.h" #include "SysSignal.h" -#include +#include #include #include diff --git a/gnu/llvm/lldb/tools/debugserver/source/MacOSX/MachProcess.h b/gnu/llvm/lldb/tools/debugserver/source/MacOSX/MachProcess.h index c749dd8426c..33c3d628a7a 100644 --- a/gnu/llvm/lldb/tools/debugserver/source/MacOSX/MachProcess.h +++ b/gnu/llvm/lldb/tools/debugserver/source/MacOSX/MachProcess.h @@ -78,22 +78,24 @@ public: }; // Child process control - pid_t AttachForDebug(pid_t pid, char *err_str, size_t err_len); + pid_t AttachForDebug(pid_t pid, bool unmask_signals, char *err_str, + size_t err_len); pid_t LaunchForDebug(const char *path, char const *argv[], char const *envp[], const char *working_directory, const char *stdin_path, const char *stdout_path, const char *stderr_path, bool no_stdio, nub_launch_flavor_t launch_flavor, - int disable_aslr, const char *event_data, DNBError &err); + int disable_aslr, const char *event_data, + bool unmask_signals, DNBError &err); static uint32_t GetCPUTypeForLocalProcess(pid_t pid); static pid_t ForkChildForPTraceDebugging(const char *path, char const *argv[], char const *envp[], MachProcess *process, DNBError &err); static pid_t PosixSpawnChildForPTraceDebugging( - const char *path, cpu_type_t cpu_type, char const *argv[], - char const *envp[], const char *working_directory, const char *stdin_path, - const char *stdout_path, const char *stderr_path, bool no_stdio, - MachProcess *process, int disable_aslr, DNBError &err); + const char *path, cpu_type_t cpu_type, cpu_subtype_t cpu_subtype, + char const *argv[], char const *envp[], const char *working_directory, + const char *stdin_path, const char *stdout_path, const char *stderr_path, + bool no_stdio, MachProcess *process, int disable_aslr, DNBError &err); nub_addr_t GetDYLDAllImageInfosAddress(); static const void *PrepareForAttach(const char *path, nub_launch_flavor_t launch_flavor, @@ -107,7 +109,7 @@ public: pid_t BoardServiceLaunchForDebug(const char *app_bundle_path, char const *argv[], char const *envp[], bool no_stdio, bool disable_aslr, - const char *event_data, + const char *event_data, bool unmask_signals, DNBError &launch_err); pid_t BoardServiceForkChildForPTraceDebugging( const char *path, char const *argv[], char const *envp[], bool no_stdio, @@ -128,7 +130,7 @@ public: #ifdef WITH_SPRINGBOARD pid_t SBLaunchForDebug(const char *app_bundle_path, char const *argv[], char const *envp[], bool no_stdio, bool disable_aslr, - DNBError &launch_err); + bool unmask_signals, DNBError &launch_err); static pid_t SBForkChildForPTraceDebugging(const char *path, char const *argv[], char const *envp[], bool no_stdio, @@ -236,15 +238,13 @@ public: operator bool() { return platform > 0; } /// The Mach-O platform type; unsigned char platform = 0; - /// Pre-LC_BUILD_VERSION files don't disambiguate between ios and ios - /// simulator. - bool maybe_simulator = false; uint32_t major_version = 0; uint32_t minor_version = 0; uint32_t patch_version = 0; }; DeploymentInfo GetDeploymentInfo(const struct load_command &, - uint64_t load_command_address); + uint64_t load_command_address, + bool is_executable); static const char *GetPlatformString(unsigned char platform); bool GetMachOInformationFromMemory(uint32_t platform, nub_addr_t mach_o_header_addr, @@ -252,7 +252,16 @@ public: struct mach_o_information &inf); JSONGenerator::ObjectSP FormatDynamicLibrariesIntoJSON( const std::vector &image_infos); - uint32_t GetAllLoadedBinariesViaDYLDSPI( + uint32_t GetPlatform(); + /// Get the runtime platform from DYLD via SPI. + uint32_t GetProcessPlatformViaDYLDSPI(); + /// Use the dyld SPI present in macOS 10.12, iOS 10, tvOS 10, + /// watchOS 3 and newer to get the load address, uuid, and filenames + /// of all the libraries. This only fills in those three fields in + /// the 'struct binary_image_information' - call + /// GetMachOInformationFromMemory to fill in the mach-o header/load + /// command details. + void GetAllLoadedBinariesViaDYLDSPI( std::vector &image_infos); JSONGenerator::ObjectSP GetLoadedDynamicLibrariesInfos( nub_process_t pid, nub_addr_t image_list_address, nub_addr_t image_count); @@ -335,6 +344,9 @@ public: bool ProcessUsingFrontBoard(); + // Size of addresses in the inferior process (4 or 8). + int GetInferiorAddrSize(pid_t pid); + Genealogy::ThreadActivitySP GetGenealogyInfoForThread(nub_thread_t tid, bool &timed_out); @@ -367,6 +379,7 @@ private: pid_t m_pid; // Process ID of child process cpu_type_t m_cpu_type; // The CPU type of this process + uint32_t m_platform; // The platform of this process int m_child_stdin; int m_child_stdout; int m_child_stderr; diff --git a/gnu/llvm/lldb/tools/debugserver/source/MacOSX/MachProcess.mm b/gnu/llvm/lldb/tools/debugserver/source/MacOSX/MachProcess.mm index 8a35f605daa..9ab33cc4b3a 100644 --- a/gnu/llvm/lldb/tools/debugserver/source/MacOSX/MachProcess.mm +++ b/gnu/llvm/lldb/tools/debugserver/source/MacOSX/MachProcess.mm @@ -79,6 +79,11 @@ #endif // WITH_SPRINGBOARD +#if WITH_CAROUSEL +// For definition of CSLSOpenApplicationOptionForClockKit. +#include +#endif // WITH_CAROUSEL + #if defined(WITH_SPRINGBOARD) || defined(WITH_BKS) || defined(WITH_FBS) // This returns a CFRetained pointer to the Bundle ID for app_bundle_path, // or NULL if there was some problem getting the bundle id. @@ -93,6 +98,7 @@ typedef void (*SetErrorFunction)(NSInteger, std::string, DNBError &); typedef bool (*CallOpenApplicationFunction)(NSString *bundleIDNSStr, NSDictionary *options, DNBError &error, pid_t *return_pid); + // This function runs the BKSSystemService (or FBSSystemService) method // openApplication:options:clientPort:withResult, // messaging the app passed in bundleIDNSStr. @@ -134,8 +140,10 @@ static bool CallBoardSystemServiceOpenApplication(NSString *bundleIDNSStr, cstr = ""; NSString *description = [options description]; - DNBLog("About to launch process for bundle ID: %s - options:\n%s", cstr, - [description UTF8String]); + DNBLog("[LaunchAttach] START (%d) templated *Board launcher: app lunch " + "request for " + "'%s' - options:\n%s", + getpid(), cstr, [description UTF8String]); [system_service openApplication:bundleIDNSStr options:options @@ -150,33 +158,36 @@ static bool CallBoardSystemServiceOpenApplication(NSString *bundleIDNSStr, if (wants_pid) { pid_in_block = [system_service pidForApplication:bundleIDNSStr]; - DNBLog( - "In completion handler, got pid for bundle id, pid: %d.", - pid_in_block); - DNBLogThreadedIf( - LOG_PROCESS, - "In completion handler, got pid for bundle id, pid: %d.", - pid_in_block); - } else - DNBLogThreadedIf(LOG_PROCESS, - "In completion handler: success."); + DNBLog("[LaunchAttach] In completion handler, got pid for " + "bundle id " + "'%s', pid: %d.", + cstr, pid_in_block); + } else { + DNBLog("[LaunchAttach] In completion handler, launch was " + "successful, " + "debugserver did not ask for the pid"); + } } else { const char *error_str = [(NSString *)[bks_error localizedDescription] UTF8String]; if (error_str) { open_app_error_string = error_str; - DNBLogError("In app launch attempt, got error " - "localizedDescription '%s'.", error_str); + DNBLogError( + "[LaunchAttach] END (%d) In app launch attempt, got error " + "localizedDescription '%s'.", + getpid(), error_str); const char *obj_desc = [NSString stringWithFormat:@"%@", bks_error].UTF8String; - DNBLogError("In app launch attempt, got error " - "NSError object description: '%s'.", - obj_desc); + DNBLogError( + "[LaunchAttach] END (%d) In app launch attempt, got error " + "NSError object description: '%s'.", + getpid(), obj_desc); } - DNBLogThreadedIf(LOG_PROCESS, "In completion handler for send " - "event, got error \"%s\"(%ld).", + DNBLogThreadedIf(LOG_PROCESS, + "In completion handler for send " + "event, got error \"%s\"(%ld).", error_str ? error_str : "", - open_app_error); + (long)open_app_error); } [system_service release]; @@ -194,15 +205,23 @@ static bool CallBoardSystemServiceOpenApplication(NSString *bundleIDNSStr, dispatch_release(semaphore); + DNBLog("[LaunchAttach] END (%d) templated *Board launcher finished app lunch " + "request for " + "'%s'", + getpid(), cstr); + if (!success) { - DNBLogError("timed out trying to send openApplication to %s.", cstr); + DNBLogError("[LaunchAttach] END (%d) timed out trying to send " + "openApplication to %s.", + getpid(), cstr); error.SetError(OPEN_APPLICATION_TIMEOUT_ERROR, DNBError::Generic); error.SetErrorString("timed out trying to launch app"); } else if (open_app_error != no_error_enum_value) { error_function(open_app_error, open_app_error_string, error); - DNBLogError("unable to launch the application with CFBundleIdentifier '%s' " - "bks_error = %u", - cstr, open_app_error); + DNBLogError("[LaunchAttach] END (%d) unable to launch the application with " + "CFBundleIdentifier '%s' " + "bks_error = %ld", + getpid(), cstr, (long)open_app_error); success = false; } else if (wants_pid) { *return_pid = pid_in_block; @@ -401,6 +420,12 @@ static bool FBSAddEventDataToOptions(NSMutableDictionary *options, DNBLog("Setting ActivateSuspended key in options dictionary."); [options setObject:@YES forKey: FBSOpenApplicationOptionKeyActivateSuspended]; found_one = true; +#if WITH_CAROUSEL + } else if (value.compare("WatchComplicationLaunch") == 0) { + DNBLog("Setting FBSOpenApplicationOptionKeyActivateSuspended key in options dictionary."); + [options setObject:@YES forKey: CSLSOpenApplicationOptionForClockKit]; + found_one = true; +#endif // WITH_CAROUSEL } else { DNBLogError("Unrecognized event type: %s. Ignoring.", value.c_str()); option_error.SetErrorString("Unrecognized event data."); @@ -483,6 +508,7 @@ static CallOpenApplicationFunction FBSCallOpenApplicationFunction = #define _POSIX_SPAWN_DISABLE_ASLR 0x0100 #endif + MachProcess::MachProcess() : m_pid(0), m_cpu_type(0), m_child_stdin(-1), m_child_stdout(-1), m_child_stderr(-1), m_path(), m_args(), m_task(this), @@ -603,9 +629,11 @@ nub_addr_t MachProcess::GetTSDAddressForThread( MachProcess::DeploymentInfo MachProcess::GetDeploymentInfo(const struct load_command &lc, - uint64_t load_command_address) { + uint64_t load_command_address, + bool is_executable) { DeploymentInfo info; uint32_t cmd = lc.cmd & ~LC_REQ_DYLD; + // Handle the older LC_VERSION load commands, which don't // distinguish between simulator and real hardware. auto handle_version_min = [&](char platform) { @@ -617,8 +645,30 @@ MachProcess::GetDeploymentInfo(const struct load_command &lc, info.major_version = vers_cmd.version >> 16; info.minor_version = (vers_cmd.version >> 8) & 0xffu; info.patch_version = vers_cmd.version & 0xffu; - info.maybe_simulator = true; + + // Disambiguate legacy simulator platforms. +#if (defined(__x86_64__) || defined(__i386__)) + // If we are running on Intel macOS, it is safe to assume this is + // really a back-deploying simulator binary. + switch (info.platform) { + case PLATFORM_IOS: + info.platform = PLATFORM_IOSSIMULATOR; + break; + case PLATFORM_TVOS: + info.platform = PLATFORM_TVOSSIMULATOR; + break; + case PLATFORM_WATCHOS: + info.platform = PLATFORM_WATCHOSSIMULATOR; + break; + } +#else + // On an Apple Silicon macOS host, there is no ambiguity. The only + // binaries that use legacy load commands are back-deploying + // native iOS binaries. All simulator binaries use the newer, + // unambiguous LC_BUILD_VERSION load commands. +#endif }; + switch (cmd) { case LC_VERSION_MIN_IPHONEOS: handle_version_min(PLATFORM_IOS); @@ -646,6 +696,27 @@ MachProcess::GetDeploymentInfo(const struct load_command &lc, } #endif } + + // The xctest binary is a pure macOS binary but is launched with + // DYLD_FORCE_PLATFORM=6. In that case, force the platform to + // macCatalyst and use the macCatalyst version of the host OS + // instead of the macOS deployment target. + if (is_executable && GetPlatform() == PLATFORM_MACCATALYST) { + info.platform = PLATFORM_MACCATALYST; + std::string catalyst_version = GetMacCatalystVersionString(); + const char *major = catalyst_version.c_str(); + char *minor = nullptr; + char *patch = nullptr; + info.major_version = std::strtoul(major, &minor, 10); + info.minor_version = 0; + info.patch_version = 0; + if (minor && *minor == '.') { + info.minor_version = std::strtoul(++minor, &patch, 10); + if (patch && *patch == '.') + info.patch_version = std::strtoul(++patch, nullptr, 10); + } + } + return info; } @@ -777,65 +848,21 @@ bool MachProcess::GetMachOInformationFromMemory( sizeof(struct uuid_command)) uuid_copy(inf.uuid, uuidcmd.uuid); } - if (DeploymentInfo deployment_info = GetDeploymentInfo(lc, load_cmds_p)) { - // Simulator support. If the platform is ambiguous, use the dyld info. - if (deployment_info.maybe_simulator) { - if (deployment_info.maybe_simulator) { -#if (defined(__x86_64__) || defined(__i386__)) - // If dyld doesn't return a platform, use a heuristic. - // If we are running on Intel macOS, it is safe to assume - // this is really a back-deploying simulator binary. - switch (deployment_info.platform) { - case PLATFORM_IOS: - deployment_info.platform = PLATFORM_IOSSIMULATOR; - break; - case PLATFORM_TVOS: - deployment_info.platform = PLATFORM_TVOSSIMULATOR; - break; - case PLATFORM_WATCHOS: - deployment_info.platform = PLATFORM_WATCHOSSIMULATOR; - break; - } -#else - // On an Apple Silicon macOS host, there is no - // ambiguity. The only binaries that use legacy load - // commands are back-deploying native iOS binaries. All - // simulator binaries use the newer, unambiguous - // LC_BUILD_VERSION load commands. - deployment_info.maybe_simulator = false; -#endif - } - } + if (DeploymentInfo deployment_info = GetDeploymentInfo( + lc, load_cmds_p, inf.mach_header.filetype == MH_EXECUTE)) { const char *lc_platform = GetPlatformString(deployment_info.platform); - // macCatalyst support. - // - // This handles two special cases: - // - // 1. Frameworks that have both a PLATFORM_MACOS and a - // PLATFORM_MACCATALYST load command. Make sure to select - // the requested one. - // - // 2. The xctest binary is a pure macOS binary but is launched - // with DYLD_FORCE_PLATFORM=6. - if (dyld_platform == PLATFORM_MACCATALYST && - inf.mach_header.filetype == MH_EXECUTE && - inf.min_version_os_name.empty() && - (strcmp("macosx", lc_platform) == 0)) { - // DYLD says this *is* a macCatalyst process. If we haven't - // parsed any load commands, transform a macOS load command - // into a generic macCatalyst load command. It will be - // overwritten by a more specific one if there is one. This - // is only done for the main executable. It is perfectly fine - // for a macCatalyst binary to link against a macOS-only framework. - inf.min_version_os_name = "maccatalyst"; - inf.min_version_os_version = GetMacCatalystVersionString(); - } else if (dyld_platform != PLATFORM_MACCATALYST && - inf.min_version_os_name == "macosx") { - // This is a binary with both PLATFORM_MACOS and - // PLATFORM_MACCATALYST load commands and the process is not - // running as PLATFORM_MACCATALYST. Stick with the - // "macosx" load command that we've already processed, - // ignore this one, which is presumed to be a + if (dyld_platform != PLATFORM_MACCATALYST && + inf.min_version_os_name == "macosx") { + // macCatalyst support. + // + // This the special case of "zippered" frameworks that have both + // a PLATFORM_MACOS and a PLATFORM_MACCATALYST load command. + // + // When we are in this block, this is a binary with both + // PLATFORM_MACOS and PLATFORM_MACCATALYST load commands and + // the process is not running as PLATFORM_MACCATALYST. Stick + // with the "macosx" load command that we've already + // processed, ignore this one, which is presumed to be a // PLATFORM_MACCATALYST one. } else { inf.min_version_os_name = lc_platform; @@ -960,23 +987,15 @@ JSONGenerator::ObjectSP MachProcess::GetLoadedDynamicLibrariesInfos( nub_process_t pid, nub_addr_t image_list_address, nub_addr_t image_count) { JSONGenerator::DictionarySP reply_sp; - int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, pid}; - struct kinfo_proc processInfo; - size_t bufsize = sizeof(processInfo); - if (sysctl(mib, (unsigned)(sizeof(mib) / sizeof(int)), &processInfo, &bufsize, - NULL, 0) == 0 && - bufsize > 0) { - uint32_t pointer_size = 4; - if (processInfo.kp_proc.p_flag & P_LP64) - pointer_size = 8; + int pointer_size = GetInferiorAddrSize(pid); - std::vector image_infos; - size_t image_infos_size = image_count * 3 * pointer_size; + std::vector image_infos; + size_t image_infos_size = image_count * 3 * pointer_size; - uint8_t *image_info_buf = (uint8_t *)malloc(image_infos_size); - if (image_info_buf == NULL) { - return reply_sp; - } + uint8_t *image_info_buf = (uint8_t *)malloc(image_infos_size); + if (image_info_buf == NULL) { + return reply_sp; + } if (ReadMemory(image_list_address, image_infos_size, image_info_buf) != image_infos_size) { return reply_sp; @@ -1058,30 +1077,46 @@ JSONGenerator::ObjectSP MachProcess::GetLoadedDynamicLibrariesInfos( //// Third, format all of the above in the JSONGenerator object. return FormatDynamicLibrariesIntoJSON(image_infos); - } return reply_sp; } -// From dyld SPI header dyld_process_info.h +/// From dyld SPI header dyld_process_info.h typedef void *dyld_process_info; struct dyld_process_cache_info { - uuid_t cacheUUID; // UUID of cache used by process - uint64_t cacheBaseAddress; // load address of dyld shared cache - bool noCache; // process is running without a dyld cache - bool privateCache; // process is using a private copy of its dyld cache + /// UUID of cache used by process. + uuid_t cacheUUID; + /// Load address of dyld shared cache. + uint64_t cacheBaseAddress; + /// Process is running without a dyld cache. + bool noCache; + /// Process is using a private copy of its dyld cache. + bool privateCache; }; -// Use the dyld SPI present in macOS 10.12, iOS 10, tvOS 10, watchOS 3 and newer -// to get -// the load address, uuid, and filenames of all the libraries. -// This only fills in those three fields in the 'struct -// binary_image_information' - call -// GetMachOInformationFromMemory to fill in the mach-o header/load command -// details. -uint32_t MachProcess::GetAllLoadedBinariesViaDYLDSPI( - std::vector &image_infos) { +uint32_t MachProcess::GetPlatform() { + if (m_platform == 0) + m_platform = MachProcess::GetProcessPlatformViaDYLDSPI(); + return m_platform; +} + +uint32_t MachProcess::GetProcessPlatformViaDYLDSPI() { + kern_return_t kern_ret; uint32_t platform = 0; + if (m_dyld_process_info_create) { + dyld_process_info info = + m_dyld_process_info_create(m_task.TaskPort(), 0, &kern_ret); + if (info) { + if (m_dyld_process_info_get_platform) + platform = m_dyld_process_info_get_platform(info); + m_dyld_process_info_release(info); + } + } + return platform; +} + +void MachProcess::GetAllLoadedBinariesViaDYLDSPI( + std::vector &image_infos) { kern_return_t kern_ret; if (m_dyld_process_info_create) { dyld_process_info info = @@ -1096,12 +1131,9 @@ uint32_t MachProcess::GetAllLoadedBinariesViaDYLDSPI( image.load_address = mach_header_addr; image_infos.push_back(image); }); - if (m_dyld_process_info_get_platform) - platform = m_dyld_process_info_get_platform(info); m_dyld_process_info_release(info); } } - return platform; } // Fetch information about all shared libraries using the dyld SPIs that exist @@ -1111,27 +1143,16 @@ JSONGenerator::ObjectSP MachProcess::GetAllLoadedLibrariesInfos(nub_process_t pid) { JSONGenerator::DictionarySP reply_sp; - int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, pid}; - struct kinfo_proc processInfo; - size_t bufsize = sizeof(processInfo); - if (sysctl(mib, (unsigned)(sizeof(mib) / sizeof(int)), &processInfo, &bufsize, - NULL, 0) == 0 && - bufsize > 0) { - uint32_t pointer_size = 4; - if (processInfo.kp_proc.p_flag & P_LP64) - pointer_size = 8; - - std::vector image_infos; - uint32_t platform = GetAllLoadedBinariesViaDYLDSPI(image_infos); - const size_t image_count = image_infos.size(); - for (size_t i = 0; i < image_count; i++) { - GetMachOInformationFromMemory(platform, - image_infos[i].load_address, pointer_size, - image_infos[i].macho_info); - } - return FormatDynamicLibrariesIntoJSON(image_infos); + int pointer_size = GetInferiorAddrSize(pid); + std::vector image_infos; + GetAllLoadedBinariesViaDYLDSPI(image_infos); + uint32_t platform = GetPlatform(); + const size_t image_count = image_infos.size(); + for (size_t i = 0; i < image_count; i++) { + GetMachOInformationFromMemory(platform, image_infos[i].load_address, + pointer_size, image_infos[i].macho_info); } - return reply_sp; + return FormatDynamicLibrariesIntoJSON(image_infos); } // Fetch information about the shared libraries at the given load addresses @@ -1141,29 +1162,22 @@ JSONGenerator::ObjectSP MachProcess::GetLibrariesInfoForAddresses( nub_process_t pid, std::vector &macho_addresses) { JSONGenerator::DictionarySP reply_sp; - int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, pid}; - struct kinfo_proc processInfo; - size_t bufsize = sizeof(processInfo); - if (sysctl(mib, (unsigned)(sizeof(mib) / sizeof(int)), &processInfo, &bufsize, - NULL, 0) == 0 && - bufsize > 0) { - uint32_t pointer_size = 4; - if (processInfo.kp_proc.p_flag & P_LP64) - pointer_size = 8; - - std::vector all_image_infos; - uint32_t platform = GetAllLoadedBinariesViaDYLDSPI(all_image_infos); - - std::vector image_infos; - const size_t macho_addresses_count = macho_addresses.size(); - const size_t all_image_infos_count = all_image_infos.size(); - for (size_t i = 0; i < macho_addresses_count; i++) { - for (size_t j = 0; j < all_image_infos_count; j++) { - if (all_image_infos[j].load_address == macho_addresses[i]) { - image_infos.push_back(all_image_infos[j]); - } + int pointer_size = GetInferiorAddrSize(pid); + + std::vector all_image_infos; + GetAllLoadedBinariesViaDYLDSPI(all_image_infos); + uint32_t platform = GetPlatform(); + + std::vector image_infos; + const size_t macho_addresses_count = macho_addresses.size(); + const size_t all_image_infos_count = all_image_infos.size(); + for (size_t i = 0; i < macho_addresses_count; i++) { + for (size_t j = 0; j < all_image_infos_count; j++) { + if (all_image_infos[j].load_address == macho_addresses[i]) { + image_infos.push_back(all_image_infos[j]); } } + } const size_t image_infos_count = image_infos.size(); for (size_t i = 0; i < image_infos_count; i++) { @@ -1172,15 +1186,13 @@ JSONGenerator::ObjectSP MachProcess::GetLibrariesInfoForAddresses( image_infos[i].macho_info); } return FormatDynamicLibrariesIntoJSON(image_infos); - } - return reply_sp; } // From dyld's internal podyld_process_info.h: JSONGenerator::ObjectSP MachProcess::GetSharedCacheInfo(nub_process_t pid) { JSONGenerator::DictionarySP reply_sp(new JSONGenerator::Dictionary()); - ; + kern_return_t kern_ret; if (m_dyld_process_info_create && m_dyld_process_info_get_cache) { dyld_process_info info = @@ -1318,6 +1330,7 @@ void MachProcess::Clear(bool detaching) { // Clear any cached thread list while the pid and task are still valid m_task.Clear(); + m_platform = 0; // Now clear out all member variables m_pid = INVALID_NUB_PROCESS; if (!detaching) @@ -1404,7 +1417,7 @@ bool MachProcess::Kill(const struct timespec *timeout_abstime) { DNBLogThreadedIf(LOG_PROCESS, "MachProcess::Kill() DoSIGSTOP() state = %s", DNBStateAsString(state)); errno = 0; - DNBLog("Sending ptrace PT_KILL to terminate inferior process."); + DNBLog("Sending ptrace PT_KILL to terminate inferior process pid %d.", m_pid); ::ptrace(PT_KILL, m_pid, 0, 0); DNBError err; err.SetErrorToErrno(); @@ -1609,6 +1622,7 @@ bool MachProcess::Detach() { // NULL our task out as we have already restored all exception ports m_task.Clear(); + m_platform = 0; // Clear out any notion of the process we once were const bool detaching = true; @@ -2576,7 +2590,8 @@ void *MachProcess::ProfileThread(void *arg) { return NULL; } -pid_t MachProcess::AttachForDebug(pid_t pid, char *err_str, size_t err_len) { +pid_t MachProcess::AttachForDebug(pid_t pid, bool unmask_signals, char *err_str, + size_t err_len) { // Clear out and clean up from any current state Clear(); if (pid != 0) { @@ -2593,20 +2608,31 @@ pid_t MachProcess::AttachForDebug(pid_t pid, char *err_str, size_t err_len) { SetState(eStateAttaching); m_pid = pid; - if (!m_task.StartExceptionThread(err)) { + if (!m_task.StartExceptionThread(unmask_signals, err)) { const char *err_cstr = err.AsString(); ::snprintf(err_str, err_len, "%s", err_cstr ? err_cstr : "unable to start the exception thread"); DNBLogThreadedIf(LOG_PROCESS, "error: failed to attach to pid %d", pid); - DNBLogError ("MachProcess::AttachForDebug failed to start exception thread: %s", err_str); + DNBLogError( + "[LaunchAttach] END (%d) MachProcess::AttachForDebug failed to start " + "exception thread attaching to pid %i: %s", + getpid(), pid, err_str); m_pid = INVALID_NUB_PROCESS; return INVALID_NUB_PROCESS; } + DNBLog("[LaunchAttach] (%d) About to ptrace(PT_ATTACHEXC, %d)...", getpid(), + pid); errno = 0; - if (::ptrace(PT_ATTACHEXC, pid, 0, 0)) { - err.SetError(errno); - DNBLogError ("MachProcess::AttachForDebug failed to ptrace(PT_ATTACHEXC): %s", err.AsString()); + int ptrace_result = ::ptrace(PT_ATTACHEXC, pid, 0, 0); + int ptrace_errno = errno; + DNBLog("[LaunchAttach] (%d) Completed ptrace(PT_ATTACHEXC, %d) == %d", + getpid(), pid, ptrace_result); + if (ptrace_result != 0) { + err.SetError(ptrace_errno); + DNBLogError("MachProcess::AttachForDebug failed to ptrace(PT_ATTACHEXC) " + "pid %i: %s", + pid, err.AsString()); } else { err.Clear(); } @@ -2617,11 +2643,16 @@ pid_t MachProcess::AttachForDebug(pid_t pid, char *err_str, size_t err_len) { // status // to stopped. ::usleep(250000); + DNBLog("[LaunchAttach] (%d) Done napping after ptrace(PT_ATTACHEXC)'ing", + getpid()); DNBLogThreadedIf(LOG_PROCESS, "successfully attached to pid %d", pid); return m_pid; } else { ::snprintf(err_str, err_len, "%s", err.AsString()); - DNBLogError ("MachProcess::AttachForDebug error: failed to attach to pid %d", pid); + DNBLogError( + "[LaunchAttach] (%d) MachProcess::AttachForDebug error: failed to " + "attach to pid %d", + getpid(), pid); struct kinfo_proc kinfo; int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, pid}; @@ -2629,7 +2660,10 @@ pid_t MachProcess::AttachForDebug(pid_t pid, char *err_str, size_t err_len) { if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), &kinfo, &len, NULL, 0) == 0 && len > 0) { if (kinfo.kp_proc.p_flag & P_TRACED) { ::snprintf(err_str, err_len, "%s - process %d is already being debugged", err.AsString(), pid); - DNBLogError ("MachProcess::AttachForDebug pid %d is already being debugged", pid); + DNBLogError( + "[LaunchAttach] (%d) MachProcess::AttachForDebug pid %d is " + "already being debugged", + getpid(), pid); } } } @@ -2650,10 +2684,6 @@ MachProcess::GetGenealogyImageInfo(size_t idx) { bool MachProcess::GetOSVersionNumbers(uint64_t *major, uint64_t *minor, uint64_t *patch) { -#if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && \ - (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 101000) - return false; -#else NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; NSOperatingSystemVersion vers = @@ -2668,7 +2698,6 @@ bool MachProcess::GetOSVersionNumbers(uint64_t *major, uint64_t *minor, [pool drain]; return true; -#endif } std::string MachProcess::GetMacCatalystVersionString() { @@ -2683,6 +2712,30 @@ std::string MachProcess::GetMacCatalystVersionString() { return {}; } +#if defined(WITH_SPRINGBOARD) || defined(WITH_BKS) || defined(WITH_FBS) +/// Get the app bundle from the given path. Returns the empty string if the +/// path doesn't appear to be an app bundle. +static std::string GetAppBundle(std::string path) { + auto pos = path.rfind(".app"); + // Path doesn't contain `.app`. + if (pos == std::string::npos) + return {}; + // Path has `.app` extension. + if (pos == path.size() - 4) + return path.substr(0, pos + 4); + + // Look for `.app` before a path separator. + do { + if (path[pos + 4] == '/') + return path.substr(0, pos + 4); + path = path.substr(0, pos); + pos = path.rfind(".app"); + } while (pos != std::string::npos); + + return {}; +} +#endif + // Do the process specific setup for attach. If this returns NULL, then there's // no // platform specific stuff to be done to wait for the attach. If you get @@ -2706,10 +2759,8 @@ const void *MachProcess::PrepareForAttach(const char *path, if (!waitfor) return NULL; - const char *app_ext = strstr(path, ".app"); - const bool is_app = - app_ext != NULL && (app_ext[4] == '\0' || app_ext[4] == '/'); - if (!is_app) { + std::string app_bundle_path = GetAppBundle(path); + if (app_bundle_path.empty()) { DNBLogThreadedIf( LOG_PROCESS, "MachProcess::PrepareForAttach(): path '%s' doesn't contain .app, " @@ -2735,8 +2786,6 @@ const void *MachProcess::PrepareForAttach(const char *path, return NULL; #endif - std::string app_bundle_path(path, app_ext + strlen(".app")); - CFStringRef bundleIDCFStr = CopyBundleIDForPath(app_bundle_path.c_str(), attach_err); std::string bundleIDStr; @@ -2790,6 +2839,9 @@ const void *MachProcess::PrepareForAttach(const char *path, NSString *bundleIDNSStr = (NSString *)bundleIDCFStr; + DNBLog("[LaunchAttach] START (%d) requesting FBS launch of app with bundle " + "ID '%s'", + getpid(), bundleIDStr.c_str()); [system_service openApplication:bundleIDNSStr options:options clientPort:client_port @@ -2868,6 +2920,9 @@ const void *MachProcess::PrepareForAttach(const char *path, NSString *bundleIDNSStr = (NSString *)bundleIDCFStr; + DNBLog("[LaunchAttach] START (%d) requesting BKS launch of app with bundle " + "ID '%s'", + getpid(), bundleIDStr.c_str()); [system_service openApplication:bundleIDNSStr options:options clientPort:client_port @@ -2898,7 +2953,7 @@ const void *MachProcess::PrepareForAttach(const char *path, std::string empty_str; SetBKSError(attach_error_code, empty_str, attach_err); DNBLogError("unable to launch the application with CFBundleIdentifier " - "'%s' bks_error = %ld", + "'%s' bks_error = %d", bundleIDStr.c_str(), attach_error_code); } dispatch_release(semaphore); @@ -2920,6 +2975,10 @@ const void *MachProcess::PrepareForAttach(const char *path, "SBSApplicationLaunchWaitForDebugger )", bundleIDStr.c_str(), stdout_err, stdout_err); + DNBLog("[LaunchAttach] START (%d) requesting SpringBoard launch of app " + "with bundle " + "ID '%s'", + getpid(), bundleIDStr.c_str()); sbs_error = SBSLaunchApplicationForDebugging( bundleIDCFStr, (CFURLRef)NULL, // openURL @@ -3053,7 +3112,7 @@ pid_t MachProcess::LaunchForDebug( // working directory for inferior to this const char *stdin_path, const char *stdout_path, const char *stderr_path, bool no_stdio, nub_launch_flavor_t launch_flavor, int disable_aslr, - const char *event_data, DNBError &launch_err) { + const char *event_data, bool unmask_signals, DNBError &launch_err) { // Clear out and clean up from any current state Clear(); @@ -3074,74 +3133,55 @@ pid_t MachProcess::LaunchForDebug( break; #ifdef WITH_FBS case eLaunchFlavorFBS: { - const char *app_ext = strstr(path, ".app"); - if (app_ext && (app_ext[4] == '\0' || app_ext[4] == '/')) { - std::string app_bundle_path(path, app_ext + strlen(".app")); + std::string app_bundle_path = GetAppBundle(path); + if (!app_bundle_path.empty()) { m_flags |= (eMachProcessFlagsUsingFBS | eMachProcessFlagsBoardCalculated); if (BoardServiceLaunchForDebug(app_bundle_path.c_str(), argv, envp, no_stdio, disable_aslr, event_data, - launch_err) != 0) + unmask_signals, launch_err) != 0) return m_pid; // A successful SBLaunchForDebug() returns and assigns a // non-zero m_pid. - else - break; // We tried a FBS launch, but didn't succeed lets get out } + DNBLog("Failed to launch '%s' with FBS", app_bundle_path); } break; #endif #ifdef WITH_BKS case eLaunchFlavorBKS: { - const char *app_ext = strstr(path, ".app"); - if (app_ext && (app_ext[4] == '\0' || app_ext[4] == '/')) { - std::string app_bundle_path(path, app_ext + strlen(".app")); + std::string app_bundle_path = GetAppBundle(path); + if (!app_bundle_path.empty()) { m_flags |= (eMachProcessFlagsUsingBKS | eMachProcessFlagsBoardCalculated); if (BoardServiceLaunchForDebug(app_bundle_path.c_str(), argv, envp, no_stdio, disable_aslr, event_data, - launch_err) != 0) + unmask_signals, launch_err) != 0) return m_pid; // A successful SBLaunchForDebug() returns and assigns a // non-zero m_pid. - else - break; // We tried a BKS launch, but didn't succeed lets get out } + DNBLog("Failed to launch '%s' with BKS", app_bundle_path); } break; #endif #ifdef WITH_SPRINGBOARD - case eLaunchFlavorSpringBoard: { - // .../whatever.app/whatever ? - // Or .../com.apple.whatever.app/whatever -- be careful of ".app" in - // "com.apple.whatever" here - const char *app_ext = strstr(path, ".app/"); - if (app_ext == NULL) { - // .../whatever.app ? - int len = strlen(path); - if (len > 5) { - if (strcmp(path + len - 4, ".app") == 0) { - app_ext = path + len - 4; - } - } - } - if (app_ext) { - std::string app_bundle_path(path, app_ext + strlen(".app")); + std::string app_bundle_path = GetAppBundle(path); + if (!app_bundle_path.empty()) { if (SBLaunchForDebug(app_bundle_path.c_str(), argv, envp, no_stdio, - disable_aslr, launch_err) != 0) + disable_aslr, unmask_signals, launch_err) != 0) return m_pid; // A successful SBLaunchForDebug() returns and assigns a // non-zero m_pid. - else - break; // We tried a springboard launch, but didn't succeed lets get out } + DNBLog("Failed to launch '%s' with SpringBoard", app_bundle_path); } break; #endif case eLaunchFlavorPosixSpawn: m_pid = MachProcess::PosixSpawnChildForPTraceDebugging( - path, DNBArchProtocol::GetArchitecture(), argv, envp, working_directory, - stdin_path, stdout_path, stderr_path, no_stdio, this, disable_aslr, - launch_err); + path, DNBArchProtocol::GetCPUType(), DNBArchProtocol::GetCPUSubType(), + argv, envp, working_directory, stdin_path, stdout_path, stderr_path, + no_stdio, this, disable_aslr, launch_err); break; default: - // Invalid launch + DNBLog("Failed to launch: invalid launch flavor: %d", launch_flavor); launch_err.SetError(NUB_GENERIC_ERROR, DNBError::Generic); return INVALID_NUB_PROCESS; } @@ -3158,7 +3198,7 @@ pid_t MachProcess::LaunchForDebug( for (i = 0; (arg = argv[i]) != NULL; i++) m_args.push_back(arg); - m_task.StartExceptionThread(launch_err); + m_task.StartExceptionThread(unmask_signals, launch_err); if (launch_err.Fail()) { if (launch_err.AsString() == NULL) launch_err.SetErrorString("unable to start the exception thread"); @@ -3175,14 +3215,19 @@ pid_t MachProcess::LaunchForDebug( SetState(eStateAttaching); errno = 0; + DNBLog("[LaunchAttach] (%d) About to ptrace(PT_ATTACHEXC, %d)...", + getpid(), m_pid); int err = ::ptrace(PT_ATTACHEXC, m_pid, 0, 0); + int ptrace_errno = errno; + DNBLog("[LaunchAttach] (%d) Completed ptrace(PT_ATTACHEXC, %d) == %d", + getpid(), m_pid, err); if (err == 0) { m_flags |= eMachProcessFlagsAttached; DNBLogThreadedIf(LOG_PROCESS, "successfully spawned pid %d", m_pid); launch_err.Clear(); } else { SetState(eStateExited); - DNBError ptrace_err(errno, DNBError::POSIX); + DNBError ptrace_err(ptrace_errno, DNBError::POSIX); DNBLogThreadedIf(LOG_PROCESS, "error: failed to attach to spawned pid " "%d (err = %i, errno = %i (%s))", m_pid, err, ptrace_err.Status(), @@ -3197,10 +3242,10 @@ pid_t MachProcess::LaunchForDebug( } pid_t MachProcess::PosixSpawnChildForPTraceDebugging( - const char *path, cpu_type_t cpu_type, char const *argv[], - char const *envp[], const char *working_directory, const char *stdin_path, - const char *stdout_path, const char *stderr_path, bool no_stdio, - MachProcess *process, int disable_aslr, DNBError &err) { + const char *path, cpu_type_t cpu_type, cpu_subtype_t cpu_subtype, + char const *argv[], char const *envp[], const char *working_directory, + const char *stdin_path, const char *stdout_path, const char *stderr_path, + bool no_stdio, MachProcess *process, int disable_aslr, DNBError &err) { posix_spawnattr_t attr; short flags; DNBLogThreadedIf(LOG_PROCESS, @@ -3243,24 +3288,44 @@ pid_t MachProcess::PosixSpawnChildForPTraceDebugging( // On SnowLeopard we should set "DYLD_NO_PIE" in the inferior environment.... -#if !defined(__arm__) - - // We don't need to do this for ARM, and we really shouldn't now that we - // have multiple CPU subtypes and no posix_spawnattr call that allows us - // to set which CPU subtype to launch... if (cpu_type != 0) { size_t ocount = 0; - err.SetError(::posix_spawnattr_setbinpref_np(&attr, 1, &cpu_type, &ocount), - DNBError::POSIX); - if (err.Fail() || DNBLogCheckLogBit(LOG_PROCESS)) - err.LogThreaded("::posix_spawnattr_setbinpref_np ( &attr, 1, cpu_type = " - "0x%8.8x, count => %llu )", - cpu_type, (uint64_t)ocount); + bool slice_preference_set = false; + + if (cpu_subtype != 0) { + typedef int (*posix_spawnattr_setarchpref_np_t)( + posix_spawnattr_t *, size_t, cpu_type_t *, cpu_subtype_t *, size_t *); + posix_spawnattr_setarchpref_np_t posix_spawnattr_setarchpref_np_fn = + (posix_spawnattr_setarchpref_np_t)dlsym( + RTLD_DEFAULT, "posix_spawnattr_setarchpref_np"); + if (posix_spawnattr_setarchpref_np_fn) { + err.SetError((*posix_spawnattr_setarchpref_np_fn)( + &attr, 1, &cpu_type, &cpu_subtype, &ocount)); + slice_preference_set = err.Success(); + if (err.Fail() || DNBLogCheckLogBit(LOG_PROCESS)) + err.LogThreaded( + "::posix_spawnattr_setarchpref_np ( &attr, 1, cpu_type = " + "0x%8.8x, cpu_subtype = 0x%8.8x, count => %llu )", + cpu_type, cpu_subtype, (uint64_t)ocount); + if (err.Fail() != 0 || ocount != 1) + return INVALID_NUB_PROCESS; + } + } - if (err.Fail() != 0 || ocount != 1) - return INVALID_NUB_PROCESS; + if (!slice_preference_set) { + err.SetError( + ::posix_spawnattr_setbinpref_np(&attr, 1, &cpu_type, &ocount), + DNBError::POSIX); + if (err.Fail() || DNBLogCheckLogBit(LOG_PROCESS)) + err.LogThreaded( + "::posix_spawnattr_setbinpref_np ( &attr, 1, cpu_type = " + "0x%8.8x, count => %llu )", + cpu_type, (uint64_t)ocount); + + if (err.Fail() != 0 || ocount != 1) + return INVALID_NUB_PROCESS; + } } -#endif PseudoTerminal pty; @@ -3501,7 +3566,8 @@ static CFStringRef CopyBundleIDForPath(const char *app_bundle_path, pid_t MachProcess::SBLaunchForDebug(const char *path, char const *argv[], char const *envp[], bool no_stdio, - bool disable_aslr, DNBError &launch_err) { + bool disable_aslr, bool unmask_signals, + DNBError &launch_err) { // Clear out and clean up from any current state Clear(); @@ -3517,7 +3583,7 @@ pid_t MachProcess::SBLaunchForDebug(const char *path, char const *argv[], char const *arg; for (i = 0; (arg = argv[i]) != NULL; i++) m_args.push_back(arg); - m_task.StartExceptionThread(launch_err); + m_task.StartExceptionThread(unmask_signals, launch_err); if (launch_err.Fail()) { if (launch_err.AsString() == NULL) @@ -3531,7 +3597,11 @@ pid_t MachProcess::SBLaunchForDebug(const char *path, char const *argv[], StartSTDIOThread(); SetState(eStateAttaching); + DNBLog("[LaunchAttach] (%d) About to ptrace(PT_ATTACHEXC, %d)...", getpid(), + m_pid); int err = ::ptrace(PT_ATTACHEXC, m_pid, 0, 0); + DNBLog("[LaunchAttach] (%d) Completed ptrace(PT_ATTACHEXC, %d) == %d", + getpid(), m_pid, err); if (err == 0) { m_flags |= eMachProcessFlagsAttached; DNBLogThreadedIf(LOG_PROCESS, "successfully attached to pid %d", m_pid); @@ -3714,7 +3784,8 @@ pid_t MachProcess::SBForkChildForPTraceDebugging( #if defined(WITH_BKS) || defined(WITH_FBS) pid_t MachProcess::BoardServiceLaunchForDebug( const char *path, char const *argv[], char const *envp[], bool no_stdio, - bool disable_aslr, const char *event_data, DNBError &launch_err) { + bool disable_aslr, const char *event_data, bool unmask_signals, + DNBError &launch_err) { DNBLogThreadedIf(LOG_PROCESS, "%s( '%s', argv)", __FUNCTION__, path); // Fork a child process for debugging @@ -3727,13 +3798,16 @@ pid_t MachProcess::BoardServiceLaunchForDebug( char const *arg; for (i = 0; (arg = argv[i]) != NULL; i++) m_args.push_back(arg); - m_task.StartExceptionThread(launch_err); + m_task.StartExceptionThread(unmask_signals, launch_err); if (launch_err.Fail()) { if (launch_err.AsString() == NULL) launch_err.SetErrorString("unable to start the exception thread"); - DNBLog("Could not get inferior's Mach exception port, sending ptrace " - "PT_KILL and exiting."); + DNBLog("[LaunchAttach] END (%d) Could not get inferior's Mach exception " + "port, " + "sending ptrace " + "PT_KILL to pid %i and exiting.", + getpid(), m_pid); ::ptrace(PT_KILL, m_pid, 0, 0); m_pid = INVALID_NUB_PROCESS; return INVALID_NUB_PROCESS; @@ -3741,13 +3815,18 @@ pid_t MachProcess::BoardServiceLaunchForDebug( StartSTDIOThread(); SetState(eStateAttaching); + DNBLog("[LaunchAttach] (%d) About to ptrace(PT_ATTACHEXC, %d)...", getpid(), + m_pid); int err = ::ptrace(PT_ATTACHEXC, m_pid, 0, 0); + DNBLog("[LaunchAttach] (%d) Completed ptrace(PT_ATTACHEXC, %d) == %d", + getpid(), m_pid, err); if (err == 0) { m_flags |= eMachProcessFlagsAttached; - DNBLogThreadedIf(LOG_PROCESS, "successfully attached to pid %d", m_pid); + DNBLog("[LaunchAttach] successfully attached to pid %d", m_pid); } else { SetState(eStateExited); - DNBLogThreadedIf(LOG_PROCESS, "error: failed to attach to pid %d", m_pid); + DNBLog("[LaunchAttach] END (%d) error: failed to attach to pid %d", + getpid(), m_pid); } } return m_pid; @@ -4086,3 +4165,17 @@ bool MachProcess::ProcessUsingFrontBoard() { CalculateBoardStatus(); return (m_flags & eMachProcessFlagsUsingFBS) != 0; } + +int MachProcess::GetInferiorAddrSize(pid_t pid) { + int pointer_size = 8; + int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, pid}; + struct kinfo_proc processInfo; + size_t bufsize = sizeof(processInfo); + if (sysctl(mib, (unsigned)(sizeof(mib) / sizeof(int)), &processInfo, &bufsize, + NULL, 0) == 0 && + bufsize > 0) { + if ((processInfo.kp_proc.p_flag & P_LP64) == 0) + pointer_size = 4; + } + return pointer_size; +} diff --git a/gnu/llvm/lldb/tools/debugserver/source/MacOSX/MachTask.h b/gnu/llvm/lldb/tools/debugserver/source/MacOSX/MachTask.h index 36e31dddd45..e9cb885bfdb 100644 --- a/gnu/llvm/lldb/tools/debugserver/source/MacOSX/MachTask.h +++ b/gnu/llvm/lldb/tools/debugserver/source/MacOSX/MachTask.h @@ -67,7 +67,7 @@ public: kern_return_t RestoreExceptionPortInfo(); kern_return_t ShutDownExcecptionThread(); - bool StartExceptionThread(DNBError &err); + bool StartExceptionThread(bool unmask_signals, DNBError &err); nub_addr_t GetDYLDAllImageInfosAddress(DNBError &err); kern_return_t BasicInfo(struct task_basic_info *info); static kern_return_t BasicInfo(task_t task, struct task_basic_info *info); diff --git a/gnu/llvm/lldb/tools/debugserver/source/MacOSX/MachTask.mm b/gnu/llvm/lldb/tools/debugserver/source/MacOSX/MachTask.mm index fcbe6e71389..767dc59b678 100644 --- a/gnu/llvm/lldb/tools/debugserver/source/MacOSX/MachTask.mm +++ b/gnu/llvm/lldb/tools/debugserver/source/MacOSX/MachTask.mm @@ -512,6 +512,7 @@ task_t MachTask::TaskPortForProcessID(pid_t pid, DNBError &err, mach_port_t task_self = mach_task_self(); task_t task = TASK_NULL; for (uint32_t i = 0; i < num_retries; i++) { + DNBLog("[LaunchAttach] (%d) about to task_for_pid(%d)", getpid(), pid); err = ::task_for_pid(task_self, pid, &task); if (DNBLogCheckLogBit(LOG_TASK) || err.Fail()) { @@ -522,13 +523,19 @@ task_t MachTask::TaskPortForProcessID(pid_t pid, DNBError &err, err.AsString() ? err.AsString() : "success"); if (err.Fail()) { err.SetErrorString(str); - DNBLogError ("MachTask::TaskPortForProcessID task_for_pid failed: %s", str); + DNBLogError( + "[LaunchAttach] MachTask::TaskPortForProcessID task_for_pid(%d) " + "failed: %s", + pid, str); } err.LogThreaded(str); } - if (err.Success()) + if (err.Success()) { + DNBLog("[LaunchAttach] (%d) successfully task_for_pid(%d)'ed", getpid(), + pid); return task; + } // Sleep a bit and try again ::usleep(usec_interval); @@ -595,7 +602,7 @@ bool MachTask::IsValid(task_t task) { return false; } -bool MachTask::StartExceptionThread(DNBError &err) { +bool MachTask::StartExceptionThread(bool unmask_signals, DNBError &err) { DNBLogThreadedIf(LOG_EXCEPTIONS, "MachTask::%s ( )", __FUNCTION__); task_t task = TaskPortForProcessID(err); @@ -624,6 +631,12 @@ bool MachTask::StartExceptionThread(DNBError &err) { return false; } + if (unmask_signals) { + m_exc_port_info.mask = m_exc_port_info.mask & + ~(EXC_MASK_BAD_ACCESS | EXC_MASK_BAD_INSTRUCTION | + EXC_MASK_ARITHMETIC); + } + // Set the ability to get all exceptions on this port err = ::task_set_exception_ports( task, m_exc_port_info.mask, m_exception_port, @@ -971,15 +984,15 @@ nub_bool_t MachTask::DeallocateMemory(nub_addr_t addr) { allocation_collection::iterator pos, end = m_allocations.end(); for (pos = m_allocations.begin(); pos != end; pos++) { if ((*pos).first == addr) { + size_t size = (*pos).second; m_allocations.erase(pos); #define ALWAYS_ZOMBIE_ALLOCATIONS 0 if (ALWAYS_ZOMBIE_ALLOCATIONS || getenv("DEBUGSERVER_ZOMBIE_ALLOCATIONS")) { - ::mach_vm_protect(task, (*pos).first, (*pos).second, 0, VM_PROT_NONE); + ::mach_vm_protect(task, addr, size, 0, VM_PROT_NONE); return true; } else - return ::mach_vm_deallocate(task, (*pos).first, (*pos).second) == - KERN_SUCCESS; + return ::mach_vm_deallocate(task, addr, size) == KERN_SUCCESS; } } return false; diff --git a/gnu/llvm/lldb/tools/debugserver/source/MacOSX/MachThread.cpp b/gnu/llvm/lldb/tools/debugserver/source/MacOSX/MachThread.cpp index d2423a5deca..d34914be802 100644 --- a/gnu/llvm/lldb/tools/debugserver/source/MacOSX/MachThread.cpp +++ b/gnu/llvm/lldb/tools/debugserver/source/MacOSX/MachThread.cpp @@ -15,8 +15,8 @@ #include "DNBLog.h" #include "MachProcess.h" #include "ThreadInfo.h" +#include #include -#include #include static uint32_t GetSequenceID() { diff --git a/gnu/llvm/lldb/tools/debugserver/source/MacOSX/MachThreadList.cpp b/gnu/llvm/lldb/tools/debugserver/source/MacOSX/MachThreadList.cpp index ce63b0fd634..71a33adf3e5 100644 --- a/gnu/llvm/lldb/tools/debugserver/source/MacOSX/MachThreadList.cpp +++ b/gnu/llvm/lldb/tools/debugserver/source/MacOSX/MachThreadList.cpp @@ -17,7 +17,7 @@ #include "DNBThreadResumeActions.h" #include "MachProcess.h" -#include +#include #include #include diff --git a/gnu/llvm/lldb/tools/debugserver/source/MacOSX/MachVMMemory.cpp b/gnu/llvm/lldb/tools/debugserver/source/MacOSX/MachVMMemory.cpp index 2b039c7b16c..14220649876 100644 --- a/gnu/llvm/lldb/tools/debugserver/source/MacOSX/MachVMMemory.cpp +++ b/gnu/llvm/lldb/tools/debugserver/source/MacOSX/MachVMMemory.cpp @@ -72,6 +72,49 @@ nub_size_t MachVMMemory::MaxBytesLeftInPage(task_t task, nub_addr_t addr, return count; } +#define MAX_STACK_ALLOC_DISPOSITIONS \ + (16 * 1024 / sizeof(int)) // 16K of allocations + +std::vector get_dirty_pages(task_t task, mach_vm_address_t addr, + mach_vm_size_t size) { + std::vector dirty_pages; + + int pages_to_query = size / vm_page_size; + // Don't try to fetch too many pages' dispositions in a single call or we + // could blow our stack out. + mach_vm_size_t dispositions_size = + std::min(pages_to_query, (int)MAX_STACK_ALLOC_DISPOSITIONS); + int dispositions[dispositions_size]; + + mach_vm_size_t chunk_count = + ((pages_to_query + MAX_STACK_ALLOC_DISPOSITIONS - 1) / + MAX_STACK_ALLOC_DISPOSITIONS); + + for (mach_vm_size_t cur_disposition_chunk = 0; + cur_disposition_chunk < chunk_count; cur_disposition_chunk++) { + mach_vm_size_t dispositions_already_queried = + cur_disposition_chunk * MAX_STACK_ALLOC_DISPOSITIONS; + + mach_vm_size_t chunk_pages_to_query = std::min( + pages_to_query - dispositions_already_queried, dispositions_size); + mach_vm_address_t chunk_page_aligned_start_addr = + addr + (dispositions_already_queried * vm_page_size); + + kern_return_t kr = mach_vm_page_range_query( + task, chunk_page_aligned_start_addr, + chunk_pages_to_query * vm_page_size, (mach_vm_address_t)dispositions, + &chunk_pages_to_query); + if (kr != KERN_SUCCESS) + return dirty_pages; + for (mach_vm_size_t i = 0; i < chunk_pages_to_query; i++) { + uint64_t dirty_addr = chunk_page_aligned_start_addr + (i * vm_page_size); + if (dispositions[i] & VM_PAGE_QUERY_PAGE_DIRTY) + dirty_pages.push_back(dirty_addr); + } + } + return dirty_pages; +} + nub_bool_t MachVMMemory::GetMemoryRegionInfo(task_t task, nub_addr_t address, DNBRegionInfo *region_info) { MachVMRegion vmRegion(task); @@ -80,6 +123,8 @@ nub_bool_t MachVMMemory::GetMemoryRegionInfo(task_t task, nub_addr_t address, region_info->addr = vmRegion.StartAddress(); region_info->size = vmRegion.GetByteSize(); region_info->permissions = vmRegion.GetDNBPermissions(); + region_info->dirty_pages = + get_dirty_pages(task, vmRegion.StartAddress(), vmRegion.GetByteSize()); } else { region_info->addr = address; region_info->size = 0; diff --git a/gnu/llvm/lldb/tools/debugserver/source/MacOSX/MachVMRegion.cpp b/gnu/llvm/lldb/tools/debugserver/source/MacOSX/MachVMRegion.cpp index 6cb34292252..ed2964cbc43 100644 --- a/gnu/llvm/lldb/tools/debugserver/source/MacOSX/MachVMRegion.cpp +++ b/gnu/llvm/lldb/tools/debugserver/source/MacOSX/MachVMRegion.cpp @@ -12,7 +12,7 @@ #include "MachVMRegion.h" #include "DNBLog.h" -#include +#include #include MachVMRegion::MachVMRegion(task_t task) diff --git a/gnu/llvm/lldb/tools/debugserver/source/MacOSX/ThreadInfo.h b/gnu/llvm/lldb/tools/debugserver/source/MacOSX/ThreadInfo.h index a114a47eaab..592d50fd428 100644 --- a/gnu/llvm/lldb/tools/debugserver/source/MacOSX/ThreadInfo.h +++ b/gnu/llvm/lldb/tools/debugserver/source/MacOSX/ThreadInfo.h @@ -20,6 +20,6 @@ public: std::string printable_name; uint32_t enum_value; }; -}; +} #endif // LLDB_TOOLS_DEBUGSERVER_SOURCE_MACOSX_THREADINFO_H diff --git a/gnu/llvm/lldb/tools/debugserver/source/MacOSX/arm/DNBArchImpl.cpp b/gnu/llvm/lldb/tools/debugserver/source/MacOSX/arm/DNBArchImpl.cpp index 90cc25650e3..0748223c421 100644 --- a/gnu/llvm/lldb/tools/debugserver/source/MacOSX/arm/DNBArchImpl.cpp +++ b/gnu/llvm/lldb/tools/debugserver/source/MacOSX/arm/DNBArchImpl.cpp @@ -22,7 +22,7 @@ #include "MacOSX/MachProcess.h" #include "MacOSX/MachThread.h" -#include +#include #include // BCR address match type @@ -105,6 +105,7 @@ static uint32_t LoHi[16] = {0}; #define MNEMONIC_STRING_SIZE 32 #define OPERAND_STRING_SIZE 128 +#if !defined(__arm64__) && !defined(__aarch64__) // Returns true if the first 16 bit opcode of a thumb instruction indicates // the instruction will be a 32 bit thumb opcode static bool IsThumb32Opcode(uint16_t opcode) { @@ -112,6 +113,7 @@ static bool IsThumb32Opcode(uint16_t opcode) { return true; return false; } +#endif void DNBArchMachARM::Initialize() { DNBArchPluginInfo arch_plugin_info = { @@ -315,6 +317,7 @@ kern_return_t DNBArchMachARM::GetEXCState(bool force) { return kret; } +#if 0 static void DumpDBGState(const DNBArchMachARM::DBG &dbg) { uint32_t i = 0; for (i = 0; i < 16; i++) { @@ -324,6 +327,7 @@ static void DumpDBGState(const DNBArchMachARM::DBG &dbg) { dbg.__wcr[i]); } } +#endif kern_return_t DNBArchMachARM::GetDBGState(bool force) { int set = e_regSetDBG; @@ -643,8 +647,8 @@ bool DNBArchMachARM::NotifyException(MachException::Data &exc) { "watchpoint %d was hit on address " "0x%llx", hw_index, (uint64_t)addr); - const int num_watchpoints = NumSupportedHardwareWatchpoints(); - for (int i = 0; i < num_watchpoints; i++) { + const uint32_t num_watchpoints = NumSupportedHardwareWatchpoints(); + for (uint32_t i = 0; i < num_watchpoints; i++) { if (LoHi[i] != 0 && LoHi[i] == hw_index && LoHi[i] != i && GetWatchpointAddressByIndex(i) != INVALID_NUB_ADDRESS) { addr = GetWatchpointAddressByIndex(i); @@ -1758,13 +1762,13 @@ const DNBRegisterInfo DNBArchMachARM::g_vfp_registers[] = { const DNBRegisterInfo DNBArchMachARM::g_exc_registers[] = { {e_regSetVFP, exc_exception, "exception", NULL, Uint, Hex, 4, EXC_OFFSET(exception), INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, - INVALID_NUB_REGNUM, INVALID_NUB_REGNUM}, + INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, NULL, NULL}, {e_regSetVFP, exc_fsr, "fsr", NULL, Uint, Hex, 4, EXC_OFFSET(fsr), INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, - INVALID_NUB_REGNUM}, + INVALID_NUB_REGNUM, NULL, NULL}, {e_regSetVFP, exc_far, "far", NULL, Uint, Hex, 4, EXC_OFFSET(far), INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, - INVALID_NUB_REGNUM}}; + INVALID_NUB_REGNUM, NULL, NULL}}; // Number of registers in each register set const size_t DNBArchMachARM::k_num_gpr_registers = @@ -2114,7 +2118,7 @@ nub_size_t DNBArchMachARM::SetRegisterContext(const void *buf, // Copy each struct individually to avoid any padding that might be between // the structs in m_state.context - uint8_t *p = (uint8_t *)buf; + uint8_t *p = const_cast(reinterpret_cast(buf)); ::memcpy(&m_state.context.gpr, p, sizeof(m_state.context.gpr)); p += sizeof(m_state.context.gpr); ::memcpy(&m_state.context.vfp, p, sizeof(m_state.context.vfp)); @@ -2122,7 +2126,7 @@ nub_size_t DNBArchMachARM::SetRegisterContext(const void *buf, ::memcpy(&m_state.context.exc, p, sizeof(m_state.context.exc)); p += sizeof(m_state.context.exc); - size_t bytes_written = p - (uint8_t *)buf; + size_t bytes_written = p - reinterpret_cast(buf); UNUSED_IF_ASSERT_DISABLED(bytes_written); assert(bytes_written == size); diff --git a/gnu/llvm/lldb/tools/debugserver/source/MacOSX/arm/DNBArchImpl.h b/gnu/llvm/lldb/tools/debugserver/source/MacOSX/arm/DNBArchImpl.h index 29cd3e5ef27..9c27e988ea0 100644 --- a/gnu/llvm/lldb/tools/debugserver/source/MacOSX/arm/DNBArchImpl.h +++ b/gnu/llvm/lldb/tools/debugserver/source/MacOSX/arm/DNBArchImpl.h @@ -44,49 +44,48 @@ public: static void Initialize(); static const DNBRegisterSetInfo *GetRegisterSetInfo(nub_size_t *num_reg_sets); - virtual bool GetRegisterValue(uint32_t set, uint32_t reg, - DNBRegisterValue *value); - virtual bool SetRegisterValue(uint32_t set, uint32_t reg, - const DNBRegisterValue *value); - virtual nub_size_t GetRegisterContext(void *buf, nub_size_t buf_len); - virtual nub_size_t SetRegisterContext(const void *buf, nub_size_t buf_len); - virtual uint32_t SaveRegisterState(); - virtual bool RestoreRegisterState(uint32_t save_id); - - virtual kern_return_t GetRegisterState(int set, bool force); - virtual kern_return_t SetRegisterState(int set); - virtual bool RegisterSetStateIsValid(int set) const; - - virtual uint64_t GetPC(uint64_t failValue); // Get program counter - virtual kern_return_t SetPC(uint64_t value); - virtual uint64_t GetSP(uint64_t failValue); // Get stack pointer - virtual void ThreadWillResume(); - virtual bool ThreadDidStop(); - virtual bool NotifyException(MachException::Data &exc); + bool GetRegisterValue(uint32_t set, uint32_t reg, + DNBRegisterValue *value) override; + bool SetRegisterValue(uint32_t set, uint32_t reg, + const DNBRegisterValue *value) override; + nub_size_t GetRegisterContext(void *buf, nub_size_t buf_len) override; + nub_size_t SetRegisterContext(const void *buf, nub_size_t buf_len) override; + uint32_t SaveRegisterState() override; + bool RestoreRegisterState(uint32_t save_id) override; + + kern_return_t GetRegisterState(int set, bool force) override; + kern_return_t SetRegisterState(int set) override; + bool RegisterSetStateIsValid(int set) const override; + + uint64_t GetPC(uint64_t failValue) override; // Get program counter + kern_return_t SetPC(uint64_t value) override; + uint64_t GetSP(uint64_t failValue) override; // Get stack pointer + void ThreadWillResume() override; + bool ThreadDidStop() override; + bool NotifyException(MachException::Data &exc) override; static DNBArchProtocol *Create(MachThread *thread); static const uint8_t *SoftwareBreakpointOpcode(nub_size_t byte_size); static uint32_t GetCPUType(); - virtual uint32_t NumSupportedHardwareBreakpoints(); - virtual uint32_t NumSupportedHardwareWatchpoints(); - virtual uint32_t EnableHardwareBreakpoint(nub_addr_t addr, nub_size_t size, - bool also_set_on_task); - virtual bool DisableHardwareBreakpoint(uint32_t hw_break_index, - bool also_set_on_task); - - virtual uint32_t EnableHardwareWatchpoint(nub_addr_t addr, nub_size_t size, - bool read, bool write, - bool also_set_on_task); - virtual bool DisableHardwareWatchpoint(uint32_t hw_break_index, - bool also_set_on_task); + uint32_t NumSupportedHardwareBreakpoints() override; + uint32_t NumSupportedHardwareWatchpoints() override; + uint32_t EnableHardwareBreakpoint(nub_addr_t addr, nub_size_t size, + bool also_set_on_task) override; + bool DisableHardwareBreakpoint(uint32_t hw_break_index, + bool also_set_on_task) override; + + uint32_t EnableHardwareWatchpoint(nub_addr_t addr, nub_size_t size, bool read, + bool write, bool also_set_on_task) override; + bool DisableHardwareWatchpoint(uint32_t hw_break_index, + bool also_set_on_task) override; virtual bool DisableHardwareWatchpoint_helper(uint32_t hw_break_index, bool also_set_on_task); virtual bool ReenableHardwareWatchpoint(uint32_t hw_break_index); virtual bool ReenableHardwareWatchpoint_helper(uint32_t hw_break_index); - virtual bool StepNotComplete(); - virtual uint32_t GetHardwareWatchpointHit(nub_addr_t &addr); + virtual bool StepNotComplete() override; + uint32_t GetHardwareWatchpointHit(nub_addr_t &addr) override; #if defined(ARM_DEBUG_STATE32) && (defined(__arm64__) || defined(__aarch64__)) typedef arm_debug_state32_t DBG; diff --git a/gnu/llvm/lldb/tools/debugserver/source/MacOSX/arm64/DNBArchImplARM64.cpp b/gnu/llvm/lldb/tools/debugserver/source/MacOSX/arm64/DNBArchImplARM64.cpp index 7e1af7a7502..69a833303c9 100644 --- a/gnu/llvm/lldb/tools/debugserver/source/MacOSX/arm64/DNBArchImplARM64.cpp +++ b/gnu/llvm/lldb/tools/debugserver/source/MacOSX/arm64/DNBArchImplARM64.cpp @@ -23,7 +23,7 @@ #include "MacOSX/MachProcess.h" #include "MacOSX/MachThread.h" -#include +#include #include #if __has_feature(ptrauth_calls) @@ -149,6 +149,18 @@ kern_return_t DNBArchMachARM64::GetGPRState(bool force) { (thread_state_t)&m_state.context.gpr, &count); if (DNBLogEnabledForAny(LOG_THREAD)) { uint64_t *x = &m_state.context.gpr.__x[0]; + +#if defined(__LP64__) + uint64_t log_fp = arm_thread_state64_get_fp(m_state.context.gpr); + uint64_t log_lr = arm_thread_state64_get_lr(m_state.context.gpr); + uint64_t log_sp = arm_thread_state64_get_sp(m_state.context.gpr); + uint64_t log_pc = arm_thread_state64_get_pc(m_state.context.gpr); +#else + uint64_t log_fp = m_state.context.gpr.__fp; + uint64_t log_fp = m_state.context.gpr.__lr; + uint64_t log_fp = m_state.context.gpr.__sp; + uint64_t log_fp = m_state.context.gpr.__pc, +#endif DNBLogThreaded( "thread_get_state(0x%4.4x, %u, &gpr, %u) => 0x%8.8x (count = %u) regs" "\n x0=%16.16llx" @@ -189,16 +201,7 @@ kern_return_t DNBArchMachARM64::GetGPRState(bool force) { x[0], x[1], x[2], x[3], x[4], x[5], x[6], x[7], x[8], x[9], x[0], x[11], x[12], x[13], x[14], x[15], x[16], x[17], x[18], x[19], x[20], x[21], x[22], x[23], x[24], x[25], x[26], x[27], x[28], -#if defined(__LP64__) - (uint64_t) arm_thread_state64_get_fp (m_state.context.gpr), - (uint64_t) arm_thread_state64_get_lr (m_state.context.gpr), - (uint64_t) arm_thread_state64_get_sp (m_state.context.gpr), - (uint64_t) arm_thread_state64_get_pc (m_state.context.gpr), -#else - m_state.context.gpr.__fp, m_state.context.gpr.__lr, - m_state.context.gpr.__sp, m_state.context.gpr.__pc, -#endif - m_state.context.gpr.__cpsr); + log_fp, log_lr, log_sp, log_pc, m_state.context.gpr.__cpsr); } m_state.SetError(set, Read, kret); return kret; @@ -340,6 +343,7 @@ kern_return_t DNBArchMachARM64::GetEXCState(bool force) { return kret; } +#if 0 static void DumpDBGState(const arm_debug_state_t &dbg) { uint32_t i = 0; for (i = 0; i < 16; i++) @@ -348,6 +352,7 @@ static void DumpDBGState(const arm_debug_state_t &dbg) { i, i, dbg.__bvr[i], dbg.__bcr[i], i, i, dbg.__wvr[i], dbg.__wcr[i]); } +#endif kern_return_t DNBArchMachARM64::GetDBGState(bool force) { int set = e_regSetDBG; @@ -502,8 +507,8 @@ bool DNBArchMachARM64::NotifyException(MachException::Data &exc) { "watchpoint %d was hit on address " "0x%llx", hw_index, (uint64_t)addr); - const int num_watchpoints = NumSupportedHardwareWatchpoints(); - for (int i = 0; i < num_watchpoints; i++) { + const uint32_t num_watchpoints = NumSupportedHardwareWatchpoints(); + for (uint32_t i = 0; i < num_watchpoints; i++) { if (LoHi[i] != 0 && LoHi[i] == hw_index && LoHi[i] != i && GetWatchpointAddressByIndex(i) != INVALID_NUB_ADDRESS) { addr = GetWatchpointAddressByIndex(i); @@ -524,6 +529,28 @@ bool DNBArchMachARM64::NotifyException(MachException::Data &exc) { return true; } + // detect a __builtin_debugtrap instruction pattern ("brk #0xf000") + // and advance the $pc past it, so that the user can continue execution. + // Generally speaking, this knowledge should be centralized in lldb, + // recognizing the builtin_trap instruction and knowing how to advance + // the pc past it, so that continue etc work. + if (exc.exc_data.size() == 2 && exc.exc_data[0] == EXC_ARM_BREAKPOINT) { + nub_addr_t pc = GetPC(INVALID_NUB_ADDRESS); + if (pc != INVALID_NUB_ADDRESS && pc > 0) { + DNBBreakpoint *bp = + m_thread->Process()->Breakpoints().FindByAddress(pc); + if (bp == nullptr) { + uint8_t insnbuf[4]; + if (m_thread->Process()->ReadMemory(pc, 4, insnbuf) == 4) { + uint8_t builtin_debugtrap_insn[4] = {0x00, 0x00, 0x3e, + 0xd4}; // brk #0xf000 + if (memcmp(insnbuf, builtin_debugtrap_insn, 4) == 0) { + SetPC(pc + 4); + } + } + } + } + } break; } return false; @@ -797,15 +824,15 @@ uint32_t DNBArchMachARM64::EnableHardwareWatchpoint(nub_addr_t addr, // an 8 byte address, or (2) a power-of-two size region of memory; minimum // 8 bytes, maximum 2GB; the starting address must be aligned to that power // of two. - // + // // For (1), 1-8 byte watchpoints, using the Byte Address Selector field in // DBGWCR.BAS. Any of the bytes may be watched, but if multiple bytes // are watched, the bytes selected must be contiguous. The start address // watched must be doubleword (8-byte) aligned; if the start address is // word (4-byte) aligned, only 4 bytes can be watched. - // + // // For (2), the MASK field in DBGWCR.MASK is used. - // + // // See the ARM ARM, section "Watchpoint exceptions", and more specifically, // "Watchpoint data address comparisons". // @@ -817,9 +844,9 @@ uint32_t DNBArchMachARM64::EnableHardwareWatchpoint(nub_addr_t addr, // "Determining the memory location that caused a Watchpoint exception"), // and silently resume the inferior (disable watchpoint, stepi, re-enable // watchpoint) if the address lies outside the region that lldb asked us - // to watch. + // to watch. // - // Alternatively, lldb would need to be prepared for a larger region + // Alternatively, lldb would need to be prepared for a larger region // being watched than it requested, and silently resume the inferior if // the accessed address is outside the region lldb wants to watch. @@ -2076,7 +2103,7 @@ bool DNBArchMachARM64::SetRegisterValue(uint32_t set, uint32_t reg, signed_value = (uint64_t) ptrauth_strip((void*) signed_value, ptrauth_key_function_pointer); signed_value = (uint64_t) ptrauth_sign_unauthenticated((void*) signed_value, ptrauth_key_function_pointer, 0); #endif - if (reg == gpr_pc) + if (reg == gpr_pc) arm_thread_state64_set_pc_fptr (m_state.context.gpr, (void*) signed_value); else if (reg == gpr_lr) arm_thread_state64_set_lr_fptr (m_state.context.gpr, (void*) signed_value); @@ -2256,7 +2283,7 @@ nub_size_t DNBArchMachARM64::SetRegisterContext(const void *buf, // Copy each struct individually to avoid any padding that might be between // the structs in m_state.context - uint8_t *p = (uint8_t *)buf; + uint8_t *p = const_cast(reinterpret_cast(buf)); ::memcpy(&m_state.context.gpr, p, sizeof(m_state.context.gpr)); p += sizeof(m_state.context.gpr); ::memcpy(&m_state.context.vfp, p, sizeof(m_state.context.vfp)); @@ -2264,7 +2291,7 @@ nub_size_t DNBArchMachARM64::SetRegisterContext(const void *buf, ::memcpy(&m_state.context.exc, p, sizeof(m_state.context.exc)); p += sizeof(m_state.context.exc); - size_t bytes_written = p - (uint8_t *)buf; + size_t bytes_written = p - reinterpret_cast(buf); UNUSED_IF_ASSERT_DISABLED(bytes_written); assert(bytes_written == size); SetGPRState(); diff --git a/gnu/llvm/lldb/tools/debugserver/source/MacOSX/arm64/DNBArchImplARM64.h b/gnu/llvm/lldb/tools/debugserver/source/MacOSX/arm64/DNBArchImplARM64.h index fafcb73837b..b492fcaca94 100644 --- a/gnu/llvm/lldb/tools/debugserver/source/MacOSX/arm64/DNBArchImplARM64.h +++ b/gnu/llvm/lldb/tools/debugserver/source/MacOSX/arm64/DNBArchImplARM64.h @@ -40,44 +40,43 @@ public: static void Initialize(); static const DNBRegisterSetInfo *GetRegisterSetInfo(nub_size_t *num_reg_sets); - virtual bool GetRegisterValue(uint32_t set, uint32_t reg, - DNBRegisterValue *value); - virtual bool SetRegisterValue(uint32_t set, uint32_t reg, - const DNBRegisterValue *value); - virtual nub_size_t GetRegisterContext(void *buf, nub_size_t buf_len); - virtual nub_size_t SetRegisterContext(const void *buf, nub_size_t buf_len); - virtual uint32_t SaveRegisterState(); - virtual bool RestoreRegisterState(uint32_t save_id); - - virtual kern_return_t GetRegisterState(int set, bool force); - virtual kern_return_t SetRegisterState(int set); - virtual bool RegisterSetStateIsValid(int set) const; - - virtual uint64_t GetPC(uint64_t failValue); // Get program counter - virtual kern_return_t SetPC(uint64_t value); - virtual uint64_t GetSP(uint64_t failValue); // Get stack pointer - virtual void ThreadWillResume(); - virtual bool ThreadDidStop(); - virtual bool NotifyException(MachException::Data &exc); + bool GetRegisterValue(uint32_t set, uint32_t reg, + DNBRegisterValue *value) override; + bool SetRegisterValue(uint32_t set, uint32_t reg, + const DNBRegisterValue *value) override; + nub_size_t GetRegisterContext(void *buf, nub_size_t buf_len) override; + nub_size_t SetRegisterContext(const void *buf, nub_size_t buf_len) override; + uint32_t SaveRegisterState() override; + bool RestoreRegisterState(uint32_t save_id) override; + + kern_return_t GetRegisterState(int set, bool force) override; + kern_return_t SetRegisterState(int set) override; + bool RegisterSetStateIsValid(int set) const override; + + uint64_t GetPC(uint64_t failValue) override; // Get program counter + kern_return_t SetPC(uint64_t value) override; + uint64_t GetSP(uint64_t failValue) override; // Get stack pointer + void ThreadWillResume() override; + bool ThreadDidStop() override; + bool NotifyException(MachException::Data &exc) override; static DNBArchProtocol *Create(MachThread *thread); static const uint8_t *SoftwareBreakpointOpcode(nub_size_t byte_size); static uint32_t GetCPUType(); - virtual uint32_t NumSupportedHardwareBreakpoints(); - virtual uint32_t NumSupportedHardwareWatchpoints(); - - virtual uint32_t EnableHardwareBreakpoint(nub_addr_t addr, nub_size_t size, - bool also_set_on_task); - virtual bool DisableHardwareBreakpoint(uint32_t hw_break_index, - bool also_set_on_task); - virtual uint32_t EnableHardwareWatchpoint(nub_addr_t addr, nub_size_t size, - bool read, bool write, - bool also_set_on_task); - virtual bool DisableHardwareWatchpoint(uint32_t hw_break_index, - bool also_set_on_task); - virtual bool DisableHardwareWatchpoint_helper(uint32_t hw_break_index, - bool also_set_on_task); + uint32_t NumSupportedHardwareBreakpoints() override; + uint32_t NumSupportedHardwareWatchpoints() override; + + uint32_t EnableHardwareBreakpoint(nub_addr_t addr, nub_size_t size, + bool also_set_on_task) override; + bool DisableHardwareBreakpoint(uint32_t hw_break_index, + bool also_set_on_task) override; + uint32_t EnableHardwareWatchpoint(nub_addr_t addr, nub_size_t size, bool read, + bool write, bool also_set_on_task) override; + bool DisableHardwareWatchpoint(uint32_t hw_break_index, + bool also_set_on_task) override; + bool DisableHardwareWatchpoint_helper(uint32_t hw_break_index, + bool also_set_on_task); protected: kern_return_t EnableHardwareSingleStep(bool enable); @@ -220,7 +219,7 @@ protected: nub_addr_t GetWatchAddress(const DBG &debug_state, uint32_t hw_index); virtual bool ReenableHardwareWatchpoint(uint32_t hw_break_index); virtual bool ReenableHardwareWatchpoint_helper(uint32_t hw_break_index); - virtual uint32_t GetHardwareWatchpointHit(nub_addr_t &addr); + uint32_t GetHardwareWatchpointHit(nub_addr_t &addr) override; class disabled_watchpoint { public: diff --git a/gnu/llvm/lldb/tools/debugserver/source/MacOSX/i386/DNBArchImplI386.cpp b/gnu/llvm/lldb/tools/debugserver/source/MacOSX/i386/DNBArchImplI386.cpp index 27bc7511062..2b1d360dcae 100644 --- a/gnu/llvm/lldb/tools/debugserver/source/MacOSX/i386/DNBArchImplI386.cpp +++ b/gnu/llvm/lldb/tools/debugserver/source/MacOSX/i386/DNBArchImplI386.cpp @@ -1356,28 +1356,28 @@ const DNBRegisterInfo DNBArchImplI386::g_fpu_registers_no_avx[] = { FPU_SIZE_UINT(mxcsrmask), FPU_OFFSET(mxcsrmask), INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, NULL, NULL}, - {e_regSetFPU, fpu_stmm0, "stmm0", NULL, Vector, VectorOfUInt8, + {e_regSetFPU, fpu_stmm0, "stmm0", "st0", Vector, VectorOfUInt8, FPU_SIZE_MMST(stmm0), FPU_OFFSET(stmm0), INVALID_NUB_REGNUM, dwarf_stmm0, INVALID_NUB_REGNUM, debugserver_stmm0, NULL, NULL}, - {e_regSetFPU, fpu_stmm1, "stmm1", NULL, Vector, VectorOfUInt8, + {e_regSetFPU, fpu_stmm1, "stmm1", "st1", Vector, VectorOfUInt8, FPU_SIZE_MMST(stmm1), FPU_OFFSET(stmm1), INVALID_NUB_REGNUM, dwarf_stmm1, INVALID_NUB_REGNUM, debugserver_stmm1, NULL, NULL}, - {e_regSetFPU, fpu_stmm2, "stmm2", NULL, Vector, VectorOfUInt8, + {e_regSetFPU, fpu_stmm2, "stmm2", "st2", Vector, VectorOfUInt8, FPU_SIZE_MMST(stmm2), FPU_OFFSET(stmm2), INVALID_NUB_REGNUM, dwarf_stmm2, INVALID_NUB_REGNUM, debugserver_stmm2, NULL, NULL}, - {e_regSetFPU, fpu_stmm3, "stmm3", NULL, Vector, VectorOfUInt8, + {e_regSetFPU, fpu_stmm3, "stmm3", "st3", Vector, VectorOfUInt8, FPU_SIZE_MMST(stmm3), FPU_OFFSET(stmm3), INVALID_NUB_REGNUM, dwarf_stmm3, INVALID_NUB_REGNUM, debugserver_stmm3, NULL, NULL}, - {e_regSetFPU, fpu_stmm4, "stmm4", NULL, Vector, VectorOfUInt8, + {e_regSetFPU, fpu_stmm4, "stmm4", "st4", Vector, VectorOfUInt8, FPU_SIZE_MMST(stmm4), FPU_OFFSET(stmm4), INVALID_NUB_REGNUM, dwarf_stmm4, INVALID_NUB_REGNUM, debugserver_stmm4, NULL, NULL}, - {e_regSetFPU, fpu_stmm5, "stmm5", NULL, Vector, VectorOfUInt8, + {e_regSetFPU, fpu_stmm5, "stmm5", "st5", Vector, VectorOfUInt8, FPU_SIZE_MMST(stmm5), FPU_OFFSET(stmm5), INVALID_NUB_REGNUM, dwarf_stmm5, INVALID_NUB_REGNUM, debugserver_stmm5, NULL, NULL}, - {e_regSetFPU, fpu_stmm6, "stmm6", NULL, Vector, VectorOfUInt8, + {e_regSetFPU, fpu_stmm6, "stmm6", "st6", Vector, VectorOfUInt8, FPU_SIZE_MMST(stmm6), FPU_OFFSET(stmm6), INVALID_NUB_REGNUM, dwarf_stmm6, INVALID_NUB_REGNUM, debugserver_stmm6, NULL, NULL}, - {e_regSetFPU, fpu_stmm7, "stmm7", NULL, Vector, VectorOfUInt8, + {e_regSetFPU, fpu_stmm7, "stmm7", "st7", Vector, VectorOfUInt8, FPU_SIZE_MMST(stmm7), FPU_OFFSET(stmm7), INVALID_NUB_REGNUM, dwarf_stmm7, INVALID_NUB_REGNUM, debugserver_stmm7, NULL, NULL}, @@ -1447,28 +1447,28 @@ const DNBRegisterInfo DNBArchImplI386::g_fpu_registers_avx[] = { FPU_SIZE_UINT(mxcsrmask), AVX_OFFSET(mxcsrmask), INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, NULL, NULL}, - {e_regSetFPU, fpu_stmm0, "stmm0", NULL, Vector, VectorOfUInt8, + {e_regSetFPU, fpu_stmm0, "stmm0", "st0", Vector, VectorOfUInt8, FPU_SIZE_MMST(stmm0), AVX_OFFSET(stmm0), INVALID_NUB_REGNUM, dwarf_stmm0, INVALID_NUB_REGNUM, debugserver_stmm0, NULL, NULL}, - {e_regSetFPU, fpu_stmm1, "stmm1", NULL, Vector, VectorOfUInt8, + {e_regSetFPU, fpu_stmm1, "stmm1", "st1", Vector, VectorOfUInt8, FPU_SIZE_MMST(stmm1), AVX_OFFSET(stmm1), INVALID_NUB_REGNUM, dwarf_stmm1, INVALID_NUB_REGNUM, debugserver_stmm1, NULL, NULL}, - {e_regSetFPU, fpu_stmm2, "stmm2", NULL, Vector, VectorOfUInt8, + {e_regSetFPU, fpu_stmm2, "stmm2", "st2", Vector, VectorOfUInt8, FPU_SIZE_MMST(stmm2), AVX_OFFSET(stmm2), INVALID_NUB_REGNUM, dwarf_stmm2, INVALID_NUB_REGNUM, debugserver_stmm2, NULL, NULL}, - {e_regSetFPU, fpu_stmm3, "stmm3", NULL, Vector, VectorOfUInt8, + {e_regSetFPU, fpu_stmm3, "stmm3", "st3", Vector, VectorOfUInt8, FPU_SIZE_MMST(stmm3), AVX_OFFSET(stmm3), INVALID_NUB_REGNUM, dwarf_stmm3, INVALID_NUB_REGNUM, debugserver_stmm3, NULL, NULL}, - {e_regSetFPU, fpu_stmm4, "stmm4", NULL, Vector, VectorOfUInt8, + {e_regSetFPU, fpu_stmm4, "stmm4", "st4", Vector, VectorOfUInt8, FPU_SIZE_MMST(stmm4), AVX_OFFSET(stmm4), INVALID_NUB_REGNUM, dwarf_stmm4, INVALID_NUB_REGNUM, debugserver_stmm4, NULL, NULL}, - {e_regSetFPU, fpu_stmm5, "stmm5", NULL, Vector, VectorOfUInt8, + {e_regSetFPU, fpu_stmm5, "stmm5", "st5", Vector, VectorOfUInt8, FPU_SIZE_MMST(stmm5), AVX_OFFSET(stmm5), INVALID_NUB_REGNUM, dwarf_stmm5, INVALID_NUB_REGNUM, debugserver_stmm5, NULL, NULL}, - {e_regSetFPU, fpu_stmm6, "stmm6", NULL, Vector, VectorOfUInt8, + {e_regSetFPU, fpu_stmm6, "stmm6", "st6", Vector, VectorOfUInt8, FPU_SIZE_MMST(stmm6), AVX_OFFSET(stmm6), INVALID_NUB_REGNUM, dwarf_stmm6, INVALID_NUB_REGNUM, debugserver_stmm6, NULL, NULL}, - {e_regSetFPU, fpu_stmm7, "stmm7", NULL, Vector, VectorOfUInt8, + {e_regSetFPU, fpu_stmm7, "stmm7", "st7", Vector, VectorOfUInt8, FPU_SIZE_MMST(stmm7), AVX_OFFSET(stmm7), INVALID_NUB_REGNUM, dwarf_stmm7, INVALID_NUB_REGNUM, debugserver_stmm7, NULL, NULL}, @@ -1596,28 +1596,28 @@ const DNBRegisterInfo DNBArchImplI386::g_fpu_registers_avx512f[] = { FPU_SIZE_UINT(mxcsrmask), AVX_OFFSET(mxcsrmask), INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, NULL, NULL}, - {e_regSetFPU, fpu_stmm0, "stmm0", NULL, Vector, VectorOfUInt8, + {e_regSetFPU, fpu_stmm0, "stmm0", "st0", Vector, VectorOfUInt8, FPU_SIZE_MMST(stmm0), AVX_OFFSET(stmm0), INVALID_NUB_REGNUM, dwarf_stmm0, INVALID_NUB_REGNUM, debugserver_stmm0, NULL, NULL}, - {e_regSetFPU, fpu_stmm1, "stmm1", NULL, Vector, VectorOfUInt8, + {e_regSetFPU, fpu_stmm1, "stmm1", "st1", Vector, VectorOfUInt8, FPU_SIZE_MMST(stmm1), AVX_OFFSET(stmm1), INVALID_NUB_REGNUM, dwarf_stmm1, INVALID_NUB_REGNUM, debugserver_stmm1, NULL, NULL}, - {e_regSetFPU, fpu_stmm2, "stmm2", NULL, Vector, VectorOfUInt8, + {e_regSetFPU, fpu_stmm2, "stmm2", "st2", Vector, VectorOfUInt8, FPU_SIZE_MMST(stmm2), AVX_OFFSET(stmm2), INVALID_NUB_REGNUM, dwarf_stmm2, INVALID_NUB_REGNUM, debugserver_stmm2, NULL, NULL}, - {e_regSetFPU, fpu_stmm3, "stmm3", NULL, Vector, VectorOfUInt8, + {e_regSetFPU, fpu_stmm3, "stmm3", "st3", Vector, VectorOfUInt8, FPU_SIZE_MMST(stmm3), AVX_OFFSET(stmm3), INVALID_NUB_REGNUM, dwarf_stmm3, INVALID_NUB_REGNUM, debugserver_stmm3, NULL, NULL}, - {e_regSetFPU, fpu_stmm4, "stmm4", NULL, Vector, VectorOfUInt8, + {e_regSetFPU, fpu_stmm4, "stmm4", "st4", Vector, VectorOfUInt8, FPU_SIZE_MMST(stmm4), AVX_OFFSET(stmm4), INVALID_NUB_REGNUM, dwarf_stmm4, INVALID_NUB_REGNUM, debugserver_stmm4, NULL, NULL}, - {e_regSetFPU, fpu_stmm5, "stmm5", NULL, Vector, VectorOfUInt8, + {e_regSetFPU, fpu_stmm5, "stmm5", "st5", Vector, VectorOfUInt8, FPU_SIZE_MMST(stmm5), AVX_OFFSET(stmm5), INVALID_NUB_REGNUM, dwarf_stmm5, INVALID_NUB_REGNUM, debugserver_stmm5, NULL, NULL}, - {e_regSetFPU, fpu_stmm6, "stmm6", NULL, Vector, VectorOfUInt8, + {e_regSetFPU, fpu_stmm6, "stmm6", "st6", Vector, VectorOfUInt8, FPU_SIZE_MMST(stmm6), AVX_OFFSET(stmm6), INVALID_NUB_REGNUM, dwarf_stmm6, INVALID_NUB_REGNUM, debugserver_stmm6, NULL, NULL}, - {e_regSetFPU, fpu_stmm7, "stmm7", NULL, Vector, VectorOfUInt8, + {e_regSetFPU, fpu_stmm7, "stmm7", "st7", Vector, VectorOfUInt8, FPU_SIZE_MMST(stmm7), AVX_OFFSET(stmm7), INVALID_NUB_REGNUM, dwarf_stmm7, INVALID_NUB_REGNUM, debugserver_stmm7, NULL, NULL}, diff --git a/gnu/llvm/lldb/tools/debugserver/source/MacOSX/i386/DNBArchImplI386.h b/gnu/llvm/lldb/tools/debugserver/source/MacOSX/i386/DNBArchImplI386.h index 43594e890f5..a702ea52e85 100644 --- a/gnu/llvm/lldb/tools/debugserver/source/MacOSX/i386/DNBArchImplI386.h +++ b/gnu/llvm/lldb/tools/debugserver/source/MacOSX/i386/DNBArchImplI386.h @@ -31,38 +31,38 @@ public: static void Initialize(); - virtual bool GetRegisterValue(uint32_t set, uint32_t reg, - DNBRegisterValue *value); - virtual bool SetRegisterValue(uint32_t set, uint32_t reg, - const DNBRegisterValue *value); - virtual nub_size_t GetRegisterContext(void *buf, nub_size_t buf_len); - virtual nub_size_t SetRegisterContext(const void *buf, nub_size_t buf_len); - virtual uint32_t SaveRegisterState(); - virtual bool RestoreRegisterState(uint32_t save_id); - - virtual kern_return_t GetRegisterState(int set, bool force); - virtual kern_return_t SetRegisterState(int set); - virtual bool RegisterSetStateIsValid(int set) const; - - virtual uint64_t GetPC(uint64_t failValue); // Get program counter - virtual kern_return_t SetPC(uint64_t value); - virtual uint64_t GetSP(uint64_t failValue); // Get stack pointer - virtual void ThreadWillResume(); - virtual bool ThreadDidStop(); - virtual bool NotifyException(MachException::Data &exc); - - virtual uint32_t NumSupportedHardwareBreakpoints(); - virtual uint32_t NumSupportedHardwareWatchpoints(); - virtual uint32_t EnableHardwareBreakpoint(nub_addr_t addr, nub_size_t size, - bool also_set_on_task); - virtual bool DisableHardwareBreakpoint(uint32_t hw_index, - bool also_set_on_task); - virtual uint32_t EnableHardwareWatchpoint(nub_addr_t addr, nub_size_t size, - bool read, bool write, - bool also_set_on_task); - virtual bool DisableHardwareWatchpoint(uint32_t hw_break_index, - bool also_set_on_task); - virtual uint32_t GetHardwareWatchpointHit(nub_addr_t &addr); + bool GetRegisterValue(uint32_t set, uint32_t reg, + DNBRegisterValue *value) override; + bool SetRegisterValue(uint32_t set, uint32_t reg, + const DNBRegisterValue *value) override; + nub_size_t GetRegisterContext(void *buf, nub_size_t buf_len) override; + nub_size_t SetRegisterContext(const void *buf, nub_size_t buf_len) override; + uint32_t SaveRegisterState() override; + bool RestoreRegisterState(uint32_t save_id) override; + + kern_return_t GetRegisterState(int set, bool force) override; + kern_return_t SetRegisterState(int set) override; + bool RegisterSetStateIsValid(int set) const override; + + uint64_t GetPC(uint64_t failValue) override; // Get program counter + kern_return_t SetPC(uint64_t value) override; + uint64_t GetSP(uint64_t failValue) override; // Get stack pointer + void ThreadWillResume() override; + bool ThreadDidStop() override; + bool NotifyException(MachException::Data &exc) override; + + uint32_t NumSupportedHardwareBreakpoints() override; + uint32_t NumSupportedHardwareWatchpoints() override; + uint32_t EnableHardwareBreakpoint(nub_addr_t addr, nub_size_t size, + bool also_set_on_task) override; + bool DisableHardwareBreakpoint(uint32_t hw_index, + bool also_set_on_task) override; + uint32_t EnableHardwareWatchpoint(nub_addr_t addr, nub_size_t size, + bool read, bool write, + bool also_set_on_task) override; + bool DisableHardwareWatchpoint(uint32_t hw_break_index, + bool also_set_on_task) override; + uint32_t GetHardwareWatchpointHit(nub_addr_t &addr) override; protected: kern_return_t EnableHardwareSingleStep(bool enable); @@ -228,9 +228,9 @@ protected: static bool IsWatchpointHit(const DBG &debug_state, uint32_t hw_index); static nub_addr_t GetWatchAddress(const DBG &debug_state, uint32_t hw_index); - virtual bool StartTransForHWP(); - virtual bool RollbackTransForHWP(); - virtual bool FinishTransForHWP(); + bool StartTransForHWP() override; + bool RollbackTransForHWP() override; + bool FinishTransForHWP() override; DBG GetDBGCheckpoint(); MachThread *m_thread; diff --git a/gnu/llvm/lldb/tools/debugserver/source/MacOSX/i386/MachRegisterStatesI386.h b/gnu/llvm/lldb/tools/debugserver/source/MacOSX/i386/MachRegisterStatesI386.h index 8458a283e84..ba76925369c 100644 --- a/gnu/llvm/lldb/tools/debugserver/source/MacOSX/i386/MachRegisterStatesI386.h +++ b/gnu/llvm/lldb/tools/debugserver/source/MacOSX/i386/MachRegisterStatesI386.h @@ -13,7 +13,7 @@ #ifndef LLDB_TOOLS_DEBUGSERVER_SOURCE_MACOSX_I386_MACHREGISTERSTATESI386_H #define LLDB_TOOLS_DEBUGSERVER_SOURCE_MACOSX_I386_MACHREGISTERSTATESI386_H -#include +#include #define __i386_THREAD_STATE 1 #define __i386_FLOAT_STATE 2 diff --git a/gnu/llvm/lldb/tools/debugserver/source/MacOSX/x86_64/DNBArchImplX86_64.cpp b/gnu/llvm/lldb/tools/debugserver/source/MacOSX/x86_64/DNBArchImplX86_64.cpp index 519b6277fd0..7270ecb55cc 100644 --- a/gnu/llvm/lldb/tools/debugserver/source/MacOSX/x86_64/DNBArchImplX86_64.cpp +++ b/gnu/llvm/lldb/tools/debugserver/source/MacOSX/x86_64/DNBArchImplX86_64.cpp @@ -20,8 +20,8 @@ #include "MacOSX/x86_64/DNBArchImplX86_64.h" #include "MachProcess.h" #include "MachThread.h" +#include #include -#include #if defined(LLDB_DEBUGSERVER_RELEASE) || defined(LLDB_DEBUGSERVER_DEBUG) enum debugState { debugStateUnknown, debugStateOff, debugStateOn }; @@ -1767,28 +1767,28 @@ const DNBRegisterInfo DNBArchImplX86_64::g_fpu_registers_no_avx[] = { FPU_SIZE_UINT(mxcsrmask), FPU_OFFSET(mxcsrmask), -1U, -1U, -1U, -1U, NULL, NULL}, - {e_regSetFPU, fpu_stmm0, "stmm0", NULL, Vector, VectorOfUInt8, + {e_regSetFPU, fpu_stmm0, "stmm0", "st0", Vector, VectorOfUInt8, FPU_SIZE_MMST(stmm0), FPU_OFFSET(stmm0), ehframe_dwarf_stmm0, ehframe_dwarf_stmm0, -1U, debugserver_stmm0, NULL, NULL}, - {e_regSetFPU, fpu_stmm1, "stmm1", NULL, Vector, VectorOfUInt8, + {e_regSetFPU, fpu_stmm1, "stmm1", "st1", Vector, VectorOfUInt8, FPU_SIZE_MMST(stmm1), FPU_OFFSET(stmm1), ehframe_dwarf_stmm1, ehframe_dwarf_stmm1, -1U, debugserver_stmm1, NULL, NULL}, - {e_regSetFPU, fpu_stmm2, "stmm2", NULL, Vector, VectorOfUInt8, + {e_regSetFPU, fpu_stmm2, "stmm2", "st2", Vector, VectorOfUInt8, FPU_SIZE_MMST(stmm2), FPU_OFFSET(stmm2), ehframe_dwarf_stmm2, ehframe_dwarf_stmm2, -1U, debugserver_stmm2, NULL, NULL}, - {e_regSetFPU, fpu_stmm3, "stmm3", NULL, Vector, VectorOfUInt8, + {e_regSetFPU, fpu_stmm3, "stmm3", "st3", Vector, VectorOfUInt8, FPU_SIZE_MMST(stmm3), FPU_OFFSET(stmm3), ehframe_dwarf_stmm3, ehframe_dwarf_stmm3, -1U, debugserver_stmm3, NULL, NULL}, - {e_regSetFPU, fpu_stmm4, "stmm4", NULL, Vector, VectorOfUInt8, + {e_regSetFPU, fpu_stmm4, "stmm4", "st4", Vector, VectorOfUInt8, FPU_SIZE_MMST(stmm4), FPU_OFFSET(stmm4), ehframe_dwarf_stmm4, ehframe_dwarf_stmm4, -1U, debugserver_stmm4, NULL, NULL}, - {e_regSetFPU, fpu_stmm5, "stmm5", NULL, Vector, VectorOfUInt8, + {e_regSetFPU, fpu_stmm5, "stmm5", "st5", Vector, VectorOfUInt8, FPU_SIZE_MMST(stmm5), FPU_OFFSET(stmm5), ehframe_dwarf_stmm5, ehframe_dwarf_stmm5, -1U, debugserver_stmm5, NULL, NULL}, - {e_regSetFPU, fpu_stmm6, "stmm6", NULL, Vector, VectorOfUInt8, + {e_regSetFPU, fpu_stmm6, "stmm6", "st6", Vector, VectorOfUInt8, FPU_SIZE_MMST(stmm6), FPU_OFFSET(stmm6), ehframe_dwarf_stmm6, ehframe_dwarf_stmm6, -1U, debugserver_stmm6, NULL, NULL}, - {e_regSetFPU, fpu_stmm7, "stmm7", NULL, Vector, VectorOfUInt8, + {e_regSetFPU, fpu_stmm7, "stmm7", "st7", Vector, VectorOfUInt8, FPU_SIZE_MMST(stmm7), FPU_OFFSET(stmm7), ehframe_dwarf_stmm7, ehframe_dwarf_stmm7, -1U, debugserver_stmm7, NULL, NULL}, @@ -1882,28 +1882,28 @@ const DNBRegisterInfo DNBArchImplX86_64::g_fpu_registers_avx[] = { FPU_SIZE_UINT(mxcsrmask), AVX_OFFSET(mxcsrmask), -1U, -1U, -1U, -1U, NULL, NULL}, - {e_regSetFPU, fpu_stmm0, "stmm0", NULL, Vector, VectorOfUInt8, + {e_regSetFPU, fpu_stmm0, "stmm0", "st0", Vector, VectorOfUInt8, FPU_SIZE_MMST(stmm0), AVX_OFFSET(stmm0), ehframe_dwarf_stmm0, ehframe_dwarf_stmm0, -1U, debugserver_stmm0, NULL, NULL}, - {e_regSetFPU, fpu_stmm1, "stmm1", NULL, Vector, VectorOfUInt8, + {e_regSetFPU, fpu_stmm1, "stmm1", "st1", Vector, VectorOfUInt8, FPU_SIZE_MMST(stmm1), AVX_OFFSET(stmm1), ehframe_dwarf_stmm1, ehframe_dwarf_stmm1, -1U, debugserver_stmm1, NULL, NULL}, - {e_regSetFPU, fpu_stmm2, "stmm2", NULL, Vector, VectorOfUInt8, + {e_regSetFPU, fpu_stmm2, "stmm2", "st2", Vector, VectorOfUInt8, FPU_SIZE_MMST(stmm2), AVX_OFFSET(stmm2), ehframe_dwarf_stmm2, ehframe_dwarf_stmm2, -1U, debugserver_stmm2, NULL, NULL}, - {e_regSetFPU, fpu_stmm3, "stmm3", NULL, Vector, VectorOfUInt8, + {e_regSetFPU, fpu_stmm3, "stmm3", "st3", Vector, VectorOfUInt8, FPU_SIZE_MMST(stmm3), AVX_OFFSET(stmm3), ehframe_dwarf_stmm3, ehframe_dwarf_stmm3, -1U, debugserver_stmm3, NULL, NULL}, - {e_regSetFPU, fpu_stmm4, "stmm4", NULL, Vector, VectorOfUInt8, + {e_regSetFPU, fpu_stmm4, "stmm4", "st4", Vector, VectorOfUInt8, FPU_SIZE_MMST(stmm4), AVX_OFFSET(stmm4), ehframe_dwarf_stmm4, ehframe_dwarf_stmm4, -1U, debugserver_stmm4, NULL, NULL}, - {e_regSetFPU, fpu_stmm5, "stmm5", NULL, Vector, VectorOfUInt8, + {e_regSetFPU, fpu_stmm5, "stmm5", "st5", Vector, VectorOfUInt8, FPU_SIZE_MMST(stmm5), AVX_OFFSET(stmm5), ehframe_dwarf_stmm5, ehframe_dwarf_stmm5, -1U, debugserver_stmm5, NULL, NULL}, - {e_regSetFPU, fpu_stmm6, "stmm6", NULL, Vector, VectorOfUInt8, + {e_regSetFPU, fpu_stmm6, "stmm6", "st6", Vector, VectorOfUInt8, FPU_SIZE_MMST(stmm6), AVX_OFFSET(stmm6), ehframe_dwarf_stmm6, ehframe_dwarf_stmm6, -1U, debugserver_stmm6, NULL, NULL}, - {e_regSetFPU, fpu_stmm7, "stmm7", NULL, Vector, VectorOfUInt8, + {e_regSetFPU, fpu_stmm7, "stmm7", "st7", Vector, VectorOfUInt8, FPU_SIZE_MMST(stmm7), AVX_OFFSET(stmm7), ehframe_dwarf_stmm7, ehframe_dwarf_stmm7, -1U, debugserver_stmm7, NULL, NULL}, @@ -2080,28 +2080,28 @@ const DNBRegisterInfo DNBArchImplX86_64::g_fpu_registers_avx512f[] = { FPU_SIZE_UINT(mxcsrmask), AVX_OFFSET(mxcsrmask), -1U, -1U, -1U, -1U, NULL, NULL}, - {e_regSetFPU, fpu_stmm0, "stmm0", NULL, Vector, VectorOfUInt8, + {e_regSetFPU, fpu_stmm0, "stmm0", "st0", Vector, VectorOfUInt8, FPU_SIZE_MMST(stmm0), AVX_OFFSET(stmm0), ehframe_dwarf_stmm0, ehframe_dwarf_stmm0, -1U, debugserver_stmm0, NULL, NULL}, - {e_regSetFPU, fpu_stmm1, "stmm1", NULL, Vector, VectorOfUInt8, + {e_regSetFPU, fpu_stmm1, "stmm1", "st1", Vector, VectorOfUInt8, FPU_SIZE_MMST(stmm1), AVX_OFFSET(stmm1), ehframe_dwarf_stmm1, ehframe_dwarf_stmm1, -1U, debugserver_stmm1, NULL, NULL}, - {e_regSetFPU, fpu_stmm2, "stmm2", NULL, Vector, VectorOfUInt8, + {e_regSetFPU, fpu_stmm2, "stmm2", "st2", Vector, VectorOfUInt8, FPU_SIZE_MMST(stmm2), AVX_OFFSET(stmm2), ehframe_dwarf_stmm2, ehframe_dwarf_stmm2, -1U, debugserver_stmm2, NULL, NULL}, - {e_regSetFPU, fpu_stmm3, "stmm3", NULL, Vector, VectorOfUInt8, + {e_regSetFPU, fpu_stmm3, "stmm3", "st3", Vector, VectorOfUInt8, FPU_SIZE_MMST(stmm3), AVX_OFFSET(stmm3), ehframe_dwarf_stmm3, ehframe_dwarf_stmm3, -1U, debugserver_stmm3, NULL, NULL}, - {e_regSetFPU, fpu_stmm4, "stmm4", NULL, Vector, VectorOfUInt8, + {e_regSetFPU, fpu_stmm4, "stmm4", "st4", Vector, VectorOfUInt8, FPU_SIZE_MMST(stmm4), AVX_OFFSET(stmm4), ehframe_dwarf_stmm4, ehframe_dwarf_stmm4, -1U, debugserver_stmm4, NULL, NULL}, - {e_regSetFPU, fpu_stmm5, "stmm5", NULL, Vector, VectorOfUInt8, + {e_regSetFPU, fpu_stmm5, "stmm5", "st5", Vector, VectorOfUInt8, FPU_SIZE_MMST(stmm5), AVX_OFFSET(stmm5), ehframe_dwarf_stmm5, ehframe_dwarf_stmm5, -1U, debugserver_stmm5, NULL, NULL}, - {e_regSetFPU, fpu_stmm6, "stmm6", NULL, Vector, VectorOfUInt8, + {e_regSetFPU, fpu_stmm6, "stmm6", "st6", Vector, VectorOfUInt8, FPU_SIZE_MMST(stmm6), AVX_OFFSET(stmm6), ehframe_dwarf_stmm6, ehframe_dwarf_stmm6, -1U, debugserver_stmm6, NULL, NULL}, - {e_regSetFPU, fpu_stmm7, "stmm7", NULL, Vector, VectorOfUInt8, + {e_regSetFPU, fpu_stmm7, "stmm7", "st7", Vector, VectorOfUInt8, FPU_SIZE_MMST(stmm7), AVX_OFFSET(stmm7), ehframe_dwarf_stmm7, ehframe_dwarf_stmm7, -1U, debugserver_stmm7, NULL, NULL}, diff --git a/gnu/llvm/lldb/tools/debugserver/source/MacOSX/x86_64/DNBArchImplX86_64.h b/gnu/llvm/lldb/tools/debugserver/source/MacOSX/x86_64/DNBArchImplX86_64.h index 0ed433f7f3a..96da02a4c9f 100644 --- a/gnu/llvm/lldb/tools/debugserver/source/MacOSX/x86_64/DNBArchImplX86_64.h +++ b/gnu/llvm/lldb/tools/debugserver/source/MacOSX/x86_64/DNBArchImplX86_64.h @@ -30,39 +30,39 @@ public: static void Initialize(); - virtual bool GetRegisterValue(uint32_t set, uint32_t reg, - DNBRegisterValue *value); - virtual bool SetRegisterValue(uint32_t set, uint32_t reg, - const DNBRegisterValue *value); - virtual nub_size_t GetRegisterContext(void *buf, nub_size_t buf_len); - virtual nub_size_t SetRegisterContext(const void *buf, nub_size_t buf_len); - virtual uint32_t SaveRegisterState(); - virtual bool RestoreRegisterState(uint32_t save_id); - - virtual kern_return_t GetRegisterState(int set, bool force); - virtual kern_return_t SetRegisterState(int set); - virtual bool RegisterSetStateIsValid(int set) const; - - virtual uint64_t GetPC(uint64_t failValue); // Get program counter - virtual kern_return_t SetPC(uint64_t value); - virtual uint64_t GetSP(uint64_t failValue); // Get stack pointer - virtual void ThreadWillResume(); - virtual bool ThreadDidStop(); - virtual bool NotifyException(MachException::Data &exc); - - virtual uint32_t NumSupportedHardwareBreakpoints(); - virtual uint32_t NumSupportedHardwareWatchpoints(); - - virtual uint32_t EnableHardwareBreakpoint(nub_addr_t addr, nub_size_t size, - bool also_set_on_task); - virtual bool DisableHardwareBreakpoint(uint32_t hw_break_index, - bool also_set_on_task); - virtual uint32_t EnableHardwareWatchpoint(nub_addr_t addr, nub_size_t size, - bool read, bool write, - bool also_set_on_task); - virtual bool DisableHardwareWatchpoint(uint32_t hw_break_index, - bool also_set_on_task); - virtual uint32_t GetHardwareWatchpointHit(nub_addr_t &addr); + bool GetRegisterValue(uint32_t set, uint32_t reg, + DNBRegisterValue *value) override; + bool SetRegisterValue(uint32_t set, uint32_t reg, + const DNBRegisterValue *value) override; + nub_size_t GetRegisterContext(void *buf, nub_size_t buf_len) override; + nub_size_t SetRegisterContext(const void *buf, nub_size_t buf_len) override; + uint32_t SaveRegisterState() override; + bool RestoreRegisterState(uint32_t save_id) override; + + kern_return_t GetRegisterState(int set, bool force) override; + kern_return_t SetRegisterState(int set) override; + bool RegisterSetStateIsValid(int set) const override; + + uint64_t GetPC(uint64_t failValue) override; // Get program counter + kern_return_t SetPC(uint64_t value) override; + uint64_t GetSP(uint64_t failValue) override; // Get stack pointer + void ThreadWillResume() override; + bool ThreadDidStop() override; + bool NotifyException(MachException::Data &exc) override; + + uint32_t NumSupportedHardwareBreakpoints() override; + uint32_t NumSupportedHardwareWatchpoints() override; + + uint32_t EnableHardwareBreakpoint(nub_addr_t addr, nub_size_t size, + bool also_set_on_task) override; + bool DisableHardwareBreakpoint(uint32_t hw_break_index, + bool also_set_on_task) override; + uint32_t EnableHardwareWatchpoint(nub_addr_t addr, nub_size_t size, + bool read, bool write, + bool also_set_on_task) override; + bool DisableHardwareWatchpoint(uint32_t hw_break_index, + bool also_set_on_task) override; + uint32_t GetHardwareWatchpointHit(nub_addr_t &addr) override; protected: kern_return_t EnableHardwareSingleStep(bool enable); @@ -232,9 +232,9 @@ protected: static bool IsWatchpointHit(const DBG &debug_state, uint32_t hw_index); static nub_addr_t GetWatchAddress(const DBG &debug_state, uint32_t hw_index); - virtual bool StartTransForHWP(); - virtual bool RollbackTransForHWP(); - virtual bool FinishTransForHWP(); + bool StartTransForHWP() override; + bool RollbackTransForHWP() override; + bool FinishTransForHWP() override; DBG GetDBGCheckpoint(); MachThread *m_thread; diff --git a/gnu/llvm/lldb/tools/debugserver/source/MacOSX/x86_64/MachRegisterStatesX86_64.h b/gnu/llvm/lldb/tools/debugserver/source/MacOSX/x86_64/MachRegisterStatesX86_64.h index f53e0a753c3..b566accd397 100644 --- a/gnu/llvm/lldb/tools/debugserver/source/MacOSX/x86_64/MachRegisterStatesX86_64.h +++ b/gnu/llvm/lldb/tools/debugserver/source/MacOSX/x86_64/MachRegisterStatesX86_64.h @@ -14,7 +14,7 @@ #ifndef LLDB_TOOLS_DEBUGSERVER_SOURCE_MACOSX_X86_64_MACHREGISTERSTATESX86_64_H #define LLDB_TOOLS_DEBUGSERVER_SOURCE_MACOSX_X86_64_MACHREGISTERSTATESX86_64_H -#include +#include #define __x86_64_THREAD_STATE 4 #define __x86_64_FLOAT_STATE 5 diff --git a/gnu/llvm/lldb/tools/debugserver/source/PThreadEvent.cpp b/gnu/llvm/lldb/tools/debugserver/source/PThreadEvent.cpp index 82d1d227867..e77c7511ae5 100644 --- a/gnu/llvm/lldb/tools/debugserver/source/PThreadEvent.cpp +++ b/gnu/llvm/lldb/tools/debugserver/source/PThreadEvent.cpp @@ -12,7 +12,7 @@ #include "PThreadEvent.h" #include "DNBLog.h" -#include "errno.h" +#include PThreadEvent::PThreadEvent(uint32_t bits, uint32_t validBits) : m_mutex(), m_set_condition(), m_reset_condition(), m_bits(bits), diff --git a/gnu/llvm/lldb/tools/debugserver/source/PThreadEvent.h b/gnu/llvm/lldb/tools/debugserver/source/PThreadEvent.h index da3d9d47677..20faf82e4ff 100644 --- a/gnu/llvm/lldb/tools/debugserver/source/PThreadEvent.h +++ b/gnu/llvm/lldb/tools/debugserver/source/PThreadEvent.h @@ -14,8 +14,8 @@ #define LLDB_TOOLS_DEBUGSERVER_SOURCE_PTHREADEVENT_H #include "PThreadCondition.h" #include "PThreadMutex.h" -#include -#include +#include +#include class PThreadEvent { public: diff --git a/gnu/llvm/lldb/tools/debugserver/source/PThreadMutex.h b/gnu/llvm/lldb/tools/debugserver/source/PThreadMutex.h index dce2e561b93..a4535dd7917 100644 --- a/gnu/llvm/lldb/tools/debugserver/source/PThreadMutex.h +++ b/gnu/llvm/lldb/tools/debugserver/source/PThreadMutex.h @@ -13,9 +13,9 @@ #ifndef LLDB_TOOLS_DEBUGSERVER_SOURCE_PTHREADMUTEX_H #define LLDB_TOOLS_DEBUGSERVER_SOURCE_PTHREADMUTEX_H -#include +#include +#include #include -#include //#define DEBUG_PTHREAD_MUTEX_DEADLOCKS 1 diff --git a/gnu/llvm/lldb/tools/debugserver/source/PseudoTerminal.cpp b/gnu/llvm/lldb/tools/debugserver/source/PseudoTerminal.cpp index fb91d74a6cc..059b5627668 100644 --- a/gnu/llvm/lldb/tools/debugserver/source/PseudoTerminal.cpp +++ b/gnu/llvm/lldb/tools/debugserver/source/PseudoTerminal.cpp @@ -11,7 +11,7 @@ //===----------------------------------------------------------------------===// #include "PseudoTerminal.h" -#include +#include #include #include diff --git a/gnu/llvm/lldb/tools/debugserver/source/RNBContext.cpp b/gnu/llvm/lldb/tools/debugserver/source/RNBContext.cpp index 3f1a37a1175..0617ef3a67f 100644 --- a/gnu/llvm/lldb/tools/debugserver/source/RNBContext.cpp +++ b/gnu/llvm/lldb/tools/debugserver/source/RNBContext.cpp @@ -258,8 +258,6 @@ const char *RNBContext::EventsAsString(nub_event_t events, std::string &s) { s += "proc_stdio_available "; if (events & event_proc_profile_data) s += "proc_profile_data "; - if (events & event_darwin_log_data_available) - s += "darwin_log_data_available "; if (events & event_read_packet_available) s += "read_packet_available "; if (events & event_read_thread_running) diff --git a/gnu/llvm/lldb/tools/debugserver/source/RNBContext.h b/gnu/llvm/lldb/tools/debugserver/source/RNBContext.h index 7d8f458ce0f..183aa0a3f79 100644 --- a/gnu/llvm/lldb/tools/debugserver/source/RNBContext.h +++ b/gnu/llvm/lldb/tools/debugserver/source/RNBContext.h @@ -30,24 +30,18 @@ public: event_read_packet_available = 0x020, event_read_thread_running = 0x040, // Sticky event_read_thread_exiting = 0x080, - event_darwin_log_data_available = 0x100, normal_event_bits = event_proc_state_changed | event_proc_thread_exiting | event_proc_stdio_available | event_proc_profile_data | event_read_packet_available | - event_read_thread_exiting | - event_darwin_log_data_available, + event_read_thread_exiting , sticky_event_bits = event_proc_thread_running | event_read_thread_running, all_event_bits = sticky_event_bits | normal_event_bits } event_t; // Constructors and Destructors - RNBContext() - : m_pid(INVALID_NUB_PROCESS), m_pid_stop_count(0), - m_events(0, all_event_bits), m_pid_pthread(), m_launch_status(), - m_arg_vec(), m_env_vec(), m_detach_on_error(false) {} - + RNBContext() = default; virtual ~RNBContext(); nub_process_t ProcessID() const { return m_pid; } @@ -124,25 +118,33 @@ public: void SetDetachOnError(bool detach) { m_detach_on_error = detach; } bool GetDetachOnError() { return m_detach_on_error; } + void SetUnmaskSignals(bool unmask_signals) { + m_unmask_signals = unmask_signals; + } + bool GetUnmaskSignals() { return m_unmask_signals; } + protected: // Classes that inherit from RNBContext can see and modify these - nub_process_t m_pid; + nub_process_t m_pid = INVALID_NUB_PROCESS; std::string m_stdin; std::string m_stdout; std::string m_stderr; std::string m_working_dir; - nub_size_t m_pid_stop_count; - PThreadEvent m_events; // Threaded events that we can wait for + nub_size_t m_pid_stop_count = 0; + /// Threaded events that we can wait for. + PThreadEvent m_events{0, all_event_bits}; pthread_t m_pid_pthread; - nub_launch_flavor_t m_launch_flavor; // How to launch our inferior process - DNBError - m_launch_status; // This holds the status from the last launch attempt. + /// How to launch our inferior process. + nub_launch_flavor_t m_launch_flavor = eLaunchFlavorDefault; + /// This holds the status from the last launch attempt. + DNBError m_launch_status; std::vector m_arg_vec; - std::vector - m_env_vec; // This will be unparsed - entries FOO=value + /// This will be unparsed entries FOO=value + std::vector m_env_vec; std::string m_working_directory; std::string m_process_event; - bool m_detach_on_error; + bool m_detach_on_error = false; + bool m_unmask_signals = false; void StartProcessStatusThread(); void StopProcessStatusThread(); diff --git a/gnu/llvm/lldb/tools/debugserver/source/RNBRemote.cpp b/gnu/llvm/lldb/tools/debugserver/source/RNBRemote.cpp index 8a3045564aa..b28b6f344b7 100644 --- a/gnu/llvm/lldb/tools/debugserver/source/RNBRemote.cpp +++ b/gnu/llvm/lldb/tools/debugserver/source/RNBRemote.cpp @@ -14,13 +14,14 @@ #include #include -#include +#include +#include #include #include #include +#include #include #include -#include #include #include #include @@ -34,8 +35,6 @@ #include "DNBDataRef.h" #include "DNBLog.h" #include "DNBThreadResumeActions.h" -#include "DarwinLogCollector.h" -#include "DarwinLogEvent.h" #include "JSON.h" #include "JSONGenerator.h" #include "JSONGenerator.h" @@ -61,8 +60,6 @@ static const std::string OS_LOG_EVENTS_KEY_NAME("events"); static const std::string JSON_ASYNC_TYPE_KEY_NAME("type"); -static const DarwinLogEventVector::size_type DARWIN_LOG_MAX_EVENTS_PER_PACKET = - 10; // std::iostream formatting macros #define RAW_HEXBASE std::setfill('0') << std::hex << std::right @@ -148,8 +145,6 @@ uint64_t decode_uint64(const char *p, int base, char **end = nullptr, extern void ASLLogCallback(void *baton, uint32_t flags, const char *format, va_list args); -#if defined(__APPLE__) && \ - (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 101000) // from System.framework/Versions/B/PrivateHeaders/sys/codesign.h extern "C" { #define CS_OPS_STATUS 0 /* return status */ @@ -164,7 +159,6 @@ typedef uint32_t csr_config_t; #define CSR_ALLOW_TASK_FOR_PID (1 << 2) int csr_check(csr_config_t mask); } -#endif RNBRemote::RNBRemote() : m_ctx(), m_comm(), m_arch(), m_continue_thread(-1), m_thread(-1), @@ -501,15 +495,6 @@ void RNBRemote::CreatePacketTable() { "Test the maximum speed at which packet can be sent/received.")); t.push_back(Packet(query_transfer, &RNBRemote::HandlePacket_qXfer, NULL, "qXfer:", "Support the qXfer packet.")); - t.push_back( - Packet(query_supported_async_json_packets, - &RNBRemote::HandlePacket_qStructuredDataPlugins, NULL, - "qStructuredDataPlugins", - "Query for the structured data plugins supported by the remote.")); - t.push_back( - Packet(configure_darwin_log, &RNBRemote::HandlePacket_QConfigureDarwinLog, - NULL, "QConfigureDarwinLog:", - "Configure the DarwinLog structured data plugin support.")); } void RNBRemote::FlushSTDIO() { @@ -547,77 +532,6 @@ void RNBRemote::SendAsyncProfileData() { } } -void RNBRemote::SendAsyncDarwinLogData() { - DNBLogThreadedIf(LOG_DARWIN_LOG, "RNBRemote::%s(): enter", __FUNCTION__); - - if (!m_ctx.HasValidProcessID()) { - DNBLogThreadedIf(LOG_DARWIN_LOG, "RNBRemote::%s(): ignoring due to" - "invalid process id", - __FUNCTION__); - return; - } - - nub_process_t pid = m_ctx.ProcessID(); - DarwinLogEventVector::size_type entry_count = 0; - - // NOTE: the current looping structure here does nothing - // to guarantee that we can send off async packets faster - // than we generate them. It will keep sending as long - // as there's data to send. - do { - DarwinLogEventVector events = DNBProcessGetAvailableDarwinLogEvents(pid); - entry_count = events.size(); - - DNBLogThreadedIf(LOG_DARWIN_LOG, "RNBRemote::%s(): outer loop enter", - __FUNCTION__); - - for (DarwinLogEventVector::size_type base_entry = 0; - base_entry < entry_count; - base_entry += DARWIN_LOG_MAX_EVENTS_PER_PACKET) { - DNBLogThreadedIf(LOG_DARWIN_LOG, "RNBRemote::%s(): inner loop enter", - __FUNCTION__); - - // We limit the total number of entries we pack - // into a single JSON async packet just so it - // doesn't get too large. - JSONGenerator::Dictionary async_dictionary; - - // Specify the type of the JSON async data we're sending. - async_dictionary.AddStringItem(JSON_ASYNC_TYPE_KEY_NAME, "DarwinLog"); - - // Create an array entry in the dictionary to hold all - // the events going in this packet. - JSONGenerator::ArraySP events_array(new JSONGenerator::Array()); - async_dictionary.AddItem(OS_LOG_EVENTS_KEY_NAME, events_array); - - // We bundle up to DARWIN_LOG_MAX_EVENTS_PER_PACKET events in - // a single packet. - const auto inner_loop_bound = - std::min(base_entry + DARWIN_LOG_MAX_EVENTS_PER_PACKET, entry_count); - for (DarwinLogEventVector::size_type i = base_entry; i < inner_loop_bound; - ++i) { - DNBLogThreadedIf(LOG_DARWIN_LOG, "RNBRemote::%s(): adding " - "entry index %lu to the JSON packet", - __FUNCTION__, i); - events_array->AddItem(events[i]); - } - - // Send off the packet. - DNBLogThreadedIf(LOG_DARWIN_LOG, "RNBRemote::%s(): sending JSON " - "packet, %lu entries remain", - __FUNCTION__, entry_count - inner_loop_bound); - SendAsyncJSONPacket(async_dictionary); - } - - DNBLogThreadedIf(LOG_DARWIN_LOG, "RNBRemote::%s(): outer loop exit", - __FUNCTION__); - - } while (entry_count > 0); - - DNBLogThreadedIf(LOG_DARWIN_LOG, "RNBRemote::%s(): exit", - __PRETTY_FUNCTION__); -} - rnb_err_t RNBRemote::SendHexEncodedBytePacket(const char *header, const void *buf, size_t buf_len, const char *footer) { @@ -1216,6 +1130,7 @@ void RNBRemote::StopReadRemoteDataThread() { PThreadEvent &events = m_ctx.Events(); if ((events.GetEventBits() & RNBContext::event_read_thread_running) == RNBContext::event_read_thread_running) { + DNBLog("debugserver about to shut down packet communications to lldb."); m_comm.Disconnect(true); struct timespec timeout_abstime; DNBTimer::OffsetTimeOfDay(&timeout_abstime, 2, 0); @@ -2437,89 +2352,6 @@ rnb_err_t RNBRemote::HandlePacket_QSetDetachOnError(const char *p) { return SendPacket("OK"); } -rnb_err_t RNBRemote::HandlePacket_qStructuredDataPlugins(const char *p) { - // We'll return a JSON array of supported packet types. - // The type is significant. For each of the supported - // packet types that have been enabled, there will be a - // 'J' async packet sent to the client with payload data. - // This payload data will be a JSON dictionary, and the - // top level dictionary will contain a string field with - // its value set to the relevant packet type from this list. - JSONGenerator::Array supported_json_packets; - - // Check for DarwinLog (libtrace os_log/activity support). - if (DarwinLogCollector::IsSupported()) - supported_json_packets.AddItem( - JSONGenerator::StringSP(new JSONGenerator::String("DarwinLog"))); - - // Send back the array. - std::ostringstream stream; - supported_json_packets.Dump(stream); - return SendPacket(stream.str()); -} - -rnb_err_t RNBRemote::HandlePacket_QConfigureDarwinLog(const char *p) { - if (!DarwinLogCollector::IsSupported()) { - // We should never have been given this request. - return SendPacket("E89"); - } - - // Ensure we have a process. We expect a separate configure request for - // each process launched/attached. - const nub_process_t pid = m_ctx.ProcessID(); - if (pid == INVALID_NUB_PROCESS) - return SendPacket("E94"); - - // Get the configuration dictionary. - p += strlen("QConfigureDarwinLog:"); - - // The configuration dictionary is binary encoded. - std::vector unescaped_config_data = decode_binary_data(p, -1); - std::string unescaped_config_string((const char *)&unescaped_config_data[0], - unescaped_config_data.size()); - DNBLogThreadedIf(LOG_DARWIN_LOG, "DarwinLog: received config data: \"%s\"", - unescaped_config_string.c_str()); - auto configuration_sp = - JSONParser(unescaped_config_string.c_str()).ParseJSONValue(); - if (!configuration_sp) { - // Malformed request - we require configuration data - // indicating whether we're enabling or disabling. - return SendPacket("E90"); - } - - if (!JSONObject::classof(configuration_sp.get())) { - // Configuration data is not of the right type. - return SendPacket("E91"); - } - JSONObject &config_dict = *static_cast(configuration_sp.get()); - - // Check if we're enabling or disabling. - auto enabled_sp = config_dict.GetObject("enabled"); - if (!enabled_sp) { - // Missing required "enabled" field. - return SendPacket("E92"); - } - if (!JSONTrue::classof(enabled_sp.get()) && - !JSONFalse::classof(enabled_sp.get())) { - // Should be a boolean type, but wasn't. - return SendPacket("E93"); - } - const bool enabling = JSONTrue::classof(enabled_sp.get()); - - // TODO - handle other configuration parameters here. - - // Shut down any active activity stream for the process. - DarwinLogCollector::CancelStreamForProcess(pid); - - if (enabling) { - // Look up the procecess. - if (!DarwinLogCollector::StartCollectingForProcess(pid, config_dict)) - return SendPacket("E95"); - } - - return SendPacket("OK"); -} - rnb_err_t RNBRemote::HandlePacket_QListThreadsInStopReply(const char *p) { // If this packet is received, it allows us to send an extra key/value // pair in the stop reply packets where we will list all of the thread IDs @@ -3066,7 +2898,7 @@ rnb_err_t RNBRemote::HandlePacket_last_signal(const char *unused) { WEXITSTATUS(pid_status)); else if (WIFSIGNALED(pid_status)) snprintf(pid_exited_packet, sizeof(pid_exited_packet), "X%02x", - WEXITSTATUS(pid_status)); + WTERMSIG(pid_status)); else if (WIFSTOPPED(pid_status)) snprintf(pid_exited_packet, sizeof(pid_exited_packet), "S%02x", WSTOPSIG(pid_status)); @@ -3919,16 +3751,29 @@ rnb_err_t RNBRemote::HandlePacket_v(const char *p) { char err_str[1024] = {'\0'}; std::string attach_name; + if (DNBDebugserverIsTranslated()) { + DNBLogError("debugserver is x86_64 binary running in translation, attach " + "failed."); + std::string return_message = "E96;"; + return_message += + cstring_to_asciihex_string("debugserver is x86_64 binary running in " + "translation, attached failed."); + SendPacket(return_message.c_str()); + return rnb_err; + } + if (strstr(p, "vAttachWait;") == p) { p += strlen("vAttachWait;"); if (!GetProcessNameFrom_vAttach(p, attach_name)) { return HandlePacket_ILLFORMED( __FILE__, __LINE__, p, "non-hex char in arg on 'vAttachWait' pkt"); } + DNBLog("[LaunchAttach] START %d vAttachWait for process name '%s'", + getpid(), attach_name.c_str()); const bool ignore_existing = true; attach_pid = DNBProcessAttachWait( - attach_name.c_str(), m_ctx.LaunchFlavor(), ignore_existing, NULL, - 1000, err_str, sizeof(err_str), RNBRemoteShouldCancelCallback); + &m_ctx, attach_name.c_str(), ignore_existing, NULL, 1000, err_str, + sizeof(err_str), RNBRemoteShouldCancelCallback); } else if (strstr(p, "vAttachOrWait;") == p) { p += strlen("vAttachOrWait;"); @@ -3938,9 +3783,12 @@ rnb_err_t RNBRemote::HandlePacket_v(const char *p) { "non-hex char in arg on 'vAttachOrWait' pkt"); } const bool ignore_existing = false; + DNBLog("[LaunchAttach] START %d vAttachWaitOrWait for process name " + "'%s'", + getpid(), attach_name.c_str()); attach_pid = DNBProcessAttachWait( - attach_name.c_str(), m_ctx.LaunchFlavor(), ignore_existing, NULL, - 1000, err_str, sizeof(err_str), RNBRemoteShouldCancelCallback); + &m_ctx, attach_name.c_str(), ignore_existing, NULL, 1000, err_str, + sizeof(err_str), RNBRemoteShouldCancelCallback); } else if (strstr(p, "vAttachName;") == p) { p += strlen("vAttachName;"); if (!GetProcessNameFrom_vAttach(p, attach_name)) { @@ -3948,7 +3796,11 @@ rnb_err_t RNBRemote::HandlePacket_v(const char *p) { __FILE__, __LINE__, p, "non-hex char in arg on 'vAttachName' pkt"); } - attach_pid = DNBProcessAttachByName(attach_name.c_str(), NULL, err_str, + DNBLog("[LaunchAttach] START %d vAttachName attach to process name " + "'%s'", + getpid(), attach_name.c_str()); + attach_pid = DNBProcessAttachByName(attach_name.c_str(), NULL, + Context().GetUnmaskSignals(), err_str, sizeof(err_str)); } else if (strstr(p, "vAttach;") == p) { @@ -3960,8 +3812,10 @@ rnb_err_t RNBRemote::HandlePacket_v(const char *p) { // Wait at most 30 second for attach struct timespec attach_timeout_abstime; DNBTimer::OffsetTimeOfDay(&attach_timeout_abstime, 30, 0); + DNBLog("[LaunchAttach] START %d vAttach to pid %d", getpid(), + pid_attaching_to); attach_pid = DNBProcessAttach(pid_attaching_to, &attach_timeout_abstime, - err_str, sizeof(err_str)); + false, err_str, sizeof(err_str)); } } else { return HandlePacket_UNIMPLEMENTED(p); @@ -3970,10 +3824,12 @@ rnb_err_t RNBRemote::HandlePacket_v(const char *p) { if (attach_pid != INVALID_NUB_PROCESS) { if (m_ctx.ProcessID() != attach_pid) m_ctx.SetProcessID(attach_pid); + DNBLog("Successfully attached to pid %d", attach_pid); // Send a stop reply packet to indicate we successfully attached! NotifyThatProcessStopped(); return rnb_success; } else { + DNBLogError("Attach failed"); m_ctx.LaunchStatus().SetError(-1, DNBError::Generic); if (err_str[0]) m_ctx.LaunchStatus().SetErrorString(err_str); @@ -4052,8 +3908,8 @@ rnb_err_t RNBRemote::HandlePacket_v(const char *p) { if (strcmp (err_str, "unable to start the exception thread") == 0) { snprintf (err_str, sizeof (err_str) - 1, "Not allowed to attach to process. Look in the console " - "messages (Console.app), near the debugserver entries " - "when the attached failed. The subsystem that denied " + "messages (Console.app), near the debugserver entries, " + "when the attach failed. The subsystem that denied " "the attach permission will likely have logged an " "informative message about why it was denied."); err_str[sizeof (err_str) - 1] = '\0'; @@ -4422,7 +4278,7 @@ rnb_err_t RNBRemote::HandlePacket_MemoryRegionInfo(const char *p) { __FILE__, __LINE__, p, "Invalid address in qMemoryRegionInfo packet"); } - DNBRegionInfo region_info = {0, 0, 0}; + DNBRegionInfo region_info; DNBProcessMemoryRegionInfo(m_ctx.ProcessID(), address, ®ion_info); std::ostringstream ostrm; @@ -4442,6 +4298,18 @@ rnb_err_t RNBRemote::HandlePacket_MemoryRegionInfo(const char *p) { if (region_info.permissions & eMemoryPermissionsExecutable) ostrm << 'x'; ostrm << ';'; + + ostrm << "dirty-pages:"; + if (region_info.dirty_pages.size() > 0) { + bool first = true; + for (nub_addr_t addr : region_info.dirty_pages) { + if (!first) + ostrm << ","; + first = false; + ostrm << "0x" << std::hex << addr; + } + } + ostrm << ";"; } return SendPacket(ostrm.str()); } @@ -4564,7 +4432,8 @@ rnb_err_t RNBRemote::HandlePacket_qSpeedTest(const char *p) { __FILE__, __LINE__, p, "Didn't find response_size value at right offset"); else if (*end == ';') { - static char g_data[4 * 1024 * 1024 + 16] = "data:"; + static char g_data[4 * 1024 * 1024 + 16]; + strcpy(g_data, "data:"); memset(g_data + 5, 'a', response_size); g_data[response_size + 5] = '\0'; return SendPacket(g_data); @@ -4644,10 +4513,14 @@ rnb_err_t RNBRemote::HandlePacket_C(const char *p) { // Detach from gdb. rnb_err_t RNBRemote::HandlePacket_D(const char *p) { if (m_ctx.HasValidProcessID()) { + DNBLog("detaching from pid %u due to D packet", m_ctx.ProcessID()); if (DNBProcessDetach(m_ctx.ProcessID())) SendPacket("OK"); - else + else { + DNBLog("error while detaching from pid %u due to D packet", + m_ctx.ProcessID()); SendPacket("E"); + } } else { SendPacket("E"); } @@ -4963,6 +4836,8 @@ rnb_err_t RNBRemote::HandlePacket_qHostInfo(const char *p) { strm << "default_packet_timeout:10;"; #endif + strm << "vm-page-size:" << std::dec << vm_page_size << ";"; + return SendPacket(strm.str()); } @@ -6356,10 +6231,11 @@ rnb_err_t RNBRemote::HandlePacket_qProcessInfo(const char *p) { DNBProcessMemoryRead(pid, load_command_addr, sizeof(lc), &lc); (void)bytes_read; + bool is_executable = true; uint32_t major_version, minor_version, patch_version; - auto *platform = DNBGetDeploymentInfo(pid, lc, load_command_addr, - major_version, minor_version, - patch_version); + auto *platform = + DNBGetDeploymentInfo(pid, is_executable, lc, load_command_addr, + major_version, minor_version, patch_version); if (platform) { os_handled = true; rep << "ostype:" << platform << ";"; diff --git a/gnu/llvm/lldb/tools/debugserver/source/RNBRemote.h b/gnu/llvm/lldb/tools/debugserver/source/RNBRemote.h index b0535372a32..527b2a7ab60 100644 --- a/gnu/llvm/lldb/tools/debugserver/source/RNBRemote.h +++ b/gnu/llvm/lldb/tools/debugserver/source/RNBRemote.h @@ -135,8 +135,6 @@ public: speed_test, // 'qSpeedTest:' set_detach_on_error, // 'QSetDetachOnError:' query_transfer, // 'qXfer:' - query_supported_async_json_packets, // 'QSupportedAsyncJSONPackets' - configure_darwin_log, // 'ConfigureDarwinLog:' unknown_type }; @@ -246,9 +244,6 @@ public: rnb_err_t HandlePacket_qXfer(const char *p); rnb_err_t HandlePacket_stop_process(const char *p); rnb_err_t HandlePacket_QSetDetachOnError(const char *p); - rnb_err_t HandlePacket_qStructuredDataPlugins(const char *p); - rnb_err_t HandlePacket_QConfigureDarwinLog(const char *p); - rnb_err_t SendStopReplyPacketForThread(nub_thread_t tid); rnb_err_t SendHexEncodedBytePacket(const char *header, const void *buf, size_t buf_len, const char *footer); @@ -257,7 +252,6 @@ public: void FlushSTDIO(); void SendAsyncProfileData(); rnb_err_t SendAsyncProfileDataPacket(char *buf, nub_size_t buf_size); - void SendAsyncDarwinLogData(); rnb_err_t SendAsyncJSONPacket(const JSONGenerator::Dictionary &dictionary); RNBContext &Context() { return m_ctx; } diff --git a/gnu/llvm/lldb/tools/debugserver/source/RNBSocket.cpp b/gnu/llvm/lldb/tools/debugserver/source/RNBSocket.cpp index 80b55b5de3b..1282ea22162 100644 --- a/gnu/llvm/lldb/tools/debugserver/source/RNBSocket.cpp +++ b/gnu/llvm/lldb/tools/debugserver/source/RNBSocket.cpp @@ -14,7 +14,7 @@ #include "DNBError.h" #include "DNBLog.h" #include -#include +#include #include #include #include @@ -30,38 +30,6 @@ #include "lockdown.h" #endif -/* Once we have a RNBSocket object with a port # specified, - this function is called to wait for an incoming connection. - This function blocks while waiting for that connection. */ - -bool ResolveIPV4HostName(const char *hostname, in_addr_t &addr) { - if (hostname == NULL || hostname[0] == '\0' || - strcmp(hostname, "localhost") == 0 || - strcmp(hostname, "127.0.0.1") == 0) { - addr = htonl(INADDR_LOOPBACK); - return true; - } else if (strcmp(hostname, "*") == 0) { - addr = htonl(INADDR_ANY); - return true; - } else { - // See if an IP address was specified as numbers - int inet_pton_result = ::inet_pton(AF_INET, hostname, &addr); - - if (inet_pton_result == 1) - return true; - - struct hostent *host_entry = gethostbyname(hostname); - if (host_entry) { - std::string ip_str( - ::inet_ntoa(*(struct in_addr *)*host_entry->h_addr_list)); - inet_pton_result = ::inet_pton(AF_INET, ip_str.c_str(), &addr); - if (inet_pton_result == 1) - return true; - } - } - return false; -} - rnb_err_t RNBSocket::Listen(const char *listen_host, uint16_t port, PortBoundCallback callback, const void *callback_baton) { diff --git a/gnu/llvm/lldb/tools/debugserver/source/StdStringExtractor.cpp b/gnu/llvm/lldb/tools/debugserver/source/StdStringExtractor.cpp index a4cad2d4bbf..2035394bba1 100644 --- a/gnu/llvm/lldb/tools/debugserver/source/StdStringExtractor.cpp +++ b/gnu/llvm/lldb/tools/debugserver/source/StdStringExtractor.cpp @@ -8,8 +8,7 @@ #include "StdStringExtractor.h" -#include - +#include static inline int xdigit_to_sint(char ch) { if (ch >= 'a' && ch <= 'f') diff --git a/gnu/llvm/lldb/tools/debugserver/source/StdStringExtractor.h b/gnu/llvm/lldb/tools/debugserver/source/StdStringExtractor.h index 88544dc6638..c9ffeefc95b 100644 --- a/gnu/llvm/lldb/tools/debugserver/source/StdStringExtractor.h +++ b/gnu/llvm/lldb/tools/debugserver/source/StdStringExtractor.h @@ -9,7 +9,7 @@ #ifndef LLDB_TOOLS_DEBUGSERVER_SOURCE_STDSTRINGEXTRACTOR_H #define LLDB_TOOLS_DEBUGSERVER_SOURCE_STDSTRINGEXTRACTOR_H -#include +#include #include diff --git a/gnu/llvm/lldb/tools/debugserver/source/SysSignal.cpp b/gnu/llvm/lldb/tools/debugserver/source/SysSignal.cpp index 9afbbec0987..da41cae8e9b 100644 --- a/gnu/llvm/lldb/tools/debugserver/source/SysSignal.cpp +++ b/gnu/llvm/lldb/tools/debugserver/source/SysSignal.cpp @@ -11,8 +11,8 @@ //===----------------------------------------------------------------------===// #include "SysSignal.h" -#include -#include +#include +#include const char *SysSignal::Name(int signal) { switch (signal) { diff --git a/gnu/llvm/lldb/tools/debugserver/source/TTYState.h b/gnu/llvm/lldb/tools/debugserver/source/TTYState.h index ac70417c3a2..8229a7cd573 100644 --- a/gnu/llvm/lldb/tools/debugserver/source/TTYState.h +++ b/gnu/llvm/lldb/tools/debugserver/source/TTYState.h @@ -13,7 +13,7 @@ #ifndef LLDB_TOOLS_DEBUGSERVER_SOURCE_TTYSTATE_H #define LLDB_TOOLS_DEBUGSERVER_SOURCE_TTYSTATE_H -#include +#include #include class TTYState { diff --git a/gnu/llvm/lldb/tools/debugserver/source/debugserver.cpp b/gnu/llvm/lldb/tools/debugserver/source/debugserver.cpp index 42205dedf4b..87198717d69 100644 --- a/gnu/llvm/lldb/tools/debugserver/source/debugserver.cpp +++ b/gnu/llvm/lldb/tools/debugserver/source/debugserver.cpp @@ -8,8 +8,8 @@ #include #include +#include #include -#include #include #include #include @@ -156,6 +156,38 @@ RNBRunLoopMode RNBRunLoopGetStartModeFromRemote(RNBRemote *remote) { return eRNBRunLoopModeExit; } +static nub_launch_flavor_t default_launch_flavor(const char *app_name) { +#if defined(WITH_FBS) || defined(WITH_BKS) || defined(WITH_SPRINGBOARD) + // Check the name to see if it ends with .app + auto is_dot_app = [](const char *app_name) { + size_t len = strlen(app_name); + if (len < 4) + return false; + + if (app_name[len - 4] == '.' && app_name[len - 3] == 'a' && + app_name[len - 2] == 'p' && app_name[len - 1] == 'p') + return true; + return false; + }; + + if (is_dot_app(app_name)) { +#if defined WITH_FBS + // Check if we have an app bundle, if so launch using FrontBoard Services. + return eLaunchFlavorFBS; +#elif defined WITH_BKS + // Check if we have an app bundle, if so launch using BackBoard Services. + return eLaunchFlavorBKS; +#elif defined WITH_SPRINGBOARD + // Check if we have an app bundle, if so launch using SpringBoard. + return eLaunchFlavorSpringBoard; +#endif + } +#endif + + // Our default launch method is posix spawn + return eLaunchFlavorPosixSpawn; +} + // This run loop mode will wait for the process to launch and hit its // entry point. It will currently ignore all events except for the // process state changed event, where it watches for the process stopped @@ -194,27 +226,8 @@ RNBRunLoopMode RNBRunLoopLaunchInferior(RNBRemote *remote, // figure our how we are going to launch automatically. nub_launch_flavor_t launch_flavor = g_launch_flavor; - if (launch_flavor == eLaunchFlavorDefault) { - // Our default launch method is posix spawn - launch_flavor = eLaunchFlavorPosixSpawn; - -#if defined WITH_FBS - // Check if we have an app bundle, if so launch using BackBoard Services. - if (strstr(inferior_argv[0], ".app")) { - launch_flavor = eLaunchFlavorFBS; - } -#elif defined WITH_BKS - // Check if we have an app bundle, if so launch using BackBoard Services. - if (strstr(inferior_argv[0], ".app")) { - launch_flavor = eLaunchFlavorBKS; - } -#elif defined WITH_SPRINGBOARD - // Check if we have an app bundle, if so launch using SpringBoard. - if (strstr(inferior_argv[0], ".app")) { - launch_flavor = eLaunchFlavorSpringBoard; - } -#endif - } + if (launch_flavor == eLaunchFlavorDefault) + launch_flavor = default_launch_flavor(inferior_argv[0]); ctx.SetLaunchFlavor(launch_flavor); char resolved_path[PATH_MAX]; @@ -232,8 +245,8 @@ RNBRunLoopMode RNBRunLoopLaunchInferior(RNBRemote *remote, : ctx.GetWorkingDirectory()); const char *process_event = ctx.GetProcessEvent(); nub_process_t pid = DNBProcessLaunch( - resolved_path, &inferior_argv[0], &inferior_envp[0], cwd, stdin_path, - stdout_path, stderr_path, no_stdio, launch_flavor, g_disable_aslr, + &ctx, resolved_path, &inferior_argv[0], &inferior_envp[0], cwd, + stdin_path, stdout_path, stderr_path, no_stdio, g_disable_aslr, process_event, launch_err_str, sizeof(launch_err_str)); g_pid = pid; @@ -355,7 +368,8 @@ RNBRunLoopMode RNBRunLoopLaunchAttaching(RNBRemote *remote, DNBLogThreadedIf(LOG_RNB_MINIMAL, "%s Attaching to pid %i...", __FUNCTION__, attach_pid); char err_str[1024]; - pid = DNBProcessAttach(attach_pid, NULL, err_str, sizeof(err_str)); + pid = DNBProcessAttach(attach_pid, NULL, ctx.GetUnmaskSignals(), err_str, + sizeof(err_str)); g_pid = pid; if (pid == INVALID_NUB_PROCESS) { @@ -512,10 +526,6 @@ RNBRunLoopMode RNBRunLoopInferiorExecuting(RNBRemote *remote) { // packets event_mask &= ~RNBContext::event_proc_stdio_available; event_mask &= ~RNBContext::event_proc_profile_data; - // When we enable async structured data packets over another logical - // channel, - // this can be relaxed. - event_mask &= ~RNBContext::event_darwin_log_data_available; } // We want to make sure we consume all process state changes and have @@ -542,10 +552,6 @@ RNBRunLoopMode RNBRunLoopInferiorExecuting(RNBRemote *remote) { remote->SendAsyncProfileData(); } - if (set_events & RNBContext::event_darwin_log_data_available) { - remote->SendAsyncDarwinLogData(); - } - if (set_events & RNBContext::event_read_packet_available) { // handleReceivedPacket will take care of resetting the // event_read_packet_available events when there are no more... @@ -569,29 +575,34 @@ RNBRunLoopMode RNBRunLoopInferiorExecuting(RNBRemote *remote) { } if (set_events & RNBContext::event_proc_thread_exiting) { + DNBLog("debugserver's process monitoring thread has exited."); mode = eRNBRunLoopModeExit; } if (set_events & RNBContext::event_read_thread_exiting) { // Out remote packet receiving thread exited, exit for now. + DNBLog( + "debugserver's packet communication to lldb has been shut down."); if (ctx.HasValidProcessID()) { + nub_process_t pid = ctx.ProcessID(); // TODO: We should add code that will leave the current process // in its current state and listen for another connection... if (ctx.ProcessStateRunning()) { if (ctx.GetDetachOnError()) { - DNBLog("debugserver's event read thread is exiting, detaching " - "from the inferior process."); - DNBProcessDetach(ctx.ProcessID()); + DNBLog("debugserver has a valid PID %d, it is still running. " + "detaching from the inferior process.", + pid); + DNBProcessDetach(pid); } else { - DNBLog("debugserver's event read thread is exiting, killing the " - "inferior process."); - DNBProcessKill(ctx.ProcessID()); + DNBLog("debugserver killing the inferior process, pid %d.", pid); + DNBProcessKill(pid); } } else { if (ctx.GetDetachOnError()) { - DNBLog("debugserver's event read thread is exiting, detaching " - "from the inferior process."); - DNBProcessDetach(ctx.ProcessID()); + DNBLog("debugserver has a valid PID %d but it may no longer " + "be running, detaching from the inferior process.", + pid); + DNBProcessDetach(pid); } } } @@ -790,8 +801,11 @@ void FileLogCallback(void *baton, uint32_t flags, const char *format, } void show_version_and_exit(int exit_code) { - printf("%s-%s for %s.\n", DEBUGSERVER_PROGRAM_NAME, DEBUGSERVER_VERSION_STR, - RNB_ARCH); + const char *in_translation = ""; + if (DNBDebugserverIsTranslated()) + in_translation = " (running under translation)"; + printf("%s-%s for %s%s.\n", DEBUGSERVER_PROGRAM_NAME, DEBUGSERVER_VERSION_STR, + RNB_ARCH, in_translation); exit(exit_code); } @@ -876,8 +890,14 @@ static struct option g_long_options[] = { 'F'}, // When debugserver launches the process, forward debugserver's // current environment variables to the child process ("./debugserver // -F localhost:1234 -- /bin/ls" + {"unmask-signals", no_argument, NULL, + 'U'}, // debugserver will ignore EXC_MASK_BAD_ACCESS, + // EXC_MASK_BAD_INSTRUCTION and EXC_MASK_ARITHMETIC, which results in + // SIGSEGV, SIGILL and SIGFPE being propagated to the target process. {NULL, 0, NULL, 0}}; +int communication_fd = -1; + // main int main(int argc, char *argv[]) { // If debugserver is launched with DYLD_INSERT_LIBRARIES, unset it so we @@ -944,7 +964,6 @@ int main(int argc, char *argv[]) { int ch; int long_option_index = 0; int debug = 0; - int communication_fd = -1; std::string compile_options; std::string waitfor_pid_name; // Wait for a process that starts with this name std::string attach_pid_name; @@ -1085,21 +1104,30 @@ int main(int argc, char *argv[]) { if (optarg && optarg[0]) { if (strcasecmp(optarg, "auto") == 0) g_launch_flavor = eLaunchFlavorDefault; - else if (strcasestr(optarg, "posix") == optarg) + else if (strcasestr(optarg, "posix") == optarg) { + DNBLog( + "[LaunchAttach] launch flavor is posix_spawn via cmdline option"); g_launch_flavor = eLaunchFlavorPosixSpawn; - else if (strcasestr(optarg, "fork") == optarg) + } else if (strcasestr(optarg, "fork") == optarg) g_launch_flavor = eLaunchFlavorForkExec; #ifdef WITH_SPRINGBOARD - else if (strcasestr(optarg, "spring") == optarg) + else if (strcasestr(optarg, "spring") == optarg) { + DNBLog( + "[LaunchAttach] launch flavor is SpringBoard via cmdline option"); g_launch_flavor = eLaunchFlavorSpringBoard; + } #endif #ifdef WITH_BKS - else if (strcasestr(optarg, "backboard") == optarg) + else if (strcasestr(optarg, "backboard") == optarg) { + DNBLog("[LaunchAttach] launch flavor is BKS via cmdline option"); g_launch_flavor = eLaunchFlavorBKS; + } #endif #ifdef WITH_FBS - else if (strcasestr(optarg, "frontboard") == optarg) + else if (strcasestr(optarg, "frontboard") == optarg) { + DNBLog("[LaunchAttach] launch flavor is FBS via cmdline option"); g_launch_flavor = eLaunchFlavorFBS; + } #endif else { @@ -1246,6 +1274,10 @@ int main(int argc, char *argv[]) { forward_env = true; break; + case 'U': + ctx.SetUnmaskSignals(true); + break; + case '2': // File descriptor passed to this process during fork/exec and is already // open and ready for communication. @@ -1316,8 +1348,12 @@ int main(int argc, char *argv[]) { // as long as we're dropping remotenub in as a replacement for gdbserver, // explicitly note that this is not gdbserver. - RNBLogSTDOUT("%s-%s %sfor %s.\n", DEBUGSERVER_PROGRAM_NAME, - DEBUGSERVER_VERSION_STR, compile_options.c_str(), RNB_ARCH); + const char *in_translation = ""; + if (DNBDebugserverIsTranslated()) + in_translation = " (running under translation)"; + RNBLogSTDOUT("%s-%s %sfor %s%s.\n", DEBUGSERVER_PROGRAM_NAME, + DEBUGSERVER_VERSION_STR, compile_options.c_str(), RNB_ARCH, + in_translation); std::string host; int port = INT32_MAX; @@ -1375,6 +1411,7 @@ int main(int argc, char *argv[]) { dup2(null, STDOUT_FILENO); dup2(null, STDERR_FILENO); } else if (g_applist_opt != 0) { + DNBLog("debugserver running in --applist mode"); // List all applications we are able to see std::string applist_plist; int err = ListApplications(applist_plist, false, false); @@ -1432,6 +1469,7 @@ int main(int argc, char *argv[]) { mode = eRNBRunLoopModeExit; } else if (g_applist_opt != 0) { // List all applications we are able to see + DNBLog("debugserver running in applist mode under lockdown"); std::string applist_plist; if (ListApplications(applist_plist, false, false) == 0) { DNBLogDebug("Task list: %s", applist_plist.c_str()); @@ -1492,35 +1530,16 @@ int main(int argc, char *argv[]) { timeout_ptr = &attach_timeout_abstime; } nub_launch_flavor_t launch_flavor = g_launch_flavor; - if (launch_flavor == eLaunchFlavorDefault) { - // Our default launch method is posix spawn - launch_flavor = eLaunchFlavorPosixSpawn; - -#if defined WITH_FBS - // Check if we have an app bundle, if so launch using SpringBoard. - if (waitfor_pid_name.find(".app") != std::string::npos) { - launch_flavor = eLaunchFlavorFBS; - } -#elif defined WITH_BKS - // Check if we have an app bundle, if so launch using SpringBoard. - if (waitfor_pid_name.find(".app") != std::string::npos) { - launch_flavor = eLaunchFlavorBKS; - } -#elif defined WITH_SPRINGBOARD - // Check if we have an app bundle, if so launch using SpringBoard. - if (waitfor_pid_name.find(".app") != std::string::npos) { - launch_flavor = eLaunchFlavorSpringBoard; - } -#endif - } + if (launch_flavor == eLaunchFlavorDefault) + launch_flavor = default_launch_flavor(waitfor_pid_name.c_str()); ctx.SetLaunchFlavor(launch_flavor); bool ignore_existing = false; RNBLogSTDOUT("Waiting to attach to process %s...\n", waitfor_pid_name.c_str()); nub_process_t pid = DNBProcessAttachWait( - waitfor_pid_name.c_str(), launch_flavor, ignore_existing, - timeout_ptr, waitfor_interval, err_str, sizeof(err_str)); + &ctx, waitfor_pid_name.c_str(), ignore_existing, timeout_ptr, + waitfor_interval, err_str, sizeof(err_str)); g_pid = pid; if (pid == INVALID_NUB_PROCESS) { @@ -1555,7 +1574,8 @@ int main(int argc, char *argv[]) { RNBLogSTDOUT("Attaching to process %s...\n", attach_pid_name.c_str()); nub_process_t pid = DNBProcessAttachByName( - attach_pid_name.c_str(), timeout_ptr, err_str, sizeof(err_str)); + attach_pid_name.c_str(), timeout_ptr, ctx.GetUnmaskSignals(), + err_str, sizeof(err_str)); g_pid = pid; if (pid == INVALID_NUB_PROCESS) { ctx.LaunchStatus().SetError(-1, DNBError::Generic); @@ -1626,6 +1646,8 @@ int main(int argc, char *argv[]) { const char *proc_name = ""; if (ctx.ArgumentCount() > 0) proc_name = ctx.ArgumentAtIndex(0); + DNBLog("[LaunchAttach] Successfully launched %s (pid = %d).\n", + proc_name, ctx.ProcessID()); RNBLogSTDOUT("Got a connection, launched process %s (pid = %d).\n", proc_name, ctx.ProcessID()); } diff --git a/gnu/llvm/lldb/tools/debugserver/source/debugserver_vers.c.in b/gnu/llvm/lldb/tools/debugserver/source/debugserver_vers.c.in index 00e34c29b07..0de78f69fd1 100644 --- a/gnu/llvm/lldb/tools/debugserver/source/debugserver_vers.c.in +++ b/gnu/llvm/lldb/tools/debugserver/source/debugserver_vers.c.in @@ -1,2 +1,2 @@ -const unsigned char debugserverVersionString[] __attribute__ ((used)) = "@(#)PROGRAM:LLDB PROJECT:lldb-@LLDB_VERSION_MAJOR@.@LLDB_VERSION_MINOR@.@LLDB_VERSION_PATCH@" "\n"; +const unsigned char debugserverVersionString[] __attribute__ ((used)) = "@(#)PROGRAM:LLDB PROJECT:lldb-@LLDB_VERSION_MAJOR@.@LLDB_VERSION_MINOR@.@LLDB_VERSION_PATCH@@LLDB_VERSION_SUFFIX@" "\n"; const double debugserverVersionNumber __attribute__ ((used)) = (double)@LLDB_VERSION_MAJOR@.@LLDB_VERSION_MINOR@; diff --git a/gnu/llvm/lldb/tools/debugserver/source/libdebugserver.cpp b/gnu/llvm/lldb/tools/debugserver/source/libdebugserver.cpp index 0c53fa4039c..6da3708b424 100644 --- a/gnu/llvm/lldb/tools/debugserver/source/libdebugserver.cpp +++ b/gnu/llvm/lldb/tools/debugserver/source/libdebugserver.cpp @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// -#include +#include #include #include #include diff --git a/gnu/llvm/lldb/tools/driver/Options.td b/gnu/llvm/lldb/tools/driver/Options.td index 96f696ec3ca..8bcb0e7bc52 100644 --- a/gnu/llvm/lldb/tools/driver/Options.td +++ b/gnu/llvm/lldb/tools/driver/Options.td @@ -232,8 +232,12 @@ def capture_path: Separate<["--", "-"], "capture-path">, def replay: Separate<["--", "-"], "replay">, MetaVarName<"">, HelpText<"Tells the debugger to replay a reproducer from .">; +def reproducer_finalize: Separate<["--", "-"], "reproducer-finalize">, + MetaVarName<"">; def no_version_check: F<"reproducer-no-version-check">, HelpText<"Disable the reproducer version check.">; +def no_verification: F<"reproducer-no-verify">, + HelpText<"Disable the reproducer verification.">; def no_generate_on_signal: F<"reproducer-no-generate-on-signal">, HelpText<"Don't generate reproducer when a signal is received.">; def generate_on_exit: F<"reproducer-generate-on-exit">, diff --git a/gnu/llvm/lldb/tools/driver/Platform.cpp b/gnu/llvm/lldb/tools/driver/Platform.cpp index f3a71eb79de..0891cfa1fa8 100644 --- a/gnu/llvm/lldb/tools/driver/Platform.cpp +++ b/gnu/llvm/lldb/tools/driver/Platform.cpp @@ -9,9 +9,9 @@ // this file is only relevant for Visual C++ #if defined(_WIN32) -#include +#include +#include #include -#include #include "Platform.h" #include "llvm/Support/ErrorHandling.h" diff --git a/gnu/llvm/lldb/tools/driver/Platform.h b/gnu/llvm/lldb/tools/driver/Platform.h index 6b893f91f44..d7573b75bf3 100644 --- a/gnu/llvm/lldb/tools/driver/Platform.h +++ b/gnu/llvm/lldb/tools/driver/Platform.h @@ -15,13 +15,13 @@ #include #if defined(_MSC_VER) -#include +#include #endif #if HAVE_SYS_TYPES_H #include #endif #include "lldb/Host/windows/windows.h" -#include +#include struct winsize { long ws_col; @@ -76,7 +76,7 @@ extern int tcsetattr(int fd, int optional_actions, extern int tcgetattr(int fildes, struct termios *termios_p); #else -#include +#include #include #include diff --git a/gnu/llvm/lldb/tools/intel-features/CMakeLists.txt b/gnu/llvm/lldb/tools/intel-features/CMakeLists.txt index efba2f74904..7d48491ec89 100644 --- a/gnu/llvm/lldb/tools/intel-features/CMakeLists.txt +++ b/gnu/llvm/lldb/tools/intel-features/CMakeLists.txt @@ -1,9 +1,8 @@ # Flags to control each individual feature option(LLDB_BUILD_INTEL_MPX "Enable Building of Intel(R) Memory Protection Extensions" ON) -option(LLDB_BUILD_INTEL_PT "Enable Building of Intel(R) Processor Trace Tool" OFF) # Return if all features are OFF -if (NOT LLDB_BUILD_INTEL_MPX AND NOT LLDB_BUILD_INTEL_PT) +if (NOT LLDB_BUILD_INTEL_MPX) return() endif() @@ -16,33 +15,6 @@ if (LLDB_BUILD_INTEL_MPX AND CMAKE_SYSTEM_NAME MATCHES "Linux") SET (CLI_WRAPPER_PREPROCESSORS "${CLI_WRAPPER_PREPROCESSORS} -DBUILD_INTEL_MPX") endif() -if (LLDB_BUILD_INTEL_PT) - add_subdirectory(intel-pt) - LIST (APPEND FEATURE_LIBS ${FEATURE_LIBS} lldbIntelPT) - SET (CLI_WRAPPER_PREPROCESSORS "${CLI_WRAPPER_PREPROCESSORS} -DBUILD_INTEL_PT") -endif() - -# Add python wrapper if python not disabled -if (LLDB_ENABLE_PYTHON AND LLDB_BUILD_INTEL_PT) - set(LLDB_INTEL_FEATURES_PYTHON_WRAP - ${LLDB_BINARY_DIR}/tools/intel-features/scripts/IntelFeaturesPythonWrap.cpp) - set_source_files_properties(${LLDB_INTEL_FEATURES_PYTHON_WRAP} - PROPERTIES GENERATED 1) - - if (CLANG_CL) - set_source_files_properties(${LLDB_INTEL_FEATURES_PYTHON_WRAP} - PROPERTIES COMPILE_FLAGS -Wno-unused-function) - endif() - - if (LLVM_COMPILER_IS_GCC_COMPATIBLE AND - NOT "${CMAKE_SYSTEM_NAME}" MATCHES "Darwin") - set_property(SOURCE ${LLDB_INTEL_FEATURES_PYTHON_WRAP} - APPEND_STRING PROPERTY COMPILE_FLAGS - " -Wno-sequence-point -Wno-cast-qual") - endif () - add_subdirectory(scripts) -endif() - if (NOT CLI_WRAPPER_PREPROCESSORS) return() endif() @@ -52,17 +24,10 @@ set_source_files_properties(cli-wrapper.cpp PROPERTIES add_lldb_library(lldbIntelFeatures SHARED cli-wrapper.cpp - ${LLDB_INTEL_FEATURES_PYTHON_WRAP} LINK_LIBS ${FEATURE_LIBS} - ${PYTHON_LIBRARY} ) -# Add link dependencies for python wrapper -if (LLDB_ENABLE_PYTHON AND LLDB_BUILD_INTEL_PT) - add_dependencies(lldbIntelFeatures intel-features-swig_wrapper) -endif() - install(TARGETS lldbIntelFeatures LIBRARY DESTINATION lib${LLVM_LIBDIR_SUFFIX}) diff --git a/gnu/llvm/lldb/tools/intel-features/README.txt b/gnu/llvm/lldb/tools/intel-features/README.txt index d46bf1392dc..e46f7c427c0 100644 --- a/gnu/llvm/lldb/tools/intel-features/README.txt +++ b/gnu/llvm/lldb/tools/intel-features/README.txt @@ -25,8 +25,8 @@ build to generate a shared library (lldbIntelFeatures) to provide all these commands. For each hardware feature, separate cli commands have been developed that are -provided by wrappers (cli-wrapper-pt.cpp and cli-wrapper-mpxtable.cpp) residing -in feature specific folders ("intel-pt" and "intel-mpx" respectively). +provided by wrappers (e.g. cli-wrapper-mpxtable.cpp) residing +in feature specific folders. For details regarding cli commands of each feature, please refer to these feature specific wrappers. @@ -44,11 +44,6 @@ Furthermore, flexibility is provided to the user to include/exclude a particular feature while building lldbIntelFeatures library. This is done by flags described below: - - LLDB_BUILD_INTEL_PT - The flag enables building of Intel(R) Processor Trace - feature (inside intel-pt folder). This flag defaults to "OFF" meaning the - feature is excluded while building lldbIntelFeatures library. Set it to "ON" - in order to include it. - - LLDB_BUILD_INTEL_MPX - Enables building Intel(R) Memory Protection Extensions feature (inside intel-mpx folder). This flag defaults to "ON" meaning the feature is excluded while building lldbIntelFeatures library. diff --git a/gnu/llvm/lldb/tools/intel-features/cli-wrapper.cpp b/gnu/llvm/lldb/tools/intel-features/cli-wrapper.cpp index f04e39a3be9..08fe7b25fe9 100644 --- a/gnu/llvm/lldb/tools/intel-features/cli-wrapper.cpp +++ b/gnu/llvm/lldb/tools/intel-features/cli-wrapper.cpp @@ -18,10 +18,6 @@ #include "intel-mpx/cli-wrapper-mpxtable.h" #endif -#ifdef BUILD_INTEL_PT -#include "intel-pt/cli-wrapper-pt.h" -#endif - #include "lldb/API/SBDebugger.h" namespace lldb { @@ -30,10 +26,6 @@ bool PluginInitialize(lldb::SBDebugger debugger); bool lldb::PluginInitialize(lldb::SBDebugger debugger) { -#ifdef BUILD_INTEL_PT - PTPluginInitialize(debugger); -#endif - #ifdef BUILD_INTEL_MPX MPXPluginInitialize(debugger); #endif diff --git a/gnu/llvm/lldb/tools/intel-features/intel-mpx/cli-wrapper-mpxtable.cpp b/gnu/llvm/lldb/tools/intel-features/intel-mpx/cli-wrapper-mpxtable.cpp index d2ef0445bc6..b19d8b7387b 100644 --- a/gnu/llvm/lldb/tools/intel-features/intel-mpx/cli-wrapper-mpxtable.cpp +++ b/gnu/llvm/lldb/tools/intel-features/intel-mpx/cli-wrapper-mpxtable.cpp @@ -64,12 +64,12 @@ static void PrintBTEntry(lldb::addr_t lbound, lldb::addr_t ubound, const lldb::addr_t one_cmpl32 = ~((uint32_t)0); if ((lbound == one_cmpl64 || one_cmpl32) && ubound == 0) { - result.Printf("Null bounds on map: pointer value = 0x%lx\n", value); + result.Printf("Null bounds on map: pointer value = 0x%" PRIu64 "\n", value); } else { - result.Printf(" lbound = 0x%lx,", lbound); - result.Printf(" ubound = 0x%lx", ubound); - result.Printf(" (pointer value = 0x%lx,", value); - result.Printf(" metadata = 0x%lx)\n", meta); + result.Printf(" lbound = 0x%" PRIu64 ",", lbound); + result.Printf(" ubound = 0x%" PRIu64 , ubound); + result.Printf(" (pointer value = 0x%" PRIu64 ",", value); + result.Printf(" metadata = 0x%" PRIu64 ")\n", meta); } } diff --git a/gnu/llvm/lldb/tools/intel-features/intel-mpx/test/TestMPXTable.py b/gnu/llvm/lldb/tools/intel-features/intel-mpx/test/TestMPXTable.py index f571252e26f..5431abcdbca 100644 --- a/gnu/llvm/lldb/tools/intel-features/intel-mpx/test/TestMPXTable.py +++ b/gnu/llvm/lldb/tools/intel-features/intel-mpx/test/TestMPXTable.py @@ -30,9 +30,7 @@ class TestMPXTable(TestBase): """Test 'mpx-table show' command""" self.build() - lldb_exec_dir = os.environ["LLDB_IMPLIB_DIR"] - lldb_lib_dir = os.path.join(lldb_exec_dir, os.pardir, "lib") - plugin_file = os.path.join(lldb_lib_dir, "liblldbIntelFeatures.so") + plugin_file = os.path.join(configuration.lldb_libs_dir, "liblldbIntelFeatures.so") if not os.path.isfile(plugin_file): self.skipTest("features plugin missing.") plugin_command = " " @@ -122,9 +120,7 @@ class TestMPXTable(TestBase): """Test 'mpx-table set' command""" self.build() - lldb_exec_dir = os.environ["LLDB_IMPLIB_DIR"] - lldb_lib_dir = os.path.join(lldb_exec_dir, os.pardir, "lib") - plugin_file = os.path.join(lldb_lib_dir, "liblldbIntelFeatures.so") + plugin_file = os.path.join(configuration.lldb_libs_dir, "liblldbIntelFeatures.so") if not os.path.isfile(plugin_file): self.skipTest("features plugin missing.") plugin_command = " " diff --git a/gnu/llvm/lldb/tools/lldb-instr/Instrument.cpp b/gnu/llvm/lldb/tools/lldb-instr/Instrument.cpp index 8ec01304891..8fbc3e64833 100644 --- a/gnu/llvm/lldb/tools/lldb-instr/Instrument.cpp +++ b/gnu/llvm/lldb/tools/lldb-instr/Instrument.cpp @@ -342,9 +342,15 @@ private: }; int main(int argc, const char **argv) { - CommonOptionsParser OP(argc, argv, InstrCategory, - "Utility for generating the macros for LLDB's " - "instrumentation framework."); + auto ExpectedParser = CommonOptionsParser::create( + argc, argv, InstrCategory, llvm::cl::OneOrMore, + "Utility for generating the macros for LLDB's " + "instrumentation framework."); + if (!ExpectedParser) { + llvm::errs() << ExpectedParser.takeError(); + return 1; + } + CommonOptionsParser &OP = ExpectedParser.get(); auto PCHOpts = std::make_shared(); PCHOpts->registerWriter(std::make_unique()); diff --git a/gnu/llvm/lldb/tools/lldb-server/LLDBServerUtilities.cpp b/gnu/llvm/lldb/tools/lldb-server/LLDBServerUtilities.cpp index 7f9271e36b6..a427af4800f 100644 --- a/gnu/llvm/lldb/tools/lldb-server/LLDBServerUtilities.cpp +++ b/gnu/llvm/lldb/tools/lldb-server/LLDBServerUtilities.cpp @@ -24,7 +24,7 @@ static std::shared_ptr GetLogStream(StringRef log_file) { if (!log_file.empty()) { std::error_code EC; std::shared_ptr stream_sp = std::make_shared( - log_file, EC, sys::fs::OF_Text | sys::fs::OF_Append); + log_file, EC, sys::fs::OF_TextWithCRLF | sys::fs::OF_Append); if (!EC) return stream_sp; errs() << llvm::formatv( diff --git a/gnu/llvm/lldb/tools/lldb-server/LLGSOptions.td b/gnu/llvm/lldb/tools/lldb-server/LLGSOptions.td new file mode 100644 index 00000000000..429a4671764 --- /dev/null +++ b/gnu/llvm/lldb/tools/lldb-server/LLGSOptions.td @@ -0,0 +1,62 @@ +include "llvm/Option/OptParser.td" + +class F: Flag<["--", "-"], name>; +class R prefixes, string name> + : Option; + +multiclass SJ { + def NAME: Separate<["--", "-"], name>, + HelpText; + def NAME # _eq: Joined<["--", "-"], name # "=">, + Alias(NAME)>; +} + +def grp_connect : OptionGroup<"connection">, HelpText<"CONNECTION">; + +defm fd: SJ<"fd", "Communicate over the given file descriptor.">, + MetaVarName<"">, + Group; + +defm named_pipe: SJ<"named-pipe", "Write port lldb-server will listen on to the given named pipe.">, + MetaVarName<"">, + Group; + +defm pipe: SJ<"pipe", "Write port lldb-server will listen on to the given file descriptor.">, + MetaVarName<"">, + Group; + +def reverse_connect: F<"reverse-connect">, + HelpText<"Connect to the client instead of passively waiting for a connection. In this case [host]:port denotes the remote address to connect to.">, + Group; + +def grp_general : OptionGroup<"general options">, HelpText<"GENERAL OPTIONS">; + +defm log_channels: SJ<"log-channels", "Channels to log. A colon-separated list of entries. Each entry starts with a channel followed by a space-separated list of categories.">, + MetaVarName<"">, + Group; + +defm log_file: SJ<"log-file", "Destination file to log to. If empty, log to stderr.">, + MetaVarName<"">, + Group; + +def setsid: F<"setsid">, HelpText<"Run lldb-server in a new session.">, + Group; +def: Flag<["-"], "S">, Alias, + Group; + +def help: F<"help">, HelpText<"Prints out the usage information for lldb-server.">, + Group; +def: Flag<["-"], "h">, Alias, + Group; + +def grp_target : OptionGroup<"target selection">, HelpText<"TARGET SELECTION">; + +defm attach: SJ<"attach", "Attach to the process given by a (numeric) process id or a name.">, + MetaVarName<"">, + Group; + +def REM : R<["--"], "">, HelpText<"Launch program for debugging.">, + MetaVarName<"program args">, + Group; + +def: F<"native-regs">; // Noop. Present for backwards compatibility only. diff --git a/gnu/llvm/lldb/tools/lldb-server/SystemInitializerLLGS.h b/gnu/llvm/lldb/tools/lldb-server/SystemInitializerLLGS.h index f3d015e94f8..4469a8ba5f6 100644 --- a/gnu/llvm/lldb/tools/lldb-server/SystemInitializerLLGS.h +++ b/gnu/llvm/lldb/tools/lldb-server/SystemInitializerLLGS.h @@ -14,6 +14,8 @@ class SystemInitializerLLGS : public lldb_private::SystemInitializerCommon { public: + SystemInitializerLLGS() : SystemInitializerCommon(nullptr) {} + llvm::Error Initialize() override; void Terminate() override; }; diff --git a/gnu/llvm/lldb/tools/lldb-server/lldb-platform.cpp b/gnu/llvm/lldb/tools/lldb-server/lldb-platform.cpp index 33f918ffc2a..d4b54362bb4 100644 --- a/gnu/llvm/lldb/tools/lldb-server/lldb-platform.cpp +++ b/gnu/llvm/lldb/tools/lldb-server/lldb-platform.cpp @@ -6,15 +6,15 @@ // //===----------------------------------------------------------------------===// -#include +#include #if defined(__APPLE__) #include #endif -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #if !defined(_WIN32) #include #endif @@ -22,6 +22,7 @@ #include "llvm/Support/FileSystem.h" #include "llvm/Support/FileUtilities.h" +#include "llvm/Support/WithColor.h" #include "llvm/Support/raw_ostream.h" #include "Acceptor.h" @@ -104,11 +105,12 @@ static Status save_socket_id_to_file(const std::string &socket_id, llvm::SmallString<64> temp_file_path; temp_file_spec.AppendPathComponent("port-file.%%%%%%"); + temp_file_path = temp_file_spec.GetPath(); Status status; if (auto Err = handleErrors(llvm::writeFileAtomically( - temp_file_path, temp_file_spec.GetPath(), socket_id), + temp_file_path, file_spec.GetPath(), socket_id), [&status, &file_spec](const AtomicFileWriteError &E) { std::string ErrorMsgBuffer; llvm::raw_string_ostream S(ErrorMsgBuffer); @@ -201,14 +203,15 @@ int main_platform(int argc, char *argv[]) { case 'p': { if (!llvm::to_integer(optarg, port_offset)) { - llvm::errs() << "error: invalid port offset string " << optarg << "\n"; + WithColor::error() << "invalid port offset string " << optarg << "\n"; option_error = 4; break; } if (port_offset < LOW_PORT || port_offset > HIGH_PORT) { - llvm::errs() << llvm::formatv("error: port offset {0} is not in the " - "valid user port range of {1} - {2}\n", - port_offset, LOW_PORT, HIGH_PORT); + WithColor::error() << llvm::formatv( + "port offset {0} is not in the " + "valid user port range of {1} - {2}\n", + port_offset, LOW_PORT, HIGH_PORT); option_error = 5; } } break; @@ -218,19 +221,20 @@ int main_platform(int argc, char *argv[]) { case 'M': { uint16_t portnum; if (!llvm::to_integer(optarg, portnum)) { - llvm::errs() << "error: invalid port number string " << optarg << "\n"; + WithColor::error() << "invalid port number string " << optarg << "\n"; option_error = 2; break; } if (portnum < LOW_PORT || portnum > HIGH_PORT) { - llvm::errs() << llvm::formatv("error: port number {0} is not in the " - "valid user port range of {1} - {2}\n", - portnum, LOW_PORT, HIGH_PORT); + WithColor::error() << llvm::formatv( + "port number {0} is not in the " + "valid user port range of {1} - {2}\n", + portnum, LOW_PORT, HIGH_PORT); option_error = 1; break; } if (ch == 'P') - gdbserver_portmap[portnum] = LLDB_INVALID_PROCESS_ID; + gdbserver_portmap.AllowPort(portnum); else if (ch == 'm') min_gdbserver_port = portnum; else @@ -249,12 +253,13 @@ int main_platform(int argc, char *argv[]) { // Make a port map for a port range that was specified. if (min_gdbserver_port && min_gdbserver_port < max_gdbserver_port) { - for (uint16_t port = min_gdbserver_port; port < max_gdbserver_port; ++port) - gdbserver_portmap[port] = LLDB_INVALID_PROCESS_ID; + gdbserver_portmap = GDBRemoteCommunicationServerPlatform::PortMap( + min_gdbserver_port, max_gdbserver_port); } else if (min_gdbserver_port || max_gdbserver_port) { - fprintf(stderr, "error: --min-gdbserver-port (%u) is not lower than " - "--max-gdbserver-port (%u)\n", - min_gdbserver_port, max_gdbserver_port); + WithColor::error() << llvm::formatv( + "--min-gdbserver-port ({0}) is not lower than " + "--max-gdbserver-port ({1})\n", + min_gdbserver_port, max_gdbserver_port); option_error = 3; } @@ -316,7 +321,7 @@ int main_platform(int argc, char *argv[]) { Connection *conn = nullptr; error = acceptor_up->Accept(children_inherit_accept_socket, conn); if (error.Fail()) { - printf("error: %s\n", error.AsCString()); + WithColor::error() << error.AsCString() << '\n'; exit(socket_error); } printf("Connection established.\n"); @@ -348,13 +353,13 @@ int main_platform(int argc, char *argv[]) { if (platform.IsConnected()) { if (inferior_arguments.GetArgumentCount() > 0) { lldb::pid_t pid = LLDB_INVALID_PROCESS_ID; - uint16_t port = 0; + llvm::Optional port = 0; std::string socket_name; Status error = platform.LaunchGDBServer(inferior_arguments, "", // hostname pid, port, socket_name); if (error.Success()) - platform.SetPendingGdbServer(pid, port, socket_name); + platform.SetPendingGdbServer(pid, *port, socket_name); else fprintf(stderr, "failed to start gdbserver: %s\n", error.AsCString()); } @@ -371,10 +376,10 @@ int main_platform(int argc, char *argv[]) { } if (error.Fail()) { - fprintf(stderr, "error: %s\n", error.AsCString()); + WithColor::error() << error.AsCString() << '\n'; } } else { - fprintf(stderr, "error: handshake with client failed\n"); + WithColor::error() << "handshake with client failed\n"; } } } while (g_server); diff --git a/gnu/llvm/lldb/tools/lldb-server/lldb-server.cpp b/gnu/llvm/lldb/tools/lldb-server/lldb-server.cpp index 749a381ebca..1e001ac7185 100644 --- a/gnu/llvm/lldb/tools/lldb-server/lldb-server.cpp +++ b/gnu/llvm/lldb/tools/lldb-server/lldb-server.cpp @@ -17,8 +17,8 @@ #include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/Signals.h" -#include -#include +#include +#include static llvm::ManagedStatic g_debugger_lifetime; @@ -50,8 +50,6 @@ static void terminate_debugger() { g_debugger_lifetime->Terminate(); } // main int main(int argc, char *argv[]) { llvm::InitLLVM IL(argc, argv, /*InstallPipeSignalExitHandler=*/false); - llvm::StringRef ToolName = argv[0]; - llvm::sys::PrintStackTraceOnErrorSignal(ToolName); llvm::PrettyStackTraceProgram X(argc, argv); int option_error = 0; diff --git a/gnu/llvm/lldb/tools/lldb-test/CMakeLists.txt b/gnu/llvm/lldb/tools/lldb-test/CMakeLists.txt index 2edbd8e56d6..562905760e2 100644 --- a/gnu/llvm/lldb/tools/lldb-test/CMakeLists.txt +++ b/gnu/llvm/lldb/tools/lldb-test/CMakeLists.txt @@ -24,9 +24,9 @@ add_lldb_tool(lldb-test Support ) -if(PYTHON_RPATH) - set_property(TARGET lldb-test APPEND PROPERTY INSTALL_RPATH "${PYTHON_RPATH}") - set_property(TARGET lldb-test APPEND PROPERTY BUILD_RPATH "${PYTHON_RPATH}") +if(Python3_RPATH) + set_property(TARGET lldb-test APPEND PROPERTY INSTALL_RPATH "${Python3_RPATH}") + set_property(TARGET lldb-test APPEND PROPERTY BUILD_RPATH "${Python3_RPATH}") endif() target_include_directories(lldb-test PRIVATE ${LLDB_SOURCE_DIR}/source) diff --git a/gnu/llvm/lldb/tools/lldb-test/SystemInitializerTest.cpp b/gnu/llvm/lldb/tools/lldb-test/SystemInitializerTest.cpp index 10b90cdc640..2b6e0f26bb4 100644 --- a/gnu/llvm/lldb/tools/lldb-test/SystemInitializerTest.cpp +++ b/gnu/llvm/lldb/tools/lldb-test/SystemInitializerTest.cpp @@ -22,7 +22,8 @@ using namespace lldb_private; -SystemInitializerTest::SystemInitializerTest() = default; +SystemInitializerTest::SystemInitializerTest() + : SystemInitializerCommon(nullptr) {} SystemInitializerTest::~SystemInitializerTest() = default; llvm::Error SystemInitializerTest::Initialize() { @@ -54,9 +55,6 @@ llvm::Error SystemInitializerTest::Initialize() { } void SystemInitializerTest::Terminate() { - static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); - Timer scoped_timer(func_cat, LLVM_PRETTY_FUNCTION); - Debugger::SettingsTerminate(); // Terminate and unload and loaded system or user LLDB plug-ins diff --git a/gnu/llvm/lldb/tools/lldb-test/lldb-test.cpp b/gnu/llvm/lldb/tools/lldb-test/lldb-test.cpp index 8625d448527..1109a6bb655 100644 --- a/gnu/llvm/lldb/tools/lldb-test/lldb-test.cpp +++ b/gnu/llvm/lldb/tools/lldb-test/lldb-test.cpp @@ -29,6 +29,7 @@ #include "lldb/Target/Process.h" #include "lldb/Target/Target.h" #include "lldb/Utility/DataExtractor.h" +#include "lldb/Utility/LLDBAssert.h" #include "lldb/Utility/State.h" #include "lldb/Utility/StreamString.h" @@ -57,6 +58,7 @@ cl::SubCommand ObjectFileSubcommand("object-file", "Display LLDB object file information"); cl::SubCommand SymbolsSubcommand("symbols", "Dump symbols for an object file"); cl::SubCommand IRMemoryMapSubcommand("ir-memory-map", "Test IRMemoryMap"); +cl::SubCommand AssertSubcommand("assert", "Test assert handling"); cl::opt Log("log", cl::desc("Path to a log file"), cl::init(""), cl::sub(BreakpointSubcommand), @@ -236,6 +238,9 @@ bool evalFree(StringRef Line, IRMemoryMapTestState &State); int evaluateMemoryMapCommands(Debugger &Dbg); } // namespace irmemorymap +namespace assert { +int lldb_assert(Debugger &Dbg); +} // namespace assert } // namespace opts std::vector parseCompilerContext() { @@ -1077,6 +1082,11 @@ int opts::irmemorymap::evaluateMemoryMapCommands(Debugger &Dbg) { return 0; } +int opts::assert::lldb_assert(Debugger &Dbg) { + lldbassert(false && "lldb-test assert"); + return 1; +} + int main(int argc, const char *argv[]) { StringRef ToolName = argv[0]; sys::PrintStackTraceOnErrorSignal(ToolName); @@ -1102,6 +1112,12 @@ int main(int argc, const char *argv[]) { Dbg->GetCommandInterpreter().HandleCommand( "settings set plugin.process.gdb-remote.packet-timeout 60", /*add_to_history*/ eLazyBoolNo, Result); + Dbg->GetCommandInterpreter().HandleCommand( + "settings set target.inherit-tcc true", + /*add_to_history*/ eLazyBoolNo, Result); + Dbg->GetCommandInterpreter().HandleCommand( + "settings set target.detach-on-error false", + /*add_to_history*/ eLazyBoolNo, Result); if (!opts::Log.empty()) Dbg->EnableLog("lldb", {"all"}, opts::Log, 0, errs()); @@ -1114,6 +1130,8 @@ int main(int argc, const char *argv[]) { return opts::symbols::dumpSymbols(*Dbg); if (opts::IRMemoryMapSubcommand) return opts::irmemorymap::evaluateMemoryMapCommands(*Dbg); + if (opts::AssertSubcommand) + return opts::assert::lldb_assert(*Dbg); WithColor::error() << "No command specified.\n"; return 1; diff --git a/gnu/llvm/lldb/tools/lldb-vscode/CMakeLists.txt b/gnu/llvm/lldb/tools/lldb-vscode/CMakeLists.txt index edf0aaa78d9..41c1f10834e 100644 --- a/gnu/llvm/lldb/tools/lldb-vscode/CMakeLists.txt +++ b/gnu/llvm/lldb/tools/lldb-vscode/CMakeLists.txt @@ -27,10 +27,14 @@ add_lldb_tool(lldb-vscode lldb-vscode.cpp BreakpointBase.cpp ExceptionBreakpoint.cpp + FifoFiles.cpp FunctionBreakpoint.cpp IOStream.cpp JSONUtils.cpp LLDBUtils.cpp + OutputRedirector.cpp + ProgressEvent.cpp + RunInTerminal.cpp SourceBreakpoint.cpp VSCode.cpp diff --git a/gnu/llvm/lldb/tools/lldb-vscode/ExceptionBreakpoint.h b/gnu/llvm/lldb/tools/lldb-vscode/ExceptionBreakpoint.h index 75c617832e0..203630ccf40 100644 --- a/gnu/llvm/lldb/tools/lldb-vscode/ExceptionBreakpoint.h +++ b/gnu/llvm/lldb/tools/lldb-vscode/ExceptionBreakpoint.h @@ -21,12 +21,9 @@ struct ExceptionBreakpoint { lldb::LanguageType language; bool default_value; lldb::SBBreakpoint bp; - ExceptionBreakpoint(std::string f, std::string l, lldb::LanguageType lang) : - filter(std::move(f)), - label(std::move(l)), - language(lang), - default_value(false), - bp() {} + ExceptionBreakpoint(std::string f, std::string l, lldb::LanguageType lang) + : filter(std::move(f)), label(std::move(l)), language(lang), + default_value(false), bp() {} void SetBreakpoint(); void ClearBreakpoint(); diff --git a/gnu/llvm/lldb/tools/lldb-vscode/FifoFiles.cpp b/gnu/llvm/lldb/tools/lldb-vscode/FifoFiles.cpp new file mode 100644 index 00000000000..e37f2020d8f --- /dev/null +++ b/gnu/llvm/lldb/tools/lldb-vscode/FifoFiles.cpp @@ -0,0 +1,91 @@ +//===-- FifoFiles.cpp -------------------------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#include "FifoFiles.h" + +#if !defined(_WIN32) +#include +#include +#include +#endif + +#include +#include +#include +#include + +#include "llvm/Support/FileSystem.h" + +#include "lldb/lldb-defines.h" + +using namespace llvm; + +namespace lldb_vscode { + +FifoFile::FifoFile(StringRef path) : m_path(path) {} + +FifoFile::~FifoFile() { +#if !defined(_WIN32) + unlink(m_path.c_str()); +#endif +} + +Expected> CreateFifoFile(StringRef path) { +#if defined(_WIN32) + return createStringError(inconvertibleErrorCode(), "Unimplemented"); +#else + if (int err = mkfifo(path.data(), 0600)) + return createStringError(std::error_code(err, std::generic_category()), + "Couldn't create fifo file: %s", path.data()); + return std::make_shared(path); +#endif +} + +FifoFileIO::FifoFileIO(StringRef fifo_file, StringRef other_endpoint_name) + : m_fifo_file(fifo_file), m_other_endpoint_name(other_endpoint_name) {} + +Expected FifoFileIO::ReadJSON(std::chrono::milliseconds timeout) { + // We use a pointer for this future, because otherwise its normal destructor + // would wait for the getline to end, rendering the timeout useless. + Optional line; + std::future *future = + new std::future(std::async(std::launch::async, [&]() { + std::ifstream reader(m_fifo_file, std::ifstream::in); + std::string buffer; + std::getline(reader, buffer); + if (!buffer.empty()) + line = buffer; + })); + if (future->wait_for(timeout) == std::future_status::timeout || + !line.hasValue()) + return createStringError(inconvertibleErrorCode(), + "Timed out trying to get messages from the " + + m_other_endpoint_name); + delete future; + return json::parse(*line); +} + +Error FifoFileIO::SendJSON(const json::Value &json, + std::chrono::milliseconds timeout) { + bool done = false; + std::future *future = + new std::future(std::async(std::launch::async, [&]() { + std::ofstream writer(m_fifo_file, std::ofstream::out); + writer << JSONToString(json) << std::endl; + done = true; + })); + if (future->wait_for(timeout) == std::future_status::timeout || !done) { + return createStringError(inconvertibleErrorCode(), + "Timed out trying to send messages to the " + + m_other_endpoint_name); + } + delete future; + return Error::success(); +} + +} // namespace lldb_vscode diff --git a/gnu/llvm/lldb/tools/lldb-vscode/FifoFiles.h b/gnu/llvm/lldb/tools/lldb-vscode/FifoFiles.h new file mode 100644 index 00000000000..f186f65e86c --- /dev/null +++ b/gnu/llvm/lldb/tools/lldb-vscode/FifoFiles.h @@ -0,0 +1,85 @@ +//===-- FifoFiles.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_TOOLS_LLDB_VSCODE_FIFOFILES_H +#define LLDB_TOOLS_LLDB_VSCODE_FIFOFILES_H + +#include "llvm/Config/llvm-config.h" // for LLVM_ON_UNIX +#include "llvm/Support/Error.h" + +#include "JSONUtils.h" + +namespace lldb_vscode { + +/// Struct that controls the life of a fifo file in the filesystem. +/// +/// The file is destroyed when the destructor is invoked. +struct FifoFile { + FifoFile(llvm::StringRef path); + + ~FifoFile(); + + std::string m_path; +}; + +/// Create a fifo file in the filesystem. +/// +/// \param[in] path +/// The path for the fifo file. +/// +/// \return +/// A \a std::shared_ptr if the file could be created, or an +/// \a llvm::Error in case of failures. +llvm::Expected> CreateFifoFile(llvm::StringRef path); + +class FifoFileIO { +public: + /// \param[in] fifo_file + /// The path to an input fifo file that exists in the file system. + /// + /// \param[in] other_endpoint_name + /// A human readable name for the other endpoint that will communicate + /// using this file. This is used for error messages. + FifoFileIO(llvm::StringRef fifo_file, llvm::StringRef other_endpoint_name); + + /// Read the next JSON object from the underlying input fifo file. + /// + /// The JSON object is expected to be a single line delimited with \a + /// std::endl. + /// + /// \return + /// An \a llvm::Error object indicating the success or failure of this + /// operation. Failures arise if the timeout is hit, the next line of text + /// from the fifo file is not a valid JSON object, or is it impossible to + /// read from the file. + llvm::Expected ReadJSON(std::chrono::milliseconds timeout); + + /// Serialize a JSON object and write it to the underlying output fifo file. + /// + /// \param[in] json + /// The JSON object to send. It will be printed as a single line delimited + /// with \a std::endl. + /// + /// \param[in] timeout + /// A timeout for how long we should until for the data to be consumed. + /// + /// \return + /// An \a llvm::Error object indicating whether the data was consumed by + /// a reader or not. + llvm::Error SendJSON( + const llvm::json::Value &json, + std::chrono::milliseconds timeout = std::chrono::milliseconds(20000)); + +private: + std::string m_fifo_file; + std::string m_other_endpoint_name; +}; + +} // namespace lldb_vscode + +#endif // LLDB_TOOLS_LLDB_VSCODE_FIFOFILES_H diff --git a/gnu/llvm/lldb/tools/lldb-vscode/FunctionBreakpoint.cpp b/gnu/llvm/lldb/tools/lldb-vscode/FunctionBreakpoint.cpp index 9dd97e7b79e..e7720a1bc84 100644 --- a/gnu/llvm/lldb/tools/lldb-vscode/FunctionBreakpoint.cpp +++ b/gnu/llvm/lldb/tools/lldb-vscode/FunctionBreakpoint.cpp @@ -27,4 +27,4 @@ void FunctionBreakpoint::SetBreakpoint() { SetHitCondition(); } -} +} // namespace lldb_vscode diff --git a/gnu/llvm/lldb/tools/lldb-vscode/IOStream.h b/gnu/llvm/lldb/tools/lldb-vscode/IOStream.h index 603ae9adcc2..0eb9b6fefb0 100644 --- a/gnu/llvm/lldb/tools/lldb-vscode/IOStream.h +++ b/gnu/llvm/lldb/tools/lldb-vscode/IOStream.h @@ -9,6 +9,8 @@ #ifndef LLDB_TOOLS_LLDB_VSCODE_IOSTREAM_H #define LLDB_TOOLS_LLDB_VSCODE_IOSTREAM_H +#include "llvm/Config/llvm-config.h" // for LLVM_ON_UNIX + #if defined(_WIN32) // We need to #define NOMINMAX in order to skip `min()` and `max()` macro // definitions that conflict with other system headers. diff --git a/gnu/llvm/lldb/tools/lldb-vscode/JSONUtils.cpp b/gnu/llvm/lldb/tools/lldb-vscode/JSONUtils.cpp index 1ebaa5c3771..0e6227f3b15 100644 --- a/gnu/llvm/lldb/tools/lldb-vscode/JSONUtils.cpp +++ b/gnu/llvm/lldb/tools/lldb-vscode/JSONUtils.cpp @@ -7,6 +7,8 @@ //===----------------------------------------------------------------------===// #include +#include +#include #include "llvm/ADT/Optional.h" #include "llvm/Support/FormatAdapters.h" @@ -15,6 +17,7 @@ #include "lldb/API/SBBreakpoint.h" #include "lldb/API/SBBreakpointLocation.h" +#include "lldb/API/SBDeclaration.h" #include "lldb/API/SBValue.h" #include "lldb/Host/PosixApi.h" @@ -327,6 +330,46 @@ llvm::json::Value CreateBreakpoint(lldb::SBBreakpoint &bp, return llvm::json::Value(std::move(object)); } +static uint64_t GetDebugInfoSizeInSection(lldb::SBSection section) { + uint64_t debug_info_size = 0; + llvm::StringRef section_name(section.GetName()); + if (section_name.startswith(".debug") || section_name.startswith("__debug") || + section_name.startswith(".apple") || section_name.startswith("__apple")) + debug_info_size += section.GetFileByteSize(); + size_t num_sub_sections = section.GetNumSubSections(); + for (size_t i = 0; i < num_sub_sections; i++) { + debug_info_size += + GetDebugInfoSizeInSection(section.GetSubSectionAtIndex(i)); + } + return debug_info_size; +} + +static uint64_t GetDebugInfoSize(lldb::SBModule module) { + uint64_t debug_info_size = 0; + size_t num_sections = module.GetNumSections(); + for (size_t i = 0; i < num_sections; i++) { + debug_info_size += GetDebugInfoSizeInSection(module.GetSectionAtIndex(i)); + } + return debug_info_size; +} + +static std::string ConvertDebugInfoSizeToString(uint64_t debug_info) { + std::ostringstream oss; + oss << std::fixed << std::setprecision(1); + if (debug_info < 1024) { + oss << debug_info << "B"; + } else if (debug_info < 1024 * 1024) { + double kb = double(debug_info) / 1024.0; + oss << kb << "KB"; + } else if (debug_info < 1024 * 1024 * 1024) { + double mb = double(debug_info) / (1024.0 * 1024.0); + oss << mb << "MB"; + } else { + double gb = double(debug_info) / (1024.0 * 1024.0 * 1024.0); + oss << gb << "GB"; + } + return oss.str(); +} llvm::json::Value CreateModule(lldb::SBModule &module) { llvm::json::Object object; if (!module.IsValid()) @@ -339,9 +382,17 @@ llvm::json::Value CreateModule(lldb::SBModule &module) { std::string module_path(module_path_arr); object.try_emplace("path", module_path); if (module.GetNumCompileUnits() > 0) { - object.try_emplace("symbolStatus", "Symbols loaded."); + std::string symbol_str = "Symbols loaded."; + std::string debug_info_size; + uint64_t debug_info = GetDebugInfoSize(module); + if (debug_info > 0) { + debug_info_size = ConvertDebugInfoSizeToString(debug_info); + } + object.try_emplace("symbolStatus", symbol_str); + object.try_emplace("debugInfoSize", debug_info_size); char symbol_path_arr[PATH_MAX]; - module.GetSymbolFileSpec().GetPath(symbol_path_arr, sizeof(symbol_path_arr)); + module.GetSymbolFileSpec().GetPath(symbol_path_arr, + sizeof(symbol_path_arr)); std::string symbol_path(symbol_path_arr); object.try_emplace("symbolFilePath", symbol_path); } else { @@ -352,8 +403,9 @@ llvm::json::Value CreateModule(lldb::SBModule &module) { object.try_emplace("addressRange", loaded_addr); std::string version_str; uint32_t version_nums[3]; - uint32_t num_versions = module.GetVersion(version_nums, sizeof(version_nums)/sizeof(uint32_t)); - for (uint32_t i=0; i"; +} + +std::string CreateUniqueVariableNameForDisplay(lldb::SBValue v, + bool is_name_duplicated) { + lldb::SBStream name_builder; + name_builder.Print(GetNonNullVariableName(v)); + if (is_name_duplicated) { + lldb::SBDeclaration declaration = v.GetDeclaration(); + const char *file_name = declaration.GetFileSpec().GetFilename(); + const uint32_t line = declaration.GetLine(); + + if (file_name != nullptr && line > 0) + name_builder.Printf(" @ %s:%u", file_name, line); + else if (const char *location = v.GetLocation()) + name_builder.Printf(" @ %s", location); + } + return name_builder.GetData(); +} + // "Variable": { // "type": "object", // "description": "A Variable is a name/value pair. Optionally a variable @@ -915,10 +999,12 @@ llvm::json::Value CreateThreadStopped(lldb::SBThread &thread, // "required": [ "name", "value", "variablesReference" ] // } llvm::json::Value CreateVariable(lldb::SBValue v, int64_t variablesReference, - int64_t varID, bool format_hex) { + int64_t varID, bool format_hex, + bool is_name_duplicated) { llvm::json::Object object; - auto name = v.GetName(); - EmplaceSafeString(object, "name", name ? name : ""); + EmplaceSafeString(object, "name", + CreateUniqueVariableNameForDisplay(v, is_name_duplicated)); + if (format_hex) v.SetFormat(lldb::eFormatHex); SetValueForKey(v, object, "value"); @@ -947,4 +1033,57 @@ llvm::json::Value CreateCompileUnit(lldb::SBCompileUnit unit) { return llvm::json::Value(std::move(object)); } +/// See +/// https://microsoft.github.io/debug-adapter-protocol/specification#Reverse_Requests_RunInTerminal +llvm::json::Object +CreateRunInTerminalReverseRequest(const llvm::json::Object &launch_request, + llvm::StringRef debug_adaptor_path, + llvm::StringRef comm_file) { + llvm::json::Object reverse_request; + reverse_request.try_emplace("type", "request"); + reverse_request.try_emplace("command", "runInTerminal"); + + llvm::json::Object run_in_terminal_args; + // This indicates the IDE to open an embedded terminal, instead of opening the + // terminal in a new window. + run_in_terminal_args.try_emplace("kind", "integrated"); + + auto launch_request_arguments = launch_request.getObject("arguments"); + // The program path must be the first entry in the "args" field + std::vector args = { + debug_adaptor_path.str(), "--comm-file", comm_file.str(), + "--launch-target", GetString(launch_request_arguments, "program").str()}; + std::vector target_args = + GetStrings(launch_request_arguments, "args"); + args.insert(args.end(), target_args.begin(), target_args.end()); + run_in_terminal_args.try_emplace("args", args); + + const auto cwd = GetString(launch_request_arguments, "cwd"); + if (!cwd.empty()) + run_in_terminal_args.try_emplace("cwd", cwd); + + // We need to convert the input list of environments variables into a + // dictionary + std::vector envs = GetStrings(launch_request_arguments, "env"); + llvm::json::Object environment; + for (const std::string &env : envs) { + size_t index = env.find('='); + environment.try_emplace(env.substr(0, index), env.substr(index + 1)); + } + run_in_terminal_args.try_emplace("env", + llvm::json::Value(std::move(environment))); + + reverse_request.try_emplace( + "arguments", llvm::json::Value(std::move(run_in_terminal_args))); + return reverse_request; +} + +std::string JSONToString(const llvm::json::Value &json) { + std::string data; + llvm::raw_string_ostream os(data); + os << json; + os.flush(); + return data; +} + } // namespace lldb_vscode diff --git a/gnu/llvm/lldb/tools/lldb-vscode/JSONUtils.h b/gnu/llvm/lldb/tools/lldb-vscode/JSONUtils.h index e2ccfdb1fb2..bb81b888959 100644 --- a/gnu/llvm/lldb/tools/lldb-vscode/JSONUtils.h +++ b/gnu/llvm/lldb/tools/lldb-vscode/JSONUtils.h @@ -9,11 +9,11 @@ #ifndef LLDB_TOOLS_LLDB_VSCODE_JSONUTILS_H #define LLDB_TOOLS_LLDB_VSCODE_JSONUTILS_H -#include -#include "llvm/ADT/StringRef.h" -#include "llvm/Support/JSON.h" #include "VSCodeForward.h" #include "lldb/API/SBModule.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/JSON.h" +#include namespace lldb_vscode { @@ -399,6 +399,18 @@ llvm::json::Value CreateThread(lldb::SBThread &thread); /// definition outlined by Microsoft. llvm::json::Value CreateThreadStopped(lldb::SBThread &thread, uint32_t stop_id); +/// \return +/// The variable name of \a value or a default placeholder. +const char *GetNonNullVariableName(lldb::SBValue value); + +/// VSCode can't display two variables with the same name, so we need to +/// distinguish them by using a suffix. +/// +/// If the source and line information is present, we use it as the suffix. +/// Otherwise, we fallback to the variable address or register location. +std::string CreateUniqueVariableNameForDisplay(lldb::SBValue v, + bool is_name_duplicated); + /// Create a "Variable" object for a LLDB thread object. /// /// This function will fill in the following keys in the returned @@ -435,14 +447,47 @@ llvm::json::Value CreateThreadStopped(lldb::SBThread &thread, uint32_t stop_id); /// It set to true the variable will be formatted as hex in /// the "value" key value pair for the value of the variable. /// +/// \param[in] is_name_duplicated +/// Whether the same variable name appears multiple times within the same +/// context (e.g. locals). This can happen due to shadowed variables in +/// nested blocks. +/// +/// As VSCode doesn't render two of more variables with the same name, we +/// apply a suffix to distinguish duplicated variables. +/// /// \return /// A "Variable" JSON object with that follows the formal JSON /// definition outlined by Microsoft. llvm::json::Value CreateVariable(lldb::SBValue v, int64_t variablesReference, - int64_t varID, bool format_hex); + int64_t varID, bool format_hex, + bool is_name_duplicated = false); llvm::json::Value CreateCompileUnit(lldb::SBCompileUnit unit); +/// Create a runInTerminal reverse request object +/// +/// \param[in] launch_request +/// The original launch_request object whose fields are used to construct +/// the reverse request object. +/// +/// \param[in] debug_adaptor_path +/// Path to the current debug adaptor. It will be used to delegate the +/// launch of the target. +/// +/// \param[in] comm_file +/// The fifo file used to communicate the with the target launcher. +/// +/// \return +/// A "runInTerminal" JSON object that follows the specification outlined by +/// Microsoft. +llvm::json::Object +CreateRunInTerminalReverseRequest(const llvm::json::Object &launch_request, + llvm::StringRef debug_adaptor_path, + llvm::StringRef comm_file); + +/// Convert a given JSON object to a string. +std::string JSONToString(const llvm::json::Value &json); + } // namespace lldb_vscode #endif diff --git a/gnu/llvm/lldb/tools/lldb-vscode/LLDBUtils.cpp b/gnu/llvm/lldb/tools/lldb-vscode/LLDBUtils.cpp index 81b5a789d1d..621f4ec37c8 100644 --- a/gnu/llvm/lldb/tools/lldb-vscode/LLDBUtils.cpp +++ b/gnu/llvm/lldb/tools/lldb-vscode/LLDBUtils.cpp @@ -55,6 +55,10 @@ bool ThreadHasStopReason(lldb::SBThread &thread) { case lldb::eStopReasonSignal: case lldb::eStopReasonException: case lldb::eStopReasonExec: + case lldb::eStopReasonProcessorTrace: + case lldb::eStopReasonFork: + case lldb::eStopReasonVFork: + case lldb::eStopReasonVForkDone: return true; case lldb::eStopReasonThreadExiting: case lldb::eStopReasonInvalid: diff --git a/gnu/llvm/lldb/tools/lldb-vscode/Options.td b/gnu/llvm/lldb/tools/lldb-vscode/Options.td index 87cfb5199b4..ff2ffd59de0 100644 --- a/gnu/llvm/lldb/tools/lldb-vscode/Options.td +++ b/gnu/llvm/lldb/tools/lldb-vscode/Options.td @@ -23,3 +23,14 @@ def port: Separate<["--", "-"], "port">, def: Separate<["-"], "p">, Alias, HelpText<"Alias for --port">; + +def launch_target: Separate<["--", "-"], "launch-target">, + MetaVarName<"">, + HelpText<"Launch a target for the launchInTerminal request. Any argument " + "provided after this one will be passed to the target. The parameter " + "--comm-files-prefix must also be specified.">; + +def comm_file: Separate<["--", "-"], "comm-file">, + MetaVarName<"">, + HelpText<"The fifo file used to communicate the with the debug adaptor" + "when using --launch-target.">; diff --git a/gnu/llvm/lldb/tools/lldb-vscode/OutputRedirector.cpp b/gnu/llvm/lldb/tools/lldb-vscode/OutputRedirector.cpp new file mode 100644 index 00000000000..7432a828d04 --- /dev/null +++ b/gnu/llvm/lldb/tools/lldb-vscode/OutputRedirector.cpp @@ -0,0 +1,56 @@ +//===-- OutputRedirector.cpp -----------------------------------*- 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 +// +//===----------------------------------------------------------------------===/ + +#if !defined(_WIN32) +#include +#endif + +#include "OutputRedirector.h" + +using namespace llvm; + +namespace lldb_vscode { + +Error RedirectFd(int fd, std::function callback) { +#if !defined(_WIN32) + int new_fd[2]; + if (pipe(new_fd) == -1) { + int error = errno; + return createStringError(inconvertibleErrorCode(), + "Couldn't create new pipe for fd %d. %s", fd, + strerror(error)); + } + + if (dup2(new_fd[1], fd) == -1) { + int error = errno; + return createStringError(inconvertibleErrorCode(), + "Couldn't override the fd %d. %s", fd, + strerror(error)); + } + + int read_fd = new_fd[0]; + std::thread t([read_fd, callback]() { + char buffer[4096]; + while (true) { + ssize_t bytes_count = read(read_fd, &buffer, sizeof(buffer)); + if (bytes_count == 0) + return; + if (bytes_count == -1) { + if (errno == EAGAIN || errno == EINTR) + continue; + break; + } + callback(StringRef(buffer, bytes_count).str()); + } + }); + t.detach(); +#endif + return Error::success(); +} + +} // namespace lldb_vscode diff --git a/gnu/llvm/lldb/tools/lldb-vscode/OutputRedirector.h b/gnu/llvm/lldb/tools/lldb-vscode/OutputRedirector.h new file mode 100644 index 00000000000..c728367a218 --- /dev/null +++ b/gnu/llvm/lldb/tools/lldb-vscode/OutputRedirector.h @@ -0,0 +1,28 @@ +//===-- OutputRedirector.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_TOOLS_LLDB_VSCODE_OUTPUT_REDIRECTOR_H +#define LLDB_TOOLS_LLDB_VSCODE_OUTPUT_REDIRECTOR_H + +#include + +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Error.h" + +namespace lldb_vscode { + +/// Redirects the output of a given file descriptor to a callback. +/// +/// \return +/// \a Error::success if the redirection was set up correctly, or an error +/// otherwise. +llvm::Error RedirectFd(int fd, std::function callback); + +} // namespace lldb_vscode + +#endif // LLDB_TOOLS_LLDB_VSCODE_OUTPUT_REDIRECTOR_H diff --git a/gnu/llvm/lldb/tools/lldb-vscode/ProgressEvent.cpp b/gnu/llvm/lldb/tools/lldb-vscode/ProgressEvent.cpp new file mode 100644 index 00000000000..5c1f8c63ebe --- /dev/null +++ b/gnu/llvm/lldb/tools/lldb-vscode/ProgressEvent.cpp @@ -0,0 +1,230 @@ +//===-- ProgressEvent.cpp ---------------------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#include "ProgressEvent.h" + +#include "JSONUtils.h" + +using namespace lldb_vscode; +using namespace llvm; + +// The minimum duration of an event for it to be reported +const std::chrono::duration kStartProgressEventReportDelay = + std::chrono::seconds(1); +// The minimum time interval between update events for reporting. If multiple +// updates fall within the same time interval, only the latest is reported. +const std::chrono::duration kUpdateProgressEventReportDelay = + std::chrono::milliseconds(250); + +ProgressEvent::ProgressEvent(uint64_t progress_id, Optional message, + uint64_t completed, uint64_t total, + const ProgressEvent *prev_event) + : m_progress_id(progress_id) { + if (message) + m_message = message->str(); + + const bool calculate_percentage = total != UINT64_MAX; + if (completed == 0) { + // Start event + m_event_type = progressStart; + // Wait a bit before reporting the start event in case in completes really + // quickly. + m_minimum_allowed_report_time = + m_creation_time + kStartProgressEventReportDelay; + if (calculate_percentage) + m_percentage = 0; + } else if (completed == total) { + // End event + m_event_type = progressEnd; + // We should report the end event right away. + m_minimum_allowed_report_time = std::chrono::seconds::zero(); + if (calculate_percentage) + m_percentage = 100; + } else { + // Update event + m_event_type = progressUpdate; + m_percentage = std::min( + (uint32_t)((double)completed / (double)total * 100.0), (uint32_t)99); + if (prev_event->Reported()) { + // Add a small delay between reports + m_minimum_allowed_report_time = + prev_event->m_minimum_allowed_report_time + + kUpdateProgressEventReportDelay; + } else { + // We should use the previous timestamp, as it's still pending + m_minimum_allowed_report_time = prev_event->m_minimum_allowed_report_time; + } + } +} + +Optional ProgressEvent::Create(uint64_t progress_id, + Optional message, + uint64_t completed, + uint64_t total, + const ProgressEvent *prev_event) { + // If it's an update without a previous event, we abort + if (completed > 0 && completed < total && !prev_event) + return None; + ProgressEvent event(progress_id, message, completed, total, prev_event); + // We shouldn't show unnamed start events in the IDE + if (event.GetEventType() == progressStart && event.GetEventName().empty()) + return None; + + if (prev_event && prev_event->EqualsForIDE(event)) + return None; + + return event; +} + +bool ProgressEvent::EqualsForIDE(const ProgressEvent &other) const { + return m_progress_id == other.m_progress_id && + m_event_type == other.m_event_type && + m_percentage == other.m_percentage; +} + +ProgressEventType ProgressEvent::GetEventType() const { return m_event_type; } + +StringRef ProgressEvent::GetEventName() const { + if (m_event_type == progressStart) + return "progressStart"; + else if (m_event_type == progressEnd) + return "progressEnd"; + else + return "progressUpdate"; +} + +json::Value ProgressEvent::ToJSON() const { + llvm::json::Object event(CreateEventObject(GetEventName())); + llvm::json::Object body; + + std::string progress_id_str; + llvm::raw_string_ostream progress_id_strm(progress_id_str); + progress_id_strm << m_progress_id; + progress_id_strm.flush(); + body.try_emplace("progressId", progress_id_str); + + if (m_event_type == progressStart) { + EmplaceSafeString(body, "title", m_message); + body.try_emplace("cancellable", false); + } + + std::string timestamp(llvm::formatv("{0:f9}", m_creation_time.count())); + EmplaceSafeString(body, "timestamp", timestamp); + + if (m_percentage) + body.try_emplace("percentage", *m_percentage); + + event.try_emplace("body", std::move(body)); + return json::Value(std::move(event)); +} + +bool ProgressEvent::Report(ProgressEventReportCallback callback) { + if (Reported()) + return true; + if (std::chrono::system_clock::now().time_since_epoch() < + m_minimum_allowed_report_time) + return false; + + m_reported = true; + callback(*this); + return true; +} + +bool ProgressEvent::Reported() const { return m_reported; } + +ProgressEventManager::ProgressEventManager( + const ProgressEvent &start_event, + ProgressEventReportCallback report_callback) + : m_start_event(start_event), m_finished(false), + m_report_callback(report_callback) {} + +bool ProgressEventManager::ReportIfNeeded() { + // The event finished before we were able to report it. + if (!m_start_event.Reported() && Finished()) + return true; + + if (!m_start_event.Report(m_report_callback)) + return false; + + if (m_last_update_event) + m_last_update_event->Report(m_report_callback); + return true; +} + +const ProgressEvent &ProgressEventManager::GetMostRecentEvent() const { + return m_last_update_event ? *m_last_update_event : m_start_event; +} + +void ProgressEventManager::Update(uint64_t progress_id, uint64_t completed, + uint64_t total) { + if (Optional event = ProgressEvent::Create( + progress_id, None, completed, total, &GetMostRecentEvent())) { + if (event->GetEventType() == progressEnd) + m_finished = true; + + m_last_update_event = *event; + ReportIfNeeded(); + } +} + +bool ProgressEventManager::Finished() const { return m_finished; } + +ProgressEventReporter::ProgressEventReporter( + ProgressEventReportCallback report_callback) + : m_report_callback(report_callback) { + m_thread_should_exit = false; + m_thread = std::thread([&] { + while (!m_thread_should_exit) { + std::this_thread::sleep_for(kUpdateProgressEventReportDelay); + ReportStartEvents(); + } + }); +} + +ProgressEventReporter::~ProgressEventReporter() { + m_thread_should_exit = true; + m_thread.join(); +} + +void ProgressEventReporter::ReportStartEvents() { + std::lock_guard locker(m_mutex); + + while (!m_unreported_start_events.empty()) { + ProgressEventManagerSP event_manager = m_unreported_start_events.front(); + if (event_manager->Finished()) + m_unreported_start_events.pop(); + else if (event_manager->ReportIfNeeded()) + m_unreported_start_events + .pop(); // we remove it from the queue as it started reporting + // already, the Push method will be able to continue its + // reports. + else + break; // If we couldn't report it, then the next event in the queue won't + // be able as well, as it came later. + } +} + +void ProgressEventReporter::Push(uint64_t progress_id, const char *message, + uint64_t completed, uint64_t total) { + std::lock_guard locker(m_mutex); + + auto it = m_event_managers.find(progress_id); + if (it == m_event_managers.end()) { + if (Optional event = + ProgressEvent::Create(progress_id, StringRef(message), completed, total)) { + ProgressEventManagerSP event_manager = + std::make_shared(*event, m_report_callback); + m_event_managers.insert({progress_id, event_manager}); + m_unreported_start_events.push(event_manager); + } + } else { + it->second->Update(progress_id, completed, total); + if (it->second->Finished()) + m_event_managers.erase(it); + } +} diff --git a/gnu/llvm/lldb/tools/lldb-vscode/ProgressEvent.h b/gnu/llvm/lldb/tools/lldb-vscode/ProgressEvent.h new file mode 100644 index 00000000000..627d723e5c2 --- /dev/null +++ b/gnu/llvm/lldb/tools/lldb-vscode/ProgressEvent.h @@ -0,0 +1,158 @@ +//===-- ProgressEvent.cpp ---------------------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#include +#include +#include + +#include "VSCodeForward.h" + +#include "llvm/Support/JSON.h" + +namespace lldb_vscode { + +enum ProgressEventType { + progressStart, + progressUpdate, + progressEnd +}; + +class ProgressEvent; +using ProgressEventReportCallback = std::function; + +class ProgressEvent { +public: + /// Actual constructor to use that returns an optional, as the event might be + /// not apt for the IDE, e.g. an unnamed start event, or a redundant one. + /// + /// \param[in] progress_id + /// ID for this event. + /// + /// \param[in] message + /// Message to display in the UI. Required for start events. + /// + /// \param[in] completed + /// Number of jobs completed. + /// + /// \param[in] total + /// Total number of jobs, or \b UINT64_MAX if not determined. + /// + /// \param[in] prev_event + /// Previous event if this one is an update. If \b nullptr, then a start + /// event will be created. + static llvm::Optional + Create(uint64_t progress_id, llvm::Optional message, + uint64_t completed, uint64_t total, + const ProgressEvent *prev_event = nullptr); + + llvm::json::Value ToJSON() const; + + /// \return + /// \b true if two event messages would result in the same event for the + /// IDE, e.g. same rounded percentage. + bool EqualsForIDE(const ProgressEvent &other) const; + + llvm::StringRef GetEventName() const; + + ProgressEventType GetEventType() const; + + /// Report this progress event to the provided callback only if enough time + /// has passed since the creation of the event and since the previous reported + /// update. + bool Report(ProgressEventReportCallback callback); + + bool Reported() const; + +private: + ProgressEvent(uint64_t progress_id, llvm::Optional message, + uint64_t completed, uint64_t total, + const ProgressEvent *prev_event); + + uint64_t m_progress_id; + std::string m_message; + ProgressEventType m_event_type; + llvm::Optional m_percentage; + std::chrono::duration m_creation_time = + std::chrono::system_clock::now().time_since_epoch(); + std::chrono::duration m_minimum_allowed_report_time; + bool m_reported = false; +}; + +/// Class that keeps the start event and its most recent update. +/// It controls when the event should start being reported to the IDE. +class ProgressEventManager { +public: + ProgressEventManager(const ProgressEvent &start_event, + ProgressEventReportCallback report_callback); + + /// Report the start event and the most recent update if the event has lasted + /// for long enough. + /// + /// \return + /// \b false if the event hasn't finished and hasn't reported anything + /// yet. + bool ReportIfNeeded(); + + /// Receive a new progress event for the start event and try to report it if + /// appropriate. + void Update(uint64_t progress_id, uint64_t completed, uint64_t total); + + /// \return + /// \b true if a \a progressEnd event has been notified. There's no + /// need to try to report manually an event that has finished. + bool Finished() const; + + const ProgressEvent &GetMostRecentEvent() const; + +private: + ProgressEvent m_start_event; + llvm::Optional m_last_update_event; + bool m_finished; + ProgressEventReportCallback m_report_callback; +}; + +using ProgressEventManagerSP = std::shared_ptr; + +/// Class that filters out progress event messages that shouldn't be reported +/// to the IDE, because they are invalid, they carry no new information, or they +/// don't last long enough. +/// +/// We need to limit the amount of events that are sent to the IDE, as they slow +/// the render thread of the UI user, and they end up spamming the DAP +/// connection, which also takes some processing time out of the IDE. +class ProgressEventReporter { +public: + /// \param[in] report_callback + /// Function to invoke to report the event to the IDE. + ProgressEventReporter(ProgressEventReportCallback report_callback); + + ~ProgressEventReporter(); + + /// Add a new event to the internal queue and report the event if + /// appropriate. + void Push(uint64_t progress_id, const char *message, uint64_t completed, + uint64_t total); + +private: + /// Report to the IDE events that haven't been reported to the IDE and have + /// lasted long enough. + void ReportStartEvents(); + + ProgressEventReportCallback m_report_callback; + std::map m_event_managers; + /// Queue of start events in chronological order + std::queue m_unreported_start_events; + /// Thread used to invoke \a ReportStartEvents periodically. + std::thread m_thread; + bool m_thread_should_exit; + /// Mutex that prevents running \a Push and \a ReportStartEvents + /// simultaneously, as both read and modify the same underlying objects. + std::mutex m_mutex; +}; + +} // namespace lldb_vscode diff --git a/gnu/llvm/lldb/tools/lldb-vscode/RunInTerminal.cpp b/gnu/llvm/lldb/tools/lldb-vscode/RunInTerminal.cpp new file mode 100644 index 00000000000..2126563d9e9 --- /dev/null +++ b/gnu/llvm/lldb/tools/lldb-vscode/RunInTerminal.cpp @@ -0,0 +1,173 @@ +//===-- RunInTerminal.cpp ---------------------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#include "RunInTerminal.h" + +#if !defined(_WIN32) +#include +#include +#include +#endif + +#include +#include +#include +#include + +#include "llvm/Support/FileSystem.h" + +#include "lldb/lldb-defines.h" + +using namespace llvm; + +namespace lldb_vscode { + +const RunInTerminalMessagePid *RunInTerminalMessage::GetAsPidMessage() const { + return static_cast(this); +} + +const RunInTerminalMessageError * +RunInTerminalMessage::GetAsErrorMessage() const { + return static_cast(this); +} + +RunInTerminalMessage::RunInTerminalMessage(RunInTerminalMessageKind kind) + : kind(kind) {} + +RunInTerminalMessagePid::RunInTerminalMessagePid(lldb::pid_t pid) + : RunInTerminalMessage(eRunInTerminalMessageKindPID), pid(pid) {} + +json::Value RunInTerminalMessagePid::ToJSON() const { + return json::Object{{"kind", "pid"}, {"pid", static_cast(pid)}}; +} + +RunInTerminalMessageError::RunInTerminalMessageError(StringRef error) + : RunInTerminalMessage(eRunInTerminalMessageKindError), error(error) {} + +json::Value RunInTerminalMessageError::ToJSON() const { + return json::Object{{"kind", "error"}, {"value", error}}; +} + +RunInTerminalMessageDidAttach::RunInTerminalMessageDidAttach() + : RunInTerminalMessage(eRunInTerminalMessageKindDidAttach) {} + +json::Value RunInTerminalMessageDidAttach::ToJSON() const { + return json::Object{{"kind", "didAttach"}}; +} + +static Expected +ParseJSONMessage(const json::Value &json) { + if (const json::Object *obj = json.getAsObject()) { + if (Optional kind = obj->getString("kind")) { + if (*kind == "pid") { + if (Optional pid = obj->getInteger("pid")) + return std::make_unique( + static_cast(*pid)); + } else if (*kind == "error") { + if (Optional error = obj->getString("error")) + return std::make_unique(*error); + } else if (*kind == "didAttach") { + return std::make_unique(); + } + } + } + + return createStringError(inconvertibleErrorCode(), + "Incorrect JSON message: " + JSONToString(json)); +} + +static Expected +GetNextMessage(FifoFileIO &io, std::chrono::milliseconds timeout) { + if (Expected json = io.ReadJSON(timeout)) + return ParseJSONMessage(*json); + else + return json.takeError(); +} + +static Error ToError(const RunInTerminalMessage &message) { + if (message.kind == eRunInTerminalMessageKindError) + return createStringError(inconvertibleErrorCode(), + message.GetAsErrorMessage()->error); + return createStringError(inconvertibleErrorCode(), + "Unexpected JSON message: " + + JSONToString(message.ToJSON())); +} + +RunInTerminalLauncherCommChannel::RunInTerminalLauncherCommChannel( + StringRef comm_file) + : m_io(comm_file, "debug adaptor") {} + +Error RunInTerminalLauncherCommChannel::WaitUntilDebugAdaptorAttaches( + std::chrono::milliseconds timeout) { + if (Expected message = + GetNextMessage(m_io, timeout)) { + if (message.get()->kind == eRunInTerminalMessageKindDidAttach) + return Error::success(); + else + return ToError(*message.get()); + } else + return message.takeError(); +} + +Error RunInTerminalLauncherCommChannel::NotifyPid() { + return m_io.SendJSON(RunInTerminalMessagePid(getpid()).ToJSON()); +} + +void RunInTerminalLauncherCommChannel::NotifyError(StringRef error) { + if (Error err = m_io.SendJSON(RunInTerminalMessageError(error).ToJSON(), + std::chrono::seconds(2))) + llvm::errs() << llvm::toString(std::move(err)) << "\n"; +} + +RunInTerminalDebugAdapterCommChannel::RunInTerminalDebugAdapterCommChannel( + StringRef comm_file) + : m_io(comm_file, "runInTerminal launcher") {} + +// Can't use \a std::future because it doesn't compile on Windows +std::future +RunInTerminalDebugAdapterCommChannel::NotifyDidAttach() { + return std::async(std::launch::async, [&]() { + lldb::SBError error; + if (llvm::Error err = + m_io.SendJSON(RunInTerminalMessageDidAttach().ToJSON())) + error.SetErrorString(llvm::toString(std::move(err)).c_str()); + return error; + }); +} + +Expected RunInTerminalDebugAdapterCommChannel::GetLauncherPid() { + if (Expected message = + GetNextMessage(m_io, std::chrono::seconds(20))) { + if (message.get()->kind == eRunInTerminalMessageKindPID) + return message.get()->GetAsPidMessage()->pid; + return ToError(*message.get()); + } else { + return message.takeError(); + } +} + +std::string RunInTerminalDebugAdapterCommChannel::GetLauncherError() { + // We know there's been an error, so a small timeout is enough. + if (Expected message = + GetNextMessage(m_io, std::chrono::seconds(1))) + return toString(ToError(*message.get())); + else + return toString(message.takeError()); +} + +Expected> CreateRunInTerminalCommFile() { + SmallString<256> comm_file; + if (std::error_code EC = sys::fs::getPotentiallyUniqueTempFileName( + "lldb-vscode-run-in-terminal-comm", "", comm_file)) + return createStringError(EC, "Error making unique file name for " + "runInTerminal communication files"); + + return CreateFifoFile(comm_file.str()); +} + +} // namespace lldb_vscode diff --git a/gnu/llvm/lldb/tools/lldb-vscode/RunInTerminal.h b/gnu/llvm/lldb/tools/lldb-vscode/RunInTerminal.h new file mode 100644 index 00000000000..cdccdd6bcf9 --- /dev/null +++ b/gnu/llvm/lldb/tools/lldb-vscode/RunInTerminal.h @@ -0,0 +1,129 @@ +//===-- RunInTerminal.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_TOOLS_LLDB_VSCODE_RUNINTERMINAL_H +#define LLDB_TOOLS_LLDB_VSCODE_RUNINTERMINAL_H + +#include "FifoFiles.h" + +#include +#include + +namespace lldb_vscode { + +enum RunInTerminalMessageKind { + eRunInTerminalMessageKindPID = 0, + eRunInTerminalMessageKindError, + eRunInTerminalMessageKindDidAttach, +}; + +struct RunInTerminalMessage; +struct RunInTerminalMessagePid; +struct RunInTerminalMessageError; +struct RunInTerminalMessageDidAttach; + +struct RunInTerminalMessage { + RunInTerminalMessage(RunInTerminalMessageKind kind); + + virtual ~RunInTerminalMessage() = default; + + /// Serialize this object to JSON + virtual llvm::json::Value ToJSON() const = 0; + + const RunInTerminalMessagePid *GetAsPidMessage() const; + + const RunInTerminalMessageError *GetAsErrorMessage() const; + + RunInTerminalMessageKind kind; +}; + +using RunInTerminalMessageUP = std::unique_ptr; + +struct RunInTerminalMessagePid : RunInTerminalMessage { + RunInTerminalMessagePid(lldb::pid_t pid); + + llvm::json::Value ToJSON() const override; + + lldb::pid_t pid; +}; + +struct RunInTerminalMessageError : RunInTerminalMessage { + RunInTerminalMessageError(llvm::StringRef error); + + llvm::json::Value ToJSON() const override; + + std::string error; +}; + +struct RunInTerminalMessageDidAttach : RunInTerminalMessage { + RunInTerminalMessageDidAttach(); + + llvm::json::Value ToJSON() const override; +}; + +class RunInTerminalLauncherCommChannel { +public: + RunInTerminalLauncherCommChannel(llvm::StringRef comm_file); + + /// Wait until the debug adaptor attaches. + /// + /// \param[in] timeout + /// How long to wait to be attached. + // + /// \return + /// An \a llvm::Error object in case of errors or if this operation times + /// out. + llvm::Error WaitUntilDebugAdaptorAttaches(std::chrono::milliseconds timeout); + + /// Notify the debug adaptor this process' pid. + /// + /// \return + /// An \a llvm::Error object in case of errors or if this operation times + /// out. + llvm::Error NotifyPid(); + + /// Notify the debug adaptor that there's been an error. + void NotifyError(llvm::StringRef error); + +private: + FifoFileIO m_io; +}; + +class RunInTerminalDebugAdapterCommChannel { +public: + RunInTerminalDebugAdapterCommChannel(llvm::StringRef comm_file); + + /// Notify the runInTerminal launcher that it was attached. + /// + /// \return + /// A future indicated whether the runInTerminal launcher received the + /// message correctly or not. + std::future NotifyDidAttach(); + + /// Fetch the pid of the runInTerminal launcher. + /// + /// \return + /// An \a llvm::Error object in case of errors or if this operation times + /// out. + llvm::Expected GetLauncherPid(); + + /// Fetch any errors emitted by the runInTerminal launcher or return a + /// default error message if a certain timeout if reached. + std::string GetLauncherError(); + +private: + FifoFileIO m_io; +}; + +/// Create a fifo file used to communicate the debug adaptor with +/// the runInTerminal launcher. +llvm::Expected> CreateRunInTerminalCommFile(); + +} // namespace lldb_vscode + +#endif // LLDB_TOOLS_LLDB_VSCODE_RUNINTERMINAL_H diff --git a/gnu/llvm/lldb/tools/lldb-vscode/SourceBreakpoint.h b/gnu/llvm/lldb/tools/lldb-vscode/SourceBreakpoint.h index 95f192beff8..2891d57ee8a 100644 --- a/gnu/llvm/lldb/tools/lldb-vscode/SourceBreakpoint.h +++ b/gnu/llvm/lldb/tools/lldb-vscode/SourceBreakpoint.h @@ -9,8 +9,8 @@ #ifndef LLDB_TOOLS_LLDB_VSCODE_SOURCEBREAKPOINT_H #define LLDB_TOOLS_LLDB_VSCODE_SOURCEBREAKPOINT_H -#include "llvm/ADT/StringRef.h" #include "BreakpointBase.h" +#include "llvm/ADT/StringRef.h" namespace lldb_vscode { diff --git a/gnu/llvm/lldb/tools/lldb-vscode/VSCode.cpp b/gnu/llvm/lldb/tools/lldb-vscode/VSCode.cpp index 4a30aef3a6d..a67fdd73522 100644 --- a/gnu/llvm/lldb/tools/lldb-vscode/VSCode.cpp +++ b/gnu/llvm/lldb/tools/lldb-vscode/VSCode.cpp @@ -6,9 +6,11 @@ // //===----------------------------------------------------------------------===// -#include +#include +#include #include #include +#include #include "LLDBUtils.h" #include "VSCode.h" @@ -16,9 +18,9 @@ #if defined(_WIN32) #define NOMINMAX -#include #include #include +#include #endif using namespace lldb_vscode; @@ -38,12 +40,15 @@ VSCode::VSCode() {"swift_catch", "Swift Catch", lldb::eLanguageTypeSwift}, {"swift_throw", "Swift Throw", lldb::eLanguageTypeSwift}}), focus_tid(LLDB_INVALID_THREAD_ID), sent_terminated_event(false), - stop_at_entry(false), is_attach(false) { + stop_at_entry(false), is_attach(false), reverse_request_seq(0), + waiting_for_run_in_terminal(false), + progress_event_reporter( + [&](const ProgressEvent &event) { SendJSON(event.ToJSON()); }) { const char *log_file_path = getenv("LLDBVSCODE_LOG"); #if defined(_WIN32) -// Windows opens stdout and stdin in text mode which converts \n to 13,10 -// while the value is just 10 on Darwin/Linux. Setting the file mode to binary -// fixes this. + // Windows opens stdout and stdin in text mode which converts \n to 13,10 + // while the value is just 10 on Darwin/Linux. Setting the file mode to binary + // fixes this. int result = _setmode(fileno(stdout), _O_BINARY); assert(result); result = _setmode(fileno(stdin), _O_BINARY); @@ -54,8 +59,7 @@ VSCode::VSCode() log.reset(new std::ofstream(log_file_path)); } -VSCode::~VSCode() { -} +VSCode::~VSCode() {} int64_t VSCode::GetLineForPC(int64_t sourceReference, lldb::addr_t pc) const { auto pos = source_map.find(sourceReference); @@ -225,6 +229,104 @@ void VSCode::SendOutput(OutputType o, const llvm::StringRef output) { SendJSON(llvm::json::Value(std::move(event))); } +// interface ProgressStartEvent extends Event { +// event: 'progressStart'; +// +// body: { +// /** +// * An ID that must be used in subsequent 'progressUpdate' and +// 'progressEnd' +// * events to make them refer to the same progress reporting. +// * IDs must be unique within a debug session. +// */ +// progressId: string; +// +// /** +// * Mandatory (short) title of the progress reporting. Shown in the UI to +// * describe the long running operation. +// */ +// title: string; +// +// /** +// * The request ID that this progress report is related to. If specified a +// * debug adapter is expected to emit +// * progress events for the long running request until the request has +// been +// * either completed or cancelled. +// * If the request ID is omitted, the progress report is assumed to be +// * related to some general activity of the debug adapter. +// */ +// requestId?: number; +// +// /** +// * If true, the request that reports progress may be canceled with a +// * 'cancel' request. +// * So this property basically controls whether the client should use UX +// that +// * supports cancellation. +// * Clients that don't support cancellation are allowed to ignore the +// * setting. +// */ +// cancellable?: boolean; +// +// /** +// * Optional, more detailed progress message. +// */ +// message?: string; +// +// /** +// * Optional progress percentage to display (value range: 0 to 100). If +// * omitted no percentage will be shown. +// */ +// percentage?: number; +// }; +// } +// +// interface ProgressUpdateEvent extends Event { +// event: 'progressUpdate'; +// +// body: { +// /** +// * The ID that was introduced in the initial 'progressStart' event. +// */ +// progressId: string; +// +// /** +// * Optional, more detailed progress message. If omitted, the previous +// * message (if any) is used. +// */ +// message?: string; +// +// /** +// * Optional progress percentage to display (value range: 0 to 100). If +// * omitted no percentage will be shown. +// */ +// percentage?: number; +// }; +// } +// +// interface ProgressEndEvent extends Event { +// event: 'progressEnd'; +// +// body: { +// /** +// * The ID that was introduced in the initial 'ProgressStartEvent'. +// */ +// progressId: string; +// +// /** +// * Optional, more detailed progress message. If omitted, the previous +// * message (if any) is used. +// */ +// message?: string; +// }; +// } + +void VSCode::SendProgressEvent(uint64_t progress_id, const char *message, + uint64_t completed, uint64_t total) { + progress_event_reporter.Push(progress_id, message, completed, total); +} + void __attribute__((format(printf, 3, 4))) VSCode::SendFormattedOutput(OutputType o, const char *format, ...) { char buffer[1024]; @@ -232,8 +334,8 @@ VSCode::SendFormattedOutput(OutputType o, const char *format, ...) { va_start(args, format); int actual_length = vsnprintf(buffer, sizeof(buffer), format, args); va_end(args); - SendOutput(o, llvm::StringRef(buffer, - std::min(actual_length, sizeof(buffer)))); + SendOutput( + o, llvm::StringRef(buffer, std::min(actual_length, sizeof(buffer)))); } int64_t VSCode::GetNextSourceReference() { @@ -313,9 +415,9 @@ void VSCode::RunTerminateCommands() { RunLLDBCommands("Running terminateCommands:", terminate_commands); } -lldb::SBTarget VSCode::CreateTargetFromArguments( - const llvm::json::Object &arguments, - lldb::SBError &error) { +lldb::SBTarget +VSCode::CreateTargetFromArguments(const llvm::json::Object &arguments, + lldb::SBError &error) { // Grab the name of the program we need to debug and create a target using // the given program as an argument. Executable file can be a source of target // architecture and platform, if they differ from the host. Setting exe path @@ -330,18 +432,15 @@ lldb::SBTarget VSCode::CreateTargetFromArguments( llvm::StringRef platform_name = GetString(arguments, "platformName"); llvm::StringRef program = GetString(arguments, "program"); auto target = this->debugger.CreateTarget( - program.data(), - target_triple.data(), - platform_name.data(), - true, // Add dependent modules. - error - ); + program.data(), target_triple.data(), platform_name.data(), + true, // Add dependent modules. + error); if (error.Fail()) { // Update message if there was an error. error.SetErrorStringWithFormat( - "Could not create a target for a program '%s': %s.", - program.data(), error.GetCString()); + "Could not create a target for a program '%s': %s.", program.data(), + error.GetCString()); } return target; @@ -358,12 +457,74 @@ void VSCode::SetTarget(const lldb::SBTarget target) { lldb::SBTarget::eBroadcastBitBreakpointChanged); listener.StartListeningForEvents(this->broadcaster, eBroadcastBitStopEventThread); - listener.StartListeningForEvents( - this->target.GetBroadcaster(), - lldb::SBTarget::eBroadcastBitModulesLoaded | - lldb::SBTarget::eBroadcastBitModulesUnloaded | - lldb::SBTarget::eBroadcastBitSymbolsLoaded); } } +PacketStatus VSCode::GetNextObject(llvm::json::Object &object) { + std::string json = ReadJSON(); + if (json.empty()) + return PacketStatus::EndOfFile; + + llvm::StringRef json_sref(json); + llvm::Expected json_value = llvm::json::parse(json_sref); + if (!json_value) { + auto error = json_value.takeError(); + if (log) { + std::string error_str; + llvm::raw_string_ostream strm(error_str); + strm << error; + strm.flush(); + *log << "error: failed to parse JSON: " << error_str << std::endl + << json << std::endl; + } + return PacketStatus::JSONMalformed; + } + object = *json_value->getAsObject(); + if (!json_value->getAsObject()) { + if (log) + *log << "error: json packet isn't a object" << std::endl; + return PacketStatus::JSONNotObject; + } + return PacketStatus::Success; +} + +bool VSCode::HandleObject(const llvm::json::Object &object) { + const auto packet_type = GetString(object, "type"); + if (packet_type == "request") { + const auto command = GetString(object, "command"); + auto handler_pos = request_handlers.find(std::string(command)); + if (handler_pos != request_handlers.end()) { + handler_pos->second(object); + return true; // Success + } else { + if (log) + *log << "error: unhandled command \"" << command.data() << std::endl; + return false; // Fail + } + } + return false; +} + +PacketStatus VSCode::SendReverseRequest(llvm::json::Object request, + llvm::json::Object &response) { + request.try_emplace("seq", ++reverse_request_seq); + SendJSON(llvm::json::Value(std::move(request))); + while (true) { + PacketStatus status = GetNextObject(response); + const auto packet_type = GetString(response, "type"); + if (packet_type == "response") + return status; + else { + // Not our response, we got another packet + HandleObject(response); + } + } + return PacketStatus::EndOfFile; +} + +void VSCode::RegisterRequestCallback(std::string request, + RequestCallback callback) { + request_handlers[request] = callback; +} + } // namespace lldb_vscode diff --git a/gnu/llvm/lldb/tools/lldb-vscode/VSCode.h b/gnu/llvm/lldb/tools/lldb-vscode/VSCode.h index ddb4c09a417..29796767c9d 100644 --- a/gnu/llvm/lldb/tools/lldb-vscode/VSCode.h +++ b/gnu/llvm/lldb/tools/lldb-vscode/VSCode.h @@ -9,16 +9,20 @@ #ifndef LLDB_TOOLS_LLDB_VSCODE_VSCODE_H #define LLDB_TOOLS_LLDB_VSCODE_VSCODE_H +#include "llvm/Config/llvm-config.h" // for LLVM_ON_UNIX + +#include +#include #include #include #include -#include #include #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" +#include "llvm/Support/JSON.h" #include "llvm/Support/raw_ostream.h" #include "lldb/API/SBAttachInfo.h" @@ -45,6 +49,8 @@ #include "ExceptionBreakpoint.h" #include "FunctionBreakpoint.h" #include "IOStream.h" +#include "ProgressEvent.h" +#include "RunInTerminal.h" #include "SourceBreakpoint.h" #include "SourceReference.h" @@ -63,9 +69,22 @@ typedef llvm::DenseMap SourceBreakpointMap; typedef llvm::StringMap FunctionBreakpointMap; enum class OutputType { Console, Stdout, Stderr, Telemetry }; -enum VSCodeBroadcasterBits { eBroadcastBitStopEventThread = 1u << 0 }; +enum VSCodeBroadcasterBits { + eBroadcastBitStopEventThread = 1u << 0, + eBroadcastBitStopProgressThread = 1u << 1 +}; + +typedef void (*RequestCallback)(const llvm::json::Object &command); + +enum class PacketStatus { + Success = 0, + EndOfFile, + JSONMalformed, + JSONNotObject +}; struct VSCode { + std::string debug_adaptor_path; InputStream input; OutputStream output; lldb::SBDebugger debugger; @@ -76,6 +95,7 @@ struct VSCode { int64_t num_locals; int64_t num_globals; std::thread event_thread; + std::thread progress_event_thread; std::unique_ptr log; llvm::DenseMap addr_to_source_ref; llvm::DenseMap source_map; @@ -91,6 +111,10 @@ struct VSCode { bool sent_terminated_event; bool stop_at_entry; bool is_attach; + uint32_t reverse_request_seq; + std::map request_handlers; + bool waiting_for_run_in_terminal; + ProgressEventReporter progress_event_reporter; // Keep track of the last stop thread index IDs as threads won't go away // unless we send a "thread" event to indicate the thread exited. llvm::DenseSet thread_ids; @@ -101,10 +125,6 @@ struct VSCode { int64_t GetLineForPC(int64_t sourceReference, lldb::addr_t pc) const; ExceptionBreakpoint *GetExceptionBreakpoint(const std::string &filter); ExceptionBreakpoint *GetExceptionBreakpoint(const lldb::break_id_t bp_id); - // Send the JSON in "json_str" to the "out" stream. Correctly send the - // "Content-Length:" field followed by the length, followed by the raw - // JSON bytes. - void SendJSON(const std::string &json_str); // Serialize the JSON value into a string and send the JSON packet to // the "out" stream. @@ -114,6 +134,9 @@ struct VSCode { void SendOutput(OutputType o, const llvm::StringRef output); + void SendProgressEvent(uint64_t progress_id, const char *message, + uint64_t completed, uint64_t total); + void __attribute__((format(printf, 3, 4))) SendFormattedOutput(OutputType o, const char *format, ...); @@ -146,13 +169,48 @@ struct VSCode { /// /// \return /// An SBTarget object. - lldb::SBTarget CreateTargetFromArguments( - const llvm::json::Object &arguments, - lldb::SBError &error); + lldb::SBTarget CreateTargetFromArguments(const llvm::json::Object &arguments, + lldb::SBError &error); /// Set given target object as a current target for lldb-vscode and start /// listeing for its breakpoint events. void SetTarget(const lldb::SBTarget target); + + const std::map &GetRequestHandlers(); + + PacketStatus GetNextObject(llvm::json::Object &object); + bool HandleObject(const llvm::json::Object &object); + + /// Send a Debug Adapter Protocol reverse request to the IDE + /// + /// \param[in] request + /// The payload of the request to send. + /// + /// \param[out] response + /// The response of the IDE. It might be undefined if there was an error. + /// + /// \return + /// A \a PacketStatus object indicating the sucess or failure of the + /// request. + PacketStatus SendReverseRequest(llvm::json::Object request, + llvm::json::Object &response); + + /// Registers a callback handler for a Debug Adapter Protocol request + /// + /// \param[in] request + /// The name of the request following the Debug Adapter Protocol + /// specification. + /// + /// \param[in] callback + /// The callback to execute when the given request is triggered by the + /// IDE. + void RegisterRequestCallback(std::string request, RequestCallback callback); + +private: + // Send the JSON in "json_str" to the "out" stream. Correctly send the + // "Content-Length:" field followed by the length, followed by the raw + // JSON bytes. + void SendJSON(const std::string &json_str); }; extern VSCode g_vsc; diff --git a/gnu/llvm/lldb/tools/lldb-vscode/lldb-vscode.cpp b/gnu/llvm/lldb/tools/lldb-vscode/lldb-vscode.cpp index 27ee832677d..9ab13cf140c 100644 --- a/gnu/llvm/lldb/tools/lldb-vscode/lldb-vscode.cpp +++ b/gnu/llvm/lldb/tools/lldb-vscode/lldb-vscode.cpp @@ -6,12 +6,14 @@ // //===----------------------------------------------------------------------===// -#include -#include -#include -#include -#include -#include +#include "VSCode.h" + +#include +#include +#include +#include +#include +#include #include #include #if defined(_WIN32) @@ -42,17 +44,21 @@ #include #include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/ScopeExit.h" #include "llvm/Option/Arg.h" #include "llvm/Option/ArgList.h" #include "llvm/Option/Option.h" #include "llvm/Support/Errno.h" #include "llvm/Support/FileSystem.h" +#include "llvm/Support/InitLLVM.h" #include "llvm/Support/Path.h" +#include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/raw_ostream.h" #include "JSONUtils.h" #include "LLDBUtils.h" -#include "VSCode.h" +#include "OutputRedirector.h" #if defined(_WIN32) #ifndef PATH_MAX @@ -173,6 +179,19 @@ void SendThreadExitedEvent(lldb::tid_t tid) { // Send a "terminated" event to indicate the process is done being // debugged. void SendTerminatedEvent() { + // If an inferior exits prior to the processing of a disconnect request, then + // the threads executing EventThreadFunction and request_discontinue + // respectively may call SendTerminatedEvent simultaneously. Without any + // synchronization, the thread executing EventThreadFunction may set + // g_vsc.sent_terminated_event before the thread executing + // request_discontinue has had a chance to test it, in which case the latter + // would move ahead to issue a response to the disconnect request. Said + // response may get dispatched ahead of the terminated event compelling the + // client to terminate the debug session without consuming any console output + // that might've been generated by the execution of terminateCommands. So, + // synchronize simultaneous calls to SendTerminatedEvent. + static std::mutex mutex; + std::lock_guard locker(mutex); if (!g_vsc.sent_terminated_event) { g_vsc.sent_terminated_event = true; g_vsc.RunTerminateCommands(); @@ -343,11 +362,39 @@ void SendStdOutStdErr(lldb::SBProcess &process) { char buffer[1024]; size_t count; while ((count = process.GetSTDOUT(buffer, sizeof(buffer))) > 0) - g_vsc.SendOutput(OutputType::Stdout, llvm::StringRef(buffer, count)); + g_vsc.SendOutput(OutputType::Stdout, llvm::StringRef(buffer, count)); while ((count = process.GetSTDERR(buffer, sizeof(buffer))) > 0) g_vsc.SendOutput(OutputType::Stderr, llvm::StringRef(buffer, count)); } +void ProgressEventThreadFunction() { + lldb::SBListener listener("lldb-vscode.progress.listener"); + g_vsc.debugger.GetBroadcaster().AddListener( + listener, lldb::SBDebugger::eBroadcastBitProgress); + g_vsc.broadcaster.AddListener(listener, eBroadcastBitStopProgressThread); + lldb::SBEvent event; + bool done = false; + while (!done) { + if (listener.WaitForEvent(1, event)) { + const auto event_mask = event.GetType(); + if (event.BroadcasterMatchesRef(g_vsc.broadcaster)) { + if (event_mask & eBroadcastBitStopProgressThread) { + done = true; + } + } else { + uint64_t progress_id = 0; + uint64_t completed = 0; + uint64_t total = 0; + bool is_debugger_specific = false; + const char *message = lldb::SBDebugger::GetProgressFromEvent( + event, progress_id, completed, total, is_debugger_specific); + if (message) + g_vsc.SendProgressEvent(progress_id, message, completed, total); + } + } + } +} + // All events from the debugger, target, process, thread and frames are // received in this function that runs in its own thread. We are using a // "FILE *" to output packets back to VS Code and they have mutexes in them @@ -435,30 +482,6 @@ void EventThreadFunction() { g_vsc.SendJSON(llvm::json::Value(std::move(bp_event))); } } - } else if (lldb::SBTarget::EventIsTargetEvent(event)) { - if (event_mask & lldb::SBTarget::eBroadcastBitModulesLoaded || - event_mask & lldb::SBTarget::eBroadcastBitModulesUnloaded || - event_mask & lldb::SBTarget::eBroadcastBitSymbolsLoaded) { - int num_modules = lldb::SBTarget::GetNumModulesFromEvent(event); - for (int i = 0; i < num_modules; i++) { - auto module = lldb::SBTarget::GetModuleAtIndexFromEvent(i, event); - auto module_event = CreateEventObject("module"); - llvm::json::Value module_value = CreateModule(module); - llvm::json::Object body; - if (event_mask & lldb::SBTarget::eBroadcastBitModulesLoaded) { - body.try_emplace("reason", "new"); - } else if (event_mask & - lldb::SBTarget::eBroadcastBitModulesUnloaded) { - body.try_emplace("reason", "removed"); - } else if (event_mask & - lldb::SBTarget::eBroadcastBitSymbolsLoaded) { - body.try_emplace("reason", "changed"); - } - body.try_emplace("module", module_value); - module_event.try_emplace("body", std::move(body)); - g_vsc.SendJSON(llvm::json::Value(std::move(module_event))); - } - } } else if (event.BroadcasterMatchesRef(g_vsc.broadcaster)) { if (event_mask & eBroadcastBitStopEventThread) { done = true; @@ -561,6 +584,8 @@ void request_attach(const llvm::json::Object &request) { llvm::StringRef core_file = GetString(arguments, "coreFile"); g_vsc.stop_at_entry = core_file.empty() ? GetBoolean(arguments, "stopOnEntry", false) : true; + std::vector postRunCommands = + GetStrings(arguments, "postRunCommands"); const llvm::StringRef debuggerRoot = GetString(arguments, "debuggerRoot"); // This is a hack for loading DWARF in .o files on Mac where the .o files @@ -629,12 +654,14 @@ void request_attach(const llvm::json::Object &request) { if (error.Fail()) { response["success"] = llvm::json::Value(false); EmplaceSafeString(response, "message", std::string(error.GetCString())); + } else { + g_vsc.RunLLDBCommands("Running postRunCommands:", postRunCommands); } + g_vsc.SendJSON(llvm::json::Value(std::move(response))); if (error.Success()) { SendProcessEvent(Attach); g_vsc.SendJSON(CreateEventObject("initialized")); - // SendThreadStoppedEvent(); } } @@ -829,6 +856,10 @@ void request_disconnect(const llvm::json::Object &request) { g_vsc.broadcaster.BroadcastEventByType(eBroadcastBitStopEventThread); g_vsc.event_thread.join(); } + if (g_vsc.progress_event_thread.joinable()) { + g_vsc.broadcaster.BroadcastEventByType(eBroadcastBitStopProgressThread); + g_vsc.progress_event_thread.join(); + } } void request_exceptionInfo(const llvm::json::Object &request) { @@ -873,7 +904,9 @@ void request_exceptionInfo(const llvm::json::Object &request) { // "CompletionsRequest": { // "allOf": [ { "$ref": "#/definitions/Request" }, { // "type": "object", -// "description": "Returns a list of possible completions for a given caret position and text.\nThe CompletionsRequest may only be called if the 'supportsCompletionsRequest' capability exists and is true.", +// "description": "Returns a list of possible completions for a given caret +// position and text.\nThe CompletionsRequest may only be called if the +// 'supportsCompletionsRequest' capability exists and is true.", // "properties": { // "command": { // "type": "string", @@ -892,19 +925,23 @@ void request_exceptionInfo(const llvm::json::Object &request) { // "properties": { // "frameId": { // "type": "integer", -// "description": "Returns completions in the scope of this stack frame. If not specified, the completions are returned for the global scope." +// "description": "Returns completions in the scope of this stack frame. +// If not specified, the completions are returned for the global scope." // }, // "text": { // "type": "string", -// "description": "One or more source lines. Typically this is the text a user has typed into the debug console before he asked for completion." +// "description": "One or more source lines. Typically this is the text a +// user has typed into the debug console before he asked for completion." // }, // "column": { // "type": "integer", -// "description": "The character position for which to determine the completion proposals." +// "description": "The character position for which to determine the +// completion proposals." // }, // "line": { // "type": "integer", -// "description": "An optional line for which to determine the completion proposals. If missing the first line of the text is assumed." +// "description": "An optional line for which to determine the completion +// proposals. If missing the first line of the text is assumed." // } // }, // "required": [ "text", "column" ] @@ -933,39 +970,51 @@ void request_exceptionInfo(const llvm::json::Object &request) { // }, // "CompletionItem": { // "type": "object", -// "description": "CompletionItems are the suggestions returned from the CompletionsRequest.", -// "properties": { +// "description": "CompletionItems are the suggestions returned from the +// CompletionsRequest.", "properties": { // "label": { // "type": "string", -// "description": "The label of this completion item. By default this is also the text that is inserted when selecting this completion." +// "description": "The label of this completion item. By default this is +// also the text that is inserted when selecting this completion." // }, // "text": { // "type": "string", -// "description": "If text is not falsy then it is inserted instead of the label." +// "description": "If text is not falsy then it is inserted instead of the +// label." // }, // "sortText": { // "type": "string", -// "description": "A string that should be used when comparing this item with other items. When `falsy` the label is used." +// "description": "A string that should be used when comparing this item +// with other items. When `falsy` the label is used." // }, // "type": { // "$ref": "#/definitions/CompletionItemType", -// "description": "The item's type. Typically the client uses this information to render the item in the UI with an icon." +// "description": "The item's type. Typically the client uses this +// information to render the item in the UI with an icon." // }, // "start": { // "type": "integer", -// "description": "This value determines the location (in the CompletionsRequest's 'text' attribute) where the completion text is added.\nIf missing the text is added at the location specified by the CompletionsRequest's 'column' attribute." +// "description": "This value determines the location (in the +// CompletionsRequest's 'text' attribute) where the completion text is +// added.\nIf missing the text is added at the location specified by the +// CompletionsRequest's 'column' attribute." // }, // "length": { // "type": "integer", -// "description": "This value determines how many characters are overwritten by the completion text.\nIf missing the value 0 is assumed which results in the completion text being inserted." +// "description": "This value determines how many characters are +// overwritten by the completion text.\nIf missing the value 0 is assumed +// which results in the completion text being inserted." // } // }, // "required": [ "label" ] // }, // "CompletionItemType": { // "type": "string", -// "description": "Some predefined types for the CompletionItem. Please note that not all clients have specific icons for all of them.", -// "enum": [ "method", "function", "constructor", "field", "variable", "class", "interface", "module", "property", "unit", "value", "enum", "keyword", "snippet", "text", "color", "file", "reference", "customcolor" ] +// "description": "Some predefined types for the CompletionItem. Please note +// that not all clients have specific icons for all of them.", "enum": [ +// "method", "function", "constructor", "field", "variable", "class", +// "interface", "module", "property", "unit", "value", "enum", "keyword", +// "snippet", "text", "color", "file", "reference", "customcolor" ] // } void request_completions(const llvm::json::Object &request) { llvm::json::Object response; @@ -992,9 +1041,7 @@ void request_completions(const llvm::json::Object &request) { lldb::SBStringList matches; lldb::SBStringList descriptions; g_vsc.debugger.GetCommandInterpreter().HandleCompletionWithDescriptions( - text.c_str(), - actual_column, - 0, -1, matches, descriptions); + text.c_str(), actual_column, 0, -1, matches, descriptions); size_t count = std::min((uint32_t)100, matches.GetSize()); targets.reserve(count); for (size_t i = 0; i < count; i++) { @@ -1004,8 +1051,8 @@ void request_completions(const llvm::json::Object &request) { llvm::json::Object item; llvm::StringRef match_ref = match; - for(llvm::StringRef commit_point: {".", "->"}) { - if (match_ref.contains(commit_point)){ + for (llvm::StringRef commit_point : {".", "->"}) { + if (match_ref.contains(commit_point)) { match_ref = match_ref.rsplit(commit_point).second; } } @@ -1132,6 +1179,7 @@ void request_evaluate(const llvm::json::Object &request) { auto arguments = request.getObject("arguments"); lldb::SBFrame frame = g_vsc.GetLLDBFrame(*arguments); const auto expression = GetString(arguments, "expression"); + llvm::StringRef context = GetString(arguments, "context"); if (!expression.empty() && expression[0] == '`') { auto result = @@ -1140,13 +1188,17 @@ void request_evaluate(const llvm::json::Object &request) { body.try_emplace("variablesReference", (int64_t)0); } else { // Always try to get the answer from the local variables if possible. If - // this fails, then actually evaluate an expression using the expression - // parser. "frame variable" is more reliable than the expression parser in + // this fails, then if the context is not "hover", actually evaluate an + // expression using the expression parser. + // + // "frame variable" is more reliable than the expression parser in // many cases and it is faster. lldb::SBValue value = frame.GetValueForVariablePath( expression.data(), lldb::eDynamicDontRunTarget); - if (value.GetError().Fail()) + + if (value.GetError().Fail() && context != "hover") value = frame.EvaluateExpression(expression.data()); + if (value.GetError().Fail()) { response["success"] = llvm::json::Value(false); // This error object must live until we're done with the pointer returned @@ -1160,7 +1212,8 @@ void request_evaluate(const llvm::json::Object &request) { } else { SetValueForKey(value, body, "result"); auto value_typename = value.GetType().GetDisplayTypeName(); - EmplaceSafeString(body, "type", value_typename ? value_typename : NO_TYPENAME); + EmplaceSafeString(body, "type", + value_typename ? value_typename : NO_TYPENAME); if (value.MightHaveChildren()) { auto variablesReference = VARIDX_TO_VARREF(g_vsc.variables.GetSize()); g_vsc.variables.Append(value); @@ -1174,26 +1227,26 @@ void request_evaluate(const llvm::json::Object &request) { g_vsc.SendJSON(llvm::json::Value(std::move(response))); } -// "getCompileUnitsRequest": { +// "compileUnitsRequest": { // "allOf": [ { "$ref": "#/definitions/Request" }, { // "type": "object", // "description": "Compile Unit request; value of command field is -// 'getCompileUnits'.", +// 'compileUnits'.", // "properties": { // "command": { // "type": "string", -// "enum": [ "getCompileUnits" ] +// "enum": [ "compileUnits" ] // }, // "arguments": { -// "$ref": "#/definitions/getCompileUnitRequestArguments" +// "$ref": "#/definitions/compileUnitRequestArguments" // } // }, // "required": [ "command", "arguments" ] // }] // }, -// "getCompileUnitsRequestArguments": { +// "compileUnitsRequestArguments": { // "type": "object", -// "description": "Arguments for 'getCompileUnits' request.", +// "description": "Arguments for 'compileUnits' request.", // "properties": { // "moduleId": { // "type": "string", @@ -1202,23 +1255,21 @@ void request_evaluate(const llvm::json::Object &request) { // }, // "required": [ "moduleId" ] // }, -// "getCompileUnitsResponse": { +// "compileUnitsResponse": { // "allOf": [ { "$ref": "#/definitions/Response" }, { // "type": "object", -// "description": "Response to 'getCompileUnits' request.", +// "description": "Response to 'compileUnits' request.", // "properties": { // "body": { -// "description": "Response to 'getCompileUnits' request. Array of +// "description": "Response to 'compileUnits' request. Array of // paths of compile units." // } // } // }] // } - -void request_getCompileUnits(const llvm::json::Object &request) { +void request_compileUnits(const llvm::json::Object &request) { llvm::json::Object response; FillResponse(request, response); - lldb::SBProcess process = g_vsc.target.GetProcess(); llvm::json::Object body; llvm::json::Array units; auto arguments = request.getObject("arguments"); @@ -1229,8 +1280,8 @@ void request_getCompileUnits(const llvm::json::Object &request) { if (module_id == curr_module.GetUUIDString()) { int num_units = curr_module.GetNumCompileUnits(); for (int j = 0; j < num_units; j++) { - auto curr_unit = curr_module.GetCompileUnitAtIndex(j);\ - units.emplace_back(CreateCompileUnit(curr_unit));\ + auto curr_unit = curr_module.GetCompileUnitAtIndex(j); + units.emplace_back(CreateCompileUnit(curr_unit)); } body.try_emplace("compileUnits", std::move(units)); break; @@ -1240,6 +1291,48 @@ void request_getCompileUnits(const llvm::json::Object &request) { g_vsc.SendJSON(llvm::json::Value(std::move(response))); } +// "modulesRequest": { +// "allOf": [ { "$ref": "#/definitions/Request" }, { +// "type": "object", +// "description": "Modules request; value of command field is +// 'modules'.", +// "properties": { +// "command": { +// "type": "string", +// "enum": [ "modules" ] +// }, +// }, +// "required": [ "command" ] +// }] +// }, +// "modulesResponse": { +// "allOf": [ { "$ref": "#/definitions/Response" }, { +// "type": "object", +// "description": "Response to 'modules' request.", +// "properties": { +// "body": { +// "description": "Response to 'modules' request. Array of +// module objects." +// } +// } +// }] +// } +void request_modules(const llvm::json::Object &request) { + llvm::json::Object response; + FillResponse(request, response); + + llvm::json::Array modules; + for (size_t i = 0; i < g_vsc.target.GetNumModules(); i++) { + lldb::SBModule module = g_vsc.target.GetModuleAtIndex(i); + modules.emplace_back(CreateModule(module)); + } + + llvm::json::Object body; + body.try_emplace("modules", std::move(modules)); + response.try_emplace("body", std::move(body)); + g_vsc.SendJSON(llvm::json::Value(std::move(response))); +} + // "InitializeRequest": { // "allOf": [ { "$ref": "#/definitions/Request" }, { // "type": "object", @@ -1318,6 +1411,8 @@ void request_getCompileUnits(const llvm::json::Object &request) { // } void request_initialize(const llvm::json::Object &request) { g_vsc.debugger = lldb::SBDebugger::Create(true /*source_init_files*/); + g_vsc.progress_event_thread = std::thread(ProgressEventThreadFunction); + // Create an empty target right away since we might get breakpoint requests // before we are given an executable to launch in a "launch" request, or a // executable when attaching to a process by process ID in a "attach" @@ -1357,6 +1452,9 @@ void request_initialize(const llvm::json::Object &request) { filters.emplace_back(CreateExceptionBreakpointFilter(exc_bp)); } body.try_emplace("exceptionBreakpointFilters", std::move(filters)); + // The debug adapter supports launching a debugee in intergrated VSCode + // terminal. + body.try_emplace("supportsRunInTerminalRequest", true); // The debug adapter supports stepping back via the stepBack and // reverseContinue requests. body.try_emplace("supportsStepBack", false); @@ -1411,11 +1509,77 @@ void request_initialize(const llvm::json::Object &request) { body.try_emplace("supportsDelayedStackTraceLoading", true); // The debug adapter supports the 'loadedSources' request. body.try_emplace("supportsLoadedSourcesRequest", false); + // The debug adapter supports sending progress reporting events. + body.try_emplace("supportsProgressReporting", true); response.try_emplace("body", std::move(body)); g_vsc.SendJSON(llvm::json::Value(std::move(response))); } +llvm::Error request_runInTerminal(const llvm::json::Object &launch_request) { + g_vsc.is_attach = true; + lldb::SBAttachInfo attach_info; + + llvm::Expected> comm_file_or_err = + CreateRunInTerminalCommFile(); + if (!comm_file_or_err) + return comm_file_or_err.takeError(); + FifoFile &comm_file = *comm_file_or_err.get(); + + RunInTerminalDebugAdapterCommChannel comm_channel(comm_file.m_path); + + llvm::json::Object reverse_request = CreateRunInTerminalReverseRequest( + launch_request, g_vsc.debug_adaptor_path, comm_file.m_path); + llvm::json::Object reverse_response; + lldb_vscode::PacketStatus status = + g_vsc.SendReverseRequest(reverse_request, reverse_response); + if (status != lldb_vscode::PacketStatus::Success) + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "Process cannot be launched by the IDE. %s", + comm_channel.GetLauncherError().c_str()); + + if (llvm::Expected pid = comm_channel.GetLauncherPid()) + attach_info.SetProcessID(*pid); + else + return pid.takeError(); + + g_vsc.debugger.SetAsync(false); + lldb::SBError error; + g_vsc.target.Attach(attach_info, error); + + if (error.Fail()) + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "Failed to attach to the target process. %s", + comm_channel.GetLauncherError().c_str()); + // This will notify the runInTerminal launcher that we attached. + // We have to make this async, as the function won't return until the launcher + // resumes and reads the data. + std::future did_attach_message_success = + comm_channel.NotifyDidAttach(); + + // We just attached to the runInTerminal launcher, which was waiting to be + // attached. We now resume it, so it can receive the didAttach notification + // and then perform the exec. Upon continuing, the debugger will stop the + // process right in the middle of the exec. To the user, what we are doing is + // transparent, as they will only be able to see the process since the exec, + // completely unaware of the preparatory work. + g_vsc.target.GetProcess().Continue(); + + // Now that the actual target is just starting (i.e. exec was just invoked), + // we return the debugger to its async state. + g_vsc.debugger.SetAsync(true); + + // If sending the notification failed, the launcher should be dead by now and + // the async didAttach notification should have an error message, so we + // return it. Otherwise, everything was a success. + did_attach_message_success.wait(); + error = did_attach_message_success.get(); + if (error.Success()) + return llvm::Error::success(); + return llvm::createStringError(llvm::inconvertibleErrorCode(), + error.GetCString()); +} + // "LaunchRequest": { // "allOf": [ { "$ref": "#/definitions/Request" }, { // "type": "object", @@ -1462,6 +1626,8 @@ void request_launch(const llvm::json::Object &request) { g_vsc.exit_commands = GetStrings(arguments, "exitCommands"); g_vsc.terminate_commands = GetStrings(arguments, "terminateCommands"); auto launchCommands = GetStrings(arguments, "launchCommands"); + std::vector postRunCommands = + GetStrings(arguments, "postRunCommands"); g_vsc.stop_at_entry = GetBoolean(arguments, "stopOnEntry", false); const llvm::StringRef debuggerRoot = GetString(arguments, "debuggerRoot"); @@ -1523,7 +1689,11 @@ void request_launch(const llvm::json::Object &request) { // Run any pre run LLDB commands the user specified in the launch.json g_vsc.RunPreRunCommands(); - if (launchCommands.empty()) { + + if (GetBoolean(arguments, "runInTerminal", false)) { + if (llvm::Error err = request_runInTerminal(request)) + error.SetErrorString(llvm::toString(std::move(err)).c_str()); + } else if (launchCommands.empty()) { // Disable async events so the launch will be successful when we return from // the launch call and the launch will happen synchronously g_vsc.debugger.SetAsync(false); @@ -1539,13 +1709,17 @@ void request_launch(const llvm::json::Object &request) { if (error.Fail()) { response["success"] = llvm::json::Value(false); EmplaceSafeString(response, "message", std::string(error.GetCString())); + } else { + g_vsc.RunLLDBCommands("Running postRunCommands:", postRunCommands); } + g_vsc.SendJSON(llvm::json::Value(std::move(response))); - SendProcessEvent(Launch); + if (g_vsc.is_attach) + SendProcessEvent(Attach); // this happens when doing runInTerminal + else + SendProcessEvent(Launch); g_vsc.SendJSON(llvm::json::Value(CreateEventObject("initialized"))); - // Reenable async events and start the event thread to catch async events. - // g_vsc.debugger.SetAsync(true); } // "NextRequest": { @@ -1862,27 +2036,32 @@ void request_setBreakpoints(const llvm::json::Object &request) { // Decode the source breakpoint infos for this "setBreakpoints" request SourceBreakpointMap request_bps; - for (const auto &bp : *breakpoints) { - auto bp_obj = bp.getAsObject(); - if (bp_obj) { - SourceBreakpoint src_bp(*bp_obj); - request_bps[src_bp.line] = src_bp; - - // We check if this breakpoint already exists to update it - auto existing_source_bps = g_vsc.source_breakpoints.find(path); - if (existing_source_bps != g_vsc.source_breakpoints.end()) { - const auto &existing_bp = existing_source_bps->second.find(src_bp.line); - if (existing_bp != existing_source_bps->second.end()) { - existing_bp->second.UpdateBreakpoint(src_bp); - AppendBreakpoint(existing_bp->second.bp, response_breakpoints, path, - src_bp.line); - continue; + // "breakpoints" may be unset, in which case we treat it the same as being set + // to an empty array. + if (breakpoints) { + for (const auto &bp : *breakpoints) { + auto bp_obj = bp.getAsObject(); + if (bp_obj) { + SourceBreakpoint src_bp(*bp_obj); + request_bps[src_bp.line] = src_bp; + + // We check if this breakpoint already exists to update it + auto existing_source_bps = g_vsc.source_breakpoints.find(path); + if (existing_source_bps != g_vsc.source_breakpoints.end()) { + const auto &existing_bp = + existing_source_bps->second.find(src_bp.line); + if (existing_bp != existing_source_bps->second.end()) { + existing_bp->second.UpdateBreakpoint(src_bp); + AppendBreakpoint(existing_bp->second.bp, response_breakpoints, path, + src_bp.line); + continue; + } } + // At this point the breakpoint is new + src_bp.SetBreakpoint(path.data()); + AppendBreakpoint(src_bp.bp, response_breakpoints, path, src_bp.line); + g_vsc.source_breakpoints[path][src_bp.line] = std::move(src_bp); } - // At this point the breakpoint is new - src_bp.SetBreakpoint(path.data()); - AppendBreakpoint(src_bp.bp, response_breakpoints, path, src_bp.line); - g_vsc.source_breakpoints[path][src_bp.line] = std::move(src_bp); } } @@ -2080,7 +2259,7 @@ void request_setFunctionBreakpoints(const llvm::json::Object &request) { // Disable any function breakpoints that aren't in the request_bps. // There is no call to remove function breakpoints other than calling this // function with a smaller or empty "breakpoints" list. - for (auto &pair: g_vsc.function_breakpoints) { + for (auto &pair : g_vsc.function_breakpoints) { auto request_pos = request_bps.find(pair.first()); if (request_pos == request_bps.end()) { // This function breakpoint no longer exists delete it from LLDB @@ -2098,7 +2277,7 @@ void request_setFunctionBreakpoints(const llvm::json::Object &request) { } } // Remove any breakpoints that are no longer in our list - for (const auto &name: remove_names) + for (const auto &name : remove_names) g_vsc.function_breakpoints.erase(name); // Any breakpoints that are left in "request_bps" are breakpoints that @@ -2188,6 +2367,7 @@ void request_source(const llvm::json::Object &request) { } else { response["success"] = llvm::json::Value(false); } + EmplaceSafeString(body, "mimeType", "text/x-lldb.disassembly"); response.try_emplace("body", std::move(body)); g_vsc.SendJSON(llvm::json::Value(std::move(response))); } @@ -2549,7 +2729,9 @@ void request_setVariable(const llvm::json::Object &request) { // This is a reference to the containing variable/scope const auto variablesReference = GetUnsigned(arguments, "variablesReference", 0); - const auto name = GetString(arguments, "name"); + llvm::StringRef name = GetString(arguments, "name"); + bool is_duplicated_variable_name = name.find(" @") != llvm::StringRef::npos; + const auto value = GetString(arguments, "value"); // Set success to false just in case we don't find the variable by name response.try_emplace("success", false); @@ -2591,14 +2773,10 @@ void request_setVariable(const llvm::json::Object &request) { break; } - // Find the variable by name in the correct scope and hope we don't have - // multiple variables with the same name. We search backwards because - // the list of variables has the top most variables first and variables - // in deeper scopes are last. This means we will catch the deepest - // variable whose name matches which is probably what the user wants. for (int64_t i = end_idx - 1; i >= start_idx; --i) { - auto curr_variable = g_vsc.variables.GetValueAtIndex(i); - llvm::StringRef variable_name(curr_variable.GetName()); + lldb::SBValue curr_variable = g_vsc.variables.GetValueAtIndex(i); + std::string variable_name = CreateUniqueVariableNameForDisplay( + curr_variable, is_duplicated_variable_name); if (variable_name == name) { variable = curr_variable; if (curr_variable.MightHaveChildren()) @@ -2607,6 +2785,9 @@ void request_setVariable(const llvm::json::Object &request) { } } } else { + // This is not under the globals or locals scope, so there are no duplicated + // names. + // We have a named item within an actual variable so we need to find it // withing the container variable by name. const int64_t var_idx = VARREF_TO_VARIDX(variablesReference); @@ -2643,6 +2824,8 @@ void request_setVariable(const llvm::json::Object &request) { EmplaceSafeString(body, "message", std::string(error.GetCString())); } response["success"] = llvm::json::Value(success); + } else { + response["success"] = llvm::json::Value(false); } response.try_emplace("body", std::move(body)); @@ -2758,12 +2941,25 @@ void request_variables(const llvm::json::Object &request) { break; } const int64_t end_idx = start_idx + ((count == 0) ? num_children : count); + + // We first find out which variable names are duplicated + std::map variable_name_counts; for (auto i = start_idx; i < end_idx; ++i) { lldb::SBValue variable = g_vsc.variables.GetValueAtIndex(i); if (!variable.IsValid()) break; - variables.emplace_back( - CreateVariable(variable, VARIDX_TO_VARREF(i), i, hex)); + variable_name_counts[GetNonNullVariableName(variable)]++; + } + + // Now we construct the result with unique display variable names + for (auto i = start_idx; i < end_idx; ++i) { + lldb::SBValue variable = g_vsc.variables.GetValueAtIndex(i); + + if (!variable.IsValid()) + break; + variables.emplace_back(CreateVariable(variable, VARIDX_TO_VARREF(i), i, + hex, + variable_name_counts[GetNonNullVariableName(variable)] > 1)); } } else { // We are expanding a variable that has children, so we will return its @@ -2813,46 +3009,44 @@ void request__testGetTargetBreakpoints(const llvm::json::Object &request) { g_vsc.SendJSON(llvm::json::Value(std::move(response))); } -const std::map &GetRequestHandlers() { -#define REQUEST_CALLBACK(name) \ - { #name, request_##name } - static std::map g_request_handlers = { - // VSCode Debug Adaptor requests - REQUEST_CALLBACK(attach), - REQUEST_CALLBACK(completions), - REQUEST_CALLBACK(continue), - REQUEST_CALLBACK(configurationDone), - REQUEST_CALLBACK(disconnect), - REQUEST_CALLBACK(evaluate), - REQUEST_CALLBACK(exceptionInfo), - REQUEST_CALLBACK(getCompileUnits), - REQUEST_CALLBACK(initialize), - REQUEST_CALLBACK(launch), - REQUEST_CALLBACK(next), - REQUEST_CALLBACK(pause), - REQUEST_CALLBACK(scopes), - REQUEST_CALLBACK(setBreakpoints), - REQUEST_CALLBACK(setExceptionBreakpoints), - REQUEST_CALLBACK(setFunctionBreakpoints), - REQUEST_CALLBACK(setVariable), - REQUEST_CALLBACK(source), - REQUEST_CALLBACK(stackTrace), - REQUEST_CALLBACK(stepIn), - REQUEST_CALLBACK(stepOut), - REQUEST_CALLBACK(threads), - REQUEST_CALLBACK(variables), - // Testing requests - REQUEST_CALLBACK(_testGetTargetBreakpoints), - }; -#undef REQUEST_CALLBACK - return g_request_handlers; +void RegisterRequestCallbacks() { + g_vsc.RegisterRequestCallback("attach", request_attach); + g_vsc.RegisterRequestCallback("completions", request_completions); + g_vsc.RegisterRequestCallback("continue", request_continue); + g_vsc.RegisterRequestCallback("configurationDone", request_configurationDone); + g_vsc.RegisterRequestCallback("disconnect", request_disconnect); + g_vsc.RegisterRequestCallback("evaluate", request_evaluate); + g_vsc.RegisterRequestCallback("exceptionInfo", request_exceptionInfo); + g_vsc.RegisterRequestCallback("initialize", request_initialize); + g_vsc.RegisterRequestCallback("launch", request_launch); + g_vsc.RegisterRequestCallback("next", request_next); + g_vsc.RegisterRequestCallback("pause", request_pause); + g_vsc.RegisterRequestCallback("scopes", request_scopes); + g_vsc.RegisterRequestCallback("setBreakpoints", request_setBreakpoints); + g_vsc.RegisterRequestCallback("setExceptionBreakpoints", + request_setExceptionBreakpoints); + g_vsc.RegisterRequestCallback("setFunctionBreakpoints", + request_setFunctionBreakpoints); + g_vsc.RegisterRequestCallback("setVariable", request_setVariable); + g_vsc.RegisterRequestCallback("source", request_source); + g_vsc.RegisterRequestCallback("stackTrace", request_stackTrace); + g_vsc.RegisterRequestCallback("stepIn", request_stepIn); + g_vsc.RegisterRequestCallback("stepOut", request_stepOut); + g_vsc.RegisterRequestCallback("threads", request_threads); + g_vsc.RegisterRequestCallback("variables", request_variables); + // Custom requests + g_vsc.RegisterRequestCallback("compileUnits", request_compileUnits); + g_vsc.RegisterRequestCallback("modules", request_modules); + // Testing requests + g_vsc.RegisterRequestCallback("_testGetTargetBreakpoints", + request__testGetTargetBreakpoints); } } // anonymous namespace static void printHelp(LLDBVSCodeOptTable &table, llvm::StringRef tool_name) { - std::string usage_str = tool_name.str() + "options"; - table.PrintHelp(llvm::outs(), usage_str.c_str(), "LLDB VSCode", false); + std::string usage_str = tool_name.str() + " options"; + table.printHelp(llvm::outs(), usage_str.c_str(), "LLDB VSCode", false); std::string examples = R"___( EXAMPLES: @@ -2872,12 +3066,103 @@ EXAMPLES: llvm::outs() << examples; } -int main(int argc, char *argv[]) { +// If --launch-target is provided, this instance of lldb-vscode becomes a +// runInTerminal launcher. It will ultimately launch the program specified in +// the --launch-target argument, which is the original program the user wanted +// to debug. This is done in such a way that the actual debug adaptor can +// place breakpoints at the beginning of the program. +// +// The launcher will communicate with the debug adaptor using a fifo file in the +// directory specified in the --comm-file argument. +// +// Regarding the actual flow, this launcher will first notify the debug adaptor +// of its pid. Then, the launcher will be in a pending state waiting to be +// attached by the adaptor. +// +// Once attached and resumed, the launcher will exec and become the program +// specified by --launch-target, which is the original target the +// user wanted to run. +// +// In case of errors launching the target, a suitable error message will be +// emitted to the debug adaptor. +void LaunchRunInTerminalTarget(llvm::opt::Arg &target_arg, + llvm::StringRef comm_file, char *argv[]) { +#if defined(_WIN32) + llvm::errs() << "runInTerminal is only supported on POSIX systems\n"; + exit(EXIT_FAILURE); +#else + RunInTerminalLauncherCommChannel comm_channel(comm_file); + if (llvm::Error err = comm_channel.NotifyPid()) { + llvm::errs() << llvm::toString(std::move(err)) << "\n"; + exit(EXIT_FAILURE); + } - // Initialize LLDB first before we do anything. - lldb::SBDebugger::Initialize(); + // We will wait to be attached with a timeout. We don't wait indefinitely + // using a signal to prevent being paused forever. + + // This env var should be used only for tests. + const char *timeout_env_var = getenv("LLDB_VSCODE_RIT_TIMEOUT_IN_MS"); + int timeout_in_ms = + timeout_env_var != nullptr ? atoi(timeout_env_var) : 20000; + if (llvm::Error err = comm_channel.WaitUntilDebugAdaptorAttaches( + std::chrono::milliseconds(timeout_in_ms))) { + llvm::errs() << llvm::toString(std::move(err)) << "\n"; + exit(EXIT_FAILURE); + } - int portno = -1; + const char *target = target_arg.getValue(); + execvp(target, argv); + + std::string error = std::strerror(errno); + comm_channel.NotifyError(error); + llvm::errs() << error << "\n"; + exit(EXIT_FAILURE); +#endif +} + +/// used only by TestVSCode_redirection_to_console.py +void redirection_test() { + printf("stdout message\n"); + fprintf(stderr, "stderr message\n"); + fflush(stdout); + fflush(stderr); +} + +/// Redirect stdout and stderr fo the IDE's console output. +/// +/// Errors in this operation will be printed to the log file and the IDE's +/// console output as well. +/// +/// \return +/// A fd pointing to the original stdout. +int SetupStdoutStderrRedirection() { + int new_stdout_fd = dup(fileno(stdout)); + auto stdout_err_redirector_callback = [&](llvm::StringRef data) { + g_vsc.SendOutput(OutputType::Console, data); + }; + + for (int fd : {fileno(stdout), fileno(stderr)}) { + if (llvm::Error err = RedirectFd(fd, stdout_err_redirector_callback)) { + std::string error_message = llvm::toString(std::move(err)); + if (g_vsc.log) + *g_vsc.log << error_message << std::endl; + stdout_err_redirector_callback(error_message); + } + } + + /// used only by TestVSCode_redirection_to_console.py + if (getenv("LLDB_VSCODE_TEST_STDOUT_STDERR_REDIRECTION") != nullptr) + redirection_test(); + return new_stdout_fd; +} + +int main(int argc, char *argv[]) { + llvm::InitLLVM IL(argc, argv, /*InstallPipeSignalExitHandler=*/false); + llvm::PrettyStackTraceProgram X(argc, argv); + + llvm::SmallString<256> program_path(argv[0]); + llvm::sys::fs::make_absolute(program_path); + g_vsc.debug_adaptor_path = program_path.str().str(); LLDBVSCodeOptTable T; unsigned MAI, MAC; @@ -2886,16 +3171,47 @@ int main(int argc, char *argv[]) { if (input_args.hasArg(OPT_help)) { printHelp(T, llvm::sys::path::filename(argv[0])); - return 0; + return EXIT_SUCCESS; } + if (llvm::opt::Arg *target_arg = input_args.getLastArg(OPT_launch_target)) { + if (llvm::opt::Arg *comm_file = input_args.getLastArg(OPT_comm_file)) { + int target_args_pos = argc; + for (int i = 0; i < argc; i++) + if (strcmp(argv[i], "--launch-target") == 0) { + target_args_pos = i + 1; + break; + } + LaunchRunInTerminalTarget(*target_arg, comm_file->getValue(), + argv + target_args_pos); + } else { + llvm::errs() << "\"--launch-target\" requires \"--comm-file\" to be " + "specified\n"; + return EXIT_FAILURE; + } + } + + // stdout/stderr redirection to the IDE's console + int new_stdout_fd = SetupStdoutStderrRedirection(); + + // Initialize LLDB first before we do anything. + lldb::SBDebugger::Initialize(); + + // Terminate the debugger before the C++ destructor chain kicks in. + auto terminate_debugger = + llvm::make_scope_exit([] { lldb::SBDebugger::Terminate(); }); + + RegisterRequestCallbacks(); + + int portno = -1; + if (auto *arg = input_args.getLastArg(OPT_port)) { auto optarg = arg->getValue(); char *remainder; portno = strtol(optarg, &remainder, 0); if (remainder == optarg || *remainder != '\0') { fprintf(stderr, "'%s' is not a valid port number.\n", optarg); - exit(1); + return EXIT_FAILURE; } } @@ -2912,60 +3228,26 @@ int main(int argc, char *argv[]) { g_vsc.input.descriptor = StreamDescriptor::from_socket(socket_fd, true); g_vsc.output.descriptor = StreamDescriptor::from_socket(socket_fd, false); } else { - exit(1); + return EXIT_FAILURE; } } else { g_vsc.input.descriptor = StreamDescriptor::from_file(fileno(stdin), false); - g_vsc.output.descriptor = - StreamDescriptor::from_file(fileno(stdout), false); + g_vsc.output.descriptor = StreamDescriptor::from_file(new_stdout_fd, false); } - auto request_handlers = GetRequestHandlers(); + uint32_t packet_idx = 0; while (!g_vsc.sent_terminated_event) { - std::string json = g_vsc.ReadJSON(); - if (json.empty()) + llvm::json::Object object; + lldb_vscode::PacketStatus status = g_vsc.GetNextObject(object); + if (status == lldb_vscode::PacketStatus::EndOfFile) break; + if (status != lldb_vscode::PacketStatus::Success) + return 1; // Fatal error - llvm::StringRef json_sref(json); - llvm::Expected json_value = llvm::json::parse(json_sref); - if (!json_value) { - auto error = json_value.takeError(); - if (g_vsc.log) { - std::string error_str; - llvm::raw_string_ostream strm(error_str); - strm << error; - strm.flush(); - - *g_vsc.log << "error: failed to parse JSON: " << error_str << std::endl - << json << std::endl; - } + if (!g_vsc.HandleObject(object)) return 1; - } - - auto object = json_value->getAsObject(); - if (!object) { - if (g_vsc.log) - *g_vsc.log << "error: json packet isn't a object" << std::endl; - return 1; - } - - const auto packet_type = GetString(object, "type"); - if (packet_type == "request") { - const auto command = GetString(object, "command"); - auto handler_pos = request_handlers.find(std::string(command)); - if (handler_pos != request_handlers.end()) { - handler_pos->second(*object); - } else { - if (g_vsc.log) - *g_vsc.log << "error: unhandled command \"" << command.data() << std::endl; - return 1; - } - } ++packet_idx; } - // We must terminate the debugger in a thread before the C++ destructor - // chain messes everything up. - lldb::SBDebugger::Terminate(); - return 0; + return EXIT_SUCCESS; } diff --git a/gnu/llvm/lldb/tools/lldb-vscode/package.json b/gnu/llvm/lldb/tools/lldb-vscode/package.json index f4408d3607d..a5c79911f6e 100644 --- a/gnu/llvm/lldb/tools/lldb-vscode/package.json +++ b/gnu/llvm/lldb/tools/lldb-vscode/package.json @@ -32,6 +32,71 @@ "vsce": "^1.36.3" }, "contributes": { + "languages": [ + { + "id": "lldb.disassembly", + "aliases": [ + "Disassembly" + ], + "extensions": [ + ".disasm" + ] + } + ], + "grammars": [ + { + "language": "lldb.disassembly", + "scopeName": "source.disassembly", + "path": "./syntaxes/disassembly.json" + } + ], + "breakpoints": [ + { + "language": "ada" + }, + { + "language": "arm" + }, + { + "language": "asm" + }, + { + "language": "c" + }, + { + "language": "cpp" + }, + { + "language": "crystal" + }, + { + "language": "d" + }, + { + "language": "fortan" + }, + { + "language": "fortran-modern" + }, + { + "language": "nim" + }, + { + "language": "objective-c" + }, + { + "language": "objectpascal" + }, + { + "language": "pascal" + }, + { + "language": "rust" + }, + { + "language": "swift" + } + ], "debuggers": [ { "type": "lldb-vscode", @@ -84,7 +149,7 @@ }, "env": { "type": "array", - "description": "Additional environment variables.", + "description": "Additional environment variables to set when launching the program. This is an array of strings that contains the variable name followed by an optional '=' character and the environment variable's value. Example: [\"FOO=BAR\", \"BAZ\"]", "default": [] }, "stopOnEntry": { @@ -143,6 +208,11 @@ "description": "Commands executed just before the program is launched.", "default": [] }, + "postRunCommands": { + "type": "array", + "description": "Commands executed just as soon as the program is successfully launched when it's in a stopped state prior to any automatic continuation.", + "default": [] + }, "launchCommands": { "type": "array", "description": "Custom commands that are executed instead of launching a process. A target will be created with the launch arguments prior to executing these commands. The commands may optionally create a new target and must perform a launch. A valid process must exist after these commands complete or the \"launch\" will fail.", @@ -157,6 +227,11 @@ "type": "array", "description": "Commands executed at the end of debugging session.", "default": [] + }, + "runInTerminal": { + "type": "boolean", + "description": "Launch the program inside an integrated terminal in the IDE. Useful for debugging interactive command line programs", + "default": false } } }, @@ -214,6 +289,11 @@ "description": "Commands executed just before the program is attached to.", "default": [] }, + "postRunCommands": { + "type": "array", + "description": "Commands executed just as soon as the program is successfully attached when it's in a stopped state prior to any automatic continuation.", + "default": [] + }, "stopCommands": { "type": "array", "description": "Commands executed each time the program stops.", diff --git a/gnu/llvm/lldb/tools/lldb-vscode/syntaxes/arm.disasm b/gnu/llvm/lldb/tools/lldb-vscode/syntaxes/arm.disasm new file mode 100644 index 00000000000..436a78bfc21 --- /dev/null +++ b/gnu/llvm/lldb/tools/lldb-vscode/syntaxes/arm.disasm @@ -0,0 +1,45 @@ +(lldb) +libIGL.so`igl::RenderPipelineDesc::TargetDesc::ColorAttachment::operator==: +libIGL.so[0x7694] <+0>: ldr r2, [r1] +libIGL.so[0x7696] <+2>: ldr r3, [r0] +libIGL.so[0x7698] <+4>: cmp r3, r2 +libIGL.so[0x769a] <+6>: bne 0x76da ; <+70> at RenderPipelineState.cpp +libIGL.so[0x769c] <+8>: ldrb r2, [r1, #0x5] +libIGL.so[0x769e] <+10>: ldrb r3, [r0, #0x5] +libIGL.so[0x76a0] <+12>: cmp r3, r2 +libIGL.so[0x76a2] <+14>: bne 0x76da ; <+70> at RenderPipelineState.cpp +libIGL.so[0x76a4] <+16>: ldr r2, [r1, #0x8] +libIGL.so[0x76a6] <+18>: ldr r3, [r0, #0x8] +libIGL.so[0x76a8] <+20>: cmp r3, r2 +libIGL.so[0x76aa] <+22>: bne 0x76da ; <+70> at RenderPipelineState.cpp +libIGL.so[0x76ac] <+24>: ldr r2, [r1, #0xc] +libIGL.so[0x76ae] <+26>: ldr r3, [r0, #0xc] +libIGL.so[0x76b0] <+28>: cmp r3, r2 +libIGL.so[0x76b2] <+30>: bne 0x76da ; <+70> at RenderPipelineState.cpp +libIGL.so[0x76b4] <+32>: ldr r2, [r1, #0x10] +libIGL.so[0x76b6] <+34>: ldr r3, [r0, #0x10] +libIGL.so[0x76b8] <+36>: cmp r3, r2 +libIGL.so[0x76ba] <+38>: bne 0x76da ; <+70> at RenderPipelineState.cpp +libIGL.so[0x76bc] <+40>: ldr r2, [r1, #0x14] +libIGL.so[0x76be] <+42>: ldr r3, [r0, #0x14] +libIGL.so[0x76c0] <+44>: cmp r3, r2 +libIGL.so[0x76c2] <+46>: bne 0x76da ; <+70> at RenderPipelineState.cpp +libIGL.so[0x76c4] <+48>: ldr r2, [r1, #0x18] +libIGL.so[0x76c6] <+50>: ldr r3, [r0, #0x18] +libIGL.so[0x76c8] <+52>: cmp r3, r2 +libIGL.so[0x76ca] <+54>: bne 0x76da ; <+70> at RenderPipelineState.cpp +libIGL.so[0x76cc] <+56>: ldr r1, [r1, #0x1c] +libIGL.so[0x76ce] <+58>: ldr r0, [r0, #0x1c] +libIGL.so[0x76d0] <+60>: subs r0, r0, r1 +libIGL.so[0x76d2] <+62>: clz r0, r0 +libIGL.so[0x76d6] <+66>: lsrs r0, r0, #0x5 +libIGL.so[0x76d8] <+68>: bx lr +libIGL.so[0x76da] <+70>: movs r0, #0x0 +libIGL.so[0x76dc] <+72>: bx lr +(lldb) disassemble --name _ZN3igl20VertexInputStateDesc28sizeForVertexAttributeFormatENS_21VertexAttributeFormatE +libIGL.so`igl::VertexInputStateDesc::sizeForVertexAttributeFormat: +libIGL.so[0x787c] <+0>: ldr r1, [pc, #0x8] ; <+12> at VertexInputState.cpp +libIGL.so[0x787e] <+2>: add r1, pc +libIGL.so[0x7880] <+4>: ldr.w r0, [r1, r0, lsl #2] +libIGL.so[0x7884] <+8>: bx lr +libIGL.so[0x7886] <+10>: nop \ No newline at end of file diff --git a/gnu/llvm/lldb/tools/lldb-vscode/syntaxes/arm64.disasm b/gnu/llvm/lldb/tools/lldb-vscode/syntaxes/arm64.disasm new file mode 100644 index 00000000000..dfe201d907d --- /dev/null +++ b/gnu/llvm/lldb/tools/lldb-vscode/syntaxes/arm64.disasm @@ -0,0 +1,91 @@ +(lldb) disassemble --name __android_log_config_read +liblog.so`::__android_log_config_read(): +liblog.so[0x6014] <+0>: stp x22, x21, [sp, #-0x30]! +liblog.so[0x6018] <+4>: stp x20, x19, [sp, #0x10] +liblog.so[0x601c] <+8>: stp x29, x30, [sp, #0x20] +liblog.so[0x6020] <+12>: add x29, sp, #0x20 ; =0x20 +liblog.so[0x6024] <+16>: adrp x8, 15 +liblog.so[0x6028] <+20>: ldr x8, [x8, #0x230] +liblog.so[0x602c] <+24>: ldr w8, [x8] +liblog.so[0x6030] <+28>: cbz w8, 0x6038 ; <+36> at config_read.cpp +liblog.so[0x6034] <+32>: tbz w8, #0x0, 0x6168 ; <+340> at config_read.cpp:65:1 +liblog.so[0x6038] <+36>: adrp x20, 15 +liblog.so[0x603c] <+40>: adrp x21, 15 +liblog.so[0x6040] <+44>: ldr x20, [x20, #0x238] +liblog.so[0x6044] <+48>: ldr x21, [x21, #0x240] +liblog.so[0x6048] <+52>: mov w19, wzr +liblog.so[0x604c] <+56>: ldr x22, [x20] +liblog.so[0x6050] <+60>: cmp x22, x20 +liblog.so[0x6054] <+64>: b.eq 0x609c ; <+136> [inlined] __android_log_add_transport(listnode*, android_log_transport_read*) + 80 at config_read.cpp:61 +liblog.so[0x6058] <+68>: ldr x8, [x22] +liblog.so[0x605c] <+72>: cmp x22, x8 +liblog.so[0x6060] <+76>: b.eq 0x60b0 ; <+156> [inlined] __android_log_add_transport(listnode*, android_log_transport_read*) + 100 at config_read.cpp:61 +liblog.so[0x6064] <+80>: ldr x8, [x22, #0x18] +liblog.so[0x6068] <+84>: cbz x8, 0x60d0 ; <+188> at config_read.cpp +liblog.so[0x606c] <+88>: mov w0, w19 +liblog.so[0x6070] <+92>: blr x8 +liblog.so[0x6074] <+96>: tbz w0, #0x1f, 0x608c ; <+120> [inlined] __android_log_add_transport(listnode*, android_log_transport_read*) + 64 at config_read.cpp:61 +liblog.so[0x6078] <+100>: ldr x8, [x21, #0x18] +liblog.so[0x607c] <+104>: cbz x8, 0x60c0 ; <+172> [inlined] __android_log_add_transport(listnode*, android_log_transport_read*) + 116 at config_read.cpp:61 +liblog.so[0x6080] <+108>: mov w0, w19 +liblog.so[0x6084] <+112>: blr x8 +liblog.so[0x6088] <+116>: tbz w0, #0x1f, 0x60c0 ; <+172> [inlined] __android_log_add_transport(listnode*, android_log_transport_read*) + 116 at config_read.cpp:61 +liblog.so[0x608c] <+120>: ldr x22, [x22] +liblog.so[0x6090] <+124>: cmp x22, x20 +liblog.so[0x6094] <+128>: b.ne 0x6058 ; <+68> [inlined] __android_log_add_transport(listnode*, android_log_transport_read*) + 12 at config_read.cpp:61 +liblog.so[0x6098] <+132>: b 0x60b0 ; <+156> [inlined] __android_log_add_transport(listnode*, android_log_transport_read*) + 100 at config_read.cpp:61 +liblog.so[0x609c] <+136>: ldr x8, [x21, #0x18] +liblog.so[0x60a0] <+140>: cbz x8, 0x60c0 ; <+172> [inlined] __android_log_add_transport(listnode*, android_log_transport_read*) + 116 at config_read.cpp:61 +liblog.so[0x60a4] <+144>: mov w0, w19 +liblog.so[0x60a8] <+148>: blr x8 +liblog.so[0x60ac] <+152>: tbz w0, #0x1f, 0x60c0 ; <+172> [inlined] __android_log_add_transport(listnode*, android_log_transport_read*) + 116 at config_read.cpp:61 +liblog.so[0x60b0] <+156>: add w19, w19, #0x1 ; =0x1 +liblog.so[0x60b4] <+160>: cmp w19, #0x8 ; =0x8 +liblog.so[0x60b8] <+164>: b.lo 0x604c ; <+56> [inlined] __android_log_add_transport(listnode*, android_log_transport_read*) at config_read.cpp:61 +liblog.so[0x60bc] <+168>: b 0x60d0 ; <+188> at config_read.cpp +liblog.so[0x60c0] <+172>: ldr x8, [x20, #0x8] +liblog.so[0x60c4] <+176>: stp x20, x8, [x21] +liblog.so[0x60c8] <+180>: str x21, [x8] +liblog.so[0x60cc] <+184>: str x21, [x20, #0x8] +liblog.so[0x60d0] <+188>: adrp x20, 15 +liblog.so[0x60d4] <+192>: adrp x21, 15 +liblog.so[0x60d8] <+196>: ldr x20, [x20, #0x248] +liblog.so[0x60dc] <+200>: ldr x21, [x21, #0x250] +liblog.so[0x60e0] <+204>: mov w19, wzr +liblog.so[0x60e4] <+208>: ldr x22, [x20] +liblog.so[0x60e8] <+212>: cmp x22, x20 +liblog.so[0x60ec] <+216>: b.eq 0x6134 ; <+288> [inlined] __android_log_add_transport(listnode*, android_log_transport_read*) + 80 at config_read.cpp:62 +liblog.so[0x60f0] <+220>: ldr x8, [x22] +liblog.so[0x60f4] <+224>: cmp x22, x8 +liblog.so[0x60f8] <+228>: b.eq 0x6148 ; <+308> [inlined] __android_log_add_transport(listnode*, android_log_transport_read*) + 100 at config_read.cpp:62 +liblog.so[0x60fc] <+232>: ldr x8, [x22, #0x18] +liblog.so[0x6100] <+236>: cbz x8, 0x6168 ; <+340> at config_read.cpp:65:1 +liblog.so[0x6104] <+240>: mov w0, w19 +liblog.so[0x6108] <+244>: blr x8 +liblog.so[0x610c] <+248>: tbz w0, #0x1f, 0x6124 ; <+272> [inlined] __android_log_add_transport(listnode*, android_log_transport_read*) + 64 at config_read.cpp:62 +liblog.so[0x6110] <+252>: ldr x8, [x21, #0x18] +liblog.so[0x6114] <+256>: cbz x8, 0x6158 ; <+324> [inlined] __android_log_add_transport(listnode*, android_log_transport_read*) + 116 at config_read.cpp:62 +liblog.so[0x6118] <+260>: mov w0, w19 +liblog.so[0x611c] <+264>: blr x8 +liblog.so[0x6120] <+268>: tbz w0, #0x1f, 0x6158 ; <+324> [inlined] __android_log_add_transport(listnode*, android_log_transport_read*) + 116 at config_read.cpp:62 +liblog.so[0x6124] <+272>: ldr x22, [x22] +liblog.so[0x6128] <+276>: cmp x22, x20 +liblog.so[0x612c] <+280>: b.ne 0x60f0 ; <+220> [inlined] __android_log_add_transport(listnode*, android_log_transport_read*) + 12 at config_read.cpp:62 +liblog.so[0x6130] <+284>: b 0x6148 ; <+308> [inlined] __android_log_add_transport(listnode*, android_log_transport_read*) + 100 at config_read.cpp:62 +liblog.so[0x6134] <+288>: ldr x8, [x21, #0x18] +liblog.so[0x6138] <+292>: cbz x8, 0x6158 ; <+324> [inlined] __android_log_add_transport(listnode*, android_log_transport_read*) + 116 at config_read.cpp:62 +liblog.so[0x613c] <+296>: mov w0, w19 +liblog.so[0x6140] <+300>: blr x8 +liblog.so[0x6144] <+304>: tbz w0, #0x1f, 0x6158 ; <+324> [inlined] __android_log_add_transport(listnode*, android_log_transport_read*) + 116 at config_read.cpp:62 +liblog.so[0x6148] <+308>: add w19, w19, #0x1 ; =0x1 +liblog.so[0x614c] <+312>: cmp w19, #0x8 ; =0x8 +liblog.so[0x6150] <+316>: b.lo 0x60e4 ; <+208> [inlined] __android_log_add_transport(listnode*, android_log_transport_read*) at config_read.cpp:62 +liblog.so[0x6154] <+320>: b 0x6168 ; <+340> at config_read.cpp:65:1 +liblog.so[0x6158] <+324>: ldr x8, [x20, #0x8] +liblog.so[0x615c] <+328>: stp x20, x8, [x21] +liblog.so[0x6160] <+332>: str x21, [x8] +liblog.so[0x6164] <+336>: str x21, [x20, #0x8] +liblog.so[0x6168] <+340>: ldp x29, x30, [sp, #0x20] +liblog.so[0x616c] <+344>: ldp x20, x19, [sp, #0x10] +liblog.so[0x6170] <+348>: ldp x22, x21, [sp], #0x30 +liblog.so[0x6174] <+352>: ret diff --git a/gnu/llvm/lldb/tools/lldb-vscode/syntaxes/disassembly.json b/gnu/llvm/lldb/tools/lldb-vscode/syntaxes/disassembly.json new file mode 100644 index 00000000000..cd086fe2f49 --- /dev/null +++ b/gnu/llvm/lldb/tools/lldb-vscode/syntaxes/disassembly.json @@ -0,0 +1,64 @@ +{ + "name": "Disassembly", + "scopeName": "source.disassembly", + "uuid": "9ade615f-5d82-4ac5-b22f-a1998c356ebe", + "patterns": [ + { + "comment": "x86 Address, bytes and opcode", + "name": "meta.instruction", + "match": "^([A-Za-z0-9]+):\\s([A-Z0-9]{2}\\s)+>?\\s+(\\w+)", + "captures": { + "1": {"name": "constant.numeric"}, + "3": {"name": "keyword.opcode"} + } + }, + { + "comment": "ARM Address, bytes and opcode", + "name": "meta.instruction", + "match": "^libIGL.so\\[([A-Za-z0-9]+)\\]\\s+(\\<\\+[0-9]*\\>):\\s+([A-Za-z]+.?[A-Za-z]*)", + "captures": { + "1": {"name": "constant.numeric"}, + "3": {"name": "keyword.opcode"} + } + }, + { + "comment": "ARM64 Address, bytes and opcode", + "name": "meta.instruction", + "match": "^liblog.so\\[([A-Za-z0-9]+)\\]\\s+(\\<\\+[0-9]*\\>):\\s+([A-Za-z]+.?[A-Za-z]*)", + "captures": { + "1": {"name": "constant.numeric"}, + "3": {"name": "keyword.opcode"} + } + }, + { + "comment": "Numeric constant", + "name": "constant.numeric", + "match": "(\\$|\\b)((0x)|[0-9])[A-Za-z0-9]+\\b" + }, + { + "comment": "x86 Register", + "name": "variable.language", + "match": "%[A-Za-z][A-Za-z0-9]*" + }, + { + "comment": "ARM Register", + "name": "variable.language", + "match": "r\\d+" + }, + { + "comment": "ARM Register Shortnames", + "name": "variable.language", + "match": "(fp|sp|lr|pc|wzr|xzr)" + }, + { + "comment": "ARM64 Register", + "name": "variable.language", + "match": "(x|w)[0-9]+" + }, + { + "comment": "End of line comment", + "name": "comment.line.semicolon", + "match": ";.*$" + } + ] +} diff --git a/gnu/llvm/lldb/tools/lldb-vscode/syntaxes/x86.disasm b/gnu/llvm/lldb/tools/lldb-vscode/syntaxes/x86.disasm new file mode 100644 index 00000000000..d86a798cb98 --- /dev/null +++ b/gnu/llvm/lldb/tools/lldb-vscode/syntaxes/x86.disasm @@ -0,0 +1,28 @@ +0x100008000: <0> popq %rdi +0x100008001: <1> pushq $0x0 +0x100008003: <3> movq %rsp, %rbp +0x100008006: <6> andq $-0x10, %rsp +0x10000800A: <10> subq $0x10, %rsp +0x10000800E: <14> movl 0x8(%rbp), %esi +0x100008011: <17> leaq 0x10(%rbp), %rdx +0x100008015: <21> leaq -0x101c(%rip), %rcx +0x10000801C: <28> leaq -0x8(%rbp), %r8 +0x100008020: <32> callq 0x100008062 # dyldbootstrap::start(dyld3::MachOLoaded const*, int, char const**, dyld3::MachOLoaded const*, unsigned long*) +0x100008025: <37> movq -0x8(%rbp), %rdi +0x100008029: <41> cmpq $0x0, %rdi +0x10000802D: <45> jne 0x10000803f # <+63> +0x10000802F: <47> movq %rbp, %rsp +0x100008032: <50> addq $0x8, %rsp +0x100008036: <54> movq $0x0, %rbp +0x10000803D: <61> jmpq *%rax +0x10000803F: <63> addq $0x10, %rsp +0x100008043: <67> pushq %rdi +0x100008044: <68> movq 0x8(%rbp), %rdi +0x100008048: <72> leaq 0x10(%rbp), %rsi +0x10000804C: <76> leaq 0x8(%rsi,%rdi,8), %rdx +0x100008051: <81> movq %rdx, %rcx +0x100008054: <84> movq (%rcx), %r8 +0x100008057: <87> addq $0x8, %rcx +0x10000805B: <91> testq %r8, %r8 +0x10000805E: <94> jne 0x100008054 # <+84> +0x100008060: <96> jmpq *%rax diff --git a/gnu/llvm/lldb/unittests/API/CMakeLists.txt b/gnu/llvm/lldb/unittests/API/CMakeLists.txt index 308249b63ad..7bdc1e3e87c 100644 --- a/gnu/llvm/lldb/unittests/API/CMakeLists.txt +++ b/gnu/llvm/lldb/unittests/API/CMakeLists.txt @@ -1,10 +1,11 @@ add_lldb_unittest(APITests SBCommandInterpreterTest.cpp + SBStructuredDataTest.cpp LINK_LIBS liblldb ) -if(PYTHON_RPATH) - set_property(TARGET APITests APPEND PROPERTY BUILD_RPATH "${PYTHON_RPATH}") +if(Python3_RPATH) + set_property(TARGET APITests APPEND PROPERTY BUILD_RPATH "${Python3_RPATH}") endif() diff --git a/gnu/llvm/lldb/unittests/API/SBStructuredDataTest.cpp b/gnu/llvm/lldb/unittests/API/SBStructuredDataTest.cpp new file mode 100644 index 00000000000..a3a33aad9a1 --- /dev/null +++ b/gnu/llvm/lldb/unittests/API/SBStructuredDataTest.cpp @@ -0,0 +1,35 @@ +//===-- SBStructuredDataTest.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 "gtest/gtest.h" + +#include "lldb/API/SBStringList.h" +#include "lldb/API/SBStructuredData.h" + +#include +#include + +using namespace lldb; + +class SBStructuredDataTest : public testing::Test {}; + +TEST_F(SBStructuredDataTest, NullImpl) { + SBStructuredData data(nullptr); + EXPECT_EQ(data.GetType(), eStructuredDataTypeInvalid); + EXPECT_EQ(data.GetSize(), 0ul); + SBStringList keys; + EXPECT_FALSE(data.GetKeys(keys)); + EXPECT_EQ(data.GetValueForKey("key").GetType(), eStructuredDataTypeInvalid); + EXPECT_EQ(data.GetItemAtIndex(0).GetType(), eStructuredDataTypeInvalid); + EXPECT_EQ(data.GetIntegerValue(UINT64_MAX), UINT64_MAX); + EXPECT_EQ(data.GetFloatValue(DBL_MAX), DBL_MAX); + EXPECT_TRUE(data.GetBooleanValue(true)); + EXPECT_FALSE(data.GetBooleanValue(false)); + char dst[1]; + EXPECT_EQ(data.GetStringValue(dst, sizeof(dst)), 0ul); +} diff --git a/gnu/llvm/lldb/unittests/CMakeLists.txt b/gnu/llvm/lldb/unittests/CMakeLists.txt index 6422b726ca6..e7b0f1c17d6 100644 --- a/gnu/llvm/lldb/unittests/CMakeLists.txt +++ b/gnu/llvm/lldb/unittests/CMakeLists.txt @@ -1,10 +1,15 @@ add_custom_target(LLDBUnitTests) set_target_properties(LLDBUnitTests PROPERTIES FOLDER "lldb tests") -add_dependencies(lldb-test-deps LLDBUnitTests) + +add_dependencies(lldb-unit-test-deps LLDBUnitTests) include_directories(${LLDB_SOURCE_ROOT}) include_directories(${LLDB_PROJECT_ROOT}/unittests) +if (CXX_SUPPORTS_SUGGEST_OVERRIDE_FLAG) + add_compile_options("-Wno-suggest-override") +endif() + set(LLDB_GTEST_COMMON_INCLUDE ${CMAKE_CURRENT_SOURCE_DIR}/gtest_common.h) if (MSVC) list(APPEND LLVM_COMPILE_FLAGS /FI ${LLDB_GTEST_COMMON_INCLUDE}) diff --git a/gnu/llvm/lldb/unittests/Core/CMakeLists.txt b/gnu/llvm/lldb/unittests/Core/CMakeLists.txt index de99856486f..dfe017b3c9c 100644 --- a/gnu/llvm/lldb/unittests/Core/CMakeLists.txt +++ b/gnu/llvm/lldb/unittests/Core/CMakeLists.txt @@ -1,8 +1,11 @@ add_lldb_unittest(LLDBCoreTests CommunicationTest.cpp + DumpDataExtractorTest.cpp + FormatEntityTest.cpp MangledTest.cpp ModuleSpecTest.cpp RichManglingContextTest.cpp + SourceLocationSpecTest.cpp SourceManagerTest.cpp StreamCallbackTest.cpp UniqueCStringMapTest.cpp diff --git a/gnu/llvm/lldb/unittests/Core/DumpDataExtractorTest.cpp b/gnu/llvm/lldb/unittests/Core/DumpDataExtractorTest.cpp new file mode 100644 index 00000000000..f76014aa938 --- /dev/null +++ b/gnu/llvm/lldb/unittests/Core/DumpDataExtractorTest.cpp @@ -0,0 +1,387 @@ +//===-- DataDumpExtractorTest.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 "lldb/Core/DumpDataExtractor.h" +#include "lldb/Utility/DataBufferHeap.h" +#include "lldb/Utility/DataExtractor.h" +#include "lldb/Utility/Endian.h" +#include "lldb/Utility/StreamString.h" +#include "gtest/gtest.h" +#include +#include + +using namespace lldb; +using namespace lldb_private; + +static void TestDumpWithAddress(uint64_t base_addr, size_t item_count, + llvm::StringRef expected) { + std::vector data{0x11, 0x22}; + StreamString result; + DataBufferHeap dumpbuffer(&data[0], data.size()); + DataExtractor extractor(dumpbuffer.GetBytes(), dumpbuffer.GetByteSize(), + endian::InlHostByteOrder(), /*addr_size=*/4); + + DumpDataExtractor(extractor, &result, 0, lldb::Format::eFormatHex, + /*item_byte_size=*/1, item_count, + /*num_per_line=*/1, base_addr, 0, 0); + ASSERT_EQ(expected, result.GetString()); +} + +TEST(DumpDataExtractorTest, BaseAddress) { + TestDumpWithAddress(0x12341234, 1, "0x12341234: 0x11"); + TestDumpWithAddress(LLDB_INVALID_ADDRESS, 1, "0x11"); + TestDumpWithAddress(0x12341234, 2, "0x12341234: 0x11\n0x12341235: 0x22"); + TestDumpWithAddress(LLDB_INVALID_ADDRESS, 2, "0x11\n0x22"); +} + +static void TestDumpWithOffset(offset_t start_offset, + llvm::StringRef expected) { + std::vector data{0x11, 0x22, 0x33}; + StreamString result; + DataBufferHeap dumpbuffer(&data[0], data.size()); + DataExtractor extractor(dumpbuffer.GetBytes(), dumpbuffer.GetByteSize(), + endian::InlHostByteOrder(), /*addr_size=*/4); + + DumpDataExtractor(extractor, &result, start_offset, lldb::Format::eFormatHex, + /*item_byte_size=*/1, /*item_count=*/data.size(), + /*num_per_line=*/data.size(), /*base_addr=*/0, 0, 0); + ASSERT_EQ(expected, result.GetString()); +} + +TEST(DumpDataExtractorTest, StartOffset) { + TestDumpWithOffset(0, "0x00000000: 0x11 0x22 0x33"); + // The offset applies to the DataExtractor, not the address used when + // formatting. + TestDumpWithOffset(1, "0x00000000: 0x22 0x33"); + // If the offset is outside the DataExtractor's range we do nothing. + TestDumpWithOffset(3, ""); +} + +TEST(DumpDataExtractorTest, NullStream) { + // We don't do any work if there is no output stream. + uint8_t c = 0x11; + StreamString result; + DataBufferHeap dumpbuffer(&c, 0); + DataExtractor extractor(dumpbuffer.GetBytes(), dumpbuffer.GetByteSize(), + endian::InlHostByteOrder(), /*addr_size=*/4); + + DumpDataExtractor(extractor, nullptr, 0, lldb::Format::eFormatHex, + /*item_byte_size=*/1, /*item_count=*/1, + /*num_per_line=*/1, /*base_addr=*/0, 0, 0); + ASSERT_EQ("", result.GetString()); +} + +static void TestDumpImpl(const void *data, size_t data_size, + size_t item_byte_size, size_t item_count, + size_t num_per_line, uint64_t base_addr, + lldb::Format format, llvm::StringRef expected) { + StreamString result; + DataBufferHeap dumpbuffer(data, data_size); + DataExtractor extractor(dumpbuffer.GetBytes(), dumpbuffer.GetByteSize(), + endian::InlHostByteOrder(), + /*addr_size=*/4); + DumpDataExtractor(extractor, &result, 0, format, item_byte_size, item_count, + num_per_line, base_addr, 0, 0); + ASSERT_EQ(expected, result.GetString()); +} + +template +static void TestDump(T data, lldb::Format format, llvm::StringRef expected) { + TestDumpImpl(&data, sizeof(T), sizeof(T), 1, 1, LLDB_INVALID_ADDRESS, format, + expected); +} + +static void TestDump(llvm::StringRef str, lldb::Format format, + llvm::StringRef expected) { + TestDumpImpl(str.bytes_begin(), + // +1 to include the NULL char as the last byte + str.size() + 1, str.size() + 1, 1, 1, LLDB_INVALID_ADDRESS, + format, expected); +} + +template +static void TestDump(const std::vector data, lldb::Format format, + llvm::StringRef expected) { + size_t sz_bytes = data.size() * sizeof(T); + TestDumpImpl(&data[0], sz_bytes, sz_bytes, data.size(), 1, + LLDB_INVALID_ADDRESS, format, expected); +} + +TEST(DumpDataExtractorTest, Formats) { + TestDump(1, lldb::eFormatDefault, "0x01"); + TestDump(1, lldb::eFormatBoolean, "true"); + TestDump(0xAA, lldb::eFormatBinary, "0b10101010"); + TestDump(1, lldb::eFormatBytes, "01"); + TestDump(1, lldb::eFormatBytesWithASCII, "01 ."); + TestDump('?', lldb::eFormatChar, "'?'"); + TestDump('\x1A', lldb::eFormatCharPrintable, "."); + TestDump('#', lldb::eFormatCharPrintable, "#"); + TestDump(std::complex(1.2, 3.4), lldb::eFormatComplex, "1.2 + 3.4i"); + TestDump(std::complex(4.5, 6.7), lldb::eFormatComplex, "4.5 + 6.7i"); + + // long double is not tested here because for some platforms we treat it as 10 + // bytes when the compiler allocates 16 bytes of space for it. (see + // DataExtractor::GetLongDouble) Meaning that when we extract the second one, + // it gets the wrong value (it's 6 bytes off). You could manually construct a + // set of bytes to match the 10 byte format but then if the test runs on a + // machine where we don't use 10 it'll break. + + TestDump(llvm::StringRef("aardvark"), lldb::Format::eFormatCString, + "\"aardvark\""); + TestDump(99, lldb::Format::eFormatDecimal, "99"); + // Just prints as a signed integer. + TestDump(-1, lldb::Format::eFormatEnum, "-1"); + TestDump(0xcafef00d, lldb::Format::eFormatHex, "0xcafef00d"); + TestDump(0xcafef00d, lldb::Format::eFormatHexUppercase, "0xCAFEF00D"); + TestDump(0.456, lldb::Format::eFormatFloat, "0.456"); + TestDump(9, lldb::Format::eFormatOctal, "011"); + // Chars packed into an integer. + TestDump(0x4C4C4442, lldb::Format::eFormatOSType, "'LLDB'"); + // Unicode8 doesn't have a specific formatter. + TestDump(0x34, lldb::Format::eFormatUnicode8, "0x34"); + TestDump(0x1122, lldb::Format::eFormatUnicode16, "U+1122"); + TestDump(0x12345678, lldb::Format::eFormatUnicode32, + "U+0x12345678"); + TestDump(654321, lldb::Format::eFormatUnsigned, "654321"); + // This pointer is printed based on the size of uint64_t, so the test is the + // same for 32/64 bit host. + TestDump(0x4444555566667777, lldb::Format::eFormatPointer, + "0x4444555566667777"); + + TestDump(std::vector{'A', '\x01', 'C'}, + lldb::Format::eFormatVectorOfChar, "{A\\x01C}"); + TestDump(std::vector{0, -1, std::numeric_limits::max()}, + lldb::Format::eFormatVectorOfSInt8, "{0 -1 127}"); + TestDump(std::vector{12, 0xFF, 34}, + lldb::Format::eFormatVectorOfUInt8, "{0x0c 0xff 0x22}"); + TestDump(std::vector{-1, 1234, std::numeric_limits::max()}, + lldb::Format::eFormatVectorOfSInt16, "{-1 1234 32767}"); + TestDump(std::vector{0xffff, 0xabcd, 0x1234}, + lldb::Format::eFormatVectorOfUInt16, "{0xffff 0xabcd 0x1234}"); + TestDump(std::vector{0, -1, std::numeric_limits::max()}, + lldb::Format::eFormatVectorOfSInt32, "{0 -1 2147483647}"); + TestDump(std::vector{0, 0xffffffff, 0x1234abcd}, + lldb::Format::eFormatVectorOfUInt32, + "{0x00000000 0xffffffff 0x1234abcd}"); + TestDump(std::vector{0, -1, std::numeric_limits::max()}, + lldb::Format::eFormatVectorOfSInt64, "{0 -1 9223372036854775807}"); + TestDump(std::vector{0, 0xaaaabbbbccccdddd}, + lldb::Format::eFormatVectorOfUInt64, + "{0x0000000000000000 0xaaaabbbbccccdddd}"); + + // See half2float for format details. + // Test zeroes. + TestDump(std::vector{0x0000, 0x8000}, + lldb::Format::eFormatVectorOfFloat16, "{0 -0}"); + // Some subnormal numbers. + TestDump(std::vector{0x0001, 0x8001}, + lldb::Format::eFormatVectorOfFloat16, "{5.96046e-08 -5.96046e-08}"); + // A full mantisse and empty expontent. + TestDump(std::vector{0x83ff, 0x03ff}, + lldb::Format::eFormatVectorOfFloat16, "{-6.09756e-05 6.09756e-05}"); + // Some normal numbers. + TestDump(std::vector{0b0100001001001000}, + lldb::Format::eFormatVectorOfFloat16, +#ifdef _WIN32 + // FIXME: This should print the same on all platforms. + "{3.14063}"); +#else + "{3.14062}"); +#endif + // Largest and smallest normal number. + TestDump(std::vector{0x0400, 0x7bff}, + lldb::Format::eFormatVectorOfFloat16, "{6.10352e-05 65504}"); + TestDump(std::vector{0xabcd, 0x1234}, + lldb::Format::eFormatVectorOfFloat16, "{-0.0609436 0.000757217}"); + + // quiet/signaling NaNs. + TestDump(std::vector{0xffff, 0xffc0, 0x7fff, 0x7fc0}, + lldb::Format::eFormatVectorOfFloat16, "{-nan -nan nan nan}"); + // +/-Inf. + TestDump(std::vector{0xfc00, 0x7c00}, + lldb::Format::eFormatVectorOfFloat16, "{-inf inf}"); + + TestDump(std::vector{std::numeric_limits::min(), + std::numeric_limits::max()}, + lldb::Format::eFormatVectorOfFloat32, "{1.17549e-38 3.40282e+38}"); + TestDump(std::vector{std::numeric_limits::quiet_NaN(), + std::numeric_limits::signaling_NaN(), + -std::numeric_limits::quiet_NaN(), + -std::numeric_limits::signaling_NaN()}, + lldb::Format::eFormatVectorOfFloat32, "{nan nan -nan -nan}"); + TestDump(std::vector{std::numeric_limits::min(), + std::numeric_limits::max()}, + lldb::Format::eFormatVectorOfFloat64, + "{2.2250738585072e-308 1.79769313486232e+308}"); + TestDump( + std::vector{ + std::numeric_limits::quiet_NaN(), + std::numeric_limits::signaling_NaN(), + -std::numeric_limits::quiet_NaN(), + -std::numeric_limits::signaling_NaN(), + }, + lldb::Format::eFormatVectorOfFloat64, "{nan nan -nan -nan}"); + + // Not sure we can rely on having uint128_t everywhere so emulate with + // uint64_t. + TestDump( + std::vector{0x1, 0x1111222233334444, 0xaaaabbbbccccdddd, 0x0}, + lldb::Format::eFormatVectorOfUInt128, + "{0x11112222333344440000000000000001 " + "0x0000000000000000aaaabbbbccccdddd}"); + + TestDump(std::vector{2, 4}, lldb::Format::eFormatComplexInteger, + "2 + 4i"); + + // Without an execution context this just prints the pointer on its own. + TestDump(0x11223344, lldb::Format::eFormatAddressInfo, + "0x11223344"); + + // Input not written in hex form because that requires C++17. + TestDump(10, lldb::Format::eFormatHexFloat, "0x1.4p3"); + TestDump(10, lldb::Format::eFormatHexFloat, "0x1.4p3"); + // long double not supported, see ItemByteSizeErrors. + + // Can't disassemble without an execution context. + TestDump(0xcafef00d, lldb::Format::eFormatInstruction, + "invalid target"); + + // Has no special handling, intended for use elsewhere. + TestDump(99, lldb::Format::eFormatVoid, "0x00000063"); +} + +TEST(DumpDataExtractorTest, FormatCharArray) { + // Unlike the other formats, charArray isn't 1 array of N chars. + // It must be passed as N chars of 1 byte each. + // (eFormatVectorOfChar does this swap for you) + std::vector data{'A', '\x01', '#'}; + StreamString result; + DataBufferHeap dumpbuffer(&data[0], data.size()); + DataExtractor extractor(dumpbuffer.GetBytes(), dumpbuffer.GetByteSize(), + endian::InlHostByteOrder(), /*addr_size=*/4); + + DumpDataExtractor(extractor, &result, 0, lldb::Format::eFormatCharArray, + /*item_byte_size=*/1, + /*item_count=*/data.size(), + /*num_per_line=*/data.size(), 0, 0, 0); + ASSERT_EQ("0x00000000: A\\x01#", result.GetString()); + + result.Clear(); + DumpDataExtractor(extractor, &result, 0, lldb::Format::eFormatCharArray, 1, + data.size(), 1, 0, 0, 0); + // ASSERT macro thinks the split strings are multiple arguments so make a var. + const char *expected = "0x00000000: A\n" + "0x00000001: \\x01\n" + "0x00000002: #"; + ASSERT_EQ(expected, result.GetString()); +} + +template +void TestDumpMultiLine(std::vector data, lldb::Format format, + size_t num_per_line, llvm::StringRef expected) { + size_t sz_bytes = data.size() * sizeof(T); + TestDumpImpl(&data[0], sz_bytes, data.size(), sz_bytes, num_per_line, + 0x80000000, format, expected); +} + +template +void TestDumpMultiLine(const T *data, size_t num_items, lldb::Format format, + size_t num_per_line, llvm::StringRef expected) { + TestDumpImpl(data, sizeof(T) * num_items, sizeof(T), num_items, num_per_line, + 0x80000000, format, expected); +} + +TEST(DumpDataExtractorTest, MultiLine) { + // A vector counts as 1 item regardless of size. + TestDumpMultiLine(std::vector{0x11}, + lldb::Format::eFormatVectorOfUInt8, 1, + "0x80000000: {0x11}"); + TestDumpMultiLine(std::vector{0x11, 0x22}, + lldb::Format::eFormatVectorOfUInt8, 1, + "0x80000000: {0x11 0x22}"); + + // If you have multiple vectors then that's multiple items. + // Here we say that these 2 bytes are actually 2 1 byte vectors. + const std::vector vector_data{0x11, 0x22}; + TestDumpMultiLine(vector_data.data(), 2, lldb::Format::eFormatVectorOfUInt8, + 1, "0x80000000: {0x11}\n0x80000001: {0x22}"); + + // Single value formats can span multiple lines. + const std::vector bytes{0x11, 0x22, 0x33}; + const char *expected_bytes_3_line = "0x80000000: 0x11\n" + "0x80000001: 0x22\n" + "0x80000002: 0x33"; + TestDumpMultiLine(bytes.data(), bytes.size(), lldb::Format::eFormatHex, 1, + expected_bytes_3_line); + + // Lines may not have the full number of items. + TestDumpMultiLine(bytes.data(), bytes.size(), lldb::Format::eFormatHex, 4, + "0x80000000: 0x11 0x22 0x33"); + const char *expected_bytes_2_line = "0x80000000: 0x11 0x22\n" + "0x80000002: 0x33"; + TestDumpMultiLine(bytes.data(), bytes.size(), lldb::Format::eFormatHex, 2, + expected_bytes_2_line); + + // The line address accounts for item sizes other than 1 byte. + const std::vector shorts{0x1111, 0x2222, 0x3333}; + const char *expected_shorts_2_line = "0x80000000: 0x1111 0x2222\n" + "0x80000004: 0x3333"; + TestDumpMultiLine(shorts.data(), shorts.size(), lldb::Format::eFormatHex, 2, + expected_shorts_2_line); + + // The ascii column is positioned using the maximum line length. + const std::vector chars{'L', 'L', 'D', 'B'}; + const char *expected_chars_2_lines = "0x80000000: 4c 4c 44 LLD\n" + "0x80000003: 42 B"; + TestDumpMultiLine(chars.data(), chars.size(), + lldb::Format::eFormatBytesWithASCII, 3, + expected_chars_2_lines); +} + +void TestDumpWithItemByteSize(size_t item_byte_size, lldb::Format format, + llvm::StringRef expected) { + // We won't be reading this data so anything will do. + uint8_t dummy = 0; + TestDumpImpl(&dummy, 1, item_byte_size, 1, 1, LLDB_INVALID_ADDRESS, format, + expected); +} + +TEST(DumpDataExtractorTest, ItemByteSizeErrors) { + TestDumpWithItemByteSize( + 16, lldb::Format::eFormatBoolean, + "error: unsupported byte size (16) for boolean format"); + TestDumpWithItemByteSize(21, lldb::Format::eFormatChar, + "error: unsupported byte size (21) for char format"); + TestDumpWithItemByteSize( + 18, lldb::Format::eFormatComplexInteger, + "error: unsupported byte size (18) for complex integer format"); + + // The code uses sizeof(long double) for these checks. This changes by host + // but we know it won't be >16. + TestDumpWithItemByteSize( + 34, lldb::Format::eFormatComplex, + "error: unsupported byte size (34) for complex float format"); + TestDumpWithItemByteSize( + 18, lldb::Format::eFormatFloat, + "error: unsupported byte size (18) for float format"); + + // We want sizes to exactly match one of float/double. + TestDumpWithItemByteSize( + 14, lldb::Format::eFormatComplex, + "error: unsupported byte size (14) for complex float format"); + TestDumpWithItemByteSize(3, lldb::Format::eFormatFloat, + "error: unsupported byte size (3) for float format"); + + // We only allow float and double size. + TestDumpWithItemByteSize( + 1, lldb::Format::eFormatHexFloat, + "error: unsupported byte size (1) for hex float format"); + TestDumpWithItemByteSize( + 17, lldb::Format::eFormatHexFloat, + "error: unsupported byte size (17) for hex float format"); +} diff --git a/gnu/llvm/lldb/unittests/Core/FormatEntityTest.cpp b/gnu/llvm/lldb/unittests/Core/FormatEntityTest.cpp new file mode 100644 index 00000000000..c22dd439957 --- /dev/null +++ b/gnu/llvm/lldb/unittests/Core/FormatEntityTest.cpp @@ -0,0 +1,159 @@ +//===-- FormatEntityTest.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 "lldb/Core/FormatEntity.h" +#include "lldb/Utility/Status.h" + +#include "llvm/ADT/StringRef.h" +#include "gtest/gtest.h" + +using namespace lldb_private; + +using Definition = FormatEntity::Entry::Definition; +using Entry = FormatEntity::Entry; + +TEST(FormatEntityTest, DefinitionConstructionNameAndType) { + Definition d("foo", FormatEntity::Entry::Type::Invalid); + + EXPECT_EQ(d.name, "foo"); + EXPECT_EQ(d.string, nullptr); + EXPECT_EQ(d.type, FormatEntity::Entry::Type::Invalid); + EXPECT_EQ(d.data, 0UL); + EXPECT_EQ(d.num_children, 0UL); + EXPECT_EQ(d.children, nullptr); + EXPECT_FALSE(d.keep_separator); +} + +TEST(FormatEntityTest, DefinitionConstructionNameAndString) { + Definition d("foo", "string"); + + EXPECT_EQ(d.name, "foo"); + EXPECT_EQ(d.string, "string"); + EXPECT_EQ(d.type, FormatEntity::Entry::Type::EscapeCode); + EXPECT_EQ(d.data, 0UL); + EXPECT_EQ(d.num_children, 0UL); + EXPECT_EQ(d.children, nullptr); + EXPECT_FALSE(d.keep_separator); +} + +TEST(FormatEntityTest, DefinitionConstructionNameTypeData) { + Definition d("foo", FormatEntity::Entry::Type::Invalid, 33); + + EXPECT_EQ(d.name, "foo"); + EXPECT_EQ(d.string, nullptr); + EXPECT_EQ(d.type, FormatEntity::Entry::Type::Invalid); + EXPECT_EQ(d.data, 33UL); + EXPECT_EQ(d.num_children, 0UL); + EXPECT_EQ(d.children, nullptr); + EXPECT_FALSE(d.keep_separator); +} + +TEST(FormatEntityTest, DefinitionConstructionNameTypeChildren) { + Definition d("foo", FormatEntity::Entry::Type::Invalid, 33); + Definition parent("parent", FormatEntity::Entry::Type::Invalid, 1, &d); + EXPECT_EQ(parent.name, "parent"); + EXPECT_EQ(parent.string, nullptr); + EXPECT_EQ(parent.type, FormatEntity::Entry::Type::Invalid); + EXPECT_EQ(parent.num_children, 1UL); + EXPECT_EQ(parent.children, &d); + EXPECT_FALSE(parent.keep_separator); + + EXPECT_EQ(parent.children[0].name, "foo"); + EXPECT_EQ(parent.children[0].string, nullptr); + EXPECT_EQ(parent.children[0].type, FormatEntity::Entry::Type::Invalid); + EXPECT_EQ(parent.children[0].data, 33UL); + EXPECT_EQ(parent.children[0].num_children, 0UL); + EXPECT_EQ(parent.children[0].children, nullptr); + EXPECT_FALSE(d.keep_separator); +} + +constexpr llvm::StringRef lookupStrings[] = { + "${addr.load}", + "${addr.file}", + "${ansi.fg.black}", + "${ansi.fg.red}", + "${ansi.fg.green}", + "${ansi.fg.yellow}", + "${ansi.fg.blue}", + "${ansi.fg.purple}", + "${ansi.fg.cyan}", + "${ansi.fg.white}", + "${ansi.bg.black}", + "${ansi.bg.red}", + "${ansi.bg.green}", + "${ansi.bg.yellow}", + "${ansi.bg.blue}", + "${ansi.bg.purple}", + "${ansi.bg.cyan}", + "${ansi.bg.white}", + "${file.basename}", + "${file.dirname}", + "${file.fullpath}", + "${frame.index}", + "${frame.pc}", + "${frame.fp}", + "${frame.sp}", + "${frame.flags}", + "${frame.no-debug}", + "${frame.reg.*}", + "${frame.is-artificial}", + "${function.id}", + "${function.name}", + "${function.name-without-args}", + "${function.name-with-args}", + "${function.mangled-name}", + "${function.addr-offset}", + "${function.concrete-only-addr-offset-no-padding}", + "${function.line-offset}", + "${function.pc-offset}", + "${function.initial-function}", + "${function.changed}", + "${function.is-optimized}", + "${line.file.basename}", + "${line.file.dirname}", + "${line.file.fullpath}", + "${line.number}", + "${line.column}", + "${line.start-addr}", + "${line.end-addr}", + "${module.file.basename}", + "${module.file.dirname}", + "${module.file.fullpath}", + "${process.id}", + "${process.name}", + "${process.file.basename}", + "${process.file.dirname}", + "${process.file.fullpath}", + "${script.frame}", + "${script.process}", + "${script.target}", + "${script.thread}", + "${script.var}", + "${script.svar}", + "${script.thread}", + "${svar.dummy-svar-to-test-wildcard}", + "${thread.id}", + "${thread.protocol_id}", + "${thread.index}", + "${thread.info.*}", + "${thread.queue}", + "${thread.name}", + "${thread.stop-reason}", + "${thread.stop-reason-raw}", + "${thread.return-value}", + "${thread.completed-expression}", + "${target.arch}", + "${var.dummy-var-to-test-wildcard}"}; + +TEST(FormatEntity, LookupAllEntriesInTree) { + for (const llvm::StringRef testString : lookupStrings) { + Entry e; + EXPECT_TRUE(FormatEntity::Parse(testString, e).Success()) + << "Formatting " << testString << " did not succeed"; + } +} diff --git a/gnu/llvm/lldb/unittests/Core/MangledTest.cpp b/gnu/llvm/lldb/unittests/Core/MangledTest.cpp index 6e1bdd59978..431993fccb1 100644 --- a/gnu/llvm/lldb/unittests/Core/MangledTest.cpp +++ b/gnu/llvm/lldb/unittests/Core/MangledTest.cpp @@ -55,6 +55,23 @@ TEST(MangledTest, EmptyForInvalidName) { EXPECT_STREQ("", TheDemangled.GetCString()); } +TEST(MangledTest, ResultForValidRustV0Name) { + ConstString mangled_name("_RNvC1a4main"); + Mangled the_mangled(mangled_name); + ConstString the_demangled = the_mangled.GetDemangledName(); + + ConstString expected_result("a::main"); + EXPECT_STREQ(expected_result.GetCString(), the_demangled.GetCString()); +} + +TEST(MangledTest, EmptyForInvalidRustV0Name) { + ConstString mangled_name("_RRR"); + Mangled the_mangled(mangled_name); + ConstString the_demangled = the_mangled.GetDemangledName(); + + EXPECT_STREQ("", the_demangled.GetCString()); +} + TEST(MangledTest, NameIndexes_FindFunctionSymbols) { SubsystemRAII subsystems; diff --git a/gnu/llvm/lldb/unittests/Core/SourceLocationSpecTest.cpp b/gnu/llvm/lldb/unittests/Core/SourceLocationSpecTest.cpp new file mode 100644 index 00000000000..b79662f865f --- /dev/null +++ b/gnu/llvm/lldb/unittests/Core/SourceLocationSpecTest.cpp @@ -0,0 +1,183 @@ +//===-- SourceLocationSpecTest.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 "gtest/gtest.h" + +#include "lldb/Core/SourceLocationSpec.h" +#include "lldb/Utility/LLDBAssert.h" + +#include "llvm/Testing/Support/Error.h" + +using namespace lldb_private; + +TEST(SourceLocationSpecTest, OperatorBool) { + SourceLocationSpec invalid(FileSpec(), 0); + EXPECT_FALSE(invalid); + + SourceLocationSpec invalid_filespec(FileSpec(), 4); + EXPECT_FALSE(invalid_filespec); + + SourceLocationSpec invalid_line(FileSpec("/foo/bar"), 0); + EXPECT_FALSE(invalid_line); + + SourceLocationSpec valid_fs_line_no_column(FileSpec("/foo/bar"), 4); + EXPECT_TRUE(valid_fs_line_no_column); + + SourceLocationSpec invalid_fs_column(FileSpec(), 4, 0); + EXPECT_FALSE(invalid_fs_column); + + SourceLocationSpec invalid_line_column(FileSpec("/foo/bar"), 0, 19); + EXPECT_FALSE(invalid_line_column); + + SourceLocationSpec valid_fs_line_zero_column(FileSpec("/foo/bar"), 4, 0); + EXPECT_TRUE(valid_fs_line_zero_column); + + SourceLocationSpec valid_fs_line_column(FileSpec("/foo/bar"), 4, 19); + EXPECT_TRUE(valid_fs_line_column); +} + +TEST(SourceLocationSpecTest, FileLineColumnComponents) { + FileSpec fs("/foo/bar", FileSpec::Style::posix); + const uint32_t line = 19; + const uint16_t column = 4; + + SourceLocationSpec without_column(fs, line, LLDB_INVALID_COLUMN_NUMBER, false, + true); + EXPECT_TRUE(without_column); + EXPECT_EQ(fs, without_column.GetFileSpec()); + EXPECT_EQ(line, without_column.GetLine().getValueOr(0)); + EXPECT_EQ(llvm::None, without_column.GetColumn()); + EXPECT_FALSE(without_column.GetCheckInlines()); + EXPECT_TRUE(without_column.GetExactMatch()); + EXPECT_STREQ("check inlines = false, exact match = true, decl = /foo/bar:19", + without_column.GetString().c_str()); + + SourceLocationSpec with_column(fs, line, column, true, false); + EXPECT_TRUE(with_column); + EXPECT_EQ(column, *with_column.GetColumn()); + EXPECT_TRUE(with_column.GetCheckInlines()); + EXPECT_FALSE(with_column.GetExactMatch()); + EXPECT_STREQ( + "check inlines = true, exact match = false, decl = /foo/bar:19:4", + with_column.GetString().c_str()); +} + +static SourceLocationSpec Create(bool check_inlines, bool exact_match, + FileSpec fs, uint32_t line, + uint16_t column = LLDB_INVALID_COLUMN_NUMBER) { + return SourceLocationSpec(fs, line, column, check_inlines, exact_match); +} + +TEST(SourceLocationSpecTest, Equal) { + auto Equal = [](SourceLocationSpec lhs, SourceLocationSpec rhs, bool full) { + return SourceLocationSpec::Equal(lhs, rhs, full); + }; + + const FileSpec fs("/foo/bar", FileSpec::Style::posix); + const FileSpec other_fs("/foo/baz", FileSpec::Style::posix); + + // mutating FileSpec + const Inlined, ExactMatch, Line + EXPECT_TRUE( + Equal(Create(false, false, fs, 4), Create(false, false, fs, 4), true)); + EXPECT_TRUE( + Equal(Create(true, true, fs, 4), Create(true, true, fs, 4), false)); + EXPECT_FALSE(Equal(Create(false, false, fs, 4), + Create(false, false, other_fs, 4), true)); + EXPECT_FALSE( + Equal(Create(true, true, fs, 4), Create(true, true, other_fs, 4), false)); + + // Mutating FileSpec + const Inlined, ExactMatch, Line, Column + EXPECT_TRUE(Equal(Create(false, false, fs, 4, 19), + Create(false, false, fs, 4, 19), true)); + EXPECT_TRUE(Equal(Create(true, true, fs, 4, 19), + Create(true, true, fs, 4, 19), false)); + EXPECT_FALSE(Equal(Create(false, false, fs, 4, 19), + Create(false, false, other_fs, 4, 19), true)); + EXPECT_FALSE(Equal(Create(true, true, fs, 4, 19), + Create(true, true, other_fs, 4, 19), false)); + + // Asymetric match + EXPECT_FALSE( + Equal(Create(true, true, fs, 4), Create(true, true, fs, 4, 19), true)); + EXPECT_TRUE(Equal(Create(false, false, fs, 4), + Create(false, false, fs, 4, 19), false)); + + // Mutating Inlined, ExactMatch + EXPECT_FALSE( + Equal(Create(true, false, fs, 4), Create(false, true, fs, 4), true)); + EXPECT_TRUE( + Equal(Create(false, true, fs, 4), Create(true, false, fs, 4), false)); + + // Mutating Column + EXPECT_FALSE(Equal(Create(true, true, fs, 4, 96), + Create(true, true, fs, 4, 19), true)); + EXPECT_TRUE(Equal(Create(false, false, fs, 4, 96), + Create(false, false, fs, 4, 19), false)); +} + +TEST(SourceLocationSpecTest, Compare) { + auto Cmp = [](SourceLocationSpec a, SourceLocationSpec b) { + return SourceLocationSpec::Compare(a, b); + }; + + FileSpec fs("/foo/bar", FileSpec::Style::posix); + FileSpec other_fs("/foo/baz", FileSpec::Style::posix); + + // Asymetric comparaison + EXPECT_EQ(-1, Cmp(Create(true, true, fs, 4), Create(true, true, fs, 4, 19))); + EXPECT_EQ(-1, + Cmp(Create(false, false, fs, 4), Create(false, false, fs, 4, 19))); + EXPECT_EQ(1, Cmp(Create(true, true, fs, 4, 19), Create(true, true, fs, 4))); + + // Mutating FS, const Line + EXPECT_EQ( + -1, Cmp(Create(false, false, fs, 4), Create(false, false, other_fs, 4))); + EXPECT_EQ(-1, + Cmp(Create(true, true, fs, 4), Create(true, true, other_fs, 4))); + EXPECT_EQ(1, + Cmp(Create(false, true, other_fs, 4), Create(false, true, fs, 4))); + EXPECT_EQ(1, + Cmp(Create(true, false, other_fs, 4), Create(true, false, fs, 4))); + + // Const FS, mutating Line + EXPECT_EQ(-1, Cmp(Create(false, false, fs, 1), Create(false, false, fs, 4))); + EXPECT_EQ(-1, Cmp(Create(true, true, fs, 1), Create(true, true, fs, 4))); + EXPECT_EQ(0, Cmp(Create(false, true, fs, 4), Create(false, true, fs, 4))); + EXPECT_EQ(0, Cmp(Create(true, false, fs, 4), Create(true, false, fs, 4))); + EXPECT_EQ(1, Cmp(Create(false, false, fs, 4), Create(false, false, fs, 1))); + EXPECT_EQ(1, Cmp(Create(true, true, fs, 4), Create(true, true, fs, 1))); + + // Const FS, mutating Line, const Column + EXPECT_EQ(-1, + Cmp(Create(false, true, fs, 1), Create(false, true, fs, 4, 19))); + EXPECT_EQ(-1, Cmp(Create(true, true, fs, 1), Create(true, true, fs, 4, 19))); + EXPECT_EQ(1, Cmp(Create(true, false, fs, 4, 19), Create(true, false, fs, 1))); + EXPECT_EQ(1, Cmp(Create(true, false, fs, 4, 19), Create(true, false, fs, 1))); + + // Mutating FS, const Line, const Column + EXPECT_EQ(-1, Cmp(Create(false, false, fs, 4, 19), + Create(false, false, other_fs, 4, 19))); + EXPECT_EQ(-1, Cmp(Create(true, true, fs, 4, 19), + Create(true, true, other_fs, 4, 19))); + EXPECT_EQ( + 0, Cmp(Create(false, false, fs, 4, 19), Create(false, false, fs, 4, 19))); + EXPECT_EQ(0, + Cmp(Create(true, true, fs, 4, 19), Create(true, true, fs, 4, 19))); + EXPECT_EQ(1, Cmp(Create(false, true, other_fs, 4, 19), + Create(false, true, fs, 4, 19))); + EXPECT_EQ(1, Cmp(Create(true, false, other_fs, 4, 19), + Create(true, false, fs, 4, 19))); + + // Const FS, const Line, mutating Column + EXPECT_EQ(-1, Cmp(Create(false, false, fs, 4, 19), + Create(false, false, fs, 4, 96))); + EXPECT_EQ(1, + Cmp(Create(true, true, fs, 4, 96), Create(true, true, fs, 4, 19))); + EXPECT_EQ( + 1, Cmp(Create(false, true, fs, 4, 96), Create(false, true, fs, 4, 19))); +} diff --git a/gnu/llvm/lldb/unittests/DataFormatter/CMakeLists.txt b/gnu/llvm/lldb/unittests/DataFormatter/CMakeLists.txt index 45011c56b0b..9d967a72bfd 100644 --- a/gnu/llvm/lldb/unittests/DataFormatter/CMakeLists.txt +++ b/gnu/llvm/lldb/unittests/DataFormatter/CMakeLists.txt @@ -1,5 +1,6 @@ add_lldb_unittest(LLDBFormatterTests FormatManagerTests.cpp + FormattersContainerTest.cpp StringPrinterTests.cpp LINK_LIBS diff --git a/gnu/llvm/lldb/unittests/DataFormatter/FormattersContainerTest.cpp b/gnu/llvm/lldb/unittests/DataFormatter/FormattersContainerTest.cpp new file mode 100644 index 00000000000..a28212391ea --- /dev/null +++ b/gnu/llvm/lldb/unittests/DataFormatter/FormattersContainerTest.cpp @@ -0,0 +1,159 @@ +//===-- FormattersContainerTests.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 "lldb/DataFormatters/FormattersContainer.h" + +#include "gtest/gtest.h" + +using namespace lldb; +using namespace lldb_private; + +// All the prefixes that the exact name matching will strip from the type. +static const std::vector exact_name_prefixes = { + "", // no prefix. + "class ", "struct ", "union ", "enum ", +}; + +// TypeMatcher that uses a exact type name string that needs to be matched. +TEST(TypeMatcherTests, ExactName) { + for (const std::string &prefix : exact_name_prefixes) { + SCOPED_TRACE("Prefix: " + prefix); + + TypeMatcher matcher(ConstString(prefix + "Name")); + EXPECT_TRUE(matcher.Matches(ConstString("class Name"))); + EXPECT_TRUE(matcher.Matches(ConstString("struct Name"))); + EXPECT_TRUE(matcher.Matches(ConstString("union Name"))); + EXPECT_TRUE(matcher.Matches(ConstString("enum Name"))); + EXPECT_TRUE(matcher.Matches(ConstString("Name"))); + + EXPECT_FALSE(matcher.Matches(ConstString("Name "))); + EXPECT_FALSE(matcher.Matches(ConstString("ame"))); + EXPECT_FALSE(matcher.Matches(ConstString("Nam"))); + EXPECT_FALSE(matcher.Matches(ConstString("am"))); + EXPECT_FALSE(matcher.Matches(ConstString("a"))); + EXPECT_FALSE(matcher.Matches(ConstString(" "))); + EXPECT_FALSE(matcher.Matches(ConstString("class N"))); + EXPECT_FALSE(matcher.Matches(ConstString("class "))); + EXPECT_FALSE(matcher.Matches(ConstString("class"))); + } +} + +// TypeMatcher that uses a regex to match a type name. +TEST(TypeMatcherTests, RegexName) { + TypeMatcher matcher(RegularExpression("^a[a-z]c$")); + EXPECT_TRUE(matcher.Matches(ConstString("abc"))); + EXPECT_TRUE(matcher.Matches(ConstString("azc"))); + + // FIXME: This isn't consistent with the 'exact' type name matches above. + EXPECT_FALSE(matcher.Matches(ConstString("class abc"))); + + EXPECT_FALSE(matcher.Matches(ConstString("abbc"))); + EXPECT_FALSE(matcher.Matches(ConstString(" abc"))); + EXPECT_FALSE(matcher.Matches(ConstString("abc "))); + EXPECT_FALSE(matcher.Matches(ConstString(" abc "))); + EXPECT_FALSE(matcher.Matches(ConstString("XabcX"))); + EXPECT_FALSE(matcher.Matches(ConstString("ac"))); + EXPECT_FALSE(matcher.Matches(ConstString("a[a-z]c"))); + EXPECT_FALSE(matcher.Matches(ConstString("aAc"))); + EXPECT_FALSE(matcher.Matches(ConstString("ABC"))); + EXPECT_FALSE(matcher.Matches(ConstString(""))); +} + +// TypeMatcher that only searches the type name. +TEST(TypeMatcherTests, RegexMatchPart) { + TypeMatcher matcher(RegularExpression("a[a-z]c")); + EXPECT_TRUE(matcher.Matches(ConstString("class abc"))); + EXPECT_TRUE(matcher.Matches(ConstString("abc"))); + EXPECT_TRUE(matcher.Matches(ConstString(" abc "))); + EXPECT_TRUE(matcher.Matches(ConstString("azc"))); + EXPECT_TRUE(matcher.Matches(ConstString("abc "))); + EXPECT_TRUE(matcher.Matches(ConstString(" abc "))); + EXPECT_TRUE(matcher.Matches(ConstString(" abc"))); + EXPECT_TRUE(matcher.Matches(ConstString("XabcX"))); + + EXPECT_FALSE(matcher.Matches(ConstString("abbc"))); + EXPECT_FALSE(matcher.Matches(ConstString("ac"))); + EXPECT_FALSE(matcher.Matches(ConstString("a[a-z]c"))); + EXPECT_FALSE(matcher.Matches(ConstString("aAc"))); + EXPECT_FALSE(matcher.Matches(ConstString("ABC"))); + EXPECT_FALSE(matcher.Matches(ConstString(""))); +} + +// GetMatchString for exact type name matchers. +TEST(TypeMatcherTests, GetMatchStringExactName) { + EXPECT_EQ(TypeMatcher(ConstString("aa")).GetMatchString(), "aa"); + EXPECT_EQ(TypeMatcher(ConstString("")).GetMatchString(), ""); + EXPECT_EQ(TypeMatcher(ConstString("[a]")).GetMatchString(), "[a]"); +} + +// GetMatchString for regex matchers. +TEST(TypeMatcherTests, GetMatchStringRegex) { + EXPECT_EQ(TypeMatcher(RegularExpression("aa")).GetMatchString(), "aa"); + EXPECT_EQ(TypeMatcher(RegularExpression("")).GetMatchString(), ""); + EXPECT_EQ(TypeMatcher(RegularExpression("[a]")).GetMatchString(), "[a]"); +} + +// GetMatchString for regex matchers. +TEST(TypeMatcherTests, CreatedBySameMatchString) { + TypeMatcher empty_str(ConstString("")); + TypeMatcher empty_regex(RegularExpression("")); + EXPECT_TRUE(empty_str.CreatedBySameMatchString(empty_str)); + EXPECT_TRUE(empty_str.CreatedBySameMatchString(empty_regex)); + + TypeMatcher a_str(ConstString("a")); + TypeMatcher a_regex(RegularExpression("a")); + EXPECT_TRUE(a_str.CreatedBySameMatchString(a_str)); + EXPECT_TRUE(a_str.CreatedBySameMatchString(a_regex)); + + TypeMatcher digit_str(ConstString("[0-9]")); + TypeMatcher digit_regex(RegularExpression("[0-9]")); + EXPECT_TRUE(digit_str.CreatedBySameMatchString(digit_str)); + EXPECT_TRUE(digit_str.CreatedBySameMatchString(digit_regex)); + + EXPECT_FALSE(empty_str.CreatedBySameMatchString(a_str)); + EXPECT_FALSE(empty_str.CreatedBySameMatchString(a_regex)); + EXPECT_FALSE(empty_str.CreatedBySameMatchString(digit_str)); + EXPECT_FALSE(empty_str.CreatedBySameMatchString(digit_regex)); + + EXPECT_FALSE(empty_regex.CreatedBySameMatchString(a_str)); + EXPECT_FALSE(empty_regex.CreatedBySameMatchString(a_regex)); + EXPECT_FALSE(empty_regex.CreatedBySameMatchString(digit_str)); + EXPECT_FALSE(empty_regex.CreatedBySameMatchString(digit_regex)); + + EXPECT_FALSE(a_str.CreatedBySameMatchString(empty_str)); + EXPECT_FALSE(a_str.CreatedBySameMatchString(empty_regex)); + EXPECT_FALSE(a_str.CreatedBySameMatchString(digit_str)); + EXPECT_FALSE(a_str.CreatedBySameMatchString(digit_regex)); + + EXPECT_FALSE(a_regex.CreatedBySameMatchString(empty_str)); + EXPECT_FALSE(a_regex.CreatedBySameMatchString(empty_regex)); + EXPECT_FALSE(a_regex.CreatedBySameMatchString(digit_str)); + EXPECT_FALSE(a_regex.CreatedBySameMatchString(digit_regex)); + + EXPECT_FALSE(digit_str.CreatedBySameMatchString(empty_str)); + EXPECT_FALSE(digit_str.CreatedBySameMatchString(empty_regex)); + EXPECT_FALSE(digit_str.CreatedBySameMatchString(a_str)); + EXPECT_FALSE(digit_str.CreatedBySameMatchString(a_regex)); + + EXPECT_FALSE(digit_regex.CreatedBySameMatchString(empty_str)); + EXPECT_FALSE(digit_regex.CreatedBySameMatchString(empty_regex)); + EXPECT_FALSE(digit_regex.CreatedBySameMatchString(a_str)); + EXPECT_FALSE(digit_regex.CreatedBySameMatchString(a_regex)); +} + +// Test CreatedBySameMatchString with stripped exact name prefixes. +TEST(TypeMatcherTests, CreatedBySameMatchStringExactNamePrefixes) { + for (const std::string &prefix : exact_name_prefixes) { + SCOPED_TRACE("Prefix: " + prefix); + TypeMatcher with_prefix(ConstString(prefix + "Name")); + TypeMatcher without_prefix(RegularExpression("")); + + EXPECT_TRUE(with_prefix.CreatedBySameMatchString(with_prefix)); + EXPECT_TRUE(without_prefix.CreatedBySameMatchString(without_prefix)); + } +} diff --git a/gnu/llvm/lldb/unittests/Editline/CMakeLists.txt b/gnu/llvm/lldb/unittests/Editline/CMakeLists.txt index 220e263ce21..4b2643d15c5 100644 --- a/gnu/llvm/lldb/unittests/Editline/CMakeLists.txt +++ b/gnu/llvm/lldb/unittests/Editline/CMakeLists.txt @@ -4,4 +4,5 @@ add_lldb_unittest(EditlineTests LINK_LIBS lldbHost lldbUtility + LLVMTestingSupport ) diff --git a/gnu/llvm/lldb/unittests/Editline/EditlineTest.cpp b/gnu/llvm/lldb/unittests/Editline/EditlineTest.cpp index 291ab3cb368..53184811450 100644 --- a/gnu/llvm/lldb/unittests/Editline/EditlineTest.cpp +++ b/gnu/llvm/lldb/unittests/Editline/EditlineTest.cpp @@ -81,8 +81,8 @@ public: void ConsumeAllOutput(); private: - static bool IsInputComplete(lldb_private::Editline *editline, - lldb_private::StringList &lines, void *baton); + bool IsInputComplete(lldb_private::Editline *editline, + lldb_private::StringList &lines); std::unique_ptr _editline_sp; @@ -99,14 +99,7 @@ EditlineAdapter::EditlineAdapter() lldb_private::Status error; // Open the first master pty available. - char error_string[256]; - error_string[0] = '\0'; - if (!_pty.OpenFirstAvailablePrimary(O_RDWR, error_string, - sizeof(error_string))) { - fprintf(stderr, "failed to open first available master pty: '%s'\n", - error_string); - return; - } + EXPECT_THAT_ERROR(_pty.OpenFirstAvailablePrimary(O_RDWR), llvm::Succeeded()); // Grab the master fd. This is a file descriptor we will: // (1) write to when we want to send input to editline. @@ -114,10 +107,7 @@ EditlineAdapter::EditlineAdapter() _pty_master_fd = _pty.GetPrimaryFileDescriptor(); // Open the corresponding secondary pty. - if (!_pty.OpenSecondary(O_RDWR, error_string, sizeof(error_string))) { - fprintf(stderr, "failed to open secondary pty: '%s'\n", error_string); - return; - } + EXPECT_THAT_ERROR(_pty.OpenSecondary(O_RDWR), llvm::Succeeded()); _pty_secondary_fd = _pty.GetSecondaryFileDescriptor(); _el_secondary_file.reset(new FilePointer(fdopen(_pty_secondary_fd, "rw"))); @@ -132,7 +122,10 @@ EditlineAdapter::EditlineAdapter() _editline_sp->SetPrompt("> "); // Hookup our input complete callback. - _editline_sp->SetIsInputCompleteCallback(IsInputComplete, this); + auto input_complete_cb = [this](Editline *editline, StringList &lines) { + return this->IsInputComplete(editline, lines); + }; + _editline_sp->SetIsInputCompleteCallback(input_complete_cb); } void EditlineAdapter::CloseInput() { @@ -193,8 +186,7 @@ bool EditlineAdapter::GetLines(lldb_private::StringList &lines, } bool EditlineAdapter::IsInputComplete(lldb_private::Editline *editline, - lldb_private::StringList &lines, - void *baton) { + lldb_private::StringList &lines) { // We'll call ourselves complete if we've received a balanced set of braces. int start_block_count = 0; int brace_balance = 0; diff --git a/gnu/llvm/lldb/unittests/Expression/CMakeLists.txt b/gnu/llvm/lldb/unittests/Expression/CMakeLists.txt index 2f5304ab212..185b19f84ca 100644 --- a/gnu/llvm/lldb/unittests/Expression/CMakeLists.txt +++ b/gnu/llvm/lldb/unittests/Expression/CMakeLists.txt @@ -7,9 +7,12 @@ add_lldb_unittest(ExpressionTests LINK_LIBS lldbCore + lldbPluginObjectFileELF + lldbPluginPlatformLinux lldbPluginExpressionParserClang lldbPluginTypeSystemClang lldbUtility lldbUtilityHelpers + lldbSymbolHelpers LLVMTestingSupport ) diff --git a/gnu/llvm/lldb/unittests/Expression/ClangParserTest.cpp b/gnu/llvm/lldb/unittests/Expression/ClangParserTest.cpp index 81f9ed839fc..4df55747531 100644 --- a/gnu/llvm/lldb/unittests/Expression/ClangParserTest.cpp +++ b/gnu/llvm/lldb/unittests/Expression/ClangParserTest.cpp @@ -11,6 +11,7 @@ #include "Plugins/ExpressionParser/Clang/ClangHost.h" #include "TestingSupport/SubsystemRAII.h" #include "TestingSupport/TestUtilities.h" +#include "lldb/Host/Config.h" #include "lldb/Host/FileSystem.h" #include "lldb/Host/HostInfo.h" #include "lldb/Utility/FileSpec.h" @@ -36,7 +37,7 @@ static std::string ComputeClangResourceDir(std::string lldb_shlib_path, TEST_F(ClangHostTest, ComputeClangResourceDirectory) { #if !defined(_WIN32) std::string path_to_liblldb = "/foo/bar/lib/"; - std::string path_to_clang_dir = "/foo/bar/lib/clang/" CLANG_VERSION_STRING; + std::string path_to_clang_dir = "/foo/bar/lib" LLDB_LIBDIR_SUFFIX "/clang/" CLANG_VERSION_STRING; #else std::string path_to_liblldb = "C:\\foo\\bar\\lib"; std::string path_to_clang_dir = "C:\\foo\\bar\\lib\\clang\\" CLANG_VERSION_STRING; diff --git a/gnu/llvm/lldb/unittests/Expression/CppModuleConfigurationTest.cpp b/gnu/llvm/lldb/unittests/Expression/CppModuleConfigurationTest.cpp index c3cc134bd5a..c1d0d00dcba 100644 --- a/gnu/llvm/lldb/unittests/Expression/CppModuleConfigurationTest.cpp +++ b/gnu/llvm/lldb/unittests/Expression/CppModuleConfigurationTest.cpp @@ -11,6 +11,7 @@ #include "TestingSupport/SubsystemRAII.h" #include "lldb/Host/FileSystem.h" #include "lldb/Host/HostInfo.h" +#include "llvm/Support/SmallVectorMemoryBuffer.h" #include "gmock/gmock.h" #include "gtest/gtest.h" @@ -19,7 +20,33 @@ using namespace lldb_private; namespace { struct CppModuleConfigurationTest : public testing::Test { - SubsystemRAII subsystems; + llvm::MemoryBufferRef m_empty_buffer; + llvm::IntrusiveRefCntPtr m_fs; + + CppModuleConfigurationTest() + : m_empty_buffer("", ""), + m_fs(new llvm::vfs::InMemoryFileSystem()) {} + + void SetUp() override { + FileSystem::Initialize(m_fs); + HostInfo::Initialize(); + } + + void TearDown() override { + HostInfo::Terminate(); + FileSystem::Terminate(); + } + + /// Utility function turning a list of paths into a FileSpecList. + FileSpecList makeFiles(llvm::ArrayRef paths) { + FileSpecList result; + for (const std::string &path : paths) { + result.Append(FileSpec(path, FileSpec::Style::posix)); + if (!m_fs->addFileNoOwn(path, static_cast(0), m_empty_buffer)) + llvm_unreachable("Invalid test configuration?"); + } + return result; + } }; } // namespace @@ -31,20 +58,18 @@ static std::string ResourceInc() { return std::string(resource_dir); } -/// Utility function turningn a list of paths into a FileSpecList. -static FileSpecList makeFiles(llvm::ArrayRef paths) { - FileSpecList result; - for (const std::string &path : paths) - result.Append(FileSpec(path, FileSpec::Style::posix)); - return result; -} TEST_F(CppModuleConfigurationTest, Linux) { // Test the average Linux configuration. - std::string libcpp = "/usr/include/c++/v1"; + std::string usr = "/usr/include"; - CppModuleConfiguration config( - makeFiles({usr + "/bits/types.h", libcpp + "/vector"})); + std::string libcpp = "/usr/include/c++/v1"; + std::vector files = {// C library + usr + "/stdio.h", + // C++ library + libcpp + "/vector", + libcpp + "/module.modulemap"}; + CppModuleConfiguration config(makeFiles(files)); EXPECT_THAT(config.GetImportedModules(), testing::ElementsAre("std")); EXPECT_THAT(config.GetIncludeDirs(), testing::ElementsAre(libcpp, ResourceInc(), usr)); @@ -52,10 +77,15 @@ TEST_F(CppModuleConfigurationTest, Linux) { TEST_F(CppModuleConfigurationTest, Sysroot) { // Test that having a sysroot for the whole system works fine. + std::string libcpp = "/home/user/sysroot/usr/include/c++/v1"; std::string usr = "/home/user/sysroot/usr/include"; - CppModuleConfiguration config( - makeFiles({usr + "/bits/types.h", libcpp + "/vector"})); + std::vector files = {// C library + usr + "/stdio.h", + // C++ library + libcpp + "/vector", + libcpp + "/module.modulemap"}; + CppModuleConfiguration config(makeFiles(files)); EXPECT_THAT(config.GetImportedModules(), testing::ElementsAre("std")); EXPECT_THAT(config.GetIncludeDirs(), testing::ElementsAre(libcpp, ResourceInc(), usr)); @@ -63,10 +93,15 @@ TEST_F(CppModuleConfigurationTest, Sysroot) { TEST_F(CppModuleConfigurationTest, LinuxLocalLibCpp) { // Test that a locally build libc++ is detected. - std::string libcpp = "/home/user/llvm-build/include/c++/v1"; + std::string usr = "/usr/include"; - CppModuleConfiguration config( - makeFiles({usr + "/bits/types.h", libcpp + "/vector"})); + std::string libcpp = "/home/user/llvm-build/include/c++/v1"; + std::vector files = {// C library + usr + "/stdio.h", + // C++ library + libcpp + "/vector", + libcpp + "/module.modulemap"}; + CppModuleConfiguration config(makeFiles(files)); EXPECT_THAT(config.GetImportedModules(), testing::ElementsAre("std")); EXPECT_THAT(config.GetIncludeDirs(), testing::ElementsAre(libcpp, ResourceInc(), usr)); @@ -74,10 +109,17 @@ TEST_F(CppModuleConfigurationTest, LinuxLocalLibCpp) { TEST_F(CppModuleConfigurationTest, UnrelatedLibrary) { // Test that having an unrelated library in /usr/include doesn't break. - std::string libcpp = "/home/user/llvm-build/include/c++/v1"; + std::string usr = "/usr/include"; - CppModuleConfiguration config(makeFiles( - {usr + "/bits/types.h", libcpp + "/vector", usr + "/boost/vector"})); + std::string libcpp = "/home/user/llvm-build/include/c++/v1"; + std::vector files = {// C library + usr + "/stdio.h", + // unrelated library + usr + "/boost/vector", + // C++ library + libcpp + "/vector", + libcpp + "/module.modulemap"}; + CppModuleConfiguration config(makeFiles(files)); EXPECT_THAT(config.GetImportedModules(), testing::ElementsAre("std")); EXPECT_THAT(config.GetIncludeDirs(), testing::ElementsAre(libcpp, ResourceInc(), usr)); @@ -85,12 +127,19 @@ TEST_F(CppModuleConfigurationTest, UnrelatedLibrary) { TEST_F(CppModuleConfigurationTest, Xcode) { // Test detection of libc++ coming from Xcode with generic platform names. + std::string p = "/Applications/Xcode.app/Contents/Developer/"; std::string libcpp = p + "Toolchains/B.xctoolchain/usr/include/c++/v1"; std::string usr = p + "Platforms/A.platform/Developer/SDKs/OSVers.sdk/usr/include"; - CppModuleConfiguration config( - makeFiles({libcpp + "/unordered_map", usr + "/stdio.h"})); + std::vector files = { + // C library + usr + "/stdio.h", + // C++ library + libcpp + "/vector", + libcpp + "/module.modulemap", + }; + CppModuleConfiguration config(makeFiles(files)); EXPECT_THAT(config.GetImportedModules(), testing::ElementsAre("std")); EXPECT_THAT(config.GetIncludeDirs(), testing::ElementsAre(libcpp, ResourceInc(), usr)); @@ -98,8 +147,14 @@ TEST_F(CppModuleConfigurationTest, Xcode) { TEST_F(CppModuleConfigurationTest, LibCppV2) { // Test that a "v2" of libc++ is still correctly detected. - CppModuleConfiguration config( - makeFiles({"/usr/include/bits/types.h", "/usr/include/c++/v2/vector"})); + + std::string libcpp = "/usr/include/c++/v2"; + std::vector files = {// C library + "/usr/include/stdio.h", + // C++ library + libcpp + "/vector", + libcpp + "/module.modulemap"}; + CppModuleConfiguration config(makeFiles(files)); EXPECT_THAT(config.GetImportedModules(), testing::ElementsAre("std")); EXPECT_THAT(config.GetIncludeDirs(), testing::ElementsAre("/usr/include/c++/v2", ResourceInc(), @@ -109,8 +164,15 @@ TEST_F(CppModuleConfigurationTest, LibCppV2) { TEST_F(CppModuleConfigurationTest, UnknownLibCppFile) { // Test that having some unknown file in the libc++ path doesn't break // anything. - CppModuleConfiguration config(makeFiles( - {"/usr/include/bits/types.h", "/usr/include/c++/v1/non_existing_file"})); + + std::string libcpp = "/usr/include/c++/v1"; + std::vector files = {// C library + "/usr/include/stdio.h", + // C++ library + libcpp + "/non_existing_file", + libcpp + "/module.modulemap", + libcpp + "/vector"}; + CppModuleConfiguration config(makeFiles(files)); EXPECT_THAT(config.GetImportedModules(), testing::ElementsAre("std")); EXPECT_THAT(config.GetIncludeDirs(), testing::ElementsAre("/usr/include/c++/v1", ResourceInc(), @@ -119,22 +181,40 @@ TEST_F(CppModuleConfigurationTest, UnknownLibCppFile) { TEST_F(CppModuleConfigurationTest, MissingUsrInclude) { // Test that we don't load 'std' if we can't find the C standard library. - CppModuleConfiguration config(makeFiles({"/usr/include/c++/v1/vector"})); + + std::string libcpp = "/usr/include/c++/v1"; + std::vector files = {// C++ library + libcpp + "/vector", + libcpp + "/module.modulemap"}; + CppModuleConfiguration config(makeFiles(files)); EXPECT_THAT(config.GetImportedModules(), testing::ElementsAre()); EXPECT_THAT(config.GetIncludeDirs(), testing::ElementsAre()); } TEST_F(CppModuleConfigurationTest, MissingLibCpp) { // Test that we don't load 'std' if we don't have a libc++. - CppModuleConfiguration config(makeFiles({"/usr/include/bits/types.h"})); + + std::string usr = "/usr/include"; + std::vector files = { + // C library + usr + "/stdio.h", + }; + CppModuleConfiguration config(makeFiles(files)); EXPECT_THAT(config.GetImportedModules(), testing::ElementsAre()); EXPECT_THAT(config.GetIncludeDirs(), testing::ElementsAre()); } TEST_F(CppModuleConfigurationTest, IgnoreLibStdCpp) { // Test that we don't do anything bad when we encounter libstdc++ paths. - CppModuleConfiguration config(makeFiles( - {"/usr/include/bits/types.h", "/usr/include/c++/8.0.1/vector"})); + + std::string usr = "/usr/include"; + std::vector files = { + // C library + usr + "/stdio.h", + // C++ library + usr + "/c++/8.0.1/vector", + }; + CppModuleConfiguration config(makeFiles(files)); EXPECT_THAT(config.GetImportedModules(), testing::ElementsAre()); EXPECT_THAT(config.GetIncludeDirs(), testing::ElementsAre()); } @@ -142,9 +222,20 @@ TEST_F(CppModuleConfigurationTest, IgnoreLibStdCpp) { TEST_F(CppModuleConfigurationTest, AmbiguousCLib) { // Test that we don't do anything when we are not sure where the // right C standard library is. - CppModuleConfiguration config( - makeFiles({"/usr/include/bits/types.h", "/usr/include/c++/v1/vector", - "/sysroot/usr/include/bits/types.h"})); + + std::string usr1 = "/usr/include"; + std::string usr2 = "/usr/include/other/path"; + std::string libcpp = usr1 + "c++/v1"; + std::vector files = { + // First C library + usr1 + "/stdio.h", + // Second C library + usr2 + "/stdio.h", + // C++ library + libcpp + "/vector", + libcpp + "/module.modulemap", + }; + CppModuleConfiguration config(makeFiles(files)); EXPECT_THAT(config.GetImportedModules(), testing::ElementsAre()); EXPECT_THAT(config.GetIncludeDirs(), testing::ElementsAre()); } @@ -152,9 +243,21 @@ TEST_F(CppModuleConfigurationTest, AmbiguousCLib) { TEST_F(CppModuleConfigurationTest, AmbiguousLibCpp) { // Test that we don't do anything when we are not sure where the // right libc++ is. - CppModuleConfiguration config( - makeFiles({"/usr/include/bits/types.h", "/usr/include/c++/v1/vector", - "/usr/include/c++/v2/vector"})); + + std::string usr = "/usr/include"; + std::string libcpp1 = usr + "c++/v1"; + std::string libcpp2 = usr + "c++/v2"; + std::vector files = { + // C library + usr + "/stdio.h", + // First C++ library + libcpp1 + "/vector", + libcpp1 + "/module.modulemap", + // Second C++ library + libcpp2 + "/vector", + libcpp2 + "/module.modulemap", + }; + CppModuleConfiguration config(makeFiles(files)); EXPECT_THAT(config.GetImportedModules(), testing::ElementsAre()); EXPECT_THAT(config.GetIncludeDirs(), testing::ElementsAre()); } diff --git a/gnu/llvm/lldb/unittests/Expression/DWARFExpressionTest.cpp b/gnu/llvm/lldb/unittests/Expression/DWARFExpressionTest.cpp index 78c400c33d4..92101e913c2 100644 --- a/gnu/llvm/lldb/unittests/Expression/DWARFExpressionTest.cpp +++ b/gnu/llvm/lldb/unittests/Expression/DWARFExpressionTest.cpp @@ -7,11 +7,15 @@ //===----------------------------------------------------------------------===// #include "lldb/Expression/DWARFExpression.h" +#include "Plugins/Platform/Linux/PlatformLinux.h" #include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "TestingSupport/Symbol/YAMLModuleTester.h" #include "lldb/Core/Value.h" +#include "lldb/Core/Debugger.h" #include "lldb/Core/dwarf.h" +#include "lldb/Host/HostInfo.h" #include "lldb/Symbol/ObjectFile.h" +#include "lldb/Utility/Reproducer.h" #include "lldb/Utility/StreamString.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Testing/Support/Error.h" @@ -21,22 +25,25 @@ using namespace lldb_private; static llvm::Expected Evaluate(llvm::ArrayRef expr, lldb::ModuleSP module_sp = {}, - DWARFUnit *unit = nullptr) { + DWARFUnit *unit = nullptr, + ExecutionContext *exe_ctx = nullptr) { DataExtractor extractor(expr.data(), expr.size(), lldb::eByteOrderLittle, /*addr_size*/ 4); Value result; Status status; - if (!DWARFExpression::Evaluate( - /*exe_ctx*/ nullptr, /*reg_ctx*/ nullptr, module_sp, extractor, unit, - lldb::eRegisterKindLLDB, - /*initial_value_ptr*/ nullptr, - /*object_address_ptr*/ nullptr, result, &status)) + if (!DWARFExpression::Evaluate(exe_ctx, /*reg_ctx*/ nullptr, module_sp, + extractor, unit, lldb::eRegisterKindLLDB, + /*initial_value_ptr*/ nullptr, + /*object_address_ptr*/ nullptr, result, + &status)) return status.ToError(); switch (result.GetValueType()) { - case Value::eValueTypeScalar: + case Value::ValueType::Scalar: return result.GetScalar(); - case Value::eValueTypeHostAddress: { + case Value::ValueType::LoadAddress: + return LLDB_INVALID_ADDRESS; + case Value::ValueType::HostAddress: { // Convert small buffers to scalars to simplify the tests. DataBufferHeap &buf = result.GetBuffer(); if (buf.GetByteSize() <= 8) { @@ -55,7 +62,7 @@ class DWARFExpressionTester : public YAMLModuleTester { public: using YAMLModuleTester::YAMLModuleTester; llvm::Expected Eval(llvm::ArrayRef expr) { - return ::Evaluate(expr, m_module_sp, m_dwarf_unit.get()); + return ::Evaluate(expr, m_module_sp, m_dwarf_unit); } }; @@ -66,6 +73,23 @@ static Scalar GetScalar(unsigned bits, uint64_t value, bool sign) { return scalar; } +/// This is needed for the tests that use a mock process. +class DWARFExpressionMockProcessTest : public ::testing::Test { +public: + void SetUp() override { + llvm::cantFail(repro::Reproducer::Initialize(repro::ReproducerMode::Off, {})); + FileSystem::Initialize(); + HostInfo::Initialize(); + platform_linux::PlatformLinux::Initialize(); + } + void TearDown() override { + platform_linux::PlatformLinux::Terminate(); + HostInfo::Terminate(); + FileSystem::Terminate(); + repro::Reproducer::Terminate(); + } +}; + TEST(DWARFExpression, DW_OP_pick) { EXPECT_THAT_EXPECTED(Evaluate({DW_OP_lit1, DW_OP_lit0, DW_OP_pick, 0}), llvm::HasValue(0)); @@ -75,73 +99,109 @@ TEST(DWARFExpression, DW_OP_pick) { llvm::Failed()); } +TEST(DWARFExpression, DW_OP_const) { + // Extend to address size. + EXPECT_THAT_EXPECTED(Evaluate({DW_OP_const1u, 0x88}), llvm::HasValue(0x88)); + EXPECT_THAT_EXPECTED(Evaluate({DW_OP_const1s, 0x88}), + llvm::HasValue(0xffffff88)); + EXPECT_THAT_EXPECTED(Evaluate({DW_OP_const2u, 0x47, 0x88}), + llvm::HasValue(0x8847)); + EXPECT_THAT_EXPECTED(Evaluate({DW_OP_const2s, 0x47, 0x88}), + llvm::HasValue(0xffff8847)); + EXPECT_THAT_EXPECTED(Evaluate({DW_OP_const4u, 0x44, 0x42, 0x47, 0x88}), + llvm::HasValue(0x88474244)); + EXPECT_THAT_EXPECTED(Evaluate({DW_OP_const4s, 0x44, 0x42, 0x47, 0x88}), + llvm::HasValue(0x88474244)); + + // Truncate to address size. + EXPECT_THAT_EXPECTED( + Evaluate({DW_OP_const8u, 0x00, 0x11, 0x22, 0x33, 0x44, 0x42, 0x47, 0x88}), + llvm::HasValue(0x33221100)); + EXPECT_THAT_EXPECTED( + Evaluate({DW_OP_const8s, 0x00, 0x11, 0x22, 0x33, 0x44, 0x42, 0x47, 0x88}), + llvm::HasValue(0x33221100)); + + // Don't truncate to address size for compatibility with clang (pr48087). + EXPECT_THAT_EXPECTED( + Evaluate({DW_OP_constu, 0x81, 0x82, 0x84, 0x88, 0x90, 0xa0, 0x40}), + llvm::HasValue(0x01010101010101)); + EXPECT_THAT_EXPECTED( + Evaluate({DW_OP_consts, 0x81, 0x82, 0x84, 0x88, 0x90, 0xa0, 0x40}), + llvm::HasValue(0xffff010101010101)); +} + TEST(DWARFExpression, DW_OP_convert) { /// Auxiliary debug info. - const char *yamldata = - "debug_abbrev:\n" - " - Code: 0x00000001\n" - " Tag: DW_TAG_compile_unit\n" - " Children: DW_CHILDREN_yes\n" - " Attributes:\n" - " - Attribute: DW_AT_language\n" - " Form: DW_FORM_data2\n" - " - Code: 0x00000002\n" - " Tag: DW_TAG_base_type\n" - " Children: DW_CHILDREN_no\n" - " Attributes:\n" - " - Attribute: DW_AT_encoding\n" - " Form: DW_FORM_data1\n" - " - Attribute: DW_AT_byte_size\n" - " Form: DW_FORM_data1\n" - "debug_info:\n" - " - Length: 0\n" - " Version: 4\n" - " AbbrOffset: 0\n" - " AddrSize: 8\n" - " Entries:\n" - " - AbbrCode: 0x00000001\n" - " Values:\n" - " - Value: 0x000000000000000C\n" - // 0x0000000e: - " - AbbrCode: 0x00000002\n" - " Values:\n" - " - Value: 0x0000000000000007\n" // DW_ATE_unsigned - " - Value: 0x0000000000000004\n" - // 0x00000011: - " - AbbrCode: 0x00000002\n" - " Values:\n" - " - Value: 0x0000000000000007\n" // DW_ATE_unsigned - " - Value: 0x0000000000000008\n" - // 0x00000014: - " - AbbrCode: 0x00000002\n" - " Values:\n" - " - Value: 0x0000000000000005\n" // DW_ATE_signed - " - Value: 0x0000000000000008\n" - // 0x00000017: - " - AbbrCode: 0x00000002\n" - " Values:\n" - " - Value: 0x0000000000000008\n" // DW_ATE_unsigned_char - " - Value: 0x0000000000000001\n" - // 0x0000001a: - " - AbbrCode: 0x00000002\n" - " Values:\n" - " - Value: 0x0000000000000006\n" // DW_ATE_signed_char - " - Value: 0x0000000000000001\n" - // 0x0000001d: - " - AbbrCode: 0x00000002\n" - " Values:\n" - " - Value: 0x000000000000000b\n" // DW_ATE_numeric_string - " - Value: 0x0000000000000001\n" - "" - " - AbbrCode: 0x00000000\n" - " Values: []\n"; + const char *yamldata = R"( +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_386 +DWARF: + debug_abbrev: + - Table: + - Code: 0x00000001 + Tag: DW_TAG_compile_unit + Children: DW_CHILDREN_yes + Attributes: + - Attribute: DW_AT_language + Form: DW_FORM_data2 + - Code: 0x00000002 + Tag: DW_TAG_base_type + Children: DW_CHILDREN_no + Attributes: + - Attribute: DW_AT_encoding + Form: DW_FORM_data1 + - Attribute: DW_AT_byte_size + Form: DW_FORM_data1 + debug_info: + - Version: 4 + AddrSize: 8 + Entries: + - AbbrCode: 0x00000001 + Values: + - Value: 0x000000000000000C + # 0x0000000e: + - AbbrCode: 0x00000002 + Values: + - Value: 0x0000000000000007 # DW_ATE_unsigned + - Value: 0x0000000000000004 + # 0x00000011: + - AbbrCode: 0x00000002 + Values: + - Value: 0x0000000000000007 # DW_ATE_unsigned + - Value: 0x0000000000000008 + # 0x00000014: + - AbbrCode: 0x00000002 + Values: + - Value: 0x0000000000000005 # DW_ATE_signed + - Value: 0x0000000000000008 + # 0x00000017: + - AbbrCode: 0x00000002 + Values: + - Value: 0x0000000000000008 # DW_ATE_unsigned_char + - Value: 0x0000000000000001 + # 0x0000001a: + - AbbrCode: 0x00000002 + Values: + - Value: 0x0000000000000006 # DW_ATE_signed_char + - Value: 0x0000000000000001 + # 0x0000001d: + - AbbrCode: 0x00000002 + Values: + - Value: 0x000000000000000b # DW_ATE_numeric_string + - Value: 0x0000000000000001 + - AbbrCode: 0x00000000 +)"; uint8_t offs_uint32_t = 0x0000000e; uint8_t offs_uint64_t = 0x00000011; uint8_t offs_sint64_t = 0x00000014; uint8_t offs_uchar = 0x00000017; uint8_t offs_schar = 0x0000001a; - DWARFExpressionTester t(yamldata, "i386-unknown-linux"); + DWARFExpressionTester t(yamldata); ASSERT_TRUE((bool)t.GetDwarfUnit()); // Constant is given as little-endian. @@ -152,38 +212,46 @@ TEST(DWARFExpression, DW_OP_convert) { // Positive tests. // - // Truncate to default unspecified (pointer-sized) type. + // Leave as is. EXPECT_THAT_EXPECTED( - t.Eval({DW_OP_const8u, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, // - DW_OP_convert, 0x00}), - llvm::HasValue(GetScalar(32, 0x44332211, not_signed))); - // Truncate to 32 bits. - EXPECT_THAT_EXPECTED(t.Eval({DW_OP_const8u, // - 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,// - DW_OP_convert, offs_uint32_t}), - llvm::HasValue(GetScalar(32, 0x44332211, not_signed))); + t.Eval({DW_OP_const4u, 0x11, 0x22, 0x33, 0x44, // + DW_OP_convert, offs_uint32_t, DW_OP_stack_value}), + llvm::HasValue(GetScalar(64, 0x44332211, not_signed))); - // Leave as is. + // Zero-extend to 64 bits. EXPECT_THAT_EXPECTED( - t.Eval({DW_OP_const8u, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, // - DW_OP_convert, offs_uint64_t}), - llvm::HasValue(GetScalar(64, 0x8877665544332211, not_signed))); + t.Eval({DW_OP_const4u, 0x11, 0x22, 0x33, 0x44, // + DW_OP_convert, offs_uint64_t, DW_OP_stack_value}), + llvm::HasValue(GetScalar(64, 0x44332211, not_signed))); // Sign-extend to 64 bits. EXPECT_THAT_EXPECTED( t.Eval({DW_OP_const4s, 0xcc, 0xdd, 0xee, 0xff, // - DW_OP_convert, offs_sint64_t}), + DW_OP_convert, offs_sint64_t, DW_OP_stack_value}), llvm::HasValue(GetScalar(64, 0xffffffffffeeddcc, is_signed))); - // Truncate to 8 bits. + // Sign-extend, then truncate. EXPECT_THAT_EXPECTED( - t.Eval({DW_OP_const4s, 'A', 'B', 'C', 'D', DW_OP_convert, offs_uchar}), - llvm::HasValue(GetScalar(8, 'A', not_signed))); + t.Eval({DW_OP_const4s, 0xcc, 0xdd, 0xee, 0xff, // + DW_OP_convert, offs_sint64_t, // + DW_OP_convert, offs_uint32_t, DW_OP_stack_value}), + llvm::HasValue(GetScalar(32, 0xffeeddcc, not_signed))); + + // Truncate to default unspecified (pointer-sized) type. + EXPECT_THAT_EXPECTED(t.Eval({DW_OP_const4s, 0xcc, 0xdd, 0xee, 0xff, // + DW_OP_convert, offs_sint64_t, // + DW_OP_convert, 0x00, DW_OP_stack_value}), + llvm::HasValue(GetScalar(32, 0xffeeddcc, not_signed))); + + // Truncate to 8 bits. + EXPECT_THAT_EXPECTED(t.Eval({DW_OP_const4s, 'A', 'B', 'C', 'D', DW_OP_convert, + offs_uchar, DW_OP_stack_value}), + llvm::HasValue(GetScalar(8, 'A', not_signed))); // Also truncate to 8 bits. - EXPECT_THAT_EXPECTED( - t.Eval({DW_OP_const4s, 'A', 'B', 'C', 'D', DW_OP_convert, offs_schar}), - llvm::HasValue(GetScalar(8, 'A', is_signed))); + EXPECT_THAT_EXPECTED(t.Eval({DW_OP_const4s, 'A', 'B', 'C', 'D', DW_OP_convert, + offs_schar, DW_OP_stack_value}), + llvm::HasValue(GetScalar(8, 'A', is_signed))); // // Errors. @@ -191,7 +259,7 @@ TEST(DWARFExpression, DW_OP_convert) { // No Module. EXPECT_THAT_ERROR(Evaluate({DW_OP_const1s, 'X', DW_OP_convert, 0x00}, nullptr, - t.GetDwarfUnit().get()) + t.GetDwarfUnit()) .takeError(), llvm::Failed()); @@ -221,9 +289,81 @@ TEST(DWARFExpression, DW_OP_piece) { llvm::HasValue(GetScalar(16, 0xff00, true))); } +TEST(DWARFExpression, DW_OP_implicit_value) { + unsigned char bytes = 4; + + EXPECT_THAT_EXPECTED( + Evaluate({DW_OP_implicit_value, bytes, 0x11, 0x22, 0x33, 0x44}), + llvm::HasValue(GetScalar(8 * bytes, 0x44332211, true))); +} + TEST(DWARFExpression, DW_OP_unknown) { EXPECT_THAT_EXPECTED( Evaluate({0xff}), llvm::FailedWithMessage( "Unhandled opcode DW_OP_unknown_ff in DWARFExpression")); } + +TEST_F(DWARFExpressionMockProcessTest, DW_OP_deref) { + EXPECT_THAT_EXPECTED(Evaluate({DW_OP_lit0, DW_OP_deref}), llvm::Failed()); + + struct MockProcess : Process { + using Process::Process; + ConstString GetPluginName() override { return ConstString("mock process"); } + uint32_t GetPluginVersion() override { return 0; } + bool CanDebug(lldb::TargetSP target, + bool plugin_specified_by_name) override { + return false; + }; + Status DoDestroy() override { return {}; } + void RefreshStateAfterStop() override {} + bool DoUpdateThreadList(ThreadList &old_thread_list, + ThreadList &new_thread_list) override { + return false; + }; + size_t DoReadMemory(lldb::addr_t vm_addr, void *buf, size_t size, + Status &error) override { + for (size_t i = 0; i < size; ++i) + ((char *)buf)[i] = (vm_addr + i) & 0xff; + error.Clear(); + return size; + } + }; + + // Set up a mock process. + ArchSpec arch("i386-pc-linux"); + Platform::SetHostPlatform( + platform_linux::PlatformLinux::CreateInstance(true, &arch)); + lldb::DebuggerSP debugger_sp = Debugger::CreateInstance(); + ASSERT_TRUE(debugger_sp); + lldb::TargetSP target_sp; + lldb::PlatformSP platform_sp; + debugger_sp->GetTargetList().CreateTarget( + *debugger_sp, "", arch, eLoadDependentsNo, platform_sp, target_sp); + ASSERT_TRUE(target_sp); + ASSERT_TRUE(target_sp->GetArchitecture().IsValid()); + ASSERT_TRUE(platform_sp); + lldb::ListenerSP listener_sp(Listener::MakeListener("dummy")); + lldb::ProcessSP process_sp = + std::make_shared(target_sp, listener_sp); + ASSERT_TRUE(process_sp); + + ExecutionContext exe_ctx(process_sp); + // Implicit location: *0x4. + EXPECT_THAT_EXPECTED(Evaluate({DW_OP_lit4, DW_OP_deref, DW_OP_stack_value}, + {}, {}, &exe_ctx), + llvm::HasValue(GetScalar(32, 0x07060504, false))); + // Memory location: *(*0x4). + // Evaluate returns LLDB_INVALID_ADDRESS for all load addresses. + EXPECT_THAT_EXPECTED(Evaluate({DW_OP_lit4, DW_OP_deref}, {}, {}, &exe_ctx), + llvm::HasValue(Scalar(LLDB_INVALID_ADDRESS))); + // Memory location: *0x4. + // Evaluate returns LLDB_INVALID_ADDRESS for all load addresses. + EXPECT_THAT_EXPECTED(Evaluate({DW_OP_lit4}, {}, {}, &exe_ctx), + llvm::HasValue(Scalar(4))); + // Implicit location: *0x4. + // Evaluate returns LLDB_INVALID_ADDRESS for all load addresses. + EXPECT_THAT_EXPECTED( + Evaluate({DW_OP_lit4, DW_OP_deref, DW_OP_stack_value}, {}, {}, &exe_ctx), + llvm::HasValue(GetScalar(32, 0x07060504, false))); +} diff --git a/gnu/llvm/lldb/unittests/Host/CMakeLists.txt b/gnu/llvm/lldb/unittests/Host/CMakeLists.txt index 663645c986f..1cc0cb081e4 100644 --- a/gnu/llvm/lldb/unittests/Host/CMakeLists.txt +++ b/gnu/llvm/lldb/unittests/Host/CMakeLists.txt @@ -7,6 +7,7 @@ set (FILES HostTest.cpp MainLoopTest.cpp NativeProcessProtocolTest.cpp + PipeTest.cpp ProcessLaunchInfoTest.cpp SocketAddressTest.cpp SocketTest.cpp diff --git a/gnu/llvm/lldb/unittests/Host/HostInfoTest.cpp b/gnu/llvm/lldb/unittests/Host/HostInfoTest.cpp index 96d47d75794..0accdd8dbcd 100644 --- a/gnu/llvm/lldb/unittests/Host/HostInfoTest.cpp +++ b/gnu/llvm/lldb/unittests/Host/HostInfoTest.cpp @@ -60,3 +60,16 @@ TEST_F(HostInfoTest, GetXcodeSDK) { EXPECT_TRUE(HostInfo::GetXcodeSDKPath(XcodeSDK("CeciNestPasUnOS.sdk")).empty()); } #endif + +TEST(HostInfoTestInitialization, InitTwice) { + llvm::VersionTuple Version; + { + SubsystemRAII subsystems; + Version = HostInfo::GetOSVersion(); + } + + { + SubsystemRAII subsystems; + EXPECT_EQ(Version, HostInfo::GetOSVersion()); + } +} diff --git a/gnu/llvm/lldb/unittests/Host/MainLoopTest.cpp b/gnu/llvm/lldb/unittests/Host/MainLoopTest.cpp index 9c9b6ae196c..890f6eb6619 100644 --- a/gnu/llvm/lldb/unittests/Host/MainLoopTest.cpp +++ b/gnu/llvm/lldb/unittests/Host/MainLoopTest.cpp @@ -102,8 +102,8 @@ TEST_F(MainLoopTest, TerminatesImmediately) { TEST_F(MainLoopTest, DetectsEOF) { PseudoTerminal term; - ASSERT_TRUE(term.OpenFirstAvailablePrimary(O_RDWR, nullptr, 0)); - ASSERT_TRUE(term.OpenSecondary(O_RDWR | O_NOCTTY, nullptr, 0)); + ASSERT_THAT_ERROR(term.OpenFirstAvailablePrimary(O_RDWR), llvm::Succeeded()); + ASSERT_THAT_ERROR(term.OpenSecondary(O_RDWR | O_NOCTTY), llvm::Succeeded()); auto conn = std::make_unique( term.ReleasePrimaryFileDescriptor(), true); @@ -152,4 +152,49 @@ TEST_F(MainLoopTest, UnmonitoredSignal) { killer.join(); ASSERT_EQ(1u, callback_count); } + +// Test that two callbacks can be registered for the same signal +// and unregistered independently. +TEST_F(MainLoopTest, TwoSignalCallbacks) { + MainLoop loop; + Status error; + unsigned callback2_count = 0; + unsigned callback3_count = 0; + + auto handle = loop.RegisterSignal(SIGUSR1, make_callback(), error); + ASSERT_TRUE(error.Success()); + + { + // Run a single iteration with two callbacks enabled. + auto handle2 = loop.RegisterSignal( + SIGUSR1, [&](MainLoopBase &loop) { ++callback2_count; }, error); + ASSERT_TRUE(error.Success()); + + kill(getpid(), SIGUSR1); + ASSERT_TRUE(loop.Run().Success()); + ASSERT_EQ(1u, callback_count); + ASSERT_EQ(1u, callback2_count); + ASSERT_EQ(0u, callback3_count); + } + + { + // Make sure that remove + add new works. + auto handle3 = loop.RegisterSignal( + SIGUSR1, [&](MainLoopBase &loop) { ++callback3_count; }, error); + ASSERT_TRUE(error.Success()); + + kill(getpid(), SIGUSR1); + ASSERT_TRUE(loop.Run().Success()); + ASSERT_EQ(2u, callback_count); + ASSERT_EQ(1u, callback2_count); + ASSERT_EQ(1u, callback3_count); + } + + // Both extra callbacks should be unregistered now. + kill(getpid(), SIGUSR1); + ASSERT_TRUE(loop.Run().Success()); + ASSERT_EQ(3u, callback_count); + ASSERT_EQ(1u, callback2_count); + ASSERT_EQ(1u, callback3_count); +} #endif diff --git a/gnu/llvm/lldb/unittests/Host/PipeTest.cpp b/gnu/llvm/lldb/unittests/Host/PipeTest.cpp new file mode 100644 index 00000000000..35a44ccf037 --- /dev/null +++ b/gnu/llvm/lldb/unittests/Host/PipeTest.cpp @@ -0,0 +1,51 @@ +//===-- PipeTest.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 "lldb/Host/Pipe.h" +#include "TestingSupport/SubsystemRAII.h" +#include "lldb/Host/FileSystem.h" +#include "lldb/Host/HostInfo.h" +#include "gtest/gtest.h" + +using namespace lldb_private; + +class PipeTest : public testing::Test { +public: + SubsystemRAII subsystems; +}; + +TEST_F(PipeTest, CreateWithUniqueName) { + Pipe pipe; + llvm::SmallString<0> name; + ASSERT_THAT_ERROR(pipe.CreateWithUniqueName("PipeTest-CreateWithUniqueName", + /*child_process_inherit=*/false, + name) + .ToError(), + llvm::Succeeded()); +} + +// Test broken +#ifndef _WIN32 +TEST_F(PipeTest, OpenAsReader) { + Pipe pipe; + llvm::SmallString<0> name; + ASSERT_THAT_ERROR(pipe.CreateWithUniqueName("PipeTest-OpenAsReader", + /*child_process_inherit=*/false, + name) + .ToError(), + llvm::Succeeded()); + + // Ensure name is not null-terminated + size_t name_len = name.size(); + name += "foobar"; + llvm::StringRef name_ref(name.data(), name_len); + ASSERT_THAT_ERROR( + pipe.OpenAsReader(name_ref, /*child_process_inherit=*/false).ToError(), + llvm::Succeeded()); +} +#endif diff --git a/gnu/llvm/lldb/unittests/Host/SocketTest.cpp b/gnu/llvm/lldb/unittests/Host/SocketTest.cpp index c53d2660f0c..27d42f83571 100644 --- a/gnu/llvm/lldb/unittests/Host/SocketTest.cpp +++ b/gnu/llvm/lldb/unittests/Host/SocketTest.cpp @@ -14,12 +14,24 @@ using namespace lldb_private; -class SocketTest : public testing::Test { +struct SocketTestParams { + bool is_ipv6; + std::string localhost_ip; +}; + +class SocketTest : public testing::TestWithParam { public: SubsystemRAII subsystems; + +protected: + bool HostSupportsProtocol() const { + if (GetParam().is_ipv6) + return HostSupportsIPv6(); + return HostSupportsIPv4(); + } }; -TEST_F(SocketTest, DecodeHostAndPort) { +TEST_P(SocketTest, DecodeHostAndPort) { std::string host_str; std::string port_str; int32_t port; @@ -86,7 +98,7 @@ TEST_F(SocketTest, DecodeHostAndPort) { } #if LLDB_ENABLE_POSIX -TEST_F(SocketTest, DomainListenConnectAccept) { +TEST_P(SocketTest, DomainListenConnectAccept) { llvm::SmallString<64> Path; std::error_code EC = llvm::sys::fs::createUniqueDirectory("DomainListenConnectAccept", Path); ASSERT_FALSE(EC); @@ -102,18 +114,22 @@ TEST_F(SocketTest, DomainListenConnectAccept) { } #endif -TEST_F(SocketTest, TCPListen0ConnectAccept) { +TEST_P(SocketTest, TCPListen0ConnectAccept) { + if (!HostSupportsProtocol()) + return; std::unique_ptr socket_a_up; std::unique_ptr socket_b_up; - CreateTCPConnectedSockets("127.0.0.1", &socket_a_up, &socket_b_up); + CreateTCPConnectedSockets(GetParam().localhost_ip, &socket_a_up, + &socket_b_up); } -TEST_F(SocketTest, TCPGetAddress) { +TEST_P(SocketTest, TCPGetAddress) { std::unique_ptr socket_a_up; std::unique_ptr socket_b_up; - if (!HostSupportsIPv4()) + if (!HostSupportsProtocol()) return; - CreateTCPConnectedSockets("127.0.0.1", &socket_a_up, &socket_b_up); + CreateTCPConnectedSockets(GetParam().localhost_ip, &socket_a_up, + &socket_b_up); EXPECT_EQ(socket_a_up->GetLocalPortNumber(), socket_b_up->GetRemotePortNumber()); @@ -121,11 +137,16 @@ TEST_F(SocketTest, TCPGetAddress) { socket_a_up->GetRemotePortNumber()); EXPECT_NE(socket_a_up->GetLocalPortNumber(), socket_b_up->GetLocalPortNumber()); - EXPECT_STREQ("127.0.0.1", socket_a_up->GetRemoteIPAddress().c_str()); - EXPECT_STREQ("127.0.0.1", socket_b_up->GetRemoteIPAddress().c_str()); + EXPECT_STREQ(GetParam().localhost_ip.c_str(), + socket_a_up->GetRemoteIPAddress().c_str()); + EXPECT_STREQ(GetParam().localhost_ip.c_str(), + socket_b_up->GetRemoteIPAddress().c_str()); } -TEST_F(SocketTest, UDPConnect) { +TEST_P(SocketTest, UDPConnect) { + // UDPSocket::Connect() creates sockets with AF_INET (IPv4). + if (!HostSupportsIPv4()) + return; llvm::Expected> socket = UDPSocket::Connect("127.0.0.1:0", /*child_processes_inherit=*/false); @@ -133,7 +154,9 @@ TEST_F(SocketTest, UDPConnect) { EXPECT_TRUE(socket.get()->IsValid()); } -TEST_F(SocketTest, TCPListen0GetPort) { +TEST_P(SocketTest, TCPListen0GetPort) { + if (!HostSupportsIPv4()) + return; Predicate port_predicate; port_predicate.SetValue(0, eBroadcastNever); llvm::Expected> sock = @@ -143,12 +166,13 @@ TEST_F(SocketTest, TCPListen0GetPort) { EXPECT_NE(sock.get()->GetLocalPortNumber(), 0); } -TEST_F(SocketTest, TCPGetConnectURI) { +TEST_P(SocketTest, TCPGetConnectURI) { std::unique_ptr socket_a_up; std::unique_ptr socket_b_up; - if (!HostSupportsIPv4()) + if (!HostSupportsProtocol()) return; - CreateTCPConnectedSockets("127.0.0.1", &socket_a_up, &socket_b_up); + CreateTCPConnectedSockets(GetParam().localhost_ip, &socket_a_up, + &socket_b_up); llvm::StringRef scheme; llvm::StringRef hostname; @@ -160,7 +184,8 @@ TEST_F(SocketTest, TCPGetConnectURI) { EXPECT_EQ(port, socket_a_up->GetRemotePortNumber()); } -TEST_F(SocketTest, UDPGetConnectURI) { +TEST_P(SocketTest, UDPGetConnectURI) { + // UDPSocket::Connect() creates sockets with AF_INET (IPv4). if (!HostSupportsIPv4()) return; llvm::Expected> socket = @@ -177,7 +202,7 @@ TEST_F(SocketTest, UDPGetConnectURI) { } #if LLDB_ENABLE_POSIX -TEST_F(SocketTest, DomainGetConnectURI) { +TEST_P(SocketTest, DomainGetConnectURI) { llvm::SmallString<64> domain_path; std::error_code EC = llvm::sys::fs::createUniqueDirectory("DomainListenConnectAccept", domain_path); @@ -202,3 +227,13 @@ TEST_F(SocketTest, DomainGetConnectURI) { EXPECT_EQ(path, domain_path); } #endif + +INSTANTIATE_TEST_SUITE_P( + SocketTests, SocketTest, + testing::Values(SocketTestParams{/*is_ipv6=*/false, + /*localhost_ip=*/"127.0.0.1"}, + SocketTestParams{/*is_ipv6=*/true, /*localhost_ip=*/"::1"}), + // Prints "SocketTests/SocketTest.DecodeHostAndPort/ipv4" etc. in test logs. + [](const testing::TestParamInfo &info) { + return info.param.is_ipv6 ? "ipv6" : "ipv4"; + }); diff --git a/gnu/llvm/lldb/unittests/Host/SocketTestUtilities.cpp b/gnu/llvm/lldb/unittests/Host/SocketTestUtilities.cpp index e2006b85115..3b52a66a09e 100644 --- a/gnu/llvm/lldb/unittests/Host/SocketTestUtilities.cpp +++ b/gnu/llvm/lldb/unittests/Host/SocketTestUtilities.cpp @@ -101,13 +101,14 @@ static bool CheckIPSupport(llvm::StringRef Proto, llvm::StringRef Addr) { "Creating a canary {0} TCP socket failed: {1}.", Proto, Err) .str(); - bool HasAddrNotAvail = false; + bool HasProtocolError = false; handleAllErrors(std::move(Err), [&](std::unique_ptr ECErr) { - if (ECErr->convertToErrorCode() == - std::make_error_code(std::errc::address_not_available)) - HasAddrNotAvail = true; + std::error_code ec = ECErr->convertToErrorCode(); + if (ec == std::make_error_code(std::errc::address_family_not_supported) || + ec == std::make_error_code(std::errc::address_not_available)) + HasProtocolError = true; }); - if (HasAddrNotAvail) { + if (HasProtocolError) { GTEST_LOG_(WARNING) << llvm::formatv( "Assuming the host does not support {0}. Skipping test.", Proto) diff --git a/gnu/llvm/lldb/unittests/Interpreter/CMakeLists.txt b/gnu/llvm/lldb/unittests/Interpreter/CMakeLists.txt index 0de5b0b7248..6ea5996e2b0 100644 --- a/gnu/llvm/lldb/unittests/Interpreter/CMakeLists.txt +++ b/gnu/llvm/lldb/unittests/Interpreter/CMakeLists.txt @@ -1,6 +1,8 @@ add_lldb_unittest(InterpreterTests TestCompletion.cpp TestOptionArgParser.cpp + TestOptionValue.cpp + TestOptionValueFileColonLine.cpp LINK_LIBS lldbInterpreter diff --git a/gnu/llvm/lldb/unittests/Interpreter/TestOptionValue.cpp b/gnu/llvm/lldb/unittests/Interpreter/TestOptionValue.cpp new file mode 100644 index 00000000000..7f383424368 --- /dev/null +++ b/gnu/llvm/lldb/unittests/Interpreter/TestOptionValue.cpp @@ -0,0 +1,175 @@ +//===-- TestOptionValue.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 "lldb/Interpreter/OptionValues.h" +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +using namespace lldb_private; + +class Callback { +public: + virtual void Invoke() const {} + void operator()() const { Invoke(); } +protected: + ~Callback() = default; +}; + +class MockCallback final : public Callback { +public: + MOCK_CONST_METHOD0(Invoke, void()); +}; + +// Test a single-value class. +TEST(OptionValueString, DeepCopy) { + OptionValueString str; + str.SetValueFromString("ab"); + + MockCallback callback; + str.SetValueChangedCallback([&callback] { callback(); }); + EXPECT_CALL(callback, Invoke()); + + auto copy_sp = str.DeepCopy(nullptr); + + // Test that the base class data members are copied/set correctly. + ASSERT_TRUE(copy_sp); + ASSERT_EQ(copy_sp->GetParent().get(), nullptr); + ASSERT_TRUE(copy_sp->OptionWasSet()); + ASSERT_EQ(copy_sp->GetStringValue(), "ab"); + + // Trigger the callback. + copy_sp->SetValueFromString("c", eVarSetOperationAppend); + ASSERT_EQ(copy_sp->GetStringValue(), "abc"); +} + +// Test an aggregate class. +TEST(OptionValueArgs, DeepCopy) { + OptionValueArgs args; + args.SetValueFromString("A B"); + + MockCallback callback; + args.SetValueChangedCallback([&callback] { callback(); }); + EXPECT_CALL(callback, Invoke()); + + auto copy_sp = args.DeepCopy(nullptr); + + // Test that the base class data members are copied/set correctly. + ASSERT_TRUE(copy_sp); + ASSERT_EQ(copy_sp->GetParent(), nullptr); + ASSERT_TRUE(copy_sp->OptionWasSet()); + + auto *args_copy_ptr = copy_sp->GetAsArgs(); + ASSERT_EQ(args_copy_ptr->GetSize(), 2U); + ASSERT_EQ((*args_copy_ptr)[0]->GetParent(), copy_sp); + ASSERT_EQ((*args_copy_ptr)[0]->GetStringValue(), "A"); + ASSERT_EQ((*args_copy_ptr)[1]->GetParent(), copy_sp); + ASSERT_EQ((*args_copy_ptr)[1]->GetStringValue(), "B"); + + // Trigger the callback. + copy_sp->SetValueFromString("C", eVarSetOperationAppend); + ASSERT_TRUE(args_copy_ptr); + ASSERT_EQ(args_copy_ptr->GetSize(), 3U); + ASSERT_EQ((*args_copy_ptr)[2]->GetStringValue(), "C"); +} + +class TestProperties : public OptionValueProperties { +public: + static std::shared_ptr CreateGlobal() { + auto props_sp = std::make_shared(); + const bool is_global = false; + + auto dict_sp = std::make_shared(1 << eTypeUInt64); + props_sp->AppendProperty(ConstString("dict"), ConstString(), is_global, + dict_sp); + + auto file_list_sp = std::make_shared(); + props_sp->AppendProperty(ConstString("file-list"), ConstString(), is_global, + file_list_sp); + return props_sp; + } + + void SetDictionaryChangedCallback(const MockCallback &callback) { + SetValueChangedCallback(m_dict_index, [&callback] { callback(); }); + } + + void SetFileListChangedCallback(const MockCallback &callback) { + SetValueChangedCallback(m_file_list_index, [&callback] { callback(); }); + } + + OptionValueDictionary *GetDictionary() { + return GetPropertyAtIndexAsOptionValueDictionary(nullptr, m_dict_index); + } + + OptionValueFileSpecList *GetFileList() { + return GetPropertyAtIndexAsOptionValueFileSpecList(nullptr, true, + m_file_list_index); + } + +private: + lldb::OptionValueSP Clone() const { + return std::make_shared(*this); + } + + uint32_t m_dict_index = 0; + uint32_t m_file_list_index = 1; +}; + +// Test a user-defined propery class. +TEST(TestProperties, DeepCopy) { + auto props_sp = TestProperties::CreateGlobal(); + props_sp->GetDictionary()->SetValueFromString("A=1 B=2"); + props_sp->GetFileList()->SetValueFromString("path/to/file"); + + MockCallback callback; + props_sp->SetDictionaryChangedCallback(callback); + props_sp->SetFileListChangedCallback(callback); + EXPECT_CALL(callback, Invoke()).Times(2); + + auto copy_sp = props_sp->DeepCopy(nullptr); + + // Test that the base class data members are copied/set correctly. + ASSERT_TRUE(copy_sp); + ASSERT_EQ(copy_sp->GetParent(), nullptr); + + // This cast is safe only if the class overrides Clone(). + auto *props_copy_ptr = static_cast(copy_sp.get()); + ASSERT_TRUE(props_copy_ptr); + + // Test the first child. + auto dict_copy_ptr = props_copy_ptr->GetDictionary(); + ASSERT_TRUE(dict_copy_ptr); + ASSERT_EQ(dict_copy_ptr->GetParent(), copy_sp); + ASSERT_TRUE(dict_copy_ptr->OptionWasSet()); + ASSERT_EQ(dict_copy_ptr->GetNumValues(), 2U); + + auto value_ptr = dict_copy_ptr->GetValueForKey(ConstString("A")); + ASSERT_TRUE(value_ptr); + ASSERT_EQ(value_ptr->GetParent().get(), dict_copy_ptr); + ASSERT_EQ(value_ptr->GetUInt64Value(), 1U); + + value_ptr = dict_copy_ptr->GetValueForKey(ConstString("B")); + ASSERT_TRUE(value_ptr); + ASSERT_EQ(value_ptr->GetParent().get(), dict_copy_ptr); + ASSERT_EQ(value_ptr->GetUInt64Value(), 2U); + + // Test the second child. + auto file_list_copy_ptr = props_copy_ptr->GetFileList(); + ASSERT_TRUE(file_list_copy_ptr); + ASSERT_EQ(file_list_copy_ptr->GetParent(), copy_sp); + ASSERT_TRUE(file_list_copy_ptr->OptionWasSet()); + + auto file_list_copy = file_list_copy_ptr->GetCurrentValue(); + ASSERT_EQ(file_list_copy.GetSize(), 1U); + ASSERT_EQ(file_list_copy.GetFileSpecAtIndex(0), FileSpec("path/to/file")); + + // Trigger the callback first time. + dict_copy_ptr->SetValueFromString("C=3", eVarSetOperationAppend); + + // Trigger the callback second time. + file_list_copy_ptr->SetValueFromString("0 another/path", eVarSetOperationReplace); +} diff --git a/gnu/llvm/lldb/unittests/Interpreter/TestOptionValueFileColonLine.cpp b/gnu/llvm/lldb/unittests/Interpreter/TestOptionValueFileColonLine.cpp new file mode 100644 index 00000000000..079c26bdd8a --- /dev/null +++ b/gnu/llvm/lldb/unittests/Interpreter/TestOptionValueFileColonLine.cpp @@ -0,0 +1,58 @@ +//===-- ArgsTest.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 "lldb/Interpreter/OptionValueFileColonLine.h" +#include "lldb/Utility/FileSpec.h" +#include "lldb/Utility/Status.h" +#include "gtest/gtest.h" + +using namespace lldb_private; + +void CheckSetting(const char *input, bool success, FileSpec path = {}, + uint32_t line_number = LLDB_INVALID_LINE_NUMBER, + uint32_t column_number = LLDB_INVALID_COLUMN_NUMBER) { + + OptionValueFileColonLine value; + Status error; + llvm::StringRef s_ref(input); + error = value.SetValueFromString(s_ref); + ASSERT_EQ(error.Success(), success); + + // If we were meant to fail, we don't need to do more checks: + if (!success) + return; + + ASSERT_EQ(value.GetLineNumber(), line_number); + ASSERT_EQ(value.GetColumnNumber(), column_number); + ASSERT_EQ(value.GetFileSpec(), path); +} + +TEST(OptionValueFileColonLine, setFromString) { + OptionValueFileColonLine value; + Status error; + + // Make sure a default constructed value is invalid: + ASSERT_EQ(value.GetLineNumber(), + static_cast(LLDB_INVALID_LINE_NUMBER)); + ASSERT_EQ(value.GetColumnNumber(), + static_cast(LLDB_INVALID_COLUMN_NUMBER)); + ASSERT_FALSE(value.GetFileSpec()); + + // Make sure it is an error to pass a specifier with no line number: + CheckSetting("foo.c", false); + + // Now try with just a file & line: + CheckSetting("foo.c:12", true, FileSpec("foo.c"), 12); + CheckSetting("foo.c:12:20", true, FileSpec("foo.c"), 12, 20); + // Make sure a colon doesn't mess us up: + CheckSetting("foo:bar.c:12", true, FileSpec("foo:bar.c"), 12); + CheckSetting("foo:bar.c:12:20", true, FileSpec("foo:bar.c"), 12, 20); + // Try errors in the line number: + CheckSetting("foo.c:12c", false); + CheckSetting("foo.c:12:20c", false); +} diff --git a/gnu/llvm/lldb/unittests/ObjectFile/CMakeLists.txt b/gnu/llvm/lldb/unittests/ObjectFile/CMakeLists.txt index a9b42ea3199..b5d248e3965 100644 --- a/gnu/llvm/lldb/unittests/ObjectFile/CMakeLists.txt +++ b/gnu/llvm/lldb/unittests/ObjectFile/CMakeLists.txt @@ -1,3 +1,4 @@ add_subdirectory(Breakpad) add_subdirectory(ELF) +add_subdirectory(MachO) add_subdirectory(PECOFF) diff --git a/gnu/llvm/lldb/unittests/ObjectFile/MachO/CMakeLists.txt b/gnu/llvm/lldb/unittests/ObjectFile/MachO/CMakeLists.txt new file mode 100644 index 00000000000..b6c4225114a --- /dev/null +++ b/gnu/llvm/lldb/unittests/ObjectFile/MachO/CMakeLists.txt @@ -0,0 +1,10 @@ +add_lldb_unittest(ObjectFileMachOTests + TestObjectFileMachO.cpp + + LINK_LIBS + lldbPluginObjectFileMachO + lldbPluginSymbolFileSymtab + lldbCore + lldbUtilityHelpers + LLVMTestingSupport + ) diff --git a/gnu/llvm/lldb/unittests/ObjectFile/MachO/TestObjectFileMachO.cpp b/gnu/llvm/lldb/unittests/ObjectFile/MachO/TestObjectFileMachO.cpp new file mode 100644 index 00000000000..119be3822cc --- /dev/null +++ b/gnu/llvm/lldb/unittests/ObjectFile/MachO/TestObjectFileMachO.cpp @@ -0,0 +1,79 @@ +//===-- ObjectFileMachOTest.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 "lldb/Host/HostInfo.h" +#include "Plugins/ObjectFile/Mach-O/ObjectFileMachO.h" +#include "TestingSupport/SubsystemRAII.h" +#include "TestingSupport/TestUtilities.h" +#include "lldb/Core/Module.h" +#include "lldb/Host/FileSystem.h" +#include "lldb/lldb-defines.h" +#include "gtest/gtest.h" + +#ifdef __APPLE__ +#include +#endif + +using namespace lldb_private; +using namespace llvm; + +namespace { +class ObjectFileMachOTest : public ::testing::Test { + SubsystemRAII subsystems; +}; +} // namespace + +#if defined(__APPLE__) +TEST_F(ObjectFileMachOTest, ModuleFromSharedCacheInfo) { + SharedCacheImageInfo image_info = + HostInfo::GetSharedCacheImageInfo("/usr/lib/libobjc.A.dylib"); + EXPECT_TRUE(image_info.uuid); + EXPECT_TRUE(image_info.data_sp); + + ModuleSpec spec(FileSpec(), UUID(), image_info.data_sp); + lldb::ModuleSP module = std::make_shared(spec); + ObjectFile *OF = module->GetObjectFile(); + ASSERT_TRUE(llvm::isa(OF)); + EXPECT_TRUE( + OF->GetArchitecture().IsCompatibleMatch(HostInfo::GetArchitecture())); + Symtab *symtab = OF->GetSymtab(); + ASSERT_NE(symtab, nullptr); + void *libobjc = dlopen("/usr/lib/libobjc.A.dylib", RTLD_LAZY); + ASSERT_NE(libobjc, nullptr); + + // This function checks that if we read something from the + // ObjectFile we get through the shared cache in-mmeory + // buffer, it matches what we get by reading directly the + // memory of the symbol. + auto check_symbol = [&](const char *sym_name) { + std::vector symbol_indices; + symtab->FindAllSymbolsWithNameAndType(ConstString(sym_name), + lldb::eSymbolTypeAny, symbol_indices); + EXPECT_EQ(symbol_indices.size(), 1u); + + Symbol *sym = symtab->SymbolAtIndex(symbol_indices[0]); + ASSERT_NE(sym, nullptr); + Address base = sym->GetAddress(); + size_t size = sym->GetByteSize(); + ASSERT_NE(size, 0u); + uint8_t buffer[size]; + EXPECT_EQ(OF->ReadSectionData(base.GetSection().get(), base.GetOffset(), + buffer, size), + size); + + void *sym_addr = dlsym(libobjc, sym_name); + ASSERT_NE(sym_addr, nullptr); + EXPECT_EQ(memcmp(buffer, sym_addr, size), 0); + }; + + // Read a symbol from the __TEXT segment... + check_symbol("objc_msgSend"); + // ... and one from the __DATA segment + check_symbol("OBJC_CLASS_$_NSObject"); +} +#endif diff --git a/gnu/llvm/lldb/unittests/Platform/CMakeLists.txt b/gnu/llvm/lldb/unittests/Platform/CMakeLists.txt index eb7f0a6ca3c..ca5031b9b43 100644 --- a/gnu/llvm/lldb/unittests/Platform/CMakeLists.txt +++ b/gnu/llvm/lldb/unittests/Platform/CMakeLists.txt @@ -1,4 +1,5 @@ add_lldb_unittest(LLDBPlatformTests + PlatformAppleSimulatorTest.cpp PlatformDarwinTest.cpp LINK_LIBS diff --git a/gnu/llvm/lldb/unittests/Platform/PlatformAppleSimulatorTest.cpp b/gnu/llvm/lldb/unittests/Platform/PlatformAppleSimulatorTest.cpp new file mode 100644 index 00000000000..42549e89cc3 --- /dev/null +++ b/gnu/llvm/lldb/unittests/Platform/PlatformAppleSimulatorTest.cpp @@ -0,0 +1,71 @@ +//===-- PlatformAppleSimulatorTest.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 "gtest/gtest.h" + +#include "Plugins/Platform/MacOSX/PlatformAppleSimulator.h" +#include "TestingSupport/SubsystemRAII.h" +#include "lldb/Host/FileSystem.h" +#include "lldb/Host/HostInfo.h" +#include "lldb/Target/Platform.h" + +using namespace lldb; +using namespace lldb_private; + +class PlatformAppleSimulatorTest : public ::testing::Test { + SubsystemRAII + subsystems; +}; + +#ifdef __APPLE__ + +static void testSimPlatformArchHasSimEnvironment(llvm::StringRef name) { + Status error; + auto platform_sp = Platform::Create(ConstString(name), error); + ASSERT_TRUE(platform_sp); + int num_arches = 0; + + while (true) { + ArchSpec arch; + if (!platform_sp->GetSupportedArchitectureAtIndex(num_arches, arch)) + break; + EXPECT_EQ(arch.GetTriple().getEnvironment(), llvm::Triple::Simulator); + num_arches++; + } + + EXPECT_GT(num_arches, 0); +} + +TEST_F(PlatformAppleSimulatorTest, TestSimHasSimEnvionament) { + testSimPlatformArchHasSimEnvironment("ios-simulator"); + testSimPlatformArchHasSimEnvironment("tvos-simulator"); + testSimPlatformArchHasSimEnvironment("watchos-simulator"); +} + +TEST_F(PlatformAppleSimulatorTest, TestHostPlatformToSim) { + static const ArchSpec platform_arch( + HostInfo::GetArchitecture(HostInfo::eArchKindDefault)); + + const llvm::Triple::OSType sim_platforms[] = { + llvm::Triple::IOS, + llvm::Triple::TvOS, + llvm::Triple::WatchOS, + }; + + for (auto sim : sim_platforms) { + ArchSpec arch = platform_arch; + arch.GetTriple().setOS(sim); + arch.GetTriple().setEnvironment(llvm::Triple::Simulator); + + Status error; + auto platform_sp = Platform::Create(arch, nullptr, error); + EXPECT_TRUE(platform_sp); + } +} + +#endif diff --git a/gnu/llvm/lldb/unittests/Process/CMakeLists.txt b/gnu/llvm/lldb/unittests/Process/CMakeLists.txt index e068908d09f..5fbecfcfa25 100644 --- a/gnu/llvm/lldb/unittests/Process/CMakeLists.txt +++ b/gnu/llvm/lldb/unittests/Process/CMakeLists.txt @@ -3,6 +3,7 @@ if (CMAKE_SYSTEM_NAME MATCHES "Linux|Android") add_subdirectory(Linux) add_subdirectory(POSIX) endif() +add_subdirectory(Utility) add_subdirectory(minidump) add_lldb_unittest(ProcessEventDataTests diff --git a/gnu/llvm/lldb/unittests/Process/Linux/CMakeLists.txt b/gnu/llvm/lldb/unittests/Process/Linux/CMakeLists.txt index 31e9a57a4e4..ae021023cf7 100644 --- a/gnu/llvm/lldb/unittests/Process/Linux/CMakeLists.txt +++ b/gnu/llvm/lldb/unittests/Process/Linux/CMakeLists.txt @@ -1,8 +1,9 @@ -include_directories(${LLDB_SOURCE_DIR}/source/Plugins/Process/Linux) - -add_lldb_unittest(ProcessorTraceTests - ProcessorTraceTest.cpp +add_lldb_unittest(TraceIntelPTTests + IntelPTManagerTests.cpp LINK_LIBS lldbPluginProcessLinux - ) \ No newline at end of file + ) + +target_include_directories(TraceIntelPTTests PRIVATE + ${LLDB_SOURCE_DIR}/source/Plugins/Process/Linux) diff --git a/gnu/llvm/lldb/unittests/Process/Linux/IntelPTManagerTests.cpp b/gnu/llvm/lldb/unittests/Process/Linux/IntelPTManagerTests.cpp new file mode 100644 index 00000000000..76eb78a5193 --- /dev/null +++ b/gnu/llvm/lldb/unittests/Process/Linux/IntelPTManagerTests.cpp @@ -0,0 +1,147 @@ +//===-- IntelPTManagerTests.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 "gtest/gtest.h" + +#include "IntelPTManager.h" +#include "llvm/ADT/ArrayRef.h" + + +using namespace lldb_private; +using namespace process_linux; + +size_t ReadCylicBufferWrapper(void *buf, size_t buf_size, void *cyc_buf, + size_t cyc_buf_size, size_t cyc_start, + size_t offset) { + llvm::MutableArrayRef dst(reinterpret_cast(buf), + buf_size); + llvm::MutableArrayRef src(reinterpret_cast(cyc_buf), + cyc_buf_size); + IntelPTThreadTrace::ReadCyclicBuffer(dst, src, cyc_start, offset); + return dst.size(); +} + +TEST(CyclicBuffer, EdgeCases) { + size_t bytes_read; + uint8_t cyclic_buffer[6] = {'l', 'i', 'c', 'c', 'y', 'c'}; + + // We will always leave the last bytes untouched + // so that string comparisons work. + char smaller_buffer[4] = {}; + + // empty buffer to read into + bytes_read = ReadCylicBufferWrapper(smaller_buffer, 0, cyclic_buffer, + sizeof(cyclic_buffer), 3, 0); + ASSERT_EQ(0u, bytes_read); + + // empty cyclic buffer + bytes_read = ReadCylicBufferWrapper(smaller_buffer, sizeof(smaller_buffer), + cyclic_buffer, 0, 3, 0); + ASSERT_EQ(0u, bytes_read); + + // bigger offset + bytes_read = + ReadCylicBufferWrapper(smaller_buffer, sizeof(smaller_buffer), + cyclic_buffer, sizeof(cyclic_buffer), 3, 6); + ASSERT_EQ(0u, bytes_read); + + // wrong offset + bytes_read = + ReadCylicBufferWrapper(smaller_buffer, sizeof(smaller_buffer), + cyclic_buffer, sizeof(cyclic_buffer), 3, 7); + ASSERT_EQ(0u, bytes_read); + + // wrong start + bytes_read = + ReadCylicBufferWrapper(smaller_buffer, sizeof(smaller_buffer), + cyclic_buffer, sizeof(cyclic_buffer), 3, 7); + ASSERT_EQ(0u, bytes_read); +} + +TEST(CyclicBuffer, EqualSizeBuffer) { + size_t bytes_read = 0; + uint8_t cyclic_buffer[6] = {'l', 'i', 'c', 'c', 'y', 'c'}; + + char cyclic[] = "cyclic"; + for (size_t i = 0; i < sizeof(cyclic); i++) { + // We will always leave the last bytes untouched + // so that string comparisons work. + char equal_size_buffer[7] = {}; + bytes_read = + ReadCylicBufferWrapper(equal_size_buffer, sizeof(cyclic_buffer), + cyclic_buffer, sizeof(cyclic_buffer), 3, i); + ASSERT_EQ((sizeof(cyclic) - i - 1), bytes_read); + ASSERT_STREQ(equal_size_buffer, (cyclic + i)); + } +} + +TEST(CyclicBuffer, SmallerSizeBuffer) { + size_t bytes_read; + uint8_t cyclic_buffer[6] = {'l', 'i', 'c', 'c', 'y', 'c'}; + + // We will always leave the last bytes untouched + // so that string comparisons work. + char smaller_buffer[4] = {}; + bytes_read = + ReadCylicBufferWrapper(smaller_buffer, (sizeof(smaller_buffer) - 1), + cyclic_buffer, sizeof(cyclic_buffer), 3, 0); + ASSERT_EQ(3u, bytes_read); + ASSERT_STREQ(smaller_buffer, "cyc"); + + bytes_read = + ReadCylicBufferWrapper(smaller_buffer, (sizeof(smaller_buffer) - 1), + cyclic_buffer, sizeof(cyclic_buffer), 3, 1); + ASSERT_EQ(3u, bytes_read); + ASSERT_STREQ(smaller_buffer, "ycl"); + + bytes_read = + ReadCylicBufferWrapper(smaller_buffer, (sizeof(smaller_buffer) - 1), + cyclic_buffer, sizeof(cyclic_buffer), 3, 2); + ASSERT_EQ(3u, bytes_read); + ASSERT_STREQ(smaller_buffer, "cli"); + + bytes_read = + ReadCylicBufferWrapper(smaller_buffer, (sizeof(smaller_buffer) - 1), + cyclic_buffer, sizeof(cyclic_buffer), 3, 3); + ASSERT_EQ(3u, bytes_read); + ASSERT_STREQ(smaller_buffer, "lic"); + + { + char smaller_buffer[4] = {}; + bytes_read = + ReadCylicBufferWrapper(smaller_buffer, (sizeof(smaller_buffer) - 1), + cyclic_buffer, sizeof(cyclic_buffer), 3, 4); + ASSERT_EQ(2u, bytes_read); + ASSERT_STREQ(smaller_buffer, "ic"); + } + { + char smaller_buffer[4] = {}; + bytes_read = + ReadCylicBufferWrapper(smaller_buffer, (sizeof(smaller_buffer) - 1), + cyclic_buffer, sizeof(cyclic_buffer), 3, 5); + ASSERT_EQ(1u, bytes_read); + ASSERT_STREQ(smaller_buffer, "c"); + } +} + +TEST(CyclicBuffer, BiggerSizeBuffer) { + size_t bytes_read = 0; + uint8_t cyclic_buffer[6] = {'l', 'i', 'c', 'c', 'y', 'c'}; + + char cyclic[] = "cyclic"; + for (size_t i = 0; i < sizeof(cyclic); i++) { + // We will always leave the last bytes untouched + // so that string comparisons work. + char bigger_buffer[10] = {}; + bytes_read = + ReadCylicBufferWrapper(bigger_buffer, (sizeof(bigger_buffer) - 1), + cyclic_buffer, sizeof(cyclic_buffer), 3, i); + ASSERT_EQ((sizeof(cyclic) - i - 1), bytes_read); + ASSERT_STREQ(bigger_buffer, (cyclic + i)); + } +} diff --git a/gnu/llvm/lldb/unittests/Process/POSIX/CMakeLists.txt b/gnu/llvm/lldb/unittests/Process/POSIX/CMakeLists.txt index eabfb58d46f..9d12495dd3e 100644 --- a/gnu/llvm/lldb/unittests/Process/POSIX/CMakeLists.txt +++ b/gnu/llvm/lldb/unittests/Process/POSIX/CMakeLists.txt @@ -1,8 +1,9 @@ -include_directories(${LLDB_SOURCE_DIR}/source/Plugins/Process/POSIX) - add_lldb_unittest(ProcessPOSIXTests NativeProcessELFTest.cpp LINK_LIBS lldbPluginProcessPOSIX ) + +target_include_directories(ProcessPOSIXTests PRIVATE + ${LLDB_SOURCE_DIR}/source/Plugins/Process/POSIX) diff --git a/gnu/llvm/lldb/unittests/Process/ProcessEventDataTest.cpp b/gnu/llvm/lldb/unittests/Process/ProcessEventDataTest.cpp index 0f032a78611..8827384ed0a 100644 --- a/gnu/llvm/lldb/unittests/Process/ProcessEventDataTest.cpp +++ b/gnu/llvm/lldb/unittests/Process/ProcessEventDataTest.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "Plugins/Platform/MacOSX/PlatformMacOSX.h" +#include "Plugins/Platform/MacOSX/PlatformRemoteMacOSX.h" #include "lldb/Core/Debugger.h" #include "lldb/Host/FileSystem.h" #include "lldb/Host/HostInfo.h" @@ -43,21 +44,21 @@ class DummyProcess : public Process { public: using Process::Process; - virtual bool CanDebug(lldb::TargetSP target, bool plugin_specified_by_name) { + bool CanDebug(lldb::TargetSP target, bool plugin_specified_by_name) override { return true; } - virtual Status DoDestroy() { return {}; } - virtual void RefreshStateAfterStop() {} - virtual size_t DoReadMemory(lldb::addr_t vm_addr, void *buf, size_t size, - Status &error) { + Status DoDestroy() override { return {}; } + void RefreshStateAfterStop() override {} + size_t DoReadMemory(lldb::addr_t vm_addr, void *buf, size_t size, + Status &error) override { return 0; } - virtual bool UpdateThreadList(ThreadList &old_thread_list, - ThreadList &new_thread_list) { + bool DoUpdateThreadList(ThreadList &old_thread_list, + ThreadList &new_thread_list) override { return false; } - virtual ConstString GetPluginName() { return ConstString("Dummy"); } - virtual uint32_t GetPluginVersion() { return 0; } + ConstString GetPluginName() override { return ConstString("Dummy"); } + uint32_t GetPluginVersion() override { return 0; } ProcessModID &GetModIDNonConstRef() { return m_mod_id; } }; @@ -111,16 +112,11 @@ typedef std::shared_ptr ProcessEventDataSP; typedef std::shared_ptr EventSP; TargetSP CreateTarget(DebuggerSP &debugger_sp, ArchSpec &arch) { - Status error; PlatformSP platform_sp; TargetSP target_sp; - error = debugger_sp->GetTargetList().CreateTarget( + debugger_sp->GetTargetList().CreateTarget( *debugger_sp, "", arch, eLoadDependentsNo, platform_sp, target_sp); - if (target_sp) { - debugger_sp->GetTargetList().SetSelectedTarget(target_sp.get()); - } - return target_sp; } @@ -151,7 +147,7 @@ ThreadSP CreateThread(ProcessSP &process_sp, bool should_stop, TEST_F(ProcessEventDataTest, DoOnRemoval) { ArchSpec arch("x86_64-apple-macosx-"); - Platform::SetHostPlatform(PlatformMacOSX::CreateInstance(true, &arch)); + Platform::SetHostPlatform(PlatformRemoteMacOSX::CreateInstance(true, &arch)); DebuggerSP debugger_sp = Debugger::CreateInstance(); ASSERT_TRUE(debugger_sp); @@ -191,7 +187,7 @@ TEST_F(ProcessEventDataTest, DoOnRemoval) { TEST_F(ProcessEventDataTest, ShouldStop) { ArchSpec arch("x86_64-apple-macosx-"); - Platform::SetHostPlatform(PlatformMacOSX::CreateInstance(true, &arch)); + Platform::SetHostPlatform(PlatformRemoteMacOSX::CreateInstance(true, &arch)); DebuggerSP debugger_sp = Debugger::CreateInstance(); ASSERT_TRUE(debugger_sp); diff --git a/gnu/llvm/lldb/unittests/Process/Utility/CMakeLists.txt b/gnu/llvm/lldb/unittests/Process/Utility/CMakeLists.txt new file mode 100644 index 00000000000..95b65cef6a4 --- /dev/null +++ b/gnu/llvm/lldb/unittests/Process/Utility/CMakeLists.txt @@ -0,0 +1,25 @@ +set(FREEBSD_SOURCES + RegisterContextFreeBSDTest.cpp) +set(NETBSD_SOURCES + RegisterContextNetBSDTest_i386.cpp + RegisterContextNetBSDTest_x86_64.cpp) + +if (CMAKE_SYSTEM_NAME MATCHES "FreeBSD") + list(APPEND PLATFORM_SOURCES ${FREEBSD_SOURCES}) +elseif (CMAKE_SYSTEM_NAME MATCHES "NetBSD") + list(APPEND PLATFORM_SOURCES ${NETBSD_SOURCES}) +endif() + +set(LLVM_OPTIONAL_SOURCES + ${FREEBSD_SOURCES} + ${NETBSD_SOURCES}) + +add_lldb_unittest(ProcessUtilityTests + RegisterContextTest.cpp + LinuxProcMapsTest.cpp + MemoryTagManagerAArch64MTETest.cpp + ${PLATFORM_SOURCES} + + LINK_LIBS + lldbPluginProcessUtility + LLVMTestingSupport) diff --git a/gnu/llvm/lldb/unittests/Process/Utility/LinuxProcMapsTest.cpp b/gnu/llvm/lldb/unittests/Process/Utility/LinuxProcMapsTest.cpp new file mode 100644 index 00000000000..66db61ff659 --- /dev/null +++ b/gnu/llvm/lldb/unittests/Process/Utility/LinuxProcMapsTest.cpp @@ -0,0 +1,262 @@ +//===-- LinuxProcMapsTest.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 "gmock/gmock.h" +#include "gtest/gtest.h" + +#include "Plugins/Process/Utility/LinuxProcMaps.h" +#include "lldb/Target/MemoryRegionInfo.h" +#include "lldb/Utility/Status.h" +#include + +using namespace lldb_private; + +typedef std::tuple + LinuxProcMapsTestParams; + +// Wrapper for convenience because Range is usually begin, size +static MemoryRegionInfo::RangeType make_range(lldb::addr_t begin, + lldb::addr_t end) { + MemoryRegionInfo::RangeType range(begin, 0); + range.SetRangeEnd(end); + return range; +} + +class LinuxProcMapsTestFixture + : public ::testing::TestWithParam { +protected: + Status error; + std::string err_str; + MemoryRegionInfos regions; + LinuxMapCallback callback; + + void SetUp() override { + callback = [this](llvm::Expected Info) { + if (Info) { + err_str.clear(); + regions.push_back(*Info); + return true; + } + + err_str = toString(Info.takeError()); + return false; + }; + } + + void check_regions(LinuxProcMapsTestParams params) { + EXPECT_THAT(std::get<1>(params), testing::ContainerEq(regions)); + ASSERT_EQ(std::get<2>(params), err_str); + } +}; + +TEST_P(LinuxProcMapsTestFixture, ParseMapRegions) { + auto params = GetParam(); + ParseLinuxMapRegions(std::get<0>(params), callback); + check_regions(params); +} + +// Note: ConstString("") != ConstString(nullptr) +// When a region has no name, it will have the latter in the MemoryRegionInfo +INSTANTIATE_TEST_SUITE_P( + ProcMapTests, LinuxProcMapsTestFixture, + ::testing::Values( + // Nothing in nothing out + std::make_tuple("", MemoryRegionInfos{}, ""), + // Various formatting error conditions + std::make_tuple("55a4512f7000/55a451b68000 rw-p 00000000 00:00 0", + MemoryRegionInfos{}, + "malformed /proc/{pid}/maps entry, missing dash " + "between address range"), + std::make_tuple("0-0 rw", MemoryRegionInfos{}, + "malformed /proc/{pid}/maps entry, missing some " + "portion of permissions"), + std::make_tuple("0-0 z--p 00000000 00:00 0", MemoryRegionInfos{}, + "unexpected /proc/{pid}/maps read permission char"), + std::make_tuple("0-0 rz-p 00000000 00:00 0", MemoryRegionInfos{}, + "unexpected /proc/{pid}/maps write permission char"), + std::make_tuple("0-0 rwzp 00000000 00:00 0", MemoryRegionInfos{}, + "unexpected /proc/{pid}/maps exec permission char"), + // Stops at first parsing error + std::make_tuple( + "0-1 rw-p 00000000 00:00 0 [abc]\n" + "0-0 rwzp 00000000 00:00 0\n" + "2-3 r-xp 00000000 00:00 0 [def]\n", + MemoryRegionInfos{ + MemoryRegionInfo(make_range(0, 1), MemoryRegionInfo::eYes, + MemoryRegionInfo::eYes, MemoryRegionInfo::eNo, + MemoryRegionInfo::eYes, ConstString("[abc]"), + MemoryRegionInfo::eDontKnow, 0, + MemoryRegionInfo::eDontKnow), + }, + "unexpected /proc/{pid}/maps exec permission char"), + // Single entry + std::make_tuple( + "55a4512f7000-55a451b68000 rw-p 00000000 00:00 0 [heap]", + MemoryRegionInfos{ + MemoryRegionInfo(make_range(0x55a4512f7000, 0x55a451b68000), + MemoryRegionInfo::eYes, MemoryRegionInfo::eYes, + MemoryRegionInfo::eNo, MemoryRegionInfo::eYes, + ConstString("[heap]"), + MemoryRegionInfo::eDontKnow, 0, + MemoryRegionInfo::eDontKnow), + }, + ""), + // Multiple entries + std::make_tuple( + "7fc090021000-7fc094000000 ---p 00000000 00:00 0\n" + "ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 " + "[vsyscall]", + MemoryRegionInfos{ + MemoryRegionInfo(make_range(0x7fc090021000, 0x7fc094000000), + MemoryRegionInfo::eNo, MemoryRegionInfo::eNo, + MemoryRegionInfo::eNo, MemoryRegionInfo::eYes, + ConstString(nullptr), + MemoryRegionInfo::eDontKnow, 0, + MemoryRegionInfo::eDontKnow), + MemoryRegionInfo( + make_range(0xffffffffff600000, 0xffffffffff601000), + MemoryRegionInfo::eYes, MemoryRegionInfo::eNo, + MemoryRegionInfo::eYes, MemoryRegionInfo::eYes, + ConstString("[vsyscall]"), MemoryRegionInfo::eDontKnow, 0, + MemoryRegionInfo::eDontKnow), + }, + ""))); + +class LinuxProcSMapsTestFixture : public LinuxProcMapsTestFixture {}; + +INSTANTIATE_TEST_SUITE_P( + ProcSMapTests, LinuxProcSMapsTestFixture, + ::testing::Values( + // Nothing in nothing out + std::make_tuple("", MemoryRegionInfos{}, ""), + // Uses the same parsing for first line, so same errors but referring to + // smaps + std::make_tuple("0/0 rw-p 00000000 00:00 0", MemoryRegionInfos{}, + "malformed /proc/{pid}/smaps entry, missing dash " + "between address range"), + // Stop parsing at first error + std::make_tuple( + "1111-2222 rw-p 00000000 00:00 0 [foo]\n" + "0/0 rw-p 00000000 00:00 0", + MemoryRegionInfos{ + MemoryRegionInfo(make_range(0x1111, 0x2222), + MemoryRegionInfo::eYes, MemoryRegionInfo::eYes, + MemoryRegionInfo::eNo, MemoryRegionInfo::eYes, + ConstString("[foo]"), + MemoryRegionInfo::eDontKnow, 0, + MemoryRegionInfo::eDontKnow), + }, + "malformed /proc/{pid}/smaps entry, missing dash between address " + "range"), + // Property line without a region is an error + std::make_tuple("Referenced: 2188 kB\n" + "1111-2222 rw-p 00000000 00:00 0 [foo]\n" + "3333-4444 rw-p 00000000 00:00 0 [bar]\n", + MemoryRegionInfos{}, + "Found a property line without a corresponding mapping " + "in /proc/{pid}/smaps"), + // Single region parses, has no flags + std::make_tuple( + "1111-2222 rw-p 00000000 00:00 0 [foo]", + MemoryRegionInfos{ + MemoryRegionInfo(make_range(0x1111, 0x2222), + MemoryRegionInfo::eYes, MemoryRegionInfo::eYes, + MemoryRegionInfo::eNo, MemoryRegionInfo::eYes, + ConstString("[foo]"), + MemoryRegionInfo::eDontKnow, 0, + MemoryRegionInfo::eDontKnow), + }, + ""), + // Single region with flags, other lines ignored + std::make_tuple( + "1111-2222 rw-p 00000000 00:00 0 [foo]\n" + "Referenced: 2188 kB\n" + "AnonHugePages: 0 kB\n" + "VmFlags: mt", + MemoryRegionInfos{ + MemoryRegionInfo( + make_range(0x1111, 0x2222), MemoryRegionInfo::eYes, + MemoryRegionInfo::eYes, MemoryRegionInfo::eNo, + MemoryRegionInfo::eYes, ConstString("[foo]"), + MemoryRegionInfo::eDontKnow, 0, MemoryRegionInfo::eYes), + }, + ""), + // Whitespace ignored + std::make_tuple( + "0-0 rw-p 00000000 00:00 0\n" + "VmFlags: mt ", + MemoryRegionInfos{ + MemoryRegionInfo(make_range(0, 0), MemoryRegionInfo::eYes, + MemoryRegionInfo::eYes, MemoryRegionInfo::eNo, + MemoryRegionInfo::eYes, ConstString(nullptr), + MemoryRegionInfo::eDontKnow, 0, + MemoryRegionInfo::eYes), + }, + ""), + // VmFlags line means it has flag info, but nothing is set + std::make_tuple( + "0-0 rw-p 00000000 00:00 0\n" + "VmFlags: ", + MemoryRegionInfos{ + MemoryRegionInfo(make_range(0, 0), MemoryRegionInfo::eYes, + MemoryRegionInfo::eYes, MemoryRegionInfo::eNo, + MemoryRegionInfo::eYes, ConstString(nullptr), + MemoryRegionInfo::eDontKnow, 0, + MemoryRegionInfo::eNo), + }, + ""), + // Handle some pages not having a flags line + std::make_tuple( + "1111-2222 rw-p 00000000 00:00 0 [foo]\n" + "Referenced: 2188 kB\n" + "AnonHugePages: 0 kB\n" + "3333-4444 r-xp 00000000 00:00 0 [bar]\n" + "VmFlags: mt", + MemoryRegionInfos{ + MemoryRegionInfo(make_range(0x1111, 0x2222), + MemoryRegionInfo::eYes, MemoryRegionInfo::eYes, + MemoryRegionInfo::eNo, MemoryRegionInfo::eYes, + ConstString("[foo]"), + MemoryRegionInfo::eDontKnow, 0, + MemoryRegionInfo::eDontKnow), + MemoryRegionInfo( + make_range(0x3333, 0x4444), MemoryRegionInfo::eYes, + MemoryRegionInfo::eNo, MemoryRegionInfo::eYes, + MemoryRegionInfo::eYes, ConstString("[bar]"), + MemoryRegionInfo::eDontKnow, 0, MemoryRegionInfo::eYes), + }, + ""), + // Handle no pages having a flags line (older kernels) + std::make_tuple( + "1111-2222 rw-p 00000000 00:00 0\n" + "Referenced: 2188 kB\n" + "AnonHugePages: 0 kB\n" + "3333-4444 r-xp 00000000 00:00 0\n" + "KernelPageSize: 4 kB\n" + "MMUPageSize: 4 kB\n", + MemoryRegionInfos{ + MemoryRegionInfo(make_range(0x1111, 0x2222), + MemoryRegionInfo::eYes, MemoryRegionInfo::eYes, + MemoryRegionInfo::eNo, MemoryRegionInfo::eYes, + ConstString(nullptr), + MemoryRegionInfo::eDontKnow, 0, + MemoryRegionInfo::eDontKnow), + MemoryRegionInfo(make_range(0x3333, 0x4444), + MemoryRegionInfo::eYes, MemoryRegionInfo::eNo, + MemoryRegionInfo::eYes, MemoryRegionInfo::eYes, + ConstString(nullptr), + MemoryRegionInfo::eDontKnow, 0, + MemoryRegionInfo::eDontKnow), + }, + ""))); + +TEST_P(LinuxProcSMapsTestFixture, ParseSMapRegions) { + auto params = GetParam(); + ParseLinuxSMapRegions(std::get<0>(params), callback); + check_regions(params); +} diff --git a/gnu/llvm/lldb/unittests/Process/Utility/MemoryTagManagerAArch64MTETest.cpp b/gnu/llvm/lldb/unittests/Process/Utility/MemoryTagManagerAArch64MTETest.cpp new file mode 100644 index 00000000000..128dac7a21c --- /dev/null +++ b/gnu/llvm/lldb/unittests/Process/Utility/MemoryTagManagerAArch64MTETest.cpp @@ -0,0 +1,322 @@ +//===-- MemoryTagManagerAArch64MTETest.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 "Plugins/Process/Utility/MemoryTagManagerAArch64MTE.h" +#include "llvm/Testing/Support/Error.h" +#include "gtest/gtest.h" + +using namespace lldb_private; + +TEST(MemoryTagManagerAArch64MTETest, UnpackTagsData) { + MemoryTagManagerAArch64MTE manager; + + // Error for insufficient tag data + std::vector input; + ASSERT_THAT_EXPECTED( + manager.UnpackTagsData(input, 2), + llvm::FailedWithMessage( + "Packed tag data size does not match expected number of tags. " + "Expected 2 tag(s) for 2 granule(s), got 0 tag(s).")); + + // This is out of the valid tag range + input.push_back(0x1f); + ASSERT_THAT_EXPECTED( + manager.UnpackTagsData(input, 1), + llvm::FailedWithMessage( + "Found tag 0x1f which is > max MTE tag value of 0xf.")); + + // MTE tags are 1 per byte + input.pop_back(); + input.push_back(0xe); + input.push_back(0xf); + + std::vector expected{0xe, 0xf}; + + llvm::Expected> got = + manager.UnpackTagsData(input, 2); + ASSERT_THAT_EXPECTED(got, llvm::Succeeded()); + ASSERT_THAT(expected, testing::ContainerEq(*got)); + + // Error for too much tag data + ASSERT_THAT_EXPECTED( + manager.UnpackTagsData(input, 1), + llvm::FailedWithMessage( + "Packed tag data size does not match expected number of tags. " + "Expected 1 tag(s) for 1 granule(s), got 2 tag(s).")); + + // By default, we don't check number of tags + llvm::Expected> got_zero = + manager.UnpackTagsData(input); + ASSERT_THAT_EXPECTED(got_zero, llvm::Succeeded()); + ASSERT_THAT(expected, testing::ContainerEq(*got)); + + // Which is the same as granules=0 + got_zero = manager.UnpackTagsData(input, 0); + ASSERT_THAT_EXPECTED(got_zero, llvm::Succeeded()); + ASSERT_THAT(expected, testing::ContainerEq(*got)); +} + +TEST(MemoryTagManagerAArch64MTETest, PackTags) { + MemoryTagManagerAArch64MTE manager; + + // Error for tag out of range + llvm::Expected> invalid_tag_err = + manager.PackTags({0x10}); + ASSERT_THAT_EXPECTED( + invalid_tag_err, + llvm::FailedWithMessage( + "Found tag 0x10 which is > max MTE tag value of 0xf.")); + + // 0xf here is the max tag value that we can pack + std::vector tags{0, 1, 0xf}; + std::vector expected{0, 1, 0xf}; + llvm::Expected> packed = manager.PackTags(tags); + ASSERT_THAT_EXPECTED(packed, llvm::Succeeded()); + ASSERT_THAT(expected, testing::ContainerEq(*packed)); +} + +TEST(MemoryTagManagerAArch64MTETest, GetLogicalTag) { + MemoryTagManagerAArch64MTE manager; + + // Set surrounding bits to check shift is correct + ASSERT_EQ((lldb::addr_t)0, manager.GetLogicalTag(0xe0e00000ffffffff)); + // Max tag value + ASSERT_EQ((lldb::addr_t)0xf, manager.GetLogicalTag(0x0f000000ffffffff)); + ASSERT_EQ((lldb::addr_t)2, manager.GetLogicalTag(0x02000000ffffffff)); +} + +TEST(MemoryTagManagerAArch64MTETest, ExpandToGranule) { + MemoryTagManagerAArch64MTE manager; + // Reading nothing, no alignment needed + ASSERT_EQ( + MemoryTagManagerAArch64MTE::TagRange(0, 0), + manager.ExpandToGranule(MemoryTagManagerAArch64MTE::TagRange(0, 0))); + + // Ranges with 0 size are unchanged even if address is non 0 + // (normally 0x1234 would be aligned to 0x1230) + ASSERT_EQ( + MemoryTagManagerAArch64MTE::TagRange(0x1234, 0), + manager.ExpandToGranule(MemoryTagManagerAArch64MTE::TagRange(0x1234, 0))); + + // Ranges already aligned don't change + ASSERT_EQ( + MemoryTagManagerAArch64MTE::TagRange(0x100, 64), + manager.ExpandToGranule(MemoryTagManagerAArch64MTE::TagRange(0x100, 64))); + + // Any read of less than 1 granule is rounded up to reading 1 granule + ASSERT_EQ( + MemoryTagManagerAArch64MTE::TagRange(0, 16), + manager.ExpandToGranule(MemoryTagManagerAArch64MTE::TagRange(0, 1))); + + // Start address is aligned down, and length modified accordingly + // Here bytes 8 through 24 straddle 2 granules. So the resulting range starts + // at 0 and covers 32 bytes. + ASSERT_EQ( + MemoryTagManagerAArch64MTE::TagRange(0, 32), + manager.ExpandToGranule(MemoryTagManagerAArch64MTE::TagRange(8, 16))); + + // Here only the size of the range needs aligning + ASSERT_EQ( + MemoryTagManagerAArch64MTE::TagRange(16, 32), + manager.ExpandToGranule(MemoryTagManagerAArch64MTE::TagRange(16, 24))); + + // Start and size need aligning here but we only need 1 granule to cover it + ASSERT_EQ( + MemoryTagManagerAArch64MTE::TagRange(16, 16), + manager.ExpandToGranule(MemoryTagManagerAArch64MTE::TagRange(18, 4))); +} + +static MemoryRegionInfo MakeRegionInfo(lldb::addr_t base, lldb::addr_t size, + bool tagged) { + return MemoryRegionInfo( + MemoryRegionInfo::RangeType(base, size), MemoryRegionInfo::eYes, + MemoryRegionInfo::eYes, MemoryRegionInfo::eYes, MemoryRegionInfo::eYes, + ConstString(), MemoryRegionInfo::eNo, 0, + /*memory_tagged=*/ + tagged ? MemoryRegionInfo::eYes : MemoryRegionInfo::eNo); +} + +TEST(MemoryTagManagerAArch64MTETest, MakeTaggedRange) { + MemoryTagManagerAArch64MTE manager; + MemoryRegionInfos memory_regions; + + // No regions means no tagged regions, error + ASSERT_THAT_EXPECTED( + manager.MakeTaggedRange(0, 0x10, memory_regions), + llvm::FailedWithMessage( + "Address range 0x0:0x10 is not in a memory tagged region")); + + // Alignment is done before checking regions. + // Here 1 is rounded up to the granule size of 0x10. + ASSERT_THAT_EXPECTED( + manager.MakeTaggedRange(0, 1, memory_regions), + llvm::FailedWithMessage( + "Address range 0x0:0x10 is not in a memory tagged region")); + + // Range must not be inverted + ASSERT_THAT_EXPECTED( + manager.MakeTaggedRange(1, 0, memory_regions), + llvm::FailedWithMessage( + "End address (0x0) must be greater than the start address (0x1)")); + + // Adding a single region to cover the whole range + memory_regions.push_back(MakeRegionInfo(0, 0x1000, true)); + + // Range can have different tags for begin and end + // (which would make it look inverted if we didn't remove them) + // Note that range comes back with an untagged base and alginment + // applied. + MemoryTagManagerAArch64MTE::TagRange expected_range(0x0, 0x10); + llvm::Expected got = + manager.MakeTaggedRange(0x0f00000000000000, 0x0e00000000000001, + memory_regions); + ASSERT_THAT_EXPECTED(got, llvm::Succeeded()); + ASSERT_EQ(*got, expected_range); + + // Error if the range isn't within any region + ASSERT_THAT_EXPECTED( + manager.MakeTaggedRange(0x1000, 0x1010, memory_regions), + llvm::FailedWithMessage( + "Address range 0x1000:0x1010 is not in a memory tagged region")); + + // Error if the first part of a range isn't tagged + memory_regions.clear(); + const char *err_msg = + "Address range 0x0:0x1000 is not in a memory tagged region"; + + // First because it has no region entry + memory_regions.push_back(MakeRegionInfo(0x10, 0x1000, true)); + ASSERT_THAT_EXPECTED(manager.MakeTaggedRange(0, 0x1000, memory_regions), + llvm::FailedWithMessage(err_msg)); + + // Then because the first region is untagged + memory_regions.push_back(MakeRegionInfo(0, 0x10, false)); + ASSERT_THAT_EXPECTED(manager.MakeTaggedRange(0, 0x1000, memory_regions), + llvm::FailedWithMessage(err_msg)); + + // If we tag that first part it succeeds + memory_regions.back().SetMemoryTagged(MemoryRegionInfo::eYes); + expected_range = MemoryTagManagerAArch64MTE::TagRange(0x0, 0x1000); + got = manager.MakeTaggedRange(0, 0x1000, memory_regions); + ASSERT_THAT_EXPECTED(got, llvm::Succeeded()); + ASSERT_EQ(*got, expected_range); + + // Error if the end of a range is untagged + memory_regions.clear(); + + // First because it has no region entry + memory_regions.push_back(MakeRegionInfo(0, 0xF00, true)); + ASSERT_THAT_EXPECTED(manager.MakeTaggedRange(0, 0x1000, memory_regions), + llvm::FailedWithMessage(err_msg)); + + // Then because the last region is untagged + memory_regions.push_back(MakeRegionInfo(0xF00, 0x100, false)); + ASSERT_THAT_EXPECTED(manager.MakeTaggedRange(0, 0x1000, memory_regions), + llvm::FailedWithMessage(err_msg)); + + // If we tag the last part it succeeds + memory_regions.back().SetMemoryTagged(MemoryRegionInfo::eYes); + got = manager.MakeTaggedRange(0, 0x1000, memory_regions); + ASSERT_THAT_EXPECTED(got, llvm::Succeeded()); + ASSERT_EQ(*got, expected_range); + + // Error if the middle of a range is untagged + memory_regions.clear(); + + // First because it has no entry + memory_regions.push_back(MakeRegionInfo(0, 0x500, true)); + memory_regions.push_back(MakeRegionInfo(0x900, 0x700, true)); + ASSERT_THAT_EXPECTED(manager.MakeTaggedRange(0, 0x1000, memory_regions), + llvm::FailedWithMessage(err_msg)); + + // Then because it's untagged + memory_regions.push_back(MakeRegionInfo(0x500, 0x400, false)); + ASSERT_THAT_EXPECTED(manager.MakeTaggedRange(0, 0x1000, memory_regions), + llvm::FailedWithMessage(err_msg)); + + // If we tag the middle part it succeeds + memory_regions.back().SetMemoryTagged(MemoryRegionInfo::eYes); + got = manager.MakeTaggedRange(0, 0x1000, memory_regions); + ASSERT_THAT_EXPECTED(got, llvm::Succeeded()); + ASSERT_EQ(*got, expected_range); +} + +TEST(MemoryTagManagerAArch64MTETest, RemoveNonAddressBits) { + MemoryTagManagerAArch64MTE manager; + + ASSERT_EQ(0, 0); + ASSERT_EQ((lldb::addr_t)0x00ffeedd11223344, + manager.RemoveNonAddressBits(0x00ffeedd11223344)); + ASSERT_EQ((lldb::addr_t)0x0000000000000000, + manager.RemoveNonAddressBits(0xFF00000000000000)); + ASSERT_EQ((lldb::addr_t)0x0055555566666666, + manager.RemoveNonAddressBits(0xee55555566666666)); +} + +TEST(MemoryTagManagerAArch64MTETest, AddressDiff) { + MemoryTagManagerAArch64MTE manager; + + ASSERT_EQ(0, manager.AddressDiff(0, 0)); + // Result is signed + ASSERT_EQ(10, manager.AddressDiff(10, 0)); + ASSERT_EQ(-10, manager.AddressDiff(0, 10)); + // Anything in the top byte is ignored + ASSERT_EQ(0, manager.AddressDiff(0x2211222233334444, 0x3311222233334444)); + ASSERT_EQ(-32, manager.AddressDiff(0x5511222233334400, 0x4411222233334420)); + ASSERT_EQ(65, manager.AddressDiff(0x9911222233334441, 0x6611222233334400)); +} + +// Helper to check that repeating "tags" over "range" gives you +// "expected_tags". +static void +test_repeating_tags(const std::vector &tags, + MemoryTagManagerAArch64MTE::TagRange range, + const std::vector &expected_tags) { + MemoryTagManagerAArch64MTE manager; + llvm::Expected> tags_or_err = + manager.RepeatTagsForRange(tags, range); + ASSERT_THAT_EXPECTED(tags_or_err, llvm::Succeeded()); + ASSERT_THAT(expected_tags, testing::ContainerEq(*tags_or_err)); +} + +TEST(MemoryTagManagerAArch64MTETest, RepeatTagsForRange) { + MemoryTagManagerAArch64MTE manager; + + // Must have some tags if your range is not empty + llvm::Expected> no_tags_err = + manager.RepeatTagsForRange({}, + MemoryTagManagerAArch64MTE::TagRange{0, 16}); + ASSERT_THAT_EXPECTED( + no_tags_err, llvm::FailedWithMessage( + "Expected some tags to cover given range, got zero.")); + + // If the range is empty, you get no tags back + test_repeating_tags({1, 2, 3}, MemoryTagManagerAArch64MTE::TagRange{0, 0}, + {}); + // And you don't need tags for an empty range + test_repeating_tags({}, MemoryTagManagerAArch64MTE::TagRange{0, 0}, {}); + + // A single tag will just be multiplied as many times as needed + test_repeating_tags({5}, MemoryTagManagerAArch64MTE::TagRange{0, 16}, {5}); + test_repeating_tags({6}, MemoryTagManagerAArch64MTE::TagRange{0, 32}, {6, 6}); + + // If you've got as many tags as granules, it's a roundtrip + test_repeating_tags({7, 8}, MemoryTagManagerAArch64MTE::TagRange{0, 32}, + {7, 8}); + + // If you've got fewer tags than granules, they repeat. Exactly or partially + // as needed. + test_repeating_tags({7, 8}, MemoryTagManagerAArch64MTE::TagRange{0, 64}, + {7, 8, 7, 8}); + test_repeating_tags({7, 8}, MemoryTagManagerAArch64MTE::TagRange{0, 48}, + {7, 8, 7}); + + // If you've got more tags than granules you get back only those needed + test_repeating_tags({1, 2, 3, 4}, MemoryTagManagerAArch64MTE::TagRange{0, 32}, + {1, 2}); +} diff --git a/gnu/llvm/lldb/unittests/Process/Utility/RegisterContextFreeBSDTest.cpp b/gnu/llvm/lldb/unittests/Process/Utility/RegisterContextFreeBSDTest.cpp new file mode 100644 index 00000000000..f14dc8faaea --- /dev/null +++ b/gnu/llvm/lldb/unittests/Process/Utility/RegisterContextFreeBSDTest.cpp @@ -0,0 +1,553 @@ +//===-- RegisterContextFreeBSDTests.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 +// +//===----------------------------------------------------------------------===// + +// clang-format off +#include +#include +#if defined(__arm__) +#include +#endif +// clang-format on + +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +#include "Plugins/Process/Utility/RegisterContextFreeBSD_i386.h" +#include "Plugins/Process/Utility/RegisterContextFreeBSD_mips64.h" +#include "Plugins/Process/Utility/RegisterContextFreeBSD_powerpc.h" +#include "Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.h" +#include "Plugins/Process/Utility/RegisterContextPOSIX_powerpc.h" +#include "Plugins/Process/Utility/RegisterInfoPOSIX_arm.h" +#include "Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h" +#include "Plugins/Process/Utility/lldb-arm-register-enums.h" +#include "Plugins/Process/Utility/lldb-arm64-register-enums.h" +#include "Plugins/Process/Utility/lldb-mips-freebsd-register-enums.h" +#include "Plugins/Process/Utility/lldb-x86-register-enums.h" + +using namespace lldb; +using namespace lldb_private; + +std::pair GetRegParams(RegisterInfoInterface &ctx, + uint32_t reg) { + const RegisterInfo &info = ctx.GetRegisterInfo()[reg]; + return {info.byte_offset, info.byte_size}; +} + +#define EXPECT_OFF(regname, offset, size) \ + EXPECT_THAT(GetRegParams(reg_ctx, lldb_##regname), \ + ::testing::Pair(offset + base_offset, size)) + +#if defined(__x86_64__) + +#define EXPECT_GPR_X86_64(regname) \ + EXPECT_THAT( \ + GetRegParams(reg_ctx, lldb_##regname##_x86_64), \ + ::testing::Pair(offsetof(reg, r_##regname), sizeof(reg::r_##regname))) +#define EXPECT_DBR_X86_64(num) \ + EXPECT_OFF(dr##num##_x86_64, offsetof(dbreg, dr[num]), sizeof(dbreg::dr[num])) + +TEST(RegisterContextFreeBSDTest, x86_64) { + ArchSpec arch{"x86_64-unknown-freebsd"}; + RegisterContextFreeBSD_x86_64 reg_ctx{arch}; + + EXPECT_GPR_X86_64(r15); + EXPECT_GPR_X86_64(r14); + EXPECT_GPR_X86_64(r13); + EXPECT_GPR_X86_64(r12); + EXPECT_GPR_X86_64(r11); + EXPECT_GPR_X86_64(r10); + EXPECT_GPR_X86_64(r9); + EXPECT_GPR_X86_64(r8); + EXPECT_GPR_X86_64(rdi); + EXPECT_GPR_X86_64(rsi); + EXPECT_GPR_X86_64(rbp); + EXPECT_GPR_X86_64(rbx); + EXPECT_GPR_X86_64(rdx); + EXPECT_GPR_X86_64(rcx); + EXPECT_GPR_X86_64(rax); + EXPECT_GPR_X86_64(fs); + EXPECT_GPR_X86_64(gs); + EXPECT_GPR_X86_64(es); + EXPECT_GPR_X86_64(ds); + EXPECT_GPR_X86_64(rip); + EXPECT_GPR_X86_64(cs); + EXPECT_GPR_X86_64(rflags); + EXPECT_GPR_X86_64(rsp); + EXPECT_GPR_X86_64(ss); + + // fctrl is the first FPR field, it is used to determine offset of the whole + // FPR struct + size_t base_offset = reg_ctx.GetRegisterInfo()[lldb_fctrl_x86_64].byte_offset; + + // assert against FXSAVE struct + EXPECT_OFF(fctrl_x86_64, 0x00, 2); + EXPECT_OFF(fstat_x86_64, 0x02, 2); + // TODO: This is a known bug, abridged ftag should is 8 bits in length. + EXPECT_OFF(ftag_x86_64, 0x04, 2); + EXPECT_OFF(fop_x86_64, 0x06, 2); + // NB: Technically fiseg/foseg are 16-bit long and the higher 16 bits + // are reserved. However, LLDB defines them to be 32-bit long for backwards + // compatibility, as they were used to reconstruct FIP/FDP before explicit + // register entries for them were added. Also, this is still how GDB does it. + EXPECT_OFF(fioff_x86_64, 0x08, 4); + EXPECT_OFF(fiseg_x86_64, 0x0C, 4); + EXPECT_OFF(fip_x86_64, 0x08, 8); + EXPECT_OFF(fooff_x86_64, 0x10, 4); + EXPECT_OFF(foseg_x86_64, 0x14, 4); + EXPECT_OFF(fdp_x86_64, 0x10, 8); + EXPECT_OFF(mxcsr_x86_64, 0x18, 4); + EXPECT_OFF(mxcsrmask_x86_64, 0x1C, 4); + EXPECT_OFF(st0_x86_64, 0x20, 10); + EXPECT_OFF(st1_x86_64, 0x30, 10); + EXPECT_OFF(st2_x86_64, 0x40, 10); + EXPECT_OFF(st3_x86_64, 0x50, 10); + EXPECT_OFF(st4_x86_64, 0x60, 10); + EXPECT_OFF(st5_x86_64, 0x70, 10); + EXPECT_OFF(st6_x86_64, 0x80, 10); + EXPECT_OFF(st7_x86_64, 0x90, 10); + EXPECT_OFF(mm0_x86_64, 0x20, 8); + EXPECT_OFF(mm1_x86_64, 0x30, 8); + EXPECT_OFF(mm2_x86_64, 0x40, 8); + EXPECT_OFF(mm3_x86_64, 0x50, 8); + EXPECT_OFF(mm4_x86_64, 0x60, 8); + EXPECT_OFF(mm5_x86_64, 0x70, 8); + EXPECT_OFF(mm6_x86_64, 0x80, 8); + EXPECT_OFF(mm7_x86_64, 0x90, 8); + EXPECT_OFF(xmm0_x86_64, 0xA0, 16); + EXPECT_OFF(xmm1_x86_64, 0xB0, 16); + EXPECT_OFF(xmm2_x86_64, 0xC0, 16); + EXPECT_OFF(xmm3_x86_64, 0xD0, 16); + EXPECT_OFF(xmm4_x86_64, 0xE0, 16); + EXPECT_OFF(xmm5_x86_64, 0xF0, 16); + EXPECT_OFF(xmm6_x86_64, 0x100, 16); + EXPECT_OFF(xmm7_x86_64, 0x110, 16); + EXPECT_OFF(xmm8_x86_64, 0x120, 16); + EXPECT_OFF(xmm9_x86_64, 0x130, 16); + EXPECT_OFF(xmm10_x86_64, 0x140, 16); + EXPECT_OFF(xmm11_x86_64, 0x150, 16); + EXPECT_OFF(xmm12_x86_64, 0x160, 16); + EXPECT_OFF(xmm13_x86_64, 0x170, 16); + EXPECT_OFF(xmm14_x86_64, 0x180, 16); + EXPECT_OFF(xmm15_x86_64, 0x190, 16); + + base_offset = reg_ctx.GetRegisterInfo()[lldb_dr0_x86_64].byte_offset; + EXPECT_DBR_X86_64(0); + EXPECT_DBR_X86_64(1); + EXPECT_DBR_X86_64(2); + EXPECT_DBR_X86_64(3); + EXPECT_DBR_X86_64(4); + EXPECT_DBR_X86_64(5); + EXPECT_DBR_X86_64(6); + EXPECT_DBR_X86_64(7); +} + +#endif // defined(__x86_64__) + +#if defined(__i386__) || defined(__x86_64__) + +#define EXPECT_GPR_I386(regname) \ + EXPECT_THAT(GetRegParams(reg_ctx, lldb_##regname##_i386), \ + ::testing::Pair(offsetof(native_i386_regs, r_##regname), \ + sizeof(native_i386_regs::r_##regname))) +#define EXPECT_DBR_I386(num) \ + EXPECT_OFF(dr##num##_i386, offsetof(native_i386_dbregs, dr[num]), \ + sizeof(native_i386_dbregs::dr[num])) + +TEST(RegisterContextFreeBSDTest, i386) { + ArchSpec arch{"i686-unknown-freebsd"}; + RegisterContextFreeBSD_i386 reg_ctx{arch}; + +#if defined(__i386__) + using native_i386_regs = ::reg; + using native_i386_dbregs = ::dbreg; +#else + using native_i386_regs = ::reg32; + using native_i386_dbregs = ::dbreg32; +#endif + + EXPECT_GPR_I386(fs); + EXPECT_GPR_I386(es); + EXPECT_GPR_I386(ds); + EXPECT_GPR_I386(edi); + EXPECT_GPR_I386(esi); + EXPECT_GPR_I386(ebp); + EXPECT_GPR_I386(ebx); + EXPECT_GPR_I386(edx); + EXPECT_GPR_I386(ecx); + EXPECT_GPR_I386(eax); + EXPECT_GPR_I386(eip); + EXPECT_GPR_I386(cs); + EXPECT_GPR_I386(eflags); + EXPECT_GPR_I386(esp); + EXPECT_GPR_I386(ss); + EXPECT_GPR_I386(gs); + + // fctrl is the first FPR field, it is used to determine offset of the whole + // FPR struct + size_t base_offset = reg_ctx.GetRegisterInfo()[lldb_fctrl_i386].byte_offset; + + // assert against FXSAVE struct + EXPECT_OFF(fctrl_i386, 0x00, 2); + EXPECT_OFF(fstat_i386, 0x02, 2); + // TODO: This is a known bug, abridged ftag should is 8 bits in length. + EXPECT_OFF(ftag_i386, 0x04, 2); + EXPECT_OFF(fop_i386, 0x06, 2); + // NB: Technically fiseg/foseg are 16-bit long and the higher 16 bits + // are reserved. However, we use them to access/recombine 64-bit FIP/FDP. + EXPECT_OFF(fioff_i386, 0x08, 4); + EXPECT_OFF(fiseg_i386, 0x0C, 4); + EXPECT_OFF(fooff_i386, 0x10, 4); + EXPECT_OFF(foseg_i386, 0x14, 4); + EXPECT_OFF(mxcsr_i386, 0x18, 4); + EXPECT_OFF(mxcsrmask_i386, 0x1C, 4); + EXPECT_OFF(st0_i386, 0x20, 10); + EXPECT_OFF(st1_i386, 0x30, 10); + EXPECT_OFF(st2_i386, 0x40, 10); + EXPECT_OFF(st3_i386, 0x50, 10); + EXPECT_OFF(st4_i386, 0x60, 10); + EXPECT_OFF(st5_i386, 0x70, 10); + EXPECT_OFF(st6_i386, 0x80, 10); + EXPECT_OFF(st7_i386, 0x90, 10); + EXPECT_OFF(mm0_i386, 0x20, 8); + EXPECT_OFF(mm1_i386, 0x30, 8); + EXPECT_OFF(mm2_i386, 0x40, 8); + EXPECT_OFF(mm3_i386, 0x50, 8); + EXPECT_OFF(mm4_i386, 0x60, 8); + EXPECT_OFF(mm5_i386, 0x70, 8); + EXPECT_OFF(mm6_i386, 0x80, 8); + EXPECT_OFF(mm7_i386, 0x90, 8); + EXPECT_OFF(xmm0_i386, 0xA0, 16); + EXPECT_OFF(xmm1_i386, 0xB0, 16); + EXPECT_OFF(xmm2_i386, 0xC0, 16); + EXPECT_OFF(xmm3_i386, 0xD0, 16); + EXPECT_OFF(xmm4_i386, 0xE0, 16); + EXPECT_OFF(xmm5_i386, 0xF0, 16); + EXPECT_OFF(xmm6_i386, 0x100, 16); + EXPECT_OFF(xmm7_i386, 0x110, 16); + + base_offset = reg_ctx.GetRegisterInfo()[lldb_dr0_i386].byte_offset; + EXPECT_DBR_I386(0); + EXPECT_DBR_I386(1); + EXPECT_DBR_I386(2); + EXPECT_DBR_I386(3); + EXPECT_DBR_I386(4); + EXPECT_DBR_I386(5); + EXPECT_DBR_I386(6); + EXPECT_DBR_I386(7); +} + +#endif // defined(__i386__) || defined(__x86_64__) + +#if defined(__arm__) + +#define EXPECT_GPR_ARM(lldb_reg, fbsd_reg) \ + EXPECT_THAT(GetRegParams(reg_ctx, gpr_##lldb_reg##_arm), \ + ::testing::Pair(offsetof(reg, fbsd_reg), sizeof(reg::fbsd_reg))) +#define EXPECT_FPU_ARM(lldb_reg, fbsd_reg) \ + EXPECT_THAT(GetRegParams(reg_ctx, fpu_##lldb_reg##_arm), \ + ::testing::Pair(offsetof(vfp_state, fbsd_reg) + base_offset, \ + sizeof(vfp_state::fbsd_reg))) + +TEST(RegisterContextFreeBSDTest, arm) { + ArchSpec arch{"arm-unknown-freebsd"}; + RegisterInfoPOSIX_arm reg_ctx{arch}; + + EXPECT_GPR_ARM(r0, r[0]); + EXPECT_GPR_ARM(r1, r[1]); + EXPECT_GPR_ARM(r2, r[2]); + EXPECT_GPR_ARM(r3, r[3]); + EXPECT_GPR_ARM(r4, r[4]); + EXPECT_GPR_ARM(r5, r[5]); + EXPECT_GPR_ARM(r6, r[6]); + EXPECT_GPR_ARM(r7, r[7]); + EXPECT_GPR_ARM(r8, r[8]); + EXPECT_GPR_ARM(r9, r[9]); + EXPECT_GPR_ARM(r10, r[10]); + EXPECT_GPR_ARM(r11, r[11]); + EXPECT_GPR_ARM(r12, r[12]); + EXPECT_GPR_ARM(sp, r_sp); + EXPECT_GPR_ARM(lr, r_lr); + EXPECT_GPR_ARM(pc, r_pc); + EXPECT_GPR_ARM(cpsr, r_cpsr); + + size_t base_offset = reg_ctx.GetRegisterInfo()[fpu_d0_arm].byte_offset; + + EXPECT_FPU_ARM(d0, reg[0]); + EXPECT_FPU_ARM(d1, reg[1]); + EXPECT_FPU_ARM(d2, reg[2]); + EXPECT_FPU_ARM(d3, reg[3]); + EXPECT_FPU_ARM(d4, reg[4]); + EXPECT_FPU_ARM(d5, reg[5]); + EXPECT_FPU_ARM(d6, reg[6]); + EXPECT_FPU_ARM(d7, reg[7]); + EXPECT_FPU_ARM(d8, reg[8]); + EXPECT_FPU_ARM(d9, reg[9]); + EXPECT_FPU_ARM(d10, reg[10]); + EXPECT_FPU_ARM(d11, reg[11]); + EXPECT_FPU_ARM(d12, reg[12]); + EXPECT_FPU_ARM(d13, reg[13]); + EXPECT_FPU_ARM(d14, reg[14]); + EXPECT_FPU_ARM(d15, reg[15]); + EXPECT_FPU_ARM(d16, reg[16]); + EXPECT_FPU_ARM(d17, reg[17]); + EXPECT_FPU_ARM(d18, reg[18]); + EXPECT_FPU_ARM(d19, reg[19]); + EXPECT_FPU_ARM(d20, reg[20]); + EXPECT_FPU_ARM(d21, reg[21]); + EXPECT_FPU_ARM(d22, reg[22]); + EXPECT_FPU_ARM(d23, reg[23]); + EXPECT_FPU_ARM(d24, reg[24]); + EXPECT_FPU_ARM(d25, reg[25]); + EXPECT_FPU_ARM(d26, reg[26]); + EXPECT_FPU_ARM(d27, reg[27]); + EXPECT_FPU_ARM(d28, reg[28]); + EXPECT_FPU_ARM(d29, reg[29]); + EXPECT_FPU_ARM(d30, reg[30]); + EXPECT_FPU_ARM(d31, reg[31]); + EXPECT_FPU_ARM(fpscr, fpscr); +} + +#endif // defined(__arm__) + +#if defined(__aarch64__) + +#define EXPECT_GPR_ARM64(lldb_reg, fbsd_reg) \ + EXPECT_THAT(GetRegParams(reg_ctx, gpr_##lldb_reg##_arm64), \ + ::testing::Pair(offsetof(reg, fbsd_reg), sizeof(reg::fbsd_reg))) +#define EXPECT_FPU_ARM64(lldb_reg, fbsd_reg) \ + EXPECT_THAT(GetRegParams(reg_ctx, fpu_##lldb_reg##_arm64), \ + ::testing::Pair(offsetof(fpreg, fbsd_reg) + base_offset, \ + sizeof(fpreg::fbsd_reg))) + +TEST(RegisterContextFreeBSDTest, arm64) { + ArchSpec arch{"aarch64-unknown-freebsd"}; + RegisterInfoPOSIX_arm64 reg_ctx{arch}; + + EXPECT_GPR_ARM64(x0, x[0]); + EXPECT_GPR_ARM64(x1, x[1]); + EXPECT_GPR_ARM64(x2, x[2]); + EXPECT_GPR_ARM64(x3, x[3]); + EXPECT_GPR_ARM64(x4, x[4]); + EXPECT_GPR_ARM64(x5, x[5]); + EXPECT_GPR_ARM64(x6, x[6]); + EXPECT_GPR_ARM64(x7, x[7]); + EXPECT_GPR_ARM64(x8, x[8]); + EXPECT_GPR_ARM64(x9, x[9]); + EXPECT_GPR_ARM64(x10, x[10]); + EXPECT_GPR_ARM64(x11, x[11]); + EXPECT_GPR_ARM64(x12, x[12]); + EXPECT_GPR_ARM64(x13, x[13]); + EXPECT_GPR_ARM64(x14, x[14]); + EXPECT_GPR_ARM64(x15, x[15]); + EXPECT_GPR_ARM64(x16, x[16]); + EXPECT_GPR_ARM64(x17, x[17]); + EXPECT_GPR_ARM64(x18, x[18]); + EXPECT_GPR_ARM64(x19, x[19]); + EXPECT_GPR_ARM64(x20, x[20]); + EXPECT_GPR_ARM64(x21, x[21]); + EXPECT_GPR_ARM64(x22, x[22]); + EXPECT_GPR_ARM64(x23, x[23]); + EXPECT_GPR_ARM64(x24, x[24]); + EXPECT_GPR_ARM64(x25, x[25]); + EXPECT_GPR_ARM64(x26, x[26]); + EXPECT_GPR_ARM64(x27, x[27]); + EXPECT_GPR_ARM64(x28, x[28]); + EXPECT_GPR_ARM64(fp, x[29]); + EXPECT_GPR_ARM64(lr, lr); + EXPECT_GPR_ARM64(sp, sp); + EXPECT_GPR_ARM64(pc, elr); + EXPECT_GPR_ARM64(cpsr, spsr); + + size_t base_offset = reg_ctx.GetRegisterInfo()[fpu_v0_arm64].byte_offset; + + EXPECT_FPU_ARM64(v0, fp_q[0]); + EXPECT_FPU_ARM64(v1, fp_q[1]); + EXPECT_FPU_ARM64(v2, fp_q[2]); + EXPECT_FPU_ARM64(v3, fp_q[3]); + EXPECT_FPU_ARM64(v4, fp_q[4]); + EXPECT_FPU_ARM64(v5, fp_q[5]); + EXPECT_FPU_ARM64(v6, fp_q[6]); + EXPECT_FPU_ARM64(v7, fp_q[7]); + EXPECT_FPU_ARM64(v8, fp_q[8]); + EXPECT_FPU_ARM64(v9, fp_q[9]); + EXPECT_FPU_ARM64(v10, fp_q[10]); + EXPECT_FPU_ARM64(v11, fp_q[11]); + EXPECT_FPU_ARM64(v12, fp_q[12]); + EXPECT_FPU_ARM64(v13, fp_q[13]); + EXPECT_FPU_ARM64(v14, fp_q[14]); + EXPECT_FPU_ARM64(v15, fp_q[15]); + EXPECT_FPU_ARM64(v16, fp_q[16]); + EXPECT_FPU_ARM64(v17, fp_q[17]); + EXPECT_FPU_ARM64(v18, fp_q[18]); + EXPECT_FPU_ARM64(v19, fp_q[19]); + EXPECT_FPU_ARM64(v20, fp_q[20]); + EXPECT_FPU_ARM64(v21, fp_q[21]); + EXPECT_FPU_ARM64(v22, fp_q[22]); + EXPECT_FPU_ARM64(v23, fp_q[23]); + EXPECT_FPU_ARM64(v24, fp_q[24]); + EXPECT_FPU_ARM64(v25, fp_q[25]); + EXPECT_FPU_ARM64(v26, fp_q[26]); + EXPECT_FPU_ARM64(v27, fp_q[27]); + EXPECT_FPU_ARM64(v28, fp_q[28]); + EXPECT_FPU_ARM64(v29, fp_q[29]); + EXPECT_FPU_ARM64(v30, fp_q[30]); + EXPECT_FPU_ARM64(v31, fp_q[31]); + EXPECT_FPU_ARM64(fpsr, fp_sr); + EXPECT_FPU_ARM64(fpcr, fp_cr); +} + +#endif // defined(__aarch64__) + +#if defined(__mips64__) + +#define EXPECT_GPR_MIPS64(lldb_reg, fbsd_regno) \ + EXPECT_THAT(GetRegParams(reg_ctx, gpr_##lldb_reg##_mips64), \ + ::testing::Pair(offsetof(reg, r_regs[fbsd_regno]), \ + sizeof(reg::r_regs[fbsd_regno]))) + +TEST(RegisterContextFreeBSDTest, mips64) { + ArchSpec arch{"mips64-unknown-freebsd"}; + RegisterContextFreeBSD_mips64 reg_ctx{arch}; + + // we can not use aliases from because macros defined + // there are not namespaced and collide a lot, e.g. 'A1' + + EXPECT_GPR_MIPS64(zero, 0); + EXPECT_GPR_MIPS64(r1, 1); + EXPECT_GPR_MIPS64(r2, 2); + EXPECT_GPR_MIPS64(r3, 3); + EXPECT_GPR_MIPS64(r4, 4); + EXPECT_GPR_MIPS64(r5, 5); + EXPECT_GPR_MIPS64(r6, 6); + EXPECT_GPR_MIPS64(r7, 7); + EXPECT_GPR_MIPS64(r8, 8); + EXPECT_GPR_MIPS64(r9, 9); + EXPECT_GPR_MIPS64(r10, 10); + EXPECT_GPR_MIPS64(r11, 11); + EXPECT_GPR_MIPS64(r12, 12); + EXPECT_GPR_MIPS64(r13, 13); + EXPECT_GPR_MIPS64(r14, 14); + EXPECT_GPR_MIPS64(r15, 15); + EXPECT_GPR_MIPS64(r16, 16); + EXPECT_GPR_MIPS64(r17, 17); + EXPECT_GPR_MIPS64(r18, 18); + EXPECT_GPR_MIPS64(r19, 19); + EXPECT_GPR_MIPS64(r20, 20); + EXPECT_GPR_MIPS64(r21, 21); + EXPECT_GPR_MIPS64(r22, 22); + EXPECT_GPR_MIPS64(r23, 23); + EXPECT_GPR_MIPS64(r24, 24); + EXPECT_GPR_MIPS64(r25, 25); + EXPECT_GPR_MIPS64(r26, 26); + EXPECT_GPR_MIPS64(r27, 27); + EXPECT_GPR_MIPS64(gp, 28); + EXPECT_GPR_MIPS64(sp, 29); + EXPECT_GPR_MIPS64(r30, 30); + EXPECT_GPR_MIPS64(ra, 31); + EXPECT_GPR_MIPS64(sr, 32); + EXPECT_GPR_MIPS64(mullo, 33); + EXPECT_GPR_MIPS64(mulhi, 34); + EXPECT_GPR_MIPS64(badvaddr, 35); + EXPECT_GPR_MIPS64(cause, 36); + EXPECT_GPR_MIPS64(pc, 37); + EXPECT_GPR_MIPS64(ic, 38); + EXPECT_GPR_MIPS64(dummy, 39); +} + +#endif // defined(__mips64__) + +#if defined(__powerpc__) + +#define EXPECT_GPR_PPC(lldb_reg, fbsd_reg) \ + EXPECT_THAT(GetRegParams(reg_ctx, gpr_##lldb_reg##_powerpc), \ + ::testing::Pair(offsetof(reg, fbsd_reg), sizeof(reg::fbsd_reg))) +#define EXPECT_FPU_PPC(lldb_reg, fbsd_reg) \ + EXPECT_THAT(GetRegParams(reg_ctx, fpr_##lldb_reg##_powerpc), \ + ::testing::Pair(offsetof(fpreg, fbsd_reg) + base_offset, \ + sizeof(fpreg::fbsd_reg))) + +TEST(RegisterContextFreeBSDTest, powerpc32) { + ArchSpec arch{"powerpc-unknown-freebsd"}; + RegisterContextFreeBSD_powerpc32 reg_ctx{arch}; + + EXPECT_GPR_PPC(r0, fixreg[0]); + EXPECT_GPR_PPC(r1, fixreg[1]); + EXPECT_GPR_PPC(r2, fixreg[2]); + EXPECT_GPR_PPC(r3, fixreg[3]); + EXPECT_GPR_PPC(r4, fixreg[4]); + EXPECT_GPR_PPC(r5, fixreg[5]); + EXPECT_GPR_PPC(r6, fixreg[6]); + EXPECT_GPR_PPC(r7, fixreg[7]); + EXPECT_GPR_PPC(r8, fixreg[8]); + EXPECT_GPR_PPC(r9, fixreg[9]); + EXPECT_GPR_PPC(r10, fixreg[10]); + EXPECT_GPR_PPC(r11, fixreg[11]); + EXPECT_GPR_PPC(r12, fixreg[12]); + EXPECT_GPR_PPC(r13, fixreg[13]); + EXPECT_GPR_PPC(r14, fixreg[14]); + EXPECT_GPR_PPC(r15, fixreg[15]); + EXPECT_GPR_PPC(r16, fixreg[16]); + EXPECT_GPR_PPC(r17, fixreg[17]); + EXPECT_GPR_PPC(r18, fixreg[18]); + EXPECT_GPR_PPC(r19, fixreg[19]); + EXPECT_GPR_PPC(r20, fixreg[20]); + EXPECT_GPR_PPC(r21, fixreg[21]); + EXPECT_GPR_PPC(r22, fixreg[22]); + EXPECT_GPR_PPC(r23, fixreg[23]); + EXPECT_GPR_PPC(r24, fixreg[24]); + EXPECT_GPR_PPC(r25, fixreg[25]); + EXPECT_GPR_PPC(r26, fixreg[26]); + EXPECT_GPR_PPC(r27, fixreg[27]); + EXPECT_GPR_PPC(r28, fixreg[28]); + EXPECT_GPR_PPC(r29, fixreg[29]); + EXPECT_GPR_PPC(r30, fixreg[30]); + EXPECT_GPR_PPC(r31, fixreg[31]); + EXPECT_GPR_PPC(lr, lr); + EXPECT_GPR_PPC(cr, cr); + EXPECT_GPR_PPC(xer, xer); + EXPECT_GPR_PPC(ctr, ctr); + EXPECT_GPR_PPC(pc, pc); + + size_t base_offset = reg_ctx.GetRegisterInfo()[fpr_f0_powerpc].byte_offset; + + EXPECT_FPU_PPC(f0, fpreg[0]); + EXPECT_FPU_PPC(f1, fpreg[1]); + EXPECT_FPU_PPC(f2, fpreg[2]); + EXPECT_FPU_PPC(f3, fpreg[3]); + EXPECT_FPU_PPC(f4, fpreg[4]); + EXPECT_FPU_PPC(f5, fpreg[5]); + EXPECT_FPU_PPC(f6, fpreg[6]); + EXPECT_FPU_PPC(f7, fpreg[7]); + EXPECT_FPU_PPC(f8, fpreg[8]); + EXPECT_FPU_PPC(f9, fpreg[9]); + EXPECT_FPU_PPC(f10, fpreg[10]); + EXPECT_FPU_PPC(f11, fpreg[11]); + EXPECT_FPU_PPC(f12, fpreg[12]); + EXPECT_FPU_PPC(f13, fpreg[13]); + EXPECT_FPU_PPC(f14, fpreg[14]); + EXPECT_FPU_PPC(f15, fpreg[15]); + EXPECT_FPU_PPC(f16, fpreg[16]); + EXPECT_FPU_PPC(f17, fpreg[17]); + EXPECT_FPU_PPC(f18, fpreg[18]); + EXPECT_FPU_PPC(f19, fpreg[19]); + EXPECT_FPU_PPC(f20, fpreg[20]); + EXPECT_FPU_PPC(f21, fpreg[21]); + EXPECT_FPU_PPC(f22, fpreg[22]); + EXPECT_FPU_PPC(f23, fpreg[23]); + EXPECT_FPU_PPC(f24, fpreg[24]); + EXPECT_FPU_PPC(f25, fpreg[25]); + EXPECT_FPU_PPC(f26, fpreg[26]); + EXPECT_FPU_PPC(f27, fpreg[27]); + EXPECT_FPU_PPC(f28, fpreg[28]); + EXPECT_FPU_PPC(f29, fpreg[29]); + EXPECT_FPU_PPC(f30, fpreg[30]); + EXPECT_FPU_PPC(f31, fpreg[31]); + EXPECT_FPU_PPC(fpscr, fpscr); +} + +#endif // defined(__powerpc__) diff --git a/gnu/llvm/lldb/unittests/Process/Utility/RegisterContextNetBSDTest_i386.cpp b/gnu/llvm/lldb/unittests/Process/Utility/RegisterContextNetBSDTest_i386.cpp new file mode 100644 index 00000000000..07e09d34d19 --- /dev/null +++ b/gnu/llvm/lldb/unittests/Process/Utility/RegisterContextNetBSDTest_i386.cpp @@ -0,0 +1,118 @@ +//===-- RegisterContextNetBSDTest_i386.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(__i386__) || defined(__x86_64__) + +// clang-format off +#include +#include +// clang-format on + +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +#include "Plugins/Process/Utility/lldb-x86-register-enums.h" +#include "Plugins/Process/Utility/RegisterContextNetBSD_i386.h" + +using namespace lldb; +using namespace lldb_private; + +static std::pair GetRegParams(RegisterInfoInterface &ctx, + uint32_t reg) { + const RegisterInfo &info = ctx.GetRegisterInfo()[reg]; + return {info.byte_offset, info.byte_size}; +} + +#define EXPECT_OFF(regname, offset, size) \ + EXPECT_THAT(GetRegParams(reg_ctx, lldb_##regname), \ + ::testing::Pair(offset + base_offset, size)) + +#define EXPECT_GPR_I386(regname) \ + EXPECT_THAT(GetRegParams(reg_ctx, lldb_##regname##_i386), \ + ::testing::Pair(offsetof(reg, r_##regname), \ + sizeof(reg::r_##regname))) +#define EXPECT_DBR_I386(num) \ + EXPECT_OFF(dr##num##_i386, offsetof(dbreg, dr[num]), \ + sizeof(dbreg::dr[num])) + +TEST(RegisterContextNetBSDTest, i386) { + ArchSpec arch{"i686-unknown-netbsd"}; + RegisterContextNetBSD_i386 reg_ctx{arch}; + + EXPECT_GPR_I386(eax); + EXPECT_GPR_I386(ecx); + EXPECT_GPR_I386(edx); + EXPECT_GPR_I386(ebx); + EXPECT_GPR_I386(esp); + EXPECT_GPR_I386(ebp); + EXPECT_GPR_I386(esi); + EXPECT_GPR_I386(edi); + EXPECT_GPR_I386(eip); + EXPECT_GPR_I386(eflags); + EXPECT_GPR_I386(cs); + EXPECT_GPR_I386(ss); + EXPECT_GPR_I386(ds); + EXPECT_GPR_I386(es); + EXPECT_GPR_I386(fs); + EXPECT_GPR_I386(gs); + + // fctrl is the first FPR field, it is used to determine offset of the whole + // FPR struct + size_t base_offset = reg_ctx.GetRegisterInfo()[lldb_fctrl_i386].byte_offset; + + // assert against FXSAVE struct + EXPECT_OFF(fctrl_i386, 0x00, 2); + EXPECT_OFF(fstat_i386, 0x02, 2); + // TODO: This is a known bug, abridged ftag should is 8 bits in length. + EXPECT_OFF(ftag_i386, 0x04, 2); + EXPECT_OFF(fop_i386, 0x06, 2); + // NB: Technically fiseg/foseg are 16-bit long and the higher 16 bits + // are reserved. However, we use them to access/recombine 64-bit FIP/FDP. + EXPECT_OFF(fioff_i386, 0x08, 4); + EXPECT_OFF(fiseg_i386, 0x0C, 4); + EXPECT_OFF(fooff_i386, 0x10, 4); + EXPECT_OFF(foseg_i386, 0x14, 4); + EXPECT_OFF(mxcsr_i386, 0x18, 4); + EXPECT_OFF(mxcsrmask_i386, 0x1C, 4); + EXPECT_OFF(st0_i386, 0x20, 10); + EXPECT_OFF(st1_i386, 0x30, 10); + EXPECT_OFF(st2_i386, 0x40, 10); + EXPECT_OFF(st3_i386, 0x50, 10); + EXPECT_OFF(st4_i386, 0x60, 10); + EXPECT_OFF(st5_i386, 0x70, 10); + EXPECT_OFF(st6_i386, 0x80, 10); + EXPECT_OFF(st7_i386, 0x90, 10); + EXPECT_OFF(mm0_i386, 0x20, 8); + EXPECT_OFF(mm1_i386, 0x30, 8); + EXPECT_OFF(mm2_i386, 0x40, 8); + EXPECT_OFF(mm3_i386, 0x50, 8); + EXPECT_OFF(mm4_i386, 0x60, 8); + EXPECT_OFF(mm5_i386, 0x70, 8); + EXPECT_OFF(mm6_i386, 0x80, 8); + EXPECT_OFF(mm7_i386, 0x90, 8); + EXPECT_OFF(xmm0_i386, 0xA0, 16); + EXPECT_OFF(xmm1_i386, 0xB0, 16); + EXPECT_OFF(xmm2_i386, 0xC0, 16); + EXPECT_OFF(xmm3_i386, 0xD0, 16); + EXPECT_OFF(xmm4_i386, 0xE0, 16); + EXPECT_OFF(xmm5_i386, 0xF0, 16); + EXPECT_OFF(xmm6_i386, 0x100, 16); + EXPECT_OFF(xmm7_i386, 0x110, 16); + + base_offset = reg_ctx.GetRegisterInfo()[lldb_dr0_i386].byte_offset; + EXPECT_DBR_I386(0); + EXPECT_DBR_I386(1); + EXPECT_DBR_I386(2); + EXPECT_DBR_I386(3); + EXPECT_DBR_I386(4); + EXPECT_DBR_I386(5); + EXPECT_DBR_I386(6); + EXPECT_DBR_I386(7); +} + +#endif // defined(__i386__) || defined(__x86_64__) diff --git a/gnu/llvm/lldb/unittests/Process/Utility/RegisterContextNetBSDTest_x86_64.cpp b/gnu/llvm/lldb/unittests/Process/Utility/RegisterContextNetBSDTest_x86_64.cpp new file mode 100644 index 00000000000..ac24c32b0d0 --- /dev/null +++ b/gnu/llvm/lldb/unittests/Process/Utility/RegisterContextNetBSDTest_x86_64.cpp @@ -0,0 +1,139 @@ +//===-- RegisterContextNetBSDTest_x86_64.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(__x86_64__) + +// clang-format off +#include +#include +// clang-format on + +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +#include "Plugins/Process/Utility/lldb-x86-register-enums.h" +#include "Plugins/Process/Utility/RegisterContextNetBSD_i386.h" +#include "Plugins/Process/Utility/RegisterContextNetBSD_x86_64.h" + +using namespace lldb; +using namespace lldb_private; + +static std::pair GetRegParams(RegisterInfoInterface &ctx, + uint32_t reg) { + const RegisterInfo &info = ctx.GetRegisterInfo()[reg]; + return {info.byte_offset, info.byte_size}; +} + +#define EXPECT_OFF(regname, offset, size) \ + EXPECT_THAT(GetRegParams(reg_ctx, lldb_##regname), \ + ::testing::Pair(offset + base_offset, size)) + +#define EXPECT_GPR_X86_64(regname, regconst) \ + EXPECT_THAT( \ + GetRegParams(reg_ctx, lldb_##regname##_x86_64), \ + ::testing::Pair(offsetof(reg, regs[regconst]), \ + sizeof(reg::regs[regconst]))) +#define EXPECT_DBR_X86_64(num) \ + EXPECT_OFF(dr##num##_x86_64, offsetof(dbreg, dr[num]), sizeof(dbreg::dr[num])) + +TEST(RegisterContextNetBSDTest, x86_64) { + ArchSpec arch{"x86_64-unknown-netbsd"}; + RegisterContextNetBSD_x86_64 reg_ctx{arch}; + + EXPECT_GPR_X86_64(rdi, _REG_RDI); + EXPECT_GPR_X86_64(rsi, _REG_RSI); + EXPECT_GPR_X86_64(rdx, _REG_RDX); + EXPECT_GPR_X86_64(rcx, _REG_RCX); + EXPECT_GPR_X86_64(r8, _REG_R8); + EXPECT_GPR_X86_64(r9, _REG_R9); + EXPECT_GPR_X86_64(r10, _REG_R10); + EXPECT_GPR_X86_64(r11, _REG_R11); + EXPECT_GPR_X86_64(r12, _REG_R12); + EXPECT_GPR_X86_64(r13, _REG_R13); + EXPECT_GPR_X86_64(r14, _REG_R14); + EXPECT_GPR_X86_64(r15, _REG_R15); + EXPECT_GPR_X86_64(rbp, _REG_RBP); + EXPECT_GPR_X86_64(rbx, _REG_RBX); + EXPECT_GPR_X86_64(rax, _REG_RAX); + EXPECT_GPR_X86_64(gs, _REG_GS); + EXPECT_GPR_X86_64(fs, _REG_FS); + EXPECT_GPR_X86_64(es, _REG_ES); + EXPECT_GPR_X86_64(ds, _REG_DS); + EXPECT_GPR_X86_64(rip, _REG_RIP); + EXPECT_GPR_X86_64(cs, _REG_CS); + EXPECT_GPR_X86_64(rflags, _REG_RFLAGS); + EXPECT_GPR_X86_64(rsp, _REG_RSP); + EXPECT_GPR_X86_64(ss, _REG_SS); + + // fctrl is the first FPR field, it is used to determine offset of the whole + // FPR struct + size_t base_offset = reg_ctx.GetRegisterInfo()[lldb_fctrl_x86_64].byte_offset; + + // assert against FXSAVE struct + EXPECT_OFF(fctrl_x86_64, 0x00, 2); + EXPECT_OFF(fstat_x86_64, 0x02, 2); + // TODO: This is a known bug, abridged ftag should is 8 bits in length. + EXPECT_OFF(ftag_x86_64, 0x04, 2); + EXPECT_OFF(fop_x86_64, 0x06, 2); + // NB: Technically fiseg/foseg are 16-bit long and the higher 16 bits + // are reserved. However, LLDB defines them to be 32-bit long for backwards + // compatibility, as they were used to reconstruct FIP/FDP before explicit + // register entries for them were added. Also, this is still how GDB does it. + EXPECT_OFF(fioff_x86_64, 0x08, 4); + EXPECT_OFF(fiseg_x86_64, 0x0C, 4); + EXPECT_OFF(fip_x86_64, 0x08, 8); + EXPECT_OFF(fooff_x86_64, 0x10, 4); + EXPECT_OFF(foseg_x86_64, 0x14, 4); + EXPECT_OFF(fdp_x86_64, 0x10, 8); + EXPECT_OFF(mxcsr_x86_64, 0x18, 4); + EXPECT_OFF(mxcsrmask_x86_64, 0x1C, 4); + EXPECT_OFF(st0_x86_64, 0x20, 10); + EXPECT_OFF(st1_x86_64, 0x30, 10); + EXPECT_OFF(st2_x86_64, 0x40, 10); + EXPECT_OFF(st3_x86_64, 0x50, 10); + EXPECT_OFF(st4_x86_64, 0x60, 10); + EXPECT_OFF(st5_x86_64, 0x70, 10); + EXPECT_OFF(st6_x86_64, 0x80, 10); + EXPECT_OFF(st7_x86_64, 0x90, 10); + EXPECT_OFF(mm0_x86_64, 0x20, 8); + EXPECT_OFF(mm1_x86_64, 0x30, 8); + EXPECT_OFF(mm2_x86_64, 0x40, 8); + EXPECT_OFF(mm3_x86_64, 0x50, 8); + EXPECT_OFF(mm4_x86_64, 0x60, 8); + EXPECT_OFF(mm5_x86_64, 0x70, 8); + EXPECT_OFF(mm6_x86_64, 0x80, 8); + EXPECT_OFF(mm7_x86_64, 0x90, 8); + EXPECT_OFF(xmm0_x86_64, 0xA0, 16); + EXPECT_OFF(xmm1_x86_64, 0xB0, 16); + EXPECT_OFF(xmm2_x86_64, 0xC0, 16); + EXPECT_OFF(xmm3_x86_64, 0xD0, 16); + EXPECT_OFF(xmm4_x86_64, 0xE0, 16); + EXPECT_OFF(xmm5_x86_64, 0xF0, 16); + EXPECT_OFF(xmm6_x86_64, 0x100, 16); + EXPECT_OFF(xmm7_x86_64, 0x110, 16); + EXPECT_OFF(xmm8_x86_64, 0x120, 16); + EXPECT_OFF(xmm9_x86_64, 0x130, 16); + EXPECT_OFF(xmm10_x86_64, 0x140, 16); + EXPECT_OFF(xmm11_x86_64, 0x150, 16); + EXPECT_OFF(xmm12_x86_64, 0x160, 16); + EXPECT_OFF(xmm13_x86_64, 0x170, 16); + EXPECT_OFF(xmm14_x86_64, 0x180, 16); + EXPECT_OFF(xmm15_x86_64, 0x190, 16); + + base_offset = reg_ctx.GetRegisterInfo()[lldb_dr0_x86_64].byte_offset; + EXPECT_DBR_X86_64(0); + EXPECT_DBR_X86_64(1); + EXPECT_DBR_X86_64(2); + EXPECT_DBR_X86_64(3); + EXPECT_DBR_X86_64(4); + EXPECT_DBR_X86_64(5); + EXPECT_DBR_X86_64(6); + EXPECT_DBR_X86_64(7); +} + +#endif // defined(__x86_64__) diff --git a/gnu/llvm/lldb/unittests/Process/Utility/RegisterContextTest.cpp b/gnu/llvm/lldb/unittests/Process/Utility/RegisterContextTest.cpp new file mode 100644 index 00000000000..f0aa6076d8f --- /dev/null +++ b/gnu/llvm/lldb/unittests/Process/Utility/RegisterContextTest.cpp @@ -0,0 +1,73 @@ +//===-- RegisterContextTest.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 "gtest/gtest.h" + +#include "Plugins/Process/Utility/RegisterContext_x86.h" + +#include "llvm/ADT/STLExtras.h" +#include "llvm/Support/FormatVariadic.h" + +#include + +using namespace lldb_private; + +struct TagWordTestVector { + uint16_t sw; + uint16_t tw; + uint8_t tw_abridged; + int st_reg_num; +}; + +constexpr MMSReg st_from_comp(uint64_t mantissa, uint16_t sign_exp) { + MMSReg ret = {}; + ret.comp.mantissa = mantissa; + ret.comp.sign_exp = sign_exp; + return ret; +} + +const std::array st_regs = { + st_from_comp(0x8000000000000000, 0x4000), // +2.0 + st_from_comp(0x3f00000000000000, 0x0000), // 1.654785e-4932 + st_from_comp(0x0000000000000000, 0x0000), // +0 + st_from_comp(0x0000000000000000, 0x8000), // -0 + st_from_comp(0x8000000000000000, 0x7fff), // +inf + st_from_comp(0x8000000000000000, 0xffff), // -inf + st_from_comp(0xc000000000000000, 0xffff), // nan + st_from_comp(0x8000000000000000, 0xc000), // -2.0 +}; + +const std::array tag_word_test_vectors{ + TagWordTestVector{0x3800, 0x3fff, 0x80, 1}, + TagWordTestVector{0x3000, 0x2fff, 0xc0, 2}, + TagWordTestVector{0x2800, 0x27ff, 0xe0, 3}, + TagWordTestVector{0x2000, 0x25ff, 0xf0, 4}, + TagWordTestVector{0x1800, 0x25bf, 0xf8, 5}, + TagWordTestVector{0x1000, 0x25af, 0xfc, 6}, + TagWordTestVector{0x0800, 0x25ab, 0xfe, 7}, + TagWordTestVector{0x0000, 0x25a8, 0xff, 8}, +}; + +TEST(RegisterContext_x86Test, AbridgedToFullTagWord) { + for (const auto &x : llvm::enumerate(tag_word_test_vectors)) { + SCOPED_TRACE(llvm::formatv("tag_word_test_vectors[{0}]", x.index())); + std::array test_regs; + for (int i = 0; i < x.value().st_reg_num; ++i) + test_regs[i] = st_regs[x.value().st_reg_num - i - 1]; + EXPECT_EQ( + AbridgedToFullTagWord(x.value().tw_abridged, x.value().sw, test_regs), + x.value().tw); + } +} + +TEST(RegisterContext_x86Test, FullToAbridgedTagWord) { + for (const auto &x : llvm::enumerate(tag_word_test_vectors)) { + SCOPED_TRACE(llvm::formatv("tag_word_test_vectors[{0}]", x.index())); + EXPECT_EQ(FullToAbridgedTagWord(x.value().tw), x.value().tw_abridged); + } +} diff --git a/gnu/llvm/lldb/unittests/Process/gdb-remote/CMakeLists.txt b/gnu/llvm/lldb/unittests/Process/gdb-remote/CMakeLists.txt index abb30e022e4..7988fff3e70 100644 --- a/gnu/llvm/lldb/unittests/Process/gdb-remote/CMakeLists.txt +++ b/gnu/llvm/lldb/unittests/Process/gdb-remote/CMakeLists.txt @@ -4,6 +4,7 @@ add_lldb_unittest(ProcessGdbRemoteTests GDBRemoteCommunicationServerTest.cpp GDBRemoteCommunicationTest.cpp GDBRemoteTestUtils.cpp + PortMapTest.cpp LINK_LIBS lldbCore diff --git a/gnu/llvm/lldb/unittests/Process/gdb-remote/GDBRemoteClientBaseTest.cpp b/gnu/llvm/lldb/unittests/Process/gdb-remote/GDBRemoteClientBaseTest.cpp index 5bbcfdff473..eb4fd29b4df 100644 --- a/gnu/llvm/lldb/unittests/Process/gdb-remote/GDBRemoteClientBaseTest.cpp +++ b/gnu/llvm/lldb/unittests/Process/gdb-remote/GDBRemoteClientBaseTest.cpp @@ -55,6 +55,8 @@ public: } protected: + // We don't have a process to get the interrupt timeout from, so make one up. + static std::chrono::seconds g_timeout; TestClient client; MockServer server; MockDelegate delegate; @@ -62,7 +64,8 @@ protected: StateType SendCPacket(StringExtractorGDBRemote &response) { return client.SendContinuePacketAndWaitForResponse(delegate, LinuxSignals(), - "c", response); + "c", g_timeout, + response); } void WaitForRunEvent() { @@ -72,6 +75,8 @@ protected: } }; +std::chrono::seconds GDBRemoteClientBaseTest::g_timeout(10); + } // end anonymous namespace TEST_F(GDBRemoteClientBaseTest, SendContinueAndWait) { @@ -103,7 +108,7 @@ TEST_F(GDBRemoteClientBaseTest, SendContinueAndAsyncSignal) { StringExtractorGDBRemote continue_response, response; // SendAsyncSignal should do nothing when we are not running. - ASSERT_FALSE(client.SendAsyncSignal(0x47)); + ASSERT_FALSE(client.SendAsyncSignal(0x47, g_timeout)); // Continue. After the run packet is sent, send an async signal. std::future continue_state = std::async( @@ -112,8 +117,9 @@ TEST_F(GDBRemoteClientBaseTest, SendContinueAndAsyncSignal) { ASSERT_EQ("c", response.GetStringRef()); WaitForRunEvent(); - std::future async_result = std::async( - std::launch::async, [&] { return client.SendAsyncSignal(0x47); }); + std::future async_result = std::async(std::launch::async, [&] { + return client.SendAsyncSignal(0x47, g_timeout); + }); // First we'll get interrupted. ASSERT_EQ(PacketResult::Success, server.GetPacket(response)); @@ -133,7 +139,6 @@ TEST_F(GDBRemoteClientBaseTest, SendContinueAndAsyncSignal) { TEST_F(GDBRemoteClientBaseTest, SendContinueAndAsyncPacket) { StringExtractorGDBRemote continue_response, async_response, response; - const bool send_async = true; // Continue. After the run packet is sent, send an async packet. std::future continue_state = std::async( @@ -143,13 +148,12 @@ TEST_F(GDBRemoteClientBaseTest, SendContinueAndAsyncPacket) { WaitForRunEvent(); // Sending without async enabled should fail. - ASSERT_EQ( - PacketResult::ErrorSendFailed, - client.SendPacketAndWaitForResponse("qTest1", response, !send_async)); + ASSERT_EQ(PacketResult::ErrorSendFailed, + client.SendPacketAndWaitForResponse("qTest1", response)); std::future async_result = std::async(std::launch::async, [&] { return client.SendPacketAndWaitForResponse("qTest2", async_response, - send_async); + g_timeout); }); // First we'll get interrupted. @@ -178,7 +182,7 @@ TEST_F(GDBRemoteClientBaseTest, SendContinueAndInterrupt) { StringExtractorGDBRemote continue_response, response; // Interrupt should do nothing when we're not running. - ASSERT_FALSE(client.Interrupt()); + ASSERT_FALSE(client.Interrupt(g_timeout)); // Continue. After the run packet is sent, send an interrupt. std::future continue_state = std::async( @@ -187,8 +191,8 @@ TEST_F(GDBRemoteClientBaseTest, SendContinueAndInterrupt) { ASSERT_EQ("c", response.GetStringRef()); WaitForRunEvent(); - std::future async_result = - std::async(std::launch::async, [&] { return client.Interrupt(); }); + std::future async_result = std::async( + std::launch::async, [&] { return client.Interrupt(g_timeout); }); // We get interrupted. ASSERT_EQ(PacketResult::Success, server.GetPacket(response)); @@ -211,8 +215,8 @@ TEST_F(GDBRemoteClientBaseTest, SendContinueAndLateInterrupt) { ASSERT_EQ("c", response.GetStringRef()); WaitForRunEvent(); - std::future async_result = - std::async(std::launch::async, [&] { return client.Interrupt(); }); + std::future async_result = std::async( + std::launch::async, [&] { return client.Interrupt(g_timeout); }); // However, the target stops due to a different reason than the original // interrupt. @@ -233,10 +237,9 @@ TEST_F(GDBRemoteClientBaseTest, SendContinueAndLateInterrupt) { TEST_F(GDBRemoteClientBaseTest, SendContinueAndInterrupt2PacketBug) { StringExtractorGDBRemote continue_response, async_response, response; - const bool send_async = true; // Interrupt should do nothing when we're not running. - ASSERT_FALSE(client.Interrupt()); + ASSERT_FALSE(client.Interrupt(g_timeout)); // Continue. After the run packet is sent, send an async signal. std::future continue_state = std::async( @@ -245,8 +248,8 @@ TEST_F(GDBRemoteClientBaseTest, SendContinueAndInterrupt2PacketBug) { ASSERT_EQ("c", response.GetStringRef()); WaitForRunEvent(); - std::future interrupt_result = - std::async(std::launch::async, [&] { return client.Interrupt(); }); + std::future interrupt_result = std::async( + std::launch::async, [&] { return client.Interrupt(g_timeout); }); // We get interrupted. We'll send two packets to simulate a buggy stub. ASSERT_EQ(PacketResult::Success, server.GetPacket(response)); @@ -261,8 +264,7 @@ TEST_F(GDBRemoteClientBaseTest, SendContinueAndInterrupt2PacketBug) { // Packet stream should remain synchronized. std::future send_result = std::async(std::launch::async, [&] { - return client.SendPacketAndWaitForResponse("qTest", async_response, - !send_async); + return client.SendPacketAndWaitForResponse("qTest", async_response); }); ASSERT_EQ(PacketResult::Success, server.GetPacket(response)); ASSERT_EQ("qTest", response.GetStringRef()); @@ -328,8 +330,8 @@ TEST_F(GDBRemoteClientBaseTest, InterruptNoResponse) { ASSERT_EQ("c", response.GetStringRef()); WaitForRunEvent(); - std::future async_result = - std::async(std::launch::async, [&] { return client.Interrupt(); }); + std::future async_result = std::async( + std::launch::async, [&] { return client.Interrupt(g_timeout); }); // We get interrupted, but we don't send a stop packet. ASSERT_EQ(PacketResult::Success, server.GetPacket(response)); @@ -352,7 +354,7 @@ TEST_F(GDBRemoteClientBaseTest, SendPacketAndReceiveResponseWithOutputSupport) { ASSERT_EQ(PacketResult::Success, server.SendPacket("OK")); PacketResult result = client.SendPacketAndReceiveResponseWithOutputSupport( - "qRcmd,test", response, true, + "qRcmd,test", response, g_timeout, [&command_output](llvm::StringRef output) { command_output << output; }); ASSERT_EQ(PacketResult::Success, result); diff --git a/gnu/llvm/lldb/unittests/Process/gdb-remote/GDBRemoteCommunicationClientTest.cpp b/gnu/llvm/lldb/unittests/Process/gdb-remote/GDBRemoteCommunicationClientTest.cpp index 6fba1cbb53b..d15b85204b5 100644 --- a/gnu/llvm/lldb/unittests/Process/gdb-remote/GDBRemoteCommunicationClientTest.cpp +++ b/gnu/llvm/lldb/unittests/Process/gdb-remote/GDBRemoteCommunicationClientTest.cpp @@ -12,12 +12,12 @@ #include "lldb/Target/MemoryRegionInfo.h" #include "lldb/Utility/DataBuffer.h" #include "lldb/Utility/StructuredData.h" -#include "lldb/Utility/TraceOptions.h" #include "lldb/lldb-enumerations.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/Testing/Support/Error.h" #include "gmock/gmock.h" #include +#include using namespace lldb_private::process_gdb_remote; using namespace lldb_private; @@ -343,6 +343,25 @@ TEST_F(GDBRemoteCommunicationClientTest, GetMemoryRegionInfo) { EXPECT_EQ(MemoryRegionInfo::eNo, region_info.GetWritable()); EXPECT_EQ(MemoryRegionInfo::eYes, region_info.GetExecutable()); EXPECT_EQ("/foo/bar.so", region_info.GetName().GetStringRef()); + EXPECT_EQ(MemoryRegionInfo::eDontKnow, region_info.GetMemoryTagged()); + + result = std::async(std::launch::async, [&] { + return client.GetMemoryRegionInfo(addr, region_info); + }); + + HandlePacket(server, "qMemoryRegionInfo:a000", + "start:a000;size:2000;flags:;"); + EXPECT_TRUE(result.get().Success()); + EXPECT_EQ(MemoryRegionInfo::eNo, region_info.GetMemoryTagged()); + + result = std::async(std::launch::async, [&] { + return client.GetMemoryRegionInfo(addr, region_info); + }); + + HandlePacket(server, "qMemoryRegionInfo:a000", + "start:a000;size:2000;flags: mt zz mt ;"); + EXPECT_TRUE(result.get().Success()); + EXPECT_EQ(MemoryRegionInfo::eYes, region_info.GetMemoryTagged()); } TEST_F(GDBRemoteCommunicationClientTest, GetMemoryRegionInfoInvalidResponse) { @@ -362,195 +381,65 @@ TEST_F(GDBRemoteCommunicationClientTest, GetMemoryRegionInfoInvalidResponse) { EXPECT_FALSE(result.get().Success()); } -TEST_F(GDBRemoteCommunicationClientTest, SendStartTracePacket) { - TraceOptions options; - Status error; - - options.setType(lldb::TraceType::eTraceTypeProcessorTrace); - options.setMetaDataBufferSize(8192); - options.setTraceBufferSize(8192); - options.setThreadID(0x23); - - StructuredData::DictionarySP custom_params = - std::make_shared(); - custom_params->AddStringItem("tracetech", "intel-pt"); - custom_params->AddIntegerItem("psb", 0x01); - - options.setTraceParams(custom_params); - - std::future result = std::async(std::launch::async, [&] { - return client.SendStartTracePacket(options, error); - }); - - // Since the line is exceeding 80 characters. - std::string expected_packet1 = - R"(jTraceStart:{"buffersize":8192,"metabuffersize":8192,"params":)"; - std::string expected_packet2 = - R"({"psb":1,"tracetech":"intel-pt"},"threadid":35,"type":1})"; - HandlePacket(server, (expected_packet1 + expected_packet2), "1"); - ASSERT_TRUE(error.Success()); - ASSERT_EQ(result.get(), 1u); - - error.Clear(); - result = std::async(std::launch::async, [&] { - return client.SendStartTracePacket(options, error); - }); - - HandlePacket(server, (expected_packet1 + expected_packet2), "E23"); - ASSERT_EQ(result.get(), LLDB_INVALID_UID); - ASSERT_FALSE(error.Success()); -} - -TEST_F(GDBRemoteCommunicationClientTest, SendStopTracePacket) { - lldb::tid_t thread_id = 0x23; - lldb::user_id_t trace_id = 3; - - std::future result = std::async(std::launch::async, [&] { - return client.SendStopTracePacket(trace_id, thread_id); - }); - - const char *expected_packet = R"(jTraceStop:{"threadid":35,"traceid":3})"; - HandlePacket(server, expected_packet, "OK"); - ASSERT_TRUE(result.get().Success()); - - result = std::async(std::launch::async, [&] { - return client.SendStopTracePacket(trace_id, thread_id); - }); - - HandlePacket(server, expected_packet, "E23"); - ASSERT_FALSE(result.get().Success()); -} - -TEST_F(GDBRemoteCommunicationClientTest, SendGetDataPacket) { - lldb::tid_t thread_id = 0x23; - lldb::user_id_t trace_id = 3; - - uint8_t buf[32] = {}; - llvm::MutableArrayRef buffer(buf, 32); - size_t offset = 0; - - std::future result = std::async(std::launch::async, [&] { - return client.SendGetDataPacket(trace_id, thread_id, buffer, offset); - }); - - std::string expected_packet1 = - R"(jTraceBufferRead:{"buffersize":32,"offset":0,"threadid":35,)"; - std::string expected_packet2 = R"("traceid":3})"; - HandlePacket(server, expected_packet1+expected_packet2, "123456"); - ASSERT_TRUE(result.get().Success()); - ASSERT_EQ(buffer.size(), 3u); - ASSERT_EQ(buf[0], 0x12); - ASSERT_EQ(buf[1], 0x34); - ASSERT_EQ(buf[2], 0x56); - - llvm::MutableArrayRef buffer2(buf, 32); - result = std::async(std::launch::async, [&] { - return client.SendGetDataPacket(trace_id, thread_id, buffer2, offset); - }); - - HandlePacket(server, expected_packet1+expected_packet2, "E23"); - ASSERT_FALSE(result.get().Success()); - ASSERT_EQ(buffer2.size(), 0u); -} - -TEST_F(GDBRemoteCommunicationClientTest, SendGetMetaDataPacket) { - lldb::tid_t thread_id = 0x23; - lldb::user_id_t trace_id = 3; +TEST_F(GDBRemoteCommunicationClientTest, SendTraceSupportedPacket) { + TraceSupportedResponse trace_type; + std::string error_message; + auto callback = [&] { + std::chrono::seconds timeout(10); + if (llvm::Expected trace_type_or_err = + client.SendTraceSupported(timeout)) { + trace_type = *trace_type_or_err; + error_message = ""; + return true; + } else { + trace_type = {}; + error_message = llvm::toString(trace_type_or_err.takeError()); + return false; + } + }; - uint8_t buf[32] = {}; - llvm::MutableArrayRef buffer(buf, 32); - size_t offset = 0; + // Success response + { + std::future result = std::async(std::launch::async, callback); - std::future result = std::async(std::launch::async, [&] { - return client.SendGetMetaDataPacket(trace_id, thread_id, buffer, offset); - }); + HandlePacket( + server, "jLLDBTraceSupported", + R"({"name":"intel-pt","description":"Intel Processor Trace"}])"); - std::string expected_packet1 = - R"(jTraceMetaRead:{"buffersize":32,"offset":0,"threadid":35,)"; - std::string expected_packet2 = R"("traceid":3})"; - HandlePacket(server, expected_packet1+expected_packet2, "123456"); - ASSERT_TRUE(result.get().Success()); - ASSERT_EQ(buffer.size(), 3u); - ASSERT_EQ(buf[0], 0x12); - ASSERT_EQ(buf[1], 0x34); - ASSERT_EQ(buf[2], 0x56); - - llvm::MutableArrayRef buffer2(buf, 32); - result = std::async(std::launch::async, [&] { - return client.SendGetMetaDataPacket(trace_id, thread_id, buffer2, offset); - }); + EXPECT_TRUE(result.get()); + ASSERT_STREQ(trace_type.name.c_str(), "intel-pt"); + ASSERT_STREQ(trace_type.description.c_str(), "Intel Processor Trace"); + } - HandlePacket(server, expected_packet1+expected_packet2, "E23"); - ASSERT_FALSE(result.get().Success()); - ASSERT_EQ(buffer2.size(), 0u); -} + // Error response - wrong json + { + std::future result = std::async(std::launch::async, callback); -TEST_F(GDBRemoteCommunicationClientTest, SendGetTraceConfigPacket) { - lldb::tid_t thread_id = 0x23; - lldb::user_id_t trace_id = 3; - TraceOptions options; - options.setThreadID(thread_id); + HandlePacket(server, "jLLDBTraceSupported", R"({"type":"intel-pt"}])"); - std::future result = std::async(std::launch::async, [&] { - return client.SendGetTraceConfigPacket(trace_id, options); - }); + EXPECT_FALSE(result.get()); + ASSERT_STREQ(error_message.c_str(), "missing value at TraceSupportedResponse.description"); + } - const char *expected_packet = - R"(jTraceConfigRead:{"threadid":35,"traceid":3})"; - std::string response1 = - R"({"buffersize":8192,"params":{"psb":1,"tracetech":"intel-pt"})"; - std::string response2 = R"(],"metabuffersize":8192,"threadid":35,"type":1}])"; - HandlePacket(server, expected_packet, response1+response2); - ASSERT_TRUE(result.get().Success()); - ASSERT_EQ(options.getTraceBufferSize(), 8192u); - ASSERT_EQ(options.getMetaDataBufferSize(), 8192u); - ASSERT_EQ(options.getType(), 1); - - auto custom_params = options.getTraceParams(); - - uint64_t psb_value; - llvm::StringRef trace_tech_value; - - ASSERT_TRUE(custom_params); - ASSERT_EQ(custom_params->GetType(), eStructuredDataTypeDictionary); - ASSERT_TRUE(custom_params->GetValueForKeyAsInteger("psb", psb_value)); - ASSERT_EQ(psb_value, 1u); - ASSERT_TRUE( - custom_params->GetValueForKeyAsString("tracetech", trace_tech_value)); - ASSERT_STREQ(trace_tech_value.data(), "intel-pt"); - - // Checking error response. - std::future result2 = std::async(std::launch::async, [&] { - return client.SendGetTraceConfigPacket(trace_id, options); - }); + // Error response + { + std::future result = std::async(std::launch::async, callback); - HandlePacket(server, expected_packet, "E23"); - ASSERT_FALSE(result2.get().Success()); + HandlePacket(server, "jLLDBTraceSupported", "E23"); - // Wrong JSON as response. - std::future result3 = std::async(std::launch::async, [&] { - return client.SendGetTraceConfigPacket(trace_id, options); - }); + EXPECT_FALSE(result.get()); + } - std::string incorrect_json1 = - R"("buffersize" : 8192,"params" : {"psb" : 1,"tracetech" : "intel-pt"})"; - std::string incorrect_json2 = - R"(],"metabuffersize" : 8192,"threadid" : 35,"type" : 1}])"; - HandlePacket(server, expected_packet, incorrect_json1+incorrect_json2); - ASSERT_FALSE(result3.get().Success()); + // Error response with error message + { + std::future result = std::async(std::launch::async, callback); - // Wrong JSON as custom_params. - std::future result4 = std::async(std::launch::async, [&] { - return client.SendGetTraceConfigPacket(trace_id, options); - }); + HandlePacket(server, "jLLDBTraceSupported", + "E23;50726F63657373206E6F742072756E6E696E672E"); - std::string incorrect_custom_params1 = - R"({"buffersize" : 8192,"params" : "psb" : 1,"tracetech" : "intel-pt"})"; - std::string incorrect_custom_params2 = - R"(],"metabuffersize" : 8192,"threadid" : 35,"type" : 1}])"; - HandlePacket(server, expected_packet, incorrect_custom_params1+ - incorrect_custom_params2); - ASSERT_FALSE(result4.get().Success()); + EXPECT_FALSE(result.get()); + ASSERT_STREQ(error_message.c_str(), "Process not running."); + } } TEST_F(GDBRemoteCommunicationClientTest, GetQOffsets) { @@ -578,3 +467,127 @@ TEST_F(GDBRemoteCommunicationClientTest, GetQOffsets) { EXPECT_EQ(llvm::None, GetQOffsets("TextSeg=0x1234")); EXPECT_EQ(llvm::None, GetQOffsets("TextSeg=12345678123456789")); } + +static void +check_qmemtags(TestClient &client, MockServer &server, size_t read_len, + int32_t type, const char *packet, llvm::StringRef response, + llvm::Optional> expected_tag_data) { + const auto &ReadMemoryTags = [&]() { + std::future result = std::async(std::launch::async, [&] { + return client.ReadMemoryTags(0xDEF0, read_len, type); + }); + + HandlePacket(server, packet, response); + return result.get(); + }; + + auto result = ReadMemoryTags(); + if (expected_tag_data) { + ASSERT_TRUE(result); + llvm::ArrayRef expected(*expected_tag_data); + llvm::ArrayRef got = result->GetData(); + ASSERT_THAT(expected, testing::ContainerEq(got)); + } else { + ASSERT_FALSE(result); + } +} + +TEST_F(GDBRemoteCommunicationClientTest, ReadMemoryTags) { + // Zero length reads are valid + check_qmemtags(client, server, 0, 1, "qMemTags:def0,0:1", "m", + std::vector{}); + + // Type can be negative. Put into the packet as the raw bytes + // (as opposed to a literal -1) + check_qmemtags(client, server, 0, -1, "qMemTags:def0,0:ffffffff", "m", + std::vector{}); + check_qmemtags(client, server, 0, std::numeric_limits::min(), + "qMemTags:def0,0:80000000", "m", std::vector{}); + check_qmemtags(client, server, 0, std::numeric_limits::max(), + "qMemTags:def0,0:7fffffff", "m", std::vector{}); + + // The client layer does not check the length of the received data. + // All we need is the "m" and for the decode to use all of the chars + check_qmemtags(client, server, 32, 2, "qMemTags:def0,20:2", "m09", + std::vector{0x9}); + + // Zero length response is fine as long as the "m" is present + check_qmemtags(client, server, 0, 0x34, "qMemTags:def0,0:34", "m", + std::vector{}); + + // Normal responses + check_qmemtags(client, server, 16, 1, "qMemTags:def0,10:1", "m66", + std::vector{0x66}); + check_qmemtags(client, server, 32, 1, "qMemTags:def0,20:1", "m0102", + std::vector{0x1, 0x2}); + + // Empty response is an error + check_qmemtags(client, server, 17, 1, "qMemTags:def0,11:1", "", llvm::None); + // Usual error response + check_qmemtags(client, server, 17, 1, "qMemTags:def0,11:1", "E01", + llvm::None); + // Leading m missing + check_qmemtags(client, server, 17, 1, "qMemTags:def0,11:1", "01", llvm::None); + // Anything other than m is an error + check_qmemtags(client, server, 17, 1, "qMemTags:def0,11:1", "z01", + llvm::None); + // Decoding tag data doesn't use all the chars in the packet + check_qmemtags(client, server, 32, 1, "qMemTags:def0,20:1", "m09zz", + llvm::None); + // Data that is not hex bytes + check_qmemtags(client, server, 32, 1, "qMemTags:def0,20:1", "mhello", + llvm::None); + // Data is not a complete hex char + check_qmemtags(client, server, 32, 1, "qMemTags:def0,20:1", "m9", llvm::None); + // Data has a trailing hex char + check_qmemtags(client, server, 32, 1, "qMemTags:def0,20:1", "m01020", + llvm::None); +} + +static void check_Qmemtags(TestClient &client, MockServer &server, + lldb::addr_t addr, size_t len, int32_t type, + const std::vector &tags, const char *packet, + llvm::StringRef response, bool should_succeed) { + const auto &WriteMemoryTags = [&]() { + std::future result = std::async(std::launch::async, [&] { + return client.WriteMemoryTags(addr, len, type, tags); + }); + + HandlePacket(server, packet, response); + return result.get(); + }; + + auto result = WriteMemoryTags(); + if (should_succeed) + ASSERT_TRUE(result.Success()); + else + ASSERT_TRUE(result.Fail()); +} + +TEST_F(GDBRemoteCommunicationClientTest, WriteMemoryTags) { + check_Qmemtags(client, server, 0xABCD, 0x20, 1, + std::vector{0x12, 0x34}, "QMemTags:abcd,20:1:1234", + "OK", true); + + // The GDB layer doesn't care that the number of tags != + // the length of the write. + check_Qmemtags(client, server, 0x4321, 0x20, 9, std::vector{}, + "QMemTags:4321,20:9:", "OK", true); + + check_Qmemtags(client, server, 0x8877, 0x123, 0x34, + std::vector{0x55, 0x66, 0x77}, + "QMemTags:8877,123:34:556677", "E01", false); + + // Type is a signed integer but is packed as its raw bytes, + // instead of having a +/-. + check_Qmemtags(client, server, 0x456789, 0, -1, std::vector{0x99}, + "QMemTags:456789,0:ffffffff:99", "E03", false); + check_Qmemtags(client, server, 0x456789, 0, + std::numeric_limits::max(), + std::vector{0x99}, "QMemTags:456789,0:7fffffff:99", + "E03", false); + check_Qmemtags(client, server, 0x456789, 0, + std::numeric_limits::min(), + std::vector{0x99}, "QMemTags:456789,0:80000000:99", + "E03", false); +} diff --git a/gnu/llvm/lldb/unittests/Process/gdb-remote/GDBRemoteCommunicationServerTest.cpp b/gnu/llvm/lldb/unittests/Process/gdb-remote/GDBRemoteCommunicationServerTest.cpp index 4c4916e3668..6ab37599ae3 100644 --- a/gnu/llvm/lldb/unittests/Process/gdb-remote/GDBRemoteCommunicationServerTest.cpp +++ b/gnu/llvm/lldb/unittests/Process/gdb-remote/GDBRemoteCommunicationServerTest.cpp @@ -9,9 +9,9 @@ #include "gtest/gtest.h" #include "GDBRemoteTestUtils.h" - #include "Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h" #include "lldb/Utility/Connection.h" +#include "lldb/Utility/UnimplementedError.h" namespace lldb_private { namespace process_gdb_remote { @@ -39,8 +39,7 @@ TEST(GDBRemoteCommunicationServerTest, SendErrorResponse_Status) { TEST(GDBRemoteCommunicationServerTest, SendErrorResponse_UnimplementedError) { MockServerWithMockConnection server; - auto error = - llvm::make_error("Test unimplemented error"); + auto error = llvm::make_error(); server.SendErrorResponse(std::move(error)); EXPECT_THAT(server.GetPackets(), testing::ElementsAre("$#00")); @@ -61,8 +60,8 @@ TEST(GDBRemoteCommunicationServerTest, SendErrorResponse_StringError) { TEST(GDBRemoteCommunicationServerTest, SendErrorResponse_ErrorList) { MockServerWithMockConnection server; - auto error = llvm::joinErrors(llvm::make_error(), - llvm::make_error()); + auto error = llvm::joinErrors(llvm::make_error(), + llvm::make_error()); server.SendErrorResponse(std::move(error)); // Make sure only one packet is sent even when there are multiple errors. diff --git a/gnu/llvm/lldb/unittests/Process/gdb-remote/PortMapTest.cpp b/gnu/llvm/lldb/unittests/Process/gdb-remote/PortMapTest.cpp new file mode 100644 index 00000000000..496a55be7ff --- /dev/null +++ b/gnu/llvm/lldb/unittests/Process/gdb-remote/PortMapTest.cpp @@ -0,0 +1,115 @@ +//===-- PortMapTest.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 "llvm/Testing/Support/Error.h" +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +#include "Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h" + +using namespace lldb_private::process_gdb_remote; + +TEST(PortMapTest, Constructors) { + // Default construct to empty map + GDBRemoteCommunicationServerPlatform::PortMap p1; + ASSERT_TRUE(p1.empty()); + + // Empty means no restrictions, return 0 and and bind to get a port + llvm::Expected available_port = p1.GetNextAvailablePort(); + ASSERT_THAT_EXPECTED(available_port, llvm::HasValue(0)); + + // Adding any port makes it not empty + p1.AllowPort(1); + ASSERT_FALSE(p1.empty()); + + // So we will return the added port this time + available_port = p1.GetNextAvailablePort(); + ASSERT_THAT_EXPECTED(available_port, llvm::HasValue(1)); + + // Construct from a range of ports + GDBRemoteCommunicationServerPlatform::PortMap p2(1, 4); + ASSERT_FALSE(p2.empty()); + + // Use up all the ports + for (uint16_t expected = 1; expected < 4; ++expected) { + available_port = p2.GetNextAvailablePort(); + ASSERT_THAT_EXPECTED(available_port, llvm::HasValue(expected)); + p2.AssociatePortWithProcess(*available_port, 1); + } + + // Now we fail since we're not an empty port map but all ports are used + available_port = p2.GetNextAvailablePort(); + ASSERT_THAT_EXPECTED(available_port, llvm::Failed()); +} + +TEST(PortMapTest, FreePort) { + GDBRemoteCommunicationServerPlatform::PortMap p(1, 4); + // Use up all the ports + for (uint16_t port = 1; port < 4; ++port) { + p.AssociatePortWithProcess(port, 1); + } + + llvm::Expected available_port = p.GetNextAvailablePort(); + ASSERT_THAT_EXPECTED(available_port, llvm::Failed()); + + // Can't free a port that isn't in the map + ASSERT_FALSE(p.FreePort(0)); + ASSERT_FALSE(p.FreePort(4)); + + // After freeing a port it becomes available + ASSERT_TRUE(p.FreePort(2)); + available_port = p.GetNextAvailablePort(); + ASSERT_THAT_EXPECTED(available_port, llvm::HasValue(2)); +} + +TEST(PortMapTest, FreePortForProcess) { + GDBRemoteCommunicationServerPlatform::PortMap p; + p.AllowPort(1); + p.AllowPort(2); + ASSERT_TRUE(p.AssociatePortWithProcess(1, 11)); + ASSERT_TRUE(p.AssociatePortWithProcess(2, 22)); + + // All ports have been used + llvm::Expected available_port = p.GetNextAvailablePort(); + ASSERT_THAT_EXPECTED(available_port, llvm::Failed()); + + // Can't free a port for a process that doesn't have any + ASSERT_FALSE(p.FreePortForProcess(33)); + + // You can move a used port to a new pid + ASSERT_TRUE(p.AssociatePortWithProcess(1, 99)); + + ASSERT_TRUE(p.FreePortForProcess(22)); + available_port = p.GetNextAvailablePort(); + ASSERT_THAT_EXPECTED(available_port, llvm::Succeeded()); + ASSERT_EQ(2, *available_port); + + // proces 22 no longer has a port + ASSERT_FALSE(p.FreePortForProcess(22)); +} + +TEST(PortMapTest, AllowPort) { + GDBRemoteCommunicationServerPlatform::PortMap p; + + // Allow port 1 and tie it to process 11 + p.AllowPort(1); + ASSERT_TRUE(p.AssociatePortWithProcess(1, 11)); + + // Allowing it a second time shouldn't change existing mapping + p.AllowPort(1); + llvm::Expected available_port = p.GetNextAvailablePort(); + ASSERT_THAT_EXPECTED(available_port, llvm::Failed()); + + // A new port is marked as free when allowed + p.AllowPort(2); + available_port = p.GetNextAvailablePort(); + ASSERT_THAT_EXPECTED(available_port, llvm::HasValue(2)); + + // 11 should still be tied to port 1 + ASSERT_TRUE(p.FreePortForProcess(11)); +} diff --git a/gnu/llvm/lldb/unittests/Process/minidump/MinidumpParserTest.cpp b/gnu/llvm/lldb/unittests/Process/minidump/MinidumpParserTest.cpp index 8f4b45b056b..e3f23c5fe33 100644 --- a/gnu/llvm/lldb/unittests/Process/minidump/MinidumpParserTest.cpp +++ b/gnu/llvm/lldb/unittests/Process/minidump/MinidumpParserTest.cpp @@ -378,15 +378,15 @@ Streams: parser->BuildMemoryRegions(), testing::Pair(testing::ElementsAre( MemoryRegionInfo({0x0, 0x10000}, no, no, no, no, - ConstString(), unknown, 0), + ConstString(), unknown, 0, unknown), MemoryRegionInfo({0x10000, 0x21000}, yes, yes, no, yes, - ConstString(), unknown, 0), + ConstString(), unknown, 0, unknown), MemoryRegionInfo({0x40000, 0x1000}, yes, no, no, yes, - ConstString(), unknown, 0), + ConstString(), unknown, 0, unknown), MemoryRegionInfo({0x7ffe0000, 0x1000}, yes, no, no, yes, - ConstString(), unknown, 0), + ConstString(), unknown, 0, unknown), MemoryRegionInfo({0x7ffe1000, 0xf000}, no, no, no, yes, - ConstString(), unknown, 0)), + ConstString(), unknown, 0, unknown)), true)); } @@ -409,12 +409,13 @@ Streams: EXPECT_THAT( parser->BuildMemoryRegions(), - testing::Pair(testing::ElementsAre( - MemoryRegionInfo({0x1000, 0x10}, yes, unknown, unknown, - yes, ConstString(), unknown, 0), - MemoryRegionInfo({0x2000, 0x20}, yes, unknown, unknown, - yes, ConstString(), unknown, 0)), - false)); + testing::Pair( + testing::ElementsAre( + MemoryRegionInfo({0x1000, 0x10}, yes, unknown, unknown, yes, + ConstString(), unknown, 0, unknown), + MemoryRegionInfo({0x2000, 0x20}, yes, unknown, unknown, yes, + ConstString(), unknown, 0, unknown)), + false)); } TEST_F(MinidumpParserTest, GetMemoryRegionInfoFromMemory64List) { @@ -424,12 +425,13 @@ TEST_F(MinidumpParserTest, GetMemoryRegionInfoFromMemory64List) { // we don't have a MemoryInfoListStream. EXPECT_THAT( parser->BuildMemoryRegions(), - testing::Pair(testing::ElementsAre( - MemoryRegionInfo({0x1000, 0x10}, yes, unknown, unknown, - yes, ConstString(), unknown, 0), - MemoryRegionInfo({0x2000, 0x20}, yes, unknown, unknown, - yes, ConstString(), unknown, 0)), - false)); + testing::Pair( + testing::ElementsAre( + MemoryRegionInfo({0x1000, 0x10}, yes, unknown, unknown, yes, + ConstString(), unknown, 0, unknown), + MemoryRegionInfo({0x2000, 0x20}, yes, unknown, unknown, yes, + ConstString(), unknown, 0, unknown)), + false)); } TEST_F(MinidumpParserTest, GetMemoryRegionInfoLinuxMaps) { @@ -453,22 +455,42 @@ Streams: ConstString app_process("/system/bin/app_process"); ConstString linker("/system/bin/linker"); ConstString liblog("/system/lib/liblog.so"); - EXPECT_THAT( - parser->BuildMemoryRegions(), - testing::Pair(testing::ElementsAre( - MemoryRegionInfo({0x400d9000, 0x2000}, yes, no, yes, - yes, app_process, unknown, 0), - MemoryRegionInfo({0x400db000, 0x1000}, yes, no, no, yes, - app_process, unknown, 0), - MemoryRegionInfo({0x400dc000, 0x1000}, yes, yes, no, - yes, ConstString(), unknown, 0), - MemoryRegionInfo({0x400ec000, 0x1000}, yes, no, no, yes, - ConstString(), unknown, 0), - MemoryRegionInfo({0x400ee000, 0x1000}, yes, yes, no, - yes, linker, unknown, 0), - MemoryRegionInfo({0x400fc000, 0x1000}, yes, yes, yes, - yes, liblog, unknown, 0)), - true)); + EXPECT_THAT(parser->BuildMemoryRegions(), + testing::Pair( + testing::ElementsAre( + MemoryRegionInfo({0x400d9000, 0x2000}, yes, no, yes, yes, + app_process, unknown, 0, unknown), + MemoryRegionInfo({0x400db000, 0x1000}, yes, no, no, yes, + app_process, unknown, 0, unknown), + MemoryRegionInfo({0x400dc000, 0x1000}, yes, yes, no, yes, + ConstString(), unknown, 0, unknown), + MemoryRegionInfo({0x400ec000, 0x1000}, yes, no, no, yes, + ConstString(), unknown, 0, unknown), + MemoryRegionInfo({0x400ee000, 0x1000}, yes, yes, no, yes, + linker, unknown, 0, unknown), + MemoryRegionInfo({0x400fc000, 0x1000}, yes, yes, yes, yes, + liblog, unknown, 0, unknown)), + true)); +} + +TEST_F(MinidumpParserTest, GetMemoryRegionInfoLinuxMapsError) { + ASSERT_THAT_ERROR(SetUpFromYaml(R"( +--- !minidump +Streams: + - Type: LinuxMaps + Text: | + 400d9000-400db000 r?xp 00000000 b3:04 227 + 400fc000-400fd000 rwxp 00001000 b3:04 1096 +... +)"), + llvm::Succeeded()); + // Test that when a /proc/maps region fails to parse + // we handle the error and continue with the rest. + EXPECT_THAT(parser->BuildMemoryRegions(), + testing::Pair(testing::ElementsAre(MemoryRegionInfo( + {0x400fc000, 0x1000}, yes, yes, yes, yes, + ConstString(nullptr), unknown, 0, unknown)), + true)); } // Windows Minidump tests @@ -689,6 +711,171 @@ Streams: EXPECT_EQ(0x0000000000001000u, filtered_modules[0]->BaseOfImage); } +TEST_F(MinidumpParserTest, MinidumpDuplicateModuleMappedFirst) { + ASSERT_THAT_ERROR(SetUpFromYaml(R"( +--- !minidump +Streams: + - Type: ModuleList + Modules: + - Base of Image: 0x400d0000 + Size of Image: 0x00002000 + Module Name: '/usr/lib/libc.so' + CodeView Record: '' + - Base of Image: 0x400d3000 + Size of Image: 0x00001000 + Module Name: '/usr/lib/libc.so' + CodeView Record: '' + - Type: LinuxMaps + Text: | + 400d0000-400d2000 r--p 00000000 b3:04 227 /usr/lib/libc.so + 400d2000-400d3000 rw-p 00000000 00:00 0 + 400d3000-400d4000 r-xp 00010000 b3:04 227 /usr/lib/libc.so + 400d4000-400d5000 rwxp 00001000 b3:04 227 /usr/lib/libc.so +... +)"), + llvm::Succeeded()); + // If we have a module mentioned twice in the module list, and we have full + // linux maps for all of the memory regions, make sure we pick the one that + // has a consecutive region with a matching path that has executable + // permissions. If clients open an object file with mmap, breakpad can create + // multiple mappings for a library errnoneously and the lowest address isn't + // always the right address. In this case we check the consective memory + // regions whose path matches starting at the base of image address and make + // sure one of the regions is executable and prefer that one. + // + // This test will make sure that if the executable is second in the module + // list, that it will become the selected module in the filtered list. + std::vector filtered_modules = + parser->GetFilteredModuleList(); + ASSERT_EQ(1u, filtered_modules.size()); + EXPECT_EQ(0x400d3000u, filtered_modules[0]->BaseOfImage); +} + +TEST_F(MinidumpParserTest, MinidumpDuplicateModuleMappedSecond) { + ASSERT_THAT_ERROR(SetUpFromYaml(R"( +--- !minidump +Streams: + - Type: ModuleList + Modules: + - Base of Image: 0x400d0000 + Size of Image: 0x00002000 + Module Name: '/usr/lib/libc.so' + CodeView Record: '' + - Base of Image: 0x400d3000 + Size of Image: 0x00001000 + Module Name: '/usr/lib/libc.so' + CodeView Record: '' + - Type: LinuxMaps + Text: | + 400d0000-400d1000 r-xp 00010000 b3:04 227 /usr/lib/libc.so + 400d1000-400d2000 rwxp 00001000 b3:04 227 /usr/lib/libc.so + 400d2000-400d3000 rw-p 00000000 00:00 0 + 400d3000-400d5000 r--p 00000000 b3:04 227 /usr/lib/libc.so +... +)"), + llvm::Succeeded()); + // If we have a module mentioned twice in the module list, and we have full + // linux maps for all of the memory regions, make sure we pick the one that + // has a consecutive region with a matching path that has executable + // permissions. If clients open an object file with mmap, breakpad can create + // multiple mappings for a library errnoneously and the lowest address isn't + // always the right address. In this case we check the consective memory + // regions whose path matches starting at the base of image address and make + // sure one of the regions is executable and prefer that one. + // + // This test will make sure that if the executable is first in the module + // list, that it will remain the correctly selected module in the filtered + // list. + std::vector filtered_modules = + parser->GetFilteredModuleList(); + ASSERT_EQ(1u, filtered_modules.size()); + EXPECT_EQ(0x400d0000u, filtered_modules[0]->BaseOfImage); +} + +TEST_F(MinidumpParserTest, MinidumpDuplicateModuleMappedSecondHigh) { + ASSERT_THAT_ERROR(SetUpFromYaml(R"( +--- !minidump +Streams: + - Type: ModuleList + Modules: + - Base of Image: 0x400d3000 + Size of Image: 0x00002000 + Module Name: '/usr/lib/libc.so' + CodeView Record: '' + - Base of Image: 0x400d0000 + Size of Image: 0x00001000 + Module Name: '/usr/lib/libc.so' + CodeView Record: '' + - Type: LinuxMaps + Text: | + 400d0000-400d2000 r--p 00000000 b3:04 227 /usr/lib/libc.so + 400d2000-400d3000 rw-p 00000000 00:00 0 + 400d3000-400d4000 r-xp 00010000 b3:04 227 /usr/lib/libc.so + 400d4000-400d5000 rwxp 00001000 b3:04 227 /usr/lib/libc.so +... +)"), + llvm::Succeeded()); + // If we have a module mentioned twice in the module list, and we have full + // linux maps for all of the memory regions, make sure we pick the one that + // has a consecutive region with a matching path that has executable + // permissions. If clients open an object file with mmap, breakpad can create + // multiple mappings for a library errnoneously and the lowest address isn't + // always the right address. In this case we check the consective memory + // regions whose path matches starting at the base of image address and make + // sure one of the regions is executable and prefer that one. + // + // This test will make sure that if the executable is first in the module + // list, that it will remain the correctly selected module in the filtered + // list, even if the non-executable module was loaded at a lower base address. + std::vector filtered_modules = + parser->GetFilteredModuleList(); + ASSERT_EQ(1u, filtered_modules.size()); + EXPECT_EQ(0x400d3000u, filtered_modules[0]->BaseOfImage); +} + +TEST_F(MinidumpParserTest, MinidumpDuplicateModuleSeparateCode) { + ASSERT_THAT_ERROR(SetUpFromYaml(R"( +--- !minidump +Streams: + - Type: ModuleList + Modules: + - Base of Image: 0x400d0000 + Size of Image: 0x00002000 + Module Name: '/usr/lib/libc.so' + CodeView Record: '' + - Base of Image: 0x400d5000 + Size of Image: 0x00001000 + Module Name: '/usr/lib/libc.so' + CodeView Record: '' + - Type: LinuxMaps + Text: | + 400d0000-400d3000 r--p 00000000 b3:04 227 /usr/lib/libc.so + 400d3000-400d5000 rw-p 00000000 00:00 0 + 400d5000-400d6000 r--p 00000000 b3:04 227 /usr/lib/libc.so + 400d6000-400d7000 r-xp 00010000 b3:04 227 /usr/lib/libc.so + 400d7000-400d8000 rwxp 00001000 b3:04 227 /usr/lib/libc.so +... +)"), + llvm::Succeeded()); + // If we have a module mentioned twice in the module list, and we have full + // linux maps for all of the memory regions, make sure we pick the one that + // has a consecutive region with a matching path that has executable + // permissions. If clients open an object file with mmap, breakpad can create + // multiple mappings for a library errnoneously and the lowest address isn't + // always the right address. In this case we check the consective memory + // regions whose path matches starting at the base of image address and make + // sure one of the regions is executable and prefer that one. + // + // This test will make sure if binaries are compiled with "-z separate-code", + // where the first region for a binary won't be marked as executable, that + // it gets selected by detecting the second consecutive mapping at 0x400d7000 + // when asked about the a module mamed "/usr/lib/libc.so" at 0x400d5000. + std::vector filtered_modules = + parser->GetFilteredModuleList(); + ASSERT_EQ(1u, filtered_modules.size()); + EXPECT_EQ(0x400d5000u, filtered_modules[0]->BaseOfImage); +} + TEST_F(MinidumpParserTest, MinidumpModuleOrder) { ASSERT_THAT_ERROR(SetUpFromYaml(R"( --- !minidump @@ -721,4 +908,3 @@ Streams: parser->GetMinidumpFile().getString(filtered_modules[1]->ModuleNameRVA), llvm::HasValue("/tmp/b")); } - diff --git a/gnu/llvm/lldb/unittests/ScriptInterpreter/Lua/CMakeLists.txt b/gnu/llvm/lldb/unittests/ScriptInterpreter/Lua/CMakeLists.txt index aa8a95c7c54..e030070a140 100644 --- a/gnu/llvm/lldb/unittests/ScriptInterpreter/Lua/CMakeLists.txt +++ b/gnu/llvm/lldb/unittests/ScriptInterpreter/Lua/CMakeLists.txt @@ -9,4 +9,4 @@ add_lldb_unittest(ScriptInterpreterLuaTests LLVMTestingSupport LINK_COMPONENTS Support - ) \ No newline at end of file + ) diff --git a/gnu/llvm/lldb/unittests/ScriptInterpreter/Lua/LuaTests.cpp b/gnu/llvm/lldb/unittests/ScriptInterpreter/Lua/LuaTests.cpp index 464babcb290..8d849cae4fb 100644 --- a/gnu/llvm/lldb/unittests/ScriptInterpreter/Lua/LuaTests.cpp +++ b/gnu/llvm/lldb/unittests/ScriptInterpreter/Lua/LuaTests.cpp @@ -13,6 +13,34 @@ using namespace lldb_private; extern "C" int luaopen_lldb(lua_State *L) { return 0; } +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wreturn-type-c-linkage" + +// Disable warning C4190: 'LLDBSwigPythonBreakpointCallbackFunction' has +// C-linkage specified, but returns UDT 'llvm::Expected' which is +// incompatible with C +#if _MSC_VER +#pragma warning (push) +#pragma warning (disable : 4190) +#endif + +extern "C" llvm::Expected LLDBSwigLuaBreakpointCallbackFunction( + lua_State *L, lldb::StackFrameSP stop_frame_sp, + lldb::BreakpointLocationSP bp_loc_sp, StructuredDataImpl *extra_args_impl) { + return false; +} + +extern "C" llvm::Expected LLDBSwigLuaWatchpointCallbackFunction( + lua_State *L, lldb::StackFrameSP stop_frame_sp, lldb::WatchpointSP wp_sp) { + return false; +} + +#if _MSC_VER +#pragma warning (pop) +#endif + +#pragma clang diagnostic pop + TEST(LuaTest, RunValid) { Lua lua; llvm::Error error = lua.Run("foo = 1"); diff --git a/gnu/llvm/lldb/unittests/ScriptInterpreter/Lua/ScriptInterpreterTests.cpp b/gnu/llvm/lldb/unittests/ScriptInterpreter/Lua/ScriptInterpreterTests.cpp index 3b7fbebdd98..e4aebfb650c 100644 --- a/gnu/llvm/lldb/unittests/ScriptInterpreter/Lua/ScriptInterpreterTests.cpp +++ b/gnu/llvm/lldb/unittests/ScriptInterpreter/Lua/ScriptInterpreterTests.cpp @@ -43,12 +43,6 @@ public: }; } // namespace -TEST_F(ScriptInterpreterTest, Plugin) { - EXPECT_EQ(ScriptInterpreterLua::GetPluginNameStatic(), "script-lua"); - EXPECT_EQ(ScriptInterpreterLua::GetPluginDescriptionStatic(), - "Lua script interpreter"); -} - TEST_F(ScriptInterpreterTest, ExecuteOneLine) { DebuggerSP debugger_sp = Debugger::CreateInstance(); ASSERT_TRUE(debugger_sp); diff --git a/gnu/llvm/lldb/unittests/ScriptInterpreter/Python/CMakeLists.txt b/gnu/llvm/lldb/unittests/ScriptInterpreter/Python/CMakeLists.txt index 913bd629526..90a53bf1751 100644 --- a/gnu/llvm/lldb/unittests/ScriptInterpreter/Python/CMakeLists.txt +++ b/gnu/llvm/lldb/unittests/ScriptInterpreter/Python/CMakeLists.txt @@ -10,6 +10,6 @@ add_lldb_unittest(ScriptInterpreterPythonTests Support ) -if(PYTHON_RPATH) - set_property(TARGET ScriptInterpreterPythonTests APPEND PROPERTY BUILD_RPATH "${PYTHON_RPATH}") -endif() \ No newline at end of file +if(Python3_RPATH) + set_property(TARGET ScriptInterpreterPythonTests APPEND PROPERTY BUILD_RPATH "${Python3_RPATH}") +endif() diff --git a/gnu/llvm/lldb/unittests/ScriptInterpreter/Python/PythonTestSuite.cpp b/gnu/llvm/lldb/unittests/ScriptInterpreter/Python/PythonTestSuite.cpp index f661835d191..f93733b3a5b 100644 --- a/gnu/llvm/lldb/unittests/ScriptInterpreter/Python/PythonTestSuite.cpp +++ b/gnu/llvm/lldb/unittests/ScriptInterpreter/Python/PythonTestSuite.cpp @@ -12,6 +12,7 @@ #include "Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h" #include "Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h" +#include "lldb/API/SBError.h" #include "lldb/Host/FileSystem.h" #include "lldb/Host/HostInfo.h" @@ -153,6 +154,14 @@ extern "C" int LLDBSwigPython_GetIndexOfChildWithName(void *implementor, return 0; } +extern "C" void *LLDBSWIGPython_CastPyObjectToSBData(void *data) { + return nullptr; +} + +extern "C" void *LLDBSWIGPython_CastPyObjectToSBError(void *data) { + return nullptr; +} + extern "C" void *LLDBSWIGPython_CastPyObjectToSBValue(void *data) { return nullptr; } @@ -207,6 +216,13 @@ LLDBSWIGPythonCreateOSPlugin(const char *python_class_name, return nullptr; } +extern "C" void *LLDBSwigPythonCreateScriptedProcess( + const char *python_class_name, const char *session_dictionary_name, + const lldb::TargetSP &target_sp, StructuredDataImpl *args_impl, + std::string &error_string) { + return nullptr; +} + extern "C" void * LLDBSWIGPython_CreateFrameRecognizer(const char *python_class_name, const char *session_dictionary_name) { @@ -254,3 +270,17 @@ LLDBSWIGPython_GetDynamicSetting(void *module, const char *setting, const lldb::TargetSP &target_sp) { return nullptr; } + +extern "C" void *LLDBSwigPythonCreateScriptedStopHook( + lldb::TargetSP target_sp, const char *python_class_name, + const char *session_dictionary_name, + lldb_private::StructuredDataImpl *args_impl, Status &error) { + return nullptr; +} + +extern "C" bool +LLDBSwigPythonStopHookCallHandleStop(void *implementor, + lldb::ExecutionContextRefSP exc_ctx_sp, + lldb::StreamSP stream) { + return false; +} diff --git a/gnu/llvm/lldb/unittests/Symbol/CMakeLists.txt b/gnu/llvm/lldb/unittests/Symbol/CMakeLists.txt index 76c7b645f27..748faf33b55 100644 --- a/gnu/llvm/lldb/unittests/Symbol/CMakeLists.txt +++ b/gnu/llvm/lldb/unittests/Symbol/CMakeLists.txt @@ -1,6 +1,7 @@ add_lldb_unittest(SymbolTests LocateSymbolFileTest.cpp PostfixExpressionTest.cpp + TestTypeSystem.cpp TestTypeSystemClang.cpp TestClangASTImporter.cpp TestDWARFCallFrameInfo.cpp diff --git a/gnu/llvm/lldb/unittests/Symbol/Inputs/inlined-functions.yaml b/gnu/llvm/lldb/unittests/Symbol/Inputs/inlined-functions.yaml index 8ce92115a0b..8498cf7f6d3 100644 --- a/gnu/llvm/lldb/unittests/Symbol/Inputs/inlined-functions.yaml +++ b/gnu/llvm/lldb/unittests/Symbol/Inputs/inlined-functions.yaml @@ -164,187 +164,186 @@ DWARF: - argv - char - sum - debug_abbrev: - - Code: 0x00000001 - Tag: DW_TAG_compile_unit - Children: DW_CHILDREN_yes - Attributes: - - Attribute: DW_AT_producer - Form: DW_FORM_strp - - Attribute: DW_AT_language - Form: DW_FORM_data2 - - Attribute: DW_AT_name - Form: DW_FORM_strp - - Attribute: DW_AT_stmt_list - Form: DW_FORM_sec_offset - - Attribute: DW_AT_comp_dir - Form: DW_FORM_strp - - Attribute: DW_AT_low_pc - Form: DW_FORM_addr - - Attribute: DW_AT_high_pc - Form: DW_FORM_data4 - - Code: 0x00000002 - Tag: DW_TAG_subprogram - Children: DW_CHILDREN_yes - Attributes: - - Attribute: DW_AT_low_pc - Form: DW_FORM_addr - - Attribute: DW_AT_high_pc - Form: DW_FORM_data4 - - Attribute: DW_AT_frame_base - Form: DW_FORM_exprloc - - Attribute: DW_AT_linkage_name - Form: DW_FORM_strp - - Attribute: DW_AT_name - Form: DW_FORM_strp - - Attribute: DW_AT_decl_file - Form: DW_FORM_data1 - - Attribute: DW_AT_decl_line - Form: DW_FORM_data1 - - Attribute: DW_AT_type - Form: DW_FORM_ref4 - - Attribute: DW_AT_external - Form: DW_FORM_flag_present - - Code: 0x00000003 - Tag: DW_TAG_formal_parameter - Children: DW_CHILDREN_no - Attributes: - - Attribute: DW_AT_location - Form: DW_FORM_exprloc - - Attribute: DW_AT_name - Form: DW_FORM_strp - - Attribute: DW_AT_decl_file - Form: DW_FORM_data1 - - Attribute: DW_AT_decl_line - Form: DW_FORM_data1 - - Attribute: DW_AT_type - Form: DW_FORM_ref4 - - Code: 0x00000004 - Tag: DW_TAG_variable - Children: DW_CHILDREN_no - Attributes: - - Attribute: DW_AT_location - Form: DW_FORM_exprloc - - Attribute: DW_AT_name - Form: DW_FORM_strp - - Attribute: DW_AT_decl_file - Form: DW_FORM_data1 - - Attribute: DW_AT_decl_line - Form: DW_FORM_data1 - - Attribute: DW_AT_type - Form: DW_FORM_ref4 - - Code: 0x00000005 - Tag: DW_TAG_subprogram - Children: DW_CHILDREN_yes - Attributes: - - Attribute: DW_AT_linkage_name - Form: DW_FORM_strp - - Attribute: DW_AT_name - Form: DW_FORM_strp - - Attribute: DW_AT_decl_file - Form: DW_FORM_data1 - - Attribute: DW_AT_decl_line - Form: DW_FORM_data1 - - Attribute: DW_AT_type - Form: DW_FORM_ref4 - - Attribute: DW_AT_external - Form: DW_FORM_flag_present - - Attribute: DW_AT_inline - Form: DW_FORM_data1 - - Code: 0x00000006 - Tag: DW_TAG_formal_parameter - Children: DW_CHILDREN_no - Attributes: - - Attribute: DW_AT_name - Form: DW_FORM_strp - - Attribute: DW_AT_decl_file - Form: DW_FORM_data1 - - Attribute: DW_AT_decl_line - Form: DW_FORM_data1 - - Attribute: DW_AT_type - Form: DW_FORM_ref4 - - Code: 0x00000007 - Tag: DW_TAG_variable - Children: DW_CHILDREN_no - Attributes: - - Attribute: DW_AT_name - Form: DW_FORM_strp - - Attribute: DW_AT_decl_file - Form: DW_FORM_data1 - - Attribute: DW_AT_decl_line - Form: DW_FORM_data1 - - Attribute: DW_AT_type - Form: DW_FORM_ref4 - - Code: 0x00000008 - Tag: DW_TAG_base_type - Children: DW_CHILDREN_no - Attributes: - - Attribute: DW_AT_name - Form: DW_FORM_strp - - Attribute: DW_AT_encoding - Form: DW_FORM_data1 - - Attribute: DW_AT_byte_size - Form: DW_FORM_data1 - - Code: 0x00000009 - Tag: DW_TAG_subprogram - Children: DW_CHILDREN_yes - Attributes: - - Attribute: DW_AT_low_pc - Form: DW_FORM_addr - - Attribute: DW_AT_high_pc - Form: DW_FORM_data4 - - Attribute: DW_AT_frame_base - Form: DW_FORM_exprloc - - Attribute: DW_AT_name - Form: DW_FORM_strp - - Attribute: DW_AT_decl_file - Form: DW_FORM_data1 - - Attribute: DW_AT_decl_line - Form: DW_FORM_data1 - - Attribute: DW_AT_type - Form: DW_FORM_ref4 - - Attribute: DW_AT_external - Form: DW_FORM_flag_present - - Code: 0x0000000A - Tag: DW_TAG_inlined_subroutine - Children: DW_CHILDREN_yes - Attributes: - - Attribute: DW_AT_abstract_origin - Form: DW_FORM_ref4 - - Attribute: DW_AT_low_pc - Form: DW_FORM_addr - - Attribute: DW_AT_high_pc - Form: DW_FORM_data4 - - Attribute: DW_AT_call_file - Form: DW_FORM_data1 - - Attribute: DW_AT_call_line - Form: DW_FORM_data1 - - Code: 0x0000000B - Tag: DW_TAG_formal_parameter - Children: DW_CHILDREN_no - Attributes: - - Attribute: DW_AT_location - Form: DW_FORM_exprloc - - Attribute: DW_AT_abstract_origin - Form: DW_FORM_ref4 - - Code: 0x0000000C - Tag: DW_TAG_variable - Children: DW_CHILDREN_no - Attributes: - - Attribute: DW_AT_location - Form: DW_FORM_exprloc - - Attribute: DW_AT_abstract_origin - Form: DW_FORM_ref4 - - Code: 0x0000000D - Tag: DW_TAG_pointer_type - Children: DW_CHILDREN_no - Attributes: - - Attribute: DW_AT_type - Form: DW_FORM_ref4 + debug_abbrev: + - Table: + - Code: 0x00000001 + Tag: DW_TAG_compile_unit + Children: DW_CHILDREN_yes + Attributes: + - Attribute: DW_AT_producer + Form: DW_FORM_strp + - Attribute: DW_AT_language + Form: DW_FORM_data2 + - Attribute: DW_AT_name + Form: DW_FORM_strp + - Attribute: DW_AT_stmt_list + Form: DW_FORM_sec_offset + - Attribute: DW_AT_comp_dir + Form: DW_FORM_strp + - Attribute: DW_AT_low_pc + Form: DW_FORM_addr + - Attribute: DW_AT_high_pc + Form: DW_FORM_data4 + - Code: 0x00000002 + Tag: DW_TAG_subprogram + Children: DW_CHILDREN_yes + Attributes: + - Attribute: DW_AT_low_pc + Form: DW_FORM_addr + - Attribute: DW_AT_high_pc + Form: DW_FORM_data4 + - Attribute: DW_AT_frame_base + Form: DW_FORM_exprloc + - Attribute: DW_AT_linkage_name + Form: DW_FORM_strp + - Attribute: DW_AT_name + Form: DW_FORM_strp + - Attribute: DW_AT_decl_file + Form: DW_FORM_data1 + - Attribute: DW_AT_decl_line + Form: DW_FORM_data1 + - Attribute: DW_AT_type + Form: DW_FORM_ref4 + - Attribute: DW_AT_external + Form: DW_FORM_flag_present + - Code: 0x00000003 + Tag: DW_TAG_formal_parameter + Children: DW_CHILDREN_no + Attributes: + - Attribute: DW_AT_location + Form: DW_FORM_exprloc + - Attribute: DW_AT_name + Form: DW_FORM_strp + - Attribute: DW_AT_decl_file + Form: DW_FORM_data1 + - Attribute: DW_AT_decl_line + Form: DW_FORM_data1 + - Attribute: DW_AT_type + Form: DW_FORM_ref4 + - Code: 0x00000004 + Tag: DW_TAG_variable + Children: DW_CHILDREN_no + Attributes: + - Attribute: DW_AT_location + Form: DW_FORM_exprloc + - Attribute: DW_AT_name + Form: DW_FORM_strp + - Attribute: DW_AT_decl_file + Form: DW_FORM_data1 + - Attribute: DW_AT_decl_line + Form: DW_FORM_data1 + - Attribute: DW_AT_type + Form: DW_FORM_ref4 + - Code: 0x00000005 + Tag: DW_TAG_subprogram + Children: DW_CHILDREN_yes + Attributes: + - Attribute: DW_AT_linkage_name + Form: DW_FORM_strp + - Attribute: DW_AT_name + Form: DW_FORM_strp + - Attribute: DW_AT_decl_file + Form: DW_FORM_data1 + - Attribute: DW_AT_decl_line + Form: DW_FORM_data1 + - Attribute: DW_AT_type + Form: DW_FORM_ref4 + - Attribute: DW_AT_external + Form: DW_FORM_flag_present + - Attribute: DW_AT_inline + Form: DW_FORM_data1 + - Code: 0x00000006 + Tag: DW_TAG_formal_parameter + Children: DW_CHILDREN_no + Attributes: + - Attribute: DW_AT_name + Form: DW_FORM_strp + - Attribute: DW_AT_decl_file + Form: DW_FORM_data1 + - Attribute: DW_AT_decl_line + Form: DW_FORM_data1 + - Attribute: DW_AT_type + Form: DW_FORM_ref4 + - Code: 0x00000007 + Tag: DW_TAG_variable + Children: DW_CHILDREN_no + Attributes: + - Attribute: DW_AT_name + Form: DW_FORM_strp + - Attribute: DW_AT_decl_file + Form: DW_FORM_data1 + - Attribute: DW_AT_decl_line + Form: DW_FORM_data1 + - Attribute: DW_AT_type + Form: DW_FORM_ref4 + - Code: 0x00000008 + Tag: DW_TAG_base_type + Children: DW_CHILDREN_no + Attributes: + - Attribute: DW_AT_name + Form: DW_FORM_strp + - Attribute: DW_AT_encoding + Form: DW_FORM_data1 + - Attribute: DW_AT_byte_size + Form: DW_FORM_data1 + - Code: 0x00000009 + Tag: DW_TAG_subprogram + Children: DW_CHILDREN_yes + Attributes: + - Attribute: DW_AT_low_pc + Form: DW_FORM_addr + - Attribute: DW_AT_high_pc + Form: DW_FORM_data4 + - Attribute: DW_AT_frame_base + Form: DW_FORM_exprloc + - Attribute: DW_AT_name + Form: DW_FORM_strp + - Attribute: DW_AT_decl_file + Form: DW_FORM_data1 + - Attribute: DW_AT_decl_line + Form: DW_FORM_data1 + - Attribute: DW_AT_type + Form: DW_FORM_ref4 + - Attribute: DW_AT_external + Form: DW_FORM_flag_present + - Code: 0x0000000A + Tag: DW_TAG_inlined_subroutine + Children: DW_CHILDREN_yes + Attributes: + - Attribute: DW_AT_abstract_origin + Form: DW_FORM_ref4 + - Attribute: DW_AT_low_pc + Form: DW_FORM_addr + - Attribute: DW_AT_high_pc + Form: DW_FORM_data4 + - Attribute: DW_AT_call_file + Form: DW_FORM_data1 + - Attribute: DW_AT_call_line + Form: DW_FORM_data1 + - Code: 0x0000000B + Tag: DW_TAG_formal_parameter + Children: DW_CHILDREN_no + Attributes: + - Attribute: DW_AT_location + Form: DW_FORM_exprloc + - Attribute: DW_AT_abstract_origin + Form: DW_FORM_ref4 + - Code: 0x0000000C + Tag: DW_TAG_variable + Children: DW_CHILDREN_no + Attributes: + - Attribute: DW_AT_location + Form: DW_FORM_exprloc + - Attribute: DW_AT_abstract_origin + Form: DW_FORM_ref4 + - Code: 0x0000000D + Tag: DW_TAG_pointer_type + Children: DW_CHILDREN_no + Attributes: + - Attribute: DW_AT_type + Form: DW_FORM_ref4 debug_info: - - Length: 579 - Version: 4 - AbbrOffset: 0 + - Version: 4 AddrSize: 8 Entries: - AbbrCode: 0x00000001 @@ -410,7 +409,6 @@ DWARF: - Value: 0x0000000000000007 - Value: 0x00000000000000B2 - AbbrCode: 0x00000000 - Values: [] - AbbrCode: 0x00000005 Values: - Value: 0x0000000000000094 @@ -439,7 +437,6 @@ DWARF: - Value: 0x0000000000000002 - Value: 0x00000000000000B2 - AbbrCode: 0x00000000 - Values: [] - AbbrCode: 0x00000008 Values: - Value: 0x00000000000000A3 @@ -485,7 +482,6 @@ DWARF: - Value: 0x000000000000000C - Value: 0x00000000000000B2 - AbbrCode: 0x00000000 - Values: [] - AbbrCode: 0x00000009 Values: - Value: 0x0000000000000020 @@ -561,7 +557,6 @@ DWARF: - 0x7F - Value: 0x00000000000000A6 - AbbrCode: 0x00000000 - Values: [] - AbbrCode: 0x0000000A Values: - Value: 0x00000000000000B9 @@ -633,7 +628,6 @@ DWARF: - 0x68 - Value: 0x00000000000000A6 - AbbrCode: 0x00000000 - Values: [] - AbbrCode: 0x0000000A Values: - Value: 0x0000000000000080 @@ -663,9 +657,7 @@ DWARF: - 0x74 - Value: 0x00000000000000A6 - AbbrCode: 0x00000000 - Values: [] - AbbrCode: 0x00000000 - Values: [] - AbbrCode: 0x0000000A Values: - Value: 0x0000000000000080 @@ -695,9 +687,7 @@ DWARF: - 0x48 - Value: 0x00000000000000A6 - AbbrCode: 0x00000000 - Values: [] - AbbrCode: 0x00000000 - Values: [] - AbbrCode: 0x0000000D Values: - Value: 0x000000000000023A @@ -710,7 +700,6 @@ DWARF: - Value: 0x0000000000000006 - Value: 0x0000000000000001 - AbbrCode: 0x00000000 - Values: [] debug_line: - Length: 202 Version: 4 @@ -722,7 +711,6 @@ DWARF: LineRange: 14 OpcodeBase: 13 StandardOpcodeLengths: [ 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1 ] - IncludeDirs: [] Files: - Name: inlined-functions.cpp DirIdx: 0 diff --git a/gnu/llvm/lldb/unittests/Symbol/LocateSymbolFileTest.cpp b/gnu/llvm/lldb/unittests/Symbol/LocateSymbolFileTest.cpp index 268faeaf1db..c51b1ba4904 100644 --- a/gnu/llvm/lldb/unittests/Symbol/LocateSymbolFileTest.cpp +++ b/gnu/llvm/lldb/unittests/Symbol/LocateSymbolFileTest.cpp @@ -14,13 +14,14 @@ #include "lldb/Host/HostInfo.h" #include "lldb/Symbol/LocateSymbolFile.h" #include "lldb/Target/Target.h" +#include "lldb/Utility/Reproducer.h" using namespace lldb_private; namespace { class SymbolsTest : public ::testing::Test { public: - SubsystemRAII subsystems; + SubsystemRAII subsystems; }; } // namespace diff --git a/gnu/llvm/lldb/unittests/Symbol/PostfixExpressionTest.cpp b/gnu/llvm/lldb/unittests/Symbol/PostfixExpressionTest.cpp index 7def709a609..9f66aeed6b6 100644 --- a/gnu/llvm/lldb/unittests/Symbol/PostfixExpressionTest.cpp +++ b/gnu/llvm/lldb/unittests/Symbol/PostfixExpressionTest.cpp @@ -111,7 +111,7 @@ ParseFPOAndStringify(llvm::StringRef prog) { ParseFPOProgram(prog, alloc); std::vector> result; for (const auto &p : parsed) - result.emplace_back(p.first, ASTPrinter::Print(p.second)); + result.emplace_back(p.first.str(), ASTPrinter::Print(p.second)); return result; } @@ -158,7 +158,7 @@ static std::string ParseAndGenerateDWARF(llvm::StringRef expr) { std::string result; llvm::raw_string_ostream os(result); llvm::DWARFExpression(extractor, addr_size, llvm::dwarf::DWARF32) - .print(os, nullptr, nullptr); + .print(os, llvm::DIDumpOptions(), nullptr, nullptr); return std::move(os.str()); } diff --git a/gnu/llvm/lldb/unittests/Symbol/TestClangASTImporter.cpp b/gnu/llvm/lldb/unittests/Symbol/TestClangASTImporter.cpp index 02151a20a20..c8ffd099716 100644 --- a/gnu/llvm/lldb/unittests/Symbol/TestClangASTImporter.cpp +++ b/gnu/llvm/lldb/unittests/Symbol/TestClangASTImporter.cpp @@ -14,9 +14,9 @@ #include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "TestingSupport/SubsystemRAII.h" #include "TestingSupport/Symbol/ClangTestUtils.h" +#include "lldb/Core/Declaration.h" #include "lldb/Host/FileSystem.h" #include "lldb/Host/HostInfo.h" -#include "lldb/Symbol/Declaration.h" #include "clang/AST/DeclCXX.h" using namespace clang; @@ -93,7 +93,7 @@ TEST_F(TestClangASTImporter, CompleteFwdDeclWithOtherOrigin) { clang_utils::SourceASTWithRecord source_with_definition; // Create an AST with a type thst is only a forward declaration with the - // same name as the one in the the other source. + // same name as the one in the other source. std::unique_ptr fwd_decl_source = clang_utils::createAST(); CompilerType fwd_decl_type = clang_utils::createRecord( *fwd_decl_source, source_with_definition.record_decl->getName()); diff --git a/gnu/llvm/lldb/unittests/Symbol/TestLineEntry.cpp b/gnu/llvm/lldb/unittests/Symbol/TestLineEntry.cpp index d32ec9b1e7c..5fc53749703 100644 --- a/gnu/llvm/lldb/unittests/Symbol/TestLineEntry.cpp +++ b/gnu/llvm/lldb/unittests/Symbol/TestLineEntry.cpp @@ -53,20 +53,23 @@ void LineEntryTest::SetUp() { } llvm::Expected LineEntryTest::GetLineEntryForLine(uint32_t line) { - bool check_inlines = true; - bool exact = true; + // TODO: Handle SourceLocationSpec column information SymbolContextList sc_comp_units; SymbolContextList sc_line_entries; FileSpec file_spec("inlined-functions.cpp"); - m_module_sp->ResolveSymbolContextsForFileSpec(file_spec, line, check_inlines, - lldb::eSymbolContextCompUnit, - sc_comp_units); + m_module_sp->ResolveSymbolContextsForFileSpec( + file_spec, line, /*check_inlines=*/true, lldb::eSymbolContextCompUnit, + sc_comp_units); if (sc_comp_units.GetSize() == 0) return llvm::createStringError(llvm::inconvertibleErrorCode(), "No comp unit found on the test object."); + + SourceLocationSpec location_spec(file_spec, line, /*column=*/llvm::None, + /*check_inlines=*/true, + /*exact_match=*/true); + sc_comp_units[0].comp_unit->ResolveSymbolContext( - file_spec, line, check_inlines, exact, eSymbolContextLineEntry, - sc_line_entries); + location_spec, eSymbolContextLineEntry, sc_line_entries); if (sc_line_entries.GetSize() == 0) return llvm::createStringError(llvm::inconvertibleErrorCode(), "No line entry found on the test object."); diff --git a/gnu/llvm/lldb/unittests/Symbol/TestTypeSystem.cpp b/gnu/llvm/lldb/unittests/Symbol/TestTypeSystem.cpp new file mode 100644 index 00000000000..59297a7475d --- /dev/null +++ b/gnu/llvm/lldb/unittests/Symbol/TestTypeSystem.cpp @@ -0,0 +1,92 @@ +//===-- TestTypeSystem.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 "TestingSupport/SubsystemRAII.h" +#include "lldb/Core/Module.h" +#include "lldb/Host/FileSystem.h" +#include "lldb/Host/HostInfo.h" +#include "lldb/Symbol/TypeSystem.h" +#include "gtest/gtest.h" + +using namespace lldb; +using namespace lldb_private; + +class TestTypeSystemMap : public testing::Test { +public: + SubsystemRAII subsystems; +}; + +TEST_F(TestTypeSystemMap, GetTypeSystemForLanguageWithInvalidModule) { + // GetTypeSystemForLanguage called with an invalid Module. + TypeSystemMap map; + Module module{ModuleSpec()}; + EXPECT_THAT_EXPECTED( + map.GetTypeSystemForLanguage(eLanguageTypeUnknown, &module, + /*can_create=*/true), + llvm::FailedWithMessage("TypeSystem for language unknown doesn't exist")); + + EXPECT_THAT_EXPECTED( + map.GetTypeSystemForLanguage(eLanguageTypeUnknown, &module, + /*can_create=*/false), + llvm::FailedWithMessage("TypeSystem for language unknown doesn't exist")); + + EXPECT_THAT_EXPECTED( + map.GetTypeSystemForLanguage(eLanguageTypeC, &module, + /*can_create=*/true), + llvm::FailedWithMessage("TypeSystem for language c doesn't exist")); + EXPECT_THAT_EXPECTED( + map.GetTypeSystemForLanguage(eLanguageTypeC, &module, + /*can_create=*/false), + llvm::FailedWithMessage("TypeSystem for language c doesn't exist")); +} + +TEST_F(TestTypeSystemMap, GetTypeSystemForLanguageWithNoModule) { + // GetTypeSystemForLanguage called with no Module. + TypeSystemMap map; + Module *module = nullptr; + EXPECT_THAT_EXPECTED( + map.GetTypeSystemForLanguage(eLanguageTypeUnknown, module, + /*can_create=*/true), + llvm::FailedWithMessage("TypeSystem for language unknown doesn't exist")); + + EXPECT_THAT_EXPECTED( + map.GetTypeSystemForLanguage(eLanguageTypeUnknown, module, + /*can_create=*/false), + llvm::FailedWithMessage("TypeSystem for language unknown doesn't exist")); + + EXPECT_THAT_EXPECTED( + map.GetTypeSystemForLanguage(eLanguageTypeC, module, /*can_create=*/true), + llvm::FailedWithMessage("TypeSystem for language c doesn't exist")); + EXPECT_THAT_EXPECTED( + map.GetTypeSystemForLanguage(eLanguageTypeC, module, + /*can_create=*/false), + llvm::FailedWithMessage("TypeSystem for language c doesn't exist")); +} + +TEST_F(TestTypeSystemMap, GetTypeSystemForLanguageWithNoTarget) { + // GetTypeSystemForLanguage called with no Target. + TypeSystemMap map; + Target *target = nullptr; + EXPECT_THAT_EXPECTED( + map.GetTypeSystemForLanguage(eLanguageTypeUnknown, target, + /*can_create=*/true), + llvm::FailedWithMessage("TypeSystem for language unknown doesn't exist")); + + EXPECT_THAT_EXPECTED( + map.GetTypeSystemForLanguage(eLanguageTypeUnknown, target, + /*can_create=*/false), + llvm::FailedWithMessage("TypeSystem for language unknown doesn't exist")); + + EXPECT_THAT_EXPECTED( + map.GetTypeSystemForLanguage(eLanguageTypeC, target, /*can_create=*/true), + llvm::FailedWithMessage("TypeSystem for language c doesn't exist")); + EXPECT_THAT_EXPECTED( + map.GetTypeSystemForLanguage(eLanguageTypeC, target, + /*can_create=*/false), + llvm::FailedWithMessage("TypeSystem for language c doesn't exist")); +} diff --git a/gnu/llvm/lldb/unittests/Symbol/TestTypeSystemClang.cpp b/gnu/llvm/lldb/unittests/Symbol/TestTypeSystemClang.cpp index bd7eb14d453..10f59147dd1 100644 --- a/gnu/llvm/lldb/unittests/Symbol/TestTypeSystemClang.cpp +++ b/gnu/llvm/lldb/unittests/Symbol/TestTypeSystemClang.cpp @@ -10,9 +10,9 @@ #include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "TestingSupport/SubsystemRAII.h" #include "TestingSupport/Symbol/ClangTestUtils.h" +#include "lldb/Core/Declaration.h" #include "lldb/Host/FileSystem.h" #include "lldb/Host/HostInfo.h" -#include "lldb/Symbol/Declaration.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/ExprCXX.h" @@ -482,9 +482,8 @@ TEST_F(TestTypeSystemClang, TemplateArguments) { m_ast->CompleteTagDeclarationDefinition(type); // typedef foo foo_def; - CompilerType typedef_type = m_ast->CreateTypedefType( - type, "foo_def", - m_ast->CreateDeclContext(m_ast->GetTranslationUnitDecl()), 0); + CompilerType typedef_type = type.CreateTypedef( + "foo_def", m_ast->CreateDeclContext(m_ast->GetTranslationUnitDecl()), 0); CompilerType auto_type( m_ast.get(), @@ -516,6 +515,193 @@ TEST_F(TestTypeSystemClang, TemplateArguments) { } } +class TestCreateClassTemplateDecl : public TestTypeSystemClang { +protected: + /// The class templates created so far by the Expect* functions below. + llvm::DenseSet m_created_templates; + + /// Utility function for creating a class template. + ClassTemplateDecl * + CreateClassTemplate(const TypeSystemClang::TemplateParameterInfos &infos) { + ClassTemplateDecl *decl = m_ast->CreateClassTemplateDecl( + m_ast->GetTranslationUnitDecl(), OptionalClangModuleID(), eAccessPublic, + "foo", TTK_Struct, infos); + return decl; + } + + /// Creates a new class template with the given template parameters. + /// Asserts that a new ClassTemplateDecl is created. + /// \param description The gtest scope string that should describe the input. + /// \param infos The template parameters that the class template should have. + /// \returns The created ClassTemplateDecl. + ClassTemplateDecl * + ExpectNewTemplate(std::string description, + const TypeSystemClang::TemplateParameterInfos &infos) { + SCOPED_TRACE(description); + ClassTemplateDecl *first_template = CreateClassTemplate(infos); + // A new template should have been created. + EXPECT_FALSE(m_created_templates.contains(first_template)) + << "Didn't create new class template but reused this existing decl:\n" + << ClangUtil::DumpDecl(first_template); + m_created_templates.insert(first_template); + + // Creating a new template with the same arguments should always return + // the template created above. + ClassTemplateDecl *second_template = CreateClassTemplate(infos); + EXPECT_EQ(first_template, second_template) + << "Second attempt to create class template didn't reuse first decl:\n" + << ClangUtil::DumpDecl(first_template) << "\nInstead created/reused:\n" + << ClangUtil::DumpDecl(second_template); + return first_template; + } + + /// Tries to create a new class template but asserts that an existing class + /// template in the current AST is reused (in contract so a new class + /// template being created). + /// \param description The gtest scope string that should describe the input. + /// \param infos The template parameters that the class template should have. + void + ExpectReusedTemplate(std::string description, + const TypeSystemClang::TemplateParameterInfos &infos, + ClassTemplateDecl *expected) { + SCOPED_TRACE(description); + ClassTemplateDecl *td = CreateClassTemplate(infos); + EXPECT_EQ(td, expected) + << "Created/reused class template is:\n" + << ClangUtil::DumpDecl(td) << "\nExpected to reuse:\n" + << ClangUtil::DumpDecl(expected); + } +}; + +TEST_F(TestCreateClassTemplateDecl, FindExistingTemplates) { + // This tests the logic in TypeSystemClang::CreateClassTemplateDecl that + // decides whether an existing ClassTemplateDecl in the AST can be reused. + // The behaviour should follow the C++ rules for redeclaring templates + // (e.g., parameter names can be changed/omitted.) + + // This describes a class template *instantiation* from which we will infer + // the structure of the class template. + TypeSystemClang::TemplateParameterInfos infos; + + // Test an empty template parameter list: <> + ExpectNewTemplate("<>", infos); + + // Test that with T = int creates a new template. + infos.names = {"T"}; + infos.args = {TemplateArgument(m_ast->getASTContext().IntTy)}; + ClassTemplateDecl *single_type_arg = ExpectNewTemplate("", infos); + + // Test that changing the parameter name doesn't create a new class template. + infos.names = {"A"}; + ExpectReusedTemplate(" (A = int)", infos, single_type_arg); + + // Test that changing the used type doesn't create a new class template. + infos.args = {TemplateArgument(m_ast->getASTContext().FloatTy)}; + ExpectReusedTemplate(" (A = float)", infos, single_type_arg); + + // Test that creates a new template with A = int + // and I = 47; + infos.names.push_back("I"); + infos.args.push_back(TemplateArgument(m_ast->getASTContext(), + llvm::APSInt(llvm::APInt(8, 47)), + m_ast->getASTContext().SignedCharTy)); + ClassTemplateDecl *type_and_char_value = + ExpectNewTemplate(" (I = 47)", infos); + + // Change the value of the I parameter to 123. The previously created + // class template should still be reused. + infos.args.pop_back(); + infos.args.push_back(TemplateArgument(m_ast->getASTContext(), + llvm::APSInt(llvm::APInt(8, 123)), + m_ast->getASTContext().SignedCharTy)); + ExpectReusedTemplate(" (I = 123)", infos, + type_and_char_value); + + // Change the type of the I parameter to int so we have . + // The class template from above can't be reused. + infos.args.pop_back(); + infos.args.push_back(TemplateArgument(m_ast->getASTContext(), + llvm::APSInt(llvm::APInt(32, 47)), + m_ast->getASTContext().IntTy)); + ExpectNewTemplate(" (I = 123)", infos); + + // Test a second type parameter will also cause a new template to be created. + // We now have . + infos.names.push_back("B"); + infos.args.push_back(TemplateArgument(m_ast->getASTContext().IntTy)); + ClassTemplateDecl *type_and_char_value_and_type = + ExpectNewTemplate("", infos); + + // Remove all the names from the parameters which shouldn't influence the + // way the templates get merged. + infos.names = {"", "", ""}; + ExpectReusedTemplate("", infos, + type_and_char_value_and_type); +} + +TEST_F(TestCreateClassTemplateDecl, FindExistingTemplatesWithParameterPack) { + // The same as FindExistingTemplates but for templates with parameter packs. + + TypeSystemClang::TemplateParameterInfos infos; + infos.packed_args = + std::make_unique(); + infos.packed_args->names = {"", ""}; + infos.packed_args->args = {TemplateArgument(m_ast->getASTContext().IntTy), + TemplateArgument(m_ast->getASTContext().IntTy)}; + ClassTemplateDecl *type_pack = + ExpectNewTemplate(" (int, int)", infos); + + // Special case: An instantiation for a parameter pack with no values fits + // to whatever class template we find. There isn't enough information to + // do an actual comparison here. + infos.packed_args = + std::make_unique(); + ExpectReusedTemplate("<...> (no values in pack)", infos, type_pack); + + // Change the type content of pack type values. + infos.packed_args->names = {"", ""}; + infos.packed_args->args = {TemplateArgument(m_ast->getASTContext().IntTy), + TemplateArgument(m_ast->getASTContext().LongTy)}; + ExpectReusedTemplate(" (int, long)", infos, type_pack); + + // Change the number of pack values. + infos.packed_args->args = {TemplateArgument(m_ast->getASTContext().IntTy)}; + ExpectReusedTemplate(" (int)", infos, type_pack); + + // The names of the pack values shouldn't matter. + infos.packed_args->names = {"A", "B"}; + ExpectReusedTemplate(" (int)", infos, type_pack); + + // Changing the kind of template argument will create a new template. + infos.packed_args->args = {TemplateArgument(m_ast->getASTContext(), + llvm::APSInt(llvm::APInt(32, 1)), + m_ast->getASTContext().IntTy)}; + ClassTemplateDecl *int_pack = ExpectNewTemplate(" (int = 1)", infos); + + // Changing the value of integral parameters will not create a new template. + infos.packed_args->args = {TemplateArgument( + m_ast->getASTContext(), llvm::APSInt(llvm::APInt(32, 123)), + m_ast->getASTContext().IntTy)}; + ExpectReusedTemplate(" (int = 123)", infos, int_pack); + + // Changing the integral type will create a new template. + infos.packed_args->args = {TemplateArgument(m_ast->getASTContext(), + llvm::APSInt(llvm::APInt(64, 1)), + m_ast->getASTContext().LongTy)}; + ExpectNewTemplate(" (long = 1)", infos); + + // Prependinding a non-pack parameter will create a new template. + infos.names = {"T"}; + infos.args = {TemplateArgument(m_ast->getASTContext().IntTy)}; + ExpectNewTemplate(" (T = int, long = 1)", infos); +} + +TEST_F(TestTypeSystemClang, OnlyPackName) { + TypeSystemClang::TemplateParameterInfos infos; + infos.pack_name = "A"; + EXPECT_FALSE(infos.IsValid()); +} + static QualType makeConstInt(clang::ASTContext &ctxt) { QualType result(ctxt.IntTy); result.addConst(); @@ -559,13 +745,14 @@ TEST_F(TestTypeSystemClang, TestFunctionTemplateConstruction) { CompilerType clang_type = m_ast->CreateFunctionType(int_type, nullptr, 0U, false, 0U); FunctionDecl *func = m_ast->CreateFunctionDeclaration( - TU, OptionalClangModuleID(), "foo", clang_type, 0, false); + TU, OptionalClangModuleID(), "foo", clang_type, StorageClass::SC_None, + false); TypeSystemClang::TemplateParameterInfos empty_params; // Create the actual function template. clang::FunctionTemplateDecl *func_template = m_ast->CreateFunctionTemplateDecl(TU, OptionalClangModuleID(), func, - "foo", empty_params); + empty_params); EXPECT_EQ(TU, func_template->getDeclContext()); EXPECT_EQ("foo", func_template->getName()); @@ -590,13 +777,14 @@ TEST_F(TestTypeSystemClang, TestFunctionTemplateInRecordConstruction) { // 1. FunctionDecls can't be in a Record (only CXXMethodDecls can). // 2. It is mirroring the behavior of DWARFASTParserClang::ParseSubroutine. FunctionDecl *func = m_ast->CreateFunctionDeclaration( - TU, OptionalClangModuleID(), "foo", clang_type, 0, false); + TU, OptionalClangModuleID(), "foo", clang_type, StorageClass::SC_None, + false); TypeSystemClang::TemplateParameterInfos empty_params; // Create the actual function template. clang::FunctionTemplateDecl *func_template = m_ast->CreateFunctionTemplateDecl(record, OptionalClangModuleID(), func, - "foo", empty_params); + empty_params); EXPECT_EQ(record, func_template->getDeclContext()); EXPECT_EQ("foo", func_template->getName()); @@ -722,3 +910,27 @@ TEST_F(TestTypeSystemClang, AddMethodToObjCObjectType) { EXPECT_FALSE(method->isDirectMethod()); EXPECT_EQ(method->getDeclName().getObjCSelector().getAsString(), "foo"); } + +TEST(TestScratchTypeSystemClang, InferSubASTFromLangOpts) { + LangOptions lang_opts; + EXPECT_EQ( + ScratchTypeSystemClang::DefaultAST, + ScratchTypeSystemClang::InferIsolatedASTKindFromLangOpts(lang_opts)); + + lang_opts.Modules = true; + EXPECT_EQ( + ScratchTypeSystemClang::IsolatedASTKind::CppModules, + ScratchTypeSystemClang::InferIsolatedASTKindFromLangOpts(lang_opts)); +} + +TEST_F(TestTypeSystemClang, GetExeModuleWhenMissingSymbolFile) { + CompilerType compiler_type = m_ast->GetBasicTypeFromAST(lldb::eBasicTypeInt); + lldb_private::Type t(0, nullptr, ConstString("MyType"), llvm::None, nullptr, + 0, {}, {}, compiler_type, + lldb_private::Type::ResolveState::Full); + // Test that getting the execution module when no type system is present + // is handled gracefully. + ModuleSP module = t.GetExeModule(); + EXPECT_EQ(module.get(), nullptr); +} + diff --git a/gnu/llvm/lldb/unittests/SymbolFile/DWARF/CMakeLists.txt b/gnu/llvm/lldb/unittests/SymbolFile/DWARF/CMakeLists.txt index 64a7b78c478..76215c31b2a 100644 --- a/gnu/llvm/lldb/unittests/SymbolFile/DWARF/CMakeLists.txt +++ b/gnu/llvm/lldb/unittests/SymbolFile/DWARF/CMakeLists.txt @@ -1,5 +1,7 @@ add_lldb_unittest(SymbolFileDWARFTests DWARFASTParserClangTests.cpp + DWARFDIETest.cpp + DWARFUnitTest.cpp SymbolFileDWARFTests.cpp XcodeSDKModuleTests.cpp @@ -11,8 +13,9 @@ add_lldb_unittest(SymbolFileDWARFTests lldbPluginSymbolFileDWARF lldbPluginSymbolFilePDB lldbPluginTypeSystemClang - lldbUtilityHelpers lldbPluginPlatformMacOSX + lldbUtilityHelpers + lldbSymbolHelpers LINK_COMPONENTS Support DebugInfoPDB diff --git a/gnu/llvm/lldb/unittests/SymbolFile/DWARF/DWARFASTParserClangTests.cpp b/gnu/llvm/lldb/unittests/SymbolFile/DWARF/DWARFASTParserClangTests.cpp index 858aa61b19b..435da1f9643 100644 --- a/gnu/llvm/lldb/unittests/SymbolFile/DWARF/DWARFASTParserClangTests.cpp +++ b/gnu/llvm/lldb/unittests/SymbolFile/DWARF/DWARFASTParserClangTests.cpp @@ -39,62 +39,63 @@ TEST_F(DWARFASTParserClangTests, EnsureAllDIEsInDeclContextHaveBeenParsedParsesOnlyMatchingEntries) { /// Auxiliary debug info. - const char *yamldata = - "debug_abbrev:\n" - " - Code: 0x00000001\n" - " Tag: DW_TAG_compile_unit\n" - " Children: DW_CHILDREN_yes\n" - " Attributes:\n" - " - Attribute: DW_AT_language\n" - " Form: DW_FORM_data2\n" - " - Code: 0x00000002\n" - " Tag: DW_TAG_base_type\n" - " Children: DW_CHILDREN_no\n" - " Attributes:\n" - " - Attribute: DW_AT_encoding\n" - " Form: DW_FORM_data1\n" - " - Attribute: DW_AT_byte_size\n" - " Form: DW_FORM_data1\n" - "debug_info:\n" - " - Length: 0\n" - " Version: 4\n" - " AbbrOffset: 0\n" - " AddrSize: 8\n" - " Entries:\n" - " - AbbrCode: 0x00000001\n" - " Values:\n" - " - Value: 0x000000000000000C\n" - // 0x0000000e: - " - AbbrCode: 0x00000002\n" - " Values:\n" - " - Value: 0x0000000000000007\n" // DW_ATE_unsigned - " - Value: 0x0000000000000004\n" - // 0x00000011: - " - AbbrCode: 0x00000002\n" - " Values:\n" - " - Value: 0x0000000000000007\n" // DW_ATE_unsigned - " - Value: 0x0000000000000008\n" - // 0x00000014: - " - AbbrCode: 0x00000002\n" - " Values:\n" - " - Value: 0x0000000000000005\n" // DW_ATE_signed - " - Value: 0x0000000000000008\n" - // 0x00000017: - " - AbbrCode: 0x00000002\n" - " Values:\n" - " - Value: 0x0000000000000008\n" // DW_ATE_unsigned_char - " - Value: 0x0000000000000001\n" - "" - " - AbbrCode: 0x00000000\n" - " Values: []\n"; + const char *yamldata = R"( +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_386 +DWARF: + debug_abbrev: + - Table: + - Code: 0x00000001 + Tag: DW_TAG_compile_unit + Children: DW_CHILDREN_yes + Attributes: + - Attribute: DW_AT_language + Form: DW_FORM_data2 + - Code: 0x00000002 + Tag: DW_TAG_base_type + Children: DW_CHILDREN_no + Attributes: + - Attribute: DW_AT_encoding + Form: DW_FORM_data1 + - Attribute: DW_AT_byte_size + Form: DW_FORM_data1 + debug_info: + - Version: 4 + AddrSize: 8 + Entries: + - AbbrCode: 0x00000001 + Values: + - Value: 0x000000000000000C + - AbbrCode: 0x00000002 + Values: + - Value: 0x0000000000000007 # DW_ATE_unsigned + - Value: 0x0000000000000004 + - AbbrCode: 0x00000002 + Values: + - Value: 0x0000000000000007 # DW_ATE_unsigned + - Value: 0x0000000000000008 + - AbbrCode: 0x00000002 + Values: + - Value: 0x0000000000000005 # DW_ATE_signed + - Value: 0x0000000000000008 + - AbbrCode: 0x00000002 + Values: + - Value: 0x0000000000000008 # DW_ATE_unsigned_char + - Value: 0x0000000000000001 + - AbbrCode: 0x00000000 +)"; - YAMLModuleTester t(yamldata, "i386-unknown-linux"); + YAMLModuleTester t(yamldata); ASSERT_TRUE((bool)t.GetDwarfUnit()); TypeSystemClang ast_ctx("dummy ASTContext", HostInfoBase::GetTargetTriple()); DWARFASTParserClangStub ast_parser(ast_ctx); - DWARFUnit *unit = t.GetDwarfUnit().get(); + DWARFUnit *unit = t.GetDwarfUnit(); const DWARFDebugInfoEntry *die_first = unit->DIE().GetDIE(); const DWARFDebugInfoEntry *die_child0 = die_first->GetFirstChild(); const DWARFDebugInfoEntry *die_child1 = die_child0->GetSibling(); diff --git a/gnu/llvm/lldb/unittests/SymbolFile/DWARF/DWARFDIETest.cpp b/gnu/llvm/lldb/unittests/SymbolFile/DWARF/DWARFDIETest.cpp new file mode 100644 index 00000000000..7fc37cefea2 --- /dev/null +++ b/gnu/llvm/lldb/unittests/SymbolFile/DWARF/DWARFDIETest.cpp @@ -0,0 +1,105 @@ +//===-- DWARFDIETest.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 "Plugins/SymbolFile/DWARF/DWARFDIE.h" +#include "TestingSupport/Symbol/YAMLModuleTester.h" +#include "llvm/ADT/STLExtras.h" +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +using namespace lldb; +using namespace lldb_private; + +TEST(DWARFDIETest, ChildIteration) { + // Tests DWARFDIE::child_iterator. + + const char *yamldata = R"( +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_386 +DWARF: + debug_abbrev: + - Table: + - Code: 0x00000001 + Tag: DW_TAG_compile_unit + Children: DW_CHILDREN_yes + Attributes: + - Attribute: DW_AT_language + Form: DW_FORM_data2 + - Code: 0x00000002 + Tag: DW_TAG_base_type + Children: DW_CHILDREN_no + Attributes: + - Attribute: DW_AT_encoding + Form: DW_FORM_data1 + - Attribute: DW_AT_byte_size + Form: DW_FORM_data1 + debug_info: + - Version: 4 + AddrSize: 8 + Entries: + - AbbrCode: 0x00000001 + Values: + - Value: 0x000000000000000C + - AbbrCode: 0x00000002 + Values: + - Value: 0x0000000000000007 # DW_ATE_unsigned + - Value: 0x0000000000000004 + - AbbrCode: 0x00000002 + Values: + - Value: 0x0000000000000007 # DW_ATE_unsigned + - Value: 0x0000000000000008 + - AbbrCode: 0x00000002 + Values: + - Value: 0x0000000000000005 # DW_ATE_signed + - Value: 0x0000000000000008 + - AbbrCode: 0x00000000 +)"; + + YAMLModuleTester t(yamldata); + ASSERT_TRUE((bool)t.GetDwarfUnit()); + + DWARFUnit *unit = t.GetDwarfUnit(); + const DWARFDebugInfoEntry *die_first = unit->DIE().GetDIE(); + + // Create a DWARFDIE that has three DW_TAG_base_type children. + DWARFDIE top_die(unit, die_first); + + // Create the iterator range that has the three tags as elements. + llvm::iterator_range children = top_die.children(); + + // Compare begin() to the first child DIE. + DWARFDIE::child_iterator child_iter = children.begin(); + ASSERT_NE(child_iter, children.end()); + const DWARFDebugInfoEntry *die_child0 = die_first->GetFirstChild(); + EXPECT_EQ((*child_iter).GetDIE(), die_child0); + + // Step to the second child DIE. + ++child_iter; + ASSERT_NE(child_iter, children.end()); + const DWARFDebugInfoEntry *die_child1 = die_child0->GetSibling(); + EXPECT_EQ((*child_iter).GetDIE(), die_child1); + + // Step to the third child DIE. + ++child_iter; + ASSERT_NE(child_iter, children.end()); + const DWARFDebugInfoEntry *die_child2 = die_child1->GetSibling(); + EXPECT_EQ((*child_iter).GetDIE(), die_child2); + + // Step to the end of the range. + ++child_iter; + EXPECT_EQ(child_iter, children.end()); + + // Take one of the DW_TAG_base_type DIEs (which has no children) and make + // sure the children range is now empty. + DWARFDIE no_children_die(unit, die_child0); + EXPECT_TRUE(no_children_die.children().empty()); +} diff --git a/gnu/llvm/lldb/unittests/SymbolFile/DWARF/DWARFUnitTest.cpp b/gnu/llvm/lldb/unittests/SymbolFile/DWARF/DWARFUnitTest.cpp new file mode 100644 index 00000000000..f5cfd1e6112 --- /dev/null +++ b/gnu/llvm/lldb/unittests/SymbolFile/DWARF/DWARFUnitTest.cpp @@ -0,0 +1,86 @@ +//===-- DWARFUnitTest.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 "Plugins/SymbolFile/DWARF/DWARFUnit.h" +#include "TestingSupport/Symbol/YAMLModuleTester.h" +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +using namespace lldb; +using namespace lldb_private; + +TEST(DWARFUnitTest, NullUnitDie) { + // Make sure we don't crash parsing a null unit DIE. + const char *yamldata = R"( +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_386 +DWARF: + debug_abbrev: + - Table: + - Code: 0x00000001 + Tag: DW_TAG_compile_unit + Children: DW_CHILDREN_yes + Attributes: + - Attribute: DW_AT_language + Form: DW_FORM_data2 + debug_info: + - Version: 4 + AddrSize: 8 + Entries: + - AbbrCode: 0x00000000 +)"; + + YAMLModuleTester t(yamldata); + ASSERT_TRUE((bool)t.GetDwarfUnit()); + + DWARFUnit *unit = t.GetDwarfUnit(); + const DWARFDebugInfoEntry *die_first = unit->DIE().GetDIE(); + ASSERT_NE(die_first, nullptr); + EXPECT_TRUE(die_first->IsNULL()); +} + +TEST(DWARFUnitTest, MissingSentinel) { + // Make sure we don't crash if the debug info is missing a null DIE sentinel. + const char *yamldata = R"( +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_386 +DWARF: + debug_abbrev: + - Table: + - Code: 0x00000001 + Tag: DW_TAG_compile_unit + Children: DW_CHILDREN_yes + Attributes: + - Attribute: DW_AT_language + Form: DW_FORM_data2 + debug_info: + - Version: 4 + AddrSize: 8 + Entries: + - AbbrCode: 0x00000001 + Values: + - Value: 0x000000000000000C +)"; + + YAMLModuleTester t(yamldata); + ASSERT_TRUE((bool)t.GetDwarfUnit()); + + DWARFUnit *unit = t.GetDwarfUnit(); + const DWARFDebugInfoEntry *die_first = unit->DIE().GetDIE(); + ASSERT_NE(die_first, nullptr); + EXPECT_EQ(die_first->GetFirstChild(), nullptr); + EXPECT_EQ(die_first->GetSibling(), nullptr); +} diff --git a/gnu/llvm/lldb/unittests/SymbolFile/DWARF/SymbolFileDWARFTests.cpp b/gnu/llvm/lldb/unittests/SymbolFile/DWARF/SymbolFileDWARFTests.cpp index 8bf019ea9ed..92fb798d5d4 100644 --- a/gnu/llvm/lldb/unittests/SymbolFile/DWARF/SymbolFileDWARFTests.cpp +++ b/gnu/llvm/lldb/unittests/SymbolFile/DWARF/SymbolFileDWARFTests.cpp @@ -19,6 +19,7 @@ #include "Plugins/SymbolFile/DWARF/DWARFDataExtractor.h" #include "Plugins/SymbolFile/DWARF/DWARFDebugAbbrev.h" #include "Plugins/SymbolFile/DWARF/DWARFDebugArangeSet.h" +#include "Plugins/SymbolFile/DWARF/DWARFDebugAranges.h" #include "Plugins/SymbolFile/DWARF/SymbolFileDWARF.h" #include "Plugins/SymbolFile/PDB/SymbolFilePDB.h" #include "Plugins/TypeSystem/Clang/TypeSystemClang.h" @@ -70,7 +71,7 @@ TEST_F(SymbolFileDWARFTests, TestAbilitiesForDWARF) { TEST_F(SymbolFileDWARFTests, TestAbbrevOrder1Start1) { // Test that if we have a .debug_abbrev that contains ordered abbreviation // codes that start at 1, that we get O(1) access. - + const auto byte_order = eByteOrderLittle; const uint8_t addr_size = 4; StreamString encoder(Stream::eBinary, addr_size, byte_order); @@ -81,7 +82,7 @@ TEST_F(SymbolFileDWARFTests, TestAbbrevOrder1Start1) { encoder.PutULEB128(DW_FORM_strp); encoder.PutULEB128(0); encoder.PutULEB128(0); - + encoder.PutULEB128(2); // Abbrev code 2 encoder.PutULEB128(DW_TAG_subprogram); encoder.PutHex8(DW_CHILDREN_no); @@ -89,9 +90,9 @@ TEST_F(SymbolFileDWARFTests, TestAbbrevOrder1Start1) { encoder.PutULEB128(DW_FORM_strp); encoder.PutULEB128(0); encoder.PutULEB128(0); - + encoder.PutULEB128(0); // Abbrev code 0 (termination) - + DWARFDataExtractor data; data.SetData(encoder.GetData(), encoder.GetSize(), byte_order); DWARFAbbreviationDeclarationSet abbrev_set; @@ -101,7 +102,7 @@ TEST_F(SymbolFileDWARFTests, TestAbbrevOrder1Start1) { // Make sure we have O(1) access to each abbreviation by making sure the // index offset is 1 and not UINT32_MAX EXPECT_EQ(abbrev_set.GetIndexOffset(), 1u); - + auto abbrev1 = abbrev_set.GetAbbreviationDeclaration(1); EXPECT_EQ(abbrev1->Tag(), DW_TAG_compile_unit); EXPECT_TRUE(abbrev1->HasChildren()); @@ -115,7 +116,7 @@ TEST_F(SymbolFileDWARFTests, TestAbbrevOrder1Start1) { TEST_F(SymbolFileDWARFTests, TestAbbrevOrder1Start5) { // Test that if we have a .debug_abbrev that contains ordered abbreviation // codes that start at 5, that we get O(1) access. - + const auto byte_order = eByteOrderLittle; const uint8_t addr_size = 4; StreamString encoder(Stream::eBinary, addr_size, byte_order); @@ -126,7 +127,7 @@ TEST_F(SymbolFileDWARFTests, TestAbbrevOrder1Start5) { encoder.PutULEB128(DW_FORM_strp); encoder.PutULEB128(0); encoder.PutULEB128(0); - + encoder.PutULEB128(6); // Abbrev code 6 encoder.PutULEB128(DW_TAG_subprogram); encoder.PutHex8(DW_CHILDREN_no); @@ -134,9 +135,9 @@ TEST_F(SymbolFileDWARFTests, TestAbbrevOrder1Start5) { encoder.PutULEB128(DW_FORM_strp); encoder.PutULEB128(0); encoder.PutULEB128(0); - + encoder.PutULEB128(0); // Abbrev code 0 (termination) - + DWARFDataExtractor data; data.SetData(encoder.GetData(), encoder.GetSize(), byte_order); DWARFAbbreviationDeclarationSet abbrev_set; @@ -146,7 +147,7 @@ TEST_F(SymbolFileDWARFTests, TestAbbrevOrder1Start5) { // Make sure we have O(1) access to each abbreviation by making sure the // index offset is 5 and not UINT32_MAX EXPECT_EQ(abbrev_set.GetIndexOffset(), 5u); - + auto abbrev1 = abbrev_set.GetAbbreviationDeclaration(5); EXPECT_EQ(abbrev1->Tag(), DW_TAG_compile_unit); EXPECT_TRUE(abbrev1->HasChildren()); @@ -160,7 +161,7 @@ TEST_F(SymbolFileDWARFTests, TestAbbrevOrder1Start5) { TEST_F(SymbolFileDWARFTests, TestAbbrevOutOfOrder) { // Test that if we have a .debug_abbrev that contains unordered abbreviation // codes, that we can access the information correctly. - + const auto byte_order = eByteOrderLittle; const uint8_t addr_size = 4; StreamString encoder(Stream::eBinary, addr_size, byte_order); @@ -171,7 +172,7 @@ TEST_F(SymbolFileDWARFTests, TestAbbrevOutOfOrder) { encoder.PutULEB128(DW_FORM_strp); encoder.PutULEB128(0); encoder.PutULEB128(0); - + encoder.PutULEB128(1); // Abbrev code 1 encoder.PutULEB128(DW_TAG_subprogram); encoder.PutHex8(DW_CHILDREN_no); @@ -179,9 +180,9 @@ TEST_F(SymbolFileDWARFTests, TestAbbrevOutOfOrder) { encoder.PutULEB128(DW_FORM_strp); encoder.PutULEB128(0); encoder.PutULEB128(0); - + encoder.PutULEB128(0); // Abbrev code 0 (termination) - + DWARFDataExtractor data; data.SetData(encoder.GetData(), encoder.GetSize(), byte_order); DWARFAbbreviationDeclarationSet abbrev_set; @@ -191,7 +192,7 @@ TEST_F(SymbolFileDWARFTests, TestAbbrevOutOfOrder) { // Make sure we don't have O(1) access to each abbreviation by making sure // the index offset is UINT32_MAX EXPECT_EQ(abbrev_set.GetIndexOffset(), UINT32_MAX); - + auto abbrev1 = abbrev_set.GetAbbreviationDeclaration(2); EXPECT_EQ(abbrev1->Tag(), DW_TAG_compile_unit); EXPECT_TRUE(abbrev1->HasChildren()); @@ -205,7 +206,7 @@ TEST_F(SymbolFileDWARFTests, TestAbbrevOutOfOrder) { TEST_F(SymbolFileDWARFTests, TestAbbrevInvalidNULLTag) { // Test that we detect when an abbreviation has a NULL tag and that we get // an error when decoding. - + const auto byte_order = eByteOrderLittle; const uint8_t addr_size = 4; StreamString encoder(Stream::eBinary, addr_size, byte_order); @@ -214,9 +215,9 @@ TEST_F(SymbolFileDWARFTests, TestAbbrevInvalidNULLTag) { encoder.PutHex8(DW_CHILDREN_no); encoder.PutULEB128(0); encoder.PutULEB128(0); - + encoder.PutULEB128(0); // Abbrev code 0 (termination) - + DWARFDataExtractor data; data.SetData(encoder.GetData(), encoder.GetSize(), byte_order); DWARFAbbreviationDeclarationSet abbrev_set; @@ -232,7 +233,7 @@ TEST_F(SymbolFileDWARFTests, TestAbbrevInvalidNULLTag) { TEST_F(SymbolFileDWARFTests, TestAbbrevNullAttrValidForm) { // Test that we detect when an abbreviation has a NULL attribute and a non // NULL form and that we get an error when decoding. - + const auto byte_order = eByteOrderLittle; const uint8_t addr_size = 4; StreamString encoder(Stream::eBinary, addr_size, byte_order); @@ -245,7 +246,7 @@ TEST_F(SymbolFileDWARFTests, TestAbbrevNullAttrValidForm) { encoder.PutULEB128(0); encoder.PutULEB128(0); // Abbrev code 0 (termination) - + DWARFDataExtractor data; data.SetData(encoder.GetData(), encoder.GetSize(), byte_order); DWARFAbbreviationDeclarationSet abbrev_set; @@ -255,13 +256,12 @@ TEST_F(SymbolFileDWARFTests, TestAbbrevNullAttrValidForm) { EXPECT_TRUE(bool(error)); EXPECT_EQ("malformed abbreviation declaration attribute", llvm::toString(std::move(error))); - } TEST_F(SymbolFileDWARFTests, TestAbbrevValidAttrNullForm) { // Test that we detect when an abbreviation has a valid attribute and a // NULL form and that we get an error when decoding. - + const auto byte_order = eByteOrderLittle; const uint8_t addr_size = 4; StreamString encoder(Stream::eBinary, addr_size, byte_order); @@ -272,9 +272,9 @@ TEST_F(SymbolFileDWARFTests, TestAbbrevValidAttrNullForm) { encoder.PutULEB128(0); // NULL form encoder.PutULEB128(0); encoder.PutULEB128(0); - + encoder.PutULEB128(0); // Abbrev code 0 (termination) - + DWARFDataExtractor data; data.SetData(encoder.GetData(), encoder.GetSize(), byte_order); DWARFAbbreviationDeclarationSet abbrev_set; @@ -290,7 +290,7 @@ TEST_F(SymbolFileDWARFTests, TestAbbrevMissingTerminator) { // Test that we detect when an abbreviation has a valid attribute and a // form, but is missing the NULL attribute and form that terminates an // abbreviation - + const auto byte_order = eByteOrderLittle; const uint8_t addr_size = 4; StreamString encoder(Stream::eBinary, addr_size, byte_order); @@ -300,7 +300,7 @@ TEST_F(SymbolFileDWARFTests, TestAbbrevMissingTerminator) { encoder.PutULEB128(DW_AT_name); encoder.PutULEB128(DW_FORM_strp); // Don't add the NULL DW_AT and NULL DW_FORM terminator - + DWARFDataExtractor data; data.SetData(encoder.GetData(), encoder.GetSize(), byte_order); DWARFAbbreviationDeclarationSet abbrev_set; @@ -346,3 +346,186 @@ TEST_F(SymbolFileDWARFTests, ParseArangesNonzeroSegmentSize) { llvm::toString(std::move(error))); EXPECT_EQ(off, 12U); // Parser should read no further than the segment size } + +TEST_F(SymbolFileDWARFTests, ParseArangesWithMultipleTerminators) { + // This .debug_aranges set has multiple terminator entries which appear in + // binaries produced by popular linux compilers and linker combinations. We + // must be able to parse all the way through the data for each + // DWARFDebugArangeSet. Previously the DWARFDebugArangeSet::extract() + // function would stop parsing as soon as we ran into a terminator even + // though the length field stated that there was more data that follows. This + // would cause the next DWARFDebugArangeSet to be parsed immediately + // following the first terminator and it would attempt to decode the + // DWARFDebugArangeSet header using the remaining segment + address pairs + // from the remaining bytes. + unsigned char binary_data[] = { + 0, 0, 0, 0, // unit_length that will be set correctly after this + 0, 2, // DWARF version number (uint16_t) + 0, 0, 0, 0, // CU offset (ignored for the purposes of this test) + 4, // address size + 0, // segment size + 0, 0, 0, 0, // alignment for the first tuple + // BEGIN TUPLES + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // premature terminator + 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, // [0x1000-0x1100) + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // premature terminator + 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x10, // [0x2000-0x2010) + // END TUPLES + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // terminator + }; + // Set the big endian length correctly. + const offset_t binary_data_size = sizeof(binary_data); + binary_data[3] = (uint8_t)binary_data_size - 4; + DWARFDataExtractor data; + data.SetData(static_cast(binary_data), sizeof binary_data, + lldb::ByteOrder::eByteOrderBig); + DWARFDebugArangeSet set; + offset_t off = 0; + llvm::Error error = set.extract(data, &off); + // Multiple terminators are not fatal as they do appear in binaries. + EXPECT_FALSE(bool(error)); + // Parser should read all terminators to the end of the length specified. + EXPECT_EQ(off, binary_data_size); + ASSERT_EQ(set.NumDescriptors(), 2U); + ASSERT_EQ(set.GetDescriptorRef(0).address, (dw_addr_t)0x1000); + ASSERT_EQ(set.GetDescriptorRef(0).length, (dw_addr_t)0x100); + ASSERT_EQ(set.GetDescriptorRef(1).address, (dw_addr_t)0x2000); + ASSERT_EQ(set.GetDescriptorRef(1).length, (dw_addr_t)0x10); +} + +TEST_F(SymbolFileDWARFTests, ParseArangesIgnoreEmpty) { + // This .debug_aranges set has some address ranges which have zero length + // and we ensure that these are ignored by our DWARFDebugArangeSet parser + // and not included in the descriptors that are returned. + unsigned char binary_data[] = { + 0, 0, 0, 0, // unit_length that will be set correctly after this + 0, 2, // DWARF version number (uint16_t) + 0, 0, 0, 0, // CU offset (ignored for the purposes of this test) + 4, // address size + 0, // segment size + 0, 0, 0, 0, // alignment for the first tuple + // BEGIN TUPLES + 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, // [0x1000-0x1100) + 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, // [0x1100-0x1100) + 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x10, // [0x2000-0x2010) + 0x00, 0x00, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, // [0x2010-0x2010) + // END TUPLES + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // terminator + }; + // Set the big endian length correctly. + const offset_t binary_data_size = sizeof(binary_data); + binary_data[3] = (uint8_t)binary_data_size - 4; + DWARFDataExtractor data; + data.SetData(static_cast(binary_data), sizeof binary_data, + lldb::ByteOrder::eByteOrderBig); + DWARFDebugArangeSet set; + offset_t off = 0; + llvm::Error error = set.extract(data, &off); + // Multiple terminators are not fatal as they do appear in binaries. + EXPECT_FALSE(bool(error)); + // Parser should read all terminators to the end of the length specified. + // Previously the DWARFDebugArangeSet would stop at the first terminator + // entry and leave the offset in the middle of the current + // DWARFDebugArangeSet data, and that would cause the next extracted + // DWARFDebugArangeSet to fail. + EXPECT_EQ(off, binary_data_size); + ASSERT_EQ(set.NumDescriptors(), 2U); + ASSERT_EQ(set.GetDescriptorRef(0).address, (dw_addr_t)0x1000); + ASSERT_EQ(set.GetDescriptorRef(0).length, (dw_addr_t)0x100); + ASSERT_EQ(set.GetDescriptorRef(1).address, (dw_addr_t)0x2000); + ASSERT_EQ(set.GetDescriptorRef(1).length, (dw_addr_t)0x10); +} + +TEST_F(SymbolFileDWARFTests, ParseAranges) { + // Test we can successfully parse a DWARFDebugAranges. The initial error + // checking code had a bug where it would always return an empty address + // ranges for everything in .debug_aranges and no error. + unsigned char binary_data[] = { + 0, 0, 0, 0, // unit_length that will be set correctly after this + 2, 0, // DWARF version number + 255, 0, 0, 0, // offset into the .debug_info_table + 8, // address size + 0, // segment size + 0, 0, 0, 0, // pad bytes + // BEGIN TUPLES + // First tuple: [0x1000-0x1100) + 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Address 0x1000 + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Size 0x0100 + // Second tuple: [0x2000-0x2100) + 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Address 0x2000 + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Size 0x0100 + // Terminating tuple + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Terminator + }; + // Set the little endian length correctly. + binary_data[0] = sizeof(binary_data) - 4; + DWARFDataExtractor data; + data.SetData(static_cast(binary_data), sizeof binary_data, + lldb::ByteOrder::eByteOrderLittle); + DWARFDebugAranges debug_aranges; + debug_aranges.extract(data); + EXPECT_EQ(debug_aranges.GetNumRanges(), 2u); + EXPECT_EQ(debug_aranges.FindAddress(0x0fff), DW_INVALID_OFFSET); + EXPECT_EQ(debug_aranges.FindAddress(0x1000), 255u); + EXPECT_EQ(debug_aranges.FindAddress(0x1100 - 1), 255u); + EXPECT_EQ(debug_aranges.FindAddress(0x1100), DW_INVALID_OFFSET); + EXPECT_EQ(debug_aranges.FindAddress(0x1fff), DW_INVALID_OFFSET); + EXPECT_EQ(debug_aranges.FindAddress(0x2000), 255u); + EXPECT_EQ(debug_aranges.FindAddress(0x2100 - 1), 255u); + EXPECT_EQ(debug_aranges.FindAddress(0x2100), DW_INVALID_OFFSET); +} + +TEST_F(SymbolFileDWARFTests, ParseArangesSkipErrors) { + // Test we can successfully parse a DWARFDebugAranges that contains some + // valid DWARFDebugArangeSet objects and some with errors as long as their + // length is set correctly. This helps LLDB ensure that it can parse newer + // .debug_aranges version that LLDB currently doesn't support, or ignore + // errors in individual DWARFDebugArangeSet objects as long as the length + // is set correctly. + const unsigned char binary_data[] = { + // This DWARFDebugArangeSet is well formed and has a single address range + // for [0x1000-0x1100) with a CU offset of 0x00000000. + 0, 0, 0, 28, // unit_length that will be set correctly after this + 0, 2, // DWARF version number (uint16_t) + 0, 0, 0, 0, // CU offset = 0x00000000 + 4, // address size + 0, // segment size + 0, 0, 0, 0, // alignment for the first tuple + 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, // [0x1000-0x1100) + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // terminator + // This DWARFDebugArangeSet has the correct length, but an invalid + // version. We need to be able to skip this correctly and ignore it. + 0, 0, 0, 20, // unit_length that will be set correctly after this + 0, 44, // invalid DWARF version number (uint16_t) + 0, 0, 1, 0, // CU offset = 0x00000100 + 4, // address size + 0, // segment size + 0, 0, 0, 0, // alignment for the first tuple + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // terminator + // This DWARFDebugArangeSet is well formed and has a single address range + // for [0x2000-0x2100) with a CU offset of 0x00000000. + 0, 0, 0, 28, // unit_length that will be set correctly after this + 0, 2, // DWARF version number (uint16_t) + 0, 0, 2, 0, // CU offset = 0x00000200 + 4, // address size + 0, // segment size + 0, 0, 0, 0, // alignment for the first tuple + 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, // [0x2000-0x2100) + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // terminator + }; + + DWARFDataExtractor data; + data.SetData(static_cast(binary_data), sizeof binary_data, + lldb::ByteOrder::eByteOrderBig); + DWARFDebugAranges debug_aranges; + debug_aranges.extract(data); + EXPECT_EQ(debug_aranges.GetNumRanges(), 2u); + EXPECT_EQ(debug_aranges.FindAddress(0x0fff), DW_INVALID_OFFSET); + EXPECT_EQ(debug_aranges.FindAddress(0x1000), 0u); + EXPECT_EQ(debug_aranges.FindAddress(0x1100 - 1), 0u); + EXPECT_EQ(debug_aranges.FindAddress(0x1100), DW_INVALID_OFFSET); + EXPECT_EQ(debug_aranges.FindAddress(0x1fff), DW_INVALID_OFFSET); + EXPECT_EQ(debug_aranges.FindAddress(0x2000), 0x200u); + EXPECT_EQ(debug_aranges.FindAddress(0x2100 - 1), 0x200u); + EXPECT_EQ(debug_aranges.FindAddress(0x2100), DW_INVALID_OFFSET); +} diff --git a/gnu/llvm/lldb/unittests/SymbolFile/DWARF/XcodeSDKModuleTests.cpp b/gnu/llvm/lldb/unittests/SymbolFile/DWARF/XcodeSDKModuleTests.cpp index 399eaf7aa64..9fb4602a41e 100644 --- a/gnu/llvm/lldb/unittests/SymbolFile/DWARF/XcodeSDKModuleTests.cpp +++ b/gnu/llvm/lldb/unittests/SymbolFile/DWARF/XcodeSDKModuleTests.cpp @@ -21,54 +21,51 @@ using namespace lldb_private; #ifdef __APPLE__ namespace { class XcodeSDKModuleTests : public testing::Test { - void SetUp() override { - HostInfoBase::Initialize(); - PlatformMacOSX::Initialize(); - } - void TearDown() override { - PlatformMacOSX::Terminate(); - HostInfoBase::Terminate(); - } + SubsystemRAII subsystems; }; } // namespace TEST_F(XcodeSDKModuleTests, TestModuleGetXcodeSDK) { const char *yamldata = R"( -debug_str: - - MacOSX10.9.sdk -debug_abbrev: - - Code: 0x00000001 - Tag: DW_TAG_compile_unit - Children: DW_CHILDREN_no - Attributes: - - Attribute: DW_AT_language - Form: DW_FORM_data2 - - Attribute: DW_AT_APPLE_sdk - Form: DW_FORM_strp -debug_info: - - Length: 8 - Version: 2 - AbbrOffset: 0 - AddrSize: 8 - Entries: - - AbbrCode: 0x00000001 - Values: - - Value: 0x000000000000000C - - Value: 0x0000000000000000 - - AbbrCode: 0x00000000 - Values: [] +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_386 +DWARF: + debug_str: + - MacOSX10.9.sdk + debug_abbrev: + - Table: + - Code: 0x00000001 + Tag: DW_TAG_compile_unit + Children: DW_CHILDREN_no + Attributes: + - Attribute: DW_AT_language + Form: DW_FORM_data2 + - Attribute: DW_AT_APPLE_sdk + Form: DW_FORM_strp + debug_info: + - Version: 2 + AddrSize: 8 + Entries: + - AbbrCode: 0x00000001 + Values: + - Value: 0x000000000000000C + - Value: 0x0000000000000000 + - AbbrCode: 0x00000000 ... )"; - auto triple = "x86_64-apple-macosx"; - YAMLModuleTester t(yamldata, triple); - auto dwarf_unit_sp = t.GetDwarfUnit(); - auto *dwarf_cu = llvm::cast(dwarf_unit_sp.get()); - ASSERT_TRUE((bool)dwarf_cu); + YAMLModuleTester t(yamldata); + DWARFUnit *dwarf_unit = t.GetDwarfUnit(); + auto *dwarf_cu = llvm::cast(dwarf_unit); + ASSERT_TRUE(static_cast(dwarf_cu)); SymbolFileDWARF &sym_file = dwarf_cu->GetSymbolFileDWARF(); CompUnitSP comp_unit = sym_file.GetCompileUnitAtIndex(0); - ASSERT_TRUE((bool)comp_unit.get()); + ASSERT_TRUE(static_cast(comp_unit.get())); ModuleSP module = t.GetModule(); ASSERT_EQ(module->GetSourceMappingList().GetSize(), 0u); XcodeSDK sdk = sym_file.ParseXcodeSDK(*comp_unit); diff --git a/gnu/llvm/lldb/unittests/SymbolFile/NativePDB/PdbFPOProgramToDWARFExpressionTests.cpp b/gnu/llvm/lldb/unittests/SymbolFile/NativePDB/PdbFPOProgramToDWARFExpressionTests.cpp index 334a08f9203..3692f0c94c5 100644 --- a/gnu/llvm/lldb/unittests/SymbolFile/NativePDB/PdbFPOProgramToDWARFExpressionTests.cpp +++ b/gnu/llvm/lldb/unittests/SymbolFile/NativePDB/PdbFPOProgramToDWARFExpressionTests.cpp @@ -39,7 +39,7 @@ CheckValidProgramTranslation(llvm::StringRef fpo_program, std::string result; llvm::raw_string_ostream os(result); llvm::DWARFExpression(extractor, /*AddressSize=*/4, llvm::dwarf::DWARF32) - .print(os, nullptr, nullptr); + .print(os, llvm::DIDumpOptions(), nullptr, nullptr); // actual check ASSERT_EQ(expected_dwarf_expression, os.str()); diff --git a/gnu/llvm/lldb/unittests/SymbolFile/PDB/SymbolFilePDBTests.cpp b/gnu/llvm/lldb/unittests/SymbolFile/PDB/SymbolFilePDBTests.cpp index 072fe6aaf0f..7c7d1902eef 100644 --- a/gnu/llvm/lldb/unittests/SymbolFile/PDB/SymbolFilePDBTests.cpp +++ b/gnu/llvm/lldb/unittests/SymbolFile/PDB/SymbolFilePDBTests.cpp @@ -171,8 +171,9 @@ TEST_F(SymbolFilePDBTests, TestResolveSymbolContextBasename) { FileSpec header_spec("test-pdb.cpp"); SymbolContextList sc_list; + SourceLocationSpec location_spec(header_spec, /*line=*/0); uint32_t result_count = symfile->ResolveSymbolContext( - header_spec, 0, false, lldb::eSymbolContextCompUnit, sc_list); + location_spec, lldb::eSymbolContextCompUnit, sc_list); EXPECT_EQ(1u, result_count); EXPECT_TRUE(ContainsCompileUnit(sc_list, header_spec)); } @@ -190,8 +191,9 @@ TEST_F(SymbolFilePDBTests, TestResolveSymbolContextFullPath) { FileSpec header_spec( R"spec(D:\src\llvm\tools\lldb\unittests\SymbolFile\PDB\Inputs\test-pdb.cpp)spec"); SymbolContextList sc_list; + SourceLocationSpec location_spec(header_spec, /*line=*/0); uint32_t result_count = symfile->ResolveSymbolContext( - header_spec, 0, false, lldb::eSymbolContextCompUnit, sc_list); + location_spec, lldb::eSymbolContextCompUnit, sc_list); EXPECT_GE(1u, result_count); EXPECT_TRUE(ContainsCompileUnit(sc_list, header_spec)); } @@ -214,8 +216,10 @@ TEST_F(SymbolFilePDBTests, TestLookupOfHeaderFileWithInlines) { FileSpec alt_cpp_spec("test-pdb-alt.cpp"); for (const auto &hspec : header_specs) { SymbolContextList sc_list; + SourceLocationSpec location_spec(hspec, /*line=*/0, /*column=*/llvm::None, + /*check_inlines=*/true); uint32_t result_count = symfile->ResolveSymbolContext( - hspec, 0, true, lldb::eSymbolContextCompUnit, sc_list); + location_spec, lldb::eSymbolContextCompUnit, sc_list); EXPECT_EQ(2u, result_count); EXPECT_TRUE(ContainsCompileUnit(sc_list, main_cpp_spec)); EXPECT_TRUE(ContainsCompileUnit(sc_list, alt_cpp_spec)); @@ -238,8 +242,9 @@ TEST_F(SymbolFilePDBTests, TestLookupOfHeaderFileWithNoInlines) { FileSpec("test-pdb-nested.h")}; for (const auto &hspec : header_specs) { SymbolContextList sc_list; + SourceLocationSpec location_spec(hspec, /*line=*/0); uint32_t result_count = symfile->ResolveSymbolContext( - hspec, 0, false, lldb::eSymbolContextCompUnit, sc_list); + location_spec, lldb::eSymbolContextCompUnit, sc_list); EXPECT_EQ(0u, result_count); } } @@ -264,8 +269,9 @@ TEST_F(SymbolFilePDBTests, TestLineTablesMatchAll) { lldb::SymbolContextItem scope = lldb::eSymbolContextCompUnit | lldb::eSymbolContextLineEntry; - uint32_t count = - symfile->ResolveSymbolContext(source_file, 0, true, scope, sc_list); + SourceLocationSpec location_spec( + source_file, /*line=*/0, /*column=*/llvm::None, /*check_inlines=*/true); + uint32_t count = symfile->ResolveSymbolContext(location_spec, scope, sc_list); EXPECT_EQ(1u, count); SymbolContext sc; EXPECT_TRUE(sc_list.GetContextAtIndex(0, sc)); @@ -314,8 +320,9 @@ TEST_F(SymbolFilePDBTests, TestLineTablesMatchSpecific) { lldb::eSymbolContextCompUnit | lldb::eSymbolContextLineEntry; // First test with line 7, and verify that only line 7 entries are added. - uint32_t count = - symfile->ResolveSymbolContext(source_file, 7, true, scope, sc_list); + SourceLocationSpec location_spec( + source_file, /*line=*/7, /*column=*/llvm::None, /*check_inlines=*/true); + uint32_t count = symfile->ResolveSymbolContext(location_spec, scope, sc_list); EXPECT_EQ(1u, count); SymbolContext sc; EXPECT_TRUE(sc_list.GetContextAtIndex(0, sc)); @@ -331,7 +338,9 @@ TEST_F(SymbolFilePDBTests, TestLineTablesMatchSpecific) { sc_list.Clear(); // Then test with line 9, and verify that only line 9 entries are added. - count = symfile->ResolveSymbolContext(source_file, 9, true, scope, sc_list); + location_spec = SourceLocationSpec( + source_file, /*line=*/9, /*column=*/llvm::None, /*check_inlines=*/true); + count = symfile->ResolveSymbolContext(location_spec, scope, sc_list); EXPECT_EQ(1u, count); EXPECT_TRUE(sc_list.GetContextAtIndex(0, sc)); @@ -363,7 +372,7 @@ TEST_F(SymbolFilePDBTests, TestSimpleClassTypes) { CompilerType compiler_type = udt_type->GetForwardCompilerType(); EXPECT_TRUE(TypeSystemClang::IsClassType(compiler_type.GetOpaqueQualType())); EXPECT_EQ(GetGlobalConstantInteger(session, "sizeof_Class"), - udt_type->GetByteSize()); + udt_type->GetByteSize(nullptr)); } TEST_F(SymbolFilePDBTests, TestNestedClassTypes) { @@ -417,7 +426,7 @@ TEST_F(SymbolFilePDBTests, TestNestedClassTypes) { EXPECT_TRUE(TypeSystemClang::IsClassType(compiler_type.GetOpaqueQualType())); EXPECT_EQ(GetGlobalConstantInteger(session, "sizeof_NestedClass"), - udt_type->GetByteSize()); + udt_type->GetByteSize(nullptr)); } TEST_F(SymbolFilePDBTests, TestClassInNamespace) { @@ -461,7 +470,7 @@ TEST_F(SymbolFilePDBTests, TestClassInNamespace) { EXPECT_TRUE(TypeSystemClang::IsClassType(compiler_type.GetOpaqueQualType())); EXPECT_EQ(GetGlobalConstantInteger(session, "sizeof_NSClass"), - udt_type->GetByteSize()); + udt_type->GetByteSize(nullptr)); } TEST_F(SymbolFilePDBTests, TestEnumTypes) { @@ -491,7 +500,7 @@ TEST_F(SymbolFilePDBTests, TestEnumTypes) { std::string sizeof_var = "sizeof_"; sizeof_var.append(Enum); EXPECT_EQ(GetGlobalConstantInteger(session, sizeof_var), - enum_type->GetByteSize()); + enum_type->GetByteSize(nullptr)); } } @@ -539,7 +548,7 @@ TEST_F(SymbolFilePDBTests, TestTypedefs) { std::string sizeof_var = "sizeof_"; sizeof_var.append(Typedef); EXPECT_EQ(GetGlobalConstantInteger(session, sizeof_var), - typedef_type->GetByteSize()); + typedef_type->GetByteSize(nullptr)); } } diff --git a/gnu/llvm/lldb/unittests/Target/ExecutionContextTest.cpp b/gnu/llvm/lldb/unittests/Target/ExecutionContextTest.cpp index 5662fda7ea8..7456faf65f6 100644 --- a/gnu/llvm/lldb/unittests/Target/ExecutionContextTest.cpp +++ b/gnu/llvm/lldb/unittests/Target/ExecutionContextTest.cpp @@ -49,21 +49,21 @@ class DummyProcess : public Process { public: using Process::Process; - virtual bool CanDebug(lldb::TargetSP target, bool plugin_specified_by_name) { + bool CanDebug(lldb::TargetSP target, bool plugin_specified_by_name) override { return true; } - virtual Status DoDestroy() { return {}; } - virtual void RefreshStateAfterStop() {} - virtual size_t DoReadMemory(lldb::addr_t vm_addr, void *buf, size_t size, - Status &error) { + Status DoDestroy() override { return {}; } + void RefreshStateAfterStop() override {} + size_t DoReadMemory(lldb::addr_t vm_addr, void *buf, size_t size, + Status &error) override { return 0; } - virtual bool UpdateThreadList(ThreadList &old_thread_list, - ThreadList &new_thread_list) { + bool DoUpdateThreadList(ThreadList &old_thread_list, + ThreadList &new_thread_list) override { return false; } - virtual ConstString GetPluginName() { return ConstString("Dummy"); } - virtual uint32_t GetPluginVersion() { return 0; } + ConstString GetPluginName() override { return ConstString("Dummy"); } + uint32_t GetPluginVersion() override { return 0; } }; } // namespace diff --git a/gnu/llvm/lldb/unittests/Target/PathMappingListTest.cpp b/gnu/llvm/lldb/unittests/Target/PathMappingListTest.cpp index 66fd97c17f6..90b6f1134a2 100644 --- a/gnu/llvm/lldb/unittests/Target/PathMappingListTest.cpp +++ b/gnu/llvm/lldb/unittests/Target/PathMappingListTest.cpp @@ -6,9 +6,9 @@ // //===----------------------------------------------------------------------===// -#include "llvm/ADT/ArrayRef.h" #include "lldb/Target/PathMappingList.h" #include "lldb/Utility/FileSpec.h" +#include "llvm/ADT/ArrayRef.h" #include "gtest/gtest.h" #include @@ -19,6 +19,8 @@ struct Matches { FileSpec original; FileSpec remapped; Matches(const char *o, const char *r) : original(o), remapped(r) {} + Matches(const char *o, llvm::sys::path::Style style, const char *r) + : original(o, style), remapped(r) {} }; } // namespace @@ -112,3 +114,27 @@ TEST(PathMappingListTest, RemapRoot) { }; TestPathMappings(map, matches, fails); } + +#ifndef _WIN32 +TEST(PathMappingListTest, CrossPlatformTests) { + PathMappingList map; + map.Append(ConstString(R"(C:\old)"), ConstString("/new"), false); + Matches matches[] = { + {R"(C:\old)", llvm::sys::path::Style::windows, "/new"}, + {R"(C:\old\)", llvm::sys::path::Style::windows, "/new"}, + {R"(C:\old\foo\.)", llvm::sys::path::Style::windows, "/new/foo"}, + {R"(C:\old\foo.c)", llvm::sys::path::Style::windows, "/new/foo.c"}, + {R"(C:\old\foo.c\.)", llvm::sys::path::Style::windows, "/new/foo.c"}, + {R"(C:\old\.\foo.c)", llvm::sys::path::Style::windows, "/new/foo.c"}, + }; + ConstString fails[] = { + ConstString("/foo"), + ConstString("/"), + ConstString("foo.c"), + ConstString("./foo.c"), + ConstString("../foo.c"), + ConstString("../bar/foo.c"), + }; + TestPathMappings(map, matches, fails); +} +#endif diff --git a/gnu/llvm/lldb/unittests/Target/StackFrameRecognizerTest.cpp b/gnu/llvm/lldb/unittests/Target/StackFrameRecognizerTest.cpp index 067a56a1990..bf458b3b141 100644 --- a/gnu/llvm/lldb/unittests/Target/StackFrameRecognizerTest.cpp +++ b/gnu/llvm/lldb/unittests/Target/StackFrameRecognizerTest.cpp @@ -51,18 +51,14 @@ public: std::string GetName() override { return "Dummy StackFrame Recognizer"; } }; -void RegisterDummyStackFrameRecognizer() { - static llvm::once_flag g_once_flag; +void RegisterDummyStackFrameRecognizer(StackFrameRecognizerManager &manager) { + RegularExpressionSP module_regex_sp = nullptr; + RegularExpressionSP symbol_regex_sp(new RegularExpression("boom")); - llvm::call_once(g_once_flag, []() { - RegularExpressionSP module_regex_sp = nullptr; - RegularExpressionSP symbol_regex_sp(new RegularExpression("boom")); + StackFrameRecognizerSP dummy_recognizer_sp(new DummyStackFrameRecognizer()); - StackFrameRecognizerSP dummy_recognizer_sp(new DummyStackFrameRecognizer()); - - StackFrameRecognizerManager::AddRecognizer( - dummy_recognizer_sp, module_regex_sp, symbol_regex_sp, false); - }); + manager.AddRecognizer(dummy_recognizer_sp, module_regex_sp, symbol_regex_sp, + false); } } // namespace @@ -71,13 +67,15 @@ TEST_F(StackFrameRecognizerTest, NullModuleRegex) { DebuggerSP debugger_sp = Debugger::CreateInstance(); ASSERT_TRUE(debugger_sp); - RegisterDummyStackFrameRecognizer(); + StackFrameRecognizerManager manager; + + RegisterDummyStackFrameRecognizer(manager); bool any_printed = false; - StackFrameRecognizerManager::ForEach( - [&any_printed](uint32_t recognizer_id, std::string name, - std::string function, llvm::ArrayRef symbols, - bool regexp) { any_printed = true; }); + manager.ForEach([&any_printed](uint32_t recognizer_id, std::string name, + std::string function, + llvm::ArrayRef symbols, + bool regexp) { any_printed = true; }); EXPECT_TRUE(any_printed); } diff --git a/gnu/llvm/lldb/unittests/TestingSupport/CMakeLists.txt b/gnu/llvm/lldb/unittests/TestingSupport/CMakeLists.txt index 3b5662a16e3..c62bc3b023b 100644 --- a/gnu/llvm/lldb/unittests/TestingSupport/CMakeLists.txt +++ b/gnu/llvm/lldb/unittests/TestingSupport/CMakeLists.txt @@ -5,12 +5,11 @@ add_lldb_library(lldbUtilityHelpers LINK_LIBS lldbUtility - lldbSymbolHelpers + gtest LINK_COMPONENTS Support ObjectYAML ) -include_directories(${LLVM_MAIN_SRC_DIR}/utils/unittest/googletest/include) add_subdirectory(Symbol) diff --git a/gnu/llvm/lldb/unittests/TestingSupport/Host/NativeProcessTestUtils.h b/gnu/llvm/lldb/unittests/TestingSupport/Host/NativeProcessTestUtils.h index dcd8b092b2e..4efb18397d9 100644 --- a/gnu/llvm/lldb/unittests/TestingSupport/Host/NativeProcessTestUtils.h +++ b/gnu/llvm/lldb/unittests/TestingSupport/Host/NativeProcessTestUtils.h @@ -25,6 +25,15 @@ public: MOCK_METHOD2(ProcessStateChanged, void(NativeProcessProtocol *Process, StateType State)); MOCK_METHOD1(DidExec, void(NativeProcessProtocol *Process)); + MOCK_METHOD2(NewSubprocessImpl, + void(NativeProcessProtocol *parent_process, + std::unique_ptr &child_process)); + // This is a hack to avoid MOCK_METHOD2 incompatibility with std::unique_ptr + // passed as value. + void NewSubprocess(NativeProcessProtocol *parent_process, + std::unique_ptr child_process) { + NewSubprocessImpl(parent_process, child_process); + } }; // NB: This class doesn't use the override keyword to avoid @@ -41,9 +50,6 @@ public: MOCK_METHOD0(Detach, Status()); MOCK_METHOD1(Signal, Status(int Signo)); MOCK_METHOD0(Kill, Status()); - MOCK_METHOD3(AllocateMemory, - Status(size_t Size, uint32_t Permissions, addr_t &Addr)); - MOCK_METHOD1(DeallocateMemory, Status(addr_t Addr)); MOCK_METHOD0(GetSharedLibraryInfoAddress, addr_t()); MOCK_METHOD0(UpdateThreads, size_t()); MOCK_CONST_METHOD0(GetAuxvData, @@ -147,4 +153,4 @@ private: }; } // namespace lldb_private -#endif \ No newline at end of file +#endif diff --git a/gnu/llvm/lldb/unittests/TestingSupport/Symbol/CMakeLists.txt b/gnu/llvm/lldb/unittests/TestingSupport/Symbol/CMakeLists.txt index 3f93b941137..c4eef2e453d 100644 --- a/gnu/llvm/lldb/unittests/TestingSupport/Symbol/CMakeLists.txt +++ b/gnu/llvm/lldb/unittests/TestingSupport/Symbol/CMakeLists.txt @@ -1,13 +1,17 @@ set_property(DIRECTORY PROPERTY EXCLUDE_FROM_ALL ON) add_lldb_library(lldbSymbolHelpers YAMLModuleTester.cpp - ) -# Our current version of gtest does not properly recognize C++11 support -# with MSVC, so it falls back to tr1 / experimental classes. Since LLVM -# itself requires C++11, we can safely force it on unconditionally so that -# we don't have to fight with the buggy gtest check. -add_definitions(-DGTEST_LANG_CXX11=1) -add_definitions(-DGTEST_HAS_TR1_TUPLE=0) -include_directories(${LLVM_MAIN_SRC_DIR}/utils/unittest/googletest/include) -include_directories(${LLVM_MAIN_SRC_DIR}/utils/unittest/googlemock/include) + LINK_LIBS + lldbCore + lldbHost + lldbPluginExpressionParserClang + lldbPluginObjectFileELF + lldbPluginSymbolFileDWARF + lldbPluginTypeSystemClang + lldbUtilityHelpers + LLVMTestingSupport + + LINK_COMPONENTS + ObjectYAML + ) diff --git a/gnu/llvm/lldb/unittests/TestingSupport/Symbol/YAMLModuleTester.cpp b/gnu/llvm/lldb/unittests/TestingSupport/Symbol/YAMLModuleTester.cpp index 54c2c9441e5..15db62451f9 100644 --- a/gnu/llvm/lldb/unittests/TestingSupport/Symbol/YAMLModuleTester.cpp +++ b/gnu/llvm/lldb/unittests/TestingSupport/Symbol/YAMLModuleTester.cpp @@ -7,112 +7,20 @@ //===----------------------------------------------------------------------===// #include "TestingSupport/Symbol/YAMLModuleTester.h" +#include "Plugins/SymbolFile/DWARF/DWARFDebugInfo.h" #include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "lldb/Core/Section.h" #include "llvm/ObjectYAML/DWARFEmitter.h" using namespace lldb_private; -/// A mock module holding an object file parsed from YAML. -class YAMLModule : public lldb_private::Module { -public: - YAMLModule(ArchSpec &arch) : Module(FileSpec("test"), arch) {} - void SetObjectFile(lldb::ObjectFileSP obj_file) { m_objfile_sp = obj_file; } - ObjectFile *GetObjectFile() override { return m_objfile_sp.get(); } -}; +YAMLModuleTester::YAMLModuleTester(llvm::StringRef yaml_data) { + llvm::Expected File = TestFile::fromYaml(yaml_data); + EXPECT_THAT_EXPECTED(File, llvm::Succeeded()); + m_file = std::move(*File); -/// A mock object file that can be parsed from YAML. -class YAMLObjectFile : public lldb_private::ObjectFile { - const lldb::ModuleSP m_module_sp; - llvm::StringMap> &m_section_map; - /// Because there is only one DataExtractor in the ObjectFile - /// interface, all sections are copied into a contiguous buffer. - std::vector m_buffer; + m_module_sp = std::make_shared(m_file->moduleSpec()); + auto &symfile = *llvm::cast(m_module_sp->GetSymbolFile()); -public: - YAMLObjectFile(const lldb::ModuleSP &module_sp, - llvm::StringMap> &map) - : ObjectFile(module_sp, &module_sp->GetFileSpec(), /*file_offset*/ 0, - /*length*/ 0, /*data_sp*/ nullptr, /*data_offset*/ 0), - m_module_sp(module_sp), m_section_map(map) {} - - /// Callback for initializing the module's list of sections. - void CreateSections(SectionList &unified_section_list) override { - lldb::offset_t total_bytes = 0; - for (auto &entry : m_section_map) - total_bytes += entry.getValue()->getBufferSize(); - m_buffer.reserve(total_bytes); - m_data = - DataExtractor(m_buffer.data(), total_bytes, lldb::eByteOrderLittle, 4); - - lldb::user_id_t sect_id = 1; - for (auto &entry : m_section_map) { - llvm::StringRef name = entry.getKey(); - lldb::SectionType sect_type = - llvm::StringSwitch(name) - .Case("debug_info", lldb::eSectionTypeDWARFDebugInfo) - .Case("debug_abbrev", lldb::eSectionTypeDWARFDebugAbbrev) - .Case("debug_str", lldb::eSectionTypeDWARFDebugStr); - auto &membuf = entry.getValue(); - lldb::addr_t file_vm_addr = 0; - lldb::addr_t vm_size = 0; - lldb::offset_t file_offset = m_buffer.size(); - lldb::offset_t file_size = membuf->getBufferSize(); - m_buffer.resize(file_offset + file_size); - memcpy(m_buffer.data() + file_offset, membuf->getBufferStart(), - file_size); - uint32_t log2align = 0; - uint32_t flags = 0; - auto section_sp = std::make_shared( - m_module_sp, this, sect_id++, ConstString(name), sect_type, - file_vm_addr, vm_size, file_offset, file_size, log2align, flags); - unified_section_list.AddSection(section_sp); - } - } - - /// \{ - /// Stub methods that aren't needed here. - ConstString GetPluginName() override { return ConstString("YAMLObjectFile"); } - uint32_t GetPluginVersion() override { return 0; } - void Dump(Stream *s) override {} - uint32_t GetAddressByteSize() const override { return 8; } - uint32_t GetDependentModules(FileSpecList &file_list) override { return 0; } - bool IsExecutable() const override { return 0; } - ArchSpec GetArchitecture() override { return {}; } - Symtab *GetSymtab() override { return nullptr; } - bool IsStripped() override { return false; } - UUID GetUUID() override { return {}; } - lldb::ByteOrder GetByteOrder() const override { - return lldb::eByteOrderLittle; - } - bool ParseHeader() override { return false; } - Type CalculateType() override { return {}; } - Strata CalculateStrata() override { return {}; } - /// \} -}; - -YAMLModuleTester::YAMLModuleTester(llvm::StringRef yaml_data, - llvm::StringRef triple) { - auto sections_map = llvm::DWARFYAML::emitDebugSections(yaml_data, true); - if (!sections_map) - return; - m_sections_map = std::move(*sections_map); - ArchSpec arch(triple); - m_module_sp = std::make_shared(arch); - m_objfile_sp = std::make_shared(m_module_sp, m_sections_map); - static_cast(m_module_sp.get())->SetObjectFile(m_objfile_sp); - - lldb::user_id_t uid = 0; - llvm::StringRef raw_debug_info = m_sections_map["debug_info"]->getBuffer(); - lldb_private::DataExtractor debug_info( - raw_debug_info.data(), raw_debug_info.size(), - m_objfile_sp->GetByteOrder(), m_objfile_sp->GetAddressByteSize()); - lldb::offset_t offset_ptr = 0; - m_symfile_dwarf = std::make_unique(m_objfile_sp, nullptr); - llvm::Expected dwarf_unit = DWARFUnit::extract( - *m_symfile_dwarf, uid, - *static_cast(&debug_info), - DIERef::DebugInfo, &offset_ptr, nullptr); - if (dwarf_unit) - m_dwarf_unit = dwarf_unit.get(); + m_dwarf_unit = symfile.DebugInfo().GetUnitAtIndex(0); } diff --git a/gnu/llvm/lldb/unittests/TestingSupport/Symbol/YAMLModuleTester.h b/gnu/llvm/lldb/unittests/TestingSupport/Symbol/YAMLModuleTester.h index 7a638b56e87..60715ab2c16 100644 --- a/gnu/llvm/lldb/unittests/TestingSupport/Symbol/YAMLModuleTester.h +++ b/gnu/llvm/lldb/unittests/TestingSupport/Symbol/YAMLModuleTester.h @@ -9,10 +9,12 @@ #ifndef LLDB_UNITTESTS_TESTINGSUPPORT_SYMBOL_YAMLMODULETESTER_H #define LLDB_UNITTESTS_TESTINGSUPPORT_SYMBOL_YAMLMODULETESTER_H +#include "Plugins/ObjectFile/ELF/ObjectFileELF.h" #include "Plugins/SymbolFile/DWARF/DWARFUnit.h" #include "Plugins/SymbolFile/DWARF/SymbolFileDWARF.h" #include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "TestingSupport/SubsystemRAII.h" +#include "TestingSupport/TestUtilities.h" #include "lldb/Core/Module.h" #include "lldb/Host/HostInfo.h" @@ -22,17 +24,17 @@ namespace lldb_private { /// DWARF expressions on it. class YAMLModuleTester { protected: - SubsystemRAII subsystems; - llvm::StringMap> m_sections_map; + SubsystemRAII + subsystems; + llvm::Optional m_file; lldb::ModuleSP m_module_sp; - lldb::ObjectFileSP m_objfile_sp; - DWARFUnitSP m_dwarf_unit; - std::unique_ptr m_symfile_dwarf; + DWARFUnit *m_dwarf_unit; public: /// Parse the debug info sections from the YAML description. - YAMLModuleTester(llvm::StringRef yaml_data, llvm::StringRef triple); - DWARFUnitSP GetDwarfUnit() const { return m_dwarf_unit; } + YAMLModuleTester(llvm::StringRef yaml_data); + DWARFUnit *GetDwarfUnit() const { return m_dwarf_unit; } lldb::ModuleSP GetModule() const { return m_module_sp; } }; diff --git a/gnu/llvm/lldb/unittests/TestingSupport/TestUtilities.cpp b/gnu/llvm/lldb/unittests/TestingSupport/TestUtilities.cpp index 4d369bd0968..86f3d1a7dfa 100644 --- a/gnu/llvm/lldb/unittests/TestingSupport/TestUtilities.cpp +++ b/gnu/llvm/lldb/unittests/TestingSupport/TestUtilities.cpp @@ -27,8 +27,6 @@ std::string lldb_private::GetInputFilePath(const llvm::Twine &name) { } llvm::Expected TestFile::fromYaml(llvm::StringRef Yaml) { - assert(testing::UnitTest::GetInstance()->current_test_info()); - std::string Buffer; llvm::raw_string_ostream OS(Buffer); llvm::yaml::Input YIn(Yaml); @@ -40,8 +38,8 @@ llvm::Expected TestFile::fromYaml(llvm::StringRef Yaml) { llvm::Expected TestFile::fromYamlFile(const llvm::Twine &Name) { auto BufferOrError = - llvm::MemoryBuffer::getFile(GetInputFilePath(Name), /*FileSize*/ -1, - /*RequiresNullTerminator*/ false); + llvm::MemoryBuffer::getFile(GetInputFilePath(Name), /*IsText=*/false, + /*RequiresNullTerminator=*/false); if (!BufferOrError) return llvm::errorCodeToError(BufferOrError.getError()); return fromYaml(BufferOrError.get()->getBuffer()); diff --git a/gnu/llvm/lldb/unittests/TestingSupport/TestUtilities.h b/gnu/llvm/lldb/unittests/TestingSupport/TestUtilities.h index 60a07119e92..811c4c15212 100644 --- a/gnu/llvm/lldb/unittests/TestingSupport/TestUtilities.h +++ b/gnu/llvm/lldb/unittests/TestingSupport/TestUtilities.h @@ -36,8 +36,6 @@ public: static llvm::Expected fromYaml(llvm::StringRef Yaml); static llvm::Expected fromYamlFile(const llvm::Twine &Name); - ~TestFile() = default; - ModuleSpec moduleSpec() { return ModuleSpec(FileSpec(), UUID(), dataBuffer()); } @@ -45,8 +43,6 @@ public: private: TestFile(std::string &&Buffer) : Buffer(std::move(Buffer)) {} - void operator=(const TestFile &) = delete; - lldb::DataBufferSP dataBuffer() { auto *Data = reinterpret_cast(Buffer.data()); return std::make_shared(const_cast(Data), diff --git a/gnu/llvm/lldb/unittests/Thread/ThreadTest.cpp b/gnu/llvm/lldb/unittests/Thread/ThreadTest.cpp index 9a79bbc12ca..a8387a5f03f 100644 --- a/gnu/llvm/lldb/unittests/Thread/ThreadTest.cpp +++ b/gnu/llvm/lldb/unittests/Thread/ThreadTest.cpp @@ -42,21 +42,21 @@ class DummyProcess : public Process { public: using Process::Process; - virtual bool CanDebug(lldb::TargetSP target, bool plugin_specified_by_name) { + bool CanDebug(lldb::TargetSP target, bool plugin_specified_by_name) override { return true; } - virtual Status DoDestroy() { return {}; } - virtual void RefreshStateAfterStop() {} - virtual size_t DoReadMemory(lldb::addr_t vm_addr, void *buf, size_t size, - Status &error) { + Status DoDestroy() override { return {}; } + void RefreshStateAfterStop() override {} + size_t DoReadMemory(lldb::addr_t vm_addr, void *buf, size_t size, + Status &error) override { return 0; } - virtual bool UpdateThreadList(ThreadList &old_thread_list, - ThreadList &new_thread_list) { + bool DoUpdateThreadList(ThreadList &old_thread_list, + ThreadList &new_thread_list) override { return false; } - virtual ConstString GetPluginName() { return ConstString("Dummy"); } - virtual uint32_t GetPluginVersion() { return 0; } + ConstString GetPluginName() override { return ConstString("Dummy"); } + uint32_t GetPluginVersion() override { return 0; } ProcessModID &GetModIDNonConstRef() { return m_mod_id; } }; @@ -83,16 +83,11 @@ public: } // namespace TargetSP CreateTarget(DebuggerSP &debugger_sp, ArchSpec &arch) { - Status error; PlatformSP platform_sp; TargetSP target_sp; - error = debugger_sp->GetTargetList().CreateTarget( + debugger_sp->GetTargetList().CreateTarget( *debugger_sp, "", arch, eLoadDependentsNo, platform_sp, target_sp); - if (target_sp) { - debugger_sp->GetTargetList().SetSelectedTarget(target_sp.get()); - } - return target_sp; } diff --git a/gnu/llvm/lldb/unittests/Utility/ArchSpecTest.cpp b/gnu/llvm/lldb/unittests/Utility/ArchSpecTest.cpp index 4e8e2f3c34d..1ef646acdef 100644 --- a/gnu/llvm/lldb/unittests/Utility/ArchSpecTest.cpp +++ b/gnu/llvm/lldb/unittests/Utility/ArchSpecTest.cpp @@ -305,6 +305,33 @@ TEST(ArchSpecTest, Compatibility) { ArchSpec B("x86_64-apple-ios-simulator"); ASSERT_FALSE(A.IsExactMatch(B)); ASSERT_FALSE(A.IsCompatibleMatch(B)); + ASSERT_FALSE(B.IsExactMatch(A)); + ASSERT_FALSE(B.IsCompatibleMatch(A)); + } + { + ArchSpec A("x86_64-apple-ios"); + ArchSpec B("x86_64-apple-ios-simulator"); + ASSERT_FALSE(A.IsExactMatch(B)); + ASSERT_FALSE(A.IsCompatibleMatch(B)); + ASSERT_FALSE(B.IsExactMatch(A)); + ASSERT_FALSE(B.IsCompatibleMatch(A)); + } + { + // FIXME: This is surprisingly not equivalent to "x86_64-*-*". + ArchSpec A("x86_64"); + ArchSpec B("x86_64-apple-ios-simulator"); + ASSERT_FALSE(A.IsExactMatch(B)); + ASSERT_TRUE(A.IsCompatibleMatch(B)); + ASSERT_FALSE(B.IsExactMatch(A)); + ASSERT_TRUE(B.IsCompatibleMatch(A)); + } + { + ArchSpec A("arm64-apple-ios"); + ArchSpec B("arm64-apple-ios-simulator"); + ASSERT_FALSE(A.IsExactMatch(B)); + ASSERT_FALSE(A.IsCompatibleMatch(B)); + ASSERT_FALSE(B.IsCompatibleMatch(A)); + ASSERT_FALSE(B.IsCompatibleMatch(A)); } { ArchSpec A("arm64-*-*"); @@ -328,6 +355,40 @@ TEST(ArchSpecTest, Compatibility) { ASSERT_TRUE(A.IsExactMatch(B)); ASSERT_TRUE(A.IsCompatibleMatch(B)); } + { + ArchSpec A("x86_64"); + ArchSpec B("x86_64-apple-ios12.0.0-macabi"); + // FIXME: The exact match also looks unintuitive. + ASSERT_TRUE(A.IsExactMatch(B)); + ASSERT_TRUE(A.IsCompatibleMatch(B)); + } + { + ArchSpec A("x86_64-apple-ios12.0.0"); + ArchSpec B("x86_64-apple-ios12.0.0-macabi"); + ASSERT_FALSE(A.IsExactMatch(B)); + ASSERT_FALSE(A.IsCompatibleMatch(B)); + } + { + ArchSpec A("x86_64-apple-macosx10.14.2"); + ArchSpec B("x86_64-apple-ios12.0.0-macabi"); + ASSERT_FALSE(A.IsExactMatch(B)); + ASSERT_TRUE(A.IsCompatibleMatch(B)); + } + { + ArchSpec A("x86_64-apple-macosx10.14.2"); + ArchSpec B("x86_64-apple-ios12.0.0-macabi"); + // ios-macabi wins. + A.MergeFrom(B); + ASSERT_TRUE(A.IsExactMatch(B)); + } + { + ArchSpec A("x86_64-apple-macosx10.14.2"); + ArchSpec B("x86_64-apple-ios12.0.0-macabi"); + ArchSpec C(B); + // ios-macabi wins. + B.MergeFrom(A); + ASSERT_TRUE(B.IsExactMatch(C)); + } } TEST(ArchSpecTest, OperatorBool) { diff --git a/gnu/llvm/lldb/unittests/Utility/ArgsTest.cpp b/gnu/llvm/lldb/unittests/Utility/ArgsTest.cpp index ed1235f99c7..0b153a8d593 100644 --- a/gnu/llvm/lldb/unittests/Utility/ArgsTest.cpp +++ b/gnu/llvm/lldb/unittests/Utility/ArgsTest.cpp @@ -9,6 +9,7 @@ #include "gtest/gtest.h" #include "lldb/Utility/Args.h" +#include "lldb/Utility/FileSpec.h" #include "lldb/Utility/StringList.h" #include @@ -313,3 +314,31 @@ TEST(ArgsTest, Yaml) { EXPECT_EQ(entries[2].GetQuoteChar(), '"'); EXPECT_EQ(entries[3].GetQuoteChar(), '\0'); } + +TEST(ArgsTest, GetShellSafeArgument) { + // Try escaping with bash at start/middle/end of the argument. + FileSpec bash("/bin/bash", FileSpec::Style::posix); + EXPECT_EQ(Args::GetShellSafeArgument(bash, "\"b"), "\\\"b"); + EXPECT_EQ(Args::GetShellSafeArgument(bash, "a\""), "a\\\""); + EXPECT_EQ(Args::GetShellSafeArgument(bash, "a\"b"), "a\\\"b"); + + FileSpec zsh("/bin/zsh", FileSpec::Style::posix); + EXPECT_EQ(Args::GetShellSafeArgument(zsh, R"('";()<>&|\)"), + R"(\'\"\;\(\)\<\>\&\|\\)"); + // Normal characters and expressions that shouldn't be escaped. + EXPECT_EQ(Args::GetShellSafeArgument(zsh, "aA$1*"), "aA$1*"); + + // String that doesn't need to be escaped + EXPECT_EQ(Args::GetShellSafeArgument(bash, "a"), "a"); + + // Try escaping with tcsh and the tcsh-specific "$" escape. + FileSpec tcsh("/bin/tcsh", FileSpec::Style::posix); + EXPECT_EQ(Args::GetShellSafeArgument(tcsh, "a$b"), "a\\$b"); + // Bash however doesn't need escaping for "$". + EXPECT_EQ(Args::GetShellSafeArgument(bash, "a$b"), "a$b"); + + // Try escaping with an unknown shell. + FileSpec unknown_shell("/bin/unknown_shell", FileSpec::Style::posix); + EXPECT_EQ(Args::GetShellSafeArgument(unknown_shell, "a'b"), "a\\'b"); + EXPECT_EQ(Args::GetShellSafeArgument(unknown_shell, "a\"b"), "a\\\"b"); +} diff --git a/gnu/llvm/lldb/unittests/Utility/CMakeLists.txt b/gnu/llvm/lldb/unittests/Utility/CMakeLists.txt index c624c367492..3dd910412e6 100644 --- a/gnu/llvm/lldb/unittests/Utility/CMakeLists.txt +++ b/gnu/llvm/lldb/unittests/Utility/CMakeLists.txt @@ -29,6 +29,7 @@ add_lldb_unittest(UtilityTests StatusTest.cpp StreamTeeTest.cpp StreamTest.cpp + StringExtractorGDBRemoteTest.cpp StringExtractorTest.cpp StringLexerTest.cpp StringListTest.cpp diff --git a/gnu/llvm/lldb/unittests/Utility/FileSpecTest.cpp b/gnu/llvm/lldb/unittests/Utility/FileSpecTest.cpp index ad2e328ce82..3dd355284ce 100644 --- a/gnu/llvm/lldb/unittests/Utility/FileSpecTest.cpp +++ b/gnu/llvm/lldb/unittests/Utility/FileSpecTest.cpp @@ -305,7 +305,7 @@ TEST(FileSpecTest, IsRelative) { "~/", "~/a", "~/a/", - "~/a/b" + "~/a/b", "~/a/b/", "/foo/.", "/foo/..", diff --git a/gnu/llvm/lldb/unittests/Utility/RangeMapTest.cpp b/gnu/llvm/lldb/unittests/Utility/RangeMapTest.cpp index 8a243b65621..97432dca983 100644 --- a/gnu/llvm/lldb/unittests/Utility/RangeMapTest.cpp +++ b/gnu/llvm/lldb/unittests/Utility/RangeMapTest.cpp @@ -12,6 +12,32 @@ using namespace lldb_private; +TEST(RangeVector, CombineConsecutiveRanges) { + using RangeVector = RangeVector; + using Entry = RangeVector::Entry; + + RangeVector V; + V.Append(0, 1); + V.Append(5, 1); + V.Append(6, 1); + V.Append(10, 9); + V.Append(15, 1); + V.Append(20, 9); + V.Append(21, 9); + V.Sort(); + V.CombineConsecutiveRanges(); + EXPECT_THAT(V, testing::ElementsAre(Entry(0, 1), Entry(5, 2), Entry(10, 9), + Entry(20, 10))); + + V.Clear(); + V.Append(0, 20); + V.Append(5, 1); + V.Append(10, 1); + V.Sort(); + V.CombineConsecutiveRanges(); + EXPECT_THAT(V, testing::ElementsAre(Entry(0, 20))); +} + using RangeDataVectorT = RangeDataVector; using EntryT = RangeDataVectorT::Entry; diff --git a/gnu/llvm/lldb/unittests/Utility/RegisterValueTest.cpp b/gnu/llvm/lldb/unittests/Utility/RegisterValueTest.cpp index 70d79ea0024..5dd39ca04a2 100644 --- a/gnu/llvm/lldb/unittests/Utility/RegisterValueTest.cpp +++ b/gnu/llvm/lldb/unittests/Utility/RegisterValueTest.cpp @@ -10,6 +10,7 @@ #include "gtest/gtest.h" using namespace lldb_private; +using llvm::APInt; TEST(RegisterValueTest, GetSet8) { RegisterValue R8(uint8_t(47)); @@ -20,3 +21,35 @@ TEST(RegisterValueTest, GetSet8) { EXPECT_EQ(42u, R8.GetAsUInt32()); EXPECT_EQ(42u, R8.GetAsUInt64()); } + +TEST(RegisterValueTest, GetScalarValue) { + using RV = RegisterValue; + const auto &Get = [](const RV &V) -> llvm::Optional { + Scalar S; + if (V.GetScalarValue(S)) + return S; + return llvm::None; + }; + EXPECT_EQ(Get(RV(uint8_t(47))), Scalar(47)); + EXPECT_EQ(Get(RV(uint16_t(4747))), Scalar(4747)); + EXPECT_EQ(Get(RV(uint32_t(47474242))), Scalar(47474242)); + EXPECT_EQ(Get(RV(uint64_t(4747424247474242))), Scalar(4747424247474242)); + EXPECT_EQ(Get(RV(APInt::getMaxValue(128))), Scalar(APInt::getMaxValue(128))); + EXPECT_EQ(Get(RV(47.5f)), Scalar(47.5f)); + EXPECT_EQ(Get(RV(47.5)), Scalar(47.5)); + EXPECT_EQ(Get(RV(47.5L)), Scalar(47.5L)); + EXPECT_EQ(Get(RV({0xff, 0xee, 0xdd, 0xcc}, lldb::eByteOrderLittle)), + Scalar(0xccddeeff)); + EXPECT_EQ(Get(RV({0xff, 0xee, 0xdd, 0xcc}, lldb::eByteOrderBig)), + Scalar(0xffeeddcc)); + EXPECT_EQ(Get(RV({0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88, 0x77, 0x66, + 0x55, 0x44, 0x33, 0x22, 0x11, 0x00}, + lldb::eByteOrderLittle)), + Scalar((APInt(128, 0x0011223344556677ull) << 64) | + APInt(128, 0x8899aabbccddeeff))); + EXPECT_EQ(Get(RV({0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88, 0x77, 0x66, + 0x55, 0x44, 0x33, 0x22, 0x11, 0x00}, + lldb::eByteOrderBig)), + Scalar((APInt(128, 0xffeeddccbbaa9988ull) << 64) | + APInt(128, 0x7766554433221100))); +} diff --git a/gnu/llvm/lldb/unittests/Utility/ReproducerInstrumentationTest.cpp b/gnu/llvm/lldb/unittests/Utility/ReproducerInstrumentationTest.cpp index 1ed00a77249..ce259c5969e 100644 --- a/gnu/llvm/lldb/unittests/Utility/ReproducerInstrumentationTest.cpp +++ b/gnu/llvm/lldb/unittests/Utility/ReproducerInstrumentationTest.cpp @@ -50,7 +50,7 @@ public: TestingRegistry(); }; -static llvm::Optional g_registry; +static std::unique_ptr g_registry; static llvm::Optional g_serializer; static llvm::Optional g_deserializer; @@ -75,13 +75,13 @@ inline TestInstrumentationData GetTestInstrumentationData() { class TestInstrumentationDataRAII { public: TestInstrumentationDataRAII(llvm::raw_string_ostream &os) { - g_registry.emplace(); + g_registry = std::make_unique(); g_serializer.emplace(os); g_deserializer.reset(); } TestInstrumentationDataRAII(llvm::StringRef buffer) { - g_registry.emplace(); + g_registry = std::make_unique(); g_serializer.reset(); g_deserializer.emplace(buffer); } @@ -576,8 +576,11 @@ TEST(SerializationRountripTest, SerializeDeserializeObjectPointer) { std::string str; llvm::raw_string_ostream os(str); + unsigned sequence = 123; + Serializer serializer(os); - serializer.SerializeAll(static_cast(1), static_cast(2)); + serializer.SerializeAll(sequence, static_cast(1)); + serializer.SerializeAll(sequence, static_cast(2)); serializer.SerializeAll(&foo, &bar); llvm::StringRef buffer(os.str()); @@ -597,8 +600,11 @@ TEST(SerializationRountripTest, SerializeDeserializeObjectReference) { std::string str; llvm::raw_string_ostream os(str); + unsigned sequence = 123; + Serializer serializer(os); - serializer.SerializeAll(static_cast(1), static_cast(2)); + serializer.SerializeAll(sequence, static_cast(1)); + serializer.SerializeAll(sequence, static_cast(2)); serializer.SerializeAll(foo, bar); llvm::StringRef buffer(os.str()); @@ -1114,3 +1120,48 @@ TEST(PassiveReplayTest, InstrumentedBarPtr) { bar.Validate(); } } + +TEST(RecordReplayTest, ValidSequence) { + std::string str; + llvm::raw_string_ostream os(str); + + { + auto data = TestInstrumentationDataRAII::GetRecordingData(os); + + unsigned sequence = 1; + int (*f)() = &lldb_private::repro::invoke::method< + InstrumentedFoo::F>::record; + unsigned id = g_registry->GetID(uintptr_t(f)); + g_serializer->SerializeAll(sequence, id); + + unsigned result = 0; + g_serializer->SerializeAll(sequence, result); + } + + TestingRegistry registry; + Deserializer deserializer(os.str()); + registry.Replay(deserializer); +} + +TEST(RecordReplayTest, InvalidSequence) { + std::string str; + llvm::raw_string_ostream os(str); + + { + auto data = TestInstrumentationDataRAII::GetRecordingData(os); + + unsigned sequence = 1; + int (*f)() = &lldb_private::repro::invoke::method< + InstrumentedFoo::F>::record; + unsigned id = g_registry->GetID(uintptr_t(f)); + g_serializer->SerializeAll(sequence, id); + + unsigned result = 0; + unsigned invalid_sequence = 2; + g_serializer->SerializeAll(invalid_sequence, result); + } + + TestingRegistry registry; + Deserializer deserializer(os.str()); + EXPECT_DEATH(registry.Replay(deserializer), ""); +} diff --git a/gnu/llvm/lldb/unittests/Utility/ReproducerTest.cpp b/gnu/llvm/lldb/unittests/Utility/ReproducerTest.cpp index 5a9dea3450f..b276de3bf1a 100644 --- a/gnu/llvm/lldb/unittests/Utility/ReproducerTest.cpp +++ b/gnu/llvm/lldb/unittests/Utility/ReproducerTest.cpp @@ -9,13 +9,13 @@ #include "gmock/gmock.h" #include "gtest/gtest.h" +#include "lldb/Utility/FileSpec.h" +#include "lldb/Utility/Reproducer.h" +#include "lldb/Utility/ReproducerProvider.h" #include "llvm/ADT/ScopeExit.h" #include "llvm/Support/Error.h" #include "llvm/Testing/Support/Error.h" -#include "lldb/Utility/FileSpec.h" -#include "lldb/Utility/Reproducer.h" - using namespace llvm; using namespace lldb_private; using namespace lldb_private::repro; diff --git a/gnu/llvm/lldb/unittests/Utility/ScalarTest.cpp b/gnu/llvm/lldb/unittests/Utility/ScalarTest.cpp index dd4683145b9..1e65cd53573 100644 --- a/gnu/llvm/lldb/unittests/Utility/ScalarTest.cpp +++ b/gnu/llvm/lldb/unittests/Utility/ScalarTest.cpp @@ -16,6 +16,7 @@ #include "llvm/Testing/Support/Error.h" using namespace lldb_private; +using llvm::APFloat; using llvm::APInt; using llvm::Failed; using llvm::Succeeded; @@ -92,6 +93,7 @@ TEST(ScalarTest, Getters) { CheckConversion(0x8765432112345678ull); CheckConversion(42.25f); CheckConversion(42.25); + CheckConversion(42.25L); EXPECT_EQ(APInt(128, 1) << 70, Scalar(std::pow(2.0f, 70.0f)).SInt128(APInt())); EXPECT_EQ(APInt(128, -1, true) << 70, @@ -135,12 +137,8 @@ TEST(ScalarTest, GetBytes) { Scalar f_scalar; DataExtractor e_data(e, sizeof(e), endian::InlHostByteOrder(), sizeof(void *)); - Status e_error = - e_scalar.SetValueFromData(e_data, lldb::eEncodingUint, sizeof(e)); DataExtractor f_data(f, sizeof(f), endian::InlHostByteOrder(), sizeof(void *)); - Status f_error = - f_scalar.SetValueFromData(f_data, lldb::eEncodingUint, sizeof(f)); a_scalar.GetBytes(Storage); ASSERT_EQ(0, memcmp(&a, Storage, sizeof(a))); b_scalar.GetBytes(Storage); @@ -149,14 +147,39 @@ TEST(ScalarTest, GetBytes) { ASSERT_EQ(0, memcmp(&c, Storage, sizeof(c))); d_scalar.GetBytes(Storage); ASSERT_EQ(0, memcmp(&d, Storage, sizeof(d))); - ASSERT_EQ(0, e_error.Fail()); + ASSERT_THAT_ERROR( + e_scalar.SetValueFromData(e_data, lldb::eEncodingUint, sizeof(e)) + .ToError(), + llvm::Succeeded()); e_scalar.GetBytes(Storage); ASSERT_EQ(0, memcmp(e, Storage, sizeof(e))); - ASSERT_EQ(0, f_error.Fail()); + ASSERT_THAT_ERROR( + f_scalar.SetValueFromData(f_data, lldb::eEncodingUint, sizeof(f)) + .ToError(), + llvm::Succeeded()); f_scalar.GetBytes(Storage); ASSERT_EQ(0, memcmp(f, Storage, sizeof(f))); } +TEST(ScalarTest, SetValueFromData) { + uint8_t a[] = {1, 2, 3, 4}; + Scalar s; + ASSERT_THAT_ERROR( + s.SetValueFromData( + DataExtractor(a, sizeof(a), lldb::eByteOrderLittle, sizeof(void *)), + lldb::eEncodingSint, sizeof(a)) + .ToError(), + llvm::Succeeded()); + EXPECT_EQ(0x04030201, s); + ASSERT_THAT_ERROR( + s.SetValueFromData( + DataExtractor(a, sizeof(a), lldb::eByteOrderBig, sizeof(void *)), + lldb::eEncodingSint, sizeof(a)) + .ToError(), + llvm::Succeeded()); + EXPECT_EQ(0x01020304, s); +} + TEST(ScalarTest, CastOperations) { long long a = 0xf1f2f3f4f5f6f7f8LL; Scalar a_scalar(a); @@ -267,42 +290,28 @@ TEST(ScalarTest, Division) { } TEST(ScalarTest, Promotion) { - static Scalar::Type int_types[] = { - Scalar::e_sint, Scalar::e_uint, Scalar::e_slong, - Scalar::e_ulong, Scalar::e_slonglong, Scalar::e_ulonglong, - Scalar::e_sint128, Scalar::e_uint128, Scalar::e_sint256, - Scalar::e_uint256, - Scalar::e_void // sentinel - }; - - static Scalar::Type float_types[] = { - Scalar::e_float, Scalar::e_double, Scalar::e_long_double, - Scalar::e_void // sentinel - }; - - for (int i = 0; int_types[i] != Scalar::e_void; ++i) { - for (int j = 0; float_types[j] != Scalar::e_void; ++j) { - Scalar lhs(2); - EXPECT_TRUE(lhs.Promote(int_types[i])) << "int promotion #" << i; - Scalar rhs(0.5f); - EXPECT_TRUE(rhs.Promote(float_types[j])) << "float promotion #" << j; - Scalar x(2.5f); - EXPECT_TRUE(x.Promote(float_types[j])); - EXPECT_EQ(lhs + rhs, x); - } - } + Scalar a(47); + EXPECT_TRUE(a.IntegralPromote(64, true)); + EXPECT_TRUE(a.IsSigned()); + EXPECT_EQ(APInt(64, 47), a.UInt128(APInt())); - for (int i = 0; float_types[i] != Scalar::e_void; ++i) { - for (int j = 0; float_types[j] != Scalar::e_void; ++j) { - Scalar lhs(2); - EXPECT_TRUE(lhs.Promote(float_types[i])) << "float promotion #" << i; - Scalar rhs(0.5f); - EXPECT_TRUE(rhs.Promote(float_types[j])) << "float promotion #" << j; - Scalar x(2.5f); - EXPECT_TRUE(x.Promote(float_types[j])); - EXPECT_EQ(lhs + rhs, x); - } - } + EXPECT_FALSE(a.IntegralPromote(32, true)); + EXPECT_FALSE(a.IntegralPromote(32, false)); + EXPECT_TRUE(a.IsSigned()); + + EXPECT_TRUE(a.IntegralPromote(64, false)); + EXPECT_FALSE(a.IsSigned()); + EXPECT_EQ(APInt(64, 47), a.UInt128(APInt())); + + EXPECT_FALSE(a.IntegralPromote(64, true)); + + EXPECT_TRUE(a.FloatPromote(APFloat::IEEEdouble())); + EXPECT_EQ(Scalar::e_float, a.GetType()); + EXPECT_EQ(47.0, a.Double()); + + EXPECT_FALSE(a.FloatPromote(APFloat::IEEEsingle())); + EXPECT_TRUE(a.FloatPromote(APFloat::x87DoubleExtended())); + EXPECT_EQ(47.0L, a.LongDouble()); } TEST(ScalarTest, SetValueFromCString) { @@ -351,20 +360,12 @@ TEST(ScalarTest, SetValueFromCString) { } TEST(ScalarTest, APIntConstructor) { - auto width_array = {8, 16, 32}; - for (auto &w : width_array) { - Scalar A(APInt(w, 24)); - EXPECT_EQ(A.GetType(), Scalar::e_sint); + for (auto &width : {8, 16, 32}) { + Scalar A(APInt(width, 24)); + EXPECT_TRUE(A.IsSigned()); + EXPECT_EQ(A.GetType(), Scalar::e_int); + EXPECT_EQ(APInt(width, 24), A.UInt128(APInt())); } - - Scalar B(APInt(64, 42)); - EXPECT_EQ(B.GetType(), Scalar::GetBestTypeForBitSize(64, true)); - Scalar C(APInt(128, 96)); - EXPECT_EQ(C.GetType(), Scalar::e_sint128); - Scalar D(APInt(256, 156)); - EXPECT_EQ(D.GetType(), Scalar::e_sint256); - Scalar E(APInt(512, 456)); - EXPECT_EQ(E.GetType(), Scalar::e_sint512); } TEST(ScalarTest, Scalar_512) { @@ -374,17 +375,17 @@ TEST(ScalarTest, Scalar_512) { ASSERT_TRUE(Z.IsZero()); Scalar S(APInt(512, 2000)); - ASSERT_STREQ(S.GetTypeAsCString(), "int512_t"); - ASSERT_STREQ(S.GetValueTypeAsCString(Scalar::e_sint512), "int512_t"); + ASSERT_STREQ(S.GetTypeAsCString(), "int"); ASSERT_TRUE(S.MakeUnsigned()); - EXPECT_EQ(S.GetType(), Scalar::e_uint512); - ASSERT_STREQ(S.GetTypeAsCString(), "uint512_t"); - ASSERT_STREQ(S.GetValueTypeAsCString(Scalar::e_uint512), "uint512_t"); + EXPECT_EQ(S.GetType(), Scalar::e_int); + EXPECT_FALSE(S.IsSigned()); + ASSERT_STREQ(S.GetTypeAsCString(), "int"); EXPECT_EQ(S.GetByteSize(), 64U); ASSERT_TRUE(S.MakeSigned()); - EXPECT_EQ(S.GetType(), Scalar::e_sint512); + EXPECT_EQ(S.GetType(), Scalar::e_int); + EXPECT_TRUE(S.IsSigned()); EXPECT_EQ(S.GetByteSize(), 64U); } diff --git a/gnu/llvm/lldb/unittests/Utility/StatusTest.cpp b/gnu/llvm/lldb/unittests/Utility/StatusTest.cpp index 862c063b2e0..9b9d870cd12 100644 --- a/gnu/llvm/lldb/unittests/Utility/StatusTest.cpp +++ b/gnu/llvm/lldb/unittests/Utility/StatusTest.cpp @@ -10,7 +10,7 @@ #include "gtest/gtest.h" #ifdef _WIN32 -#include +#include #endif using namespace lldb_private; @@ -71,14 +71,26 @@ TEST(StatusTest, ErrorWin32) { EXPECT_FALSE(success.ToError()); EXPECT_TRUE(success.Success()); + WCHAR name[128]{}; + ULONG nameLen = llvm::array_lengthof(name); + ULONG langs = 0; + GetUserPreferredUILanguages(MUI_LANGUAGE_NAME, &langs, + reinterpret_cast(&name), &nameLen); + // Skip the following tests on non-English, non-US, locales because the + // formatted messages will be different. + bool skip = wcscmp(L"en-US", name) != 0; + auto s = Status(ERROR_ACCESS_DENIED, ErrorType::eErrorTypeWin32); EXPECT_TRUE(s.Fail()); - EXPECT_STREQ("Access is denied. ", s.AsCString()); + if (!skip) + EXPECT_STREQ("Access is denied. ", s.AsCString()); s.SetError(ERROR_IPSEC_IKE_TIMED_OUT, ErrorType::eErrorTypeWin32); - EXPECT_STREQ("Negotiation timed out ", s.AsCString()); + if (!skip) + EXPECT_STREQ("Negotiation timed out ", s.AsCString()); s.SetError(16000, ErrorType::eErrorTypeWin32); - EXPECT_STREQ("unknown error", s.AsCString()); + if (!skip) + EXPECT_STREQ("unknown error", s.AsCString()); } #endif diff --git a/gnu/llvm/lldb/unittests/Utility/StringExtractorGDBRemoteTest.cpp b/gnu/llvm/lldb/unittests/Utility/StringExtractorGDBRemoteTest.cpp new file mode 100644 index 00000000000..88362c028a9 --- /dev/null +++ b/gnu/llvm/lldb/unittests/Utility/StringExtractorGDBRemoteTest.cpp @@ -0,0 +1,185 @@ +#include "gmock/gmock.h" +#include "gtest/gtest.h" +#include + +#include "lldb/Utility/StringExtractorGDBRemote.h" +#include "lldb/lldb-defines.h" + +TEST(StringExtractorGDBRemoteTest, GetPidTid) { + StringExtractorGDBRemote ex(""); + EXPECT_EQ(ex.GetPidTid(0), llvm::None); + + // invalid/short values + + ex.Reset("narf"); + EXPECT_EQ(ex.GetPidTid(0), llvm::None); + + ex.Reset(";1234"); + EXPECT_EQ(ex.GetPidTid(0), llvm::None); + + ex.Reset(".1234"); + EXPECT_EQ(ex.GetPidTid(0), llvm::None); + + ex.Reset("p"); + EXPECT_EQ(ex.GetPidTid(0), llvm::None); + + ex.Reset("pnarf"); + EXPECT_EQ(ex.GetPidTid(0), llvm::None); + + ex.Reset("p;1234"); + EXPECT_EQ(ex.GetPidTid(0), llvm::None); + + ex.Reset("p.1234"); + EXPECT_EQ(ex.GetPidTid(0), llvm::None); + + ex.Reset("p1234."); + EXPECT_EQ(ex.GetPidTid(0), llvm::None); + + EXPECT_EQ(ex.GetPidTid(0), llvm::None); + + ex.Reset("p1234.;1234"); + EXPECT_EQ(ex.GetPidTid(0), llvm::None); + + ex.Reset("-2"); + EXPECT_EQ(ex.GetPidTid(0), llvm::None); + + ex.Reset("p1234.-2"); + EXPECT_EQ(ex.GetPidTid(0), llvm::None); + + ex.Reset("p-2"); + EXPECT_EQ(ex.GetPidTid(0), llvm::None); + + ex.Reset("p-2.1234"); + EXPECT_EQ(ex.GetPidTid(0), llvm::None); + + // overflow + + ex.Reset("p10000000000000000"); + EXPECT_EQ(ex.GetPidTid(0), llvm::None); + + ex.Reset("p10000000000000000.0"); + EXPECT_EQ(ex.GetPidTid(0), llvm::None); + + ex.Reset("10000000000000000"); + EXPECT_EQ(ex.GetPidTid(0), llvm::None); + + ex.Reset("p0.10000000000000000"); + EXPECT_EQ(ex.GetPidTid(0), llvm::None); + + ex.Reset("p10000000000000000.10000000000000000"); + EXPECT_EQ(ex.GetPidTid(0), llvm::None); + + // invalid: all processes but specific thread + + ex.Reset("p-1.0"); + EXPECT_EQ(ex.GetPidTid(100), llvm::None); + + ex.Reset("p-1.1234"); + EXPECT_EQ(ex.GetPidTid(100), llvm::None); + + ex.Reset("p-1.123456789ABCDEF0"); + EXPECT_EQ(ex.GetPidTid(100), llvm::None); + + // unsupported: pid/tid 0 + + ex.Reset("0"); + EXPECT_EQ(ex.GetPidTid(100), llvm::None); + + ex.Reset("p0"); + EXPECT_EQ(ex.GetPidTid(100), llvm::None); + + ex.Reset("p0.0"); + EXPECT_EQ(ex.GetPidTid(100), llvm::None); + + ex.Reset("p0.-1"); + EXPECT_EQ(ex.GetPidTid(100), llvm::None); + + ex.Reset("p0.1234"); + EXPECT_EQ(ex.GetPidTid(100), llvm::None); + + ex.Reset("p0.123456789ABCDEF0"); + EXPECT_EQ(ex.GetPidTid(100), llvm::None); + + ex.Reset("p1234.0"); + EXPECT_EQ(ex.GetPidTid(100), llvm::None); + + ex.Reset("p123456789ABCDEF0.0"); + EXPECT_EQ(ex.GetPidTid(100), llvm::None); + + // pure thread id + + ex.Reset("-1"); + EXPECT_THAT(ex.GetPidTid(100).getValue(), + ::testing::Pair(100, StringExtractorGDBRemote::AllThreads)); + + ex.Reset("1234"); + EXPECT_THAT(ex.GetPidTid(100).getValue(), ::testing::Pair(100, 0x1234ULL)); + + ex.Reset("123456789ABCDEF0"); + EXPECT_THAT(ex.GetPidTid(100).getValue(), + ::testing::Pair(100, 0x123456789ABCDEF0ULL)); + + // pure process id + + ex.Reset("p-1"); + EXPECT_THAT(ex.GetPidTid(100).getValue(), + ::testing::Pair(StringExtractorGDBRemote::AllProcesses, + StringExtractorGDBRemote::AllThreads)); + + ex.Reset("p1234"); + EXPECT_THAT(ex.GetPidTid(100).getValue(), + ::testing::Pair(0x1234ULL, StringExtractorGDBRemote::AllThreads)); + + ex.Reset("p123456789ABCDEF0"); + EXPECT_THAT(ex.GetPidTid(100).getValue(), + ::testing::Pair(0x123456789ABCDEF0ULL, + StringExtractorGDBRemote::AllThreads)); + + ex.Reset("pFFFFFFFFFFFFFFFF"); + EXPECT_THAT(ex.GetPidTid(100).getValue(), + ::testing::Pair(StringExtractorGDBRemote::AllProcesses, + StringExtractorGDBRemote::AllThreads)); + + // combined thread id + process id + + ex.Reset("p-1.-1"); + EXPECT_THAT(ex.GetPidTid(100).getValue(), + ::testing::Pair(StringExtractorGDBRemote::AllProcesses, + StringExtractorGDBRemote::AllThreads)); + + ex.Reset("p1234.-1"); + EXPECT_THAT(ex.GetPidTid(100).getValue(), + ::testing::Pair(0x1234ULL, StringExtractorGDBRemote::AllThreads)); + + ex.Reset("p1234.123456789ABCDEF0"); + EXPECT_THAT(ex.GetPidTid(100).getValue(), + ::testing::Pair(0x1234ULL, 0x123456789ABCDEF0ULL)); + + ex.Reset("p123456789ABCDEF0.-1"); + EXPECT_THAT(ex.GetPidTid(100).getValue(), + ::testing::Pair(0x123456789ABCDEF0ULL, + StringExtractorGDBRemote::AllThreads)); + + ex.Reset("p123456789ABCDEF0.1234"); + EXPECT_THAT(ex.GetPidTid(100).getValue(), + ::testing::Pair(0x123456789ABCDEF0ULL, 0x1234ULL)); + + ex.Reset("p123456789ABCDEF0.123456789ABCDEF0"); + EXPECT_THAT(ex.GetPidTid(100).getValue(), + ::testing::Pair(0x123456789ABCDEF0ULL, 0x123456789ABCDEF0ULL)); + + ex.Reset("p123456789ABCDEF0.123456789ABCDEF0"); + EXPECT_THAT(ex.GetPidTid(100).getValue(), + ::testing::Pair(0x123456789ABCDEF0ULL, 0x123456789ABCDEF0ULL)); +} + +TEST(StringExtractorGDBRemoteTest, GetPidTidMultipleValues) { + StringExtractorGDBRemote ex("1234;p12;p1234.-1"); + ASSERT_THAT(ex.GetPidTid(100).getValue(), ::testing::Pair(100, 0x1234ULL)); + ASSERT_EQ(ex.GetChar(), ';'); + ASSERT_THAT(ex.GetPidTid(100).getValue(), + ::testing::Pair(0x12ULL, StringExtractorGDBRemote::AllThreads)); + ASSERT_EQ(ex.GetChar(), ';'); + ASSERT_THAT(ex.GetPidTid(100).getValue(), + ::testing::Pair(0x1234ULL, StringExtractorGDBRemote::AllThreads)); +} diff --git a/gnu/llvm/lldb/unittests/Utility/TildeExpressionResolverTest.cpp b/gnu/llvm/lldb/unittests/Utility/TildeExpressionResolverTest.cpp index bc1ca7a4481..bcb7fdb8604 100644 --- a/gnu/llvm/lldb/unittests/Utility/TildeExpressionResolverTest.cpp +++ b/gnu/llvm/lldb/unittests/Utility/TildeExpressionResolverTest.cpp @@ -31,6 +31,9 @@ TEST(TildeExpressionResolver, ResolveFullPath) { EXPECT_EQ("/lars", Result); ASSERT_FALSE(Resolver.ResolveFullPath("~Jaso", Result)); + EXPECT_EQ("~Jaso", Result); ASSERT_FALSE(Resolver.ResolveFullPath("", Result)); + EXPECT_EQ("", Result); ASSERT_FALSE(Resolver.ResolveFullPath("Jason", Result)); + EXPECT_EQ("Jason", Result); } diff --git a/gnu/llvm/lldb/unittests/Utility/TimerTest.cpp b/gnu/llvm/lldb/unittests/Utility/TimerTest.cpp index 2d323c0dc2a..c6d1facdebb 100644 --- a/gnu/llvm/lldb/unittests/Utility/TimerTest.cpp +++ b/gnu/llvm/lldb/unittests/Utility/TimerTest.cpp @@ -97,7 +97,7 @@ TEST(TimerTest, CategoryTimesStats) { int count1, count2; ASSERT_EQ( 6, sscanf(ss.GetData(), - "%lf sec (total: %lfs; child: %lfs; count: %d) for CAT1%*[\n ]" + "%lf sec (total: %lfs; child: %lfs; count: %d) for CAT1%*[\n\r ]" "%lf sec (total: %*fs; child: %*fs; count: %d) for CAT2", &seconds1, &total1, &child1, &count1, &seconds2, &count2)) << "String: " << ss.GetData(); diff --git a/gnu/llvm/lldb/unittests/debugserver/CMakeLists.txt b/gnu/llvm/lldb/unittests/debugserver/CMakeLists.txt index c216eecd7d8..fd488c1623b 100644 --- a/gnu/llvm/lldb/unittests/debugserver/CMakeLists.txt +++ b/gnu/llvm/lldb/unittests/debugserver/CMakeLists.txt @@ -4,9 +4,6 @@ # of the debugserver communication path. If you are looking for a non-darwin # remote debugging server, please use lldb-server. -include_directories(${LLDB_SOURCE_DIR}/tools/debugserver/source - ${LLDB_SOURCE_DIR}/tools/debugserver/source/MacOSX) - add_lldb_unittest(debugserverTests JSONTest.cpp RNBSocketTest.cpp @@ -20,7 +17,11 @@ add_lldb_unittest(debugserverTests Support ) -if(IOS) +target_include_directories(debugserverTests PRIVATE + ${LLDB_SOURCE_DIR}/tools/debugserver/source + ${LLDB_SOURCE_DIR}/tools/debugserver/source/MacOSX) + +if(APPLE_EMBEDDED) set_property(TARGET debugserverTests APPEND PROPERTY COMPILE_DEFINITIONS WITH_LOCKDOWN WITH_FBS diff --git a/gnu/llvm/lldb/unittests/debugserver/RNBSocketTest.cpp b/gnu/llvm/lldb/unittests/debugserver/RNBSocketTest.cpp index 7840c48f82b..2625a6d36b5 100644 --- a/gnu/llvm/lldb/unittests/debugserver/RNBSocketTest.cpp +++ b/gnu/llvm/lldb/unittests/debugserver/RNBSocketTest.cpp @@ -28,7 +28,7 @@ static void ServerCallbackv4(const void *baton, in_port_t port) { auto child_pid = fork(); if (child_pid == 0) { char addr_buffer[256]; - sprintf(addr_buffer, "%s:%d", baton, port); + sprintf(addr_buffer, "%s:%d", (const char *)baton, port); llvm::Expected> socket_or_err = Socket::TcpConnect(addr_buffer, false); ASSERT_THAT_EXPECTED(socket_or_err, llvm::Succeeded()); diff --git a/gnu/llvm/lldb/unittests/tools/lldb-server/tests/MessageObjects.cpp b/gnu/llvm/lldb/unittests/tools/lldb-server/tests/MessageObjects.cpp index 3d1a153d289..77bc3a5e6ee 100644 --- a/gnu/llvm/lldb/unittests/tools/lldb-server/tests/MessageObjects.cpp +++ b/gnu/llvm/lldb/unittests/tools/lldb-server/tests/MessageObjects.cpp @@ -171,7 +171,7 @@ Expected RegisterInfoParser::create(StringRef Response) { Info.byte_size /= CHAR_BIT; if (!to_integer(Elements["offset"], Info.byte_offset, 10)) - return make_parsing_error("qRegisterInfo: offset"); + Info.byte_offset = LLDB_INVALID_INDEX32; Info.encoding = Args::StringToEncoding(Elements["encoding"]); if (Info.encoding == eEncodingInvalid) diff --git a/gnu/llvm/lldb/unittests/tools/lldb-server/tests/TestClient.cpp b/gnu/llvm/lldb/unittests/tools/lldb-server/tests/TestClient.cpp index 52428e4afc8..0bb60f26219 100644 --- a/gnu/llvm/lldb/unittests/tools/lldb-server/tests/TestClient.cpp +++ b/gnu/llvm/lldb/unittests/tools/lldb-server/tests/TestClient.cpp @@ -193,7 +193,7 @@ Error TestClient::SendMessage(StringRef message, std::string &response_string, PacketResult expected_result) { StringExtractorGDBRemote response; GTEST_LOG_(INFO) << "Send Packet: " << message.str(); - PacketResult result = SendPacketAndWaitForResponse(message, response, false); + PacketResult result = SendPacketAndWaitForResponse(message, response); response.GetEscapedBinaryData(response_string); GTEST_LOG_(INFO) << "Read Packet: " << response_string; if (result != expected_result) @@ -219,6 +219,7 @@ Error TestClient::qProcessInfo() { } Error TestClient::qRegisterInfos() { + uint32_t reg_offset = 0; for (unsigned int Reg = 0;; ++Reg) { std::string Message = formatv("qRegisterInfo{0:x-}", Reg).str(); Expected InfoOr = SendMessage(Message); @@ -227,6 +228,12 @@ Error TestClient::qRegisterInfos() { break; } m_register_infos.emplace_back(std::move(*InfoOr)); + + if (m_register_infos[Reg].byte_offset == LLDB_INVALID_INDEX32) + m_register_infos[Reg].byte_offset = reg_offset; + + reg_offset = + m_register_infos[Reg].byte_offset + m_register_infos[Reg].byte_size; if (m_register_infos[Reg].kinds[eRegisterKindGeneric] == LLDB_REGNUM_GENERIC_PC) m_pc_register = Reg; diff --git a/gnu/llvm/lldb/utils/lldb-dotest/CMakeLists.txt b/gnu/llvm/lldb/utils/lldb-dotest/CMakeLists.txt index 0ef60c14276..aab3f363a54 100644 --- a/gnu/llvm/lldb/utils/lldb-dotest/CMakeLists.txt +++ b/gnu/llvm/lldb/utils/lldb-dotest/CMakeLists.txt @@ -1,6 +1,6 @@ # Make lldb-dotest a custom target. add_custom_target(lldb-dotest) -add_dependencies(lldb-dotest lldb-test-deps) +add_dependencies(lldb-dotest lldb-test-depends) set_target_properties(lldb-dotest PROPERTIES FOLDER "lldb utils") get_property(LLDB_DOTEST_ARGS GLOBAL PROPERTY LLDB_DOTEST_ARGS_PROPERTY) @@ -10,6 +10,19 @@ llvm_canonicalize_cmake_booleans( LLDB_BUILD_INTEL_PT ) +set(LLVM_TOOLS_DIR "${LLVM_TOOLS_BINARY_DIR}") +set(vars + LLDB_DOTEST_ARGS + LLDB_SOURCE_DIR + LLDB_FRAMEWORK_DIR + LLDB_TEST_BUILD_DIRECTORY + LLDB_TEST_EXECUTABLE + LLDB_TEST_COMPILER + LLDB_TEST_DSYMUTIL + LLDB_LIBS_DIR + LLVM_TOOLS_DIR + ) + # Generate lldb-dotest Python driver script for each build mode. if(LLDB_BUILT_STANDALONE) set(config_types ".") @@ -19,38 +32,21 @@ if(LLDB_BUILT_STANDALONE) foreach(config_type ${config_types}) # In paths to our build-tree, replace CMAKE_CFG_INTDIR with our actual configuration names. string(REPLACE ${CMAKE_CFG_INTDIR} ${config_type} config_runtime_output_dir ${LLVM_RUNTIME_OUTPUT_INTDIR}) - string(REPLACE ${LLVM_RUNTIME_OUTPUT_INTDIR} ${config_runtime_output_dir} LLDB_DOTEST_ARGS_CONFIGURED "${LLDB_DOTEST_ARGS}") - string(REPLACE ${LLVM_RUNTIME_OUTPUT_INTDIR} ${config_runtime_output_dir} LLDB_SOURCE_DIR_CONFIGURED "${LLDB_SOURCE_DIR}") - string(REPLACE ${LLVM_RUNTIME_OUTPUT_INTDIR} ${config_runtime_output_dir} LLDB_TEST_BUILD_DIRECTORY_CONFIGURED "${LLDB_TEST_BUILD_DIRECTORY}") - string(REPLACE ${LLVM_RUNTIME_OUTPUT_INTDIR} ${config_runtime_output_dir} LLDB_TEST_EXECUTABLE_CONFIGURED "${LLDB_TEST_EXECUTABLE}") - string(REPLACE ${LLVM_RUNTIME_OUTPUT_INTDIR} ${config_runtime_output_dir} LLDB_TEST_COMPILER_CONFIGURED "${LLDB_TEST_COMPILER}") - string(REPLACE ${LLVM_RUNTIME_OUTPUT_INTDIR} ${config_runtime_output_dir} LLDB_TEST_DSYMUTIL_CONFIGURED "${LLDB_TEST_DSYMUTIL}") - string(REPLACE ${LLVM_RUNTIME_OUTPUT_INTDIR} ${config_runtime_output_dir} LLDB_TEST_FILECHECK_CONFIGURED "${LLDB_TEST_FILECHECK}") - string(REPLACE ${LLVM_RUNTIME_OUTPUT_INTDIR} ${config_runtime_output_dir} LLDB_TEST_YAML2OBJ_CONFIGURED "${LLDB_TEST_YAML2OBJ}") + foreach(var ${vars}) + string(REPLACE ${LLVM_RUNTIME_OUTPUT_INTDIR} ${config_runtime_output_dir} "${var}_CONFIGURED" "${${var}}") + endforeach() # Remaining ones must be paths to the provided LLVM build-tree. if(${config_type} IN_LIST LLVM_CONFIGURATION_TYPES) # Multi-configuration generator like Xcode (with a matching config). - string(REPLACE ${CMAKE_CFG_INTDIR} ${config_type} LLDB_DOTEST_ARGS_CONFIGURED "${LLDB_DOTEST_ARGS}") - string(REPLACE ${CMAKE_CFG_INTDIR} ${config_type} LLDB_SOURCE_DIR_CONFIGURED "${LLDB_SOURCE_DIR}") - string(REPLACE ${CMAKE_CFG_INTDIR} ${config_type} LLDB_TEST_BUILD_DIRECTORY_CONFIGURED "${LLDB_TEST_BUILD_DIRECTORY}") - string(REPLACE ${CMAKE_CFG_INTDIR} ${config_type} LLDB_TEST_EXECUTABLE_CONFIGURED "${LLDB_TEST_EXECUTABLE}") - string(REPLACE ${CMAKE_CFG_INTDIR} ${config_type} LLDB_TEST_COMPILER_CONFIGURED "${LLDB_TEST_COMPILER}") - string(REPLACE ${CMAKE_CFG_INTDIR} ${config_type} LLDB_TEST_DSYMUTIL_CONFIGURED "${LLDB_TEST_DSYMUTIL}") - string(REPLACE ${CMAKE_CFG_INTDIR} ${config_type} LLDB_TEST_FILECHECK_CONFIGURED "${LLDB_TEST_FILECHECK}") - string(REPLACE ${CMAKE_CFG_INTDIR} ${config_type} LLDB_TEST_YAML2OBJ_CONFIGURED "${LLDB_TEST_YAML2OBJ}") - string(REPLACE ${CMAKE_CFG_INTDIR} ${config_type} LLDB_LIBS_DIR_CONFIGURED "${LLDB_LIBS_DIR}") + foreach(var ${vars}) + string(REPLACE ${CMAKE_CFG_INTDIR} ${config_type} "${var}_CONFIGURED" "${${var}}") + endforeach() else() # Single-configuration generator like Ninja. - string(REPLACE ${CMAKE_CFG_INTDIR} "." LLDB_DOTEST_ARGS_CONFIGURED "${LLDB_DOTEST_ARGS}") - string(REPLACE ${CMAKE_CFG_INTDIR} "." LLDB_SOURCE_DIR_CONFIGURED "${LLDB_SOURCE_DIR}") - string(REPLACE ${CMAKE_CFG_INTDIR} "." LLDB_TEST_BUILD_DIRECTORY_CONFIGURED "${LLDB_TEST_BUILD_DIRECTORY}") - string(REPLACE ${CMAKE_CFG_INTDIR} "." LLDB_TEST_EXECUTABLE_CONFIGURED "${LLDB_TEST_EXECUTABLE}") - string(REPLACE ${CMAKE_CFG_INTDIR} "." LLDB_TEST_COMPILER_CONFIGURED "${LLDB_TEST_COMPILER}") - string(REPLACE ${CMAKE_CFG_INTDIR} "." LLDB_TEST_DSYMUTIL_CONFIGURED "${LLDB_TEST_DSYMUTIL}") - string(REPLACE ${CMAKE_CFG_INTDIR} "." LLDB_TEST_FILECHECK_CONFIGURED "${LLDB_TEST_FILECHECK}") - string(REPLACE ${CMAKE_CFG_INTDIR} "." LLDB_TEST_YAML2OBJ_CONFIGURED "${LLDB_TEST_YAML2OBJ_CONFIGURED}") - string(REPLACE ${CMAKE_CFG_INTDIR} "." LLDB_LIBS_DIR_CONFIGURED "${LLDB_LIBS_DIR}") + foreach(var ${vars}) + string(REPLACE ${CMAKE_CFG_INTDIR} "." "${var}_CONFIGURED" "${${var}}") + endforeach() endif() configure_file( @@ -61,15 +57,9 @@ if(LLDB_BUILT_STANDALONE) elseif(NOT "${CMAKE_CFG_INTDIR}" STREQUAL ".") foreach(LLVM_BUILD_MODE ${CMAKE_CONFIGURATION_TYPES}) string(REPLACE ${CMAKE_CFG_INTDIR} ${LLVM_BUILD_MODE} LLDB_DOTEST_DIR ${LLVM_RUNTIME_OUTPUT_INTDIR}) - string(REPLACE ${CMAKE_CFG_INTDIR} ${LLVM_BUILD_MODE} LLDB_DOTEST_ARGS_CONFIGURED "${LLDB_DOTEST_ARGS}") - string(REPLACE ${CMAKE_CFG_INTDIR} ${LLVM_BUILD_MODE} LLDB_SOURCE_DIR_CONFIGURED "${LLDB_SOURCE_DIR}") - string(REPLACE ${CMAKE_CFG_INTDIR} ${LLVM_BUILD_MODE} LLDB_TEST_BUILD_DIRECTORY_CONFIGURED "${LLDB_TEST_BUILD_DIRECTORY}") - string(REPLACE ${CMAKE_CFG_INTDIR} ${LLVM_BUILD_MODE} LLDB_TEST_EXECUTABLE_CONFIGURED "${LLDB_TEST_EXECUTABLE}") - string(REPLACE ${CMAKE_CFG_INTDIR} ${LLVM_BUILD_MODE} LLDB_TEST_COMPILER_CONFIGURED "${LLDB_TEST_COMPILER}") - string(REPLACE ${CMAKE_CFG_INTDIR} ${LLVM_BUILD_MODE} LLDB_TEST_DSYMUTIL_CONFIGURED "${LLDB_TEST_DSYMUTIL}") - string(REPLACE ${CMAKE_CFG_INTDIR} ${LLVM_BUILD_MODE} LLDB_TEST_FILECHECK_CONFIGURED "${LLDB_TEST_FILECHECK}") - string(REPLACE ${CMAKE_CFG_INTDIR} ${LLVM_BUILD_MODE} LLDB_TEST_YAML2OBJ_CONFIGURED "${LLDB_TEST_YAML2OBJ}") - string(REPLACE ${CMAKE_CFG_INTDIR} ${LLVM_BUILD_MODE} LLDB_LIBS_DIR_CONFIGURED "${LLDB_LIBS_DIR}") + foreach(var ${vars}) + string(REPLACE ${CMAKE_CFG_INTDIR} ${LLVM_BUILD_MODE} "${var}_CONFIGURED" "${${var}}") + endforeach() configure_file( lldb-dotest.in @@ -77,15 +67,9 @@ elseif(NOT "${CMAKE_CFG_INTDIR}" STREQUAL ".") ) endforeach() else() - set(LLDB_DOTEST_ARGS_CONFIGURED "${LLDB_DOTEST_ARGS}") - set(LLDB_SOURCE_DIR_CONFIGURED "${LLDB_SOURCE_DIR}") - set(LLDB_TEST_BUILD_DIRECTORY_CONFIGURED "${LLDB_TEST_BUILD_DIRECTORY}") - set(LLDB_TEST_EXECUTABLE_CONFIGURED "${LLDB_TEST_EXECUTABLE}") - set(LLDB_TEST_COMPILER_CONFIGURED "${LLDB_TEST_COMPILER}") - set(LLDB_TEST_DSYMUTIL_CONFIGURED "${LLDB_TEST_DSYMUTIL}") - set(LLDB_TEST_FILECHECK_CONFIGURED "${LLDB_TEST_FILECHECK}") - set(LLDB_TEST_YAML2OBJ_CONFIGURED "${LLDB_TEST_YAML2OBJ}") - set(LLDB_LIBS_DIR_CONFIGURED "${LLDB_LIBS_DIR}") + foreach(var ${vars}) + set("${var}_CONFIGURED" "${${var}}") + endforeach() configure_file( lldb-dotest.in diff --git a/gnu/llvm/lldb/utils/lldb-dotest/lldb-dotest.in b/gnu/llvm/lldb/utils/lldb-dotest/lldb-dotest.in index ee0ea6dff74..f6b5e0d01dc 100755 --- a/gnu/llvm/lldb/utils/lldb-dotest/lldb-dotest.in +++ b/gnu/llvm/lldb/utils/lldb-dotest/lldb-dotest.in @@ -1,18 +1,18 @@ -#!@PYTHON_EXECUTABLE@ +#!@Python3_EXECUTABLE@ import subprocess import sys dotest_path = '@LLDB_SOURCE_DIR_CONFIGURED@/test/API/dotest.py' -build_dir = '@LLDB_TEST_BUILD_DIRECTORY_CONFIGURED@' dotest_args_str = '@LLDB_DOTEST_ARGS_CONFIGURED@' arch = '@LLDB_TEST_ARCH@' executable = '@LLDB_TEST_EXECUTABLE_CONFIGURED@' compiler = '@LLDB_TEST_COMPILER_CONFIGURED@' dsymutil = '@LLDB_TEST_DSYMUTIL_CONFIGURED@' -filecheck = '@LLDB_TEST_FILECHECK_CONFIGURED@' -yaml2obj = '@LLDB_TEST_YAML2OBJ_CONFIGURED@' -lldb_libs_dir = "@LLDB_LIBS_DIR_CONFIGURED@" +lldb_build_dir = '@LLDB_TEST_BUILD_DIRECTORY_CONFIGURED@' lldb_build_intel_pt = "@LLDB_BUILD_INTEL_PT@" +lldb_framework_dir = "@LLDB_FRAMEWORK_DIR_CONFIGURED@" +lldb_libs_dir = "@LLDB_LIBS_DIR_CONFIGURED@" +llvm_tools_dir = "@LLVM_TOOLS_DIR_CONFIGURED@" if __name__ == '__main__': wrapper_args = sys.argv[1:] @@ -21,13 +21,14 @@ if __name__ == '__main__': cmd = [sys.executable, dotest_path] cmd.extend(['--arch', arch]) cmd.extend(dotest_args) - cmd.extend(['--build-dir', build_dir]) + cmd.extend(['--build-dir', lldb_build_dir]) cmd.extend(['--executable', executable]) cmd.extend(['--compiler', compiler]) cmd.extend(['--dsymutil', dsymutil]) - cmd.extend(['--yaml2obj', yaml2obj]) - cmd.extend(['--filecheck', filecheck]) cmd.extend(['--lldb-libs-dir', lldb_libs_dir]) + cmd.extend(['--llvm-tools-dir', llvm_tools_dir]) + if lldb_framework_dir: + cmd.extend(['--framework', lldb_framework_dir]) if lldb_build_intel_pt == "1": cmd.extend(['--enable-plugin', 'intel-pt']) cmd.extend(wrapper_args) diff --git a/gnu/llvm/lldb/utils/lldb-repro/CMakeLists.txt b/gnu/llvm/lldb/utils/lldb-repro/CMakeLists.txt index a496e998619..725cb66c475 100644 --- a/gnu/llvm/lldb/utils/lldb-repro/CMakeLists.txt +++ b/gnu/llvm/lldb/utils/lldb-repro/CMakeLists.txt @@ -1,5 +1,5 @@ add_custom_target(lldb-repro) -add_dependencies(lldb-repro lldb-test-deps) +add_dependencies(lldb-repro lldb-test-depends) set_target_properties(lldb-repro PROPERTIES FOLDER "lldb utils") # Generate lldb-repro Python script for each build mode. diff --git a/gnu/llvm/lldb/utils/lldb-repro/lldb-repro.py b/gnu/llvm/lldb/utils/lldb-repro/lldb-repro.py index 2b7b23f8cf2..928e1008984 100755 --- a/gnu/llvm/lldb/utils/lldb-repro/lldb-repro.py +++ b/gnu/llvm/lldb/utils/lldb-repro/lldb-repro.py @@ -62,9 +62,14 @@ def main(): # exit code and return that for tests that expect a non-zero exit code. exit_code_path = os.path.join(reproducer_path, 'exit_code.txt') if sys.argv[1] == "replay": + replay_exit_code = exit_code with open(exit_code_path, 'r') as f: - assert exit_code == 0 exit_code = int(f.read()) + if replay_exit_code != 0: + print("error: replay failed with exit code {}".format(replay_exit_code)) + print("invocation: " + " ".join(new_args)) + # Return 1 if the expected exit code is 0 or vice versa. + return 1 if (exit_code == 0) else 0 shutil.rmtree(reproducer_path, True) elif sys.argv[1] == "capture": with open(exit_code_path, 'w') as f: