Update from https://crrev.com/318214

TBR=qsr@chromium.org

Review URL: https://codereview.chromium.org/960873002
diff --git a/base/BUILD.gn b/base/BUILD.gn
index c63d377..9dbc41c 100644
--- a/base/BUILD.gn
+++ b/base/BUILD.gn
@@ -310,6 +310,7 @@
     "mac/scoped_sending_event.h",
     "mac/scoped_sending_event.mm",
     "mac/sdk_forward_declarations.h",
+    "mac/sdk_forward_declarations.mm",
     "macros.h",
     "md5.cc",
     "md5.h",
@@ -675,6 +676,10 @@
     "trace_event/memory_dump_provider.h",
     "trace_event/process_memory_dump.cc",
     "trace_event/process_memory_dump.h",
+    "trace_event/process_memory_maps.cc",
+    "trace_event/process_memory_maps.h",
+    "trace_event/process_memory_maps_dump_provider.cc",
+    "trace_event/process_memory_maps_dump_provider.h",
     "trace_event/process_memory_totals.cc",
     "trace_event/process_memory_totals.h",
     "trace_event/process_memory_totals_dump_provider.cc",
@@ -759,7 +764,29 @@
   ]
 
   if (is_nacl) {
-    sources += [ "files/file_path_watcher_stub.cc" ]
+    # We reset sources_assignment_filter in order to explicitly include
+    # the linux file (which would otherwise be filtered out).
+    set_sources_assignment_filter([])
+    sources += [
+      "files/file_path_watcher_stub.cc",
+      "sync_socket_nacl.cc",
+      "threading/platform_thread_linux.cc",
+    ]
+    set_sources_assignment_filter(sources_assignment_filter)
+
+    sources -= [
+      "allocator/type_profiler_control.cc",
+      "allocator/type_profiler_control.h",
+      "async_socket_io_handler_posix.cc",
+      "base_paths.cc",
+      "cpu.cc",
+      "files/file_proxy.cc",
+      "files/file_util.cc",
+      "files/file_util_proxy.cc",
+      "path_service.cc",
+      "scoped_native_library.cc",
+      "files/scoped_temp_dir.cc",
+    ]
   }
 
   sources -= [
@@ -847,11 +874,12 @@
       "process/launch_posix.cc",
       "process/process_metrics_posix.cc",
       "process/process_posix.cc",
+      "rand_util_posix.cc",
       "sync_socket_posix.cc",
       "sys_info_posix.cc",
     ]
   } else {
-    # Remove nacl stuff.
+    # Remove NaCl stuff.
     sources -= [
       "memory/shared_memory_nacl.cc",
       "os_compat_nacl.cc",
@@ -1134,6 +1162,23 @@
   ]
 }
 
+if (is_win) {
+  shared_library("pe_image_test") {
+    sources = [
+      "win/pe_image_test.cc",
+    ]
+    ldflags = [
+      "/DELAYLOAD:cfgmgr32.dll",
+      "/DELAYLOAD:shell32.dll",
+      "/SUBSYSTEM:WINDOWS",
+    ]
+    libs = [
+      "cfgmgr32.lib",
+      "shell32.lib",
+    ]
+  }
+}
+
 test("base_unittests") {
   sources = [
     "android/application_status_listener_unittest.cc",
@@ -1336,6 +1381,7 @@
     "timer/timer_unittest.cc",
     "tools_sanity_unittest.cc",
     "trace_event/memory_dump_manager_unittest.cc",
+    "trace_event/process_memory_maps_dump_provider_unittest.cc",
     "trace_event/process_memory_totals_dump_provider_unittest.cc",
     "trace_event/trace_event_argument_unittest.cc",
     "trace_event/trace_event_memory_unittest.cc",
@@ -1441,6 +1487,10 @@
     set_sources_assignment_filter(sources_assignment_filter)
   }
 
+  if (is_win) {
+    deps += [ ":pe_image_test" ]
+  }
+
   # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
   configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
 }
diff --git a/base/android/java/src/org/chromium/base/ObserverList.java b/base/android/java/src/org/chromium/base/ObserverList.java
index e812b0d..7a2ab98 100644
--- a/base/android/java/src/org/chromium/base/ObserverList.java
+++ b/base/android/java/src/org/chromium/base/ObserverList.java
@@ -46,6 +46,7 @@
     public final List<E> mObservers = new ArrayList<E>();
     private int mIterationDepth = 0;
     private int mCount = 0;
+    private boolean mNeedsCompact = false;
 
     public ObserverList() {}
 
@@ -91,6 +92,7 @@
             // No one is iterating over the list.
             mObservers.remove(index);
         } else {
+            mNeedsCompact = true;
             mObservers.set(index, null);
         }
         --mCount;
@@ -112,6 +114,7 @@
         }
 
         int size = mObservers.size();
+        mNeedsCompact |= size != 0;
         for (int i = 0; i < size; i++) {
             mObservers.set(i, null);
         }
@@ -167,7 +170,10 @@
     private void decrementIterationDepthAndCompactIfNeeded() {
         mIterationDepth--;
         assert mIterationDepth >= 0;
-        if (mIterationDepth == 0) compact();
+        if (mIterationDepth > 0) return;
+        if (!mNeedsCompact) return;
+        mNeedsCompact = false;
+        compact();
     }
 
     /**
diff --git a/base/android/java/src/org/chromium/base/library_loader/LibraryLoader.java b/base/android/java/src/org/chromium/base/library_loader/LibraryLoader.java
index d68fb4a..c7d8527 100644
--- a/base/android/java/src/org/chromium/base/library_loader/LibraryLoader.java
+++ b/base/android/java/src/org/chromium/base/library_loader/LibraryLoader.java
@@ -42,7 +42,7 @@
     private static final Object sLock = new Object();
 
     // The singleton instance of LibraryLoader.
-    private static LibraryLoader sInstance;
+    private static volatile LibraryLoader sInstance;
 
     // One-way switch becomes true when the libraries are loaded.
     private boolean mLoaded;
@@ -54,7 +54,9 @@
     // One-way switch becomes true when the libraries are initialized (
     // by calling nativeLibraryLoaded, which forwards to LibraryLoaded(...) in
     // library_loader_hooks.cc).
-    private boolean mInitialized;
+    // Note that this member should remain a one-way switch, since it accessed from multiple
+    // threads without a lock.
+    private volatile boolean mInitialized;
 
     // One-way switches recording attempts to use Relro sharing in the browser.
     // The flags are used to report UMA stats later.
@@ -81,7 +83,9 @@
     private boolean mLibraryIsMappableInApk = true;
 
     // The type of process the shared library is loaded in.
-    private int mLibraryProcessType;
+    // This member can be accessed from multiple threads simultaneously, so it have to be
+    // final (like now) or be protected in some way (volatile of synchronized).
+    private final int mLibraryProcessType;
 
     /**
      * @param libraryProcessType the process the shared library is loaded in. refer to
@@ -141,9 +145,7 @@
      * Checks if library is fully loaded and initialized.
      */
     public static boolean isInitialized() {
-        synchronized (sLock) {
-            return sInstance != null && sInstance.mInitialized;
-        }
+        return sInstance != null && sInstance.mInitialized;
     }
 
     /**
@@ -377,10 +379,6 @@
             Log.e(TAG, "error calling nativeLibraryLoaded");
             throw new ProcessInitException(LoaderErrors.LOADER_ERROR_FAILED_TO_REGISTER_JNI);
         }
-        // From this point on, native code is ready to use and checkIsReady()
-        // shouldn't complain from now on (and in fact, it's used by the
-        // following calls).
-        mInitialized = true;
 
         // The Chrome JNI is registered by now so we can switch the Java
         // command line over to delegating to native if it's necessary.
@@ -391,6 +389,13 @@
 
         // From now on, keep tracing in sync with native.
         TraceEvent.registerNativeEnabledObserver();
+
+        // From this point on, native code is ready to use and checkIsReady()
+        // shouldn't complain from now on (and in fact, it's used by the
+        // following calls).
+        // Note that this flag can be accessed asynchronously, so any initialization
+        // must be performed before.
+        mInitialized = true;
     }
 
     // Called after all native initializations are complete.
@@ -455,10 +460,8 @@
      */
     @CalledByNative
     public static int getLibraryProcessType() {
-        synchronized (sLock) {
-            if (sInstance == null) return LibraryProcessType.PROCESS_UNINITIALIZED;
-            return sInstance.mLibraryProcessType;
-        }
+        if (sInstance == null) return LibraryProcessType.PROCESS_UNINITIALIZED;
+        return sInstance.mLibraryProcessType;
     }
 
     private native void nativeInitCommandLine(String[] initCommandLine);
diff --git a/base/android/jni_generator/golden_sample_for_tests_jni.h b/base/android/jni_generator/golden_sample_for_tests_jni.h
index 0fcdc69..ba7494e 100644
--- a/base/android/jni_generator/golden_sample_for_tests_jni.h
+++ b/base/android/jni_generator/golden_sample_for_tests_jni.h
@@ -373,6 +373,7 @@
 };
 
 static bool RegisterNativesImpl(JNIEnv* env) {
+
   g_InnerStructA_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
       base::android::GetClass(env, kInnerStructAClassPath).obj()));
   g_SampleForTests_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
