summaryrefslogtreecommitdiffstats
path: root/ceee/testing
diff options
context:
space:
mode:
authorinitial.commit@chromium.org <initial.commit@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-11-02 02:14:31 +0000
committerinitial.commit@chromium.org <initial.commit@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-11-02 02:14:31 +0000
commit5a7bdf208c28c210b39cff63d1cf91302b02821b (patch)
tree5ff484561562f78b29d2670168a9e3b40b48dcab /ceee/testing
parent26a54a5e0f4603c8fda2fe51789d331125993c9a (diff)
downloadchromium_src-5a7bdf208c28c210b39cff63d1cf91302b02821b.zip
chromium_src-5a7bdf208c28c210b39cff63d1cf91302b02821b.tar.gz
chromium_src-5a7bdf208c28c210b39cff63d1cf91302b02821b.tar.bz2
Checking in the initial version of CEEE (Chrome Extensions Execution
Environment), an optional feature of Chrome Frame that acts as an adapter layer for a subset of the Chrome Extension APIs. This enables extensions that stick to the supported subset of APIs to work in the context of Chrome Frame with minimal or sometimes no changes. See http://www.chromium.org/developers/design-documents/ceee for an overview of the design of CEEE. TEST=unit tests (run ceee/smoke_tests.bat as an administrator on Windows) BUG=none git-svn-id: svn://svn.chromium.org/chrome/trunk/src@64712 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ceee/testing')
-rw-r--r--ceee/testing/manual/ie_broker/call_broker/call_broker.cc247
-rw-r--r--ceee/testing/manual/ie_broker/call_broker/call_broker.gyp35
-rw-r--r--ceee/testing/manual/ie_broker/call_broker/precompile.cc6
-rw-r--r--ceee/testing/manual/ie_broker/call_broker/precompile.h13
-rw-r--r--ceee/testing/sidestep/auto_testing_hook.h128
-rw-r--r--ceee/testing/sidestep/documentation.h20
-rw-r--r--ceee/testing/sidestep/ia32_modrm_map.cc92
-rw-r--r--ceee/testing/sidestep/ia32_opcode_map.cc1159
-rw-r--r--ceee/testing/sidestep/integration.h63
-rw-r--r--ceee/testing/sidestep/mini_disassembler.cc390
-rw-r--r--ceee/testing/sidestep/mini_disassembler.h155
-rw-r--r--ceee/testing/sidestep/mini_disassembler_types.h197
-rw-r--r--ceee/testing/sidestep/preamble_patcher.cc310
-rw-r--r--ceee/testing/sidestep/preamble_patcher.h350
-rw-r--r--ceee/testing/sidestep/preamble_patcher_test.cc168
-rw-r--r--ceee/testing/sidestep/preamble_patcher_with_stub.cc172
-rw-r--r--ceee/testing/sidestep/sidestep.gyp39
-rw-r--r--ceee/testing/utils/com_mock.py166
-rw-r--r--ceee/testing/utils/dispex_mocks.h129
-rw-r--r--ceee/testing/utils/gflag_utils.cc157
-rw-r--r--ceee/testing/utils/gflag_utils.h125
-rw-r--r--ceee/testing/utils/gflag_utils_unittest.cc28
-rw-r--r--ceee/testing/utils/instance_count_mixin.cc64
-rw-r--r--ceee/testing/utils/instance_count_mixin.h82
-rw-r--r--ceee/testing/utils/instance_count_mixin_unittest.cc79
-rw-r--r--ceee/testing/utils/mock_com.h229
-rw-r--r--ceee/testing/utils/mock_iactivescript.gen31
-rw-r--r--ceee/testing/utils/mock_iactivescriptsite.gen20
-rw-r--r--ceee/testing/utils/mock_iactivescriptsitedebug.gen16
-rw-r--r--ceee/testing/utils/mock_idebugapplication.gen62
-rw-r--r--ceee/testing/utils/mock_idebugdocumenthelper.gen42
-rw-r--r--ceee/testing/utils/mock_idispatchex.gen34
-rw-r--r--ceee/testing/utils/mock_ihtmldocument2.gen145
-rw-r--r--ceee/testing/utils/mock_ihtmlwindow2.gen95
-rw-r--r--ceee/testing/utils/mock_iobjectsafety.gen10
-rw-r--r--ceee/testing/utils/mock_ioleobject.gen43
-rw-r--r--ceee/testing/utils/mock_iprocessdebugmanager.gen16
-rw-r--r--ceee/testing/utils/mock_itravellogstg.gen20
-rw-r--r--ceee/testing/utils/mock_iwebbrowser2.gen110
-rw-r--r--ceee/testing/utils/mock_static.h161
-rw-r--r--ceee/testing/utils/mock_win32.h119
-rw-r--r--ceee/testing/utils/mock_window_utils.h40
-rw-r--r--ceee/testing/utils/mshtml_mocks.h16
-rw-r--r--ceee/testing/utils/mshtml_mocks.py85
-rw-r--r--ceee/testing/utils/nt_internals.cc63
-rw-r--r--ceee/testing/utils/nt_internals.h206
-rw-r--r--ceee/testing/utils/nt_internals_unittest.cc103
-rw-r--r--ceee/testing/utils/test_utils.cc170
-rw-r--r--ceee/testing/utils/test_utils.gyp104
-rw-r--r--ceee/testing/utils/test_utils.h314
-rw-r--r--ceee/testing/utils/test_utils_unittest.cc143
-rw-r--r--ceee/testing/utils/test_utils_unittest_main.cc26
52 files changed, 6797 insertions, 0 deletions
diff --git a/ceee/testing/manual/ie_broker/call_broker/call_broker.cc b/ceee/testing/manual/ie_broker/call_broker/call_broker.cc
new file mode 100644
index 0000000..ed51183
--- /dev/null
+++ b/ceee/testing/manual/ie_broker/call_broker/call_broker.cc
@@ -0,0 +1,247 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// A console app driving the IE broker to and from many threads.
+
+#include <atlbase.h>
+#include <atlstr.h>
+
+#include "base/json/json_reader.h"
+#include "base/json/json_writer.h"
+#include "base/logging.h"
+#include "base/scoped_ptr.h"
+#include "base/values.h"
+#include "chrome/browser/automation/extension_automation_constants.h"
+#include "chrome/browser/extensions/extension_tabs_module_constants.h"
+#include "ceee/common/com_utils.h"
+
+#include "broker_lib.h" // NOLINT
+
+namespace keys = extension_automation_constants;
+namespace ext = extension_tabs_module_constants;
+
+namespace {
+
+// Unused WindowProc to create windows.
+LRESULT CALLBACK WindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
+ return 1;
+}
+
+// The number of destination thread that we will create.
+static const size_t kTestSize = 222;
+HWND g_windows[kTestSize];
+CHandle thread_ready[kTestSize];
+
+CHandle kill_all_indexed_threads;
+HMODULE g_module = NULL;
+
+// Faking IEFrame for the Broker.
+static const wchar_t* kWindowClassName = L"IEFrame";
+
+// A ThreadProc to run all the threads that create windows and set their
+// HWND in g_windows[] so that they can be used as destination threads.
+DWORD WINAPI IndexedWindowCreationProc(LPVOID param) {
+ size_t index = reinterpret_cast<size_t>(param);
+ printf("Starting destination thread: 0x%08x, index: %d\n",
+ ::GetCurrentThreadId(), index);
+ g_windows[index] = ::CreateWindow(kWindowClassName, NULL, 0, 0, 0, 0, 0,
+ NULL, NULL, NULL, 0);
+ DCHECK_NE(static_cast<HWND>(NULL), g_windows[index]) <<
+ com::LogWe(::GetLastError());
+ // The destination thread MUST be CoInitialized.
+ CoInitialize(NULL);
+
+ // We're ready, our creator can continue.
+ ::SetEvent(thread_ready[index]);
+ MSG msg;
+ while (true) {
+ // Regular message loop for destination threads.
+ DWORD result = ::MsgWaitForMultipleObjects(1, &kill_all_indexed_threads.m_h,
+ FALSE, INFINITE, QS_POSTMESSAGE);
+ if (result == WAIT_OBJECT_0) {
+ // Our death signal!
+ break;
+ }
+ DCHECK_EQ(WAIT_OBJECT_0 + 1, result);
+ // We got woken up by a message, empty the queue.
+ while (::PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) {
+ BOOL result = ::GetMessage(&msg, NULL, 0, 0);
+ if (result != 0 && result != -1) {
+ ::TranslateMessage(&msg);
+ ::DispatchMessage(&msg);
+ }
+ }
+ }
+ return 0;
+}
+
+void CreateMessage(HWND window, int request_id, std::string* message_str) {
+ // Create a JSON encoded message to call GetWindow for our window of interest.
+ DictionaryValue message;
+ message.SetString(keys::kAutomationNameKey, "windows.get");
+ message.SetInteger(keys::kAutomationRequestIdKey, request_id);
+ scoped_ptr<Value> function_args(Value::CreateIntegerValue(
+ reinterpret_cast<int>(window)));
+ std::string function_args_str;
+ base::JSONWriter::Write(function_args.get(), false, &function_args_str);
+ message.SetString(keys::kAutomationArgsKey, function_args_str);
+ base::JSONWriter::Write(&message, false, message_str);
+}
+
+void ValidateResponse(BSTR response, HWND window, int request_id,
+ bool may_have_failed) {
+ scoped_ptr<Value> response_value(base::JSONReader::Read(
+ CW2A(response).m_psz, true));
+ DCHECK(response_value.get() != NULL);
+ DCHECK(response_value->IsType(Value::TYPE_DICTIONARY));
+ DictionaryValue* response_dict =
+ static_cast<DictionaryValue*>(response_value.get());
+ DCHECK(response_dict->HasKey(keys::kAutomationRequestIdKey));
+ int response_id = -1;
+ response_dict->GetInteger(keys::kAutomationRequestIdKey, &response_id);
+ DCHECK(response_id == request_id);
+ if (response_dict->HasKey(keys::kAutomationErrorKey)) {
+ // The only error we should get is if the window isn't valid anymore
+ DCHECK(::IsWindow(window) == FALSE || may_have_failed);
+ } else {
+ DCHECK(response_dict->HasKey(keys::kAutomationResponseKey));
+ std::string response_str;
+ response_dict->GetString(keys::kAutomationResponseKey, &response_str);
+ scoped_ptr<Value> response_value(
+ base::JSONReader::Read(response_str, true));
+ DCHECK(response_value.get() != NULL);
+ DCHECK(response_value->IsType(Value::TYPE_DICTIONARY));
+ DictionaryValue* dict = static_cast<DictionaryValue*>(response_value.get());
+ DCHECK(dict->HasKey(ext::kIdKey));
+ int window_id = 0;
+ dict->GetInteger(ext::kIdKey, &window_id);
+ DCHECK(window_id == reinterpret_cast<int>(window));
+ }
+}
+
+void ExecuteAtIndex(ICeeeBroker* broker, size_t index) {
+ DCHECK(index < kTestSize);
+ printf("Calling Execute for Window: 0x%08x, index: %d\n",
+ g_windows[index], index);
+ std::string message_str;
+ CreateMessage(g_windows[index], 42 + index, &message_str);
+ CComBSTR response;
+ HRESULT hr = broker->Execute(CComBSTR(CA2W(message_str.c_str()).m_psz),
+ &response);
+ DCHECK(SUCCEEDED(hr)) << com::LogHr(hr);
+ ValidateResponse(response, g_windows[index], 42 + index, false);
+}
+
+
+// Source threads are created to make concurrent calls to the broker.
+DWORD WINAPI IndexedSourceThreadProc(LPVOID param) {
+ size_t index = reinterpret_cast<size_t>(param);
+ printf("Starting source thread: 0x%08x, for index: %d\n",
+ ::GetCurrentThreadId(), index);
+ // Of course...
+ ::CoInitialize(NULL);
+
+ CComPtr<ICeeeBroker> broker;
+ HRESULT hr = broker.CoCreateInstance(__uuidof(CeeeBroker));
+ DCHECK(SUCCEEDED(hr)) << com::LogHr(hr);
+
+ // We aim at different destination threads to create concurrency.
+ // When threads 0, 1, 2, 3 are started they all call into destination thread
+ // index 0, same for 0-7 afterward, and 0-15.
+ ExecuteAtIndex(broker, index / 4);
+ ExecuteAtIndex(broker, index / 8);
+ ExecuteAtIndex(broker, index / 16);
+
+ printf("Done with calls from thread: 0x%08x, calling execute for index: %d\n",
+ ::GetCurrentThreadId(), index);
+
+ return 0;
+}
+
+} // namespace
+
+
+int _tmain(int argc, _TCHAR* argv[]) {
+ // We need the module handle to create windows.
+ BOOL success = ::GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
+ reinterpret_cast<LPCTSTR>(WindowProc), &g_module);
+ DCHECK(success) << com::LogWe(::GetLastError());
+
+ WNDCLASS window_class;
+ window_class.cbClsExtra = 0;
+ window_class.cbWndExtra = 0;
+ window_class.hbrBackground = NULL;
+ window_class.hCursor = NULL;
+ window_class.hIcon = NULL;
+ window_class.hInstance = static_cast<HINSTANCE>(g_module);
+ window_class.lpfnWndProc = WindowProc;
+ window_class.lpszClassName = kWindowClassName;
+ window_class.lpszMenuName = NULL;
+ window_class.style = 0;
+ ATOM window_class_atom = ::RegisterClass(&window_class);
+ DCHECK_NE(static_cast<ATOM>(NULL), window_class_atom) <<
+ com::LogWe(::GetLastError());
+
+ ::CoInitialize(NULL);
+
+ // Needed by more than one thread so manual reset.
+ kill_all_indexed_threads.Attach(::CreateEvent(NULL, TRUE, FALSE, NULL));
+ DCHECK_NE(static_cast<HANDLE>(NULL), kill_all_indexed_threads.m_h) <<
+ com::LogWe(::GetLastError());
+
+ // We'll also make some calls from this thread... Why not?
+ CComPtr<ICeeeBroker> broker;
+ HRESULT hr = broker.CoCreateInstance(__uuidof(CeeeBroker));
+ DCHECK(SUCCEEDED(hr)) << com::LogHr(hr);
+
+ // Create all our destination threads...
+ for (size_t index = 0; index < kTestSize; ++index) {
+ thread_ready[index].Attach(::CreateEvent(NULL, FALSE, FALSE, NULL));
+ CHandle thread_handle(::CreateThread(NULL, 0, IndexedWindowCreationProc,
+ reinterpret_cast<void*>(index), 0, NULL));
+ DCHECK_NE(CHandle(), thread_handle) << com::LogWe(::GetLastError());
+ DWORD result = ::WaitForSingleObject(thread_ready[index], 3000);
+ DCHECK_EQ(WAIT_OBJECT_0, result);
+ }
+
+ // Now create 4 times as many source threads, each making a few calls.
+ CHandle last_thread_handle;
+ for (size_t index = 0; index < kTestSize * 4; ++index) {
+ if (index % 4 == 0) {
+ CComBSTR response;
+ // Once in a while, make a call from here...
+ printf("Initiating call from main thread, for index: %d\n", index);
+ std::string message;
+ CreateMessage(g_windows[index % kTestSize], index, &message);
+ hr = broker->Execute(CComBSTR(CA2W(message.c_str()).m_psz),
+ &response);
+ DCHECK(SUCCEEDED(hr)) << com::LogHr(hr);
+ ValidateResponse(response, g_windows[index % kTestSize], index, false);
+ printf("Done with call from main thread, for index: %d\n", index);
+ } else {
+ // And for the rest of the time, create a temporary caller thread.
+ CHandle src_thread_handle(::CreateThread(NULL, 0, IndexedSourceThreadProc,
+ reinterpret_cast<void*>(index), 0, NULL));
+ }
+ }
+
+ puts("Waiting to make sure ceee_broker.exe won't go away too soon");
+ ::Sleep(10000);
+
+ printf("Initiating one last call from main thread, for index: %d\n",
+ 42 % kTestSize);
+ std::string message;
+ CreateMessage(g_windows[42 % kTestSize], 666, &message);
+ CComBSTR response;
+ hr = broker->Execute(CComBSTR(CA2W(message.c_str()).m_psz),
+ &response);
+ DCHECK(SUCCEEDED(hr)) << com::LogHr(hr);
+ ValidateResponse(response, g_windows[42 % kTestSize], 666, false);
+
+ printf("Done with call from main thread, for index: %d\n", 42 % kTestSize);
+
+ puts("Kill all threads.");
+ ::SetEvent(kill_all_indexed_threads);
+ return 0;
+}
diff --git a/ceee/testing/manual/ie_broker/call_broker/call_broker.gyp b/ceee/testing/manual/ie_broker/call_broker/call_broker.gyp
new file mode 100644
index 0000000..6021b60
--- /dev/null
+++ b/ceee/testing/manual/ie_broker/call_broker/call_broker.gyp
@@ -0,0 +1,35 @@
+# Copyright (c) 2010 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'includes': [
+ '../../../../../build/common.gypi',
+ ],
+ 'targets': [
+ {
+ 'target_name': 'call_broker',
+ 'type': 'executable',
+ 'sources': [
+ 'call_broker.cc',
+ 'precompile.cc',
+ 'precompile.h',
+ ],
+ 'configurations': {
+ 'Debug': {
+ 'msvs_precompiled_header': 'precompile.h',
+ 'msvs_precompiled_source': 'precompile.cc',
+ },
+ },
+ 'defines': [
+ '_CONSOLE',
+ ],
+ 'dependencies': [
+ '<(DEPTH)/ceee/ie/plugin/toolband/toolband.gyp:toolband_idl',
+ '<(DEPTH)/ceee/ie/common/common.gyp:ie_common',
+ '<(DEPTH)/base/base.gyp:base',
+ '<(DEPTH)/ceee/common/common.gyp:ceee_common',
+ ],
+ },
+ ]
+}
diff --git a/ceee/testing/manual/ie_broker/call_broker/precompile.cc b/ceee/testing/manual/ie_broker/call_broker/precompile.cc
new file mode 100644
index 0000000..76d5c35
--- /dev/null
+++ b/ceee/testing/manual/ie_broker/call_broker/precompile.cc
@@ -0,0 +1,6 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Precompile generator file.
+#include "ceee/testing/manual/ie_broker/call_broker/precompile.h"
diff --git a/ceee/testing/manual/ie_broker/call_broker/precompile.h b/ceee/testing/manual/ie_broker/call_broker/precompile.h
new file mode 100644
index 0000000..ca9238e
--- /dev/null
+++ b/ceee/testing/manual/ie_broker/call_broker/precompile.h
@@ -0,0 +1,13 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Precompile header for IE broker manual test to call the broker.
+
+#ifndef CEEE_TESTING_MANUAL_IE_BROKER_CALL_BROKER_PRECOMPILE_H_
+#define CEEE_TESTING_MANUAL_IE_BROKER_CALL_BROKER_PRECOMPILE_H_
+
+#include <stdio.h>
+#include <tchar.h>
+
+#endif // CEEE_TESTING_MANUAL_IE_BROKER_CALL_BROKER_PRECOMPILE_H_
diff --git a/ceee/testing/sidestep/auto_testing_hook.h b/ceee/testing/sidestep/auto_testing_hook.h
new file mode 100644
index 0000000..33f3ba2
--- /dev/null
+++ b/ceee/testing/sidestep/auto_testing_hook.h
@@ -0,0 +1,128 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// 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 "ceee/testing/sidestep/integration.h"
+#include "ceee/testing/sidestep/preamble_patcher.h"
+
+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(
+ target_function_, replacement_function_,
+ 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),
+ replacement_function_(replacement_function),
+ original_function_(NULL),
+ 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/ceee/testing/sidestep/documentation.h b/ceee/testing/sidestep/documentation.h
new file mode 100644
index 0000000..00ca47f
--- /dev/null
+++ b/ceee/testing/sidestep/documentation.h
@@ -0,0 +1,20 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// SideStep SideStep Library Overview
+//
+// The SideStep library includes two main components:
+// -# A preamble patching utility, enabling patching of most
+// functions. See PreamblePatcher.
+// -# A mini disassembler, used by the preamble patching utility. See
+// MiniDisassembler.
+//
+// To use the library, see integration.h; at a high level, you need to:
+// -# Link in a function sidestep::AssertImpl or explicitly define
+// the SIDESTEP_ASSERT macro.
+// -# Link in a function sidestep::LogImpl or explicitly define the
+// SIDESTEP_LOG macro.
+// -# Optional: Call sidestep::UnitTests() from from a unit test in your
+// code and check that it returns true (otherwise the unit test
+// found an error).
diff --git a/ceee/testing/sidestep/ia32_modrm_map.cc b/ceee/testing/sidestep/ia32_modrm_map.cc
new file mode 100644
index 0000000..bfb19a8e
--- /dev/null
+++ b/ceee/testing/sidestep/ia32_modrm_map.cc
@@ -0,0 +1,92 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// 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 "ceee/testing/sidestep/mini_disassembler.h"
+#include "ceee/testing/sidestep/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/ceee/testing/sidestep/ia32_opcode_map.cc b/ceee/testing/sidestep/ia32_opcode_map.cc
new file mode 100644
index 0000000..bfb094c
--- /dev/null
+++ b/ceee/testing/sidestep/ia32_opcode_map.cc
@@ -0,0 +1,1159 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// 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 "ceee/testing/sidestep/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 } },
+ /* 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 } },
+ /* 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 } },
+ /* 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 } },
+ /* 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/ceee/testing/sidestep/integration.h b/ceee/testing/sidestep/integration.h
new file mode 100644
index 0000000..f1239cf
--- /dev/null
+++ b/ceee/testing/sidestep/integration.h
@@ -0,0 +1,63 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Defines functions/macros that can and/or need to be defined by the
+// user of this library, and a unit test function that can optionally
+// be called from whichever unit test harness the user of the library
+// is using.
+
+#ifndef CEEE_TESTING_SIDESTEP_INTEGRATION_H_
+#define CEEE_TESTING_SIDESTEP_INTEGRATION_H_
+
+#ifndef SIDESTEP_ASSERT // you may define it explicitly yourself
+#if defined(ENABLE_SIDESTEP_ASSERTIONS) || defined(_DEBUG) || defined(DEBUG)
+#define SIDESTEP_ASSERT(x) sidestep::AssertImpl(x, #x)
+#else
+#define SIDESTEP_ASSERT(x)
+#endif
+#endif
+
+#ifndef SIDESTEP_LOG // you may define it explicitly yourself
+#if defined(ENABLE_SIDESTEP_LOGGING) || defined(_DEBUG) || defined(DEBUG)
+#define SIDESTEP_LOG(x) sidestep::LogImpl(x)
+#else
+#define SIDESTEP_LOG(x)
+#endif
+#endif
+
+// You may define SIDESTEP_CHK yourself to make it fail your unit test
+// harness when the condition is not met (see auto_testing_hook.h).
+#ifndef SIDESTEP_CHK
+#define SIDESTEP_CHK(x) if (x) {}
+#endif
+
+// You may define SIDESTEP_EXPECT_TRUE to override the behavior of
+// the SideStep unit test in preamble_patcher_test.cc
+#ifndef SIDESTEP_EXPECT_TRUE
+#define SIDESTEP_EXPECT_TRUE(x) \
+ do { if (!(x)) { \
+ SIDESTEP_ASSERT(false && #x); \
+ return false; } } while (false)
+#endif
+
+namespace sidestep {
+
+// This is the function the macro SIDESTEP_ASSERT calls in debug
+// builds by default. Users of the library must link in its
+// implementation.
+// @param assertion_is_true True if the condition of the assertion was met.
+// @param message A stringified version of the condition of the assertion.
+void AssertImpl(bool assertion_is_true, const char* message);
+
+// This is the function the macro SIDESTEP_LOG calls in debug builds,
+// by default. Users of the library must link in its implementation.
+// @param message The message to be logged.
+void LogImpl(const char* message);
+
+// Runs the SideStep unit tests and returns true on success.
+bool UnitTests();
+
+}; // namespace sidestep
+
+#endif // CEEE_TESTING_SIDESTEP_INTEGRATION_H_
diff --git a/ceee/testing/sidestep/mini_disassembler.cc b/ceee/testing/sidestep/mini_disassembler.cc
new file mode 100644
index 0000000..3858a1b
--- /dev/null
+++ b/ceee/testing/sidestep/mini_disassembler.cc
@@ -0,0 +1,390 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+// Implementation of MiniDisassembler.
+
+#include "ceee/testing/sidestep/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_;
+ 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;
+
+ 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 =
+ reinterpret_cast<const 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 or doubleword, depending on operand-size attribute.
+ 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/ceee/testing/sidestep/mini_disassembler.h b/ceee/testing/sidestep/mini_disassembler.h
new file mode 100644
index 0000000..aeee3b1
--- /dev/null
+++ b/ceee/testing/sidestep/mini_disassembler.h
@@ -0,0 +1,155 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+// Definition of MiniDisassembler.
+
+#ifndef CEEE_TESTING_SIDESTEP_MINI_DISASSEMBLER_H_
+#define CEEE_TESTING_SIDESTEP_MINI_DISASSEMBLER_H_
+
+#include "ceee/testing/sidestep/mini_disassembler_types.h"
+
+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 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_;
+
+ // 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 // CEEE_TESTING_SIDESTEP_MINI_DISASSEMBLER_H_
diff --git a/ceee/testing/sidestep/mini_disassembler_types.h b/ceee/testing/sidestep/mini_disassembler_types.h
new file mode 100644
index 0000000..479d75a
--- /dev/null
+++ b/ceee/testing/sidestep/mini_disassembler_types.h
@@ -0,0 +1,197 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Several simple types used by the disassembler and some of the patching
+// mechanisms.
+
+#ifndef CEEE_TESTING_SIDESTEP_MINI_DISASSEMBLER_TYPES_H_
+#define CEEE_TESTING_SIDESTEP_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
+};
+
+// 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 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_;
+};
+
+// 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 // CEEE_TESTING_SIDESTEP_MINI_DISASSEMBLER_TYPES_H_
diff --git a/ceee/testing/sidestep/preamble_patcher.cc b/ceee/testing/sidestep/preamble_patcher.cc
new file mode 100644
index 0000000..cdbfcfa
--- /dev/null
+++ b/ceee/testing/sidestep/preamble_patcher.cc
@@ -0,0 +1,310 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Implementation of PreamblePatcher
+
+#include "ceee/testing/sidestep/integration.h"
+#include "ceee/testing/sidestep/preamble_patcher.h"
+#include "ceee/testing/sidestep/mini_disassembler.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
+
+namespace sidestep {
+
+// 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.
+void* PreamblePatcher::ResolveTargetImpl(unsigned char* target,
+ unsigned char* stop_before) {
+ 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) {
+ // 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;
+ 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 {
+ break;
+ }
+ if (new_target == stop_before)
+ break;
+ target = new_target;
+ }
+ return target;
+}
+
+// Special case scoped_ptr to avoid dependency on scoped_ptr below.
+class DeleteUnsignedCharArray {
+ public:
+ explicit DeleteUnsignedCharArray(unsigned char* array) : array_(array) {
+ }
+
+ ~DeleteUnsignedCharArray() {
+ if (array_) {
+ delete [] 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;
+ }
+
+ // @see MAX_PREAMBLE_STUB_SIZE for an explanation of how we arrives at
+ // this size
+ unsigned char* preamble_stub = new unsigned char[MAX_PREAMBLE_STUB_SIZE];
+ 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);
+
+ // Change the protection of the newly allocated preamble stub to
+ // PAGE_EXECUTE_READWRITE. This is required to work with DEP (Data
+ // Execution Prevention) which will cause an exception if code is executed
+ // from a page on which you do not have read access.
+ DWORD old_stub_protect = 0;
+ BOOL succeeded = VirtualProtect(preamble_stub, MAX_PREAMBLE_STUB_SIZE,
+ PAGE_EXECUTE_READWRITE, &old_stub_protect);
+ if (!succeeded) {
+ SIDESTEP_ASSERT(false &&
+ "Failed to make page preamble stub read-write-execute.");
+ return SIDESTEP_ACCESS_DENIED;
+ }
+
+ 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;
+ }
+
+ // We disassemble the preamble of the _stub_ to see how many bytes we
+ // originally copied to the stub.
+ MiniDisassembler disassembler;
+ unsigned int preamble_bytes = 0;
+ while (preamble_bytes < 5) {
+ InstructionType instruction_type =
+ disassembler.Disassemble(
+ reinterpret_cast<unsigned char*>(original_function_stub) +
+ preamble_bytes,
+ preamble_bytes);
+ if (IT_GENERIC != instruction_type) {
+ SIDESTEP_ASSERT(false &&
+ "Should only have generic instructions in stub!!");
+ return SIDESTEP_UNSUPPORTED_INSTRUCTION;
+ }
+ }
+
+ // 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)));
+ // 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;
+ }
+
+ // 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),
+ 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;
+ }
+
+ // Replace the first few bytes of the original function with the bytes we
+ // previously moved to the preamble stub.
+ memcpy(reinterpret_cast<void*>(target),
+ original_function_stub, preamble_bytes);
+
+ // Stub is now useless so delete it.
+ delete original_function_stub;
+
+ // Restore the protection of the first MAX_PREAMBLE_STUB_SIZE bytes of
+ // target to what they were before we started goofing around.
+ succeeded = ::VirtualProtect(reinterpret_cast<void*>(target),
+ MAX_PREAMBLE_STUB_SIZE,
+ 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;
+}
+
+}; // namespace sidestep
diff --git a/ceee/testing/sidestep/preamble_patcher.h b/ceee/testing/sidestep/preamble_patcher.h
new file mode 100644
index 0000000..bfe6569
--- /dev/null
+++ b/ceee/testing/sidestep/preamble_patcher.h
@@ -0,0 +1,350 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Definition of PreamblePatcher
+
+#ifndef CEEE_TESTING_SIDESTEP_PREAMBLE_PATCHER_H_
+#define CEEE_TESTING_SIDESTEP_PREAMBLE_PATCHER_H_
+
+#include <windows.h>
+
+// 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 :)
+#define MAX_PREAMBLE_STUB_SIZE (32)
+
+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)
+
+// 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 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 Unpatch, 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(
+ reinterpret_cast<unsigned char*>(target_function), NULL);
+ }
+
+ private:
+ // 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.
+ //
+ // @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);
+};
+
+}; // namespace sidestep
+
+#endif // CEEE_TESTING_SIDESTEP_PREAMBLE_PATCHER_H_
diff --git a/ceee/testing/sidestep/preamble_patcher_test.cc b/ceee/testing/sidestep/preamble_patcher_test.cc
new file mode 100644
index 0000000..fafa5e8
--- /dev/null
+++ b/ceee/testing/sidestep/preamble_patcher_test.cc
@@ -0,0 +1,168 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Unit tests for PreamblePatcher
+
+#include "ceee/testing/sidestep/integration.h"
+#include "ceee/testing/sidestep/preamble_patcher.h"
+#include "ceee/testing/sidestep/mini_disassembler.h"
+#pragma warning(push)
+#pragma warning(disable:4553)
+#include "ceee/testing/sidestep/auto_testing_hook.h"
+#pragma warning(pop)
+
+// 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)
+
+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) {
+ return i + 1;
+}
+
+// A function that is too short to patch
+int __declspec(naked) TooShortFunction(int) {
+ __asm {
+ ret
+ }
+}
+
+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 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 ==
+ sidestep::PreamblePatcher::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 ==
+ sidestep::PreamblePatcher::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 UnitTests() {
+ return TestPatchUsingDynamicStub() && PatchThenUnpatch() &&
+ AutoTestingHookTest() && AutoTestingHookInContainerTest();
+}
+
+}; // namespace sidestep
+
+#pragma optimize("", on)
diff --git a/ceee/testing/sidestep/preamble_patcher_with_stub.cc b/ceee/testing/sidestep/preamble_patcher_with_stub.cc
new file mode 100644
index 0000000..8422475
--- /dev/null
+++ b/ceee/testing/sidestep/preamble_patcher_with_stub.cc
@@ -0,0 +1,172 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Implementation of PreamblePatcher
+
+#include "ceee/testing/sidestep/integration.h"
+#include "ceee/testing/sidestep/preamble_patcher.h"
+#include "ceee/testing/sidestep/mini_disassembler.h"
+
+// Definitions of assembly statements we need
+#define ASM_JMP32REL 0xE9
+#define ASM_INT3 0xCC
+
+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(joi@chromium.org) siggi@chromium.org and I 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@chromium.org 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.
+
+ // 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) { // we're in the IAT case
+ // I'd like to just say "target = new_target", but I can't,
+ // because the new target will need to have its protections set.
+ return RawPatchWithStubAndProtections(new_target, replacement_function,
+ preamble_stub, stub_size,
+ bytes_needed);
+ }
+ unsigned char* target = reinterpret_cast<unsigned char*>(new_target);
+
+ // 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;
+ while (preamble_bytes < 5) {
+ InstructionType instruction_type =
+ disassembler.Disassemble(target + preamble_bytes, preamble_bytes);
+ if (IT_JUMP == instruction_type) {
+ SIDESTEP_ASSERT(false &&
+ "Unable to patch because there is a jump instruction "
+ "in the first 5 bytes.");
+ return SIDESTEP_JUMP_INSTRUCTION;
+ } 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) {
+ SIDESTEP_ASSERT(false &&
+ "Disassembler encountered unsupported instruction "
+ "(either unused or unknown");
+ return SIDESTEP_UNSUPPORTED_INSTRUCTION;
+ }
+ }
+
+ if (NULL != bytes_needed)
+ *bytes_needed = preamble_bytes + 5;
+
+ // 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 + size of
+ // jmp (5)
+ if (preamble_bytes + 5 > stub_size) {
+ SIDESTEP_ASSERT(false);
+ return SIDESTEP_INSUFFICIENT_BUFFER;
+ }
+
+ // First, copy the preamble that we will overwrite.
+ memcpy(reinterpret_cast<void*>(preamble_stub),
+ reinterpret_cast<void*>(target), preamble_bytes);
+
+ // 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 + preamble_bytes + 5));
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+ // jmp (Jump near, relative, displacement relative to next instruction)
+ preamble_stub[preamble_bytes] = ASM_JMP32REL;
+ // copy the address
+ memcpy(reinterpret_cast<void*>(preamble_stub + preamble_bytes + 1),
+ reinterpret_cast<void*>(&relative_offset_to_target_rest), 4);
+
+ // 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 > 5) {
+ memset(reinterpret_cast<void*>(target + 5), ASM_INT3, preamble_bytes - 5);
+ }
+
+ // 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.
+
+ return SIDESTEP_SUCCESS;
+}
+
+}; // namespace sidestep
diff --git a/ceee/testing/sidestep/sidestep.gyp b/ceee/testing/sidestep/sidestep.gyp
new file mode 100644
index 0000000..fc125b7
--- /dev/null
+++ b/ceee/testing/sidestep/sidestep.gyp
@@ -0,0 +1,39 @@
+# Copyright (c) 2010 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'variables': {
+ 'chromium_code': 1,
+ },
+ 'includes': [
+ '../../../build/common.gypi',
+ ],
+ 'target_defaults': {
+ 'include_dirs': [
+ '../../..',
+ ],
+ },
+ 'targets': [
+ {
+ 'target_name': 'sidestep',
+ 'type': 'static_library',
+ 'dependencies': [],
+ 'msvs_guid': '92E7FB64-89B3-49B0-BEB5-5FBC39813266',
+ 'sources': [
+ 'auto_testing_hook.h',
+ 'documentation.h',
+ 'ia32_modrm_map.cc',
+ 'ia32_opcode_map.cc',
+ 'integration.h',
+ 'mini_disassembler.cc',
+ 'mini_disassembler.h',
+ 'mini_disassembler_types.h',
+ 'preamble_patcher.cc',
+ 'preamble_patcher.h',
+ 'preamble_patcher_test.cc',
+ 'preamble_patcher_with_stub.cc',
+ ],
+ },
+ ]
+}
diff --git a/ceee/testing/utils/com_mock.py b/ceee/testing/utils/com_mock.py
new file mode 100644
index 0000000..4c63374
--- /dev/null
+++ b/ceee/testing/utils/com_mock.py
@@ -0,0 +1,166 @@
+#!/bin/env python
+# Copyright (c) 2010 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Generates a file with MOCK_METHODX(...) macros for a COM interface.
+
+For interfaces that will not change, you can run this file by hand. For
+interfaces that may still change, you could run it as part of your build
+system to generate code, then #include the generated list of methods inside an
+appropriate wrapper class.
+
+Usage:
+ com_mock.py INTERFACE_NAME HEADER [ADD_HEADERS]* > output-inl.h
+"""
+
+import re
+import sys
+
+# Finds an interface block in a header file generated by IDL.
+_INTERFACE_PATTERN = (r'MIDL_INTERFACE\("[A-Za-z0-9\-]+"\)\s*%s\s*:\s*'
+ r'public\s*(?P<base>\w+)\s*{\s*public:'
+ r'(?P<method_block>[^}]+)};')
+
+# Parses out a method from within an interface block.
+_METHOD_RE = re.compile(r'virtual\s*(:?/\*[^*]+\*/)?\s*(?P<ret>\w+)\s*'
+ r'STDMETHODCALLTYPE\s*(?P<name>\w+)\s*\('
+ r'(?P<params>[^\)]+)\)\s*=\s*0;')
+
+# Finds inline C-style comments.
+_COMMENTS_RE = re.compile('/\*.*?\*/')
+
+# Finds __RPC_xyz defines.
+_RPC_RE = re.compile(' __RPC\w*')
+
+# Finds whitespace.
+_WHITESPACE_RE = re.compile('\s+')
+
+# Finds default argument values.
+_DEFAULT_ARG_RE = re.compile('\s*=\s*[^,]*')
+
+# Header for generated files.
+_FILE_HEADER = '''\
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Auto-generated by com_mock.py
+
+'''
+
+class Mocker(object):
+ """Given a set of header files, can generate mocky goodness for interfaces
+ defined in them.
+ """
+
+ def __init__(self):
+ self.headers_ = ''
+
+ def AddHeaders(self, header_files):
+ """Adds the specified files to the headers to parse."""
+ assert header_files
+ # Slurp all the header files into a single huge big string.
+ # Yummy nonperformant code - but it probably doesn't need to be.
+ headers = []
+ for f in header_files:
+ fo = open(f, 'r')
+ headers.append(fo.read())
+ fo.close()
+ self.headers_ += '\n'.join(headers)
+
+ def _GetInterfaceInfo(self, interface_name):
+ """Returns a tuple (base_interface, method_block) or None."""
+ m = re.search(_INTERFACE_PATTERN % interface_name, self.headers_)
+ if m:
+ return (m.group('base'), m.group('method_block'))
+ else:
+ return None
+
+ @staticmethod
+ def _ProcessParams(params):
+ """Return a tuple (count, cleaned_up_params)."""
+ if params == ' void':
+ return (0, '')
+ else:
+ params = params.replace('\n', ' ')
+ params = _COMMENTS_RE.sub('', params)
+ params = _RPC_RE.sub(' ', params)
+ params = _WHITESPACE_RE.sub(' ', params)
+ params = _DEFAULT_ARG_RE.sub(' ', params)
+ return (params.count(',') + 1, params.strip())
+
+ def _MockMethodsInBlock(self, block):
+ """Return a list of mock functions for each of the methods defined
+ in 'block', which is the text between 'public:' and '};' in an interface
+ definition.
+ """
+ methods = []
+ for m in _METHOD_RE.finditer(block):
+ return_type = m.group('ret')
+ name = m.group('name')
+ params = m.group('params')
+ (param_count, clean_params) = self._ProcessParams(params)
+
+ method_definition = ('MOCK_METHOD%d_WITH_CALLTYPE(__stdcall, %s, %s(%s));'
+ % (param_count, name, return_type, clean_params))
+ if len(method_definition) > 78:
+ method_definition = (
+ 'MOCK_METHOD%d_WITH_CALLTYPE(__stdcall, %s, %s(\n %s));' %
+ (param_count, name, return_type, clean_params))
+ methods.append(method_definition)
+ return methods
+
+ def MockInterface(self, name):
+ """Returns a list of all the mock methods needed for the given
+ interface (including methods from inherited interfaces, but stopping
+ short of IDispatch and IUnknown).
+ """
+ info = self._GetInterfaceInfo(name)
+ if not info:
+ return ''
+
+ # Generate inherited methods
+ methods = []
+ if info[0] not in ('IUnknown', 'IDispatch'):
+ methods.extend(self.MockInterface(info[0]))
+ methods.extend(self._MockMethodsInBlock(info[1]))
+ return methods
+
+
+def MockMethods(interface_name, header_files):
+ """Returns a string with a correctly filled-out MOCK_METHODX(...) line
+ for each method in the given interface, plus all of its inherited interfaces,
+ terminating when IDispatch or IUnknown is reached.
+
+ You must list all header files required to find the interface itself and
+ all of the interfaces it inherits from, except IDispatch and IUnknown.
+
+ Header files must be IDL-generated for the pattern matching used in the
+ code to work correctly.
+
+ Args:
+ interface_name: 'IWebBrowser2'
+ header_files: ['c:\\platform_sdk\\files\\Include\\exdisp.h',
+ 'c:\\platform_sdk\\files\\Include\\oaidl.h']
+
+ Returns:
+ 'MOCK_METHOD1_WITH_CALLTYPE(__stdcall, GetWindow, HRESULT()); ...'
+ """
+ mocker = Mocker()
+ mocker.AddHeaders(header_files)
+ return '\n'.join(mocker.MockInterface(interface_name))
+
+
+def Main(args):
+ if not args or len(args) < 2:
+ print __doc__
+ return 1
+ else:
+ print _FILE_HEADER
+ print MockMethods(args[0], args[1:])
+ return 0
+
+
+if __name__ == '__main__':
+ sys.exit(Main(sys.argv[1:]))
diff --git a/ceee/testing/utils/dispex_mocks.h b/ceee/testing/utils/dispex_mocks.h
new file mode 100644
index 0000000..cf4b04d
--- /dev/null
+++ b/ceee/testing/utils/dispex_mocks.h
@@ -0,0 +1,129 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Mock class implementations for IDispatch/IDispatchEx.
+#ifndef CEEE_TESTING_UTILS_DISPEX_MOCKS_H_
+#define CEEE_TESTING_UTILS_DISPEX_MOCKS_H_
+
+#include <dispex.h>
+#include "gmock/gmock.h"
+#include "ceee/common/initializing_coclass.h"
+#include "ceee/testing/utils/instance_count_mixin.h"
+
+namespace testing {
+
+class IDispatchExMockImpl: public IDispatchEx {
+ public:
+ // The methods in this class are code generated using this command line:
+ // [ tools\com_mock.py IDispatchEx "%WindowsSdkDir%\Include\dispex.h" ]
+ // (and then massaged slightly by hand)
+#include "ceee/testing/utils/mock_idispatchex.gen"
+};
+
+// A mock implementation of IDispatch(Ex) with a handy set of
+// functions to set up an expectation for Invoke.
+class MockDispatchEx
+ : public CComObjectRootEx<CComSingleThreadModel>,
+ public InitializingCoClass<MockDispatchEx>,
+ public InstanceCountMixin<MockDispatchEx>,
+ public StrictMock<IDispatchExMockImpl> {
+ public:
+ BEGIN_COM_MAP(MockDispatchEx)
+ COM_INTERFACE_ENTRY(IDispatch)
+ COM_INTERFACE_ENTRY(IDispatchEx)
+ END_COM_MAP()
+
+ HRESULT Initialize(MockDispatchEx** self) {
+ *self = this;
+ return S_OK;
+ }
+
+ // Expect a function invoke with 0 params.
+ void ExpectInvoke(DISPID disp_id) {
+ EXPECT_CALL(*this, Invoke(disp_id, _, _, DISPATCH_METHOD,
+ Field(&DISPPARAMS::cArgs, Eq(0)), _, _, _));
+ }
+
+ // Expect a function invoke with 1 param.
+ template <class A0>
+ void ExpectInvoke(DISPID disp_id, const A0& a0) {
+ EXPECT_CALL(*this, Invoke(disp_id, _, _, DISPATCH_METHOD,
+ AllOf(
+ Field(&DISPPARAMS::cArgs, Eq(1)),
+ DispParamArgEq<0>(CComVariant(a0))),
+ _, _, _));
+ }
+
+ // Expect a function invoke with 2 params.
+ template <class A0, class A1>
+ void ExpectInvoke(DISPID disp_id,
+ const A0& a0,
+ const A1& a1) {
+ // Note the reverse order of dispid params from args.
+ EXPECT_CALL(*this, Invoke(disp_id, _, _, DISPATCH_METHOD,
+ AllOf(
+ Field(&DISPPARAMS::cArgs, Eq(2)),
+ DispParamArgEq<1>(CComVariant(a0)),
+ DispParamArgEq<0>(CComVariant(a1))),
+ _, _, _));
+ }
+
+ // Expect a function invoke with 3 params.
+ template <class A0, class A1, class A2>
+ void ExpectInvoke(DISPID disp_id,
+ const A0& a0,
+ const A1& a1,
+ const A2& a2) {
+ // Note the reverse order of dispid params from args.
+ EXPECT_CALL(*this, Invoke(disp_id, _, _, DISPATCH_METHOD,
+ AllOf(
+ Field(&DISPPARAMS::cArgs, Eq(3)),
+ DispParamArgEq<2>(CComVariant(a0)),
+ DispParamArgEq<1>(CComVariant(a1)),
+ DispParamArgEq<0>(CComVariant(a2))),
+ _, _, _));
+ }
+
+ // Expect a function invoke with 4 params.
+ template <class A0, class A1, class A2, class A3>
+ void ExpectInvoke(DISPID disp_id,
+ const A0& a0,
+ const A1& a1,
+ const A2& a2,
+ const A3& a3) {
+ // Note the reverse order of dispid params from args.
+ EXPECT_CALL(*this, Invoke(disp_id, _, _, DISPATCH_METHOD,
+ AllOf(
+ Field(&DISPPARAMS::cArgs, Eq(4)),
+ DispParamArgEq<3>(CComVariant(a0)),
+ DispParamArgEq<2>(CComVariant(a1)),
+ DispParamArgEq<1>(CComVariant(a2)),
+ DispParamArgEq<0>(CComVariant(a3))),
+ _, _, _));
+ }
+
+ // Expect a function invoke with 5 params.
+ template <class A0, class A1, class A2, class A3, class A4>
+ void ExpectInvoke(DISPID disp_id,
+ const A0& a0,
+ const A1& a1,
+ const A2& a2,
+ const A3& a3,
+ const A4& a4) {
+ // Note the reverse order of dispid params from args.
+ EXPECT_CALL(*this, Invoke(disp_id, _, _, DISPATCH_METHOD,
+ AllOf(Field(&DISPPARAMS::cArgs, Eq(5)),
+ AllOf(
+ DispParamArgEq<4>(CComVariant(a0)),
+ DispParamArgEq<3>(CComVariant(a1)),
+ DispParamArgEq<2>(CComVariant(a2)),
+ DispParamArgEq<1>(CComVariant(a3)),
+ DispParamArgEq<0>(CComVariant(a4)))),
+ _, _, _));
+ }
+};
+
+} // testing
+
+#endif // CEEE_TESTING_UTILS_DISPEX_MOCKS_H_
diff --git a/ceee/testing/utils/gflag_utils.cc b/ceee/testing/utils/gflag_utils.cc
new file mode 100644
index 0000000..b30553a
--- /dev/null
+++ b/ceee/testing/utils/gflag_utils.cc
@@ -0,0 +1,157 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Implementation of the launch with gflags function.
+#include "ceee/testing/utils/gflag_utils.h"
+
+#include "ceee/testing/utils/nt_internals.h"
+#include <shlwapi.h>
+
+namespace testing {
+
+using nt_internals::NTSTATUS;
+using nt_internals::NtQueryInformationProcess;
+
+HRESULT WriteProcessGFlags(HANDLE process, DWORD gflags) {
+ nt_internals::PROCESS_BASIC_INFORMATION basic_info = {};
+ ULONG return_len = 0;
+ NTSTATUS status =
+ NtQueryInformationProcess(process,
+ nt_internals::ProcessBasicInformation,
+ &basic_info,
+ sizeof(basic_info),
+ &return_len);
+ if (0 != status)
+ return HRESULT_FROM_NT(status);
+ else if (return_len != sizeof(basic_info))
+ return E_UNEXPECTED;
+
+ LPVOID gflags_location =
+ reinterpret_cast<char*>(basic_info.PebBaseAddress) + kGFlagsPEBOffset;
+
+ SIZE_T num_written = 0;
+ if (!::WriteProcessMemory(process,
+ gflags_location,
+ &gflags,
+ sizeof(gflags),
+ &num_written) ||
+ sizeof(gflags) != num_written)
+ return HRESULT_FROM_WIN32(::GetLastError());
+
+ return S_OK;
+}
+
+HRESULT CreateProcessWithGFlags(LPCWSTR application_name,
+ LPWSTR command_line,
+ LPSECURITY_ATTRIBUTES process_attributes,
+ LPSECURITY_ATTRIBUTES thread_attributes,
+ BOOL inherit_handles,
+ DWORD creation_flags,
+ LPVOID environment,
+ LPCWSTR current_directory,
+ LPSTARTUPINFOW startup_info,
+ LPPROCESS_INFORMATION proc_info,
+ DWORD gflags) {
+ // Create the process, but make sure it's suspended at creation.
+ BOOL created = ::CreateProcess(application_name,
+ command_line,
+ process_attributes,
+ thread_attributes,
+ inherit_handles,
+ creation_flags | CREATE_SUSPENDED,
+ environment,
+ current_directory,
+ startup_info,
+ proc_info);
+ if (!created)
+ return HRESULT_FROM_WIN32(::GetLastError());
+
+ // If we succeeded, go through and write the new process'
+ // PEB with the requested gflags.
+ HRESULT hr = WriteProcessGFlags(proc_info->hProcess, gflags);
+ if (FAILED(hr)) {
+ // We failed to write the gflags value, clean up and bail.
+ ::TerminateProcess(proc_info->hProcess, 0);
+ ::CloseHandle(proc_info->hProcess);
+ ::CloseHandle(proc_info->hThread);
+
+ return hr;
+ }
+
+ // Resume the main thread unless suspended creation was requested.
+ if (!(creation_flags & CREATE_SUSPENDED))
+ ::ResumeThread(proc_info->hThread);
+
+ return hr;
+}
+
+HRESULT RelaunchWithGFlags(DWORD wanted_gflags) {
+ DWORD current_gflags = nt_internals::RtlGetNtGlobalFlags();
+
+ // Do we already have all the wanted_gflags?
+ if (wanted_gflags == (wanted_gflags & current_gflags))
+ return S_FALSE;
+
+ wchar_t app_name[MAX_PATH] = {};
+ if (!::GetModuleFileName(NULL, app_name, ARRAYSIZE(app_name)))
+ return HRESULT_FROM_WIN32(::GetLastError());
+
+ // If there is a GFlags registry entry for our executable, we don't
+ // want to relaunch because it's futile. The spawned process would pick
+ // up the registry settings in preference to ours, and we'd effectively
+ // have a fork bomb on our hands.
+ wchar_t key_name[MAX_PATH] =
+ L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\"
+ L"Image File Execution Options\\";
+
+ if (0 != wcscat_s(key_name, ::PathFindFileName(app_name)))
+ return E_UNEXPECTED;
+
+ HKEY key = NULL;
+ LONG err = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE, key_name, 0, KEY_READ, &key);
+ if (err == ERROR_SUCCESS) {
+ // There's a setting for this executable in registry, does it
+ // specify global flags?
+ DWORD data_len = 0;
+ err = ::RegQueryValueEx(key, L"GlobalFlag", NULL, NULL, NULL, &data_len);
+
+ // Close the key.
+ ::RegCloseKey(key);
+
+ if (err == ERROR_SUCCESS) {
+ // We can't relaunch because we'd run the risk of a fork bomb.
+ return E_FAIL;
+ }
+ }
+
+ wchar_t current_dir[MAX_PATH] = {};
+ if (!::GetCurrentDirectory(ARRAYSIZE(current_dir), current_dir))
+ return HRESULT_FROM_WIN32(::GetLastError());
+
+ STARTUPINFO startup_info = {};
+ ::GetStartupInfo(&startup_info);
+ PROCESS_INFORMATION proc_info = {};
+ HRESULT hr;
+ hr = CreateProcessWithGFlags(app_name,
+ ::GetCommandLine(),
+ NULL,
+ NULL,
+ FALSE,
+ 0,
+ NULL,
+ current_dir,
+ &startup_info,
+ &proc_info,
+ current_gflags | wanted_gflags);
+ if (SUCCEEDED(hr)) {
+ ::WaitForSingleObject(proc_info.hProcess, INFINITE);
+ DWORD exit_code = 0;
+ ::GetExitCodeProcess(proc_info.hProcess, &exit_code);
+ ::ExitProcess(exit_code);
+ }
+
+ return hr;
+}
+
+} // namespace testing
diff --git a/ceee/testing/utils/gflag_utils.h b/ceee/testing/utils/gflag_utils.h
new file mode 100644
index 0000000..fe88721
--- /dev/null
+++ b/ceee/testing/utils/gflag_utils.h
@@ -0,0 +1,125 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Utilities and declarations to do with GFlags.
+#ifndef CEEE_TESTING_UTILS_GFLAG_UTILS_H_
+#define CEEE_TESTING_UTILS_GFLAG_UTILS_H_
+
+#include <windows.h>
+
+namespace testing {
+
+// Offset to the NtGlobalFlags from observation of running processes.
+#ifdef _WIN64
+// For 64 bit processes.
+const ptrdiff_t kGFlagsPEBOffset = 0xBC;
+#else
+// For 32 bit processes.
+const ptrdiff_t kGFlagsPEBOffset = 0x68;
+#endif
+
+// Nt global flags values gleaned from MSDN documentation
+// at e.g. http://msdn.microsoft.com/en-us/library/cc265893.aspx.
+
+// Stop on exception
+#define FLG_STOP_ON_EXCEPTION 0x00000001
+// Show loader snaps
+#define FLG_SHOW_LDR_SNAPS 0x00000002
+// Debug initial command
+#define FLG_DEBUG_INITIAL_COMMAND 0x00000004
+// Stop on hung GUI
+#define FLG_STOP_ON_HUNG_GUI 0x00000008
+// Enable heap tail checking
+#define FLG_HEAP_ENABLE_TAIL_CHECK 0x00000010
+// Enable heap free checking
+#define FLG_HEAP_ENABLE_FREE_CHECK 0x00000020
+// Enable heap parameter checking
+#define FLG_HEAP_VALIDATE_PARAMETERS 0x00000040
+// Enable heap validation on call
+#define FLG_HEAP_VALIDATE_ALL 0x00000080
+// Enable application verifier
+#define FLG_APPLICATION_VERIFIER 0x00000100
+// Enable pool tagging (Windows 2000 and Windows XP only)
+#define FLG_POOL_ENABLE_TAGGING 0x00000400
+// Enable heap tagging
+#define FLG_HEAP_ENABLE_TAGGING 0x00000800
+// Create user mode stack trace database
+#define FLG_USER_STACK_TRACE_DB 0x00001000
+// Create kernel mode stack trace database
+#define FLG_KERNEL_STACK_TRACE_DB 0x00002000
+// Maintain a list of objects for each type
+#define FLG_MAINTAIN_OBJECT_TYPELIST 0x00004000
+// Enable heap tagging by DLL
+#define FLG_HEAP_ENABLE_TAG_BY_DLL 0x00008000
+// Disable stack extension
+#define FLG_DISABLE_STACK_EXTENSION 0x00010000
+// Enable debugging of Win32 subsystem
+#define FLG_ENABLE_CSRDEBUG 0x00020000
+// Enable loading of kernel debugger symbols
+#define FLG_ENABLE_KDEBUG_SYMBOL_LOAD 0x00040000
+// Disable paging of kernel stacks
+#define FLG_DISABLE_PAGE_KERNEL_STACKS 0x00080000
+// Enable system critical breaks
+#define FLG_ENABLE_SYSTEM_CRIT_BREAKS 0x00100000
+// Disable heap coalesce on free
+#define FLG_HEAP_DISABLE_COALESCING 0x00200000
+// Enable close exception
+#define FLG_ENABLE_CLOSE_EXCEPTIONS 0x00400000
+// Enable exception logging
+#define FLG_ENABLE_EXCEPTION_LOGGING 0x00800000
+// Enable object handle type tagging
+#define FLG_ENABLE_HANDLE_TYPE_TAGGING 0x01000000
+// Enable page heap
+#define FLG_HEAP_PAGE_ALLOCS 0x02000000
+// Debug WinLogon
+#define FLG_DEBUG_INITIAL_COMMAND_EX 0x04000000
+// Buffer DbgPrint output
+#define FLG_DISABLE_DBGPRINT 0x08000000
+// Early critical section event creation
+#define FLG_CRITSEC_EVENT_CREATION 0x10000000
+// Load DLLs top-down (Win64 only)
+#define FLG_LDR_TOP_DOWN 0x20000000
+// Enable bad handles detection
+#define FLG_ENABLE_HANDLE_EXCEPTIONS 0x40000000
+// Disable protected DLL verification
+#define FLG_DISABLE_PROTDLLS 0x80000000
+#define FLG_VALID_BITS 0x7FFFFFFF
+
+
+// Writes gflags to process' PEB.
+// @param process a handle the the process, must grant
+// PROCESS_QUERY_INFORMATION, PROCESS_VM_WRITE and
+// PROCESS_VM_OPERATION.
+// @param gflags the set of nt global flags to write.
+HRESULT WriteProcessGFlags(HANDLE process, DWORD gflags);
+
+// Creates a new process with the supplied gflags.
+// Parameters are the same as for ::CreateProcess.
+HRESULT CreateProcessWithGFlags(LPCWSTR application_name,
+ LPWSTR command_line,
+ LPSECURITY_ATTRIBUTES process_attributes,
+ LPSECURITY_ATTRIBUTES thread_attributes,
+ BOOL inherit_handles,
+ DWORD creation_flags,
+ LPVOID environment,
+ LPCWSTR current_directory,
+ LPSTARTUPINFOW startup_info,
+ LPPROCESS_INFORMATION proc_info,
+ DWORD gflags);
+
+// Relaunches the current executable with the same command
+// line, environment, current directory, as this process has,
+// but with the supplied gflags in addition to the current process'
+// gflags.
+// @param wanted_gflags the set of global flags requested.
+// @return S_FALSE if the current process is already running with
+// all of the supplied flags, or an appropriate error otherwise.
+// @note On success, this function will not return, but will
+// call ExitProcess to propagate the exit code of the
+// relaunched child process.
+HRESULT RelaunchWithGFlags(DWORD wanted_gflags);
+
+} // namespace testing
+
+#endif // CEEE_TESTING_UTILS_GFLAG_UTILS_H_
diff --git a/ceee/testing/utils/gflag_utils_unittest.cc b/ceee/testing/utils/gflag_utils_unittest.cc
new file mode 100644
index 0000000..c48bfc7
--- /dev/null
+++ b/ceee/testing/utils/gflag_utils_unittest.cc
@@ -0,0 +1,28 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Unittests for the gflags utilities.
+#include "gtest/gtest.h"
+#include "ceee/testing/utils/gflag_utils.h"
+#include "ceee/testing/utils/nt_internals.h"
+
+namespace testing {
+
+TEST(GFlagUtilsTest, WriteProcessGFlags) {
+ // Get our own global flags.
+ ULONG old_gflags = nt_internals::RtlGetNtGlobalFlags();
+
+ // Toggle one bit.
+ ULONG new_gflags = old_gflags ^ FLG_SHOW_LDR_SNAPS;
+ EXPECT_HRESULT_SUCCEEDED(WriteProcessGFlags(::GetCurrentProcess(),
+ new_gflags));
+ EXPECT_EQ(new_gflags, nt_internals::RtlGetNtGlobalFlags());
+
+ // Restore old global flags.
+ EXPECT_HRESULT_SUCCEEDED(WriteProcessGFlags(::GetCurrentProcess(),
+ old_gflags));
+ EXPECT_EQ(old_gflags, nt_internals::RtlGetNtGlobalFlags());
+}
+
+} // namespace testing
diff --git a/ceee/testing/utils/instance_count_mixin.cc b/ceee/testing/utils/instance_count_mixin.cc
new file mode 100644
index 0000000..c6d8bdc
--- /dev/null
+++ b/ceee/testing/utils/instance_count_mixin.cc
@@ -0,0 +1,64 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Implementation of instance count mixin base class.
+#include "ceee/testing/utils/instance_count_mixin.h"
+#include "base/logging.h"
+#include "gtest/gtest.h"
+
+namespace {
+// Set of existing instances.
+testing::InstanceCountMixinBase::InstanceSet instances;
+};
+
+namespace testing {
+
+Lock InstanceCountMixinBase::lock_;
+
+InstanceCountMixinBase::InstanceCountMixinBase() {
+ AutoLock lock(lock_);
+
+ instances.insert(this);
+}
+
+InstanceCountMixinBase::~InstanceCountMixinBase() {
+ AutoLock lock(lock_);
+
+ EXPECT_EQ(1, instances.erase(this));
+}
+
+void InstanceCountMixinBase::GetDescription(std::string* description) const {
+ *description = "Override GetDescription in your test classes\n"
+ "to get useful information about the leaked objects.";
+}
+
+void InstanceCountMixinBase::LogLeakedInstances() {
+ AutoLock lock(lock_);
+
+ InstanceSet::const_iterator it(instances.begin());
+ InstanceSet::const_iterator end(instances.end());
+
+ for (; it != end; ++it) {
+ std::string description;
+ (*it)->GetDescription(&description);
+ LOG(ERROR) << "Leaked: " << description.c_str();
+ }
+}
+
+typedef InstanceCountMixinBase::InstanceSet InstanceSet;
+
+size_t InstanceCountMixinBase::all_instance_count() {
+ AutoLock lock(lock_);
+ return instances.size();
+}
+
+InstanceSet::const_iterator InstanceCountMixinBase::begin() {
+ return instances.begin();
+}
+
+InstanceSet::const_iterator InstanceCountMixinBase::end() {
+ return instances.end();
+}
+
+} // namespace testing
diff --git a/ceee/testing/utils/instance_count_mixin.h b/ceee/testing/utils/instance_count_mixin.h
new file mode 100644
index 0000000..11627da
--- /dev/null
+++ b/ceee/testing/utils/instance_count_mixin.h
@@ -0,0 +1,82 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// A mixin class that makes it easy to assert on test object
+// instance counts.
+#ifndef CEEE_TESTING_UTILS_INSTANCE_COUNT_MIXIN_H_
+#define CEEE_TESTING_UTILS_INSTANCE_COUNT_MIXIN_H_
+
+#include <string>
+#include <set>
+
+#include "base/lock.h"
+
+namespace testing {
+
+// A base class for the InstanceCountMixin template class below.
+// The base class keeps a set of all derived class instances,
+// which allows tests to assert on object counts and to enumerate
+// leaked objects.
+class InstanceCountMixinBase {
+ public:
+ InstanceCountMixinBase();
+ virtual ~InstanceCountMixinBase();
+
+ // Override this in subclasses to provide a description of the instance.
+ // @note If you find that your tests are leaking objects, it can make your
+ // life easier to override this function in your test classes and invoke
+ // LogLeakedObjects to get a handle on the type and identity of the leaked
+ // objects.
+ virtual void GetDescription(std::string* description) const;
+
+ // Logs the description of every instance to the error log.
+ static void LogLeakedInstances();
+
+ // @return the count of all InstanceCountMixinBase-derived instances.
+ static size_t all_instance_count();
+
+ typedef std::set<InstanceCountMixinBase*> InstanceSet;
+
+ // @return the start enumerator over the existing instances.
+ // @note use of this enumerator is not thread safe.
+ static InstanceSet::const_iterator begin();
+
+ // @return the end enumerator over the existing instances.
+ // @note use of this enumerator is not thread safe.
+ static InstanceSet::const_iterator end();
+
+ protected:
+ static Lock lock_;
+};
+
+// Inherit test classes from this class to get a per-class instance count.
+// Usage:
+// class TestFoo: public InstanceCountMixin<TestFoo> {
+// }
+//
+// EXPECT_EQ(0, TestFoo::instance_count());
+template <class T>
+class InstanceCountMixin : public InstanceCountMixinBase {
+ public:
+ InstanceCountMixin() {
+ AutoLock lock(lock_);
+ ++instance_count_;
+ }
+ ~InstanceCountMixin() {
+ AutoLock lock(lock_);
+ --instance_count_;
+ }
+
+ // @return the number of T instances.
+ static size_t instance_count() { return instance_count_; }
+
+ private:
+ static size_t instance_count_;
+};
+
+template <class T> size_t InstanceCountMixin<T>::instance_count_ = 0;
+
+} // namespace testing
+
+#endif // CEEE_TESTING_UTILS_INSTANCE_COUNT_MIXIN_H_
diff --git a/ceee/testing/utils/instance_count_mixin_unittest.cc b/ceee/testing/utils/instance_count_mixin_unittest.cc
new file mode 100644
index 0000000..ceaf3c2
--- /dev/null
+++ b/ceee/testing/utils/instance_count_mixin_unittest.cc
@@ -0,0 +1,79 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Implementation of instance count mixin class.
+#include "ceee/testing/utils/instance_count_mixin.h"
+#include "gtest/gtest.h"
+
+namespace testing {
+
+class TestMixin1 : public InstanceCountMixin<TestMixin1> {
+ public:
+};
+class TestMixin2 : public InstanceCountMixin<TestMixin2> {
+ public:
+};
+
+TEST(InstanceCountMixinTest, AllInstanceCounts) {
+ ASSERT_EQ(0, TestMixin1::all_instance_count());
+ ASSERT_EQ(0, TestMixin2::all_instance_count());
+
+ {
+ TestMixin1 one;
+
+ ASSERT_EQ(1, TestMixin1::all_instance_count());
+ ASSERT_EQ(1, TestMixin2::all_instance_count());
+
+ TestMixin2 two;
+
+ ASSERT_EQ(2, TestMixin1::all_instance_count());
+ ASSERT_EQ(2, TestMixin2::all_instance_count());
+ }
+
+ ASSERT_EQ(0, TestMixin1::all_instance_count());
+ ASSERT_EQ(0, TestMixin2::all_instance_count());
+}
+
+TEST(InstanceCountMixinTest, ClassInstanceCounts) {
+ ASSERT_EQ(0, TestMixin1::instance_count());
+ ASSERT_EQ(0, TestMixin2::instance_count());
+
+ {
+ TestMixin1 one;
+
+ ASSERT_EQ(1, TestMixin1::instance_count());
+ ASSERT_EQ(0, TestMixin2::instance_count());
+
+ TestMixin2 two;
+
+ ASSERT_EQ(1, TestMixin1::instance_count());
+ ASSERT_EQ(1, TestMixin2::instance_count());
+ }
+
+ ASSERT_EQ(0, TestMixin1::instance_count());
+ ASSERT_EQ(0, TestMixin2::instance_count());
+}
+
+TEST(InstanceCountMixinTest, Iteration) {
+ ASSERT_TRUE(TestMixin1::begin() == TestMixin1::end());
+ ASSERT_TRUE(TestMixin1::begin() == TestMixin2::begin());
+
+ TestMixin1 one, two;
+ TestMixin2 three, four;
+
+ InstanceCountMixinBase::InstanceSet::const_iterator
+ it(InstanceCountMixinBase::begin());
+ InstanceCountMixinBase::InstanceSet::const_iterator
+ end(InstanceCountMixinBase::end());
+ size_t count = 0;
+
+ for (; it != end; ++it) {
+ ++count;
+ ASSERT_TRUE(*it == &one || *it == &two || *it == &three || *it == &four);
+ }
+
+ ASSERT_EQ(4, count);
+}
+
+} // namespace testing
diff --git a/ceee/testing/utils/mock_com.h b/ceee/testing/utils/mock_com.h
new file mode 100644
index 0000000..36f2d65
--- /dev/null
+++ b/ceee/testing/utils/mock_com.h
@@ -0,0 +1,229 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Mock objects for various COM interfaces.
+
+#ifndef CEEE_TESTING_UTILS_MOCK_COM_H_
+#define CEEE_TESTING_UTILS_MOCK_COM_H_
+
+#include <atlbase.h>
+#include <atlcom.h>
+#include <dispex.h>
+#include <exdisp.h>
+#include <mshtml.h>
+#include <objsafe.h>
+#include <tlogstg.h>
+
+#include "third_party/activscp/activscp.h"
+#include "third_party/activscp/activdbg.h"
+
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace testing {
+
+class IOleObjecMockImpl: public IOleObject {
+ public:
+ // The methods in this class are code generated using this command line:
+ // [ ceee\testing\utils\com_mock.py IOleObject \
+ // "%WindowsSdkDir%\Include\OleIdl.h" ]
+#include "ceee/testing/utils/mock_ioleobject.gen"
+};
+
+class IServiceProviderMockImpl : public IServiceProvider {
+ public:
+ MOCK_METHOD3_WITH_CALLTYPE(__stdcall, QueryService,
+ HRESULT(REFGUID guidService, REFIID riid, void **ppvObject));
+};
+
+class IWebBrowser2MockImpl : public IDispatchImpl<IWebBrowser2,
+ &IID_IWebBrowser2,
+ &LIBID_SHDocVw,
+ 1,
+ 1> {
+ public:
+ // The methods in this class are code generated using this command line:
+ // [ ceee\testing\utils\com_mock.py IWebBrowser2 \
+ // "%WindowsSdkDir%\Include\ExDisp.h" ]
+#include "ceee/testing/utils/mock_iwebbrowser2.gen"
+};
+
+class IObjectSafetyMockImpl : public IObjectSafety {
+ public:
+ // The methods in this class are code generated using this command line:
+ // [ ceee\testing\utils\com_mock.py IObjectSafety \
+ // "%WindowsSdkDir%\Include\ObjSafe.h" ]
+#include "ceee/testing/utils/mock_iobjectsafety.gen"
+};
+
+class IActiveScriptMockImpl : public IActiveScript {
+ public:
+ // The methods in this class are code generated using this command line:
+ // [ ceee\testing\utils\com_mock.py IActiveScript \
+ // third_party\activescp\activescp.h ]
+#include "ceee/testing/utils/mock_iactivescript.gen"
+};
+
+class IActiveScriptParseMockImpl : public IActiveScriptParse {
+ public:
+ // Unfortunately, MOCK_METHODx only exists for x = [0, 10]
+ // and AddScriptlet has 11 arguments. Lucky for us, this interface
+ // only has 3 methods.
+ MOCK_METHOD0_WITH_CALLTYPE(__stdcall, InitNew, HRESULT());
+ MOCK_METHOD9_WITH_CALLTYPE(__stdcall, ParseScriptText, HRESULT(
+ LPCOLESTR pstrCode, LPCOLESTR pstrItemName, IUnknown *punkContext,
+ LPCOLESTR pstrDelimiter, DWORD dwSourceContextCookie,
+ ULONG ulStartingLineNumber, DWORD dwFlags, VARIANT *pvarResult,
+ EXCEPINFO *pexcepinfo));
+
+ // This will not work with GMock as it will not give any indication
+ // as to whether it has been called or not.
+ HRESULT __stdcall AddScriptlet(
+ LPCOLESTR pstrDefaultName, LPCOLESTR pstrCode, LPCOLESTR pstrItemName,
+ LPCOLESTR pstrSubItemName, LPCOLESTR pstrEventName,
+ LPCOLESTR pstrDelimiter, DWORD dwSourceContextCookie,
+ ULONG ulStartingLineNumber, DWORD dwFlags, BSTR *pbstrName,
+ EXCEPINFO *pexcepinfo) {
+ return E_NOTIMPL;
+ }
+};
+
+class IActiveScriptSiteMockImpl : public IActiveScriptSite {
+ public:
+ // The methods in this class are code generated using this command line:
+ // [ ceee\testing\utils\com_mock.py IActiveScriptSite \
+ // third_party\activescp\activescp.h ]
+#include "ceee/testing/utils/mock_iactivescriptsite.gen"
+};
+
+class IActiveScriptSiteDebugMockImpl : public IActiveScriptSiteDebug {
+ public:
+ // The methods in this class are code generated using this command line:
+ // [ ceee\testing\utils\com_mock.py IActiveScriptSiteDebug \
+ // third_party\activescp\activedbg.h ]
+#include "ceee/testing/utils/mock_iactivescriptsitedebug.gen"
+};
+
+class IProcessDebugManagerMockImpl : public IProcessDebugManager {
+ public:
+ // The methods in this class are code generated using this command line:
+ // [ ceee\testing\utils\com_mock.py IProcessDebugManager
+ // third_party\activscp\activdbg.h ]
+#include "ceee/testing/utils/mock_iprocessdebugmanager.gen"
+};
+
+class IDebugApplicationMockImpl : public IDebugApplication {
+ public:
+ // The methods in this class are code generated using this command line:
+ // [ ceee\testing\utils\com_mock.py IDebugApplication \
+ // third_party\activscp\activdbg.h ]
+#include "ceee/testing/utils/mock_idebugapplication.gen"
+};
+
+class IDebugDocumentHelperMockImpl : public IDebugDocumentHelper {
+ public:
+ // The methods in this class are code generated using this command line:
+ // [ ceee\testing\utils\com_mock.py IDebugDocumentHelper \
+ // third_party\activscp\activdbg.h ]
+#include "ceee/testing/utils/mock_idebugdocumenthelper.gen"
+};
+
+class ITravelLogStgMockImpl : public ITravelLogStg {
+ public:
+ // The methods in this class are code generated using this command line:
+ // [ ceee\testing\utils\com_mock.py ITravelLogStg \
+ // "%WindowsSdkDir%\Include\tlogstg.h" ]
+#include "ceee/testing/utils/mock_itravellogstg.gen"
+};
+
+class MockIServiceProvider
+ : public CComObjectRootEx<CComSingleThreadModel>,
+ public testing::StrictMock<IServiceProviderMockImpl> {
+ DECLARE_NOT_AGGREGATABLE(MockIServiceProvider )
+ BEGIN_COM_MAP(MockIServiceProvider)
+ COM_INTERFACE_ENTRY(IServiceProvider)
+ END_COM_MAP()
+ DECLARE_PROTECT_FINAL_CONSTRUCT()
+
+ HRESULT Initialize(MockIServiceProvider** browser) {
+ *browser = this;
+ return S_OK;
+ }
+};
+
+class MockIWebBrowser2
+ : public CComObjectRootEx<CComSingleThreadModel>,
+ public StrictMock<IWebBrowser2MockImpl>,
+ public StrictMock<IServiceProviderMockImpl> {
+ public:
+ DECLARE_NOT_AGGREGATABLE(MockIWebBrowser2)
+ BEGIN_COM_MAP(MockIWebBrowser2)
+ COM_INTERFACE_ENTRY(IDispatch)
+ COM_INTERFACE_ENTRY(IWebBrowser2)
+ COM_INTERFACE_ENTRY(IWebBrowserApp)
+ COM_INTERFACE_ENTRY(IWebBrowser)
+ COM_INTERFACE_ENTRY(IServiceProvider)
+ END_COM_MAP()
+ DECLARE_PROTECT_FINAL_CONSTRUCT()
+
+ HRESULT Initialize(MockIWebBrowser2** browser) {
+ *browser = this;
+ return S_OK;
+ }
+};
+
+class MockIProcessDebugManager
+ : public CComObjectRootEx<CComSingleThreadModel>,
+ public StrictMock<IProcessDebugManagerMockImpl> {
+ public:
+ BEGIN_COM_MAP(MockIProcessDebugManager)
+ COM_INTERFACE_ENTRY(IProcessDebugManager)
+ END_COM_MAP()
+
+ HRESULT Initialize(MockIProcessDebugManager** debug_manager) {
+ *debug_manager = this;
+ return S_OK;
+ }
+};
+
+class MockIDebugApplication
+ : public CComObjectRootEx<CComSingleThreadModel>,
+ public StrictMock<IDebugApplicationMockImpl> {
+ public:
+ BEGIN_COM_MAP(MockIDebugApplication)
+ COM_INTERFACE_ENTRY(IDebugApplication)
+ END_COM_MAP()
+
+ HRESULT Initialize(MockIDebugApplication** debug_application) {
+ *debug_application = this;
+ return S_OK;
+ }
+};
+
+class MockIDebugDocumentHelper
+ : public CComObjectRootEx<CComSingleThreadModel>,
+ public StrictMock<IDebugDocumentHelperMockImpl> {
+ public:
+ BEGIN_COM_MAP(MockIDebugDocumentHelper)
+ COM_INTERFACE_ENTRY(IDebugDocumentHelper)
+ END_COM_MAP();
+
+ HRESULT Initialize(MockIDebugDocumentHelper** debug_document) {
+ *debug_document = this;
+ return S_OK;
+ }
+};
+
+class MockITravelLogStg : public CComObjectRootEx<CComSingleThreadModel>,
+ public StrictMock<ITravelLogStgMockImpl> {
+ public:
+ DECLARE_NOT_AGGREGATABLE(MockITravelLogStg)
+ BEGIN_COM_MAP(MockITravelLogStg)
+ COM_INTERFACE_ENTRY(ITravelLogStg)
+ END_COM_MAP()
+ DECLARE_PROTECT_FINAL_CONSTRUCT()
+};
+
+} // namespace testing
+
+#endif // CEEE_TESTING_UTILS_MOCK_COM_H_
diff --git a/ceee/testing/utils/mock_iactivescript.gen b/ceee/testing/utils/mock_iactivescript.gen
new file mode 100644
index 0000000..8733d80
--- /dev/null
+++ b/ceee/testing/utils/mock_iactivescript.gen
@@ -0,0 +1,31 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Auto-generated by com_mock.py
+
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, SetScriptSite, HRESULT(
+ IActiveScriptSite *pass));
+MOCK_METHOD2_WITH_CALLTYPE(__stdcall, GetScriptSite, HRESULT(
+ REFIID riid, void *__RPC_FAR *ppvObject));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, SetScriptState, HRESULT(
+ SCRIPTSTATE ss));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, GetScriptState, HRESULT(
+ SCRIPTSTATE *pssState));
+MOCK_METHOD0_WITH_CALLTYPE(__stdcall, Close, HRESULT());
+MOCK_METHOD2_WITH_CALLTYPE(__stdcall, AddNamedItem, HRESULT(
+ LPCOLESTR pstrName, DWORD dwFlags));
+MOCK_METHOD4_WITH_CALLTYPE(__stdcall, AddTypeLib, HRESULT(
+ REFGUID rguidTypeLib, DWORD dwMajor, DWORD dwMinor, DWORD dwFlags));
+MOCK_METHOD2_WITH_CALLTYPE(__stdcall, GetScriptDispatch, HRESULT(
+ LPCOLESTR pstrItemName, IDispatch *__RPC_FAR *ppdisp));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, GetCurrentScriptThreadID, HRESULT(
+ SCRIPTTHREADID *pstidThread));
+MOCK_METHOD2_WITH_CALLTYPE(__stdcall, GetScriptThreadID, HRESULT(
+ DWORD dwWin32ThreadId, SCRIPTTHREADID *pstidThread));
+MOCK_METHOD2_WITH_CALLTYPE(__stdcall, GetScriptThreadState, HRESULT(
+ SCRIPTTHREADID stidThread, SCRIPTTHREADSTATE *pstsState));
+MOCK_METHOD3_WITH_CALLTYPE(__stdcall, InterruptScriptThread, HRESULT(
+ SCRIPTTHREADID stidThread, const EXCEPINFO *pexcepinfo, DWORD dwFlags));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, Clone, HRESULT(
+ IActiveScript *__RPC_FAR *ppscript));
diff --git a/ceee/testing/utils/mock_iactivescriptsite.gen b/ceee/testing/utils/mock_iactivescriptsite.gen
new file mode 100644
index 0000000..d6b18ca
--- /dev/null
+++ b/ceee/testing/utils/mock_iactivescriptsite.gen
@@ -0,0 +1,20 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Auto-generated by com_mock.py
+
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, GetLCID, HRESULT(LCID *plcid));
+MOCK_METHOD4_WITH_CALLTYPE(__stdcall, GetItemInfo, HRESULT(
+ LPCOLESTR pstrName, DWORD dwReturnMask, IUnknown *__RPC_FAR *ppiunkItem,
+ ITypeInfo *__RPC_FAR *ppti));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, GetDocVersionString, HRESULT(
+ BSTR *pbstrVersion));
+MOCK_METHOD2_WITH_CALLTYPE(__stdcall, OnScriptTerminate, HRESULT(
+ const VARIANT *pvarResult, const EXCEPINFO *pexcepinfo));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, OnStateChange, HRESULT(
+ SCRIPTSTATE ssScriptState));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, OnScriptError, HRESULT(
+ IActiveScriptError *pscripterror));
+MOCK_METHOD0_WITH_CALLTYPE(__stdcall, OnEnterScript, HRESULT());
+MOCK_METHOD0_WITH_CALLTYPE(__stdcall, OnLeaveScript, HRESULT());
diff --git a/ceee/testing/utils/mock_iactivescriptsitedebug.gen b/ceee/testing/utils/mock_iactivescriptsitedebug.gen
new file mode 100644
index 0000000..7714dc3
--- /dev/null
+++ b/ceee/testing/utils/mock_iactivescriptsitedebug.gen
@@ -0,0 +1,16 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Auto-generated by com_mock.py
+
+MOCK_METHOD4_WITH_CALLTYPE(__stdcall, GetDocumentContextFromPosition, HRESULT(
+ DWORD dwSourceContext, ULONG uCharacterOffset, ULONG uNumChars,
+ IDebugDocumentContext *__RPC_FAR *ppsc));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, GetApplication, HRESULT(
+ IDebugApplication *__RPC_FAR *ppda));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, GetRootApplicationNode, HRESULT(
+ IDebugApplicationNode *__RPC_FAR *ppdanRoot));
+MOCK_METHOD3_WITH_CALLTYPE(__stdcall, OnScriptErrorDebug, HRESULT(
+ IActiveScriptErrorDebug *pErrorDebug, BOOL *pfEnterDebugger,
+ BOOL *pfCallOnScriptErrorWhenContinuing));
diff --git a/ceee/testing/utils/mock_idebugapplication.gen b/ceee/testing/utils/mock_idebugapplication.gen
new file mode 100644
index 0000000..50c542f
--- /dev/null
+++ b/ceee/testing/utils/mock_idebugapplication.gen
@@ -0,0 +1,62 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Auto-generated by com_mock.py
+
+MOCK_METHOD3_WITH_CALLTYPE(__stdcall, ResumeFromBreakPoint, HRESULT(
+ IRemoteDebugApplicationThread *prptFocus, BREAKRESUMEACTION bra,
+ ERRORRESUMEACTION era));
+MOCK_METHOD0_WITH_CALLTYPE(__stdcall, CauseBreak, HRESULT());
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, ConnectDebugger, HRESULT(
+ IApplicationDebugger *pad));
+MOCK_METHOD0_WITH_CALLTYPE(__stdcall, DisconnectDebugger, HRESULT());
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, GetDebugger, HRESULT(
+ IApplicationDebugger *__RPC_FAR *pad));
+MOCK_METHOD5_WITH_CALLTYPE(__stdcall, CreateInstanceAtApplication, HRESULT(
+ REFCLSID rclsid, IUnknown *pUnkOuter, DWORD dwClsContext, REFIID riid,
+ IUnknown *__RPC_FAR *ppvObject));
+MOCK_METHOD0_WITH_CALLTYPE(__stdcall, QueryAlive, HRESULT());
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, EnumThreads, HRESULT(
+ IEnumRemoteDebugApplicationThreads *__RPC_FAR *pperdat));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, GetName, HRESULT(BSTR *pbstrName));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, GetRootNode, HRESULT(
+ IDebugApplicationNode *__RPC_FAR *ppdanRoot));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, EnumGlobalExpressionContexts, HRESULT(
+ IEnumDebugExpressionContexts *__RPC_FAR *ppedec));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, SetName, HRESULT(LPCOLESTR pstrName));
+MOCK_METHOD0_WITH_CALLTYPE(__stdcall, StepOutComplete, HRESULT());
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, DebugOutput, HRESULT(LPCOLESTR pstr));
+MOCK_METHOD0_WITH_CALLTYPE(__stdcall, StartDebugSession, HRESULT());
+MOCK_METHOD2_WITH_CALLTYPE(__stdcall, HandleBreakPoint, HRESULT(
+ BREAKREASON br, BREAKRESUMEACTION *pbra));
+MOCK_METHOD0_WITH_CALLTYPE(__stdcall, Close, HRESULT());
+MOCK_METHOD2_WITH_CALLTYPE(__stdcall, GetBreakFlags, HRESULT(
+ APPBREAKFLAGS *pabf,
+ IRemoteDebugApplicationThread *__RPC_FAR *pprdatSteppingThread));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, GetCurrentThread, HRESULT(
+ IDebugApplicationThread *__RPC_FAR *pat));
+MOCK_METHOD2_WITH_CALLTYPE(__stdcall, CreateAsyncDebugOperation, HRESULT(
+ IDebugSyncOperation *psdo, IDebugAsyncOperation *__RPC_FAR *ppado));
+MOCK_METHOD2_WITH_CALLTYPE(__stdcall, AddStackFrameSniffer, HRESULT(
+ IDebugStackFrameSniffer *pdsfs, DWORD *pdwCookie));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, RemoveStackFrameSniffer, HRESULT(
+ DWORD dwCookie));
+MOCK_METHOD0_WITH_CALLTYPE(__stdcall, QueryCurrentThreadIsDebuggerThread,
+ HRESULT());
+MOCK_METHOD4_WITH_CALLTYPE(__stdcall, SynchronousCallInDebuggerThread, HRESULT(
+ IDebugThreadCall *pptc, DWORD dwParam1, DWORD dwParam2, DWORD dwParam3));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, CreateApplicationNode, HRESULT(
+ IDebugApplicationNode *__RPC_FAR *ppdanNew));
+MOCK_METHOD2_WITH_CALLTYPE(__stdcall, FireDebuggerEvent, HRESULT(
+ REFGUID riid, IUnknown *punk));
+MOCK_METHOD5_WITH_CALLTYPE(__stdcall, HandleRuntimeError, HRESULT(
+ IActiveScriptErrorDebug *pErrorDebug, IActiveScriptSite *pScriptSite,
+ BREAKRESUMEACTION *pbra, ERRORRESUMEACTION *perra,
+ BOOL *pfCallOnScriptError));
+MOCK_METHOD0_WITH_CALLTYPE(__stdcall, FCanJitDebug, BOOL());
+MOCK_METHOD0_WITH_CALLTYPE(__stdcall, FIsAutoJitDebugEnabled, BOOL());
+MOCK_METHOD2_WITH_CALLTYPE(__stdcall, AddGlobalExpressionContextProvider,
+ HRESULT(IProvideExpressionContexts *pdsfs, DWORD *pdwCookie));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, RemoveGlobalExpressionContextProvider,
+ HRESULT(DWORD dwCookie));
diff --git a/ceee/testing/utils/mock_idebugdocumenthelper.gen b/ceee/testing/utils/mock_idebugdocumenthelper.gen
new file mode 100644
index 0000000..35a2e14
--- /dev/null
+++ b/ceee/testing/utils/mock_idebugdocumenthelper.gen
@@ -0,0 +1,42 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Auto-generated by com_mock.py
+
+MOCK_METHOD4_WITH_CALLTYPE(__stdcall, Init, HRESULT(
+ IDebugApplication *pda, LPCOLESTR pszShortName, LPCOLESTR pszLongName,
+ TEXT_DOC_ATTR docAttr));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, Attach, HRESULT(
+ IDebugDocumentHelper *pddhParent));
+MOCK_METHOD0_WITH_CALLTYPE(__stdcall, Detach, HRESULT());
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, AddUnicodeText, HRESULT(
+ LPCOLESTR pszText));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, AddDBCSText, HRESULT(LPCSTR pszText));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, SetDebugDocumentHost, HRESULT(
+ IDebugDocumentHost *pddh));
+MOCK_METHOD2_WITH_CALLTYPE(__stdcall, AddDeferredText, HRESULT(
+ ULONG cChars, DWORD dwTextStartCookie));
+MOCK_METHOD5_WITH_CALLTYPE(__stdcall, DefineScriptBlock, HRESULT(
+ ULONG ulCharOffset, ULONG cChars, IActiveScript *pas, BOOL fScriptlet,
+ DWORD *pdwSourceContext));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, SetDefaultTextAttr, HRESULT(
+ SOURCE_TEXT_ATTR staTextAttr));
+MOCK_METHOD3_WITH_CALLTYPE(__stdcall, SetTextAttributes, HRESULT(
+ ULONG ulCharOffset, ULONG cChars, SOURCE_TEXT_ATTR *pstaTextAttr));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, SetLongName, HRESULT(
+ LPCOLESTR pszLongName));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, SetShortName, HRESULT(
+ LPCOLESTR pszShortName));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, SetDocumentAttr, HRESULT(
+ TEXT_DOC_ATTR pszAttributes));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, GetDebugApplicationNode, HRESULT(
+ IDebugApplicationNode *__RPC_FAR *ppdan));
+MOCK_METHOD4_WITH_CALLTYPE(__stdcall, GetScriptBlockInfo, HRESULT(
+ DWORD dwSourceContext, IActiveScript *__RPC_FAR *ppasd, ULONG *piCharPos,
+ ULONG *pcChars));
+MOCK_METHOD3_WITH_CALLTYPE(__stdcall, CreateDebugDocumentContext, HRESULT(
+ ULONG iCharPos, ULONG cChars, IDebugDocumentContext *__RPC_FAR *ppddc));
+MOCK_METHOD0_WITH_CALLTYPE(__stdcall, BringDocumentToTop, HRESULT());
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, BringDocumentContextToTop, HRESULT(
+ IDebugDocumentContext *pddc));
diff --git a/ceee/testing/utils/mock_idispatchex.gen b/ceee/testing/utils/mock_idispatchex.gen
new file mode 100644
index 0000000..c2423bf
--- /dev/null
+++ b/ceee/testing/utils/mock_idispatchex.gen
@@ -0,0 +1,34 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Auto-generated by com_mock.py
+
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, GetTypeInfoCount, HRESULT(
+ UINT *pctinfo));
+MOCK_METHOD3_WITH_CALLTYPE(__stdcall, GetTypeInfo, HRESULT(
+ UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo));
+MOCK_METHOD5_WITH_CALLTYPE(__stdcall, GetIDsOfNames, HRESULT(
+ REFIID riid, LPOLESTR *rgszNames, UINT cNames, LCID lcid,
+ DISPID *rgDispId));
+MOCK_METHOD8_WITH_CALLTYPE(__stdcall, Invoke, HRESULT(
+ DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags,
+ DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo,
+ UINT *puArgErr));
+MOCK_METHOD3_WITH_CALLTYPE(__stdcall, GetDispID, HRESULT(
+ BSTR bstrName, DWORD grfdex, DISPID *pid));
+MOCK_METHOD7_WITH_CALLTYPE(__stdcall, InvokeEx, HRESULT(
+ DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp, VARIANT *pvarRes,
+ EXCEPINFO *pei, IServiceProvider *pspCaller));
+MOCK_METHOD2_WITH_CALLTYPE(__stdcall, DeleteMemberByName, HRESULT(
+ BSTR bstrName, DWORD grfdex));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, DeleteMemberByDispID, HRESULT(
+ DISPID id));
+MOCK_METHOD3_WITH_CALLTYPE(__stdcall, GetMemberProperties, HRESULT(
+ DISPID id, DWORD grfdexFetch, DWORD *pgrfdex));
+MOCK_METHOD2_WITH_CALLTYPE(__stdcall, GetMemberName, HRESULT(
+ DISPID id, BSTR *pbstrName));
+MOCK_METHOD3_WITH_CALLTYPE(__stdcall, GetNextDispID, HRESULT(
+ DWORD grfdex, DISPID id, DISPID *pid));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, GetNameSpaceParent, HRESULT(
+ IUnknown **ppunk));
diff --git a/ceee/testing/utils/mock_ihtmldocument2.gen b/ceee/testing/utils/mock_ihtmldocument2.gen
new file mode 100644
index 0000000..a7ec3ae
--- /dev/null
+++ b/ceee/testing/utils/mock_ihtmldocument2.gen
@@ -0,0 +1,145 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Auto-generated by com_mock.py
+
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_Script, HRESULT(IDispatch **p));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_all, HRESULT(
+ IHTMLElementCollection **p));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_body, HRESULT(IHTMLElement **p));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_activeElement, HRESULT(
+ IHTMLElement **p));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_images, HRESULT(
+ IHTMLElementCollection **p));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_applets, HRESULT(
+ IHTMLElementCollection **p));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_links, HRESULT(
+ IHTMLElementCollection **p));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_forms, HRESULT(
+ IHTMLElementCollection **p));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_anchors, HRESULT(
+ IHTMLElementCollection **p));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, put_title, HRESULT(BSTR v));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_title, HRESULT(BSTR *p));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_scripts, HRESULT(
+ IHTMLElementCollection **p));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, put_designMode, HRESULT(BSTR v));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_designMode, HRESULT(BSTR *p));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_selection, HRESULT(
+ IHTMLSelectionObject **p));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_readyState, HRESULT(BSTR *p));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_frames, HRESULT(
+ IHTMLFramesCollection2 **p));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_embeds, HRESULT(
+ IHTMLElementCollection **p));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_plugins, HRESULT(
+ IHTMLElementCollection **p));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, put_alinkColor, HRESULT(VARIANT v));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_alinkColor, HRESULT(VARIANT *p));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, put_bgColor, HRESULT(VARIANT v));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_bgColor, HRESULT(VARIANT *p));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, put_fgColor, HRESULT(VARIANT v));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_fgColor, HRESULT(VARIANT *p));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, put_linkColor, HRESULT(VARIANT v));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_linkColor, HRESULT(VARIANT *p));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, put_vlinkColor, HRESULT(VARIANT v));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_vlinkColor, HRESULT(VARIANT *p));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_referrer, HRESULT(BSTR *p));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_location, HRESULT(
+ IHTMLLocation **p));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_lastModified, HRESULT(BSTR *p));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, put_URL, HRESULT(BSTR v));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_URL, HRESULT(BSTR *p));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, put_domain, HRESULT(BSTR v));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_domain, HRESULT(BSTR *p));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, put_cookie, HRESULT(BSTR v));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_cookie, HRESULT(BSTR *p));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, put_expando, HRESULT(VARIANT_BOOL v));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_expando, HRESULT(VARIANT_BOOL *p));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, put_charset, HRESULT(BSTR v));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_charset, HRESULT(BSTR *p));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, put_defaultCharset, HRESULT(BSTR v));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_defaultCharset, HRESULT(BSTR *p));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_mimeType, HRESULT(BSTR *p));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_fileSize, HRESULT(BSTR *p));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_fileCreatedDate, HRESULT(BSTR *p));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_fileModifiedDate, HRESULT(BSTR *p));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_fileUpdatedDate, HRESULT(BSTR *p));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_security, HRESULT(BSTR *p));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_protocol, HRESULT(BSTR *p));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_nameProp, HRESULT(BSTR *p));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, write, HRESULT(SAFEARRAY * psarray));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, writeln, HRESULT(SAFEARRAY * psarray));
+MOCK_METHOD5_WITH_CALLTYPE(__stdcall, open, HRESULT(
+ BSTR url, VARIANT name, VARIANT features, VARIANT replace, IDispatch **pomWindowResult));
+MOCK_METHOD0_WITH_CALLTYPE(__stdcall, close, HRESULT());
+MOCK_METHOD0_WITH_CALLTYPE(__stdcall, clear, HRESULT());
+MOCK_METHOD2_WITH_CALLTYPE(__stdcall, queryCommandSupported, HRESULT(
+ BSTR cmdID, VARIANT_BOOL *pfRet));
+MOCK_METHOD2_WITH_CALLTYPE(__stdcall, queryCommandEnabled, HRESULT(
+ BSTR cmdID, VARIANT_BOOL *pfRet));
+MOCK_METHOD2_WITH_CALLTYPE(__stdcall, queryCommandState, HRESULT(
+ BSTR cmdID, VARIANT_BOOL *pfRet));
+MOCK_METHOD2_WITH_CALLTYPE(__stdcall, queryCommandIndeterm, HRESULT(
+ BSTR cmdID, VARIANT_BOOL *pfRet));
+MOCK_METHOD2_WITH_CALLTYPE(__stdcall, queryCommandText, HRESULT(
+ BSTR cmdID, BSTR *pcmdText));
+MOCK_METHOD2_WITH_CALLTYPE(__stdcall, queryCommandValue, HRESULT(
+ BSTR cmdID, VARIANT *pcmdValue));
+MOCK_METHOD4_WITH_CALLTYPE(__stdcall, execCommand, HRESULT(
+ BSTR cmdID, VARIANT_BOOL showUI, VARIANT value, VARIANT_BOOL *pfRet));
+MOCK_METHOD2_WITH_CALLTYPE(__stdcall, execCommandShowHelp, HRESULT(
+ BSTR cmdID, VARIANT_BOOL *pfRet));
+MOCK_METHOD2_WITH_CALLTYPE(__stdcall, createElement, HRESULT(
+ BSTR eTag, IHTMLElement **newElem));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, put_onhelp, HRESULT(VARIANT v));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_onhelp, HRESULT(VARIANT *p));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, put_onclick, HRESULT(VARIANT v));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_onclick, HRESULT(VARIANT *p));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, put_ondblclick, HRESULT(VARIANT v));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_ondblclick, HRESULT(VARIANT *p));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, put_onkeyup, HRESULT(VARIANT v));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_onkeyup, HRESULT(VARIANT *p));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, put_onkeydown, HRESULT(VARIANT v));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_onkeydown, HRESULT(VARIANT *p));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, put_onkeypress, HRESULT(VARIANT v));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_onkeypress, HRESULT(VARIANT *p));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, put_onmouseup, HRESULT(VARIANT v));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_onmouseup, HRESULT(VARIANT *p));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, put_onmousedown, HRESULT(VARIANT v));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_onmousedown, HRESULT(VARIANT *p));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, put_onmousemove, HRESULT(VARIANT v));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_onmousemove, HRESULT(VARIANT *p));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, put_onmouseout, HRESULT(VARIANT v));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_onmouseout, HRESULT(VARIANT *p));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, put_onmouseover, HRESULT(VARIANT v));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_onmouseover, HRESULT(VARIANT *p));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, put_onreadystatechange, HRESULT(
+ VARIANT v));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_onreadystatechange, HRESULT(
+ VARIANT *p));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, put_onafterupdate, HRESULT(VARIANT v));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_onafterupdate, HRESULT(VARIANT *p));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, put_onrowexit, HRESULT(VARIANT v));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_onrowexit, HRESULT(VARIANT *p));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, put_onrowenter, HRESULT(VARIANT v));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_onrowenter, HRESULT(VARIANT *p));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, put_ondragstart, HRESULT(VARIANT v));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_ondragstart, HRESULT(VARIANT *p));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, put_onselectstart, HRESULT(VARIANT v));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_onselectstart, HRESULT(VARIANT *p));
+MOCK_METHOD3_WITH_CALLTYPE(__stdcall, elementFromPoint, HRESULT(
+ long x, long y, IHTMLElement **elementHit));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_parentWindow, HRESULT(
+ IHTMLWindow2 **p));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_styleSheets, HRESULT(
+ IHTMLStyleSheetsCollection **p));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, put_onbeforeupdate, HRESULT(VARIANT v));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_onbeforeupdate, HRESULT(
+ VARIANT *p));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, put_onerrorupdate, HRESULT(VARIANT v));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_onerrorupdate, HRESULT(VARIANT *p));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, toString, HRESULT(BSTR *String));
+MOCK_METHOD3_WITH_CALLTYPE(__stdcall, createStyleSheet, HRESULT(
+ BSTR bstrHref, long lIndex, IHTMLStyleSheet **ppnewStyleSheet));
diff --git a/ceee/testing/utils/mock_ihtmlwindow2.gen b/ceee/testing/utils/mock_ihtmlwindow2.gen
new file mode 100644
index 0000000..b9641cb
--- /dev/null
+++ b/ceee/testing/utils/mock_ihtmlwindow2.gen
@@ -0,0 +1,95 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Auto-generated by com_mock.py
+
+MOCK_METHOD2_WITH_CALLTYPE(__stdcall, item, HRESULT(
+ VARIANT *pvarIndex, VARIANT *pvarResult));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_length, HRESULT(long *p));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_frames, HRESULT(
+ IHTMLFramesCollection2 **p));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, put_defaultStatus, HRESULT(BSTR v));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_defaultStatus, HRESULT(BSTR *p));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, put_status, HRESULT(BSTR v));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_status, HRESULT(BSTR *p));
+MOCK_METHOD4_WITH_CALLTYPE(__stdcall, setTimeout, HRESULT(
+ BSTR expression, long msec, VARIANT *language, long *timerID));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, clearTimeout, HRESULT(long timerID));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, alert, HRESULT(BSTR message = L""));
+MOCK_METHOD2_WITH_CALLTYPE(__stdcall, confirm, HRESULT(
+ BSTR message, VARIANT_BOOL *confirmed));
+MOCK_METHOD3_WITH_CALLTYPE(__stdcall, prompt, HRESULT(
+ BSTR message, BSTR defstr, VARIANT *textdata));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_Image, HRESULT(
+ IHTMLImageElementFactory **p));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_location, HRESULT(
+ IHTMLLocation **p));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_history, HRESULT(IOmHistory **p));
+MOCK_METHOD0_WITH_CALLTYPE(__stdcall, close, HRESULT());
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, put_opener, HRESULT(VARIANT v));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_opener, HRESULT(VARIANT *p));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_navigator, HRESULT(
+ IOmNavigator **p));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, put_name, HRESULT(BSTR v));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_name, HRESULT(BSTR *p));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_parent, HRESULT(IHTMLWindow2 **p));
+MOCK_METHOD5_WITH_CALLTYPE(__stdcall, open, HRESULT(
+ BSTR url, BSTR name, BSTR features, VARIANT_BOOL replace, IHTMLWindow2 **pomWindowResult));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_self, HRESULT(IHTMLWindow2 **p));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_top, HRESULT(IHTMLWindow2 **p));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_window, HRESULT(IHTMLWindow2 **p));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, navigate, HRESULT(BSTR url));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, put_onfocus, HRESULT(VARIANT v));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_onfocus, HRESULT(VARIANT *p));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, put_onblur, HRESULT(VARIANT v));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_onblur, HRESULT(VARIANT *p));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, put_onload, HRESULT(VARIANT v));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_onload, HRESULT(VARIANT *p));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, put_onbeforeunload, HRESULT(VARIANT v));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_onbeforeunload, HRESULT(
+ VARIANT *p));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, put_onunload, HRESULT(VARIANT v));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_onunload, HRESULT(VARIANT *p));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, put_onhelp, HRESULT(VARIANT v));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_onhelp, HRESULT(VARIANT *p));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, put_onerror, HRESULT(VARIANT v));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_onerror, HRESULT(VARIANT *p));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, put_onresize, HRESULT(VARIANT v));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_onresize, HRESULT(VARIANT *p));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, put_onscroll, HRESULT(VARIANT v));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_onscroll, HRESULT(VARIANT *p));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_document, HRESULT(
+ IHTMLDocument2 **p));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_event, HRESULT(IHTMLEventObj **p));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get__newEnum, HRESULT(IUnknown **p));
+MOCK_METHOD4_WITH_CALLTYPE(__stdcall, showModalDialog, HRESULT(
+ BSTR dialog, VARIANT *varArgIn, VARIANT *varOptions, VARIANT *varArgOut));
+MOCK_METHOD3_WITH_CALLTYPE(__stdcall, showHelp, HRESULT(
+ BSTR helpURL, VARIANT helpArg, BSTR features));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_screen, HRESULT(IHTMLScreen **p));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_Option, HRESULT(
+ IHTMLOptionElementFactory **p));
+MOCK_METHOD0_WITH_CALLTYPE(__stdcall, focus, HRESULT());
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_closed, HRESULT(VARIANT_BOOL *p));
+MOCK_METHOD0_WITH_CALLTYPE(__stdcall, blur, HRESULT());
+MOCK_METHOD2_WITH_CALLTYPE(__stdcall, scroll, HRESULT(long x, long y));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_clientInformation, HRESULT(
+ IOmNavigator **p));
+MOCK_METHOD4_WITH_CALLTYPE(__stdcall, setInterval, HRESULT(
+ BSTR expression, long msec, VARIANT *language, long *timerID));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, clearInterval, HRESULT(long timerID));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, put_offscreenBuffering, HRESULT(
+ VARIANT v));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_offscreenBuffering, HRESULT(
+ VARIANT *p));
+MOCK_METHOD3_WITH_CALLTYPE(__stdcall, execScript, HRESULT(
+ BSTR code, BSTR language, VARIANT *pvarRet));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, toString, HRESULT(BSTR *String));
+MOCK_METHOD2_WITH_CALLTYPE(__stdcall, scrollBy, HRESULT(long x, long y));
+MOCK_METHOD2_WITH_CALLTYPE(__stdcall, scrollTo, HRESULT(long x, long y));
+MOCK_METHOD2_WITH_CALLTYPE(__stdcall, moveTo, HRESULT(long x, long y));
+MOCK_METHOD2_WITH_CALLTYPE(__stdcall, moveBy, HRESULT(long x, long y));
+MOCK_METHOD2_WITH_CALLTYPE(__stdcall, resizeTo, HRESULT(long x, long y));
+MOCK_METHOD2_WITH_CALLTYPE(__stdcall, resizeBy, HRESULT(long x, long y));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_external, HRESULT(IDispatch **p));
diff --git a/ceee/testing/utils/mock_iobjectsafety.gen b/ceee/testing/utils/mock_iobjectsafety.gen
new file mode 100644
index 0000000..044ef39
--- /dev/null
+++ b/ceee/testing/utils/mock_iobjectsafety.gen
@@ -0,0 +1,10 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Auto-generated by com_mock.py
+
+MOCK_METHOD3_WITH_CALLTYPE(__stdcall, GetInterfaceSafetyOptions, HRESULT(
+ REFIID riid, DWORD *pdwSupportedOptions, DWORD *pdwEnabledOptions));
+MOCK_METHOD3_WITH_CALLTYPE(__stdcall, SetInterfaceSafetyOptions, HRESULT(
+ REFIID riid, DWORD dwOptionSetMask, DWORD dwEnabledOptions));
diff --git a/ceee/testing/utils/mock_ioleobject.gen b/ceee/testing/utils/mock_ioleobject.gen
new file mode 100644
index 0000000..97df4e6
--- /dev/null
+++ b/ceee/testing/utils/mock_ioleobject.gen
@@ -0,0 +1,43 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Auto-generated by com_mock.py
+
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, SetClientSite, HRESULT(
+ IOleClientSite *pClientSite));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, GetClientSite, HRESULT(
+ IOleClientSite **ppClientSite));
+MOCK_METHOD2_WITH_CALLTYPE(__stdcall, SetHostNames, HRESULT(
+ LPCOLESTR szContainerApp, LPCOLESTR szContainerObj));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, Close, HRESULT(DWORD dwSaveOption));
+MOCK_METHOD2_WITH_CALLTYPE(__stdcall, SetMoniker, HRESULT(
+ DWORD dwWhichMoniker, IMoniker *pmk));
+MOCK_METHOD3_WITH_CALLTYPE(__stdcall, GetMoniker, HRESULT(
+ DWORD dwAssign, DWORD dwWhichMoniker, IMoniker **ppmk));
+MOCK_METHOD3_WITH_CALLTYPE(__stdcall, InitFromData, HRESULT(
+ IDataObject *pDataObject, BOOL fCreation, DWORD dwReserved));
+MOCK_METHOD2_WITH_CALLTYPE(__stdcall, GetClipboardData, HRESULT(
+ DWORD dwReserved, IDataObject **ppDataObject));
+MOCK_METHOD6_WITH_CALLTYPE(__stdcall, DoVerb, HRESULT(
+ LONG iVerb, LPMSG lpmsg, IOleClientSite *pActiveSite, LONG lindex, HWND hwndParent, LPCRECT lprcPosRect));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, EnumVerbs, HRESULT(
+ IEnumOLEVERB **ppEnumOleVerb));
+MOCK_METHOD0_WITH_CALLTYPE(__stdcall, Update, HRESULT());
+MOCK_METHOD0_WITH_CALLTYPE(__stdcall, IsUpToDate, HRESULT());
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, GetUserClassID, HRESULT(CLSID *pClsid));
+MOCK_METHOD2_WITH_CALLTYPE(__stdcall, GetUserType, HRESULT(
+ DWORD dwFormOfType, LPOLESTR *pszUserType));
+MOCK_METHOD2_WITH_CALLTYPE(__stdcall, SetExtent, HRESULT(
+ DWORD dwDrawAspect, SIZEL *psizel));
+MOCK_METHOD2_WITH_CALLTYPE(__stdcall, GetExtent, HRESULT(
+ DWORD dwDrawAspect, SIZEL *psizel));
+MOCK_METHOD2_WITH_CALLTYPE(__stdcall, Advise, HRESULT(
+ IAdviseSink *pAdvSink, DWORD *pdwConnection));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, Unadvise, HRESULT(DWORD dwConnection));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, EnumAdvise, HRESULT(
+ IEnumSTATDATA **ppenumAdvise));
+MOCK_METHOD2_WITH_CALLTYPE(__stdcall, GetMiscStatus, HRESULT(
+ DWORD dwAspect, DWORD *pdwStatus));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, SetColorScheme, HRESULT(
+ LOGPALETTE *pLogpal));
diff --git a/ceee/testing/utils/mock_iprocessdebugmanager.gen b/ceee/testing/utils/mock_iprocessdebugmanager.gen
new file mode 100644
index 0000000..1835269
--- /dev/null
+++ b/ceee/testing/utils/mock_iprocessdebugmanager.gen
@@ -0,0 +1,16 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Auto-generated by com_mock.py
+
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, CreateApplication, HRESULT(
+ IDebugApplication *__RPC_FAR *ppda));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, GetDefaultApplication, HRESULT(
+ IDebugApplication *__RPC_FAR *ppda));
+MOCK_METHOD2_WITH_CALLTYPE(__stdcall, AddApplication, HRESULT(
+ IDebugApplication *pda, DWORD *pdwAppCookie));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, RemoveApplication, HRESULT(
+ DWORD dwAppCookie));
+MOCK_METHOD2_WITH_CALLTYPE(__stdcall, CreateDebugDocumentHelper, HRESULT(
+ IUnknown *punkOuter, IDebugDocumentHelper *__RPC_FAR *pddh));
diff --git a/ceee/testing/utils/mock_itravellogstg.gen b/ceee/testing/utils/mock_itravellogstg.gen
new file mode 100644
index 0000000..1c948ce
--- /dev/null
+++ b/ceee/testing/utils/mock_itravellogstg.gen
@@ -0,0 +1,20 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Auto-generated by com_mock.py
+
+MOCK_METHOD5_WITH_CALLTYPE(__stdcall, CreateEntry, HRESULT(
+ LPCWSTR pszUrl, LPCWSTR pszTitle, ITravelLogEntry *ptleRelativeTo, BOOL fPrepend, ITravelLogEntry **pptle));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, TravelTo, HRESULT(
+ ITravelLogEntry *ptle));
+MOCK_METHOD2_WITH_CALLTYPE(__stdcall, EnumEntries, HRESULT(
+ TLENUMF flags, IEnumTravelLogEntry **ppenum));
+MOCK_METHOD3_WITH_CALLTYPE(__stdcall, FindEntries, HRESULT(
+ TLENUMF flags, LPCWSTR pszUrl, IEnumTravelLogEntry **ppenum));
+MOCK_METHOD2_WITH_CALLTYPE(__stdcall, GetCount, HRESULT(
+ TLENUMF flags, DWORD *pcEntries));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, RemoveEntry, HRESULT(
+ ITravelLogEntry *ptle));
+MOCK_METHOD2_WITH_CALLTYPE(__stdcall, GetRelativeEntry, HRESULT(
+ int iOffset, ITravelLogEntry **ptle));
diff --git a/ceee/testing/utils/mock_iwebbrowser2.gen b/ceee/testing/utils/mock_iwebbrowser2.gen
new file mode 100644
index 0000000..5b4fa976
--- /dev/null
+++ b/ceee/testing/utils/mock_iwebbrowser2.gen
@@ -0,0 +1,110 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Auto-generated by com_mock.py
+
+MOCK_METHOD0_WITH_CALLTYPE(__stdcall, GoBack, HRESULT());
+MOCK_METHOD0_WITH_CALLTYPE(__stdcall, GoForward, HRESULT());
+MOCK_METHOD0_WITH_CALLTYPE(__stdcall, GoHome, HRESULT());
+MOCK_METHOD0_WITH_CALLTYPE(__stdcall, GoSearch, HRESULT());
+MOCK_METHOD5_WITH_CALLTYPE(__stdcall, Navigate, HRESULT(
+ BSTR URL, VARIANT *Flags, VARIANT *TargetFrameName, VARIANT *PostData, VARIANT *Headers));
+MOCK_METHOD0_WITH_CALLTYPE(__stdcall, Refresh, HRESULT());
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, Refresh2, HRESULT(VARIANT *Level));
+MOCK_METHOD0_WITH_CALLTYPE(__stdcall, Stop, HRESULT());
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_Application, HRESULT(
+ IDispatch **ppDisp));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_Parent, HRESULT(
+ IDispatch **ppDisp));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_Container, HRESULT(
+ IDispatch **ppDisp));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_Document, HRESULT(
+ IDispatch **ppDisp));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_TopLevelContainer, HRESULT(
+ VARIANT_BOOL *pBool));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_Type, HRESULT(BSTR *Type));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_Left, HRESULT(long *pl));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, put_Left, HRESULT(long Left));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_Top, HRESULT(long *pl));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, put_Top, HRESULT(long Top));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_Width, HRESULT(long *pl));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, put_Width, HRESULT(long Width));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_Height, HRESULT(long *pl));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, put_Height, HRESULT(long Height));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_LocationName, HRESULT(
+ BSTR *LocationName));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_LocationURL, HRESULT(
+ BSTR *LocationURL));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_Busy, HRESULT(VARIANT_BOOL *pBool));
+MOCK_METHOD0_WITH_CALLTYPE(__stdcall, Quit, HRESULT());
+MOCK_METHOD2_WITH_CALLTYPE(__stdcall, ClientToWindow, HRESULT(
+ int *pcx, int *pcy));
+MOCK_METHOD2_WITH_CALLTYPE(__stdcall, PutProperty, HRESULT(
+ BSTR Property, VARIANT vtValue));
+MOCK_METHOD2_WITH_CALLTYPE(__stdcall, GetProperty, HRESULT(
+ BSTR Property, VARIANT *pvtValue));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_Name, HRESULT(BSTR *Name));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_HWND, HRESULT(SHANDLE_PTR *pHWND));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_FullName, HRESULT(BSTR *FullName));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_Path, HRESULT(BSTR *Path));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_Visible, HRESULT(
+ VARIANT_BOOL *pBool));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, put_Visible, HRESULT(
+ VARIANT_BOOL Value));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_StatusBar, HRESULT(
+ VARIANT_BOOL *pBool));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, put_StatusBar, HRESULT(
+ VARIANT_BOOL Value));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_StatusText, HRESULT(
+ BSTR *StatusText));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, put_StatusText, HRESULT(
+ BSTR StatusText));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_ToolBar, HRESULT(int *Value));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, put_ToolBar, HRESULT(int Value));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_MenuBar, HRESULT(
+ VARIANT_BOOL *Value));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, put_MenuBar, HRESULT(
+ VARIANT_BOOL Value));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_FullScreen, HRESULT(
+ VARIANT_BOOL *pbFullScreen));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, put_FullScreen, HRESULT(
+ VARIANT_BOOL bFullScreen));
+MOCK_METHOD5_WITH_CALLTYPE(__stdcall, Navigate2, HRESULT(
+ VARIANT *URL, VARIANT *Flags, VARIANT *TargetFrameName, VARIANT *PostData, VARIANT *Headers));
+MOCK_METHOD2_WITH_CALLTYPE(__stdcall, QueryStatusWB, HRESULT(
+ OLECMDID cmdID, OLECMDF *pcmdf));
+MOCK_METHOD4_WITH_CALLTYPE(__stdcall, ExecWB, HRESULT(
+ OLECMDID cmdID, OLECMDEXECOPT cmdexecopt, VARIANT *pvaIn, VARIANT *pvaOut));
+MOCK_METHOD3_WITH_CALLTYPE(__stdcall, ShowBrowserBar, HRESULT(
+ VARIANT *pvaClsid, VARIANT *pvarShow, VARIANT *pvarSize));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_ReadyState, HRESULT(
+ READYSTATE *plReadyState));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_Offline, HRESULT(
+ VARIANT_BOOL *pbOffline));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, put_Offline, HRESULT(
+ VARIANT_BOOL bOffline));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_Silent, HRESULT(
+ VARIANT_BOOL *pbSilent));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, put_Silent, HRESULT(
+ VARIANT_BOOL bSilent));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_RegisterAsBrowser, HRESULT(
+ VARIANT_BOOL *pbRegister));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, put_RegisterAsBrowser, HRESULT(
+ VARIANT_BOOL bRegister));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_RegisterAsDropTarget, HRESULT(
+ VARIANT_BOOL *pbRegister));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, put_RegisterAsDropTarget, HRESULT(
+ VARIANT_BOOL bRegister));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_TheaterMode, HRESULT(
+ VARIANT_BOOL *pbRegister));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, put_TheaterMode, HRESULT(
+ VARIANT_BOOL bRegister));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_AddressBar, HRESULT(
+ VARIANT_BOOL *Value));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, put_AddressBar, HRESULT(
+ VARIANT_BOOL Value));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, get_Resizable, HRESULT(
+ VARIANT_BOOL *Value));
+MOCK_METHOD1_WITH_CALLTYPE(__stdcall, put_Resizable, HRESULT(
+ VARIANT_BOOL Value));
diff --git a/ceee/testing/utils/mock_static.h b/ceee/testing/utils/mock_static.h
new file mode 100644
index 0000000..07b4cda
--- /dev/null
+++ b/ceee/testing/utils/mock_static.h
@@ -0,0 +1,161 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Framework for mocking sets of static functions using SideStep, so that
+// no code change is needed in the static functions themselves.
+//
+// Note that tiny functions may get inlined by the compiler in debug builds,
+// so this approach is not suitable for tiny functions you need to unit test in
+// release mode. Mock classes based on this framework are further limited to
+// use from a single thread at a time, they are non-nestable, and only intended
+// for testing code.
+//
+// To define a new static mock class, the structure is as follows:
+//
+// === cut here ===
+// MOCK_STATIC_CLASS_BEGIN(MockClassName)
+// MOCK_STATIC_INIT_BEGIN(MockClassName)
+// MOCK_STATIC_INIT(IsWindow);
+// MOCK_STATIC_INIT2(SomeClass::SomeStatic, SomeStatic);
+// ... more MOCK_STATIC_INIT(2) macros ...
+// MOCK_STATIC_INIT_END()
+//
+// MOCK_STATIC1(BOOL, CALLBACK, IsWindow, HWND);
+// MOCK_STATIC3(BOOL,, SomeStatic, SomeClass*, int, int);
+// ... more MOCK_STATICX macros ...
+// MOCK_STATIC_CLASS_END(MockClassName)
+// === cut here ===
+//
+// Note that each function being mocked appears twice, once in the
+// initialization map (between MOCK_STATIC_INIT_BEGIN and _END) and again
+// in the method map (the MOCK_STATICX macros). For further details see
+// documentation of the macros.
+
+#ifndef CEEE_TESTING_UTILS_MOCK_STATIC_H_
+#define CEEE_TESTING_UTILS_MOCK_STATIC_H_
+
+#include "base/scoped_vector.h"
+#include "ceee/testing/sidestep/auto_testing_hook.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace testing {
+
+// A base class for mock objects that mock sets of static functions. Used via
+// MOCK_STATIC_XYZ macros below.
+class MockStatic {
+ public:
+ virtual ~MockStatic() {}
+
+ protected:
+ ScopedVector<sidestep::AutoTestingHookBase> hooks_;
+};
+
+} // namespace testing
+
+// Begins definition of a static mock class named ClassName.
+#define MOCK_STATIC_CLASS_BEGIN(ClassName) \
+ class ClassName : public testing::MockStatic { \
+ public: \
+ virtual ~ClassName() { \
+ current_ = NULL; \
+ } \
+ static ClassName* GetCurrent() { return current_; } \
+ private: \
+ static ClassName* current_; // NOLINT
+
+// Begins the initialization map of a static mock class named ClassName.
+#define MOCK_STATIC_INIT_BEGIN(ClassName) \
+ public: \
+ ClassName() { \
+ current_ = this;
+
+// Add this to the initialization map of a static mock class to mock a
+// global function named function_name.
+#define MOCK_STATIC_INIT(function_name) \
+ hooks_.push_back(sidestep::MakeTestingHookHolder(::##function_name, \
+ &function_name##Hook));
+
+// Add this to the initialization map of a static mock class to mock a
+// static function that is not global (e.g. in a namespace or a class function)
+// @param function The function to mock
+// @param method_name The name of the mock method you are defining for this
+// function using one of the MOCK_STATICX macros below.
+#define MOCK_STATIC_INIT2(function, method_name) \
+ hooks_.push_back(sidestep::MakeTestingHookHolder(function, \
+ &method_name##Hook));
+
+// Ends the initialization map of a static mock class.
+#define MOCK_STATIC_INIT_END() \
+ }
+
+// Each of the following MOCK_STATICX macros defines a mock method taking X
+// arguments and a corresponding static function, used as a hook on the
+// production function, that redirects calls to your mock method for the
+// lifetime of the static mock object.
+//
+// @param return_type Return type of the function you are mocking.
+// @param cconv The calling convention of the function you are mocking.
+// @param name The name of the mock method. For global functions, this must
+// match the name of the global function. For non-global static functions,
+// it must match the method_name you provided in the MOCK_STATIC_INIT2
+// macro.
+// @param t1 The type of the 1st parameter of the function.
+// @param t2 The type of the 2nd parameter of the function.
+// @param t3 The type of the 3rd parameter of the function.
+// @param t4 The type of the 4th parameter of the function.
+// @param t5 The type of the 5th parameter of the function.
+// @param t6 The type of the 6th parameter of the function.
+// @param t7 The type of the 7th parameter of the function.
+#define MOCK_STATIC0(return_type, cconv, name) \
+ MOCK_METHOD0(name, return_type()); \
+ static return_type cconv name##Hook () { \
+ return GetCurrent()->name(); \
+ } // NOLINT
+#define MOCK_STATIC1(return_type, cconv, name, t1) \
+ MOCK_METHOD1(name, return_type(t1)); \
+ static return_type cconv name##Hook (t1 p1) { \
+ return GetCurrent()->name(p1); \
+ } // NOLINT
+#define MOCK_STATIC2(return_type, cconv, name, t1, t2) \
+ MOCK_METHOD2(name, return_type(t1, t2)); \
+ static return_type cconv name##Hook (t1 p1, t2 p2) { \
+ return GetCurrent()->name(p1, p2); \
+ } // NOLINT
+#define MOCK_STATIC3(return_type, cconv, name, t1, t2, t3) \
+ MOCK_METHOD3(name, return_type(t1, t2, t3)); \
+ static return_type cconv name##Hook (t1 p1, t2 p2, t3 p3) { \
+ return GetCurrent()->name(p1, p2, p3); \
+ } // NOLINT
+#define MOCK_STATIC4(return_type, cconv, name, t1, t2, t3, t4) \
+ MOCK_METHOD4(name, return_type(t1, t2, t3, t4)); \
+ static return_type cconv name##Hook (t1 p1, t2 p2, t3 p3, t4 p4) { \
+ return GetCurrent()->name(p1, p2, p3, p4); \
+ } // NOLINT
+#define MOCK_STATIC5(return_type, cconv, name, \
+ t1, t2, t3, t4, t5) \
+ MOCK_METHOD5(name, return_type(t1, t2, t3, t4, t5)); \
+ static return_type cconv name##Hook (t1 p1, t2 p2, t3 p3, t4 p4, t5 p5) { \
+ return GetCurrent()->name(p1, p2, p3, p4, p5); \
+ } // NOLINT
+#define MOCK_STATIC6(return_type, cconv, name, \
+ t1, t2, t3, t4, t5, t6) \
+ MOCK_METHOD6(name, return_type(t1, t2, t3, t4, t5, t6)); \
+ static return_type cconv name##Hook ( \
+ t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6) { \
+ return GetCurrent()->name(p1, p2, p3, p4, p5, p6); \
+ } // NOLINT
+#define MOCK_STATIC7(return_type, cconv, name, \
+ t1, t2, t3, t4, t5, t6, t7) \
+ MOCK_METHOD7(name, return_type(t1, t2, t3, t4, t5, t6, t7)); \
+ static return_type cconv name##Hook ( \
+ t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7) { \
+ return GetCurrent()->name(p1, p2, p3, p4, p5, p6, p7); \
+ } // NOLINT
+
+// Ends definition of a static mock class named ClassName.
+#define MOCK_STATIC_CLASS_END(ClassName) \
+ }; \
+ __declspec(selectany) ClassName* ClassName::current_ = NULL;
+
+#endif // CEEE_TESTING_UTILS_MOCK_STATIC_H_
diff --git a/ceee/testing/utils/mock_win32.h b/ceee/testing/utils/mock_win32.h
new file mode 100644
index 0000000..e022964
--- /dev/null
+++ b/ceee/testing/utils/mock_win32.h
@@ -0,0 +1,119 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Win32 mocks.
+
+#ifndef CEEE_TESTING_UTILS_MOCK_WIN32_H_
+#define CEEE_TESTING_UTILS_MOCK_WIN32_H_
+
+// atlwin.h re#defines SetWindowLongPtr and it caused a build error here.
+#ifdef __ATLWIN_H__
+#error "Do not include <atlwin.h> ahead of this."
+#endif
+
+#include <windows.h>
+
+#include "ceee/testing/sidestep/auto_testing_hook.h"
+#include "ceee/testing/utils/mock_static.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace testing {
+
+// Mock object for some Kernel32 functions.
+MOCK_STATIC_CLASS_BEGIN(MockKernel32)
+ MOCK_STATIC_INIT_BEGIN(MockKernel32)
+ MOCK_STATIC_INIT(GetModuleFileName);
+ MOCK_STATIC_INIT(GetNativeSystemInfo);
+ MOCK_STATIC_INIT(OpenThread);
+ MOCK_STATIC_INIT(GetCommandLine);
+ MOCK_STATIC_INIT_END()
+
+ MOCK_STATIC3(DWORD, WINAPI, GetModuleFileName, HMODULE, LPTSTR, DWORD);
+ MOCK_STATIC1(void, WINAPI, GetNativeSystemInfo, LPSYSTEM_INFO);
+ MOCK_STATIC3(HANDLE, CALLBACK, OpenThread, DWORD, BOOL, DWORD);
+ MOCK_STATIC0(LPTSTR, WINAPI, GetCommandLine);
+MOCK_STATIC_CLASS_END(MockKernel32)
+
+// Separate from MockKernel32 since here be dragons.
+// First off, putting the LoadLibrary functions with the rest of MockUser32
+// is not a good idea since we want to avoid hooking these functions whenever
+// the others are used. Also, for some undetermined reason, they just don't
+// work when coupled in the MockUser32 class. So chances are you cannot use both
+// MockLoadLibrary and MockUser32 in the same test...
+MOCK_STATIC_CLASS_BEGIN(MockLoadLibrary)
+ MOCK_STATIC_INIT_BEGIN(MockLoadLibrary)
+ MOCK_STATIC_INIT(LoadLibrary);
+ MOCK_STATIC_INIT(GetProcAddress);
+ MOCK_STATIC_INIT(FreeLibrary);
+ MOCK_STATIC_INIT_END()
+
+ MOCK_STATIC1(HINSTANCE, WINAPI, LoadLibrary, LPCTSTR);
+ MOCK_STATIC2(FARPROC, WINAPI, GetProcAddress, HMODULE, LPCSTR);
+ MOCK_STATIC1(BOOL, WINAPI, FreeLibrary, HMODULE);
+MOCK_STATIC_CLASS_END(MockLoadLibrary)
+
+// Mock object for some User32 functions.
+MOCK_STATIC_CLASS_BEGIN(MockUser32)
+ MOCK_STATIC_INIT_BEGIN(MockUser32)
+ MOCK_STATIC_INIT(DefWindowProc);
+ MOCK_STATIC_INIT(EnumChildWindows);
+ MOCK_STATIC_INIT(EnumWindows);
+ MOCK_STATIC_INIT(IsWindow);
+ MOCK_STATIC_INIT(IsWindowVisible);
+ MOCK_STATIC_INIT(GetClassName);
+ MOCK_STATIC_INIT(GetForegroundWindow);
+ MOCK_STATIC_INIT(GetParent);
+ MOCK_STATIC_INIT(GetTopWindow);
+ MOCK_STATIC_INIT(GetWindow);
+ MOCK_STATIC_INIT(GetWindowRect);
+ MOCK_STATIC_INIT(GetWindowThreadProcessId);
+ MOCK_STATIC_INIT(MoveWindow);
+ MOCK_STATIC_INIT(PostMessage);
+ MOCK_STATIC_INIT(SendMessage);
+ MOCK_STATIC_INIT(SetProp);
+ MOCK_STATIC_INIT(SetWindowLongPtr);
+ MOCK_STATIC_INIT(SetWindowPos);
+ MOCK_STATIC_INIT_END()
+
+ MOCK_STATIC4(LRESULT, CALLBACK, DefWindowProc, HWND, UINT, WPARAM, LPARAM);
+ MOCK_STATIC3(BOOL, CALLBACK, EnumChildWindows, HWND, WNDENUMPROC, LPARAM);
+ MOCK_STATIC2(BOOL, CALLBACK, EnumWindows, WNDENUMPROC, LPARAM);
+ MOCK_STATIC1(BOOL, CALLBACK, IsWindow, HWND);
+ MOCK_STATIC1(BOOL, CALLBACK, IsWindowVisible, HWND);
+ MOCK_STATIC3(int, CALLBACK, GetClassName, HWND, LPTSTR, int);
+ MOCK_STATIC0(HWND, CALLBACK, GetForegroundWindow);
+ MOCK_STATIC1(HWND, CALLBACK, GetParent, HWND);
+ MOCK_STATIC1(HWND, CALLBACK, GetTopWindow, HWND);
+ MOCK_STATIC2(HWND, CALLBACK, GetWindow, HWND, UINT);
+ MOCK_STATIC2(BOOL, CALLBACK, GetWindowRect, HWND, LPRECT);
+ MOCK_STATIC2(DWORD, CALLBACK, GetWindowThreadProcessId, HWND, LPDWORD);
+ MOCK_STATIC6(BOOL, CALLBACK, MoveWindow,
+ HWND, int, int, int, int, BOOL);
+ MOCK_STATIC4(BOOL, CALLBACK, PostMessage, HWND, UINT, WPARAM, LPARAM);
+ MOCK_STATIC4(LRESULT, CALLBACK, SendMessage, HWND, UINT, WPARAM, LPARAM);
+ MOCK_STATIC3(BOOL, CALLBACK, SetProp, HWND, LPCWSTR, HANDLE);
+ MOCK_STATIC3(LONG_PTR, CALLBACK, SetWindowLongPtr, HWND, int, LONG_PTR);
+ MOCK_STATIC7(BOOL, CALLBACK, SetWindowPos,
+ HWND, HWND, int, int, int, int, UINT);
+MOCK_STATIC_CLASS_END(MockUser32)
+
+// Static functions for (effectively) mocking GetNativeSystemInfo
+class NativeSystemInfoMockTool {
+ public:
+ static void SetEnvironment_x86(LPSYSTEM_INFO psys_info) {
+ memset(psys_info, 0, sizeof(*psys_info));
+ psys_info->wProcessorArchitecture = PROCESSOR_ARCHITECTURE_INTEL;
+ psys_info->dwNumberOfProcessors = 1;
+ }
+
+ static void SetEnvironment_x64(LPSYSTEM_INFO psys_info) {
+ memset(psys_info, 0, sizeof(*psys_info));
+ psys_info->wProcessorArchitecture = PROCESSOR_ARCHITECTURE_AMD64;
+ psys_info->dwNumberOfProcessors = 4;
+ }
+};
+
+} // namespace testing
+
+#endif // CEEE_TESTING_UTILS_MOCK_WIN32_H_
diff --git a/ceee/testing/utils/mock_window_utils.h b/ceee/testing/utils/mock_window_utils.h
new file mode 100644
index 0000000..7150111
--- /dev/null
+++ b/ceee/testing/utils/mock_window_utils.h
@@ -0,0 +1,40 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// window_utils mocks.
+
+#ifndef CEEE_TESTING_UTILS_MOCK_WINDOW_UTILS_H_
+#define CEEE_TESTING_UTILS_MOCK_WINDOW_UTILS_H_
+
+#include <set>
+
+#include "ceee/testing/utils/mock_static.h"
+#include "ceee/common/window_utils.h"
+
+namespace testing {
+
+// Mock object for some User32 functions.
+MOCK_STATIC_CLASS_BEGIN(MockWindowUtils)
+ MOCK_STATIC_INIT_BEGIN(MockWindowUtils)
+ MOCK_STATIC_INIT2(window_utils::IsWindowClass, IsWindowClass);
+ MOCK_STATIC_INIT2(window_utils::IsWindowThread, IsWindowThread);
+ MOCK_STATIC_INIT2(window_utils::GetTopLevelParent, GetTopLevelParent);
+ MOCK_STATIC_INIT2(window_utils::WindowHasNoThread, WindowHasNoThread);
+ MOCK_STATIC_INIT2(window_utils::FindDescendentWindow, FindDescendentWindow);
+ MOCK_STATIC_INIT2(window_utils::FindTopLevelWindows, FindTopLevelWindows);
+ MOCK_STATIC_INIT_END()
+
+ MOCK_STATIC2(bool, , IsWindowClass, HWND, const std::wstring&);
+ MOCK_STATIC1(bool, , IsWindowThread, HWND);
+ MOCK_STATIC1(HWND, , GetTopLevelParent, HWND);
+ MOCK_STATIC1(bool, , WindowHasNoThread, HWND);
+ MOCK_STATIC4(bool, , FindDescendentWindow, HWND, const std::wstring&,
+ bool, HWND*);
+ MOCK_STATIC2(void, , FindTopLevelWindows, const std::wstring&,
+ std::set<HWND>*);
+MOCK_STATIC_CLASS_END(MockWindowUtils)
+
+} // namespace testing
+
+#endif // CEEE_TESTING_UTILS_MOCK_WINDOW_UTILS_H_
diff --git a/ceee/testing/utils/mshtml_mocks.h b/ceee/testing/utils/mshtml_mocks.h
new file mode 100644
index 0000000..83b8d00
--- /dev/null
+++ b/ceee/testing/utils/mshtml_mocks.h
@@ -0,0 +1,16 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Autogenerated mock interface definitions for MSHTML.
+// The mocked interfaces are declared in mshtml_mocks.py. To add a new
+// interface, edit that file.
+#ifndef CEEE_TESTING_UTILS_MSHTML_MOCKS_H_
+#define CEEE_TESTING_UTILS_MSHTML_MOCKS_H_
+
+#include <mshtml.h>
+#include "gmock/gmock.h"
+
+#include "mshtml_mocks.gen" // NOLINT
+
+#endif // CEEE_TESTING_UTILS_MSHTML_MOCKS_H_
diff --git a/ceee/testing/utils/mshtml_mocks.py b/ceee/testing/utils/mshtml_mocks.py
new file mode 100644
index 0000000..8691b15
--- /dev/null
+++ b/ceee/testing/utils/mshtml_mocks.py
@@ -0,0 +1,85 @@
+# Copyright (c) 2010 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+#!python
+'''Autogenerates mock interface implementations for MSHTML interfaces.'''
+import os
+import string
+import sys
+
+import com_mock
+
+# Adjust our module path so we can import com_mock.
+script_dir = os.path.abspath(os.path.dirname(__file__))
+client_root = os.path.normpath(os.path.join(script_dir, '../../..'))
+
+
+# The interfaces we want mocked. These have to be declared in MsHTML.h,
+# and this will only work for IDispatch-derived interfaces.
+# Any interface "IFoo" named here will have a corresponding IFooMockImpl
+# mock implementation class in the generated output file.
+_INTERFACES = [
+ 'IHTMLDocument2',
+ 'IHTMLDocument3',
+ 'IHTMLDOMNode',
+ 'IHTMLElement',
+ 'IHTMLElementCollection',
+ 'IHTMLStyleElement',
+ 'IHTMLStyleSheet',
+ 'IHTMLWindow2',
+]
+
+
+# Find the path to the MSHTML.h include file.
+_MSHTML_PATH = None
+include_dirs = os.environ['INCLUDE'].split(';')
+for include_dir in include_dirs:
+ candidate_path = os.path.join(include_dir, 'MsHTML.h')
+ if os.path.exists(candidate_path):
+ _MSHTML_PATH = candidate_path
+if not _MSHTML_PATH:
+ print >> sys.stderr, "Could not find MsHTML.h in any INCLUDE path."
+ sys.exit(2)
+
+
+# Template string for output file header.
+_HEADER_TEMPLATE = '''\
+// This file is autogenerated by ${file} ** DO NOT EDIT **
+
+'''
+
+# Template string for output file footer.
+_FOOTER_TEMPLATE = ''
+
+# Template string for mock interface definition.
+_INTERFACE_TEMPLATE = '''\
+class ${interface}MockImpl
+ : public IDispatchImpl<${interface},
+ &IID_${interface},
+ &LIBID_MSHTML,
+ 4, 0> { // Version 4.0 of the typelib.
+ public:
+${mocks}
+};
+
+'''
+
+
+def Main():
+ mocker = com_mock.Mocker()
+ mocker.AddHeaders([_MSHTML_PATH])
+
+ header_template = string.Template(_HEADER_TEMPLATE)
+ print header_template.substitute(file = __file__)
+
+ interface_template = string.Template(_INTERFACE_TEMPLATE)
+ for interface in _INTERFACES:
+ mocks = '\n'.join(mocker.MockInterface(interface))
+ print interface_template.substitute(interface = interface, mocks = mocks)
+
+ footer_template = string.Template(_FOOTER_TEMPLATE)
+ print footer_template.substitute(file = os.path.abspath(__file__))
+
+
+if __name__ == '__main__':
+ Main()
diff --git a/ceee/testing/utils/nt_internals.cc b/ceee/testing/utils/nt_internals.cc
new file mode 100644
index 0000000..7bfccd0
--- /dev/null
+++ b/ceee/testing/utils/nt_internals.cc
@@ -0,0 +1,63 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// NT internal data structures and functions that rely upon them.
+#include "ceee/testing/utils/nt_internals.h"
+
+namespace nt_internals {
+
+const HMODULE ntdll = ::GetModuleHandle(L"ntdll.dll");
+
+NtQueryInformationThreadFunc NtQueryInformationThread =
+ reinterpret_cast<NtQueryInformationThreadFunc>(
+ ::GetProcAddress(ntdll, "NtQueryInformationThread"));
+
+NtQueryInformationProcessFunc NtQueryInformationProcess =
+ reinterpret_cast<NtQueryInformationProcessFunc>(
+ ::GetProcAddress(ntdll, "NtQueryInformationProcess"));
+
+NtQueryObjectFunc NtQueryObject = reinterpret_cast<NtQueryObjectFunc>(
+ ::GetProcAddress(ntdll, "NtQueryObject"));
+
+RtlGetNtGlobalFlagsFunc RtlGetNtGlobalFlags =
+ reinterpret_cast<RtlGetNtGlobalFlagsFunc>(
+ ::GetProcAddress(ntdll, "RtlGetNtGlobalFlags"));
+
+RtlNtStatusToDosErrorFunc RtlNtStatusToDosError =
+ reinterpret_cast<RtlNtStatusToDosErrorFunc>(
+ ::GetProcAddress(ntdll, "RtlNtStatusToDosError"));
+
+RtlQueryProcessBackTraceInformationFunc RtlQueryProcessBackTraceInformation =
+ reinterpret_cast<RtlQueryProcessBackTraceInformationFunc>(
+ ::GetProcAddress(ntdll, "RtlQueryProcessBackTraceInformation"));
+
+RtlCreateQueryDebugBufferFunc RtlCreateQueryDebugBuffer =
+ reinterpret_cast<RtlCreateQueryDebugBufferFunc>(
+ ::GetProcAddress(ntdll, "RtlCreateQueryDebugBuffer"));
+RtlQueryProcessDebugInformationFunc RtlQueryProcessDebugInformation =
+ reinterpret_cast<RtlQueryProcessDebugInformationFunc>(
+ ::GetProcAddress(ntdll, "RtlQueryProcessDebugInformation"));
+RtlDestroyQueryDebugBufferFunc RtlDestroyQueryDebugBuffer =
+ reinterpret_cast<RtlDestroyQueryDebugBufferFunc>(
+ ::GetProcAddress(ntdll, "RtlDestroyQueryDebugBuffer"));
+
+
+PNT_TIB GetThreadTIB(HANDLE thread) {
+ if (!NtQueryInformationThread)
+ return NULL;
+
+ THREAD_BASIC_INFO info = {};
+ ULONG ret_len = 0;
+ NTSTATUS status = NtQueryInformationThread(thread,
+ ThreadBasicInformation,
+ &info,
+ sizeof(info),
+ &ret_len);
+ if (0 != status || ret_len != sizeof(info))
+ return NULL;
+
+ return reinterpret_cast<PNT_TIB>(info.TebBaseAddress);
+}
+
+} // namespace nt_internals
diff --git a/ceee/testing/utils/nt_internals.h b/ceee/testing/utils/nt_internals.h
new file mode 100644
index 0000000..55ec3d4
--- /dev/null
+++ b/ceee/testing/utils/nt_internals.h
@@ -0,0 +1,206 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// NT internal data structures and functions that rely upon them.
+#ifndef CEEE_TESTING_UTILS_NT_INTERNALS_H_
+#define CEEE_TESTING_UTILS_NT_INTERNALS_H_
+
+#include <windows.h>
+
+namespace nt_internals {
+
+// The structures, constants and function declarations in here are gleaned
+// from various sources, primarily from Microsoft symbol information for
+// system DLLs, kernel modules and executables, as well as from MSDN help.
+// For more information on the Windows NT native API, see e.g.
+// the "Windows NT/2000 Native API Reference" by Gary Nebbett,
+// ISBN 9781578701995.
+typedef LONG NTSTATUS;
+typedef DWORD KPRIORITY;
+typedef WORD UWORD;
+
+struct CLIENT_ID {
+ PVOID UniqueProcess;
+ PVOID UniqueThread;
+};
+
+struct THREAD_BASIC_INFO {
+ NTSTATUS ExitStatus;
+ PVOID TebBaseAddress;
+ CLIENT_ID ClientId;
+ KAFFINITY AffinityMask;
+ KPRIORITY Priority;
+ KPRIORITY BasePriority;
+};
+
+enum THREADINFOCLASS {
+ ThreadBasicInformation,
+};
+
+// NtQueryInformationProcess is documented in winternl.h, but we link
+// dynamically to it because we might as well.
+typedef NTSTATUS (WINAPI *NtQueryInformationThreadFunc)(
+ IN HANDLE ThreadHandle,
+ IN THREADINFOCLASS ThreadInformationClass,
+ OUT PVOID ThreadInformation,
+ IN ULONG ThreadInformationLength,
+ OUT PULONG ReturnLength OPTIONAL);
+extern NtQueryInformationThreadFunc NtQueryInformationThread;
+
+typedef struct _PROCESS_BASIC_INFORMATION {
+ NTSTATUS ExitStatus;
+ PVOID PebBaseAddress;
+ ULONG AffinityMask;
+ ULONG BasePriority;
+ ULONG_PTR UniqueProcessId;
+ ULONG_PTR InheritedFromUniqueProcessId;
+} PROCESS_BASIC_INFORMATION;
+
+enum PROCESSINFOCLASS {
+ ProcessBasicInformation
+};
+
+typedef NTSTATUS (WINAPI *NtQueryInformationProcessFunc)(
+ IN HANDLE ProcessHandle,
+ IN PROCESSINFOCLASS ProcessInformationClass,
+ OUT PVOID ProcessInformation,
+ IN ULONG ProcessInformationLength,
+ OUT PULONG ReturnLength OPTIONAL);
+extern NtQueryInformationProcessFunc NtQueryInformationProcess;
+
+// NtQueryObject is also documented in winternl.h, but we link
+// dynamically to it because we might as well.
+typedef struct _PUBLIC_OBJECT_BASIC_INFORMATION {
+ ULONG Attributes;
+ ACCESS_MASK GrantedAccess;
+ ULONG HandleCount;
+ ULONG PointerCount;
+ ULONG Reserved[10]; // reserved for internal use
+} PUBLIC_OBJECT_BASIC_INFORMATION;
+
+enum OBJECT_INFORMATION_CLASS {
+ ObjectBasicInformation = 0,
+ ObjectTypeInformation = 2,
+};
+
+typedef NTSTATUS (WINAPI *NtQueryObjectFunc)(
+ IN HANDLE Handle,
+ IN OBJECT_INFORMATION_CLASS ObjectInformationClass,
+ OUT PVOID ObjectInformation,
+ IN ULONG ObjectInformationLength,
+ OUT PULONG ReturnLength);
+extern NtQueryObjectFunc NtQueryObject;
+
+// @returns the TIB/TEB address for "thread".
+extern PNT_TIB GetThreadTIB(HANDLE thread);
+
+// Debug-related structure declarations.
+typedef struct _RTL_PROCESS_BACKTRACE_INFORMATION {
+ PVOID SymbolicBackTrace;
+ ULONG TraceCount;
+ USHORT Index;
+ USHORT Depth;
+ PVOID BackTrace[32];
+} RTL_PROCESS_BACKTRACE_INFORMATION, *PRTL_PROCESS_BACKTRACE_INFORMATION;
+
+typedef struct _RTL_PROCESS_BACKTRACES {
+ ULONG CommittedMemory;
+ ULONG ReservedMemory;
+ ULONG NumberOfBackTraceLookups;
+ ULONG NumberOfBackTraces;
+ RTL_PROCESS_BACKTRACE_INFORMATION BackTraces[1];
+} RTL_PROCESS_BACKTRACES, *PRTL_PROCESS_BACKTRACES;
+
+typedef struct _RTL_PROCESS_MODULE_INFORMATION {
+ ULONG Section;
+ PVOID MappedBase;
+ PVOID ImageBase;
+ ULONG ImageSize;
+ ULONG Flags;
+ USHORT LoadOrderIndex;
+ USHORT InitOrderIndex;
+ USHORT LoadCount;
+ USHORT OffsetToFileName;
+ CHAR FullPathName[256];
+} RTL_PROCESS_MODULE_INFORMATION, *PRTL_PROCESS_MODULE_INFORMATION;
+
+typedef struct _RTL_PROCESS_MODULES {
+ ULONG NumberOfModules;
+ RTL_PROCESS_MODULE_INFORMATION Modules[1];
+} RTL_PROCESS_MODULES, *PRTL_PROCESS_MODULES;
+
+typedef struct _RTL_PROCESS_MODULE_INFORMATION_EX {
+ ULONG NextOffset;
+ RTL_PROCESS_MODULE_INFORMATION BaseInfo;
+ ULONG ImageCheckSum;
+ ULONG TimeDateStamp;
+ PVOID DefaultBase;
+} RTL_PROCESS_MODULE_INFORMATION_EX, *PRTL_PROCESS_MODULE_INFORMATION_EX;
+
+typedef struct _RTL_DEBUG_INFORMATION {
+ HANDLE SectionHandleClient;
+ PVOID ViewBaseClient;
+ PVOID ViewBaseTarget;
+ ULONG ViewBaseDelta;
+ HANDLE EventPairClient;
+ PVOID EventPairTarget;
+ HANDLE TargetProcessId;
+ HANDLE TargetThreadHandle;
+ ULONG Flags;
+ ULONG OffsetFree;
+ ULONG CommitSize;
+ ULONG ViewSize;
+ union {
+ PRTL_PROCESS_MODULES Modules;
+ PRTL_PROCESS_MODULE_INFORMATION_EX ModulesEx;
+ };
+ PRTL_PROCESS_BACKTRACES BackTraces;
+ void * /*PRTL_PROCESS_HEAPS*/ Heaps;
+ void * /*PRTL_PROCESS_LOCKS*/ Locks;
+ HANDLE SpecificHeap;
+ HANDLE TargetProcessHandle;
+ void * /*RTL_PROCESS_VERIFIER_OPTIONS*/ VerifierOptions;
+ HANDLE ProcessHeap;
+ HANDLE CriticalSectionHandle;
+ HANDLE CriticalSectionOwnerThread;
+ PVOID Reserved[4];
+} RTL_DEBUG_INFORMATION, *PRTL_DEBUG_INFORMATION;
+
+// RtlQueryProcessDebugInformation.DebugInfoClassMask constants
+#define PDI_MODULES 0x01
+#define PDI_BACKTRACE 0x02
+#define PDI_HEAPS 0x04
+#define PDI_HEAP_TAGS 0x08
+#define PDI_HEAP_BLOCKS 0x10
+#define PDI_LOCKS 0x20
+
+typedef NTSTATUS (NTAPI *RtlQueryProcessBackTraceInformationFunc)(
+ PRTL_DEBUG_INFORMATION debug_info);
+typedef PRTL_DEBUG_INFORMATION (NTAPI *RtlCreateQueryDebugBufferFunc)(
+ IN ULONG size, IN BOOLEAN event_pair);
+typedef NTSTATUS (NTAPI *RtlQueryProcessDebugInformationFunc)(
+ IN ULONG ProcessId, IN ULONG DebugInfoClassMask,
+ IN OUT PRTL_DEBUG_INFORMATION DebugBuffer);
+typedef NTSTATUS (NTAPI *RtlDestroyQueryDebugBufferFunc)(
+ IN PRTL_DEBUG_INFORMATION DebugBuffer);
+
+typedef ULONG (NTAPI *RtlGetNtGlobalFlagsFunc)();
+typedef ULONG (NTAPI *RtlNtStatusToDosErrorFunc)(NTSTATUS nt_status);
+
+// Debug-related runtime functions.
+extern RtlQueryProcessBackTraceInformationFunc
+ RtlQueryProcessBackTraceInformation;
+extern RtlCreateQueryDebugBufferFunc
+ RtlCreateQueryDebugBuffer;
+extern RtlQueryProcessDebugInformationFunc
+ RtlQueryProcessDebugInformation;
+extern RtlDestroyQueryDebugBufferFunc
+ RtlDestroyQueryDebugBuffer;
+
+extern RtlGetNtGlobalFlagsFunc RtlGetNtGlobalFlags;
+extern RtlNtStatusToDosErrorFunc RtlNtStatusToDosError;
+
+} // namespace nt_internals
+
+#endif // CEEE_TESTING_UTILS_NT_INTERNALS_H_
diff --git a/ceee/testing/utils/nt_internals_unittest.cc b/ceee/testing/utils/nt_internals_unittest.cc
new file mode 100644
index 0000000..d6e43ee
--- /dev/null
+++ b/ceee/testing/utils/nt_internals_unittest.cc
@@ -0,0 +1,103 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Test the functions defined in nt_internals.h.
+#include "ceee/testing/utils/nt_internals.h"
+#include <iostream>
+#include "gtest/gtest.h"
+#include "ceee/testing/utils/gflag_utils.h"
+
+#define STATUS_SUCCESS ((NTSTATUS)0)
+
+namespace nt_internals {
+
+TEST(NtInternalsTest, GetThreadTIB) {
+ ASSERT_TRUE(NULL != GetThreadTIB(::GetCurrentThread()));
+}
+
+TEST(NtInternalsTest, NtQueryInformationThread) {
+ ASSERT_TRUE(NULL != NtQueryInformationThread);
+ THREAD_BASIC_INFO info = {};
+ ULONG ret_len = 0;
+ NTSTATUS status = NtQueryInformationThread(::GetCurrentThread(),
+ ThreadBasicInformation, &info, sizeof(info), &ret_len);
+ EXPECT_EQ(sizeof(info), ret_len);
+ EXPECT_TRUE(NULL != info.TebBaseAddress);
+ EXPECT_EQ(reinterpret_cast<DWORD>(info.ClientId.UniqueThread),
+ ::GetCurrentThreadId());
+ EXPECT_EQ(reinterpret_cast<DWORD>(info.ClientId.UniqueProcess),
+ ::GetCurrentProcessId());
+}
+
+TEST(NtInternalsTest, RtlCreateQueryDebugBuffer) {
+ ASSERT_TRUE(NULL != RtlCreateQueryDebugBuffer);
+ ASSERT_TRUE(NULL != RtlDestroyQueryDebugBuffer);
+
+ PRTL_DEBUG_INFORMATION debug_info = RtlCreateQueryDebugBuffer(0, 0);
+ ASSERT_TRUE(NULL != debug_info);
+ RtlDestroyQueryDebugBuffer(debug_info);
+}
+
+TEST(NtInternalsTest, RtlQueryProcessDebugInformation) {
+ ASSERT_TRUE(NULL != RtlCreateQueryDebugBuffer);
+ ASSERT_TRUE(NULL != RtlDestroyQueryDebugBuffer);
+ ASSERT_TRUE(NULL != RtlQueryProcessDebugInformation);
+ ASSERT_TRUE(NULL != RtlGetNtGlobalFlags);
+
+ PRTL_DEBUG_INFORMATION debug_info = RtlCreateQueryDebugBuffer(0, 0);
+ ASSERT_TRUE(NULL != debug_info);
+
+ NTSTATUS status =
+ RtlQueryProcessDebugInformation(::GetCurrentProcessId(),
+ PDI_MODULES | PDI_BACKTRACE,
+ debug_info);
+ EXPECT_EQ(STATUS_SUCCESS, status);
+
+ ASSERT_TRUE(NULL != debug_info->Modules);
+ EXPECT_LT(0U, debug_info->Modules->NumberOfModules);
+
+ // The global flag is usually set by our main function, but when
+ // we e.g. run under app verifier it won't. For some reason we
+ // get stack backtraces under app verifier even when the backtrace
+ // flag is not set.
+ // ASSERT_TRUE(FLG_USER_STACK_TRACE_DB & RtlGetNtGlobalFlags());
+
+ ASSERT_TRUE(NULL != debug_info->BackTraces);
+ EXPECT_LT(0U, debug_info->BackTraces->NumberOfBackTraces);
+
+ status = RtlDestroyQueryDebugBuffer(debug_info);
+ EXPECT_EQ(STATUS_SUCCESS, status);
+}
+
+TEST(NtInternalsTest, RtlQueryProcessBackTraceInformation) {
+ ASSERT_TRUE(NULL != RtlQueryProcessBackTraceInformation);
+ ASSERT_TRUE(NULL != RtlGetNtGlobalFlags);
+
+ // Size gleaned from buffers returned from RtlCreateQueryDebugBuffer.
+ static char buf[0x00400000];
+ PRTL_DEBUG_INFORMATION info = reinterpret_cast<PRTL_DEBUG_INFORMATION>(buf);
+
+ memset(buf, 0, sizeof(buf));
+ info->OffsetFree = sizeof(RTL_DEBUG_INFORMATION);
+ info->ViewSize = sizeof(buf);
+ info->CommitSize = sizeof(buf);
+ NTSTATUS status = RtlQueryProcessBackTraceInformation(info);
+ ASSERT_EQ(STATUS_SUCCESS, status);
+
+ // The global flag is usually set by our main function, but when
+ // we e.g. run under app verifier it won't. For some reason we
+ // get stack backtraces under app verifier even when the backtrace
+ // flag is not set.
+ // ASSERT_TRUE(FLG_USER_STACK_TRACE_DB & RtlGetNtGlobalFlags());
+
+ ASSERT_TRUE(info->BackTraces != NULL);
+ ASSERT_LT(0UL, info->BackTraces->NumberOfBackTraces);
+}
+
+TEST(NtInternalsTest, RtlGetNtGlobalFlags) {
+ // No crash...
+ RtlGetNtGlobalFlags();
+}
+
+} // namespace nt_internals
diff --git a/ceee/testing/utils/test_utils.cc b/ceee/testing/utils/test_utils.cc
new file mode 100644
index 0000000..29b0bd6
--- /dev/null
+++ b/ceee/testing/utils/test_utils.cc
@@ -0,0 +1,170 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Utilities for testing.
+
+#include "base/file_path.h"
+#include "base/path_service.h"
+#include "base/utf_string_conversions.h"
+#include "ceee/testing/utils/test_utils.h"
+
+namespace testing {
+
+HRESULT GetConnectionCount(IUnknown* container,
+ REFIID connection_point_id,
+ size_t* num_connections) {
+ if (!num_connections)
+ return E_POINTER;
+
+ *num_connections = 0;
+
+ CComPtr<IConnectionPointContainer> cpc;
+ HRESULT hr = container->QueryInterface(&cpc);
+ if (FAILED(hr))
+ return hr;
+
+ CHECK(cpc != NULL);
+
+ CComPtr<IConnectionPoint> cp;
+ hr = cpc->FindConnectionPoint(connection_point_id, &cp);
+
+ CComPtr<IEnumConnections> enum_connections;
+ if (SUCCEEDED(hr))
+ hr = cp->EnumConnections(&enum_connections);
+
+ if (FAILED(hr))
+ return hr;
+
+ while (true) {
+ CONNECTDATA conn = {};
+ ULONG fetched = 0;
+ hr = enum_connections->Next(1, &conn, &fetched);
+ if (FAILED(hr)) {
+ CHECK(conn.pUnk == NULL);
+ return hr;
+ }
+ if (hr == S_FALSE) {
+ CHECK(conn.pUnk == NULL);
+ return S_OK;
+ }
+ CHECK(NULL != conn.pUnk);
+ conn.pUnk->Release();
+
+ (*num_connections)++;
+ }
+ NOTREACHED();
+ return E_UNEXPECTED;
+}
+
+
+LogDisabler::LogDisabler() {
+ initial_log_level_ = logging::GetMinLogLevel();
+ logging::SetMinLogLevel(logging::LOG_FATAL + 1);
+}
+
+LogDisabler::~LogDisabler() {
+ logging::SetMinLogLevel(initial_log_level_);
+}
+
+PathServiceOverrider::PathServiceOverrider(int key, const FilePath& path) {
+ key_ = key;
+ PathService::Get(key, &original_path_);
+ PathService::Override(key, path);
+}
+
+PathServiceOverrider::~PathServiceOverrider() {
+ PathService::Override(key_, original_path_);
+}
+
+
+namespace internal {
+
+void WriteVariant(const VARIANT& var, ::std::ostream* os) {
+ *os << "{type=";
+
+ static struct {
+ VARTYPE vt;
+ const char *name;
+ } vartypes[] = {
+#define TYP(x) { x, #x },
+ TYP(VT_EMPTY)
+ TYP(VT_NULL)
+ TYP(VT_I2)
+ TYP(VT_I4)
+ TYP(VT_R4)
+ TYP(VT_R8)
+ TYP(VT_CY)
+ TYP(VT_DATE)
+ TYP(VT_BSTR)
+ TYP(VT_DISPATCH)
+ TYP(VT_ERROR)
+ TYP(VT_BOOL)
+ TYP(VT_VARIANT)
+ TYP(VT_UNKNOWN)
+ TYP(VT_DECIMAL)
+ TYP(VT_I1)
+ TYP(VT_UI1)
+ TYP(VT_UI2)
+ TYP(VT_UI4)
+ TYP(VT_I8)
+ TYP(VT_UI8)
+ TYP(VT_INT)
+ TYP(VT_UINT)
+ TYP(VT_VOID)
+ TYP(VT_HRESULT)
+ TYP(VT_PTR)
+ TYP(VT_SAFEARRAY)
+ TYP(VT_CARRAY)
+ TYP(VT_USERDEFINED)
+ TYP(VT_LPSTR)
+ TYP(VT_LPWSTR)
+ TYP(VT_RECORD)
+ TYP(VT_INT_PTR)
+ TYP(VT_UINT_PTR)
+ TYP(VT_FILETIME)
+ TYP(VT_BLOB)
+ TYP(VT_STREAM)
+ TYP(VT_STORAGE)
+ TYP(VT_STREAMED_OBJECT)
+ TYP(VT_STORED_OBJECT)
+ TYP(VT_BLOB_OBJECT)
+ TYP(VT_CF)
+ TYP(VT_CLSID)
+ TYP(VT_VERSIONED_STREAM)
+ TYP(VT_BSTR_BLOB)
+ TYP(VT_ILLEGAL)
+#undef TYP
+ };
+
+ bool found = false;
+ for (int i = 0; !found && i < ARRAYSIZE(vartypes); ++i) {
+ if (vartypes[i].vt == (var.vt & VT_TYPEMASK)) {
+ *os << vartypes[i].name;
+ found = true;
+ }
+ }
+
+ if (!found)
+ *os << "*ILLEGAL*";
+
+#define ATTRBIT(x) if (var.vt & x) *os << "| " #x;
+ ATTRBIT(VT_VECTOR)
+ ATTRBIT(VT_ARRAY)
+ ATTRBIT(VT_BYREF)
+ ATTRBIT(VT_RESERVED)
+#undef ATTRBIT
+
+ CComVariant copy;
+ if (SUCCEEDED(copy.ChangeType(VT_BSTR, &var))) {
+ *os << ", value=\""
+ << WideToUTF8(std::wstring(copy.bstrVal, ::SysStringLen(copy.bstrVal)))
+ << "\"";
+ }
+
+ *os << "}";
+}
+
+} // namespace testing::internal
+
+} // namespace testing
diff --git a/ceee/testing/utils/test_utils.gyp b/ceee/testing/utils/test_utils.gyp
new file mode 100644
index 0000000..7a62688
--- /dev/null
+++ b/ceee/testing/utils/test_utils.gyp
@@ -0,0 +1,104 @@
+# Copyright (c) 2010 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'variables': {
+ 'chromium_code': 1,
+ },
+ 'includes': [
+ '../../../build/common.gypi',
+ '../../common.gypi',
+ ],
+ 'target_defaults': {
+ 'include_dirs': [
+ '..',
+ ],
+ },
+ 'targets': [
+ {
+ 'target_name': 'test_utils',
+ 'type': 'static_library',
+ 'sources': [
+ 'gflag_utils.cc',
+ 'gflag_utils.h',
+ 'instance_count_mixin.cc',
+ 'instance_count_mixin.h',
+ 'mock_com.h',
+ 'mock_win32.h',
+ 'mock_static.h',
+ 'mock_window_utils.h',
+ 'mshtml_mocks.h',
+ 'dispex_mocks.h',
+ 'nt_internals.cc',
+ 'nt_internals.h',
+ 'test_utils.cc',
+ 'test_utils.h',
+ ],
+ 'dependencies': [
+ 'mshtml_mocks',
+ '<(DEPTH)/base/base.gyp:base',
+ '<(DEPTH)/testing/gmock.gyp:gmock',
+ '<(DEPTH)/testing/gtest.gyp:gtest',
+ ],
+ 'all_dependent_settings': {
+ 'include_dirs': [
+ '..'
+ ],
+ },
+ },
+ {
+ 'target_name': 'mshtml_mocks',
+ 'type': 'none',
+ 'sources': [
+ 'mshtml_mocks.h',
+ 'mshtml_mocks.py',
+ 'com_mock.py',
+ '<(SHARED_INTERMEDIATE_DIR)/mshtml_mocks.gen',
+ ],
+ 'actions': [
+ {
+ 'action_name': 'make_mshtml_mocks',
+ 'msvs_cygwin_shell': 0,
+ 'msvs_quote_cmd': 0,
+ 'inputs': [
+ 'mshtml_mocks.py',
+ ],
+ 'outputs': [
+ '<(SHARED_INTERMEDIATE_DIR)/mshtml_mocks.gen',
+ ],
+ 'action': [
+ '<@(python)',
+ 'mshtml_mocks.py',
+ '> "<(SHARED_INTERMEDIATE_DIR)/mshtml_mocks.gen"',
+ ],
+ },
+ ],
+ # All who use this need to be able to find the .gen file we generate.
+ 'all_dependent_settings': {
+ 'include_dirs': ['<(SHARED_INTERMEDIATE_DIR)'],
+ },
+ },
+ {
+ 'target_name': 'test_utils_unittests',
+ 'type': 'executable',
+ 'sources': [
+ 'gflag_utils_unittest.cc',
+ 'instance_count_mixin_unittest.cc',
+ 'nt_internals_unittest.cc',
+ 'test_utils_unittest.cc',
+ 'test_utils_unittest_main.cc',
+ ],
+ 'dependencies': [
+ 'test_utils',
+ '<(DEPTH)/base/base.gyp:base',
+ '<(DEPTH)/testing/gmock.gyp:gmock',
+ '<(DEPTH)/testing/gtest.gyp:gtest',
+ ],
+ 'libraries': [
+ 'oleacc.lib',
+ 'shlwapi.lib',
+ ],
+ }
+ ]
+}
diff --git a/ceee/testing/utils/test_utils.h b/ceee/testing/utils/test_utils.h
new file mode 100644
index 0000000..28ddb94
--- /dev/null
+++ b/ceee/testing/utils/test_utils.h
@@ -0,0 +1,314 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Utilities for testing.
+
+#ifndef CEEE_TESTING_UTILS_TEST_UTILS_H_
+#define CEEE_TESTING_UTILS_TEST_UTILS_H_
+
+#include <atlbase.h>
+#include <atlcom.h>
+#include <vector>
+
+#include "base/file_path.h"
+#include "base/logging.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace testing {
+
+// Counts the number of connections of type connection_point_id on container.
+HRESULT GetConnectionCount(IUnknown* container,
+ REFIID connection_point_id,
+ size_t* num_connections);
+
+// Fires event with dispid |id| on IConnectionPointImpl-derived connection
+// point instance |cp| with the |num_args| arguments specified in |args|.
+template <typename ConnectionPoint>
+void FireEvent(ConnectionPoint *cp, DISPID id, size_t num_args, VARIANT* args) {
+ typedef std::vector<IUnknown*> SinkVector;
+ SinkVector sinks;
+
+ // Grab all the sinks.
+ sinks.insert(sinks.end(), cp->m_vec.begin(), cp->m_vec.end());
+
+ // Grab a reference to them all in a loop.
+ // This does not cause an IPC, so we don't need to worry about
+ // reentrancy on the collection so far.
+ SinkVector::const_iterator it(sinks.begin()), end(sinks.end());
+ for (; it != end; ++it) {
+ if (*it)
+ (*it)->AddRef();
+ }
+
+ DISPPARAMS dispparams = { args, NULL, num_args, 0 };
+
+ // And fire the event at them.
+ for (it = sinks.begin(); it != sinks.end(); ++it) {
+ CComDispatchDriver sink_disp(*it);
+
+ if (sink_disp != NULL)
+ sink_disp->Invoke(id, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD,
+ &dispparams, NULL, NULL, NULL);
+ }
+
+ // Release the reference we grabbed above.
+ for (it = sinks.begin(); it != sinks.end(); ++it) {
+ if (*it)
+ (*it)->Release();
+ }
+}
+
+// Prevents any logging actions (DCHECKs, killing the process,
+// informational output, or anything) for the scope of its lifetime.
+class LogDisabler {
+ public:
+ LogDisabler();
+ ~LogDisabler();
+
+ private:
+ int initial_log_level_;
+};
+
+// Overrides a path in the PathService singleton, replacing the
+// original at the end of its lifetime.
+class PathServiceOverrider {
+public:
+ PathServiceOverrider(int key, const FilePath& path);
+ ~PathServiceOverrider();
+
+private:
+ int key_;
+ FilePath original_path_;
+};
+
+// GMock action to simplify writing the side effect of copying a string
+// to an output parameter.
+template <size_t N>
+inline SetArrayArgumentActionP2<N, const char*, const char*>
+ CopyStringToArgument(const char* s) {
+ return SetArrayArgument<N>(s, s + lstrlenA(s) + 1);
+}
+
+template <size_t N>
+inline SetArrayArgumentActionP2<N, const wchar_t*, const wchar_t*>
+ CopyStringToArgument(const wchar_t* s) {
+ return SetArrayArgument<N>(s, s + lstrlenW(s) + 1);
+}
+
+// GMock action to simplify writing the side effect of copying a wchar_t string
+// to a BSTR output parameter. The wchar_t string must be in scope when the
+// expected call is made.
+ACTION_TEMPLATE(CopyBSTRToArgument,
+ HAS_1_TEMPLATE_PARAMS(size_t, N),
+ AND_1_VALUE_PARAMS(value)) {
+ StaticAssertTypeEq<const wchar_t*, value_type>();
+ *::std::tr1::get<N>(args) = ::SysAllocString(value);
+}
+
+namespace internal {
+
+template <size_t N, typename InputInterface>
+class CopyInterfaceToArgumentAction {
+ public:
+ // Constructs an action that sets the variable pointed to by the
+ // N-th function argument to 'value'.
+ explicit CopyInterfaceToArgumentAction(InputInterface* value)
+ : value_(value) {}
+
+ template <typename Result, typename ArgumentTuple>
+ void Perform(const ArgumentTuple& args) const {
+ CompileAssertTypesEqual<void, Result>();
+ HRESULT hr = const_cast<CComPtr<InputInterface>&>(value_)
+ .CopyTo(::std::tr1::get<N>(args));
+ ASSERT_HRESULT_SUCCEEDED(hr);
+ }
+
+ private:
+ CComPtr<InputInterface> value_;
+};
+
+template <size_t N>
+class CopyVariantToArgumentAction {
+ public:
+ // Constructs an action that sets the variable pointed to by the
+ // N-th function argument to 'value'.
+ explicit CopyVariantToArgumentAction(const VARIANT& value) : value_(value) {}
+
+ template <typename Result, typename ArgumentTuple>
+ void Perform(const ArgumentTuple& args) const {
+ CompileAssertTypesEqual<void, Result>();
+ HRESULT hr = ::VariantCopy(::std::tr1::get<N>(args), &value_);
+ ASSERT_HRESULT_SUCCEEDED(hr);
+ }
+
+ private:
+ CComVariant value_;
+};
+
+void WriteVariant(const VARIANT& var, ::std::ostream* os);
+
+// Comparator for variants.
+class VariantMatcher : public ::testing::MatcherInterface<VARIANT> {
+ public:
+ explicit VariantMatcher(const VARIANT& value)
+ : value_(value) {}
+
+ virtual bool MatchAndExplain(VARIANT var,
+ MatchResultListener* listener) const {
+ // listener is guaranteed not to be NULL by Google Mock, but its
+ // stream may be NULL though (it sometimes uses DummyMatchResultListener).
+ if (listener->stream() != NULL)
+ DescribeTo(listener->stream());
+ return value_ == var;
+ }
+
+ virtual void DescribeTo(::std::ostream* os) const {
+ *os << "equals ";
+ WriteVariant(value_, os);
+ }
+
+ virtual void DescribeNegationTo(::std::ostream* os) const {
+ *os << "does not equal ";
+ WriteVariant(value_, os);
+ }
+ private:
+ CComVariant value_;
+};
+
+// Comparator for variant pointers.
+class VariantPointerMatcher : public ::testing::MatcherInterface<VARIANT*> {
+ public:
+ explicit VariantPointerMatcher(const VARIANT* value)
+ : value_(value) {}
+
+ virtual bool MatchAndExplain(VARIANT* var,
+ MatchResultListener* listener) const {
+ // listener is guaranteed not to be NULL by Google Mock, but its
+ // stream may be NULL though (it sometimes uses DummyMatchResultListener).
+ if (listener->stream() != NULL)
+ DescribeTo(listener->stream());
+ return value_ == *var;
+ }
+
+ virtual void DescribeTo(::std::ostream* os) const {
+ *os << "equals ";
+ WriteVariant(value_, os);
+ }
+
+ virtual void DescribeNegationTo(::std::ostream* os) const {
+ *os << "does not equal ";
+ WriteVariant(value_, os);
+ }
+ private:
+ CComVariant value_;
+};
+
+template <size_t N>
+class DispParamArgMatcher : public ::testing::MatcherInterface<DISPPARAMS*> {
+ public:
+ explicit DispParamArgMatcher(const VARIANT& value)
+ : value_(value) {}
+
+ virtual bool MatchAndExplain(DISPPARAMS* params,
+ MatchResultListener* listener) const {
+ // listener is guaranteed not to be NULL by Google Mock, but its
+ // stream may be NULL though (it sometimes uses DummyMatchResultListener).
+ if (listener->stream() != NULL)
+ DescribeTo(listener->stream());
+ return params->cArgs >= N && value_ == params->rgvarg[N];
+ }
+
+ virtual void DescribeTo(::std::ostream* os) const {
+ *os << "equals ";
+ WriteVariant(value_, os);
+ }
+
+ virtual void DescribeNegationTo(::std::ostream* os) const {
+ *os << "does not equal ";
+ WriteVariant(value_, os);
+ }
+ private:
+ CComVariant value_;
+};
+
+} // namespace internal
+
+// GMock action to simplify writing the side effect of copying an interface
+// to an output parameter, observing COM reference counting rules.
+template <size_t N, typename InputInterface>
+PolymorphicAction<internal::CopyInterfaceToArgumentAction<N, InputInterface> >
+CopyInterfaceToArgument(InputInterface* itf) {
+ return MakePolymorphicAction(
+ internal::CopyInterfaceToArgumentAction<N, InputInterface>(itf));
+}
+template <size_t N, typename InputInterface>
+PolymorphicAction<internal::CopyInterfaceToArgumentAction<N, InputInterface> >
+CopyInterfaceToArgument(const CComPtr<InputInterface> &itf) {
+ return MakePolymorphicAction(
+ internal::CopyInterfaceToArgumentAction<N, InputInterface>(itf));
+}
+
+// GMock action to simplify writing the side effect of copying a variant
+// to an output parameter, using variant copy methods.
+template <size_t N>
+PolymorphicAction<internal::CopyVariantToArgumentAction<N> >
+CopyVariantToArgument(const VARIANT& variant) {
+ return MakePolymorphicAction(
+ internal::CopyVariantToArgumentAction<N>(variant));
+}
+
+// GMock matcher to compare variants.
+inline Matcher<VARIANT> VariantEq(const VARIANT& var) {
+ return MakeMatcher(new internal::VariantMatcher(var));
+}
+
+// GMock matcher to compare variant pointers.
+inline Matcher<VARIANT *> VariantPointerEq(const VARIANT* var) {
+ return MakeMatcher(new internal::VariantPointerMatcher(var));
+}
+
+// GMock matcher to match argument N in a DISPPARAM pointer.
+// This makes it humane to match on parameters to IDispatch::Invoke.
+template <size_t N>
+inline Matcher<DISPPARAMS*> DispParamArgEq(const VARIANT& var) {
+ return MakeMatcher(new internal::DispParamArgMatcher<N>(var));
+}
+
+// Gmock action to add a reference to a COM object you are having a mock
+// method return.
+ACTION_P(AddRef, p) {
+ p->AddRef();
+}
+
+} // namespace testing
+
+// Allow GMock to print VARIANT values.
+inline ::std::ostream& operator<<(::std::ostream& os, const VARIANT& var) {
+ testing::internal::WriteVariant(var, &os);
+ return os;
+}
+
+// Sometimes our tests that use SideStep to stub out dependencies fail in
+// release builds because one or more of the functions being hooked by
+// SideStep is inlined by the compiler, and therefore cannot be hooked.
+// In rare cases, we might use a noinline pragma to make such functions always
+// hookable, but usually it is easier and better (so as not to impact the
+// production code) to simply run the test in debug builds only.
+//
+// For noinline pragma, see
+// http://msdn.microsoft.com/en-us/library/cx053bca(VS.71).aspx
+#ifdef _DEBUG
+#define TEST_DEBUG_ONLY(test_case_name, test_name) \
+ TEST(test_case_name, test_name)
+#define TEST_F_DEBUG_ONLY(test_fixture, test_name) \
+ TEST_F(test_fixture, test_name)
+#else
+#define TEST_DEBUG_ONLY(test_case_name, test_name) \
+ void DisabledTest##test_case_name##test_name()
+#define TEST_F_DEBUG_ONLY TEST_DEBUG_ONLY
+#endif
+
+
+
+#endif // CEEE_TESTING_UTILS_TEST_UTILS_H_
diff --git a/ceee/testing/utils/test_utils_unittest.cc b/ceee/testing/utils/test_utils_unittest.cc
new file mode 100644
index 0000000..4ca4a4e
--- /dev/null
+++ b/ceee/testing/utils/test_utils_unittest.cc
@@ -0,0 +1,143 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Unit tests for test utils.
+
+#include "ceee/testing/utils/test_utils.h"
+
+#include "base/scoped_vector.h"
+#include "ceee/common/initializing_coclass.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+TEST(LogDisabler, ItDisables) {
+ testing::LogDisabler disabler;
+ DCHECK(false);
+}
+
+} // namespace
+
+namespace {
+
+using testing::_;
+using testing::CopyBSTRToArgument;
+using testing::CopyInterfaceToArgument;
+using testing::CopyStringToArgument;
+using testing::CopyVariantToArgument;
+using testing::DoAll;
+using testing::Return;
+
+class IInt : public IUnknown {
+ public:
+ virtual int get() const = 0;
+ virtual void set(int i) = 0;
+};
+
+// {FA26DE41-C212-4e11-A23F-C7DC405180A2}
+const GUID IID_IInt =
+ { 0xfa26de41, 0xc212, 0x4e11,
+ { 0xa2, 0x3f, 0xc7, 0xdc, 0x40, 0x51, 0x80, 0xa2 } };
+
+class MockInt
+ : public CComObjectRootEx<CComSingleThreadModel>,
+ public IInt {
+ public:
+ BEGIN_COM_MAP(MockInt)
+ COM_INTERFACE_ENTRY_IID(IID_IInt, IInt)
+ END_COM_MAP()
+
+ HRESULT Initialize(MockInt** i) {
+ *i = this;
+ return S_OK;
+ }
+
+ int get() const { return i_; }
+ void set(int i) { i_ = i; }
+
+ private:
+ int i_;
+};
+
+class MockGetter {
+ public:
+ MOCK_METHOD1(GetString, void(wchar_t* str));
+ MOCK_METHOD1(GetBSTR, void(BSTR* str));
+ MOCK_METHOD1(GetIInt, void(IInt** i));
+ MOCK_METHOD1(GetVariant, void(VARIANT* var));
+};
+
+const wchar_t* kStr = L"hello";
+const int kInt = 5;
+
+TEST(CopyStringToArgument, ItCopies) {
+ MockGetter getter;
+
+ EXPECT_CALL(getter, GetString(_)).WillOnce(CopyStringToArgument<0>(kStr));
+
+ wchar_t* ret = new wchar_t[lstrlenW(kStr) + 1];
+ getter.GetString(ret);
+ ASSERT_EQ(wcscmp(ret, kStr), 0);
+ delete[] ret;
+}
+
+TEST(CopyBSTRToArgument, ItCopies) {
+ MockGetter getter;
+
+ EXPECT_CALL(getter, GetBSTR(_)).WillOnce(CopyBSTRToArgument<0>(kStr));
+
+ CComBSTR expected = kStr;
+ CComBSTR ret;
+ getter.GetBSTR(&ret);
+ ASSERT_EQ(ret, expected);
+}
+
+TEST(CopyInterfaceToArgument, ItCopies) {
+ MockGetter getter;
+
+ {
+ // Cause ptr to go out of scope.
+ MockInt* mock_int;
+ CComPtr<IInt> int_ptr;
+ ASSERT_HRESULT_SUCCEEDED(
+ InitializingCoClass<MockInt>::CreateInitializedIID(
+ &mock_int, IID_IInt, &int_ptr));
+ int_ptr->set(kInt);
+
+ EXPECT_CALL(getter, GetIInt(_))
+ .WillOnce(CopyInterfaceToArgument<0>(int_ptr));
+ }
+
+ CComPtr<IInt> int_ptr;
+ getter.GetIInt(&int_ptr);
+ ASSERT_EQ(int_ptr->get(), kInt);
+}
+
+TEST(CopyVariantToArgument, ItCopies) {
+ MockGetter getter;
+
+ {
+ // Cause the variant to go out of scope.
+ MockInt* mock_int;
+ CComPtr<IInt> int_ptr;
+ ASSERT_HRESULT_SUCCEEDED(
+ InitializingCoClass<MockInt>::CreateInitializedIID(
+ &mock_int, IID_IInt, &int_ptr));
+ int_ptr->set(kInt);
+
+ CComVariant var(int_ptr);
+ EXPECT_CALL(getter, GetVariant(_)).WillOnce(CopyVariantToArgument<0>(var));
+ }
+
+ CComVariant ret;
+ getter.GetVariant(&ret);
+ ASSERT_EQ(V_VT(&ret), VT_UNKNOWN);
+
+ CComPtr<IInt> int_ptr;
+ ASSERT_HRESULT_SUCCEEDED(V_UNKNOWN(&ret)->QueryInterface(
+ IID_IInt, reinterpret_cast<void**>(&int_ptr)));
+ ASSERT_EQ(int_ptr->get(), kInt);
+}
+
+} // namespace
diff --git a/ceee/testing/utils/test_utils_unittest_main.cc b/ceee/testing/utils/test_utils_unittest_main.cc
new file mode 100644
index 0000000..a1203ff
--- /dev/null
+++ b/ceee/testing/utils/test_utils_unittest_main.cc
@@ -0,0 +1,26 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Main function for common unittests.
+#include <atlbase.h>
+#include <atlcom.h>
+#include "gtest/gtest.h"
+#include "ceee/testing/utils/gflag_utils.h"
+
+// The global flags we want these tests to run with.
+const DWORD kGlobalFlags = FLG_USER_STACK_TRACE_DB;
+
+// We're testing ATL code that requires a module object.
+class ObligatoryModule: public CAtlDllModuleT<ObligatoryModule> {
+};
+
+ObligatoryModule g_obligatory_atl_module;
+
+int main(int argc, char **argv) {
+ if (!IsDebuggerPresent())
+ testing::RelaunchWithGFlags(kGlobalFlags);
+
+ testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}