1 /*
2 Copyright (c) 2005-2022 Intel Corporation
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 "oneapi/tbb/detail/_config.h"
18 #include "oneapi/tbb/detail/_assert.h"
19 #include "../tbb/assert_impl.h"
20
21 #if !__TBB_WIN8UI_SUPPORT && defined(_WIN32)
22
23 #ifndef _CRT_SECURE_NO_DEPRECATE
24 #define _CRT_SECURE_NO_DEPRECATE 1
25 #endif
26
27 // no standard-conforming implementation of snprintf prior to VS 2015
28 #if !defined(_MSC_VER) || _MSC_VER>=1900
29 #define LOG_PRINT(s, n, format, ...) snprintf(s, n, format, __VA_ARGS__)
30 #else
31 #define LOG_PRINT(s, n, format, ...) _snprintf_s(s, n, _TRUNCATE, format, __VA_ARGS__)
32 #endif
33
34 #include <windows.h>
35 #include <new>
36 #include <stdio.h>
37 #include <string.h>
38
39 #include "function_replacement.h"
40
41 // The information about a standard memory allocation function for the replacement log
42 struct FunctionInfo {
43 const char* funcName;
44 const char* dllName;
45 };
46
47 // Namespace that processes and manages the output of records to the Log journal
48 // that will be provided to user by TBB_malloc_replacement_log()
49 namespace Log {
50 // Value of RECORDS_COUNT is set due to the fact that we maximally
51 // scan 8 modules, and in every module we can swap 6 opcodes. (rounded to 8)
52 static const unsigned RECORDS_COUNT = 8 * 8;
53 static const unsigned RECORD_LENGTH = MAX_PATH;
54
55 // Need to add 1 to count of records, because last record must be always nullptr
56 static char *records[RECORDS_COUNT + 1];
57 static bool replacement_status = true;
58
59 // Internal counter that contains number of next string for record
60 static unsigned record_number = 0;
61
62 // Function that writes info about (not)found opcodes to the Log journal
63 // functionInfo - information about a standard memory allocation function for the replacement log
64 // opcodeString - string, that contain byte code of this function
65 // status - information about function replacement status
record(FunctionInfo functionInfo,const char * opcodeString,bool status)66 static void record(FunctionInfo functionInfo, const char * opcodeString, bool status) {
67 __TBB_ASSERT(functionInfo.dllName, "Empty DLL name value");
68 __TBB_ASSERT(functionInfo.funcName, "Empty function name value");
69 __TBB_ASSERT(opcodeString, "Empty opcode");
70 __TBB_ASSERT(record_number <= RECORDS_COUNT, "Incorrect record number");
71
72 //If some replacement failed -> set status to false
73 replacement_status &= status;
74
75 // If we reach the end of the log, write this message to the last line
76 if (record_number == RECORDS_COUNT) {
77 // %s - workaround to fix empty variable argument parsing behavior in GCC
78 LOG_PRINT(records[RECORDS_COUNT - 1], RECORD_LENGTH, "%s", "Log was truncated.");
79 return;
80 }
81
82 char* entry = (char*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, RECORD_LENGTH);
83 __TBB_ASSERT(entry, "Invalid memory was returned");
84
85 LOG_PRINT(entry, RECORD_LENGTH, "%s: %s (%s), byte pattern: <%s>",
86 status ? "Success" : "Fail", functionInfo.funcName, functionInfo.dllName, opcodeString);
87
88 records[record_number++] = entry;
89 }
90 };
91
Ptr2Addrint(LPVOID ptr)92 inline UINT_PTR Ptr2Addrint(LPVOID ptr)
93 {
94 Int2Ptr i2p;
95 i2p.lpv = ptr;
96 return i2p.uip;
97 }
98
Addrint2Ptr(UINT_PTR ptr)99 inline LPVOID Addrint2Ptr(UINT_PTR ptr)
100 {
101 Int2Ptr i2p;
102 i2p.uip = ptr;
103 return i2p.lpv;
104 }
105
106 // Is the distance between addr1 and addr2 smaller than dist
IsInDistance(UINT_PTR addr1,UINT_PTR addr2,__int64 dist)107 inline bool IsInDistance(UINT_PTR addr1, UINT_PTR addr2, __int64 dist)
108 {
109 __int64 diff = addr1>addr2 ? addr1-addr2 : addr2-addr1;
110 return diff<dist;
111 }
112
113 /*
114 * When inserting a probe in 64 bits process the distance between the insertion
115 * point and the target may be bigger than 2^32. In this case we are using
116 * indirect jump through memory where the offset to this memory location
117 * is smaller than 2^32 and it contains the absolute address (8 bytes).
118 *
119 * This class is used to hold the pages used for the above trampolines.
120 * Since this utility will be used to replace malloc functions this implementation
121 * doesn't allocate memory dynamically.
122 *
123 * The struct MemoryBuffer holds the data about a page in the memory used for
124 * replacing functions in 64-bit code where the target is too far to be replaced
125 * with a short jump. All the calculations of m_base and m_next are in a multiple
126 * of SIZE_OF_ADDRESS (which is 8 in Win64).
127 */
128 class MemoryProvider {
129 private:
130 struct MemoryBuffer {
131 UINT_PTR m_base; // base address of the buffer
132 UINT_PTR m_next; // next free location in the buffer
133 DWORD m_size; // size of buffer
134
135 // Default constructor
MemoryBufferMemoryProvider::MemoryBuffer136 MemoryBuffer() : m_base(0), m_next(0), m_size(0) {}
137
138 // Constructor
MemoryBufferMemoryProvider::MemoryBuffer139 MemoryBuffer(void *base, DWORD size)
140 {
141 m_base = Ptr2Addrint(base);
142 m_next = m_base;
143 m_size = size;
144 }
145 };
146
CreateBuffer(UINT_PTR addr)147 MemoryBuffer *CreateBuffer(UINT_PTR addr)
148 {
149 // No more room in the pages database
150 if (m_lastBuffer - m_pages == MAX_NUM_BUFFERS)
151 return 0;
152
153 void *newAddr = Addrint2Ptr(addr);
154 // Get information for the region which the given address belongs to
155 MEMORY_BASIC_INFORMATION memInfo;
156 if (VirtualQuery(newAddr, &memInfo, sizeof(memInfo)) != sizeof(memInfo))
157 return 0;
158
159 for(;;) {
160 // The new address to check is beyond the current region and aligned to allocation size
161 newAddr = Addrint2Ptr( (Ptr2Addrint(memInfo.BaseAddress) + memInfo.RegionSize + m_allocSize) & ~(UINT_PTR)(m_allocSize-1) );
162
163 // Check that the address is in the right distance.
164 // VirtualAlloc can only round the address down; so it will remain in the right distance
165 if (!IsInDistance(addr, Ptr2Addrint(newAddr), MAX_DISTANCE))
166 break;
167
168 if (VirtualQuery(newAddr, &memInfo, sizeof(memInfo)) != sizeof(memInfo))
169 break;
170
171 if (memInfo.State == MEM_FREE && memInfo.RegionSize >= m_allocSize)
172 {
173 // Found a free region, try to allocate a page in this region
174 void *newPage = VirtualAlloc(newAddr, m_allocSize, MEM_COMMIT|MEM_RESERVE, PAGE_READWRITE);
175 if (!newPage)
176 break;
177
178 // Add the new page to the pages database
179 MemoryBuffer *pBuff = new (m_lastBuffer) MemoryBuffer(newPage, m_allocSize);
180 ++m_lastBuffer;
181 return pBuff;
182 }
183 }
184
185 // Failed to find a buffer in the distance
186 return 0;
187 }
188
189 public:
MemoryProvider()190 MemoryProvider()
191 {
192 SYSTEM_INFO sysInfo;
193 GetSystemInfo(&sysInfo);
194 m_allocSize = sysInfo.dwAllocationGranularity;
195 m_lastBuffer = &m_pages[0];
196 }
197
198 // We can't free the pages in the destructor because the trampolines
199 // are using these memory locations and a replaced function might be called
200 // after the destructor was called.
~MemoryProvider()201 ~MemoryProvider()
202 {
203 }
204
205 // Return a memory location in distance less than 2^31 from input address
GetLocation(UINT_PTR addr)206 UINT_PTR GetLocation(UINT_PTR addr)
207 {
208 MemoryBuffer *pBuff = m_pages;
209 for (; pBuff<m_lastBuffer && IsInDistance(pBuff->m_next, addr, MAX_DISTANCE); ++pBuff)
210 {
211 if (pBuff->m_next < pBuff->m_base + pBuff->m_size)
212 {
213 UINT_PTR loc = pBuff->m_next;
214 pBuff->m_next += MAX_PROBE_SIZE;
215 return loc;
216 }
217 }
218
219 pBuff = CreateBuffer(addr);
220 if(!pBuff)
221 return 0;
222
223 UINT_PTR loc = pBuff->m_next;
224 pBuff->m_next += MAX_PROBE_SIZE;
225 return loc;
226 }
227
228 private:
229 MemoryBuffer m_pages[MAX_NUM_BUFFERS];
230 MemoryBuffer *m_lastBuffer;
231 DWORD m_allocSize;
232 };
233
234 static MemoryProvider memProvider;
235
236 // Compare opcodes from dictionary (str1) and opcodes from code (str2)
237 // str1 might contain '*' to mask addresses
238 // RETURN: 0 if opcodes did not match, 1 on success
compareStrings(const char * str1,const char * str2)239 size_t compareStrings( const char *str1, const char *str2 )
240 {
241 for (size_t i=0; str1[i]!=0; i++){
242 if( str1[i]!='*' && str1[i]!='#' && str1[i]!=str2[i] ) return 0;
243 }
244 return 1;
245 }
246
247 // Check function prologue with known prologues from the dictionary
248 // opcodes - dictionary
249 // inpAddr - pointer to function prologue
250 // Dictionary contains opcodes for several full asm instructions
251 // + one opcode byte for the next asm instruction for safe address processing
252 // RETURN: 1 + the index of the matched pattern, or 0 if no match found.
CheckOpcodes(const char ** opcodes,void * inpAddr,bool abortOnError,const FunctionInfo * functionInfo=nullptr)253 static UINT CheckOpcodes( const char ** opcodes, void *inpAddr, bool abortOnError, const FunctionInfo* functionInfo = nullptr)
254 {
255 static size_t opcodesStringsCount = 0;
256 static size_t maxOpcodesLength = 0;
257 static size_t opcodes_pointer = (size_t)opcodes;
258 char opcodeString[2*MAX_PATTERN_SIZE+1];
259 size_t i;
260 size_t result = 0;
261
262 // Get the values for static variables
263 // max length and number of patterns
264 if( !opcodesStringsCount || opcodes_pointer != (size_t)opcodes ){
265 while( *(opcodes + opcodesStringsCount)!= nullptr ){
266 if( (i=strlen(*(opcodes + opcodesStringsCount))) > maxOpcodesLength )
267 maxOpcodesLength = i;
268 opcodesStringsCount++;
269 }
270 opcodes_pointer = (size_t)opcodes;
271 __TBB_ASSERT( maxOpcodesLength/2 <= MAX_PATTERN_SIZE, "Pattern exceeded the limit of 28 opcodes/56 symbols" );
272 }
273
274 // Translate prologue opcodes to string format to compare
275 for( i=0; i<maxOpcodesLength/2 && i<MAX_PATTERN_SIZE; ++i ){
276 sprintf( opcodeString + 2*i, "%.2X", *((unsigned char*)inpAddr+i) );
277 }
278 opcodeString[2*i] = 0;
279
280 // Compare translated opcodes with patterns
281 for( UINT idx=0; idx<opcodesStringsCount; ++idx ){
282 result = compareStrings( opcodes[idx],opcodeString );
283 if( result ) {
284 if (functionInfo) {
285 Log::record(*functionInfo, opcodeString, /*status*/ true);
286 }
287 return idx + 1; // avoid 0 which indicates a failure
288 }
289 }
290 if (functionInfo) {
291 Log::record(*functionInfo, opcodeString, /*status*/ false);
292 }
293 if (abortOnError) {
294 // Impossibility to find opcodes in the dictionary is a serious issue,
295 // as if we unable to call original function, leak or crash is expected result.
296 __TBB_ASSERT_RELEASE( false, "CheckOpcodes failed" );
297 }
298 return 0;
299 }
300
301 // Modify offsets in original code after moving it to a trampoline.
302 // We do not have more than one offset to correct in existing opcode patterns.
CorrectOffset(UINT_PTR address,const char * pattern,UINT distance)303 static void CorrectOffset( UINT_PTR address, const char* pattern, UINT distance )
304 {
305 const char* pos = strstr(pattern, "#*******");
306 if( pos ) {
307 address += (pos - pattern)/2; // compute the offset position
308 UINT value;
309 // UINT assignment is not used to avoid potential alignment issues
310 memcpy(&value, Addrint2Ptr(address), sizeof(value));
311 value += distance;
312 memcpy(Addrint2Ptr(address), &value, sizeof(value));
313 }
314 }
315
316 // Insert jump relative instruction to the input address
317 // RETURN: the size of the trampoline or 0 on failure
InsertTrampoline32(void * inpAddr,void * targetAddr,const char * pattern,void ** storedAddr)318 static DWORD InsertTrampoline32(void *inpAddr, void *targetAddr, const char* pattern, void** storedAddr)
319 {
320 size_t bytesToMove = SIZE_OF_RELJUMP;
321 UINT_PTR srcAddr = Ptr2Addrint(inpAddr);
322 UINT_PTR tgtAddr = Ptr2Addrint(targetAddr);
323 // Check that the target fits in 32 bits
324 if (!IsInDistance(srcAddr, tgtAddr, MAX_DISTANCE))
325 return 0;
326
327 UINT_PTR offset;
328 UINT offset32;
329 UCHAR *codePtr = (UCHAR *)inpAddr;
330
331 if ( storedAddr ){ // If requested, store original function code
332 bytesToMove = strlen(pattern)/2-1; // The last byte matching the pattern must not be copied
333 __TBB_ASSERT_RELEASE( bytesToMove >= SIZE_OF_RELJUMP, "Incorrect bytecode pattern?" );
334 UINT_PTR trampAddr = memProvider.GetLocation(srcAddr);
335 if (!trampAddr)
336 return 0;
337 *storedAddr = Addrint2Ptr(trampAddr);
338 // Set 'executable' flag for original instructions in the new place
339 DWORD pageFlags = PAGE_EXECUTE_READWRITE;
340 if (!VirtualProtect(*storedAddr, MAX_PROBE_SIZE, pageFlags, &pageFlags)) return 0;
341 // Copy original instructions to the new place
342 memcpy(*storedAddr, codePtr, bytesToMove);
343 offset = srcAddr - trampAddr;
344 offset32 = (UINT)(offset & 0xFFFFFFFF);
345 CorrectOffset( trampAddr, pattern, offset32 );
346 // Set jump to the code after replacement
347 offset32 -= SIZE_OF_RELJUMP;
348 *(UCHAR*)(trampAddr+bytesToMove) = 0xE9;
349 memcpy((UCHAR*)(trampAddr+bytesToMove+1), &offset32, sizeof(offset32));
350 }
351
352 // The following will work correctly even if srcAddr>tgtAddr, as long as
353 // address difference is less than 2^31, which is guaranteed by IsInDistance.
354 offset = tgtAddr - srcAddr - SIZE_OF_RELJUMP;
355 offset32 = (UINT)(offset & 0xFFFFFFFF);
356 // Insert the jump to the new code
357 *codePtr = 0xE9;
358 memcpy(codePtr+1, &offset32, sizeof(offset32));
359
360 // Fill the rest with NOPs to correctly see disassembler of old code in debugger.
361 for( unsigned i=SIZE_OF_RELJUMP; i<bytesToMove; i++ ){
362 *(codePtr+i) = 0x90;
363 }
364
365 return SIZE_OF_RELJUMP;
366 }
367
368 // This function is called when the offset doesn't fit in 32 bits
369 // 1 Find and allocate a page in the small distance (<2^31) from input address
370 // 2 Put jump RIP relative indirect through the address in the close page
371 // 3 Put the absolute address of the target in the allocated location
372 // RETURN: the size of the trampoline or 0 on failure
InsertTrampoline64(void * inpAddr,void * targetAddr,const char * pattern,void ** storedAddr)373 static DWORD InsertTrampoline64(void *inpAddr, void *targetAddr, const char* pattern, void** storedAddr)
374 {
375 size_t bytesToMove = SIZE_OF_INDJUMP;
376
377 UINT_PTR srcAddr = Ptr2Addrint(inpAddr);
378 UINT_PTR tgtAddr = Ptr2Addrint(targetAddr);
379
380 // Get a location close to the source address
381 UINT_PTR location = memProvider.GetLocation(srcAddr);
382 if (!location)
383 return 0;
384
385 UINT_PTR offset;
386 UINT offset32;
387 UCHAR *codePtr = (UCHAR *)inpAddr;
388
389 // Fill the location
390 UINT_PTR *locPtr = (UINT_PTR *)Addrint2Ptr(location);
391 *locPtr = tgtAddr;
392
393 if ( storedAddr ){ // If requested, store original function code
394 bytesToMove = strlen(pattern)/2-1; // The last byte matching the pattern must not be copied
395 __TBB_ASSERT_RELEASE( bytesToMove >= SIZE_OF_INDJUMP, "Incorrect bytecode pattern?" );
396 UINT_PTR trampAddr = memProvider.GetLocation(srcAddr);
397 if (!trampAddr)
398 return 0;
399 *storedAddr = Addrint2Ptr(trampAddr);
400 // Set 'executable' flag for original instructions in the new place
401 DWORD pageFlags = PAGE_EXECUTE_READWRITE;
402 if (!VirtualProtect(*storedAddr, MAX_PROBE_SIZE, pageFlags, &pageFlags)) return 0;
403 // Copy original instructions to the new place
404 memcpy(*storedAddr, codePtr, bytesToMove);
405 offset = srcAddr - trampAddr;
406 offset32 = (UINT)(offset & 0xFFFFFFFF);
407 CorrectOffset( trampAddr, pattern, offset32 );
408 // Set jump to the code after replacement. It is within the distance of relative jump!
409 offset32 -= SIZE_OF_RELJUMP;
410 *(UCHAR*)(trampAddr+bytesToMove) = 0xE9;
411 memcpy((UCHAR*)(trampAddr+bytesToMove+1), &offset32, sizeof(offset32));
412 }
413
414 // Fill the buffer
415 offset = location - srcAddr - SIZE_OF_INDJUMP;
416 offset32 = (UINT)(offset & 0xFFFFFFFF);
417 *(codePtr) = 0xFF;
418 *(codePtr+1) = 0x25;
419 memcpy(codePtr+2, &offset32, sizeof(offset32));
420
421 // Fill the rest with NOPs to correctly see disassembler of old code in debugger.
422 for( unsigned i=SIZE_OF_INDJUMP; i<bytesToMove; i++ ){
423 *(codePtr+i) = 0x90;
424 }
425
426 return SIZE_OF_INDJUMP;
427 }
428
429 // Insert a jump instruction in the inpAddr to the targetAddr
430 // 1. Get the memory protection of the page containing the input address
431 // 2. Change the memory protection to writable
432 // 3. Call InsertTrampoline32 or InsertTrampoline64
433 // 4. Restore memory protection
434 // RETURN: FALSE on failure, TRUE on success
InsertTrampoline(void * inpAddr,void * targetAddr,const char ** opcodes,void ** origFunc)435 static bool InsertTrampoline(void *inpAddr, void *targetAddr, const char ** opcodes, void** origFunc)
436 {
437 DWORD probeSize;
438 // Change page protection to EXECUTE+WRITE
439 DWORD origProt = 0;
440 if (!VirtualProtect(inpAddr, MAX_PROBE_SIZE, PAGE_EXECUTE_WRITECOPY, &origProt))
441 return FALSE;
442
443 const char* pattern = nullptr;
444 if ( origFunc ){ // Need to store original function code
445 UCHAR * const codePtr = (UCHAR *)inpAddr;
446 if ( *codePtr == 0xE9 ){ // JMP relative instruction
447 // For the special case when a system function consists of a single near jump,
448 // instead of moving it somewhere we use the target of the jump as the original function.
449 unsigned offsetInJmp = *(unsigned*)(codePtr + 1);
450 *origFunc = (void*)(Ptr2Addrint(inpAddr) + offsetInJmp + SIZE_OF_RELJUMP);
451 origFunc = nullptr; // now it must be ignored by InsertTrampoline32/64
452 } else {
453 // find the right opcode pattern
454 UINT opcodeIdx = CheckOpcodes( opcodes, inpAddr, /*abortOnError=*/true );
455 __TBB_ASSERT( opcodeIdx > 0, "abortOnError ignored in CheckOpcodes?" );
456 pattern = opcodes[opcodeIdx-1]; // -1 compensates for +1 in CheckOpcodes
457 }
458 }
459
460 probeSize = InsertTrampoline32(inpAddr, targetAddr, pattern, origFunc);
461 if (!probeSize)
462 probeSize = InsertTrampoline64(inpAddr, targetAddr, pattern, origFunc);
463
464 // Restore original protection
465 VirtualProtect(inpAddr, MAX_PROBE_SIZE, origProt, &origProt);
466
467 if (!probeSize)
468 return FALSE;
469
470 FlushInstructionCache(GetCurrentProcess(), inpAddr, probeSize);
471 FlushInstructionCache(GetCurrentProcess(), origFunc, probeSize);
472
473 return TRUE;
474 }
475
476 // Routine to replace the functions
477 // TODO: replace opcodesNumber with opcodes and opcodes number to check if we replace right code.
ReplaceFunctionA(const char * dllName,const char * funcName,FUNCPTR newFunc,const char ** opcodes,FUNCPTR * origFunc)478 FRR_TYPE ReplaceFunctionA(const char *dllName, const char *funcName, FUNCPTR newFunc, const char ** opcodes, FUNCPTR* origFunc)
479 {
480 // Cache the results of the last search for the module
481 // Assume that there was no DLL unload between
482 static char cachedName[MAX_PATH+1];
483 static HMODULE cachedHM = 0;
484
485 if (!dllName || !*dllName)
486 return FRR_NODLL;
487
488 if (!cachedHM || strncmp(dllName, cachedName, MAX_PATH) != 0)
489 {
490 // Find the module handle for the input dll
491 HMODULE hModule = GetModuleHandleA(dllName);
492 if (hModule == 0)
493 {
494 // Couldn't find the module with the input name
495 cachedHM = 0;
496 return FRR_NODLL;
497 }
498
499 cachedHM = hModule;
500 strncpy(cachedName, dllName, MAX_PATH);
501 }
502
503 FARPROC inpFunc = GetProcAddress(cachedHM, funcName);
504 if (inpFunc == 0)
505 {
506 // Function was not found
507 return FRR_NOFUNC;
508 }
509
510 if (!InsertTrampoline((void*)inpFunc, (void*)newFunc, opcodes, (void**)origFunc)){
511 // Failed to insert the trampoline to the target address
512 return FRR_FAILED;
513 }
514
515 return FRR_OK;
516 }
517
ReplaceFunctionW(const wchar_t * dllName,const char * funcName,FUNCPTR newFunc,const char ** opcodes,FUNCPTR * origFunc)518 FRR_TYPE ReplaceFunctionW(const wchar_t *dllName, const char *funcName, FUNCPTR newFunc, const char ** opcodes, FUNCPTR* origFunc)
519 {
520 // Cache the results of the last search for the module
521 // Assume that there was no DLL unload between
522 static wchar_t cachedName[MAX_PATH+1];
523 static HMODULE cachedHM = 0;
524
525 if (!dllName || !*dllName)
526 return FRR_NODLL;
527
528 if (!cachedHM || wcsncmp(dllName, cachedName, MAX_PATH) != 0)
529 {
530 // Find the module handle for the input dll
531 HMODULE hModule = GetModuleHandleW(dllName);
532 if (hModule == 0)
533 {
534 // Couldn't find the module with the input name
535 cachedHM = 0;
536 return FRR_NODLL;
537 }
538
539 cachedHM = hModule;
540 wcsncpy(cachedName, dllName, MAX_PATH);
541 }
542
543 FARPROC inpFunc = GetProcAddress(cachedHM, funcName);
544 if (inpFunc == 0)
545 {
546 // Function was not found
547 return FRR_NOFUNC;
548 }
549
550 if (!InsertTrampoline((void*)inpFunc, (void*)newFunc, opcodes, (void**)origFunc)){
551 // Failed to insert the trampoline to the target address
552 return FRR_FAILED;
553 }
554
555 return FRR_OK;
556 }
557
IsPrologueKnown(const char * dllName,const char * funcName,const char ** opcodes,HMODULE module)558 bool IsPrologueKnown(const char* dllName, const char *funcName, const char **opcodes, HMODULE module)
559 {
560 FARPROC inpFunc = GetProcAddress(module, funcName);
561 FunctionInfo functionInfo = { funcName, dllName };
562
563 if (!inpFunc) {
564 Log::record(functionInfo, "unknown", /*status*/ false);
565 return false;
566 }
567
568 return CheckOpcodes( opcodes, (void*)inpFunc, /*abortOnError=*/false, &functionInfo) != 0;
569 }
570
571 // Public Windows API
TBB_malloc_replacement_log(char *** function_replacement_log_ptr)572 extern "C" __declspec(dllexport) int TBB_malloc_replacement_log(char *** function_replacement_log_ptr)
573 {
574 if (function_replacement_log_ptr != nullptr) {
575 *function_replacement_log_ptr = Log::records;
576 }
577
578 // If we have no logs -> return false status
579 return Log::replacement_status && Log::records[0] != nullptr ? 0 : -1;
580 }
581
582 #endif /* !__TBB_WIN8UI_SUPPORT && defined(_WIN32) */
583