summaryrefslogtreecommitdiffstats
path: root/ceee/testing
diff options
context:
space:
mode:
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();
+}