replace.h
Go to the documentation of this file.
1 // HippoMocks, a library for using mocks in unit testing of C++ code.
2 // Copyright (C) 2008, Bas van Tiel, Christian Rexwinkel, Mike Looijmans,
3 // Peter Bindels
4 //
5 // This library is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU Lesser General Public
7 // License as published by the Free Software Foundation; either
8 // version 2.1 of the License, or (at your option) any later version.
9 //
10 // This library is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 // Lesser General Public License for more details.
14 //
15 // You should have received a copy of the GNU Lesser General Public
16 // License along with this library; if not, write to the Free Software
17 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 //
19 // You can also retrieve it from http://www.gnu.org/licenses/lgpl-2.1.html
20 
21 #ifndef HIPPOMOCKS_REPLACE_H
22 #define HIPPOMOCKS_REPLACE_H
23 
24 # if defined(_M_IX86) || defined(__i386__) || defined(i386) || defined(_X86_) || defined(__THW_INTEL) || defined(__x86_64__) || defined(_M_X64)
25 # define SOME_X86
26 # elif defined(arm) || defined(__arm__) || defined(ARM) || defined(_ARM_) || defined(__aarch64__)
27 # define SOME_ARM
28 # endif
29 
30 # if defined(__x86_64__) || defined(_M_X64)
31 # define CMOCK_FUNC_PLATFORMIS64BIT
32 # endif
33 
34 # ifdef SOME_X86
35 # if defined(_MSC_VER) && (defined(_WIN32) || defined(_WIN64))
36 # define _HIPPOMOCKS__ENABLE_CFUNC_MOCKING_SUPPORT
37 # elif defined(__linux__) && defined(__GNUC__)
38 # define _HIPPOMOCKS__ENABLE_CFUNC_MOCKING_SUPPORT
39 # elif defined(__APPLE__)
40 # define _HIPPOMOCKS__ENABLE_CFUNC_MOCKING_SUPPORT
41 # endif
42 # elif defined(SOME_ARM) && defined(__GNUC__)
43 # define _HIPPOMOCKS__ENABLE_CFUNC_MOCKING_SUPPORT
44 
45 // This clear-cache is *required*. The tests will fail if you remove it.
46 extern "C" void __clear_cache(char *beg, char *end);
47 # endif
48 
49 # ifdef _HIPPOMOCKS__ENABLE_CFUNC_MOCKING_SUPPORT
50 # include <memory.h>
51 
52 # ifdef _WIN32
53 // De-windows.h-ified import to avoid including that file.
54 # ifdef _WIN64
55 extern "C" __declspec(dllimport) int WINCALL VirtualProtect(void *func, unsigned long long byteCount, unsigned long flags, unsigned long *oldFlags);
56 # else
57 extern "C" __declspec(dllimport) int WINCALL VirtualProtect(void *func, unsigned long byteCount, unsigned long flags, unsigned long *oldFlags);
58 # endif
59 
60 # ifndef PAGE_EXECUTE_READWRITE
61 # define PAGE_EXECUTE_READWRITE 0x40
62 # endif
63 
64 # ifndef NO_HIPPOMOCKS_NAMESPACE
65 namespace HippoMocks
66 {
67 # endif
68 
69 class Unprotect
70 {
71 public:
72  Unprotect(void *location, size_t byteCount)
73  : origFunc(location)
74  , byteCount(byteCount)
75  {
76  VirtualProtect(origFunc, byteCount, PAGE_EXECUTE_READWRITE, &oldprotect);
77  }
78  ~Unprotect()
79  {
80  unsigned long dontcare;
81  VirtualProtect(origFunc, byteCount, oldprotect, &dontcare);
82  }
83 private:
84  void *origFunc;
85  size_t byteCount;
86  unsigned long oldprotect;
87 };
88 # else
89 # include <sys/mman.h>
90 # include <stdint.h>
91 
92 # ifndef NO_HIPPOMOCKS_NAMESPACE
93 namespace HippoMocks
94 {
95 # endif
96 
97 
98 class Unprotect
99 {
100 public:
101  Unprotect(void *location, size_t count)
102  : origFunc((intptr_t)location & (~0xFFF))
103  , byteCount(count + ((intptr_t)location - origFunc))
104  {
105  mprotect((void *)origFunc, this->byteCount, PROT_READ | PROT_WRITE | PROT_EXEC);
106  };
107  ~Unprotect()
108  {
109  mprotect((void *)origFunc, byteCount, PROT_READ | PROT_EXEC);
110  }
111 private:
112  intptr_t origFunc;
113  int byteCount;
114 };
115 # endif
116 
117 typedef unsigned int e9ptrsize_t;
118 
119 template <typename T, typename U>
120 T horrible_cast(U u)
121 {
122  union { T t; U u; } un;
123  un.u = u;
124  return un.t;
125 }
126 
127 class Replace
128 {
129 private:
130  void *origFunc;
131  char backupData[16]; // typical use is 5 for 32-bit and 14 for 64-bit code.
132 public:
133  template <typename T>
134  Replace(T funcptr, T replacement)
135  : origFunc(horrible_cast<void *>(funcptr))
136  {
137  Unprotect _allow_write(origFunc, sizeof(backupData));
138  memcpy(backupData, origFunc, sizeof(backupData));
139 # ifdef SOME_X86
140 # ifdef CMOCK_FUNC_PLATFORMIS64BIT
141  if (llabs((long long)origFunc - (long long)replacement) < 0x80000000LL)
142  {
143 # endif
144  *(unsigned char *)origFunc = 0xE9;
145  *(e9ptrsize_t *)(horrible_cast<intptr_t>(origFunc) + 1) = (e9ptrsize_t)(horrible_cast<intptr_t>(replacement) - horrible_cast<intptr_t>(origFunc) - sizeof(e9ptrsize_t) - 1);
146 # ifdef CMOCK_FUNC_PLATFORMIS64BIT
147  }
148  else
149  {
150  unsigned char *func = (unsigned char *)origFunc;
151  func[0] = 0xFF; // jmp (rip + imm32)
152  func[1] = 0x25;
153  func[2] = 0x00; // imm32 of 0, so immediately after the instruction
154  func[3] = 0x00;
155  func[4] = 0x00;
156  func[5] = 0x00;
157  *(long long *)(horrible_cast<intptr_t>(origFunc) + 6) = (long long)(horrible_cast<intptr_t>(replacement));
158  }
159 # endif
160 # elif defined(SOME_ARM)
161  unsigned int *rawptr = (unsigned int *)((intptr_t)(origFunc) & (~3));
162  if ((intptr_t)origFunc & 1)
163  {
164  rawptr[0] = 0x6800A001;
165  rawptr[1] = 0x46874687;
166  rawptr[2] = (intptr_t)replacement;
167  }
168  else
169  {
170  rawptr[0] = 0xE59FF000;
171  rawptr[1] = (intptr_t)replacement;
172  rawptr[2] = (intptr_t)replacement;
173  }
174  __clear_cache((char *)rawptr, (char *)rawptr + 16);
175 # endif
176  }
177  ~Replace()
178  {
179  Unprotect _allow_write(origFunc, sizeof(backupData));
180  memcpy(origFunc, backupData, sizeof(backupData));
181 # ifdef SOME_ARM
182  unsigned int *rawptr = (unsigned int *)((intptr_t)(origFunc) & (~3));
183  __clear_cache((char *)rawptr, (char *)rawptr + 16);
184 # endif
185  }
186 };
187 # endif
188 
189 # ifndef NO_HIPPOMOCKS_NAMESPACE
190 }
191 # endif
192 
193 #endif
auto end(reversed_container< T > container) -> decltype(container.container.rend())
Definition: reverse.h:43