Squashed 'third_party/gperftools/' content from commit 54505f1

Change-Id: Id02e833828732b0efe7dac722b8485279e67c5fa
git-subtree-dir: third_party/gperftools
git-subtree-split: 54505f1d50c2d1f4676f5e87090b64a117fd980e
diff --git a/src/windows/TODO b/src/windows/TODO
new file mode 100644
index 0000000..708ec23
--- /dev/null
+++ b/src/windows/TODO
@@ -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=
diff --git a/src/windows/addr2line-pdb.c b/src/windows/addr2line-pdb.c
new file mode 100644
index 0000000..5c65a03
--- /dev/null
+++ b/src/windows/addr2line-pdb.c
@@ -0,0 +1,163 @@
+/* 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 <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 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], "-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 : %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;
+  }
+
+  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 addr = _strtoui64(buf, NULL, 16);
+    ULONG64 buffer[(sizeof(SYMBOL_INFO) +
+                    MAX_SYM_NAME*sizeof(TCHAR) +
+                    sizeof(ULONG64) - 1)
+                   / sizeof(ULONG64)];
+    PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)buffer;
+    IMAGEHLP_LINE64 line;
+    DWORD dummy;
+    pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO);
+    pSymbol->MaxNameLen = MAX_SYM_NAME;
+    if (print_function_name) {
+      if (SymFromAddr(process, (DWORD64)addr, NULL, pSymbol)) {
+        printf("%s\n", pSymbol->Name);
+      } else {
+        printf("??\n");
+      }
+    }
+    line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
+    if (SymGetLineFromAddr64(process, (DWORD64)addr, &dummy, &line)) {
+      printf("%s:%d\n", line.FileName, (int)line.LineNumber);
+    } else {
+      printf("??:0\n");
+    }
+  }
+  SymUnloadModule64(process, module_base);
+  SymCleanup(process);
+  return rv;
+}
diff --git a/src/windows/auto_testing_hook.h b/src/windows/auto_testing_hook.h
new file mode 100644
index 0000000..fc2b710
--- /dev/null
+++ b/src/windows/auto_testing_hook.h
@@ -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_
diff --git a/src/windows/config.h b/src/windows/config.h
new file mode 100644
index 0000000..9976457
--- /dev/null
+++ b/src/windows/config.h
@@ -0,0 +1,310 @@
+/* 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_
+
+/* define this if you are linking tcmalloc statically and overriding the
+ * default allocators.
+ * For instructions on how to use this mode, see
+ * http://groups.google.com/group/google-perftools/browse_thread/thread/41cd3710af85e57b
+ */
+#undef WIN32_OVERRIDE_ALLOCATORS
+
+/* Define to 1 if your libc has a snprintf implementation */
+#undef HAVE_SNPRINTF
+
+/* Define to 1 if compiler supports __builtin_stack_pointer */
+#undef HAVE_BUILTIN_STACK_POINTER
+
+/* Define to 1 if you have the <conflict-signal.h> header file. */
+#undef HAVE_CONFLICT_SIGNAL_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 `cfree', and to 0 if you don't.
+   */
+#undef HAVE_DECL_CFREE
+
+/* Define to 1 if you have the declaration of `memalign', and to 0 if you
+   don't. */
+#undef HAVE_DECL_MEMALIGN
+
+/* Define to 1 if you have the declaration of `posix_memalign', and to 0 if
+   you don't. */
+#undef HAVE_DECL_POSIX_MEMALIGN
+
+/* Define to 1 if you have the declaration of `pvalloc', and to 0 if you
+   don't. */
+#undef HAVE_DECL_PVALLOC
+
+/* Define to 1 if you have the declaration of `uname', and to 0 if you don't.
+   */
+#undef HAVE_DECL_UNAME
+
+/* Define to 1 if you have the declaration of `valloc', and to 0 if you don't.
+   */
+#undef HAVE_DECL_VALLOC
+
+/* 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. */
+#undef HAVE_FCNTL_H
+
+/* Define to 1 if you have the <features.h> header file. */
+#undef HAVE_FEATURES_H
+
+/* Define to 1 if you have the `geteuid' function. */
+#undef HAVE_GETEUID
+
+/* Define to 1 if you have the `getpagesize' function. */
+#define HAVE_GETPAGESIZE 1   /* we define it in windows/port.cc */
+
+/* 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. */
+#undef HAVE_INTTYPES_H
+
+/* 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 to 1 if you have the <malloc.h> header file. */
+#define HAVE_MALLOC_H 1
+
+/* Define to 1 if you have the <malloc/malloc.h> header file. */
+#undef HAVE_MALLOC_MALLOC_H
+
+/* Define to 1 if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* Define to 1 if you have a working `mmap' system call. */
+#undef HAVE_MMAP
+
+/* define if the compiler implements namespaces */
+#define HAVE_NAMESPACES 1
+
+/* 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
+
+/* 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. */
+#undef HAVE_STDINT_H
+
+/* 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/malloc.h> header file. */
+#undef HAVE_SYS_MALLOC_H
+
+/* Define to 1 if you have the <sys/param.h> header file. */
+#undef HAVE_SYS_PARAM_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
+
+/* <sys/ucontext.h> is broken on redhat 7 */
+#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
+
+/* Define to 1 if you have the <unwind.h> header file. */
+#undef HAVE_UNWIND_H
+
+/* Define to 1 if you have the <valgrind.h> header file. */
+#undef HAVE_VALGRIND_H
+
+/* define if your compiler has __attribute__ */
+#undef HAVE___ATTRIBUTE__
+
+/* Define to 1 if compiler supports __environ */
+#undef HAVE___ENVIRON
+
+/* Define to 1 if the system has the type `__int64'. */
+#define HAVE___INT64 1
+
+/* prefix where we look for installed files */
+#undef INSTALL_PREFIX
+
+/* Define to 1 if int32_t is equivalent to intptr_t */
+#undef INT32_EQUALS_INTPTR
+
+/* Define to the sub-directory in which libtool stores uninstalled libraries.
+   */
+#undef LT_OBJDIR
+
+/* Define to 'volatile' if __malloc_hook is declared volatile */
+#undef MALLOC_HOOK_MAYBE_VOLATILE
+
+/* Define to 1 if your C compiler doesn't accept -c and -o together. */
+#undef NO_MINUS_C_MINUS_O
+
+/* Name of package */
+#define PACKAGE "gperftools"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT "opensource@google.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.4"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "gperftools"
+
+/* Define to the home page for this package. */
+#undef PACKAGE_URL
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "2.4"
+
+/* 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
+
+/* printf format code for printing a size_t and ssize_t */
+#define PRIdS  "Id"
+
+/* printf format code for printing a size_t and ssize_t */
+#define PRIuS  "Iu"
+
+/* printf format code for printing a size_t and ssize_t */
+#define PRIxS  "Ix"
+
+/* 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
+
+/* the namespace where STL code like vector<> is defined */
+#define STL_NAMESPACE  std
+
+/* Version number of package */
+#undef VERSION
+
+/* C99 says: define this to get the PRI... macros from stdint.h */
+#ifndef __STDC_FORMAT_MACROS
+# define __STDC_FORMAT_MACROS 1
+#endif
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+   calls it, or to nothing if 'inline' is not supported under any name.  */
+#ifndef __cplusplus
+#undef inline
+#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_ */
diff --git a/src/windows/get_mangled_names.cc b/src/windows/get_mangled_names.cc
new file mode 100644
index 0000000..08bd03b
--- /dev/null
+++ b/src/windows/get_mangled_names.cc
@@ -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() { }
diff --git a/src/windows/google/tcmalloc.h b/src/windows/google/tcmalloc.h
new file mode 100644
index 0000000..c7db631
--- /dev/null
+++ b/src/windows/google/tcmalloc.h
@@ -0,0 +1,34 @@
+/* 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.
+ */
+
+/* The code has moved to gperftools/.  Use that include-directory for
+ * new code.
+ */
+#include <gperftools/tcmalloc.h>
diff --git a/src/windows/gperftools/tcmalloc.h b/src/windows/gperftools/tcmalloc.h
new file mode 100644
index 0000000..9ba79a9
--- /dev/null
+++ b/src/windows/gperftools/tcmalloc.h
@@ -0,0 +1,125 @@
+// -*- 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.in file by Craig Silverstein <opensource@google.com>
+ */
+
+#ifndef TCMALLOC_TCMALLOC_H_
+#define TCMALLOC_TCMALLOC_H_
+
+#include <stddef.h>                     // for size_t
+#ifdef HAVE_SYS_CDEFS_H
+#include <sys/cdefs.h>   // where glibc defines __THROW
+#endif
+
+// __THROW is defined in glibc systems.  It means, counter-intuitively,
+// "This function will never throw an exception."  It's an optional
+// optimization tool, but we may need to use it to match glibc prototypes.
+#ifndef __THROW    /* I guess we're not on a glibc system */
+# define __THROW   /* __THROW is just an optimization, so ok to make it "" */
+#endif
+
+// Define the version number so folks can check against it
+#define TC_VERSION_MAJOR  2
+#define TC_VERSION_MINOR  4
+#define TC_VERSION_PATCH  ""
+#define TC_VERSION_STRING "gperftools 2.4"
+
+#include <stdlib.h>   // for struct mallinfo, if it's defined
+
+// Annoying stuff for windows -- makes sure clients can import these functions
+#ifndef PERFTOOLS_DLL_DECL
+# ifdef _WIN32
+#   define PERFTOOLS_DLL_DECL  __declspec(dllimport)
+# else
+#   define PERFTOOLS_DLL_DECL
+# endif
+#endif
+
+#ifdef __cplusplus
+namespace std {
+struct nothrow_t;
+}
+
+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) __THROW;
+
+  PERFTOOLS_DLL_DECL void* tc_malloc(size_t size) __THROW;
+  PERFTOOLS_DLL_DECL void* tc_malloc_skip_new_handler(size_t size) __THROW;
+  PERFTOOLS_DLL_DECL void tc_free(void* ptr) __THROW;
+  PERFTOOLS_DLL_DECL void* tc_realloc(void* ptr, size_t size) __THROW;
+  PERFTOOLS_DLL_DECL void* tc_calloc(size_t nmemb, size_t size) __THROW;
+  PERFTOOLS_DLL_DECL void tc_cfree(void* ptr) __THROW;
+
+  PERFTOOLS_DLL_DECL void* tc_memalign(size_t __alignment,
+                                       size_t __size) __THROW;
+  PERFTOOLS_DLL_DECL int tc_posix_memalign(void** ptr,
+                                           size_t align, size_t size) __THROW;
+  PERFTOOLS_DLL_DECL void* tc_valloc(size_t __size) __THROW;
+  PERFTOOLS_DLL_DECL void* tc_pvalloc(size_t __size) __THROW;
+
+  PERFTOOLS_DLL_DECL void tc_malloc_stats(void) __THROW;
+  PERFTOOLS_DLL_DECL int tc_mallopt(int cmd, int value) __THROW;
+#if 0
+  PERFTOOLS_DLL_DECL struct mallinfo tc_mallinfo(void) __THROW;
+#endif
+
+  // 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) __THROW;
+
+#ifdef __cplusplus
+  PERFTOOLS_DLL_DECL int tc_set_new_mode(int flag) __THROW;
+  PERFTOOLS_DLL_DECL void* tc_new(size_t size);
+  PERFTOOLS_DLL_DECL void* tc_new_nothrow(size_t size,
+                                          const std::nothrow_t&) __THROW;
+  PERFTOOLS_DLL_DECL void tc_delete(void* p) __THROW;
+  PERFTOOLS_DLL_DECL void tc_delete_nothrow(void* p,
+                                            const std::nothrow_t&) __THROW;
+  PERFTOOLS_DLL_DECL void* tc_newarray(size_t size);
+  PERFTOOLS_DLL_DECL void* tc_newarray_nothrow(size_t size,
+                                               const std::nothrow_t&) __THROW;
+  PERFTOOLS_DLL_DECL void tc_deletearray(void* p) __THROW;
+  PERFTOOLS_DLL_DECL void tc_deletearray_nothrow(void* p,
+                                                 const std::nothrow_t&) __THROW;
+}
+#endif
+
+#endif  // #ifndef TCMALLOC_TCMALLOC_H_
diff --git a/src/windows/gperftools/tcmalloc.h.in b/src/windows/gperftools/tcmalloc.h.in
new file mode 100644
index 0000000..7458de1
--- /dev/null
+++ b/src/windows/gperftools/tcmalloc.h.in
@@ -0,0 +1,125 @@
+// -*- 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.in file by Craig Silverstein <opensource@google.com>
+ */
+
+#ifndef TCMALLOC_TCMALLOC_H_
+#define TCMALLOC_TCMALLOC_H_
+
+#include <stddef.h>                     // for size_t
+#ifdef HAVE_SYS_CDEFS_H
+#include <sys/cdefs.h>   // where glibc defines __THROW
+#endif
+
+// __THROW is defined in glibc systems.  It means, counter-intuitively,
+// "This function will never throw an exception."  It's an optional
+// optimization tool, but we may need to use it to match glibc prototypes.
+#ifndef __THROW    /* I guess we're not on a glibc system */
+# define __THROW   /* __THROW is just an optimization, so ok to make it "" */
+#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@"
+
+#include <stdlib.h>   // for struct mallinfo, if it's defined
+
+// Annoying stuff for windows -- makes sure clients can import these functions
+#ifndef PERFTOOLS_DLL_DECL
+# ifdef _WIN32
+#   define PERFTOOLS_DLL_DECL  __declspec(dllimport)
+# else
+#   define PERFTOOLS_DLL_DECL
+# endif
+#endif
+
+#ifdef __cplusplus
+namespace std {
+struct nothrow_t;
+}
+
+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) __THROW;
+
+  PERFTOOLS_DLL_DECL void* tc_malloc(size_t size) __THROW;
+  PERFTOOLS_DLL_DECL void* tc_malloc_skip_new_handler(size_t size) __THROW;
+  PERFTOOLS_DLL_DECL void tc_free(void* ptr) __THROW;
+  PERFTOOLS_DLL_DECL void* tc_realloc(void* ptr, size_t size) __THROW;
+  PERFTOOLS_DLL_DECL void* tc_calloc(size_t nmemb, size_t size) __THROW;
+  PERFTOOLS_DLL_DECL void tc_cfree(void* ptr) __THROW;
+
+  PERFTOOLS_DLL_DECL void* tc_memalign(size_t __alignment,
+                                       size_t __size) __THROW;
+  PERFTOOLS_DLL_DECL int tc_posix_memalign(void** ptr,
+                                           size_t align, size_t size) __THROW;
+  PERFTOOLS_DLL_DECL void* tc_valloc(size_t __size) __THROW;
+  PERFTOOLS_DLL_DECL void* tc_pvalloc(size_t __size) __THROW;
+
+  PERFTOOLS_DLL_DECL void tc_malloc_stats(void) __THROW;
+  PERFTOOLS_DLL_DECL int tc_mallopt(int cmd, int value) __THROW;
+#if 0
+  PERFTOOLS_DLL_DECL struct mallinfo tc_mallinfo(void) __THROW;
+#endif
+
+  // 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) __THROW;
+
+#ifdef __cplusplus
+  PERFTOOLS_DLL_DECL int tc_set_new_mode(int flag) __THROW;
+  PERFTOOLS_DLL_DECL void* tc_new(size_t size);
+  PERFTOOLS_DLL_DECL void* tc_new_nothrow(size_t size,
+                                          const std::nothrow_t&) __THROW;
+  PERFTOOLS_DLL_DECL void tc_delete(void* p) __THROW;
+  PERFTOOLS_DLL_DECL void tc_delete_nothrow(void* p,
+                                            const std::nothrow_t&) __THROW;
+  PERFTOOLS_DLL_DECL void* tc_newarray(size_t size);
+  PERFTOOLS_DLL_DECL void* tc_newarray_nothrow(size_t size,
+                                               const std::nothrow_t&) __THROW;
+  PERFTOOLS_DLL_DECL void tc_deletearray(void* p) __THROW;
+  PERFTOOLS_DLL_DECL void tc_deletearray_nothrow(void* p,
+                                                 const std::nothrow_t&) __THROW;
+}
+#endif
+
+#endif  // #ifndef TCMALLOC_TCMALLOC_H_
diff --git a/src/windows/ia32_modrm_map.cc b/src/windows/ia32_modrm_map.cc
new file mode 100644
index 0000000..f1f1906
--- /dev/null
+++ b/src/windows/ia32_modrm_map.cc
@@ -0,0 +1,121 @@
+/* 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
diff --git a/src/windows/ia32_opcode_map.cc b/src/windows/ia32_opcode_map.cc
new file mode 100644
index 0000000..ba6a79e
--- /dev/null
+++ b/src/windows/ia32_opcode_map.cc
@@ -0,0 +1,1219 @@
+/* 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
+ *
+ * Opcode decoding maps.  Based on the IA-32 Intel® Architecture
+ * Software DeveloperÂ’s Manual Volume 2: Instruction Set Reference.  Idea
+ * for how to lay out the tables in memory taken from the implementation
+ * in the Bastard disassembly environment.
+ */
+
+#include "mini_disassembler.h"
+
+namespace sidestep {
+
+/*
+* This is the first table to be searched; the first field of each
+* Opcode in the table is either 0 to indicate you're in the
+* right table, or an index to the correct table, in the global
+* map g_pentiumOpcodeMap
+*/
+const Opcode s_first_opcode_byte[] = {
+  /* 0x0 */ { 0, IT_GENERIC, AM_E | OT_B, AM_G | OT_B, AM_NOT_USED, "add", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x1 */ { 0, IT_GENERIC, AM_E | OT_V, AM_G | OT_V, AM_NOT_USED, "add", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x2 */ { 0, IT_GENERIC, AM_G | OT_B, AM_E | OT_B, AM_NOT_USED, "add", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x3 */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "add", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x4 */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_I | OT_B, AM_NOT_USED, "add", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x5 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_I | OT_V, AM_NOT_USED, "add", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x6 */ { 0, IT_GENERIC, AM_REGISTER | OT_W, AM_NOT_USED, AM_NOT_USED, "push", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x7 */ { 0, IT_GENERIC, AM_REGISTER | OT_W, AM_NOT_USED, AM_NOT_USED, "pop", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x8 */ { 0, IT_GENERIC, AM_E | OT_B, AM_G | OT_B, AM_NOT_USED, "or", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x9 */ { 0, IT_GENERIC, AM_E | OT_V, AM_G | OT_V, AM_NOT_USED, "or", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xA */ { 0, IT_GENERIC, AM_G | OT_B, AM_E | OT_B, AM_NOT_USED, "or", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xB */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "or", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xC */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_I | OT_B, AM_NOT_USED, "or", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xD */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_I | OT_V, AM_NOT_USED, "or", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xE */ { 0, IT_GENERIC, AM_REGISTER | OT_W, AM_NOT_USED, AM_NOT_USED, "push", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xF */ { 1, IT_REFERENCE, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x10 */ { 0, IT_GENERIC, AM_E | OT_B, AM_G | OT_B, AM_NOT_USED, "adc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x11 */ { 0, IT_GENERIC, AM_E | OT_V, AM_G | OT_V, AM_NOT_USED, "adc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x12 */ { 0, IT_GENERIC, AM_G | OT_B, AM_E | OT_B, AM_NOT_USED, "adc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x13 */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "adc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x14 */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_I | OT_B, AM_NOT_USED, "adc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x15 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_I | OT_V, AM_NOT_USED, "adc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x16 */ { 0, IT_GENERIC, AM_REGISTER | OT_W, AM_NOT_USED, AM_NOT_USED, "push", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x17 */ { 0, IT_GENERIC, AM_REGISTER | OT_W, AM_NOT_USED, AM_NOT_USED, "pop", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x18 */ { 0, IT_GENERIC, AM_E | OT_B, AM_G | OT_B, AM_NOT_USED, "sbb", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x19 */ { 0, IT_GENERIC, AM_E | OT_V, AM_G | OT_V, AM_NOT_USED, "sbb", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x1A */ { 0, IT_GENERIC, AM_G | OT_B, AM_E | OT_B, AM_NOT_USED, "sbb", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x1B */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "sbb", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x1C */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_I | OT_B, AM_NOT_USED, "sbb", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x1D */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_I | OT_V, AM_NOT_USED, "sbb", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x1E */ { 0, IT_GENERIC, AM_REGISTER | OT_W, AM_NOT_USED, AM_NOT_USED, "push", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x1F */ { 0, IT_GENERIC, AM_REGISTER | OT_W, AM_NOT_USED, AM_NOT_USED, "pop", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x20 */ { 0, IT_GENERIC, AM_E | OT_B, AM_G | OT_B, AM_NOT_USED, "and", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x21 */ { 0, IT_GENERIC, AM_E | OT_V, AM_G | OT_V, AM_NOT_USED, "and", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x22 */ { 0, IT_GENERIC, AM_G | OT_B, AM_E | OT_B, AM_NOT_USED, "and", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x23 */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "and", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x24 */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_I | OT_B, AM_NOT_USED, "and", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x25 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_I | OT_V, AM_NOT_USED, "and", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x26 */ { 0, IT_PREFIX, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x27 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "daa", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x28 */ { 0, IT_GENERIC, AM_E | OT_B, AM_G | OT_B, AM_NOT_USED, "sub", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x29 */ { 0, IT_GENERIC, AM_E | OT_V, AM_G | OT_V, AM_NOT_USED, "sub", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x2A */ { 0, IT_GENERIC, AM_G | OT_B, AM_E | OT_B, AM_NOT_USED, "sub", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x2B */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "sub", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x2C */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_I | OT_B, AM_NOT_USED, "sub", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x2D */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_I | OT_V, AM_NOT_USED, "sub", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x2E */ { 0, IT_PREFIX, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x2F */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "das", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x30 */ { 0, IT_GENERIC, AM_E | OT_B, AM_G | OT_B, AM_NOT_USED, "xor", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x31 */ { 0, IT_GENERIC, AM_E | OT_V, AM_G | OT_V, AM_NOT_USED, "xor", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x32 */ { 0, IT_GENERIC, AM_G | OT_B, AM_E | OT_B, AM_NOT_USED, "xor", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x33 */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "xor", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x34 */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_I | OT_B, AM_NOT_USED, "xor", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x35 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_I | OT_V, AM_NOT_USED, "xor", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x36 */ { 0, IT_PREFIX, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x37 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "aaa", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x38 */ { 0, IT_GENERIC, AM_E | OT_B, AM_G | OT_B, AM_NOT_USED, "cmp", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x39 */ { 0, IT_GENERIC, AM_E | OT_V, AM_G | OT_V, AM_NOT_USED, "cmp", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x3A */ { 0, IT_GENERIC, AM_G | OT_B, AM_E | OT_B, AM_NOT_USED, "cmp", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x3B */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "cmp", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x3C */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_I | OT_B, AM_NOT_USED, "cmp", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x3D */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_I | OT_V, AM_NOT_USED, "cmp", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x3E */ { 0, IT_PREFIX, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x3F */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "aas", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+#ifdef _M_X64
+  /* REX Prefixes in 64-bit mode. */
+  /* 0x40 */ { 0, IT_PREFIX, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x41 */ { 0, IT_PREFIX, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x42 */ { 0, IT_PREFIX, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x43 */ { 0, IT_PREFIX, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x44 */ { 0, IT_PREFIX, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x45 */ { 0, IT_PREFIX, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x46 */ { 0, IT_PREFIX, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x47 */ { 0, IT_PREFIX, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x48 */ { 0, IT_PREFIX, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x49 */ { 0, IT_PREFIX, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x4A */ { 0, IT_PREFIX, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x4B */ { 0, IT_PREFIX, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x4C */ { 0, IT_PREFIX, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x4D */ { 0, IT_PREFIX, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x4E */ { 0, IT_PREFIX, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x4F */ { 0, IT_PREFIX, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+#else
+  /* 0x40 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "inc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x41 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "inc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x42 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "inc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x43 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "inc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x44 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "inc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x45 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "inc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x46 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "inc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x47 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "inc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x48 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "dec", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x49 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "dec", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x4A */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "dec", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x4B */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "dec", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x4C */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "dec", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x4D */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "dec", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x4E */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "dec", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x4F */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "dec", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+#endif
+  /* 0x50 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "push", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x51 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "push", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x52 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "push", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x53 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "push", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x54 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "push", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x55 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "push", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x56 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "push", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x57 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "push", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x58 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "pop", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x59 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "pop", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x5A */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "pop", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x5B */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "pop", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x5C */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "pop", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x5D */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "pop", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x5E */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "pop", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x5F */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_NOT_USED, AM_NOT_USED, "pop", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x60 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "pushad", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x61 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "popad", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x62 */ { 0, IT_GENERIC, AM_G | OT_V, AM_M | OT_A, AM_NOT_USED, "bound", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x63 */ { 0, IT_GENERIC, AM_E | OT_W, AM_G | OT_W, AM_NOT_USED, "arpl", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x64 */ { 0, IT_PREFIX, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x65 */ { 0, IT_PREFIX, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x66 */ { 0, IT_PREFIX_OPERAND, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x67 */ { 0, IT_PREFIX_ADDRESS, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x68 */ { 0, IT_GENERIC, AM_I | OT_V, AM_NOT_USED, AM_NOT_USED, "push", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x69 */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_I | OT_V, "imul", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x6A */ { 0, IT_GENERIC, AM_I | OT_B, AM_NOT_USED, AM_NOT_USED, "push", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x6B */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_I |  OT_B, "imul", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x6C */ { 0, IT_GENERIC, AM_Y | OT_B, AM_REGISTER | OT_B, AM_NOT_USED, "insb", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x6D */ { 0, IT_GENERIC, AM_Y | OT_V, AM_REGISTER | OT_V, AM_NOT_USED, "insd", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x6E */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_X | OT_B, AM_NOT_USED, "outsb", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x6F */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_X | OT_V, AM_NOT_USED, "outsb", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x70 */ { 0, IT_JUMP, AM_J | OT_B, AM_NOT_USED, AM_NOT_USED, "jo", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x71 */ { 0, IT_JUMP, AM_J | OT_B, AM_NOT_USED, AM_NOT_USED, "jno", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x72 */ { 0, IT_JUMP, AM_J | OT_B, AM_NOT_USED, AM_NOT_USED, "jc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x73 */ { 0, IT_JUMP, AM_J | OT_B, AM_NOT_USED, AM_NOT_USED, "jnc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x74 */ { 0, IT_JUMP, AM_J | OT_B, AM_NOT_USED, AM_NOT_USED, "jz", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x75 */ { 0, IT_JUMP, AM_J | OT_B, AM_NOT_USED, AM_NOT_USED, "jnz", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x76 */ { 0, IT_JUMP, AM_J | OT_B, AM_NOT_USED, AM_NOT_USED, "jbe", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x77 */ { 0, IT_JUMP, AM_J | OT_B, AM_NOT_USED, AM_NOT_USED, "ja", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x78 */ { 0, IT_JUMP, AM_J | OT_B, AM_NOT_USED, AM_NOT_USED, "js", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x79 */ { 0, IT_JUMP, AM_J | OT_B, AM_NOT_USED, AM_NOT_USED, "jns", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x7A */ { 0, IT_JUMP, AM_J | OT_B, AM_NOT_USED, AM_NOT_USED, "jpe", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x7B */ { 0, IT_JUMP, AM_J | OT_B, AM_NOT_USED, AM_NOT_USED, "jpo", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x7C */ { 0, IT_JUMP, AM_J | OT_B, AM_NOT_USED, AM_NOT_USED, "jl", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x7D */ { 0, IT_JUMP, AM_J | OT_B, AM_NOT_USED, AM_NOT_USED, "jge", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x7E */ { 0, IT_JUMP, AM_J | OT_B, AM_NOT_USED, AM_NOT_USED, "jle", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x7F */ { 0, IT_JUMP, AM_J | OT_B, AM_NOT_USED, AM_NOT_USED, "jg", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x80 */ { 2, IT_REFERENCE, AM_E | OT_B, AM_I | OT_B, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x81 */ { 3, IT_REFERENCE, AM_E | OT_V, AM_I | OT_V, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x82 */ { 4, IT_REFERENCE, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x83 */ { 5, IT_REFERENCE, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x84 */ { 0, IT_GENERIC, AM_E | OT_B, AM_G | OT_B, AM_NOT_USED, "test", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x85 */ { 0, IT_GENERIC, AM_E | OT_V, AM_G | OT_V, AM_NOT_USED, "test", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x86 */ { 0, IT_GENERIC, AM_E | OT_B, AM_G | OT_B, AM_NOT_USED, "xchg", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x87 */ { 0, IT_GENERIC, AM_E | OT_V, AM_G | OT_V, AM_NOT_USED, "xchg", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x88 */ { 0, IT_GENERIC, AM_E | OT_B, AM_G | OT_B, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x89 */ { 0, IT_GENERIC, AM_E | OT_V, AM_G | OT_V, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x8A */ { 0, IT_GENERIC, AM_G | OT_B, AM_E | OT_B, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x8B */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x8C */ { 0, IT_GENERIC, AM_E | OT_W, AM_S | OT_W, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x8D */ { 0, IT_GENERIC, AM_G | OT_V, AM_M | OT_ADDRESS_MODE_M, AM_NOT_USED, "lea", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x8E */ { 0, IT_GENERIC, AM_S | OT_W, AM_E | OT_W, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x8F */ { 0, IT_GENERIC, AM_E | OT_V, AM_NOT_USED, AM_NOT_USED, "pop", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x90 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "nop", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x91 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_REGISTER | OT_V, AM_NOT_USED, "xchg", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x92 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_REGISTER | OT_V, AM_NOT_USED, "xchg", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x93 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_REGISTER | OT_V, AM_NOT_USED, "xchg", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x94 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_REGISTER | OT_V, AM_NOT_USED, "xchg", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x95 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_REGISTER | OT_V, AM_NOT_USED, "xchg", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x96 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_REGISTER | OT_V, AM_NOT_USED, "xchg", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x97 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_REGISTER | OT_V, AM_NOT_USED, "xchg", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x98 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "cwde", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x99 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "cdq", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x9A */ { 0, IT_JUMP, AM_A | OT_P, AM_NOT_USED, AM_NOT_USED, "callf", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x9B */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "wait", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x9C */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "pushfd", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x9D */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "popfd", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x9E */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "sahf", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x9F */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "lahf", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xA0 */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_O | OT_B, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xA1 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_O | OT_V, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xA2 */ { 0, IT_GENERIC, AM_O | OT_B, AM_REGISTER | OT_B, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xA3 */ { 0, IT_GENERIC, AM_O | OT_V, AM_REGISTER | OT_V, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xA4 */ { 0, IT_GENERIC, AM_X | OT_B, AM_Y | OT_B, AM_NOT_USED, "movsb", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xA5 */ { 0, IT_GENERIC, AM_X | OT_V, AM_Y | OT_V, AM_NOT_USED, "movsd", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xA6 */ { 0, IT_GENERIC, AM_X | OT_B, AM_Y | OT_B, AM_NOT_USED, "cmpsb", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xA7 */ { 0, IT_GENERIC, AM_X | OT_V, AM_Y | OT_V, AM_NOT_USED, "cmpsd", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xA8 */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_I | OT_B, AM_NOT_USED, "test", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xA9 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_I | OT_V, AM_NOT_USED, "test", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xAA */ { 0, IT_GENERIC, AM_Y | OT_B, AM_REGISTER | OT_B, AM_NOT_USED, "stosb", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xAB */ { 0, IT_GENERIC, AM_Y | OT_V, AM_REGISTER | OT_V, AM_NOT_USED, "stosd", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xAC */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_X| OT_B, AM_NOT_USED, "lodsb", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xAD */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_X| OT_V, AM_NOT_USED, "lodsd", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xAE */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_Y | OT_B, AM_NOT_USED, "scasb", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xAF */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_Y | OT_V, AM_NOT_USED, "scasd", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xB0 */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_I | OT_B, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xB1 */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_I | OT_B, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xB2 */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_I | OT_B, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xB3 */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_I | OT_B, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xB4 */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_I | OT_B, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xB5 */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_I | OT_B, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xB6 */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_I | OT_B, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xB7 */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_I | OT_B, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+#ifdef _M_X64
+  /* 0xB8 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_I | OT_V | IOS_64, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xB9 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_I | OT_V | IOS_64, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xBA */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_I | OT_V | IOS_64, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xBB */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_I | OT_V | IOS_64, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xBC */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_I | OT_V | IOS_64, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xBD */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_I | OT_V | IOS_64, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xBE */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_I | OT_V | IOS_64, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xBF */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_I | OT_V | IOS_64, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+#else
+  /* 0xB8 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_I | OT_V, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xB9 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_I | OT_V, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xBA */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_I | OT_V, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xBB */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_I | OT_V, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xBC */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_I | OT_V, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xBD */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_I | OT_V, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xBE */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_I | OT_V, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xBF */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_I | OT_V, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+#endif
+  /* 0xC0 */ { 6, IT_REFERENCE, AM_E | OT_B, AM_I | OT_B, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xC1 */ { 7, IT_REFERENCE, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xC2 */ { 0, IT_RETURN, AM_I | OT_W, AM_NOT_USED, AM_NOT_USED, "ret", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xC3 */ { 0, IT_RETURN, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "ret", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xC4 */ { 0, IT_GENERIC, AM_G | OT_V, AM_M | OT_P, AM_NOT_USED, "les", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xC5 */ { 0, IT_GENERIC, AM_G | OT_V, AM_M | OT_P, AM_NOT_USED, "lds", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xC6 */ { 0, IT_GENERIC, AM_E | OT_B, AM_I | OT_B, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xC7 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_V, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xC8 */ { 0, IT_GENERIC, AM_I | OT_W, AM_I | OT_B, AM_NOT_USED, "enter", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xC9 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "leave", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xCA */ { 0, IT_RETURN, AM_I | OT_W, AM_NOT_USED, AM_NOT_USED, "retf", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xCB */ { 0, IT_RETURN, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "retf", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xCC */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "int3", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xCD */ { 0, IT_GENERIC, AM_I | OT_B, AM_NOT_USED, AM_NOT_USED, "int", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xCE */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "into", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xCF */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "iret", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xD0 */ { 8, IT_REFERENCE, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xD1 */ { 9, IT_REFERENCE, AM_E | OT_V, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xD2 */ { 10, IT_REFERENCE, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xD3 */ { 11, IT_REFERENCE, AM_E | OT_V, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xD4 */ { 0, IT_GENERIC, AM_I | OT_B, AM_NOT_USED, AM_NOT_USED, "aam", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xD5 */ { 0, IT_GENERIC, AM_I | OT_B, AM_NOT_USED, AM_NOT_USED, "aad", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xD6 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xD7 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "xlat", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  
+  // The following 8 lines would be references to the FPU tables, but we currently
+  // do not support the FPU instructions in this disassembler.
+  
+  /* 0xD8 */ { 0, IT_UNKNOWN, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xD9 */ { 0, IT_UNKNOWN, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xDA */ { 0, IT_UNKNOWN, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xDB */ { 0, IT_UNKNOWN, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xDC */ { 0, IT_UNKNOWN, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xDD */ { 0, IT_UNKNOWN, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xDE */ { 0, IT_UNKNOWN, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xDF */ { 0, IT_UNKNOWN, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  
+  
+  /* 0xE0 */ { 0, IT_JUMP, AM_J | OT_B, AM_NOT_USED, AM_NOT_USED, "loopnz", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xE1 */ { 0, IT_JUMP, AM_J | OT_B, AM_NOT_USED, AM_NOT_USED, "loopz", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xE2 */ { 0, IT_JUMP, AM_J | OT_B, AM_NOT_USED, AM_NOT_USED, "loop", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xE3 */ { 0, IT_JUMP, AM_J | OT_B, AM_NOT_USED, AM_NOT_USED, "jcxz", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xE4 */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_I | OT_B, AM_NOT_USED, "in", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xE5 */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_I | OT_B, AM_NOT_USED, "in", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xE6 */ { 0, IT_GENERIC, AM_I | OT_B, AM_REGISTER | OT_B, AM_NOT_USED, "out", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xE7 */ { 0, IT_GENERIC, AM_I | OT_B, AM_REGISTER | OT_B, AM_NOT_USED, "out", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xE8 */ { 0, IT_JUMP, AM_J | OT_V, AM_NOT_USED, AM_NOT_USED, "call", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xE9 */ { 0, IT_JUMP, AM_J | OT_V, AM_NOT_USED, AM_NOT_USED, "jmp", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xEA */ { 0, IT_JUMP, AM_A | OT_P, AM_NOT_USED, AM_NOT_USED, "jmp", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xEB */ { 0, IT_JUMP, AM_J | OT_B, AM_NOT_USED, AM_NOT_USED, "jmp", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xEC */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_REGISTER | OT_W, AM_NOT_USED, "in", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xED */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_REGISTER | OT_W, AM_NOT_USED, "in", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xEE */ { 0, IT_GENERIC, AM_REGISTER | OT_W, AM_REGISTER | OT_B, AM_NOT_USED, "out", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xEF */ { 0, IT_GENERIC, AM_REGISTER | OT_W, AM_REGISTER | OT_V, AM_NOT_USED, "out", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xF0 */ { 0, IT_PREFIX, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "lock:", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xF1 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xF2 */ { 0, IT_PREFIX, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "repne:", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xF3 */ { 0, IT_PREFIX, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "rep:", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xF4 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "hlt", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xF5 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "cmc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xF6 */ { 12, IT_REFERENCE, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xF7 */ { 13, IT_REFERENCE, AM_E | OT_V, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xF8 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "clc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xF9 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "stc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xFA */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "cli", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xFB */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "sti", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xFC */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "cld", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xFD */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "std", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xFE */ { 14, IT_REFERENCE, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xFF */ { 15, IT_REFERENCE, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }
+};
+
+const Opcode s_opcode_byte_after_0f[] = {
+  /* 0x0 */ { 16, IT_REFERENCE, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x1 */ { 17, IT_REFERENCE, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x2 */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_W, AM_NOT_USED, "lar", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x3 */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_W, AM_NOT_USED, "lsl", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x4 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x5 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x6 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "clts", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x7 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x8 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "invd", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x9 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "wbinvd", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xA */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xB */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "ud2", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xC */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xD */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xE */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xF */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x10 */ { 0, IT_GENERIC, AM_V | OT_PS, AM_W | OT_PS, AM_NOT_USED, "movups", true,
+    /* F2h */ { 0, IT_GENERIC, AM_V | OT_SD, AM_W | OT_SD, AM_NOT_USED, "movsd" },
+    /* F3h */ { 0, IT_GENERIC, AM_V | OT_SS, AM_W | OT_SS, AM_NOT_USED, "movss" },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_PD, AM_W | OT_PD, AM_NOT_USED, "movupd" } },
+  /* 0x11 */ { 0, IT_GENERIC, AM_W | OT_PS, AM_V | OT_PS, AM_NOT_USED, "movups", true,
+    /* F2h */ { 0, IT_GENERIC, AM_W | OT_SD, AM_V | OT_SD, AM_NOT_USED, "movsd" },
+    /* F3h */ { 0, IT_GENERIC, AM_W | OT_SS, AM_V | OT_SS, AM_NOT_USED, "movss" },
+    /* 66h */ { 0, IT_GENERIC, AM_W | OT_PD, AM_V | OT_PD, AM_NOT_USED, "movupd" } },
+  /* 0x12 */ { 0, IT_GENERIC, AM_W | OT_Q, AM_V | OT_Q, AM_NOT_USED, "movlps", true,
+    /* F2h */ { 0, IT_GENERIC, AM_V | OT_Q, AM_V | OT_Q, AM_NOT_USED, "movhlps" },  // only one of ...
+    /* F3h */ { 0, IT_GENERIC, AM_V | OT_Q, AM_V | OT_Q, AM_NOT_USED, "movhlps" },  // ...these two is correct, Intel doesn't specify which
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_Q, AM_W | OT_S, AM_NOT_USED, "movlpd" } },
+  /* 0x13 */ { 0, IT_GENERIC, AM_V | OT_Q, AM_W | OT_Q, AM_NOT_USED, "movlps", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_Q, AM_W | OT_Q, AM_NOT_USED, "movlpd" } },
+  /* 0x14 */ { 0, IT_GENERIC, AM_V | OT_PS, AM_W | OT_Q, AM_NOT_USED, "unpcklps", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_PD, AM_W | OT_Q, AM_NOT_USED, "unpcklpd" } },
+  /* 0x15 */ { 0, IT_GENERIC, AM_V | OT_PS, AM_W | OT_Q, AM_NOT_USED, "unpckhps", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_PD, AM_W | OT_Q, AM_NOT_USED, "unpckhpd" } },
+  /* 0x16 */ { 0, IT_GENERIC, AM_V | OT_Q, AM_W | OT_Q, AM_NOT_USED, "movhps", true,
+    /* F2h */ { 0, IT_GENERIC, AM_V | OT_Q, AM_V | OT_Q, AM_NOT_USED, "movlhps" },  // only one of...
+    /* F3h */ { 0, IT_GENERIC, AM_V | OT_Q, AM_V | OT_Q, AM_NOT_USED, "movlhps" },  // ...these two is correct, Intel doesn't specify which
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_Q, AM_W | OT_Q, AM_NOT_USED, "movhpd" } },
+  /* 0x17 */ { 0, IT_GENERIC, AM_W | OT_Q, AM_V | OT_Q, AM_NOT_USED, "movhps", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_W | OT_Q, AM_V | OT_Q, AM_NOT_USED, "movhpd" } },
+  /* 0x18 */ { 18, IT_REFERENCE, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x19 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x1A */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x1B */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x1C */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x1D */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x1E */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x1F */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x20 */ { 0, IT_GENERIC, AM_R | OT_D, AM_C | OT_D, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x21 */ { 0, IT_GENERIC, AM_R | OT_D, AM_D | OT_D, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x22 */ { 0, IT_GENERIC, AM_C | OT_D, AM_R | OT_D, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x23 */ { 0, IT_GENERIC, AM_D | OT_D, AM_R | OT_D, AM_NOT_USED, "mov", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x24 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x25 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x26 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x27 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x28 */ { 0, IT_GENERIC, AM_V | OT_PS, AM_W | OT_PS, AM_NOT_USED, "movaps", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_PD, AM_W | OT_PD, AM_NOT_USED, "movapd" } },
+  /* 0x29 */ { 0, IT_GENERIC, AM_W | OT_PS, AM_V | OT_PS, AM_NOT_USED, "movaps", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_W | OT_PD, AM_V | OT_PD, AM_NOT_USED, "movapd" } },
+  /* 0x2A */ { 0, IT_GENERIC, AM_V | OT_PS, AM_Q | OT_Q, AM_NOT_USED, "cvtpi2ps", true,
+    /* F2h */ { 0, IT_GENERIC, AM_V | OT_SD, AM_E | OT_D, AM_NOT_USED, "cvtsi2sd" },
+    /* F3h */ { 0, IT_GENERIC, AM_V | OT_SS, AM_E | OT_D, AM_NOT_USED, "cvtsi2ss" },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_PD, AM_Q | OT_DQ, AM_NOT_USED, "cvtpi2pd" } },
+  /* 0x2B */ { 0, IT_GENERIC, AM_W | OT_PS, AM_V | OT_PS, AM_NOT_USED, "movntps", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_W | OT_PD, AM_V | OT_PD, AM_NOT_USED, "movntpd" } },
+  /* 0x2C */ { 0, IT_GENERIC, AM_Q | OT_Q, AM_W | OT_PS, AM_NOT_USED, "cvttps2pi", true,
+    /* F2h */ { 0, IT_GENERIC, AM_G | OT_D, AM_W | OT_SD, AM_NOT_USED, "cvttsd2si" },
+    /* F3h */ { 0, IT_GENERIC, AM_G | OT_D, AM_W | OT_SS, AM_NOT_USED, "cvttss2si" },
+    /* 66h */ { 0, IT_GENERIC, AM_Q | OT_DQ, AM_W | OT_PD, AM_NOT_USED, "cvttpd2pi" } },
+  /* 0x2D */ { 0, IT_GENERIC, AM_Q | OT_Q, AM_W | OT_PS, AM_NOT_USED, "cvtps2pi", true,
+    /* F2h */ { 0, IT_GENERIC, AM_G | OT_D, AM_W | OT_SD, AM_NOT_USED, "cvtsd2si" },
+    /* F3h */ { 0, IT_GENERIC, AM_G | OT_D, AM_W | OT_SS, AM_NOT_USED, "cvtss2si" },
+    /* 66h */ { 0, IT_GENERIC, AM_Q | OT_DQ, AM_W | OT_PD, AM_NOT_USED, "cvtpd2pi" } },
+  /* 0x2E */ { 0, IT_GENERIC, AM_V | OT_SS, AM_W | OT_SS, AM_NOT_USED, "ucomiss", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_SD, AM_W | OT_SD, AM_NOT_USED, "ucomisd" } },
+  /* 0x2F */ { 0, IT_GENERIC, AM_V | OT_PS, AM_W | OT_SS, AM_NOT_USED, "comiss", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_SD, AM_W | OT_SD, AM_NOT_USED, "comisd" } },
+  /* 0x30 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "wrmsr", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x31 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "rdtsc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x32 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "rdmsr", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x33 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "rdpmc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x34 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "sysenter", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x35 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "sysexit", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x36 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x37 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x38 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x39 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x3A */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x3B */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x3C */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "movnti", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x3D */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x3E */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x3F */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x40 */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "cmovo", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x41 */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "cmovno", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x42 */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "cmovc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x43 */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "cmovnc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x44 */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "cmovz", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x45 */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "cmovnz", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x46 */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "cmovbe", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x47 */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "cmova", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x48 */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "cmovs", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x49 */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "cmovns", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x4A */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "cmovpe", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x4B */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "cmovpo", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x4C */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "cmovl", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x4D */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "cmovge", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x4E */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "cmovle", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x4F */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "cmovg", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x50 */ { 0, IT_GENERIC, AM_E | OT_D, AM_V | OT_PS, AM_NOT_USED, "movmskps", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_E | OT_D, AM_V | OT_PD, AM_NOT_USED, "movmskpd" } },
+  /* 0x51 */ { 0, IT_GENERIC, AM_V | OT_PS, AM_W | OT_PS, AM_NOT_USED, "sqrtps", true,
+    /* F2h */ { 0, IT_GENERIC, AM_V | OT_SD, AM_W | OT_SD, AM_NOT_USED, "sqrtsd" },
+    /* F3h */ { 0, IT_GENERIC, AM_V | OT_SS, AM_W | OT_SS, AM_NOT_USED, "sqrtss" },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_PD, AM_W | OT_PD, AM_NOT_USED, "sqrtpd" } },
+  /* 0x52 */ { 0, IT_GENERIC, AM_V | OT_PS, AM_W | OT_PS, AM_NOT_USED, "rsqrtps", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0, IT_GENERIC, AM_V | OT_SS, AM_W | OT_SS, AM_NOT_USED, "rsqrtss" },
+    /* 66h */ { 0 } },
+  /* 0x53 */ { 0, IT_GENERIC, AM_V | OT_PS, AM_W | OT_PS, AM_NOT_USED, "rcpps", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0, IT_GENERIC, AM_V | OT_SS, AM_W | OT_SS, AM_NOT_USED, "rcpss" },
+    /* 66h */ { 0 } },
+  /* 0x54 */ { 0, IT_GENERIC, AM_V | OT_PS, AM_W | OT_PS, AM_NOT_USED, "andps", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_PD, AM_W | OT_PD, AM_NOT_USED, "andpd" } },
+  /* 0x55 */ { 0, IT_GENERIC, AM_V | OT_PS, AM_W | OT_PS, AM_NOT_USED, "andnps", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_PD, AM_W | OT_PD, AM_NOT_USED, "andnpd" } },
+  /* 0x56 */ { 0, IT_GENERIC, AM_V | OT_PS, AM_W | OT_PS, AM_NOT_USED, "orps", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_PD, AM_W | OT_PD, AM_NOT_USED, "orpd" } },
+  /* 0x57 */ { 0, IT_GENERIC, AM_V | OT_PS, AM_W | OT_PS, AM_NOT_USED, "xorps", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_PD, AM_W | OT_PD, AM_NOT_USED, "xorpd" } },
+  /* 0x58 */ { 0, IT_GENERIC, AM_V | OT_PS, AM_W | OT_PS, AM_NOT_USED, "addps", true,
+    /* F2h */ { 0, IT_GENERIC, AM_V | OT_SD, AM_W | OT_SD, AM_NOT_USED, "addsd" },
+    /* F3h */ { 0, IT_GENERIC, AM_V | OT_SS, AM_W | OT_SS, AM_NOT_USED, "addss" },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_PD, AM_W | OT_PD, AM_NOT_USED, "addpd" } },
+  /* 0x59 */ { 0, IT_GENERIC, AM_V | OT_PS, AM_W | OT_PS, AM_NOT_USED, "mulps", true,
+    /* F2h */ { 0, IT_GENERIC, AM_V | OT_SD, AM_W | OT_SD, AM_NOT_USED, "mulsd" },
+    /* F3h */ { 0, IT_GENERIC, AM_V | OT_SS, AM_W | OT_SS, AM_NOT_USED, "mulss" },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_PD, AM_W | OT_PD, AM_NOT_USED, "mulpd" } },
+  /* 0x5A */ { 0, IT_GENERIC, AM_V | OT_PD, AM_W | OT_PS, AM_NOT_USED, "cvtps2pd", true,
+    /* F2h */ { 0, IT_GENERIC, AM_V | OT_SD, AM_W | OT_SD, AM_NOT_USED, "cvtsd2ss" },
+    /* F3h */ { 0, IT_GENERIC, AM_V | OT_SS, AM_W | OT_SS, AM_NOT_USED, "cvtss2sd" },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_PS, AM_W | OT_PD, AM_NOT_USED, "cvtpd2ps" } },
+  /* 0x5B */ { 0, IT_GENERIC, AM_V | OT_PS, AM_W | OT_DQ, AM_NOT_USED, "cvtdq2ps", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_PS, AM_NOT_USED, "cvttps2dq" },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_PS, AM_NOT_USED, "cvtps2dq" } },
+  /* 0x5C */ { 0, IT_GENERIC, AM_V | OT_PS, AM_W | OT_PS, AM_NOT_USED, "subps", true,
+    /* F2h */ { 0, IT_GENERIC, AM_V | OT_SD, AM_W | OT_SD, AM_NOT_USED, "subsd" },
+    /* F3h */ { 0, IT_GENERIC, AM_V | OT_SS, AM_W | OT_SS, AM_NOT_USED, "subss" },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_PD, AM_W | OT_PD, AM_NOT_USED, "subpd" } },
+  /* 0x5D */ { 0, IT_GENERIC, AM_V | OT_PS, AM_W | OT_PS, AM_NOT_USED, "minps", true,
+    /* F2h */ { 0, IT_GENERIC, AM_V | OT_SD, AM_W | OT_SD, AM_NOT_USED, "minsd" },
+    /* F3h */ { 0, IT_GENERIC, AM_V | OT_SS, AM_W | OT_SS, AM_NOT_USED, "minss" },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_PD, AM_W | OT_PD, AM_NOT_USED, "minpd" } },
+  /* 0x5E */ { 0, IT_GENERIC, AM_V | OT_PS, AM_W | OT_PS, AM_NOT_USED, "divps", true,
+    /* F2h */ { 0, IT_GENERIC, AM_V | OT_SD, AM_W | OT_SD, AM_NOT_USED, "divsd" },
+    /* F3h */ { 0, IT_GENERIC, AM_V | OT_SS, AM_W | OT_SS, AM_NOT_USED, "divss" },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_PD, AM_W | OT_PD, AM_NOT_USED, "divpd" } },
+  /* 0x5F */ { 0, IT_GENERIC, AM_V | OT_PS, AM_W | OT_PS, AM_NOT_USED, "maxps", true,
+    /* F2h */ { 0, IT_GENERIC, AM_V | OT_SD, AM_W | OT_SD, AM_NOT_USED, "maxsd" },
+    /* F3h */ { 0, IT_GENERIC, AM_V | OT_SS, AM_W | OT_SS, AM_NOT_USED, "maxss" },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_PD, AM_W | OT_PD, AM_NOT_USED, "maxpd" } },
+  /* 0x60 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_D, AM_NOT_USED, "punpcklbw", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "punpcklbw" } },
+  /* 0x61 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_D, AM_NOT_USED, "punpcklwd", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "punpcklwd" } },
+  /* 0x62 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_D, AM_NOT_USED, "punpckldq", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "punpckldq" } },
+  /* 0x63 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_D, AM_NOT_USED, "packsswb", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "packsswb" } },
+  /* 0x64 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_D, AM_NOT_USED, "pcmpgtb", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "pcmpgtb" } },
+  /* 0x65 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_D, AM_NOT_USED, "pcmpgtw", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "pcmpgtw" } },
+  /* 0x66 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_D, AM_NOT_USED, "pcmpgtd", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "pcmpgtd" } },
+  /* 0x67 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_D, AM_NOT_USED, "packuswb", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "packuswb" } },
+  /* 0x68 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_D, AM_NOT_USED, "punpckhbw", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_P | OT_DQ, AM_Q | OT_DQ, AM_NOT_USED, "punpckhbw" } },
+  /* 0x69 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_D, AM_NOT_USED, "punpckhwd", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_P | OT_DQ, AM_Q | OT_DQ, AM_NOT_USED, "punpckhwd" } },
+  /* 0x6A */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_D, AM_NOT_USED, "punpckhdq", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_P | OT_DQ, AM_Q | OT_DQ, AM_NOT_USED, "punpckhdq" } },
+  /* 0x6B */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_D, AM_NOT_USED, "packssdw", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_P | OT_DQ, AM_Q | OT_DQ, AM_NOT_USED, "packssdw" } },
+  /* 0x6C */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "not used without prefix", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "punpcklqdq" } },
+  /* 0x6D */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "not used without prefix", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "punpcklqdq" } },
+  /* 0x6E */ { 0, IT_GENERIC, AM_P | OT_D, AM_E | OT_D, AM_NOT_USED, "movd", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_E | OT_D, AM_NOT_USED, "movd" } },
+  /* 0x6F */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_D, AM_NOT_USED, "movq", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "movdqu" },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "movdqa" } },
+  /* 0x70 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_I |  OT_B, "pshuf", true,
+    /* F2h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_I | OT_B, "pshuflw" },
+    /* F3h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_I | OT_B, "pshufhw" },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_I | OT_B, "pshufd" } },
+  /* 0x71 */ { 19, IT_REFERENCE, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x72 */ { 20, IT_REFERENCE, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x73 */ { 21, IT_REFERENCE, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x74 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "pcmpeqb", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "pcmpeqb" } },
+  /* 0x75 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "pcmpeqw", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "pcmpeqw" } },
+  /* 0x76 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "pcmpeqd", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "pcmpeqd" } },
+  /* 0x77 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "emms", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  
+  // The following six opcodes are escapes into the MMX stuff, which this disassembler does not support.
+  /* 0x78 */ { 0, IT_UNKNOWN, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x79 */ { 0, IT_UNKNOWN, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x7A */ { 0, IT_UNKNOWN, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x7B */ { 0, IT_UNKNOWN, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x7C */ { 0, IT_UNKNOWN, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x7D */ { 0, IT_UNKNOWN, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  
+  /* 0x7E */ { 0, IT_GENERIC, AM_E | OT_D, AM_P | OT_D, AM_NOT_USED, "movd", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0, IT_GENERIC, AM_V | OT_Q, AM_W | OT_Q, AM_NOT_USED, "movq" },
+    /* 66h */ { 0, IT_GENERIC, AM_E | OT_D, AM_V | OT_DQ, AM_NOT_USED, "movd" } },
+  /* 0x7F */ { 0, IT_GENERIC, AM_Q | OT_Q, AM_P | OT_Q, AM_NOT_USED, "movq", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0, IT_GENERIC, AM_W | OT_DQ, AM_V | OT_DQ, AM_NOT_USED, "movdqu" },
+    /* 66h */ { 0, IT_GENERIC, AM_W | OT_DQ, AM_V | OT_DQ, AM_NOT_USED, "movdqa" } },
+  /* 0x80 */ { 0, IT_JUMP, AM_J | OT_V, AM_NOT_USED, AM_NOT_USED, "jo", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x81 */ { 0, IT_JUMP, AM_J | OT_V, AM_NOT_USED, AM_NOT_USED, "jno", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x82 */ { 0, IT_JUMP, AM_J | OT_V, AM_NOT_USED, AM_NOT_USED, "jc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x83 */ { 0, IT_JUMP, AM_J | OT_V, AM_NOT_USED, AM_NOT_USED, "jnc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x84 */ { 0, IT_JUMP, AM_J | OT_V, AM_NOT_USED, AM_NOT_USED, "jz", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x85 */ { 0, IT_JUMP, AM_J | OT_V, AM_NOT_USED, AM_NOT_USED, "jnz", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x86 */ { 0, IT_JUMP, AM_J | OT_V, AM_NOT_USED, AM_NOT_USED, "jbe", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x87 */ { 0, IT_JUMP, AM_J | OT_V, AM_NOT_USED, AM_NOT_USED, "ja", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x88 */ { 0, IT_JUMP, AM_J | OT_V, AM_NOT_USED, AM_NOT_USED, "js", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x89 */ { 0, IT_JUMP, AM_J | OT_V, AM_NOT_USED, AM_NOT_USED, "jns", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x8A */ { 0, IT_JUMP, AM_J | OT_V, AM_NOT_USED, AM_NOT_USED, "jpe", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x8B */ { 0, IT_JUMP, AM_J | OT_V, AM_NOT_USED, AM_NOT_USED, "jpo", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x8C */ { 0, IT_JUMP, AM_J | OT_V, AM_NOT_USED, AM_NOT_USED, "jl", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x8D */ { 0, IT_JUMP, AM_J | OT_V, AM_NOT_USED, AM_NOT_USED, "jge", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x8E */ { 0, IT_JUMP, AM_J | OT_V, AM_NOT_USED, AM_NOT_USED, "jle", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x8F */ { 0, IT_JUMP, AM_J | OT_V, AM_NOT_USED, AM_NOT_USED, "jg", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x90 */ { 0, IT_GENERIC, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, "seto", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x91 */ { 0, IT_GENERIC, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, "setno", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x92 */ { 0, IT_GENERIC, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, "setc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x93 */ { 0, IT_GENERIC, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, "setnc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x94 */ { 0, IT_GENERIC, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, "setz", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x95 */ { 0, IT_GENERIC, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, "setnz", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x96 */ { 0, IT_GENERIC, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, "setbe", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x97 */ { 0, IT_GENERIC, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, "seta", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x98 */ { 0, IT_GENERIC, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, "sets", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x99 */ { 0, IT_GENERIC, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, "setns", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x9A */ { 0, IT_GENERIC, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, "setpe", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x9B */ { 0, IT_GENERIC, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, "setpo", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x9C */ { 0, IT_GENERIC, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, "setl", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x9D */ { 0, IT_GENERIC, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, "setge", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x9E */ { 0, IT_GENERIC, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, "setle", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x9F */ { 0, IT_GENERIC, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, "setg", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xA0 */ { 0, IT_GENERIC, AM_REGISTER | OT_W, AM_NOT_USED, AM_NOT_USED, "push", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xA1 */ { 0, IT_GENERIC, AM_REGISTER | OT_W, AM_NOT_USED, AM_NOT_USED, "pop", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xA2 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "cpuid", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xA3 */ { 0, IT_GENERIC, AM_E | OT_V, AM_G | OT_V, AM_NOT_USED, "bt", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xA4 */ { 0, IT_GENERIC, AM_E | OT_V, AM_G | OT_V, AM_I | OT_B, "shld", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xA5 */ { 0, IT_GENERIC, AM_E | OT_V, AM_G | OT_V, AM_I | OT_B | AM_REGISTER, "shld", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xA6 */ { 0, IT_UNKNOWN, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xA7 */ { 0, IT_UNKNOWN, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xA8 */ { 0, IT_GENERIC, AM_REGISTER | OT_W, AM_NOT_USED, AM_NOT_USED, "push", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xA9 */ { 0, IT_GENERIC, AM_REGISTER | OT_W, AM_NOT_USED, AM_NOT_USED, "pop", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xAA */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "rsm", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xAB */ { 0, IT_GENERIC, AM_E | OT_V, AM_G | OT_V, AM_NOT_USED, "bts", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xAC */ { 0, IT_GENERIC, AM_E | OT_V, AM_G | OT_V, AM_I | OT_B, "shrd", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xAD */ { 0, IT_GENERIC, AM_E | OT_V, AM_G | OT_V, AM_I | OT_B | AM_REGISTER, "shrd", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xAE */ { 22, IT_REFERENCE, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xAF */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "imul", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xB0 */ { 0, IT_GENERIC, AM_E | OT_B, AM_G | OT_B, AM_NOT_USED, "cmpxchg", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xB1 */ { 0, IT_GENERIC, AM_E | OT_V, AM_G | OT_V, AM_NOT_USED, "cmpxchg", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xB2 */ { 0, IT_GENERIC, AM_M | OT_P, AM_NOT_USED, AM_NOT_USED, "lss", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xB3 */ { 0, IT_GENERIC, AM_E | OT_V, AM_G | OT_V, AM_NOT_USED, "btr", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xB4 */ { 0, IT_GENERIC, AM_M | OT_P, AM_NOT_USED, AM_NOT_USED, "lfs", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xB5 */ { 0, IT_GENERIC, AM_M | OT_P, AM_NOT_USED, AM_NOT_USED, "lgs", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xB6 */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_B, AM_NOT_USED, "movzx", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xB7 */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_W, AM_NOT_USED, "movzx", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xB8 */ { 0, IT_UNKNOWN, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xB9 */ { 0, IT_UNKNOWN, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "ud1", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xBA */ { 23, IT_REFERENCE, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xBB */ { 0, IT_GENERIC, AM_E | OT_V, AM_G | OT_V, AM_NOT_USED, "btc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xBC */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "bsf", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xBD */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_V, AM_NOT_USED, "bsr", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xBE */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_B, AM_NOT_USED, "movsx", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xBF */ { 0, IT_GENERIC, AM_G | OT_V, AM_E | OT_W, AM_NOT_USED, "movsx", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xC0 */ { 0, IT_GENERIC, AM_E | OT_B, AM_G | OT_B, AM_NOT_USED, "xadd", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xC1 */ { 0, IT_GENERIC, AM_E | OT_V, AM_NOT_USED, AM_NOT_USED, "xadd", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xC2 */ { 0, IT_GENERIC, AM_V | OT_PS, AM_W | OT_PS, AM_I | OT_B, "cmpps", true,
+    /* F2h */ { 0, IT_GENERIC, AM_V | OT_SD, AM_W | OT_SD, AM_I | OT_B, "cmpsd" },
+    /* F3h */ { 0, IT_GENERIC, AM_V | OT_SS, AM_W  | OT_SS, AM_I | OT_B, "cmpss" },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_PD, AM_W | OT_PD, AM_I | OT_B, "cmppd" } },
+  /* 0xC3 */ { 0, IT_GENERIC, AM_E | OT_D, AM_G | OT_D, AM_NOT_USED, "movnti", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xC4 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_E | OT_D, AM_I | OT_B, "pinsrw", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_E | OT_D, AM_I | OT_B, "pinsrw" } },
+  /* 0xC5 */ { 0, IT_GENERIC, AM_G | OT_D, AM_P | OT_Q, AM_I | OT_B, "pextrw", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_G | OT_D, AM_V | OT_DQ, AM_I | OT_B, "pextrw" } },
+  /* 0xC6 */ { 0, IT_GENERIC, AM_V | OT_PS, AM_W | OT_PS, AM_I | OT_B, "shufps", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_PD, AM_W | OT_PD, AM_I | OT_B, "shufpd" } },
+  /* 0xC7 */ { 24, IT_REFERENCE, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xC8 */ { 0, IT_GENERIC, AM_REGISTER | OT_D, AM_NOT_USED, AM_NOT_USED, "bswap", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xC9 */ { 0, IT_GENERIC, AM_REGISTER | OT_D, AM_NOT_USED, AM_NOT_USED, "bswap", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xCA */ { 0, IT_GENERIC, AM_REGISTER | OT_D, AM_NOT_USED, AM_NOT_USED, "bswap", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xCB */ { 0, IT_GENERIC, AM_REGISTER | OT_D, AM_NOT_USED, AM_NOT_USED, "bswap", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xCC */ { 0, IT_GENERIC, AM_REGISTER | OT_D, AM_NOT_USED, AM_NOT_USED, "bswap", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xCD */ { 0, IT_GENERIC, AM_REGISTER | OT_D, AM_NOT_USED, AM_NOT_USED, "bswap", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xCE */ { 0, IT_GENERIC, AM_REGISTER | OT_D, AM_NOT_USED, AM_NOT_USED, "bswap", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xCF */ { 0, IT_GENERIC, AM_REGISTER | OT_D, AM_NOT_USED, AM_NOT_USED, "bswap", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xD0 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xD1 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "psrlw", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "psrlw" } },
+  /* 0xD2 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "psrld", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "psrld" } },
+  /* 0xD3 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "psrlq", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "psrlq" } },
+  /* 0xD4 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "paddq", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "paddq" } },
+  /* 0xD5 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "pmullw", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "pmullw" } },
+  /* 0xD6 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "unused without prefix", true,
+    /* F2h */ { 0, IT_GENERIC, AM_P | OT_Q, AM_W | OT_Q, AM_NOT_USED, "movdq2q" },
+    /* F3h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_Q | OT_Q, AM_NOT_USED, "movq2dq" },
+    /* 66h */ { 0, IT_GENERIC, AM_W | OT_Q, AM_V | OT_Q, AM_NOT_USED, "movq" } },
+  /* 0xD7 */ { 0, IT_GENERIC, AM_G | OT_D, AM_P | OT_Q, AM_NOT_USED, "pmovmskb", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_G | OT_D, AM_V | OT_DQ, AM_NOT_USED, "pmovmskb" } },
+  /* 0xD8 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "psubusb", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "psubusb" } },
+  /* 0xD9 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "psubusw", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "psubusw" } },
+  /* 0xDA */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "pminub", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "pminub" } },
+  /* 0xDB */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "pand", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "pand" } },
+  /* 0xDC */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "paddusb", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "paddusb" } },
+  /* 0xDD */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "paddusw", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "paddusw" } },
+  /* 0xDE */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "pmaxub", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "pmaxub" } },
+  /* 0xDF */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "pandn", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "pandn" } },
+  /* 0xE0 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "pavgb", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "pavgb" } },
+  /* 0xE1 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "psraw", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "psrqw" } },
+  /* 0xE2 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "psrad", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "psrad" } },
+  /* 0xE3 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "pavgw", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "pavgw" } },
+  /* 0xE4 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "pmulhuw", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "pmulhuw" } },
+  /* 0xE5 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "pmulhuw", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "pmulhw" } },
+  /* 0xE6 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "not used without prefix", true,
+    /* F2h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_PD, AM_NOT_USED, "cvtpd2dq" },
+    /* F3h */ { 0, IT_GENERIC, AM_V | OT_PD, AM_W | OT_DQ, AM_NOT_USED, "cvtdq2pd" },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_PD, AM_NOT_USED, "cvttpd2dq" } },
+  /* 0xE7 */ { 0, IT_GENERIC, AM_W | OT_Q, AM_V | OT_Q, AM_NOT_USED, "movntq", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_W | OT_DQ, AM_V | OT_DQ, AM_NOT_USED, "movntdq" } },
+  /* 0xE8 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "psubsb", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "psubsb" } },
+  /* 0xE9 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "psubsw", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "psubsw" } },
+  /* 0xEA */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "pminsw", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "pminsw" } },
+  /* 0xEB */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "por", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "por" } },
+  /* 0xEC */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "paddsb", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "paddsb" } },
+  /* 0xED */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "paddsw", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "paddsw" } },
+  /* 0xEE */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "pmaxsw", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "pmaxsw" } },
+  /* 0xEF */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "pxor", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "pxor" } },
+  /* 0xF0 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0xF1 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "psllw", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "psllw" } },
+  /* 0xF2 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "pslld", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "pslld" } },
+  /* 0xF3 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "psllq", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "psllq" } },
+  /* 0xF4 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "pmuludq", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "pmuludq" } },
+  /* 0xF5 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "pmaddwd", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "pmaddwd" } },
+  /* 0xF6 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "psadbw", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "psadbw" } },
+  /* 0xF7 */ { 0, IT_GENERIC, AM_P | OT_PI, AM_Q | OT_PI, AM_NOT_USED, "maskmovq", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "maskmovdqu" } },
+  /* 0xF8 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "psubb", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "psubb" } },
+  /* 0xF9 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "psubw", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "psubw" } },
+  /* 0xFA */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "psubd", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "psubd" } },
+  /* 0xFB */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "psubq", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "psubq" } },
+  /* 0xFC */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "paddb", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "paddb" } },
+  /* 0xFD */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "paddw", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "paddw" } },
+  /* 0xFE */ { 0, IT_GENERIC, AM_P | OT_Q, AM_Q | OT_Q, AM_NOT_USED, "paddd", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_V | OT_DQ, AM_W | OT_DQ, AM_NOT_USED, "paddd" } },
+  /* 0xFF */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }
+};
+
+const Opcode s_opcode_byte_after_0f00[] = {
+  /* 0x0 */ { 0, IT_GENERIC, AM_E | OT_W, AM_NOT_USED, AM_NOT_USED, "sldt", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x1 */ { 0, IT_GENERIC, AM_E | OT_W, AM_NOT_USED, AM_NOT_USED, "str", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x2 */ { 0, IT_GENERIC, AM_E | OT_W, AM_NOT_USED, AM_NOT_USED, "lldt", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x3 */ { 0, IT_GENERIC, AM_E | OT_W, AM_NOT_USED, AM_NOT_USED, "ltr", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x4 */ { 0, IT_GENERIC, AM_E | OT_W, AM_NOT_USED, AM_NOT_USED, "verr", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x5 */ { 0, IT_GENERIC, AM_E | OT_W, AM_NOT_USED, AM_NOT_USED, "verw", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x6 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x7 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }
+};
+
+const Opcode s_opcode_byte_after_0f01[] = {
+  /* 0x0 */ { 0, IT_GENERIC, AM_M | OT_S, AM_NOT_USED, AM_NOT_USED, "sgdt", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x1 */ { 0, IT_GENERIC, AM_M | OT_S, AM_NOT_USED, AM_NOT_USED, "sidt", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x2 */ { 0, IT_GENERIC, AM_M | OT_S, AM_NOT_USED, AM_NOT_USED, "lgdt", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x3 */ { 0, IT_GENERIC, AM_M | OT_S, AM_NOT_USED, AM_NOT_USED, "lidt", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x4 */ { 0, IT_GENERIC, AM_E | OT_W, AM_NOT_USED, AM_NOT_USED, "smsw", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x5 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x6 */ { 0, IT_GENERIC, AM_E | OT_W, AM_NOT_USED, AM_NOT_USED, "lmsw", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x7 */ { 0, IT_GENERIC, AM_M | OT_B, AM_NOT_USED, AM_NOT_USED, "invlpg", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }
+};
+
+const Opcode s_opcode_byte_after_0f18[] = {
+  /* 0x0 */ { 0, IT_GENERIC, AM_M | OT_ADDRESS_MODE_M, AM_NOT_USED, AM_NOT_USED, "prefetch", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x1 */ { 0, IT_GENERIC, AM_REGISTER | OT_D, AM_NOT_USED, AM_NOT_USED, "prefetch", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x2 */ { 0, IT_GENERIC, AM_REGISTER | OT_D, AM_NOT_USED, AM_NOT_USED, "prefetch", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x3 */ { 0, IT_GENERIC, AM_REGISTER | OT_D, AM_NOT_USED, AM_NOT_USED, "prefetch", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x4 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x5 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x6 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x7 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }
+};
+
+const Opcode s_opcode_byte_after_0f71[] = {
+  /* 0x0 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x1 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x2 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_I | OT_B, AM_NOT_USED, "psrlw", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_P | OT_DQ, AM_I | OT_B, AM_NOT_USED, "psrlw" } },
+  /* 0x3 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x4 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_I | OT_B, AM_NOT_USED, "psraw", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_P | OT_DQ, AM_I | OT_B, AM_NOT_USED, "psraw" } },
+  /* 0x5 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x6 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_I | OT_B, AM_NOT_USED, "psllw", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_P | OT_DQ, AM_I | OT_B, AM_NOT_USED, "psllw" } },
+  /* 0x7 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }
+};
+
+const Opcode s_opcode_byte_after_0f72[] = {
+  /* 0x0 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x1 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x2 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_I | OT_B, AM_NOT_USED, "psrld", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_W | OT_DQ, AM_I | OT_B, AM_NOT_USED, "psrld" } },
+  /* 0x3 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x4 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_I | OT_B, AM_NOT_USED, "psrad", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_W | OT_DQ, AM_I | OT_B, AM_NOT_USED, "psrad" } },
+  /* 0x5 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x6 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_I | OT_B, AM_NOT_USED, "pslld", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_W | OT_DQ, AM_I | OT_B, AM_NOT_USED, "pslld" } },
+  /* 0x7 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }
+};
+
+const Opcode s_opcode_byte_after_0f73[] = {
+  /* 0x0 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x1 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x2 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_I | OT_B, AM_NOT_USED, "psrlq", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_W | OT_DQ, AM_I | OT_B, AM_NOT_USED, "psrlq" } },
+  /* 0x3 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x4 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x5 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x6 */ { 0, IT_GENERIC, AM_P | OT_Q, AM_I | OT_B, AM_NOT_USED, "psllq", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_W | OT_DQ, AM_I | OT_B, AM_NOT_USED, "psllq" } },
+  /* 0x7 */ { 0, IT_GENERIC, AM_W | OT_DQ, AM_I | OT_B, AM_NOT_USED, "pslldq", true,
+    /* F2h */ { 0 },
+    /* F3h */ { 0 },
+    /* 66h */ { 0, IT_GENERIC, AM_W | OT_DQ, AM_I | OT_B, AM_NOT_USED, "pslldq" } },
+};
+
+const Opcode s_opcode_byte_after_0fae[] = {
+  /* 0x0 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "fxsave", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x1 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "fxrstor", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x2 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "ldmxcsr", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x3 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "stmxcsr", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x4 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x5 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "lfence", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x6 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "mfence", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x7 */ { 0, IT_GENERIC, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, "clflush/sfence", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+};
+
+const Opcode s_opcode_byte_after_0fba[] = {
+  /* 0x0 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x1 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x2 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x3 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x4 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "bt", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x5 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "bts", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x6 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "btr", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x7 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "btc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }
+};
+
+const Opcode s_opcode_byte_after_0fc7[] = {
+  /* 0x0 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x1 */ { 0, IT_GENERIC, AM_M | OT_Q, AM_NOT_USED, AM_NOT_USED, "cmpxch8b", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }
+};
+
+const Opcode s_opcode_byte_after_80[] = {
+  /* 0x0 */ { 0, IT_GENERIC, AM_E | OT_B, AM_I | OT_B, AM_NOT_USED, "add", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x1 */ { 0, IT_GENERIC, AM_E | OT_B, AM_I | OT_B, AM_NOT_USED, "or", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x2 */ { 0, IT_GENERIC, AM_E | OT_B, AM_I | OT_B, AM_NOT_USED, "adc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x3 */ { 0, IT_GENERIC, AM_E | OT_B, AM_I | OT_B, AM_NOT_USED, "sbb", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x4 */ { 0, IT_GENERIC, AM_E | OT_B, AM_I | OT_B, AM_NOT_USED, "and", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x5 */ { 0, IT_GENERIC, AM_E | OT_B, AM_I | OT_B, AM_NOT_USED, "sub", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x6 */ { 0, IT_GENERIC, AM_E | OT_B, AM_I | OT_B, AM_NOT_USED, "xor", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x7 */ { 0, IT_GENERIC, AM_E | OT_B, AM_I | OT_B, AM_NOT_USED, "cmp", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }
+};
+
+const Opcode s_opcode_byte_after_81[] = {
+  /* 0x0 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_V, AM_NOT_USED, "add", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x1 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_V, AM_NOT_USED, "or", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x2 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_V, AM_NOT_USED, "adc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x3 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_V, AM_NOT_USED, "sbb", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x4 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_V, AM_NOT_USED, "and", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x5 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_V, AM_NOT_USED, "sub", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x6 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_V, AM_NOT_USED, "xor", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x7 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_V, AM_NOT_USED, "cmp", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }
+};
+
+const Opcode s_opcode_byte_after_82[] = {
+  /* 0x0 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "add", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x1 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "or", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x2 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "adc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x3 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "sbb", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x4 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "and", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x5 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "sub", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x6 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "xor", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x7 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "cmp", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }
+};
+
+const Opcode s_opcode_byte_after_83[] = {
+  /* 0x0 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "add", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x1 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "or", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x2 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "adc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x3 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "sbb", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x4 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "and", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x5 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "sub", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x6 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "xor", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x7 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "cmp", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }
+};
+
+const Opcode s_opcode_byte_after_c0[] = {
+  /* 0x0 */ { 0, IT_GENERIC, AM_E | OT_B, AM_I | OT_B, AM_NOT_USED, "rol", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x1 */ { 0, IT_GENERIC, AM_E | OT_B, AM_I | OT_B, AM_NOT_USED, "ror", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x2 */ { 0, IT_GENERIC, AM_E | OT_B, AM_I | OT_B, AM_NOT_USED, "rcl", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x3 */ { 0, IT_GENERIC, AM_E | OT_B, AM_I | OT_B, AM_NOT_USED, "rcr", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x4 */ { 0, IT_GENERIC, AM_E | OT_B, AM_I | OT_B, AM_NOT_USED, "shl", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x5 */ { 0, IT_GENERIC, AM_E | OT_B, AM_I | OT_B, AM_NOT_USED, "shr", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x6 */ { 0, IT_GENERIC, AM_E | OT_B, AM_I | OT_B, AM_NOT_USED, "sal", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x7 */ { 0, IT_GENERIC, AM_E | OT_B, AM_I | OT_B, AM_NOT_USED, "sar", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }
+};
+
+const Opcode s_opcode_byte_after_c1[] = {
+  /* 0x0 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "rol", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x1 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "ror", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x2 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "rcl", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x3 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "rcr", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x4 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "shl", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x5 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "shr", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x6 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "sal", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x7 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_B, AM_NOT_USED, "sar", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }
+};
+
+const Opcode s_opcode_byte_after_d0[] = {
+  /* 0x0 */ { 0, IT_GENERIC, AM_E | OT_B, AM_IMPLICIT, AM_NOT_USED, "rol", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x1 */ { 0, IT_GENERIC, AM_E | OT_B, AM_IMPLICIT, AM_NOT_USED, "ror", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x2 */ { 0, IT_GENERIC, AM_E | OT_B, AM_IMPLICIT, AM_NOT_USED, "rcl", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x3 */ { 0, IT_GENERIC, AM_E | OT_B, AM_IMPLICIT, AM_NOT_USED, "rcr", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x4 */ { 0, IT_GENERIC, AM_E | OT_B, AM_IMPLICIT, AM_NOT_USED, "shl", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x5 */ { 0, IT_GENERIC, AM_E | OT_B, AM_IMPLICIT, AM_NOT_USED, "shr", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x6 */ { 0, IT_GENERIC, AM_E | OT_B, AM_IMPLICIT, AM_NOT_USED, "sal", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x7 */ { 0, IT_GENERIC, AM_E | OT_B, AM_IMPLICIT, AM_NOT_USED, "sar", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }
+};
+
+const Opcode s_opcode_byte_after_d1[] = {
+  /* 0x0 */ { 0, IT_GENERIC, AM_E | OT_V, AM_IMPLICIT, AM_NOT_USED, "rol", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x1 */ { 0, IT_GENERIC, AM_E | OT_V, AM_IMPLICIT, AM_NOT_USED, "ror", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x2 */ { 0, IT_GENERIC, AM_E | OT_V, AM_IMPLICIT, AM_NOT_USED, "rcl", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x3 */ { 0, IT_GENERIC, AM_E | OT_V, AM_IMPLICIT, AM_NOT_USED, "rcr", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x4 */ { 0, IT_GENERIC, AM_E | OT_V, AM_IMPLICIT, AM_NOT_USED, "shl", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x5 */ { 0, IT_GENERIC, AM_E | OT_V, AM_IMPLICIT, AM_NOT_USED, "shr", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x6 */ { 0, IT_GENERIC, AM_E | OT_V, AM_IMPLICIT, AM_NOT_USED, "sal", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x7 */ { 0, IT_GENERIC, AM_E | OT_V, AM_IMPLICIT, AM_NOT_USED, "sar", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }
+};
+
+const Opcode s_opcode_byte_after_d2[] = {
+  /* 0x0 */ { 0, IT_GENERIC, AM_E | OT_B, AM_REGISTER | OT_B, AM_NOT_USED, "rol", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x1 */ { 0, IT_GENERIC, AM_E | OT_B, AM_REGISTER | OT_B, AM_NOT_USED, "ror", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x2 */ { 0, IT_GENERIC, AM_E | OT_B, AM_REGISTER | OT_B, AM_NOT_USED, "rcl", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x3 */ { 0, IT_GENERIC, AM_E | OT_B, AM_REGISTER | OT_B, AM_NOT_USED, "rcr", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x4 */ { 0, IT_GENERIC, AM_E | OT_B, AM_REGISTER | OT_B, AM_NOT_USED, "shl", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x5 */ { 0, IT_GENERIC, AM_E | OT_B, AM_REGISTER | OT_B, AM_NOT_USED, "shr", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x6 */ { 0, IT_GENERIC, AM_E | OT_B, AM_REGISTER | OT_B, AM_NOT_USED, "sal", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x7 */ { 0, IT_GENERIC, AM_E | OT_B, AM_REGISTER | OT_B, AM_NOT_USED, "sar", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }
+};
+
+const Opcode s_opcode_byte_after_d3[] = {
+  /* 0x0 */ { 0, IT_GENERIC, AM_E | OT_V, AM_REGISTER | OT_B, AM_NOT_USED, "rol", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x1 */ { 0, IT_GENERIC, AM_E | OT_V, AM_REGISTER | OT_B, AM_NOT_USED, "ror", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x2 */ { 0, IT_GENERIC, AM_E | OT_V, AM_REGISTER | OT_B, AM_NOT_USED, "rcl", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x3 */ { 0, IT_GENERIC, AM_E | OT_V, AM_REGISTER | OT_B, AM_NOT_USED, "rcr", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x4 */ { 0, IT_GENERIC, AM_E | OT_V, AM_REGISTER | OT_B, AM_NOT_USED, "shl", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x5 */ { 0, IT_GENERIC, AM_E | OT_V, AM_REGISTER | OT_B, AM_NOT_USED, "shr", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x6 */ { 0, IT_GENERIC, AM_E | OT_V, AM_REGISTER | OT_B, AM_NOT_USED, "sal", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x7 */ { 0, IT_GENERIC, AM_E | OT_V, AM_REGISTER | OT_B, AM_NOT_USED, "sar", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }
+};
+
+const Opcode s_opcode_byte_after_f6[] = {
+  /* 0x0 */ { 0, IT_GENERIC, AM_E | OT_B, AM_I | OT_B, AM_NOT_USED, "test", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x1 */ { 0, IT_GENERIC, AM_E | OT_B, AM_I | OT_B, AM_NOT_USED, "test", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x2 */ { 0, IT_GENERIC, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, "not", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x3 */ { 0, IT_GENERIC, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, "neg", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x4 */ { 0, IT_GENERIC, OT_B | AM_REGISTER, AM_E | OT_B, AM_NOT_USED, "mul", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x5 */ { 0, IT_GENERIC, OT_B | AM_REGISTER, AM_E | OT_B, AM_NOT_USED, "imul", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x6 */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_E | OT_B, AM_NOT_USED, "div", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x7 */ { 0, IT_GENERIC, AM_REGISTER | OT_B, AM_E | OT_B, AM_NOT_USED, "idiv", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }
+};
+
+const Opcode s_opcode_byte_after_f7[] = {
+  /* 0x0 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_V, AM_NOT_USED, "test", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x1 */ { 0, IT_GENERIC, AM_E | OT_V, AM_I | OT_V, AM_NOT_USED, "test", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x2 */ { 0, IT_GENERIC, AM_E | OT_V, AM_NOT_USED, AM_NOT_USED, "not", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x3 */ { 0, IT_GENERIC, AM_E | OT_V, AM_NOT_USED, AM_NOT_USED, "neg", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x4 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_E | OT_V, AM_NOT_USED, "mul", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x5 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_E | OT_V, AM_NOT_USED, "imul", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x6 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_E | OT_V, AM_NOT_USED, "div", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x7 */ { 0, IT_GENERIC, AM_REGISTER | OT_V, AM_E | OT_V, AM_NOT_USED, "idiv", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }
+};
+
+const Opcode s_opcode_byte_after_fe[] = {
+  /* 0x0 */ { 0, IT_GENERIC, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, "inc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x1 */ { 0, IT_GENERIC, AM_E | OT_B, AM_NOT_USED, AM_NOT_USED, "dec", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }
+};
+
+const Opcode s_opcode_byte_after_ff[] = {
+  /* 0x0 */ { 0, IT_GENERIC, AM_E | OT_V, AM_NOT_USED, AM_NOT_USED, "inc", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x1 */ { 0, IT_GENERIC, AM_E | OT_V, AM_NOT_USED, AM_NOT_USED, "dec", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x2 */ { 0, IT_JUMP, AM_E | OT_V, AM_NOT_USED, AM_NOT_USED, "call", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x3 */ { 0, IT_JUMP, AM_E | OT_P, AM_NOT_USED, AM_NOT_USED, "call", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x4 */ { 0, IT_JUMP, AM_E | OT_V, AM_NOT_USED, AM_NOT_USED, "jmp", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x5 */ { 0, IT_JUMP, AM_E | OT_P, AM_NOT_USED, AM_NOT_USED, "jmp", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x6 */ { 0, IT_GENERIC, AM_E | OT_V, AM_NOT_USED, AM_NOT_USED, "push", false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } },
+  /* 0x7 */ { 0, IT_UNUSED, AM_NOT_USED, AM_NOT_USED, AM_NOT_USED, 0, false, /* F2h */ { 0 }, /* F3h */ { 0 }, /* 66h */ { 0 } }
+};
+
+/*
+* A table of all the other tables, containing some extra information, e.g.
+* how to mask out the byte we're looking at.
+*/
+const OpcodeTable MiniDisassembler::s_ia32_opcode_map_[]={
+  // One-byte opcodes and jumps to larger
+  /*  0 */ {s_first_opcode_byte, 0, 0xff, 0, 0xff},
+  // Two-byte opcodes (second byte)
+  /*  1 */ {s_opcode_byte_after_0f, 0, 0xff, 0, 0xff},
+  // Start of tables for opcodes using ModR/M bits as extension
+  /*  2 */ {s_opcode_byte_after_80, 3, 0x07, 0, 0x07},
+  /*  3 */ {s_opcode_byte_after_81, 3, 0x07, 0, 0x07}, 
+  /*  4 */ {s_opcode_byte_after_82, 3, 0x07, 0, 0x07}, 
+  /*  5 */ {s_opcode_byte_after_83, 3, 0x07, 0, 0x07}, 
+  /*  6 */ {s_opcode_byte_after_c0, 3, 0x07, 0, 0x07}, 
+  /*  7 */ {s_opcode_byte_after_c1, 3, 0x07, 0, 0x07}, 
+  /*  8 */ {s_opcode_byte_after_d0, 3, 0x07, 0, 0x07}, 
+  /*  9 */ {s_opcode_byte_after_d1, 3, 0x07, 0, 0x07}, 
+  /* 10 */ {s_opcode_byte_after_d2, 3, 0x07, 0, 0x07}, 
+  /* 11 */ {s_opcode_byte_after_d3, 3, 0x07, 0, 0x07}, 
+  /* 12 */ {s_opcode_byte_after_f6, 3, 0x07, 0, 0x07}, 
+  /* 13 */ {s_opcode_byte_after_f7, 3, 0x07, 0, 0x07}, 
+  /* 14 */ {s_opcode_byte_after_fe, 3, 0x07, 0, 0x01}, 
+  /* 15 */ {s_opcode_byte_after_ff, 3, 0x07, 0, 0x07}, 
+  /* 16 */ {s_opcode_byte_after_0f00, 3, 0x07, 0, 0x07}, 
+  /* 17 */ {s_opcode_byte_after_0f01, 3, 0x07, 0, 0x07}, 
+  /* 18 */ {s_opcode_byte_after_0f18, 3, 0x07, 0, 0x07}, 
+  /* 19 */ {s_opcode_byte_after_0f71, 3, 0x07, 0, 0x07}, 
+  /* 20 */ {s_opcode_byte_after_0f72, 3, 0x07, 0, 0x07}, 
+  /* 21 */ {s_opcode_byte_after_0f73, 3, 0x07, 0, 0x07}, 
+  /* 22 */ {s_opcode_byte_after_0fae, 3, 0x07, 0, 0x07}, 
+  /* 23 */ {s_opcode_byte_after_0fba, 3, 0x07, 0, 0x07}, 
+  /* 24 */ {s_opcode_byte_after_0fc7, 3, 0x07, 0, 0x01}
+};
+
+};  // namespace sidestep
diff --git a/src/windows/mingw.h b/src/windows/mingw.h
new file mode 100644
index 0000000..0586e62
--- /dev/null
+++ b/src/windows/mingw.h
@@ -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
+
+#define HAVE_SNPRINTF 1
+
+// 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
+
+#define HAVE_PID_T
+
+#include "windows/port.h"
+
+#endif  /* __MINGW32__ */
+
+#endif  /* GOOGLE_PERFTOOLS_WINDOWS_MINGW_H_ */
diff --git a/src/windows/mini_disassembler.cc b/src/windows/mini_disassembler.cc
new file mode 100644
index 0000000..0c62004
--- /dev/null
+++ b/src/windows/mini_disassembler.cc
@@ -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
diff --git a/src/windows/mini_disassembler.h b/src/windows/mini_disassembler.h
new file mode 100644
index 0000000..93bdc06
--- /dev/null
+++ b/src/windows/mini_disassembler.h
@@ -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_
diff --git a/src/windows/mini_disassembler_types.h b/src/windows/mini_disassembler_types.h
new file mode 100644
index 0000000..06d4755
--- /dev/null
+++ b/src/windows/mini_disassembler_types.h
@@ -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.
+  int flag_dest_;
+  int flag_source_;
+  int 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_
diff --git a/src/windows/nm-pdb.c b/src/windows/nm-pdb.c
new file mode 100644
index 0000000..95a080d
--- /dev/null
+++ b/src/windows/nm-pdb.c
@@ -0,0 +1,273 @@
+/* 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;
+}
diff --git a/src/windows/override_functions.cc b/src/windows/override_functions.cc
new file mode 100644
index 0000000..e7917d3
--- /dev/null
+++ b/src/windows/override_functions.cc
@@ -0,0 +1,123 @@
+// -*- 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* _recalloc(void* p, size_t n, size_t size) {
+  void* result = realloc(p, n * size);
+  memset(result, 0, n * size);
+  return result;
+}
+
+extern "C" void* _calloc_impl(size_t n, size_t size) {
+  return calloc(n, size);
+}
+
+extern "C" size_t _msize(void* p) {
+  return MallocExtension::instance()->GetAllocatedSize(p);
+}
+
+extern "C" intptr_t _get_heap_handle() {
+  return 0;
+}
+
+// The CRT heap initialization stub.
+extern "C" 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.
+extern "C" void _heap_term() {
+}
+
+extern "C" int _set_new_mode(int flag) {
+  return tc_set_new_mode(flag);
+}
+
+#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
+
+// 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.
+extern "C" void* _crtheap = reinterpret_cast<void*>(1);
diff --git a/src/windows/patch_functions.cc b/src/windows/patch_functions.cc
new file mode 100644
index 0000000..ff1bec7
--- /dev/null
+++ b/src/windows/patch_functions.cc
@@ -0,0 +1,1077 @@
+// 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
+//
+// The main purpose of this file is to patch the libc allocation
+// routines (malloc and friends, but also _msize and other
+// windows-specific libc-style routines).  However, we also patch
+// windows routines to do accounting.  We do better at the former than
+// the latter.  Here are some comments from Paul Pluzhnikov about what
+// it might take to do a really good job patching windows routines to
+// keep track of memory usage:
+//
+// "You should intercept at least the following:
+//     HeapCreate HeapDestroy HeapAlloc HeapReAlloc HeapFree
+//     RtlCreateHeap RtlDestroyHeap RtlAllocateHeap RtlFreeHeap
+//     malloc calloc realloc free
+//     malloc_dbg calloc_dbg realloc_dbg free_dbg
+// Some of these call the other ones (but not always), sometimes
+// recursively (i.e. HeapCreate may call HeapAlloc on a different
+// heap, IIRC)."
+//
+// Since Paul didn't mention VirtualAllocEx, he may not have even been
+// considering all the mmap-like functions that windows has (or he may
+// just be ignoring it because he's seen we already patch it).  Of the
+// above, we do not patch the *_dbg functions, and of the windows
+// functions, we only patch HeapAlloc and HeapFree.
+//
+// The *_dbg functions come into play with /MDd, /MTd, and /MLd,
+// probably.  It may be ok to just turn off tcmalloc in those cases --
+// if the user wants the windows debug malloc, they probably don't
+// want tcmalloc!  We should also test with all of /MD, /MT, and /ML,
+// which we're not currently doing.
+
+// TODO(csilvers): try to do better here?  Paul does conclude:
+//                 "Keeping track of all of this was a nightmare."
+
+#ifndef _WIN32
+# error You should only be including windows/patch_functions.cc in a windows environment!
+#endif
+
+#include <config.h>
+
+#ifdef WIN32_OVERRIDE_ALLOCATORS
+#error This file is intended for patching allocators - use override_functions.cc instead.
+#endif
+
+// We use psapi.  Non-MSVC systems will have to link this in themselves.
+#ifdef _MSC_VER
+#pragma comment(lib, "Psapi.lib")
+#endif
+
+// Make sure we always use the 'old' names of the psapi functions.
+#ifndef PSAPI_VERSION
+#define PSAPI_VERSION 1
+#endif
+
+#include <windows.h>
+#include <stdio.h>
+#include <malloc.h>       // for _msize and _expand
+#include <psapi.h>        // for EnumProcessModules, GetModuleInformation, etc.
+#include <set>
+#include <map>
+#include <vector>
+#include <base/logging.h>
+#include "base/spinlock.h"
+#include "gperftools/malloc_hook.h"
+#include "malloc_hook-inl.h"
+#include "preamble_patcher.h"
+
+// The maximum number of modules we allow to be in one executable
+const int kMaxModules = 8182;
+
+// These are hard-coded, unfortunately. :-( They are also probably
+// compiler specific.  See get_mangled_names.cc, in this directory,
+// for instructions on how to update these names for your compiler.
+const char kMangledNew[] = "??2@YAPAXI@Z";
+const char kMangledNewArray[] = "??_U@YAPAXI@Z";
+const char kMangledDelete[] = "??3@YAXPAX@Z";
+const char kMangledDeleteArray[] = "??_V@YAXPAX@Z";
+const char kMangledNewNothrow[] = "??2@YAPAXIABUnothrow_t@std@@@Z";
+const char kMangledNewArrayNothrow[] = "??_U@YAPAXIABUnothrow_t@std@@@Z";
+const char kMangledDeleteNothrow[] = "??3@YAXPAXABUnothrow_t@std@@@Z";
+const char kMangledDeleteArrayNothrow[] = "??_V@YAXPAXABUnothrow_t@std@@@Z";
+
+// This is an unused but exported symbol that we can use to tell the
+// MSVC linker to bring in libtcmalloc, via the /INCLUDE linker flag.
+// Without this, the linker will likely decide that libtcmalloc.dll
+// doesn't add anything to the executable (since it does all its work
+// through patching, which the linker can't see), and ignore it
+// entirely.  (The name 'tcmalloc' is already reserved for a
+// namespace.  I'd rather export a variable named "_tcmalloc", but I
+// couldn't figure out how to get that to work.  This function exports
+// the symbol "__tcmalloc".)
+extern "C" PERFTOOLS_DLL_DECL void _tcmalloc();
+void _tcmalloc() { }
+
+// This is the version needed for windows x64, which has a different
+// decoration scheme which doesn't auto-add a leading underscore.
+extern "C" PERFTOOLS_DLL_DECL void __tcmalloc();
+void __tcmalloc() { }
+
+namespace {    // most everything here is in an unnamed namespace
+
+typedef void (*GenericFnPtr)();
+
+using sidestep::PreamblePatcher;
+
+struct ModuleEntryCopy;   // defined below
+
+// These functions are how we override the memory allocation
+// functions, just like tcmalloc.cc and malloc_hook.cc do.
+
+// This is information about the routines we're patching, for a given
+// module that implements libc memory routines.  A single executable
+// can have several libc implementations running about (in different
+// .dll's), and we need to patch/unpatch them all.  This defines
+// everything except the new functions we're patching in, which
+// are defined in LibcFunctions, below.
+class LibcInfo {
+ public:
+  LibcInfo() {
+    memset(this, 0, sizeof(*this));  // easiest way to initialize the array
+  }
+
+  bool patched() const { return is_valid(); }
+  void set_is_valid(bool b) { is_valid_ = b; }
+  // According to http://msdn.microsoft.com/en-us/library/ms684229(VS.85).aspx:
+  // "The load address of a module (lpBaseOfDll) is the same as the HMODULE
+  // value."
+  HMODULE hmodule() const {
+    return reinterpret_cast<HMODULE>(const_cast<void*>(module_base_address_));
+  }
+
+  // Populates all the windows_fn_[] vars based on our module info.
+  // Returns false if windows_fn_ is all NULL's, because there's
+  // nothing to patch.  Also populates the rest of the module_entry
+  // info, such as the module's name.
+  bool PopulateWindowsFn(const ModuleEntryCopy& module_entry);
+
+ protected:
+  void CopyFrom(const LibcInfo& that) {
+    if (this == &that)
+      return;
+    this->is_valid_ = that.is_valid_;
+    memcpy(this->windows_fn_, that.windows_fn_, sizeof(windows_fn_));
+    this->module_base_address_ = that.module_base_address_;
+    this->module_base_size_ = that.module_base_size_;
+  }
+
+  enum {
+    kMalloc, kFree, kRealloc, kCalloc,
+    kNew, kNewArray, kDelete, kDeleteArray,
+    kNewNothrow, kNewArrayNothrow, kDeleteNothrow, kDeleteArrayNothrow,
+    // These are windows-only functions from malloc.h
+    k_Msize, k_Expand,
+    // A MS CRT "internal" function, implemented using _calloc_impl
+    k_CallocCrt,
+    kNumFunctions
+  };
+
+  // I'd like to put these together in a struct (perhaps in the
+  // subclass, so we can put in perftools_fn_ as well), but vc8 seems
+  // to have a bug where it doesn't initialize the struct properly if
+  // we try to take the address of a function that's not yet loaded
+  // from a dll, as is the common case for static_fn_.  So we need
+  // each to be in its own array. :-(
+  static const char* const function_name_[kNumFunctions];
+
+  // This function is only used when statically linking the binary.
+  // In that case, loading malloc/etc from the dll (via
+  // PatchOneModule) won't work, since there are no dlls.  Instead,
+  // you just want to be taking the address of malloc/etc directly.
+  // In the common, non-static-link case, these pointers will all be
+  // NULL, since this initializer runs before msvcrt.dll is loaded.
+  static const GenericFnPtr static_fn_[kNumFunctions];
+
+  // This is the address of the function we are going to patch
+  // (malloc, etc).  Other info about the function is in the
+  // patch-specific subclasses, below.
+  GenericFnPtr windows_fn_[kNumFunctions];
+
+  // This is set to true when this structure is initialized (because
+  // we're patching a new library) and set to false when it's
+  // uninitialized (because we've freed that library).
+  bool is_valid_;
+
+  const void *module_base_address_;
+  size_t module_base_size_;
+
+ public:
+  // These shouldn't have to be public, since only subclasses of
+  // LibcInfo need it, but they do.  Maybe something to do with
+  // templates.  Shrug.  I hide them down here so users won't see
+  // them. :-)  (OK, I also need to define ctrgProcAddress late.)
+  bool is_valid() const { return is_valid_; }
+  GenericFnPtr windows_fn(int ifunction) const {
+    return windows_fn_[ifunction];
+  }
+  // These three are needed by ModuleEntryCopy.
+  static const int ctrgProcAddress = kNumFunctions;
+  static GenericFnPtr static_fn(int ifunction) {
+    return static_fn_[ifunction];
+  }
+  static const char* const function_name(int ifunction) {
+    return function_name_[ifunction];
+  }
+};
+
+// Template trickiness: logically, a LibcInfo would include
+// Windows_malloc_, origstub_malloc_, and Perftools_malloc_: for a
+// given module, these three go together.  And in fact,
+// Perftools_malloc_ may need to call origstub_malloc_, which means we
+// either need to change Perftools_malloc_ to take origstub_malloc_ as
+// an argument -- unfortunately impossible since it needs to keep the
+// same API as normal malloc -- or we need to write a different
+// version of Perftools_malloc_ for each LibcInfo instance we create.
+// We choose the second route, and use templates to implement it (we
+// could have also used macros).  So to get multiple versions
+// of the struct, we say "struct<1> var1; struct<2> var2;".  The price
+// we pay is some code duplication, and more annoying, each instance
+// of this var is a separate type.
+template<int> class LibcInfoWithPatchFunctions : public LibcInfo {
+ public:
+  // me_info should have had PopulateWindowsFn() called on it, so the
+  // module_* vars and windows_fn_ are set up.
+  bool Patch(const LibcInfo& me_info);
+  void Unpatch();
+
+ private:
+  // This holds the original function contents after we patch the function.
+  // This has to be defined static in the subclass, because the perftools_fns
+  // reference origstub_fn_.
+  static GenericFnPtr origstub_fn_[kNumFunctions];
+
+  // This is the function we want to patch in
+  static const GenericFnPtr perftools_fn_[kNumFunctions];
+
+  static void* Perftools_malloc(size_t size) __THROW;
+  static void Perftools_free(void* ptr) __THROW;
+  static void* Perftools_realloc(void* ptr, size_t size) __THROW;
+  static void* Perftools_calloc(size_t nmemb, size_t size) __THROW;
+  static void* Perftools_new(size_t size);
+  static void* Perftools_newarray(size_t size);
+  static void Perftools_delete(void *ptr);
+  static void Perftools_deletearray(void *ptr);
+  static void* Perftools_new_nothrow(size_t size,
+                                     const std::nothrow_t&) __THROW;
+  static void* Perftools_newarray_nothrow(size_t size,
+                                          const std::nothrow_t&) __THROW;
+  static void Perftools_delete_nothrow(void *ptr,
+                                       const std::nothrow_t&) __THROW;
+  static void Perftools_deletearray_nothrow(void *ptr,
+                                            const std::nothrow_t&) __THROW;
+  static size_t Perftools__msize(void *ptr) __THROW;
+  static void* Perftools__expand(void *ptr, size_t size) __THROW;
+  // malloc.h also defines these functions:
+  //   _aligned_malloc, _aligned_free,
+  //   _recalloc, _aligned_offset_malloc, _aligned_realloc, _aligned_recalloc
+  //   _aligned_offset_realloc, _aligned_offset_recalloc, _malloca, _freea
+  // But they seem pretty obscure, and I'm fine not overriding them for now.
+  // It may be they all call into malloc/free anyway.
+};
+
+// This is a subset of MODDULEENTRY32, that we need for patching.
+struct ModuleEntryCopy {
+  LPVOID  modBaseAddr;     // the same as hmodule
+  DWORD   modBaseSize;
+  // This is not part of MODDULEENTRY32, but is needed to avoid making
+  // windows syscalls while we're holding patch_all_modules_lock (see
+  // lock-inversion comments at patch_all_modules_lock definition, below).
+  GenericFnPtr rgProcAddresses[LibcInfo::ctrgProcAddress];
+
+  ModuleEntryCopy() {
+    modBaseAddr = NULL;
+    modBaseSize = 0;
+    for (int i = 0; i < sizeof(rgProcAddresses)/sizeof(*rgProcAddresses); i++)
+      rgProcAddresses[i] = LibcInfo::static_fn(i);
+  }
+  ModuleEntryCopy(const MODULEINFO& mi) {
+    this->modBaseAddr = mi.lpBaseOfDll;
+    this->modBaseSize = mi.SizeOfImage;
+    LPVOID modEndAddr = (char*)mi.lpBaseOfDll + mi.SizeOfImage;
+    for (int i = 0; i < sizeof(rgProcAddresses)/sizeof(*rgProcAddresses); i++) {
+      FARPROC target = ::GetProcAddress(
+          reinterpret_cast<const HMODULE>(mi.lpBaseOfDll),
+          LibcInfo::function_name(i));
+      // Sometimes a DLL forwards a function to a function in another
+      // DLL.  We don't want to patch those forwarded functions --
+      // they'll get patched when the other DLL is processed.
+      if (target >= modBaseAddr && target < modEndAddr)
+        rgProcAddresses[i] = (GenericFnPtr)target;
+      else
+        rgProcAddresses[i] = (GenericFnPtr)NULL;
+    }
+  }
+};
+
+// This class is easier because there's only one of them.
+class WindowsInfo {
+ public:
+  void Patch();
+  void Unpatch();
+
+ private:
+  // TODO(csilvers): should we be patching GlobalAlloc/LocalAlloc instead,
+  //                 for pre-XP systems?
+  enum {
+    kHeapAlloc, kHeapFree, kVirtualAllocEx, kVirtualFreeEx,
+    kMapViewOfFileEx, kUnmapViewOfFile, kLoadLibraryExW, kFreeLibrary,
+    kNumFunctions
+  };
+
+  struct FunctionInfo {
+    const char* const name;          // name of fn in a module (eg "malloc")
+    GenericFnPtr windows_fn;         // the fn whose name we call (&malloc)
+    GenericFnPtr origstub_fn;        // original fn contents after we patch
+    const GenericFnPtr perftools_fn; // fn we want to patch in
+  };
+
+  static FunctionInfo function_info_[kNumFunctions];
+
+  // A Windows-API equivalent of malloc and free
+  static LPVOID WINAPI Perftools_HeapAlloc(HANDLE hHeap, DWORD dwFlags,
+                                           DWORD_PTR dwBytes);
+  static BOOL WINAPI Perftools_HeapFree(HANDLE hHeap, DWORD dwFlags,
+                                        LPVOID lpMem);
+  // A Windows-API equivalent of mmap and munmap, for "anonymous regions"
+  static LPVOID WINAPI Perftools_VirtualAllocEx(HANDLE process, LPVOID address,
+                                                SIZE_T size, DWORD type,
+                                                DWORD protect);
+  static BOOL WINAPI Perftools_VirtualFreeEx(HANDLE process, LPVOID address,
+                                             SIZE_T size, DWORD type);
+  // A Windows-API equivalent of mmap and munmap, for actual files
+  static LPVOID WINAPI Perftools_MapViewOfFileEx(HANDLE hFileMappingObject,
+                                                 DWORD dwDesiredAccess,
+                                                 DWORD dwFileOffsetHigh,
+                                                 DWORD dwFileOffsetLow,
+                                                 SIZE_T dwNumberOfBytesToMap,
+                                                 LPVOID lpBaseAddress);
+  static BOOL WINAPI Perftools_UnmapViewOfFile(LPCVOID lpBaseAddress);
+  // We don't need the other 3 variants because they all call this one. */
+  static HMODULE WINAPI Perftools_LoadLibraryExW(LPCWSTR lpFileName,
+                                                 HANDLE hFile,
+                                                 DWORD dwFlags);
+  static BOOL WINAPI Perftools_FreeLibrary(HMODULE hLibModule);
+};
+
+// If you run out, just add a few more to the array.  You'll also need
+// to update the switch statement in PatchOneModule(), and the list in
+// UnpatchWindowsFunctions().
+// main_executable and main_executable_windows are two windows into
+// the same executable.  One is responsible for patching the libc
+// routines that live in the main executable (if any) to use tcmalloc;
+// the other is responsible for patching the windows routines like
+// HeapAlloc/etc to use tcmalloc.
+static LibcInfoWithPatchFunctions<0> main_executable;
+static LibcInfoWithPatchFunctions<1> libc1;
+static LibcInfoWithPatchFunctions<2> libc2;
+static LibcInfoWithPatchFunctions<3> libc3;
+static LibcInfoWithPatchFunctions<4> libc4;
+static LibcInfoWithPatchFunctions<5> libc5;
+static LibcInfoWithPatchFunctions<6> libc6;
+static LibcInfoWithPatchFunctions<7> libc7;
+static LibcInfoWithPatchFunctions<8> libc8;
+static LibcInfo* g_module_libcs[] = {
+  &libc1, &libc2, &libc3, &libc4, &libc5, &libc6, &libc7, &libc8
+};
+static WindowsInfo main_executable_windows;
+
+const char* const LibcInfo::function_name_[] = {
+  "malloc", "free", "realloc", "calloc",
+  kMangledNew, kMangledNewArray, kMangledDelete, kMangledDeleteArray,
+  // Ideally we should patch the nothrow versions of new/delete, but
+  // at least in msvcrt, nothrow-new machine-code is of a type we
+  // can't patch.  Since these are relatively rare, I'm hoping it's ok
+  // not to patch them.  (NULL name turns off patching.)
+  NULL,  // kMangledNewNothrow,
+  NULL,  // kMangledNewArrayNothrow,
+  NULL,  // kMangledDeleteNothrow,
+  NULL,  // kMangledDeleteArrayNothrow,
+  "_msize", "_expand", "_calloc_crt",
+};
+
+// For mingw, I can't patch the new/delete here, because the
+// instructions are too small to patch.  Luckily, they're so small
+// because all they do is call into malloc/free, so they still end up
+// calling tcmalloc routines, and we don't actually lose anything
+// (except maybe some stacktrace goodness) by not patching.
+const GenericFnPtr LibcInfo::static_fn_[] = {
+  (GenericFnPtr)&::malloc,
+  (GenericFnPtr)&::free,
+  (GenericFnPtr)&::realloc,
+  (GenericFnPtr)&::calloc,
+#ifdef __MINGW32__
+  NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+#else
+  (GenericFnPtr)(void*(*)(size_t))&::operator new,
+  (GenericFnPtr)(void*(*)(size_t))&::operator new[],
+  (GenericFnPtr)(void(*)(void*))&::operator delete,
+  (GenericFnPtr)(void(*)(void*))&::operator delete[],
+  (GenericFnPtr)
+  (void*(*)(size_t, struct std::nothrow_t const &))&::operator new,
+  (GenericFnPtr)
+  (void*(*)(size_t, struct std::nothrow_t const &))&::operator new[],
+  (GenericFnPtr)
+  (void(*)(void*, struct std::nothrow_t const &))&::operator delete,
+  (GenericFnPtr)
+  (void(*)(void*, struct std::nothrow_t const &))&::operator delete[],
+#endif
+  (GenericFnPtr)&::_msize,
+  (GenericFnPtr)&::_expand,
+  (GenericFnPtr)&::calloc,
+};
+
+template<int T> GenericFnPtr LibcInfoWithPatchFunctions<T>::origstub_fn_[] = {
+  // This will get filled in at run-time, as patching is done.
+};
+
+template<int T>
+const GenericFnPtr LibcInfoWithPatchFunctions<T>::perftools_fn_[] = {
+  (GenericFnPtr)&Perftools_malloc,
+  (GenericFnPtr)&Perftools_free,
+  (GenericFnPtr)&Perftools_realloc,
+  (GenericFnPtr)&Perftools_calloc,
+  (GenericFnPtr)&Perftools_new,
+  (GenericFnPtr)&Perftools_newarray,
+  (GenericFnPtr)&Perftools_delete,
+  (GenericFnPtr)&Perftools_deletearray,
+  (GenericFnPtr)&Perftools_new_nothrow,
+  (GenericFnPtr)&Perftools_newarray_nothrow,
+  (GenericFnPtr)&Perftools_delete_nothrow,
+  (GenericFnPtr)&Perftools_deletearray_nothrow,
+  (GenericFnPtr)&Perftools__msize,
+  (GenericFnPtr)&Perftools__expand,
+  (GenericFnPtr)&Perftools_calloc,
+};
+
+/*static*/ WindowsInfo::FunctionInfo WindowsInfo::function_info_[] = {
+  { "HeapAlloc", NULL, NULL, (GenericFnPtr)&Perftools_HeapAlloc },
+  { "HeapFree", NULL, NULL, (GenericFnPtr)&Perftools_HeapFree },
+  { "VirtualAllocEx", NULL, NULL, (GenericFnPtr)&Perftools_VirtualAllocEx },
+  { "VirtualFreeEx", NULL, NULL, (GenericFnPtr)&Perftools_VirtualFreeEx },
+  { "MapViewOfFileEx", NULL, NULL, (GenericFnPtr)&Perftools_MapViewOfFileEx },
+  { "UnmapViewOfFile", NULL, NULL, (GenericFnPtr)&Perftools_UnmapViewOfFile },
+  { "LoadLibraryExW", NULL, NULL, (GenericFnPtr)&Perftools_LoadLibraryExW },
+  { "FreeLibrary", NULL, NULL, (GenericFnPtr)&Perftools_FreeLibrary },
+};
+
+bool LibcInfo::PopulateWindowsFn(const ModuleEntryCopy& module_entry) {
+  // First, store the location of the function to patch before
+  // patching it.  If none of these functions are found in the module,
+  // then this module has no libc in it, and we just return false.
+  for (int i = 0; i < kNumFunctions; i++) {
+    if (!function_name_[i])     // we can turn off patching by unsetting name
+      continue;
+    // The ::GetProcAddress calls were done in the ModuleEntryCopy
+    // constructor, so we don't have to make any windows calls here.
+    const GenericFnPtr fn = module_entry.rgProcAddresses[i];
+    if (fn) {
+      windows_fn_[i] = PreamblePatcher::ResolveTarget(fn);
+    }
+  }
+
+  // Some modules use the same function pointer for new and new[].  If
+  // we find that, set one of the pointers to NULL so we don't double-
+  // patch.  Same may happen with new and nothrow-new, or even new[]
+  // and nothrow-new.  It's easiest just to check each fn-ptr against
+  // every other.
+  for (int i = 0; i < kNumFunctions; i++) {
+    for (int j = i+1; j < kNumFunctions; j++) {
+      if (windows_fn_[i] == windows_fn_[j]) {
+        // We NULL the later one (j), so as to minimize the chances we
+        // NULL kFree and kRealloc.  See comments below.  This is fragile!
+        windows_fn_[j] = NULL;
+      }
+    }
+  }
+
+  // There's always a chance that our module uses the same function
+  // as another module that we've already loaded.  In that case, we
+  // need to set our windows_fn to NULL, to avoid double-patching.
+  for (int ifn = 0; ifn < kNumFunctions; ifn++) {
+    for (int imod = 0;
+         imod < sizeof(g_module_libcs)/sizeof(*g_module_libcs);  imod++) {
+      if (g_module_libcs[imod]->is_valid() &&
+          this->windows_fn(ifn) == g_module_libcs[imod]->windows_fn(ifn)) {
+        windows_fn_[ifn] = NULL;
+      }
+    }
+  }
+
+  bool found_non_null = false;
+  for (int i = 0; i < kNumFunctions; i++) {
+    if (windows_fn_[i])
+      found_non_null = true;
+  }
+  if (!found_non_null)
+    return false;
+
+  // It's important we didn't NULL out windows_fn_[kFree] or [kRealloc].
+  // The reason is, if those are NULL-ed out, we'll never patch them
+  // and thus never get an origstub_fn_ value for them, and when we
+  // try to call origstub_fn_[kFree/kRealloc] in Perftools_free and
+  // Perftools_realloc, below, it will fail.  We could work around
+  // that by adding a pointer from one patch-unit to the other, but we
+  // haven't needed to yet.
+  CHECK(windows_fn_[kFree]);
+  CHECK(windows_fn_[kRealloc]);
+
+  // OK, we successfully populated.  Let's store our member information.
+  module_base_address_ = module_entry.modBaseAddr;
+  module_base_size_ = module_entry.modBaseSize;
+  return true;
+}
+
+template<int T>
+bool LibcInfoWithPatchFunctions<T>::Patch(const LibcInfo& me_info) {
+  CopyFrom(me_info);   // copies the module_entry and the windows_fn_ array
+  for (int i = 0; i < kNumFunctions; i++) {
+    if (windows_fn_[i] && windows_fn_[i] != perftools_fn_[i]) {
+      // if origstub_fn_ is not NULL, it's left around from a previous
+      // patch.  We need to set it to NULL for the new Patch call.
+      //
+      // Note that origstub_fn_ was logically freed by
+      // PreamblePatcher::Unpatch, so we don't have to do anything
+      // about it.
+      origstub_fn_[i] = NULL;   // Patch() will fill this in
+      CHECK_EQ(sidestep::SIDESTEP_SUCCESS,
+               PreamblePatcher::Patch(windows_fn_[i], perftools_fn_[i],
+                                      &origstub_fn_[i]));
+    }
+  }
+  set_is_valid(true);
+  return true;
+}
+
+template<int T>
+void LibcInfoWithPatchFunctions<T>::Unpatch() {
+  // We have to cast our GenericFnPtrs to void* for unpatch.  This is
+  // contra the C++ spec; we use C-style casts to empahsize that.
+  for (int i = 0; i < kNumFunctions; i++) {
+    if (windows_fn_[i])
+      CHECK_EQ(sidestep::SIDESTEP_SUCCESS,
+               PreamblePatcher::Unpatch((void*)windows_fn_[i],
+                                        (void*)perftools_fn_[i],
+                                        (void*)origstub_fn_[i]));
+  }
+  set_is_valid(false);
+}
+
+void WindowsInfo::Patch() {
+  HMODULE hkernel32 = ::GetModuleHandleA("kernel32");
+  CHECK_NE(hkernel32, NULL);
+
+  // Unlike for libc, we know these exist in our module, so we can get
+  // and patch at the same time.
+  for (int i = 0; i < kNumFunctions; i++) {
+    function_info_[i].windows_fn = (GenericFnPtr)
+        ::GetProcAddress(hkernel32, function_info_[i].name);
+    // If origstub_fn is not NULL, it's left around from a previous
+    // patch.  We need to set it to NULL for the new Patch call.
+    // Since we've patched Unpatch() not to delete origstub_fn_ (it
+    // causes problems in some contexts, though obviously not this
+    // one), we should delete it now, before setting it to NULL.
+    // 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++.
+    delete[] (char*)(function_info_[i].origstub_fn);
+    function_info_[i].origstub_fn = NULL;  // Patch() will fill this in
+    CHECK_EQ(sidestep::SIDESTEP_SUCCESS,
+             PreamblePatcher::Patch(function_info_[i].windows_fn,
+                                    function_info_[i].perftools_fn,
+                                    &function_info_[i].origstub_fn));
+  }
+}
+
+void WindowsInfo::Unpatch() {
+  // We have to cast our GenericFnPtrs to void* for unpatch.  This is
+  // contra the C++ spec; we use C-style casts to empahsize that.
+  for (int i = 0; i < kNumFunctions; i++) {
+    CHECK_EQ(sidestep::SIDESTEP_SUCCESS,
+             PreamblePatcher::Unpatch((void*)function_info_[i].windows_fn,
+                                      (void*)function_info_[i].perftools_fn,
+                                      (void*)function_info_[i].origstub_fn));
+  }
+}
+
+// You should hold the patch_all_modules_lock when calling this.
+void PatchOneModuleLocked(const LibcInfo& me_info) {
+  // If we don't already have info on this module, let's add it.  This
+  // is where we're sad that each libcX has a different type, so we
+  // can't use an array; instead, we have to use a switch statement.
+  // Patch() returns false if there were no libc functions in the module.
+  for (int i = 0; i < sizeof(g_module_libcs)/sizeof(*g_module_libcs); i++) {
+    if (!g_module_libcs[i]->is_valid()) {   // found an empty spot to add!
+      switch (i) {
+        case 0: libc1.Patch(me_info); return;
+        case 1: libc2.Patch(me_info); return;
+        case 2: libc3.Patch(me_info); return;
+        case 3: libc4.Patch(me_info); return;
+        case 4: libc5.Patch(me_info); return;
+        case 5: libc6.Patch(me_info); return;
+        case 6: libc7.Patch(me_info); return;
+        case 7: libc8.Patch(me_info); return;
+      }
+    }
+  }
+  printf("PERFTOOLS ERROR: Too many modules containing libc in this executable\n");
+}
+
+void PatchMainExecutableLocked() {
+  if (main_executable.patched())
+    return;    // main executable has already been patched
+  ModuleEntryCopy fake_module_entry;   // make a fake one to pass into Patch()
+  // No need to call PopulateModuleEntryProcAddresses on the main executable.
+  main_executable.PopulateWindowsFn(fake_module_entry);
+  main_executable.Patch(main_executable);
+}
+
+// This lock is subject to a subtle and annoying lock inversion
+// problem: it may interact badly with unknown internal windows locks.
+// In particular, windows may be holding a lock when it calls
+// LoadLibraryExW and FreeLibrary, which we've patched.  We have those
+// routines call PatchAllModules, which acquires this lock.  If we
+// make windows system calls while holding this lock, those system
+// calls may need the internal windows locks that are being held in
+// the call to LoadLibraryExW, resulting in deadlock.  The solution is
+// to be very careful not to call *any* windows routines while holding
+// patch_all_modules_lock, inside PatchAllModules().
+static SpinLock patch_all_modules_lock(SpinLock::LINKER_INITIALIZED);
+
+// last_loaded: The set of modules that were loaded the last time
+// PatchAllModules was called.  This is an optimization for only
+// looking at modules that were added or removed from the last call.
+static std::set<HMODULE> *g_last_loaded;
+
+// Iterates over all the modules currently loaded by the executable,
+// according to windows, and makes sure they're all patched.  Most
+// modules will already be in loaded_modules, meaning we have already
+// loaded and either patched them or determined they did not need to
+// be patched.  Others will not, which means we need to patch them
+// (if necessary).  Finally, we have to go through the existing
+// g_module_libcs and see if any of those are *not* in the modules
+// currently loaded by the executable.  If so, we need to invalidate
+// them.  Returns true if we did any work (patching or invalidating),
+// false if we were a noop.  May update loaded_modules as well.
+// NOTE: you must hold the patch_all_modules_lock to access loaded_modules.
+bool PatchAllModules() {
+  std::vector<ModuleEntryCopy> modules;
+  bool made_changes = false;
+
+  const HANDLE hCurrentProcess = GetCurrentProcess();
+  DWORD num_modules = 0;
+  HMODULE hModules[kMaxModules];  // max # of modules we support in one process
+  if (!::EnumProcessModules(hCurrentProcess, hModules, sizeof(hModules),
+                            &num_modules)) {
+    num_modules = 0;
+  }
+  // EnumProcessModules actually set the bytes written into hModules,
+  // so we need to divide to make num_modules actually be a module-count.
+  num_modules /= sizeof(*hModules);
+  if (num_modules >= kMaxModules) {
+    printf("PERFTOOLS ERROR: Too many modules in this executable to try"
+           " to patch them all (if you need to, raise kMaxModules in"
+           " patch_functions.cc).\n");
+    num_modules = kMaxModules;
+  }
+
+  // Now we handle the unpatching of modules we have in g_module_libcs
+  // but that were not found in EnumProcessModules.  We need to
+  // invalidate them.  To speed that up, we store the EnumProcessModules
+  // output in a set.
+  // At the same time, we prepare for the adding of new modules, by
+  // removing from hModules all the modules we know we've already
+  // patched (or decided don't need to be patched).  At the end,
+  // hModules will hold only the modules that we need to consider patching.
+  std::set<HMODULE> currently_loaded_modules;
+  {
+    SpinLockHolder h(&patch_all_modules_lock);
+    if (!g_last_loaded)  g_last_loaded = new std::set<HMODULE>;
+    // At the end of this loop, currently_loaded_modules contains the
+    // full list of EnumProcessModules, and hModules just the ones we
+    // haven't handled yet.
+    for (int i = 0; i < num_modules; ) {
+      currently_loaded_modules.insert(hModules[i]);
+      if (g_last_loaded->count(hModules[i]) > 0) {
+        hModules[i] = hModules[--num_modules];  // replace element i with tail
+      } else {
+        i++;                                    // keep element i
+      }
+    }
+    // Now we do the unpatching/invalidation.
+    for (int i = 0; i < sizeof(g_module_libcs)/sizeof(*g_module_libcs); i++) {
+      if (g_module_libcs[i]->patched() &&
+          currently_loaded_modules.count(g_module_libcs[i]->hmodule()) == 0) {
+        // Means g_module_libcs[i] is no longer loaded (no me32 matched).
+        // We could call Unpatch() here, but why bother?  The module
+        // has gone away, so nobody is going to call into it anyway.
+        g_module_libcs[i]->set_is_valid(false);
+        made_changes = true;
+      }
+    }
+    // Update the loaded module cache.
+    g_last_loaded->swap(currently_loaded_modules);
+  }
+
+  // Now that we know what modules are new, let's get the info we'll
+  // need to patch them.  Note this *cannot* be done while holding the
+  // lock, since it needs to make windows calls (see the lock-inversion
+  // comments before the definition of patch_all_modules_lock).
+  MODULEINFO mi;
+  for (int i = 0; i < num_modules; i++) {
+    if (::GetModuleInformation(hCurrentProcess, hModules[i], &mi, sizeof(mi)))
+      modules.push_back(ModuleEntryCopy(mi));
+  }
+
+  // Now we can do the patching of new modules.
+  {
+    SpinLockHolder h(&patch_all_modules_lock);
+    for (std::vector<ModuleEntryCopy>::iterator it = modules.begin();
+         it != modules.end(); ++it) {
+      LibcInfo libc_info;
+      if (libc_info.PopulateWindowsFn(*it)) { // true==module has libc routines
+        PatchOneModuleLocked(libc_info);
+        made_changes = true;
+      }
+    }
+
+    // Now that we've dealt with the modules (dlls), update the main
+    // executable.  We do this last because PatchMainExecutableLocked
+    // wants to look at how other modules were patched.
+    if (!main_executable.patched()) {
+      PatchMainExecutableLocked();
+      made_changes = true;
+    }
+  }
+  // TODO(csilvers): for this to be reliable, we need to also take
+  // into account if we *would* have patched any modules had they not
+  // already been loaded.  (That is, made_changes should ignore
+  // g_last_loaded.)
+  return made_changes;
+}
+
+
+}  // end unnamed namespace
+
+// ---------------------------------------------------------------------
+// Now that we've done all the patching machinery, let's actually
+// define the functions we're patching in.  Mostly these are
+// simple wrappers around the do_* routines in tcmalloc.cc.
+//
+// In fact, we #include tcmalloc.cc to get at the tcmalloc internal
+// do_* functions, the better to write our own hook functions.
+// U-G-L-Y, I know.  But the alternatives are, perhaps, worse.  This
+// also lets us define _msize(), _expand(), and other windows-specific
+// functions here, using tcmalloc internals, without polluting
+// tcmalloc.cc.
+// -------------------------------------------------------------------
+
+// TODO(csilvers): refactor tcmalloc.cc into two files, so I can link
+// against the file with do_malloc, and ignore the one with malloc.
+#include "tcmalloc.cc"
+
+template<int T>
+void* LibcInfoWithPatchFunctions<T>::Perftools_malloc(size_t size) __THROW {
+  void* result = do_malloc_or_cpp_alloc(size);
+  MallocHook::InvokeNewHook(result, size);
+  return result;
+}
+
+template<int T>
+void LibcInfoWithPatchFunctions<T>::Perftools_free(void* ptr) __THROW {
+  MallocHook::InvokeDeleteHook(ptr);
+  // This calls the windows free if do_free decides ptr was not
+  // allocated by tcmalloc.  Note it calls the origstub_free from
+  // *this* templatized instance of LibcInfo.  See "template
+  // trickiness" above.
+  do_free_with_callback(ptr, (void (*)(void*))origstub_fn_[kFree]);
+}
+
+template<int T>
+void* LibcInfoWithPatchFunctions<T>::Perftools_realloc(
+    void* old_ptr, size_t new_size) __THROW {
+  if (old_ptr == NULL) {
+    void* result = do_malloc_or_cpp_alloc(new_size);
+    MallocHook::InvokeNewHook(result, new_size);
+    return result;
+  }
+  if (new_size == 0) {
+    MallocHook::InvokeDeleteHook(old_ptr);
+    do_free_with_callback(old_ptr,
+                          (void (*)(void*))origstub_fn_[kFree]);
+    return NULL;
+  }
+  return do_realloc_with_callback(
+      old_ptr, new_size,
+      (void (*)(void*))origstub_fn_[kFree],
+      (size_t (*)(const void*))origstub_fn_[k_Msize]);
+}
+
+template<int T>
+void* LibcInfoWithPatchFunctions<T>::Perftools_calloc(
+    size_t n, size_t elem_size) __THROW {
+  void* result = do_calloc(n, elem_size);
+  MallocHook::InvokeNewHook(result, n * elem_size);
+  return result;
+}
+
+template<int T>
+void* LibcInfoWithPatchFunctions<T>::Perftools_new(size_t size) {
+  void* p = cpp_alloc(size, false);
+  MallocHook::InvokeNewHook(p, size);
+  return p;
+}
+
+template<int T>
+void* LibcInfoWithPatchFunctions<T>::Perftools_newarray(size_t size) {
+  void* p = cpp_alloc(size, false);
+  MallocHook::InvokeNewHook(p, size);
+  return p;
+}
+
+template<int T>
+void LibcInfoWithPatchFunctions<T>::Perftools_delete(void *p) {
+  MallocHook::InvokeDeleteHook(p);
+  do_free_with_callback(p, (void (*)(void*))origstub_fn_[kFree]);
+}
+
+template<int T>
+void LibcInfoWithPatchFunctions<T>::Perftools_deletearray(void *p) {
+  MallocHook::InvokeDeleteHook(p);
+  do_free_with_callback(p, (void (*)(void*))origstub_fn_[kFree]);
+}
+
+template<int T>
+void* LibcInfoWithPatchFunctions<T>::Perftools_new_nothrow(
+    size_t size, const std::nothrow_t&) __THROW {
+  void* p = cpp_alloc(size, true);
+  MallocHook::InvokeNewHook(p, size);
+  return p;
+}
+
+template<int T>
+void* LibcInfoWithPatchFunctions<T>::Perftools_newarray_nothrow(
+    size_t size, const std::nothrow_t&) __THROW {
+  void* p = cpp_alloc(size, true);
+  MallocHook::InvokeNewHook(p, size);
+  return p;
+}
+
+template<int T>
+void LibcInfoWithPatchFunctions<T>::Perftools_delete_nothrow(
+    void *p, const std::nothrow_t&) __THROW {
+  MallocHook::InvokeDeleteHook(p);
+  do_free_with_callback(p, (void (*)(void*))origstub_fn_[kFree]);
+}
+
+template<int T>
+void LibcInfoWithPatchFunctions<T>::Perftools_deletearray_nothrow(
+    void *p, const std::nothrow_t&) __THROW {
+  MallocHook::InvokeDeleteHook(p);
+  do_free_with_callback(p, (void (*)(void*))origstub_fn_[kFree]);
+}
+
+
+// _msize() lets you figure out how much space is reserved for a
+// pointer, in Windows.  Even if applications don't call it, any DLL
+// with global constructors will call (transitively) something called
+// __dllonexit_lk in order to make sure the destructors get called
+// when the dll unloads.  And that will call msize -- horrible things
+// can ensue if this is not hooked.  Other parts of libc may also call
+// this internally.
+
+template<int T>
+size_t LibcInfoWithPatchFunctions<T>::Perftools__msize(void* ptr) __THROW {
+  return GetSizeWithCallback(ptr, (size_t (*)(const void*))origstub_fn_[k_Msize]);
+}
+
+// We need to define this because internal windows functions like to
+// call into it(?).  _expand() is like realloc but doesn't move the
+// pointer.  We punt, which will cause callers to fall back on realloc.
+template<int T>
+void* LibcInfoWithPatchFunctions<T>::Perftools__expand(void *ptr,
+                                                       size_t size) __THROW {
+  return NULL;
+}
+
+LPVOID WINAPI WindowsInfo::Perftools_HeapAlloc(HANDLE hHeap, DWORD dwFlags,
+                                               DWORD_PTR dwBytes) {
+  LPVOID result = ((LPVOID (WINAPI *)(HANDLE, DWORD, DWORD_PTR))
+                   function_info_[kHeapAlloc].origstub_fn)(
+                       hHeap, dwFlags, dwBytes);
+  MallocHook::InvokeNewHook(result, dwBytes);
+  return result;
+}
+
+BOOL WINAPI WindowsInfo::Perftools_HeapFree(HANDLE hHeap, DWORD dwFlags,
+                                            LPVOID lpMem) {
+  MallocHook::InvokeDeleteHook(lpMem);
+  return ((BOOL (WINAPI *)(HANDLE, DWORD, LPVOID))
+          function_info_[kHeapFree].origstub_fn)(
+              hHeap, dwFlags, lpMem);
+}
+
+LPVOID WINAPI WindowsInfo::Perftools_VirtualAllocEx(HANDLE process,
+                                                    LPVOID address,
+                                                    SIZE_T size, DWORD type,
+                                                    DWORD protect) {
+  LPVOID result = ((LPVOID (WINAPI *)(HANDLE, LPVOID, SIZE_T, DWORD, DWORD))
+                   function_info_[kVirtualAllocEx].origstub_fn)(
+                       process, address, size, type, protect);
+  // VirtualAllocEx() seems to be the Windows equivalent of mmap()
+  MallocHook::InvokeMmapHook(result, address, size, protect, type, -1, 0);
+  return result;
+}
+
+BOOL WINAPI WindowsInfo::Perftools_VirtualFreeEx(HANDLE process, LPVOID address,
+                                                 SIZE_T size, DWORD type) {
+  MallocHook::InvokeMunmapHook(address, size);
+  return ((BOOL (WINAPI *)(HANDLE, LPVOID, SIZE_T, DWORD))
+          function_info_[kVirtualFreeEx].origstub_fn)(
+              process, address, size, type);
+}
+
+LPVOID WINAPI WindowsInfo::Perftools_MapViewOfFileEx(
+    HANDLE hFileMappingObject, DWORD dwDesiredAccess, DWORD dwFileOffsetHigh,
+    DWORD dwFileOffsetLow, SIZE_T dwNumberOfBytesToMap, LPVOID lpBaseAddress) {
+  // For this function pair, you always deallocate the full block of
+  // data that you allocate, so NewHook/DeleteHook is the right API.
+  LPVOID result = ((LPVOID (WINAPI *)(HANDLE, DWORD, DWORD, DWORD,
+                                      SIZE_T, LPVOID))
+                   function_info_[kMapViewOfFileEx].origstub_fn)(
+                       hFileMappingObject, dwDesiredAccess, dwFileOffsetHigh,
+                       dwFileOffsetLow, dwNumberOfBytesToMap, lpBaseAddress);
+  MallocHook::InvokeNewHook(result, dwNumberOfBytesToMap);
+  return result;
+}
+
+BOOL WINAPI WindowsInfo::Perftools_UnmapViewOfFile(LPCVOID lpBaseAddress) {
+  MallocHook::InvokeDeleteHook(lpBaseAddress);
+  return ((BOOL (WINAPI *)(LPCVOID))
+          function_info_[kUnmapViewOfFile].origstub_fn)(
+              lpBaseAddress);
+}
+
+// g_load_map holds a copy of windows' refcount for how many times
+// each currently loaded module has been loaded and unloaded.  We use
+// it as an optimization when the same module is loaded more than
+// once: as long as the refcount stays above 1, we don't need to worry
+// about patching because it's already patched.  Likewise, we don't
+// need to unpatch until the refcount drops to 0.  load_map is
+// maintained in LoadLibraryExW and FreeLibrary, and only covers
+// modules explicitly loaded/freed via those interfaces.
+static std::map<HMODULE, int>* g_load_map = NULL;
+
+HMODULE WINAPI WindowsInfo::Perftools_LoadLibraryExW(LPCWSTR lpFileName,
+                                                     HANDLE hFile,
+                                                     DWORD dwFlags) {
+  HMODULE rv;
+  // Check to see if the modules is already loaded, flag 0 gets a
+  // reference if it was loaded.  If it was loaded no need to call
+  // PatchAllModules, just increase the reference count to match
+  // what GetModuleHandleExW does internally inside windows.
+  if (::GetModuleHandleExW(0, lpFileName, &rv)) {
+    return rv;
+  } else {
+    // Not already loaded, so load it.
+    rv = ((HMODULE (WINAPI *)(LPCWSTR, HANDLE, DWORD))
+                  function_info_[kLoadLibraryExW].origstub_fn)(
+                      lpFileName, hFile, dwFlags);
+    // This will patch any newly loaded libraries, if patching needs
+    // to be done.
+    PatchAllModules();
+
+    return rv;
+  }
+}
+
+BOOL WINAPI WindowsInfo::Perftools_FreeLibrary(HMODULE hLibModule) {
+  BOOL rv = ((BOOL (WINAPI *)(HMODULE))
+             function_info_[kFreeLibrary].origstub_fn)(hLibModule);
+
+  // Check to see if the module is still loaded by passing the base
+  // address and seeing if it comes back with the same address.  If it
+  // is the same address it's still loaded, so the FreeLibrary() call
+  // was a noop, and there's no need to redo the patching.
+  HMODULE owner = NULL;
+  BOOL result = ::GetModuleHandleExW(
+      (GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
+       GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT),
+      (LPCWSTR)hLibModule,
+      &owner);
+  if (result && owner == hLibModule)
+    return rv;
+
+  PatchAllModules();    // this will fix up the list of patched libraries
+  return rv;
+}
+
+
+// ---------------------------------------------------------------------
+// PatchWindowsFunctions()
+//    This is the function that is exposed to the outside world.
+//    It should be called before the program becomes multi-threaded,
+//    since main_executable_windows.Patch() is not thread-safe.
+// ---------------------------------------------------------------------
+
+void PatchWindowsFunctions() {
+  // This does the libc patching in every module, and the main executable.
+  PatchAllModules();
+  main_executable_windows.Patch();
+}
+
+#if 0
+// It's possible to unpatch all the functions when we are exiting.
+
+// The idea is to handle properly windows-internal data that is
+// allocated before PatchWindowsFunctions is called.  If all
+// destruction happened in reverse order from construction, then we
+// could call UnpatchWindowsFunctions at just the right time, so that
+// that early-allocated data would be freed using the windows
+// allocation functions rather than tcmalloc.  The problem is that
+// windows allocates some structures lazily, so it would allocate them
+// late (using tcmalloc) and then try to deallocate them late as well.
+// So instead of unpatching, we just modify all the tcmalloc routines
+// so they call through to the libc rountines if the memory in
+// question doesn't seem to have been allocated with tcmalloc.  I keep
+// this unpatch code around for reference.
+
+void UnpatchWindowsFunctions() {
+  // We need to go back to the system malloc/etc at global destruct time,
+  // so objects that were constructed before tcmalloc, using the system
+  // malloc, can destroy themselves using the system free.  This depends
+  // on DLLs unloading in the reverse order in which they load!
+  //
+  // We also go back to the default HeapAlloc/etc, just for consistency.
+  // Who knows, it may help avoid weird bugs in some situations.
+  main_executable_windows.Unpatch();
+  main_executable.Unpatch();
+  if (libc1.is_valid()) libc1.Unpatch();
+  if (libc2.is_valid()) libc2.Unpatch();
+  if (libc3.is_valid()) libc3.Unpatch();
+  if (libc4.is_valid()) libc4.Unpatch();
+  if (libc5.is_valid()) libc5.Unpatch();
+  if (libc6.is_valid()) libc6.Unpatch();
+  if (libc7.is_valid()) libc7.Unpatch();
+  if (libc8.is_valid()) libc8.Unpatch();
+}
+#endif
diff --git a/src/windows/port.cc b/src/windows/port.cc
new file mode 100644
index 0000000..76224a2
--- /dev/null
+++ b/src/windows/port.cc
@@ -0,0 +1,235 @@
+// -*- 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 http://www.codeproject.com/threads/tls.asp.
+// 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.
+extern "C" {
+// This tells the linker to run these functions.
+#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"
+
+#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);
+  }
+}
diff --git a/src/windows/port.h b/src/windows/port.h
new file mode 100644
index 0000000..0350f45
--- /dev/null
+++ b/src/windows/port.h
@@ -0,0 +1,497 @@
+// -*- 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 _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
+#ifndef HAVE___INT64    /* we need to have all the __intX names */
+# error  Do not know how to set up type aliases.  Edit port.h for your system.
+#endif
+
+typedef __int8 int8_t;
+typedef __int16 int16_t;
+typedef __int32 int32_t;
+typedef __int64 int64_t;
+typedef unsigned __int8 uint8_t;
+typedef unsigned __int16 uint16_t;
+typedef unsigned __int32 uint32_t;
+typedef unsigned __int64 uint64_t;
+#endif  /* #ifndef HAVE_STDINT_H */
+
+/* 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_SNPRINTF
+inline int snprintf(char *str, size_t size, const char *format, ...) {
+  va_list ap;
+  int r;
+  va_start(ap, format);
+  r = perftools_vsnprintf(str, size, format, ap);
+  va_end(ap);
+  return r;
+}
+#endif
+
+#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
+
+/* ----------------------------------- 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 _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_ */
diff --git a/src/windows/preamble_patcher.cc b/src/windows/preamble_patcher.cc
new file mode 100644
index 0000000..ec05537
--- /dev/null
+++ b/src/windows/preamble_patcher.cc
@@ -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 <= NULL) {
+      // 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
diff --git a/src/windows/preamble_patcher.h b/src/windows/preamble_patcher.h
new file mode 100644
index 0000000..76f158a
--- /dev/null
+++ b/src/windows/preamble_patcher.h
@@ -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_
diff --git a/src/windows/preamble_patcher_test.cc b/src/windows/preamble_patcher_test.cc
new file mode 100644
index 0000000..e4605c6
--- /dev/null
+++ b/src/windows/preamble_patcher_test.cc
@@ -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)
diff --git a/src/windows/preamble_patcher_with_stub.cc b/src/windows/preamble_patcher_with_stub.cc
new file mode 100644
index 0000000..23f9d3a
--- /dev/null
+++ b/src/windows/preamble_patcher_with_stub.cc
@@ -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
diff --git a/src/windows/shortproc.asm b/src/windows/shortproc.asm
new file mode 100644
index 0000000..7e8e3d7
--- /dev/null
+++ b/src/windows/shortproc.asm
@@ -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

diff --git a/src/windows/system-alloc.cc b/src/windows/system-alloc.cc
new file mode 100644
index 0000000..9537745
--- /dev/null
+++ b/src/windows/system-alloc.cc
@@ -0,0 +1,204 @@
+// 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* 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();
+  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 = 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
+}