├── .gitmodules ├── .gitignore ├── test ├── CMakeLists.txt └── main.cpp ├── include ├── vmu.hpp └── vmu │ ├── detail │ ├── native_handle.hpp │ ├── windows │ │ ├── error.hpp │ │ ├── protect.inl │ │ ├── definitions.hpp │ │ ├── protection.inl │ │ └── query.inl │ ├── error_handlers.hpp │ ├── posix │ │ ├── protection.inl │ │ └── protect.inl │ ├── uintptr_cast.hpp │ ├── address_cast.hpp │ ├── query_range_using_query.inl │ ├── osx │ │ └── query.inl │ └── linux │ │ └── query.inl │ ├── address_concept.hpp │ ├── query_iterator.hpp │ ├── protect.hpp │ ├── region.hpp │ ├── protection.hpp │ ├── query.hpp │ └── protection_guard.hpp ├── appveyor.yml ├── CMakeLists.txt ├── .travis.yml ├── README.md └── LICENSE /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "test/Catch"] 2 | path = test/Catch 3 | url = https://github.com/philsquared/Catch 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | /.vs 34 | 35 | \.idea/ 36 | 37 | cmake-build-debug/ 38 | -------------------------------------------------------------------------------- /test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set (CATCH_MODULE_PATH "${PROJECT_SOURCE_DIR}/test/Catch") 2 | set (CATCH_INCLUDE_PATH "${CATCH_MODULE_PATH}/include") 3 | 4 | #include custom cmake function 5 | include ("${CATCH_MODULE_PATH}/contrib/ParseAndAddCatchTests.cmake") 6 | 7 | #configure variables 8 | set (TEST_APP_NAME "vmu_test") 9 | 10 | #configure directories 11 | set (TEST_MODULE_PATH "${PROJECT_SOURCE_DIR}/test") 12 | 13 | #set includes 14 | include_directories (${PROJECT_SOURCE_DIR}/include ${CATCH_INCLUDE_PATH}) 15 | 16 | #set test sources 17 | #file (GLOB TEST_SOURCE_FILES "$${CMAKE_CURRENT_LIST_DIR}/*.cpp") 18 | 19 | set (TEST_SOURCE_FILES 20 | ${TEST_MODULE_PATH}/main.cpp) 21 | 22 | #set target executable 23 | add_executable (${TEST_APP_NAME} ${TEST_SOURCE_FILES}) 24 | 25 | #add the library 26 | target_link_libraries (${TEST_APP_NAME} vmu) 27 | 28 | # Turn on CMake testing capabilities 29 | enable_testing() 30 | 31 | #parse catch tests 32 | ParseAndAddCatchTests (${TEST_APP_NAME}) -------------------------------------------------------------------------------- /include/vmu.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Justas Masiulis 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef VMU_VMU_HPP 18 | #define VMU_VMU_HPP 19 | 20 | // TODO 21 | // proper noexcept specifications according to pointer checking 22 | // allocator support for everything... 23 | // get rid of std::vector 24 | // proper docs 25 | // proper tests 26 | 27 | #include "vmu/protection_guard.hpp" 28 | #include "vmu/query_iterator.hpp" 29 | 30 | #endif // include guard 31 | -------------------------------------------------------------------------------- /include/vmu/detail/native_handle.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Justas Masiulis 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef VMU_NATIVE_HANDLES 18 | #define VMU_NATIVE_HANDLES 19 | 20 | /// \brief The native, operating system dependant handle 21 | #if defined(_WIN32) 22 | using native_handle_t = void*; 23 | #elif defined(__APPLE__) 24 | #include 25 | using native_handle_t = ::mach_port_t; 26 | #else 27 | #include 28 | using native_handle_t = ::pid_t; 29 | #endif 30 | 31 | #endif // include guard -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | # version string format -- This will be overwritten later anyway 2 | version: "{build}" 3 | 4 | os: 5 | - Visual Studio 2017 6 | - Visual Studio 2015 7 | 8 | init: 9 | - git config --global core.autocrlf input 10 | # Set build version to git commit-hash 11 | - ps: Update-AppveyorBuild -Version "$($env:APPVEYOR_REPO_BRANCH) - $($env:APPVEYOR_REPO_COMMIT)" 12 | 13 | install: 14 | - git submodule update --init --recursive 15 | 16 | # Win32 and x64 are CMake-compatible solution platform names. 17 | # This allows us to pass %PLATFORM% to CMake -A. 18 | platform: 19 | - Win32 20 | - x64 21 | 22 | # build Configurations, i.e. Debug, Release, etc. 23 | configuration: 24 | - Debug 25 | - Release 26 | 27 | #Cmake will autodetect the compiler, but we set the arch 28 | before_build: 29 | - cmake -H. -BBuild -A%PLATFORM% 30 | 31 | # build with MSBuild 32 | build: 33 | project: Build\vmu.sln # path to Visual Studio solution or project 34 | parallel: true # enable MSBuild parallel builds 35 | verbosity: normal # MSBuild verbosity level {quiet|minimal|normal|detailed} 36 | 37 | test_script: 38 | - cd Build 39 | - ctest -V -j 2 -C %CONFIGURATION% 40 | -------------------------------------------------------------------------------- /include/vmu/detail/windows/error.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Justas Masiulis 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef VMI_WINDOWS_ERROR_HPP 18 | #define VMI_WINDOWS_ERROR_HPP 19 | 20 | #include 21 | #include "definitions.hpp" 22 | 23 | namespace vmu { namespace detail { 24 | 25 | inline std::error_code get_last_error() noexcept 26 | { 27 | return std::error_code(static_cast(GetLastError()), std::system_category()); 28 | } 29 | 30 | inline void throw_last_error(const char* msg) 31 | { 32 | throw std::system_error(get_last_error(), msg); 33 | } 34 | 35 | }} 36 | 37 | #endif // include guard 38 | -------------------------------------------------------------------------------- /include/vmu/address_concept.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Justas Masiulis 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include 18 | #include 19 | 20 | #ifndef VMU_ADDRESS_CONCEPT_HPP 21 | #define VMU_ADDRESS_CONCEPT_HPP 22 | 23 | namespace vmu { 24 | 25 | /// \brief An address is a pointer of any type or a 32 bit or 64 bit unsigned integer 26 | template 27 | struct is_address { 28 | constexpr static bool value = std::is_pointer::value 29 | || ((sizeof(T) == 4 || sizeof(T) == 8) 30 | && std::is_integral::value 31 | && std::is_unsigned::value); 32 | }; 33 | 34 | } 35 | 36 | #endif // include guard 37 | -------------------------------------------------------------------------------- /include/vmu/detail/error_handlers.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Justas Masiulis 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef VMU_ERROR_HANDLERS_HPP 18 | #define VMU_ERROR_HANDLERS_HPP 19 | 20 | #include 21 | 22 | // TODO force inline these 23 | 24 | namespace vmu { namespace detail { 25 | 26 | struct handle_with_exception { 27 | constexpr static bool is_noexcept = false; 28 | 29 | [[noreturn]] inline void operator()(int code, const char* msg) const 30 | { 31 | throw std::system_error(std::error_code(code, std::system_category()), 32 | msg); 33 | } 34 | }; 35 | 36 | struct handle_with_ec { 37 | constexpr static bool is_noexcept = true; 38 | 39 | std::error_code& _ec; 40 | 41 | inline void operator()(int code, const char*) noexcept 42 | { 43 | _ec = std::error_code(code, std::system_category()); 44 | } 45 | }; 46 | 47 | }} // namespace vmu::detail 48 | 49 | #endif // VMU_ERROR_HANDLERS_HPP 50 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.3) 2 | project(vmu) 3 | 4 | set(CMAKE_CXX_STANDARD 14) 5 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 6 | 7 | if(WIN32) 8 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4") 9 | else() 10 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra") 11 | endif() 12 | 13 | set(detail_header_files 14 | ${CMAKE_CURRENT_SOURCE_DIR}/include/vmu/detail/query_range_using_query.inl 15 | ${CMAKE_CURRENT_SOURCE_DIR}/include/vmu/detail/address_cast.hpp 16 | ${CMAKE_CURRENT_SOURCE_DIR}/include/vmu/detail/uintptr_cast.hpp 17 | ${CMAKE_CURRENT_SOURCE_DIR}/include/vmu/detail/error_handlers.hpp 18 | 19 | ${CMAKE_CURRENT_SOURCE_DIR}/include/vmu/detail/windows/query.inl 20 | ${CMAKE_CURRENT_SOURCE_DIR}/include/vmu/detail/windows/protect.inl 21 | 22 | ${CMAKE_CURRENT_SOURCE_DIR}/include/vmu/detail/posix/protect.inl) 23 | 24 | set(header_files 25 | ${CMAKE_CURRENT_SOURCE_DIR}/include/vmu.hpp 26 | ${CMAKE_CURRENT_SOURCE_DIR}/include/vmu/protection.hpp 27 | ${CMAKE_CURRENT_SOURCE_DIR}/include/vmu/query.hpp 28 | ${CMAKE_CURRENT_SOURCE_DIR}/include/vmu/region.hpp 29 | ${CMAKE_CURRENT_SOURCE_DIR}/include/vmu/protection_guard.hpp 30 | ${CMAKE_CURRENT_SOURCE_DIR}/include/vmu/protect.hpp) 31 | 32 | include_directories(${PROJECT_SOURCE_DIR}/include) 33 | add_library(vmu INTERFACE) 34 | target_sources(vmu INTERFACE $) 35 | target_include_directories(vmu INTERFACE $) 36 | target_include_directories(vmu SYSTEM INTERFACE $/include>) 37 | 38 | enable_testing() 39 | add_subdirectory(test) -------------------------------------------------------------------------------- /include/vmu/detail/posix/protection.inl: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Justas Masiulis 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef VMU_POSIX_PROTECTION_INL 18 | #define VMU_POSIX_PROTECTION_INL 19 | 20 | #include "../../protection.hpp" 21 | 22 | namespace vmu { 23 | 24 | constexpr inline native_protection_t to_native(access flags) 25 | { 26 | return static_cast(flags); 27 | } 28 | 29 | constexpr inline access from_native(native_protection_t my_flags) 30 | { 31 | return static_cast(my_flags); 32 | } 33 | 34 | constexpr bool protection_t::accessible() const noexcept 35 | { 36 | return _native != 0; 37 | } 38 | 39 | constexpr bool protection_t::readable() const noexcept 40 | { 41 | return (_native & static_cast(access::read)); 42 | } 43 | 44 | constexpr bool protection_t::writable() const noexcept 45 | { 46 | return (_native & static_cast(access::write)); 47 | } 48 | 49 | constexpr bool protection_t::executable() const noexcept 50 | { 51 | return (_native & static_cast(access::exec)); 52 | } 53 | 54 | } // namespace vmu 55 | 56 | #endif // include guard 57 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: cpp 2 | sudo: required 3 | dist: trusty 4 | 5 | matrix: 6 | include: 7 | 8 | # Linux C++14 GCC builds 9 | - os: linux 10 | compiler: gcc 11 | addons: &gcc6 12 | apt: 13 | sources: ['ubuntu-toolchain-r-test'] 14 | packages: ['g++-6'] 15 | env: COMPILER='g++-6' BUILD_TYPE='Release' 16 | 17 | - os: linux 18 | compiler: gcc 19 | addons: *gcc6 20 | env: COMPILER='g++-6' BUILD_TYPE='Debug' 21 | 22 | # Linux C++14 Clang builds 23 | - os: linux 24 | compiler: clang 25 | addons: &clang40 26 | apt: 27 | sources: ['llvm-toolchain-trusty-4.0', 'ubuntu-toolchain-r-test'] 28 | packages: ['clang-4.0', 'libc++-dev', 'libc++abi-dev', 'g++-6'] 29 | env: COMPILER='clang++-4.0' BUILD_TYPE='Release' 30 | 31 | - os: linux 32 | compiler: clang 33 | addons: *clang40 34 | env: COMPILER='clang++-4.0' BUILD_TYPE='Debug' 35 | 36 | # OSX C++14 Clang Builds 37 | 38 | - os: osx 39 | osx_image: xcode8.3 40 | compiler: clang 41 | env: COMPILER='clang++' BUILD_TYPE='Debug' 42 | 43 | - os: osx 44 | osx_image: xcode8.3 45 | compiler: clang 46 | env: COMPILER='clang++' BUILD_TYPE='Release' 47 | 48 | 49 | install: 50 | - DEPS_DIR="${TRAVIS_BUILD_DIR}/deps" 51 | - mkdir -p ${DEPS_DIR} && cd ${DEPS_DIR} 52 | - | 53 | if [[ "${TRAVIS_OS_NAME}" == "linux" ]]; then 54 | CMAKE_URL="http://www.cmake.org/files/v3.3/cmake-3.3.2-Linux-x86_64.tar.gz" 55 | mkdir cmake && travis_retry wget --no-check-certificate --quiet -O - ${CMAKE_URL} | tar --strip-components=1 -xz -C cmake 56 | export PATH=${DEPS_DIR}/cmake/bin:${PATH} 57 | elif [[ "${TRAVIS_OS_NAME}" == "osx" ]]; then 58 | which cmake || brew install cmake 59 | fi 60 | before_script: 61 | - export CXX=${COMPILER} 62 | - cd ${TRAVIS_BUILD_DIR} 63 | - cmake -H. -BBuild -DCMAKE_BUILD_TYPE=${BUILD_TYPE} -Wdev 64 | - cd Build 65 | 66 | script: 67 | - make -j 2 68 | - ctest -V -j 2 -------------------------------------------------------------------------------- /include/vmu/detail/uintptr_cast.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Justas Masiulis 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef VMU_UINTPTR_CAST_HPP 18 | #define VMU_UINTPTR_CAST_HPP 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | namespace vmu { namespace detail { 25 | 26 | template 27 | struct _select_uintptr_t; 28 | 29 | template<> 30 | struct _select_uintptr_t<4> { 31 | using type = std::uint32_t; 32 | }; 33 | template<> 34 | struct _select_uintptr_t<8> { 35 | using type = std::uint64_t; 36 | }; 37 | 38 | template 39 | struct is_pointer_or_unsigned { 40 | static constexpr bool value = std::is_pointer::value || std::is_unsigned::value; 41 | }; 42 | 43 | template 44 | using as_uintptr_t = typename _select_uintptr_t::type; 45 | 46 | template 47 | inline constexpr A1 address_cast_unchecked(A2 addr) noexcept 48 | { 49 | static_assert(is_pointer_or_unsigned::value && is_pointer_or_unsigned::value, 50 | "address cast can only be used on valid address types"); 51 | 52 | // clang, gcc and msvc all optimize the memcpy away 53 | A1 value{ 0 }; 54 | std::memcpy(&value, &addr, sizeof(A2)); 55 | 56 | return value; 57 | }; 58 | 59 | template 60 | inline constexpr auto uintptr_cast(Address address) noexcept 61 | { 62 | return address_cast_unchecked>(address); 63 | } 64 | 65 | }} 66 | 67 | #endif // include guard 68 | -------------------------------------------------------------------------------- /include/vmu/detail/posix/protect.inl: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Justas Masiulis 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef VMU_POSIX_PROTECT_MEMORY_INL 18 | #define VMU_POSIX_PROTECT_MEMORY_INL 19 | 20 | #include "../../protect.hpp" 21 | #include "vmu/detail/address_cast.hpp" 22 | #include 23 | #include 24 | 25 | namespace vmu { 26 | 27 | inline std::size_t page_size() noexcept 28 | { 29 | // theoretically this may fail but don't think that this could happen in practice 30 | const static auto size = static_cast(::sysconf(_SC_PAGESIZE)); 31 | return size; 32 | } 33 | 34 | template 35 | inline void protect(Address begin, Address end, protection_t prot) 36 | { 37 | if (begin == end) 38 | return; 39 | 40 | const auto address = (detail::address_cast(begin) & -page_size()); 41 | 42 | if (::mprotect(detail::address_cast_unchecked(address) 43 | , detail::address_cast(end) - address 44 | , prot.native()) == -1) 45 | throw std::system_error(std::error_code(errno, std::system_category()) 46 | , "mprotect() failed"); 47 | } 48 | 49 | 50 | template 51 | inline void 52 | protect(Address begin, Address end, protection_t prot, std::error_code& ec) 53 | { 54 | if(begin == end) 55 | return; 56 | 57 | const auto address = (detail::address_cast(begin) & -page_size()); 58 | 59 | if (::mprotect(detail::address_cast_unchecked(address) 60 | , detail::address_cast(end) - address 61 | , prot.native()) == -1) 62 | ec = std::error_code(errno, std::system_category()); 63 | } 64 | 65 | } // namespace vmu 66 | 67 | namespace vmu { namespace detail { 68 | 69 | template 70 | inline auto fix_singular_address(Address address) 71 | { 72 | return detail::uintptr_cast(address); 73 | } 74 | 75 | }} 76 | 77 | #endif // include guard 78 | -------------------------------------------------------------------------------- /include/vmu/detail/address_cast.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Justas Masiulis 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef VMU_CHECKED_POINTERS_HPP 18 | #define VMU_CHECKED_POINTERS_HPP 19 | 20 | #include 21 | #include 22 | 23 | #include "uintptr_cast.hpp" 24 | 25 | namespace vmu { namespace detail { 26 | 27 | template 28 | struct _address_cast_checker { 29 | constexpr static bool is_checked = false; 30 | 31 | template 32 | inline static constexpr void check(P1) noexcept {} 33 | }; 34 | 35 | #if !defined(VMU_NO_PTR_CHECKING) 36 | 37 | template<> 38 | struct _address_cast_checker { 39 | constexpr static bool is_checked = true; 40 | 41 | template 42 | inline static constexpr void check(P1 p1) 43 | { 44 | if ( uintptr_cast(p1) > std::numeric_limits>::max()) 45 | throw std::overflow_error( 46 | "attempt to cast address to type of insufficient size"); 47 | } 48 | }; 49 | 50 | #endif 51 | 52 | template 53 | struct ptr_checked { 54 | constexpr static bool value = _address_cast_checker<(sizeof(P2) > sizeof(P1)) 55 | >::is_checked; 56 | }; 57 | 58 | template 59 | inline constexpr Px address_cast(Py ptr) noexcept(!ptr_checked::value) 60 | { 61 | using checker = _address_cast_checker<(sizeof(Py) > sizeof(Px))>; 62 | checker::template check(ptr); 63 | 64 | return address_cast_unchecked(ptr); 65 | } 66 | 67 | // TODO do some TMP to avoid casts in some cases 68 | template 69 | inline constexpr Address advance_ptr(Address ptr, Address size) noexcept 70 | { 71 | return address_cast_unchecked
(uintptr_cast(ptr) + uintptr_cast(size)); 72 | } 73 | 74 | template 75 | inline constexpr Address ptr_distance(Address p1, Address p2) noexcept 76 | { 77 | return address_cast_unchecked
(uintptr_cast(p1) - uintptr_cast(p2)); 78 | } 79 | 80 | }} 81 | 82 | #endif // include guard 83 | -------------------------------------------------------------------------------- /include/vmu/detail/windows/protect.inl: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Justas Masiulis 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef VMU_WINDOWS_PROTECT_MEMORY_INL 18 | #define VMU_WINDOWS_PROTECT_MEMORY_INL 19 | 20 | #include "error.hpp" 21 | #include "../../protect.hpp" 22 | #include "vmu/detail/address_cast.hpp" 23 | 24 | namespace vmu { 25 | 26 | inline std::size_t page_size() noexcept 27 | { 28 | const static auto ps = [] { 29 | detail::SYSTEM_INFO_ info; 30 | detail::GetSystemInfo(reinterpret_cast<::_SYSTEM_INFO*>(&info)); 31 | return static_cast(info.dwPageSize); 32 | }(); 33 | 34 | return ps; 35 | } 36 | 37 | template 38 | inline void protect(Address begin, Address end, protection_t prot) 39 | { 40 | if (begin == end) 41 | return; 42 | 43 | unsigned long old; 44 | const auto size = detail::address_cast(end) 45 | - detail::address_cast_unchecked(begin); 46 | 47 | if (!detail::VirtualProtect(detail::address_cast_unchecked(begin) 48 | , size 49 | , prot.native() 50 | , &old)) 51 | detail::throw_last_error("VirtualProtect() failed"); 52 | 53 | if (!detail::FlushInstructionCache(detail::GetCurrentProcess() 54 | , detail::address_cast_unchecked(begin) 55 | , size)) 56 | detail::throw_last_error("FlushInstructionCache() failed"); 57 | } 58 | 59 | 60 | template 61 | inline void 62 | protect(Address begin, Address end, protection_t prot, std::error_code& ec) 63 | { 64 | if (begin == end) 65 | return; 66 | 67 | unsigned long old; 68 | const auto size = detail::address_cast(end) 69 | - detail::address_cast_unchecked(begin); 70 | 71 | if (detail::VirtualProtect(detail::address_cast_unchecked(begin) 72 | , size 73 | , prot.native() 74 | , &old)) 75 | if (detail::FlushInstructionCache(detail::GetCurrentProcess() 76 | , detail::address_cast_unchecked(begin) 77 | , size)) 78 | return; 79 | 80 | ec = detail::get_last_error(); 81 | } 82 | 83 | } // namespace vmu 84 | 85 | #endif // include guard 86 | -------------------------------------------------------------------------------- /include/vmu/query_iterator.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Justas Masiulis 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef VMU_MEMORY_ITERATOR_HPP 18 | #define VMU_MEMORY_ITERATOR_HPP 19 | 20 | #include 21 | #include "query.hpp" 22 | 23 | namespace vmu { 24 | 25 | template 26 | class basic_query_iterator { 27 | basic_region _region; 28 | 29 | public: 30 | typedef basic_region value_type; 31 | typedef value_type& reference; 32 | typedef const value_type& const_reference; 33 | typedef value_type* pointer; 34 | typedef const value_type* const_pointer; 35 | typedef std::ptrdiff_t difference_type; 36 | typedef std::forward_iterator_tag iterator_category; 37 | 38 | template 39 | basic_query_iterator(Address address) : _region(query(address)) 40 | {} 41 | 42 | reference operator*() noexcept { return _region; } 43 | const_reference operator*() const noexcept { return _region; } 44 | pointer operator->() noexcept { return &_region; } 45 | const_pointer operator->() const noexcept { return &_region; } 46 | 47 | basic_query_iterator& operator++() 48 | { 49 | _region = vmu::query(_region.end()); 50 | return *this; 51 | } 52 | basic_query_iterator operator++(int) 53 | { 54 | auto temp = *this; 55 | _region = vmu::query(_region.end()); 56 | return temp; 57 | } 58 | 59 | template 60 | bool operator==(const basic_query_iterator& other) const 61 | noexcept 62 | { 63 | return detail::uintptr_cast(other._region.begin()) >= 64 | detail::uintptr_cast(_region.begin()) && 65 | detail::uintptr_cast(other._region.end()) <= 66 | detail::uintptr_cast(_region.end()); 67 | } 68 | 69 | template 70 | bool operator!=(const basic_query_iterator& other) const 71 | noexcept 72 | { 73 | return !(operator==(other)); 74 | } 75 | }; 76 | 77 | using query_iterator = basic_query_iterator<>; 78 | 79 | }; // namespace vmu 80 | 81 | #endif // include gaurd 82 | -------------------------------------------------------------------------------- /include/vmu/detail/windows/definitions.hpp: -------------------------------------------------------------------------------- 1 | #ifndef VMU_WINDOWS_DEFINITIONS_HPP 2 | #define VMU_WINDOWS_DEFINITIONS_HPP 3 | 4 | extern "C" struct _SYSTEM_INFO; 5 | extern "C" struct _MEMORY_BASIC_INFORMATION; 6 | 7 | namespace vmu { namespace detail { 8 | 9 | #ifdef _WIN64 10 | #if defined(__CYGWIN__) 11 | typedef unsigned long ULONG_PTR_; 12 | #else 13 | typedef unsigned __int64 ULONG_PTR_; 14 | #endif 15 | #else 16 | typedef unsigned long ULONG_PTR_; 17 | #endif 18 | 19 | struct MEMORY_BASIC_INFORMATION_ { 20 | void* BaseAddress; 21 | void* AllocationBase; 22 | unsigned long AllocationProtect; 23 | ULONG_PTR_ RegionSize; 24 | unsigned long State; 25 | unsigned long Protect; 26 | unsigned long Type; 27 | }; 28 | 29 | struct SYSTEM_INFO_ { 30 | union { 31 | unsigned long dwOemId; 32 | struct { 33 | unsigned short wProcessorArchitecture; 34 | unsigned short wReserved; 35 | } info; 36 | }; 37 | unsigned long dwPageSize; 38 | void* lpMinimumApplicationAddress; 39 | void* lpMaximumApplicationAddress; 40 | ULONG_PTR_ dwActiveProcessorMask; 41 | unsigned long dwNumberOfProcessors; 42 | unsigned long dwProcessorType; 43 | unsigned long dwAllocationGranularity; 44 | unsigned short wProcessorLevel; 45 | unsigned short wProcessorRevision; 46 | }; 47 | 48 | extern "C" { 49 | 50 | __declspec(dllimport) unsigned long __stdcall GetLastError(); 51 | 52 | __declspec(dllimport) ULONG_PTR_ 53 | __stdcall VirtualQueryEx(void* handle, 54 | const void* address, 55 | ::_MEMORY_BASIC_INFORMATION* buffer, 56 | ULONG_PTR_ size_of_info); 57 | 58 | __declspec(dllimport) int __stdcall VirtualProtect( 59 | void* address, 60 | ULONG_PTR_ size, 61 | unsigned long new_protection, 62 | unsigned long* old_protection); 63 | 64 | __declspec(dllimport) void __stdcall GetSystemInfo(::_SYSTEM_INFO* lpSystemInfo); 65 | 66 | __declspec(dllimport) void* __stdcall GetCurrentProcess(); 67 | 68 | __declspec(dllimport) int __stdcall FlushInstructionCache(void* handle, 69 | const void* address, 70 | ULONG_PTR_ size); 71 | } 72 | 73 | constexpr static unsigned long mem_commit = 0x1000; 74 | constexpr static unsigned long mem_free = 0x10000; 75 | constexpr static unsigned long mem_reserve = 0x2000; 76 | constexpr static unsigned long mem_private = 0x20000; 77 | constexpr static unsigned long page_guard = 0x100; 78 | constexpr static unsigned long no_access = 0x01; 79 | 80 | }} // namespace vmu::detail 81 | 82 | #endif // include guard 83 | -------------------------------------------------------------------------------- /include/vmu/protect.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Justas Masiulis 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef VMU_PROTECT_MEMORY_HPP 18 | #define VMU_PROTECT_MEMORY_HPP 19 | 20 | #include 21 | #include "protection.hpp" 22 | 23 | namespace vmu { 24 | 25 | /// \brief Returns the operating systems page size. 26 | /// \throws Does not throw 27 | inline std::size_t page_size() noexcept; 28 | 29 | /// \brief Changes protection of pages in the range [begin; end) 30 | /// \param begin The beginning of range to protect. 31 | /// \param end One past the end of range to protect. 32 | /// \param prot The protection to apply to the range. 33 | /// \throws May throw system_error or overflow_error if address overflows. 34 | template 35 | inline void protect(Address begin, Address end, protection_t prot); 36 | 37 | /// \brief Changes protection of pages in the range [begin; end) 38 | /// \param begin The beginning of range to protect. 39 | /// \param end One past the end of range to protect. 40 | /// \param prot The protection to apply to the range. 41 | /// \throws May throw overflow_error if address overflows. 42 | template 43 | inline void protect(Address begin 44 | , Address end 45 | , protection_t prot 46 | , std::error_code& ec); 47 | 48 | /// \brief Changes the protection of a page. 49 | /// \param begin The address of the page to protect. 50 | /// \param prot The protection to apply to the page. 51 | /// \throws May throw system_error or overflow_error if address overflows. 52 | template 53 | inline void protect(Address address, protection_t prot) 54 | { 55 | auto fixed_address = detail::uintptr_cast(address); 56 | #ifndef _WIN32 57 | fixed_address &= -page_size(); 58 | #endif 59 | protect(fixed_address, fixed_address + 1, prot); 60 | } 61 | 62 | /// \brief Changes the protection of a page. 63 | /// \param begin The address of the page to protect. 64 | /// \param prot The protection to apply to the page. 65 | /// \throws May throw overflow_error if address overflows. 66 | template 67 | inline void protect(Address address, protection_t prot, std::error_code& ec) 68 | { 69 | auto fixed_address = detail::uintptr_cast(address); 70 | #ifndef _WIN32 71 | fixed_address &= -page_size(); 72 | #endif 73 | protect(fixed_address, fixed_address + 1, prot, ec); 74 | } 75 | 76 | } // namespace vmu 77 | 78 | #if defined(_WIN32) 79 | #include "detail/windows/protect.inl" 80 | #else 81 | #include "detail/posix/protect.inl" 82 | #endif 83 | 84 | #endif // include guard 85 | -------------------------------------------------------------------------------- /include/vmu/detail/query_range_using_query.inl: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Justas Masiulis 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef VMU_QUERY_RANGE_USING_QUERY_INL 18 | #define VMU_QUERY_RANGE_USING_QUERY_INL 19 | 20 | #include "../query.hpp" 21 | 22 | namespace vmu { 23 | 24 | template 25 | inline std::vector> query_range(Address begin, Address end) 26 | { 27 | std::vector> regions; 28 | auto checked_begin = detail::address_cast(begin); 29 | const auto checked_end = detail::address_cast(end); 30 | 31 | while (checked_begin < checked_end) { 32 | regions.emplace_back(query(checked_begin)); 33 | checked_begin = regions.back().end(); 34 | } 35 | 36 | return regions; 37 | } 38 | 39 | template 40 | inline std::vector> 41 | query_range(Address begin, Address end, std::error_code& ec) 42 | { 43 | std::vector> regions; 44 | auto checked_begin = detail::address_cast(begin); 45 | const auto checked_end = detail::address_cast(end); 46 | 47 | while (checked_begin < checked_end) { 48 | regions.emplace_back(query(checked_begin, ec)); 49 | if(ec) 50 | return regions; 51 | checked_begin = regions.back().end(); 52 | } 53 | 54 | return regions; 55 | } 56 | 57 | 58 | template 59 | inline std::vector> 60 | query_range(native_handle_t handle, Address begin, Address end) 61 | { 62 | std::vector> regions; 63 | auto checked_begin = detail::address_cast(begin); 64 | const auto checked_end = detail::address_cast(end); 65 | 66 | while (checked_begin < checked_end) { 67 | regions.emplace_back(query(handle, checked_begin)); 68 | checked_begin = regions.back().end(); 69 | } 70 | 71 | return regions; 72 | } 73 | 74 | template 75 | inline std::vector> 76 | query_range(native_handle_t handle, Address begin, Address end, std::error_code& ec) 77 | { 78 | std::vector> regions; 79 | auto checked_begin = detail::address_cast(begin); 80 | const auto checked_end = detail::address_cast(end); 81 | 82 | while (checked_begin < checked_end) { 83 | regions.emplace_back(query(handle, checked_begin, ec)); 84 | if(ec) 85 | return regions; 86 | checked_begin = regions.back().end(); 87 | } 88 | 89 | return regions; 90 | } 91 | } 92 | 93 | #endif // !VMU_WINDOWS_QUERY_INL 94 | -------------------------------------------------------------------------------- /include/vmu/region.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Justas Masiulis 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef VMU_REGION_HPP 18 | #define VMU_REGION_HPP 19 | 20 | #include "protection.hpp" 21 | #include "vmu/detail/address_cast.hpp" 22 | 23 | // a dirty macro to not have large #ifdef blocks 24 | #ifdef __linux__ 25 | #define VMU_NOT_FOR_LINUX(expr) 26 | #define VMU_COMMA_NOT_FOR_LINUX(expr) 27 | #else 28 | #define VMU_NOT_FOR_LINUX(expr) expr 29 | #define VMU_COMMA_NOT_FOR_LINUX(expr) , expr 30 | #endif 31 | 32 | namespace vmu { 33 | 34 | /// \brief The class representing memory region 35 | /// \tparam Ptr The type representing pointer in address space 36 | template 37 | class basic_region { 38 | Address _begin{static_cast
(0)}; 39 | Address _end{static_cast
(0)}; 40 | protection_t _protection{0}; 41 | bool _used{false}; 42 | bool _shared{false}; 43 | VMU_NOT_FOR_LINUX(bool _guarded{false}); 44 | 45 | public: 46 | using address_type = Address; 47 | 48 | constexpr basic_region() noexcept = default; 49 | 50 | /// \brief Constructs a memory region that is not in use. 51 | constexpr basic_region(address_type begin, address_type end) noexcept 52 | : _begin(begin) 53 | , _end(end) {} 54 | 55 | constexpr basic_region(address_type begin 56 | , address_type end 57 | , protection_t protection 58 | , bool shared 59 | VMU_COMMA_NOT_FOR_LINUX(bool guarded)) noexcept 60 | : _begin(begin) 61 | , _end(end) 62 | , _protection(protection) 63 | , _used(true) 64 | , _shared(shared) 65 | VMU_COMMA_NOT_FOR_LINUX(_guarded(guarded)) {} 66 | 67 | /// \brief Returns the base address of the region. 68 | constexpr address_type begin() const noexcept { return _begin; } 69 | 70 | /// \brief Returns one past the end of the region. 71 | constexpr address_type end() const noexcept 72 | { 73 | return detail::address_cast_unchecked
(detail::uintptr_cast(_end) + 1); 74 | } 75 | 76 | /// \brief Returns the size of the region. 77 | constexpr detail::as_uintptr_t size() const noexcept 78 | { 79 | return detail::uintptr_cast(detail::uintptr_cast(_end) - detail::uintptr_cast(_begin)); 80 | } 81 | 82 | /// \brief Returns the protection of the region. 83 | constexpr protection_t protection() const noexcept { return _protection; } 84 | 85 | /// \brief Returns whether the memory region is guarded. 86 | constexpr bool guarded() const noexcept 87 | { 88 | #ifndef __linux__ 89 | return _guarded; 90 | #else 91 | return false; 92 | #endif 93 | } 94 | 95 | /// \brief Returns whether the memory region is shared. 96 | constexpr bool shared() const noexcept { return _shared; }; 97 | 98 | /// \brief Returns whether the memory region is in use. 99 | constexpr explicit operator bool() const noexcept { return _used; } 100 | }; 101 | 102 | 103 | using local_region = basic_region; 104 | using remote_region = basic_region; 105 | 106 | } 107 | 108 | #endif // include guard 109 | -------------------------------------------------------------------------------- /include/vmu/protection.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Justas Masiulis 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef VMU_PROTECTION_HPP 18 | #define VMU_PROTECTION_HPP 19 | 20 | namespace vmu { 21 | 22 | #if defined(_WIN32) 23 | using native_protection_t = unsigned long; 24 | #else 25 | using native_protection_t = int; 26 | #endif 27 | 28 | 29 | enum class access : native_protection_t { 30 | none = 0, 31 | read = 1, 32 | write = 2, 33 | exec = 4, 34 | read_write = read | write, 35 | read_exec = read | exec, 36 | write_exec = write | exec, 37 | read_write_exec = read | write | exec 38 | }; 39 | 40 | constexpr inline native_protection_t to_native(access flags); 41 | 42 | constexpr inline access from_native(native_protection_t flags); 43 | 44 | /// /brief A basic wrapper class around memory protection constants. 45 | class protection_t { 46 | native_protection_t _native; 47 | 48 | public: 49 | explicit constexpr protection_t() 50 | : _native() {} 51 | 52 | constexpr protection_t(access flags) 53 | : _native(to_native(flags)) {} 54 | 55 | constexpr protection_t(native_protection_t native) noexcept 56 | : _native(native) {} 57 | 58 | constexpr bool accessible() const noexcept; 59 | constexpr bool readable() const noexcept; 60 | constexpr bool writable() const noexcept; 61 | constexpr bool executable() const noexcept; 62 | 63 | constexpr native_protection_t native() const noexcept { return _native; } 64 | constexpr access to_flags() const { return from_native(_native); } 65 | }; 66 | 67 | 68 | constexpr access operator|(access lhs, access rhs) noexcept 69 | { 70 | return static_cast(static_cast(lhs) 71 | | static_cast(rhs)); 72 | } 73 | 74 | constexpr access operator&(access lhs, access rhs) noexcept 75 | { 76 | return static_cast(static_cast(lhs) 77 | & static_cast(rhs)); 78 | } 79 | 80 | constexpr access operator^(access lhs, access rhs) noexcept 81 | { 82 | return static_cast(static_cast(lhs) 83 | ^ static_cast(rhs)); 84 | } 85 | 86 | constexpr access operator~(access rhs) noexcept 87 | { 88 | return static_cast(~static_cast(rhs)); 89 | } 90 | 91 | constexpr access& operator|=(access& lhs, access rhs) noexcept 92 | { 93 | lhs = static_cast (static_cast(lhs) 94 | | static_cast(rhs)); 95 | 96 | return lhs; 97 | } 98 | 99 | constexpr access& operator&=(access& lhs, access rhs) noexcept 100 | { 101 | lhs = static_cast(static_cast(lhs) 102 | & static_cast(rhs)); 103 | 104 | return lhs; 105 | } 106 | 107 | constexpr access& operator^=(access& lhs, access rhs) noexcept 108 | { 109 | lhs = static_cast(static_cast(lhs) 110 | ^ static_cast(rhs)); 111 | 112 | return lhs; 113 | } 114 | 115 | } // namespace vmu 116 | 117 | #ifdef _WIN32 118 | #include "detail/windows/protection.inl" 119 | #else 120 | #include "detail/posix/protection.inl" 121 | #endif 122 | 123 | #endif // include guard 124 | -------------------------------------------------------------------------------- /include/vmu/detail/windows/protection.inl: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Justas Masiulis 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef VMU_WINDOWS_PROTECTION_INL 18 | #define VMU_WINDOWS_PROTECTION_INL 19 | 20 | #include "../../protection.hpp" 21 | #include 22 | #include 23 | 24 | namespace vmu { 25 | 26 | namespace detail { 27 | 28 | enum page_protection : native_protection_t { 29 | noaccess = 0x01, 30 | readonly = 0x02, 31 | readwrite = 0x04, 32 | writecopy = 0x08, 33 | execute = 0x10, 34 | execute_read = 0x20, 35 | execute_readwrite = 0x40, 36 | execute_writecopy = 0x80, 37 | 38 | guard = 0x100, 39 | nocache = 0x200, 40 | writecombine = 0x400, 41 | }; 42 | } 43 | 44 | constexpr inline native_protection_t to_native(access flags) 45 | { 46 | switch (flags) { 47 | case access::none: 48 | return detail::noaccess; 49 | case access::read: 50 | return detail::readonly; 51 | case access::write: // no writeonly 52 | return detail::readwrite; 53 | case access::exec: 54 | return detail::execute; 55 | case access::read_write: 56 | return detail::readwrite; 57 | case access::read | access::exec: 58 | return detail::execute_read; 59 | case access::write_exec: 60 | case access::read_write_exec: 61 | return detail::execute_readwrite; 62 | default: 63 | throw std::logic_error("unknown protection access combination"); 64 | } 65 | } 66 | 67 | constexpr inline access from_native(native_protection_t flags) 68 | { 69 | switch (flags & 70 | (~(detail::guard | detail::nocache | detail::writecombine))) { 71 | case detail::noaccess: 72 | return access::none; 73 | case detail::readonly: 74 | return access::read; 75 | case detail::execute: 76 | return access::exec; 77 | case detail::readwrite: 78 | case detail::writecopy: 79 | return access::read_write; 80 | case detail::execute_read: 81 | return access::read_exec; 82 | case detail::execute_readwrite: 83 | case detail::execute_writecopy: 84 | return access::read_write_exec; 85 | default: 86 | throw std::range_error("unknown protection constant: " + 87 | std::to_string(flags)); 88 | } 89 | } 90 | 91 | constexpr inline bool protection_t::accessible() const noexcept 92 | { 93 | return !(_native & detail::noaccess); 94 | } 95 | 96 | constexpr inline bool protection_t::readable() const noexcept 97 | { 98 | return accessible() && 99 | ((_native & detail::readwrite) || (_native & detail::execute_read) || 100 | (_native & detail::execute_readwrite) || 101 | (_native & detail::readonly) || (_native & detail::writecopy) || 102 | (_native & detail::execute_writecopy)); 103 | } 104 | 105 | constexpr inline bool protection_t::writable() const noexcept 106 | { 107 | return accessible() && ((_native & detail::readwrite) || 108 | (_native & detail::execute_readwrite) || 109 | (_native & detail::execute_writecopy) || 110 | (_native & detail::writecopy)); 111 | } 112 | 113 | constexpr inline bool protection_t::executable() const noexcept 114 | { 115 | return accessible() && 116 | ((_native & detail::execute_read) || (_native & detail::execute) || 117 | (_native & detail::execute_readwrite) || 118 | (_native & detail::execute_writecopy)); 119 | } 120 | 121 | } // namespace vmu 122 | 123 | #endif // include guard 124 | -------------------------------------------------------------------------------- /test/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | template 7 | void check_region(const vmu::basic_region
region, Address2 addr) 8 | { 9 | REQUIRE(static_cast(region)); 10 | CHECK(region.protection().readable()); 11 | CHECK(region.protection().writable()); 12 | CHECK(region.size() != 0); 13 | CHECK(vmu::detail::uintptr_cast(region.begin()) <= 14 | vmu::detail::uintptr_cast(addr)); 15 | CHECK(vmu::detail::uintptr_cast(region.end()) >= 16 | vmu::detail::uintptr_cast(addr)); 17 | } 18 | 19 | TEST_CASE("address_cast sanity check") 20 | { 21 | std::uintptr_t uintptr = 0xdeadbeef; 22 | void* ptr = vmu::detail::address_cast(uintptr); 23 | REQUIRE(memcmp(&uintptr, &ptr, sizeof(void*)) == 0); 24 | } 25 | 26 | TEST_CASE("query") 27 | { 28 | int i = 5; 29 | auto ret = vmu::query(&i); 30 | check_region(ret, &i); 31 | } 32 | 33 | TEST_CASE("query error code") 34 | { 35 | std::error_code ec; 36 | int i = 5; 37 | auto ptr_i = reinterpret_cast(&i); 38 | auto ret = vmu::query(ptr_i, ec); 39 | check_region(ret, ptr_i); 40 | } 41 | 42 | TEST_CASE("query_range") 43 | { 44 | int i = 5; 45 | auto ptr = reinterpret_cast(&i); 46 | const auto rets = vmu::query_range(ptr, ptr + 16); 47 | 48 | REQUIRE_FALSE(rets.empty()); 49 | for (const auto& ret : rets) 50 | check_region(ret, ptr); 51 | } 52 | 53 | TEST_CASE("query_range error code") 54 | { 55 | int i = 5; 56 | auto ptr = reinterpret_cast(&i); 57 | std::error_code ec; 58 | const auto rets = vmu::query_range(&i, &i + 16, ec); 59 | 60 | REQUIRE_FALSE(ec); 61 | REQUIRE_FALSE(rets.empty()); 62 | for (const auto& ret : rets) 63 | check_region(ret, ptr); 64 | } 65 | 66 | TEST_CASE("protection_guard(Address, protection_t)") 67 | { 68 | auto random_data = std::make_unique(4096 * 3); 69 | auto testing_arr = random_data.get(); 70 | memset(testing_arr, 12, 4096 * 3); 71 | auto result = vmu::query(testing_arr); 72 | REQUIRE(result); 73 | 74 | { 75 | const auto new_prot = vmu::access::read_write_exec; 76 | CHECK_FALSE(new_prot == result.protection().to_flags()); 77 | 78 | vmu::protection_guard pg(testing_arr, new_prot); 79 | 80 | auto new_flags = vmu::query(testing_arr); 81 | CHECK(new_flags); 82 | CHECK(new_flags.protection().to_flags() == new_prot); 83 | } 84 | 85 | auto result2 = vmu::query(testing_arr); 86 | REQUIRE(result2.shared() == result.shared()); 87 | REQUIRE(result2.begin() == result.begin()); 88 | REQUIRE(result2.protection().to_flags() == result.protection().to_flags()); 89 | REQUIRE(result2.guarded() == result.guarded()); 90 | } 91 | 92 | TEST_CASE("protection_guard(Address, Address, protection_t)") 93 | { 94 | auto random_data = std::make_unique(4096 * 6); 95 | auto testing_arr = random_data.get(); 96 | memset(testing_arr, 0xCC, 4096 * 6); 97 | auto result = vmu::query(testing_arr); 98 | REQUIRE(result); 99 | { 100 | const auto new_prot = vmu::access::read; 101 | CHECK_FALSE(new_prot == result.protection().to_flags()); 102 | 103 | vmu::protection_guard pg( 104 | testing_arr + 4097, testing_arr + 4096 * 3, new_prot); 105 | 106 | auto new_flags = vmu::query(testing_arr + 4097); 107 | CHECK(new_flags); 108 | CHECK(new_flags.protection().to_flags() == new_prot); 109 | } 110 | 111 | auto result2 = vmu::query(testing_arr); 112 | REQUIRE(result2.shared() == result.shared()); 113 | REQUIRE(result2.begin() == result.begin()); 114 | REQUIRE(result2.protection().to_flags() == result.protection().to_flags()); 115 | REQUIRE(result2.guarded() == result.guarded()); 116 | } 117 | 118 | TEST_CASE("query_iterator") 119 | { 120 | const auto total_size = vmu::page_size() * 5; 121 | auto random_data = std::make_unique(total_size); 122 | auto begin = random_data.get(); 123 | auto end = begin + total_size; 124 | 125 | vmu::query_iterator end_it(end); 126 | for (vmu::query_iterator it(begin); it != end_it; ++it) { 127 | REQUIRE(static_cast(*it)); 128 | CHECK(it->protection().readable()); 129 | CHECK(it->protection().writable()); 130 | CHECK(it->size() != 0); 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vmutils [![Build Status](https://travis-ci.org/JustasMasiulis/vmutils.svg?branch=master)](https://travis-ci.org/JustasMasiulis/vmutils) [![Build status](https://ci.appveyor.com/api/projects/status/kty003rauanbu8xh?svg=true)](https://ci.appveyor.com/project/JustasMasiulis/vmutils) 2 | 3 | cross platform virtual memory utilities library. 4 | 5 | ## small example 6 | ```cpp 7 | // address can be unsinged integer or pointer 8 | const auto region = vmu::query(address); 9 | if(region && region.protection().accessible()) { 10 | const auto new_flags = vmu::access::read_write_exec; 11 | vmu::protection_guard guard(address, new_flags); 12 | // do something 13 | } // protection will be restored on scope exit 14 | ``` 15 | 16 | *** 17 | 18 | # quick reference 19 | ## `basic_region
` 20 | Provides information about a memory region. Can be obtained using `query` or `query_region`. 21 | 22 | | function | return type | explanation | 23 | | ------------- |--------------------------------- | ----------------------------- | 24 | | begin | Address | beginning of region | 25 | | end | Address | one past the end of region | 26 | | size | uint big enough to store Address | size of region | 27 | | protection | protection_t | the protection of page | 28 | | guarded | bool | whether the region is guarded | 29 | | shared | bool | whether the region is shared | 30 | | operator bool | bool | whether the region is used | 31 | 32 | ## `protection_t` 33 | Wrapper class around protection flags. 34 | 35 | | function | return type | 36 | | ---------- |-------------------- | 37 | | accessible | bool | 38 | | readable | bool | 39 | | writable | bool | 40 | | executable | bool | 41 | | native | native_protection_t | 42 | | to_flags | access | 43 | 44 | ## `access` enumeration 45 | - read 46 | - write 47 | - exec 48 | - read_write 49 | - read_exec 50 | - write_exec 51 | - read_write_exec 52 | 53 | ## region query functions 54 | Arguments in `[]` are not required - overloaded functions are present. 55 | ### `basic_region query([native_handle_t], Address, [std::error_code&])` 56 | Returns information about a region that the given address is in. 57 | ### `std::vector> query_range([native_handle_t], Address, Address, [std::error_code&])` 58 | Returns information about regions that the given range of addresses are in. 59 | 60 | The default for RegionAddress is `std::uintptr_t` or if the first function argument is of type 61 | `native_handle_t` - `std::uint64_t`. 62 | 63 | ## region protection 64 | ### `protection_guard` 65 | RAII based memory region protection and query class that protects a region of memory and 66 | restores it upon destruction. 67 | 68 | If adopt_protection_t tag type is given constructor performs no 69 | actions and destructor sets the given protection instead. 70 | 71 | In critical code it is recommended to manually call `restore` or define `VMU_HANDLE_PG_DESTRUCTOR_FAILURE` 72 | macro that will handle errors in destructor, because by default on error memory regions is left unrestored. 73 | 74 | constructor overloads: 75 | - `protection_guard(Address, protection_t)` 76 | - `protection_guard(Address, Address, protection_t)` 77 | - `protection_guard(Range, protection_t)` 78 | - `protection_guard(Address, protection_t, adopt_protection_t)` 79 | - `protection_guard(Address, Address, protection_t, adopt_protection_t)` 80 | - `protection_guard(Range, protection_t, adopt_protection_t)` 81 | 82 | | function | explanation | 83 | | --------------------------- | ----------------------------------------------------------------------- | 84 | | restore([std::error_code&]) | restores protection to its original state | 85 | | release | "releases" protection so it does not get restored on object destruction | 86 | 87 | ### `void protect(Address, protection_t, [std::error_code&])` 88 | Changes protection of a single page that the address is in. 89 | ### `void protect(Address, Address, protection_t, [std::error_code&])` 90 | Changes protections of pages that range of addresses are in. 91 | 92 | ## Address types 93 | In library addresses are 32bit or 64bit unsigned integers or pointers. Conversions are applied 94 | automatically. By default every address that can cause an overflow / underflow is checked and an 95 | std::overflow_error is thrown if the target address type cannot represent the source address type. 96 | 97 | An example of this would be if you called `vmu::query(std::numeric_limits::max() * 2)` 98 | it's pretty obvious that this regions end will definetly overflow the requested 32 bit integer. 99 | -------------------------------------------------------------------------------- /include/vmu/detail/osx/query.inl: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Justas Masiulis 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef VMU_OSX_QUERY_INL 18 | #define VMU_OSX_QUERY_INL 19 | 20 | #include "../../query.hpp" 21 | #include "../error_handlers.hpp" 22 | #include 23 | #include 24 | #include 25 | 26 | namespace vmu { namespace detail { 27 | 28 | constexpr inline bool is_shared(int sharing) noexcept 29 | { 30 | return sharing == SM_SHARED 31 | || sharing == SM_TRUESHARED 32 | || sharing == SM_SHARED_ALIASED; 33 | } 34 | 35 | extern "C" kern_return_t mach_vm_region(vm_map_t target_task 36 | , mach_vm_address_t* address 37 | , mach_vm_size_t* size 38 | , vm_region_flavor_t flavor 39 | , vm_region_info_t info 40 | , mach_msg_type_number_t* infoCnt 41 | , mach_port_t* object_name); 42 | 43 | template 44 | inline basic_region 45 | query_impl(vm_map_t handle, Address address, Handler&& handler) 46 | noexcept(Handler::is_noexcept) 47 | { 48 | // The address is aligned to the enclosing region 49 | auto region_base = address_cast<::mach_vm_address_t>(address); 50 | ::mach_vm_size_t region_size = 0; 51 | ::vm_region_extended_info info; 52 | ::mach_msg_type_number_t info_size = sizeof(::vm_region_extended_info); 53 | ::mach_port_t object_name = 0; 54 | 55 | const auto kr = mach_vm_region(handle 56 | , ®ion_base 57 | , ®ion_size 58 | , VM_REGION_EXTENDED_INFO 59 | , reinterpret_cast<::vm_region_info_t>(&info) 60 | , &info_size 61 | , &object_name); 62 | if(kr != KERN_SUCCESS) { 63 | handler(kr, "mach_vm_region() failed"); 64 | return {}; 65 | } 66 | 67 | if (region_base > address_cast<::mach_vm_address_t>(address)) 68 | return {address_cast(address) 69 | , address_cast(region_base)}; 70 | 71 | return {detail::address_cast_unchecked(region_base) 72 | , advance_ptr(region_base, region_size) 73 | , info.protection 74 | , is_shared(info.share_mode) 75 | , info.user_tag == VM_MEMORY_GUARD}; 76 | } 77 | 78 | }} 79 | 80 | namespace vmu { 81 | 82 | template 83 | inline basic_region query(Address address) 84 | { 85 | return detail::query_impl(::mach_task_self() 86 | , address 87 | , detail::handle_with_exception{}); 88 | }; 89 | template 90 | inline basic_region query(Address address, std::error_code& ec) 91 | { 92 | return detail::query_impl(::mach_task_self() 93 | , address 94 | , detail::handle_with_ec{ec}); 95 | } 96 | 97 | 98 | template 99 | inline basic_region query(native_handle_t handle, Address address) 100 | { 101 | return detail::query_impl(handle 102 | , address 103 | , detail::handle_with_exception{}); 104 | } 105 | template 106 | inline basic_region query(native_handle_t handle 107 | , Address address 108 | , std::error_code& ec) 109 | { 110 | return detail::query_impl(handle 111 | , address 112 | , detail::handle_with_ec{ec}); 113 | } 114 | 115 | } 116 | 117 | #endif // include guard 118 | -------------------------------------------------------------------------------- /include/vmu/detail/windows/query.inl: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Justas Masiulis 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef VMU_WINDOWS_QUERY_INL 18 | #define VMU_WINDOWS_QUERY_INL 19 | 20 | #include "error.hpp" 21 | #include "../../query.hpp" 22 | #include "vmu/detail/address_cast.hpp" 23 | 24 | namespace vmu { namespace detail { 25 | 26 | template 27 | inline basic_region parse_info(const InfoT& info) noexcept 28 | { 29 | const auto end = uintptr_cast(info.BaseAddress) + uintptr_cast(info.RegionSize); 30 | 31 | if(info.State == mem_free) 32 | return {address_cast(info.BaseAddress) 33 | , address_cast(end)}; 34 | 35 | return {address_cast(info.BaseAddress) 36 | , address_cast(end) 37 | , info.State == mem_reserve ? no_access : info.Protect 38 | , (info.Type & mem_private) == 0 39 | , (info.Protect & page_guard) != 0}; 40 | } 41 | 42 | struct native_query { 43 | using address_type = const void*; 44 | 45 | static MEMORY_BASIC_INFORMATION_ query(void* handle, address_type address) 46 | { 47 | MEMORY_BASIC_INFORMATION_ info; 48 | if (detail::VirtualQueryEx(handle 49 | , address 50 | , reinterpret_cast<::_MEMORY_BASIC_INFORMATION*>(&info) 51 | , sizeof(info)) == 0) 52 | throw_last_error("VirtualQueryEx() failed"); 53 | 54 | return info; 55 | } 56 | static MEMORY_BASIC_INFORMATION_ 57 | query(void* handle, address_type address, std::error_code& ec) noexcept 58 | { 59 | MEMORY_BASIC_INFORMATION_ info; 60 | if (detail::VirtualQueryEx(handle 61 | , address 62 | , reinterpret_cast<::_MEMORY_BASIC_INFORMATION*>(&info) 63 | , sizeof(info)) == 0) 64 | ec = get_last_error(); 65 | 66 | return info; 67 | } 68 | }; 69 | 70 | struct wow64_query { 71 | using address_type = std::uint64_t; 72 | 73 | static MEMORY_BASIC_INFORMATION_ query(void* handle, address_type address) 74 | { 75 | if (address >= std::numeric_limits::max()) 76 | throw std::logic_error("not implemented"); 77 | 78 | return native_query::query(handle 79 | , address_cast_unchecked(address)); 80 | } 81 | static MEMORY_BASIC_INFORMATION_ 82 | query(void* handle, address_type address, std::error_code& ec) 83 | { 84 | if (address >= std::numeric_limits::max()) 85 | throw std::logic_error("not implemented"); 86 | 87 | return native_query::query(handle 88 | , address_cast_unchecked(address) 89 | , ec); 90 | } 91 | }; 92 | 93 | #ifdef _WIN64 94 | using remote_query = native_query; 95 | #else 96 | using remote_query = wow64_query; 97 | #endif 98 | 99 | template 100 | inline basic_region query_impl(void* handle, Address address) 101 | { 102 | using addr_t = typename QueryT::address_type; 103 | return parse_info(QueryT::query(handle 104 | , address_cast(address))); 105 | }; 106 | 107 | template 108 | inline basic_region 109 | query_impl(void* handle, Address addr, std::error_code& ec) 110 | noexcept(!detail::ptr_checked::value) 111 | { 112 | using addr_t = typename QueryT::address_type; 113 | return parse_info(QueryT::query(handle 114 | , address_cast(addr) 115 | , ec)); 116 | }; 117 | 118 | }} 119 | 120 | namespace vmu { 121 | 122 | template 123 | inline basic_region query(Address address) 124 | { 125 | return detail::query_impl( 126 | detail::GetCurrentProcess(), address); 127 | } 128 | template 129 | inline basic_region query(Address address, std::error_code& ec) 130 | { 131 | return detail::query_impl( 132 | detail::GetCurrentProcess(), address, ec); 133 | } 134 | 135 | template 136 | inline basic_region query(native_handle_t handle, Address address) 137 | { 138 | return detail::query_impl(handle, address); 139 | } 140 | template 141 | inline basic_region 142 | query(native_handle_t handle, Address address, std::error_code& ec) 143 | { 144 | return detail::query_impl(handle 145 | , address 146 | , ec); 147 | } 148 | 149 | } 150 | 151 | #endif // include guard 152 | -------------------------------------------------------------------------------- /include/vmu/query.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Justas Masiulis 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef VMU_QUERY_HPP 18 | #define VMU_QUERY_HPP 19 | 20 | #include 21 | #include 22 | #include "region.hpp" 23 | #include "detail/native_handle.hpp" 24 | 25 | namespace vmu { 26 | 27 | /// \brief Performs a query over a memory page located at given address. 28 | /// \tparam RegionAddress The type to use for address in basic_region. 29 | /// \tparam Address The type of argument address. 30 | /// \param address The address of page to be queried. 31 | /// \throw Throws std::system_error on failure or std::overflow_error if 32 | /// address overflows. 33 | template 34 | inline basic_region query(Address address); 35 | 36 | /// \brief Performs a query over a memory page located at given address. 37 | /// \tparam RegionAddress The type to use for address in basic_region. 38 | /// \tparam Address The type of argument address. 39 | /// \param address The address of page to be queried. 40 | /// \throw Does not throw if the address does not overflow. 41 | template 42 | inline basic_region query(Address address, std::error_code& ec); 43 | 44 | /// \brief Performs a query over memory pages in range [begin; end) 45 | /// \tparam RegionAddress The type to use for address in basic_region. 46 | /// \tparam Address The type of arguments begin and end. 47 | /// \param begin The beginning of range of pages to query. 48 | /// \param end One pas the end of pages to query. 49 | /// \throw Throws std::system_error on failure or std::overflow_error if 50 | /// begin or end addresses overflow. 51 | template 52 | inline std::vector> 53 | query_range(Address begin, Address end); 54 | 55 | /// \brief Performs a query over memory pages in range [begin; end) 56 | /// \tparam RegionAddress The type to use for region. 57 | /// \tparam Address The type of arguments begin and end. 58 | /// \param begin The beginning of range of pages to query. 59 | /// \param end One pas the end of pages to query. 60 | /// \throw Does not throw if the address does not overflow. 61 | template 62 | inline std::vector> 63 | query_range(Address begin, Address end, std::error_code& ec); 64 | 65 | 66 | /// \brief Performs a query over a memory page located at given address. 67 | /// \tparam RegionAddress The type to use for address in basic_region. 68 | /// \tparam Address The type of argument address. 69 | /// \param handle Handle to the target process. 70 | /// \param address The address of page to be queried. 71 | /// \throw Throws std::system_error on failure or std::overflow_error if 72 | /// address overflows. 73 | template 74 | inline basic_region query(native_handle_t handle, Address address); 75 | 76 | /// \brief Performs a query over a memory page located at given address. 77 | /// \tparam RegionAddress The type to use for address in basic_region. 78 | /// \tparam Address The type of argument address. 79 | /// \param handle Handle to the target process. 80 | /// \param address The address of page to be queried. 81 | /// \throw Does not throw if the address does not overflow. 82 | template 83 | inline basic_region 84 | query(native_handle_t handle, Address address, std::error_code& ec); 85 | 86 | /// \brief Performs a query over memory pages in range [begin; end) 87 | /// \tparam RegionAddress The type to use for address in basic_region. 88 | /// \tparam Address The type of arguments begin and end. 89 | /// \param handle Handle to the target process. 90 | /// \param begin The beginning of range of pages to query. 91 | /// \param end One pas the end of pages to query. 92 | /// \throw Throws std::system_error on failure or std::overflow_error if 93 | /// begin or end addresses overflow. 94 | template 95 | inline std::vector> 96 | query_range(native_handle_t handle, Address begin, Address end); 97 | 98 | /// \brief Performs a query over memory pages in range [begin; end) 99 | /// \tparam RegionAddress The type to use for region. 100 | /// \tparam Address The type of arguments begin and end. 101 | /// \param handle Handle to the target process. 102 | /// \param begin The beginning of range of pages to query. 103 | /// \param end One pas the end of pages to query. 104 | /// \throw Does not throw if the address does not overflow. 105 | template 106 | inline std::vector> 107 | query_range(native_handle_t handle, Address begin, Address end, std::error_code& ec); 108 | 109 | } 110 | 111 | #if defined(_WIN32) 112 | #include "detail/windows/query.inl" 113 | #include "detail/query_range_using_query.inl" 114 | #elif defined(__APPLE__) 115 | #include "detail/osx/query.inl" 116 | #include "detail/query_range_using_query.inl" 117 | #else 118 | #include "detail/linux/query.inl" 119 | #endif 120 | 121 | #endif // include guard 122 | -------------------------------------------------------------------------------- /include/vmu/detail/linux/query.inl: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Justas Masiulis 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef VMU_LINUX_QUERY_INL 18 | #define VMU_LINUX_QUERY_INL 19 | 20 | #include "vmu/detail/address_cast.hpp" 21 | #include "../../query.hpp" 22 | #include 23 | #include 24 | #include 25 | 26 | namespace vmu { namespace detail { 27 | 28 | constexpr inline vmu::protection_t transform_prot(char (&prot)[4]) noexcept 29 | { 30 | return {(prot[0] != '-') | ((prot[1] != '-') * 2) | ((prot[2] != '-') * 4)}; 31 | } 32 | 33 | template 34 | inline void fill_region_gaps(Region& regions) 35 | { 36 | for (std::size_t i = 1; i < regions.size(); ++i) 37 | if (regions[i].begin() != regions[i - 1].end()) { 38 | regions.emplace(regions.begin() + i 39 | , regions[i - 1].end() 40 | , regions[i].begin()); 41 | // increment i twice to skip the newly inserted region 42 | ++i; 43 | } 44 | } 45 | 46 | template 47 | inline basic_region query_impl(std::ifstream& maps, std::uint64_t address) 48 | { 49 | std::uint64_t begin; 50 | std::uint64_t end = 0; 51 | char prot[4]; 52 | 53 | for (; maps; maps.ignore(std::numeric_limits::max(), '\n')) { 54 | maps >> std::hex >> begin; 55 | // address is in free memory and the last end is the beginning of the region 56 | if (begin > address) 57 | return {address_cast(end) 58 | , address_cast(begin)}; 59 | 60 | // ignore the dash between addresses 61 | maps.ignore(); 62 | maps >> std::hex >> end; 63 | 64 | if (end < address) 65 | continue; 66 | 67 | // ignore the space 68 | maps.ignore(); 69 | maps.read(prot, 4); 70 | 71 | return {address_cast(begin) 72 | , address_cast(end) 73 | , transform_prot(prot) 74 | , prot[3] != '-'}; 75 | } 76 | 77 | return {address_cast(end) 78 | , detail::address_cast_unchecked( 79 | std::numeric_limits>::max())}; 80 | } 81 | 82 | template 83 | inline std::vector> 84 | query_range_impl(std::ifstream& maps, std::uint64_t first, std::uint64_t last) 85 | { 86 | std::uint64_t begin; 87 | std::uint64_t end = 0; 88 | char prot[4]; 89 | std::vector> regions; 90 | 91 | for (; maps; maps.ignore(std::numeric_limits::max(), '\n')) { 92 | maps >> std::hex >> begin; 93 | if (begin > last) 94 | break; 95 | 96 | // ignore the dash between addresses 97 | maps.ignore(); 98 | maps >> std::hex >> end; 99 | 100 | if (end < first) 101 | continue; 102 | 103 | // ignore the space 104 | maps.ignore(); 105 | maps.read(prot, 4); 106 | 107 | regions.emplace_back(detail::address_cast(begin) 108 | , detail::address_cast(end) 109 | , transform_prot(prot) 110 | , prot[3] != '-'); 111 | } 112 | 113 | // we now have the regions, but still need to find if there are any gaps and 114 | // fill them with free memory regions 115 | fill_region_gaps(regions); 116 | return regions; 117 | } 118 | 119 | }} 120 | 121 | namespace vmu { 122 | 123 | template 124 | inline basic_region query(Address address) 125 | { 126 | return query(::getpid(), detail::address_cast 127 | (address)); 128 | } 129 | template 130 | inline basic_region query(Address address, std::error_code& ec) 131 | { 132 | return query(::getpid(), address, ec); 133 | } 134 | 135 | template 136 | inline std::vector> query_range(Address begin, Address end) 137 | { 138 | return query_range(::getpid(), begin, end); 139 | } 140 | template 141 | inline std::vector> 142 | query_range(Address begin, Address end, std::error_code& ec) 143 | { 144 | return query_range(::getpid(), begin, end, ec); 145 | } 146 | 147 | 148 | template 149 | inline basic_region query(native_handle_t handle, Address address) 150 | { 151 | std::ifstream maps; 152 | maps.exceptions(std::ifstream::failbit | std::ifstream::badbit); 153 | maps.open("/proc/" + std::to_string(handle) + "/maps"); 154 | 155 | return detail::query_impl(maps, 156 | detail::address_cast(address)); 157 | } 158 | template 159 | inline basic_region query(native_handle_t handle 160 | , Address address 161 | , std::error_code& ec) 162 | { 163 | std::ifstream maps("/proc/" + std::to_string(static_cast(handle)) + "/maps"); 164 | if (!maps.is_open()) { 165 | ec = std::make_error_code(std::errc::io_error); 166 | return {}; 167 | } 168 | 169 | return detail::query_impl(maps, 170 | detail::address_cast(address)); 171 | } 172 | 173 | template 174 | inline std::vector> 175 | query_range(native_handle_t handle, Address begin, Address end) 176 | { 177 | std::ifstream maps; 178 | maps.exceptions(std::ifstream::failbit | std::ifstream::badbit); 179 | maps.open("/proc/" + std::to_string(handle) + "/maps"); 180 | 181 | return detail::query_range_impl(maps, 182 | detail::address_cast(begin), 183 | detail::address_cast(end)); 184 | } 185 | template 186 | inline std::vector> 187 | query_range(native_handle_t handle, Address begin, Address end, std::error_code& ec) 188 | { 189 | std::ifstream maps("/proc/" + std::to_string(static_cast(handle)) + "/maps"); 190 | if (!maps.is_open()) { 191 | ec = std::make_error_code(std::errc::io_error); 192 | return {}; 193 | } 194 | 195 | return detail::query_range_impl(maps, 196 | detail::address_cast(begin), 197 | detail::address_cast(end)); 198 | } 199 | 200 | } 201 | 202 | #endif // include guard 203 | -------------------------------------------------------------------------------- /include/vmu/protection_guard.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Justas Masiulis 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef VMU_PROTECTION_GUARD_HPP 18 | #define VMU_PROTECTION_GUARD_HPP 19 | 20 | #include 21 | #include "query.hpp" 22 | #include "protect.hpp" 23 | #include "address_concept.hpp" 24 | 25 | namespace vmu { 26 | 27 | struct adopt_protection_t { 28 | explicit adopt_protection_t() = default; 29 | }; 30 | 31 | /// \brief Provides a RAII based page protection 32 | class protection_guard { 33 | struct old_prot_storage { 34 | std::uintptr_t begin; 35 | std::uintptr_t end; 36 | native_protection_t prot; 37 | }; 38 | 39 | std::vector _old; 40 | 41 | public: 42 | /// \brief Restores the memory protection to its state before the 43 | /// protection_guard constructor was called. \throws Does not throw. \note 44 | /// May not actually restore memory protection back to its original state. 45 | /// In critical code sections prefer to manually call restore member 46 | /// function. This behaviour may be overriden by defining a 47 | /// VMU_HANDLE_PG_DESTRUCTOR_FAILURE macro. 48 | ~protection_guard() 49 | { 50 | std::error_code ec; 51 | for (const auto& ele : _old) { 52 | protect(ele.begin, ele.end, ele.prot, ec); 53 | #ifdef VMU_HANDLE_PG_DESTRUCTOR_FAILURE 54 | if (ec) { 55 | VMU_HANDLE_PG_DESTRUCTOR_FAILURE(ec); 56 | } 57 | #endif 58 | } 59 | } 60 | 61 | /// \brief Changes protection of a single page to given protection. 62 | /// \param address The address that is situated in page whose protection is 63 | /// to be changed. \param new_protection The new protection to be applied to 64 | /// the page. 65 | template 66 | protection_guard(Address address, protection_t new_protection) 67 | { 68 | const auto fixed_address = 69 | detail::uintptr_cast(address) & ~(page_size() - 1); 70 | const auto old = query(address); 71 | _old.reserve(1); 72 | _old.push_back( 73 | { fixed_address, fixed_address + 1, old.protection().native() }); 74 | protect(address, new_protection); 75 | } 76 | 77 | /// \brief Changes protection of pages between range [begin; end) to given 78 | /// protection. \param begin The beginning of the memory range to apply new 79 | /// protection to. \param end One pas the end of the memory range to apply 80 | /// new protection to. \param new_protection The new protection to be applied 81 | /// to the pages. 82 | template 83 | protection_guard(Address begin, Address end, protection_t new_protection) 84 | { 85 | const auto regions = query_range(begin, end); 86 | _old.reserve(regions.size()); 87 | for (auto& region : regions) { 88 | const auto region_begin = 89 | std::max(region.begin(), 90 | detail::address_cast_unchecked(begin)); 91 | 92 | // NOTE this might be bad on osx 93 | const auto region_end = 94 | std::min(region.end(), 95 | detail::address_cast_unchecked(end)); 96 | 97 | _old.push_back( 98 | { region_begin, region_end, region.protection().native() }); 99 | } 100 | 101 | protect(begin, end, new_protection); 102 | } 103 | 104 | /// \brief Changes protection of pages that the given range crosses to given 105 | /// protection. \param range The memory range whose protection is to be 106 | /// changed. \param new_protection The new protection to be applied to the 107 | /// pages. 108 | template::value>::type> 110 | protection_guard(const Range& range, protection_t new_protection) 111 | : protection_guard(range.begin(), range.end(), new_protection) 112 | {} 113 | 114 | /// \brief Changes protection of a single page to given protection when the 115 | /// protection_guard object is destructed. \param range The memory range 116 | /// whose protection is to be changed. \param new_protection The new 117 | /// protection to be applied to the pages. 118 | template 119 | protection_guard(Address address, 120 | protection_t restore_to, 121 | adopt_protection_t) 122 | { 123 | const auto fixed_address = detail::uintptr_cast(address) & -page_size(); 124 | _old.reserve(1); 125 | _old.push_back({ fixed_address, fixed_address + 1, restore_to }); 126 | } 127 | 128 | /// \brief Changes the protection of pages in memory range [begin; end) upon 129 | /// destruction of protection_guard object \param range The memory range 130 | /// whose protection is to be changed. \param new_protection The new 131 | /// protection to be applied to the pages. 132 | template 133 | protection_guard(Address begin, 134 | Address end, 135 | protection_t restore_to, 136 | adopt_protection_t) 137 | { 138 | _old.reserve(1); 139 | _old.emplace_back(detail::address_cast_unchecked(begin), 140 | detail::address_cast(end), 141 | restore_to); 142 | } 143 | 144 | template 145 | protection_guard(const Range& r, protection_t prot, adopt_protection_t) 146 | : protection_guard(r.begin(), r.end(), prot, adopt_protection_t{}) 147 | {} 148 | 149 | 150 | /// \brief not copy constructible 151 | protection_guard(const protection_guard&) = delete; 152 | /// \brief not copy assignable 153 | protection_guard& operator=(const protection_guard&) = delete; 154 | 155 | /// \brief Restores the memory protection back to its previous state. 156 | void restore() 157 | { 158 | while (!_old.empty()) { 159 | const auto& back = _old.back(); 160 | protect(back.begin, back.end, back.prot); 161 | _old.pop_back(); 162 | } 163 | } 164 | void restore(std::error_code& ec) noexcept 165 | { 166 | while (!_old.empty()) { 167 | const auto& back = _old.back(); 168 | protect(back.begin, back.end, back.prot, ec); 169 | if (ec) 170 | return; 171 | 172 | _old.pop_back(); 173 | } 174 | } 175 | 176 | /// \brief Releases protections to restore. 177 | /// \throws Should not throw due to the fact that shrink_to_fit is called on 178 | /// empty vector. 179 | void release() 180 | { 181 | _old.clear(); 182 | _old.shrink_to_fit(); 183 | } 184 | }; 185 | 186 | } // namespace vmu 187 | 188 | #endif // include guard 189 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | --------------------------------------------------------------------------------