diff --git a/base/android/jni_generator/jni_generator.py b/base/android/jni_generator/jni_generator.py
index 54fea6b..fd03f0e 100755
--- a/base/android/jni_generator/jni_generator.py
+++ b/base/android/jni_generator/jni_generator.py
@@ -922,7 +922,8 @@
     """Returns the code for RegisterNatives."""
     template = Template("""\
 ${REGISTER_NATIVES_SIGNATURE} {
-${EARLY_EXIT}${CLASSES}
+${EARLY_EXIT}
+${CLASSES}
 ${NATIVES}
 ${CALLED_BY_NATIVES}
   return true;
@@ -1073,8 +1074,10 @@
 """
     if self.options.native_exports:
       template_str += """
-__attribute__((visibility("default"), alias("${NAME}")))
-${RETURN} ${STUB_NAME}(JNIEnv* env, ${PARAMS});
+__attribute__((visibility("default")))
+${RETURN} ${STUB_NAME}(JNIEnv* env, ${PARAMS}) {
+  return ${NAME}(${PARAMS_IN_CALL});
+}
 """
     template = Template(template_str)
     params_in_call = []
@@ -1312,7 +1315,7 @@
     if self.init_native:
       if self.options.native_exports:
         template = Template("""\
-    base::subtle::Release_Store(&g_${JAVA_CLASS}_clazz,
+  base::subtle::Release_Store(&g_${JAVA_CLASS}_clazz,
       static_cast<base::subtle::AtomicWord>(env->NewWeakGlobalRef(clazz));""")
       else:
         template = Template("""\
diff --git a/base/android/jni_generator/testCalledByNatives.golden b/base/android/jni_generator/testCalledByNatives.golden
index 22aa45d..e33356a 100644
--- a/base/android/jni_generator/testCalledByNatives.golden
+++ b/base/android/jni_generator/testCalledByNatives.golden
@@ -498,6 +498,7 @@
 // Step 3: RegisterNatives.
 
 static bool RegisterNativesImpl(JNIEnv* env) {
+
   g_TestJni_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
       base::android::GetClass(env, kTestJniClassPath).obj()));
   g_InfoBar_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
diff --git a/base/android/jni_generator/testConstantsFromJavaP.golden b/base/android/jni_generator/testConstantsFromJavaP.golden
index f122529..1c816bc 100644
--- a/base/android/jni_generator/testConstantsFromJavaP.golden
+++ b/base/android/jni_generator/testConstantsFromJavaP.golden
@@ -2221,6 +2221,7 @@
 // Step 3: RegisterNatives.
 
 static bool RegisterNativesImpl(JNIEnv* env) {
+
   g_MotionEvent_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
       base::android::GetClass(env, kMotionEventClassPath).obj()));
 
diff --git a/base/android/jni_generator/testEagerCalledByNativesOption.golden b/base/android/jni_generator/testEagerCalledByNativesOption.golden
index 6c1323e..19108bf 100644
--- a/base/android/jni_generator/testEagerCalledByNativesOption.golden
+++ b/base/android/jni_generator/testEagerCalledByNativesOption.golden
@@ -79,6 +79,7 @@
 };
 
 static bool RegisterNativesImpl(JNIEnv* env, jclass clazz) {
+
   g_Test_clazz = static_cast<jclass>(env->NewWeakGlobalRef(clazz));
 
   const int kMethodsTestSize = arraysize(kMethodsTest);
diff --git a/base/android/jni_generator/testFromJavaP.golden b/base/android/jni_generator/testFromJavaP.golden
index 5827410..b7276bc 100644
--- a/base/android/jni_generator/testFromJavaP.golden
+++ b/base/android/jni_generator/testFromJavaP.golden
@@ -255,6 +255,7 @@
 // Step 3: RegisterNatives.
 
 static bool RegisterNativesImpl(JNIEnv* env) {
+
   g_InputStream_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
       base::android::GetClass(env, kInputStreamClassPath).obj()));
 
diff --git a/base/android/jni_generator/testFromJavaPGenerics.golden b/base/android/jni_generator/testFromJavaPGenerics.golden
index 5d78390..489872c 100644
--- a/base/android/jni_generator/testFromJavaPGenerics.golden
+++ b/base/android/jni_generator/testFromJavaPGenerics.golden
@@ -53,6 +53,7 @@
 // Step 3: RegisterNatives.
 
 static bool RegisterNativesImpl(JNIEnv* env) {
+
   g_HashSet_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
       base::android::GetClass(env, kHashSetClassPath).obj()));
 
diff --git a/base/android/jni_generator/testInnerClassNatives.golden b/base/android/jni_generator/testInnerClassNatives.golden
index 2dee84e..5a525ef 100644
--- a/base/android/jni_generator/testInnerClassNatives.golden
+++ b/base/android/jni_generator/testInnerClassNatives.golden
@@ -40,6 +40,7 @@
 };
 
 static bool RegisterNativesImpl(JNIEnv* env) {
+
   g_TestJni_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
       base::android::GetClass(env, kTestJniClassPath).obj()));
 
diff --git a/base/android/jni_generator/testInnerClassNativesBothInnerAndOuter.golden b/base/android/jni_generator/testInnerClassNativesBothInnerAndOuter.golden
index 6ffbaac..c8d4b3c 100644
--- a/base/android/jni_generator/testInnerClassNativesBothInnerAndOuter.golden
+++ b/base/android/jni_generator/testInnerClassNativesBothInnerAndOuter.golden
@@ -50,6 +50,7 @@
 };
 
 static bool RegisterNativesImpl(JNIEnv* env) {
+
   g_TestJni_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
       base::android::GetClass(env, kTestJniClassPath).obj()));
 
diff --git a/base/android/jni_generator/testInnerClassNativesMultiple.golden b/base/android/jni_generator/testInnerClassNativesMultiple.golden
index b74e65f..42643ae 100644
--- a/base/android/jni_generator/testInnerClassNativesMultiple.golden
+++ b/base/android/jni_generator/testInnerClassNativesMultiple.golden
@@ -51,6 +51,7 @@
 };
 
 static bool RegisterNativesImpl(JNIEnv* env) {
+
   g_TestJni_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
       base::android::GetClass(env, kTestJniClassPath).obj()));
 
diff --git a/base/android/jni_generator/testJNIInitNativeNameOption.golden b/base/android/jni_generator/testJNIInitNativeNameOption.golden
index 53b5f17..a0998da 100644
--- a/base/android/jni_generator/testJNIInitNativeNameOption.golden
+++ b/base/android/jni_generator/testJNIInitNativeNameOption.golden
@@ -46,6 +46,7 @@
 };
 
 static bool RegisterNativesImpl(JNIEnv* env, jclass clazz) {
+
   g_Test_clazz = static_cast<jclass>(env->NewWeakGlobalRef(clazz));
 
   const int kMethodsTestSize = arraysize(kMethodsTest);
diff --git a/base/android/jni_generator/testJarJarRemapping.golden b/base/android/jni_generator/testJarJarRemapping.golden
index 75a35c5..2f85122 100644
--- a/base/android/jni_generator/testJarJarRemapping.golden
+++ b/base/android/jni_generator/testJarJarRemapping.golden
@@ -65,6 +65,7 @@
 };
 
 static bool RegisterNativesImpl(JNIEnv* env) {
+
   g_Example_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
       base::android::GetClass(env, kExampleClassPath).obj()));
 
diff --git a/base/android/jni_generator/testMultipleJNIAdditionalImport.golden b/base/android/jni_generator/testMultipleJNIAdditionalImport.golden
index df5b1c8..b0db9dd 100644
--- a/base/android/jni_generator/testMultipleJNIAdditionalImport.golden
+++ b/base/android/jni_generator/testMultipleJNIAdditionalImport.golden
@@ -68,6 +68,7 @@
 };
 
 static bool RegisterNativesImpl(JNIEnv* env) {
+
   g_Foo_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
       base::android::GetClass(env, kFooClassPath).obj()));
 
diff --git a/base/android/jni_generator/testNativeExportsOption.golden b/base/android/jni_generator/testNativeExportsOption.golden
index a4953cc..395fc39 100644
--- a/base/android/jni_generator/testNativeExportsOption.golden
+++ b/base/android/jni_generator/testNativeExportsOption.golden
@@ -30,17 +30,21 @@
 
 static jint Init(JNIEnv* env, jobject jcaller);
 
-__attribute__((visibility("default"), alias("Init")))
+__attribute__((visibility("default")))
 jint
     Java_org_chromium_example_jni_1generator_SampleForTests_00024MyInnerClass_nativeInit(JNIEnv*
-    env, jobject jcaller);
+    env, jobject jcaller) {
+  return Init(env, jcaller);
+}
 
 static jint Init(JNIEnv* env, jobject jcaller);
 
-__attribute__((visibility("default"), alias("Init")))
+__attribute__((visibility("default")))
 jint
     Java_org_chromium_example_jni_1generator_SampleForTests_00024MyOtherInnerClass_nativeInit(JNIEnv*
-    env, jobject jcaller);
+    env, jobject jcaller) {
+  return Init(env, jcaller);
+}
 
 };  // extern "C"
 
@@ -199,7 +203,8 @@
 // Step 3: RegisterNatives.
 
 static bool RegisterNativesImpl(JNIEnv* env, jclass clazz) {
-    base::subtle::Release_Store(&g_SampleForTests_clazz,
+
+  base::subtle::Release_Store(&g_SampleForTests_clazz,
       static_cast<base::subtle::AtomicWord>(env->NewWeakGlobalRef(clazz));
 
   return true;
diff --git a/base/android/jni_generator/testNativeExportsOptionalOption.golden b/base/android/jni_generator/testNativeExportsOptionalOption.golden
index 2a3b172..f47cb98 100644
--- a/base/android/jni_generator/testNativeExportsOptionalOption.golden
+++ b/base/android/jni_generator/testNativeExportsOptionalOption.golden
@@ -30,17 +30,21 @@
 
 static jint Init(JNIEnv* env, jobject jcaller);
 
-__attribute__((visibility("default"), alias("Init")))
+__attribute__((visibility("default")))
 jint
     Java_org_chromium_example_jni_1generator_SampleForTests_00024MyInnerClass_nativeInit(JNIEnv*
-    env, jobject jcaller);
+    env, jobject jcaller) {
+  return Init(env, jcaller);
+}
 
 static jint Init(JNIEnv* env, jobject jcaller);
 
-__attribute__((visibility("default"), alias("Init")))
+__attribute__((visibility("default")))
 jint
     Java_org_chromium_example_jni_1generator_SampleForTests_00024MyOtherInnerClass_nativeInit(JNIEnv*
-    env, jobject jcaller);
+    env, jobject jcaller) {
+  return Init(env, jcaller);
+}
 
 };  // extern "C"
 
@@ -237,7 +241,8 @@
 
 static bool RegisterNativesImpl(JNIEnv* env, jclass clazz) {
   if (base::android::IsManualJniRegistrationDisabled()) return true;
-    base::subtle::Release_Store(&g_SampleForTests_clazz,
+
+  base::subtle::Release_Store(&g_SampleForTests_clazz,
       static_cast<base::subtle::AtomicWord>(env->NewWeakGlobalRef(clazz));
 
   const int kMethodsMyOtherInnerClassSize =
diff --git a/base/android/jni_generator/testNatives.golden b/base/android/jni_generator/testNatives.golden
index 8708fa2..e5a4fab 100644
--- a/base/android/jni_generator/testNatives.golden
+++ b/base/android/jni_generator/testNatives.golden
@@ -198,6 +198,7 @@
 };
 
 static bool RegisterNativesImpl(JNIEnv* env) {
+
   g_TestJni_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
       base::android::GetClass(env, kTestJniClassPath).obj()));
 
diff --git a/base/android/jni_generator/testNativesLong.golden b/base/android/jni_generator/testNativesLong.golden
index 11e7c49..5fa901c 100644
--- a/base/android/jni_generator/testNativesLong.golden
+++ b/base/android/jni_generator/testNativesLong.golden
@@ -45,6 +45,7 @@
 };
 
 static bool RegisterNativesImpl(JNIEnv* env) {
+
   g_TestJni_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
       base::android::GetClass(env, kTestJniClassPath).obj()));
 
diff --git a/base/android/jni_generator/testPureNativeMethodsOption.golden b/base/android/jni_generator/testPureNativeMethodsOption.golden
index a45a386..ad63cca 100644
--- a/base/android/jni_generator/testPureNativeMethodsOption.golden
+++ b/base/android/jni_generator/testPureNativeMethodsOption.golden
@@ -46,6 +46,7 @@
 };
 
 static bool RegisterNativesImpl(JNIEnv* env) {
+
   g_Test_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
       base::android::GetClass(env, kTestClassPath).obj()));
 
diff --git a/base/android/jni_generator/testSingleJNIAdditionalImport.golden b/base/android/jni_generator/testSingleJNIAdditionalImport.golden
index 787f7f5..1cf6554 100644
--- a/base/android/jni_generator/testSingleJNIAdditionalImport.golden
+++ b/base/android/jni_generator/testSingleJNIAdditionalImport.golden
@@ -64,6 +64,7 @@
 };
 
 static bool RegisterNativesImpl(JNIEnv* env) {
+
   g_Foo_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
       base::android::GetClass(env, kFooClassPath).obj()));
 
diff --git a/base/android/library_loader/library_loader_hooks.h b/base/android/library_loader/library_loader_hooks.h
index 6203eb0..7e8d527 100644
--- a/base/android/library_loader/library_loader_hooks.h
+++ b/base/android/library_loader/library_loader_hooks.h
@@ -62,7 +62,7 @@
 BASE_EXPORT void LibraryLoaderExitHook();
 
 // Return the process type the shared library is loaded in.
-BASE_EXPORT LibraryProcessType GetLibraryProcesssType();
+BASE_EXPORT LibraryProcessType GetLibraryProcessType(JNIEnv* env);
 
 }  // namespace android
 }  // namespace base
diff --git a/base/base.gyp b/base/base.gyp
index 213e62d..30de275 100644
--- a/base/base.gyp
+++ b/base/base.gyp
@@ -188,6 +188,14 @@
               },
             },
           },
+          'copies': [
+            {
+              'destination': '<(PRODUCT_DIR)/',
+              'files': [
+                '../build/win/dbghelp_xp/dbghelp.dll',
+              ],
+            },
+          ],
         }],
         ['OS == "mac" or (OS == "ios" and _toolset == "host")', {
           'link_settings': {
@@ -645,6 +653,7 @@
         'timer/timer_unittest.cc',
         'tools_sanity_unittest.cc',
         'trace_event/memory_dump_manager_unittest.cc',
+        'trace_event/process_memory_maps_dump_provider_unittest.cc',
         'trace_event/process_memory_totals_dump_provider_unittest.cc',
         'trace_event/trace_event_argument_unittest.cc',
         'trace_event/trace_event_memory_unittest.cc',
@@ -769,6 +778,9 @@
             'message_loop/message_pump_libevent_unittest.cc',
             'threading/worker_pool_posix_unittest.cc',
           ],
+          'dependencies': [
+            'pe_image_test',
+          ],
           # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
           'msvs_disabled_warnings': [
             4267,
@@ -876,6 +888,7 @@
         'base_i18n',
         '../testing/gmock.gyp:gmock',
         '../testing/gtest.gyp:gtest',
+        '../third_party/icu/icu.gyp:icuuc',
         '../third_party/libxml/libxml.gyp:libxml',
         'third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
       ],
@@ -1537,6 +1550,26 @@
             },
           },
         },
+        {
+          'target_name': 'pe_image_test',
+          'type': 'shared_library',
+          'sources': [
+            'win/pe_image_test.cc',
+          ],
+          'msvs_settings': {
+            'VCLinkerTool': {
+              'SubSystem': '2',         # Set /SUBSYSTEM:WINDOWS
+              'DelayLoadDLLs': [
+                'cfgmgr32.dll',
+                'shell32.dll',
+              ],
+              'AdditionalDependencies': [
+                'cfgmgr32.lib',
+                'shell32.lib',
+              ],
+            },
+          },
+        },
       ],
     }],
     ['test_isolation_mode != "noop"', {
diff --git a/base/base.gypi b/base/base.gypi
index b7c33b8..148246f 100644
--- a/base/base.gypi
+++ b/base/base.gypi
@@ -671,6 +671,10 @@
           'trace_event/memory_dump_provider.h',
           'trace_event/process_memory_dump.cc',
           'trace_event/process_memory_dump.h',
+          'trace_event/process_memory_maps.cc',
+          'trace_event/process_memory_maps.h',
+          'trace_event/process_memory_maps_dump_provider.cc',
+          'trace_event/process_memory_maps_dump_provider.h',
           'trace_event/process_memory_totals.cc',
           'trace_event/process_memory_totals.h',
           'trace_event/process_memory_totals_dump_provider.cc',
diff --git a/base/base.isolate b/base/base.isolate
index cb85965..a245819 100644
--- a/base/base.isolate
+++ b/base/base.isolate
@@ -30,6 +30,14 @@
         ],
       },
     }],
+    ['OS=="win"', {
+      # Required for base/stack_trace_win.cc to symbolize correctly.
+      'variables': {
+        'files': [
+          '<(PRODUCT_DIR)/dbghelp.dll',
+        ],
+      },
+    }],
     ['OS=="win" and asan==1 and component=="shared_library"', {
       'variables': {
         'files': [
@@ -53,13 +61,6 @@
         ],
       },
     }],
-    ['lsan==1', {
-      'variables': {
-        'files': [
-          '../tools/lsan/suppressions.txt',
-        ],
-      },
-    }],
     # Copy the VS runtime DLLs into the isolate so that they
     # don't have to be preinstalled on the target machine.
     ['OS=="win" and component=="shared_library" and CONFIGURATION_NAME=="Debug"', {
diff --git a/base/base_unittests.isolate b/base/base_unittests.isolate
index 2e33cc0..e5495e3 100644
--- a/base/base_unittests.isolate
+++ b/base/base_unittests.isolate
@@ -72,6 +72,13 @@
         ],
       },
     }],
+    ['OS=="win"', {
+      'variables': {
+        'files': [
+          '<(PRODUCT_DIR)/pe_image_test.dll',
+        ],
+      },
+    }],
   ],
   'includes': [
     'base.isolate',
diff --git a/base/debug/stack_trace_unittest.cc b/base/debug/stack_trace_unittest.cc
index b07fcdb..15c9093 100644
--- a/base/debug/stack_trace_unittest.cc
+++ b/base/debug/stack_trace_unittest.cc
@@ -148,8 +148,9 @@
 TEST_F(StackTraceTest, AsyncSignalUnsafeSignalHandlerHang) {
   Process child = SpawnChild("MismatchedMallocChildProcess");
   ASSERT_TRUE(child.IsValid());
-  ASSERT_TRUE(WaitForSingleProcess(child.Handle(),
-                                   TestTimeouts::action_timeout()));
+  int exit_code;
+  ASSERT_TRUE(child.WaitForExitWithTimeout(TestTimeouts::action_timeout(),
+                                           &exit_code));
 }
 #endif  // !defined(OS_IOS)
 
diff --git a/base/debug/stack_trace_win.cc b/base/debug/stack_trace_win.cc
index 27661ed..55d5562 100644
--- a/base/debug/stack_trace_win.cc
+++ b/base/debug/stack_trace_win.cc
@@ -152,10 +152,6 @@
 
     init_error_ = ERROR_SUCCESS;
 
-    // Work around a mysterious hang on Windows XP.
-    if (base::win::GetVersion() < base::win::VERSION_VISTA)
-      return;
-
     // When transferring the binaries e.g. between bots, path put
     // into the executable will get off. To still retrieve symbols correctly,
     // add the directory of the executable to symbol search path.
diff --git a/base/files/file_enumerator_win.cc b/base/files/file_enumerator_win.cc
index 6da1667..931d154 100644
--- a/base/files/file_enumerator_win.cc
+++ b/base/files/file_enumerator_win.cc
@@ -147,7 +147,8 @@
         // add it to pending_paths_ so we scan it after we finish scanning this
         // directory. However, don't do recursion through reparse points or we
         // may end up with an infinite cycle.
-        if (!(find_data_.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT))
+        DWORD attributes = GetFileAttributes(cur_file.value().c_str());
+        if (!(attributes & FILE_ATTRIBUTE_REPARSE_POINT))
           pending_paths_.push(cur_file);
       }
       if (file_type_ & FileEnumerator::DIRECTORIES)
diff --git a/base/memory/shared_memory_win.cc b/base/memory/shared_memory_win.cc
index 20659ab..7e0cf0b 100644
--- a/base/memory/shared_memory_win.cc
+++ b/base/memory/shared_memory_win.cc
@@ -144,7 +144,8 @@
                          rand_values[2], rand_values[3]);
   }
   mapped_file_ = CreateFileMapping(INVALID_HANDLE_VALUE, &sa,
-      PAGE_READWRITE, 0, static_cast<DWORD>(rounded_size), name_.c_str());
+      PAGE_READWRITE, 0, static_cast<DWORD>(rounded_size),
+      name_.empty() ? nullptr : name_.c_str());
   if (!mapped_file_)
     return false;
 
diff --git a/base/process/kill.h b/base/process/kill.h
index e8ce334..8c0a213 100644
--- a/base/process/kill.h
+++ b/base/process/kill.h
@@ -119,12 +119,6 @@
     base::TimeDelta wait,
     const ProcessFilter* filter);
 
-// Wait for a single process to exit. Return true if it exited cleanly within
-// the given time limit. On Linux |handle| must be a child process, however
-// on Mac and Windows it can be any process.
-BASE_EXPORT bool WaitForSingleProcess(ProcessHandle handle,
-                                      base::TimeDelta wait);
-
 // Waits a certain amount of time (can be 0) for all the processes with a given
 // executable name to exit, then kills off any of them that are still around.
 // If filter is non-null, then only processes selected by the filter are waited
diff --git a/base/process/kill_posix.cc b/base/process/kill_posix.cc
index 5e8b61f..77705ee 100644
--- a/base/process/kill_posix.cc
+++ b/base/process/kill_posix.cc
@@ -84,6 +84,97 @@
 
   return ret_pid > 0;
 }
+
+#if defined(OS_MACOSX)
+// Using kqueue on Mac so that we can wait on non-child processes.
+// We can't use kqueues on child processes because we need to reap
+// our own children using wait.
+static bool WaitForSingleNonChildProcess(ProcessHandle handle,
+                                         TimeDelta wait) {
+  DCHECK_GT(handle, 0);
+  DCHECK(wait.InMilliseconds() == kNoTimeout || wait > TimeDelta());
+
+  ScopedFD kq(kqueue());
+  if (!kq.is_valid()) {
+    DPLOG(ERROR) << "kqueue";
+    return false;
+  }
+
+  struct kevent change = {0};
+  EV_SET(&change, handle, EVFILT_PROC, EV_ADD, NOTE_EXIT, 0, NULL);
+  int result = HANDLE_EINTR(kevent(kq.get(), &change, 1, NULL, 0, NULL));
+  if (result == -1) {
+    if (errno == ESRCH) {
+      // If the process wasn't found, it must be dead.
+      return true;
+    }
+
+    DPLOG(ERROR) << "kevent (setup " << handle << ")";
+    return false;
+  }
+
+  // Keep track of the elapsed time to be able to restart kevent if it's
+  // interrupted.
+  bool wait_forever = wait.InMilliseconds() == kNoTimeout;
+  TimeDelta remaining_delta;
+  TimeTicks deadline;
+  if (!wait_forever) {
+    remaining_delta = wait;
+    deadline = TimeTicks::Now() + remaining_delta;
+  }
+
+  result = -1;
+  struct kevent event = {0};
+
+  while (wait_forever || remaining_delta > TimeDelta()) {
+    struct timespec remaining_timespec;
+    struct timespec* remaining_timespec_ptr;
+    if (wait_forever) {
+      remaining_timespec_ptr = NULL;
+    } else {
+      remaining_timespec = remaining_delta.ToTimeSpec();
+      remaining_timespec_ptr = &remaining_timespec;
+    }
+
+    result = kevent(kq.get(), NULL, 0, &event, 1, remaining_timespec_ptr);
+
+    if (result == -1 && errno == EINTR) {
+      if (!wait_forever) {
+        remaining_delta = deadline - TimeTicks::Now();
+      }
+      result = 0;
+    } else {
+      break;
+    }
+  }
+
+  if (result < 0) {
+    DPLOG(ERROR) << "kevent (wait " << handle << ")";
+    return false;
+  } else if (result > 1) {
+    DLOG(ERROR) << "kevent (wait " << handle << "): unexpected result "
+                << result;
+    return false;
+  } else if (result == 0) {
+    // Timed out.
+    return false;
+  }
+
+  DCHECK_EQ(result, 1);
+
+  if (event.filter != EVFILT_PROC ||
+      (event.fflags & NOTE_EXIT) == 0 ||
+      event.ident != static_cast<uintptr_t>(handle)) {
+    DLOG(ERROR) << "kevent (wait " << handle
+                << "): unexpected event: filter=" << event.filter
+                << ", fflags=" << event.fflags
+                << ", ident=" << event.ident;
+    return false;
+  }
+
+  return true;
+}
+#endif  // OS_MACOSX
 #endif  // !defined(OS_NACL_NONSFI)
 
 TerminationStatus GetTerminationStatusImpl(ProcessHandle handle,
@@ -230,7 +321,19 @@
 
 bool WaitForExitCodeWithTimeout(ProcessHandle handle,
                                 int* exit_code,
-                                base::TimeDelta timeout) {
+                                TimeDelta timeout) {
+  ProcessHandle parent_pid = GetParentProcessId(handle);
+  ProcessHandle our_pid = GetCurrentProcessHandle();
+  if (parent_pid != our_pid) {
+#if defined(OS_MACOSX)
+    // On Mac we can wait on non child processes.
+    return WaitForSingleNonChildProcess(handle, timeout);
+#else
+    // Currently on Linux we can't handle non child processes.
+    NOTIMPLEMENTED();
+#endif  // OS_MACOSX
+  }
+
   int status;
   if (!WaitpidWithTimeout(handle, &status, timeout))
     return false;
@@ -246,138 +349,28 @@
 }
 
 bool WaitForProcessesToExit(const FilePath::StringType& executable_name,
-                            base::TimeDelta wait,
+                            TimeDelta wait,
                             const ProcessFilter* filter) {
   bool result = false;
 
   // TODO(port): This is inefficient, but works if there are multiple procs.
   // TODO(port): use waitpid to avoid leaving zombies around
 
-  base::TimeTicks end_time = base::TimeTicks::Now() + wait;
+  TimeTicks end_time = TimeTicks::Now() + wait;
   do {
     NamedProcessIterator iter(executable_name, filter);
     if (!iter.NextProcessEntry()) {
       result = true;
       break;
     }
-    base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(100));
-  } while ((end_time - base::TimeTicks::Now()) > base::TimeDelta());
+    PlatformThread::Sleep(TimeDelta::FromMilliseconds(100));
+  } while ((end_time - TimeTicks::Now()) > TimeDelta());
 
   return result;
 }
 
-#if defined(OS_MACOSX)
-// Using kqueue on Mac so that we can wait on non-child processes.
-// We can't use kqueues on child processes because we need to reap
-// our own children using wait.
-static bool WaitForSingleNonChildProcess(ProcessHandle handle,
-                                         base::TimeDelta wait) {
-  DCHECK_GT(handle, 0);
-  DCHECK(wait.InMilliseconds() == base::kNoTimeout || wait > base::TimeDelta());
-
-  ScopedFD kq(kqueue());
-  if (!kq.is_valid()) {
-    DPLOG(ERROR) << "kqueue";
-    return false;
-  }
-
-  struct kevent change = {0};
-  EV_SET(&change, handle, EVFILT_PROC, EV_ADD, NOTE_EXIT, 0, NULL);
-  int result = HANDLE_EINTR(kevent(kq.get(), &change, 1, NULL, 0, NULL));
-  if (result == -1) {
-    if (errno == ESRCH) {
-      // If the process wasn't found, it must be dead.
-      return true;
-    }
-
-    DPLOG(ERROR) << "kevent (setup " << handle << ")";
-    return false;
-  }
-
-  // Keep track of the elapsed time to be able to restart kevent if it's
-  // interrupted.
-  bool wait_forever = wait.InMilliseconds() == base::kNoTimeout;
-  base::TimeDelta remaining_delta;
-  base::TimeTicks deadline;
-  if (!wait_forever) {
-    remaining_delta = wait;
-    deadline = base::TimeTicks::Now() + remaining_delta;
-  }
-
-  result = -1;
-  struct kevent event = {0};
-
-  while (wait_forever || remaining_delta > base::TimeDelta()) {
-    struct timespec remaining_timespec;
-    struct timespec* remaining_timespec_ptr;
-    if (wait_forever) {
-      remaining_timespec_ptr = NULL;
-    } else {
-      remaining_timespec = remaining_delta.ToTimeSpec();
-      remaining_timespec_ptr = &remaining_timespec;
-    }
-
-    result = kevent(kq.get(), NULL, 0, &event, 1, remaining_timespec_ptr);
-
-    if (result == -1 && errno == EINTR) {
-      if (!wait_forever) {
-        remaining_delta = deadline - base::TimeTicks::Now();
-      }
-      result = 0;
-    } else {
-      break;
-    }
-  }
-
-  if (result < 0) {
-    DPLOG(ERROR) << "kevent (wait " << handle << ")";
-    return false;
-  } else if (result > 1) {
-    DLOG(ERROR) << "kevent (wait " << handle << "): unexpected result "
-                << result;
-    return false;
-  } else if (result == 0) {
-    // Timed out.
-    return false;
-  }
-
-  DCHECK_EQ(result, 1);
-
-  if (event.filter != EVFILT_PROC ||
-      (event.fflags & NOTE_EXIT) == 0 ||
-      event.ident != static_cast<uintptr_t>(handle)) {
-    DLOG(ERROR) << "kevent (wait " << handle
-                << "): unexpected event: filter=" << event.filter
-                << ", fflags=" << event.fflags
-                << ", ident=" << event.ident;
-    return false;
-  }
-
-  return true;
-}
-#endif  // OS_MACOSX
-
-bool WaitForSingleProcess(ProcessHandle handle, base::TimeDelta wait) {
-  ProcessHandle parent_pid = GetParentProcessId(handle);
-  ProcessHandle our_pid = GetCurrentProcessHandle();
-  if (parent_pid != our_pid) {
-#if defined(OS_MACOSX)
-    // On Mac we can wait on non child processes.
-    return WaitForSingleNonChildProcess(handle, wait);
-#else
-    // Currently on Linux we can't handle non child processes.
-    NOTIMPLEMENTED();
-#endif  // OS_MACOSX
-  }
-
-  int status;
-  if (!WaitpidWithTimeout(handle, &status, wait))
-    return false;
-  return WIFEXITED(status);
-}
-
 bool CleanupProcesses(const FilePath::StringType& executable_name,
-                      base::TimeDelta wait,
+                      TimeDelta wait,
                       int exit_code,
                       const ProcessFilter* filter) {
   bool exited_cleanly = WaitForProcessesToExit(executable_name, wait, filter);
diff --git a/base/process/kill_win.cc b/base/process/kill_win.cc
index f280c6f..7daf5f8 100644
--- a/base/process/kill_win.cc
+++ b/base/process/kill_win.cc
@@ -189,7 +189,7 @@
 
 bool WaitForExitCodeWithTimeout(ProcessHandle handle,
                                 int* exit_code,
-                                base::TimeDelta timeout) {
+                                TimeDelta timeout) {
   if (::WaitForSingleObject(
       handle, static_cast<DWORD>(timeout.InMilliseconds())) != WAIT_OBJECT_0)
     return false;
@@ -202,7 +202,7 @@
 }
 
 bool WaitForProcessesToExit(const FilePath::StringType& executable_name,
-                            base::TimeDelta wait,
+                            TimeDelta wait,
                             const ProcessFilter* filter) {
   bool result = true;
   DWORD start_time = GetTickCount();
@@ -224,13 +224,8 @@
   return result;
 }
 
-bool WaitForSingleProcess(ProcessHandle handle, base::TimeDelta wait) {
-  int exit_code;
-  return WaitForExitCodeWithTimeout(handle, &exit_code, wait) && exit_code == 0;
-}
-
 bool CleanupProcesses(const FilePath::StringType& executable_name,
-                      base::TimeDelta wait,
+                      TimeDelta wait,
                       int exit_code,
                       const ProcessFilter* filter) {
   if (WaitForProcessesToExit(executable_name, wait, filter))
@@ -249,9 +244,9 @@
 
   MessageLoop::current()->PostDelayedTask(
       FROM_HERE,
-      base::Bind(&TimerExpiredTask::TimedOut,
-                 base::Owned(new TimerExpiredTask(process.Pass()))),
-      base::TimeDelta::FromMilliseconds(kWaitInterval));
+      Bind(&TimerExpiredTask::TimedOut,
+           Owned(new TimerExpiredTask(process.Pass()))),
+      TimeDelta::FromMilliseconds(kWaitInterval));
 }
 
 }  // namespace base
diff --git a/base/process/process.h b/base/process/process.h
index 77d2bce..a834a29 100644
--- a/base/process/process.h
+++ b/base/process/process.h
@@ -98,6 +98,8 @@
 
   // Waits for the process to exit. Returns true on success.
   // On POSIX, if the process has been signaled then |exit_code| is set to -1.
+  // On Linux this must be a child process, however on Mac and Windows it can be
+  // any process.
   bool WaitForExit(int* exit_code);
 
   // Same as WaitForExit() but only waits for up to |timeout|.
diff --git a/base/process/process_unittest.cc b/base/process/process_unittest.cc
index 4ea7a5e..535a36f 100644
--- a/base/process/process_unittest.cc
+++ b/base/process/process_unittest.cc
@@ -124,7 +124,8 @@
   exit_code = kDummyExitCode;
   int kExpectedExitCode = 250;
   process.Terminate(kExpectedExitCode);
-  WaitForSingleProcess(process.Handle(), TestTimeouts::action_max_timeout());
+  process.WaitForExitWithTimeout(TestTimeouts::action_max_timeout(),
+                                 &exit_code);
 
   EXPECT_NE(TERMINATION_STATUS_STILL_RUNNING,
             GetTerminationStatus(process.Handle(), &exit_code));
diff --git a/base/process/process_util_unittest.cc b/base/process/process_util_unittest.cc
index 5ed15d2..11d8874 100644
--- a/base/process/process_util_unittest.cc
+++ b/base/process/process_util_unittest.cc
@@ -151,8 +151,9 @@
 TEST_F(ProcessUtilTest, SpawnChild) {
   base::Process process = SpawnChild("SimpleChildProcess");
   ASSERT_TRUE(process.IsValid());
-  EXPECT_TRUE(base::WaitForSingleProcess(process.Handle(),
-                                         TestTimeouts::action_max_timeout()));
+  int exit_code;
+  EXPECT_TRUE(process.WaitForExitWithTimeout(
+                  TestTimeouts::action_max_timeout(), &exit_code));
 }
 
 MULTIPROCESS_TEST_MAIN(SlowChildProcess) {
@@ -167,8 +168,9 @@
   base::Process process = SpawnChild("SlowChildProcess");
   ASSERT_TRUE(process.IsValid());
   SignalChildren(signal_file.c_str());
-  EXPECT_TRUE(base::WaitForSingleProcess(process.Handle(),
-                                         TestTimeouts::action_max_timeout()));
+  int exit_code;
+  EXPECT_TRUE(process.WaitForExitWithTimeout(
+                  TestTimeouts::action_max_timeout(), &exit_code));
   remove(signal_file.c_str());
 }
 
@@ -550,12 +552,12 @@
 
 #if defined(THREAD_SANITIZER)
   // Compiler-based ThreadSanitizer makes this test slow.
-  CHECK(base::WaitForSingleProcess(process.Handle(),
-                                   base::TimeDelta::FromSeconds(3)));
+  base::TimeDelta timeout = base::TimeDelta::FromSeconds(3);
 #else
-  CHECK(base::WaitForSingleProcess(process.Handle(),
-                                   base::TimeDelta::FromSeconds(1)));
+  base::TimeDelta timeout = base::TimeDelta::FromSeconds(1);
 #endif
+  int exit_code;
+  CHECK(process.WaitForExitWithTimeout(timeout, &exit_code));
   ret = IGNORE_EINTR(close(fds[0]));
   DPCHECK(ret == 0);
 
@@ -891,8 +893,9 @@
   base::Process child_process = SpawnChild("process_util_test_never_die");
   ASSERT_TRUE(child_process.IsValid());
   base::EnsureProcessTerminated(child_process.Duplicate());
-  base::WaitForSingleProcess(child_process.Handle(),
-                             base::TimeDelta::FromSeconds(5));
+  int exit_code;
+  child_process.WaitForExitWithTimeout(base::TimeDelta::FromSeconds(5),
+                                       &exit_code);
 
   // Check that process was really killed.
   EXPECT_TRUE(IsProcessDead(child_process.Handle()));
diff --git a/base/test/BUILD.gn b/base/test/BUILD.gn
index cca72dd..05a3dc3 100644
--- a/base/test/BUILD.gn
+++ b/base/test/BUILD.gn
@@ -116,6 +116,7 @@
     "//testing/gmock",
     "//testing/gtest",
     "//third_party/libxml",
+    "//third_party/icu:icuuc",
   ]
 
   if (!is_posix) {
diff --git a/base/third_party/dynamic_annotations/BUILD.gn b/base/third_party/dynamic_annotations/BUILD.gn
index e52938c..d6a5123 100644
--- a/base/third_party/dynamic_annotations/BUILD.gn
+++ b/base/third_party/dynamic_annotations/BUILD.gn
@@ -2,14 +2,22 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-source_set("dynamic_annotations") {
-  sources = [
-    "../valgrind/valgrind.h",
-    "dynamic_annotations.c",
-    "dynamic_annotations.h",
-  ]
-  if (is_android && !is_debug) {
-    configs -= [ "//build/config/compiler:optimize" ]
-    configs += [ "//build/config/compiler:optimize_max" ]
+if (is_nacl) {
+  # Native client doesn't need dynamic annotations, so we provide a
+  # dummy target in order for clients to not have to special-case the
+  # dependency.
+  group("dynamic_annotations") {
+  }
+} else {
+  source_set("dynamic_annotations") {
+    sources = [
+      "../valgrind/valgrind.h",
+      "dynamic_annotations.c",
+      "dynamic_annotations.h",
+    ]
+    if (is_android && !is_debug) {
+      configs -= [ "//build/config/compiler:optimize" ]
+      configs += [ "//build/config/compiler:optimize_max" ]
+    }
   }
 }
diff --git a/base/time/time.h b/base/time/time.h
index 6d61861..b18c0b2 100644
--- a/base/time/time.h
+++ b/base/time/time.h
@@ -158,34 +158,30 @@
     return TimeDelta(-delta_);
   }
 
-  // Computations with ints, note that we only allow multiplicative operations
-  // with ints, and additive operations with other deltas.
-  TimeDelta operator*(int64 a) const {
+  // Computations with numeric types.
+  template<typename T>
+  TimeDelta operator*(T a) const {
     return TimeDelta(delta_ * a);
   }
-  TimeDelta operator/(int64 a) const {
+  template<typename T>
+  TimeDelta operator/(T a) const {
     return TimeDelta(delta_ / a);
   }
-  TimeDelta& operator*=(int64 a) {
+  template<typename T>
+  TimeDelta& operator*=(T a) {
     delta_ *= a;
     return *this;
   }
-  TimeDelta& operator/=(int64 a) {
+  template<typename T>
+  TimeDelta& operator/=(T a) {
     delta_ /= a;
     return *this;
   }
+
   int64 operator/(TimeDelta a) const {
     return delta_ / a.delta_;
   }
 
-  // Multiplicative computations with floats.
-  TimeDelta multiply_by(double a) const {
-    return TimeDelta(delta_ * a);
-  }
-  TimeDelta divide_by(double a) const {
-    return TimeDelta(delta_ / a);
-  }
-
   // Defined below because it depends on the definition of the other classes.
   Time operator+(Time t) const;
   TimeTicks operator+(TimeTicks t) const;
@@ -213,7 +209,6 @@
  private:
   friend class Time;
   friend class TimeTicks;
-  friend TimeDelta operator*(int64 a, TimeDelta td);
 
   // Constructs a delta given the duration in microseconds. This is private
   // to avoid confusion by callers with an integer constructor. Use
@@ -225,8 +220,9 @@
   int64 delta_;
 };
 
-inline TimeDelta operator*(int64 a, TimeDelta td) {
-  return TimeDelta(a * td.delta_);
+template<typename T>
+inline TimeDelta operator*(T a, TimeDelta td) {
+  return td * a;
 }
 
 // For logging use only.
diff --git a/base/time/time_unittest.cc b/base/time/time_unittest.cc
index 6387ec7..a96787c 100644
--- a/base/time/time_unittest.cc
+++ b/base/time/time_unittest.cc
@@ -868,12 +868,78 @@
 }
 
 
-TEST(TimeDelta, multiply_by) {
+TEST(TimeDelta, NumericOperators) {
   double d = 0.5;
   EXPECT_EQ(TimeDelta::FromMilliseconds(500),
-            TimeDelta::FromMilliseconds(1000).multiply_by(d));
+            TimeDelta::FromMilliseconds(1000) * d);
   EXPECT_EQ(TimeDelta::FromMilliseconds(2000),
-            TimeDelta::FromMilliseconds(1000).divide_by(d));
+            TimeDelta::FromMilliseconds(1000) / d);
+  EXPECT_EQ(TimeDelta::FromMilliseconds(500),
+            TimeDelta::FromMilliseconds(1000) *= d);
+  EXPECT_EQ(TimeDelta::FromMilliseconds(2000),
+            TimeDelta::FromMilliseconds(1000) /= d);
+  EXPECT_EQ(TimeDelta::FromMilliseconds(500),
+            d * TimeDelta::FromMilliseconds(1000));
+
+  float f = 0.5;
+  EXPECT_EQ(TimeDelta::FromMilliseconds(500),
+            TimeDelta::FromMilliseconds(1000) * f);
+  EXPECT_EQ(TimeDelta::FromMilliseconds(2000),
+            TimeDelta::FromMilliseconds(1000) / f);
+  EXPECT_EQ(TimeDelta::FromMilliseconds(500),
+            TimeDelta::FromMilliseconds(1000) *= f);
+  EXPECT_EQ(TimeDelta::FromMilliseconds(2000),
+            TimeDelta::FromMilliseconds(1000) /= f);
+  EXPECT_EQ(TimeDelta::FromMilliseconds(500),
+            f * TimeDelta::FromMilliseconds(1000));
+
+
+  int i = 2;
+  EXPECT_EQ(TimeDelta::FromMilliseconds(2000),
+            TimeDelta::FromMilliseconds(1000) * i);
+  EXPECT_EQ(TimeDelta::FromMilliseconds(500),
+            TimeDelta::FromMilliseconds(1000) / i);
+  EXPECT_EQ(TimeDelta::FromMilliseconds(2000),
+            TimeDelta::FromMilliseconds(1000) *= i);
+  EXPECT_EQ(TimeDelta::FromMilliseconds(500),
+            TimeDelta::FromMilliseconds(1000) /= i);
+  EXPECT_EQ(TimeDelta::FromMilliseconds(2000),
+            i * TimeDelta::FromMilliseconds(1000));
+
+  int64_t i64 = 2;
+  EXPECT_EQ(TimeDelta::FromMilliseconds(2000),
+            TimeDelta::FromMilliseconds(1000) * i64);
+  EXPECT_EQ(TimeDelta::FromMilliseconds(500),
+            TimeDelta::FromMilliseconds(1000) / i64);
+  EXPECT_EQ(TimeDelta::FromMilliseconds(2000),
+            TimeDelta::FromMilliseconds(1000) *= i64);
+  EXPECT_EQ(TimeDelta::FromMilliseconds(500),
+            TimeDelta::FromMilliseconds(1000) /= i64);
+  EXPECT_EQ(TimeDelta::FromMilliseconds(2000),
+            i64 * TimeDelta::FromMilliseconds(1000));
+
+
+  EXPECT_EQ(TimeDelta::FromMilliseconds(500),
+            TimeDelta::FromMilliseconds(1000) * 0.5);
+  EXPECT_EQ(TimeDelta::FromMilliseconds(2000),
+            TimeDelta::FromMilliseconds(1000) / 0.5);
+  EXPECT_EQ(TimeDelta::FromMilliseconds(500),
+            TimeDelta::FromMilliseconds(1000) *= 0.5);
+  EXPECT_EQ(TimeDelta::FromMilliseconds(2000),
+            TimeDelta::FromMilliseconds(1000) /= 0.5);
+  EXPECT_EQ(TimeDelta::FromMilliseconds(500),
+            0.5 * TimeDelta::FromMilliseconds(1000));
+
+  EXPECT_EQ(TimeDelta::FromMilliseconds(2000),
+            TimeDelta::FromMilliseconds(1000) * 2);
+  EXPECT_EQ(TimeDelta::FromMilliseconds(500),
+            TimeDelta::FromMilliseconds(1000) / 2);
+  EXPECT_EQ(TimeDelta::FromMilliseconds(2000),
+            TimeDelta::FromMilliseconds(1000) *= 2);
+  EXPECT_EQ(TimeDelta::FromMilliseconds(500),
+            TimeDelta::FromMilliseconds(1000) /= 2);
+  EXPECT_EQ(TimeDelta::FromMilliseconds(2000),
+            2 * TimeDelta::FromMilliseconds(1000));
 }
 
 TEST(TimeDeltaLogging, DCheckEqCompiles) {
diff --git a/base/trace_event/process_memory_dump.cc b/base/trace_event/process_memory_dump.cc
index 6da9132..5363db5 100644
--- a/base/trace_event/process_memory_dump.cc
+++ b/base/trace_event/process_memory_dump.cc
@@ -10,7 +10,8 @@
 namespace base {
 namespace trace_event {
 
-ProcessMemoryDump::ProcessMemoryDump() : has_process_totals_(false) {
+ProcessMemoryDump::ProcessMemoryDump()
+    : has_process_totals_(false), has_process_mmaps_(false) {
 }
 
 ProcessMemoryDump::~ProcessMemoryDump() {
@@ -23,6 +24,11 @@
     process_totals_.AsValueInto(value);
     value->EndDictionary();
   }
+  if (has_process_mmaps_) {
+    value->BeginDictionary("process_mmaps");
+    process_mmaps_.AsValueInto(value);
+    value->EndDictionary();
+  }
 }
 
 }  // namespace trace_event
diff --git a/base/trace_event/process_memory_dump.h b/base/trace_event/process_memory_dump.h
index f70537b..4256c4c 100644
--- a/base/trace_event/process_memory_dump.h
+++ b/base/trace_event/process_memory_dump.h
@@ -6,6 +6,7 @@
 #define BASE_TRACE_EVENT_PROCESS_MEMORY_DUMP_H_
 
 #include "base/base_export.h"
+#include "base/trace_event/process_memory_maps.h"
 #include "base/trace_event/process_memory_totals.h"
 
 namespace base {
@@ -31,10 +32,17 @@
   bool has_process_totals() const { return has_process_totals_; }
   void set_has_process_totals() { has_process_totals_ = true; }
 
+  ProcessMemoryMaps* process_mmaps() { return &process_mmaps_; }
+  bool has_process_mmaps() const { return has_process_mmaps_; }
+  void set_has_process_mmaps() { has_process_mmaps_ = true; }
+
  private:
   ProcessMemoryTotals process_totals_;
   bool has_process_totals_;
 
+  ProcessMemoryMaps process_mmaps_;
+  bool has_process_mmaps_;
+
   DISALLOW_COPY_AND_ASSIGN(ProcessMemoryDump);
 };
 
diff --git a/base/trace_event/process_memory_maps.cc b/base/trace_event/process_memory_maps.cc
new file mode 100644
index 0000000..bf3c5a0
--- /dev/null
+++ b/base/trace_event/process_memory_maps.cc
@@ -0,0 +1,45 @@
+// Copyright 2015 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.
+
+#include "base/trace_event/process_memory_maps.h"
+
+#include "base/trace_event/trace_event_argument.h"
+
+namespace base {
+namespace trace_event {
+
+// static
+const uint32 ProcessMemoryMaps::VMRegion::kProtectionFlagsRead = 4;
+const uint32 ProcessMemoryMaps::VMRegion::kProtectionFlagsWrite = 2;
+const uint32 ProcessMemoryMaps::VMRegion::kProtectionFlagsExec = 1;
+
+ProcessMemoryMaps::ProcessMemoryMaps() {
+}
+
+ProcessMemoryMaps::~ProcessMemoryMaps() {
+}
+
+void ProcessMemoryMaps::AsValueInto(TracedValue* value) const {
+  value->BeginArray("vm_regions");
+  for (const auto& region : vm_regions_) {
+    value->BeginDictionary();
+
+    value->SetDouble("start_address", region.start_address);
+    value->SetDouble("size_in_bytes", region.size_in_bytes);
+    value->SetInteger("protection_flags", region.protection_flags);
+    value->SetString("mapped_file", region.mapped_file);
+    value->SetDouble("mapped_file_offset", region.mapped_file_offset);
+
+    value->BeginDictionary("byte_stats");
+    value->SetDouble("resident", region.byte_stats_resident);
+    value->SetDouble("anonymous", region.byte_stats_anonymous);
+    value->EndDictionary();
+
+    value->EndDictionary();
+  }
+  value->EndArray();
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/base/trace_event/process_memory_maps.h b/base/trace_event/process_memory_maps.h
new file mode 100644
index 0000000..70f6610
--- /dev/null
+++ b/base/trace_event/process_memory_maps.h
@@ -0,0 +1,54 @@
+// Copyright 2015 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.
+
+#ifndef BASE_TRACE_EVENT_PROCESS_MEMORY_MAPS_H_
+#define BASE_TRACE_EVENT_PROCESS_MEMORY_MAPS_H_
+
+#include <string>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+
+namespace base {
+namespace trace_event {
+
+class TracedValue;
+
+// Data model for process-wide memory stats.
+class BASE_EXPORT ProcessMemoryMaps {
+ public:
+  struct VMRegion {
+    static const uint32 kProtectionFlagsRead;
+    static const uint32 kProtectionFlagsWrite;
+    static const uint32 kProtectionFlagsExec;
+
+    uint64 start_address;
+    uint64 size_in_bytes;
+    uint32 protection_flags;
+    std::string mapped_file;
+    uint64 mapped_file_offset;
+    uint64 byte_stats_resident;
+    uint64 byte_stats_anonymous;
+  };
+
+  ProcessMemoryMaps();
+  ~ProcessMemoryMaps();
+
+  void AddVMRegion(const VMRegion& region) { vm_regions_.push_back(region); }
+  const std::vector<VMRegion>& vm_regions() const { return vm_regions_; }
+
+  // Called at trace generation time to populate the TracedValue.
+  void AsValueInto(TracedValue* value) const;
+
+ private:
+  std::vector<VMRegion> vm_regions_;
+
+  DISALLOW_COPY_AND_ASSIGN(ProcessMemoryMaps);
+};
+
+}  // namespace trace_event
+}  // namespace base
+
+#endif  // BASE_TRACE_EVENT_PROCESS_MEMORY_MAPS_H_
diff --git a/base/trace_event/process_memory_maps_dump_provider.cc b/base/trace_event/process_memory_maps_dump_provider.cc
new file mode 100644
index 0000000..e1cefc3
--- /dev/null
+++ b/base/trace_event/process_memory_maps_dump_provider.cc
@@ -0,0 +1,176 @@
+// Copyright 2015 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.
+
+#include "base/trace_event/process_memory_maps_dump_provider.h"
+
+#include <cctype>
+#include <fstream>
+
+#include "base/logging.h"
+#include "base/process/process_metrics.h"
+#include "base/trace_event/process_memory_dump.h"
+#include "base/trace_event/process_memory_maps.h"
+
+namespace base {
+namespace trace_event {
+
+#if defined(OS_LINUX) || defined(OS_ANDROID)
+// static
+std::istream* ProcessMemoryMapsDumpProvider::proc_smaps_for_testing = nullptr;
+
+namespace {
+
+const uint32 kMaxLineSize = 4096;
+
+bool ParseSmapsHeader(std::istream* smaps,
+                      ProcessMemoryMaps::VMRegion* region) {
+  // e.g., "00400000-00421000 r-xp 00000000 fc:01 1234  /foo.so\n"
+  bool res = true;  // Whether this region should be appended or skipped.
+  uint64 end_addr;
+  std::string protection_flags;
+  std::string ignored;
+  *smaps >> std::hex >> region->start_address;
+  smaps->ignore(1);
+  *smaps >> std::hex >> end_addr;
+  if (end_addr > region->start_address) {
+    region->size_in_bytes = end_addr - region->start_address;
+  } else {
+    // This is not just paranoia, it can actually happen (See crbug.com/461237).
+    region->size_in_bytes = 0;
+    res = false;
+  }
+
+  region->protection_flags = 0;
+  *smaps >> protection_flags;
+  CHECK(4UL == protection_flags.size());
+  if (protection_flags[0] == 'r') {
+    region->protection_flags |=
+        ProcessMemoryMaps::VMRegion::kProtectionFlagsRead;
+  }
+  if (protection_flags[1] == 'w') {
+    region->protection_flags |=
+        ProcessMemoryMaps::VMRegion::kProtectionFlagsWrite;
+  }
+  if (protection_flags[2] == 'x') {
+    region->protection_flags |=
+        ProcessMemoryMaps::VMRegion::kProtectionFlagsExec;
+  }
+  *smaps >> std::hex >> region->mapped_file_offset;
+  *smaps >> ignored;  // Ignore device maj-min (fc:01 in the example above).
+  *smaps >> ignored;  // Ignore inode number (1234 in the example above).
+
+  while (smaps->peek() == ' ')
+    smaps->ignore(1);
+  char mapped_file[kMaxLineSize];
+  smaps->getline(mapped_file, sizeof(mapped_file));
+  region->mapped_file = mapped_file;
+
+  return res;
+}
+
+uint32 ParseSmapsCounter(std::istream* smaps,
+                         ProcessMemoryMaps::VMRegion* region) {
+  // e.g., "RSS:  0 Kb\n"
+  uint32 res = 0;
+  std::string counter_name;
+  *smaps >> counter_name;
+
+  // TODO(primiano): "Swap" should also be accounted as resident. Check
+  // whether Rss isn't already counting swapped and fix below if that is
+  // the case.
+  if (counter_name == "Rss:") {
+    *smaps >> std::dec >> region->byte_stats_resident;
+    region->byte_stats_resident *= 1024;
+    res = 1;
+  } else if (counter_name == "Anonymous:") {
+    *smaps >> std::dec >> region->byte_stats_anonymous;
+    region->byte_stats_anonymous *= 1024;
+    res = 1;
+  }
+
+#ifndef NDEBUG
+  // Paranoid check against changes of the Kernel /proc interface.
+  if (res) {
+    std::string unit;
+    *smaps >> unit;
+    DCHECK_EQ("kB", unit);
+  }
+#endif
+
+  smaps->ignore(kMaxLineSize, '\n');
+
+  return res;
+}
+
+uint32 ReadLinuxProcSmapsFile(std::istream* smaps, ProcessMemoryMaps* pmm) {
+  if (!smaps->good()) {
+    LOG(ERROR) << "Could not read smaps file.";
+    return 0;
+  }
+  const uint32 kNumExpectedCountersPerRegion = 2;
+  uint32 counters_parsed_for_current_region = 0;
+  uint32 num_valid_regions = 0;
+  ProcessMemoryMaps::VMRegion region;
+  bool should_add_current_region = false;
+  for (;;) {
+    int next = smaps->peek();
+    if (next == std::ifstream::traits_type::eof() || next == '\n')
+      break;
+    if (isxdigit(next) && !isupper(next)) {
+      region = {0};
+      counters_parsed_for_current_region = 0;
+      should_add_current_region = ParseSmapsHeader(smaps, &region);
+    } else {
+      counters_parsed_for_current_region += ParseSmapsCounter(smaps, &region);
+      DCHECK_LE(counters_parsed_for_current_region,
+                kNumExpectedCountersPerRegion);
+      if (counters_parsed_for_current_region == kNumExpectedCountersPerRegion) {
+        if (should_add_current_region) {
+          pmm->AddVMRegion(region);
+          ++num_valid_regions;
+          should_add_current_region = false;
+        }
+      }
+    }
+  }
+  return num_valid_regions;
+}
+
+}  // namespace
+#endif  // defined(OS_LINUX) || defined(OS_ANDROID)
+
+// static
+ProcessMemoryMapsDumpProvider* ProcessMemoryMapsDumpProvider::GetInstance() {
+  return Singleton<ProcessMemoryMapsDumpProvider,
+                   LeakySingletonTraits<ProcessMemoryMapsDumpProvider>>::get();
+}
+
+ProcessMemoryMapsDumpProvider::ProcessMemoryMapsDumpProvider() {
+}
+
+ProcessMemoryMapsDumpProvider::~ProcessMemoryMapsDumpProvider() {
+}
+
+// Called at trace dump point time. Creates a snapshot the memory maps for the
+// current process.
+void ProcessMemoryMapsDumpProvider::DumpInto(ProcessMemoryDump* pmd) {
+  uint32 res = 0;
+
+#if defined(OS_LINUX) || defined(OS_ANDROID)
+  if (UNLIKELY(proc_smaps_for_testing)) {
+    res = ReadLinuxProcSmapsFile(proc_smaps_for_testing, pmd->process_mmaps());
+  } else {
+    std::ifstream proc_self_smaps("/proc/self/smaps");
+    res = ReadLinuxProcSmapsFile(&proc_self_smaps, pmd->process_mmaps());
+  }
+#else
+  LOG(ERROR) << "ProcessMemoryMaps dump provider is supported only on Linux";
+#endif
+
+  if (res > 0)
+    pmd->set_has_process_mmaps();
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/base/trace_event/process_memory_maps_dump_provider.h b/base/trace_event/process_memory_maps_dump_provider.h
new file mode 100644
index 0000000..543f7fd
--- /dev/null
+++ b/base/trace_event/process_memory_maps_dump_provider.h
@@ -0,0 +1,42 @@
+// Copyright 2015 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.
+
+#ifndef BASE_TRACE_EVENT_PROCESS_MEMORY_MAPS_DUMP_PROVIDER_H_
+#define BASE_TRACE_EVENT_PROCESS_MEMORY_MAPS_DUMP_PROVIDER_H_
+
+#include <istream>
+
+#include "base/gtest_prod_util.h"
+#include "base/memory/singleton.h"
+#include "base/trace_event/memory_dump_provider.h"
+
+namespace base {
+namespace trace_event {
+
+// Dump provider which collects process-wide memory stats.
+class BASE_EXPORT ProcessMemoryMapsDumpProvider : public MemoryDumpProvider {
+ public:
+  static ProcessMemoryMapsDumpProvider* GetInstance();
+
+  // MemoryDumpProvider implementation.
+  void DumpInto(ProcessMemoryDump* pmd) override;
+
+ private:
+  friend struct DefaultSingletonTraits<ProcessMemoryMapsDumpProvider>;
+  FRIEND_TEST_ALL_PREFIXES(ProcessMemoryMapsDumpProviderTest, ParseProcSmaps);
+
+#if defined(OS_LINUX) || defined(OS_ANDROID)
+  static std::istream* proc_smaps_for_testing;
+#endif
+
+  ProcessMemoryMapsDumpProvider();
+  ~ProcessMemoryMapsDumpProvider() override;
+
+  DISALLOW_COPY_AND_ASSIGN(ProcessMemoryMapsDumpProvider);
+};
+
+}  // namespace trace_event
+}  // namespace base
+
+#endif  // BASE_TRACE_EVENT_PROCESS_MEMORY_MAPS_DUMP_PROVIDER_H_
diff --git a/base/trace_event/process_memory_maps_dump_provider_unittest.cc b/base/trace_event/process_memory_maps_dump_provider_unittest.cc
new file mode 100644
index 0000000..02fd136
--- /dev/null
+++ b/base/trace_event/process_memory_maps_dump_provider_unittest.cc
@@ -0,0 +1,175 @@
+// Copyright 2015 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.
+
+#include "base/trace_event/process_memory_maps_dump_provider.h"
+
+#include <fstream>
+#include <sstream>
+
+#include "base/trace_event/process_memory_dump.h"
+#include "base/trace_event/process_memory_maps.h"
+#include "base/trace_event/trace_event_argument.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace trace_event {
+
+#if defined(OS_LINUX) || defined(OS_ANDROID)
+namespace {
+const char kTestSmaps1[] =
+    "00400000-004be000 r-xp 00000000 fc:01 1234              /file/1\n"
+    "Size:                760 kB\n"
+    "Rss:                 296 kB\n"
+    "Pss:                 162 kB\n"
+    "Shared_Clean:        228 kB\n"
+    "Shared_Dirty:          0 kB\n"
+    "Private_Clean:         0 kB\n"
+    "Private_Dirty:        68 kB\n"
+    "Referenced:          296 kB\n"
+    "Anonymous:            68 kB\n"
+    "AnonHugePages:         0 kB\n"
+    "Swap:                  0 kB\n"
+    "KernelPageSize:        4 kB\n"
+    "MMUPageSize:           4 kB\n"
+    "Locked:                0 kB\n"
+    "VmFlags: rd ex mr mw me dw sd\n"
+    "ff000000-ff800000 -w-p 00001080 fc:01 0            /file/name with space\n"
+    "Size:                  0 kB\n"
+    "Rss:                 128 kB\n"
+    "Pss:                 128 kB\n"
+    "Shared_Clean:        124 kB\n"
+    "Shared_Dirty:          0 kB\n"
+    "Private_Clean:        68 kB\n"
+    "Private_Dirty:         0 kB\n"
+    "Referenced:          296 kB\n"
+    "Anonymous:             0 kB\n"
+    "AnonHugePages:         0 kB\n"
+    "Swap:                  0 kB\n"
+    "KernelPageSize:        4 kB\n"
+    "MMUPageSize:           4 kB\n"
+    "Locked:                0 kB\n"
+    "VmFlags: rd ex mr mw me dw sd";
+
+const char kTestSmaps2[] =
+    // An invalid region, with zero size and overlapping with the last one
+    // (See crbug.com/461237).
+    "7fe7ce79c000-7fe7ce79c000 ---p 00000000 00:00 0 \n"
+    "Size:                  4 kB\n"
+    "Rss:                   0 kB\n"
+    "Pss:                   0 kB\n"
+    "Shared_Clean:          0 kB\n"
+    "Shared_Dirty:          0 kB\n"
+    "Private_Clean:         0 kB\n"
+    "Private_Dirty:         0 kB\n"
+    "Referenced:            0 kB\n"
+    "Anonymous:             0 kB\n"
+    "AnonHugePages:         0 kB\n"
+    "Swap:                  0 kB\n"
+    "KernelPageSize:        4 kB\n"
+    "MMUPageSize:           4 kB\n"
+    "Locked:                0 kB\n"
+    "VmFlags: rd ex mr mw me dw sd\n"
+    // A invalid region with its range going backwards.
+    "00400000-00200000 ---p 00000000 00:00 0 \n"
+    "Size:                  4 kB\n"
+    "Rss:                   0 kB\n"
+    "Pss:                   0 kB\n"
+    "Shared_Clean:          0 kB\n"
+    "Shared_Dirty:          0 kB\n"
+    "Private_Clean:         0 kB\n"
+    "Private_Dirty:         0 kB\n"
+    "Referenced:            0 kB\n"
+    "Anonymous:             0 kB\n"
+    "AnonHugePages:         0 kB\n"
+    "Swap:                  0 kB\n"
+    "KernelPageSize:        4 kB\n"
+    "MMUPageSize:           4 kB\n"
+    "Locked:                0 kB\n"
+    "VmFlags: rd ex mr mw me dw sd\n"
+    // A good anonymous region at the end.
+    "7fe7ce79c000-7fe7ce7a8000 ---p 00000000 00:00 0 \n"
+    "Size:                 48 kB\n"
+    "Rss:                  40 kB\n"
+    "Pss:                   0 kB\n"
+    "Shared_Clean:         16 kB\n"
+    "Shared_Dirty:         12 kB\n"
+    "Private_Clean:         8 kB\n"
+    "Private_Dirty:         4 kB\n"
+    "Referenced:           40 kB\n"
+    "Anonymous:            16 kB\n"
+    "AnonHugePages:         0 kB\n"
+    "Swap:                  0 kB\n"
+    "KernelPageSize:        4 kB\n"
+    "MMUPageSize:           4 kB\n"
+    "Locked:                0 kB\n"
+    "VmFlags: rd wr mr mw me ac sd\n";
+}  // namespace
+
+TEST(ProcessMemoryMapsDumpProviderTest, ParseProcSmaps) {
+  const uint32 kProtR = ProcessMemoryMaps::VMRegion::kProtectionFlagsRead;
+  const uint32 kProtW = ProcessMemoryMaps::VMRegion::kProtectionFlagsWrite;
+  const uint32 kProtX = ProcessMemoryMaps::VMRegion::kProtectionFlagsExec;
+
+  auto pmmdp = ProcessMemoryMapsDumpProvider::GetInstance();
+
+  // Emulate a non-existent /proc/self/smaps.
+  ProcessMemoryDump pmd_invalid;
+  std::ifstream non_existent_file("/tmp/does-not-exist");
+  ProcessMemoryMapsDumpProvider::proc_smaps_for_testing = &non_existent_file;
+  CHECK_EQ(false, non_existent_file.good());
+  pmmdp->DumpInto(&pmd_invalid);
+  ASSERT_FALSE(pmd_invalid.has_process_mmaps());
+
+  // Emulate an empty /proc/self/smaps.
+  std::ifstream empty_file("/dev/null");
+  ProcessMemoryMapsDumpProvider::proc_smaps_for_testing = &empty_file;
+  CHECK_EQ(true, empty_file.good());
+  pmmdp->DumpInto(&pmd_invalid);
+  ASSERT_FALSE(pmd_invalid.has_process_mmaps());
+
+  // Parse the 1st smaps file.
+  ProcessMemoryDump pmd_1;
+  std::istringstream test_smaps_1(kTestSmaps1);
+  ProcessMemoryMapsDumpProvider::proc_smaps_for_testing = &test_smaps_1;
+  pmmdp->DumpInto(&pmd_1);
+  ASSERT_TRUE(pmd_1.has_process_mmaps());
+  const auto& regions_1 = pmd_1.process_mmaps()->vm_regions();
+  ASSERT_EQ(2UL, regions_1.size());
+
+  EXPECT_EQ(0x00400000UL, regions_1[0].start_address);
+  EXPECT_EQ(0x004be000UL - 0x00400000UL, regions_1[0].size_in_bytes);
+  EXPECT_EQ(kProtR | kProtX, regions_1[0].protection_flags);
+  EXPECT_EQ("/file/1", regions_1[0].mapped_file);
+  EXPECT_EQ(0UL, regions_1[0].mapped_file_offset);
+  EXPECT_EQ(296 * 1024UL, regions_1[0].byte_stats_resident);
+  EXPECT_EQ(68 * 1024UL, regions_1[0].byte_stats_anonymous);
+
+  EXPECT_EQ(0xff000000UL, regions_1[1].start_address);
+  EXPECT_EQ(0xff800000UL - 0xff000000UL, regions_1[1].size_in_bytes);
+  EXPECT_EQ(kProtW, regions_1[1].protection_flags);
+  EXPECT_EQ("/file/name with space", regions_1[1].mapped_file);
+  EXPECT_EQ(0x00001080UL, regions_1[1].mapped_file_offset);
+  EXPECT_EQ(128 * 1024UL, regions_1[1].byte_stats_resident);
+  EXPECT_EQ(0UL, regions_1[1].byte_stats_anonymous);
+
+  // Parse the 2nd smaps file.
+  ProcessMemoryDump pmd_2;
+  std::istringstream test_smaps_2(kTestSmaps2);
+  ProcessMemoryMapsDumpProvider::proc_smaps_for_testing = &test_smaps_2;
+  pmmdp->DumpInto(&pmd_2);
+  ASSERT_TRUE(pmd_2.has_process_mmaps());
+  const auto& regions_2 = pmd_2.process_mmaps()->vm_regions();
+  ASSERT_EQ(1UL, regions_2.size());
+  EXPECT_EQ(0x7fe7ce79c000UL, regions_2[0].start_address);
+  EXPECT_EQ(0x7fe7ce7a8000UL - 0x7fe7ce79c000UL, regions_2[0].size_in_bytes);
+  EXPECT_EQ(0U, regions_2[0].protection_flags);
+  EXPECT_EQ("", regions_2[0].mapped_file);
+  EXPECT_EQ(0UL, regions_2[0].mapped_file_offset);
+  EXPECT_EQ(40 * 1024UL, regions_2[0].byte_stats_resident);
+  EXPECT_EQ(16 * 1024UL, regions_2[0].byte_stats_anonymous);
+}
+#endif  // defined(OS_LINUX) || defined(OS_ANDROID)
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/base/trace_event/trace_event.h b/base/trace_event/trace_event.h
index 07a2afa..e12d8f4 100644
--- a/base/trace_event/trace_event.h
+++ b/base/trace_event/trace_event.h
@@ -1008,7 +1008,8 @@
             phase, INTERNAL_TRACE_EVENT_UID(category_group_enabled), \
             name, trace_event_trace_id.data(), \
             thread_id, base::TimeTicks::FromInternalValue(timestamp), \
-            trace_event_flags, ##__VA_ARGS__); \
+            trace_event_flags | TRACE_EVENT_FLAG_EXPLICIT_TIMESTAMP, \
+            ##__VA_ARGS__); \
       } \
     } while (0)
 
@@ -1045,9 +1046,11 @@
 #define TRACE_EVENT_FLAG_HAS_ID       (static_cast<unsigned char>(1 << 1))
 #define TRACE_EVENT_FLAG_MANGLE_ID    (static_cast<unsigned char>(1 << 2))
 #define TRACE_EVENT_FLAG_SCOPE_OFFSET (static_cast<unsigned char>(1 << 3))
+#define TRACE_EVENT_FLAG_SCOPE_EXTRA  (static_cast<unsigned char>(1 << 4))
+#define TRACE_EVENT_FLAG_EXPLICIT_TIMESTAMP (static_cast<unsigned char>(1 << 5))
 
 #define TRACE_EVENT_FLAG_SCOPE_MASK   (static_cast<unsigned char>( \
-    TRACE_EVENT_FLAG_SCOPE_OFFSET | (TRACE_EVENT_FLAG_SCOPE_OFFSET << 1)))
+    TRACE_EVENT_FLAG_SCOPE_OFFSET | TRACE_EVENT_FLAG_SCOPE_EXTRA))
 
 // Type values for identifying types in the TraceValue union.
 #define TRACE_VALUE_TYPE_BOOL         (static_cast<unsigned char>(1))
diff --git a/base/trace_event/trace_event_impl.cc b/base/trace_event/trace_event_impl.cc
index 9ca0ddc..445cb6d 100644
--- a/base/trace_event/trace_event_impl.cc
+++ b/base/trace_event/trace_event_impl.cc
@@ -1914,7 +1914,8 @@
     id ^= process_id_hash_;
 
   TimeTicks offset_event_timestamp = OffsetTimestamp(timestamp);
-  TimeTicks now = OffsetNow();
+  TimeTicks now = flags & TRACE_EVENT_FLAG_EXPLICIT_TIMESTAMP ?
+      OffsetNow() : offset_event_timestamp;
   TimeTicks thread_now = ThreadNow();
 
   ThreadLocalEventBuffer* thread_local_event_buffer = NULL;
@@ -2035,9 +2036,6 @@
     }
   }
 
-  // Use |now| instead of |offset_event_timestamp| to compute overhead, because
-  // event timestamp may be not the real time that we started to add the event
-  // (e.g. event with zero timestamp or that was generated some time ago).
   if (thread_local_event_buffer)
     thread_local_event_buffer->ReportOverhead(now, thread_now);
 
diff --git a/base/win/pe_image_test.cc b/base/win/pe_image_test.cc
new file mode 100644
index 0000000..e374598
--- /dev/null
+++ b/base/win/pe_image_test.cc
@@ -0,0 +1,31 @@
+// Copyright 2015 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.
+
+#include <windows.h>
+
+#include <cfgmgr32.h>
+#include <shellapi.h>
+
+extern "C" {
+
+__declspec(dllexport) void ExportFunc1() {
+  // Call into user32.dll.
+  HWND dummy = GetDesktopWindow();
+  SetWindowTextA(dummy, "dummy");
+}
+
+__declspec(dllexport) void ExportFunc2() {
+  // Call into cfgmgr32.dll.
+  CM_MapCrToWin32Err(CR_SUCCESS, ERROR_SUCCESS);
+
+  // Call into shell32.dll.
+  SHFILEOPSTRUCT file_operation = {0};
+  SHFileOperation(&file_operation);
+
+  // Call into kernel32.dll.
+  HANDLE h = CreateEvent(NULL, FALSE, FALSE, NULL);
+  CloseHandle(h);
+}
+
+}  // extern "C"
diff --git a/base/win/pe_image_unittest.cc b/base/win/pe_image_unittest.cc
index af4209b..4134741 100644
--- a/base/win/pe_image_unittest.cc
+++ b/base/win/pe_image_unittest.cc
@@ -3,29 +3,140 @@
 // found in the LICENSE file.
 
 // This file contains unit tests for PEImage.
+#include <algorithm>
+#include <vector>
 
 #include "testing/gtest/include/gtest/gtest.h"
 #include "base/win/pe_image.h"
 #include "base/win/windows_version.h"
 
+namespace {
+
+class Expectations {
+ public:
+  enum Value {
+    SECTIONS = 0,
+    IMPORTS_DLLS,
+    DELAY_DLLS,
+    EXPORTS,
+    IMPORTS,
+    DELAY_IMPORTS,
+    RELOCS
+  };
+
+  enum Arch {
+    ARCH_X86 = 0,
+    ARCH_X64,
+    ARCH_ALL
+  };
+
+  Expectations();
+
+  void SetDefault(Value value, int count);
+  void SetOverride(Value value, base::win::Version version,
+                   Arch arch, int count);
+  void SetOverride(Value value, base::win::Version version, int count);
+  void SetOverride(Value value, Arch arch, int count);
+
+  // returns -1 on failure.
+  int GetExpectation(Value value);
+
+ private:
+  class Override {
+   public:
+    enum MatchType { MATCH_VERSION, MATCH_ARCH, MATCH_BOTH, MATCH_NONE };
+
+    Override(Value value, base::win::Version version, Arch arch, int count)
+      : value_(value), version_(version), arch_(arch), count_(count) {
+    };
+
+    bool Matches(Value value, base::win::Version version,
+                 Arch arch, MatchType type) {
+      if (value_ != value)
+        return false;
+
+      switch (type) {
+        case MATCH_BOTH:
+          return (arch == arch_ && version == version_);
+        case MATCH_ARCH:
+          return (arch == arch_ && version_ == base::win::VERSION_WIN_LAST);
+        case MATCH_VERSION:
+          return (arch_ == ARCH_ALL && version == version_);
+        case MATCH_NONE:
+          return (arch_ == ARCH_ALL && version_ == base::win::VERSION_WIN_LAST);
+      }
+      return false;
+    }
+
+    int GetCount() { return count_; }
+
+   private:
+    Value value_;
+    base::win::Version version_;
+    Arch arch_;
+    int count_;
+  };
+
+  bool MatchesMyArch(Arch arch);
+
+  std::vector<Override> overrides_;
+  Arch my_arch_;
+  base::win::Version my_version_;
+};
+
+Expectations::Expectations() {
+  my_version_ = base::win::GetVersion();
+#if defined(ARCH_CPU_64_BITS)
+  my_arch_ = ARCH_X64;
+#else
+  my_arch_ = ARCH_X86;
+#endif
+}
+
+int Expectations::GetExpectation(Value value) {
+  // Prefer OS version specificity over Arch specificity.
+  for (auto type : { Override::MATCH_BOTH,
+                     Override::MATCH_VERSION,
+                     Override::MATCH_ARCH,
+                     Override::MATCH_NONE }) {
+    for (auto override : overrides_) {
+      if (override.Matches(value, my_version_, my_arch_, type))
+        return override.GetCount();
+    }
+  }
+  return -1;
+}
+
+void Expectations::SetDefault(Value value, int count) {
+  SetOverride(value, base::win::VERSION_WIN_LAST, ARCH_ALL, count);
+}
+
+void Expectations::SetOverride(Value value,
+                               base::win::Version version,
+                               Arch arch,
+                               int count) {
+  overrides_.push_back(Override(value, version, arch, count));
+}
+
+void Expectations::SetOverride(Value value,
+                               base::win::Version version,
+                               int count) {
+  SetOverride(value, version, ARCH_ALL, count);
+}
+
+void Expectations::SetOverride(Value value, Arch arch, int count) {
+  SetOverride(value, base::win::VERSION_WIN_LAST, arch, count);
+}
+
+}  // namespace
+
 namespace base {
 namespace win {
 
-// Just counts the number of invocations.
-bool ExportsCallback(const PEImage &image,
-                     DWORD ordinal,
-                     DWORD hint,
-                     LPCSTR name,
-                     PVOID function,
-                     LPCSTR forward,
-                     PVOID cookie) {
-  int* count = reinterpret_cast<int*>(cookie);
-  (*count)++;
-  return true;
-}
+namespace {
 
 // Just counts the number of invocations.
-bool ImportsCallback(const PEImage &image,
+bool ImportsCallback(const PEImage& image,
                      LPCSTR module,
                      DWORD ordinal,
                      LPCSTR name,
@@ -38,18 +149,18 @@
 }
 
 // Just counts the number of invocations.
-bool SectionsCallback(const PEImage &image,
-                       PIMAGE_SECTION_HEADER header,
-                       PVOID section_start,
-                       DWORD section_size,
-                       PVOID cookie) {
+bool SectionsCallback(const PEImage& image,
+                      PIMAGE_SECTION_HEADER header,
+                      PVOID section_start,
+                      DWORD section_size,
+                      PVOID cookie) {
   int* count = reinterpret_cast<int*>(cookie);
   (*count)++;
   return true;
 }
 
 // Just counts the number of invocations.
-bool RelocsCallback(const PEImage &image,
+bool RelocsCallback(const PEImage& image,
                     WORD type,
                     PVOID address,
                     PVOID cookie) {
@@ -59,7 +170,7 @@
 }
 
 // Just counts the number of invocations.
-bool ImportChunksCallback(const PEImage &image,
+bool ImportChunksCallback(const PEImage& image,
                           LPCSTR module,
                           PIMAGE_THUNK_DATA name_table,
                           PIMAGE_THUNK_DATA iat,
@@ -70,7 +181,7 @@
 }
 
 // Just counts the number of invocations.
-bool DelayImportChunksCallback(const PEImage &image,
+bool DelayImportChunksCallback(const PEImage& image,
                                PImgDelayDescr delay_descriptor,
                                LPCSTR module,
                                PIMAGE_THUNK_DATA name_table,
@@ -83,167 +194,89 @@
   return true;
 }
 
-// Identifiers for the set of supported expectations.
-enum ExpectationSet {
-  WIN_2K_SET,
-  WIN_XP_SET,
-  WIN_VISTA_SET,
-  WIN_7_SET,
-  WIN_8_SET,
-  UNSUPPORTED_SET,
-};
-
-// We'll be using some known values for the tests.
-enum Value {
-  sections = 0,
-  imports_dlls,
-  delay_dlls,
-  exports,
-  imports,
-  delay_imports,
-  relocs
-};
-
-ExpectationSet GetExpectationSet(DWORD os) {
-  if (os == 50)
-    return WIN_2K_SET;
-  if (os == 51)
-    return WIN_XP_SET;
-  if (os == 60)
-    return WIN_VISTA_SET;
-  if (os == 61)
-    return WIN_7_SET;
-  if (os >= 62)
-    return WIN_8_SET;
-  return UNSUPPORTED_SET;
+// Just counts the number of invocations.
+bool ExportsCallback(const PEImage& image,
+                     DWORD ordinal,
+                     DWORD hint,
+                     LPCSTR name,
+                     PVOID function,
+                     LPCSTR forward,
+                     PVOID cookie) {
+  int* count = reinterpret_cast<int*>(cookie);
+  (*count)++;
+  return true;
 }
 
-// Retrieves the expected value from advapi32.dll based on the OS.
-int GetExpectedValue(Value value, DWORD os) {
-  const int xp_delay_dlls = 2;
-  const int xp_exports = 675;
-  const int xp_imports = 422;
-  const int xp_delay_imports = 8;
-  const int xp_relocs = 9180;
-  const int vista_delay_dlls = 4;
-  const int vista_exports = 799;
-  const int vista_imports = 476;
-  const int vista_delay_imports = 24;
-  const int vista_relocs = 10188;
-  const int w2k_delay_dlls = 0;
-  const int w2k_exports = 566;
-  const int w2k_imports = 357;
-  const int w2k_delay_imports = 0;
-  const int w2k_relocs = 7388;
-  const int win7_delay_dlls = 7;
-  const int win7_exports = 806;
-  const int win7_imports = 568;
-  const int win7_delay_imports = 71;
-  int win7_relocs = 7812;
-  int win7_sections = 4;
-  const int win8_delay_dlls = 9;
-  const int win8_exports = 806;
-  const int win8_imports = 568;
-  const int win8_delay_imports = 113;
-  const int win8_relocs = 9478;
-  int win8_sections = 4;
-  int win8_import_dlls = 17;
-
-  base::win::OSInfo* os_info = base::win::OSInfo::GetInstance();
-  // 32-bit process on a 32-bit system.
-  if (os_info->architecture() == base::win::OSInfo::X86_ARCHITECTURE) {
-    win8_sections = 5;
-    win8_import_dlls = 19;
-
-  // 64-bit process on a 64-bit system.
-  } else if (os_info->wow64_status() == base::win::OSInfo::WOW64_DISABLED) {
-    win7_sections = 6;
-    win7_relocs = 2712;
-  }
-
-  // Contains the expected value, for each enumerated property (Value), and the
-  // OS version: [Value][os_version]
-  const int expected[][5] = {
-    {4, 4, 4, win7_sections, win8_sections},
-    {3, 3, 3, 13, win8_import_dlls},
-    {w2k_delay_dlls, xp_delay_dlls, vista_delay_dlls, win7_delay_dlls,
-     win8_delay_dlls},
-    {w2k_exports, xp_exports, vista_exports, win7_exports, win8_exports},
-    {w2k_imports, xp_imports, vista_imports, win7_imports, win8_imports},
-    {w2k_delay_imports, xp_delay_imports,
-     vista_delay_imports, win7_delay_imports, win8_delay_imports},
-    {w2k_relocs, xp_relocs, vista_relocs, win7_relocs, win8_relocs}
-  };
-  COMPILE_ASSERT(arraysize(expected[0]) == UNSUPPORTED_SET,
-                 expected_value_set_mismatch);
-
-  if (value > relocs)
-    return 0;
-  ExpectationSet expected_set = GetExpectationSet(os);
-  if (expected_set >= arraysize(expected)) {
-    // This should never happen.  Log a failure if it does.
-    EXPECT_NE(UNSUPPORTED_SET, expected_set);
-    expected_set = WIN_2K_SET;
-  }
-
-  return expected[value][expected_set];
-}
-
-
-// TODO(jschuh): crbug.com/167707 Need to fix test on Win64 bots
-#if defined(OS_WIN) && defined(ARCH_CPU_X86_64)
-#define MAYBE_EnumeratesPE DISABLED_EnumeratesPE
-#else
-#define MAYBE_EnumeratesPE EnumeratesPE
-#endif
+}  // namespace
 
 // Tests that we are able to enumerate stuff from a PE file, and that
 // the actual number of items found is within the expected range.
-TEST(PEImageTest, MAYBE_EnumeratesPE) {
-  HMODULE module = LoadLibrary(L"advapi32.dll");
+TEST(PEImageTest, EnumeratesPE) {
+  Expectations expectations;
+
+#ifndef NDEBUG
+  // Default Debug expectations.
+  expectations.SetDefault(Expectations::SECTIONS, 7);
+  expectations.SetDefault(Expectations::IMPORTS_DLLS, 3);
+  expectations.SetDefault(Expectations::DELAY_DLLS, 2);
+  expectations.SetDefault(Expectations::EXPORTS, 2);
+  expectations.SetDefault(Expectations::IMPORTS, 49);
+  expectations.SetDefault(Expectations::DELAY_IMPORTS, 2);
+  expectations.SetDefault(Expectations::RELOCS, 438);
+
+  // 64-bit Debug expectations.
+  expectations.SetOverride(Expectations::SECTIONS, Expectations::ARCH_X64, 8);
+  expectations.SetOverride(Expectations::IMPORTS, Expectations::ARCH_X64, 69);
+  expectations.SetOverride(Expectations::RELOCS, Expectations::ARCH_X64, 632);
+#else
+  // Default Release expectations.
+  expectations.SetDefault(Expectations::SECTIONS, 5);
+  expectations.SetDefault(Expectations::IMPORTS_DLLS, 2);
+  expectations.SetDefault(Expectations::DELAY_DLLS, 2);
+  expectations.SetDefault(Expectations::EXPORTS, 2);
+  expectations.SetDefault(Expectations::IMPORTS, 66);
+  expectations.SetDefault(Expectations::DELAY_IMPORTS, 2);
+  expectations.SetDefault(Expectations::RELOCS, 1586);
+
+  // 64-bit Release expectations.
+  expectations.SetOverride(Expectations::SECTIONS, Expectations::ARCH_X64, 6);
+  expectations.SetOverride(Expectations::IMPORTS, Expectations::ARCH_X64, 69);
+  expectations.SetOverride(Expectations::RELOCS, Expectations::ARCH_X64, 632);
+#endif
+
+  HMODULE module = LoadLibrary(L"pe_image_test.dll");
   ASSERT_TRUE(NULL != module);
 
   PEImage pe(module);
   int count = 0;
   EXPECT_TRUE(pe.VerifyMagic());
 
-  DWORD os = pe.GetNTHeaders()->OptionalHeader.MajorOperatingSystemVersion;
-  os = os * 10 + pe.GetNTHeaders()->OptionalHeader.MinorOperatingSystemVersion;
-
-  // Skip this test for unsupported OS versions.
-  if (GetExpectationSet(os) == UNSUPPORTED_SET)
-    return;
-
   pe.EnumSections(SectionsCallback, &count);
-  EXPECT_EQ(GetExpectedValue(sections, os), count);
+  EXPECT_EQ(expectations.GetExpectation(Expectations::SECTIONS), count);
 
   count = 0;
   pe.EnumImportChunks(ImportChunksCallback, &count);
-  EXPECT_EQ(GetExpectedValue(imports_dlls, os), count);
+  EXPECT_EQ(expectations.GetExpectation(Expectations::IMPORTS_DLLS), count);
 
   count = 0;
   pe.EnumDelayImportChunks(DelayImportChunksCallback, &count);
-  EXPECT_EQ(GetExpectedValue(delay_dlls, os), count);
+  EXPECT_EQ(expectations.GetExpectation(Expectations::DELAY_DLLS), count);
 
   count = 0;
   pe.EnumExports(ExportsCallback, &count);
-  EXPECT_GT(count, GetExpectedValue(exports, os) - 20);
-  EXPECT_LT(count, GetExpectedValue(exports, os) + 100);
+  EXPECT_EQ(expectations.GetExpectation(Expectations::EXPORTS), count);
 
   count = 0;
   pe.EnumAllImports(ImportsCallback, &count);
-  EXPECT_GT(count, GetExpectedValue(imports, os) - 20);
-  EXPECT_LT(count, GetExpectedValue(imports, os) + 100);
+  EXPECT_EQ(expectations.GetExpectation(Expectations::IMPORTS), count);
 
   count = 0;
   pe.EnumAllDelayImports(ImportsCallback, &count);
-  EXPECT_GT(count, GetExpectedValue(delay_imports, os) - 2);
-  EXPECT_LT(count, GetExpectedValue(delay_imports, os) + 8);
+  EXPECT_EQ(expectations.GetExpectation(Expectations::DELAY_IMPORTS), count);
 
   count = 0;
   pe.EnumRelocs(RelocsCallback, &count);
-  EXPECT_GT(count, GetExpectedValue(relocs, os) - 150);
-  EXPECT_LT(count, GetExpectedValue(relocs, os) + 1500);
+  EXPECT_EQ(expectations.GetExpectation(Expectations::RELOCS), count);
 
   FreeLibrary(module);
 }