Add SOS/lldb plugin tests from coreclr.
Add native build, test and ci scripts.
# Mac desktop service store files
.DS_Store
+
+# SOS stress log
+StressLog.txt
+
--- /dev/null
+# Verify minimum required version
+cmake_minimum_required(VERSION 2.8.12)
+
+if(CMAKE_VERSION VERSION_EQUAL 3.0 OR CMAKE_VERSION VERSION_GREATER 3.0)
+ cmake_policy(SET CMP0042 NEW)
+endif()
+
+# Set the project name
+project(diagnostics)
+
+# Include cmake functions
+include(functions.cmake)
+
+if (WIN32)
+ message(STATUS "VS_PLATFORM_TOOLSET is ${CMAKE_VS_PLATFORM_TOOLSET}")
+ message(STATUS "VS_PLATFORM_NAME is ${CMAKE_VS_PLATFORM_NAME}")
+endif (WIN32)
+
+set(CORECLR_SET_RPATH ON)
+if(CORECLR_SET_RPATH)
+ # Enable @rpath support for shared libraries.
+ set(MACOSX_RPATH ON)
+endif(CORECLR_SET_RPATH)
+
+OPTION(CLR_CMAKE_ENABLE_CODE_COVERAGE "Enable code coverage" OFF)
+OPTION(CLR_CMAKE_WARNINGS_ARE_ERRORS "Warnings are errors" ON)
+
+# Ensure that python is present
+find_program(PYTHON NAMES python2.7 python2 python)
+if (PYTHON STREQUAL "PYTHON-NOTFOUND")
+ message(FATAL_ERROR "PYTHON not found: Please install Python 2.7.9 or later from https://www.python.org/downloads/")
+endif()
+
+# Ensure other tools are present
+if (WIN32)
+ if(CLR_CMAKE_HOST_ARCH STREQUAL arm)
+
+ # Confirm that Windows SDK is present
+ if(NOT DEFINED CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION OR CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION STREQUAL "" )
+ message(FATAL_ERROR "Windows SDK is required for the Arm32 build.")
+ else()
+ message("Using Windows SDK version ${CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION}")
+ endif()
+
+ # Explicitly specify the assembler to be used for Arm32 compile
+ if($ENV{__VSVersion} STREQUAL "vs2015")
+ file(TO_CMAKE_PATH "$ENV{VCINSTALLDIR}\\bin\\x86_arm\\armasm.exe" CMAKE_ASM_COMPILER)
+ else()
+ file(TO_CMAKE_PATH "$ENV{VCToolsInstallDir}\\bin\\HostX86\\arm\\armasm.exe" CMAKE_ASM_COMPILER)
+ endif()
+
+ set(CMAKE_ASM_MASM_COMPILER ${CMAKE_ASM_COMPILER})
+ message("CMAKE_ASM_MASM_COMPILER explicitly set to: ${CMAKE_ASM_MASM_COMPILER}")
+
+ # Enable generic assembly compilation to avoid CMake generate VS proj files that explicitly
+ # use ml[64].exe as the assembler.
+ enable_language(ASM)
+ else()
+ enable_language(ASM_MASM)
+ endif()
+
+ # Ensure that MC is present
+ find_program(MC mc)
+ if (MC STREQUAL "MC-NOTFOUND")
+ message(FATAL_ERROR "MC not found")
+ endif()
+
+ if (CLR_CMAKE_HOST_ARCH STREQUAL arm64)
+ # CMAKE_CXX_COMPILER will default to the compiler installed with
+ # Visual studio. Overwrite it to the compiler on the path.
+ # TODO, remove when cmake generator supports Arm64 as a target.
+ find_program(PATH_CXX_COMPILER cl)
+ set(CMAKE_CXX_COMPILER ${PATH_CXX_COMPILER})
+ message("Overwriting the CMAKE_CXX_COMPILER.")
+ message(CMAKE_CXX_COMPILER found:${CMAKE_CXX_COMPILER})
+ endif()
+
+else (WIN32)
+ enable_language(ASM)
+
+ # Ensure that awk is present
+ find_program(AWK awk)
+ if (AWK STREQUAL "AWK-NOTFOUND")
+ message(FATAL_ERROR "AWK not found")
+ endif()
+
+ # Try to locate the paxctl tool. Failure to find it is not fatal,
+ # but the generated executables won't work on a system where PAX is set
+ # to prevent applications to create executable memory mappings.
+ find_program(PAXCTL paxctl)
+
+ if (CMAKE_SYSTEM_NAME STREQUAL Darwin)
+
+ # Ensure that dsymutil and strip are present
+ find_program(DSYMUTIL dsymutil)
+ if (DSYMUTIL STREQUAL "DSYMUTIL-NOTFOUND")
+ message(FATAL_ERROR "dsymutil not found")
+ endif()
+
+ find_program(STRIP strip)
+ if (STRIP STREQUAL "STRIP-NOTFOUND")
+ message(FATAL_ERROR "strip not found")
+ endif()
+
+ else (CMAKE_SYSTEM_NAME STREQUAL Darwin)
+
+ # Ensure that objcopy is present
+ if (CLR_UNIX_CROSS_BUILD AND NOT DEFINED CLR_CROSS_COMPONENTS_BUILD)
+ if (CMAKE_SYSTEM_PROCESSOR STREQUAL armv7l OR CMAKE_SYSTEM_PROCESSOR STREQUAL aarch64 OR CMAKE_SYSTEM_PROCESSOR STREQUAL arm)
+ find_program(OBJCOPY ${TOOLCHAIN}-objcopy)
+ elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL i686)
+ find_program(OBJCOPY objcopy)
+ else()
+ clr_unknown_arch()
+ endif()
+ else()
+ find_program(OBJCOPY objcopy)
+ endif()
+
+ if (OBJCOPY STREQUAL "OBJCOPY-NOTFOUND")
+ message(FATAL_ERROR "objcopy not found")
+ endif()
+
+ endif (CMAKE_SYSTEM_NAME STREQUAL Darwin)
+endif(WIN32)
+
+#----------------------------------------
+# Detect and set platform variable names
+# - for non-windows build platform & architecture is detected using inbuilt CMAKE variables and cross target component configure
+# - for windows we use the passed in parameter to CMAKE to determine build arch
+#----------------------------------------
+if(CMAKE_SYSTEM_NAME STREQUAL Linux)
+ set(CLR_CMAKE_PLATFORM_UNIX 1)
+ if(CLR_CROSS_COMPONENTS_BUILD)
+ # CMAKE_HOST_SYSTEM_PROCESSOR returns the value of `uname -p` on host.
+ if(CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL x86_64 OR CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL amd64)
+ if(CLR_CMAKE_TARGET_ARCH STREQUAL "arm")
+ set(CLR_CMAKE_PLATFORM_UNIX_X86 1)
+ else()
+ set(CLR_CMAKE_PLATFORM_UNIX_AMD64 1)
+ endif()
+ elseif(CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL i686)
+ set(CLR_CMAKE_PLATFORM_UNIX_X86 1)
+ else()
+ clr_unknown_arch()
+ endif()
+ else()
+ # CMAKE_SYSTEM_PROCESSOR returns the value of `uname -p` on target.
+ # For the AMD/Intel 64bit architecture two different strings are common.
+ # Linux and Darwin identify it as "x86_64" while FreeBSD and netbsd uses the
+ # "amd64" string. Accept either of the two here.
+ if(CMAKE_SYSTEM_PROCESSOR STREQUAL x86_64 OR CMAKE_SYSTEM_PROCESSOR STREQUAL amd64)
+ set(CLR_CMAKE_PLATFORM_UNIX_AMD64 1)
+ elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL armv7l)
+ set(CLR_CMAKE_PLATFORM_UNIX_ARM 1)
+ elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL arm)
+ set(CLR_CMAKE_PLATFORM_UNIX_ARM 1)
+ elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL aarch64)
+ set(CLR_CMAKE_PLATFORM_UNIX_ARM64 1)
+ elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL i686)
+ set(CLR_CMAKE_PLATFORM_UNIX_X86 1)
+ else()
+ clr_unknown_arch()
+ endif()
+ endif()
+ set(CLR_CMAKE_PLATFORM_LINUX 1)
+
+ # Detect Linux ID
+ if(DEFINED CLR_CMAKE_LINUX_ID)
+ if(CLR_CMAKE_LINUX_ID STREQUAL ubuntu)
+ set(CLR_CMAKE_TARGET_UBUNTU_LINUX 1)
+ elseif(CLR_CMAKE_LINUX_ID STREQUAL tizen)
+ set(CLR_CMAKE_TARGET_TIZEN_LINUX 1)
+ elseif(CLR_CMAKE_LINUX_ID STREQUAL alpine)
+ set(CLR_CMAKE_PLATFORM_ALPINE_LINUX 1)
+ endif()
+ if(CLR_CMAKE_LINUX_ID STREQUAL ubuntu)
+ set(CLR_CMAKE_PLATFORM_UBUNTU_LINUX 1)
+ endif()
+ endif(DEFINED CLR_CMAKE_LINUX_ID)
+endif(CMAKE_SYSTEM_NAME STREQUAL Linux)
+
+if(CMAKE_SYSTEM_NAME STREQUAL Darwin)
+ set(CLR_CMAKE_PLATFORM_UNIX 1)
+ set(CLR_CMAKE_PLATFORM_UNIX_AMD64 1)
+ set(CLR_CMAKE_PLATFORM_DARWIN 1)
+ if(CMAKE_VERSION VERSION_LESS "3.4.0")
+ set(CMAKE_ASM_COMPILE_OBJECT "${CMAKE_C_COMPILER} <FLAGS> <DEFINES> -o <OBJECT> -c <SOURCE>")
+ else()
+ set(CMAKE_ASM_COMPILE_OBJECT "${CMAKE_C_COMPILER} <FLAGS> <DEFINES> <INCLUDES> -o <OBJECT> -c <SOURCE>")
+ endif(CMAKE_VERSION VERSION_LESS "3.4.0")
+endif(CMAKE_SYSTEM_NAME STREQUAL Darwin)
+
+if(CMAKE_SYSTEM_NAME STREQUAL FreeBSD)
+ set(CLR_CMAKE_PLATFORM_UNIX 1)
+ set(CLR_CMAKE_PLATFORM_UNIX_AMD64 1)
+ set(CLR_CMAKE_PLATFORM_FREEBSD 1)
+endif(CMAKE_SYSTEM_NAME STREQUAL FreeBSD)
+
+if(CMAKE_SYSTEM_NAME STREQUAL OpenBSD)
+ set(CLR_CMAKE_PLATFORM_UNIX 1)
+ set(CLR_CMAKE_PLATFORM_UNIX_AMD64 1)
+ set(CLR_CMAKE_PLATFORM_OPENBSD 1)
+endif(CMAKE_SYSTEM_NAME STREQUAL OpenBSD)
+
+if(CMAKE_SYSTEM_NAME STREQUAL NetBSD)
+ set(CLR_CMAKE_PLATFORM_UNIX 1)
+ set(CLR_CMAKE_PLATFORM_UNIX_AMD64 1)
+ set(CLR_CMAKE_PLATFORM_NETBSD 1)
+endif(CMAKE_SYSTEM_NAME STREQUAL NetBSD)
+
+if(CMAKE_SYSTEM_NAME STREQUAL SunOS)
+ set(CLR_CMAKE_PLATFORM_UNIX 1)
+ EXECUTE_PROCESS(
+ COMMAND isainfo -n
+ OUTPUT_VARIABLE SUNOS_NATIVE_INSTRUCTION_SET
+ )
+ if(SUNOS_NATIVE_INSTRUCTION_SET MATCHES "amd64")
+ set(CLR_CMAKE_PLATFORM_UNIX_AMD64 1)
+ set(CMAKE_SYSTEM_PROCESSOR "amd64")
+ else()
+ clr_unknown_arch()
+ endif()
+ set(CLR_CMAKE_PLATFORM_SUNOS 1)
+endif(CMAKE_SYSTEM_NAME STREQUAL SunOS)
+
+#--------------------------------------------
+# This repo builds two set of binaries
+# 1. binaries which execute on target arch machine
+# - for such binaries host architecture & target architecture are same
+# - eg. coreclr.dll
+# 2. binaries which execute on host machine but target another architecture
+# - host architecture is different from target architecture
+# - eg. crossgen.exe - runs on x64 machine and generates nis targeting arm64
+# - for complete list of such binaries refer to file crosscomponents.cmake
+#-------------------------------------------------------------
+# Set HOST architecture variables
+if(CLR_CMAKE_PLATFORM_UNIX_ARM)
+ set(CLR_CMAKE_PLATFORM_ARCH_ARM 1)
+ set(CLR_CMAKE_HOST_ARCH "arm")
+elseif(CLR_CMAKE_PLATFORM_UNIX_ARM64)
+ set(CLR_CMAKE_PLATFORM_ARCH_ARM64 1)
+ set(CLR_CMAKE_HOST_ARCH "arm64")
+elseif(CLR_CMAKE_PLATFORM_UNIX_AMD64)
+ set(CLR_CMAKE_PLATFORM_ARCH_AMD64 1)
+ set(CLR_CMAKE_HOST_ARCH "x64")
+elseif(CLR_CMAKE_PLATFORM_UNIX_X86)
+ set(CLR_CMAKE_PLATFORM_ARCH_I386 1)
+ set(CLR_CMAKE_HOST_ARCH "x86")
+elseif(WIN32)
+ # CLR_CMAKE_HOST_ARCH is passed in as param to cmake
+ if (CLR_CMAKE_HOST_ARCH STREQUAL x64)
+ set(CLR_CMAKE_PLATFORM_ARCH_AMD64 1)
+ elseif(CLR_CMAKE_HOST_ARCH STREQUAL x86)
+ set(CLR_CMAKE_PLATFORM_ARCH_I386 1)
+ elseif(CLR_CMAKE_HOST_ARCH STREQUAL arm)
+ set(CLR_CMAKE_PLATFORM_ARCH_ARM 1)
+ elseif(CLR_CMAKE_HOST_ARCH STREQUAL arm64)
+ set(CLR_CMAKE_PLATFORM_ARCH_ARM64 1)
+ else()
+ clr_unknown_arch()
+ endif()
+endif()
+
+# Set TARGET architecture variables
+# Target arch will be a cmake param (optional) for both windows as well as non-windows build
+# if target arch is not specified then host & target are same
+if(NOT DEFINED CLR_CMAKE_TARGET_ARCH OR CLR_CMAKE_TARGET_ARCH STREQUAL "" )
+ set(CLR_CMAKE_TARGET_ARCH ${CLR_CMAKE_HOST_ARCH})
+endif()
+
+# Set target architecture variables
+if (CLR_CMAKE_TARGET_ARCH STREQUAL x64)
+ set(CLR_CMAKE_TARGET_ARCH_AMD64 1)
+ elseif(CLR_CMAKE_TARGET_ARCH STREQUAL x86)
+ set(CLR_CMAKE_TARGET_ARCH_I386 1)
+ elseif(CLR_CMAKE_TARGET_ARCH STREQUAL arm64)
+ set(CLR_CMAKE_TARGET_ARCH_ARM64 1)
+ elseif(CLR_CMAKE_TARGET_ARCH STREQUAL arm)
+ set(CLR_CMAKE_TARGET_ARCH_ARM 1)
+ else()
+ clr_unknown_arch()
+endif()
+
+# check if host & target arch combination are valid
+if(NOT(CLR_CMAKE_TARGET_ARCH STREQUAL CLR_CMAKE_HOST_ARCH))
+ if(NOT((CLR_CMAKE_PLATFORM_ARCH_AMD64 AND CLR_CMAKE_TARGET_ARCH_ARM64) OR (CLR_CMAKE_PLATFORM_ARCH_I386 AND CLR_CMAKE_TARGET_ARCH_ARM)))
+ message(FATAL_ERROR "Invalid host and target arch combination")
+ endif()
+endif()
+
+#-----------------------------------------------------
+# Initialize Cmake compiler flags and other variables
+#-----------------------------------------------------
+
+if (CMAKE_CONFIGURATION_TYPES) # multi-configuration generator?
+ set(CMAKE_CONFIGURATION_TYPES "Debug;Checked;Release;RelWithDebInfo" CACHE STRING "" FORCE)
+endif (CMAKE_CONFIGURATION_TYPES)
+
+set(CMAKE_C_FLAGS_CHECKED ${CLR_C_FLAGS_CHECKED_INIT} CACHE STRING "Flags used by the compiler during checked builds.")
+set(CMAKE_CXX_FLAGS_CHECKED ${CLR_CXX_FLAGS_CHECKED_INIT} CACHE STRING "Flags used by the compiler during checked builds.")
+set(CMAKE_EXE_LINKER_FLAGS_CHECKED "")
+set(CMAKE_SHARED_LINKER_FLAGS_CHECKED "")
+
+set(CMAKE_CXX_STANDARD_LIBRARIES "") # do not link against standard win32 libs i.e. kernel32, uuid, user32, etc.
+
+if (WIN32)
+ # For multi-configuration toolset (as Visual Studio)
+ # set the different configuration defines.
+ foreach (Config DEBUG CHECKED RELEASE RELWITHDEBINFO)
+ foreach (Definition IN LISTS CLR_DEFINES_${Config}_INIT)
+ set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS $<$<CONFIG:${Config}>:${Definition}>)
+ endforeach (Definition)
+ endforeach (Config)
+
+ set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /GUARD:CF")
+ set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /GUARD:CF")
+
+ # Linker flags
+ #
+ set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /MANIFEST:NO") #Do not create Side-by-Side Assembly Manifest
+
+ if (CLR_CMAKE_PLATFORM_ARCH_ARM)
+ set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /SUBSYSTEM:WINDOWS,6.02") #windows subsystem - arm minimum is 6.02
+ elseif(CLR_CMAKE_PLATFORM_ARCH_ARM64)
+ set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /SUBSYSTEM:WINDOWS,6.03") #windows subsystem - arm64 minimum is 6.03
+ else ()
+ set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /SUBSYSTEM:WINDOWS,6.01") #windows subsystem
+ endif ()
+
+ set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /LARGEADDRESSAWARE") # can handle addresses larger than 2 gigabytes
+ set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /NXCOMPAT") #Compatible with Data Execution Prevention
+ set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /DYNAMICBASE") #Use address space layout randomization
+ set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /PDBCOMPRESS") #shrink pdb size
+ set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /DEBUG")
+ set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /IGNORE:4197,4013,4254,4070,4221")
+
+ set(CMAKE_STATIC_LINKER_FLAGS "${CMAKE_STATIC_LINKER_FLAGS} /IGNORE:4221")
+
+ set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /DEBUG /PDBCOMPRESS")
+ set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /STACK:1572864")
+
+ # Temporarily disable incremental link due to incremental linking CFG bug crashing crossgen.
+ # See https://github.com/dotnet/coreclr/issues/12592
+ # This has been fixed in VS 2017 Update 5 but we're keeping this around until everyone is off
+ # the versions that have the bug. The bug manifests itself as a bad crash.
+ set(NO_INCREMENTAL_LINKER_FLAGS "/INCREMENTAL:NO")
+
+ # Debug build specific flags
+ set(CMAKE_SHARED_LINKER_FLAGS_DEBUG "/NOVCFEATURE ${NO_INCREMENTAL_LINKER_FLAGS}")
+ set(CMAKE_EXE_LINKER_FLAGS_DEBUG "${NO_INCREMENTAL_LINKER_FLAGS}")
+
+ # Checked build specific flags
+ set(CMAKE_SHARED_LINKER_FLAGS_CHECKED "${CMAKE_SHARED_LINKER_FLAGS_CHECKED} /OPT:REF /OPT:NOICF /NOVCFEATURE ${NO_INCREMENTAL_LINKER_FLAGS}")
+ set(CMAKE_STATIC_LINKER_FLAGS_CHECKED "${CMAKE_STATIC_LINKER_FLAGS_CHECKED}")
+ set(CMAKE_EXE_LINKER_FLAGS_CHECKED "${CMAKE_EXE_LINKER_FLAGS_CHECKED} /OPT:REF /OPT:NOICF ${NO_INCREMENTAL_LINKER_FLAGS}")
+
+ # Release build specific flags
+ set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} /LTCG /OPT:REF /OPT:ICF ${NO_INCREMENTAL_LINKER_FLAGS}")
+ set(CMAKE_STATIC_LINKER_FLAGS_RELEASE "${CMAKE_STATIC_LINKER_FLAGS_RELEASE} /LTCG")
+ set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /LTCG /OPT:REF /OPT:ICF ${NO_INCREMENTAL_LINKER_FLAGS}")
+
+ # ReleaseWithDebugInfo build specific flags
+ set(CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO} /LTCG /OPT:REF /OPT:ICF ${NO_INCREMENTAL_LINKER_FLAGS}")
+ set(CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO} /LTCG")
+ set(CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO} /LTCG /OPT:REF /OPT:ICF ${NO_INCREMENTAL_LINKER_FLAGS}")
+
+ # Temporary until cmake has VS generators for arm64
+ if(CLR_CMAKE_PLATFORM_ARCH_ARM64)
+ set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /machine:arm64")
+ set(CMAKE_STATIC_LINKER_FLAGS "${CMAKE_STATIC_LINKER_FLAGS} /machine:arm64")
+ set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /machine:arm64")
+ endif(CLR_CMAKE_PLATFORM_ARCH_ARM64)
+
+ # Force uCRT to be dynamically linked for Release build
+ set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} /NODEFAULTLIB:libucrt.lib /DEFAULTLIB:ucrt.lib")
+ set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /NODEFAULTLIB:libucrt.lib /DEFAULTLIB:ucrt.lib")
+ set(CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO} /NODEFAULTLIB:libucrt.lib /DEFAULTLIB:ucrt.lib")
+ set(CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO} /NODEFAULTLIB:libucrt.lib /DEFAULTLIB:ucrt.lib")
+
+elseif (CLR_CMAKE_PLATFORM_UNIX)
+ # Set the values to display when interactively configuring CMAKE_BUILD_TYPE
+ set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "DEBUG;CHECKED;RELEASE;RELWITHDEBINFO")
+
+ # Use uppercase CMAKE_BUILD_TYPE for the string comparisons below
+ string(TOUPPER ${CMAKE_BUILD_TYPE} UPPERCASE_CMAKE_BUILD_TYPE)
+
+ # For single-configuration toolset
+ # set the different configuration defines.
+ if (UPPERCASE_CMAKE_BUILD_TYPE STREQUAL DEBUG)
+ # First DEBUG
+ set_property(DIRECTORY PROPERTY COMPILE_DEFINITIONS ${CLR_DEFINES_DEBUG_INIT})
+ elseif (UPPERCASE_CMAKE_BUILD_TYPE STREQUAL CHECKED)
+ # Then CHECKED
+ set_property(DIRECTORY PROPERTY COMPILE_DEFINITIONS ${CLR_DEFINES_CHECKED_INIT})
+ elseif (UPPERCASE_CMAKE_BUILD_TYPE STREQUAL RELEASE)
+ # Then RELEASE
+ set_property(DIRECTORY PROPERTY COMPILE_DEFINITIONS ${CLR_DEFINES_RELEASE_INIT})
+ elseif (UPPERCASE_CMAKE_BUILD_TYPE STREQUAL RELWITHDEBINFO)
+ # And then RELWITHDEBINFO
+ set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS ${CLR_DEFINES_RELWITHDEBINFO_INIT})
+ else ()
+ message(FATAL_ERROR "Unknown build type! Set CMAKE_BUILD_TYPE to DEBUG, CHECKED, RELEASE, or RELWITHDEBINFO!")
+ endif ()
+
+ # set the CLANG sanitizer flags for debug build
+ if(UPPERCASE_CMAKE_BUILD_TYPE STREQUAL DEBUG OR UPPERCASE_CMAKE_BUILD_TYPE STREQUAL CHECKED)
+ # obtain settings from running enablesanitizers.sh
+ string(FIND "$ENV{DEBUG_SANITIZERS}" "asan" __ASAN_POS)
+ string(FIND "$ENV{DEBUG_SANITIZERS}" "ubsan" __UBSAN_POS)
+ if ((${__ASAN_POS} GREATER -1) OR (${__UBSAN_POS} GREATER -1))
+ set(CLR_SANITIZE_CXX_FLAGS "${CLR_SANITIZE_CXX_FLAGS} -fsanitize-blacklist=${CMAKE_CURRENT_SOURCE_DIR}/sanitizerblacklist.txt -fsanitize=")
+ set(CLR_SANITIZE_LINK_FLAGS "${CLR_SANITIZE_LINK_FLAGS} -fsanitize=")
+ if (${__ASAN_POS} GREATER -1)
+ set(CLR_SANITIZE_CXX_FLAGS "${CLR_SANITIZE_CXX_FLAGS}address,")
+ set(CLR_SANITIZE_LINK_FLAGS "${CLR_SANITIZE_LINK_FLAGS}address,")
+ add_definitions(-DHAS_ASAN)
+ message("Address Sanitizer (asan) enabled")
+ endif ()
+ if (${__UBSAN_POS} GREATER -1)
+ # all sanitizier flags are enabled except alignment (due to heavy use of __unaligned modifier)
+ set(CLR_SANITIZE_CXX_FLAGS "${CLR_SANITIZE_CXX_FLAGS}bool,bounds,enum,float-cast-overflow,float-divide-by-zero,function,integer,nonnull-attribute,null,object-size,return,returns-nonnull-attribute,shift,unreachable,vla-bound,vptr")
+ set(CLR_SANITIZE_LINK_FLAGS "${CLR_SANITIZE_LINK_FLAGS}undefined")
+ message("Undefined Behavior Sanitizer (ubsan) enabled")
+ endif ()
+
+ # -fdata-sections -ffunction-sections: each function has own section instead of one per .o file (needed for --gc-sections)
+ # -fPIC: enable Position Independent Code normally just for shared libraries but required when linking with address sanitizer
+ # -O1: optimization level used instead of -O0 to avoid compile error "invalid operand for inline asm constraint"
+ set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${CLR_SANITIZE_CXX_FLAGS} -fdata-sections -ffunction-sections -fPIC -O1")
+ set(CMAKE_CXX_FLAGS_CHECKED "${CMAKE_CXX_FLAGS_CHECKED} ${CLR_SANITIZE_CXX_FLAGS} -fdata-sections -ffunction-sections -fPIC -O1")
+
+ set(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} ${CLR_SANITIZE_LINK_FLAGS}")
+ set(CMAKE_EXE_LINKER_FLAGS_CHECKED "${CMAKE_EXE_LINKER_FLAGS_CHECKED} ${CLR_SANITIZE_LINK_FLAGS}")
+
+ # -Wl and --gc-sections: drop unused sections\functions (similar to Windows /Gy function-level-linking)
+ set(CMAKE_SHARED_LINKER_FLAGS_DEBUG "${CMAKE_SHARED_LINKER_FLAGS_DEBUG} ${CLR_SANITIZE_LINK_FLAGS} -Wl,--gc-sections")
+ set(CMAKE_SHARED_LINKER_FLAGS_CHECKED "${CMAKE_SHARED_LINKER_FLAGS_CHECKED} ${CLR_SANITIZE_LINK_FLAGS} -Wl,--gc-sections")
+ endif ()
+ endif(UPPERCASE_CMAKE_BUILD_TYPE STREQUAL DEBUG OR UPPERCASE_CMAKE_BUILD_TYPE STREQUAL CHECKED)
+endif(WIN32)
+
+# CLR_ADDITIONAL_LINKER_FLAGS - used for passing additional arguments to linker
+# CLR_ADDITIONAL_COMPILER_OPTIONS - used for passing additional arguments to compiler
+#
+# For example:
+# ./build-native.sh cmakeargs "-DCLR_ADDITIONAL_COMPILER_OPTIONS=<...>" cmakeargs "-DCLR_ADDITIONAL_LINKER_FLAGS=<...>"
+#
+if(CLR_CMAKE_PLATFORM_UNIX)
+ set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${CLR_ADDITIONAL_LINKER_FLAGS}")
+ set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${CLR_ADDITIONAL_LINKER_FLAGS}" )
+ add_compile_options(${CLR_ADDITIONAL_COMPILER_OPTIONS})
+endif(CLR_CMAKE_PLATFORM_UNIX)
+
+if(CLR_CMAKE_PLATFORM_LINUX)
+ set(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} -Wa,--noexecstack")
+ set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--build-id=sha1")
+ set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--build-id=sha1")
+endif(CLR_CMAKE_PLATFORM_LINUX)
+
+#------------------------------------
+# Definitions (for platform)
+#-----------------------------------
+if (CLR_CMAKE_PLATFORM_ARCH_AMD64)
+ add_definitions(-D_AMD64_)
+ add_definitions(-D_WIN64)
+ add_definitions(-DAMD64)
+ add_definitions(-DBIT64=1)
+elseif (CLR_CMAKE_PLATFORM_ARCH_I386)
+ add_definitions(-D_X86_)
+elseif (CLR_CMAKE_PLATFORM_ARCH_ARM)
+ add_definitions(-D_ARM_)
+ add_definitions(-DARM)
+elseif (CLR_CMAKE_PLATFORM_ARCH_ARM64)
+ add_definitions(-D_ARM64_)
+ add_definitions(-DARM64)
+ add_definitions(-D_WIN64)
+ add_definitions(-DBIT64=1)
+else ()
+ clr_unknown_arch()
+endif ()
+
+if (CLR_CMAKE_PLATFORM_UNIX)
+ if(CLR_CMAKE_PLATFORM_LINUX)
+ if(CLR_CMAKE_PLATFORM_UNIX_AMD64)
+ message("Detected Linux x86_64")
+ add_definitions(-DLINUX64)
+ elseif(CLR_CMAKE_PLATFORM_UNIX_ARM)
+ message("Detected Linux ARM")
+ add_definitions(-DLINUX32)
+ elseif(CLR_CMAKE_PLATFORM_UNIX_ARM64)
+ message("Detected Linux ARM64")
+ add_definitions(-DLINUX64)
+ elseif(CLR_CMAKE_PLATFORM_UNIX_X86)
+ message("Detected Linux i686")
+ add_definitions(-DLINUX32)
+ else()
+ clr_unknown_arch()
+ endif()
+ endif(CLR_CMAKE_PLATFORM_LINUX)
+endif(CLR_CMAKE_PLATFORM_UNIX)
+
+if (CLR_CMAKE_PLATFORM_UNIX)
+ add_definitions(-DPLATFORM_UNIX=1)
+
+ if(CLR_CMAKE_PLATFORM_DARWIN)
+ message("Detected OSX x86_64")
+ endif(CLR_CMAKE_PLATFORM_DARWIN)
+
+ if(CLR_CMAKE_PLATFORM_FREEBSD)
+ message("Detected FreeBSD amd64")
+ endif(CLR_CMAKE_PLATFORM_FREEBSD)
+
+ if(CLR_CMAKE_PLATFORM_NETBSD)
+ message("Detected NetBSD amd64")
+ endif(CLR_CMAKE_PLATFORM_NETBSD)
+endif(CLR_CMAKE_PLATFORM_UNIX)
+
+if (WIN32)
+ # Define the CRT lib references that link into Desktop imports
+ set(STATIC_MT_CRT_LIB "libcmt$<$<OR:$<CONFIG:Debug>,$<CONFIG:Checked>>:d>.lib")
+ set(STATIC_MT_VCRT_LIB "libvcruntime$<$<OR:$<CONFIG:Debug>,$<CONFIG:Checked>>:d>.lib")
+ set(STATIC_MT_CPP_LIB "libcpmt$<$<OR:$<CONFIG:Debug>,$<CONFIG:Checked>>:d>.lib")
+endif(WIN32)
+
+# Architecture specific files folder name
+if (CLR_CMAKE_TARGET_ARCH_AMD64)
+ set(ARCH_SOURCES_DIR amd64)
+elseif (CLR_CMAKE_TARGET_ARCH_ARM64)
+ set(ARCH_SOURCES_DIR arm64)
+elseif (CLR_CMAKE_TARGET_ARCH_ARM)
+ set(ARCH_SOURCES_DIR arm)
+elseif (CLR_CMAKE_TARGET_ARCH_I386)
+ set(ARCH_SOURCES_DIR i386)
+else ()
+ clr_unknown_arch()
+endif ()
+
+#--------------------------------------
+# Compile Options
+#--------------------------------------
+include(compileoptions.cmake)
+
+#-----------------------------------------
+# Native Projects
+#-----------------------------------------
+add_subdirectory(src)
+
.NET Core Diagnostics Repo
==========================
-This repository contains the source code for various .NET Core runtime diagnostic tools.
+This repository contains the source code for various .NET Core runtime diagnostic tools. It currently contains the managed portion of SOS and the lldb SOS plugin. One of goals of this repo is to build the lldb SOS plugin for the portable Linux platform (Centos 7) and the platforms not supported by the portable build (Centos 6, Alpine, eventually macOS) and to test across various indexes in a very large matrix: OSs/distros (Centos 6/7, Ubuntu, Alpine, Fedora, Debian, RHEL 7.2), architectures (x64, x86, arm, arm64), lldb versions (3.9, 4.0, 5.0, 6.0) and even .NET Core versions (1.1, 2.0.x, 2.1).
+
+Another goal to make it easier to obtain a version of lldb (currently 3.9) with scripts and documentation for platforms/distros like Centos, Alpine, Fedora, etc. that by default provide really old versions.
+
+This repo will also allow out of band development of new SOS and lldb plugin features like symbol server support and solve the source build problem having SOS.NETCore (managed portion of SOS) in the coreclr repo.
## Useful Links
* [Debugging CoreCLR](https://github.com/dotnet/coreclr/blob/master/Documentation/building/debugging-instructions.md) - Instructions for debugging .NET Core and the CoreCLR runtime.
+[//]: # (Begin current test results)
+
+## Daily Builds
+
+| | x64 Debug|x64 Release|
+|:--:|:--:|:--:|
+|**Windows**|[](https://ci.dot.net/job/dotnet_diagnostics/job/master/job/Windows_NT_Debug/)|[](https://ci.dot.net/job/dotnet_diagnostics/job/master/job/Windows_NT_Release/)|
+|**Ubuntu 16.04**|[](https://ci.dot.net/job/dotnet_diagnostics/job/master/job/Ubuntu16.04_Debug/)|[](https://ci.dot.net/job/dotnet_diagnostics/job/master/job/Ubuntu16.04_Release/)|
+|**CentOS 7**|[](https://ci.dot.net/job/dotnet_diagnostics/job/master/job/CentOS7.1_Debug/)|[](https://ci.dot.net/job/dotnet_diagnostics/job/master/job/CentOS7.1_Release/)|
+
+[//]: # (End current test results)
+
+
+
## License
-.NET Core (including the coreclr repo) is licensed under the [MIT license](LICENSE.TXT).
+The diagnostics repository is licensed under the [MIT license](LICENSE.TXT). This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
+
done
scriptroot="$( cd -P "$( dirname "$source" )" && pwd )"
-"$scriptroot/eng/common/build.sh" --build --restore $@
\ No newline at end of file
+"$scriptroot/eng/build.sh" --restore --build $@
--- /dev/null
+if (CLR_CMAKE_PLATFORM_UNIX)
+ # Disable frame pointer optimizations so profilers can get better call stacks
+ add_compile_options(-fno-omit-frame-pointer)
+
+ # The -fms-extensions enable the stuff like __if_exists, __declspec(uuid()), etc.
+ add_compile_options(-fms-extensions )
+ #-fms-compatibility Enable full Microsoft Visual C++ compatibility
+ #-fms-extensions Accept some non-standard constructs supported by the Microsoft compiler
+
+ # Make signed arithmetic overflow of addition, subtraction, and multiplication wrap around
+ # using twos-complement representation (this is normally undefined according to the C++ spec).
+ add_compile_options(-fwrapv)
+
+ if(CLR_CMAKE_PLATFORM_DARWIN)
+ # We cannot enable "stack-protector-strong" on OS X due to a bug in clang compiler (current version 7.0.2)
+ add_compile_options(-fstack-protector)
+ else()
+ add_compile_options(-fstack-protector-strong)
+ endif(CLR_CMAKE_PLATFORM_DARWIN)
+
+ add_definitions(-DDISABLE_CONTRACTS)
+ # The -ferror-limit is helpful during the porting, it makes sure the compiler doesn't stop
+ # after hitting just about 20 errors.
+ add_compile_options(-ferror-limit=4096)
+
+ if (CLR_CMAKE_WARNINGS_ARE_ERRORS)
+ # All warnings that are not explicitly disabled are reported as errors
+ add_compile_options(-Werror)
+ endif(CLR_CMAKE_WARNINGS_ARE_ERRORS)
+
+ # Disabled warnings
+ add_compile_options(-Wno-unused-private-field)
+ add_compile_options(-Wno-unused-variable)
+ # Explicit constructor calls are not supported by clang (this->ClassName::ClassName())
+ add_compile_options(-Wno-microsoft)
+ # This warning is caused by comparing 'this' to NULL
+ add_compile_options(-Wno-tautological-compare)
+ # There are constants of type BOOL used in a condition. But BOOL is defined as int
+ # and so the compiler thinks that there is a mistake.
+ add_compile_options(-Wno-constant-logical-operand)
+ # We use pshpack1/2/4/8.h and poppack.h headers to set and restore packing. However
+ # clang 6.0 complains when the packing change lifetime is not contained within
+ # a header file.
+ add_compile_options(-Wno-pragma-pack)
+
+ add_compile_options(-Wno-unknown-warning-option)
+
+ #These seem to indicate real issues
+ add_compile_options(-Wno-invalid-offsetof)
+ # The following warning indicates that an attribute __attribute__((__ms_struct__)) was applied
+ # to a struct or a class that has virtual members or a base class. In that case, clang
+ # may not generate the same object layout as MSVC.
+ add_compile_options(-Wno-incompatible-ms-struct)
+
+ # Some architectures (e.g., ARM) assume char type is unsigned while CoreCLR assumes char is signed
+ # as x64 does. It has been causing issues in ARM (https://github.com/dotnet/coreclr/issues/4746)
+ add_compile_options(-fsigned-char)
+endif(CLR_CMAKE_PLATFORM_UNIX)
+
+if(CLR_CMAKE_PLATFORM_UNIX_ARM)
+ # Because we don't use CMAKE_C_COMPILER/CMAKE_CXX_COMPILER to use clang
+ # we have to set the triple by adding a compiler argument
+ add_compile_options(-mthumb)
+ add_compile_options(-mfpu=vfpv3)
+ add_compile_options(-march=armv7-a)
+ if(ARM_SOFTFP)
+ add_definitions(-DARM_SOFTFP)
+ add_compile_options(-mfloat-abi=softfp)
+ endif(ARM_SOFTFP)
+endif(CLR_CMAKE_PLATFORM_UNIX_ARM)
+
+if (WIN32)
+ # Compile options for targeting windows
+
+ # The following options are set by the razzle build
+ add_compile_options(/TP) # compile all files as C++
+ add_compile_options(/d2Zi+) # make optimized builds debugging easier
+ add_compile_options(/nologo) # Suppress Startup Banner
+ add_compile_options(/W3) # set warning level to 3
+ add_compile_options(/WX) # treat warnings as errors
+ add_compile_options(/Oi) # enable intrinsics
+ add_compile_options(/Oy-) # disable suppressing of the creation of frame pointers on the call stack for quicker function calls
+ add_compile_options(/U_MT) # undefine the predefined _MT macro
+ add_compile_options(/GF) # enable read-only string pooling
+ add_compile_options(/Gm-) # disable minimal rebuild
+ add_compile_options(/EHa) # enable C++ EH (w/ SEH exceptions)
+ add_compile_options(/Zp8) # pack structs on 8-byte boundary
+ add_compile_options(/Gy) # separate functions for linker
+ add_compile_options(/Zc:wchar_t-) # C++ language conformance: wchar_t is NOT the native type, but a typedef
+ add_compile_options(/Zc:forScope) # C++ language conformance: enforce Standard C++ for scoping rules
+ add_compile_options(/GR-) # disable C++ RTTI
+ add_compile_options(/FC) # use full pathnames in diagnostics
+ add_compile_options(/MP) # Build with Multiple Processes (number of processes equal to the number of processors)
+ add_compile_options(/GS) # Buffer Security Check
+ add_compile_options(/Zm200) # Specify Precompiled Header Memory Allocation Limit of 150MB
+ add_compile_options(/wd4960 /wd4961 /wd4603 /wd4627 /wd4838 /wd4456 /wd4457 /wd4458 /wd4459 /wd4091 /we4640)
+ add_compile_options(/Zi) # enable debugging information
+ add_compile_options(/ZH:SHA_256) # use SHA256 for generating hashes of compiler processed source files.
+ add_compile_options(/source-charset:utf-8) # Force MSVC to compile source as UTF-8.
+
+ if (CLR_CMAKE_PLATFORM_ARCH_I386)
+ add_compile_options(/Gz)
+ endif (CLR_CMAKE_PLATFORM_ARCH_I386)
+
+ add_compile_options($<$<OR:$<CONFIG:Release>,$<CONFIG:Relwithdebinfo>>:/GL>)
+ add_compile_options($<$<OR:$<OR:$<CONFIG:Release>,$<CONFIG:Relwithdebinfo>>,$<CONFIG:Checked>>:/O1>)
+
+ if (CLR_CMAKE_PLATFORM_ARCH_AMD64)
+ # The generator expression in the following command means that the /homeparams option is added only for debug builds
+ add_compile_options($<$<CONFIG:Debug>:/homeparams>) # Force parameters passed in registers to be written to the stack
+ endif (CLR_CMAKE_PLATFORM_ARCH_AMD64)
+
+ # enable control-flow-guard support for native components for non-Arm64 builds
+ add_compile_options(/guard:cf)
+
+ # Statically linked CRT (libcmt[d].lib, libvcruntime[d].lib and libucrt[d].lib) by default. This is done to avoid
+ # linking in VCRUNTIME140.DLL for a simplified xcopy experience by reducing the dependency on VC REDIST.
+ #
+ # For Release builds, we shall dynamically link into uCRT [ucrtbase.dll] (which is pushed down as a Windows Update on downlevel OS) but
+ # wont do the same for debug/checked builds since ucrtbased.dll is not redistributable and Debug/Checked builds are not
+ # production-time scenarios.
+ add_compile_options($<$<OR:$<CONFIG:Release>,$<CONFIG:Relwithdebinfo>>:/MT>)
+ add_compile_options($<$<OR:$<CONFIG:Debug>,$<CONFIG:Checked>>:/MTd>)
+
+ set(CMAKE_ASM_MASM_FLAGS "${CMAKE_ASM_MASM_FLAGS} /ZH:SHA_256")
+
+endif (WIN32)
+
+if(CLR_CMAKE_ENABLE_CODE_COVERAGE)
+
+ if(CLR_CMAKE_PLATFORM_UNIX)
+ string(TOUPPER ${CMAKE_BUILD_TYPE} UPPERCASE_CMAKE_BUILD_TYPE)
+ if(NOT UPPERCASE_CMAKE_BUILD_TYPE STREQUAL DEBUG)
+ message( WARNING "Code coverage results with an optimised (non-Debug) build may be misleading" )
+ endif(NOT UPPERCASE_CMAKE_BUILD_TYPE STREQUAL DEBUG)
+
+ add_compile_options(-fprofile-arcs)
+ add_compile_options(-ftest-coverage)
+ set(CLANG_COVERAGE_LINK_FLAGS "--coverage")
+ set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${CLANG_COVERAGE_LINK_FLAGS}")
+ set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${CLANG_COVERAGE_LINK_FLAGS}")
+ else()
+ message(FATAL_ERROR "Code coverage builds not supported on current platform")
+ endif(CLR_CMAKE_PLATFORM_UNIX)
+
+endif(CLR_CMAKE_ENABLE_CODE_COVERAGE)
# Visual Studio 15
VisualStudioVersion = 15.0.27004.2005
MinimumVisualStudioVersion = 10.0.40219.1
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SOS.NETCore", "src\SOS\NETCore\SOS.NETCore.csproj", "{20513BA2-A156-4A17-4C70-5AC2DBD4F833}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SOS.NETCore", "src\SOS\NETCore\SOS.NETCore.csproj", "{20513BA2-A156-4A17-4C70-5AC2DBD4F833}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestDebuggee", "src\SOS\TestDebuggee\TestDebuggee.csproj", "{6C43BE85-F8C3-4D76-8050-F25CE953A7FD}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{20513BA2-A156-4A17-4C70-5AC2DBD4F833}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{20513BA2-A156-4A17-4C70-5AC2DBD4F833}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {20513BA2-A156-4A17-4C70-5AC2DBD4F833}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {20513BA2-A156-4A17-4C70-5AC2DBD4F833}.Debug|x64.Build.0 = Debug|Any CPU
{20513BA2-A156-4A17-4C70-5AC2DBD4F833}.Release|Any CPU.ActiveCfg = Release|Any CPU
{20513BA2-A156-4A17-4C70-5AC2DBD4F833}.Release|Any CPU.Build.0 = Release|Any CPU
+ {20513BA2-A156-4A17-4C70-5AC2DBD4F833}.Release|x64.ActiveCfg = Release|Any CPU
+ {20513BA2-A156-4A17-4C70-5AC2DBD4F833}.Release|x64.Build.0 = Release|Any CPU
+ {6C43BE85-F8C3-4D76-8050-F25CE953A7FD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {6C43BE85-F8C3-4D76-8050-F25CE953A7FD}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {6C43BE85-F8C3-4D76-8050-F25CE953A7FD}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {6C43BE85-F8C3-4D76-8050-F25CE953A7FD}.Debug|x64.Build.0 = Debug|Any CPU
+ {6C43BE85-F8C3-4D76-8050-F25CE953A7FD}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {6C43BE85-F8C3-4D76-8050-F25CE953A7FD}.Release|Any CPU.Build.0 = Release|Any CPU
+ {6C43BE85-F8C3-4D76-8050-F25CE953A7FD}.Release|x64.ActiveCfg = Release|Any CPU
+ {6C43BE85-F8C3-4D76-8050-F25CE953A7FD}.Release|x64.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
--- /dev/null
+#!/usr/bin/env bash
+
+# Obtain the location of the bash script to figure out where the root of the repo is.
+source="${BASH_SOURCE[0]}"
+
+# Resolve $source until the file is no longer a symlink
+while [[ -h "$source" ]]; do
+ scriptroot="$( cd -P "$( dirname "$source" )" && pwd )"
+ source="$(readlink "$source")"
+ # if $source was a relative symlink, we need to resolve it relative to the path where the
+ # symlink file was located
+ [[ $source != /* ]] && source="$scriptroot/$source"
+done
+__ProjectRoot="$( cd -P "$( dirname "$source" )" && pwd )/.."
+
+__BuildOS=Linux
+__HostOS=Linux
+__BuildArch=x64
+__HostArch=x64
+__BuildType=Debug
+__PortableBuild=1
+__ExtraCmakeArgs=""
+__ClangMajorVersion=0
+__ClangMinorVersion=0
+__CrossBuild=0
+__NumProc=1
+__UnprocessedBuildArgs=
+__Build=0
+__Test=0
+
+usage()
+{
+ echo "Usage: $0 [options]"
+ echo "--build - build native components"
+ echo "--test - test native components"
+ echo "--architechure <x64|x86|arm|armel|arm64>"
+ echo "--configuration <debug|release>"
+ echo "--clangx.y - optional argument to build using clang version x.y."
+ exit 1
+}
+
+# Argument types supported by this script:
+#
+# Build architecture - valid values are: x64, x86, arm, armel, arm64
+# Build Type - valid values are: debug, release
+#
+# Set the default arguments for build
+
+# Use uname to determine what the CPU is.
+CPUName=$(uname -p)
+# Some Linux platforms report unknown for platform, but the arch for machine.
+if [ "$CPUName" == "unknown" ]; then
+ CPUName=$(uname -m)
+fi
+
+case $CPUName in
+ i686)
+ echo "Unsupported CPU $CPUName detected, build might not succeed!"
+ __BuildArch=x86
+ __HostArch=x86
+ ;;
+
+ x86_64)
+ __BuildArch=x64
+ __HostArch=x64
+ ;;
+
+ armv7l)
+ echo "Unsupported CPU $CPUName detected, build might not succeed!"
+ __BuildArch=arm
+ __HostArch=arm
+ ;;
+
+ aarch64)
+ __BuildArch=arm64
+ __HostArch=arm64
+ ;;
+
+ *)
+ echo "Unknown CPU $CPUName detected, configuring as if for x64"
+ __BuildArch=x64
+ __HostArch=x64
+ ;;
+esac
+
+# Use uname to determine what the OS is.
+OSName=$(uname -s)
+case $OSName in
+ Linux)
+ __BuildOS=Linux
+ __HostOS=Linux
+ ;;
+
+ Darwin)
+ __BuildOS=OSX
+ __HostOS=OSX
+ ;;
+
+ FreeBSD)
+ __BuildOS=FreeBSD
+ __HostOS=FreeBSD
+ ;;
+
+ OpenBSD)
+ __BuildOS=OpenBSD
+ __HostOS=OpenBSD
+ ;;
+
+ NetBSD)
+ __BuildOS=NetBSD
+ __HostOS=NetBSD
+ ;;
+
+ SunOS)
+ __BuildOS=SunOS
+ __HostOS=SunOS
+ ;;
+
+ *)
+ echo "Unsupported OS $OSName detected, configuring as if for Linux"
+ __BuildOS=Linux
+ __HostOS=Linux
+ ;;
+esac
+
+
+while :; do
+ if [ $# -le 0 ]; then
+ break
+ fi
+
+ lowerI="$(echo $1 | awk '{print tolower($0)}')"
+ case $lowerI in
+ -\?|-h|--help)
+ usage
+ exit 1
+ ;;
+
+ --build)
+ __Build=1
+ ;;
+
+ --test)
+ __Test=1
+ ;;
+
+ --configuration)
+ __BuildType=$2
+ shift
+ ;;
+
+ --architechure)
+ __BuildArch=$2
+ shift
+ ;;
+
+ --clang3.5)
+ __ClangMajorVersion=3
+ __ClangMinorVersion=5
+ ;;
+
+ --clang3.6)
+ __ClangMajorVersion=3
+ __ClangMinorVersion=6
+ ;;
+
+ --clang3.7)
+ __ClangMajorVersion=3
+ __ClangMinorVersion=7
+ ;;
+
+ --clang3.8)
+ __ClangMajorVersion=3
+ __ClangMinorVersion=8
+ ;;
+
+ --clang3.9)
+ __ClangMajorVersion=3
+ __ClangMinorVersion=9
+ ;;
+
+ --clang4.0)
+ __ClangMajorVersion=4
+ __ClangMinorVersion=0
+ ;;
+
+ *)
+ __UnprocessedBuildArgs="$__UnprocessedBuildArgs $1"
+ ;;
+ esac
+
+ shift
+done
+
+__RootBinDir=$__ProjectRoot/artifacts
+__IntermediatesDir="$__RootBinDir/obj/$__BuildOS.$__BuildArch.$__BuildType"
+__LogFileDir="$__RootBinDir/log/$__BuildOS.$__BuildArch.$__BuildType"
+
+# Specify path to be set for CMAKE_INSTALL_PREFIX.
+# This is where all built native libraries will copied to.
+export __CMakeBinDir="$__RootBinDir/bin/$__BuildOS.$__BuildArch.$__BuildType"
+
+# Set default clang version
+if [[ $__ClangMajorVersion == 0 && $__ClangMinorVersion == 0 ]]; then
+ if [[ "$__BuildArch" == "arm" || "$__BuildArch" == "armel" ]]; then
+ __ClangMajorVersion=5
+ __ClangMinorVersion=0
+ else
+ __ClangMajorVersion=3
+ __ClangMinorVersion=9
+ fi
+fi
+
+mkdir -p "$__IntermediatesDir"
+mkdir -p "$__LogFileDir"
+mkdir -p "$__CMakeBinDir"
+
+build_native()
+{
+ platformArch="$1"
+ intermediatesForBuild="$2"
+ extraCmakeArguments="$3"
+
+ # All set to commence the build
+ echo "Commencing $__DistroRid build for $__BuildOS.$__BuildArch.$__BuildType in $intermediatesForBuild"
+
+ generator=""
+ buildFile="Makefile"
+ buildTool="make"
+
+ pushd "$intermediatesForBuild"
+ echo "Invoking \"$__ProjectRoot/eng/gen-buildsys-clang.sh\" \"$__ProjectRoot\" $__ClangMajorVersion $__ClangMinorVersion $platformArch $__BuildType $generator $extraCmakeArguments $__cmakeargs"
+ "$__ProjectRoot/eng/gen-buildsys-clang.sh" "$__ProjectRoot" $__ClangMajorVersion $__ClangMinorVersion $platformArch $__BuildType $generator "$extraCmakeArguments" "$__cmakeargs"
+ popd
+
+ if [ ! -f "$intermediatesForBuild/$buildFile" ]; then
+ echo "Failed to generate build project!"
+ exit 1
+ fi
+
+ # Check that the makefiles were created.
+ pushd "$intermediatesForBuild"
+
+ echo "Executing $buildTool install -j $__NumProc"
+
+ $buildTool install -j $__NumProc
+ if [ $? != 0 ]; then
+ echo "Failed to build."
+ exit 1
+ fi
+
+ popd
+}
+
+initHostDistroRid()
+{
+ __HostDistroRid=""
+ if [ "$__HostOS" == "Linux" ]; then
+ if [ -e /etc/os-release ]; then
+ source /etc/os-release
+ __HostDistroRid="$ID.$VERSION_ID-$__HostArch"
+ elif [ -e /etc/redhat-release ]; then
+ local redhatRelease=$(</etc/redhat-release)
+ if [[ $redhatRelease == "CentOS release 6."* || $redhatRelease == "Red Hat Enterprise Linux Server release 6."* ]]; then
+ __HostDistroRid="rhel.6-$__HostArch"
+ fi
+ fi
+ fi
+
+ if [ "$__HostDistroRid" == "" ]; then
+ echo "WARNING: Can not determine runtime id for current distro."
+ fi
+}
+
+initTargetDistroRid()
+{
+ if [ $__CrossBuild == 1 ]; then
+ if [ "$__BuildOS" == "Linux" ]; then
+ if [ ! -e $ROOTFS_DIR/etc/os-release ]; then
+ echo "WARNING: Can not determine runtime id for current distro."
+ export __DistroRid=""
+ else
+ source $ROOTFS_DIR/etc/os-release
+ export __DistroRid="$ID.$VERSION_ID-$__BuildArch"
+ fi
+ fi
+ else
+ export __DistroRid="$__HostDistroRid"
+ fi
+
+ # Portable builds target the base RID
+ if [ $__PortableBuild == 1 ]; then
+ if [ "$__BuildOS" == "Linux" ]; then
+ export __DistroRid="linux-$__BuildArch"
+ elif [ "$__BuildOS" == "OSX" ]; then
+ export __DistroRid="osx-$__BuildArch"
+ fi
+ fi
+}
+
+# Init the host distro name
+initHostDistroRid
+
+# Init the target distro name
+initTargetDistroRid
+
+# Build native components
+if [ $__Build == 1 ]; then
+ build_native "$__BuildArch" "$__IntermediatesDir" "$__ExtraCmakeArgs"
+fi
+
+# Run native SOS/lldbplugin tests
+if [ $__Test == 1 ]; then
+ "$__ProjectRoot/src/SOS/tests/testsos.sh" "$__ProjectRoot" "$__CMakeBinDir" "$__RootBinDir/$__BuildType/bin" "$__LogFileDir" "$__BuildArch"
+fi
--- /dev/null
+#!/usr/bin/env bash
+
+source="${BASH_SOURCE[0]}"
+
+# resolve $SOURCE until the file is no longer a symlink
+while [[ -h $source ]]; do
+ scriptroot="$( cd -P "$( dirname "$source" )" && pwd )"
+ source="$(readlink "$source")"
+
+ # if $source was a relative symlink, we need to resolve it relative to the path where the
+ # symlink file was located
+ [[ $source != /* ]] && source="$scriptroot/$source"
+done
+
+scriptroot="$( cd -P "$( dirname "$source" )" && pwd )"
+
+# build/test managed components
+"$scriptroot/common/build.sh" $@
+
+# build/test native components
+"$scriptroot/build-native.sh" $@
+
--- /dev/null
+#!/usr/bin/env bash
+
+source="${BASH_SOURCE[0]}"
+
+# resolve $SOURCE until the file is no longer a symlink
+while [[ -h $source ]]; do
+ scriptroot="$( cd -P "$( dirname "$source" )" && pwd )"
+ source="$(readlink "$source")"
+
+ # if $source was a relative symlink, we need to resolve it relative to the path where
+ # the symlink file was located
+ [[ $source != /* ]] && source="$scriptroot/$source"
+done
+
+scriptroot="$( cd -P "$( dirname "$source" )" && pwd )"
+"$scriptroot/build.sh" --restore --build --test --pack --ci $@
--- /dev/null
+SET (CMAKE_C_FLAGS_INIT "-Wall -std=c11")
+SET (CMAKE_C_FLAGS_DEBUG_INIT "-g -O0")
+SET (CLR_C_FLAGS_CHECKED_INIT "-g -O1")
+# Refer to the below instruction to support __thread with -O2/-O3 on Linux/ARM
+# https://github.com/dotnet/coreclr/blob/master/Documentation/building/linux-instructions.md
+SET (CMAKE_C_FLAGS_RELEASE_INIT "-g -O1")
+SET (CMAKE_C_FLAGS_RELWITHDEBINFO_INIT "-g -O1")
+
+SET (CMAKE_CXX_FLAGS_INIT "-Wall -Wno-null-conversion -std=c++11")
+SET (CMAKE_CXX_FLAGS_DEBUG_INIT "-g -O0")
+SET (CLR_CXX_FLAGS_CHECKED_INIT "-g -O1")
+SET (CMAKE_CXX_FLAGS_RELEASE_INIT "-g -O1")
+SET (CMAKE_CXX_FLAGS_RELWITHDEBINFO_INIT "-g -O1")
+
+SET (CLR_DEFINES_DEBUG_INIT DEBUG _DEBUG _DBG URTBLDENV_FRIENDLY=Checked BUILDENV_CHECKED=1)
+SET (CLR_DEFINES_CHECKED_INIT DEBUG _DEBUG _DBG URTBLDENV_FRIENDLY=Checked BUILDENV_CHECKED=1)
+SET (CLR_DEFINES_RELEASE_INIT NDEBUG URTBLDENV_FRIENDLY=Retail)
+SET (CLR_DEFINES_RELWITHDEBINFO_INIT NDEBUG URTBLDENV_FRIENDLY=Retail)
+
+SET (CMAKE_INSTALL_PREFIX $ENV{__CMakeBinDir})
--- /dev/null
+SET (CMAKE_C_FLAGS_INIT "-Wall -std=c11")
+SET (CMAKE_C_FLAGS_DEBUG_INIT "-g -O0")
+SET (CLR_C_FLAGS_CHECKED_INIT "-g -O2")
+# Refer to the below instruction to support __thread with -O2/-O3 on Linux/ARM
+# https://github.com/dotnet/coreclr/blob/master/Documentation/building/linux-instructions.md
+SET (CMAKE_C_FLAGS_RELEASE_INIT "-g -O3")
+SET (CMAKE_C_FLAGS_RELWITHDEBINFO_INIT "-g -O2")
+
+SET (CMAKE_CXX_FLAGS_INIT "-Wall -Wno-null-conversion -std=c++11")
+SET (CMAKE_CXX_FLAGS_DEBUG_INIT "-g -O0")
+SET (CLR_CXX_FLAGS_CHECKED_INIT "-g -O2")
+SET (CMAKE_CXX_FLAGS_RELEASE_INIT "-g -O3")
+SET (CMAKE_CXX_FLAGS_RELWITHDEBINFO_INIT "-g -O2")
+
+SET (CLR_DEFINES_DEBUG_INIT DEBUG _DEBUG _DBG URTBLDENV_FRIENDLY=Checked BUILDENV_CHECKED=1)
+SET (CLR_DEFINES_CHECKED_INIT DEBUG _DEBUG _DBG URTBLDENV_FRIENDLY=Checked BUILDENV_CHECKED=1)
+SET (CLR_DEFINES_RELEASE_INIT NDEBUG URTBLDENV_FRIENDLY=Retail)
+SET (CLR_DEFINES_RELWITHDEBINFO_INIT NDEBUG URTBLDENV_FRIENDLY=Retail)
+
+SET (CMAKE_INSTALL_PREFIX $ENV{__CMakeBinDir})
--- /dev/null
+#!/usr/bin/env bash
+#
+# This file invokes cmake and generates the build system for Clang.
+#
+
+if [ $# -lt 4 ]
+then
+ echo "Usage..."
+ echo "gen-buildsys-clang.sh <path to top level CMakeLists.txt> <ClangMajorVersion> <ClangMinorVersion> <Architecture> [build flavor] [coverage] [ninja] [cmakeargs]"
+ echo "Specify the path to the top level CMake file - <ProjectK>/src/NDP"
+ echo "Specify the clang version to use, split into major and minor version"
+ echo "Specify the target architecture."
+ echo "Optionally specify the build configuration (flavor.) Defaults to DEBUG."
+ echo "Optionally specify 'coverage' to enable code coverage build."
+ echo "Target ninja instead of make. ninja must be on the PATH."
+ echo "Pass additional arguments to CMake call."
+ exit 1
+fi
+
+# Set up the environment to be used for building with clang.
+if command -v "clang-$2.$3" > /dev/null
+ then
+ export CC="$(command -v clang-$2.$3)"
+ export CXX="$(command -v clang++-$2.$3)"
+elif command -v "clang$2$3" > /dev/null
+ then
+ export CC="$(command -v clang$2$3)"
+ export CXX="$(command -v clang++$2$3)"
+elif command -v clang > /dev/null
+ then
+ export CC="$(command -v clang)"
+ export CXX="$(command -v clang++)"
+else
+ echo "Unable to find Clang Compiler"
+ exit 1
+fi
+
+build_arch="$4"
+buildtype=DEBUG
+build_tests=OFF
+generator="Unix Makefiles"
+__UnprocessedCMakeArgs=""
+
+for i in "${@:5}"; do
+ upperI="$(echo $i | awk '{print toupper($0)}')"
+ case $upperI in
+ # Possible build types are DEBUG, CHECKED, RELEASE, RELWITHDEBINFO, MINSIZEREL.
+ DEBUG | CHECKED | RELEASE | RELWITHDEBINFO | MINSIZEREL)
+ buildtype=$upperI
+ ;;
+ NINJA)
+ generator=Ninja
+ ;;
+ *)
+ __UnprocessedCMakeArgs="${__UnprocessedCMakeArgs}${__UnprocessedCMakeArgs:+ }$i"
+ esac
+done
+
+OS=`uname`
+
+# Locate llvm
+# This can be a little complicated, because the common use-case of Ubuntu with
+# llvm-3.5 installed uses a rather unusual llvm installation with the version
+# number postfixed (i.e. llvm-ar-3.5), so we check for that first.
+# On FreeBSD the version number is appended without point and dash (i.e.
+# llvm-ar35).
+# Additionally, OSX doesn't use the llvm- prefix.
+if [ $OS = "Linux" -o $OS = "FreeBSD" -o $OS = "OpenBSD" -o $OS = "NetBSD" -o $OS = "SunOS" ]; then
+ llvm_prefix="llvm-"
+elif [ $OS = "Darwin" ]; then
+ llvm_prefix=""
+else
+ echo "Unable to determine build platform"
+ exit 1
+fi
+
+desired_llvm_major_version=$2
+desired_llvm_minor_version=$3
+if [ $OS = "FreeBSD" ]; then
+ desired_llvm_version="$desired_llvm_major_version$desired_llvm_minor_version"
+elif [ $OS = "OpenBSD" ]; then
+ desired_llvm_version=""
+elif [ $OS = "NetBSD" ]; then
+ desired_llvm_version=""
+elif [ $OS = "SunOS" ]; then
+ desired_llvm_version=""
+else
+ desired_llvm_version="-$desired_llvm_major_version.$desired_llvm_minor_version"
+fi
+locate_llvm_exec() {
+ if command -v "$llvm_prefix$1$desired_llvm_version" > /dev/null 2>&1
+ then
+ echo "$(command -v $llvm_prefix$1$desired_llvm_version)"
+ elif command -v "$llvm_prefix$1" > /dev/null 2>&1
+ then
+ echo "$(command -v $llvm_prefix$1)"
+ else
+ exit 1
+ fi
+}
+
+llvm_ar="$(locate_llvm_exec ar)"
+[[ $? -eq 0 ]] || { echo "Unable to locate llvm-ar"; exit 1; }
+llvm_link="$(locate_llvm_exec link)"
+[[ $? -eq 0 ]] || { echo "Unable to locate llvm-link"; exit 1; }
+llvm_nm="$(locate_llvm_exec nm)"
+[[ $? -eq 0 ]] || { echo "Unable to locate llvm-nm"; exit 1; }
+if [ $OS = "Linux" -o $OS = "FreeBSD" -o $OS = "OpenBSD" -o $OS = "NetBSD" -o $OS = "SunOS" ]; then
+ llvm_objdump="$(locate_llvm_exec objdump)"
+ [[ $? -eq 0 ]] || { echo "Unable to locate llvm-objdump"; exit 1; }
+fi
+
+cmake_extra_defines=
+if [[ -n "$LLDB_LIB_DIR" ]]; then
+ cmake_extra_defines="$cmake_extra_defines -DWITH_LLDB_LIBS=$LLDB_LIB_DIR"
+fi
+if [[ -n "$LLDB_INCLUDE_DIR" ]]; then
+ cmake_extra_defines="$cmake_extra_defines -DWITH_LLDB_INCLUDES=$LLDB_INCLUDE_DIR"
+fi
+if [[ -n "$CROSSCOMPONENT" ]]; then
+ cmake_extra_defines="$cmake_extra_defines -DCLR_CROSS_COMPONENTS_BUILD=1"
+fi
+if [ "$CROSSCOMPILE" == "1" ]; then
+ if ! [[ -n "$ROOTFS_DIR" ]]; then
+ echo "ROOTFS_DIR not set for crosscompile"
+ exit 1
+ fi
+ if [[ -z $CONFIG_DIR ]]; then
+ CONFIG_DIR="$1/cross"
+ fi
+ export TARGET_BUILD_ARCH=$build_arch
+ cmake_extra_defines="$cmake_extra_defines -C $CONFIG_DIR/tryrun.cmake"
+ cmake_extra_defines="$cmake_extra_defines -DCMAKE_TOOLCHAIN_FILE=$CONFIG_DIR/toolchain.cmake"
+ cmake_extra_defines="$cmake_extra_defines -DCLR_UNIX_CROSS_BUILD=1"
+fi
+if [ $OS == "Linux" ]; then
+ linux_id_file="/etc/os-release"
+ if [[ -n "$CROSSCOMPILE" ]]; then
+ linux_id_file="$ROOTFS_DIR/$linux_id_file"
+ fi
+ if [[ -e $linux_id_file ]]; then
+ source $linux_id_file
+ cmake_extra_defines="$cmake_extra_defines -DCLR_CMAKE_LINUX_ID=$ID"
+ fi
+fi
+if [ "$build_arch" == "armel" ]; then
+ cmake_extra_defines="$cmake_extra_defines -DARM_SOFTFP=1"
+fi
+
+clang_version=$( $CC --version | head -1 | sed 's/[^0-9]*\([0-9]*\.[0-9]*\).*/\1/' )
+# Use O1 option when the clang version is smaller than 3.9
+# Otherwise use O3 option in release build
+if [[ ( ${clang_version%.*} -eq 3 && ${clang_version#*.} -lt 9 ) &&
+ ( "$build_arch" == "arm" || "$build_arch" == "armel" ) ]]; then
+ overridefile=clang-compiler-override-arm.txt
+else
+ overridefile=clang-compiler-override.txt
+fi
+
+cmake \
+ -G "$generator" \
+ "-DCMAKE_USER_MAKE_RULES_OVERRIDE=$1/eng/$overridefile" \
+ "-DCMAKE_AR=$llvm_ar" \
+ "-DCMAKE_LINKER=$llvm_link" \
+ "-DCMAKE_NM=$llvm_nm" \
+ "-DCMAKE_OBJDUMP=$llvm_objdump" \
+ "-DCMAKE_BUILD_TYPE=$buildtype" \
+ "-DCMAKE_EXPORT_COMPILE_COMMANDS=1 " \
+ $cmake_extra_defines \
+ $__UnprocessedCMakeArgs \
+ "$1"
--- /dev/null
+function(clr_unknown_arch)
+ if (WIN32)
+ message(FATAL_ERROR "Only AMD64, ARM64, ARM and I386 are supported")
+ elseif(CLR_CROSS_COMPONENTS_BUILD)
+ message(FATAL_ERROR "Only AMD64, I386 host are supported for linux cross-architecture component")
+ else()
+ message(FATAL_ERROR "Only AMD64, ARM64 and ARM are supported")
+ endif()
+endfunction()
+
+function(strip_symbols targetName outputFilename)
+ if (CLR_CMAKE_PLATFORM_UNIX)
+ if (STRIP_SYMBOLS)
+
+ # On the older version of cmake (2.8.12) used on Ubuntu 14.04 the TARGET_FILE
+ # generator expression doesn't work correctly returning the wrong path and on
+ # the newer cmake versions the LOCATION property isn't supported anymore.
+ if (CMAKE_VERSION VERSION_EQUAL 3.0 OR CMAKE_VERSION VERSION_GREATER 3.0)
+ set(strip_source_file $<TARGET_FILE:${targetName}>)
+ else()
+ get_property(strip_source_file TARGET ${targetName} PROPERTY LOCATION)
+ endif()
+
+ if (CMAKE_SYSTEM_NAME STREQUAL Darwin)
+ set(strip_destination_file ${strip_source_file}.dwarf)
+
+ add_custom_command(
+ TARGET ${targetName}
+ POST_BUILD
+ VERBATIM
+ COMMAND ${DSYMUTIL} --flat --minimize ${strip_source_file}
+ COMMAND ${STRIP} -S ${strip_source_file}
+ COMMENT Stripping symbols from ${strip_source_file} into file ${strip_destination_file}
+ )
+ else (CMAKE_SYSTEM_NAME STREQUAL Darwin)
+ set(strip_destination_file ${strip_source_file}.dbg)
+
+ add_custom_command(
+ TARGET ${targetName}
+ POST_BUILD
+ VERBATIM
+ COMMAND ${OBJCOPY} --only-keep-debug ${strip_source_file} ${strip_destination_file}
+ COMMAND ${OBJCOPY} --strip-debug ${strip_source_file}
+ COMMAND ${OBJCOPY} --add-gnu-debuglink=${strip_destination_file} ${strip_source_file}
+ COMMENT Stripping symbols from ${strip_source_file} into file ${strip_destination_file}
+ )
+ endif (CMAKE_SYSTEM_NAME STREQUAL Darwin)
+
+ set(${outputFilename} ${strip_destination_file} PARENT_SCOPE)
+ endif (STRIP_SYMBOLS)
+ endif(CLR_CMAKE_PLATFORM_UNIX)
+endfunction()
+
+function(install_clr targetName)
+ list(FIND CLR_CROSS_COMPONENTS_LIST ${targetName} INDEX)
+ if (NOT DEFINED CLR_CROSS_COMPONENTS_LIST OR NOT ${INDEX} EQUAL -1)
+ strip_symbols(${targetName} strip_destination_file)
+ # On the older version of cmake (2.8.12) used on Ubuntu 14.04 the TARGET_FILE
+ # generator expression doesn't work correctly returning the wrong path and on
+ # the newer cmake versions the LOCATION property isn't supported anymore.
+ if(CMAKE_VERSION VERSION_EQUAL 3.0 OR CMAKE_VERSION VERSION_GREATER 3.0)
+ set(install_source_file $<TARGET_FILE:${targetName}>)
+ else()
+ get_property(install_source_file TARGET ${targetName} PROPERTY LOCATION)
+ endif()
+
+ install(PROGRAMS ${install_source_file} DESTINATION .)
+ if(WIN32)
+ install(FILES ${CMAKE_CURRENT_BINARY_DIR}/$<CONFIG>/${targetName}.pdb DESTINATION PDB)
+ else()
+ install(FILES ${strip_destination_file} DESTINATION .)
+ endif()
+ if(CLR_CMAKE_PGO_INSTRUMENT)
+ if(WIN32)
+ install(FILES ${CMAKE_CURRENT_BINARY_DIR}/$<CONFIG>/${targetName}.pgd DESTINATION PGD OPTIONAL)
+ endif()
+ endif()
+ endif()
+endfunction()
+
+function(_add_library)
+ if(NOT WIN32)
+ add_library(${ARGV} ${VERSION_FILE_PATH})
+ else()
+ add_library(${ARGV})
+ endif(NOT WIN32)
+ list(FIND CLR_CROSS_COMPONENTS_LIST ${ARGV0} INDEX)
+ if (DEFINED CLR_CROSS_COMPONENTS_LIST AND ${INDEX} EQUAL -1)
+ set_target_properties(${ARGV0} PROPERTIES EXCLUDE_FROM_ALL 1)
+ endif()
+endfunction()
+
+function(add_library_clr)
+ _add_library(${ARGV})
+endfunction()
// Groovy Script: http://www.groovy-lang.org/syntax.html
// Jenkins DSL: https://github.com/jenkinsci/job-dsl-plugin/wiki
-import jobs.generation.Utilities;
+// Import the pipeline declaration classes.
+import org.dotnet.ci.pipelines.Pipeline
+
+// The input project name (e.g. dotnet/diagnostics)
+def project = GithubProject
+
+// The input branch name (e.g. master)
+def branch = GithubBranchName
+
+class Constants {
+
+ def static osList = [
+ 'Windows_NT',
+// 'Ubuntu',
+ 'Ubuntu16.04',
+// 'Ubuntu16.10',
+// 'Debian8.4',
+ 'CentOS7.1',
+// 'RHEL7.2',
+// 'Fedora24'
+ ]
+
+ def static configurationList = [
+// 'Debug',
+ 'Release'
+ ]
+
+ // This is the set of architectures
+ def static architectureList = [
+// 'arm',
+// 'arm64',
+ 'x64',
+// 'x86'
+ ]
-static getJobName(def opsysName, def configName) {
- return "${opsysName}_${configName}"
}
-static addArchival(def job, def filesToArchive, def filesToExclude) {
- def doNotFailIfNothingArchived = false
- def archiveOnlyIfSuccessful = false
+// Create build and test pipeline job
+def pipeline = Pipeline.createPipeline(this, project, branch, 'pipeline.groovy')
- Utilities.addArchival(job, filesToArchive, filesToExclude, doNotFailIfNothingArchived, archiveOnlyIfSuccessful)
-}
-
-static addGithubPRTriggerForBranch(def job, def branchName, def jobName) {
- def prContext = "prtest/${jobName.replace('_', '/')}"
- def triggerPhrase = "(?i)^\\s*(@?dotnet-bot\\s+)?(re)?test\\s+(${prContext})(\\s+please)?\\s*\$"
- def triggerOnPhraseOnly = false
-
- Utilities.addGithubPRTriggerForBranch(job, branchName, prContext, triggerPhrase, triggerOnPhraseOnly)
-}
-
-static addXUnitDotNETResults(def job, def configName) {
- def resultFilePattern = "**/artifacts/${configName}/TestResults/*.xml"
- def skipIfNoTestFiles = false
-
- Utilities.addXUnitDotNETResults(job, resultFilePattern, skipIfNoTestFiles)
-}
-
-static addBuildSteps(def job, def projectName, def os, def configName, def isPR) {
- def buildJobName = getJobName(os, configName)
- def buildFullJobName = Utilities.getFullJobName(projectName, buildJobName, isPR)
-
- job.with {
- steps {
- if (os == "Windows_NT") {
- batchFile(""".\\eng\\common\\CIBuild.cmd -configuration ${configName} -prepareMachine""")
- } else {
- shell("./eng/common/cibuild.sh --configuration ${configName} --prepareMachine")
- }
- }
- }
-}
-
-[true, false].each { isPR ->
- ['Ubuntu16.04', 'Windows_NT'].each { os ->
- ['Debug', 'Release'].each { configName ->
- def projectName = GithubProject
-
- def branchName = GithubBranchName
-
- def filesToArchive = "**/artifacts/${configName}/**"
-
- def jobName = getJobName(os, configName)
- def fullJobName = Utilities.getFullJobName(projectName, jobName, isPR)
- def myJob = job(fullJobName)
-
- Utilities.standardJobSetup(myJob, projectName, isPR, "*/${branchName}")
-
- if (isPR) {
- addGithubPRTriggerForBranch(myJob, branchName, jobName)
- } else {
- Utilities.addGithubPushTrigger(myJob)
- }
-
- addArchival(myJob, filesToArchive, "")
- addXUnitDotNETResults(myJob, configName)
+Constants.osList.each { os ->
+ Constants.architectureList.each { architechure ->
+ Constants.configurationList.each { configuration ->
+ def triggerName = "${os} ${architechure} ${configuration} Build and Test"
+ def params = ['OS':os, 'Architechure':architechure, 'Configuration':configuration]
- if (os == 'Windows_NT') {
- Utilities.setMachineAffinity(myJob, os, 'latest-dev15-3')
- } else {
- Utilities.setMachineAffinity(myJob, os, 'latest-or-auto')
- }
+ pipeline.triggerPipelineOnEveryPR(triggerName, params)
- addBuildSteps(myJob, projectName, os, configName, isPR)
+ // Add trigger to run on merge
+ pipeline.triggerPipelineOnPush(params)
+ }
}
- }
}
--- /dev/null
+@Library('dotnet-ci') _
+import jobs.generation.Utilities
+
+// Accepts parameters
+// OS - Windows_NT, Ubuntu, Ubuntu16.04, Ubuntu16.10, Debian8.4, CentOS7.1, RHEL7.2, Fedora24
+// Architechure - x64, x86, arm, arm64
+// Configuration - Debug or Release
+
+def os = params.OS
+def architechure = params.Architechure
+def configuration = params.Configuration
+
+// build and test
+simpleNode(os, 'latest') {
+
+ stage ('Checkout Source') {
+ checkout scm
+ }
+
+ stage ('Build/Test') {
+
+ if (os == "Windows_NT") {
+ bat ".\\eng\\common\\CIBuild.cmd -configuration ${configuration} -prepareMachine"
+ } else {
+ sh "./eng/cibuild.sh --configuration ${configuration} --architechure ${architechure} --prepareMachine"
+ }
+ }
+
+ stage ('Archive artifacts') {
+ def resultFilePattern = "**/artifacts/${configuration}/TestResults/*.xml"
+ Utilities.addXUnitDotNETResults(job, resultFilePattern, skipIfNoTestFiles: false)
+
+ def filesToArchive = "**/artifacts/${configuration}/**"
+ archiveArtifacts allowEmptyArchive: true, artifacts: filesToArchive
+ }
+}
done
scriptroot="$( cd -P "$( dirname "$source" )" && pwd )"
-"$scriptroot/eng/common/build.sh" --restore $@
\ No newline at end of file
+"$scriptroot/eng/build.sh" --restore $@
--- /dev/null
+add_subdirectory(SOS)
--- /dev/null
+if(CLR_CMAKE_PLATFORM_UNIX)
+ add_subdirectory(lldbplugin)
+endif(CLR_CMAKE_PLATFORM_UNIX)
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+
+class Test
+{
+ static void LikelyInlined()
+ {
+ Console.WriteLine("I would like to be inlined");
+ }
+
+ static void UnlikelyInlined()
+ {
+ Console.Write("I");
+ Console.Write(" ");
+ Console.Write("w");
+ Console.Write("o");
+ Console.Write("u");
+ Console.Write("l");
+ Console.Write("d");
+ Console.Write(" ");
+ Console.Write("n");
+ Console.Write("o");
+ Console.Write("t");
+ Console.Write(" ");
+ Console.Write("l");
+ Console.Write("i");
+ Console.Write("k");
+ Console.Write("e");
+ Console.Write(" ");
+ Console.Write("t");
+ Console.Write("o");
+ Console.Write(" ");
+ Console.Write("b");
+ Console.Write("e");
+ Console.Write(" ");
+ Console.Write("i");
+ Console.Write("n");
+ Console.Write("l");
+ Console.Write("i");
+ Console.Write("n");
+ Console.Write("e");
+ Console.Write("d");
+ Console.Write("\n");
+ }
+
+ static void ClrU()
+ {
+ Console.WriteLine("test dumpclass");
+ }
+
+ static void DumpClass()
+ {
+ Console.WriteLine("test dumpclass");
+ }
+
+ static void DumpIL()
+ {
+ Console.WriteLine("test dumpil");
+ }
+
+ static void DumpMD()
+ {
+ Console.WriteLine("test dumpmd");
+ }
+
+ static void DumpModule()
+ {
+ Console.WriteLine("test dumpmodule");
+ }
+
+ static void DumpObject()
+ {
+ Console.WriteLine("test dumpobject");
+ }
+
+ static void DumpStackObjects()
+ {
+ Console.WriteLine("test dso");
+ }
+
+ static void Name2EE()
+ {
+ Console.WriteLine("test name2ee");
+ }
+
+
+ static int Main()
+ {
+ DumpIL();
+ LikelyInlined();
+ UnlikelyInlined();
+
+ return 0;
+ }
+}
--- /dev/null
+<!-- Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -->
+<Project Sdk="RoslynTools.RepoToolset">
+ <PropertyGroup>
+ <OutputType>Exe</OutputType>
+ <TargetFrameworks>netcoreapp1.0;netcoreapp2.0</TargetFrameworks>
+ <GenerateRuntimeConfigurationFiles>true</GenerateRuntimeConfigurationFiles>
+ <NoWarn>;1591;1701</NoWarn>
+ </PropertyGroup>
+</Project>
--- /dev/null
+project(sosplugin)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+# Set the RPATH of the plugin so that it can find dependencies without needing to set LD_LIBRARY_PATH
+# For more information: http://www.cmake.org/Wiki/CMake_RPATH_handling.
+if (CORECLR_SET_RPATH)
+ set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE)
+ if(CLR_CMAKE_PLATFORM_DARWIN)
+ set(CMAKE_INSTALL_RPATH "@loader_path")
+ else()
+ set(CMAKE_INSTALL_RPATH "\$ORIGIN")
+ endif(CLR_CMAKE_PLATFORM_DARWIN)
+endif (CORECLR_SET_RPATH)
+
+add_definitions(-DPAL_STDCPP_COMPAT)
+
+set(ENABLE_LLDBPLUGIN ${CLR_CMAKE_PLATFORM_UNIX} CACHE BOOL "Enable building the SOS plugin for LLDB.")
+set(REQUIRE_LLDBPLUGIN ${CLR_CMAKE_PLATFORM_LINUX} CACHE BOOL "Require building the SOS plugin for LLDB.")
+
+if(SKIP_LLDBPLUGIN)
+ SET(REQUIRE_LLDBPLUGIN false)
+endif()
+
+if(CLR_CMAKE_PLATFORM_ARCH_AMD64)
+ add_definitions(-D_TARGET_AMD64_=1)
+ add_definitions(-DDBG_TARGET_64BIT=1)
+ add_definitions(-DDBG_TARGET_AMD64=1)
+ add_definitions(-DDBG_TARGET_WIN64=1)
+ add_definitions(-DBIT64)
+elseif(CLR_CMAKE_PLATFORM_ARCH_I386)
+ add_definitions(-D_TARGET_X86_=1)
+ add_definitions(-DDBG_TARGET_32BIT=1)
+ add_definitions(-DDBG_TARGET_X86=1)
+elseif(CLR_CMAKE_PLATFORM_ARCH_ARM)
+ add_definitions(-D_TARGET_ARM_=1)
+ add_definitions(-DDBG_TARGET_32BIT=1)
+ add_definitions(-DDBG_TARGET_ARM=1)
+elseif(CLR_CMAKE_PLATFORM_ARCH_ARM64)
+ add_definitions(-D_TARGET_ARM64_=1)
+ add_definitions(-DDBG_TARGET_64BIT=1)
+ add_definitions(-DDBG_TARGET_ARM64=1)
+ add_definitions(-DDBG_TARGET_WIN64=1)
+ add_definitions(-DBIT64)
+ SET(REQUIRE_LLDBPLUGIN false)
+endif()
+
+set(LLVM_HOST_DIR "$ENV{LLVM_HOME}")
+set(WITH_LLDB_LIBS "${LLVM_HOST_DIR}/lib" CACHE PATH "Path to LLDB libraries")
+set(WITH_LLDB_INCLUDES "${LLVM_HOST_DIR}/include" CACHE PATH "Path to LLDB headers")
+
+if(NOT ENABLE_LLDBPLUGIN)
+ return()
+endif()
+
+if (CLR_CMAKE_PLATFORM_DARWIN)
+ # Check for LLDB library
+ find_library(LLDB NAMES LLDB lldb lldb-6.0 lldb-5.0 lldb-4.0 lldb-3.9 lldb-3.8 lldb-3.7 lldb-3.6 lldb-3.5 PATHS "${WITH_LLDB_LIBS}" PATH_SUFFIXES llvm NO_DEFAULT_PATH)
+ find_library(LLDB NAMES LLDB lldb lldb-6.0 lldb-5.0 lldb-4.0 lldb-3.9 lldb-3.8 lldb-3.7 lldb-3.6 lldb-3.5 PATH_SUFFIXES llvm)
+ if(LLDB STREQUAL LLDB-NOTFOUND)
+ if(REQUIRE_LLDBPLUGIN)
+ set(MESSAGE_MODE FATAL_ERROR)
+ else()
+ set(MESSAGE_MODE WARNING)
+ endif()
+ message(${MESSAGE_MODE} "Cannot find lldb-3.5, lldb-3.6, lldb-3.8, lldb-3.9, lldb-4.0, lldb-5.0 or lldb-6.0. Try installing liblldb-3.9-dev (or the appropriate package for your platform). You may need to set LLVM_HOME if the build still can't find it.")
+
+ return()
+ endif()
+
+ message(STATUS "LLDB: ${LLDB}")
+endif()
+
+# Check for LLDB headers
+# Multiple versions of LLDB can install side-by-side, so we need to check for lldb in various locations.
+# If the file in a directory is found the result is stored in the variable and the search will not be repeated unless the variable is cleared.
+find_path(LLDB_H "lldb/API/LLDB.h" PATHS "${WITH_LLDB_INCLUDES}" NO_DEFAULT_PATH)
+find_path(LLDB_H "lldb/API/LLDB.h")
+find_path(LLDB_H "lldb/API/LLDB.h" PATHS "/usr/lib/llvm-6.0/include")
+find_path(LLDB_H "lldb/API/LLDB.h" PATHS "/usr/lib/llvm-5.0/include")
+find_path(LLDB_H "lldb/API/LLDB.h" PATHS "/usr/lib/llvm-4.0/include")
+find_path(LLDB_H "lldb/API/LLDB.h" PATHS "/usr/lib/llvm-3.9/include")
+find_path(LLDB_H "lldb/API/LLDB.h" PATHS "/usr/lib/llvm-3.8/include")
+find_path(LLDB_H "lldb/API/LLDB.h" PATHS "/usr/lib/llvm-3.7/include")
+find_path(LLDB_H "lldb/API/LLDB.h" PATHS "/usr/lib/llvm-3.6/include")
+find_path(LLDB_H "lldb/API/LLDB.h" PATHS "/usr/lib/llvm-3.5/include")
+#FreeBSD
+find_path(LLDB_H "lldb/API/LLDB.h" PATHS "/usr/local/llvm39/include")
+find_path(LLDB_H "lldb/API/LLDB.h" PATHS "/usr/local/llvm38/include")
+
+if(LLDB_H STREQUAL LLDB_H-NOTFOUND)
+ if(REQUIRE_LLDBPLUGIN)
+ set(MESSAGE_MODE FATAL_ERROR)
+ else()
+ set(MESSAGE_MODE WARNING)
+ endif()
+ message(${MESSAGE_MODE} "Cannot find LLDB.h Try installing lldb-3.9-dev (or the appropriate package for your platform). You may need to set LLVM_HOME if the build still can't find it.")
+ return()
+endif()
+
+message(STATUS "LLDB_H: ${LLDB_H}")
+
+add_compile_options(-Wno-delete-non-virtual-dtor)
+
+include_directories(inc)
+include_directories("${LLDB_H}")
+
+set(SOURCES
+ sosplugin.cpp
+ soscommand.cpp
+ setclrpathcommand.cpp
+ setsostidcommand.cpp
+ services.cpp
+)
+
+_add_library(sosplugin SHARED ${SOURCES})
+
+if (CLR_CMAKE_PLATFORM_DARWIN)
+ target_link_libraries(sosplugin ${LLDB})
+endif()
+
+# add the install targets
+install_clr(sosplugin)
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+// crosscomp.h - cross-compilation enablement structures.
+//
+
+
+#pragma once
+
+#if defined(_X86_) && defined(_TARGET_ARM_) // Host X86 managing ARM related code
+
+#ifndef CROSS_COMPILE
+#define CROSS_COMPILE
+#endif
+
+#define ARM_MAX_BREAKPOINTS 8
+#define ARM_MAX_WATCHPOINTS 1
+
+#define CONTEXT_UNWOUND_TO_CALL 0x20000000
+
+typedef struct _NEON128 {
+ ULONGLONG Low;
+ LONGLONG High;
+} NEON128, *PNEON128;
+
+typedef struct DECLSPEC_ALIGN(8) _T_CONTEXT {
+ //
+ // Control flags.
+ //
+
+ DWORD ContextFlags;
+
+ //
+ // Integer registers
+ //
+
+ DWORD R0;
+ DWORD R1;
+ DWORD R2;
+ DWORD R3;
+ DWORD R4;
+ DWORD R5;
+ DWORD R6;
+ DWORD R7;
+ DWORD R8;
+ DWORD R9;
+ DWORD R10;
+ DWORD R11;
+ DWORD R12;
+
+ //
+ // Control Registers
+ //
+
+ DWORD Sp;
+ DWORD Lr;
+ DWORD Pc;
+ DWORD Cpsr;
+
+ //
+ // Floating Point/NEON Registers
+ //
+
+ DWORD Fpscr;
+ DWORD Padding;
+ union {
+ NEON128 Q[16];
+ ULONGLONG D[32];
+ DWORD S[32];
+ };
+
+ //
+ // Debug registers
+ //
+
+ DWORD Bvr[ARM_MAX_BREAKPOINTS];
+ DWORD Bcr[ARM_MAX_BREAKPOINTS];
+ DWORD Wvr[ARM_MAX_WATCHPOINTS];
+ DWORD Wcr[ARM_MAX_WATCHPOINTS];
+
+ DWORD Padding2[2];
+
+} T_CONTEXT, *PT_CONTEXT;
+
+//
+// Define function table entry - a function table entry is generated for
+// each frame function.
+//
+
+#ifndef FEATURE_PAL
+typedef struct _RUNTIME_FUNCTION {
+ DWORD BeginAddress;
+ DWORD UnwindData;
+} RUNTIME_FUNCTION, *PRUNTIME_FUNCTION;
+
+//
+// Define unwind history table structure.
+//
+
+#define UNWIND_HISTORY_TABLE_SIZE 12
+
+typedef struct _UNWIND_HISTORY_TABLE_ENTRY {
+ DWORD ImageBase;
+ PRUNTIME_FUNCTION FunctionEntry;
+} UNWIND_HISTORY_TABLE_ENTRY, *PUNWIND_HISTORY_TABLE_ENTRY;
+
+typedef struct _UNWIND_HISTORY_TABLE {
+ DWORD Count;
+ BYTE LocalHint;
+ BYTE GlobalHint;
+ BYTE Search;
+ BYTE Once;
+ DWORD LowAddress;
+ DWORD HighAddress;
+ UNWIND_HISTORY_TABLE_ENTRY Entry[UNWIND_HISTORY_TABLE_SIZE];
+} UNWIND_HISTORY_TABLE, *PUNWIND_HISTORY_TABLE;
+#endif // !FEATURE_PAL
+
+
+//
+// Nonvolatile context pointer record.
+//
+
+typedef struct _T_KNONVOLATILE_CONTEXT_POINTERS {
+
+ PDWORD R4;
+ PDWORD R5;
+ PDWORD R6;
+ PDWORD R7;
+ PDWORD R8;
+ PDWORD R9;
+ PDWORD R10;
+ PDWORD R11;
+ PDWORD Lr;
+
+ PULONGLONG D8;
+ PULONGLONG D9;
+ PULONGLONG D10;
+ PULONGLONG D11;
+ PULONGLONG D12;
+ PULONGLONG D13;
+ PULONGLONG D14;
+ PULONGLONG D15;
+
+} T_KNONVOLATILE_CONTEXT_POINTERS, *PT_KNONVOLATILE_CONTEXT_POINTERS;
+
+//
+// Define dynamic function table entry.
+//
+
+typedef
+PRUNTIME_FUNCTION
+(*PGET_RUNTIME_FUNCTION_CALLBACK) (
+ IN DWORD64 ControlPc,
+ IN PVOID Context
+ );
+
+typedef struct _T_DISPATCHER_CONTEXT {
+ ULONG ControlPc;
+ ULONG ImageBase;
+ PRUNTIME_FUNCTION FunctionEntry;
+ ULONG EstablisherFrame;
+ ULONG TargetPc;
+ PT_CONTEXT ContextRecord;
+ PEXCEPTION_ROUTINE LanguageHandler;
+ PVOID HandlerData;
+ PUNWIND_HISTORY_TABLE HistoryTable;
+ ULONG ScopeIndex;
+ BOOLEAN ControlPcIsUnwound;
+ PUCHAR NonVolatileRegisters;
+} T_DISPATCHER_CONTEXT, *PT_DISPATCHER_CONTEXT;
+
+#define T_RUNTIME_FUNCTION RUNTIME_FUNCTION
+#define PT_RUNTIME_FUNCTION PRUNTIME_FUNCTION
+
+#elif defined(_AMD64_) && defined(_TARGET_ARM64_) // Host amd64 managing ARM64 related code
+
+#ifndef CROSS_COMPILE
+#define CROSS_COMPILE
+#endif
+
+//
+// Specify the number of breakpoints and watchpoints that the OS
+// will track. Architecturally, ARM64 supports up to 16. In practice,
+// however, almost no one implements more than 4 of each.
+//
+
+#define ARM64_MAX_BREAKPOINTS 8
+#define ARM64_MAX_WATCHPOINTS 2
+
+#define CONTEXT_UNWOUND_TO_CALL 0x20000000
+
+typedef union _NEON128 {
+ struct {
+ ULONGLONG Low;
+ LONGLONG High;
+ };
+ double D[2];
+ float S[4];
+ WORD H[8];
+ BYTE B[16];
+} NEON128, *PNEON128;
+
+typedef struct DECLSPEC_ALIGN(16) _T_CONTEXT {
+
+ //
+ // Control flags.
+ //
+
+ /* +0x000 */ DWORD ContextFlags;
+
+ //
+ // Integer registers
+ //
+
+ /* +0x004 */ DWORD Cpsr; // NZVF + DAIF + CurrentEL + SPSel
+ /* +0x008 */ union {
+ struct {
+ DWORD64 X0;
+ DWORD64 X1;
+ DWORD64 X2;
+ DWORD64 X3;
+ DWORD64 X4;
+ DWORD64 X5;
+ DWORD64 X6;
+ DWORD64 X7;
+ DWORD64 X8;
+ DWORD64 X9;
+ DWORD64 X10;
+ DWORD64 X11;
+ DWORD64 X12;
+ DWORD64 X13;
+ DWORD64 X14;
+ DWORD64 X15;
+ DWORD64 X16;
+ DWORD64 X17;
+ DWORD64 X18;
+ DWORD64 X19;
+ DWORD64 X20;
+ DWORD64 X21;
+ DWORD64 X22;
+ DWORD64 X23;
+ DWORD64 X24;
+ DWORD64 X25;
+ DWORD64 X26;
+ DWORD64 X27;
+ DWORD64 X28;
+ };
+ DWORD64 X[29];
+ };
+ /* +0x0f0 */ DWORD64 Fp;
+ /* +0x0f8 */ DWORD64 Lr;
+ /* +0x100 */ DWORD64 Sp;
+ /* +0x108 */ DWORD64 Pc;
+
+ //
+ // Floating Point/NEON Registers
+ //
+
+ /* +0x110 */ NEON128 V[32];
+ /* +0x310 */ DWORD Fpcr;
+ /* +0x314 */ DWORD Fpsr;
+
+ //
+ // Debug registers
+ //
+
+ /* +0x318 */ DWORD Bcr[ARM64_MAX_BREAKPOINTS];
+ /* +0x338 */ DWORD64 Bvr[ARM64_MAX_BREAKPOINTS];
+ /* +0x378 */ DWORD Wcr[ARM64_MAX_WATCHPOINTS];
+ /* +0x380 */ DWORD64 Wvr[ARM64_MAX_WATCHPOINTS];
+ /* +0x390 */
+
+} T_CONTEXT, *PT_CONTEXT;
+
+// _IMAGE_ARM64_RUNTIME_FUNCTION_ENTRY (see ExternalAPIs\Win9CoreSystem\inc\winnt.h)
+typedef struct _T_RUNTIME_FUNCTION {
+ DWORD BeginAddress;
+ union {
+ DWORD UnwindData;
+ struct {
+ DWORD Flag : 2;
+ DWORD FunctionLength : 11;
+ DWORD RegF : 3;
+ DWORD RegI : 4;
+ DWORD H : 1;
+ DWORD CR : 2;
+ DWORD FrameSize : 9;
+ } PackedUnwindData;
+ };
+} T_RUNTIME_FUNCTION, *PT_RUNTIME_FUNCTION;
+
+
+//
+// Define exception dispatch context structure.
+//
+
+typedef struct _T_DISPATCHER_CONTEXT {
+ DWORD64 ControlPc;
+ DWORD64 ImageBase;
+ PT_RUNTIME_FUNCTION FunctionEntry;
+ DWORD64 EstablisherFrame;
+ DWORD64 TargetPc;
+ PCONTEXT ContextRecord;
+ PEXCEPTION_ROUTINE LanguageHandler;
+ PVOID HandlerData;
+ PUNWIND_HISTORY_TABLE HistoryTable;
+ DWORD ScopeIndex;
+ BOOLEAN ControlPcIsUnwound;
+ PBYTE NonVolatileRegisters;
+} T_DISPATCHER_CONTEXT, *PT_DISPATCHER_CONTEXT;
+
+
+
+//
+// Nonvolatile context pointer record.
+//
+
+typedef struct _T_KNONVOLATILE_CONTEXT_POINTERS {
+
+ PDWORD64 X19;
+ PDWORD64 X20;
+ PDWORD64 X21;
+ PDWORD64 X22;
+ PDWORD64 X23;
+ PDWORD64 X24;
+ PDWORD64 X25;
+ PDWORD64 X26;
+ PDWORD64 X27;
+ PDWORD64 X28;
+ PDWORD64 Fp;
+ PDWORD64 Lr;
+
+ PDWORD64 D8;
+ PDWORD64 D9;
+ PDWORD64 D10;
+ PDWORD64 D11;
+ PDWORD64 D12;
+ PDWORD64 D13;
+ PDWORD64 D14;
+ PDWORD64 D15;
+
+} T_KNONVOLATILE_CONTEXT_POINTERS, *PT_KNONVOLATILE_CONTEXT_POINTERS;
+
+#else // !(defined(_X86_) && defined(_TARGET_ARM_)) && !(defined(_AMD64_) && defined(_TARGET_ARM64_))
+
+#define T_CONTEXT CONTEXT
+#define PT_CONTEXT PCONTEXT
+
+#define T_DISPATCHER_CONTEXT DISPATCHER_CONTEXT
+#define PT_DISPATCHER_CONTEXT PDISPATCHER_CONTEXT
+
+#define T_KNONVOLATILE_CONTEXT_POINTERS KNONVOLATILE_CONTEXT_POINTERS
+#define PT_KNONVOLATILE_CONTEXT_POINTERS PKNONVOLATILE_CONTEXT_POINTERS
+
+#define T_RUNTIME_FUNCTION RUNTIME_FUNCTION
+#define PT_RUNTIME_FUNCTION PRUNTIME_FUNCTION
+
+#endif
+
+
+#ifdef CROSSGEN_COMPILE
+void CrossGenNotSupported(const char * message);
+#endif
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#ifndef __DBG_PORTABLE_INCLUDED
+#define __DBG_PORTABLE_INCLUDED
+
+//
+// This header defines the template class Portable<T> which is designed to wrap primitive types in such a way
+// that their physical representation is in a canonical format that can be safely transferred between hosts on
+// different platforms.
+//
+// This is achieved by storing the wrapped datum in little-endian format (since most of our platforms are
+// little-endian this makes the most sense from a performance perspective). On little-endian platforms the
+// wrapper code will become a no-op and get optimized away by the compiler. On big-endian platforms
+// assignments to a Portable<T> value will reverse the order of the bytes in the T value and reverse them back
+// again on a read.
+//
+// Portable<T> is typically used to wrap the fields of structures sent directly over a network channel. In
+// this fashion many of the values that would otherwise require manual endian-ness fixups are now marshalled
+// and unmarshalled transparent right at the network transition.
+//
+// Care must be taken to identify any code that takes the address of a Portable<T>, since this is not
+// generally safe (it could expose naive code to the network encoded form of the datum). In such situations
+// the code is normally re-written to create a temporary instance of T on the stack, initialized to the
+// correct host value by reading from the Portable<T> field. The address of this variable can now be taken
+// safely (assuming its value is required only for some lexically scoped operation). Once the value is no
+// longer being used, and if there is a possibility that the value may have been updated, the new value can be
+// copied back into the Portable<T> field.
+//
+// Note that this header uses very basic data types only as it is included from both Win32/PAL code and native
+// Mac code.
+//
+
+#if BIGENDIAN || __BIG_ENDIAN__
+#define DBG_BYTE_SWAP_REQUIRED
+#endif
+
+#if defined(_ASSERTE)
+#define _PASSERT(_expr) _ASSERTE(_expr)
+#elif defined(assert)
+#define _PASSERT(_expr) assert(_expr)
+#else
+#define _PASSERT(_expr)
+#endif
+
+// Lowest level helper used to reverse the order of a sequence of bytes, either as an in-place operation or as
+// part of a copy.
+inline void ByteSwapPrimitive(const void *pSrc, void *pDst, unsigned int cbSize)
+{
+ _PASSERT(cbSize == 2 || cbSize == 4 || cbSize == 8);
+
+ unsigned char *pbSrc = (unsigned char*)pSrc;
+ unsigned char *pbDst = (unsigned char*)pDst;
+
+ for (unsigned int i = 0; i < (cbSize / 2); i++)
+ {
+ unsigned int j = cbSize - i - 1;
+ unsigned char bTemp = pbSrc[i];
+ pbDst[i] = pbSrc[j];
+ pbDst[j] = bTemp;
+ }
+}
+
+template <typename T>
+class Portable
+{
+ T m_data;
+
+public:
+ // No constructors -- this will be used in unions.
+
+ // Convert data to portable format on assignment.
+ T operator = (T value)
+ {
+ _PASSERT(sizeof(value) <= sizeof(double));
+#ifdef DBG_BYTE_SWAP_REQUIRED
+ m_data = ByteSwap(value);
+#else // DBG_BYTE_SWAP_REQUIRED
+ m_data = value;
+#endif // DBG_BYTE_SWAP_REQUIRED
+ return value;
+ }
+
+ // Return data in native format on access.
+ operator T () const
+ {
+#ifdef DBG_BYTE_SWAP_REQUIRED
+ return ByteSwap(m_data);
+#else // DBG_BYTE_SWAP_REQUIRED
+ return m_data;
+#endif // DBG_BYTE_SWAP_REQUIRED
+ }
+
+ bool operator == (T other) const
+ {
+#ifdef DBG_BYTE_SWAP_REQUIRED
+ return ByteSwap(m_data) == other;
+#else // DBG_BYTE_SWAP_REQUIRED
+ return m_data == other;
+#endif // DBG_BYTE_SWAP_REQUIRED
+ }
+
+ bool operator != (T other) const
+ {
+#ifdef DBG_BYTE_SWAP_REQUIRED
+ return ByteSwap(m_data) != other;
+#else // DBG_BYTE_SWAP_REQUIRED
+ return m_data != other;
+#endif // DBG_BYTE_SWAP_REQUIRED
+ }
+
+ T Unwrap()
+ {
+#ifdef DBG_BYTE_SWAP_REQUIRED
+ return ByteSwap(m_data);
+#else // DBG_BYTE_SWAP_REQUIRED
+ return m_data;
+#endif // DBG_BYTE_SWAP_REQUIRED
+ }
+
+private:
+#ifdef DBG_BYTE_SWAP_REQUIRED
+ // Big endian helper routine to swap the order of bytes of an arbitrary sized type
+ // (though obviously this type must be an integral primitive for this to make any
+ // sense).
+ static T ByteSwap(T inval)
+ {
+ if (sizeof(T) > 1)
+ {
+ T outval;
+ ByteSwapPrimitive(&inval, &outval, sizeof(T));
+ return outval;
+ }
+ else
+ return inval;
+ }
+#endif // DBG_BYTE_SWAP_REQUIRED
+};
+
+#endif // !__DBG_PORTABLE_INCLUDED
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#ifndef __DBG_TARGET_CONTEXT_INCLUDED
+#define __DBG_TARGET_CONTEXT_INCLUDED
+
+#include <dbgportable.h>
+#include <stddef.h>
+#include "crosscomp.h"
+
+//
+// The right side of the debugger can now be built to target multiple platforms. This means it is no longer
+// safe to use the CONTEXT structure directly: the context of the platform we're building for might not match
+// that of the one the debugger is targetting. So now all right side code will use the DT_CONTEXT abstraction
+// instead. When the debugger target is the local platform this will just resolve back into CONTEXT, but cross
+// platform we'll provide a hand-rolled version.
+//
+
+//
+// For cross platform cases we also need to provide a helper function for byte-swapping a context structure
+// should the endian-ness of the debugger and debuggee platforms differ. This is called ByteSwapContext and is
+// obviously a no-op for those cases where the left and right sides agree on storage format.
+//
+// NOTE: Any changes to the field layout of DT_CONTEXT must be tracked in the associated definition of
+// ByteSwapContext.
+//
+
+// For now, the only cross-platform CONTEXTs we support are x86/PAL and ARM/Win. Look in
+// rotor/pal/inc/rotor_pal.h for the original PAL definitions.
+
+//
+// **** NOTE: Keep these in sync with rotor/pal/inc/rotor_pal.h ****
+//
+
+// This odd define pattern is needed because in DBI we set _TARGET_ to match the host and
+// DBG_TARGET to control our targeting. In x-plat DBI DBG_TARGET won't match _TARGET_ and
+// DBG_TARGET needs to take precedence
+#if defined(DBG_TARGET_X86)
+#define DTCONTEXT_IS_X86
+#elif defined (DBG_TARGET_AMD64)
+#define DTCONTEXT_IS_AMD64
+#elif defined (DBG_TARGET_ARM)
+#define DTCONTEXT_IS_ARM
+#elif defined (DBG_TARGET_ARM64)
+#define DTCONTEXT_IS_ARM64
+#elif defined (_TARGET_X86_)
+#define DTCONTEXT_IS_X86
+#elif defined (_TARGET_AMD64_)
+#define DTCONTEXT_IS_AMD64
+#elif defined (_TARGET_ARM_)
+#define DTCONTEXT_IS_ARM
+#elif defined (_TARGET_ARM64_)
+#define DTCONTEXT_IS_ARM64
+#endif
+
+#if defined(DTCONTEXT_IS_X86)
+
+#define DT_SIZE_OF_80387_REGISTERS 80
+
+#define DT_CONTEXT_i386 0x00010000
+#define DT_CONTEXT_CONTROL (DT_CONTEXT_i386 | 0x00000001L) // SS:SP, CS:IP, FLAGS, BP
+#define DT_CONTEXT_INTEGER (DT_CONTEXT_i386 | 0x00000002L) // AX, BX, CX, DX, SI, DI
+#define DT_CONTEXT_SEGMENTS (DT_CONTEXT_i386 | 0x00000004L)
+#define DT_CONTEXT_FLOATING_POINT (DT_CONTEXT_i386 | 0x00000008L) // 387 state
+#define DT_CONTEXT_DEBUG_REGISTERS (DT_CONTEXT_i386 | 0x00000010L)
+
+#define DT_CONTEXT_FULL (DT_CONTEXT_CONTROL | DT_CONTEXT_INTEGER | DT_CONTEXT_SEGMENTS)
+#define DT_CONTEXT_EXTENDED_REGISTERS (DT_CONTEXT_i386 | 0x00000020L)
+
+#define DT_MAXIMUM_SUPPORTED_EXTENSION 512
+
+typedef struct {
+ DWORD ControlWord;
+ DWORD StatusWord;
+ DWORD TagWord;
+ DWORD ErrorOffset;
+ DWORD ErrorSelector;
+ DWORD DataOffset;
+ DWORD DataSelector;
+ BYTE RegisterArea[DT_SIZE_OF_80387_REGISTERS];
+ DWORD Cr0NpxState;
+} DT_FLOATING_SAVE_AREA;
+
+typedef struct {
+ ULONG ContextFlags;
+
+ ULONG Dr0;
+ ULONG Dr1;
+ ULONG Dr2;
+ ULONG Dr3;
+ ULONG Dr6;
+ ULONG Dr7;
+
+ DT_FLOATING_SAVE_AREA FloatSave;
+
+ ULONG SegGs;
+ ULONG SegFs;
+ ULONG SegEs;
+ ULONG SegDs;
+
+ ULONG Edi;
+ ULONG Esi;
+ ULONG Ebx;
+ ULONG Edx;
+ ULONG Ecx;
+ ULONG Eax;
+
+ ULONG Ebp;
+ ULONG Eip;
+ ULONG SegCs;
+ ULONG EFlags;
+ ULONG Esp;
+ ULONG SegSs;
+
+ UCHAR ExtendedRegisters[DT_MAXIMUM_SUPPORTED_EXTENSION];
+
+} DT_CONTEXT;
+
+// Since the target is little endian in this case we only have to provide a real implementation of
+// ByteSwapContext if the platform we're building on is big-endian.
+#ifdef BIGENDIAN
+inline void ByteSwapContext(DT_CONTEXT *pContext)
+{
+ // Our job is simplified since the context has large contiguous ranges with fields of the same size. Keep
+ // the following logic in sync with the definition of DT_CONTEXT above.
+ BYTE *pbContext = (BYTE*)pContext;
+
+ // The first span consists of 4 byte fields.
+ DWORD cbFields = (offsetof(DT_CONTEXT, FloatSave) + offsetof(DT_FLOATING_SAVE_AREA, RegisterArea)) / 4;
+ for (DWORD i = 0; i < cbFields; i++)
+ {
+ ByteSwapPrimitive(pbContext, pbContext, 4);
+ pbContext += 4;
+ }
+
+ // Then there's a float save area containing 8 byte fields.
+ cbFields = sizeof(pContext->FloatSave.RegisterArea);
+ for (DWORD i = 0; i < cbFields; i++)
+ {
+ ByteSwapPrimitive(pbContext, pbContext, 8);
+ pbContext += 8;
+ }
+
+ // Back to 4 byte fields.
+ cbFields = (offsetof(DT_CONTEXT, ExtendedRegisters) - offsetof(DT_CONTEXT, SegGs)) / 4;
+ for (DWORD i = 0; i < cbFields; i++)
+ {
+ ByteSwapPrimitive(pbContext, pbContext, 4);
+ pbContext += 4;
+ }
+
+ // We don't know the formatting of the extended register area, but the debugger doesn't access this data
+ // on the left side, so just leave it in left-side format for now.
+
+ // Validate that we converted up to where we think we did as a hedge against DT_CONTEXT layout changes.
+ _PASSERT((pbContext - ((BYTE*)pContext)) == (sizeof(DT_CONTEXT) - sizeof(pContext->ExtendedRegisters)));
+}
+#else // BIGENDIAN
+inline void ByteSwapContext(DT_CONTEXT *pContext)
+{
+}
+#endif // BIGENDIAN
+
+#elif defined(DTCONTEXT_IS_AMD64)
+
+#define DT_CONTEXT_AMD64 0x00100000L
+
+#define DT_CONTEXT_CONTROL (DT_CONTEXT_AMD64 | 0x00000001L)
+#define DT_CONTEXT_INTEGER (DT_CONTEXT_AMD64 | 0x00000002L)
+#define DT_CONTEXT_SEGMENTS (DT_CONTEXT_AMD64 | 0x00000004L)
+#define DT_CONTEXT_FLOATING_POINT (DT_CONTEXT_AMD64 | 0x00000008L)
+#define DT_CONTEXT_DEBUG_REGISTERS (DT_CONTEXT_AMD64 | 0x00000010L)
+
+#define DT_CONTEXT_FULL (DT_CONTEXT_CONTROL | DT_CONTEXT_INTEGER | DT_CONTEXT_FLOATING_POINT)
+#define DT_CONTEXT_ALL (DT_CONTEXT_CONTROL | DT_CONTEXT_INTEGER | DT_CONTEXT_SEGMENTS | DT_CONTEXT_FLOATING_POINT | DT_CONTEXT_DEBUG_REGISTERS)
+
+typedef struct {
+ ULONGLONG Low;
+ LONGLONG High;
+} DT_M128A;
+
+typedef struct {
+ WORD ControlWord;
+ WORD StatusWord;
+ BYTE TagWord;
+ BYTE Reserved1;
+ WORD ErrorOpcode;
+ DWORD ErrorOffset;
+ WORD ErrorSelector;
+ WORD Reserved2;
+ DWORD DataOffset;
+ WORD DataSelector;
+ WORD Reserved3;
+ DWORD MxCsr;
+ DWORD MxCsr_Mask;
+ DT_M128A FloatRegisters[8];
+ DT_M128A XmmRegisters[16];
+ BYTE Reserved4[96];
+} DT_XMM_SAVE_AREA32;
+
+typedef struct DECLSPEC_ALIGN(16) {
+
+ DWORD64 P1Home;
+ DWORD64 P2Home;
+ DWORD64 P3Home;
+ DWORD64 P4Home;
+ DWORD64 P5Home;
+ DWORD64 P6Home;
+
+ DWORD ContextFlags;
+ DWORD MxCsr;
+
+ WORD SegCs;
+ WORD SegDs;
+ WORD SegEs;
+ WORD SegFs;
+ WORD SegGs;
+ WORD SegSs;
+ DWORD EFlags;
+
+ DWORD64 Dr0;
+ DWORD64 Dr1;
+ DWORD64 Dr2;
+ DWORD64 Dr3;
+ DWORD64 Dr6;
+ DWORD64 Dr7;
+
+ DWORD64 Rax;
+ DWORD64 Rcx;
+ DWORD64 Rdx;
+ DWORD64 Rbx;
+ DWORD64 Rsp;
+ DWORD64 Rbp;
+ DWORD64 Rsi;
+ DWORD64 Rdi;
+ DWORD64 R8;
+ DWORD64 R9;
+ DWORD64 R10;
+ DWORD64 R11;
+ DWORD64 R12;
+ DWORD64 R13;
+ DWORD64 R14;
+ DWORD64 R15;
+
+ DWORD64 Rip;
+
+ union {
+ DT_XMM_SAVE_AREA32 FltSave;
+ struct {
+ DT_M128A Header[2];
+ DT_M128A Legacy[8];
+ DT_M128A Xmm0;
+ DT_M128A Xmm1;
+ DT_M128A Xmm2;
+ DT_M128A Xmm3;
+ DT_M128A Xmm4;
+ DT_M128A Xmm5;
+ DT_M128A Xmm6;
+ DT_M128A Xmm7;
+ DT_M128A Xmm8;
+ DT_M128A Xmm9;
+ DT_M128A Xmm10;
+ DT_M128A Xmm11;
+ DT_M128A Xmm12;
+ DT_M128A Xmm13;
+ DT_M128A Xmm14;
+ DT_M128A Xmm15;
+ };
+ };
+
+ DT_M128A VectorRegister[26];
+ DWORD64 VectorControl;
+
+ DWORD64 DebugControl;
+ DWORD64 LastBranchToRip;
+ DWORD64 LastBranchFromRip;
+ DWORD64 LastExceptionToRip;
+ DWORD64 LastExceptionFromRip;
+} DT_CONTEXT;
+
+#elif defined(DTCONTEXT_IS_ARM)
+
+#define DT_CONTEXT_ARM 0x00200000L
+
+#define DT_CONTEXT_CONTROL (DT_CONTEXT_ARM | 0x1L)
+#define DT_CONTEXT_INTEGER (DT_CONTEXT_ARM | 0x2L)
+#define DT_CONTEXT_FLOATING_POINT (DT_CONTEXT_ARM | 0x4L)
+#define DT_CONTEXT_DEBUG_REGISTERS (DT_CONTEXT_ARM | 0x8L)
+
+#define DT_CONTEXT_FULL (DT_CONTEXT_CONTROL | DT_CONTEXT_INTEGER | DT_CONTEXT_FLOATING_POINT)
+#define DT_CONTEXT_ALL (DT_CONTEXT_CONTROL | DT_CONTEXT_INTEGER | DT_CONTEXT_FLOATING_POINT | DT_CONTEXT_DEBUG_REGISTERS)
+
+#define DT_ARM_MAX_BREAKPOINTS 8
+#define DT_ARM_MAX_WATCHPOINTS 1
+
+typedef struct {
+ ULONGLONG Low;
+ LONGLONG High;
+} DT_NEON128;
+
+typedef DECLSPEC_ALIGN(8) struct {
+
+ //
+ // Control flags.
+ //
+
+ DWORD ContextFlags;
+
+ //
+ // Integer registers
+ //
+
+ DWORD R0;
+ DWORD R1;
+ DWORD R2;
+ DWORD R3;
+ DWORD R4;
+ DWORD R5;
+ DWORD R6;
+ DWORD R7;
+ DWORD R8;
+ DWORD R9;
+ DWORD R10;
+ DWORD R11;
+ DWORD R12;
+
+ //
+ // Control Registers
+ //
+
+ DWORD Sp;
+ DWORD Lr;
+ DWORD Pc;
+ DWORD Cpsr;
+
+ //
+ // Floating Point/NEON Registers
+ //
+
+ DWORD Fpscr;
+ DWORD Padding;
+ union {
+ DT_NEON128 Q[16];
+ ULONGLONG D[32];
+ DWORD S[32];
+ } DUMMYUNIONNAME;
+
+ //
+ // Debug registers
+ //
+
+ DWORD Bvr[DT_ARM_MAX_BREAKPOINTS];
+ DWORD Bcr[DT_ARM_MAX_BREAKPOINTS];
+ DWORD Wvr[DT_ARM_MAX_WATCHPOINTS];
+ DWORD Wcr[DT_ARM_MAX_WATCHPOINTS];
+
+ DWORD Padding2[2];
+
+} DT_CONTEXT;
+
+#elif defined(DTCONTEXT_IS_ARM64)
+
+#define DT_CONTEXT_ARM64 0x00400000L
+
+#define DT_CONTEXT_CONTROL (DT_CONTEXT_ARM64 | 0x1L)
+#define DT_CONTEXT_INTEGER (DT_CONTEXT_ARM64 | 0x2L)
+#define DT_CONTEXT_FLOATING_POINT (DT_CONTEXT_ARM64 | 0x4L)
+#define DT_CONTEXT_DEBUG_REGISTERS (DT_CONTEXT_ARM64 | 0x8L)
+
+#define DT_CONTEXT_FULL (DT_CONTEXT_CONTROL | DT_CONTEXT_INTEGER | DT_CONTEXT_FLOATING_POINT)
+#define DT_CONTEXT_ALL (DT_CONTEXT_CONTROL | DT_CONTEXT_INTEGER | DT_CONTEXT_FLOATING_POINT | DT_CONTEXT_DEBUG_REGISTERS)
+
+#define DT_ARM64_MAX_BREAKPOINTS 8
+#define DT_ARM64_MAX_WATCHPOINTS 2
+
+typedef struct {
+ ULONGLONG Low;
+ LONGLONG High;
+} DT_NEON128;
+
+typedef DECLSPEC_ALIGN(16) struct {
+ //
+ // Control flags.
+ //
+
+ /* +0x000 */ DWORD ContextFlags;
+
+ //
+ // Integer registers
+ //
+
+ /* +0x004 */ DWORD Cpsr; // NZVF + DAIF + CurrentEL + SPSel
+ /* +0x008 */ union {
+ struct {
+ DWORD64 X0;
+ DWORD64 X1;
+ DWORD64 X2;
+ DWORD64 X3;
+ DWORD64 X4;
+ DWORD64 X5;
+ DWORD64 X6;
+ DWORD64 X7;
+ DWORD64 X8;
+ DWORD64 X9;
+ DWORD64 X10;
+ DWORD64 X11;
+ DWORD64 X12;
+ DWORD64 X13;
+ DWORD64 X14;
+ DWORD64 X15;
+ DWORD64 X16;
+ DWORD64 X17;
+ DWORD64 X18;
+ DWORD64 X19;
+ DWORD64 X20;
+ DWORD64 X21;
+ DWORD64 X22;
+ DWORD64 X23;
+ DWORD64 X24;
+ DWORD64 X25;
+ DWORD64 X26;
+ DWORD64 X27;
+ DWORD64 X28;
+ };
+ DWORD64 X[29];
+ };
+ /* +0x0f0 */ DWORD64 Fp;
+ /* +0x0f8 */ DWORD64 Lr;
+ /* +0x100 */ DWORD64 Sp;
+ /* +0x108 */ DWORD64 Pc;
+
+ //
+ // Floating Point/NEON Registers
+ //
+
+ /* +0x110 */ DT_NEON128 V[32];
+ /* +0x310 */ DWORD Fpcr;
+ /* +0x314 */ DWORD Fpsr;
+
+ //
+ // Debug registers
+ //
+
+ /* +0x318 */ DWORD Bcr[DT_ARM64_MAX_BREAKPOINTS];
+ /* +0x338 */ DWORD64 Bvr[DT_ARM64_MAX_BREAKPOINTS];
+ /* +0x378 */ DWORD Wcr[DT_ARM64_MAX_WATCHPOINTS];
+ /* +0x380 */ DWORD64 Wvr[DT_ARM64_MAX_WATCHPOINTS];
+ /* +0x390 */
+
+} DT_CONTEXT;
+
+#else
+#error Unsupported platform
+#endif
+
+
+#endif // __DBG_TARGET_CONTEXT_INCLUDED
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+//----------------------------------------------------------------------------
+//
+// LLDB debugger services for sos
+//
+//----------------------------------------------------------------------------
+
+#ifndef __LLDBSERVICES_H__
+#define __LLDBSERVICES_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Output mask bits.
+// Normal output.
+#define DEBUG_OUTPUT_NORMAL 0x00000001
+// Error output.
+#define DEBUG_OUTPUT_ERROR 0x00000002
+// Warnings.
+#define DEBUG_OUTPUT_WARNING 0x00000004
+// Additional output.
+#define DEBUG_OUTPUT_VERBOSE 0x00000008
+// Prompt output.
+#define DEBUG_OUTPUT_PROMPT 0x00000010
+// Register dump before prompt.
+#define DEBUG_OUTPUT_PROMPT_REGISTERS 0x00000020
+// Warnings specific to extension operation.
+#define DEBUG_OUTPUT_EXTENSION_WARNING 0x00000040
+// Debuggee debug output, such as from OutputDebugString.
+#define DEBUG_OUTPUT_DEBUGGEE 0x00000080
+// Debuggee-generated prompt, such as from DbgPrompt.
+#define DEBUG_OUTPUT_DEBUGGEE_PROMPT 0x00000100
+// Symbol messages, such as for !sym noisy.
+#define DEBUG_OUTPUT_SYMBOLS 0x00000200
+
+// Execute and ExecuteCommandFile flags.
+// These flags only apply to the command
+// text itself; output from the executed
+// command is controlled by the output
+// control parameter.
+// Default execution. Command is logged
+// but not output.
+#define DEBUG_EXECUTE_DEFAULT 0x00000000
+// Echo commands during execution. In
+// ExecuteCommandFile also echoes the prompt
+// for each line of the file.
+#define DEBUG_EXECUTE_ECHO 0x00000001
+// Do not log or output commands during execution.
+// Overridden by DEBUG_EXECUTE_ECHO.
+#define DEBUG_EXECUTE_NOT_LOGGED 0x00000002
+// If this flag is not set an empty string
+// to Execute will repeat the last Execute
+// string.
+#define DEBUG_EXECUTE_NO_REPEAT 0x00000004
+
+// Classes of debuggee. Each class
+// has different qualifiers for specific
+// kinds of debuggees.
+#define DEBUG_CLASS_UNINITIALIZED 0
+#define DEBUG_CLASS_KERNEL 1
+#define DEBUG_CLASS_USER_WINDOWS 2
+#define DEBUG_CLASS_IMAGE_FILE 3
+
+// Generic dump types. These can be used
+// with either user or kernel sessions.
+// Session-type-specific aliases are also
+// provided.
+#define DEBUG_DUMP_SMALL 1024
+#define DEBUG_DUMP_DEFAULT 1025
+#define DEBUG_DUMP_FULL 1026
+#define DEBUG_DUMP_IMAGE_FILE 1027
+#define DEBUG_DUMP_TRACE_LOG 1028
+#define DEBUG_DUMP_WINDOWS_CE 1029
+
+#define IMAGE_FILE_MACHINE_I386 0x014c // Intel 386.
+#define IMAGE_FILE_MACHINE_ARMNT 0x01c4 // ARM Thumb-2 Little-Endian
+#define IMAGE_FILE_MACHINE_AMD64 0x8664 // AMD64 (K8)
+#define IMAGE_FILE_MACHINE_ARM64 0xAA64 // ARM64 Little-Endian
+
+// Execution status codes used for waiting,
+// for returning current status and for
+// event method return values.
+#define DEBUG_STATUS_NO_CHANGE 0
+#define DEBUG_STATUS_GO 1
+#define DEBUG_STATUS_GO_HANDLED 2
+#define DEBUG_STATUS_GO_NOT_HANDLED 3
+#define DEBUG_STATUS_STEP_OVER 4
+#define DEBUG_STATUS_STEP_INTO 5
+#define DEBUG_STATUS_BREAK 6
+#define DEBUG_STATUS_NO_DEBUGGEE 7
+#define DEBUG_STATUS_STEP_BRANCH 8
+#define DEBUG_STATUS_IGNORE_EVENT 9
+#define DEBUG_STATUS_RESTART_REQUESTED 10
+#define DEBUG_STATUS_REVERSE_GO 11
+#define DEBUG_STATUS_REVERSE_STEP_BRANCH 12
+#define DEBUG_STATUS_REVERSE_STEP_OVER 13
+#define DEBUG_STATUS_REVERSE_STEP_INTO 14
+#define DEBUG_STATUS_OUT_OF_SYNC 15
+#define DEBUG_STATUS_WAIT_INPUT 16
+#define DEBUG_STATUS_TIMEOUT 17
+
+#define DEBUG_STATUS_MASK 0x1f
+
+#define DEBUG_EVENT_EXCEPTION 0x00000002
+
+typedef struct _DEBUG_LAST_EVENT_INFO_EXCEPTION
+{
+ EXCEPTION_RECORD64 ExceptionRecord;
+ ULONG FirstChance;
+} DEBUG_LAST_EVENT_INFO_EXCEPTION, *PDEBUG_LAST_EVENT_INFO_EXCEPTION;
+
+//
+// Information about a module.
+//
+
+// Flags.
+#define DEBUG_MODULE_LOADED 0x00000000
+#define DEBUG_MODULE_UNLOADED 0x00000001
+#define DEBUG_MODULE_USER_MODE 0x00000002
+#define DEBUG_MODULE_EXPLICIT 0x00000008
+#define DEBUG_MODULE_SECONDARY 0x00000010
+#define DEBUG_MODULE_SYNTHETIC 0x00000020
+#define DEBUG_MODULE_SYM_BAD_CHECKSUM 0x00010000
+
+// Symbol types.
+#define DEBUG_SYMTYPE_NONE 0
+#define DEBUG_SYMTYPE_COFF 1
+#define DEBUG_SYMTYPE_CODEVIEW 2
+#define DEBUG_SYMTYPE_PDB 3
+#define DEBUG_SYMTYPE_EXPORT 4
+#define DEBUG_SYMTYPE_DEFERRED 5
+#define DEBUG_SYMTYPE_SYM 6
+#define DEBUG_SYMTYPE_DIA 7
+
+typedef struct _DEBUG_MODULE_PARAMETERS
+{
+ ULONG64 Base;
+ ULONG Size;
+ ULONG TimeDateStamp;
+ ULONG Checksum;
+ ULONG Flags;
+ ULONG SymbolType;
+ ULONG ImageNameSize;
+ ULONG ModuleNameSize;
+ ULONG LoadedImageNameSize;
+ ULONG SymbolFileNameSize;
+ ULONG MappedImageNameSize;
+ ULONG64 Reserved[2];
+} DEBUG_MODULE_PARAMETERS, *PDEBUG_MODULE_PARAMETERS;
+
+// FindSourceFile flags.
+#define DEBUG_FIND_SOURCE_DEFAULT 0x00000000
+// Returns fully-qualified paths only. If this
+// is not set the path returned may be relative.
+#define DEBUG_FIND_SOURCE_FULL_PATH 0x00000001
+// Scans all the path elements for a match and
+// returns the one that has the most similarity
+// between the given file and the matching element.
+#define DEBUG_FIND_SOURCE_BEST_MATCH 0x00000002
+// Do not search source server paths.
+#define DEBUG_FIND_SOURCE_NO_SRCSRV 0x00000004
+// Restrict FindSourceFileAndToken to token lookup only.
+#define DEBUG_FIND_SOURCE_TOKEN_LOOKUP 0x00000008
+
+// A special value marking an offset that should not
+// be treated as a valid offset. This is only used
+// in special situations where it is unlikely that
+// this value would be a valid offset.
+#define DEBUG_INVALID_OFFSET ((ULONG64)-1)
+
+// General unspecified ID constant.
+#define DEBUG_ANY_ID 0xffffffff
+
+typedef struct _DEBUG_STACK_FRAME
+{
+ ULONG64 InstructionOffset;
+ ULONG64 ReturnOffset;
+ ULONG64 FrameOffset;
+ ULONG64 StackOffset;
+ ULONG64 FuncTableEntry;
+ ULONG64 Params[4];
+ ULONG64 Reserved[6];
+ BOOL Virtual;
+ ULONG FrameNumber;
+} DEBUG_STACK_FRAME, *PDEBUG_STACK_FRAME;
+
+#define DBG_FRAME_DEFAULT 0 // the same as INLINE_FRAME_CONTEXT_INIT in dbghelp.h
+#define DBG_FRAME_IGNORE_INLINE 0xFFFFFFFF // the same as INLINE_FRAME_CONTEXT_IGNORE in dbghelp.h
+
+typedef struct _DEBUG_STACK_FRAME_EX
+{
+ // First DEBUG_STACK_FRAME structure
+ ULONG64 InstructionOffset;
+ ULONG64 ReturnOffset;
+ ULONG64 FrameOffset;
+ ULONG64 StackOffset;
+ ULONG64 FuncTableEntry;
+ ULONG64 Params[4];
+ ULONG64 Reserved[6];
+ BOOL Virtual;
+ ULONG FrameNumber;
+
+ // Extended DEBUG_STACK_FRAME fields.
+ ULONG InlineFrameContext;
+ ULONG Reserved1; // For alignment purpose.
+} DEBUG_STACK_FRAME_EX, *PDEBUG_STACK_FRAME_EX;
+
+// The types of inline frame context.
+#define STACK_FRAME_TYPE_INIT 0x00
+#define STACK_FRAME_TYPE_STACK 0x01
+#define STACK_FRAME_TYPE_INLINE 0x02
+#define STACK_FRAME_TYPE_RA 0x80 // Whether the instruction pointer is the current IP or a RA from callee frame.
+#define STACK_FRAME_TYPE_IGNORE 0xFF
+
+//
+// options that are set/returned by SymSetOptions() & SymGetOptions()
+// these are used as a mask
+//
+#define SYMOPT_LOAD_LINES 0x00000010
+
+interface ILLDBServices;
+typedef HRESULT (*PFN_EXCEPTION_CALLBACK)(ILLDBServices *services);
+
+//----------------------------------------------------------------------------
+// ILLDBServices
+//----------------------------------------------------------------------------
+
+MIDL_INTERFACE("2E6C569A-9E14-4DA4-9DFC-CDB73A532566")
+ILLDBServices : public IUnknown
+{
+public:
+ //----------------------------------------------------------------------------
+ // ILLDBServices
+ //----------------------------------------------------------------------------
+
+ // Returns the coreclr module directory found by lldb plugin
+ // in the target process.
+ virtual PCSTR GetCoreClrDirectory() = 0;
+
+ // Evaluates a lldb expression into a value.
+ virtual DWORD_PTR GetExpression(
+ /* [in] */ PCSTR exp) = 0;
+
+ // Unwind one native stack frame given a thread and register context
+ virtual HRESULT VirtualUnwind(
+ /* [in] */ DWORD threadID,
+ /* [in] */ ULONG32 contextSize,
+ /* [in, out, size_is(contextSize)] */ PBYTE context) = 0;
+
+ // Set an exception throw callback
+ virtual HRESULT SetExceptionCallback(
+ /* [in] */ PFN_EXCEPTION_CALLBACK callback) = 0;
+
+ // Clear the exception throw callback
+ virtual HRESULT ClearExceptionCallback() = 0;
+
+ //------------------------------------------------
+ // IDebugControl2
+ //------------------------------------------------
+
+ // Checks for a user interrupt, such a Ctrl-C
+ // or stop button.
+ // This method is reentrant.
+ virtual HRESULT GetInterrupt(
+ void) = 0;
+
+ virtual HRESULT OutputVaList(
+ ULONG mask,
+ PCSTR format,
+ va_list args) = 0;
+
+ // Returns information about the debuggee such
+ // as user vs. kernel, dump vs. live, etc.
+ virtual HRESULT GetDebuggeeType(
+ PULONG debugClass,
+ PULONG qualifier) = 0;
+
+ // Returns the page size for the currently executing
+ // processor context. The page size may vary between
+ // processor types.
+ virtual HRESULT GetPageSize(
+ PULONG size) = 0;
+
+ // Returns the type of processor used in the
+ // current processor context.
+ virtual HRESULT GetExecutingProcessorType(
+ PULONG type) = 0;
+
+ // Executes the given command string.
+ // If the string has multiple commands
+ // Execute will not return until all
+ // of them have been executed. If this
+ // requires waiting for the debuggee to
+ // execute an internal wait will be done
+ // so Execute can take an arbitrary amount
+ // of time.
+ virtual HRESULT Execute(
+ ULONG outputControl,
+ PCSTR command,
+ ULONG flags) = 0;
+
+ // Retrieves information about the last event that occurred.
+ // EventType is one of the event callback mask bits.
+ // ExtraInformation contains additional event-specific
+ // information. Not all events have additional information.
+ virtual HRESULT GetLastEventInformation(
+ PULONG type,
+ PULONG processId,
+ PULONG threadId,
+ PVOID extraInformation,
+ ULONG extraInformationSize,
+ PULONG extraInformationUsed,
+ PSTR description,
+ ULONG descriptionSize,
+ PULONG descriptionUsed) = 0;
+
+ virtual HRESULT Disassemble(
+ ULONG64 offset,
+ ULONG flags,
+ PSTR buffer,
+ ULONG bufferSize,
+ PULONG disassemblySize,
+ PULONG64 endOffset) = 0;
+
+ //----------------------------------------------------------------------------
+ // IDebugControl4
+ //----------------------------------------------------------------------------
+
+ // Stack tracing with a full initial context
+ // and full context return for each frame.
+ // The FrameContextsSize parameter is the total
+ // byte size of FrameContexts. FrameContextsEntrySize
+ // gives the byte size of each entry in
+ // FrameContexts.
+ virtual HRESULT GetContextStackTrace(
+ PVOID startContext,
+ ULONG startContextSize,
+ PDEBUG_STACK_FRAME frames,
+ ULONG framesSize,
+ PVOID frameContexts,
+ ULONG frameContextsSize,
+ ULONG frameContextsEntrySize,
+ PULONG framesFilled) = 0;
+
+ //------------------------------------------------
+ // IDebugDataSpaces
+ //------------------------------------------------
+
+ virtual HRESULT ReadVirtual(
+ ULONG64 offset,
+ PVOID buffer,
+ ULONG bufferSize,
+ PULONG bytesRead) = 0;
+
+ virtual HRESULT WriteVirtual(
+ ULONG64 offset,
+ PVOID buffer,
+ ULONG bufferSize,
+ PULONG bytesWritten) = 0;
+
+ //------------------------------------------------
+ // IDebugSymbols
+ //------------------------------------------------
+
+ // Controls the symbol options used during
+ // symbol operations.
+ // Uses the same flags as dbghelps SymSetOptions.
+ virtual HRESULT GetSymbolOptions(
+ PULONG options) = 0;
+
+ virtual HRESULT GetNameByOffset(
+ ULONG64 offset,
+ PSTR nameBuffer,
+ ULONG nameBufferSize,
+ PULONG nameSize,
+ PULONG64 displacement) = 0;
+
+ // Enumerates the engines list of modules
+ // loaded for the current process. This may
+ // or may not match the system module list
+ // for the process. Reload can be used to
+ // synchronize the engines list with the system
+ // if necessary.
+ // Some sessions also track recently unloaded
+ // code modules for help in analyzing failures
+ // where an attempt is made to call unloaded code.
+ // These modules are indexed after the loaded
+ // modules.
+ virtual HRESULT GetNumberModules(
+ PULONG loaded,
+ PULONG unloaded) = 0;
+
+ virtual HRESULT GetModuleByIndex(
+ ULONG index,
+ PULONG64 base) = 0;
+
+ // The module name may not be unique.
+ // This method returns the first match.
+ virtual HRESULT GetModuleByModuleName(
+ PCSTR name,
+ ULONG startIndex,
+ PULONG index,
+ PULONG64 base) = 0;
+
+ // Offset can be any offset within
+ // the module extent. Extents may
+ // not be unique when including unloaded
+ // drivers. This method returns the
+ // first match.
+ virtual HRESULT GetModuleByOffset(
+ ULONG64 offset,
+ ULONG startIndex,
+ PULONG index,
+ PULONG64 base) = 0;
+
+ // If Index is DEBUG_ANY_ID the base address
+ // is used to look up the module instead.
+ virtual HRESULT GetModuleNames(
+ ULONG index,
+ ULONG64 base,
+ PSTR imageNameBuffer,
+ ULONG imageNameBufferSize,
+ PULONG imageNameSize,
+ PSTR moduleNameBuffer,
+ ULONG moduleNameBufferSize,
+ PULONG moduleNameSize,
+ PSTR loadedImageNameBuffer,
+ ULONG loadedImageNameBufferSize,
+ PULONG loadedImageNameSize) = 0;
+
+ HRESULT virtual GetLineByOffset(
+ ULONG64 offset,
+ PULONG line,
+ PSTR fileBuffer,
+ ULONG fileBufferSize,
+ PULONG fileSize,
+ PULONG64 displacement) = 0;
+
+ HRESULT virtual GetSourceFileLineOffsets(
+ PCSTR file,
+ PULONG64 buffer,
+ ULONG bufferLines,
+ PULONG fileLines) = 0;
+
+ // Uses the given file path and the source path
+ // information to try and locate an existing file.
+ // The given file path is merged with elements
+ // of the source path and checked for existence.
+ // If a match is found the element used is returned.
+ // A starting element can be specified to restrict
+ // the search to a subset of the path elements;
+ // this can be useful when checking for multiple
+ // matches along the source path.
+ // The returned element can be 1, indicating
+ // the file was found directly and not on the path.
+ HRESULT virtual FindSourceFile(
+ ULONG startElement,
+ PCSTR file,
+ ULONG flags,
+ PULONG foundElement,
+ PSTR buffer,
+ ULONG bufferSize,
+ PULONG foundSize) = 0;
+
+ //------------------------------------------------
+ // IDebugSystemObjects
+ //------------------------------------------------
+
+ virtual HRESULT GetCurrentProcessId(
+ PULONG id) = 0;
+
+ // Controls implicit thread used by the
+ // debug engine. The debuggers current
+ // thread is just a piece of data held
+ // by the debugger for calls which use
+ // thread-specific information. In those
+ // calls the debuggers current thread is used.
+ // The debuggers current thread is not related
+ // to any system thread attribute.
+ // IDs for threads are small integer IDs
+ // maintained by the engine. They are not
+ // related to system thread IDs.
+ virtual HRESULT GetCurrentThreadId(
+ PULONG id) = 0;
+
+ virtual HRESULT SetCurrentThreadId(
+ ULONG id) = 0;
+
+ // Returns the system unique ID for the current thread.
+ // Not currently supported when kernel debugging.
+ virtual HRESULT GetCurrentThreadSystemId(
+ PULONG sysId) = 0;
+
+ // Looks up a debugger thread ID for the given
+ // system thread ID.
+ // Currently when kernel debugging this will fail
+ // if the thread is not executing on a processor.
+ virtual HRESULT GetThreadIdBySystemId(
+ ULONG sysId,
+ PULONG id) = 0;
+
+ // This is a special sos/lldb function used to implement the ICLRDataTarget interface and
+ // not actually part of dbgeng's IDebugSystemObjects interface.
+ virtual HRESULT GetThreadContextById(
+ /* [in] */ ULONG32 threadID,
+ /* [in] */ ULONG32 contextFlags,
+ /* [in] */ ULONG32 contextSize,
+ /* [out, size_is(contextSize)] */ PBYTE context) = 0;
+
+ //------------------------------------------------
+ // IDebugRegister
+ //------------------------------------------------
+
+ // This is the combination of dbgeng's GetIndexByName and GetValue and not
+ // actually part of the dbgeng's IDebugRegister interface.
+ virtual HRESULT GetValueByName(
+ PCSTR name,
+ PDWORD_PTR value) = 0;
+
+ // Abstracted pieces of processor information.
+ // The mapping of these values to architectural
+ // registers is architecture-specific and their
+ // interpretation and existence may vary. They
+ // are intended to be directly compatible with
+ // calls which take this information, such as
+ // stack walking.
+ virtual HRESULT GetInstructionOffset(
+ PULONG64 offset) = 0;
+
+ virtual HRESULT GetStackOffset(
+ PULONG64 offset) = 0;
+
+ virtual HRESULT GetFrameOffset(
+ PULONG64 offset) = 0;
+};
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif // #ifndef __LLDBSERVICES_H__
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+// Contains some definitions duplicated from pal.h, palrt.h, rpc.h,
+// etc. because they have various conflicits with the linux standard
+// runtime h files like wchar_t, memcpy, etc.
+
+#include <stdarg.h>
+#include <string.h>
+#include <pal_mstypes.h>
+
+#define MAX_PATH 260
+#define MAX_LONGPATH 1024 /* max. length of full pathname */
+
+// Platform-specific library naming
+//
+#ifdef __APPLE__
+#define MAKEDLLNAME_W(name) u"lib" name u".dylib"
+#define MAKEDLLNAME_A(name) "lib" name ".dylib"
+#elif defined(_AIX)
+#define MAKEDLLNAME_W(name) L"lib" name L".a"
+#define MAKEDLLNAME_A(name) "lib" name ".a"
+#elif defined(__hppa__) || defined(_IA64_)
+#define MAKEDLLNAME_W(name) L"lib" name L".sl"
+#define MAKEDLLNAME_A(name) "lib" name ".sl"
+#else
+#define MAKEDLLNAME_W(name) u"lib" name u".so"
+#define MAKEDLLNAME_A(name) "lib" name ".so"
+#endif
+
+#define interface struct
+typedef GUID IID;
+
+#ifdef __cplusplus
+#define REFGUID const GUID &
+#else
+#define REFGUID const GUID *
+#endif
+
+typedef GUID *LPGUID;
+typedef const GUID FAR *LPCGUID;
+
+#ifdef __cplusplus
+extern "C++" {
+#if !defined _SYS_GUID_OPERATOR_EQ_ && !defined _NO_SYS_GUID_OPERATOR_EQ_
+#define _SYS_GUID_OPERATOR_EQ_
+inline int IsEqualGUID(REFGUID rguid1, REFGUID rguid2)
+ { return !memcmp(&rguid1, &rguid2, sizeof(GUID)); }
+inline int operator==(REFGUID guidOne, REFGUID guidOther)
+ { return IsEqualGUID(guidOne,guidOther); }
+inline int operator!=(REFGUID guidOne, REFGUID guidOther)
+ { return !IsEqualGUID(guidOne,guidOther); }
+#endif
+};
+#endif // __cplusplus
+
+#ifdef __cplusplus
+#define REFIID const IID &
+#else
+#define REFIID const IID *
+#endif
+#define IsEqualIID(riid1, riid2) IsEqualGUID(riid1, riid2)
+
+#ifndef _DECLSPEC_DEFINED_
+#define _DECLSPEC_DEFINED_
+
+#if defined(_MSC_VER)
+#define DECLSPEC_NOVTABLE __declspec(novtable)
+#define DECLSPEC_IMPORT __declspec(dllimport)
+#define DECLSPEC_SELECTANY __declspec(selectany)
+#elif defined(__GNUC__)
+#define DECLSPEC_NOVTABLE
+#define DECLSPEC_IMPORT
+#define DECLSPEC_SELECTANY __attribute__((weak))
+#else
+#define DECLSPEC_NOVTABLE
+#define DECLSPEC_IMPORT
+#define DECLSPEC_SELECTANY
+#endif
+
+#if defined(_MSC_VER) || defined(__llvm__)
+#define DECLSPEC_ALIGN(x) __declspec(align(x))
+#else
+#define DECLSPEC_ALIGN(x)
+#endif
+
+#endif // !_DECLSPEC_DEFINED_
+
+#define DECLSPEC_UUID(x) __declspec(uuid(x))
+#define MIDL_INTERFACE(x) struct DECLSPEC_UUID(x) DECLSPEC_NOVTABLE
+
+#define STDMETHODCALLTYPE __cdecl
+#define STDMETHODVCALLTYPE __cdecl
+
+#define STDAPICALLTYPE __cdecl
+#define STDAPIVCALLTYPE __cdecl
+
+#ifdef RC_INVOKED
+#define _HRESULT_TYPEDEF_(_sc) _sc
+#else // RC_INVOKED
+#define _HRESULT_TYPEDEF_(_sc) ((HRESULT)_sc)
+#endif // RC_INVOKED
+
+#define S_OK _HRESULT_TYPEDEF_(0x00000000L)
+#define S_FALSE _HRESULT_TYPEDEF_(0x00000001L)
+
+#define E_NOTIMPL _HRESULT_TYPEDEF_(0x80004001L)
+#define E_NOINTERFACE _HRESULT_TYPEDEF_(0x80004002L)
+#define E_UNEXPECTED _HRESULT_TYPEDEF_(0x8000FFFFL)
+#define E_OUTOFMEMORY _HRESULT_TYPEDEF_(0x8007000EL)
+#define E_INVALIDARG _HRESULT_TYPEDEF_(0x80070057L)
+#define E_POINTER _HRESULT_TYPEDEF_(0x80004003L)
+#define E_HANDLE _HRESULT_TYPEDEF_(0x80070006L)
+#define E_ABORT _HRESULT_TYPEDEF_(0x80004004L)
+#define E_FAIL _HRESULT_TYPEDEF_(0x80004005L)
+#define E_ACCESSDENIED _HRESULT_TYPEDEF_(0x80070005L)
+#define E_PENDING _HRESULT_TYPEDEF_(0x8000000AL)
+
+#define EXCEPTION_MAXIMUM_PARAMETERS 15
+
+typedef struct _EXCEPTION_RECORD64 {
+ DWORD ExceptionCode;
+ ULONG ExceptionFlags;
+ ULONG64 ExceptionRecord;
+ ULONG64 ExceptionAddress;
+ ULONG NumberParameters;
+ ULONG __unusedAlignment;
+ ULONG64 ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS];
+} EXCEPTION_RECORD64, *PEXCEPTION_RECORD64;
+
+#include <unknwn.h>
+
+#ifndef FORCEINLINE
+#if _MSC_VER < 1200
+#define FORCEINLINE inline
+#else
+#define FORCEINLINE __forceinline
+#endif
+#endif
+
+FORCEINLINE void PAL_ArmInterlockedOperationBarrier()
+{
+#ifdef _ARM64_
+ // On arm64, most of the __sync* functions generate a code sequence like:
+ // loop:
+ // ldaxr (load acquire exclusive)
+ // ...
+ // stlxr (store release exclusive)
+ // cbnz loop
+ //
+ // It is possible for a load following the code sequence above to be reordered to occur prior to the store above due to the
+ // release barrier, this is substantiated by https://github.com/dotnet/coreclr/pull/17508. Interlocked operations in the PAL
+ // require the load to occur after the store. This memory barrier should be used following a call to a __sync* function to
+ // prevent that reordering. Code generated for arm32 includes a 'dmb' after 'cbnz', so no issue there at the moment.
+ __sync_synchronize();
+#endif // _ARM64_
+}
+
+/*++
+Function:
+InterlockedIncrement
+
+The InterlockedIncrement function increments (increases by one) the
+value of the specified variable and checks the resulting value. The
+function prevents more than one thread from using the same variable
+simultaneously.
+
+Parameters
+
+lpAddend
+[in/out] Pointer to the variable to increment.
+
+Return Values
+
+The return value is the resulting incremented value.
+
+--*/
+EXTERN_C
+PALIMPORT
+inline
+LONG
+PALAPI
+InterlockedIncrement(
+ IN OUT LONG volatile *lpAddend)
+{
+ LONG result = __sync_add_and_fetch(lpAddend, (LONG)1);
+ PAL_ArmInterlockedOperationBarrier();
+ return result;
+}
+
+/*++
+Function:
+InterlockedDecrement
+
+The InterlockedDecrement function decrements (decreases by one) the
+value of the specified variable and checks the resulting value. The
+function prevents more than one thread from using the same variable
+simultaneously.
+
+Parameters
+
+lpAddend
+[in/out] Pointer to the variable to decrement.
+
+Return Values
+
+The return value is the resulting decremented value.
+
+--*/
+EXTERN_C
+PALIMPORT
+inline
+LONG
+PALAPI
+InterlockedDecrement(
+ IN OUT LONG volatile *lpAddend)
+{
+ LONG result = __sync_sub_and_fetch(lpAddend, (LONG)1);
+ PAL_ArmInterlockedOperationBarrier();
+ return result;
+}
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+
+
+--*/
+
+////////////////////////////////////////////////////////////////////////
+// Extensions to the usual posix header files
+////////////////////////////////////////////////////////////////////////
+
+#ifndef __PAL_MSTYPES_H__
+#define __PAL_MSTYPES_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+////////////////////////////////////////////////////////////////////////
+// calling convention stuff
+////////////////////////////////////////////////////////////////////////
+
+
+#ifdef __cplusplus
+#define EXTERN_C extern "C"
+#else
+#define EXTERN_C
+#endif // __cplusplus
+
+#ifndef _MSC_VER
+
+// Note: Win32-hosted GCC predefines __stdcall and __cdecl, but Unix-
+// hosted GCC does not.
+
+#ifdef __i386__
+
+#if !defined(__stdcall)
+#define __stdcall __attribute__((stdcall))
+#endif
+#if !defined(_stdcall)
+#define _stdcall __stdcall
+#endif
+
+#if !defined(__cdecl)
+#define __cdecl __attribute__((cdecl))
+#endif
+#if !defined(_cdecl)
+#define _cdecl __cdecl
+#endif
+#if !defined(CDECL)
+#define CDECL __cdecl
+#endif
+
+
+#else // !defined(__i386__)
+
+#define __stdcall
+#define _stdcall
+#define __cdecl
+#define _cdecl
+#define CDECL
+
+// On ARM __fastcall is ignored and causes a compile error
+#if !defined(PAL_STDCPP_COMPAT) || defined(__arm__)
+# undef __fastcall
+# undef _fastcall
+# define __fastcall
+# define _fastcall
+#endif // !defined(PAL_STDCPP_COMPAT) || defined(__arm__)
+
+#endif // !defined(__i386__)
+
+#define CALLBACK __cdecl
+
+#if !defined(_declspec)
+#define _declspec(e) __declspec(e)
+#endif
+
+#if defined(_VAC_) && defined(__cplusplus)
+#define __inline inline
+#endif
+
+#define __forceinline inline
+
+#endif // !_MSC_VER
+
+#ifdef _MSC_VER
+
+#if defined(PAL_IMPLEMENTATION)
+#define PALIMPORT
+#else
+#define PALIMPORT __declspec(dllimport)
+#endif
+#define PAL_NORETURN __declspec(noreturn)
+
+#else
+
+#define PALIMPORT
+#define PAL_NORETURN __attribute__((noreturn))
+
+#endif
+
+#define PALAPI __cdecl
+#define PALAPIV __cdecl
+
+////////////////////////////////////////////////////////////////////////
+// Type attribute stuff
+////////////////////////////////////////////////////////////////////////
+
+#define CONST const
+#define IN
+#define OUT
+#define OPTIONAL
+#define FAR
+
+#ifdef UNICODE
+#define __TEXT(x) L##x
+#else
+#define __TEXT(x) x
+#endif
+#define TEXT(x) __TEXT(x)
+
+////////////////////////////////////////////////////////////////////////
+// Some special values
+////////////////////////////////////////////////////////////////////////
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+////////////////////////////////////////////////////////////////////////
+// Misc. type helpers
+////////////////////////////////////////////////////////////////////////
+
+#ifdef _MSC_VER
+
+// MSVC's way of declaring large integer constants
+// If you define these in one step, without the _HELPER macros, you
+// get extra whitespace when composing these with other concatenating macros.
+#define I64_HELPER(x) x ## i64
+#define I64(x) I64_HELPER(x)
+
+#define UI64_HELPER(x) x ## ui64
+#define UI64(x) UI64_HELPER(x)
+
+#else // _MSC_VER
+
+// GCC's way of declaring large integer constants
+// If you define these in one step, without the _HELPER macros, you
+// get extra whitespace when composing these with other concatenating macros.
+#define I64_HELPER(x) x ## LL
+#define I64(x) I64_HELPER(x)
+
+#define UI64_HELPER(x) x ## ULL
+#define UI64(x) UI64_HELPER(x)
+
+#endif // _MSC_VER
+
+////////////////////////////////////////////////////////////////////////
+// Misc. types
+////////////////////////////////////////////////////////////////////////
+
+#ifndef _MSC_VER
+
+// A bunch of source files (e.g. most of the ndp tree) include pal.h
+// but are written to be LLP64, not LP64. (LP64 => long = 64 bits
+// LLP64 => longs = 32 bits, long long = 64 bits)
+//
+// To handle this difference, we #define long to be int (and thus 32 bits) when
+// compiling those files. (See the bottom of this file or search for
+// #define long to see where we do this.)
+//
+// But this fix is more complicated than it seems, because we also use the
+// preprocessor to #define __int64 to long for LP64 architectures (__int64
+// isn't a builtin in gcc). We don't want __int64 to be an int (by cascading
+// macro rules). So we play this little trick below where we add
+// __cppmungestrip before "long", which is what we're really #defining __int64
+// to. The preprocessor sees __cppmungestriplong as something different than
+// long, so it doesn't replace it with int. The during the cppmunge phase, we
+// remove the __cppmungestrip part, leaving long for the compiler to see.
+//
+// Note that we can't just use a typedef to define __int64 as long before
+// #defining long because typedefed types can't be signedness-agnostic (i.e.
+// they must be either signed or unsigned) and we want to be able to use
+// __int64 as though it were intrinsic
+
+#ifdef BIT64
+#define __int64 long
+#else // BIT64
+#define __int64 long long
+#endif // BIT64
+
+#define __int32 int
+#define __int16 short int
+#define __int8 char // assumes char is signed
+
+#endif // _MSC_VER
+
+#ifndef PAL_STDCPP_COMPAT
+// Defined in gnu's types.h. For non PAL_IMPLEMENTATION system
+// includes are not included, so we need to define them.
+#ifndef PAL_IMPLEMENTATION
+
+// OS X already defines these types in 64 bit
+#if !defined(_TARGET_MAC64)
+typedef __int64 int64_t;
+typedef unsigned __int64 uint64_t;
+typedef __int32 int32_t;
+typedef unsigned __int32 uint32_t;
+typedef __int16 int16_t;
+typedef unsigned __int16 uint16_t;
+typedef __int8 int8_t;
+typedef unsigned __int8 uint8_t;
+#endif
+
+#endif // PAL_IMPLEMENTATION
+
+#ifndef _MSC_VER
+
+#if _WIN64
+typedef long double LONG_DOUBLE;
+#endif
+
+#endif // _MSC_VER
+#endif // !PAL_STDCPP_COMPAT
+
+typedef void VOID;
+
+typedef int LONG; // NOTE: diff from windows.h, for LP64 compat
+typedef unsigned int ULONG; // NOTE: diff from windows.h, for LP64 compat
+
+typedef __int64 LONGLONG;
+typedef unsigned __int64 ULONGLONG;
+typedef ULONGLONG DWORD64;
+typedef DWORD64 *PDWORD64;
+typedef LONGLONG *PLONG64;
+typedef ULONGLONG *PULONG64;
+typedef ULONGLONG *PULONGLONG;
+typedef ULONG *PULONG;
+typedef short SHORT;
+typedef SHORT *PSHORT;
+typedef unsigned short USHORT;
+typedef USHORT *PUSHORT;
+typedef unsigned char UCHAR;
+typedef UCHAR *PUCHAR;
+typedef char *PSZ;
+typedef ULONGLONG DWORDLONG;
+
+typedef unsigned int DWORD; // NOTE: diff from windows.h, for LP64 compat
+typedef unsigned int DWORD32, *PDWORD32;
+
+typedef int BOOL;
+typedef unsigned char BYTE;
+typedef unsigned short WORD;
+typedef float FLOAT;
+typedef double DOUBLE;
+typedef BOOL *PBOOL;
+typedef BOOL *LPBOOL;
+typedef BYTE *PBYTE;
+typedef BYTE *LPBYTE;
+typedef const BYTE *LPCBYTE;
+typedef int *PINT;
+typedef int *LPINT;
+typedef WORD *PWORD;
+typedef WORD *LPWORD;
+typedef LONG *LPLONG;
+typedef LPLONG PLONG;
+typedef DWORD *PDWORD;
+typedef DWORD *LPDWORD;
+typedef void *PVOID;
+typedef void *LPVOID;
+typedef CONST void *LPCVOID;
+typedef int INT;
+typedef unsigned int UINT;
+typedef unsigned int *PUINT;
+typedef BYTE BOOLEAN;
+typedef BOOLEAN *PBOOLEAN;
+
+typedef unsigned __int8 UINT8;
+typedef signed __int8 INT8;
+typedef unsigned __int16 UINT16;
+typedef signed __int16 INT16;
+typedef unsigned __int32 UINT32, *PUINT32;
+typedef signed __int32 INT32, *PINT32;
+typedef unsigned __int64 UINT64, *PUINT64;
+typedef signed __int64 INT64, *PINT64;
+
+typedef unsigned __int32 ULONG32, *PULONG32;
+typedef signed __int32 LONG32, *PLONG32;
+typedef unsigned __int64 ULONG64;
+typedef signed __int64 LONG64;
+
+#if defined(_X86_) && _MSC_VER >= 1300
+#define _W64 __w64
+#else
+#define _W64
+#endif
+
+#ifdef BIT64
+
+#define _atoi64 (__int64)atoll
+
+typedef __int64 INT_PTR, *PINT_PTR;
+typedef unsigned __int64 UINT_PTR, *PUINT_PTR;
+typedef __int64 LONG_PTR, *PLONG_PTR;
+typedef unsigned __int64 ULONG_PTR, *PULONG_PTR;
+typedef unsigned __int64 DWORD_PTR, *PDWORD_PTR;
+
+/* maximum signed 64 bit value */
+#define LONG_PTR_MAX I64(9223372036854775807)
+/* maximum unsigned 64 bit value */
+#define ULONG_PTR_MAX UI64(0xffffffffffffffff)
+
+#ifndef SIZE_MAX
+#define SIZE_MAX _UI64_MAX
+#endif
+
+#define __int3264 __int64
+
+#if !defined(BIT64)
+__inline
+unsigned long
+HandleToULong(
+ const void *h
+ )
+{
+ return((unsigned long) (ULONG_PTR) h );
+}
+
+__inline
+long
+HandleToLong(
+ const void *h
+ )
+{
+ return((long) (LONG_PTR) h );
+}
+
+__inline
+void *
+ULongToHandle(
+ const unsigned long h
+ )
+{
+ return((void *) (UINT_PTR) h );
+}
+
+
+__inline
+void *
+LongToHandle(
+ const long h
+ )
+{
+ return((void *) (INT_PTR) h );
+}
+
+
+__inline
+unsigned long
+PtrToUlong(
+ const void *p
+ )
+{
+ return((unsigned long) (ULONG_PTR) p );
+}
+
+__inline
+unsigned int
+PtrToUint(
+ const void *p
+ )
+{
+ return((unsigned int) (UINT_PTR) p );
+}
+
+__inline
+unsigned short
+PtrToUshort(
+ const void *p
+ )
+{
+ return((unsigned short) (unsigned long) (ULONG_PTR) p );
+}
+
+__inline
+long
+PtrToLong(
+ const void *p
+ )
+{
+ return((long) (LONG_PTR) p );
+}
+
+__inline
+int
+PtrToInt(
+ const void *p
+ )
+{
+ return((int) (INT_PTR) p );
+}
+
+__inline
+short
+PtrToShort(
+ const void *p
+ )
+{
+ return((short) (long) (LONG_PTR) p );
+}
+
+__inline
+void *
+IntToPtr(
+ const int i
+ )
+// Caution: IntToPtr() sign-extends the int value.
+{
+ return( (void *)(INT_PTR)i );
+}
+
+__inline
+void *
+UIntToPtr(
+ const unsigned int ui
+ )
+// Caution: UIntToPtr() zero-extends the unsigned int value.
+{
+ return( (void *)(UINT_PTR)ui );
+}
+
+__inline
+void *
+LongToPtr(
+ const long l
+ )
+// Caution: LongToPtr() sign-extends the long value.
+{
+ return( (void *)(LONG_PTR)l );
+}
+
+__inline
+void *
+ULongToPtr(
+ const unsigned long ul
+ )
+// Caution: ULongToPtr() zero-extends the unsigned long value.
+{
+ return( (void *)(ULONG_PTR)ul );
+}
+
+__inline
+void *
+ShortToPtr(
+ const short s
+ )
+// Caution: ShortToPtr() sign-extends the short value.
+{
+ return( (void *)(INT_PTR)s );
+}
+
+__inline
+void *
+UShortToPtr(
+ const unsigned short us
+ )
+// Caution: UShortToPtr() zero-extends the unsigned short value.
+{
+ return( (void *)(UINT_PTR)us );
+}
+
+#else // !defined(BIT64)
+#define HandleToULong( h ) ((ULONG)(ULONG_PTR)(h) )
+#define HandleToLong( h ) ((LONG)(LONG_PTR) (h) )
+#define ULongToHandle( ul ) ((HANDLE)(ULONG_PTR) (ul) )
+#define LongToHandle( h ) ((HANDLE)(LONG_PTR) (h) )
+#define PtrToUlong( p ) ((ULONG)(ULONG_PTR) (p) )
+#define PtrToLong( p ) ((LONG)(LONG_PTR) (p) )
+#define PtrToUint( p ) ((UINT)(UINT_PTR) (p) )
+#define PtrToInt( p ) ((INT)(INT_PTR) (p) )
+#define PtrToUshort( p ) ((unsigned short)(ULONG_PTR)(p) )
+#define PtrToShort( p ) ((short)(LONG_PTR)(p) )
+#define IntToPtr( i ) ((VOID *)(INT_PTR)((int)(i)))
+#define UIntToPtr( ui ) ((VOID *)(UINT_PTR)((unsigned int)(ui)))
+#define LongToPtr( l ) ((VOID *)(LONG_PTR)((long)(l)))
+#define ULongToPtr( ul ) ((VOID *)(ULONG_PTR)((unsigned long)(ul)))
+#define ShortToPtr( s ) ((VOID *)(INT_PTR)((short)(s)))
+#define UShortToPtr( us ) ((VOID *)(UINT_PTR)((unsigned short)(s)))
+#endif // !defined(BIT64)
+
+
+
+#else
+
+typedef _W64 __int32 INT_PTR;
+typedef _W64 unsigned __int32 UINT_PTR;
+
+typedef _W64 __int32 LONG_PTR;
+typedef _W64 unsigned __int32 ULONG_PTR, *PULONG_PTR;
+typedef _W64 unsigned __int32 DWORD_PTR, *PDWORD_PTR;
+
+/* maximum signed 32 bit value */
+#define LONG_PTR_MAX 2147483647L
+/* maximum unsigned 32 bit value */
+#define ULONG_PTR_MAX 0xffffffffUL
+
+#ifndef SIZE_MAX
+#define SIZE_MAX UINT_MAX
+#endif
+
+#define __int3264 __int32
+
+#define HandleToULong( h ) ((ULONG)(ULONG_PTR)(h) )
+#define HandleToLong( h ) ((LONG)(LONG_PTR) (h) )
+#define ULongToHandle( ul ) ((HANDLE)(ULONG_PTR) (ul) )
+#define LongToHandle( h ) ((HANDLE)(LONG_PTR) (h) )
+#define PtrToUlong( p ) ((ULONG)(ULONG_PTR) (p) )
+#define PtrToLong( p ) ((LONG)(LONG_PTR) (p) )
+#define PtrToUint( p ) ((UINT)(UINT_PTR) (p) )
+#define PtrToInt( p ) ((INT)(INT_PTR) (p) )
+#define PtrToUshort( p ) ((unsigned short)(ULONG_PTR)(p) )
+#define PtrToShort( p ) ((short)(LONG_PTR)(p) )
+#define IntToPtr( i ) ((VOID *)(INT_PTR)((int)i))
+#define UIntToPtr( ui ) ((VOID *)(UINT_PTR)((unsigned int)ui))
+#define LongToPtr( l ) ((VOID *)(LONG_PTR)((long)l))
+#define ULongToPtr( ul ) ((VOID *)(ULONG_PTR)((unsigned long)ul))
+#define ShortToPtr( s ) ((VOID *)(INT_PTR)((short)s))
+#define UShortToPtr( us ) ((VOID *)(UINT_PTR)((unsigned short)s))
+
+#endif
+
+#define HandleToUlong(h) HandleToULong(h)
+#define UlongToHandle(ul) ULongToHandle(ul)
+#define UlongToPtr(ul) ULongToPtr(ul)
+#define UintToPtr(ui) UIntToPtr(ui)
+
+typedef ULONG_PTR SIZE_T, *PSIZE_T;
+typedef LONG_PTR SSIZE_T, *PSSIZE_T;
+
+#ifndef SIZE_T_MAX
+#define SIZE_T_MAX ULONG_PTR_MAX
+#endif // SIZE_T_MAX
+
+#ifndef SSIZE_T_MAX
+#define SSIZE_T_MAX LONG_PTR_MAX
+#endif
+
+#ifndef SSIZE_T_MIN
+#define SSIZE_T_MIN I64(0x8000000000000000)
+#endif
+
+#ifndef PAL_STDCPP_COMPAT
+#if defined(__APPLE_CC__) || defined(__linux__)
+#ifdef BIT64
+typedef unsigned long size_t;
+typedef long ptrdiff_t;
+#else // !BIT64
+typedef unsigned int size_t;
+typedef int ptrdiff_t;
+#endif // !BIT64
+#else
+typedef ULONG_PTR size_t;
+typedef LONG_PTR ptrdiff_t;
+#endif
+#endif // !PAL_STDCPP_COMPAT
+#define _SIZE_T_DEFINED
+
+typedef LONG_PTR LPARAM;
+
+#define _PTRDIFF_T_DEFINED
+#ifdef _MINGW_
+// We need to define _PTRDIFF_T to make sure ptrdiff_t doesn't get defined
+// again by system headers - but only for MinGW.
+#define _PTRDIFF_T
+#endif
+
+#ifdef PAL_STDCPP_COMPAT
+
+#ifdef BIT64
+typedef unsigned long int uintptr_t;
+#else // !BIT64
+typedef unsigned int uintptr_t;
+#endif // !BIT64
+
+typedef char16_t WCHAR;
+
+#else // PAL_STDCPP_COMPAT
+
+typedef wchar_t WCHAR;
+#if defined(__linux__)
+#ifdef BIT64
+typedef long int intptr_t;
+typedef unsigned long int uintptr_t;
+#else // !BIT64
+typedef int intptr_t;
+typedef unsigned int uintptr_t;
+#endif // !BIT64
+#else
+typedef INT_PTR intptr_t;
+typedef UINT_PTR uintptr_t;
+#endif
+
+#endif // PAL_STDCPP_COMPAT
+
+#define _INTPTR_T_DEFINED
+#define _UINTPTR_T_DEFINED
+
+typedef DWORD LCID;
+typedef PDWORD PLCID;
+typedef WORD LANGID;
+
+typedef DWORD LCTYPE;
+
+typedef WCHAR *PWCHAR;
+typedef WCHAR *LPWCH, *PWCH;
+typedef CONST WCHAR *LPCWCH, *PCWCH;
+typedef WCHAR *NWPSTR;
+typedef WCHAR *LPWSTR, *PWSTR;
+
+typedef CONST WCHAR *LPCWSTR, *PCWSTR;
+
+typedef char CHAR;
+typedef CHAR *PCHAR;
+typedef CHAR *LPCH, *PCH;
+typedef CONST CHAR *LPCCH, *PCCH;
+typedef CHAR *NPSTR;
+typedef CHAR *LPSTR, *PSTR;
+typedef CONST CHAR *LPCSTR, *PCSTR;
+
+#ifdef UNICODE
+typedef WCHAR TCHAR;
+typedef WCHAR _TCHAR;
+#else
+typedef CHAR TCHAR;
+typedef CHAR _TCHAR;
+#endif
+typedef TCHAR *PTCHAR;
+typedef TCHAR *LPTSTR, *PTSTR;
+typedef CONST TCHAR *LPCTSTR;
+
+#define MAKEWORD(a, b) ((WORD)(((BYTE)((DWORD_PTR)(a) & 0xff)) | ((WORD)((BYTE)((DWORD_PTR)(b) & 0xff))) << 8))
+#define MAKELONG(a, b) ((LONG)(((WORD)((DWORD_PTR)(a) & 0xffff)) | ((DWORD)((WORD)((DWORD_PTR)(b) & 0xffff))) << 16))
+#define LOWORD(l) ((WORD)((DWORD_PTR)(l) & 0xffff))
+#define HIWORD(l) ((WORD)((DWORD_PTR)(l) >> 16))
+#define LOBYTE(w) ((BYTE)((DWORD_PTR)(w) & 0xff))
+#define HIBYTE(w) ((BYTE)((DWORD_PTR)(w) >> 8))
+
+typedef VOID *HANDLE;
+typedef HANDLE HWND;
+typedef struct __PAL_RemoteHandle__ { HANDLE h; } *RHANDLE;
+typedef HANDLE *PHANDLE;
+typedef HANDLE *LPHANDLE;
+#define INVALID_HANDLE_VALUE ((VOID *)(-1))
+#define INVALID_FILE_SIZE ((DWORD)0xFFFFFFFF)
+#define INVALID_FILE_ATTRIBUTES ((DWORD) -1)
+typedef HANDLE HMODULE;
+typedef HANDLE HINSTANCE;
+typedef HANDLE HGLOBAL;
+typedef HANDLE HLOCAL;
+typedef HANDLE HRSRC;
+
+typedef LONG HRESULT;
+typedef LONG NTSTATUS;
+
+typedef union _LARGE_INTEGER {
+ struct {
+#if BIGENDIAN
+ LONG HighPart;
+ DWORD LowPart;
+#else
+ DWORD LowPart;
+ LONG HighPart;
+#endif
+ } u;
+ LONGLONG QuadPart;
+} LARGE_INTEGER, *PLARGE_INTEGER;
+
+#ifndef GUID_DEFINED
+typedef struct _GUID {
+ ULONG Data1; // NOTE: diff from Win32, for LP64
+ USHORT Data2;
+ USHORT Data3;
+ UCHAR Data4[ 8 ];
+} GUID;
+typedef const GUID *LPCGUID;
+#define GUID_DEFINED
+#endif // !GUID_DEFINED
+
+typedef struct _FILETIME {
+ DWORD dwLowDateTime;
+ DWORD dwHighDateTime;
+} FILETIME, *PFILETIME, *LPFILETIME;
+
+/* Code Page Default Values */
+#define CP_ACP 0 /* default to ANSI code page */
+#define CP_OEMCP 1 /* default to OEM code page */
+#define CP_MACCP 2 /* default to MAC code page */
+#define CP_THREAD_ACP 3 /* current thread's ANSI code page */
+#define CP_WINUNICODE 1200
+#define CP_UNICODE 1200 /* Unicode */
+#define CP_UNICODESWAP 1201 /* Unicode Big-Endian */
+#define CP_UTF7 65000 /* UTF-7 translation */
+#define CP_UTF8 65001 /* UTF-8 translation */
+
+typedef PVOID PSID;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __PAL_MSTYPES_H__
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+
+//
+// ===========================================================================
+// File: unknwn.h
+//
+// ===========================================================================
+// simplified unknwn.h for PAL
+
+
+#ifndef __IUnknown_INTERFACE_DEFINED__
+#define __IUnknown_INTERFACE_DEFINED__
+
+typedef interface IUnknown IUnknown;
+
+typedef /* [unique] */ IUnknown *LPUNKNOWN;
+
+// 00000000-0000-0000-C000-000000000046
+EXTERN_C const IID IID_IUnknown;
+
+MIDL_INTERFACE("00000000-0000-0000-C000-000000000046")
+IUnknown
+{
+ virtual HRESULT STDMETHODCALLTYPE QueryInterface(
+ REFIID riid,
+ void **ppvObject) = 0;
+
+ virtual ULONG STDMETHODCALLTYPE AddRef( void) = 0;
+
+ virtual ULONG STDMETHODCALLTYPE Release( void) = 0;
+
+ template<class Q>
+ HRESULT
+ STDMETHODCALLTYPE
+ QueryInterface(Q** pp)
+ {
+ return QueryInterface(__uuidof(Q), (void **)pp);
+ }
+};
+
+#endif // __IUnknown_INTERFACE_DEFINED__
+
+#ifndef __IClassFactory_INTERFACE_DEFINED__
+#define __IClassFactory_INTERFACE_DEFINED__
+
+// 00000001-0000-0000-C000-000000000046
+EXTERN_C const IID IID_IClassFactory;
+
+MIDL_INTERFACE("00000001-0000-0000-C000-000000000046")
+IClassFactory : public IUnknown
+{
+ virtual HRESULT STDMETHODCALLTYPE CreateInstance(
+ IUnknown *pUnkOuter,
+ REFIID riid,
+ void **ppvObject) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE LockServer(
+ BOOL fLock) = 0;
+};
+
+#endif // __IClassFactory_INTERFACE_DEFINED__
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#include <cstdarg>
+#include <cstdlib>
+#include "sosplugin.h"
+#include <string.h>
+#include <string>
+
+#define CONVERT_FROM_SIGN_EXTENDED(offset) ((ULONG_PTR)(offset))
+
+ULONG g_currentThreadIndex = -1;
+ULONG g_currentThreadSystemId = -1;
+char *g_coreclrDirectory;
+
+LLDBServices::LLDBServices(lldb::SBDebugger &debugger, lldb::SBCommandReturnObject &returnObject, lldb::SBProcess *process, lldb::SBThread *thread) :
+ m_ref(1),
+ m_debugger(debugger),
+ m_returnObject(returnObject),
+ m_currentProcess(process),
+ m_currentThread(thread)
+{
+ returnObject.SetStatus(lldb::eReturnStatusSuccessFinishResult);
+}
+
+LLDBServices::~LLDBServices()
+{
+}
+
+//----------------------------------------------------------------------------
+// IUnknown
+//----------------------------------------------------------------------------
+
+HRESULT
+LLDBServices::QueryInterface(
+ REFIID InterfaceId,
+ PVOID* Interface
+ )
+{
+ if (InterfaceId == __uuidof(IUnknown) ||
+ InterfaceId == __uuidof(ILLDBServices))
+ {
+ *Interface = (ILLDBServices*)this;
+ AddRef();
+ return S_OK;
+ }
+ else
+ {
+ *Interface = NULL;
+ return E_NOINTERFACE;
+ }
+}
+
+ULONG
+LLDBServices::AddRef()
+{
+ LONG ref = InterlockedIncrement(&m_ref);
+ return ref;
+}
+
+ULONG
+LLDBServices::Release()
+{
+ LONG ref = InterlockedDecrement(&m_ref);
+ if (ref == 0)
+ {
+ delete this;
+ }
+ return ref;
+}
+
+//----------------------------------------------------------------------------
+// ILLDBServices
+//----------------------------------------------------------------------------
+
+PCSTR
+LLDBServices::GetCoreClrDirectory()
+{
+ return g_coreclrDirectory;
+}
+
+DWORD_PTR
+LLDBServices::GetExpression(
+ PCSTR exp)
+{
+ if (exp == nullptr)
+ {
+ return 0;
+ }
+
+ lldb::SBFrame frame = GetCurrentFrame();
+ if (!frame.IsValid())
+ {
+ return 0;
+ }
+
+ DWORD_PTR result = 0;
+ lldb::SBError error;
+ std::string str;
+
+ // To be compatible with windbg/dbgeng, we need to emulate the default
+ // hex radix (because sos prints addresses and other hex values without
+ // the 0x) by first prepending 0x and if that fails use the actual
+ // undecorated expression.
+ str.append("0x");
+ str.append(exp);
+
+ result = GetExpression(frame, error, str.c_str());
+ if (error.Fail())
+ {
+ result = GetExpression(frame, error, exp);
+ }
+
+ return result;
+}
+
+// Internal function
+DWORD_PTR
+LLDBServices::GetExpression(
+ /* const */ lldb::SBFrame& frame,
+ lldb::SBError& error,
+ PCSTR exp)
+{
+ DWORD_PTR result = 0;
+
+ lldb::SBValue value = frame.EvaluateExpression(exp, lldb::eNoDynamicValues);
+ if (value.IsValid())
+ {
+ result = value.GetValueAsUnsigned(error);
+ }
+
+ return result;
+}
+
+//
+// lldb doesn't have a way or API to unwind an arbitary context (IP, SP)
+// and return the next frame so we have to stick with the native frames
+// lldb has found and find the closest frame to the incoming context SP.
+//
+HRESULT
+LLDBServices::VirtualUnwind(
+ DWORD threadID,
+ ULONG32 contextSize,
+ PBYTE context)
+{
+ lldb::SBProcess process;
+ lldb::SBThread thread;
+
+ if (context == NULL || contextSize < sizeof(DT_CONTEXT))
+ {
+ return E_INVALIDARG;
+ }
+
+ process = GetCurrentProcess();
+ if (!process.IsValid())
+ {
+ return E_FAIL;
+ }
+
+ thread = process.GetThreadByID(threadID);
+ if (!thread.IsValid())
+ {
+ return E_FAIL;
+ }
+
+ DT_CONTEXT *dtcontext = (DT_CONTEXT*)context;
+ lldb::SBFrame frameFound;
+
+#ifdef DBG_TARGET_AMD64
+ DWORD64 spToFind = dtcontext->Rsp;
+#elif DBG_TARGET_X86
+ DWORD spToFind = dtcontext->Esp;
+#elif DBG_TARGET_ARM
+ DWORD spToFind = dtcontext->Sp;
+#elif DBG_TARGET_ARM64
+ DWORD64 spToFind = dtcontext->Sp;
+#else
+#error "spToFind undefined for this platform"
+#endif
+
+ int numFrames = thread.GetNumFrames();
+ for (int i = 0; i < numFrames; i++)
+ {
+ lldb::SBFrame frame = thread.GetFrameAtIndex(i);
+ if (!frame.IsValid())
+ {
+ break;
+ }
+ lldb::addr_t sp = frame.GetSP();
+
+ if ((i + 1) < numFrames)
+ {
+ lldb::SBFrame frameNext = thread.GetFrameAtIndex(i + 1);
+ if (frameNext.IsValid())
+ {
+ lldb::addr_t spNext = frameNext.GetSP();
+
+ // An exact match of the current frame's SP would be nice
+ // but sometimes the incoming context is between lldb frames
+ if (spToFind >= sp && spToFind < spNext)
+ {
+ frameFound = frameNext;
+ break;
+ }
+ }
+ }
+ }
+
+ if (!frameFound.IsValid())
+ {
+ return E_FAIL;
+ }
+
+ GetContextFromFrame(frameFound, dtcontext);
+
+ return S_OK;
+}
+
+bool
+ExceptionBreakpointCallback(
+ void *baton,
+ lldb::SBProcess &process,
+ lldb::SBThread &thread,
+ lldb::SBBreakpointLocation &location)
+{
+ lldb::SBDebugger debugger = process.GetTarget().GetDebugger();
+
+ // Send the normal and error output to stdout/stderr since we
+ // don't have a return object from the command interpreter.
+ lldb::SBCommandReturnObject result;
+ result.SetImmediateOutputFile(stdout);
+ result.SetImmediateErrorFile(stderr);
+
+ // Save the process and thread to be used by the current process/thread
+ // helper functions.
+ LLDBServices* client = new LLDBServices(debugger, result, &process, &thread);
+ return ((PFN_EXCEPTION_CALLBACK)baton)(client) == S_OK;
+}
+
+lldb::SBBreakpoint g_exceptionbp;
+
+HRESULT
+LLDBServices::SetExceptionCallback(
+ PFN_EXCEPTION_CALLBACK callback)
+{
+ if (!g_exceptionbp.IsValid())
+ {
+ lldb::SBTarget target = m_debugger.GetSelectedTarget();
+ if (!target.IsValid())
+ {
+ return E_FAIL;
+ }
+ lldb::SBBreakpoint exceptionbp = target.BreakpointCreateForException(lldb::LanguageType::eLanguageTypeC_plus_plus, false, true);
+ if (!exceptionbp.IsValid())
+ {
+ return E_FAIL;
+ }
+#ifdef FLAGS_ANONYMOUS_ENUM
+ exceptionbp.AddName("DoNotDeleteOrDisable");
+#endif
+ exceptionbp.SetCallback(ExceptionBreakpointCallback, (void *)callback);
+ g_exceptionbp = exceptionbp;
+ }
+ return S_OK;
+}
+
+HRESULT
+LLDBServices::ClearExceptionCallback()
+{
+ if (g_exceptionbp.IsValid())
+ {
+ lldb::SBTarget target = m_debugger.GetSelectedTarget();
+ if (!target.IsValid())
+ {
+ return E_FAIL;
+ }
+ target.BreakpointDelete(g_exceptionbp.GetID());
+ g_exceptionbp = lldb::SBBreakpoint();
+ }
+ return S_OK;
+}
+
+//----------------------------------------------------------------------------
+// IDebugControl2
+//----------------------------------------------------------------------------
+
+// Checks for a user interrupt, such a Ctrl-C
+// or stop button.
+// This method is reentrant.
+HRESULT
+LLDBServices::GetInterrupt()
+{
+ return E_FAIL;
+}
+
+// Sends output through clients
+// output callbacks if the mask is allowed
+// by the current output control mask and
+// according to the output distribution
+// settings.
+HRESULT
+LLDBServices::Output(
+ ULONG mask,
+ PCSTR format,
+ ...)
+{
+ va_list args;
+ va_start (args, format);
+ HRESULT result = OutputVaList(mask, format, args);
+ va_end (args);
+ return result;
+}
+
+HRESULT
+LLDBServices::OutputVaList(
+ ULONG mask,
+ PCSTR format,
+ va_list args)
+{
+ HRESULT result = S_OK;
+ char str[1024];
+
+ va_list args_copy;
+ va_copy (args_copy, args);
+
+ // Try and format our string into a fixed buffer first and see if it fits
+ size_t length = ::vsnprintf(str, sizeof(str), format, args);
+ if (length < sizeof(str))
+ {
+ OutputString(mask, str);
+ }
+ else
+ {
+ // Our stack buffer wasn't big enough to contain the entire formatted
+ // string, so lets let vasprintf create the string for us!
+ char *str_ptr = nullptr;
+ length = ::vasprintf(&str_ptr, format, args_copy);
+ if (str_ptr)
+ {
+ OutputString(mask, str_ptr);
+ ::free (str_ptr);
+ }
+ else
+ {
+ result = E_FAIL;
+ }
+ }
+
+ va_end (args_copy);
+
+ return result;
+}
+
+// The following methods allow direct control
+// over the distribution of the given output
+// for situations where something other than
+// the default is desired. These methods require
+// extra work in the engine so they should
+// only be used when necessary.
+HRESULT
+LLDBServices::ControlledOutput(
+ ULONG outputControl,
+ ULONG mask,
+ PCSTR format,
+ ...)
+{
+ va_list args;
+ va_start (args, format);
+ HRESULT result = ControlledOutputVaList(outputControl, mask, format, args);
+ va_end (args);
+ return result;
+}
+
+HRESULT
+LLDBServices::ControlledOutputVaList(
+ ULONG outputControl,
+ ULONG mask,
+ PCSTR format,
+ va_list args)
+{
+ return OutputVaList(mask, format, args);
+}
+
+// Returns information about the debuggee such
+// as user vs. kernel, dump vs. live, etc.
+HRESULT
+LLDBServices::GetDebuggeeType(
+ PULONG debugClass,
+ PULONG qualifier)
+{
+ *debugClass = DEBUG_CLASS_USER_WINDOWS;
+ *qualifier = 0;
+ return S_OK;
+}
+
+// Returns the page size for the currently executing
+// processor context. The page size may vary between
+// processor types.
+HRESULT
+LLDBServices::GetPageSize(
+ PULONG size)
+{
+ *size = 4096;
+ return S_OK;
+}
+
+HRESULT
+LLDBServices::GetExecutingProcessorType(
+ PULONG type)
+{
+#ifdef DBG_TARGET_AMD64
+ *type = IMAGE_FILE_MACHINE_AMD64;
+#elif DBG_TARGET_ARM
+ *type = IMAGE_FILE_MACHINE_ARMNT;
+#elif DBG_TARGET_ARM64
+ *type = IMAGE_FILE_MACHINE_ARM64;
+#elif DBG_TARGET_X86
+ *type = IMAGE_FILE_MACHINE_I386;
+#else
+#error "Unsupported target"
+#endif
+ return S_OK;
+}
+
+HRESULT
+LLDBServices::Execute(
+ ULONG outputControl,
+ PCSTR command,
+ ULONG flags)
+{
+ lldb::SBCommandInterpreter interpreter = m_debugger.GetCommandInterpreter();
+
+ lldb::SBCommandReturnObject result;
+ lldb::ReturnStatus status = interpreter.HandleCommand(command, result);
+
+ return status <= lldb::eReturnStatusSuccessContinuingResult ? S_OK : E_FAIL;
+}
+
+// PAL raise exception function and exception record pointer variable name
+// See coreclr\src\pal\src\exception\seh-unwind.cpp for the details. This
+// function depends on RtlpRaisException not being inlined or optimized.
+#define FUNCTION_NAME "RtlpRaiseException"
+#define VARIABLE_NAME "ExceptionRecord"
+
+HRESULT
+LLDBServices::GetLastEventInformation(
+ PULONG type,
+ PULONG processId,
+ PULONG threadId,
+ PVOID extraInformation,
+ ULONG extraInformationSize,
+ PULONG extraInformationUsed,
+ PSTR description,
+ ULONG descriptionSize,
+ PULONG descriptionUsed)
+{
+ if (extraInformationSize < sizeof(DEBUG_LAST_EVENT_INFO_EXCEPTION) ||
+ type == NULL || processId == NULL || threadId == NULL || extraInformationUsed == NULL)
+ {
+ return E_INVALIDARG;
+ }
+
+ *type = DEBUG_EVENT_EXCEPTION;
+ *processId = 0;
+ *threadId = 0;
+ *extraInformationUsed = sizeof(DEBUG_LAST_EVENT_INFO_EXCEPTION);
+
+ DEBUG_LAST_EVENT_INFO_EXCEPTION *pdle = (DEBUG_LAST_EVENT_INFO_EXCEPTION *)extraInformation;
+ pdle->FirstChance = 1;
+
+ lldb::SBProcess process = GetCurrentProcess();
+ if (!process.IsValid())
+ {
+ return E_FAIL;
+ }
+ lldb::SBThread thread = GetCurrentThread();
+ if (!thread.IsValid())
+ {
+ return E_FAIL;
+ }
+
+ *processId = process.GetProcessID();
+ *threadId = thread.GetThreadID();
+
+ // Enumerate each stack frame at the special "throw"
+ // breakpoint and find the raise exception function
+ // with the exception record parameter.
+ int numFrames = thread.GetNumFrames();
+ for (int i = 0; i < numFrames; i++)
+ {
+ lldb::SBFrame frame = thread.GetFrameAtIndex(i);
+ if (!frame.IsValid())
+ {
+ break;
+ }
+
+ const char *functionName = frame.GetFunctionName();
+ if (functionName == NULL || strncmp(functionName, FUNCTION_NAME, sizeof(FUNCTION_NAME) - 1) != 0)
+ {
+ continue;
+ }
+
+ lldb::SBValue exValue = frame.FindVariable(VARIABLE_NAME);
+ if (!exValue.IsValid())
+ {
+ break;
+ }
+
+ lldb::SBError error;
+ ULONG64 pExceptionRecord = exValue.GetValueAsUnsigned(error);
+ if (error.Fail())
+ {
+ break;
+ }
+
+ process.ReadMemory(pExceptionRecord, &pdle->ExceptionRecord, sizeof(pdle->ExceptionRecord), error);
+ if (error.Fail())
+ {
+ break;
+ }
+
+ return S_OK;
+ }
+
+ return E_FAIL;
+}
+
+HRESULT
+LLDBServices::Disassemble(
+ ULONG64 offset,
+ ULONG flags,
+ PSTR buffer,
+ ULONG bufferSize,
+ PULONG disassemblySize,
+ PULONG64 endOffset)
+{
+ lldb::SBInstruction instruction;
+ lldb::SBInstructionList list;
+ lldb::SBTarget target;
+ lldb::SBAddress address;
+ lldb::SBError error;
+ lldb::SBData data;
+ std::string str;
+ HRESULT hr = S_OK;
+ ULONG size = 0;
+ uint8_t byte;
+ int cch;
+
+ // lldb doesn't expect sign-extended address
+ offset = CONVERT_FROM_SIGN_EXTENDED(offset);
+
+ if (buffer == NULL)
+ {
+ hr = E_INVALIDARG;
+ goto exit;
+ }
+ *buffer = 0;
+
+ target = m_debugger.GetSelectedTarget();
+ if (!target.IsValid())
+ {
+ hr = E_INVALIDARG;
+ goto exit;
+ }
+ address = target.ResolveLoadAddress(offset);
+ if (!address.IsValid())
+ {
+ hr = E_INVALIDARG;
+ goto exit;
+ }
+ list = target.ReadInstructions(address, 1, "intel");
+ if (!list.IsValid())
+ {
+ hr = E_FAIL;
+ goto exit;
+ }
+ instruction = list.GetInstructionAtIndex(0);
+ if (!instruction.IsValid())
+ {
+ hr = E_FAIL;
+ goto exit;
+ }
+ cch = snprintf(buffer, bufferSize, "%016llx ", (unsigned long long)offset);
+ buffer += cch;
+ bufferSize -= cch;
+
+ size = instruction.GetByteSize();
+ data = instruction.GetData(target);
+ for (int i = 0; i < size && bufferSize > 0; i++)
+ {
+ byte = data.GetUnsignedInt8(error, i);
+ if (error.Fail())
+ {
+ hr = E_FAIL;
+ goto exit;
+ }
+ cch = snprintf(buffer, bufferSize, "%02x", byte);
+ buffer += cch;
+ bufferSize -= cch;
+ }
+ // Pad the data bytes to 16 chars
+ cch = size * 2;
+ while (bufferSize > 0)
+ {
+ *buffer++ = ' ';
+ bufferSize--;
+ if (++cch >= 21)
+ break;
+ }
+
+ cch = snprintf(buffer, bufferSize, "%s", instruction.GetMnemonic(target));
+ buffer += cch;
+ bufferSize -= cch;
+
+ // Pad the mnemonic to 8 chars
+ while (bufferSize > 0)
+ {
+ *buffer++ = ' ';
+ bufferSize--;
+ if (++cch >= 8)
+ break;
+ }
+ snprintf(buffer, bufferSize, "%s\n", instruction.GetOperands(target));
+
+exit:
+ if (disassemblySize != NULL)
+ {
+ *disassemblySize = size;
+ }
+ if (endOffset != NULL)
+ {
+ *endOffset = offset + size;
+ }
+ return hr;
+}
+
+// Internal output string function
+void
+LLDBServices::OutputString(
+ ULONG mask,
+ PCSTR str)
+{
+ if (mask == DEBUG_OUTPUT_ERROR)
+ {
+ m_returnObject.SetStatus(lldb::eReturnStatusFailed);
+ }
+ // Can not use AppendMessage or AppendWarning because they add a newline. SetError
+ // can not be used for DEBUG_OUTPUT_ERROR mask because it caches the error strings
+ // seperately from the normal output so error/normal texts are not intermixed
+ // correctly.
+ m_returnObject.Printf("%s", str);
+}
+
+//----------------------------------------------------------------------------
+// IDebugControl4
+//----------------------------------------------------------------------------
+
+HRESULT
+LLDBServices::GetContextStackTrace(
+ PVOID startContext,
+ ULONG startContextSize,
+ PDEBUG_STACK_FRAME frames,
+ ULONG framesSize,
+ PVOID frameContexts,
+ ULONG frameContextsSize,
+ ULONG frameContextsEntrySize,
+ PULONG framesFilled)
+{
+ DT_CONTEXT *currentContext = (DT_CONTEXT*)frameContexts;
+ PDEBUG_STACK_FRAME currentFrame = frames;
+ lldb::SBThread thread;
+ lldb::SBFrame frame;
+ ULONG cFrames = 0;
+ HRESULT hr = S_OK;
+
+ // Doesn't support a starting context
+ if (startContext != NULL || frames == NULL || frameContexts == NULL || frameContextsEntrySize != sizeof(DT_CONTEXT))
+ {
+ hr = E_INVALIDARG;
+ goto exit;
+ }
+
+ thread = GetCurrentThread();
+ if (!thread.IsValid())
+ {
+ hr = E_FAIL;
+ goto exit;
+ }
+
+ frame = thread.GetFrameAtIndex(0);
+ for (int i = 0; i < thread.GetNumFrames(); i++)
+ {
+ if (!frame.IsValid() || (cFrames > framesSize) || ((char *)currentContext > ((char *)frameContexts + frameContextsSize)))
+ {
+ break;
+ }
+ lldb::SBFrame framePrevious;
+ lldb::SBFrame frameNext;
+
+ currentFrame->InstructionOffset = frame.GetPC();
+ currentFrame->StackOffset = frame.GetSP();
+
+ currentFrame->FuncTableEntry = 0;
+ currentFrame->Params[0] = 0;
+ currentFrame->Params[1] = 0;
+ currentFrame->Params[2] = 0;
+ currentFrame->Params[3] = 0;
+ currentFrame->Virtual = i == 0 ? TRUE : FALSE;
+ currentFrame->FrameNumber = frame.GetFrameID();
+
+ frameNext = thread.GetFrameAtIndex(i + 1);
+ if (frameNext.IsValid())
+ {
+ currentFrame->ReturnOffset = frameNext.GetPC();
+ }
+
+ if (framePrevious.IsValid())
+ {
+ currentFrame->FrameOffset = framePrevious.GetSP();
+ }
+ else
+ {
+ currentFrame->FrameOffset = frame.GetSP();
+ }
+
+ GetContextFromFrame(frame, currentContext);
+
+ framePrevious = frame;
+ frame = frameNext;
+ currentContext++;
+ currentFrame++;
+ cFrames++;
+ }
+
+exit:
+ if (framesFilled != NULL)
+ {
+ *framesFilled = cFrames;
+ }
+ return hr;
+}
+
+//----------------------------------------------------------------------------
+// IDebugDataSpaces
+//----------------------------------------------------------------------------
+
+HRESULT
+LLDBServices::ReadVirtual(
+ ULONG64 offset,
+ PVOID buffer,
+ ULONG bufferSize,
+ PULONG bytesRead)
+{
+ lldb::SBError error;
+ size_t read = 0;
+
+ // lldb doesn't expect sign-extended address
+ offset = CONVERT_FROM_SIGN_EXTENDED(offset);
+
+ lldb::SBProcess process = GetCurrentProcess();
+ if (!process.IsValid())
+ {
+ goto exit;
+ }
+
+ read = process.ReadMemory(offset, buffer, bufferSize, error);
+
+exit:
+ if (bytesRead)
+ {
+ *bytesRead = read;
+ }
+ return error.Success() ? S_OK : E_FAIL;
+}
+
+HRESULT
+LLDBServices::WriteVirtual(
+ ULONG64 offset,
+ PVOID buffer,
+ ULONG bufferSize,
+ PULONG bytesWritten)
+{
+ lldb::SBError error;
+ size_t written = 0;
+
+ // lldb doesn't expect sign-extended address
+ offset = CONVERT_FROM_SIGN_EXTENDED(offset);
+
+ lldb::SBProcess process = GetCurrentProcess();
+ if (!process.IsValid())
+ {
+ goto exit;
+ }
+
+ written = process.WriteMemory(offset, buffer, bufferSize, error);
+
+exit:
+ if (bytesWritten)
+ {
+ *bytesWritten = written;
+ }
+ return error.Success() ? S_OK : E_FAIL;
+}
+
+//----------------------------------------------------------------------------
+// IDebugSymbols
+//----------------------------------------------------------------------------
+
+HRESULT
+LLDBServices::GetSymbolOptions(
+ PULONG options)
+{
+ *options = SYMOPT_LOAD_LINES;
+ return S_OK;
+}
+
+HRESULT
+LLDBServices::GetNameByOffset(
+ ULONG64 offset,
+ PSTR nameBuffer,
+ ULONG nameBufferSize,
+ PULONG nameSize,
+ PULONG64 displacement)
+{
+ ULONG64 disp = DEBUG_INVALID_OFFSET;
+ HRESULT hr = S_OK;
+
+ lldb::SBTarget target;
+ lldb::SBAddress address;
+ lldb::SBModule module;
+ lldb::SBFileSpec file;
+ lldb::SBSymbol symbol;
+ std::string str;
+
+ // lldb doesn't expect sign-extended address
+ offset = CONVERT_FROM_SIGN_EXTENDED(offset);
+
+ target = m_debugger.GetSelectedTarget();
+ if (!target.IsValid())
+ {
+ hr = E_FAIL;
+ goto exit;
+ }
+
+ address = target.ResolveLoadAddress(offset);
+ if (!address.IsValid())
+ {
+ hr = E_INVALIDARG;
+ goto exit;
+ }
+
+ module = address.GetModule();
+ if (!module.IsValid())
+ {
+ hr = E_FAIL;
+ goto exit;
+ }
+
+ file = module.GetFileSpec();
+ if (file.IsValid())
+ {
+ str.append(file.GetFilename());
+ }
+
+ symbol = address.GetSymbol();
+ if (symbol.IsValid())
+ {
+ lldb::SBAddress startAddress = symbol.GetStartAddress();
+ disp = address.GetOffset() - startAddress.GetOffset();
+
+ const char *name = symbol.GetName();
+ if (name)
+ {
+ if (file.IsValid())
+ {
+ str.append("!");
+ }
+ str.append(name);
+ }
+ }
+
+ str.append(1, '\0');
+
+exit:
+ if (nameSize)
+ {
+ *nameSize = str.length();
+ }
+ if (nameBuffer)
+ {
+ str.copy(nameBuffer, nameBufferSize);
+ }
+ if (displacement)
+ {
+ *displacement = disp;
+ }
+ return hr;
+}
+
+HRESULT
+LLDBServices::GetNumberModules(
+ PULONG loaded,
+ PULONG unloaded)
+{
+ ULONG numModules = 0;
+ HRESULT hr = S_OK;
+
+ lldb::SBTarget target = m_debugger.GetSelectedTarget();
+ if (!target.IsValid())
+ {
+ hr = E_FAIL;
+ goto exit;
+ }
+
+ numModules = target.GetNumModules();
+
+exit:
+ if (loaded)
+ {
+ *loaded = numModules;
+ }
+ if (unloaded)
+ {
+ *unloaded = 0;
+ }
+ return hr;
+}
+
+HRESULT LLDBServices::GetModuleByIndex(
+ ULONG index,
+ PULONG64 base)
+{
+ ULONG64 moduleBase = UINT64_MAX;
+
+ lldb::SBTarget target;
+ lldb::SBModule module;
+
+ target = m_debugger.GetSelectedTarget();
+ if (!target.IsValid())
+ {
+ goto exit;
+ }
+
+ module = target.GetModuleAtIndex(index);
+ if (!module.IsValid())
+ {
+ goto exit;
+ }
+
+ moduleBase = GetModuleBase(target, module);
+
+exit:
+ if (base)
+ {
+ *base = moduleBase;
+ }
+ return moduleBase == UINT64_MAX ? E_FAIL : S_OK;
+}
+
+HRESULT
+LLDBServices::GetModuleByModuleName(
+ PCSTR name,
+ ULONG startIndex,
+ PULONG index,
+ PULONG64 base)
+{
+ ULONG64 moduleBase = UINT64_MAX;
+ ULONG moduleIndex = UINT32_MAX;
+
+ lldb::SBTarget target;
+ lldb::SBModule module;
+ lldb::SBFileSpec fileSpec;
+ fileSpec.SetFilename(name);
+
+ target = m_debugger.GetSelectedTarget();
+ if (!target.IsValid())
+ {
+ goto exit;
+ }
+
+ module = target.FindModule(fileSpec);
+ if (!module.IsValid())
+ {
+ goto exit;
+ }
+
+ moduleBase = GetModuleBase(target, module);
+
+ if (index)
+ {
+ int numModules = target.GetNumModules();
+ for (int mi = startIndex; mi < numModules; mi++)
+ {
+ lldb::SBModule mod = target.GetModuleAtIndex(mi);
+ if (module == mod)
+ {
+ moduleIndex = mi;
+ break;
+ }
+ }
+ }
+
+exit:
+ if (index)
+ {
+ *index = moduleIndex;
+ }
+ if (base)
+ {
+ *base = moduleBase;
+ }
+ return moduleBase == UINT64_MAX ? E_FAIL : S_OK;
+}
+
+HRESULT
+LLDBServices::GetModuleByOffset(
+ ULONG64 offset,
+ ULONG startIndex,
+ PULONG index,
+ PULONG64 base)
+{
+ ULONG64 moduleBase = UINT64_MAX;
+ ULONG moduleIndex = UINT32_MAX;
+
+ lldb::SBTarget target;
+ int numModules;
+
+ // lldb doesn't expect sign-extended address
+ offset = CONVERT_FROM_SIGN_EXTENDED(offset);
+
+ target = m_debugger.GetSelectedTarget();
+ if (!target.IsValid())
+ {
+ goto exit;
+ }
+
+ numModules = target.GetNumModules();
+ for (int mi = startIndex; mi < numModules; mi++)
+ {
+ lldb::SBModule module = target.GetModuleAtIndex(mi);
+
+ int numSections = module.GetNumSections();
+ for (int si = 0; si < numSections; si++)
+ {
+ lldb::SBSection section = module.GetSectionAtIndex(si);
+ if (section.IsValid())
+ {
+ lldb::addr_t baseAddress = section.GetLoadAddress(target);
+ if (baseAddress != LLDB_INVALID_ADDRESS)
+ {
+ if (offset > baseAddress)
+ {
+ if ((offset - baseAddress) < section.GetByteSize())
+ {
+ moduleIndex = mi;
+ moduleBase = baseAddress - section.GetFileOffset();
+ goto exit;
+ }
+ }
+ }
+ }
+ }
+ }
+
+exit:
+ if (index)
+ {
+ *index = moduleIndex;
+ }
+ if (base)
+ {
+ *base = moduleBase;
+ }
+ return moduleBase == UINT64_MAX ? E_FAIL : S_OK;
+}
+
+HRESULT
+LLDBServices::GetModuleNames(
+ ULONG index,
+ ULONG64 base,
+ PSTR imageNameBuffer,
+ ULONG imageNameBufferSize,
+ PULONG imageNameSize,
+ PSTR moduleNameBuffer,
+ ULONG moduleNameBufferSize,
+ PULONG moduleNameSize,
+ PSTR loadedImageNameBuffer,
+ ULONG loadedImageNameBufferSize,
+ PULONG loadedImageNameSize)
+{
+ lldb::SBTarget target;
+ lldb::SBFileSpec fileSpec;
+ HRESULT hr = S_OK;
+
+ // lldb doesn't expect sign-extended address
+ base = CONVERT_FROM_SIGN_EXTENDED(base);
+
+ target = m_debugger.GetSelectedTarget();
+ if (!target.IsValid())
+ {
+ hr = E_FAIL;
+ goto exit;
+ }
+
+ if (index != DEBUG_ANY_ID)
+ {
+ lldb::SBModule module = target.GetModuleAtIndex(index);
+ if (module.IsValid())
+ {
+ fileSpec = module.GetFileSpec();
+ }
+ }
+ else
+ {
+ int numModules = target.GetNumModules();
+ for (int mi = 0; mi < numModules; mi++)
+ {
+ lldb::SBModule module = target.GetModuleAtIndex(mi);
+ if (module.IsValid())
+ {
+ ULONG64 moduleBase = GetModuleBase(target, module);
+ if (base == moduleBase)
+ {
+ fileSpec = module.GetFileSpec();
+ break;
+ }
+ }
+ }
+ }
+
+ if (!fileSpec.IsValid())
+ {
+ hr = E_FAIL;
+ goto exit;
+ }
+
+exit:
+ if (imageNameBuffer)
+ {
+ int size = fileSpec.GetPath(imageNameBuffer, imageNameBufferSize);
+ if (imageNameSize)
+ {
+ *imageNameSize = size;
+ }
+ }
+ if (moduleNameBuffer)
+ {
+ const char *fileName = fileSpec.GetFilename();
+ if (fileName == NULL)
+ {
+ fileName = "";
+ }
+ stpncpy(moduleNameBuffer, fileName, moduleNameBufferSize);
+ if (moduleNameSize)
+ {
+ *moduleNameSize = strlen(fileName);
+ }
+ }
+ if (loadedImageNameBuffer)
+ {
+ int size = fileSpec.GetPath(loadedImageNameBuffer, loadedImageNameBufferSize);
+ if (loadedImageNameSize)
+ {
+ *loadedImageNameSize = size;
+ }
+ }
+ return hr;
+}
+
+HRESULT
+LLDBServices::GetLineByOffset(
+ ULONG64 offset,
+ PULONG fileLine,
+ PSTR fileBuffer,
+ ULONG fileBufferSize,
+ PULONG fileSize,
+ PULONG64 displacement)
+{
+ ULONG64 disp = DEBUG_INVALID_OFFSET;
+ HRESULT hr = S_OK;
+ ULONG line = 0;
+
+ lldb::SBTarget target;
+ lldb::SBAddress address;
+ lldb::SBFileSpec file;
+ lldb::SBLineEntry lineEntry;
+ std::string str;
+
+ // lldb doesn't expect sign-extended address
+ offset = CONVERT_FROM_SIGN_EXTENDED(offset);
+
+ target = m_debugger.GetSelectedTarget();
+ if (!target.IsValid())
+ {
+ hr = E_FAIL;
+ goto exit;
+ }
+
+ address = target.ResolveLoadAddress(offset);
+ if (!address.IsValid())
+ {
+ hr = E_INVALIDARG;
+ goto exit;
+ }
+
+ if (displacement)
+ {
+ lldb::SBSymbol symbol = address.GetSymbol();
+ if (symbol.IsValid())
+ {
+ lldb::SBAddress startAddress = symbol.GetStartAddress();
+ disp = address.GetOffset() - startAddress.GetOffset();
+ }
+ }
+
+ lineEntry = address.GetLineEntry();
+ if (!lineEntry.IsValid())
+ {
+ hr = E_FAIL;
+ goto exit;
+ }
+
+ line = lineEntry.GetLine();
+ file = lineEntry.GetFileSpec();
+ if (file.IsValid())
+ {
+ str.append(file.GetDirectory());
+ str.append(1, '/');
+ str.append(file.GetFilename());
+ }
+
+ str.append(1, '\0');
+
+exit:
+ if (fileLine)
+ {
+ *fileLine = line;
+ }
+ if (fileSize)
+ {
+ *fileSize = str.length();
+ }
+ if (fileBuffer)
+ {
+ str.copy(fileBuffer, fileBufferSize);
+ }
+ if (displacement)
+ {
+ *displacement = disp;
+ }
+ return hr;
+}
+
+HRESULT
+LLDBServices::GetSourceFileLineOffsets(
+ PCSTR file,
+ PULONG64 buffer,
+ ULONG bufferLines,
+ PULONG fileLines)
+{
+ if (fileLines != NULL)
+ {
+ *fileLines = (ULONG)-1;
+ }
+ return E_NOTIMPL;
+}
+
+HRESULT
+LLDBServices::FindSourceFile(
+ ULONG startElement,
+ PCSTR file,
+ ULONG flags,
+ PULONG foundElement,
+ PSTR buffer,
+ ULONG bufferSize,
+ PULONG foundSize)
+{
+ return E_NOTIMPL;
+}
+
+// Internal functions
+PCSTR
+LLDBServices::GetModuleDirectory(
+ PCSTR name)
+{
+ lldb::SBTarget target = m_debugger.GetSelectedTarget();
+ if (!target.IsValid())
+ {
+ return NULL;
+ }
+
+ lldb::SBFileSpec fileSpec;
+ fileSpec.SetFilename(name);
+
+ lldb::SBModule module = target.FindModule(fileSpec);
+ if (!module.IsValid())
+ {
+ return NULL;
+ }
+
+ return module.GetFileSpec().GetDirectory();
+}
+
+ULONG64
+LLDBServices::GetModuleBase(
+ /* const */ lldb::SBTarget& target,
+ /* const */ lldb::SBModule& module)
+{
+ // Find the first section with an valid base address
+ int numSections = module.GetNumSections();
+ for (int si = 0; si < numSections; si++)
+ {
+ lldb::SBSection section = module.GetSectionAtIndex(si);
+ if (section.IsValid())
+ {
+ lldb::addr_t baseAddress = section.GetLoadAddress(target);
+ if (baseAddress != LLDB_INVALID_ADDRESS)
+ {
+ return baseAddress - section.GetFileOffset();
+ }
+ }
+ }
+
+ return UINT64_MAX;
+}
+
+//----------------------------------------------------------------------------
+// IDebugSystemObjects
+//----------------------------------------------------------------------------
+
+HRESULT
+LLDBServices::GetCurrentProcessId(
+ PULONG id)
+{
+ if (id == NULL)
+ {
+ return E_INVALIDARG;
+ }
+
+ lldb::SBProcess process = GetCurrentProcess();
+ if (!process.IsValid())
+ {
+ *id = 0;
+ return E_FAIL;
+ }
+
+ *id = process.GetProcessID();
+ return S_OK;
+}
+
+HRESULT
+LLDBServices::GetCurrentThreadId(
+ PULONG id)
+{
+ if (id == NULL)
+ {
+ return E_INVALIDARG;
+ }
+
+ lldb::SBThread thread = GetCurrentThread();
+ if (!thread.IsValid())
+ {
+ *id = 0;
+ return E_FAIL;
+ }
+
+ // This is allow the a valid current TID to be returned to
+ // workaround a bug in lldb on core dumps.
+ if (g_currentThreadIndex != -1)
+ {
+ *id = g_currentThreadIndex;
+ return S_OK;
+ }
+
+ *id = thread.GetIndexID();
+ return S_OK;
+}
+
+HRESULT
+LLDBServices::SetCurrentThreadId(
+ ULONG id)
+{
+ lldb::SBProcess process = GetCurrentProcess();
+ if (!process.IsValid())
+ {
+ return E_FAIL;
+ }
+
+ if (!process.SetSelectedThreadByIndexID(id))
+ {
+ return E_FAIL;
+ }
+
+ return S_OK;
+}
+
+HRESULT
+LLDBServices::GetCurrentThreadSystemId(
+ PULONG sysId)
+{
+ if (sysId == NULL)
+ {
+ return E_INVALIDARG;
+ }
+
+ lldb::SBThread thread = GetCurrentThread();
+ if (!thread.IsValid())
+ {
+ *sysId = 0;
+ return E_FAIL;
+ }
+
+ // This is allow the a valid current TID to be returned to
+ // workaround a bug in lldb on core dumps.
+ if (g_currentThreadSystemId != -1)
+ {
+ *sysId = g_currentThreadSystemId;
+ return S_OK;
+ }
+
+ *sysId = thread.GetThreadID();
+ return S_OK;
+}
+
+HRESULT
+LLDBServices::GetThreadIdBySystemId(
+ ULONG sysId,
+ PULONG threadId)
+{
+ HRESULT hr = E_FAIL;
+ ULONG id = 0;
+
+ lldb::SBProcess process;
+ lldb::SBThread thread;
+
+ if (threadId == NULL)
+ {
+ return E_INVALIDARG;
+ }
+
+ process = GetCurrentProcess();
+ if (!process.IsValid())
+ {
+ goto exit;
+ }
+
+ // If we have a "fake" thread OS (system) id and a fake thread index,
+ // we need to return fake thread index.
+ if (g_currentThreadSystemId == sysId && g_currentThreadIndex != -1)
+ {
+ id = g_currentThreadIndex;
+ }
+ else
+ {
+ thread = process.GetThreadByID(sysId);
+ if (!thread.IsValid())
+ {
+ goto exit;
+ }
+
+ id = thread.GetIndexID();
+ }
+ hr = S_OK;
+
+exit:
+ *threadId = id;
+ return hr;
+}
+
+HRESULT
+LLDBServices::GetThreadContextById(
+ /* in */ ULONG32 threadID,
+ /* in */ ULONG32 contextFlags,
+ /* in */ ULONG32 contextSize,
+ /* out */ PBYTE context)
+{
+ lldb::SBProcess process;
+ lldb::SBThread thread;
+ lldb::SBFrame frame;
+ DT_CONTEXT *dtcontext;
+ HRESULT hr = E_FAIL;
+
+ if (context == NULL || contextSize < sizeof(DT_CONTEXT))
+ {
+ goto exit;
+ }
+ memset(context, 0, contextSize);
+
+ process = GetCurrentProcess();
+ if (!process.IsValid())
+ {
+ goto exit;
+ }
+
+ // If we have a "fake" thread OS (system) id and a fake thread index,
+ // use the fake thread index to get the context.
+ if (g_currentThreadSystemId == threadID && g_currentThreadIndex != -1)
+ {
+ thread = process.GetThreadByIndexID(g_currentThreadIndex);
+ }
+ else
+ {
+ thread = process.GetThreadByID(threadID);
+ }
+
+ if (!thread.IsValid())
+ {
+ goto exit;
+ }
+
+ frame = thread.GetFrameAtIndex(0);
+ if (!frame.IsValid())
+ {
+ goto exit;
+ }
+
+ dtcontext = (DT_CONTEXT*)context;
+ dtcontext->ContextFlags = contextFlags;
+
+ GetContextFromFrame(frame, dtcontext);
+ hr = S_OK;
+
+exit:
+ return hr;
+}
+
+// Internal function
+void
+LLDBServices::GetContextFromFrame(
+ /* const */ lldb::SBFrame& frame,
+ DT_CONTEXT *dtcontext)
+{
+#ifdef DBG_TARGET_AMD64
+ dtcontext->Rip = frame.GetPC();
+ dtcontext->Rsp = frame.GetSP();
+ dtcontext->Rbp = frame.GetFP();
+ dtcontext->EFlags = GetRegister(frame, "rflags");
+
+ dtcontext->Rax = GetRegister(frame, "rax");
+ dtcontext->Rbx = GetRegister(frame, "rbx");
+ dtcontext->Rcx = GetRegister(frame, "rcx");
+ dtcontext->Rdx = GetRegister(frame, "rdx");
+ dtcontext->Rsi = GetRegister(frame, "rsi");
+ dtcontext->Rdi = GetRegister(frame, "rdi");
+ dtcontext->R8 = GetRegister(frame, "r8");
+ dtcontext->R9 = GetRegister(frame, "r9");
+ dtcontext->R10 = GetRegister(frame, "r10");
+ dtcontext->R11 = GetRegister(frame, "r11");
+ dtcontext->R12 = GetRegister(frame, "r12");
+ dtcontext->R13 = GetRegister(frame, "r13");
+ dtcontext->R14 = GetRegister(frame, "r14");
+ dtcontext->R15 = GetRegister(frame, "r15");
+
+ dtcontext->SegCs = GetRegister(frame, "cs");
+ dtcontext->SegSs = GetRegister(frame, "ss");
+ dtcontext->SegDs = GetRegister(frame, "ds");
+ dtcontext->SegEs = GetRegister(frame, "es");
+ dtcontext->SegFs = GetRegister(frame, "fs");
+ dtcontext->SegGs = GetRegister(frame, "gs");
+#elif DBG_TARGET_ARM
+ dtcontext->Pc = frame.GetPC();
+ dtcontext->Sp = frame.GetSP();
+ dtcontext->Lr = GetRegister(frame, "lr");
+ dtcontext->Cpsr = GetRegister(frame, "cpsr");
+
+ dtcontext->R0 = GetRegister(frame, "r0");
+ dtcontext->R1 = GetRegister(frame, "r1");
+ dtcontext->R2 = GetRegister(frame, "r2");
+ dtcontext->R3 = GetRegister(frame, "r3");
+ dtcontext->R4 = GetRegister(frame, "r4");
+ dtcontext->R5 = GetRegister(frame, "r5");
+ dtcontext->R6 = GetRegister(frame, "r6");
+ dtcontext->R7 = GetRegister(frame, "r7");
+ dtcontext->R8 = GetRegister(frame, "r8");
+ dtcontext->R9 = GetRegister(frame, "r9");
+ dtcontext->R10 = GetRegister(frame, "r10");
+ dtcontext->R11 = GetRegister(frame, "r11");
+ dtcontext->R12 = GetRegister(frame, "r12");
+#elif DBG_TARGET_X86
+ dtcontext->Eip = frame.GetPC();
+ dtcontext->Esp = frame.GetSP();
+ dtcontext->Ebp = frame.GetFP();
+ dtcontext->EFlags = GetRegister(frame, "eflags");
+
+ dtcontext->Edi = GetRegister(frame, "edi");
+ dtcontext->Esi = GetRegister(frame, "esi");
+ dtcontext->Ebx = GetRegister(frame, "ebx");
+ dtcontext->Edx = GetRegister(frame, "edx");
+ dtcontext->Ecx = GetRegister(frame, "ecx");
+ dtcontext->Eax = GetRegister(frame, "eax");
+
+ dtcontext->SegCs = GetRegister(frame, "cs");
+ dtcontext->SegSs = GetRegister(frame, "ss");
+ dtcontext->SegDs = GetRegister(frame, "ds");
+ dtcontext->SegEs = GetRegister(frame, "es");
+ dtcontext->SegFs = GetRegister(frame, "fs");
+ dtcontext->SegGs = GetRegister(frame, "gs");
+#endif
+}
+
+// Internal function
+DWORD_PTR
+LLDBServices::GetRegister(
+ /* const */ lldb::SBFrame& frame,
+ const char *name)
+{
+ lldb::SBValue regValue = frame.FindRegister(name);
+
+ lldb::SBError error;
+ DWORD_PTR result = regValue.GetValueAsUnsigned(error);
+
+ return result;
+}
+
+//----------------------------------------------------------------------------
+// IDebugRegisters
+//----------------------------------------------------------------------------
+
+HRESULT
+LLDBServices::GetValueByName(
+ PCSTR name,
+ PDWORD_PTR debugValue)
+{
+ lldb::SBFrame frame = GetCurrentFrame();
+ if (!frame.IsValid())
+ {
+ *debugValue = 0;
+ return E_FAIL;
+ }
+
+ lldb::SBValue value = frame.FindRegister(name);
+ if (!value.IsValid())
+ {
+ *debugValue = 0;
+ return E_FAIL;
+ }
+
+ *debugValue = value.GetValueAsUnsigned();
+ return S_OK;
+}
+
+HRESULT
+LLDBServices::GetInstructionOffset(
+ PULONG64 offset)
+{
+ lldb::SBFrame frame = GetCurrentFrame();
+ if (!frame.IsValid())
+ {
+ *offset = 0;
+ return E_FAIL;
+ }
+
+ *offset = frame.GetPC();
+ return S_OK;
+}
+
+HRESULT
+LLDBServices::GetStackOffset(
+ PULONG64 offset)
+{
+ lldb::SBFrame frame = GetCurrentFrame();
+ if (!frame.IsValid())
+ {
+ *offset = 0;
+ return E_FAIL;
+ }
+
+ *offset = frame.GetSP();
+ return S_OK;
+}
+
+HRESULT
+LLDBServices::GetFrameOffset(
+ PULONG64 offset)
+{
+ lldb::SBFrame frame = GetCurrentFrame();
+ if (!frame.IsValid())
+ {
+ *offset = 0;
+ return E_FAIL;
+ }
+
+ *offset = frame.GetFP();
+ return S_OK;
+}
+
+//----------------------------------------------------------------------------
+// Helper functions
+//----------------------------------------------------------------------------
+
+lldb::SBProcess
+LLDBServices::GetCurrentProcess()
+{
+ lldb::SBProcess process;
+
+ if (m_currentProcess == nullptr)
+ {
+ lldb::SBTarget target = m_debugger.GetSelectedTarget();
+ if (target.IsValid())
+ {
+ process = target.GetProcess();
+ }
+ }
+ else
+ {
+ process = *m_currentProcess;
+ }
+
+ return process;
+}
+
+lldb::SBThread
+LLDBServices::GetCurrentThread()
+{
+ lldb::SBThread thread;
+
+ if (m_currentThread == nullptr)
+ {
+ lldb::SBProcess process = GetCurrentProcess();
+ if (process.IsValid())
+ {
+ thread = process.GetSelectedThread();
+ }
+ }
+ else
+ {
+ thread = *m_currentThread;
+ }
+
+ return thread;
+}
+
+lldb::SBFrame
+LLDBServices::GetCurrentFrame()
+{
+ lldb::SBFrame frame;
+
+ lldb::SBThread thread = GetCurrentThread();
+ if (thread.IsValid())
+ {
+ frame = thread.GetSelectedFrame();
+ }
+
+ return frame;
+}
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#include <cstdarg>
+
+class LLDBServices : public ILLDBServices
+{
+private:
+ LONG m_ref;
+ lldb::SBDebugger &m_debugger;
+ lldb::SBCommandReturnObject &m_returnObject;
+
+ lldb::SBProcess *m_currentProcess;
+ lldb::SBThread *m_currentThread;
+
+ void OutputString(ULONG mask, PCSTR str);
+ ULONG64 GetModuleBase(lldb::SBTarget& target, lldb::SBModule& module);
+ DWORD_PTR GetExpression(lldb::SBFrame& frame, lldb::SBError& error, PCSTR exp);
+ void GetContextFromFrame(lldb::SBFrame& frame, DT_CONTEXT *dtcontext);
+ DWORD_PTR GetRegister(lldb::SBFrame& frame, const char *name);
+
+ lldb::SBProcess GetCurrentProcess();
+ lldb::SBThread GetCurrentThread();
+ lldb::SBFrame GetCurrentFrame();
+
+public:
+ LLDBServices(lldb::SBDebugger &debugger, lldb::SBCommandReturnObject &returnObject, lldb::SBProcess *process = nullptr, lldb::SBThread *thread = nullptr);
+ ~LLDBServices();
+
+ //----------------------------------------------------------------------------
+ // IUnknown
+ //----------------------------------------------------------------------------
+
+ HRESULT STDMETHODCALLTYPE QueryInterface(
+ REFIID InterfaceId,
+ PVOID* Interface);
+
+ ULONG STDMETHODCALLTYPE AddRef();
+
+ ULONG STDMETHODCALLTYPE Release();
+
+ //----------------------------------------------------------------------------
+ // ILLDBServices
+ //----------------------------------------------------------------------------
+
+ PCSTR GetCoreClrDirectory();
+
+ DWORD_PTR GetExpression(
+ PCSTR exp);
+
+ HRESULT VirtualUnwind(
+ DWORD threadID,
+ ULONG32 contextSize,
+ PBYTE context);
+
+ HRESULT SetExceptionCallback(
+ PFN_EXCEPTION_CALLBACK callback);
+
+ HRESULT ClearExceptionCallback();
+
+ //----------------------------------------------------------------------------
+ // IDebugControl2
+ //----------------------------------------------------------------------------
+
+ HRESULT GetInterrupt();
+
+ HRESULT Output(
+ ULONG mask,
+ PCSTR format,
+ ...);
+
+ HRESULT OutputVaList(
+ ULONG mask,
+ PCSTR format,
+ va_list args);
+
+ HRESULT ControlledOutput(
+ ULONG outputControl,
+ ULONG mask,
+ PCSTR format,
+ ...);
+
+ HRESULT ControlledOutputVaList(
+ ULONG outputControl,
+ ULONG mask,
+ PCSTR format,
+ va_list args);
+
+ HRESULT GetDebuggeeType(
+ PULONG debugClass,
+ PULONG qualifier);
+
+ HRESULT GetPageSize(
+ PULONG size);
+
+ HRESULT GetExecutingProcessorType(
+ PULONG type);
+
+ HRESULT Execute(
+ ULONG outputControl,
+ PCSTR command,
+ ULONG flags);
+
+ HRESULT GetLastEventInformation(
+ PULONG type,
+ PULONG processId,
+ PULONG threadId,
+ PVOID extraInformation,
+ ULONG extraInformationSize,
+ PULONG extraInformationUsed,
+ PSTR description,
+ ULONG descriptionSize,
+ PULONG descriptionUsed);
+
+ HRESULT Disassemble(
+ ULONG64 offset,
+ ULONG flags,
+ PSTR buffer,
+ ULONG bufferSize,
+ PULONG disassemblySize,
+ PULONG64 endOffset);
+
+ //----------------------------------------------------------------------------
+ // IDebugControl4
+ //----------------------------------------------------------------------------
+
+ HRESULT
+ GetContextStackTrace(
+ PVOID startContext,
+ ULONG startContextSize,
+ PDEBUG_STACK_FRAME frames,
+ ULONG framesSize,
+ PVOID frameContexts,
+ ULONG frameContextsSize,
+ ULONG frameContextsEntrySize,
+ PULONG framesFilled);
+
+ //----------------------------------------------------------------------------
+ // IDebugDataSpaces
+ //----------------------------------------------------------------------------
+
+ HRESULT ReadVirtual(
+ ULONG64 offset,
+ PVOID buffer,
+ ULONG bufferSize,
+ PULONG bytesRead);
+
+ HRESULT WriteVirtual(
+ ULONG64 offset,
+ PVOID buffer,
+ ULONG bufferSize,
+ PULONG bytesWritten);
+
+ //----------------------------------------------------------------------------
+ // IDebugSymbols
+ //----------------------------------------------------------------------------
+
+ HRESULT GetSymbolOptions(
+ PULONG options);
+
+ HRESULT GetNameByOffset(
+ ULONG64 offset,
+ PSTR nameBuffer,
+ ULONG nameBufferSize,
+ PULONG nameSize,
+ PULONG64 displacement);
+
+ HRESULT GetNumberModules(
+ PULONG loaded,
+ PULONG unloaded);
+
+ HRESULT GetModuleByIndex(
+ ULONG index,
+ PULONG64 base);
+
+ HRESULT GetModuleByModuleName(
+ PCSTR name,
+ ULONG startIndex,
+ PULONG index,
+ PULONG64 base);
+
+ HRESULT GetModuleByOffset(
+ ULONG64 offset,
+ ULONG startIndex,
+ PULONG index,
+ PULONG64 base);
+
+ HRESULT GetModuleNames(
+ ULONG index,
+ ULONG64 base,
+ PSTR imageNameBuffer,
+ ULONG imageNameBufferSize,
+ PULONG imageNameSize,
+ PSTR moduleNameBuffer,
+ ULONG moduleNameBufferSize,
+ PULONG moduleNameSize,
+ PSTR loadedImageNameBuffer,
+ ULONG loadedImageNameBufferSize,
+ PULONG loadedImageNameSize);
+
+ HRESULT GetLineByOffset(
+ ULONG64 offset,
+ PULONG line,
+ PSTR fileBuffer,
+ ULONG fileBufferSize,
+ PULONG fileSize,
+ PULONG64 displacement);
+
+ HRESULT GetSourceFileLineOffsets(
+ PCSTR file,
+ PULONG64 buffer,
+ ULONG bufferLines,
+ PULONG fileLines);
+
+ HRESULT FindSourceFile(
+ ULONG startElement,
+ PCSTR file,
+ ULONG flags,
+ PULONG foundElement,
+ PSTR buffer,
+ ULONG bufferSize,
+ PULONG foundSize);
+
+ //----------------------------------------------------------------------------
+ // IDebugSystemObjects
+ //----------------------------------------------------------------------------
+
+ HRESULT GetCurrentProcessId(
+ PULONG id);
+
+ HRESULT GetCurrentThreadId(
+ PULONG id);
+
+ HRESULT SetCurrentThreadId(
+ ULONG id);
+
+ HRESULT GetCurrentThreadSystemId(
+ PULONG sysId);
+
+ HRESULT GetThreadIdBySystemId(
+ ULONG sysId,
+ PULONG threadId);
+
+ HRESULT GetThreadContextById(
+ ULONG32 threadID,
+ ULONG32 contextFlags,
+ ULONG32 contextSize,
+ PBYTE context);
+
+ //----------------------------------------------------------------------------
+ // IDebugRegisters
+ //----------------------------------------------------------------------------
+
+ HRESULT GetValueByName(
+ PCSTR name,
+ PDWORD_PTR debugValue);
+
+ HRESULT GetInstructionOffset(
+ PULONG64 offset);
+
+ HRESULT GetStackOffset(
+ PULONG64 offset);
+
+ HRESULT GetFrameOffset(
+ PULONG64 offset);
+
+ //----------------------------------------------------------------------------
+ // LLDBServices (internal)
+ //----------------------------------------------------------------------------
+
+ PCSTR GetModuleDirectory(
+ PCSTR name);
+};
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#include "sosplugin.h"
+#include <dlfcn.h>
+#include <string.h>
+#include <string>
+#include <stdlib.h>
+#include <limits.h>
+
+class setclrpathCommand : public lldb::SBCommandPluginInterface
+{
+public:
+ setclrpathCommand()
+ {
+ }
+
+ virtual bool
+ DoExecute (lldb::SBDebugger debugger,
+ char** arguments,
+ lldb::SBCommandReturnObject &result)
+ {
+ if (arguments[0] == NULL)
+ {
+ result.Printf("Load path for sos/dac/dbi: '%s'\n", g_coreclrDirectory == NULL ? "<none>" : g_coreclrDirectory);
+ }
+ else {
+ if (g_coreclrDirectory != NULL)
+ {
+ free(g_coreclrDirectory);
+ }
+
+ std::string path(arguments[0]);
+ if (path[path.length() - 1] != '/')
+ {
+ path.append("/");
+ }
+
+ g_coreclrDirectory = strdup(path.c_str());
+ result.Printf("Set load path for sos/dac/dbi to '%s'\n", g_coreclrDirectory);
+ }
+ return result.Succeeded();
+ }
+};
+
+bool
+setclrpathCommandInitialize(lldb::SBDebugger debugger)
+{
+ lldb::SBCommandInterpreter interpreter = debugger.GetCommandInterpreter();
+ lldb::SBCommand command = interpreter.AddCommand("setclrpath", new setclrpathCommand(), "Set the path to load coreclr sos/dac/dbi files. setclrpath <path>");
+ return true;
+}
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#include "sosplugin.h"
+#include <dlfcn.h>
+#include <string.h>
+#include <string>
+#include <stdlib.h>
+#include <limits.h>
+
+class setsostidCommand : public lldb::SBCommandPluginInterface
+{
+public:
+ setsostidCommand()
+ {
+ }
+
+ virtual bool
+ DoExecute(lldb::SBDebugger debugger,
+ char** arguments,
+ lldb::SBCommandReturnObject &result)
+ {
+ if (arguments[0] == NULL)
+ {
+ if (g_currentThreadSystemId == -1 || g_currentThreadIndex == -1)
+ {
+ result.Printf("sos OS tid not mapped\n");
+ }
+ else {
+ result.Printf("sos OS tid 0x%x mapped to lldb thread index %d\n",
+ g_currentThreadSystemId, g_currentThreadIndex);
+ }
+ }
+ else if (strcmp(arguments[0], "-clear") == 0) {
+ g_currentThreadIndex = -1;
+ g_currentThreadSystemId = -1;
+ result.Printf("Cleared sos OS tid/index\n");
+ }
+ else if (arguments[1] == NULL)
+ {
+ result.Printf("Need thread index parameter that maps to the OS tid\n");
+ }
+ else
+ {
+ ULONG tid = strtoul(arguments[0], NULL, 16);
+ g_currentThreadSystemId = tid;
+
+ ULONG index = strtoul(arguments[1], NULL, 16);
+ g_currentThreadIndex = index;
+
+ result.Printf("Mapped sos OS tid 0x%x to lldb thread index %d\n", tid, index);
+ }
+ return result.Succeeded();
+ }
+};
+
+bool
+setsostidCommandInitialize(lldb::SBDebugger debugger)
+{
+ lldb::SBCommandInterpreter interpreter = debugger.GetCommandInterpreter();
+ lldb::SBCommand command = interpreter.AddCommand("setsostid", new setsostidCommand(), "Set the current os tid/thread index instead of using the one lldb provides. setsostid <tid> <index>");
+ return true;
+}
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#include "sosplugin.h"
+#include <dlfcn.h>
+#include <string.h>
+#include <string>
+
+class sosCommand : public lldb::SBCommandPluginInterface
+{
+ const char *m_command;
+ void *m_sosHandle;
+
+public:
+ sosCommand(const char *command)
+ {
+ m_command = command;
+ m_sosHandle = NULL;
+ }
+
+ virtual bool
+ DoExecute (lldb::SBDebugger debugger,
+ char** arguments,
+ lldb::SBCommandReturnObject &result)
+ {
+ LLDBServices* services = new LLDBServices(debugger, result);
+ LoadSos(services);
+
+ if (m_sosHandle)
+ {
+ const char* sosCommand = m_command;
+ if (sosCommand == NULL)
+ {
+ if (arguments == NULL || *arguments == NULL) {
+ sosCommand = "Help";
+ }
+ else
+ {
+ sosCommand = *arguments++;
+ }
+ }
+ CommandFunc commandFunc = (CommandFunc)dlsym(m_sosHandle, sosCommand);
+ if (commandFunc)
+ {
+ std::string str;
+ if (arguments != NULL)
+ {
+ for (const char* arg = *arguments; arg; arg = *(++arguments))
+ {
+ str.append(arg);
+ str.append(" ");
+ }
+ }
+ const char* sosArgs = str.c_str();
+ HRESULT hr = commandFunc(services, sosArgs);
+ if (hr != S_OK)
+ {
+ services->Output(DEBUG_OUTPUT_ERROR, "%s %s failed\n", sosCommand, sosArgs);
+ }
+ }
+ else
+ {
+ services->Output(DEBUG_OUTPUT_ERROR, "SOS command '%s' not found %s\n", sosCommand, dlerror());
+ }
+ }
+
+ services->Release();
+ return result.Succeeded();
+ }
+
+ void
+ LoadSos(LLDBServices *services)
+ {
+ if (m_sosHandle == NULL)
+ {
+ if (g_coreclrDirectory == NULL)
+ {
+ const char *coreclrModule = MAKEDLLNAME_A("coreclr");
+ const char *directory = services->GetModuleDirectory(coreclrModule);
+ if (directory != NULL)
+ {
+ std::string path(directory);
+ path.append("/");
+ g_coreclrDirectory = strdup(path.c_str());
+ }
+ else
+ {
+ services->Output(DEBUG_OUTPUT_WARNING, "The %s module is not loaded yet in the target process\n", coreclrModule);
+ }
+ }
+
+ if (g_coreclrDirectory != NULL)
+ {
+ // Load the DAC module first explicitly because SOS and DBI
+ // have implicit references to the DAC's PAL.
+ LoadModule(services, MAKEDLLNAME_A("mscordaccore"));
+
+ m_sosHandle = LoadModule(services, MAKEDLLNAME_A("sos"));
+ }
+ }
+ }
+
+ void *
+ LoadModule(LLDBServices *services, const char *moduleName)
+ {
+ std::string modulePath(g_coreclrDirectory);
+ modulePath.append(moduleName);
+
+ void *moduleHandle = dlopen(modulePath.c_str(), RTLD_NOW);
+ if (moduleHandle == NULL)
+ {
+ services->Output(DEBUG_OUTPUT_ERROR, "dlopen(%s) failed %s\n", modulePath.c_str(), dlerror());
+ }
+
+ return moduleHandle;
+ }
+};
+
+bool
+sosCommandInitialize(lldb::SBDebugger debugger)
+{
+ lldb::SBCommandInterpreter interpreter = debugger.GetCommandInterpreter();
+ interpreter.AddCommand("sos", new sosCommand(NULL), "Various coreclr debugging commands. See 'soshelp' for more details. sos <command-name> <args>");
+ interpreter.AddCommand("bpmd", new sosCommand("bpmd"), "Creates a breakpoint at the specified managed method in the specified module.");
+ interpreter.AddCommand("clrstack", new sosCommand("ClrStack"), "Provides a stack trace of managed code only.");
+ interpreter.AddCommand("clrthreads", new sosCommand("Threads"), "List the managed threads running.");
+ interpreter.AddCommand("createdump", new sosCommand("CreateDump"), "Create a xplat minidump.");
+ interpreter.AddCommand("clru", new sosCommand("u"), "Displays an annotated disassembly of a managed method.");
+ interpreter.AddCommand("dumpclass", new sosCommand("DumpClass"), "Displays information about a EE class structure at the specified address.");
+ interpreter.AddCommand("dumpheap", new sosCommand("DumpHeap"), "Displays info about the garbage-collected heap and collection statistics about objects.");
+ interpreter.AddCommand("dumpil", new sosCommand("DumpIL"), "Displays the Microsoft intermediate language (MSIL) that is associated with a managed method.");
+ interpreter.AddCommand("dumplog", new sosCommand("DumpLog"), "Writes the contents of an in-memory stress log to the specified file.");
+ interpreter.AddCommand("dumpmd", new sosCommand("DumpMD"), "Displays information about a MethodDesc structure at the specified address.");
+ interpreter.AddCommand("dumpmodule", new sosCommand("DumpModule"), "Displays information about a EE module structure at the specified address.");
+ interpreter.AddCommand("dumpmt", new sosCommand("DumpMT"), "Displays information about a method table at the specified address.");
+ interpreter.AddCommand("dumpobj", new sosCommand("DumpObj"), "Displays info about an object at the specified address.");
+ interpreter.AddCommand("dumpstack", new sosCommand("DumpStack"), "Displays a native and managed stack trace.");
+ interpreter.AddCommand("dso", new sosCommand("DumpStackObjects"), "Displays all managed objects found within the bounds of the current stack.");
+ interpreter.AddCommand("eeheap", new sosCommand("EEHeap"), "Displays info about process memory consumed by internal runtime data structures.");
+ interpreter.AddCommand("eestack", new sosCommand("EEStack"), "Runs dumpstack on all threads in the process.");
+ interpreter.AddCommand("gcroot", new sosCommand("GCRoot"), "Displays info about references (or roots) to an object at the specified address.");
+ interpreter.AddCommand("ip2md", new sosCommand("IP2MD"), "Displays the MethodDesc structure at the specified address in code that has been JIT-compiled.");
+ interpreter.AddCommand("name2ee", new sosCommand("Name2EE"), "Displays the MethodTable structure and EEClass structure for the specified type or method in the specified module.");
+ interpreter.AddCommand("pe", new sosCommand("PrintException"), "Displays and formats fields of any object derived from the Exception class at the specified address.");
+ interpreter.AddCommand("histclear", new sosCommand("HistClear"), "Releases any resources used by the family of Hist commands.");
+ interpreter.AddCommand("histinit", new sosCommand("HistInit"), "Initializes the SOS structures from the stress log saved in the debuggee.");
+ interpreter.AddCommand("histobj", new sosCommand("HistObj"), "Examines all stress log relocation records and displays the chain of garbage collection relocations that may have led to the address passed in as an argument.");
+ interpreter.AddCommand("histobjfind", new sosCommand("HistObjFind"), "Displays all the log entries that reference an object at the specified address.");
+ interpreter.AddCommand("histroot", new sosCommand("HistRoot"), "Displays information related to both promotions and relocations of the specified root.");
+ interpreter.AddCommand("soshelp", new sosCommand("Help"), "Displays all available commands when no parameter is specified, or displays detailed help information about the specified command. soshelp <command>");
+ return true;
+}
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#include "sosplugin.h"
+
+namespace lldb {
+ bool PluginInitialize (lldb::SBDebugger debugger);
+}
+
+bool
+lldb::PluginInitialize (lldb::SBDebugger debugger)
+{
+ sosCommandInitialize(debugger);
+ setclrpathCommandInitialize(debugger);
+ setsostidCommandInitialize(debugger);
+ return true;
+}
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#include <lldb/API/LLDB.h>
+#define DEFINE_EXCEPTION_RECORD
+#include <pal.h>
+#include <lldbservices.h>
+#include <dbgtargetcontext.h>
+#include "services.h"
+
+typedef HRESULT (*CommandFunc)(ILLDBServices* services, const char *args);
+
+extern char *g_coreclrDirectory;
+extern ULONG g_currentThreadIndex;
+extern ULONG g_currentThreadSystemId;
+
+bool
+sosCommandInitialize(lldb::SBDebugger debugger);
+
+bool
+setsostidCommandInitialize(lldb::SBDebugger debugger);
+
+bool
+setclrpathCommandInitialize(lldb::SBDebugger debugger);
--- /dev/null
+Testing libsosplugin
+=====================================
+
+**Test assembly**
+Compile test assembly file using any C# compiler you have, for example:
+- `gmcs test.cs`
+- `corerun csc.exe /nologo /r:System.Private.CoreLib.dll test.cs`
+
+
+**Running tests**
+Make sure that python's lldb module is accessible. To run the tests, use the following command:
+`python2 test_libsosplugin.py --corerun=corerun --sosplugin=sosplugin --assembly=assembly --timeout=timeout`
+- `lldb` is a path to `lldb` to run
+- `clrdir` is a directory with `corerun` and sosplugin
+- `assembly` is a compiled test assembly (e.g. Test.exe)
+- `timeout` is a deadline for a single test (in seconds)
+- `regex` is a regular expression matching tests to run
+- `repeat` is a number of passes for each test
+
+
+
+Log files for both failed and passed tests are `*.log` and `*.log.2` for standard output and error correspondingly.
+
+
+**Writing tests**
+Tests start with the `TestSosCommands` class defined in `test_libsosplugin.py`. To add a test to the suite, start with implementing a new method inside this class whose name begins with `test_`. Most new commands will require only one line of code in this method: `self.do_test("scenarioname")`. This command will launch a new `lldb` instance, which in turn will call the `runScenario` method from `scenarioname` module. `scenarioname` is the name of the python module that will be running the scenario inside `lldb` (found in `tests` folder alongside with `test_libsosplugin.py` and named `scenarioname.py`).
+An example of a scenario looks like this:
+
+ import lldb
+ def runScenario(assemblyName, debugger, target):
+ process = target.GetProcess()
+
+ # do some work
+
+ process.Continue()
+ return True
+
+ `runScenario` method does all the work related to running the scenario: setting breakpoints, running SOS commands and examining their output. It should return a boolean value indicating a success or a failure.
+***Note:*** `testutils.py` defines some useful commands that can be reused in many scenarios.
+
+
+**Useful links**
+[Python scripting in LLDB](http://lldb.llvm.org/python-reference.html)
+[Python unittest framework](https://docs.python.org/2.7/library/unittest.html)
--- /dev/null
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+import lldb
+import re
+import testutils as test
+
+# bpmd -clearall
+
+
+def runScenario(assembly, debugger, target):
+ process = target.GetProcess()
+ res = lldb.SBCommandReturnObject()
+ ci = debugger.GetCommandInterpreter()
+
+ # Run debugger, wait until libcoreclr is loaded,
+ # set breakpoint at Test.Main and stop there
+ test.stop_in_main(debugger, assembly)
+
+ # Set breakpoint
+
+ ci.HandleCommand("bpmd " + assembly + " Test.UnlikelyInlined", res)
+ out_msg = res.GetOutput()
+ err_msg = res.GetError()
+ print(out_msg)
+ print(err_msg)
+ # Interpreter must have this command and able to run it
+ test.assertTrue(res.Succeeded())
+
+ # Output is not empty
+ # Should be at least 'Adding pending breakpoints...'
+ test.assertTrue(len(out_msg) > 0)
+
+ # Error message is empty
+ test.assertTrue(len(err_msg) == 0)
+
+ # Delete the first breakpoint
+
+ ci.HandleCommand("bpmd -clear 1", res)
+ out_msg = res.GetOutput()
+ err_msg = res.GetError()
+ print(out_msg)
+ print(err_msg)
+ # Interpreter must have this command and able to run it
+ test.assertTrue(res.Succeeded())
+
+ match = re.search('Cleared', out_msg)
+ # Check for specific output
+ test.assertTrue(match)
+
+ # Error message is empty
+ test.assertEqual(err_msg, '')
+
+ process.Continue()
+ # Process must be exited
+ test.assertEqual(process.GetState(), lldb.eStateExited)
+
+ # The reason of this stop must be a breakpoint
+ test.assertEqual(process.GetSelectedThread().GetStopReason(),
+ lldb.eStopReasonNone)
+
+ #
+
+ # Delete all breakpoints, continue current process and checks its exit code
+ test.exit_lldb(debugger, assembly)
--- /dev/null
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+import lldb
+import re
+import testutils as test
+
+# bpmd -clearall
+
+
+def runScenario(assembly, debugger, target):
+ process = target.GetProcess()
+ res = lldb.SBCommandReturnObject()
+ ci = debugger.GetCommandInterpreter()
+
+ # Run debugger, wait until libcoreclr is loaded,
+ # set breakpoint at Test.Main and stop there
+ test.stop_in_main(debugger, assembly)
+
+ # Set breakpoint
+
+ ci.HandleCommand("bpmd " + assembly + " Test.UnlikelyInlined", res)
+ out_msg = res.GetOutput()
+ err_msg = res.GetError()
+ print(out_msg)
+ print(err_msg)
+ # Interpreter must have this command and able to run it
+ test.assertTrue(res.Succeeded())
+
+ # Output is not empty
+ # Should be at least 'Adding pending breakpoints...'
+ test.assertTrue(res.GetOutputSize() > 0)
+
+ # Error message is empty
+ test.assertTrue(res.GetErrorSize() == 0)
+
+ # Delete all breakpoints
+
+ ci.HandleCommand("bpmd -clearall", res)
+ out_msg = res.GetOutput()
+ err_msg = res.GetError()
+ print(out_msg)
+ print(err_msg)
+ # Interpreter must have this command and able to run it
+ test.assertTrue(res.Succeeded())
+
+ match = re.search('All pending breakpoints cleared.', out_msg)
+ # Check for specific output
+ test.assertTrue(match)
+
+ # Error message is empty
+ test.assertTrue(res.GetErrorSize() == 0)
+
+ process.Continue()
+ # Process must be exited
+ test.assertEqual(process.GetState(), lldb.eStateExited)
+
+ # The reason of this stop must be a breakpoint
+ test.assertEqual(process.GetSelectedThread().GetStopReason(),
+ lldb.eStopReasonNone)
+
+ #
+
+ # Delete all breakpoints, continue current process and checks its exit code
+ test.exit_lldb(debugger, assembly)
--- /dev/null
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+import lldb
+import re
+import testutils as test
+
+# bpmd -md <MethodDesc pointer>
+
+
+def runScenario(assembly, debugger, target):
+ process = target.GetProcess()
+ res = lldb.SBCommandReturnObject()
+ ci = debugger.GetCommandInterpreter()
+
+ # Run debugger, wait until libcoreclr is loaded,
+ # set breakpoint at Test.Main and stop there
+ test.stop_in_main(debugger, assembly)
+
+ md_addr = test.get_methoddesc(debugger, assembly, "Test.UnlikelyInlined")
+
+ ci.HandleCommand("bpmd -md %s" % md_addr, res)
+ out_msg = res.GetOutput()
+ err_msg = res.GetError()
+ print(out_msg)
+ print(err_msg)
+ # Interpreter must have this command and able to run it
+ test.assertTrue(res.Succeeded())
+
+ # Output is not empty
+ # Should be at least 'Adding pending breakpoints...'
+ test.assertTrue(res.GetOutputSize() > 0)
+
+ # Error message is empty
+ test.assertTrue(res.GetErrorSize() == 0)
+
+ process.Continue()
+ # Process must be stopped at UnlinkelyInlined
+ test.assertEqual(process.GetState(), lldb.eStateStopped)
+
+ # The reason of this stop must be a breakpoint
+ test.assertEqual(process.GetSelectedThread().GetStopReason(),
+ lldb.eStopReasonBreakpoint)
+
+ #
+
+ # Continue current process and checks its exit code
+ test.exit_lldb(debugger, assembly)
--- /dev/null
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+import lldb
+import re
+import testutils as test
+
+# bpmd <module name> <managed function name>
+
+
+def runScenario(assembly, debugger, target):
+ process = target.GetProcess()
+ res = lldb.SBCommandReturnObject()
+ ci = debugger.GetCommandInterpreter()
+
+ # Run debugger, wait until libcoreclr is loaded,
+ # set breakpoint at Test.Main and stop there
+ test.stop_in_main(debugger, assembly)
+
+ ci.HandleCommand("bpmd " + assembly + " Test.UnlikelyInlined", res)
+ out_msg = res.GetOutput()
+ err_msg = res.GetError()
+ print(out_msg)
+ print(err_msg)
+ # Interpreter must have this command and able to run it
+ test.assertTrue(res.Succeeded())
+
+ # Output is not empty
+ # Should be at least 'Adding pending breakpoints...'
+ test.assertTrue(res.GetOutputSize() > 0)
+
+ # Error message is empty
+ test.assertTrue(res.GetErrorSize() == 0)
+
+ process.Continue()
+ # Process must be stopped at UnlinkelyInlined
+ test.assertEqual(process.GetState(), lldb.eStateStopped)
+
+ # The reason of this stop must be a breakpoint
+ test.assertEqual(process.GetSelectedThread().GetStopReason(),
+ lldb.eStopReasonBreakpoint)
+
+ #
+
+ # Delete all breakpoints, continue current process and checks its exit code
+ test.exit_lldb(debugger, assembly)
--- /dev/null
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+import lldb
+import re
+import testutils as test
+
+# bpmd <module name> <managed function name> [<il offset>]
+
+
+def runScenario(assembly, debugger, target):
+ process = target.GetProcess()
+ res = lldb.SBCommandReturnObject()
+ ci = debugger.GetCommandInterpreter()
+
+ # Run debugger, wait until libcoreclr is loaded,
+ # set breakpoint at Test.Main and stop there
+ test.stop_in_main(debugger, assembly)
+
+ ci.HandleCommand("bpmd " + assembly + " Test.UnlikelyInlined 66", res)
+ out_msg = res.GetOutput()
+ err_msg = res.GetError()
+ print(out_msg)
+ print(err_msg)
+ # Interpreter must have this command and able to run it
+ test.assertTrue(res.Succeeded())
+
+ # Output is not empty
+ # Should be at least 'Adding pending breakpoints...'
+ test.assertTrue(res.GetOutputSize() > 0)
+
+ # Error message is empty
+ test.assertTrue(res.GetErrorSize() == 0)
+
+ process.Continue()
+ # Process must be stopped at UnlinkelyInlined
+ test.assertEqual(process.GetState(), lldb.eStateStopped)
+
+ # The reason of this stop must be a breakpoint
+ test.assertEqual(process.GetSelectedThread().GetStopReason(),
+ lldb.eStopReasonBreakpoint)
+
+ #
+
+ # Delete all breakpoints, continue current process and checks its exit code
+ test.exit_lldb(debugger, assembly)
--- /dev/null
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+import lldb
+import re
+import testutils as test
+
+# bpmd -nofuturemodule <module name> <managed function name>
+
+
+def runScenario(assembly, debugger, target):
+ process = target.GetProcess()
+ res = lldb.SBCommandReturnObject()
+ ci = debugger.GetCommandInterpreter()
+
+ # Process must be stopped here while libcoreclr loading.
+ # This test usually fails on release version of coreclr
+ # since we depend on 'LoadLibraryExW' symbol present.
+ test.assertEqual(process.GetState(), lldb.eStateStopped)
+
+ # The reason of this stop must be a breakpoint
+ test.assertEqual(process.GetSelectedThread().GetStopReason(),
+ lldb.eStopReasonBreakpoint)
+
+ ci.HandleCommand("bpmd -nofuturemodule " + assembly + " Test.Main", res)
+ out_msg = res.GetOutput()
+ err_msg = res.GetError()
+ print(out_msg)
+ print(err_msg)
+ # Interpreter must have this command and able to run it
+ test.assertTrue(res.Succeeded())
+
+ # Output is empty
+ test.assertTrue(res.GetOutputSize() == 0)
+
+ # Error message is empty
+ test.assertTrue(res.GetErrorSize() == 0)
+
+ process.Continue()
+ # Process must be exited because of -nofuturemodule flag
+ test.assertEqual(process.GetState(), lldb.eStateExited)
+
+ # The reason of this stop must be a breakpoint
+ test.assertEqual(process.GetSelectedThread().GetStopReason(),
+ lldb.eStopReasonNone)
+
+ #
+
+ # Delete all breakpoints, continue current process and checks its exit code
+ test.exit_lldb(debugger, assembly)
--- /dev/null
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+import lldb
+import re
+import testutils as test
+
+
+def runScenario(assembly, debugger, target):
+ process = target.GetProcess()
+ res = lldb.SBCommandReturnObject()
+ ci = debugger.GetCommandInterpreter()
+
+ # Run debugger, wait until libcoreclr is loaded,
+ # set breakpoint at Test.Main and stop there
+ test.stop_in_main(debugger, assembly)
+
+ ci.HandleCommand("clrstack", res)
+ print(res.GetOutput())
+ print(res.GetError())
+ # Interpreter must have this command and able to run it
+ test.assertTrue(res.Succeeded())
+
+ output = res.GetOutput()
+ # Output is not empty
+ test.assertTrue(res.GetOutputSize() > 0)
+
+ match = re.search('OS Thread Id', output)
+ # Specific string must be in the output
+ test.assertTrue(match)
+
+ match = re.search('Failed to start', output)
+ # Check if a fail was reported
+ test.assertFalse(match)
+
+ # TODO: test other use cases
+
+ # Continue current process and checks its exit code
+ test.exit_lldb(debugger, assembly)
--- /dev/null
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+import lldb
+import re
+import testutils as test
+
+
+def runScenario(assembly, debugger, target):
+ process = target.GetProcess()
+ res = lldb.SBCommandReturnObject()
+ ci = debugger.GetCommandInterpreter()
+
+ # Run debugger, wait until libcoreclr is loaded,
+ # set breakpoint at Test.Main and stop there
+ test.stop_in_main(debugger, assembly)
+
+ ci.HandleCommand("clrthreads", res)
+ print(res.GetOutput())
+ print(res.GetError())
+ # Interpreter must have this command and able to run it
+ test.assertTrue(res.Succeeded())
+
+ output = res.GetOutput()
+ # Output is not empty
+ test.assertTrue(len(output) > 0)
+
+ # Specific string must be in the output
+ test.assertNotEqual(output.find("ThreadCount:"), -1)
+
+ # TODO: test other use cases
+
+ # Continue current process and checks its exit code
+ test.exit_lldb(debugger, assembly)
--- /dev/null
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+import lldb
+import re
+import testutils as test
+
+
+def runScenario(assembly, debugger, target):
+ process = target.GetProcess()
+ res = lldb.SBCommandReturnObject()
+ ci = debugger.GetCommandInterpreter()
+
+ # Run debugger, wait until libcoreclr is loaded,
+ # set breakpoint at Test.Main and stop there
+ test.stop_in_main(debugger, assembly)
+
+ ci.HandleCommand("name2ee " + assembly + " Test.Main", res)
+ print(res.GetOutput())
+ print(res.GetError())
+ # Interpreter must have this command and able to run it
+ test.assertTrue(res.Succeeded())
+
+ output = res.GetOutput()
+ # Output is not empty
+ test.assertTrue(len(output) > 0)
+
+ match = re.search('JITTED Code Address:\s+([0-9a-fA-F]+)', output)
+ # Line matched
+ test.assertTrue(match)
+
+ groups = match.groups()
+ # Match has a single subgroup
+ test.assertEqual(len(groups), 1)
+
+ jit_addr = groups[0]
+ # Address must be a hex number
+ test.assertTrue(test.is_hexnum(jit_addr))
+
+ ci.HandleCommand("clru " + jit_addr, res)
+ print(res.GetOutput())
+ print(res.GetError())
+ # Interpreter must have this command and able to run it
+ test.assertTrue(res.Succeeded())
+
+ # TODO: test other use cases
+
+ # Continue current process and checks its exit code
+ test.exit_lldb(debugger, assembly)
--- /dev/null
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+import lldb
+import re
+import testutils as test
+
+
+def runScenario(assembly, debugger, target):
+ process = target.GetProcess()
+ res = lldb.SBCommandReturnObject()
+ ci = debugger.GetCommandInterpreter()
+
+ # Run debugger, wait until libcoreclr is loaded,
+ # set breakpoint at Test.Main and stop there
+ test.stop_in_main(debugger, assembly)
+
+ ci.HandleCommand("dso", res)
+ print(res.GetOutput())
+ print(res.GetError())
+ # Interpreter must have this command and able to run it
+ test.assertTrue(res.Succeeded())
+
+ output = res.GetOutput()
+ # Output is not empty
+ test.assertTrue(len(output) > 0)
+
+ # Specific string must be in the output
+ test.assertNotEqual(output.find("SP/REG"), -1)
+
+ # TODO: test other use cases
+
+ # Continue current process and checks its exit code
+ test.exit_lldb(debugger, assembly)
--- /dev/null
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+import lldb
+import re
+import testutils as test
+
+
+def runScenario(assembly, debugger, target):
+ process = target.GetProcess()
+ res = lldb.SBCommandReturnObject()
+ ci = debugger.GetCommandInterpreter()
+
+ # Run debugger, wait until libcoreclr is loaded,
+ # set breakpoint at Test.Main and stop there
+ test.stop_in_main(debugger, assembly)
+
+ ci.HandleCommand("name2ee " + assembly + " Test.Main", res)
+ print(res.GetOutput())
+ print(res.GetError())
+ # Interpreter must have this command and able to run it
+ test.assertTrue(res.Succeeded())
+
+ output = res.GetOutput()
+ # Output is not empty
+ test.assertTrue(len(output) > 0)
+
+ match = re.search('MethodDesc:\s+([0-9a-fA-F]+)', output)
+ # Line matched
+ test.assertTrue(match)
+
+ groups = match.groups()
+ # Match has a single subgroup
+ test.assertEqual(len(groups), 1)
+
+ md_addr = groups[0]
+ # Address must be a hex number
+ test.assertTrue(test.is_hexnum(md_addr))
+
+ ci.HandleCommand("dumpmd " + md_addr, res)
+ print(res.GetOutput())
+ print(res.GetError())
+ # Interpreter must have this command and able to run it
+ test.assertTrue(res.Succeeded())
+
+ output = res.GetOutput()
+ # Output is not empty
+ test.assertTrue(len(output) > 0)
+
+ match = re.search('Class:\s+([0-9a-fA-F]+)', output)
+ # Line matched
+ test.assertTrue(match)
+
+ groups = match.groups()
+ # Match has a single subgroup
+ test.assertEqual(len(groups), 1)
+
+ class_addr = groups[0]
+ # Address must be a hex number
+ test.assertTrue(test.is_hexnum(class_addr))
+
+ ci.HandleCommand("dumpmd " + class_addr, res)
+ print(res.GetOutput())
+ print(res.GetError())
+ # Interpreter must have this command and able to run it
+ test.assertTrue(res.Succeeded())
+
+ # TODO: test other use cases
+
+ # Continue current process and checks its exit code
+ test.exit_lldb(debugger, assembly)
--- /dev/null
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+import lldb
+import re
+import testutils as test
+
+
+def runScenario(assembly, debugger, target):
+ process = target.GetProcess()
+ res = lldb.SBCommandReturnObject()
+ ci = debugger.GetCommandInterpreter()
+
+ # Run debugger, wait until libcoreclr is loaded,
+ # set breakpoint at Test.Main and stop there
+ test.stop_in_main(debugger, assembly)
+
+ ci.HandleCommand("dumpheap", res)
+ print(res.GetOutput())
+ print(res.GetError())
+ # Interpreter must have this command and able to run it
+ test.assertTrue(res.Succeeded())
+
+ output = res.GetOutput()
+ # Output is not empty
+ test.assertTrue(len(output) > 0)
+
+ # Specific string must be in the output
+ test.assertNotEqual(output.find("Address"), -1)
+
+ # TODO: test other use cases
+
+ # Continue current process and checks its exit code
+ test.exit_lldb(debugger, assembly)
--- /dev/null
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+import lldb
+import re
+import testutils as test
+
+
+def runScenario(assembly, debugger, target):
+ process = target.GetProcess()
+ res = lldb.SBCommandReturnObject()
+ ci = debugger.GetCommandInterpreter()
+
+ # Run debugger, wait until libcoreclr is loaded,
+ # set breakpoint at Test.Main and stop there
+ test.stop_in_main(debugger, assembly)
+
+ md_addr = test.get_methoddesc(debugger, assembly, "Test.DumpIL")
+
+ ci.HandleCommand("dumpil " + md_addr, res)
+ print(res.GetOutput())
+ print(res.GetError())
+ # Interpreter must have this command and able to run it
+ test.assertTrue(res.Succeeded())
+
+ insts = res.GetOutput()
+ print(insts)
+ # Function must have some instructions
+ test.assertTrue(len(insts) > 0)
+
+ match = re.search(r'IL_\w{4}:\sldstr.*test\sdumpil.*' +
+ r'IL_\w{4}:\scall.*System\.Console::WriteLine.*' +
+ r'IL_\w{4}:\sret',
+ insts.replace('\n', ' '))
+ # Must have ldstr, call and ret instructions
+ test.assertTrue(match)
+
+ # TODO: test other use cases
+
+ # Continue current process and checks its exit code
+ test.exit_lldb(debugger, assembly)
--- /dev/null
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+import lldb
+import re
+import testutils as test
+
+
+def runScenario(assembly, debugger, target):
+ process = target.GetProcess()
+ res = lldb.SBCommandReturnObject()
+ ci = debugger.GetCommandInterpreter()
+
+ # Run debugger, wait until libcoreclr is loaded,
+ # set breakpoint at Test.Main and stop there
+ test.stop_in_main(debugger, assembly)
+
+ ci.HandleCommand("dumplog", res)
+ print(res.GetOutput())
+ print(res.GetError())
+ # Interpreter must have this command and able to run it
+ test.assertTrue(res.Succeeded())
+
+ output = res.GetOutput()
+ # Output is not empty
+ test.assertTrue(len(output) > 0)
+
+ # Specific string must be in the output
+ test.assertNotEqual(output.find(" dump "), -1)
+
+ # TODO: test other use cases
+
+ # Continue current process and checks its exit code
+ test.exit_lldb(debugger, assembly)
--- /dev/null
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+import lldb
+import re
+import testutils as test
+
+
+def runScenario(assembly, debugger, target):
+ process = target.GetProcess()
+ res = lldb.SBCommandReturnObject()
+ ci = debugger.GetCommandInterpreter()
+
+ # Run debugger, wait until libcoreclr is loaded,
+ # set breakpoint at Test.Main and stop there
+ test.stop_in_main(debugger, assembly)
+
+ ci.HandleCommand("name2ee " + assembly + " Test.Main", res)
+ print(res.GetOutput())
+ print(res.GetError())
+ # Interpreter must have this command and able to run it
+ test.assertTrue(res.Succeeded())
+
+ output = res.GetOutput()
+ # Output is not empty
+ test.assertTrue(len(output) > 0)
+
+ match = re.search('MethodDesc:\s+([0-9a-fA-F]+)', output)
+ # Line matched
+ test.assertTrue(match)
+
+ groups = match.groups()
+ # Match has a single subgroup
+ test.assertEqual(len(groups), 1)
+
+ md_addr = groups[0]
+ # Address must be a hex number
+ test.assertTrue(test.is_hexnum(md_addr))
+
+ ci.HandleCommand("dumpmd " + md_addr, res)
+ print(res.GetOutput())
+ print(res.GetError())
+ # Interpreter must have this command and able to run it
+ test.assertTrue(res.Succeeded())
+
+ # TODO: test other use cases
+
+ # Continue current process and checks its exit code
+ test.exit_lldb(debugger, assembly)
--- /dev/null
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+import lldb
+import re
+import testutils as test
+
+
+def runScenario(assembly, debugger, target):
+ process = target.GetProcess()
+ res = lldb.SBCommandReturnObject()
+ ci = debugger.GetCommandInterpreter()
+
+ # Run debugger, wait until libcoreclr is loaded,
+ # set breakpoint at Test.Main and stop there
+ test.stop_in_main(debugger, assembly)
+
+ ci.HandleCommand("name2ee " + assembly + " Test.Main", res)
+ print(res.GetOutput())
+ print(res.GetError())
+ # Interpreter must have this command and able to run it
+ test.assertTrue(res.Succeeded())
+
+ output = res.GetOutput()
+ # Output is not empty
+ test.assertTrue(len(output) > 0)
+
+ match = re.search('Module:\s+([0-9a-fA-F]+)', output)
+ # Line matched
+ test.assertTrue(match)
+
+ groups = match.groups()
+ # Match has a single subgroup
+ test.assertEqual(len(groups), 1)
+
+ md_addr = groups[0]
+ # Address must be a hex number
+ test.assertTrue(test.is_hexnum(md_addr))
+
+ ci.HandleCommand("dumpmodule " + md_addr, res)
+ print(res.GetOutput())
+ print(res.GetError())
+ # Interpreter must have this command and able to run it
+ test.assertTrue(res.Succeeded())
+
+ # TODO: test other use cases
+
+ # Continue current process and checks its exit code
+ test.exit_lldb(debugger, assembly)
--- /dev/null
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+import lldb
+import re
+import testutils as test
+
+
+def runScenario(assembly, debugger, target):
+ process = target.GetProcess()
+ res = lldb.SBCommandReturnObject()
+ ci = debugger.GetCommandInterpreter()
+
+ # Run debugger, wait until libcoreclr is loaded,
+ # set breakpoint at Test.Main and stop there
+ test.stop_in_main(debugger, assembly)
+
+ ci.HandleCommand("name2ee " + assembly + " Test.Main", res)
+ print(res.GetOutput())
+ print(res.GetError())
+ # Interpreter must have this command and able to run it
+ test.assertTrue(res.Succeeded())
+
+ output = res.GetOutput()
+ # Output is not empty
+ test.assertTrue(len(output) > 0)
+
+ match = re.search('MethodDesc:\s+([0-9a-fA-F]+)', output)
+ # Line matched
+ test.assertTrue(match)
+
+ groups = match.groups()
+ # Match has a single subgroup
+ test.assertEqual(len(groups), 1)
+
+ md_addr = groups[0]
+ # Address must be a hex number
+ test.assertTrue(test.is_hexnum(md_addr))
+
+ ci.HandleCommand("dumpmd " + md_addr, res)
+ print(res.GetOutput())
+ print(res.GetError())
+ # Interpreter must have this command and able to run it
+ test.assertTrue(res.Succeeded())
+
+ output = res.GetOutput()
+ # Output is not empty
+ test.assertTrue(len(output) > 0)
+
+ match = re.search('MethodTable:\s+([0-9a-fA-F]+)', output)
+ # Line matched
+ test.assertTrue(match)
+
+ groups = match.groups()
+ # Match has a single subgroup
+ test.assertEqual(len(groups), 1)
+
+ mt_addr = groups[0]
+ # Address must be a hex number
+ test.assertTrue(test.is_hexnum(mt_addr))
+
+ ci.HandleCommand("dumpmt " + mt_addr, res)
+ print(res.GetOutput())
+ print(res.GetError())
+ # Interpreter must have this command and able to run it
+ test.assertTrue(res.Succeeded())
+
+ # TODO: test other use cases
+
+ # Continue current process and checks its exit code
+ test.exit_lldb(debugger, assembly)
--- /dev/null
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+import lldb
+import re
+import testutils as test
+
+
+def runScenario(assembly, debugger, target):
+ process = target.GetProcess()
+ res = lldb.SBCommandReturnObject()
+ ci = debugger.GetCommandInterpreter()
+
+ # Run debugger, wait until libcoreclr is loaded,
+ # set breakpoint at Test.Main and stop there
+ test.stop_in_main(debugger, assembly)
+
+ ci.HandleCommand("dso", res)
+ print(res.GetOutput())
+ print(res.GetError())
+ # Interpreter must have this command and able to run it
+ test.assertTrue(res.Succeeded())
+
+ output = res.GetOutput()
+ # Output is not empty
+ test.assertTrue(len(output) > 0)
+
+ # Get all objects
+ objects = []
+ for line in output.split('\n'):
+ match = re.match('([0-9a-fA-F]+)\s+([0-9a-fA-F]+)\s', line)
+ # Not all lines list objects
+ if match:
+ groups = match.groups()
+ # Match has exactly two subgroups
+ test.assertEqual(len(groups), 2)
+
+ obj_addr = groups[1]
+ # Address must be a hex number
+ test.assertTrue(test.is_hexnum(obj_addr))
+
+ objects.append(obj_addr)
+
+ # There must be at least one object
+ test.assertTrue(len(objects) > 0)
+
+ for obj in objects:
+ ci.HandleCommand("dumpobj " + obj, res)
+ print(res.GetOutput())
+ print(res.GetError())
+ # Interpreter must have this command and able to run it
+ test.assertTrue(res.Succeeded())
+
+ output = res.GetOutput()
+ # Output is not empty
+ test.assertTrue(len(output) > 0)
+
+ match = re.search('Name:\s+\S+', output)
+ test.assertTrue(match)
+ match = re.search('MethodTable:\s+[0-9a-fA-F]+', output)
+ test.assertTrue(match)
+ match = re.search('EEClass:\s+[0-9a-fA-F]+', output)
+ test.assertTrue(match)
+ match = re.search('Size:\s+[0-9a-fA-F]+', output)
+ test.assertTrue(match)
+ match = re.search('Fields:', output)
+ test.assertTrue(match)
+
+ # TODO: test other use cases
+
+ # Continue current process and checks its exit code
+ test.exit_lldb(debugger, assembly)
--- /dev/null
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+import lldb
+import re
+import testutils as test
+
+
+def runScenario(assembly, debugger, target):
+ process = target.GetProcess()
+ res = lldb.SBCommandReturnObject()
+ ci = debugger.GetCommandInterpreter()
+
+ # Run debugger, wait until libcoreclr is loaded,
+ # set breakpoint at Test.Main and stop there
+ test.stop_in_main(debugger, assembly)
+
+ ci.HandleCommand("dumpstack", res)
+ print(res.GetOutput())
+ print(res.GetError())
+ # Interpreter must have this command and able to run it
+ test.assertTrue(res.Succeeded())
+
+ output = res.GetOutput()
+ # Output is not empty
+ test.assertTrue(len(output) > 0)
+
+ # Specific string must be in the output
+ test.assertNotEqual(output.find("Test.Main()"), -1)
+
+ # TODO: test other use cases
+
+ # Continue current process and checks its exit code
+ test.exit_lldb(debugger, assembly)
--- /dev/null
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+import lldb
+import re
+import testutils as test
+
+
+def runScenario(assembly, debugger, target):
+ process = target.GetProcess()
+ res = lldb.SBCommandReturnObject()
+ ci = debugger.GetCommandInterpreter()
+
+ # Run debugger, wait until libcoreclr is loaded,
+ # set breakpoint at Test.Main and stop there
+ test.stop_in_main(debugger, assembly)
+
+ ci.HandleCommand("eeheap", res)
+ print(res.GetOutput())
+ print(res.GetError())
+ # Interpreter must have this command and able to run it
+ test.assertTrue(res.Succeeded())
+
+ output = res.GetOutput()
+ # Output is not empty
+ test.assertTrue(len(output) > 0)
+
+ # Specific string must be in the output
+ test.assertNotEqual(output.find("Loader Heap"), -1)
+
+ # TODO: test other use cases
+
+ # Continue current process and checks its exit code
+ test.exit_lldb(debugger, assembly)
--- /dev/null
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+import lldb
+import re
+import testutils as test
+
+
+def runScenario(assembly, debugger, target):
+ process = target.GetProcess()
+ res = lldb.SBCommandReturnObject()
+ ci = debugger.GetCommandInterpreter()
+
+ # Run debugger, wait until libcoreclr is loaded,
+ # set breakpoint at Test.Main and stop there
+ test.stop_in_main(debugger, assembly)
+
+ ci.HandleCommand("eestack", res)
+ print(res.GetOutput())
+ print(res.GetError())
+ # Interpreter must have this command and able to run it
+ test.assertTrue(res.Succeeded())
+
+ output = res.GetOutput()
+ # Output is not empty
+ test.assertTrue(len(output) > 0)
+
+ # Specific string must be in the output
+ test.assertNotEqual(output.find("Current frame"), -1)
+
+ # TODO: test other use cases
+
+ # Continue current process and checks its exit code
+ test.exit_lldb(debugger, assembly)
--- /dev/null
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+import lldb
+import re
+import testutils as test
+
+
+def runScenario(assembly, debugger, target):
+ process = target.GetProcess()
+ res = lldb.SBCommandReturnObject()
+ ci = debugger.GetCommandInterpreter()
+
+ # Run debugger, wait until libcoreclr is loaded,
+ # set breakpoint at Test.Main and stop there
+ test.stop_in_main(debugger, assembly)
+
+ ci.HandleCommand("dso", res)
+ print(res.GetOutput())
+ print(res.GetError())
+ # Interpreter must have this command and able to run it
+ test.assertTrue(res.Succeeded())
+
+ output = res.GetOutput()
+ # Output is not empty
+ test.assertTrue(len(output) > 0)
+
+ # Get all objects
+ objects = []
+ for line in output.split('\n'):
+ match = re.match('([0-9a-fA-F]+)\s+([0-9a-fA-F]+)\s', line)
+ # Not all lines list objects
+ if match:
+ groups = match.groups()
+ # Match has exactly two subgroups
+ test.assertEqual(len(groups), 2)
+
+ obj_addr = groups[1]
+ # Address must be a hex number
+ test.assertTrue(test.is_hexnum(obj_addr))
+
+ objects.append(obj_addr)
+
+ # There must be at least one object
+ test.assertTrue(len(objects) > 0)
+
+ for obj in objects:
+ ci.HandleCommand("gcroot " + obj, res)
+ print(res.GetOutput())
+ print(res.GetError())
+ # Interpreter must have this command and able to run it
+ test.assertTrue(res.Succeeded())
+
+ output = res.GetOutput()
+ # Output is not empty
+ test.assertTrue(len(output) > 0)
+
+ match = re.search('Found', output)
+ test.assertTrue(match)
+
+ # TODO: test other use cases
+
+ # Continue current process and checks its exit code
+ test.exit_lldb(debugger, assembly)
--- /dev/null
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+import lldb
+import re
+import testutils as test
+
+
+def runScenario(assembly, debugger, target):
+ process = target.GetProcess()
+ res = lldb.SBCommandReturnObject()
+ ci = debugger.GetCommandInterpreter()
+
+ # Run debugger, wait until libcoreclr is loaded,
+ # set breakpoint at Test.Main and stop there
+ test.stop_in_main(debugger, assembly)
+
+ ci.HandleCommand("histclear", res)
+ print(res.GetOutput())
+ print(res.GetError())
+ # Interpreter must have this command and able to run it
+ test.assertTrue(res.Succeeded())
+
+ output = res.GetOutput()
+ # Output is not empty
+ test.assertTrue(len(output) > 0)
+
+ # Specific string must be in the output
+ test.assertNotEqual(output.find("Completed successfully."), -1)
+
+ # TODO: test other use cases
+
+ # Continue current process and checks its exit code
+ test.exit_lldb(debugger, assembly)
--- /dev/null
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+import lldb
+import re
+import testutils as test
+
+
+def runScenario(assembly, debugger, target):
+ process = target.GetProcess()
+ res = lldb.SBCommandReturnObject()
+ ci = debugger.GetCommandInterpreter()
+
+ # Run debugger, wait until libcoreclr is loaded,
+ # set breakpoint at Test.Main and stop there
+ test.stop_in_main(debugger, assembly)
+
+ ci.HandleCommand("histinit", res)
+ print(res.GetOutput())
+ print(res.GetError())
+ # Interpreter must have this command and able to run it
+ test.assertTrue(res.Succeeded())
+
+ output = res.GetOutput()
+ # Output is not empty
+ test.assertTrue(len(output) > 0)
+
+ # Specific string must be in the output
+ test.assertNotEqual(output.find("STRESS LOG:"), -1)
+
+ # TODO: test other use cases
+
+ # Continue current process and checks its exit code
+ test.exit_lldb(debugger, assembly)
--- /dev/null
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+import lldb
+import re
+import testutils as test
+
+
+def runScenario(assembly, debugger, target):
+ process = target.GetProcess()
+ res = lldb.SBCommandReturnObject()
+ ci = debugger.GetCommandInterpreter()
+
+ # Run debugger, wait until libcoreclr is loaded,
+ # set breakpoint at Test.Main and stop there
+ test.stop_in_main(debugger, assembly)
+
+ ci.HandleCommand("dso", res)
+ print(res.GetOutput())
+ print(res.GetError())
+ # Interpreter must have this command and able to run it
+ test.assertTrue(res.Succeeded())
+
+ output = res.GetOutput()
+ # Output is not empty
+ test.assertTrue(len(output) > 0)
+
+ # Get all objects
+ objects = []
+ for line in output.split('\n'):
+ match = re.match('([0-9a-fA-F]+)\s+([0-9a-fA-F]+)\s', line)
+ # Not all lines list objects
+ if match:
+ groups = match.groups()
+ # Match has exactly two subgroups
+ test.assertEqual(len(groups), 2)
+
+ obj_addr = groups[1]
+ # Address must be a hex number
+ test.assertTrue(test.is_hexnum(obj_addr))
+
+ objects.append(obj_addr)
+
+ # There must be at least one object
+ test.assertTrue(len(objects) > 0)
+
+ for obj in objects:
+ ci.HandleCommand("histobj " + obj, res)
+ print(res.GetOutput())
+ print(res.GetError())
+ # Interpreter must have this command and able to run it
+ test.assertTrue(res.Succeeded())
+
+ output = res.GetOutput()
+ # Output is not empty
+ test.assertTrue(len(output) > 0)
+
+ match = re.search('GCCount', output)
+ test.assertTrue(match)
+
+ # TODO: test other use cases
+
+ # Continue current process and checks its exit code
+ test.exit_lldb(debugger, assembly)
--- /dev/null
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+import lldb
+import re
+import testutils as test
+
+
+def runScenario(assembly, debugger, target):
+ process = target.GetProcess()
+ res = lldb.SBCommandReturnObject()
+ ci = debugger.GetCommandInterpreter()
+
+ # Run debugger, wait until libcoreclr is loaded,
+ # set breakpoint at Test.Main and stop there
+ test.stop_in_main(debugger, assembly)
+
+ ci.HandleCommand("dso", res)
+ print(res.GetOutput())
+ print(res.GetError())
+ # Interpreter must have this command and able to run it
+ test.assertTrue(res.Succeeded())
+
+ output = res.GetOutput()
+ # Output is not empty
+ test.assertTrue(len(output) > 0)
+
+ # Get all objects
+ objects = []
+ for line in output.split('\n'):
+ match = re.match('([0-9a-fA-F]+)\s+([0-9a-fA-F]+)\s', line)
+ # Not all lines list objects
+ if match:
+ groups = match.groups()
+ # Match has exactly two subgroups
+ test.assertEqual(len(groups), 2)
+
+ obj_addr = groups[1]
+ # Address must be a hex number
+ test.assertTrue(test.is_hexnum(obj_addr))
+
+ objects.append(obj_addr)
+
+ # There must be at least one object
+ test.assertTrue(len(objects) > 0)
+
+ for obj in objects:
+ ci.HandleCommand("histobjfind " + obj, res)
+ print(res.GetOutput())
+ print(res.GetError())
+ # Interpreter must have this command and able to run it
+ test.assertTrue(res.Succeeded())
+
+ output = res.GetOutput()
+ # Output is not empty
+ test.assertTrue(len(output) > 0)
+
+ match = re.search('GCCount', output)
+ test.assertTrue(match)
+
+ # TODO: test other use cases
+
+ # Continue current process and checks its exit code
+ test.exit_lldb(debugger, assembly)
--- /dev/null
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+import lldb
+import re
+import testutils as test
+
+
+def runScenario(assembly, debugger, target):
+ process = target.GetProcess()
+ res = lldb.SBCommandReturnObject()
+ ci = debugger.GetCommandInterpreter()
+
+ # Run debugger, wait until libcoreclr is loaded,
+ # set breakpoint at Test.Main and stop there
+ test.stop_in_main(debugger, assembly)
+
+ ci.HandleCommand("dso", res)
+ print(res.GetOutput())
+ print(res.GetError())
+ # Interpreter must have this command and able to run it
+ test.assertTrue(res.Succeeded())
+
+ output = res.GetOutput()
+ # Output is not empty
+ test.assertTrue(len(output) > 0)
+
+ # Get all objects
+ objects = []
+ for line in output.split('\n'):
+ match = re.match('([0-9a-fA-F]+)\s+([0-9a-fA-F]+)\s', line)
+ # Not all lines list objects
+ if match:
+ groups = match.groups()
+ # Match has exactly two subgroups
+ test.assertEqual(len(groups), 2)
+
+ obj_addr = groups[1]
+ # Address must be a hex number
+ test.assertTrue(test.is_hexnum(obj_addr))
+
+ objects.append(obj_addr)
+
+ # There must be at least one object
+ test.assertTrue(len(objects) > 0)
+
+ for obj in objects:
+ ci.HandleCommand("histroot " + obj, res)
+ print(res.GetOutput())
+ print(res.GetError())
+ # Interpreter must have this command and able to run it
+ test.assertTrue(res.Succeeded())
+
+ output = res.GetOutput()
+ # Output is not empty
+ test.assertTrue(len(output) > 0)
+
+ match = re.search('GCCount', output)
+ test.assertTrue(match)
+
+ # TODO: test other use cases
+
+ # Continue current process and checks its exit code
+ test.exit_lldb(debugger, assembly)
--- /dev/null
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+import lldb
+import re
+import testutils as test
+
+
+def runScenario(assembly, debugger, target):
+ process = target.GetProcess()
+ res = lldb.SBCommandReturnObject()
+ ci = debugger.GetCommandInterpreter()
+
+ # Run debugger, wait until libcoreclr is loaded,
+ # set breakpoint at Test.Main and stop there
+ test.stop_in_main(debugger, assembly)
+
+ ci.HandleCommand("name2ee " + assembly + " Test.Main", res)
+ print(res.GetOutput())
+ print(res.GetError())
+ # Interpreter must have this command and able to run it
+ test.assertTrue(res.Succeeded())
+
+ output = res.GetOutput()
+ # Output is not empty
+ test.assertTrue(len(output) > 0)
+
+ match = re.search('JITTED Code Address:\s+([0-9a-fA-F]+)', output)
+ # Line matched
+ test.assertTrue(match)
+
+ groups = match.groups()
+ # Match has a single subgroup
+ test.assertEqual(len(groups), 1)
+
+ jit_addr = groups[0]
+ # Address must be a hex number
+ test.assertTrue(test.is_hexnum(jit_addr))
+
+ ci.HandleCommand("ip2md " + jit_addr, res)
+ print(res.GetOutput())
+ print(res.GetError())
+ # Interpreter must have this command and able to run it
+ test.assertTrue(res.Succeeded())
+
+ output = res.GetOutput()
+ # Output is not empty
+ test.assertTrue(len(output) > 0)
+
+ # Specific string must be in the output
+ test.assertNotEqual(output.find("MethodDesc:"), -1)
+
+ # TODO: test other use cases
+
+ # Continue current process and checks its exit code
+ test.exit_lldb(debugger, assembly)
--- /dev/null
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+import lldb
+import re
+import testutils as test
+
+
+def runScenario(assembly, debugger, target):
+ process = target.GetProcess()
+ res = lldb.SBCommandReturnObject()
+ ci = debugger.GetCommandInterpreter()
+
+ # Run debugger, wait until libcoreclr is loaded,
+ # set breakpoint at Test.Main and stop there
+ test.stop_in_main(debugger, assembly)
+
+ ci.HandleCommand("name2ee " + assembly + " Test.Main", res)
+ print(res.GetOutput())
+ print(res.GetError())
+ # Interpreter must have this command and able to run it
+ test.assertTrue(res.Succeeded())
+
+ output = res.GetOutput()
+ # Output is not empty
+ test.assertTrue(len(output) > 0)
+
+ match = re.search('Module:\s+[0-9a-fA-F]+', output)
+ test.assertTrue(match)
+ match = re.search('Assembly:\s+\S+', output)
+ test.assertTrue(match)
+ match = re.search('Token:\s+[0-9a-fA-F]+', output)
+ test.assertTrue(match)
+ match = re.search('MethodDesc:\s+[0-9a-fA-F]+', output)
+ test.assertTrue(match)
+ match = re.search('Name:\s+\S+', output)
+ test.assertTrue(match)
+
+ process.Continue()
+ # Process must exit
+ test.assertEqual(process.GetState(), lldb.eStateExited)
+
+ # Process must exit with zero code
+ test.assertEqual(process.GetExitStatus(), 0)
+
+ # TODO: test other use cases
+
+ # Continue current process and checks its exit code
+ test.exit_lldb(debugger, assembly)
--- /dev/null
+import lldb
+import re
+import testutils as test
+
+
+def runScenario(assembly, debugger, target):
+ process = target.GetProcess()
+ res = lldb.SBCommandReturnObject()
+ ci = debugger.GetCommandInterpreter()
+
+ # Run debugger, wait until libcoreclr is loaded,
+ # set breakpoint at Test.Main and stop there
+ test.stop_in_main(debugger, assembly)
+
+ ci.HandleCommand("dso", res)
+ print(res.GetOutput())
+ print(res.GetError())
+ # Interpreter must have this command and able to run it
+ test.assertTrue(res.Succeeded())
+
+ output = res.GetOutput()
+ # Output is not empty
+ test.assertTrue(len(output) > 0)
+
+ # TODO: test other use cases
+
+ # Continue current process and checks its exit code
+ test.exit_lldb(debugger, assembly)
--- /dev/null
+import lldb
+import re
+import testutils as test
+
+
+def runScenario(assembly, debugger, target):
+ process = target.GetProcess()
+ res = lldb.SBCommandReturnObject()
+ ci = debugger.GetCommandInterpreter()
+
+ # Run debugger, wait until libcoreclr is loaded,
+ # set breakpoint at Test.Main and stop there
+ test.stop_in_main(debugger, assembly)
+
+ ci.HandleCommand("sos", res)
+ print(res.GetOutput())
+ print(res.GetError())
+ # Interpreter must have this command and able to run it
+ test.assertTrue(res.Succeeded())
+
+ output = res.GetOutput()
+ # Output is not empty
+ test.assertTrue(len(output) > 0)
+
+ # Specific string must be in the output
+ test.assertNotEqual(output.find("SOS"), -1)
+
+ # TODO: test other use cases
+
+ # Continue current process and checks its exit code
+ test.exit_lldb(debugger, assembly)
--- /dev/null
+import lldb
+import re
+import testutils as test
+
+
+def runScenario(assembly, debugger, target):
+ process = target.GetProcess()
+ res = lldb.SBCommandReturnObject()
+ ci = debugger.GetCommandInterpreter()
+
+ # Run debugger, wait until libcoreclr is loaded,
+ # set breakpoint at Test.Main and stop there
+ test.stop_in_main(debugger, assembly)
+
+ ci.HandleCommand("soshelp", res)
+ print(res.GetOutput())
+ print(res.GetError())
+ # Interpreter must have this command and able to run it
+ test.assertTrue(res.Succeeded())
+
+ output = res.GetOutput()
+ # Output is not empty
+ test.assertTrue(len(output) > 0)
+
+ # Specific string must be in the output
+ test.assertNotEqual(output.find("soshelp <functionname>"), -1)
+
+ # TODO: test other use cases
+
+ # Continue current process and checks its exit code
+ test.exit_lldb(debugger, assembly)
--- /dev/null
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+from __future__ import print_function
+import unittest
+import argparse
+import re
+import tempfile
+import subprocess
+import threading
+import os
+import sys
+import inspect
+
+lldb = ''
+logfiledir = ''
+host = ''
+plugin = ''
+assembly = ''
+fail_flag = ''
+fail_flag_lldb = ''
+summary_file = ''
+timeout = 0
+regex = ''
+repeat = 0
+
+
+def runWithTimeout(cmd):
+ p = None
+
+ def run():
+ global p
+ p = subprocess.Popen(cmd, shell=True)
+ p.communicate()
+
+ thread = threading.Thread(target=run)
+ thread.start()
+
+ thread.join(timeout)
+ if thread.is_alive():
+ with open(summary_file, 'a+') as summary:
+ print('Timeout!', file=summary)
+ p.kill()
+ thread.join()
+
+
+class TestSosCommands(unittest.TestCase):
+
+ def do_test(self, command):
+ open(fail_flag, 'a').close()
+ try:
+ os.unlink(fail_flag_lldb)
+ except:
+ pass
+
+ logfile = os.path.join(logfiledir, command)
+
+ cmd = (('%s -b ' % lldb) +
+ ("-k \"script open('%s', 'a').close()\" " % fail_flag_lldb) +
+ ("-k 'quit' ") +
+ ("--no-lldbinit ") +
+ ("-O \"plugin load %s \" " % plugin) +
+ ("-o \"script import testutils as test\" ") +
+ ("-o \"script test.fail_flag = '%s'\" " % fail_flag) +
+ ("-o \"script test.summary_file = '%s'\" " % summary_file) +
+ ("-o \"script test.run('%s', '%s')\" " % (assembly, command)) +
+ ("-o \"quit\" ") +
+ (" -- %s %s > %s.log 2> %s.log.2" % (host, assembly, logfile, logfile)))
+
+ runWithTimeout(cmd)
+ self.assertFalse(os.path.isfile(fail_flag))
+ self.assertFalse(os.path.isfile(fail_flag_lldb))
+
+ try:
+ os.unlink(fail_flag)
+ except:
+ pass
+ try:
+ os.unlink(fail_flag_lldb)
+ except:
+ pass
+
+ def t_cmd_bpmd_nofuturemodule_module_function(self):
+ self.do_test('t_cmd_bpmd_nofuturemodule_module_function')
+
+ def t_cmd_bpmd_module_function(self):
+ self.do_test('t_cmd_bpmd_module_function')
+
+ def t_cmd_bpmd_module_function_iloffset(self):
+ self.do_test('t_cmd_bpmd_module_function_iloffset')
+
+ def t_cmd_bpmd_methoddesc(self):
+ self.do_test('t_cmd_bpmd_methoddesc')
+
+ def t_cmd_bpmd_clearall(self):
+ self.do_test('t_cmd_bpmd_clearall')
+
+ def t_cmd_clrstack(self):
+ self.do_test('t_cmd_clrstack')
+
+ def t_cmd_clrthreads(self):
+ self.do_test('t_cmd_clrthreads')
+
+ def t_cmd_clru(self):
+ self.do_test('t_cmd_clru')
+
+ def t_cmd_dumpclass(self):
+ self.do_test('t_cmd_dumpclass')
+
+ def t_cmd_dumpheap(self):
+ self.do_test('t_cmd_dumpheap')
+
+ def t_cmd_dumpil(self):
+ self.do_test('t_cmd_dumpil')
+
+ def t_cmd_dumplog(self):
+ self.do_test('t_cmd_dumplog')
+
+ def t_cmd_dumpmd(self):
+ self.do_test('t_cmd_dumpmd')
+
+ def t_cmd_dumpmodule(self):
+ self.do_test('t_cmd_dumpmodule')
+
+ def t_cmd_dumpmt(self):
+ self.do_test('t_cmd_dumpmt')
+
+ def t_cmd_dumpobj(self):
+ self.do_test('t_cmd_dumpobj')
+
+ def t_cmd_dumpstack(self):
+ self.do_test('t_cmd_dumpstack')
+
+ def t_cmd_dso(self):
+ self.do_test('t_cmd_dso')
+
+ def t_cmd_eeheap(self):
+ self.do_test('t_cmd_eeheap')
+
+ def t_cmd_eestack(self):
+ self.do_test('t_cmd_eestack')
+
+ def t_cmd_gcroot(self):
+ self.do_test('t_cmd_gcroot')
+
+ def t_cmd_ip2md(self):
+ self.do_test('t_cmd_ip2md')
+
+ def t_cmd_name2ee(self):
+ self.do_test('t_cmd_name2ee')
+
+ def t_cmd_pe(self):
+ self.do_test('t_cmd_pe')
+
+ def t_cmd_histclear(self):
+ self.do_test('t_cmd_histclear')
+
+ def t_cmd_histinit(self):
+ self.do_test('t_cmd_histinit')
+
+ def t_cmd_histobj(self):
+ self.do_test('t_cmd_histobj')
+
+ def t_cmd_histobjfind(self):
+ self.do_test('t_cmd_histobjfind')
+
+ def t_cmd_histroot(self):
+ self.do_test('t_cmd_histroot')
+
+ def t_cmd_sos(self):
+ self.do_test('t_cmd_sos')
+
+ def t_cmd_soshelp(self):
+ self.do_test('t_cmd_soshelp')
+
+
+def generate_report():
+ report = [{'name': 'TOTAL', True: 0, False: 0, 'completed': True}]
+ fail_messages = []
+
+ if not os.path.isfile(summary_file):
+ print('No summary file to process!')
+ return
+
+ with open(summary_file, 'r') as summary:
+ for line in summary:
+ if line.startswith('new_suite: '):
+ report.append({'name': line.split()[-1], True: 0, False: 0,
+ 'completed': False, 'timeout': False})
+ elif line.startswith('True'):
+ report[-1][True] += 1
+ elif line.startswith('False'):
+ report[-1][False] += 1
+ elif line.startswith('Completed!'):
+ report[-1]['completed'] = True
+ elif line.startswith('Timeout!'):
+ report[-1]['timeout'] = True
+ elif line.startswith('!!! '):
+ fail_messages.append(line.rstrip('\n'))
+
+ for suite in report[1:]:
+ report[0][True] += suite[True]
+ report[0][False] += suite[False]
+ report[0]['completed'] &= suite['completed']
+
+ for line in fail_messages:
+ print(line)
+
+ print()
+ print('=' * 79)
+ print('{:72} {:6}'.format('Test suite', 'Result'))
+ print('-' * 79)
+ for suite in report[1:]:
+ if suite['timeout']:
+ result = 'Timeout'
+ elif suite[False]:
+ result = 'Fail'
+ elif not suite['completed']:
+ result = 'Crash'
+ elif suite[True]:
+ result = 'Success'
+ else:
+ result = 'Please, report'
+ print('{:68} {:>10}'.format(suite['name'], result))
+ print('=' * 79)
+
+
+if __name__ == '__main__':
+ parser = argparse.ArgumentParser()
+ parser.add_argument('--lldb', default='lldb')
+ parser.add_argument('--host', default='.')
+ parser.add_argument('--plugin', default='.')
+ parser.add_argument('--logfiledir', default='.')
+ parser.add_argument('--assembly', default='Test.exe')
+ parser.add_argument('--timeout', default=90)
+ parser.add_argument('--regex', default='t_cmd_')
+ parser.add_argument('--repeat', default=1)
+ parser.add_argument('unittest_args', nargs='*')
+
+ args = parser.parse_args()
+
+ lldb = args.lldb
+ host = args.host
+ plugin = args.plugin
+ logfiledir = args.logfiledir
+ assembly = args.assembly
+ timeout = int(args.timeout)
+ regex = args.regex
+ repeat = int(args.repeat)
+ print("lldb: %s" % lldb)
+ print("host: %s" % host)
+ print("plugin: %s" % plugin)
+ print("logfiledir: %s" % logfiledir)
+ print("assembly: %s" % assembly)
+ print("timeout: %i" % timeout)
+ print("regex: %s" % regex)
+ print("repeat: %i" % repeat)
+
+ if os.name != 'posix':
+ print('OS not supported')
+ exit(1)
+
+ print("host: %s" % host)
+ print("lldb plugin: %s" % plugin)
+
+ fail_flag = os.path.join(logfiledir, 'fail_flag')
+ fail_flag_lldb = os.path.join(logfiledir, 'fail_flag.lldb')
+
+ print("fail_flag: %s" % fail_flag)
+ print("fail_flag_lldb: %s" % fail_flag_lldb)
+
+ summary_file = os.path.join(logfiledir, 'summary')
+ print("summary_file: %s" % summary_file)
+
+ try:
+ os.unlink(summary_file)
+ except:
+ pass
+
+ sys.argv[1:] = args.unittest_args
+ suite = unittest.TestSuite()
+ all_tests = inspect.getmembers(TestSosCommands, predicate=inspect.ismethod)
+ for (test_name, test_func) in all_tests:
+ if re.match(regex, test_name):
+ suite.addTest(TestSosCommands(test_name))
+ unittest.TextTestRunner(verbosity=1).run(suite)
+
+ generate_report()
--- /dev/null
+#!/usr/bin/env bash
+__ProjectRoot="$1"
+__NativeBinDir="$2"
+__ManagedBinDir="$3"
+__LogFileDir="$4"
+__BuildArch="$5"
+
+if [[ "$__ProjectRoot" = "" || "$__NativeBinDir" = "" || "$__ManagedBinDir" = "" || "$__LogFileDir" = "" ]]; then
+ echo "Project root, bin or log directory required"
+ exit 1
+fi
+
+__Plugin=$__NativeBinDir/libsosplugin.so
+__Host=$__ProjectRoot/.dotnet/dotnet
+__TestProgram=$__ManagedBinDir/TestDebuggee/netcoreapp2.0/TestDebuggee.dll
+
+cd $__ProjectRoot/src/SOS/tests/
+rm StressLog.txt
+python2 $__ProjectRoot/src/SOS/tests/test_libsosplugin.py --lldb $LLDB_PATH --host $__Host --plugin $__Plugin --logfiledir $__LogFileDir --assembly $__TestProgram
+
--- /dev/null
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+from __future__ import print_function
+import lldb
+import re
+import inspect
+import sys
+import os
+import importlib
+
+summary_file = ''
+fail_flag = ''
+
+failed = False
+
+
+def assertCommon(passed, fatal):
+ global failed
+ with open(summary_file, 'a+') as summary:
+ print(bool(passed), file=summary)
+ if (not passed):
+ failed = True
+ print('!!! test failed:', file=summary)
+ for s in inspect.stack()[2:]:
+ print("!!! %s:%i" % (s[1], s[2]), file=summary)
+ print("!!! %s" % s[4][0], file=summary)
+ if re.match('\W*t_\w+\.py$', s[1]):
+ break
+ print('!!! ', file=summary)
+
+ if fatal:
+ exit(1)
+
+
+def assertTrue(x, fatal=True):
+ passed = bool(x)
+ assertCommon(passed, fatal)
+
+
+def assertFalse(x, fatal=True):
+ passed = not bool(x)
+ assertCommon(passed, fatal)
+
+
+def assertEqual(x, y, fatal=True):
+ passed = (x == y)
+ if not passed:
+ print(str(x), ' != ', str(y))
+ assertCommon(passed, fatal)
+
+
+def assertNotEqual(x, y, fatal=True):
+ passed = (x != y)
+ if not passed:
+ print(str(x), ' == ', str(y))
+ assertCommon(passed, fatal)
+
+
+def checkResult(res):
+ if not res.Succeeded():
+ print(res.GetOutput())
+ print(res.GetError())
+ exit(1)
+
+
+def is_hexnum(s):
+ try:
+ int(s, 16)
+ return True
+ except ValueError:
+ return False
+
+
+def exec_and_find(commandInterpreter, cmd, regexp):
+ res = lldb.SBCommandReturnObject()
+ commandInterpreter.HandleCommand(cmd, res)
+ checkResult(res)
+
+ expr = re.compile(regexp)
+ addr = None
+
+ print(res.GetOutput())
+ lines = res.GetOutput().splitlines()
+ for line in lines:
+ match = expr.match(line)
+ if match:
+ addr = match.group(1)
+ break
+
+ print("Found addr: " + str(addr))
+ return addr
+
+
+def stop_in_main(debugger, assembly):
+ ci = debugger.GetCommandInterpreter()
+ target = debugger.GetSelectedTarget()
+ process = target.GetProcess()
+ res = lldb.SBCommandReturnObject()
+
+ # Process must be stopped here while libcoreclr loading.
+ # This test usually fails on release version of coreclr
+ # since we depend on 'LoadLibraryExW' symbol present.
+ assertEqual(process.GetState(), lldb.eStateStopped)
+
+ # The reason of this stop must be a breakpoint
+ assertEqual(process.GetSelectedThread().GetStopReason(),
+ lldb.eStopReasonBreakpoint)
+
+ ci.HandleCommand("bpmd " + assembly + " Test.Main", res)
+ out_msg = res.GetOutput()
+ err_msg = res.GetError()
+ print(res.GetOutput())
+ print(res.GetError())
+ # Interpreter must have this command and able to run it
+ assertTrue(res.Succeeded())
+
+ # Output is not empty
+ # Should be at least 'Adding pending breakpoints...'
+ assertTrue(res.GetOutputSize() > 0)
+
+ # Error message is empty
+ assertTrue(res.GetErrorSize() == 0)
+
+ process.Continue()
+ # Process must be stopped here if bpmd works at all
+ assertEqual(process.GetState(), lldb.eStateStopped)
+
+ # The reason of this stop must be a breakpoint
+ assertEqual(process.GetSelectedThread().GetStopReason(),
+ lldb.eStopReasonBreakpoint)
+
+
+def exit_lldb(debugger, assembly):
+ ci = debugger.GetCommandInterpreter()
+ target = debugger.GetSelectedTarget()
+ process = target.GetProcess()
+ res = lldb.SBCommandReturnObject()
+
+ ci.HandleCommand("breakpoint delete --force", res)
+ out_msg = res.GetOutput()
+ err_msg = res.GetError()
+ print(out_msg)
+ print(err_msg)
+ # Interpreter must have this command and able to run it
+ # assertTrue(res.Succeeded())
+
+ process.Continue()
+ # Process must exit
+ assertEqual(process.GetState(), lldb.eStateExited)
+
+ # Process must exit with zero code
+ assertEqual(process.GetExitStatus(), 0)
+
+
+def get_methoddesc(debugger, assembly, funcname):
+ ci = debugger.GetCommandInterpreter()
+ target = debugger.GetSelectedTarget()
+ process = target.GetProcess()
+ res = lldb.SBCommandReturnObject()
+
+ ci.HandleCommand("name2ee %s %s" % (assembly, funcname), res)
+ print(res.GetOutput())
+ print(res.GetError())
+ # Interpreter must have this command and able to run it
+ assertTrue(res.Succeeded())
+
+ output = res.GetOutput()
+ # Output is not empty
+ assertTrue(len(output) > 0)
+
+ match = re.search('MethodDesc:\s+([0-9a-fA-F]+)', output)
+ # Line matched
+ assertTrue(match)
+
+ groups = match.groups()
+ # Match has a single subgroup
+ assertEqual(len(groups), 1)
+
+ md_addr = groups[0]
+ # Address must be a hex number
+ assertTrue(is_hexnum(md_addr))
+
+ return md_addr
+
+
+def run(assembly, module):
+ with open(summary_file, 'a+') as summary:
+ print('new_suite: %s' % module, file=summary)
+
+ debugger = lldb.debugger
+
+ debugger.SetAsync(False)
+ target = lldb.target
+
+ version = debugger.GetVersionString()
+ if (re.search('^lldb version 6.*', version)):
+ debugger.HandleCommand("breakpoint set --one-shot true --name coreclr_execute_assembly")
+ else:
+ debugger.HandleCommand("breakpoint set --one-shot --name coreclr_execute_assembly")
+
+ debugger.HandleCommand("process launch")
+
+ # run the scenario
+ print("starting scenario...")
+ i = importlib.import_module(module)
+ scenarioResult = i.runScenario(os.path.basename(assembly), debugger,
+ target)
+
+ if (target.GetProcess().GetExitStatus() == 0) and not failed:
+ os.unlink(fail_flag)
+
+ with open(summary_file, 'a+') as summary:
+ print('Completed!', file=summary)
--- /dev/null
+#!/usr/bin/env bash
+
+source="${BASH_SOURCE[0]}"
+
+# resolve $SOURCE until the file is no longer a symlink
+while [[ -h $source ]]; do
+ scriptroot="$( cd -P "$( dirname "$source" )" && pwd )"
+ source="$(readlink "$source")"
+
+ # if $source was a relative symlink, we need to resolve it relative to the path where the
+ # symlink file was located
+ [[ $source != /* ]] && source="$scriptroot/$source"
+done
+
+scriptroot="$( cd -P "$( dirname "$source" )" && pwd )"
+"$scriptroot/eng/build.sh" --test $@
+