mirror of
https://github.com/ossrs/srs.git
synced 2025-03-09 15:49:59 +00:00
Squash: Fix bugs
This commit is contained in:
parent
10d188faab
commit
716e578a19
382 changed files with 170096 additions and 220 deletions
86
trunk/3rdparty/gperftools-2-fit/src/windows/TODO
vendored
Normal file
86
trunk/3rdparty/gperftools-2-fit/src/windows/TODO
vendored
Normal file
|
@ -0,0 +1,86 @@
|
|||
* Get heap-profile-table.cc using DeleteMatchingFiles
|
||||
* Get heap-profile-table.cc using FillProcSelfMaps, DumpProcSelfMaps
|
||||
* Play around with ExperimentalGetStackTrace
|
||||
* Support the windows-level memory-allocation functions? See
|
||||
/home/build/googleclient/earth/client/tools/memorytracking/client/memorytrace/src/memorytrace.cpp
|
||||
/home/build/googleclient/total_recall/common/sitestep/*
|
||||
http://www.internals.com/articles/apispy/apispy.htm
|
||||
http://www.wheaty.net/APISPY32.zip
|
||||
* Verify /proc/xxx/maps:
|
||||
http://www.geocities.com/wah_java_dotnet/procmap/index.html
|
||||
* Figure out how to edit the executable IAT so tcmalloc.dll is loaded first
|
||||
* Use QueryPerformanceCounter instead of GetTickCount() (also for sparsehash)
|
||||
|
||||
----
|
||||
More info on windows-level memory-allocation functions:
|
||||
C runtime malloc
|
||||
LocalAlloc
|
||||
GlobalAlloc
|
||||
HeapAlloc
|
||||
VirtualAlloc
|
||||
mmap stuff
|
||||
|
||||
malloc, LocalAlloc and GlobalAlloc call HeapAlloc, which calls
|
||||
VirtualAlloc when needed, which calls VirtualAllocEx (the __sbrk equiv?)
|
||||
|
||||
siggi sez: If you want to do a generic job, you probably need to
|
||||
preserve the semantics of all of these Win32 calls:
|
||||
Heap32First
|
||||
Heap32ListFirst
|
||||
Heap32ListNext
|
||||
Heap32Next
|
||||
HeapAlloc
|
||||
HeapCompact
|
||||
HeapCreate
|
||||
HeapCreateTagsW
|
||||
HeapDestroy
|
||||
HeapExtend
|
||||
HeapFree
|
||||
HeapLock
|
||||
HeapQueryInformation
|
||||
HeapQueryTagW
|
||||
HeapReAlloc
|
||||
HeapSetInformation
|
||||
HeapSize
|
||||
HeapSummary
|
||||
HeapUnlock
|
||||
HeapUsage
|
||||
HeapValidate
|
||||
HeapWalk
|
||||
|
||||
kernel32.dll export functions and nt.dll export functions:
|
||||
http://www.shorthike.com/svn/trunk/tools_win32/dm/lib/kernel32.def
|
||||
http://undocumented.ntinternals.net/
|
||||
|
||||
You can edit the executable IAT to have the patching DLL be the
|
||||
first one loaded.
|
||||
|
||||
Most complete way to intercept system calls is patch the functions
|
||||
(not the IAT).
|
||||
|
||||
Microsoft has somee built-in routines for heap-checking:
|
||||
http://support.microsoft.com/kb/268343
|
||||
|
||||
----
|
||||
Itimer replacement:
|
||||
http://msdn2.microsoft.com/en-us/library/ms712713.aspx
|
||||
|
||||
----
|
||||
Changes I've had to make to the project file:
|
||||
|
||||
0) When creating the project file, click on "no autogenerated files"
|
||||
|
||||
--- For each project:
|
||||
1) Alt-F7 -> General -> [pulldown "all configurations" ] -> Output Directory -> $(SolutionDir)$(ConfigurationName)
|
||||
2) Alt-F7 -> General -> [pulldown "all configurations" ] -> Intermediate Directory -> $(ConfigurationName)
|
||||
|
||||
--- For each .cc file:
|
||||
1) Alt-F7 -> C/C++ -> General -> [pulldown "all configurations"] -> Additional Include Directives --> src/windows + src/
|
||||
2) Alt-F7 -> C/C++ -> Code Generation -> Runtime Library -> Multi-threaded, debug/release, DLL or not
|
||||
|
||||
--- For DLL:
|
||||
3) Alt-F7 -> Linker -> Input -> [pulldown "all configurations" ] -> Module Definition File -> src\windows\vc7and8.def
|
||||
--- For binaries depending on a DLL:
|
||||
3) Right-click on project -> Project Dependencies -> [add dll]
|
||||
--- For static binaries (not depending on a DLL)
|
||||
3) Alt-F7 -> C/C++ -> Command Line -> [pulldown "all configurations"] -> /D PERFTOOLS_DLL_DECL=
|
183
trunk/3rdparty/gperftools-2-fit/src/windows/addr2line-pdb.c
vendored
Normal file
183
trunk/3rdparty/gperftools-2-fit/src/windows/addr2line-pdb.c
vendored
Normal file
|
@ -0,0 +1,183 @@
|
|||
/* -*- Mode: c; c-basic-offset: 2; indent-tabs-mode: nil -*- */
|
||||
/* Copyright (c) 2008, Google Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* * Neither the name of Google Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* ---
|
||||
* Author: David Vitek
|
||||
*
|
||||
* Dump function addresses using Microsoft debug symbols. This works
|
||||
* on PDB files. Note that this program will download symbols to
|
||||
* c:\websymbols without asking.
|
||||
*/
|
||||
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
|
||||
#ifndef _CRT_SECURE_NO_WARNINGS
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
#endif
|
||||
|
||||
#ifndef _CRT_SECURE_NO_DEPRECATE
|
||||
#define _CRT_SECURE_NO_DEPRECATE
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <windows.h>
|
||||
#include <dbghelp.h>
|
||||
|
||||
#define SEARCH_CAP (1024*1024)
|
||||
#define WEBSYM "SRV*c:\\websymbols*http://msdl.microsoft.com/download/symbols"
|
||||
|
||||
void usage() {
|
||||
fprintf(stderr, "usage: addr2line-pdb "
|
||||
"[-f|--functions] [-C|--demangle] [-e|--exe filename]\n");
|
||||
fprintf(stderr, "(Then list the hex addresses on stdin, one per line)\n");
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
DWORD error;
|
||||
HANDLE process;
|
||||
ULONG64 module_base;
|
||||
int i;
|
||||
char* search;
|
||||
char buf[256]; /* Enough to hold one hex address, I trust! */
|
||||
int rv = 0;
|
||||
/* We may add SYMOPT_UNDNAME if --demangle is specified: */
|
||||
DWORD symopts = SYMOPT_DEFERRED_LOADS | SYMOPT_DEBUG | SYMOPT_LOAD_LINES;
|
||||
char* filename = "a.out"; /* The default if -e isn't specified */
|
||||
int print_function_name = 0; /* Set to 1 if -f is specified */
|
||||
|
||||
for (i = 1; i < argc; i++) {
|
||||
if (strcmp(argv[i], "--functions") == 0 || strcmp(argv[i], "-f") == 0) {
|
||||
print_function_name = 1;
|
||||
} else if (strcmp(argv[i], "--demangle") == 0 ||
|
||||
strcmp(argv[i], "-C") == 0) {
|
||||
symopts |= SYMOPT_UNDNAME;
|
||||
} else if (strcmp(argv[i], "--exe") == 0 ||
|
||||
strcmp(argv[i], "-e") == 0) {
|
||||
if (i + 1 >= argc) {
|
||||
fprintf(stderr, "FATAL ERROR: -e must be followed by a filename\n");
|
||||
return 1;
|
||||
}
|
||||
filename = argv[i+1];
|
||||
i++; /* to skip over filename too */
|
||||
} else if (strcmp(argv[i], "--help") == 0) {
|
||||
usage();
|
||||
exit(0);
|
||||
} else {
|
||||
usage();
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
process = GetCurrentProcess();
|
||||
|
||||
if (!SymInitialize(process, NULL, FALSE)) {
|
||||
error = GetLastError();
|
||||
fprintf(stderr, "SymInitialize returned error : %lu\n", error);
|
||||
return 1;
|
||||
}
|
||||
|
||||
search = malloc(SEARCH_CAP);
|
||||
if (SymGetSearchPath(process, search, SEARCH_CAP)) {
|
||||
if (strlen(search) + sizeof(";" WEBSYM) > SEARCH_CAP) {
|
||||
fprintf(stderr, "Search path too long\n");
|
||||
SymCleanup(process);
|
||||
return 1;
|
||||
}
|
||||
strcat(search, ";" WEBSYM);
|
||||
} else {
|
||||
error = GetLastError();
|
||||
fprintf(stderr, "SymGetSearchPath returned error : %lu\n", error);
|
||||
rv = 1; /* An error, but not a fatal one */
|
||||
strcpy(search, WEBSYM); /* Use a default value */
|
||||
}
|
||||
if (!SymSetSearchPath(process, search)) {
|
||||
error = GetLastError();
|
||||
fprintf(stderr, "SymSetSearchPath returned error : %lu\n", error);
|
||||
rv = 1; /* An error, but not a fatal one */
|
||||
}
|
||||
|
||||
SymSetOptions(symopts);
|
||||
module_base = SymLoadModuleEx(process, NULL, filename, NULL, 0, 0, NULL, 0);
|
||||
if (!module_base) {
|
||||
/* SymLoadModuleEx failed */
|
||||
error = GetLastError();
|
||||
fprintf(stderr, "SymLoadModuleEx returned error : %lu for %s\n",
|
||||
error, filename);
|
||||
SymCleanup(process);
|
||||
return 1;
|
||||
}
|
||||
|
||||
buf[sizeof(buf)-1] = '\0'; /* Just to be safe */
|
||||
while (fgets(buf, sizeof(buf)-1, stdin)) {
|
||||
/* GNU addr2line seems to just do a strtol and ignore any
|
||||
* weird characters it gets, so we will too.
|
||||
*/
|
||||
unsigned __int64 reladdr = _strtoui64(buf, NULL, 16);
|
||||
ULONG64 buffer[(sizeof(SYMBOL_INFO) +
|
||||
MAX_SYM_NAME*sizeof(TCHAR) +
|
||||
sizeof(ULONG64) - 1)
|
||||
/ sizeof(ULONG64)];
|
||||
memset(buffer, 0, sizeof(buffer));
|
||||
PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)buffer;
|
||||
IMAGEHLP_LINE64 line;
|
||||
DWORD dummy;
|
||||
|
||||
// Just ignore overflow. In an overflow scenario, the resulting address
|
||||
// will be lower than module_base which hasn't been mapped by any prior
|
||||
// SymLoadModuleEx() command. This will cause SymFromAddr() and
|
||||
// SymGetLineFromAddr64() both to return failures and print the correct
|
||||
// ?? and ??:0 message variant.
|
||||
ULONG64 absaddr = reladdr + module_base;
|
||||
|
||||
pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO);
|
||||
// The length of the name is not including the null-terminating character.
|
||||
pSymbol->MaxNameLen = MAX_SYM_NAME - 1;
|
||||
if (print_function_name) {
|
||||
if (SymFromAddr(process, (DWORD64)absaddr, NULL, pSymbol)) {
|
||||
printf("%s\n", pSymbol->Name);
|
||||
} else {
|
||||
printf("??\n");
|
||||
}
|
||||
}
|
||||
line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
|
||||
if (SymGetLineFromAddr64(process, (DWORD64)absaddr, &dummy, &line)) {
|
||||
printf("%s:%d\n", line.FileName, (int)line.LineNumber);
|
||||
} else {
|
||||
printf("??:0\n");
|
||||
}
|
||||
}
|
||||
SymUnloadModule64(process, module_base);
|
||||
SymCleanup(process);
|
||||
return rv;
|
||||
}
|
156
trunk/3rdparty/gperftools-2-fit/src/windows/auto_testing_hook.h
vendored
Normal file
156
trunk/3rdparty/gperftools-2-fit/src/windows/auto_testing_hook.h
vendored
Normal file
|
@ -0,0 +1,156 @@
|
|||
// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
|
||||
// Copyright (c) 2010 The Chromium Authors. All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Utility for using SideStep with unit tests.
|
||||
|
||||
#ifndef CEEE_TESTING_SIDESTEP_AUTO_TESTING_HOOK_H_
|
||||
#define CEEE_TESTING_SIDESTEP_AUTO_TESTING_HOOK_H_
|
||||
|
||||
#include "base/basictypes.h"
|
||||
#include "base/logging.h"
|
||||
#include "preamble_patcher.h"
|
||||
|
||||
#define SIDESTEP_CHK(x) CHECK(x)
|
||||
#define SIDESTEP_EXPECT_TRUE(x) SIDESTEP_CHK(x)
|
||||
|
||||
namespace sidestep {
|
||||
|
||||
// Same trick as common/scope_cleanup.h ScopeGuardImplBase
|
||||
class AutoTestingHookBase {
|
||||
public:
|
||||
virtual ~AutoTestingHookBase() {}
|
||||
};
|
||||
|
||||
// This is the typedef you normally use for the class, e.g.
|
||||
//
|
||||
// AutoTestingHook hook = MakeTestingHook(TargetFunc, HookTargetFunc);
|
||||
//
|
||||
// The 'hook' variable will then be destroyed when it goes out of scope.
|
||||
//
|
||||
// NOTE: You must not hold this type as a member of another class. Its
|
||||
// destructor will not get called.
|
||||
typedef const AutoTestingHookBase& AutoTestingHook;
|
||||
|
||||
// This is the class you must use when holding a hook as a member of another
|
||||
// class, e.g.
|
||||
//
|
||||
// public:
|
||||
// AutoTestingHookHolder holder_;
|
||||
// MyClass() : my_hook_holder(MakeTestingHookHolder(Target, Hook)) {}
|
||||
class AutoTestingHookHolder {
|
||||
public:
|
||||
explicit AutoTestingHookHolder(AutoTestingHookBase* hook) : hook_(hook) {}
|
||||
~AutoTestingHookHolder() { delete hook_; }
|
||||
private:
|
||||
AutoTestingHookHolder() {} // disallow
|
||||
AutoTestingHookBase* hook_;
|
||||
};
|
||||
|
||||
// This class helps patch a function, then unpatch it when the object exits
|
||||
// scope, and also maintains the pointer to the original function stub.
|
||||
//
|
||||
// To enable use of the class without having to explicitly provide the
|
||||
// type of the function pointers (and instead only providing it
|
||||
// implicitly) we use the same trick as ScopeGuard (see
|
||||
// common/scope_cleanup.h) uses, so to create a hook you use the MakeHook
|
||||
// function rather than a constructor.
|
||||
//
|
||||
// NOTE: This function is only safe for e.g. unit tests and _not_ for
|
||||
// production code. See PreamblePatcher class for details.
|
||||
template <typename T>
|
||||
class AutoTestingHookImpl : public AutoTestingHookBase {
|
||||
public:
|
||||
static AutoTestingHookImpl<T> MakeTestingHook(T target_function,
|
||||
T replacement_function,
|
||||
bool do_it) {
|
||||
return AutoTestingHookImpl<T>(target_function, replacement_function, do_it);
|
||||
}
|
||||
|
||||
static AutoTestingHookImpl<T>* MakeTestingHookHolder(T target_function,
|
||||
T replacement_function,
|
||||
bool do_it) {
|
||||
return new AutoTestingHookImpl<T>(target_function,
|
||||
replacement_function, do_it);
|
||||
}
|
||||
|
||||
~AutoTestingHookImpl() {
|
||||
if (did_it_) {
|
||||
SIDESTEP_CHK(SIDESTEP_SUCCESS == PreamblePatcher::Unpatch(
|
||||
(void*)target_function_, (void*)replacement_function_,
|
||||
(void*)original_function_));
|
||||
}
|
||||
}
|
||||
|
||||
// Returns a pointer to the original function. To use this method you will
|
||||
// have to explicitly create an AutoTestingHookImpl of the specific
|
||||
// function pointer type (i.e. not use the AutoTestingHook typedef).
|
||||
T original_function() {
|
||||
return original_function_;
|
||||
}
|
||||
|
||||
private:
|
||||
AutoTestingHookImpl(T target_function, T replacement_function, bool do_it)
|
||||
: target_function_(target_function),
|
||||
original_function_(NULL),
|
||||
replacement_function_(replacement_function),
|
||||
did_it_(do_it) {
|
||||
if (do_it) {
|
||||
SIDESTEP_CHK(SIDESTEP_SUCCESS == PreamblePatcher::Patch(target_function,
|
||||
replacement_function,
|
||||
&original_function_));
|
||||
}
|
||||
}
|
||||
|
||||
T target_function_; // always valid
|
||||
T original_function_; // always valid
|
||||
T replacement_function_; // always valid
|
||||
bool did_it_; // Remember if we did it or not...
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
inline AutoTestingHookImpl<T> MakeTestingHook(T target,
|
||||
T replacement,
|
||||
bool do_it) {
|
||||
return AutoTestingHookImpl<T>::MakeTestingHook(target, replacement, do_it);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline AutoTestingHookImpl<T> MakeTestingHook(T target, T replacement) {
|
||||
return AutoTestingHookImpl<T>::MakeTestingHook(target, replacement, true);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline AutoTestingHookImpl<T>* MakeTestingHookHolder(T target, T replacement) {
|
||||
return AutoTestingHookImpl<T>::MakeTestingHookHolder(target, replacement,
|
||||
true);
|
||||
}
|
||||
|
||||
}; // namespace sidestep
|
||||
|
||||
#endif // CEEE_TESTING_SIDESTEP_AUTO_TESTING_HOOK_H_
|
306
trunk/3rdparty/gperftools-2-fit/src/windows/config.h
vendored
Normal file
306
trunk/3rdparty/gperftools-2-fit/src/windows/config.h
vendored
Normal file
|
@ -0,0 +1,306 @@
|
|||
/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */
|
||||
/* A manual version of config.h fit for windows machines.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can
|
||||
* be found in the LICENSE file.
|
||||
*/
|
||||
|
||||
/* Sometimes we accidentally #include this config.h instead of the one
|
||||
in .. -- this is particularly true for msys/mingw, which uses the
|
||||
unix config.h but also runs code in the windows directory.
|
||||
*/
|
||||
#ifdef __MINGW32__
|
||||
#include "../config.h"
|
||||
#define GOOGLE_PERFTOOLS_WINDOWS_CONFIG_H_
|
||||
#endif
|
||||
|
||||
#ifndef GOOGLE_PERFTOOLS_WINDOWS_CONFIG_H_
|
||||
#define GOOGLE_PERFTOOLS_WINDOWS_CONFIG_H_
|
||||
/* used by tcmalloc.h */
|
||||
#define GPERFTOOLS_CONFIG_H_
|
||||
|
||||
/* Enable aggressive decommit by default */
|
||||
/* #undef ENABLE_AGGRESSIVE_DECOMMIT_BY_DEFAULT */
|
||||
|
||||
/* Build new/delete operators for overaligned types */
|
||||
/* #undef ENABLE_ALIGNED_NEW_DELETE */
|
||||
|
||||
/* Build runtime detection for sized delete */
|
||||
/* #undef ENABLE_DYNAMIC_SIZED_DELETE */
|
||||
|
||||
/* Report large allocation */
|
||||
/* #undef ENABLE_LARGE_ALLOC_REPORT */
|
||||
|
||||
/* Build sized deletion operators */
|
||||
/* #undef ENABLE_SIZED_DELETE */
|
||||
|
||||
/* Define to 1 if you have the <asm/ptrace.h> header file. */
|
||||
/* #undef HAVE_ASM_PTRACE_H */
|
||||
|
||||
/* Define to 1 if you have the <cygwin/signal.h> header file. */
|
||||
/* #undef HAVE_CYGWIN_SIGNAL_H */
|
||||
|
||||
/* Define to 1 if you have the declaration of `backtrace', and to 0 if you
|
||||
don't. */
|
||||
/* #undef HAVE_DECL_BACKTRACE */
|
||||
|
||||
/* Define to 1 if you have the declaration of `cfree', and to 0 if you don't.
|
||||
*/
|
||||
#define HAVE_DECL_CFREE 0
|
||||
|
||||
/* Define to 1 if you have the declaration of `memalign', and to 0 if you
|
||||
don't. */
|
||||
#define HAVE_DECL_MEMALIGN 0
|
||||
|
||||
/* Define to 1 if you have the declaration of `nanosleep', and to 0 if you
|
||||
don't. */
|
||||
#define HAVE_DECL_NANOSLEEP 0
|
||||
|
||||
/* Define to 1 if you have the declaration of `posix_memalign', and to 0 if
|
||||
you don't. */
|
||||
#define HAVE_DECL_POSIX_MEMALIGN 0
|
||||
|
||||
/* Define to 1 if you have the declaration of `pvalloc', and to 0 if you
|
||||
don't. */
|
||||
#define HAVE_DECL_PVALLOC 0
|
||||
|
||||
/* Define to 1 if you have the declaration of `sleep', and to 0 if you don't.
|
||||
*/
|
||||
#define HAVE_DECL_SLEEP 0
|
||||
|
||||
/* Define to 1 if you have the declaration of `valloc', and to 0 if you don't.
|
||||
*/
|
||||
#define HAVE_DECL_VALLOC 0
|
||||
|
||||
/* Define to 1 if you have the <dlfcn.h> header file. */
|
||||
/* #undef HAVE_DLFCN_H */
|
||||
|
||||
/* Define to 1 if the system has the type `Elf32_Versym'. */
|
||||
/* #undef HAVE_ELF32_VERSYM */
|
||||
|
||||
/* Define to 1 if you have the <execinfo.h> header file. */
|
||||
/* #undef HAVE_EXECINFO_H */
|
||||
|
||||
/* Define to 1 if you have the <fcntl.h> header file. */
|
||||
#define HAVE_FCNTL_H 1
|
||||
|
||||
/* Define to 1 if you have the <features.h> header file. */
|
||||
/* #undef HAVE_FEATURES_H */
|
||||
|
||||
/* Define to 1 if you have the `fork' function. */
|
||||
/* #undef HAVE_FORK */
|
||||
|
||||
/* Define to 1 if you have the `geteuid' function. */
|
||||
/* #undef HAVE_GETEUID */
|
||||
|
||||
/* Define to 1 if you have the <glob.h> header file. */
|
||||
/* #undef HAVE_GLOB_H */
|
||||
|
||||
/* Define to 1 if you have the <grp.h> header file. */
|
||||
/* #undef HAVE_GRP_H */
|
||||
|
||||
/* Define to 1 if you have the <inttypes.h> header file. */
|
||||
#if defined(_MSC_VER) && _MSC_VER >= 1900
|
||||
#define HAVE_INTTYPES_H 1
|
||||
#endif
|
||||
|
||||
/* Define to 1 if you have the <libunwind.h> header file. */
|
||||
/* #undef HAVE_LIBUNWIND_H */
|
||||
|
||||
/* Define to 1 if you have the <linux/ptrace.h> header file. */
|
||||
/* #undef HAVE_LINUX_PTRACE_H */
|
||||
|
||||
/* Define if this is Linux that has SIGEV_THREAD_ID */
|
||||
/* #undef HAVE_LINUX_SIGEV_THREAD_ID */
|
||||
|
||||
/* Define to 1 if you have the <malloc.h> header file. */
|
||||
#define HAVE_MALLOC_H 1
|
||||
|
||||
/* Define to 1 if you have the <memory.h> header file. */
|
||||
#define HAVE_MEMORY_H 1
|
||||
|
||||
/* Define to 1 if you have a working `mmap' system call. */
|
||||
/* #undef HAVE_MMAP */
|
||||
|
||||
/* Define to 1 if you have the <poll.h> header file. */
|
||||
/* #undef HAVE_POLL_H */
|
||||
|
||||
/* define if libc has program_invocation_name */
|
||||
/* #undef HAVE_PROGRAM_INVOCATION_NAME */
|
||||
|
||||
/* Define if you have POSIX threads libraries and header files. */
|
||||
/* #undef HAVE_PTHREAD */
|
||||
|
||||
/* defined to 1 if pthread symbols are exposed even without include pthread.h
|
||||
*/
|
||||
/* #undef HAVE_PTHREAD_DESPITE_ASKING_FOR */
|
||||
|
||||
/* Define to 1 if you have the <pwd.h> header file. */
|
||||
/* #undef HAVE_PWD_H */
|
||||
|
||||
/* Define to 1 if you have the `sbrk' function. */
|
||||
/* #undef HAVE_SBRK */
|
||||
|
||||
/* Define to 1 if you have the <sched.h> header file. */
|
||||
/* #undef HAVE_SCHED_H */
|
||||
|
||||
/* Define to 1 if you have the <stdint.h> header file. */
|
||||
#define HAVE_STDINT_H 1
|
||||
|
||||
/* Define to 1 if you have the <stdlib.h> header file. */
|
||||
#define HAVE_STDLIB_H 1
|
||||
|
||||
/* Define to 1 if you have the <strings.h> header file. */
|
||||
/* #undef HAVE_STRINGS_H */
|
||||
|
||||
/* Define to 1 if you have the <string.h> header file. */
|
||||
#define HAVE_STRING_H 1
|
||||
|
||||
/* Define to 1 if the system has the type `struct mallinfo'. */
|
||||
/* #undef HAVE_STRUCT_MALLINFO */
|
||||
|
||||
/* Define to 1 if you have the <sys/cdefs.h> header file. */
|
||||
/* #undef HAVE_SYS_CDEFS_H */
|
||||
|
||||
/* Define to 1 if you have the <sys/prctl.h> header file. */
|
||||
/* #undef HAVE_SYS_PRCTL_H */
|
||||
|
||||
/* Define to 1 if you have the <sys/resource.h> header file. */
|
||||
/* #undef HAVE_SYS_RESOURCE_H */
|
||||
|
||||
/* Define to 1 if you have the <sys/socket.h> header file. */
|
||||
/* #undef HAVE_SYS_SOCKET_H */
|
||||
|
||||
/* Define to 1 if you have the <sys/stat.h> header file. */
|
||||
#define HAVE_SYS_STAT_H 1
|
||||
|
||||
/* Define to 1 if you have the <sys/syscall.h> header file. */
|
||||
/* #undef HAVE_SYS_SYSCALL_H */
|
||||
|
||||
/* Define to 1 if you have the <sys/types.h> header file. */
|
||||
#define HAVE_SYS_TYPES_H 1
|
||||
|
||||
/* Define to 1 if you have the <sys/ucontext.h> header file. */
|
||||
/* #undef HAVE_SYS_UCONTEXT_H */
|
||||
|
||||
/* Define to 1 if you have the <sys/wait.h> header file. */
|
||||
/* #undef HAVE_SYS_WAIT_H */
|
||||
|
||||
/* Define to 1 if compiler supports __thread */
|
||||
#define HAVE_TLS 1
|
||||
|
||||
/* Define to 1 if you have the <ucontext.h> header file. */
|
||||
/* #undef HAVE_UCONTEXT_H */
|
||||
|
||||
/* Define to 1 if you have the <unistd.h> header file. */
|
||||
/* #undef HAVE_UNISTD_H */
|
||||
|
||||
/* Whether <unwind.h> contains _Unwind_Backtrace */
|
||||
/* #undef HAVE_UNWIND_BACKTRACE */
|
||||
|
||||
/* Define to 1 if you have the <unwind.h> header file. */
|
||||
/* #undef HAVE_UNWIND_H */
|
||||
|
||||
/* define if your compiler has __attribute__ */
|
||||
/* #undef HAVE___ATTRIBUTE__ */
|
||||
|
||||
/* define if your compiler supports alignment of functions */
|
||||
/* #undef HAVE___ATTRIBUTE__ALIGNED_FN */
|
||||
|
||||
/* Define to 1 if compiler supports __environ */
|
||||
/* #undef HAVE___ENVIRON */
|
||||
|
||||
/* Define to 1 if you have the `__sbrk' function. */
|
||||
/* #undef HAVE___SBRK */
|
||||
|
||||
/* prefix where we look for installed files */
|
||||
/* #undef INSTALL_PREFIX */
|
||||
|
||||
/* Define to 1 if int32_t is equivalent to intptr_t */
|
||||
#ifndef _WIN64
|
||||
#define INT32_EQUALS_INTPTR 1
|
||||
#endif
|
||||
|
||||
/* Define to the sub-directory where libtool stores uninstalled libraries. */
|
||||
/* #undef LT_OBJDIR */
|
||||
|
||||
/* Name of package */
|
||||
#define PACKAGE "gperftools"
|
||||
|
||||
/* Define to the address where bug reports for this package should be sent. */
|
||||
#define PACKAGE_BUGREPORT "gperftools@googlegroups.com"
|
||||
|
||||
/* Define to the full name of this package. */
|
||||
#define PACKAGE_NAME "gperftools"
|
||||
|
||||
/* Define to the full name and version of this package. */
|
||||
#define PACKAGE_STRING "gperftools 2.9.1"
|
||||
|
||||
/* Define to the one symbol short name of this package. */
|
||||
#define PACKAGE_TARNAME "gperftools"
|
||||
|
||||
/* Define to the home page for this package. */
|
||||
#define PACKAGE_URL ""
|
||||
|
||||
/* Define to the version of this package. */
|
||||
#define PACKAGE_VERSION "2.9.1"
|
||||
|
||||
/* How to access the PC from a struct ucontext */
|
||||
/* #undef PC_FROM_UCONTEXT */
|
||||
|
||||
/* Always the empty-string on non-windows systems. On windows, should be
|
||||
"__declspec(dllexport)". This way, when we compile the dll, we export our
|
||||
functions/classes. It's safe to define this here because config.h is only
|
||||
used internally, to compile the DLL, and every DLL source file #includes
|
||||
"config.h" before anything else. */
|
||||
#ifndef PERFTOOLS_DLL_DECL
|
||||
# define PERFTOOLS_IS_A_DLL 1 /* not set if you're statically linking */
|
||||
# define PERFTOOLS_DLL_DECL __declspec(dllexport)
|
||||
# define PERFTOOLS_DLL_DECL_FOR_UNITTESTS __declspec(dllimport)
|
||||
#endif
|
||||
|
||||
/* Mark the systems where we know it's bad if pthreads runs too
|
||||
early before main (before threads are initialized, presumably). */
|
||||
#ifdef __FreeBSD__
|
||||
#define PTHREADS_CRASHES_IF_RUN_TOO_EARLY 1
|
||||
#endif
|
||||
|
||||
/* Define to necessary symbol if this constant uses a non-standard name on
|
||||
your system. */
|
||||
/* #undef PTHREAD_CREATE_JOINABLE */
|
||||
|
||||
/* Define to 1 if you have the ANSI C header files. */
|
||||
#define STDC_HEADERS 1
|
||||
|
||||
/* Define 8 bytes of allocation alignment for tcmalloc */
|
||||
/* #undef TCMALLOC_ALIGN_8BYTES */
|
||||
|
||||
/* Define internal page size for tcmalloc as number of left bitshift */
|
||||
/* #undef TCMALLOC_PAGE_SIZE_SHIFT */
|
||||
|
||||
/* Version number of package */
|
||||
#define VERSION "2.9.1"
|
||||
|
||||
/* C99 says: define this to get the PRI... macros from stdint.h */
|
||||
#ifndef __STDC_FORMAT_MACROS
|
||||
# define __STDC_FORMAT_MACROS 1
|
||||
#endif
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Extra stuff not found in config.h.in
|
||||
|
||||
// This must be defined before the windows.h is included. We need at
|
||||
// least 0x0400 for mutex.h to have access to TryLock, and at least
|
||||
// 0x0501 for patch_functions.cc to have access to GetModuleHandleEx.
|
||||
// (This latter is an optimization we could take out if need be.)
|
||||
#ifndef _WIN32_WINNT
|
||||
# define _WIN32_WINNT 0x0501
|
||||
#endif
|
||||
|
||||
// We want to make sure not to ever try to #include heap-checker.h
|
||||
#define NO_HEAP_CHECK 1
|
||||
|
||||
// TODO(csilvers): include windows/port.h in every relevant source file instead?
|
||||
#include "windows/port.h"
|
||||
|
||||
#endif /* GOOGLE_PERFTOOLS_WINDOWS_CONFIG_H_ */
|
65
trunk/3rdparty/gperftools-2-fit/src/windows/get_mangled_names.cc
vendored
Normal file
65
trunk/3rdparty/gperftools-2-fit/src/windows/get_mangled_names.cc
vendored
Normal file
|
@ -0,0 +1,65 @@
|
|||
// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
|
||||
// Copyright (c) 2008, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// ---
|
||||
// Author: Craig Silverstein (opensource@google.com)
|
||||
|
||||
// When you are porting perftools to a new compiler or architecture
|
||||
// (win64 vs win32) for instance, you'll need to change the mangled
|
||||
// symbol names for operator new and friends at the top of
|
||||
// patch_functions.cc. This file helps you do that.
|
||||
//
|
||||
// It does this by defining these functions with the proper signature.
|
||||
// All you need to do is compile this file and the run dumpbin on it.
|
||||
// (See http://msdn.microsoft.com/en-us/library/5x49w699.aspx for more
|
||||
// on dumpbin). To do this in MSVC, use the MSVC commandline shell:
|
||||
// http://msdn.microsoft.com/en-us/library/ms235639(VS.80).aspx)
|
||||
//
|
||||
// The run:
|
||||
// cl /c get_mangled_names.cc
|
||||
// dumpbin /symbols get_mangled_names.obj
|
||||
//
|
||||
// It will print out the mangled (and associated unmangled) names of
|
||||
// the 8 symbols you need to put at the top of patch_functions.cc
|
||||
|
||||
#include <sys/types.h> // for size_t
|
||||
#include <new> // for nothrow_t
|
||||
|
||||
static char m; // some dummy memory so new doesn't return NULL.
|
||||
|
||||
void* operator new(size_t size) { return &m; }
|
||||
void operator delete(void* p) throw() { }
|
||||
void* operator new[](size_t size) { return &m; }
|
||||
void operator delete[](void* p) throw() { }
|
||||
|
||||
void* operator new(size_t size, const std::nothrow_t&) throw() { return &m; }
|
||||
void operator delete(void* p, const std::nothrow_t&) throw() { }
|
||||
void* operator new[](size_t size, const std::nothrow_t&) throw() { return &m; }
|
||||
void operator delete[](void* p, const std::nothrow_t&) throw() { }
|
155
trunk/3rdparty/gperftools-2-fit/src/windows/gperftools/tcmalloc.h
vendored
Normal file
155
trunk/3rdparty/gperftools-2-fit/src/windows/gperftools/tcmalloc.h
vendored
Normal file
|
@ -0,0 +1,155 @@
|
|||
// -*- Mode: C; c-basic-offset: 2; indent-tabs-mode: nil -*-
|
||||
/* Copyright (c) 2003, Google Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* * Neither the name of Google Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* ---
|
||||
* Author: Sanjay Ghemawat <opensource@google.com>
|
||||
* .h file by Craig Silverstein <opensource@google.com>
|
||||
*/
|
||||
|
||||
#ifndef TCMALLOC_TCMALLOC_H_
|
||||
#define TCMALLOC_TCMALLOC_H_
|
||||
|
||||
#include <stddef.h> /* for size_t */
|
||||
#ifdef __cplusplus
|
||||
#include <new> /* for std::nothrow_t, std::align_val_t */
|
||||
#endif
|
||||
|
||||
/* Define the version number so folks can check against it */
|
||||
#define TC_VERSION_MAJOR 2
|
||||
#define TC_VERSION_MINOR 9
|
||||
#define TC_VERSION_PATCH ".1"
|
||||
#define TC_VERSION_STRING "gperftools 2.9.1"
|
||||
|
||||
#ifndef PERFTOOLS_NOTHROW
|
||||
|
||||
#if __cplusplus >= 201103L
|
||||
#define PERFTOOLS_NOTHROW noexcept
|
||||
#elif defined(__cplusplus)
|
||||
#define PERFTOOLS_NOTHROW throw()
|
||||
#else
|
||||
# ifdef __GNUC__
|
||||
# define PERFTOOLS_NOTHROW __attribute__((__nothrow__))
|
||||
# else
|
||||
# define PERFTOOLS_NOTHROW
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef PERFTOOLS_DLL_DECL
|
||||
# ifdef _WIN32
|
||||
# define PERFTOOLS_DLL_DECL __declspec(dllimport)
|
||||
# else
|
||||
# define PERFTOOLS_DLL_DECL
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
/*
|
||||
* Returns a human-readable version string. If major, minor,
|
||||
* and/or patch are not NULL, they are set to the major version,
|
||||
* minor version, and patch-code (a string, usually "").
|
||||
*/
|
||||
PERFTOOLS_DLL_DECL const char* tc_version(int* major, int* minor,
|
||||
const char** patch) PERFTOOLS_NOTHROW;
|
||||
|
||||
PERFTOOLS_DLL_DECL void* tc_malloc(size_t size) PERFTOOLS_NOTHROW;
|
||||
PERFTOOLS_DLL_DECL void* tc_malloc_skip_new_handler(size_t size) PERFTOOLS_NOTHROW;
|
||||
PERFTOOLS_DLL_DECL void tc_free(void* ptr) PERFTOOLS_NOTHROW;
|
||||
PERFTOOLS_DLL_DECL void tc_free_sized(void *ptr, size_t size) PERFTOOLS_NOTHROW;
|
||||
PERFTOOLS_DLL_DECL void* tc_realloc(void* ptr, size_t size) PERFTOOLS_NOTHROW;
|
||||
PERFTOOLS_DLL_DECL void* tc_calloc(size_t nmemb, size_t size) PERFTOOLS_NOTHROW;
|
||||
PERFTOOLS_DLL_DECL void tc_cfree(void* ptr) PERFTOOLS_NOTHROW;
|
||||
|
||||
PERFTOOLS_DLL_DECL void* tc_memalign(size_t __alignment,
|
||||
size_t __size) PERFTOOLS_NOTHROW;
|
||||
PERFTOOLS_DLL_DECL int tc_posix_memalign(void** ptr,
|
||||
size_t align, size_t size) PERFTOOLS_NOTHROW;
|
||||
PERFTOOLS_DLL_DECL void* tc_valloc(size_t __size) PERFTOOLS_NOTHROW;
|
||||
PERFTOOLS_DLL_DECL void* tc_pvalloc(size_t __size) PERFTOOLS_NOTHROW;
|
||||
|
||||
PERFTOOLS_DLL_DECL void tc_malloc_stats(void) PERFTOOLS_NOTHROW;
|
||||
PERFTOOLS_DLL_DECL int tc_mallopt(int cmd, int value) PERFTOOLS_NOTHROW;
|
||||
|
||||
/*
|
||||
* This is an alias for MallocExtension::instance()->GetAllocatedSize().
|
||||
* It is equivalent to
|
||||
* OS X: malloc_size()
|
||||
* glibc: malloc_usable_size()
|
||||
* Windows: _msize()
|
||||
*/
|
||||
PERFTOOLS_DLL_DECL size_t tc_malloc_size(void* ptr) PERFTOOLS_NOTHROW;
|
||||
|
||||
#ifdef __cplusplus
|
||||
PERFTOOLS_DLL_DECL int tc_set_new_mode(int flag) PERFTOOLS_NOTHROW;
|
||||
PERFTOOLS_DLL_DECL void* tc_new(size_t size);
|
||||
PERFTOOLS_DLL_DECL void* tc_new_nothrow(size_t size,
|
||||
const std::nothrow_t&) PERFTOOLS_NOTHROW;
|
||||
PERFTOOLS_DLL_DECL void tc_delete(void* p) PERFTOOLS_NOTHROW;
|
||||
PERFTOOLS_DLL_DECL void tc_delete_sized(void* p, size_t size) PERFTOOLS_NOTHROW;
|
||||
PERFTOOLS_DLL_DECL void tc_delete_nothrow(void* p,
|
||||
const std::nothrow_t&) PERFTOOLS_NOTHROW;
|
||||
PERFTOOLS_DLL_DECL void* tc_newarray(size_t size);
|
||||
PERFTOOLS_DLL_DECL void* tc_newarray_nothrow(size_t size,
|
||||
const std::nothrow_t&) PERFTOOLS_NOTHROW;
|
||||
PERFTOOLS_DLL_DECL void tc_deletearray(void* p) PERFTOOLS_NOTHROW;
|
||||
PERFTOOLS_DLL_DECL void tc_deletearray_sized(void* p, size_t size) PERFTOOLS_NOTHROW;
|
||||
PERFTOOLS_DLL_DECL void tc_deletearray_nothrow(void* p,
|
||||
const std::nothrow_t&) PERFTOOLS_NOTHROW;
|
||||
|
||||
#if defined(__cpp_aligned_new) || (defined(_MSVC_LANG) && _MSVC_LANG > 201402L)
|
||||
PERFTOOLS_DLL_DECL void* tc_new_aligned(size_t size, std::align_val_t al);
|
||||
PERFTOOLS_DLL_DECL void* tc_new_aligned_nothrow(size_t size, std::align_val_t al,
|
||||
const std::nothrow_t&) PERFTOOLS_NOTHROW;
|
||||
PERFTOOLS_DLL_DECL void tc_delete_aligned(void* p, std::align_val_t al) PERFTOOLS_NOTHROW;
|
||||
PERFTOOLS_DLL_DECL void tc_delete_sized_aligned(void* p, size_t size, std::align_val_t al) PERFTOOLS_NOTHROW;
|
||||
PERFTOOLS_DLL_DECL void tc_delete_aligned_nothrow(void* p, std::align_val_t al,
|
||||
const std::nothrow_t&) PERFTOOLS_NOTHROW;
|
||||
PERFTOOLS_DLL_DECL void* tc_newarray_aligned(size_t size, std::align_val_t al);
|
||||
PERFTOOLS_DLL_DECL void* tc_newarray_aligned_nothrow(size_t size, std::align_val_t al,
|
||||
const std::nothrow_t&) PERFTOOLS_NOTHROW;
|
||||
PERFTOOLS_DLL_DECL void tc_deletearray_aligned(void* p, std::align_val_t al) PERFTOOLS_NOTHROW;
|
||||
PERFTOOLS_DLL_DECL void tc_deletearray_sized_aligned(void* p, size_t size, std::align_val_t al) PERFTOOLS_NOTHROW;
|
||||
PERFTOOLS_DLL_DECL void tc_deletearray_aligned_nothrow(void* p, std::align_val_t al,
|
||||
const std::nothrow_t&) PERFTOOLS_NOTHROW;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
/* We're only un-defining for public */
|
||||
#if !defined(GPERFTOOLS_CONFIG_H_)
|
||||
|
||||
#undef PERFTOOLS_NOTHROW
|
||||
|
||||
#endif /* GPERFTOOLS_CONFIG_H_ */
|
||||
|
||||
#endif /* #ifndef TCMALLOC_TCMALLOC_H_ */
|
155
trunk/3rdparty/gperftools-2-fit/src/windows/gperftools/tcmalloc.h.in
vendored
Normal file
155
trunk/3rdparty/gperftools-2-fit/src/windows/gperftools/tcmalloc.h.in
vendored
Normal file
|
@ -0,0 +1,155 @@
|
|||
// -*- Mode: C; c-basic-offset: 2; indent-tabs-mode: nil -*-
|
||||
/* Copyright (c) 2003, Google Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* * Neither the name of Google Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* ---
|
||||
* Author: Sanjay Ghemawat <opensource@google.com>
|
||||
* .h file by Craig Silverstein <opensource@google.com>
|
||||
*/
|
||||
|
||||
#ifndef TCMALLOC_TCMALLOC_H_
|
||||
#define TCMALLOC_TCMALLOC_H_
|
||||
|
||||
#include <stddef.h> /* for size_t */
|
||||
#ifdef __cplusplus
|
||||
#include <new> /* for std::nothrow_t, std::align_val_t */
|
||||
#endif
|
||||
|
||||
/* Define the version number so folks can check against it */
|
||||
#define TC_VERSION_MAJOR @TC_VERSION_MAJOR@
|
||||
#define TC_VERSION_MINOR @TC_VERSION_MINOR@
|
||||
#define TC_VERSION_PATCH "@TC_VERSION_PATCH@"
|
||||
#define TC_VERSION_STRING "gperftools @TC_VERSION_MAJOR@.@TC_VERSION_MINOR@@TC_VERSION_PATCH@"
|
||||
|
||||
#ifndef PERFTOOLS_NOTHROW
|
||||
|
||||
#if __cplusplus >= 201103L
|
||||
#define PERFTOOLS_NOTHROW noexcept
|
||||
#elif defined(__cplusplus)
|
||||
#define PERFTOOLS_NOTHROW throw()
|
||||
#else
|
||||
# ifdef __GNUC__
|
||||
# define PERFTOOLS_NOTHROW __attribute__((__nothrow__))
|
||||
# else
|
||||
# define PERFTOOLS_NOTHROW
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef PERFTOOLS_DLL_DECL
|
||||
# ifdef _WIN32
|
||||
# define PERFTOOLS_DLL_DECL __declspec(dllimport)
|
||||
# else
|
||||
# define PERFTOOLS_DLL_DECL
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
/*
|
||||
* Returns a human-readable version string. If major, minor,
|
||||
* and/or patch are not NULL, they are set to the major version,
|
||||
* minor version, and patch-code (a string, usually "").
|
||||
*/
|
||||
PERFTOOLS_DLL_DECL const char* tc_version(int* major, int* minor,
|
||||
const char** patch) PERFTOOLS_NOTHROW;
|
||||
|
||||
PERFTOOLS_DLL_DECL void* tc_malloc(size_t size) PERFTOOLS_NOTHROW;
|
||||
PERFTOOLS_DLL_DECL void* tc_malloc_skip_new_handler(size_t size) PERFTOOLS_NOTHROW;
|
||||
PERFTOOLS_DLL_DECL void tc_free(void* ptr) PERFTOOLS_NOTHROW;
|
||||
PERFTOOLS_DLL_DECL void tc_free_sized(void *ptr, size_t size) PERFTOOLS_NOTHROW;
|
||||
PERFTOOLS_DLL_DECL void* tc_realloc(void* ptr, size_t size) PERFTOOLS_NOTHROW;
|
||||
PERFTOOLS_DLL_DECL void* tc_calloc(size_t nmemb, size_t size) PERFTOOLS_NOTHROW;
|
||||
PERFTOOLS_DLL_DECL void tc_cfree(void* ptr) PERFTOOLS_NOTHROW;
|
||||
|
||||
PERFTOOLS_DLL_DECL void* tc_memalign(size_t __alignment,
|
||||
size_t __size) PERFTOOLS_NOTHROW;
|
||||
PERFTOOLS_DLL_DECL int tc_posix_memalign(void** ptr,
|
||||
size_t align, size_t size) PERFTOOLS_NOTHROW;
|
||||
PERFTOOLS_DLL_DECL void* tc_valloc(size_t __size) PERFTOOLS_NOTHROW;
|
||||
PERFTOOLS_DLL_DECL void* tc_pvalloc(size_t __size) PERFTOOLS_NOTHROW;
|
||||
|
||||
PERFTOOLS_DLL_DECL void tc_malloc_stats(void) PERFTOOLS_NOTHROW;
|
||||
PERFTOOLS_DLL_DECL int tc_mallopt(int cmd, int value) PERFTOOLS_NOTHROW;
|
||||
|
||||
/*
|
||||
* This is an alias for MallocExtension::instance()->GetAllocatedSize().
|
||||
* It is equivalent to
|
||||
* OS X: malloc_size()
|
||||
* glibc: malloc_usable_size()
|
||||
* Windows: _msize()
|
||||
*/
|
||||
PERFTOOLS_DLL_DECL size_t tc_malloc_size(void* ptr) PERFTOOLS_NOTHROW;
|
||||
|
||||
#ifdef __cplusplus
|
||||
PERFTOOLS_DLL_DECL int tc_set_new_mode(int flag) PERFTOOLS_NOTHROW;
|
||||
PERFTOOLS_DLL_DECL void* tc_new(size_t size);
|
||||
PERFTOOLS_DLL_DECL void* tc_new_nothrow(size_t size,
|
||||
const std::nothrow_t&) PERFTOOLS_NOTHROW;
|
||||
PERFTOOLS_DLL_DECL void tc_delete(void* p) PERFTOOLS_NOTHROW;
|
||||
PERFTOOLS_DLL_DECL void tc_delete_sized(void* p, size_t size) PERFTOOLS_NOTHROW;
|
||||
PERFTOOLS_DLL_DECL void tc_delete_nothrow(void* p,
|
||||
const std::nothrow_t&) PERFTOOLS_NOTHROW;
|
||||
PERFTOOLS_DLL_DECL void* tc_newarray(size_t size);
|
||||
PERFTOOLS_DLL_DECL void* tc_newarray_nothrow(size_t size,
|
||||
const std::nothrow_t&) PERFTOOLS_NOTHROW;
|
||||
PERFTOOLS_DLL_DECL void tc_deletearray(void* p) PERFTOOLS_NOTHROW;
|
||||
PERFTOOLS_DLL_DECL void tc_deletearray_sized(void* p, size_t size) PERFTOOLS_NOTHROW;
|
||||
PERFTOOLS_DLL_DECL void tc_deletearray_nothrow(void* p,
|
||||
const std::nothrow_t&) PERFTOOLS_NOTHROW;
|
||||
|
||||
#if defined(__cpp_aligned_new) || (defined(_MSVC_LANG) && _MSVC_LANG > 201402L)
|
||||
PERFTOOLS_DLL_DECL void* tc_new_aligned(size_t size, std::align_val_t al);
|
||||
PERFTOOLS_DLL_DECL void* tc_new_aligned_nothrow(size_t size, std::align_val_t al,
|
||||
const std::nothrow_t&) PERFTOOLS_NOTHROW;
|
||||
PERFTOOLS_DLL_DECL void tc_delete_aligned(void* p, std::align_val_t al) PERFTOOLS_NOTHROW;
|
||||
PERFTOOLS_DLL_DECL void tc_delete_sized_aligned(void* p, size_t size, std::align_val_t al) PERFTOOLS_NOTHROW;
|
||||
PERFTOOLS_DLL_DECL void tc_delete_aligned_nothrow(void* p, std::align_val_t al,
|
||||
const std::nothrow_t&) PERFTOOLS_NOTHROW;
|
||||
PERFTOOLS_DLL_DECL void* tc_newarray_aligned(size_t size, std::align_val_t al);
|
||||
PERFTOOLS_DLL_DECL void* tc_newarray_aligned_nothrow(size_t size, std::align_val_t al,
|
||||
const std::nothrow_t&) PERFTOOLS_NOTHROW;
|
||||
PERFTOOLS_DLL_DECL void tc_deletearray_aligned(void* p, std::align_val_t al) PERFTOOLS_NOTHROW;
|
||||
PERFTOOLS_DLL_DECL void tc_deletearray_sized_aligned(void* p, size_t size, std::align_val_t al) PERFTOOLS_NOTHROW;
|
||||
PERFTOOLS_DLL_DECL void tc_deletearray_aligned_nothrow(void* p, std::align_val_t al,
|
||||
const std::nothrow_t&) PERFTOOLS_NOTHROW;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
/* We're only un-defining for public */
|
||||
#if !defined(GPERFTOOLS_CONFIG_H_)
|
||||
|
||||
#undef PERFTOOLS_NOTHROW
|
||||
|
||||
#endif /* GPERFTOOLS_CONFIG_H_ */
|
||||
|
||||
#endif /* #ifndef TCMALLOC_TCMALLOC_H_ */
|
122
trunk/3rdparty/gperftools-2-fit/src/windows/ia32_modrm_map.cc
vendored
Normal file
122
trunk/3rdparty/gperftools-2-fit/src/windows/ia32_modrm_map.cc
vendored
Normal file
|
@ -0,0 +1,122 @@
|
|||
// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
|
||||
/* Copyright (c) 2007, Google Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* * Neither the name of Google Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* ---
|
||||
* Author: Joi Sigurdsson
|
||||
*
|
||||
* Table of relevant information about how to decode the ModR/M byte.
|
||||
* Based on information in the IA-32 Intel® Architecture
|
||||
* Software Developer's Manual Volume 2: Instruction Set Reference.
|
||||
*/
|
||||
|
||||
#include "mini_disassembler.h"
|
||||
#include "mini_disassembler_types.h"
|
||||
|
||||
namespace sidestep {
|
||||
|
||||
const ModrmEntry MiniDisassembler::s_ia16_modrm_map_[] = {
|
||||
// mod == 00
|
||||
/* r/m == 000 */ { false, false, OS_ZERO },
|
||||
/* r/m == 001 */ { false, false, OS_ZERO },
|
||||
/* r/m == 010 */ { false, false, OS_ZERO },
|
||||
/* r/m == 011 */ { false, false, OS_ZERO },
|
||||
/* r/m == 100 */ { false, false, OS_ZERO },
|
||||
/* r/m == 101 */ { false, false, OS_ZERO },
|
||||
/* r/m == 110 */ { true, false, OS_WORD },
|
||||
/* r/m == 111 */ { false, false, OS_ZERO },
|
||||
// mod == 01
|
||||
/* r/m == 000 */ { true, false, OS_BYTE },
|
||||
/* r/m == 001 */ { true, false, OS_BYTE },
|
||||
/* r/m == 010 */ { true, false, OS_BYTE },
|
||||
/* r/m == 011 */ { true, false, OS_BYTE },
|
||||
/* r/m == 100 */ { true, false, OS_BYTE },
|
||||
/* r/m == 101 */ { true, false, OS_BYTE },
|
||||
/* r/m == 110 */ { true, false, OS_BYTE },
|
||||
/* r/m == 111 */ { true, false, OS_BYTE },
|
||||
// mod == 10
|
||||
/* r/m == 000 */ { true, false, OS_WORD },
|
||||
/* r/m == 001 */ { true, false, OS_WORD },
|
||||
/* r/m == 010 */ { true, false, OS_WORD },
|
||||
/* r/m == 011 */ { true, false, OS_WORD },
|
||||
/* r/m == 100 */ { true, false, OS_WORD },
|
||||
/* r/m == 101 */ { true, false, OS_WORD },
|
||||
/* r/m == 110 */ { true, false, OS_WORD },
|
||||
/* r/m == 111 */ { true, false, OS_WORD },
|
||||
// mod == 11
|
||||
/* r/m == 000 */ { false, false, OS_ZERO },
|
||||
/* r/m == 001 */ { false, false, OS_ZERO },
|
||||
/* r/m == 010 */ { false, false, OS_ZERO },
|
||||
/* r/m == 011 */ { false, false, OS_ZERO },
|
||||
/* r/m == 100 */ { false, false, OS_ZERO },
|
||||
/* r/m == 101 */ { false, false, OS_ZERO },
|
||||
/* r/m == 110 */ { false, false, OS_ZERO },
|
||||
/* r/m == 111 */ { false, false, OS_ZERO }
|
||||
};
|
||||
|
||||
const ModrmEntry MiniDisassembler::s_ia32_modrm_map_[] = {
|
||||
// mod == 00
|
||||
/* r/m == 000 */ { false, false, OS_ZERO },
|
||||
/* r/m == 001 */ { false, false, OS_ZERO },
|
||||
/* r/m == 010 */ { false, false, OS_ZERO },
|
||||
/* r/m == 011 */ { false, false, OS_ZERO },
|
||||
/* r/m == 100 */ { false, true, OS_ZERO },
|
||||
/* r/m == 101 */ { true, false, OS_DOUBLE_WORD },
|
||||
/* r/m == 110 */ { false, false, OS_ZERO },
|
||||
/* r/m == 111 */ { false, false, OS_ZERO },
|
||||
// mod == 01
|
||||
/* r/m == 000 */ { true, false, OS_BYTE },
|
||||
/* r/m == 001 */ { true, false, OS_BYTE },
|
||||
/* r/m == 010 */ { true, false, OS_BYTE },
|
||||
/* r/m == 011 */ { true, false, OS_BYTE },
|
||||
/* r/m == 100 */ { true, true, OS_BYTE },
|
||||
/* r/m == 101 */ { true, false, OS_BYTE },
|
||||
/* r/m == 110 */ { true, false, OS_BYTE },
|
||||
/* r/m == 111 */ { true, false, OS_BYTE },
|
||||
// mod == 10
|
||||
/* r/m == 000 */ { true, false, OS_DOUBLE_WORD },
|
||||
/* r/m == 001 */ { true, false, OS_DOUBLE_WORD },
|
||||
/* r/m == 010 */ { true, false, OS_DOUBLE_WORD },
|
||||
/* r/m == 011 */ { true, false, OS_DOUBLE_WORD },
|
||||
/* r/m == 100 */ { true, true, OS_DOUBLE_WORD },
|
||||
/* r/m == 101 */ { true, false, OS_DOUBLE_WORD },
|
||||
/* r/m == 110 */ { true, false, OS_DOUBLE_WORD },
|
||||
/* r/m == 111 */ { true, false, OS_DOUBLE_WORD },
|
||||
// mod == 11
|
||||
/* r/m == 000 */ { false, false, OS_ZERO },
|
||||
/* r/m == 001 */ { false, false, OS_ZERO },
|
||||
/* r/m == 010 */ { false, false, OS_ZERO },
|
||||
/* r/m == 011 */ { false, false, OS_ZERO },
|
||||
/* r/m == 100 */ { false, false, OS_ZERO },
|
||||
/* r/m == 101 */ { false, false, OS_ZERO },
|
||||
/* r/m == 110 */ { false, false, OS_ZERO },
|
||||
/* r/m == 111 */ { false, false, OS_ZERO },
|
||||
};
|
||||
|
||||
}; // namespace sidestep
|
1220
trunk/3rdparty/gperftools-2-fit/src/windows/ia32_opcode_map.cc
vendored
Normal file
1220
trunk/3rdparty/gperftools-2-fit/src/windows/ia32_opcode_map.cc
vendored
Normal file
File diff suppressed because it is too large
Load diff
72
trunk/3rdparty/gperftools-2-fit/src/windows/mingw.h
vendored
Normal file
72
trunk/3rdparty/gperftools-2-fit/src/windows/mingw.h
vendored
Normal file
|
@ -0,0 +1,72 @@
|
|||
/* -*- Mode: C; c-basic-offset: 2; indent-tabs-mode: nil -*- */
|
||||
/* Copyright (c) 2007, Google Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* * Neither the name of Google Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* ---
|
||||
* Author: Craig Silverstein
|
||||
*
|
||||
* MinGW is an interesting mix of unix and windows. We use a normal
|
||||
* configure script, but still need the windows port.h to define some
|
||||
* stuff that MinGW doesn't support, like pthreads.
|
||||
*/
|
||||
|
||||
#ifndef GOOGLE_PERFTOOLS_WINDOWS_MINGW_H_
|
||||
#define GOOGLE_PERFTOOLS_WINDOWS_MINGW_H_
|
||||
|
||||
#ifdef __MINGW32__
|
||||
|
||||
// Older version of the mingw msvcrt don't define _aligned_malloc
|
||||
#if __MSVCRT_VERSION__ < 0x0700
|
||||
# define PERFTOOLS_NO_ALIGNED_MALLOC 1
|
||||
#endif
|
||||
|
||||
// This must be defined before the windows.h is included. We need at
|
||||
// least 0x0400 for mutex.h to have access to TryLock, and at least
|
||||
// 0x0501 for patch_functions.cc to have access to GetModuleHandleEx.
|
||||
// (This latter is an optimization we could take out if need be.)
|
||||
#ifndef _WIN32_WINNT
|
||||
# define _WIN32_WINNT 0x0501
|
||||
#endif
|
||||
|
||||
// Some mingw distributions have a pthreads wrapper, but it doesn't
|
||||
// work as well as native windows spinlocks (at least for us). So
|
||||
// pretend the pthreads wrapper doesn't exist, even when it does.
|
||||
#ifndef HAVE_PTHREAD_DESPITE_ASKING_FOR
|
||||
#undef HAVE_PTHREAD
|
||||
#endif
|
||||
|
||||
#undef HAVE_FORK
|
||||
|
||||
#define HAVE_PID_T
|
||||
|
||||
#include "windows/port.h"
|
||||
|
||||
#endif /* __MINGW32__ */
|
||||
|
||||
#endif /* GOOGLE_PERFTOOLS_WINDOWS_MINGW_H_ */
|
432
trunk/3rdparty/gperftools-2-fit/src/windows/mini_disassembler.cc
vendored
Normal file
432
trunk/3rdparty/gperftools-2-fit/src/windows/mini_disassembler.cc
vendored
Normal file
|
@ -0,0 +1,432 @@
|
|||
// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
|
||||
/* Copyright (c) 2007, Google Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* * Neither the name of Google Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* ---
|
||||
* Author: Joi Sigurdsson
|
||||
*
|
||||
* Implementation of MiniDisassembler.
|
||||
*/
|
||||
|
||||
#include "mini_disassembler.h"
|
||||
|
||||
namespace sidestep {
|
||||
|
||||
MiniDisassembler::MiniDisassembler(bool operand_default_is_32_bits,
|
||||
bool address_default_is_32_bits)
|
||||
: operand_default_is_32_bits_(operand_default_is_32_bits),
|
||||
address_default_is_32_bits_(address_default_is_32_bits) {
|
||||
Initialize();
|
||||
}
|
||||
|
||||
MiniDisassembler::MiniDisassembler()
|
||||
: operand_default_is_32_bits_(true),
|
||||
address_default_is_32_bits_(true) {
|
||||
Initialize();
|
||||
}
|
||||
|
||||
InstructionType MiniDisassembler::Disassemble(
|
||||
unsigned char* start_byte,
|
||||
unsigned int& instruction_bytes) {
|
||||
// Clean up any state from previous invocations.
|
||||
Initialize();
|
||||
|
||||
// Start by processing any prefixes.
|
||||
unsigned char* current_byte = start_byte;
|
||||
unsigned int size = 0;
|
||||
InstructionType instruction_type = ProcessPrefixes(current_byte, size);
|
||||
|
||||
if (IT_UNKNOWN == instruction_type)
|
||||
return instruction_type;
|
||||
|
||||
current_byte += size;
|
||||
size = 0;
|
||||
|
||||
// Invariant: We have stripped all prefixes, and the operand_is_32_bits_
|
||||
// and address_is_32_bits_ flags are correctly set.
|
||||
|
||||
instruction_type = ProcessOpcode(current_byte, 0, size);
|
||||
|
||||
// Check for error processing instruction
|
||||
if ((IT_UNKNOWN == instruction_type_) || (IT_UNUSED == instruction_type_)) {
|
||||
return IT_UNKNOWN;
|
||||
}
|
||||
|
||||
current_byte += size;
|
||||
|
||||
// Invariant: operand_bytes_ indicates the total size of operands
|
||||
// specified by the opcode and/or ModR/M byte and/or SIB byte.
|
||||
// pCurrentByte points to the first byte after the ModR/M byte, or after
|
||||
// the SIB byte if it is present (i.e. the first byte of any operands
|
||||
// encoded in the instruction).
|
||||
|
||||
// We get the total length of any prefixes, the opcode, and the ModR/M and
|
||||
// SIB bytes if present, by taking the difference of the original starting
|
||||
// address and the current byte (which points to the first byte of the
|
||||
// operands if present, or to the first byte of the next instruction if
|
||||
// they are not). Adding the count of bytes in the operands encoded in
|
||||
// the instruction gives us the full length of the instruction in bytes.
|
||||
instruction_bytes += operand_bytes_ + (current_byte - start_byte);
|
||||
|
||||
// Return the instruction type, which was set by ProcessOpcode().
|
||||
return instruction_type_;
|
||||
}
|
||||
|
||||
void MiniDisassembler::Initialize() {
|
||||
operand_is_32_bits_ = operand_default_is_32_bits_;
|
||||
address_is_32_bits_ = address_default_is_32_bits_;
|
||||
#ifdef _M_X64
|
||||
operand_default_support_64_bits_ = true;
|
||||
#else
|
||||
operand_default_support_64_bits_ = false;
|
||||
#endif
|
||||
operand_is_64_bits_ = false;
|
||||
operand_bytes_ = 0;
|
||||
have_modrm_ = false;
|
||||
should_decode_modrm_ = false;
|
||||
instruction_type_ = IT_UNKNOWN;
|
||||
got_f2_prefix_ = false;
|
||||
got_f3_prefix_ = false;
|
||||
got_66_prefix_ = false;
|
||||
}
|
||||
|
||||
InstructionType MiniDisassembler::ProcessPrefixes(unsigned char* start_byte,
|
||||
unsigned int& size) {
|
||||
InstructionType instruction_type = IT_GENERIC;
|
||||
const Opcode& opcode = s_ia32_opcode_map_[0].table_[*start_byte];
|
||||
|
||||
switch (opcode.type_) {
|
||||
case IT_PREFIX_ADDRESS:
|
||||
address_is_32_bits_ = !address_default_is_32_bits_;
|
||||
goto nochangeoperand;
|
||||
case IT_PREFIX_OPERAND:
|
||||
operand_is_32_bits_ = !operand_default_is_32_bits_;
|
||||
nochangeoperand:
|
||||
case IT_PREFIX:
|
||||
|
||||
if (0xF2 == (*start_byte))
|
||||
got_f2_prefix_ = true;
|
||||
else if (0xF3 == (*start_byte))
|
||||
got_f3_prefix_ = true;
|
||||
else if (0x66 == (*start_byte))
|
||||
got_66_prefix_ = true;
|
||||
else if (operand_default_support_64_bits_ && (*start_byte) & 0x48)
|
||||
operand_is_64_bits_ = true;
|
||||
|
||||
instruction_type = opcode.type_;
|
||||
size ++;
|
||||
// we got a prefix, so add one and check next byte
|
||||
ProcessPrefixes(start_byte + 1, size);
|
||||
default:
|
||||
break; // not a prefix byte
|
||||
}
|
||||
|
||||
return instruction_type;
|
||||
}
|
||||
|
||||
InstructionType MiniDisassembler::ProcessOpcode(unsigned char* start_byte,
|
||||
unsigned int table_index,
|
||||
unsigned int& size) {
|
||||
const OpcodeTable& table = s_ia32_opcode_map_[table_index]; // Get our table
|
||||
unsigned char current_byte = (*start_byte) >> table.shift_;
|
||||
current_byte = current_byte & table.mask_; // Mask out the bits we will use
|
||||
|
||||
// Check whether the byte we have is inside the table we have.
|
||||
if (current_byte < table.min_lim_ || current_byte > table.max_lim_) {
|
||||
instruction_type_ = IT_UNKNOWN;
|
||||
return instruction_type_;
|
||||
}
|
||||
|
||||
const Opcode& opcode = table.table_[current_byte];
|
||||
if (IT_UNUSED == opcode.type_) {
|
||||
// This instruction is not used by the IA-32 ISA, so we indicate
|
||||
// this to the user. Probably means that we were pointed to
|
||||
// a byte in memory that was not the start of an instruction.
|
||||
instruction_type_ = IT_UNUSED;
|
||||
return instruction_type_;
|
||||
} else if (IT_REFERENCE == opcode.type_) {
|
||||
// We are looking at an opcode that has more bytes (or is continued
|
||||
// in the ModR/M byte). Recursively find the opcode definition in
|
||||
// the table for the opcode's next byte.
|
||||
size++;
|
||||
ProcessOpcode(start_byte + 1, opcode.table_index_, size);
|
||||
return instruction_type_;
|
||||
}
|
||||
|
||||
const SpecificOpcode* specific_opcode = (SpecificOpcode*)&opcode;
|
||||
if (opcode.is_prefix_dependent_) {
|
||||
if (got_f2_prefix_ && opcode.opcode_if_f2_prefix_.mnemonic_ != 0) {
|
||||
specific_opcode = &opcode.opcode_if_f2_prefix_;
|
||||
} else if (got_f3_prefix_ && opcode.opcode_if_f3_prefix_.mnemonic_ != 0) {
|
||||
specific_opcode = &opcode.opcode_if_f3_prefix_;
|
||||
} else if (got_66_prefix_ && opcode.opcode_if_66_prefix_.mnemonic_ != 0) {
|
||||
specific_opcode = &opcode.opcode_if_66_prefix_;
|
||||
}
|
||||
}
|
||||
|
||||
// Inv: The opcode type is known.
|
||||
instruction_type_ = specific_opcode->type_;
|
||||
|
||||
// Let's process the operand types to see if we have any immediate
|
||||
// operands, and/or a ModR/M byte.
|
||||
|
||||
ProcessOperand(specific_opcode->flag_dest_);
|
||||
ProcessOperand(specific_opcode->flag_source_);
|
||||
ProcessOperand(specific_opcode->flag_aux_);
|
||||
|
||||
// Inv: We have processed the opcode and incremented operand_bytes_
|
||||
// by the number of bytes of any operands specified by the opcode
|
||||
// that are stored in the instruction (not registers etc.). Now
|
||||
// we need to return the total number of bytes for the opcode and
|
||||
// for the ModR/M or SIB bytes if they are present.
|
||||
|
||||
if (table.mask_ != 0xff) {
|
||||
if (have_modrm_) {
|
||||
// we're looking at a ModR/M byte so we're not going to
|
||||
// count that into the opcode size
|
||||
ProcessModrm(start_byte, size);
|
||||
return IT_GENERIC;
|
||||
} else {
|
||||
// need to count the ModR/M byte even if it's just being
|
||||
// used for opcode extension
|
||||
size++;
|
||||
return IT_GENERIC;
|
||||
}
|
||||
} else {
|
||||
if (have_modrm_) {
|
||||
// The ModR/M byte is the next byte.
|
||||
size++;
|
||||
ProcessModrm(start_byte + 1, size);
|
||||
return IT_GENERIC;
|
||||
} else {
|
||||
size++;
|
||||
return IT_GENERIC;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool MiniDisassembler::ProcessOperand(int flag_operand) {
|
||||
bool succeeded = true;
|
||||
if (AM_NOT_USED == flag_operand)
|
||||
return succeeded;
|
||||
|
||||
// Decide what to do based on the addressing mode.
|
||||
switch (flag_operand & AM_MASK) {
|
||||
// No ModR/M byte indicated by these addressing modes, and no
|
||||
// additional (e.g. immediate) parameters.
|
||||
case AM_A: // Direct address
|
||||
case AM_F: // EFLAGS register
|
||||
case AM_X: // Memory addressed by the DS:SI register pair
|
||||
case AM_Y: // Memory addressed by the ES:DI register pair
|
||||
case AM_IMPLICIT: // Parameter is implicit, occupies no space in
|
||||
// instruction
|
||||
break;
|
||||
|
||||
// There is a ModR/M byte but it does not necessarily need
|
||||
// to be decoded.
|
||||
case AM_C: // reg field of ModR/M selects a control register
|
||||
case AM_D: // reg field of ModR/M selects a debug register
|
||||
case AM_G: // reg field of ModR/M selects a general register
|
||||
case AM_P: // reg field of ModR/M selects an MMX register
|
||||
case AM_R: // mod field of ModR/M may refer only to a general register
|
||||
case AM_S: // reg field of ModR/M selects a segment register
|
||||
case AM_T: // reg field of ModR/M selects a test register
|
||||
case AM_V: // reg field of ModR/M selects a 128-bit XMM register
|
||||
have_modrm_ = true;
|
||||
break;
|
||||
|
||||
// In these addressing modes, there is a ModR/M byte and it needs to be
|
||||
// decoded. No other (e.g. immediate) params than indicated in ModR/M.
|
||||
case AM_E: // Operand is either a general-purpose register or memory,
|
||||
// specified by ModR/M byte
|
||||
case AM_M: // ModR/M byte will refer only to memory
|
||||
case AM_Q: // Operand is either an MMX register or memory (complex
|
||||
// evaluation), specified by ModR/M byte
|
||||
case AM_W: // Operand is either a 128-bit XMM register or memory (complex
|
||||
// eval), specified by ModR/M byte
|
||||
have_modrm_ = true;
|
||||
should_decode_modrm_ = true;
|
||||
break;
|
||||
|
||||
// These addressing modes specify an immediate or an offset value
|
||||
// directly, so we need to look at the operand type to see how many
|
||||
// bytes.
|
||||
case AM_I: // Immediate data.
|
||||
case AM_J: // Jump to offset.
|
||||
case AM_O: // Operand is at offset.
|
||||
switch (flag_operand & OT_MASK) {
|
||||
case OT_B: // Byte regardless of operand-size attribute.
|
||||
operand_bytes_ += OS_BYTE;
|
||||
break;
|
||||
case OT_C: // Byte or word, depending on operand-size attribute.
|
||||
if (operand_is_32_bits_)
|
||||
operand_bytes_ += OS_WORD;
|
||||
else
|
||||
operand_bytes_ += OS_BYTE;
|
||||
break;
|
||||
case OT_D: // Doubleword, regardless of operand-size attribute.
|
||||
operand_bytes_ += OS_DOUBLE_WORD;
|
||||
break;
|
||||
case OT_DQ: // Double-quadword, regardless of operand-size attribute.
|
||||
operand_bytes_ += OS_DOUBLE_QUAD_WORD;
|
||||
break;
|
||||
case OT_P: // 32-bit or 48-bit pointer, depending on operand-size
|
||||
// attribute.
|
||||
if (operand_is_32_bits_)
|
||||
operand_bytes_ += OS_48_BIT_POINTER;
|
||||
else
|
||||
operand_bytes_ += OS_32_BIT_POINTER;
|
||||
break;
|
||||
case OT_PS: // 128-bit packed single-precision floating-point data.
|
||||
operand_bytes_ += OS_128_BIT_PACKED_SINGLE_PRECISION_FLOATING;
|
||||
break;
|
||||
case OT_Q: // Quadword, regardless of operand-size attribute.
|
||||
operand_bytes_ += OS_QUAD_WORD;
|
||||
break;
|
||||
case OT_S: // 6-byte pseudo-descriptor.
|
||||
operand_bytes_ += OS_PSEUDO_DESCRIPTOR;
|
||||
break;
|
||||
case OT_SD: // Scalar Double-Precision Floating-Point Value
|
||||
case OT_PD: // Unaligned packed double-precision floating point value
|
||||
operand_bytes_ += OS_DOUBLE_PRECISION_FLOATING;
|
||||
break;
|
||||
case OT_SS:
|
||||
// Scalar element of a 128-bit packed single-precision
|
||||
// floating data.
|
||||
// We simply return enItUnknown since we don't have to support
|
||||
// floating point
|
||||
succeeded = false;
|
||||
break;
|
||||
case OT_V: // Word, doubleword or quadword, depending on operand-size
|
||||
// attribute.
|
||||
if (operand_is_64_bits_ && flag_operand & AM_I &&
|
||||
flag_operand & IOS_64)
|
||||
operand_bytes_ += OS_QUAD_WORD;
|
||||
else if (operand_is_32_bits_)
|
||||
operand_bytes_ += OS_DOUBLE_WORD;
|
||||
else
|
||||
operand_bytes_ += OS_WORD;
|
||||
break;
|
||||
case OT_W: // Word, regardless of operand-size attribute.
|
||||
operand_bytes_ += OS_WORD;
|
||||
break;
|
||||
|
||||
// Can safely ignore these.
|
||||
case OT_A: // Two one-word operands in memory or two double-word
|
||||
// operands in memory
|
||||
case OT_PI: // Quadword MMX technology register (e.g. mm0)
|
||||
case OT_SI: // Doubleword integer register (e.g., eax)
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return succeeded;
|
||||
}
|
||||
|
||||
bool MiniDisassembler::ProcessModrm(unsigned char* start_byte,
|
||||
unsigned int& size) {
|
||||
// If we don't need to decode, we just return the size of the ModR/M
|
||||
// byte (there is never a SIB byte in this case).
|
||||
if (!should_decode_modrm_) {
|
||||
size++;
|
||||
return true;
|
||||
}
|
||||
|
||||
// We never care about the reg field, only the combination of the mod
|
||||
// and r/m fields, so let's start by packing those fields together into
|
||||
// 5 bits.
|
||||
unsigned char modrm = (*start_byte);
|
||||
unsigned char mod = modrm & 0xC0; // mask out top two bits to get mod field
|
||||
modrm = modrm & 0x07; // mask out bottom 3 bits to get r/m field
|
||||
mod = mod >> 3; // shift the mod field to the right place
|
||||
modrm = mod | modrm; // combine the r/m and mod fields as discussed
|
||||
mod = mod >> 3; // shift the mod field to bits 2..0
|
||||
|
||||
// Invariant: modrm contains the mod field in bits 4..3 and the r/m field
|
||||
// in bits 2..0, and mod contains the mod field in bits 2..0
|
||||
|
||||
const ModrmEntry* modrm_entry = 0;
|
||||
if (address_is_32_bits_)
|
||||
modrm_entry = &s_ia32_modrm_map_[modrm];
|
||||
else
|
||||
modrm_entry = &s_ia16_modrm_map_[modrm];
|
||||
|
||||
// Invariant: modrm_entry points to information that we need to decode
|
||||
// the ModR/M byte.
|
||||
|
||||
// Add to the count of operand bytes, if the ModR/M byte indicates
|
||||
// that some operands are encoded in the instruction.
|
||||
if (modrm_entry->is_encoded_in_instruction_)
|
||||
operand_bytes_ += modrm_entry->operand_size_;
|
||||
|
||||
// Process the SIB byte if necessary, and return the count
|
||||
// of ModR/M and SIB bytes.
|
||||
if (modrm_entry->use_sib_byte_) {
|
||||
size++;
|
||||
return ProcessSib(start_byte + 1, mod, size);
|
||||
} else {
|
||||
size++;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool MiniDisassembler::ProcessSib(unsigned char* start_byte,
|
||||
unsigned char mod,
|
||||
unsigned int& size) {
|
||||
// get the mod field from the 2..0 bits of the SIB byte
|
||||
unsigned char sib_base = (*start_byte) & 0x07;
|
||||
if (0x05 == sib_base) {
|
||||
switch (mod) {
|
||||
case 0x00: // mod == 00
|
||||
case 0x02: // mod == 10
|
||||
operand_bytes_ += OS_DOUBLE_WORD;
|
||||
break;
|
||||
case 0x01: // mod == 01
|
||||
operand_bytes_ += OS_BYTE;
|
||||
break;
|
||||
case 0x03: // mod == 11
|
||||
// According to the IA-32 docs, there does not seem to be a disp
|
||||
// value for this value of mod
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
size++;
|
||||
return true;
|
||||
}
|
||||
|
||||
}; // namespace sidestep
|
198
trunk/3rdparty/gperftools-2-fit/src/windows/mini_disassembler.h
vendored
Normal file
198
trunk/3rdparty/gperftools-2-fit/src/windows/mini_disassembler.h
vendored
Normal file
|
@ -0,0 +1,198 @@
|
|||
// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
|
||||
/* Copyright (c) 2007, Google Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* * Neither the name of Google Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* ---
|
||||
* Author: Joi Sigurdsson
|
||||
*
|
||||
* Definition of MiniDisassembler.
|
||||
*/
|
||||
|
||||
#ifndef GOOGLE_PERFTOOLS_MINI_DISASSEMBLER_H_
|
||||
#define GOOGLE_PERFTOOLS_MINI_DISASSEMBLER_H_
|
||||
|
||||
#include "config.h"
|
||||
#include <windows.h>
|
||||
#include "mini_disassembler_types.h"
|
||||
|
||||
// compatibility shim
|
||||
#include "base/logging.h"
|
||||
#define SIDESTEP_ASSERT(cond) RAW_DCHECK(cond, #cond)
|
||||
#define SIDESTEP_LOG(msg) RAW_VLOG(1, msg)
|
||||
|
||||
namespace sidestep {
|
||||
|
||||
// This small disassembler is very limited
|
||||
// in its functionality, and in fact does only the bare minimum required by the
|
||||
// preamble patching utility. It may be useful for other purposes, however.
|
||||
//
|
||||
// The limitations include at least the following:
|
||||
// -# No support for coprocessor opcodes, MMX, etc.
|
||||
// -# No machine-readable identification of opcodes or decoding of
|
||||
// assembly parameters. The name of the opcode (as a string) is given,
|
||||
// however, to aid debugging.
|
||||
//
|
||||
// You may ask what this little disassembler actually does, then? The answer is
|
||||
// that it does the following, which is exactly what the patching utility needs:
|
||||
// -# Indicates if opcode is a jump (any kind) or a return (any kind)
|
||||
// because this is important for the patching utility to determine if
|
||||
// a function is too short or there are jumps too early in it for it
|
||||
// to be preamble patched.
|
||||
// -# The opcode length is always calculated, so that the patching utility
|
||||
// can figure out where the next instruction starts, and whether it
|
||||
// already has enough instructions to replace with the absolute jump
|
||||
// to the patching code.
|
||||
//
|
||||
// The usage is quite simple; just create a MiniDisassembler and use its
|
||||
// Disassemble() method.
|
||||
//
|
||||
// If you would like to extend this disassembler, please refer to the
|
||||
// IA-32 Intel® Architecture Software Developer's Manual Volume 2:
|
||||
// Instruction Set Reference for information about operand decoding
|
||||
// etc.
|
||||
class PERFTOOLS_DLL_DECL MiniDisassembler {
|
||||
public:
|
||||
|
||||
// Creates a new instance and sets defaults.
|
||||
//
|
||||
// @param operand_default_32_bits If true, the default operand size is
|
||||
// set to 32 bits, which is the default under Win32. Otherwise it is 16 bits.
|
||||
// @param address_default_32_bits If true, the default address size is
|
||||
// set to 32 bits, which is the default under Win32. Otherwise it is 16 bits.
|
||||
MiniDisassembler(bool operand_default_32_bits,
|
||||
bool address_default_32_bits);
|
||||
|
||||
// Equivalent to MiniDisassembler(true, true);
|
||||
MiniDisassembler();
|
||||
|
||||
// Attempts to disassemble a single instruction starting from the
|
||||
// address in memory it is pointed to.
|
||||
//
|
||||
// @param start Address where disassembly should start.
|
||||
// @param instruction_bytes Variable that will be <b>incremented</b> by
|
||||
// the length in bytes of the instruction.
|
||||
// @return enItJump, enItReturn or enItGeneric on success. enItUnknown
|
||||
// if unable to disassemble, enItUnused if this seems to be an unused
|
||||
// opcode. In the last two (error) cases, cbInstruction will be set
|
||||
// to 0xffffffff.
|
||||
//
|
||||
// @post This instance of the disassembler is ready to be used again,
|
||||
// with unchanged defaults from creation time.
|
||||
InstructionType Disassemble(unsigned char* start, unsigned int& instruction_bytes);
|
||||
|
||||
private:
|
||||
|
||||
// Makes the disassembler ready for reuse.
|
||||
void Initialize();
|
||||
|
||||
// Sets the flags for address and operand sizes.
|
||||
// @return Number of prefix bytes.
|
||||
InstructionType ProcessPrefixes(unsigned char* start, unsigned int& size);
|
||||
|
||||
// Sets the flag for whether we have ModR/M, and increments
|
||||
// operand_bytes_ if any are specifies by the opcode directly.
|
||||
// @return Number of opcode bytes.
|
||||
InstructionType ProcessOpcode(unsigned char* start,
|
||||
unsigned int table,
|
||||
unsigned int& size);
|
||||
|
||||
// Checks the type of the supplied operand. Increments
|
||||
// operand_bytes_ if it directly indicates an immediate etc.
|
||||
// operand. Asserts have_modrm_ if the operand specifies
|
||||
// a ModR/M byte.
|
||||
bool ProcessOperand(int flag_operand);
|
||||
|
||||
// Increments operand_bytes_ by size specified by ModR/M and
|
||||
// by SIB if present.
|
||||
// @return 0 in case of error, 1 if there is just a ModR/M byte,
|
||||
// 2 if there is a ModR/M byte and a SIB byte.
|
||||
bool ProcessModrm(unsigned char* start, unsigned int& size);
|
||||
|
||||
// Processes the SIB byte that it is pointed to.
|
||||
// @param start Pointer to the SIB byte.
|
||||
// @param mod The mod field from the ModR/M byte.
|
||||
// @return 1 to indicate success (indicates 1 SIB byte)
|
||||
bool ProcessSib(unsigned char* start, unsigned char mod, unsigned int& size);
|
||||
|
||||
// The instruction type we have decoded from the opcode.
|
||||
InstructionType instruction_type_;
|
||||
|
||||
// Counts the number of bytes that is occupied by operands in
|
||||
// the current instruction (note: we don't care about how large
|
||||
// operands stored in registers etc. are).
|
||||
unsigned int operand_bytes_;
|
||||
|
||||
// True iff there is a ModR/M byte in this instruction.
|
||||
bool have_modrm_;
|
||||
|
||||
// True iff we need to decode the ModR/M byte (sometimes it just
|
||||
// points to a register, we can tell by the addressing mode).
|
||||
bool should_decode_modrm_;
|
||||
|
||||
// Current operand size is 32 bits if true, 16 bits if false.
|
||||
bool operand_is_32_bits_;
|
||||
|
||||
// Default operand size is 32 bits if true, 16 bits if false.
|
||||
bool operand_default_is_32_bits_;
|
||||
|
||||
// Current address size is 32 bits if true, 16 bits if false.
|
||||
bool address_is_32_bits_;
|
||||
|
||||
// Default address size is 32 bits if true, 16 bits if false.
|
||||
bool address_default_is_32_bits_;
|
||||
|
||||
// Determines if 64 bit operands are supported (x64).
|
||||
bool operand_default_support_64_bits_;
|
||||
|
||||
// Current operand size is 64 bits if true, 32 bits if false.
|
||||
bool operand_is_64_bits_;
|
||||
|
||||
// Huge big opcode table based on the IA-32 manual, defined
|
||||
// in Ia32OpcodeMap.cc
|
||||
static const OpcodeTable s_ia32_opcode_map_[];
|
||||
|
||||
// Somewhat smaller table to help with decoding ModR/M bytes
|
||||
// when 16-bit addressing mode is being used. Defined in
|
||||
// Ia32ModrmMap.cc
|
||||
static const ModrmEntry s_ia16_modrm_map_[];
|
||||
|
||||
// Somewhat smaller table to help with decoding ModR/M bytes
|
||||
// when 32-bit addressing mode is being used. Defined in
|
||||
// Ia32ModrmMap.cc
|
||||
static const ModrmEntry s_ia32_modrm_map_[];
|
||||
|
||||
// Indicators of whether we got certain prefixes that certain
|
||||
// silly Intel instructions depend on in nonstandard ways for
|
||||
// their behaviors.
|
||||
bool got_f2_prefix_, got_f3_prefix_, got_66_prefix_;
|
||||
};
|
||||
|
||||
}; // namespace sidestep
|
||||
|
||||
#endif // GOOGLE_PERFTOOLS_MINI_DISASSEMBLER_H_
|
237
trunk/3rdparty/gperftools-2-fit/src/windows/mini_disassembler_types.h
vendored
Normal file
237
trunk/3rdparty/gperftools-2-fit/src/windows/mini_disassembler_types.h
vendored
Normal file
|
@ -0,0 +1,237 @@
|
|||
// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
|
||||
/* Copyright (c) 2007, Google Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* * Neither the name of Google Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* ---
|
||||
* Author: Joi Sigurdsson
|
||||
*
|
||||
* Several simple types used by the disassembler and some of the patching
|
||||
* mechanisms.
|
||||
*/
|
||||
|
||||
#ifndef GOOGLE_PERFTOOLS_MINI_DISASSEMBLER_TYPES_H_
|
||||
#define GOOGLE_PERFTOOLS_MINI_DISASSEMBLER_TYPES_H_
|
||||
|
||||
namespace sidestep {
|
||||
|
||||
// Categories of instructions that we care about
|
||||
enum InstructionType {
|
||||
// This opcode is not used
|
||||
IT_UNUSED,
|
||||
// This disassembler does not recognize this opcode (error)
|
||||
IT_UNKNOWN,
|
||||
// This is not an instruction but a reference to another table
|
||||
IT_REFERENCE,
|
||||
// This byte is a prefix byte that we can ignore
|
||||
IT_PREFIX,
|
||||
// This is a prefix byte that switches to the nondefault address size
|
||||
IT_PREFIX_ADDRESS,
|
||||
// This is a prefix byte that switches to the nondefault operand size
|
||||
IT_PREFIX_OPERAND,
|
||||
// A jump or call instruction
|
||||
IT_JUMP,
|
||||
// A return instruction
|
||||
IT_RETURN,
|
||||
// Any other type of instruction (in this case we don't care what it is)
|
||||
IT_GENERIC,
|
||||
};
|
||||
|
||||
// Lists IA-32 operand sizes in multiples of 8 bits
|
||||
enum OperandSize {
|
||||
OS_ZERO = 0,
|
||||
OS_BYTE = 1,
|
||||
OS_WORD = 2,
|
||||
OS_DOUBLE_WORD = 4,
|
||||
OS_QUAD_WORD = 8,
|
||||
OS_DOUBLE_QUAD_WORD = 16,
|
||||
OS_32_BIT_POINTER = 32/8,
|
||||
OS_48_BIT_POINTER = 48/8,
|
||||
OS_SINGLE_PRECISION_FLOATING = 32/8,
|
||||
OS_DOUBLE_PRECISION_FLOATING = 64/8,
|
||||
OS_DOUBLE_EXTENDED_PRECISION_FLOATING = 80/8,
|
||||
OS_128_BIT_PACKED_SINGLE_PRECISION_FLOATING = 128/8,
|
||||
OS_PSEUDO_DESCRIPTOR = 6
|
||||
};
|
||||
|
||||
// Operand addressing methods from the IA-32 manual. The enAmMask value
|
||||
// is a mask for the rest. The other enumeration values are named for the
|
||||
// names given to the addressing methods in the manual, e.g. enAm_D is for
|
||||
// the D addressing method.
|
||||
//
|
||||
// The reason we use a full 4 bytes and a mask, is that we need to combine
|
||||
// these flags with the enOperandType to store the details
|
||||
// on the operand in a single integer.
|
||||
enum AddressingMethod {
|
||||
AM_NOT_USED = 0, // This operand is not used for this instruction
|
||||
AM_MASK = 0x00FF0000, // Mask for the rest of the values in this enumeration
|
||||
AM_A = 0x00010000, // A addressing type
|
||||
AM_C = 0x00020000, // C addressing type
|
||||
AM_D = 0x00030000, // D addressing type
|
||||
AM_E = 0x00040000, // E addressing type
|
||||
AM_F = 0x00050000, // F addressing type
|
||||
AM_G = 0x00060000, // G addressing type
|
||||
AM_I = 0x00070000, // I addressing type
|
||||
AM_J = 0x00080000, // J addressing type
|
||||
AM_M = 0x00090000, // M addressing type
|
||||
AM_O = 0x000A0000, // O addressing type
|
||||
AM_P = 0x000B0000, // P addressing type
|
||||
AM_Q = 0x000C0000, // Q addressing type
|
||||
AM_R = 0x000D0000, // R addressing type
|
||||
AM_S = 0x000E0000, // S addressing type
|
||||
AM_T = 0x000F0000, // T addressing type
|
||||
AM_V = 0x00100000, // V addressing type
|
||||
AM_W = 0x00110000, // W addressing type
|
||||
AM_X = 0x00120000, // X addressing type
|
||||
AM_Y = 0x00130000, // Y addressing type
|
||||
AM_REGISTER = 0x00140000, // Specific register is always used as this op
|
||||
AM_IMPLICIT = 0x00150000, // An implicit, fixed value is used
|
||||
};
|
||||
|
||||
// Operand types from the IA-32 manual. The enOtMask value is
|
||||
// a mask for the rest. The rest of the values are named for the
|
||||
// names given to these operand types in the manual, e.g. enOt_ps
|
||||
// is for the ps operand type in the manual.
|
||||
//
|
||||
// The reason we use a full 4 bytes and a mask, is that we need
|
||||
// to combine these flags with the enAddressingMethod to store the details
|
||||
// on the operand in a single integer.
|
||||
enum OperandType {
|
||||
OT_MASK = 0xFF000000,
|
||||
OT_A = 0x01000000,
|
||||
OT_B = 0x02000000,
|
||||
OT_C = 0x03000000,
|
||||
OT_D = 0x04000000,
|
||||
OT_DQ = 0x05000000,
|
||||
OT_P = 0x06000000,
|
||||
OT_PI = 0x07000000,
|
||||
OT_PS = 0x08000000, // actually unsupported for (we don't know its size)
|
||||
OT_Q = 0x09000000,
|
||||
OT_S = 0x0A000000,
|
||||
OT_SS = 0x0B000000,
|
||||
OT_SI = 0x0C000000,
|
||||
OT_V = 0x0D000000,
|
||||
OT_W = 0x0E000000,
|
||||
OT_SD = 0x0F000000, // scalar double-precision floating-point value
|
||||
OT_PD = 0x10000000, // double-precision floating point
|
||||
// dummy "operand type" for address mode M - which doesn't specify
|
||||
// operand type
|
||||
OT_ADDRESS_MODE_M = 0x80000000
|
||||
};
|
||||
|
||||
// Flag that indicates if an immediate operand is 64-bits.
|
||||
//
|
||||
// The Intel 64 and IA-32 Architecture Software Developer's Manual currently
|
||||
// defines MOV as the only instruction supporting a 64-bit immediate operand.
|
||||
enum ImmediateOperandSize {
|
||||
IOS_MASK = 0x0000F000,
|
||||
IOS_DEFAULT = 0x0,
|
||||
IOS_64 = 0x00001000
|
||||
};
|
||||
|
||||
// Everything that's in an Opcode (see below) except the three
|
||||
// alternative opcode structs for different prefixes.
|
||||
struct SpecificOpcode {
|
||||
// Index to continuation table, or 0 if this is the last
|
||||
// byte in the opcode.
|
||||
int table_index_;
|
||||
|
||||
// The opcode type
|
||||
InstructionType type_;
|
||||
|
||||
// Description of the type of the dest, src and aux operands,
|
||||
// put together from enOperandType, enAddressingMethod and
|
||||
// enImmediateOperandSize flags.
|
||||
int flag_dest_;
|
||||
int flag_source_;
|
||||
int flag_aux_;
|
||||
|
||||
// We indicate the mnemonic for debugging purposes
|
||||
const char* mnemonic_;
|
||||
};
|
||||
|
||||
// The information we keep in our tables about each of the different
|
||||
// valid instructions recognized by the IA-32 architecture.
|
||||
struct Opcode {
|
||||
// Index to continuation table, or 0 if this is the last
|
||||
// byte in the opcode.
|
||||
int table_index_;
|
||||
|
||||
// The opcode type
|
||||
InstructionType type_;
|
||||
|
||||
// Description of the type of the dest, src and aux operands,
|
||||
// put together from an enOperandType flag and an enAddressingMethod
|
||||
// flag.
|
||||
unsigned flag_dest_;
|
||||
unsigned flag_source_;
|
||||
unsigned flag_aux_;
|
||||
|
||||
// We indicate the mnemonic for debugging purposes
|
||||
const char* mnemonic_;
|
||||
|
||||
// Alternative opcode info if certain prefixes are specified.
|
||||
// In most cases, all of these are zeroed-out. Only used if
|
||||
// bPrefixDependent is true.
|
||||
bool is_prefix_dependent_;
|
||||
SpecificOpcode opcode_if_f2_prefix_;
|
||||
SpecificOpcode opcode_if_f3_prefix_;
|
||||
SpecificOpcode opcode_if_66_prefix_;
|
||||
};
|
||||
|
||||
// Information about each table entry.
|
||||
struct OpcodeTable {
|
||||
// Table of instruction entries
|
||||
const Opcode* table_;
|
||||
// How many bytes left to shift ModR/M byte <b>before</b> applying mask
|
||||
unsigned char shift_;
|
||||
// Mask to apply to byte being looked at before comparing to table
|
||||
unsigned char mask_;
|
||||
// Minimum/maximum indexes in table.
|
||||
unsigned char min_lim_;
|
||||
unsigned char max_lim_;
|
||||
};
|
||||
|
||||
// Information about each entry in table used to decode ModR/M byte.
|
||||
struct ModrmEntry {
|
||||
// Is the operand encoded as bytes in the instruction (rather than
|
||||
// if it's e.g. a register in which case it's just encoded in the
|
||||
// ModR/M byte)
|
||||
bool is_encoded_in_instruction_;
|
||||
|
||||
// Is there a SIB byte? In this case we always need to decode it.
|
||||
bool use_sib_byte_;
|
||||
|
||||
// What is the size of the operand (only important if it's encoded
|
||||
// in the instruction)?
|
||||
OperandSize operand_size_;
|
||||
};
|
||||
|
||||
}; // namespace sidestep
|
||||
|
||||
#endif // GOOGLE_PERFTOOLS_MINI_DISASSEMBLER_TYPES_H_
|
274
trunk/3rdparty/gperftools-2-fit/src/windows/nm-pdb.c
vendored
Normal file
274
trunk/3rdparty/gperftools-2-fit/src/windows/nm-pdb.c
vendored
Normal file
|
@ -0,0 +1,274 @@
|
|||
/* -*- Mode: c; c-basic-offset: 2; indent-tabs-mode: nil -*- */
|
||||
/* Copyright (c) 2008, Google Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* * Neither the name of Google Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* ---
|
||||
* Author: David Vitek
|
||||
*
|
||||
* Dump function addresses using Microsoft debug symbols. This works
|
||||
* on PDB files. Note that this program will download symbols to
|
||||
* c:\websymbols without asking.
|
||||
*/
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
#define _CRT_SECURE_NO_DEPRECATE
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h> // for _strdup
|
||||
|
||||
#include <windows.h>
|
||||
#include <dbghelp.h>
|
||||
|
||||
// Unfortunately, there is no versioning info in dbghelp.h so I can
|
||||
// tell whether it has an old-style (circa VC7.1) IMAGEHLP_MODULE64
|
||||
// struct, with only a few fields, or a new-style (circa VC8)
|
||||
// IMAGEHLP_MODULE64, with lots of fields. These fields are just used
|
||||
// for debugging, so it's fine to just assume the smaller struct, but
|
||||
// for most people, using a modern MSVC, the full struct is available.
|
||||
// If you are one of those people and would like this extra debugging
|
||||
// info, you can uncomment the line below.
|
||||
//#define VC8_OR_ABOVE
|
||||
|
||||
#define SEARCH_CAP (1024*1024)
|
||||
#define WEBSYM "SRV*c:\\websymbols*http://msdl.microsoft.com/download/symbols"
|
||||
|
||||
typedef struct {
|
||||
char *name;
|
||||
ULONG64 addr;
|
||||
ULONG flags;
|
||||
} SYM;
|
||||
|
||||
typedef struct {
|
||||
ULONG64 module_base;
|
||||
SYM *syms;
|
||||
DWORD syms_len;
|
||||
DWORD syms_cap;
|
||||
} SYM_CONTEXT;
|
||||
|
||||
static int sym_cmp(const void *_s1, const void *_s2) {
|
||||
const SYM *s1 = (const SYM *)_s1;
|
||||
const SYM *s2 = (const SYM *)_s2;
|
||||
|
||||
if (s1->addr < s2->addr)
|
||||
return -1;
|
||||
if (s1->addr > s2->addr)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static BOOL CALLBACK EnumSymProc(PSYMBOL_INFO symbol_info,
|
||||
ULONG symbol_size,
|
||||
PVOID user_context) {
|
||||
SYM_CONTEXT *ctx = (SYM_CONTEXT*)user_context;
|
||||
if (symbol_info->Address < ctx->module_base ||
|
||||
(symbol_info->Flags & SYMFLAG_TLSREL)) {
|
||||
return TRUE;
|
||||
}
|
||||
if (ctx->syms_len == ctx->syms_cap) {
|
||||
if (!ctx->syms_cap)
|
||||
ctx->syms_cap++;
|
||||
ctx->syms_cap *= 2;
|
||||
ctx->syms = realloc(ctx->syms, sizeof(ctx->syms[0]) * ctx->syms_cap);
|
||||
}
|
||||
ctx->syms[ctx->syms_len].name = _strdup(symbol_info->Name);
|
||||
ctx->syms[ctx->syms_len].addr = symbol_info->Address;
|
||||
ctx->syms[ctx->syms_len].flags = symbol_info->Flags;
|
||||
ctx->syms_len++;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void MaybePrint(const char* var, const char* description) {
|
||||
if (var[0])
|
||||
printf("%s: %s\n", description, var);
|
||||
}
|
||||
|
||||
static void PrintAvailability(BOOL var, const char *description) {
|
||||
printf("%s: %s\n", description, (var ? "Available" : "Not available"));
|
||||
}
|
||||
|
||||
static void ShowSymbolInfo(HANDLE process, ULONG64 module_base) {
|
||||
/* Get module information. */
|
||||
IMAGEHLP_MODULE64 module_info;
|
||||
BOOL getmoduleinfo_rv;
|
||||
printf("Load Address: %I64x\n", module_base);
|
||||
memset(&module_info, 0, sizeof(module_info));
|
||||
module_info.SizeOfStruct = sizeof(module_info);
|
||||
getmoduleinfo_rv = SymGetModuleInfo64(process, module_base, &module_info);
|
||||
if (!getmoduleinfo_rv) {
|
||||
printf("Error: SymGetModuleInfo64() failed. Error code: %u\n",
|
||||
GetLastError());
|
||||
return;
|
||||
}
|
||||
/* Display information about symbols, based on kind of symbol. */
|
||||
switch (module_info.SymType) {
|
||||
case SymNone:
|
||||
printf(("No symbols available for the module.\n"));
|
||||
break;
|
||||
case SymExport:
|
||||
printf(("Loaded symbols: Exports\n"));
|
||||
break;
|
||||
case SymCoff:
|
||||
printf(("Loaded symbols: COFF\n"));
|
||||
break;
|
||||
case SymCv:
|
||||
printf(("Loaded symbols: CodeView\n"));
|
||||
break;
|
||||
case SymSym:
|
||||
printf(("Loaded symbols: SYM\n"));
|
||||
break;
|
||||
case SymVirtual:
|
||||
printf(("Loaded symbols: Virtual\n"));
|
||||
break;
|
||||
case SymPdb:
|
||||
printf(("Loaded symbols: PDB\n"));
|
||||
break;
|
||||
case SymDia:
|
||||
printf(("Loaded symbols: DIA\n"));
|
||||
break;
|
||||
case SymDeferred:
|
||||
printf(("Loaded symbols: Deferred\n")); /* not actually loaded */
|
||||
break;
|
||||
default:
|
||||
printf(("Loaded symbols: Unknown format.\n"));
|
||||
break;
|
||||
}
|
||||
|
||||
MaybePrint("Image name", module_info.ImageName);
|
||||
MaybePrint("Loaded image name", module_info.LoadedImageName);
|
||||
#ifdef VC8_OR_ABOVE /* TODO(csilvers): figure out how to tell */
|
||||
MaybePrint("PDB file name", module_info.LoadedPdbName);
|
||||
if (module_info.PdbUnmatched || module_info.DbgUnmatched) {
|
||||
/* This can only happen if the debug information is contained in a
|
||||
* separate file (.DBG or .PDB)
|
||||
*/
|
||||
printf(("Warning: Unmatched symbols.\n"));
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Contents */
|
||||
#ifdef VC8_OR_ABOVE /* TODO(csilvers): figure out how to tell */
|
||||
PrintAvailability("Line numbers", module_info.LineNumbers);
|
||||
PrintAvailability("Global symbols", module_info.GlobalSymbols);
|
||||
PrintAvailability("Type information", module_info.TypeInfo);
|
||||
#endif
|
||||
}
|
||||
|
||||
void usage() {
|
||||
fprintf(stderr, "usage: nm-pdb [-C|--demangle] <module or filename>\n");
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
DWORD error;
|
||||
HANDLE process;
|
||||
ULONG64 module_base;
|
||||
SYM_CONTEXT ctx;
|
||||
int i;
|
||||
char* search;
|
||||
char* filename = NULL;
|
||||
int rv = 0;
|
||||
/* We may add SYMOPT_UNDNAME if --demangle is specified: */
|
||||
DWORD symopts = SYMOPT_DEFERRED_LOADS | SYMOPT_DEBUG;
|
||||
|
||||
for (i = 1; i < argc; i++) {
|
||||
if (strcmp(argv[i], "--demangle") == 0 || strcmp(argv[i], "-C") == 0) {
|
||||
symopts |= SYMOPT_UNDNAME;
|
||||
} else if (strcmp(argv[i], "--help") == 0) {
|
||||
usage();
|
||||
exit(0);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i != argc - 1) {
|
||||
usage();
|
||||
exit(1);
|
||||
}
|
||||
filename = argv[i];
|
||||
|
||||
process = GetCurrentProcess();
|
||||
|
||||
if (!SymInitialize(process, NULL, FALSE)) {
|
||||
error = GetLastError();
|
||||
fprintf(stderr, "SymInitialize returned error : %d\n", error);
|
||||
return 1;
|
||||
}
|
||||
|
||||
search = malloc(SEARCH_CAP);
|
||||
if (SymGetSearchPath(process, search, SEARCH_CAP)) {
|
||||
if (strlen(search) + sizeof(";" WEBSYM) > SEARCH_CAP) {
|
||||
fprintf(stderr, "Search path too long\n");
|
||||
SymCleanup(process);
|
||||
return 1;
|
||||
}
|
||||
strcat(search, ";" WEBSYM);
|
||||
} else {
|
||||
error = GetLastError();
|
||||
fprintf(stderr, "SymGetSearchPath returned error : %d\n", error);
|
||||
rv = 1; /* An error, but not a fatal one */
|
||||
strcpy(search, WEBSYM); /* Use a default value */
|
||||
}
|
||||
if (!SymSetSearchPath(process, search)) {
|
||||
error = GetLastError();
|
||||
fprintf(stderr, "SymSetSearchPath returned error : %d\n", error);
|
||||
rv = 1; /* An error, but not a fatal one */
|
||||
}
|
||||
|
||||
SymSetOptions(symopts);
|
||||
module_base = SymLoadModuleEx(process, NULL, filename, NULL, 0, 0, NULL, 0);
|
||||
if (!module_base) {
|
||||
/* SymLoadModuleEx failed */
|
||||
error = GetLastError();
|
||||
fprintf(stderr, "SymLoadModuleEx returned error : %d for %s\n",
|
||||
error, filename);
|
||||
SymCleanup(process);
|
||||
return 1;
|
||||
}
|
||||
|
||||
ShowSymbolInfo(process, module_base);
|
||||
|
||||
memset(&ctx, 0, sizeof(ctx));
|
||||
ctx.module_base = module_base;
|
||||
if (!SymEnumSymbols(process, module_base, NULL, EnumSymProc, &ctx)) {
|
||||
error = GetLastError();
|
||||
fprintf(stderr, "SymEnumSymbols returned error: %d\n", error);
|
||||
rv = 1;
|
||||
} else {
|
||||
DWORD j;
|
||||
qsort(ctx.syms, ctx.syms_len, sizeof(ctx.syms[0]), sym_cmp);
|
||||
for (j = 0; j < ctx.syms_len; j++) {
|
||||
printf("%016I64x X %s\n", ctx.syms[j].addr, ctx.syms[j].name);
|
||||
}
|
||||
/* In a perfect world, maybe we'd clean up ctx's memory? */
|
||||
}
|
||||
SymUnloadModule64(process, module_base);
|
||||
SymCleanup(process);
|
||||
return rv;
|
||||
}
|
173
trunk/3rdparty/gperftools-2-fit/src/windows/override_functions.cc
vendored
Normal file
173
trunk/3rdparty/gperftools-2-fit/src/windows/override_functions.cc
vendored
Normal file
|
@ -0,0 +1,173 @@
|
|||
// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
|
||||
// Copyright (c) 2007, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// ---
|
||||
// Author: Mike Belshe
|
||||
//
|
||||
// To link tcmalloc into a EXE or DLL statically without using the patching
|
||||
// facility, we can take a stock libcmt and remove all the allocator functions.
|
||||
// When we relink the EXE/DLL with the modified libcmt and tcmalloc, a few
|
||||
// functions are missing. This file contains the additional overrides which
|
||||
// are required in the VS2005 libcmt in order to link the modified libcmt.
|
||||
//
|
||||
// See also
|
||||
// http://groups.google.com/group/google-perftools/browse_thread/thread/41cd3710af85e57b
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#ifndef _WIN32
|
||||
# error You should only be including this file in a windows environment!
|
||||
#endif
|
||||
|
||||
#ifndef WIN32_OVERRIDE_ALLOCATORS
|
||||
# error This file is intended for use when overriding allocators
|
||||
#endif
|
||||
|
||||
#include "tcmalloc.cc"
|
||||
|
||||
extern "C" {
|
||||
|
||||
void* _malloc_base(size_t size) {
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
void _free_base(void* p) {
|
||||
free(p);
|
||||
}
|
||||
|
||||
void* _calloc_base(size_t n, size_t size) {
|
||||
return calloc(n, size);
|
||||
}
|
||||
|
||||
void* _recalloc(void* old_ptr, size_t n, size_t size) {
|
||||
// Ensure that (n * size) does not overflow
|
||||
if (!(n == 0 || (std::numeric_limits<size_t>::max)() / n >= size)) {
|
||||
errno = ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const size_t old_size = tc_malloc_size(old_ptr);
|
||||
const size_t new_size = n * size;
|
||||
|
||||
void* new_ptr = realloc(old_ptr, new_size);
|
||||
|
||||
// If the reallocation succeeded and the new block is larger, zero-fill the
|
||||
// new bytes:
|
||||
if (new_ptr != NULL && new_size > old_size) {
|
||||
memset(static_cast<char*>(new_ptr) + old_size, 0, tc_nallocx(new_size, 0) - old_size);
|
||||
}
|
||||
|
||||
return new_ptr;
|
||||
}
|
||||
|
||||
void* _calloc_impl(size_t n, size_t size) {
|
||||
return calloc(n, size);
|
||||
}
|
||||
|
||||
size_t _msize(void* p) {
|
||||
return MallocExtension::instance()->GetAllocatedSize(p);
|
||||
}
|
||||
|
||||
HANDLE __acrt_heap = nullptr;
|
||||
|
||||
bool __acrt_initialize_heap() {
|
||||
new TCMallocGuard();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool __acrt_uninitialize_heap(bool) {
|
||||
return true;
|
||||
}
|
||||
|
||||
intptr_t _get_heap_handle() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
HANDLE __acrt_getheap() {
|
||||
return __acrt_heap;
|
||||
}
|
||||
|
||||
// The CRT heap initialization stub.
|
||||
int _heap_init() {
|
||||
// We intentionally leak this object. It lasts for the process
|
||||
// lifetime. Trying to teardown at _heap_term() is so late that
|
||||
// you can't do anything useful anyway.
|
||||
new TCMallocGuard();
|
||||
return 1;
|
||||
}
|
||||
|
||||
// The CRT heap cleanup stub.
|
||||
void _heap_term() {
|
||||
}
|
||||
|
||||
// We set this to 1 because part of the CRT uses a check of _crtheap != 0
|
||||
// to test whether the CRT has been initialized. Once we've ripped out
|
||||
// the allocators from libcmt, we need to provide this definition so that
|
||||
// the rest of the CRT is still usable.
|
||||
void* _crtheap = reinterpret_cast<void*>(1);
|
||||
|
||||
int _set_new_mode(int flag) {
|
||||
return tc_set_new_mode(flag);
|
||||
}
|
||||
|
||||
int _query_new_mode() {
|
||||
return tc_query_new_mode();
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
|
||||
#ifndef NDEBUG
|
||||
#undef malloc
|
||||
#undef free
|
||||
#undef calloc
|
||||
int _CrtDbgReport(int, const char*, int, const char*, const char*, ...) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _CrtDbgReportW(int, const wchar_t*, int, const wchar_t*, const wchar_t*, ...) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _CrtSetReportMode(int, int) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern "C" void* _malloc_dbg(size_t size, int , const char*, int) {
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
extern "C" void _free_dbg(void* ptr, int) {
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
extern "C" void* _calloc_dbg(size_t n, size_t size, int, const char*, int) {
|
||||
return calloc(n, size);
|
||||
}
|
||||
#endif // NDEBUG
|
1098
trunk/3rdparty/gperftools-2-fit/src/windows/patch_functions.cc
vendored
Normal file
1098
trunk/3rdparty/gperftools-2-fit/src/windows/patch_functions.cc
vendored
Normal file
File diff suppressed because it is too large
Load diff
249
trunk/3rdparty/gperftools-2-fit/src/windows/port.cc
vendored
Normal file
249
trunk/3rdparty/gperftools-2-fit/src/windows/port.cc
vendored
Normal file
|
@ -0,0 +1,249 @@
|
|||
// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
|
||||
/* Copyright (c) 2007, Google Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* * Neither the name of Google Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* ---
|
||||
* Author: Craig Silverstein
|
||||
*/
|
||||
|
||||
#ifndef _WIN32
|
||||
# error You should only be including windows/port.cc in a windows environment!
|
||||
#endif
|
||||
|
||||
#define NOMINMAX // so std::max, below, compiles correctly
|
||||
#include <config.h>
|
||||
#include <string.h> // for strlen(), memset(), memcmp()
|
||||
#include <assert.h>
|
||||
#include <stdarg.h> // for va_list, va_start, va_end
|
||||
#include <algorithm> // for std:{min,max}
|
||||
#include <windows.h>
|
||||
#include "port.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/spinlock.h"
|
||||
#include "internal_logging.h"
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Basic libraries
|
||||
|
||||
PERFTOOLS_DLL_DECL
|
||||
int getpagesize() {
|
||||
static int pagesize = 0;
|
||||
if (pagesize == 0) {
|
||||
SYSTEM_INFO system_info;
|
||||
GetSystemInfo(&system_info);
|
||||
pagesize = std::max(system_info.dwPageSize,
|
||||
system_info.dwAllocationGranularity);
|
||||
}
|
||||
return pagesize;
|
||||
}
|
||||
|
||||
extern "C" PERFTOOLS_DLL_DECL void* __sbrk(ptrdiff_t increment) {
|
||||
LOG(FATAL, "Windows doesn't implement sbrk!\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// We need to write to 'stderr' without having windows allocate memory.
|
||||
// The safest way is via a low-level call like WriteConsoleA(). But
|
||||
// even then we need to be sure to print in small bursts so as to not
|
||||
// require memory allocation.
|
||||
extern "C" PERFTOOLS_DLL_DECL void WriteToStderr(const char* buf, int len) {
|
||||
// Looks like windows allocates for writes of >80 bytes
|
||||
for (int i = 0; i < len; i += 80) {
|
||||
write(STDERR_FILENO, buf + i, std::min(80, len - i));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Threads code
|
||||
|
||||
// Windows doesn't support pthread_key_create's destr_function, and in
|
||||
// fact it's a bit tricky to get code to run when a thread exits. This
|
||||
// is cargo-cult magic from https://www.codeproject.com/Articles/8113/Thread-Local-Storage-The-C-Way
|
||||
// and http://lallouslab.net/2017/05/30/using-cc-tls-callbacks-in-visual-studio-with-your-32-or-64bits-programs/.
|
||||
// This code is for VC++ 7.1 and later; VC++ 6.0 support is possible
|
||||
// but more busy-work -- see the webpage for how to do it. If all
|
||||
// this fails, we could use DllMain instead. The big problem with
|
||||
// DllMain is it doesn't run if this code is statically linked into a
|
||||
// binary (it also doesn't run if the thread is terminated via
|
||||
// TerminateThread, which if we're lucky this routine does).
|
||||
|
||||
// Force a reference to _tls_used to make the linker create the TLS directory
|
||||
// if it's not already there (that is, even if __declspec(thread) is not used).
|
||||
// Force a reference to p_thread_callback_tcmalloc and p_process_term_tcmalloc
|
||||
// to prevent whole program optimization from discarding the variables.
|
||||
#ifdef _MSC_VER
|
||||
#if defined(_M_IX86)
|
||||
#pragma comment(linker, "/INCLUDE:__tls_used")
|
||||
#pragma comment(linker, "/INCLUDE:_p_thread_callback_tcmalloc")
|
||||
#pragma comment(linker, "/INCLUDE:_p_process_term_tcmalloc")
|
||||
#elif defined(_M_X64)
|
||||
#pragma comment(linker, "/INCLUDE:_tls_used")
|
||||
#pragma comment(linker, "/INCLUDE:p_thread_callback_tcmalloc")
|
||||
#pragma comment(linker, "/INCLUDE:p_process_term_tcmalloc")
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// When destr_fn eventually runs, it's supposed to take as its
|
||||
// argument the tls-value associated with key that pthread_key_create
|
||||
// creates. (Yeah, it sounds confusing but it's really not.) We
|
||||
// store the destr_fn/key pair in this data structure. Because we
|
||||
// store this in a single var, this implies we can only have one
|
||||
// destr_fn in a program! That's enough in practice. If asserts
|
||||
// trigger because we end up needing more, we'll have to turn this
|
||||
// into an array.
|
||||
struct DestrFnClosure {
|
||||
void (*destr_fn)(void*);
|
||||
pthread_key_t key_for_destr_fn_arg;
|
||||
};
|
||||
|
||||
static DestrFnClosure destr_fn_info; // initted to all NULL/0.
|
||||
|
||||
static int on_process_term(void) {
|
||||
if (destr_fn_info.destr_fn) {
|
||||
void *ptr = TlsGetValue(destr_fn_info.key_for_destr_fn_arg);
|
||||
// This shouldn't be necessary, but in Release mode, Windows
|
||||
// sometimes trashes the pointer in the TLS slot, so we need to
|
||||
// remove the pointer from the TLS slot before the thread dies.
|
||||
TlsSetValue(destr_fn_info.key_for_destr_fn_arg, NULL);
|
||||
if (ptr) // pthread semantics say not to call if ptr is NULL
|
||||
(*destr_fn_info.destr_fn)(ptr);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void NTAPI on_tls_callback(HINSTANCE h, DWORD dwReason, PVOID pv) {
|
||||
if (dwReason == DLL_THREAD_DETACH) { // thread is being destroyed!
|
||||
on_process_term();
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
|
||||
// extern "C" suppresses C++ name mangling so we know the symbol names
|
||||
// for the linker /INCLUDE:symbol pragmas above.
|
||||
// Note that for some unknown reason, the extern "C" {} construct is ignored
|
||||
// by the MSVC VS2017 compiler (at least) when a const modifier is used
|
||||
#if defined(_M_IX86)
|
||||
extern "C" {
|
||||
// In x86, the PE loader looks for callbacks in a data segment
|
||||
#pragma data_seg(push, old_seg)
|
||||
#pragma data_seg(".CRT$XLB")
|
||||
void (NTAPI *p_thread_callback_tcmalloc)(
|
||||
HINSTANCE h, DWORD dwReason, PVOID pv) = on_tls_callback;
|
||||
#pragma data_seg(".CRT$XTU")
|
||||
int (*p_process_term_tcmalloc)(void) = on_process_term;
|
||||
#pragma data_seg(pop, old_seg)
|
||||
} // extern "C"
|
||||
#elif defined(_M_X64)
|
||||
// In x64, the PE loader looks for callbacks in a constant segment
|
||||
#pragma const_seg(push, oldseg)
|
||||
#pragma const_seg(".CRT$XLB")
|
||||
extern "C" void (NTAPI * const p_thread_callback_tcmalloc)(
|
||||
HINSTANCE h, DWORD dwReason, PVOID pv) = on_tls_callback;
|
||||
#pragma const_seg(".CRT$XTU")
|
||||
extern "C" int (NTAPI * const p_process_term_tcmalloc)(void) = on_process_term;
|
||||
#pragma const_seg(pop, oldseg)
|
||||
#endif
|
||||
|
||||
#else // #ifdef _MSC_VER [probably msys/mingw]
|
||||
|
||||
// We have to try the DllMain solution here, because we can't use the
|
||||
// msvc-specific pragmas.
|
||||
BOOL WINAPI DllMain(HINSTANCE h, DWORD dwReason, PVOID pv) {
|
||||
if (dwReason == DLL_THREAD_DETACH)
|
||||
on_tls_callback(h, dwReason, pv);
|
||||
else if (dwReason == DLL_PROCESS_DETACH)
|
||||
on_process_term();
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#endif // #ifdef _MSC_VER
|
||||
|
||||
extern "C" pthread_key_t PthreadKeyCreate(void (*destr_fn)(void*)) {
|
||||
// Semantics are: we create a new key, and then promise to call
|
||||
// destr_fn with TlsGetValue(key) when the thread is destroyed
|
||||
// (as long as TlsGetValue(key) is not NULL).
|
||||
pthread_key_t key = TlsAlloc();
|
||||
if (destr_fn) { // register it
|
||||
// If this assert fails, we'll need to support an array of destr_fn_infos
|
||||
assert(destr_fn_info.destr_fn == NULL);
|
||||
destr_fn_info.destr_fn = destr_fn;
|
||||
destr_fn_info.key_for_destr_fn_arg = key;
|
||||
}
|
||||
return key;
|
||||
}
|
||||
|
||||
// NOTE: this is Win2K and later. For Win98 we could use a CRITICAL_SECTION...
|
||||
extern "C" int perftools_pthread_once(pthread_once_t *once_control,
|
||||
void (*init_routine)(void)) {
|
||||
// Try for a fast path first. Note: this should be an acquire semantics read.
|
||||
// It is on x86 and x64, where Windows runs.
|
||||
if (*once_control != 1) {
|
||||
while (true) {
|
||||
switch (InterlockedCompareExchange(once_control, 2, 0)) {
|
||||
case 0:
|
||||
init_routine();
|
||||
InterlockedExchange(once_control, 1);
|
||||
return 0;
|
||||
case 1:
|
||||
// The initializer has already been executed
|
||||
return 0;
|
||||
default:
|
||||
// The initializer is being processed by another thread
|
||||
SwitchToThread();
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// These functions rework existing functions of the same name in the
|
||||
// Google codebase.
|
||||
|
||||
// A replacement for HeapProfiler::CleanupOldProfiles.
|
||||
void DeleteMatchingFiles(const char* prefix, const char* full_glob) {
|
||||
WIN32_FIND_DATAA found; // that final A is for Ansi (as opposed to Unicode)
|
||||
HANDLE hFind = FindFirstFileA(full_glob, &found); // A is for Ansi
|
||||
if (hFind != INVALID_HANDLE_VALUE) {
|
||||
const int prefix_length = strlen(prefix);
|
||||
do {
|
||||
const char *fname = found.cFileName;
|
||||
if ((strlen(fname) >= prefix_length) &&
|
||||
(memcmp(fname, prefix, prefix_length) == 0)) {
|
||||
RAW_VLOG(0, "Removing old heap profile %s\n", fname);
|
||||
// TODO(csilvers): we really need to unlink dirname + fname
|
||||
_unlink(fname);
|
||||
}
|
||||
} while (FindNextFileA(hFind, &found) != FALSE); // A is for Ansi
|
||||
FindClose(hFind);
|
||||
}
|
||||
}
|
477
trunk/3rdparty/gperftools-2-fit/src/windows/port.h
vendored
Normal file
477
trunk/3rdparty/gperftools-2-fit/src/windows/port.h
vendored
Normal file
|
@ -0,0 +1,477 @@
|
|||
// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
|
||||
/* Copyright (c) 2007, Google Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* * Neither the name of Google Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* ---
|
||||
* Author: Craig Silverstein
|
||||
*
|
||||
* These are some portability typedefs and defines to make it a bit
|
||||
* easier to compile this code under VC++.
|
||||
*
|
||||
* Several of these are taken from glib:
|
||||
* http://developer.gnome.org/doc/API/glib/glib-windows-compatability-functions.html
|
||||
*/
|
||||
|
||||
#ifndef GOOGLE_BASE_WINDOWS_H_
|
||||
#define GOOGLE_BASE_WINDOWS_H_
|
||||
|
||||
/* You should never include this file directly, but always include it
|
||||
from either config.h (MSVC) or mingw.h (MinGW/msys). */
|
||||
#if !defined(GOOGLE_PERFTOOLS_WINDOWS_CONFIG_H_) && \
|
||||
!defined(GOOGLE_PERFTOOLS_WINDOWS_MINGW_H_)
|
||||
# error "port.h should only be included from config.h or mingw.h"
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN /* We always want minimal includes */
|
||||
#endif
|
||||
#include <windows.h>
|
||||
#include <io.h> /* because we so often use open/close/etc */
|
||||
#include <direct.h> /* for _getcwd */
|
||||
#include <process.h> /* for _getpid */
|
||||
#include <limits.h> /* for PATH_MAX */
|
||||
#include <stdarg.h> /* for va_list */
|
||||
#include <stdio.h> /* need this to override stdio's (v)snprintf */
|
||||
#include <sys/types.h> /* for _off_t */
|
||||
#include <assert.h>
|
||||
#include <stdlib.h> /* for rand, srand, _strtoxxx */
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER >= 1900
|
||||
#define _TIMESPEC_DEFINED
|
||||
#include <time.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
* 4018: signed/unsigned mismatch is common (and ok for signed_i < unsigned_i)
|
||||
* 4244: otherwise we get problems when subtracting two size_t's to an int
|
||||
* 4288: VC++7 gets confused when a var is defined in a loop and then after it
|
||||
* 4267: too many false positives for "conversion gives possible data loss"
|
||||
* 4290: it's ok windows ignores the "throw" directive
|
||||
* 4996: Yes, we're ok using "unsafe" functions like vsnprintf and getenv()
|
||||
* 4146: internal_logging.cc intentionally negates an unsigned value
|
||||
*/
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable:4018 4244 4288 4267 4290 4996 4146)
|
||||
#endif
|
||||
|
||||
#ifndef __cplusplus
|
||||
/* MSVC does not support C99 */
|
||||
# if !defined(__STDC_VERSION__) || __STDC_VERSION__ < 199901L
|
||||
# ifdef _MSC_VER
|
||||
# define inline __inline
|
||||
# else
|
||||
# define inline static
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
# define EXTERN_C extern "C"
|
||||
#else
|
||||
# define EXTERN_C extern
|
||||
#endif
|
||||
|
||||
/* ----------------------------------- BASIC TYPES */
|
||||
|
||||
#ifndef HAVE_STDINT_H
|
||||
# error Do not know how to set up type aliases. Edit port.h for your system.
|
||||
#endif
|
||||
|
||||
/* I guess MSVC's <types.h> doesn't include ssize_t by default? */
|
||||
#ifdef _MSC_VER
|
||||
typedef intptr_t ssize_t;
|
||||
#endif
|
||||
|
||||
/* ----------------------------------- THREADS */
|
||||
|
||||
#ifndef HAVE_PTHREAD /* not true for MSVC, but may be true for MSYS */
|
||||
typedef DWORD pthread_t;
|
||||
typedef DWORD pthread_key_t;
|
||||
typedef LONG pthread_once_t;
|
||||
enum { PTHREAD_ONCE_INIT = 0 }; /* important that this be 0! for SpinLock */
|
||||
|
||||
inline pthread_t pthread_self(void) {
|
||||
return GetCurrentThreadId();
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
inline bool pthread_equal(pthread_t left, pthread_t right) {
|
||||
return left == right;
|
||||
}
|
||||
|
||||
/*
|
||||
* windows/port.h defines compatibility APIs for several .h files, which
|
||||
* we therefore shouldn't be #including directly. This hack keeps us from
|
||||
* doing so. TODO(csilvers): do something more principled.
|
||||
*/
|
||||
#define GOOGLE_MAYBE_THREADS_H_ 1
|
||||
/* This replaces maybe_threads.{h,cc} */
|
||||
|
||||
EXTERN_C pthread_key_t PthreadKeyCreate(void (*destr_fn)(void*)); /* port.cc */
|
||||
|
||||
inline int perftools_pthread_key_create(pthread_key_t *pkey,
|
||||
void (*destructor)(void*)) {
|
||||
pthread_key_t key = PthreadKeyCreate(destructor);
|
||||
if (key != TLS_OUT_OF_INDEXES) {
|
||||
*(pkey) = key;
|
||||
return 0;
|
||||
} else {
|
||||
return GetLastError();
|
||||
}
|
||||
}
|
||||
|
||||
inline void* perftools_pthread_getspecific(DWORD key) {
|
||||
DWORD err = GetLastError();
|
||||
void* rv = TlsGetValue(key);
|
||||
if (err) SetLastError(err);
|
||||
return rv;
|
||||
}
|
||||
|
||||
inline int perftools_pthread_setspecific(pthread_key_t key, const void *value) {
|
||||
if (TlsSetValue(key, (LPVOID)value))
|
||||
return 0;
|
||||
else
|
||||
return GetLastError();
|
||||
}
|
||||
|
||||
EXTERN_C int perftools_pthread_once(pthread_once_t *once_control,
|
||||
void (*init_routine)(void));
|
||||
|
||||
#endif /* __cplusplus */
|
||||
|
||||
inline void sched_yield(void) {
|
||||
Sleep(0);
|
||||
}
|
||||
|
||||
#endif /* HAVE_PTHREAD */
|
||||
|
||||
/*
|
||||
* __declspec(thread) isn't usable in a dll opened via LoadLibrary().
|
||||
* But it doesn't work to LoadLibrary() us anyway, because of all the
|
||||
* things we need to do before main()! So this kind of TLS is safe for us.
|
||||
*/
|
||||
#define __thread __declspec(thread)
|
||||
|
||||
/*
|
||||
* This code is obsolete, but I keep it around in case we are ever in
|
||||
* an environment where we can't or don't want to use google spinlocks
|
||||
* (from base/spinlock.{h,cc}). In that case, uncommenting this out,
|
||||
* and removing spinlock.cc from the build, should be enough to revert
|
||||
* back to using native spinlocks.
|
||||
*/
|
||||
#if 0
|
||||
// Windows uses a spinlock internally for its mutexes, making our life easy!
|
||||
// However, the Windows spinlock must always be initialized, making life hard,
|
||||
// since we want LINKER_INITIALIZED. We work around this by having the
|
||||
// linker initialize a bool to 0, and check that before accessing the mutex.
|
||||
// This replaces spinlock.{h,cc}, and all the stuff it depends on (atomicops)
|
||||
#ifdef __cplusplus
|
||||
class SpinLock {
|
||||
public:
|
||||
SpinLock() : initialize_token_(PTHREAD_ONCE_INIT) {}
|
||||
// Used for global SpinLock vars (see base/spinlock.h for more details).
|
||||
enum StaticInitializer { LINKER_INITIALIZED };
|
||||
explicit SpinLock(StaticInitializer) : initialize_token_(PTHREAD_ONCE_INIT) {
|
||||
perftools_pthread_once(&initialize_token_, InitializeMutex);
|
||||
}
|
||||
|
||||
// It's important SpinLock not have a destructor: otherwise we run
|
||||
// into problems when the main thread has exited, but other threads
|
||||
// are still running and try to access a main-thread spinlock. This
|
||||
// means we leak mutex_ (we should call DeleteCriticalSection()
|
||||
// here). However, I've verified that all SpinLocks used in
|
||||
// perftools have program-long scope anyway, so the leak is
|
||||
// perfectly fine. But be aware of this for the future!
|
||||
|
||||
void Lock() {
|
||||
// You'd thionk this would be unnecessary, since we call
|
||||
// InitializeMutex() in our constructor. But sometimes Lock() can
|
||||
// be called before our constructor is! This can only happen in
|
||||
// global constructors, when this is a global. If we live in
|
||||
// bar.cc, and some global constructor in foo.cc calls a routine
|
||||
// in bar.cc that calls this->Lock(), then Lock() may well run
|
||||
// before our global constructor does. To protect against that,
|
||||
// we do this check. For SpinLock objects created after main()
|
||||
// has started, this pthread_once call will always be a noop.
|
||||
perftools_pthread_once(&initialize_token_, InitializeMutex);
|
||||
EnterCriticalSection(&mutex_);
|
||||
}
|
||||
void Unlock() {
|
||||
LeaveCriticalSection(&mutex_);
|
||||
}
|
||||
|
||||
// Used in assertion checks: assert(lock.IsHeld()) (see base/spinlock.h).
|
||||
inline bool IsHeld() const {
|
||||
// This works, but probes undocumented internals, so I've commented it out.
|
||||
// c.f. http://msdn.microsoft.com/msdnmag/issues/03/12/CriticalSections/
|
||||
//return mutex_.LockCount>=0 && mutex_.OwningThread==GetCurrentThreadId();
|
||||
return true;
|
||||
}
|
||||
private:
|
||||
void InitializeMutex() { InitializeCriticalSection(&mutex_); }
|
||||
|
||||
pthread_once_t initialize_token_;
|
||||
CRITICAL_SECTION mutex_;
|
||||
};
|
||||
|
||||
class SpinLockHolder { // Acquires a spinlock for as long as the scope lasts
|
||||
private:
|
||||
SpinLock* lock_;
|
||||
public:
|
||||
inline explicit SpinLockHolder(SpinLock* l) : lock_(l) { l->Lock(); }
|
||||
inline ~SpinLockHolder() { lock_->Unlock(); }
|
||||
};
|
||||
#endif // #ifdef __cplusplus
|
||||
|
||||
// This keeps us from using base/spinlock.h's implementation of SpinLock.
|
||||
#define BASE_SPINLOCK_H_ 1
|
||||
|
||||
#endif /* #if 0 */
|
||||
|
||||
/* ----------------------------------- MMAP and other memory allocation */
|
||||
|
||||
#ifndef HAVE_MMAP /* not true for MSVC, but may be true for msys */
|
||||
#define MAP_FAILED 0
|
||||
#define MREMAP_FIXED 2 /* the value in linux, though it doesn't really matter */
|
||||
/* These, when combined with the mmap invariants below, yield the proper action */
|
||||
#define PROT_READ PAGE_READWRITE
|
||||
#define PROT_WRITE PAGE_READWRITE
|
||||
#define MAP_ANONYMOUS MEM_RESERVE
|
||||
#define MAP_PRIVATE MEM_COMMIT
|
||||
#define MAP_SHARED MEM_RESERVE /* value of this #define is 100% arbitrary */
|
||||
|
||||
#if __STDC__ && !defined(__MINGW32__)
|
||||
typedef _off_t off_t;
|
||||
#endif
|
||||
|
||||
/* VirtualAlloc only replaces for mmap when certain invariants are kept. */
|
||||
inline void *mmap(void *addr, size_t length, int prot, int flags,
|
||||
int fd, off_t offset) {
|
||||
if (addr == NULL && fd == -1 && offset == 0 &&
|
||||
prot == (PROT_READ|PROT_WRITE) && flags == (MAP_PRIVATE|MAP_ANONYMOUS)) {
|
||||
return VirtualAlloc(0, length, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
inline int munmap(void *addr, size_t length) {
|
||||
return VirtualFree(addr, 0, MEM_RELEASE) ? 0 : -1;
|
||||
}
|
||||
#endif /* HAVE_MMAP */
|
||||
|
||||
/* We could maybe use VirtualAlloc for sbrk as well, but no need */
|
||||
inline void *sbrk(intptr_t increment) {
|
||||
// sbrk returns -1 on failure
|
||||
return (void*)-1;
|
||||
}
|
||||
|
||||
|
||||
/* ----------------------------------- STRING ROUTINES */
|
||||
|
||||
/*
|
||||
* We can't just use _vsnprintf and _snprintf as drop-in-replacements,
|
||||
* because they don't always NUL-terminate. :-( We also can't use the
|
||||
* name vsnprintf, since windows defines that (but not snprintf (!)).
|
||||
*/
|
||||
#if defined(_MSC_VER) && _MSC_VER >= 1400
|
||||
/* We can use safe CRT functions, which the required functionality */
|
||||
inline int perftools_vsnprintf(char *str, size_t size, const char *format,
|
||||
va_list ap) {
|
||||
return vsnprintf_s(str, size, _TRUNCATE, format, ap);
|
||||
}
|
||||
#else
|
||||
inline int perftools_vsnprintf(char *str, size_t size, const char *format,
|
||||
va_list ap) {
|
||||
if (size == 0) /* not even room for a \0? */
|
||||
return -1; /* not what C99 says to do, but what windows does */
|
||||
str[size-1] = '\0';
|
||||
return _vsnprintf(str, size-1, format, ap);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_INTTYPES_H
|
||||
#define PRIx64 "I64x"
|
||||
#define SCNx64 "I64x"
|
||||
#define PRId64 "I64d"
|
||||
#define SCNd64 "I64d"
|
||||
#define PRIu64 "I64u"
|
||||
#ifdef _WIN64
|
||||
# define PRIuPTR "llu"
|
||||
# define PRIxPTR "llx"
|
||||
#else
|
||||
# define PRIuPTR "lu"
|
||||
# define PRIxPTR "lx"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* ----------------------------------- FILE IO */
|
||||
|
||||
#ifndef PATH_MAX
|
||||
#define PATH_MAX 1024
|
||||
#endif
|
||||
#ifndef __MINGW32__
|
||||
enum { STDIN_FILENO = 0, STDOUT_FILENO = 1, STDERR_FILENO = 2 };
|
||||
#endif
|
||||
#ifndef O_RDONLY
|
||||
#define O_RDONLY _O_RDONLY
|
||||
#endif
|
||||
|
||||
#if __STDC__ && !defined(__MINGW32__)
|
||||
/* These functions are considered non-standard */
|
||||
inline int access(const char *pathname, int mode) {
|
||||
return _access(pathname, mode);
|
||||
}
|
||||
inline int open(const char *pathname, int flags, int mode = 0) {
|
||||
return _open(pathname, flags, mode);
|
||||
}
|
||||
inline int close(int fd) {
|
||||
return _close(fd);
|
||||
}
|
||||
inline ssize_t read(int fd, void *buf, size_t count) {
|
||||
return _read(fd, buf, count);
|
||||
}
|
||||
inline ssize_t write(int fd, const void *buf, size_t count) {
|
||||
return _write(fd, buf, count);
|
||||
}
|
||||
inline off_t lseek(int fd, off_t offset, int whence) {
|
||||
return _lseek(fd, offset, whence);
|
||||
}
|
||||
inline char *getcwd(char *buf, size_t size) {
|
||||
return _getcwd(buf, size);
|
||||
}
|
||||
inline int mkdir(const char *pathname, int) {
|
||||
return _mkdir(pathname);
|
||||
}
|
||||
|
||||
inline FILE *popen(const char *command, const char *type) {
|
||||
return _popen(command, type);
|
||||
}
|
||||
inline int pclose(FILE *stream) {
|
||||
return _pclose(stream);
|
||||
}
|
||||
#endif
|
||||
|
||||
EXTERN_C PERFTOOLS_DLL_DECL void WriteToStderr(const char* buf, int len);
|
||||
|
||||
/* ----------------------------------- SYSTEM/PROCESS */
|
||||
|
||||
#ifndef HAVE_PID_T
|
||||
typedef int pid_t;
|
||||
#endif
|
||||
|
||||
#if __STDC__ && !defined(__MINGW32__)
|
||||
inline pid_t getpid(void) { return _getpid(); }
|
||||
#endif
|
||||
inline pid_t getppid(void) { return 0; }
|
||||
|
||||
/* Handle case when poll is used to simulate sleep. */
|
||||
inline int poll(struct pollfd* fds, int nfds, int timeout) {
|
||||
assert(fds == NULL);
|
||||
assert(nfds == 0);
|
||||
Sleep(timeout);
|
||||
return 0;
|
||||
}
|
||||
|
||||
EXTERN_C PERFTOOLS_DLL_DECL int getpagesize(); /* in port.cc */
|
||||
|
||||
/* ----------------------------------- OTHER */
|
||||
|
||||
inline void srandom(unsigned int seed) { srand(seed); }
|
||||
inline long random(void) { return rand(); }
|
||||
|
||||
#ifndef HAVE_DECL_SLEEP
|
||||
#define HAVE_DECL_SLEEP 0
|
||||
#endif
|
||||
|
||||
#if !HAVE_DECL_SLEEP
|
||||
inline unsigned int sleep(unsigned int seconds) {
|
||||
Sleep(seconds * 1000);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
// mingw64 seems to define timespec (though mingw.org mingw doesn't),
|
||||
// protected by the _TIMESPEC_DEFINED macro.
|
||||
#ifndef _TIMESPEC_DEFINED
|
||||
struct timespec {
|
||||
int tv_sec;
|
||||
int tv_nsec;
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_DECL_NANOSLEEP
|
||||
#define HAVE_DECL_NANOSLEEP 0
|
||||
#endif
|
||||
|
||||
// latest mingw64 has nanosleep. Earlier mingw and MSVC do not
|
||||
#if !HAVE_DECL_NANOSLEEP
|
||||
inline int nanosleep(const struct timespec *req, struct timespec *rem) {
|
||||
Sleep(req->tv_sec * 1000 + req->tv_nsec / 1000000);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef __MINGW32__
|
||||
#if defined(_MSC_VER) && _MSC_VER < 1800
|
||||
inline long long int strtoll(const char *nptr, char **endptr, int base) {
|
||||
return _strtoi64(nptr, endptr, base);
|
||||
}
|
||||
inline unsigned long long int strtoull(const char *nptr, char **endptr,
|
||||
int base) {
|
||||
return _strtoui64(nptr, endptr, base);
|
||||
}
|
||||
inline long long int strtoq(const char *nptr, char **endptr, int base) {
|
||||
return _strtoi64(nptr, endptr, base);
|
||||
}
|
||||
#endif
|
||||
inline unsigned long long int strtouq(const char *nptr, char **endptr,
|
||||
int base) {
|
||||
return _strtoui64(nptr, endptr, base);
|
||||
}
|
||||
inline long long atoll(const char *nptr) {
|
||||
return _atoi64(nptr);
|
||||
}
|
||||
#endif
|
||||
|
||||
#define __THROW throw()
|
||||
|
||||
/* ----------------------------------- TCMALLOC-SPECIFIC */
|
||||
|
||||
/* tcmalloc.cc calls this so we can patch VirtualAlloc() et al. */
|
||||
extern void PatchWindowsFunctions();
|
||||
|
||||
#endif /* _WIN32 */
|
||||
|
||||
#undef inline
|
||||
#undef EXTERN_C
|
||||
|
||||
#endif /* GOOGLE_BASE_WINDOWS_H_ */
|
736
trunk/3rdparty/gperftools-2-fit/src/windows/preamble_patcher.cc
vendored
Normal file
736
trunk/3rdparty/gperftools-2-fit/src/windows/preamble_patcher.cc
vendored
Normal file
|
@ -0,0 +1,736 @@
|
|||
// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
|
||||
/* Copyright (c) 2007, Google Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* * Neither the name of Google Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* ---
|
||||
* Author: Joi Sigurdsson
|
||||
* Author: Scott Francis
|
||||
*
|
||||
* Implementation of PreamblePatcher
|
||||
*/
|
||||
|
||||
#include "preamble_patcher.h"
|
||||
|
||||
#include "mini_disassembler.h"
|
||||
|
||||
// compatibility shims
|
||||
#include "base/logging.h"
|
||||
|
||||
// Definitions of assembly statements we need
|
||||
#define ASM_JMP32REL 0xE9
|
||||
#define ASM_INT3 0xCC
|
||||
#define ASM_JMP32ABS_0 0xFF
|
||||
#define ASM_JMP32ABS_1 0x25
|
||||
#define ASM_JMP8REL 0xEB
|
||||
#define ASM_JCC32REL_0 0x0F
|
||||
#define ASM_JCC32REL_1_MASK 0x80
|
||||
#define ASM_NOP 0x90
|
||||
// X64 opcodes
|
||||
#define ASM_REXW 0x48
|
||||
#define ASM_MOVRAX_IMM 0xB8
|
||||
#define ASM_JMP 0xFF
|
||||
#define ASM_JMP_RAX 0xE0
|
||||
|
||||
namespace sidestep {
|
||||
|
||||
PreamblePatcher::PreamblePage* PreamblePatcher::preamble_pages_ = NULL;
|
||||
long PreamblePatcher::granularity_ = 0;
|
||||
long PreamblePatcher::pagesize_ = 0;
|
||||
bool PreamblePatcher::initialized_ = false;
|
||||
|
||||
static const unsigned int kPreamblePageMagic = 0x4347414D; // "MAGC"
|
||||
|
||||
// Handle a special case that we see with functions that point into an
|
||||
// IAT table (including functions linked statically into the
|
||||
// application): these function already starts with ASM_JMP32*. For
|
||||
// instance, malloc() might be implemented as a JMP to __malloc().
|
||||
// This function follows the initial JMPs for us, until we get to the
|
||||
// place where the actual code is defined. If we get to STOP_BEFORE,
|
||||
// we return the address before stop_before. The stop_before_trampoline
|
||||
// flag is used in 64-bit mode. If true, we will return the address
|
||||
// before a trampoline is detected. Trampolines are defined as:
|
||||
//
|
||||
// nop
|
||||
// mov rax, <replacement_function>
|
||||
// jmp rax
|
||||
//
|
||||
// See PreamblePatcher::RawPatchWithStub for more information.
|
||||
void* PreamblePatcher::ResolveTargetImpl(unsigned char* target,
|
||||
unsigned char* stop_before,
|
||||
bool stop_before_trampoline) {
|
||||
if (target == NULL)
|
||||
return NULL;
|
||||
while (1) {
|
||||
unsigned char* new_target;
|
||||
if (target[0] == ASM_JMP32REL) {
|
||||
// target[1-4] holds the place the jmp goes to, but it's
|
||||
// relative to the next instruction.
|
||||
int relative_offset; // Windows guarantees int is 4 bytes
|
||||
SIDESTEP_ASSERT(sizeof(relative_offset) == 4);
|
||||
memcpy(reinterpret_cast<void*>(&relative_offset),
|
||||
reinterpret_cast<void*>(target + 1), 4);
|
||||
new_target = target + 5 + relative_offset;
|
||||
} else if (target[0] == ASM_JMP8REL) {
|
||||
// Visual Studio 7.1 implements new[] as an 8 bit jump to new
|
||||
signed char relative_offset;
|
||||
memcpy(reinterpret_cast<void*>(&relative_offset),
|
||||
reinterpret_cast<void*>(target + 1), 1);
|
||||
new_target = target + 2 + relative_offset;
|
||||
} else if (target[0] == ASM_JMP32ABS_0 &&
|
||||
target[1] == ASM_JMP32ABS_1) {
|
||||
jmp32rel:
|
||||
// Visual studio seems to sometimes do it this way instead of the
|
||||
// previous way. Not sure what the rules are, but it was happening
|
||||
// with operator new in some binaries.
|
||||
void** new_target_v;
|
||||
if (kIs64BitBinary) {
|
||||
// In 64-bit mode JMPs are RIP-relative, not absolute
|
||||
int target_offset;
|
||||
memcpy(reinterpret_cast<void*>(&target_offset),
|
||||
reinterpret_cast<void*>(target + 2), 4);
|
||||
new_target_v = reinterpret_cast<void**>(target + target_offset + 6);
|
||||
} else {
|
||||
SIDESTEP_ASSERT(sizeof(new_target) == 4);
|
||||
memcpy(&new_target_v, reinterpret_cast<void*>(target + 2), 4);
|
||||
}
|
||||
new_target = reinterpret_cast<unsigned char*>(*new_target_v);
|
||||
} else if (kIs64BitBinary && target[0] == ASM_REXW
|
||||
&& target[1] == ASM_JMP32ABS_0
|
||||
&& target[2] == ASM_JMP32ABS_1) {
|
||||
// in Visual Studio 2012 we're seeing jump like that:
|
||||
// rex.W jmpq *0x11d019(%rip)
|
||||
//
|
||||
// according to docs I have, rex prefix is actually unneeded and
|
||||
// can be ignored. I.e. docs say for jumps like that operand
|
||||
// already defaults to 64-bit. But clearly it breaks abs. jump
|
||||
// detection above and we just skip rex
|
||||
target++;
|
||||
goto jmp32rel;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
if (new_target == stop_before)
|
||||
break;
|
||||
if (stop_before_trampoline && *new_target == ASM_NOP
|
||||
&& new_target[1] == ASM_REXW && new_target[2] == ASM_MOVRAX_IMM)
|
||||
break;
|
||||
target = new_target;
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
||||
// Special case scoped_ptr to avoid dependency on scoped_ptr below.
|
||||
class DeleteUnsignedCharArray {
|
||||
public:
|
||||
DeleteUnsignedCharArray(unsigned char* array) : array_(array) {
|
||||
}
|
||||
|
||||
~DeleteUnsignedCharArray() {
|
||||
if (array_) {
|
||||
PreamblePatcher::FreePreambleBlock(array_);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned char* Release() {
|
||||
unsigned char* temp = array_;
|
||||
array_ = NULL;
|
||||
return temp;
|
||||
}
|
||||
|
||||
private:
|
||||
unsigned char* array_;
|
||||
};
|
||||
|
||||
SideStepError PreamblePatcher::RawPatchWithStubAndProtections(
|
||||
void* target_function, void *replacement_function,
|
||||
unsigned char* preamble_stub, unsigned long stub_size,
|
||||
unsigned long* bytes_needed) {
|
||||
// We need to be able to write to a process-local copy of the first
|
||||
// MAX_PREAMBLE_STUB_SIZE bytes of target_function
|
||||
DWORD old_target_function_protect = 0;
|
||||
BOOL succeeded = ::VirtualProtect(reinterpret_cast<void*>(target_function),
|
||||
MAX_PREAMBLE_STUB_SIZE,
|
||||
PAGE_EXECUTE_READWRITE,
|
||||
&old_target_function_protect);
|
||||
if (!succeeded) {
|
||||
SIDESTEP_ASSERT(false && "Failed to make page containing target function "
|
||||
"copy-on-write.");
|
||||
return SIDESTEP_ACCESS_DENIED;
|
||||
}
|
||||
|
||||
SideStepError error_code = RawPatchWithStub(target_function,
|
||||
replacement_function,
|
||||
preamble_stub,
|
||||
stub_size,
|
||||
bytes_needed);
|
||||
|
||||
// Restore the protection of the first MAX_PREAMBLE_STUB_SIZE bytes of
|
||||
// pTargetFunction to what they were before we started goofing around.
|
||||
// We do this regardless of whether the patch succeeded or not.
|
||||
succeeded = ::VirtualProtect(reinterpret_cast<void*>(target_function),
|
||||
MAX_PREAMBLE_STUB_SIZE,
|
||||
old_target_function_protect,
|
||||
&old_target_function_protect);
|
||||
if (!succeeded) {
|
||||
SIDESTEP_ASSERT(false &&
|
||||
"Failed to restore protection to target function.");
|
||||
// We must not return an error here because the function has
|
||||
// likely actually been patched, and returning an error might
|
||||
// cause our client code not to unpatch it. So we just keep
|
||||
// going.
|
||||
}
|
||||
|
||||
if (SIDESTEP_SUCCESS != error_code) { // Testing RawPatchWithStub, above
|
||||
SIDESTEP_ASSERT(false);
|
||||
return error_code;
|
||||
}
|
||||
|
||||
// Flush the instruction cache to make sure the processor doesn't execute the
|
||||
// old version of the instructions (before our patch).
|
||||
//
|
||||
// FlushInstructionCache is actually a no-op at least on
|
||||
// single-processor XP machines. I'm not sure why this is so, but
|
||||
// it is, yet I want to keep the call to the API here for
|
||||
// correctness in case there is a difference in some variants of
|
||||
// Windows/hardware.
|
||||
succeeded = ::FlushInstructionCache(::GetCurrentProcess(),
|
||||
target_function,
|
||||
MAX_PREAMBLE_STUB_SIZE);
|
||||
if (!succeeded) {
|
||||
SIDESTEP_ASSERT(false && "Failed to flush instruction cache.");
|
||||
// We must not return an error here because the function has actually
|
||||
// been patched, and returning an error would likely cause our client
|
||||
// code not to unpatch it. So we just keep going.
|
||||
}
|
||||
|
||||
return SIDESTEP_SUCCESS;
|
||||
}
|
||||
|
||||
SideStepError PreamblePatcher::RawPatch(void* target_function,
|
||||
void* replacement_function,
|
||||
void** original_function_stub) {
|
||||
if (!target_function || !replacement_function || !original_function_stub ||
|
||||
(*original_function_stub) || target_function == replacement_function) {
|
||||
SIDESTEP_ASSERT(false && "Preconditions not met");
|
||||
return SIDESTEP_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
BOOL succeeded = FALSE;
|
||||
|
||||
// First, deal with a special case that we see with functions that
|
||||
// point into an IAT table (including functions linked statically
|
||||
// into the application): these function already starts with
|
||||
// ASM_JMP32REL. For instance, malloc() might be implemented as a
|
||||
// JMP to __malloc(). In that case, we replace the destination of
|
||||
// the JMP (__malloc), rather than the JMP itself (malloc). This
|
||||
// way we get the correct behavior no matter how malloc gets called.
|
||||
void* new_target = ResolveTarget(target_function);
|
||||
if (new_target != target_function) {
|
||||
target_function = new_target;
|
||||
}
|
||||
|
||||
// In 64-bit mode, preamble_stub must be within 2GB of target function
|
||||
// so that if target contains a jump, we can translate it.
|
||||
unsigned char* preamble_stub = AllocPreambleBlockNear(target_function);
|
||||
if (!preamble_stub) {
|
||||
SIDESTEP_ASSERT(false && "Unable to allocate preamble-stub.");
|
||||
return SIDESTEP_INSUFFICIENT_BUFFER;
|
||||
}
|
||||
|
||||
// Frees the array at end of scope.
|
||||
DeleteUnsignedCharArray guard_preamble_stub(preamble_stub);
|
||||
|
||||
SideStepError error_code = RawPatchWithStubAndProtections(
|
||||
target_function, replacement_function, preamble_stub,
|
||||
MAX_PREAMBLE_STUB_SIZE, NULL);
|
||||
|
||||
if (SIDESTEP_SUCCESS != error_code) {
|
||||
SIDESTEP_ASSERT(false);
|
||||
return error_code;
|
||||
}
|
||||
|
||||
// Flush the instruction cache to make sure the processor doesn't execute the
|
||||
// old version of the instructions (before our patch).
|
||||
//
|
||||
// FlushInstructionCache is actually a no-op at least on
|
||||
// single-processor XP machines. I'm not sure why this is so, but
|
||||
// it is, yet I want to keep the call to the API here for
|
||||
// correctness in case there is a difference in some variants of
|
||||
// Windows/hardware.
|
||||
succeeded = ::FlushInstructionCache(::GetCurrentProcess(),
|
||||
target_function,
|
||||
MAX_PREAMBLE_STUB_SIZE);
|
||||
if (!succeeded) {
|
||||
SIDESTEP_ASSERT(false && "Failed to flush instruction cache.");
|
||||
// We must not return an error here because the function has actually
|
||||
// been patched, and returning an error would likely cause our client
|
||||
// code not to unpatch it. So we just keep going.
|
||||
}
|
||||
|
||||
SIDESTEP_LOG("PreamblePatcher::RawPatch successfully patched.");
|
||||
|
||||
// detach the scoped pointer so the memory is not freed
|
||||
*original_function_stub =
|
||||
reinterpret_cast<void*>(guard_preamble_stub.Release());
|
||||
return SIDESTEP_SUCCESS;
|
||||
}
|
||||
|
||||
SideStepError PreamblePatcher::Unpatch(void* target_function,
|
||||
void* replacement_function,
|
||||
void* original_function_stub) {
|
||||
SIDESTEP_ASSERT(target_function && replacement_function &&
|
||||
original_function_stub);
|
||||
if (!target_function || !replacement_function ||
|
||||
!original_function_stub) {
|
||||
return SIDESTEP_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
// Before unpatching, target_function should be a JMP to
|
||||
// replacement_function. If it's not, then either it's an error, or
|
||||
// we're falling into the case where the original instruction was a
|
||||
// JMP, and we patched the jumped_to address rather than the JMP
|
||||
// itself. (For instance, if malloc() is just a JMP to __malloc(),
|
||||
// we patched __malloc() and not malloc().)
|
||||
unsigned char* target = reinterpret_cast<unsigned char*>(target_function);
|
||||
target = reinterpret_cast<unsigned char*>(
|
||||
ResolveTargetImpl(
|
||||
target, reinterpret_cast<unsigned char*>(replacement_function),
|
||||
true));
|
||||
// We should end at the function we patched. When we patch, we insert
|
||||
// a ASM_JMP32REL instruction, so look for that as a sanity check.
|
||||
if (target[0] != ASM_JMP32REL) {
|
||||
SIDESTEP_ASSERT(false &&
|
||||
"target_function does not look like it was patched.");
|
||||
return SIDESTEP_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
const unsigned int kRequiredTargetPatchBytes = 5;
|
||||
|
||||
// We need to be able to write to a process-local copy of the first
|
||||
// kRequiredTargetPatchBytes bytes of target_function
|
||||
DWORD old_target_function_protect = 0;
|
||||
BOOL succeeded = ::VirtualProtect(reinterpret_cast<void*>(target),
|
||||
kRequiredTargetPatchBytes,
|
||||
PAGE_EXECUTE_READWRITE,
|
||||
&old_target_function_protect);
|
||||
if (!succeeded) {
|
||||
SIDESTEP_ASSERT(false && "Failed to make page containing target function "
|
||||
"copy-on-write.");
|
||||
return SIDESTEP_ACCESS_DENIED;
|
||||
}
|
||||
|
||||
unsigned char* preamble_stub = reinterpret_cast<unsigned char*>(
|
||||
original_function_stub);
|
||||
|
||||
// Disassemble the preamble of stub and copy the bytes back to target.
|
||||
// If we've done any conditional jumps in the preamble we need to convert
|
||||
// them back to the original REL8 jumps in the target.
|
||||
MiniDisassembler disassembler;
|
||||
unsigned int preamble_bytes = 0;
|
||||
unsigned int target_bytes = 0;
|
||||
while (target_bytes < kRequiredTargetPatchBytes) {
|
||||
unsigned int cur_bytes = 0;
|
||||
InstructionType instruction_type =
|
||||
disassembler.Disassemble(preamble_stub + preamble_bytes, cur_bytes);
|
||||
if (IT_JUMP == instruction_type) {
|
||||
unsigned int jump_bytes = 0;
|
||||
SideStepError jump_ret = SIDESTEP_JUMP_INSTRUCTION;
|
||||
if (IsNearConditionalJump(preamble_stub + preamble_bytes, cur_bytes) ||
|
||||
IsNearRelativeJump(preamble_stub + preamble_bytes, cur_bytes) ||
|
||||
IsNearAbsoluteCall(preamble_stub + preamble_bytes, cur_bytes) ||
|
||||
IsNearRelativeCall(preamble_stub + preamble_bytes, cur_bytes)) {
|
||||
jump_ret = PatchNearJumpOrCall(preamble_stub + preamble_bytes,
|
||||
cur_bytes, target + target_bytes,
|
||||
&jump_bytes, MAX_PREAMBLE_STUB_SIZE);
|
||||
}
|
||||
if (jump_ret == SIDESTEP_JUMP_INSTRUCTION) {
|
||||
SIDESTEP_ASSERT(false &&
|
||||
"Found unsupported jump instruction in stub!!");
|
||||
return SIDESTEP_UNSUPPORTED_INSTRUCTION;
|
||||
}
|
||||
target_bytes += jump_bytes;
|
||||
} else if (IT_GENERIC == instruction_type) {
|
||||
if (IsMovWithDisplacement(preamble_stub + preamble_bytes, cur_bytes)) {
|
||||
unsigned int mov_bytes = 0;
|
||||
if (PatchMovWithDisplacement(preamble_stub + preamble_bytes, cur_bytes,
|
||||
target + target_bytes, &mov_bytes,
|
||||
MAX_PREAMBLE_STUB_SIZE)
|
||||
!= SIDESTEP_SUCCESS) {
|
||||
SIDESTEP_ASSERT(false &&
|
||||
"Found unsupported generic instruction in stub!!");
|
||||
return SIDESTEP_UNSUPPORTED_INSTRUCTION;
|
||||
}
|
||||
} else {
|
||||
memcpy(reinterpret_cast<void*>(target + target_bytes),
|
||||
reinterpret_cast<void*>(reinterpret_cast<unsigned char*>(
|
||||
original_function_stub) + preamble_bytes), cur_bytes);
|
||||
target_bytes += cur_bytes;
|
||||
}
|
||||
} else {
|
||||
SIDESTEP_ASSERT(false &&
|
||||
"Found unsupported instruction in stub!!");
|
||||
return SIDESTEP_UNSUPPORTED_INSTRUCTION;
|
||||
}
|
||||
preamble_bytes += cur_bytes;
|
||||
}
|
||||
|
||||
FreePreambleBlock(reinterpret_cast<unsigned char*>(original_function_stub));
|
||||
|
||||
// Restore the protection of the first kRequiredTargetPatchBytes bytes of
|
||||
// target to what they were before we started goofing around.
|
||||
succeeded = ::VirtualProtect(reinterpret_cast<void*>(target),
|
||||
kRequiredTargetPatchBytes,
|
||||
old_target_function_protect,
|
||||
&old_target_function_protect);
|
||||
|
||||
// Flush the instruction cache to make sure the processor doesn't execute the
|
||||
// old version of the instructions (before our patch).
|
||||
//
|
||||
// See comment on FlushInstructionCache elsewhere in this file.
|
||||
succeeded = ::FlushInstructionCache(::GetCurrentProcess(),
|
||||
target,
|
||||
MAX_PREAMBLE_STUB_SIZE);
|
||||
if (!succeeded) {
|
||||
SIDESTEP_ASSERT(false && "Failed to flush instruction cache.");
|
||||
return SIDESTEP_UNEXPECTED;
|
||||
}
|
||||
|
||||
SIDESTEP_LOG("PreamblePatcher::Unpatch successfully unpatched.");
|
||||
return SIDESTEP_SUCCESS;
|
||||
}
|
||||
|
||||
void PreamblePatcher::Initialize() {
|
||||
if (!initialized_) {
|
||||
SYSTEM_INFO si = { 0 };
|
||||
::GetSystemInfo(&si);
|
||||
granularity_ = si.dwAllocationGranularity;
|
||||
pagesize_ = si.dwPageSize;
|
||||
initialized_ = true;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned char* PreamblePatcher::AllocPreambleBlockNear(void* target) {
|
||||
PreamblePage* preamble_page = preamble_pages_;
|
||||
while (preamble_page != NULL) {
|
||||
if (preamble_page->free_ != NULL) {
|
||||
__int64 val = reinterpret_cast<__int64>(preamble_page) -
|
||||
reinterpret_cast<__int64>(target);
|
||||
if ((val > 0 && val + pagesize_ <= INT_MAX) ||
|
||||
(val < 0 && val >= INT_MIN)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
preamble_page = preamble_page->next_;
|
||||
}
|
||||
|
||||
// The free_ member of the page is used to store the next available block
|
||||
// of memory to use or NULL if there are no chunks available, in which case
|
||||
// we'll allocate a new page.
|
||||
if (preamble_page == NULL || preamble_page->free_ == NULL) {
|
||||
// Create a new preamble page and initialize the free list
|
||||
preamble_page = reinterpret_cast<PreamblePage*>(AllocPageNear(target));
|
||||
SIDESTEP_ASSERT(preamble_page != NULL && "Could not allocate page!");
|
||||
void** pp = &preamble_page->free_;
|
||||
unsigned char* ptr = reinterpret_cast<unsigned char*>(preamble_page) +
|
||||
MAX_PREAMBLE_STUB_SIZE;
|
||||
unsigned char* limit = reinterpret_cast<unsigned char*>(preamble_page) +
|
||||
pagesize_;
|
||||
while (ptr < limit) {
|
||||
*pp = ptr;
|
||||
pp = reinterpret_cast<void**>(ptr);
|
||||
ptr += MAX_PREAMBLE_STUB_SIZE;
|
||||
}
|
||||
*pp = NULL;
|
||||
// Insert the new page into the list
|
||||
preamble_page->magic_ = kPreamblePageMagic;
|
||||
preamble_page->next_ = preamble_pages_;
|
||||
preamble_pages_ = preamble_page;
|
||||
}
|
||||
unsigned char* ret = reinterpret_cast<unsigned char*>(preamble_page->free_);
|
||||
preamble_page->free_ = *(reinterpret_cast<void**>(preamble_page->free_));
|
||||
return ret;
|
||||
}
|
||||
|
||||
void PreamblePatcher::FreePreambleBlock(unsigned char* block) {
|
||||
SIDESTEP_ASSERT(block != NULL);
|
||||
SIDESTEP_ASSERT(granularity_ != 0);
|
||||
uintptr_t ptr = reinterpret_cast<uintptr_t>(block);
|
||||
ptr -= ptr & (granularity_ - 1);
|
||||
PreamblePage* preamble_page = reinterpret_cast<PreamblePage*>(ptr);
|
||||
SIDESTEP_ASSERT(preamble_page->magic_ == kPreamblePageMagic);
|
||||
*(reinterpret_cast<void**>(block)) = preamble_page->free_;
|
||||
preamble_page->free_ = block;
|
||||
}
|
||||
|
||||
void* PreamblePatcher::AllocPageNear(void* target) {
|
||||
MEMORY_BASIC_INFORMATION mbi = { 0 };
|
||||
if (!::VirtualQuery(target, &mbi, sizeof(mbi))) {
|
||||
SIDESTEP_ASSERT(false && "VirtualQuery failed on target address");
|
||||
return 0;
|
||||
}
|
||||
if (initialized_ == false) {
|
||||
PreamblePatcher::Initialize();
|
||||
SIDESTEP_ASSERT(initialized_);
|
||||
}
|
||||
void* pv = NULL;
|
||||
unsigned char* allocation_base = reinterpret_cast<unsigned char*>(
|
||||
mbi.AllocationBase);
|
||||
__int64 i = 1;
|
||||
bool high_target = reinterpret_cast<__int64>(target) > UINT_MAX;
|
||||
while (pv == NULL) {
|
||||
__int64 val = reinterpret_cast<__int64>(allocation_base) -
|
||||
(i * granularity_);
|
||||
if (high_target &&
|
||||
reinterpret_cast<__int64>(target) - val > INT_MAX) {
|
||||
// We're further than 2GB from the target
|
||||
break;
|
||||
} else if (val <= 0) {
|
||||
// Less than 0
|
||||
break;
|
||||
}
|
||||
pv = ::VirtualAlloc(reinterpret_cast<void*>(allocation_base -
|
||||
(i++ * granularity_)),
|
||||
pagesize_, MEM_COMMIT | MEM_RESERVE,
|
||||
PAGE_EXECUTE_READWRITE);
|
||||
}
|
||||
|
||||
// We couldn't allocate low, try to allocate high
|
||||
if (pv == NULL) {
|
||||
i = 1;
|
||||
// Round up to the next multiple of page granularity
|
||||
allocation_base = reinterpret_cast<unsigned char*>(
|
||||
(reinterpret_cast<__int64>(target) &
|
||||
(~(granularity_ - 1))) + granularity_);
|
||||
while (pv == NULL) {
|
||||
__int64 val = reinterpret_cast<__int64>(allocation_base) +
|
||||
(i * granularity_) - reinterpret_cast<__int64>(target);
|
||||
if (val > INT_MAX || val < 0) {
|
||||
// We're too far or we overflowed
|
||||
break;
|
||||
}
|
||||
pv = ::VirtualAlloc(reinterpret_cast<void*>(allocation_base +
|
||||
(i++ * granularity_)),
|
||||
pagesize_, MEM_COMMIT | MEM_RESERVE,
|
||||
PAGE_EXECUTE_READWRITE);
|
||||
}
|
||||
}
|
||||
return pv;
|
||||
}
|
||||
|
||||
bool PreamblePatcher::IsShortConditionalJump(
|
||||
unsigned char* target,
|
||||
unsigned int instruction_size) {
|
||||
return (*(target) & 0x70) == 0x70 && instruction_size == 2;
|
||||
}
|
||||
|
||||
bool PreamblePatcher::IsShortJump(
|
||||
unsigned char* target,
|
||||
unsigned int instruction_size) {
|
||||
return target[0] == 0xeb && instruction_size == 2;
|
||||
}
|
||||
|
||||
bool PreamblePatcher::IsNearConditionalJump(
|
||||
unsigned char* target,
|
||||
unsigned int instruction_size) {
|
||||
return *(target) == 0xf && (*(target + 1) & 0x80) == 0x80 &&
|
||||
instruction_size == 6;
|
||||
}
|
||||
|
||||
bool PreamblePatcher::IsNearRelativeJump(
|
||||
unsigned char* target,
|
||||
unsigned int instruction_size) {
|
||||
return *(target) == 0xe9 && instruction_size == 5;
|
||||
}
|
||||
|
||||
bool PreamblePatcher::IsNearAbsoluteCall(
|
||||
unsigned char* target,
|
||||
unsigned int instruction_size) {
|
||||
return *(target) == 0xff && (*(target + 1) & 0x10) == 0x10 &&
|
||||
instruction_size == 6;
|
||||
}
|
||||
|
||||
bool PreamblePatcher::IsNearRelativeCall(
|
||||
unsigned char* target,
|
||||
unsigned int instruction_size) {
|
||||
return *(target) == 0xe8 && instruction_size == 5;
|
||||
}
|
||||
|
||||
bool PreamblePatcher::IsMovWithDisplacement(
|
||||
unsigned char* target,
|
||||
unsigned int instruction_size) {
|
||||
// In this case, the ModRM byte's mod field will be 0 and r/m will be 101b (5)
|
||||
return instruction_size == 7 && *target == 0x48 && *(target + 1) == 0x8b &&
|
||||
(*(target + 2) >> 6) == 0 && (*(target + 2) & 0x7) == 5;
|
||||
}
|
||||
|
||||
SideStepError PreamblePatcher::PatchShortConditionalJump(
|
||||
unsigned char* source,
|
||||
unsigned int instruction_size,
|
||||
unsigned char* target,
|
||||
unsigned int* target_bytes,
|
||||
unsigned int target_size) {
|
||||
// note: rel8 offset is signed. Thus we need to ask for signed char
|
||||
// to negative offsets right
|
||||
unsigned char* original_jump_dest = (source + 2) + static_cast<signed char>(source[1]);
|
||||
unsigned char* stub_jump_from = target + 6;
|
||||
__int64 fixup_jump_offset = original_jump_dest - stub_jump_from;
|
||||
if (fixup_jump_offset > INT_MAX || fixup_jump_offset < INT_MIN) {
|
||||
SIDESTEP_ASSERT(false &&
|
||||
"Unable to fix up short jump because target"
|
||||
" is too far away.");
|
||||
return SIDESTEP_JUMP_INSTRUCTION;
|
||||
}
|
||||
|
||||
*target_bytes = 6;
|
||||
if (target_size > *target_bytes) {
|
||||
// Convert the short jump to a near jump.
|
||||
//
|
||||
// 0f 8x xx xx xx xx = Jcc rel32off
|
||||
unsigned short jmpcode = ((0x80 | (source[0] & 0xf)) << 8) | 0x0f;
|
||||
memcpy(reinterpret_cast<void*>(target),
|
||||
reinterpret_cast<void*>(&jmpcode), 2);
|
||||
memcpy(reinterpret_cast<void*>(target + 2),
|
||||
reinterpret_cast<void*>(&fixup_jump_offset), 4);
|
||||
}
|
||||
|
||||
return SIDESTEP_SUCCESS;
|
||||
}
|
||||
|
||||
SideStepError PreamblePatcher::PatchShortJump(
|
||||
unsigned char* source,
|
||||
unsigned int instruction_size,
|
||||
unsigned char* target,
|
||||
unsigned int* target_bytes,
|
||||
unsigned int target_size) {
|
||||
// note: rel8 offset is _signed_. Thus we need signed char here.
|
||||
unsigned char* original_jump_dest = (source + 2) + static_cast<signed char>(source[1]);
|
||||
unsigned char* stub_jump_from = target + 5;
|
||||
__int64 fixup_jump_offset = original_jump_dest - stub_jump_from;
|
||||
if (fixup_jump_offset > INT_MAX || fixup_jump_offset < INT_MIN) {
|
||||
SIDESTEP_ASSERT(false &&
|
||||
"Unable to fix up short jump because target"
|
||||
" is too far away.");
|
||||
return SIDESTEP_JUMP_INSTRUCTION;
|
||||
}
|
||||
|
||||
*target_bytes = 5;
|
||||
if (target_size > *target_bytes) {
|
||||
// Convert the short jump to a near jump.
|
||||
//
|
||||
// e9 xx xx xx xx = jmp rel32off
|
||||
target[0] = 0xe9;
|
||||
memcpy(reinterpret_cast<void*>(target + 1),
|
||||
reinterpret_cast<void*>(&fixup_jump_offset), 4);
|
||||
}
|
||||
|
||||
return SIDESTEP_SUCCESS;
|
||||
}
|
||||
|
||||
SideStepError PreamblePatcher::PatchNearJumpOrCall(
|
||||
unsigned char* source,
|
||||
unsigned int instruction_size,
|
||||
unsigned char* target,
|
||||
unsigned int* target_bytes,
|
||||
unsigned int target_size) {
|
||||
SIDESTEP_ASSERT(instruction_size == 5 || instruction_size == 6);
|
||||
unsigned int jmp_offset_in_instruction = instruction_size == 5 ? 1 : 2;
|
||||
unsigned char* original_jump_dest = reinterpret_cast<unsigned char *>(
|
||||
reinterpret_cast<__int64>(source + instruction_size) +
|
||||
*(reinterpret_cast<int*>(source + jmp_offset_in_instruction)));
|
||||
unsigned char* stub_jump_from = target + instruction_size;
|
||||
__int64 fixup_jump_offset = original_jump_dest - stub_jump_from;
|
||||
if (fixup_jump_offset > INT_MAX || fixup_jump_offset < INT_MIN) {
|
||||
SIDESTEP_ASSERT(false &&
|
||||
"Unable to fix up near jump because target"
|
||||
" is too far away.");
|
||||
return SIDESTEP_JUMP_INSTRUCTION;
|
||||
}
|
||||
|
||||
if ((fixup_jump_offset < SCHAR_MAX && fixup_jump_offset > SCHAR_MIN)) {
|
||||
*target_bytes = 2;
|
||||
if (target_size > *target_bytes) {
|
||||
// If the new offset is in range, use a short jump instead of a near jump.
|
||||
if (source[0] == ASM_JCC32REL_0 &&
|
||||
(source[1] & ASM_JCC32REL_1_MASK) == ASM_JCC32REL_1_MASK) {
|
||||
unsigned short jmpcode = (static_cast<unsigned char>(
|
||||
fixup_jump_offset) << 8) | (0x70 | (source[1] & 0xf));
|
||||
memcpy(reinterpret_cast<void*>(target),
|
||||
reinterpret_cast<void*>(&jmpcode),
|
||||
2);
|
||||
} else {
|
||||
target[0] = ASM_JMP8REL;
|
||||
target[1] = static_cast<unsigned char>(fixup_jump_offset);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
*target_bytes = instruction_size;
|
||||
if (target_size > *target_bytes) {
|
||||
memcpy(reinterpret_cast<void*>(target),
|
||||
reinterpret_cast<void*>(source),
|
||||
jmp_offset_in_instruction);
|
||||
memcpy(reinterpret_cast<void*>(target + jmp_offset_in_instruction),
|
||||
reinterpret_cast<void*>(&fixup_jump_offset),
|
||||
4);
|
||||
}
|
||||
}
|
||||
|
||||
return SIDESTEP_SUCCESS;
|
||||
}
|
||||
|
||||
SideStepError PreamblePatcher::PatchMovWithDisplacement(
|
||||
unsigned char* source,
|
||||
unsigned int instruction_size,
|
||||
unsigned char* target,
|
||||
unsigned int* target_bytes,
|
||||
unsigned int target_size) {
|
||||
SIDESTEP_ASSERT(instruction_size == 7);
|
||||
const int mov_offset_in_instruction = 3; // 0x48 0x8b 0x0d <offset>
|
||||
unsigned char* original_mov_dest = reinterpret_cast<unsigned char*>(
|
||||
reinterpret_cast<__int64>(source + instruction_size) +
|
||||
*(reinterpret_cast<int*>(source + mov_offset_in_instruction)));
|
||||
unsigned char* stub_mov_from = target + instruction_size;
|
||||
__int64 fixup_mov_offset = original_mov_dest - stub_mov_from;
|
||||
if (fixup_mov_offset > INT_MAX || fixup_mov_offset < INT_MIN) {
|
||||
SIDESTEP_ASSERT(false &&
|
||||
"Unable to fix up near MOV because target is too far away.");
|
||||
return SIDESTEP_UNEXPECTED;
|
||||
}
|
||||
*target_bytes = instruction_size;
|
||||
if (target_size > *target_bytes) {
|
||||
memcpy(reinterpret_cast<void*>(target),
|
||||
reinterpret_cast<void*>(source),
|
||||
mov_offset_in_instruction);
|
||||
memcpy(reinterpret_cast<void*>(target + mov_offset_in_instruction),
|
||||
reinterpret_cast<void*>(&fixup_mov_offset),
|
||||
4);
|
||||
}
|
||||
return SIDESTEP_SUCCESS;
|
||||
}
|
||||
|
||||
}; // namespace sidestep
|
620
trunk/3rdparty/gperftools-2-fit/src/windows/preamble_patcher.h
vendored
Normal file
620
trunk/3rdparty/gperftools-2-fit/src/windows/preamble_patcher.h
vendored
Normal file
|
@ -0,0 +1,620 @@
|
|||
// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
|
||||
/* Copyright (c) 2007, Google Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* * Neither the name of Google Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* ---
|
||||
* Author: Joi Sigurdsson
|
||||
* Author: Scott Francis
|
||||
*
|
||||
* Definition of PreamblePatcher
|
||||
*/
|
||||
|
||||
#ifndef GOOGLE_PERFTOOLS_PREAMBLE_PATCHER_H_
|
||||
#define GOOGLE_PERFTOOLS_PREAMBLE_PATCHER_H_
|
||||
|
||||
#include "config.h"
|
||||
#include <windows.h>
|
||||
|
||||
// compatibility shim
|
||||
#include "base/logging.h"
|
||||
#define SIDESTEP_ASSERT(cond) RAW_DCHECK(cond, #cond)
|
||||
#define SIDESTEP_LOG(msg) RAW_VLOG(1, msg)
|
||||
|
||||
// Maximum size of the preamble stub. We overwrite at least the first 5
|
||||
// bytes of the function. Considering the worst case scenario, we need 4
|
||||
// bytes + the max instruction size + 5 more bytes for our jump back to
|
||||
// the original code. With that in mind, 32 is a good number :)
|
||||
#ifdef _M_X64
|
||||
// In 64-bit mode we may need more room. In 64-bit mode all jumps must be
|
||||
// within +/-2GB of RIP. Because of this limitation we may need to use a
|
||||
// trampoline to jump to the replacement function if it is further than 2GB
|
||||
// away from the target. The trampoline is 14 bytes.
|
||||
//
|
||||
// So 4 bytes + max instruction size (17 bytes) + 5 bytes to jump back to the
|
||||
// original code + trampoline size. 64 bytes is a nice number :-)
|
||||
#define MAX_PREAMBLE_STUB_SIZE (64)
|
||||
#else
|
||||
#define MAX_PREAMBLE_STUB_SIZE (32)
|
||||
#endif
|
||||
|
||||
// Determines if this is a 64-bit binary.
|
||||
#ifdef _M_X64
|
||||
static const bool kIs64BitBinary = true;
|
||||
#else
|
||||
static const bool kIs64BitBinary = false;
|
||||
#endif
|
||||
|
||||
namespace sidestep {
|
||||
|
||||
// Possible results of patching/unpatching
|
||||
enum SideStepError {
|
||||
SIDESTEP_SUCCESS = 0,
|
||||
SIDESTEP_INVALID_PARAMETER,
|
||||
SIDESTEP_INSUFFICIENT_BUFFER,
|
||||
SIDESTEP_JUMP_INSTRUCTION,
|
||||
SIDESTEP_FUNCTION_TOO_SMALL,
|
||||
SIDESTEP_UNSUPPORTED_INSTRUCTION,
|
||||
SIDESTEP_NO_SUCH_MODULE,
|
||||
SIDESTEP_NO_SUCH_FUNCTION,
|
||||
SIDESTEP_ACCESS_DENIED,
|
||||
SIDESTEP_UNEXPECTED,
|
||||
};
|
||||
|
||||
#define SIDESTEP_TO_HRESULT(error) \
|
||||
MAKE_HRESULT(SEVERITY_ERROR, FACILITY_NULL, error)
|
||||
|
||||
class DeleteUnsignedCharArray;
|
||||
|
||||
// Implements a patching mechanism that overwrites the first few bytes of
|
||||
// a function preamble with a jump to our hook function, which is then
|
||||
// able to call the original function via a specially-made preamble-stub
|
||||
// that imitates the action of the original preamble.
|
||||
//
|
||||
// NOTE: This patching mechanism should currently only be used for
|
||||
// non-production code, e.g. unit tests, because it is not threadsafe.
|
||||
// See the TODO in preamble_patcher_with_stub.cc for instructions on what
|
||||
// we need to do before using it in production code; it's fairly simple
|
||||
// but unnecessary for now since we only intend to use it in unit tests.
|
||||
//
|
||||
// To patch a function, use either of the typesafe Patch() methods. You
|
||||
// can unpatch a function using Unpatch().
|
||||
//
|
||||
// Typical usage goes something like this:
|
||||
// @code
|
||||
// typedef int (*MyTypesafeFuncPtr)(int x);
|
||||
// MyTypesafeFuncPtr original_func_stub;
|
||||
// int MyTypesafeFunc(int x) { return x + 1; }
|
||||
// int HookMyTypesafeFunc(int x) { return 1 + original_func_stub(x); }
|
||||
//
|
||||
// void MyPatchInitializingFunction() {
|
||||
// original_func_stub = PreamblePatcher::Patch(
|
||||
// MyTypesafeFunc, HookMyTypesafeFunc);
|
||||
// if (!original_func_stub) {
|
||||
// // ... error handling ...
|
||||
// }
|
||||
//
|
||||
// // ... continue - you have patched the function successfully ...
|
||||
// }
|
||||
// @endcode
|
||||
//
|
||||
// Note that there are a number of ways that this method of patching can
|
||||
// fail. The most common are:
|
||||
// - If there is a jump (jxx) instruction in the first 5 bytes of
|
||||
// the function being patched, we cannot patch it because in the
|
||||
// current implementation we do not know how to rewrite relative
|
||||
// jumps after relocating them to the preamble-stub. Note that
|
||||
// if you really really need to patch a function like this, it
|
||||
// would be possible to add this functionality (but at some cost).
|
||||
// - If there is a return (ret) instruction in the first 5 bytes
|
||||
// we cannot patch the function because it may not be long enough
|
||||
// for the jmp instruction we use to inject our patch.
|
||||
// - If there is another thread currently executing within the bytes
|
||||
// that are copied to the preamble stub, it will crash in an undefined
|
||||
// way.
|
||||
//
|
||||
// If you get any other error than the above, you're either pointing the
|
||||
// patcher at an invalid instruction (e.g. into the middle of a multi-
|
||||
// byte instruction, or not at memory containing executable instructions)
|
||||
// or, there may be a bug in the disassembler we use to find
|
||||
// instruction boundaries.
|
||||
//
|
||||
// NOTE: In optimized builds, when you have very trivial functions that
|
||||
// the compiler can reason do not have side effects, the compiler may
|
||||
// reuse the result of calling the function with a given parameter, which
|
||||
// may mean if you patch the function in between your patch will never get
|
||||
// invoked. See preamble_patcher_test.cc for an example.
|
||||
class PERFTOOLS_DLL_DECL PreamblePatcher {
|
||||
public:
|
||||
|
||||
// This is a typesafe version of RawPatch(), identical in all other
|
||||
// ways than it takes a template parameter indicating the type of the
|
||||
// function being patched.
|
||||
//
|
||||
// @param T The type of the function you are patching. Usually
|
||||
// you will establish this type using a typedef, as in the following
|
||||
// example:
|
||||
// @code
|
||||
// typedef BOOL (WINAPI *MessageBoxPtr)(HWND, LPCTSTR, LPCTSTR, UINT);
|
||||
// MessageBoxPtr original = NULL;
|
||||
// PreamblePatcher::Patch(MessageBox, Hook_MessageBox, &original);
|
||||
// @endcode
|
||||
template <class T>
|
||||
static SideStepError Patch(T target_function,
|
||||
T replacement_function,
|
||||
T* original_function_stub) {
|
||||
// NOTE: casting from a function to a pointer is contra the C++
|
||||
// spec. It's not safe on IA64, but is on i386. We use
|
||||
// a C-style cast here to emphasize this is not legal C++.
|
||||
return RawPatch((void*)(target_function),
|
||||
(void*)(replacement_function),
|
||||
(void**)(original_function_stub));
|
||||
}
|
||||
|
||||
// Patches a named function imported from the named module using
|
||||
// preamble patching. Uses RawPatch() to do the actual patching
|
||||
// work.
|
||||
//
|
||||
// @param T The type of the function you are patching. Must
|
||||
// exactly match the function you specify using module_name and
|
||||
// function_name.
|
||||
//
|
||||
// @param module_name The name of the module from which the function
|
||||
// is being imported. Note that the patch will fail if this module
|
||||
// has not already been loaded into the current process.
|
||||
//
|
||||
// @param function_name The name of the function you wish to patch.
|
||||
//
|
||||
// @param replacement_function Your replacement function which
|
||||
// will be called whenever code tries to call the original function.
|
||||
//
|
||||
// @param original_function_stub Pointer to memory that should receive a
|
||||
// pointer that can be used (e.g. in the replacement function) to call the
|
||||
// original function, or NULL to indicate failure.
|
||||
//
|
||||
// @return One of the EnSideStepError error codes; only SIDESTEP_SUCCESS
|
||||
// indicates success.
|
||||
template <class T>
|
||||
static SideStepError Patch(LPCTSTR module_name,
|
||||
LPCSTR function_name,
|
||||
T replacement_function,
|
||||
T* original_function_stub) {
|
||||
SIDESTEP_ASSERT(module_name && function_name);
|
||||
if (!module_name || !function_name) {
|
||||
SIDESTEP_ASSERT(false &&
|
||||
"You must specify a module name and function name.");
|
||||
return SIDESTEP_INVALID_PARAMETER;
|
||||
}
|
||||
HMODULE module = ::GetModuleHandle(module_name);
|
||||
SIDESTEP_ASSERT(module != NULL);
|
||||
if (!module) {
|
||||
SIDESTEP_ASSERT(false && "Invalid module name.");
|
||||
return SIDESTEP_NO_SUCH_MODULE;
|
||||
}
|
||||
FARPROC existing_function = ::GetProcAddress(module, function_name);
|
||||
if (!existing_function) {
|
||||
SIDESTEP_ASSERT(
|
||||
false && "Did not find any function with that name in the module.");
|
||||
return SIDESTEP_NO_SUCH_FUNCTION;
|
||||
}
|
||||
// NOTE: casting from a function to a pointer is contra the C++
|
||||
// spec. It's not safe on IA64, but is on i386. We use
|
||||
// a C-style cast here to emphasize this is not legal C++.
|
||||
return RawPatch((void*)existing_function, (void*)replacement_function,
|
||||
(void**)(original_function_stub));
|
||||
}
|
||||
|
||||
// Patches a function by overwriting its first few bytes with
|
||||
// a jump to a different function. This is the "worker" function
|
||||
// for each of the typesafe Patch() functions. In most cases,
|
||||
// it is preferable to use the Patch() functions rather than
|
||||
// this one as they do more checking at compile time.
|
||||
//
|
||||
// @param target_function A pointer to the function that should be
|
||||
// patched.
|
||||
//
|
||||
// @param replacement_function A pointer to the function that should
|
||||
// replace the target function. The replacement function must have
|
||||
// exactly the same calling convention and parameters as the original
|
||||
// function.
|
||||
//
|
||||
// @param original_function_stub Pointer to memory that should receive a
|
||||
// pointer that can be used (e.g. in the replacement function) to call the
|
||||
// original function, or NULL to indicate failure.
|
||||
//
|
||||
// @param original_function_stub Pointer to memory that should receive a
|
||||
// pointer that can be used (e.g. in the replacement function) to call the
|
||||
// original function, or NULL to indicate failure.
|
||||
//
|
||||
// @return One of the EnSideStepError error codes; only SIDESTEP_SUCCESS
|
||||
// indicates success.
|
||||
//
|
||||
// @note The preamble-stub (the memory pointed to by
|
||||
// *original_function_stub) is allocated on the heap, and (in
|
||||
// production binaries) never destroyed, resulting in a memory leak. This
|
||||
// will be the case until we implement safe unpatching of a method.
|
||||
// However, it is quite difficult to unpatch a method (because other
|
||||
// threads in the process may be using it) so we are leaving it for now.
|
||||
// See however UnsafeUnpatch, which can be used for binaries where you
|
||||
// know only one thread is running, e.g. unit tests.
|
||||
static SideStepError RawPatch(void* target_function,
|
||||
void* replacement_function,
|
||||
void** original_function_stub);
|
||||
|
||||
// Unpatches target_function and deletes the stub that previously could be
|
||||
// used to call the original version of the function.
|
||||
//
|
||||
// DELETES the stub that is passed to the function.
|
||||
//
|
||||
// @param target_function Pointer to the target function which was
|
||||
// previously patched, i.e. a pointer which value should match the value
|
||||
// of the symbol prior to patching it.
|
||||
//
|
||||
// @param replacement_function Pointer to the function target_function
|
||||
// was patched to.
|
||||
//
|
||||
// @param original_function_stub Pointer to the stub returned when
|
||||
// patching, that could be used to call the original version of the
|
||||
// patched function. This function will also delete the stub, which after
|
||||
// unpatching is useless.
|
||||
//
|
||||
// If your original call was
|
||||
// Patch(VirtualAlloc, MyVirtualAlloc, &origptr)
|
||||
// then to undo it you would call
|
||||
// Unpatch(VirtualAlloc, MyVirtualAlloc, origptr);
|
||||
//
|
||||
// @return One of the EnSideStepError error codes; only SIDESTEP_SUCCESS
|
||||
// indicates success.
|
||||
static SideStepError Unpatch(void* target_function,
|
||||
void* replacement_function,
|
||||
void* original_function_stub);
|
||||
|
||||
// A helper routine when patching, which follows jmp instructions at
|
||||
// function addresses, to get to the "actual" function contents.
|
||||
// This allows us to identify two functions that are at different
|
||||
// addresses but actually resolve to the same code.
|
||||
//
|
||||
// @param target_function Pointer to a function.
|
||||
//
|
||||
// @return Either target_function (the input parameter), or if
|
||||
// target_function's body consists entirely of a JMP instruction,
|
||||
// the address it JMPs to (or more precisely, the address at the end
|
||||
// of a chain of JMPs).
|
||||
template <class T>
|
||||
static T ResolveTarget(T target_function) {
|
||||
return (T)ResolveTargetImpl((unsigned char*)target_function, NULL);
|
||||
}
|
||||
|
||||
// Allocates a block of memory of size MAX_PREAMBLE_STUB_SIZE that is as
|
||||
// close (within 2GB) as possible to target. This is done to ensure that
|
||||
// we can perform a relative jump from target to a trampoline if the
|
||||
// replacement function is > +-2GB from target. This means that we only need
|
||||
// to patch 5 bytes in the target function.
|
||||
//
|
||||
// @param target Pointer to target function.
|
||||
//
|
||||
// @return Returns a block of memory of size MAX_PREAMBLE_STUB_SIZE that can
|
||||
// be used to store a function preamble block.
|
||||
static unsigned char* AllocPreambleBlockNear(void* target);
|
||||
|
||||
// Frees a block allocated by AllocPreambleBlockNear.
|
||||
//
|
||||
// @param block Block that was returned by AllocPreambleBlockNear.
|
||||
static void FreePreambleBlock(unsigned char* block);
|
||||
|
||||
private:
|
||||
friend class DeleteUnsignedCharArray;
|
||||
|
||||
// Used to store data allocated for preamble stubs
|
||||
struct PreamblePage {
|
||||
unsigned int magic_;
|
||||
PreamblePage* next_;
|
||||
// This member points to a linked list of free blocks within the page
|
||||
// or NULL if at the end
|
||||
void* free_;
|
||||
};
|
||||
|
||||
// In 64-bit mode, the replacement function must be within 2GB of the original
|
||||
// target in order to only require 5 bytes for the function patch. To meet
|
||||
// this requirement we're creating an allocator within this class to
|
||||
// allocate blocks that are within 2GB of a given target. This member is the
|
||||
// head of a linked list of pages used to allocate blocks that are within
|
||||
// 2GB of the target.
|
||||
static PreamblePage* preamble_pages_;
|
||||
|
||||
// Page granularity
|
||||
static long granularity_;
|
||||
|
||||
// Page size
|
||||
static long pagesize_;
|
||||
|
||||
// Determines if the patcher has been initialized.
|
||||
static bool initialized_;
|
||||
|
||||
// Used to initialize static members.
|
||||
static void Initialize();
|
||||
|
||||
// Patches a function by overwriting its first few bytes with
|
||||
// a jump to a different function. This is similar to the RawPatch
|
||||
// function except that it uses the stub allocated by the caller
|
||||
// instead of allocating it.
|
||||
//
|
||||
// We call VirtualProtect to make the
|
||||
// target function writable at least for the duration of the call.
|
||||
//
|
||||
// @param target_function A pointer to the function that should be
|
||||
// patched.
|
||||
//
|
||||
// @param replacement_function A pointer to the function that should
|
||||
// replace the target function. The replacement function must have
|
||||
// exactly the same calling convention and parameters as the original
|
||||
// function.
|
||||
//
|
||||
// @param preamble_stub A pointer to a buffer where the preamble stub
|
||||
// should be copied. The size of the buffer should be sufficient to
|
||||
// hold the preamble bytes.
|
||||
//
|
||||
// @param stub_size Size in bytes of the buffer allocated for the
|
||||
// preamble_stub
|
||||
//
|
||||
// @param bytes_needed Pointer to a variable that receives the minimum
|
||||
// number of bytes required for the stub. Can be set to NULL if you're
|
||||
// not interested.
|
||||
//
|
||||
// @return An error code indicating the result of patching.
|
||||
static SideStepError RawPatchWithStubAndProtections(
|
||||
void* target_function,
|
||||
void* replacement_function,
|
||||
unsigned char* preamble_stub,
|
||||
unsigned long stub_size,
|
||||
unsigned long* bytes_needed);
|
||||
|
||||
// A helper function used by RawPatchWithStubAndProtections -- it
|
||||
// does everything but the VirtualProtect work. Defined in
|
||||
// preamble_patcher_with_stub.cc.
|
||||
//
|
||||
// @param target_function A pointer to the function that should be
|
||||
// patched.
|
||||
//
|
||||
// @param replacement_function A pointer to the function that should
|
||||
// replace the target function. The replacement function must have
|
||||
// exactly the same calling convention and parameters as the original
|
||||
// function.
|
||||
//
|
||||
// @param preamble_stub A pointer to a buffer where the preamble stub
|
||||
// should be copied. The size of the buffer should be sufficient to
|
||||
// hold the preamble bytes.
|
||||
//
|
||||
// @param stub_size Size in bytes of the buffer allocated for the
|
||||
// preamble_stub
|
||||
//
|
||||
// @param bytes_needed Pointer to a variable that receives the minimum
|
||||
// number of bytes required for the stub. Can be set to NULL if you're
|
||||
// not interested.
|
||||
//
|
||||
// @return An error code indicating the result of patching.
|
||||
static SideStepError RawPatchWithStub(void* target_function,
|
||||
void* replacement_function,
|
||||
unsigned char* preamble_stub,
|
||||
unsigned long stub_size,
|
||||
unsigned long* bytes_needed);
|
||||
|
||||
|
||||
// A helper routine when patching, which follows jmp instructions at
|
||||
// function addresses, to get to the "actual" function contents.
|
||||
// This allows us to identify two functions that are at different
|
||||
// addresses but actually resolve to the same code.
|
||||
//
|
||||
// @param target_function Pointer to a function.
|
||||
//
|
||||
// @param stop_before If, when following JMP instructions from
|
||||
// target_function, we get to the address stop, we return
|
||||
// immediately, the address that jumps to stop_before.
|
||||
//
|
||||
// @param stop_before_trampoline When following JMP instructions from
|
||||
// target_function, stop before a trampoline is detected. See comment in
|
||||
// PreamblePatcher::RawPatchWithStub for more information. This parameter
|
||||
// has no effect in 32-bit mode.
|
||||
//
|
||||
// @return Either target_function (the input parameter), or if
|
||||
// target_function's body consists entirely of a JMP instruction,
|
||||
// the address it JMPs to (or more precisely, the address at the end
|
||||
// of a chain of JMPs).
|
||||
static void* ResolveTargetImpl(unsigned char* target_function,
|
||||
unsigned char* stop_before,
|
||||
bool stop_before_trampoline = false);
|
||||
|
||||
// Helper routine that attempts to allocate a page as close (within 2GB)
|
||||
// as possible to target.
|
||||
//
|
||||
// @param target Pointer to target function.
|
||||
//
|
||||
// @return Returns an address that is within 2GB of target.
|
||||
static void* AllocPageNear(void* target);
|
||||
|
||||
// Helper routine that determines if a target instruction is a short
|
||||
// conditional jump.
|
||||
//
|
||||
// @param target Pointer to instruction.
|
||||
//
|
||||
// @param instruction_size Size of the instruction in bytes.
|
||||
//
|
||||
// @return Returns true if the instruction is a short conditional jump.
|
||||
static bool IsShortConditionalJump(unsigned char* target,
|
||||
unsigned int instruction_size);
|
||||
|
||||
static bool IsShortJump(unsigned char *target, unsigned int instruction_size);
|
||||
|
||||
// Helper routine that determines if a target instruction is a near
|
||||
// conditional jump.
|
||||
//
|
||||
// @param target Pointer to instruction.
|
||||
//
|
||||
// @param instruction_size Size of the instruction in bytes.
|
||||
//
|
||||
// @return Returns true if the instruction is a near conditional jump.
|
||||
static bool IsNearConditionalJump(unsigned char* target,
|
||||
unsigned int instruction_size);
|
||||
|
||||
// Helper routine that determines if a target instruction is a near
|
||||
// relative jump.
|
||||
//
|
||||
// @param target Pointer to instruction.
|
||||
//
|
||||
// @param instruction_size Size of the instruction in bytes.
|
||||
//
|
||||
// @return Returns true if the instruction is a near absolute jump.
|
||||
static bool IsNearRelativeJump(unsigned char* target,
|
||||
unsigned int instruction_size);
|
||||
|
||||
// Helper routine that determines if a target instruction is a near
|
||||
// absolute call.
|
||||
//
|
||||
// @param target Pointer to instruction.
|
||||
//
|
||||
// @param instruction_size Size of the instruction in bytes.
|
||||
//
|
||||
// @return Returns true if the instruction is a near absolute call.
|
||||
static bool IsNearAbsoluteCall(unsigned char* target,
|
||||
unsigned int instruction_size);
|
||||
|
||||
// Helper routine that determines if a target instruction is a near
|
||||
// absolute call.
|
||||
//
|
||||
// @param target Pointer to instruction.
|
||||
//
|
||||
// @param instruction_size Size of the instruction in bytes.
|
||||
//
|
||||
// @return Returns true if the instruction is a near absolute call.
|
||||
static bool IsNearRelativeCall(unsigned char* target,
|
||||
unsigned int instruction_size);
|
||||
|
||||
// Helper routine that determines if a target instruction is a 64-bit MOV
|
||||
// that uses a RIP-relative displacement.
|
||||
//
|
||||
// @param target Pointer to instruction.
|
||||
//
|
||||
// @param instruction_size Size of the instruction in bytes.
|
||||
//
|
||||
// @return Returns true if the instruction is a MOV with displacement.
|
||||
static bool IsMovWithDisplacement(unsigned char* target,
|
||||
unsigned int instruction_size);
|
||||
|
||||
// Helper routine that converts a short conditional jump instruction
|
||||
// to a near conditional jump in a target buffer. Note that the target
|
||||
// buffer must be within 2GB of the source for the near jump to work.
|
||||
//
|
||||
// A short conditional jump instruction is in the format:
|
||||
// 7x xx = Jcc rel8off
|
||||
//
|
||||
// @param source Pointer to instruction.
|
||||
//
|
||||
// @param instruction_size Size of the instruction.
|
||||
//
|
||||
// @param target Target buffer to write the new instruction.
|
||||
//
|
||||
// @param target_bytes Pointer to a buffer that contains the size
|
||||
// of the target instruction, in bytes.
|
||||
//
|
||||
// @param target_size Size of the target buffer.
|
||||
//
|
||||
// @return Returns SIDESTEP_SUCCESS if successful, otherwise an error.
|
||||
static SideStepError PatchShortConditionalJump(unsigned char* source,
|
||||
unsigned int instruction_size,
|
||||
unsigned char* target,
|
||||
unsigned int* target_bytes,
|
||||
unsigned int target_size);
|
||||
|
||||
static SideStepError PatchShortJump(unsigned char* source,
|
||||
unsigned int instruction_size,
|
||||
unsigned char* target,
|
||||
unsigned int* target_bytes,
|
||||
unsigned int target_size);
|
||||
|
||||
// Helper routine that converts an instruction that will convert various
|
||||
// jump-like instructions to corresponding instructions in the target buffer.
|
||||
// What this routine does is fix up the relative offsets contained in jump
|
||||
// instructions to point back to the original target routine. Like with
|
||||
// PatchShortConditionalJump, the target buffer must be within 2GB of the
|
||||
// source.
|
||||
//
|
||||
// We currently handle the following instructions:
|
||||
//
|
||||
// E9 xx xx xx xx = JMP rel32off
|
||||
// 0F 8x xx xx xx xx = Jcc rel32off
|
||||
// FF /2 xx xx xx xx = CALL reg/mem32/mem64
|
||||
// E8 xx xx xx xx = CALL rel32off
|
||||
//
|
||||
// It should not be hard to update this function to support other
|
||||
// instructions that jump to relative targets.
|
||||
//
|
||||
// @param source Pointer to instruction.
|
||||
//
|
||||
// @param instruction_size Size of the instruction.
|
||||
//
|
||||
// @param target Target buffer to write the new instruction.
|
||||
//
|
||||
// @param target_bytes Pointer to a buffer that contains the size
|
||||
// of the target instruction, in bytes.
|
||||
//
|
||||
// @param target_size Size of the target buffer.
|
||||
//
|
||||
// @return Returns SIDESTEP_SUCCESS if successful, otherwise an error.
|
||||
static SideStepError PatchNearJumpOrCall(unsigned char* source,
|
||||
unsigned int instruction_size,
|
||||
unsigned char* target,
|
||||
unsigned int* target_bytes,
|
||||
unsigned int target_size);
|
||||
|
||||
// Helper routine that patches a 64-bit MOV instruction with a RIP-relative
|
||||
// displacement. The target buffer must be within 2GB of the source.
|
||||
//
|
||||
// 48 8B 0D XX XX XX XX = MOV rel32off
|
||||
//
|
||||
// @param source Pointer to instruction.
|
||||
//
|
||||
// @param instruction_size Size of the instruction.
|
||||
//
|
||||
// @param target Target buffer to write the new instruction.
|
||||
//
|
||||
// @param target_bytes Pointer to a buffer that contains the size
|
||||
// of the target instruction, in bytes.
|
||||
//
|
||||
// @param target_size Size of the target buffer.
|
||||
//
|
||||
// @return Returns SIDESTEP_SUCCESS if successful, otherwise an error.
|
||||
static SideStepError PatchMovWithDisplacement(unsigned char* source,
|
||||
unsigned int instruction_size,
|
||||
unsigned char* target,
|
||||
unsigned int* target_bytes,
|
||||
unsigned int target_size);
|
||||
};
|
||||
|
||||
}; // namespace sidestep
|
||||
|
||||
#endif // GOOGLE_PERFTOOLS_PREAMBLE_PATCHER_H_
|
368
trunk/3rdparty/gperftools-2-fit/src/windows/preamble_patcher_test.cc
vendored
Normal file
368
trunk/3rdparty/gperftools-2-fit/src/windows/preamble_patcher_test.cc
vendored
Normal file
|
@ -0,0 +1,368 @@
|
|||
// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
|
||||
/* Copyright (c) 2011, Google Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* * Neither the name of Google Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* ---
|
||||
* Author: Joi Sigurdsson
|
||||
* Author: Scott Francis
|
||||
*
|
||||
* Unit tests for PreamblePatcher
|
||||
*/
|
||||
|
||||
#include "config_for_unittests.h"
|
||||
#include "preamble_patcher.h"
|
||||
#include "mini_disassembler.h"
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4553)
|
||||
#include "auto_testing_hook.h"
|
||||
#pragma warning(pop)
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#include <tchar.h>
|
||||
|
||||
// Turning off all optimizations for this file, since the official build's
|
||||
// "Whole program optimization" seems to cause the TestPatchUsingDynamicStub
|
||||
// test to crash with an access violation. We debugged this and found
|
||||
// that the optimized access a register that is changed by a call to the hook
|
||||
// function.
|
||||
#pragma optimize("", off)
|
||||
|
||||
// A convenience macro to avoid a lot of casting in the tests.
|
||||
// I tried to make this a templated function, but windows complained:
|
||||
// error C2782: 'sidestep::SideStepError `anonymous-namespace'::Unpatch(T,T,T *)' : template parameter 'T' is ambiguous
|
||||
// could be 'int (int)'
|
||||
// or 'int (__cdecl *)(int)'
|
||||
// My life isn't long enough to try to figure out how to fix this.
|
||||
#define UNPATCH(target_function, replacement_function, original_function_stub) \
|
||||
sidestep::PreamblePatcher::Unpatch((void*)(target_function), \
|
||||
(void*)(replacement_function), \
|
||||
(void*)(original_function))
|
||||
|
||||
namespace {
|
||||
|
||||
// Function for testing - this is what we patch
|
||||
//
|
||||
// NOTE: Because of the way the compiler optimizes this function in
|
||||
// release builds, we need to use a different input value every time we
|
||||
// call it within a function, otherwise the compiler will just reuse the
|
||||
// last calculated incremented value.
|
||||
int __declspec(noinline) IncrementNumber(int i) {
|
||||
#ifdef _M_X64
|
||||
__int64 i2 = i + 1;
|
||||
return (int) i2;
|
||||
#else
|
||||
return i + 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
extern "C" int TooShortFunction(int);
|
||||
|
||||
extern "C" int JumpShortCondFunction(int);
|
||||
|
||||
extern "C" int JumpNearCondFunction(int);
|
||||
|
||||
extern "C" int JumpAbsoluteFunction(int);
|
||||
|
||||
extern "C" int CallNearRelativeFunction(int);
|
||||
|
||||
typedef int (*IncrementingFunc)(int);
|
||||
IncrementingFunc original_function = NULL;
|
||||
|
||||
int HookIncrementNumber(int i) {
|
||||
SIDESTEP_ASSERT(original_function != NULL);
|
||||
int incremented_once = original_function(i);
|
||||
return incremented_once + 1;
|
||||
}
|
||||
|
||||
// For the AutoTestingHook test, we can't use original_function, because
|
||||
// all that is encapsulated.
|
||||
// This function "increments" by 10, just to set it apart from the other
|
||||
// functions.
|
||||
int __declspec(noinline) AutoHookIncrementNumber(int i) {
|
||||
return i + 10;
|
||||
}
|
||||
|
||||
}; // namespace
|
||||
|
||||
namespace sidestep {
|
||||
|
||||
bool TestDisassembler() {
|
||||
unsigned int instruction_size = 0;
|
||||
sidestep::MiniDisassembler disassembler;
|
||||
void * target = reinterpret_cast<unsigned char *>(IncrementNumber);
|
||||
void * new_target = PreamblePatcher::ResolveTarget(target);
|
||||
if (target != new_target)
|
||||
target = new_target;
|
||||
|
||||
while (1) {
|
||||
sidestep::InstructionType instructionType = disassembler.Disassemble(
|
||||
reinterpret_cast<unsigned char *>(target) + instruction_size,
|
||||
instruction_size);
|
||||
if (sidestep::IT_RETURN == instructionType) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool TestPatchWithLongJump() {
|
||||
original_function = NULL;
|
||||
void *p = ::VirtualAlloc(reinterpret_cast<void *>(0x0000020000000000), 4096,
|
||||
MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
|
||||
SIDESTEP_EXPECT_TRUE(p != NULL);
|
||||
memset(p, 0xcc, 4096);
|
||||
SIDESTEP_EXPECT_TRUE(sidestep::SIDESTEP_SUCCESS ==
|
||||
sidestep::PreamblePatcher::Patch(IncrementNumber,
|
||||
(IncrementingFunc) p,
|
||||
&original_function));
|
||||
SIDESTEP_ASSERT((*original_function)(1) == 2);
|
||||
SIDESTEP_EXPECT_TRUE(sidestep::SIDESTEP_SUCCESS ==
|
||||
UNPATCH(IncrementNumber,
|
||||
(IncrementingFunc)p,
|
||||
original_function));
|
||||
::VirtualFree(p, 0, MEM_RELEASE);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TestPatchWithPreambleShortCondJump() {
|
||||
original_function = NULL;
|
||||
SIDESTEP_EXPECT_TRUE(sidestep::SIDESTEP_SUCCESS ==
|
||||
sidestep::PreamblePatcher::Patch(JumpShortCondFunction,
|
||||
HookIncrementNumber,
|
||||
&original_function));
|
||||
(*original_function)(1);
|
||||
SIDESTEP_EXPECT_TRUE(sidestep::SIDESTEP_SUCCESS ==
|
||||
UNPATCH(JumpShortCondFunction,
|
||||
(void*)HookIncrementNumber,
|
||||
original_function));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TestPatchWithPreambleNearRelativeCondJump() {
|
||||
original_function = NULL;
|
||||
SIDESTEP_EXPECT_TRUE(sidestep::SIDESTEP_SUCCESS ==
|
||||
sidestep::PreamblePatcher::Patch(JumpNearCondFunction,
|
||||
HookIncrementNumber,
|
||||
&original_function));
|
||||
(*original_function)(0);
|
||||
(*original_function)(1);
|
||||
SIDESTEP_EXPECT_TRUE(sidestep::SIDESTEP_SUCCESS ==
|
||||
UNPATCH(JumpNearCondFunction,
|
||||
HookIncrementNumber,
|
||||
original_function));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TestPatchWithPreambleAbsoluteJump() {
|
||||
original_function = NULL;
|
||||
SIDESTEP_EXPECT_TRUE(sidestep::SIDESTEP_SUCCESS ==
|
||||
sidestep::PreamblePatcher::Patch(JumpAbsoluteFunction,
|
||||
HookIncrementNumber,
|
||||
&original_function));
|
||||
(*original_function)(0);
|
||||
(*original_function)(1);
|
||||
SIDESTEP_EXPECT_TRUE(sidestep::SIDESTEP_SUCCESS ==
|
||||
UNPATCH(JumpAbsoluteFunction,
|
||||
HookIncrementNumber,
|
||||
original_function));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TestPatchWithPreambleNearRelativeCall() {
|
||||
original_function = NULL;
|
||||
SIDESTEP_EXPECT_TRUE(sidestep::SIDESTEP_SUCCESS ==
|
||||
sidestep::PreamblePatcher::Patch(
|
||||
CallNearRelativeFunction,
|
||||
HookIncrementNumber,
|
||||
&original_function));
|
||||
(*original_function)(0);
|
||||
(*original_function)(1);
|
||||
SIDESTEP_EXPECT_TRUE(sidestep::SIDESTEP_SUCCESS ==
|
||||
UNPATCH(CallNearRelativeFunction,
|
||||
HookIncrementNumber,
|
||||
original_function));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TestPatchUsingDynamicStub() {
|
||||
original_function = NULL;
|
||||
SIDESTEP_EXPECT_TRUE(IncrementNumber(1) == 2);
|
||||
SIDESTEP_EXPECT_TRUE(sidestep::SIDESTEP_SUCCESS ==
|
||||
sidestep::PreamblePatcher::Patch(IncrementNumber,
|
||||
HookIncrementNumber,
|
||||
&original_function));
|
||||
SIDESTEP_EXPECT_TRUE(original_function);
|
||||
SIDESTEP_EXPECT_TRUE(IncrementNumber(2) == 4);
|
||||
SIDESTEP_EXPECT_TRUE(original_function(3) == 4);
|
||||
|
||||
// Clearbox test to see that the function has been patched.
|
||||
sidestep::MiniDisassembler disassembler;
|
||||
unsigned int instruction_size = 0;
|
||||
SIDESTEP_EXPECT_TRUE(sidestep::IT_JUMP == disassembler.Disassemble(
|
||||
reinterpret_cast<unsigned char*>(IncrementNumber),
|
||||
instruction_size));
|
||||
|
||||
// Since we patched IncrementNumber, its first statement is a
|
||||
// jmp to the hook function. So verify that we now can not patch
|
||||
// IncrementNumber because it starts with a jump.
|
||||
#if 0
|
||||
IncrementingFunc dummy = NULL;
|
||||
// TODO(joi@chromium.org): restore this test once flag is added to
|
||||
// disable JMP following
|
||||
SIDESTEP_EXPECT_TRUE(sidestep::SIDESTEP_JUMP_INSTRUCTION ==
|
||||
sidestep::PreamblePatcher::Patch(IncrementNumber,
|
||||
HookIncrementNumber,
|
||||
&dummy));
|
||||
|
||||
// This test disabled because code in preamble_patcher_with_stub.cc
|
||||
// asserts before returning the error code -- so there is no way
|
||||
// to get an error code here, in debug build.
|
||||
dummy = NULL;
|
||||
SIDESTEP_EXPECT_TRUE(sidestep::SIDESTEP_FUNCTION_TOO_SMALL ==
|
||||
sidestep::PreamblePatcher::Patch(TooShortFunction,
|
||||
HookIncrementNumber,
|
||||
&dummy));
|
||||
#endif
|
||||
|
||||
SIDESTEP_EXPECT_TRUE(sidestep::SIDESTEP_SUCCESS ==
|
||||
UNPATCH(IncrementNumber,
|
||||
HookIncrementNumber,
|
||||
original_function));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PatchThenUnpatch() {
|
||||
original_function = NULL;
|
||||
SIDESTEP_EXPECT_TRUE(sidestep::SIDESTEP_SUCCESS ==
|
||||
sidestep::PreamblePatcher::Patch(IncrementNumber,
|
||||
HookIncrementNumber,
|
||||
&original_function));
|
||||
SIDESTEP_EXPECT_TRUE(original_function);
|
||||
SIDESTEP_EXPECT_TRUE(IncrementNumber(1) == 3);
|
||||
SIDESTEP_EXPECT_TRUE(original_function(2) == 3);
|
||||
|
||||
SIDESTEP_EXPECT_TRUE(sidestep::SIDESTEP_SUCCESS ==
|
||||
UNPATCH(IncrementNumber,
|
||||
HookIncrementNumber,
|
||||
original_function));
|
||||
original_function = NULL;
|
||||
SIDESTEP_EXPECT_TRUE(IncrementNumber(3) == 4);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AutoTestingHookTest() {
|
||||
SIDESTEP_EXPECT_TRUE(IncrementNumber(1) == 2);
|
||||
|
||||
// Inner scope, so we can test what happens when the AutoTestingHook
|
||||
// goes out of scope
|
||||
{
|
||||
AutoTestingHook hook = MakeTestingHook(IncrementNumber,
|
||||
AutoHookIncrementNumber);
|
||||
(void) hook;
|
||||
SIDESTEP_EXPECT_TRUE(IncrementNumber(2) == 12);
|
||||
}
|
||||
SIDESTEP_EXPECT_TRUE(IncrementNumber(3) == 4);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AutoTestingHookInContainerTest() {
|
||||
SIDESTEP_EXPECT_TRUE(IncrementNumber(1) == 2);
|
||||
|
||||
// Inner scope, so we can test what happens when the AutoTestingHook
|
||||
// goes out of scope
|
||||
{
|
||||
AutoTestingHookHolder hook(MakeTestingHookHolder(IncrementNumber,
|
||||
AutoHookIncrementNumber));
|
||||
(void) hook;
|
||||
SIDESTEP_EXPECT_TRUE(IncrementNumber(2) == 12);
|
||||
}
|
||||
SIDESTEP_EXPECT_TRUE(IncrementNumber(3) == 4);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TestPreambleAllocation() {
|
||||
__int64 diff = 0;
|
||||
void* p1 = reinterpret_cast<void*>(0x110000000);
|
||||
void* p2 = reinterpret_cast<void*>(0x810000000);
|
||||
unsigned char* b1 = PreamblePatcher::AllocPreambleBlockNear(p1);
|
||||
SIDESTEP_EXPECT_TRUE(b1 != NULL);
|
||||
diff = reinterpret_cast<__int64>(p1) - reinterpret_cast<__int64>(b1);
|
||||
// Ensure blocks are within 2GB
|
||||
SIDESTEP_EXPECT_TRUE(diff <= INT_MAX && diff >= INT_MIN);
|
||||
unsigned char* b2 = PreamblePatcher::AllocPreambleBlockNear(p2);
|
||||
SIDESTEP_EXPECT_TRUE(b2 != NULL);
|
||||
diff = reinterpret_cast<__int64>(p2) - reinterpret_cast<__int64>(b2);
|
||||
SIDESTEP_EXPECT_TRUE(diff <= INT_MAX && diff >= INT_MIN);
|
||||
|
||||
// Ensure we're reusing free blocks
|
||||
unsigned char* b3 = b1;
|
||||
unsigned char* b4 = b2;
|
||||
PreamblePatcher::FreePreambleBlock(b1);
|
||||
PreamblePatcher::FreePreambleBlock(b2);
|
||||
b1 = PreamblePatcher::AllocPreambleBlockNear(p1);
|
||||
SIDESTEP_EXPECT_TRUE(b1 == b3);
|
||||
b2 = PreamblePatcher::AllocPreambleBlockNear(p2);
|
||||
SIDESTEP_EXPECT_TRUE(b2 == b4);
|
||||
PreamblePatcher::FreePreambleBlock(b1);
|
||||
PreamblePatcher::FreePreambleBlock(b2);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool UnitTests() {
|
||||
return TestPatchWithPreambleNearRelativeCall() &&
|
||||
TestPatchWithPreambleAbsoluteJump() &&
|
||||
TestPatchWithPreambleNearRelativeCondJump() &&
|
||||
TestPatchWithPreambleShortCondJump() &&
|
||||
TestDisassembler() && TestPatchWithLongJump() &&
|
||||
TestPatchUsingDynamicStub() && PatchThenUnpatch() &&
|
||||
AutoTestingHookTest() && AutoTestingHookInContainerTest() &&
|
||||
TestPreambleAllocation();
|
||||
}
|
||||
|
||||
}; // namespace sidestep
|
||||
|
||||
int safe_vsnprintf(char *str, size_t size, const char *format, va_list ap) {
|
||||
if (size == 0) // not even room for a \0?
|
||||
return -1; // not what C99 says to do, but what windows does
|
||||
str[size-1] = '\0';
|
||||
return _vsnprintf(str, size-1, format, ap);
|
||||
}
|
||||
|
||||
int _tmain(int argc, _TCHAR* argv[])
|
||||
{
|
||||
bool ret = sidestep::UnitTests();
|
||||
printf("%s\n", ret ? "PASS" : "FAIL");
|
||||
return ret ? 0 : -1;
|
||||
}
|
||||
|
||||
#pragma optimize("", on)
|
302
trunk/3rdparty/gperftools-2-fit/src/windows/preamble_patcher_with_stub.cc
vendored
Normal file
302
trunk/3rdparty/gperftools-2-fit/src/windows/preamble_patcher_with_stub.cc
vendored
Normal file
|
@ -0,0 +1,302 @@
|
|||
// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
|
||||
/* Copyright (c) 2007, Google Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* * Neither the name of Google Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* ---
|
||||
* Author: Joi Sigurdsson
|
||||
* Author: Scott Francis
|
||||
*
|
||||
* Implementation of PreamblePatcher
|
||||
*/
|
||||
|
||||
#include "preamble_patcher.h"
|
||||
|
||||
#include "mini_disassembler.h"
|
||||
|
||||
// Definitions of assembly statements we need
|
||||
#define ASM_JMP32REL 0xE9
|
||||
#define ASM_INT3 0xCC
|
||||
#define ASM_NOP 0x90
|
||||
// X64 opcodes
|
||||
#define ASM_MOVRAX_IMM 0xB8
|
||||
#define ASM_REXW 0x48
|
||||
#define ASM_JMP 0xFF
|
||||
#define ASM_JMP_RAX 0xE0
|
||||
#define ASM_PUSH 0x68
|
||||
#define ASM_RET 0xC3
|
||||
|
||||
namespace sidestep {
|
||||
|
||||
SideStepError PreamblePatcher::RawPatchWithStub(
|
||||
void* target_function,
|
||||
void* replacement_function,
|
||||
unsigned char* preamble_stub,
|
||||
unsigned long stub_size,
|
||||
unsigned long* bytes_needed) {
|
||||
if ((NULL == target_function) ||
|
||||
(NULL == replacement_function) ||
|
||||
(NULL == preamble_stub)) {
|
||||
SIDESTEP_ASSERT(false &&
|
||||
"Invalid parameters - either pTargetFunction or "
|
||||
"pReplacementFunction or pPreambleStub were NULL.");
|
||||
return SIDESTEP_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
// TODO(V7:joi) Siggi and I just had a discussion and decided that both
|
||||
// patching and unpatching are actually unsafe. We also discussed a
|
||||
// method of making it safe, which is to freeze all other threads in the
|
||||
// process, check their thread context to see if their eip is currently
|
||||
// inside the block of instructions we need to copy to the stub, and if so
|
||||
// wait a bit and try again, then unfreeze all threads once we've patched.
|
||||
// Not implementing this for now since we're only using SideStep for unit
|
||||
// testing, but if we ever use it for production code this is what we
|
||||
// should do.
|
||||
//
|
||||
// NOTE: Stoyan suggests we can write 8 or even 10 bytes atomically using
|
||||
// FPU instructions, and on newer processors we could use cmpxchg8b or
|
||||
// cmpxchg16b. So it might be possible to do the patching/unpatching
|
||||
// atomically and avoid having to freeze other threads. Note though, that
|
||||
// doing it atomically does not help if one of the other threads happens
|
||||
// to have its eip in the middle of the bytes you change while you change
|
||||
// them.
|
||||
unsigned char* target = reinterpret_cast<unsigned char*>(target_function);
|
||||
unsigned int required_trampoline_bytes = 0;
|
||||
const unsigned int kRequiredStubJumpBytes = 5;
|
||||
const unsigned int kRequiredTargetPatchBytes = 5;
|
||||
|
||||
// Initialize the stub with INT3's just in case.
|
||||
if (stub_size) {
|
||||
memset(preamble_stub, 0xcc, stub_size);
|
||||
}
|
||||
if (kIs64BitBinary) {
|
||||
// In 64-bit mode JMP instructions are always relative to RIP. If the
|
||||
// replacement - target offset is > 2GB, we can't JMP to the replacement
|
||||
// function. In this case, we're going to use a trampoline - that is,
|
||||
// we're going to do a relative jump to a small chunk of code in the stub
|
||||
// that will then do the absolute jump to the replacement function. By
|
||||
// doing this, we only need to patch 5 bytes in the target function, as
|
||||
// opposed to patching 12 bytes if we were to do an absolute jump.
|
||||
//
|
||||
// Note that the first byte of the trampoline is a NOP instruction. This
|
||||
// is used as a trampoline signature that will be detected when unpatching
|
||||
// the function.
|
||||
//
|
||||
// jmp <trampoline>
|
||||
//
|
||||
// trampoline:
|
||||
// nop
|
||||
// mov rax, <replacement_function>
|
||||
// jmp rax
|
||||
//
|
||||
__int64 replacement_target_offset = reinterpret_cast<__int64>(
|
||||
replacement_function) - reinterpret_cast<__int64>(target) - 5;
|
||||
if (replacement_target_offset > INT_MAX
|
||||
|| replacement_target_offset < INT_MIN) {
|
||||
// The stub needs to be within 2GB of the target for the trampoline to
|
||||
// work!
|
||||
__int64 trampoline_offset = reinterpret_cast<__int64>(preamble_stub)
|
||||
- reinterpret_cast<__int64>(target) - 5;
|
||||
if (trampoline_offset > INT_MAX || trampoline_offset < INT_MIN) {
|
||||
// We're screwed.
|
||||
SIDESTEP_ASSERT(false
|
||||
&& "Preamble stub is too far from target to patch.");
|
||||
return SIDESTEP_UNEXPECTED;
|
||||
}
|
||||
required_trampoline_bytes = 13;
|
||||
}
|
||||
}
|
||||
|
||||
// Let's disassemble the preamble of the target function to see if we can
|
||||
// patch, and to see how much of the preamble we need to take. We need 5
|
||||
// bytes for our jmp instruction, so let's find the minimum number of
|
||||
// instructions to get 5 bytes.
|
||||
MiniDisassembler disassembler;
|
||||
unsigned int preamble_bytes = 0;
|
||||
unsigned int stub_bytes = 0;
|
||||
while (preamble_bytes < kRequiredTargetPatchBytes) {
|
||||
unsigned int cur_bytes = 0;
|
||||
InstructionType instruction_type =
|
||||
disassembler.Disassemble(target + preamble_bytes, cur_bytes);
|
||||
if (IT_JUMP == instruction_type) {
|
||||
unsigned int jump_bytes = 0;
|
||||
SideStepError jump_ret = SIDESTEP_JUMP_INSTRUCTION;
|
||||
if (IsShortConditionalJump(target + preamble_bytes, cur_bytes)) {
|
||||
jump_ret = PatchShortConditionalJump(target + preamble_bytes, cur_bytes,
|
||||
preamble_stub + stub_bytes,
|
||||
&jump_bytes,
|
||||
stub_size - stub_bytes);
|
||||
} else if (IsShortJump(target + preamble_bytes, cur_bytes)) {
|
||||
jump_ret = PatchShortJump(target + preamble_bytes, cur_bytes,
|
||||
preamble_stub + stub_bytes,
|
||||
&jump_bytes,
|
||||
stub_size - stub_bytes);
|
||||
} else if (IsNearConditionalJump(target + preamble_bytes, cur_bytes) ||
|
||||
IsNearRelativeJump(target + preamble_bytes, cur_bytes) ||
|
||||
IsNearAbsoluteCall(target + preamble_bytes, cur_bytes) ||
|
||||
IsNearRelativeCall(target + preamble_bytes, cur_bytes)) {
|
||||
jump_ret = PatchNearJumpOrCall(target + preamble_bytes, cur_bytes,
|
||||
preamble_stub + stub_bytes, &jump_bytes,
|
||||
stub_size - stub_bytes);
|
||||
}
|
||||
if (jump_ret != SIDESTEP_SUCCESS) {
|
||||
SIDESTEP_ASSERT(false &&
|
||||
"Unable to patch because there is an unhandled branch "
|
||||
"instruction in the initial preamble bytes.");
|
||||
return SIDESTEP_JUMP_INSTRUCTION;
|
||||
}
|
||||
stub_bytes += jump_bytes;
|
||||
} else if (IT_RETURN == instruction_type) {
|
||||
SIDESTEP_ASSERT(false &&
|
||||
"Unable to patch because function is too short");
|
||||
return SIDESTEP_FUNCTION_TOO_SMALL;
|
||||
} else if (IT_GENERIC == instruction_type) {
|
||||
if (IsMovWithDisplacement(target + preamble_bytes, cur_bytes)) {
|
||||
unsigned int mov_bytes = 0;
|
||||
if (PatchMovWithDisplacement(target + preamble_bytes, cur_bytes,
|
||||
preamble_stub + stub_bytes, &mov_bytes,
|
||||
stub_size - stub_bytes)
|
||||
!= SIDESTEP_SUCCESS) {
|
||||
return SIDESTEP_UNSUPPORTED_INSTRUCTION;
|
||||
}
|
||||
stub_bytes += mov_bytes;
|
||||
} else {
|
||||
memcpy(reinterpret_cast<void*>(preamble_stub + stub_bytes),
|
||||
reinterpret_cast<void*>(target + preamble_bytes), cur_bytes);
|
||||
stub_bytes += cur_bytes;
|
||||
}
|
||||
} else {
|
||||
SIDESTEP_ASSERT(false &&
|
||||
"Disassembler encountered unsupported instruction "
|
||||
"(either unused or unknown");
|
||||
return SIDESTEP_UNSUPPORTED_INSTRUCTION;
|
||||
}
|
||||
preamble_bytes += cur_bytes;
|
||||
}
|
||||
|
||||
if (NULL != bytes_needed)
|
||||
*bytes_needed = stub_bytes + kRequiredStubJumpBytes
|
||||
+ required_trampoline_bytes;
|
||||
|
||||
// Inv: cbPreamble is the number of bytes (at least 5) that we need to take
|
||||
// from the preamble to have whole instructions that are 5 bytes or more
|
||||
// in size total. The size of the stub required is cbPreamble +
|
||||
// kRequiredStubJumpBytes (5) + required_trampoline_bytes (0 or 13)
|
||||
if (stub_bytes + kRequiredStubJumpBytes + required_trampoline_bytes
|
||||
> stub_size) {
|
||||
SIDESTEP_ASSERT(false);
|
||||
return SIDESTEP_INSUFFICIENT_BUFFER;
|
||||
}
|
||||
|
||||
// Now, make a jmp instruction to the rest of the target function (minus the
|
||||
// preamble bytes we moved into the stub) and copy it into our preamble-stub.
|
||||
// find address to jump to, relative to next address after jmp instruction
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4244)
|
||||
#endif
|
||||
int relative_offset_to_target_rest
|
||||
= ((reinterpret_cast<unsigned char*>(target) + preamble_bytes) -
|
||||
(preamble_stub + stub_bytes + kRequiredStubJumpBytes));
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
// jmp (Jump near, relative, displacement relative to next instruction)
|
||||
preamble_stub[stub_bytes] = ASM_JMP32REL;
|
||||
// copy the address
|
||||
memcpy(reinterpret_cast<void*>(preamble_stub + stub_bytes + 1),
|
||||
reinterpret_cast<void*>(&relative_offset_to_target_rest), 4);
|
||||
|
||||
if (kIs64BitBinary && required_trampoline_bytes != 0) {
|
||||
// Construct the trampoline
|
||||
unsigned int trampoline_pos = stub_bytes + kRequiredStubJumpBytes;
|
||||
preamble_stub[trampoline_pos] = ASM_NOP;
|
||||
preamble_stub[trampoline_pos + 1] = ASM_REXW;
|
||||
preamble_stub[trampoline_pos + 2] = ASM_MOVRAX_IMM;
|
||||
memcpy(reinterpret_cast<void*>(preamble_stub + trampoline_pos + 3),
|
||||
reinterpret_cast<void*>(&replacement_function),
|
||||
sizeof(void *));
|
||||
preamble_stub[trampoline_pos + 11] = ASM_JMP;
|
||||
preamble_stub[trampoline_pos + 12] = ASM_JMP_RAX;
|
||||
|
||||
// Now update replacement_function to point to the trampoline
|
||||
replacement_function = preamble_stub + trampoline_pos;
|
||||
}
|
||||
|
||||
// Inv: preamble_stub points to assembly code that will execute the
|
||||
// original function by first executing the first cbPreamble bytes of the
|
||||
// preamble, then jumping to the rest of the function.
|
||||
|
||||
// Overwrite the first 5 bytes of the target function with a jump to our
|
||||
// replacement function.
|
||||
// (Jump near, relative, displacement relative to next instruction)
|
||||
target[0] = ASM_JMP32REL;
|
||||
|
||||
// Find offset from instruction after jmp, to the replacement function.
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4244)
|
||||
#endif
|
||||
int offset_to_replacement_function =
|
||||
reinterpret_cast<unsigned char*>(replacement_function) -
|
||||
reinterpret_cast<unsigned char*>(target) - 5;
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
// complete the jmp instruction
|
||||
memcpy(reinterpret_cast<void*>(target + 1),
|
||||
reinterpret_cast<void*>(&offset_to_replacement_function), 4);
|
||||
|
||||
// Set any remaining bytes that were moved to the preamble-stub to INT3 so
|
||||
// as not to cause confusion (otherwise you might see some strange
|
||||
// instructions if you look at the disassembly, or even invalid
|
||||
// instructions). Also, by doing this, we will break into the debugger if
|
||||
// some code calls into this portion of the code. If this happens, it
|
||||
// means that this function cannot be patched using this patcher without
|
||||
// further thought.
|
||||
if (preamble_bytes > kRequiredTargetPatchBytes) {
|
||||
memset(reinterpret_cast<void*>(target + kRequiredTargetPatchBytes),
|
||||
ASM_INT3, preamble_bytes - kRequiredTargetPatchBytes);
|
||||
}
|
||||
|
||||
// Inv: The memory pointed to by target_function now points to a relative
|
||||
// jump instruction that jumps over to the preamble_stub. The preamble
|
||||
// stub contains the first stub_size bytes of the original target
|
||||
// function's preamble code, followed by a relative jump back to the next
|
||||
// instruction after the first cbPreamble bytes.
|
||||
//
|
||||
// In 64-bit mode the memory pointed to by target_function *may* point to a
|
||||
// relative jump instruction that jumps to a trampoline which will then
|
||||
// perform an absolute jump to the replacement function. The preamble stub
|
||||
// still contains the original target function's preamble code, followed by a
|
||||
// jump back to the instructions after the first preamble bytes.
|
||||
//
|
||||
return SIDESTEP_SUCCESS;
|
||||
}
|
||||
|
||||
}; // namespace sidestep
|
169
trunk/3rdparty/gperftools-2-fit/src/windows/shortproc.asm
vendored
Normal file
169
trunk/3rdparty/gperftools-2-fit/src/windows/shortproc.asm
vendored
Normal file
|
@ -0,0 +1,169 @@
|
|||
; Copyright (c) 2011, Google Inc.
|
||||
; All rights reserved.
|
||||
;
|
||||
; Redistribution and use in source and binary forms, with or without
|
||||
; modification, are permitted provided that the following conditions are
|
||||
; met:
|
||||
;
|
||||
; * Redistributions of source code must retain the above copyright
|
||||
; notice, this list of conditions and the following disclaimer.
|
||||
; * Redistributions in binary form must reproduce the above
|
||||
; copyright notice, this list of conditions and the following disclaimer
|
||||
; in the documentation and/or other materials provided with the
|
||||
; distribution.
|
||||
; * Neither the name of Google Inc. nor the names of its
|
||||
; contributors may be used to endorse or promote products derived from
|
||||
; this software without specific prior written permission.
|
||||
;
|
||||
; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
; "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
; LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
; A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
; OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
; SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
; LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
; DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
; THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
; OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
;
|
||||
; ---
|
||||
; Author: Scott Francis
|
||||
;
|
||||
; Unit tests for PreamblePatcher
|
||||
|
||||
.MODEL small
|
||||
|
||||
.CODE
|
||||
|
||||
TooShortFunction PROC
|
||||
ret
|
||||
TooShortFunction ENDP
|
||||
|
||||
JumpShortCondFunction PROC
|
||||
test cl, 1
|
||||
jnz jumpspot
|
||||
int 3
|
||||
int 3
|
||||
int 3
|
||||
int 3
|
||||
int 3
|
||||
int 3
|
||||
int 3
|
||||
int 3
|
||||
int 3
|
||||
int 3
|
||||
int 3
|
||||
int 3
|
||||
int 3
|
||||
int 3
|
||||
int 3
|
||||
int 3
|
||||
int 3
|
||||
int 3
|
||||
int 3
|
||||
int 3
|
||||
int 3
|
||||
int 3
|
||||
int 3
|
||||
int 3
|
||||
int 3
|
||||
int 3
|
||||
int 3
|
||||
int 3
|
||||
jumpspot:
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
mov rax, 1
|
||||
ret
|
||||
JumpShortCondFunction ENDP
|
||||
|
||||
JumpNearCondFunction PROC
|
||||
test cl, 1
|
||||
jnz jumpspot
|
||||
mov rdx, 0ffff1111H
|
||||
mov rdx, 0ffff1111H
|
||||
mov rdx, 0ffff1111H
|
||||
mov rdx, 0ffff1111H
|
||||
mov rdx, 0ffff1111H
|
||||
mov rdx, 0ffff1111H
|
||||
mov rdx, 0ffff1111H
|
||||
mov rdx, 0ffff1111H
|
||||
mov rdx, 0ffff1111H
|
||||
mov rdx, 0ffff1111H
|
||||
mov rdx, 0ffff1111H
|
||||
mov rdx, 0ffff1111H
|
||||
mov rdx, 0ffff1111H
|
||||
mov rdx, 0ffff1111H
|
||||
mov rdx, 0ffff1111H
|
||||
mov rdx, 0ffff1111H
|
||||
mov rdx, 0ffff1111H
|
||||
mov rdx, 0ffff1111H
|
||||
mov rdx, 0ffff1111H
|
||||
mov rdx, 0ffff1111H
|
||||
jumpspot:
|
||||
nop
|
||||
nop
|
||||
mov rax, 1
|
||||
ret
|
||||
JumpNearCondFunction ENDP
|
||||
|
||||
JumpAbsoluteFunction PROC
|
||||
test cl, 1
|
||||
jmp jumpspot
|
||||
mov rdx, 0ffff1111H
|
||||
mov rdx, 0ffff1111H
|
||||
mov rdx, 0ffff1111H
|
||||
mov rdx, 0ffff1111H
|
||||
mov rdx, 0ffff1111H
|
||||
mov rdx, 0ffff1111H
|
||||
mov rdx, 0ffff1111H
|
||||
mov rdx, 0ffff1111H
|
||||
mov rdx, 0ffff1111H
|
||||
mov rdx, 0ffff1111H
|
||||
mov rdx, 0ffff1111H
|
||||
mov rdx, 0ffff1111H
|
||||
mov rdx, 0ffff1111H
|
||||
mov rdx, 0ffff1111H
|
||||
mov rdx, 0ffff1111H
|
||||
mov rdx, 0ffff1111H
|
||||
mov rdx, 0ffff1111H
|
||||
mov rdx, 0ffff1111H
|
||||
mov rdx, 0ffff1111H
|
||||
mov rdx, 0ffff1111H
|
||||
mov rdx, 0ffff1111H
|
||||
mov rdx, 0ffff1111H
|
||||
mov rdx, 0ffff1111H
|
||||
mov rdx, 0ffff1111H
|
||||
mov rdx, 0ffff1111H
|
||||
mov rdx, 0ffff1111H
|
||||
mov rdx, 0ffff1111H
|
||||
jumpspot:
|
||||
nop
|
||||
nop
|
||||
mov rax, 1
|
||||
ret
|
||||
JumpAbsoluteFunction ENDP
|
||||
|
||||
CallNearRelativeFunction PROC
|
||||
test cl, 1
|
||||
call TooShortFunction
|
||||
mov rdx, 0ffff1111H
|
||||
mov rdx, 0ffff1111H
|
||||
mov rdx, 0ffff1111H
|
||||
mov rdx, 0ffff1111H
|
||||
mov rdx, 0ffff1111H
|
||||
mov rdx, 0ffff1111H
|
||||
mov rdx, 0ffff1111H
|
||||
mov rdx, 0ffff1111H
|
||||
mov rdx, 0ffff1111H
|
||||
mov rdx, 0ffff1111H
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
ret
|
||||
CallNearRelativeFunction ENDP
|
||||
|
||||
END
|
205
trunk/3rdparty/gperftools-2-fit/src/windows/system-alloc.cc
vendored
Normal file
205
trunk/3rdparty/gperftools-2-fit/src/windows/system-alloc.cc
vendored
Normal file
|
@ -0,0 +1,205 @@
|
|||
// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
|
||||
// Copyright (c) 2013, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// ---
|
||||
// Author: Petr Hosek
|
||||
|
||||
#ifndef _WIN32
|
||||
# error You should only be including windows/system-alloc.cc in a windows environment!
|
||||
#endif
|
||||
|
||||
#include <config.h>
|
||||
#include <windows.h>
|
||||
#include <algorithm> // std::min
|
||||
#include <gperftools/malloc_extension.h>
|
||||
#include "base/logging.h"
|
||||
#include "base/spinlock.h"
|
||||
#include "internal_logging.h"
|
||||
#include "system-alloc.h"
|
||||
|
||||
static SpinLock spinlock(SpinLock::LINKER_INITIALIZED);
|
||||
|
||||
// The current system allocator declaration
|
||||
SysAllocator* tcmalloc_sys_alloc = NULL;
|
||||
// Number of bytes taken from system.
|
||||
size_t TCMalloc_SystemTaken = 0;
|
||||
|
||||
class VirtualSysAllocator : public SysAllocator {
|
||||
public:
|
||||
VirtualSysAllocator() : SysAllocator() {
|
||||
}
|
||||
void* Alloc(size_t size, size_t *actual_size, size_t alignment);
|
||||
};
|
||||
static char virtual_space[sizeof(VirtualSysAllocator)];
|
||||
|
||||
// This is mostly like MmapSysAllocator::Alloc, except it does these weird
|
||||
// munmap's in the middle of the page, which is forbidden in windows.
|
||||
void* VirtualSysAllocator::Alloc(size_t size, size_t *actual_size,
|
||||
size_t alignment) {
|
||||
// Align on the pagesize boundary
|
||||
const int pagesize = getpagesize();
|
||||
if (alignment < pagesize) alignment = pagesize;
|
||||
size = ((size + alignment - 1) / alignment) * alignment;
|
||||
|
||||
// Report the total number of bytes the OS actually delivered. This might be
|
||||
// greater than |size| because of alignment concerns. The full size is
|
||||
// necessary so that adjacent spans can be coalesced.
|
||||
// TODO(antonm): proper processing of alignments
|
||||
// in actual_size and decommitting.
|
||||
if (actual_size) {
|
||||
*actual_size = size;
|
||||
}
|
||||
|
||||
// We currently do not support alignments larger than the pagesize or
|
||||
// alignments that are not multiples of the pagesize after being floored.
|
||||
// If this ability is needed it can be done by the caller (assuming it knows
|
||||
// the page size).
|
||||
assert(alignment <= pagesize);
|
||||
|
||||
void* result = VirtualAlloc(0, size,
|
||||
MEM_COMMIT|MEM_RESERVE, PAGE_READWRITE);
|
||||
if (result == NULL)
|
||||
return NULL;
|
||||
|
||||
// If the result is not aligned memory fragmentation will result which can
|
||||
// lead to pathological memory use.
|
||||
assert((reinterpret_cast<uintptr_t>(result) & (alignment - 1)) == 0);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
|
||||
extern "C" SysAllocator* tc_get_sysalloc_override(SysAllocator *def);
|
||||
extern "C" SysAllocator* tc_get_sysalloc_default(SysAllocator *def)
|
||||
{
|
||||
return def;
|
||||
}
|
||||
|
||||
#if defined(_M_IX86)
|
||||
#pragma comment(linker, "/alternatename:_tc_get_sysalloc_override=_tc_get_sysalloc_default")
|
||||
#elif defined(_M_X64)
|
||||
#pragma comment(linker, "/alternatename:tc_get_sysalloc_override=tc_get_sysalloc_default")
|
||||
#endif
|
||||
|
||||
#else // !_MSC_VER
|
||||
|
||||
extern "C" ATTRIBUTE_NOINLINE
|
||||
SysAllocator* tc_get_sysalloc_override(SysAllocator *def)
|
||||
{
|
||||
return def;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static bool system_alloc_inited = false;
|
||||
void InitSystemAllocators(void) {
|
||||
VirtualSysAllocator *alloc = new (virtual_space) VirtualSysAllocator();
|
||||
tcmalloc_sys_alloc = tc_get_sysalloc_override(alloc);
|
||||
}
|
||||
|
||||
extern PERFTOOLS_DLL_DECL
|
||||
void* TCMalloc_SystemAlloc(size_t size, size_t *actual_size,
|
||||
size_t alignment) {
|
||||
SpinLockHolder lock_holder(&spinlock);
|
||||
|
||||
if (!system_alloc_inited) {
|
||||
InitSystemAllocators();
|
||||
system_alloc_inited = true;
|
||||
}
|
||||
|
||||
void* result = tcmalloc_sys_alloc->Alloc(size, actual_size, alignment);
|
||||
if (result != NULL) {
|
||||
if (actual_size) {
|
||||
TCMalloc_SystemTaken += *actual_size;
|
||||
} else {
|
||||
TCMalloc_SystemTaken += size;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
extern PERFTOOLS_DLL_DECL
|
||||
bool TCMalloc_SystemRelease(void* start, size_t length) {
|
||||
if (VirtualFree(start, length, MEM_DECOMMIT))
|
||||
return true;
|
||||
|
||||
// The decommit may fail if the memory region consists of allocations
|
||||
// from more than one call to VirtualAlloc. In this case, fall back to
|
||||
// using VirtualQuery to retrieve the allocation boundaries and decommit
|
||||
// them each individually.
|
||||
|
||||
char* ptr = static_cast<char*>(start);
|
||||
char* end = ptr + length;
|
||||
MEMORY_BASIC_INFORMATION info;
|
||||
while (ptr < end) {
|
||||
size_t resultSize = VirtualQuery(ptr, &info, sizeof(info));
|
||||
assert(resultSize == sizeof(info));
|
||||
size_t decommitSize = std::min<size_t>(info.RegionSize, end - ptr);
|
||||
BOOL success = VirtualFree(ptr, decommitSize, MEM_DECOMMIT);
|
||||
assert(success == TRUE);
|
||||
ptr += decommitSize;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
extern PERFTOOLS_DLL_DECL
|
||||
void TCMalloc_SystemCommit(void* start, size_t length) {
|
||||
if (VirtualAlloc(start, length, MEM_COMMIT, PAGE_READWRITE) == start)
|
||||
return;
|
||||
|
||||
// The commit may fail if the memory region consists of allocations
|
||||
// from more than one call to VirtualAlloc. In this case, fall back to
|
||||
// using VirtualQuery to retrieve the allocation boundaries and commit them
|
||||
// each individually.
|
||||
|
||||
char* ptr = static_cast<char*>(start);
|
||||
char* end = ptr + length;
|
||||
MEMORY_BASIC_INFORMATION info;
|
||||
while (ptr < end) {
|
||||
size_t resultSize = VirtualQuery(ptr, &info, sizeof(info));
|
||||
assert(resultSize == sizeof(info));
|
||||
|
||||
size_t commitSize = std::min<size_t>(info.RegionSize, end - ptr);
|
||||
void* newAddress = VirtualAlloc(ptr, commitSize, MEM_COMMIT,
|
||||
PAGE_READWRITE);
|
||||
assert(newAddress == ptr);
|
||||
ptr += commitSize;
|
||||
}
|
||||
}
|
||||
|
||||
bool RegisterSystemAllocator(SysAllocator *allocator, int priority) {
|
||||
return false; // we don't allow registration on windows, right now
|
||||
}
|
||||
|
||||
void DumpSystemAllocatorStats(TCMalloc_Printer* printer) {
|
||||
// We don't dump stats on windows, right now
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue