From 286f2e028a368322d8db0b63bf6d99548ede2cdd Mon Sep 17 00:00:00 2001
From: yzh <570350928@qq.com>
Date: Mon, 1 Dec 2025 21:21:54 +0800
Subject: [PATCH] mockcpp_support_arm64.patch
include/mockcpp/ApiHookFunctor.h | 127 ++++++++++++++-----
include/mockcpp/ApiHookGenerator.h | 8 +-
include/mockcpp/ApiHookHolderFactory.h | 2 +-
include/mockcpp/ApiHookMocker.h | 113 ++++++++++++++++-
include/mockcpp/ChainableMockMethod.h | 3 +-
include/mockcpp/ChainableMockMethodCore.h | 1 +
include/mockcpp/GlobalMockObject.h | 15 +++
include/mockcpp/GnuMethodInfoReader.h | 4 +
include/mockcpp/Invocation.h | 5 +
include/mockcpp/Invokable.h | 1 +
include/mockcpp/JmpCode.h | 1 +
include/mockcpp/ParameterizedApiHookHolder.h | 2 +-
include/mockcpp/mockcpp.h | 6 +-
include/mockcpp/mokc.h | 4 +-
src/ChainableMockMethodCore.cpp | 3 +-
src/Invocation.cpp | 23 ++++
src/JmpCode.cpp | 16 ++-
src/JmpCodeAARCH64.h | 69 ++++++++++
src/JmpCodeARM32.h | 36 ++++++
src/JmpCodeArch.h | 20 ++-
src/JmpCodeX64.h | 3 +-
src/JmpCodeX86.h | 3 +-
src/JmpOnlyApiHook.cpp | 1 +
src/UnixCodeModifier.cpp | 16 ++-
24 files changed, 424 insertions(+), 58 deletions(-)
create mode 100644 src/JmpCodeAARCH64.h
create mode 100644 src/JmpCodeARM32.h
@@ -20,6 +20,7 @@
#include <mockcpp/mockcpp.h>
#include <mockcpp/GlobalMockObject.h>
+#include <mockcpp/ArgumentsMacroHelpers.h>
MOCKCPP_NS_START
@@ -30,20 +31,21 @@ struct ApiHookFunctor
};
const std::string empty_caller("");
-#define __MOCKCPP_API_HOOK_FUNCTOR_DEF(n, CallingConvention) \
-template <typename R DECL_TEMPLATE_ARGS(n), unsigned int Seq> \
-struct ApiHookFunctor<R CallingConvention (DECL_ARGS(n)), Seq> \
+
+#define __MOCKCPP_C_API_HOOK_FUNCTOR_DEF(n, CallingConvention) \
+template<typename R DECL_TEMPLATE_ARGS(n), unsigned int Seq> \
+struct ApiHookFunctor<R (CallingConvention *)(DECL_ARGS(n)), Seq> \
{ \
private: \
- typedef R CallingConvention F (DECL_ARGS(n)); \
+ typedef R (CallingConvention *F) (DECL_ARGS(n)); \
\
static R CallingConvention hook(DECL_PARAMS_LIST(n)) \
{ \
- return GlobalMockObject::instance.invoke<R>(apiAddress) \
- (empty_caller DECL_REST_PARAMS(n)); \
+ return GlobalMockObject::instance.invoke<R>(apiAddress) \
+ (empty_caller, RefAny() DECL_REST_PARAMS(n)); \
} \
\
- static bool appliedBy(F* api) \
+ static bool appliedBy(F api) \
{ return apiAddress == reinterpret_cast<void*>(api); } \
\
static void* getHook() \
@@ -53,51 +55,112 @@ private: \
{ if(--refCount == 0) apiAddress = 0; } \
public: \
\
- static void* getApiHook(F* api) \
+ static void* getApiHook(F api) \
+ { \
+ if(!appliedBy(api)) return 0; \
+ ++refCount; \
+ return getHook(); \
+ } \
+ \
+ static void* applyApiHook(F api) \
+ { \
+ if(apiAddress != 0) return 0; \
+ apiAddress = reinterpret_cast<void*>(api); \
+ refCount = 1; \
+ return getHook(); \
+ } \
+ \
+ static bool freeApiHook(void* hook) \
+ { \
+ if(getHook() != hook) return false; \
+ freeHook(); \
+ return true; \
+ } \
+private: \
+ static void* apiAddress; \
+ static unsigned int refCount; \
+}; \
+template<typename R DECL_TEMPLATE_ARGS(n), unsigned int Seq> \
+void* ApiHookFunctor<R (CallingConvention *)(DECL_ARGS(n)), Seq>::apiAddress = 0; \
+template<typename R DECL_TEMPLATE_ARGS(n), unsigned int Seq> \
+unsigned int ApiHookFunctor<R (CallingConvention *)(DECL_ARGS(n)), Seq>::refCount = 0
+
+/* For C++ method */
+#define __MOCKCPP_CXX_API_HOOK_FUNCTOR_DEF(n, CallingConvention, ConstConvention) \
+template<typename C, typename R DECL_TEMPLATE_ARGS(n), unsigned int Seq> \
+struct ApiHookFunctor<R (CallingConvention C::*)(DECL_ARGS(n)) ConstConvention, Seq> \
+{ \
+private: \
+ typedef ApiHookFunctor<R (CallingConvention C::*)(DECL_ARGS(n)) ConstConvention, Seq> ThisType; \
+ typedef R (CallingConvention C::*F) (DECL_ARGS(n)) ConstConvention; \
+ \
+ R CallingConvention hook(DECL_PARAMS_LIST(n)) \
+ { \
+ C *This = reinterpret_cast<C *>(this); \
+ return GlobalMockObject::instance.invoke<R>(apiAddress) \
+ (empty_caller, This DECL_REST_PARAMS(n)); \
+ } \
+ \
+ static bool appliedBy(F api) \
+ { return apiAddress == Details::methodToAddr(api); } \
+ \
+ static void* getHook() \
+ { return Details::methodToAddr(&ThisType::hook); } \
+ \
+ static void freeHook() \
+ { if(--refCount == 0) apiAddress = 0; } \
+public: \
+ \
+ static void* getApiHook(F api) \
{ \
- if(! appliedBy(api)) return 0; \
- ++refCount; \
- return getHook(); \
+ if(!appliedBy(api)) return 0; \
+ ++refCount; \
+ return getHook(); \
} \
\
- static void* applyApiHook(F* api) \
+ static void* applyApiHook(F api) \
{ \
- if(apiAddress != 0) return 0; \
- apiAddress = reinterpret_cast<void*>(api); \
- refCount = 1; \
- return getHook(); \
+ if(apiAddress != 0) return 0; \
+ apiAddress = Details::methodToAddr(api); \
+ refCount = 1; \
+ return getHook(); \
} \
\
static bool freeApiHook(void* hook) \
{ \
- if(getHook() != hook) return false; \
- freeHook(); \
- return true; \
+ if(getHook() != hook) return false; \
+ freeHook(); \
+ return true; \
} \
private: \
static void* apiAddress; \
static unsigned int refCount; \
}; \
-template <typename R DECL_TEMPLATE_ARGS(n), unsigned int Seq> \
-void* ApiHookFunctor<R CallingConvention (DECL_ARGS(n)), Seq>::apiAddress = 0; \
-template <typename R DECL_TEMPLATE_ARGS(n), unsigned int Seq> \
-unsigned int ApiHookFunctor<R CallingConvention (DECL_ARGS(n)), Seq>::refCount = 0
+template<typename C, typename R DECL_TEMPLATE_ARGS(n), unsigned int Seq> \
+void* ApiHookFunctor<R (CallingConvention C::*)(DECL_ARGS(n)) ConstConvention, Seq>::apiAddress = 0; \
+template<typename C, typename R DECL_TEMPLATE_ARGS(n), unsigned int Seq> \
+unsigned int ApiHookFunctor<R (CallingConvention C::*)(DECL_ARGS(n)) ConstConvention, Seq>::refCount = 0
-#if defined(_MSC_VER)
-// TODO: ApiHook related tests failed on VS2019.
-// [ ERROR ] TestApiHook.h:66: hardware exception STATUS_ILLEGAL_INSTRUCTION raised in setup or running test
-// [ ERROR ] TestApiHook.h:66 : hardware exception STATUS_ACCESS_VIOLATION raised in teardown
-#if _MSC_VER >= 1920 // VS 2019
+#ifdef WIN32
+#if defined(_MSC_VER) && defined(BUILD_FOR_X86)
#define MOCKCPP_API_HOOK_FUNCTOR_DEF(n) \
-__MOCKCPP_API_HOOK_FUNCTOR_DEF(n, __stdcall)
+__MOCKCPP_C_API_HOOK_FUNCTOR_DEF(n, ); \
+__MOCKCPP_C_API_HOOK_FUNCTOR_DEF(n, __stdcall); \
+__MOCKCPP_CXX_API_HOOK_FUNCTOR_DEF(n, , ); \
+__MOCKCPP_CXX_API_HOOK_FUNCTOR_DEF(n, , const); \
+__MOCKCPP_CXX_API_HOOK_FUNCTOR_DEF(n, __stdcall, ); \
+__MOCKCPP_CXX_API_HOOK_FUNCTOR_DEF(n, __stdcall, const)
#else
#define MOCKCPP_API_HOOK_FUNCTOR_DEF(n) \
-__MOCKCPP_API_HOOK_FUNCTOR_DEF(n, ); \
-__MOCKCPP_API_HOOK_FUNCTOR_DEF(n, __stdcall)
+__MOCKCPP_C_API_HOOK_FUNCTOR_DEF(n, ); \
+__MOCKCPP_CXX_API_HOOK_FUNCTOR_DEF(n, , ); \
+__MOCKCPP_CXX_API_HOOK_FUNCTOR_DEF(n, , const)
#endif
#else
#define MOCKCPP_API_HOOK_FUNCTOR_DEF(n) \
-__MOCKCPP_API_HOOK_FUNCTOR_DEF(n, )
+__MOCKCPP_C_API_HOOK_FUNCTOR_DEF(n, ); \
+__MOCKCPP_CXX_API_HOOK_FUNCTOR_DEF(n, , ); \
+__MOCKCPP_CXX_API_HOOK_FUNCTOR_DEF(n, , const)
#endif
MOCKCPP_API_HOOK_FUNCTOR_DEF(0);
@@ -26,7 +26,7 @@ MOCKCPP_NS_START
template <typename F, unsigned int Seq>
struct ApiHookGenerator
{
- static void* findApiHook(F* api)
+ static void* findApiHook(F api)
{
void* hook;
@@ -36,7 +36,7 @@ struct ApiHookGenerator
return hook;
}
- static void* appyApiHook(F* api)
+ static void* appyApiHook(F api)
{
void* hook;
@@ -61,10 +61,10 @@ private:
template <typename F>
struct ApiHookGenerator<F, 0>
{
- static void* findApiHook(F* api)
+ static void* findApiHook(F api)
{ return 0; }
- static void* appyApiHook(F* api)
+ static void* appyApiHook(F api)
{
oss_t oss;
@@ -27,7 +27,7 @@ struct ApiHookHolder;
struct ApiHookHolderFactory
{
template <typename F>
- static ApiHookHolder* create(F* api)
+ static ApiHookHolder* create(F api)
{
return new ParameterizedApiHookHolder<F>(api);
}
@@ -21,18 +21,119 @@
#include <mockcpp/mockcpp.h>
#include <mockcpp/GlobalMockObject.h>
#include <mockcpp/ApiHookHolderFactory.h>
+#include <mockcpp/ArgumentsMacroHelpers.h>
+#include <mockcpp/MethodInfoReader.h>
+#include <mockcpp/DelegatedMethodGetter.h>
MOCKCPP_NS_START
-template <typename API>
-InvocationMockBuilderGetter mockAPI(const std::string& name, API* api)
+struct mockAPIauto {};
+template<typename API = mockAPIauto> struct mockAPI;
+
+template<typename API> struct mockAPI
{
+ static InvocationMockBuilderGetter get(
+ const std::string& name, const std::string& type, API api)
+ {
+ return MOCKCPP_NS::GlobalMockObject::instance.method
+ ( type.empty() ? name : name + " #" + type + "#"
+ , Details::methodToAddr(api)
+ , ApiHookHolderFactory::create(api));
+ }
+
+ template<typename C>
+ static InvocationMockBuilderGetter get_virtual(
+ const std::string& name, const std::string& type, const C *c, API api)
+ {
+ void ***vtbl = (void ***)c;
+ std::pair<unsigned int, unsigned int> indices =
+ getIndicesOfMethod<C, API>(api);
+ union { void *_addr; API _api; };
+ _addr = (*vtbl)[indices.second];
return MOCKCPP_NS::GlobalMockObject::instance.method
- ( name
- , reinterpret_cast<const void*>(api)
- , ApiHookHolderFactory::create(api));
-}
+ ( type.empty() ? name : name + " #" + type + "#"
+ , _addr
+ , ApiHookHolderFactory::create(_api));
+ }
+
+ template<typename C>
+ static InvocationMockBuilderGetter get_virtual(
+ const std::string& name, const std::string& type, const C &c, API api)
+ {
+ return get_virtual(name, type, &c, api);
+ }
+}; // struct mockAPI
+
+template<> struct mockAPI<mockAPIauto>
+{
+#define __MOCKCPP_C_API_GET_FUNCTION_DEF(n, CallingConvention) \
+ template<typename R DECL_TEMPLATE_ARGS(n)> \
+ static InvocationMockBuilderGetter get( \
+ const std::string& name, const std::string& type, R (CallingConvention *api)(DECL_ARGS(n))) \
+ { \
+ typedef R (CallingConvention *API)(DECL_ARGS(n)); \
+ return mockAPI<API>::get(name, type, api); \
+ }
+
+#define __MOCKCPP_CXX_API_GET_FUNCTION_DEF(n, CallingConvention, ConstMethod) \
+ template<typename R, typename C DECL_TEMPLATE_ARGS(n)> \
+ static InvocationMockBuilderGetter get( \
+ const std::string& name, const std::string& type, R (CallingConvention C::*api)(DECL_ARGS(n)) ConstMethod) \
+ { \
+ typedef R (CallingConvention C::*API)(DECL_ARGS(n)) ConstMethod; \
+ return mockAPI<API>::get(name, type, api); \
+ } \
+ template<typename R, typename C DECL_TEMPLATE_ARGS(n)> \
+ static InvocationMockBuilderGetter get_virtual( \
+ const std::string& name, const std::string& type, const C *c, R (CallingConvention C::*api)(DECL_ARGS(n)) ConstMethod) \
+ { \
+ typedef R (CallingConvention C::*API)(DECL_ARGS(n)) ConstMethod; \
+ return mockAPI<API>::get_virtual(name, type, c, api); \
+ } \
+ template<typename R, typename C DECL_TEMPLATE_ARGS(n)> \
+ static InvocationMockBuilderGetter get_virtual( \
+ const std::string& name, const std::string& type, const C &c, R (CallingConvention C::*api)(DECL_ARGS(n)) ConstMethod) \
+ { \
+ typedef R (CallingConvention C::*API)(DECL_ARGS(n)) ConstMethod; \
+ return mockAPI<API>::get_virtual(name, type, c, api); \
+ }
+
+#ifdef WIN32
+#if defined(_MSC_VER) && defined(BUILD_FOR_X86)
+#define MOCKCPP_API_GET_FUNCTION_DEF(n) \
+ __MOCKCPP_C_API_GET_FUNCTION_DEF(n, ); \
+ __MOCKCPP_C_API_GET_FUNCTION_DEF(n, __stdcall); \
+ __MOCKCPP_CXX_API_GET_FUNCTION_DEF(n, , ); \
+ __MOCKCPP_CXX_API_GET_FUNCTION_DEF(n, , const); \
+ __MOCKCPP_CXX_API_GET_FUNCTION_DEF(n, __stdcall, ); \
+ __MOCKCPP_CXX_API_GET_FUNCTION_DEF(n, __stdcall, const)
+#else
+#define MOCKCPP_API_GET_FUNCTION_DEF(n) \
+ __MOCKCPP_C_API_GET_FUNCTION_DEF(n, ); \
+ __MOCKCPP_CXX_API_GET_FUNCTION_DEF(n, , ); \
+ __MOCKCPP_CXX_API_GET_FUNCTION_DEF(n, , const)
+#endif
+#else
+#define MOCKCPP_API_GET_FUNCTION_DEF(n) \
+ __MOCKCPP_C_API_GET_FUNCTION_DEF(n, ); \
+ __MOCKCPP_CXX_API_GET_FUNCTION_DEF(n, , ); \
+ __MOCKCPP_CXX_API_GET_FUNCTION_DEF(n, , const)
+#endif
+ MOCKCPP_API_GET_FUNCTION_DEF(0);
+ MOCKCPP_API_GET_FUNCTION_DEF(1);
+ MOCKCPP_API_GET_FUNCTION_DEF(2);
+ MOCKCPP_API_GET_FUNCTION_DEF(3);
+ MOCKCPP_API_GET_FUNCTION_DEF(4);
+ MOCKCPP_API_GET_FUNCTION_DEF(5);
+ MOCKCPP_API_GET_FUNCTION_DEF(6);
+ MOCKCPP_API_GET_FUNCTION_DEF(7);
+ MOCKCPP_API_GET_FUNCTION_DEF(8);
+ MOCKCPP_API_GET_FUNCTION_DEF(9);
+ MOCKCPP_API_GET_FUNCTION_DEF(10);
+ MOCKCPP_API_GET_FUNCTION_DEF(11);
+ MOCKCPP_API_GET_FUNCTION_DEF(12);
+}; // struct mockAPI<mockAPIauto>
MOCKCPP_NS_END
@@ -39,6 +39,7 @@ struct ChainableMockMethodBase
{}
RT operator()( const std::string& nameOfCaller
+ , const RefAny& pThisPointer = RefAny()
, const RefAny& p01 = RefAny()
, const RefAny& p02 = RefAny()
, const RefAny& p03 = RefAny()
@@ -57,7 +58,7 @@ struct ChainableMockMethodBase
try {
const Any& result = \
- invokable->invoke( nameOfCaller
+ invokable->invoke( nameOfCaller, pThisPointer
, p01, p02, p03, p04, p05, p06
, p07, p08, p09, p10, p11, p12
, resultProvider);
@@ -46,6 +46,7 @@ public:
// Method
const Any&
invoke( const std::string& nameOfCaller
+ , const RefAny& pThisPointer
, const RefAny& p1
, const RefAny& p2
, const RefAny& p3
@@ -42,6 +42,21 @@ struct GlobalMockObject
static MockObjectType instance;
};
+namespace Details {
+ template<typename Method>
+ void *methodToAddr(Method m)
+ {
+ union
+ {
+ void *addr_;
+ Method m_;
+ };
+
+ m_ = m;
+ return addr_;
+ }
+} // namespace Details
+
MOCKCPP_NS_END
#endif
@@ -73,6 +73,10 @@ GnuMethodDescription getGnuDescOfVirtualMethod(Method input)
MethodDescriptionUnion<ExpectedMethodType> m;
m.method = input;
+#if defined(__arm__) || defined(__aarch64__)
+ m.desc.u.index++;
+#endif
+
oss_t oss;
oss << "Virtual method address should be odd, please make sure the method "
<< TypeString<Method>::value() << " is a virtual method";
@@ -32,6 +32,7 @@ struct InvocationImpl;
struct Invocation
{
Invocation(const std::string nameOfCaller
+ , const RefAny& pThisPointer = RefAny()
, const RefAny& p01 = RefAny()
, const RefAny& p02 = RefAny()
, const RefAny& p03 = RefAny()
@@ -48,8 +49,12 @@ struct Invocation
virtual ~Invocation();
+ RefAny& getThisPointer(void) const;
+
RefAny& getParameter(const unsigned int i) const;
+ RefAny& getParameterWithThis(const unsigned int i) const;
+
std::string getNameOfCaller() const;
std::string toString(void) const;
@@ -35,6 +35,7 @@ struct Invokable
{
virtual const Any&
invoke( const std::string& nameOfCaller
+ , const RefAny& pThisPointer
, const RefAny& p1
, const RefAny& p2
, const RefAny& p3
@@ -33,6 +33,7 @@ struct JmpCode
void* getCodeData() const;
size_t getCodeSize() const;
+ void flushCache() const;
private:
JmpCodeImpl* This;
};
@@ -30,7 +30,7 @@ struct ParameterizedApiHookHolder
{
const static unsigned int maxSeq = 10;
- ParameterizedApiHookHolder(F* api)
+ ParameterizedApiHookHolder(F api)
{
(m_hook = ApiHookGenerator<F, maxSeq>::findApiHook(api)) ||
(m_hook = ApiHookGenerator<F, maxSeq>::appyApiHook(api));
@@ -39,7 +39,11 @@
#endif
-#if ( defined (__LP64__) \
+#if defined (__aarch64__)
+#define BUILD_FOR_AARCH64
+#elif defined (__arm__)
+#define BUILD_FOR_ARM32
+#elif ( defined (__LP64__) \
|| defined (__64BIT__) \
|| defined (_LP64) \
|| ((defined(__WORDSIZE)) && (__WORDSIZE == 64)) \
@@ -27,7 +27,9 @@
# define MOCKER(api) MOCKCPP_NS::GlobalMockObject::instance.method(#api)
# else
# include <mockcpp/ApiHookMocker.h>
-# define MOCKER(api) MOCKCPP_NS::mockAPI(#api, api)
+# define MOCKER(api, ...) MOCKCPP_NS::mockAPI<__VA_ARGS__>::get(#api, ""#__VA_ARGS__, api)
+# define MOCKER_CPP(api, ...) MOCKCPP_NS::mockAPI<__VA_ARGS__>::get(#api, ""#__VA_ARGS__, api)
+# define MOCKER_CPP_VIRTUAL(obj, api, ...) MOCKCPP_NS::mockAPI<__VA_ARGS__>::get_virtual(#api, ""#__VA_ARGS__, obj, api)
# endif
USING_MOCKCPP_NS
@@ -149,6 +149,7 @@ ChainableMockMethodCore::getName() const
const Any&
ChainableMockMethodCore::invoke
( const std::string& nameOfCaller
+ , const RefAny& pThisPointer
, const RefAny& p1
, const RefAny& p2
, const RefAny& p3
@@ -163,7 +164,7 @@ ChainableMockMethodCore::invoke
, const RefAny& p12
, SelfDescribe* &resultProvider)
{
- Invocation inv(nameOfCaller,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12);
+ Invocation inv(nameOfCaller,pThisPointer,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12);
return This->invoke(inv, resultProvider);
}
@@ -35,6 +35,7 @@ struct InvocationImpl
{
std::vector<RefAny> parameters;
std::string nameOfCaller;
+ RefAny thisPointer;
std::string toString(void) const;
@@ -70,6 +71,7 @@ std::string InvocationImpl::toString() const
Invocation::Invocation(
const std::string name
+ , const RefAny& pThisPointer
, const RefAny& p1
, const RefAny& p2
, const RefAny& p3
@@ -85,6 +87,7 @@ Invocation::Invocation(
)
: This(new InvocationImpl(name))
{
+ This->thisPointer = pThisPointer;
INIT_PARAMETER(1);
INIT_PARAMETER(2);
INIT_PARAMETER(3);
@@ -106,6 +109,11 @@ Invocation::~Invocation()
}
////////////////////////////////////////////////////////////////
+RefAny& Invocation::getThisPointer(void) const
+{
+ return This->thisPointer;
+}
+
RefAny& Invocation::getParameter(const unsigned int i) const
{
if (i < 1 || i > maxNumOfParameters )
@@ -116,6 +124,21 @@ RefAny& Invocation::getParameter(const unsigned int i) const
return This->parameters[i-1];
}
+RefAny& Invocation::getParameterWithThis(const unsigned int i) const
+{
+ if (This->thisPointer.empty())
+ {
+ return getParameter(i);
+ }
+
+ if (1 == i)
+ {
+ return This->thisPointer;
+ }
+
+ return getParameter(i - 1);
+}
+
////////////////////////////////////////////////////////////////
std::string Invocation::toString(void) const
{
@@ -30,6 +30,7 @@ struct JmpCodeImpl
////////////////////////////////////////////////
JmpCodeImpl(const void* from, const void* to)
{
+ m_from = from;
::memcpy(m_code, jmpCodeTemplate, JMP_CODE_SIZE);
SET_JMP_CODE(m_code, from, to);
}
@@ -47,7 +48,14 @@ struct JmpCodeImpl
}
////////////////////////////////////////////////
+ void flushCache() const
+ {
+ FLUSH_CACHE((const char *)m_from, JMP_CODE_SIZE);
+ }
+ ////////////////////////////////////////////////
+
+ const void *m_from;
unsigned char m_code[JMP_CODE_SIZE];
};
@@ -77,5 +85,11 @@ JmpCode::getCodeSize() const
return This->getCodeSize();
}
-MOCKCPP_NS_END
+///////////////////////////////////////////////////
+void
+JmpCode::flushCache() const
+{
+ return This->flushCache();
+}
+MOCKCPP_NS_END
new file mode 100644
@@ -0,0 +1,69 @@
+/***
+ mockcpp is a C/C++ mock framework.
+ Copyright [2008] [Darwin Yuan <darwin.yuan@gmail.com>]
+ [Chen Guodong <sinojelly@gmail.com>]
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+***/
+#ifndef __MOCKCPP_JMP_CODE_AARCH64_H__
+#define __MOCKCPP_JMP_CODE_AARCH64_H__
+
+#include <asm/unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/prctl.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+
+MOCKCPP_NS_START
+
+struct l2cache_addr_range {
+ uintptr_t start;
+ uintptr_t end;
+};
+
+MOCKCPP_NS_END
+
+#define ADDR_ALIGN_UP(addr) ((((addr) + ((4096) - 1)) & (~((4096) - 1))) & 0xffffffffffffffff)
+#define ADDR_ALIGN_DOWN(addr) (((addr) & (~((4096) - 1))) & 0xffffffffffffffff)
+#define OUTER_CACHE_INV_RANGE _IOWR('S', 0x00, struct l2cache_addr_range)
+#define OUTER_CACHE_CLEAN_RANGE _IOWR('S', 0x01, struct l2cache_addr_range)
+#define OUTER_CACHE_FLUSH_RANGE _IOWR('S', 0x02, struct l2cache_addr_range)
+#define L1_INV_I_CACHE _IOWR('S', 0x03, struct l2cache_addr_range)
+#define D_TO_I_CACHE_FLUSH_RANGE _IOWR('S', 0x04, struct l2cache_addr_range)
+
+const unsigned char jmpCodeTemplate[] =
+ { 0x57, 0x00, 0x00, 0x58, 0xe0, 0x02, 0x1f, 0xd6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+#define SET_SJMP_CODE(base, from, to) do { \
+ using instruct_t = signed int; \
+ instruct_t offset = (intptr_t)to - (intptr_t)from; \
+ offset = ((offset >> 2) & 0x03FFFFFF) | 0x14000000; \
+ *(instruct_t *)(base) = offset; \
+ } while(0)
+
+#define SET_JMP_CODE(base, from, to) do { \
+ *(void **)(base + 8) = (void *)to; \
+ } while(0)
+
+#define FLUSH_CACHE(from, length) do { \
+ struct l2cache_addr_range usr_data; \
+ usr_data.start = ADDR_ALIGN_DOWN((unsigned long long)from); \
+ usr_data.end = ADDR_ALIGN_UP((unsigned long long)from) + length; \
+ __builtin___clear_cache((char *)usr_data.start, (char *)usr_data.end); \
+} while (0)
+
+#endif
new file mode 100644
@@ -0,0 +1,36 @@
+/***
+ mockcpp is a C/C++ mock framework.
+ Copyright [2008] [Darwin Yuan <darwin.yuan@gmail.com>]
+ [Chen Guodong <sinojelly@gmail.com>]
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+***/
+#ifndef __MOCKCPP_JMP_CODE_ARM32_H__
+#define __MOCKCPP_JMP_CODE_ARM32_H__
+
+#include <stdlib.h>
+
+const unsigned char jmpCodeTemplate[] =
+ { 0xEA, 0x00, 0x00, 0x00 };
+
+#define SET_JMP_CODE(base, from, to) do { \
+ int offset = (int)to - (int)from - 8; \
+ offset = (offset >> 2) & 0x00FFFFFF; \
+ int code = *(int *)(base) | offset; \
+ *(int *)(base) = changeByteOrder(code); \
+ } while(0)
+
+#define FLUSH_CACHE(from, length) do { \
+ ::system("echo 3 > /proc/sys/vm/drop_caches"); \
+} while (0)
+
+#endif
@@ -19,11 +19,29 @@
#include <mockcpp/mockcpp.h>
+template <typename T>
+inline T changeByteOrder(const T v) {
+ enum { S = sizeof(T) };
+ T rst = v;
+ char *p = (char *)&rst;
+ char tmp = 0;
+ for (unsigned int i = 0; i < S / 2; ++i) {
+ tmp = p[i];
+ p[i] = p[S - i - 1];
+ p [S - i - 1] = tmp;
+ }
+
+ return rst;
+}
+
#if BUILD_FOR_X64
# include "JmpCodeX64.h"
#elif BUILD_FOR_X86
# include "JmpCodeX86.h"
+#elif defined(BUILD_FOR_ARM32)
+# include "JmpCodeARM32.h"
+#elif defined(BUILD_FOR_AARCH64)
+# include "JmpCodeAARCH64.h"
#endif
#endif
-
@@ -27,5 +27,6 @@ const unsigned char jmpCodeTemplate[] =
*(uintptr_t *)(base + 6) = (uintptr_t)to; \
} while(0)
-#endif
+#define FLUSH_CACHE(from, length) ((void)0)
+#endif
@@ -23,5 +23,6 @@ const unsigned char jmpCodeTemplate[] = { 0xE9, 0x00, 0x00, 0x00, 0x00 };
(unsigned long long)to - (unsigned long long)from - sizeof(jmpCodeTemplate); \
} while(0)
-#endif
+#define FLUSH_CACHE(from, length) ((void)0)
+#endif
@@ -68,6 +68,7 @@ struct JmpOnlyApiHookImpl
void changeCode(const void* data)
{
CodeModifier::modify(const_cast<void*>(m_api), data, m_jmpCode.getCodeSize());
+ m_jmpCode.flushCache();
}
/////////////////////////////////////////////////////
@@ -18,26 +18,30 @@
#include <string.h>
#include <inttypes.h>
#include <sys/mman.h>
+#include <unistd.h>
#include <mockcpp/CodeModifier.h>
-
+#include "JmpCodeArch.h"
#define PAGE_ALIGN_BITS 12
//////////////////////////////////////////////////////////////////
#define PAGE_SIZE (1 << PAGE_ALIGN_BITS)
-#define ALIGN_TO_PAGE_BOUNDARY(addr) (void*) (((uintptr_t)addr) & (~((1<<(PAGE_ALIGN_BITS))-1)))
+#define ALIGN_TO_PAGE_BOUNDARY(addr, page_size) (void*) (((uintptr_t)addr) & (~((page_size)-1)))
//////////////////////////////////////////////////////////////////
MOCKCPP_NS_START
bool CodeModifier::modify(void *dest, const void *src, size_t size)
{
- if(::mprotect(ALIGN_TO_PAGE_BOUNDARY(dest), PAGE_SIZE * 2, PROT_EXEC | PROT_WRITE | PROT_READ ) != 0)
- {
- return false;
- }
+ uint64_t page_size = getpagesize();
+ if (::mprotect(ALIGN_TO_PAGE_BOUNDARY(dest, page_size), page_size * 2, PROT_EXEC | PROT_WRITE | PROT_READ) != 0) {
+ return false;
+ }
+
::memcpy(dest, src, size);
+
+ FLUSH_CACHE(dest, size);
#if 0
--
2.27.0