15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/app/image_pre_reader_win.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <windows.h>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <algorithm>
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <limits>
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <vector>
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/scoped_ptr.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/threading/thread_restrictions.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/win/pe_image.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/win/scoped_handle.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/win/windows_version.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The minimum buffer size to allocate when reading the PE file headers.
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The PE file headers usually fit into a single 1KB page, and a PE file must
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// at least contain the initial page with the headers. That said, as long as
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// we expect at least sizeof(IMAGE_DOS_HEADER) bytes, we're ok.
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const size_t kMinHeaderBufferSize = 0x400;
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// A handy symbolic constant.
29d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)const size_t kOneHundredPercent = 100;
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void StaticAssertions() {
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  COMPILE_ASSERT(kMinHeaderBufferSize >= sizeof(IMAGE_DOS_HEADER),
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 min_header_buffer_size_at_least_as_big_as_the_dos_header);
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This struct provides a deallocation functor for use with scoped_ptr<T>
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// allocated with ::VirtualAlloc().
385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)struct VirtualFreeDeleter {
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void operator() (void* ptr) {
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ::VirtualFree(ptr, 0, MEM_RELEASE);
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// A wrapper for the Win32 ::SetFilePointer() function with some error checking.
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool SetFilePointer(HANDLE file_handle, size_t position) {
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return position <= static_cast<size_t>(std::numeric_limits<LONG>::max()) &&
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ::SetFilePointer(file_handle,
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       static_cast<LONG>(position),
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       NULL,
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       FILE_BEGIN) != INVALID_SET_FILE_POINTER;
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// A helper function to read the next |bytes_to_read| bytes from the file
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// given by |file_handle| into |buffer|.
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ReadNextBytes(HANDLE file_handle, void* buffer, size_t bytes_to_read) {
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(file_handle != INVALID_HANDLE_VALUE);
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(buffer != NULL);
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(bytes_to_read > 0);
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DWORD bytes_read = 0;
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return bytes_to_read <= std::numeric_limits<DWORD>::max() &&
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ::ReadFile(file_handle,
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 buffer,
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 static_cast<DWORD>(bytes_to_read),
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 &bytes_read,
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 NULL) &&
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      bytes_read == bytes_to_read;
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// A helper function to extend the |current_buffer| of bytes such that it
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// contains |desired_length| bytes read from the file given by |file_handle|.
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// It is assumed that |file_handle| has been used to sequentially populate
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// |current_buffer| thus far and is already positioned at the appropriate
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// read location.
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ReadMissingBytes(HANDLE file_handle,
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      std::vector<uint8>* current_buffer,
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                      size_t desired_length) {
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(file_handle != INVALID_HANDLE_VALUE);
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(current_buffer != NULL);
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t current_length = current_buffer->size();
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (current_length >= desired_length)
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t bytes_to_read = desired_length - current_length;
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  current_buffer->resize(desired_length);
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ReadNextBytes(file_handle,
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       &(current_buffer->at(current_length)),
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       bytes_to_read);
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Return a |percentage| of the number of initialized bytes in the given
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// |section|.
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This returns a percentage of the lesser of the size of the raw data in
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// the section and the virtual size of the section.
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Note that sections can have their tails implicitly initialized to zero
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// (i.e., their virtual size is larger than the raw size) and that raw data
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// is padded to the PE page size if the entire section is initialized (i.e.,
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// their raw data size will be larger than the virtual size).
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Any data after the initialized portion of the section will be soft-faulted
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// in (very quickly) as needed, so we don't need to include it in the returned
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// length.
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)size_t GetPercentageOfSectionLength(const IMAGE_SECTION_HEADER* section,
108d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)                                    size_t percentage) {
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(section != NULL);
110d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  DCHECK_GT(percentage, 0u);
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_LE(percentage, kOneHundredPercent);
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t initialized_length = std::min(section->SizeOfRawData,
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                       section->Misc.VirtualSize);
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (initialized_length == 0)
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 0;
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t length = (initialized_length * percentage) / kOneHundredPercent;
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return std::max<size_t>(length, 1);
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Helper function to read through a |percentage| of the given |section|
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// of the file denoted by |file_handle|. The |temp_buffer| is (re)used as
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// a transient storage area as the section is read in chunks of
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// |temp_buffer_size| bytes.
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ReadThroughSection(HANDLE file_handle,
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        const IMAGE_SECTION_HEADER* section,
130d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)                        size_t percentage,
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        void* temp_buffer,
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        size_t temp_buffer_size) {
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(file_handle != INVALID_HANDLE_VALUE);
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(section != NULL);
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_LE(percentage, kOneHundredPercent);
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(temp_buffer != NULL);
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(temp_buffer_size > 0);
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t bytes_to_read = GetPercentageOfSectionLength(section, percentage);
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (bytes_to_read == 0)
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!SetFilePointer(file_handle, section->PointerToRawData))
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Read all chunks except the last one.
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (bytes_to_read > temp_buffer_size) {
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!ReadNextBytes(file_handle, temp_buffer, temp_buffer_size))
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bytes_to_read -= temp_buffer_size;
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Read the last (possibly partial) chunk and return.
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(bytes_to_read > 0);
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(bytes_to_read <= temp_buffer_size);
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ReadNextBytes(file_handle, temp_buffer, bytes_to_read);
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// A helper function to touch all pages in the range
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// [base_addr, base_addr + length).
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void TouchPagesInRange(void* base_addr, size_t length) {
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(base_addr != NULL);
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(length > 0);
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Get the system info so we know the page size. Also, make sure we use a
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // non-zero value for the page size; GetSystemInfo() is hookable/patchable,
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // and you never know what shenanigans someone could get up to.
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SYSTEM_INFO system_info = {};
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  GetSystemInfo(&system_info);
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (system_info.dwPageSize == 0)
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    system_info.dwPageSize = 4096;
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We don't want to read outside the byte range (which could trigger an
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // access violation), so let's figure out the exact locations of the first
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // and final bytes we want to read.
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  volatile uint8* touch_ptr = reinterpret_cast<uint8*>(base_addr);
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  volatile uint8* final_touch_ptr = touch_ptr + length - 1;
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Read the memory in the range [touch_ptr, final_touch_ptr] with a stride
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // of the system page size, to ensure that it's been paged in.
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  uint8 dummy;
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (touch_ptr < final_touch_ptr) {
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    dummy = *touch_ptr;
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    touch_ptr += system_info.dwPageSize;
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  dummy = *final_touch_ptr;
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ImagePreReader::PartialPreReadImageOnDisk(const wchar_t* file_path,
192d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)                                               size_t percentage,
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                               size_t max_chunk_size) {
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(rogerm): change this to have the number of bytes pre-read per
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //     section be driven by a static table within the PE file (defaulting to
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //     full read if it's not there?) that's initialized by the optimization
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //     toolchain.
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(file_path != NULL);
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (percentage == 0)
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (percentage > kOneHundredPercent)
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    percentage = kOneHundredPercent;
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Validate/setup max_chunk_size, imposing a 1MB minimum on the chunk size.
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const size_t kMinChunkSize = 1024 * 1024;
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  max_chunk_size = std::max(max_chunk_size, kMinChunkSize);
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Open the file.
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::win::ScopedHandle file(
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      CreateFile(file_path,
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 GENERIC_READ,
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 NULL,
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 OPEN_EXISTING,
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 FILE_FLAG_SEQUENTIAL_SCAN,
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 NULL));
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!file.IsValid())
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Allocate a resizable buffer for the headers. We initially reserve as much
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // space as we typically see as the header size for chrome.dll and other
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // PE images.
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<uint8> headers;
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  headers.reserve(kMinHeaderBufferSize);
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Read, hopefully, all of the headers.
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!ReadMissingBytes(file, &headers, kMinHeaderBufferSize))
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The DOS header starts at offset 0 and allows us to get the offset of the
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // NT headers. Let's ensure we've read enough to capture the NT headers.
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t nt_headers_start =
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      reinterpret_cast<IMAGE_DOS_HEADER*>(&headers[0])->e_lfanew;
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t nt_headers_end = nt_headers_start + sizeof(IMAGE_NT_HEADERS);
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!ReadMissingBytes(file, &headers, nt_headers_end))
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Now that we've got the NT headers we can get the total header size,
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // including all of the section headers. Let's ensure we've read enough
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // to capture all of the header data.
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t size_of_headers = reinterpret_cast<IMAGE_NT_HEADERS*>(
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      &headers[nt_headers_start])->OptionalHeader.SizeOfHeaders;
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!ReadMissingBytes(file, &headers, size_of_headers))
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Now we have all of the headers. This is enough to let us use the PEImage
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // wrapper to query the structure of the image.
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::win::PEImage pe_image(reinterpret_cast<HMODULE>(&headers[0]));
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK(pe_image.VerifyMagic());
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Allocate a buffer to hold the pre-read bytes.
2555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_ptr<uint8, VirtualFreeDeleter> buffer(
2565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      static_cast<uint8*>(
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          ::VirtualAlloc(NULL, max_chunk_size, MEM_COMMIT, PAGE_READWRITE)));
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (buffer.get() == NULL)
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Iterate over each section, reading in a percentage of each.
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const IMAGE_SECTION_HEADER* section = NULL;
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (UINT i = 0; (section = pe_image.GetSectionHeader(i)) != NULL; ++i) {
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CHECK_LE(reinterpret_cast<const uint8*>(section + 1),
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             &headers[0] + headers.size());
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!ReadThroughSection(
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            file, section, percentage, buffer.get(), max_chunk_size))
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We're done.
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ImagePreReader::PartialPreReadImageInMemory(const wchar_t* file_path,
276d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)                                                 size_t percentage) {
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(rogerm): change this to have the number of bytes pre-read per
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //     section be driven by a static table within the PE file (defaulting to
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //     full read if it's not there?) that's initialized by the optimization
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  //     toolchain.
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(file_path != NULL);
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (percentage == 0)
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (percentage > kOneHundredPercent)
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    percentage = kOneHundredPercent;
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HMODULE dll_module = ::LoadLibraryExW(
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      file_path,
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NULL,
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      LOAD_WITH_ALTERED_SEARCH_PATH | DONT_RESOLVE_DLL_REFERENCES);
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!dll_module)
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::win::PEImage pe_image(dll_module);
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK(pe_image.VerifyMagic());
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Iterate over each section, stepping through a percentage of each to page
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // it in off the disk.
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const IMAGE_SECTION_HEADER* section = NULL;
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (UINT i = 0; (section = pe_image.GetSectionHeader(i)) != NULL; ++i) {
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Get the extent we want to touch.
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    size_t length = GetPercentageOfSectionLength(section, percentage);
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (length == 0)
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    uint8* start =
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        static_cast<uint8*>(pe_image.RVAToAddr(section->VirtualAddress));
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Verify that the extent we're going to touch falls inside the section
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // we expect it to (and by implication, inside the pe_image).
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CHECK_EQ(section,
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             pe_image.GetImageSectionFromAddr(start));
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CHECK_EQ(section,
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             pe_image.GetImageSectionFromAddr(start + length - 1));
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Page in the section range.
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    TouchPagesInRange(start, length);
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FreeLibrary(dll_module);
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ImagePreReader::PreReadImage(const wchar_t* file_path,
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  size_t size_to_read,
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  size_t step_size) {
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::ThreadRestrictions::AssertIOAllowed();
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (base::win::GetVersion() > base::win::VERSION_XP) {
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Vista+ branch. On these OSes, the forced reads through the DLL actually
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // slows warm starts. The solution is to sequentially read file contents
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // with an optional cap on total amount to read.
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::win::ScopedHandle file(
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        CreateFile(file_path,
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   GENERIC_READ,
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   NULL,
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   OPEN_EXISTING,
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   FILE_FLAG_SEQUENTIAL_SCAN,
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   NULL));
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!file.IsValid())
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Default to 1MB sequential reads.
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const DWORD actual_step_size = std::max(static_cast<DWORD>(step_size),
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                            static_cast<DWORD>(1024*1024));
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LPVOID buffer = ::VirtualAlloc(NULL,
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   actual_step_size,
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   MEM_COMMIT,
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                   PAGE_READWRITE);
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (buffer == NULL)
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DWORD len;
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    size_t total_read = 0;
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    while (::ReadFile(file, buffer, actual_step_size, &len, NULL) &&
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           len > 0 &&
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           (size_to_read ? total_read < size_to_read : true)) {
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      total_read += static_cast<size_t>(len);
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ::VirtualFree(buffer, 0, MEM_RELEASE);
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // WinXP branch. Here, reading the DLL from disk doesn't do
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // what we want so instead we pull the pages into memory by loading
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // the DLL and touching pages at a stride. We use the system's page
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // size as the stride, ignoring the passed in step_size, to make sure
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // each page in the range is touched.
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    HMODULE dll_module = ::LoadLibraryExW(
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        file_path,
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        NULL,
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        LOAD_WITH_ALTERED_SEARCH_PATH | DONT_RESOLVE_DLL_REFERENCES);
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!dll_module)
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return false;
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::win::PEImage pe_image(dll_module);
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CHECK(pe_image.VerifyMagic());
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We don't want to read past the end of the module (which could trigger
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // an access violation), so make sure to check the image size.
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PIMAGE_NT_HEADERS nt_headers = pe_image.GetNTHeaders();
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    size_t dll_module_length = std::min(
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        size_to_read ? size_to_read : ~0,
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        static_cast<size_t>(nt_headers->OptionalHeader.SizeOfImage));
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Page in then release the module.
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    TouchPagesInRange(dll_module, dll_module_length);
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    FreeLibrary(dll_module);
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ImagePreReader::PartialPreReadImage(const wchar_t* file_path,
399d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)                                         size_t percentage,
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                         size_t max_chunk_size) {
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::ThreadRestrictions::AssertIOAllowed();
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (percentage >= kOneHundredPercent) {
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If we're reading the whole image, we don't need to parse headers and
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // navigate sections, the basic PreReadImage() can be used to just step
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // blindly through the entire file / address-space.
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return PreReadImage(file_path, 0, max_chunk_size);
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (base::win::GetVersion() > base::win::VERSION_XP) {
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Vista+ branch. On these OSes, we warm up the Image by reading its
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // file off the disk.
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return PartialPreReadImageOnDisk(file_path, percentage, max_chunk_size);
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // WinXP branch. For XP, reading the image from disk doesn't do what we want
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // so instead we pull the pages into memory by loading the DLL and touching
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // initialized pages at a stride.
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return PartialPreReadImageInMemory(file_path, percentage);
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
421