diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000000..2284477d14 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,6 @@ +[submodule "cmake/Modules/FindTBB"] + path = cmake/Modules/FindTBB + url = https://github.com/justusc/FindTBB +[submodule "testsuite"] + path = testsuite + url = https://github.com/dyninst/testsuite diff --git a/CMakeLists.txt b/CMakeLists.txt index a0980a6110..ab0829032d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required (VERSION 2.6.4) +cmake_minimum_required (VERSION 3.0.0) project (Dyninst) set (DYNINST_ROOT ${PROJECT_SOURCE_DIR}) @@ -37,13 +37,18 @@ if(NOT ${PLATFORM} MATCHES nt) ) endif() + + foreach (dir ${HEADER_DIRS}) include_directories ( ${DYNINST_ROOT}/${dir}/h ) endforeach() + include_directories ( ${DYNINST_ROOT} ${DYNINST_ROOT}/external + ${CILKSCREEN_INCLUDES} + ${TBB_INCLUDE_DIRS} ) set(Boost_USE_STATIC_LIBS OFF) # Component time @@ -68,7 +73,7 @@ endif() if(BUILD_RTLIB) # Build the RT library as a separate project so we can change compilers - message(STATUS "Configuring DyninstAPI_RT") + message(STATUS "Configuring DyninstAPI_RT in ${RT_BINARY_DIR}") file(REMOVE_RECURSE ${RT_BINARY_DIR}/CMakeCache.txt ${RT_BINARY_DIR}/CMakeFiles ${RT_BINARY_DIR}/Makefile) file(MAKE_DIRECTORY ${RT_BINARY_DIR}) if (PLATFORM MATCHES bgq) @@ -92,7 +97,8 @@ if(BUILD_RTLIB) -DPLATFORM=${PLATFORM} -G ${CMAKE_GENERATOR} ${RT_SOURCE_DIR}) - + find_file(${RT_MAKEFILE} Makefile PATHS ${RT_BINARY_DIR} NO_DEFAULT_PATH) + message(STATUS "RTlib Makefile: ${RT_MAKEFILE}") if(MSVC) include_external_msproject(DyninstAPI_RT dyninstAPI_RT/dyninstAPI_RT.vcxproj) include_external_msproject(DyninstAPI_RT_static dyninstAPI_RT/dyninstAPI_RT_static.vcxproj) @@ -205,7 +211,7 @@ if(UNIX) endif() if(SHOULD_INSTALL_LIBELF) get_filename_component(ELFDIR "${LIBELF_LIBRARIES}" PATH) - file(GLOB LIBELF_INSTALL_FILES ${ELFDIR}/libelf.so*) + file(GLOB LIBELF_INSTALL_FILES ${ELFDIR}/libelf*.so*) message(STATUS "Libelf is ${LIBELF_LIBRARIES}") message(STATUS "Installing ${LIBELF_INSTALL_FILES} from ${ELFDIR}") install (FILES ${LIBELF_INSTALL_FILES} @@ -221,3 +227,6 @@ endif() if(TARGET boost) add_dependencies(common boost) endif() + +#add_subdirectory(testsuite) + diff --git a/cmake/Modules/FindLibDwarf.cmake b/cmake/Modules/FindLibDwarf.cmake index d745226cf1..f7d9b5d3f9 100644 --- a/cmake/Modules/FindLibDwarf.cmake +++ b/cmake/Modules/FindLibDwarf.cmake @@ -7,10 +7,6 @@ # LIBDWARF_DEFINITIONS - Compiler switches required for using libdwarf # -# Locate libelf library at first -#if (NOT LIBELF_FOUND) -# find_package (LibElf REQUIRED) -#endif (NOT LIBELF_FOUND) if (LIBDWARF_LIBRARIES AND LIBDWARF_INCLUDE_DIRS) set (LibDwarf_FIND_QUIETLY TRUE) diff --git a/cmake/Modules/FindTBB b/cmake/Modules/FindTBB new file mode 160000 index 0000000000..25ecdea817 --- /dev/null +++ b/cmake/Modules/FindTBB @@ -0,0 +1 @@ +Subproject commit 25ecdea817b3af4a26d74ddcd439642dbd706acb diff --git a/cmake/Modules/FindTBB.cmake b/cmake/Modules/FindTBB.cmake new file mode 100644 index 0000000000..b5a5133b43 --- /dev/null +++ b/cmake/Modules/FindTBB.cmake @@ -0,0 +1,310 @@ +# The MIT License (MIT) +# +# Copyright (c) 2015 Justus Calvin +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +# +# FindTBB +# ------- +# +# Find TBB include directories and libraries. +# +# Usage: +# +# find_package(TBB [major[.minor]] [EXACT] +# [QUIET] [REQUIRED] +# [[COMPONENTS] [components...]] +# [OPTIONAL_COMPONENTS components...]) +# +# where the allowed components are tbbmalloc and tbb_preview. Users may modify +# the behavior of this module with the following variables: +# +# * TBB_ROOT_DIR - The base directory the of TBB installation. +# * TBB_INCLUDE_DIR - The directory that contains the TBB headers files. +# * TBB_LIBRARY - The directory that contains the TBB library files. +# * TBB__LIBRARY - The path of the TBB the corresponding TBB library. +# These libraries, if specified, override the +# corresponding library search results, where +# may be tbb, tbb_debug, tbbmalloc, tbbmalloc_debug, +# tbb_preview, or tbb_preview_debug. +# * TBB_USE_DEBUG_BUILD - The debug version of tbb libraries, if present, will +# be used instead of the release version. +# +# Users may modify the behavior of this module with the following environment +# variables: +# +# * TBB_INSTALL_DIR +# * TBBROOT +# * LIBRARY_PATH +# +# This module will set the following variables: +# +# * TBB_FOUND - Set to false, or undefined, if we haven’t found, or +# don’t want to use TBB. +# * TBB__FOUND - If False, optional part of TBB sytem is +# not available. +# * TBB_VERSION - The full version string +# * TBB_VERSION_MAJOR - The major version +# * TBB_VERSION_MINOR - The minor version +# * TBB_INTERFACE_VERSION - The interface version number defined in +# tbb/tbb_stddef.h. +# * TBB__LIBRARY_RELEASE - The path of the TBB release version of +# , where may be tbb, tbb_debug, +# tbbmalloc, tbbmalloc_debug, tbb_preview, or +# tbb_preview_debug. +# * TBB__LIBRARY_DEGUG - The path of the TBB release version of +# , where may be tbb, tbb_debug, +# tbbmalloc, tbbmalloc_debug, tbb_preview, or +# tbb_preview_debug. +# +# The following varibles should be used to build and link with TBB: +# +# * TBB_INCLUDE_DIRS - The include directory for TBB. +# * TBB_LIBRARIES - The libraries to link against to use TBB. +# * TBB_LIBRARIES_RELEASE - The release libraries to link against to use TBB. +# * TBB_LIBRARIES_DEBUG - The debug libraries to link against to use TBB. +# * TBB_DEFINITIONS - Definitions to use when compiling code that uses +# TBB. +# * TBB_DEFINITIONS_RELEASE - Definitions to use when compiling release code that +# uses TBB. +# * TBB_DEFINITIONS_DEBUG - Definitions to use when compiling debug code that +# uses TBB. +# +# This module will also create the "tbb" target that may be used when building +# executables and libraries. + +include(FindPackageHandleStandardArgs) + +if(NOT TBB_FOUND) + + ################################## + # Check the build type + ################################## + + if(NOT DEFINED TBB_USE_DEBUG_BUILD) + if(CMAKE_BUILD_TYPE MATCHES "(Debug|DEBUG|debug)")#|RelWithDebInfo|RELWITHDEBINFO|relwithdebinfo)") + set(TBB_BUILD_TYPE DEBUG) + else() + set(TBB_BUILD_TYPE RELEASE) + endif() + elseif(TBB_USE_DEBUG_BUILD) + set(TBB_BUILD_TYPE DEBUG) + else() + set(TBB_BUILD_TYPE RELEASE) + endif() + + ################################## + # Set the TBB search directories + ################################## + + # Define search paths based on user input and environment variables + set(TBB_SEARCH_DIR ${TBB_ROOT_DIR} $ENV{TBB_INSTALL_DIR} $ENV{TBBROOT}) + + # Define the search directories based on the current platform + if(CMAKE_SYSTEM_NAME STREQUAL "Windows") + set(TBB_DEFAULT_SEARCH_DIR "C:/Program Files/Intel/TBB" + "C:/Program Files (x86)/Intel/TBB") + + # Set the target architecture + if(CMAKE_SIZEOF_VOID_P EQUAL 8) + set(TBB_ARCHITECTURE "intel64") + else() + set(TBB_ARCHITECTURE "ia32") + endif() + + # Set the TBB search library path search suffix based on the version of VC + if(WINDOWS_STORE) + set(TBB_LIB_PATH_SUFFIX "lib/${TBB_ARCHITECTURE}/vc11_ui") + elseif(MSVC14) + set(TBB_LIB_PATH_SUFFIX "lib/${TBB_ARCHITECTURE}/vc14") + elseif(MSVC12) + set(TBB_LIB_PATH_SUFFIX "lib/${TBB_ARCHITECTURE}/vc12") + elseif(MSVC11) + set(TBB_LIB_PATH_SUFFIX "lib/${TBB_ARCHITECTURE}/vc11") + elseif(MSVC10) + set(TBB_LIB_PATH_SUFFIX "lib/${TBB_ARCHITECTURE}/vc10") + endif() + + # Add the library path search suffix for the VC independent version of TBB + list(APPEND TBB_LIB_PATH_SUFFIX "lib/${TBB_ARCHITECTURE}/vc_mt") + + elseif(CMAKE_SYSTEM_NAME STREQUAL "Darwin") + # OS X + set(TBB_DEFAULT_SEARCH_DIR "/opt/intel/tbb") + + # TODO: Check to see which C++ library is being used by the compiler. + if(NOT ${CMAKE_SYSTEM_VERSION} VERSION_LESS 13.0) + # The default C++ library on OS X 10.9 and later is libc++ + set(TBB_LIB_PATH_SUFFIX "lib/libc++" "lib") + else() + set(TBB_LIB_PATH_SUFFIX "lib") + endif() + elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux") + # Linux + set(TBB_DEFAULT_SEARCH_DIR "/opt/intel/tbb") + + # TODO: Check compiler version to see the suffix should be /gcc4.1 or + # /gcc4.1. For now, assume that the compiler is more recent than + # gcc 4.4.x or later. + if(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64") + set(TBB_LIB_PATH_SUFFIX "lib/intel64/gcc4.4") + elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^i.86$") + set(TBB_LIB_PATH_SUFFIX "lib/ia32/gcc4.4") + endif() + endif() + + ################################## + # Find the TBB include dir + ################################## + + find_path(TBB_INCLUDE_DIRS tbb/tbb.h + HINTS ${TBB_INCLUDE_DIRS} ${TBB_SEARCH_DIR} + PATHS ${TBB_DEFAULT_SEARCH_DIR} + PATH_SUFFIXES include) + + ################################## + # Set version strings + ################################## + + if(TBB_INCLUDE_DIRS) + file(READ "${TBB_INCLUDE_DIRS}/tbb/tbb_stddef.h" _tbb_version_file) + string(REGEX REPLACE ".*#define TBB_VERSION_MAJOR ([0-9]+).*" "\\1" + TBB_VERSION_MAJOR "${_tbb_version_file}") + string(REGEX REPLACE ".*#define TBB_VERSION_MINOR ([0-9]+).*" "\\1" + TBB_VERSION_MINOR "${_tbb_version_file}") + string(REGEX REPLACE ".*#define TBB_INTERFACE_VERSION ([0-9]+).*" "\\1" + TBB_INTERFACE_VERSION "${_tbb_version_file}") + set(TBB_VERSION "${TBB_VERSION_MAJOR}.${TBB_VERSION_MINOR}") + endif() + + ################################## + # Find TBB components + ################################## + + if(TBB_VERSION VERSION_LESS 4.3) + set(TBB_SEARCH_COMPOMPONENTS tbb_preview tbbmalloc tbb) + else() + set(TBB_SEARCH_COMPOMPONENTS tbb_preview tbbmalloc_proxy tbbmalloc tbb) + endif() + + # Find each component + foreach(_comp ${TBB_SEARCH_COMPOMPONENTS}) + message(STATUS "Searching for ${_comp}...") + message(STATUS "Hints: ${TBB_LIBRARY} ${TBB_SEARCH_DIR}") + if(";${TBB_FIND_COMPONENTS};tbb;" MATCHES ";${_comp};") + + # Search for the libraries + find_library(TBB_${_comp}_LIBRARY_RELEASE ${_comp} + HINTS ${TBB_LIBRARY} ${TBB_SEARCH_DIR} + PATHS ${TBB_DEFAULT_SEARCH_DIR} ENV LIBRARY_PATH + PATH_SUFFIXES ${TBB_LIB_PATH_SUFFIX} lib_release) + + find_library(TBB_${_comp}_LIBRARY_DEBUG ${_comp}_debug + HINTS ${TBB_LIBRARY} ${TBB_SEARCH_DIR} + PATHS ${TBB_DEFAULT_SEARCH_DIR} ENV LIBRARY_PATH + PATH_SUFFIXES ${TBB_LIB_PATH_SUFFIX} lib_debug) + + if(TBB_${_comp}_LIBRARY_DEBUG) + list(APPEND TBB_LIBRARIES_DEBUG "${TBB_${_comp}_LIBRARY_DEBUG}") + message(STATUS "Found ${TBB_${_comp}_LIBRARY_DEBUG}") + endif() + if(TBB_${_comp}_LIBRARY_RELEASE) + list(APPEND TBB_LIBRARIES_RELEASE "${TBB_${_comp}_LIBRARY_RELEASE}") + message(STATUS "Found ${TBB_${_comp}_LIBRARY_RELEASE}") + endif() + if(TBB_${_comp}_LIBRARY_${TBB_BUILD_TYPE} AND NOT TBB_${_comp}_LIBRARY) + set(TBB_${_comp}_LIBRARY "${TBB_${_comp}_LIBRARY_${TBB_BUILD_TYPE}}") + endif() + + if(TBB_${_comp}_LIBRARY AND EXISTS "${TBB_${_comp}_LIBRARY}") + set(TBB_${_comp}_FOUND TRUE) + else() + set(TBB_${_comp}_FOUND FALSE) + endif() + + # Mark internal variables as advanced + mark_as_advanced(TBB_${_comp}_LIBRARY_RELEASE) + mark_as_advanced(TBB_${_comp}_LIBRARY_DEBUG) + mark_as_advanced(TBB_${_comp}_LIBRARY) + + endif() + endforeach() + + ################################## + # Set compile flags and libraries + ################################## + + set(TBB_DEFINITIONS_RELEASE "") + set(TBB_DEFINITIONS_DEBUG "-DTBB_USE_DEBUG=1") + + if(TBB_LIBRARIES_${TBB_BUILD_TYPE}) + set(TBB_DEFINITIONS "${TBB_DEFINITIONS_${TBB_BUILD_TYPE}}") + set(TBB_LIBRARIES "${TBB_LIBRARIES_${TBB_BUILD_TYPE}}") + elseif(TBB_LIBRARIES_RELEASE) + set(TBB_DEFINITIONS "${TBB_DEFINITIONS_RELEASE}") + set(TBB_LIBRARIES "${TBB_LIBRARIES_RELEASE}") + elseif(TBB_LIBRARIES_DEBUG) + set(TBB_DEFINITIONS "${TBB_DEFINITIONS_DEBUG}") + set(TBB_LIBRARIES "${TBB_LIBRARIES_DEBUG}") + endif() + + find_package_handle_standard_args(TBB + REQUIRED_VARS TBB_INCLUDE_DIRS TBB_LIBRARIES + HANDLE_COMPONENTS + VERSION_VAR TBB_VERSION) + + ################################## + # Create targets + ################################## + + if(NOT CMAKE_VERSION VERSION_LESS 3.0 AND TBB_FOUND) + add_library(tbb SHARED IMPORTED) + message(STATUS "TBB debug libraries: ${TBB_LIBRARIES_DEBUG}") + message(STATUS "TBB release libraries: ${TBB_LIBRARIES_RELEASE}") + message(STATUS "TBB libraries: ${TBB_LIBRARIES}") + message(STATUS "TBB includes: ${TBB_INCLUDE_DIRS}") + set_target_properties(tbb PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES ${TBB_INCLUDE_DIRS} + IMPORTED_LOCATION ${TBB_LIBRARIES}) + if(TBB_LIBRARIES_RELEASE AND TBB_LIBRARIES_DEBUG) + set_target_properties(tbb PROPERTIES + INTERFACE_COMPILE_DEFINITIONS "$<$:TBB_USE_DEBUG=1>" + IMPORTED_LOCATION_DEBUG ${TBB_LIBRARIES_DEBUG} + IMPORTED_LOCATION_RELWITHDEBINFO ${TBB_LIBRARIES_DEBUG} + IMPORTED_LOCATION_RELEASE ${TBB_LIBRARIES_RELEASE} + IMPORTED_LOCATION_MINSIZEREL ${TBB_LIBRARIES_RELEASE} + ) + elseif(TBB_LIBRARIES_RELEASE) + set_target_properties(tbb PROPERTIES IMPORTED_LOCATION ${TBB_LIBRARIES_RELEASE}) + else() + set_target_properties(tbb PROPERTIES + IMPORTED_LOCATION ${TBB_LIBRARIES_DEBUG} + ) + endif() + endif() + + mark_as_advanced(TBB_INCLUDE_DIRS TBB_LIBRARIES) + + unset(TBB_ARCHITECTURE) + unset(TBB_BUILD_TYPE) + unset(TBB_LIB_PATH_SUFFIX) + unset(TBB_DEFAULT_SEARCH_DIR) + +endif() diff --git a/cmake/endian.cmake b/cmake/endian.cmake new file mode 100644 index 0000000000..c0be21b772 --- /dev/null +++ b/cmake/endian.cmake @@ -0,0 +1,8 @@ +INCLUDE(TestBigEndian) + +TEST_BIG_ENDIAN(BIGENDIAN) +if(${BIGENDIAN}) + ADD_DEFINITIONS(-DDYNINST_BIG_ENDIAN) +else() + ADD_DEFINITIONS(-DDYNINST_LITTLE_ENDIAN) +endif(${BIGENDIAN}) diff --git a/cmake/options.cmake b/cmake/options.cmake index 4ff74ce502..0ee49e333b 100644 --- a/cmake/options.cmake +++ b/cmake/options.cmake @@ -9,6 +9,10 @@ option (BUILD_RTLIB_32 "Build 32-bit runtime library on mixed 32/64 systems" OFF option(BUILD_RTLIB "Building runtime library (can be disabled safely for component-level builds)" ON) option(BUILD_DOCS "Build manuals from LaTeX sources" ON) +option(USE_COTIRE "Enable Cotire precompiled headers") +option(USE_GNU_DEMANGLER "Use cxa_demangle (ON) or binutils demangle (OFF)" ON) + +option (ENABLE_LTO "Enable Link-Time Optimization" OFF) # Some global on/off switches if (LIGHTWEIGHT_SYMTAB) diff --git a/cmake/packages.cmake b/cmake/packages.cmake index 0ae6ed2d7f..6a30490cc8 100644 --- a/cmake/packages.cmake +++ b/cmake/packages.cmake @@ -1,7 +1,7 @@ if (UNIX) find_package (LibDwarf) find_package (LibElf 0.173) - + find_package(TBB) if(NOT LIBELF_FOUND OR NOT LIBDWARF_FOUND) message(STATUS "Attempting to build elfutils as external project") cmake_minimum_required (VERSION 2.8.11) @@ -21,7 +21,26 @@ if (UNIX) else() set(SHOULD_INSTALL_LIBELF 0) endif() - + if(NOT TBB_FOUND) + message(STATUS "Attempting to build TBB as external project") + cmake_minimum_required (VERSION 2.8.11) + include(ExternalProject) + ExternalProject_Add(TBB + PREFIX ${CMAKE_BINARY_DIR}/tbb + STAMP_DIR ${CMAKE_BINARY_DIR}/tbb/src/TBB-stamp + URL https://github.com/01org/tbb/archive/2018_U6.tar.gz + SOURCE_DIR ${CMAKE_BINARY_DIR}/tbb/src/TBB/src + CONFIGURE_COMMAND "" + BINARY_DIR ${CMAKE_BINARY_DIR}/tbb/src/TBB/src + BUILD_COMMAND make -j${NCPU} tbb tbbmalloc compiler=gcc tbb_build_dir=${CMAKE_BINARY_DIR}/tbb/src/TBB-build tbb_build_prefix=tbb + INSTALL_COMMAND sh -c "mkdir -p ${CMAKE_BINARY_DIR}/tbb/include && mkdir -p ${CMAKE_BINARY_DIR}/tbb/lib \ + && cp ${CMAKE_BINARY_DIR}/tbb/src/TBB-build/tbb_release/*.so* ${CMAKE_BINARY_DIR}/tbb/lib \ + && cp -r ${CMAKE_BINARY_DIR}/tbb/src/TBB/src/include/* ${CMAKE_BINARY_DIR}/tbb/include" + ) + set(TBB_INCLUDE_DIRS ${CMAKE_BINARY_DIR}/tbb/include) + set(TBB_LIBRARIES ${CMAKE_BINARY_DIR}/tbb/libtbb.so ${CMAKE_BINARY_DIR}/tbb/libtbbmalloc_proxy.so) + set(TBB_FOUND 1) + endif() add_library(libelf_imp SHARED IMPORTED) set_property(TARGET libelf_imp PROPERTY IMPORTED_LOCATION ${LIBELF_LIBRARIES}) @@ -110,18 +129,20 @@ endif() if(DEFINED PATH_BOOST OR DEFINED Boost_INCLUDE_DIR OR DEFINED Boost_LIBRARY_DIR) - set(Boost_NO_SYSTEM_PATHS ON) +# set(Boost_NO_SYSTEM_PATHS ON) endif() -find_package (Boost ${BOOST_MIN_VERSION} COMPONENTS thread system date_time filesystem) - +find_package (Boost ${BOOST_MIN_VERSION} COMPONENTS thread system date_time timer filesystem atomic) if(NOT Boost_FOUND) set (BOOST_ARGS --with-system --with-thread --with-date_time + --with-filesystem + --with-timer + --with-atomic --ignore-site-config --link=static --runtime-link=shared @@ -157,28 +178,32 @@ if(NOT Boost_FOUND) BUILD_COMMAND ${BOOST_BUILD} ${BOOST_ARGS} stage INSTALL_COMMAND "" ) - set(Boost_INCLUDE_DIRS ${CMAKE_BINARY_DIR}/${BOOST_BASE}) + set(Boost_INCLUDE_DIR ${CMAKE_BINARY_DIR}/${BOOST_BASE}) set(Boost_LIBRARY_DIRS ${CMAKE_BINARY_DIR}/${BOOST_BASE}/stage/lib) if(MSVC) # We need to specify different library names for debug vs release set(Boost_LIBRARIES optimized libboost_thread-mt debug libboost_thread-mt-gd) list(APPEND Boost_LIBRARIES optimized libboost_system-mt debug libboost_system-mt-gd) list(APPEND Boost_LIBRARIES optimized libboost_date_time-mt debug libboost_date_time-mt-gd) + list(APPEND Boost_LIBRARIES optimized libboost_atomic-mt debug libboost_atomic-mt-gd) + else() - set(Boost_LIBRARIES boost_thread boost_system boost_date_time) + set(Boost_LIBRARIES boost_thread-mt boost_system-mt boost_date_time-mt boost_filesystem-mt boost_atomic-mt) endif() endif() link_directories ( ${Boost_LIBRARY_DIRS} ) include_directories ( - ${Boost_INCLUDE_DIRS} + ${Boost_INCLUDE_DIR} ) add_definitions(-DBOOST_MULTI_INDEX_DISABLE_SERIALIZATION) -message(STATUS "Boost includes: ${Boost_INCLUDE_DIRS}") +message(STATUS "Boost includes: ${Boost_INCLUDE_DIR}") message(STATUS "Boost library dirs: ${Boost_LIBRARY_DIRS}") message(STATUS "Boost thread library: ${Boost_THREAD_LIBRARY}") message(STATUS "Boost libraries: ${Boost_LIBRARIES}") +find_package(Threads) +set(Boost_LIBRARIES ${Boost_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT}) include(${DYNINST_ROOT}/cmake/CheckCXX11Features.cmake) if(NOT HAS_CXX11_AUTO) diff --git a/cmake/shared.cmake b/cmake/shared.cmake index 5254e7b625..023e9bb95d 100644 --- a/cmake/shared.cmake +++ b/cmake/shared.cmake @@ -3,7 +3,7 @@ set (DYNINST_MINOR_VERSION 3) set (DYNINST_PATCH_VERSION 2) # Debugging -# set(Boost_DEBUG 1) +set(Boost_DEBUG 1) add_definitions(-DBOOST_ALL_NO_LIB=1) set (SOVERSION "${DYNINST_MAJOR_VERSION}.${DYNINST_MINOR_VERSION}") @@ -87,9 +87,6 @@ endfunction() #Change to switch between libiberty/libstdc++ demangler -#set(USE_GNU_DEMANGLER 1) - -set (ENABLE_LTO FALSE CACHE BOOL "Enable Link-Time Optimization") set (CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${DYNINST_ROOT}/cmake/Modules") include (${DYNINST_ROOT}/cmake/platform.cmake) @@ -101,32 +98,32 @@ include (${DYNINST_ROOT}/cmake/visibility.cmake) include (${DYNINST_ROOT}/cmake/warnings.cmake) include (${DYNINST_ROOT}/cmake/options.cmake) include (${DYNINST_ROOT}/cmake/optimization.cmake) +include (${DYNINST_ROOT}/cmake/endian.cmake) # Check for cotire-gcc compatibility -set(USE_COTIRE true) IF(CMAKE_COMPILER_IS_GNUCC) execute_process(COMMAND ${CMAKE_C_COMPILER} -dumpversion OUTPUT_VARIABLE GCC_VERSION) string(REGEX MATCHALL "[0-9]+" GCC_VERSION_COMPONENTS ${GCC_VERSION}) IF(GCC_VERSION VERSION_LESS 4.5) - SET(USE_COTIRE false) + SET(USE_COTIRE OFF) ENDIF() ENDIF(CMAKE_COMPILER_IS_GNUCC) # If we're compiling for unix, cotire only supports Intel, GCC and Clang. IF (UNIX AND NOT ((${CMAKE_CXX_COMPILER_ID} MATCHES Clang) OR (${CMAKE_CXX_COMPILER_ID} MATCHES GNU) OR (${CMAKE_CXX_COMPILER_ID} MATCHES Intel))) - set(USE_COTIRE false) + set(USE_COTIRE OFF) ENDIF() # Make sure our CMake version is actually supported by cotire IF(CMAKE_VERSION VERSION_LESS 2.8.12) - SET(USE_COTIRE false) + SET(USE_COTIRE OFF) ENDIF() if (USE_COTIRE) include (${DYNINST_ROOT}/cmake/cotire.cmake) + set_directory_properties(PROPERTIES COTIRE_ADD_UNITY_BUILD FALSE) endif() -set_directory_properties(PROPERTIES COTIRE_ADD_UNITY_BUILD FALSE) set (BUILD_SHARED_LIBS ON) diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index 62b09f7e19..75497cc420 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -1,6 +1,5 @@ # CMake configuration for common directory - if(NOT WIN32) include_directories ( ${PROJECT_SOURCE_DIR}/common/h @@ -10,28 +9,28 @@ else() include_directories ( ${PROJECT_SOURCE_DIR}/common/h # don't include common/src; anything from there can still collide with default includes. # stupid Windows case-insensitive naming. + ${CILKSCREEN_INCLUDES} ) endif() set (SRC_LIST - src/Ident.C - src/string-regex.C + src/mcs-lock.C + src/pfq-rwlock.C + src/race-detector-annotations.C + src/string-regex.C src/Timer.C src/Types.C - src/debugOstream.C - src/lprintf.C + src/lprintf.C src/pathName.C src/Time.C - src/fraction.C + src/fraction.C src/timing.C src/stats.C src/Annotatable.C src/MappedFile.C src/sha1.C - src/serialize-bin.C - src/serialize-xml.C - src/util.C + src/util.C src/Node.C src/Graph.C src/Edge.C @@ -116,7 +115,7 @@ if(PLATFORM MATCHES nt OR PLATFORM MATCHES windows) target_link_private_libraries(common Psapi WS2_32 dbghelp) endif() target_link_private_libraries(common ${Boost_LIBRARIES}) - +target_link_libraries(common PUBLIC ${TBB_LIBRARIES}) IF (USE_COTIRE) cotire(common) diff --git a/common/h/IBSTree-fast.h b/common/h/IBSTree-fast.h index 6eb5dc86fe..5c6a64558e 100644 --- a/common/h/IBSTree-fast.h +++ b/common/h/IBSTree-fast.h @@ -42,53 +42,17 @@ #include #include - +#include "pfq-rwlock.h" namespace Dyninst { - template - struct Interval - { - typedef RangeType range_type; - RangeType first; - RangeType second; - template - Interval(T t) { - first = t.startAddr(); - second = t.endAddr(); - } - Interval(RangeType t) - { - first = t; - second = t; - } - Interval(RangeType start, RangeType end) - { - first = start; - second = end; - } - Interval merge(const Interval& other) - { - return Interval(std::min(first, other.first), std::max(second, other.second)); - } - bool operator==(const Interval& rhs) const { - return (first == rhs.first) && (second == rhs.second); - } - bool operator<(const Interval& rhs) const { - return (first < rhs.first) || ((first == rhs.first) && (second < rhs.second)); - } - bool operator==(RangeType off) const { - return ((first <= off) && (off < second)) || - ((first == off) && (off == second)); - } - struct by_low{}; - struct by_high{}; - - }; template - class IBSTree_fast - { + class IBSTree_fast { + private: + // reader-writer lock to coordinate concurrent operations + mutable pfq_rwlock_t rwlock; + public: typedef typename ITYPE::type interval_type; @@ -104,6 +68,7 @@ namespace Dyninst IBSTree_fast() { + pfq_rwlock_init(rwlock); } ~IBSTree_fast() { @@ -111,11 +76,17 @@ namespace Dyninst } int size() const { - return overlapping_intervals.size() + unique_intervals.size(); + pfq_rwlock_read_lock(rwlock); + int result = overlapping_intervals.size() + unique_intervals.size(); + pfq_rwlock_read_unlock(rwlock); + return result; } bool empty() const { - return unique_intervals.empty() && overlapping_intervals.empty(); + pfq_rwlock_read_lock(rwlock); + bool result = unique_intervals.empty() && overlapping_intervals.empty(); + pfq_rwlock_read_unlock(rwlock); + return result; } void insert(ITYPE*); void remove(ITYPE*); @@ -126,9 +97,11 @@ namespace Dyninst void clear(); friend std::ostream& operator<<(std::ostream& stream, const IBSTree_fast& tree) { + pfq_rwlock_read_lock(tree.rwlock); std::copy(tree.unique_intervals.begin(), tree.unique_intervals.end(), std::ostream_iterator::interval_set::value_type>(stream, "\n")); stream << tree.overlapping_intervals; + pfq_rwlock_read_unlock(tree.rwlock); return stream; } @@ -137,60 +110,78 @@ namespace Dyninst template void IBSTree_fast::insert(ITYPE* entry) { + pfq_rwlock_node_t me; + pfq_rwlock_write_lock(rwlock, me); + + do { // find in overlapping first std::set dummy; if(overlapping_intervals.find(entry, dummy)) { overlapping_intervals.insert(entry); - return; - } - typename interval_set::iterator lower = - unique_intervals.upper_bound(entry->low()); - // lower.high first >= entry.low - if(lower != unique_intervals.end() && (**lower == *entry)) return; - typename interval_set::iterator upper = lower; - while(upper != unique_intervals.end() && - (*upper)->low() <= entry->high()) - { - overlapping_intervals.insert(*upper); - ++upper; - } - if(upper != lower) - { - unique_intervals.erase(lower, upper); - overlapping_intervals.insert(entry); - } - else - { - unique_intervals.insert(entry); - } + } else { + typename interval_set::iterator lower = + unique_intervals.upper_bound(entry->low()); + // lower.high first >= entry.low + if (lower != unique_intervals.end() && (**lower == *entry)) break; + typename interval_set::iterator upper = lower; + while(upper != unique_intervals.end() && + (*upper)->low() <= entry->high()) + { + overlapping_intervals.insert(*upper); + ++upper; + } + if(upper != lower) + { + unique_intervals.erase(lower, upper); + overlapping_intervals.insert(entry); + } + else + { + unique_intervals.insert(entry); + } + } + } while(0); + + pfq_rwlock_write_unlock(rwlock, me); } template void IBSTree_fast::remove(ITYPE* entry) { + pfq_rwlock_node_t me; + pfq_rwlock_write_lock(rwlock, me); + overlapping_intervals.remove(entry); typename interval_set::iterator found = unique_intervals.find(entry->high()); if(found != unique_intervals.end() && *found == entry) unique_intervals.erase(found); + pfq_rwlock_write_unlock(rwlock, me); } template int IBSTree_fast::find(interval_type X, std::set &results) const { + int count = 0; + pfq_rwlock_read_lock(rwlock); + do { int num_old_results = results.size(); int num_overlapping = overlapping_intervals.find(X, results); - if(num_overlapping > 0) return num_overlapping; + if(num_overlapping > 0) { count = num_overlapping; break; } typename interval_set::const_iterator found_unique = unique_intervals.upper_bound(X); if(found_unique != unique_intervals.end()) { - if((*found_unique)->low() > X) return 0; + if((*found_unique)->low() > X) { count = 0; break; } results.insert(*found_unique); } - return results.size() - num_old_results; + count = results.size() - num_old_results; + } while (0); + pfq_rwlock_read_unlock(rwlock); + return count; } template int IBSTree_fast::find(ITYPE* I, std::set&results) const { + pfq_rwlock_read_lock(rwlock); int num_old_results = results.size(); int num_overlapping = overlapping_intervals.find(I, results); if(num_overlapping) return num_overlapping; @@ -201,11 +192,14 @@ namespace Dyninst results.insert(*ub); ++ub; } - return results.size() - num_old_results; + int result = results.size() - num_old_results; + pfq_rwlock_read_unlock(rwlock); + return result; } template void IBSTree_fast::successor(interval_type X, std::set& results) const { + pfq_rwlock_read_lock(rwlock); ITYPE* overlapping_ub = overlapping_intervals.successor(X); typename interval_set::const_iterator unique_ub = unique_intervals.upper_bound(X); @@ -221,6 +215,7 @@ namespace Dyninst { results.insert(*unique_ub); } + pfq_rwlock_read_unlock(rwlock); } template ITYPE* IBSTree_fast::successor(interval_type X) const @@ -230,13 +225,15 @@ namespace Dyninst assert(tmp.size() <= 1); if(tmp.empty()) return NULL; return *tmp.begin(); - } template void IBSTree_fast::clear() { + pfq_rwlock_node_t me; + pfq_rwlock_write_lock(rwlock, me); overlapping_intervals.clear(); unique_intervals.clear(); + pfq_rwlock_write_unlock(rwlock, me); } } diff --git a/common/h/IBSTree.h b/common/h/IBSTree.h index cb73f52ded..3979849e8a 100644 --- a/common/h/IBSTree.h +++ b/common/h/IBSTree.h @@ -39,6 +39,7 @@ #include #include "dyntypes.h" +#include "pfq-rwlock.h" #include #include @@ -181,20 +182,22 @@ class IBSTree { IBSNode *nil; +private: /** size of tree **/ - int treeSize; + boost::atomic treeSize; /** pointer to the tree root **/ IBSNode *root; + /** reader-writer lock to coordinate concurrent operations **/ + mutable pfq_rwlock_t rwlock; + /** RB-tree left rotation with modification to enforce IBS invariants **/ void leftRotate(IBSNode *); /** RB-tree right rotation with modification to enforce IBS invariants **/ void rightRotate(IBSNode *); - /** Node deletion **/ - void deleteFixup(IBSNode *); void removeInterval(IBSNode *R, ITYPE *range); @@ -239,7 +242,7 @@ class IBSTree { int height(IBSNode *n); int CountMarks(IBSNode *R) const; - unsigned MemUse() const; +public: friend std::ostream& operator<<(std::ostream& stream, const IBSTree& tree) { return stream << *(tree.root); @@ -250,9 +253,12 @@ class IBSTree { /** public for debugging purposes **/ //StatContainer stats_; - IBSTree() : treeSize(0) { - nil = new IBSNode; - root = nil; + IBSTree() : + nil(new IBSNode), + treeSize(0), + root(nil) + { + pfq_rwlock_init(rwlock); //stats_.add("insert",TimerStat); //stats_.add("remove",TimerStat); } @@ -262,21 +268,28 @@ class IBSTree { delete nil; } - size_type size() const { return treeSize; } + size_type size() const { + return treeSize.load(); + } const_iterator begin() const { + pfq_rwlock_read_lock(rwlock); iterator b = root; - while(root->left) b = root->left; + while(b->left) b = b->left; + pfq_rwlock_read_unlock(rwlock); return b; } const_iterator end() const { + pfq_rwlock_read_lock(rwlock); iterator e = root; - while(root->right) e = root->right; + while(e->right) e = e->right; + pfq_rwlock_read_unlock(rwlock); return e; - } int CountMarks() const; - bool empty() const { return (root == nil); } + bool empty() const { + return (root == nil); + } void insert(ITYPE *); @@ -296,7 +309,11 @@ class IBSTree { /** Delete all entries in the tree **/ void clear(); - void PrintPreorder() { PrintPreorder(root, 0); } + void PrintPreorder() { + pfq_rwlock_read_lock(rwlock); + PrintPreorder(root, 0); + pfq_rwlock_read_unlock(rwlock); + } }; template @@ -439,7 +456,7 @@ IBSTree::addLeft(ITYPE *I, IBSNode *R) if(R == nil) { // create a new node IBSNode *tmp = new IBSNode( ilow, nil ); - treeSize++; + treeSize.fetch_add(1); created = true; if(parent == NULL) // must be the root @@ -510,7 +527,7 @@ IBSTree::addRight(ITYPE *I, IBSNode *R) bool created = false; if(R == nil) { IBSNode *tmp = new IBSNode(ihigh,nil); - ++treeSize; + treeSize.fetch_add(1); created = true; if(parent == NULL) // must be the root root = tmp; @@ -768,6 +785,9 @@ void IBSTree::insert(ITYPE *range) { //stats_.startTimer("insert"); + pfq_rwlock_node_t me; + pfq_rwlock_write_lock(rwlock, me); + // Insert the endpoints of the range, rebalancing if new // nodes were created IBSNode *x = addLeft(range,root); @@ -779,6 +799,8 @@ void IBSTree::insert(ITYPE *range) insertFixup(x); } + pfq_rwlock_write_unlock(rwlock, me); + //stats_.stopTimer("insert"); } @@ -801,7 +823,12 @@ void IBSTree::remove(ITYPE * range) // the tests of the insertion procedures would avoid many of these // O(log n) lookups + pfq_rwlock_node_t me; + pfq_rwlock_write_lock(rwlock, me); + removeInterval(root,range); + + pfq_rwlock_write_unlock(rwlock, me); //stats_.startTimer("remove"); } @@ -810,7 +837,13 @@ template int IBSTree::find(interval_type X, std::set &out) const { unsigned size = out.size(); + + pfq_rwlock_read_lock(rwlock); + findIntervals(X,root,out); + + pfq_rwlock_read_unlock(rwlock); + return out.size() - size; } @@ -818,7 +851,13 @@ template int IBSTree::find(ITYPE * I, std::set &out) const { unsigned size = out.size(); + + pfq_rwlock_read_lock(rwlock); + findIntervals(I,root,out); + + pfq_rwlock_read_unlock(rwlock); + return out.size() - size; } @@ -830,6 +869,8 @@ void IBSTree::successor(interval_type X, std::set &out) const std::vector< IBSNode* > stack; + pfq_rwlock_read_lock(rwlock); + /* last will hold the node immediately greater than X */ while(1) { if(n == nil) { @@ -865,13 +906,21 @@ void IBSTree::successor(interval_type X, std::set &out) const n = n->left; } } + + pfq_rwlock_read_unlock(rwlock); } template ITYPE * IBSTree::successor(interval_type X) const { std::set out; + + pfq_rwlock_read_lock(rwlock); + successor(X,out); + + pfq_rwlock_read_unlock(rwlock); + assert( out.size() <= 1 ); if(!out.empty()) return *out.begin(); @@ -882,9 +931,15 @@ ITYPE * IBSTree::successor(interval_type X) const template void IBSTree::clear() { if(root == nil) return; + + pfq_rwlock_node_t me; + pfq_rwlock_write_lock(rwlock, me); + destroy(root); root = nil; - treeSize = 0; + treeSize.store(0); + + pfq_rwlock_write_unlock(rwlock, me); } template @@ -893,9 +948,13 @@ int IBSTree::height(IBSNode *n) if(!n) return 0; + pfq_rwlock_read_lock(rwlock); + int leftHeight = 1 + height(n->left); int rightHeight = 1 + height(n->right); + pfq_rwlock_read_unlock(rwlock); + if(leftHeight > rightHeight) return leftHeight; else @@ -928,7 +987,13 @@ void IBSTree::PrintPreorder(IBSNode *n, int indent) template int IBSTree::CountMarks() const { - return CountMarks(root); + pfq_rwlock_read_lock(rwlock); + + int nmarks = CountMarks(root); + + pfq_rwlock_read_unlock(rwlock); + + return nmarks; } }/* Dyninst */ diff --git a/common/h/dyntypes.h b/common/h/dyntypes.h index b7cd20eb55..c69b6f4b20 100644 --- a/common/h/dyntypes.h +++ b/common/h/dyntypes.h @@ -121,6 +121,12 @@ #error Unknown compiler #endif +// TODO: when should we use thread_local? +#if defined(_MSC_VER) + #define dyn_tls __declspec(thread) +#else + #define dyn_tls __thread +#endif namespace Dyninst { diff --git a/common/h/mcs-lock.h b/common/h/mcs-lock.h new file mode 100644 index 0000000000..2ca30faf97 --- /dev/null +++ b/common/h/mcs-lock.h @@ -0,0 +1,79 @@ +//*************************************************************************** +// +// File: +// mcs_lock.h +// +// Purpose: +// Define an API for the MCS lock: a fair queue-based lock. +// +// Reference: +// John M. Mellor-Crummey and Michael L. Scott. 1991. Algorithms for scalable +// synchronization on shared-memory multiprocessors. ACM Transactions on +// Computing Systems 9, 1 (February 1991), 21-65. +// http://doi.acm.org/10.1145/103727.103729 +//*************************************************************************** + + + +#ifndef _mcs_lock_h_ +#define _mcs_lock_h_ + +//****************************************************************************** +// global includes +//****************************************************************************** + +#include + + +//****************************************************************************** +// local includes +//****************************************************************************** + +#include "util.h" + + + +//****************************************************************************** +// types +//****************************************************************************** + +typedef struct mcs_node_s { + boost::atomic next; + boost::atomic blocked; +} mcs_node_t; + + +typedef struct { + boost::atomic tail; +} mcs_lock_t; + + + +//****************************************************************************** +// constants +//****************************************************************************** + +#define mcs_nil (struct mcs_node_s*) 0 + +//****************************************************************************** +// interface functions +//****************************************************************************** + +static inline void +mcs_init(mcs_lock_t &l) +{ + l.tail.store(mcs_nil); +} + +COMMON_EXPORT void +mcs_lock(mcs_lock_t &l, mcs_node_t &me); + + +COMMON_EXPORT bool +mcs_trylock(mcs_lock_t &l, mcs_node_t &me); + + +COMMON_EXPORT void +mcs_unlock(mcs_lock_t &l, mcs_node_t &me); + +#endif diff --git a/common/h/pfq-rwlock.h b/common/h/pfq-rwlock.h new file mode 100644 index 0000000000..f7616d6332 --- /dev/null +++ b/common/h/pfq-rwlock.h @@ -0,0 +1,99 @@ +//****************************************************************************** +// +// File: +// pfq_rwlock.h +// +// Purpose: +// Define the API for a fair, phased reader-writer lock with local spinning +// +// Reference: +// Björn B. Brandenburg and James H. Anderson. 2010. Spin-based reader-writer +// synchronization for multiprocessor real-time systems. Real-Time Systems +// 46(1):25-87 (September 2010). http://dx.doi.org/10.1007/s11241-010-9097-2 +// +// Notes: +// the reference uses a queue for arriving readers. on a cache coherent +// machine, the local spinning property for waiting readers can be achieved +// by simply using a cacheble flag. the implementation here uses that +// simplification. +// +//****************************************************************************** + +#ifndef __pfq_rwlock_h__ +#define __pfq_rwlock_h__ + + + +//****************************************************************************** +// global includes +//****************************************************************************** + +#include + + +//****************************************************************************** +// local includes +//****************************************************************************** + +#include "mcs-lock.h" + + +//****************************************************************************** +// macros +//****************************************************************************** + +// align a variable at the start of a cache line +#define cache_aligned __attribute__((aligned(128))) + + + +//****************************************************************************** +// types +//****************************************************************************** + +typedef mcs_node_t pfq_rwlock_node_t; + +typedef struct bigbool { + boost::atomic bit cache_aligned; +} bigbool; + +typedef struct { + //---------------------------------------------------------------------------- + // reader management + //---------------------------------------------------------------------------- + boost::atomic rin cache_aligned; // = 0 + boost::atomic rout cache_aligned; // = 0 + boost::atomic last cache_aligned; // = WRITER_PRESENT + bigbool writer_blocking_readers[2]; // false + + //---------------------------------------------------------------------------- + // writer management + //---------------------------------------------------------------------------- + mcs_lock_t wtail cache_aligned; // init + mcs_node_t *whead cache_aligned; // null + +} pfq_rwlock_t; + + + +//****************************************************************************** +// interface operations +//****************************************************************************** + +COMMON_EXPORT void +pfq_rwlock_init(pfq_rwlock_t &l); + +COMMON_EXPORT void +pfq_rwlock_read_lock(pfq_rwlock_t &l); + +COMMON_EXPORT void +pfq_rwlock_read_unlock(pfq_rwlock_t &l); + +COMMON_EXPORT void +pfq_rwlock_write_lock(pfq_rwlock_t &l, pfq_rwlock_node_t &me); + +COMMON_EXPORT void +pfq_rwlock_write_unlock(pfq_rwlock_t &l, pfq_rwlock_node_t &me); + + +#endif diff --git a/common/h/race-detector-annotations.h b/common/h/race-detector-annotations.h new file mode 100644 index 0000000000..d056ef2961 --- /dev/null +++ b/common/h/race-detector-annotations.h @@ -0,0 +1,27 @@ +#ifndef __race_detector_annotations_h__ +#define __race_detector_annotations_h__ + +#include "util.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef ENABLE_RACE_DETECTION + COMMON_EXPORT void race_detector_fake_lock_acquire(void *fake_lock); + COMMON_EXPORT void race_detector_fake_lock_release(void *fake_lock); + COMMON_EXPORT void race_detector_forget_access_history(void *loc, unsigned int nbytes); + +#else +#define race_detector_fake_lock_acquire(fake_lock) +#define race_detector_fake_lock_release(fake_lock) +#define race_detector_forget_access_history(loc, nbytes) +#endif + +#define race_detector_fake_lock(lock) ((void *) &lock) + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/common/h/util.h b/common/h/util.h index b1cc9e2fd4..0f226de829 100644 --- a/common/h/util.h +++ b/common/h/util.h @@ -216,7 +216,6 @@ #endif #endif - #ifndef __UTIL_H__ #define __UTIL_H__ diff --git a/common/src/LockTraits.h b/common/src/LockTraits.h new file mode 100644 index 0000000000..976fc89dc0 --- /dev/null +++ b/common/src/LockTraits.h @@ -0,0 +1,21 @@ +// +// Created by bill on 5/1/17. +// + +#ifndef DYNINST_LOCKTRAITS_H +#define DYNINST_LOCKTRAITS_H + +#include "dthread.h" + + +template >, + typename WriteLock = ReadLock> +class LockTraits { + typedef Mutex mutex_t; + typedef WriteLock lock_t; + typedef ReadLock readlock_t; +}; + + +#endif //DYNINST_LOCKTRAITS_H diff --git a/common/src/arch-aarch64.h b/common/src/arch-aarch64.h index 374ac91558..f9f7ab3859 100644 --- a/common/src/arch-aarch64.h +++ b/common/src/arch-aarch64.h @@ -187,6 +187,9 @@ class COMMON_EXPORT instruction { instruction(const void *ptr) { insn_ = *((const instructUnion *)ptr); } + instruction(const void *ptr, bool mode_64) { + insn_ = *((const instructUnion *)ptr); + } instruction(const instruction &insn) : insn_(insn.insn_) {}; instruction(instructUnion &insn) : diff --git a/common/src/arch-power.h b/common/src/arch-power.h index 9f46c037e1..7897977b24 100644 --- a/common/src/arch-power.h +++ b/common/src/arch-power.h @@ -803,7 +803,9 @@ class COMMON_EXPORT instruction { instruction(const void *ptr) { insn_ = *((const instructUnion *)ptr); } - + instruction(const void *ptr, bool mode_64) { + insn_ = *((const instructUnion *)ptr); + } instruction(const instruction &insn) : insn_(insn.insn_) {}; instruction(instructUnion &insn) : insn_(insn) {}; diff --git a/common/src/arch-x86.C b/common/src/arch-x86.C index a75ca953ce..9e11c509e0 100644 --- a/common/src/arch-x86.C +++ b/common/src/arch-x86.C @@ -123,7 +123,7 @@ * The main objective of the decoding process is to get the length of the instruction * correct. Because x86 has variable length instructions, getting the instruction * length wrong will mess up the decoding for the instructions that follow. - * + * * */ @@ -136,11 +136,13 @@ #include #include #include +#include // once_flag, call_once #include "boost/assign/list_of.hpp" #include "boost/assign/std/vector.hpp" #include "boost/assign/std/set.hpp" - +#include +#include #include "common/src/arch-x86.h" #include "dyn_regs.h" @@ -2007,13 +2009,13 @@ dyn_hash_map prefixEntryNames_IAPI = map_list_of (prefix_repnz, "REPNZ") ; +dyn_hash_map ia32_instruction::flagTable; + + COMMON_EXPORT dyn_hash_map const& ia32_instruction::getFlagTable() { - static dyn_hash_map flagTable; - if(flagTable.empty()) - { - ia32_instruction::initFlagTable(flagTable); - } + static std::once_flag flagTableInit; + std::call_once(flagTableInit, [&]() {initFlagTable(flagTable);}); return flagTable; } @@ -2197,8 +2199,8 @@ bool ia32_entry::flagsUsed(std::set& flagsRead, std::set If this is a B, then the Mod value was 3 * | +-------> This is the value of the Reg value in binary * +-------------------> This is the group number. - * + * */ /* rows are none or 66 prefixed in this order (see book) */ @@ -8067,7 +8069,7 @@ static struct ia32_entry vexWMap[][2] = { e_vgatherdpd, t_done, 0, true, { Vpd, Wpd, Hpd }, 0, s1RW2R3RW, 0 } /* W = 1 */ }, { /* VEXW25 */ { e_vgatherqps, t_done, 0, true, { Vps, Wps, Hps }, 0, s1RW2R3RW, 0 }, /* W = 0 */ - { e_vgatherqpd, t_done, 0, true, { Vpd, Wpd, Hpd }, 0, s1RW2R3RW, 0 } /* W = 1 */ + { e_vgatherqpd, t_done, 0, true, { Vpd, Wpd, Hpd }, 0, s1RW2R3RW, 0 } /* W = 1 */ }, { /* VEXW26 */ { e_vpextrd, t_done, 0, true, { Vpd, Wpd, Ib }, 0, s1W2R3R, 0 }, /* W = 0 */ { e_vpextrq, t_done, 0, true, { Vpd, Wpd, Ib }, 0, s1W2R3R, 0 } /* W = 1 */ @@ -8418,13 +8420,9 @@ void ia32_set_mode_64(bool mode) { mode_64 = mode; } -bool ia32_is_mode_64() { - return mode_64; -} - ia32_entry movsxd = { e_movsxd, t_done, 0, true, { Gv, Ed, Zz }, 0, s1W2R, 0 }; ia32_entry invalid = { e_No_Entry, t_ill, 0, true, { Zz, Zz, Zz }, 0, 0, 0 }; -ia32_entry seg_mov = { e_mov, t_done, 0, true, {Ev, Sw, Zz}, 0, s1W2R, 0 }; +ia32_entry seg_mov = { e_mov, t_done, 0, true, {Ev, Sw, Zz}, 0, s1W2R, 0 }; static void ia32_translate_for_64(ia32_entry** gotit_ptr) { if (*gotit_ptr == &oneByteMap[0x63]) // APRL redefined to MOVSXD @@ -8463,11 +8461,8 @@ static void ia32_translate_for_64(ia32_entry** gotit_ptr) } /* full decoding version: supports memory access information */ -static unsigned int ia32_decode_modrm(const unsigned int addrSzAttr, - const unsigned char* addr, - ia32_memacc* macadr, - const ia32_prefixes* pref, - ia32_locations *pos); +static unsigned int ia32_decode_modrm(const unsigned int addrSzAttr, const unsigned char *addr, ia32_memacc *macadr, + const ia32_prefixes *pref, ia32_locations *pos, bool mode_64); void ia32_memacc::print() @@ -8507,18 +8502,18 @@ int getOperSz(const ia32_prefixes &pref) * @param addr A pointer to the start of the instruction that should be decoded. * @param instruc A reference to an ia32_instruction that should be setup with the decoded instruction. */ -ia32_instruction& ia32_decode(unsigned int capa, const unsigned char* addr, ia32_instruction& instruct) +ia32_instruction &ia32_decode(unsigned int capa, const unsigned char *addr, ia32_instruction &instruct, bool mode_64) { const unsigned char* addr_orig = addr; /* The original start to this instruction (addr will change) */ ia32_prefixes& pref = instruct.prf; /* A reference to the prefix information for this instruction */ ia32_entry *gotit = NULL; /* A pointer to the descriptor for the decoded instruction */ - /* If we are being assed to decode memory accesses, then instrut.mac must not be null. */ + /* If we are being assed to decode memory accesses, then instrut.mac must not be null. */ if(capa & IA32_DECODE_MEMACCESS) assert(instruct.mac != NULL); /* First decode any prefixes for this instruction */ - if (!ia32_decode_prefixes(addr, instruct)) + if (!ia32_decode_prefixes(addr, instruct, mode_64)) { #ifdef VEX_DEBUG fprintf(stderr, "PREFIX DECODE FAILURE\n"); @@ -8535,7 +8530,7 @@ ia32_instruction& ia32_decode(unsigned int capa, const unsigned char* addr, ia32 /* Get the entry in the decoding tables */ int opcode_decoding; - if((opcode_decoding = ia32_decode_opcode(capa, addr, instruct, &gotit))) + if((opcode_decoding = ia32_decode_opcode(capa, addr, instruct, &gotit, mode_64))) { if(opcode_decoding > 0) { @@ -8556,7 +8551,7 @@ ia32_instruction& ia32_decode(unsigned int capa, const unsigned char* addr, ia32 addr = addr_orig + instruct.size; /* Do the operand decoding */ - ia32_decode_operands(pref, *gotit, addr, instruct, instruct.mac); + ia32_decode_operands(pref, *gotit, addr, instruct, instruct.mac, mode_64); /* Decode the memory accesses if requested */ if(capa & IA32_DECODE_MEMACCESS) @@ -8773,7 +8768,9 @@ ia32_instruction& ia32_decode(unsigned int capa, const unsigned char* addr, ia32 default: break; } +#if STUB_OUT_TO_AVOID_RACE gotit->id = newID; +#endif } instruct.entry = gotit; @@ -8791,8 +8788,8 @@ ia32_instruction& ia32_decode(unsigned int capa, const unsigned char* addr, ia32 * @return >= 0 on success. < 0 on failure. A result greater that zero usually means * that it was an FPU instruction that has been fully decoded. */ -int ia32_decode_opcode(unsigned int capa, const unsigned char* addr, - ia32_instruction& instruct, ia32_entry** gotit_ret) +int ia32_decode_opcode(unsigned int capa, const unsigned char *addr, ia32_instruction &instruct, ia32_entry **gotit_ret, + bool mode_64) { ia32_prefixes& pref = instruct.prf; unsigned int table, nxtab, idx; @@ -9105,8 +9102,7 @@ int ia32_decode_opcode(unsigned int capa, const unsigned char* addr, unsigned int reg = (addr[0] >> 3) & 7; unsigned int mod = addr[0] >> 6; gotit = &fpuMap[gotit->tabidx][mod==3][reg]; - ia32_decode_FP(idx, pref, addr, - instruct, gotit, instruct.mac); + ia32_decode_FP(idx, pref, addr, instruct, gotit, instruct.mac, mode_64); if(gotit_ret) *gotit_ret = gotit; @@ -9276,9 +9272,9 @@ int ia32_decode_opcode(unsigned int capa, const unsigned char* addr, return 0; } -ia32_instruction& ia32_decode_FP(unsigned int opcode, const ia32_prefixes& pref, - const unsigned char* addr, ia32_instruction& instruct, - ia32_entry * entry, ia32_memacc *mac) +ia32_instruction & +ia32_decode_FP(unsigned int opcode, const ia32_prefixes &pref, const unsigned char *addr, ia32_instruction &instruct, + ia32_entry *entry, ia32_memacc *mac, bool mode_64) { // addr points after the opcode, and the size has been adjusted accordingly if (instruct.loc) instruct.loc->opcode_size = instruct.size - pref.getCount(); @@ -9296,7 +9292,7 @@ ia32_instruction& ia32_decode_FP(unsigned int opcode, const ia32_prefixes& pref, instruct.loc->opcode_size; instruct.loc->modrm_operand = 0; } - nib += ia32_decode_modrm(addrSzAttr, addr, mac, &pref, instruct.loc); + nib += ia32_decode_modrm(addrSzAttr, addr, mac, &pref, instruct.loc, mode_64); // also need to check for AMD64 rip-relative data addressing // occurs when mod == 0 and r/m == 101 if (mode_64) @@ -9487,15 +9483,12 @@ ia32_instruction& ia32_decode_FP(unsigned int opcode, const ia32_prefixes& pref, #define MODRM_SET_RM(x, y) ((x) |= (y)) #define MODRM_SET_REG(x, y) ((x) |= ((y) << 3)) -static unsigned int ia32_decode_modrm(const unsigned int addrSzAttr, - const unsigned char* addr, - ia32_memacc* macadr, - const ia32_prefixes* pref, - ia32_locations *loc) +static unsigned int ia32_decode_modrm(const unsigned int addrSzAttr, const unsigned char *addr, ia32_memacc *macadr, + const ia32_prefixes *pref, ia32_locations *loc, bool mode_64) { - /** + /** * ModR/M Format: - * 11 111 111 + * 11 111 111 * | | +-> R/M bits * | +------> REG bits * +----------> MOD bits @@ -9507,7 +9500,7 @@ static unsigned int ia32_decode_modrm(const unsigned int addrSzAttr, unsigned char reg = MODRM_REG(modrm); /* If locations are provided, configure them */ - if (loc) + if (loc) { loc->modrm_byte = modrm; loc->modrm_mod = mod; @@ -9527,12 +9520,12 @@ static unsigned int ia32_decode_modrm(const unsigned int addrSzAttr, if(addrSzAttr == 1) // 16-bit, cannot have SIB { /* This mode can only occur when running in 32 bit mode. */ - switch(mod) + switch(mod) { case 0: if(macadr) { - switch (rm) + switch (rm) { case 0: // [BX+SI] macadr->set16(mBX, mSI, 0); @@ -9552,14 +9545,14 @@ static unsigned int ia32_decode_modrm(const unsigned int addrSzAttr, case 5: macadr->set16(mDI, -1, 0); break; - case 6: + case 6: macadr->set16(-1, -1, *disp16); - if (loc) - { + if (loc) + { loc->disp_position = loc->modrm_position + 1; loc->disp_size = 2; /* 16 bit displacement */ } - break; + break; case 7: macadr->set16(mBX, -1, 0); break; @@ -9571,7 +9564,7 @@ static unsigned int ia32_decode_modrm(const unsigned int addrSzAttr, return rm == 6 ? wordSzB : 0; case 1: - if(macadr) + if(macadr) { if (loc) { @@ -9579,9 +9572,9 @@ static unsigned int ia32_decode_modrm(const unsigned int addrSzAttr, loc->disp_size = 1; } - switch (rm) + switch (rm) { - case 0: + case 0: macadr->set16(mBX, mSI, *disp8); break; case 1: @@ -9613,17 +9606,17 @@ static unsigned int ia32_decode_modrm(const unsigned int addrSzAttr, return byteSzB; case 2: - if(macadr) + if(macadr) { - if (loc) - { + if (loc) + { loc->disp_position = loc->modrm_position + 1; loc->disp_size = 2; } - switch (rm) + switch (rm) { - case 0: + case 0: macadr->set16(mBX, mSI, *disp16); break; case 1: @@ -9674,15 +9667,15 @@ static unsigned int ia32_decode_modrm(const unsigned int addrSzAttr, int base = 0, scale = -1, index = -1; // prevent g++ from whining. /* Do we have an sib? */ - if(hassib) + if(hassib) { /* Grab the sib */ sib = addr[0]; nsib = byteSzB; /* Update locations if needed */ - if (loc) - { + if (loc) + { loc->sib_position = loc->modrm_position + 1; loc->sib_byte = sib; } @@ -9691,7 +9684,7 @@ static unsigned int ia32_decode_modrm(const unsigned int addrSzAttr, addr++; base = sib & 7; - if(macadr) + if(macadr) { scale = sib >> 6; index = (sib >> 3) & 7; @@ -9701,7 +9694,7 @@ static unsigned int ia32_decode_modrm(const unsigned int addrSzAttr, index = -1; } } - + /* Update displacement pointers */ disp8 = (const char*)addr; disp16 = (const short*)addr; @@ -9710,12 +9703,12 @@ static unsigned int ia32_decode_modrm(const unsigned int addrSzAttr, /* this is tricky: there is a disp32 iff (1) rm == 5 or (2) hassib && base == 5 */ unsigned char check5 = hassib ? base : rm; - switch(mod) + switch(mod) { - case 0: + case 0: if(macadr) { - switch (rm) + switch (rm) { case 0: macadr->set(apply_rex_bit(mEAX, pref->rexB()), 0, addrSzAttr); @@ -9730,27 +9723,27 @@ static unsigned int ia32_decode_modrm(const unsigned int addrSzAttr, macadr->set(apply_rex_bit(mEBX, pref->rexB()), 0, addrSzAttr); break; case 4: // SIB - if(base == 5) - { + if(base == 5) + { // disp32[index<disp_position = loc->sib_position + 1; loc->disp_size = 4; } - macadr->set_sib(-1, scale, apply_rex_bit(index, pref->rexX()), + macadr->set_sib(-1, scale, apply_rex_bit(index, pref->rexX()), *disp32, addrSzAttr); } else { - macadr->set_sib(apply_rex_bit(base, pref->rexB()), scale, + macadr->set_sib(apply_rex_bit(base, pref->rexB()), scale, apply_rex_bit(index, pref->rexX()), 0, addrSzAttr); } break; - case 5: - { + case 5: + { // disp32 (or [RIP + disp32] for 64-bit mode) - if (loc) - { + if (loc) + { loc->disp_position = loc->modrm_position + 1; loc->disp_size = 4; } @@ -9759,7 +9752,7 @@ static unsigned int ia32_decode_modrm(const unsigned int addrSzAttr, macadr->set(mRIP, *disp32, addrSzAttr); else macadr->set(-1, *disp32, addrSzAttr); - break; + break; } case 6: macadr->set(apply_rex_bit(mESI, pref->rexB()), 0, addrSzAttr); @@ -9775,15 +9768,15 @@ static unsigned int ia32_decode_modrm(const unsigned int addrSzAttr, return nsib + ((check5 == 5) ? dwordSzB : 0); case 1: - if(macadr) + if(macadr) { - if (loc) - { + if (loc) + { loc->disp_position = loc->modrm_position + 1; loc->disp_size = 1; } - switch (rm) + switch (rm) { case 0: macadr->set(apply_rex_bit(mEAX, pref->rexB()), *disp8, addrSzAttr); @@ -9799,10 +9792,10 @@ static unsigned int ia32_decode_modrm(const unsigned int addrSzAttr, break; case 4: // disp8[EBP + index<disp_position = loc->sib_position + 1; loc->disp_size = 1; - } + } macadr->set_sib(apply_rex_bit(base, pref->rexB()), scale, apply_rex_bit(index, pref->rexX()), *disp8, addrSzAttr); break; @@ -9820,15 +9813,15 @@ static unsigned int ia32_decode_modrm(const unsigned int addrSzAttr, return nsib + byteSzB; case 2: - if(macadr) + if(macadr) { - if (loc) - { + if (loc) + { loc->disp_position = loc->modrm_position + 1; loc->disp_size = 4; } - switch (rm) + switch (rm) { case 0: macadr->set(apply_rex_bit(mEAX, pref->rexB()), *disp32, addrSzAttr); @@ -9844,7 +9837,7 @@ static unsigned int ia32_decode_modrm(const unsigned int addrSzAttr, break; case 4: // disp32[EBP + index<disp_position = loc->sib_position + 1; loc->disp_size = 4; } @@ -9939,16 +9932,16 @@ static inline int type2size(unsigned int optype, unsigned int operSzAttr) } unsigned int ia32_decode_operands (const ia32_prefixes& pref, - const ia32_entry& gotit, - const unsigned char* addr, - ia32_instruction& instruct, - ia32_memacc *mac) + const ia32_entry& gotit, + const unsigned char* addr, + ia32_instruction& instruct, + ia32_memacc *mac, bool mode_64) { /* # of bytes in instruction */ - unsigned int nib = 0; + unsigned int nib = 0; ia32_locations *loc = instruct.loc; - if(loc) + if(loc) loc->imm_cnt = 0; /* If the prefix is present, the address size changes to 16 bit */ @@ -9967,11 +9960,11 @@ unsigned int ia32_decode_operands (const ia32_prefixes& pref, { const ia32_operand& op = gotit.operands[i]; - if(op.admet) + if(op.admet) { // At most two operands can be memory, the third is register or immediate //assert(i<2 || op.admet == am_reg || op.admet == am_I); - switch(op.admet) + switch(op.admet) { case am_A: /* address = segment + offset (word or dword or qword) */ nib += wordSzB; // segment @@ -9979,10 +9972,10 @@ unsigned int ia32_decode_operands (const ia32_prefixes& pref, break; case am_O: /* operand offset */ nib += wordSzB * addrSzAttr; - if(mac) + if(mac) { int offset = 0; - switch(addrSzAttr) + switch(addrSzAttr) { case 1: // 16-bit offset offset = *((const short int*)addr); @@ -10024,7 +10017,7 @@ unsigned int ia32_decode_operands (const ia32_prefixes& pref, case am_H: /* XMM, YMM or ZMM register (vvvv of prefix) */ case am_HK: /* K register (vvvv of prefix) */ case am_VK: /* K register (vvvv of prefix) */ - case am_reg: /* register implicitely encoded in opcode */ + case am_reg: /* register implicitely encoded in opcode */ case am_allgprs: break; case am_E: /* register or memory location, so decoding needed */ @@ -10036,7 +10029,7 @@ unsigned int ia32_decode_operands (const ia32_prefixes& pref, case am_YW: /* XMM or YMM register or memory location */ case am_W: /* XMM, YMM or ZMM register or memory location */ case am_WK: /* K register (vvvv of prefix) */ - if (loc) + if (loc) { loc->modrm_position = loc->opcode_size + loc->opcode_position; loc->modrm_operand = i; @@ -10044,13 +10037,13 @@ unsigned int ia32_decode_operands (const ia32_prefixes& pref, if(mac) { - nib += ia32_decode_modrm(addrSzAttr, addr, &mac[i], &pref, loc); + nib += ia32_decode_modrm(addrSzAttr, addr, &mac[i], &pref, loc, mode_64); mac[i].size = type2size(op.optype, operSzAttr); - if (loc) + if (loc) loc->address_size = mac[i].size; } else { - nib += ia32_decode_modrm(addrSzAttr, addr, NULL, &pref, loc); + nib += ia32_decode_modrm(addrSzAttr, addr, NULL, &pref, loc, mode_64); } // also need to check for AMD64 rip-relative data addressing @@ -10061,16 +10054,16 @@ unsigned int ia32_decode_operands (const ia32_prefixes& pref, break; case am_I: /* immediate data */ case am_J: /* instruction pointer offset */ - { + { int imm_size = type2size(op.optype, operSzAttr); - if (loc) + if (loc) { // sanity - if(loc->imm_cnt > 1) + if(loc->imm_cnt > 1) { fprintf(stderr,"Oops, more than two immediate operands\n"); } else { - loc->imm_position[loc->imm_cnt] = + loc->imm_position[loc->imm_cnt] = nib + loc->opcode_position + loc->opcode_size; loc->imm_size[loc->imm_cnt] = imm_size; ++loc->imm_cnt; @@ -10099,7 +10092,7 @@ unsigned int ia32_decode_operands (const ia32_prefixes& pref, #endif assert(0 && "Bad addressing mode!"); } - } else { + } else { break; } } @@ -10110,9 +10103,9 @@ unsigned int ia32_decode_operands (const ia32_prefixes& pref, /* This last one is always Ib */ int imm_size = type2size(op_b, operSzAttr); - if (loc) + if (loc) { - if(loc->imm_cnt > 1) + if(loc->imm_cnt > 1) { fprintf(stderr,"Oops, more than two immediate operands\n"); } else { @@ -10184,7 +10177,7 @@ unsigned int ia32_decode_operands (const ia32_prefixes& pref, while((mac[index].regs[0] != -1) || (mac[index].regs[1] != -1) || (mac[index].scale != 0) || - (mac[index].imm != 0)) + (mac[index].imm != 0)) { index++; assert(index < 3); @@ -10281,10 +10274,10 @@ bool is_sse_opcode(unsigned char byte1, unsigned char byte2, unsigned char byte3 * * @return true if the prefixes were decoded successfully, false if there was a problem. */ -bool ia32_decode_prefixes(const unsigned char* addr, ia32_instruction& instruct) + bool ia32_decode_prefixes(const unsigned char *addr, ia32_instruction &instruct, bool mode_64) { ia32_prefixes& pref = instruct.prf; - ia32_locations* loc = instruct.loc; + ia32_locations* loc = instruct.loc; /* Initilize the prefix */ memset(pref.prfx, 0, 5); @@ -10311,7 +10304,7 @@ bool ia32_decode_prefixes(const unsigned char* addr, ia32_instruction& instruct) bool err = false; - while(in_prefix && !err) + while(in_prefix && !err) { /** * Switch based on the current byte. If the current byte @@ -10323,16 +10316,16 @@ bool ia32_decode_prefixes(const unsigned char* addr, ia32_instruction& instruct) * some prefixes cannot go together. */ - switch(addr[0]) + switch(addr[0]) { case PREFIX_REPNZ: case PREFIX_REP: - if(mode_64 && REX_ISREX(addr[1]) - && is_sse_opcode(addr[2],addr[3],addr[4])) + if(mode_64 && REX_ISREX(addr[1]) + && is_sse_opcode(addr[2],addr[3],addr[4])) { ++pref.count; pref.opcode_prefix = addr[0]; - } else if(is_sse_opcode(addr[1],addr[2],addr[3])) + } else if(is_sse_opcode(addr[1],addr[2],addr[3])) { ++pref.count; pref.opcode_prefix = addr[0]; @@ -10501,7 +10494,7 @@ bool ia32_decode_prefixes(const unsigned char* addr, ia32_instruction& instruct) } /* VEX prefixes exclude all others */ - in_prefix = false; + in_prefix = false; break; default: // If we hit a REX prefix, keep going and process other potential prefixes. @@ -10516,7 +10509,7 @@ bool ia32_decode_prefixes(const unsigned char* addr, ia32_instruction& instruct) break; } - if(!REX_ISREX(addr[0])) + if(!REX_ISREX(addr[0])) { /* We probably hit the opcode now */ in_prefix = false; @@ -10528,7 +10521,7 @@ bool ia32_decode_prefixes(const unsigned char* addr, ia32_instruction& instruct) in_prefix = false; } break; - } + } /* Move to the next byte */ ++addr; @@ -10545,40 +10538,40 @@ bool ia32_decode_prefixes(const unsigned char* addr, ia32_instruction& instruct) /* Print debug information that is super helpful for VEX debugging. */ #ifdef VEX_DEBUG /* Print out prefix information (very verbose) */ - fprintf(stderr, "Prefix buffer: %x %x %x %x %x\n", pref.prfx[0], pref.prfx[1], + fprintf(stderr, "Prefix buffer: %x %x %x %x %x\n", pref.prfx[0], pref.prfx[1], pref.prfx[2], pref.prfx[3], pref.prfx[4]); fprintf(stderr, "opcode prefix: 0x%x\n", pref.opcode_prefix); fprintf(stderr, "REX W: %s R: %s X: %s B: %s\n", - pref.rexW() ? "yes" : "no", pref.rexR() ? "yes" : "no", + pref.rexW() ? "yes" : "no", pref.rexR() ? "yes" : "no", pref.rexX() ? "yes" : "no", pref.rexB() ? "yes" : "no"); fprintf(stderr, "IS VEX PRESENT? %s\n", pref.vex_present ? "YES" : "NO"); if(pref.vex_present) { - fprintf(stderr, "VEX IS PRESENT: %d\n", + fprintf(stderr, "VEX IS PRESENT: %d\n", pref.vex_type); fprintf(stderr, "VEX BYTES: %x %x %x %x %x\n", pref.vex_prefix[0], pref.vex_prefix[1], pref.vex_prefix[2], pref.vex_prefix[3], pref.vex_prefix[4]); - fprintf(stderr, "VEX SSE MULT: %d 0x%x\n", + fprintf(stderr, "VEX SSE MULT: %d 0x%x\n", pref.vex_sse_mult, pref.vex_sse_mult); - fprintf(stderr, "VEX_VVVV: %d 0x%x\n", + fprintf(stderr, "VEX_VVVV: %d 0x%x\n", pref.vex_vvvv_reg, pref.vex_vvvv_reg); - fprintf(stderr, "VEX_LL: %d 0x%x\n", + fprintf(stderr, "VEX_LL: %d 0x%x\n", pref.vex_ll, pref.vex_ll); - fprintf(stderr, "VEX_PP: %d 0x%x\n", + fprintf(stderr, "VEX_PP: %d 0x%x\n", pref.vex_pp, pref.vex_pp); - fprintf(stderr, "VEX_M-MMMM: %d 0x%x\n", + fprintf(stderr, "VEX_M-MMMM: %d 0x%x\n", pref.vex_m_mmmm, pref.vex_m_mmmm); - fprintf(stderr, "VEX_W: %d 0x%x\n", + fprintf(stderr, "VEX_W: %d 0x%x\n", pref.vex_w, pref.vex_w); - fprintf(stderr, "VEX_r: %d 0x%x\n", + fprintf(stderr, "VEX_r: %d 0x%x\n", pref.vex_r, pref.vex_r); - fprintf(stderr, "VEX_R: %d 0x%x\n", + fprintf(stderr, "VEX_R: %d 0x%x\n", pref.vex_R, pref.vex_R); - fprintf(stderr, "VEX_x: %d 0x%x\n", + fprintf(stderr, "VEX_x: %d 0x%x\n", pref.vex_x, pref.vex_x); - fprintf(stderr, "VEX_b: %d 0x%x\n", + fprintf(stderr, "VEX_b: %d 0x%x\n", pref.vex_b, pref.vex_b); } #endif @@ -10600,7 +10593,7 @@ bool ia32_decode_prefixes(const unsigned char* addr, ia32_instruction& instruct) bool ia32_decode_rex(const unsigned char* addr, ia32_prefixes& pref, ia32_locations *loc) { - if (REX_ISREX(addr[0])) + if (REX_ISREX(addr[0])) { /** * it is an error to have legacy prefixes after a REX prefix @@ -10626,11 +10619,11 @@ bool ia32_decode_rex(const unsigned char* addr, ia32_prefixes& pref, } /* We also must ignore all but the last REX prefix. */ - if(REX_ISREX(addr[1])) + if(REX_ISREX(addr[1])) return false; /* Set the locations for this REX prefix. */ - if (loc) + if (loc) { loc->rex_byte = addr[0]; loc->rex_w = REX_W(addr[0]); @@ -10661,7 +10654,7 @@ bool ia32_decode_rex(const unsigned char* addr, ia32_prefixes& pref, return true; } -unsigned int ia32_emulate_old_type(ia32_instruction& instruct) +unsigned int ia32_emulate_old_type(ia32_instruction &instruct, bool mode_64) { const ia32_prefixes& pref = instruct.prf; unsigned int& insnType = instruct.legacy_type; @@ -10724,15 +10717,15 @@ unsigned int ia32_emulate_old_type(ia32_instruction& instruct) /* decode instruction at address addr, return size of instruction */ unsigned get_instruction(const unsigned char* addr, unsigned &insnType, - const unsigned char** op_ptr) + const unsigned char** op_ptr, bool mode_64) { int r1; - ia32_instruction i; - ia32_decode(0, addr, i); + ia32_instruction i; + ia32_decode(0, addr, i, mode_64); r1 = i.getSize(); - insnType = ia32_emulate_old_type(i); + insnType = ia32_emulate_old_type(i, mode_64); if (op_ptr) *op_ptr = addr + i.getPrefixCount(); @@ -10797,7 +10790,7 @@ int displacement(const unsigned char *instr, unsigned type) { } else if (type & REL_D) { disp = *(const int *)(instr+1); } - } + } return disp; } @@ -10845,7 +10838,7 @@ unsigned copy_prefixes(const unsigned char *&origInsn, unsigned char *&newInsn, //Copy all prefixes but the Operand-Size and Address-Size prefixes (0x66 and 0x67) unsigned copy_prefixes_nosize(const unsigned char *&origInsn, unsigned char *&newInsn, - unsigned insnType) + unsigned insnType) { unsigned nPrefixes = count_prefixes(insnType); @@ -10942,7 +10935,7 @@ skip_headers(const unsigned char* addr, ia32_instruction* instruct) ia32_instruction tmp; if(!instruct) instruct = &tmp; - ia32_decode_prefixes(addr, *instruct); + ia32_decode_prefixes(addr, *instruct, false); return addr + instruct->getSize(); } @@ -11016,49 +11009,6 @@ entryID ia32_entry::getID(ia32_locations* l) const return id; } -Address get_immediate_operand(instruction *instr) -{ - ia32_memacc mac[3]; - ia32_condition cond; - ia32_locations loc; - ia32_instruction detail(mac,&cond,&loc); - - ia32_decode(IA32_FULL_DECODER,(const unsigned char *)(instr->ptr()),detail); - - if (loc.imm_cnt < 1) - return 0; - - // now find the immediate value in the locations - Address immediate = 0; - - switch(loc.imm_size[0]) { - case 8: - immediate = *(const unsigned long*)(instr->ptr()+loc.imm_position[0]); - break; - case 4: - immediate = *(const unsigned int*)(instr->ptr()+loc.imm_position[0]); - break; - case 2: - immediate = *(const unsigned short*)(instr->ptr()+loc.imm_position[0]); - break; - case 1: - immediate = *(const unsigned char*)(instr->ptr()+loc.imm_position[0]); - break; - default: - // fprintf(stderr,"%s[%u]: invalid immediate size %d in insn\n", - // FILE__,__LINE__,loc.imm_size[0]); - break; - } - - return immediate; -} - -// get the displacement of a relative jump or call - -int get_disp(instruction *insn) { - return displacement(insn->ptr(), insn->type()); -} - bool isStackFramePrecheck_gcc( const unsigned char *buffer ) { //Currently enabled entry bytes for gaps: @@ -11109,9 +11059,9 @@ bool isStackFramePrecheck_msvs( const unsigned char *buffer ) /* bool isStackFramePreamble( instruction& insn1 ) - { + { instruction insn2, insn3; - insn2.setInstruction( insn1.ptr() + insn1.size() ); + insn2.setInstruction( insn1.ptr() + insn1.size() ); insn3.setInstruction( insn2.ptr() + insn2.size() ); const unsigned char* p = insn1.op_ptr(); @@ -11129,16 +11079,16 @@ bool isStackFramePrecheck_msvs( const unsigned char *buffer ) } if( p[ 0 ] == PUSHEBP ) - { + { // Looking for mov %esp -> %ebp in one of the two -// following instructions. There are two ways to encode -// mov %esp -> %ebp: as '0x8b 0xec' or as '0x89 0xe5'. -if( insn2.isMoveRegMemToRegMem() && +// following instructions. There are two ways to encode +// mov %esp -> %ebp: as '0x8b 0xec' or as '0x89 0xe5'. +if( insn2.isMoveRegMemToRegMem() && ((Mod1_1 == 0x05 && Mod1_2 == 0x04) || (Mod1_1 == 0x04 && Mod1_2 == 0x05))) return true; -if( insn3.isMoveRegMemToRegMem() && +if( insn3.isMoveRegMemToRegMem() && ((Mod2_1 == 0x05 && Mod2_2 == 0x04) || (Mod2_1 == 0x04 && Mod2_2 == 0x05))) return true; @@ -11222,7 +11172,7 @@ unsigned instruction::jumpSize(long disp, unsigned addr_width) return JUMP_SZ; } #else -unsigned instruction::jumpSize(long /*disp*/, unsigned /*addr_width*/) +unsigned instruction::jumpSize(long /*disp*/, unsigned /*addr_width*/) { return JUMP_SZ; } @@ -11242,241 +11192,16 @@ unsigned instruction::maxJumpSize(unsigned addr_width) return JUMP_SZ; } #else -unsigned instruction::maxJumpSize(unsigned /*addr_width*/) +unsigned instruction::maxJumpSize(unsigned /*addr_width*/) { return JUMP_SZ; } #endif -bool instruction::isCmp() const { - if(*op_ptr_ == CMP_EB_GB || *op_ptr_ == CMP_EV_GV || - *op_ptr_ == CMP_GB_EB || *op_ptr_ == CMP_GV_EV || - *op_ptr_ == CMP_AL_LB || *op_ptr_ == CMP_RAX_LZ) - { - return true; - } - - if(*op_ptr_ == 0x80 || *op_ptr_ == 0x81 || *op_ptr_ == 0x83) - { - // group 1 opcodes -- operation depends on reg (bits 3-5) of - // modr/m byte - const unsigned char *p = op_ptr_+1; - if( (*p & (7<<3)) == (7<<3)) - return true; - } - - return false; -} #define SIB_SET_REG(x, y) ((x) |= ((y) & 7)) #define SIB_SET_INDEX(x, y) ((x) |= (((y) & 7) << 3)) #define SIB_SET_SS(x, y) ((x) | (((y) & 3) << 6)) -bool instruction::getUsedRegs(pdvector ®s) { - const unsigned char *insn_ptr = ptr(); - - struct ia32_memacc memacc[3]; - struct ia32_condition cond; - class ia32_locations loc; - ia32_entry *entry; - ia32_instruction orig_instr(memacc, &cond, &loc); - ia32_decode(IA32_DECODE_MEMACCESS | IA32_DECODE_CONDITION, - insn_ptr, orig_instr); - entry = orig_instr.getEntry(); - - if (orig_instr.getPrefix()->getPrefix(1) != 0) - //The instruction accesses memory via segment registers. Disallow. - return false; - - if (loc.modrm_position == -1) - //Only supporting MOD/RM instructions now - return false; - - if (loc.address_size == 1) - //Don't support 16-bit instructions yet - return false; - - if (loc.modrm_reg == 4 && !loc.rex_r) - //The non-memory access register is %rsp/%esp, we can't work with - // this register due to our register saving techniques. - return false; - - if (loc.modrm_mod == 3) - //This instruction doesn't use the MOD/RM to access memory - return false; - - for (unsigned i=0; i<3; i++) { - const ia32_operand& op = entry->operands[i]; - if (op.admet == am_O) { - //The MOD/RM specifies a register that's used - int regused = loc.modrm_reg; - if (loc.address_size == 4 && loc.rex_r) { - regused |= 0x8; - } - regs.push_back(regused); - } - else if (op.admet == am_reg) { - //using namespace Dyninst::InstructionAPI; - //The instruction implicitely references a memory instruction - switch (op.optype) { - case x86::iah: - case x86::ial: - case x86::iax: - case x86::ieax: - regs.push_back(REGNUM_RAX); - if (loc.rex_byte) regs.push_back(REGNUM_R8); - break; - case x86::ibh: - case x86::ibl: - case x86::ibx: - case x86::iebx: - regs.push_back(REGNUM_RBX); - if (loc.rex_byte) regs.push_back(REGNUM_R11); - break; - case x86::ich: - case x86::icl: - case x86::icx: - case x86::iecx: - regs.push_back(REGNUM_RCX); - if (loc.rex_byte) regs.push_back(REGNUM_R9); - break; - case x86::idh: - case x86::idl: - case x86::idx: - case x86::iedx: - regs.push_back(REGNUM_RDX); - if (loc.rex_byte) regs.push_back(REGNUM_R10); - break; - case x86::isp: - case x86::iesp: - regs.push_back(REGNUM_RSP); - if (loc.rex_byte) regs.push_back(REGNUM_R12); - break; - case x86::ibp: - case x86::iebp: - regs.push_back(REGNUM_RBP); - if (loc.rex_byte) regs.push_back(REGNUM_R13); - break; - case x86::isi: - case x86::iesi: - regs.push_back(REGNUM_RSI); - if (loc.rex_byte) regs.push_back(REGNUM_R14); - break; - case x86::idi: - case x86::iedi: - regs.push_back(REGNUM_RDI); - if (loc.rex_byte) regs.push_back(REGNUM_R15); - break; - case op_edxeax: - regs.push_back(REGNUM_RAX); - regs.push_back(REGNUM_RDX); - break; - case op_ecxebx: - regs.push_back(REGNUM_RBX); - regs.push_back(REGNUM_RCX); - break; - } - } - } - return true; -} - -int instruction::getStackDelta() -{ - ia32_instruction instruc; - const unsigned char *p = ptr(); - ia32_decode(0, ptr(), instruc); - - if (instruc.getEntry()->id == e_push) - return -4; - if (instruc.getEntry()->id == e_pop) - return 4; - if (instruc.getEntry()->id == e_pusha) - return (-2 * 9); - if (instruc.getEntry()->id == e_pushad) - return (-4 * 9); - if (instruc.getEntry()->id == e_popa) - return (2 * 9); - if (instruc.getEntry()->id == e_popad) - return (4 * 9); - - if (p[0] == 0x83 && p[1] == 0xec) { - //Subtract byte - return -1 * (signed char) p[2]; - } - - if (p[0] == 0x83 && p[1] == 0xc4) { - //Add byte - return (signed char) p[2]; - } - - return 0; -} - -bool instruction::isNop() const -{ - - if (!(type_ & IS_NOP)) //NOP or LEA - return false; - - if (*op_ptr_ == NOP) { - return true; - } - - ia32_memacc mac[3]; - ia32_condition cnd; - ia32_locations loc; - - ia32_instruction instruc(mac, &cnd, &loc); - - ia32_decode(IA32_FULL_DECODER, ptr(), instruc); - - - if (instruc.getEntry()->id == e_nop) { - return true; - } - - if (loc.modrm_mod == 3) { - return false; - } - if (loc.modrm_mod == 0 && loc.modrm_rm == 5) { - return false; - } - - if (loc.rex_x) { - return false; - } - if ((!loc.rex_r) != (!loc.rex_b)) { // Logical exclusive or - return false; - } - - if (loc.disp_position != -1) { - for (unsigned i=0; i const& getFlagTable(); static void initFlagTable(dyn_hash_map&); +private: + static dyn_hash_map flagTable; }; @@ -948,7 +945,7 @@ class ia32_instruction #define IA32_SIZE_DECODER 0 /* TODO: documentation*/ -COMMON_EXPORT bool ia32_decode_prefixes(const unsigned char* addr, ia32_instruction& insn); +COMMON_EXPORT bool ia32_decode_prefixes(const unsigned char *addr, ia32_instruction &insn, bool mode_64); /** * Decode just the opcode of the given instruction. This implies that @@ -956,9 +953,9 @@ COMMON_EXPORT bool ia32_decode_prefixes(const unsigned char* addr, ia32_instruct * and addr has been moved past the prefix bytes. Returns zero on success, * non zero otherwise. */ -COMMON_EXPORT int ia32_decode_opcode(unsigned int capa, - const unsigned char* addr, ia32_instruction& instruct, - ia32_entry** gotit_ret); +COMMON_EXPORT int +ia32_decode_opcode(unsigned int capa, const unsigned char *addr, ia32_instruction &instruct, ia32_entry **gotit_ret, + bool mode_64); /** * Do a complete decoding of the instruction at the given address. This @@ -968,8 +965,8 @@ COMMON_EXPORT int ia32_decode_opcode(unsigned int capa, * is not defined. capabilities is a mask of the above flags (IA32_DECODE_*). * The mask determines what part of the instruction should be decoded. */ -COMMON_EXPORT ia32_instruction& ia32_decode(unsigned int capabilities, - const unsigned char* addr, ia32_instruction&); +COMMON_EXPORT ia32_instruction & +ia32_decode(unsigned int capabilities, const unsigned char *addr, ia32_instruction &, bool mode_64); enum dynamic_call_address_mode { @@ -982,8 +979,8 @@ enum dynamic_call_address_mode { get_instruction: get the instruction that starts at instr. return the size of the instruction and set instType to a type descriptor */ -COMMON_EXPORT unsigned get_instruction(const unsigned char *instr, unsigned &instType, - const unsigned char** op_ptr = NULL); +COMMON_EXPORT unsigned +get_instruction(const unsigned char *instr, unsigned &instType, const unsigned char **op_ptr, bool mode_64); /* get the target of a jump or call */ COMMON_EXPORT Address get_target(const unsigned char *instr, unsigned type, unsigned size, @@ -1049,14 +1046,14 @@ class instruction { COMMON_EXPORT instruction *copy() const; - instruction(const void *ptr) : + instruction(const void *ptr, bool mode_64) : type_(0), size_(0), ptr_(NULL), op_ptr_(0) { - setInstruction((const unsigned char*)ptr); + setInstruction((const unsigned char *) ptr, 0, mode_64); } - unsigned setInstruction(const unsigned char *p, Address = 0) { + unsigned setInstruction(const unsigned char *p, Address, bool mode_64) { ptr_ = p; - size_ = get_instruction(ptr_, type_, &op_ptr_); + size_ = get_instruction(ptr_, type_, &op_ptr_, mode_64); return size_; } @@ -1091,9 +1088,7 @@ class instruction { COMMON_EXPORT static unsigned jumpSize(long disp, unsigned addr_width); COMMON_EXPORT static unsigned maxJumpSize(unsigned addr_width); - COMMON_EXPORT bool getUsedRegs(pdvector ®s); - - bool isCall() const { return type_ & IS_CALL; } + bool isCall() const { return type_ & IS_CALL; } bool isCallIndir() const { return (type_ & IS_CALL) && (type_ & INDIR); } bool isReturn() const { return (type_ & IS_RET) || (type_ & IS_RETF); } bool isRetFar() const { return type_ & IS_RETF; } @@ -1103,8 +1098,8 @@ class instruction { { return !(type_ & INDIR) && ((type_ & IS_JUMP) || (type_ & IS_JCC)); } bool isUncondJump() const { return ((type_ & IS_JUMP) && !(type_ & IS_JCC)); } - bool isNop() const; - bool isIndir() const { return type_ & INDIR; } + + bool isIndir() const { return type_ & INDIR; } bool isIllegal() const { return type_ & ILLEGAL; } bool isLeave() const { return *ptr_ == 0xC9; } bool isPrivileged() const { return (type_ & PRVLGD); } @@ -1126,18 +1121,14 @@ class instruction { static bool isAligned(const Address ) { return true; } - bool isCmp() const; - - void print() + void print() { for (unsigned i = 0; i < size_; i++) fprintf(stderr, " %02x", *(ptr_ + i)); fprintf(stderr, "\n"); } - - int getStackDelta(); - private: +private: unsigned type_; // type of the instruction (e.g. IS_CALL | INDIR) unsigned size_; // size in bytes const unsigned char *ptr_; // pointer to the instruction @@ -1145,14 +1136,12 @@ class instruction { }; /** Only appropriate for call/jump functions **/ -COMMON_EXPORT int get_disp(instruction *insn); -int set_disp(bool setDisp, instruction *insn, int newOffset, bool outOfFunc); + int set_disp(bool setDisp, instruction *insn, int newOffset, bool outOfFunc); int displacement(const unsigned char *instr, unsigned type); /** Returns the immediate operand of an instruction **/ -COMMON_EXPORT Address get_immediate_operand(instruction *instr); -COMMON_EXPORT int count_prefixes(unsigned insnType); + COMMON_EXPORT int count_prefixes(unsigned insnType); inline bool is_disp8(long disp) { return (disp >= -128 && disp < 127); diff --git a/common/src/dthread.C b/common/src/dthread.C index 375ea1ae90..bf1f2f9417 100644 --- a/common/src/dthread.C +++ b/common/src/dthread.C @@ -32,3 +32,6 @@ #include + + + diff --git a/common/src/dthread.h b/common/src/dthread.h index c483af2713..b9e551942a 100644 --- a/common/src/dthread.h +++ b/common/src/dthread.h @@ -54,6 +54,8 @@ #define WINAPI #endif + + class PC_EXPORT DThread { #if defined(cap_pthreads) pthread_t thrd; @@ -93,6 +95,8 @@ struct boost_mutex_selector template class PC_EXPORT Mutex : public boost_mutex_selector::mutex { +public: + typedef Mutex type; }; @@ -129,4 +133,6 @@ class ScopeLock : public boost::interprocess::scoped_lock ScopeLock(Mut &mut) : boost::interprocess::scoped_lock(mut) {} }; + + #endif diff --git a/common/src/linuxKludges.C b/common/src/linuxKludges.C index ab650a65ea..6284f516f1 100644 --- a/common/src/linuxKludges.C +++ b/common/src/linuxKludges.C @@ -199,28 +199,68 @@ unsigned long long PDYN_mulMillion(unsigned long long in) { return result; } -#if defined(cap_gnu_demangler) #include +#include +#include + +#include + using namespace abi; -#endif + +inline void set_thread_local_pointer(char* &var, char* val) { + race_detector_fake_lock_acquire(race_detector_fake_lock(var)); + var = val; + race_detector_fake_lock_release(race_detector_fake_lock(var)); +} + +inline void set_thread_local_bool(bool &var, bool val) { + race_detector_fake_lock_acquire(race_detector_fake_lock(var)); + var = val; + race_detector_fake_lock_release(race_detector_fake_lock(var)); +} + +inline char* get_thread_local_pointer(char* &var) { + char *ret; + race_detector_fake_lock_acquire(race_detector_fake_lock(var)); + ret = var; + race_detector_fake_lock_release(race_detector_fake_lock(var)); + return ret; +} + +inline bool get_thread_local_bool(bool &var) { + bool ret; + race_detector_fake_lock_acquire(race_detector_fake_lock(var)); + ret = var; + race_detector_fake_lock_release(race_detector_fake_lock(var)); + return ret; +} + char * P_cplus_demangle( const char * symbol, bool nativeCompiler, bool includeTypes ) { - static char* last_symbol = NULL; - static bool last_native = false; - static bool last_typed = false; - static char* last_demangled = NULL; - - if(last_symbol && last_demangled && (nativeCompiler == last_native) - && (includeTypes == last_typed) && (strcmp(symbol, last_symbol) == 0)) + static __thread char* last_symbol; + set_thread_local_pointer(last_symbol, NULL); + static __thread bool last_native; + set_thread_local_bool(last_native, false); + static __thread bool last_typed; + set_thread_local_bool(last_typed, false); + static __thread char* last_demangled; + set_thread_local_pointer(last_demangled, NULL); + + if(get_thread_local_pointer(last_symbol) && + get_thread_local_pointer(last_demangled) && + (nativeCompiler == get_thread_local_bool(last_native)) && + (includeTypes == get_thread_local_bool(last_typed)) && + (strcmp(symbol, get_thread_local_pointer(last_symbol)) == 0)) { - return strdup(last_demangled); + return strdup(get_thread_local_pointer(last_demangled)); } - -#if defined(cap_gnu_demangler) int status; - char *demangled = __cxa_demangle(symbol, NULL, NULL, &status); + char* demangled; + { + demangled = __cxa_demangle(symbol, NULL, NULL, &status); + } if (status == -1) { //Memory allocation failure. return NULL; @@ -230,16 +270,6 @@ char * P_cplus_demangle( const char * symbol, bool nativeCompiler, return NULL; } assert(status == 0); //Success -#else - int opts = 0; - opts |= includeTypes ? DMGL_PARAMS | DMGL_ANSI : 0; - // [ pgcc/CC are the "native" compilers on Linux. Go figure. ] - // pgCC's mangling scheme most closely resembles that of the Annotated - // C++ Reference Manual, only with "some exceptions" (to quote the PGI - // documentation). I guess we'll demangle names with "some exceptions". - opts |= nativeCompiler ? DMGL_ARM : 0; - char * demangled = cplus_demangle( const_cast< char *>(symbol), opts); -#endif if( demangled == NULL ) { return NULL; } @@ -254,12 +284,12 @@ char * P_cplus_demangle( const char * symbol, bool nativeCompiler, demangled = dedemangled; } - free(last_symbol); - free(last_demangled); - last_native = nativeCompiler; - last_typed = includeTypes; - last_symbol = strdup(symbol); - last_demangled = strdup(demangled); + free(get_thread_local_pointer(last_symbol)); + free(get_thread_local_pointer(last_demangled)); + set_thread_local_bool(last_native, nativeCompiler); + set_thread_local_bool(last_typed, includeTypes); + set_thread_local_pointer(last_symbol, strdup(symbol)); + set_thread_local_pointer(last_demangled, strdup(demangled)); return demangled; } /* end P_cplus_demangle() */ diff --git a/common/src/mcs-lock.C b/common/src/mcs-lock.C new file mode 100644 index 0000000000..b380e9e55f --- /dev/null +++ b/common/src/mcs-lock.C @@ -0,0 +1,147 @@ +//****************************************************************************** +// +// File: +// mcs_lock.c +// +// Purpose: +// Implement an API for the MCS lock: a fair queue-based lock. +// +// Reference: +// John M. Mellor-Crummey and Michael L. Scott. 1991. Algorithms for scalable +// synchronization on shared-memory multiprocessors. ACM Transactions on +// Computing Systems 9, 1 (February 1991), 21-65. +// http://doi.acm.org/10.1145/103727.103729 +//****************************************************************************** + + + +//****************************************************************************** +// local includes +//****************************************************************************** + +#include "mcs-lock.h" +#include "race-detector-annotations.h" + +#include + +//****************************************************************************** +// private operations +//****************************************************************************** + +//****************************************************************************** +// interface operations +//****************************************************************************** + +void +mcs_lock(mcs_lock_t &l, mcs_node_t &me) +{ + race_detector_fake_lock_acquire(&l); + + //-------------------------------------------------------------------- + // initialize my queue node + //-------------------------------------------------------------------- + me.next.store(mcs_nil); + + //-------------------------------------------------------------------- + // install my node at the tail of the lock queue. + // determine my predecessor, if any. + // + // note: the rel aspect of the ordering below ensures that + // initialization of me->next completes before anyone sees my node + //-------------------------------------------------------------------- + mcs_node_t *predecessor = l.tail.exchange(&me, boost::memory_order_acq_rel); + + //-------------------------------------------------------------------- + // if I have a predecessor, wait until it signals me + //-------------------------------------------------------------------- + if (predecessor != mcs_nil) { + //------------------------------------------------------------------ + // prepare to block until signaled by my predecessor + //------------------------------------------------------------------ + me.blocked.store(true); + + //------------------------------------------------------------------ + // link behind my predecessor + // note: use release to ensure that prior assignment to blocked + // occurs first + //------------------------------------------------------------------ + predecessor->next.store(&me, boost::memory_order_release); + + //------------------------------------------------------------------ + // wait for my predecessor to clear my flag + // note: use acquire order to ensure that reads or writes in the + // critical section will not occur until after blocked is + // cleared + //------------------------------------------------------------------ + while (me.blocked.load(boost::memory_order_acquire)); + } +} + + +bool +mcs_trylock(mcs_lock_t &l, mcs_node_t &me) +{ + race_detector_fake_lock_acquire(&l); + //-------------------------------------------------------------------- + // initialize my queue node + //-------------------------------------------------------------------- + me.next.store(mcs_nil, boost::memory_order_relaxed); + + //-------------------------------------------------------------------- + // if the tail pointer is nil, swap it with a pointer to me, which + // acquires the lock and installs myself at the tail of the queue. + // note: the acq_rel ordering ensures that + // (1) rel: my store of me->next above completes before the exchange + // (2) acq: any accesses after the exchange can't begin until after + // the exchange completes. + //-------------------------------------------------------------------- + mcs_node_t *oldme = mcs_nil; + bool locked = l.tail.compare_exchange_strong(oldme, &me, + boost::memory_order_acq_rel, + boost::memory_order_relaxed); + if (!locked) { + race_detector_fake_lock_release(&l); + } + return locked; +} + + +void +mcs_unlock(mcs_lock_t &l, mcs_node_t &me) +{ + mcs_node_t *successor = me.next.load(boost::memory_order_acquire); + + if (successor == mcs_nil) { + //-------------------------------------------------------------------- + // I don't currently have a successor, so I may be at the tail + //-------------------------------------------------------------------- + + //-------------------------------------------------------------------- + // if my node is at the tail of the queue, attempt to remove myself + // note: release order below on success guarantees that all accesses + // above the exchange must complete before the exchange if the + // exchange unlinks me from the tail of the queue + //-------------------------------------------------------------------- + mcs_node_t *oldme = &me; + + if (l.tail.compare_exchange_strong(oldme, mcs_nil, + boost::memory_order_release, + boost::memory_order_relaxed)) { + //------------------------------------------------------------------ + // I removed myself from the queue; I will never have a + // successor, so I'm done + //------------------------------------------------------------------ + race_detector_fake_lock_release(&l); + return; + } + + //------------------------------------------------------------------ + // another thread is writing me->next to define itself as our successor; + // wait for it to finish that + //------------------------------------------------------------------ + while (mcs_nil == (successor = me.next.load(boost::memory_order_acquire))); + } + + successor->blocked.store(false, boost::memory_order_release); + race_detector_fake_lock_release(&l); +} diff --git a/common/src/pathName.C b/common/src/pathName.C index 90aa2c413f..414da5e604 100644 --- a/common/src/pathName.C +++ b/common/src/pathName.C @@ -277,29 +277,12 @@ bool executableFromArgv0AndPathAndCwd(std::string &result, #define PATH_SEP ('/') #endif +#include + std::string extract_pathname_tail(const std::string &path) { - if (!path.length()) - { - return std::string(""); - } - - const char *path_str = path.c_str(); - if (!path_str) - { - return std::string(""); - } - - const char *path_sep = P_strrchr(path_str, PATH_SEP); - -#if defined(SECOND_PATH_SEP) - const char *sec_path_sep = P_strrchr(path_str, SECOND_PATH_SEP); - if (sec_path_sep && (!path_sep || sec_path_sep > path_sep)) - path_sep = sec_path_sep; -#endif - - std::string ret = (path_sep) ? (path_sep + 1) : (path_str); - return ret; + boost::filesystem::path p(path); + return p.filename().string(); } #if !defined (os_windows) diff --git a/common/src/pfq-rwlock.C b/common/src/pfq-rwlock.C new file mode 100644 index 0000000000..589b48cc08 --- /dev/null +++ b/common/src/pfq-rwlock.C @@ -0,0 +1,204 @@ +//****************************************************************************** +// +// File: +// pfq_rwlock.c +// +// Purpose: +// Implement the API for a fair, phased reader-writer lock with local spinning +// +// Reference: +// Björn B. Brandenburg and James H. Anderson. 2010. Spin-based reader-writer +// synchronization for multiprocessor real-time systems. Real-Time Systems +// 46(1):25-87 (September 2010). http://dx.doi.org/10.1007/s11241-010-9097-2 +// +// Notes: +// the reference uses a queue for arriving readers. on a cache coherent +// machine, the local spinning property for waiting readers can be achieved +// by simply using a cacheable flag. the implementation here uses that +// simplification. +// +//****************************************************************************** + + + +//****************************************************************************** +// local includes +//****************************************************************************** + +#include "pfq-rwlock.h" +#include "race-detector-annotations.h" + + + +//****************************************************************************** +// macros +//****************************************************************************** + +#define READER_INCREMENT 0x100U + +#define PHASE_BIT 0x001U +#define WRITER_PRESENT 0x002U + +#define WRITER_MASK (PHASE_BIT | WRITER_PRESENT) +#define TICKET_MASK ~(WRITER_MASK) + +//------------------------------------------------------------------ +// define a macro to point to the low-order byte of an integer type +// in a way that will work on both big-endian and little-endian +// processors +//------------------------------------------------------------------ +#ifdef DYNINST_BIG_ENDIAN +#define LSB_PTR(p) (((unsigned char *) p) + (sizeof(*p) - 1)) +#endif + + +#ifdef DYNINST_LITTLE_ENDIAN +#define LSB_PTR(p) ((unsigned char *) p) +#endif + +#ifndef LSB_PTR +#error "endianness must be configured. " \ + "use --enable-endian to force configuration" +#endif + +//****************************************************************************** +// interface operations +//****************************************************************************** + +void +pfq_rwlock_init(pfq_rwlock_t &l) +{ + l.rin.store(0U); + l.rout.store(0U); + l.last.store(0U); + l.writer_blocking_readers[0].bit.store(false); + l.writer_blocking_readers[1].bit.store(false); + mcs_init(l.wtail); + l.whead = mcs_nil; +} + +void +pfq_rwlock_read_lock(pfq_rwlock_t &l) +{ + race_detector_fake_lock_acquire(&l.wtail); + uint32_t ticket = l.rin.fetch_add(READER_INCREMENT, boost::memory_order_acq_rel); + + if (ticket & WRITER_PRESENT) { + uint32_t phase = ticket & PHASE_BIT; + while (l.writer_blocking_readers[phase].bit.load(boost::memory_order_acquire)); + } +} + + +void +pfq_rwlock_read_unlock(pfq_rwlock_t &l) +{ + uint32_t ticket = l.rout.fetch_add(READER_INCREMENT, boost::memory_order_acq_rel); + + if (ticket & WRITER_PRESENT) { + //---------------------------------------------------------------------------- + // finish reading counter before reading last + //---------------------------------------------------------------------------- + if (ticket == l.last.load(boost::memory_order_acquire)) + l.whead->blocked.store(false, boost::memory_order_release); + } + race_detector_fake_lock_release(&l.wtail); +} + + +void +pfq_rwlock_write_lock(pfq_rwlock_t &l, pfq_rwlock_node_t &me) +{ + //-------------------------------------------------------------------- + // use MCS lock to enforce mutual exclusion with other writers + //-------------------------------------------------------------------- + mcs_lock(l.wtail, me); + + //-------------------------------------------------------------------- + // this may be false when at the head of the mcs queue + //-------------------------------------------------------------------- + me.blocked.store(true, boost::memory_order_relaxed); + + //-------------------------------------------------------------------- + // announce myself as next writer + //-------------------------------------------------------------------- + l.whead = &me; + + //-------------------------------------------------------------------- + // set writer_blocking_readers to block any readers in the next batch + //-------------------------------------------------------------------- + uint32_t phase = l.rin.load(boost::memory_order_relaxed) & PHASE_BIT; + l.writer_blocking_readers[phase].bit.store(true, boost::memory_order_release); + + //---------------------------------------------------------------------------- + // store to writer_blocking_headers bit must complete before incrementing rin + //---------------------------------------------------------------------------- + + //-------------------------------------------------------------------- + // acquire an "in" sequence number to see how many readers arrived + // set the WRITER_PRESENT bit so subsequent readers will wait + //-------------------------------------------------------------------- + uint32_t in = l.rin.fetch_or(WRITER_PRESENT, boost::memory_order_acq_rel); + + //-------------------------------------------------------------------- + // save the ticket that the last reader will see + //-------------------------------------------------------------------- + l.last.store(in - READER_INCREMENT + WRITER_PRESENT, boost::memory_order_release); + + //------------------------------------------------------------- + // update to 'last' must complete before others see changed value of rout. + // acquire an "out" sequence number to see how many readers left + // set the WRITER_PRESENT bit so the last reader will know to signal + // it is responsible for signaling the waiting writer + //------------------------------------------------------------- + uint32_t out = l.rout.fetch_or(WRITER_PRESENT, boost::memory_order_acq_rel); + + //-------------------------------------------------------------------- + // if any reads are active, wait for last reader to signal me + //-------------------------------------------------------------------- + if (in != out) { + while (me.blocked.load(boost::memory_order_acquire)); + // wait for active reads to drain + + //-------------------------------------------------------------------------- + // store to writer_blocking headers bit must complete before notifying + // readers of writer + //-------------------------------------------------------------------------- + } +} + + +void +pfq_rwlock_write_unlock(pfq_rwlock_t &l, pfq_rwlock_node_t &me) +{ + //-------------------------------------------------------------------- + // toggle phase and clear WRITER_PRESENT in rin. No synch issues + // since there are no concurrent updates of the low-order byte + //-------------------------------------------------------------------- + unsigned char *lsb = LSB_PTR(&l.rin); + uint32_t phase = *lsb & PHASE_BIT; + *lsb ^= WRITER_MASK; + + //-------------------------------------------------------------------- + // toggle phase and clear WRITER_PRESENT in rout. No synch issues + // since the low-order byte modified here isn't modified again until + // another writer has the mcs_lock. + //-------------------------------------------------------------------- + lsb = LSB_PTR(&l.rout); + *lsb ^= WRITER_MASK; + + //---------------------------------------------------------------------------- + // clearing writer present in rin can be reordered with writer_blocking_readers set below + // because any arriving reader will see the cleared writer_blocking_readers and proceed. + //---------------------------------------------------------------------------- + + //-------------------------------------------------------------------- + // clear writer_blocking_readers to release waiting readers in the current read phase + //-------------------------------------------------------------------- + l.writer_blocking_readers[phase].bit.store(false, boost::memory_order_release); + + //-------------------------------------------------------------------- + // pass writer lock to next writer + //-------------------------------------------------------------------- + mcs_unlock(l.wtail, me); +} diff --git a/common/src/race-detector-annotations.C b/common/src/race-detector-annotations.C new file mode 100644 index 0000000000..c335feca13 --- /dev/null +++ b/common/src/race-detector-annotations.C @@ -0,0 +1,80 @@ +//*************************************************************************** +// +// File: +// race-detector-annotations.C +// +// Purpose: +// Inform a race detector about invariants known to the programmer +// that are relevant to race detection. Specifically, let the +// programmer know: +// (1) a code region may be treated as if it were executed under +// mutual exclusion. no accesses in the region will be endpoints +// of race reports. +// (2) forget about the prior access history associated with a region +// of memory. this enables memory that has been allocated and freed +// by one thread to be reused by another without the appearance of +// any races. +// +// +// Description: +// void fake_lock_acquire(void) +// +// void fake_lock_release(void) +// +// Note: +// the contents of this file will be ignored unless CILKSCREEN is defined +// +//*************************************************************************** + +#ifdef ENABLE_RACE_DETECTION + +//**************************************************************************** +// system include files +//**************************************************************************** + +#ifdef __INTEL_COMPILER +#include +#endif + + + +//**************************************************************************** +// local include files +//**************************************************************************** + +#include "race-detector-annotations.h" + + + +//**************************************************************************** +// public operations +//**************************************************************************** + + +void +race_detector_fake_lock_acquire(void *fake_lock) +{ +#ifdef __INTEL_COMPILER + __cilkscreen_acquire_lock(fake_lock); +#endif +} + + +void +race_detector_fake_lock_release(void *fake_lock) +{ +#ifdef __INTEL_COMPILER + __cilkscreen_release_lock(fake_lock); +#endif +} + + +void +race_detector_forget_access_history(void *loc, unsigned int nbytes) +{ +#ifdef __INTEL_COMPILER + __cilkscreen_clean(loc, ((char *) loc) + nbytes); +#endif +} + +#endif diff --git a/common/src/singleton_object_pool.h b/common/src/singleton_object_pool.h index bf0f5c303c..8878247f49 100644 --- a/common/src/singleton_object_pool.h +++ b/common/src/singleton_object_pool.h @@ -30,119 +30,51 @@ #if !defined(SINGLETON_OBJECT_POOL_H) #define SINGLETON_OBJECT_POOL_H -//#define BOOST_POOL_NO_MT -//#undef BOOST_HAS_THREADS - -#include #include "pool_allocators.h" - +#include "dthread.h" +#include // This is only safe for objects with nothrow constructors... -template -class singleton_object_pool : private boost::singleton_pool +template > +class singleton_object_pool : public Alloc { - typedef boost::singleton_pool parent_t; - - inline static void free(T* free_me) - { - parent_t::free(free_me); - } - - inline static T* malloc() - { - return reinterpret_cast(parent_t::malloc()); - } - public: - inline static bool is_from(T* t) - { - return parent_t::is_from(t); - } - - static T* construct() - { - T* const temp = malloc(); - if(temp == 0) return temp; - new(temp) T(); - return temp; - } - template - static T* construct(const A1& a1) - { - T* const temp = malloc(); - if(temp == 0) return temp; - new(temp) T(a1); - return temp; - } - template - static T* construct(const A1& a1, const A2& a2) - { - T* const temp = malloc(); - if(temp == 0) return temp; - new(temp) T(a1, a2); - return temp; - } - template - static T* construct(const A1& a1, const A2& a2, const A3& a3) - { - T* const temp = malloc(); - if(temp == 0) return temp; - new(temp) T(a1, a2, a3); - return temp; - } - template - static T* construct(const A1& a1, const A2& a2, const A3& a3, const A4& a4) - { - T* const temp = malloc(); - if(temp == 0) return temp; - new(temp) T(a1, a2, a3, a4); - return temp; - } - template - static T* construct(const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5) - { - T* const temp = malloc(); - if(temp == 0) return temp; - new(temp) T(a1, a2, a3, a4, a5); - return temp; - } - template - static T* construct(const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6) - { - T* const temp = malloc(); - if(temp == 0) return temp; - new(temp) T(a1, a2, a3, a4, a5, a6); - return temp; - } - - inline static void destroy(T* const kill_me) - { - - kill_me->~T(); - free(kill_me); - } + using typename Alloc::pointer; + using typename Alloc::size_type; +public: + static typename Alloc::pointer allocate( size_type n ) { + return Alloc().allocate(n); + } + static void deallocate( typename Alloc::pointer p ) { + Alloc().deallocate(p, 1); + } + template + static T* construct(Args&&... args) + { + T* p = allocate(1); + Alloc().construct(p, std::forward(args)...); + return p; + }; + static void destroy(typename Alloc::pointer p) + { + Alloc().destroy(p); + }; }; - -template +template struct PoolDestructor { - inline void operator()(T* e) - { - // We'll see if this kills performance or not... - if(singleton_object_pool::is_from(e)) { + inline void operator()(T* e) { singleton_object_pool::destroy(e); - } - } }; template inline boost::shared_ptr make_shared(T* t) { - return boost::shared_ptr(t, PoolDestructor()/*, typename unlocked_fast_alloc::type()*/); + return boost::shared_ptr(t, PoolDestructor()/*, typename unlocked_fast_alloc::type()*/); } - + #endif //!defined(SINGLETON_OBJECT_POOL_H) diff --git a/common/src/string-regex.C b/common/src/string-regex.C index fe7f600464..a1453c1058 100644 --- a/common/src/string-regex.C +++ b/common/src/string-regex.C @@ -38,7 +38,6 @@ #include #endif -#include /* This doesn't actually belong here. */ void dedemangle( char * demangled, char * result ) @@ -51,7 +50,7 @@ void dedemangle( char * demangled, char * result ) before the 'const'. */ char * resultBegins = NULL; char * resultEnds = NULL; - + // starts with open paren, is a member function if ( demangled[0] == '(' && strstr( demangled, "::" ) != NULL) { @@ -222,13 +221,10 @@ bool regexEquiv(const char *str_, const char *s, bool checkCase ) bool prefixed_by(std::string &haystack, std::string &prefix) { - if (!haystack.c_str()) + if (haystack.empty()) return false; - const char *res = strstr(haystack.c_str(), prefix.c_str()); - - if (res == haystack.c_str()) - return true; + if(haystack.find(prefix) == 0) return true; return false; } @@ -242,20 +238,10 @@ bool prefixed_by(std::string &haystack, const char *prefix) bool suffixed_by(std::string &haystack, std::string &suffix) { - if (!haystack.c_str()) + if (haystack.empty()) return false; - - int lastchar = haystack.length() - 1; - - int j = 0; - for (int i = suffix.length() - 1; i >= 0; i--) - { - if (haystack[lastchar - i] != suffix[j]) - return false; - j++; - } - - return true; + if(haystack.rfind(suffix) == haystack.length() - suffix.length()) return true; + return false; } bool suffixed_by(std::string &haystack, const char *suffix) diff --git a/dataflowAPI/h/ABI.h b/dataflowAPI/h/ABI.h index 4d53b9e5d3..3a6d3f51e1 100644 --- a/dataflowAPI/h/ABI.h +++ b/dataflowAPI/h/ABI.h @@ -37,8 +37,8 @@ using namespace Dyninst; class ABI{ - static ABI* globalABI_; - static ABI* globalABI64_; + static dyn_tls ABI* globalABI_; + static dyn_tls ABI* globalABI64_; std::map *index; int addr_width; @@ -65,29 +65,29 @@ class ABI{ DATAFLOW_EXPORT static ABI* getABI(int addr_width); DATAFLOW_EXPORT bitArray getBitArray(); private: - static bitArray callRead_; - static bitArray callRead64_; + static dyn_tls bitArray* callRead_; + static dyn_tls bitArray* callRead64_; - static bitArray callWritten_; - static bitArray callWritten64_; + static dyn_tls bitArray* callWritten_; + static dyn_tls bitArray* callWritten64_; - static bitArray returnRead_; - static bitArray returnRead64_; + static dyn_tls bitArray* returnRead_; + static dyn_tls bitArray* returnRead64_; - static bitArray returnRegs_; - static bitArray returnRegs64_; + static dyn_tls bitArray* returnRegs_; + static dyn_tls bitArray* returnRegs64_; - static bitArray callParam_; - static bitArray callParam64_; + static dyn_tls bitArray* callParam_; + static dyn_tls bitArray* callParam64_; - static bitArray syscallRead_; - static bitArray syscallRead64_; + static dyn_tls bitArray* syscallRead_; + static dyn_tls bitArray* syscallRead64_; - static bitArray syscallWritten_; - static bitArray syscallWritten64_; + static dyn_tls bitArray* syscallWritten_; + static dyn_tls bitArray* syscallWritten64_; - static bitArray allRegs_; - static bitArray allRegs64_; + static dyn_tls bitArray* allRegs_; + static dyn_tls bitArray* allRegs64_; static bitArray getBitArray(int size){ return bitArray(size); diff --git a/dataflowAPI/h/Absloc.h b/dataflowAPI/h/Absloc.h index a136716c0a..d95c1b54ee 100644 --- a/dataflowAPI/h/Absloc.h +++ b/dataflowAPI/h/Absloc.h @@ -294,7 +294,7 @@ class Assignment { DATAFLOW_EXPORT const std::vector &inputs() const { return inputs_; } DATAFLOW_EXPORT std::vector &inputs() { return inputs_; } - DATAFLOW_EXPORT InstructionAPI::Instruction::Ptr insn() const { return insn_; } + DATAFLOW_EXPORT InstructionAPI::Instruction insn() const { return insn_; } DATAFLOW_EXPORT Address addr() const { return addr_; } DATAFLOW_EXPORT const AbsRegion &out() const { return out_; } @@ -306,10 +306,10 @@ class Assignment { Aliases aliases; // Factory functions. - DATAFLOW_EXPORT static std::set create(InstructionAPI::Instruction::Ptr insn, + DATAFLOW_EXPORT static std::set create(InstructionAPI::Instruction insn, Address addr); - DATAFLOW_EXPORT Assignment(const InstructionAPI::Instruction::Ptr i, + DATAFLOW_EXPORT Assignment(const InstructionAPI::Instruction& i, const Address a, ParseAPI::Function *f, ParseAPI::Block *b, @@ -322,7 +322,7 @@ class Assignment { inputs_(ins), out_(o) {}; - DATAFLOW_EXPORT Assignment(const InstructionAPI::Instruction::Ptr i, + DATAFLOW_EXPORT Assignment(const InstructionAPI::Instruction& i, const Address a, ParseAPI::Function *f, ParseAPI::Block *b, @@ -333,14 +333,14 @@ class Assignment { block_(b), out_(o) {}; - DATAFLOW_EXPORT static Assignment::Ptr makeAssignment(const InstructionAPI::Instruction::Ptr i, + DATAFLOW_EXPORT static Assignment::Ptr makeAssignment(const InstructionAPI::Instruction& i, const Address a, ParseAPI::Function *f, ParseAPI::Block *b, const std::vector &ins, const AbsRegion &o); - DATAFLOW_EXPORT static Assignment::Ptr makeAssignment(const InstructionAPI::Instruction::Ptr i, + DATAFLOW_EXPORT static Assignment::Ptr makeAssignment(const InstructionAPI::Instruction& i, const Address a, ParseAPI::Function *f, ParseAPI::Block *b, @@ -364,7 +364,7 @@ class Assignment { } private: - InstructionAPI::Instruction::Ptr insn_; + InstructionAPI::Instruction insn_; Address addr_; ParseAPI::Function *func_; diff --git a/dataflowAPI/h/AbslocInterface.h b/dataflowAPI/h/AbslocInterface.h index 9bf93b9c5d..419774a901 100644 --- a/dataflowAPI/h/AbslocInterface.h +++ b/dataflowAPI/h/AbslocInterface.h @@ -64,7 +64,7 @@ class AbsRegionConverter { ParseAPI::Block *block, std::vector ®ions); - DATAFLOW_EXPORT void convertAll(InstructionAPI::Instruction::Ptr insn, + DATAFLOW_EXPORT void convertAll(InstructionAPI::Instruction insn, Address addr, ParseAPI::Function *func, ParseAPI::Block *block, @@ -124,7 +124,7 @@ class AssignmentConverter { public: DATAFLOW_EXPORT AssignmentConverter(bool cache, bool stack) : cacheEnabled_(cache), aConverter(false, stack) {}; - DATAFLOW_EXPORT void convert(InstructionAPI::Instruction::Ptr insn, + DATAFLOW_EXPORT void convert(const InstructionAPI::Instruction insn, const Address &addr, ParseAPI::Function *func, ParseAPI::Block *block, @@ -132,13 +132,13 @@ class AssignmentConverter { private: - void handlePushEquivalent(const InstructionAPI::Instruction::Ptr I, + void handlePushEquivalent(const InstructionAPI::Instruction I, Address addr, ParseAPI::Function *func, ParseAPI::Block *block, std::vector &operands, std::vector &assignments); - void handlePopEquivalent(const InstructionAPI::Instruction::Ptr I, + void handlePopEquivalent(const InstructionAPI::Instruction I, Address addr, ParseAPI::Function *func, ParseAPI::Block *block, diff --git a/dataflowAPI/h/SymEval.h b/dataflowAPI/h/SymEval.h index 81aece3114..5ead7c4e16 100644 --- a/dataflowAPI/h/SymEval.h +++ b/dataflowAPI/h/SymEval.h @@ -348,7 +348,7 @@ class SymEval { // We assume the assignments are prepped in the input; whatever // they point to is discarded. DATAFLOW_EXPORT static bool expand(Result_t &res, - std::set &failedInsns, + std::set &failedInsns, bool applyVisitors = true); // Hand in a Graph (of SliceNodes, natch) and get back a Result; @@ -360,9 +360,9 @@ class SymEval { // Symbolically evaluate an instruction and assign // an AST representation to every written absloc - static bool expandInsn(const InstructionPtr insn, - const uint64_t addr, - Result_t& res); + static bool expandInsn(const InstructionAPI::Instruction &insn, + const uint64_t addr, + Result_t &res); static Retval_t process(SliceNodePtr ptr, Result_t &dbase, std::set &skipEdges); diff --git a/dataflowAPI/h/liveness.h b/dataflowAPI/h/liveness.h index a6ef46e298..d919fa060f 100644 --- a/dataflowAPI/h/liveness.h +++ b/dataflowAPI/h/liveness.h @@ -64,7 +64,7 @@ class DATAFLOW_EXPORT LivenessAnalyzer{ void summarizeBlockLivenessInfo(ParseAPI::Function* func, ParseAPI::Block *block, bitArray &allRegsDefined); bool updateBlockLivenessInfo(ParseAPI::Block *block, bitArray &allRegsDefined); - ReadWriteInfo calcRWSets(Instruction::Ptr curInsn, ParseAPI::Block* blk, Address a); + ReadWriteInfo calcRWSets(Instruction curInsn, ParseAPI::Block *blk, Address a); void* getPtrToInstruction(ParseAPI::Block *block, Address addr) const; bool isExitBlock(ParseAPI::Block *block); diff --git a/dataflowAPI/h/slicing.h b/dataflowAPI/h/slicing.h index 02172d4044..4fe9869a00 100644 --- a/dataflowAPI/h/slicing.h +++ b/dataflowAPI/h/slicing.h @@ -134,7 +134,7 @@ class SliceEdge : public Edge { class Slicer { public: - typedef std::pair InsnInstance; + typedef std::pair InsnInstance; typedef std::vector InsnVec; DATAFLOW_EXPORT Slicer(AssignmentPtr a, @@ -646,11 +646,11 @@ class Slicer { SliceNode::Ptr& target, AbsRegion const& data); - void convertInstruction(InstructionPtr, - Address, - ParseAPI::Function *, + void convertInstruction(InstructionAPI::Instruction, + Address, + ParseAPI::Function *, ParseAPI::Block *, - std::vector &); + std::vector &); void fastForward(Location &loc, Address addr); diff --git a/dataflowAPI/h/stackanalysis.h b/dataflowAPI/h/stackanalysis.h index bea76da96c..50e5380e75 100644 --- a/dataflowAPI/h/stackanalysis.h +++ b/dataflowAPI/h/stackanalysis.h @@ -547,46 +547,46 @@ class StackAnalysis { void meetSummary(const TransferSet &source, TransferSet &accum); AbslocState getSrcOutputLocs(ParseAPI::Edge* e); TransferSet getSummarySrcOutputLocs(ParseAPI::Edge *e); - void computeInsnEffects(ParseAPI::Block *block, InstructionPtr insn, - const Offset off, TransferFuncs &xferFunc, TransferSet &funcSummary); - - bool isCall(InstructionPtr insn); - bool isJump(InstructionPtr insn); - bool handleNormalCall(InstructionPtr insn, ParseAPI::Block *block, - Offset off, TransferFuncs &xferFuncs, TransferSet &funcSummary); - bool handleThunkCall(InstructionPtr insn, ParseAPI::Block *block, - const Offset off, TransferFuncs &xferFuncs); - bool handleJump(InstructionPtr insn, ParseAPI::Block *block, - Offset off, TransferFuncs &xferFuncs, TransferSet &funcSummary); - void handlePushPop(InstructionPtr insn, ParseAPI::Block *block, - const Offset off, int sign, TransferFuncs &xferFuncs); - void handleReturn(InstructionPtr insn, TransferFuncs &xferFuncs); - void handleAddSub(InstructionPtr insn, ParseAPI::Block *block, - const Offset off, int sign, TransferFuncs &xferFuncs); - void handleLEA(InstructionPtr insn, TransferFuncs &xferFuncs); + void computeInsnEffects(ParseAPI::Block *block, InstructionAPI::Instruction insn, + const Offset off, TransferFuncs &xferFunc, TransferSet &funcSummary); + + bool isCall(InstructionAPI::Instruction insn); + bool isJump(InstructionAPI::Instruction insn); + bool handleNormalCall(InstructionAPI::Instruction insn, ParseAPI::Block *block, + Offset off, TransferFuncs &xferFuncs, TransferSet &funcSummary); + bool handleThunkCall(InstructionAPI::Instruction insn, ParseAPI::Block *block, + const Offset off, TransferFuncs &xferFuncs); + bool handleJump(InstructionAPI::Instruction insn, ParseAPI::Block *block, + Offset off, TransferFuncs &xferFuncs, TransferSet &funcSummary); + void handlePushPop(InstructionAPI::Instruction insn, ParseAPI::Block *block, + const Offset off, int sign, TransferFuncs &xferFuncs); + void handleReturn(InstructionAPI::Instruction insn, TransferFuncs &xferFuncs); + void handleAddSub(InstructionAPI::Instruction insn, ParseAPI::Block *block, + const Offset off, int sign, TransferFuncs &xferFuncs); + void handleLEA(InstructionAPI::Instruction insn, TransferFuncs &xferFuncs); void handleLeave(ParseAPI::Block *block, const Offset off, TransferFuncs &xferFuncs); void handlePushPopFlags(int sign, TransferFuncs &xferFuncs); void handlePushPopRegs(int sign, TransferFuncs &xferFuncs); - void handlePowerAddSub(InstructionPtr insn, ParseAPI::Block *block, - const Offset off, int sign, TransferFuncs &xferFuncs); - void handlePowerStoreUpdate(InstructionPtr insn, ParseAPI::Block *block, - const Offset off, TransferFuncs &xferFuncs); - void handleMov(InstructionPtr insn, ParseAPI::Block *block, - const Offset off, TransferFuncs &xferFuncs); - void handleZeroExtend(InstructionPtr insn, ParseAPI::Block *block, - const Offset off, TransferFuncs &xferFuncs); - void handleSignExtend(InstructionPtr insn, ParseAPI::Block *block, - const Offset off, TransferFuncs &xferFuncs); - void handleSpecialSignExtend(InstructionPtr insn, TransferFuncs &xferFuncs); - void handleXor(InstructionPtr insn, ParseAPI::Block *block, const Offset off, - TransferFuncs &xferFuncs); - void handleDiv(InstructionPtr insn, TransferFuncs &xferFuncs); - void handleMul(InstructionPtr insn, TransferFuncs &xferFuncs); - void handleSyscall(InstructionPtr insn, ParseAPI::Block *block, - const Offset off, TransferFuncs &xferFuncs); - void handleDefault(InstructionPtr insn, ParseAPI::Block *block, - const Offset off, TransferFuncs &xferFuncs); + void handlePowerAddSub(InstructionAPI::Instruction insn, ParseAPI::Block *block, + const Offset off, int sign, TransferFuncs &xferFuncs); + void handlePowerStoreUpdate(InstructionAPI::Instruction insn, ParseAPI::Block *block, + const Offset off, TransferFuncs &xferFuncs); + void handleMov(InstructionAPI::Instruction insn, ParseAPI::Block *block, + const Offset off, TransferFuncs &xferFuncs); + void handleZeroExtend(InstructionAPI::Instruction insn, ParseAPI::Block *block, + const Offset off, TransferFuncs &xferFuncs); + void handleSignExtend(InstructionAPI::Instruction insn, ParseAPI::Block *block, + const Offset off, TransferFuncs &xferFuncs); + void handleSpecialSignExtend(InstructionAPI::Instruction insn, TransferFuncs &xferFuncs); + void handleXor(InstructionAPI::Instruction insn, ParseAPI::Block *block, const Offset off, + TransferFuncs &xferFuncs); + void handleDiv(InstructionAPI::Instruction insn, TransferFuncs &xferFuncs); + void handleMul(InstructionAPI::Instruction insn, TransferFuncs &xferFuncs); + void handleSyscall(InstructionAPI::Instruction insn, ParseAPI::Block *block, + const Offset off, TransferFuncs &xferFuncs); + void handleDefault(InstructionAPI::Instruction insn, ParseAPI::Block *block, + const Offset off, TransferFuncs &xferFuncs); long extractDelta(InstructionAPI::Result deltaRes); bool getSubReg(const MachRegister ®, MachRegister &subreg); diff --git a/dataflowAPI/rose/semantics/DispatcherPowerpc.C b/dataflowAPI/rose/semantics/DispatcherPowerpc.C index e9b1736754..565e3c0f4d 100644 --- a/dataflowAPI/rose/semantics/DispatcherPowerpc.C +++ b/dataflowAPI/rose/semantics/DispatcherPowerpc.C @@ -1074,6 +1074,7 @@ DispatcherPowerpc::iproc_init() iproc_set(powerpc_oris, new Powerpc::IP_oris); iproc_set(powerpc_rldic, new Powerpc::IP_rldicr); iproc_set(powerpc_rldicr, new Powerpc::IP_rldicr); + iproc_set(powerpc_rldicl, new Powerpc::IP_rldicr); iproc_set(powerpc_rlwimi, new Powerpc::IP_rlwimi); iproc_set(powerpc_rlwinm, new Powerpc::IP_rlwinm(false)); iproc_set(powerpc_rlwinm_record, new Powerpc::IP_rlwinm(true)); diff --git a/dataflowAPI/rose/semantics/Registers.C b/dataflowAPI/rose/semantics/Registers.C index 5c8580f198..aa1a728342 100644 --- a/dataflowAPI/rose/semantics/Registers.C +++ b/dataflowAPI/rose/semantics/Registers.C @@ -5,6 +5,7 @@ #include "external/rose/rose-compat.h" #include "external/rose/powerpcInstructionEnum.h" #include +#include // These are here temporarily until the classes in this file can be moved into rose::BinaryAnalysis using namespace rose; @@ -647,8 +648,10 @@ RegisterDictionary::print(std::ostream &o) const { * There are a total of 32 general purpose registers each 64 bits wide. Each of these registers can be addressed as its 32-bit or 64-bit form. The former are named with the prefix W and the latter with a prefix X. The 32nd register is not a physical register but the zero register and referred to as WZR/ZR. */ const RegisterDictionary * RegisterDictionary::dictionary_armv8() { + static std::once_flag initialized; static RegisterDictionary *regs = NULL; - if (!regs) { + + std::call_once(initialized, []() { regs = new RegisterDictionary("armv8"); /* All 60 variations (32- and 64-bit) of the 32 general purpose registers */ @@ -700,7 +703,7 @@ RegisterDictionary::dictionary_armv8() { regs->insert("z", armv8_regclass_pstate, 0, armv8_pstatefield_z, 1); regs->insert("c", armv8_regclass_pstate, 0, armv8_pstatefield_c, 1); regs->insert("v", armv8_regclass_pstate, 0, armv8_pstatefield_v, 1); - } + }); return regs; } @@ -708,8 +711,10 @@ RegisterDictionary::dictionary_armv8() { const RegisterDictionary * RegisterDictionary::dictionary_powerpc() { + static std::once_flag initialized; static RegisterDictionary *regs = NULL; - if (!regs) { + + std::call_once(initialized, []() { regs = new RegisterDictionary("powerpc"); /********************************************************************************************************************** @@ -808,6 +813,6 @@ RegisterDictionary::dictionary_powerpc() regs->insert("tbl", powerpc_regclass_tbr, powerpc_tbr_tbl, 0, 32); /* time base lower */ regs->insert("tbu", powerpc_regclass_tbr, powerpc_tbr_tbu, 0, 32); /* time base upper */ - } + }); return regs; } diff --git a/dataflowAPI/rose/semantics/SymEvalSemantics.h b/dataflowAPI/rose/semantics/SymEvalSemantics.h index 220f87776d..abf1d9c5d8 100644 --- a/dataflowAPI/rose/semantics/SymEvalSemantics.h +++ b/dataflowAPI/rose/semantics/SymEvalSemantics.h @@ -310,7 +310,7 @@ namespace rose { StateAST(Dyninst::DataflowAPI::Result_t &r, Dyninst::Address a, Dyninst::Architecture ac, - Dyninst::InstructionAPI::Instruction::Ptr insn_, + Dyninst::InstructionAPI::Instruction insn_, const BaseSemantics::RegisterStatePtr ®isters, const BaseSemantics::MemoryStatePtr &memory): BaseSemantics::State(registers, memory), res(r), addr(a), arch(ac), insn(insn_) { for (Dyninst::DataflowAPI::Result_t::iterator iter = r.begin(); @@ -338,7 +338,7 @@ namespace rose { static StateASTPtr instance(Dyninst::DataflowAPI::Result_t &r, Dyninst::Address a, Dyninst::Architecture ac, - Dyninst::InstructionAPI::Instruction::Ptr insn_, + Dyninst::InstructionAPI::Instruction insn_, const BaseSemantics::RegisterStatePtr ®isters, const BaseSemantics::MemoryStatePtr &memory) { return StateASTPtr(new StateAST(r, a, ac, insn_, registers, memory)); @@ -347,7 +347,7 @@ namespace rose { virtual BaseSemantics::StatePtr create(Dyninst::DataflowAPI::Result_t &r, Dyninst::Address a, Dyninst::Architecture ac, - Dyninst::InstructionAPI::Instruction::Ptr insn_, + Dyninst::InstructionAPI::Instruction insn_, const BaseSemantics::RegisterStatePtr ®isters, const BaseSemantics::MemoryStatePtr &memory) const { return instance(r, a, ac, insn_, registers, memory); @@ -373,7 +373,7 @@ namespace rose { Dyninst::DataflowAPI::Result_t &res; Dyninst::Architecture arch; Dyninst::Address addr; - Dyninst::InstructionAPI::Instruction::Ptr insn; + Dyninst::InstructionAPI::Instruction insn; std::map aaMap; }; diff --git a/dataflowAPI/src/ABI.C b/dataflowAPI/src/ABI.C index 214b1ab5ad..2b466b33ce 100644 --- a/dataflowAPI/src/ABI.C +++ b/dataflowAPI/src/ABI.C @@ -35,25 +35,25 @@ using namespace Dyninst; using namespace DataflowAPI; -bitArray ABI::callRead_; -bitArray ABI::callWritten_; -bitArray ABI::returnRead_; -bitArray ABI::returnRegs_; -bitArray ABI::callParam_; -bitArray ABI::syscallRead_; -bitArray ABI::syscallWritten_; - -bitArray ABI::callRead64_; -bitArray ABI::callWritten64_; -bitArray ABI::returnRead64_; -bitArray ABI::returnRegs64_; -bitArray ABI::callParam64_; -bitArray ABI::syscallRead64_; -bitArray ABI::syscallWritten64_; -bitArray ABI::allRegs_; -bitArray ABI::allRegs64_; -ABI* ABI::globalABI_ = NULL; -ABI* ABI::globalABI64_ = NULL; +dyn_tls bitArray* ABI::callRead_ = NULL; +dyn_tls bitArray* ABI::callWritten_ = NULL; +dyn_tls bitArray* ABI::returnRead_ = NULL; +dyn_tls bitArray* ABI::returnRegs_ = NULL; +dyn_tls bitArray* ABI::callParam_ = NULL; +dyn_tls bitArray* ABI::syscallRead_ = NULL; +dyn_tls bitArray* ABI::syscallWritten_ = NULL; + +dyn_tls bitArray* ABI::callRead64_ = NULL; +dyn_tls bitArray* ABI::callWritten64_ = NULL; +dyn_tls bitArray* ABI::returnRead64_ = NULL; +dyn_tls bitArray* ABI::returnRegs64_ = NULL; +dyn_tls bitArray* ABI::callParam64_ = NULL; +dyn_tls bitArray* ABI::syscallRead64_ = NULL; +dyn_tls bitArray* ABI::syscallWritten64_ = NULL; +dyn_tls bitArray* ABI::allRegs_ = NULL; +dyn_tls bitArray* ABI::allRegs64_ = NULL; +dyn_tls ABI* ABI::globalABI_ = NULL; +dyn_tls ABI* ABI::globalABI64_ = NULL; int ABI::getIndex(MachRegister machReg){ if (index->find(machReg) == index->end()){ @@ -102,88 +102,88 @@ ABI* ABI::getABI(int addr_width){ const bitArray &ABI::getCallReadRegisters() const { if (addr_width == 4) - return callRead_; + return *callRead_; else if (addr_width == 8) - return callRead64_; + return *callRead64_; else { assert(0); - return callRead_; + return *callRead_; } } const bitArray &ABI::getCallWrittenRegisters() const { if (addr_width == 4) - return callWritten_; + return *callWritten_; else if (addr_width == 8) - return callWritten64_; + return *callWritten64_; else { assert(0); - return callWritten_; + return *callWritten_; } } const bitArray &ABI::getReturnReadRegisters() const { if (addr_width == 4) - return returnRead_; + return *returnRead_; else if (addr_width == 8) - return returnRead64_; + return *returnRead64_; else { assert(0); - return returnRead_; + return *returnRead_; } } const bitArray &ABI::getReturnRegisters() const { if (addr_width == 4) - return returnRegs_; + return *returnRegs_; else if (addr_width == 8) - return returnRegs64_; + return *returnRegs64_; else { assert(0); - return returnRegs_; + return *returnRegs_; } } const bitArray &ABI::getParameterRegisters() const { if (addr_width == 4) - return callParam_; + return *callParam_; else if (addr_width == 8) - return callParam64_; + return *callParam64_; else { assert(0); - return callParam_; + return *callParam_; } } const bitArray &ABI::getSyscallReadRegisters() const { if (addr_width == 4) - return syscallRead_; + return *syscallRead_; else if (addr_width == 8) - return syscallRead64_; + return *syscallRead64_; else { assert(0); - return syscallRead_; + return *syscallRead_; } } const bitArray &ABI::getSyscallWrittenRegisters() const { if (addr_width == 4) - return syscallWritten_; + return *syscallWritten_; else if (addr_width == 8) - return syscallWritten64_; + return *syscallWritten64_; else { assert(0); - return syscallWritten_; + return *syscallWritten_; } } const bitArray &ABI::getAllRegs() const { if (addr_width == 4) - return allRegs_; + return *allRegs_; else if (addr_width == 8) - return allRegs64_; + return *allRegs64_; else { assert(0); - return allRegs_; + return *allRegs_; } } @@ -193,76 +193,77 @@ bitArray ABI::getBitArray() { #if defined(arch_x86) || defined(arch_x86_64) void ABI::initialize32(){ - returnRegs_ = getBitArray(machRegIndex_x86().size()); - returnRegs_[machRegIndex_x86()[x86::eax]] = true; + returnRegs_ = new bitArray(machRegIndex_x86().size()); + (*returnRegs_)[machRegIndex_x86()[x86::eax]] = true; - callParam_ = getBitArray(machRegIndex_x86().size()); + callParam_ = new bitArray(machRegIndex_x86().size()); - returnRead_ = getBitArray(machRegIndex_x86().size()); + returnRead_ = new bitArray(machRegIndex_x86().size()); // Callee-save registers... - returnRead_[machRegIndex_x86()[x86::ebx]] = true; - returnRead_[machRegIndex_x86()[x86::esi]] = true; - returnRead_[machRegIndex_x86()[x86::edi]] = true; + (*returnRead_)[machRegIndex_x86()[x86::ebx]] = true; + (*returnRead_)[machRegIndex_x86()[x86::esi]] = true; + (*returnRead_)[machRegIndex_x86()[x86::edi]] = true; // And return value - returnRead_[machRegIndex_x86()[x86::eax]] = true; + (*returnRead_)[machRegIndex_x86()[x86::eax]] = true; // Return reads no registers - callRead_ = getBitArray(machRegIndex_x86().size()); + callRead_ = new bitArray(machRegIndex_x86().size()); // CallRead reads no registers // We wish... - callRead_[machRegIndex_x86()[x86::ecx]] = true; - callRead_[machRegIndex_x86()[x86::edx]] = true; + (*callRead_)[machRegIndex_x86()[x86::ecx]] = true; + (*callRead_)[machRegIndex_x86()[x86::edx]] = true; // PLT entries use ebx - callRead_[machRegIndex_x86()[x86::ebx]] = true; + (*callRead_)[machRegIndex_x86()[x86::ebx]] = true; // TODO: Fix this for platform-specific calling conventions - callWritten_ = getBitArray(machRegIndex_x86().size()); + callWritten_ = new bitArray(machRegIndex_x86().size()); // Assume calls write flags - callWritten_[machRegIndex_x86()[x86::of]] = true; - callWritten_[machRegIndex_x86()[x86::sf]] = true; - callWritten_[machRegIndex_x86()[x86::zf]] = true; - callWritten_[machRegIndex_x86()[x86::af]] = true; - callWritten_[machRegIndex_x86()[x86::pf]] = true; - callWritten_[machRegIndex_x86()[x86::cf]] = true; - callWritten_[machRegIndex_x86()[x86::tf]] = true; - callWritten_[machRegIndex_x86()[x86::if_]] = true; - callWritten_[machRegIndex_x86()[x86::df]] = true; - callWritten_[machRegIndex_x86()[x86::nt_]] = true; - callWritten_[machRegIndex_x86()[x86::rf]] = true; + (*callWritten_)[machRegIndex_x86()[x86::of]] = true; + (*callWritten_)[machRegIndex_x86()[x86::sf]] = true; + (*callWritten_)[machRegIndex_x86()[x86::zf]] = true; + (*callWritten_)[machRegIndex_x86()[x86::af]] = true; + (*callWritten_)[machRegIndex_x86()[x86::pf]] = true; + (*callWritten_)[machRegIndex_x86()[x86::cf]] = true; + (*callWritten_)[machRegIndex_x86()[x86::tf]] = true; + (*callWritten_)[machRegIndex_x86()[x86::if_]] = true; + (*callWritten_)[machRegIndex_x86()[x86::df]] = true; + (*callWritten_)[machRegIndex_x86()[x86::nt_]] = true; + (*callWritten_)[machRegIndex_x86()[x86::rf]] = true; // And scratch registers: eax, ecx, edx - callWritten_[machRegIndex_x86()[x86::eax]] = true; - callWritten_[machRegIndex_x86()[x86::ecx]] = true; - callWritten_[machRegIndex_x86()[x86::edx]] = true; + (*callWritten_)[machRegIndex_x86()[x86::eax]] = true; + (*callWritten_)[machRegIndex_x86()[x86::ecx]] = true; + (*callWritten_)[machRegIndex_x86()[x86::edx]] = true; - // And assume a syscall reads or writes _everything_ - syscallRead_ = getBitArray(machRegIndex_x86().size()).set(); - syscallWritten_ = syscallRead_; + syscallRead_ = new bitArray(machRegIndex_x86().size()); + syscallRead_->set(); + syscallWritten_ = new bitArray(machRegIndex_x86().size()); + *syscallWritten_ = *syscallRead_; #if defined(os_windows) // VERY conservative, but it's safe wrt the ABI. // Let's set everything and unset flags - callRead_ = syscallRead_; - callRead_[machRegIndex_x86()[x86::of]] = false; - callRead_[machRegIndex_x86()[x86::sf]] = false; - callRead_[machRegIndex_x86()[x86::zf]] = false; - callRead_[machRegIndex_x86()[x86::af]] = false; - callRead_[machRegIndex_x86()[x86::pf]] = false; - callRead_[machRegIndex_x86()[x86::cf]] = false; - callRead_[machRegIndex_x86()[x86::tf]] = false; - callRead_[machRegIndex_x86()[x86::if_]] = false; - callRead_[machRegIndex_x86()[x86::df]] = false; - callRead_[machRegIndex_x86()[x86::nt_]] = false; - callRead_[machRegIndex_x86()[x86::rf]] = false; - - - callWritten_ = syscallWritten_; + (*callRead_) = syscallRead_; + (*callRead_)[machRegIndex_x86()[x86::of]] = false; + (*callRead_)[machRegIndex_x86()[x86::sf]] = false; + (*callRead_)[machRegIndex_x86()[x86::zf]] = false; + (*callRead_)[machRegIndex_x86()[x86::af]] = false; + (*callRead_)[machRegIndex_x86()[x86::pf]] = false; + (*callRead_)[machRegIndex_x86()[x86::cf]] = false; + (*callRead_)[machRegIndex_x86()[x86::tf]] = false; + (*callRead_)[machRegIndex_x86()[x86::if_]] = false; + (*callRead_)[machRegIndex_x86()[x86::df]] = false; + (*callRead_)[machRegIndex_x86()[x86::nt_]] = false; + (*callRead_)[machRegIndex_x86()[x86::rf]] = false; + + + *callWritten_ = *syscallWritten_; // IF DEFINED KEVIN FUNKY MODE - returnRead_ = callRead_; + (*returnRead_) = (*callRead_); // Doesn't exist, but should //returnWritten_ = callWritten_; // ENDIF DEFINED KEVIN FUNKY MODE @@ -270,272 +271,283 @@ void ABI::initialize32(){ #endif - allRegs_ = getBitArray(machRegIndex_x86().size()).set(); + allRegs_ = new bitArray(machRegIndex_x86().size()); + allRegs_->set(); } void ABI::initialize64(){ - returnRegs64_ = getBitArray(machRegIndex_x86_64().size()); - returnRegs64_[machRegIndex_x86_64()[x86_64::rax]] = true; - returnRegs64_[machRegIndex_x86_64()[x86_64::rdx]] = true; - - callParam64_ = getBitArray(machRegIndex_x86_64().size()); - callParam64_[machRegIndex_x86_64()[x86_64::rdi]] = true; - callParam64_[machRegIndex_x86_64()[x86_64::rsi]] = true; - callParam64_[machRegIndex_x86_64()[x86_64::rdx]] = true; - callParam64_[machRegIndex_x86_64()[x86_64::rcx]] = true; - callParam64_[machRegIndex_x86_64()[x86_64::r8]] = true; - callParam64_[machRegIndex_x86_64()[x86_64::r9]] = true; - - returnRead64_ = getBitArray(machRegIndex_x86_64().size()); - returnRead64_[machRegIndex_x86_64()[x86_64::rax]] = true; - returnRead64_[machRegIndex_x86_64()[x86_64::rcx]] = true; //Not correct, temporary + returnRegs64_ = new bitArray(machRegIndex_x86_64().size()); + (*returnRegs64_)[machRegIndex_x86_64()[x86_64::rax]] = true; + (*returnRegs64_)[machRegIndex_x86_64()[x86_64::rdx]] = true; + + callParam64_ = new bitArray(machRegIndex_x86_64().size()); + (*callParam64_)[machRegIndex_x86_64()[x86_64::rdi]] = true; + (*callParam64_)[machRegIndex_x86_64()[x86_64::rsi]] = true; + (*callParam64_)[machRegIndex_x86_64()[x86_64::rdx]] = true; + (*callParam64_)[machRegIndex_x86_64()[x86_64::rcx]] = true; + (*callParam64_)[machRegIndex_x86_64()[x86_64::r8]] = true; + (*callParam64_)[machRegIndex_x86_64()[x86_64::r9]] = true; + + returnRead64_ = new bitArray(machRegIndex_x86_64().size()); + (*returnRead64_)[machRegIndex_x86_64()[x86_64::rax]] = true; + (*returnRead64_)[machRegIndex_x86_64()[x86_64::rcx]] = true; //Not correct, temporary // Returns also "read" any callee-saved registers - returnRead64_[machRegIndex_x86_64()[x86_64::rbx]] = true; - returnRead64_[machRegIndex_x86_64()[x86_64::rdx]] = true; - returnRead64_[machRegIndex_x86_64()[x86_64::r12]] = true; - returnRead64_[machRegIndex_x86_64()[x86_64::r13]] = true; - returnRead64_[machRegIndex_x86_64()[x86_64::r14]] = true; - returnRead64_[machRegIndex_x86_64()[x86_64::r15]] = true; - - returnRead64_[machRegIndex_x86_64()[x86_64::xmm0]] = true; - returnRead64_[machRegIndex_x86_64()[x86_64::xmm1]] = true; - - - callRead64_ = getBitArray(machRegIndex_x86_64().size()); - callRead64_[machRegIndex_x86_64()[x86_64::rax]] = true; - callRead64_[machRegIndex_x86_64()[x86_64::rcx]] = true; - callRead64_[machRegIndex_x86_64()[x86_64::rdx]] = true; - callRead64_[machRegIndex_x86_64()[x86_64::r8]] = true; - callRead64_[machRegIndex_x86_64()[x86_64::r9]] = true; - callRead64_[machRegIndex_x86_64()[x86_64::rdi]] = true; - callRead64_[machRegIndex_x86_64()[x86_64::rsi]] = true; - - callRead64_[machRegIndex_x86_64()[x86_64::xmm0]] = true; - callRead64_[machRegIndex_x86_64()[x86_64::xmm1]] = true; - callRead64_[machRegIndex_x86_64()[x86_64::xmm2]] = true; - callRead64_[machRegIndex_x86_64()[x86_64::xmm3]] = true; - callRead64_[machRegIndex_x86_64()[x86_64::xmm4]] = true; - callRead64_[machRegIndex_x86_64()[x86_64::xmm5]] = true; - callRead64_[machRegIndex_x86_64()[x86_64::xmm6]] = true; - callRead64_[machRegIndex_x86_64()[x86_64::xmm7]] = true; + (*returnRead64_)[machRegIndex_x86_64()[x86_64::rbx]] = true; + (*returnRead64_)[machRegIndex_x86_64()[x86_64::rdx]] = true; + (*returnRead64_)[machRegIndex_x86_64()[x86_64::r12]] = true; + (*returnRead64_)[machRegIndex_x86_64()[x86_64::r13]] = true; + (*returnRead64_)[machRegIndex_x86_64()[x86_64::r14]] = true; + (*returnRead64_)[machRegIndex_x86_64()[x86_64::r15]] = true; + + (*returnRead64_)[machRegIndex_x86_64()[x86_64::xmm0]] = true; + (*returnRead64_)[machRegIndex_x86_64()[x86_64::xmm1]] = true; + + + callRead64_ = new bitArray(machRegIndex_x86_64().size()); + (*callRead64_)[machRegIndex_x86_64()[x86_64::rax]] = true; + (*callRead64_)[machRegIndex_x86_64()[x86_64::rcx]] = true; + (*callRead64_)[machRegIndex_x86_64()[x86_64::rdx]] = true; + (*callRead64_)[machRegIndex_x86_64()[x86_64::r8]] = true; + (*callRead64_)[machRegIndex_x86_64()[x86_64::r9]] = true; + (*callRead64_)[machRegIndex_x86_64()[x86_64::rdi]] = true; + (*callRead64_)[machRegIndex_x86_64()[x86_64::rsi]] = true; + + (*callRead64_)[machRegIndex_x86_64()[x86_64::xmm0]] = true; + (*callRead64_)[machRegIndex_x86_64()[x86_64::xmm1]] = true; + (*callRead64_)[machRegIndex_x86_64()[x86_64::xmm2]] = true; + (*callRead64_)[machRegIndex_x86_64()[x86_64::xmm3]] = true; + (*callRead64_)[machRegIndex_x86_64()[x86_64::xmm4]] = true; + (*callRead64_)[machRegIndex_x86_64()[x86_64::xmm5]] = true; + (*callRead64_)[machRegIndex_x86_64()[x86_64::xmm6]] = true; + (*callRead64_)[machRegIndex_x86_64()[x86_64::xmm7]] = true; // Anything in those four is not preserved across a call... // So we copy this as a shorthand then augment it - callWritten64_ = callRead64_; + callWritten64_ = new bitArray(machRegIndex_x86_64().size()); + (*callWritten64_) = (*callRead64_); // As well as RAX, R10, R11 - callWritten64_[machRegIndex_x86_64()[x86_64::rax]] = true; - callWritten64_[machRegIndex_x86_64()[x86_64::r10]] = true; - callWritten64_[machRegIndex_x86_64()[x86_64::r11]] = true; + (*callWritten64_)[machRegIndex_x86_64()[x86_64::rax]] = true; + (*callWritten64_)[machRegIndex_x86_64()[x86_64::r10]] = true; + (*callWritten64_)[machRegIndex_x86_64()[x86_64::r11]] = true; // And flags - callWritten64_[machRegIndex_x86_64()[x86_64::of]] = true; - callWritten64_[machRegIndex_x86_64()[x86_64::sf]] = true; - callWritten64_[machRegIndex_x86_64()[x86_64::zf]] = true; - callWritten64_[machRegIndex_x86_64()[x86_64::af]] = true; - callWritten64_[machRegIndex_x86_64()[x86_64::pf]] = true; - callWritten64_[machRegIndex_x86_64()[x86_64::cf]] = true; - callWritten64_[machRegIndex_x86_64()[x86_64::tf]] = true; - callWritten64_[machRegIndex_x86_64()[x86_64::if_]] = true; - callWritten64_[machRegIndex_x86_64()[x86_64::df]] = true; - callWritten64_[machRegIndex_x86_64()[x86_64::nt_]] = true; - callWritten64_[machRegIndex_x86_64()[x86_64::rf]] = true; + (*callWritten64_)[machRegIndex_x86_64()[x86_64::of]] = true; + (*callWritten64_)[machRegIndex_x86_64()[x86_64::sf]] = true; + (*callWritten64_)[machRegIndex_x86_64()[x86_64::zf]] = true; + (*callWritten64_)[machRegIndex_x86_64()[x86_64::af]] = true; + (*callWritten64_)[machRegIndex_x86_64()[x86_64::pf]] = true; + (*callWritten64_)[machRegIndex_x86_64()[x86_64::cf]] = true; + (*callWritten64_)[machRegIndex_x86_64()[x86_64::tf]] = true; + (*callWritten64_)[machRegIndex_x86_64()[x86_64::if_]] = true; + (*callWritten64_)[machRegIndex_x86_64()[x86_64::df]] = true; + (*callWritten64_)[machRegIndex_x86_64()[x86_64::nt_]] = true; + (*callWritten64_)[machRegIndex_x86_64()[x86_64::rf]] = true; // And assume a syscall reads or writes _everything_ - syscallRead64_ = getBitArray(machRegIndex_x86_64().size()).set(); + syscallRead64_ = new bitArray(machRegIndex_x86_64().size()); + syscallRead64_->set(); + syscallWritten64_ = new bitArray(machRegIndex_x86_64().size()); syscallWritten64_ = syscallRead64_; - allRegs64_ = getBitArray(machRegIndex_x86_64().size()).set(); + allRegs64_ = new bitArray(machRegIndex_x86_64().size()); + allRegs64_->set(); } #endif #if defined(arch_power) void ABI::initialize32(){ - returnRegs_ = getBitArray(machRegIndex_ppc().size()); - returnRegs_[machRegIndex_ppc()[ppc32::r3]] = true; + returnRegs_ = new bitArray(machRegIndex_ppc().size()); + (*returnRegs_)[machRegIndex_ppc()[ppc32::r3]] = true; - callParam_ = getBitArray(machRegIndex_ppc().size()); - callParam_[machRegIndex_ppc()[ppc32::r3]] = true; - callParam_[machRegIndex_ppc()[ppc32::r4]] = true; - callParam_[machRegIndex_ppc()[ppc32::r5]] = true; - callParam_[machRegIndex_ppc()[ppc32::r6]] = true; - callParam_[machRegIndex_ppc()[ppc32::r7]] = true; - callParam_[machRegIndex_ppc()[ppc32::r8]] = true; - callParam_[machRegIndex_ppc()[ppc32::r9]] = true; - callParam_[machRegIndex_ppc()[ppc32::r10]] = true; + callParam_ = new bitArray(machRegIndex_ppc().size()); + (*callParam_)[machRegIndex_ppc()[ppc32::r3]] = true; + (*callParam_)[machRegIndex_ppc()[ppc32::r4]] = true; + (*callParam_)[machRegIndex_ppc()[ppc32::r5]] = true; + (*callParam_)[machRegIndex_ppc()[ppc32::r6]] = true; + (*callParam_)[machRegIndex_ppc()[ppc32::r7]] = true; + (*callParam_)[machRegIndex_ppc()[ppc32::r8]] = true; + (*callParam_)[machRegIndex_ppc()[ppc32::r9]] = true; + (*callParam_)[machRegIndex_ppc()[ppc32::r10]] = true; - returnRead_ = getBitArray(machRegIndex_ppc().size()); + returnRead_ = new bitArray(machRegIndex_ppc().size()); // Return reads r3, r4, fpr1, fpr2 - returnRead_[machRegIndex_ppc()[ppc32::r3]] = true; - returnRead_[machRegIndex_ppc()[ppc32::r4]] = true; - returnRead_[machRegIndex_ppc()[ppc32::fpr1]] = true; - returnRead_[machRegIndex_ppc()[ppc32::fpr2]] = true; + (*returnRead_)[machRegIndex_ppc()[ppc32::r3]] = true; + (*returnRead_)[machRegIndex_ppc()[ppc32::r4]] = true; + (*returnRead_)[machRegIndex_ppc()[ppc32::fpr1]] = true; + (*returnRead_)[machRegIndex_ppc()[ppc32::fpr2]] = true; // Calls - callRead_ = getBitArray(machRegIndex_ppc().size()); + callRead_ = new bitArray(machRegIndex_ppc().size()); // Calls read r3 -> r10 (parameters), fpr1 -> fpr13 (volatile FPRs) /* for (unsigned i = r3; i <= r10; i++) callRead_[i] = true; for (unsigned i = fpr1; i <= fpr13; i++) callRead_[i] = true;*/ - callRead_[machRegIndex_ppc()[ppc32::r3]] = true; - callRead_[machRegIndex_ppc()[ppc32::r4]] = true; - callRead_[machRegIndex_ppc()[ppc32::r5]] = true; - callRead_[machRegIndex_ppc()[ppc32::r6]] = true; - callRead_[machRegIndex_ppc()[ppc32::r7]] = true; - callRead_[machRegIndex_ppc()[ppc32::r8]] = true; - callRead_[machRegIndex_ppc()[ppc32::r9]] = true; - callRead_[machRegIndex_ppc()[ppc32::r10]] = true; - - callRead_[machRegIndex_ppc()[ppc32::fpr1]] = true; - callRead_[machRegIndex_ppc()[ppc32::fpr2]] = true; - callRead_[machRegIndex_ppc()[ppc32::fpr3]] = true; - callRead_[machRegIndex_ppc()[ppc32::fpr4]] = true; - callRead_[machRegIndex_ppc()[ppc32::fpr5]] = true; - callRead_[machRegIndex_ppc()[ppc32::fpr6]] = true; - callRead_[machRegIndex_ppc()[ppc32::fpr7]] = true; - callRead_[machRegIndex_ppc()[ppc32::fpr8]] = true; - callRead_[machRegIndex_ppc()[ppc32::fpr9]] = true; - callRead_[machRegIndex_ppc()[ppc32::fpr10]] = true; - callRead_[machRegIndex_ppc()[ppc32::fpr11]] = true; - callRead_[machRegIndex_ppc()[ppc32::fpr12]] = true; - callRead_[machRegIndex_ppc()[ppc32::fpr13]] = true; - - callWritten_ = getBitArray(machRegIndex_ppc().size()); + (*callRead_)[machRegIndex_ppc()[ppc32::r3]] = true; + (*callRead_)[machRegIndex_ppc()[ppc32::r4]] = true; + (*callRead_)[machRegIndex_ppc()[ppc32::r5]] = true; + (*callRead_)[machRegIndex_ppc()[ppc32::r6]] = true; + (*callRead_)[machRegIndex_ppc()[ppc32::r7]] = true; + (*callRead_)[machRegIndex_ppc()[ppc32::r8]] = true; + (*callRead_)[machRegIndex_ppc()[ppc32::r9]] = true; + (*callRead_)[machRegIndex_ppc()[ppc32::r10]] = true; + + (*callRead_)[machRegIndex_ppc()[ppc32::fpr1]] = true; + (*callRead_)[machRegIndex_ppc()[ppc32::fpr2]] = true; + (*callRead_)[machRegIndex_ppc()[ppc32::fpr3]] = true; + (*callRead_)[machRegIndex_ppc()[ppc32::fpr4]] = true; + (*callRead_)[machRegIndex_ppc()[ppc32::fpr5]] = true; + (*callRead_)[machRegIndex_ppc()[ppc32::fpr6]] = true; + (*callRead_)[machRegIndex_ppc()[ppc32::fpr7]] = true; + (*callRead_)[machRegIndex_ppc()[ppc32::fpr8]] = true; + (*callRead_)[machRegIndex_ppc()[ppc32::fpr9]] = true; + (*callRead_)[machRegIndex_ppc()[ppc32::fpr10]] = true; + (*callRead_)[machRegIndex_ppc()[ppc32::fpr11]] = true; + (*callRead_)[machRegIndex_ppc()[ppc32::fpr12]] = true; + (*callRead_)[machRegIndex_ppc()[ppc32::fpr13]] = true; + + callWritten_ = new bitArray(machRegIndex_ppc().size()); // Calls write to pretty much every register we use for code generation - callWritten_[machRegIndex_ppc()[ppc32::r0]] = true; + (*callWritten_)[machRegIndex_ppc()[ppc32::r0]] = true; /* for (unsigned i = r3; i <= r12; i++) callWritten_[i] = true; // FPRs 0->13 are volatile for (unsigned i = fpr0; i <= fpr13; i++) callWritten_[i] = true;*/ - callWritten_[machRegIndex_ppc()[ppc32::r3]] = true; - callWritten_[machRegIndex_ppc()[ppc32::r4]] = true; - callWritten_[machRegIndex_ppc()[ppc32::r5]] = true; - callWritten_[machRegIndex_ppc()[ppc32::r6]] = true; - callWritten_[machRegIndex_ppc()[ppc32::r7]] = true; - callWritten_[machRegIndex_ppc()[ppc32::r8]] = true; - callWritten_[machRegIndex_ppc()[ppc32::r9]] = true; - callWritten_[machRegIndex_ppc()[ppc32::r10]] = true; - callWritten_[machRegIndex_ppc()[ppc32::r11]] = true; - callWritten_[machRegIndex_ppc()[ppc32::r12]] = true; - - callWritten_[machRegIndex_ppc()[ppc32::fpr0]] = true; - callWritten_[machRegIndex_ppc()[ppc32::fpr1]] = true; - callWritten_[machRegIndex_ppc()[ppc32::fpr2]] = true; - callWritten_[machRegIndex_ppc()[ppc32::fpr3]] = true; - callWritten_[machRegIndex_ppc()[ppc32::fpr4]] = true; - callWritten_[machRegIndex_ppc()[ppc32::fpr5]] = true; - callWritten_[machRegIndex_ppc()[ppc32::fpr6]] = true; - callWritten_[machRegIndex_ppc()[ppc32::fpr7]] = true; - callWritten_[machRegIndex_ppc()[ppc32::fpr8]] = true; - callWritten_[machRegIndex_ppc()[ppc32::fpr9]] = true; - callWritten_[machRegIndex_ppc()[ppc32::fpr10]] = true; - callWritten_[machRegIndex_ppc()[ppc32::fpr11]] = true; - callWritten_[machRegIndex_ppc()[ppc32::fpr12]] = true; - callWritten_[machRegIndex_ppc()[ppc32::fpr13]] = true; + (*callWritten_)[machRegIndex_ppc()[ppc32::r3]] = true; + (*callWritten_)[machRegIndex_ppc()[ppc32::r4]] = true; + (*callWritten_)[machRegIndex_ppc()[ppc32::r5]] = true; + (*callWritten_)[machRegIndex_ppc()[ppc32::r6]] = true; + (*callWritten_)[machRegIndex_ppc()[ppc32::r7]] = true; + (*callWritten_)[machRegIndex_ppc()[ppc32::r8]] = true; + (*callWritten_)[machRegIndex_ppc()[ppc32::r9]] = true; + (*callWritten_)[machRegIndex_ppc()[ppc32::r10]] = true; + (*callWritten_)[machRegIndex_ppc()[ppc32::r11]] = true; + (*callWritten_)[machRegIndex_ppc()[ppc32::r12]] = true; + + (*callWritten_)[machRegIndex_ppc()[ppc32::fpr0]] = true; + (*callWritten_)[machRegIndex_ppc()[ppc32::fpr1]] = true; + (*callWritten_)[machRegIndex_ppc()[ppc32::fpr2]] = true; + (*callWritten_)[machRegIndex_ppc()[ppc32::fpr3]] = true; + (*callWritten_)[machRegIndex_ppc()[ppc32::fpr4]] = true; + (*callWritten_)[machRegIndex_ppc()[ppc32::fpr5]] = true; + (*callWritten_)[machRegIndex_ppc()[ppc32::fpr6]] = true; + (*callWritten_)[machRegIndex_ppc()[ppc32::fpr7]] = true; + (*callWritten_)[machRegIndex_ppc()[ppc32::fpr8]] = true; + (*callWritten_)[machRegIndex_ppc()[ppc32::fpr9]] = true; + (*callWritten_)[machRegIndex_ppc()[ppc32::fpr10]] = true; + (*callWritten_)[machRegIndex_ppc()[ppc32::fpr11]] = true; + (*callWritten_)[machRegIndex_ppc()[ppc32::fpr12]] = true; + (*callWritten_)[machRegIndex_ppc()[ppc32::fpr13]] = true; // Syscall - assume the same as call - //syscallRead_ = getBitArray().set(); - //syscallWritten_ = getBitArray().set(); - syscallRead_ = callRead_; - syscallRead_[machRegIndex_ppc()[ppc32::r0]] = true; - syscallWritten_ = callWritten_; - - allRegs_ = getBitArray(machRegIndex_ppc().size()).set(); + //syscallRead_ = new bitArray().set(); + //syscallWritten_ = new bitArray().set(); + syscallRead_ = new bitArray(machRegIndex_ppc().size()); + (*syscallRead_) = (*callRead_); + (*syscallRead_)[machRegIndex_ppc()[ppc32::r0]] = true; + syscallWritten_ = new bitArray(machRegIndex_ppc().size()); + *syscallWritten_ = (*callWritten_); + + allRegs_ = new bitArray(machRegIndex_ppc().size()); + allRegs_->set(); } void ABI::initialize64(){ - returnRegs64_ = getBitArray(machRegIndex_ppc_64().size()); - returnRegs64_[machRegIndex_ppc_64()[ppc64::r3]] = true; - - callParam64_ = getBitArray(machRegIndex_ppc_64().size()); - callParam64_[machRegIndex_ppc_64()[ppc64::r3]] = true; - callParam64_[machRegIndex_ppc_64()[ppc64::r4]] = true; - callParam64_[machRegIndex_ppc_64()[ppc64::r5]] = true; - callParam64_[machRegIndex_ppc_64()[ppc64::r6]] = true; - callParam64_[machRegIndex_ppc_64()[ppc64::r7]] = true; - callParam64_[machRegIndex_ppc_64()[ppc64::r8]] = true; - callParam64_[machRegIndex_ppc_64()[ppc64::r9]] = true; - callParam64_[machRegIndex_ppc_64()[ppc64::r10]] = true; - - returnRead64_ = getBitArray(machRegIndex_ppc_64().size()); + returnRegs64_ = new bitArray(machRegIndex_ppc_64().size()); + (*returnRegs64_)[machRegIndex_ppc_64()[ppc64::r3]] = true; + + callParam64_ = new bitArray(machRegIndex_ppc_64().size()); + (*callParam64_)[machRegIndex_ppc_64()[ppc64::r3]] = true; + (*callParam64_)[machRegIndex_ppc_64()[ppc64::r4]] = true; + (*callParam64_)[machRegIndex_ppc_64()[ppc64::r5]] = true; + (*callParam64_)[machRegIndex_ppc_64()[ppc64::r6]] = true; + (*callParam64_)[machRegIndex_ppc_64()[ppc64::r7]] = true; + (*callParam64_)[machRegIndex_ppc_64()[ppc64::r8]] = true; + (*callParam64_)[machRegIndex_ppc_64()[ppc64::r9]] = true; + (*callParam64_)[machRegIndex_ppc_64()[ppc64::r10]] = true; + + returnRead64_ = new bitArray(machRegIndex_ppc_64().size()); // Return reads r3, r4, fpr1, fpr2 - returnRead64_[machRegIndex_ppc_64()[ppc64::r3]] = true; - returnRead64_[machRegIndex_ppc_64()[ppc64::r4]] = true; - returnRead64_[machRegIndex_ppc_64()[ppc64::fpr3]] = true; - returnRead64_[machRegIndex_ppc_64()[ppc64::fpr2]] = true; + (*returnRead64_)[machRegIndex_ppc_64()[ppc64::r3]] = true; + (*returnRead64_)[machRegIndex_ppc_64()[ppc64::r4]] = true; + (*returnRead64_)[machRegIndex_ppc_64()[ppc64::fpr3]] = true; + (*returnRead64_)[machRegIndex_ppc_64()[ppc64::fpr2]] = true; // Calls - callRead64_ = getBitArray(machRegIndex_ppc_64().size()); + callRead64_ = new bitArray(machRegIndex_ppc_64().size()); // Calls read r3 -> r10 (parameters), fpr1 -> fpr13 (volatile FPRs) - callRead64_[machRegIndex_ppc_64()[ppc64::r3]] = true; - callRead64_[machRegIndex_ppc_64()[ppc64::r4]] = true; - callRead64_[machRegIndex_ppc_64()[ppc64::r5]] = true; - callRead64_[machRegIndex_ppc_64()[ppc64::r6]] = true; - callRead64_[machRegIndex_ppc_64()[ppc64::r7]] = true; - callRead64_[machRegIndex_ppc_64()[ppc64::r8]] = true; - callRead64_[machRegIndex_ppc_64()[ppc64::r9]] = true; - callRead64_[machRegIndex_ppc_64()[ppc64::r10]] = true; - - callRead64_[machRegIndex_ppc_64()[ppc64::fpr1]] = true; - callRead64_[machRegIndex_ppc_64()[ppc64::fpr2]] = true; - callRead64_[machRegIndex_ppc_64()[ppc64::fpr3]] = true; - callRead64_[machRegIndex_ppc_64()[ppc64::fpr4]] = true; - callRead64_[machRegIndex_ppc_64()[ppc64::fpr5]] = true; - callRead64_[machRegIndex_ppc_64()[ppc64::fpr6]] = true; - callRead64_[machRegIndex_ppc_64()[ppc64::fpr7]] = true; - callRead64_[machRegIndex_ppc_64()[ppc64::fpr8]] = true; - callRead64_[machRegIndex_ppc_64()[ppc64::fpr9]] = true; - callRead64_[machRegIndex_ppc_64()[ppc64::fpr10]] = true; - callRead64_[machRegIndex_ppc_64()[ppc64::fpr11]] = true; - callRead64_[machRegIndex_ppc_64()[ppc64::fpr12]] = true; - callRead64_[machRegIndex_ppc_64()[ppc64::fpr13]] = true; - - - callWritten64_ = getBitArray(machRegIndex_ppc_64().size()); + (*callRead64_)[machRegIndex_ppc_64()[ppc64::r3]] = true; + (*callRead64_)[machRegIndex_ppc_64()[ppc64::r4]] = true; + (*callRead64_)[machRegIndex_ppc_64()[ppc64::r5]] = true; + (*callRead64_)[machRegIndex_ppc_64()[ppc64::r6]] = true; + (*callRead64_)[machRegIndex_ppc_64()[ppc64::r7]] = true; + (*callRead64_)[machRegIndex_ppc_64()[ppc64::r8]] = true; + (*callRead64_)[machRegIndex_ppc_64()[ppc64::r9]] = true; + (*callRead64_)[machRegIndex_ppc_64()[ppc64::r10]] = true; + + (*callRead64_)[machRegIndex_ppc_64()[ppc64::fpr1]] = true; + (*callRead64_)[machRegIndex_ppc_64()[ppc64::fpr2]] = true; + (*callRead64_)[machRegIndex_ppc_64()[ppc64::fpr3]] = true; + (*callRead64_)[machRegIndex_ppc_64()[ppc64::fpr4]] = true; + (*callRead64_)[machRegIndex_ppc_64()[ppc64::fpr5]] = true; + (*callRead64_)[machRegIndex_ppc_64()[ppc64::fpr6]] = true; + (*callRead64_)[machRegIndex_ppc_64()[ppc64::fpr7]] = true; + (*callRead64_)[machRegIndex_ppc_64()[ppc64::fpr8]] = true; + (*callRead64_)[machRegIndex_ppc_64()[ppc64::fpr9]] = true; + (*callRead64_)[machRegIndex_ppc_64()[ppc64::fpr10]] = true; + (*callRead64_)[machRegIndex_ppc_64()[ppc64::fpr11]] = true; + (*callRead64_)[machRegIndex_ppc_64()[ppc64::fpr12]] = true; + (*callRead64_)[machRegIndex_ppc_64()[ppc64::fpr13]] = true; + + + callWritten64_ = new bitArray(machRegIndex_ppc_64().size()); // Calls write to pretty much every register we use for code generation - callWritten64_[machRegIndex_ppc_64()[ppc64::r0]] = true; - - callWritten64_[machRegIndex_ppc_64()[ppc64::r3]] = true; - callWritten64_[machRegIndex_ppc_64()[ppc64::r4]] = true; - callWritten64_[machRegIndex_ppc_64()[ppc64::r5]] = true; - callWritten64_[machRegIndex_ppc_64()[ppc64::r6]] = true; - callWritten64_[machRegIndex_ppc_64()[ppc64::r7]] = true; - callWritten64_[machRegIndex_ppc_64()[ppc64::r8]] = true; - callWritten64_[machRegIndex_ppc_64()[ppc64::r9]] = true; - callWritten64_[machRegIndex_ppc_64()[ppc64::r10]] = true; - callWritten64_[machRegIndex_ppc_64()[ppc64::r11]] = true; - callWritten64_[machRegIndex_ppc_64()[ppc64::r12]] = true; - - callWritten64_[machRegIndex_ppc_64()[ppc64::fpr0]] = true; - callWritten64_[machRegIndex_ppc_64()[ppc64::fpr1]] = true; - callWritten64_[machRegIndex_ppc_64()[ppc64::fpr2]] = true; - callWritten64_[machRegIndex_ppc_64()[ppc64::fpr3]] = true; - callWritten64_[machRegIndex_ppc_64()[ppc64::fpr4]] = true; - callWritten64_[machRegIndex_ppc_64()[ppc64::fpr5]] = true; - callWritten64_[machRegIndex_ppc_64()[ppc64::fpr6]] = true; - callWritten64_[machRegIndex_ppc_64()[ppc64::fpr7]] = true; - callWritten64_[machRegIndex_ppc_64()[ppc64::fpr8]] = true; - callWritten64_[machRegIndex_ppc_64()[ppc64::fpr9]] = true; - callWritten64_[machRegIndex_ppc_64()[ppc64::fpr10]] = true; - callWritten64_[machRegIndex_ppc_64()[ppc64::fpr11]] = true; - callWritten64_[machRegIndex_ppc_64()[ppc64::fpr12]] = true; - callWritten64_[machRegIndex_ppc_64()[ppc64::fpr13]] = true; + (*callWritten64_)[machRegIndex_ppc_64()[ppc64::r0]] = true; + + (*callWritten64_)[machRegIndex_ppc_64()[ppc64::r3]] = true; + (*callWritten64_)[machRegIndex_ppc_64()[ppc64::r4]] = true; + (*callWritten64_)[machRegIndex_ppc_64()[ppc64::r5]] = true; + (*callWritten64_)[machRegIndex_ppc_64()[ppc64::r6]] = true; + (*callWritten64_)[machRegIndex_ppc_64()[ppc64::r7]] = true; + (*callWritten64_)[machRegIndex_ppc_64()[ppc64::r8]] = true; + (*callWritten64_)[machRegIndex_ppc_64()[ppc64::r9]] = true; + (*callWritten64_)[machRegIndex_ppc_64()[ppc64::r10]] = true; + (*callWritten64_)[machRegIndex_ppc_64()[ppc64::r11]] = true; + (*callWritten64_)[machRegIndex_ppc_64()[ppc64::r12]] = true; + + (*callWritten64_)[machRegIndex_ppc_64()[ppc64::fpr0]] = true; + (*callWritten64_)[machRegIndex_ppc_64()[ppc64::fpr1]] = true; + (*callWritten64_)[machRegIndex_ppc_64()[ppc64::fpr2]] = true; + (*callWritten64_)[machRegIndex_ppc_64()[ppc64::fpr3]] = true; + (*callWritten64_)[machRegIndex_ppc_64()[ppc64::fpr4]] = true; + (*callWritten64_)[machRegIndex_ppc_64()[ppc64::fpr5]] = true; + (*callWritten64_)[machRegIndex_ppc_64()[ppc64::fpr6]] = true; + (*callWritten64_)[machRegIndex_ppc_64()[ppc64::fpr7]] = true; + (*callWritten64_)[machRegIndex_ppc_64()[ppc64::fpr8]] = true; + (*callWritten64_)[machRegIndex_ppc_64()[ppc64::fpr9]] = true; + (*callWritten64_)[machRegIndex_ppc_64()[ppc64::fpr10]] = true; + (*callWritten64_)[machRegIndex_ppc_64()[ppc64::fpr11]] = true; + (*callWritten64_)[machRegIndex_ppc_64()[ppc64::fpr12]] = true; + (*callWritten64_)[machRegIndex_ppc_64()[ppc64::fpr13]] = true; // Syscall - assume the same as call - syscallRead64_ = getBitArray(machRegIndex_ppc_64().size()).set(); - syscallWritten64_ = getBitArray(machRegIndex_ppc_64().size()).set(); + syscallRead64_ = new bitArray(machRegIndex_ppc_64().size()); + syscallRead64_->set(); + syscallWritten64_ = new bitArray(machRegIndex_ppc_64().size()); + syscallWritten64_->set(); - allRegs64_ = getBitArray(machRegIndex_ppc_64().size()).set(); + allRegs64_ = new bitArray(machRegIndex_ppc_64().size()); + allRegs64_->set(); } #endif diff --git a/dataflowAPI/src/Absloc.C b/dataflowAPI/src/Absloc.C index ebea96465b..05aac543f1 100644 --- a/dataflowAPI/src/Absloc.C +++ b/dataflowAPI/src/Absloc.C @@ -268,7 +268,7 @@ void AbsRegion::erase(const AbsRegion &rhs) { } */ -Assignment::Ptr Assignment::makeAssignment(const InstructionAPI::Instruction::Ptr i, +Assignment::Ptr Assignment::makeAssignment(const InstructionAPI::Instruction& i, const Address a, ParseAPI::Function *f, ParseAPI::Block *b, @@ -277,7 +277,7 @@ Assignment::Ptr Assignment::makeAssignment(const InstructionAPI::Instruction::Pt return make_shared(singleton_object_pool::construct(i, a, f, b, ins, o)); } -Assignment::Ptr Assignment::makeAssignment(const InstructionAPI::Instruction::Ptr i, +Assignment::Ptr Assignment::makeAssignment(const InstructionAPI::Instruction& i, const Address a, ParseAPI::Function *f, ParseAPI::Block *b, diff --git a/dataflowAPI/src/AbslocInterface.C b/dataflowAPI/src/AbslocInterface.C index fddbbf4583..68274dfbd7 100644 --- a/dataflowAPI/src/AbslocInterface.C +++ b/dataflowAPI/src/AbslocInterface.C @@ -37,6 +37,8 @@ #include "Register.h" #include "Result.h" #include "Dereference.h" +#include "BinaryFunction.h" +#include "Immediate.h" #include "dataflowAPI/h/stackanalysis.h" #include "common/src/singleton_object_pool.h" @@ -76,7 +78,7 @@ void AbsRegionConverter::convertAll(InstructionAPI::Expression::Ptr expr, } } -void AbsRegionConverter::convertAll(InstructionAPI::Instruction::Ptr insn, +void AbsRegionConverter::convertAll(InstructionAPI::Instruction insn, Address addr, ParseAPI::Function *func, ParseAPI::Block *block, @@ -85,12 +87,12 @@ void AbsRegionConverter::convertAll(InstructionAPI::Instruction::Ptr insn, if (!usedCache(addr, func, used)) { std::set regsRead; - insn->getReadSet(regsRead); + insn.getReadSet(regsRead); for (std::set::const_iterator i = regsRead.begin(); i != regsRead.end(); ++i) { - if(insn->getArch() == Arch_aarch64) { + if(insn.getArch() == Arch_aarch64) { MachRegister machReg = (*i)->getID(); std::vector flagRegs = {aarch64::n, aarch64::z, aarch64::c, aarch64::v}; @@ -106,9 +108,9 @@ void AbsRegionConverter::convertAll(InstructionAPI::Instruction::Ptr insn, } } - if (insn->readsMemory()) { + if (insn.readsMemory()) { std::set memReads; - insn->getMemoryReadOperands(memReads); + insn.getMemoryReadOperands(memReads); for (std::set::const_iterator r = memReads.begin(); r != memReads.end(); ++r) { @@ -119,10 +121,10 @@ void AbsRegionConverter::convertAll(InstructionAPI::Instruction::Ptr insn, if (!definedCache(addr, func, defined)) { // Defined time std::set regsWritten; - insn->getWriteSet(regsWritten); + insn.getWriteSet(regsWritten); for (std::set::const_iterator i = regsWritten.begin(); i != regsWritten.end(); ++i) { - if(insn->getArch() == Arch_aarch64) { + if(insn.getArch() == Arch_aarch64) { MachRegister machReg = (*i)->getID(); std::vector flagRegs = {aarch64::n, aarch64::z, aarch64::c, aarch64::v}; @@ -140,17 +142,17 @@ void AbsRegionConverter::convertAll(InstructionAPI::Instruction::Ptr insn, // special case for repeat-prefixed instructions on x86 // may disappear if Dyninst's representation of these instructions changes - if (insn->getArch() == Arch_x86) { - prefixEntryID insnPrefix = insn->getOperation().getPrefixID(); + if (insn.getArch() == Arch_x86) { + prefixEntryID insnPrefix = insn.getOperation().getPrefixID(); if ( (prefix_rep == insnPrefix) || (prefix_repnz == insnPrefix) ) { defined.push_back(AbsRegionConverter::convert(RegisterAST::Ptr( new RegisterAST(MachRegister::getPC(Arch_x86))))); } } - if (insn->writesMemory()) { + if (insn.writesMemory()) { std::set memWrites; - insn->getMemoryWriteOperands(memWrites); + insn.getMemoryWriteOperands(memWrites); for (std::set::const_iterator r = memWrites.begin(); r != memWrites.end(); ++r) { @@ -166,15 +168,102 @@ void AbsRegionConverter::convertAll(InstructionAPI::Instruction::Ptr insn, } AbsRegion AbsRegionConverter::convert(RegisterAST::Ptr reg) { - // FIXME: - // Upcast register so we can be sure to match things later - AbsRegion tmp = AbsRegion(Absloc(reg->getID().getBaseRegister())); - - //std::cerr << "ARC::convert from " << reg->format() << " to " - // << tmp.format() << std::endl; - return tmp; + // We do not distinguish partial registers from full register. + // So, eax and rax are treated the same. + // But for flags, we want to separate CF, ZF, and so on + if (reg->getID().isFlag()) { + return AbsRegion(Absloc(reg->getID())); + } else { + return AbsRegion(Absloc(reg->getID().getBaseRegister())); + } } +class bindKnownRegs : public InstructionAPI::Visitor +{ +public: + bindKnownRegs(Address sp, Address fp, Address ip, bool sdef, bool fdef) : + defined(true), + is_stack(false), + is_frame(false), + m_sp(sp), + m_fp(fp), + m_ip(ip), + stackDefined(sdef), + frameDefined(fdef) {} + virtual ~bindKnownRegs() {} + bool defined; + bool is_stack; + bool is_frame; + std::deque results; + Address m_sp; + Address m_fp; + Address m_ip; + bool stackDefined; + bool frameDefined; + long getResult() { + if(results.empty()) return 0; + return results.front(); + } + bool isDefined() { + return defined && (results.size() == 1); + } + virtual void visit(BinaryFunction* b) + { + if(!defined) return; + long arg1 = results.back(); + results.pop_back(); + long arg2 = results.back(); + results.pop_back(); + if(b->isAdd()) + { + results.push_back(arg1+arg2); + } + else if(b->isMultiply()) + { + results.push_back(arg1*arg2); + } + else + { + defined = false; + } + } + virtual void visit(Immediate* i) + { + if(!defined) return; + results.push_back(i->eval().convert()); + } + virtual void visit(RegisterAST* r) + { + if(!defined) return; + if(r->getID().isPC()) + { + results.push_back(m_ip); + return; + } + if(r->getID().isFramePointer() && frameDefined) + { + results.push_back(m_fp); + is_frame = true; + return; + } + if(r->getID().isStackPointer() && stackDefined) + { + results.push_back(m_sp); + is_stack = true; + return; + } + + defined = false; + results.push_back(0); + } + virtual void visit(Dereference* ) + { + //defined = false; + } + +}; + + AbsRegion AbsRegionConverter::convert(Expression::Ptr exp, Address addr, ParseAPI::Function *func, @@ -223,49 +312,18 @@ AbsRegion AbsRegionConverter::convert(Expression::Ptr exp, addr, fpHeight); - bool isStack = false; - bool isFrame = false; - - - static Expression::Ptr theStackPtr(new RegisterAST(MachRegister::getStackPointer(Arch_x86))); - static Expression::Ptr theStackPtr64(new RegisterAST(MachRegister::getStackPointer(Arch_x86_64))); - static Expression::Ptr theStackPtrPPC(new RegisterAST(MachRegister::getStackPointer(Arch_ppc32))); - - static Expression::Ptr theFramePtr(new RegisterAST(MachRegister::getFramePointer(Arch_x86))); - static Expression::Ptr theFramePtr64(new RegisterAST(MachRegister::getFramePointer(Arch_x86_64))); - - static Expression::Ptr thePC(new RegisterAST(MachRegister::getPC(Arch_x86))); - static Expression::Ptr thePC64(new RegisterAST(MachRegister::getPC(Arch_x86_64))); - static Expression::Ptr thePCPPC(new RegisterAST(MachRegister::getPC(Arch_ppc32))); - - // We currently have to try and bind _every_ _single_ _alias_ - // of the stack pointer... - if (stackDefined) { - if (exp->bind(theStackPtr.get(), Result(s32, spHeight)) || - exp->bind(theStackPtr64.get(), Result(s64, spHeight)) || - exp->bind(theStackPtrPPC.get(), Result(s32, spHeight))) { - isStack = true; - } - } - if (frameDefined) { - if (exp->bind(theFramePtr.get(), Result(s32, fpHeight)) || - exp->bind(theFramePtr64.get(), Result(s64, fpHeight))) { - isFrame = true; - } - } - - // Bind the IP, why not... - exp->bind(thePC.get(), Result(u32, addr)); - exp->bind(thePC64.get(), Result(u64, addr)); - exp->bind(thePCPPC.get(), Result(u32, addr)); - - Result res = exp->eval(); + // Currently, we only bind sp, fp, and pc. + // If we decide to also bind aliases of these registers, + // we need to change bindKnownRegs accordingly. + bindKnownRegs calc(spHeight, fpHeight, addr, stackDefined, frameDefined); + exp->apply(&calc); + bool isFrame = calc.is_frame; + bool isStack = calc.is_stack; + Address res = calc.getResult(); if (isFrame && stackAnalysisEnabled_) { - if (res.defined && frameDefined) { - return AbsRegion(Absloc(res.convert
(), - 0, - func)); + if (calc.isDefined() && frameDefined) { + return AbsRegion(Absloc(res, 0, func)); } else { return AbsRegion(Absloc::Stack); @@ -273,8 +331,8 @@ AbsRegion AbsRegionConverter::convert(Expression::Ptr exp, } if (isStack && stackAnalysisEnabled_) { - if (res.defined && stackDefined) { - return AbsRegion(Absloc(res.convert
(), + if (calc.isDefined() && stackDefined) { + return AbsRegion(Absloc(res, 0, func)); } @@ -288,8 +346,8 @@ AbsRegion AbsRegionConverter::convert(Expression::Ptr exp, } // Otherwise we're on the heap - if (res.defined) { - return AbsRegion(Absloc(res.convert
())); + if (calc.isDefined()) { + return AbsRegion(Absloc(res)); } else { return AbsRegion(Absloc::Heap); @@ -419,7 +477,7 @@ bool AbsRegionConverter::definedCache(Address addr, // Instruction. /////////////////////////////////////////////////////// -void AssignmentConverter::convert(const Instruction::Ptr I, +void AssignmentConverter::convert(const Instruction I, const Address &addr, ParseAPI::Function *func, ParseAPI::Block *block, @@ -436,13 +494,13 @@ void AssignmentConverter::convert(const Instruction::Ptr I, // 2) Generic handling for things like flags and the PC. // Non-PC handling section - switch(I->getOperation().getID()) { + switch(I.getOperation().getID()) { case e_push: { // SP = SP - 4 // *SP = std::vector operands; - I->getOperands(operands); + I.getOperands(operands); // According to the InstructionAPI, the first operand will be the argument, the second will be ESP. assert(operands.size() == 2); @@ -516,7 +574,7 @@ void AssignmentConverter::convert(const Instruction::Ptr I, // As with push, eSP shows up as operand 1. std::vector operands; - I->getOperands(operands); + I.getOperands(operands); // According to the InstructionAPI, the first operand will be the explicit register, the second will be ESP. assert(operands.size() == 2); @@ -610,7 +668,7 @@ void AssignmentConverter::convert(const Instruction::Ptr I, // xchg defines two abslocs, and uses them as appropriate... std::vector operands; - I->getOperands(operands); + I.getOperands(operands); // According to the InstructionAPI, the first operand will be the argument, the second will be ESP. assert(operands.size() == 2); @@ -649,7 +707,7 @@ void AssignmentConverter::convert(const Instruction::Ptr I, case power_op_stwu: { std::vector operands; - I->getOperands(operands); + I.getOperands(operands); // stwu , , // = R1 @@ -661,7 +719,7 @@ void AssignmentConverter::convert(const Instruction::Ptr I, // deref(b) <= c std::set writes; - I->getMemoryWriteOperands(writes); + I.getMemoryWriteOperands(writes); assert(writes.size() == 1); Expression::Ptr tmp = *(writes.begin()); @@ -740,7 +798,7 @@ void AssignmentConverter::convert(const Instruction::Ptr I, } -void AssignmentConverter::handlePushEquivalent(const Instruction::Ptr I, +void AssignmentConverter::handlePushEquivalent(const Instruction I, Address addr, ParseAPI::Function *func, ParseAPI::Block *block, @@ -767,7 +825,7 @@ void AssignmentConverter::handlePushEquivalent(const Instruction::Ptr I, assignments.push_back(spB); } -void AssignmentConverter::handlePopEquivalent(const Instruction::Ptr I, +void AssignmentConverter::handlePopEquivalent(const Instruction I, Address addr, ParseAPI::Function *func, ParseAPI::Block *block, diff --git a/dataflowAPI/src/RegisterMap.C b/dataflowAPI/src/RegisterMap.C index f6708f9292..90a192056b 100644 --- a/dataflowAPI/src/RegisterMap.C +++ b/dataflowAPI/src/RegisterMap.C @@ -48,9 +48,10 @@ namespace DataflowAPI { // Also on gcc 4.3. RegisterMap &machRegIndex_x86() { - static RegisterMap mrmap; - if (mrmap.empty()) { - mrmap = { + static dyn_tls RegisterMap* mrmap = NULL; + if (mrmap == NULL) { + mrmap = new RegisterMap(); + *mrmap = { {x86::eax, 0}, {x86::ecx, 1}, {x86::edx, 2}, @@ -216,13 +217,14 @@ RegisterMap &machRegIndex_x86() { {x86::tr6, 162}, {x86::tr7, 163} }; } - return mrmap; + return *mrmap; } RegisterMap &machRegIndex_x86_64() { - static RegisterMap mrmap; - if (mrmap.empty()) { - mrmap = { + static dyn_tls RegisterMap* mrmap = NULL; + if (mrmap == NULL) { + mrmap = new RegisterMap(); + *mrmap = { {x86_64::rax, 0}, {x86_64::rcx, 1}, {x86_64::rdx, 2}, @@ -391,13 +393,14 @@ RegisterMap &machRegIndex_x86_64() { {x86_64::tr7, 165}, }; } - return mrmap; + return *mrmap; } RegisterMap &machRegIndex_ppc() { - static RegisterMap mrmap; - if (mrmap.empty()) { - mrmap = { + static dyn_tls RegisterMap* mrmap = NULL; + if (mrmap == NULL) { + mrmap = new RegisterMap(); + *mrmap = { {ppc32::r0, 0}, {ppc32::r1, 1}, {ppc32::r2, 2}, @@ -571,13 +574,14 @@ RegisterMap &machRegIndex_ppc() { {ppc32::sprg7_ro, 163} }; } - return mrmap; + return *mrmap; } RegisterMap &machRegIndex_ppc_64() { - static RegisterMap mrmap; - if (mrmap.empty()) { - mrmap = { + static dyn_tls RegisterMap* mrmap = NULL; + if (mrmap == NULL) { + mrmap = new RegisterMap(); + *mrmap = { {ppc64::r0, 0}, {ppc64::r1, 1}, {ppc64::r2, 2}, @@ -751,13 +755,14 @@ RegisterMap &machRegIndex_ppc_64() { {ppc64::sprg7_ro, 163} }; } - return mrmap; + return *mrmap; } RegisterMap &machRegIndex_aarch64() { - static RegisterMap mrmap; - if (mrmap.empty()) { - mrmap = { + static dyn_tls RegisterMap* mrmap = NULL; + if (mrmap == NULL) { + mrmap = new RegisterMap(); + *mrmap = { {aarch64::x0, 0}, {aarch64::x1, 1}, {aarch64::x2, 2}, @@ -859,15 +864,16 @@ RegisterMap &machRegIndex_aarch64() { {aarch64::pstate, 67}, {aarch64::xzr, 68}}; } - return mrmap; + return *mrmap; } #else // This fails on VS 2015... but not VS 2010... RegisterMap &machRegIndex_x86() { - static RegisterMap mrmap; - if (mrmap.empty()) { - mrmap = map_list_of + static dyn_tls RegisterMap* mrmap = NULL; + if (mrmap == NULL) { + mrmap = new RegisterMap(); + *mrmap = map_list_of (x86::eax, 0) (x86::ecx, 1) (x86::edx, 2) @@ -937,13 +943,14 @@ RegisterMap &machRegIndex_x86() { (x86::tr6, 66) (x86::tr7, 67); } - return mrmap; + return *mrmap; } RegisterMap &machRegIndex_x86_64() { - static RegisterMap mrmap; - if (mrmap.empty()) { - mrmap = map_list_of + static dyn_tls RegisterMap* mrmap = NULL; + if (mrmap == NULL) { + mrmap = new RegisterMap(); + *mrmap = map_list_of (x86_64::rax, 0) (x86_64::rcx, 1) (x86_64::rdx, 2) @@ -1112,13 +1119,14 @@ RegisterMap &machRegIndex_x86_64() { (x86_64::tr7, 164) ; } - return mrmap; + return *mrmap; } RegisterMap &machRegIndex_ppc() { - static RegisterMap mrmap; - if (mrmap.empty()) { - mrmap = map_list_of + static dyn_tls RegisterMap* mrmap = NULL; + if (mrmap == NULL) { + mrmap = new RegisterMap(); + *mrmap = map_list_of (ppc32::r0, 0) (ppc32::r1, 1) (ppc32::r2, 2) @@ -1291,13 +1299,14 @@ RegisterMap &machRegIndex_ppc() { (ppc32::sprg7, 163) (ppc32::sprg7_ro, 163); } - return mrmap; + return *mrmap; } RegisterMap &machRegIndex_ppc_64() { - static RegisterMap mrmap; - if (mrmap.empty()) { - mrmap = map_list_of + static dyn_tls RegisterMap* mrmap = NULL; + if (mrmap == NULL) { + mrmap = new RegisterMap(); + *mrmap = map_list_of (ppc64::r0, 0) (ppc64::r1, 1) (ppc64::r2, 2) @@ -1470,13 +1479,14 @@ RegisterMap &machRegIndex_ppc_64() { (ppc64::sprg7, 163) (ppc64::sprg7_ro, 163); } - return mrmap; + return *mrmap; } RegisterMap &machRegIndex_aarch64() { - static RegisterMap mrmap; - if (mrmap.empty()) { - mrmap = map_list_of + static dyn_tls RegisterMap* mrmap = NULL; + if (mrmap == NULL) { + mrmap = new RegisterMap(); + *mrmap = map_list_of (aarch64::x0, 0) (aarch64::x1, 1) (aarch64::x2, 2) diff --git a/dataflowAPI/src/RoseInsnFactory.C b/dataflowAPI/src/RoseInsnFactory.C index a9ec71b7c0..42bc9ab247 100644 --- a/dataflowAPI/src/RoseInsnFactory.C +++ b/dataflowAPI/src/RoseInsnFactory.C @@ -51,12 +51,12 @@ using namespace Dyninst; using namespace InstructionAPI; using namespace DataflowAPI; -SgAsmInstruction *RoseInsnFactory::convert(const InstructionAPI::Instruction::Ptr &insn, uint64_t addr) { +SgAsmInstruction *RoseInsnFactory::convert(const Instruction &insn, uint64_t addr) { SgAsmInstruction *rinsn = createInsn(); rinsn->set_address(addr); - rinsn->set_mnemonic(insn->format()); - setOpcode(rinsn, insn->getOperation().getID(), insn->getOperation().getPrefixID(), insn->getOperation().format()); + rinsn->set_mnemonic(insn.format()); + setOpcode(rinsn, insn.getOperation().getID(), insn.getOperation().getPrefixID(), insn.getOperation().format()); // semantics don't support 64-bit code setSizes(rinsn); @@ -65,33 +65,33 @@ SgAsmInstruction *RoseInsnFactory::convert(const InstructionAPI::Instruction::Pt //rinsn->set_addressSize(x86_insnsize_32); std::vector rawBytes; - for (unsigned i = 0; i < insn->size(); ++i) rawBytes.push_back(insn->rawByte(i)); + for (unsigned i = 0; i < insn.size(); ++i) rawBytes.push_back(insn.rawByte(i)); rinsn->set_raw_bytes(rawBytes); // operand list SgAsmOperandList *roperands = new SgAsmOperandList; - //std::cerr << "Converting " << insn->format(addr) << " @" << std::hex << addr << std::dec << std::endl; + //std::cerr << "Converting " << insn.format(addr) << " @" << std::hex << addr << std::dec << std::endl; - //std::cerr << "checking instruction: " << insn->format(addr) << " for special handling" << std::endl; - if (handleSpecialCases(insn->getOperation().getID(), rinsn, roperands)) { + //std::cerr << "checking instruction: " << insn.format(addr) << " for special handling" << std::endl; + if (handleSpecialCases(insn.getOperation().getID(), rinsn, roperands)) { rinsn->set_operandList(roperands); return rinsn; } //std::cerr << "no special handling by opcode, checking if we should mangle operands..." << std::endl; std::vector operands; - insn->getOperands(operands); + insn.getOperands(operands); //std::cerr << "\t " << operands.size() << " operands" << std::endl; massageOperands(insn, operands); int i = 0; -// std::cerr << "converting insn " << insn->format(addr) << std::endl; +// std::cerr << "converting insn " << insn.format(addr) << std::endl; for (std::vector::iterator opi = operands.begin(); opi != operands.end(); ++opi, ++i) { InstructionAPI::Operand &currOperand = *opi; // std::cerr << "Converting operand " << currOperand.format(arch(), addr) << std::endl; - roperands->append_operand(convertOperand(currOperand.getValue(), addr, insn->size())); + roperands->append_operand(convertOperand(currOperand.getValue(), addr, insn.size())); } rinsn->set_operandList(roperands); return rinsn; @@ -135,9 +135,9 @@ bool RoseInsnX86Factory::handleSpecialCases(entryID, SgAsmInstruction *, SgAsmOp return false; } -void RoseInsnX86Factory::massageOperands(const InstructionAPI::Instruction::Ptr &insn, - std::vector &operands) { - switch (insn->getOperation().getID()) { +void RoseInsnX86Factory::massageOperands(const Instruction &insn, + std::vector &operands) { + switch (insn.getOperation().getID()) { case e_lea: { // ROSE expects there to be a "memory reference" statement wrapping the // address calculation. It then unwraps it. @@ -341,13 +341,13 @@ bool RoseInsnPPCFactory::handleSpecialCases(entryID iapi_opcode, } -void RoseInsnPPCFactory::massageOperands(const InstructionAPI::Instruction::Ptr &insn, - std::vector &operands) { +void RoseInsnPPCFactory::massageOperands(const Instruction &insn, + std::vector &operands) { /* - if(insn->writesMemory()) + if(insn.writesMemory()) std::swap(operands[0], operands[1]); */ - entryID opcode = insn->getOperation().getID(); + entryID opcode = insn.getOperation().getID(); // Anything that's writing RA, ROSE sometimes expects in RA, RS, RB/immediates form. // Any store, however, Dyninst expects in RS, RA, RB/displacement form. Very confusing, // but we handle it cleanly here. @@ -355,7 +355,7 @@ void RoseInsnPPCFactory::massageOperands(const InstructionAPI::Instruction::Ptr opcode != power_op_rldic && !operands[0].isWritten() && operands.size() >= 2 && operands[1].isWritten() && !operands[1].writesMemory()) { - //std::cerr << "swapping RS and RA in " << insn->format() << std::endl; + //std::cerr << "swapping RS and RA in " << insn.format() << std::endl; std::swap(operands[0], operands[1]); } if(opcode == power_op_cmp || @@ -366,8 +366,8 @@ void RoseInsnPPCFactory::massageOperands(const InstructionAPI::Instruction::Ptr std::swap(operands[2], operands[3]); std::swap(operands[1], operands[2]); } - if(insn->getOperation().format().find(".") != std::string::npos && - insn->getOperation().getID() != power_op_stwcx_rc) { + if(insn.getOperation().format().find(".") != std::string::npos && + insn.getOperation().getID() != power_op_stwcx_rc) { operands.pop_back(); } @@ -400,7 +400,7 @@ bool RoseInsnArmv8Factory::handleSpecialCases(entryID, SgAsmInstruction *, SgAsm return false; } -void RoseInsnArmv8Factory::massageOperands(const InstructionAPI::Instruction::Ptr &, - std::vector &) { +void RoseInsnArmv8Factory::massageOperands(const Instruction &, + std::vector &) { return; } diff --git a/dataflowAPI/src/RoseInsnFactory.h b/dataflowAPI/src/RoseInsnFactory.h index 62a04ec990..8bb6afcb75 100644 --- a/dataflowAPI/src/RoseInsnFactory.h +++ b/dataflowAPI/src/RoseInsnFactory.h @@ -37,6 +37,7 @@ #include "external/rose/powerpcInstructionEnum.h" #include "external/rose/armv8InstructionEnum.h" #include "Visitor.h" +#include "Instruction.h" #include "common/h/util.h" #include "boost/shared_ptr.hpp" #include @@ -90,7 +91,7 @@ namespace Dyninst { DATAFLOW_EXPORT virtual ~RoseInsnFactory(void) { }; - DATAFLOW_EXPORT virtual SgAsmInstruction *convert(const InstructionPtr &insn, uint64_t addr); + DATAFLOW_EXPORT virtual SgAsmInstruction *convert(const InstructionAPI::Instruction &insn, uint64_t addr); protected: virtual SgAsmInstruction *createInsn() = 0; @@ -101,7 +102,7 @@ namespace Dyninst { virtual bool handleSpecialCases(entryID opcode, SgAsmInstruction *rinsn, SgAsmOperandList *roperands) = 0; - virtual void massageOperands(const InstructionPtr &insn, + virtual void massageOperands(const InstructionAPI::Instruction &insn, std::vector &operands) = 0; virtual SgAsmExpression *convertOperand(const ExpressionPtr expression, int64_t addr, size_t insnSize); @@ -128,7 +129,8 @@ namespace Dyninst { virtual bool handleSpecialCases(entryID opcode, SgAsmInstruction *rinsn, SgAsmOperandList *roperands); - virtual void massageOperands(const InstructionPtr &insn, std::vector &operands); + virtual void massageOperands(const InstructionAPI::Instruction &insn, + std::vector &operands); X86InstructionKind convertKind(entryID opcode, prefixEntryID prefix); @@ -150,7 +152,8 @@ namespace Dyninst { virtual bool handleSpecialCases(entryID opcode, SgAsmInstruction *rinsn, SgAsmOperandList *roperands); - virtual void massageOperands(const InstructionPtr &insn, std::vector &operands); + virtual void massageOperands(const InstructionAPI::Instruction &insn, + std::vector &operands); PowerpcInstructionKind convertKind(entryID opcode, std::string mnem); @@ -175,7 +178,8 @@ namespace Dyninst { virtual bool handleSpecialCases(entryID opcode, SgAsmInstruction *rinsn, SgAsmOperandList *roperands); - virtual void massageOperands(const InstructionPtr &insn, std::vector &operands); + virtual void massageOperands(const InstructionAPI::Instruction &insn, + std::vector &operands); virtual void setSizes(SgAsmInstruction *insn); diff --git a/dataflowAPI/src/SymEval.C b/dataflowAPI/src/SymEval.C index 3c3c154ada..cfd06f1bb3 100644 --- a/dataflowAPI/src/SymEval.C +++ b/dataflowAPI/src/SymEval.C @@ -70,13 +70,13 @@ std::pair SymEval::expand(const Assignment::Ptr &assignment, boo Result_t res; // Fill it in to mark it as existing res[assignment] = AST::Ptr(); - std::set ignored; + std::set ignored; bool succ = expand(res, ignored, applyVisitors); return std::make_pair(res[assignment], succ); } bool SymEval::expand(Result_t &res, - std::set &failedInsns, + std::set &failedInsns, bool applyVisitors) { // Symbolic evaluation works off an Instruction // so we have something to hand to ROSE. @@ -424,36 +424,36 @@ SymEval::Retval_t SymEval::expand(Dyninst::Graph::Ptr slice, DataflowAPI::Result else return SUCCESS; } -bool SymEval::expandInsn(const InstructionAPI::Instruction::Ptr insn, +bool SymEval::expandInsn(const Instruction &insn, const uint64_t addr, Result_t &res) { SgAsmInstruction *roseInsn; - switch (insn->getArch()) { + switch (insn.getArch()) { case Arch_x86: { - SymEvalPolicy policy(res, addr, insn->getArch(), insn); + SymEvalPolicy policy(res, addr, insn.getArch(), insn); RoseInsnX86Factory fac(Arch_x86); roseInsn = fac.convert(insn, addr); SymbolicExpansion exp; exp.expandX86(roseInsn, policy); if (policy.failedTranslate()) { - cerr << "Warning: failed semantic translation of instruction " << insn->format() << endl; + cerr << "Warning: failed semantic translation of instruction " << insn.format() << endl; return false; } break; } case Arch_x86_64: { - SymEvalPolicy_64 policy(res, addr, insn->getArch(), insn); + SymEvalPolicy_64 policy(res, addr, insn.getArch(), insn); RoseInsnX86Factory fac(Arch_x86_64); roseInsn = fac.convert(insn, addr); SymbolicExpansion exp; exp.expandX86_64(roseInsn, policy); if (policy.failedTranslate()) { - cerr << "Warning: failed semantic translation of instruction " << insn->format() << endl; + cerr << "Warning: failed semantic translation of instruction " << insn.format() << endl; return false; } @@ -470,10 +470,10 @@ bool SymEval::expandInsn(const InstructionAPI::Instruction::Ptr insn, BaseSemantics::SValuePtr protoval = SymEvalSemantics::SValue::instance(1, 0); BaseSemantics::RegisterStatePtr registerState = SymEvalSemantics::RegisterStateASTPPC32::instance(protoval, reg_dict); BaseSemantics::MemoryStatePtr memoryState = SymEvalSemantics::MemoryStateAST::instance(protoval, protoval); - BaseSemantics::StatePtr state = SymEvalSemantics::StateAST::instance(res, addr, insn->getArch(), insn, registerState, memoryState); + BaseSemantics::StatePtr state = SymEvalSemantics::StateAST::instance(res, addr, insn.getArch(), insn, registerState, memoryState); BaseSemantics::RiscOperatorsPtr ops = SymEvalSemantics::RiscOperatorsAST::instance(state); - exp.expandPPC32(roseInsn, ops, insn->format()); + exp.expandPPC32(roseInsn, ops, insn.format()); break; } @@ -487,10 +487,10 @@ bool SymEval::expandInsn(const InstructionAPI::Instruction::Ptr insn, BaseSemantics::SValuePtr protoval = SymEvalSemantics::SValue::instance(1, 0); BaseSemantics::RegisterStatePtr registerState = SymEvalSemantics::RegisterStateASTPPC64::instance(protoval, reg_dict); BaseSemantics::MemoryStatePtr memoryState = SymEvalSemantics::MemoryStateAST::instance(protoval, protoval); - BaseSemantics::StatePtr state = SymEvalSemantics::StateAST::instance(res, addr, insn->getArch(), insn, registerState, memoryState); + BaseSemantics::StatePtr state = SymEvalSemantics::StateAST::instance(res, addr, insn.getArch(), insn, registerState, memoryState); BaseSemantics::RiscOperatorsPtr ops = SymEvalSemantics::RiscOperatorsAST::instance(state); - exp.expandPPC64(roseInsn, ops, insn->format()); + exp.expandPPC64(roseInsn, ops, insn.format()); break; @@ -505,10 +505,10 @@ bool SymEval::expandInsn(const InstructionAPI::Instruction::Ptr insn, BaseSemantics::SValuePtr protoval = SymEvalSemantics::SValue::instance(1, 0); BaseSemantics::RegisterStatePtr registerState = SymEvalSemantics::RegisterStateASTARM64::instance(protoval, reg_dict); BaseSemantics::MemoryStatePtr memoryState = SymEvalSemantics::MemoryStateAST::instance(protoval, protoval); - BaseSemantics::StatePtr state = SymEvalSemantics::StateAST::instance(res, addr, insn->getArch(), insn, registerState, memoryState); + BaseSemantics::StatePtr state = SymEvalSemantics::StateAST::instance(res, addr, insn.getArch(), insn, registerState, memoryState); BaseSemantics::RiscOperatorsPtr ops = SymEvalSemantics::RiscOperatorsAST::instance(state); - exp.expandAarch64(roseInsn, ops, insn->format()); + exp.expandAarch64(roseInsn, ops, insn.format()); } break; default: diff --git a/dataflowAPI/src/SymEvalPolicy.C b/dataflowAPI/src/SymEvalPolicy.C index 674e4d4be7..8230d591be 100644 --- a/dataflowAPI/src/SymEvalPolicy.C +++ b/dataflowAPI/src/SymEvalPolicy.C @@ -36,9 +36,9 @@ using namespace Dyninst::DataflowAPI; using namespace Dyninst::InstructionAPI; SymEvalPolicy::SymEvalPolicy(Result_t &r, - Address a, - Dyninst::Architecture ac, - Instruction::Ptr insn) : + Address a, + Dyninst::Architecture ac, + Instruction insn) : res(r), arch(ac), addr(a), @@ -248,7 +248,7 @@ Absloc SymEvalPolicy::convert(X86Flag f) SymEvalPolicy_64::SymEvalPolicy_64(Result_t &r, Address a, Dyninst::Architecture ac, - Instruction::Ptr insn) : + Instruction insn) : res(r), arch(ac), addr(a), diff --git a/dataflowAPI/src/SymEvalPolicy.h b/dataflowAPI/src/SymEvalPolicy.h index 6e4f99e984..06836aa007 100644 --- a/dataflowAPI/src/SymEvalPolicy.h +++ b/dataflowAPI/src/SymEvalPolicy.h @@ -53,7 +53,7 @@ #define Sym_Eval_Policy_h #include "DynAST.h" -#include "Operation.h" +#include "Operation_impl.h" #include "../h/Absloc.h" #include @@ -131,7 +131,7 @@ struct Handle { SymEvalPolicy(Result_t &r, Address addr, Dyninst::Architecture a, - Dyninst::InstructionAPI::Instruction::Ptr insn); + InstructionAPI::Instruction insn); ~SymEvalPolicy() {}; @@ -590,7 +590,7 @@ struct Handle { bool failedTranslate_; // The Dyninst version of the instruction we're translating - Dyninst::InstructionAPI::Instruction::Ptr insn_; + Dyninst::InstructionAPI::Instruction insn_; // The above is an Assignment::Ptr -> AST::Ptr map @@ -651,7 +651,7 @@ struct Handle { SymEvalPolicy_64(Result_t &r, Address addr, Dyninst::Architecture a, - Dyninst::InstructionAPI::Instruction::Ptr insn); + Dyninst::InstructionAPI::Instruction insn); ~SymEvalPolicy_64() {}; @@ -1110,7 +1110,7 @@ struct Handle { bool failedTranslate_; // The Dyninst version of the instruction we're translating - Dyninst::InstructionAPI::Instruction::Ptr insn_; + Dyninst::InstructionAPI::Instruction insn_; // The above is an Assignment::Ptr -> AST::Ptr map diff --git a/dataflowAPI/src/debug_dataflow.C b/dataflowAPI/src/debug_dataflow.C index 5a6077f4f5..31e87809cf 100644 --- a/dataflowAPI/src/debug_dataflow.C +++ b/dataflowAPI/src/debug_dataflow.C @@ -34,69 +34,110 @@ #include #include #include +#include #include "debug_dataflow.h" #include #include +#include + // Internal debugging -int df_debug_slicing= 0; -int df_debug_stackanalysis = 0; -int df_debug_convert = 0; -int df_debug_expand = 0; -int df_debug_liveness = 0; +static int df_debug_slicing= 0; +static int df_debug_stackanalysis = 0; +static int df_debug_convert = 0; +static int df_debug_expand = 0; +static int df_debug_liveness = 0; -bool df_init_debug() { +void set_debug_flag(int &flag) +{ + flag = 1; + + // avoid the appearance of a race between setting the flag once here + // when invoked by call_once and subsequent reads by check_debug_flag. + race_detector_forget_access_history(&flag, sizeof(flag)); +} - static bool init = false; - if (init) return true; - init = true; +static int check_debug_flag(int &flag) +{ + // use a fake lock to suppress reports about races associated with + // concurrent setting and checking of the initialized flag by + // code generated for the implementation of call_once. + race_detector_fake_lock_acquire(race_detector_fake_lock(df_debug_slicing)); + static std::once_flag initialized; #if defined(_MSC_VER) #pragma warning(push) #pragma warning(disable:4996) #endif + std::call_once(initialized, []() { + if ((getenv("DATAFLOW_DEBUG_STACKANALYSIS"))) { fprintf(stderr, "Enabling DataflowAPI stack analysis debugging\n"); - df_debug_stackanalysis = 1; + set_debug_flag(df_debug_stackanalysis); } if ((getenv("DATAFLOW_DEBUG_SLICING"))) { fprintf(stderr, "Enabling DataflowAPI slicing debugging\n"); - df_debug_slicing = 1; + set_debug_flag(df_debug_slicing); } if ((getenv("DATAFLOW_DEBUG_CONVERT"))) { fprintf(stderr, "Enabling DataflowAPI->ROSE conversion debugging\n"); - df_debug_convert = 1; + set_debug_flag(df_debug_convert); } if ((getenv("DATAFLOW_DEBUG_EXPAND"))) { fprintf(stderr, "Enabling DataflowAPI symbolic expansion debugging\n"); - df_debug_expand = 1; + set_debug_flag(df_debug_expand); } if ((getenv("DATAFLOW_DEBUG_LIVENESS"))) { fprintf(stderr, "Enabling DataflowAPI liveness debugging\n"); - df_debug_liveness = 1; + set_debug_flag(df_debug_liveness); } + }); + + race_detector_fake_lock_release(race_detector_fake_lock(df_debug_slicing)); + #if defined(_MSC_VER) #pragma warning(pop) #endif - return true; + return flag; +} + +int df_debug_slicing_on() +{ + return check_debug_flag(df_debug_slicing); +} + +int df_debug_stackanalysis_on() +{ + return check_debug_flag(df_debug_stackanalysis); +} + +int df_debug_convert_on() +{ + return check_debug_flag(df_debug_convert); } -bool slicing_debug_on() { - return df_debug_slicing != 0; +int df_debug_expand_on() +{ + return check_debug_flag(df_debug_expand); +} + +int df_debug_liveness_on() +{ + return check_debug_flag(df_debug_liveness); } int stackanalysis_printf_int(const char *format, ...) { - if (!df_debug_stackanalysis) return 0; + if (!df_debug_stackanalysis_on()) return 0; if (NULL == format) return -1; va_list va; @@ -109,7 +150,7 @@ int stackanalysis_printf_int(const char *format, ...) int slicing_printf_int(const char *format, ...) { - if (!df_debug_slicing) return 0; + if (!df_debug_slicing_on()) return 0; if (NULL == format) return -1; va_list va; @@ -122,7 +163,7 @@ int slicing_printf_int(const char *format, ...) int convert_printf_int(const char *format, ...) { - if (!df_debug_convert) return 0; + if (!df_debug_convert_on()) return 0; if (NULL == format) return -1; va_list va; @@ -135,7 +176,7 @@ int convert_printf_int(const char *format, ...) int expand_printf_int(const char *format, ...) { - if (!df_debug_expand) return 0; + if (!df_debug_expand_on()) return 0; if (NULL == format) return -1; va_list va; @@ -148,7 +189,7 @@ int expand_printf_int(const char *format, ...) int liveness_printf_int(const char *format, ...) { - if (!df_debug_liveness) return 0; + if (!df_debug_liveness_on()) return 0; if (NULL == format) return -1; va_list va; diff --git a/dataflowAPI/src/debug_dataflow.h b/dataflowAPI/src/debug_dataflow.h index 4bc3c07a71..0d993e2703 100644 --- a/dataflowAPI/src/debug_dataflow.h +++ b/dataflowAPI/src/debug_dataflow.h @@ -33,17 +33,17 @@ #include -extern int df_debug_slicing; -extern int df_debug_stackanalysis; -extern int df_debug_convert; -extern int df_debug_expand; -extern int df_debug_liveness; +extern int df_debug_slicing_on(); +extern int df_debug_stackanalysis_on(); +extern int df_debug_convert_on(); +extern int df_debug_expand_on(); +extern int df_debug_liveness_on(); -#define slicing_cerr if (df_debug_slicing) cerr -#define stackanalysis_cerr if (df_debug_stackanalysis) cerr -#define convert_cerr if (df_debug_convert) cerr -#define expand_cerr if (df_debug_expand) cerr -#define liveness_cerr if (df_debug_liveness) cerr +#define slicing_cerr if (df_debug_slicing_on()) cerr +#define stackanalysis_cerr if (df_debug_stackanalysis_on()) cerr +#define convert_cerr if (df_debug_convert_on()) cerr +#define expand_cerr if (df_debug_expand_on()) cerr +#define liveness_cerr if (df_debug_liveness_on()) cerr extern int slicing_printf_int(const char *format, ...); extern int stackanalysis_printf_int(const char *format, ...); @@ -52,11 +52,11 @@ extern int expand_printf_int(const char *format, ...); extern int liveness_printf_int(const char *format, ...); #if defined(__GNUC__) -#define slicing_printf(format, args...) do {if (df_debug_slicing) slicing_printf_int(format, ## args); } while(0) -#define stackanalysis_printf(format, args...) do {if (df_debug_stackanalysis) stackanalysis_printf_int(format, ## args); } while(0) -#define convert_printf(format, args...) do {if (df_debug_convert) convert_printf_int(format, ## args); } while(0) -#define expand_printf(format, args...) do {if (df_debug_expand) expand_printf_int(format, ## args); } while(0) -#define liveness_printf(format, args...) do {if (df_debug_liveness) liveness_printf_int(format, ## args); } while(0) +#define slicing_printf(format, args...) do {if (df_debug_slicing_on()) slicing_printf_int(format, ## args); } while(0) +#define stackanalysis_printf(format, args...) do {if (df_debug_stackanalysis_on()) stackanalysis_printf_int(format, ## args); } while(0) +#define convert_printf(format, args...) do {if (df_debug_convert_on()) convert_printf_int(format, ## args); } while(0) +#define expand_printf(format, args...) do {if (df_debug_expand_on()) expand_printf_int(format, ## args); } while(0) +#define liveness_printf(format, args...) do {if (df_debug_liveness_on()) liveness_printf_int(format, ## args); } while(0) #else // Non-GCC doesn't have the ## macro diff --git a/dataflowAPI/src/liveness.C b/dataflowAPI/src/liveness.C index 86481779ac..cf9ef3d08e 100644 --- a/dataflowAPI/src/liveness.C +++ b/dataflowAPI/src/liveness.C @@ -102,6 +102,7 @@ const bitArray& LivenessAnalyzer::getLivenessOut(Block *block, bitArray &allRegs // OUT(X) = UNION(IN(Y)) for all successors Y of X + boost::lock_guard g(*block); const Block::edgelist & target_edges = block -> targets(); liveness_cerr << "getLivenessOut for block [" << hex << block->start() << "," << block->end() << "]" << dec << endl; @@ -139,11 +140,11 @@ void LivenessAnalyzer::summarizeBlockLivenessInfo(Function* func, Block *block, reinterpret_cast(getPtrToInstruction(block, block->start())), block->size(), block->obj()->cs()->getArch()); - Instruction::Ptr curInsn = decoder.decode(); - while(curInsn) { + Instruction curInsn = decoder.decode(); + while(curInsn.isValid()) { ReadWriteInfo curInsnRW; liveness_printf("%s[%d] After instruction %s at address 0x%lx:\n", - FILE__, __LINE__, curInsn->format().c_str(), current); + FILE__, __LINE__, curInsn.format().c_str(), current); if(!cachedLivenessInfo.getLivenessInfo(current, func, curInsnRW)) { curInsnRW = calcRWSets(curInsn, block, current); @@ -164,7 +165,7 @@ void LivenessAnalyzer::summarizeBlockLivenessInfo(Function* func, Block *block, liveness_cerr << "Used " << data.use << endl; liveness_cerr << "Defined " << data.def << endl; - current += curInsn->size(); + current += curInsn.size(); curInsn = decoder.decode(); } @@ -260,8 +261,6 @@ void LivenessAnalyzer::analyze(Function *func) { // asked for it, we take its existence to indicate that they'll // also be instrumenting. bool LivenessAnalyzer::query(Location loc, Type type, bitArray &bitarray) { - - df_init_debug(); //TODO: consider the trustness of the location if (!loc.isValid()){ @@ -371,7 +370,7 @@ bool LivenessAnalyzer::query(Location loc, Type type, bitArray &bitarray) { ReadWriteInfo rw; if(!cachedLivenessInfo.getLivenessInfo(curInsnAddr, loc.func, rw)) { - Instruction::Ptr tmp = decoder.decode(insnBuffer); + Instruction tmp = decoder.decode(insnBuffer); rw = calcRWSets(tmp, loc.block, curInsnAddr); cachedLivenessInfo.insertInstructionInfo(curInsnAddr, rw, loc.func); } @@ -426,17 +425,17 @@ bool LivenessAnalyzer::query(Location loc, Type type, const MachRegister& machRe } -ReadWriteInfo LivenessAnalyzer::calcRWSets(Instruction::Ptr curInsn, Block* blk, Address a) +ReadWriteInfo LivenessAnalyzer::calcRWSets(Instruction curInsn, Block *blk, Address a) { - liveness_cerr << "calcRWSets for " << curInsn->format() << " @ " << hex << a << dec << endl; + liveness_cerr << "calcRWSets for " << curInsn.format() << " @ " << hex << a << dec << endl; ReadWriteInfo ret; ret.read = abi->getBitArray(); ret.written = abi->getBitArray(); - ret.insnSize = curInsn->size(); + ret.insnSize = curInsn.size(); std::set cur_read, cur_written; - curInsn->getReadSet(cur_read); - curInsn->getWriteSet(cur_written); + curInsn.getReadSet(cur_read); + curInsn.getWriteSet(cur_written); liveness_printf("Read registers: \n"); for (std::set::const_iterator i = cur_read.begin(); @@ -520,7 +519,7 @@ ReadWriteInfo LivenessAnalyzer::calcRWSets(Instruction::Ptr curInsn, Block* blk, } } } - InsnCategory category = curInsn->getCategory(); + InsnCategory category = curInsn.getCategory(); switch(category) { case c_CallInsn: @@ -537,7 +536,7 @@ ReadWriteInfo LivenessAnalyzer::calcRWSets(Instruction::Ptr curInsn, Block* blk, // Nothing written implicitly by a return break; case c_BranchInsn: - if(!curInsn->allowsFallThrough() && isExitBlock(blk)) + if(!curInsn.allowsFallThrough() && isExitBlock(blk)) { //Tail call, union of call and return ret.read |= ((abi->getCallReadRegisters()) | @@ -551,21 +550,21 @@ ReadWriteInfo LivenessAnalyzer::calcRWSets(Instruction::Ptr curInsn, Block* blk, bool isSyscall = false; - if ((curInsn->getOperation().getID() == e_int) || - (curInsn->getOperation().getID() == e_int3)) { + if ((curInsn.getOperation().getID() == e_int) || + (curInsn.getOperation().getID() == e_int3)) { isInterrupt = true; } static RegisterAST::Ptr gs(new RegisterAST(x86::gs)); - if (((curInsn->getOperation().getID() == e_call) && + if (((curInsn.getOperation().getID() == e_call) && /*(curInsn()->getOperation().isRead(gs))) ||*/ - (curInsn->getOperand(0).format(curInsn->getFormatter(), curInsn->getArch()) == "16")) || - (curInsn->getOperation().getID() == e_syscall) || - (curInsn->getOperation().getID() == e_int) || - (curInsn->getOperation().getID() == power_op_sc)) { + (curInsn.getOperand(0).format(curInsn.getArch()) == "16")) || + (curInsn.getOperation().getID() == e_syscall) || + (curInsn.getOperation().getID() == e_int) || + (curInsn.getOperation().getID() == power_op_sc)) { isSyscall = true; } - if (curInsn->getOperation().getID() == power_op_svcs) { + if (curInsn.getOperation().getID() == power_op_svcs) { isSyscall = true; } if (isInterrupt || isSyscall) { @@ -581,11 +580,12 @@ ReadWriteInfo LivenessAnalyzer::calcRWSets(Instruction::Ptr curInsn, Block* blk, void *LivenessAnalyzer::getPtrToInstruction(Block *block, Address addr) const{ if (addr < block->start()) return NULL; - if (addr >= block->end()) return NULL; + if (addr > block->end()) return NULL; return block->region()->getPtrToInstruction(addr); } bool LivenessAnalyzer::isExitBlock(Block *block) { + boost::lock_guard g(*block); const Block::edgelist & trgs = block->targets(); bool interprocEdge = false; diff --git a/dataflowAPI/src/slicing.C b/dataflowAPI/src/slicing.C index 86e4136278..1a96e41198 100644 --- a/dataflowAPI/src/slicing.C +++ b/dataflowAPI/src/slicing.C @@ -378,7 +378,7 @@ bool Slicer::updateAndLink( vector killed; vector matches; vector newactive; - Instruction::Ptr insn; + Instruction insn; bool change = false; killed.resize(cand.active.size(),false); @@ -727,6 +727,16 @@ void Slicer::handlePredecessorEdge(ParseAPI::Edge* e, slicing_printf("\t\t Ignore catch edges ... "); break; default: + if (e->interproc()) { + slicing_printf("\t\t Handling tail call... "); + if(handleCallBackward(p,cand,newCands,e,err)) { + slicing_printf("succeess, err: %d\n",err); + } else { + slicing_printf("failed, err: %d\n",err); + } + return; + } + nf = cand; slicing_printf("\t\t Handling default edge type %d... ", e->type()); @@ -775,7 +785,7 @@ Slicer::getPredecessors( slicing_printf("\t\t\t\t Adding intra-block predecessor %lx\n", nf.loc.addr()); slicing_printf("\t\t\t\t Current regions are:\n"); - if(slicing_debug_on()) { + if(df_debug_slicing_on()) { SliceFrame::ActiveMap::const_iterator ait = cand.active.begin(); for( ; ait != cand.active.end(); ++ait) { slicing_printf("\t\t\t\t%s\n", @@ -798,26 +808,11 @@ Slicer::getPredecessors( bool err = false; SliceFrame nf; - // The curernt function may have an invalid cache status. - // We may have to first finalize this function before - // iteratingover the src edges of the current block. - // Otherwise, the iterator in the for_each loop can get - // invalidated during the loop. - // We force finalizing if necessary - cand.loc.func->num_blocks(); - SingleContextOrInterproc epred(cand.loc.func, true, true); - const Block::edgelist & sources = cand.loc.block->sources(); - std::for_each(boost::make_filter_iterator(epred, sources.begin(), sources.end()), - boost::make_filter_iterator(epred, sources.end(), sources.end()), - boost::bind(&Slicer::handlePredecessorEdge, - this, - _1, - boost::ref(p), - boost::ref(cand), - boost::ref(newCands), - boost::ref(err), - boost::ref(nf) - )); + Block::edgelist sources; + cand.loc.block->copy_sources(sources); + for (auto eit = sources.begin(); eit != sources.end(); eit++) { + handlePredecessorEdge(*eit, p, cand, newCands, err, nf); + } return !err; } @@ -1352,7 +1347,7 @@ static void getInsnInstances(ParseAPI::Block *block, InstructionDecoder d(ptr, block->size(), block->obj()->cs()->getArch()); while (off < block->end()) { insns.push_back(std::make_pair(d.decode(), off)); - off += insns.back().first->size(); + off += insns.back().first.size(); } } @@ -1373,7 +1368,6 @@ Slicer::Slicer(Assignment::Ptr a, b_(block), f_(func), converter(cache, stackAnalysis) { - df_init_debug(); }; Graph::Ptr Slicer::forwardSlice(Predicates &predicates) { @@ -1483,7 +1477,7 @@ bool Slicer::kills(AbsRegion const®, Assignment::Ptr &assign) { return false; } - if (assign->insn()->getOperation().getID() == e_call && reg.absloc().type() == Absloc::Register) { + if (assign->insn().getOperation().getID() == e_call && reg.absloc().type() == Absloc::Register) { MachRegister r = reg.absloc().reg(); ABI* abi = ABI::getABI(b_->obj()->cs()->getAddressWidth()); int index = abi->getIndex(r); @@ -1524,11 +1518,11 @@ std::string SliceNode::format() const { // Note that we CANNOT use a global cache based on the address // of the instruction to convert because the block that contains // the instructino may change during parsing. -void Slicer::convertInstruction(Instruction::Ptr insn, - Address addr, - ParseAPI::Function *func, +void Slicer::convertInstruction(Instruction insn, + Address addr, + ParseAPI::Function *func, ParseAPI::Block *block, - std::vector &ret) { + std::vector &ret) { converter.convert(insn, addr, func, @@ -1786,7 +1780,7 @@ void Slicer::constructInitialFrame( Direction dir, SliceFrame & initFrame) { - Instruction::Ptr init_instruction; + Instruction init_instruction; initFrame.con.push_front(ContextElement(f_)); initFrame.loc = Location(f_,b_); diff --git a/dataflowAPI/src/stackanalysis.C b/dataflowAPI/src/stackanalysis.C index bb9253797e..23bbee17a9 100644 --- a/dataflowAPI/src/stackanalysis.C +++ b/dataflowAPI/src/stackanalysis.C @@ -100,8 +100,6 @@ if(!(X)) { \ bool StackAnalysis::analyze() { - df_init_debug(); - genInsnEffects(); stackanalysis_printf("\tPerforming fixpoint analysis\n"); @@ -111,7 +109,7 @@ bool StackAnalysis::analyze() { func->addAnnotation(intervals_, Stack_Anno_Intervals); - if (df_debug_stackanalysis) { + if (df_debug_stackanalysis_on()) { debug(); } @@ -171,7 +169,7 @@ bool StackAnalysis::genInsnEffects() { return true; } -typedef std::vector > InsnVec; +typedef std::vector > InsnVec; static void getInsnInstances(Block *block, InsnVec &insns) { Offset off = block->start(); const unsigned char *ptr = (const unsigned char *) @@ -180,7 +178,7 @@ static void getInsnInstances(Block *block, InsnVec &insns) { InstructionDecoder d(ptr, block->size(), block->obj()->cs()->getArch()); while (off < block->end()) { insns.push_back(std::make_pair(d.decode(), off)); - off += insns.back().first->size(); + off += insns.back().first.size(); } } @@ -238,7 +236,7 @@ void StackAnalysis::summarizeBlocks(bool verbose) { InsnVec instances; getInsnInstances(block, instances); for (unsigned j = 0; j < instances.size(); j++) { - const InstructionAPI::Instruction::Ptr insn = instances[j].first; + const InstructionAPI::Instruction& insn = instances[j].first; const Offset &off = instances[j].second; // Fills in insnEffects[off] @@ -264,6 +262,7 @@ void StackAnalysis::summarizeBlocks(bool verbose) { } // Add blocks reachable from this one to the work stack + boost::lock_guard g(*block); const Block::edgelist &targs = block->targets(); std::for_each( boost::make_filter_iterator(epred, targs.begin(), targs.end()), @@ -338,6 +337,7 @@ void StackAnalysis::fixpoint(bool verbose) { } // Step 4: push all children on the worklist. + boost::lock_guard g(*block); const Block::edgelist &outEdges = block->targets(); std::for_each( boost::make_filter_iterator(epred2, outEdges.begin(), outEdges.end()), @@ -365,6 +365,7 @@ void getRetAndTailCallBlocks(Function *func, std::set &retBlocks) { Block *currBlock = workstack.top(); workstack.pop(); + boost::lock_guard g(*currBlock); const Block::edgelist &targs = currBlock->targets(); for (auto iter = targs.begin(); iter != targs.end(); iter++) { Edge *currEdge = *iter; @@ -395,7 +396,6 @@ bool StackAnalysis::canGetFunctionSummary() { bool StackAnalysis::getFunctionSummary(TransferSet &summary) { - df_init_debug(); try { genInsnEffects(); @@ -492,6 +492,7 @@ void StackAnalysis::summaryFixpoint() { (*blockEffects)[block].accumulate(input, blockSummaryOutputs[block]); // Step 4: push all children on the worklist. + boost::lock_guard g(*block); const Block::edgelist &outEdges = block->targets(); std::for_each( boost::make_filter_iterator(epred2, outEdges.begin(), outEdges.end()), @@ -613,9 +614,9 @@ void StackAnalysis::summarize() { } void StackAnalysis::computeInsnEffects(ParseAPI::Block *block, - Instruction::Ptr insn, const Offset off, TransferFuncs &xferFuncs, - TransferSet &funcSummary) { - entryID what = insn->getOperation().getID(); + Instruction insn, const Offset off, TransferFuncs &xferFuncs, + TransferSet &funcSummary) { + entryID what = insn.getOperation().getID(); // Reminder: what we're interested in: // a) Use of the stack pointer to define another register @@ -750,14 +751,14 @@ StackAnalysis::Height StackAnalysis::getStackCleanAmount(Function *func) { Block *ret = *rets; cur = (unsigned char *) ret->region()->getPtrToInstruction( ret->lastInsnAddr()); - Instruction::Ptr insn = decoder.decode(cur); + Instruction insn = decoder.decode(cur); - entryID what = insn->getOperation().getID(); + entryID what = insn.getOperation().getID(); if (what != e_ret_near) continue; int val; std::vector ops; - insn->getOperands(ops); + insn.getOperands(ops); if (ops.size() == 1) { val = 0; } else { @@ -1040,9 +1041,9 @@ class StateEvalVisitor : public Visitor { public: // addr is the starting address of instruction insn. // insn is the instruction containing the expression to evaluate. - StateEvalVisitor(Address addr, Instruction::Ptr insn, + StateEvalVisitor(Address addr, Instruction insn, StackAnalysis::AbslocState *s) : defined(true), state(s) { - rip = addr + insn->size(); + rip = addr + insn.size(); } StateEvalVisitor() : defined(false), state(NULL), rip(0) {} @@ -1125,10 +1126,10 @@ private: }; -void StackAnalysis::handleXor(Instruction::Ptr insn, Block *block, - const Offset off, TransferFuncs &xferFuncs) { +void StackAnalysis::handleXor(Instruction insn, Block *block, + const Offset off, TransferFuncs &xferFuncs) { std::vector operands; - insn->getOperands(operands); + insn.getOperands(operands); STACKANALYSIS_ASSERT(operands.size() == 2); // Handle the case where a register is being zeroed out. @@ -1157,7 +1158,7 @@ void StackAnalysis::handleXor(Instruction::Ptr insn, Block *block, } - if (insn->writesMemory()) { + if (insn.writesMemory()) { // xor mem1, reg2/imm2 STACKANALYSIS_ASSERT(writtenSet.size() == 0); @@ -1213,7 +1214,7 @@ void StackAnalysis::handleXor(Instruction::Ptr insn, Block *block, MachRegister written = (*writtenSet.begin())->getID(); Absloc writtenLoc(written); - if (insn->readsMemory()) { + if (insn.readsMemory()) { // xor reg1, mem2 // Extract the expression inside the dereference std::vector &addrExpr = children1; @@ -1277,10 +1278,10 @@ void StackAnalysis::handleXor(Instruction::Ptr insn, Block *block, } -void StackAnalysis::handleDiv(Instruction::Ptr insn, - TransferFuncs &xferFuncs) { +void StackAnalysis::handleDiv(Instruction insn, + TransferFuncs &xferFuncs) { std::vector operands; - insn->getOperands(operands); + insn.getOperands(operands); STACKANALYSIS_ASSERT(operands.size() == 3); Expression::Ptr quotient = operands[1].getValue(); @@ -1302,8 +1303,8 @@ void StackAnalysis::handleDiv(Instruction::Ptr insn, } -void StackAnalysis::handleMul(Instruction::Ptr insn, - TransferFuncs &xferFuncs) { +void StackAnalysis::handleMul(Instruction insn, + TransferFuncs &xferFuncs) { // MULs have a few forms: // 1. mul reg1, reg2/mem2 // -- reg1 = reg1 * reg2/mem2 @@ -1312,7 +1313,7 @@ void StackAnalysis::handleMul(Instruction::Ptr insn, // 3. mul reg1, reg2, reg3/mem3 // -- reg1:reg2 = reg2 * reg3/mem3 std::vector operands; - insn->getOperands(operands); + insn.getOperands(operands); STACKANALYSIS_ASSERT(operands.size() == 2 || operands.size() == 3); Expression::Ptr target = operands[0].getValue(); @@ -1372,10 +1373,10 @@ void StackAnalysis::handleMul(Instruction::Ptr insn, } -void StackAnalysis::handlePushPop(Instruction::Ptr insn, Block *block, - const Offset off, int sign, TransferFuncs &xferFuncs) { +void StackAnalysis::handlePushPop(Instruction insn, Block *block, + const Offset off, int sign, TransferFuncs &xferFuncs) { long delta = 0; - Operand arg = insn->getOperand(0); + Operand arg = insn.getOperand(0); // Why was this here? bernat, 12JAN11 if (arg.getValue()->eval().defined) { delta = sign * word_size; @@ -1385,7 +1386,7 @@ void StackAnalysis::handlePushPop(Instruction::Ptr insn, Block *block, xferFuncs.push_back(TransferFunc::deltaFunc(Absloc(sp()), delta)); copyBaseSubReg(sp(), xferFuncs); - if (insn->getOperation().getID() == e_push && insn->writesMemory()) { + if (insn.getOperation().getID() == e_push && insn.writesMemory()) { // This is a push. Let's record the value pushed on the stack if // possible. if (intervals_ != NULL) { @@ -1397,7 +1398,7 @@ void StackAnalysis::handlePushPop(Instruction::Ptr insn, Block *block, long writtenSlotHeight = spHeight.height() - word_size; Absloc writtenLoc(writtenSlotHeight, 0, NULL); - Expression::Ptr readExpr = insn->getOperand(0).getValue(); + Expression::Ptr readExpr = insn.getOperand(0).getValue(); if (dynamic_cast(readExpr.get())) { // Get copied register MachRegister readReg = boost::dynamic_pointer_cast( @@ -1444,11 +1445,11 @@ void StackAnalysis::handlePushPop(Instruction::Ptr insn, Block *block, } } } - } else if (insn->getOperation().getID() == e_pop && !insn->writesMemory()) { + } else if (insn.getOperation().getID() == e_pop && !insn.writesMemory()) { // This is a pop. Let's record the value popped if possible. // Get target register - Expression::Ptr targExpr = insn->getOperand(0).getValue(); + Expression::Ptr targExpr = insn.getOperand(0).getValue(); STACKANALYSIS_ASSERT(dynamic_cast(targExpr.get())); MachRegister targReg = boost::dynamic_pointer_cast( targExpr)->getID(); @@ -1484,11 +1485,11 @@ void StackAnalysis::handlePushPop(Instruction::Ptr insn, Block *block, } } -void StackAnalysis::handleReturn(Instruction::Ptr insn, - TransferFuncs &xferFuncs) { +void StackAnalysis::handleReturn(Instruction insn, + TransferFuncs &xferFuncs) { long delta = 0; std::vector operands; - insn->getOperands(operands); + insn.getOperands(operands); if (operands.size() < 2) { delta = word_size; } else { @@ -1514,8 +1515,8 @@ void StackAnalysis::handleReturn(Instruction::Ptr insn, } -void StackAnalysis::handleAddSub(Instruction::Ptr insn, Block *block, - const Offset off, int sign, TransferFuncs &xferFuncs) { +void StackAnalysis::handleAddSub(Instruction insn, Block *block, + const Offset off, int sign, TransferFuncs &xferFuncs) { // Possible forms for add/sub: // 1. add reg1, reg2 // -- reg1 = reg1 + reg2 @@ -1544,7 +1545,7 @@ void StackAnalysis::handleAddSub(Instruction::Ptr insn, Block *block, // b. Otherwise, nothing happens. std::vector operands; - insn->getOperands(operands); + insn.getOperands(operands); STACKANALYSIS_ASSERT(operands.size() == 2); std::set readSet; @@ -1552,8 +1553,7 @@ void StackAnalysis::handleAddSub(Instruction::Ptr insn, Block *block, operands[1].getReadSet(readSet); operands[0].getWriteSet(writeSet); - ArchSpecificFormatter *insnFormatter = insn->getFormatter(); - if (insn->writesMemory()) { + if (insn.writesMemory()) { // Cases 3 and 5 STACKANALYSIS_ASSERT(writeSet.size() == 0); @@ -1625,7 +1625,7 @@ void StackAnalysis::handleAddSub(Instruction::Ptr insn, Block *block, return; } - if (insn->readsMemory()) { + if (insn.readsMemory()) { // Case 2 // Extract the expression inside the dereference std::vector addrExpr; @@ -1691,8 +1691,8 @@ void StackAnalysis::handleAddSub(Instruction::Ptr insn, Block *block, } } -void StackAnalysis::handleLEA(Instruction::Ptr insn, - TransferFuncs &xferFuncs) { +void StackAnalysis::handleLEA(Instruction insn, + TransferFuncs &xferFuncs) { // LEA has a few patterns: // op0: target register //------------------------------- @@ -1710,20 +1710,18 @@ void StackAnalysis::handleLEA(Instruction::Ptr insn, // std::set readSet; std::set writtenSet; - insn->getOperand(0).getWriteSet(writtenSet); - insn->getOperand(1).getReadSet(readSet); + insn.getOperand(0).getWriteSet(writtenSet); + insn.getOperand(1).getReadSet(readSet); STACKANALYSIS_ASSERT(writtenSet.size() == 1); STACKANALYSIS_ASSERT(readSet.size() == 0 || readSet.size() == 1 || readSet.size() == 2); MachRegister written = (*writtenSet.begin())->getID(); Absloc writeloc(written); - InstructionAPI::Operand srcOperand = insn->getOperand(1); + InstructionAPI::Operand srcOperand = insn.getOperand(1); InstructionAPI::Expression::Ptr srcExpr = srcOperand.getValue(); std::vector children; srcExpr->getChildren(children); - ArchSpecificFormatter *insnFormatter = insn->getFormatter(); - if (readSet.size() == 0) { // op1: imm STACKANALYSIS_ASSERT(typeid(*srcExpr) == typeid(Immediate)); @@ -1918,15 +1916,15 @@ void StackAnalysis::handlePushPopRegs(int sign, TransferFuncs &xferFuncs) { copyBaseSubReg(sp(), xferFuncs); } -void StackAnalysis::handlePowerAddSub(Instruction::Ptr insn, Block *block, - const Offset off, int sign, TransferFuncs &xferFuncs) { +void StackAnalysis::handlePowerAddSub(Instruction insn, Block *block, + const Offset off, int sign, TransferFuncs &xferFuncs) { // Add/subtract are op0 = op1 +/- op2; we'd better read the stack pointer as // well as writing it - if (!insn->isRead(theStackPtr) || !insn->isWritten(theStackPtr)) { + if (!insn.isRead(theStackPtr) || !insn.isWritten(theStackPtr)) { return handleDefault(insn, block, off, xferFuncs); } - Operand arg = insn->getOperand(2); + Operand arg = insn.getOperand(2); Result res = arg.getValue()->eval(); Absloc sploc(sp()); if (res.defined) { @@ -1939,14 +1937,14 @@ void StackAnalysis::handlePowerAddSub(Instruction::Ptr insn, Block *block, } } -void StackAnalysis::handlePowerStoreUpdate(Instruction::Ptr insn, Block *block, - const Offset off, TransferFuncs &xferFuncs) { - if (!insn->isWritten(theStackPtr)) { +void StackAnalysis::handlePowerStoreUpdate(Instruction insn, Block *block, + const Offset off, TransferFuncs &xferFuncs) { + if (!insn.isWritten(theStackPtr)) { return handleDefault(insn, block, off, xferFuncs); } std::set memWriteAddrs; - insn->getMemoryWriteOperands(memWriteAddrs); + insn.getMemoryWriteOperands(memWriteAddrs); Expression::Ptr stackWrite = *(memWriteAddrs.begin()); stackWrite->bind(theStackPtr.get(), Result(u32, 0)); Result res = stackWrite->eval(); @@ -1962,8 +1960,8 @@ void StackAnalysis::handlePowerStoreUpdate(Instruction::Ptr insn, Block *block, } -void StackAnalysis::handleMov(Instruction::Ptr insn, Block *block, - const Offset off, TransferFuncs &xferFuncs) { +void StackAnalysis::handleMov(Instruction insn, Block *block, + const Offset off, TransferFuncs &xferFuncs) { // Some cases: // 1. mov reg, reg // 2. mov imm, reg @@ -1991,7 +1989,7 @@ void StackAnalysis::handleMov(Instruction::Ptr insn, Block *block, // Extract operands std::vector operands; - insn->getOperands(operands); + insn.getOperands(operands); STACKANALYSIS_ASSERT(operands.size() == 2); // Extract written/read register sets @@ -2001,7 +1999,7 @@ void StackAnalysis::handleMov(Instruction::Ptr insn, Block *block, operands[1].getReadSet(readRegs); - if (insn->writesMemory()) { + if (insn.writesMemory()) { STACKANALYSIS_ASSERT(writtenRegs.size() == 0); // Extract the expression inside the dereference @@ -2068,7 +2066,7 @@ void StackAnalysis::handleMov(Instruction::Ptr insn, Block *block, return; } - if (insn->readsMemory()) { + if (insn.readsMemory()) { // Extract the expression inside the dereference std::vector addrExpr; operands[1].getValue()->getChildren(addrExpr); @@ -2134,14 +2132,14 @@ void StackAnalysis::handleMov(Instruction::Ptr insn, Block *block, } } -void StackAnalysis::handleZeroExtend(Instruction::Ptr insn, Block *block, - const Offset off, TransferFuncs &xferFuncs) { +void StackAnalysis::handleZeroExtend(Instruction insn, Block *block, + const Offset off, TransferFuncs &xferFuncs) { // In x86/x86_64, zero extends can't write to memory - STACKANALYSIS_ASSERT(!insn->writesMemory()); + STACKANALYSIS_ASSERT(!insn.writesMemory()); // Extract operands std::vector operands; - insn->getOperands(operands); + insn.getOperands(operands); STACKANALYSIS_ASSERT(operands.size() == 2); // Extract written/read register sets @@ -2155,7 +2153,7 @@ void StackAnalysis::handleZeroExtend(Instruction::Ptr insn, Block *block, Absloc writtenLoc(written); // Handle memory loads - if (insn->readsMemory()) { + if (insn.readsMemory()) { // Extract the expression inside the dereference std::vector addrExpr; operands[1].getValue()->getChildren(addrExpr); @@ -2197,18 +2195,18 @@ void StackAnalysis::handleZeroExtend(Instruction::Ptr insn, Block *block, copyBaseSubReg(written, xferFuncs); } -void StackAnalysis::handleSignExtend(Instruction::Ptr insn, Block *block, - const Offset off, TransferFuncs &xferFuncs) { +void StackAnalysis::handleSignExtend(Instruction insn, Block *block, + const Offset off, TransferFuncs &xferFuncs) { // This instruction sign extends the read register into the written // register. Copying insn't really correct here...sign extension is going // to change the value... // In x86/x86_64, sign extends can't write to memory - STACKANALYSIS_ASSERT(!insn->writesMemory()); + STACKANALYSIS_ASSERT(!insn.writesMemory()); // Extract operands std::vector operands; - insn->getOperands(operands); + insn.getOperands(operands); STACKANALYSIS_ASSERT(operands.size() == 2); // Extract written/read register sets @@ -2222,7 +2220,7 @@ void StackAnalysis::handleSignExtend(Instruction::Ptr insn, Block *block, Absloc writtenLoc(written); // Handle memory loads - if (insn->readsMemory()) { + if (insn.readsMemory()) { // Extract the expression inside the dereference std::vector addrExpr; operands[1].getValue()->getChildren(addrExpr); @@ -2265,15 +2263,15 @@ void StackAnalysis::handleSignExtend(Instruction::Ptr insn, Block *block, copyBaseSubReg(written, xferFuncs); } -void StackAnalysis::handleSpecialSignExtend(Instruction::Ptr insn, - TransferFuncs &xferFuncs) { +void StackAnalysis::handleSpecialSignExtend(Instruction insn, + TransferFuncs &xferFuncs) { // This instruction sign extends the read register into the written // register. Copying insn't really correct here...sign extension is going // to change the value... // Extract written/read register sets std::set writtenRegs; - insn->getWriteSet(writtenRegs); + insn.getWriteSet(writtenRegs); STACKANALYSIS_ASSERT(writtenRegs.size() == 1); MachRegister writtenReg = (*writtenRegs.begin())->getID(); MachRegister readReg; @@ -2291,9 +2289,9 @@ void StackAnalysis::handleSpecialSignExtend(Instruction::Ptr insn, copyBaseSubReg(writtenReg, xferFuncs); } -void StackAnalysis::handleSyscall(Instruction::Ptr insn, Block *block, - const Offset off, TransferFuncs &xferFuncs) { - Architecture arch = insn->getArch(); +void StackAnalysis::handleSyscall(Instruction insn, Block *block, + const Offset off, TransferFuncs &xferFuncs) { + Architecture arch = insn.getArch(); if (arch == Arch_x86) { // x86 returns an error code in EAX xferFuncs.push_back(TransferFunc::retopFunc(Absloc(x86::eax))); @@ -2312,13 +2310,13 @@ void StackAnalysis::handleSyscall(Instruction::Ptr insn, Block *block, // Handle instructions for which we have no special handling implemented. Be // conservative for safety. -void StackAnalysis::handleDefault(Instruction::Ptr insn, Block *block, - const Offset off, TransferFuncs &xferFuncs) { +void StackAnalysis::handleDefault(Instruction insn, Block *block, + const Offset off, TransferFuncs &xferFuncs) { // Form sets of read/written Abslocs std::set writtenRegs; std::set readRegs; - insn->getWriteSet(writtenRegs); - insn->getReadSet(readRegs); + insn.getWriteSet(writtenRegs); + insn.getReadSet(readRegs); std::set writtenLocs; std::set readLocs; for (auto iter = writtenRegs.begin(); iter != writtenRegs.end(); iter++) { @@ -2335,10 +2333,10 @@ void StackAnalysis::handleDefault(Instruction::Ptr insn, Block *block, readLocs.insert(Absloc(reg)); } } - if (insn->readsMemory()) { + if (insn.readsMemory()) { // Add any determinable read locations to readLocs std::set memExprs; - insn->getMemoryReadOperands(memExprs); + insn.getMemoryReadOperands(memExprs); for (auto iter = memExprs.begin(); iter != memExprs.end(); iter++) { const Expression::Ptr &memExpr = *iter; StateEvalVisitor visitor; @@ -2363,10 +2361,10 @@ void StackAnalysis::handleDefault(Instruction::Ptr insn, Block *block, } } } - if (insn->writesMemory()) { + if (insn.writesMemory()) { // Add any determinable written locations to writtenLocs std::set memExprs; - insn->getMemoryWriteOperands(memExprs); + insn.getMemoryWriteOperands(memExprs); for (auto iter = memExprs.begin(); iter != memExprs.end(); iter++) { const Expression::Ptr &memExpr = *iter; StateEvalVisitor visitor; @@ -2424,19 +2422,19 @@ void StackAnalysis::handleDefault(Instruction::Ptr insn, Block *block, } } -bool StackAnalysis::isCall(Instruction::Ptr insn) { - return insn->getCategory() == c_CallInsn; +bool StackAnalysis::isCall(Instruction insn) { + return insn.getCategory() == c_CallInsn; } -bool StackAnalysis::isJump(Instruction::Ptr insn) { - return insn->getCategory() == c_BranchInsn; +bool StackAnalysis::isJump(Instruction insn) { + return insn.getCategory() == c_BranchInsn; } -bool StackAnalysis::handleNormalCall(Instruction::Ptr insn, Block *block, - Offset off, TransferFuncs &xferFuncs, TransferSet &funcSummary) { +bool StackAnalysis::handleNormalCall(Instruction insn, Block *block, + Offset off, TransferFuncs &xferFuncs, TransferSet &funcSummary) { // Identify syscalls of the form: call *%gs:0x10 - Expression::Ptr callAddrExpr = insn->getOperand(0).getValue(); + Expression::Ptr callAddrExpr = insn.getOperand(0).getValue(); if (dynamic_cast(callAddrExpr.get())) { std::vector children; callAddrExpr->getChildren(children); @@ -2449,12 +2447,13 @@ bool StackAnalysis::handleNormalCall(Instruction::Ptr insn, Block *block, } } - if (!insn->getControlFlowTarget()) return false; + if (!insn.getControlFlowTarget()) return false; // Must be a thunk based on parsing. if (off != block->lastInsnAddr()) return false; Address calledAddr = 0; + boost::lock_guard g(*block); const Block::edgelist &outs = block->targets(); for (auto eit = outs.begin(); eit != outs.end(); eit++) { Edge *edge = *eit; @@ -2550,7 +2549,7 @@ bool StackAnalysis::handleNormalCall(Instruction::Ptr insn, Block *block, ++iter) { // We only care about GPRs right now unsigned int gpr; - Architecture arch = insn->getArch(); + Architecture arch = insn.getArch(); switch(arch) { case Arch_x86: gpr = x86::GPR; @@ -2622,9 +2621,10 @@ bool StackAnalysis::handleNormalCall(Instruction::Ptr insn, Block *block, } // Create transfer functions for tail calls -bool StackAnalysis::handleJump(Instruction::Ptr insn, Block *block, Offset off, - TransferFuncs &xferFuncs, TransferSet &funcSummary) { +bool StackAnalysis::handleJump(Instruction insn, Block *block, Offset off, + TransferFuncs &xferFuncs, TransferSet &funcSummary) { Address calledAddr = 0; + boost::lock_guard g(*block); const Block::edgelist &outs = block->targets(); for (auto eit = outs.begin(); eit != outs.end(); eit++) { Edge *edge = *eit; @@ -2728,7 +2728,7 @@ bool StackAnalysis::handleJump(Instruction::Ptr insn, Block *block, Offset off, ++iter) { // We only care about GPRs right now unsigned int gpr; - Architecture arch = insn->getArch(); + Architecture arch = insn.getArch(); switch(arch) { case Arch_x86: gpr = x86::GPR; @@ -2771,21 +2771,21 @@ bool StackAnalysis::handleJump(Instruction::Ptr insn, Block *block, Offset off, return true; } -bool StackAnalysis::handleThunkCall(Instruction::Ptr insn, Block *block, - const Offset off, TransferFuncs &xferFuncs) { +bool StackAnalysis::handleThunkCall(Instruction insn, Block *block, + const Offset off, TransferFuncs &xferFuncs) { // We know that we're not a normal call, so it depends on whether the CFT is // "next instruction" or not. - if (insn->getCategory() != c_CallInsn || !insn->getControlFlowTarget()) { + if (insn.getCategory() != c_CallInsn || !insn.getControlFlowTarget()) { return false; } // Eval of getCFT(0) == size? - Expression::Ptr cft = insn->getControlFlowTarget(); + Expression::Ptr cft = insn.getControlFlowTarget(); cft->bind(thePC.get(), Result(u32, 0)); Result res = cft->eval(); if (!res.defined) return false; - if (res.convert() == insn->size()) { + if (res.convert() == insn.size()) { Absloc sploc(sp()); xferFuncs.push_back(TransferFunc::deltaFunc(sploc, -1 * word_size)); copyBaseSubReg(sp(), xferFuncs); @@ -2795,12 +2795,12 @@ bool StackAnalysis::handleThunkCall(Instruction::Ptr insn, Block *block, // Check the next instruction to see which register is holding the PC. // Assumes next instruction is add thunk_reg, offset. - const Address pc = off + insn->size(); - Instruction::Ptr thunkAddInsn = block->getInsn(pc); - if (thunkAddInsn == Instruction::Ptr()) return true; - if (thunkAddInsn->getOperation().getID() != e_add) return true; + const Address pc = off + insn.size(); + Instruction thunkAddInsn = block->getInsn(pc); + if (!thunkAddInsn.isValid()) return true; + if (thunkAddInsn.getOperation().getID() != e_add) return true; std::set writtenRegs; - thunkAddInsn->getOperand(0).getWriteSet(writtenRegs); + thunkAddInsn.getOperand(0).getWriteSet(writtenRegs); if (writtenRegs.size() != 1) return true; const MachRegister &thunkTarget = (*writtenRegs.begin())->getID(); @@ -2878,6 +2878,8 @@ void StackAnalysis::meetInputs(Block *block, AbslocState &blockInput, intra_nosink_nocatch epred2; stackanalysis_printf("\t ... In edges: "); + boost::lock_guard g(*block); + const Block::edgelist & inEdges = block->sources(); std::for_each( boost::make_filter_iterator(epred2, inEdges.begin(), inEdges.end()), @@ -2895,6 +2897,7 @@ void StackAnalysis::meetSummaryInputs(Block *block, TransferSet &blockInput, TransferSet &input) { input.clear(); intra_nosink_nocatch epred2; + boost::lock_guard g(*block); const Block::edgelist & inEdges = block->sources(); std::for_each( diff --git a/dynC_API/CMakeLists.txt b/dynC_API/CMakeLists.txt index 75d965a15a..1a9039a16a 100644 --- a/dynC_API/CMakeLists.txt +++ b/dynC_API/CMakeLists.txt @@ -14,6 +14,7 @@ add_definitions(-DYY_NO_UNISTD_H) endif() dyninst_library(dynC_API dyninstAPI) +target_link_private_libraries(dynC_API ${Boost_LIBRARIES}) if (USE_COTIRE) cotire(dynC_API) endif() diff --git a/dyninstAPI/CMakeLists.txt b/dyninstAPI/CMakeLists.txt index 0a78bf67e1..95d50a233b 100644 --- a/dyninstAPI/CMakeLists.txt +++ b/dyninstAPI/CMakeLists.txt @@ -195,7 +195,7 @@ endif () dyninst_library(dyninstAPI common instructionAPI stackwalk pcontrol patchAPI parseAPI symtabAPI) -target_link_private_libraries(dyninstAPI ${Boost_LIBRARIES}) +target_link_private_libraries(dyninstAPI ${Boost_LIBRARIES} ${TBB_LIBRARIES}) if (UNIX) # Boost auto-links on Windows; don't double-link target_link_private_libraries (dyninstAPI pthread) diff --git a/dyninstAPI/h/BPatch_basicBlock.h b/dyninstAPI/h/BPatch_basicBlock.h index 0fdfc959e2..73fa35bde5 100644 --- a/dyninstAPI/h/BPatch_basicBlock.h +++ b/dyninstAPI/h/BPatch_basicBlock.h @@ -89,7 +89,7 @@ struct comparison { */ class BPatch_flowGraph; -struct BPATCH_DLL_EXPORT insnPredicate : public std::unary_function +struct BPATCH_DLL_EXPORT insnPredicate : public std::unary_function { virtual result_type operator()(argument_type arg) = 0; virtual ~insnPredicate() {} @@ -286,15 +286,15 @@ class BPATCH_DLL_EXPORT BPatch_basicBlock { BPatch_Vector * findPoint(const BPatch_Set& ops); BPatch_Vector * findPoint(const std::set& ops); - BPatch_Vector * findPoint(bool(*filter)(Dyninst::InstructionAPI::Instruction::Ptr)); + BPatch_Vector * findPoint(bool(*filter)(Dyninst::InstructionAPI::Instruction)); BPatch_point * findPoint(Dyninst::Address addr); /** BPatch_basicBlock::getInstructions */ /** return the instructions that belong to the block */ - bool getInstructions(std::vector& insns); - bool getInstructions(std::vector >& insnInstances); + bool getInstructions(std::vector& insns); + bool getInstructions(std::vector >& insnInstances); /** BPatch_basicBlock::getIncomingEdges */ diff --git a/dyninstAPI/h/BPatch_parRegion.h b/dyninstAPI/h/BPatch_parRegion.h index 27d9431c5b..f48aa2197f 100644 --- a/dyninstAPI/h/BPatch_parRegion.h +++ b/dyninstAPI/h/BPatch_parRegion.h @@ -74,7 +74,7 @@ class BPATCH_DLL_EXPORT BPatch_parRegion { BPatch_Vector * getInstructions(); - bool getInstructions(std::vector& insns); + bool getInstructions(std::vector& insns); /** BPatch_parRegion::size */ diff --git a/dyninstAPI/h/BPatch_point.h b/dyninstAPI/h/BPatch_point.h index 3605845c43..7fee0cc72f 100644 --- a/dyninstAPI/h/BPatch_point.h +++ b/dyninstAPI/h/BPatch_point.h @@ -35,7 +35,6 @@ #include "BPatch_Vector.h" #include "BPatch_Set.h" #include "BPatch_enums.h" - class InstrucIter; class instPoint; class miniTramp; @@ -229,7 +228,7 @@ class BPATCH_DLL_EXPORT BPatch_point { const BPatch_memoryAccess * getMemoryAccess(); - Dyninst::InstructionAPI::Instruction::Ptr getInsnAtPoint(); + Dyninst::InstructionAPI::Instruction getInsnAtPoint(); // BPatch_point::getCurrentSnippets diff --git a/dyninstAPI/h/BPatch_snippet.h b/dyninstAPI/h/BPatch_snippet.h index d127023d66..590bd46ff7 100644 --- a/dyninstAPI/h/BPatch_snippet.h +++ b/dyninstAPI/h/BPatch_snippet.h @@ -563,20 +563,6 @@ class BPATCH_DLL_EXPORT BPatch_tidExpr : public BPatch_snippet { class BPatch_instruction; -class BPATCH_DLL_EXPORT BPatch_insnExpr : public BPatch_snippet { - public: - // - // BPatch_insnExpr::BPatch_insnExpr - BPatch_insnExpr(BPatch_instruction *insn); - - // Replace the effective address of a load with the provided snippet - bool overrideLoadAddress(BPatch_snippet &l); - - // Replace the effective address of a store with the provided snippet - bool overrideStoreAddress(BPatch_snippet &s); - -}; - typedef enum { BPatch_noInterp, BPatch_interpAsTarget, diff --git a/dyninstAPI/src/BPatch.C b/dyninstAPI/src/BPatch.C index ebf7db0c45..bab8406984 100644 --- a/dyninstAPI/src/BPatch.C +++ b/dyninstAPI/src/BPatch.C @@ -1400,7 +1400,7 @@ BPatch_type * BPatch::createEnum( const char * name, return NULL; } string typeName = name; - vector *>elements; + tbb::concurrent_vector *>elements; for (unsigned int i=0; i < elementNames.size(); i++) elements.push_back(new pair(elementNames[i], elementIds[i])); @@ -1429,7 +1429,7 @@ BPatch_type * BPatch::createEnum( const char * name, BPatch_Vector &elementNames) { string typeName = name; - vector *>elements; + tbb::concurrent_vector *>elements; for (unsigned int i=0; i < elementNames.size(); i++) elements.push_back(new pair(elementNames[i], i)); @@ -1465,7 +1465,7 @@ BPatch_type * BPatch::createStruct( const char * name, } string typeName = name; - vector *> fields; + tbb::concurrent_vector *> fields; for(i=0; i *> fields; + tbb::concurrent_vector *> fields; for(i=0; ireadsMemory(); + return i.readsMemory(); } -bool isStore(Instruction::Ptr i) +bool isStore(Instruction i) { - return i->writesMemory(); + return i.writesMemory(); } -bool isPrefetch(Instruction::Ptr i) +bool isPrefetch(Instruction i) { - return i->getCategory() == c_PrefetchInsn; + return i.getCategory() == c_PrefetchInsn; } struct funcPtrPredicate : public insnPredicate @@ -517,7 +517,7 @@ BPatch_basicBlock::findPointByPredicate(insnPredicate& f) BPatch_locInstruction); if(!tmp) { fprintf(stderr, "WARNING: failed to create instpoint for load/store/prefetch %s at 0x%lx\n", - iter->second->format().c_str(), iter->first); + iter->second.format().c_str(), iter->first); } else { ret->push_back(tmp); @@ -549,7 +549,7 @@ BPatch_Vector *BPatch_basicBlock::findPoint(const BPatch_Set *BPatch_basicBlock::findPoint(bool(*filter)(Instruction::Ptr)) +BPatch_Vector *BPatch_basicBlock::findPoint(bool(*filter)(Instruction)) { funcPtrPredicate filterPtr(filter); @@ -601,7 +601,7 @@ BPatch_function * BPatch_basicBlock::getCallTarget() * */ -bool BPatch_basicBlock::getInstructions(std::vector& insns) { +bool BPatch_basicBlock::getInstructions(std::vector& insns) { using namespace InstructionAPI; InstructionDecoder d((const unsigned char*) @@ -610,7 +610,7 @@ bool BPatch_basicBlock::getInstructions(std::vectorllb()->obj()->cs()->getArch()); do { insns.push_back(d.decode()); - } while (insns.back() && insns.back()->isValid()); + } while (insns.back().isValid()); // Remove final invalid instruction if (!insns.empty()) insns.pop_back(); @@ -618,7 +618,7 @@ bool BPatch_basicBlock::getInstructions(std::vector >& insnInstances) { +bool BPatch_basicBlock::getInstructions(std::vector >& insnInstances) { using namespace InstructionAPI; Address addr = getStartAddress(); const unsigned char *ptr = (const unsigned char *)iblock->proc()->getPtrToInstruction(addr); @@ -627,7 +627,7 @@ bool BPatch_basicBlock::getInstructions(std::vectorsize(); + addr += insnInstances.back().first.size(); } return !insnInstances.empty(); diff --git a/dyninstAPI/src/BPatch_flowGraph.C b/dyninstAPI/src/BPatch_flowGraph.C index ea76e4a318..ebc11727fb 100644 --- a/dyninstAPI/src/BPatch_flowGraph.C +++ b/dyninstAPI/src/BPatch_flowGraph.C @@ -479,9 +479,9 @@ bool BPatch_flowGraph::createSourceBlocks() { BPatch_Vector lines; using namespace Dyninst::InstructionAPI; - std::vector > insnsByAddr; + std::vector > insnsByAddr; currentBlock->getInstructions(insnsByAddr); - for(std::vector >::const_iterator cur = insnsByAddr.begin(); + for(auto cur = insnsByAddr.begin(); cur != insnsByAddr.end(); ++cur) { diff --git a/dyninstAPI/src/BPatch_function.C b/dyninstAPI/src/BPatch_function.C index f297fc63b6..115403852c 100644 --- a/dyninstAPI/src/BPatch_function.C +++ b/dyninstAPI/src/BPatch_function.C @@ -497,11 +497,6 @@ void BPatch_function::getCallerPoints(std::vector& callerPoints) } void BPatch_function::getCallPoints(BPatch_Vector &callPoints) { - /* - const func_instance::BlockSet &blocks = func->callBlocks(); - for (func_instance::BlockSet::const_iterator iter = blocks.begin(); - iter != blocks.end(); ++iter) { -*/ const PatchFunction::Blockset &blocks = func->callBlocks(); for (PatchFunction::Blockset::const_iterator iter = blocks.begin(); iter != blocks.end(); ++iter) { diff --git a/dyninstAPI/src/BPatch_memoryAccessAdapter.C b/dyninstAPI/src/BPatch_memoryAccessAdapter.C index fa1c0edd30..36459a1bb8 100644 --- a/dyninstAPI/src/BPatch_memoryAccessAdapter.C +++ b/dyninstAPI/src/BPatch_memoryAccessAdapter.C @@ -43,7 +43,7 @@ using namespace Dyninst; using namespace InstructionAPI; -BPatch_memoryAccess* BPatch_memoryAccessAdapter::convert(Instruction::Ptr insn, +BPatch_memoryAccess* BPatch_memoryAccessAdapter::convert(Instruction insn, Address current, bool is64) { #if defined(arch_x86) || defined(arch_x86_64) @@ -57,12 +57,11 @@ BPatch_memoryAccess* BPatch_memoryAccessAdapter::convert(Instruction::Ptr insn, ia32_condition cnd; ia32_instruction i(mac, &cnd); - const unsigned char* addr = reinterpret_cast(insn->ptr()); + const unsigned char* addr = reinterpret_cast(insn.ptr()); BPatch_memoryAccess* bmap = BPatch_memoryAccess::none; - ia32_set_mode_64(is64); - - ia32_decode(IA32_DECODE_MEMACCESS|IA32_DECODE_CONDITION, addr, i); + + ia32_decode(IA32_DECODE_MEMACCESS | IA32_DECODE_CONDITION, addr, i, is64); bool first = true; @@ -74,7 +73,7 @@ BPatch_memoryAccess* BPatch_memoryAccessAdapter::convert(Instruction::Ptr insn, // here, we can set the correct address for RIP-relative addressing if (mac.regs[0] == mRIP) { - mac.imm = current + insn->size() + mac.imm; + mac.imm = current + insn.size() + mac.imm; } if(first) { @@ -179,7 +178,7 @@ BPatch_memoryAccess* BPatch_memoryAccessAdapter::convert(Instruction::Ptr insn, #else (void) is64; //Silence warnings std::vector operands; - insn->getOperands(operands); + insn.getOperands(operands); for(std::vector::iterator op = operands.begin(); op != operands.end(); ++op) @@ -189,27 +188,27 @@ BPatch_memoryAccess* BPatch_memoryAccessAdapter::convert(Instruction::Ptr insn, if(isLoad || isStore) { op->getValue()->apply(this); - if(insn->getOperation().getID() == power_op_lmw || - insn->getOperation().getID() == power_op_stmw) + if(insn.getOperation().getID() == power_op_lmw || + insn.getOperation().getID() == power_op_stmw) { RegisterAST::Ptr byteOverride = - boost::dynamic_pointer_cast(insn->getOperand(0).getValue()); + boost::dynamic_pointer_cast(insn.getOperand(0).getValue()); assert(byteOverride); MachRegister base = byteOverride->getID().getBaseRegister(); unsigned int converted = base.val() & 0xFFFF; bytes = (32 - converted) << 2; } - if(insn->getOperation().getID() == power_op_lswi || - insn->getOperation().getID() == power_op_stswi) + if(insn.getOperation().getID() == power_op_lswi || + insn.getOperation().getID() == power_op_stswi) { Immediate::Ptr byteOverride = - boost::dynamic_pointer_cast(insn->getOperand(2).getValue()); + boost::dynamic_pointer_cast(insn.getOperand(2).getValue()); assert(byteOverride); bytes = byteOverride->eval().convert(); if(bytes == 0) bytes = 32; } - if(insn->getOperation().getID() == power_op_lswx || - insn->getOperation().getID() == power_op_stswx) + if(insn.getOperation().getID() == power_op_lswx || + insn.getOperation().getID() == power_op_stswx) { return new BPatch_memoryAccess(new internal_instruction(NULL), current, isLoad, isStore, (long)0, ra, rb, (long)0, 9999, -1); } diff --git a/dyninstAPI/src/BPatch_memoryAccessAdapter.h b/dyninstAPI/src/BPatch_memoryAccessAdapter.h index 31c440d9b6..3abb1c4eba 100644 --- a/dyninstAPI/src/BPatch_memoryAccessAdapter.h +++ b/dyninstAPI/src/BPatch_memoryAccessAdapter.h @@ -47,7 +47,7 @@ class BPatch_memoryAccessAdapter : public Dyninst::InstructionAPI::Visitor virtual ~BPatch_memoryAccessAdapter() { } - BPatch_memoryAccess* convert(Dyninst::InstructionAPI::Instruction::Ptr insn, + BPatch_memoryAccess* convert(Dyninst::InstructionAPI::Instruction insn, Address current, bool is64); virtual void visit(Dyninst::InstructionAPI::BinaryFunction* b); virtual void visit(Dyninst::InstructionAPI::Dereference* d); diff --git a/dyninstAPI/src/BPatch_parRegion.C b/dyninstAPI/src/BPatch_parRegion.C index e258b99c21..1b39794c60 100644 --- a/dyninstAPI/src/BPatch_parRegion.C +++ b/dyninstAPI/src/BPatch_parRegion.C @@ -64,15 +64,15 @@ BPatch_Vector *BPatch_parRegion::getInstructions(void) { return NULL; } -bool BPatch_parRegion::getInstructions(std::vector& insns) { +bool BPatch_parRegion::getInstructions(std::vector& insns) { using namespace InstructionAPI; const unsigned char* buffer = (const unsigned char*)(lowlevel_region()->intFunc()->proc()->getPtrToInstruction(getStartAddress())); InstructionDecoder d(buffer, size(), lowlevel_region()->intFunc()->proc()->getArch()); - Instruction::Ptr curInsn = d.decode(); - while(curInsn && curInsn->isValid()) + Instruction curInsn = d.decode(); + while(curInsn.isValid()) { insns.push_back(curInsn); curInsn = d.decode(); diff --git a/dyninstAPI/src/BPatch_point.C b/dyninstAPI/src/BPatch_point.C index f616ce77ef..cf30e8c9ae 100644 --- a/dyninstAPI/src/BPatch_point.C +++ b/dyninstAPI/src/BPatch_point.C @@ -219,17 +219,17 @@ BPatch_function *BPatch_point::getCalledFunction() parsing_printf("findCallee failed in getCalledFunction- not a call site\n"); return NULL; } - func_instance *_func = point->block()->callee(); + if (!_func) { + parsing_printf("findCallee failed in getCalledFunction\n"); + return NULL; + } if (_func->getPowerPreambleFunc() != NULL) { func_instance * preambleFunc = _func->getPowerPreambleFunc(); return addSpace->findOrCreateBPFunc(preambleFunc, NULL); } - if (!_func) { - parsing_printf("findCallee failed in getCalledFunction\n"); - return NULL; - } + return addSpace->findOrCreateBPFunc(_func, NULL); } @@ -284,15 +284,15 @@ const BPatch_memoryAccess *BPatch_point::getMemoryAccess() // point->addr()); assert(point); // Try to find it... we do so through an InstrucIter - Dyninst::InstructionAPI::Instruction::Ptr i = getInsnAtPoint(); - if (!i) return NULL; + Dyninst::InstructionAPI::Instruction i = getInsnAtPoint(); + if (!i.isValid()) return NULL; BPatch_memoryAccessAdapter converter; attachMemAcc(converter.convert(i, point->insnAddr(), point->proc()->getAddressWidth() == 8)); return memacc; } -InstructionAPI::Instruction::Ptr BPatch_point::getInsnAtPoint() +InstructionAPI::Instruction BPatch_point::getInsnAtPoint() { return point->insn(); } @@ -462,7 +462,7 @@ void *BPatch_point::monitorCalls( BPatch_function * user_cb ) // The callback takes two arguments: the first is the (address of the) callee, // the second the (address of the) callsite. - InstructionAPI::Instruction::Ptr insn = point->block()->getInsn(point->block()->last()); + InstructionAPI::Instruction insn = point->block()->getInsn(point->block()->last()); pdvector args; if (!lladdSpace->getDynamicCallSiteArgs(insn, point->block()->last(), args)) return NULL; diff --git a/dyninstAPI/src/BPatch_snippet.C b/dyninstAPI/src/BPatch_snippet.C index 1e00924994..a548884ee8 100644 --- a/dyninstAPI/src/BPatch_snippet.C +++ b/dyninstAPI/src/BPatch_snippet.C @@ -341,12 +341,11 @@ AstNodePtr generateFieldRef(const BPatch_snippet &lOperand, return AstNodePtr(); } - vector *fields; Field *field = NULL; // check that the name of the right operand is a field of the left operand - fields = structType->getComponents(); + auto fields = structType->getComponents(); unsigned int i; @@ -1600,27 +1599,6 @@ BPatch_tidExpr::BPatch_tidExpr(BPatch_process *proc) // BPATCH INSN EXPR -BPatch_insnExpr::BPatch_insnExpr(BPatch_instruction *insn) { - ast_wrapper = AstNodePtr(AstNode::insnNode(insn)); -} - -bool BPatch_insnExpr::overrideLoadAddress(BPatch_snippet &l) { - // We can assert our AST is an insn type... - // Don't hand back insnAst to anyone else - AstInsnNode *insnAst = dynamic_cast(ast_wrapper.get()); - assert(insnAst); - - return insnAst->overrideLoadAddr(l.ast_wrapper); -} - -bool BPatch_insnExpr::overrideStoreAddress(BPatch_snippet &s) { - // We can assert our AST is an insn type... - AstInsnNode *insnAst = dynamic_cast(ast_wrapper.get()); - assert(insnAst); - - return insnAst->overrideStoreAddr(s.ast_wrapper); -} - /* Causes us to create only one StopThreadCallback per BPatchStopThreadCallback, though we create a function call snippet diff --git a/dyninstAPI/src/BPatch_type.C b/dyninstAPI/src/BPatch_type.C index 819b5700ac..b7da6ec2b2 100644 --- a/dyninstAPI/src/BPatch_type.C +++ b/dyninstAPI/src/BPatch_type.C @@ -229,7 +229,7 @@ BPatch_Vector *BPatch_type::getComponents() const{ return NULL; BPatch_Vector *components = new BPatch_Vector(); if(fieldlisttype) { - vector *comps = fieldlisttype->getComponents(); + auto comps = fieldlisttype->getComponents(); if(!comps){ delete components; return NULL; @@ -241,7 +241,7 @@ BPatch_Vector *BPatch_type::getComponents() const{ if (enumtype) { - vector > &constants = enumtype->getConstants(); + auto constants = enumtype->getConstants(); for (unsigned i = 0; i < constants.size(); i++) { Field *fld = new Field(constants[i].first.c_str(), NULL); @@ -262,7 +262,7 @@ BPatch_Vector *BPatch_type::getCblocks() const if (!commontype) return NULL; - std::vector *cblocks = commontype->getCblocks(); + auto cblocks = commontype->getCblocks(); if (!cblocks) return NULL; @@ -612,7 +612,7 @@ void BPatch_cblock::fixupUnknowns(BPatch_module *module) { BPatch_Vector *BPatch_cblock::getComponents() { BPatch_Vector *components = new BPatch_Vector; - std::vector *vars = cBlk->getComponents(); + auto vars = cBlk->getComponents(); if (!vars) return NULL; @@ -639,7 +639,7 @@ BPatch_Vector *BPatch_cblock::getComponents() BPatch_Vector *BPatch_cblock::getFunctions() { - std::vector *funcs = cBlk->getFunctions(); + auto funcs = cBlk->getFunctions(); if(!funcs) return NULL; assert(0); diff --git a/dyninstAPI/src/Parsing.C b/dyninstAPI/src/Parsing.C index 4b04ea2f03..41b023318a 100644 --- a/dyninstAPI/src/Parsing.C +++ b/dyninstAPI/src/Parsing.C @@ -161,9 +161,11 @@ DynCFGFactory::mkfunc( break; } } - ret = new parse_func(stf, pdmod,_img,obj,reg,isrc,src); - ret->isPLTFunction_ = true; - return ret; + if(stf->getFirstSymbol()) { + ret = new parse_func(stf, pdmod,_img,obj,reg,isrc,src); + ret->isPLTFunction_ = true; + return ret; + } } if(!st->findFuncByEntryOffset(stf,addr)) { pdmod = _img->getOrCreateModule(st->getDefaultModule()); diff --git a/dyninstAPI/src/Relocation/CFG/RelocBlock.C b/dyninstAPI/src/Relocation/CFG/RelocBlock.C index fc860fc36a..31bdd1b2c5 100644 --- a/dyninstAPI/src/Relocation/CFG/RelocBlock.C +++ b/dyninstAPI/src/Relocation/CFG/RelocBlock.C @@ -83,7 +83,7 @@ RelocBlock *RelocBlock::createReloc(block_instance *block, func_instance *func) if (block->_ignorePowerPreamble && cnt < 2) continue; relocation_cerr << " Adding instruction @" << std::hex << iter->first << std::dec - << ": " << iter->second->format(iter->first) << endl; + << ": " << iter->second.format(iter->first) << endl; Widget::Ptr ptr = InsnWidget::create(iter->second, iter->first); if (!ptr) { @@ -161,7 +161,7 @@ void RelocBlock::getPredecessors(RelocGraph *cfg) { } -// There's some tricky logic going on here. We want to create the following +// There's some tricky logic going on here. We want to create the following // edges: // 1) All out-edges, as _someone_ has to create them // 2) In-edges that aren't from RelocBlocks; if it's from a RelocBlock we assume we'll @@ -315,11 +315,11 @@ void RelocBlock::createCFWidget() { bool hasCF = false; - InstructionAPI::Instruction::Ptr insn = elements_.back()->insn(); - if (insn) { - if (insn->getCategory() == c_CallInsn || - insn->getCategory() == c_ReturnInsn || - insn->getCategory() == c_BranchInsn) { + InstructionAPI::Instruction insn = elements_.back()->insn(); + if (insn.isValid()) { + if (insn.getCategory() == c_CallInsn || + insn.getCategory() == c_ReturnInsn || + insn.getCategory() == c_BranchInsn) { hasCF = true; } } @@ -358,7 +358,7 @@ void RelocBlock::preserveBlockGap() { const PatchBlock::edgelist &targets = block_->targets(); bool hasCall = false; bool hasFT = false; - for (PatchBlock::edgelist::const_iterator iter = targets.begin(); iter != targets.end(); ++iter) { + for (auto iter = targets.begin(); iter != targets.end(); ++iter) { if ((*iter)->type() == ParseAPI::CALL) { hasCall = true; } @@ -397,13 +397,13 @@ void RelocBlock::preserveBlockGap() { // jump instruction that we may not have encoded in ParseAPI. std::pair RelocBlock::getJumpTarget() { - InstructionAPI::Instruction::Ptr insn = cfWidget()->insn(); - if (!insn) return std::make_pair(false, 0); + InstructionAPI::Instruction insn = cfWidget()->insn(); + if (!insn.isValid()) return std::make_pair(false, 0); - Expression::Ptr cft = insn->getControlFlowTarget(); + Expression::Ptr cft = insn.getControlFlowTarget(); if (!cft) return std::make_pair(false, 0); - Expression::Ptr thePC(new RegisterAST(MachRegister::getPC(insn->getArch()))); + Expression::Ptr thePC(new RegisterAST(MachRegister::getPC(insn.getArch()))); cft->bind(thePC.get(), Result(u64, cfWidget()->addr())); Result res = cft->eval(); diff --git a/dyninstAPI/src/Relocation/CodeBuffer.C b/dyninstAPI/src/Relocation/CodeBuffer.C index e7d0ccf37e..a7cc80aae5 100644 --- a/dyninstAPI/src/Relocation/CodeBuffer.C +++ b/dyninstAPI/src/Relocation/CodeBuffer.C @@ -294,10 +294,10 @@ void CodeBuffer::disassemble() const { gen_.getArch()); Address addr = gen_.startAddr(); - Instruction::Ptr cur = decoder.decode(); - while (cur && cur->isValid()) { - cerr << "\t" << std::hex << addr << std::dec << ": " << cur->format() << endl; - addr += cur->size(); + Instruction cur = decoder.decode(); + while (cur.isValid()) { + cerr << "\t" << std::hex << addr << std::dec << ": " << cur.format() << endl; + addr += cur.size(); cur = decoder.decode(); } } diff --git a/dyninstAPI/src/Relocation/DynPointMaker.C b/dyninstAPI/src/Relocation/DynPointMaker.C index 756584b061..26ed8ed69c 100644 --- a/dyninstAPI/src/Relocation/DynPointMaker.C +++ b/dyninstAPI/src/Relocation/DynPointMaker.C @@ -47,8 +47,8 @@ Point *DynPointMaker::mkBlockPoint(Point::Type t, PatchMgrPtr m, PatchBlock *b, return new instPoint(t, m, SCAST_BI(b), SCAST_FI(context)); } -Point *DynPointMaker::mkInsnPoint(Point::Type t, PatchMgrPtr m, PatchBlock *b, Address a, - InstructionAPI::Instruction::Ptr i, PatchFunction *context) { +Point *DynPointMaker::mkInsnPoint(Point::Type t, PatchMgrPtr m, PatchBlock *b, Address a, + InstructionAPI::Instruction i, PatchFunction *context) { return new instPoint(t, m, SCAST_BI(b), a, i, SCAST_FI(context)); } diff --git a/dyninstAPI/src/Relocation/DynPointMaker.h b/dyninstAPI/src/Relocation/DynPointMaker.h index 6457af6c66..32eeaacb6c 100644 --- a/dyninstAPI/src/Relocation/DynPointMaker.h +++ b/dyninstAPI/src/Relocation/DynPointMaker.h @@ -52,8 +52,8 @@ class DynPointMaker : public Dyninst::PatchAPI::PointMaker { virtual Point *mkFuncPoint(Point::Type t, PatchMgrPtr m, PatchFunction *); virtual Point *mkFuncSitePoint(Point::Type t, PatchMgrPtr m, PatchFunction *, PatchBlock *); virtual Point *mkBlockPoint(Point::Type t, PatchMgrPtr m, PatchBlock *, PatchFunction *context); - virtual Point *mkInsnPoint(Point::Type t, PatchMgrPtr m, PatchBlock *, Address, - InstructionAPI::Instruction::Ptr, PatchFunction *context); + virtual Point *mkInsnPoint(Point::Type t, PatchMgrPtr m, PatchBlock *, Address, + InstructionAPI::Instruction, PatchFunction *context); virtual Point *mkEdgePoint(Point::Type t, PatchMgrPtr m, PatchEdge *, PatchFunction *f); }; diff --git a/dyninstAPI/src/Relocation/Transformers/Instrumenter.C b/dyninstAPI/src/Relocation/Transformers/Instrumenter.C index bc6401ca8c..f176007f7b 100644 --- a/dyninstAPI/src/Relocation/Transformers/Instrumenter.C +++ b/dyninstAPI/src/Relocation/Transformers/Instrumenter.C @@ -168,7 +168,7 @@ bool Instrumenter::insnInstrumentation(RelocBlock *trace) { RelocBlock::WidgetList::iterator tmp = elem; while ((tmp != trace->elements().end()) && ((*tmp)->addr() == postAddr) && - ((*tmp)->insn())) ++tmp; + ((*tmp)->insn().isValid())) ++tmp; Widget::Ptr inst = makeInstrumentation(post->second); if (!inst) { relocation_cerr << "Failed to make post-instrumentation at " << hex << postAddr << ", ret failed" << dec << endl; @@ -202,8 +202,8 @@ bool Instrumenter::preCallInstrumentation(RelocBlock *trace) { if (!inst) return false; RelocBlock::WidgetList::reverse_iterator riter = elements.rbegin(); - InstructionAPI::Instruction::Ptr call_insn = (*riter)->insn(); - if (call_insn) { + InstructionAPI::Instruction call_insn = (*riter)->insn(); + if (call_insn.isValid()) { while (riter != elements.rend() && (*riter)->insn() == call_insn) ++riter; } elements.insert(riter.base(), inst); @@ -242,7 +242,7 @@ bool Instrumenter::funcExitInstrumentation(RelocBlock *trace, RelocGraph *cfg) { CFWidget::Ptr retcc = trace->cfWidget(); assert(retcc); - relocation_cerr << "Checking return statement " << (retcc->insn() ? retcc->insn()->format() : "") << ": " + relocation_cerr << "Checking return statement " << (retcc->insn().isValid() ? retcc->insn().format() : "") << ": " << (retcc->isConditional() ? "" : "") << (retcc->isIndirect() ? "" : "") << endl; @@ -336,7 +336,7 @@ bool Instrumenter::handleCondDirExits(RelocBlock *trace, RelocGraph *cfg, instPo CFWidget::Ptr retcc = trace->cfWidget(); assert(retcc); - relocation_cerr << "Checking return statement " << (retcc->insn() ? retcc->insn()->format() : "") << ": " + relocation_cerr << "Checking return statement " << (retcc->insn().isValid() ? retcc->insn().format() : "") << ": " << (retcc->isConditional() ? "" : "") << (retcc->isIndirect() ? "" : "") << endl; diff --git a/dyninstAPI/src/Relocation/Transformers/Movement-adhoc.C b/dyninstAPI/src/Relocation/Transformers/Movement-adhoc.C index faef833b41..d0f8a8004e 100644 --- a/dyninstAPI/src/Relocation/Transformers/Movement-adhoc.C +++ b/dyninstAPI/src/Relocation/Transformers/Movement-adhoc.C @@ -137,8 +137,8 @@ bool adhocMovementTransformer::process(RelocBlock *cur, RelocGraph *cfg) { // first insert new (before iter) and then remove iter // Cache this so we don't re-decode... - InsnPtr insn = (*iter)->insn(); - if (!insn) continue; + auto insn = (*iter)->insn(); + if (!insn.isValid()) continue; Address target = 0; Absloc aloc; @@ -149,7 +149,7 @@ bool adhocMovementTransformer::process(RelocBlock *cur, RelocGraph *cfg) { cf->setOrigTarget(target); } if (isPCRelData(*iter, insn, target)) { - relocation_cerr << " ... isPCRelData at " + relocation_cerr << " ... isPCRelData at " << std::hex << (*iter)->addr() << std::dec << endl; // Two options: a memory reference or a indirect call. The indirect call we // just want to set target in the CFWidget, as it has the hardware to handle @@ -201,9 +201,9 @@ bool adhocMovementTransformer::process(RelocBlock *cur, RelocGraph *cfg) { // Perform check and generate StackModWidget if necessary Offset origDisp; signed long delta; - Architecture arch = insn->getArch(); + Architecture arch = insn.getArch(); stackmods_printf("Checking isStackFrameSensitive @ 0x%lx = %s\n", - (*iter)->addr(), insn->format().c_str()); + (*iter)->addr(), insn.format().c_str()); try { if (isStackFrameSensitive(origDisp, delta, accesses, offVec, tMap, cur->block()->llb(), (*iter)->addr())) { @@ -238,30 +238,30 @@ bool adhocMovementTransformer::process(RelocBlock *cur, RelocGraph *cfg) { return true; } -static Address PCValue(Address addr, Instruction::Ptr insn) { +static Address PCValue(Address addr, Instruction insn) { // ARM is for sure using pre-insnstruction PC value - if (insn->getArch() == Arch_aarch64 || insn->getArch() == Arch_aarch32) { + if (insn.getArch() == Arch_aarch64 || insn.getArch() == Arch_aarch32) { return addr; } else { - return addr + insn->size(); + return addr + insn.size(); } } bool adhocMovementTransformer::isPCDerefCF(Widget::Ptr ptr, - InsnPtr insn, + Instruction insn, Address &target) { - Expression::Ptr cf = insn->getControlFlowTarget(); + Expression::Ptr cf = insn.getControlFlowTarget(); if (!cf) return false; // Architecture fixme = insn->getArch(); // if (fixme == Arch_ppc32) fixme = Arch_ppc64; - Expression::Ptr thePC(new RegisterAST(MachRegister::getPC(insn->getArch()))); + Expression::Ptr thePC(new RegisterAST(MachRegister::getPC(insn.getArch()))); // Expression::Ptr thePCFixme(new RegisterAST(MachRegister::getPC(fixme))); // Okay, see if we're memory set mems; - insn->getMemoryReadOperands(mems); + insn.getMemoryReadOperands(mems); for (set::const_iterator iter = mems.begin(); iter != mems.end(); ++iter) { @@ -270,7 +270,7 @@ bool adhocMovementTransformer::isPCDerefCF(Widget::Ptr ptr, // Bind succeeded, eval to get target address Result res = exp->eval(); if (!res.defined) { - cerr << "ERROR: failed bind/eval at " << std::hex << ptr->addr() << endl;if (insn->getControlFlowTarget()) return false; + cerr << "ERROR: failed bind/eval at " << std::hex << ptr->addr() << endl;if (insn.getControlFlowTarget()) return false; } assert(res.defined); target = res.convert
(); @@ -285,26 +285,28 @@ bool adhocMovementTransformer::isPCDerefCF(Widget::Ptr ptr, // We define this as "uses PC and is not control flow" bool adhocMovementTransformer::isPCRelData(Widget::Ptr ptr, - InsnPtr insn, + Instruction insn, Address &target) { target = 0; - if (insn->getControlFlowTarget()) return false; + switch(insn.getCategory()) + { + case c_CallInsn: + case c_BranchInsn: + case c_ReturnInsn: + return false; + } + if (insn.getControlFlowTarget()) return false; - //Architecture fixme = insn->getArch(); - //if (fixme == Arch_ppc32) fixme = Arch_ppc64; - - Expression::Ptr thePC(new RegisterAST(MachRegister::getPC(insn->getArch()))); - //Expression::Ptr thePCFixme(new RegisterAST(MachRegister::getPC(fixme))); - if (!insn->isRead(thePC)) - //&& -// !insn->isRead(thePCFixme)) + Expression::Ptr thePC(new RegisterAST(MachRegister::getPC(insn.getArch()))); + + if (!insn.isRead(thePC)) return false; // Okay, see if we're memory set mems; - insn->getMemoryReadOperands(mems); - insn->getMemoryWriteOperands(mems); + insn.getMemoryReadOperands(mems); + insn.getMemoryWriteOperands(mems); for (set::const_iterator iter = mems.begin(); iter != mems.end(); ++iter) { Expression::Ptr exp = *iter; @@ -325,7 +327,7 @@ bool adhocMovementTransformer::isPCRelData(Widget::Ptr ptr, // all the operands. We didn't do this directly because the // memory-topping deref stops eval... vector operands; - insn->getOperands(operands); + insn.getOperands(operands); for (vector::iterator iter = operands.begin(); iter != operands.end(); ++iter) { // If we can bind the PC, then we're in the operand @@ -340,7 +342,7 @@ bool adhocMovementTransformer::isPCRelData(Widget::Ptr ptr, } } if (target == 0) { - cerr << "Error: failed to bind PC in " << insn->format() << endl; + cerr << "Error: failed to bind PC in " << insn.format() << endl; } assert(target != 0); return true; @@ -393,27 +395,27 @@ public: bool adhocMovementTransformer::isGetPC(Widget::Ptr ptr, - InsnPtr insn, - Absloc &aloc, - Address &thunk) { + Instruction insn, + Absloc &aloc, + Address &thunk) { // TODO: // Check for call + size; // Check for call to thunk. // TODO: need a return register parameter. - if (insn->getCategory() != InstructionAPI::c_CallInsn) return false; + if (insn.getCategory() != InstructionAPI::c_CallInsn) return false; // Okay: checking for call + size - Expression::Ptr CFT = insn->getControlFlowTarget(); + Expression::Ptr CFT = insn.getControlFlowTarget(); if (!CFT) { relocation_cerr << " ... no CFT, ret false from isGetPC" << endl; return false; } - Expression::Ptr thePC(new RegisterAST(MachRegister::getPC(insn->getArch()))); + Expression::Ptr thePC(new RegisterAST(MachRegister::getPC(insn.getArch()))); - switch(insn->getArch()) { + switch(insn.getArch()) { case Arch_x86: case Arch_ppc32: CFT->bind(thePC.get(), Result(u32, ptr->addr())); @@ -437,7 +439,7 @@ bool adhocMovementTransformer::isGetPC(Widget::Ptr ptr, Address target = res.convert
(); - if (target == (ptr->addr() + insn->size())) { + if (target == (ptr->addr() + insn.size())) { aloc = Absloc(0, 0, NULL); relocation_cerr << " ... call next insn, ret true" << endl; return true; @@ -453,7 +455,7 @@ bool adhocMovementTransformer::isGetPC(Widget::Ptr ptr, const unsigned char* buf = reinterpret_cast(addrSpace->getPtrToInstruction(target)); if (!buf) { cerr << "Error: illegal pointer to buffer!" << endl; - cerr << "Target of " << hex << target << " from addr " << ptr->addr() << " in insn " << insn->format() << dec << endl; + cerr << "Target of " << hex << target << " from addr " << ptr->addr() << " in insn " << insn.format() << dec << endl; assert(0); } @@ -461,20 +463,21 @@ bool adhocMovementTransformer::isGetPC(Widget::Ptr ptr, 2*InstructionDecoder::maxInstructionLength, addrSpace->getArch()); - Instruction::Ptr firstInsn = decoder.decode(); - Instruction::Ptr secondInsn = decoder.decode(); + Instruction firstInsn = decoder.decode(); + Instruction secondInsn = decoder.decode(); relocation_cerr << " ... decoded target insns " - << firstInsn->format() << ", " - << secondInsn->format() << endl; + << firstInsn.format() << ", " + << secondInsn.format() << endl; - if(firstInsn && firstInsn->getOperation().getID() == e_mov - && firstInsn->readsMemory() && !firstInsn->writesMemory() - && secondInsn && secondInsn->getCategory() == c_ReturnInsn) { + if(firstInsn.isValid() && firstInsn.getOperation().getID() == e_mov + && firstInsn.readsMemory() && !firstInsn.writesMemory() + && secondInsn.isValid() && secondInsn.getCategory() == c_ReturnInsn) { thunkVisitor visitor; - relocation_cerr << "Checking operand " << firstInsn->getOperand(1).format(firstInsn->getFormatter(), firstInsn->getArch()) << endl; - firstInsn->getOperand(1).getValue()->apply(&visitor); + relocation_cerr << "Checking operand " + << firstInsn.getOperand(1).format(firstInsn.getArch()) << endl; + firstInsn.getOperand(1).getValue()->apply(&visitor); if (!visitor.isThunk) return false; #if 0 @@ -494,7 +497,7 @@ bool adhocMovementTransformer::isGetPC(Widget::Ptr ptr, #endif std::set writes; - firstInsn->getWriteSet(writes); + firstInsn.getWriteSet(writes); assert(writes.size() == 1); aloc = Absloc((*(writes.begin()))->getID()); thunk = target; diff --git a/dyninstAPI/src/Relocation/Transformers/Movement-adhoc.h b/dyninstAPI/src/Relocation/Transformers/Movement-adhoc.h index 9d65c4de02..c307a5348b 100644 --- a/dyninstAPI/src/Relocation/Transformers/Movement-adhoc.h +++ b/dyninstAPI/src/Relocation/Transformers/Movement-adhoc.h @@ -61,16 +61,16 @@ class adhocMovementTransformer : public Transformer { private: bool isPCDerefCF(WidgetPtr ptr, - InsnPtr insn, + InstructionAPI::Instruction insn, Address &destPtr); bool isPCRelData(WidgetPtr ptr, - InsnPtr insn, - Address &target); + InstructionAPI::Instruction insn, + Address &target); // Records where PC was stored bool isGetPC(WidgetPtr ptr, - InsnPtr insn, - Absloc &aloc, - Address &thunkAddr); + InstructionAPI::Instruction insn, + Absloc &aloc, + Address &thunkAddr); #if defined(cap_stack_mods) bool isStackFrameSensitive(Offset& origOffset, signed long& delta, diff --git a/dyninstAPI/src/Relocation/Transformers/Movement-analysis.C b/dyninstAPI/src/Relocation/Transformers/Movement-analysis.C index c6a8942030..0fd7dbccd2 100644 --- a/dyninstAPI/src/Relocation/Transformers/Movement-analysis.C +++ b/dyninstAPI/src/Relocation/Transformers/Movement-analysis.C @@ -99,8 +99,8 @@ bool PCSensitiveTransformer::process(RelocBlock *reloc, RelocGraph *g) { // Get the instruction contained by this element; might be from // an original instruction (RelocInsn) or the CF wrapper (CFWidget) - Instruction::Ptr insn = (*iter)->insn(); - if (!insn) continue; + Instruction insn = (*iter)->insn(); + if (!insn.isValid()) continue; Address addr = (*iter)->addr(); // We want to identify all PC-sensitive instructions and @@ -142,7 +142,7 @@ bool PCSensitiveTransformer::process(RelocBlock *reloc, RelocGraph *g) { extSens_++; thunk_++; continue; - } else if (insn->getCategory() == c_CallInsn && exceptionSensitive(addr+insn->size(), block)) { + } else if (insn.getCategory() == c_CallInsn && exceptionSensitive(addr+insn.size(), block)) { extSens = true; sensitivity_cerr << "\tException sensitive @ " << hex << addr << dec << endl; } @@ -236,7 +236,7 @@ bool PCSensitiveTransformer::process(RelocBlock *reloc, RelocGraph *g) { // original instruction, which means the internally sensitive target will // be transferring back to the original instruction address. Go ahead and // record this... - recordIntSensitive(addr+insn->size()); + recordIntSensitive(addr+insn.size()); } } @@ -269,12 +269,12 @@ bool PCSensitiveTransformer::process(RelocBlock *reloc, RelocGraph *g) { return true; } -bool PCSensitiveTransformer::isPCSensitive(Instruction::Ptr insn, - Address addr, - const func_instance *func, - const block_instance *block, - AssignList &sensitiveAssignments) { - if (!(insn->getOperation().getID() == e_call)) return false; +bool PCSensitiveTransformer::isPCSensitive(Instruction insn, + Address addr, + const func_instance *func, + const block_instance *block, + AssignList &sensitiveAssignments) { + if (!(insn.getOperation().getID() == e_call)) return false; if(func->obj()->hybridMode() == BPatch_normalMode) return false; // FIXME for loopnz instruction Absloc pc = Absloc::makePC(func->ifunc()->isrc()->getArch()); @@ -434,14 +434,14 @@ bool PCSensitiveTransformer::determineSensitivity(Graph::Ptr slice, // An example of a group transformation. If this is a call to a thunk // function then record both that (as in return true) and where the return // address gets put... -bool PCSensitiveTransformer::insnIsThunkCall(InstructionAPI::Instruction::Ptr insn, - Address addr, - Absloc &destination) { +bool PCSensitiveTransformer::insnIsThunkCall(Instruction insn, + Address addr, + Absloc &destination) { // Should be able to handle this much more efficiently by following the CFG - if (insn->getCategory() != c_CallInsn) { + if (insn.getCategory() != c_CallInsn) { return false; } - Expression::Ptr CFT = insn->getControlFlowTarget(); + Expression::Ptr CFT = insn.getControlFlowTarget(); if (!CFT) { return false; } @@ -464,7 +464,7 @@ bool PCSensitiveTransformer::insnIsThunkCall(InstructionAPI::Instruction::Ptr in Address target = res.convert
(); // Check for a call to a thunk function - if (target == (addr + insn->size())) { + if (target == (addr + insn.size())) { destination = Absloc(0, 0, NULL); return true; } @@ -479,19 +479,19 @@ bool PCSensitiveTransformer::insnIsThunkCall(InstructionAPI::Instruction::Ptr in 2*InstructionDecoder::maxInstructionLength, addrSpace->getArch()); - Instruction::Ptr firstInsn = decoder.decode(); - Instruction::Ptr secondInsn = decoder.decode(); + Instruction firstInsn = decoder.decode(); + Instruction secondInsn = decoder.decode(); //relocation_cerr << " ... decoded target insns " //<< firstInsn->format() << ", " //<< secondInsn->format() << endl; - if(firstInsn && firstInsn->getOperation().getID() == e_mov - && firstInsn->readsMemory() && !firstInsn->writesMemory() - && secondInsn && secondInsn->getCategory() == c_ReturnInsn) { + if(firstInsn.isValid() && firstInsn.getOperation().getID() == e_mov + && firstInsn.readsMemory() && !firstInsn.writesMemory() + && secondInsn.isValid() && secondInsn.getCategory() == c_ReturnInsn) { // Check to be sure we're reading memory std::set reads; - firstInsn->getReadSet(reads); + firstInsn.getReadSet(reads); bool found = false; for (std::set::iterator iter = reads.begin(); iter != reads.end(); ++iter) { @@ -504,7 +504,7 @@ bool PCSensitiveTransformer::insnIsThunkCall(InstructionAPI::Instruction::Ptr in if (!found) return false; std::set writes; - firstInsn->getWriteSet(writes); + firstInsn.getWriteSet(writes); assert(writes.size() == 1); destination = Absloc((*(writes.begin()))->getID()); return true; @@ -563,14 +563,14 @@ void PCSensitiveTransformer::recordIntSensitive(Address addr) { void PCSensitiveTransformer::emulateInsn(RelocBlock *reloc, RelocGraph *cfg, - RelocBlock::WidgetList::iterator &iter, - InstructionAPI::Instruction::Ptr insn, - Address addr) { + RelocBlock::WidgetList::iterator &iter, + Instruction insn, + Address addr) { //cerr << "Emulating @" << std::hex << addr << std::dec << endl; // We emulate calls by replacing them with push/jump combinations. The jump will be handled - // by a CFWidget, so we just need a "push" (and then to create everything else). + // by a CFWidget, so we just need a "push" (and then to create everything else). - if(insn->getOperation().getID() != e_call) { + if(insn.getOperation().getID() != e_call) { // emulating a non-call is a no-op return; } @@ -908,12 +908,12 @@ bool ExtPCSensVisitor::isExtSens(AST::Ptr a) { } } -bool PCSensitiveTransformer::isSyscall(InstructionAPI::Instruction::Ptr insn, Address) { +bool PCSensitiveTransformer::isSyscall(Instruction insn, Address) { // call *%gs:0x10 // Build a GS static Expression::Ptr x86_gs(new RegisterAST(x86::gs)); - if (insn->isRead(x86_gs)) { + if (insn.isRead(x86_gs)) { //relocation_cerr << "Skipping syscall " << insn->format() << hex << "@ " << addr << dec << endl; return true; } diff --git a/dyninstAPI/src/Relocation/Transformers/Movement-analysis.h b/dyninstAPI/src/Relocation/Transformers/Movement-analysis.h index 8ecb06fa2b..30985f5e77 100644 --- a/dyninstAPI/src/Relocation/Transformers/Movement-analysis.h +++ b/dyninstAPI/src/Relocation/Transformers/Movement-analysis.h @@ -107,11 +107,11 @@ class PCSensitiveTransformer : public Transformer { private: bool analysisRequired(RelocBlock *); - bool isPCSensitive(InstructionAPI::Instruction::Ptr insn, - Address addr, - const func_instance *func, - const block_instance *block, - AssignList &sensitiveAssignment); + bool isPCSensitive(InstructionAPI::Instruction insn, + Address addr, + const func_instance *func, + const block_instance *block, + AssignList &sensitiveAssignment); Graph::Ptr forwardSlice(Assignment::Ptr ptr, parse_block *block, parse_func *func); @@ -119,23 +119,23 @@ class PCSensitiveTransformer : public Transformer { bool &intSens, bool &extSens); - bool insnIsThunkCall(InstructionAPI::Instruction::Ptr insn, - Address addr, - Absloc &destination); + bool insnIsThunkCall(InstructionAPI::Instruction insn, + Address addr, + Absloc &destination); void handleThunkCall(RelocBlock *b_iter, RelocGraph *cfg, WidgetList::iterator &iter, Absloc &destination); void recordIntSensitive(Address addr); void emulateInsn(RelocBlock *b_iter, - RelocGraph *cfg, - WidgetList::iterator &iter, - InstructionAPI::Instruction::Ptr insn, - Address addr); + RelocGraph *cfg, + WidgetList::iterator &iter, + InstructionAPI::Instruction insn, + Address addr); bool exceptionSensitive(Address addr, const block_instance *bbl); - bool isSyscall(InstructionAPI::Instruction::Ptr insn, Address addr); + bool isSyscall(InstructionAPI::Instruction insn, Address addr); static void cacheAnalysis(const block_instance *bbl, Address addr, bool intSens, bool extSens); static bool queryCache(const block_instance *bbl, Address addr, bool &intSens, bool &extSens); diff --git a/dyninstAPI/src/Relocation/Widgets/CFPatch.C b/dyninstAPI/src/Relocation/Widgets/CFPatch.C index 5279f179dc..af9b348d10 100644 --- a/dyninstAPI/src/Relocation/Widgets/CFPatch.C +++ b/dyninstAPI/src/Relocation/Widgets/CFPatch.C @@ -47,19 +47,6 @@ using namespace Dyninst; using namespace Relocation; using namespace InstructionAPI; -CFPatch::CFPatch(Type a, - InstructionAPI::Instruction::Ptr b, - TargetInt *c, - Address d) : - type(a), orig_insn(b), target(c), origAddr_(d) { - if (b) - ugly_insn = new NS_x86::instruction(b->ptr()); - else - ugly_insn = NULL; - // New branches don't get an original instruction... -} - - bool CFPatch::apply(codeGen &gen, CodeBuffer *buf) { // Question 1: are we doing an inter-module static control transfer? // If so, things get... complicated diff --git a/dyninstAPI/src/Relocation/Widgets/CFWidget-ppc.C b/dyninstAPI/src/Relocation/Widgets/CFWidget-ppc.C index 3d4a394e12..a20cc62391 100644 --- a/dyninstAPI/src/Relocation/Widgets/CFWidget-ppc.C +++ b/dyninstAPI/src/Relocation/Widgets/CFWidget-ppc.C @@ -52,12 +52,12 @@ using namespace NS_power; bool CFWidget::generateIndirect(CodeBuffer &buffer, Register, const RelocBlock *trace, - Instruction::Ptr insn) { + Instruction insn) { // Copying an indirect jump; unlike x86 we don't do // call -> indirect conversion yet. // ... though that would be really freaking easy. - NS_power::instruction ugly_insn(insn->ptr()); + NS_power::instruction ugly_insn(insn.ptr()); IFORM_LK_SET(ugly_insn, 0); codeGen gen(4); insnCodeGen::generate(gen, ugly_insn); @@ -72,11 +72,11 @@ bool CFWidget::generateIndirect(CodeBuffer &buffer, bool CFWidget::generateIndirectCall(CodeBuffer &buffer, Register /*reg*/, - Instruction::Ptr insn, + Instruction insn, const RelocBlock *trace, Address /*origAddr*/) { - NS_power::instruction ugly_insn(insn->ptr()); + NS_power::instruction ugly_insn(insn.ptr()); IFORM_LK_SET(ugly_insn, 1); codeGen gen(4); insnCodeGen::generate(gen, ugly_insn); @@ -116,7 +116,7 @@ bool CFPatch::apply(codeGen &gen, CodeBuffer *buf) { relocation_cerr << "\t\t CFPatch::apply, type " << type << ", origAddr " << hex << origAddr_ << ", and label " << dec << targetLabel << endl; - if (orig_insn) { + if (orig_insn.isValid()) { relocation_cerr << "\t\t\t Currently at " << hex << gen.currAddr() << " and targeting predicted " << buf->predictedAddr(targetLabel) << dec << endl; switch(type) { case CFPatch::Jump: { diff --git a/dyninstAPI/src/Relocation/Widgets/CFWidget-x86.C b/dyninstAPI/src/Relocation/Widgets/CFWidget-x86.C index c3d544fdfb..e9ba380088 100644 --- a/dyninstAPI/src/Relocation/Widgets/CFWidget-x86.C +++ b/dyninstAPI/src/Relocation/Widgets/CFWidget-x86.C @@ -57,9 +57,9 @@ using namespace InstructionAPI; using namespace NS_x86; bool CFWidget::generateIndirect(CodeBuffer &buffer, - Register reg, - const RelocBlock *trace, - Instruction::Ptr insn) { + Register reg, + const RelocBlock *trace, + Instruction insn) { // Two possibilities here: either copying an indirect jump w/o // changes, or turning an indirect call into an indirect jump because // we've had the isCall_ flag overridden. @@ -82,11 +82,11 @@ bool CFWidget::generateIndirect(CodeBuffer &buffer, ia32_condition cond; ia32_instruction orig_instr(memacc, &cond, &loc); - ia32_decode(IA32_FULL_DECODER, (const unsigned char *)insn->ptr(), orig_instr); - const unsigned char *ptr = (const unsigned char *)insn->ptr(); + ia32_decode(IA32_FULL_DECODER, (const unsigned char *) insn.ptr(), orig_instr, (buffer.gen().width() == 8)); + const unsigned char *ptr = (const unsigned char *)insn.ptr(); std::vector raw (ptr, - ptr + insn->size()); + ptr + insn.size()); // Opcode might get modified; // 0xe8 -> 0xe9 (call Jz -> jmp Jz) @@ -110,7 +110,7 @@ bool CFWidget::generateIndirect(CodeBuffer &buffer, } for (int i = loc.num_prefixes + (int) loc.opcode_size; - i < (int) insn->size(); + i < (int) insn.size(); ++i) { if ((i == loc.modrm_position) && fiddle_mod_rm) { @@ -131,7 +131,7 @@ bool CFWidget::generateIndirect(CodeBuffer &buffer, bool CFWidget::generateIndirectCall(CodeBuffer &buffer, Register reg, - Instruction::Ptr insn, + Instruction insn, const RelocBlock *trace, Address /*origAddr*/) { @@ -139,7 +139,7 @@ bool CFWidget::generateIndirectCall(CodeBuffer &buffer, // turned into a push/jump combo already. assert(reg == Null_Register); // Check this to see if it's RIP-relative - NS_x86::instruction ugly_insn(insn->ptr()); + NS_x86::instruction ugly_insn(insn.ptr(), (buffer.gen().width() == 8)); if (ugly_insn.type() & REL_D_DATA) { // This was an IP-relative call that we moved to a new location. assert(origTarget_); @@ -151,7 +151,7 @@ bool CFWidget::generateIndirectCall(CodeBuffer &buffer, buffer.addPatch(newPatch, tracker(trace)); } else { - buffer.addPIC(insn->ptr(), insn->size(), tracker(trace)); + buffer.addPIC(insn.ptr(), insn.size(), tracker(trace)); } return true; @@ -172,13 +172,13 @@ bool CFPatch::apply(codeGen &gen, CodeBuffer *buf) { // Otherwise this is a classic, and therefore easy. int targetLabel = target->label(buf); - relocation_cerr << "\t\t CFPatch::apply, type " << type << ", origAddr " << hex << origAddr_ + relocation_cerr << "\t\t CFPatch::apply, type " << type << ", origAddr " << hex << origAddr_ << ", and label " << dec << targetLabel << endl; - if (orig_insn) { + if (orig_insn.isValid()) { relocation_cerr << "\t\t\t Currently at " << hex << gen.currAddr() << " and targeting predicted " << buf->predictedAddr(targetLabel) << dec << endl; switch(type) { case CFPatch::Jump: { - relocation_cerr << "\t\t\t Generating CFPatch::Jump from " + relocation_cerr << "\t\t\t Generating CFPatch::Jump from " << hex << gen.currAddr() << " to " << buf->predictedAddr(targetLabel) << dec << endl; if (!insnCodeGen::modifyJump(buf->predictedAddr(targetLabel), *ugly_insn, gen)) { cerr << "Failed to modify jump" << endl; @@ -187,7 +187,7 @@ bool CFPatch::apply(codeGen &gen, CodeBuffer *buf) { return true; } case CFPatch::JCC: { - relocation_cerr << "\t\t\t Generating CFPatch::JCC from " + relocation_cerr << "\t\t\t Generating CFPatch::JCC from " << hex << gen.currAddr() << " to " << buf->predictedAddr(targetLabel) << dec << endl; if (!insnCodeGen::modifyJcc(buf->predictedAddr(targetLabel), *ugly_insn, gen)) { cerr << "Failed to modify conditional jump" << endl; @@ -251,7 +251,7 @@ bool CFPatch::isPLT(codeGen &gen) { } bool CFPatch::applyPLT(codeGen &gen, CodeBuffer *) { - // We should try and keep any prefixes that were on the instruction. + // We should try and keep any prefixes that were on the instruction. // However... yeah, right. I'm not that good with x86. So instead // I'm copying the code from emitCallInstruction... diff --git a/dyninstAPI/src/Relocation/Widgets/CFWidget.C b/dyninstAPI/src/Relocation/Widgets/CFWidget.C index c17cc829b4..e1b2e6e1ca 100644 --- a/dyninstAPI/src/Relocation/Widgets/CFWidget.C +++ b/dyninstAPI/src/Relocation/Widgets/CFWidget.C @@ -75,7 +75,7 @@ CFWidget::Ptr CFWidget::create(Widget::Ptr atom) { return ptr; } -CFWidget::CFWidget(InstructionAPI::Instruction::Ptr insn, Address addr) : +CFWidget::CFWidget(InstructionAPI::Instruction insn, Address addr) : isCall_(false), isConditional_(false), isIndirect_(false), @@ -86,11 +86,12 @@ CFWidget::CFWidget(InstructionAPI::Instruction::Ptr insn, Address addr) : { // HACK to be sure things are parsed... - insn->format(); - - for (Instruction::cftConstIter iter = insn->cft_begin(); iter != insn->cft_end(); ++iter) { + insn.format(); + for (Instruction::cftConstIter iter = insn.cft_begin(); iter != insn.cft_end(); ++iter) { if (iter->isCall) isCall_ = true; - if (iter->isIndirect) isIndirect_ = true; + if (iter->isIndirect) { + isIndirect_ = true; + } if (iter->isConditional) isConditional_ = true; } @@ -110,18 +111,15 @@ CFWidget::CFWidget(InstructionAPI::Instruction::Ptr insn, Address addr) : // so that things work. - // TODO: IAPI is recording all PPC64 instructions as PPC32. However, the - // registers they use are still PPC64. This is a pain to fix, and therefore - // I'm working around it here and in Movement-adhoc.C by checking _both_ - // 32- and 64-bit. - //Architecture fixme = insn_->getArch(); - //if (fixme == Arch_ppc32) fixme = Arch_ppc64; + Expression::Ptr thePC(new RegisterAST(MachRegister::getPC(insn_.getArch()))); - Expression::Ptr thePC(new RegisterAST(MachRegister::getPC(insn_->getArch()))); - //Expression::Ptr thePCFixme(new RegisterAST(MachRegister::getPC(fixme))); + Expression::Ptr exp = insn_.getControlFlowTarget(); - Expression::Ptr exp = insn_->getControlFlowTarget(); + if(!exp) { + isIndirect_ = true; + return; + } exp->bind(thePC.get(), Result(u64, addr_)); //exp->bind(thePCFixme.get(), Result(u64, addr_)); @@ -291,7 +289,7 @@ bool CFWidget::generate(const codeGen &templ, if (destMap_.find(Fallthrough) != destMap_.end()) { if (!generateBranch(buffer, destMap_[Fallthrough], - Instruction::Ptr(), + Instruction(), trace, true)) return false; @@ -380,10 +378,10 @@ TargetInt *CFWidget::getDestination(Address dest) const { bool CFWidget::generateBranch(CodeBuffer &buffer, - TargetInt *to, - Instruction::Ptr insn, - const RelocBlock *trace, - bool fallthrough) { + TargetInt *to, + Instruction insn, + const RelocBlock *trace, + bool fallthrough) { assert(to); if (!to->necessary()) return true; @@ -408,9 +406,9 @@ bool CFWidget::generateBranch(CodeBuffer &buffer, } bool CFWidget::generateCall(CodeBuffer &buffer, - TargetInt *to, - const RelocBlock *trace, - Instruction::Ptr insn) { + TargetInt *to, + const RelocBlock *trace, + Instruction insn) { if (!to) { // This can mean an inter-module branch... return true; @@ -424,9 +422,9 @@ bool CFWidget::generateCall(CodeBuffer &buffer, } bool CFWidget::generateConditionalBranch(CodeBuffer &buffer, - TargetInt *to, - const RelocBlock *trace, - Instruction::Ptr insn) { + TargetInt *to, + const RelocBlock *trace, + Instruction insn) { assert(to); CFPatch *newPatch = new CFPatch(CFPatch::JCC, insn, to, trace->func(), addr_); @@ -478,24 +476,30 @@ unsigned CFWidget::size() const ///////////////////////// CFPatch::CFPatch(Type a, - InstructionAPI::Instruction::Ptr b, + Instruction b, TargetInt *c, - const func_instance *d, + const func_instance *d, Address e) : type(a), orig_insn(b), target(c), func(d), origAddr_(e) { - if (b) - ugly_insn = new instruction(b->ptr()); + if (b.isValid()) { + insn_ptr = new unsigned char[b.size()]; + memcpy(insn_ptr, b.ptr(), b.size()); + ugly_insn = new instruction(insn_ptr, (b.getArch() == Dyninst::Arch_x86_64)); + } else ugly_insn = NULL; } CFPatch::~CFPatch() { - if (ugly_insn) delete ugly_insn; + if (ugly_insn) { + delete ugly_insn; + delete[] insn_ptr; + } } unsigned CFPatch::estimate(codeGen &) { - if (orig_insn) { - return orig_insn->size(); + if (orig_insn.isValid()) { + return orig_insn.size(); } return 0; } diff --git a/dyninstAPI/src/Relocation/Widgets/CFWidget.h b/dyninstAPI/src/Relocation/Widgets/CFWidget.h index a2a13bab65..f057d8bb4a 100644 --- a/dyninstAPI/src/Relocation/Widgets/CFWidget.h +++ b/dyninstAPI/src/Relocation/Widgets/CFWidget.h @@ -101,7 +101,7 @@ class CFWidget : public Widget { virtual std::string format() const; virtual Address addr() const { return addr_; } - virtual InstructionAPI::Instruction::Ptr insn() const { return insn_; } + virtual InstructionAPI::Instruction insn() const { return insn_; } void setGap(unsigned gap) { gap_ = gap; } void setOrigTarget(Address a) { origTarget_ = a; } @@ -122,7 +122,7 @@ class CFWidget : public Widget { addr_(a), origTarget_(0) {}; - CFWidget(InstructionAPI::Instruction::Ptr insn, + CFWidget(InstructionAPI::Instruction insn, Address addr); TrackerElement *tracker(const RelocBlock *) const; @@ -139,7 +139,7 @@ class CFWidget : public Widget { unsigned gap_; - InstructionAPI::Instruction::Ptr insn_; + InstructionAPI::Instruction insn_; Address addr_; // If we were a PC-relative indirect store that data here @@ -161,32 +161,32 @@ class CFWidget : public Widget { // The Instruction input allows pulling out ancillary data (e.g., // conditions, prediction, etc. bool generateBranch(CodeBuffer &gens, - TargetInt *to, - InstructionAPI::Instruction::Ptr insn, - const RelocBlock *trace, - bool fallthrough); + TargetInt *to, + InstructionAPI::Instruction insn, + const RelocBlock *trace, + bool fallthrough); bool generateCall(CodeBuffer &gens, - TargetInt *to, - const RelocBlock *trace, - InstructionAPI::Instruction::Ptr insn); + TargetInt *to, + const RelocBlock *trace, + InstructionAPI::Instruction insn); bool generateConditionalBranch(CodeBuffer &gens, - TargetInt *to, - const RelocBlock *trace, - InstructionAPI::Instruction::Ptr insn); + TargetInt *to, + const RelocBlock *trace, + InstructionAPI::Instruction insn); // The Register holds the translated destination (if any) // TODO replace with the register IDs that Bill's building typedef unsigned Register; bool generateIndirect(CodeBuffer &gens, - Register reg, - const RelocBlock *trace, - InstructionAPI::Instruction::Ptr insn); + Register reg, + const RelocBlock *trace, + InstructionAPI::Instruction insn); bool generateIndirectCall(CodeBuffer &gens, - Register reg, - InstructionAPI::Instruction::Ptr insn, - const RelocBlock *trace, - Address origAddr); + Register reg, + InstructionAPI::Instruction insn, + const RelocBlock *trace, + Address origAddr); bool generateAddressTranslator(CodeBuffer &buffer, const codeGen &templ, @@ -204,22 +204,23 @@ struct CFPatch : public Patch { Data } Type; // Data: RIP-relative expression for the destination - CFPatch(Type a, - InstructionAPI::Instruction::Ptr b, - TargetInt *c, - const func_instance *d, - Address e = 0); + CFPatch(Type a, + InstructionAPI::Instruction b, + TargetInt *c, + const func_instance *d, + Address e = 0); virtual bool apply(codeGen &gen, CodeBuffer *buf); virtual unsigned estimate(codeGen &templ); virtual ~CFPatch(); Type type; - InstructionAPI::Instruction::Ptr orig_insn; + InstructionAPI::Instruction orig_insn; TargetInt *target; const func_instance *func; Address origAddr_; arch_insn *ugly_insn; + unsigned char* insn_ptr; #if defined(arch_power) diff --git a/dyninstAPI/src/Relocation/Widgets/InsnWidget.C b/dyninstAPI/src/Relocation/Widgets/InsnWidget.C index da53bc44ce..bf79d53b20 100644 --- a/dyninstAPI/src/Relocation/Widgets/InsnWidget.C +++ b/dyninstAPI/src/Relocation/Widgets/InsnWidget.C @@ -45,7 +45,7 @@ using namespace InstructionAPI; bool InsnWidget::generate(const codeGen &, const RelocBlock *t, CodeBuffer &buffer) { - buffer.addPIC(insn()->ptr(), insn()->size(), tracker(t)); + buffer.addPIC(insn().ptr(), insn().size(), tracker(t)); return true; } @@ -54,22 +54,22 @@ TrackerElement *InsnWidget::tracker(const RelocBlock *t) const { return e; } -InsnWidget::Ptr InsnWidget::create(Instruction::Ptr insn, - Address addr) { +InsnWidget::Ptr InsnWidget::create(Instruction insn, + Address addr) { return Ptr(new InsnWidget(insn, addr)); } -InsnWidget::InsnWidget(Instruction::Ptr insn, Address addr) : +InsnWidget::InsnWidget(Instruction insn, Address addr) : insn_(insn), addr_(addr) {} string InsnWidget::format() const { stringstream ret; // ret << "Insn(" << insn_->format() << ")"; ret << "Insn(" << hex << addr_ - << ": " << insn_->format(addr_) << dec << ")"; + << ": " << insn_.format(addr_) << dec << ")"; return ret.str(); } unsigned InsnWidget::size() const { - return insn_->size(); + return insn_.size(); } diff --git a/dyninstAPI/src/Relocation/Widgets/InsnWidget.h b/dyninstAPI/src/Relocation/Widgets/InsnWidget.h index 26e6877f76..4085af7c45 100644 --- a/dyninstAPI/src/Relocation/Widgets/InsnWidget.h +++ b/dyninstAPI/src/Relocation/Widgets/InsnWidget.h @@ -49,23 +49,23 @@ class InsnWidget : public Widget { TrackerElement *tracker(const RelocBlock *trace) const; - static Ptr create(InstructionAPI::Instruction::Ptr insn, - Address addr); + static Ptr create(InstructionAPI::Instruction insn, + Address addr); virtual ~InsnWidget() {}; virtual std::string format() const; - virtual InstructionAPI::Instruction::Ptr insn() const { return insn_; } + virtual InstructionAPI::Instruction insn() const { return insn_; } virtual Address addr() const { return addr_; } virtual unsigned size() const; private: - InsnWidget(InstructionAPI::Instruction::Ptr insn, - Address addr); + InsnWidget(InstructionAPI::Instruction insn, + Address addr); // Pointer to the instruction we represent - InstructionAPI::Instruction::Ptr insn_; + InstructionAPI::Instruction insn_; // Original address of this instruction Address addr_; diff --git a/dyninstAPI/src/Relocation/Widgets/PCWidget.C b/dyninstAPI/src/Relocation/Widgets/PCWidget.C index 2a57317f26..e54fe8cf2e 100644 --- a/dyninstAPI/src/Relocation/Widgets/PCWidget.C +++ b/dyninstAPI/src/Relocation/Widgets/PCWidget.C @@ -47,7 +47,7 @@ using namespace Relocation; using namespace InstructionAPI; //////////////////////// -PCWidget::Ptr PCWidget::create(Instruction::Ptr insn, +PCWidget::Ptr PCWidget::create(Instruction insn, Address addr, Absloc a, Address thunk) { @@ -80,7 +80,7 @@ bool PCWidget::PCtoReturnAddr(const codeGen &templ, const RelocBlock *t, CodeBuf std::vector newInsn; #if defined(arch_x86) || defined(arch_x86_64) newInsn.push_back(0x68); // push - Address EIP = addr_ + insn_->size(); + Address EIP = addr_ + insn_.size(); unsigned char *tmp = (unsigned char *) &EIP; newInsn.insert(newInsn.end(), tmp, @@ -98,7 +98,7 @@ bool PCWidget::PCtoReturnAddr(const codeGen &templ, const RelocBlock *t, CodeBuf if (!point || (point->type() != instPoint::PreInsn && point->insnAddr() != addr())) { - point = instPoint::preInsn(t->func(), t->block(), addr(), insn(), true); + point = instPoint::preInsn(t->func(), t->block(), addr(), insn_, true); } assert(point); @@ -108,7 +108,7 @@ bool PCWidget::PCtoReturnAddr(const codeGen &templ, const RelocBlock *t, CodeBuf pdvector freeReg; pdvector excludeReg; - Address origRet = addr() + insn()->size(); + Address origRet = addr() + insn_.size(); Register scratch = gen.rs()->getScratchRegister(gen, true); if (scratch == REG_NULL) { stackSize = insnCodeGen::createStackFrame(gen, 1, freeReg, excludeReg); @@ -139,7 +139,7 @@ bool PCWidget::PCtoReg(const codeGen &templ, const RelocBlock *t, CodeBuffer &bu // MOV family, destination of the register encoded by // 'reg', source is an Iv immediate - Address EIP = addr_ + insn_->size(); + Address EIP = addr_ + insn_.size(); unsigned char *tmp = (unsigned char *) &EIP; newInsn.insert(newInsn.end(), tmp, @@ -186,7 +186,7 @@ bool IPPatch::apply(codeGen &gen, CodeBuffer *) { *temp = 0; newInsn += sizeof(uint32_t); SET_PTR(newInsn, gen); - Address offset = addr - gen.currAddr() + insn->size(); + Address offset = addr - gen.currAddr() + insn.size(); REGET_PTR(newInsn, gen); *newInsn = 0x81; newInsn++; diff --git a/dyninstAPI/src/Relocation/Widgets/PCWidget.h b/dyninstAPI/src/Relocation/Widgets/PCWidget.h index 24a5e2e472..da45556b1a 100644 --- a/dyninstAPI/src/Relocation/Widgets/PCWidget.h +++ b/dyninstAPI/src/Relocation/Widgets/PCWidget.h @@ -46,7 +46,7 @@ class PCWidget : public Widget { public: typedef boost::shared_ptr Ptr; - static Ptr create(InstructionAPI::Instruction::Ptr insn, + static Ptr create(InstructionAPI::Instruction insn, Address addr, Absloc a, Address thunk = 0); @@ -56,12 +56,12 @@ class PCWidget : public Widget { virtual ~PCWidget() {}; virtual std::string format() const; - virtual unsigned size() const { return insn_->size(); } + virtual unsigned size() const { return insn_.size(); } virtual Address addr() const { return addr_; } - virtual InstructionAPI::Instruction::Ptr insn() const { return insn_; } + virtual InstructionAPI::Instruction insn() const { return insn_; } private: - PCWidget(InstructionAPI::Instruction::Ptr insn, + PCWidget(InstructionAPI::Instruction insn, Address addr, Absloc &a, Address thunkAddr = 0) : @@ -74,7 +74,7 @@ class PCWidget : public Widget { bool PCtoReturnAddr(const codeGen &templ, const RelocBlock *, CodeBuffer &); bool PCtoReg(const codeGen &templ, const RelocBlock *, CodeBuffer &); - InstructionAPI::Instruction::Ptr insn_; + InstructionAPI::Instruction insn_; Address addr_; Absloc a_; @@ -85,13 +85,13 @@ struct IPPatch : public Patch { typedef enum { Push, Reg } Type; - IPPatch(Type a, Address b, InstructionAPI::Instruction::Ptr c, + IPPatch(Type a, Address b, InstructionAPI::Instruction c, block_instance *d, func_instance *e) : type(a), addr(b), reg((Register)-1), thunk(0), insn(c), block(d), func(e) {}; IPPatch(Type a, Address b, Register c, Address d, - InstructionAPI::Instruction::Ptr e, block_instance *f, func_instance *g) : + InstructionAPI::Instruction e, block_instance *f, func_instance *g) : type(a), addr(b), reg(c), thunk(d), insn(e), block(f), func(g) {}; @@ -104,7 +104,7 @@ struct IPPatch : public Patch { Register reg; Address thunk; // Necessary for live registers - InstructionAPI::Instruction::Ptr insn; + InstructionAPI::Instruction insn; block_instance *block; func_instance *func; }; diff --git a/dyninstAPI/src/Relocation/Widgets/RelDataWidget.C b/dyninstAPI/src/Relocation/Widgets/RelDataWidget.C index 3d6e48c8f2..9afa5e8d85 100644 --- a/dyninstAPI/src/Relocation/Widgets/RelDataWidget.C +++ b/dyninstAPI/src/Relocation/Widgets/RelDataWidget.C @@ -42,9 +42,9 @@ using namespace Dyninst; using namespace Relocation; using namespace InstructionAPI; -RelDataWidget::Ptr RelDataWidget::create(Instruction::Ptr insn, - Address addr, - Address target) { +RelDataWidget::Ptr RelDataWidget::create(Instruction insn, + Address addr, + Address target) { assert(addr); return Ptr(new RelDataWidget(insn, addr, target)); } @@ -63,9 +63,9 @@ bool RelDataWidget::generate(const codeGen &, // Fortunately, we can reuse old code to handle the // translation - // Find the original target of the instruction + // Find the original target of the instruction - relocation_cerr << " Generating a PC-relative data access (" << insn_->format() + relocation_cerr << " Generating a PC-relative data access (" << insn_.format() << "," << std::hex << addr_ <<"," << target_ << std::dec << ")" << endl; @@ -79,13 +79,12 @@ bool RelDataWidget::generate(const codeGen &, string RelDataWidget::format() const { stringstream ret; - ret << "PCRel(" << insn_->format() << ")"; + ret << "PCRel(" << insn_.format() << ")"; return ret.str(); } bool RelDataPatch::apply(codeGen &gen, CodeBuffer *) { - instruction ugly_insn(orig_insn->ptr()); - + instruction ugly_insn(orig_insn.ptr(), (gen.width() == 8)); instPoint *point = gen.point(); if (!point || (point->type() != instPoint::PreInsn && point->insnAddr() != orig)) { point = instPoint::preInsn(func, block, orig, orig_insn, true); @@ -102,5 +101,5 @@ bool RelDataPatch::apply(codeGen &gen, CodeBuffer *) { unsigned RelDataPatch::estimate(codeGen &) { // Underestimate if possible - return orig_insn->size(); + return orig_insn.size(); } diff --git a/dyninstAPI/src/Relocation/Widgets/RelDataWidget.h b/dyninstAPI/src/Relocation/Widgets/RelDataWidget.h index 14e1d8c578..b9aed8a15d 100644 --- a/dyninstAPI/src/Relocation/Widgets/RelDataWidget.h +++ b/dyninstAPI/src/Relocation/Widgets/RelDataWidget.h @@ -47,22 +47,22 @@ class RelDataWidget : public Widget { TrackerElement *tracker(const RelocBlock *t) const; - static Ptr create(InstructionAPI::Instruction::Ptr insn, - Address addr, - Address target); + static Ptr create(InstructionAPI::Instruction insn, + Address addr, + Address target); virtual ~RelDataWidget() {}; virtual std::string format() const; - virtual unsigned size() const { return insn_->size(); } + virtual unsigned size() const { return insn_.size(); } virtual Address addr() const { return addr_; } private: - RelDataWidget(InstructionAPI::Instruction::Ptr insn, - Address addr, - Address target) : insn_(insn), addr_(addr), target_(target) {}; + RelDataWidget(InstructionAPI::Instruction insn, + Address addr, + Address target) : insn_(insn), addr_(addr), target_(target) {}; - InstructionAPI::Instruction::Ptr insn_; + InstructionAPI::Instruction insn_; Address addr_; Address target_; // Read vs. write doesn't matter now but might @@ -71,7 +71,7 @@ class RelDataWidget : public Widget { struct RelDataPatch : public Patch { - RelDataPatch(InstructionAPI::Instruction::Ptr a, Address b, Address o) : + RelDataPatch(InstructionAPI::Instruction a, Address b, Address o) : orig_insn(a), target_addr(b), orig(o) {}; virtual bool apply(codeGen &gen, CodeBuffer *buffer); @@ -81,7 +81,7 @@ struct RelDataPatch : public Patch { void setFunc(func_instance *_func) { func = _func; } void setBlock(block_instance *_block) { block = _block; } - InstructionAPI::Instruction::Ptr orig_insn; + InstructionAPI::Instruction orig_insn; Address target_addr; Address orig; diff --git a/dyninstAPI/src/Relocation/Widgets/StackModWidget.C b/dyninstAPI/src/Relocation/Widgets/StackModWidget.C index 1be15f82f0..fd16110319 100644 --- a/dyninstAPI/src/Relocation/Widgets/StackModWidget.C +++ b/dyninstAPI/src/Relocation/Widgets/StackModWidget.C @@ -41,10 +41,10 @@ using namespace Dyninst; using namespace Relocation; using namespace InstructionAPI; -StackModWidget::Ptr StackModWidget::create(Instruction::Ptr insn, - Address addr, - signed long newDisp, - Architecture arch) { +StackModWidget::Ptr StackModWidget::create(Instruction insn, + Address addr, + signed long newDisp, + Architecture arch) { assert(addr); return Ptr(new StackModWidget(insn, addr, newDisp, arch)); } @@ -57,7 +57,7 @@ TrackerElement *StackModWidget::tracker(const RelocBlock *t) const { bool StackModWidget::generate(const codeGen &, const RelocBlock *t, CodeBuffer &buffer) { - relocation_cerr << " Generating a stackframe-sensitive memory access (" << insn_->format() + relocation_cerr << " Generating a stackframe-sensitive memory access (" << insn_.format() << "," << std::hex << addr_ <<", newDisp " << newDisp_ << std::dec << ")" << endl; @@ -69,13 +69,13 @@ bool StackModWidget::generate(const codeGen &, string StackModWidget::format() const { stringstream ret; - ret << "MemRel(" << insn_->format() << ")"; + ret << "MemRel(" << insn_.format() << ")"; return ret.str(); } bool StackModPatch::apply(codeGen &gen, CodeBuffer *) { #if defined(cap_stack_mods) - instruction ugly_insn(orig_insn->ptr()); + instruction ugly_insn(orig_insn.ptr(), (gen.width() == 8)); if (gen.modifiedStackFrame()) { relocation_cerr << " Calling modifyDisp" << endl; if (!insnCodeGen::modifyDisp(newDisp, ugly_insn, gen, arch, addr)) @@ -99,5 +99,5 @@ bool StackModPatch::apply(codeGen &gen, CodeBuffer *) { unsigned StackModPatch::estimate(codeGen &) { // Underestimate if possible - return orig_insn->size(); + return orig_insn.size(); } diff --git a/dyninstAPI/src/Relocation/Widgets/StackModWidget.h b/dyninstAPI/src/Relocation/Widgets/StackModWidget.h index 0571242552..171a6c546d 100644 --- a/dyninstAPI/src/Relocation/Widgets/StackModWidget.h +++ b/dyninstAPI/src/Relocation/Widgets/StackModWidget.h @@ -45,35 +45,35 @@ class StackModWidget : public Widget { TrackerElement *tracker(const RelocBlock *t) const; - static Ptr create(InstructionAPI::Instruction::Ptr insn, - Address addr, - signed long newDisp, - Architecture arch); + static Ptr create(InstructionAPI::Instruction insn, + Address addr, + signed long newDisp, + Architecture arch); virtual ~StackModWidget() {}; virtual std::string format() const; - virtual unsigned size() const { return insn_->size(); } + virtual unsigned size() const { return insn_.size(); } virtual Address addr() const { return addr_; } private: - StackModWidget(InstructionAPI::Instruction::Ptr insn, - Address addr, - signed long newDisp, - Architecture arch) : + StackModWidget(InstructionAPI::Instruction insn, + Address addr, + signed long newDisp, + Architecture arch) : insn_(insn), addr_(addr), newDisp_(newDisp), arch_(arch) {}; - InstructionAPI::Instruction::Ptr insn_; + InstructionAPI::Instruction insn_; Address addr_; signed long newDisp_; Architecture arch_; }; struct StackModPatch : public Patch { - StackModPatch(InstructionAPI::Instruction::Ptr a, signed long d, Architecture ar, Address ad) : + StackModPatch(InstructionAPI::Instruction a, signed long d, Architecture ar, Address ad) : orig_insn(a), newDisp(d), arch(ar), @@ -83,7 +83,7 @@ struct StackModPatch : public Patch { virtual unsigned estimate(codeGen &templ); virtual ~StackModPatch() {}; - InstructionAPI::Instruction::Ptr orig_insn; + InstructionAPI::Instruction orig_insn; signed long newDisp; Architecture arch; Address addr; diff --git a/dyninstAPI/src/Relocation/Widgets/Widget.h b/dyninstAPI/src/Relocation/Widgets/Widget.h index 1c36756195..945a21c06d 100644 --- a/dyninstAPI/src/Relocation/Widgets/Widget.h +++ b/dyninstAPI/src/Relocation/Widgets/Widget.h @@ -66,8 +66,8 @@ class Widget { // A default value to make sure things don't go wonky. virtual Address addr() const { return 0; } virtual unsigned size() const { return 0; } - virtual InstructionAPI::Instruction::Ptr insn() const { - return InstructionAPI::Instruction::Ptr(); + virtual InstructionAPI::Instruction insn() const { + return InstructionAPI::Instruction(); } // Make binary from the thing diff --git a/dyninstAPI/src/StackMod/StackAccess.C b/dyninstAPI/src/StackMod/StackAccess.C index 76acc3ab4a..3f7b2a7cee 100644 --- a/dyninstAPI/src/StackMod/StackAccess.C +++ b/dyninstAPI/src/StackMod/StackAccess.C @@ -97,10 +97,10 @@ bool isDebugType(StackAccess::StackAccessType t) t==StackAccess::DEBUGINFO_PARAM); } -int getAccessSize(InstructionAPI::Instruction::Ptr insn) +int getAccessSize(InstructionAPI::Instruction insn) { std::vector operands; - insn->getOperands(operands); + insn.getOperands(operands); int accessSize = 0; for (unsigned i = 0; i < operands.size(); i++) { InstructionAPI::Expression::Ptr value = operands[i].getValue(); @@ -241,28 +241,28 @@ bool defsSameHeights(const StackAnalysis::DefHeightSet &dhSet) { } -bool getAccesses(ParseAPI::Function* func, - ParseAPI::Block* block, - Address addr, - InstructionAPI::Instruction::Ptr insn, - Accesses* accesses, - std::set
&defPointsToMod, - bool analyzeDefinition) +bool getAccesses(ParseAPI::Function *func, + ParseAPI::Block *block, + Address addr, + InstructionAPI::Instruction insn, + Accesses *accesses, + std::set
&defPointsToMod, + bool analyzeDefinition) { stackmods_printf("\t\t getAccesses %s, 0x%lx @ 0x%lx: %s\n", - func->name().c_str(), block->start(), addr, insn->format().c_str()); + func->name().c_str(), block->start(), addr, insn.format().c_str()); - Architecture arch = insn->getArch(); + Architecture arch = insn.getArch(); std::set readRegs; - insn->getReadSet(readRegs); + insn.getReadSet(readRegs); StackAnalysis sa(func); std::vector > heights; std::vector > defHeights; sa.findDefinedHeights(block, addr, heights); sa.findDefHeightPairs(block, addr, defHeights); - if (insn->getOperation().getID() == e_ret_far || - insn->getOperation().getID() == e_ret_near) { + if (insn.getOperation().getID() == e_ret_far || + insn.getOperation().getID() == e_ret_near) { return true; } @@ -282,7 +282,7 @@ bool getAccesses(ParseAPI::Function* func, // If this instruction is a call, check if any stack pointers are possibly // being passed as parameters. If so, we don't know what the callee will // access through that pointer and need to return false. - if (insn->getCategory() == InstructionAPI::c_CallInsn) { + if (insn.getCategory() == InstructionAPI::c_CallInsn) { // Check parameter registers for stack pointers ABI *abi = ABI::getABI(word_size); const bitArray &callParamRegs = abi->getParameterRegisters(); @@ -448,9 +448,9 @@ bool getAccesses(ParseAPI::Function* func, // Since StackAnalysis tops loads from unresolved locations, we have to // fail if we write out stack heights to unresolved locations. We also fail // if an accessed location has a stack height base and an unknown offset. - if (insn->writesMemory()) { + if (insn.writesMemory()) { std::set writeOperands; - insn->getMemoryWriteOperands(writeOperands); + insn.getMemoryWriteOperands(writeOperands); assert(writeOperands.size() == 1); detectToppedLoc dtl(defHeights); @@ -478,9 +478,9 @@ bool getAccesses(ParseAPI::Function* func, "location\n"); return false; } - } else if (insn->readsMemory()) { + } else if (insn.readsMemory()) { std::set readOperands; - insn->getMemoryReadOperands(readOperands); + insn.getMemoryReadOperands(readOperands); for (auto rIter = readOperands.begin(); rIter != readOperands.end(); rIter++) { detectToppedLoc dtl(defHeights); @@ -511,7 +511,7 @@ using namespace InstructionAPI; class zeroAllGPRegisters : public InstructionAPI::Visitor { public: - zeroAllGPRegisters(Address ip, ParseAPI::Function* f, ParseAPI::Block* b, InstructionAPI::Instruction::Ptr i, bool z = false) : + zeroAllGPRegisters(Address ip, ParseAPI::Function* f, ParseAPI::Block* b, InstructionAPI::Instruction i, bool z = false) : defined(true), m_ip(ip), func(f), block(b), insn(i), zero(z) { if (func) { StackAnalysis tmp(func); @@ -525,7 +525,7 @@ class zeroAllGPRegisters : public InstructionAPI::Visitor Address m_ip; ParseAPI::Function* func; ParseAPI::Block* block; - InstructionAPI::Instruction::Ptr insn; + InstructionAPI::Instruction insn; StackAnalysis sa; bool zero; long getResult() { @@ -593,25 +593,25 @@ class zeroAllGPRegisters : public InstructionAPI::Visitor }; -bool getMemoryOffset(ParseAPI::Function* func, - ParseAPI::Block* block, - InstructionAPI::InstructionPtr insn, - Address addr, - const MachRegister ®, - const StackAnalysis::Height &height, - const StackAnalysis::Definition &def, - StackAccess*& ret, - Architecture arch, - bool analyzeDefinition) +bool getMemoryOffset(ParseAPI::Function *func, + ParseAPI::Block *block, + Instruction insn, + Address addr, + const MachRegister ®, + const StackAnalysis::Height &height, + const StackAnalysis::Definition &def, + StackAccess *&ret, + Architecture arch, + bool analyzeDefinition) { stackmods_printf("\t\t\t getMemoryOffset for %s; checking reg %s = %s\n", - insn->format().c_str(), reg.name().c_str(), height.format().c_str()); + insn.format().c_str(), reg.name().c_str(), height.format().c_str()); InstructionAPI::RegisterAST* regAST = new InstructionAPI::RegisterAST(reg); InstructionAPI::RegisterAST::Ptr regASTPtr = InstructionAPI::RegisterAST::Ptr(regAST); std::vector operands; - insn->getOperands(operands); + insn.getOperands(operands); signed long disp = 0; // Stack height of access signed long offset = 0; // Offset from the base register used in the access @@ -621,11 +621,11 @@ bool getMemoryOffset(ParseAPI::Function* func, StackAccess::StackAccessType type = StackAccess::UNKNOWN; if (analyzeDefinition) { type = StackAccess::DEFINITION; - } else if (insn->readsMemory() && insn->writesMemory()) { + } else if (insn.readsMemory() && insn.writesMemory()) { type = StackAccess::READWRITE; - } else if (insn->readsMemory()) { + } else if (insn.readsMemory()) { type = StackAccess::READ; - } else if (insn->writesMemory()) { + } else if (insn.writesMemory()) { type = StackAccess::WRITE; } @@ -636,7 +636,7 @@ bool getMemoryOffset(ParseAPI::Function* func, for (unsigned i = 0; i < operands.size(); i++) { stackmods_printf("\t\t\t\t operand[%d] = %s\n", i, - operands[i].getValue()->format(insn->getFormatter()).c_str()); + operands[i].getValue()->format(insn.getArch()).c_str()); // Set match if reg is read or written bool match = false; @@ -675,7 +675,7 @@ bool getMemoryOffset(ParseAPI::Function* func, // Won't find an offset for a registerAST. However, we do want to // record a push (e.g., callee-saved registers). if (dynamic_cast(val.get()) && - insn->getOperation().getID() != e_push) { + insn.getOperation().getID() != e_push) { continue; } @@ -744,7 +744,7 @@ bool getMemoryOffset(ParseAPI::Function* func, // Stackanalysis is reporting the heights at the start of the // instruction, not the end; for push, we want to record the final // state, which is where the value is actually stored - if (insn->getOperation().getID() == e_push) { + if (insn.getOperation().getID() == e_push) { long width; if (arch == Arch_x86) width = 4; else width = 8; diff --git a/dyninstAPI/src/StackMod/StackAccess.h b/dyninstAPI/src/StackMod/StackAccess.h index f7c0839e7b..0753f2d1da 100644 --- a/dyninstAPI/src/StackMod/StackAccess.h +++ b/dyninstAPI/src/StackMod/StackAccess.h @@ -97,26 +97,26 @@ typedef std::map > Accesses; bool isDebugType(StackAccess::StackAccessType t); -int getAccessSize(InstructionAPI::Instruction::Ptr insn); - -bool getAccesses(ParseAPI::Function* func, - ParseAPI::Block* block, - Address addr, - InstructionAPI::Instruction::Ptr insn, - Accesses* accesses, - std::set
&defPointsToMod, - bool analyzeDefinition = false); - -bool getMemoryOffset(ParseAPI::Function* func, - ParseAPI::Block* block, - InstructionAPI::Instruction::Ptr insn, - Address addr, - const MachRegister ®, - const StackAnalysis::Height &height, - const StackAnalysis::Definition &def, - StackAccess*& ret, - Architecture arch, - bool analyzeDefintion = false); +int getAccessSize(InstructionAPI::Instruction insn); + +bool getAccesses(ParseAPI::Function *func, + ParseAPI::Block *block, + Address addr, + InstructionAPI::Instruction insn, + Accesses *accesses, + std::set
&defPointsToMod, + bool analyzeDefinition = false); + +bool getMemoryOffset(ParseAPI::Function *func, + ParseAPI::Block *block, + InstructionAPI::Instruction insn, + Address addr, + const MachRegister ®, + const StackAnalysis::Height &height, + const StackAnalysis::Definition &def, + StackAccess *&ret, + Architecture arch, + bool analyzeDefintion = false); #endif diff --git a/dyninstAPI/src/StackMod/StackModChecker.C b/dyninstAPI/src/StackMod/StackModChecker.C index e416b9453b..b75a20673e 100644 --- a/dyninstAPI/src/StackMod/StackModChecker.C +++ b/dyninstAPI/src/StackMod/StackModChecker.C @@ -894,7 +894,7 @@ void StackModChecker::processBlock(StackAnalysis& sa, ParseAPI::Block* block) heightVec->push_back(sa.findSP(block, block->start())); for (auto iter = insns.begin(); iter != insns.end(); ++iter) { Offset off = (*iter).first; - InstructionAPI::Instruction::Ptr insn = (*iter).second; + InstructionAPI::Instruction insn = (*iter).second; StackAnalysis::Height curHeight = sa.findSP(block, off); if (curHeight != heightVec->back()) { heightVec->push_back(curHeight); @@ -1292,7 +1292,7 @@ bool StackModChecker::areModificationsSafe() block->getInsns(insns); for (auto iIter = insns.begin(); iIter != insns.end(); ++iIter) { Offset off = (*iIter).first; - InstructionAPI::InstructionPtr insn = (*iIter).second; + InstructionAPI::Instruction insn = (*iIter).second; Accesses* accesses = func->getAccesses(off); for (auto aIter = accesses->begin(); aIter != accesses->end(); ++aIter) { @@ -1317,7 +1317,7 @@ bool StackModChecker::areModificationsSafe() * - removing any part of the accessed range, or * - moving a portion (but not the whole) accessed range. */ -bool StackModChecker::isAccessSafe(InstructionAPI::InstructionPtr insn, StackAccess* access) +bool StackModChecker::isAccessSafe(InstructionAPI::Instruction insn, StackAccess *access) { OffsetVector* offVec = func->getOffsetVector(); TMap* tMap = func->getTMap(); diff --git a/dyninstAPI/src/StackMod/StackModChecker.h b/dyninstAPI/src/StackMod/StackModChecker.h index 2c1ed2dd5b..5058a93fa9 100644 --- a/dyninstAPI/src/StackMod/StackModChecker.h +++ b/dyninstAPI/src/StackMod/StackModChecker.h @@ -80,7 +80,7 @@ class StackModChecker std::vector* checkPoints); bool areModificationsSafe(); - bool isAccessSafe(Dyninst::InstructionAPI::Instruction::Ptr insn, StackAccess* access); + bool isAccessSafe(InstructionAPI::Instruction insn, StackAccess *access); bool _unsafeStackGrowth; diff --git a/dyninstAPI/src/addressSpace.C b/dyninstAPI/src/addressSpace.C index 2f72dc3e18..bf0d69a36e 100644 --- a/dyninstAPI/src/addressSpace.C +++ b/dyninstAPI/src/addressSpace.C @@ -1007,9 +1007,9 @@ func_instance *AddressSpace::findJumpTargetFuncByAddr(Address addr) { InstructionDecoder decoder((const unsigned char*)getPtrToInstruction(addr), InstructionDecoder::maxInstructionLength, getArch()); - Instruction::Ptr curInsn = decoder.decode(); + Instruction curInsn = decoder.decode(); - Expression::Ptr target = curInsn->getControlFlowTarget(); + Expression::Ptr target = curInsn.getControlFlowTarget(); RegisterAST thePC = RegisterAST::makePC(getArch()); target->bind(&thePC, Result(u32, addr)); Result cft = target->eval(); @@ -1797,15 +1797,15 @@ bool AddressSpace::relocateInt(FuncSet::const_iterator begin, FuncSet::const_ite Address base = baseAddr; InstructionDecoder deco (cm->ptr(),cm->size(),getArch()); - Instruction::Ptr insn = deco.decode(); - while(insn) { + Instruction insn = deco.decode(); + while(insn.isValid()) { std::stringstream rawInsn; - unsigned idx = insn->size(); - while(idx--) rawInsn << hex << setfill('0') << setw(2) << (unsigned int) insn->rawByte(idx); + unsigned idx = insn.size(); + while(idx--) rawInsn << hex << ((unsigned int) insn.rawByte(idx)) / 16 << ((unsigned int) insn.rawByte(idx)) % 16 ; cerr << "\t" << hex << base << ": " << rawInsn.str() << " " - << insn->format(base) << dec << endl; - base += insn->size(); + << insn.format(base) << dec << endl; + base += insn.size(); insn = deco.decode(); } cerr << dec; diff --git a/dyninstAPI/src/addressSpace.h b/dyninstAPI/src/addressSpace.h index 5c63ce980f..d4823f1341 100644 --- a/dyninstAPI/src/addressSpace.h +++ b/dyninstAPI/src/addressSpace.h @@ -340,7 +340,7 @@ class AddressSpace : public InstructionSource { // And this.... typedef boost::shared_ptr InstructionPtr; - bool getDynamicCallSiteArgs(InstructionPtr insn, + bool getDynamicCallSiteArgs(InstructionAPI::Instruction insn, Address addr, pdvector &args); diff --git a/dyninstAPI/src/ast.C b/dyninstAPI/src/ast.C index 4e15f051c4..69528aedb0 100644 --- a/dyninstAPI/src/ast.C +++ b/dyninstAPI/src/ast.C @@ -252,15 +252,6 @@ AstNodePtr AstNode::miniTrampNode(AstNodePtr tramp) { return AstNodePtr(new AstMiniTrampNode(tramp)); } -AstNodePtr AstNode::insnNode(BPatch_instruction *insn) { - // Figure out what kind of instruction we've got... - if (dynamic_cast(insn)) { - return AstNodePtr(new AstInsnMemoryNode(insn->insn()->insn(), (Address) insn->getAddress())); - } - - return AstNodePtr(new AstInsnNode(insn->insn()->insn(), (Address) insn->getAddress())); -} - AstNodePtr AstNode::originalAddrNode() { if (originalAddrNode_ == NULL) { originalAddrNode_ = AstNodePtr(new AstOriginalAddrNode()); @@ -475,12 +466,6 @@ AstVariableNode::AstVariableNode(vector&ast_wrappers, vector(this)) fprintf(stderr, "callNode\n"); if (dynamic_cast(this)) fprintf(stderr, "seqNode\n"); if (dynamic_cast(this)) fprintf(stderr, "varNode\n"); - if (dynamic_cast(this)) fprintf(stderr, "insnNode\n"); if (dynamic_cast(this)) fprintf(stderr, "miniTrampNode\n"); if (dynamic_cast(this)) fprintf(stderr, "memoryNode\n"); assert(0); @@ -2192,86 +2176,6 @@ bool AstVariableNode::generateCode_phase2(codeGen &gen, bool noCost, return ast_wrappers_[index]->generateCode_phase2(gen, noCost, addr, retReg); } -bool AstInsnNode::generateCode_phase2(codeGen &gen, bool, - Address &, Register &) { - assert(insn_); - - insnCodeGen::generate(gen,*insn_,gen.addrSpace(),origAddr_,gen.currAddr()); - decUseCount(gen); - - return true; -} - -bool AstInsnBranchNode::generateCode_phase2(codeGen &gen, bool noCost, - Address &, Register & ) { - assert(insn_); - - // Generate side 2 and get the result... - Address targetAddr = ADDR_NULL; - Register targetReg = REG_NULL; - if (target_) { - // TODO: address vs. register... - if (!target_->generateCode_phase2(gen, noCost, targetAddr, targetReg)) ERROR_RETURN; - } - // We'd now generate a fixed or register branch. But we don't. So there. - assert(0 && "Unimplemented"); - insnCodeGen::generate(gen,*insn_,gen.addrSpace(), origAddr_, gen.currAddr(), 0, 0); - decUseCount(gen); - - return true; -} - -bool AstInsnMemoryNode::generateCode_phase2(codeGen &gen, bool noCost, - Address &, Register &) { - Register loadReg = REG_NULL; - Register storeReg = REG_NULL; - Address loadAddr = ADDR_NULL; - Address storeAddr = ADDR_NULL; - assert(insn_); - - // Step 1: save machine-specific state (AKA flags) and mark registers used in - // the instruction itself as off-limits. - - gen.rs()->saveVolatileRegisters(gen); - pdvector usedRegisters; - if (insn_->getUsedRegs(usedRegisters)) { - for (unsigned i = 0; i < usedRegisters.size(); i++) { - gen.rs()->markReadOnly(usedRegisters[i]); - } - } - else { - // We don't know who to avoid... return false? - fprintf(stderr, "WARNING: unknown \"off limits\" register set, returning false from memory modification\n"); - return false; - } - - // Step 2: generate code (this may spill registers) - - if (load_) - if (!load_->generateCode_phase2(gen, noCost, loadAddr, loadReg)) ERROR_RETURN; - - if (store_) - if (!store_->generateCode_phase2(gen, noCost, storeAddr, storeReg)) ERROR_RETURN; - - // Step 3: restore flags (before the original instruction) - - gen.rs()->restoreVolatileRegisters(gen); - - // Step 4: generate the memory instruction - if (!insnCodeGen::generateMem(gen,*insn_,origAddr_, gen.currAddr(), loadReg, storeReg)) { - fprintf(stderr, "ERROR: generateMem call failed\n"); - return false; - } - - // Step 5: restore any registers that were st0mped. - - - gen.rs()->restoreAllRegisters(gen, true); - - decUseCount(gen); - return true; -} - bool AstOriginalAddrNode::generateCode_phase2(codeGen &gen, bool noCost, Address &, @@ -2315,8 +2219,8 @@ bool AstDynamicTargetNode::generateCode_phase2(codeGen &gen, gen.point()->type() != instPoint::PreInsn) return false; - InstructionAPI::Instruction::Ptr insn = gen.point()->block()->getInsn(gen.point()->block()->last()); - if (insn->getCategory() == c_ReturnInsn) { + InstructionAPI::Instruction insn = gen.point()->block()->getInsn(gen.point()->block()->last()); + if (insn.getCategory() == c_ReturnInsn) { // if this is a return instruction our AST reads the top stack value if (retReg == REG_NULL) { retReg = allocateAndKeep(gen, noCost); @@ -3304,15 +3208,6 @@ void AstVariableNode::setVariableAST(codeGen &gen){ assert(found); } -void AstInsnBranchNode::setVariableAST(codeGen &g){ - if(target_) target_->setVariableAST(g); -} - -void AstInsnMemoryNode::setVariableAST(codeGen &g){ - if(load_) load_->setVariableAST(g); - if(store_) store_->setVariableAST(g); -} - void AstMiniTrampNode::setVariableAST(codeGen &g){ if(ast_) ast_->setVariableAST(g); } @@ -3352,12 +3247,6 @@ bool AstVariableNode::containsFuncCall() const return ast_wrappers_[index]->containsFuncCall(); } -bool AstInsnMemoryNode::containsFuncCall() const { - if (load_ && load_->containsFuncCall()) return true; - if (store_ && store_->containsFuncCall()) return true; - return false; -} - bool AstNullNode::containsFuncCall() const { return false; @@ -3388,11 +3277,6 @@ bool AstMemoryNode::containsFuncCall() const return false; } -bool AstInsnNode::containsFuncCall() const -{ - return false; -} - bool AstOriginalAddrNode::containsFuncCall() const { return false; @@ -3459,12 +3343,6 @@ bool AstVariableNode::usesAppRegister() const return ast_wrappers_[index]->usesAppRegister(); } -bool AstInsnMemoryNode::usesAppRegister() const { - if (load_ && load_->usesAppRegister()) return true; - if (store_ && store_->usesAppRegister()) return true; - return false; -} - bool AstNullNode::usesAppRegister() const { return false; @@ -3510,10 +3388,6 @@ bool AstMemoryNode::usesAppRegister() const return true; } -bool AstInsnNode::usesAppRegister() const -{ - return true; -} bool AstScrambleRegistersNode::usesAppRegister() const { return true; diff --git a/dyninstAPI/src/ast.h b/dyninstAPI/src/ast.h index b2bdf96d57..3011515c4e 100644 --- a/dyninstAPI/src/ast.h +++ b/dyninstAPI/src/ast.h @@ -236,9 +236,7 @@ class AstNode : public Dyninst::PatchAPI::Snippet { static AstNodePtr funcCallNode(Address addr, pdvector &args); // For when you absolutely need // to jump somewhere. - static AstNodePtr insnNode(BPatch_instruction *insn); - - // Acquire the thread index value - a 0...n labelling of threads. + // Acquire the thread index value - a 0...n labelling of threads. static AstNodePtr threadIndexNode(); static AstNodePtr scrambleRegistersNode(); @@ -786,76 +784,6 @@ class AstVariableNode : public AstNode { }; -class AstInsnNode : public AstNode { - public: - - AstInsnNode(instruction *insn, Address addr); - - - // Template methods... - virtual bool overrideBranchTarget(AstNodePtr) { return false; } - virtual bool overrideLoadAddr(AstNodePtr) { return false; } - virtual bool overrideStoreAddr(AstNodePtr) { return false; } - - bool canBeKept() const { return false; } - virtual bool containsFuncCall() const; - - virtual bool usesAppRegister() const; - - protected: - virtual bool generateCode_phase2(codeGen &gen, - bool noCost, - Address &retAddr, - Register &retReg); - - AstInsnNode() {}; - instruction *insn_; - Address origAddr_; // The instruction class should wrap an address, but _wow_ - // reengineering -}; - -class AstInsnBranchNode : public AstInsnNode { - public: - AstInsnBranchNode(instruction *insn, Address addr) : AstInsnNode(insn, addr), target_() {}; - - - virtual bool overrideBranchTarget(AstNodePtr t) { target_ = t; return true; } - virtual bool containsFuncCall() const; - virtual bool usesAppRegister() const; - - - virtual void setVariableAST(codeGen &gen); - - protected: - virtual bool generateCode_phase2(codeGen &gen, - bool noCost, - Address &retAddr, - Register &retReg); - - AstNodePtr target_; -}; - -class AstInsnMemoryNode : public AstInsnNode { - public: - AstInsnMemoryNode(instruction *insn, Address addr) : AstInsnNode(insn, addr), load_(), store_() {}; - - virtual bool overrideLoadAddr(AstNodePtr l) { load_ = l; return true; } - virtual bool overrideStoreAddr(AstNodePtr s) { store_ = s; return true; } - virtual bool containsFuncCall() const; - virtual bool usesAppRegister() const; - - virtual void setVariableAST(codeGen &gen); - - protected: - virtual bool generateCode_phase2(codeGen &gen, - bool noCost, - Address &retAddr, - Register &retReg); - - AstNodePtr load_; - AstNodePtr store_; -}; - class AstMiniTrampNode : public AstNode { public: diff --git a/dyninstAPI/src/block.h b/dyninstAPI/src/block.h index 96af66b4e9..dd4e26f568 100644 --- a/dyninstAPI/src/block.h +++ b/dyninstAPI/src/block.h @@ -115,7 +115,6 @@ class block_instance : public Dyninst::PatchAPI::PatchBlock { std::string calleeName(); bool _ignorePowerPreamble; int id() const; - void GetBlockInstructions(std::vector & ret){llb()->GetBlockInstructions(ret); return;}; // Functions to avoid // These are convinence wrappers for really expensive diff --git a/dyninstAPI/src/codegen-x86.C b/dyninstAPI/src/codegen-x86.C index c35229bc48..eb88444606 100644 --- a/dyninstAPI/src/codegen-x86.C +++ b/dyninstAPI/src/codegen-x86.C @@ -203,15 +203,16 @@ static const unsigned char trapRep[8] = {0xCC}; void insnCodeGen::generateIllegal(codeGen &gen) { - instruction insn; - insn.setInstruction(illegalRep); - generate(gen,insn); + GET_PTR(insn, gen); + *insn++ = 0x0f; + *insn++ = 0x0b; + SET_PTR(insn, gen); } void insnCodeGen::generateTrap(codeGen &gen) { - instruction insn; - insn.setInstruction(trapRep); - generate(gen,insn); + GET_PTR(insn, gen); + *insn++ = 0xCC; + SET_PTR(insn, gen); } /* @@ -799,7 +800,6 @@ bool insnCodeGen::generate(codeGen &, #define SIB_SET_REG(x, y) ((x) |= ((y) & 7)) #define SIB_SET_INDEX(x, y) ((x) |= (((y) & 7) << 3)) -#define SIB_SET_SS(x, y) ((x) | (((y) & 3) << 6)) /** * The comments and naming schemes in this function assume some familiarity with @@ -852,8 +852,7 @@ bool insnCodeGen::generateMem(codeGen &gen, class ia32_locations loc; ia32_instruction orig_instr(memacc, &cond, &loc); - ia32_decode(IA32_DECODE_MEMACCESS | IA32_DECODE_CONDITION, - insn_ptr, orig_instr); + ia32_decode(IA32_DECODE_MEMACCESS | IA32_DECODE_CONDITION, insn_ptr, orig_instr, (gen.width() == 8)); if (orig_instr.getPrefix()->getPrefix(1) != 0) { //The instruction accesses memory via segment registers. Disallow. @@ -1193,7 +1192,7 @@ bool insnCodeGen::modifyData(Address targetAddr, instruction &insn, codeGen &gen * This information is generated during ia32_decode. To make this faster * We are only going to do the prefix and opcode decodings */ - if(!ia32_decode_prefixes(origInsn, instruct)) + if(!ia32_decode_prefixes(origInsn, instruct, gen.width() == 8)) assert(!"Couldn't decode prefix of already known instruction!\n"); /* get the prefix count */ @@ -1201,7 +1200,7 @@ bool insnCodeGen::modifyData(Address targetAddr, instruction &insn, codeGen &gen origInsn += pref_count; /* Decode the opcode */ - if(ia32_decode_opcode(0, origInsn, instruct, NULL) < 0) + if(ia32_decode_opcode(0, origInsn, instruct, NULL, (gen.width() == 8)) < 0) assert(!"Couldn't decode opcode of already known instruction!\n"); /* Calculate the amount of opcode bytes */ @@ -1295,10 +1294,10 @@ bool insnCodeGen::modifyDisp(signed long newDisp, instruction &insn, codeGen &ge unsigned newInsnSz = 0; InstructionAPI::InstructionDecoder d2(origInsn, insnSz, arch); - InstructionAPI::Instruction::Ptr origInsnPtr = d2.decode(); + InstructionAPI::Instruction origInsnPtr = d2.decode(); bool modifyDefinition = false; - if (!origInsnPtr->readsMemory() && !origInsnPtr->writesMemory()) { + if (!origInsnPtr.readsMemory() && !origInsnPtr.writesMemory()) { // This instruction should be a definition modifyDefinition = true; } @@ -1327,7 +1326,7 @@ bool insnCodeGen::modifyDisp(signed long newDisp, instruction &insn, codeGen &ge * This information is generated during ia32_decode. To make this faster * We are only going to do the prefix and opcode decodings */ - if(!ia32_decode_prefixes(origInsn, instruct)) + if(!ia32_decode_prefixes(origInsn, instruct, false)) assert(!"Couldn't decode prefix of already known instruction!\n"); /* get the prefix count */ @@ -1339,7 +1338,7 @@ bool insnCodeGen::modifyDisp(signed long newDisp, instruction &insn, codeGen &ge origInsn += pref_count; /* Decode the opcode */ - if(ia32_decode_opcode(0, origInsn, instruct, NULL) < 0) + if(ia32_decode_opcode(0, origInsn, instruct, NULL, (gen.width() == 8)) < 0) assert(!"Couldn't decode opcode of already known instruction!\n"); /* Calculate the amount of opcode bytes */ @@ -1479,7 +1478,7 @@ bool insnCodeGen::modifyDisp(signed long newDisp, instruction &insn, codeGen &ge /******************************** done ************************************/ InstructionAPI::InstructionDecoder d(newInsnStart, newInsnSz, arch); - InstructionAPI::Instruction::Ptr newInsnPtr = d.decode(); + InstructionAPI::Instruction i = d.decode(); if ((insnSz + expectedDifference) != newInsnSz) { relocation_cerr << "\t\tERROR: Old Size: " << std::dec << insnSz << " New size: " << newInsnSz << " Expected size: " << (insnSz + expectedDifference) << std::endl; @@ -1488,7 +1487,7 @@ bool insnCodeGen::modifyDisp(signed long newDisp, instruction &insn, codeGen &ge // Validate StackAccess* newAccess = NULL; - getMemoryOffset(NULL, NULL, newInsnPtr, addr, MachRegister(), + getMemoryOffset(NULL, NULL, i, addr, MachRegister(), StackAnalysis::Height(0), StackAnalysis::Definition(), newAccess, arch, modifyDefinition); if (!newAccess) { diff --git a/dyninstAPI/src/codegen.C b/dyninstAPI/src/codegen.C index 35f8d36710..0dde7b2bae 100644 --- a/dyninstAPI/src/codegen.C +++ b/dyninstAPI/src/codegen.C @@ -783,22 +783,21 @@ void codeGen::registerDefensivePad(block_instance *callBlock, Address padStart, using namespace InstructionAPI; std::string codeGen::format() const { - if (!aSpace_) return ""; - - stringstream ret; - - Address base = (addr_ != (Address)-1) ? addr_ : 0; - InstructionDecoder deco (buffer_,used(),aSpace_->getArch()); - Instruction::Ptr insn = deco.decode(); - ret << hex; - while(insn) { - ret << "\t" << base << ": " - << "\t" << *((const unsigned *)insn->ptr()) - << "\t" << insn->format(base) << endl; - base += insn->size(); - insn = deco.decode(); - } - ret << dec; - return ret.str(); + if (!aSpace_) return ""; + + stringstream ret; + + Address base = (addr_ != (Address)-1) ? addr_ : 0; + InstructionDecoder deco + (buffer_,used(),aSpace_->getArch()); + Instruction insn = deco.decode(); + ret << hex; + while(insn.isValid()) { + ret << "\t" << base << ": " << insn.format(base) << " / " << *((const unsigned *)insn.ptr()) << endl; + base += insn.size(); + insn = deco.decode(); + } + ret << dec; + return ret.str(); }; diff --git a/dyninstAPI/src/frameChecker.C b/dyninstAPI/src/frameChecker.C index b0625133b0..488f428560 100644 --- a/dyninstAPI/src/frameChecker.C +++ b/dyninstAPI/src/frameChecker.C @@ -52,8 +52,8 @@ frameChecker::frameChecker(const unsigned char* addr, size_t max_length, Dyninst for(unsigned i = 0; i < max_insns && bytesDecoded < max_length; i++) { m_Insns.push_back(d.decode()); - addr += m_Insns.back()->size(); - bytesDecoded += m_Insns.back()->size(); + addr += m_Insns.back().size(); + bytesDecoded += m_Insns.back().size(); } } @@ -64,13 +64,13 @@ frameChecker::~frameChecker() bool frameChecker::isReturn() const { - entryID firstOpcode = m_Insns[0]->getOperation().getID(); + entryID firstOpcode = m_Insns[0].getOperation().getID(); return (firstOpcode == e_ret_far) || (firstOpcode == e_ret_near); } bool frameChecker::isStackPreamble() const { - if(m_Insns[0]->getOperation().getID() != e_push) + if(m_Insns[0].getOperation().getID() != e_push) { return false; } @@ -84,19 +84,19 @@ bool frameChecker::isStackPreamble() const bool frameChecker::isMovStackToBase(unsigned index_to_check) const { if(m_Insns.size() <= index_to_check) return false; - if(m_Insns[index_to_check]->getOperation().getID() == e_mov) + if(m_Insns[index_to_check].getOperation().getID() == e_mov) { RegisterAST::Ptr stack_ptr(new RegisterAST(MachRegister::getStackPointer(Arch_x86))); RegisterAST::Ptr base_ptr(new RegisterAST(MachRegister::getFramePointer(Arch_x86))); - std::string debugMe = m_Insns[index_to_check]->format(); + std::string debugMe = m_Insns[index_to_check].format(); - if(m_Insns[index_to_check]->isWritten(base_ptr) && m_Insns[index_to_check]->isRead(stack_ptr)) + if(m_Insns[index_to_check].isWritten(base_ptr) && m_Insns[index_to_check].isRead(stack_ptr)) { return true; } stack_ptr = RegisterAST::Ptr(new RegisterAST(MachRegister::getStackPointer(Arch_x86_64))); base_ptr = RegisterAST::Ptr(new RegisterAST(MachRegister::getFramePointer(Arch_x86_64))); - if(m_Insns[index_to_check]->isWritten(base_ptr) && m_Insns[index_to_check]->isRead(stack_ptr)) + if(m_Insns[index_to_check].isWritten(base_ptr) && m_Insns[index_to_check].isRead(stack_ptr)) { return true; } diff --git a/dyninstAPI/src/frameChecker.h b/dyninstAPI/src/frameChecker.h index f64a12a5c3..31a55776db 100644 --- a/dyninstAPI/src/frameChecker.h +++ b/dyninstAPI/src/frameChecker.h @@ -45,7 +45,7 @@ class frameChecker private: bool isMovStackToBase(unsigned index_to_check) const; - std::vector m_Insns; + std::vector m_Insns; Dyninst::Architecture arch; }; diff --git a/dyninstAPI/src/function.C b/dyninstAPI/src/function.C index 9fe3cab991..301b572f62 100644 --- a/dyninstAPI/src/function.C +++ b/dyninstAPI/src/function.C @@ -606,7 +606,7 @@ bool func_instance::getBlocks(const Address addr, set &blks) { if (objblks.size() > 1) { // only add blocks that have an instruction at "addr" for (set::iterator bit = objblks.begin(); bit != objblks.end(); bit++) { - if ((*bit)->getInsn(addr)) { + if ((*bit)->getInsn(addr).isValid()) { blks.insert(*bit); } } @@ -623,7 +623,7 @@ block_instance *func_instance::getBlock(const Address addr) { std::set blks; getBlocks(addr, blks); for (std::set::iterator iter = blks.begin(); iter != blks.end(); ++iter) { - if ((*iter)->getInsn(addr)) return *iter; + if ((*iter)->getInsn(addr).isValid()) return *iter; } return NULL; } @@ -773,19 +773,19 @@ instPoint *func_instance::blockExitPoint(block_instance* b, bool create) { return p; } -instPoint *func_instance::preInsnPoint(block_instance* b, Address a, - InstructionAPI::Instruction::Ptr ptr, +instPoint *func_instance::preInsnPoint(block_instance *b, Address a, + InstructionAPI::Instruction insn, bool trusted, bool create) { - Location loc = Location::InstructionInstance(this, b, a, ptr, trusted); + Location loc = Location::InstructionInstance(this, b, a, insn, trusted); instPoint *p = IPCONV(proc()->mgr()->findPoint(loc, Point::PreInsn, create)); return p; } -instPoint *func_instance::postInsnPoint(block_instance* b, Address a, - InstructionAPI::Instruction::Ptr ptr, +instPoint *func_instance::postInsnPoint(block_instance *b, Address a, + InstructionAPI::Instruction insn, bool trusted, bool create) { - Location loc = Location::InstructionInstance(this, b, a, ptr, trusted); + Location loc = Location::InstructionInstance(this, b, a, insn, trusted); instPoint *p = IPCONV(proc()->mgr()->findPoint(loc, Point::PostInsn, create)); return p; @@ -999,7 +999,7 @@ bool func_instance::createOffsetVector() for (auto insnIter = insns.begin(); insnIter != insns.end(); ++insnIter) { Address addr = (*insnIter).first; - InstructionAPI::Instruction::Ptr insn = (*insnIter).second; + InstructionAPI::Instruction insn = (*insnIter).second; if (!createOffsetVector_Analysis(func, block, insn, addr)) { ret = false; break; @@ -1017,7 +1017,7 @@ bool func_instance::createOffsetVector() // Get the appropriate block and instruction for the definition ParseAPI::Block *defBlock = NULL; - InstructionAPI::Instruction::Ptr defInsn; + InstructionAPI::Instruction defInsn; for (auto blockIter = blocks.begin(); blockIter != blocks.end(); blockIter++) { ParseAPI::Block *block = *blockIter; @@ -1346,14 +1346,14 @@ bool func_instance::createOffsetVector_Symbols() } -bool func_instance::createOffsetVector_Analysis(ParseAPI::Function* func, - ParseAPI::Block* block, - InstructionAPI::Instruction::Ptr insn, - Address addr) +bool func_instance::createOffsetVector_Analysis(ParseAPI::Function *func, + ParseAPI::Block *block, + InstructionAPI::Instruction insn, + Address addr) { bool ret = true; - stackmods_printf("\t Processing %lx: %s\n", addr, insn->format().c_str()); + stackmods_printf("\t Processing %lx: %s\n", addr, insn.format().c_str()); int accessSize = getAccessSize(insn); Accesses* accesses = new Accesses(); diff --git a/dyninstAPI/src/function.h b/dyninstAPI/src/function.h index d0363b2408..13e6581a19 100644 --- a/dyninstAPI/src/function.h +++ b/dyninstAPI/src/function.h @@ -285,11 +285,11 @@ class func_instance : public patchTarget, public Dyninst::PatchAPI::PatchFunctio instPoint *postCallPoint(block_instance* blk, bool create); instPoint *blockEntryPoint(block_instance* blk, bool create); instPoint *blockExitPoint(block_instance* b, bool create); - instPoint *preInsnPoint(block_instance* b, Address a, - InstructionAPI::Instruction::Ptr ptr, + instPoint *preInsnPoint(block_instance *b, Address a, + InstructionAPI::Instruction insn, bool trusted, bool create); - instPoint *postInsnPoint(block_instance* b, Address a, - InstructionAPI::Instruction::Ptr ptr, + instPoint *postInsnPoint(block_instance *b, Address a, + InstructionAPI::Instruction insn, bool trusted, bool create); instPoint *edgePoint(edge_instance* eg, bool create); @@ -400,10 +400,10 @@ class func_instance : public patchTarget, public Dyninst::PatchAPI::PatchFunctio // Stack modification bool createOffsetVector_Symbols(); - bool createOffsetVector_Analysis(ParseAPI::Function* func, - ParseAPI::Block* block, - InstructionAPI::Instruction::Ptr insn, - Address addr); + bool createOffsetVector_Analysis(ParseAPI::Function *func, + ParseAPI::Block *block, + InstructionAPI::Instruction insn, + Address addr); bool addToOffsetVector(StackAnalysis::Height off, int size, diff --git a/dyninstAPI/src/hybridInstrumentation.C b/dyninstAPI/src/hybridInstrumentation.C index 00a7d4a992..17b5d8b5eb 100644 --- a/dyninstAPI/src/hybridInstrumentation.C +++ b/dyninstAPI/src/hybridInstrumentation.C @@ -829,8 +829,8 @@ bool HybridAnalysis::parseAfterCallAndInstrument(BPatch_point *callPoint, { using namespace InstructionAPI; Address curFallThroughAddr = (*cIter)->getCallFallThroughAddr(); - if (NULL != (*cIter)->getInsnAtPoint() && - c_BranchInsn != (*cIter)->getInsnAtPoint()->getCategory() && + if ((*cIter)->getInsnAtPoint().isValid() && + c_BranchInsn != (*cIter)->getInsnAtPoint().getCategory() && BPatch_defensiveMode == (*cIter)->llpoint()->func()->obj()->hybridMode() && ! hasEdge((*cIter)->getFunction(), (Address)((*cIter)->llpoint()->block()->start()), @@ -1481,8 +1481,8 @@ bool HybridAnalysis::getCFTargets(BPatch_point *point, vector
&targets) else { // compute static targets with bad addresses using namespace InstructionAPI; - Instruction::Ptr insn = ipoint->block()->getInsn(ipoint->block()->last()); - Expression::Ptr expr = insn->getControlFlowTarget(); + Instruction insn = ipoint->block()->getInsn(ipoint->block()->last()); + Expression::Ptr expr = insn.getControlFlowTarget(); //Expression::Ptr expr = ipoint->insn()->getControlFlowTarget(); Architecture arch = proc_->lowlevel_process()->getArch(); expr->bind(RegisterAST::Ptr @@ -1542,8 +1542,8 @@ bool HybridAnalysis::getCFTargets(BPatch_point *point, vector
&targets) assert(ptr); InstructionDecoder dec (ptr, InstructionDecoder::maxInstructionLength, arch); - Instruction::Ptr insn = dec.decode(); - Expression::Ptr trgExpr = insn->getControlFlowTarget(); + Instruction insn = dec.decode(); + Expression::Ptr trgExpr = insn.getControlFlowTarget(); trgExpr->bind(thePC.get(), Result(s64, ipoint->block()->last())); Result actualTarget = trgExpr->eval(); diff --git a/dyninstAPI/src/hybridOverwrites.C b/dyninstAPI/src/hybridOverwrites.C index e609e70d69..c25aa5631e 100644 --- a/dyninstAPI/src/hybridOverwrites.C +++ b/dyninstAPI/src/hybridOverwrites.C @@ -1337,8 +1337,8 @@ bool HybridAnalysisOW::isRealStore(Address insnAddr, block_instance *block, InstructionDecoder decoder(buf, InstructionDecoder::maxInstructionLength, proc()->lowlevel_process()->getArch()); - Instruction::Ptr insn = decoder.decode(); - assert(insn != NULL); + Instruction insn = decoder.decode(); + assert(insn.isValid()); parse_func *imgfunc = func->lowlevel_func()->ifunc(); Address image_addr = func->lowlevel_func()->addrToOffset(insnAddr); diff --git a/dyninstAPI/src/image.C b/dyninstAPI/src/image.C index fef50b1a9d..62616e6364 100644 --- a/dyninstAPI/src/image.C +++ b/dyninstAPI/src/image.C @@ -309,8 +309,9 @@ namespace { // looking for the *last* instruction in the block // that defines GR8 - Instruction::Ptr r8_def; + Instruction r8_def; Address r8_def_addr; + bool find = false; InstructionDecoder dec( b->region()->getPtrToInstruction(b->start()), @@ -321,22 +322,24 @@ namespace { RegisterAST::Ptr r8( new RegisterAST(ppc32::r8) ); Address cur_addr = b->start(); - while(Instruction::Ptr cur = dec.decode()) { - if(cur->isWritten(r8)) { + while(cur_addr < b->end()) { + Instruction cur = dec.decode(); + if(cur.isWritten(r8)) { + find = true; r8_def = cur; r8_def_addr = cur_addr; } - cur_addr += cur->size(); + cur_addr += cur.size(); } - if(!r8_def) + if(!find) return 0; Address ss_addr = 0; // Try a TOC-based lookup first - if (r8_def->isRead(r2)) { + if (r8_def.isRead(r2)) { set memReads; - r8_def->getMemoryReadOperands(memReads); + r8_def.getMemoryReadOperands(memReads); Address TOC = f->obj()->cs()->getTOC(r8_def_addr); if (TOC != 0 && memReads.size() == 1) { Expression::Ptr expr = *memReads.begin(); @@ -621,22 +624,22 @@ int image::findMain() // p += (eAddr - eStart); // } - switch(linkedFile->getAddressWidth()) { - case 4: - // 32-bit... - startup_printf("%s[%u]: setting 32-bit mode\n", - FILE__,__LINE__); - ia32_set_mode_64(false); - break; - case 8: - startup_printf("%s[%u]: setting 64-bit mode\n", - FILE__,__LINE__); - ia32_set_mode_64(true); - break; - default: - assert(0 && "Illegal address width"); - break; - } +// switch(linkedFile->getAddressWidth()) { +// case 4: +// // 32-bit... +// startup_printf("%s[%u]: setting 32-bit mode\n", +// FILE__,__LINE__); +// ia32_set_mode_64(false); +// break; +// case 8: +// startup_printf("%s[%u]: setting 64-bit mode\n", +// FILE__,__LINE__); +// ia32_set_mode_64(true); +// break; +// default: +// assert(0 && "Illegal address width"); +// break; +// } Address mainAddress = 0; @@ -704,7 +707,7 @@ int image::findMain() return -1; } - // To get the secont to last instruction, which loads the address of main + // To get the secont to last instruction, which loads the address of main auto iit = insns.end(); --iit; --iit; @@ -723,7 +726,8 @@ int image::findMain() { /* expand failed */ mainAddress = 0x0; - startup_printf("%s[%u]: cannot expand %s from instruction %s\n", FILE__, __LINE__, assignment->format().c_str(), assignment->insn()->format().c_str()); + startup_printf("%s[%u]: cannot expand %s from instruction %s\n", FILE__, __LINE__, assignment->format().c_str(), + assignment->insn().format().c_str()); } else { startup_printf("%s[%u]: try to visit %s\n", FILE__, __LINE__, ast->format().c_str()); FindMainVisitor fmv; @@ -1323,15 +1327,32 @@ void image::analyzeIfNeeded() { } static bool CheckForPowerPreamble(parse_block* entryBlock) { - std::vector retString; - entryBlock->GetBlockInstructions(retString); - if (retString.size() < 2) + ParseAPI::Block::Insns insns; + entryBlock->getInsns(insns); + if (insns.size() < 2) return false; - // Power Preambles - if ((retString[0].find("lis r2") != std::string::npos && retString[1].find("addi r2") != std::string::npos) || - (retString[0].find("addis r2") != std::string::npos && retString[1].find("addi r2") != std::string::npos)) { - return true; - } + // Get the first two instructions + auto iter = insns.begin(); + InstructionAPI::Instruction i1 = iter->second; + ++iter; + InstructionAPI::Instruction i2 = iter->second; + + const uint32_t * buf1 = (const uint32_t*) i1.ptr(); + const uint32_t * buf2 = (const uint32_t*) i2.ptr(); + + uint32_t p1 = buf1[0] >> 16; + uint32_t p2 = buf2[0] >> 16; + + // Check for two types of preamble + // Preamble 1: used in executables + // lis r2, IMM bytes: IMM1 IMM2 40 3c + // addi r2, r2, IMM bytes: IMM1 IMM2 42 38 + if (p1 == 0x3c40 && p2 == 0x3842) return true; + + // Preamble 2: used in libraries + // addis r2, r12, IMM bytes: IMM1 IMM2 4c 3c + // addi r2, r2,IMM bytes: IMM1 IMM2 42 38 + if (p1 == 0x3c4c && p2 == 0x3842) return true; return false; } @@ -1344,10 +1365,6 @@ void image::analyzeImage() { #endif stats_parse.startTimer(PARSE_ANALYZE_TIMER); -// FIXME necessary? -#if defined(arch_x86_64) - ia32_set_mode_64(getObject()->getAddressWidth() == 8); -#endif assert(parseState_ < analyzed); if(parseState_ < symtab){ diff --git a/dyninstAPI/src/inst-aarch64.C b/dyninstAPI/src/inst-aarch64.C index 76685591d0..21493dfab7 100644 --- a/dyninstAPI/src/inst-aarch64.C +++ b/dyninstAPI/src/inst-aarch64.C @@ -1022,12 +1022,12 @@ void emitStorePreviousStackFrameRegister(Address, } using namespace Dyninst::InstructionAPI; - -bool AddressSpace::getDynamicCallSiteArgs(InstructionAPI::Instruction::Ptr i, - Address addr, - std::vector &args) { - assert(0); //Not implemented - return false; +bool AddressSpace::getDynamicCallSiteArgs(InstructionAPI::Instruction i, + Address addr, + pdvector &args) +{ + assert(0); //Not implemented + return false; } bool writeFunctionPtr(AddressSpace *p, Address addr, func_instance *f) { diff --git a/dyninstAPI/src/inst-power.C b/dyninstAPI/src/inst-power.C index 8e577a6b26..3e592c4eba 100644 --- a/dyninstAPI/src/inst-power.C +++ b/dyninstAPI/src/inst-power.C @@ -2557,7 +2557,7 @@ void emitStorePreviousStackFrameRegister(Address, } using namespace Dyninst::InstructionAPI; -bool AddressSpace::getDynamicCallSiteArgs(InstructionAPI::Instruction::Ptr i, +bool AddressSpace::getDynamicCallSiteArgs(InstructionAPI::Instruction i, Address addr, pdvector &args) { @@ -2569,8 +2569,8 @@ bool AddressSpace::getDynamicCallSiteArgs(InstructionAPI::Instruction::Ptr i, // Is this a branch conditional link register (BCLR) // BCLR uses the xlform (6,5,5,5,10,1) - for(Instruction::cftConstIter curCFT = i->cft_begin(); - curCFT != i->cft_end(); + for(Instruction::cftConstIter curCFT = i.cft_begin(); + curCFT != i.cft_end(); ++curCFT) { if(curCFT->target->isUsed(ctr32) || diff --git a/dyninstAPI/src/inst-x86.C b/dyninstAPI/src/inst-x86.C index fe00056d5b..2ef2b5d20a 100644 --- a/dyninstAPI/src/inst-x86.C +++ b/dyninstAPI/src/inst-x86.C @@ -2262,12 +2262,12 @@ void emitStorePreviousStackFrameRegister(Address register_num, // First AST node: target of the call // Second AST node: source of the call // This can handle indirect control transfers as well -bool AddressSpace::getDynamicCallSiteArgs(InstructionAPI::Instruction::Ptr insn, - Address addr, +bool AddressSpace::getDynamicCallSiteArgs(InstructionAPI::Instruction insn, + Address addr, pdvector &args) { using namespace Dyninst::InstructionAPI; - Expression::Ptr cft = insn->getControlFlowTarget(); + Expression::Ptr cft = insn.getControlFlowTarget(); ASTFactory f; cft->apply(&f); assert(f.m_stack.size() == 1); @@ -2275,7 +2275,7 @@ bool AddressSpace::getDynamicCallSiteArgs(InstructionAPI::Instruction::Ptr insn, args.push_back(AstNode::operandNode(AstNode::Constant, (void *) addr)); inst_printf("%s[%d]: Inserting dynamic call site instrumentation for %s\n", - FILE__, __LINE__, cft->format(insn->getFormatter()).c_str()); + FILE__, __LINE__, cft->format(insn.getArch()).c_str()); return true; } diff --git a/dyninstAPI/src/instPoint.C b/dyninstAPI/src/instPoint.C index e63866833c..08cd55c7d1 100644 --- a/dyninstAPI/src/instPoint.C +++ b/dyninstAPI/src/instPoint.C @@ -96,17 +96,17 @@ instPoint *instPoint::edge(func_instance *f, edge_instance *e) { instPoint *instPoint::preInsn(func_instance *f, block_instance *b, Address a, - InstructionAPI::Instruction::Ptr ptr, + Instruction insn, bool trusted) { - return f->preInsnPoint(b, a, ptr, trusted, true); + return f->preInsnPoint(b, a, insn, trusted, true); } instPoint *instPoint::postInsn(func_instance *f, block_instance *b, Address a, - InstructionAPI::Instruction::Ptr ptr, + Instruction insn, bool trusted) { - return f->postInsnPoint(b, a, ptr, trusted, true); + return f->postInsnPoint(b, a, insn, trusted, true); } instPoint::instPoint(Type t, @@ -132,11 +132,11 @@ instPoint::instPoint(Type t, baseTramp_(NULL) { }; -instPoint::instPoint(Type t, - PatchMgrPtr mgr, +instPoint::instPoint(Type t, + PatchMgrPtr mgr, block_instance *b, Address a, - InstructionAPI::Instruction::Ptr i, + Instruction i, func_instance *f) : Point(t, mgr, b, a, i, f), baseTramp_(NULL) { @@ -192,7 +192,7 @@ instPoint *instPoint::fork(instPoint *parent, AddressSpace *child) { func_instance *f = parent->func() ? child->findFunction(parent->func()->ifunc()) : NULL; block_instance *b = parent->block() ? child->findBlock(parent->block()->llb()) : NULL; edge_instance *e = parent->edge() ? child->findEdge(parent->edge()->edge()) : NULL; - Instruction::Ptr i = parent->insn_; + Instruction i = parent->insn_; Address a = parent->addr_; instPoint *point = NULL; @@ -289,7 +289,7 @@ edge_instance *instPoint::edge() const { } bool instPoint::checkInsn(block_instance *b, - Instruction::Ptr &insn, + Instruction &insn, Address a) { block_instance::Insns insns; b->getInsns(insns); @@ -358,7 +358,7 @@ Address instPoint::addr_compat() const { return addr_; case PostInsn: // This gets weird for things like jumps... - return addr_ + insn_->size(); + return addr_ + insn_.size(); case PreCall: return block()->last(); case PostCall: { @@ -424,8 +424,8 @@ std::string instPoint::format() const { if (addr_) { ret << ", Addr(" << hex << addr_ << dec << ")"; } - if (insn_) { - ret << ", Insn(" << insn_->format() << ")"; + if (insn_.isValid()) { + ret << ", Insn(" << insn_.format() << ")"; } ret << ")"; return ret.str(); diff --git a/dyninstAPI/src/instPoint.h b/dyninstAPI/src/instPoint.h index 4cde95a259..32bd2fc0ae 100644 --- a/dyninstAPI/src/instPoint.h +++ b/dyninstAPI/src/instPoint.h @@ -87,14 +87,14 @@ class instPoint : public Dyninst::PatchAPI::Point { static instPoint *blockExit(func_instance *, block_instance *); static instPoint *edge(func_instance *, edge_instance *); static instPoint *preInsn(func_instance *, - block_instance *, - Address, - InstructionAPI::Instruction::Ptr = InstructionAPI::Instruction::Ptr(), - bool trusted = false); + block_instance *, + Address, + InstructionAPI::Instruction = InstructionAPI::Instruction(), + bool trusted = false); static instPoint *postInsn(func_instance *, - block_instance *, Address, - InstructionAPI::Instruction::Ptr = InstructionAPI::Instruction::Ptr(), - bool trusted = false); + block_instance *, Address, + InstructionAPI::Instruction = InstructionAPI::Instruction(), + bool trusted = false); static instPoint *preCall(func_instance *, block_instance *); static instPoint *postCall(func_instance *, @@ -111,7 +111,7 @@ class instPoint : public Dyninst::PatchAPI::Point { // (possibly func context) block instPoint(Type, PatchMgrPtr, block_instance *, func_instance *); // Insn - instPoint(Type, PatchMgrPtr, block_instance *, Address, InstructionAPI::Instruction::Ptr, func_instance *); + instPoint(Type, PatchMgrPtr, block_instance *, Address, InstructionAPI::Instruction, func_instance *); instPoint(Type, PatchMgrPtr, edge_instance *, func_instance *); public: @@ -153,7 +153,7 @@ class instPoint : public Dyninst::PatchAPI::Point { void calcLiveness(); // Will fill in insn if it's NULL-equivalent static bool checkInsn(block_instance *, - InstructionAPI::Instruction::Ptr &insn, + InstructionAPI::Instruction &insn, Address a); baseTramp *baseTramp_; diff --git a/dyninstAPI/src/mapped_object.C b/dyninstAPI/src/mapped_object.C index dc6fd33e5f..2f472d0860 100644 --- a/dyninstAPI/src/mapped_object.C +++ b/dyninstAPI/src/mapped_object.C @@ -1247,9 +1247,9 @@ bool mapped_object::parseNewEdges(const std::vector &stubs) // the easy way to do things. block_instance::Insns insns; stubs[idx].src->getInsns(insns); - InstructionAPI::Instruction::Ptr cf = insns[stubs[idx].src->last()]; - assert(cf); - switch (cf->getCategory()) { + InstructionAPI::Instruction cf = insns[stubs[idx].src->last()]; + assert(cf.isValid()); + switch (cf.getCategory()) { case c_CallInsn: if (stubs[idx].trg == stubs[idx].src->end()) { @@ -1266,11 +1266,11 @@ bool mapped_object::parseNewEdges(const std::vector &stubs) edgeType = INDIRECT; break; case c_BranchInsn: - if (cf->readsMemory()) + if (cf.readsMemory()) { edgeType = INDIRECT; } - else if (!cf->allowsFallThrough()) + else if (!cf.allowsFallThrough()) { edgeType = DIRECT; } diff --git a/dyninstAPI/src/parse-cfg.C b/dyninstAPI/src/parse-cfg.C index 65886ab49d..92f58f420e 100644 --- a/dyninstAPI/src/parse-cfg.C +++ b/dyninstAPI/src/parse-cfg.C @@ -212,7 +212,7 @@ parse_block::parse_block( parse_func * func, CodeRegion * reg, Address firstOffset) : - Block(func->obj(),reg,firstOffset), + Block(func->obj(),reg,firstOffset, func), needsRelocation_(false), blockNumber_(0), unresolvedCF_(false), @@ -426,10 +426,10 @@ void parse_block::getInsns(Insns &insns, Address base) { InstructionDecoder d(ptr, getSize(),obj()->cs()->getArch()); while (off < endOffset()) { - Instruction::Ptr insn = d.decode(); + Instruction insn = d.decode(); insns[off + base] = insn; - off += insn->size(); + off += insn.size(); } } @@ -532,27 +532,18 @@ parse_func *parse_block::getCallee() { return NULL; } -void parse_block::GetBlockInstructions(std::vector & ret) { - Insns tmp; - getInsns(tmp, 0); - for (auto iit = tmp.begin(); iit != tmp.end(); ++iit) { - ret.push_back(iit->second->format()); - } - return; -} - std::pair parse_block::callTarget() { using namespace InstructionAPI; Offset off = lastInsnOffset(); const unsigned char *ptr = (const unsigned char *)getPtrToInstruction(off); if (ptr == NULL) return std::make_pair(false, 0); InstructionDecoder d(ptr, endOffset() - lastInsnOffset(), obj()->cs()->getArch()); - Instruction::Ptr insn = d.decode(); + Instruction insn = d.decode(); // Bind PC to that insn // We should build a free function to do this... - Expression::Ptr cft = insn->getControlFlowTarget(); + Expression::Ptr cft = insn.getControlFlowTarget(); if (cft) { Expression::Ptr pc(new RegisterAST(MachRegister::getPC(obj()->cs()->getArch()))); cft->bind(pc.get(), Result(u64, lastInsnAddr())); diff --git a/dyninstAPI/src/parse-cfg.h b/dyninstAPI/src/parse-cfg.h index 774da914d5..c0e921583c 100644 --- a/dyninstAPI/src/parse-cfg.h +++ b/dyninstAPI/src/parse-cfg.h @@ -131,11 +131,10 @@ class parse_block : public codeRange, public ParseAPI::Block { // This is copied from the union of all successor blocks const bitArray getLivenessOut(parse_func * context); - typedef std::map Insns; + typedef std::map Insns; // The provided parameter is a magic offset to add to each instruction's // address; we do this to avoid a copy when getting Insns from block_instances void getInsns(Insns &instances, Address offset = 0); - void GetBlockInstructions(std::vector & ret); private: bool needsRelocation_; @@ -192,8 +191,8 @@ class image_edge : public ParseAPI::Edge { // MSVC++ 2003 does not properly support covariant return types // in overloaded methods #if !defined _MSC_VER || _MSC_VER > 1310 - virtual parse_block * src() const { return (parse_block*)_source; } - virtual parse_block * trg() const { return (parse_block*)_target; } + virtual parse_block * src() const { return (parse_block*)ParseAPI::Edge::src(); } + virtual parse_block * trg() const { return (parse_block*)ParseAPI::Edge::trg(); } #endif const char * getTypeString(); diff --git a/dyninstAPI/src/parse-power.C b/dyninstAPI/src/parse-power.C index 008658fa03..6d81390509 100644 --- a/dyninstAPI/src/parse-power.C +++ b/dyninstAPI/src/parse-power.C @@ -543,10 +543,13 @@ void parse_func::calcUsedRegs() InstructionDecoder d(getPtrToInstruction((*curBlock)->start()), (*curBlock)->size(), isrc()->getArch()); - Instruction::Ptr i; - while(i = d.decode()) + Instruction i; + int size = 0; + while(size < (*curBlock)->size()) { - i->getWriteSet(writtenRegs); + i = d.decode(); + size += i.size(); + i.getWriteSet(writtenRegs); } } for(std::set::const_iterator curReg = writtenRegs.begin(); @@ -813,16 +816,16 @@ func_instance *mapped_object::findGlobalConstructorFunc(const std::string &ctorH InstructionDecoder decoder(p, initRegion->getDiskSize(), parse_img()->codeObject()->cs()->getArch()); - Instruction::Ptr curInsn = decoder.decode(); - while(numCalls < CTOR_NUM_CALLS && curInsn && curInsn->isValid() && + Instruction curInsn = decoder.decode(); + while(numCalls < CTOR_NUM_CALLS && curInsn.isValid() && bytesSeen < initRegion->getDiskSize()) { - InsnCategory category = curInsn->getCategory(); + InsnCategory category = curInsn.getCategory(); if( category == c_CallInsn ) { numCalls++; } if( numCalls < CTOR_NUM_CALLS ) { - bytesSeen += curInsn->size(); + bytesSeen += curInsn.size(); curInsn = decoder.decode(); } } @@ -837,7 +840,7 @@ func_instance *mapped_object::findGlobalConstructorFunc(const std::string &ctorH RegisterAST thePC = RegisterAST( Dyninst::MachRegister::getPC(parse_img()->codeObject()->cs()->getArch())); - Expression::Ptr callTarget = curInsn->getControlFlowTarget(); + Expression::Ptr callTarget = curInsn.getControlFlowTarget(); if( !callTarget.get() ) { logLine("failed to find global constructor function\n"); return NULL; @@ -916,23 +919,25 @@ func_instance *mapped_object::findGlobalDestructorFunc(const std::string &dtorHa InstructionDecoder decoder(p, finiRegion->getDiskSize(), parse_img()->codeObject()->cs()->getArch()); - Instruction::Ptr lastCall; - Instruction::Ptr curInsn = decoder.decode(); + Instruction lastCall; + Instruction curInsn = decoder.decode(); + bool find = false; - while(curInsn && curInsn->isValid() && + while(curInsn.isValid() && bytesSeen < finiRegion->getDiskSize()) { - InsnCategory category = curInsn->getCategory(); + InsnCategory category = curInsn.getCategory(); if( category == c_CallInsn ) { + find = true; lastCall = curInsn; break; } - bytesSeen += curInsn->size(); + bytesSeen += curInsn.size(); curInsn = decoder.decode(); } - if( !lastCall.get() || !lastCall->isValid() ) { + if( !find || !lastCall.isValid() ) { logLine("heuristic for finding global destructor function failed\n"); return NULL; } @@ -942,7 +947,7 @@ func_instance *mapped_object::findGlobalDestructorFunc(const std::string &dtorHa RegisterAST thePC = RegisterAST( Dyninst::MachRegister::getPC(parse_img()->codeObject()->cs()->getArch())); - Expression::Ptr callTarget = lastCall->getControlFlowTarget(); + Expression::Ptr callTarget = lastCall.getControlFlowTarget(); if( !callTarget.get() ) { logLine("failed to find global destructor function\n"); return NULL; diff --git a/dyninstAPI/src/parse-x86.C b/dyninstAPI/src/parse-x86.C index 7eecda5bc3..20fa3f4653 100644 --- a/dyninstAPI/src/parse-x86.C +++ b/dyninstAPI/src/parse-x86.C @@ -68,9 +68,9 @@ bool parse_func::writesFPRs(unsigned level) { const Function::edgelist & calls = callEdges(); Function::edgelist::const_iterator cit = calls.begin(); for( ; cit != calls.end(); ++cit) { - image_edge * ce = static_cast(*cit); - parse_func * ct = static_cast( - obj()->findFuncByEntry(region(),ce->trg()->start())); + if(!(*cit)->trg()) continue; + parse_func * ct = dynamic_cast( + obj()->findFuncByEntry(region(),(*cit)->trg()->start())); if(ct && ct != this) { if (ct->writesFPRs(level+1)) { // One of our kids does... if we're top-level, cache it; in @@ -120,30 +120,31 @@ bool parse_func::writesFPRs(unsigned level) { return true; } InstructionDecoder d(buf,fe->end()-fe->start(),isrc()->getArch()); - Instruction::Ptr i; - - while((i = d.decode())) { - if(i->isWritten(st0) || - i->isWritten(st1) || - i->isWritten(st2) || - i->isWritten(st3) || - i->isWritten(st4) || - i->isWritten(st5) || - i->isWritten(st6) || - i->isWritten(st7) || - i->isWritten(xmm0) || - i->isWritten(xmm1) || - i->isWritten(xmm2) || - i->isWritten(xmm3) || - i->isWritten(xmm4) || - i->isWritten(xmm5) || - i->isWritten(xmm6) || - i->isWritten(xmm7) + Instruction i = d.decode(); + + while((i.isValid())) { + if(i.isWritten(st0) || + i.isWritten(st1) || + i.isWritten(st2) || + i.isWritten(st3) || + i.isWritten(st4) || + i.isWritten(st5) || + i.isWritten(st6) || + i.isWritten(st7) || + i.isWritten(xmm0) || + i.isWritten(xmm1) || + i.isWritten(xmm2) || + i.isWritten(xmm3) || + i.isWritten(xmm4) || + i.isWritten(xmm5) || + i.isWritten(xmm6) || + i.isWritten(xmm7) ) { containsFPRWrites_ = used; return true; } + i = d.decode(); } } // No kids do, and we don't. Impressive. diff --git a/dyninstAPI/src/pcEventMuxer.C b/dyninstAPI/src/pcEventMuxer.C index 72a305b51c..df4c13b1fe 100644 --- a/dyninstAPI/src/pcEventMuxer.C +++ b/dyninstAPI/src/pcEventMuxer.C @@ -263,10 +263,10 @@ PCEventMuxer::cb_ret_t PCEventMuxer::SingleStepCallback(EventPtr ev) { unsigned size = 4; process->readDataSpace((void *) base, size, disass, false); InstructionDecoder deco(disass,size,process->getArch()); - Instruction::Ptr insn = deco.decode(); - while(insn) { - cerr << "\t" << hex << base << ": " << insn->format(base) << dec << endl; - base += insn->size(); + Instruction insn = deco.decode(); + while(insn.isValid()) { + cerr << "\t" << hex << base << ": " << insn.format(base) << dec << endl; + base += insn.size(); insn = deco.decode(); } diff --git a/elf/src/Elf_X.C b/elf/src/Elf_X.C index 1b049579d1..09364542ed 100644 --- a/elf/src/Elf_X.C +++ b/elf/src/Elf_X.C @@ -798,7 +798,7 @@ bool Elf_X_Shdr::next_data() bool Elf_X_Shdr::isValid() const { - return (shdr32 || shdr64); + return (shdr32 || shdr64) && data; } unsigned Elf_X_Shdr::wordSize() const @@ -961,7 +961,7 @@ Elf_X_Sym Elf_X_Data::get_sym() bool Elf_X_Data::isValid() const { - return data; + return data != NULL; } // ------------------------------------------------------------------------ @@ -1663,6 +1663,8 @@ bool Elf_X::findDebugFile(std::string origfilename, string &output_name, char* & cached_debug = true; uint16_t shnames_idx = e_shstrndx(); + // If we don't have names, bail. + if(shnames_idx >= e_shnum()) return false; Elf_X_Shdr shnames_hdr = get_shdr(shnames_idx); if (!shnames_hdr.isValid()) return false; diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index e702e8c43f..dcb032c2cc 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -8,18 +8,17 @@ add_executable(unstrip unstrip/unstrip.C unstrip/fingerprint.C unstrip/callback.C) add_dependencies(unstrip parseAPI symtabAPI instructionAPI common) -target_link_libraries(unstrip parseAPI symtabAPI instructionAPI common) +target_link_libraries(unstrip parseAPI symtabAPI instructionAPI common ${Boost_LIBRARIES}) add_executable(codeCoverage codeCoverage/codeCoverage.C) -add_dependencies(codeCoverage dyninstAPI patchAPI parseAPI symtabAPI instructionAPI pcontrol common) -target_link_libraries(codeCoverage dyninstAPI patchAPI parseAPI symtabAPI instructionAPI pcontrol common) +add_dependencies(codeCoverage dyninstAPI patchAPI parseAPI symtabAPI instructionAPI pcontrol common stackwalk dynDwarf dynElf) +target_link_libraries(codeCoverage dyninstAPI patchAPI parseAPI symtabAPI instructionAPI pcontrol common stackwalk dynDwarf dynElf ${Boost_LIBRARIES}) add_library(Inst SHARED codeCoverage/libInst.C) add_executable(cfg_to_dot ../parseAPI/doc/example.cc) -add_dependencies(cfg_to_dot parseAPI symtabAPI) -target_link_libraries(cfg_to_dot parseAPI symtabAPI - ) +add_dependencies(cfg_to_dot parseAPI symtabAPI instructionAPI common dynDwarf dynElf) +target_link_libraries(cfg_to_dot parseAPI symtabAPI instructionAPI common dynDwarf dynElf ${Boost_LIBRARIES}) #add_executable(retee) install (TARGETS cfg_to_dot unstrip codeCoverage Inst diff --git a/examples/unstrip/callback.C b/examples/unstrip/callback.C index 29f56ff89e..f6f25d3b1c 100644 --- a/examples/unstrip/callback.C +++ b/examples/unstrip/callback.C @@ -56,7 +56,7 @@ void InstrCallback::instruction_cb(ParseAPI::Function * f, Address addr, insn_details* insnDetails) { - InstructionAPI::Instruction::Ptr insn = insnDetails->insn->getInstruction(); + InstructionAPI::Instruction insn = insnDetails->insn->getInstruction(); /* If we haven't found the syscallTrampStore yet, * check if this is an indirect call through it */ diff --git a/examples/unstrip/fingerprint.C b/examples/unstrip/fingerprint.C index 9215b32a4a..29b0094349 100644 --- a/examples/unstrip/fingerprint.C +++ b/examples/unstrip/fingerprint.C @@ -56,14 +56,14 @@ void Fingerprint::findMain(SymtabAPI::Symtab * symtab, const unsigned char* textBuffer = (const unsigned char*) textsection->getPtrToRawData(); using namespace Dyninst::InstructionAPI; InstructionDecoder d(textBuffer, textsection->getMemSize(), sts->getArch()); - Instruction::Ptr curInsn, prevInsn; + Instruction curInsn, prevInsn; curInsn = d.decode(); - while(curInsn && curInsn->getCategory() != c_CallInsn) + while(curInsn.isValid() && curInsn.getCategory() != c_CallInsn) { prevInsn = curInsn; curInsn = d.decode(); } - unsigned int mainAddr = prevInsn->getOperand(0).getValue()->eval().convert(); + unsigned int mainAddr = prevInsn.getOperand(0).getValue()->eval().convert(); //fprintf(stderr, "found main at 0x%lx\n", mainAddr); using namespace SymtabAPI; @@ -279,7 +279,7 @@ bool Fingerprint::parse(ParseAPI::Function * f, vector::iterator tIter; for (tIter = trapLocs.begin(); tIter != trapLocs.end(); ++tIter) { - InstructionAPI::Instruction::Ptr insn = (*tIter).instr(); + InstructionAPI::Instruction insn = (*tIter).instr(); curTrap.clear(); /* Backward slice to get the value in EAX, which will dictate how we proceed */ diff --git a/examples/unstrip/types.h b/examples/unstrip/types.h index 4336c508f3..01337c286f 100644 --- a/examples/unstrip/types.h +++ b/examples/unstrip/types.h @@ -63,14 +63,14 @@ ParamType getParamType(char * type); class trapLoc { private: Address a; - InstructionAPI::Instruction::Ptr i; + InstructionAPI::Instruction i; ParseAPI::Block * b; public: - trapLoc(Address _a, InstructionAPI::Instruction::Ptr _i, ParseAPI::Block * _b) : + trapLoc(Address _a, InstructionAPI::Instruction _i, ParseAPI::Block * _b) : a(_a), i(_i), b(_b) {} Address addr() { return a; } - InstructionAPI::Instruction::Ptr instr() { return i; } + InstructionAPI::Instruction instr() { return i; } ParseAPI::Block * block() { return b; } bool operator<(const trapLoc & t2) const { diff --git a/examples/unstrip/util.C b/examples/unstrip/util.C index 86dc8f0daf..450a1a430b 100644 --- a/examples/unstrip/util.C +++ b/examples/unstrip/util.C @@ -83,14 +83,14 @@ void getInsnInstances(ParseAPI::Block *block, InstructionDecoder d(ptr, block->size(), block->obj()->cs()->getArch()); while (off < block->end()) { insns.push_back(std::make_pair(d.decode(), off)); - off += insns.back().first->size(); + off += insns.back().first.size(); } } /* * Determine if insn is a system call */ -bool isSyscall(Instruction::Ptr & insn, Address & syscallTrampStore) +bool isSyscall(Instruction insn, Address & syscallTrampStore) { static RegisterAST::Ptr gs(new RegisterAST(x86::gs)); @@ -98,13 +98,13 @@ bool isSyscall(Instruction::Ptr & insn, Address & syscallTrampStore) syscallTrampStore)); Dereference syscallTrampCall(syscallTrampPtr, u32); - return (((insn->getOperation().getID() == e_call) && - (insn->isRead(gs))) || - ((insn->getOperation().getID() == e_call) && - (*(insn->getControlFlowTarget()) == syscallTrampCall)) || - (insn->getOperation().getID() == e_syscall) || - (insn->getOperation().getID() == e_int) || - (insn->getOperation().getID() == power_op_sc)); + return (((insn.getOperation().getID() == e_call) && + (insn.isRead(gs))) || + ((insn.getOperation().getID() == e_call) && + (*(insn.getControlFlowTarget()) == syscallTrampCall)) || + (insn.getOperation().getID() == e_syscall) || + (insn.getOperation().getID() == e_int) || + (insn.getOperation().getID() == power_op_sc)); } @@ -112,10 +112,10 @@ bool isSyscall(Instruction::Ptr & insn, Address & syscallTrampStore) * Check if a given instruction is an indirect call through the _dl_sysinfo symbol. * If so, store the symbol address. */ -bool isCallToSyscallTrampStore(Instruction::Ptr & insn, Address & _syscallTramp) +bool isCallToSyscallTrampStore(Instruction insn, Address & _syscallTramp) { - if (insn->getOperation().getID() == e_call) { - Expression::Ptr cft = insn->getControlFlowTarget(); + if (insn.getOperation().getID() == e_call) { + Expression::Ptr cft = insn.getControlFlowTarget(); if (typeid(cft) == typeid(Dereference::Ptr)) { vector children; cft->getChildren(children); @@ -175,13 +175,13 @@ Address searchForSyscallTrampStore(CodeObject::funclist & procedures) ParseAPI::Function::blocklist::iterator bIter; for (bIter = blocks.begin(); bIter != blocks.end(); ++bIter) { - std::vector > insns; + std::vector > insns; getInsnInstances(*bIter, insns); - std::vector >::iterator insnIter; + std::vector >::iterator insnIter; for (insnIter= insns.begin(); insnIter != insns.end(); ++insnIter) { - std::pair insn = *insnIter; + std::pair insn = *insnIter; if (isCallToSyscallTrampStore(insn.first, syscallTramp)) { return syscallTramp; } diff --git a/examples/unstrip/util.h b/examples/unstrip/util.h index 6ba7e9f17e..1f65332fc1 100644 --- a/examples/unstrip/util.h +++ b/examples/unstrip/util.h @@ -72,9 +72,9 @@ using namespace Dyninst; void getInsnInstances(ParseAPI::Block *block, Slicer::InsnVec &insns); -bool isSyscall(InstructionAPI::Instruction::Ptr & insn, Address & syscallTrampStore); +bool isSyscall(InstructionAPI::Instruction insn, Address & syscallTrampStore); -bool isCallToSyscallTrampStore(InstructionAPI::Instruction::Ptr & insn, Address & _syscallTramp); +bool isCallToSyscallTrampStore(InstructionAPI::Instruction insn, Address & _syscallTramp); Address getSyscallTrampStore(SymtabAPI::Symtab * symtab); diff --git a/instructionAPI/CMakeLists.txt b/instructionAPI/CMakeLists.txt index bfb418d940..276a618393 100644 --- a/instructionAPI/CMakeLists.txt +++ b/instructionAPI/CMakeLists.txt @@ -28,15 +28,15 @@ SET_SOURCE_FILES_PROPERTIES(${SRC_LIST} PROPERTIES LANGUAGE CXX) # variables by default, rather then waiting until the variable tracking limit # is reached. if (${CMAKE_CXX_COMPILER_ID} MATCHES "GNU") -set_source_files_properties(src/InstructionDecoder-aarch64.C PROPERTIES COMPILE_FLAGS - -fno-var-tracking-assignments) +set_source_files_properties(src/InstructionDecoder-aarch64.C + PROPERTIES COMPILE_FLAGS -fno-var-tracking-assignments) endif() ADD_DEFINITIONS(-DINSTRUCTION_LIB) dyninst_library(instructionAPI common) -target_link_private_libraries(instructionAPI ${Boost_LIBRARIES}) +target_link_private_libraries(instructionAPI ${Boost_LIBRARIES} ${TBB_LIBRARIES} tbbmalloc) if (USE_COTIRE) cotire(instructionAPI) diff --git a/instructionAPI/h/ArchSpecificFormatters.h b/instructionAPI/h/ArchSpecificFormatters.h index 43b99d8476..9e7fc7318c 100644 --- a/instructionAPI/h/ArchSpecificFormatters.h +++ b/instructionAPI/h/ArchSpecificFormatters.h @@ -34,6 +34,7 @@ #include #include #include +#include namespace Dyninst { namespace InstructionAPI { @@ -46,6 +47,8 @@ namespace Dyninst { virtual std::string formatRegister(std::string) = 0; virtual std::string formatBinaryFunc(std::string, std::string, std::string); virtual ~ArchSpecificFormatter() {} + static INSTRUCTION_EXPORT ArchSpecificFormatter& getFormatter(Dyninst::Architecture a); + }; class PPCFormatter : public ArchSpecificFormatter { @@ -87,6 +90,7 @@ namespace Dyninst { virtual std::string formatBinaryFunc(std::string, std::string, std::string); virtual ~x86Formatter() {} }; + }; }; diff --git a/instructionAPI/h/BinaryFunction.h b/instructionAPI/h/BinaryFunction.h index 2104c4cc82..59841b8e3c 100644 --- a/instructionAPI/h/BinaryFunction.h +++ b/instructionAPI/h/BinaryFunction.h @@ -34,6 +34,7 @@ #include "Expression.h" #include "Register.h" #include "Result.h" +#include "ArchSpecificFormatters.h" #include #if defined(_MSC_VER) @@ -346,32 +347,33 @@ namespace Dyninst virtual std::string format(formatStyle how) const { - std::stringstream retVal; + std::string retVal; if(how == memoryAccessStyle) { - retVal << m_arg2->format() << "(" << m_arg1->format() << ")"; + retVal = m_arg2->format() + "(" + m_arg1->format() + ")"; } else { - retVal << m_arg1->format() << " " << m_funcPtr->format() << " " << m_arg2->format(); + retVal = m_arg1->format() + " " + m_funcPtr->format() + " " + m_arg2->format(); } - return retVal.str(); + return retVal; } - virtual std::string format(ArchSpecificFormatter *formatter, formatStyle how) const + virtual std::string format(Architecture arch, formatStyle how) const { - std::stringstream retVal; + std::string retVal; if(how == memoryAccessStyle) { - retVal << m_arg2->format(formatter) << "(" << m_arg1->format(formatter) << ")"; + retVal = m_arg2->format(arch) + "(" + m_arg1->format(arch) + ")"; } else { - return formatter->formatBinaryFunc(m_arg1->format(formatter), m_funcPtr->format(), m_arg2->format(formatter)); + return ArchSpecificFormatter::getFormatter(arch).formatBinaryFunc( + m_arg1->format(arch), m_funcPtr->format(), m_arg2->format(arch)); } - return retVal.str(); + return retVal; } virtual bool bind(Expression* expr, const Result& value); diff --git a/instructionAPI/h/Dereference.h b/instructionAPI/h/Dereference.h index 2b265295b9..5a4e65a510 100644 --- a/instructionAPI/h/Dereference.h +++ b/instructionAPI/h/Dereference.h @@ -37,6 +37,7 @@ #include "Immediate.h" #include "Register.h" #include "Visitor.h" +#include "ArchSpecificFormatters.h" #include @@ -107,54 +108,53 @@ namespace Dyninst virtual std::string format(formatStyle) const { - std::stringstream retVal; + std::string retVal; #if defined(DEBUG_MEMORY_ACCESS_WIDTH) switch(Expression::userSetValue.type) { case u8: - retVal << "u8 @ "; + retVal += "u8 @ "; break; case s8: - retVal << "s8 @ "; + retVal += "s8 @ "; break; case u16: - retVal << "u16 @ "; + retVal += "u16 @ "; break; case s16: - retVal << "s16 @ "; + retVal += "s16 @ "; break; case u32: - retVal << "u32 @ "; + retVal += "u32 @ "; break; case s32: - retVal << "s32 @ "; + retVal += "s32 @ "; break; case u64: - retVal << "u64 @ "; + retVal += "u64 @ "; break; case s64: - retVal << "s64 @ "; + retVal += "s64 @ "; break; case sp_float: - retVal << "float @ "; + retVal += "float @ "; break; case dp_float: - retVal << "double @ "; + retVal += "double @ "; break; case dbl128: - retVal << "packed double @ "; + retVal += "packed double @ "; break; default: - retVal << "UNKNOWN SIZE @ "; + retVal += "UNKNOWN SIZE @ "; break; } #endif - retVal << "[" << addressToDereference->format() << "]"; -// retVal << addressToDereference->format(memoryAccessStyle); - return retVal.str(); + retVal += "[" + addressToDereference->format() + "]"; + return retVal; } - virtual std::string format(ArchSpecificFormatter *formatter, formatStyle) const + virtual std::string format(Architecture arch, formatStyle) const { #if defined(DEBUG_MEMORY_ACCESS_WIDTH) switch(Expression::userSetValue.type) @@ -211,7 +211,7 @@ namespace Dyninst std::cout << "\tDisplacement: " << list.displacement << std::endl; #endif - return formatter->formatDeref(addressToDereference->format(formatter)); + return ArchSpecificFormatter::getFormatter(arch).formatDeref(addressToDereference->format(arch)); } virtual bool bind(Expression* expr, const Result& value) diff --git a/instructionAPI/h/Expression.h b/instructionAPI/h/Expression.h index de1c30208e..0908f76e5c 100644 --- a/instructionAPI/h/Expression.h +++ b/instructionAPI/h/Expression.h @@ -121,7 +121,7 @@ namespace Dyninst public: /// \brief A type definition for a reference counted pointer to a %Expression. typedef boost::shared_ptr Ptr; - friend class Operation; + friend class Operation_impl; protected: Expression(Result_Type t); Expression(MachRegister r); @@ -178,7 +178,7 @@ namespace Dyninst virtual void getChildren(vector& ) const {}; virtual void getUses(set& ) {}; virtual bool isUsed(InstructionAST::Ptr ) const { return true;}; - virtual std::string format(ArchSpecificFormatter *, formatStyle) const { return "[WILDCARD]";}; + virtual std::string format(Architecture, formatStyle) const { return "[WILDCARD]";}; virtual std::string format(formatStyle) const { return "[WILDCARD]";}; DummyExpr() : Expression(u8) {} protected: diff --git a/instructionAPI/h/Immediate.h b/instructionAPI/h/Immediate.h index c6446daace..6efc3fd59a 100644 --- a/instructionAPI/h/Immediate.h +++ b/instructionAPI/h/Immediate.h @@ -63,7 +63,7 @@ namespace Dyninst /// by another %InstructionAST if and only if the first %InstructionAST is a subtree of the second one. virtual bool isUsed(InstructionAST::Ptr findMe) const; - virtual std::string format(ArchSpecificFormatter *, formatStyle) const; + virtual std::string format(Architecture, formatStyle) const; virtual std::string format(formatStyle) const; static Immediate::Ptr makeImmediate(const Result& val); virtual void apply(Visitor* v); @@ -78,7 +78,7 @@ namespace Dyninst ArmConditionImmediate(const Result &val); static ArmConditionImmediate::Ptr makeArmConditionImmediate(const Result &val); - virtual std::string format(ArchSpecificFormatter *, formatStyle) const; + virtual std::string format(Architecture, formatStyle) const; virtual std::string format(formatStyle) const; private: @@ -91,7 +91,7 @@ namespace Dyninst ArmPrfmTypeImmediate(const Result &val); static Immediate::Ptr makeArmPrfmTypeImmediate(const Result &val); - virtual std::string format(ArchSpecificFormatter *, formatStyle) const; + virtual std::string format(Architecture, formatStyle) const; virtual std::string format(formatStyle) const; private: diff --git a/instructionAPI/h/Instruction.h b/instructionAPI/h/Instruction.h index 58337d8e8b..d8f49f3966 100644 --- a/instructionAPI/h/Instruction.h +++ b/instructionAPI/h/Instruction.h @@ -36,7 +36,7 @@ #include #include #include "Expression.h" -#include "Operation.h" +#include "Operation_impl.h" #include "Operand.h" #include "InstructionCategories.h" #include "ArchSpecificFormatters.h" @@ -119,7 +119,7 @@ namespace Dyninst /// which operands are read and written /// in the %Operation object \c what to the value computations in \c operandSource. - INSTRUCTION_EXPORT Instruction(Operation::Ptr what, size_t size, const unsigned char* raw, + INSTRUCTION_EXPORT Instruction(Operation what, size_t size, const unsigned char* raw, Dyninst::Architecture arch); INSTRUCTION_EXPORT Instruction(); @@ -132,6 +132,7 @@ namespace Dyninst /// \return The %Operation used by the %Instruction /// /// See Operation for details of the %Operation interface. + INSTRUCTION_EXPORT Operation& getOperation(); INSTRUCTION_EXPORT const Operation& getOperation() const; /// The vector \c operands has the instruction's operands appended to it @@ -198,7 +199,7 @@ namespace Dyninst /// \c readsMemory will return true for a pop operation. INSTRUCTION_EXPORT bool readsMemory() const; - INSTRUCTION_EXPORT ArchSpecificFormatter *getFormatter() const; + INSTRUCTION_EXPORT ArchSpecificFormatter& getFormatter() const; /// \return Returns true if the instruction writes at least one memory address. /// @@ -275,6 +276,21 @@ namespace Dyninst INSTRUCTION_EXPORT cftConstIter cft_end() const { return m_Successors.end(); } + INSTRUCTION_EXPORT bool operator<(const Instruction& rhs) const + { + if(m_size < rhs.m_size) return true; + if(m_size <= sizeof(m_RawInsn.small_insn)) { + return m_RawInsn.small_insn < rhs.m_RawInsn.small_insn; + } + return memcmp(m_RawInsn.large_insn, rhs.m_RawInsn.large_insn, m_size) < 0; + } + INSTRUCTION_EXPORT bool operator==(const Instruction& rhs) const { + if(m_size != rhs.m_size) return false; + if(m_size <= sizeof(m_RawInsn.small_insn)) { + return m_RawInsn.small_insn == rhs.m_RawInsn.small_insn; + } + return memcmp(m_RawInsn.large_insn, rhs.m_RawInsn.large_insn, m_size) == 0; + } typedef boost::shared_ptr Ptr; @@ -288,14 +304,14 @@ namespace Dyninst void copyRaw(size_t size, const unsigned char* raw); Expression::Ptr makeReturnExpression() const; mutable std::list m_Operands; - Operation::Ptr m_InsnOp; + mutable Operation m_InsnOp; bool m_Valid; raw_insn_T m_RawInsn; unsigned int m_size; Architecture arch_decoded_from; mutable std::list m_Successors; static int numInsnsAllocated; - ArchSpecificFormatter *formatter; + ArchSpecificFormatter& formatter; }; }; }; diff --git a/instructionAPI/h/InstructionAST.h b/instructionAPI/h/InstructionAST.h index 1b859dcf2c..813e5fc871 100644 --- a/instructionAPI/h/InstructionAST.h +++ b/instructionAPI/h/InstructionAST.h @@ -111,7 +111,7 @@ namespace Dyninst /// The \c format interface returns the contents of an %InstructionAST /// object as a string. By default, \c format() produces assembly language. - virtual std::string format(ArchSpecificFormatter *, formatStyle how = defaultStyle) const = 0; + virtual std::string format(Architecture arch, formatStyle how = defaultStyle) const = 0; /// The \c format interface returns the contents of an %InstructionAST /// object as a string. By default, \c format() produces assembly language. diff --git a/instructionAPI/h/InstructionDecoder.h b/instructionAPI/h/InstructionDecoder.h index 4a64c6576f..fdba154310 100644 --- a/instructionAPI/h/InstructionDecoder.h +++ b/instructionAPI/h/InstructionDecoder.h @@ -66,12 +66,12 @@ namespace Dyninst /// machine language of the type understood by this %InstructionDecoder. /// If the buffer does not contain a valid instruction stream, a null %Instruction pointer /// will be returned. The %Instruction's \c size field will contain the size of the instruction decoded. - Instruction::Ptr decode(); + Instruction decode(); /// Decode the instruction at \c buffer, interpreting it as machine language of the type /// understood by this %InstructionDecoder. If the buffer does not contain a valid instruction stream, /// a null %Instruction pointer will be returned. The %Instruction's \c size field will contain /// the size of the instruction decoded. - Instruction::Ptr decode(const unsigned char* buffer); + Instruction decode(const unsigned char *buffer); void doDelayedDecode(const Instruction* insn_to_complete); struct INSTRUCTION_EXPORT buffer { diff --git a/instructionAPI/h/Operand.h b/instructionAPI/h/Operand.h index 9404d6bce9..ec551a64e8 100644 --- a/instructionAPI/h/Operand.h +++ b/instructionAPI/h/Operand.h @@ -123,10 +123,6 @@ namespace Dyninst INSTRUCTION_EXPORT void addEffectiveWriteAddresses(std::set& memAccessors) const; /// \brief Return a printable string representation of the operand. /// \return The operand in a disassembly format - INSTRUCTION_EXPORT std::string format(ArchSpecificFormatter *formatter, Architecture arch, Address addr = 0) const; - - /// \brief Return a printable string representation of the operand. Please use the updated function instead. - /// \return The operand in a dissassembly format. INSTRUCTION_EXPORT std::string format(Architecture arch, Address addr = 0) const; /// The \c getValue method returns an %Expression::Ptr to the AST contained by the operand. diff --git a/instructionAPI/h/Operation.h b/instructionAPI/h/Operation_impl.h similarity index 73% rename from instructionAPI/h/Operation.h rename to instructionAPI/h/Operation_impl.h index 75ef36ad5b..b4d4061c1a 100644 --- a/instructionAPI/h/Operation.h +++ b/instructionAPI/h/Operation_impl.h @@ -36,8 +36,12 @@ #include "entryIDs.h" #include "Result.h" #include +#include #include "util.h" +#include +#include +#include // OpCode = operation + encoding // contents: @@ -90,28 +94,27 @@ namespace Dyninst /// %Operations are constructed by the %InstructionDecoder as part of the process /// of constructing an %Instruction. - class Operation + class Operation_impl : public boost::lockable_adapter { public: typedef std::set registerSet; typedef std::set VCSet; - typedef boost::shared_ptr Ptr; friend class InstructionDecoder_power; // for editing mnemonics after creation friend class InstructionDecoder_aarch64; public: - INSTRUCTION_EXPORT Operation(NS_x86::ia32_entry* e, NS_x86::ia32_prefixes* p = NULL, ia32_locations* l = NULL, + INSTRUCTION_EXPORT Operation_impl(NS_x86::ia32_entry* e, NS_x86::ia32_prefixes* p = NULL, ia32_locations* l = NULL, Architecture arch = Arch_none); - INSTRUCTION_EXPORT Operation(const Operation& o); - INSTRUCTION_EXPORT Operation(); - INSTRUCTION_EXPORT Operation(entryID id, const char* mnem, Architecture arch); + INSTRUCTION_EXPORT Operation_impl(const Operation_impl& o); + INSTRUCTION_EXPORT Operation_impl(); + INSTRUCTION_EXPORT Operation_impl(entryID id, std::string m, Architecture arch); - INSTRUCTION_EXPORT const Operation& operator=(const Operation& o); + INSTRUCTION_EXPORT const Operation_impl& operator=(const Operation_impl& o); /// Returns the set of registers implicitly read (i.e. those not included in the operands, but read anyway) - INSTRUCTION_EXPORT const registerSet& implicitReads() const; + INSTRUCTION_EXPORT const registerSet& implicitReads() ; /// Returns the set of registers implicitly written (i.e. those not included in the operands, but written anyway) - INSTRUCTION_EXPORT const registerSet& implicitWrites() const; + INSTRUCTION_EXPORT const registerSet& implicitWrites() ; /// Returns the mnemonic for the operation. Like \c instruction::format, this is exposed for debugging /// and will be replaced with stream operators in the public interface. INSTRUCTION_EXPORT std::string format() const; @@ -123,31 +126,56 @@ namespace Dyninst INSTRUCTION_EXPORT prefixEntryID getPrefixID() const; /// Returns true if the expression represented by \c candidate is read implicitly. - INSTRUCTION_EXPORT bool isRead(Expression::Ptr candidate) const; + INSTRUCTION_EXPORT bool isRead(Expression::Ptr candidate) ; /// Returns true if the expression represented by \c candidate is written implicitly. - INSTRUCTION_EXPORT bool isWritten(Expression::Ptr candidate) const; + INSTRUCTION_EXPORT bool isWritten(Expression::Ptr candidate) ; /// Returns the set of memory locations implicitly read. - INSTRUCTION_EXPORT const VCSet& getImplicitMemReads() const; + INSTRUCTION_EXPORT const VCSet& getImplicitMemReads() ; /// Returns the set of memory locations implicitly written. + INSTRUCTION_EXPORT const VCSet& getImplicitMemWrites() ; + friend std::size_t hash_value(Operation_impl const& op) + { + size_t seed = 0; + boost::hash_combine(seed, op.operationID); + boost::hash_combine(seed, op.prefixID); + boost::hash_combine(seed, op.archDecodedFrom); + boost::hash_combine(seed, op.addrWidth); + boost::hash_combine(seed, op.segPrefix); + boost::hash_combine(seed, op.isVectorInsn); + return seed; + } + bool operator==(const Operation_impl& rhs) const { + return hash_value(*this) == hash_value(rhs); + } INSTRUCTION_EXPORT const VCSet& getImplicitMemWrites() const; bool isVectorInsn; private: - void SetUpNonOperandData(bool doFlags = false) const; + std::once_flag data_initialized; + void SetUpNonOperandData(bool doFlags = false) ; mutable registerSet otherRead; mutable registerSet otherWritten; mutable VCSet otherEffAddrsRead; mutable VCSet otherEffAddrsWritten; - mutable std::string mnemonic; - mutable entryID operationID; - mutable bool doneOtherSetup; - mutable bool doneFlagsSetup; + + protected: + mutable entryID operationID; Architecture archDecodedFrom; prefixEntryID prefixID; Result_Type addrWidth; + int segPrefix; + mutable std::string mnemonic; + }; + struct Operation: public Operation_impl { + Operation(entryID id, std::string m, Architecture arch) + : Operation_impl(id, m, arch) {} + Operation(NS_x86::ia32_entry* e, NS_x86::ia32_prefixes* p = NULL, ia32_locations* l = NULL, + Architecture arch = Arch_none) : Operation_impl(e, p, l, arch) {} + Operation() : Operation_impl() {} + }; }; }; diff --git a/instructionAPI/h/Register.h b/instructionAPI/h/Register.h index f9d50e3bb4..307985f3cd 100644 --- a/instructionAPI/h/Register.h +++ b/instructionAPI/h/Register.h @@ -75,7 +75,7 @@ namespace Dyninst virtual bool isUsed(InstructionAST::Ptr findMe) const; /// The \c format method on a %RegisterAST object returns the name associated with its ID. - virtual std::string format(ArchSpecificFormatter *, formatStyle how = defaultStyle) const; + virtual std::string format(Architecture, formatStyle how = defaultStyle) const; /// The \c format method on a %RegisterAST object returns the name associated with its ID. virtual std::string format(formatStyle how = defaultStyle) const; @@ -128,8 +128,8 @@ namespace Dyninst : RegisterAST(r, lowbit, highbit) {} MaskRegisterAST(MachRegister r, unsigned int lowbit, unsigned int highbit, Result_Type regType) : RegisterAST(r, lowbit, highbit, regType) {} + virtual std::string format(Architecture, formatStyle how = defaultStyle) const; - virtual std::string format(ArchSpecificFormatter *formatter, formatStyle how = defaultStyle) const; virtual std::string format(formatStyle how = defaultStyle) const; }; }; diff --git a/instructionAPI/h/Result.h b/instructionAPI/h/Result.h index 2a365ef49b..a3d6d12932 100644 --- a/instructionAPI/h/Result.h +++ b/instructionAPI/h/Result.h @@ -424,81 +424,77 @@ namespace Dyninst } else { - std::stringstream ret; -// ret << std::hex << "0x"; - ret << std::hex; + char hex[20]; switch(type) { case u8: - // Type promote the characters so that they're treated as integral, not as strings - ret << (long)(val.u8val); + snprintf(hex, 20, "%x", val.u8val); break; case s8: - ret << (long)(val.s8val); + snprintf(hex, 20, "%x", val.s8val); break; case u16: - ret << val.u16val; + snprintf(hex, 20, "%x", val.u16val); break; case s16: - ret << val.s16val; + snprintf(hex, 20, "%x", val.s16val); break; case u24: - ret << val.u24val; + snprintf(hex, 20, "%x", val.u24val); break; case u32: - ret << val.u32val; + snprintf(hex, 20, "%x", val.u32val); break; case s32: - ret << val.s32val; + snprintf(hex, 20, "%x", val.s32val); break; case u64: - ret << val.u64val; + snprintf(hex, 20, "%lx", val.u64val); break; case s64: - ret << val.s64val; + snprintf(hex, 20, "%lx", val.s64val); break; case sp_float: - ret << val.floatval; + snprintf(hex, 20, "%f", val.floatval); break; case dp_float: - ret << val.dblval; + snprintf(hex, 20, "%lf", val.dblval); break; case bit_flag: - ret << val.bitval; + snprintf(hex, 20, "%x", val.bitval); break; case u48: - ret << val.u48val; + snprintf(hex, 20, "%lx", val.s48val); break; case s48: - ret << val.s48val; + snprintf(hex, 20, "%lx", val.s48val); break; case m512: - ret << val.m512val; + snprintf(hex, 20, "%p", val.m512val); break; case m14: - ret << val.m14val; + snprintf(hex, 20, "%p", val.m14val); break; case m96: - ret << val.m96val; + snprintf(hex, 20, "%p", val.m96val); break; case dbl128: - ret << val.dbl128val; + snprintf(hex, 20, "%p", val.dbl128val); break; case m192: - ret << val.m192val; + snprintf(hex, 20, "%p", val.m192val); break; case m256: - ret << val.m256val; + snprintf(hex, 20, "%p", val.m256val); break; case m384: - ret << val.m384val; + snprintf(hex, 20, "%p", val.m384val); break; default: - ret << "[ERROR: invalid type value!]"; + snprintf(hex, 20, "[invalid type]"); break; }; - ret << std::dec; - return ret.str(); + return std::string(hex); } } diff --git a/instructionAPI/src/ArchSpecificFormatters.C b/instructionAPI/src/ArchSpecificFormatters.C index 4a2491ace5..b1c0bc8427 100644 --- a/instructionAPI/src/ArchSpecificFormatters.C +++ b/instructionAPI/src/ArchSpecificFormatters.C @@ -65,18 +65,18 @@ std::string PPCFormatter::formatDeref(std::string addrString) { } std::string PPCFormatter::getInstructionString(std::vector operands) { - std::stringstream out; + std::string out; for(std::vector::iterator itr = operands.begin(); itr != operands.end(); itr++) { if (*itr != "") { - out<<*itr; + out += *itr; if(itr != operands.end() - 1) { - out<<", "; + out += ", "; } } } - return out.str(); + return out; } std::string PPCFormatter::formatBinaryFunc(std::string left, std::string func, std::string right) { @@ -111,32 +111,32 @@ std::string ArmFormatter::formatRegister(std::string regName) { } std::string ArmFormatter::formatDeref(std::string addrString) { - std::stringstream out; + std::string out; size_t pluspos = addrString.find("+"); if(pluspos != std::string::npos && addrString.substr(0, pluspos - 1) == "PC") { - out< operands) { - std::stringstream out; + std::string out; for(std::vector::iterator itr = operands.begin(); itr != operands.end(); itr++) { - out<<*itr; + out += *itr; if(itr != operands.end() - 1) - out<<", "; + out += ", "; } - return out.str(); + return out; } std::string ArmFormatter::formatBinaryFunc(std::string left, std::string func, std::string right) { @@ -181,19 +181,9 @@ std::string x86Formatter::formatRegister(std::string regName) /* convert to a standard string */ regName = pointer; free(orig); - - std::stringstream ss; - ss << "%" << regName; - regName = ss.str(); - - // if(!regName.compare(1, 1, "k")) - // { - // std::stringstream kss; - // kss << "{" << regName << "}" ; - // regName = kss.str(); - // } - - return ss.str(); + std::string ss = "%" + regName; + regName = ss; + return ss; } std::string x86Formatter::formatDeref(std::string addrString) @@ -232,9 +222,7 @@ std::string x86Formatter::getInstructionString(std::vector operands /* If we still have a leading ##, it's an indirect call or SIB expression */ if(!op.compare(0, 2, "##")) { - std::stringstream ss; - ss << "0x0(" << op.substr(2) << ")"; - op = ss.str(); + op = "0x0(" + op.substr(2) + ")"; } if(itr == operands.begin()) @@ -252,16 +240,11 @@ std::string x86Formatter::getInstructionString(std::vector operands } /* Put the instruction together */ - std::stringstream ss; - - ss << source_ops; - if(ss.str().compare("")) - ss << ","; - ss << dest_op; - ss << kmask_op; - - /* Return the formatted instruction */ - return ss.str(); + std::string ret = source_ops; + if (ret.compare("")) ret += ","; + ret += dest_op; + ret += kmask_op; + return ret; } std::string x86Formatter::formatBinaryFunc(std::string left, std::string func, std::string right) @@ -311,14 +294,16 @@ std::string x86Formatter::formatBinaryFunc(std::string left, std::string func, s uintptr_t offset = strtoul(left.c_str() + 1, NULL, 16); uintptr_t result = edit_l + offset; - std::stringstream ss; - ss << "0x" << std::hex << result << "(%rip)"; + std::string ss; + char hex[20]; + snprintf(hex, 20, "%lx", result); + ss = "0x" + std::string(hex) + "(%rip)"; /* Free allocations */ free(edit_f); /* Return the processed string */ - return ss.str(); + return ss; } else { /* This is the simplest for of a dereference e.g. 0x1(%eax) */ @@ -337,3 +322,25 @@ std::string x86Formatter::formatBinaryFunc(std::string left, std::string func, s } /////////////////////////// +ArchSpecificFormatter& ArchSpecificFormatter::getFormatter(Architecture a) +{ + static dyn_tls std::map > theFormatters; + auto found = theFormatters.find(a); + if(found != theFormatters.end()) return *found->second; + switch(a) { + case Arch_aarch32: + case Arch_aarch64: + theFormatters[a] = boost::shared_ptr(new ArmFormatter()); + break; + case Arch_ppc32: + case Arch_ppc64: + theFormatters[a] = boost::shared_ptr(new PPCFormatter()); + break; + case Arch_x86: + case Arch_x86_64: + default: + theFormatters[a] = boost::shared_ptr(new x86Formatter()); + break; + } + return *theFormatters[a]; +} diff --git a/instructionAPI/src/Immediate.C b/instructionAPI/src/Immediate.C index d9a19f0192..6107238614 100644 --- a/instructionAPI/src/Immediate.C +++ b/instructionAPI/src/Immediate.C @@ -35,6 +35,7 @@ #include "Immediate.h" #include "../../common/src/singleton_object_pool.h" #include "Visitor.h" +#include "ArchSpecificFormatters.h" #include namespace Dyninst { @@ -67,8 +68,8 @@ namespace Dyninst { return; } - std::string Immediate::format(ArchSpecificFormatter *formatter, formatStyle) const { - return formatter->formatImmediate(eval().format()); + std::string Immediate::format(Architecture arch, formatStyle) const { + return ArchSpecificFormatter::getFormatter(arch).formatImmediate(eval().format()); } std::string Immediate::format(formatStyle) const { @@ -94,12 +95,8 @@ namespace Dyninst { return ret; } - std::string ArmConditionImmediate::format(ArchSpecificFormatter *, formatStyle) const { - unsigned int cond_val = eval().convert(); - if(m_condLookupMap.count(cond_val) > 0) - return m_condLookupMap.find(cond_val)->second; - else - return "Error: Invalid condition code for ARM64!"; + std::string ArmConditionImmediate::format(Architecture, formatStyle f) const { + return format(f); } std::string ArmConditionImmediate::format(formatStyle) const { @@ -119,12 +116,8 @@ namespace Dyninst { return ret; } - std::string ArmPrfmTypeImmediate::format(ArchSpecificFormatter *, formatStyle) const { - unsigned prfm_type = eval().convert(); - if(m_prfmTypeLookupMap.count(prfm_type) > 0) - return m_prfmTypeLookupMap.find(prfm_type)->second; - else - return "Error: Invalid prefetech memory type for ARM64!"; + std::string ArmPrfmTypeImmediate::format(Architecture, formatStyle f) const { + return format(f); } std::string ArmPrfmTypeImmediate::format(formatStyle) const { diff --git a/instructionAPI/src/Instruction.C b/instructionAPI/src/Instruction.C index 5f0e7c8430..e3446b7206 100644 --- a/instructionAPI/src/Instruction.C +++ b/instructionAPI/src/Instruction.C @@ -37,7 +37,7 @@ #include "../h/InstructionCategories.h" #include "../h/Instruction.h" #include "../h/Register.h" -#include "../h/Operation.h" +#include "Operation_impl.h" #include "InstructionDecoder.h" #include "Dereference.h" #include @@ -54,6 +54,7 @@ using namespace std; using namespace NS_x86; #include "../../common/src/singleton_object_pool.h" +#include "ArchSpecificFormatters.h" namespace Dyninst { @@ -72,26 +73,12 @@ namespace Dyninst } int Instruction::numInsnsAllocated = 0; - INSTRUCTION_EXPORT Instruction::Instruction(Operation::Ptr what, + INSTRUCTION_EXPORT Instruction::Instruction(Operation what, size_t size, const unsigned char* raw, Dyninst::Architecture arch) - : m_InsnOp(what), m_Valid(true), arch_decoded_from(arch) + : m_InsnOp(what), m_Valid(true), arch_decoded_from(arch), + formatter(ArchSpecificFormatter::getFormatter(arch)) { - switch(arch_decoded_from) { - case Arch_aarch64: - formatter = new ArmFormatter(); - break; - case Arch_x86_64: - case Arch_x86: - formatter = new x86Formatter(); - break; - case Arch_ppc64: - case Arch_ppc32: - formatter = new PPCFormatter(); - break; - default:formatter = NULL; - break; - } copyRaw(size, raw); #if defined(DEBUG_INSN_ALLOCATIONS) @@ -135,7 +122,7 @@ namespace Dyninst } INSTRUCTION_EXPORT Instruction::Instruction() : - m_Valid(false), m_size(0), arch_decoded_from(Arch_none), formatter(NULL) + m_Valid(false), m_size(0), arch_decoded_from(Arch_none), formatter(ArchSpecificFormatter::getFormatter(Arch_x86_64)) { #if defined(DEBUG_INSN_ALLOCATIONS) numInsnsAllocated++; @@ -154,8 +141,6 @@ namespace Dyninst delete[] m_RawInsn.large_insn; } - if(formatter) - delete formatter; #if defined(DEBUG_INSN_ALLOCATIONS) numInsnsAllocated--; if((numInsnsAllocated % 1000) == 0) @@ -166,9 +151,13 @@ namespace Dyninst } INSTRUCTION_EXPORT Instruction::Instruction(const Instruction& o) : - arch_decoded_from(o.arch_decoded_from) + arch_decoded_from(o.arch_decoded_from), + m_Operands(o.m_Operands), + m_InsnOp(o.m_InsnOp), + m_Valid(o.m_Valid), + formatter(o.formatter) + { - m_Operands = o.m_Operands; m_size = o.m_size; if(o.m_size > sizeof(m_RawInsn.small_insn)) { @@ -180,9 +169,7 @@ namespace Dyninst m_RawInsn.small_insn = o.m_RawInsn.small_insn; } - m_InsnOp = o.m_InsnOp; - m_Valid = o.m_Valid; - formatter = o.formatter; + m_Successors = o.m_Successors; #if defined(DEBUG_INSN_ALLOCATIONS) numInsnsAllocated++; @@ -219,6 +206,7 @@ namespace Dyninst m_Valid = rhs.m_Valid; formatter = rhs.formatter; arch_decoded_from = rhs.arch_decoded_from; + m_Successors = rhs.m_Successors; return *this; } @@ -227,11 +215,15 @@ namespace Dyninst return m_Valid; } - INSTRUCTION_EXPORT const Operation& Instruction::getOperation() const + INSTRUCTION_EXPORT Operation& Instruction::getOperation() { - return *m_InsnOp; + return m_InsnOp; } - + INSTRUCTION_EXPORT const Operation& Instruction::getOperation() const + { + return m_InsnOp; + } + INSTRUCTION_EXPORT void Instruction::getOperands(std::vector& operands) const { if(m_Operands.empty()) @@ -301,7 +293,8 @@ namespace Dyninst { curOperand->getReadSet(regsRead); } - std::copy(m_InsnOp->implicitReads().begin(), m_InsnOp->implicitReads().end(), std::inserter(regsRead, regsRead.begin())); + std::copy(m_InsnOp.implicitReads().begin(), m_InsnOp.implicitReads().end(), + std::inserter(regsRead, regsRead.begin())); } @@ -317,8 +310,8 @@ namespace Dyninst { curOperand->getWriteSet(regsWritten); } - std::copy(m_InsnOp->implicitWrites().begin(), m_InsnOp->implicitWrites().end(), std::inserter(regsWritten, -regsWritten.begin())); + std::copy(m_InsnOp.implicitWrites().begin(), m_InsnOp.implicitWrites().end(), + std::inserter(regsWritten, regsWritten.begin())); } @@ -337,7 +330,7 @@ regsWritten.begin())); return true; } } - return m_InsnOp->isRead(candidate); + return m_InsnOp.isRead(candidate); } INSTRUCTION_EXPORT bool Instruction::isWritten(Expression::Ptr candidate) const @@ -355,7 +348,7 @@ regsWritten.begin())); return true; } } - return m_InsnOp->isWritten(candidate); + return m_InsnOp.isWritten(candidate); } INSTRUCTION_EXPORT bool Instruction::readsMemory() const @@ -377,7 +370,7 @@ regsWritten.begin())); return true; } } - return !m_InsnOp->getImplicitMemReads().empty(); + return !m_InsnOp.getImplicitMemReads().empty(); } INSTRUCTION_EXPORT bool Instruction::writesMemory() const @@ -395,7 +388,7 @@ regsWritten.begin())); return true; } } - return !m_InsnOp->getImplicitMemWrites().empty(); + return !m_InsnOp.getImplicitMemWrites().empty(); } INSTRUCTION_EXPORT void Instruction::getMemoryReadOperands(std::set& memAccessors) const @@ -410,7 +403,7 @@ regsWritten.begin())); { curOperand->addEffectiveReadAddresses(memAccessors); } - std::copy(m_InsnOp->getImplicitMemReads().begin(), m_InsnOp->getImplicitMemReads().end(), std::inserter(memAccessors, + std::copy(m_InsnOp.getImplicitMemReads().begin(), m_InsnOp.getImplicitMemReads().end(), std::inserter(memAccessors, memAccessors.begin())); } @@ -426,7 +419,7 @@ memAccessors.begin())); { curOperand->addEffectiveWriteAddresses(memAccessors); } - std::copy(m_InsnOp->getImplicitMemWrites().begin(), m_InsnOp->getImplicitMemWrites().end(), std::inserter(memAccessors, + std::copy(m_InsnOp.getImplicitMemWrites().begin(), m_InsnOp.getImplicitMemWrites().end(), std::inserter(memAccessors, memAccessors.begin())); } @@ -457,7 +450,7 @@ memAccessors.begin())); return m_Successors.front().target; } - INSTRUCTION_EXPORT ArchSpecificFormatter *Instruction::getFormatter() const { + INSTRUCTION_EXPORT ArchSpecificFormatter& Instruction::getFormatter() const { return formatter; } @@ -469,10 +462,8 @@ memAccessors.begin())); } //remove this once ArchSpecificFormatter is extended for all architectures - if(formatter == NULL) - return ""; - std::string opstr = m_InsnOp->format(); + std::string opstr = m_InsnOp.format(); opstr += " "; std::list::const_iterator currOperand; std::vector formattedOperands; @@ -485,7 +476,7 @@ memAccessors.begin())); if(currOperand->isImplicit()) continue; - formattedOperands.push_back(currOperand->format(formatter, getArch(), addr)); + formattedOperands.push_back(currOperand->format(getArch(), addr)); } #if defined(DEBUG_READ_WRITE) @@ -531,12 +522,12 @@ memAccessors.begin())); cout << endl; #endif // defined(DEBUG_READ_WRITE) - return opstr + formatter->getInstructionString(formattedOperands); + return opstr + formatter.getInstructionString(formattedOperands); } INSTRUCTION_EXPORT bool Instruction::allowsFallThrough() const { - switch(m_InsnOp->getID()) + switch(m_InsnOp.getID()) { case e_ret_far: case e_ret_near: @@ -580,11 +571,12 @@ memAccessors.begin())); return m_Successors.empty(); } } - + // can't happen but make the compiler happy + return false; } INSTRUCTION_EXPORT bool Instruction::isLegalInsn() const { - return (m_InsnOp->getID() != e_No_Entry); + return (m_InsnOp.getID() != e_No_Entry); } INSTRUCTION_EXPORT Architecture Instruction::getArch() const { @@ -600,8 +592,8 @@ memAccessors.begin())); } INSTRUCTION_EXPORT InsnCategory Instruction::getCategory() const { - if(m_InsnOp->isVectorInsn) return c_VectorInsn; - InsnCategory c = entryToCategory(m_InsnOp->getID()); + if(m_InsnOp.isVectorInsn) return c_VectorInsn; + InsnCategory c = entryToCategory(m_InsnOp.getID()); if(c == c_BranchInsn && (arch_decoded_from == Arch_ppc32 || arch_decoded_from == Arch_ppc64)) { if(m_Operands.empty()) decodeOperands(); @@ -614,7 +606,7 @@ memAccessors.begin())); return c_CallInsn; } } - if(m_InsnOp->getID() == power_op_bclr) + if(m_InsnOp.getID() == power_op_bclr) { return c_ReturnInsn; } diff --git a/instructionAPI/src/InstructionAST.C b/instructionAPI/src/InstructionAST.C index 0e9d237eb7..046911081d 100644 --- a/instructionAPI/src/InstructionAST.C +++ b/instructionAPI/src/InstructionAST.C @@ -36,6 +36,8 @@ namespace Dyninst { namespace InstructionAPI { + static DummyExpr dummyExpr; + InstructionAST::InstructionAST() { } @@ -48,9 +50,8 @@ namespace Dyninst { // isStrictEqual assumes rhs and this to be of the same derived type // so isSameType enforces this restriction - static DummyExpr d; - if((typeid(*this) == typeid(d)) || - (typeid(rhs) == typeid(d))) + if((typeid(*this) == typeid(dummyExpr)) || + (typeid(rhs) == typeid(dummyExpr))) { return true; } diff --git a/instructionAPI/src/InstructionDecoder-aarch64.C b/instructionAPI/src/InstructionDecoder-aarch64.C index b2432fa2fd..7c2e7a80a1 100644 --- a/instructionAPI/src/InstructionDecoder-aarch64.C +++ b/instructionAPI/src/InstructionDecoder-aarch64.C @@ -164,9 +164,9 @@ namespace Dyninst { using namespace std; - Instruction::Ptr InstructionDecoder_aarch64::decode(InstructionDecoder::buffer &b) { + Instruction InstructionDecoder_aarch64::decode(InstructionDecoder::buffer &b) { if (b.start > b.end) - return Instruction::Ptr(); + return Instruction(); isPstateRead = isPstateWritten = false; isFPInsn = false; @@ -214,7 +214,7 @@ namespace Dyninst { mainDecode(); b.start += 4; - return make_shared(insn_in_progress); + return *insn_in_progress; } /* replace this function with a more generic function, which is setRegWidth @@ -3098,7 +3098,7 @@ Expression::Ptr InstructionDecoder_aarch64::makeMemRefExPair2(){ } insn_in_progress->arch_decoded_from = Arch_aarch64; - insn_in_progress->m_InsnOp->isVectorInsn = + insn_in_progress->m_InsnOp.isVectorInsn = (*(insn_table_entry->operands.begin()) == &InstructionDecoder_aarch64::setSIMDMode); return; } diff --git a/instructionAPI/src/InstructionDecoder-aarch64.h b/instructionAPI/src/InstructionDecoder-aarch64.h index f35edefe77..aa36d1164d 100644 --- a/instructionAPI/src/InstructionDecoder-aarch64.h +++ b/instructionAPI/src/InstructionDecoder-aarch64.h @@ -59,7 +59,7 @@ namespace Dyninst { virtual void decodeOpcode(InstructionDecoder::buffer &b); - virtual Instruction::Ptr decode(InstructionDecoder::buffer &b); + virtual Instruction decode(InstructionDecoder::buffer &b); virtual void setMode(bool) { } diff --git a/instructionAPI/src/InstructionDecoder-power.C b/instructionAPI/src/InstructionDecoder-power.C index 3456e60375..e28699c2ac 100644 --- a/instructionAPI/src/InstructionDecoder-power.C +++ b/instructionAPI/src/InstructionDecoder-power.C @@ -31,7 +31,7 @@ #include "InstructionDecoder-power.h" #include #include "../../common/src/singleton_object_pool.h" - +#include namespace Dyninst { namespace InstructionAPI @@ -69,7 +69,6 @@ namespace Dyninst nextTableFunc next_table; operandSpec operands; static void buildTables(); - static bool built_tables; static std::vector main_opcode_table; static power_table extended_op_0; static power_table extended_op_4; @@ -244,9 +243,9 @@ namespace Dyninst } using namespace std; - Instruction::Ptr InstructionDecoder_power::decode(InstructionDecoder::buffer& b) + Instruction InstructionDecoder_power::decode(InstructionDecoder::buffer& b) { - if(b.start > b.end) return Instruction::Ptr(); + if(b.start > b.end) return Instruction(); isRAWritten = false; isFPInsn = false; bcIsConditional = false; @@ -260,7 +259,7 @@ namespace Dyninst #endif mainDecode(); b.start += 4; - return make_shared(insn_in_progress); + return *insn_in_progress; } bool InstructionDecoder_power::decodeOperands(const Instruction*) @@ -803,36 +802,62 @@ using namespace boost::assign; unsigned int xo = field<26, 30>(insn); if(xo <= 31) { - return power_entry::extended_op_0[xo]; + const power_table::const_iterator entry_it = power_entry::extended_op_0.find(xo); + if (entry_it == power_entry::extended_op_0.end()) + return invalid_entry; + return entry_it->second; } - return power_entry::extended_op_0[field<21, 30>(insn)]; + const power_table::const_iterator entry_it = power_entry::extended_op_0.find(field<21, 30>(insn)); + if (entry_it == power_entry::extended_op_0.end()) + return invalid_entry; + return entry_it->second; } const power_entry& InstructionDecoder_power::extended_op_4() { - return power_entry::extended_op_4[field<26, 30>(insn)]; + const power_table::const_iterator entry_it = power_entry::extended_op_4.find(field<26, 30>(insn)); + if (entry_it == power_entry::extended_op_4.end()) + return invalid_entry; + return entry_it->second; } const power_entry& InstructionDecoder_power::extended_op_19() { - return power_entry::extended_op_19[field<21, 30>(insn)]; + const power_table::const_iterator entry_it = power_entry::extended_op_19.find(field<21, 30>(insn)); + if (entry_it == power_entry::extended_op_19.end()) + return invalid_entry; + return entry_it->second; } const power_entry& InstructionDecoder_power::extended_op_30() { - return power_entry::extended_op_30[field<27, 29>(insn)]; + const power_table::const_iterator entry_it = power_entry::extended_op_30.find(field<27, 29>(insn)); + if (entry_it == power_entry::extended_op_30.end()) + return invalid_entry; + return entry_it->second; } const power_entry& InstructionDecoder_power::extended_op_31() { // sradi is a special instruction. Its xop is from 21 to 29 and its xop value is 413 if (field<21,29>(insn) == 413) { - return power_entry::extended_op_31[413]; + const power_table::const_iterator entry_it = power_entry::extended_op_31.find(413); + if (entry_it == power_entry::extended_op_31.end()) + return invalid_entry; + return entry_it->second; } - const power_entry& xoform_entry = power_entry::extended_op_31[field<22, 30>(insn)]; - if(find(xoform_entry.operands.begin(), xoform_entry.operands.end(), &InstructionDecoder_power::OE) - != xoform_entry.operands.end()) + const power_entry* xoform_entry; + const power_table::const_iterator entry_it = power_entry::extended_op_31.find(field<22, 30>(insn)); + if (entry_it == power_entry::extended_op_31.end()) + xoform_entry = &invalid_entry; + else + xoform_entry = &(entry_it->second); + if(find(xoform_entry->operands.begin(), xoform_entry->operands.end(), &InstructionDecoder_power::OE) + != xoform_entry->operands.end()) { - return xoform_entry; + return *xoform_entry; } - return power_entry::extended_op_31[field<21, 30>(insn)]; + const power_table::const_iterator entry_it2 = power_entry::extended_op_31.find(field<21, 30>(insn)); + if (entry_it2 == power_entry::extended_op_31.end()) + return invalid_entry; + return entry_it2->second; } // extended_op_57 needs revisiting const power_entry& InstructionDecoder_power::extended_op_57() @@ -841,11 +866,17 @@ using namespace boost::assign; } const power_entry& InstructionDecoder_power::extended_op_58() { - return power_entry::extended_op_58[field<30, 31>(insn)]; + const power_table::const_iterator entry_it = power_entry::extended_op_58.find(field<30, 31>(insn)); + if (entry_it == power_entry::extended_op_58.end()) + return invalid_entry; + return entry_it->second; } const power_entry& InstructionDecoder_power::extended_op_59() { - return power_entry::extended_op_59[field<26, 30>(insn)]; + const power_table::const_iterator entry_it = power_entry::extended_op_59.find(field<26, 30>(insn)); + if (entry_it == power_entry::extended_op_59.end()) + return invalid_entry; + return entry_it->second; } // extended_op_60 needs revisiting const power_entry& InstructionDecoder_power::extended_op_60() @@ -875,7 +906,10 @@ using namespace boost::assign; if(found != power_entry::extended_op_63.end()) return found->second; } - return power_entry::extended_op_63[field<21, 30>(insn)]; + const power_table::const_iterator entry_it = power_entry::extended_op_63.find(field<21, 30>(insn)); + if (entry_it == power_entry::extended_op_63.end()) + return invalid_entry; + return entry_it->second; } void InstructionDecoder_power::BF() @@ -1143,7 +1177,7 @@ using namespace boost::assign; insn_in_progress->arch_decoded_from = m_Arch; //insn_in_progress->arch_decoded_from = Arch_ppc32; if(field<0,5>(insn) == 0x04) { - insn_in_progress->m_InsnOp->isVectorInsn = true; + insn_in_progress->m_InsnOp.isVectorInsn = true; } return; } diff --git a/instructionAPI/src/InstructionDecoder-power.h b/instructionAPI/src/InstructionDecoder-power.h index 526f474ee6..45168a3fc4 100644 --- a/instructionAPI/src/InstructionDecoder-power.h +++ b/instructionAPI/src/InstructionDecoder-power.h @@ -47,7 +47,7 @@ namespace Dyninst { InstructionDecoder_power(Architecture a); virtual ~InstructionDecoder_power(); virtual void decodeOpcode(InstructionDecoder::buffer& b); - virtual Instruction::Ptr decode(InstructionDecoder::buffer& b); + virtual Instruction decode(InstructionDecoder::buffer& b); virtual void setMode(bool) { } diff --git a/instructionAPI/src/InstructionDecoder-x86.C b/instructionAPI/src/InstructionDecoder-x86.C index e2945bc9fc..35352f5368 100644 --- a/instructionAPI/src/InstructionDecoder-x86.C +++ b/instructionAPI/src/InstructionDecoder-x86.C @@ -133,25 +133,26 @@ namespace Dyninst } - TLS_VAR NS_x86::ia32_instruction* InstructionDecoder_x86::decodedInstruction = NULL; - TLS_VAR ia32_locations* InstructionDecoder_x86::locs = NULL; - TLS_VAR bool InstructionDecoder_x86::sizePrefixPresent = false; - TLS_VAR bool InstructionDecoder_x86::addrSizePrefixPresent = false; INSTRUCTION_EXPORT InstructionDecoder_x86::InstructionDecoder_x86(Architecture a) : - InstructionDecoderImpl(a) + InstructionDecoderImpl(a), + decodedInstruction(NULL), + locs(NULL), + sizePrefixPresent(false), + addrSizePrefixPresent(false) { if(a == Arch_x86_64) setMode(true); } INSTRUCTION_EXPORT InstructionDecoder_x86::~InstructionDecoder_x86() { - + free(decodedInstruction); + free(locs); } static const unsigned char modrm_use_sib = 4; INSTRUCTION_EXPORT void InstructionDecoder_x86::setMode(bool is64) { - ia32_set_mode_64(is64); + InstructionDecoder_x86::is64BitMode = is64; } Expression::Ptr InstructionDecoder_x86::makeSIBExpression(const InstructionDecoder::buffer& b) @@ -159,9 +160,9 @@ namespace Dyninst unsigned scale; Register index; Register base; - Result_Type registerType = ia32_is_mode_64() ? u64 : u32; + Result_Type registerType = is64BitMode ? u64 : u32; - int op_type = ia32_is_mode_64() ? op_q : op_d; + int op_type = is64BitMode ? op_q : op_d; decode_SIB(locs->sib_byte, scale, index, base); Expression::Ptr scaleAST(make_shared(singleton_object_pool::construct(Result(u8, dword_t(scale))))); @@ -177,7 +178,7 @@ namespace Dyninst break; case 0x01: case 0x02: - baseAST = make_shared(singleton_object_pool::construct(makeRegisterID(base, + baseAST = make_shared(singleton_object_pool::construct(makeRegisterID(base, op_type, locs->rex_b))); break; @@ -189,12 +190,12 @@ namespace Dyninst } else { - baseAST = make_shared(singleton_object_pool::construct(makeRegisterID(base, + baseAST = make_shared(singleton_object_pool::construct(makeRegisterID(base, op_type, locs->rex_b))); } - if(index == 0x04 && (!(ia32_is_mode_64()) || !(locs->rex_x))) + if(index == 0x04 && (!(is64BitMode) || !(locs->rex_x))) { return baseAST; } @@ -206,9 +207,9 @@ namespace Dyninst { unsigned int regType = op_d; Result_Type aw; - if(ia32_is_mode_64()) + if(is64BitMode) { - if(addrSizePrefixPresent) + if(addrSizePrefixPresent) { aw = u32; } else { @@ -216,7 +217,7 @@ namespace Dyninst regType = op_q; } } else { - if(!addrSizePrefixPresent) + if(!addrSizePrefixPresent) { aw = u32; } else { @@ -225,7 +226,7 @@ namespace Dyninst } } - if (opType == op_lea) + if (opType == op_lea) { // For an LEA, aw (address width) is insufficient, use makeSizeType aw = makeSizeType(opType); @@ -237,13 +238,13 @@ namespace Dyninst { case 0: /* modrm_rm == 0x4 is use SIB */ - if(locs->modrm_rm == modrm_use_sib) + if(locs->modrm_rm == modrm_use_sib) e = makeSIBExpression(b); else if(locs->modrm_rm == 0x5 && !addrSizePrefixPresent) { /* modrm_rm 00 0x5 is use 32 bit displacement only */ assert(locs->opcode_position > -1); - if(ia32_is_mode_64()) + if(is64BitMode) { e = makeAddExpression(makeRegisterExpression(x86_64::rip), getModRMDisplacement(b), aw); @@ -390,7 +391,7 @@ namespace Dyninst break; case 0: // In 16-bit mode, the word displacement is modrm r/m 6 - if(sizePrefixPresent && !ia32_is_mode_64()) + if(sizePrefixPresent && !is64BitMode) { if(locs->modrm_rm == 6) { @@ -414,7 +415,7 @@ namespace Dyninst { if(locs->modrm_rm == 5) { - if (b.start + disp_pos + 4 <= b.end) + if (b.start + disp_pos + 4 <= b.end) return make_shared(singleton_object_pool::construct(Result(s32, *((const dword_t*)(b.start + disp_pos))))); else @@ -556,7 +557,7 @@ namespace Dyninst bool InstructionDecoder_x86::isDefault64Insn() { - switch(m_Operation->getID()) + switch(m_Operation.getID()) { case e_jmp: case e_pop: @@ -662,7 +663,7 @@ namespace Dyninst } } - if (!ia32_is_mode_64()) { + if (!is64BitMode) { if ((retVal.val() & 0x00ffffff) == 0x0001000c) assert(0); } @@ -695,7 +696,7 @@ namespace Dyninst { return u64; } - //if(ia32_is_mode_64() || !sizePrefixPresent) + //if(is64BitMode || !sizePrefixPresent) //{ return u32; //} @@ -705,14 +706,14 @@ namespace Dyninst //} break; case op_y: - if(ia32_is_mode_64()) + if(is64BitMode) return u64; else return u32; break; case op_p: // book says operand size; arch-x86 says word + word * operand size - if(!ia32_is_mode_64() ^ sizePrefixPresent) + if(!is64BitMode ^ sizePrefixPresent) { return u48; } @@ -924,7 +925,7 @@ namespace Dyninst bool InstructionDecoder_x86::decodeOneOperand(const InstructionDecoder::buffer& b, const ia32_operand& operand, int & imm_index, /* immediate operand index */ - const Instruction* insn_to_complete, + const Instruction* insn_to_complete, bool isRead, bool isWritten, bool isImplicit) { bool isCFT = false; @@ -941,7 +942,7 @@ namespace Dyninst } } - if(cat == c_BranchInsn && insn_to_complete->getOperation().getID() != e_jmp) + if(cat == c_BranchInsn && insn_to_complete->getOperation().getID() != e_jmp) { isConditional = true; } @@ -971,14 +972,14 @@ namespace Dyninst } if (sizePrefixPresent && ((optype == op_v) - || (optype == op_z)) && (operand.admet != am_J)) + || (optype == op_z)) && (operand.admet != am_J)) { optype = op_w; } if(optype == op_y) { - if(ia32_is_mode_64() && locs->rex_w) + if(is64BitMode && locs->rex_w) { optype = op_q; } else { @@ -1018,7 +1019,7 @@ namespace Dyninst } /* Grab the correct bank and bank index for this type of register */ - if(decodeAVX(bank, &bank_index, pref.vex_vvvv_reg, + if(decodeAVX(bank, &bank_index, pref.vex_vvvv_reg, avx_type, pref, operand.admet)) return false; @@ -1057,7 +1058,7 @@ namespace Dyninst // am_R is the inverse of am_M; it should only have a mod of 3 case am_R: // can be am_R or am_M - case am_RM: + case am_RM: if(isCFT) { insn_to_complete->addSuccessor( @@ -1096,7 +1097,7 @@ namespace Dyninst /* Append the operand */ insn_to_complete->appendOperand(makeRegisterExpression( - IntelRegTable(m_Arch, bank, bank_index)), + IntelRegTable(m_Arch, bank, bank_index)), isRead, isWritten, isImplicit); break; @@ -1182,7 +1183,7 @@ namespace Dyninst offset_position++; insn_to_complete->appendOperand(makeDereferenceExpression( - decodeImmediate(pseudoOpType, b.start + offset_position), + decodeImmediate(pseudoOpType, b.start + offset_position), makeSizeType(optype)), isRead, isWritten, isImplicit); } break; @@ -1200,7 +1201,7 @@ namespace Dyninst case 0x00: case 0x01: case 0x02: - insn_to_complete->appendOperand(makeModRMExpression(b, optype), + insn_to_complete->appendOperand(makeModRMExpression(b, optype), isRead, isWritten, isImplicit); break; case 0x03: @@ -1225,7 +1226,7 @@ namespace Dyninst // test register in modrm reg; should only be tr6/tr7, but we'll decode any of them // NOTE: this only appears in deprecated opcodes insn_to_complete->appendOperand(makeRegisterExpression( - IntelRegTable(m_Arch,b_tr,locs->modrm_reg)), + IntelRegTable(m_Arch,b_tr,locs->modrm_reg)), isRead, isWritten, isImplicit); break; @@ -1251,14 +1252,14 @@ namespace Dyninst } /* Grab the register bank and index */ - if(decodeAVX(bank, &bank_index, locs->modrm_rm, AVX_XMM, + if(decodeAVX(bank, &bank_index, locs->modrm_rm, AVX_XMM, pref, operand.admet)) return false; /* Append the operand */ insn_to_complete->appendOperand(makeRegisterExpression( - IntelRegTable(m_Arch, bank, bank_index)), - isRead, isWritten, isImplicit); + IntelRegTable(m_Arch, bank, bank_index)), + isRead, isWritten, isImplicit); break; } default: @@ -1280,7 +1281,7 @@ namespace Dyninst return false; insn_to_complete->appendOperand(makeRegisterExpression( - IntelRegTable(m_Arch, bank, bank_index)), + IntelRegTable(m_Arch, bank, bank_index)), isRead, isWritten, isImplicit); break; @@ -1299,13 +1300,13 @@ namespace Dyninst /* Append the operand */ insn_to_complete->appendOperand(makeRegisterExpression( - IntelRegTable(m_Arch, bank, bank_index)), + IntelRegTable(m_Arch, bank, bank_index)), isRead, isWritten, isImplicit); break; case am_U: /* Could be XMM, YMM, or ZMM (or possibly non VEX)*/ - /* Is this a vex prefixed instruction? */ + /* Is this a vex prefixed instruction? */ if(pref.vex_present) { if(!AVX_TYPE_OKAY(avx_type)) @@ -1318,7 +1319,7 @@ namespace Dyninst /* Append the operand */ insn_to_complete->appendOperand(makeRegisterExpression( - IntelRegTable(m_Arch, bank, bank_index)), + IntelRegTable(m_Arch, bank, bank_index)), isRead, isWritten, isImplicit); break; case am_XU: /* Must be XMM (must be VEX) */ @@ -1335,7 +1336,7 @@ namespace Dyninst /* Append the operand */ insn_to_complete->appendOperand(makeRegisterExpression( - IntelRegTable(m_Arch, bank, bank_index)), + IntelRegTable(m_Arch, bank, bank_index)), isRead, isWritten, isImplicit); break; case am_YU: /* Must be XMM or YMM (must be VEX) */ @@ -1353,7 +1354,7 @@ namespace Dyninst /* Append the operand */ insn_to_complete->appendOperand(makeRegisterExpression( - IntelRegTable(m_Arch, bank, bank_index)), + IntelRegTable(m_Arch, bank, bank_index)), isRead, isWritten, isImplicit); break; case am_V: /* Could be XMM, YMM or ZMM (possibly non VEX)*/ @@ -1370,7 +1371,7 @@ namespace Dyninst /* Append the operand */ insn_to_complete->appendOperand(makeRegisterExpression( - IntelRegTable(m_Arch, bank, bank_index)), + IntelRegTable(m_Arch, bank, bank_index)), isRead, isWritten, isImplicit); break; case am_XV: /* Must be XMM (must be VEX) */ @@ -1405,7 +1406,7 @@ namespace Dyninst /* Append the operand */ insn_to_complete->appendOperand(makeRegisterExpression( - IntelRegTable(m_Arch, bank, bank_index)), + IntelRegTable(m_Arch, bank, bank_index)), isRead, isWritten, isImplicit); break; case am_VK: /* A KMasking register defined in the reg of a Mod/RM*/ @@ -1422,7 +1423,7 @@ namespace Dyninst /* Append the operand */ insn_to_complete->appendOperand(makeRegisterExpression( - IntelRegTable(m_Arch, bank, bank_index)), + IntelRegTable(m_Arch, bank, bank_index)), isRead, isWritten, isImplicit); break; case am_WK: /* Could be a K mask register or memory address*/ @@ -1445,18 +1446,18 @@ namespace Dyninst case 0x01: case 0x02: insn_to_complete->appendOperand( - makeModRMExpression(b, makeSizeType(optype)), + makeModRMExpression(b, makeSizeType(optype)), isRead, isWritten, isImplicit); break; case 0x03: /* Just the register is used */ - if(decodeAVX(bank, &bank_index, locs->modrm_rm, + if(decodeAVX(bank, &bank_index, locs->modrm_rm, avx_type, pref, operand.admet)) return false; insn_to_complete->appendOperand( makeRegisterExpression(IntelRegTable( - m_Arch, bank, bank_index)), + m_Arch, bank, bank_index)), isRead, isWritten, isImplicit); break; default: @@ -1479,8 +1480,8 @@ namespace Dyninst case 0x00: case 0x01: case 0x02: - insn_to_complete->appendOperand(makeModRMExpression(b, - makeSizeType(optype)), + insn_to_complete->appendOperand(makeModRMExpression(b, + makeSizeType(optype)), isRead, isWritten, isImplicit); break; case 0x03: @@ -1489,7 +1490,7 @@ namespace Dyninst return false; insn_to_complete->appendOperand( makeRegisterExpression(IntelRegTable - (m_Arch, bank, bank_index)), + (m_Arch, bank, bank_index)), isRead, isWritten, isImplicit); break; default: @@ -1514,7 +1515,7 @@ namespace Dyninst case 0x01: case 0x02: insn_to_complete->appendOperand(makeModRMExpression( - b, makeSizeType(optype)), + b, makeSizeType(optype)), isRead, isWritten, isImplicit); break; case 0x03: @@ -1524,7 +1525,7 @@ namespace Dyninst /* Append the operand */ insn_to_complete->appendOperand(makeRegisterExpression( - IntelRegTable(m_Arch, bank, bank_index)), + IntelRegTable(m_Arch, bank, bank_index)), isRead, isWritten, isImplicit); break; default: @@ -1561,7 +1562,7 @@ namespace Dyninst ds, segmentOffset, u32); Expression::Ptr ds_si = makeAddExpression(ds_segment, si, u32); insn_to_complete->appendOperand( - makeDereferenceExpression(ds_si, makeSizeType(optype)), + makeDereferenceExpression(ds_si, makeSizeType(optype)), isRead, isWritten, isImplicit); } break; @@ -1645,12 +1646,12 @@ namespace Dyninst r = MachRegister((r.val() & ~r.getArchitecture()) | m_Arch); entryID entryid = decodedInstruction->getEntry()->getID(locs); - if(insn_to_complete->m_Operands.empty() && + if(insn_to_complete->m_Operands.empty() && (entryid == e_push || entryid == e_pop || entryid == e_xchg || ((*(b.start + locs->opcode_position) & 0xf0) == 0xb0) ) ) { unsigned int opcode_byte = *(b.start+locs->opcode_position); unsigned int reg_id = (opcode_byte & 0x07); - if(locs->rex_b) + if(locs->rex_b) { // FP stack registers are not affected by the rex_b bit in AM_REG. if(r.regClass() == (unsigned) x86::GPR) @@ -1745,7 +1746,7 @@ namespace Dyninst locs = new(locs) ia32_locations; //reinit(); assert(locs->sib_position == -1); decodedInstruction = new (decodedInstruction) ia32_instruction(NULL, NULL, locs); - ia32_decode(IA32_DECODE_PREFIXES, b.start, *decodedInstruction); + ia32_decode(IA32_DECODE_PREFIXES, b.start, *decodedInstruction, is64BitMode); sizePrefixPresent = (decodedInstruction->getPrefix()->getOperSzPrefix() == 0x66); if (decodedInstruction->getPrefix()->rexW()) { // as per 2.2.1.2 - rex.w overrides 66h @@ -1781,13 +1782,13 @@ namespace Dyninst case e_xchg: break; default: - m_Operation =make_shared(singleton_object_pool::construct(&invalid, - decodedInstruction->getPrefix(), locs, m_Arch)); + m_Operation = Operation(&invalid, + decodedInstruction->getPrefix(), locs, m_Arch); return; } } - m_Operation = make_shared(singleton_object_pool::construct(decodedInstruction->getEntry(), - decodedInstruction->getPrefix(), locs, m_Arch)); + m_Operation = Operation(decodedInstruction->getEntry(), + decodedInstruction->getPrefix(), locs, m_Arch); } else { // Gap parsing can trigger this case; in particular, when it encounters prefixes in an invalid order. @@ -1795,8 +1796,8 @@ namespace Dyninst // we'll reject the instruction as invalid and send it back with no entry. Since this is a common // byte sequence to see in, for example, ASCII strings, we want to simply accept this and move on, not // yell at the user. - m_Operation = make_shared(singleton_object_pool::construct(&invalid, - decodedInstruction->getPrefix(), locs, m_Arch)); + m_Operation = Operation(&invalid, + decodedInstruction->getPrefix(), locs, m_Arch); } } @@ -1813,16 +1814,16 @@ namespace Dyninst if(!decodedInstruction || !decodedInstruction->getEntry()) return false; unsigned int opsema = decodedInstruction->getEntry()->opsema; unsigned int semantics = opsema & 0xFF; - unsigned int implicit_operands = + unsigned int implicit_operands = sGetImplicitOPs(decodedInstruction->getEntry()->impl_dec); InstructionDecoder::buffer b(insn_to_complete->ptr(), insn_to_complete->size()); if (decodedInstruction->getEntry()->getID() == e_ret_near || - decodedInstruction->getEntry()->getID() == e_ret_far) { - Expression::Ptr ret_addr = makeDereferenceExpression(makeRegisterExpression(ia32_is_mode_64() ? x86_64::rsp : x86::esp), - ia32_is_mode_64() ? u64 : u32); - insn_to_complete->addSuccessor(ret_addr, false, true, false, false); - } + decodedInstruction->getEntry()->getID() == e_ret_far) { + Expression::Ptr ret_addr = makeDereferenceExpression(makeRegisterExpression(is64BitMode ? x86_64::rsp : x86::esp), + is64BitMode ? u64 : u32); + insn_to_complete->addSuccessor(ret_addr, false, true, false, false); + } for(int i = 0; i < 3; i++) { @@ -1831,9 +1832,9 @@ namespace Dyninst break; if(!decodeOneOperand(b, - decodedInstruction->getEntry()->operands[i], - imm_index, - insn_to_complete, + decodedInstruction->getEntry()->operands[i], + imm_index, + insn_to_complete, readsOperand(semantics, i), writesOperand(semantics, i), implicitOperand(implicit_operands, i))) @@ -1870,7 +1871,7 @@ namespace Dyninst } - INSTRUCTION_EXPORT Instruction::Ptr InstructionDecoder_x86::decode(InstructionDecoder::buffer& b) + INSTRUCTION_EXPORT Instruction InstructionDecoder_x86::decode(InstructionDecoder::buffer& b) { return InstructionDecoderImpl::decode(b); } diff --git a/instructionAPI/src/InstructionDecoder-x86.h b/instructionAPI/src/InstructionDecoder-x86.h index f67a836f39..5b61e1bd46 100644 --- a/instructionAPI/src/InstructionDecoder-x86.h +++ b/instructionAPI/src/InstructionDecoder-x86.h @@ -69,7 +69,7 @@ namespace Dyninst private: INSTRUCTION_EXPORT InstructionDecoder_x86(const InstructionDecoder_x86& o); public: - INSTRUCTION_EXPORT virtual Instruction::Ptr decode(InstructionDecoder::buffer& b); + INSTRUCTION_EXPORT virtual Instruction decode(InstructionDecoder::buffer& b); INSTRUCTION_EXPORT virtual void setMode(bool is64); virtual void doDelayedDecode(const Instruction* insn_to_complete); @@ -95,12 +95,13 @@ namespace Dyninst private: void doIA32Decode(InstructionDecoder::buffer& b); - bool isDefault64Insn(); + bool isDefault64Insn(); - static TLS_VAR ia32_locations* locs; - static TLS_VAR NS_x86::ia32_instruction* decodedInstruction; - static TLS_VAR bool sizePrefixPresent; - static TLS_VAR bool addrSizePrefixPresent; + ia32_locations* locs; + NS_x86::ia32_instruction* decodedInstruction; + bool sizePrefixPresent; + bool addrSizePrefixPresent; + bool is64BitMode; }; }; }; diff --git a/instructionAPI/src/InstructionDecoder.C b/instructionAPI/src/InstructionDecoder.C index 452b32bdb0..d0a592da65 100644 --- a/instructionAPI/src/InstructionDecoder.C +++ b/instructionAPI/src/InstructionDecoder.C @@ -58,15 +58,13 @@ namespace Dyninst { } - INSTRUCTION_EXPORT Instruction::Ptr InstructionDecoder::decode() + INSTRUCTION_EXPORT Instruction InstructionDecoder::decode() { - if(m_buf.start >= m_buf.end) return Instruction::Ptr(); - - Instruction::Ptr ret = m_Impl->decode(m_buf); - return ret; + if(m_buf.start >= m_buf.end) return Instruction(); + return m_Impl->decode(m_buf); } - INSTRUCTION_EXPORT Instruction::Ptr InstructionDecoder::decode(const unsigned char* b) + INSTRUCTION_EXPORT Instruction InstructionDecoder::decode(const unsigned char* b) { buffer tmp(b, b+maxInstructionLength); diff --git a/instructionAPI/src/InstructionDecoderImpl.C b/instructionAPI/src/InstructionDecoderImpl.C index b6a04d8aeb..da5f34b677 100644 --- a/instructionAPI/src/InstructionDecoderImpl.C +++ b/instructionAPI/src/InstructionDecoderImpl.C @@ -35,6 +35,7 @@ #include "InstructionDecoder-aarch64.h" #include "BinaryFunction.h" #include "Dereference.h" +#include using namespace std; namespace Dyninst @@ -44,39 +45,38 @@ namespace Dyninst Instruction* InstructionDecoderImpl::makeInstruction(entryID opcode, const char* mnem, unsigned int decodedSize, const unsigned char* raw) { - Operation::Ptr tmp(make_shared(singleton_object_pool::construct(opcode, mnem, m_Arch))); + Operation tmp(opcode, mnem, m_Arch); return singleton_object_pool::construct(tmp, decodedSize, raw, m_Arch); } - Instruction::Ptr InstructionDecoderImpl::decode(InstructionDecoder::buffer& b) + Instruction InstructionDecoderImpl::decode(InstructionDecoder::buffer& b) { //setMode(m_Arch == Arch_x86_64); const unsigned char* start = b.start; decodeOpcode(b); unsigned int decodedSize = b.start - start; - return make_shared(singleton_object_pool::construct( - m_Operation, decodedSize, start, m_Arch)); + return Instruction(m_Operation, decodedSize, start, m_Arch); } - std::map InstructionDecoderImpl::impls; InstructionDecoderImpl::Ptr InstructionDecoderImpl::makeDecoderImpl(Architecture a) { - if(impls.empty()) + switch(a) { - impls[Arch_x86] = Ptr(new InstructionDecoder_x86(Arch_x86)); - impls[Arch_x86_64] = Ptr(new InstructionDecoder_x86(Arch_x86_64)); - impls[Arch_ppc32] = Ptr(new InstructionDecoder_power(Arch_ppc32)); - impls[Arch_ppc64] = Ptr(new InstructionDecoder_power(Arch_ppc64)); - impls[Arch_aarch64] = Ptr(new InstructionDecoder_aarch64(Arch_aarch64)); + case Arch_x86: + case Arch_x86_64: + return Ptr(new InstructionDecoder_x86(a)); + case Arch_ppc32: + case Arch_ppc64: + return Ptr(new InstructionDecoder_power(a)); + case Arch_aarch32: + case Arch_aarch64: + return Ptr(new InstructionDecoder_aarch64(a)); + default: + assert(0); + return Ptr(); } - std::map::const_iterator foundImpl = impls.find(a); - if(foundImpl == impls.end()) - { - return Ptr(); - } - return foundImpl->second; } Expression::Ptr InstructionDecoderImpl::makeAddExpression(Expression::Ptr lhs, Expression::Ptr rhs, Result_Type resultType) diff --git a/instructionAPI/src/InstructionDecoderImpl.h b/instructionAPI/src/InstructionDecoderImpl.h index 2d75a501ed..c99aefcde8 100644 --- a/instructionAPI/src/InstructionDecoderImpl.h +++ b/instructionAPI/src/InstructionDecoderImpl.h @@ -33,7 +33,7 @@ #include "Expression.h" #include "dyn_regs.h" -#include "Operation.h" +#include "Operation_impl.h" #include "entryIDs.h" #include "Instruction.h" #include "InstructionDecoder.h" // buffer...anything else? @@ -49,7 +49,7 @@ class InstructionDecoderImpl InstructionDecoderImpl(Architecture a) : m_Arch(a) {} virtual ~InstructionDecoderImpl() {} - virtual Instruction::Ptr decode(InstructionDecoder::buffer& b); + virtual Instruction decode(InstructionDecoder::buffer& b); virtual void doDelayedDecode(const Instruction* insn_to_complete) = 0; virtual void setMode(bool is64) = 0; static Ptr makeDecoderImpl(Architecture a); @@ -75,10 +75,9 @@ class InstructionDecoderImpl const unsigned char* raw); protected: - Operation::Ptr m_Operation; + Operation m_Operation; Architecture m_Arch; - static std::map impls; - + }; } diff --git a/instructionAPI/src/Operand.C b/instructionAPI/src/Operand.C index aebc8bb60d..20cccc1908 100644 --- a/instructionAPI/src/Operand.C +++ b/instructionAPI/src/Operand.C @@ -114,30 +114,6 @@ namespace Dyninst } } - INSTRUCTION_EXPORT std::string Operand::format(ArchSpecificFormatter *formatter, Architecture arch, Address addr) const - { - if(!op_value) return "ERROR: format() called on empty operand!"; - - if (addr) { - - Expression::Ptr thePC = Expression::Ptr( - new RegisterAST(MachRegister::getPC(arch))); - - op_value->bind(thePC.get(), Result(u32, addr)); - Result res = op_value->eval(); - if (res.defined) { - stringstream ret; - ret << hex << res.convert() << dec; - return ret.str(); - } - } - - /** - * If this is a jump or IP relative load/store, this will be a - * binary function, so we have to parse the AST from hand - */ - return op_value->format(formatter); - } INSTRUCTION_EXPORT std::string Operand::format(Architecture arch, Address addr) const { @@ -147,12 +123,12 @@ namespace Dyninst op_value->bind(thePC.get(), Result(u32, addr)); Result res = op_value->eval(); if (res.defined) { - stringstream ret; - ret << hex << res.convert() << dec; - return ret.str(); + char hex[20]; + snprintf(hex, 20, "%x", res.convert()); + return string(hex); } } - return op_value->format(); + return op_value->format(arch); } INSTRUCTION_EXPORT Expression::Ptr Operand::getValue() const diff --git a/instructionAPI/src/Operation.C b/instructionAPI/src/Operation.C index 94597578ad..ddb04e3677 100644 --- a/instructionAPI/src/Operation.C +++ b/instructionAPI/src/Operation.C @@ -32,12 +32,14 @@ #include "common/src/Types.h" -#include "Operation.h" +#include "Operation_impl.h" #include "common/src/arch-x86.h" #include "entryIDs.h" #include "common/src/Singleton.h" #include "Register.h" #include +#include +#include #include "common/src/singleton_object_pool.h" using namespace NS_x86; @@ -57,9 +59,8 @@ namespace Dyninst return make_shared(singleton_object_pool::construct(regID, 0, regID.size() * 8)); } - Operation::Operation(entryID id, const char* mnem, Architecture arch) - : mnemonic(mnem), operationID(id), doneOtherSetup(true), doneFlagsSetup(true), - archDecodedFrom(arch), prefixID(prefix_none), isVectorInsn(false) + Operation_impl::Operation_impl(entryID id, std::string m, Architecture arch) + : operationID(id), archDecodedFrom(arch), prefixID(prefix_none) { switch(archDecodedFrom) { @@ -71,8 +72,10 @@ namespace Dyninst addrWidth = u64; break; } + segPrefix = 0; + isVectorInsn = false; + mnemonic = m; } - static bool getVectorizationInfo(ia32_entry* e) { @@ -106,12 +109,12 @@ namespace Dyninst } return false; } - - Operation::Operation(ia32_entry* e, ia32_prefixes* p, ia32_locations* l, Architecture arch) : - doneOtherSetup(false), doneFlagsSetup(false), archDecodedFrom(arch), prefixID(prefix_none), - isVectorInsn(getVectorizationInfo(e)) + Operation_impl::Operation_impl(ia32_entry* e, ia32_prefixes* p, ia32_locations* l, Architecture arch) : + archDecodedFrom(arch), prefixID(prefix_none) { + segPrefix = 0; + isVectorInsn = getVectorizationInfo(e); operationID = e->getID(l); // Defaults for no size prefix switch(archDecodedFrom) @@ -124,50 +127,11 @@ namespace Dyninst addrWidth = u64; break; } - if(p && p->getCount()) { - if (p->getPrefix(0) == PREFIX_REP || p->getPrefix(0) == PREFIX_REPNZ) - { - otherRead.insert(makeRegFromID((archDecodedFrom == Arch_x86) ? x86::df : x86_64::df)); - otherRead.insert(makeRegFromID((archDecodedFrom == Arch_x86) ? x86::ecx : x86_64::rcx)); - otherWritten.insert(makeRegFromID((archDecodedFrom == Arch_x86) ? x86::ecx : x86_64::rcx)); - if(p->getPrefix(0) == PREFIX_REPNZ) - { - otherRead.insert(makeRegFromID((archDecodedFrom == Arch_x86) ? x86::zf : x86_64::zf)); - prefixID = prefix_repnz; - } - else - { - prefixID = prefix_rep; - } - } - else - { - prefixID = prefix_none; - } - int segPrefix = p->getPrefix(1); - switch(segPrefix) - { - case PREFIX_SEGCS: - otherRead.insert(makeRegFromID((archDecodedFrom == Arch_x86) ? x86::cs : x86_64::cs)); - break; - case PREFIX_SEGDS: - otherRead.insert(makeRegFromID((archDecodedFrom == Arch_x86) ? x86::ds : x86_64::ds)); - break; - case PREFIX_SEGES: - otherRead.insert(makeRegFromID((archDecodedFrom == Arch_x86) ? x86::es : x86_64::es)); - break; - case PREFIX_SEGFS: - otherRead.insert(makeRegFromID((archDecodedFrom == Arch_x86) ? x86::fs : x86_64::fs)); - break; - case PREFIX_SEGGS: - otherRead.insert(makeRegFromID((archDecodedFrom == Arch_x86) ? x86::gs : x86_64::gs)); - break; - case PREFIX_SEGSS: - otherRead.insert(makeRegFromID((archDecodedFrom == Arch_x86) ? x86::ss : x86_64::ss)); - break; - } + if (p->getPrefix(0) == PREFIX_REP) prefixID = prefix_rep; + if (p->getPrefix(0) == PREFIX_REPNZ) prefixID = prefix_repnz; + segPrefix = p->getPrefix(1); if(p->getAddrSzPrefix()) { addrWidth = u16; @@ -175,57 +139,50 @@ namespace Dyninst } } - Operation::Operation(const Operation& o) + Operation_impl::Operation_impl(const Operation_impl& o) { - otherRead = o.otherRead; - otherWritten = o.otherWritten; - otherEffAddrsRead = o.otherEffAddrsRead; - otherEffAddrsWritten = o.otherEffAddrsWritten; operationID = o.operationID; - doneOtherSetup = o.doneOtherSetup; - doneFlagsSetup = o.doneFlagsSetup; archDecodedFrom = o.archDecodedFrom; - prefixID = prefix_none; + prefixID = o.prefixID; addrWidth = o.addrWidth; - + segPrefix = o.segPrefix; + isVectorInsn = o.isVectorInsn; + mnemonic = o.mnemonic; } - const Operation& Operation::operator=(const Operation& o) + const Operation_impl& Operation_impl::operator=(const Operation_impl& o) { - otherRead = o.otherRead; - otherWritten = o.otherWritten; - otherEffAddrsRead = o.otherEffAddrsRead; - otherEffAddrsWritten = o.otherEffAddrsWritten; operationID = o.operationID; - doneOtherSetup = o.doneOtherSetup; - doneFlagsSetup = o.doneFlagsSetup; archDecodedFrom = o.archDecodedFrom; prefixID = o.prefixID; addrWidth = o.addrWidth; + segPrefix = o.segPrefix; + isVectorInsn = o.isVectorInsn; + mnemonic = o.mnemonic; return *this; } - Operation::Operation() + Operation_impl::Operation_impl() { operationID = e_No_Entry; - doneOtherSetup = false; - doneFlagsSetup = false; archDecodedFrom = Arch_none; prefixID = prefix_none; addrWidth = u64; + segPrefix = 0; + isVectorInsn = false; } - const Operation::registerSet& Operation::implicitReads() const + const Operation_impl::registerSet& Operation_impl::implicitReads() { SetUpNonOperandData(true); return otherRead; } - const Operation::registerSet& Operation::implicitWrites() const + const Operation_impl::registerSet& Operation_impl::implicitWrites() { SetUpNonOperandData(true); return otherWritten; } - bool Operation::isRead(Expression::Ptr candidate) const + bool Operation_impl::isRead(Expression::Ptr candidate) { SetUpNonOperandData(candidate->isFlag()); @@ -250,18 +207,18 @@ namespace Dyninst } return false; } - const Operation::VCSet& Operation::getImplicitMemReads() const + const Operation_impl::VCSet& Operation_impl::getImplicitMemReads() { SetUpNonOperandData(true); return otherEffAddrsRead; } - const Operation::VCSet& Operation::getImplicitMemWrites() const + const Operation_impl::VCSet& Operation_impl::getImplicitMemWrites() { SetUpNonOperandData(true); return otherEffAddrsWritten; } - bool Operation::isWritten(Expression::Ptr candidate) const + bool Operation_impl::isWritten(Expression::Ptr candidate) { SetUpNonOperandData(candidate->isFlag()); @@ -287,7 +244,7 @@ namespace Dyninst return false; } - std::string Operation::format() const + std::string Operation_impl::format() const { if(mnemonic != "") { @@ -311,18 +268,20 @@ namespace Dyninst return result; } - entryID Operation::getID() const + entryID Operation_impl::getID() const { return operationID; } - prefixEntryID Operation::getPrefixID() const + prefixEntryID Operation_impl::getPrefixID() const { return prefixID; } struct OperationMaps { + typedef tbb::concurrent_hash_map reg_info_t; + typedef tbb::concurrent_hash_map mem_info_t; public: OperationMaps(Architecture arch) { @@ -334,95 +293,98 @@ namespace Dyninst framePointer.insert(RegisterAST::Ptr(new RegisterAST(MachRegister::getFramePointer(arch)))); spAndBP.insert(RegisterAST::Ptr(new RegisterAST(MachRegister::getStackPointer(arch)))); spAndBP.insert(RegisterAST::Ptr(new RegisterAST(MachRegister::getFramePointer(arch)))); - si.insert(RegisterAST::Ptr(new RegisterAST(arch == Arch_x86_64 ? x86_64::esi : x86::esi))); - di.insert(RegisterAST::Ptr(new RegisterAST(arch == Arch_x86_64 ? x86_64::edi : x86::edi))); - si_and_di.insert(RegisterAST::Ptr(new RegisterAST(arch == Arch_x86_64 ? x86_64::esi : x86::esi))); - si_and_di.insert(RegisterAST::Ptr(new RegisterAST(arch == Arch_x86_64 ? x86_64::edi : x86::edi))); + si.insert(RegisterAST::Ptr(new RegisterAST(arch == Arch_x86_64 ? x86_64::rsi : x86::esi))); + di.insert(RegisterAST::Ptr(new RegisterAST(arch == Arch_x86_64 ? x86_64::rdi : x86::edi))); + si_and_di.insert(RegisterAST::Ptr(new RegisterAST(arch == Arch_x86_64 ? x86_64::rsi : x86::esi))); + si_and_di.insert(RegisterAST::Ptr(new RegisterAST(arch == Arch_x86_64 ? x86_64::rdi : x86::edi))); - nonOperandRegisterReads[e_call] = pcAndSP; - nonOperandRegisterReads[e_ret_near] = stackPointer; - nonOperandRegisterReads[e_ret_far] = stackPointer; - nonOperandRegisterReads[e_leave] = framePointer; - nonOperandRegisterReads[e_enter] = spAndBP; - - nonOperandRegisterWrites[e_call] = pcAndSP; - nonOperandRegisterWrites[e_ret_near] = pcAndSP; - nonOperandRegisterWrites[e_ret_far] = pcAndSP; - nonOperandRegisterWrites[e_leave] = spAndBP; - nonOperandRegisterWrites[e_enter] = spAndBP; - nonOperandRegisterWrites[e_loop] = thePC; - nonOperandRegisterWrites[e_loope] = thePC; - nonOperandRegisterWrites[e_loopn] = thePC; - nonOperandRegisterWrites[e_jb] = thePC; - nonOperandRegisterWrites[e_jb_jnaej_j] = thePC; - nonOperandRegisterWrites[e_jbe] = thePC; - nonOperandRegisterWrites[e_jcxz_jec] = thePC; - nonOperandRegisterWrites[e_jl] = thePC; - nonOperandRegisterWrites[e_jle] = thePC; - nonOperandRegisterWrites[e_jmp] = thePC; - nonOperandRegisterWrites[e_jnb] = thePC; - nonOperandRegisterWrites[e_jnb_jae_j] = thePC; - nonOperandRegisterWrites[e_jnbe] = thePC; - nonOperandRegisterWrites[e_jnl] = thePC; - nonOperandRegisterWrites[e_jnle] = thePC; - nonOperandRegisterWrites[e_jno] = thePC; - nonOperandRegisterWrites[e_jnp] = thePC; - nonOperandRegisterWrites[e_jns] = thePC; - nonOperandRegisterWrites[e_jnz] = thePC; - nonOperandRegisterWrites[e_jo] = thePC; - nonOperandRegisterWrites[e_jp] = thePC; - nonOperandRegisterWrites[e_js] = thePC; - nonOperandRegisterWrites[e_jz] = thePC; - nonOperandMemoryReads[e_pop] = stackPointerAsExpr; - nonOperandMemoryReads[e_popa] = stackPointerAsExpr; - nonOperandMemoryReads[e_popad] = stackPointerAsExpr; - nonOperandMemoryWrites[e_push] = stackPointerAsExpr; - nonOperandMemoryWrites[e_pusha] = stackPointerAsExpr; - nonOperandMemoryWrites[e_pushad] = stackPointerAsExpr; - nonOperandMemoryWrites[e_call] = stackPointerAsExpr; - nonOperandMemoryReads[e_ret_near] = stackPointerAsExpr; - nonOperandMemoryReads[e_ret_far] = stackPointerAsExpr; - nonOperandMemoryReads[e_leave] = stackPointerAsExpr; - nonOperandRegisterWrites[e_cmpsb] = si_and_di; - nonOperandRegisterWrites[e_cmpsd] = si_and_di; - nonOperandRegisterWrites[e_cmpsw] = si_and_di; - nonOperandRegisterWrites[e_movsb] = si_and_di; - nonOperandRegisterWrites[e_movsd] = si_and_di; - nonOperandRegisterWrites[e_movsw] = si_and_di; - nonOperandRegisterWrites[e_cmpsb] = si_and_di; - nonOperandRegisterWrites[e_cmpsd] = si_and_di; - nonOperandRegisterWrites[e_cmpsw] = si_and_di; - nonOperandRegisterWrites[e_insb] = di; - nonOperandRegisterWrites[e_insd] = di; - nonOperandRegisterWrites[e_insw] = di; - nonOperandRegisterWrites[e_stosb] = di; - nonOperandRegisterWrites[e_stosd] = di; - nonOperandRegisterWrites[e_stosw] = di; - nonOperandRegisterWrites[e_scasb] = di; - nonOperandRegisterWrites[e_scasd] = di; - nonOperandRegisterWrites[e_scasw] = di; - nonOperandRegisterWrites[e_lodsb] = si; - nonOperandRegisterWrites[e_lodsd] = si; - nonOperandRegisterWrites[e_lodsw] = si; - nonOperandRegisterWrites[e_outsb] = si; - nonOperandRegisterWrites[e_outsd] = si; - nonOperandRegisterWrites[e_outsw] = si; - + nonOperandRegisterReads.insert(make_pair(e_call, pcAndSP)); + nonOperandRegisterReads.insert(make_pair(e_ret_near, stackPointer)); + nonOperandRegisterReads.insert(make_pair(e_ret_far, stackPointer)); + nonOperandRegisterReads.insert(make_pair(e_leave, framePointer)); + nonOperandRegisterReads.insert(make_pair(e_enter, spAndBP)); + + nonOperandRegisterWrites.insert(make_pair(e_call, pcAndSP)); + nonOperandRegisterWrites.insert(make_pair(e_ret_near, pcAndSP)); + nonOperandRegisterWrites.insert(make_pair(e_ret_far, pcAndSP)); + nonOperandRegisterWrites.insert(make_pair(e_leave, spAndBP)); + nonOperandRegisterWrites.insert(make_pair(e_enter, spAndBP)); + + nonOperandRegisterWrites.insert(make_pair(e_loop, thePC)); + nonOperandRegisterWrites.insert(make_pair(e_loope, thePC)); + nonOperandRegisterWrites.insert(make_pair(e_loopn, thePC)); + + nonOperandRegisterWrites.insert(make_pair(e_jb, thePC)); + nonOperandRegisterWrites.insert(make_pair(e_jb_jnaej_j, thePC)); + nonOperandRegisterWrites.insert(make_pair(e_jbe, thePC)); + nonOperandRegisterWrites.insert(make_pair(e_jcxz_jec, thePC)); + nonOperandRegisterWrites.insert(make_pair(e_jl, thePC)); + nonOperandRegisterWrites.insert(make_pair(e_jle, thePC)); + nonOperandRegisterWrites.insert(make_pair(e_jmp, thePC)); + nonOperandRegisterWrites.insert(make_pair(e_jnb, thePC)); + nonOperandRegisterWrites.insert(make_pair(e_jnb_jae_j, thePC)); + nonOperandRegisterWrites.insert(make_pair(e_jnbe, thePC)); + nonOperandRegisterWrites.insert(make_pair(e_jnl, thePC)); + nonOperandRegisterWrites.insert(make_pair(e_jnle, thePC)); + nonOperandRegisterWrites.insert(make_pair(e_jno, thePC)); + nonOperandRegisterWrites.insert(make_pair(e_jnp, thePC)); + nonOperandRegisterWrites.insert(make_pair(e_jns, thePC)); + nonOperandRegisterWrites.insert(make_pair(e_jnz, thePC)); + nonOperandRegisterWrites.insert(make_pair(e_jo, thePC)); + nonOperandRegisterWrites.insert(make_pair(e_jp, thePC)); + nonOperandRegisterWrites.insert(make_pair(e_js, thePC)); + nonOperandRegisterWrites.insert(make_pair(e_jz, thePC)); + + nonOperandMemoryReads.insert(make_pair(e_pop, stackPointerAsExpr)); + nonOperandMemoryReads.insert(make_pair(e_popa, stackPointerAsExpr)); + nonOperandMemoryReads.insert(make_pair(e_popad, stackPointerAsExpr)); + nonOperandMemoryWrites.insert(make_pair(e_push, stackPointerAsExpr)); + nonOperandMemoryWrites.insert(make_pair(e_pusha, stackPointerAsExpr)); + nonOperandMemoryWrites.insert(make_pair(e_pushad, stackPointerAsExpr)); + nonOperandMemoryWrites.insert(make_pair(e_call, stackPointerAsExpr)); + nonOperandMemoryReads.insert(make_pair(e_ret_near, stackPointerAsExpr)); + nonOperandMemoryReads.insert(make_pair(e_ret_far, stackPointerAsExpr)); + nonOperandMemoryReads.insert(make_pair(e_leave, stackPointerAsExpr)); + + nonOperandRegisterWrites.insert(make_pair(e_cmpsb, si_and_di)); + nonOperandRegisterWrites.insert(make_pair(e_cmpsd, si_and_di)); + nonOperandRegisterWrites.insert(make_pair(e_cmpsw, si_and_di)); + nonOperandRegisterWrites.insert(make_pair(e_movsb, si_and_di)); + nonOperandRegisterWrites.insert(make_pair(e_movsd, si_and_di)); + nonOperandRegisterWrites.insert(make_pair(e_movsw, si_and_di)); + nonOperandRegisterWrites.insert(make_pair(e_insb, di)); + nonOperandRegisterWrites.insert(make_pair(e_insd, di)); + nonOperandRegisterWrites.insert(make_pair(e_insw, di)); + nonOperandRegisterWrites.insert(make_pair(e_stosb, di)); + nonOperandRegisterWrites.insert(make_pair(e_stosd, di)); + nonOperandRegisterWrites.insert(make_pair(e_stosw, di)); + nonOperandRegisterWrites.insert(make_pair(e_scasb, di)); + nonOperandRegisterWrites.insert(make_pair(e_scasd, di)); + nonOperandRegisterWrites.insert(make_pair(e_scasw, di)); + nonOperandRegisterWrites.insert(make_pair(e_lodsb, di)); + nonOperandRegisterWrites.insert(make_pair(e_lodsd, di)); + nonOperandRegisterWrites.insert(make_pair(e_lodsw, di)); + nonOperandRegisterWrites.insert(make_pair(e_outsb, di)); + nonOperandRegisterWrites.insert(make_pair(e_outsd, di)); + nonOperandRegisterWrites.insert(make_pair(e_outsw, di)); + + } - Operation::registerSet thePC; - Operation::registerSet pcAndSP; - Operation::registerSet stackPointer; - Operation::VCSet stackPointerAsExpr; - Operation::registerSet framePointer; - Operation::registerSet spAndBP; - Operation::registerSet si; - Operation::registerSet di; - Operation::registerSet si_and_di; - dyn_hash_map nonOperandRegisterReads; - dyn_hash_map nonOperandRegisterWrites; + Operation_impl::registerSet thePC; + Operation_impl::registerSet pcAndSP; + Operation_impl::registerSet stackPointer; + Operation_impl::VCSet stackPointerAsExpr; + Operation_impl::registerSet framePointer; + Operation_impl::registerSet spAndBP; + Operation_impl::registerSet si; + Operation_impl::registerSet di; + Operation_impl::registerSet si_and_di; + + reg_info_t nonOperandRegisterReads; + reg_info_t nonOperandRegisterWrites; - dyn_hash_map nonOperandMemoryReads; - dyn_hash_map nonOperandMemoryWrites; + mem_info_t nonOperandMemoryReads; + mem_info_t nonOperandMemoryWrites; }; OperationMaps op_data_32(Arch_x86); OperationMaps op_data_64(Arch_x86_64); @@ -438,137 +400,150 @@ namespace Dyninst return op_data_32; } } - void Operation::SetUpNonOperandData(bool needFlags) const + void Operation_impl::SetUpNonOperandData(bool needFlags) { - if(doneOtherSetup && doneFlagsSetup) return; -#if defined(arch_x86) || defined(arch_x86_64) - dyn_hash_map::const_iterator foundRegs; - foundRegs = op_data(archDecodedFrom).nonOperandRegisterReads.find(operationID); - if(foundRegs != op_data(archDecodedFrom).nonOperandRegisterReads.end()) - { - otherRead.insert(foundRegs->second.begin(), foundRegs->second.end()); - } - foundRegs = op_data(archDecodedFrom).nonOperandRegisterWrites.find(operationID); - if(foundRegs != op_data(archDecodedFrom).nonOperandRegisterWrites.end()) - { - otherWritten.insert(foundRegs->second.begin(), foundRegs->second.end()); - } - dyn_hash_map::const_iterator foundMem; - foundMem = op_data(archDecodedFrom).nonOperandMemoryReads.find(operationID); - if(foundMem != op_data(archDecodedFrom).nonOperandMemoryReads.end()) - { - otherEffAddrsRead.insert(foundMem->second.begin(), foundMem->second.end()); - } - if(operationID == e_push) - { - BinaryFunction::funcT::Ptr adder(new BinaryFunction::addResult()); - // special case for push: we write at the new value of the SP. - Result dummy(addrWidth, 0); - Expression::Ptr push_addr(new BinaryFunction( - *(op_data(archDecodedFrom).stackPointerAsExpr.begin()), - Immediate::makeImmediate(Result(s8, -(dummy.size()))), - addrWidth, - adder)); - - otherEffAddrsWritten.insert(push_addr); - - } - else - { - foundMem = op_data(archDecodedFrom).nonOperandMemoryWrites.find(operationID); - if(foundMem != op_data(archDecodedFrom).nonOperandMemoryWrites.end()) - { - otherEffAddrsWritten.insert(foundMem->second.begin(), foundMem->second.end()); - } - } - if(needFlags && !doneFlagsSetup) - { - - dyn_hash_map::const_iterator found = ia32_instruction::getFlagTable().find(operationID); - if(found != ia32_instruction::getFlagTable().end()) - { - for(unsigned i = 0; i < found->second.readFlags.size(); i++) - { - switch(found->second.readFlags[i]) { - case x86::icf: - otherRead.insert(makeRegFromID((archDecodedFrom == Arch_x86) ? x86::cf : x86_64::cf)); - break; - case x86::ipf: - otherRead.insert(makeRegFromID((archDecodedFrom == Arch_x86) ? x86::pf : x86_64::pf)); - break; - case x86::iaf: - otherRead.insert(makeRegFromID((archDecodedFrom == Arch_x86) ? x86::af : x86_64::af)); - break; - case x86::izf: - otherRead.insert(makeRegFromID((archDecodedFrom == Arch_x86) ? x86::zf : x86_64::zf)); - break; - case x86::isf: - otherRead.insert(makeRegFromID((archDecodedFrom == Arch_x86) ? x86::sf : x86_64::sf)); - break; - case x86::itf: - otherRead.insert(makeRegFromID((archDecodedFrom == Arch_x86) ? x86::tf : x86_64::tf)); - break; - case x86::idf: - otherRead.insert(makeRegFromID((archDecodedFrom == Arch_x86) ? x86::df : x86_64::df)); - break; - case x86::iof: - otherRead.insert(makeRegFromID((archDecodedFrom == Arch_x86) ? x86::of : x86_64::of)); - break; - case x86::int_: - otherRead.insert(makeRegFromID((archDecodedFrom == Arch_x86) ? x86::nt_ : x86_64::nt_)); - break; - case x86::iif_: - otherRead.insert(makeRegFromID((archDecodedFrom == Arch_x86) ? x86::if_ : x86_64::if_)); - break; - default: - assert(0); - } - } - for(unsigned j = 0; j < found->second.writtenFlags.size(); j++) - { - switch(found->second.writtenFlags[j]) { - case x86::icf: - otherWritten.insert(makeRegFromID((archDecodedFrom == Arch_x86) ? x86::cf : x86_64::cf)); - break; - case x86::ipf: - otherWritten.insert(makeRegFromID((archDecodedFrom == Arch_x86) ? x86::pf : x86_64::pf)); - break; - case x86::iaf: - otherWritten.insert(makeRegFromID((archDecodedFrom == Arch_x86) ? x86::af : x86_64::af)); - break; - case x86::izf: - otherWritten.insert(makeRegFromID((archDecodedFrom == Arch_x86) ? x86::zf : x86_64::zf)); - break; - case x86::isf: - otherWritten.insert(makeRegFromID((archDecodedFrom == Arch_x86) ? x86::sf : x86_64::sf)); - break; - case x86::itf: - otherWritten.insert(makeRegFromID((archDecodedFrom == Arch_x86) ? x86::tf : x86_64::tf)); - break; - case x86::idf: - otherWritten.insert(makeRegFromID((archDecodedFrom == Arch_x86) ? x86::df : x86_64::df)); - break; - case x86::iof: - otherWritten.insert(makeRegFromID((archDecodedFrom == Arch_x86) ? x86::of : x86_64::of)); - break; - case x86::int_: - otherWritten.insert(makeRegFromID((archDecodedFrom == Arch_x86) ? x86::nt_ : x86_64::nt_)); - break; - case x86::iif_: - otherWritten.insert(makeRegFromID((archDecodedFrom == Arch_x86) ? x86::if_ : x86_64::if_)); - break; - default: - fprintf(stderr, "ERROR: unhandled entry %s\n", found->second.writtenFlags[j].name().c_str()); - assert(0); - } - } - } - doneFlagsSetup = true; - } - doneOtherSetup = true; -#else - (void) needFlags; //Silence warnings -#endif //defined(arch_x86) || defined(arch_x86_64) + #if defined(arch_x86) || defined(arch_x86_64) + std::call_once(data_initialized, [&]() { + if (prefixID == prefix_rep || prefixID == prefix_repnz) { + otherRead.insert(makeRegFromID((archDecodedFrom == Arch_x86) ? x86::df : x86_64::df)); + otherRead.insert(makeRegFromID((archDecodedFrom == Arch_x86) ? x86::ecx : x86_64::rcx)); + otherWritten.insert(makeRegFromID((archDecodedFrom == Arch_x86) ? x86::ecx : x86_64::rcx)); + if(prefixID == prefix_repnz) + { + otherRead.insert(makeRegFromID((archDecodedFrom == Arch_x86) ? x86::zf : x86_64::zf)); + } + } + switch(segPrefix) + { + case PREFIX_SEGCS: + otherRead.insert(makeRegFromID((archDecodedFrom == Arch_x86) ? x86::cs : x86_64::cs)); + break; + case PREFIX_SEGDS: + otherRead.insert(makeRegFromID((archDecodedFrom == Arch_x86) ? x86::ds : x86_64::ds)); + break; + case PREFIX_SEGES: + otherRead.insert(makeRegFromID((archDecodedFrom == Arch_x86) ? x86::es : x86_64::es)); + break; + case PREFIX_SEGFS: + otherRead.insert(makeRegFromID((archDecodedFrom == Arch_x86) ? x86::fs : x86_64::fs)); + break; + case PREFIX_SEGGS: + otherRead.insert(makeRegFromID((archDecodedFrom == Arch_x86) ? x86::gs : x86_64::gs)); + break; + case PREFIX_SEGSS: + otherRead.insert(makeRegFromID((archDecodedFrom == Arch_x86) ? x86::ss : x86_64::ss)); + break; + } + + OperationMaps::reg_info_t::const_accessor a, b; + if (op_data(archDecodedFrom).nonOperandRegisterReads.find(a, operationID)) { + otherRead.insert(a->second.begin(), a->second.end()); + } + if (op_data(archDecodedFrom).nonOperandRegisterWrites.find(b, operationID)) { + otherWritten.insert(b->second.begin(), b->second.end()); + } + OperationMaps::mem_info_t::const_accessor c, d; + if (op_data(archDecodedFrom).nonOperandMemoryReads.find(c, operationID)) { + otherEffAddrsRead.insert(c->second.begin(), c->second.end()); + } + if (operationID == e_push) { + BinaryFunction::funcT::Ptr adder(new BinaryFunction::addResult()); + // special case for push: we write at the new value of the SP. + Result dummy(addrWidth, 0); + Expression::Ptr push_addr(new BinaryFunction( + *(op_data(archDecodedFrom).stackPointerAsExpr.begin()), + Immediate::makeImmediate(Result(s8, -(dummy.size()))), + addrWidth, + adder)); + + otherEffAddrsWritten.insert(push_addr); + + } else { + if (op_data(archDecodedFrom).nonOperandMemoryWrites.find(d, operationID)) { + otherEffAddrsWritten.insert(d->second.begin(), d->second.end()); + } + } + + dyn_hash_map::const_iterator found = ia32_instruction::getFlagTable().find(operationID); + if (found != ia32_instruction::getFlagTable().end()) { + for (unsigned i = 0; i < found->second.readFlags.size(); i++) { + switch (found->second.readFlags[i]) { + case x86::icf: + otherRead.insert(makeRegFromID((archDecodedFrom == Arch_x86) ? x86::cf : x86_64::cf)); + break; + case x86::ipf: + otherRead.insert(makeRegFromID((archDecodedFrom == Arch_x86) ? x86::pf : x86_64::pf)); + break; + case x86::iaf: + otherRead.insert(makeRegFromID((archDecodedFrom == Arch_x86) ? x86::af : x86_64::af)); + break; + case x86::izf: + otherRead.insert(makeRegFromID((archDecodedFrom == Arch_x86) ? x86::zf : x86_64::zf)); + break; + case x86::isf: + otherRead.insert(makeRegFromID((archDecodedFrom == Arch_x86) ? x86::sf : x86_64::sf)); + break; + case x86::itf: + otherRead.insert(makeRegFromID((archDecodedFrom == Arch_x86) ? x86::tf : x86_64::tf)); + break; + case x86::idf: + otherRead.insert(makeRegFromID((archDecodedFrom == Arch_x86) ? x86::df : x86_64::df)); + break; + case x86::iof: + otherRead.insert(makeRegFromID((archDecodedFrom == Arch_x86) ? x86::of : x86_64::of)); + break; + case x86::int_: + otherRead.insert(makeRegFromID((archDecodedFrom == Arch_x86) ? x86::nt_ : x86_64::nt_)); + break; + case x86::iif_: + otherRead.insert(makeRegFromID((archDecodedFrom == Arch_x86) ? x86::if_ : x86_64::if_)); + break; + default: + assert(0); + } + } + + for (unsigned j = 0; j < found->second.writtenFlags.size(); j++) { + switch (found->second.writtenFlags[j]) { + case x86::icf: + otherWritten.insert(makeRegFromID((archDecodedFrom == Arch_x86) ? x86::cf : x86_64::cf)); + break; + case x86::ipf: + otherWritten.insert(makeRegFromID((archDecodedFrom == Arch_x86) ? x86::pf : x86_64::pf)); + break; + case x86::iaf: + otherWritten.insert(makeRegFromID((archDecodedFrom == Arch_x86) ? x86::af : x86_64::af)); + break; + case x86::izf: + otherWritten.insert(makeRegFromID((archDecodedFrom == Arch_x86) ? x86::zf : x86_64::zf)); + break; + case x86::isf: + otherWritten.insert(makeRegFromID((archDecodedFrom == Arch_x86) ? x86::sf : x86_64::sf)); + break; + case x86::itf: + otherWritten.insert(makeRegFromID((archDecodedFrom == Arch_x86) ? x86::tf : x86_64::tf)); + break; + case x86::idf: + otherWritten.insert(makeRegFromID((archDecodedFrom == Arch_x86) ? x86::df : x86_64::df)); + break; + case x86::iof: + otherWritten.insert(makeRegFromID((archDecodedFrom == Arch_x86) ? x86::of : x86_64::of)); + break; + case x86::int_: + otherWritten.insert(makeRegFromID((archDecodedFrom == Arch_x86) ? x86::nt_ : x86_64::nt_)); + break; + case x86::iif_: + otherWritten.insert(makeRegFromID((archDecodedFrom == Arch_x86) ? x86::if_ : x86_64::if_)); + break; + default: + fprintf(stderr, "ERROR: unhandled entry %s\n", + found->second.writtenFlags[j].name().c_str()); + assert(0); + } + } + } + }); +#endif return; } } diff --git a/instructionAPI/src/Register.C b/instructionAPI/src/Register.C index 9ccbe8f639..685ad0ab26 100644 --- a/instructionAPI/src/Register.C +++ b/instructionAPI/src/Register.C @@ -37,6 +37,7 @@ #include "../../common/src/singleton_object_pool.h" #include "InstructionDecoder-power.h" #include "dyn_regs.h" +#include "ArchSpecificFormatters.h" using namespace std; @@ -88,14 +89,9 @@ namespace Dyninst return m_Reg; } - std::string RegisterAST::format(ArchSpecificFormatter *formatter, formatStyle) const + std::string RegisterAST::format(Architecture arch, formatStyle) const { - return formatter->formatRegister(m_Reg.name()); - } - - std::string MaskRegisterAST::format(ArchSpecificFormatter* formatter, formatStyle) const - { - return formatter->formatRegister(m_Reg.name()); + return ArchSpecificFormatter::getFormatter(arch).formatRegister(m_Reg.name()); } std::string RegisterAST::format(formatStyle) const @@ -111,6 +107,10 @@ namespace Dyninst std::transform(name.begin(), name.end(), name.begin(), ::toupper); return name; } + std::string MaskRegisterAST::format(Architecture, formatStyle f) const + { + return format(f); + } std::string MaskRegisterAST::format(formatStyle) const { @@ -122,10 +122,7 @@ namespace Dyninst } /* The syntax for a masking register is {kX} in AT&T syntax. */ - std::stringstream ss; - ss << "{" << name << "}"; - - return ss.str(); + return "{" + name + "}"; } diff --git a/instructionAPI/src/power_opcode_tables.C b/instructionAPI/src/power_opcode_tables.C index 43c3f93f31..a332c21a57 100644 --- a/instructionAPI/src/power_opcode_tables.C +++ b/instructionAPI/src/power_opcode_tables.C @@ -27,7 +27,7 @@ * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -bool power_entry::built_tables = false; +std::once_flag built_tables; std::vector power_entry::main_opcode_table; power_table power_entry::extended_op_0; @@ -42,9 +42,11 @@ power_table power_entry::extended_op_60; power_table power_entry::extended_op_61; power_table power_entry::extended_op_63; +power_entry invalid_entry; + void power_entry::buildTables() { - if(built_tables) return; + std::call_once(built_tables, [&]() { main_opcode_table.push_back(power_entry(power_op_extended, "extended", fn(extended_op_0), operandSpec())); main_opcode_table.push_back(power_entry(power_op_INVALID, "INVALID", NULL, operandSpec())); main_opcode_table.push_back(power_entry(power_op_tdi, "tdi", NULL, list_of(fn(TO))(fn(RA))(fn(SI)))); @@ -125,66 +127,73 @@ void power_entry::buildTables() main_opcode_table.push_back(power_entry(power_op_stdu, "stdu", NULL, list_of(fn(RS))(fn(STU)))); main_opcode_table.push_back(power_entry(power_op_extended, "extended", fn(extended_op_63), operandSpec())); - extended_op_0[1] = power_entry(power_op_qvfxxmadds, "qvfxxmadds", NULL, + extended_op_0[1] = power_entry(power_op_qvfxxmadds, "qvfxxmadds", NULL, list_of(fn(setFPMode))(fn(QFRTP))(fn(QFRA))(fn(QRB))(fn(QFRCP))); - extended_op_0[3] = power_entry(power_op_qvfxxcpnmadds, "qvfxxcpnmadds", NULL, + extended_op_0[3] = power_entry(power_op_qvfxxcpnmadds, "qvfxxcpnmadds", NULL, list_of(fn(setFPMode))(fn(QFRTP))(fn(QFRA))(fn(QRB))(fn(QFRCP))); - extended_op_0[5] = power_entry(power_op_fpsel, "fpsel", NULL, - list_of(fn(setFPMode))(fn(FRTP))(fn(FRAP))(fn(FRBP))(fn(FRCP))); - extended_op_0[8] = power_entry(power_op_fpmul, "fpmul", NULL, list_of(fn(setFPMode))(fn(FRTP))(fn(FRAP))(fn(FRCP))); - extended_op_0[10] = power_entry(power_op_fxpmul, "fxpmul", NULL, list_of(fn(setFPMode))(fn(FRTP))(fn(FRA))(fn(FRCP))); - extended_op_0[12] = power_entry(power_op_fpadd, "fpadd", NULL, list_of(fn(setFPMode))(fn(FRTP))(fn(FRAP))(fn(FRBP))); - extended_op_0[13] = power_entry(power_op_fpsub, "fpsub", NULL, list_of(fn(setFPMode))(fn(FRTP))(fn(FRAP))(fn(FRBP))); - extended_op_0[14] = power_entry(power_op_fpre, "fpre", NULL, list_of(fn(setFPMode))(fn(FRTP))(fn(FRBP))); - extended_op_0[15] = power_entry(power_op_fprsqrte, "fprsqrte", NULL, list_of(fn(setFPMode))(fn(FRTP))(fn(FRBP))); - extended_op_0[16] = power_entry(power_op_fpmadd, "fpmadd", NULL, -list_of(fn(setFPMode))(fn(FRTP))(fn(FRAP))(fn(FRBP))(fn(FRCP))); - extended_op_0[17] = power_entry(power_op_fxmadd, "fxmadd", NULL, -list_of(fn(setFPMode))(fn(FRTP))(fn(FRAP))(fn(FRBP))(fn(FRCP))); - extended_op_0[18] = power_entry(power_op_fxcpmadd, "fxcpmadd", NULL, -list_of(fn(setFPMode))(fn(FRTP))(fn(FRA))(fn(FRBP))(fn(FRCP))); - extended_op_0[19] = power_entry(power_op_fxcsmadd, "fxcsmadd", NULL, -list_of(fn(setFPMode))(fn(FRTP))(fn(FRAS))(fn(FRBP))(fn(FRCP))); + extended_op_0[5] = power_entry(power_op_fpsel, "fpsel", NULL, + list_of(fn(setFPMode))(fn(FRTP))(fn(FRAP))(fn(FRBP))(fn(FRCP))); + extended_op_0[8] = power_entry(power_op_fpmul, "fpmul", NULL, + list_of(fn(setFPMode))(fn(FRTP))(fn(FRAP))(fn(FRCP))); + extended_op_0[10] = power_entry(power_op_fxpmul, "fxpmul", NULL, + list_of(fn(setFPMode))(fn(FRTP))(fn(FRA))(fn(FRCP))); + extended_op_0[12] = power_entry(power_op_fpadd, "fpadd", NULL, + list_of(fn(setFPMode))(fn(FRTP))(fn(FRAP))(fn(FRBP))); + extended_op_0[13] = power_entry(power_op_fpsub, "fpsub", NULL, + list_of(fn(setFPMode))(fn(FRTP))(fn(FRAP))(fn(FRBP))); + extended_op_0[14] = power_entry(power_op_fpre, "fpre", NULL, list_of(fn(setFPMode))(fn(FRTP))(fn(FRBP))); + extended_op_0[15] = power_entry(power_op_fprsqrte, "fprsqrte", NULL, + list_of(fn(setFPMode))(fn(FRTP))(fn(FRBP))); + extended_op_0[16] = power_entry(power_op_fpmadd, "fpmadd", NULL, + list_of(fn(setFPMode))(fn(FRTP))(fn(FRAP))(fn(FRBP))(fn(FRCP))); + extended_op_0[17] = power_entry(power_op_fxmadd, "fxmadd", NULL, + list_of(fn(setFPMode))(fn(FRTP))(fn(FRAP))(fn(FRBP))(fn(FRCP))); + extended_op_0[18] = power_entry(power_op_fxcpmadd, "fxcpmadd", NULL, + list_of(fn(setFPMode))(fn(FRTP))(fn(FRA))(fn(FRBP))(fn(FRCP))); + extended_op_0[19] = power_entry(power_op_fxcsmadd, "fxcsmadd", NULL, + list_of(fn(setFPMode))(fn(FRTP))(fn(FRAS))(fn(FRBP))(fn(FRCP))); #ifdef os_bgq - extended_op_0[9] = power_entry(power_op_qvfxmadds, "qvfxmadds", NULL, - list_of(fn(setFPMode))(fn(QFRTP))(fn(QFRA))(fn(QRB))(fn(QFRCP))); - extended_op_0[11] = power_entry(power_op_qvfxxnpmadds, "qvfxxnpmadds", NULL, - list_of(fn(setFPMode))(fn(QFRTP))(fn(QFRA))(fn(QRB))(fn(QFRCP))); - extended_op_0[17] = power_entry(power_op_qvfxmuls, "qvfxmuls", NULL, list_of(fn(setFPMode))(fn(QFRTP))(fn(QFRA))(fn(QFRCP))); - extended_op_0[20] = power_entry(power_op_qvfsubs, "qvfsubs", NULL, list_of(fn(setFPMode))(fn(QFRTP))(fn(QFRA))(fn(QRB))); - extended_op_0[21] = power_entry(power_op_qvfadds, "qvfadds", NULL, list_of(fn(setFPMode))(fn(QFRTP))(fn(QFRA))(fn(QRB))); - extended_op_0[24] = power_entry(power_op_qvfres, "qvfres", NULL, list_of(fn(setFPMode))(fn(QFRTP))(fn(QRB))); - extended_op_0[25] = power_entry(power_op_qvfmuls, "qvfmuls", NULL, list_of(fn(setFPMode))(fn(QFRTP))(fn(QFRA))(fn(QFRCP))); - extended_op_0[26] = power_entry(power_op_qvfrsqrtes, "qvfrsqrtes", NULL, list_of(fn(setFPMode))(fn(QFRTP))(fn(QRB))); - extended_op_0[28] = power_entry(power_op_qvfmsubs, "qvfmsubs", NULL, - list_of(fn(setFPMode))(fn(QFRTP))(fn(QFRA))(fn(QRB))(fn(QFRCP))); - extended_op_0[29] = power_entry(power_op_qvfmadds, "qvfmadds", NULL, - list_of(fn(setFPMode))(fn(QFRTP))(fn(QFRA))(fn(QRB))(fn(QFRCP))); - extended_op_0[30] = power_entry(power_op_qvfnmsubs, "qvfnmsubs", NULL, - list_of(fn(setFPMode))(fn(QFRTP))(fn(QFRA))(fn(QRB))(fn(QFRCP))); - extended_op_0[31] = power_entry(power_op_qvfnmadds, "qvfnmadds", NULL, - list_of(fn(setFPMode))(fn(QFRTP))(fn(QFRA))(fn(QRB))(fn(QFRCP))); + extended_op_0[9] = power_entry(power_op_qvfxmadds, "qvfxmadds", NULL, + list_of(fn(setFPMode))(fn(QFRTP))(fn(QFRA))(fn(QRB))(fn(QFRCP))); + extended_op_0[11] = power_entry(power_op_qvfxxnpmadds, "qvfxxnpmadds", NULL, + list_of(fn(setFPMode))(fn(QFRTP))(fn(QFRA))(fn(QRB))(fn(QFRCP))); + extended_op_0[17] = power_entry(power_op_qvfxmuls, "qvfxmuls", NULL, list_of(fn(setFPMode))(fn(QFRTP))(fn(QFRA))(fn(QFRCP))); + extended_op_0[20] = power_entry(power_op_qvfsubs, "qvfsubs", NULL, list_of(fn(setFPMode))(fn(QFRTP))(fn(QFRA))(fn(QRB))); + extended_op_0[21] = power_entry(power_op_qvfadds, "qvfadds", NULL, list_of(fn(setFPMode))(fn(QFRTP))(fn(QFRA))(fn(QRB))); + extended_op_0[24] = power_entry(power_op_qvfres, "qvfres", NULL, list_of(fn(setFPMode))(fn(QFRTP))(fn(QRB))); + extended_op_0[25] = power_entry(power_op_qvfmuls, "qvfmuls", NULL, list_of(fn(setFPMode))(fn(QFRTP))(fn(QFRA))(fn(QFRCP))); + extended_op_0[26] = power_entry(power_op_qvfrsqrtes, "qvfrsqrtes", NULL, list_of(fn(setFPMode))(fn(QFRTP))(fn(QRB))); + extended_op_0[28] = power_entry(power_op_qvfmsubs, "qvfmsubs", NULL, + list_of(fn(setFPMode))(fn(QFRTP))(fn(QFRA))(fn(QRB))(fn(QFRCP))); + extended_op_0[29] = power_entry(power_op_qvfmadds, "qvfmadds", NULL, + list_of(fn(setFPMode))(fn(QFRTP))(fn(QFRA))(fn(QRB))(fn(QFRCP))); + extended_op_0[30] = power_entry(power_op_qvfnmsubs, "qvfnmsubs", NULL, + list_of(fn(setFPMode))(fn(QFRTP))(fn(QFRA))(fn(QRB))(fn(QFRCP))); + extended_op_0[31] = power_entry(power_op_qvfnmadds, "qvfnmadds", NULL, + list_of(fn(setFPMode))(fn(QFRTP))(fn(QFRA))(fn(QRB))(fn(QFRCP))); #else - extended_op_0[9] = power_entry(power_op_fxmul, "fxmul", NULL, list_of(fn(setFPMode))(fn(FRTP))(fn(FRAP))(fn(FRCP))); - extended_op_0[11] = power_entry(power_op_fxsmul, "fxsmul", NULL, list_of(fn(setFPMode))(fn(FRTP))(fn(FRAS))(fn(FRCP))); - extended_op_0[20] = power_entry(power_op_fpnmadd, "fpnmadd", NULL, -list_of(fn(setFPMode))(fn(FRTP))(fn(FRAP))(fn(FRBP))(fn(FRCP))); - extended_op_0[21] = power_entry(power_op_fxnmadd, "fxnmadd", NULL, -list_of(fn(setFPMode))(fn(FRTP))(fn(FRAP))(fn(FRBP))(fn(FRCP))); - extended_op_0[24] = power_entry(power_op_fpmsub, "fpmsub", NULL, -list_of(fn(setFPMode))(fn(FRTP))(fn(FRAP))(fn(FRBP))(fn(FRCP))); - extended_op_0[25] = power_entry(power_op_fxmsub, "fxmsub", NULL, -list_of(fn(setFPMode))(fn(FRTP))(fn(FRAP))(fn(FRBP))(fn(FRCP))); - extended_op_0[26] = power_entry(power_op_fxcpmsub, "fxcpmsub", NULL, -list_of(fn(setFPMode))(fn(FRTP))(fn(FRA))(fn(FRBP))(fn(FRCP))); - extended_op_0[28] = power_entry(power_op_fpnmsub, "fpnmsub", NULL, -list_of(fn(setFPMode))(fn(FRTP))(fn(FRAP))(fn(FRBP))(fn(FRCP))); - extended_op_0[29] = power_entry(power_op_fxnmsub, "fxnmsub", NULL, -list_of(fn(setFPMode))(fn(FRTP))(fn(FRAP))(fn(FRBP))(fn(FRCP))); - extended_op_0[30] = power_entry(power_op_fxcpnmsub, "fxcpnmsub", NULL, -list_of(fn(setFPMode))(fn(FRTP))(fn(FRA))(fn(FRBP))(fn(FRCP))); - extended_op_0[31] = power_entry(power_op_fxcsnmsub, "fxcsnmsub", NULL, -list_of(fn(setFPMode))(fn(FRTP))(fn(FRAS))(fn(FRBP))(fn(FRCP))); + extended_op_0[9] = power_entry(power_op_fxmul, "fxmul", NULL, + list_of(fn(setFPMode))(fn(FRTP))(fn(FRAP))(fn(FRCP))); + extended_op_0[11] = power_entry(power_op_fxsmul, "fxsmul", NULL, + list_of(fn(setFPMode))(fn(FRTP))(fn(FRAS))(fn(FRCP))); + extended_op_0[20] = power_entry(power_op_fpnmadd, "fpnmadd", NULL, + list_of(fn(setFPMode))(fn(FRTP))(fn(FRAP))(fn(FRBP))(fn(FRCP))); + extended_op_0[21] = power_entry(power_op_fxnmadd, "fxnmadd", NULL, + list_of(fn(setFPMode))(fn(FRTP))(fn(FRAP))(fn(FRBP))(fn(FRCP))); + extended_op_0[24] = power_entry(power_op_fpmsub, "fpmsub", NULL, + list_of(fn(setFPMode))(fn(FRTP))(fn(FRAP))(fn(FRBP))(fn(FRCP))); + extended_op_0[25] = power_entry(power_op_fxmsub, "fxmsub", NULL, + list_of(fn(setFPMode))(fn(FRTP))(fn(FRAP))(fn(FRBP))(fn(FRCP))); + extended_op_0[26] = power_entry(power_op_fxcpmsub, "fxcpmsub", NULL, + list_of(fn(setFPMode))(fn(FRTP))(fn(FRA))(fn(FRBP))(fn(FRCP))); + extended_op_0[28] = power_entry(power_op_fpnmsub, "fpnmsub", NULL, + list_of(fn(setFPMode))(fn(FRTP))(fn(FRAP))(fn(FRBP))(fn(FRCP))); + extended_op_0[29] = power_entry(power_op_fxnmsub, "fxnmsub", NULL, + list_of(fn(setFPMode))(fn(FRTP))(fn(FRAP))(fn(FRBP))(fn(FRCP))); + extended_op_0[30] = power_entry(power_op_fxcpnmsub, "fxcpnmsub", NULL, + list_of(fn(setFPMode))(fn(FRTP))(fn(FRA))(fn(FRBP))(fn(FRCP))); + extended_op_0[31] = power_entry(power_op_fxcsnmsub, "fxcsnmsub", NULL, + list_of(fn(setFPMode))(fn(FRTP))(fn(FRAS))(fn(FRBP))(fn(FRCP))); #endif extended_op_0[22] = power_entry(power_op_fxcpnmadd, "fxcpnmadd", NULL, list_of(fn(setFPMode))(fn(FRTP))(fn(FRA))(fn(FRBP))(fn(FRCP))); @@ -215,17 +224,17 @@ list_of(fn(setFPMode))(fn(FRTP))(fn(FRAS))(fn(FRBP))(fn(FRCP))); list_of(fn(setFPMode))(fn(QFRTP))(fn(QFRA))(fn(QRB))); extended_op_4[1] = power_entry(power_op_qvfxxmadd, "qvfxxmadd", NULL, list_of(fn(setFPMode))(fn(QFRTP))(fn(QFRA))(fn(QRB))(fn(QFRCP))); - extended_op_4[3] = power_entry(power_op_qvfxxcpnmadd, "qvfxxcpnmadd", NULL, + extended_op_4[3] = power_entry(power_op_qvfxxcpnmadd, "qvfxxcpnmadd", NULL, list_of(fn(setFPMode))(fn(QFRTP))(fn(QFRA))(fn(QRB))(fn(QFRCP))); - extended_op_4[4] = power_entry(power_op_qvflogical, "qvflogical", NULL, + extended_op_4[4] = power_entry(power_op_qvflogical, "qvflogical", NULL, list_of(fn(setFPMode))(fn(QFRTP))(fn(QFRA))(fn(QRB))(fn(QTT))); - extended_op_4[5] = power_entry(power_op_qvfaligni, "qvfaligni", NULL, + extended_op_4[5] = power_entry(power_op_qvfaligni, "qvfaligni", NULL, list_of(fn(setFPMode))(fn(QFRTP))(fn(QFRA))(fn(QRB))(fn(QVD))); - extended_op_4[6] = power_entry(power_op_qvfperm, "qvfperm", NULL, + extended_op_4[6] = power_entry(power_op_qvfperm, "qvfperm", NULL, list_of(fn(setFPMode))(fn(QFRTP))(fn(QFRA))(fn(QRB))(fn(QFRCP))); - extended_op_4[8] = power_entry(power_op_qvfcpsgn, "qvfcpsgn", NULL, + extended_op_4[8] = power_entry(power_op_qvfcpsgn, "qvfcpsgn", NULL, list_of(fn(setFPMode))(fn(QFRTP))(fn(QFRA))(fn(QRB))); - extended_op_4[9] = power_entry(power_op_qvfxmadd, "qvfxmadd", NULL, + extended_op_4[9] = power_entry(power_op_qvfxmadd, "qvfxmadd", NULL, list_of(fn(setFPMode))(fn(QFRTP))(fn(QFRA))(fn(QRB))(fn(QFRCP))); extended_op_4[11] = power_entry(power_op_qvfxxnpmadd, "qvfxxnpmadd", NULL, list_of(fn(setFPMode))(fn(QFRTP))(fn(QFRA))(fn(QRB))(fn(QFRCP))); @@ -252,31 +261,32 @@ extended_op_4[12] = power_entry(power_op_vmrghb, "vmrghb", NULL, list_of(fn(VRT) extended_op_4[14] = power_entry(power_op_vpkuhum, "vpkuhum", NULL, list_of(fn(VRT))(fn(VRA))(fn(VRB))); #ifdef os_bgq - extended_op_4[24] = power_entry(power_op_qvfre, "qvfre", NULL, list_of(fn(setFPMode))(fn(QFRTP))(fn(QRB))); - extended_op_4[25] = power_entry(power_op_qvfmul, "qvfmul", NULL, list_of(fn(setFPMode))(fn(QFRTP))(fn(QFRA))(fn(QFRCP))); - extended_op_4[26] = power_entry(power_op_qvfrsqrte, "qvfrsqrte", NULL, list_of(fn(setFPMode))(fn(QFRTP))(fn(QRB))); - extended_op_4[28] = power_entry(power_op_qvfmsub, "qvfmsub", NULL, - list_of(fn(setFPMode))(fn(QFRTP))(fn(QFRA))(fn(QRB))(fn(QFRCP))); - extended_op_4[29] = power_entry(power_op_qvfmadd, "qvfmadd", NULL, - list_of(fn(setFPMode))(fn(QFRTP))(fn(QFRA))(fn(QRB))(fn(QFRCP))); - extended_op_4[30] = power_entry(power_op_qvfnmsub, "qvfnmsub", NULL, - list_of(fn(setFPMode))(fn(QFRTP))(fn(QFRA))(fn(QRB))(fn(QFRCP))); - extended_op_4[31] = power_entry(power_op_qvfnmadd, "qvfnmadd", NULL, - list_of(fn(setFPMode))(fn(QFRTP))(fn(QFRA))(fn(QRB))(fn(QFRCP))); + extended_op_4[24] = power_entry(power_op_qvfre, "qvfre", NULL, list_of(fn(setFPMode))(fn(QFRTP))(fn(QRB))); + extended_op_4[25] = power_entry(power_op_qvfmul, "qvfmul", NULL, list_of(fn(setFPMode))(fn(QFRTP))(fn(QFRA))(fn(QFRCP))); + extended_op_4[26] = power_entry(power_op_qvfrsqrte, "qvfrsqrte", NULL, list_of(fn(setFPMode))(fn(QFRTP))(fn(QRB))); + extended_op_4[28] = power_entry(power_op_qvfmsub, "qvfmsub", NULL, + list_of(fn(setFPMode))(fn(QFRTP))(fn(QFRA))(fn(QRB))(fn(QFRCP))); + extended_op_4[29] = power_entry(power_op_qvfmadd, "qvfmadd", NULL, + list_of(fn(setFPMode))(fn(QFRTP))(fn(QFRA))(fn(QRB))(fn(QFRCP))); + extended_op_4[30] = power_entry(power_op_qvfnmsub, "qvfnmsub", NULL, + list_of(fn(setFPMode))(fn(QFRTP))(fn(QFRA))(fn(QRB))(fn(QFRCP))); + extended_op_4[31] = power_entry(power_op_qvfnmadd, "qvfnmadd", NULL, + list_of(fn(setFPMode))(fn(QFRTP))(fn(QFRA))(fn(QRB))(fn(QFRCP))); #else - extended_op_4[24] = power_entry(power_op_fxcpnpma, "fxcpnpma", NULL, - list_of(fn(setFPMode))(fn(FRTP))(fn(FRA))(fn(FRBP))(fn(FRCP))); - extended_op_4[25] = power_entry(power_op_fxcsnpma, "fxcsnpma", NULL, - list_of(fn(setFPMode))(fn(FRTP))(fn(FRAS))(fn(FRBP))(fn(FRCP))); - extended_op_4[26] = power_entry(power_op_fxcpnsma, "fxcpnsma", NULL, - list_of(fn(setFPMode))(fn(FRTP))(fn(FRA))(fn(FRBP))(fn(FRCP))); - extended_op_4[28] = power_entry(power_op_fxcxnpma, "fxcxnpma", NULL, - list_of(fn(setFPMode))(fn(FRTP))(fn(FRAS))(fn(FRBP))(fn(FRCP))); - extended_op_4[29] = power_entry(power_op_fxcxnsma, "fxcxnsma", NULL, - list_of(fn(setFPMode))(fn(FRTP))(fn(FRAS))(fn(FRBP))(fn(FRCP))); - extended_op_4[30] = power_entry(power_op_fxcxma, "fxcxma", NULL, list_of(fn(setFPMode))(fn(FRTP))(fn(FRAS))(fn(FRBP))(fn(FRCP))); - extended_op_4[31] = power_entry(power_op_fxcxnms, "fxcxnms", NULL, - list_of(fn(setFPMode))(fn(FRTP))(fn(FRAS))(fn(FRBP))(fn(FRCP))); + extended_op_4[24] = power_entry(power_op_fxcpnpma, "fxcpnpma", NULL, + list_of(fn(setFPMode))(fn(FRTP))(fn(FRA))(fn(FRBP))(fn(FRCP))); + extended_op_4[25] = power_entry(power_op_fxcsnpma, "fxcsnpma", NULL, + list_of(fn(setFPMode))(fn(FRTP))(fn(FRAS))(fn(FRBP))(fn(FRCP))); + extended_op_4[26] = power_entry(power_op_fxcpnsma, "fxcpnsma", NULL, + list_of(fn(setFPMode))(fn(FRTP))(fn(FRA))(fn(FRBP))(fn(FRCP))); + extended_op_4[28] = power_entry(power_op_fxcxnpma, "fxcxnpma", NULL, + list_of(fn(setFPMode))(fn(FRTP))(fn(FRAS))(fn(FRBP))(fn(FRCP))); + extended_op_4[29] = power_entry(power_op_fxcxnsma, "fxcxnsma", NULL, + list_of(fn(setFPMode))(fn(FRTP))(fn(FRAS))(fn(FRBP))(fn(FRCP))); + extended_op_4[30] = power_entry(power_op_fxcxma, "fxcxma", NULL, + list_of(fn(setFPMode))(fn(FRTP))(fn(FRAS))(fn(FRBP))(fn(FRCP))); + extended_op_4[31] = power_entry(power_op_fxcxnms, "fxcxnms", NULL, + list_of(fn(setFPMode))(fn(FRTP))(fn(FRAS))(fn(FRBP))(fn(FRCP))); #endif extended_op_4[27] = power_entry(power_op_fxcsnsma, "fxcsnsma", NULL, list_of(fn(setFPMode))(fn(FRTP))(fn(FRAS))(fn(FRBP))(fn(FRCP))); @@ -582,13 +592,15 @@ extended_op_19[417] = power_entry(power_op_crorc, "crorc", NULL, list_of(fn(BT)) extended_op_19[449] = power_entry(power_op_cror, "cror", NULL, list_of(fn(BT))(fn(BA))(fn(BB))); extended_op_19[528] = power_entry(power_op_bcctr, "bcctr", NULL, list_of(fn(BO))(fn(BI))(fn(LK))); - power_entry::extended_op_30[1] = power_entry(power_op_rldicr, "rldicr", NULL, - list_of(fn(RA))(fn(RS))(fn(SH))(fn(ME))(fn(Rc))); -extended_op_30[2] = power_entry(power_op_rldic, "rldic", NULL, list_of(fn(RA))(fn(RS))(fn(SH))(fn(MB))(fn(Rc))); -extended_op_30[3] = power_entry(power_op_rldimi, "rldimi", NULL, list_of(fn(RA))(fn(RS))(fn(SH))(fn(MB))(fn(Rc))); -extended_op_30[8] = power_entry(power_op_rldcl, "rldcl", NULL, list_of(fn(RA))(fn(RS))(fn(RB))(fn(MB))(fn(Rc))); -extended_op_30[9] = power_entry(power_op_rldcr, "rldcr", NULL, list_of(fn(RA))(fn(RS))(fn(RB))(fn(ME))(fn(Rc))); -extended_op_30[0] = power_entry(power_op_rldicl, "rldicl", NULL, list_of(fn(RA))(fn(RS))(fn(SH))(fn(MB))(fn(SH))(fn(Rc))); + power_entry::extended_op_30[1] = power_entry(power_op_rldicr, "rldicr", NULL, + list_of(fn(RA))(fn(RS))(fn(SH))(fn(ME))(fn(Rc))); + extended_op_30[2] = power_entry(power_op_rldic, "rldic", NULL, list_of(fn(RA))(fn(RS))(fn(SH))(fn(MB))(fn(Rc))); + extended_op_30[3] = power_entry(power_op_rldimi, "rldimi", NULL, + list_of(fn(RA))(fn(RS))(fn(SH))(fn(MB))(fn(Rc))); + extended_op_30[8] = power_entry(power_op_rldcl, "rldcl", NULL, list_of(fn(RA))(fn(RS))(fn(RB))(fn(MB))(fn(Rc))); + extended_op_30[9] = power_entry(power_op_rldcr, "rldcr", NULL, list_of(fn(RA))(fn(RS))(fn(RB))(fn(ME))(fn(Rc))); + extended_op_30[0] = power_entry(power_op_rldicl, "rldicl", NULL, + list_of(fn(RA))(fn(RS))(fn(SH))(fn(MB))(fn(Rc))); power_entry::extended_op_31[0] = power_entry(power_op_cmp, "cmp", NULL, list_of(fn(BF))(fn(L))(fn(RA))(fn(RB))); extended_op_31[4] = power_entry(power_op_tw, "tw", NULL, list_of(fn(TO))(fn(RA))(fn(RB))); @@ -617,8 +629,7 @@ extended_op_31[54] = power_entry(power_op_dcbst, "dcbst", NULL, list_of(fn(RA))( extended_op_31[55] = power_entry(power_op_lwzux, "lwzux", NULL, list_of(fn(RT))(fn(LUX))); extended_op_31[58] = power_entry(power_op_cntlzd, "cntlzd", NULL, list_of(fn(RS))(fn(RA))(fn(Rc))); extended_op_31[60] = power_entry(power_op_andc, "andc", NULL, list_of(fn(RS))(fn(RA))(fn(RB))(fn(Rc))); -extended_op_31[62] = power_entry(power_op_wait, "wait", NULL, list_of(fn(WC))); -extended_op_31[68] = power_entry(power_op_td, "td", NULL, list_of(fn(TO))(fn(RA))(fn(RB))); +extended_op_31[62] = power_entry(power_op_wait, "wait", NULL, list_of(fn(WC)));extended_op_31[68] = power_entry(power_op_td, "td", NULL, list_of(fn(TO))(fn(RA))(fn(RB))); extended_op_31[70] = power_entry(power_op_qvlpcrdx, "qvlpcrdx", NULL, list_of(fn(QFRTP))(fn(LX))); extended_op_31[71] = power_entry(power_op_lvewx, "lvewx", NULL, list_of(fn(VRT))(fn(RA))(fn(RB))); extended_op_31[73] = power_entry(power_op_mulhd, "mulhd", NULL, list_of(fn(RT))(fn(RA))(fn(RB))(fn(Rc))); @@ -633,8 +644,7 @@ extended_op_31[104] = power_entry(power_op_neg, "neg", NULL, list_of(fn(RT))(fn( extended_op_31[107] = power_entry(power_op_mul, "mul", NULL, list_of(fn(RT))(fn(RA))(fn(RB))(fn(OE))(fn(Rc))); extended_op_31[118] = power_entry(power_op_clf, "clf", NULL, list_of(fn(RA))(fn(RB))(fn(Rc))); extended_op_31[119] = power_entry(power_op_lbzux, "lbzux", NULL, list_of(fn(RT))(fn(LUX))); -extended_op_31[122] = power_entry(power_op_popcntb, "popcntb", NULL, list_of(fn(RS))(fn(RA))); -extended_op_31[124] = power_entry(power_op_nor, "nor", NULL, list_of(fn(RS))(fn(RA))(fn(RB))(fn(Rc))); +extended_op_31[122] = power_entry(power_op_popcntb, "popcntb", NULL, list_of(fn(RS))(fn(RA)));extended_op_31[124] = power_entry(power_op_nor, "nor", NULL, list_of(fn(RS))(fn(RA))(fn(RB))(fn(Rc))); extended_op_31[133] = power_entry(power_op_qvstfcsxi, "qvstfcsxi", NULL, list_of(fn(QFRSP))(fn(STX))); extended_op_31[135] = power_entry(power_op_stvebx, "stvebx", NULL, list_of(fn(VRS))(fn(RA))(fn(RB))); extended_op_31[136] = power_entry(power_op_subfe, "subfe", NULL, list_of(fn(RT))(fn(RA))(fn(RB))(fn(OE))(fn(Rc))); @@ -698,10 +708,8 @@ extended_op_31[360] = power_entry(power_op_abs, "abs", NULL, list_of(fn(RT))(fn( extended_op_31[363] = power_entry(power_op_divs, "divs", NULL, list_of(fn(RT))(fn(RA))(fn(RB))(fn(Rc))); extended_op_31[364] = power_entry(power_op_lxvwsx, "lxvwsx", NULL, list_of(fn(XT))(fn(RA))(fn(RB))); extended_op_31[366] = power_entry(power_op_lfxdux, "lfxdux", NULL, list_of(fn(FRTP))(fn(LUX))); - // xop 371 is mftb (Move from time base). It is phased-out and equivalent to mfspr Rx, 268 -extended_op_31[371] = power_entry(power_op_mfspr, "mfspr", NULL, list_of(fn(RT))(fn(spr))(fn(Rc))); -extended_op_31[373] = power_entry(power_op_lwaux, "lwaux", NULL, list_of(fn(RT))(fn(LUX))); +extended_op_31[371] = power_entry(power_op_mfspr, "mfspr", NULL, list_of(fn(RT))(fn(spr))(fn(Rc)));extended_op_31[373] = power_entry(power_op_lwaux, "lwaux", NULL, list_of(fn(RT))(fn(LUX))); extended_op_31[375] = power_entry(power_op_lhaux, "lhaux", NULL, list_of(fn(RT))(fn(LUX))); extended_op_31[378] = power_entry(power_op_popcntw, "popcntw", NULL, list_of(fn(RS))(fn(RA))); extended_op_31[396] = power_entry(power_op_stxvx, "stxvx", NULL, list_of(fn(XS))(fn(RA))(fn(RB))); @@ -726,8 +734,7 @@ extended_op_31[488] = power_entry(power_op_nabs, "nabs", NULL, list_of(fn(RT))(f extended_op_31[489] = power_entry(power_op_divd, "divd", NULL, list_of(fn(RT))(fn(RA))(fn(RB))(fn(OE))(fn(Rc))); extended_op_31[491] = power_entry(power_op_divw, "divw", NULL, list_of(fn(RT))(fn(RA))(fn(RB))(fn(OE))(fn(Rc))); extended_op_31[494] = power_entry(power_op_lfpdux, "lfpdux", NULL, list_of(fn(FRTP))(fn(LUX))); -extended_op_31[502] = power_entry(power_op_cli, "cli", NULL, list_of(fn(RA))(fn(RB))(fn(Rc))); -extended_op_31[506] = power_entry(power_op_popcntd, "popcntd", NULL, list_of(fn(RS))(fn(RA))); +extended_op_31[502] = power_entry(power_op_cli, "cli", NULL, list_of(fn(RA))(fn(RB))(fn(Rc)));extended_op_31[506] = power_entry(power_op_popcntd, "popcntd", NULL, list_of(fn(RS))(fn(RA))); extended_op_31[512] = power_entry(power_op_mcrxr, "mcrxr", NULL, list_of(fn(BF))); extended_op_31[518] = power_entry(power_op_qvlpclsx, "qvlpclsx", NULL, list_of(fn(QFRTP))(fn(LX))); extended_op_31[519] = power_entry(power_op_qvlfsx, "qvlfsx", NULL, list_of(fn(QFRTP))(fn(LX))); @@ -1265,5 +1272,54 @@ extended_op_63_836[25] = power_entry(power_op_xscvqpsdz, "xscvqpsdz", list_of(fn */ -built_tables = true; + extended_op_63[0] = power_entry(power_op_fcmpu, "fcmpu", NULL, + list_of(fn(setFPMode))(fn(BF))(fn(FRA))(fn(FRB))); + extended_op_63[12] = power_entry(power_op_frsp, "frsp", NULL, list_of(fn(setFPMode))(fn(FRT))(fn(FRB))(fn(Rc))); + extended_op_63[14] = power_entry(power_op_fctiw, "fctiw", NULL, + list_of(fn(setFPMode))(fn(FRT))(fn(FRB))(fn(Rc))); + extended_op_63[15] = power_entry(power_op_fctiwz, "fctiwz", NULL, + list_of(fn(setFPMode))(fn(FRT))(fn(FRB))(fn(Rc))); + extended_op_63[18] = power_entry(power_op_fdiv, "fdiv", NULL, + list_of(fn(setFPMode))(fn(FRT))(fn(FRA))(fn(FRB))(fn(Rc))); + extended_op_63[20] = power_entry(power_op_fsub, "fsub", NULL, + list_of(fn(setFPMode))(fn(FRT))(fn(FRA))(fn(FRB))(fn(Rc))); + extended_op_63[21] = power_entry(power_op_fadd, "fadd", NULL, + list_of(fn(setFPMode))(fn(FRT))(fn(FRA))(fn(FRB))(fn(Rc))); + extended_op_63[22] = power_entry(power_op_fsqrt, "fsqrt", NULL, + list_of(fn(setFPMode))(fn(FRT))(fn(FRB))(fn(Rc))); + extended_op_63[23] = power_entry(power_op_fsel, "fsel", NULL, + list_of(fn(setFPMode))(fn(FRT))(fn(FRA))(fn(FRB))(fn(FRC))(fn(Rc))); + extended_op_63[25] = power_entry(power_op_fmul, "fmul", NULL, + list_of(fn(setFPMode))(fn(FRT))(fn(FRA))(fn(FRC))(fn(Rc))); + extended_op_63[26] = power_entry(power_op_frsqrte, "frsqrte", NULL, + list_of(fn(setFPMode))(fn(FRT))(fn(FRB))(fn(Rc))); + extended_op_63[28] = power_entry(power_op_fmsub, "fmsub", NULL, + list_of(fn(setFPMode))(fn(FRT))(fn(FRA))(fn(FRB))(fn(FRC))(fn(Rc))); + extended_op_63[29] = power_entry(power_op_fmadd, "fmadd", NULL, + list_of(fn(setFPMode))(fn(FRT))(fn(FRA))(fn(FRB))(fn(FRC))(fn(Rc))); + extended_op_63[30] = power_entry(power_op_fnmsub, "fnmsub", NULL, + list_of(fn(setFPMode))(fn(FRT))(fn(FRA))(fn(FRB))(fn(FRC))(fn(Rc))); + extended_op_63[31] = power_entry(power_op_fnmadd, "fnmadd", NULL, + list_of(fn(setFPMode))(fn(FRT))(fn(FRA))(fn(FRB))(fn(FRC))(fn(Rc))); + extended_op_63[32] = power_entry(power_op_fcmpo, "fcmpo", NULL, + list_of(fn(setFPMode))(fn(BF))(fn(FRA))(fn(FRB))); + extended_op_63[38] = power_entry(power_op_mtfsb1, "mtfsb1", NULL, list_of(fn(setFPMode))(fn(BT))(fn(Rc))); + extended_op_63[40] = power_entry(power_op_fneg, "fneg", NULL, list_of(fn(setFPMode))(fn(FRT))(fn(FRB))(fn(Rc))); + extended_op_63[64] = power_entry(power_op_mcrfs, "mcrfs", NULL, list_of(fn(BF))(fn(BFA))); + extended_op_63[70] = power_entry(power_op_mtfsb0, "mtfsb0", NULL, list_of(fn(BT))(fn(Rc))); + extended_op_63[72] = power_entry(power_op_fmr, "fmr", NULL, list_of(fn(setFPMode))(fn(FRT))(fn(FRB))(fn(Rc))); + extended_op_63[134] = power_entry(power_op_mtfsfi, "mtfsfi", NULL, list_of(fn(BF))(fn(U))(fn(Rc))); + extended_op_63[136] = power_entry(power_op_fnabs, "fnabs", NULL, list_of(fn(setFPMode))(fn(FRT))(fn(FRB))); + extended_op_63[264] = power_entry(power_op_fabs, "fabs", NULL, + list_of(fn(setFPMode))(fn(FRT))(fn(FRB))(fn(Rc))); + extended_op_63[583] = power_entry(power_op_mffs, "mffs", NULL, list_of(fn(setFPMode))(fn(FRT))(fn(Rc))); + extended_op_63[711] = power_entry(power_op_mtfsf, "mtfsf", NULL, + list_of(fn(setFPMode))(fn(FLM))(fn(FRB))(fn(Rc))); + extended_op_63[814] = power_entry(power_op_fctid, "fctid", NULL, + list_of(fn(setFPMode))(fn(FRT))(fn(FRB))(fn(Rc))); + extended_op_63[815] = power_entry(power_op_fctidz, "fctidz", NULL, + list_of(fn(setFPMode))(fn(FRT))(fn(FRB))(fn(Rc))); + extended_op_63[846] = power_entry(power_op_fcfid, "fcfid", NULL, + list_of(fn(setFPMode))(fn(FRT))(fn(FRB))(fn(Rc))); + }); } diff --git a/parseAPI/CMakeLists.txt b/parseAPI/CMakeLists.txt index 00f0045606..9253023efa 100644 --- a/parseAPI/CMakeLists.txt +++ b/parseAPI/CMakeLists.txt @@ -4,7 +4,6 @@ include_directories ( ${PROJECT_SOURCE_DIR}/parseAPI/src ) - set (SRC_LIST src/ParserDetails.C src/Parser.C @@ -110,20 +109,18 @@ endif() ADD_DEFINITIONS(-DPARSER_LIB) ADD_DEFINITIONS(-DDATAFLOW_LIB) - if(WIN32) ADD_DEFINITIONS(-DROSE_UTIL_EXPORTS) ADD_DEFINITIONS(-DNOMINMAX) endif() - dyninst_library(parseAPI common instructionAPI ${SYMREADER}) - -target_link_private_libraries(parseAPI ${Boost_LIBRARIES}) +set(OPENMP_LIBRARIES gomp) +target_link_private_libraries(parseAPI ${Boost_LIBRARIES} ${TBB_LIBRARIES} tbbmalloc) if (WIN32) target_link_private_libraries(parseAPI shlwapi) endif() - +message(STATUS "Architecture is: ${CMAKE_LIBRARY_ARCHITECTURE}") FILE (GLOB headers "h/*.h") FILE (GLOB dataflowheaders "../dataflowAPI/h/*.h") set_target_properties (parseAPI PROPERTIES PUBLIC_HEADER "${headers};${dataflowheaders}") diff --git a/parseAPI/doc/example.cc b/parseAPI/doc/example.cc index 87fcefaadf..eb5051f9d4 100644 --- a/parseAPI/doc/example.cc +++ b/parseAPI/doc/example.cc @@ -71,7 +71,7 @@ int main(int argc, char * argv[]) auto it = b->targets().begin(); for( ; it != b->targets().end(); ++it) { - + if(!*it) continue; std::string s = ""; if((*it)->type() == CALL) s = " [color=blue]"; diff --git a/parseAPI/h/CFG.h b/parseAPI/h/CFG.h index fa149e9537..a37c44d517 100644 --- a/parseAPI/h/CFG.h +++ b/parseAPI/h/CFG.h @@ -37,6 +37,7 @@ #include #include #include +#include #include "dyntypes.h" #include "IBSTree.h" @@ -44,6 +45,11 @@ #include "ParseContainers.h" #include "Annotatable.h" #include +#include +#include +#include +#include +#include "race-detector-annotations.h" namespace Dyninst { @@ -58,7 +64,8 @@ class LoopAnalyzer; class dominatorCFG; class CodeObject; class CFGModifier; - +class ParseData; +class region_data; enum EdgeTypeEnum { CALL = 0, COND_TAKEN, @@ -141,9 +148,11 @@ class Block; class PARSER_EXPORT Edge : public allocatable { friend class CFGModifier; + friend class Block; protected: Block * _source; - Block * _target; + ParseData* index; + Offset _target_off; private: @@ -173,7 +182,8 @@ class PARSER_EXPORT Edge : public allocatable { virtual ~Edge(); Block * src() const { return _source; } - Block * trg() const { return _target; } + Block * trg() const; + Address trg_addr() const { return _target_off; } EdgeTypeEnum type() const { return static_cast(_type._type_enum); } @@ -251,11 +261,11 @@ class PARSER_EXPORT Intraproc : public EdgePredicate { class Function; class PARSER_EXPORT SingleContext : public EdgePredicate { private: - Function * _context; + const Function * _context; bool _forward; bool _backward; public: - SingleContext(Function * f, bool forward, bool backward) : + SingleContext(const Function * f, bool forward, bool backward) : _context(f), _forward(forward), _backward(backward) { } @@ -267,11 +277,11 @@ class Function; * Will follow interprocedural call/return edges */ class PARSER_EXPORT SingleContextOrInterproc : public EdgePredicate { private: - Function * _context; + const Function * _context; bool _forward; bool _backward; public: - SingleContextOrInterproc(Function * f, bool forward, bool backward) : + SingleContextOrInterproc(const Function * f, bool forward, bool backward) : _context(f), _forward(forward), _backward(backward) { } @@ -284,31 +294,46 @@ class Function; }; class CodeRegion; -class PARSER_EXPORT Block : public Dyninst::SimpleInterval, - public allocatable { + +class PARSER_EXPORT Block : + public Dyninst::SimpleInterval, + public allocatable, + public boost::lockable_adapter { friend class CFGModifier; + friend class Parser; public: - typedef std::map Insns; - typedef std::vector edgelist; + typedef std::map Insns; + typedef std::list edgelist; +public: + static Block * sink_block; - Block(CodeObject * o, CodeRegion * r, Address start); + Block(CodeObject * o, CodeRegion * r, Address start, Function* f = NULL); virtual ~Block(); + boost::recursive_mutex& lockable() { return boost::lockable_adapter::lockable(); } - Address start() const { return _start; } - Address end() const { return _end; } - Address lastInsnAddr() const { return _lastInsn; } - Address last() const { return lastInsnAddr(); } - Address size() const { return _end - _start; } - bool containsAddr(Address addr) const { return addr >= _start && addr < _end; } + inline Address start() const { return _start; } + inline Address end() const { return _end; } + inline Address lastInsnAddr() const { return _lastInsn; } + inline Address last() const { return lastInsnAddr(); } + inline Address size() const { return _end - _start; } + bool containsAddr(Address addr) const { return addr >= _start && addr < _end; } - bool parsed() const { return _parsed; } + bool parsed() const { return _parsed; } - CodeObject * obj() const { return _obj; } - CodeRegion * region() const { return _region; } + CodeObject * obj() const { return _obj; } + CodeRegion * region() const { return _region; } /* Edge access */ const edgelist & sources() const { return _srclist; } const edgelist & targets() const { return _trglist; } + void copy_sources(edgelist & src) { + boost::lock_guard g(*this); + src = _srclist; + } + void copy_targets(edgelist & trg) { + boost::lock_guard g(*this); + trg = _trglist; + } bool consistent(Address addr, Address & prev_insn); @@ -317,13 +342,13 @@ class PARSER_EXPORT Block : public Dyninst::SimpleInterval, template void getFuncs(OutputIterator result); void getInsns(Insns &insns) const; - InstructionAPI::InstructionPtr getInsn(Offset o) const; + InstructionAPI::Instruction getInsn(Offset o) const; bool wasUserAdded() const; /* interval implementation */ - Address low() const { return start(); } - Address high() const { return end(); } + Address low() const override { return start(); } + Address high() const override { return end(); } struct compare { bool operator()(Block * const & b1, Block * const & b2) const { @@ -346,6 +371,7 @@ class PARSER_EXPORT Block : public Dyninst::SimpleInterval, bool operator==(const Block &rhs) const; bool operator!=(const Block &rhs) const; + Function * createdByFunc() { return _createdByFunc; } private: void addSource(Edge * e); @@ -353,6 +379,7 @@ class PARSER_EXPORT Block : public Dyninst::SimpleInterval, void removeTarget(Edge * e); void removeSource(Edge * e); void removeFunc(Function *); + friend class region_data; void updateEnd(Address addr); private: @@ -369,6 +396,8 @@ class PARSER_EXPORT Block : public Dyninst::SimpleInterval, int _func_cnt; bool _parsed; + Function * _createdByFunc; + friend class Edge; friend class Function; @@ -378,33 +407,38 @@ class PARSER_EXPORT Block : public Dyninst::SimpleInterval, inline void Block::addSource(Edge * e) { + boost::lock_guard g(*this); _srclist.push_back(e); } inline void Block::addTarget(Edge * e) { + boost::lock_guard g(*this); + if(e->type() == FALLTHROUGH || + e->type() == COND_NOT_TAKEN) + { + assert(e->_target_off == end()); + } + /* This loop checks whether duplicated edges are added. + * It should only be used in debugging as it can significantly + * slow down the performance + for (auto eit = _trglist.begin(); eit != _trglist.end(); ++eit) { + assert( (*eit)->trg_addr() != e->trg_addr() || (*eit)->type() != e->type()); + } + */ _trglist.push_back(e); } inline void Block::removeTarget(Edge * e) { - for(unsigned i=0;i<_trglist.size();++i) { - if(_trglist[i] == e) { - _trglist[i] = _trglist.back(); - _trglist.pop_back(); - break; - } - } + boost::lock_guard g(*this); + _trglist.remove(e); } inline void Block::removeSource(Edge * e) { - for(unsigned i=0;i<_srclist.size();++i) { - if(_srclist[i] == e) { - _srclist[i] = _srclist.back(); - _srclist.pop_back(); - break; - } - } + + boost::lock_guard g(*this); + _srclist.remove(e); } enum FuncReturnStatus { @@ -439,7 +473,7 @@ class FuncExtent; class Loop; class LoopTreeNode; -class PARSER_EXPORT Function : public allocatable, public AnnotatableSparse { +class PARSER_EXPORT Function : public allocatable, public AnnotatableSparse, public boost::lockable_adapter { friend class CFGModifier; friend class LoopAnalyzer; protected: @@ -449,7 +483,7 @@ class PARSER_EXPORT Function : public allocatable, public AnnotatableSparse { InstructionSource * _isrc; FuncSource _src; - FuncReturnStatus _rs; + boost::atomic _rs; std::string _name; Block * _entry; @@ -482,15 +516,22 @@ class PARSER_EXPORT Function : public allocatable, public AnnotatableSparse { CodeRegion * region, InstructionSource * isource); virtual ~Function(); + boost::recursive_mutex& lockable() { return boost::lockable_adapter::lockable(); } virtual const std::string & name() const; + void rename(std::string n) { _name = n; } Address addr() const { return _start; } CodeRegion * region() const { return _region; } InstructionSource * isrc() const { return _isrc; } CodeObject * obj() const { return _obj; } FuncSource src() const { return _src; } - FuncReturnStatus retstatus() const { return _rs; } + FuncReturnStatus retstatus() const { + race_detector_fake_lock_acquire(race_detector_fake_lock(_rs)); + FuncReturnStatus ret = _rs.load(); + race_detector_fake_lock_release(race_detector_fake_lock(_rs)); + return ret; + } Block * entry() const { return _entry; } bool parsed() const { return _parsed; } @@ -499,11 +540,18 @@ class PARSER_EXPORT Function : public allocatable, public AnnotatableSparse { const_blocklist blocks() const; size_t num_blocks() { + boost::lock_guard g(*this); if(!_cache_valid) finalize(); return _bmap.size(); } + size_t num_blocks() const + { + return _bmap.size(); + } + bool contains(Block *b); + bool contains(Block *b) const; const edgelist & callEdges(); const_blocklist returnBlocks() ; const_blocklist exitBlocks(); @@ -558,9 +606,11 @@ class PARSER_EXPORT Function : public allocatable, public AnnotatableSparse { /* This should not remain here - this is an experimental fix for defensive mode CFG inconsistency */ void invalidateCache() { _cache_valid = false; } + inline std::pair get_next_block( + Address addr, + CodeRegion *codereg) const; static void destroy(Function *f); - private: void delayed_link_return(CodeObject * co, Block * retblk); void finalize(); @@ -653,6 +703,25 @@ class PARSER_EXPORT Function : public allocatable, public AnnotatableSparse { friend class CodeObject; friend class dominatorCFG; }; +inline std::pair Function::get_next_block( + Address addr, + CodeRegion *codereg) const +{ + Block * nextBlock = NULL; + Address nextBlockAddr; + nextBlockAddr = std::numeric_limits
::max(); + for(auto i = _bmap.begin(); + i != _bmap.end(); + ++i) + { + if(i->first > addr && i->first < nextBlockAddr) { + nextBlockAddr = i->first; + nextBlock = i->second; + } + } + + return std::pair(nextBlockAddr,nextBlock); +} /* Describes a contiguous extent of a Function object */ class PARSER_EXPORT FuncExtent : public Dyninst::SimpleInterval { diff --git a/parseAPI/h/CFGFactory.h b/parseAPI/h/CFGFactory.h index d9d31a34b3..99b26bc53b 100644 --- a/parseAPI/h/CFGFactory.h +++ b/parseAPI/h/CFGFactory.h @@ -32,6 +32,7 @@ #include "dyntypes.h" +#include "LockFreeQueue.h" #include "CFG.h" #include "InstructionSource.h" @@ -71,47 +72,46 @@ class flist_iter { } }; + template class fact_list { - public: - typedef flist_iter iterator; - typedef const flist_iter const_iterator; - typedef T elem; +public: + typedef typename LockFreeQueue::iterator iterator; + typedef std::forward_iterator_tag iterator_category; + typedef T elem; + typedef T &reference; - fact_list() { - head.alloc_set_next(&head); - head.alloc_set_prev(&head); - } + fact_list() { + } - ~fact_list() { } + ~fact_list() { } - void add(elem & new_elem) { - head.append(new_elem); - } - void add_tail(elem & new_elem) { - head.prepend(new_elem); - } - void clear() { - while(head.alloc_next() != &head) - head.alloc_next()->remove(); - } + void add(elem new_elem) { + queue.insert(new_elem); + } - // iterators - iterator begin() { return iterator(head.alloc_next()); } - iterator end() { return iterator(&head); } - const_iterator begin() const { return iterator(head.alloc_next()); } - const_iterator end() const { return iterator(&head); } - private: - allocatable head; + // iterators + iterator begin() { return queue.begin(); } + iterator end() { return queue.end(); } +private: + LockFreeQueue queue; }; + + /** An implementation of CFGFactory is responsible for allocation and deallocation of CFG objects like Blocks, Edges, and Functions. Overriding the default methods of this interface allows the parsing routines to generate and work with extensions of the base types **/ /** Objects created by a CFGFactory must descend from `allocatable' **/ +enum EdgeState { + created, + destroyed_cb, + destroyed_noreturn, + destroyed_all +}; -class PARSER_EXPORT CFGFactory { +class PARSER_EXPORT CFGFactory : public boost::basic_lockable_adapter { public: CFGFactory() {}; virtual ~CFGFactory(); @@ -124,13 +124,14 @@ class PARSER_EXPORT CFGFactory { std::string name, CodeObject *obj, CodeRegion *region, InstructionSource *isrc); Block *_mkblock(Function *f, CodeRegion *r, Address addr); + Block *_mkblock(CodeObject *co, CodeRegion *r, Address addr); Edge *_mkedge(Block *src, Block *trg, EdgeTypeEnum type); Block *_mksink(CodeObject *obj, CodeRegion *r); void destroy_func(Function *f); void destroy_block(Block *b); - void destroy_edge(Edge *e); + void destroy_edge(Edge *e, EdgeState reason); void destroy_all(); @@ -153,9 +154,9 @@ class PARSER_EXPORT CFGFactory { virtual void free_block(Block * b); virtual void free_edge(Edge * e); - fact_list edges_; - fact_list blocks_; - fact_list funcs_; + fact_list edges_; + fact_list blocks_; + fact_list funcs_; }; diff --git a/parseAPI/h/CodeObject.h b/parseAPI/h/CodeObject.h index a294765947..17333d8cdd 100644 --- a/parseAPI/h/CodeObject.h +++ b/parseAPI/h/CodeObject.h @@ -159,6 +159,7 @@ class CodeObject { * Hacky "for insertion" method */ PARSER_EXPORT Address getFreeAddr() const; + ParseData* parse_data(); private: void process_hints(); diff --git a/parseAPI/h/CodeSource.h b/parseAPI/h/CodeSource.h index b86e605379..5de8c5d296 100644 --- a/parseAPI/h/CodeSource.h +++ b/parseAPI/h/CodeSource.h @@ -41,6 +41,11 @@ #include "InstructionSource.h" +#include +#include +#include +#include + class StatContainer; namespace Dyninst { @@ -158,6 +163,8 @@ class PARSER_EXPORT CodeSource : public Dyninst::InstructionSource { static dyn_hash_map non_returning_syscalls_x86_64; public: + typedef tbb::concurrent_hash_map RegionMap; + /* Returns true if the function at an address is known to be non returning (e.g., is named `exit' on Linux/ELF, etc.). @@ -222,6 +229,8 @@ class PARSER_EXPORT SymtabCodeRegion : public CodeRegion { std::map knownData; public: SymtabCodeRegion(SymtabAPI::Symtab *, SymtabAPI::Region *); + SymtabCodeRegion(SymtabAPI::Symtab *, SymtabAPI::Region *, + std::vector &symbols); ~SymtabCodeRegion(); void names(Address, std::vector &); @@ -246,11 +255,11 @@ class PARSER_EXPORT SymtabCodeRegion : public CodeRegion { SymtabAPI::Region * symRegion() const { return _region; } }; -class PARSER_EXPORT SymtabCodeSource : public CodeSource { +class PARSER_EXPORT SymtabCodeSource : public CodeSource, public boost::lockable_adapter { private: SymtabAPI::Symtab * _symtab; bool owns_symtab; - mutable CodeRegion * _lookup_cache; + mutable boost::atomic _lookup_cache; // Stats information StatContainer * stats_parse; @@ -319,7 +328,7 @@ class PARSER_EXPORT SymtabCodeSource : public CodeSource { private: void init(hint_filt *, bool); void init_regions(hint_filt *, bool); - void init_hints(dyn_hash_map &, hint_filt*); + void init_hints(RegionMap &, hint_filt*); void init_linkage(); void init_try_blocks(); @@ -335,7 +344,8 @@ class PARSER_EXPORT SymtabCodeSource : public CodeSource { inline bool CodeRegion::contains(const Address addr) const { - return addr >= offset() && addr < (offset() + length()); + Address start = offset(); + return addr >= start && addr < (start + length()); } } diff --git a/parseAPI/h/InstructionAdapter.h b/parseAPI/h/InstructionAdapter.h index db7ffcf80c..3792309db6 100644 --- a/parseAPI/h/InstructionAdapter.h +++ b/parseAPI/h/InstructionAdapter.h @@ -68,7 +68,7 @@ class InstructionAdapter ParseAPI::CodeRegion *r, InstructionSource *isrc, ParseAPI::Block *); // Implemented - virtual InstructionAPI::Instruction::Ptr getInstruction() const = 0; + virtual const InstructionAPI::Instruction& getInstruction() const = 0; virtual bool hasCFT() const = 0; virtual size_t getSize() const = 0; virtual bool isFrameSetupInsn() const = 0; @@ -110,7 +110,8 @@ const; virtual bool isInterruptOrSyscall() const = 0; virtual bool isCall() const = 0; virtual bool isReturnAddrSave(Address &ret_addr) const = 0; // ret_addr holds the return address pushed in the stack using mflr at function entry - virtual bool isTailCall(ParseAPI::Function *, ParseAPI::EdgeTypeEnum type, unsigned int num_insns, const std::set
&) const = 0; + virtual bool isTailCall(const ParseAPI::Function *, ParseAPI::EdgeTypeEnum type, unsigned int num_insns, + const std::set
&) const = 0; protected: // Uses pattern heuristics or backward slicing to determine if a blr instruction is a return or jump table virtual bool isReturn(Dyninst::ParseAPI::Function * context, Dyninst::ParseAPI::Block* currBlk) const = 0; diff --git a/parseAPI/h/Location.h b/parseAPI/h/Location.h index 8651ed8fa7..bf81a498ac 100644 --- a/parseAPI/h/Location.h +++ b/parseAPI/h/Location.h @@ -71,7 +71,7 @@ struct BlockSite{ BlockSite(Function *f, Block *b): func(f), block(b) {}; }; -typedef std::vector > InsnVec; +typedef std::vector > InsnVec; static void getInsnInstances(Block *block, InsnVec &insns) { @@ -81,7 +81,7 @@ static void getInsnInstances(Block *block, InstructionAPI::InstructionDecoder d(ptr, block->size(), block->obj()->cs()->getArch()); while (off < block->end()) { insns.push_back(std::make_pair(d.decode(), off)); - off += insns.back().first->size(); + off += insns.back().first.size(); } } @@ -89,8 +89,8 @@ static void getInsnInstances(Block *block, struct InsnLoc { Block *const block; const Offset offset; - const InstructionAPI::Instruction::Ptr insn; -InsnLoc(Block *const b, Offset o, const InstructionAPI::Instruction::Ptr i) : + InstructionAPI::Instruction insn; +InsnLoc(Block *const b, Offset o, const InstructionAPI::Instruction& i) : block(b), offset(o), insn(i) {}; }; @@ -111,7 +111,7 @@ Location(BlockSite b): func(b.func), block(b.block), offset(0), edge(NULL), untr // A trusted instruction (in a particular function) Location(Function *f, InsnLoc l) : func(f), block(l.block), offset(l.offset), insn(l.insn), edge(NULL), untrusted(false), type(instructionInstance_) {}; // An untrusted (raw) instruction (in a particular function) -Location(Function *f, Block *b, Offset o, InstructionAPI::Instruction::Ptr i) : func(f), block(b), offset(o), insn(i), edge(NULL), untrusted(true), type(instructionInstance_) {}; +Location(Function *f, Block *b, Offset o, InstructionAPI::Instruction i) : func(f), block(b), offset(o), insn(i), edge(NULL), untrusted(true), type(instructionInstance_) {}; // An edge (in a particular function) Location(Function *f, Edge *e) : func(f), block(NULL), offset(0), edge(e), untrusted(true), type(edge_) {}; Location(EdgeLoc e): func(e.func), block(NULL), offset(0), edge(e.edge), untrusted(false), type(edge_){}; @@ -187,7 +187,7 @@ Location(Edge *e) : func(NULL), block(NULL), offset(0), edge(e), untrusted(false Function *const func; Block *const block; const Offset offset; -const InstructionAPI::Instruction::Ptr insn; +InstructionAPI::Instruction insn; Edge *const edge; const bool untrusted; const type_t type; diff --git a/parseAPI/h/LockFreeQueue.h b/parseAPI/h/LockFreeQueue.h new file mode 100644 index 0000000000..872cdbaf90 --- /dev/null +++ b/parseAPI/h/LockFreeQueue.h @@ -0,0 +1,242 @@ +/* + * See the dyninst/COPYRIGHT file for copyright information. + * + * We provide the Paradyn Tools (below described as "Paradyn") + * on an AS IS basis, and do not warrant its validity or performance. + * We reserve the right to update, modify, or discontinue this + * software at any time. We shall have no obligation to supply such + * updates or modifications or any other form of support to you. + * + * By your use of Paradyn, you understand and agree that we (or any + * other person or entity with proprietary rights in Paradyn) are + * under no obligation to provide either maintenance services, + * update services, notices of latent defects, or correction of + * defects for Paradyn. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +#ifndef _LOCK_FREE_QUEUE_H_ +#define _LOCK_FREE_QUEUE_H_ + +#include +#include "race-detector-annotations.h" +#include + +#define DEBUG_LOCKFREEQUEUE 0 + +#if DEBUG_LOCKFREEQUEUE +#define LFQ_DEBUG(x) x +#else +#define LFQ_DEBUG(x) +#endif + +template +class LockFreeQueueItem { +private: + typedef LockFreeQueueItem item_type; + +public: + LockFreeQueueItem(T __value) : _next(0), _value(__value) { + LFQ_DEBUG(validate = this); + }; + ~LockFreeQueueItem() { + LFQ_DEBUG(validate = 0); + }; + + void setNext(item_type *__next) { + LFQ_DEBUG(assert(validate == this)); + race_detector_fake_lock_acquire(race_detector_fake_lock(_next)); + _next.store(__next); + race_detector_fake_lock_release(race_detector_fake_lock(_next)); + }; + + void setNextPending() { + LFQ_DEBUG(assert(validate == this)); + race_detector_fake_lock_acquire(race_detector_fake_lock(_next)); + _next.store(pending()); + race_detector_fake_lock_release(race_detector_fake_lock(_next)); + }; + + item_type *next() { + LFQ_DEBUG(assert(validate == this)); + race_detector_fake_lock_acquire(race_detector_fake_lock(_next)); + item_type *succ = _next.load(); + race_detector_fake_lock_release(race_detector_fake_lock(_next)); + // wait for successor to be written, if necessary + while (succ == pending()) { + race_detector_fake_lock_acquire(race_detector_fake_lock(_next)); + succ = _next.load(); + race_detector_fake_lock_release(race_detector_fake_lock(_next)); + } + return succ; + }; + + T value() { + LFQ_DEBUG(assert(validate == this)); + return _value; + }; + +private: + item_type *pending() { + LFQ_DEBUG(assert(validate == this)); + return (item_type * const) ~0; + } + + boost::atomic _next; + T _value; + LFQ_DEBUG(item_type *validate); +}; + + +// designed for use in a context where where only insert_chain operations +// that have completed their exchange may be concurrent with iteration on +// the queue +template +class LockFreeQueueIterator { +private: + typedef LockFreeQueueItem item_type; + typedef LockFreeQueueIterator iterator; + +public: + typedef T value_type; + typedef T * pointer; + typedef T & reference; + typedef std::ptrdiff_t difference_type; + typedef std::forward_iterator_tag iterator_category; + +public: + LockFreeQueueIterator(item_type *_item) : item(_item) {}; + + T operator *() { return item->value(); }; + + bool operator != (iterator i) { return item != i.item; }; + + iterator operator ++() { + if (item) item = item->next(); + return *this; + }; + + iterator operator ++(int) { + iterator clone(*this); + ++(*this); + return clone; + }; + +private: + item_type *item; +}; + + +template +class LockFreeQueue { +public: + typedef LockFreeQueueIterator iterator; + typedef LockFreeQueueItem item_type; + +public: + LockFreeQueue(item_type *_head = 0) : head(_head) {}; + +public: + // wait-free member functions designed for concurrent use + + // insert a singleton at the head of the queue + // note: this operation is wait-free unless the allocator blocks + void insert(T value) { + item_type *entry = new item_type(value); + insert_chain(entry, entry); + }; + + // steal the linked list from q and insert it at the front of this queue + void splice(LockFreeQueue &q) { + if (q.peek()) { // only empty q if it is non-empty + item_type *first = q.steal(); + item_type *last = first; + for (;;) { + item_type *next = last->next(); + if (!next) break; + last = next; + } + insert_chain(first, last); + } + }; + + // inspect the head of the queue + item_type *peek() { + race_detector_fake_lock_acquire(race_detector_fake_lock(head)); + item_type* ret = head.load(); + race_detector_fake_lock_release(race_detector_fake_lock(head)); + return ret; + }; + + // grab the contents of the queue for your own private use + item_type *steal() { + race_detector_fake_lock_acquire(race_detector_fake_lock(head)); + item_type* ret = head.exchange(0); + race_detector_fake_lock_release(race_detector_fake_lock(head)); + return ret; + }; + +public: + // designed for use in a context where where only insert_chain + // operations that have completed their exchange may be concurrent + + item_type *pop() { + race_detector_fake_lock_acquire(race_detector_fake_lock(head)); + item_type *first = head.load(); + race_detector_fake_lock_release(race_detector_fake_lock(head)); + if (first) { + item_type *succ = first->next(); + race_detector_fake_lock_acquire(race_detector_fake_lock(head)); + head.store(succ); + race_detector_fake_lock_release(race_detector_fake_lock(head)); + first->setNext(0); + } + return first; + }; + + iterator begin() { + race_detector_fake_lock_acquire(race_detector_fake_lock(head)); + iterator ret(head.load()); + race_detector_fake_lock_release(race_detector_fake_lock(head)); + return ret; + }; + + iterator end() { return iterator(0); }; + + ~LockFreeQueue() { clear(); }; + + void clear() { + item_type *first; + while((first = pop())) { + delete first; + } + }; + +private: + + // insert a chain at the head of the queue + void insert_chain(item_type *first, item_type *last) { + last->setNextPending(); // make in-progress splice visible + race_detector_fake_lock_acquire(race_detector_fake_lock(head)); + item_type *oldhead = head.exchange(first); + race_detector_fake_lock_release(race_detector_fake_lock(head)); + last->setNext(oldhead); + }; + +private: + boost::atomic head; +}; + +#endif diff --git a/parseAPI/h/ParseCallback.h b/parseAPI/h/ParseCallback.h index ef64b23e6d..b29b1b5672 100644 --- a/parseAPI/h/ParseCallback.h +++ b/parseAPI/h/ParseCallback.h @@ -155,6 +155,7 @@ class ParseCallback { virtual void add_block_cb(Function *, Block *) {}; virtual void modify_edge_cb(Edge *, Block *, ParseCallback::edge_type_t) {}; + virtual void function_discovery_cb(Function*) {}; private: }; @@ -204,7 +205,7 @@ class ParseCallbackManager { bool hasWeirdInsns(const Function*); void foundWeirdInsns(Function*); void split_block_cb(Block *, Block *); - + void discover_function(Function*); private: // Named the same as ParseCallback to make the code diff --git a/parseAPI/src/Block.C b/parseAPI/src/Block.C index ddbf0ebe06..6aa1c5c354 100644 --- a/parseAPI/src/Block.C +++ b/parseAPI/src/Block.C @@ -41,14 +41,16 @@ using namespace Dyninst::ParseAPI; int HACKCOUNT = 0; -Block::Block(CodeObject * o, CodeRegion *r, Address start) : +Block::Block(CodeObject * o, CodeRegion *r, Address start, Function *f) : + SimpleInterval(start, start, 0), _obj(o), _region(r), _start(start), _end(start), _lastInsn(start), _func_cnt(0), - _parsed(false) + _parsed(false), + _createdByFunc(f) { if (_obj && _obj->cs()) { _obj->cs()->incrementCounter(PARSE_BLOCK_COUNT); @@ -70,7 +72,7 @@ Block::consistent(Address addr, Address & prev_insn) { if (addr >= end() || addr < start()) return false; InstructionSource * isrc; - if(!_obj->cs()->regionsOverlap()) + if(_obj && !_obj->cs()->regionsOverlap()) isrc = _obj->cs(); else isrc = region(); @@ -95,11 +97,12 @@ Block::consistent(Address addr, Address & prev_insn) void Block::getFuncs(vector & funcs) { + if(!_obj) return; // universal sink set stab; _obj->findFuncs(region(),start(),stab); set::iterator sit = stab.begin(); for( ; sit != stab.end() ;++sit) { - if((*sit)->contains(this)) + if(((const Function*)(*sit))->contains(this)) funcs.push_back(*sit); } } @@ -148,13 +151,13 @@ SingleContextOrInterproc::pred_impl(Edge * e) const } int Block::containingFuncs() const { - _obj->finalize(); + if(_obj) _obj->finalize(); return _func_cnt; } void Block::removeFunc(Function *) { - if (0 == _func_cnt) { + if ((0 == _func_cnt) && _obj) { _obj->finalize(); } assert(0 != _func_cnt); @@ -163,9 +166,10 @@ void Block::removeFunc(Function *) void Block::updateEnd(Address addr) { + if(!_obj) return; _obj->cs()->addCounter(PARSE_BLOCK_SIZE, -1*size()); _end = addr; -// assert(_end != 0x7b320f); + high_ = addr; _obj->cs()->addCounter(PARSE_BLOCK_SIZE, size()); } @@ -182,7 +186,7 @@ void Edge::install() void Edge::uninstall() { mal_printf("Uninstalling edge [%lx]->[%lx]\n", - _source->lastInsnAddr(), _target->start()); + _source->lastInsnAddr(), _target_off); // if it's a call edge, it's cached in the function object, remove it if (CALL == type()) { vector srcFs; @@ -205,13 +209,24 @@ void Edge::uninstall() } // remove from source and target blocks _source->removeTarget(this); - _target->removeSource(this); + trg()->removeSource(this); } void Edge::destroy(Edge *e, CodeObject *o) { o->destroy(e); } + +Block *Edge::trg() const { + Block* found = index->findBlock(_source->region(), _target_off); + if(found) return found; + Block* newBlock = NULL; +// newBlock = _source->obj()->fact()->_mkblock(NULL, _source->region(), _target_off); +// newBlock = _source->obj()->fact()->_mksink(_source->obj(), _source->region()); +// index->record_block(_source->region(), newBlock); + return newBlock; +} + std::string format(EdgeTypeEnum e) { switch(e) { case CALL: return "call"; @@ -240,13 +255,13 @@ Block::getInsns(Insns &insns) const { if (ptr == NULL) return; InstructionDecoder d(ptr, size(), obj()->cs()->getArch()); while (off < end()) { - Instruction::Ptr insn = d.decode(); + Instruction insn = d.decode(); insns[off] = insn; - off += insn->size(); + off += insn.size(); } } -InstructionAPI::Instruction::Ptr +InstructionAPI::Instruction Block::getInsn(Offset a) const { Insns insns; getInsns(insns); @@ -255,6 +270,12 @@ Block::getInsn(Offset a) const { bool Block::operator==(const Block &rhs) const { + boost::lock_guard g1(*this); + boost::lock_guard g2(rhs); + // All sinks are equal + if(_start == std::numeric_limits
::max()) { + return rhs._start == _start; + } return _obj == rhs._obj && _region == rhs._region && _start == rhs._start && diff --git a/parseAPI/src/BoundFactCalculator.C b/parseAPI/src/BoundFactCalculator.C index 4aa8dfdd8b..3afef05e89 100644 --- a/parseAPI/src/BoundFactCalculator.C +++ b/parseAPI/src/BoundFactCalculator.C @@ -48,8 +48,10 @@ static void BuildEdgeFromVirtualEntry(SliceNode::Ptr virtualEntry, } if (visit.find(curBlock) != visit.end()) return; visit.insert(curBlock); - for (auto eit = curBlock->targets().begin(); eit != curBlock->targets().end(); ++eit) - if ((*eit)->type() != CALL && (*eit)->type() != RET) { + Block::edgelist targets; + curBlock->copy_targets(targets); + for (auto eit = targets.begin(); eit != targets.end(); ++eit) + if ((*eit)->type() != CALL && (*eit)->type() != RET && (*eit)->type() != CATCH && !(*eit)->interproc()) { BuildEdgeFromVirtualEntry(virtualEntry, (*eit)->trg(), targetMap, visit, slice); } } @@ -123,7 +125,6 @@ void BoundFactsCalculator::DetermineAnalysisOrder() { } } } - slice->clearEntryNodes(); slice->markAsEntryNode(virtualEntry); } @@ -203,7 +204,7 @@ bool BoundFactsCalculator::CalculateBoundedFacts() { BoundFact* oldFactIn = GetBoundFactIn(curNode); parsing_printf("Calculate Meet for %lx", node->addr()); if (node->assign()) { - parsing_printf(", insn: %s, assignment %s\n", node->assign()->insn()->format().c_str(), node->assign()->format().c_str()); + parsing_printf(", insn: %s, assignment %s\n", node->assign()->insn().format().c_str(), node->assign()->format().c_str()); } else { if (node->block() == NULL) @@ -312,8 +313,8 @@ void BoundFactsCalculator::ThunkBound( BoundFact*& curFact, Node::Ptr src, Node: } -static bool IsConditionalJump(Instruction::Ptr insn) { - entryID id = insn->getOperation().getID(); +static bool IsConditionalJump(Instruction insn) { + entryID id = insn.getOperation().getID(); if (id == e_jz || id == e_jnz || id == e_jb || id == e_jnb || @@ -408,14 +409,14 @@ void BoundFactsCalculator::CalcTransferFunction(Node::Ptr curNode, BoundFact *ne newFact->SetPredicate(node->assign(), se.ExpandAssignment(node->assign()) ); return; } - entryID id = node->assign()->insn()->getOperation().getID(); + entryID id = node->assign()->insn().getOperation().getID(); // The predecessor is not a conditional jump, // then we can determine buond fact based on the src assignment parsing_printf("\t\tThe predecessor node is normal node\n"); parsing_printf("\t\t\tentry id %d\n", id); AbsRegion &ar = node->assign()->out(); - Instruction::Ptr insn = node->assign()->insn(); + Instruction insn = node->assign()->insn(); pair expandRet = se.ExpandAssignment(node->assign()); if (expandRet.first == NULL) { @@ -431,10 +432,10 @@ void BoundFactsCalculator::CalcTransferFunction(Node::Ptr curNode, BoundFact *ne AST::Ptr calculation = expandRet.first; int derefSize = 0; - if (node->assign() && node->assign()->insn() && node->assign()->insn()->readsMemory()) { - Instruction::Ptr i = node->assign()->insn(); + if (node->assign() && node->assign()->insn().isValid() && node->assign()->insn().readsMemory()) { + Instruction i = node->assign()->insn(); std::vector ops; - i->getOperands(ops); + i.getOperands(ops); for (auto oit = ops.begin(); oit != ops.end(); ++oit) { Operand o = *oit; if (o.readsMemory()) { @@ -456,10 +457,10 @@ void BoundFactsCalculator::CalcTransferFunction(Node::Ptr curNode, BoundFact *ne // In other cases, if the AbsRegion represents a register, // the generator is not set. if (ar.generator() != NULL) - outAST = SymbolicExpression::SimplifyAnAST( + outAST = se.SimplifyAnAST( RoseAST::create(ROSEOperation(ROSEOperation::derefOp, ar.size()), ar.generator()), SymbolicExpression::PCValue(node->assign()->addr(), - insn->size(), + insn.size(), node->assign()->block()->obj()->cs()->getArch())); else diff --git a/parseAPI/src/BoundFactData.C b/parseAPI/src/BoundFactData.C index 76bf0eb2a0..4db63618a8 100644 --- a/parseAPI/src/BoundFactData.C +++ b/parseAPI/src/BoundFactData.C @@ -375,65 +375,6 @@ static bool IsTableIndex(set &values) { return true; } -/* -void StridedInterval::MemoryRead(Block* b, int readSize) { - if (interval.stride == 0) { - // This is a read to variable, not a table read - *this = StridedInterval::top; - return; - } - - if (interval != StridedInterval::top) { - Address memAddrLow = (Address)interval.low; - Address memAddrHigh = (Address)interval.high; -#if defined(os_windows) - memAddrLow -= b->obj()->cs()->loadAddress(); - memAddrHigh -= b->obj()->cs()->loadAddress(); -#endif - if (IsInReadOnlyRegion(memAddrLow, memAddrHigh)) { - set values; - if (interval.size() <= MAX_TABLE_ENTRY && b->obj()->cs()->isReadOnly(memAddrLow)) { - for (Address memAddr = memAddrLow ; memAddr <= memAddrHigh; memAddr += interval.stride) { - if (!b->obj()->cs()->isReadOnly(memAddr)) { - parsing_printf("NOT READ ONLY SECTION %lx\n", memAddr); - continue; - } - uint64_t val; - switch (readSize) { - case 8: - val = *(const uint64_t *) b->obj()->cs()->getPtrToInstruction(memAddr); - break; - case 4: - val = *(const uint32_t *) b->obj()->cs()->getPtrToInstruction(memAddr); - break; - case 2: - val = *(const uint16_t *) b->obj()->cs()->getPtrToInstruction(memAddr); - break; - case 1: - val = *(const uint8_t *) b->obj()->cs()->getPtrToInstruction(memAddr); - break; - default: - parsing_printf("Invalid table stride %d\n", readSize); - *this = top; - return; - } - values.insert(val); - } - } - if (IsTableIndex(values)) { - // This is a table for indexing a next level table - interval.low = *(values.begin()); - interval.high = *(values.rbegin()); - interval.stride = 1; - ClearTableCheck(); - } else { - tableReadSize = readSize; - } - } else - tableReadSize = readSize; - } -} -*/ void BoundFact::Meet(BoundFact &bf, Block* b) { for (auto fit = fact.begin(); fit != fact.end();) { StridedInterval *val2 = bf.GetBound(fit->first); @@ -646,13 +587,13 @@ BoundFact::BoundFact(const BoundFact &bf) { } -bool BoundFact::ConditionalJumpBound(Instruction::Ptr insn, EdgeTypeEnum type) { +bool BoundFact::ConditionalJumpBound(Instruction insn, EdgeTypeEnum type) { if (!pred.valid) { parsing_printf("WARNING: We reach a conditional jump, but have not tracked the flag! Do nothing and return\n"); return true; } - entryID id = insn->getOperation().getID(); - parsing_printf("\t\tproduce conditional bound for %s, edge type %d\n", insn->format().c_str(), type); + entryID id = insn.getOperation().getID(); + parsing_printf("\t\tproduce conditional bound for %s, edge type %d\n", insn.format().c_str(), type); if (type == COND_TAKEN) { switch (id) { // unsigned @@ -1033,7 +974,7 @@ bool BoundFact::ConditionalJumpBound(Instruction::Ptr insn, EdgeTypeEnum type) { } } else { - fprintf(stderr, "Instruction %s\n", insn->format().c_str()); + fprintf(stderr, "Instruction %s\n", insn.format().c_str()); fprintf(stderr, "type should be either COND_TAKEN or COND_NOT_TAKEN, but it is %d\n", type); return false; } @@ -1059,10 +1000,10 @@ bool BoundFact::ConditionalJumpBound(Instruction::Ptr insn, EdgeTypeEnum type) { void BoundFact::SetPredicate(Assignment::Ptr assign,std::pair expandRet ) { - Instruction::Ptr insn = assign->insn(); - entryID id = insn->getOperation().getID(); + Instruction insn = assign->insn(); + entryID id = insn.getOperation().getID(); pred.valid = true; - parsing_printf("\t\tLook for predicates for instruction %s, assign %s\n", insn->format().c_str(), assign->format().c_str()); + parsing_printf("\t\tLook for predicates for instruction %s, assign %s\n", insn.format().c_str(), assign->format().c_str()); if (expandRet.first == NULL) { // If the instruction is outside the set of instrutions we // add instruction semantics. We assume this instruction diff --git a/parseAPI/src/BoundFactData.h b/parseAPI/src/BoundFactData.h index c657a1cd1b..32b5452502 100644 --- a/parseAPI/src/BoundFactData.h +++ b/parseAPI/src/BoundFactData.h @@ -184,7 +184,7 @@ struct BoundFact { void Meet(BoundFact &bf, ParseAPI::Block* b); - bool ConditionalJumpBound(InstructionAPI::Instruction::Ptr insn, EdgeTypeEnum type); + bool ConditionalJumpBound(InstructionAPI::Instruction insn, EdgeTypeEnum type); void SetPredicate(Assignment::Ptr assign, std::pair expand); void GenFact(const AST::Ptr ast, StridedInterval* bv, bool isConditionalJump); void KillFact(const AST::Ptr ast, bool isConditionalJump); diff --git a/parseAPI/src/CFGFactory.C b/parseAPI/src/CFGFactory.C index dbf845d55e..c9c4f75e38 100644 --- a/parseAPI/src/CFGFactory.C +++ b/parseAPI/src/CFGFactory.C @@ -34,6 +34,11 @@ #include "CFG.h" #include +#include "ParseData.h" + + +#include + using namespace std; using namespace Dyninst; using namespace Dyninst::ParseAPI; @@ -73,7 +78,8 @@ std::string ParseAPI::format(EdgeTypeEnum e) { Edge::Edge(Block *source, Block *target, EdgeTypeEnum type) : _source(source), - _target(target), + index(source->obj()->parse_data()), + _target_off(target->low()), _type(type,false) { } @@ -89,7 +95,13 @@ CFGFactory::_mkfunc(Address addr, FuncSource src, string name, CodeObject * obj, CodeRegion * reg, Dyninst::InstructionSource * isrc) { Function * ret = mkfunc(addr,src,name,obj,reg,isrc); - funcs_.add(*ret); + + // forget about initialization of this function descriptor by this thread + // before making it available to others. the initialization will not race + // with a later access by another thread. + race_detector_forget_access_history(ret, sizeof(*ret)); + + funcs_.add(ret); ret->_src = src; return ret; } @@ -100,21 +112,32 @@ CFGFactory::mkfunc(Address addr, FuncSource, string name, CodeObject * obj, CodeRegion * reg, Dyninst::InstructionSource * isrc) { Function * ret = new Function(addr,name,obj,reg,isrc); + return ret; } Block * -CFGFactory::_mkblock(Function * f , CodeRegion *r, Address addr) { +CFGFactory::_mkblock(Function * f , CodeRegion *r, Address addr) +{ + Block * ret = mkblock(f, r, addr); + race_detector_forget_access_history(ret, sizeof(*ret)); + blocks_.add(ret); + return ret; +} - Block * ret = mkblock(f, r, addr);; - blocks_.add(*ret); +Block * +CFGFactory::_mkblock(CodeObject* co, CodeRegion *r, Address addr) +{ + Block* ret = new Block(co, r, addr); + race_detector_forget_access_history(ret, sizeof(*ret)); + blocks_.add(ret); return ret; } Block * CFGFactory::mkblock(Function * f , CodeRegion *r, Address addr) { - Block * ret = new Block(f->obj(),r,addr); + Block * ret = new Block(f->obj(),r,addr, f); return ret; } @@ -122,7 +145,7 @@ CFGFactory::mkblock(Function * f , CodeRegion *r, Address addr) { Block * CFGFactory::_mksink(CodeObject * obj, CodeRegion *r) { Block * ret = mksink(obj,r); - blocks_.add(*ret); + blocks_.add(ret); return ret; } @@ -135,7 +158,7 @@ CFGFactory::mksink(CodeObject * obj, CodeRegion *r) { Edge * CFGFactory::_mkedge(Block * src, Block * trg, EdgeTypeEnum type) { Edge * ret = mkedge(src,trg,type); - edges_.add(*ret); + edges_.add(ret); return ret; } @@ -146,6 +169,7 @@ CFGFactory::mkedge(Block * src, Block * trg, EdgeTypeEnum type) { } void CFGFactory::destroy_func(Function *f) { + boost::lock_guard g(*this); f->remove(); free_func(f); } @@ -157,6 +181,7 @@ CFGFactory::free_func(Function *f) { void CFGFactory::destroy_block(Block *b) { + boost::lock_guard g(*this); b->remove(); free_block(b); } @@ -166,10 +191,25 @@ CFGFactory::free_block(Block *b) { delete b; } +std::string to_str(EdgeState e) +{ + switch(e) + { + case created: return "ok"; + case destroyed_noreturn: return "destroyed fallthrough from non-returning call/syscall"; + case destroyed_cb: return "destroyed from callback"; + case destroyed_all: return "destroyed during global cleanup"; + default: return "ERROR: unknown state"; + } +} + void -CFGFactory::destroy_edge(Edge *e) { - e->remove(); - free_edge(e); +CFGFactory::destroy_edge(Edge *e, Dyninst::ParseAPI::EdgeState reason) { + boost::lock_guard g(*this); + e->remove(); + if(reason == destroyed_all) { + free_edge(e); + } } void @@ -179,23 +219,24 @@ CFGFactory::free_edge(Edge *e) { void CFGFactory::destroy_all() { + boost::lock_guard g(*this); // XXX carefully calling free_* routines; could be faster and just // call delete - fact_list::iterator eit = edges_.begin(); + fact_list::iterator eit = edges_.begin(); while(eit != edges_.end()) { - fact_list::iterator cur = eit++; - destroy_edge(&*cur); + fact_list::iterator cur = eit++; + destroy_edge(*cur, destroyed_all); } - fact_list::iterator bit = blocks_.begin(); + fact_list::iterator bit = blocks_.begin(); while(bit != blocks_.end()) { - fact_list::iterator cur = bit++; - destroy_block(&*cur); + fact_list::iterator cur = bit++; + destroy_block(*cur); } - fact_list::iterator fit = funcs_.begin(); + fact_list::iterator fit = funcs_.begin(); while(fit != funcs_.end()) { - fact_list::iterator cur = fit++; - destroy_func(&*cur); + fact_list::iterator cur = fit++; + destroy_func(*cur); } } diff --git a/parseAPI/src/CFGModifier.C b/parseAPI/src/CFGModifier.C index 1b4f99e24f..1c6110161a 100644 --- a/parseAPI/src/CFGModifier.C +++ b/parseAPI/src/CFGModifier.C @@ -49,7 +49,7 @@ bool CFGModifier::redirect(Edge *edge, Block *target) { bool linkToSink = false; if (!edge) return false; if (!target) { - target = edge->src()->obj()->parser->_sink; + target = new Block(edge->src()->obj(), edge->src()->region(), std::numeric_limits
::max()); linkToSink = true; } if (edge->trg() == target) return true; @@ -66,6 +66,7 @@ bool CFGModifier::redirect(Edge *edge, Block *target) { // if the source block has a sink edge of the same type, remove this edge bool hasSink = false; if (linkToSink) { + boost::lock_guard g(*edge->src()); const Block::edgelist & trgs = edge->src()->targets(); for (Block::edgelist::const_iterator titer = trgs.begin(); titer != trgs.end(); titer++) { if ((*titer)->sinkEdge() && (*titer)->type() == edge->type()) { @@ -102,7 +103,7 @@ bool CFGModifier::redirect(Edge *edge, Block *target) { edge->_type._sink = 0; } - edge->_target = target; + edge->_target_off = target->low(); target->addSource(edge); target->obj()->_pcb->addEdge(target, edge, ParseCallback::source); edge->src()->obj()->_pcb->modifyEdge(edge, target, ParseCallback::target); @@ -164,7 +165,7 @@ Block *CFGModifier::split(Block *b, Address a, bool trust, Address newlast) { // 2b) - for (vector::iterator iter = b->_trglist.begin(); + for (Block::edgelist::iterator iter = b->_trglist.begin(); iter != b->_trglist.end(); ++iter) { b->obj()->_pcb->removeEdge(b, *iter, ParseCallback::target); (*iter)->_source = ret; @@ -253,7 +254,7 @@ bool CFGModifier::remove(vector &blks, bool force) { if (!b->_srclist.empty()) { if (!force) return false; - for (std::vector::iterator iter = b->_srclist.begin(); + for (Block::edgelist::iterator iter = b->_srclist.begin(); iter != b->_srclist.end(); ++iter) { Edge *edge = *iter; @@ -275,7 +276,7 @@ bool CFGModifier::remove(vector &blks, bool force) { } // 3) - for (std::vector::iterator iter = b->_trglist.begin(); + for (Block::edgelist::iterator iter = b->_trglist.begin(); iter != b->_trglist.end(); ++iter) { Edge *edge = *iter; @@ -348,7 +349,7 @@ bool CFGModifier::remove(Function *f) { InsertedRegion *CFGModifier::insert(CodeObject *obj, Address base, void *data, unsigned size) { - parsing_cerr << "Inserting new code: " << hex << (unsigned) (*((unsigned *)data)) << dec << endl; + parsing_printf("Inserting new code: %lx\n", (unsigned) (*((unsigned *)data))); // As per Nate's suggestion, we're going to add this data as a new // Region in the CodeObject. @@ -376,11 +377,13 @@ InsertedRegion *CFGModifier::insert(CodeObject *obj, Function *CFGModifier::makeEntry(Block *b) { // This is actually a really straightforward application of the existing // functionality. - // We want to call ParseData::get_func(CodeRegion *, Address, FuncSource) ParseData *data = b->obj()->parser->_parse_data; - - return data->get_func(b->region(), b->start(), MODIFICATION); + + Function* f = data->createAndRecordFunc(b->region(), b->start(), MODIFICATION); + if (f == NULL) + f = data->findFunc(b->region(),b->start()); + return f; } diff --git a/parseAPI/src/CodeObject.C b/parseAPI/src/CodeObject.C index 29c9c57a53..1cfe897431 100644 --- a/parseAPI/src/CodeObject.C +++ b/parseAPI/src/CodeObject.C @@ -74,8 +74,7 @@ CodeObject::CodeObject(CodeSource *cs, flist(parser->sorted_funcs) { process_hints(); // if any - if (cs->getArch() == Arch_ppc64) - parse(); + parse(); } void @@ -117,35 +116,41 @@ CodeObject::findFuncByEntry(CodeRegion * cr, Address entry) int CodeObject::findFuncs(CodeRegion * cr, Address addr, set & funcs) { + assert(parser); return parser->findFuncs(cr,addr,funcs); } int CodeObject::findFuncs(CodeRegion * cr, Address start, Address end, set & funcs) { + assert(parser); return parser->findFuncs(cr,start,end,funcs); } Block * CodeObject::findBlockByEntry(CodeRegion * cr, Address addr) { + assert(parser); return parser->findBlockByEntry(cr, addr); } Block * CodeObject::findNextBlock(CodeRegion * cr, Address addr) { + assert(parser); return parser->findNextBlock(cr, addr); } int CodeObject::findBlocks(CodeRegion * cr, Address addr, set & blocks) { + assert(parser); return parser->findBlocks(cr,addr,blocks); } // find without parsing. int CodeObject::findCurrentBlocks(CodeRegion * cr, Address addr, set & blocks) { + assert(parser); return parser->findCurrentBlocks(cr,addr,blocks); } @@ -203,9 +208,9 @@ void CodeObject::add_edge(Block * src, Block * trg, EdgeTypeEnum et) { if (trg == NULL) { - parser->link(src, parser->_sink, et, true); + parser->link_block(src, parser->_sink, et, true); } else { - parser->link(src,trg,et,false); + parser->link_block(src,trg,et,false); } } @@ -236,6 +241,7 @@ CodeObject::parseNewEdges( vector & worklist ) // don't add edges that already exist // (this could happen because of shared code) bool edgeExists = false; + boost::lock_guard g(*worklist[idx].source); const Block::edgelist & existingTs = worklist[idx].source->targets(); for (Block::edgelist::const_iterator tit = existingTs.begin(); tit != existingTs.end(); @@ -258,6 +264,7 @@ CodeObject::parseNewEdges( vector & worklist ) fit != funcs.end(); fit++) { + boost::lock_guard g(*worklist[idx].source); const Block::edgelist & tedges = worklist[idx].source->targets(); for(Block::edgelist::const_iterator eit = tedges.begin(); eit != tedges.end(); @@ -289,6 +296,7 @@ CodeObject::parseNewEdges( vector & worklist ) ( bundle, ParseWorkElem::checked_call_ft, parser->link_tempsink(worklist[idx].source, worklist[idx].edge_type), + worklist[idx].source->last(), worklist[idx].target, true, false )); @@ -296,6 +304,7 @@ CodeObject::parseNewEdges( vector & worklist ) elem = bundle->add(new ParseWorkElem ( bundle, parser->link_tempsink(worklist[idx].source, worklist[idx].edge_type), + worklist[idx].source->last(), worklist[idx].target, true, false )); @@ -403,3 +412,5 @@ Address CodeObject::getFreeAddr() const { } return hi; } + +ParseData *CodeObject::parse_data() { return parser->parse_data(); } diff --git a/parseAPI/src/CodeSource.C b/parseAPI/src/CodeSource.C index 7faf48cb14..eaeb74801b 100644 --- a/parseAPI/src/CodeSource.C +++ b/parseAPI/src/CodeSource.C @@ -94,7 +94,11 @@ CodeSource::non_returning_funcs = ("_ZSt20__throw_out_of_rangePKc",true) ("__cxa_rethrow",true) ("__cxa_throw",true) + ("__cxa_call_unexpected", true) + ("__cxa_bad_cast", true) + ("_ZSt24__throw_out_of_range_fmtPKcz", true) ("_ZSt21__throw_runtime_errorPKc",true) + ("_ZSt20__throw_system_errori", true) ("_ZSt9terminatev",true) ("_gfortran_os_error",true) ("_gfortran_runtime_error",true) diff --git a/parseAPI/src/Function.C b/parseAPI/src/Function.C index a46d2cb02e..f957c761b9 100644 --- a/parseAPI/src/Function.C +++ b/parseAPI/src/Function.C @@ -47,6 +47,7 @@ #include "StackTamperVisitor.h" #include "common/src/dthread.h" +#include using namespace std; @@ -136,7 +137,7 @@ Function::~Function() Function::blocklist Function::blocks() { - + boost::lock_guard g(*this); if(!_cache_valid) finalize(); return blocklist(blocks_begin(), blocks_end()); @@ -147,11 +148,7 @@ Function::blocks() Function::const_blocklist Function::blocks() const { - /*Function* mutable_this = const_cast(this); - - if(!_cache_valid) - mutable_this->finalize(); - */ + boost::lock_guard g(*this); assert(_cache_valid); return const_blocklist(blocks_begin(), blocks_end()); @@ -160,6 +157,7 @@ Function::blocks() const const Function::edgelist & Function::callEdges() { + boost::lock_guard g(*this); if(!_cache_valid) finalize(); return _call_edge_list; @@ -167,14 +165,16 @@ Function::callEdges() { Function::const_blocklist Function::returnBlocks() { - if (!_cache_valid) + boost::lock_guard g(*this); + if (!_cache_valid) finalize(); return const_blocklist(ret_begin(), ret_end()); } Function::const_blocklist Function::exitBlocks() { - if (!_cache_valid) + boost::lock_guard g(*this); + if (!_cache_valid) finalize(); return const_blocklist(exit_begin(), exit_end()); @@ -183,6 +183,7 @@ Function::exitBlocks() { Function::const_blocklist Function::exitBlocks() const { + boost::lock_guard g(*this); assert(_cache_valid); return const_blocklist(exit_begin(), exit_end()); @@ -191,6 +192,7 @@ Function::exitBlocks() const { vector const& Function::extents() { + boost::lock_guard g(*this); if(!_cache_valid) finalize(); return _extents; @@ -199,6 +201,7 @@ Function::extents() void Function::finalize() { + boost::lock_guard g(*this); _extents.clear(); _exitBL.clear(); @@ -209,6 +212,7 @@ Function::finalize() _bmap.clear(); _retBL.clear(); _call_edge_list.clear(); + _cache_valid = false; // The Parser knows how to finalize // a Function's parse data @@ -218,6 +222,7 @@ Function::finalize() Function::blocklist Function::blocks_int() { + boost::lock_guard g(*this); if(_cache_valid || !_entry) return blocklist(blocks_begin(), blocks_end()); @@ -250,6 +255,7 @@ Function::blocks_int() bool exit_func = false; bool found_call = false; bool found_call_ft = false; + boost::lock_guard g(*cur); if (cur->targets().empty()) exit_func = true; for (auto eit = cur->targets().begin(); eit != cur->targets().end(); ++eit) { @@ -262,7 +268,7 @@ Function::blocks_int() found_call_ft = true; } - if (e->type() == RET || t->obj() != cur->obj()) { + if (e->type() == RET || !t || t->obj() != cur->obj()) { exit_func = true; break; } @@ -304,8 +310,12 @@ Function::blocks_int() Edge * e = *tit; Block * t = e->trg(); - parsing_printf("\t Considering target block [0x%lx,0x%lx) from edge %p\n", - t->start(), t->end(), e); + if(t) + { + parsing_printf("\t Considering target block [0x%lx,0x%lx) from edge %p\n", + t->start(), t->end(), e); + + } if (e->type() == CALL_FT) { found_call_ft = true; @@ -326,7 +336,6 @@ Function::blocks_int() if (_tamper != TAMPER_UNSET && _tamper != TAMPER_NONE) continue; } - set_retstatus(RETURN); continue; } @@ -339,7 +348,7 @@ Function::blocks_int() } // If we are heading to a different CodeObject, call it a return // and don't add target blocks. - if (t->obj() != cur->obj()) { + if (t && (t->obj() != cur->obj())) { // This is a jump to a different CodeObject; call it an exit parsing_printf("Block exits object\n"); exits_func = true; @@ -352,11 +361,13 @@ Function::blocks_int() continue; } - if(!HASHDEF(visited,t->start())) { - parsing_printf("\t Adding target block [%lx,%lx) to worklist according to edge from %lx, type %d\n", t->start(), t->end(), e->src()->last(), e->type()); - worklist.push_back(t); - visited[t->start()] = true; - add_block(t); + if(!HASHDEF(visited,e->trg_addr())) { + if(t) { + parsing_printf("\t Adding target block [%lx,%lx) to worklist according to edge from %lx, type %d\n", t->start(), t->end(), e->src()->last(), e->type()); + worklist.push_back(t); + visited[e->trg_addr()] = 1; + add_block(t); + } } } if (found_call && !found_call_ft && !obj()->defensiveMode()) { @@ -393,15 +404,21 @@ Function::blocks_int() void Function::delayed_link_return(CodeObject * o, Block * retblk) { + boost::lock_guard g(*this); bool link_entry = false; - + Block::edgelist::const_iterator eit; dyn_hash_map linked; - Block::edgelist::const_iterator eit = retblk->targets().begin(); - for( ; eit != retblk->targets().end(); ++eit) { - Edge * e = *eit; - linked[e->trg()->start()] = true; + { + boost::lock_guard g(*retblk); + eit = retblk->targets().begin(); + for( ; eit != retblk->targets().end(); ++eit) { + Edge * e = *eit; + linked[e->trg_addr()] = true; + } + } + boost::lock_guard g2(*_entry); eit = _entry->sources().begin(); for( ; eit != _entry->sources().end(); ++eit) { Edge * e = *eit; @@ -434,6 +451,7 @@ Function::delayed_link_return(CodeObject * o, Block * retblk) void Function::add_block(Block *b) { + boost::lock_guard g(*this); ++b->_func_cnt; // block counts references _bmap[b->start()] = b; } @@ -447,6 +465,7 @@ Function::name() const bool Function::contains(Block *b) { + boost::lock_guard g(*this); if (b == NULL) return false; if(!_cache_valid) finalize(); @@ -454,8 +473,18 @@ Function::contains(Block *b) return HASHDEF(_bmap,b->start()); } +bool +Function::contains(Block *b) const +{ +// boost::lock_guard g(*this); + if (b == NULL) return false; + return HASHDEF(_bmap,b->start()); +} + + void Function::setEntryBlock(Block *new_entry) { + boost::lock_guard g(*this); obj()->parser->move_func(this, new_entry->start(), new_entry->region()); _region = new_entry->region(); _start = new_entry->start(); @@ -464,13 +493,16 @@ void Function::setEntryBlock(Block *new_entry) void Function::set_retstatus(FuncReturnStatus rs) { + boost::lock_guard g(*this); // If this function is a known non-returning function, // we should ignore this result. // A exmaple is .Unwind_Resume, which is non-returning. // But on powerpc, the function contains a BLR instruction, // looking like a return instruction, but actually is not. if (obj()->cs()->nonReturning(_name) && rs != NORETURN) return; - + assert(!(_rs == RETURN && rs == NORETURN)); + assert(!(_rs == NORETURN && rs == RETURN)); + // If we are changing the return status, update prev counter if (_rs != UNSET) { if (_rs == NORETURN) { @@ -490,12 +522,15 @@ void Function::set_retstatus(FuncReturnStatus rs) } else if (rs == UNKNOWN) { _obj->cs()->incrementCounter(PARSE_UNKNOWN_COUNT); } - _rs = rs; + race_detector_fake_lock_acquire(race_detector_fake_lock(_rs)); + _rs.store(rs); + race_detector_fake_lock_release(race_detector_fake_lock(_rs)); } void Function::removeBlock(Block* dead) { + boost::lock_guard g(*this); _cache_valid = false; // specify replacement entry prior to deleting entry block, unless // deleting all blocks @@ -507,6 +542,7 @@ Function::removeBlock(Block* dead) } // remove dead block from _retBL and _call_edge_list + boost::lock_guard g2(*dead); const Block::edgelist & outs = dead->targets(); for (Block::edgelist::const_iterator oit = outs.begin(); outs.end() != oit; @@ -545,6 +581,7 @@ class ST_Predicates : public Slicer::Predicates {}; StackTamper Function::tampersStack(bool recalculate) { + boost::lock_guard g(*this); using namespace SymbolicEvaluation; using namespace InstructionAPI; @@ -579,7 +616,7 @@ Function::tampersStack(bool recalculate) InstructionDecoder retdec(this->isrc()->getPtrToInstruction(retnAddr), InstructionDecoder::maxInstructionLength, this->region()->getArch() ); - Instruction::Ptr retn = retdec.decode(); + Instruction retn = retdec.decode(); converter.convert(retn, retnAddr, this, *bit, assgns); vector::iterator ait; AST::Ptr sliceAtRet; @@ -668,6 +705,7 @@ void Function::destroy(Function *f) { } LoopTreeNode* Function::getLoopTree() const{ + boost::lock_guard g(*this); if (_loop_root == NULL) { LoopAnalyzer la(this); la.createLoopHierarchy(); @@ -681,6 +719,7 @@ LoopTreeNode* Function::getLoopTree() const{ void Function::getLoopsByNestingLevel(vector& lbb, bool outerMostOnly) const { + boost::lock_guard g(*this); if (_loop_analyzed == false) { LoopAnalyzer la(this); la.analyzeLoops(); @@ -703,6 +742,7 @@ void Function::getLoopsByNestingLevel(vector& lbb, bool Function::getLoops(vector& lbb) const { + boost::lock_guard g(*this); getLoopsByNestingLevel(lbb, false); return true; } @@ -711,12 +751,14 @@ Function::getLoops(vector& lbb) const bool Function::getOuterLoops(vector& lbb) const { + boost::lock_guard g(*this); getLoopsByNestingLevel(lbb, true); return true; } Loop *Function::findLoop(const char *name) const { + boost::lock_guard g(*this); return getLoopTree()->findLoop(name); } @@ -730,6 +772,7 @@ Loop *Function::findLoop(const char *name) const //be called to process dominator related fields and methods. void Function::fillDominatorInfo() const { + boost::lock_guard g(*this); if (!isDominatorInfoReady) { dominatorCFG domcfg(this); domcfg.calcDominators(); @@ -739,6 +782,7 @@ void Function::fillDominatorInfo() const void Function::fillPostDominatorInfo() const { + boost::lock_guard g(*this); if (!isPostDominatorInfoReady) { dominatorCFG domcfg(this); domcfg.calcPostDominators(); @@ -747,6 +791,7 @@ void Function::fillPostDominatorInfo() const } bool Function::dominates(Block* A, Block *B) const { + boost::lock_guard g(*this); if (A == NULL || B == NULL) return false; if (A == B) return true; @@ -760,17 +805,20 @@ bool Function::dominates(Block* A, Block *B) const { } Block* Function::getImmediateDominator(Block *A) const { + boost::lock_guard g(*this); fillDominatorInfo(); return immediateDominator[A]; } void Function::getImmediateDominates(Block *A, set &imd) const { + boost::lock_guard g(*this); fillDominatorInfo(); if (immediateDominates[A] != NULL) imd.insert(immediateDominates[A]->begin(), immediateDominates[A]->end()); } void Function::getAllDominates(Block *A, set &d) const { + boost::lock_guard g(*this); fillDominatorInfo(); d.insert(A); if (immediateDominates[A] == NULL) return; @@ -780,6 +828,7 @@ void Function::getAllDominates(Block *A, set &d) const { } bool Function::postDominates(Block* A, Block *B) const { + boost::lock_guard g(*this); if (A == NULL || B == NULL) return false; if (A == B) return true; @@ -793,17 +842,20 @@ bool Function::postDominates(Block* A, Block *B) const { } Block* Function::getImmediatePostDominator(Block *A) const { + boost::lock_guard g(*this); fillPostDominatorInfo(); return immediatePostDominator[A]; } void Function::getImmediatePostDominates(Block *A, set &imd) const { + boost::lock_guard g(*this); fillPostDominatorInfo(); if (immediatePostDominates[A] != NULL) imd.insert(immediatePostDominates[A]->begin(), immediatePostDominates[A]->end()); } void Function::getAllPostDominates(Block *A, set &d) const { + boost::lock_guard g(*this); fillPostDominatorInfo(); d.insert(A); if (immediatePostDominates[A] == NULL) return; diff --git a/parseAPI/src/IA_IAPI.C b/parseAPI/src/IA_IAPI.C index a7f92c7f1f..93a1dee517 100644 --- a/parseAPI/src/IA_IAPI.C +++ b/parseAPI/src/IA_IAPI.C @@ -213,23 +213,23 @@ IA_IAPI::reset( void IA_IAPI::advance() { - if(!curInsn()) { - parsing_printf("..... WARNING: failed to advance InstructionAdapter at 0x%lx, allInsns.size() = %d\n", current, - allInsns.size()); - return; - } +// if(!curInsn()) { +// parsing_printf("..... WARNING: failed to advance InstructionAdapter at 0x%lx, allInsns.size() = %d\n", current, +// allInsns.size()); +// return; +// } InstructionAdapter::advance(); - current += curInsn()->size(); + current += curInsn().size(); curInsnIter = allInsns.insert( allInsns.end(), std::make_pair(current, dec.decode())); - if(!curInsn()) - { - parsing_printf("......WARNING: after advance at 0x%lx, curInsn() NULL\n", current); - } +// if(!curInsn()) +// { +// parsing_printf("......WARNING: after advance at 0x%lx, curInsn() NULL\n", current); +// } validCFT = false; validLinkerStubState = false; hascftstatus.first = false; @@ -238,11 +238,11 @@ void IA_IAPI::advance() bool IA_IAPI::retreat() { - if(!curInsn()) { - parsing_printf("..... WARNING: failed to retreat InstructionAdapter at 0x%lx, allInsns.size() = %d\n", current, - allInsns.size()); - return false; - } +// if(!curInsn()) { +// parsing_printf("..... WARNING: failed to retreat InstructionAdapter at 0x%lx, allInsns.size() = %d\n", current, +// allInsns.size()); +// return false; +// } InstructionAdapter::retreat(); allInsns_t::iterator remove = curInsnIter; if(curInsnIter != allInsns.begin()) { @@ -273,24 +273,23 @@ bool IA_IAPI::retreat() size_t IA_IAPI::getSize() const { - Instruction::Ptr ci = curInsn(); - assert(ci); - return ci->size(); + assert(curInsn().isValid()); + return curInsn().size(); } bool IA_IAPI::hasCFT() const { - parsing_cerr << "hasCFT called" << endl; + parsing_printf("hasCFT called\n"); if(hascftstatus.first) { - parsing_cerr << "\t Returning cached entry: " << hascftstatus.second << endl; + parsing_printf("\t Returning cached entry: %d\n",hascftstatus.second); return hascftstatus.second; } - InsnCategory c = curInsn()->getCategory(); + InsnCategory c = curInsn().getCategory(); hascftstatus.second = false; if(c == c_BranchInsn || c == c_ReturnInsn) { if ( likely ( ! (_obj->defensiveMode() && isNopJump()) ) ) { - parsing_cerr << "\t branch or return, ret true" << endl; + parsing_printf("\t branch or return, ret true\n"); hascftstatus.second = true; } } @@ -320,14 +319,14 @@ bool IA_IAPI::hasCFT() const bool IA_IAPI::isAbort() const { - entryID e = curInsn()->getOperation().getID(); + entryID e = curInsn().getOperation().getID(); return e == e_int3 || e == e_hlt; } bool IA_IAPI::isInvalidInsn() const { - entryID e = curInsn()->getOperation().getID(); + entryID e = curInsn().getOperation().getID(); if(e == e_No_Entry) { parsing_printf("...WARNING: un-decoded instruction at 0x%x\n", current); @@ -348,7 +347,7 @@ bool IA_IAPI::isGarbageInsn() const bool ret = false; // GARBAGE PARSING HEURISTIC if (unlikely(_obj->defensiveMode())) { - entryID e = curInsn()->getOperation().getID(); + entryID e = curInsn().getOperation().getID(); switch (e) { case e_arpl: cerr << "REACHED AN ARPL AT "<< std::hex << current @@ -367,7 +366,7 @@ bool IA_IAPI::isGarbageInsn() const break; case e_mov: { set regs; - curInsn()->getWriteSet(regs); + curInsn().getWriteSet(regs); for (set::iterator rit = regs.begin(); rit != regs.end(); rit++) { @@ -381,9 +380,9 @@ bool IA_IAPI::isGarbageInsn() const break; } case e_add: - if (2 == curInsn()->size() && - 0 == curInsn()->rawByte(0) && - 0 == curInsn()->rawByte(1)) + if (2 == curInsn().size() && + 0 == curInsn().rawByte(0) && + 0 == curInsn().rawByte(1)) { cerr << "REACHED A 0x0000 INSTRUCTION "<< std::hex << current << std::dec <<" COUNTING AS INVALID" << endl; @@ -405,7 +404,7 @@ bool IA_IAPI::isGarbageInsn() const } } #else // faster raw-byte implementation - switch (curInsn()->rawByte(0)) { + switch (curInsn().rawByte(0)) { case 0x06: case 0x0e: case 0x16: @@ -415,8 +414,8 @@ bool IA_IAPI::isGarbageInsn() const << std::dec <<" COUNTING AS INVALID" << endl; break; case 0x0f: - if (2 == curInsn()->size() && - ((0xa0 == curInsn()->rawByte(1)) || (0xa8 == curInsn()->rawByte(1)))) + if (2 == curInsn().size() && + ((0xa0 == curInsn().rawByte(1)) || (0xa8 == curInsn().rawByte(1)))) { ret = true; cerr << "REACHED A 2-BYTE PUSH OF A SEGMENT REGISTER "<< std::hex << current @@ -440,8 +439,8 @@ bool IA_IAPI::isFrameSetupInsn() const bool IA_IAPI::isDynamicCall() const { - Instruction::Ptr ci = curInsn(); - if(ci && (ci->getCategory() == c_CallInsn)) + Instruction ci = curInsn(); + if(ci.isValid() && (ci.getCategory() == c_CallInsn)) { Address addr; bool success; @@ -456,10 +455,10 @@ bool IA_IAPI::isDynamicCall() const bool IA_IAPI::isAbsoluteCall() const { - Instruction::Ptr ci = curInsn(); - if(ci->getCategory() == c_CallInsn) + Instruction ci = curInsn(); + if(ci.getCategory() == c_CallInsn) { - Expression::Ptr cft = ci->getControlFlowTarget(); + Expression::Ptr cft = ci.getControlFlowTarget(); if(cft && boost::dynamic_pointer_cast(cft)) { return true; @@ -474,11 +473,11 @@ bool IA_IAPI::isAbsoluteCall() const bool IA_IAPI::isBranch() const { - return curInsn()->getCategory() == c_BranchInsn; + return curInsn().getCategory() == c_BranchInsn; } bool IA_IAPI::isCall() const { - return curInsn()->getCategory() == c_CallInsn; + return curInsn().getCategory() == c_CallInsn; } bool IA_IAPI::isInterruptOrSyscall() const @@ -490,34 +489,34 @@ bool IA_IAPI::isSyscall() const { static RegisterAST::Ptr gs(new RegisterAST(x86::gs)); - Instruction::Ptr ci = curInsn(); + Instruction ci = curInsn(); - return (((ci->getOperation().getID() == e_call) && - (curInsn()->getOperation().isRead(gs)) && - (ci->getOperand(0).format(ci->getFormatter(), ci->getArch()) == "16")) || - (ci->getOperation().getID() == e_syscall) || - (ci->getOperation().getID() == e_int) || - (ci->getOperation().getID() == power_op_sc)); + return (((ci.getOperation().getID() == e_call) && + (ci.getOperation().isRead(gs)) && + (ci.getOperand(0).format(ci.getArch()) == "16")) || + (ci.getOperation().getID() == e_syscall) || + (ci.getOperation().getID() == e_int) || + (ci.getOperation().getID() == power_op_sc)); } bool IA_IAPI::isInterrupt() const { - Instruction::Ptr ci = curInsn(); - return ((ci->getOperation().getID() == e_int) || - (ci->getOperation().getID() == e_int3)); + Instruction ci = curInsn(); + return ((ci.getOperation().getID() == e_int) || + (ci.getOperation().getID() == e_int3)); } bool IA_IAPI::isSysEnter() const { - Instruction::Ptr ci = curInsn(); - return (ci->getOperation().getID() == e_sysenter); + Instruction ci = curInsn(); + return (ci.getOperation().getID() == e_sysenter); } bool IA_IAPI::isIndirectJump() const { - Instruction::Ptr ci = curInsn(); - if(ci->getCategory() != c_BranchInsn) return false; - if(ci->allowsFallThrough()) return false; + Instruction ci = curInsn(); + if(ci.getCategory() != c_BranchInsn) return false; + if(ci.allowsFallThrough()) return false; bool valid; Address target; boost::tie(valid, target) = getCFT(); @@ -541,7 +540,7 @@ void IA_IAPI::parseSysEnter(std::vector >& outE do { scratch->advance(); } while(scratch->isNop()); - if(scratch->curInsn()->getCategory() == c_BranchInsn) + if(scratch->curInsn().getCategory() == c_BranchInsn) { parsing_printf("[%s:%d] Detected Linux-ish sysenter idiom at 0x%lx\n", FILE__, __LINE__, getAddr()); @@ -567,10 +566,10 @@ void IA_IAPI::getNewEdges(std::vector >& outEd dyn_hash_map *plt_entries, const set
& knownTargets) const { - Instruction::Ptr ci = curInsn(); + Instruction ci = curInsn(); // Only call this on control flow instructions! - if(ci->getCategory() == c_CallInsn) + if(ci.getCategory() == c_CallInsn) { bool success; Address target; @@ -618,9 +617,9 @@ void IA_IAPI::getNewEdges(std::vector >& outEd } return; } - else if(ci->getCategory() == c_BranchInsn) + else if(ci.getCategory() == c_BranchInsn) { - if(ci->allowsFallThrough()) + if(ci.allowsFallThrough()) { outEdges.push_back(std::make_pair(getCFT().second, COND_TAKEN)); @@ -670,7 +669,7 @@ void IA_IAPI::getNewEdges(std::vector >& outEd { parsing_printf("\tIndirect branch as 2nd insn of entry block, treating as tail call\n"); parsing_printf("%s[%d]: indirect tail call %s at 0x%lx\n", FILE__, __LINE__, - ci->format().c_str(), current); + ci.format().c_str(), current); outEdges.push_back(std::make_pair((Address)-1,INDIRECT)); tailCalls[INDIRECT]=true; // Fix the cache, because we're dumb. @@ -685,29 +684,29 @@ void IA_IAPI::getNewEdges(std::vector >& outEd } if(isTailCall(context, INDIRECT, num_insns, knownTargets)) { parsing_printf("%s[%d]: indirect tail call %s at 0x%lx\n", FILE__, __LINE__, - ci->format().c_str(), current); + ci.format().c_str(), current); outEdges.push_back(std::make_pair((Address)-1,INDIRECT)); tailCalls[INDIRECT] = true; return; } parsing_printf("%s[%d]: jump table candidate %s at 0x%lx\n", FILE__, __LINE__, - ci->format().c_str(), current); + ci.format().c_str(), current); parsedJumpTable = true; successfullyParsedJumpTable = parseJumpTable(context, currBlk, outEdges); parsing_printf("Parsed jump table\n"); if(!successfullyParsedJumpTable || outEdges.empty()) { outEdges.push_back(std::make_pair((Address)-1,INDIRECT)); parsing_printf("%s[%d]: unparsed jump table %s at 0x%lx in function %s UNINSTRUMENTABLE\n", FILE__, __LINE__, - ci->format().c_str(), current, context->name().c_str()); + ci.format().c_str(), current, context->name().c_str()); } return; } } - else if(ci->getCategory() == c_ReturnInsn) + else if(ci.getCategory() == c_ReturnInsn) { parsing_printf("%s[%d]: return candidate %s at 0x%lx\n", FILE__, __LINE__, - ci->format().c_str(), current); - if(ci->allowsFallThrough()) + ci.format().c_str(), current); + if(ci.allowsFallThrough()) { outEdges.push_back(std::make_pair(getNextAddr(), FALLTHROUGH)); } @@ -715,12 +714,12 @@ void IA_IAPI::getNewEdges(std::vector >& outEd // If BLR is not a return, then it is a jump table parsedJumpTable = true; parsing_printf("%s[%d]: BLR jump table candidate %s at 0x%lx\n", FILE__, __LINE__, - ci->format().c_str(), current); + ci.format().c_str(), current); successfullyParsedJumpTable = parseJumpTable(context, currBlk, outEdges); parsing_printf("Parsed BLR jump table\n"); if(!successfullyParsedJumpTable || outEdges.empty()) { parsing_printf("%s[%d]: BLR unparsed jump table %s at 0x%lx in function %s UNINSTRUMENTABLE\n", - FILE__, __LINE__, ci->format().c_str(), current, context->name().c_str()); + FILE__, __LINE__, ci.format().c_str(), current, context->name().c_str()); outEdges.push_back(std::make_pair((Address)-1,INDIRECT)); } } @@ -737,7 +736,7 @@ void IA_IAPI::getNewEdges(std::vector >& outEd return; } - fprintf(stderr, "Unhandled instruction %s\n", ci->format().c_str()); + fprintf(stderr, "Unhandled instruction %s\n", ci.format().c_str()); assert(0); } @@ -747,19 +746,19 @@ bool IA_IAPI::isIPRelativeBranch() const #if !defined(arch_x86_64) return false; #endif - Instruction::Ptr ci = curInsn(); + Instruction ci = curInsn(); bool valid; Address target; boost::tie(valid, target) = getCFT(); - if(ci->getCategory() == c_BranchInsn && + if(ci.getCategory() == c_BranchInsn && !valid) { - Expression::Ptr cft = ci->getControlFlowTarget(); + Expression::Ptr cft = ci.getControlFlowTarget(); if(cft->isUsed(thePC[_isrc->getArch()])) { parsing_printf("\tIP-relative indirect jump to %s at 0x%lx\n", - cft->format(ci->getFormatter()).c_str(), current); + cft->format(ci.getArch()).c_str(), current); return true; } } @@ -767,15 +766,15 @@ bool IA_IAPI::isIPRelativeBranch() const } -Instruction::Ptr IA_IAPI::curInsn() const +const Instruction & IA_IAPI::curInsn() const { return curInsnIter->second; } bool IA_IAPI::isLeave() const { - Instruction::Ptr ci = curInsn(); - return ci && (ci->getOperation().getID() == e_leave); + Instruction ci = curInsn(); + return ci.isValid() && (ci.getOperation().getID() == e_leave); } bool IA_IAPI::isDelaySlot() const @@ -783,7 +782,7 @@ bool IA_IAPI::isDelaySlot() const return false; } -Instruction::Ptr IA_IAPI::getInstruction() const +const Instruction& IA_IAPI::getInstruction() const { return curInsn(); } @@ -810,7 +809,7 @@ std::map IA_IAPI::thunkAtTarget; bool IA_IAPI::isConditional() const { - return curInsn()->allowsFallThrough(); + return curInsn().allowsFallThrough(); } bool IA_IAPI::simulateJump() const @@ -827,18 +826,18 @@ bool IA_IAPI::simulateJump() const std::pair IA_IAPI::getFallthrough() const { - return make_pair(true, curInsnIter->first + curInsnIter->second->size()); + return make_pair(true, curInsnIter->first + curInsnIter->second.size()); } std::pair IA_IAPI::getCFT() const { if(validCFT) return cachedCFT; - Expression::Ptr callTarget = curInsn()->getControlFlowTarget(); + Expression::Ptr callTarget = curInsn().getControlFlowTarget(); if (!callTarget) return make_pair(false, 0); // FIXME: templated bind(),dammit! callTarget->bind(thePC[_isrc->getArch()].get(), Result(s64, current)); parsing_printf("%s[%d]: binding PC %s in %s to 0x%x...", FILE__, __LINE__, - thePC[_isrc->getArch()]->format(curInsn()->getFormatter()).c_str(), curInsn()->format().c_str(), current); + thePC[_isrc->getArch()]->format(curInsn().getArch()).c_str(), curInsn().format().c_str(), current); Result actualTarget = callTarget->eval(); #if defined(os_vxworks) @@ -905,7 +904,7 @@ std::pair IA_IAPI::getCFT() const { cachedCFT = std::make_pair(false, 0); parsing_printf("FAIL (CFT=0x%x), callTarget exp: %s\n", - cachedCFT.second,callTarget->format(curInsn()->getFormatter()).c_str()); + cachedCFT.second,callTarget->format(curInsn().getArch()).c_str()); } validCFT = true; @@ -919,8 +918,8 @@ std::pair IA_IAPI::getCFT() const bool IA_IAPI::isRelocatable(InstrumentableLevel lvl) const { - Instruction::Ptr ci = curInsn(); - if(ci && (ci->getCategory() == c_CallInsn)) + Instruction ci = curInsn(); + if(ci.isValid() && (ci.getCategory() == c_CallInsn)) { if(!isDynamicCall()) { diff --git a/parseAPI/src/IA_IAPI.h b/parseAPI/src/IA_IAPI.h index 64978985fc..4f79797525 100644 --- a/parseAPI/src/IA_IAPI.h +++ b/parseAPI/src/IA_IAPI.h @@ -56,12 +56,12 @@ class IA_IAPI : public InstructionAdapter { Dyninst::InstructionSource *isrc, Dyninst::ParseAPI::Block * curBlk_); // We have a iterator, and so can't use the implicit copiers - IA_IAPI(const IA_IAPI &); + IA_IAPI(const IA_IAPI &); IA_IAPI &operator=(const IA_IAPI &r); ~IA_IAPI() { } static IA_IAPI* makePlatformIA_IAPI(Dyninst::Architecture arch, Dyninst::InstructionAPI::InstructionDecoder dec_, - Address start_, + Address start_, Dyninst::ParseAPI::CodeObject* o, Dyninst::ParseAPI::CodeRegion* r, Dyninst::InstructionSource *isrc, @@ -71,7 +71,7 @@ class IA_IAPI : public InstructionAdapter { Address start, ParseAPI::CodeObject *o, ParseAPI::CodeRegion *r, InstructionSource *isrc, ParseAPI::Block *); - virtual Dyninst::InstructionAPI::Instruction::Ptr getInstruction() const; + virtual const Dyninst::InstructionAPI::Instruction& getInstruction() const; virtual bool hasCFT() const; virtual size_t getSize() const; @@ -97,10 +97,10 @@ class IA_IAPI : public InstructionAdapter { virtual bool isLeave() const; virtual bool isDelaySlot() const; virtual bool isRelocatable(InstrumentableLevel lvl) const; - virtual bool isTailCall(Dyninst::ParseAPI::Function *, - Dyninst::ParseAPI::EdgeTypeEnum, - unsigned int, - const std::set
&) const = 0; + virtual bool isTailCall(const ParseAPI::Function *, + Dyninst::ParseAPI::EdgeTypeEnum, + unsigned int, + const std::set
&) const = 0; virtual std::pair getCFT() const; virtual bool isStackFramePreamble() const = 0; virtual bool savesFP() const = 0; @@ -124,7 +124,7 @@ class IA_IAPI : public InstructionAdapter { Dyninst::ParseAPI::Block* currBlk, std::vector >& outEdges) const; virtual bool isIPRelativeBranch() const; - virtual bool isFrameSetupInsn(Dyninst::InstructionAPI::Instruction::Ptr i) const = 0; + virtual bool isFrameSetupInsn(Dyninst::InstructionAPI::Instruction i) const = 0; virtual bool isReturn(Dyninst::ParseAPI::Function *, Dyninst::ParseAPI::Block* currBlk) const = 0; virtual bool isFakeCall() const = 0; virtual bool isLinkerStub() const = 0; @@ -146,11 +146,11 @@ class IA_IAPI : public InstructionAdapter { public: typedef std::vector< std::pair + Dyninst::InstructionAPI::Instruction> > allInsns_t; protected: allInsns_t allInsns; - Dyninst::InstructionAPI::Instruction::Ptr curInsn() const; + const InstructionAPI::Instruction & curInsn() const; allInsns_t::iterator curInsnIter; mutable bool validCFT; diff --git a/parseAPI/src/IA_aarch64.C b/parseAPI/src/IA_aarch64.C index 826442accc..67dd94780a 100644 --- a/parseAPI/src/IA_aarch64.C +++ b/parseAPI/src/IA_aarch64.C @@ -71,17 +71,18 @@ IA_aarch64* IA_aarch64::clone() const { return new IA_aarch64(*this); } -bool IA_aarch64::isFrameSetupInsn(Instruction::Ptr i) const +bool IA_aarch64::isFrameSetupInsn(Instruction i) const { - if(i->getOperation().getID() == aarch64_op_mov_add_addsub_imm) + if(i.getOperation().getID() == aarch64_op_mov_add_addsub_imm) { - if(i->readsMemory() || i->writesMemory()) + if(i.readsMemory() || i.writesMemory()) { - parsing_printf("%s[%d]: discarding insn %s as stack frame preamble, not a reg-reg move\n", FILE__, __LINE__, i->format().c_str()); + parsing_printf("%s[%d]: discarding insn %s as stack frame preamble, not a reg-reg move\n", FILE__, __LINE__, + i.format().c_str()); return false; } - if(i->isRead(stackPtr[_isrc->getArch()]) && i->isWritten(framePtr[_isrc->getArch()])) + if(i.isRead(stackPtr[_isrc->getArch()]) && i.isWritten(framePtr[_isrc->getArch()])) { return true; } @@ -90,9 +91,9 @@ bool IA_aarch64::isFrameSetupInsn(Instruction::Ptr i) const bool IA_aarch64::isNop() const { - Instruction::Ptr ci = curInsn(); + Instruction ci = curInsn(); - if(ci->getOperation().getID() == aarch64_op_nop_hint) + if(ci.getOperation().getID() == aarch64_op_nop_hint) return true; return false; @@ -103,7 +104,7 @@ bool IA_aarch64::isThunk() const return false; } -bool IA_aarch64::isTailCall(Function* context, EdgeTypeEnum type, unsigned int, +bool IA_aarch64::isTailCall(const Function* context, EdgeTypeEnum type, unsigned int, const std::set
& knownTargets ) const { switch(type) { @@ -139,34 +140,14 @@ bool IA_aarch64::isTailCall(Function* context, EdgeTypeEnum type, unsigned int, Function *callee = _obj->findFuncByEntry(_cr, addr); Block *target = _obj->findBlockByEntry(_cr, addr); - // check if addr is in a block if it is not entry. - if (target == NULL) { - std::set blocks; - _obj->findCurrentBlocks(_cr, addr, blocks); - if (blocks.size() == 1) { - target = *blocks.begin(); - } else if (blocks.size() == 0) { - // This case can happen when the jump target is a function entry, - // but we have not parsed the function yet - target = NULL; - } else { - // If this case happens, it means the jump goes into overlapping instruction streams, - // it is not likely to be a tail call. - parsing_printf("\tjumps into overlapping instruction streams\n"); - for (auto bit = blocks.begin(); bit != blocks.end(); ++bit) { - parsing_printf("\t block [%lx,%lx)\n", (*bit)->start(), (*bit)->end()); - } - parsing_printf("\tjump to 0x%lx, NOT TAIL CALL\n", addr); - tailCalls[type] = false; - return false; - } - } - - if(curInsn()->getCategory() == c_BranchInsn && + if(curInsn().getCategory() == c_BranchInsn && valid && callee && callee != context && - !context->contains(target) + // We can only trust entry points from hints + callee->src() == HINT && + /* the target can either be not parsed or not within the current context */ + ((target == NULL) || (target && !context->contains(target))) ) { parsing_printf("\tjump to 0x%lx, TAIL CALL\n", addr); @@ -174,7 +155,7 @@ bool IA_aarch64::isTailCall(Function* context, EdgeTypeEnum type, unsigned int, return true; } - if (curInsn()->getCategory() == c_BranchInsn && + if (curInsn().getCategory() == c_BranchInsn && valid && !callee) { if (target) { @@ -203,15 +184,15 @@ bool IA_aarch64::isTailCall(Function* context, EdgeTypeEnum type, unsigned int, bool IA_aarch64::savesFP() const { - Instruction::Ptr insn = curInsn(); + Instruction insn = curInsn(); RegisterAST::Ptr returnAddrReg(new RegisterAST(aarch64::x30)); //stp x29, x30, [sp, imm]! - if(insn->getOperation().getID() == aarch64_op_stp_gen && - insn->isRead(framePtr[_isrc->getArch()]) && - insn->isRead(returnAddrReg) && - insn->isRead(stackPtr[_isrc->getArch()]) && - insn->isWritten(stackPtr[_isrc->getArch()])) + if(insn.getOperation().getID() == aarch64_op_stp_gen && + insn.isRead(framePtr[_isrc->getArch()]) && + insn.isRead(returnAddrReg) && + insn.isRead(stackPtr[_isrc->getArch()]) && + insn.isWritten(stackPtr[_isrc->getArch()])) return true; return false; @@ -231,15 +212,15 @@ bool IA_aarch64::isStackFramePreamble() const bool IA_aarch64::cleansStack() const { - Instruction::Ptr insn = curInsn(); + Instruction insn = curInsn(); RegisterAST::Ptr returnAddrReg(new RegisterAST(aarch64::x30)); //ldp x29, x30, [sp], imm - if(insn->getOperation().getID() == aarch64_op_ldp_gen && - insn->isWritten(framePtr[_isrc->getArch()]) && - insn->isWritten(returnAddrReg) && - insn->isRead(stackPtr[_isrc->getArch()]) && - insn->isWritten(stackPtr[_isrc->getArch()])) + if(insn.getOperation().getID() == aarch64_op_ldp_gen && + insn.isWritten(framePtr[_isrc->getArch()]) && + insn.isWritten(returnAddrReg) && + insn.isRead(stackPtr[_isrc->getArch()]) && + insn.isWritten(stackPtr[_isrc->getArch()])) return true; return false; @@ -257,7 +238,7 @@ bool IA_aarch64::isReturnAddrSave(Address& retAddr) const bool IA_aarch64::isReturn(Dyninst::ParseAPI::Function * context, Dyninst::ParseAPI::Block* currBlk) const { - return curInsn()->getCategory() == c_ReturnInsn; + return curInsn().getCategory() == c_ReturnInsn; } bool IA_aarch64::isFakeCall() const diff --git a/parseAPI/src/IA_aarch64.h b/parseAPI/src/IA_aarch64.h index 04dd00f003..474c06178c 100644 --- a/parseAPI/src/IA_aarch64.h +++ b/parseAPI/src/IA_aarch64.h @@ -49,10 +49,11 @@ class IA_aarch64 : public IA_IAPI { Dyninst::ParseAPI::Block * curBlk_); IA_aarch64(const IA_aarch64 &); virtual IA_aarch64* clone() const; - virtual bool isFrameSetupInsn(Dyninst::InstructionAPI::Instruction::Ptr) const; + virtual bool isFrameSetupInsn(Dyninst::InstructionAPI::Instruction) const; virtual bool isNop() const; virtual bool isThunk() const; - virtual bool isTailCall(ParseAPI::Function* context, ParseAPI::EdgeTypeEnum type, unsigned int, const set
& knownTargets) const; + virtual bool isTailCall(const ParseAPI::Function* context, ParseAPI::EdgeTypeEnum type, + unsigned int, const set
& knownTargets) const; virtual bool savesFP() const; virtual bool isStackFramePreamble() const; virtual bool cleansStack() const; diff --git a/parseAPI/src/IA_power.C b/parseAPI/src/IA_power.C index 7dd9b54a21..8b49054f18 100644 --- a/parseAPI/src/IA_power.C +++ b/parseAPI/src/IA_power.C @@ -75,7 +75,7 @@ IA_power* IA_power::clone() const{ } -bool IA_power::isFrameSetupInsn(Instruction::Ptr) const +bool IA_power::isFrameSetupInsn(Instruction) const { return false; } @@ -89,7 +89,7 @@ bool IA_power::isThunk() const { return false; } -bool IA_power::isTailCall(Function* context, EdgeTypeEnum type, unsigned int, const set
& knownTargets) const +bool IA_power::isTailCall(const Function* context, EdgeTypeEnum type, unsigned int, const set
& knownTargets) const { // Collapse down to "branch" or "fallthrough" switch(type) { @@ -127,44 +127,21 @@ bool IA_power::isTailCall(Function* context, EdgeTypeEnum type, unsigned int, co Function* callee = _obj->findFuncByEntry(_cr, addr); Block* target = _obj->findBlockByEntry(_cr, addr); - if (callee == NULL) { - // It could be that this is a within linkage tail call. - // So, the function symbol is two instructions ahead of the call target. - addr -= 8; - callee = _obj->findFuncByEntry(_cr, addr); - target = _obj->findBlockByEntry(_cr, addr); - } - - // check if addr is in a block if it is not entry. - if (target == NULL) { - std::set blocks; - _obj->findCurrentBlocks(_cr, addr, blocks); - if (blocks.size() == 1) { - target = *blocks.begin(); - } else if (blocks.size() == 0) { - // This case can happen when the jump target is a function entry, - // but we have not parsed the function yet, - // or when this is an indirect jump - target = NULL; - } else { - // If this case happens, it means the jump goes into overlapping instruction streams, - // it is not likely to be a tail call. - parsing_printf("\tjumps into overlapping instruction streams\n"); - for (auto bit = blocks.begin(); bit != blocks.end(); ++bit) { - parsing_printf("\t block [%lx,%lx)\n", (*bit)->start(), (*bit)->end()); - } - parsing_printf("\tjump to 0x%lx, NOT TAIL CALL\n", addr); - tailCalls[type] = false; - return false; - } - } + Function *preambleCallee = _obj->findFuncByEntry(_cr, addr - 8); + Block* preambleTarget = _obj->findBlockByEntry(_cr, addr - 8); - if(curInsn()->getCategory() == c_BranchInsn && + if (callee == NULL || (preambleCallee != NULL && callee->src() != HINT && preambleCallee->src() == HINT)) { + callee = preambleCallee; + target = preambleTarget; + } + if(curInsn().getCategory() == c_BranchInsn && valid && callee && callee != context && - target && - !context->contains(target) + // We can only trust entry points from hints + callee->src() == HINT && + /* the target can either be not parsed or not within the current context */ + ((target == NULL) || (target && !context->contains(target))) ) { parsing_printf("\tjump to 0x%lx, TAIL CALL\n", addr); @@ -172,7 +149,7 @@ bool IA_power::isTailCall(Function* context, EdgeTypeEnum type, unsigned int, co return true; } - if (curInsn()->getCategory() == c_BranchInsn && + if (curInsn().getCategory() == c_BranchInsn && valid && !callee) { if (target) { @@ -187,7 +164,7 @@ bool IA_power::isTailCall(Function* context, EdgeTypeEnum type, unsigned int, co } if(allInsns.size() < 2) { - if(context->addr() == _curBlk->start() && curInsn()->getCategory() == c_BranchInsn) + if(context->addr() == _curBlk->start() && curInsn().getCategory() == c_BranchInsn) { parsing_printf("\tjump as only insn in entry block, TAIL CALL\n"); tailCalls[type] = true; @@ -248,7 +225,7 @@ bool IA_power::sliceReturn(ParseAPI::Block* bit, Address ret_addr, ParseAPI::Fun InstructionDecoder retdec( _isrc->getPtrToInstruction( retnAddr ), InstructionDecoder::maxInstructionLength, _cr->getArch() ); - Instruction::Ptr retn = retdec.decode(); + Instruction retn = retdec.decode(); converter.convert(retn, retnAddr, func, bit, assgns); for (ait = assgns.begin(); assgns.end() != ait; ait++) { AbsRegion & outReg = (*ait)->out(); @@ -301,19 +278,19 @@ bool IA_power::isReturnAddrSave(Address& retAddr) const bool foundMFLR = false; Address ret = 0; int cnt = 1; - Instruction::Ptr ci = curInsn (); + Instruction ci = curInsn (); parsing_printf(" Examining address 0x%lx to check if LR is saved on stack \n", getAddr()); - parsing_printf("\t\tchecking insn %s \n", ci->format().c_str()); + parsing_printf("\t\tchecking insn %s \n", ci.format().c_str()); - if (ci->getOperation ().getID () == power_op_mfspr && - ci->isRead (regLR)) + if (ci.getOperation().getID () == power_op_mfspr && + ci.isRead (regLR)) { foundMFLR = true; - ci->getWriteSet (regs); + ci.getWriteSet (regs); if (regs.size () != 1) { parsing_printf ("mfspr wrote %d registers instead of 1. insn: %s\n", - regs.size (), ci->format ().c_str ()); + regs.size (), ci.format ().c_str ()); return 0; } destLRReg = *(regs.begin ()); @@ -328,16 +305,16 @@ bool IA_power::isReturnAddrSave(Address& retAddr) const // walk to first control flow transfer instruction, looking // for a save of destLRReg IA_power copy (dec, getAddr (), _obj, _cr, _isrc, _curBlk); - while (!copy.hasCFT () && copy.curInsn ()) + while (!copy.hasCFT ()) { ci = copy.curInsn (); - if (ci->writesMemory () && - ci->isRead (regSP) && ci->isRead (destLRReg)) + if (ci.writesMemory () && + ci.isRead (regSP) && ci.isRead (destLRReg)) { ret = true; break; } - else if (ci->isWritten (destLRReg)) + else if (ci.isWritten (destLRReg)) { ret = false; break; @@ -353,11 +330,11 @@ bool IA_power::isReturnAddrSave(Address& retAddr) const bool IA_power::isReturn(Dyninst::ParseAPI::Function * context, Dyninst::ParseAPI::Block* currBlk) const { /* Check for leaf node or lw - mflr - blr pattern */ - if (curInsn()->getCategory() != c_ReturnInsn) { + if (curInsn().getCategory() != c_ReturnInsn) { parsing_printf(" Not BLR - returning false \n"); return false; } - Instruction::Ptr ci = curInsn (); + Instruction ci = curInsn (); Function *func = context; parsing_printf ("isblrReturn at 0x%lx Addr 0x%lx 0x%lx Function addr 0x%lx leaf %d \n", @@ -384,7 +361,7 @@ bool IA_power::isReturn(Dyninst::ParseAPI::Function * context, Dyninst::ParseAPI std::set < RegisterAST::Ptr > regs; RegisterAST::Ptr sourceLRReg; - Instruction::Ptr ci = curInsn (); + Instruction ci = curInsn (); bool foundMTLR = false; allInsns_t::reverse_iterator iter; Address blockStart = currBlk->start (); @@ -394,23 +371,23 @@ bool IA_power::isReturn(Dyninst::ParseAPI::Function * context, Dyninst::ParseAPI InstructionDecoder decCopy (b, currBlk->size (), this->_isrc->getArch ()); IA_power copy (decCopy, blockStart, _obj, _cr, _isrc, _curBlk); - while (copy.getInstruction () && !copy.hasCFT ()) + while (!copy.hasCFT ()) { copy.advance (); } for(iter = copy.allInsns.rbegin(); iter != copy.allInsns.rend(); iter++) { parsing_printf ("\t\tchecking insn 0x%x: %s \n", iter->first, - iter->second->format ().c_str ()); - if (iter->second->getOperation ().getID () == power_op_mtspr && - iter->second->isWritten (regLR)) + iter->second.format ().c_str ()); + if (iter->second.getOperation().getID () == power_op_mtspr && + iter->second.isWritten (regLR)) { - iter->second->getReadSet (regs); + iter->second.getReadSet (regs); if (regs.size () != 1) { parsing_printf ("expected mtspr to read 1 register, insn is %s\n", - ci->format ().c_str ()); + ci.format ().c_str ()); return false; } sourceLRReg = *(regs.begin ()); @@ -419,10 +396,10 @@ bool IA_power::isReturn(Dyninst::ParseAPI::Function * context, Dyninst::ParseAPI foundMTLR = true; } else if (foundMTLR && - iter->second->readsMemory () && - (iter->second->isRead (regSP) || - (iter->second->isRead (reg11))) && - iter->second->isWritten (sourceLRReg)) + iter->second.readsMemory () && + (iter->second.isRead (regSP) || + (iter->second.isRead (reg11))) && + iter->second.isWritten (sourceLRReg)) { parsing_printf ("\t\t\t **** Found lwz - RETURNING TRUE\n"); return true; diff --git a/parseAPI/src/IA_power.h b/parseAPI/src/IA_power.h index 777f0acfdd..29eb06e882 100644 --- a/parseAPI/src/IA_power.h +++ b/parseAPI/src/IA_power.h @@ -85,10 +85,10 @@ class IA_power : public IA_IAPI { Dyninst::ParseAPI::Block * curBlk_); IA_power(const IA_power &); virtual IA_power* clone() const; - virtual bool isFrameSetupInsn(Dyninst::InstructionAPI::Instruction::Ptr) const; + virtual bool isFrameSetupInsn(Dyninst::InstructionAPI::Instruction) const; virtual bool isNop() const; virtual bool isThunk() const; - virtual bool isTailCall(ParseAPI::Function* context, ParseAPI::EdgeTypeEnum type, unsigned int, const set
& knownTargets) const; + virtual bool isTailCall(const ParseAPI::Function* context, ParseAPI::EdgeTypeEnum type, unsigned int, const set
& knownTargets) const; virtual bool savesFP() const; virtual bool isStackFramePreamble() const; virtual bool cleansStack() const; diff --git a/parseAPI/src/IA_x86.C b/parseAPI/src/IA_x86.C index 295c8dfab2..503b160dc2 100644 --- a/parseAPI/src/IA_x86.C +++ b/parseAPI/src/IA_x86.C @@ -48,7 +48,7 @@ using namespace Dyninst::InsnAdapter; using namespace Dyninst::ParseAPI; IA_x86::IA_x86(Dyninst::InstructionAPI::InstructionDecoder dec_, - Address start_, + Address start_, Dyninst::ParseAPI::CodeObject* o, Dyninst::ParseAPI::CodeRegion* r, Dyninst::InstructionSource *isrc, @@ -62,27 +62,27 @@ IA_x86* IA_x86::clone() const { return new IA_x86(*this); } -bool IA_x86::isFrameSetupInsn(Instruction::Ptr i) const +bool IA_x86::isFrameSetupInsn(Instruction i) const { - if(i->getOperation().getID() == e_mov) + if(i.getOperation().getID() == e_mov) { - if(i->readsMemory() || i->writesMemory()) + if(i.readsMemory() || i.writesMemory()) { parsing_printf("%s[%d]: discarding insn %s as stack frame preamble, not a reg-reg move\n", - FILE__, __LINE__, i->format().c_str()); + FILE__, __LINE__, i.format().c_str()); //return false; } - if(i->isRead(stackPtr[_isrc->getArch()]) && - i->isWritten(framePtr[_isrc->getArch()])) + if(i.isRead(stackPtr[_isrc->getArch()]) && + i.isWritten(framePtr[_isrc->getArch()])) { - if((unsigned) i->getOperand(0).getValue()->size() == _isrc->getAddressWidth()) + if((unsigned) i.getOperand(0).getValue()->size() == _isrc->getAddressWidth()) { return true; } else { parsing_printf("%s[%d]: discarding insn %s as stack frame preamble, size mismatch for %d-byte addr width\n", - FILE__, __LINE__, i->format().c_str(), _isrc->getAddressWidth()); + FILE__, __LINE__, i.format().c_str(), _isrc->getAddressWidth()); } } } @@ -122,17 +122,17 @@ class nopVisitor : public InstructionAPI::Visitor } }; -bool isNopInsn(Instruction::Ptr insn) +bool isNopInsn(Instruction insn) { // TODO: add LEA no-ops - if(insn->getOperation().getID() == e_nop) + if(insn.getOperation().getID() == e_nop) return true; - if(insn->getOperation().getID() == e_lea) + if(insn.getOperation().getID() == e_lea) { std::set memReadAddr; - insn->getMemoryReadOperands(memReadAddr); + insn.getMemoryReadOperands(memReadAddr); std::set writtenRegs; - insn->getWriteSet(writtenRegs); + insn.getWriteSet(writtenRegs); if(memReadAddr.size() == 1 && writtenRegs.size() == 1) { @@ -145,7 +145,7 @@ bool isNopInsn(Instruction::Ptr insn) nopVisitor visitor; // We need to get the src operand - insn->getOperand(1).getValue()->apply(&visitor); + insn.getOperand(1).getValue()->apply(&visitor); if (visitor.isNop) return true; } return false; @@ -153,10 +153,9 @@ bool isNopInsn(Instruction::Ptr insn) bool IA_x86::isNop() const { - Instruction::Ptr ci = curInsn(); + Instruction ci = curInsn(); + - assert(ci); - return isNopInsn(ci); } @@ -208,18 +207,17 @@ bool IA_x86::isThunk() const { (const unsigned char *)_isrc->getPtrToInstruction(addr); InstructionDecoder targetChecker(target, 2*InstructionDecoder::maxInstructionLength, _isrc->getArch()); - Instruction::Ptr thunkFirst = targetChecker.decode(); - Instruction::Ptr thunkSecond = targetChecker.decode(); - if(thunkFirst && thunkSecond && - (thunkFirst->getOperation().getID() == e_mov) && - (thunkSecond->getCategory() == c_ReturnInsn)) + Instruction thunkFirst = targetChecker.decode(); + Instruction thunkSecond = targetChecker.decode(); + if((thunkFirst.getOperation().getID() == e_mov) && + (thunkSecond.getCategory() == c_ReturnInsn)) { - if(thunkFirst->isRead(stackPtr[_isrc->getArch()])) + if(thunkFirst.isRead(stackPtr[_isrc->getArch()])) { // it is not enough that the stack pointer is read; it must // be a zero-offset read from the stack pointer ThunkVisitor tv; - Operand op = thunkFirst->getOperand(1); + Operand op = thunkFirst.getOperand(1); op.getValue()->apply(&tv); return tv.offset() == 0; @@ -228,7 +226,8 @@ bool IA_x86::isThunk() const { return false; } -bool IA_x86::isTailCall(Function * context, EdgeTypeEnum type, unsigned int, const set
& knownTargets) const +bool IA_x86::isTailCall(const Function *context, EdgeTypeEnum type, unsigned int, + const set
&knownTargets) const { // Collapse down to "branch" or "fallthrough" switch(type) { @@ -262,36 +261,14 @@ bool IA_x86::isTailCall(Function * context, EdgeTypeEnum type, unsigned int, con Function* callee = _obj->findFuncByEntry(_cr, addr); Block* target = _obj->findBlockByEntry(_cr, addr); - // check if addr is in a block if it is not entry. - if (target == NULL) { - std::set blocks; - _obj->findCurrentBlocks(_cr, addr, blocks); - if (blocks.size() == 1) { - target = *blocks.begin(); - } else if (blocks.size() == 0) { - // This case can happen when the jump target is a function entry, - // but we have not parsed the function yet, - // or when this is an indirect jump - target = NULL; - } else { - // If this case happens, it means the jump goes into overlapping instruction streams, - // it is not likely to be a tail call. - parsing_printf("\tjumps into overlapping instruction streams\n"); - for (auto bit = blocks.begin(); bit != blocks.end(); ++bit) { - parsing_printf("\t block [%lx,%lx)\n", (*bit)->start(), (*bit)->end()); - } - parsing_printf("\tjump to 0x%lx, NOT TAIL CALL\n", addr); - tailCalls[type] = false; - return false; - } - } - - if(curInsn()->getCategory() == c_BranchInsn && + if(curInsn().getCategory() == c_BranchInsn && valid && callee && callee != context && - target && - !context->contains(target) + // We can only trust entry points from hints + callee->src() == HINT && + /* the target can either be not parsed or not within the current context */ + ((target == NULL) || (target && !context->contains(target))) ) { parsing_printf("\tjump to 0x%lx, TAIL CALL\n", addr); @@ -299,7 +276,7 @@ bool IA_x86::isTailCall(Function * context, EdgeTypeEnum type, unsigned int, con return true; } - if (curInsn()->getCategory() == c_BranchInsn && + if (curInsn().getCategory() == c_BranchInsn && valid && !callee) { if (target) { @@ -314,7 +291,7 @@ bool IA_x86::isTailCall(Function * context, EdgeTypeEnum type, unsigned int, con } if(allInsns.size() < 2) { - if(context->addr() == _curBlk->start() && curInsn()->getCategory() == c_BranchInsn) + if(context->addr() == _curBlk->start() && curInsn().getCategory() == c_BranchInsn) { parsing_printf("\tjump as only insn in entry block, TAIL CALL\n"); tailCalls[type] = true; @@ -329,7 +306,7 @@ bool IA_x86::isTailCall(Function * context, EdgeTypeEnum type, unsigned int, con } } - if ((curInsn()->getCategory() == c_BranchInsn)) + if ((curInsn().getCategory() == c_BranchInsn)) { //std::map::const_iterator prevIter = //allInsns.find(current); @@ -338,34 +315,36 @@ bool IA_x86::isTailCall(Function * context, EdgeTypeEnum type, unsigned int, con allInsns_t::const_iterator prevIter = curInsnIter; --prevIter; - Instruction::Ptr prevInsn = prevIter->second; + Instruction prevInsn = prevIter->second; while ( isNopInsn(prevInsn) && (prevIter != allInsns.begin()) ) { --prevIter; prevInsn = prevIter->second; } prevInsn = prevIter->second; - if(prevInsn->getOperation().getID() == e_leave) + if(prevInsn.getOperation().getID() == e_leave) { parsing_printf("\tprev insn was leave, TAIL CALL\n"); tailCalls[type] = true; return true; } - else if(prevInsn->getOperation().getID() == e_pop) + else if(prevInsn.getOperation().getID() == e_pop) { - if(prevInsn->isWritten(framePtr[_isrc->getArch()])) + if(prevInsn.isWritten(framePtr[_isrc->getArch()])) { - parsing_printf("\tprev insn was %s, TAIL CALL\n", prevInsn->format().c_str()); + parsing_printf("\tprev insn was %s, TAIL CALL\n", prevInsn.format().c_str()); tailCalls[type] = true; return true; } } - else if(prevInsn->getOperation().getID() == e_add) + else if(prevInsn.getOperation().getID() == e_add) { - if(prevInsn->isWritten(stackPtr[_isrc->getArch()])) + if(prevInsn.isWritten(stackPtr[_isrc->getArch()])) { bool call_fallthrough = false; - if (_curBlk->start() == prevIter->first) { + boost::lock_guard g(*_curBlk); + + if (_curBlk->start() == prevIter->first) { for (auto eit = _curBlk->sources().begin(); eit != _curBlk->sources().end(); ++eit) { if ((*eit)->type() == CALL_FT) { call_fallthrough = true; @@ -374,14 +353,15 @@ bool IA_x86::isTailCall(Function * context, EdgeTypeEnum type, unsigned int, con } } if (call_fallthrough) { - parsing_printf("\tprev insn was %s, but it is the next instruction of a function call, not a tail call %x %x\n", prevInsn->format().c_str()); + parsing_printf("\tprev insn was %s, but it is the next instruction of a function call, not a tail call %x %x\n", + prevInsn.format().c_str()); } else { - parsing_printf("\tprev insn was %s, TAIL CALL\n", prevInsn->format().c_str()); + parsing_printf("\tprev insn was %s, TAIL CALL\n", prevInsn.format().c_str()); tailCalls[type] = true; return true; } } else - parsing_printf("\tprev insn was %s, not tail call\n", prevInsn->format().c_str()); + parsing_printf("\tprev insn was %s, not tail call\n", prevInsn.format().c_str()); } } @@ -392,7 +372,7 @@ bool IA_x86::isTailCall(Function * context, EdgeTypeEnum type, unsigned int, con bool IA_x86::savesFP() const { - std::vector insns; + std::vector insns; insns.push_back(curInsn()); #if defined(os_windows) // Windows functions can start with a noop... @@ -400,10 +380,10 @@ bool IA_x86::savesFP() const insns.push_back(tmp.decode()); #endif for (unsigned i = 0; i < insns.size(); ++i) { - InstructionAPI::Instruction::Ptr ci = insns[i]; - if(ci->getOperation().getID() == e_push) + InstructionAPI::Instruction ci = insns[i]; + if(ci.getOperation().getID() == e_push) { - if (ci->isRead(framePtr[_isrc->getArch()])) { + if (ci.isRead(framePtr[_isrc->getArch()])) { return true; } else return false; @@ -424,7 +404,7 @@ bool IA_x86::isStackFramePreamble() const InstructionDecoder tmp(dec); std::vector nextTwoInsns; for (int i = 0; i < limit; ++i) { - Instruction::Ptr insn = tmp.decode(); + Instruction insn = tmp.decode(); if (isFrameSetupInsn(insn)) { return true; } @@ -434,21 +414,21 @@ bool IA_x86::isStackFramePreamble() const bool IA_x86::cleansStack() const { - Instruction::Ptr ci = curInsn(); - if (ci->getCategory() != c_ReturnInsn) return false; + Instruction ci = curInsn(); + if (ci.getCategory() != c_ReturnInsn) return false; std::vector ops; - ci->getOperands(ops); + ci.getOperands(ops); return (ops.size() > 1); } -bool IA_x86::isReturn(Dyninst::ParseAPI::Function * /*context*/, +bool IA_x86::isReturn(Dyninst::ParseAPI::Function * /*context*/, Dyninst::ParseAPI::Block* /*currBlk*/) const { // For x86, we check if an instruction is return based on the category. // However, for powerpc, the return instruction BLR can be a return or // an indirect jump used for jump tables etc. Hence, we need to function and block // to determine if an instruction is a return. But these parameters are unused for x86. - return curInsn()->getCategory() == c_ReturnInsn; + return curInsn().getCategory() == c_ReturnInsn; } bool IA_x86::isReturnAddrSave(Dyninst::Address&) const @@ -503,12 +483,12 @@ bool IA_x86::isFakeCall() const _cr->length() - entryOff, _cr->getArch() ); IA_x86 *ah = new IA_x86(newdec, entry, _obj, _cr, _isrc, _curBlk); - Instruction::Ptr insn = ah->curInsn(); + Instruction insn = ah->curInsn(); // follow ctrl transfers until you get a block containing non-ctrl // transfer instructions, or hit a return instruction - while (insn->getCategory() == c_CallInsn || - insn->getCategory() == c_BranchInsn) + while (insn.getCategory() == c_CallInsn || + insn.getCategory() == c_BranchInsn) { boost::tie(valid, entry) = ah->getCFT(); if ( !valid || ! _cr->contains(entry) || ! _isrc->isCode(entry) ) { @@ -539,16 +519,16 @@ bool IA_x86::isFakeCall() const while(true) { // exit condition 1 - if (insn->getCategory() == c_CallInsn || - insn->getCategory() == c_ReturnInsn || - insn->getCategory() == c_BranchInsn) + if (insn.getCategory() == c_CallInsn || + insn.getCategory() == c_ReturnInsn || + insn.getCategory() == c_BranchInsn) { break; } // calculate instruction delta - if(insn->isWritten(theStackPtr)) { - entryID what = insn->getOperation().getID(); + if(insn.isWritten(theStackPtr)) { + entryID what = insn.getOperation().getID(); int sign = 1; switch(what) { @@ -556,7 +536,7 @@ bool IA_x86::isFakeCall() const sign = -1; //FALLTHROUGH case e_pop: { - int size = insn->getOperand(0).getValue()->size(); + int size = insn.getOperand(0).getValue()->size(); stackDelta += sign * size; break; } @@ -614,7 +594,7 @@ bool IA_x86::isFakeCall() const sign = -1; //FALLTHROUGH case e_add: { - Operand arg = insn->getOperand(1); + Operand arg = insn.getOperand(1); Result delta = arg.getValue()->eval(); if(delta.defined) { int delta_int = sign; @@ -667,16 +647,16 @@ bool IA_x86::isFakeCall() const // exit condition 2 ah->advance(); - Instruction::Ptr next = ah->curInsn(); - if (NULL == next) { + Instruction next = ah->curInsn(); + if (!next.isValid()) { break; } - curAddr += insn->size(); + curAddr += insn.size(); insn = next; } // not a fake call if it ends w/ a return instruction - if (insn->getCategory() == c_ReturnInsn) { + if (insn.getCategory() == c_ReturnInsn) { delete ah; return false; } @@ -700,12 +680,12 @@ bool IA_x86::isIATcall(std::string &calleeName) const return false; } - if (!curInsn()->readsMemory()) { + if (!curInsn().readsMemory()) { return false; } std::set memReads; - curInsn()->getMemoryReadOperands(memReads); + curInsn().getMemoryReadOperands(memReads); if (memReads.size() != 1) { return false; } @@ -760,7 +740,7 @@ bool IA_x86::isIATcall(std::string &calleeName) const bool IA_x86::isNopJump() const { - InsnCategory cat = curInsn()->getCategory(); + InsnCategory cat = curInsn().getCategory(); if (c_BranchInsn != cat) { return false; } diff --git a/parseAPI/src/IA_x86.h b/parseAPI/src/IA_x86.h index 49938f13fb..a09ce02079 100644 --- a/parseAPI/src/IA_x86.h +++ b/parseAPI/src/IA_x86.h @@ -49,10 +49,11 @@ class IA_x86 : public IA_IAPI { Dyninst::ParseAPI::Block * curBlk_); IA_x86(const IA_x86 &); virtual IA_x86* clone() const; - virtual bool isFrameSetupInsn(Dyninst::InstructionAPI::Instruction::Ptr) const; + virtual bool isFrameSetupInsn(Dyninst::InstructionAPI::Instruction) const; virtual bool isNop() const; virtual bool isThunk() const; - virtual bool isTailCall(ParseAPI::Function* context, ParseAPI::EdgeTypeEnum type, unsigned int, const set
& knownTargets) const; + virtual bool isTailCall(const ParseAPI::Function* context, ParseAPI::EdgeTypeEnum type, unsigned int, + const set
& knownTargets) const; virtual bool savesFP() const; virtual bool isStackFramePreamble() const; virtual bool cleansStack() const; diff --git a/parseAPI/src/IndirectASTVisitor.C b/parseAPI/src/IndirectASTVisitor.C index 4eeec9bc9b..ca7fd8062d 100644 --- a/parseAPI/src/IndirectASTVisitor.C +++ b/parseAPI/src/IndirectASTVisitor.C @@ -3,14 +3,13 @@ #include "debug_parse.h" #include "CodeObject.h" #include -#include "SymbolicExpression.h" using namespace Dyninst::ParseAPI; AST::Ptr SimplifyVisitor::visit(DataflowAPI::RoseAST *ast) { unsigned totalChildren = ast->numChildren(); for (unsigned i = 0 ; i < totalChildren; ++i) { ast->child(i)->accept(this); - ast->setChild(i, SymbolicExpression::SimplifyRoot(ast->child(i), addr, keepMultiOne)); + ast->setChild(i, se.SimplifyRoot(ast->child(i), addr, keepMultiOne)); } return AST::Ptr(); } @@ -360,10 +359,11 @@ bool JumpTableFormatVisitor::PotentialIndexing(AST::Ptr ast) { return false; } -JumpTableReadVisitor::JumpTableReadVisitor(AbsRegion i, int v, CodeSource *c, bool ze, int m) { +JumpTableReadVisitor::JumpTableReadVisitor(AbsRegion i, int v, CodeSource *c, CodeRegion *r, bool ze, int m) { index = i; indexValue = v; cs = c; + cr = r; isZeroExtend = ze; valid = true; memoryReadSize = m; diff --git a/parseAPI/src/IndirectASTVisitor.h b/parseAPI/src/IndirectASTVisitor.h index 71f1271861..3d88fd9114 100644 --- a/parseAPI/src/IndirectASTVisitor.h +++ b/parseAPI/src/IndirectASTVisitor.h @@ -7,6 +7,7 @@ #include "SymEval.h" #include "CodeSource.h" #include "BoundFactData.h" +#include "SymbolicExpression.h" using namespace std; using namespace Dyninst; @@ -25,10 +26,11 @@ using namespace Dyninst::DataflowAPI; class SimplifyVisitor: public ASTVisitor { Address addr; bool keepMultiOne; + SymbolicExpression &se; public: using ASTVisitor::visit; virtual ASTPtr visit(DataflowAPI::RoseAST *ast); - SimplifyVisitor(Address a, bool k): addr(a), keepMultiOne(k) {} + SimplifyVisitor(Address a, bool k, SymbolicExpression &sym): addr(a), keepMultiOne(k), se(sym) {} }; @@ -97,6 +99,7 @@ class JumpTableReadVisitor: public ASTVisitor { AbsRegion index; int64_t indexValue; CodeSource* cs; + CodeRegion* cr; Address targetAddress; int memoryReadSize; bool valid; @@ -105,7 +108,7 @@ class JumpTableReadVisitor: public ASTVisitor { // This tracks the results of computation for each sub AST map results; - JumpTableReadVisitor(AbsRegion i, int v, CodeSource *c, bool ze, int m); + JumpTableReadVisitor(AbsRegion i, int v, CodeSource *c, CodeRegion *r, bool ze, int m); virtual ASTPtr visit(DataflowAPI::RoseAST *ast); virtual ASTPtr visit(DataflowAPI::ConstantAST *ast); virtual ASTPtr visit(DataflowAPI::VariableAST *ast); diff --git a/parseAPI/src/IndirectAnalyzer.C b/parseAPI/src/IndirectAnalyzer.C index a3697c4fa3..bb4de2fe1a 100644 --- a/parseAPI/src/IndirectAnalyzer.C +++ b/parseAPI/src/IndirectAnalyzer.C @@ -60,7 +60,7 @@ static bool IsVariableArgumentFormat(AST::Ptr t, AbsRegion &index) { bool IndirectControlFlowAnalyzer::NewJumpTableAnalysis(std::vector >& outEdges) { parsing_printf("Apply indirect control flow analysis at %lx\n", block->last()); parsing_printf("Looking for thunk\n"); - +boost::make_lock_guard(*func); // Find all blocks that reach the block containing the indirect jump // This is a prerequisit for finding thunks GetAllReachableBlock(); @@ -73,9 +73,9 @@ bool IndirectControlFlowAnalyzer::NewJumpTableAnalysis(std::vectorobj()->cs()->getPtrToInstruction(block->last()); + const unsigned char * buf = (const unsigned char*) block->region()->getPtrToInstruction(block->last()); InstructionDecoder dec(buf, InstructionDecoder::maxInstructionLength, block->obj()->cs()->getArch()); - Instruction::Ptr insn = dec.decode(); + Instruction insn = dec.decode(); AssignmentConverter ac(true, false); vector assignments; ac.convert(insn, block->last(), func, block, assignments); @@ -83,16 +83,23 @@ bool IndirectControlFlowAnalyzer::NewJumpTableAnalysis(std::vectorobj()->cs(); + se.cr = block->region(); JumpTableFormatPred jtfp(func, block, rf, thunks, se); GraphPtr slice = formatSlicer.backwardSlice(jtfp); //parsing_printf("\tJump table format: %s\n", jtfp.format().c_str()); // If the jump target expression is not in a form we recognize, // we do not try to resolve it - parsing_printf("In function %s, Address %lx, jump target format %s, index loc %s, index variable %s", func->name().c_str(), block->last(), jtfp.format().c_str(), jtfp.indexLoc ? jtfp.indexLoc->format().c_str() : "" , jtfp.index.format().c_str() ); + parsing_printf("In function %s, Address %lx, jump target format %s, index loc %s, index variable %s, memory read loc %s, isJumpTableFormat %d\n", + func->name().c_str(), + block->last(), + jtfp.format().c_str(), + jtfp.indexLoc ? jtfp.indexLoc->format().c_str() : "null" , + jtfp.index.format().c_str(), + jtfp.memLoc ? jtfp.memLoc->format().c_str() : "null", + jtfp.isJumpTableFormat()); bool variableArguFormat = false; if (!jtfp.isJumpTableFormat()) { - parsing_printf(" not jump table\n"); if (jtfp.jumpTargetExpr && func->entry() == block && IsVariableArgumentFormat(jtfp.jumpTargetExpr, jtfp.index)) { parsing_printf("\tVariable number of arguments format, index %s\n", jtfp.index.format().c_str()); variableArguFormat = true; @@ -102,16 +109,17 @@ bool IndirectControlFlowAnalyzer::NewJumpTableAnalysis(std::vectorblock(), func, false, false); + Slicer indexSlicer(jtfp.indexLoc, jtfp.indexLoc->block(), func, false, false); JumpTableIndexPred jtip(func, block, jtfp.index, se); jtip.setSearchForControlFlowDep(true); slice = indexSlicer.backwardSlice(jtip); - + if (!jtip.findBound && block->obj()->cs()->getArch() != Arch_aarch64) { - // After the slicing is done, we do one last check to - // see if we can resolve the indirect jump by assuming + // After the slicing is done, we do one last check to + // see if we can resolve the indirect jump by assuming // one byte read is in bound [0,255] GraphPtr g = jtip.BuildAnalysisGraph(indexSlicer.visitedEdges); BoundFactsCalculator bfc(func, g, func->entry() == block, true, se); @@ -121,23 +129,26 @@ bool IndirectControlFlowAnalyzer::NewJumpTableAnalysis(std::vectorlast()); b = jtip.bound; } else { - parsing_printf(" Cannot find bound, assume there are at most 256 entries and scan the table\n"); + parsing_printf(" Cannot find bound, assume there are at most 256 entries and scan the table for indirect jump at %lx\n", block->last()); b = StridedInterval(1, 0, 255); + scanTable = true; } } else { b = StridedInterval(1, 0, 8); } std::vector > jumpTableOutEdges; - ReadTable(jtfp.jumpTargetExpr, - jtfp.index, - b, - GetMemoryReadSize(jtfp.memLoc), + ReadTable(jtfp.jumpTargetExpr, + jtfp.index, + b, + GetMemoryReadSize(jtfp.memLoc), + IsZeroExtend(jtfp.memLoc), + scanTable, jtfp.constAddr, jumpTableOutEdges); - parsing_printf(", find %d edges\n", jumpTableOutEdges.size()); + parsing_printf(", find %d edges\n", jumpTableOutEdges.size()); outEdges.insert(outEdges.end(), jumpTableOutEdges.begin(), jumpTableOutEdges.end()); return !jumpTableOutEdges.empty(); } @@ -155,6 +166,7 @@ void IndirectControlFlowAnalyzer::GetAllReachableBlock() { q.pop(); if (reachable.find(cur) != reachable.end()) continue; reachable.insert(cur); + boost::lock_guard g(*cur); for (auto eit = cur->sources().begin(); eit != cur->sources().end(); ++eit) if ((*eit)->intraproc()) { if ((*eit)->src() == NULL) { @@ -172,13 +184,13 @@ static Address ThunkAdjustment(Address afterThunk, MachRegister reg, ParseAPI::B // an add insturction like ADD ebx, OFFSET to adjust // the value coming out of thunk. - const unsigned char* buf = (const unsigned char*) (b->obj()->cs()->getPtrToInstruction(afterThunk)); + const unsigned char* buf = (const unsigned char*) (b->region()->getPtrToInstruction(afterThunk)); InstructionDecoder dec(buf, b->end() - b->start(), b->obj()->cs()->getArch()); - Instruction::Ptr nextInsn = dec.decode(); + Instruction nextInsn = dec.decode(); // It has to be an add - if (nextInsn->getOperation().getID() != e_add) return 0; + if (nextInsn.getOperation().getID() != e_add) return 0; vector operands; - nextInsn->getOperands(operands); + nextInsn.getOperands(operands); RegisterAST::Ptr regAST = boost::dynamic_pointer_cast(operands[0].getValue()); // The first operand should be a register if (regAST == 0) return 0; @@ -197,7 +209,7 @@ void IndirectControlFlowAnalyzer::FindAllThunks() { // end a basic block. So, we need to check every instruction to find all thunks ParseAPI::Block *b = *bit; const unsigned char* buf = - (const unsigned char*)(b->obj()->cs()->getPtrToInstruction(b->start())); + (const unsigned char*)(b->region()->getPtrToInstruction(b->start())); if( buf == NULL ) { parsing_printf("%s[%d]: failed to get pointer to instruction by offset\n",FILE__, __LINE__); return; @@ -206,76 +218,77 @@ void IndirectControlFlowAnalyzer::FindAllThunks() { InsnAdapter::IA_IAPI* block = InsnAdapter::IA_IAPI::makePlatformIA_IAPI(b->obj()->cs()->getArch(), dec, b->start(), b->obj() , b->region(), b->obj()->cs(), b); Address cur = b->start(); while (cur < b->end()) { - if (block->getInstruction()->getCategory() == c_CallInsn && block->isThunk()) { + if (block->getInstruction().getCategory() == c_CallInsn && block->isThunk()) { bool valid; Address addr; boost::tie(valid, addr) = block->getCFT(); - const unsigned char *target = (const unsigned char *) b->obj()->cs()->getPtrToInstruction(addr); + const unsigned char *target = (const unsigned char *) b->region()->getPtrToInstruction(addr); InstructionDecoder targetChecker(target, InstructionDecoder::maxInstructionLength, b->obj()->cs()->getArch()); - Instruction::Ptr thunkFirst = targetChecker.decode(); + Instruction thunkFirst = targetChecker.decode(); set thunkTargetRegs; - thunkFirst->getWriteSet(thunkTargetRegs); + thunkFirst.getWriteSet(thunkTargetRegs); for (auto curReg = thunkTargetRegs.begin(); curReg != thunkTargetRegs.end(); ++curReg) { ThunkInfo t; t.reg = (*curReg)->getID(); - t.value = block->getAddr() + block->getInstruction()->size(); + t.value = block->getAddr() + block->getInstruction().size(); t.value += ThunkAdjustment(t.value, t.reg, b); t.block = b; thunks.insert(make_pair(block->getAddr(), t)); parsing_printf("\tfind thunk at %lx, storing value %lx to %s\n", block->getAddr(), t.value , t.reg.name().c_str()); } } - cur += block->getInstruction()->size(); + cur += block->getInstruction().size(); if (cur < b->end()) block->advance(); } delete block; } } -void IndirectControlFlowAnalyzer::ReadTable(AST::Ptr jumpTargetExpr, +void IndirectControlFlowAnalyzer::ReadTable(AST::Ptr jumpTargetExpr, AbsRegion index, - StridedInterval &indexBound, + StridedInterval &indexBound, int memoryReadSize, + bool isZeroExtend, + bool scanTable, set
&constAddr, std::vector > &targetEdges) { - CodeSource *cs = block->obj()->cs(); + CodeSource *cs = block->obj()->cs(); set
jumpTargets; for (int v = indexBound.low; v <= indexBound.high; v += indexBound.stride) { - // TODO: need to detect whether the memory is a zero extend or a sign extend - JumpTableReadVisitor jtrv(index, v, cs, false, memoryReadSize); + JumpTableReadVisitor jtrv(index, v, cs, block->region(), isZeroExtend, memoryReadSize); jumpTargetExpr->accept(&jtrv); if (jtrv.valid && cs->isCode(jtrv.targetAddress)) { bool stop = false; - set blocks; - block->obj()->findCurrentBlocks(block->region(), jtrv.targetAddress, blocks); - for (auto bit = blocks.begin(); bit != blocks.end(); ++bit) { - if ((*bit)->start() < jtrv.targetAddress && jtrv.targetAddress <= (*bit)->end()) { - Block::Insns insns; - (*bit)->getInsns(insns); - if (insns.find(jtrv.targetAddress) == insns.end()) { - stop = true; - parsing_printf("WARNING: resolving jump tables leads to address %lx, which causes overlapping instructions in basic blocks [%lx,%lx)\n", jtrv.targetAddress, (*bit)->start(), (*bit)->end()); - break; - } - } - } // Assume that indirect jump should not jump beyond the function range. // This assumption is shaky in terms of non-contiguous functions. // But non-contiguous blocks tend not be reach by indirect jumps if (func->src() == HINT) { - Hint h(func->addr(), 0 , NULL, ""); - auto range = equal_range(cs->hints().begin(), cs->hints().end(), h); - if (range.first != range.second && range.first != cs->hints().end()) { - Address startAddr = range.first->_addr; - int size = range.first->_size; + Hint h(block->last(), 0 , NULL, ""); + auto iter = upper_bound(cs->hints().begin(), cs->hints().end(), h); + if (iter != cs->hints().begin()) { + iter--; + Address startAddr = iter->_addr; + int size = iter->_size; if (jtrv.targetAddress < startAddr || jtrv.targetAddress >= startAddr + size) { stop = true; - parsing_printf("WARNING: resolving jump tables leads to address %lx, which is not in the function range specified in the symbol table\n", jtrv.targetAddress); + parsing_printf("WARNING: resolving jump tables leads to address %lx, which is not in the function range specified in the symbol table\n", jtrv.targetAddress); parsing_printf("\tSymbol at %lx, end at %lx\n", startAddr, startAddr + size); } } } + if (scanTable && jumpTargets.size() > 0 && cs->getArch() != Arch_ppc64) { + // This is a tentative scan of the table, where we do not know the index size. + // Typically, the table is layout in a way that the target address is increasing + // or decreasing. + auto smallIt = jumpTargets.begin(); + auto largeIt = jumpTargets.end(); + --largeIt; + if (jtrv.targetAddress < *largeIt && jtrv.targetAddress > *smallIt) { + stop = true; + parsing_printf("WARNING: we do not know the index size and we are scanning the table. We stop now because the jump target seems to not increasing or decreasing\n"); + } + } if (stop) break; jumpTargets.insert(jtrv.targetAddress); } else { @@ -287,20 +300,24 @@ void IndirectControlFlowAnalyzer::ReadTable(AST::Ptr jumpTargetExpr, if (indexBound.stride == 0) break; } for (auto ait = constAddr.begin(); ait != constAddr.end(); ++ait) { - if (cs->isCode(*ait)) { + if (block->region()->isCode(*ait)) { jumpTargets.insert(*ait); } } for (auto tit = jumpTargets.begin(); tit != jumpTargets.end(); ++tit) { targetEdges.push_back(make_pair(*tit, INDIRECT)); } -} +} int IndirectControlFlowAnalyzer::GetMemoryReadSize(Assignment::Ptr memLoc) { - if (!memLoc) return 0; - Instruction::Ptr i = memLoc->insn(); + if (!memLoc) { + parsing_printf("\tmemLoc is null\n"); + return 0; + } + Instruction i = memLoc->insn(); std::vector ops; - i->getOperands(ops); + i.getOperands(ops); + parsing_printf("\t there are %d operands\n", ops.size()); for (auto oit = ops.begin(); oit != ops.end(); ++oit) { Operand o = *oit; if (o.readsMemory()) { @@ -310,3 +327,14 @@ int IndirectControlFlowAnalyzer::GetMemoryReadSize(Assignment::Ptr memLoc) { } return 0; } + +bool IndirectControlFlowAnalyzer::IsZeroExtend(Assignment::Ptr memLoc) { + if (!memLoc) { + parsing_printf("\tmemLoc is null\n"); + return false; + } + Instruction i = memLoc->insn(); + parsing_printf("check zero extend %s\n", i.format().c_str()); + if (i.format().find("movz") != string::npos) return true; + return false; +} diff --git a/parseAPI/src/IndirectAnalyzer.h b/parseAPI/src/IndirectAnalyzer.h index d2a6c7feb0..fa4d2d65d7 100644 --- a/parseAPI/src/IndirectAnalyzer.h +++ b/parseAPI/src/IndirectAnalyzer.h @@ -17,13 +17,16 @@ class IndirectControlFlowAnalyzer { void GetAllReachableBlock(); void FindAllThunks(); - void ReadTable(AST::Ptr, - AbsRegion, - StridedInterval &, + void ReadTable(AST::Ptr, + AbsRegion, + StridedInterval &, int , - std::set
&, + bool, + bool, + std::set
&, std::vector > &); int GetMemoryReadSize(Assignment::Ptr loc); + bool IsZeroExtend(Assignment::Ptr loc); public: diff --git a/parseAPI/src/JumpTableFormatPred.C b/parseAPI/src/JumpTableFormatPred.C index b6dd0ca7ad..dfb996ebdd 100644 --- a/parseAPI/src/JumpTableFormatPred.C +++ b/parseAPI/src/JumpTableFormatPred.C @@ -21,39 +21,56 @@ JumpTableFormatPred::JumpTableFormatPred(ParseAPI::Function *f, findIndex = false; findTableBase = false; firstMemoryRead = true; + toc_address = 0; if (b->obj()->cs()->getArch() == Arch_ppc64) { FindTOC(); } } +static bool ComputeTOC(Address &ret, Address entry, Block* b) { + if (!b->region()->isCode(entry)) return false; + const uint32_t * buf = (const uint32_t*) b->region()->getPtrToInstruction(entry); + if (buf == NULL) return false; + + uint32_t i1 = buf[0]; + uint32_t i2 = buf[1]; + + uint32_t p1 = i1 >> 16; + uint32_t p2 = i2 >> 16; + + // lis and addis treat imm unsigned + Address a1 = i1 & 0xffff; + // addi treats imm signed + Address a2 = i2 & 0xffff; + if (a2 & 0x8000) a2 = a2 | SIGNEX_64_16; + + // Check for two types of preamble + // Preamble 1: used in executables + // lis r2, IMM bytes: IMM1 IMM2 40 3c + // addi r2, r2, IMM bytes: IMM1 IMM2 42 38 + if (p1 == 0x3c40 && p2 == 0x3842) { + ret = (a1 << 16) + a2; + return true; + } + + // Preamble 2: used in libraries + // addis r2, r12, IMM bytes: IMM1 IMM2 4c 3c + // addi r2, r2,IMM bytes: IMM1 IMM2 42 38 + if (p1 == 0x3c4c && p2 == 0x3842) { + ret = entry + (a1 << 16) + a2; + return true; + } + return false; +} + void JumpTableFormatPred::FindTOC() { - toc_address = block->obj()->cs()->getTOC(func->addr()); - if (!toc_address) { // Little endian powerpc changes its ABI, which does not have .opd section, but often load R2 at function entry - Address entry = 0; - if (func->src() == HINT) { - entry = func->addr(); - } else if (func->src() == RT) { - entry = func->addr() - 8; - } else { - parsing_printf("\tUnhandled type of function for getting TOC address\n"); - return; - } - const uint32_t * buf = (const uint32_t*) block->obj()->cs()->getPtrToInstruction(entry); - if (buf == NULL) return; - if ((buf[0] >> 16) != 0x3c40 || (buf[1] >> 16) != 0x3842) return; - if (buf[0] & 0x8000) { - toc_address = (buf[0] & 0xffff) | SIGNEX_64_16; - } else { - toc_address = buf[0] & 0xffff; - } - if (buf[1] & 0x8000) { - toc_address = (toc_address << 16) + ((buf[1] & 0xffff) | SIGNEX_64_16); - } else { - toc_address = (toc_address << 16) + (buf[1] & 0xffff); - } + if (ComputeTOC(toc_address, func->addr(), block) || + ComputeTOC(toc_address, func->addr() - 8, block)) { + parsing_printf("\t find TOC address %lx in R2\n", toc_address); + return; } - parsing_printf("\t TOC address %lx in R2\n", toc_address); + parsing_printf("\tDid not find TOC for function at %lx\n", func->addr()); } static int CountInDegree(SliceNode::Ptr n) { @@ -167,7 +184,8 @@ bool JumpTableFormatPred::modifyCurrentFrame(Slicer::SliceFrame &frame, Graph::P */ pair expandRet = se.ExpandAssignment(n->assign(), true); if (!expandRet.second || expandRet.first == NULL) { - parsing_printf("\tWARNING: Jump table format slice contains unknown instructions: %s\n", n->assign()->insn()->format().c_str()); + parsing_printf("\tWARNING: Jump table format slice contains unknown instructions: %s\n", + n->assign()->insn().format().c_str()); unknownInstruction = true; jumpTableFormat = false; return false; @@ -184,6 +202,7 @@ bool JumpTableFormatPred::modifyCurrentFrame(Slicer::SliceFrame &frame, Graph::P // We start plug in ASTs from predecessors n->ins(nbegin, nend); map inputs; + map input_addr; if (block->obj()->cs()->getArch() == Arch_ppc64) { inputs.insert(make_pair(VariableAST::create(Variable(AbsRegion(Absloc(ppc64::r2)))), ConstantAST::create(Constant(toc_address, 64)))); @@ -194,8 +213,10 @@ bool JumpTableFormatPred::modifyCurrentFrame(Slicer::SliceFrame &frame, Graph::P exp = SymbolicExpression::SubstituteAnAST(exp, inputs); inputs.clear(); } + parsing_printf("JumpTableFormatPred: analyze %s at %lx\n", n->assign()->format().c_str(), n->assign()->addr()); for (; nbegin != nend; ++nbegin) { SliceNode::Ptr p = boost::static_pointer_cast(*nbegin); + if (exprs.find(p->assign()) == exprs.end()) { parsing_printf("\tWARNING: For %s, its predecessor %s does not have an expression\n", n->assign()->format().c_str(), p->assign()->format().c_str()); jumpTableFormat = false; @@ -203,9 +224,27 @@ bool JumpTableFormatPred::modifyCurrentFrame(Slicer::SliceFrame &frame, Graph::P } AST::Ptr rhs = exprs[p->assign()]; AST::Ptr lhs = VariableAST::create(Variable(p->assign()->out())); - // TODO: there may be more than one expression for a single variable - inputs.insert(make_pair(lhs, rhs)); + bool find = false; + for (auto iit = inputs.begin(); iit != inputs.end(); ++iit) + if (*(iit->first) == *lhs) { + find = true; + if (p->assign()->addr() < input_addr[iit->first]) { + inputs[iit->first] = rhs; + input_addr[iit->first] = p->assign()->addr(); + } + break; + } + if (!find) { + inputs[lhs] = rhs; + input_addr[lhs] = p->assign()->addr(); + } + parsing_printf("\t\t pred %s at %lx, lhs %s, rhs %s\n", p->assign()->format().c_str(), p->assign()->addr(), lhs->format().c_str(), rhs->format().c_str()); + } + parsing_printf("Input map:\n"); + for (auto iit = inputs.begin(); iit != inputs.end(); ++iit) { + parsing_printf("\t %s %s\n", iit->first->format().c_str(), iit->second->format().c_str()); + } if (g->isExitNode(n)) { // Here we try to detect the case where there are multiple // paths to the indirect jump, and on some of the paths, the jump @@ -247,6 +286,8 @@ bool JumpTableFormatPred::modifyCurrentFrame(Slicer::SliceFrame &frame, Graph::P // TODO: need to consider thunk exp = SymbolicExpression::SubstituteAnAST(exp, inputs); exprs[n->assign()] = exp; + parsing_printf("\t expression %s\n", exp->format().c_str()); + // Enumerate every successor and add them to the working list n->outs(nbegin, nend); for (; nbegin != nend; ++nbegin) { @@ -266,7 +307,7 @@ bool JumpTableFormatPred::modifyCurrentFrame(Slicer::SliceFrame &frame, Graph::P } JumpTableFormatVisitor jtfv(block); assert(jumpTarget); - jumpTarget = SymbolicExpression::SimplifyAnAST(jumpTarget, 0, true); + jumpTarget = se.SimplifyAnAST(jumpTarget, 0, true); parsing_printf("Check expression %s\n", jumpTarget->format().c_str()); jumpTarget->accept(&jtfv); if (jtfv.findIncorrectFormat) { @@ -316,7 +357,7 @@ bool JumpTableFormatPred::findRead(Graph::Ptr g, SliceNode::Ptr &readNode) { if (n->assign() == memLoc) { continue; } - if (n->assign() && n->assign()->insn() && n->assign()->insn()->readsMemory()) { + if (n->assign() && n->assign()->insn().isValid() && n->assign()->insn().readsMemory()) { readNode = n; return true; } @@ -333,7 +374,7 @@ static Assignment::Ptr SearchForWrite(SliceNode::Ptr n, AbsRegion &src, Slicer:: inQueue.insert(n->block()); set memReads; - n->assign()->insn()->getMemoryReadOperands(memReads); + n->assign()->insn().getMemoryReadOperands(memReads); if (memReads.size() != 1) { parsing_printf("\tThe instruction has %d memory read operands, Should have only one\n", memReads.size()); return Assignment::Ptr(); @@ -341,7 +382,7 @@ static Assignment::Ptr SearchForWrite(SliceNode::Ptr n, AbsRegion &src, Slicer:: Expression::Ptr memRead = *memReads.begin(); parsing_printf("\tsearch for memory operand %s\n", memRead->format().c_str()); Block* targetBlock = NULL; - Instruction::Ptr targetInsn; + Instruction targetInsn; Address targetAddr; while (!workingList.empty() && targetBlock == NULL) { @@ -359,14 +400,14 @@ static Assignment::Ptr SearchForWrite(SliceNode::Ptr n, AbsRegion &src, Slicer:: for (auto iit = insns.rbegin(); iit != insns.rend(); ++iit) { if (addr > 0 && iit->first > addr) continue; - Instruction::Ptr i = iit->second; + Instruction i = iit->second; // We find an the first instruction that only writes to memory // and the memory operand has the exact AST as the memory read. // Ideally, we need an architecture independent way to check whether this is a move instruction. // Category c_NoCategory excludes lots of non-move instructions - if (!i->readsMemory() && i->writesMemory() && i->getCategory() == c_NoCategory) { + if (!i.readsMemory() && i.writesMemory() && i.getCategory() == c_NoCategory) { set memWrites; - i->getMemoryWriteOperands(memWrites); + i.getMemoryWriteOperands(memWrites); if (memWrites.size() == 1 && *memRead == *(*memWrites.begin())) { targetBlock = curBlock; targetInsn = i; @@ -375,7 +416,7 @@ static Assignment::Ptr SearchForWrite(SliceNode::Ptr n, AbsRegion &src, Slicer:: // Now we try to identify the source register std::vector ops; - i->getOperands(ops); + i.getOperands(ops); for (auto oit = ops.begin(); oit != ops.end(); ++oit) { if (!(*oit).writesMemory() && !(*oit).readsMemory()) { std::set regsRead; @@ -396,8 +437,9 @@ static Assignment::Ptr SearchForWrite(SliceNode::Ptr n, AbsRegion &src, Slicer:: } } } - - for (auto eit = curBlock->sources().begin(); eit != curBlock->sources().end(); ++eit) { + Block::edgelist sources; + curBlock->copy_sources(sources); + for (auto eit = sources.begin(); eit != sources.end(); ++eit) { ParseAPI::Edge *e = *eit; if (e->interproc()) continue; if (e->type() == CATCH) continue; diff --git a/parseAPI/src/JumpTableFormatPred.h b/parseAPI/src/JumpTableFormatPred.h index f1aec908f9..8046dc0d1b 100644 --- a/parseAPI/src/JumpTableFormatPred.h +++ b/parseAPI/src/JumpTableFormatPred.h @@ -37,7 +37,7 @@ class JumpTableFormatPred : public Slicer::Predicates { virtual bool modifyCurrentFrame(Slicer::SliceFrame &frame, Graph::Ptr g, Slicer*); std::string format(); - bool isJumpTableFormat() { return jumpTableFormat && findIndex && findTableBase;} + bool isJumpTableFormat() { return jumpTableFormat && findIndex && findTableBase && memLoc;} bool findRead(Graph::Ptr g, SliceNode::Ptr &); bool adjustSliceFrame(Slicer::SliceFrame &frame, SliceNode::Ptr, Slicer*); bool isTOCRead(Slicer::SliceFrame &frame, SliceNode::Ptr); diff --git a/parseAPI/src/JumpTableIndexPred.C b/parseAPI/src/JumpTableIndexPred.C index f4c5b28d55..f3e6a6a4f7 100644 --- a/parseAPI/src/JumpTableIndexPred.C +++ b/parseAPI/src/JumpTableIndexPred.C @@ -56,14 +56,20 @@ static void BuildEdgesAux(SliceNode::Ptr srcNode, if (visit.find(curBlock) != visit.end()) return; visit.insert(curBlock); - for (auto eit = curBlock->targets().begin(); eit != curBlock->targets().end(); ++eit) { + Block::edgelist targets; + curBlock->copy_targets(targets); + for (auto eit = targets.begin(); eit != targets.end(); ++eit) { // Xiaozhu: // Our current slicing code ignores tail calls // (the slice code only checks if an edge type is CALL or not) // so, I should be consistent here. // If the slice code considers tail calls, need to change // the predicate to (*eit)->interproc() - if ((*eit)->type() != CALL && (*eit)->type() != RET && allowedEdges.find(*eit) != allowedEdges.end()) { + if ((*eit)->type() != CALL && + (*eit)->type() != RET && + (*eit)->type() != CATCH && + !(*eit)->interproc() && + allowedEdges.find(*eit) != allowedEdges.end()) { EdgeTypeEnum newT = t; if (t == _edgetype_end_) { if ((*eit)->type() == COND_TAKEN || (*eit)->type() == COND_NOT_TAKEN) @@ -91,7 +97,7 @@ static bool AssignIsZF(Assignment::Ptr a) { } static bool IsPushAndChangeSP(Assignment::Ptr a) { - entryID id = a->insn()->getOperation().getID(); + entryID id = a->insn().getOperation().getID(); if (id != e_push) return false; Absloc aloc = a->out().absloc(); if (aloc.type() == Absloc::Register && aloc.reg().isStackPointer()) return true; @@ -120,7 +126,7 @@ GraphPtr JumpTableIndexPred::BuildAnalysisGraph(set &visitedEdg set
xchgCount; set xchgAssign; for (auto ait = currentAssigns.begin(); ait != currentAssigns.end(); ++ait) { - if ((*ait)->insn()->getOperation().getID() == e_xchg) { + if ((*ait)->insn().getOperation().getID() == e_xchg) { if (xchgCount.find( (*ait)->addr() ) != xchgCount.end() ) continue; xchgCount.insert((*ait)->addr()); xchgAssign.insert(*ait); @@ -132,8 +138,8 @@ GraphPtr JumpTableIndexPred::BuildAnalysisGraph(set &visitedEdg Assignment::Ptr a = *ait; if ( (AssignIsZF(a) || shouldSkip.find(a->addr()) == shouldSkip.end()) && !IsPushAndChangeSP(a) - && (!a->insn()->writesMemory() || MatchReadAST(a))) { - if (a->insn()->getOperation().getID() == e_xchg && xchgAssign.find(a) == xchgAssign.end()) continue; + && (!a->insn().writesMemory() || MatchReadAST(a))) { + if (a->insn().getOperation().getID() == e_xchg && xchgAssign.find(a) == xchgAssign.end()) continue; SliceNode::Ptr newNode = SliceNode::create(a, a->block(), a->func()); targetMap[a->block()][a] = newNode; newG->addNode(newNode); @@ -182,9 +188,9 @@ bool JumpTableIndexPred::addNodeCallback(AssignmentPtr ap, set currentAssigns.insert(ap); - parsing_printf("Adding assignment %s in instruction %s at %lx, total %d\n", ap->format().c_str(), ap->insn()->format().c_str(), ap->addr(), currentAssigns.size()); + parsing_printf("Adding assignment %s in instruction %s at %lx, total %d\n", ap->format().c_str(), ap->insn().format().c_str(), ap->addr(), currentAssigns.size()); /* - if (ap->insn() && ap->insn()->readsMemory() && firstMemoryRead) { + if (ap->insn() && ap->insn().readsMemory() && firstMemoryRead) { firstMemoryRead = false; parsing_printf("\tThe first memory read, check if format is correct\n"); if @@ -202,7 +208,7 @@ bool JumpTableIndexPred::addNodeCallback(AssignmentPtr ap, set // we only want to analyze it when it writes to // an AST we have seen before and potentially // can used for aliasing - if (ap->insn()->writesMemory()) { + if (ap->insn().writesMemory()) { if (!MatchReadAST(ap)) return true; } @@ -210,7 +216,7 @@ bool JumpTableIndexPred::addNodeCallback(AssignmentPtr ap, set // we record the AST of the read so // that in the future we can match a // corresponding write to identify aliasing - if (ap->insn()->readsMemory() && expandRet.first->getID() == AST::V_RoseAST) { + if (ap->insn().readsMemory() && expandRet.first->getID() == AST::V_RoseAST) { RoseAST::Ptr roseAST = boost::static_pointer_cast(expandRet.first); if (roseAST->val().op == ROSEOperation::derefOp) { readAST.push_back(expandRet.first); @@ -286,9 +292,9 @@ bool JumpTableIndexPred::MatchReadAST(Assignment::Ptr a) { pair expandRet = se.ExpandAssignment(a); if (!expandRet.second || expandRet.first == NULL) return false; if (a->out().generator() == NULL) return false; - AST::Ptr write = SymbolicExpression::SimplifyAnAST(RoseAST::create(ROSEOperation(ROSEOperation::derefOp, a->out().size()), a->out().generator()), + AST::Ptr write = se.SimplifyAnAST(RoseAST::create(ROSEOperation(ROSEOperation::derefOp, a->out().size()), a->out().generator()), SymbolicExpression::PCValue(a->addr(), - a->insn()->size(), + a->insn().size(), a->block()->obj()->cs()->getArch())); if (write == NULL) return false; diff --git a/parseAPI/src/ParseCallback.C b/parseAPI/src/ParseCallback.C index 760a017558..77007a358d 100644 --- a/parseAPI/src/ParseCallback.C +++ b/parseAPI/src/ParseCallback.C @@ -99,7 +99,7 @@ void ParseCallbackManager::batch_end(CFGFactory *fact) { // now that we're done with callbacks, delete dangling objects for (std::vector::iterator iter = destroyedEdges_.begin(); iter != destroyedEdges_.end(); ++iter) { - fact->destroy_edge(*iter); + fact->destroy_edge(*iter, destroyed_cb); } destroyedEdges_.clear(); for (std::vector::iterator iter = destroyedBlocks_.begin(); @@ -127,7 +127,7 @@ void ParseCallbackManager::destroy(Edge *e, CFGFactory *fact) { if (inBatch_) destroyedEdges_.push_back(e); else { destroy_cb(e); - fact->destroy_edge(e); + fact->destroy_edge(e, destroyed_cb); } } @@ -186,6 +186,7 @@ void ParseCallbackManager::overlapping_blocks(Block *a, Block *b) { }; void ParseCallbackManager::newfunction_retstatus(Function *f) { + boost::lock_guard g(*f); for (iterator iter = begin(); iter != end(); ++iter) (*iter)->newfunction_retstatus(f); }; @@ -231,6 +232,11 @@ void ParseCallbackManager::split_block_cb(Block *a, Block *b) { (*iter)->split_block_cb(a, b); }; +void ParseCallbackManager::discover_function(Function* f) { + for (iterator iter = begin(); iter != end(); ++iter) + (*iter)->function_discovery_cb(f); +}; + void ParseCallbackManager::destroy_cb(Block *b) { for (iterator iter = begin(); iter != end(); ++iter) (*iter)->destroy_cb(b); diff --git a/parseAPI/src/ParseData.C b/parseAPI/src/ParseData.C index 43002eccd3..62cbe235f7 100644 --- a/parseAPI/src/ParseData.C +++ b/parseAPI/src/ParseData.C @@ -40,13 +40,17 @@ using namespace Dyninst::ParseAPI; void ParseFrame::set_status(Status s) { - _status = s; + boost::lock_guard g(*this); + race_detector_fake_lock_acquire(race_detector_fake_lock(_status)); + _status.store(s); + race_detector_fake_lock_release(race_detector_fake_lock(_status)); _pd->setFrameStatus(codereg,func->addr(),s); } ParseWorkElem * ParseFrame::mkWork( ParseWorkBundle * b, Edge * e, + Address source, Address target, bool resolvable, bool tailcall) @@ -55,7 +59,7 @@ ParseWorkElem * ParseFrame::mkWork( b = new ParseWorkBundle(); work_bundles.push_back(b); } - ParseWorkElem * ret = new ParseWorkElem(b,e,target,resolvable,tailcall); + ParseWorkElem * ret = new ParseWorkElem(b,e,source, target,resolvable,tailcall); b->add( ret ); return ret; } @@ -73,10 +77,23 @@ ParseWorkElem * ParseFrame::mkWork( return ret; } +ParseWorkElem * ParseFrame::mkWork( + ParseWorkBundle *b, + Function * shared_func) +{ + if(!b) { + b = new ParseWorkBundle(); + work_bundles.push_back(b); + } + ParseWorkElem * ret = new ParseWorkElem(b,shared_func); + b->add( ret ); + return ret; + +} /**** Standard [no overlapping regions] ParseData ****/ StandardParseData::StandardParseData(Parser *p) : - ParseData(p) + ParseData(p), _rdata(&p->obj(), p->obj().cs()->regions()[0]) { } StandardParseData::~StandardParseData() @@ -111,31 +128,17 @@ int StandardParseData::findBlocks(CodeRegion * /* cr */, Address addr, set & blocks) { int ret = _rdata.findBlocks(addr,blocks); -#if 0 // old sanity check that discovered blocks at a given address are all - // in the same region, the problem with the check is that it blocks - // has to be empty when you call this function, so with the sanity - // check in place you can't call findBlocks on a range of addresses - // accumulating the results in the blocks set. Copying would allow - // the sanity check to work, but it seems unnecessary - CodeRegion *check = 0; - for (std::set::iterator iter = blocks.begin(); iter != blocks.end(); ++iter) - { - if (!check) check = (*iter)->region(); - else assert(check == (*iter)->region()); - } -#endif return ret; } Function * -StandardParseData::get_func(CodeRegion * cr, Address entry, FuncSource src) +StandardParseData::createAndRecordFunc(CodeRegion * cr, Address entry, FuncSource src) { - CodeRegion * reg = NULL; + CodeRegion * reg = reglookup(cr,entry); Function * ret = NULL; char name[32]; - - if(!(ret = findFunc(cr,entry))) { - reg = reglookup(cr,entry); // get the *correct* CodeRegion + boost::lock_guard g(*this); + if(!(ret = findFunc(reg,entry))) { if(reg && reg->isCode(entry)) { if (src == MODIFICATION) { snprintf(name,32,"mod%lx",entry); @@ -154,37 +157,53 @@ StandardParseData::get_func(CodeRegion * cr, Address entry, FuncSource src) void StandardParseData::record_frame(ParseFrame * pf) { - _rdata.frame_map[pf->func->addr()] = pf; + _rdata.record_frame(pf); } void StandardParseData::remove_frame(ParseFrame * pf) { - _rdata.frame_map.erase(pf->func->addr()); + race_detector_fake_lock_acquire(race_detector_fake_lock(_rdata.frame_map)); + { + tbb::concurrent_hash_map::accessor a; + if(_rdata.frame_map.find(a, pf->func->addr())) _rdata.frame_map.erase(a); + } + race_detector_fake_lock_release(race_detector_fake_lock(_rdata.frame_map)); } ParseFrame * StandardParseData::findFrame(CodeRegion * /* cr */, Address addr) { - if(HASHDEF(_rdata.frame_map,addr)) - return _rdata.frame_map[addr]; - else - return NULL; + return _rdata.findFrame(addr); } ParseFrame::Status StandardParseData::frameStatus(CodeRegion * /* cr */, Address addr) { - if(HASHDEF(_rdata.frame_status,addr)) - return _rdata.frame_status[addr]; - else - return ParseFrame::BAD_LOOKUP; + return _rdata.getFrameStatus(addr); } void StandardParseData::setFrameStatus(CodeRegion * /* cr */, Address addr, ParseFrame::Status status) { - _rdata.frame_status[addr] = status; + _rdata.setFrameStatus(addr, status); +} +ParseFrame* +StandardParseData::createAndRecordFrame(Function* f) +{ + boost::lock_guard g(*this); + ParseFrame * pf = findFrame(NULL, f->addr()); + if (pf == NULL && frameStatus(NULL, f->addr()) == ParseFrame::BAD_LOOKUP) { + // We only create a new frame, when we currently cannot find it + // and the address is not parsed before. + pf = new ParseFrame(f, this); + _parser->init_frame(*pf); + // We have to first initialized the frame before setting the frame status + // and recording the frame, because these two operations make the frame public. + pf->set_status(ParseFrame::UNPARSED); + record_frame(pf); + return pf; + } + return NULL; } - CodeRegion * StandardParseData::reglookup(CodeRegion * /* cr */, Address addr) { @@ -231,13 +250,15 @@ OverlappingParseData::OverlappingParseData( Parser *p, vector & regions) : ParseData(p) { + boost::lock_guard g(*this); for(unsigned i=0;iobj(), regions[i]); } } OverlappingParseData::~OverlappingParseData() { + boost::lock_guard g(*this); reg_map_t::iterator it = rmap.begin(); for( ; it != rmap.end(); ++it) delete it->second; @@ -246,6 +267,7 @@ OverlappingParseData::~OverlappingParseData() Function * OverlappingParseData::findFunc(CodeRegion * cr, Address entry) { + boost::lock_guard g(*this); if(!HASHDEF(rmap,cr)) return NULL; region_data * rd = rmap[cr]; return rd->findFunc(entry); @@ -253,6 +275,7 @@ OverlappingParseData::findFunc(CodeRegion * cr, Address entry) Block * OverlappingParseData::findBlock(CodeRegion * cr, Address entry) { + boost::lock_guard g(*this); if(!HASHDEF(rmap,cr)) return NULL; region_data * rd = rmap[cr]; return rd->findBlock(entry); @@ -261,6 +284,7 @@ int OverlappingParseData::findFuncs(CodeRegion * cr, Address addr, set & funcs) { + boost::lock_guard g(*this); if(!HASHDEF(rmap,cr)) return 0; region_data * rd = rmap[cr]; return rd->findFuncs(addr,funcs); @@ -269,6 +293,7 @@ int OverlappingParseData::findFuncs(CodeRegion * cr, Address start, Address end, set & funcs) { + boost::lock_guard g(*this); if(!HASHDEF(rmap,cr)) return 0; region_data * rd = rmap[cr]; return rd->findFuncs(start,end,funcs); @@ -277,6 +302,7 @@ int OverlappingParseData::findBlocks(CodeRegion * cr, Address addr, set & blocks) { + boost::lock_guard g(*this); if(!HASHDEF(rmap,cr)) return 0; region_data * rd = rmap[cr]; return rd->findBlocks(addr,blocks); @@ -284,34 +310,57 @@ OverlappingParseData::findBlocks(CodeRegion * cr, Address addr, ParseFrame * OverlappingParseData::findFrame(CodeRegion *cr, Address addr) { + boost::lock_guard g(*this); if(!HASHDEF(rmap,cr)) return NULL; region_data * rd = rmap[cr]; - if(HASHDEF(rd->frame_map,addr)) - return rd->frame_map[addr]; - else - return NULL; + return rd->findFrame(addr); +} +void +OverlappingParseData::setFrameStatus(CodeRegion *cr, Address addr, + ParseFrame::Status status) +{ + boost::lock_guard g(*this); + if(!HASHDEF(rmap,cr)) return; + region_data * rd = rmap[cr]; + rd->setFrameStatus(addr, status); } + ParseFrame::Status OverlappingParseData::frameStatus(CodeRegion *cr, Address addr) { + boost::lock_guard g(*this); if(!HASHDEF(rmap,cr)) return ParseFrame::BAD_LOOKUP; region_data * rd = rmap[cr]; - if(HASHDEF(rd->frame_status,addr)) - return rd->frame_status[addr]; - else + tbb::concurrent_hash_map::const_accessor a; + if (rd->frame_status.find(a, addr)) { + return a->second; + } else { return ParseFrame::BAD_LOOKUP; + } } -void -OverlappingParseData::setFrameStatus(CodeRegion *cr, Address addr, - ParseFrame::Status status) -{ - if(!HASHDEF(rmap,cr)) return; - region_data * rd = rmap[cr]; - rd->frame_status[addr] = status; + +ParseFrame* +OverlappingParseData::createAndRecordFrame(Function* f) +{ + boost::lock_guard g(*this); + ParseFrame * pf = findFrame(f->region(), f->addr()); + if (pf == NULL && frameStatus(f->region(), f->addr()) == ParseFrame::BAD_LOOKUP) { + // We only create a new frame, when we currently cannot find it + // and the address is not parsed before. + pf = new ParseFrame(f, this); + _parser->init_frame(*pf); + pf->set_status(ParseFrame::UNPARSED); + record_frame(pf); + return pf; + } + return NULL; } + + Function * -OverlappingParseData::get_func(CodeRegion * cr, Address addr, FuncSource src) +OverlappingParseData::createAndRecordFunc(CodeRegion * cr, Address addr, FuncSource src) { + boost::lock_guard g(*this); Function * ret = NULL; char name[32]; @@ -334,12 +383,14 @@ OverlappingParseData::get_func(CodeRegion * cr, Address addr, FuncSource src) region_data * OverlappingParseData::findRegion(CodeRegion *cr) { + boost::lock_guard g(*this); if(!HASHDEF(rmap,cr)) return NULL; return rmap[cr]; } void OverlappingParseData::record_func(Function *f) { + boost::lock_guard g(*this); CodeRegion * cr = f->region(); if(!HASHDEF(rmap,cr)) { fprintf(stderr,"Error, invalid code region [%lx,%lx) in record_func\n", @@ -347,23 +398,28 @@ OverlappingParseData::record_func(Function *f) return; } region_data * rd = rmap[cr]; - rd->funcsByAddr[f->addr()] = f; + rd->record_func(f); } -void +Block* OverlappingParseData::record_block(CodeRegion *cr, Block *b) { - if(!HASHDEF(rmap,cr)) { - fprintf(stderr,"Error, invalid code region [%lx,%lx) in record_block\n", - cr->offset(),cr->offset()+cr->length()); - return; + region_data* rd = NULL; + { + boost::lock_guard g(*this); + + if(!HASHDEF(rmap,cr)) { + fprintf(stderr,"Error, invalid code region [%lx,%lx) in record_block\n", + cr->offset(),cr->offset()+cr->length()); + return b; + } + rd = rmap[cr]; } - region_data * rd = rmap[cr]; - rd->blocksByAddr[b->start()] = b; - rd->blocksByRange.insert(b); + return rd->record_block(b); } void OverlappingParseData::remove_func(Function *f) { + boost::lock_guard g(*this); remove_extents(f->extents()); CodeRegion * cr = f->region(); @@ -379,6 +435,7 @@ OverlappingParseData::remove_func(Function *f) void OverlappingParseData::remove_block(Block *b) { + boost::lock_guard g(*this); CodeRegion * cr = b->region(); if(!HASHDEF(rmap,cr)) { fprintf(stderr,"Error, invalid code region [%lx,%lx) in record_block\n", @@ -392,6 +449,7 @@ OverlappingParseData::remove_block(Block *b) void //extents should all belong to the same code region OverlappingParseData::remove_extents(const vector & extents) { + boost::lock_guard g(*this); if (0 == extents.size()) { return; } @@ -411,6 +469,7 @@ OverlappingParseData::remove_extents(const vector & extents) void OverlappingParseData::record_frame(ParseFrame *pf) { + boost::lock_guard g(*this); CodeRegion * cr = pf->codereg; if(!HASHDEF(rmap,cr)) { fprintf(stderr,"Error, invalid code region [%lx,%lx) in record_frame\n", @@ -418,11 +477,12 @@ OverlappingParseData::record_frame(ParseFrame *pf) return; } region_data * rd = rmap[cr]; - rd->frame_map[pf->func->addr()] = pf; + rd->record_frame(pf); } void OverlappingParseData::remove_frame(ParseFrame *pf) { + boost::lock_guard g(*this); CodeRegion * cr = pf->codereg; if(!HASHDEF(rmap,cr)) { fprintf(stderr,"Error, invalid code region [%lx,%lx) in remove_frame\n", @@ -430,10 +490,43 @@ OverlappingParseData::remove_frame(ParseFrame *pf) return; } region_data * rd = rmap[cr]; + race_detector_fake_lock_acquire(race_detector_fake_lock(rd->frame_map)); rd->frame_map.erase(pf->func->addr()); + race_detector_fake_lock_release(race_detector_fake_lock(rd->frame_map)); } CodeRegion * OverlappingParseData::reglookup(CodeRegion *cr, Address /* addr */) { return cr; } + +edge_parsing_data +OverlappingParseData::setEdgeParsingStatus(CodeRegion *cr, Address addr, Function *f, Block *b) +{ + boost::lock_guard g(*this); + if(!HASHDEF(rmap,cr)) { + fprintf(stderr,"Error, invalid code region [%lx,%lx) in remove_frame\n", + cr->offset(),cr->offset()+cr->length()); + return edge_parsing_data(); + } + region_data * rd = rmap[cr]; + return rd->set_edge_parsed(addr,f, b); +} + +void +OverlappingParseData::getAllRegionData(vector &rds) { + for (auto rit = rmap.begin(); rit != rmap.end(); ++rit) + rds.push_back(rit->second); +} + +region_data::edge_data_map* +OverlappingParseData::get_edge_data_map(CodeRegion *cr) { + boost::lock_guard g(*this); + if(!HASHDEF(rmap,cr)) { + fprintf(stderr,"Error, invalid code region [%lx,%lx) in remove_frame\n", + cr->offset(),cr->offset()+cr->length()); + return NULL; + } + region_data * rd = rmap[cr]; + return rd->get_edge_data_map(); +} diff --git a/parseAPI/src/ParseData.h b/parseAPI/src/ParseData.h index c67a060cc2..3270ab0b01 100644 --- a/parseAPI/src/ParseData.h +++ b/parseAPI/src/ParseData.h @@ -42,6 +42,14 @@ #include "ParserDetails.h" #include "debug_parse.h" +#include "race-detector-annotations.h" + +#include +#include +#include +#include + +#include "tbb/concurrent_hash_map.h" using namespace std; @@ -53,7 +61,7 @@ class ParseData; /** Describes a saved frame during recursive parsing **/ // Parsing data for a function. -class ParseFrame { +class ParseFrame : public boost::lockable_adapter { public: enum Status { UNPARSED, @@ -79,6 +87,7 @@ class ParseFrame { ParseWorkElem * mkWork( ParseWorkBundle * b, Edge * e, + Address source, Address target, bool resolvable, bool tailcall); @@ -86,11 +95,16 @@ class ParseFrame { ParseWorkBundle * b, Block* block, const InsnAdapter::IA_IAPI *ah); - + ParseWorkElem * mkWork( + ParseWorkBundle *b, + Function* shared_func); void pushWork(ParseWorkElem * elem) { + boost::lock_guard g(*this); + parsing_printf("\t pushing work element for block %p, edge %p, target %p\n", elem->cur(), elem->edge(), elem->target()); worklist.push(elem); } ParseWorkElem * popWork() { + boost::lock_guard g(*this); ParseWorkElem * ret = NULL; if(!worklist.empty()) { ret = worklist.top(); @@ -100,6 +114,7 @@ class ParseFrame { } void pushDelayedWork(ParseWorkElem * elem, Function * ct) { + boost::lock_guard g(*this); delayedWork.insert(make_pair(elem, ct)); } @@ -111,7 +126,8 @@ class ParseFrame { // Delayed work elements std::map delayedWork; - dyn_hash_map leadersToBlock; // block map + std::map leadersToBlock; + //dyn_hash_map leadersToBlock; // block map Address curAddr; // current insn address unsigned num_insns; dyn_hash_map visited; @@ -123,6 +139,7 @@ class ParseFrame { CodeRegion * codereg; ParseWorkElem * seed; // stored for cleanup + std::set
value_driven_jump_tables; ParseFrame(Function * f,ParseData *pd) : curAddr(0), @@ -133,32 +150,60 @@ class ParseFrame { seed(NULL), _pd(pd) { - set_status(UNPARSED); + busy.store(false); } ~ParseFrame(); - Status status() const { return _status; } + Status status() const { + race_detector_fake_lock_acquire(race_detector_fake_lock(_status)); + Status result = _status.load(); + race_detector_fake_lock_release(race_detector_fake_lock(_status)); + return result; + } void set_status(Status); + bool swap_busy(bool value) { + return busy.exchange(value); + } +; private: - Status _status; + boost::atomic _status; + boost::atomic busy; ParseData * _pd; }; -/* per-CodeRegion parsing data */ -class region_data { +class edge_parsing_data { + public: - // Function lookups - Dyninst::IBSTree_fast funcsByRange; - dyn_hash_map funcsByAddr; + Block* b; + Function *f; + edge_parsing_data(Function *ff, Block *bb) { + b = bb; + f = ff; + } + edge_parsing_data() : b(NULL), f(NULL) {} +}; + + +/* per-CodeRegion parsing data */ +class region_data { +public: + // Function lookups + Dyninst::IBSTree_fast funcsByRange; + tbb::concurrent_hash_map funcsByAddr; // Block lookups - Dyninst::IBSTree_fast blocksByRange; - dyn_hash_map blocksByAddr; + Dyninst::IBSTree_fast blocksByRange; + tbb::concurrent_hash_map blocksByAddr; // Parsing internals - dyn_hash_map frame_map; - dyn_hash_map frame_status; + tbb::concurrent_hash_map frame_map; + tbb::concurrent_hash_map frame_status; + + // Edge parsing records + // We only want one thread to create edges for a location + typedef tbb::concurrent_hash_map edge_data_map; + edge_data_map edge_parsing_status; Function * findFunc(Address entry); Block * findBlock(Address entry); @@ -182,9 +227,121 @@ class region_data { return std::pair(nextBlockAddr,nextBlock); } - + ParseFrame* findFrame(Address addr) const { + ParseFrame *result = NULL; + race_detector_fake_lock_acquire(race_detector_fake_lock(frame_map)); + { + tbb::concurrent_hash_map::const_accessor a; + if(frame_map.find(a, addr)) result = a->second; + } + race_detector_fake_lock_release(race_detector_fake_lock(frame_map)); + return result; + } + ParseFrame::Status getFrameStatus(Address addr) { + ParseFrame::Status ret; + race_detector_fake_lock_acquire(race_detector_fake_lock(frame_status)); + { + tbb::concurrent_hash_map::const_accessor a; + if(frame_status.find(a, addr)) { + ret = a->second; + } else { + ret = ParseFrame::BAD_LOOKUP; + } + } + race_detector_fake_lock_release(race_detector_fake_lock(frame_status)); + return ret; + } + + + void setFrameStatus(Address addr, ParseFrame::Status status) + { + race_detector_fake_lock_acquire(race_detector_fake_lock(frame_status)); + { + tbb::concurrent_hash_map::accessor a; + frame_status.insert(a, make_pair(addr, status)); + a->second = status; + } + race_detector_fake_lock_release(race_detector_fake_lock(frame_status)); + } + + void record_func(Function* f) { + race_detector_fake_lock_acquire(race_detector_fake_lock(funcsByAddr)); + { + tbb::concurrent_hash_map::accessor a; + funcsByAddr.insert(a, std::make_pair(f->addr(), f)); + } + race_detector_fake_lock_release(race_detector_fake_lock(funcsByAddr)); + + } + Block* record_block(Block* b) { + Block* ret = NULL; + race_detector_fake_lock_acquire(race_detector_fake_lock(blocksByAddr)); + { + tbb::concurrent_hash_map::accessor a; + bool inserted = blocksByAddr.insert(a, std::make_pair(b->start(), b)); + // Inserting failed when another thread has inserted a block with the same starting address + if(!inserted) { + ret = a->second; + } else { + ret = b; + } + } + race_detector_fake_lock_release(race_detector_fake_lock(blocksByAddr)); + return ret; + } + void insertBlockByRange(Block* b) { + blocksByRange.insert(b); + } + void record_frame(ParseFrame* pf) { + race_detector_fake_lock_acquire(race_detector_fake_lock(frame_map)); + { + tbb::concurrent_hash_map::accessor a; + frame_map.insert(a, make_pair(pf->func->addr(), pf)); + } + race_detector_fake_lock_release(race_detector_fake_lock(frame_map)); + } + // Find functions within [start,end) int findFuncs(Address start, Address end, set & funcs); + region_data(CodeObject* obj, CodeRegion* reg) { + Block* sink = new Block(obj, reg, numeric_limits
::max()); + blocksByAddr.insert(make_pair(sink->start(),sink)); + blocksByRange.insert(sink); + } + + edge_data_map* get_edge_data_map() { return &edge_parsing_status; } + + edge_parsing_data set_edge_parsed(Address addr, Function *f, Block *b) { + edge_parsing_data ret; + race_detector_fake_lock_acquire(race_detector_fake_lock(edge_parsing_status)); + { + tbb::concurrent_hash_map::accessor a; + // A successful insertion means the thread should + // continue to create edges. We return the passed in Function* + // as indication of successful insertion. + // + // Otherwise, another thread has started creating edges. + // The current thread should give up. We return + // the function who succeeded. + if (!edge_parsing_status.insert(a, addr)) + ret = a->second; + else { + ret.f = f; + ret.b = b; + } + } + race_detector_fake_lock_release(race_detector_fake_lock(edge_parsing_status)); + return ret; + } + + void getAllBlocks(std::map &allBlocks) { + // This function should be only called in single-threaded mode, + // such as when we are finalizing parsing + + // We convert hash map to an ordered tree + for (auto it = blocksByAddr.begin(); it != blocksByAddr.end(); ++it) + allBlocks[it->first] = it->second; + } }; /** region_data inlines **/ @@ -192,20 +349,26 @@ class region_data { inline Function * region_data::findFunc(Address entry) { - dyn_hash_map::iterator fit; - if((fit = funcsByAddr.find(entry)) != funcsByAddr.end()) - return fit->second; - else - return NULL; + Function *result = NULL; + race_detector_fake_lock_acquire(race_detector_fake_lock(funcsByAddr)); + { + tbb::concurrent_hash_map::const_accessor a; + if(funcsByAddr.find(a, entry)) result = a->second; + } + race_detector_fake_lock_release(race_detector_fake_lock(funcsByAddr)); + return result; } inline Block * region_data::findBlock(Address entry) { - dyn_hash_map::iterator bit; - if((bit = blocksByAddr.find(entry)) != blocksByAddr.end()) - return bit->second; - else - return NULL; + Block *result = NULL; + race_detector_fake_lock_acquire(race_detector_fake_lock(blocksByAddr)); + { + tbb::concurrent_hash_map::const_accessor a; + if(blocksByAddr.find(a, entry)) result = a->second; + } + race_detector_fake_lock_release(race_detector_fake_lock(blocksByAddr)); + return result; } inline int region_data::findFuncs(Address addr, set & funcs) @@ -240,7 +403,6 @@ inline int region_data::findBlocks(Address addr, set & blocks) { int sz = blocks.size(); - blocksByRange.find(addr,blocks); return blocks.size() - sz; } @@ -248,7 +410,7 @@ region_data::findBlocks(Address addr, set & blocks) /** end region_data **/ -class ParseData { +class ParseData : public boost::lockable_adapter { protected: ParseData(Parser *p) : _parser(p) { } Parser * _parser; @@ -262,18 +424,24 @@ class ParseData { virtual int findFuncs(CodeRegion *, Address, Address, set &) =0; virtual int findBlocks(CodeRegion *, Address, set &) =0; virtual ParseFrame * findFrame(CodeRegion *, Address) = 0; - virtual ParseFrame::Status frameStatus(CodeRegion *, Address) = 0; + virtual ParseFrame::Status frameStatus(CodeRegion *, Address addr) = 0; virtual void setFrameStatus(CodeRegion*,Address,ParseFrame::Status) = 0; + // Atomically lookup whether there is a frame for a Function object. + // If there is no frame for the Function, create a new frame and record it. + // Return NULL if a frame already exists; + // Return the pointer to the new frame if a new frame is created + virtual ParseFrame* createAndRecordFrame(Function*) = 0; + // creation (if non-existing) - virtual Function * get_func(CodeRegion *, Address, FuncSource) =0; + virtual Function * createAndRecordFunc(CodeRegion *, Address, FuncSource) =0; // mapping virtual region_data * findRegion(CodeRegion *) =0; // accounting virtual void record_func(Function *) =0; - virtual void record_block(CodeRegion *, Block *) =0; + virtual Block* record_block(CodeRegion *, Block *) =0; virtual void record_frame(ParseFrame *) =0; // removal @@ -285,6 +453,10 @@ class ParseData { // does the Right Thing(TM) for standard- and overlapping-region // object types virtual CodeRegion * reglookup(CodeRegion *cr, Address addr) =0; + virtual edge_parsing_data setEdgeParsingStatus(CodeRegion *cr, Address addr, Function *f, Block *b) = 0; + virtual void getAllRegionData(std::vector&) = 0; + virtual region_data::edge_data_map* get_edge_data_map(CodeRegion*) = 0; + }; /* StandardParseData represents parse data for Parsers that disallow @@ -306,12 +478,14 @@ class StandardParseData : public ParseData { ParseFrame::Status frameStatus(CodeRegion *, Address); void setFrameStatus(CodeRegion*,Address,ParseFrame::Status); - Function * get_func(CodeRegion * cr, Address addr, FuncSource src); + virtual ParseFrame* createAndRecordFrame(Function*); + + Function * createAndRecordFunc(CodeRegion * cr, Address addr, FuncSource src); region_data * findRegion(CodeRegion *cr); void record_func(Function *f); - void record_block(CodeRegion *cr, Block *b); + Block* record_block(CodeRegion *cr, Block *b); void record_frame(ParseFrame *pf); void remove_frame(ParseFrame *); @@ -320,6 +494,10 @@ class StandardParseData : public ParseData { void remove_extents(const std::vector &extents); CodeRegion * reglookup(CodeRegion *cr, Address addr); + edge_parsing_data setEdgeParsingStatus(CodeRegion *cr, Address addr, Function *f, Block *b); + void getAllRegionData(std::vector& rds); + region_data::edge_data_map* get_edge_data_map(CodeRegion* cr); + }; inline region_data * StandardParseData::findRegion(CodeRegion * /* cr */) @@ -328,14 +506,26 @@ inline region_data * StandardParseData::findRegion(CodeRegion * /* cr */) } inline void StandardParseData::record_func(Function *f) { - _rdata.funcsByAddr[f->addr()] = f; + _rdata.record_func(f); +} +inline Block* StandardParseData::record_block(CodeRegion * /* cr */, Block *b) +{ + return _rdata.record_block(b); } -inline void StandardParseData::record_block(CodeRegion * /* cr */, Block *b) + +inline edge_parsing_data StandardParseData::setEdgeParsingStatus(CodeRegion *, Address addr, Function *f, Block *b) { - _rdata.blocksByAddr[b->start()] = b; - _rdata.blocksByRange.insert(b); + return _rdata.set_edge_parsed(addr, f, b); +} + +inline void StandardParseData::getAllRegionData(std::vector & rds) { + rds.push_back(&_rdata); +} +inline region_data::edge_data_map* StandardParseData::get_edge_data_map(CodeRegion*) { + return _rdata.get_edge_data_map(); } + /* OverlappingParseData handles binary code objects like .o files where CodeRegions may overlap on the same linear address space */ class OverlappingParseData : public ParseData { @@ -356,12 +546,14 @@ class OverlappingParseData : public ParseData { ParseFrame::Status frameStatus(CodeRegion *, Address); void setFrameStatus(CodeRegion*,Address,ParseFrame::Status); - Function * get_func(CodeRegion * cr, Address addr, FuncSource src); + virtual ParseFrame* createAndRecordFrame(Function*); + + Function * createAndRecordFunc(CodeRegion * cr, Address addr, FuncSource src); region_data * findRegion(CodeRegion *cr); void record_func(Function *f); - void record_block(CodeRegion *cr, Block *b); + Block* record_block(CodeRegion *cr, Block *b); void record_frame(ParseFrame *pf); void remove_frame(ParseFrame *); @@ -370,6 +562,10 @@ class OverlappingParseData : public ParseData { void remove_extents(const std::vector &extents); CodeRegion * reglookup(CodeRegion *cr, Address addr); + edge_parsing_data setEdgeParsingStatus(CodeRegion *cr, Address addr, Function* f, Block *b); + void getAllRegionData(std::vector&); + region_data::edge_data_map* get_edge_data_map(CodeRegion* cr); + }; } diff --git a/parseAPI/src/Parser.C b/parseAPI/src/Parser.C index 4b271cf375..faa828902e 100644 --- a/parseAPI/src/Parser.C +++ b/parseAPI/src/Parser.C @@ -28,9 +28,11 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include + #include #include - +#include // For Mutex #define PROCCONTROL_EXPORTS @@ -40,11 +42,30 @@ #include "CFGFactory.h" #include "ParseCallback.h" #include "Parser.h" +#include "Parser.h" #include "CFG.h" #include "util.h" #include "debug_parse.h" +#include "IndirectAnalyzer.h" + +#include + + +#include +#include + +#ifdef ENABLE_RACE_DETECTION +#define USE_CILK 1 +#else +#define USE_OPENMP 1 +#endif + +#if USE_CILK +#include +#include +#endif -#include +#include "race-detector-annotations.h" using namespace std; using namespace Dyninst; @@ -58,23 +79,19 @@ typedef vector< edge_pair_t > Edges_t; namespace { struct less_cr { - bool operator()(CodeRegion * x, CodeRegion * y) - { - return x->offset() < y->offset(); - } + bool operator()(CodeRegion * x, CodeRegion * y) + { + return x->offset() < y->offset(); + } }; } Parser::Parser(CodeObject & obj, CFGFactory & fact, ParseCallbackManager & pcb) : - _obj(obj), - _cfgfact(fact), - _pcb(pcb), - _parse_data(NULL), - num_delayedFrames(0), - _sink(NULL), - _parse_state(UNPARSED), - _in_parse(false), - _in_finalize(false) + _obj(obj), + _cfgfact(fact), + _pcb(pcb), + _parse_data(NULL), + _parse_state(UNPARSED) { // cache plt entries for fast lookup const map & lm = obj.cs()->linkage(); @@ -86,8 +103,8 @@ Parser::Parser(CodeObject & obj, CFGFactory & fact, ParseCallbackManager & pcb) if(obj.cs()->regions().empty()) { parsing_printf("[%s:%d] CodeSource provides no CodeRegions" - " -- unparesable\n", - FILE__,__LINE__); + " -- unparesable\n", + FILE__,__LINE__); _parse_state = UNPARSEABLE; return; } @@ -98,7 +115,7 @@ Parser::Parser(CodeObject & obj, CFGFactory & fact, ParseCallbackManager & pcb) sort(copy.begin(),copy.end(),less_cr()); // allocate a sink block -- region is arbitrary - _sink = _cfgfact._mksink(&_obj,copy[0]); + _sink = new Block(&_obj, regs[0], std::numeric_limits
::max()); bool overlap = false; CodeRegion * prev = copy[0], *cur = NULL; @@ -106,8 +123,8 @@ Parser::Parser(CodeObject & obj, CFGFactory & fact, ParseCallbackManager & pcb) cur = copy[i]; if(cur->offset() < prev->offset() + prev->length()) { parsing_printf("Overlapping code regions [%lx,%lx) and [%lx,%lx)\n", - prev->offset(),prev->offset()+prev->length(), - cur->offset(),cur->offset()+cur->length()); + prev->offset(),prev->offset()+prev->length(), + cur->offset(),cur->offset()+cur->length()); overlap = true; break; } @@ -129,9 +146,9 @@ Parser::~Parser() if(_parse_data) delete _parse_data; - vector::iterator fit = frames.begin(); - for( ; fit != frames.end(); ++fit) + for(auto fit = frames.begin() ; fit != frames.end(); ++fit) delete *fit; + frames.clear(); } @@ -142,6 +159,15 @@ Parser::add_hint(Function * f) record_func(f); } +template +std::string pair_to_string(T pr) +{ + std::stringstream s; + s << pr.first << ", " << pr.second; + return s.str(); +} + + void Parser::parse() { @@ -151,36 +177,38 @@ Parser::parse() // For modification: once we've full-parsed once, don't do it again if (_parse_state >= COMPLETE) return; - if(_parse_state == UNPARSEABLE) - return; - - assert(!_in_parse); - _in_parse = true; - + ScopeLock > L(parse_mutex); parse_vanilla(); finalize(); // anything else by default...? if(_parse_state < COMPLETE) _parse_state = COMPLETE; - - _in_parse = false; + parsing_printf("[%s:%d] parsing complete for Parser %p with state %d\n", FILE__, __LINE__, this, _parse_state); +#ifdef ADD_PARSE_FRAME_TIMERS + std::ofstream stat_log("functions.csv"); + stat_log << "Results for " << time_histogram.size() << " buckets\n"; + stat_log << "usecs,count\n"; + std::transform(time_histogram.begin(), time_histogram.end(), + std::ostream_iterator(stat_log, "\n"), + pair_to_string >); +#endif } void Parser::parse_at( - CodeRegion * region, - Address target, - bool recursive, - FuncSource src) + CodeRegion * region, + Address target, + bool recursive, + FuncSource src) { Function *f; ParseFrame *pf; - vector work; + LockFreeQueue work; parsing_printf("[%s:%d] entered parse_at([%lx,%lx),%lx)\n", - FILE__,__LINE__,region->low(),region->high(),target); + FILE__,__LINE__,region->low(),region->high(),target); if(!region->contains(target)) { parsing_printf("\tbad address, bailing\n"); @@ -189,8 +217,9 @@ Parser::parse_at( if(_parse_state < PARTIAL) _parse_state = PARTIAL; - - f = _parse_data->get_func(region,target,src); + f = _parse_data->createAndRecordFunc(region, target, src); + if (f == NULL) + f = _parse_data->findFunc(region,target); if(!f) { parsing_printf(" could not create function at %lx\n",target); return; @@ -199,18 +228,17 @@ Parser::parse_at( ParseFrame::Status exist = _parse_data->frameStatus(region,target); if(exist != ParseFrame::BAD_LOOKUP && exist != ParseFrame::UNPARSED) { parsing_printf(" function at %lx already parsed, status %d\n", - target, exist); + target, exist); return; } - - if(!(pf = _parse_data->findFrame(region,target))) { - pf = new ParseFrame(f,_parse_data); - init_frame(*pf); - frames.push_back(pf); - _parse_data->record_frame(pf); - } - - work.push_back(pf); + pf = _parse_data->createAndRecordFrame(f); + if (pf != NULL) { + frames.insert(pf); + } else { + pf = _parse_data->findFrame(region, target); + } + if (pf->func->entry()) + work.insert(pf); parse_frames(work,recursive); // downgrade state if necessary @@ -247,9 +275,7 @@ Parser::parse_at(Address target, bool recursive, FuncSource src) void Parser::parse_vanilla() { - ParseFrame *pf; - vector work; - vector::iterator fit; + LockFreeQueue work; parsing_printf("[%s:%d] entered parse_vanilla()\n",FILE__,__LINE__); parsing_printf("\t%d function hints\n",hint_funcs.size()); @@ -258,25 +284,31 @@ Parser::parse_vanilla() _parse_state = PARTIAL; else parsing_printf("\tparse state is %d, some parsing already done\n", - _parse_state); + _parse_state); /* Initialize parse frames from hints */ - for(fit=hint_funcs.begin();fit!=hint_funcs.end();++fit) { - Function * hf = *fit; + + // Note: there is no fundamental obstacle to parallelizing this loop. However, + // race conditions need to be resolved in supporting laysrs first. + for (unsigned int i = 0; i < hint_funcs.size(); i++) { + Function * hf = hint_funcs[i]; ParseFrame::Status test = frame_status(hf->region(),hf->addr()); if(test != ParseFrame::BAD_LOOKUP && test != ParseFrame::UNPARSED) { parsing_printf("\tskipping repeat parse of %lx [%s]\n", - hf->addr(),hf->name().c_str()); + hf->addr(),hf->name().c_str()); continue; } - - pf = new ParseFrame(hf,_parse_data); - init_frame(*pf); - frames.push_back(pf); - work.push_back(pf); - _parse_data->record_frame(pf); + + ParseFrame *pf = _parse_data->createAndRecordFrame(hf); + if (pf == NULL) { + pf = _parse_data->findFrame(hf->region(), hf->addr()); + } else { + frames.insert(pf); + } + if (pf->func->entry()) + work.insert(pf); } parse_frames(work,true); @@ -290,7 +322,7 @@ Parser::parse_edges( vector< ParseWorkElem * > & work_elems ) // build up set of needed parse frames and load them with work elements set frameset; // for dup checking - vector frames; + LockFreeQueue frames; for (unsigned idx=0; idx < work_elems.size(); idx++) { @@ -299,16 +331,17 @@ Parser::parse_edges( vector< ParseWorkElem * > & work_elems ) if (elem->order() == ParseWorkElem::call_fallthrough) { - Edge *callEdge = NULL; + ParseAPI::Edge *callEdge = NULL; + boost::lock_guard g(*src); Block::edgelist trgs = src->targets(); - for (Block::edgelist::iterator eit = trgs.begin(); - eit != trgs.end(); - eit++) + for (Block::edgelist::iterator eit = trgs.begin(); + eit != trgs.end(); + eit++) { if ((*eit)->type() == CALL) { callEdge = *eit; if (!(*eit)->sinkEdge()) // if it's a sink edge, look for nonsink CALL - break; + break; } } // create a call work elem so that the bundle is complete @@ -323,226 +356,393 @@ Parser::parse_edges( vector< ParseWorkElem * > & work_elems ) // Also, in the case I saw, the callee was _not_ returning. Not directly. It // led into a big case with a longjmp() equivalent. - if (callEdge) + if (callEdge) { bool isResolvable = false; Address callTarget = 0; - if ( ! callEdge->sinkEdge() ) + if ( ! callEdge->sinkEdge() ) { isResolvable = true; - callTarget = callEdge->trg()->start(); + callTarget = callEdge->trg_addr(); // the call target may be in another Code Object Function *callee = callEdge->trg()->obj()->findFuncByEntry( - callEdge->trg()->region(), callTarget); + callEdge->trg()->region(), callTarget); assert(callee); callee->set_retstatus(RETURN); callee->_tamper = TAMPER_NONE; } elem->bundle()->add(new ParseWorkElem - ( elem->bundle(), - callEdge, - callTarget, - isResolvable, - false )); + ( elem->bundle(), + callEdge, + callEdge->src()->last(), + callTarget, + isResolvable, + false )); } } - ParseFrame *frame = _parse_data->findFrame - ( src->region(), - src->lastInsnAddr() ); - bool isNewFrame = false; - if (!frame) { - vector funcs; - src->getFuncs(funcs); - frame = new ParseFrame(*funcs.begin(),_parse_data); - for (unsigned fix=1; fix < funcs.size(); fix++) { - // if the block is shared, all of its funcs need - // to add the new edge - funcs[fix]->_cache_valid = false; - } - isNewFrame = true; + + vector funcs; + src->getFuncs(funcs); + for (unsigned fix=1; fix < funcs.size(); fix++) { + // if the block is shared, all of its funcs need + // to add the new edge + funcs[fix]->_cache_valid = false; + } + Function * f = NULL; + if (funcs.size() > 0) { + // Choosing any function is fine + f = funcs[0]; + } else { + f = _parse_data->createAndRecordFunc(src->region(), src->start(), RT); } - // push before frame init so no seed is added + ParseFrame *frame = _parse_data->createAndRecordFrame(f); + if (frame == NULL) { + frame = _parse_data->findFrame(src->region(), f->addr()); + } if (elem->bundle()) { frame->work_bundles.push_back(elem->bundle()); } + // push before frame init so no seed is added frame->pushWork(elem); - if (isNewFrame) { - init_frame(*frame); - } - if (frameset.end() == frameset.find(frame)) { frameset.insert(frame); - frames.push_back(frame); + frames.insert(frame); } } - + ScopeLock > L(parse_mutex); // now parse if(_parse_state < PARTIAL) _parse_state = PARTIAL; - _in_parse = true; parse_frames( frames, true ); if(_parse_state > COMPLETE) _parse_state = COMPLETE; - _in_parse = false; finalize(); } -void -Parser::parse_frames(vector & work, bool recursive) -{ - ParseFrame * pf; - - /* Recursive traversal parsing */ - while(!work.empty()) { - - pf = work.back(); - work.pop_back(); - if(pf->status() == ParseFrame::PARSED) - continue; +LockFreeQueueItem * +Parser::ProcessOneFrame(ParseFrame* pf, bool recursive) { + LockFreeQueueItem *frame_list = 0; + if (pf->func && !pf->swap_busy(true)) { + boost::lock_guard g(*pf); +#ifdef ADD_PARSE_FRAME_TIMERS + boost::timer::cpu_timer t; + t.start(); +#endif + parse_frame(*pf,recursive); +#ifdef ADD_PARSE_FRAME_TIMERS + t.stop(); + unsigned int msecs = floor(t.elapsed().wall / 1000000.0); + race_detector_fake_lock_acquire(race_detector_fake_lock(time_histogram)); + { + tbb::concurrent_hash_map::accessor a; + time_histogram.insert(a, msecs); + ++(a->second); + } + race_detector_fake_lock_release(race_detector_fake_lock(time_histogram)); +#endif + frame_list = postProcessFrame(pf, recursive); + + // exclusive access to each ParseFrame is mediated by marking a frame busy. + // we clear evidence of our access to the ParseFrame here because a concurrent + // thread may try to touch it because of duplicates in the work list. that + // won't actually be concurrent because of swap_busy. we suppress the race + // report by scrubbing information about our access. + race_detector_forget_access_history(pf, sizeof(*pf)); + + pf->swap_busy(false); + } + return frame_list; +} - parse_frame(*pf,recursive); - switch(pf->status()) { - case ParseFrame::CALL_BLOCKED: { - parsing_printf("[%s] frame %lx blocked at %lx\n", - FILE__,pf->func->addr(),pf->curAddr); +LockFreeQueueItem *Parser::postProcessFrame(ParseFrame *pf, bool recursive) { + LockFreeQueue work; + switch(pf->status()) { + case ParseFrame::CALL_BLOCKED: { + parsing_printf("[%s] frame %lx blocked at %lx\n", + FILE__,pf->func->addr(),pf->curAddr); + { - assert(pf->call_target); + assert(pf->call_target); parsing_printf(" call target %lx\n",pf->call_target->addr()); - work.push_back(pf); - + work.insert(pf); + CodeRegion * cr = pf->call_target->region(); Address targ = pf->call_target->addr(); + ParseFrame * tf = NULL; - ParseFrame * tf = _parse_data->findFrame(cr,targ); - if(!tf) - { - // sanity - if(_parse_data->frameStatus(cr,targ) == ParseFrame::PARSED) - assert(0); - - tf = new ParseFrame(pf->call_target,_parse_data); - init_frame(*tf); - frames.push_back(tf); - _parse_data->record_frame(tf); + tf = _parse_data->createAndRecordFrame(pf->call_target); + if (tf) { + frames.insert(tf); } - if(likely(recursive)) - work.push_back(tf); else { - assert(0); - // XXX should never get here - //parsing_printf(" recursive parsing disabled\n"); + tf = _parse_data->findFrame(cr, targ); } + // tf can still be NULL if the target frame is parsed and deleted + + // We put the frame at the front of the worklist, so + // the parser will parse the callee next + if(tf && recursive && tf->func->entry()) + work.insert(tf); - break; } - case ParseFrame::PARSED: - parsing_printf("[%s] frame %lx complete, return status: %d\n", - FILE__,pf->func->addr(),pf->func->_rs); - - if (unlikely( _obj.defensiveMode() && - TAMPER_NONE != pf->func->tampersStack() && - TAMPER_NONZERO != pf->func->tampersStack() )) - { // may adjust CALL_FT targets, add a frame to the worklist, - // or trigger parsing in a separate target CodeObject - tamper_post_processing(work,pf); - } - - /* add waiting frames back onto the worklist */ - resumeFrames(pf->func, work); - - pf->cleanup(); - break; - case ParseFrame::FRAME_ERROR: - parsing_printf("[%s] frame %lx error at %lx\n", - FILE__,pf->func->addr(),pf->curAddr); - break; - case ParseFrame::FRAME_DELAYED: { - parsing_printf("[%s] frame %lx delayed at %lx\n", - FILE__, - pf->func->addr(), - pf->curAddr); - - if (pf->delayedWork.size()) { - // Add frame to global delayed list - map::iterator iter; - map >::iterator fIter; - for (iter = pf->delayedWork.begin(); - iter != pf->delayedWork.end(); - ++iter) { - - Function * ct = iter->second; - parsing_printf("[%s] waiting on %s\n", - __FILE__, - ct->name().c_str()); - - fIter = delayedFrames.find(ct); - if (fIter == delayedFrames.end()) { - std::set waiters; + resumeFrames(pf->func, work); + break; + } + case ParseFrame::PARSED:{ + parsing_printf("[%s] frame %lx complete, return status: %d\n", + FILE__,pf->func->addr(),pf->func->retstatus()); + + if (unlikely(_obj.defensiveMode() && + TAMPER_NONE != pf->func->tampersStack() && + TAMPER_NONZERO != pf->func->tampersStack() )) + { // may adjust CALL_FT targets, add a frame to the worklist, + // or trigger parsing in a separate target CodeObject + tamper_post_processing(work,pf); + } + + /* add waiting frames back onto the worklist */ + resumeFrames(pf->func, work); + + pf->cleanup(); + break; + } + case ParseFrame::FRAME_ERROR: + parsing_printf("[%s] frame %lx error at %lx\n", + FILE__,pf->func->addr(),pf->curAddr); + break; + case ParseFrame::FRAME_DELAYED: + { + boost::lock_guard g(delayed_frames); + parsing_printf("[%s] frame %lx delayed at %lx\n", + FILE__, + pf->func->addr(), + pf->curAddr); + + if (pf->delayedWork.size()) { + // Add frame to global delayed list + + for (auto iter = pf->delayedWork.begin(); + iter != pf->delayedWork.end(); + ++iter) { + + Function * ct = iter->second; + parsing_printf("[%s] waiting on %s\n", + __FILE__, + ct->name().c_str()); + { + + auto fIter = delayed_frames.frames.find(ct); + if (fIter == delayed_frames.frames.end()) { + set waiters; waiters.insert(pf); - delayedFrames[ct] = waiters; + delayed_frames.frames[ct] = waiters; } else { - delayedFrames[ct].insert(pf); + delayed_frames.frames[ct].insert(pf); } } - } else { - // We shouldn't get here - assert(0 && "Delayed frame with no delayed work"); } - - /* if the return status of this function has been updated, add - * waiting frames back onto the work list */ - resumeFrames(pf->func, work); - break; + } else { + // We shouldn't get here + assert(0 && "Delayed frame with no delayed work"); + } + + /* if the return status of this function has been updated, add + * waiting frames back onto the work list */ + resumeFrames(pf->func, work); + break; + } + case ParseFrame::PROGRESS: + // another thread is working on this already; possibly something else unblocked. + break; + + default: + assert(0 && "invalid parse frame status"); + } + return work.steal(); +} + + +static void +InsertFrames +( + LockFreeQueueItem *frames, + LockFreeQueue *q +) +{ + if (frames) { + LockFreeQueue myq(frames); + q->splice(myq); + } +} + + +void +Parser::LaunchWork +( + LockFreeQueueItem *frame_list, + bool recursive +) +{ + LockFreeQueue private_queue(frame_list); + for(;;) { + LockFreeQueueItem *first = private_queue.pop(); + if (first == 0) break; + ParseFrame *frame = first->value(); + delete first; +#if USE_OPENMP +#pragma omp task firstprivate(frame, recursive) + SpawnProcessFrame(frame, recursive); +#else + cilk_spawn SpawnProcessFrame(frame, recursive); +#endif + } +} + + +void +Parser::SpawnProcessFrame +( + ParseFrame *pf, + bool recursive +) +{ + LockFreeQueueItem *new_frames = ProcessOneFrame(pf, recursive); + LaunchWork(new_frames, recursive); +} + +void print_work_queue(LockFreeQueue *work_queue) +{ + LockFreeQueueItem *current = work_queue->peek(); + + std::cout << "Work Queue" << std::endl; + while (current) { + std::cout << " parse frame " << std::hex << current->value() + << std::dec << std::endl; + current = current->next(); + } +} + + +void +Parser::ProcessFrames +( + LockFreeQueue *work_queue, + bool recursive +) +{ +#if USE_OPENMP +#pragma omp parallel shared(work_queue) + { +#pragma omp master + LaunchWork(work_queue->steal(), recursive); + } +#else + LaunchWork(work_queue->steal(), recursive); +#endif +} + + +void +Parser::parse_frames(LockFreeQueue &work, bool recursive) +{ + ProcessFrames(&work, recursive); + bool done = false, cycle = false; + { + boost::lock_guard g(delayed_frames); + + // Check if we can resume any frames yet + vector updated; + for (auto iter = delayed_frames.frames.begin(); + iter != delayed_frames.frames.end(); + ++iter) { + if (iter->first->retstatus() != UNSET) { + updated.push_back(iter->first); } - default: - assert(0 && "invalid parse frame status"); + } + if (updated.size()) { + for (auto uIter = updated.begin(); + uIter != updated.end(); + ++uIter) { + resumeFrames((*uIter), work); + } + } + + if(delayed_frames.frames.empty() && updated.empty()) { + parsing_printf("[%s] Fixed point reached (0 funcs with unknown return status)\n)", + __FILE__); + delayed_frames.prev_frames.clear(); + done = true; + } else if(delayed_frames.frames.size() > 0 && delayed_frames.prev_frames == delayed_frames.frames && updated.empty()) { + cycle = true; } } // Use fixed-point to ensure we parse frames whose parsing had to be delayed - if (delayedFrames.size() == 0) { - // Done! - parsing_printf("[%s] Fixed point reached (0 funcs with unknown return status)\n)", - __FILE__); - num_delayedFrames = 0; - } else if (delayedFrames.size() == num_delayedFrames) { - // If we've reached a fixedpoint and have remaining frames, we must - // have a cyclic dependency - parsing_printf("[%s] Fixed point reached (%d funcs with unknown return status)\n", - __FILE__, - delayedFrames.size()); + if (!done) { + if(cycle) { + processCycle(work,recursive); + } else { + processFixedPoint(work, recursive); + } + } + + cleanup_frames(); +} + +void Parser::processFixedPoint(LockFreeQueue &work, bool recursive) {// We haven't yet reached a fixedpoint; let's recurse + { + boost::lock_guard g(delayed_frames); + + parsing_printf("[%s] Fixed point not yet reached (%d funcs with unknown return status)\n", + __FILE__, + delayed_frames.frames.size()); + + // Update delayed_frames for next iteration + delayed_frames.prev_frames = delayed_frames.frames; + } + // Recurse through parse_frames + parsing_printf("[%s] Calling parse_frames again... \n", __FILE__); + + parse_frames(work, recursive); +} + +void Parser::processCycle(LockFreeQueue &work, bool recursive) {// If we've reached a fixedpoint and have remaining frames, we must + // have a cyclic dependency + vector updated; + { + boost::lock_guard g(delayed_frames); + parsing_printf("[%s] Fixed point reached (%d funcs with unknown return status)\n", + __FILE__, + delayed_frames.frames.size()); // Mark UNSET functions in cycle as NORETURN - // except if we're doing non-recursive parsing. - // If we're just parsing one function, we want - // to mark everything RETURN instead. - map >::iterator iter; - vector updated; - for (iter = delayedFrames.begin(); iter != delayedFrames.end(); ++iter) { + // except if we're doing non-recursive parsing. + // If we're just parsing one function, we want + // to mark everything RETURN instead. + for (auto iter = delayed_frames.frames.begin(); iter != delayed_frames.frames.end(); ++iter) { Function * func = iter->first; if (func->retstatus() == UNSET) { - if(recursive) - { - func->set_retstatus(NORETURN); - func->obj()->cs()->incrementCounter(PARSE_NORETURN_HEURISTIC); - } - else - { - func->set_retstatus(RETURN); - } - updated.push_back(func); - } + if(recursive) + { + func->set_retstatus(NORETURN); + func->obj()->cs()->incrementCounter(PARSE_NORETURN_HEURISTIC); + } + else + { + func->set_retstatus(RETURN); + } + updated.push_back(func); + } set vec = iter->second; - set::iterator vIter; - for (vIter = vec.begin(); vIter != vec.end(); ++vIter) { + for (auto vIter = vec.begin(); vIter != vec.end(); ++vIter) { Function * delayed = (*vIter)->func; if (delayed->retstatus() == UNSET) { delayed->set_retstatus(NORETURN); @@ -552,66 +752,60 @@ Parser::parse_frames(vector & work, bool recursive) } } - // We should have updated the return status of one or more frames; recurse - if (updated.size()) { - for (vector::iterator uIter = updated.begin(); - uIter != updated.end(); - ++uIter) { - resumeFrames((*uIter), work); - } - - if (work.size()) { - parsing_printf("[%s] Updated retstatus of delayed frames, trying again; work.size() = %d\n", - __FILE__, - work.size()); - parse_frames(work, recursive); - } - } else { - // We shouldn't get here - parsing_printf("[%s] No more work can be done (%d funcs with unknown return status)\n", - __FILE__, - delayedFrames.size()); - assert(0); - } - } else { - // We haven't yet reached a fixedpoint; let's recurse - parsing_printf("[%s] Fixed point not yet reached (%d funcs with unknown return status)\n", - __FILE__, - delayedFrames.size()); - - // Update num_delayedFrames for next iteration - num_delayedFrames = delayedFrames.size(); + } - // Check if we can resume any frames yet - vector updated; - for (map >::iterator iter = delayedFrames.begin(); - iter != delayedFrames.end(); - ++iter) { - if (iter->first->_rs != UNSET) { - updated.push_back(iter->first); - } + // We should have updated the return status of one or more frames; recurse + if (updated.size()) { + for (auto uIter = updated.begin(); + uIter != updated.end(); + ++uIter) { + resumeFrames((*uIter), work); } - if (updated.size()) { - for (vector::iterator uIter = updated.begin(); - uIter != updated.end(); - ++uIter) { - resumeFrames((*uIter), work); - } + if (work.peek()) { + parsing_printf("[%s] Updated retstatus of delayed frames, trying again...\n", __FILE__); + parse_frames(work, recursive); } - - // Recurse through parse_frames - parsing_printf("[%s] Calling parse_frames again, work.size() = %d\n", - __FILE__, - work.size()); - parse_frames(work, recursive); + } else { + // We shouldn't get here + parsing_printf("[%s] No more work can be done (%d funcs with unknown return status)\n", + __FILE__, + delayed_frames.frames.size()); + assert(0); } +} - for(unsigned i=0;iremove_frame(frames[i]); - delete frames[i]; +void Parser::cleanup_frames() { + vector pfv; + std::copy(frames.begin(), frames.end(), std::back_inserter(pfv)); +#if USE_OPENMP +#pragma omp parallel for schedule(auto) + for (unsigned int i = 0; i < pfv.size(); i++) { + ParseFrame *pf = pfv[i]; + if (pf) { + _parse_data->remove_frame(pf); + delete pf; } - frames.clear(); + } + frames.clear(); +#elif USE_CILK + cilk_for(unsigned i=0; i < pfv.size(); ++i) { + ParseFrame *pf = pfv[i]; + if (pf) { + _parse_data->remove_frame(pf); + delete pf; + } + } +#else + for(unsigned i=0; i < pfv.size(); ++i) { + ParseFrame *pf = pfv[i]; + if (pf) { + _parse_data->remove_frame(pf); + delete pf; + } + } +#endif + frames.clear(); } /* Finalizing all functions for consumption: @@ -620,56 +814,101 @@ Parser::parse_frames(vector & work, bool recursive) - Prepare and record FuncExtents for range-based lookup */ -// Could set cache_valid depending on whether the function is currently -// being parsed somewhere. - void Parser::finalize(Function *f) { + boost::lock_guard g(*f); if(f->_cache_valid) { return; } if(!f->_parsed) { parsing_printf("[%s:%d] Parser::finalize(f[%lx]) " - "forced parsing\n", - FILE__,__LINE__,f->addr()); - parse(); + "forced parsing\n", + FILE__,__LINE__,f->addr()); + parse_at(f->region(), f->addr(), true, f->src()); } - bool cache_value = true; - /* this is commented out to prevent a failure in tampersStack, but + bool cache_value = true; + /* this is commented out to prevent a failure in tampersStack, but this may be an incorrect approach to fixing the problem. - if(frame_status(f->region(), f->addr()) < ParseFrame::PARSED) { - // XXX prevent caching of blocks, extents for functions that - // are actively being parsed. This prevents callbacks and other - // functions called from within, e.g. parse_frame from setting - // the caching flag and preventing later updates to the blocks() - // vector during finalization. - cache_value = false; - }*/ + if(frame_status(f->region(), f->addr()) < ParseFrame::PARSED) { + // XXX prevent caching of blocks, extents for functions that + // are actively being parsed. This prevents callbacks and other + // functions called from within, e.g. parse_frame from setting + // the caching flag and preventing later updates to the blocks() + // vector during finalization. + cache_value = false; + }*/ parsing_printf("[%s] finalizing %s (%lx)\n", - FILE__,f->name().c_str(),f->addr()); + FILE__,f->name().c_str(),f->addr()); - region_data * rd = _parse_data->findRegion(f->region()); - assert(rd); // finish delayed parsing and sorting Function::blocklist blocks = f->blocks_int(); + // Check whether there are tail calls to blocks within the same function + dyn_hash_map visited; + for (auto bit = blocks.begin(); bit != blocks.end(); ++bit) { + Block * b = *bit; + visited[b] = true; + } + int block_cnt = 0; + for (auto bit = blocks.begin(); bit != blocks.end(); ++bit) { + Block * b = *bit; + block_cnt++; + for (auto eit = b->targets().begin(); eit != b->targets().end(); ++eit) { + ParseAPI::Edge *e = *eit; + if (e->interproc() && (e->type() == DIRECT || e->type() == COND_TAKEN)) { + if (visited.find(e->trg()) != visited.end() && e->trg() != f->entry()) { + // Find a tail call targeting a block within the same function. + // If the jump target is the function entry, + // it is a recursive tail call. + // Otherwise, this edge is not a tail call + e->_type._interproc = false; + parsing_printf("from %lx to %lx, marked as not tail call\n", b->last(), e->trg()->start()); + } + } + } + } + + // Check whether the function contains only one block, + // and the block contains only an unresolve indirect jump. + // If it is the case, change the edge to tail call if necessary. + // + // This is part of the tail call heuristics. + // However, during parsing, the entry block may be created by + // the function, or may be created by another function sharing code. + // If the block is created by a larger function, the heuristic will + // not mark the edge as tail call + if (block_cnt == 1) { + Block *b = f->entry(); + Block::Insns insns; + b->getInsns(insns); + if (insns.size() == 1 && insns.begin()->second.getCategory() == c_BranchInsn) { + for (auto eit = b->targets().begin(); eit != b->targets().end(); ++eit) { + ParseAPI::Edge *e = *eit; + if (e->type() == INDIRECT || e->type() == DIRECT) { + e->_type._interproc = true; + parsing_printf("from %lx to %lx, marked as tail call\n", b->last(), e->trg()->start()); + } + } + } + } + // is this the first time we've parsed this function? if (unlikely( !f->_extents.empty() )) { _parse_data->remove_extents(f->_extents); f->_extents.clear(); } - + if(blocks.empty()) { f->_cache_valid = cache_value; // see above return; } - + auto bit = blocks.begin(); FuncExtent * ext = NULL; Address ext_s = (*bit)->start(); @@ -679,16 +918,28 @@ Parser::finalize(Function *f) Block * b = *bit; if(b->start() > ext_e) { ext = new FuncExtent(f,ext_s,ext_e); + + // remove access history for ext before publishing it + // to concurrent readers to avoid false race reports. + // ext is written before it is published and only read + // thereafter. + race_detector_forget_access_history(ext, sizeof(*ext)); + parsing_printf("%lx extent [%lx,%lx)\n",f->addr(),ext_s,ext_e); f->_extents.push_back(ext); - rd->funcsByRange.insert(ext); ext_s = b->start(); } ext_e = b->end(); } ext = new FuncExtent(f,ext_s,ext_e); + + // remove access history for ext before publishing it + // to concurrent readers to avoid false race reports. + // ext is written before it is published and only read + // thereafter. + race_detector_forget_access_history(ext, sizeof(*ext)); + parsing_printf("%lx extent [%lx,%lx)\n",f->addr(),ext_s,ext_e); - rd->funcsByRange.insert(ext); f->_extents.push_back(ext); f->_cache_valid = cache_value; // see comment at function entry @@ -699,14 +950,15 @@ Parser::finalize(Function *f) // the FT block is also a branch target) Function::edgelist & edges = f->_call_edge_list; for (Function::edgelist::iterator eit = edges.begin(); - eit != edges.end(); + eit != edges.end(); eit++) { + boost::lock_guard g(*(*eit)->src()); if (2 > (*eit)->src()->targets().size()) { Block *ft = _parse_data->findBlock((*eit)->src()->region(), (*eit)->src()->end()); if (ft && HASHDEF(f->_bmap,ft->start())) { - link((*eit)->src(),ft,CALL_FT,false); + link_block((*eit)->src(),ft,CALL_FT,false); } } } @@ -716,10 +968,16 @@ Parser::finalize(Function *f) void Parser::finalize() { - ScopeLock<> l(finalize_lock); if(_parse_state < FINALIZED) { + split_overlapped_blocks(); + finalize_funcs(hint_funcs); finalize_funcs(discover_funcs); + clean_bogus_funcs(discover_funcs); + + finalize_ranges(hint_funcs); + finalize_ranges(discover_funcs); + _parse_state = FINALIZED; } } @@ -727,14 +985,217 @@ Parser::finalize() void Parser::finalize_funcs(vector &funcs) { - vector::iterator fit = funcs.begin(); - for( ; fit != funcs.end(); ++fit) { - finalize(*fit); - } + vector thread_local_funcs; + std::copy(funcs.begin(), funcs.end(), std::back_inserter(thread_local_funcs)); +#if USE_OPENMP + #pragma omp parallel for schedule(auto) + for(int i = 0; i < thread_local_funcs.size(); ++i) { + Function *f = thread_local_funcs[i]; + f->finalize(); + } +#elif USE_CILK + cilk_for(int i = 0; i < thread_local_funcs.size(); ++i) { + Function *f = thread_local_funcs[i]; + f->finalize(); + } +#else + for(int i = 0; i < thread_local_funcs.size(); ++i) { + Function *f = thread_local_funcs[i]; + f->finalize(); + } +#endif + +} + +void +Parser::finalize_ranges(vector &funcs) +{ + for (int i = 0; i < funcs.size(); ++i) { + Function *f = funcs[i]; + region_data * rd = _parse_data->findRegion(f->region()); + for (auto eit = f->extents().begin(); eit != f->extents().end(); ++eit) + rd->funcsByRange.insert(*eit); + } +} + +void +Parser::clean_bogus_funcs(vector &funcs) +{ + for (auto fit = funcs.begin(); fit != funcs.end(); ) { + Function *f = *fit; + if (f->src() == HINT) { + fit++; + continue; + } + bool interprocEdge = false; + // Here we do not need locking because we + // are single-threaded during finalizing + for (auto eit = f->entry()->sources().begin(); !interprocEdge && eit != f->entry()->sources().end(); ++eit) + if ((*eit)->interproc()) interprocEdge = true; + if (!interprocEdge) { + parsing_printf("Removing function %lx with name %s\n", f->addr(), f->name().c_str()); + // This is a discovered function that has no inter-procedural entry edge. + // This function should be created because tail call heuristic makes a mistake + // We have already fixed such bogos tail calls in the previous step of finalizing, + // so now we should remove such bogus function + if (sorted_funcs.end() != sorted_funcs.find(f)) { + sorted_funcs.erase(f); + } + fit = funcs.erase(fit); + _parse_data->remove_func(f); + } else { + fit++; + } + } } void -Parser::record_func(Function *f) { +Parser::split_overlapped_blocks() +{ + vector regData; + _parse_data->getAllRegionData(regData); + for (auto rit = regData.begin(); rit != regData.end(); ++rit) { + region_data *rd = *rit; + // First get all basic blocks in this region data + map allBlocks; + rd->getAllBlocks(allBlocks); + // Split blocks needs to do range lookup + for (auto bit = allBlocks.begin(); bit != allBlocks.end(); ++bit) { + Block * b = bit->second; + rd->insertBlockByRange(b); + } + split_consistent_blocks(rd, allBlocks); + split_inconsistent_blocks(rd, allBlocks); + } + +} + +void +Parser::split_consistent_blocks(region_data* rd, map &allBlocks) { + // We do not need to create new blocks in such cases + for (auto bit = allBlocks.begin(); bit != allBlocks.end(); ++bit) { + Block* b = bit->second; + Block* edge_b = b; + set overlappingBlocks; + rd->findBlocks(b->start(), overlappingBlocks); + if (overlappingBlocks.size() > 1) { + for (auto obit = overlappingBlocks.begin(); obit != overlappingBlocks.end(); ++obit) { + Block * ob = *obit; + if (ob == b) continue; + Address previnsn; + if (ob->consistent(b->start(), previnsn)) { + parsing_printf("in finalizing , split block [%lx, %lx), at %lx\n", ob->start(), ob->end(), b->start()); + // For consistent blocks, + // we only need to create a new fall through edge + // and move edges + move_edges_consistent_blocks(ob, b); + rd->blocksByRange.remove(ob); + ob->updateEnd(b->start()); + ob->_lastInsn = previnsn; + link_block(ob, b,FALLTHROUGH,false); + rd->insertBlockByRange(ob); + } + } + } + } +} + +static bool AbruptEndBlock(Block *b) { + for (auto eit = b->targets().begin(); eit != b->targets().end(); ++eit) + if ((*eit)->sinkEdge() && (*eit)->type() == DIRECT) return true; + return false; +} + +void +Parser::split_inconsistent_blocks(region_data* rd, map &allBlocks) { + // Now, let's deal with inconsistent overlapping blocks + // We will need to create new blocks + for (auto bit = allBlocks.begin(); bit != allBlocks.end(); ++bit) { + Block* b = bit->second; + if (AbruptEndBlock(b)) continue; + set overlappingBlocks; + rd->findBlocks(b->start(), overlappingBlocks); + if (overlappingBlocks.size() > 1) { + for (auto obit = overlappingBlocks.begin(); obit != overlappingBlocks.end(); ++obit) { + Block * ob = *obit; + if (ob == b) continue; + if (AbruptEndBlock(ob)) continue; + Address previnsn; + if (!ob->consistent(b->start(), previnsn)) { + Block::Insns b1_insns; + Block::Insns b2_insns; + b->getInsns(b1_insns); + ob->getInsns(b2_insns); + //assert(b->end() == ob->end()); + Address cur = 0; + for (auto iit = b1_insns.begin(); iit != b1_insns.end(); ++iit) { + cur = iit->first; + if (b2_insns.find(cur) != b2_insns.end()) { + // The two blocks align + rd->blocksByRange.remove(ob); + rd->blocksByRange.remove(b); + + // We only need to keep one copy of the outgoing edges + Block * newB = factory()._mkblock(b->obj(), b->region(), cur); + newB->updateEnd(b->end()); + newB->_lastInsn = b->_lastInsn; + newB->_parsed = true; + newB = record_block(newB); + + set targets; + Block::edgelist &trgs = ob ->_trglist; + Block::edgelist::iterator tit = trgs.begin(); + for (; tit != trgs.end(); ++tit) { + ParseAPI::Edge *e = *tit; + e->_source = newB; + newB->addTarget(e); + targets.insert(e->trg()); + } + trgs.clear(); + + Block::edgelist &trgs2 = b->_trglist; + tit = trgs2.begin(); + // Copy the outgoing edges to the new block + for (; tit != trgs2.end(); ++tit) { + ParseAPI::Edge *e = *tit; + Block* trg = e->trg(); + if (targets.find(trg) != targets.end()) { + trg->removeSource(e); + } else { + e->_source = newB; + newB->addTarget(e); + targets.insert(trg); + } + } + trgs2.clear(); + + + b->updateEnd(cur); + auto iter = b1_insns.find(cur); + --iter; + b->_lastInsn = iter ->first; + link_block(b,newB,FALLTHROUGH,false); + + iter = b2_insns.find(cur); + --iter; + ob->updateEnd(cur); + ob->_lastInsn = iter->first; + link_block(ob, newB, FALLTHROUGH, false); + + rd->insertBlockByRange(b); + rd->insertBlockByRange(ob); + rd->insertBlockByRange(newB); + break; + } + } + } + } + } + } +} +void +Parser::record_func(Function *f) +{ if(!f) return; if(f->src() == HINT) @@ -750,21 +1211,22 @@ Parser::record_func(Function *f) { void Parser::init_frame(ParseFrame & frame) { - Block * b = NULL; + boost::lock_guard g(frame); + Block * b = NULL; Block * split = NULL; - if ( ! frame.func->_entry ) + if ( ! frame.func->_entry ) { // Find or create a block - b = block_at(frame.func, frame.func->addr(),split); + b = block_at(frame, frame.func, frame.func->addr(),split, NULL); if(b) { frame.leadersToBlock[frame.func->addr()] = b; frame.func->_entry = b; - frame.seed = new ParseWorkElem(NULL,NULL,frame.func->addr(),true,false); + frame.seed = new ParseWorkElem(NULL,NULL,0, frame.func->addr(),true,false); frame.pushWork(frame.seed); } else { parsing_printf("[%s] failed to initialize parsing frame\n", - FILE__); + FILE__); return; } if (split) { @@ -774,23 +1236,24 @@ Parser::init_frame(ParseFrame & frame) // FIXME these operations should move into the actual parsing Address ia_start = frame.func->addr(); - unsigned size = - frame.codereg->offset() + frame.codereg->length() - ia_start; + unsigned size = + frame.codereg->offset() + frame.codereg->length() - ia_start; const unsigned char* bufferBegin = - (const unsigned char *)(frame.func->isrc()->getPtrToInstruction(ia_start)); + (const unsigned char *)(frame.func->isrc()->getPtrToInstruction(ia_start)); InstructionDecoder dec(bufferBegin,size,frame.codereg->getArch()); - InstructionAdapter_t* ah = InstructionAdapter_t::makePlatformIA_IAPI(b->obj()->cs()->getArch(), + InstructionAdapter_t* ah = InstructionAdapter_t::makePlatformIA_IAPI(obj().cs()->getArch(), dec, ia_start, frame.func->obj(), - frame.codereg, frame.func->isrc(), b); - if(ah->isStackFramePreamble()) { + frame.codereg, frame.func->isrc(), b); + if(ah->isStackFramePreamble()) { frame.func->_no_stack_frame = false; - } + } frame.func->_saves_fp = ah->savesFP(); delete ah; } void ParseFrame::cleanup() { + boost::lock_guard g(*this); for(unsigned i=0;i const& elems = b->elems(); + vector::const_iterator it = elems.begin(); + for( ; it != elems.end(); ++it) { + if((*it)->edge()->type() == CALL) + return (*it); + } + return NULL; + } /* * Look up the next block for detection of straight-line * fallthrough edges into existing blocks. */ - inline std::pair get_next_block( - Address addr, - CodeRegion * codereg, - ParseData * _parse_data) - { - Block * nextBlock = NULL; - Address nextBlockAddr; - - nextBlockAddr = numeric_limits
::max(); - region_data * rd = _parse_data->findRegion(codereg); - - if((nextBlock = rd->blocksByRange.successor(addr)) && - nextBlock->start() > addr) - { - nextBlockAddr = nextBlock->start(); - } - - return std::pair(nextBlockAddr,nextBlock); - } } void Parser::parse_frame(ParseFrame & frame, bool recursive) { - /** Persistent intermediate state **/ - InstructionAdapter_t *ahPtr = NULL; - ParseFrame::worklist_t & worklist = frame.worklist; - dyn_hash_map & leadersToBlock = frame.leadersToBlock; - Address & curAddr = frame.curAddr; - Function * func = frame.func; - dyn_hash_map & visited = frame.visited; - unsigned & num_insns = frame.num_insns; - func->_cache_valid = false; - - /** Non-persistent intermediate state **/ - Address nextBlockAddr; - Block * nextBlock; + frame.func->_cache_valid = false; if (frame.status() == ParseFrame::UNPARSED) { parsing_printf("[%s] ==== starting to parse frame %lx ====\n", - FILE__,frame.func->addr()); + FILE__,frame.func->addr()); // prevents recursion of parsing frame.func->_parsed = true; } else { parsing_printf("[%s] ==== resuming parse of frame %lx ====\n", - FILE__,frame.func->addr()); + FILE__,frame.func->addr()); // Pull work that can be resumed off the delayedWork list std::map::iterator iter; - + vector updated; vector::iterator uIter; for (iter = frame.delayedWork.begin(); - iter != frame.delayedWork.end(); - ++iter) { - if (iter->second->_rs != UNSET) { + iter != frame.delayedWork.end(); + ++iter) { + if (iter->second->retstatus() != UNSET) { frame.pushWork(iter->first); updated.push_back(iter->first); } @@ -881,86 +1325,147 @@ Parser::parse_frame(ParseFrame & frame, bool recursive) { } } - frame.set_status(ParseFrame::PROGRESS); + // The resolving jump tables depend on the current shape of CFG. + // We use a fix-point analysis, where we we-analyze jump tables + // that may need re-analysis, which may find new out-going edges + int count = 0; + do { + count++; + parsing_printf("Iteration %d for function %s at %lx\n", count, frame.func->name().c_str(), frame.func->addr()); + bool ret = parse_frame_one_iteration(frame, recursive); + if (ret) return; + } while (inspect_value_driven_jump_tables(frame)); + + /** parsing complete **/ + if (HASHDEF(plt_entries,frame.func->addr())) { + // For PLT entries, they are either NORETURN or RETURN. + // They should not be in any cyclic dependency + if (obj().cs()->nonReturning(plt_entries[frame.func->addr()])) { + frame.func->set_retstatus(NORETURN); + } else { + frame.func->set_retstatus(RETURN); + } + + // Convenience -- adopt PLT name + frame.func->_name = plt_entries[frame.func->addr()]; + } else if (frame.func->retstatus() == UNSET) { + frame.func->set_retstatus(NORETURN); + } + + frame.set_status(ParseFrame::PARSED); + + if (unlikely(obj().defensiveMode())) { + // calculate this after setting the function to PARSED, so that when + // we finalize the function we'll actually save the results and won't + // re-finalize it + frame.func->tampersStack(); + } + _pcb.newfunction_retstatus( frame.func ); +} + +bool +Parser::parse_frame_one_iteration(ParseFrame &frame, bool recursive) { + InstructionAdapter_t *ahPtr = NULL; + ParseFrame::worklist_t & worklist = frame.worklist; + map & leadersToBlock = frame.leadersToBlock; + Address & curAddr = frame.curAddr; + Function * func = frame.func; + dyn_hash_map & visited = frame.visited; + unsigned & num_insns = frame.num_insns; + + /** Non-persistent intermediate state **/ + Address nextBlockAddr; + Block * nextBlock; while(!worklist.empty()) { - + Block * cur = NULL; ParseWorkElem * work = frame.popWork(); if (work->order() == ParseWorkElem::call) { + region_data::edge_data_map::accessor a; + region_data::edge_data_map* edm = _parse_data->get_edge_data_map(func->region()); + assert(edm->find(a, work->source())); + parsing_printf("Handling call work element\n"); + cur = a->second.b; Function * ct = NULL; - - if (!work->callproc()) { - // If we're not doing recursive traversal, skip *all* of the call edge processing. - // We don't want to create a stub. We'll handle the assumption of a fallthrough - // target for the fallthrough work element, not the call work element. Catch blocks - // will get excluded but that's okay; our heuristic is not reliable enough that I'm willing to deploy - // it when we'd only be detecting a non-returning callee by name anyway. - // --BW 12/2012 - if (!recursive) { - parsing_printf("[%s] non-recursive parse skipping call %lx->%lx\n", - FILE__, work->edge()->src()->lastInsnAddr(), work->target()); - continue; - } - - parsing_printf("[%s] binding call %lx->%lx\n", - FILE__,work->edge()->src()->lastInsnAddr(),work->target()); - pair ctp = - bind_call(frame, - work->target(), - work->edge()->src(), - work->edge()); - ct = ctp.first; + // If we're not doing recursive traversal, skip *all* of the call edge processing. + // We don't want to create a stub. We'll handle the assumption of a fallthrough + // target for the fallthrough work element, not the call work element. Catch blocks + // will get excluded but that's okay; our heuristic is not reliable enough that I'm willing to deploy + // it when we'd only be detecting a non-returning callee by name anyway. + // --BW 12/2012 + if (!recursive) { + parsing_printf("[%s] non-recursive parse skipping call %lx->%lx\n", + FILE__, cur->lastInsnAddr(), work->target()); + continue; + } + + FuncSource how = RT; + if(frame.func->_src == GAP || frame.func->_src == GAPRT) + how = GAPRT; - work->mark_call(); + ct = _parse_data->createAndRecordFunc(frame.codereg, work->target(), how); + if (ct) { + _pcb.discover_function(ct); } else { - ct = _parse_data->findFunc(frame.codereg,work->target()); + ct = _parse_data->findFunc(frame.codereg, work->target()); + } + bool frame_parsing_not_started = + (frame_status(ct->region(),ct->addr())==ParseFrame::UNPARSED || + frame_status(ct->region(),ct->addr())==ParseFrame::BAD_LOOKUP); + parsing_printf("\tframe %lx, UNPARSED: %d, BAD_LOOKUP %d\n", ct->addr(), frame_status(ct->region(),ct->addr())==ParseFrame::UNPARSED,frame_status(ct->region(),ct->addr())==ParseFrame::BAD_LOOKUP); + + + if (!frame_parsing_not_started && !work->callproc()) { + parsing_printf("[%s] binding call (call target should have been parsed) %lx->%lx\n", + FILE__,cur->lastInsnAddr(),work->target()); + Function *tfunc = _parse_data->findFunc(frame.codereg,work->target()); + pair ctp = + bind_call(frame, + work->target(), + cur, + work->edge()); + work->mark_call(); } - if (recursive && ct && - (frame_status(ct->region(),ct->addr())==ParseFrame::UNPARSED || - frame_status(ct->region(),ct->addr())==ParseFrame::BAD_LOOKUP)) { + if (recursive && ct && frame_parsing_not_started) { // suspend this frame and parse the next - parsing_printf(" [suspend frame %lx]\n", func->addr()); + parsing_printf(" [suspend frame %lx]\n", func->addr()); frame.call_target = ct; frame.set_status(ParseFrame::CALL_BLOCKED); // need to re-visit this edge frame.pushWork(work); - if (ahPtr) delete ahPtr; - return; + if (ahPtr) delete ahPtr; + return true; } else if (ct && work->tailcall()) { - // XXX The target has been or is currently being parsed (else - // the previous conditional would have been taken), - // so if its return status is unset then this - // function has to take UNKNOWN - if (func->_rs != RETURN) { - if (ct->_rs > NORETURN) - func->set_retstatus(ct->_rs); - else if (ct->_rs == UNSET) - frame.pushDelayedWork(work, ct); + // If func's return status is RETURN, + // then this tail callee does not impact the func's return status + if (func->retstatus() != RETURN) { + update_function_ret_status(frame, ct, work); } } continue; } else if (work->order() == ParseWorkElem::call_fallthrough) { // check associated call edge's return status - Edge * ce = bundle_call_edge(work->bundle()); - if (!ce) { + ParseWorkElem * call_elem = bundle_call_elem(work->bundle()); + if (!call_elem) { // odd; no call edge in this bundle parsing_printf("[%s] unexpected missing call edge at %lx\n", - FILE__,work->edge()->src()->lastInsnAddr()); + FILE__,work->edge()->src()->lastInsnAddr()); } else { // check for system call FT - Edge* edge = work->edge(); + ParseAPI::Edge* edge = work->edge(); Block::Insns blockInsns; +// boost::lock_guard src_guard(*edge->src()); edge->src()->getInsns(blockInsns); auto prev = blockInsns.rbegin(); - InstructionAPI::InstructionPtr prevInsn = prev->second; + InstructionAPI::Instruction prevInsn = prev->second; bool is_nonret = false; - if (prevInsn->getOperation().getID() == e_syscall) { + if (prevInsn.getOperation().getID() == e_syscall) { Address src = edge->src()->lastInsnAddr(); @@ -970,40 +1475,43 @@ Parser::parse_frame(ParseFrame & frame, bool recursive) { // If we cannot retrieve a syscall number, assume the syscall returns parsing_printf("[%s] could not retrieve syscall edge, assuming returns\n", FILE__); } else { - if (obj().cs()->nonReturningSyscall(syscallNumber)) { - is_nonret = true; - } - } + if (obj().cs()->nonReturningSyscall(syscallNumber)) { + is_nonret = true; + } + } if (is_nonret) { parsing_printf("[%s] no fallthrough for non-returning syscall\n", - FILE__, - work->edge()->src()->lastInsnAddr()); + FILE__, + work->edge()->src()->lastInsnAddr()); // unlink tempsink fallthrough edge - Edge * remove = work->edge(); + ParseAPI::Edge * remove = work->edge(); remove->src()->removeTarget(remove); - factory().destroy_edge(remove); + factory().destroy_edge(remove, destroyed_noreturn); continue; } - } else { - Address target = ce->trg()->start(); + } else if (call_elem->target() > 0) { + // For indirect calls, since we do not know the callee, + // the call fallthrough edges are assumed to exist + Address target = call_elem->target(); Function * ct = _parse_data->findFunc(frame.codereg,target); + assert(ct); bool is_plt = false; // check if associated call edge's return status is still unknown - if (ct && (ct->_rs == UNSET) ) { + if (ct && (ct->retstatus() == UNSET) ) { // Delay parsing until we've finished the corresponding call edge parsing_printf("[%s] Parsing FT edge %lx, corresponding callee (%s) return status unknown; delaying work\n", - __FILE__, - work->edge()->src()->lastInsnAddr(), - ct->name().c_str()); + __FILE__, + work->edge()->src()->lastInsnAddr(), + ct->name().c_str()); // Add work to ParseFrame's delayed list frame.pushDelayedWork(work, ct); // Continue other work for this frame - continue; + continue; } is_plt = HASHDEF(plt_entries,target); @@ -1031,119 +1539,126 @@ Parser::parse_frame(ParseFrame & frame, bool recursive) { is_nonret |= (ct->retstatus() == UNKNOWN); if (is_nonret) { parsing_printf("\t Disallowing FT edge: function in " - "defensive binary may not return\n"); + "defensive binary may not return\n"); mal_printf("Disallowing FT edge: function %lx in " - "defensive binary may not return\n", ct->addr()); + "defensive binary may not return\n", ct->addr()); } else { StackTamper ct_tamper = ct->tampersStack(); is_nonret |= (TAMPER_NONZERO == ct_tamper); is_nonret |= (TAMPER_ABS == ct_tamper); if (is_nonret) { mal_printf("Disallowing FT edge: function at %lx " - "tampers with its stack\n", ct->addr()); + "tampers with its stack\n", ct->addr()); parsing_printf("\t Disallowing FT edge: function " - "tampers with its stack\n"); + "tampers with its stack\n"); } } } if (is_nonret) { parsing_printf("[%s] no fallthrough for non-returning call " - "to %lx at %lx\n",FILE__,target, - work->edge()->src()->lastInsnAddr()); + "to %lx at %lx\n",FILE__,target, + work->edge()->src()->lastInsnAddr()); // unlink tempsink fallthrough edge - Edge * remove = work->edge(); - remove->src()->removeTarget(remove); - factory().destroy_edge(remove); - continue; + ParseAPI::Edge * remove = work->edge(); + //remove->src()->removeTarget(remove); + factory().destroy_edge(remove, destroyed_noreturn); + continue; } else - // Invalidate cache_valid for all sharing functions - invalidateContainingFuncs(func, ce->src()); + // Invalidate cache_valid for all sharing functions + invalidateContainingFuncs(func, work->edge()->src()); } } } else if (work->order() == ParseWorkElem::seed_addr) { cur = leadersToBlock[work->target()]; } else if (work->order() == ParseWorkElem::resolve_jump_table) { - // resume to resolve jump table - parsing_printf("... continue parse indirect jump at %lx\n", work->ah()->getAddr()); - Block *nextBlock = work->cur(); - if (nextBlock->last() != work->ah()->getAddr()) { - // The block has been split - region_data * rd = _parse_data->findRegion(frame.codereg); - set blocks; - rd->blocksByRange.find(work->ah()->getAddr(), blocks); - for (auto bit = blocks.begin(); bit != blocks.end(); ++bit) { - if ((*bit)->last() == work->ah()->getAddr()) { - nextBlock = *bit; - break; - } - } - - } - ProcessCFInsn(frame,nextBlock,work->ah()); + // resume to resolve jump table + auto work_ah = work->ah(); + parsing_printf("... continue parse indirect jump at %lx\n", work_ah->getAddr()); + ProcessCFInsn(frame,NULL,work->ah()); + frame.value_driven_jump_tables.insert(work_ah->getAddr()); continue; - } - // call fallthrough case where we have already checked that - // the target returns. this is used in defensive mode. + } + // call fallthrough case where we have already checked that + // the target returns. this is used in defensive mode. else if (work->order() == ParseWorkElem::checked_call_ft) { Edge* ce = bundle_call_edge(work->bundle()); if (ce != NULL) { invalidateContainingFuncs(func, ce->src()); } else { parsing_printf("[%s] unexpected missing call edge at %lx\n", - FILE__,work->edge()->src()->lastInsnAddr()); + FILE__,work->edge()->src()->lastInsnAddr()); } + } else if (work->order() == ParseWorkElem::func_shared_code) { + if (func->retstatus() != RETURN) { + // The current function shares code with another function. + // current function on this control flow path is the same + // as the shared function. + // + update_function_ret_status(frame, work->shared_func(), work); + } + func->_cache_valid = false; + continue; + } - + if (NULL == cur) { - pair newedge = - add_edge(frame, - frame.func, - work->edge()->src(), - work->target(), - work->edge()->type(), - work->edge()); + pair newedge = + add_edge(frame, + frame.func, + work->edge()->src(), + work->source(), + work->target(), + work->edge()->type(), + work->edge()); cur = newedge.first; } if (HASHDEF(visited,cur->start())) { - parsing_printf("[%s] skipping locally parsed target at %lx\n", - FILE__,work->target()); + parsing_printf("[%s] skipping locally parsed target at %lx, [%lx, %lx)\n", + FILE__,work->target(), cur->start(), cur->end()); continue; - } - visited[cur->start()] = true; - leadersToBlock[cur->start()] = cur; + } - if (!cur->_parsed) + // Multiple functions can get accesses to a block, + // but only the function that creates the block should + // parse the block + if (cur->createdByFunc() == frame.func && !cur->_parsed) { parsing_printf("[%s] parsing block %lx\n", - FILE__,cur->start()); + FILE__,cur->start()); if (frame.func->obj()->defensiveMode()) { mal_printf("new block at %lx (0x%lx)\n",cur->start(), cur); } cur->_parsed = true; curAddr = cur->start(); - } else { + visited[cur->start()] = true; + leadersToBlock[cur->start()] = cur; + } else if (cur->createdByFunc() != frame.func) { parsing_printf("[%s] deferring parse of shared block %lx\n", - FILE__,cur->start()); - if (func->_rs < UNKNOWN) { - // we've parsed into another function, if we've parsed - // into it's entry point, set retstatus to match it - Function * other_func = _parse_data->findFunc( - func->region(), cur->start()); - if (other_func && other_func->retstatus() > UNKNOWN) { - func->set_retstatus(other_func->retstatus()); - } else { - func->set_retstatus(UNKNOWN); - } + FILE__,cur->start()); + if (func->retstatus() < UNKNOWN) { + // The current function shares code with the function + // that created the block. So, the return status of the + // current function on this control flow path is the same + // as the shared function. + // + // This code is designed for the new POWER ABI, + // where each function has two entries. But this code + // also works if the functions that share the code + // have the same return blocks. + Function * other_func = cur->createdByFunc(); + update_function_ret_status(frame, other_func, frame.mkWork(NULL, other_func)); } - // The edge to this shared block is changed from - // "going to sink" to going to this shared block. - // This changes the function boundary, so we need to - // invalidate the cache. - func->_cache_valid = false; + // The edge to this shared block is changed from + // "going to sink" to going to this shared block. + // This changes the function boundary, so we need to + // invalidate the cache. + func->_cache_valid = false; + continue; + } else { continue; } @@ -1157,25 +1672,27 @@ Parser::parse_frame(ParseFrame & frame, bool recursive) { // NB Using block's region() here because it may differ from the // function's if control flow has jumped to another region - unsigned size = - cur->region()->offset() + cur->region()->length() - curAddr; + unsigned size = + cur->region()->offset() + cur->region()->length() - curAddr; const unsigned char* bufferBegin = - (const unsigned char *)(func->isrc()->getPtrToInstruction(curAddr)); + (const unsigned char *)(func->isrc()->getPtrToInstruction(curAddr)); InstructionDecoder dec(bufferBegin,size,frame.codereg->getArch()); if (!ahPtr) - ahPtr = InstructionAdapter_t::makePlatformIA_IAPI(func->obj()->cs()->getArch(), dec, curAddr, func->obj(), - cur->region(), func->isrc(), cur); + ahPtr = InstructionAdapter_t::makePlatformIA_IAPI(func->obj()->cs()->getArch(), dec, curAddr, func->obj(), + cur->region(), func->isrc(), cur); else ahPtr->reset(dec,curAddr,func->obj(), cur->region(), func->isrc(), cur); - - InstructionAdapter_t * ah = ahPtr; - - using boost::tuples::tie; - tie(nextBlockAddr,nextBlock) = get_next_block( - frame.curAddr, frame.codereg, _parse_data); + InstructionAdapter_t * ah = ahPtr; + + nextBlockAddr = std::numeric_limits
::max(); + auto nextBlockIter = frame.leadersToBlock.upper_bound(frame.curAddr); + if (nextBlockIter != frame.leadersToBlock.end()) { + nextBlockAddr = nextBlockIter->first; + nextBlock = nextBlockIter->second; + } bool isNopBlock = ah->isNop(); while(true) { @@ -1183,167 +1700,119 @@ Parser::parse_frame(ParseFrame & frame, bool recursive) { /** Check for straight-line fallthrough **/ if (curAddr == nextBlockAddr) { parsing_printf("[%s] straight-line parse into block at %lx\n", - FILE__,curAddr); + FILE__,curAddr); if (frame.func->obj()->defensiveMode()) { mal_printf("straight-line parse into block at %lx\n",curAddr); } ah->retreat(); curAddr = ah->getAddr(); - end_block(cur,ah); - pair newedge = - add_edge(frame,frame.func,cur, - nextBlockAddr,FALLTHROUGH,NULL); - - if (!HASHDEF(visited,nextBlockAddr) && - !HASHDEF(leadersToBlock,nextBlockAddr)) { - parsing_printf("[%s:%d] pushing %lx onto worklist\n", - FILE__,__LINE__,nextBlockAddr); - - frame.pushWork( + end_block(cur,ahPtr); + if (!set_edge_parsing_status(frame, cur->last(), cur)) break; + ParseAPI::Edge* newedge = link_tempsink(cur, FALLTHROUGH); + parsing_printf("[%s:%d] pushing %lx onto worklist\n", + FILE__,__LINE__,nextBlockAddr); + frame.pushWork( frame.mkWork( - NULL, - newedge.second, - nextBlockAddr, - true, - false) - ); - /* preserved as example of leaky code; use mkWork instead - frame.pushWork( - new ParseWorkElem( - NULL, - newedge.second, - nextBlockAddr, - true, - false) - ); - */ - leadersToBlock[nextBlockAddr] = nextBlock; - } + NULL, + newedge, + ahPtr->getAddr(), + nextBlockAddr, + true, + false) + ); break; - } else if (curAddr > nextBlockAddr) { - parsing_printf("[%s:%d] inconsistent instruction stream: " - "%lx is within [%lx,%lx)\n", - FILE__,__LINE__,curAddr, - nextBlock->start(),nextBlock->end()); - Address prev_insn; - if (nextBlock->consistent(curAddr, prev_insn)) { - // The two overlapping blocks aligned. - // We need to split the large block, and create new edge to the later block - Block* new_block = split_block(frame.func, nextBlock, curAddr, prev_insn); - ah->retreat(); - end_block(cur, ah); - add_edge(frame, frame.func, cur, curAddr, FALLTHROUGH, NULL); - leadersToBlock[curAddr] = new_block; - - // We break from this loop because no need more stright-line parsing - break; - } - - // NB "cur" hasn't ended, so its range may - // not look like it overlaps with nextBlock - _pcb.overlapping_blocks(cur,nextBlock); - - tie(nextBlockAddr,nextBlock) = - get_next_block(frame.curAddr, frame.codereg, _parse_data); - } + } - // per-instruction callback notification + // per-instruction callback notification ParseCallback::insn_details insn_det; insn_det.insn = ah; - - parsing_printf("[%s:%d] curAddr 0x%lx: %s \n", - FILE__,__LINE__,curAddr, insn_det.insn->getInstruction()->format().c_str() ); + + parsing_printf("[%s:%d] curAddr 0x%lx: %s \n", + FILE__,__LINE__,curAddr, insn_det.insn->getInstruction().format().c_str() ); if (func->_is_leaf_function) { Address ret_addr; - func->_is_leaf_function = !(insn_det.insn->isReturnAddrSave(ret_addr)); - parsing_printf("[%s:%d] leaf %d funcname %s \n", - FILE__,__LINE__,func->_is_leaf_function, func->name().c_str()); - if (!func->_is_leaf_function) func->_ret_addr = ret_addr; + func->_is_leaf_function = !(insn_det.insn->isReturnAddrSave(ret_addr)); + parsing_printf("[%s:%d] leaf %d funcname %s \n", + FILE__,__LINE__,func->_is_leaf_function, func->name().c_str()); + if (!func->_is_leaf_function) func->_ret_addr = ret_addr; } - + _pcb.instruction_cb(func,cur,curAddr,&insn_det); if (isNopBlock && !ah->isNop()) { ah->retreat(); - end_block(cur,ah); - pair newedge = - add_edge(frame,frame.func,cur,curAddr,FALLTHROUGH,NULL); - Block * targ = newedge.first; - - parsing_printf("[%s:%d] nop-block ended at %lx\n", - FILE__,__LINE__,curAddr); - if (targ && !HASHDEF(visited,targ->start())) { - parsing_printf("[%s:%d] pushing %lx onto worklist\n", - FILE__,__LINE__,targ->start()); + end_block(cur,ahPtr); + if (!set_edge_parsing_status(frame,cur->last(), cur)) break; + ParseAPI::Edge* newedge = link_tempsink(cur, FALLTHROUGH); - frame.pushWork( + parsing_printf("[%s:%d] nop-block ended at %lx\n", + FILE__,__LINE__,curAddr); + parsing_printf("[%s:%d] pushing %lx onto worklist\n", + FILE__,__LINE__,curAddr); + frame.pushWork( frame.mkWork( - NULL, - newedge.second, - targ->start(), - true, - false) - ); - leadersToBlock[targ->start()] = targ; - } + NULL, + newedge, + ah->getAddr(), + curAddr, + true, + false) + ); break; } - + /** Particular instruction handling (calls, branches, etc) **/ - ++num_insns; + ++num_insns; if(ah->hasCFT()) { - if (ah->isIndirectJump()) { - // Create a work element to represent that - // we will resolve the jump table later - end_block(cur,ah); - frame.pushWork( frame.mkWork( work->bundle(), cur, ah)); - } else { - ProcessCFInsn(frame,cur,ah); - } - break; + if (ah->isIndirectJump()) { + // Create a work element to represent that + // we will resolve the jump table later + end_block(cur,ahPtr); + if (!set_edge_parsing_status(frame,cur->last(), cur)) break; + frame.pushWork( frame.mkWork( work->bundle(), cur, ahPtr)); + } else { + end_block(cur,ahPtr); + if (!set_edge_parsing_status(frame,cur->last(), cur)) break; + ProcessCFInsn(frame,cur,ahPtr); + } + break; } else if (func->_saves_fp && func->_no_stack_frame && ah->isFrameSetupInsn()) { // isframeSetup is expensive - func->_no_stack_frame = false; + func->_no_stack_frame = false; } else if (ah->isLeave()) { func->_no_stack_frame = false; } else if ( ah->isAbort() ) { // 4. `abort-causing' instructions - end_block(cur,ah); - //link(cur, _sink, DIRECT, true); - break; + end_block(cur,ahPtr); + //link(cur, sink_block, DIRECT, true); + break; } else if ( ah->isInvalidInsn() ) { // 4. Invalid or `abort-causing' instructions - end_block(cur,ah); - link(cur, _sink, DIRECT, true); - break; + end_block(cur,ahPtr); + if (!set_edge_parsing_status(frame,cur->last(), cur)) break; + link_addr(ahPtr->getAddr(), _sink, DIRECT, true, func); + break; } else if ( ah->isInterruptOrSyscall() ) { // 5. Raising instructions - end_block(cur,ah); - - pair newedge = - add_edge(frame,frame.func,cur,ah->getNextAddr(),FALLTHROUGH,NULL); - Block * targ = newedge.first; - - if (targ && !HASHDEF(visited,targ->start()) && - !HASHDEF(leadersToBlock,targ->start())) { - parsing_printf("[%s:%d] pushing %lx onto worklist\n", - FILE__,__LINE__,targ->start()); - - frame.pushWork( + end_block(cur,ahPtr); + if (!set_edge_parsing_status(frame,cur->last(), cur)) break; + ParseAPI::Edge* newedge = link_tempsink(cur, FALLTHROUGH); + parsing_printf("[%s:%d] pushing %lx onto worklist\n", + FILE__,__LINE__,curAddr); + frame.pushWork( frame.mkWork( - NULL, - newedge.second, - targ->start(), - true, - false) - ); - leadersToBlock[targ->start()] = targ; - } + NULL, + newedge, + ahPtr->getAddr(), + curAddr, + true, + false) + ); if (unlikely(func->obj()->defensiveMode())) { fprintf(stderr,"parsed bluepill insn sysenter or syscall " "in defensive mode at %lx\n",curAddr); @@ -1354,14 +1823,15 @@ Parser::parse_frame(ParseFrame & frame, bool recursive) { // add instrumentation at this addr so we can // extend the function if this really executes ParseCallback::default_details det( - (unsigned char*) cur->region()->getPtrToInstruction(cur->lastInsnAddr()), - cur->end() - cur->lastInsnAddr(), - true); + (unsigned char*) cur->region()->getPtrToInstruction(cur->lastInsnAddr()), + cur->end() - cur->lastInsnAddr(), + true); _pcb.abruptEnd_cf(cur->lastInsnAddr(),cur,&det); _pcb.foundWeirdInsns(func); - end_block(cur,ah); + end_block(cur,ahPtr); + if (!set_edge_parsing_status(frame,cur->last(), cur)) break; // allow invalid instructions to end up as a sink node. - link(cur, _sink, DIRECT, true); + link_addr(ahPtr->getAddr(), _sink, DIRECT, true, func); break; } else if (ah->isNopJump()) { // patch the jump to make it a nop, and re-set the @@ -1370,16 +1840,17 @@ Parser::parse_frame(ParseFrame & frame, bool recursive) { // instruction to be parsed correctly mal_printf("Nop jump at %lx, changing it to nop\n",ah->getAddr()); _pcb.patch_nop_jump(ah->getAddr()); - unsigned bufsize = - func->region()->offset() + func->region()->length() - ah->getAddr(); + unsigned bufsize = + func->region()->offset() + func->region()->length() - ah->getAddr(); + func->region()->offset() + func->region()->length() - ahPtr->getAddr(); const unsigned char* bufferBegin = (const unsigned char *) - (func->isrc()->getPtrToInstruction(ah->getAddr())); + (func->isrc()->getPtrToInstruction(ah->getAddr())); dec = InstructionDecoder - (bufferBegin, bufsize, frame.codereg->getArch()); - ah->reset(dec, curAddr, func->obj(), - func->region(), func->isrc(), cur); + (bufferBegin, bufsize, frame.codereg->getArch()); + ah->reset(dec, curAddr, func->obj(), + func->region(), func->isrc(), cur); } else { - entryID id = ah->getInstruction()->getOperation().getID(); + entryID id = ah->getInstruction().getOperation().getID(); switch (id) { case e_rdtsc: fprintf(stderr,"parsed bluepill insn rdtsc at %lx\n",curAddr); @@ -1400,18 +1871,21 @@ Parser::parse_frame(ParseFrame & frame, bool recursive) { parsing_printf("[%s] next insn %lx is invalid\n", FILE__,ah->getNextAddr()); - end_block(cur,ah); + end_block(cur,ahPtr); + if (!set_edge_parsing_status(frame, cur->last(), cur)) break; // We need to tag the block with a sink edge - link(cur, _sink, DIRECT, true); + link_addr(ahPtr->getAddr(), _sink, DIRECT, true, func); + break; } else if (!cur->region()->contains(ah->getNextAddr())) { parsing_printf("[%s] next address %lx is outside [%lx,%lx)\n", - FILE__,ah->getNextAddr(), - cur->region()->offset(), - cur->region()->offset()+cur->region()->length()); - end_block(cur,ah); + FILE__,ah->getNextAddr(), + cur->region()->offset(), + cur->region()->offset()+cur->region()->length()); + end_block(cur,ahPtr); + if (!set_edge_parsing_status(frame, cur->last(), cur)) break; // We need to tag the block with a sink edge - link(cur, _sink, DIRECT, true); + link_addr(ahPtr->getAddr(), _sink, DIRECT, true, func); break; } ah->advance(); @@ -1421,158 +1895,142 @@ Parser::parse_frame(ParseFrame & frame, bool recursive) { // Check if parsing is complete if (!frame.delayedWork.empty()) { frame.set_status(ParseFrame::FRAME_DELAYED); - return; - } - - /** parsing complete **/ - if (HASHDEF(plt_entries,frame.func->addr())) { -// if (obj().cs()->nonReturning(frame.func->addr())) { - if (obj().cs()->nonReturning(plt_entries[frame.func->addr()])) { - frame.func->set_retstatus(NORETURN); - } else { - frame.func->set_retstatus(UNKNOWN); - } - - // Convenience -- adopt PLT name - frame.func->_name = plt_entries[frame.func->addr()]; - } else if (frame.func->_rs == UNSET) { - frame.func->set_retstatus(NORETURN); - } - - frame.set_status(ParseFrame::PARSED); - - if (unlikely(obj().defensiveMode())) { - // calculate this after setting the function to PARSED, so that when - // we finalize the function we'll actually save the results and won't - // re-finalize it - func->tampersStack(); - _pcb.newfunction_retstatus( func ); + return true; } + return false; } void Parser::end_block(Block * b, InstructionAdapter_t * ah) { - b->_lastInsn = ah->getAddr(); b->updateEnd(ah->getNextAddr()); - - record_block(b); + b->_lastInsn = ah->getAddr(); } -void +Block* Parser::record_block(Block *b) { parsing_printf("[%s:%d] recording block [%lx,%lx)\n", - FILE__,__LINE__,b->start(),b->end()); - _parse_data->record_block(b->region(),b); + FILE__,__LINE__,b->start(),b->end()); + return _parse_data->record_block(b->region(),b); } +// block_at should only be called when +// we know the we want to create a block within the function. +// So, we should not call this function to create the entry block +// of a callee function. Block * -Parser::block_at( - Function * owner, - Address addr, - Block * & split) +Parser::block_at(ParseFrame &frame, + Function * owner, + Address addr, + Block * & split, + Block * src) { - set overlap; +// ScopeLock > l(work_mutex); + Block * exist = NULL; Block * ret = NULL; Block * inconsistent = NULL; Address prev_insn = 0; split = NULL; - CodeRegion *cr; if(owner->region()->contains(addr)) cr = owner->region(); else cr = _parse_data->reglookup(owner->region(),addr); + if(!is_code(owner,addr)) { parsing_printf("[%s] block address %lx rejected by isCode()\n", - FILE__,addr); + FILE__,addr); return NULL; } - if(NULL == (exist = _parse_data->findBlock(cr,addr))) { - _parse_data->findBlocks(cr,addr,overlap); - if(overlap.size() > 1) - parsing_printf("[%s] address %lx overlapped by %d blocks\n", - FILE__,addr,overlap.size()); - - /* Platform specific consistency test: - generally checking for whether the address is an - instruction boundary in a block */ - for(set::iterator sit=overlap.begin();sit!=overlap.end();++sit) - { - Block * b = *sit; - // consistent will fill in prev_insn with the address of the - // instruction preceeding addr if addr is consistent - if(b->consistent(addr,prev_insn)) { - exist = b; - break; - } else { - parsing_printf("[%s] %lx is inconsistent with [%lx,%lx)\n", - FILE__,addr,b->start(),b->end()); - if(inconsistent) { - parsing_printf(" multiple inconsistent blocks!\n"); - } - inconsistent = b; - } - } + { +#ifdef ENABLE_RACE_DETECTION + // this lock causes deadlock when running in parallel, but it is + // useful for suppressing unimportant races on the iterator + boost::lock_guard g(*owner); +#endif + // An already existing block + auto iter = frame.leadersToBlock.find(addr); + if (iter != frame.leadersToBlock.end()) { + return iter->second; } - - if(exist) { - if(exist->start() == addr) { - parsing_printf("[%s] block %lx exists\n", - FILE__,addr); - ret = exist; - } - else { - parsing_printf("[%s] address %lx splits [%lx,%lx) (%p)\n", - FILE__,addr,exist->start(),exist->end(),exist); - if (owner->obj()->defensiveMode()) { - mal_printf("new block at %lx splits [%lx %lx)\n", - addr, exist->start(), exist->end()); - } - split = exist; - ret = split_block(owner,exist,addr,prev_insn); - } - } else { - ret = factory()._mkblock(owner,cr,addr); - record_block(ret); - _pcb.addBlock(owner, ret); + // A block that may need to be split + /* + iter = frame.leadersToBlock.upper_bound(addr); + if (iter != frame.leadersToBlock.begin()) { + --iter; } - - if(unlikely(inconsistent)) { - _pcb.overlapping_blocks(ret,inconsistent); + if (iter != frame.leadersToBlock.end()) { + Block* b = iter->second; + Address prev_insn; + if (b->consistent(addr, prev_insn)) { + if (src == b) { + ret = split_block(owner, b, addr, prev_insn); + split = b; + frame.visited[ret->start()] = true; + return ret; + } + region_data::edge_data_map::accessor a; + region_data::edge_data_map* edm = _parse_data->get_edge_data_map(owner->region()); + assert(edm->find(a, b->last())); + if (a->second.b == b) { + ret = split_block(owner, b, addr, prev_insn); + split = b; + frame.visited[ret->start()] = true; + return ret; + } else if (a->second.b->consistent(addr, prev_insn)){ + ret = split_block(owner, a->second.b, addr, prev_insn); + split = a->second.b; + frame.visited[ret->start()] = true; + return ret; + } + } } - + */ + ret = _cfgfact._mkblock(owner, cr, addr); + ret = record_block(ret); return ret; + } } -pair +pair Parser::add_edge( - ParseFrame & frame, - Function * owner, - Block * src, - Address dst, - EdgeTypeEnum et, - Edge * exist) + ParseFrame & frame, + Function * owner, + Block * src, + Address src_addr, + Address dst, + EdgeTypeEnum et, + ParseAPI::Edge * exist) { Block * split = NULL; Block * ret = NULL; - Edge * newedge = NULL; - pair retpair((Block *) NULL, (Edge *) NULL); + Block * original_block = NULL; + ParseAPI::Edge * newedge = NULL; + pair retpair((Block *) NULL, (ParseAPI::Edge *) NULL); if(!is_code(owner,dst)) { parsing_printf("[%s:%d] target address %lx rejected by isCode()\n", FILE__, __LINE__, dst); return retpair; } - - ret = block_at(owner,dst,split); + region_data::edge_data_map::accessor a; + region_data::edge_data_map* edm = _parse_data->get_edge_data_map(owner->region()); + assert(edm->find(a, src_addr)); + src = a->second.b; + assert(src->last() == src_addr); + + // The source block of the edge may have been split + // since adding into the worklist. We use the edge + // source address and follow fall-througth edge + // to find the correct block object + ret = block_at(frame, owner,dst, split, src); retpair.first = ret; if(split == src) { @@ -1580,17 +2038,24 @@ Parser::add_edge( src = ret; } - if(split && HASHDEF(frame.visited,split->start())) { - // prevent "delayed parsing" of extant block if - // this frame has already visited it - frame.visited[ret->start()] = true; + if(et != CALL && frame.leadersToBlock.find(ret->start()) == frame.leadersToBlock.end()) { + // If we created a new block, and this is not a function call, + // then the new block is part of the current function. + // We need to mark it frame.leadersToBlock[ret->start()] = ret; } if(NULL == exist) { - newedge = link(src,ret,et,false); + newedge = link_block(src,ret,et,false); retpair.second = newedge; } else { + assert(src->last() == src_addr); + if (exist->type() == FALLTHROUGH || exist->type() == COND_NOT_TAKEN || exist->type() == CALL_FT) { + if (src->end() != ret->start()) { +fprintf(stderr, "src_addr %lx, src: [%lx, %lx), dst [%lx, %lx), target %lx, edge type %d\n", src_addr, src->start(), src->end(), ret->start(), src->end(), dst, et); + } + } + relink(exist,src,ret); retpair.second = exist; } @@ -1598,13 +2063,37 @@ Parser::add_edge( return retpair; } +Block* +Parser::follow_fallthrough(Block *b, Address addr) +{ + if (addr == 0) return b; + while (b->last() != addr) { + bool find_ft = false; + Block::edgelist targets; + b->copy_targets(targets); + for (auto eit = targets.begin(); eit != targets.end(); ++eit) { + if ((*eit)->type() == FALLTHROUGH) { + b = (*eit)->trg(); + find_ft = true; + break; + } + } + if (!find_ft) { + fprintf(stderr, "WARNING: Block [%lx, %lx) with last %lx does not align with address %lx, and cannot find fall-through edge\n", b->start(), b->end(), b->last(), addr); + return NULL; + } + } + return b; +} + Block * Parser::split_block( - Function * owner, - Block *b, - Address addr, - Address previnsn) + Function * owner, + Block *b, + Address addr, + Address previnsn) { + parsing_printf("split_block split block [%lx, %lx) at %lx in function %s\n", b->start(), b->end(), addr, owner->name().c_str()); Block * ret; CodeRegion * cr; bool isRetBlock = false; @@ -1618,31 +2107,30 @@ Parser::split_block( // assert(b->consistent(addr); ret = factory()._mkblock(owner,cr,addr); - - // move out edges - vector & trgs = b->_trglist; - vector::iterator tit = trgs.begin(); - for(;tit!=trgs.end();++tit) { - Edge *e = *tit; - e->_source = ret; - ret->_trglist.push_back(e); - } - if (!trgs.empty() && RET == (*trgs.begin())->type()) { - isRetBlock = true; - } - trgs.clear(); - ret->updateEnd(b->_end); + ret->updateEnd(b->end()); ret->_lastInsn = b->_lastInsn; ret->_parsed = true; - link(b,ret,FALLTHROUGH,false); - record_block(ret); - // b's range has changed - rd->blocksByRange.remove(b); + // Should only publish this block after range is set + Block * exist = record_block(ret); + bool block_exist = false; + if (exist != ret) { + block_exist = true; + ret = exist; + } + Block::edgelist & trgs = b->_trglist; + if (!trgs.empty() && RET == (*trgs.begin())->type()) { + isRetBlock = true; + } + move_edges_consistent_blocks(b, ret); b->updateEnd(addr); b->_lastInsn = previnsn; - rd->blocksByRange.insert(b); + edge_parsing_data epd = _parse_data->setEdgeParsingStatus(b->region(), b->last(), owner, b); + if (epd.f != owner || epd.b != b) { + parsing_printf("Spliting block [%lx, %lx) at %lx. However, %lx already has edge parsed. This Should not happen\n", b->start(), ret->end(), ret->start(), ret->start()); + } + link_block(b,ret,FALLTHROUGH,false); // Any functions holding b that have already been finalized // need to have their caches invalidated so that they will // find out that they have this new 'ret' block @@ -1653,48 +2141,37 @@ Parser::split_block( { Function * po = *oit; if (po->_cache_valid) { - po->_cache_valid = false; - parsing_printf("[%s:%d] split of [%lx,%lx) invalidates cache of " - "func at %lx\n", - FILE__,__LINE__,b->start(),b->end(),po->addr()); + po->_cache_valid = false; + parsing_printf("[%s:%d] split of [%lx,%lx) invalidates cache of " + "func at %lx\n", + FILE__,__LINE__,b->start(),b->end(),po->addr()); } if (isRetBlock) { - po->_retBL.clear(); //could remove b from the vector instead of clearing it, not sure what's cheaper + po->_retBL.clear(); //could remove b from the vector instead of clearing it, not sure what's cheaper } } // KEVINTODO: study performance impact of this callback _pcb.splitBlock(b,ret); - return ret; - } +} -pair -Parser::bind_call(ParseFrame & frame, Address target, Block * cur, Edge * exist) +pair +Parser::bind_call(ParseFrame & frame, Address target, Block * cur, ParseAPI::Edge * exist) { Function * tfunc = NULL; Block * tblock = NULL; - FuncSource how = RT; - if(frame.func->_src == GAP || frame.func->_src == GAPRT) - how = GAPRT; // look it up - tfunc = _parse_data->get_func(frame.codereg,target,how); + tfunc = _parse_data->findFunc(frame.codereg,target); if(!tfunc) { parsing_printf("[%s:%d] can't bind call to %lx\n", - FILE__,__LINE__,target); - return pair((Function *) NULL,exist); - } - - // add an edge - pair ret = add_edge(frame,tfunc,cur,target,CALL,exist); - tblock = ret.first; - if(!tblock) { - parsing_printf("[%s:%d] can't bind call to %lx\n", - FILE__,__LINE__,target); - return pair((Function *) NULL,exist); + FILE__,__LINE__,target); + return pair((Function *) NULL,exist); } - - return pair(tfunc,ret.second); + assert(tfunc->entry()); + + relink(exist,cur,tfunc->entry()); + return pair(tfunc,exist); } Function * @@ -1702,44 +2179,44 @@ Parser::findFuncByEntry(CodeRegion *r, Address entry) { if(_parse_state < PARTIAL) { parsing_printf("[%s:%d] Parser::findFuncByEntry([%lx,%lx),%lx) " - "forced parsing\n", - FILE__,__LINE__,r->low(),r->high(),entry); + "forced parsing\n", + FILE__,__LINE__,r->low(),r->high(),entry); parse(); } return _parse_data->findFunc(r,entry); } -int +int Parser::findFuncs(CodeRegion *r, Address addr, set & funcs) { if(_parse_state < COMPLETE) { parsing_printf("[%s:%d] Parser::findFuncs([%lx,%lx),%lx,...) " - "forced parsing\n", - FILE__,__LINE__,r->low(),r->high(),addr); + "forced parsing\n", + FILE__,__LINE__,r->low(),r->high(),addr); parse(); } if(_parse_state < FINALIZED) { parsing_printf("[%s:%d] Parser::findFuncs([%lx,%lx),%lx,...) " - "forced finalization\n", - FILE__,__LINE__,r->low(),r->high(),addr); + "forced finalization\n", + FILE__,__LINE__,r->low(),r->high(),addr); finalize(); } return _parse_data->findFuncs(r,addr,funcs); } -int +int Parser::findFuncs(CodeRegion *r, Address start, Address end, set & funcs) { if(_parse_state < COMPLETE) { parsing_printf("[%s:%d] Parser::findFuncs([%lx,%lx),%lx,%lx) " - "forced parsing\n", - FILE__,__LINE__,r->low(),r->high(),start,end); + "forced parsing\n", + FILE__,__LINE__,r->low(),r->high(),start,end); parse(); } if(_parse_state < FINALIZED) { parsing_printf("[%s:%d] Parser::findFuncs([%lx,%lx),%lx,%lx) " - "forced finalization\n", - FILE__,__LINE__,r->low(),r->high(),start,end); + "forced finalization\n", + FILE__,__LINE__,r->low(),r->high(),start,end); finalize(); } return _parse_data->findFuncs(r,start,end,funcs); @@ -1750,8 +2227,8 @@ Parser::findBlockByEntry(CodeRegion *r, Address entry) { if(_parse_state < PARTIAL) { parsing_printf("[%s:%d] Parser::findBlockByEntry([%lx,%lx),%lx) " - "forced parsing\n", - FILE__,__LINE__,r->low(),r->high(),entry); + "forced parsing\n", + FILE__,__LINE__,r->low(),r->high(),entry); parse(); } return _parse_data->findBlock(r,entry); @@ -1762,8 +2239,8 @@ Parser::findNextBlock(CodeRegion *r, Address addr) { if(_parse_state < PARTIAL) { parsing_printf("[%s:%d] Parser::findBlockByEntry([%lx,%lx),%lx) " - "forced parsing\n", - FILE__,__LINE__,r->low(),r->high(),addr); + "forced parsing\n", + FILE__,__LINE__,r->low(),r->high(),addr); parse(); } return _parse_data->findRegion(r)->get_next_block(addr).second; @@ -1774,16 +2251,16 @@ Parser::findBlocks(CodeRegion *r, Address addr, set & blocks) { if(_parse_state < COMPLETE) { parsing_printf("[%s:%d] Parser::findBlocks([%lx,%lx),%lx,...) " - "forced parsing\n", - FILE__,__LINE__,r->low(),r->high(),addr); + "forced parsing\n", + FILE__,__LINE__,r->low(),r->high(),addr); parse(); } - return _parse_data->findBlocks(r,addr,blocks); + return _parse_data->findBlocks(r,addr,blocks); } // find blocks without parsing. -int Parser::findCurrentBlocks(CodeRegion* cr, Address addr, - std::set& blocks) { +int Parser::findCurrentBlocks(CodeRegion* cr, Address addr, + std::set& blocks) { return _parse_data->findBlocks(cr, addr, blocks); } @@ -1791,19 +2268,47 @@ int Parser::findCurrentFuncs(CodeRegion * cr, Address addr, std::set return _parse_data->findFuncs(cr, addr, funcs); } -Edge* -Parser::link(Block *src, Block *dst, EdgeTypeEnum et, bool sink) +/* This function creates an edge by specifying + * the source address. This function will look + * up the source address in the block end map. + * So, any function that calls this function should + * not acquire an accessor to the source address + */ + +ParseAPI::Edge* +Parser::link_addr(Address src_addr, Block *dst, EdgeTypeEnum et, bool sink, Function * func) { + region_data::edge_data_map::accessor a; + region_data::edge_data_map* edm = _parse_data->get_edge_data_map(func->region()); + assert(edm->find(a, src_addr)); + Block * src = a->second.b; + return link_block(src, dst, et, sink); +} + +/* This function creates an edge by specifying + * the source Block. Any function that calls this + * function should first acquire an accessor to + * the source address and lookup the block object. + * + * Otherwise, the source block may be split and cause + * wrong edges. + */ +ParseAPI::Edge* +Parser::link_block(Block* src, Block *dst, EdgeTypeEnum et, bool sink) +{ + if (et == FALLTHROUGH) + assert(src->end() == dst->start()); assert(et != NOEDGE); - Edge * e = factory()._mkedge(src,dst,et); + ParseAPI::Edge * e = factory()._mkedge(src,dst,et); e->_type._sink = sink; - src->_trglist.push_back(e); - dst->_srclist.push_back(e); + src->addTarget(e); + dst->addSource(e); _pcb.addEdge(src, e, ParseCallback::target); _pcb.addEdge(dst, e, ParseCallback::source); return e; } + /* * During parsing, all edges are temporarily linked to the _tempsink * block. Adding and then removing edges to and from this block is @@ -1818,45 +2323,59 @@ Parser::link(Block *src, Block *dst, EdgeTypeEnum et, bool sink) * parsing callbacks are the only ones who can see this state; * they have been warned and should know better. */ -Edge* +ParseAPI::Edge* Parser::link_tempsink(Block *src, EdgeTypeEnum et) { - Edge * e = factory()._mkedge(src,_sink,et); + // Do not put the edge into block target list at this moment, + // because the source block is likely to be split. + Block* tmpsink = parse_data()->findBlock(src->region(), std::numeric_limits
::max()); + ParseAPI::Edge * e = factory()._mkedge(src, tmpsink,et); e->_type._sink = true; - src->_trglist.push_back(e); return e; } void -Parser::relink(Edge * e, Block *src, Block *dst) +Parser::relink(ParseAPI::Edge * e, Block *src, Block *dst) { - bool addSrcAndDest = true; - if(src != e->src()) { - e->src()->removeTarget(e); - _pcb.removeEdge(e->src(), e, ParseCallback::target); - e->_source = src; - src->addTarget(e); - _pcb.addEdge(src, e, ParseCallback::target); - addSrcAndDest = false; + if (e->type() == FALLTHROUGH || e->type() == COND_NOT_TAKEN || e->type() == CALL_FT) { + if (src->end() != dst->start()) { +fprintf(stderr, "In relink : src [%lx, %lx) dst [%lx, %lx)\n", src->start(), src->end(), dst->start(), dst->end()); +assert(src->end() == dst->start()); + } } - if(dst != e->trg()) { - if(e->trg() != _sink) { - e->trg()->removeSource(e); + unsigned long srcOut = 0, dstIn = 0, oldDstIn = 0; + Block* oldDst = NULL; + if(e->trg() && e->trg_addr() != std::numeric_limits
::max()) { + oldDst = e->trg(); + } + bool addSrcAndDest = true; + if(dst != e->trg()) { + if(oldDst) // old edge was not sink + { + oldDst->removeSource(e); _pcb.removeEdge(e->trg(), e, ParseCallback::source); addSrcAndDest = false; } - e->_target = dst; + e->_target_off = dst->start(); dst->addSource(e); _pcb.addEdge(dst, e, ParseCallback::source); - if (addSrcAndDest) { - // We're re-linking a sinkEdge to be a non-sink edge; since - // we don't inform PatchAPI of temporary sinkEdges, we have - // to add both the source AND target edges - _pcb.addEdge(src, e, ParseCallback::target); - } } - e->_type._sink = (dst == _sink); + // Add the edge into the block's target list + e->_source = src; + src->addTarget(e); + _pcb.addEdge(src, e, ParseCallback::target); + + if (addSrcAndDest) { + // We're re-linking a sinkEdge to be a non-sink edge; since + // we don't inform PatchAPI of temporary sinkEdges, we have + // to add both the source AND target edges + _pcb.addEdge(src, e, ParseCallback::target); + } + if(parse_data()->findBlock(dst->region(), dst->start()) != dst) { + assert(!"another block already exist!"); + } + e->_type._sink = (dst->start() == std::numeric_limits
::max()); } ParseFrame::Status @@ -1891,23 +2410,32 @@ Parser::remove_func(Function *func) } } } - + _parse_data->remove_func(func); } void Parser::remove_block(Dyninst::ParseAPI::Block *block) { + boost::lock_guard g(*_parse_data, boost::adopt_lock); _parse_data->remove_block(block); } void Parser::move_func(Function *func, Address new_entry, CodeRegion *new_reg) { region_data *reg_data = _parse_data->findRegion(func->region()); - reg_data->funcsByAddr.erase(func->addr()); - reg_data = _parse_data->findRegion(new_reg); - reg_data->funcsByAddr[new_entry] = func; + race_detector_fake_lock_acquire(race_detector_fake_lock(reg_data->funcsByAddr)); + { + tbb::concurrent_hash_map::accessor a; + if(reg_data->funcsByAddr.find(a, func->addr())) + { + reg_data->funcsByAddr.erase(a); + } + reg_data = _parse_data->findRegion(new_reg); + reg_data->funcsByAddr.insert(a, make_pair(new_entry, func)); + } + race_detector_fake_lock_release(race_detector_fake_lock(reg_data->funcsByAddr)); } void Parser::invalidateContainingFuncs(Function *owner, Block *b) @@ -1918,7 +2446,7 @@ void Parser::invalidateContainingFuncs(Function *owner, Block *b) else cr = _parse_data->reglookup(owner->region(),b->start()); region_data * rd = _parse_data->findRegion(cr); - + // Any functions holding b that have already been finalized // need to have their caches invalidated so that they will @@ -1931,53 +2459,54 @@ void Parser::invalidateContainingFuncs(Function *owner, Block *b) Function * po = *oit; po->_cache_valid = false; parsing_printf("[%s:%d] split of [%lx,%lx) invalidates cache of " - "func at %lx\n", + "func at %lx\n", FILE__,__LINE__,b->start(),b->end(),po->addr()); - } + } } /* Add ParseFrames waiting on func back to the work queue */ -void Parser::resumeFrames(Function * func, vector & work) +void Parser::resumeFrames(Function * func, LockFreeQueue & work) { // If we do not know the function's return status, don't put its waiters back on the worklist - if (func->_rs == UNSET) { + if (func->retstatus() == UNSET) { parsing_printf("[%s] %s return status unknown, cannot resume waiters\n", - __FILE__, - func->name().c_str()); - return; + __FILE__, + func->name().c_str()); + return; } + boost::lock_guard g(delayed_frames); // When a function's return status is set, all waiting frames back into the worklist - map >::iterator iter = delayedFrames.find(func); - if (iter == delayedFrames.end()) { + map >::iterator iter = delayed_frames.frames.find(func); + if (iter == delayed_frames.frames.end()) { // There were no frames waiting, ignore parsing_printf("[%s] %s return status %d, no waiters\n", - __FILE__, - func->name().c_str(), - func->_rs); + __FILE__, + func->name().c_str(), + func->retstatus()); return; } else { parsing_printf("[%s] %s return status %d, undelaying waiting functions\n", - __FILE__, - func->name().c_str(), - func->_rs); + __FILE__, + func->name().c_str(), + func->retstatus()); // Add each waiting frame back to the worklist set vec = iter->second; - for (set::iterator fIter = vec.begin(); - fIter != vec.end(); - ++fIter) { - work.push_back(*fIter); + for (set::iterator fIter = vec.begin(); + fIter != vec.end(); + ++fIter) { + work.insert(*fIter); } // remove func from delayedFrames map - delayedFrames.erase(func); + delayed_frames.frames.erase(func); } } bool Parser::getSyscallNumber(Function * /*func*/, - Block * block, - Address /*addr*/, - Architecture arch, - long int & val) + Block * block, + Address /*addr*/, + Architecture arch, + long int & val) { val = -1; @@ -1988,8 +2517,8 @@ bool Parser::getSyscallNumber(Function * /*func*/, Block::Insns blockInsns; block->getInsns(blockInsns); auto prevPair = ++(blockInsns.rbegin()); - InstructionAPI::InstructionPtr prevInsn = prevPair->second; - if (prevInsn->getOperation().getID() != e_mov) { + InstructionAPI::Instruction prevInsn = prevPair->second; + if (prevInsn.getOperation().getID() != e_mov) { return false; } @@ -2001,7 +2530,7 @@ bool Parser::getSyscallNumber(Function * /*func*/, InstructionAPI::RegisterAST::Ptr regASTPtr = InstructionAPI::RegisterAST::Ptr(regAST); std::vector operands; - prevInsn->getOperands(operands); + prevInsn.getOperands(operands); for (unsigned i = 0; i < operands.size(); i++) { if (!operands[i].isWritten(regASTPtr)) { InstructionAPI::Expression::Ptr value = operands[i].getValue(); @@ -2011,7 +2540,284 @@ bool Parser::getSyscallNumber(Function * /*func*/, } } } - return (val != -1); } +bool Parser::set_edge_parsing_status(ParseFrame& frame, Address addr, Block* b) { + Function *f = frame.func; + parsing_printf("Function %s tries to set parsing edge at %lx\n", frame.func->name().c_str(), addr); + region_data::edge_data_map * edm = _parse_data->get_edge_data_map(b->region()); + region_data::edge_data_map::accessor a1; + if (edm->insert(a1, addr)) { + // This is the first time that a block ends at this address. + // We record this block and function + a1->second.f = f; + a1->second.b = b; + return true; + } else { + parsing_printf("[%s:%d] parsing edge at %lx has started by another thread, function %s at %lx\n",FILE__, __LINE__, addr, a1->second.f->name().c_str(), a1->second.f->addr()); + // the same function may have created edges before, + // due to overlapping instructions + if (a1->second.f != f) { + // If another function has been here, the current function + // must share code with that function. And the return status + // of the current function depends on the shared function + frame.pushWork(frame.mkWork(NULL, a1->second.f)); + } + + // The current block and the recorded block overlap. + // We attempt to split the blocks. + Block *A, *B; + Function *fA, *fB; + if (b->start() < a1->second.b->start()) { + A = b; + B = a1->second.b; + fA = f; + fB = a1->second.f; + } else { + A = a1->second.b; + B = b; + fA = a1->second.f; + fB = f; + } + assert(A->end() == B->end()); + Address prev_insn; + bool inconsistent = false; + region_data::edge_data_map::accessor a2; + if (A->consistent(B->start(), prev_insn)) { + // The edge should stay with the shorter block + move_edges_consistent_blocks(A,B); + a1->second.f = fB; + a1->second.b = B; + A->updateEnd(B->start()); + A->_lastInsn = prev_insn; + bool cont = true; + // Iteratively split the block + while (!edm->insert(a2, A->last())) { + cont = false; + B = a2->second.b; + if (A->start() < B->start()) { + if (A->consistent(B->start(), prev_insn)) { + A->updateEnd(B->start()); + A->_lastInsn = prev_insn; + cont = true; + } + } else { + if (B->consistent(A->start(), prev_insn)) { + Block * tmp = A; + Function * tmpF = fA; + A = B; + B = tmp; + move_edges_consistent_blocks(A,B); + fA = a2->second.f; + a2->second.b = tmp; + a2->second.f = tmpF; + A->updateEnd(B->start()); + A->_lastInsn = prev_insn; + cont = true; + } + } + if (!cont) { + inconsistent = true; + break; + } + } + if (cont) { + assert(A->end() == B->start()); + link_block(A,B,FALLTHROUGH,false); + a2->second.f = fA; + a2->second.b = A; + } + } else { + inconsistent = true; + } + if (inconsistent) { + Block::Insns A_insns, B_insns; + A->getInsns(A_insns); + B->getInsns(B_insns); + for (auto iit = B_insns.begin(); iit != B_insns.end(); ++iit) { + auto ait = A_insns.find(iit->first); + if (ait != A_insns.end()) { + Address addr = iit->first; + --ait; + --iit; + + Block * ret = factory()._mkblock(fA, b->region(),addr); + ret->updateEnd(B->end()); + ret->_lastInsn = B->_lastInsn; + ret->_parsed = true; + + Block * exist = record_block(ret); + bool block_exist = false; + if (exist != ret) { + block_exist = true; + ret = exist; + } + + move_edges_consistent_blocks(A, ret); + move_edges_consistent_blocks(B, ret); + + A->updateEnd(addr); + A->_lastInsn = ait->first; + B->updateEnd(addr); + B->_lastInsn = iit->first; + + if (a2.empty()) { + a1->second.f = fA; + a1->second.b = ret; + } else { + a2->second.f = fA; + a2->second.b = ret; + } + + link_block(A,ret,FALLTHROUGH,false); + link_block(B,ret,FALLTHROUGH,false); + + region_data::edge_data_map::accessor a3; + assert(edm->insert(a3, A->last())); + a3->second.f = fA; + a3->second.b = A; + region_data::edge_data_map::accessor a4; + assert(edm->insert(a4, B->last())); + a4->second.f = fB; + a4->second.b = B; + break; + } + } + } + return false; + } +} + +void Parser::move_edges_consistent_blocks(Block *A, Block *B) { + /* We move outgoing edges from block A to block B, which is + * necessary when spliting blocks. + * The start of block B should be consistent with block A. + * + * There are three cases: + * + * Case 1: the end of A and B are the same + * A : [ ] + * B : [ ] + * In such case, we can directly move the edges from A to B + * + * Case 2: block A contains block B + * A : [ ] + * B : [ ] + * edge_b : [] + * In this case, the outgoing edges of A should not be moved to B. + * Instead, we need to follow the fallthrough edge of B to find a + * block (edge_b), which ends at same location as A. We then move + * outgoing edges of A to edge_b. + * Case 3: End of A is smaller than the end of B + * A : [ ] + * B : [ ] + * In this case, the outgoing edges of A should only contain a + * fallthrough edge (otherwise, B's end will the same as A). + * We remove this fall through edge for now and we will add the + * edge back in finalizing. + */ + Block* edge_b = B; + if (B->end() < A->end()) { + // For case 2 + edge_b = follow_fallthrough(B, A->last()); + } + Block::edgelist &trgs = A ->_trglist; + Block::edgelist::iterator tit = trgs.begin(); + if (B->end() <= A->end()) { + // In case 1 & 2, we move edges + for (; tit != trgs.end(); ++tit) { + ParseAPI::Edge *e = *tit; + e->_source = edge_b; + edge_b->addTarget(e); + } + } else { + // In case 3, we only remove edges + for (; tit != trgs.end(); ++tit) { + ParseAPI::Edge *e = *tit; + e->trg()->removeSource(e); + } + } + trgs.clear(); +} + +bool Parser::inspect_value_driven_jump_tables(ParseFrame &frame) { + bool ret = false; + ParseWorkBundle *bundle = NULL; + /* Right now, we just re-calculate jump table targets for + * every jump tables. An optimization is to improve the jump + * table analysis to record which indirect jump is value + * driven, and then only re-calculated value driven tables + */ + for (auto bit = frame.value_driven_jump_tables.begin(); + bit != frame.value_driven_jump_tables.end(); + ++bit) { + Address addr = *bit; + region_data::edge_data_map::accessor a; + region_data::edge_data_map* edm = _parse_data->get_edge_data_map(frame.func->region()); + assert(edm->find(a, addr)); + Block * block = a->second.b; + std::vector > outEdges; + IndirectControlFlowAnalyzer icfa(frame.func, block); + icfa.NewJumpTableAnalysis(outEdges); + + // Collect original targets + set
existing; + for (auto eit = block->targets().begin(); eit != block->targets().end(); ++eit) { + existing.insert((*eit)->trg_addr()); + } + bool new_edges = false; + for (auto oit = outEdges.begin(); oit != outEdges.end(); ++oit) { + if (existing.find(oit->first) != existing.end()) continue; + // Find a new target and push it into work list + ret = true; + parsing_printf("Finding new target from block [%lx, %lx) to %lx\n", block->start(), block->end(), oit->first); + ParseAPI::Edge* newedge = link_tempsink(block, oit->second); + frame.knownTargets.insert(oit->first); + + frame.pushWork(frame.mkWork( + NULL, + newedge, + block->last(), + oit->first, + true, + false) + ); + + } + } + return ret; +} + + +void +Parser::update_function_ret_status(ParseFrame &frame, Function * other_func, ParseWorkElem *work) { + /* The return status starts with UNSET, and increases to RETURN, and maybe NORETURN + * Once it is RETURN or NORETURN, it will not go back to UNSET. + * + * Therefore, it is crucial for the following if statements to be the right order: + * First check the smaller values, and then check the larger values. + * + * Consider that if we reverse the order. So the code looks like + * 1) if (other_func->retstatus() == RETURN) { + * .... + * 2) } else if (other_func->retstatus() == UNSET) { + * .... + * } + * In such code structure, at line 1), the other_func can be in UNSET, so the check fails. + * Concurrently, the other_func can be immediately set to RETURN, making the check at + * line 2) failing. So, the frame.func is neither delayed, nor updates its return status + * to RETURN, which can lead to wrong NORETURN status. + */ + parsing_printf("Function %s at %lx share code with function %s at %lx\n", frame.func->name().c_str(), frame.func->addr(), other_func->name().c_str(), other_func->addr()); + if (other_func->retstatus() == UNSET) { + parsing_printf("\t other_func is UNSET, create delayed work\n"); + frame.pushDelayedWork(work, other_func); + } else if (other_func->retstatus() == RETURN) { + parsing_printf("\t other_func is RETURN, set this function to RETURN\n"); + frame.func->set_retstatus(RETURN); + } else { + parsing_printf("\t other_func is NORETURN, this path does not impact the return status of this function\n"); + } + +} diff --git a/parseAPI/src/Parser.h b/parseAPI/src/Parser.h index 5cbc4cdf01..f4bf639d1c 100644 --- a/parseAPI/src/Parser.h +++ b/parseAPI/src/Parser.h @@ -38,6 +38,8 @@ #include "dyntypes.h" #include "IBSTree.h" +#include "LockFreeQueue.h" + #include "IA_IAPI.h" #include "InstructionAdapter.h" @@ -47,56 +49,64 @@ #include "ParseData.h" #include "common/src/dthread.h" +#include +#include +#include using namespace std; typedef Dyninst::InsnAdapter::IA_IAPI InstructionAdapter_t; namespace Dyninst { -namespace ParseAPI { + namespace ParseAPI { - class CFGModifier; + class CFGModifier; /** This is the internal parser **/ -class Parser { - // The CFG modifier needs to manipulate the lookup structures, - // which are internal Parser data. - friend class CFGModifier; - private: - Mutex finalize_lock; + class Parser { + // The CFG modifier needs to manipulate the lookup structures, + // which are internal Parser data. + friend class CFGModifier; + + private: - // Owning code object - CodeObject & _obj; + // Owning code object + CodeObject &_obj; - // CFG object factory - CFGFactory & _cfgfact; + // CFG object factory + CFGFactory &_cfgfact; - // Callback notifications - ParseCallbackManager & _pcb; + // Callback notifications + ParseCallbackManager &_pcb; - // region data store - ParseData * _parse_data; + // region data store + ParseData *_parse_data; // All allocated frames - vector frames; + LockFreeQueue frames; - // Delayed frames - unsigned num_delayedFrames; - std::map > delayedFrames; + // Delayed frames + struct DelayedFrames : public boost::basic_lockable_adapter { + std::map > frames, prev_frames; - // differentiate those provided via hints and - // those found through RT or speculative parsing - vector hint_funcs; - vector discover_funcs; + }; + DelayedFrames delayed_frames; - set sorted_funcs; + // differentiate those provided via hints and + // those found through RT or speculative parsing + vector hint_funcs; + vector discover_funcs; - // PLT, IAT entries - dyn_hash_map plt_entries; + set sorted_funcs; - // a sink block for unbound edges - Block * _sink; + // PLT, IAT entries + dyn_hash_map plt_entries; + // a sink block for unbound edges + boost::atomic _sink; +#ifdef ADD_PARSE_FRAME_TIMERS + tbb::concurrent_hash_map time_histogram; +#endif enum ParseState { UNPARSED, // raw state PARTIAL, // parsing has started @@ -105,128 +115,189 @@ class Parser { UNPARSEABLE // error condition }; ParseState _parse_state; - // XXX sanity checking - bool _in_parse; - bool _in_finalize; - - public: - Parser(CodeObject & obj, CFGFactory & fact, ParseCallbackManager & pcb); - ~Parser(); - - /** Initialization & hints **/ - void add_hint(Function * f); - - // functions - Function * findFuncByEntry(CodeRegion * cr, Address entry); - int findFuncs(CodeRegion * cr, Address addr, set & funcs); - int findFuncs(CodeRegion * cr, Address start, Address end, set & funcs); - - // blocks - Block * findBlockByEntry(CodeRegion * cr, Address entry); - int findBlocks(CodeRegion * cr, Address addr, set & blocks); - // returns current blocks without parsing. - int findCurrentBlocks(CodeRegion* cr, Address addr, std::set& blocks); - int findCurrentFuncs(CodeRegion * cr, Address addr, set & funcs); - - Block * findNextBlock(CodeRegion * cr, Address addr); - - void parse(); - void parse_at(CodeRegion *cr, Address addr, bool recursive, FuncSource src); - void parse_at(Address addr, bool recursive, FuncSource src); - void parse_edges(vector< ParseWorkElem * > & work_elems); - - CFGFactory & factory() const { return _cfgfact; } - CodeObject & obj() { return _obj; } - - // removal - void remove_block(Block *); - void remove_func(Function *); - void move_func(Function *, Address new_entry, CodeRegion *new_reg); - - public: - /** XXX all strictly internals below this point **/ - void record_block(Block *b); - void record_func(Function *f); - - void init_frame(ParseFrame & frame); - - void finalize(Function *f); - - private: - void parse_vanilla(); - void parse_gap_heuristic(CodeRegion *cr); - void probabilistic_gap_parsing(CodeRegion* cr); - //void parse_sbp(); - - ParseFrame::Status frame_status(CodeRegion * cr, Address addr); - - /** CFG structure manipulations **/ - void end_block(Block *b, InstructionAdapter_t * ah); - Block * block_at(Function * owner, - Address addr, - Block * & split); - pair add_edge( - ParseFrame & frame, - Function * owner, - Block * src, - Address dst, - EdgeTypeEnum et, - Edge * exist); - Block * split_block(Function * owner, - Block *b, - Address addr, - Address previnsn); - - Edge* link(Block *src, Block *dst, EdgeTypeEnum et, bool sink); - Edge* link_tempsink(Block *src, EdgeTypeEnum et); - void relink(Edge *exist, Block *src, Block *dst); - - pair bind_call( - ParseFrame & frame, Address target,Block *cur,Edge *exist); - - void parse_frames(std::vector &, bool); + public: + Parser(CodeObject &obj, CFGFactory &fact, ParseCallbackManager &pcb); + + ~Parser(); + + /** Initialization & hints **/ + void add_hint(Function *f); + + // functions + Function *findFuncByEntry(CodeRegion *cr, Address entry); + + int findFuncs(CodeRegion *cr, Address addr, set &funcs); + + int findFuncs(CodeRegion *cr, Address start, Address end, set &funcs); + + // blocks + Block *findBlockByEntry(CodeRegion *cr, Address entry); + + int findBlocks(CodeRegion *cr, Address addr, set &blocks); + + // returns current blocks without parsing. + int findCurrentBlocks(CodeRegion *cr, Address addr, std::set &blocks); + + int findCurrentFuncs(CodeRegion *cr, Address addr, set &funcs); + + Block *findNextBlock(CodeRegion *cr, Address addr); + + void parse(); + + void parse_at(CodeRegion *cr, Address addr, bool recursive, FuncSource src); + + void parse_at(Address addr, bool recursive, FuncSource src); + + void parse_edges(vector &work_elems); + + CFGFactory &factory() const { return _cfgfact; } + + CodeObject &obj() { return _obj; } + + // removal + void remove_block(Block *); + + void remove_func(Function *); + + void move_func(Function *, Address new_entry, CodeRegion *new_reg); + + public: + /** XXX all strictly internals below this point **/ + Block* record_block(Block *b); + + void record_func(Function *f); + + void init_frame(ParseFrame &frame); + + void finalize(Function *f); + + ParseData *parse_data() { return _parse_data; } + + private: + void parse_vanilla(); + void cleanup_frames(); + void parse_gap_heuristic(CodeRegion *cr); + + void probabilistic_gap_parsing(CodeRegion *cr); + //void parse_sbp(); + + ParseFrame::Status frame_status(CodeRegion *cr, Address addr); + + /** CFG structure manipulations **/ + void end_block(Block *b, InstructionAdapter_t *ah); + + Block *block_at(ParseFrame &frame, + Function *owner, + Address addr, + Block *&split, + Block* src); + + pair add_edge( + ParseFrame &frame, + Function *owner, + Block *src, + Address src_addr, + Address dst, + EdgeTypeEnum et, + Edge *exist); + + Block *follow_fallthrough(Block *b, Address addr); + Block *split_block(Function *owner, + Block *b, + Address addr, + Address previnsn); + + Edge *link_addr(Address src, Block *dst, EdgeTypeEnum et, bool sink, Function* func); + Edge *link_block(Block* src, Block *dst, EdgeTypeEnum et, bool sink); + + + Edge *link_tempsink(Block *src, EdgeTypeEnum et); + + void relink(Edge *exist, Block *src, Block *dst); + + pair bind_call( + ParseFrame &frame, Address target, Block *cur, Edge *exist); + + void parse_frames(LockFreeQueue &, bool); void parse_frame(ParseFrame & frame,bool); + bool parse_frame_one_iteration(ParseFrame & frame, bool); + bool inspect_value_driven_jump_tables(ParseFrame &); + + void resumeFrames(Function * func, LockFreeQueue & work); - void resumeFrames(Function * func, vector & work); - // defensive parsing details - void tamper_post_processing(std::vector&, ParseFrame *); + void tamper_post_processing(LockFreeQueue&, ParseFrame *); ParseFrame * getTamperAbsFrame(Function *tamperFunc); - /* implementation of the parsing loop */ - void ProcessUnresBranchEdge( - ParseFrame&, - Block*, - InstructionAdapter_t*, - Address target); - void ProcessCallInsn( - ParseFrame&, - Block*, - InstructionAdapter_t*, - bool, - bool, - bool, - Address); - void ProcessReturnInsn( - ParseFrame&, - Block*, - InstructionAdapter_t*); - void ProcessCFInsn( - ParseFrame&, - Block*, - InstructionAdapter_t*); - - void finalize(); - void finalize_funcs(vector & funcs); - - void invalidateContainingFuncs(Function *, Block *); - - bool getSyscallNumber(Function *, Block *, Address, Architecture, long int &); - - friend class CodeObject; -}; + /* implementation of the parsing loop */ + void ProcessUnresBranchEdge( + ParseFrame &, + Block *, + InstructionAdapter_t *, + Address target); -} + void ProcessCallInsn( + ParseFrame &, + Block *, + InstructionAdapter_t *, + bool, + bool, + bool, + Address); + + void ProcessReturnInsn( + ParseFrame &, + Block *, + InstructionAdapter_t *); + + void ProcessCFInsn( + ParseFrame &, + Block *, + InstructionAdapter_t *); + + void finalize(); + + void finalize_funcs(vector &funcs); + void clean_bogus_funcs(vector &funcs); + void finalize_ranges(vector &funcs); + void split_overlapped_blocks(); + void split_consistent_blocks(region_data *, map &); + void split_inconsistent_blocks(region_data *, map &); + bool set_edge_parsing_status(ParseFrame&, Address addr, Block *b); + void move_edges_consistent_blocks(Block *, Block *); + void update_function_ret_status(ParseFrame &, Function*, ParseWorkElem* ); + + + + void invalidateContainingFuncs(Function *, Block *); + + bool getSyscallNumber(Function *, Block *, Address, Architecture, long int &); + + friend class CodeObject; + + Mutex parse_mutex; + + struct NewFrames : public std::set, public boost::lockable_adapter {}; + + LockFreeQueueItem *ProcessOneFrame(ParseFrame *pf, bool recursive); + + void SpawnProcessFrame(ParseFrame *frame, bool recursive); + + void ProcessFrames(LockFreeQueue *work_queue, bool recursive); + + void LaunchWork(LockFreeQueueItem *frame_list, bool recursive); + + + void processCycle(LockFreeQueue &work, bool recursive); + + void processFixedPoint(LockFreeQueue &work, bool recursive); + + LockFreeQueueItem *postProcessFrame(ParseFrame *pf, bool recursive); + + void updateBlockEnd(Block *b, Address addr, Address previnsn, region_data *rd) const; + }; + + } } diff --git a/parseAPI/src/ParserDetails.C b/parseAPI/src/ParserDetails.C index 9e993a904a..fd8af7f635 100644 --- a/parseAPI/src/ParserDetails.C +++ b/parseAPI/src/ParserDetails.C @@ -41,94 +41,92 @@ using namespace std; using namespace Dyninst; using namespace Dyninst::ParseAPI; -typedef std::pair< Address, EdgeTypeEnum > edge_pair_t; -typedef vector< edge_pair_t > Edges_t; +typedef std::pair edge_pair_t; +typedef vector Edges_t; #define VERBOSE_EDGE_LOG namespace { -inline void -#ifndef VERBOSE_EDGE_LOG -verbose_log(Address /* currAddr */, Edges_t::iterator & /* curEdge */) -{ -#else -verbose_log(Address currAddr, Edges_t::iterator & curEdge) -{ - using namespace Dyninst::ParseAPI; - - switch(curEdge->second) + inline void +#ifndef VERBOSE_EDGE_LOG + verbose_log(Address /* currAddr */, Edges_t::iterator & /* curEdge */) { - case CALL: - parsing_printf("%s[%d]: adding call edge %lx->%lx\n", - FILE__, __LINE__, currAddr, curEdge->first); - break; - case CALL_FT: - parsing_printf("%s[%d]: adding function fallthrough edge %lx->%lx\n", - FILE__, __LINE__, currAddr, curEdge->first); - break; - case FALLTHROUGH: - parsing_printf("%s[%d]: adding fallthrough edge %lx->%lx\n", - FILE__, __LINE__, currAddr, curEdge->first); - break; - case COND_TAKEN: - parsing_printf("%s[%d]: adding conditional taken edge %lx->%lx\n", - FILE__, __LINE__, currAddr, curEdge->first); - break; - case COND_NOT_TAKEN: - parsing_printf("%s[%d]: adding conditional not taken edge %lx->%lx\n", - FILE__, __LINE__, currAddr, curEdge->first); - break; - case INDIRECT: - parsing_printf("%s[%d]: adding indirect edge %lx->%lx\n", - FILE__, __LINE__, currAddr, curEdge->first); - break; - case DIRECT: - parsing_printf("%s[%d]: adding direct edge %lx->%lx\n", - FILE__, __LINE__, currAddr, curEdge->first); - break; - case CATCH: - parsing_printf("%s[%d]: adding catch block edge %lx->%lx\n", - FILE__, __LINE__, currAddr, curEdge->first); - break; - default: - parsing_printf("%s[%d]: adding unknown edge type %d edge %lx->%lx\n", - FILE__, __LINE__, curEdge->second, currAddr, curEdge->first); - break; - } +#else + verbose_log(Address currAddr, Edges_t::iterator &curEdge) { + using namespace Dyninst::ParseAPI; + + switch (curEdge->second) { + case CALL: + parsing_printf("%s[%d]: adding call edge %lx->%lx\n", + FILE__, __LINE__, currAddr, curEdge->first); + break; + case CALL_FT: + parsing_printf("%s[%d]: adding function fallthrough edge %lx->%lx\n", + FILE__, __LINE__, currAddr, curEdge->first); + break; + case FALLTHROUGH: + parsing_printf("%s[%d]: adding fallthrough edge %lx->%lx\n", + FILE__, __LINE__, currAddr, curEdge->first); + break; + case COND_TAKEN: + parsing_printf("%s[%d]: adding conditional taken edge %lx->%lx\n", + FILE__, __LINE__, currAddr, curEdge->first); + break; + case COND_NOT_TAKEN: + parsing_printf("%s[%d]: adding conditional not taken edge %lx->%lx\n", + FILE__, __LINE__, currAddr, curEdge->first); + break; + case INDIRECT: + parsing_printf("%s[%d]: adding indirect edge %lx->%lx\n", + FILE__, __LINE__, currAddr, curEdge->first); + break; + case DIRECT: + parsing_printf("%s[%d]: adding direct edge %lx->%lx\n", + FILE__, __LINE__, currAddr, curEdge->first); + break; + case CATCH: + parsing_printf("%s[%d]: adding catch block edge %lx->%lx\n", + FILE__, __LINE__, currAddr, curEdge->first); + break; + default: + parsing_printf("%s[%d]: adding unknown edge type %d edge %lx->%lx\n", + FILE__, __LINE__, curEdge->second, currAddr, curEdge->first); + break; + } #endif // VERBOSE_EDGE_LOG -} + } } // anonymous namespace -static void -getBlockInsns(Block &blk, std::set
&addrs) -{ +static void +getBlockInsns(Block &blk, std::set
&addrs) { unsigned bufSize = blk.size(); using namespace InstructionAPI; - const unsigned char* bufferBegin = (const unsigned char *) - (blk.obj()->cs()->getPtrToInstruction(blk.start())); + const unsigned char *bufferBegin = (const unsigned char *) + (blk.obj()->cs()->getPtrToInstruction(blk.start())); InstructionDecoder dec = InstructionDecoder - (bufferBegin, bufSize, blk.region()->getArch()); - InstructionAdapter_t *ah = InstructionAdapter_t::makePlatformIA_IAPI(blk.obj()->cs()->getArch(),dec, blk.start(), blk.obj(), blk.region(), blk.obj()->cs(), &blk); + (bufferBegin, bufSize, blk.region()->getArch()); + InstructionAdapter_t *ah = InstructionAdapter_t::makePlatformIA_IAPI(blk.obj()->cs()->getArch(), dec, blk.start(), + blk.obj(), blk.region(), blk.obj()->cs(), + &blk); - for (; ah->getAddr() < blk.end(); ah->advance()) { + for (; ah->getAddr() < blk.end(); ah->advance()) { addrs.insert(ah->getAddr()); - } + } delete ah; } /* called in defensive mode to create parseFrames at tampered addresses for functions that return TAMPER_ABS. */ -ParseFrame * -Parser::getTamperAbsFrame(Function *tamperFunc) -{ +ParseFrame * +Parser::getTamperAbsFrame(Function *tamperFunc) { assert(TAMPER_ABS == tamperFunc->tampersStack()); - Function * targFunc = NULL; + Function *targFunc = NULL; // get the binary's load address and subtract it CodeSource *cs = tamperFunc->obj()->cs(); - set targRegs; + set targRegs; Address loadAddr = cs->loadAddress(); Address target = tamperFunc->_tamper_addr - loadAddr; @@ -137,69 +135,70 @@ Parser::getTamperAbsFrame(Function *tamperFunc) } if (targRegs.empty()) { mal_printf("ERROR: could not create function at tamperAbs " - "addr, which is in another object %lx\n",target); + "addr, which is in another object %lx\n", target); return NULL; } - + assert(1 == targRegs.size()); // we don't do analyze stack tampering on - // platforms that use archive files - targFunc = _parse_data->get_func - (*(targRegs.begin()), - target, - tamperFunc->src()); + // platforms that use archive files + targFunc = _parse_data->createAndRecordFunc + (*(targRegs.begin()), + target, + tamperFunc->src()); if (!targFunc) { - targFunc = _parse_data->get_func(*(targRegs.begin()),target,RT); + targFunc = _parse_data->createAndRecordFunc(*(targRegs.begin()), target, RT); } + if (!targFunc) + targFunc = _parse_data->findFunc(*(targRegs.begin()), target); - if(!targFunc) { + if (!targFunc) { mal_printf("ERROR: could not create function at tamperAbs addr %lx\n", tamperFunc->_tamper_addr); return NULL; } - ParseFrame * pf = NULL; + ParseFrame *pf = NULL; CodeRegion *reg = targFunc->region(); ParseFrame::Status exist = _parse_data->frameStatus(reg, target); - switch(exist) { - case ParseFrame::FRAME_ERROR: - case ParseFrame::PROGRESS: - fprintf(stderr,"ERROR: function frame at %lx in bad state, can't " - "add edge; status=%d\n",target, exist); - return NULL; - break; - case ParseFrame::PARSED: - fprintf(stderr,"ERROR: function frame at %lx already parsed, can't " - "add edge; status=%d\n",target, exist); - return NULL; - break; - case ParseFrame::BAD_LOOKUP: - // create new frame - pf = _parse_data->findFrame(reg, target); - assert( !pf ); - pf = new ParseFrame(targFunc,_parse_data); - break; - case ParseFrame::UNPARSED: - case ParseFrame::CALL_BLOCKED: - pf = _parse_data->findFrame(reg, target); - if ( !pf ) { - fprintf(stderr,"ERROR: no function frame at %lx for frame " - "that should exist, can't add edge; status=%d\n", - target, exist); + switch (exist) { + case ParseFrame::FRAME_ERROR: + case ParseFrame::PROGRESS: + fprintf(stderr, "ERROR: function frame at %lx in bad state, can't " + "add edge; status=%d\n", target, exist); return NULL; - } - break; - default: - assert(0); + break; + case ParseFrame::PARSED: + fprintf(stderr, "ERROR: function frame at %lx already parsed, can't " + "add edge; status=%d\n", target, exist); + return NULL; + break; + case ParseFrame::BAD_LOOKUP: + // create new frame + pf = _parse_data->findFrame(reg, target); + assert(!pf); + pf = new ParseFrame(targFunc, _parse_data); + break; + case ParseFrame::UNPARSED: + case ParseFrame::CALL_BLOCKED: + pf = _parse_data->findFrame(reg, target); + if (!pf) { + fprintf(stderr, "ERROR: no function frame at %lx for frame " + "that should exist, can't add edge; status=%d\n", + target, exist); + return NULL; + } + break; + default: + assert(0); } - + // make a temp edge Function::const_blocklist ret_blks = tamperFunc->returnBlocks(); - for (auto bit = ret_blks.begin(); - bit != ret_blks.end(); - ++bit) - { + for (auto bit = ret_blks.begin(); + bit != ret_blks.end(); + ++bit) { Edge *edge = link_tempsink(*bit, CALL); // create new bundle since we're not adding CALL,CALL_FT edge pairs @@ -210,7 +209,7 @@ Parser::getTamperAbsFrame(Function *tamperFunc) leak-free idiom, but I don't know whether this is intended or a bug. You might want to wrap the call in a frame.pushWork. */ - (void)pf->mkWork(NULL,edge,target,true,true); + (void) pf->mkWork(NULL, edge, edge->src()->last(), target, true, true); /* ParseWorkBundle *bundle = new ParseWorkBundle(); pf->work_bundles.push_back(bundle); @@ -233,45 +232,37 @@ Parser::getTamperAbsFrame(Function *tamperFunc) // In the second case, add a new ParseFrame to the worklist or // trigger parsing in the target object. void -Parser::tamper_post_processing(vector & work, ParseFrame *pf) -{ +Parser::tamper_post_processing(LockFreeQueue &work_queue, ParseFrame *pf) { + vector work; + std::copy(work_queue.begin(), work_queue.end(), std::back_inserter(work)); // tampers with stack by relative amount: // adjust CALL_FT target edge if there is one - for (unsigned widx = 0; - pf->func->tampersStack() == TAMPER_REL && - widx < work.size(); - widx++) - { - if (work[widx]->status() == ParseFrame::CALL_BLOCKED && - pf->func == work[widx]->call_target) - { - for (unsigned bidx=0 ; - bidx < work[widx]->work_bundles.size(); - bidx++) - { - const vector &elems = - work[widx]->work_bundles[bidx]->elems(); + for (auto widx = work.begin(); + pf->func->tampersStack() == TAMPER_REL && + widx != work.end(); + widx++) { + if ((*widx)->status() == ParseFrame::CALL_BLOCKED && + pf->func == (*widx)->call_target) { + for (unsigned bidx = 0; + bidx < (*widx)->work_bundles.size(); + bidx++) { + const vector &elems = + (*widx)->work_bundles[bidx]->elems(); bool rightBundle = false; - ParseWorkElem * ftEdge = NULL; - for (unsigned eix=0; eix < elems.size(); eix++) - { - if (NULL == elems[eix]->edge()) - { + ParseWorkElem *ftEdge = NULL; + for (unsigned eix = 0; eix < elems.size(); eix++) { + if (NULL == elems[eix]->edge()) { continue; } if (elems[eix]->edge()->type() == CALL && - elems[eix]->target()==pf->func->addr()) - { + elems[eix]->target() == pf->func->addr()) { rightBundle = true; - } - else if (elems[eix]->edge()->type() == CALL_FT) - { + } else if (elems[eix]->edge()->type() == CALL_FT) { ftEdge = elems[eix]; } } - if (rightBundle && ftEdge) - { - ftEdge->setTarget(ftEdge->target() + + if (rightBundle && ftEdge) { + ftEdge->setTarget(ftEdge->target() + pf->func->_tamper_addr); } } @@ -279,39 +270,34 @@ Parser::tamper_post_processing(vector & work, ParseFrame *pf) } // create frame for TAMPER_ABS target in this object or parse // in target object - if (pf->func->tampersStack() == TAMPER_ABS) - { + if (pf->func->tampersStack() == TAMPER_ABS) { Address objLoad = 0; CodeObject *targObj = NULL; - if (_pcb.absAddr(pf->func->_tamper_addr, - objLoad, - targObj)) - { + if (_pcb.absAddr(pf->func->_tamper_addr, + objLoad, + targObj)) { if (targObj == &_obj) { // target is in this object, add frame - ParseFrame * tf = getTamperAbsFrame(pf->func); - if (tf && ! _parse_data->findFrame(tf->func->region(), - tf->func->addr()) ) - { + ParseFrame *tf = getTamperAbsFrame(pf->func); + if (tf && !_parse_data->findFrame(tf->func->region(), + tf->func->addr())) { init_frame(*tf); - frames.push_back(tf); + frames.insert(tf); _parse_data->record_frame(tf); _pcb.updateCodeBytes(pf->func->_tamper_addr - objLoad); } if (tf) { - mal_printf("adding TAMPER_ABS target %lx frame\n", + mal_printf("adding TAMPER_ABS target %lx frame\n", pf->func->_tamper_addr); - work.push_back(tf); + work_queue.insert(tf); } - } - else { // target is in another object, parse there + } else { // target is in another object, parse there mal_printf("adding TAMPER_ABS target %lx " - "in separate object at %lx\n", + "in separate object at %lx\n", pf->func->_tamper_addr, objLoad); _obj.parse(pf->func->_tamper_addr - objLoad, true); } - } - else { - mal_printf("discarding invalid TAMPER_ABS target %lx\n", + } else { + mal_printf("discarding invalid TAMPER_ABS target %lx\n", pf->func->_tamper_addr); } } @@ -323,16 +309,15 @@ Parser::tamper_post_processing(vector & work, ParseFrame *pf) */ inline void Parser::ProcessUnresBranchEdge( - ParseFrame & frame, - Block * cur, - InstructionAdapter_t * ah, - Address target) -{ + ParseFrame &frame, + Block *cur, + InstructionAdapter_t *ah, + Address target) { ParseCallback::interproc_details det; - det.ibuf = (unsigned char*) - frame.func->isrc()->getPtrToInstruction(ah->getAddr()); + det.ibuf = (unsigned char *) + frame.func->isrc()->getPtrToInstruction(ah->getAddr()); det.isize = ah->getSize(); - if (((Address)-1) == target) { + if (((Address) -1) == target) { det.data.unres.target = 0; } else { det.data.unres.target = target; @@ -340,7 +325,8 @@ void Parser::ProcessUnresBranchEdge( det.type = ParseCallback::interproc_details::unresolved; det.data.unres.target = target; - bool valid; Address addr; + bool valid; + Address addr; boost::tie(valid, addr) = ah->getCFT(); if (!valid) { det.data.unres.dynamic = true; @@ -349,7 +335,7 @@ void Parser::ProcessUnresBranchEdge( det.data.unres.dynamic = false; det.data.unres.absolute_address = false; } - _pcb.interproc_cf(frame.func,cur,ah->getAddr(),&det); + _pcb.interproc_cf(frame.func, cur, ah->getAddr(), &det); } /* @@ -357,20 +343,19 @@ void Parser::ProcessUnresBranchEdge( */ inline void Parser::ProcessReturnInsn( - ParseFrame & frame, - Block * cur, - InstructionAdapter_t * ah) -{ + ParseFrame &frame, + Block *cur, + InstructionAdapter_t *ah) { // returns always target the sink block - link(cur,_sink,RET,true); + link_block(cur, _sink, RET, true); ParseCallback::interproc_details det; - det.ibuf = (unsigned char*) - frame.func->isrc()->getPtrToInstruction(ah->getAddr()); + det.ibuf = (unsigned char *) + frame.func->isrc()->getPtrToInstruction(ah->getAddr()); det.isize = ah->getSize(); det.type = ParseCallback::interproc_details::ret; - _pcb.interproc_cf(frame.func, cur, ah->getAddr(),&det); + _pcb.interproc_cf(frame.func, cur, ah->getAddr(), &det); } @@ -380,140 +365,145 @@ void Parser::ProcessReturnInsn( */ inline void Parser::ProcessCallInsn( - ParseFrame & frame, - Block * cur, - InstructionAdapter_t * ah, - bool isDynamic, - bool isAbsolute, - bool isResolved, - Address target) -{ + ParseFrame &frame, + Block *cur, + InstructionAdapter_t *ah, + bool isDynamic, + bool isAbsolute, + bool isResolved, + Address target) { ParseCallback::interproc_details det; - det.ibuf = (unsigned char*) - frame.func->isrc()->getPtrToInstruction(ah->getAddr()); + det.ibuf = (unsigned char *) + frame.func->isrc()->getPtrToInstruction(ah->getAddr()); det.isize = ah->getSize(); - - if(ah->isCall()) { + + if (ah->isCall()) { det.data.call.absolute_address = isAbsolute; det.data.call.dynamic_call = isDynamic; det.data.call.target = target; if (likely(isResolved)) - det.type = ParseCallback::interproc_details::call; + det.type = ParseCallback::interproc_details::call; else - det.type = ParseCallback::interproc_details::unresolved; - } - else + det.type = ParseCallback::interproc_details::unresolved; + } else det.type = ParseCallback::interproc_details::branch_interproc; - - _pcb.interproc_cf(frame.func,cur,ah->getAddr(),&det); + + _pcb.interproc_cf(frame.func, cur, ah->getAddr(), &det); } void Parser::ProcessCFInsn( - ParseFrame & frame, - Block * cur, - InstructionAdapter_t * ah) + ParseFrame &frame, + Block *cur, + InstructionAdapter_t *ah) { FuncReturnStatus insn_ret; Edges_t edges_out; - ParseWorkBundle * bundle = NULL; + ParseWorkBundle *bundle = NULL; + + region_data::edge_data_map::accessor a; + region_data::edge_data_map* edm = _parse_data->get_edge_data_map(frame.func->region()); + assert(edm->find(a, ah->getAddr())); + cur = a->second.b; - // terminate the block at this address - end_block(cur,ah); - // Instruction adapter provides edge estimates from an instruction parsing_printf("Getting edges\n"); - ah->getNewEdges(edges_out, frame.func, cur, frame.num_insns, &plt_entries, frame.knownTargets); + ah->getNewEdges(edges_out, frame.func, cur, frame.num_insns, &plt_entries, frame.knownTargets); parsing_printf("Returned %d edges\n", edges_out.size()); if (unlikely(_obj.defensiveMode() && !ah->isCall() && edges_out.size())) { // only parse branch edges that align with existing blocks + // + // Xiaozhu: The person who works on defensive mode needs to + // revisit this code. In parallel parsing, the block boundary (cur->end()) + // is not reliable because it can be split by another thread bool hasUnalignedEdge = false; - set tregs; - set tblocks; + set tregs; + set tblocks; set
insns_cur; - for(Edges_t::iterator curEdge = edges_out.begin(); - !hasUnalignedEdge && curEdge != edges_out.end(); - ++curEdge) - { + for (Edges_t::iterator curEdge = edges_out.begin(); + !hasUnalignedEdge && curEdge != edges_out.end(); + ++curEdge) { if (cur->end() <= curEdge->first) { - parsing_printf("%s[%d] skipping edge\n", FILE__, __LINE__); + parsing_printf("%s[%d] skipping edge\n", FILE__, __LINE__); continue; } - _obj.cs()->findRegions(curEdge->first,tregs); + _obj.cs()->findRegions(curEdge->first, tregs); if (!tregs.empty()) { - _parse_data->findBlocks(*tregs.begin(),curEdge->first, tblocks); - for (set::iterator bit= tblocks.begin(); - !hasUnalignedEdge && bit != tblocks.end(); - bit++) - { + _parse_data->findBlocks(*tregs.begin(), curEdge->first, tblocks); + for (set::iterator bit = tblocks.begin(); + !hasUnalignedEdge && bit != tblocks.end(); + bit++) { if ((*bit)->end() <= cur->start() || - (*bit) == cur) - { - parsing_printf("%s[%d] skipping edge\n", FILE__, __LINE__); + (*bit) == cur) { + parsing_printf("%s[%d] skipping edge\n", FILE__, __LINE__); continue; } set
insns_tblk; - getBlockInsns(**bit,insns_tblk); + getBlockInsns(**bit, insns_tblk); if (insns_cur.empty()) { - getBlockInsns(*cur,insns_cur); + getBlockInsns(*cur, insns_cur); } if ((*bit)->start() < cur->start()) { if (insns_tblk.end() == insns_tblk.find(cur->start())) { hasUnalignedEdge = true; - } + } } else if (insns_cur.end() == insns_cur.find((*bit)->start())) { hasUnalignedEdge = true; } if (hasUnalignedEdge) { mal_printf("Found unaligned blocks [%lx %lx) [%lx %lx), adding abruptEnd " - "point and killing out edges\n", cur->start(), cur->end(), + "point and killing out edges\n", cur->start(), cur->end(), (*bit)->start(), (*bit)->end()); } } } } if (true == hasUnalignedEdge) { - parsing_printf("Has unaligned edge, clearing and treating as abrupt end\n"); + parsing_printf("Has unaligned edge, clearing and treating as abrupt end\n"); edges_out.clear(); ParseCallback::default_details det( - (unsigned char*) cur->region()->getPtrToInstruction(cur->lastInsnAddr()), - cur->end() - cur->lastInsnAddr(), - true); - _pcb.abruptEnd_cf(cur->lastInsnAddr(),cur,&det); + (unsigned char *) cur->region()->getPtrToInstruction(cur->lastInsnAddr()), + cur->end() - cur->lastInsnAddr(), + true); + _pcb.abruptEnd_cf(cur->lastInsnAddr(), cur, &det); } } - insn_ret = ah->getReturnStatus(frame.func,frame.num_insns); + insn_ret = ah->getReturnStatus(frame.func, frame.num_insns); // Update function return status if possible - if(unlikely(insn_ret != UNSET && frame.func->_rs < RETURN)) - frame.func->set_retstatus(insn_ret); + if (unlikely(insn_ret != UNSET && frame.func->_rs < RETURN) && !HASHDEF(plt_entries, frame.func->addr())) { + // insn_ret can only be UNSET, UNKNOWN, or RETURN + // UNKNOWN means that there is an unresolved undirect control flow, + // such as unresolve jump tables or indirect tail calls. + // In such cases, we do not have concrete evidence that + // the function cannot not return, so we mark this function as RETURN. + frame.func->set_retstatus(RETURN); + } // Return instructions need extra processing - if(insn_ret == RETURN) - ProcessReturnInsn(frame,cur,ah); + if (insn_ret == RETURN) + ProcessReturnInsn(frame, cur, ah); bool dynamic_call = ah->isDynamicCall(); bool absolute_call = ah->isAbsoluteCall(); // unresolved is true for indirect calls, unresolved indirect branches, // and later on is set set to true for transfers to bad addresses - bool has_unres = ah->hasUnresolvedControlFlow(frame.func,frame.num_insns); + bool has_unres = ah->hasUnresolvedControlFlow(frame.func, frame.num_insns); - parsing_printf("\t\t%d edges:\n",edges_out.size()); - for(Edges_t::iterator curEdge = edges_out.begin(); - curEdge != edges_out.end(); ++curEdge) - { - Edge * newedge = NULL; + parsing_printf("\t\t%d edges:\n", edges_out.size()); + for (Edges_t::iterator curEdge = edges_out.begin(); + curEdge != edges_out.end(); ++curEdge) { + Edge *newedge = NULL; bool resolvable_edge = true; bool tailcall = false; - if(!is_code(frame.func,curEdge->first) && - !HASHDEF(plt_entries,curEdge->first)) - { - if(curEdge->second != CALL || !dynamic_call) { + if (!is_code(frame.func, curEdge->first) && + !HASHDEF(plt_entries, curEdge->first)) { + if (curEdge->second != CALL || !dynamic_call) { has_unres = true; resolvable_edge = false; - if ((int)curEdge->second != -1 && _obj.defensiveMode()) + if ((int) curEdge->second != -1 && _obj.defensiveMode()) mal_printf("bad edge target at %lx type %d\n", curEdge->first, curEdge->second); } @@ -521,100 +511,95 @@ void Parser::ProcessCFInsn( /* * Call case - */ - if(curEdge->second == CALL) - { + */ + if (curEdge->second == CALL) { // call callback resolvable_edge = resolvable_edge && !dynamic_call; - ProcessCallInsn(frame,cur,ah,dynamic_call, - absolute_call,resolvable_edge,curEdge->first); + ProcessCallInsn(frame, cur, ah, dynamic_call, + absolute_call, resolvable_edge, curEdge->first); - if(resolvable_edge) { - newedge = link_tempsink(cur,CALL); + if (resolvable_edge) { + newedge = link_tempsink(cur, CALL); + } else { + newedge = link_block(cur, _sink, CALL, true); } - else { - newedge = link(cur,_sink,CALL,true); - } - if(!ah->isCall()) { - parsing_printf("Setting edge 0x%lx (0x%lx/0x%lx) to interproc\n", - newedge, - newedge->src()->start(), - newedge->trg()->start()); + if (!ah->isCall()) { + parsing_printf("Setting edge 0x%lx (0x%lx/0x%lx) to interproc\n", + newedge, + newedge->src()->start(), + newedge->trg_addr()); newedge->_type._interproc = true; } } - /* - * All other edge types are handled identically - */ - else - { - if(resolvable_edge) { - newedge = link_tempsink(cur,curEdge->second); - } - else - newedge = link(cur,_sink,curEdge->second,true); + /* + * All other edge types are handled identically + */ + else { + if (resolvable_edge) { + newedge = link_tempsink(cur, curEdge->second); + } else + newedge = link_block(cur, _sink, curEdge->second, true); } if (ah->isTailCall(frame.func, curEdge->second, frame.num_insns, frame.knownTargets)) { - tailcall = true; + tailcall = true; parsing_printf("Setting edge 0x%lx (0x%lx/0x%lx) to interproc (tail call)\n", - newedge, - newedge->src()->start(), - newedge->trg()->start()); - newedge->_type._interproc = true; + newedge, + newedge->src()->start(), + newedge->trg_addr()); + newedge->_type._interproc = true; } - if(!bundle) { + if (!bundle) { bundle = new ParseWorkBundle(); frame.work_bundles.push_back(bundle); } - verbose_log(ah->getAddr(),curEdge); - parsing_printf("resolveable_edge: %d, tailcall: %d, target: %lx\n", resolvable_edge, tailcall, curEdge->first); - ParseWorkElem * we = - bundle->add( - new ParseWorkElem( - bundle, - newedge, - curEdge->first, - resolvable_edge, - tailcall) - ); - frame.knownTargets.insert(curEdge->first); + verbose_log(ah->getAddr(), curEdge); + parsing_printf("resolveable_edge: %d, tailcall: %d, target: %lx\n", resolvable_edge, tailcall, curEdge->first); + ParseWorkElem *we = + bundle->add( + new ParseWorkElem( + bundle, + newedge, + ah->getAddr(), + curEdge->first, + resolvable_edge, + tailcall) + ); + frame.knownTargets.insert(curEdge->first); // We will not attempt to further process // unresolvable edges; they stay sinks - if(resolvable_edge) { + if (resolvable_edge) { parsing_printf("[%s:%d] pushing %lx onto worklist\n", - FILE__,__LINE__,we->target()); + FILE__, __LINE__, we->target()); + parsing_printf("[%s:%d] new edge is %p\n", FILE__, __LINE__, newedge); frame.pushWork(we); if (unlikely(_obj.defensiveMode())) { // update the underlying code bytes for CF targets - if ( CALL == curEdge->second - || DIRECT == curEdge->second - || COND_TAKEN == curEdge->second) - { + if (CALL == curEdge->second + || DIRECT == curEdge->second + || COND_TAKEN == curEdge->second) { _pcb.updateCodeBytes(curEdge->first); } } - } - else if( unlikely(_obj.defensiveMode()) ) - { + } else if (unlikely(_obj.defensiveMode())) { ProcessUnresBranchEdge(frame, cur, ah, curEdge->first); } } if (unlikely(has_unres && edges_out.empty())) { - link(cur, _sink, INDIRECT, true); + link_block(cur, _sink, INDIRECT, true); ProcessUnresBranchEdge(frame, cur, ah, -1); - } + } - if(ah->isDelaySlot()) + if (ah->isDelaySlot()) ah->advance(); - if(!frame.func->_cleans_stack && ah->cleansStack()) { + if (!frame.func->_cleans_stack && ah->cleansStack()) { frame.func->_cleans_stack = true; - } + } } diff --git a/parseAPI/src/ParserDetails.h b/parseAPI/src/ParserDetails.h index 59dfa54852..fb144321f1 100644 --- a/parseAPI/src/ParserDetails.h +++ b/parseAPI/src/ParserDetails.h @@ -78,6 +78,11 @@ class ParseWorkElem * 3. Jump table analysis would like to have as much intraprocedural control flow * as possible to resolve an indirect jump. So resolve_jump_table is delayed. * + * 4. Parsing cond_not_taken edges over cond_taken edges. This is because cond_taken + * edges may split a block. In special cases, the source block of the edge is split. + * The cond_not_taken edge work element would still have the unsplit block, which is + * now the upper portion after spliting. + * * Please make sure to update this comment * if you change the order of the things appearing in the enum * @@ -87,13 +92,17 @@ class ParseWorkElem ret_fallthrough, /* conditional returns */ call, call_fallthrough, - cond_taken, cond_not_taken, + cond_taken, br_direct, br_indirect, catch_block, checked_call_ft, resolve_jump_table, // We want to finish all possible parsing work before parsing jump tables + // For shared code, we only parse once. The return statuses of + // the functions that share code depend on the function that performs + // the real parsing + func_shared_code, __parse_work_end__ }; @@ -102,32 +111,40 @@ class ParseWorkElem ParseWorkBundle *b, parse_work_order o, Edge *e, + Address source, Address target, bool resolvable, bool tailcall) : _bundle(b), - _edge(e), + _edge(e), + _src(source), _targ(target), _can_resolve(resolvable), _tailcall(tailcall), _order(o), - _call_processed(false) { } + _call_processed(false), + _cur(NULL), + _shared_func(NULL) { } ParseWorkElem( ParseWorkBundle *b, Edge *e, + /* We also the source address of the edge because the source block + * may be split */ + Address source, Address target, bool resolvable, bool tailcall) : _bundle(b), _edge(e), + _src(source), _targ(target), _can_resolve(resolvable), _tailcall(tailcall), _order(__parse_work_end__), _call_processed(false), - _cur(NULL), - _ah(NULL) + _cur(NULL), + _shared_func(NULL) { if(e) { @@ -135,7 +152,14 @@ class ParseWorkElem case CALL: _order = call; break; case COND_TAKEN: - _order = cond_taken; break; + { + if (tailcall) { + _order = call; + } else { + _order = cond_taken; + } + break; + } case COND_NOT_TAKEN: _order = cond_not_taken; break; case INDIRECT: @@ -167,13 +191,14 @@ class ParseWorkElem ParseWorkElem() : _bundle(NULL), _edge(NULL), + _src(0), _targ((Address)-1), _can_resolve(false), _tailcall(false), _order(__parse_work_end__), _call_processed(false), - _cur(NULL), - _ah(NULL) + _cur(NULL), + _shared_func(NULL) { } // This work element is a continuation of @@ -188,16 +213,31 @@ class ParseWorkElem _call_processed(false), _cur(b) { _ah = ah->clone(); + _src = _ah->getAddr(); + _shared_func = NULL; } + ParseWorkElem(ParseWorkBundle *bundle, Function *f): + _bundle(bundle), + _targ((Address)-1), + _can_resolve(false), + _tailcall(false), + _order(func_shared_code), + _call_processed(false), + _cur(NULL) { + _shared_func = f; + _src = 0; + } + + ~ParseWorkElem() { - if (_ah != NULL) delete _ah; } ParseWorkBundle * bundle() const { return _bundle; } Edge * edge() const { return _edge; } + Address source() const { return _src; } Address target() const { return _targ; } bool resolvable() const { return _can_resolve; } parse_work_order order() const { return _order; } @@ -207,8 +247,9 @@ class ParseWorkElem bool callproc() const { return _call_processed; } void mark_call() { _call_processed = true; } - Block * cur() const { return _cur; } - InsnAdapter::IA_IAPI * ah() const { return _ah; } + Block* cur() const { return _cur; } + InsnAdapter::IA_IAPI* ah() const { return _ah; } + Function* shared_func() const { return _shared_func; } /* * Note that compare treats the parse_work_order as `lowest is @@ -234,6 +275,7 @@ class ParseWorkElem private: ParseWorkBundle * _bundle; Edge * _edge; + Address _src; Address _targ; bool _can_resolve; bool _tailcall; @@ -241,8 +283,9 @@ class ParseWorkElem bool _call_processed; // Data for continuing parsing jump tables - Block * _cur; - InsnAdapter::IA_IAPI * _ah; + Block* _cur; + InsnAdapter::IA_IAPI* _ah; + Function * _shared_func; }; // ParseWorkElem container diff --git a/parseAPI/src/ProbabilisticParser.C b/parseAPI/src/ProbabilisticParser.C index bf3dfded55..be7b30f5a3 100644 --- a/parseAPI/src/ProbabilisticParser.C +++ b/parseAPI/src/ProbabilisticParser.C @@ -490,22 +490,22 @@ bool ProbabilityCalculator::decodeInstruction(DecodeData &data, Address addr) { return false; } InstructionDecoder dec( buf , 30, cs->getArch()); - Instruction::Ptr insn = dec.decode(); - if (!insn) { + Instruction insn = dec.decode(); + if (!insn.isValid()) { decodeCache.insert(make_pair(addr, DecodeData(JUNK_OPCODE, 0,0,0))); return false; } - data.len = (unsigned short)insn->size(); + data.len = (unsigned short)insn.size(); if (data.len == 0) { decodeCache.insert(make_pair(addr, DecodeData(JUNK_OPCODE, 0,0,0))); return false; } - const Operation & op = insn->getOperation(); + auto op = insn.getOperation(); data.entry_id = op.getID(); vector ops; - insn->getOperands(ops); + insn.getOperands(ops); int args[2] = {NOARG,NOARG}; for(unsigned int i=0;i<2 && icallEdges(); for (auto eit = call_edges.begin(); eit != call_edges.end(); ++eit) { if ((*eit)->type() == CALL_FT) continue; - Address target = (*eit)->trg()->start(); + Address target = (*eit)->trg_addr(); if (reachingProb.find(target) == reachingProb.end()) continue; if (double_cmp(cur_prob, getFEPProb(target)) > 0) { newFEPProb[target] = cur_prob; diff --git a/parseAPI/src/SymbolicExpression.C b/parseAPI/src/SymbolicExpression.C index a2e561244b..e1b33457a1 100644 --- a/parseAPI/src/SymbolicExpression.C +++ b/parseAPI/src/SymbolicExpression.C @@ -11,8 +11,6 @@ using namespace Dyninst; using namespace Dyninst::ParseAPI; using namespace Dyninst::DataflowAPI; -CodeSource* SymbolicExpression::cs = NULL; - bool SymbolicExpression::ReadMemory(Address addr, uint64_t &v, int ) { int addressWidth = cs->getAddressWidth(); if (addressWidth == 4) { @@ -272,7 +270,7 @@ AST::Ptr SymbolicExpression::SimplifyRoot(AST::Ptr ast, Address addr, bool keepM AST::Ptr SymbolicExpression::SimplifyAnAST(AST::Ptr ast, Address addr, bool keepMultiOne) { - SimplifyVisitor sv(addr, keepMultiOne); + SimplifyVisitor sv(addr, keepMultiOne, *this); ast->accept(&sv); return SimplifyRoot(ast, addr, keepMultiOne); } @@ -323,13 +321,14 @@ pair SymbolicExpression::ExpandAssignment(Assignment::Ptr assign return make_pair(ast, false); } } else { - parsing_printf("\t\tExpanding instruction @ %x: %s, assignment %s\n", assign->addr(), assign->insn()->format().c_str(), assign->format().c_str()); + parsing_printf("\t\tExpanding instruction @ %x: %s, assignment %s\n", + assign->addr(), assign->insn().format().c_str(), assign->format().c_str()); pair expandRet = SymEval::expand(assign, false); if (expandRet.second && expandRet.first) { parsing_printf("Original expand: %s\n", expandRet.first->format().c_str()); AST::Ptr calculation = SimplifyAnAST(expandRet.first, PCValue(assign->addr(), - assign->insn()->size(), + assign->insn().size(), assign->block()->obj()->cs()->getArch()), true); expandCache[assign] = calculation; diff --git a/parseAPI/src/SymbolicExpression.h b/parseAPI/src/SymbolicExpression.h index 0df686e2e0..fd10859cc7 100644 --- a/parseAPI/src/SymbolicExpression.h +++ b/parseAPI/src/SymbolicExpression.h @@ -15,13 +15,16 @@ class SymbolicExpression { public: - static AST::Ptr SimplifyRoot(AST::Ptr ast, Address addr, bool keepMultiOne = false); - static AST::Ptr SimplifyAnAST(AST::Ptr ast, Address addr, bool keepMultiOne = false); + AST::Ptr SimplifyRoot(AST::Ptr ast, Address addr, bool keepMultiOne = false); + AST::Ptr SimplifyAnAST(AST::Ptr ast, Address addr, bool keepMultiOne = false); static AST::Ptr SubstituteAnAST(AST::Ptr ast, const std::map& aliasMap); static AST::Ptr DeepCopyAnAST(AST::Ptr ast); static bool ContainAnAST(AST::Ptr root, AST::Ptr check); - static bool ReadMemory(Address addr, uint64_t &val, int size); - static ParseAPI::CodeSource* cs; + bool ReadMemory(Address addr, uint64_t &val, int size); + ParseAPI::CodeSource* cs; + // For archive, there are overlapping regions. + // Need to use the right region. + ParseAPI::CodeRegion* cr; std::pair ExpandAssignment(Assignment::Ptr, bool keepMultiOne = false); //On x86 and x86-64, the value of PC is post-instruction, diff --git a/parseAPI/src/SymtabCodeSource.C b/parseAPI/src/SymtabCodeSource.C index fa7dea50fc..eea0b04f88 100644 --- a/parseAPI/src/SymtabCodeSource.C +++ b/parseAPI/src/SymtabCodeSource.C @@ -42,11 +42,32 @@ #include "CodeSource.h" #include "debug_parse.h" #include "util.h" +#include "race-detector-annotations.h" + + +#ifdef ENABLE_RACE_DETECTION +#include +#include +#endif using namespace std; using namespace Dyninst; using namespace Dyninst::ParseAPI; +typedef tbb::concurrent_hash_map SeenMap; + +static const vector skipped_symbols = { + "_non_rtti_object::`vftable'", + "bad_cast::`vftable'", + "exception::`vftable'", + "bad_typeid::`vftable'" , + "sys_errlist", + "std::_non_rtti_object::`vftable'", + "std::__non_rtti_object::`vftable'", + "std::bad_cast::`vftable'", + "std::exception::`vftable'", + "std::bad_typeid::`vftable'" }; + /** SymtabCodeRegion **/ @@ -69,6 +90,20 @@ SymtabCodeRegion::SymtabCodeRegion( } } + +SymtabCodeRegion::SymtabCodeRegion( + SymtabAPI::Symtab * st, + SymtabAPI::Region * reg, + vector &symbols) : + _symtab(st), + _region(reg) +{ + for (auto sit = symbols.begin(); sit != symbols.end(); ++sit) + if ( (*sit)->getRegion() == reg && (*sit)->getType() != SymtabAPI::Symbol::ST_FUNCTION && (*sit)->getType() != SymtabAPI::Symbol::ST_INDIRECT) { + knownData[(*sit)->getOffset()] = (*sit)->getOffset() + (*sit)->getSize(); + } +} + void SymtabCodeRegion::names(Address entry, vector & names) { @@ -116,13 +151,8 @@ SymtabCodeRegion::getPtrToInstruction(const Address addr) const { if(!contains(addr)) return NULL; - if(isCode(addr)) - return (void*)((Address)_region->getPtrToRawData() + - addr - _region->getMemOffset()); - else if(isData(addr)) - return getPtrToData(addr); - else - return NULL; + return (void*)((Address)_region->getPtrToRawData() + + addr - _region->getMemOffset()); } void * @@ -130,11 +160,8 @@ SymtabCodeRegion::getPtrToData(const Address addr) const { if(!contains(addr)) return NULL; - if(isData(addr)) - return (void*)((Address)_region->getPtrToRawData() + - addr - _region->getMemOffset()); - else - return NULL; + return (void*)((Address)_region->getPtrToRawData() + + addr - _region->getMemOffset()); } unsigned int @@ -387,10 +414,13 @@ SymtabCodeSource::init(hint_filt * filt , bool allLoadedRegions) void SymtabCodeSource::init_regions(hint_filt * filt , bool allLoadedRegions) { - dyn_hash_map rmap; + RegionMap rmap; vector regs; vector dregs; - vector::iterator rit; + vector symbols; + mcs_lock_t reg_lock; + + mcs_init(reg_lock); if ( ! allLoadedRegions ) { _symtab->getCodeRegions(regs); @@ -403,12 +433,22 @@ SymtabCodeSource::init_regions(hint_filt * filt , bool allLoadedRegions) parsing_printf("[%s:%d] processing %d symtab regions in %s\n", FILE__,__LINE__,regs.size(),_symtab->name().c_str()); - for(rit = regs.begin(); rit != regs.end(); ++rit) { - parsing_printf(" %lx %s",(*rit)->getMemOffset(), - (*rit)->getRegionName().c_str()); + + _symtab->getAllSymbols(symbols); + +#ifdef ENABLE_RACE_DETECTION + cilk_for +#else +#pragma omp parallel for shared(regs,dregs,symbols,reg_lock) schedule(auto) + for +#endif + (unsigned int i = 0; i < regs.size(); i++) { + SymtabAPI::Region *r = regs[i]; + parsing_printf(" %lx %s",r->getMemOffset(), + r->getRegionName().c_str()); // XXX only TEXT, DATA, TEXTDATA? - SymtabAPI::Region::RegionType rt = (*rit)->getRegionType(); + SymtabAPI::Region::RegionType rt = r->getRegionType(); if(false == allLoadedRegions && rt != SymtabAPI::Region::RT_TEXT && rt != SymtabAPI::Region::RT_DATA && @@ -419,20 +459,31 @@ SymtabCodeSource::init_regions(hint_filt * filt , bool allLoadedRegions) } //#if defined(os_vxworks) - if(0 == (*rit)->getMemSize()) { + if(0 == r->getMemSize()) { parsing_printf(" [skipped null region]\n"); continue; } //#endif parsing_printf("\n"); - if(HASHDEF(rmap,*rit)) { + CodeRegion * cr = new SymtabCodeRegion(_symtab,r, symbols); + bool already_present = false; + + race_detector_fake_lock_acquire(race_detector_fake_lock(rmap)); + { + RegionMap::accessor a; + already_present = rmap.insert(a, std::make_pair(r, cr)); + } + race_detector_fake_lock_release(race_detector_fake_lock(rmap)); + + if (already_present) { parsing_printf("[%s:%d] duplicate region at address %lx\n", - FILE__,__LINE__,(*rit)->getMemOffset()); + FILE__,__LINE__,r->getMemOffset()); } - CodeRegion * cr = new SymtabCodeRegion(_symtab,*rit); - rmap[*rit] = cr; + mcs_node_t me; + mcs_lock(reg_lock, me); addRegion(cr); + mcs_unlock(reg_lock, me); } // Hints are initialized at the SCS level rather than the SCR level @@ -442,12 +493,10 @@ SymtabCodeSource::init_regions(hint_filt * filt , bool allLoadedRegions) } void -SymtabCodeSource::init_hints(dyn_hash_map & rmap, - hint_filt * filt) +SymtabCodeSource::init_hints(RegionMap &rmap, hint_filt * filt) { vector fsyms; - vector::iterator fsit; - dyn_hash_map seen; + SeenMap seen; int dupes = 0; if(!_symtab->getAllFunctions(fsyms)) @@ -455,12 +504,14 @@ SymtabCodeSource::init_hints(dyn_hash_map & rmap, parsing_printf("[%s:%d] processing %d symtab hints\n",FILE__,__LINE__, fsyms.size()); - for(fsit = fsyms.begin(); fsit != fsyms.end(); ++fsit) { - if(filt && (*filt)(*fsit)) - { - parsing_printf(" == filtered hint %s [%lx] ==\n", - FILE__,__LINE__,(*fsit)->getOffset(), - (*fsit)->getFirstSymbol()->getPrettyName().c_str()); + + for (unsigned int i = 0; i < fsyms.size(); i++) { + SymtabAPI::Function *f = fsyms[i]; + string fname_s = f->getFirstSymbol()->getPrettyName(); + const char *fname = fname_s.c_str(); + if(filt && (*filt)(f)) { + parsing_printf("[%s:%d} == filtered hint %s [%lx] ==\n", + FILE__,__LINE__,fname, f->getOffset()); continue; } @@ -468,64 +519,63 @@ SymtabCodeSource::init_hints(dyn_hash_map & rmap, // right place to do this? Should these symbols not be filtered by the // loop above? /*Achin added code starts 12/15/2014*/ - static const vector skipped_symbols = { - "_non_rtti_object::`vftable'", - "bad_cast::`vftable'", - "exception::`vftable'", - "bad_typeid::`vftable'" , - "sys_errlist", - "std::_non_rtti_object::`vftable'", - "std::__non_rtti_object::`vftable'", - "std::bad_cast::`vftable'", - "std::exception::`vftable'", - "std::bad_typeid::`vftable'" }; if (std::find(skipped_symbols.begin(), skipped_symbols.end(), - (*fsit)->getFirstSymbol()->getPrettyName()) != skipped_symbols.end()) { + fsyms[i]->getFirstSymbol()->getPrettyName()) != skipped_symbols.end()) { continue; } /*Achin added code ends*/ - if(HASHDEF(seen,(*fsit)->getOffset())) { + bool present = false; + { + SeenMap::accessor a; + Offset offset = f->getOffset(); + present = seen.find(a, offset); + if (!present) seen.insert(a, std::make_pair(offset, true)); + } + + if (present) { // XXX it looks as though symtabapi now does de-duplication // of function symbols automatically, so this code should // never be reached, except in the case of overlapping // regions parsing_printf("[%s:%d] duplicate function at address %lx: %s\n", - FILE__,__LINE__, - (*fsit)->getOffset(), - (*fsit)->getFirstSymbol()->getPrettyName().c_str()); + FILE__,__LINE__, f->getOffset(), fname); ++dupes; } - seen[(*fsit)->getOffset()] = true; - SymtabAPI::Region * sr = (*fsit)->getRegion(); - if(!sr) { + SymtabAPI::Region * sr = f->getRegion(); + if (!sr) { parsing_printf("[%s:%d] missing Region in function at %lx\n", - FILE__,__LINE__,(*fsit)->getOffset()); + FILE__,__LINE__,f->getOffset()); continue; } - if(!HASHDEF(rmap,sr)) { + + CodeRegion * cr = NULL; + + { + RegionMap::accessor a; + present = rmap.find(a, sr); + if (present) cr = a->second; + } + + if (!present) { parsing_printf("[%s:%d] unrecognized Region %lx in function %lx\n", - FILE__,__LINE__,sr->getMemOffset(),(*fsit)->getOffset()); + FILE__,__LINE__,sr->getMemOffset(),f->getOffset()); continue; } - CodeRegion * cr = rmap[sr]; - if(!cr->isCode((*fsit)->getOffset())) - { + + if(!cr->isCode(f->getOffset())) { parsing_printf("\t<%lx> skipped non-code, region [%lx,%lx)\n", - (*fsit)->getOffset(), - sr->getMemOffset(), - sr->getMemOffset()+sr->getDiskSize()); + f->getOffset(), + sr->getMemOffset(), + sr->getMemOffset()+sr->getDiskSize()); } else { - _hints.push_back( Hint((*fsit)->getOffset(), - (*fsit)->getSize(), - cr, - (*fsit)->getFirstSymbol()->getPrettyName()) ); - parsing_printf("\t<%lx,%s,[%lx,%lx)>\n", - (*fsit)->getOffset(), - (*fsit)->getFirstSymbol()->getPrettyName().c_str(), - cr->offset(), - cr->offset()+cr->length()); + _hints.push_back(Hint(f->getOffset(), f->getSize(), cr, fname_s)); + parsing_printf("\t<%lx,%s,[%lx,%lx)>\n", + f->getOffset(), + fname, + cr->offset(), + cr->offset()+cr->length()); } } sort(_hints.begin(), _hints.end()); @@ -625,8 +675,11 @@ inline CodeRegion * SymtabCodeSource::lookup_region(const Address addr) const { CodeRegion * ret = NULL; - if(_lookup_cache && _lookup_cache->contains(addr)) - ret = _lookup_cache; + race_detector_fake_lock_acquire(race_detector_fake_lock(_lookup_cache)); + CodeRegion * cache = _lookup_cache.load(); + race_detector_fake_lock_release(race_detector_fake_lock(_lookup_cache)); + if(cache && cache->contains(addr)) + ret = cache; else { set stab; int rcnt = findRegions(addr,stab); @@ -634,8 +687,10 @@ SymtabCodeSource::lookup_region(const Address addr) const assert(rcnt <= 1 || regionsOverlap()); if(rcnt) { - ret = *stab.begin(); - _lookup_cache = ret; + ret = *stab.begin(); + race_detector_fake_lock_acquire(race_detector_fake_lock(_lookup_cache)); + _lookup_cache.store(ret); + race_detector_fake_lock_release(race_detector_fake_lock(_lookup_cache)); } } return ret; @@ -646,9 +701,9 @@ SymtabCodeSource::overlapping_warn(const char * file, unsigned line) const { if(regionsOverlap()) { - //fprintf(stderr,"Invocation of routine at %s:%d is ambiguous for " - // "binaries with overlapping code regions\n", - // file,line); + parsing_printf("Invocation of routine at %s:%d is ambiguous for " + "binaries with overlapping code regions\n", + file,line); } } diff --git a/parseAPI/src/ThunkData.C b/parseAPI/src/ThunkData.C index a776cc3f70..f937b48ede 100644 --- a/parseAPI/src/ThunkData.C +++ b/parseAPI/src/ThunkData.C @@ -14,6 +14,7 @@ using namespace Dyninst::ParseAPI; void ReachFact::ReverseDFS(ParseAPI::Block *cur, set &visited) { if (visited.find(cur) != visited.end()) return; visited.insert(cur); + boost::lock_guard g(*cur); for (auto eit = cur->sources().begin(); eit != cur->sources().end(); ++eit) if ((*eit)->type() != CALL && (*eit)->type() != RET) ReverseDFS((*eit)->src(), visited); @@ -22,6 +23,7 @@ void ReachFact::ReverseDFS(ParseAPI::Block *cur, set &visited) void ReachFact::NaturalDFS(ParseAPI::Block *cur, set &visited) { if (visited.find(cur) != visited.end()) return; visited.insert(cur); + boost::lock_guard g(*cur); for (auto eit = cur->targets().begin(); eit != cur->targets().end(); ++eit) if ((*eit)->type() != CALL && (*eit)->type() != RET) NaturalDFS((*eit)->trg(), visited); diff --git a/parseAPI/src/debug_parse.C b/parseAPI/src/debug_parse.C index 9bf6ce403d..aff0e79256 100644 --- a/parseAPI/src/debug_parse.C +++ b/parseAPI/src/debug_parse.C @@ -45,6 +45,9 @@ int Dyninst::ParseAPI::dyn_debug_initialized = 0; #pragma warning(disable:4996) #endif +#include +dyn_tls FILE* log_file = NULL; + int Dyninst::ParseAPI::parsing_printf_int(const char *format, ...) { if(!dyn_debug_initialized) { @@ -57,10 +60,15 @@ int Dyninst::ParseAPI::parsing_printf_int(const char *format, ...) if(!dyn_debug_parsing) return 0; if(NULL == format) return -1; + if (log_file == NULL) { + char filename[128]; + snprintf(filename, 128, "%s-%d.txt", getenv("DYNINST_DEBUG_PARSING"), omp_get_thread_num()); + log_file = fopen(filename, "w"); + } va_list va; va_start(va,format); - int ret = vfprintf(stderr, format, va); + int ret = vfprintf(log_file, format, va); va_end(va); return ret; diff --git a/parseThat/CMakeLists.txt b/parseThat/CMakeLists.txt index 11a9f599f5..247773ba68 100644 --- a/parseThat/CMakeLists.txt +++ b/parseThat/CMakeLists.txt @@ -1,4 +1,4 @@ add_executable(parseThat src/parseThat.C src/config.C src/ipc.C src/record.C src/strlist.C src/reglist.C src/log.C src/utils.C src/sha1.C src/dyninstCore.C src/dyninstCompat.v5.C) add_definitions(-DHAVE_BPATCH_PROCESS_H) -target_link_private_libraries(parseThat dyninstAPI) +target_link_private_libraries(parseThat dyninstAPI patchAPI parseAPI instructionAPI stackwalk symtabAPI common pcontrol dynDwarf dynElf ${Boost_LIBRARIES}) install(TARGETS parseThat RUNTIME DESTINATION bin) diff --git a/patchAPI/CMakeLists.txt b/patchAPI/CMakeLists.txt index 17dfeadb96..0184eba28d 100644 --- a/patchAPI/CMakeLists.txt +++ b/patchAPI/CMakeLists.txt @@ -28,7 +28,7 @@ SET_SOURCE_FILES_PROPERTIES(${SRC_LIST} PROPERTIES LANGUAGE CXX) ADD_DEFINITIONS(-DPATCHAPI_LIB) dyninst_library(patchAPI common instructionAPI parseAPI) -target_link_private_libraries(patchAPI ${Boost_LIBRARIES} -lboost_filesystem) +target_link_private_libraries(patchAPI ${Boost_LIBRARIES}) if (USE_COTIRE) cotire(patchAPI) endif() diff --git a/patchAPI/h/PatchCFG.h b/patchAPI/h/PatchCFG.h index 64f32588c4..14aa0814cb 100644 --- a/patchAPI/h/PatchCFG.h +++ b/patchAPI/h/PatchCFG.h @@ -97,7 +97,7 @@ class PATCHAPI_EXPORT PatchBlock { friend class PatchParseCallback; public: - typedef std::map Insns; + typedef std::map Insns; typedef std::vector edgelist; static PatchBlock *create(ParseAPI::Block *, PatchFunction *); @@ -115,7 +115,7 @@ class PATCHAPI_EXPORT PatchBlock { bool isShared(); int containingFuncs() const; void getInsns(Insns &insns) const; - InstructionAPI::Instruction::Ptr getInsn(Address a) const; + InstructionAPI::Instruction getInsn(Address a) const; std::string disassemble() const; bool containsCall() const { return 0 < numCallEdges(); }; bool containsDynamicCall(); diff --git a/patchAPI/h/Point.h b/patchAPI/h/Point.h index d2489647c3..035ec6357a 100644 --- a/patchAPI/h/Point.h +++ b/patchAPI/h/Point.h @@ -61,8 +61,8 @@ ExitSite_t(PatchFunction *f, PatchBlock *b) : func(f), block(b) {}; struct InsnLoc_t { PatchBlock *block; Address addr; - InstructionAPI::Instruction::Ptr insn; -InsnLoc_t(PatchBlock *b, Address a, InstructionAPI::Instruction::Ptr i) : + InstructionAPI::Instruction insn; +InsnLoc_t(PatchBlock *b, Address a, InstructionAPI::Instruction i) : block(b), addr(a), insn(i) {}; }; @@ -71,52 +71,53 @@ InsnLoc_t(PatchBlock *b, Address a, InstructionAPI::Instruction::Ptr i) : // uniquely identifies a point. struct Location { static Location Function(PatchFunction *f) { - return Location(f, NULL, 0, InstructionAPI::Instruction::Ptr(), NULL, true, Function_); + return Location(f, NULL, 0, InstructionAPI::Instruction(), NULL, true, Function_); } static Location Block(PatchBlock *b) { - return Location(NULL, b, 0, InstructionAPI::Instruction::Ptr(), NULL, true, Block_); + return Location(NULL, b, 0, InstructionAPI::Instruction(), NULL, true, Block_); } static Location BlockInstance(PatchFunction *f, PatchBlock *b, bool trusted = false) { - return Location(f, b, 0, InstructionAPI::Instruction::Ptr(), NULL, trusted, BlockInstance_); + return Location(f, b, 0, InstructionAPI::Instruction(), NULL, trusted, BlockInstance_); } static Location Instruction(InsnLoc_t l) { return Location(NULL, l.block, l.addr, l.insn, NULL, true, Instruction_); } static Location Instruction(PatchBlock *b, Address a) { - return Location(NULL, b, a, InstructionAPI::Instruction::Ptr(), NULL, false, Instruction_); + return Location(NULL, b, a, InstructionAPI::Instruction(), NULL, false, Instruction_); } static Location InstructionInstance(PatchFunction *f, InsnLoc_t l, bool trusted = false) { return Location(f, l.block, l.addr, l.insn, NULL, trusted, InstructionInstance_); } static Location InstructionInstance(PatchFunction *f, PatchBlock *b, Address a) { - return Location(f, b, a, InstructionAPI::Instruction::Ptr(), NULL, false, InstructionInstance_); + return Location(f, b, a, InstructionAPI::Instruction(), NULL, false, InstructionInstance_); } - static Location InstructionInstance(PatchFunction *f, PatchBlock *b, Address a, InstructionAPI::Instruction::Ptr i, bool trusted = false) { + static Location InstructionInstance(PatchFunction *f, PatchBlock *b, Address a, + InstructionAPI::Instruction i, bool trusted = false) { return Location(f, b, a, i, NULL, trusted, InstructionInstance_); } static Location Edge(PatchEdge *e) { - return Location(NULL, NULL, 0, InstructionAPI::Instruction::Ptr(), e, true, Edge_); + return Location(NULL, NULL, 0, InstructionAPI::Instruction(), e, true, Edge_); } static Location EdgeInstance(PatchFunction *f, PatchEdge *e) { - return Location(f, NULL, 0, InstructionAPI::Instruction::Ptr(), e, false, EdgeInstance_); + return Location(f, NULL, 0, InstructionAPI::Instruction(), e, false, EdgeInstance_); } static Location EntrySite(EntrySite_t e) { - return Location(e.func, e.block, 0, InstructionAPI::Instruction::Ptr(), NULL, true, Entry_); + return Location(e.func, e.block, 0, InstructionAPI::Instruction(), NULL, true, Entry_); } static Location EntrySite(PatchFunction *f, PatchBlock *b, bool trusted = false) { - return Location(f, b, 0, InstructionAPI::Instruction::Ptr(), NULL, trusted, Entry_); + return Location(f, b, 0, InstructionAPI::Instruction(), NULL, trusted, Entry_); } static Location CallSite(CallSite_t c) { - return Location(c.func, c.block, 0, InstructionAPI::Instruction::Ptr(), NULL, true, Call_); + return Location(c.func, c.block, 0, InstructionAPI::Instruction(), NULL, true, Call_); } static Location CallSite(PatchFunction *f, PatchBlock *b) { - return Location(f, b, 0, InstructionAPI::Instruction::Ptr(), NULL, false, Call_); + return Location(f, b, 0, InstructionAPI::Instruction(), NULL, false, Call_); } static Location ExitSite(ExitSite_t e) { - return Location(e.func, e.block, 0, InstructionAPI::Instruction::Ptr(), NULL, true, Exit_); + return Location(e.func, e.block, 0, InstructionAPI::Instruction(), NULL, true, Exit_); } static Location ExitSite(PatchFunction *f, PatchBlock *b) { - return Location(f, b, 0, InstructionAPI::Instruction::Ptr(), NULL, false, Exit_); } + return Location(f, b, 0, InstructionAPI::Instruction(), NULL, false, Exit_); } typedef enum { Function_, @@ -138,13 +139,13 @@ struct Location { PatchFunction *func; PatchBlock *block; Address addr; - InstructionAPI::Instruction::Ptr insn; + InstructionAPI::Instruction insn; PatchEdge *edge; bool trusted; type_t type; private: -Location(PatchFunction *f, PatchBlock *b, Address a, InstructionAPI::Instruction::Ptr i, PatchEdge *e, bool u, type_t t) : +Location(PatchFunction *f, PatchBlock *b, Address a, InstructionAPI::Instruction i, PatchEdge *e, bool u, type_t t) : func(f), block(b), addr(a), insn(i), edge(e), trusted(u), type(t) {}; }; @@ -206,7 +207,7 @@ class PATCHAPI_EXPORT Point { // Block instrumentation /w/ optional function context Point(Point::Type t, PatchMgrPtr mgr, PatchBlock *, PatchFunction * = NULL); // Insn instrumentation /w/ optional function context - Point(Point::Type t, PatchMgrPtr mgr, PatchBlock *, Address, InstructionAPI::Instruction::Ptr, PatchFunction * = NULL); + Point(Point::Type t, PatchMgrPtr mgr, PatchBlock *, Address, InstructionAPI::Instruction, PatchFunction * = NULL); // Function entry or during Point(Point::Type t, PatchMgrPtr mgr, PatchFunction *); // Function call or exit site @@ -236,7 +237,7 @@ class PATCHAPI_EXPORT Point { PatchFunction* getCallee(); PatchObject* obj() const; - const InstructionAPI::Instruction::Ptr insn() const { return insn_; } + const InstructionAPI::Instruction& insn() const { return insn_; } PatchFunction *func() const { return the_func_; } PatchBlock *block() const { return the_block_; } @@ -269,7 +270,7 @@ class PATCHAPI_EXPORT Point { PatchBlock* the_block_; PatchEdge* the_edge_; PatchFunction* the_func_; - InstructionAPI::Instruction::Ptr insn_; + InstructionAPI::Instruction insn_; }; inline Point::Type operator|(Point::Type a, Point::Type b) { @@ -368,7 +369,8 @@ class PATCHAPI_EXPORT PointMaker { virtual Point *mkFuncPoint(Point::Type t, PatchMgrPtr m, PatchFunction *); virtual Point *mkFuncSitePoint(Point::Type t, PatchMgrPtr m, PatchFunction *, PatchBlock *); virtual Point *mkBlockPoint(Point::Type t, PatchMgrPtr m, PatchBlock *, PatchFunction *context); - virtual Point *mkInsnPoint(Point::Type t, PatchMgrPtr m, PatchBlock *, Address, InstructionAPI::Instruction::Ptr, PatchFunction *context); + virtual Point *mkInsnPoint(Point::Type t, PatchMgrPtr m, PatchBlock *, Address, InstructionAPI::Instruction, + PatchFunction *context); virtual Point *mkEdgePoint(Point::Type t, PatchMgrPtr m, PatchEdge *, PatchFunction *context); diff --git a/patchAPI/src/ParseCallback.C b/patchAPI/src/ParseCallback.C index c6ece25302..04fb369760 100644 --- a/patchAPI/src/ParseCallback.C +++ b/patchAPI/src/ParseCallback.C @@ -146,6 +146,7 @@ void PatchParseCallback::remove_edge_cb(ParseAPI::Block *block, ParseAPI::Edge * void PatchParseCallback::add_edge_cb(ParseAPI::Block *block, ParseAPI::Edge *edge, edge_type_t type) { PatchObject *pbObj = _obj->addrSpace()->findObject(block->obj()); + if(!pbObj) return; // e.g. sink block PatchBlock *pb = pbObj->getBlock(block, false); if (!pb) return; // We haven't created the block, so we'll get around to the edge later. @@ -159,6 +160,7 @@ void PatchParseCallback::add_edge_cb(ParseAPI::Block *block, ParseAPI::Edge *edg return; ParseAPI::Block *block2 = (type == source) ? edge->src() : edge->trg(); + if(!block2->obj()) return; PatchObject *pb2Obj = _obj->addrSpace()->findObject(block2->obj()); PatchBlock *pb2 = pb2Obj->getBlock(block2); assert(pb2); diff --git a/patchAPI/src/PatchBlock.C b/patchAPI/src/PatchBlock.C index e144a5c581..be5bf1147a 100644 --- a/patchAPI/src/PatchBlock.C +++ b/patchAPI/src/PatchBlock.C @@ -244,12 +244,12 @@ PatchBlock::containsDynamicCall() { // see if it's a static call to a bad address if ((*eit)->sinkEdge()) { using namespace InstructionAPI; - Instruction::Ptr insn = getInsn(last()); - if (insn->readsMemory()) { // memory indirect + Instruction insn = getInsn(last()); + if (insn.readsMemory()) { // memory indirect return true; } else { // check for register indirect set regs; - Expression::Ptr tExpr = insn->getControlFlowTarget(); + Expression::Ptr tExpr = insn.getControlFlowTarget(); if (tExpr) tExpr->getUses(regs); for (set::iterator rit = regs.begin(); @@ -275,12 +275,12 @@ PatchBlock::disassemble() const { getInsns(instances); for (Insns::iterator iter = instances.begin(); iter != instances.end(); ++iter) { - ret << "\t" << hex << iter->first << ": " << iter->second->format() << dec << endl; + ret << "\t" << hex << iter->first << ": " << iter->second.format() << dec << endl; } return ret.str(); } -InstructionAPI::Instruction::Ptr +InstructionAPI::Instruction PatchBlock::getInsn(Address a) const { Insns insns; getInsns(insns); @@ -296,7 +296,7 @@ PatchBlock::long_format() const { getInsns(insns); for (Insns::iterator iter = insns.begin(); iter != insns.end(); ++iter) { - ret << "\t" << hex << iter->first << " : " << iter->second->format() << dec << endl; + ret << "\t" << hex << iter->first << " : " << iter->second.format() << dec << endl; } return ret.str(); } @@ -358,7 +358,7 @@ Point *PatchBlock::findPoint(Location loc, Point::Type type, bool create) { return points_.during; break; case Point::PreInsn: { - if (!loc.addr || !loc.insn) return NULL; + if (!loc.addr || !loc.insn.isValid()) return NULL; InsnPoints::iterator iter2 = points_.preInsn.find(loc.addr); if (iter2 == points_.preInsn.end()) { if (!create) return NULL; @@ -372,7 +372,7 @@ Point *PatchBlock::findPoint(Location loc, Point::Type type, bool create) { break; } case Point::PostInsn: { - if (!loc.addr || !loc.insn) return NULL; + if (!loc.addr || !loc.insn.isValid()) return NULL; InsnPoints::iterator iter2 = points_.postInsn.find(loc.addr); if (iter2 == points_.postInsn.end()) { if (!create) return NULL; @@ -616,7 +616,7 @@ bool BlockPoints::consistency(const PatchBlock *b, const PatchFunction *f) const if (iter->second->func() != f) CONSIST_FAIL; if (iter->second->addr() != iter->first) CONSIST_FAIL; if (iter->second->type() != Point::PreInsn) CONSIST_FAIL; - if (!b->getInsn(iter->first)) CONSIST_FAIL; + if (!b->getInsn(iter->first).isValid()) CONSIST_FAIL; } for (InsnPoints::const_iterator iter = postInsn.begin(); iter != postInsn.end(); ++iter) { if (!iter->second->consistency()) CONSIST_FAIL; @@ -624,7 +624,7 @@ bool BlockPoints::consistency(const PatchBlock *b, const PatchFunction *f) const if (iter->second->func() != f) CONSIST_FAIL; if (iter->second->addr() != iter->first) CONSIST_FAIL; if (iter->second->type() != Point::PostInsn) CONSIST_FAIL; - if (!b->getInsn(iter->first)) CONSIST_FAIL; + if (!b->getInsn(iter->first).isValid()) CONSIST_FAIL; } return true; } diff --git a/patchAPI/src/PatchFunction.C b/patchAPI/src/PatchFunction.C index 36d3b6f344..0666705e71 100644 --- a/patchAPI/src/PatchFunction.C +++ b/patchAPI/src/PatchFunction.C @@ -211,7 +211,7 @@ Point *PatchFunction::findPoint(Location loc, Point::Type type, bool create) { return iter->second.during; break; case Point::PreInsn: { - if (!loc.addr || !loc.insn) { + if (!loc.addr || !loc.insn.isValid()) { assert(0); } InsnPoints::iterator iter2 = iter->second.preInsn.find(loc.addr); @@ -227,7 +227,7 @@ Point *PatchFunction::findPoint(Location loc, Point::Type type, bool create) { break; } case Point::PostInsn: { - if (!loc.addr || !loc.insn) return NULL; + if (!loc.addr || !loc.insn.isValid()) return NULL; InsnPoints::iterator iter2 = iter->second.postInsn.find(loc.addr); if (iter2 == iter->second.postInsn.end()) { if (!create) return NULL; diff --git a/patchAPI/src/PatchMgr.C b/patchAPI/src/PatchMgr.C index df8431675a..e5a4c74bcb 100644 --- a/patchAPI/src/PatchMgr.C +++ b/patchAPI/src/PatchMgr.C @@ -441,7 +441,7 @@ bool PatchMgr::verify(Location &loc) { if (loc.addr < loc.block->start()) return false; if (loc.addr > loc.block->last()) return false; loc.insn = loc.block->getInsn(loc.addr); - if (!loc.insn) return false; + if (!loc.insn.isValid()) return false; break; case Location::Edge_: break; diff --git a/patchAPI/src/PatchModifier.C b/patchAPI/src/PatchModifier.C index a126d2aa0b..360a48c16b 100644 --- a/patchAPI/src/PatchModifier.C +++ b/patchAPI/src/PatchModifier.C @@ -96,7 +96,7 @@ bool PatchModifier::redirect(PatchEdge *edge, PatchBlock *target) { PatchBlock *PatchModifier::split(PatchBlock *block, Address addr, bool trust, Address newlast) { if (!trust) { - if (!block->getInsn(addr)) return NULL; + if (!block->getInsn(addr).isValid()) return NULL; newlast = -1; // If we don't trust the address, don't // trust the new last instruction addr. } diff --git a/patchAPI/src/Point.C b/patchAPI/src/Point.C index 8bbf56ab44..0b84a8c7f0 100644 --- a/patchAPI/src/Point.C +++ b/patchAPI/src/Point.C @@ -112,7 +112,7 @@ PatchObject *Point::obj() const { } /* for single instruction */ -Point::Point(Point::Type type, PatchMgrPtr mgr, PatchBlock *b, Address a, InstructionAPI::Instruction::Ptr i, PatchFunction *f) +Point::Point(Point::Type type, PatchMgrPtr mgr, PatchBlock *b, Address a, InstructionAPI::Instruction i, PatchFunction *f) :addr_(a), type_(type), mgr_(mgr), the_block_(b), the_edge_(NULL), the_func_(f), insn_(i) { initCodeStructure(); @@ -280,7 +280,7 @@ bool Point::consistency() const { switch (type()) { case PreInsn: case PostInsn: - if (!insn()) return false; + if (!insn().isValid()) return false; if (!addr()) return false; if (!block()) return false; // Can have a function or not, that's okay @@ -289,14 +289,14 @@ bool Point::consistency() const { case BlockEntry: case BlockExit: case BlockDuring: - if (insn()) return false; + if (insn().isValid()) return false; if (addr()) return false; if (!block()) return false; if (edge()) return false; break; case FuncEntry: case FuncDuring: - if (insn()) return false; + if (insn().isValid()) return false; if (addr()) return false; if (block()) return false; if (edge()) return false; @@ -305,14 +305,14 @@ bool Point::consistency() const { case PreCall: case PostCall: case FuncExit: - if (insn()) return false; + if (insn().isValid()) return false; if (addr()) return false; if (!block()) return false; if (edge()) return false; if (!func()) return false; break; case EdgeDuring: - if (insn()) return false; + if (insn().isValid()) return false; if (addr()) return false; if (block()) return false; if (!edge()) return false; diff --git a/patchAPI/src/PointMaker.C b/patchAPI/src/PointMaker.C index 6574710674..df32abc478 100644 --- a/patchAPI/src/PointMaker.C +++ b/patchAPI/src/PointMaker.C @@ -82,8 +82,8 @@ Point *PointMaker::mkFuncSitePoint(Point::Type t, PatchMgrPtr m, PatchFunction * Point *PointMaker::mkBlockPoint(Point::Type t, PatchMgrPtr m, PatchBlock *b, PatchFunction *f) { return new Point(t, m, b, f); } -Point *PointMaker::mkInsnPoint(Point::Type t, PatchMgrPtr m, PatchBlock *b, - Address a, InstructionAPI::Instruction::Ptr i, PatchFunction *f) { +Point *PointMaker::mkInsnPoint(Point::Type t, PatchMgrPtr m, PatchBlock *b, + Address a, InstructionAPI::Instruction i, PatchFunction *f) { return new Point(t, m, b, a, i, f); } Point *PointMaker::mkEdgePoint(Point::Type t, PatchMgrPtr m, PatchEdge *e, PatchFunction *f) { diff --git a/stackwalk/CMakeLists.txt b/stackwalk/CMakeLists.txt index 9b71ddfded..1397feccfe 100644 --- a/stackwalk/CMakeLists.txt +++ b/stackwalk/CMakeLists.txt @@ -108,7 +108,7 @@ endif() dyninst_library(stackwalk ${DEPS}) -#target_link_private_libraries(stackwalk ${Boost_LIBRARIES} -lboost_filesystem) +target_link_private_libraries(stackwalk ${Boost_LIBRARIES}) if (USE_COTIRE) cotire(stackwalk) endif() diff --git a/stackwalk/src/callchecker-IAPI.C b/stackwalk/src/callchecker-IAPI.C index 0b39b29e4d..ef79289252 100644 --- a/stackwalk/src/callchecker-IAPI.C +++ b/stackwalk/src/callchecker-IAPI.C @@ -63,13 +63,13 @@ bool CallChecker::isPrevInstrACall(Address addr, Address &target) unsigned int aligned = 0; // Decode all instructions in the buffer - InstructionAPI::Instruction::Ptr tmp = d.decode(); - InstructionAPI::Instruction::Ptr prevInsn = tmp; + InstructionAPI::Instruction tmp = d.decode(); + InstructionAPI::Instruction prevInsn = tmp; - while (tmp) { - if (tmp->size() > size) break; + while (tmp.isValid()) { + if (tmp.size() > size) break; - aligned += tmp->size(); + aligned += tmp.size(); prevInsn = tmp; tmp = d.decode(); } @@ -77,8 +77,8 @@ bool CallChecker::isPrevInstrACall(Address addr, Address &target) // prevInsn was the last valid instruction found // is it (a) aligned and (b) a call? if ( (aligned == size) && - (prevInsn->getOperation().getID() == e_call) ) { - int disp = *((int*)(bufferPtr+(size-prevInsn->size() + 2))); + (prevInsn.getOperation().getID() == e_call) ) { + int disp = *((int*)(bufferPtr+(size-prevInsn.size() + 2))); target = addr + disp; sw_printf("[%s:%u] - Found call encoded by %d to %lx (addr = %lx, disp = %lx)\n", FILE__, __LINE__, diff --git a/stackwalk/src/framestepper.C b/stackwalk/src/framestepper.C index 0bf607e48b..eda53a974e 100644 --- a/stackwalk/src/framestepper.C +++ b/stackwalk/src/framestepper.C @@ -77,10 +77,8 @@ void FrameStepper::registerStepperGroup(StepperGroup *group) unsigned addr_width = group->getWalker()->getProcessState()->getAddressWidth(); if (addr_width == 4) group->addStepper(this, 0, 0xffffffff); -#if defined(arch_64bit) else if (addr_width == 8) group->addStepper(this, 0, 0xffffffffffffffff); -#endif else assert(0 && "Unknown architecture word size"); } @@ -182,10 +180,8 @@ void DyninstInstrStepperImpl::registerStepperGroup(StepperGroup *group) unsigned addr_width = group->getWalker()->getProcessState()->getAddressWidth(); if (addr_width == 4) group->addStepper(parent, 0, 0xffffffff); -#if defined(arch_64bit) else if (addr_width == 8) group->addStepper(parent, 0, 0xffffffffffffffff); -#endif else assert(0 && "Unknown architecture word size"); } @@ -249,10 +245,8 @@ void BottomOfStackStepperImpl::registerStepperGroup(StepperGroup *group) unsigned addr_width = group->getWalker()->getProcessState()->getAddressWidth(); if (addr_width == 4) group->addStepper(parent, 0, 0xffffffff); -#if defined(arch_64bit) else if (addr_width == 8) group->addStepper(parent, 0, 0xffffffffffffffff); -#endif else assert(0 && "Unknown architecture word size"); } @@ -309,10 +303,8 @@ void DyninstDynamicStepperImpl::registerStepperGroup(StepperGroup *group) unsigned addr_width = group->getWalker()->getProcessState()->getAddressWidth(); if (addr_width == 4) group->addStepper(parent, 0, 0xffffffff); -#if defined(arch_64bit) else if (addr_width == 8) group->addStepper(parent, 0, 0xffffffffffffffff); -#endif else assert(0 && "Unknown architecture word size"); } diff --git a/stackwalk/src/linux-aarch64-swk.C b/stackwalk/src/linux-aarch64-swk.C index c746cd0d54..a1d5e3d926 100644 --- a/stackwalk/src/linux-aarch64-swk.C +++ b/stackwalk/src/linux-aarch64-swk.C @@ -38,6 +38,7 @@ #include "stackwalk/src/dbgstepper-impl.h" #include "common/h/dyn_regs.h" +#include "frame.h" #include #include @@ -45,7 +46,7 @@ #include #include -#define TEST_DEBUGINFO_ALONE 1 +#define TEST_DEBUGINFO_ALONE 0 using namespace Dyninst; using namespace Dyninst::Stackwalker; @@ -55,7 +56,17 @@ bool Walker::createDefaultSteppers() FrameStepper *stepper; bool result; -#if !TEST_DEBUGINFO_ALONE + stepper = new DebugStepper(this); + result = addStepper(stepper); + if (!result){ + sw_printf("[%s:%u] - Error adding stepper %p\n", FILE__, __LINE__, + stepper); + return false; + }else{ + sw_printf("[%s:%u] - Stepper %p is DebugStepper\n", + FILE__, __LINE__, stepper); + } + stepper = new FrameFuncStepper(this); result = addStepper(stepper); if (!result) { @@ -77,18 +88,6 @@ bool Walker::createDefaultSteppers() FILE__, __LINE__, stepper); } -#else - stepper = new DebugStepper(this); - result = addStepper(stepper); - if (!result){ - sw_printf("[%s:%u] - Error adding stepper %p\n", FILE__, __LINE__, - stepper); - return false; - }else{ - sw_printf("[%s:%u] - Stepper %p is DebugStepper\n", - FILE__, __LINE__, stepper); - } -#endif return true; } @@ -113,17 +112,7 @@ bool DebugStepperImpl::isStackRegister(MachRegister reg) return (reg == aarch64::sp); } -gcframe_ret_t SigHandlerStepperImpl::getCallerFrame(const Frame &/*in*/, - Frame &/*out*/) -{ - /** - * TODO: Implement me on non-x86 platforms. - **/ - return gcf_not_me; -} -// what the hell are these numbers? -// could the last developers leave any comments? -/* + static const int fp_offset_64 = 120; static const int pc_offset_64 = 168; static const int frame_size_64 = 1088; @@ -225,4 +214,3 @@ gcframe_ret_t SigHandlerStepperImpl::getCallerFrame(const Frame & in, return gcf_not_me; return gcf_not_me; } -*/ diff --git a/stackwalk/src/linux-x86-swk.C b/stackwalk/src/linux-x86-swk.C index 31ad2e1cf2..499a72ad84 100644 --- a/stackwalk/src/linux-x86-swk.C +++ b/stackwalk/src/linux-x86-swk.C @@ -49,6 +49,8 @@ #include #include #include +#include + using namespace Dyninst; using namespace Dyninst::Stackwalker; diff --git a/symtabAPI/CMakeLists.txt b/symtabAPI/CMakeLists.txt index a5af474a0e..ed2d29df6b 100644 --- a/symtabAPI/CMakeLists.txt +++ b/symtabAPI/CMakeLists.txt @@ -109,7 +109,7 @@ else() endif() dyninst_library(symtabAPI ${DEPS}) -target_link_private_libraries(symtabAPI ${Boost_LIBRARIES} -lboost_filesystem) +target_link_private_libraries(symtabAPI ${Boost_LIBRARIES}) if (USE_COTIRE) cotire(symtabAPI) diff --git a/symtabAPI/h/Collections.h b/symtabAPI/h/Collections.h index 18bb31a634..d03561ca94 100644 --- a/symtabAPI/h/Collections.h +++ b/symtabAPI/h/Collections.h @@ -31,6 +31,7 @@ #ifndef _Collections_h_ #define _Collections_h_ +#include #include "Type.h" #include "Variable.h" #include "Serialization.h" @@ -54,7 +55,7 @@ class DwarfWalker; class SYMTAB_EXPORT localVarCollection : public AnnotationContainer { - std::vector localVars; + tbb::concurrent_vector localVars; bool addItem_impl(localVar *); public: @@ -63,7 +64,7 @@ class SYMTAB_EXPORT localVarCollection : public AnnotationContainer void addLocalVar(localVar * var); localVar * findLocalVar(std::string &name); - std::vector *getAllVars(); + const tbb::concurrent_vector &getAllVars() const; Serializable *ac_serialize_impl(SerializerBase *, const char * = "localVarCollection") THROW_SPEC (SerializerError); }; @@ -82,9 +83,9 @@ class SYMTAB_EXPORT typeCollection : public Serializable//, public AnnotatableSp friend class Type; friend class DwarfWalker; - dyn_hash_map typesByName; - dyn_hash_map globalVarsByName; - dyn_hash_map typesByID; + tbb::concurrent_hash_map typesByName; + tbb::concurrent_hash_map globalVarsByName; + tbb::concurrent_hash_map typesByID; // DWARF: @@ -103,12 +104,9 @@ class SYMTAB_EXPORT typeCollection : public Serializable//, public AnnotatableSp ~typeCollection(); public: static void addDeferredLookup(int, dataClass, Type **); + static boost::mutex create_lock; static typeCollection *getModTypeCollection(Module *mod); -#if 0 - static typeCollection *getGlobalTypeCollection(); - static void freeTypeCollection(typeCollection *tc); -#endif // DWARF... bool dwarfParsed() { return dwarfParsed_; } @@ -119,6 +117,7 @@ class SYMTAB_EXPORT typeCollection : public Serializable//, public AnnotatableSp Type *findTypeLocal(std::string name); Type *findTypeLocal(const int ID); void addType(Type *type); + void addType(Type *type, boost::lock_guard&); void addGlobalVariable(std::string &name, Type *type); /* Some debug formats allow forward references. Rather than @@ -135,6 +134,10 @@ class SYMTAB_EXPORT typeCollection : public Serializable//, public AnnotatableSp std::vector *getAllTypes(); std::vector > *getAllGlobalVariables(); void clearNumberedTypes(); + private: + boost::mutex placeholder_mutex; // The only intermodule contention should be around + // typedefs/other placeholders, but we'll go ahead and lock around type add operations + // to be safe }; /* diff --git a/symtabAPI/h/Module.h b/symtabAPI/h/Module.h index 6c6cc2ab99..4f3941dd46 100644 --- a/symtabAPI/h/Module.h +++ b/symtabAPI/h/Module.h @@ -86,7 +86,6 @@ namespace Dyninst{ typedef StatementLess LineNoTupleLess; bool operator==(const Statement &cmp) const; -// bool operator==(const char* file) const {return strcmp(file, first) == 0; } bool operator==(Offset addr) const { return AddressRange::contains(addr); } @@ -110,8 +109,6 @@ namespace Dyninst{ typedef Statement* Ptr; typedef const Statement* ConstPtr; -// typedef boost::shared_ptr Ptr; -// typedef boost::shared_ptr ConstPtr; }; template diff --git a/symtabAPI/h/StringTable.h b/symtabAPI/h/StringTable.h index e6d0a451ca..09a871a87a 100644 --- a/symtabAPI/h/StringTable.h +++ b/symtabAPI/h/StringTable.h @@ -10,6 +10,8 @@ #include #include #include +#include +#include namespace Dyninst { namespace SymtabAPI { diff --git a/symtabAPI/h/Symtab.h b/symtabAPI/h/Symtab.h index cb7185a5fa..62551d3cf6 100644 --- a/symtabAPI/h/Symtab.h +++ b/symtabAPI/h/Symtab.h @@ -44,6 +44,8 @@ #include "dyninstversion.h" +#include "pfq-rwlock.h" + #include "boost/shared_ptr.hpp" #include "boost/multi_index_container.hpp" #include @@ -368,6 +370,7 @@ class SYMTAB_EXPORT Symtab : public LookupInterface, /***** Error Handling *****/ static SymtabError getLastSymtabError(); + static void setSymtabError(SymtabError new_err); static std::string printError(SymtabError serr); ~Symtab(); @@ -465,7 +468,8 @@ class SYMTAB_EXPORT Symtab : public LookupInterface, static boost::shared_ptr setupStdTypes(); static boost::shared_ptr setupBuiltinTypes(); - + pfq_rwlock_t symbols_rwlock; + // boost::mutex symbols_mutex; std::string member_name_; Offset member_offset_; diff --git a/symtabAPI/h/Type.h b/symtabAPI/h/Type.h index f1cfb93e44..4421657578 100644 --- a/symtabAPI/h/Type.h +++ b/symtabAPI/h/Type.h @@ -34,6 +34,7 @@ #include "Serialization.h" #include "Annotatable.h" #include "symutil.h" +#include namespace Dyninst{ namespace SymtabAPI{ @@ -230,7 +231,7 @@ class SYMTAB_EXPORT Type : public Serializable, public TYPE_ANNOTATABLE_CLASS class SYMTAB_EXPORT fieldListInterface { public: virtual ~fieldListInterface() {}; - virtual std::vector *getComponents() const = 0; + virtual tbb::concurrent_vector *getComponents() const = 0; }; class SYMTAB_EXPORT rangedInterface { @@ -253,17 +254,17 @@ class SYMTAB_EXPORT fieldListType : public Type, public fieldListInterface private: void fixupComponents(); protected: - std::vector fieldList; - std::vector *derivedFieldList; + tbb::concurrent_vector fieldList; + tbb::concurrent_vector *derivedFieldList; fieldListType(std::string &name, typeId_t ID, dataClass typeDes); /* Each subclass may need to update its size after adding a field */ public: fieldListType(); ~fieldListType(); bool operator==(const Type &) const; - std::vector *getComponents() const; + tbb::concurrent_vector *getComponents() const; - std::vector *getFields() const; + tbb::concurrent_vector *getFields() const; virtual void postFieldInsert(int nsize) = 0; @@ -316,16 +317,16 @@ class SYMTAB_EXPORT derivedType : public Type, public derivedInterface { class SYMTAB_EXPORT typeEnum : public Type { private: - std::vector > consts; + tbb::concurrent_vector > consts; public: typeEnum(); typeEnum(typeId_t ID, std::string name = ""); typeEnum(std::string name); - static typeEnum *create(std::string &name, std::vector *>&elements, + static typeEnum *create(std::string &name, tbb::concurrent_vector *>&elements, Symtab *obj = NULL); - static typeEnum *create(std::string &name, std::vector &constNames, Symtab *obj); + static typeEnum *create(std::string &name, tbb::concurrent_vector &constNames, Symtab *obj); bool addConstant(const std::string &fieldname,int value); - std::vector > &getConstants(); + tbb::concurrent_vector > &getConstants(); bool setName(const char *name); bool isCompatible(Type *otype); void serialize_specific(SerializerBase *) THROW_SPEC(SerializerError); @@ -336,19 +337,19 @@ class SYMTAB_EXPORT typeFunction : public Type { void fixupUnknowns(Module *); private: Type *retType_; /* Return type of the function */ - std::vector params_; + tbb::concurrent_vector params_; public: typeFunction(); typeFunction(typeId_t ID, Type *retType, std::string name = ""); typeFunction(Type *retType, std::string name = ""); static typeFunction *create(std::string &name, Type *retType, - std::vector ¶mTypes, Symtab *obj = NULL); + tbb::concurrent_vector ¶mTypes, Symtab *obj = NULL); ~typeFunction(); bool addParam( Type *type); Type *getReturnType() const; bool setRetType(Type *rtype); - std::vector &getParams(); + tbb::concurrent_vector &getParams(); bool isCompatible(Type *otype); void serialize_specific(SerializerBase *) THROW_SPEC(SerializerError); }; @@ -368,7 +369,7 @@ class SYMTAB_EXPORT typeScalar : public Type { class SYMTAB_EXPORT typeCommon : public fieldListType { private: - std::vector cblocks; + tbb::concurrent_vector cblocks; protected: void postFieldInsert(int nsize) { size_ += nsize; } //void postFieldInsert(int offset, int nsize) { if ((unsigned int) (offset + nsize) > size_) size_ = offset + nsize; } @@ -378,7 +379,7 @@ class SYMTAB_EXPORT typeCommon : public fieldListType { typeCommon(typeId_t ID, std::string name = ""); typeCommon(std::string name); static typeCommon *create(std::string &name, Symtab *obj = NULL); - std::vector *getCblocks() const; + tbb::concurrent_vector *getCblocks() const; void beginCommonBlock(); void endCommonBlock(Symbol *, void *baseAddr); void serialize_specific(SerializerBase *) THROW_SPEC(SerializerError); @@ -389,15 +390,15 @@ class SYMTAB_EXPORT CBlock : public Serializable, public AnnotatableSparse friend class typeCommon; private: // the list of fields - std::vector fieldList; + tbb::concurrent_vector fieldList; // which functions use this list // Should probably be updated to use aggregates - std::vector functions; + tbb::concurrent_vector functions; public: - std::vector *getComponents(); - std::vector *getFunctions(); + tbb::concurrent_vector *getComponents(); + tbb::concurrent_vector *getFunctions(); void fixupUnknowns(Module *); @@ -415,10 +416,10 @@ class SYMTAB_EXPORT typeStruct : public fieldListType { typeStruct(); typeStruct(typeId_t ID, std::string name = ""); typeStruct(std::string name); - static typeStruct *create(std::string &name, std::vector< std::pair *> &flds, + static typeStruct *create(std::string &name, tbb::concurrent_vector< std::pair *> &flds, Symtab *obj = NULL); - static typeStruct *create(std::string &name, std::vector &fields, + static typeStruct *create(std::string &name, tbb::concurrent_vector &fields, Symtab *obj = NULL); bool isCompatible(Type *otype); @@ -435,9 +436,9 @@ class SYMTAB_EXPORT typeUnion : public fieldListType { typeUnion(); typeUnion(typeId_t ID, std::string name = ""); typeUnion(std::string name); - static typeUnion *create(std::string &name, std::vector *> &fieldNames, + static typeUnion *create(std::string &name, tbb::concurrent_vector *> &fieldNames, Symtab *obj = NULL); - static typeUnion *create(std::string &name, std::vector &fields, + static typeUnion *create(std::string &name, tbb::concurrent_vector &fields, Symtab *obj = NULL); bool isCompatible(Type *otype); void serialize_specific(SerializerBase *) THROW_SPEC(SerializerError); diff --git a/symtabAPI/src/Collections.C b/symtabAPI/src/Collections.C index 7431dd6bf7..f6f3545029 100644 --- a/symtabAPI/src/Collections.C +++ b/symtabAPI/src/Collections.C @@ -58,7 +58,7 @@ using namespace Dyninst::SymtabAPI; */ localVarCollection::~localVarCollection() { - std::vector::iterator li = localVars.begin(); + auto li = localVars.begin(); for(;li!=localVars.end();li++) { delete *li; @@ -95,7 +95,7 @@ void localVarCollection::addLocalVar(localVar * var) */ localVar *localVarCollection::findLocalVar(std::string &name){ - std::vector::iterator li = localVars.begin(); + auto li = localVars.begin(); for(;li!=localVars.end();li++) { if (name == (*li)->getName()) { @@ -109,57 +109,18 @@ localVar *localVarCollection::findLocalVar(std::string &name){ * localVarCollection::getAllVars() * this function returns all the local variables in the collection. */ -std::vector *localVarCollection::getAllVars() +const tbb::concurrent_vector &localVarCollection::getAllVars() const { - return &localVars; + return localVars; } -#if !defined(SERIALIZATION_DISABLED) -Serializable *localVarCollection::ac_serialize_impl(SerializerBase *s, const char *tag) THROW_SPEC (SerializerError) -{ - unsigned short lvmagic = 72; - serialize_printf("%s[%d]: welcome to localVarCollection: ac_serialize_impl\n", - FILE__, __LINE__); - ifxml_start_element(s, tag); - gtranslate(s, lvmagic, "LocalVarMagicID"); - gtranslate(s, localVars, "LocalVariables"); - s->magic_check(FILE__, __LINE__); - ifxml_end_element(s, tag); - - if (lvmagic != 72) - { - create_printf("\n\n%s[%d]: FIXME: out-of-sync\n\n\n", FILE__, __LINE__); - } - - serialize_printf("%s[%d]: localVarCollection: ac_serialize_impl, translate done\n", FILE__, __LINE__); - - if (s->isInput()) - { - // rebuild name->variable mapping - for (unsigned int i = 0; i < localVars.size(); ++i) - { - localVar *lv = localVars[i]; - assert(lv); - } - serialize_printf("%s[%d]: deserialized %ld local vars\n", FILE__, __LINE__, localVars.size()); - } - else - serialize_printf("%s[%d]: serialized %ld local vars\n", FILE__, __LINE__, localVars.size()); - - return NULL; -} -#else Serializable *localVarCollection::ac_serialize_impl(SerializerBase *, const char *) THROW_SPEC (SerializerError) { return NULL; } -#endif // Could be somewhere else... for DWARF-work. dyn_hash_map typeCollection::fileToTypesMap; -#if 0 -dyn_hash_map > > typeCollection::deferred_lookups; -#endif dyn_hash_map > *> *deferred_lookups_p = NULL; void typeCollection::addDeferredLookup(int tid, dataClass tdc,Type **th) @@ -253,17 +214,11 @@ bool typeCollection::doDeferredLookups(typeCollection *primary_tc) * Reference count */ -#if 0 -typeCollection *typeCollection::getGlobalTypeCollection() -{ - typeCollection *tc = new typeCollection(); - //tc->refcount++; - return tc; -} -#endif +boost::mutex typeCollection::create_lock; typeCollection *typeCollection::getModTypeCollection(Module *mod) { + boost::lock_guard g(create_lock); if (!mod) return NULL; dyn_hash_map::iterator iter = fileToTypesMap.find((void *)mod); @@ -277,22 +232,6 @@ typeCollection *typeCollection::getModTypeCollection(Module *mod) return newTC; } -#if 0 -void typeCollection::freeTypeCollection(typeCollection *tc) { - assert(tc); - tc->refcount--; - if (tc->refcount == 0) { - dyn_hash_map::iterator iter = fileToTypesMap.begin(); - for (; iter!= fileToTypesMap.end(); iter++) { - if (iter->second == tc) { - fileToTypesMap.erase(iter->first); - break; - } - } - delete tc; - } -} -#endif /* * typeCollection::typeCollection @@ -339,8 +278,10 @@ typeCollection::~typeCollection() */ Type *typeCollection::findType(std::string name) { - if (typesByName.find(name) != typesByName.end()) - return typesByName[name]; + tbb::concurrent_hash_map::const_accessor a; + + if (typesByName.find(a, name)) + return a->second; else if (Symtab::builtInTypes()) return Symtab::builtInTypes()->findBuiltInType(name); else @@ -349,16 +290,19 @@ Type *typeCollection::findType(std::string name) Type *typeCollection::findTypeLocal(std::string name) { - if (typesByName.find(name) != typesByName.end()) - return typesByName[name]; + tbb::concurrent_hash_map::const_accessor a; + + if (typesByName.find(a, name)) + return a->second; else return NULL; } Type *typeCollection::findTypeLocal(const int ID) { - if (typesByID.find(ID) != typesByID.end()) - return typesByID[ID]; + tbb::concurrent_hash_map::const_accessor a; + if (typesByID.find(a, ID)) + return a->second; else return NULL; } @@ -366,9 +310,11 @@ Type *typeCollection::findTypeLocal(const int ID) Type * typeCollection::findOrCreateType( const int ID ) { - if ( typesByID.find(ID) != typesByID.end()) - { - return typesByID[ID]; + boost::lock_guard g(placeholder_mutex); + tbb::concurrent_hash_map::const_accessor a; + if (typesByID.find(a, ID)) + { + return a->second; } Type * returnType = NULL; @@ -386,16 +332,17 @@ Type * typeCollection::findOrCreateType( const int ID ) assert( returnType != NULL ); /* Having created the type, add it. */ - addType( returnType ); + addType( returnType, g ); return returnType; } /* end findOrCreateType() */ Type *typeCollection::findType(const int ID) { - if (typesByID.find(ID) != typesByID.end()) - return typesByID[ID]; - else + tbb::concurrent_hash_map::const_accessor a; + if (typesByID.find(a, ID)) + return a->second; + else { Type *ret = NULL; @@ -417,8 +364,9 @@ Type *typeCollection::findType(const int ID) */ Type *typeCollection::findVariableType(std::string &name) { - if (globalVarsByName.find(name) != globalVarsByName.end()) - return globalVarsByName[name]; + tbb::concurrent_hash_map::const_accessor a; + if (globalVarsByName.find(a, name)) + return a->second; else return (Type *) NULL; } @@ -433,29 +381,32 @@ Type *typeCollection::findVariableType(std::string &name) */ void typeCollection::addType(Type *type) { - if(type->getName() != "") { //Type could have no name. - typesByName[type->getName()] = type; - type->incrRefCount(); - } + boost::lock_guard g(placeholder_mutex); + addType(type, g); - //Types can share the same ID for typedef, thus not adding types with - //same ID to the collection +} +void typeCollection::addType(Type *type, boost::lock_guard& g) +{ + if(type->getName() != "") { //Type could have no name. + tbb::concurrent_hash_map::accessor a; + typesByName.insert(a, make_pair(type->getName(), type)); + type->incrRefCount(); + } + tbb::concurrent_hash_map::accessor id_a; + typesByID.insert(id_a, make_pair(type->getID(), type)); + type->incrRefCount(); - // XXX - Fortran seems to restart type numbers for each subroutine - // if(!(this->findType(type->getID()))) - typesByID[type->getID()] = type; - type->incrRefCount(); } void typeCollection::addGlobalVariable(std::string &name, Type *type) { - - globalVarsByName[name] = type; + tbb::concurrent_hash_map::accessor a; + globalVarsByName.insert(a, make_pair(type->getName(), type)); } void typeCollection::clearNumberedTypes() { - for (dyn_hash_map::iterator it = typesByID.begin(); + for (auto it = typesByID.begin(); it != typesByID.end(); it ++) { @@ -475,7 +426,7 @@ std::vector *typeCollection::getAllTypes() { //for (dyn_hash_map::iterator it = typesByID.begin(); // it != typesByID.end(); // it ++) { - for (dyn_hash_map::iterator it = typesByName.begin(); + for (auto it = typesByName.begin(); it != typesByName.end(); it ++) { typesVec->push_back(it->second); @@ -489,7 +440,7 @@ std::vector *typeCollection::getAllTypes() { vector > *typeCollection::getAllGlobalVariables() { vector > *varsVec = new vector >; - for(dyn_hash_map::iterator it = globalVarsByName.begin(); + for(auto it = globalVarsByName.begin(); it != globalVarsByName.end(); it++) { varsVec->push_back(pair(it->first, it->second)); } diff --git a/symtabAPI/src/Function.C b/symtabAPI/src/Function.C index c39bf1e892..31551919d5 100644 --- a/symtabAPI/src/Function.C +++ b/symtabAPI/src/Function.C @@ -109,7 +109,7 @@ bool FunctionBase::getLocalVariables(std::vector &vars) if (!locals) return false; - std::vector &p = *locals->getAllVars(); + auto p = locals->getAllVars(); std::copy(p.begin(), p.end(), back_inserter(vars)); if (p.empty()) @@ -123,7 +123,7 @@ bool FunctionBase::getParams(std::vector ¶ms_) if (!params) return false; - std::vector &p = *params->getAllVars(); + auto p = params->getAllVars(); std::copy(p.begin(), p.end(), back_inserter(params_)); if (p.empty()) diff --git a/symtabAPI/src/LineInformation.C b/symtabAPI/src/LineInformation.C index 1bac6c8678..c8b49c9cd4 100644 --- a/symtabAPI/src/LineInformation.C +++ b/symtabAPI/src/LineInformation.C @@ -105,7 +105,6 @@ std::string print(const Dyninst::SymtabAPI::Statement& stmt) bool LineInformation::getSourceLines(Offset addressInRange, vector &lines) { - ++num_queries; const_iterator start_addr_valid = project(get().lower_bound(addressInRange )); const_iterator end_addr_valid = impl_t::upper_bound(addressInRange ); while(start_addr_valid != end_addr_valid && start_addr_valid != end()) @@ -114,10 +113,6 @@ bool LineInformation::getSourceLines(Offset addressInRange, { lines.push_back(*start_addr_valid); } - else - { - ++wasted_compares; - } ++start_addr_valid; } return true; @@ -188,6 +183,7 @@ unsigned LineInformation::getSize() const LineInformation::~LineInformation() { + impl_t::clear_(); } LineInformation::const_line_info_iterator LineInformation::begin_by_source() const { diff --git a/symtabAPI/src/Module.C b/symtabAPI/src/Module.C index d3923376f0..17b26a28fb 100644 --- a/symtabAPI/src/Module.C +++ b/symtabAPI/src/Module.C @@ -108,7 +108,7 @@ string Module::getCompDir() } -bool Module::findSymbol(std::vector &found, +bool Module::findSymbol(std::vector &found, const std::string& name, Symbol::SymbolType sType, NameType nameType, diff --git a/symtabAPI/src/Object-elf.C b/symtabAPI/src/Object-elf.C index 6840e92866..fcf261d975 100644 --- a/symtabAPI/src/Object-elf.C +++ b/symtabAPI/src/Object-elf.C @@ -55,13 +55,12 @@ using namespace std; #endif #if defined(cap_dwarf) + #include "dwarf.h" #endif //#include "symutil.h" -#include "common/src/pathName.h" -#include "Collections.h" #if defined(TIMED_PARSE) #include #endif @@ -89,30 +88,30 @@ Symbol *symt_current_func = NULL; std::vector opdsymbols_; -extern void print_symbols( std::vector< Symbol *>& allsymbols ); -extern void print_symbol_map( dyn_hash_map< std::string, std::vector< Symbol *> > *symbols); +extern void print_symbols(std::vector &allsymbols); + +extern void print_symbol_map(dyn_hash_map > *symbols); void (*dwarf_err_func)(const char *); // error callback for dwarf errors -static bool pdelf_check_ehdr(Elf_X &elf) -{ +static bool pdelf_check_ehdr(Elf_X &elf) { // Elf header integrity check // This implies a valid header is a header for an executable, a shared object // or a relocatable file (e.g .o) and it either has section headers or program headers - return ( (elf.e_type() == ET_EXEC || elf.e_type() == ET_DYN || elf.e_type() == ET_REL ) && - ( ((elf.e_shoff() != 0) && (elf.e_shnum() != 0)) - || ((elf.e_phoff() != 0) && (elf.e_phnum() != 0)) - ) + return ((elf.e_type() == ET_EXEC || elf.e_type() == ET_DYN || elf.e_type() == ET_REL) && + (((elf.e_shoff() != 0) && (elf.e_shnum() != 0)) + || ((elf.e_phoff() != 0) && (elf.e_phnum() != 0)) + ) ); } -const char *pdelf_get_shnames(Elf_X *elf) -{ +const char *pdelf_get_shnames(Elf_X *elf) { const char *result = NULL; size_t shstrndx = elf->e_shstrndx(); - + // NULL on failure + if (shstrndx >= elf->e_shnum()) return result; Elf_X_Shdr &shstrscn = elf->get_shdr(shstrndx); if (shstrscn.isValid()) { Elf_X_Data shstrdata = shstrscn.get_data(); @@ -127,78 +126,73 @@ const char *pdelf_get_shnames(Elf_X *elf) // // Compare function for use with the Vector sort method. // -struct SectionHeaderSortFunction: public binary_function -{ +struct SectionHeaderSortFunction : public binary_function { bool operator()(Elf_X_Shdr *hdr1, Elf_X_Shdr *hdr2) { return (hdr1->sh_addr() < hdr2->sh_addr()); } }; -Region::perm_t getSegmentPerms(unsigned long flags){ - if(flags == 7) +Region::perm_t getSegmentPerms(unsigned long flags) { + if (flags == 7) return Region::RP_RWX; - else if(flags == 6) + else if (flags == 6) return Region::RP_RW; - else if(flags == 5) + else if (flags == 5) return Region::RP_RX; else return Region::RP_R; } -Region::RegionType getSegmentType(unsigned long type, unsigned long flags) -{ - if(type == PT_DYNAMIC) +Region::RegionType getSegmentType(unsigned long type, unsigned long flags) { + if (type == PT_DYNAMIC) return Region::RT_DYNAMIC; - if(flags == 7) + if (flags == 7) return Region::RT_TEXTDATA; - if(flags == 5) + if (flags == 5) return Region::RT_TEXT; - if(flags == 6) + if (flags == 6) return Region::RT_DATA; return Region::RT_OTHER; } /* binary search to find the section starting at a particular address */ -Elf_X_Shdr *Object::getRegionHdrByAddr(Offset addr) -{ +Elf_X_Shdr *Object::getRegionHdrByAddr(Offset addr) { unsigned end = allRegionHdrs.size() - 1, start = 0; unsigned mid = 0; - while(start < end) { - mid = start + (end-start)/2; - if(allRegionHdrs[mid]->sh_addr() == addr) + while (start < end) { + mid = start + (end - start) / 2; + if (allRegionHdrs[mid]->sh_addr() == addr) return allRegionHdrs[mid]; - else if(allRegionHdrs[mid]->sh_addr() < addr) + else if (allRegionHdrs[mid]->sh_addr() < addr) start = mid + 1; else end = mid; } - if(allRegionHdrs[start]->sh_addr() == addr) + if (allRegionHdrs[start]->sh_addr() == addr) return allRegionHdrs[start]; return NULL; } /* binary search to find the index into the RegionHdrs vector of the section starting at a partidular address*/ -int Object::getRegionHdrIndexByAddr(Offset addr) -{ +int Object::getRegionHdrIndexByAddr(Offset addr) { int end = allRegionHdrs.size() - 1, start = 0; int mid = 0; - while(start < end) { - mid = start + (end-start)/2; - if(allRegionHdrs[mid]->sh_addr() == addr) + while (start < end) { + mid = start + (end - start) / 2; + if (allRegionHdrs[mid]->sh_addr() == addr) return mid; - else if(allRegionHdrs[mid]->sh_addr() < addr) + else if (allRegionHdrs[mid]->sh_addr() < addr) start = mid + 1; else end = mid; } - if(allRegionHdrs[start]->sh_addr() == addr) + if (allRegionHdrs[start]->sh_addr() == addr) return start; return -1; } -Elf_X_Shdr *Object::getRegionHdrByIndex(unsigned index) -{ +Elf_X_Shdr *Object::getRegionHdrByIndex(unsigned index) { if (index >= allRegionHdrs.size()) return NULL; return allRegionHdrs[index]; @@ -206,11 +200,11 @@ Elf_X_Shdr *Object::getRegionHdrByIndex(unsigned index) /* Check if there is a section which belongs to the segment and update permissions of that section. * Return value indicates whether the segment has to be added to the list of regions*/ -bool Object::isRegionPresent(Offset segmentStart, Offset segmentSize, unsigned segPerms){ +bool Object::isRegionPresent(Offset segmentStart, Offset segmentSize, unsigned segPerms) { bool present = false; - for(unsigned i = 0; i < regions_.size() ;i++){ - if((regions_[i]->getDiskOffset() >= segmentStart) && - ((regions_[i]->getDiskOffset()+regions_[i]->getDiskSize()) <= (segmentStart+segmentSize))){ + for (unsigned i = 0; i < regions_.size(); i++) { + if ((regions_[i]->getDiskOffset() >= segmentStart) && + ((regions_[i]->getDiskOffset() + regions_[i]->getDiskSize()) <= (segmentStart + segmentSize))) { present = true; regions_[i]->setRegionPermissions(getSegmentPerms(segPerms)); } @@ -219,19 +213,19 @@ bool Object::isRegionPresent(Offset segmentStart, Offset segmentSize, unsigned s return present; } -Region::perm_t getRegionPerms(unsigned long flags){ - if((flags & SHF_WRITE) && !(flags & SHF_EXECINSTR)) +Region::perm_t getRegionPerms(unsigned long flags) { + if ((flags & SHF_WRITE) && !(flags & SHF_EXECINSTR)) return Region::RP_RW; - else if(!(flags & SHF_WRITE) && (flags & SHF_EXECINSTR)) + else if (!(flags & SHF_WRITE) && (flags & SHF_EXECINSTR)) return Region::RP_RX; - else if((flags & SHF_WRITE) && (flags & SHF_EXECINSTR)) + else if ((flags & SHF_WRITE) && (flags & SHF_EXECINSTR)) return Region::RP_RWX; else return Region::RP_R; } -Region::RegionType getRegionType(unsigned long type, unsigned long flags, const char *reg_name){ - switch(type){ +Region::RegionType getRegionType(unsigned long type, unsigned long flags, const char *reg_name) { + switch (type) { case SHT_SYMTAB: case SHT_DYNSYM: return Region::RT_SYMTAB; @@ -249,9 +243,9 @@ Region::RegionType getRegionType(unsigned long type, unsigned long flags, const else return Region::RT_BSS; case SHT_PROGBITS: - if((flags & SHF_EXECINSTR) && (flags & SHF_WRITE)) + if ((flags & SHF_EXECINSTR) && (flags & SHF_WRITE)) return Region::RT_TEXTDATA; - else if(flags & SHF_EXECINSTR) + else if (flags & SHF_EXECINSTR) return Region::RT_TEXT; else return Region::RT_DATA; @@ -272,7 +266,7 @@ Region::RegionType getRegionType(unsigned long type, unsigned long flags, const static Region::RegionType getRelTypeByElfMachine(Elf_X *localHdr) { Region::RegionType ret; - switch(localHdr->e_machine()) { + switch (localHdr->e_machine()) { case EM_SPARC: case EM_SPARC32PLUS: case EM_SPARCV9: @@ -290,37 +284,37 @@ static Region::RegionType getRelTypeByElfMachine(Elf_X *localHdr) { return ret; } -const char* EDITED_TEXT_NAME = ".edited.text"; +const char *EDITED_TEXT_NAME = ".edited.text"; const char* INIT_NAME = ".init"; -const char *INTERP_NAME = ".interp"; -const char* FINI_NAME = ".fini"; -const char* TEXT_NAME = ".text"; -const char* BSS_NAME = ".bss"; -const char* SYMTAB_NAME = ".symtab"; -const char* STRTAB_NAME = ".strtab"; -const char* STAB_NAME = ".stab"; -const char* STABSTR_NAME = ".stabstr"; -const char* STAB_INDX_NAME = ".stab.index"; -const char* STABSTR_INDX_NAME= ".stab.indexstr"; -const char* COMMENT_NAME= ".comment"; -const char* OPD_NAME = ".opd"; // PPC64 Official Procedure Descriptors +const char *INTERP_NAME = ".interp"; +const char *FINI_NAME = ".fini"; +const char *TEXT_NAME = ".text"; +const char *BSS_NAME = ".bss"; +const char *SYMTAB_NAME = ".symtab"; +const char *STRTAB_NAME = ".strtab"; +const char *STAB_NAME = ".stab"; +const char *STABSTR_NAME = ".stabstr"; +const char *STAB_INDX_NAME = ".stab.index"; +const char *STABSTR_INDX_NAME = ".stab.indexstr"; +const char *COMMENT_NAME = ".comment"; +const char *OPD_NAME = ".opd"; // PPC64 Official Procedure Descriptors // sections from dynamic executables and shared objects -const char* PLT_NAME = ".plt"; +const char *PLT_NAME = ".plt"; #if defined(os_vxworks) const char* REL_PLT_NAME = ".rela.text"; #else -const char* REL_PLT_NAME = ".rela.plt"; // sparc-solaris +const char *REL_PLT_NAME = ".rela.plt"; // sparc-solaris #endif -const char* REL_PLT_NAME2 = ".rel.plt"; // x86-solaris -const char* GOT_NAME = ".got"; -const char* DYNSYM_NAME = ".dynsym"; -const char* DYNSTR_NAME = ".dynstr"; -const char* DATA_NAME = ".data"; -const char* RO_DATA_NAME = ".ro_data"; // mips -const char* DYNAMIC_NAME = ".dynamic"; -const char* EH_FRAME_NAME = ".eh_frame"; -const char* EXCEPT_NAME = ".gcc_except_table"; -const char* EXCEPT_NAME_ALT = ".except_table"; +const char *REL_PLT_NAME2 = ".rel.plt"; // x86-solaris +const char *GOT_NAME = ".got"; +const char *DYNSYM_NAME = ".dynsym"; +const char *DYNSTR_NAME = ".dynstr"; +const char *DATA_NAME = ".data"; +const char *RO_DATA_NAME = ".ro_data"; // mips +const char *DYNAMIC_NAME = ".dynamic"; +const char *EH_FRAME_NAME = ".eh_frame"; +const char *EXCEPT_NAME = ".gcc_except_table"; +const char *EXCEPT_NAME_ALT = ".except_table"; extern template @@ -334,20 +328,19 @@ set debugInfoSections = list_of(string(SYMTAB_NAME)) // loaded_elf(): populate elf section pointers // for EEL rewritten code, also populate "code_*_" members -bool Object::loaded_elf(Offset& txtaddr, Offset& dataddr, - Elf_X_Shdr* &bssscnp, - Elf_X_Shdr*& symscnp, Elf_X_Shdr*& strscnp, - Elf_X_Shdr*& stabscnp, Elf_X_Shdr*& stabstrscnp, - Elf_X_Shdr*& stabs_indxcnp, Elf_X_Shdr*& stabstrs_indxcnp, - Elf_X_Shdr*& rel_plt_scnp, Elf_X_Shdr*& plt_scnp, - Elf_X_Shdr*& got_scnp, Elf_X_Shdr*& dynsym_scnp, - Elf_X_Shdr*& dynstr_scnp, Elf_X_Shdr* &dynamic_scnp, - Elf_X_Shdr*& eh_frame, Elf_X_Shdr*& gcc_except, - Elf_X_Shdr *& interp_scnp, Elf_X_Shdr *& opd_scnp, - bool) -{ +bool Object::loaded_elf(Offset &txtaddr, Offset &dataddr, + Elf_X_Shdr *&bssscnp, + Elf_X_Shdr *&symscnp, Elf_X_Shdr *&strscnp, + Elf_X_Shdr *&stabscnp, Elf_X_Shdr *&stabstrscnp, + Elf_X_Shdr *&stabs_indxcnp, Elf_X_Shdr *&stabstrs_indxcnp, + Elf_X_Shdr *&rel_plt_scnp, Elf_X_Shdr *&plt_scnp, + Elf_X_Shdr *&got_scnp, Elf_X_Shdr *&dynsym_scnp, + Elf_X_Shdr *&dynstr_scnp, Elf_X_Shdr *&dynamic_scnp, + Elf_X_Shdr *&eh_frame, Elf_X_Shdr *&gcc_except, + Elf_X_Shdr *&interp_scnp, Elf_X_Shdr *&opd_scnp, + bool) { std::map secnNameMap; - dwarf_err_func = err_func_; + dwarf_err_func = err_func_; entryAddress_ = elfHdr->e_entry(); no_of_sections_ = elfHdr->e_shnum(); @@ -417,7 +410,7 @@ bool Object::loaded_elf(Offset& txtaddr, Offset& dataddr, for (unsigned i = 0; i < phdr_max_count; i++) { Elf_X_Phdr &elfPhdr = elfHdr->get_phdr(i); - if(elfPhdr.p_type() == PT_DYNAMIC){ + if (elfPhdr.p_type() == PT_DYNAMIC) { dynamic_offset_ = elfPhdr.p_offset(); dynamic_size_ = elfPhdr.p_memsz(); } else if (elfPhdr.p_type() == PT_INTERP) { @@ -435,12 +428,12 @@ bool Object::loaded_elf(Offset& txtaddr, Offset& dataddr, int dynamic_section_index = -1; unsigned int dynamic_section_type = 0; size_t dynamic_section_size = 0; - for (int i = 0; i < elfHdr->e_shnum();++i) { + for (int i = 0; i < elfHdr->e_shnum(); ++i) { Elf_X_Shdr &scn = elfHdr->get_shdr(i); - if (! scn.isValid()) { // section is malformed + if (!scn.isValid()) { // section is malformed continue; } - if ((dynamic_offset_ !=0) && (scn.sh_offset() == dynamic_offset_)) { + if ((dynamic_offset_ != 0) && (scn.sh_offset() == dynamic_offset_)) { if (!foundDynamicSection) { dynamic_section_index = i; dynamic_section_size = scn.sh_size(); @@ -493,7 +486,7 @@ bool Object::loaded_elf(Offset& txtaddr, Offset& dataddr, secAddrTagMapping[dynsecData.d_ptr(j)] = dynsecData.d_tag(j); elf_hash_addr_ = dynsecData.d_ptr(j); break; - case 0x6ffffef5: //DT_GNU_HASH (not defined on all platforms) + case 0x6ffffef5: //DT_GNU_HASH (not defined on all platforms) secAddrTagMapping[dynsecData.d_ptr(j)] = dynsecData.d_tag(j); gnu_hash_addr_ = dynsecData.d_ptr(j); break; @@ -536,12 +529,12 @@ bool Object::loaded_elf(Offset& txtaddr, Offset& dataddr, case DT_VERNEED: case DT_VERDEF: case DT_HASH: - case 0x6ffffef5: // DT_GNU_HASH (not defined on all platforms) + case 0x6ffffef5: // DT_GNU_HASH (not defined on all platforms) if (secTagSizeMapping.find(tag) != secTagSizeMapping.end()) { vector row; row.push_back(it->first); - row.push_back(it->first+ secTagSizeMapping[tag]); + row.push_back(it->first + secTagSizeMapping[tag]); moveSecAddrRange.push_back(row); } else { vector row; @@ -578,7 +571,7 @@ bool Object::loaded_elf(Offset& txtaddr, Offset& dataddr, bool isFromDebugFile = (i >= elfHdr_numSections); Elf_X_Shdr &scn = (!isFromDebugFile) ? elfHdr->get_shdr(i) : elfHdrDbg->get_shdr(i - elfHdr_numSections); - if (! scn.isValid()) { // section is malformed + if (!scn.isValid()) { // section is malformed continue; } Elf_X_Shdr *scnp = &scn; @@ -587,15 +580,14 @@ bool Object::loaded_elf(Offset& txtaddr, Offset& dataddr, name = &shnames[scn.sh_name()]; sectionsInOriginalBinary.insert(string(name)); - if(scn.sh_flags() & SHF_ALLOC) { + if (scn.sh_flags() & SHF_ALLOC) { DbgAddrConversion_t orig; orig.name = std::string(name); orig.orig_offset = scn.sh_addr(); secnNameMap[orig.name] = DebugSectionMap.size(); DebugSectionMap.push_back(orig); } - } - else { + } else { if (!shnamesForDebugInfo) break; name = &shnamesForDebugInfo[scn.sh_name()]; @@ -614,7 +606,7 @@ bool Object::loaded_elf(Offset& txtaddr, Offset& dataddr, } } - if(scn.sh_type() == SHT_NOTE) { + if (scn.sh_type() == SHT_NOTE) { hasNoteSection_ = true; } @@ -631,21 +623,20 @@ bool Object::loaded_elf(Offset& txtaddr, Offset& dataddr, data.d_type(ELF_T_XWORD); data.xlatetom(elfHdr->e_endian() ? ELFDATA2MSB : ELFDATA2LSB); } - if(strcmp(name, TEXT_NAME) == 0 || strcmp(name, ".rodata") == 0 || - strcmp(name, INIT_NAME) == 0 || strcmp(name, FINI_NAME) == 0 || - (scn.sh_flags() & SHF_EXECINSTR)) { - data.d_type(ELF_T_WORD); + if(strcmp(name, TEXT_NAME) == 0 || strcmp(name, ".rodata") == 0|| + strcmp(name, INIT_NAME) == 0 || strcmp(name, FINI_NAME) == 0 || + (scn.sh_flags() & SHF_EXECINSTR)) { data.d_type(ELF_T_WORD); data.xlatetom(elfHdr->e_endian() ? ELFDATA2MSB : ELFDATA2LSB); } } - if(scn.sh_flags() & SHF_ALLOC) { + if (scn.sh_flags() & SHF_ALLOC) { // .bss, etc. have a disk size of 0 - unsigned long diskSize = (scn.sh_type() == SHT_NOBITS) ? 0 : scn.sh_size(); + unsigned long diskSize = (scn.sh_type() == SHT_NOBITS) ? 0 : scn.sh_size(); Region *reg = new Region(i, name, scn.sh_addr(), diskSize, scn.sh_addr(), scn.sh_size(), - ((char*)data.d_buf()), + ((char *) data.d_buf()), getRegionPerms(scn.sh_flags()), getRegionType(scn.sh_type(), scn.sh_flags(), @@ -654,10 +645,9 @@ bool Object::loaded_elf(Offset& txtaddr, Offset& dataddr, scn.sh_addralign()); reg->setFileOffset(scn.sh_offset()); regions_.push_back(reg); - } - else { + } else { Region *reg = new Region(i, name, scn.sh_addr(), scn.sh_size(), 0, 0, - ((char*)data.d_buf()), + ((char *) data.d_buf()), getRegionPerms(scn.sh_flags()), getRegionType(scn.sh_type(), scn.sh_flags(), @@ -676,8 +666,8 @@ bool Object::loaded_elf(Offset& txtaddr, Offset& dataddr, EEL = true; if (txtaddr == 0) txtaddr = scn.sh_addr(); - char *file_ptr = (char *)mf->base_addr(); - code_ptr_ = (char *)(void*)&file_ptr[scn.sh_offset() - EXTRA_SPACE]; + char *file_ptr = (char *) mf->base_addr(); + code_ptr_ = (char *) (void *) &file_ptr[scn.sh_offset() - EXTRA_SPACE]; code_off_ = scn.sh_addr() - EXTRA_SPACE; code_len_ = scn.sh_size() + EXTRA_SPACE; } @@ -691,7 +681,7 @@ bool Object::loaded_elf(Offset& txtaddr, Offset& dataddr, // .o's don't have program headers, so these members need // to be populated here - if( !elfHdr->e_phnum() && !code_len_) { + if (!elfHdr->e_phnum() && !code_len_) { // Populate code members code_ptr_ = reinterpret_cast(scn.get_data().d_buf()); code_off_ = scn.sh_offset(); @@ -705,23 +695,20 @@ bool Object::loaded_elf(Offset& txtaddr, Offset& dataddr, // .o's don't have program headers, so these members need // to be populated here - if( !elfHdr->e_phnum() && !data_len_) { + if (!elfHdr->e_phnum() && !data_len_) { // Populate data members data_ptr_ = reinterpret_cast(scn.get_data().d_buf()); data_off_ = scn.sh_offset(); data_len_ = scn.sh_size(); } - } - else if (strcmp(name, RO_DATA_NAME) == 0) { + } else if (strcmp(name, RO_DATA_NAME) == 0) { if (!dataddr) dataddr = scn.sh_addr(); - } - else if (strcmp(name, GOT_NAME) == 0) { + } else if (strcmp(name, GOT_NAME) == 0) { got_scnp = scnp; got_addr_ = scn.sh_addr(); got_size_ = scn.sh_size(); if (!dataddr) dataddr = scn.sh_addr(); - } - else if (strcmp(name, BSS_NAME) == 0) { + } else if (strcmp(name, BSS_NAME) == 0) { bssscnp = scnp; if (!dataddr) dataddr = scn.sh_addr(); } @@ -734,8 +721,7 @@ bool Object::loaded_elf(Offset& txtaddr, Offset& dataddr, symscnp = scnp; symtab_addr_ = scn.sh_addr(); } - } - else if (strcmp(name, STRTAB_NAME) == 0) { + } else if (strcmp(name, STRTAB_NAME) == 0) { if (!strscnp) { strscnp = scnp; strtab_addr_ = scn.sh_addr(); @@ -757,15 +743,15 @@ bool Object::loaded_elf(Offset& txtaddr, Offset& dataddr, } #if defined(os_vxworks) else if ((strcmp(name, REL_PLT_NAME) == 0) || - (strcmp(name, REL_PLT_NAME2) == 0)) { + (strcmp(name, REL_PLT_NAME2) == 0)) { rel_plt_scnp = scnp; rel_plt_addr_ = scn.sh_addr(); rel_plt_size_ = scn.sh_size(); rel_plt_entry_size_ = scn.sh_entsize(); } #else - else if ((secAddrTagMapping.find(scn.sh_addr()) != secAddrTagMapping.end() ) && - secAddrTagMapping[scn.sh_addr()] == DT_JMPREL ) { + else if ((secAddrTagMapping.find(scn.sh_addr()) != secAddrTagMapping.end()) && + secAddrTagMapping[scn.sh_addr()] == DT_JMPREL) { rel_plt_scnp = scnp; rel_plt_addr_ = scn.sh_addr(); rel_plt_size_ = scn.sh_size(); @@ -776,12 +762,11 @@ bool Object::loaded_elf(Offset& txtaddr, Offset& dataddr, opd_scnp = scnp; opd_addr_ = scn.sh_addr(); opd_size_ = scn.sh_size(); - } - else if (strcmp(name, PLT_NAME) == 0) { + } else if (strcmp(name, PLT_NAME) == 0) { plt_scnp = scnp; plt_addr_ = scn.sh_addr(); plt_size_ = scn.sh_size(); - if(getArch() == Dyninst::Arch_x86 || getArch() == Dyninst::Arch_x86_64) { + if (getArch() == Dyninst::Arch_x86 || getArch() == Dyninst::Arch_x86_64) { // // On x86, the GNU linker purposefully sets the PLT // table entry size to an incorrect value to be @@ -815,12 +800,9 @@ bool Object::loaded_elf(Offset& txtaddr, Offset& dataddr, // //plt_entry_size_ = plt_size_ / ((rel_plt_size_ / rel_plt_entry_size_) + 1); plt_entry_size_ = 16; - } - else - { + } else { plt_entry_size_ = scn.sh_entsize(); - if(getArch() == Dyninst::Arch_ppc32) - { + if (getArch() == Dyninst::Arch_ppc32) { if (scn.sh_flags() & SHF_EXECINSTR) { // Old style executable PLT if (!plt_entry_size_) @@ -847,59 +829,50 @@ bool Object::loaded_elf(Offset& txtaddr, Offset& dataddr, unsigned int index = 0; size_t size = data.d_size(); char *buf = (char *) data.d_buf(); - while (buf && (index < size)) - { - string comment = buf+index; + while (buf && (index < size)) { + string comment = buf + index; size_t pos_p = comment.find("BGP"); size_t pos_q = comment.find("BGQ"); - if (pos_p !=string::npos) { + if (pos_p != string::npos) { isBlueGeneP_ = true; break; - } else if (pos_q !=string::npos) { + } else if (pos_q != string::npos) { isBlueGeneQ_ = true; break; } index += comment.size(); if (comment.size() == 0) { // Skip NULL characters in the comment section - index ++; + index++; } } - } - - else if ((secAddrTagMapping.find(scn.sh_addr()) != secAddrTagMapping.end() ) && - secAddrTagMapping[scn.sh_addr()] == DT_SYMTAB ) { + } else if ((secAddrTagMapping.find(scn.sh_addr()) != secAddrTagMapping.end()) && + secAddrTagMapping[scn.sh_addr()] == DT_SYMTAB) { is_dynamic_ = true; dynsym_scnp = scnp; dynsym_addr_ = scn.sh_addr(); - dynsym_size_ = scn.sh_size()/scn.sh_entsize(); - } - else if ((secAddrTagMapping.find(scn.sh_addr()) != secAddrTagMapping.end() ) && - secAddrTagMapping[scn.sh_addr()] == DT_STRTAB ) { + dynsym_size_ = scn.sh_size() / scn.sh_entsize(); + } else if ((secAddrTagMapping.find(scn.sh_addr()) != secAddrTagMapping.end()) && + secAddrTagMapping[scn.sh_addr()] == DT_STRTAB) { dynstr_scnp = scnp; dynstr_addr_ = scn.sh_addr(); - } - else if (strcmp(name, ".debug_info") == 0) { + } else if (strcmp(name, ".debug_info") == 0) { dwarvenDebugInfo = true; - } - else if (strcmp(name, EH_FRAME_NAME) == 0) { + } else if (strcmp(name, EH_FRAME_NAME) == 0) { eh_frame = scnp; - } - else if ((strcmp(name, EXCEPT_NAME) == 0) || - (strcmp(name, EXCEPT_NAME_ALT) == 0)) { + } else if ((strcmp(name, EXCEPT_NAME) == 0) || + (strcmp(name, EXCEPT_NAME_ALT) == 0)) { gcc_except = scnp; - } - else if (strcmp(name, INTERP_NAME) == 0) { + } else if (strcmp(name, INTERP_NAME) == 0) { interp_scnp = scnp; - } - else if ((int) i == dynamic_section_index) { + } else if ((int) i == dynamic_section_index) { dynamic_scnp = scnp; dynamic_addr_ = scn.sh_addr(); } } - if(!symscnp || !strscnp) { + if (!symscnp || !strscnp) { isStripped = true; - if(dynsym_scnp && dynstr_scnp){ + if (dynsym_scnp && dynstr_scnp) { symscnp = dynsym_scnp; strscnp = dynstr_scnp; } @@ -929,7 +902,7 @@ bool Object::loaded_elf(Offset& txtaddr, Offset& dataddr, // sort the section headers by base address sort(allRegionHdrs.begin(), allRegionHdrs.end(), SectionHeaderSortFunction()); - for (unsigned j = 0 ; j < regions_.size() ; j++) { + for (unsigned j = 0; j < regions_.size(); j++) { if (secAddrTagMapping.find(regions_[j]->getDiskOffset()) != secAddrTagMapping.end()) { secTagRegionMapping[secAddrTagMapping[regions_[j]->getDiskOffset()]] = regions_[j]; } @@ -952,20 +925,18 @@ bool Object::loaded_elf(Offset& txtaddr, Offset& dataddr, return true; } -bool Object::is_offset_in_plt(Offset offset) const -{ +bool Object::is_offset_in_plt(Offset offset) const { return (offset > plt_addr_ && offset < plt_addr_ + plt_size_); } void Object::parseDynamic(Elf_X_Shdr *&dyn_scnp, Elf_X_Shdr *&dynsym_scnp, - Elf_X_Shdr *&dynstr_scnp) -{ + Elf_X_Shdr *&dynstr_scnp) { Elf_X_Data data = dyn_scnp->get_data(); Elf_X_Dyn dyns = data.get_dyn(); int rel_scnp_index = -1; for (unsigned i = 0; i < dyns.count(); ++i) { - switch(dyns.d_tag(i)) { + switch (dyns.d_tag(i)) { case DT_REL: case DT_RELA: /*found Relocation section*/ @@ -976,11 +947,11 @@ void Object::parseDynamic(Elf_X_Shdr *&dyn_scnp, Elf_X_Shdr *&dynsym_scnp, rel_plt_addr_ = (Offset) dyns.d_ptr(i); break; case DT_PLTRELSZ: - rel_plt_size_ = dyns.d_val(i) ; + rel_plt_size_ = dyns.d_val(i); break; case DT_RELSZ: case DT_RELASZ: - rel_size_ = dyns.d_val(i) ; + rel_size_ = dyns.d_val(i); break; case DT_RELENT: case DT_RELAENT: @@ -998,43 +969,42 @@ void Object::parseDynamic(Elf_X_Shdr *&dyn_scnp, Elf_X_Shdr *&dynsym_scnp, break; } } - if (rel_scnp_index != -1) + if (rel_scnp_index != -1) get_relocationDyn_entries(rel_scnp_index, dynsym_scnp, dynstr_scnp); } /* parse relocations for the sections represented by DT_REL/DT_RELA in * the dynamic section. This section is the one we would want to emit */ -bool Object::get_relocationDyn_entries( unsigned rel_scnp_index, - Elf_X_Shdr *&dynsym_scnp, - Elf_X_Shdr *&dynstr_scnp ) -{ +bool Object::get_relocationDyn_entries(unsigned rel_scnp_index, + Elf_X_Shdr *&dynsym_scnp, + Elf_X_Shdr *&dynstr_scnp) { Elf_X_Data symdata = dynsym_scnp->get_data(); Elf_X_Data strdata = dynstr_scnp->get_data(); - Elf_X_Shdr* rel_scnp = NULL; - if( !symdata.isValid() || !strdata.isValid()) + Elf_X_Shdr *rel_scnp = NULL; + if (!symdata.isValid() || !strdata.isValid()) return false; const char *strs = strdata.get_string(); Elf_X_Sym sym = symdata.get_sym(); unsigned num_rel_entries_found = 0; - unsigned num_rel_entries = rel_size_/rel_entry_size_; + unsigned num_rel_entries = rel_size_ / rel_entry_size_; - if (rel_addr_ + rel_size_ > rel_plt_addr_){ + if (rel_addr_ + rel_size_ > rel_plt_addr_) { // REL/RELA section overlaps with REL PLT section - num_rel_entries = (rel_plt_addr_-rel_addr_)/rel_entry_size_; + num_rel_entries = (rel_plt_addr_ - rel_addr_) / rel_entry_size_; } while (num_rel_entries_found != num_rel_entries) { rel_scnp = getRegionHdrByIndex(rel_scnp_index++); Elf_X_Data reldata = rel_scnp->get_data(); - if( ! reldata.isValid()) return false; + if (!reldata.isValid()) return false; Elf_X_Rel rel = reldata.get_rel(); Elf_X_Rela rela = reldata.get_rela(); if (sym.isValid() && (rel.isValid() || rela.isValid()) && strs) { /* Iterate over the entries. */ - for( u_int i = 0; i < (reldata.d_size()/rel_entry_size_); ++i ) { + for (u_int i = 0; i < (reldata.d_size() / rel_entry_size_); ++i) { num_rel_entries_found++; long offset; long addend; @@ -1062,11 +1032,11 @@ bool Object::get_relocationDyn_entries( unsigned rel_scnp_index, // We should never reach this case. return false; }; - relocationEntry re( offset, string( &strs[ sym.st_name(index) ] ), NULL, type ); + relocationEntry re(offset, string(&strs[sym.st_name(index)]), NULL, type); re.setAddend(addend); re.setRegionType(rtype); - if(symbols_.find(&strs[ sym.st_name(index)]) != symbols_.end()){ - vector &syms = symbols_[&strs[ sym.st_name(index)]]; + if (symbols_.find(&strs[sym.st_name(index)]) != symbols_.end()) { + vector &syms = symbols_[&strs[sym.st_name(index)]]; for (vector::iterator i = syms.begin(); i != syms.end(); i++) { if (!(*i)->isInDynSymtab()) continue; @@ -1085,367 +1055,357 @@ bool Object::get_relocationDyn_entries( unsigned rel_scnp_index, return true; } -bool Object::get_relocation_entries( Elf_X_Shdr *&rel_plt_scnp, - Elf_X_Shdr *&dynsym_scnp, - Elf_X_Shdr *&dynstr_scnp ) -{ +bool Object::get_relocation_entries(Elf_X_Shdr *&rel_plt_scnp, + Elf_X_Shdr *&dynsym_scnp, + Elf_X_Shdr *&dynstr_scnp) { if (rel_plt_size_ && rel_plt_addr_) { Elf_X_Data reldata = rel_plt_scnp->get_data(); Elf_X_Data symdata = dynsym_scnp->get_data(); Elf_X_Data strdata = dynstr_scnp->get_data(); - if( reldata.isValid() && symdata.isValid() && strdata.isValid() ) { + if (reldata.isValid() && symdata.isValid() && strdata.isValid()) { Offset next_plt_entry_addr = plt_addr_; - if(getArch() == Dyninst::Arch_x86 || getArch() == Dyninst::Arch_x86_64) - { - next_plt_entry_addr += plt_entry_size_; // 1st PLT entry is special - } - else if(getArch()==Dyninst::Arch_ppc32) - { - bool extraStubs = false; - - // Sanity check. - if (!plt_entry_size_) { - create_printf("%s[%d]: FIXME: plt_entry_size not established\n", FILE__, __LINE__); - plt_entry_size_ = 8; - } - - if (plt_entry_size_ == 8) { - // Old style executable PLT section - next_plt_entry_addr += 9*plt_entry_size_; // 1st 9 PLT entries are special - - } else if (plt_entry_size_ == 16) { - // New style secure PLT - Region *plt = NULL, *dynamic = NULL, - *got = NULL, *glink = NULL; - unsigned int glink_addr = 0; - unsigned int stub_addr = 0; - - // Find the GLINK section. See ppc_elf_get_synthetic_symtab() in - // bfd/elf32-ppc.c of GNU's binutils for more information. - - for (unsigned iter = 0; iter < regions_.size(); ++iter) { - std::string name = regions_[iter]->getRegionName(); - if (name == PLT_NAME) plt = regions_[iter]; - // else if (name == REL_PLT_NAME) relplt = regions_[iter]; - else if (name == DYNAMIC_NAME) dynamic = regions_[iter]; - else if (name == GOT_NAME) got = regions_[iter]; + if (getArch() == Dyninst::Arch_x86 || getArch() == Dyninst::Arch_x86_64) { + next_plt_entry_addr += plt_entry_size_; // 1st PLT entry is special + } else if (getArch() == Dyninst::Arch_ppc32) { + bool extraStubs = false; + + // Sanity check. + if (!plt_entry_size_) { + create_printf("%s[%d]: FIXME: plt_entry_size not established\n", FILE__, __LINE__); + plt_entry_size_ = 8; } - // Rely on .dynamic section for prelinked binaries. - if (dynamic != NULL) { - Elf32_Dyn *dyn = (Elf32_Dyn *)dynamic->getPtrToRawData(); - unsigned int count = dynamic->getMemSize() / sizeof(Elf32_Dyn); - - for (unsigned int i = 0; i < count; ++i) { - // Use DT_LOPROC instead of DT_PPC_GOT to circumvent problems - // caused by early versions of libelf where DT_PPC_GOT has - // yet to be defined. - if (dyn[i].d_tag == DT_LOPROC) { - unsigned int g_o_t = dyn[i].d_un.d_val; - if (got != NULL) { - unsigned char *data = - (unsigned char *)got->getPtrToRawData(); - glink_addr = *(unsigned int *) - (data + (g_o_t - got->getMemOffset() + 4)); - break; + if (plt_entry_size_ == 8) { + // Old style executable PLT section + next_plt_entry_addr += 9 * plt_entry_size_; // 1st 9 PLT entries are special + + } else if (plt_entry_size_ == 16) { + // New style secure PLT + Region *plt = NULL, *dynamic = NULL, + *got = NULL, *glink = NULL; + unsigned int glink_addr = 0; + unsigned int stub_addr = 0; + + // Find the GLINK section. See ppc_elf_get_synthetic_symtab() in + // bfd/elf32-ppc.c of GNU's binutils for more information. + + for (unsigned iter = 0; iter < regions_.size(); ++iter) { + std::string name = regions_[iter]->getRegionName(); + if (name == PLT_NAME) plt = regions_[iter]; + // else if (name == REL_PLT_NAME) relplt = regions_[iter]; + else if (name == DYNAMIC_NAME) dynamic = regions_[iter]; + else if (name == GOT_NAME) got = regions_[iter]; + } + + // Rely on .dynamic section for prelinked binaries. + if (dynamic != NULL) { + Elf32_Dyn *dyn = (Elf32_Dyn *) dynamic->getPtrToRawData(); + unsigned int count = dynamic->getMemSize() / sizeof(Elf32_Dyn); + + for (unsigned int i = 0; i < count; ++i) { + // Use DT_LOPROC instead of DT_PPC_GOT to circumvent problems + // caused by early versions of libelf where DT_PPC_GOT has + // yet to be defined. + if (dyn[i].d_tag == DT_LOPROC) { + unsigned int g_o_t = dyn[i].d_un.d_val; + if (got != NULL) { + unsigned char *data = + (unsigned char *) got->getPtrToRawData(); + glink_addr = *(unsigned int *) + (data + (g_o_t - got->getMemOffset() + 4)); + break; + } } } } - } - - // Otherwise, first entry in .plt section holds the glink address - if (glink_addr == 0) { - unsigned char *data = (unsigned char *)plt->getPtrToRawData(); - glink_addr = *(unsigned int *)(data); - } - // Search for region that contains glink address - for (unsigned iter = 0; iter < regions_.size(); ++iter) { - unsigned int start = regions_[iter]->getMemOffset(); - unsigned int end = start + regions_[iter]->getMemSize(); - if (start <= glink_addr && glink_addr < end) { - glink = regions_[iter]; - break; + // Otherwise, first entry in .plt section holds the glink address + if (glink_addr == 0) { + unsigned char *data = (unsigned char *) plt->getPtrToRawData(); + glink_addr = *(unsigned int *) (data); } - } - if (!glink) { - return false; - } - - // Find PLT function stubs. They preceed the glink section. - stub_addr = glink_addr - (rel_plt_size_/rel_plt_entry_size_) * 16; - - const unsigned int LWZ_11_30 = 0x817e0000; - const unsigned int ADDIS_11_30 = 0x3d7e0000; - const unsigned int LWZ_11_11 = 0x816b0000; - const unsigned int MTCTR_11 = 0x7d6903a6; - const unsigned int BCTR = 0x4e800420; - - unsigned char *sec_data = (unsigned char *)glink->getPtrToRawData(); - unsigned int *insn = (unsigned int *) - (sec_data + (stub_addr - glink->getMemOffset())); - - // Keep moving pointer back if more -fPIC stubs are found. - while (sec_data < (unsigned char *)insn) { - unsigned int *back = insn - 4; - - if (( (back[0] & 0xffff0000) == LWZ_11_30 - && back[1] == MTCTR_11 - && back[2] == BCTR) - - || ( (back[0] & 0xffff0000) == ADDIS_11_30 - && (back[1] & 0xffff0000) == LWZ_11_11 - && back[2] == MTCTR_11 - && back[3] == BCTR)) - { - extraStubs = true; - stub_addr -= 16; - insn = back; - } else { - break; + // Search for region that contains glink address + for (unsigned iter = 0; iter < regions_.size(); ++iter) { + unsigned int start = regions_[iter]->getMemOffset(); + unsigned int end = start + regions_[iter]->getMemSize(); + if (start <= glink_addr && glink_addr < end) { + glink = regions_[iter]; + break; + } } - } - // Okay, this is where things get hairy. If we have a one to one - // relationship between the glink stubs and plt entries (meaning - // extraStubs == false), then we can generate our relocationEntry - // objects normally below. - - // However, if we have extra glink stubs, then we must generate - // relocations with unknown destinations for *all* stubs. Then, - // we use the loop below to store additional information about - // the data plt entry keyed by plt entry address. - - // Finally, if a symbol with any of the following forms: - // [hex_addr].got2.plt_pic32.[sym_name] - // [hex_addr].plt_pic32.[sym_name] - // - // matches the glink stub address, then stub symbols exist and we - // can rely on these tell us where the stub will eventually go. - - if (extraStubs == true) { - std::string name; - relocationEntry re; - - while (stub_addr < glink_addr) { - if (symsByOffset_.find(stub_addr) != symsByOffset_.end()) { - name = (symsByOffset_[stub_addr])[0]->getMangledName(); - name = name.substr( name.rfind("plt_pic32.") + 10 ); - } + if (!glink) { + return false; + } - if (!name.empty()) { - re = relocationEntry( stub_addr, 0, name, NULL, 0 ); + // Find PLT function stubs. They preceed the glink section. + stub_addr = glink_addr - (rel_plt_size_ / rel_plt_entry_size_) * 16; + + const unsigned int LWZ_11_30 = 0x817e0000; + const unsigned int ADDIS_11_30 = 0x3d7e0000; + const unsigned int LWZ_11_11 = 0x816b0000; + const unsigned int MTCTR_11 = 0x7d6903a6; + const unsigned int BCTR = 0x4e800420; + + unsigned char *sec_data = (unsigned char *) glink->getPtrToRawData(); + unsigned int *insn = (unsigned int *) + (sec_data + (stub_addr - glink->getMemOffset())); + + // Keep moving pointer back if more -fPIC stubs are found. + while (sec_data < (unsigned char *) insn) { + unsigned int *back = insn - 4; + + if (((back[0] & 0xffff0000) == LWZ_11_30 + && back[1] == MTCTR_11 + && back[2] == BCTR) + + || ((back[0] & 0xffff0000) == ADDIS_11_30 + && (back[1] & 0xffff0000) == LWZ_11_11 + && back[2] == MTCTR_11 + && back[3] == BCTR)) { + extraStubs = true; + stub_addr -= 16; + insn = back; } else { - re = relocationEntry( stub_addr, 0, "@plt", NULL, 0 ); + break; } - fbt_.push_back(re); - stub_addr += 16; } - // Now prepare to iterate over plt below. - next_plt_entry_addr = plt_addr_; - plt_entry_size_ = 4; - - } else { - next_plt_entry_addr = stub_addr; - } + // Okay, this is where things get hairy. If we have a one to one + // relationship between the glink stubs and plt entries (meaning + // extraStubs == false), then we can generate our relocationEntry + // objects normally below. + + // However, if we have extra glink stubs, then we must generate + // relocations with unknown destinations for *all* stubs. Then, + // we use the loop below to store additional information about + // the data plt entry keyed by plt entry address. + + // Finally, if a symbol with any of the following forms: + // [hex_addr].got2.plt_pic32.[sym_name] + // [hex_addr].plt_pic32.[sym_name] + // + // matches the glink stub address, then stub symbols exist and we + // can rely on these tell us where the stub will eventually go. + + if (extraStubs == true) { + std::string name; + relocationEntry re; + + while (stub_addr < glink_addr) { + if (symsByOffset_.find(stub_addr) != symsByOffset_.end()) { + name = (symsByOffset_[stub_addr])[0]->getMangledName(); + name = name.substr(name.rfind("plt_pic32.") + 10); + } - } else { - create_printf("ERROR: Can't handle %d PLT entry size\n", - plt_entry_size_); - return false; - } + if (!name.empty()) { + re = relocationEntry(stub_addr, 0, name, NULL, 0); + } else { + re = relocationEntry(stub_addr, 0, "@plt", NULL, 0); + } + fbt_.push_back(re); + stub_addr += 16; + } - // actually this is just fudged to make the offset value 72, which is what binutils uses - // Note that binutils makes the distinction between PLT_SLOT_SIZE (8), - // and PLT_ENTRY_SIZE (12). PLT_SLOT_SIZE seems to be what we want, even though we also - // have PLT_INITIAL_ENTRY_SIZE (72) - // see binutils/bfd/elf32-ppc.c/h if more info is needed - //next_plt_entry_addr += 72; // 1st 6 PLT entries art special + // Now prepare to iterate over plt below. + next_plt_entry_addr = plt_addr_; + plt_entry_size_ = 4; + } else { + next_plt_entry_addr = stub_addr; + } - } else if(getArch() == Dyninst::Arch_ppc64) - { - // Unlike PPC32 Linux, we don't have a deterministic way of finding - // PPC64 Linux linker stubs. So, we'll wait until the CFG is built - // inside Dyninst, and code read at that point. To find them at this - // point would require a scan of the entire .text section. - // - // If we're lucky, symbols may exist for these linker stubs. They will - // come in the following forms: - // [hex_addr].plt_call.[sym_name] - // [hex_addr].plt_branch.[sym_name] - // [hex_addr].long_branch.[sym_name] - // [hex_addr].plt_branch_r2off.[sym_name] - // [hex_addr].long_branch_r2off.[sym_name] - // - // Again unlike PPC32 above, we have no glink stub address to compare - // against, so we must search through all symbols to find these names. - // - - // First, build a map of the .rela.plt symbol name -> .rela.plt offset: - dyn_hash_map plt_rel_map; - - // I'm not a fan of code duplication, but merging this into the - // loop below would be ugly and difficult to maintain. - Elf_X_Sym _sym = symdata.get_sym(); - Elf_X_Rel _rel = reldata.get_rel(); - Elf_X_Rela _rela = reldata.get_rela(); - const char *_strs = strdata.get_string(); - - for( u_int i = 0; i < (rel_plt_size_/rel_plt_entry_size_); ++i ) { - long _offset; - long _index; + } else { + create_printf("ERROR: Can't handle %d PLT entry size\n", + plt_entry_size_); + return false; + } - switch (reldata.d_type()) { - case ELF_T_REL: - _offset = _rel.r_offset(i); - _index = _rel.R_SYM(i); - break; + // actually this is just fudged to make the offset value 72, which is what binutils uses + // Note that binutils makes the distinction between PLT_SLOT_SIZE (8), + // and PLT_ENTRY_SIZE (12). PLT_SLOT_SIZE seems to be what we want, even though we also + // have PLT_INITIAL_ENTRY_SIZE (72) + // see binutils/bfd/elf32-ppc.c/h if more info is needed + //next_plt_entry_addr += 72; // 1st 6 PLT entries art special - case ELF_T_RELA: - _offset = _rela.r_offset(i); - _index = _rela.R_SYM(i); - break; - default: - // We should never reach this case. - return false; - }; + } else if (getArch() == Dyninst::Arch_ppc64) { + // Unlike PPC32 Linux, we don't have a deterministic way of finding + // PPC64 Linux linker stubs. So, we'll wait until the CFG is built + // inside Dyninst, and code read at that point. To find them at this + // point would require a scan of the entire .text section. + // + // If we're lucky, symbols may exist for these linker stubs. They will + // come in the following forms: + // [hex_addr].plt_call.[sym_name] + // [hex_addr].plt_branch.[sym_name] + // [hex_addr].long_branch.[sym_name] + // [hex_addr].plt_branch_r2off.[sym_name] + // [hex_addr].long_branch_r2off.[sym_name] + // + // Again unlike PPC32 above, we have no glink stub address to compare + // against, so we must search through all symbols to find these names. + // - std::string _name = &_strs[ _sym.st_name(_index) ]; - // I'm interested to see if this assert will ever fail. - if(!_name.length()) - { - create_printf("Empty name for REL/RELA entry found, ignoring\n"); - continue; - } + // First, build a map of the .rela.plt symbol name -> .rela.plt offset: + dyn_hash_map plt_rel_map; - plt_rel_map[_name] = _offset; - } - // End code duplication. - - dyn_hash_map >::iterator iter; - for (iter = symbols_.begin(); iter != symbols_.end(); ++iter) { - std::string name = iter->first; - if (name.length() > 8) { - if (name.substr(8, 10) == ".plt_call.") - name = name.substr(8 + 10); - else if (name.substr(8, 12) == ".plt_branch.") - name = name.substr(8 + 12); - else if (name.substr(8, 13) == ".long_branch.") - name = name.substr(8 + 13); - else if (name.substr(8, 18) == ".plt_branch_r2off.") - name = name.substr(8 + 18); - else if (name.substr(8, 19) == ".long_branch_r2off.") - name = name.substr(8 + 19); - else - continue; + // I'm not a fan of code duplication, but merging this into the + // loop below would be ugly and difficult to maintain. + Elf_X_Sym _sym = symdata.get_sym(); + Elf_X_Rel _rel = reldata.get_rel(); + Elf_X_Rela _rela = reldata.get_rela(); + const char *_strs = strdata.get_string(); - // Remove possible trailing addend value. - std::string::size_type pos = name.rfind('+'); - if (pos != std::string::npos) name.erase(pos); + for (u_int i = 0; i < (rel_plt_size_ / rel_plt_entry_size_); ++i) { + long _offset; + long _index; - // Remove possible version number. - pos = name.find('@'); - if (pos != std::string::npos) name.erase(pos); + switch (reldata.d_type()) { + case ELF_T_REL: + _offset = _rel.r_offset(i); + _index = _rel.R_SYM(i); + break; - // Find the dynamic symbol this linker stub branches to. - Symbol *targ_sym = NULL; - if (symbols_.find(name) != symbols_.end()) - for (unsigned i = 0; i < symbols_[name].size(); ++i) - if ( (symbols_[name])[i]->isInDynSymtab()) - targ_sym = (symbols_[name])[i]; + case ELF_T_RELA: + _offset = _rela.r_offset(i); + _index = _rela.R_SYM(i); + break; - // If a corresponding target symbol cannot be found for a - // named linker stub, then ignore it. We'll find it during - // parsing. - if (!targ_sym) continue; + default: + // We should never reach this case. + return false; + }; - if (iter->second.size() != 1) - continue; - dyn_hash_map::iterator pltrel_iter = plt_rel_map.find(name); - if (pltrel_iter == plt_rel_map.end()) + std::string _name = &_strs[_sym.st_name(_index)]; + // I'm interested to see if this assert will ever fail. + if (!_name.length()) { + create_printf("Empty name for REL/RELA entry found, ignoring\n"); continue; + } - Symbol *stub_sym = iter->second[0]; - relocationEntry re(stub_sym->getOffset(), - pltrel_iter->second, - name, - targ_sym); - fbt_.push_back(re); + plt_rel_map[_name] = _offset; } - } + // End code duplication. + + dyn_hash_map >::iterator iter; + for (iter = symbols_.begin(); iter != symbols_.end(); ++iter) { + std::string name = iter->first; + if (name.length() > 8) { + if (name.substr(8, 10) == ".plt_call.") + name = name.substr(8 + 10); + else if (name.substr(8, 12) == ".plt_branch.") + name = name.substr(8 + 12); + else if (name.substr(8, 13) == ".long_branch.") + name = name.substr(8 + 13); + else if (name.substr(8, 18) == ".plt_branch_r2off.") + name = name.substr(8 + 18); + else if (name.substr(8, 19) == ".long_branch_r2off.") + name = name.substr(8 + 19); + else + continue; - // 1st plt entry is special. - next_plt_entry_addr += plt_entry_size_; + // Remove possible trailing addend value. + std::string::size_type pos = name.rfind('+'); + if (pos != std::string::npos) name.erase(pos); - } else if (getArch() == Dyninst::Arch_aarch64) - { - next_plt_entry_addr += 2 * plt_entry_size_; - } else { - next_plt_entry_addr += 4*(plt_entry_size_); //1st 4 entries are special - } + // Remove possible version number. + pos = name.find('@'); + if (pos != std::string::npos) name.erase(pos); + // Find the dynamic symbol this linker stub branches to. + Symbol *targ_sym = NULL; + if (symbols_.find(name) != symbols_.end()) + for (unsigned i = 0; i < symbols_[name].size(); ++i) + if ((symbols_[name])[i]->isInDynSymtab()) + targ_sym = (symbols_[name])[i]; - Elf_X_Sym sym = symdata.get_sym(); - Elf_X_Rel rel = reldata.get_rel(); - Elf_X_Rela rela = reldata.get_rela(); - const char *strs = strdata.get_string(); + // If a corresponding target symbol cannot be found for a + // named linker stub, then ignore it. We'll find it during + // parsing. + if (!targ_sym) continue; - if (sym.isValid() && (rel.isValid() || rela.isValid()) && strs) { + if (iter->second.size() != 1) + continue; + dyn_hash_map::iterator pltrel_iter = plt_rel_map.find(name); + if (pltrel_iter == plt_rel_map.end()) + continue; - // Sometimes, PPC32 Linux may use this loop to update fbt entries. - // Should stay -1 for all other platforms. See notes above. - int fbt_iter = -1; - if (fbt_.size() > 0 && !fbt_[0].rel_addr() && fbt_[0].name() != "@plt") - fbt_iter = 0; + Symbol *stub_sym = iter->second[0]; + relocationEntry re(stub_sym->getOffset(), + pltrel_iter->second, + name, + targ_sym); + fbt_.push_back(re); + } + } - for( u_int i = 0; i < (rel_plt_size_/rel_plt_entry_size_); ++i ) { - long offset; - long addend; - long index; - unsigned long type; - Region::RegionType rtype; + // 1st plt entry is special. + next_plt_entry_addr += plt_entry_size_; - switch (reldata.d_type()) { - case ELF_T_REL: - offset = rel.r_offset(i); - addend = 0; - index = rel.R_SYM(i); - type = rel.R_TYPE(i); - rtype = Region::RT_REL; - break; + } else if (getArch() == Dyninst::Arch_aarch64) { + next_plt_entry_addr += 2 * plt_entry_size_; + } else { + next_plt_entry_addr += 4 * (plt_entry_size_); //1st 4 entries are special + } - case ELF_T_RELA: - offset = rela.r_offset(i); - addend = rela.r_addend(i); - index = rela.R_SYM(i); - type = rela.R_TYPE(i); - rtype = Region::RT_RELA; - break; - default: - // We should never reach this case. - return false; - }; + Elf_X_Sym sym = symdata.get_sym(); + Elf_X_Rel rel = reldata.get_rel(); + Elf_X_Rela rela = reldata.get_rela(); + const char *strs = strdata.get_string(); + + if (sym.isValid() && (rel.isValid() || rela.isValid()) && strs) { + + // Sometimes, PPC32 Linux may use this loop to update fbt entries. + // Should stay -1 for all other platforms. See notes above. + int fbt_iter = -1; + if (fbt_.size() > 0 && !fbt_[0].rel_addr() && fbt_[0].name() != "@plt") + fbt_iter = 0; + + for (u_int i = 0; i < (rel_plt_size_ / rel_plt_entry_size_); ++i) { + long offset; + long addend; + long index; + unsigned long type; + Region::RegionType rtype; + + switch (reldata.d_type()) { + case ELF_T_REL: + offset = rel.r_offset(i); + addend = 0; + index = rel.R_SYM(i); + type = rel.R_TYPE(i); + rtype = Region::RT_REL; + break; - std::string targ_name = &strs[ sym.st_name(index) ]; - vector dynsym_list; - if (symbols_.find(targ_name) != symbols_.end()) - { - vector &syms = symbols_[&strs[ sym.st_name(index)]]; - for (vector::iterator i = syms.begin(); i != syms.end(); i++) { - if (!(*i)->isInDynSymtab()) - continue; - dynsym_list.push_back(*i); + case ELF_T_RELA: + offset = rela.r_offset(i); + addend = rela.r_addend(i); + index = rela.R_SYM(i); + type = rela.R_TYPE(i); + rtype = Region::RT_RELA; + break; + + default: + // We should never reach this case. + return false; + }; + + std::string targ_name = &strs[sym.st_name(index)]; + vector dynsym_list; + if (symbols_.find(targ_name) != symbols_.end()) { + vector &syms = symbols_[&strs[sym.st_name(index)]]; + for (vector::iterator i = syms.begin(); i != syms.end(); i++) { + if (!(*i)->isInDynSymtab()) + continue; + dynsym_list.push_back(*i); + } + } else { + dynsym_list.clear(); } - } - else { - dynsym_list.clear(); - } #if defined(os_vxworks) // VxWorks Kernel Images don't use PLT's, but we'll use the fbt to @@ -1455,26 +1415,26 @@ bool Object::get_relocation_entries( Elf_X_Shdr *&rel_plt_scnp, #endif if (fbt_iter == -1) { // Create new relocation entry. - relocationEntry re( next_plt_entry_addr, offset, targ_name, - NULL, type ); - if (type == R_X86_64_IRELATIVE) { - vector funcs; - dyn_hash_map >::iterator iter; - // find the resolver function and use that as the - // caller function symbol. The resolver has not run - // so we don't know the ultimate destination. - // Since the funcsByOffset map hasn't been setup yet - // we cannot call associated_symtab->findFuncByEntryOffset - for (iter = symbols_.begin(); iter != symbols_.end(); ++iter) { - std::string name = iter->first; - Symbol *sym = iter->second[0]; - if (sym->getOffset() == (Offset)addend) { - // Use dynsym_list.push_back(sym) instead? - re.addDynSym(sym); - break; - } - } - } + relocationEntry re(next_plt_entry_addr, offset, targ_name, + NULL, type); + if (type == R_X86_64_IRELATIVE) { + vector funcs; + dyn_hash_map >::iterator iter; + // find the resolver function and use that as the + // caller function symbol. The resolver has not run + // so we don't know the ultimate destination. + // Since the funcsByOffset map hasn't been setup yet + // we cannot call associated_symtab->findFuncByEntryOffset + for (iter = symbols_.begin(); iter != symbols_.end(); ++iter) { + std::string name = iter->first; + Symbol *sym = iter->second[0]; + if (sym->getOffset() == (Offset) addend) { + // Use dynsym_list.push_back(sym) instead? + re.addDynSym(sym); + break; + } + } + } re.setAddend(addend); re.setRegionType(rtype); if (dynsym_list.size() > 0) @@ -1482,7 +1442,7 @@ bool Object::get_relocation_entries( Elf_X_Shdr *&rel_plt_scnp, fbt_.push_back(re); } else { // Update existing relocation entry. - while ((unsigned)fbt_iter < fbt_.size() && + while ((unsigned) fbt_iter < fbt_.size() && fbt_[fbt_iter].name() == targ_name) { fbt_[fbt_iter].setRelAddr(offset); @@ -1508,8 +1468,7 @@ bool Object::get_relocation_entries( Elf_X_Shdr *&rel_plt_scnp, return false; } -void Object::load_object(bool alloc_syms) -{ +void Object::load_object(bool alloc_syms) { Elf_X_Shdr *bssscnp = 0; Elf_X_Shdr *symscnp = 0; Elf_X_Shdr *strscnp = 0; @@ -1552,9 +1511,8 @@ void Object::load_object(bool alloc_syms) if (!loaded_elf(txtaddr, dataddr, bssscnp, symscnp, strscnp, stabscnp, stabstrscnp, stabs_indxcnp, stabstrs_indxcnp, rel_plt_scnp, plt_scnp, got_scnp, dynsym_scnp, dynstr_scnp, - dynamic_scnp, eh_frame_scnp,gcc_except, interp_scnp, - opd_scnp, true)) - { + dynamic_scnp, eh_frame_scnp, gcc_except, interp_scnp, + opd_scnp, true)) { goto cleanup; } @@ -1563,10 +1521,8 @@ void Object::load_object(bool alloc_syms) // find code and data segments.... find_code_and_data(*elfHdr, txtaddr, dataddr); - if (elfHdr->e_type() != ET_REL) - { - if (!code_ptr_ || !code_len_) - { + if (elfHdr->e_type() != ET_REL) { + if (!code_ptr_ || !code_len_) { //bpfatal( "no text segment\n"); goto cleanup; } @@ -1576,11 +1532,10 @@ void Object::load_object(bool alloc_syms) #if (defined(os_linux) || defined(os_freebsd)) // if(getArch() == Dyninst::Arch_x86 || getArch() == Dyninst::Arch_x86_64) // { - if (eh_frame_scnp != 0 && gcc_except != 0) - { - find_catch_blocks(eh_frame_scnp, gcc_except, - txtaddr, dataddr, catch_addrs_); - } + if (eh_frame_scnp != 0 && gcc_except != 0) { + find_catch_blocks(eh_frame_scnp, gcc_except, + txtaddr, dataddr, catch_addrs_); + } // } #endif if (interp_scnp) { @@ -1600,8 +1555,7 @@ void Object::load_object(bool alloc_syms) struct timeval starttime; gettimeofday(&starttime, NULL); #endif - if (alloc_syms) - { + if (alloc_syms) { // find symbol and string data #if defined(os_vxworks) // Avoid assigning symbols to DEFAULT_MODULE on VxWorks @@ -1609,11 +1563,10 @@ void Object::load_object(bool alloc_syms) #else string module = "DEFAULT_MODULE"; #endif - string name = "DEFAULT_NAME"; + string name = "DEFAULT_NAME"; Elf_X_Data symdata, strdata; - if (symscnp && strscnp) - { + if (symscnp && strscnp) { symdata = symscnp->get_data(); strdata = strscnp->get_data(); parse_symbols(symdata, strdata, bssscnp, symscnp, false, module); @@ -1631,8 +1584,7 @@ void Object::load_object(bool alloc_syms) // DWARF format (.debug_info section) fix_global_symbol_modules_static_dwarf(); - if (dynamic_addr_ && dynsym_scnp && dynstr_scnp) - { + if (dynamic_addr_ && dynsym_scnp && dynstr_scnp) { symdata = dynsym_scnp->get_data(); strdata = dynstr_scnp->get_data(); parse_dynamicSymbols(dynamic_scnp, symdata, strdata, false, module); @@ -1658,8 +1610,7 @@ void Object::load_object(bool alloc_syms) cout << "parsing/fixing/overriding elf took "<pathname(); - string name = "DEFAULT_NAME"; + string name = "DEFAULT_NAME"; Elf_X_Data symdata, strdata; - if (symscnp && strscnp) - { + if (symscnp && strscnp) { symdata = symscnp->get_data(); strdata = strscnp->get_data(); if (!symdata.isValid() || !strdata.isValid()) { @@ -1810,8 +1757,7 @@ void Object::load_shared_object(bool alloc_syms) // DWARF format (.debug_info section) fix_global_symbol_modules_static_dwarf(); - if (dynamic_addr_ && dynsym_scnp && dynstr_scnp) - { + if (dynamic_addr_ && dynsym_scnp && dynstr_scnp) { symdata = dynsym_scnp->get_data(); strdata = dynstr_scnp->get_data(); parse_dynamicSymbols(dynamic_scnp, symdata, strdata, false, module); @@ -1827,7 +1773,7 @@ void Object::load_shared_object(bool alloc_syms) cout << "*INSERT SYMBOLS* elf took "<e_type(); if (e_type == ET_DYN) { obj_type_ = obj_SharedLib; - } - else if (e_type == ET_EXEC) { + } else if (e_type == ET_EXEC) { obj_type_ = obj_Executable; - }else if( e_type == ET_REL ) { + } else if (e_type == ET_REL) { obj_type_ = obj_RelocatableFile; } @@ -1878,42 +1823,55 @@ void Object::load_shared_object(bool alloc_syms) } } -static Symbol::SymbolType pdelf_type(int elf_type) -{ +static Symbol::SymbolType pdelf_type(int elf_type) { switch (elf_type) { - case STT_FILE: return Symbol::ST_MODULE; - case STT_SECTION:return Symbol::ST_SECTION; - case STT_OBJECT: return Symbol::ST_OBJECT; - case STT_TLS: return Symbol::ST_TLS; - case STT_FUNC: return Symbol::ST_FUNCTION; - case STT_NOTYPE: return Symbol::ST_NOTYPE; + case STT_FILE: + return Symbol::ST_MODULE; + case STT_SECTION: + return Symbol::ST_SECTION; + case STT_OBJECT: + return Symbol::ST_OBJECT; + case STT_TLS: + return Symbol::ST_TLS; + case STT_FUNC: + return Symbol::ST_FUNCTION; + case STT_NOTYPE: + return Symbol::ST_NOTYPE; #if defined(STT_GNU_IFUNC) - case STT_GNU_IFUNC: return Symbol::ST_INDIRECT; + case STT_GNU_IFUNC: + return Symbol::ST_INDIRECT; #endif - default: return Symbol::ST_UNKNOWN; + default: + return Symbol::ST_UNKNOWN; } } -static Symbol::SymbolLinkage pdelf_linkage(int elf_binding) -{ +static Symbol::SymbolLinkage pdelf_linkage(int elf_binding) { switch (elf_binding) { - case STB_LOCAL: return Symbol::SL_LOCAL; - case STB_WEAK: return Symbol::SL_WEAK; - case STB_GLOBAL: return Symbol::SL_GLOBAL; -#if defined(STB_GNU_UNIQUE) - case STB_GNU_UNIQUE: return Symbol::SL_UNIQUE; + case STB_LOCAL: + return Symbol::SL_LOCAL; + case STB_WEAK: + return Symbol::SL_WEAK; + case STB_GLOBAL: + return Symbol::SL_GLOBAL; +#if defined(STB_GNU_UNIQUE) + case STB_GNU_UNIQUE: + return Symbol::SL_UNIQUE; #endif } return Symbol::SL_UNKNOWN; } -static Symbol::SymbolVisibility pdelf_visibility(int elf_visibility) -{ +static Symbol::SymbolVisibility pdelf_visibility(int elf_visibility) { switch (elf_visibility) { - case STV_DEFAULT: return Symbol::SV_DEFAULT; - case STV_INTERNAL: return Symbol::SV_INTERNAL; - case STV_HIDDEN: return Symbol::SV_HIDDEN; - case STV_PROTECTED: return Symbol::SV_PROTECTED; + case STV_DEFAULT: + return Symbol::SV_DEFAULT; + case STV_INTERNAL: + return Symbol::SV_INTERNAL; + case STV_HIDDEN: + return Symbol::SV_HIDDEN; + case STV_PROTECTED: + return Symbol::SV_PROTECTED; } return Symbol::SV_UNKNOWN; } @@ -1927,24 +1885,18 @@ static Symbol::SymbolVisibility pdelf_visibility(int elf_visibility) //#include "dyninstAPI/src/rpcMgr.h" //linear search -bool lookUpSymbol( std::vector< Symbol *>& allsymbols, Offset& addr ) -{ - for( unsigned i = 0; i < allsymbols.size(); i++ ) - { - if( allsymbols[ i ]->getOffset() == addr ) - { +bool lookUpSymbol(std::vector &allsymbols, Offset &addr) { + for (unsigned i = 0; i < allsymbols.size(); i++) { + if (allsymbols[i]->getOffset() == addr) { return true; } } return false; } -bool lookUpAddress( std::vector< Offset >& jumpTargets, Offset& addr ) -{ - for( unsigned i = 0; i < jumpTargets.size(); i++ ) - { - if( jumpTargets[ i ] == addr ) - { +bool lookUpAddress(std::vector &jumpTargets, Offset &addr) { + for (unsigned i = 0; i < jumpTargets.size(); i++) { + if (jumpTargets[i] == addr) { return true; } } @@ -1952,15 +1904,12 @@ bool lookUpAddress( std::vector< Offset >& jumpTargets, Offset& addr ) } //utitility function to print std::vector of symbols -void printSyms( std::vector< Symbol *>& allsymbols ) -{ - for( unsigned i = 0; i < allsymbols.size(); i++ ) - { - if( allsymbols[ i ]->getType() != Symbol::ST_FUNCTION ) - { +void printSyms(std::vector &allsymbols) { + for (unsigned i = 0; i < allsymbols.size(); i++) { + if (allsymbols[i]->getType() != Symbol::ST_FUNCTION) { continue; } - cout << allsymbols[ i ] << endl; + cout << allsymbols[i] << endl; } } @@ -1984,13 +1933,13 @@ void printSyms( std::vector< Symbol *>& allsymbols ) void Object::parse_opd(Elf_X_Shdr *opd_hdr) { // If the OPD is filled in, parse it and fill in our TOC table - if(!opd_hdr) return; + if (!opd_hdr) return; Elf_X_Data data = opd_hdr->get_data(); - if(!(data.isValid())) return; + if (!(data.isValid())) return; // Let's read this puppy - unsigned long *buf = (unsigned long *)data.d_buf(); + unsigned long *buf = (unsigned long *) data.d_buf(); // In some cases, the OPD is a set of 3-tuples: . // In others, it's a set of 2-tuples. Since we can't tell the difference, we // instead look for function offsets. @@ -2007,7 +1956,7 @@ void Object::parse_opd(Elf_X_Shdr *opd_hdr) { unsigned i = 0; while (i < (data.d_size() / sizeof(unsigned long))) { Offset func = buf[i]; - Offset toc = buf[i+1]; + Offset toc = buf[i + 1]; if (func == 0 && i != 0) break; @@ -2018,34 +1967,35 @@ void Object::parse_opd(Elf_X_Shdr *opd_hdr) { if (toc != baseTOC) { TOC_table_[func] = toc; - create_printf("Set TOC for %p to %p\n", func, toc); + create_printf("Set TOC for %p to %p\n", func, toc); } i += 2; } } -void Object::handle_opd_relocations(){ +void Object::handle_opd_relocations() { unsigned int i = 0, opdregion = 0; while (i < regions_.size()) { - if(regions_[i]->getRegionName().compare(".opd") == 0){ + if (regions_[i]->getRegionName().compare(".opd") == 0) { opdregion = i; break; } i++; } + if (i == regions_.size()) return; vector region_rels = (regions_[opdregion])->getRelocations(); vector::iterator rel_it; vector::iterator sym_it; - for(sym_it = opdsymbols_.begin(); sym_it != opdsymbols_.end(); ++sym_it) { - for(rel_it = region_rels.begin(); rel_it != region_rels.end(); ++rel_it) { - if((*sym_it)->getPtrOffset() == (*rel_it).rel_addr()) { + for (sym_it = opdsymbols_.begin(); sym_it != opdsymbols_.end(); ++sym_it) { + for (rel_it = region_rels.begin(); rel_it != region_rels.end(); ++rel_it) { + if ((*sym_it)->getPtrOffset() == (*rel_it).rel_addr()) { i = 0; while (i < regions_.size()) { - if(regions_[i]->getRegionName().compare((*rel_it).getDynSym()->getMangledName()) == 0){ + if (regions_[i]->getRegionName().compare((*rel_it).getDynSym()->getMangledName()) == 0) { Region *targetRegion = regions_[i]; - Offset regionOffset = targetRegion->getDiskOffset()+(*rel_it).addend(); + Offset regionOffset = targetRegion->getDiskOffset() + (*rel_it).addend(); (*sym_it)->setRegion(targetRegion); (*sym_it)->setOffset(regionOffset); // Store code address for the function. break; @@ -2058,14 +2008,13 @@ void Object::handle_opd_relocations(){ opdsymbols_.clear(); } -Symbol *Object::handle_opd_symbol(Region *opd, Symbol *sym) -{ +Symbol *Object::handle_opd_symbol(Region *opd, Symbol *sym) { if (!sym) return NULL; Offset soffset = sym->getOffset(); - if(!opd->isOffsetInRegion(soffset)) return NULL; // Symbol must be in .opd section. + if (!opd->isOffsetInRegion(soffset)) return NULL; // Symbol must be in .opd section. - Offset* opd_entry = (Offset*)opd->getPtrToRawData(); + Offset *opd_entry = (Offset *) opd->getPtrToRawData(); opd_entry += (soffset - opd->getDiskOffset()) / sizeof(Offset); // table of offsets; Symbol *retval = new Symbol(*sym); // Copy the .opd symbol. retval->setOffset(opd_entry[0]); // Store code address for the function. @@ -2093,10 +2042,9 @@ Symbol *Object::handle_opd_symbol(Region *opd, Symbol *sym) // parse_symbols(): populate "allsymbols" bool Object::parse_symbols(Elf_X_Data &symdata, Elf_X_Data &strdata, - Elf_X_Shdr* bssscnp, - Elf_X_Shdr* symscnp, - bool /*shared*/, string smodule) -{ + Elf_X_Shdr *bssscnp, + Elf_X_Shdr *symscnp, + bool /*shared*/, string smodule) { #if defined(TIMED_PARSE) struct timeval starttime; gettimeofday(&starttime, NULL); @@ -2108,7 +2056,7 @@ bool Object::parse_symbols(Elf_X_Data &symdata, Elf_X_Data &strdata, Elf_X_Sym syms = symdata.get_sym(); const char *strs = strdata.get_string(); - if(syms.isValid()){ + if (syms.isValid()) { for (unsigned i = 0; i < syms.count(); i++) { //If it is not a dynamic executable then we need undefined symbols //in symtab section so that we can resolve symbol references. So @@ -2122,7 +2070,7 @@ bool Object::parse_symbols(Elf_X_Data &symdata, Elf_X_Data &strdata, int evisibility = syms.ST_VISIBILITY(i); // resolve symbol elements - string sname = &strs[ syms.st_name(i) ]; + string sname = &strs[syms.st_name(i)]; Symbol::SymbolType stype = pdelf_type(etype); Symbol::SymbolLinkage slinkage = pdelf_linkage(ebinding); Symbol::SymbolVisibility svisibility = pdelf_visibility(evisibility); @@ -2140,8 +2088,7 @@ bool Object::parse_symbols(Elf_X_Data &symdata, Elf_X_Data &strdata, continue; } } - } - else { + } else { soffset = syms.st_value(i); } @@ -2152,30 +2099,29 @@ bool Object::parse_symbols(Elf_X_Data &symdata, Elf_X_Data &strdata, */ if (bssscnp) { Offset bssStart = Offset(bssscnp->sh_addr()); - Offset bssEnd = Offset (bssStart + bssscnp->sh_size()) ; + Offset bssEnd = Offset(bssStart + bssscnp->sh_size()); - if(( bssStart <= soffset) && ( soffset < bssEnd ) && (ssize > 0) && - (stype == Symbol::ST_NOTYPE)) - { + if ((bssStart <= soffset) && (soffset < bssEnd) && (ssize > 0) && + (stype == Symbol::ST_NOTYPE)) { stype = Symbol::ST_OBJECT; } } // discard "dummy" symbol at beginning of file - if (i==0 && sname == "" && soffset == (Offset)0) + if (i == 0 && sname == "" && soffset == (Offset) 0) continue; Region *sec; - if(secNumber >= 1 && secNumber < regions_.size()) { + if (secNumber >= 1 && secNumber < regions_.size()) { sec = regions_[secNumber]; } else { sec = NULL; } - int ind = int (i); + int ind = int(i); int strindex = syms.st_name(i); - if(stype == Symbol::ST_SECTION && sec != NULL) { + if (stype == Symbol::ST_SECTION && sec != NULL) { sname = sec->getRegionName(); soffset = sec->getDiskOffset(); } @@ -2200,7 +2146,7 @@ bool Object::parse_symbols(Elf_X_Data &symdata, Elf_X_Data &strdata, if (stype == Symbol::ST_UNKNOWN) newsym->setInternalType(etype); - if (sec && sec->getRegionName() == OPD_NAME && stype == Symbol::ST_FUNCTION ) { + if (sec && sec->getRegionName() == OPD_NAME && stype == Symbol::ST_FUNCTION) { newsym = handle_opd_symbol(sec, newsym); opdsymbols_.push_back(newsym); @@ -2231,13 +2177,11 @@ bool Object::parse_symbols(Elf_X_Data &symdata, Elf_X_Data &strdata, // Lazy parsing of dynamic symbol & string tables // Parsing the dynamic symbols lazily would certainly // not increase the overhead of the entire parse -void Object::parse_dynamicSymbols (Elf_X_Shdr *& -dyn_scnp - , Elf_X_Data &symdata, - Elf_X_Data &strdata, - bool /*shared*/, - std::string smodule) -{ +void Object::parse_dynamicSymbols(Elf_X_Shdr *& +dyn_scnp, Elf_X_Data &symdata, + Elf_X_Data &strdata, + bool /*shared*/, + std::string smodule) { #if defined(TIMED_PARSE) struct timeval starttime; gettimeofday(&starttime, NULL); @@ -2253,7 +2197,7 @@ dyn_scnp Elf_X_Verdef *symVersionDefs = NULL; Elf_X_Verneed *symVersionNeeds = NULL; for (unsigned i = 0; i < dyns.count(); ++i) { - switch(dyns.d_tag(i)) { + switch (dyns.d_tag(i)) { case DT_NEEDED: if(strs) deps_.push_back(&strs[dyns.d_ptr(i)]); break; @@ -2278,14 +2222,14 @@ dyn_scnp break; } } - if(versymSec) + if (versymSec) symVersions = versymSec->get_data().get_versyms(); - if(verdefSec) + if (verdefSec) symVersionDefs = verdefSec->get_data().get_verDefSym(); - if(verneedSec) + if (verneedSec) symVersionNeeds = verneedSec->get_data().get_verNeedSym(); - for(unsigned i = 0; i < verdefnum ;i++) { + for (unsigned i = 0; i < verdefnum; i++) { Elf_X_Verdaux *aux = symVersionDefs->get_aux(); for(unsigned j=0; j< symVersionDefs->vd_cnt(); j++){ if(strs) versionMapping[symVersionDefs->vd_ndx()].push_back(&strs[aux->vda_name()]); @@ -2298,7 +2242,7 @@ dyn_scnp symVersionDefs = symVersionDefsnext; } - for(unsigned i = 0; i < verneednum; i++){ + for (unsigned i = 0; i < verneednum; i++) { Elf_X_Vernaux *aux = symVersionNeeds->get_aux(); for(unsigned j=0; j< symVersionNeeds->vn_cnt(); j++){ if(strs) versionMapping[aux->vna_other()].push_back(&strs[aux->vna_name()]); @@ -2319,7 +2263,7 @@ dyn_scnp int evisibility = syms.ST_VISIBILITY(i); // resolve symbol elements - string sname = &strs[ syms.st_name(i) ]; + string sname = &strs[syms.st_name(i)]; Symbol::SymbolType stype = pdelf_type(etype); Symbol::SymbolLinkage slinkage = pdelf_linkage(ebinding); Symbol::SymbolVisibility svisibility = pdelf_visibility(evisibility); @@ -2328,17 +2272,17 @@ dyn_scnp unsigned secNumber = syms.st_shndx(i); // discard "dummy" symbol at beginning of file - if (i==0 && sname == "" && soffset == 0) + if (i == 0 && sname == "" && soffset == 0) continue; Region *sec; - if(secNumber >= 1 && secNumber < regions_.size()) { + if (secNumber >= 1 && secNumber < regions_.size()) { sec = regions_[secNumber]; } else { sec = NULL; } - int ind = int (i); + int ind = int(i); int strindex = syms.st_name(i); if (stype == Symbol::ST_MODULE) { @@ -2362,16 +2306,16 @@ dyn_scnp if (stype == Symbol::ST_UNKNOWN) newsym->setInternalType(etype); - if(versymSec) { + if (versymSec) { unsigned short raw = symVersions.get(i); bool hidden = raw >> 15; int index = raw & 0x7fff; - if(versionFileNameMapping.find(index) != versionFileNameMapping.end()) { + if (versionFileNameMapping.find(index) != versionFileNameMapping.end()) { //printf("version filename for %s: %s\n", sname.c_str(), //versionFileNameMapping[index].c_str()); newsym->setVersionFileName(versionFileNameMapping[index]); } - if(versionMapping.find(index) != versionMapping.end()) { + if (versionMapping.find(index) != versionMapping.end()) { //printf("versions for %s: ", sname.c_str()); //for (unsigned k=0; k < versionMapping[index].size(); k++) //printf(" %s", versionMapping[index][k].c_str()); @@ -2384,7 +2328,7 @@ dyn_scnp } // register symbol in dictionary - if (sec && sec->getRegionName() == OPD_NAME && stype == Symbol::ST_FUNCTION ) { + if (sec && sec->getRegionName() == OPD_NAME && stype == Symbol::ST_FUNCTION) { newsym = handle_opd_symbol(sec, newsym); opdsymbols_.push_back(newsym); @@ -2412,21 +2356,20 @@ dyn_scnp #if defined(cap_dwarf) -string Object::find_symbol(string name) -{ +string Object::find_symbol(string name) { string name2; // pass #1: unmodified name2 = name; - if (symbols_.find(name2)!=symbols_.end()) return name2; + if (symbols_.find(name2) != symbols_.end()) return name2; // pass #2: leading underscore (C) name2 = "_" + name; - if (symbols_.find(name2)!=symbols_.end()) return name2; + if (symbols_.find(name2) != symbols_.end()) return name2; // pass #3: trailing underscore (Fortran) name2 = name + "_"; - if (symbols_.find(name2)!=symbols_.end()) + if (symbols_.find(name2) != symbols_.end()) return name2; return ""; @@ -2447,10 +2390,9 @@ string Object::find_symbol(string name) #if defined(cap_dwarf) -void pd_dwarf_handler() -{ +void pd_dwarf_handler() { const char *dwarf_msg = dwarf_errmsg(0); - + if (dwarf_msg == NULL) return; @@ -2461,43 +2403,40 @@ void pd_dwarf_handler() } Dwarf_Sword declFileNo = 0; -char ** declFileNoToName = NULL; +char **declFileNoToName = NULL; -bool Object::dwarf_parse_aranges(Dwarf * dbg, std::set& dies_seen) -{ - Dwarf_Aranges* ranges; +bool Object::dwarf_parse_aranges(Dwarf *dbg, std::set &dies_seen) { + Dwarf_Aranges *ranges; size_t num_ranges; int status = dwarf_getaranges(dbg, &ranges, &num_ranges); - if(status != 0) return false; + if (status != 0) return false; // cout << "Processing " << num_ranges << "DWARF ranges" << endl; - for(size_t i = 0; i < num_ranges; i++) - { - Dwarf_Arange * range = dwarf_onearange(ranges, i); - if(!range) continue; + for (size_t i = 0; i < num_ranges; i++) { + Dwarf_Arange *range = dwarf_onearange(ranges, i); + if (!range) continue; Dwarf_Addr start; Dwarf_Word len; Dwarf_Off some_offset; status = dwarf_getarangeinfo(range, &start, &len, &some_offset); assert(status == 0); - if(len == 0) continue; + if (len == 0) continue; Dwarf_Die cu_die, *cu_die_off_p; - cu_die_off_p = dwarf_addrdie(dbg, start, &cu_die); + cu_die_off_p = dwarf_addrdie(dbg, start, &cu_die); assert(cu_die_off_p != NULL); auto off_die = dwarf_dieoffset(&cu_die); - if(dies_seen.find(off_die) != dies_seen.end()) continue; + if (dies_seen.find(off_die) != dies_seen.end()) continue; std::string modname; - if(!DwarfWalker::findDieName(dbg, cu_die, modname)) - { + if (!DwarfWalker::findDieName(dbg, cu_die, modname)) { modname = associated_symtab->file(); // default module } Offset actual_start, actual_end; convertDebugOffset(start, actual_start); convertDebugOffset(start + len, actual_end); - Module* m = associated_symtab->getOrCreateModule(modname, actual_start); + Module *m = associated_symtab->getOrCreateModule(modname, actual_start); m->addRange(actual_start, actual_end); m->addDebugInfo(cu_die); DwarfWalker::buildSrcFiles(dbg, cu_die, m->getStrings()); @@ -2506,8 +2445,7 @@ bool Object::dwarf_parse_aranges(Dwarf * dbg, std::set& dies_seen) return true; } -bool Object::fix_global_symbol_modules_static_dwarf() -{ +bool Object::fix_global_symbol_modules_static_dwarf() { /* Initialize libdwarf. */ Dwarf **dbg_ptr = dwarf->type_dbg(); if (!dbg_ptr) @@ -2518,60 +2456,52 @@ bool Object::fix_global_symbol_modules_static_dwarf() /* Iterate over the compilation-unit headers. */ size_t cu_header_size; - for(Dwarf_Off cu_off = 0, next_cu_off; - dwarf_nextcu(dbg, cu_off, &next_cu_off, &cu_header_size, - NULL, NULL, NULL) == 0; - cu_off = next_cu_off) - { + for (Dwarf_Off cu_off = 0, next_cu_off; + dwarf_nextcu(dbg, cu_off, &next_cu_off, &cu_header_size, + NULL, NULL, NULL) == 0; + cu_off = next_cu_off) { Dwarf_Off cu_die_off = cu_off + cu_header_size; - Dwarf_Die cu_die, *cu_die_p; + Dwarf_Die cu_die, *cu_die_p; cu_die_p = dwarf_offdie(dbg, cu_die_off, &cu_die); - if(cu_die_p == NULL) continue; + if (cu_die_p == NULL) continue; //if(dies_seen.find(cu_die_off) != dies_seen.end()) continue; - + std::string modname; - if(!DwarfWalker::findDieName(dbg, cu_die, modname)) - { + if (!DwarfWalker::findDieName(dbg, cu_die, modname)) { modname = associated_symtab->file(); // default module } //cerr << "Processing CU DIE for " << modname << " offset: " << next_cu_off << endl; Address tempModLow; Address modLow = 0; - if (DwarfWalker::findConstant(DW_AT_low_pc, tempModLow, cu_die, dbg)) { + if (DwarfWalker::findConstant(DW_AT_low_pc, tempModLow, &cu_die, dbg)) { convertDebugOffset(tempModLow, modLow); } std::vector mod_ranges = DwarfWalker::getDieRanges(dbg, cu_die, modLow); - Module* m = associated_symtab->getOrCreateModule(modname, modLow); - for(auto r = mod_ranges.begin(); - r != mod_ranges.end(); ++r) - { + Module *m = associated_symtab->getOrCreateModule(modname, modLow); + for (auto r = mod_ranges.begin(); + r != mod_ranges.end(); ++r) { m->addRange(r->first, r->second); } - if(!m->hasRanges()) - { + if (!m->hasRanges()) { // cout << "No ranges for module " << modname << ", need to extract from statements\n"; - Dwarf_Lines* lines; + Dwarf_Lines *lines; size_t num_lines; - if(dwarf_getsrclines(&cu_die, &lines, &num_lines) == 0) - { + if (dwarf_getsrclines(&cu_die, &lines, &num_lines) == 0) { Dwarf_Addr low; - for(size_t i = 0; i < num_lines; ++i) - { + for (size_t i = 0; i < num_lines; ++i) { Dwarf_Line *line = dwarf_onesrcline(lines, i); - if((dwarf_lineaddr(line, &low) == 0) && low) - { + if ((dwarf_lineaddr(line, &low) == 0) && low) { Dwarf_Addr high = low; int result = 0; - for(; (i < num_lines) && - (result == 0); ++i) - { + for (; (i < num_lines) && + (result == 0); ++i) { line = dwarf_onesrcline(lines, i); - if(!line) continue; + if (!line) continue; bool is_end = false; result = dwarf_lineendsequence(line, &is_end); - if(result == 0 && is_end) { + if (result == 0 && is_end) { result = dwarf_lineaddr(line, &high); break; } @@ -2607,8 +2537,7 @@ bool Object::fix_global_symbol_modules_static_dwarf() * ********************************************************/ -bool Object::fix_global_symbol_modules_static_stab(Elf_X_Shdr* stabscnp, Elf_X_Shdr* stabstrscnp) -{ +bool Object::fix_global_symbol_modules_static_stab(Elf_X_Shdr *stabscnp, Elf_X_Shdr *stabstrscnp) { // Read the stab section to find the module of global symbols. // The symbols appear in the stab section by module. A module begins // with a symbol of type N_UNDF and ends with a symbol of type N_ENDM. @@ -2622,8 +2551,7 @@ bool Object::fix_global_symbol_modules_static_stab(Elf_X_Shdr* stabscnp, Elf_X_S if (!stabdata.isValid() || !stabstrdata.isValid()) return false; - switch (addressWidth_nbytes) - { + switch (addressWidth_nbytes) { case 4: stabptr = new stab_entry_32(stabdata.d_buf(), stabstrdata.get_string(), @@ -2646,10 +2574,8 @@ bool Object::fix_global_symbol_modules_static_stab(Elf_X_Shdr* stabscnp, Elf_X_S bool is_fortran = false; // is the current module fortran code? - for (unsigned i = 0; i < stabptr->count(); i++) - { - switch(stabptr->type(i)) - { + for (unsigned i = 0; i < stabptr->count(); i++) { + switch (stabptr->type(i)) { case N_UNDF: /* start of object file */ stabptr->setStringBase(next_stabstr); next_stabstr = stabptr->getStringBase() + stabptr->val(i); @@ -2678,32 +2604,27 @@ bool Object::fix_global_symbol_modules_static_stab(Elf_X_Shdr* stabscnp, Elf_X_S // bperr("got %d type, str = %s\n", stabptr->type(i), p); // if (stabptr->type(i) == N_FUN && strlen(p) == 0) { - if (strlen(p) == 0) - { + if (strlen(p) == 0) { // GNU CC 2.8 and higher associate a null-named function // entry with the end of a function. Just skip it. break; } - const char *q = strchr(p,':'); + const char *q = strchr(p, ':'); unsigned len; - if (q) - { + if (q) { len = q - p; - } - else - { + } else { len = strlen(p); } - if (len == 0) - { + if (len == 0) { // symbol name is empty.Skip it.- 02/12/07 -Giri break; } - char *sname = new char[len+1]; + char *sname = new char[len + 1]; strncpy(sname, p, len); sname[len] = 0; @@ -2713,33 +2634,26 @@ bool Object::fix_global_symbol_modules_static_stab(Elf_X_Shdr* stabscnp, Elf_X_S // q[1] is the symbol descriptor. We must check the symbol descriptor // here to skip things we are not interested in, such as prototypes. - bool res = (symbols_.find(SymName)!=symbols_.end()); + bool res = (symbols_.find(SymName) != symbols_.end()); - if (!res && is_fortran) - { + if (!res && is_fortran) { // Fortran symbols usually appear with an '_' appended in .symtab, // but not on .stab SymName += "_"; - res = (symbols_.find(SymName)!=symbols_.end()); + res = (symbols_.find(SymName) != symbols_.end()); } - if (res && (q == 0 || q[1] != SD_PROTOTYPE)) - { + if (res && (q == 0 || q[1] != SD_PROTOTYPE)) { unsigned int count = 0; - std::vector< Symbol *> & syms = symbols_[SymName]; + std::vector &syms = symbols_[SymName]; /* If there's only one, apply regardless. */ - if ( syms.size() == 1 ) - { + if (syms.size() == 1) { // TODO: set module // symbols_[SymName][0]->setModuleName(module); - } - else - { - for ( unsigned int i = 0; i < syms.size(); i++ ) - { - if ( syms[i]->getLinkage() == Symbol::SL_GLOBAL ) - { + } else { + for (unsigned int i = 0; i < syms.size(); i++) { + if (syms[i]->getLinkage() == Symbol::SL_GLOBAL) { // TODO: set module // symbols_[SymName][i]->setModuleName(module); count++; @@ -2754,46 +2668,41 @@ bool Object::fix_global_symbol_modules_static_stab(Elf_X_Shdr* stabscnp, Elf_X_S { const char *p = stabptr->name(i); - if (strlen(p) == 0) - { + if (strlen(p) == 0) { // Rumours are that GNU CC 2.8 and higher associate a // null-named function entry with the end of a // function. Just skip it. break; } - const char *q = strchr(p,':'); + const char *q = strchr(p, ':'); - if (q == 0) - { + if (q == 0) { // bperr( "Unrecognized stab format: %s\n", p); // Happens with the Solaris native compiler (.xstabs entries?) break; } - if (q[1] == SD_PROTOTYPE) - { + if (q[1] == SD_PROTOTYPE) { // We see a prototype, skip it break; } unsigned long entryAddr = stabptr->val(i); - if (entryAddr == 0) - { + if (entryAddr == 0) { // The function stab doesn't contain a function address // (happens with the Solaris native compiler). We have to // look up the symbol by its name. That's unfortunate, since // names may not be unique and we may end up assigning a wrong // module name to the symbol. unsigned len = q - p; - if (len == 0) - { + if (len == 0) { // symbol name is empty.Skip it.- 02/12/07 -Giri break; } - char *sname = new char[len+1]; + char *sname = new char[len + 1]; strncpy(sname, p, len); sname[len] = 0; string nameFromStab = string(sname); @@ -2802,10 +2711,8 @@ bool Object::fix_global_symbol_modules_static_stab(Elf_X_Shdr* stabscnp, Elf_X_S for (unsigned i = 0; i < symbols_[nameFromStab].size(); i++) { symsToModules_[symbols_[nameFromStab][i]] = module; } - } - else - { - if (symsByOffset_.find(entryAddr)==symsByOffset_.end()) { + } else { + if (symsByOffset_.find(entryAddr) == symsByOffset_.end()) { //bperr( "fix_global_symbol_modules_static_stab " // "can't find address 0x%lx of STABS entry %s\n", entryAddr, p); break; @@ -2834,8 +2741,7 @@ bool Object::fix_global_symbol_modules_static_stab(Elf_X_Shdr* stabscnp, Elf_X_S // data_ptr_, data_off_, data_len_ void Object::find_code_and_data(Elf_X &elf, Offset txtaddr, - Offset dataddr) -{ + Offset dataddr) { /* Note: * .o's don't have program headers, so these fields are populated earlier * when the sections are processed -> see loaded_elf() @@ -2844,7 +2750,7 @@ void Object::find_code_and_data(Elf_X &elf, for (int i = 0; i < elf.e_phnum(); ++i) { Elf_X_Phdr &phdr = elf.get_phdr(i); - char *file_ptr = (char *)mf->base_addr(); + char *file_ptr = (char *) mf->base_addr(); /* if(!isRegionPresent(phdr.p_paddr(), phdr.p_filesz(), phdr.p_flags())) { Region *reg = new Region(i, "", phdr.p_paddr(), phdr.p_filesz(), @@ -2865,42 +2771,40 @@ void Object::find_code_and_data(Elf_X &elf, (phdr.p_vaddr() + phdr.p_filesz() >= entryAddress_)))) { if (code_ptr_ == 0 && code_off_ == 0 && code_len_ == 0) { - code_ptr_ = (char *)(void*)&file_ptr[phdr.p_offset()]; - code_off_ = (Offset)phdr.p_vaddr(); - code_len_ = (unsigned)phdr.p_filesz(); + code_ptr_ = (char *) (void *) &file_ptr[phdr.p_offset()]; + code_off_ = (Offset) phdr.p_vaddr(); + code_len_ = (unsigned) phdr.p_filesz(); } } else if (((phdr.p_vaddr() <= dataddr) && (phdr.p_vaddr() + phdr.p_filesz() >= dataddr)) || (!dataddr && (phdr.p_type() == PT_LOAD))) { if (data_ptr_ == 0 && data_off_ == 0 && data_len_ == 0) { - data_ptr_ = (char *)(void *)&file_ptr[phdr.p_offset()]; - data_off_ = (Offset)phdr.p_vaddr(); - data_len_ = (unsigned)phdr.p_filesz(); + data_ptr_ = (char *) (void *) &file_ptr[phdr.p_offset()]; + data_off_ = (Offset) phdr.p_vaddr(); + data_len_ = (unsigned) phdr.p_filesz(); } } } //if (addressWidth_nbytes == 8) bperr( ">>> 64-bit find_code_and_data() successful\n"); } -const char *Object::elf_vaddr_to_ptr(Offset vaddr) const -{ +const char *Object::elf_vaddr_to_ptr(Offset vaddr) const { const char *ret = NULL; unsigned code_size_ = code_len_; unsigned data_size_ = data_len_; if (vaddr >= code_off_ && vaddr < code_off_ + code_size_) { - ret = ((char *)code_ptr_) + (vaddr - code_off_); + ret = ((char *) code_ptr_) + (vaddr - code_off_); } else if (vaddr >= data_off_ && vaddr < data_off_ + data_size_) { - ret = ((char *)data_ptr_) + (vaddr - data_off_); + ret = ((char *) data_ptr_) + (vaddr - data_off_); } return ret; } -stab_entry *Object::get_stab_info() const -{ - char *file_ptr = (char *)mf->base_addr(); +stab_entry *Object::get_stab_info() const { + char *file_ptr = (char *) mf->base_addr(); // check that file has .stab info if (stab_off_ && stab_size_ && stabstr_off_) { @@ -2922,7 +2826,7 @@ stab_entry *Object::get_stab_info() const } Object::Object(MappedFile *mf_, bool, void (*err_func)(const char *), - bool alloc_syms, Symtab* st) : + bool alloc_syms, Symtab *st) : AObject(mf_, err_func, st), elfHdr(NULL), hasReldyn_(false), @@ -2963,40 +2867,36 @@ Object::Object(MappedFile *mf_, bool, void (*err_func)(const char *), #endif is_aout_ = false; - if(mf->getFD() != -1) { + if (mf->getFD() != -1) { elfHdr = Elf_X::newElf_X(mf->getFD(), ELF_C_READ, NULL, mf_->pathname()); - } - else { - elfHdr = Elf_X::newElf_X((char *)mf->base_addr(), mf->size(), mf_->pathname()); + } else { + elfHdr = Elf_X::newElf_X((char *) mf->base_addr(), mf->size(), mf_->pathname()); } // ELF header: sanity check //if (!elfHdr->isValid()|| !pdelf_check_ehdr(elfHdr)) - if (!elfHdr->isValid()) { + if (!elfHdr->isValid()) { log_elferror(err_func_, "ELF header"); has_error = true; return; - } - else if (!pdelf_check_ehdr(*elfHdr)) { + } else if (!pdelf_check_ehdr(*elfHdr)) { log_elferror(err_func_, "ELF header failed integrity check"); has_error = true; return; } dwarf = DwarfHandle::createDwarfHandle(mf_->pathname(), elfHdr); - if( elfHdr->e_type() == ET_DYN ) { + if (elfHdr->e_type() == ET_DYN) { // load_shared_object(alloc_syms); - load_object(alloc_syms); - } - else if( elfHdr->e_type() == ET_REL || elfHdr->e_type() == ET_EXEC ) { + load_object(alloc_syms); + } else if (elfHdr->e_type() == ET_REL || elfHdr->e_type() == ET_EXEC) { // Differentiate between an executable and an object file - if( elfHdr->e_phnum() ) is_aout_ = true; + if (elfHdr->e_phnum()) is_aout_ = true; else is_aout_ = false; load_object(alloc_syms); - } - else { - log_perror(err_func_,"Invalid filetype in Elf header"); + } else { + log_perror(err_func_, "Invalid filetype in Elf header"); has_error = true; return; } @@ -3015,8 +2915,7 @@ Object::Object(MappedFile *mf_, bool, void (*err_func)(const char *), #endif } -Object::~Object() -{ +Object::~Object() { relocation_table_.clear(); fbt_.clear(); allRegionHdrs.clear(); @@ -3029,36 +2928,32 @@ Object::~Object() } } -void Object::log_elferror(void (*err_func)(const char *), const char* msg) -{ - const char* err = elf_errmsg(elf_errno()); - err = err ? err: "(bad elf error)"; - string str = string(err)+string(msg); +void Object::log_elferror(void (*err_func)(const char *), const char *msg) { + const char *err = elf_errmsg(elf_errno()); + err = err ? err : "(bad elf error)"; + string str = string(err) + string(msg); err_func(str.c_str()); } -bool Object::get_func_binding_table(std::vector &fbt) const -{ +bool Object::get_func_binding_table(std::vector &fbt) const { #if !defined(os_vxworks) - if(!plt_addr_ || (!fbt_.size())) return false; + if (!plt_addr_ || (!fbt_.size())) return false; #endif fbt = fbt_; return true; } -bool Object::get_func_binding_table_ptr(const std::vector *&fbt) const -{ - if(!plt_addr_ || (!fbt_.size())) return false; +bool Object::get_func_binding_table_ptr(const std::vector *&fbt) const { + if (!plt_addr_ || (!fbt_.size())) return false; fbt = &fbt_; return true; } -void Object::getDependencies(std::vector &deps){ +void Object::getDependencies(std::vector &deps) { deps = deps_; } -bool Object::addRelocationEntry(relocationEntry &re) -{ +bool Object::addRelocationEntry(relocationEntry &re) { relocation_table_.push_back(re); return true; } @@ -3103,14 +2998,13 @@ const ostream &Object::dump_state_info(ostream &s) #endif -Offset Object::getPltSlot(string funcName) const -{ +Offset Object::getPltSlot(string funcName) const { relocationEntry re; - Offset offset=0; + Offset offset = 0; - for ( unsigned int i = 0; i < fbt_.size(); i++ ){ - if (funcName == fbt_[i].name() ){ - offset = fbt_[i].rel_addr(); + for (unsigned int i = 0; i < fbt_.size(); i++) { + if (funcName == fbt_[i].name()) { + offset = fbt_[i].rel_addr(); } } @@ -3122,11 +3016,10 @@ Offset Object::getPltSlot(string funcName) const // sections mapped to them // -void Object::get_valid_memory_areas(Elf_X &elf) -{ +void Object::get_valid_memory_areas(Elf_X &elf) { for (unsigned i = 0; i < elf.e_shnum(); ++i) { Elf_X_Shdr &shdr = elf.get_shdr(i); - if ( !shdr.isValid()) { + if (!shdr.isValid()) { break; } if (shdr.sh_flags() & SHF_ALLOC) { // This section is in memory @@ -3154,17 +3047,18 @@ void Object::get_valid_memory_areas(Elf_X &elf) // // #if defined(os_linux) + // Differentiating between g++ and pgCC by stabs info (as in the solaris/ // aix case, below) will not work; the gcc-compiled object files that // get included at link time will fill in the N_OPT stabs line. Instead, // look for "pgCC_compiled." symbols. -bool parseCompilerType(Object *objPtr) -{ - dyn_hash_map >*syms = objPtr->getAllSymbols(); - if(syms->find("pgCC_compiled.") != syms->end()) +bool parseCompilerType(Object *objPtr) { + dyn_hash_map > *syms = objPtr->getAllSymbols(); + if (syms->find("pgCC_compiled.") != syms->end()) return true; return false; } + #else bool parseCompilerType(Object *objPtr) { @@ -3195,13 +3089,11 @@ bool parseCompilerType(Object *objPtr) #if (defined(os_linux) || defined(os_freebsd)) -static unsigned long read_uleb128(const unsigned char *data, unsigned *bytes_read) -{ +static unsigned long read_uleb128(const unsigned char *data, unsigned *bytes_read) { unsigned long result = 0; unsigned shift = 0; *bytes_read = 0; - while (1) - { + while (1) { result |= (data[*bytes_read] & 0x7f) << shift; if ((data[(*bytes_read)++] & 0x80) == 0) break; @@ -3210,13 +3102,11 @@ static unsigned long read_uleb128(const unsigned char *data, unsigned *bytes_rea return result; } -static signed long read_sleb128(const unsigned char *data, unsigned *bytes_read) -{ +static signed long read_sleb128(const unsigned char *data, unsigned *bytes_read) { unsigned long result = 0; unsigned shift = 0; *bytes_read = 0; - while (1) - { + while (1) { result |= (data[*bytes_read] & 0x7f) << shift; shift += 7; if ((data[*bytes_read] & 0x80) == 0) @@ -3270,8 +3160,7 @@ static uint64_t endian_64bit(const uint64_t value, bool big) { } static int read_val_of_type(int type, unsigned long *value, const unsigned char *addr, - const mach_relative_info &mi) -{ + const mach_relative_info &mi) { unsigned size = 0; if (type == DW_EH_PE_omit) return 0; @@ -3283,8 +3172,7 @@ static int read_val_of_type(int type, unsigned long *value, const unsigned char * and I'm finding the upper bit seems to sometimes contain garbage. * gcc uses the 0x70 bits in its exception parsing, so that's what we'll do. **/ - switch (type & 0x70) - { + switch (type & 0x70) { case DW_EH_PE_pcrel: base = mi.pc; break; @@ -3299,25 +3187,21 @@ static int read_val_of_type(int type, unsigned long *value, const unsigned char break; } - if ((type & 0x70) == DW_EH_PE_aligned) - { + if ((type & 0x70) == DW_EH_PE_aligned) { if (mi.word_size == 4) { - addr = (const unsigned char*)(((unsigned long)addr + 3) & (~0x3l)); - } - else if (mi.word_size == 8) { - addr = (const unsigned char*)(((unsigned long)addr + 7) & (~0x7l)); + addr = (const unsigned char *) (((unsigned long) addr + 3) & (~0x3l)); + } else if (mi.word_size == 8) { + addr = (const unsigned char *) (((unsigned long) addr + 7) & (~0x7l)); } } - switch (type & 0x0f) - { + switch (type & 0x0f) { case DW_EH_PE_absptr: if (mi.word_size == 4) { *value = (unsigned long) endian_32bit(*((const uint32_t *) addr), mi.big_input); size = 4; - } - else if (mi.word_size == 8) { + } else if (mi.word_size == 8) { *value = (unsigned long) endian_64bit(*((const uint64_t *) addr), mi.big_input); size = 8; } @@ -3391,12 +3275,12 @@ static int read_val_of_type(int type, unsigned long *value, const unsigned char **/ #define SHORT_FDE_HLEN 4 #define LONG_FDE_HLEN 12 + static int read_except_table_gcc3( const unsigned char e_ident[], mach_relative_info &mi, Elf_X_Shdr *eh_frame, Elf_X_Shdr *except_scn, - std::vector &addresses) -{ + std::vector &addresses) { Dwarf_Addr low_pc = 0; Dwarf_Off fde_offset; int result, ptr_size; @@ -3410,13 +3294,12 @@ int read_except_table_gcc3( Elf_Data * eh_frame_data = eh_frame->get_data().elf_data(); //For each CFI entry - do - { + do { Dwarf_CFI_Entry entry; res = dwarf_next_cfi(e_ident, eh_frame_data, true, offset, &next_offset, &entry); saved_cur_offset = offset; //saved in case needed later offset = next_offset; - + // If no more CFI entries left in the section if(res==1 && next_offset==(Dwarf_Off)-1) break; @@ -3491,15 +3374,11 @@ int read_except_table_gcc3( // field, a byte telling how the LSDA pointer is encoded. cur_augdata = const_cast(thisCIE.cie.augmentation_data); lsda_encoding = DW_EH_PE_omit; - for (j=0; j -{ +struct exception_compare : public binary_function { bool operator()(const ExceptionBlock &e1, const ExceptionBlock &e2) { if (e1.tryStart() < e2.tryStart()) return true; @@ -3698,15 +3570,14 @@ struct exception_compare: public binary_function & catch_addrs) { @@ -3736,13 +3607,11 @@ bool Object::find_catch_blocks(Elf_X_Shdr * eh_frame, #endif -ObjectType Object::objType() const -{ +ObjectType Object::objType() const { return obj_type_; } -void Object::getModuleLanguageInfo(dyn_hash_map *mod_langs) -{ +void Object::getModuleLanguageInfo(dyn_hash_map *mod_langs) { string working_module; const char *ptr; // check .stabs section to get language info for modules: @@ -3784,33 +3653,26 @@ void Object::getModuleLanguageInfo(dyn_hash_map *mod stabptr = get_stab_info(); next_stabstr = stabptr->getStringBase(); - for( unsigned int i = 0; i < stabptr->count(); i++ ) - { - if (stabptr->type(i) == N_UNDF) - {/* start of object file */ + for (unsigned int i = 0; i < stabptr->count(); i++) { + if (stabptr->type(i) == N_UNDF) {/* start of object file */ /* value contains offset of the next string table for next module */ // assert(stabptr->nameIdx(i) == 1); stabptr->setStringBase(next_stabstr); next_stabstr = stabptr->getStringBase() + stabptr->val(i); - } - else if (stabptr->type(i) == N_OPT) - { + } else if (stabptr->type(i) == N_OPT) { // We can use the compiler option string (in a pinch) to guess at the source file language // There is possibly more useful information encoded somewhere around here, but I lack // an immediate reference.... if (working_name) working_options = const_cast(stabptr->name(i)); - } - else if ((stabptr->type(i) == N_SO) || (stabptr->type(i) == N_ENDM)) - { /* compilation source or file name */ + } else if ((stabptr->type(i) == N_SO) || (stabptr->type(i) == N_ENDM)) { /* compilation source or file name */ // We have arrived at the next source file, finish up with the last one and reset state // before starting next // XXXXXXXXXXX This block is mirrored near the end of routine, if you edit it, // XXXXXXXXXXX change it there too. - if (working_name) - { + if (working_name) { working_lang = pickLanguage(working_module, working_options, working_lang); if (working_lang == lang_Fortran_with_pretty_debug) fortran_kludge_flag = 1; @@ -3825,37 +3687,29 @@ void Object::getModuleLanguageInfo(dyn_hash_map *mod // Now: out with the old, in with the new - if (stabptr->type(i) == N_ENDM) - { + if (stabptr->type(i) == N_ENDM) { // special case: // which is most likely both broken (and ignorable ???) working_name = "DEFAULT_MODULE"; - } - else - { + } else { working_name = stabptr->name(i); ptr = strrchr(working_name, '/'); - if (ptr) - { + if (ptr) { ptr++; working_name = ptr; } } working_module = string(working_name); - if ((mod_langs->find(working_module) != mod_langs->end()) && (*mod_langs)[working_module] != lang_Unknown) - { + if ((mod_langs->find(working_module) != mod_langs->end()) && (*mod_langs)[working_module] != lang_Unknown) { // we already have a module with this name in the map. If it has been given // a language assignment (not lang_Unknown), we can just skip ahead working_name = NULL; working_options = NULL; continue; - } - else - { + } else { //cerr << __FILE__ << __LINE__ << ": Module: " <desc(i) << endl; - switch (stabptr->desc(i)) - { + switch (stabptr->desc(i)) { case N_SO_FORTRAN: working_lang = lang_Fortran; break; @@ -3887,8 +3741,7 @@ void Object::getModuleLanguageInfo(dyn_hash_map *mod // about // XXXXXXXXXXX see note above (find the X's) - if (working_name) - { + if (working_name) { working_lang = pickLanguage(working_module, working_options, working_lang); if (working_lang == lang_Fortran_with_pretty_debug) fortran_kludge_flag = 1; @@ -3896,19 +3749,16 @@ void Object::getModuleLanguageInfo(dyn_hash_map *mod } // XXXXXXXXXXX - if (fortran_kludge_flag) - { + if (fortran_kludge_flag) { // XXX This code does not appear to be used anymore?? // go through map and change all lang_Fortran to lang_Fortran_with_pretty_symtab dyn_hash_map::iterator iter = (*mod_langs).begin(); string aname; supportedLanguages alang; - for(;iter!=(*mod_langs).end();iter++) - { + for (; iter != (*mod_langs).end(); iter++) { aname = iter->first; alang = iter->second; - if(lang_Fortran == alang) - { + if (lang_Fortran == alang) { (*mod_langs)[aname] = lang_Fortran_with_pretty_debug; } } @@ -3925,26 +3775,24 @@ void Object::getModuleLanguageInfo(dyn_hash_map *mod delete stabptr; #if defined(cap_dwarf) - if (hasDwarfInfo()) - { + if (hasDwarfInfo()) { Dwarf **dbg_ptr = dwarf->type_dbg(); if (!dbg_ptr) return; - Dwarf * &dbg = *dbg_ptr; + Dwarf *&dbg = *dbg_ptr; Dwarf_Die moduleDIE; Dwarf_Attribute languageAttribute; /* Only .debug_info for now, not .debug_types */ size_t cu_header_size; - for(Dwarf_Off cu_off = 0, next_cu_off; - dwarf_nextcu(dbg, cu_off, &next_cu_off, &cu_header_size, - NULL, NULL, NULL) == 0; - cu_off = next_cu_off) - { + for (Dwarf_Off cu_off = 0, next_cu_off; + dwarf_nextcu(dbg, cu_off, &next_cu_off, &cu_header_size, + NULL, NULL, NULL) == 0; + cu_off = next_cu_off) { Dwarf_Off cu_die_off = cu_off + cu_header_size; - Dwarf_Die *cu_die_p; + Dwarf_Die *cu_die_p; cu_die_p = dwarf_offdie(dbg, cu_die_off, &moduleDIE); - if(cu_die_p == NULL) break; + if (cu_die_p == NULL) break; Dwarf_Half moduleTag = dwarf_tag(&moduleDIE); if (moduleTag != DW_TAG_compile_unit) { @@ -3952,7 +3800,7 @@ void Object::getModuleLanguageInfo(dyn_hash_map *mod } /* Extract the name of this module. */ - auto moduleName = dwarf_diename(&moduleDIE); + auto moduleName = dwarf_diename(&moduleDIE); if (!moduleName) { break; } @@ -3974,8 +3822,7 @@ void Object::getModuleLanguageInfo(dyn_hash_map *mod break; } - switch( languageConstant ) - { + switch (languageConstant) { case DW_LANG_C: case DW_LANG_C89: case DW_LANG_C99: @@ -4004,17 +3851,16 @@ void Object::getModuleLanguageInfo(dyn_hash_map *mod } /* end languageConstant switch */ } } -#endif +#endif } -bool AObject::getSegments(vector &segs) const -{ +bool AObject::getSegments(vector &segs) const { unsigned i; - for(i=0;igetRegionName() == ".text") || (regions_[i]->getRegionName() == ".init") || (regions_[i]->getRegionName() == ".fini") || - (regions_[i]->getRegionName() == ".rodata") || (regions_[i]->getRegionName() == ".plt") || (regions_[i]->getRegionName() == ".data")) - { + for (i = 0; i < regions_.size(); i++) { + if ((regions_[i]->getRegionName() == ".text") || (regions_[i]->getRegionName() == ".init") || + (regions_[i]->getRegionName() == ".fini") || + (regions_[i]->getRegionName() == ".rodata") || (regions_[i]->getRegionName() == ".plt") || + (regions_[i]->getRegionName() == ".data")) { Segment seg; seg.data = regions_[i]->getPtrToRawData(); seg.loadaddr = regions_[i]->getDiskOffset(); @@ -4028,33 +3874,29 @@ bool AObject::getSegments(vector &segs) const } -bool Object::emitDriver(string fName, std::set &allSymbols, unsigned) -{ +bool Object::emitDriver(string fName, std::set &allSymbols, unsigned) { #ifdef BINEDIT_DEBUG printf("emitting...\n"); //print_symbol_map(&symbols_); print_symbols(allSymbols); printf("%d total symbol(s)\n", allSymbols.size()); #endif - if (elfHdr->e_ident()[EI_CLASS] == ELFCLASS32) - { + if (elfHdr->e_ident()[EI_CLASS] == ELFCLASS32) { Dyninst::SymtabAPI::emitElf *em = - new Dyninst::SymtabAPI::emitElf(elfHdr, isStripped, this, err_func_, associated_symtab); + new Dyninst::SymtabAPI::emitElf(elfHdr, isStripped, this, err_func_, + associated_symtab); bool ok = em->createSymbolTables(allSymbols); - if(ok) - { + if (ok) { ok = em->driver(fName); } delete em; return ok; - } - else if (elfHdr->e_ident()[EI_CLASS] == ELFCLASS64) - { + } else if (elfHdr->e_ident()[EI_CLASS] == ELFCLASS64) { Dyninst::SymtabAPI::emitElf *em = - new Dyninst::SymtabAPI::emitElf(elfHdr, isStripped, this, err_func_, associated_symtab); + new Dyninst::SymtabAPI::emitElf(elfHdr, isStripped, this, err_func_, + associated_symtab); bool ok = em->createSymbolTables(allSymbols); - if(ok) - { + if (ok) { ok = em->driver(fName); } delete em; @@ -4063,41 +3905,37 @@ bool Object::emitDriver(string fName, std::set &allSymbols, unsigned) return false; } -const char *Object::interpreter_name() const -{ +const char *Object::interpreter_name() const { return interpreter_name_; } /* Parse everything in the file on disk, and cache that we've done so, because our modules may not bear any relation to the name source files. */ -void Object::parseStabFileLineInfo() -{ - static dyn_hash_map< string, bool > haveParsedFileMap; +void Object::parseStabFileLineInfo() { + static dyn_hash_map haveParsedFileMap; /* We haven't parsed this file already, so iterate over its stab entries. */ - stab_entry * stabEntry = get_stab_info(); - if( stabEntry == NULL ) return; - const char * nextStabString = stabEntry->getStringBase(); + stab_entry *stabEntry = get_stab_info(); + if (stabEntry == NULL) return; + const char *nextStabString = stabEntry->getStringBase(); - const char * currentSourceFile = NULL; - const char * moduleName = NULL; + const char *currentSourceFile = NULL; + const char *moduleName = NULL; Function *currentFunction = NULL; Offset currentAddress = 0; unsigned currentLineBase = 0; unsigned functionLineToPossiblyAdd = 0; //Offset baseAddress = getBaseAddress(); - LineInformation* li_for_module = NULL; + LineInformation *li_for_module = NULL; - for ( unsigned int i = 0; i < stabEntry->count(); i++ ) - { - switch (stabEntry->type( i )) - { + for (unsigned int i = 0; i < stabEntry->count(); i++) { + switch (stabEntry->type(i)) { case N_UNDF: /* start of an object file */ { - stabEntry->setStringBase( nextStabString ); - nextStabString = stabEntry->getStringBase() + stabEntry->val( i ); + stabEntry->setStringBase(nextStabString); + nextStabString = stabEntry->getStringBase() + stabEntry->val(i); currentSourceFile = NULL; } @@ -4105,26 +3943,22 @@ void Object::parseStabFileLineInfo() case N_SO: /* compilation source or file name */ { - const char * sourceFile = stabEntry->name( i ); - currentSourceFile = strrchr( sourceFile, '/' ); + const char *sourceFile = stabEntry->name(i); + currentSourceFile = strrchr(sourceFile, '/'); - if ( currentSourceFile == NULL ) - { + if (currentSourceFile == NULL) { currentSourceFile = sourceFile; - } - else - { + } else { ++currentSourceFile; } - Module* mod; + Module *mod; moduleName = currentSourceFile; - if(!associated_symtab->findModuleByName(mod, moduleName)) { + if (!associated_symtab->findModuleByName(mod, moduleName)) { mod = associated_symtab->getDefaultModule(); } li_for_module = mod->getLineInformation(); - if(!li_for_module) - { + if (!li_for_module) { li_for_module = new LineInformation; mod->setLineInfo(li_for_module); } @@ -4134,14 +3968,11 @@ void Object::parseStabFileLineInfo() case N_SOL: /* file name (possibly an include file) */ { - const char * sourceFile = stabEntry->name( i ); - currentSourceFile = strrchr( sourceFile, '/' ); - if ( currentSourceFile == NULL ) - { + const char *sourceFile = stabEntry->name(i); + currentSourceFile = strrchr(sourceFile, '/'); + if (currentSourceFile == NULL) { currentSourceFile = sourceFile; - } - else - { + } else { ++currentSourceFile; } @@ -4150,8 +3981,7 @@ void Object::parseStabFileLineInfo() case N_FUN: /* a function */ { - if ( *stabEntry->name( i ) == 0 ) - { + if (*stabEntry->name(i) == 0) { currentFunction = NULL; currentLineBase = 0; break; @@ -4162,12 +3992,10 @@ void Object::parseStabFileLineInfo() const char *stabstr = stabEntry->name(i); unsigned iter = 0; - while (iter < 2048) - { + while (iter < 2048) { char c = stabstr[iter]; - if ( (c == ':') || (c == '\0')) - { + if ((c == ':') || (c == '\0')) { //stabstrs use ':' as delimiter stringbuf[iter] = '\0'; break; @@ -4178,15 +4006,11 @@ void Object::parseStabFileLineInfo() iter++; } - if (iter >= 2047) - { + if (iter >= 2047) { create_printf("%s[%d]: something went horribly awry\n", FILE__, __LINE__); continue; - } - else - { - switch (stabstr[iter+1]) - { + } else { + switch (stabstr[iter + 1]) { case 'F': case 'f': // A "good" function @@ -4202,9 +4026,8 @@ void Object::parseStabFileLineInfo() }; } - if (! associated_symtab->findFunctionsByName(funcs, std::string(stringbuf)) - || !funcs.size()) - { + if (!associated_symtab->findFunctionsByName(funcs, std::string(stringbuf)) + || !funcs.size()) { continue; } @@ -4212,18 +4035,16 @@ void Object::parseStabFileLineInfo() currentLineBase = stabEntry->desc(i); functionLineToPossiblyAdd = currentLineBase; - if(!currentFunction) continue; + if (!currentFunction) continue; currentAddress = currentFunction->getOffset(); } break; - case N_SLINE: - { + case N_SLINE: { unsigned current_col = 0; - if (!currentLineBase) - { + if (!currentLineBase) { continue; } @@ -4232,8 +4053,7 @@ void Object::parseStabFileLineInfo() // Addresses specified in SLINEs are relative to the beginning of the fn Offset newLineAddress = stabEntry->val(i) + currentFunction->getOffset(); - if (newLineAddress <= currentAddress) - { + if (newLineAddress <= currentAddress) { continue; } @@ -4244,24 +4064,22 @@ void Object::parseStabFileLineInfo() // the line number of the original function definition in addition // to this SLINE ( use the same address range) - if (functionLineToPossiblyAdd) - { - if (functionLineToPossiblyAdd < newLineSpec) - { - if(li_for_module) + if (functionLineToPossiblyAdd) { + if (functionLineToPossiblyAdd < newLineSpec) { + if (li_for_module) li_for_module->addLine(currentSourceFile, functionLineToPossiblyAdd, current_col, currentAddress, - newLineAddress ); + newLineAddress); } functionLineToPossiblyAdd = 0; } - if(li_for_module) + if (li_for_module) li_for_module->addLine(currentSourceFile, newLineSpec, current_col, currentAddress, - newLineAddress ); + newLineAddress); currentAddress = newLineAddress; currentLineBase = newLineSpec + 1; @@ -4320,24 +4138,22 @@ class open_statement { void Object::parseLineInfoForCU(Dwarf_Die cuDIE, LineInformation* li_for_module) { /* Acquire this CU's source lines. */ - Dwarf_Lines * lineBuffer; + Dwarf_Lines *lineBuffer; size_t lineCount; int status = dwarf_getsrclines(&cuDIE, &lineBuffer, &lineCount); /* It's OK for a CU not to have line information. */ - if(status != 0) - { + if (status != 0) { return; } StringTablePtr strings(li_for_module->getStrings()); - Dwarf_Files * files; + Dwarf_Files *files; size_t offset = strings->size(); size_t filecount; status = dwarf_getsrcfiles(&cuDIE, &files, &filecount); - if (status != 0 ) - { + if (status != 0) { // It could happen the line table is present, - // but there is no line in the table + // but there is no line in the table return; } @@ -4345,7 +4161,7 @@ void Object::parseLineInfoForCU(Dwarf_Die cuDIE, LineInformation* li_for_module) Dwarf_Attribute attr; const char * comp_dir = dwarf_formstring( dwarf_attr(&cuDIE, DW_AT_comp_dir, &attr) ); std::string comp_dir_str( comp_dir ? comp_dir : "" ); - + // lambda function to convert relative to absolute path auto convert_to_absolute = [&comp_dir_str](const char * &filename) -> std::string { @@ -4399,23 +4215,21 @@ void Object::parseLineInfoForCU(Dwarf_Die cuDIE, LineInformation* li_for_module) /* Iterate over this CU's source lines. */ open_statement current_line; open_statement current_statement; - for(size_t i = 0; i < lineCount; i++ ) - { - auto line = dwarf_onesrcline(lineBuffer, i); + for (size_t i = 0; i < lineCount; i++) { + auto line = dwarf_onesrcline(lineBuffer, i); /* Acquire the line number, address, source, and end of sequence flag. */ status = dwarf_lineno(line, ¤t_statement.line_number); - if ( status != 0 ) { + if (status != 0) { cout << "dwarf_lineno failed" << endl; continue; } status = dwarf_linecol(line, ¤t_statement.column_number); - if ( status != 0 ) { current_statement.column_number = 0; } + if (status != 0) { current_statement.column_number = 0; } status = dwarf_lineaddr(line, ¤t_statement.start_addr); - if ( status != 0 ) - { + if (status != 0) { cout << "dwarf_lineaddr failed" << endl; continue; } @@ -4428,10 +4242,10 @@ void Object::parseLineInfoForCU(Dwarf_Die cuDIE, LineInformation* li_for_module) if (result) current_statement.start_addr = new_lineAddr; } - + //status = dwarf_line_srcfileno(line, ¤t_statement.string_table_index); - const char * file_name = dwarf_linesrc(line, NULL, NULL); - if ( !file_name ) { + const char *file_name = dwarf_linesrc(line, NULL, NULL); + if (!file_name) { cout << "dwarf_linesrc - empty name" << endl; continue; } @@ -4439,15 +4253,13 @@ void Object::parseLineInfoForCU(Dwarf_Die cuDIE, LineInformation* li_for_module) // search filename index std::string file_name_str(convert_to_absolute(file_name)); int index = -1; - for(size_t idx = offset; idx < strings->size(); ++idx) - { - if((*strings)[idx].str==file_name_str) - { - index = idx; + for (size_t idx = offset; idx < strings->size(); ++idx) { + if ((*strings)[idx].str == file_name_str) { + index = idx; break; } } - if( index == -1 ) { + if (index == -1) { cout << "dwarf_linesrc didn't find index" << endl; continue; } @@ -4455,16 +4267,16 @@ void Object::parseLineInfoForCU(Dwarf_Die cuDIE, LineInformation* li_for_module) bool isEndOfSequence; status = dwarf_lineendsequence(line, &isEndOfSequence); - if ( status != 0 ) { + if (status != 0) { cout << "dwarf_lineendsequence failed" << endl; continue; } - if(i == lineCount - 1) { + if (i == lineCount - 1) { isEndOfSequence = true; } bool isStatement; status = dwarf_linebeginstatement(line, &isStatement); - if(status != 0) { + if (status != 0) { cout << "dwarf_linebeginstatement failed" << endl; continue; } @@ -4646,25 +4458,20 @@ LineInformation* Object::parseLineInfoForObject(StringTablePtr strings) } - -void Object::parseLineInfoForAddr(Offset addr_to_find) -{ +void Object::parseLineInfoForAddr(Offset addr_to_find) { Dwarf **dbg_ptr = dwarf->line_dbg(); if (!dbg_ptr) return; - std::set mod_for_offset; + std::set mod_for_offset; associated_symtab->findModuleByOffset(mod_for_offset, addr_to_find); - for(auto mod = mod_for_offset.begin(); - mod != mod_for_offset.end(); - ++mod) - { + for (auto mod = mod_for_offset.begin(); + mod != mod_for_offset.end(); + ++mod) { (*mod)->parseLineInformation(); } // no mod for offset means no line info for sure if we've parsed all ranges... } - - bool Object::hasDebugInfo() { Region *ignore; @@ -4679,17 +4486,15 @@ void Object::parseDwarfFileLineInfo() vector mods; associated_symtab->getAllModules(mods); - for(auto mod = mods.begin(); - mod != mods.end(); - ++mod) - { + for (auto mod = mods.begin(); + mod != mods.end(); + ++mod) { (*mod)->parseLineInformation(); } } /* end parseDwarfFileLineInfo() */ -void Object::parseFileLineInfo() -{ - if(parsedAllLineInfo) return; +void Object::parseFileLineInfo() { + if (parsedAllLineInfo) return; parseStabFileLineInfo(); parseDwarfFileLineInfo(); @@ -4697,16 +4502,15 @@ void Object::parseFileLineInfo() } -void Object::parseTypeInfo() -{ +void Object::parseTypeInfo() { #if defined(TIMED_PARSE) struct timeval starttime; gettimeofday(&starttime, NULL); #endif parseStabTypes(); - Dwarf ** typeInfo = dwarf->type_dbg(); - if(!typeInfo) return; + Dwarf **typeInfo = dwarf->type_dbg(); + if (!typeInfo) return; DwarfWalker walker(associated_symtab, *typeInfo); walker.parse(); #if defined(TIMED_PARSE) @@ -4721,8 +4525,7 @@ void Object::parseTypeInfo() #endif } -void Object::parseStabTypes() -{ +void Object::parseStabTypes() { types_printf("Entry to parseStabTypes for %s\n", associated_symtab->name().c_str()); stab_entry *stabptr = NULL; const char *next_stabstr = NULL; @@ -4765,8 +4568,8 @@ void Object::parseStabTypes() // XXX - Elf32 specific needs to be in seperate file -- jkh 3/18/99 next_stabstr = stabptr->getStringBase(); types_printf("\t Parsing %d stab entries\n", stabptr->count()); - for (i=0; icount(); i++) { - switch(stabptr->type(i)){ + for (i = 0; i < stabptr->count(); i++) { + switch (stabptr->type(i)) { case N_UNDF: /* start of object file */ /* value contains offset of the next string table for next module */ // assert(stabptr->nameIdx(i) == 1); @@ -4802,7 +4605,7 @@ void Object::parseStabTypes() symt_current_mangled_func_name = ""; // reset for next object file symt_current_func = NULL; - modName = const_cast(stabptr->name(i)); + modName = const_cast(stabptr->name(i)); // cerr << "checkpoint B" << endl; ptr = strrchr(modName, '/'); // cerr << "checkpoint C" << endl; @@ -4815,19 +4618,16 @@ void Object::parseStabTypes() parseActive = true; if (!mod) { create_printf("%s[%d]: FIXME\n", FILE__, __LINE__); - } - else if (!tc) - { + } else if (!tc) { create_printf("%s[%d]: FIXME\n", FILE__, __LINE__); - } - else + } else tc->clearNumberedTypes(); - } - else { + } else { //parseActive = false; mod = associated_symtab->getDefaultModule(); tc = typeCollection::getModTypeCollection(mod); - types_printf("\t Warning: failed to find module name matching %s, using %s\n", modName, mod->fileName().c_str()); + types_printf("\t Warning: failed to find module name matching %s, using %s\n", modName, + mod->fileName().c_str()); } #ifdef TIMED_PARSE @@ -4842,50 +4642,50 @@ void Object::parseStabTypes() default: break; } - if(parseActive || !is_aout()) { + if (parseActive || !is_aout()) { std::vector bpfv; - switch(stabptr->type(i)){ + switch (stabptr->type(i)) { case N_FUN: #ifdef TIMED_PARSE fun_count++; - gettimeofday(&t1, NULL); + gettimeofday(&t1, NULL); #endif //all we have to do with function stabs at this point is to assure that we have //properly set the var currentFunctionName for the later case of (parseActive) symt_current_func = NULL; int currentEntry = i; int funlen = strlen(stabptr->name(currentEntry)); - ptr = new char[funlen+1]; + ptr = new char[funlen + 1]; strcpy(ptr, stabptr->name(currentEntry)); - while(strlen(ptr) != 0 && ptr[strlen(ptr)-1] == '\\'){ - ptr[strlen(ptr)-1] = '\0'; + while (strlen(ptr) != 0 && ptr[strlen(ptr) - 1] == '\\') { + ptr[strlen(ptr) - 1] = '\0'; currentEntry++; - strcat(ptr,stabptr->name(currentEntry)); + strcat(ptr, stabptr->name(currentEntry)); } - char* colonPtr = NULL; - if(currentFunctionName) delete currentFunctionName; - if(!ptr || !(colonPtr = strchr(ptr,':'))) + char *colonPtr = NULL; + if (currentFunctionName) delete currentFunctionName; + if (!ptr || !(colonPtr = strchr(ptr, ':'))) currentFunctionName = NULL; else { - char* tmp = new char[colonPtr-ptr+1]; - strncpy(tmp,ptr,colonPtr-ptr); - tmp[colonPtr-ptr] = '\0'; + char *tmp = new char[colonPtr - ptr + 1]; + strncpy(tmp, ptr, colonPtr - ptr); + tmp[colonPtr - ptr] = '\0'; currentFunctionName = new string(tmp); // Shouldn't this be a function name lookup? - std::vectorsyms; - if(!associated_symtab->findSymbol(syms, - *currentFunctionName, - Symbol::ST_FUNCTION, - mangledName)) { - if(!associated_symtab->findSymbol(syms, - "_"+*currentFunctionName, - Symbol::ST_FUNCTION, - mangledName)) { + std::vector syms; + if (!associated_symtab->findSymbol(syms, + *currentFunctionName, + Symbol::ST_FUNCTION, + mangledName)) { + if (!associated_symtab->findSymbol(syms, + "_" + *currentFunctionName, + Symbol::ST_FUNCTION, + mangledName)) { string fortranName = *currentFunctionName + string("_"); if (associated_symtab->findSymbol(syms, - fortranName, - Symbol::ST_FUNCTION, - mangledName)) { + fortranName, + Symbol::ST_FUNCTION, + mangledName)) { delete currentFunctionName; currentFunctionName = new string(fortranName); } @@ -4897,35 +4697,34 @@ void Object::parseStabTypes() delete[] ptr; #ifdef TIMED_PARSE gettimeofday(&t2, NULL); - fun_dur += (t2.tv_sec - t1.tv_sec)*1000.0 + (t2.tv_usec - t1.tv_usec)/1000.0; - //fun_dur += (t2.tv_sec/1000 + t2.tv_usec*1000) - (t1.tv_sec/1000 + t1.tv_usec*1000); + fun_dur += (t2.tv_sec - t1.tv_sec)*1000.0 + (t2.tv_usec - t1.tv_usec)/1000.0; + //fun_dur += (t2.tv_sec/1000 + t2.tv_usec*1000) - (t1.tv_sec/1000 + t1.tv_usec*1000); #endif break; } if (!parseActive) continue; - switch(stabptr->type(i)){ - case N_BCOMM: { + switch (stabptr->type(i)) { + case N_BCOMM: { // begin Fortran named common block string tmp = string(stabptr->name(i)); commonBlockName = &tmp; // find the variable for the common block //TODO? change this. findLocalVar will cause an infinite loop - std::vectorvars; - if(!associated_symtab->findSymbol(vars, - *commonBlockName, - Symbol::ST_OBJECT, - mangledName)) { - if(!associated_symtab->findSymbol(vars, - *commonBlockName, - Symbol::ST_OBJECT, - mangledName, - true)) + std::vector vars; + if (!associated_symtab->findSymbol(vars, + *commonBlockName, + Symbol::ST_OBJECT, + mangledName)) { + if (!associated_symtab->findSymbol(vars, + *commonBlockName, + Symbol::ST_OBJECT, + mangledName, + true)) commonBlockVar = NULL; else commonBlockVar = vars[0]; - } - else + } else commonBlockVar = vars[0]; if (!commonBlockVar) { // //bperr("unable to find variable %s\n", commonBlockName); @@ -4943,21 +4742,20 @@ void Object::parseStabTypes() } case N_ECOMM: { //copy this set of fields - if(!currentFunctionName) break; - if(!associated_symtab->findSymbol(bpfv, - *currentFunctionName, - Symbol::ST_FUNCTION, - mangledName)) { - if(!associated_symtab->findSymbol(bpfv, - *currentFunctionName, - Symbol::ST_FUNCTION, - mangledName, - true)){ + if (!currentFunctionName) break; + if (!associated_symtab->findSymbol(bpfv, + *currentFunctionName, + Symbol::ST_FUNCTION, + mangledName)) { + if (!associated_symtab->findSymbol(bpfv, + *currentFunctionName, + Symbol::ST_FUNCTION, + mangledName, + true)) { // //bperr("unable to locate current function %s\n", currentFunctionName->c_str()); - } - else{ + } else { Symbol *func = bpfv[0]; - commonBlock->endCommonBlock(func, (void *)commonBlockVar->getOffset()); + commonBlock->endCommonBlock(func, (void *) commonBlockVar->getOffset()); } } else { if (bpfv.size() > 1) { @@ -4966,7 +4764,7 @@ void Object::parseStabTypes() // __FILE__, __LINE__, bpfv.size(), currentFunctionName->c_str()); } Symbol *func = bpfv[0]; - commonBlock->endCommonBlock(func, (void *)commonBlockVar->getOffset()); + commonBlock->endCommonBlock(func, (void *) commonBlockVar->getOffset()); } //TODO?? size for local variables?? // // update size if needed @@ -4987,16 +4785,16 @@ void Object::parseStabTypes() case 0xc8: // position-independant external typedefs -- N_ESYM #ifdef TIMED_PARSE pss_count++; - gettimeofday(&t1, NULL); + gettimeofday(&t1, NULL); #endif if (stabptr->type(i) == N_FUN) symt_current_func = NULL; ptr = const_cast(stabptr->name(i)); - while (ptr[strlen(ptr)-1] == '\\') { + while (ptr[strlen(ptr) - 1] == '\\') { //ptr[strlen(ptr)-1] = '\0'; - ptr2 = const_cast(stabptr->name(i+1)); + ptr2 = const_cast(stabptr->name(i + 1)); ptr3 = (char *) malloc(strlen(ptr) + strlen(ptr2) + 1); strcpy(ptr3, ptr); - ptr3[strlen(ptr)-1] = '\0'; + ptr3[strlen(ptr) - 1] = '\0'; strcat(ptr3, ptr2); ptr = ptr3; i++; @@ -5006,9 +4804,9 @@ void Object::parseStabTypes() // may be nothing to parse - XXX jdd 5/13/99 if (parseCompilerType(this)) - temp = parseStabString(mod, mostRecentLinenum, (char *)ptr, stabptr->val(i), commonBlock); + temp = parseStabString(mod, mostRecentLinenum, (char *) ptr, stabptr->val(i), commonBlock); else - temp = parseStabString(mod, stabptr->desc(i), (char *)ptr, stabptr->val(i), commonBlock); + temp = parseStabString(mod, stabptr->desc(i), (char *) ptr, stabptr->val(i), commonBlock); if (temp.length()) { //Error parsing the stabstr, return should be \0 // //bperr( "Stab string parsing ERROR!! More to parse: %s\n", @@ -5017,8 +4815,8 @@ void Object::parseStabTypes() } #ifdef TIMED_PARSE gettimeofday(&t2, NULL); - pss_dur += (t2.tv_sec - t1.tv_sec)*1000.0 + (t2.tv_usec - t1.tv_usec)/1000.0; - // pss_dur += (t2.tv_sec/1000 + t2.tv_usec*1000) - (t1.tv_sec/1000 + t1.tv_usec*1000); + pss_dur += (t2.tv_sec - t1.tv_sec)*1000.0 + (t2.tv_usec - t1.tv_usec)/1000.0; + // pss_dur += (t2.tv_sec/1000 + t2.tv_usec*1000) - (t1.tv_sec/1000 + t1.tv_usec*1000); #endif break; default: @@ -5045,8 +4843,7 @@ void Object::parseStabTypes() } bool sort_dbg_map(const Object::DbgAddrConversion_t &a, - const Object::DbgAddrConversion_t &b) -{ + const Object::DbgAddrConversion_t &b) { return (a.dbg_offset < b.dbg_offset); } @@ -5080,40 +4877,32 @@ bool Object::convertDebugOffset(Offset off, Offset &new_off) const DbgAddrConversion_t &cur_d = DebugSectionMap[cur]; - if (off >= cur_d.dbg_offset && off < cur_d.dbg_offset+cur_d.dbg_size) { + if (off >= cur_d.dbg_offset && off < cur_d.dbg_offset + cur_d.dbg_size) { new_off = off - cur_d.dbg_offset + cur_d.orig_offset; return true; - } - else if (off > cur_d.dbg_offset) - { + } else if (off > cur_d.dbg_offset) { low = cur; - } - else if (off < cur_d.dbg_offset) - { + } else if (off < cur_d.dbg_offset) { hi = cur; } } } -void Object::insertPrereqLibrary(std::string libname) -{ +void Object::insertPrereqLibrary(std::string libname) { prereq_libs.insert(libname); } -bool Object::removePrereqLibrary(std::string libname) -{ +bool Object::removePrereqLibrary(std::string libname) { rmd_deps.push_back(libname); return true; } -std::vector &Object::libsRMd() -{ +std::vector &Object::libsRMd() { return rmd_deps; } -void Object::insertDynamicEntry(long name, long value) -{ +void Object::insertDynamicEntry(long name, long value) { new_dynamic_entries.push_back(std::pair(name, value)); } @@ -5129,11 +4918,11 @@ bool Object::parse_all_relocations(Elf_X &elf, Elf_X_Shdr *dynsym_scnp, Elf_X_Data dynsym_data, dynstr_data; Elf_X_Sym dynsym; const char *dynstr = NULL; - if( dynsym_scnp && dynstr_scnp ) { + if (dynsym_scnp && dynstr_scnp) { dynsym_offset = dynsym_scnp->sh_offset(); dynsym_data = dynsym_scnp->get_data(); dynstr_data = dynstr_scnp->get_data(); - if( !(dynsym_data.isValid() && dynstr_data.isValid()) ) { + if (!(dynsym_data.isValid() && dynstr_data.isValid())) { return false; } dynsym = dynsym_data.get_sym(); @@ -5144,18 +4933,18 @@ bool Object::parse_all_relocations(Elf_X &elf, Elf_X_Shdr *dynsym_scnp, Elf_X_Data symtab_data, strtab_data; Elf_X_Sym symtab; const char *strtab = NULL; - if( symtab_scnp && strtab_scnp) { + if (symtab_scnp && strtab_scnp) { symtab_offset = symtab_scnp->sh_offset(); symtab_data = symtab_scnp->get_data(); strtab_data = strtab_scnp->get_data(); - if( !(symtab_data.isValid() && strtab_data.isValid()) ) { + if (!(symtab_data.isValid() && strtab_data.isValid())) { return false; } symtab = symtab_data.get_sym(); strtab = strtab_data.get_string(); } - if( dynstr == NULL && strtab == NULL ) return false; + if (dynstr == NULL && strtab == NULL) return false; // Symbols are only truly uniquely idenfitied by their index in their // respective symbol table (this really applies to the symbols associated @@ -5165,43 +4954,46 @@ bool Object::parse_all_relocations(Elf_X &elf, Elf_X_Shdr *dynsym_scnp, dyn_hash_map dynsymByIndex; dyn_hash_map >::iterator symVec_it; - for(symVec_it = symbols_.begin(); symVec_it != symbols_.end(); ++symVec_it) { + for (symVec_it = symbols_.begin(); symVec_it != symbols_.end(); ++symVec_it) { std::vector::iterator sym_it; - for(sym_it = symVec_it->second.begin(); sym_it != symVec_it->second.end(); ++sym_it) { + for (sym_it = symVec_it->second.begin(); sym_it != symVec_it->second.end(); ++sym_it) { // Skip any symbols pointing to the undefined symbol entry - if( (*sym_it)->getIndex() == STN_UNDEF ) { + if ((*sym_it)->getIndex() == STN_UNDEF) { continue; } - if( (*sym_it)->tag() == Symbol::TAG_INTERNAL ) { + if ((*sym_it)->tag() == Symbol::TAG_INTERNAL) { continue; } - if( (*sym_it)->isDebug() ) { + if ((*sym_it)->isDebug()) { continue; } std::pair::iterator, bool> result; - if( (*sym_it)->isInDynSymtab() ) { + if ((*sym_it)->isInDynSymtab()) { result = dynsymByIndex.insert(std::make_pair((*sym_it)->getIndex(), (*sym_it))); - }else{ + } else { result = symtabByIndex.insert(std::make_pair((*sym_it)->getIndex(), (*sym_it))); } // A symbol should be uniquely identified by its index in the symbol table - if(!result.second) continue; + if (!result.second) continue; } } // Build mapping from section headers to Regions std::vector::iterator reg_it; dyn_hash_map shToRegion; - for(reg_it = regions_.begin(); reg_it != regions_.end(); ++reg_it) { + for (reg_it = regions_.begin(); reg_it != regions_.end(); ++reg_it) { std::pair::iterator, bool> result; result = shToRegion.insert(std::make_pair((*reg_it)->getRegionNumber(), (*reg_it))); } - for(unsigned i = 0; i < elf.e_shnum(); ++i) { - Elf_X_Shdr *shdr = allRegionHdrsByShndx[i]; - if( shdr->sh_type() != SHT_REL && shdr->sh_type() != SHT_RELA ) continue; + for (auto i = 0; + i < allRegionHdrsByShndx.size(); + ++i) { + auto shdr = allRegionHdrsByShndx[i]; + if(!shdr) continue; + if (shdr->sh_type() != SHT_REL && shdr->sh_type() != SHT_RELA) continue; Elf_X_Data reldata = shdr->get_data(); Elf_X_Rel rel = reldata.get_rel(); @@ -5211,7 +5003,7 @@ bool Object::parse_all_relocations(Elf_X &elf, Elf_X_Shdr *dynsym_scnp, // Apparently, relocation entries may not have associated symbols. - for(unsigned j = 0; j < (shdr->sh_size() / shdr->sh_entsize()); ++j) { + for (unsigned j = 0; j < (shdr->sh_size() / shdr->sh_entsize()); ++j) { // Relocation entry fields - need to be populated Offset relOff, addend = 0; @@ -5220,7 +5012,7 @@ bool Object::parse_all_relocations(Elf_X &elf, Elf_X_Shdr *dynsym_scnp, Region::RegionType regType; long symbol_index; - switch(shdr->sh_type()) { + switch (shdr->sh_type()) { case SHT_REL: relType = rel.R_TYPE(j); relOff = rel.r_offset(j); @@ -5241,24 +5033,24 @@ bool Object::parse_all_relocations(Elf_X &elf, Elf_X_Shdr *dynsym_scnp, // Determine which symbol table to use Symbol *sym = NULL; // Use dynstr to ensure we've initialized dynsym... - if( dynstr && curSymHdr->sh_offset() == dynsym_offset ) { - name = string( &dynstr[dynsym.st_name(symbol_index)] ); + if (dynstr && curSymHdr && curSymHdr->sh_offset() == dynsym_offset) { + name = string(&dynstr[dynsym.st_name(symbol_index)]); dyn_hash_map::iterator sym_it; sym_it = dynsymByIndex.find(symbol_index); - if( sym_it != dynsymByIndex.end() ) { + if (sym_it != dynsymByIndex.end()) { sym = sym_it->second; - if(sym->getType() == Symbol::ST_SECTION) { + if (sym->getType() == Symbol::ST_SECTION) { name = sym->getRegion()->getRegionName().c_str(); } } - }else if( strtab && curSymHdr->sh_offset() == symtab_offset ) { - name = string( &strtab[symtab.st_name(symbol_index)] ); + } else if (strtab && curSymHdr && curSymHdr->sh_offset() == symtab_offset) { + name = string(&strtab[symtab.st_name(symbol_index)]); dyn_hash_map::iterator sym_it; sym_it = symtabByIndex.find(symbol_index); - if( sym_it != symtabByIndex.end() ) { + if (sym_it != symtabByIndex.end()) { sym = sym_it->second; - if(sym->getType() == Symbol::ST_SECTION) { + if (sym->getType() == Symbol::ST_SECTION) { name = sym->getRegion()->getRegionName().c_str(); } } @@ -5267,12 +5059,11 @@ bool Object::parse_all_relocations(Elf_X &elf, Elf_X_Shdr *dynsym_scnp, Region *region = NULL; dyn_hash_map::iterator shToReg_it; shToReg_it = shToRegion.find(i); - if( shToReg_it != shToRegion.end() ) { + if (shToReg_it != shToRegion.end()) { region = shToReg_it->second; } - if(region != NULL) - { + if (region != NULL) { relocationEntry newrel(0, relOff, addend, name, sym, relType, regType); region->addRelocationEntry(newrel); // relocations are also stored with their targets @@ -5281,7 +5072,7 @@ bool Object::parse_all_relocations(Elf_X &elf, Elf_X_Shdr *dynsym_scnp, if (shdr->sh_info() != 0) { Region *targetRegion = NULL; shToReg_it = shToRegion.find(shdr->sh_info()); - if( shToReg_it != shToRegion.end() ) { + if (shToReg_it != shToRegion.end()) { targetRegion = shToReg_it->second; } assert(targetRegion != NULL); @@ -5295,44 +5086,37 @@ bool Object::parse_all_relocations(Elf_X &elf, Elf_X_Shdr *dynsym_scnp, return true; } -bool Region::isStandardCode() -{ +bool Region::isStandardCode() { return ((getRegionPermissions() == RP_RX || getRegionPermissions() == RP_RWX) && ((name_ == std::string(".text")) || (name_ == std::string(".init")) || (name_ == std::string(".fini")))); } -void Object::setTruncateLinePaths(bool value) -{ +void Object::setTruncateLinePaths(bool value) { truncateLineFilenames = value; } -bool Object::getTruncateLinePaths() -{ +bool Object::getTruncateLinePaths() { return truncateLineFilenames; } -Dyninst::Architecture Object::getArch() const -{ +Dyninst::Architecture Object::getArch() const { return elfHdr->getArch(); } -bool Object::getABIVersion(int &major, int &minor) const -{ - if (elfHdr->e_machine() == EM_PPC64 && elfHdr->e_flags() == 0x2) { - major = elfHdr->e_flags(); - minor = 0; - return true; - } - else { - return false; - } +bool Object::getABIVersion(int &major, int &minor) const { + if (elfHdr->e_machine() == EM_PPC64 && elfHdr->e_flags() == 0x2) { + major = elfHdr->e_flags(); + minor = 0; + return true; + } else { + return false; + } } -bool Object::isBigEndianDataEncoding() const -{ - return (elfHdr->e_endian() != 0); +bool Object::isBigEndianDataEncoding() const { + return (elfHdr->e_endian() != 0); } Offset Object::getTOCoffset(Offset off) const { @@ -5369,9 +5153,8 @@ void Object::getSegmentsSymReader(vector &segs) { } } -std::string Object::getFileName() const -{ - if(soname_) { +std::string Object::getFileName() const { + if (soname_) { return soname_; } diff --git a/symtabAPI/src/Object-elf.h b/symtabAPI/src/Object-elf.h index ca87665895..d8ab45f583 100644 --- a/symtabAPI/src/Object-elf.h +++ b/symtabAPI/src/Object-elf.h @@ -601,8 +601,8 @@ class Object : public AObject std::vector > new_dynamic_entries; private: const char* soname_; - -}; + + }; }//namespace SymtabAPI }//namespace Dyninst diff --git a/symtabAPI/src/Object-nt.h b/symtabAPI/src/Object-nt.h index 965236ff7f..7283d97d25 100644 --- a/symtabAPI/src/Object-nt.h +++ b/symtabAPI/src/Object-nt.h @@ -190,7 +190,9 @@ class Object : public AObject SYMTAB_EXPORT unsigned int GetTextSectionId( void ) const { return textSectionId;} SYMTAB_EXPORT PIMAGE_NT_HEADERS GetImageHeader( void ) const { return peHdr; } SYMTAB_EXPORT PVOID GetMapAddr( void ) const { return mf->base_addr(); } - SYMTAB_EXPORT Offset getEntryPoint( void ) const { if (peHdr) return peHdr->OptionalHeader.AddressOfEntryPoint; return 0;} + SYMTAB_EXPORT Offset getEntryPoint( void ) const { + if (peHdr) return peHdr->OptionalHeader.AddressOfEntryPoint; + return 0;} //+ desc.loadAddr(); } //laodAddr is always zero in our fake address space. // TODO. Change these later. SYMTAB_EXPORT Offset getLoadAddress() const { return imageBase; } diff --git a/symtabAPI/src/Symtab-edit.C b/symtabAPI/src/Symtab-edit.C index 23f2c937b7..49ad45f14f 100644 --- a/symtabAPI/src/Symtab-edit.C +++ b/symtabAPI/src/Symtab-edit.C @@ -142,11 +142,14 @@ bool Symtab::deleteSymbolFromIndices(Symbol *sym) { bool Symtab::deleteSymbol(Symbol *sym) { + pfq_rwlock_node_t me; + pfq_rwlock_write_lock(symbols_rwlock, me); if (sym->aggregate_) { sym->aggregate_->removeSymbol(sym); } - - return deleteSymbolFromIndices(sym); + bool result = deleteSymbolFromIndices(sym); + pfq_rwlock_write_unlock(symbols_rwlock, me); + return result; } bool Symtab::changeSymbolOffset(Symbol *sym, Offset newOffset) { @@ -258,11 +261,14 @@ bool Symtab::addSymbol(Symbol *newSym) demangleSymbol(newSym); } + pfq_rwlock_node_t me; + pfq_rwlock_write_lock(symbols_rwlock, me); // Add to appropriate indices addSymbolToIndices(newSym, false); // And to aggregates addSymbolToAggregates(newSym); + pfq_rwlock_write_unlock(symbols_rwlock, me); return true; } diff --git a/symtabAPI/src/Symtab-lookup.C b/symtabAPI/src/Symtab-lookup.C index 5ded0c4d43..df6d9a2a97 100644 --- a/symtabAPI/src/Symtab-lookup.C +++ b/symtabAPI/src/Symtab-lookup.C @@ -62,17 +62,23 @@ using namespace Dyninst; using namespace Dyninst::SymtabAPI; using namespace std; -extern SymtabError serr; +// extern thread_local SymtabError serr; bool regexEquiv( const std::string &str,const std::string &them, bool checkCase ); bool pattern_match( const char *p, const char *s, bool checkCase ); std::vector Symtab::findSymbolByOffset(Offset o) { - std::vector ret; + std::vector ret; + + pfq_rwlock_read_lock(symbols_rwlock); + indexed_symbols::index::type& syms_by_offset = everyDefinedSymbol.get(); std::copy(syms_by_offset.lower_bound(o), syms_by_offset.upper_bound(o), std::back_inserter(ret)); + + pfq_rwlock_read_unlock(symbols_rwlock); + return ret; /* //Symbol *s = NULL; @@ -86,6 +92,7 @@ bool Symtab::findSymbol(std::vector &ret, const std::string& name, Symbol::SymbolType sType, NameType nameType, bool isRegex, bool checkCase, bool includeUndefined) { + pfq_rwlock_read_lock(symbols_rwlock); unsigned old_size = ret.size(); @@ -182,10 +189,13 @@ bool Symtab::findSymbol(std::vector &ret, const std::string& name, matches.insert(*iter); } } + + pfq_rwlock_read_unlock(symbols_rwlock); + ret.insert(ret.end(), matches.begin(), matches.end()); if (ret.size() == old_size) { - serr = No_Such_Symbol; + setSymtabError(No_Such_Symbol); return false; } else { @@ -195,8 +205,13 @@ bool Symtab::findSymbol(std::vector &ret, const std::string& name, bool Symtab::getAllSymbols(std::vector &ret) { + pfq_rwlock_read_lock(symbols_rwlock); + std::copy(everyDefinedSymbol.begin(), everyDefinedSymbol.end(), back_inserter(ret)); std::copy(undefDynSyms.begin(), undefDynSyms.end(), back_inserter(ret)); + + pfq_rwlock_read_unlock(symbols_rwlock); + // ret = everyDefinedSymbol; @@ -207,10 +222,12 @@ bool Symtab::getAllSymbols(std::vector &ret) //for (it = temp.begin(); it != temp.end(); it++) // ret.push_back(*it); - if(ret.size() > 0) - return true; - serr = No_Such_Symbol; + if(ret.size() > 0) { + return true; + } else { + setSymtabError(No_Such_Symbol); return false; + } } bool Symtab::getAllSymbolsByType(std::vector &ret, Symbol::SymbolType sType) @@ -219,6 +236,9 @@ bool Symtab::getAllSymbolsByType(std::vector &ret, Symbol::SymbolType return getAllSymbols(ret); unsigned old_size = ret.size(); + + pfq_rwlock_read_lock(symbols_rwlock); + // Filter by the given type for (auto i = everyDefinedSymbol.begin(); i != everyDefinedSymbol.end(); i++) { if ((*i)->getType() == sType) @@ -235,11 +255,13 @@ bool Symtab::getAllSymbolsByType(std::vector &ret, Symbol::SymbolType } + pfq_rwlock_read_unlock(symbols_rwlock); + if (ret.size() > old_size) { return true; } else { - serr = No_Such_Symbol; + setSymtabError(No_Such_Symbol); return false; } } @@ -247,21 +269,33 @@ bool Symtab::getAllSymbolsByType(std::vector &ret, Symbol::SymbolType bool Symtab::getAllDefinedSymbols(std::vector &ret) { ret.clear(); + + pfq_rwlock_read_lock(symbols_rwlock); + std::copy(everyDefinedSymbol.begin(), everyDefinedSymbol.end(), back_inserter(ret)); + + pfq_rwlock_read_unlock(symbols_rwlock); + // ret = everyDefinedSymbol; if(ret.size() > 0) return true; - serr = No_Such_Symbol; + setSymtabError(No_Such_Symbol); return false; } bool Symtab::getAllUndefinedSymbols(std::vector &ret){ unsigned size = ret.size(); + + pfq_rwlock_read_lock(symbols_rwlock); + ret.insert(ret.end(), undefDynSyms.begin(), undefDynSyms.end()); + + pfq_rwlock_read_unlock(symbols_rwlock); + if(ret.size()>size) return true; - serr = No_Such_Symbol; + setSymtabError(No_Such_Symbol); return false; } @@ -277,7 +311,7 @@ bool Symtab::findFuncByEntryOffset(Function *&ret, const Offset entry) ret = funcsByOffset[entry]; return true; } - serr = No_Such_Function; + setSymtabError(No_Such_Symbol); return false; } @@ -333,7 +367,7 @@ bool Symtab::findVariableByOffset(Variable *&ret, const Offset offset) { ret = varsByOffset[offset]; return true; } - serr = No_Such_Variable; + setSymtabError(No_Such_Symbol); return false; } @@ -378,7 +412,7 @@ bool Symtab::getAllModules(std::vector &ret) return true; } - serr = No_Such_Module; + setSymtabError(No_Such_Symbol); return false; } @@ -429,7 +463,7 @@ bool Symtab::findModuleByName(Module *&ret, const std::string name) return true; } - serr = No_Such_Module; + setSymtabError(No_Such_Module); ret = NULL; return false; } @@ -556,7 +590,7 @@ bool Symtab::findRegionByEntry(Region *&ret, const Offset offset) ret = regionsByEntryAddr[offset]; return true; } - serr = No_Such_Region; + setSymtabError(No_Such_Region); return false; } @@ -600,7 +634,7 @@ bool Symtab::findRegion(Region *&ret, const std::string secName) return true; } } - serr = No_Such_Region; + setSymtabError(No_Such_Region); return false; } @@ -630,14 +664,14 @@ bool Symtab::findRegion(Region *&ret, const Offset addr, const unsigned long siz } - serr = Multiple_Region_Matches; + setSymtabError(Multiple_Region_Matches); return false; } ret = regions_[index]; } } if (ret) return true; - serr = No_Such_Region; + setSymtabError(No_Such_Region); return false; } diff --git a/symtabAPI/src/Symtab.C b/symtabAPI/src/Symtab.C index 680efb8093..123aac8090 100644 --- a/symtabAPI/src/Symtab.C +++ b/symtabAPI/src/Symtab.C @@ -36,6 +36,8 @@ #include #include +#include "common/h/race-detector-annotations.h" + #include "common/src/Timer.h" #include "common/src/debugOstream.h" #include "common/src/serialize.h" @@ -54,6 +56,7 @@ #include "symtabAPI/src/Object.h" + #if !defined(os_windows) #include #else @@ -91,19 +94,25 @@ void symtab_log_perror(const char *msg) }; -SymtabError serr; +static thread_local SymtabError serr; std::vector Symtab::allSymtabs; +#define fake_symtab_error_lock race_detector_fake_lock(Symtab::getLastSymtabError) SymtabError Symtab::getLastSymtabError() { - return serr; + race_detector_fake_lock_acquire(fake_symtab_error_lock); + SymtabError last = serr; + race_detector_fake_lock_release(fake_symtab_error_lock); + return last; } -void setSymtabError(SymtabError new_err) +void Symtab::setSymtabError(SymtabError new_err) { + race_detector_fake_lock_acquire(fake_symtab_error_lock); serr = new_err; + race_detector_fake_lock_release(fake_symtab_error_lock); } std::string Symtab::printError(SymtabError serr) @@ -395,6 +404,7 @@ SYMTAB_EXPORT Symtab::Symtab(MappedFile *mf_) : obj_private(NULL), _ref_cnt(1) { + pfq_rwlock_init(symbols_rwlock); init_debug_symtabAPI(); #if defined(os_vxworks) @@ -437,7 +447,8 @@ SYMTAB_EXPORT Symtab::Symtab() : mod_lookup_(NULL), obj_private(NULL), _ref_cnt(1) -{ +{ + pfq_rwlock_init(symbols_rwlock); init_debug_symtabAPI(); create_printf("%s[%d]: Created symtab via default constructor\n", FILE__, __LINE__); } @@ -1236,7 +1247,8 @@ Symtab::Symtab(std::string filename, bool defensive_bin, bool &err) : obj_private(NULL), _ref_cnt(1) { - init_debug_symtabAPI(); + pfq_rwlock_init(symbols_rwlock); + init_debug_symtabAPI(); // Initialize error parameter err = false; @@ -1312,6 +1324,7 @@ Symtab::Symtab(unsigned char *mem_image, size_t image_size, obj_private(NULL), _ref_cnt(1) { + pfq_rwlock_init(symbols_rwlock); // Initialize error parameter err = false; @@ -1401,7 +1414,7 @@ bool Symtab::extractInfo(Object *linkedFile) if( object_type_ != obj_RelocatableFile || linkedFile->code_ptr() == 0) { - serr = Obj_Parsing; + setSymtabError(Obj_Parsing); return false; } } @@ -1507,13 +1520,13 @@ bool Symtab::extractInfo(Object *linkedFile) if (!extractSymbolsFromFile(linkedFile, raw_syms)) { - serr = Syms_To_Functions; + setSymtabError(Syms_To_Functions); return false; } if (!fixSymModules(raw_syms)) { - serr = Syms_To_Functions; + setSymtabError(Syms_To_Functions); return false; } Object *obj = getObject(); @@ -1537,14 +1550,14 @@ bool Symtab::extractInfo(Object *linkedFile) if (!createIndices(raw_syms, false)) { - serr = Syms_To_Functions; + setSymtabError(Syms_To_Functions); return false; } if (!createAggregates()) { - serr = Syms_To_Functions; + setSymtabError(Syms_To_Functions); return false; } @@ -1604,6 +1617,7 @@ Symtab::Symtab(const Symtab& obj) : obj_private(NULL), _ref_cnt(1) { + pfq_rwlock_init(symbols_rwlock); create_printf("%s[%d]: Creating symtab 0x%p from symtab 0x%p\n", FILE__, __LINE__, this, &obj); unsigned i; diff --git a/symtabAPI/src/Type-mem.h b/symtabAPI/src/Type-mem.h index a3beca61f8..4f671a45df 100644 --- a/symtabAPI/src/Type-mem.h +++ b/symtabAPI/src/Type-mem.h @@ -31,12 +31,15 @@ #if !defined(TYPE_MEM_H_) #define TYPE_MEM_H_ +#include + #include "symtabAPI/h/Type.h" #include "boost/static_assert.hpp" +#include namespace Dyninst { namespace SymtabAPI { - extern std::map type_memory; + extern tbb::concurrent_hash_map type_memory; } } @@ -47,15 +50,16 @@ template T *upgradePlaceholder(Type *placeholder, T *new_type) { void *mem = (void *) placeholder; - assert(type_memory.count(mem)); - size_t size = type_memory[mem]; - + tbb::concurrent_hash_map::accessor a; + assert(type_memory.find(a, placeholder)); + size_t size = a->second; assert(sizeof(T) < size); memset(mem, 0, size); T *ret = new(mem) T(); assert(mem == (void *) ret); *ret = *new_type; + race_detector_forget_access_history(ret, sizeof(T)); return ret; } @@ -67,15 +71,18 @@ T* typeCollection::addOrUpdateType(T *type) //then a caller to this function is likely using 'Type'. Change //this to a more specific call, e.g. typeFunction instead of Type BOOST_STATIC_ASSERT(sizeof(T) != sizeof(Type)); + boost::lock_guard g(placeholder_mutex); Type *existingType = findTypeLocal(type->getID()); + tbb::concurrent_hash_map::accessor id_accessor; + tbb::concurrent_hash_map::accessor name_accessor; if (!existingType) { if ( type->getName() != "" ) { - typesByName[ type->getName() ] = type; + typesByName.insert(name_accessor, std::make_pair(type->getName(), type)); } - typesByID[ type->getID() ] = type; + typesByID.insert(id_accessor, std::make_pair(type->getID(), type)); type->incrRefCount(); return type; } @@ -103,18 +110,20 @@ T* typeCollection::addOrUpdateType(T *type) /* The type may have gained a name. */ if ( existingType->getName() != "") { - if (typesByName.find(existingType->getName()) != typesByName.end()) + tbb::concurrent_hash_map::accessor a; + bool found = typesByName.find(a, existingType->getName()); + if (found) { - if (typesByName[ existingType->getName() ] != existingType) + if (a->second != existingType) { - typesByName[ existingType->getName() ]->decrRefCount(); - typesByName[ existingType->getName() ] = existingType; + a->second->decrRefCount(); + a->second = existingType; existingType->incrRefCount(); } } else { - typesByName[ existingType->getName() ] = existingType; + typesByName.insert(a, std::make_pair(existingType->getName(), existingType)); existingType->incrRefCount(); } } diff --git a/symtabAPI/src/Type.C b/symtabAPI/src/Type.C index 4943176c64..5da33561a2 100644 --- a/symtabAPI/src/Type.C +++ b/symtabAPI/src/Type.C @@ -42,6 +42,7 @@ #include "Type-mem.h" #include +#include using namespace Dyninst; using namespace Dyninst::SymtabAPI; @@ -58,7 +59,7 @@ typeId_t Type::USER_TYPE_ID = -10000; namespace Dyninst { namespace SymtabAPI { - std::map type_memory; + tbb::concurrent_hash_map type_memory; } } @@ -105,9 +106,11 @@ Type *Type::createPlaceholder(typeId_t ID, std::string name) void *mem = malloc(max_size); assert(mem); - type_memory[mem] = max_size; + tbb::concurrent_hash_map::accessor a; + type_memory.insert(a, make_pair(mem, max_size)); Type *placeholder_type = new(mem) Type(name, ID, dataUnknownType); + race_detector_forget_access_history(placeholder_type, max_size); return placeholder_type; } @@ -318,7 +321,7 @@ typeEnum::typeEnum(std::string name) size_ = sizeof(int); } -typeEnum *typeEnum::create(std::string &name, std::vector< std::pair *> &constants, Symtab *obj) +typeEnum *typeEnum::create(std::string &name, tbb::concurrent_vector< std::pair *> &constants, Symtab *obj) { typeEnum *typ = new typeEnum(name); for(unsigned i=0; i &constNames, Symtab *obj) +typeEnum *typeEnum::create(std::string &name, tbb::concurrent_vector &constNames, Symtab *obj) { typeEnum *typ = new typeEnum(name); for(unsigned i=0; i &constNam return typ; } -std::vector > &typeEnum::getConstants() +tbb::concurrent_vector > &typeEnum::getConstants() { return consts; } @@ -369,8 +372,8 @@ bool typeEnum::isCompatible(Type *otype) if ( (name_ != "") &&( oEnumtype->name_ != "") && (name_ == oEnumtype->name_) && (ID_ == oEnumtype->ID_)) return true; - const std::vector< std::pair > &fields1 = this->getConstants(); - const std::vector< std::pair > &fields2 = oEnumtype->getConstants(); + const tbb::concurrent_vector< std::pair > &fields1 = this->getConstants(); + const tbb::concurrent_vector< std::pair > &fields2 = oEnumtype->getConstants(); if ( fields1.size() != fields2.size()) { @@ -505,7 +508,7 @@ typeFunction::typeFunction(Type *retType, std::string name) : retType->incrRefCount(); } -typeFunction *typeFunction::create(std::string &name, Type *retType, std::vector ¶mTypes, Symtab *obj) +typeFunction *typeFunction::create(std::string &name, Type *retType, tbb::concurrent_vector ¶mTypes, Symtab *obj) { typeFunction *type = new typeFunction(retType, name); for(unsigned i=0;i &typeFunction::getParams(){ +tbb::concurrent_vector &typeFunction::getParams(){ return params_; } @@ -553,9 +556,9 @@ bool typeFunction::isCompatible(Type *otype) { if (retType_ != oFunctiontype->retType_) return false; - std::vector fields1 = this->getParams(); - std::vector fields2 = oFunctiontype->getParams(); - //const std::vector * fields2 = (std::vector *) &(otype->fieldList); + tbb::concurrent_vector fields1 = this->getParams(); + tbb::concurrent_vector fields2 = oFunctiontype->getParams(); + //const tbb::concurrent_vector * fields2 = (tbb::concurrent_vector *) &(otype->fieldList); if (fields1.size() != fields2.size()) { //reportError(BPatchWarning, 112, @@ -819,7 +822,7 @@ typeStruct::typeStruct(std::string name) : { } -typeStruct *typeStruct::create(std::string &name, std::vector< std::pair *> &flds, +typeStruct *typeStruct::create(std::string &name, tbb::concurrent_vector< std::pair *> &flds, Symtab *obj) { int offset = 0; @@ -838,7 +841,7 @@ typeStruct *typeStruct::create(std::string &name, std::vector< std::pair &flds, Symtab *obj) +typeStruct *typeStruct::create(std::string &name, tbb::concurrent_vector &flds, Symtab *obj) { typeStruct *typ = new typeStruct(name); for(unsigned i=0;ifieldList; if (otherstruct->derivedFieldList) { - derivedFieldList = new std::vector; + derivedFieldList = new tbb::concurrent_vector; *derivedFieldList = *otherstruct->derivedFieldList; } } @@ -912,9 +915,9 @@ bool typeStruct::isCompatible(Type *otype) if (oStructtype == NULL) return false; - const std::vector * fields1 = this->getComponents(); - const std::vector * fields2 = oStructtype->getComponents(); - //const std::vector * fields2 = (std::vector *) &(otype->fieldList); + const tbb::concurrent_vector * fields1 = this->getComponents(); + const tbb::concurrent_vector * fields2 = oStructtype->getComponents(); + //const tbb::concurrent_vector * fields2 = (tbb::concurrent_vector *) &(otype->fieldList); if (fields1->size() != fields2->size()) { //reportError(BPatchWarning, 112, @@ -959,7 +962,7 @@ typeUnion::typeUnion(std::string name) : { } -typeUnion *typeUnion::create(std::string &name, std::vector< std::pair *> &flds, +typeUnion *typeUnion::create(std::string &name, tbb::concurrent_vector< std::pair *> &flds, Symtab *obj) { typeUnion *typ = new typeUnion(name); @@ -973,7 +976,7 @@ typeUnion *typeUnion::create(std::string &name, std::vector< std::pair &flds, Symtab *obj) +typeUnion *typeUnion::create(std::string &name, tbb::concurrent_vector &flds, Symtab *obj) { typeUnion *typ = new typeUnion(name); for(unsigned i=0;ifieldList; if (otherunion->derivedFieldList) { - derivedFieldList = new std::vector; + derivedFieldList = new tbb::concurrent_vector; *derivedFieldList = *otherunion->derivedFieldList; } } @@ -1047,9 +1050,9 @@ bool typeUnion::isCompatible(Type *otype) { if (oUniontype == NULL) return false; - const std::vector * fields1 = this->getComponents(); - const std::vector * fields2 = oUniontype->getComponents(); - //const std::vector * fields2 = (std::vector *) &(otype->fieldList); + const tbb::concurrent_vector * fields1 = this->getComponents(); + const tbb::concurrent_vector * fields2 = oUniontype->getComponents(); + //const tbb::concurrent_vector * fields2 = (tbb::concurrent_vector *) &(otype->fieldList); if (fields1->size() != fields2->size()) { //reportError(BPatchWarning, 112, @@ -1170,10 +1173,7 @@ typeCommon::typeCommon(std::string name) : void typeCommon::beginCommonBlock() { - std::vector emptyList; - - // null out field list - fieldList = emptyList; + fieldList.clear(); } void typeCommon::endCommonBlock(Symbol *func, void *baseAddr) @@ -1230,9 +1230,9 @@ void typeCommon::fixupUnknowns(Module *module) { cblocks[i]->fixupUnknowns(module); } -std::vector *typeCommon::getCblocks() const +tbb::concurrent_vector *typeCommon::getCblocks() const { - return const_cast*>(&cblocks); + return const_cast*>(&cblocks); } /* @@ -1435,16 +1435,16 @@ bool fieldListType::operator==(const Type &otype) const } } -std::vector * fieldListType::getComponents() const +tbb::concurrent_vector * fieldListType::getComponents() const { if (derivedFieldList == NULL) const_cast(this)->fixupComponents(); return derivedFieldList; } -std::vector *fieldListType::getFields() const +tbb::concurrent_vector *fieldListType::getFields() const { - return const_cast *>(&fieldList); + return const_cast *>(&fieldList); } void fieldListType::fixupComponents() @@ -1452,7 +1452,7 @@ void fieldListType::fixupComponents() // bperr "Getting the %d components of '%s' at 0x%x\n", fieldList.size(), getName(), this ); /* Iterate over the field list. Recursively (replace) '{superclass}' with the superclass's non-private fields. */ - derivedFieldList = new std::vector< Field * >(); + derivedFieldList = new tbb::concurrent_vector< Field * >(); for( unsigned int i = 0; i < fieldList.size(); i++ ) { Field * currentField = fieldList[i]; // bperr( "Considering field '%s'\n", currentField->getName() ); @@ -1463,7 +1463,7 @@ void fieldListType::fixupComponents() // bperr( "Found superclass '%s'...\n", currentField->getType()->getName() ); fieldListInterface *superclass = dynamic_cast(currentField->getType()); assert (superclass != NULL); - const std::vector * superClassFields = superclass->getComponents(); + const tbb::concurrent_vector * superClassFields = superclass->getComponents(); // bperr( "Superclass has %d components.\n", superClassFields->size() ); /* FIXME: do we also need to consider the visibility of the superclass itself? */ /* FIXME: visibility can also be described on a per-name basis in the @@ -1520,7 +1520,11 @@ void fieldListType::addField(unsigned num, std::string fieldname, Type *type, in if(num >fieldList.size()+1) num = fieldList.size(); // Add field to list of struct/union fields - fieldList.insert(fieldList.begin()+num, newField); + tbb::concurrent_vector newFieldList; + std::copy(fieldList.begin(), fieldList.begin() + num, back_inserter(newFieldList)); + newFieldList.push_back(newField); + std::copy(fieldList.begin() + num, fieldList.end(), back_inserter(newFieldList)); + std::swap(fieldList, newFieldList); // API defined structs/union's size are defined on the fly. postFieldInsert(type->getSize()); @@ -1533,7 +1537,11 @@ void fieldListType::addField(unsigned num, Field *fld) if(num >fieldList.size()+1) num = fieldList.size(); // Add field to list of struct/union fields - fieldList.insert(fieldList.begin()+num, newField); + tbb::concurrent_vector newFieldList; + std::copy(fieldList.begin(), fieldList.begin() + num, back_inserter(newFieldList)); + newFieldList.push_back(newField); + std::copy(fieldList.begin() + num, fieldList.end(), back_inserter(newFieldList)); + std::swap(fieldList, newFieldList); // API defined structs/union's size are defined on the fly. postFieldInsert(newField->getSize()); @@ -1772,12 +1780,12 @@ void CBlock::fixupUnknowns(Module *module) } } -std::vector *CBlock::getComponents() +tbb::concurrent_vector *CBlock::getComponents() { return &fieldList; } -std::vector *CBlock::getFunctions() +tbb::concurrent_vector *CBlock::getFunctions() { return &functions; } @@ -1908,7 +1916,7 @@ void typeFunction::serialize_specific(SerializerBase *sb) THROW_SPEC(SerializerE int t_id = retType_ ? retType_->getID() : 0xdeadbeef; int t_dc = (int) (retType_ ? retType_->getDataClass() : dataUnknownType); - std::vector > ptypes; + tbb::concurrent_vector > ptypes; for (unsigned int i = 0; i < params_.size(); ++i) ptypes.push_back(std::pair(params_[i]->getID(), params_[i]->getDataClass())); @@ -2018,7 +2026,7 @@ void fieldListType::serialize_fieldlist(SerializerBase *sb, const char *tag) THR // TODO: this dereference should work transparently // without requiring a manual realloc here if (sb->isInput()) - derivedFieldList = new std::vector(); + derivedFieldList = new tbb::concurrent_vector(); gtranslate(sb, *derivedFieldList, "derivedFieldList"); } ifxml_end_element(sb, tag); @@ -2073,7 +2081,7 @@ Serializable *Field::serialize_impl(SerializerBase *sb, const char *tag) THROW_S Serializable * CBlock::serialize_impl(SerializerBase *sb, const char *tag) THROW_SPEC(SerializerError) { - std::vector f_offsets; + tbb::concurrent_vector f_offsets; for (unsigned int i = 0; i < functions.size(); ++i) f_offsets.push_back(functions[i]->getOffset()); diff --git a/symtabAPI/src/dwarfWalker.C b/symtabAPI/src/dwarfWalker.C index f7b447d60a..2d1ec18ccb 100644 --- a/symtabAPI/src/dwarfWalker.C +++ b/symtabAPI/src/dwarfWalker.C @@ -45,6 +45,11 @@ #include #include "elfutils/libdw.h" #include +#include + +#ifdef ENABLE_RACE_DETECTION +#include +#endif using namespace Dyninst; using namespace SymtabAPI; @@ -127,6 +132,7 @@ bool DwarfWalker::parse() { /* Iterate over the compilation-unit headers for .debug_types. */ uint64_t type_signaturep; + std::vector module_dies; for(Dwarf_Off cu_off = 0; dwarf_next_unit(dbg(), cu_off, &next_cu_header, &cu_header_length, NULL, &abbrev_offset, &addr_size, &offset_size, @@ -136,16 +142,16 @@ bool DwarfWalker::parse() { if(!dwarf_offdie_types(dbg(), cu_off + cu_header_length, ¤t_cu_die)) continue; +#if 0 push(); -// DwarfWalker mod_walker(*this); -// pop(); bool ret = parseModule(false, fixUnknownMod); pop(); - if(!ret) { - return false; - } + if(!ret) return false; +#endif + module_dies.push_back(current_cu_die); compile_offset = next_cu_header; } + /* Iterate over the compilation-unit headers for .debug_info. */ for(Dwarf_Off cu_off = 0; dwarf_nextcu(dbg(), cu_off, &next_cu_header, &cu_header_length, @@ -155,16 +161,35 @@ bool DwarfWalker::parse() { if(!dwarf_offdie(dbg(), cu_off + cu_header_length, ¤t_cu_die)) continue; +#if 0 push(); -// DwarfWalker mod_walker(*this); -// pop(); bool ret = parseModule(true, fixUnknownMod); pop(); - if(!ret) { - return false; - } + if(!ret) return false; +#endif + module_dies.push_back(current_cu_die); compile_offset = next_cu_header; } + +// std::for_each(module_dies.begin(), module_dies.end(), [&](Dwarf_Die cur) { +#ifdef ENABLE_RACE_DETECTION + cilk_for +#else +//#pragma omp parallel for + for +#endif + (unsigned int i = 0; i < module_dies.size(); i++) { + Dwarf_Die cur = module_dies[i]; + int local_fd = open(symtab()->file().c_str(), O_RDONLY); + Dwarf* temp_dwarf = dwarf_begin(local_fd, DWARF_C_READ); + DwarfWalker w(symtab_, temp_dwarf); + w.push(); + bool ok = w.parseModule(cur, fixUnknownMod); + w.pop(); + dwarf_end(temp_dwarf); + close(local_fd); + } + if (!fixUnknownMod) return true; @@ -195,18 +220,7 @@ bool DwarfWalker::parse() { return true; } -bool DwarfWalker::parseModule(bool /*is_info*/, Module *&fixUnknownMod) { - /* Obtain the module DIE. */ - Dwarf_Die moduleDIE = current_cu_die; - /*Dwarf_Die * cu_die_p = 0; - if(is_info){ - cu_die_p = dwarf_offdie(dbg(), compile_offset, &moduleDIE); - }else{ - cu_die_p = dwarf_offdie_types(dbg(), compile_offset, &moduleDIE); - } - if (cu_die_p == 0) { - return false; - }*/ +bool DwarfWalker::parseModule(Dwarf_Die moduleDIE, Module *&fixUnknownMod) { /* Make sure we've got the right one. */ Dwarf_Half moduleTag; @@ -245,10 +259,14 @@ bool DwarfWalker::parseModule(bool /*is_info*/, Module *&fixUnknownMod) { // These may not be set. Address tempModLow, tempModHigh; modLow = modHigh = 0; - if (findConstant(DW_AT_low_pc, tempModLow, entry(), dbg())) { + Dwarf_Die e; + bool found_entry = dwarf_offdie(dbg(),offset(), &e); + if(!found_entry) return false; + + if (findConstant(DW_AT_low_pc, tempModLow, &e, dbg())) { modLow = convertDebugOffset(tempModLow); } - if (findConstant(DW_AT_high_pc, tempModHigh, entry(), dbg())) { + if (findConstant(DW_AT_high_pc, tempModHigh, &e, dbg())) { modHigh = convertDebugOffset(tempModHigh); } @@ -499,7 +517,7 @@ bool DwarfWalker::parseCallsite() return false; Dyninst::Offset inline_line; - result = findConstant(DW_AT_call_line, inline_line, e, dbg()); + result = findConstant(DW_AT_call_line, inline_line, &e, dbg()); if (!result) return false; @@ -1838,9 +1856,10 @@ bool DwarfWalker::findString(Dwarf_Half attr, Dwarf_Half form; Dwarf_Attribute strattr; + Dwarf_Die e = entry(); if (attr == DW_AT_call_file || attr == DW_AT_decl_file) { unsigned long line_index; - bool result = findConstant(attr, line_index, entry(), dbg()); + bool result = findConstant(attr, line_index, &e, dbg()); if (!result) return false; if (line_index >= mod()->getStrings()->size()) { @@ -1852,7 +1871,6 @@ bool DwarfWalker::findString(Dwarf_Half attr, str = (*srcFiles())[line_index].str; return true; } - Dwarf_Die e = entry(); auto ret_p = dwarf_attr(&e, attr, &strattr); if(!ret_p) return false; form = dwarf_whatform(&strattr); @@ -1890,13 +1908,13 @@ bool DwarfWalker::findString(Dwarf_Half attr, return result; } -bool DwarfWalker::findConstant(Dwarf_Half attr, Address &value, Dwarf_Die entry, Dwarf * /*dbg*/) { - bool has = dwarf_hasattr(&entry, attr); +bool DwarfWalker::findConstant(Dwarf_Half attr, Address &value, Dwarf_Die *entry, Dwarf * /*dbg*/) { + bool has = dwarf_hasattr(entry, attr); if (!has) return false; // Get the attribute Dwarf_Attribute d_attr; - auto ret_p = dwarf_attr(&entry, attr, &d_attr); + auto ret_p = dwarf_attr(entry, attr, &d_attr); if(!ret_p) return false; // Get the form (datatype) for this particular attribute @@ -2526,14 +2544,12 @@ void DwarfParseActions::clearFunc() { typeId_t DwarfWalker::get_type_id(Dwarf_Off offset, bool is_info) { - static typeId_t next_type_id = 0; + static unsigned int next_type_id = 0; auto& type_ids = is_info ? info_type_ids_ : types_type_ids_; auto it = type_ids.find(offset); if (it != type_ids.end()) return it->second; -// size_t size = info_type_ids_.size() + types_type_ids_.size(); -// typeId_t id = (typeId_t) size + 1; type_ids[offset] = ++next_type_id; return next_type_id; } diff --git a/symtabAPI/src/dwarfWalker.h b/symtabAPI/src/dwarfWalker.h index fdcd2f91f5..cad23479c4 100644 --- a/symtabAPI/src/dwarfWalker.h +++ b/symtabAPI/src/dwarfWalker.h @@ -38,7 +38,7 @@ class Type; class DwarfParseActions { protected: - Dwarf* dbg() { return dbg_; } + Dwarf* dbg() { return dbg_; } Module *& mod() { return mod_; } @@ -69,9 +69,8 @@ class DwarfParseActions { fieldListType *enclosure; bool parseSibling; bool parseChild; - Dwarf_Die entry; - Dwarf_Die specEntry; - Dwarf_Die abstractEntry; + Dwarf_Off specEntry; + Dwarf_Off abstractEntry; Dwarf_Off offset; unsigned int tag; Address base; @@ -89,7 +88,6 @@ class DwarfParseActions { enclosure(o.enclosure), parseSibling(o.parseSibling), parseChild(o.parseChild), - entry(o.entry), specEntry(o.specEntry), abstractEntry(o.specEntry), offset(o.offset), @@ -113,9 +111,21 @@ class DwarfParseActions { fieldListType *curEnclosure() { return c.top().enclosure; } bool parseSibling() { return c.top().parseSibling; } bool parseChild() { return c.top().parseChild; } - Dwarf_Die entry() { return c.top().entry; } - Dwarf_Die specEntry() { return c.top().specEntry; } - Dwarf_Die abstractEntry() { return c.top().abstractEntry; } + Dwarf_Die entry() { + Dwarf_Die ret; + dwarf_offdie(dbg(), c.top().offset, &ret); + return ret; + } + Dwarf_Die specEntry() { + Dwarf_Die ret; + dwarf_offdie(dbg(), c.top().specEntry, &ret); + return ret; + } + Dwarf_Die abstractEntry() { + Dwarf_Die ret; + dwarf_offdie(dbg(), c.top().abstractEntry, &ret); + return ret; + } Dwarf_Off offset() { return c.top().offset; } unsigned int tag() { return c.top().tag; } Address base() { return c.top().base; } @@ -127,9 +137,9 @@ class DwarfParseActions { void setEnclosure(fieldListType *f) { c.top().enclosure = f; } void setParseSibling(bool p) { c.top().parseSibling = p; } void setParseChild(bool p) { c.top().parseChild = p; } - virtual void setEntry(Dwarf_Die e) { c.top().entry = e; } - void setSpecEntry(Dwarf_Die e) { c.top().specEntry = e; } - void setAbstractEntry(Dwarf_Die e) { c.top().abstractEntry = e; } + virtual void setEntry(Dwarf_Die e) { c.top().offset = dwarf_dieoffset(&e); } + void setSpecEntry(Dwarf_Die e) { c.top().specEntry = dwarf_dieoffset(&e); } + void setAbstractEntry(Dwarf_Die e) { c.top().abstractEntry = dwarf_dieoffset(&e); } void setOffset(Dwarf_Off o) { c.top().offset = o; } void setTag(unsigned int t) { c.top().tag = t; } void setBase(Address a) { c.top().base = a; } @@ -224,7 +234,7 @@ class DwarfWalker : public DwarfParseActions { bool parse(); // Takes current debug state as represented by dbg_; - bool parseModule(bool is_info, Module *&fixUnknownMod); + bool parseModule(Dwarf_Die is_info, Module *&fixUnknownMod); // Non-recursive version of parse // A Context must be provided as an _input_ to this function, @@ -331,7 +341,7 @@ class DwarfWalker : public DwarfParseActions { Dwarf_Half &form); bool findString(Dwarf_Half attr, std::string &str); public: - static bool findConstant(Dwarf_Half attr, Address &value, Dwarf_Die entry, Dwarf* dbg); + static bool findConstant(Dwarf_Half attr, Address &value, Dwarf_Die *entry, Dwarf *dbg); static bool findConstantWithForm(Dwarf_Attribute &attr, Dwarf_Half form, Address &value); static std::vector getDieRanges(Dwarf* dbg, Dwarf_Die die, Offset base); diff --git a/symtabAPI/src/emitElf.C b/symtabAPI/src/emitElf.C index 0bc30b100c..70783c31de 100644 --- a/symtabAPI/src/emitElf.C +++ b/symtabAPI/src/emitElf.C @@ -51,7 +51,6 @@ using namespace Dyninst; using namespace Dyninst::SymtabAPI; using namespace std; -extern void setSymtabError(SymtabError new_err); unsigned int elfHash(const char *name) { unsigned int h = 0, g; @@ -1768,7 +1767,7 @@ bool emitElf::createSymbolTables(set &allSymbols) { std::string("Failed to link to static library code into the binary: ") + emitElfStatic::printStaticLinkError(err) + std::string(" = ") + errMsg; - setSymtabError(Emit_Error); + Symtab::setSymtabError(Emit_Error); symtab_log_perror(linkStaticError.c_str()); return false; } diff --git a/symtabAPI/src/parseDwarf.C b/symtabAPI/src/parseDwarf.C index d0bbf5aca8..ec5d553fbe 100644 --- a/symtabAPI/src/parseDwarf.C +++ b/symtabAPI/src/parseDwarf.C @@ -78,7 +78,6 @@ int dwarf_get_fde_info_for_cfa_reg3( using namespace Dyninst; using namespace Dyninst::SymtabAPI; -void setSymtabError(SymtabError new_err); std::string convertCharToString(char *ptr) { @@ -115,7 +114,7 @@ bool Object::getRegValueAtFrame(Address pc, dwarf->frame_dbg(); assert(dwarf->frameParser()); result = dwarf->frameParser()->getRegValueAtFrame(pc, reg, reg_result, reader, frame_error); - setSymtabError((SymtabError) frame_error); + Symtab::setSymtabError((SymtabError) frame_error); return result; } diff --git a/symtabAPI/src/parseStab.C b/symtabAPI/src/parseStab.C index 449099eec6..4c47d35acf 100644 --- a/symtabAPI/src/parseStab.C +++ b/symtabAPI/src/parseStab.C @@ -741,8 +741,7 @@ std::string Dyninst::SymtabAPI::parseStabString(Module *mod, int linenum, char * */ bool found = false; - const std::vector *fields; - fields = commonBlock->getFields(); + auto fields = commonBlock->getFields(); if (fields) { for (unsigned int i=0; i < fields->size(); i++)