1c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// Copyright 2013 Google Inc. All rights reserved. 2c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// 3c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// Redistribution and use in source and binary forms, with or without 4c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// modification, are permitted provided that the following conditions are 5c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// met: 6c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// 7c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// * Redistributions of source code must retain the above copyright 8c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// notice, this list of conditions and the following disclaimer. 9c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// * Redistributions in binary form must reproduce the above 10c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// copyright notice, this list of conditions and the following disclaimer 11c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// in the documentation and/or other materials provided with the 12c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// distribution. 13c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// * Neither the name of Google Inc. nor the names of its 14c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// contributors may be used to endorse or promote products derived from 15c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// this software without specific prior written permission. 16c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// 17c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org 29c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// This contains a suite of tools for transforming symbol information when 30c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// when that information has been extracted from a PDB containing OMAP 31c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// information. 32c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org 33c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// OMAP information is a lightweight description of a mapping between two 34c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// address spaces. It consists of two streams, each of them a vector 2-tuples. 35c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// The OMAPTO stream contains tuples of the form 36c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// 37c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// (RVA in transformed image, RVA in original image) 38c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// 39c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// while the OMAPFROM stream contains tuples of the form 40c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// 41c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// (RVA in original image, RVA in transformed image) 42c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// 43c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// The entries in each vector are sorted by the first value of the tuple, and 44c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// the lengths associated with a mapping are implicit as the distance between 45c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// two successive addresses in the vector. 46c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org 47c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// Consider a trivial 10-byte function described by the following symbol: 48c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// 49c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// Function: RVA 0x00001000, length 10, "foo" 50c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// 51c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// Now consider the same function, but with 5-bytes of instrumentation injected 52c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// at offset 5. The OMAP streams describing this would look like: 53c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// 54c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// OMAPTO : [ [0x00001000, 0x00001000], 55c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// [0x00001005, 0xFFFFFFFF], 56c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// [0x0000100a, 0x00001005] ] 57c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// OMAPFROM: [ [0x00001000, 0x00001000], 58c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// [0x00001005, 0x0000100a] ] 59c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// 60c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// In this case the injected code has been marked as not originating in the 61c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// source image, and thus it will have no symbol information at all. However, 62c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// the injected code may also be associated with an original address range; 63c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// for example, when prepending instrumentation to a basic block the 64c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// instrumentation can be labelled as originating from the same source BB such 65c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// that symbol resolution will still find the appropriate source code line 66c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// number. In this case the OMAP stream would look like: 67c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// 68c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// OMAPTO : [ [0x00001000, 0x00001000], 69c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// [0x00001005, 0x00001005], 70c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// [0x0000100a, 0x00001005] ] 71c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// OMAPFROM: [ [0x00001000, 0x00001000], 72c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// [0x00001005, 0x0000100a] ] 73c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// 74c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// Suppose we asked DIA to lookup the symbol at location 0x0000100a of the 75c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// instrumented image. It would first run this through the OMAPTO table and 76c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// translate that address to 0x00001005. It would then lookup the symbol 77c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// at that address and return the symbol for the function "foo". This is the 78c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// correct result. 79c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// 80c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// However, if we query DIA for the length and address of the symbol it will 81c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// tell us that it has length 10 and is at RVA 0x00001000. The location is 82c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// correct, but the length doesn't take into account the 5-bytes of injected 83c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// code. Symbol resolution works (starting from an instrumented address, 84c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// mapping to an original address, and looking up a symbol), but the symbol 85c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// metadata is incorrect. 86c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// 87c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// If we dump the symbols using DIA they will have their addresses 88c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// appropriately transformed and reflect positions in the instrumented image. 89c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// However, if we try to do a lookup using those symbols resolution can fail. 90c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// For example, the address 0x0000100a will not map to the symbol for "foo", 91c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// because DIA tells us it is at location 0x00001000 (correct) with length 92c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// 10 (incorrect). The problem is one of order of operations: in this case 93c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// we're attempting symbol resolution by looking up an instrumented address 94c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// in the table of translated symbols. 95c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// 96c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// One way to handle this is to dump the OMAP information as part of the 97c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// breakpad symbols. This requires the rest of the toolchain to be aware of 98c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// OMAP information and to use it when present prior to performing lookup. The 99c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// other option is to properly transform the symbols (updating length as well as 100c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// position) so that resolution will work as expected for translated addresses. 101c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// This is transparent to the rest of the toolchain. 102c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org 103c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org#include "common/windows/omap.h" 104c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org 105c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org#include <atlbase.h> 106c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org 107c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org#include <algorithm> 108c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org#include <cassert> 109c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org#include <set> 110c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org 111c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org#include "common/windows/dia_util.h" 112c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org 113c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.orgnamespace google_breakpad { 114c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org 115c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.orgnamespace { 116c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org 117c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.orgstatic const wchar_t kOmapToDebugStreamName[] = L"OMAPTO"; 118c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.orgstatic const wchar_t kOmapFromDebugStreamName[] = L"OMAPFROM"; 119c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org 120c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// Dependending on where this is used in breakpad we sometimes get min/max from 121c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// windef, and other times from algorithm. To get around this we simply 122c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// define our own min/max functions. 123c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.orgtemplate<typename T> 124c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.orgconst T& Min(const T& t1, const T& t2) { return t1 < t2 ? t1 : t2; } 125c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.orgtemplate<typename T> 126c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.orgconst T& Max(const T& t1, const T& t2) { return t1 > t2 ? t1 : t2; } 127c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org 128c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// It makes things more readable to have two different OMAP types. We cast 129c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// normal OMAPs into these. They must be the same size as the OMAP structure 130c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// for this to work, hence the static asserts. 131c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.orgstruct OmapOrigToTran { 132c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org DWORD rva_original; 133c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org DWORD rva_transformed; 134c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org}; 135c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.orgstruct OmapTranToOrig { 136c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org DWORD rva_transformed; 137c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org DWORD rva_original; 138c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org}; 139c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.orgstatic_assert(sizeof(OmapOrigToTran) == sizeof(OMAP), 140c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org "OmapOrigToTran must have same size as OMAP."); 141c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.orgstatic_assert(sizeof(OmapTranToOrig) == sizeof(OMAP), 142c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org "OmapTranToOrig must have same size as OMAP."); 143c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.orgtypedef std::vector<OmapOrigToTran> OmapFromTable; 144c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.orgtypedef std::vector<OmapTranToOrig> OmapToTable; 145c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org 146c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// Used for sorting and searching through a Mapping. 147c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.orgbool MappedRangeOriginalLess(const MappedRange& lhs, const MappedRange& rhs) { 148c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org if (lhs.rva_original < rhs.rva_original) 149c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org return true; 150c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org if (lhs.rva_original > rhs.rva_original) 151c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org return false; 152c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org return lhs.length < rhs.length; 153c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org} 154c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.orgbool MappedRangeMappedLess(const MappedRange& lhs, const MappedRange& rhs) { 155c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org if (lhs.rva_transformed < rhs.rva_transformed) 156c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org return true; 157c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org if (lhs.rva_transformed > rhs.rva_transformed) 158c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org return false; 159c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org return lhs.length < rhs.length; 160c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org} 161c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org 162c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// Used for searching through the EndpointIndexMap. 163c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.orgbool EndpointIndexLess(const EndpointIndex& ei1, const EndpointIndex& ei2) { 164c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org return ei1.endpoint < ei2.endpoint; 165c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org} 166c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org 167c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// Finds the debug stream with the given |name| in the given |session|, and 168c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// populates |table| with its contents. Casts the data directly into OMAP 169c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// structs. 170c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.orgbool FindAndLoadOmapTable(const wchar_t* name, 171c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org IDiaSession* session, 172c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org OmapTable* table) { 173c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org assert(name != NULL); 174c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org assert(session != NULL); 175c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org assert(table != NULL); 176c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org 177c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org CComPtr<IDiaEnumDebugStreamData> stream; 178c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org if (!FindDebugStream(name, session, &stream)) 179c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org return false; 180c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org assert(stream.p != NULL); 181c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org 182c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org LONG count = 0; 183c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org if (FAILED(stream->get_Count(&count))) { 184c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org fprintf(stderr, "IDiaEnumDebugStreamData::get_Count failed for stream " 185c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org "\"%ws\"\n", name); 186c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org return false; 187c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org } 188c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org 189c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org // Get the length of the stream in bytes. 190c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org DWORD bytes_read = 0; 191c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org ULONG count_read = 0; 192c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org if (FAILED(stream->Next(count, 0, &bytes_read, NULL, &count_read))) { 193c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org fprintf(stderr, "IDiaEnumDebugStreamData::Next failed while reading " 194c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org "length of stream \"%ws\"\n", name); 195c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org return false; 196c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org } 197c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org 198c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org // Ensure it's consistent with the OMAP data type. 199c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org DWORD bytes_expected = count * sizeof(OmapTable::value_type); 200c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org if (count * sizeof(OmapTable::value_type) != bytes_read) { 201c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org fprintf(stderr, "DIA debug stream \"%ws\" has an unexpected length", name); 202c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org return false; 203c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org } 204c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org 205c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org // Read the table. 206c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org table->resize(count); 207c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org bytes_read = 0; 208c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org count_read = 0; 209c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org if (FAILED(stream->Next(count, bytes_expected, &bytes_read, 210c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org reinterpret_cast<BYTE*>(&table->at(0)), 211c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org &count_read))) { 212c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org fprintf(stderr, "IDiaEnumDebugStreamData::Next failed while reading " 213c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org "data from stream \"%ws\"\n"); 214c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org return false; 215c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org } 216c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org 217c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org return true; 218c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org} 219c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org 220c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// This determines the original image length by looking through the segment 221c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// table. 222c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.orgbool GetOriginalImageLength(IDiaSession* session, DWORD* image_length) { 223c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org assert(session != NULL); 224c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org assert(image_length != NULL); 225c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org 226c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org CComPtr<IDiaEnumSegments> enum_segments; 227c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org if (!FindTable(session, &enum_segments)) 228c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org return false; 229c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org assert(enum_segments.p != NULL); 230c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org 231c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org DWORD temp_image_length = 0; 232c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org CComPtr<IDiaSegment> segment; 233c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org ULONG fetched = 0; 234c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org while (SUCCEEDED(enum_segments->Next(1, &segment, &fetched)) && 235c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org fetched == 1) { 236c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org assert(segment.p != NULL); 237c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org 238c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org DWORD rva = 0; 239c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org DWORD length = 0; 240c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org DWORD frame = 0; 241c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org if (FAILED(segment->get_relativeVirtualAddress(&rva)) || 242c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org FAILED(segment->get_length(&length)) || 243c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org FAILED(segment->get_frame(&frame))) { 244c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org fprintf(stderr, "Failed to get basic properties for IDiaSegment\n"); 245c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org return false; 246c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org } 247c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org 248c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org if (frame > 0) { 249c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org DWORD segment_end = rva + length; 250c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org if (segment_end > temp_image_length) 251c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org temp_image_length = segment_end; 252c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org } 253c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org segment.Release(); 254c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org } 255c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org 256c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org *image_length = temp_image_length; 257c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org return true; 258c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org} 259c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org 260c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// Detects regions of the original image that have been removed in the 261c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// transformed image, and sets the 'removed' property on all mapped ranges 262c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// immediately preceding a gap. The mapped ranges must be sorted by 263c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// 'rva_original'. 264c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.orgvoid FillInRemovedLengths(Mapping* mapping) { 265c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org assert(mapping != NULL); 266c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org 267c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org // Find and fill gaps. We do this with two sweeps. We first sweep forward 268c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org // looking for gaps. When we identify a gap we then sweep forward with a 269c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org // second scan and set the 'removed' property for any intervals that 270c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org // immediately precede the gap. 271c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org // 272c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org // Gaps are typically between two successive intervals, but not always: 273c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org // 274c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org // Range 1: --------------- 275c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org // Range 2: ------- 276c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org // Range 3: ------------- 277c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org // Gap : ****** 278c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org // 279c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org // In the above example the gap is between range 1 and range 3. A forward 280c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org // sweep finds the gap, and a second forward sweep identifies that range 1 281c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org // immediately precedes the gap and sets its 'removed' property. 282c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org 283c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org size_t fill = 0; 284c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org DWORD rva_front = 0; 285c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org for (size_t find = 0; find < mapping->size(); ++find) { 286c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org#ifndef NDEBUG 287c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org // We expect the mapped ranges to be sorted by 'rva_original'. 288c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org if (find > 0) { 289c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org assert(mapping->at(find - 1).rva_original <= 290c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org mapping->at(find).rva_original); 291c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org } 292c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org#endif 293c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org 294c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org if (rva_front < mapping->at(find).rva_original) { 295c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org // We've found a gap. Fill it in by setting the 'removed' property for 296c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org // any affected intervals. 297c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org DWORD removed = mapping->at(find).rva_original - rva_front; 298c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org for (; fill < find; ++fill) { 299c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org if (mapping->at(fill).rva_original + mapping->at(fill).length != 300c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org rva_front) { 301c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org continue; 302c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org } 303c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org 304c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org // This interval ends right where the gap starts. It needs to have its 305c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org // 'removed' information filled in. 306c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org mapping->at(fill).removed = removed; 307c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org } 308c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org } 309c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org 310c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org // Advance the front that indicates the covered portion of the image. 311c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org rva_front = mapping->at(find).rva_original + mapping->at(find).length; 312c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org } 313c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org} 314c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org 315c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// Builds a unified view of the mapping between the original and transformed 316c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// image space by merging OMAPTO and OMAPFROM data. 317c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.orgvoid BuildMapping(const OmapData& omap_data, Mapping* mapping) { 318c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org assert(mapping != NULL); 319c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org 320c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org mapping->clear(); 321c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org 322c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org if (omap_data.omap_from.empty() || omap_data.omap_to.empty()) 323c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org return; 324c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org 325c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org // The names 'omap_to' and 'omap_from' are awfully confusing, so we make 326c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org // ourselves more explicit here. This cast is only safe because the underlying 327c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org // types have the exact same size. 328c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org const OmapToTable& tran2orig = 329c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org reinterpret_cast<const OmapToTable&>(omap_data.omap_to); 330c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org const OmapFromTable& orig2tran = reinterpret_cast<const OmapFromTable&>( 331c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org omap_data.omap_from); 332c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org 333c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org // Handle the range of data at the beginning of the image. This is not usually 334c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org // specified by the OMAP data. 335c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org if (tran2orig[0].rva_transformed > 0 && orig2tran[0].rva_original > 0) { 336c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org DWORD header_transformed = tran2orig[0].rva_transformed; 337c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org DWORD header_original = orig2tran[0].rva_original; 338c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org DWORD header = Min(header_transformed, header_original); 339c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org 340c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org MappedRange mr = {}; 341c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org mr.length = header; 342c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org mr.injected = header_transformed - header; 343c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org mr.removed = header_original - header; 344c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org mapping->push_back(mr); 345c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org } 346c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org 347c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org // Convert the implied lengths to explicit lengths, and infer which content 348c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org // has been injected into the transformed image. Injected content is inferred 349c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org // as regions of the transformed address space that does not map back to 350c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org // known valid content in the original image. 351c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org for (size_t i = 0; i < tran2orig.size(); ++i) { 352c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org const OmapTranToOrig& o1 = tran2orig[i]; 353c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org 354c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org // This maps to content that is outside the original image, thus it 355c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org // describes injected content. We can skip this entry. 356c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org if (o1.rva_original >= omap_data.length_original) 357c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org continue; 358c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org 359c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org // Calculate the length of the current OMAP entry. This is implicit as the 360c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org // distance between successive |rva| values, capped at the end of the 361c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org // original image. 362c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org DWORD length = 0; 363c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org if (i + 1 < tran2orig.size()) { 364c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org const OmapTranToOrig& o2 = tran2orig[i + 1]; 365c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org 366c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org // We expect the table to be sorted by rva_transformed. 367c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org assert(o1.rva_transformed <= o2.rva_transformed); 368c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org 369c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org length = o2.rva_transformed - o1.rva_transformed; 370c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org if (o1.rva_original + length > omap_data.length_original) { 371c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org length = omap_data.length_original - o1.rva_original; 372c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org } 373c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org } else { 374c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org length = omap_data.length_original - o1.rva_original; 375c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org } 376c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org 377c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org // Zero-length entries don't describe anything and can be ignored. 378c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org if (length == 0) 379c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org continue; 380c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org 381c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org // Any gaps in the transformed address-space are due to injected content. 382c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org if (!mapping->empty()) { 383c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org MappedRange& prev_mr = mapping->back(); 384c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org prev_mr.injected += o1.rva_transformed - 385c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org (prev_mr.rva_transformed + prev_mr.length); 386c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org } 387c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org 388c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org MappedRange mr = {}; 389c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org mr.rva_original = o1.rva_original; 390c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org mr.rva_transformed = o1.rva_transformed; 391c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org mr.length = length; 392c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org mapping->push_back(mr); 393c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org } 394c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org 395c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org // Sort based on the original image addresses. 396c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org std::sort(mapping->begin(), mapping->end(), MappedRangeOriginalLess); 397c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org 398c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org // Fill in the 'removed' lengths by looking for gaps in the coverage of the 399c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org // original address space. 400c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org FillInRemovedLengths(mapping); 401c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org 402c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org return; 403c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org} 404c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org 405c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.orgvoid BuildEndpointIndexMap(ImageMap* image_map) { 406c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org assert(image_map != NULL); 407c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org 408c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org if (image_map->mapping.size() == 0) 409c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org return; 410c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org 411c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org const Mapping& mapping = image_map->mapping; 412c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org EndpointIndexMap& eim = image_map->endpoint_index_map; 413c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org 414c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org // Get the unique set of interval endpoints. 415c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org std::set<DWORD> endpoints; 416c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org for (size_t i = 0; i < mapping.size(); ++i) { 417c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org endpoints.insert(mapping[i].rva_original); 418c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org endpoints.insert(mapping[i].rva_original + 419c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org mapping[i].length + 420c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org mapping[i].removed); 421c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org } 422c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org 423c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org // Use the endpoints to initialize the secondary search structure for the 424c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org // mapping. 425c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org eim.resize(endpoints.size()); 426c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org std::set<DWORD>::const_iterator it = endpoints.begin(); 427c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org for (size_t i = 0; it != endpoints.end(); ++it, ++i) { 428c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org eim[i].endpoint = *it; 429c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org eim[i].index = mapping.size(); 430c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org } 431c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org 432c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org // For each endpoint we want the smallest index of any interval containing 433c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org // it. We iterate over the intervals and update the indices associated with 434c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org // each interval endpoint contained in the current interval. In the general 435c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org // case of an arbitrary set of intervals this is O(n^2), but the structure of 436c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org // OMAP data makes this O(n). 437c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org for (size_t i = 0; i < mapping.size(); ++i) { 438c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org EndpointIndex ei1 = { mapping[i].rva_original, 0 }; 439c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org EndpointIndexMap::iterator it1 = std::lower_bound( 440c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org eim.begin(), eim.end(), ei1, EndpointIndexLess); 441c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org 442c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org EndpointIndex ei2 = { mapping[i].rva_original + mapping[i].length + 443c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org mapping[i].removed, 0 }; 444c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org EndpointIndexMap::iterator it2 = std::lower_bound( 445c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org eim.begin(), eim.end(), ei2, EndpointIndexLess); 446c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org 447c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org for (; it1 != it2; ++it1) 448c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org it1->index = Min(i, it1->index); 449c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org } 450c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org} 451c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org 452c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org// Clips the given mapped range. 453c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.orgvoid ClipMappedRangeOriginal(const AddressRange& clip_range, 454c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org MappedRange* mapped_range) { 455c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org assert(mapped_range != NULL); 456c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org 457c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org // The clipping range is entirely outside of the mapped range. 458c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org if (clip_range.end() <= mapped_range->rva_original || 459c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org mapped_range->rva_original + mapped_range->length + 460c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org mapped_range->removed <= clip_range.rva) { 461c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org mapped_range->length = 0; 462c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org mapped_range->injected = 0; 463c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org mapped_range->removed = 0; 464c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org return; 465c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org } 466c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org 467c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org // Clip the left side. 468c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org if (mapped_range->rva_original < clip_range.rva) { 469c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org DWORD clip_left = clip_range.rva - mapped_range->rva_original; 470c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org mapped_range->rva_original += clip_left; 471c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org mapped_range->rva_transformed += clip_left; 472c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org 473c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org if (clip_left > mapped_range->length) { 474c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org // The left clipping boundary entirely erases the content section of the 475c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org // range. 476c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org DWORD trim = clip_left - mapped_range->length; 477c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org mapped_range->length = 0; 478c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org mapped_range->injected -= Min(trim, mapped_range->injected); 479c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org // We know that trim <= mapped_range->remove. 480c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org mapped_range->removed -= trim; 481c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org } else { 482c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org // The left clipping boundary removes some, but not all, of the content. 483c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org // As such it leaves the removed/injected component intact. 484c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org mapped_range->length -= clip_left; 485c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org } 486c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org } 487c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org 488c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org // Clip the right side. 489c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org DWORD end_original = mapped_range->rva_original + mapped_range->length; 490c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org if (clip_range.end() < end_original) { 491c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org // The right clipping boundary lands in the 'content' section of the range, 492c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org // entirely clearing the injected/removed portion. 493c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org DWORD clip_right = end_original - clip_range.end(); 494c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org mapped_range->length -= clip_right; 495c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org mapped_range->injected = 0; 496c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org mapped_range->removed = 0; 497c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org return; 498c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org } else { 499c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org // The right clipping boundary is outside of the content, but may affect 500c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org // the removed/injected portion of the range. 501c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org DWORD end_removed = end_original + mapped_range->removed; 502c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org if (clip_range.end() < end_removed) 503c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org mapped_range->removed = clip_range.end() - end_original; 504c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org 505c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org DWORD end_injected = end_original + mapped_range->injected; 506c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org if (clip_range.end() < end_injected) 507c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org mapped_range->injected = clip_range.end() - end_original; 508c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org } 509c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org 510c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org return; 511c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org} 512c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org 513c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org} // namespace 514c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org 515c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.orgint AddressRange::Compare(const AddressRange& rhs) const { 516c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org if (end() <= rhs.rva) 517c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org return -1; 518c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org if (rhs.end() <= rva) 519c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org return 1; 520c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org return 0; 521c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org} 522c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org 523c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.orgbool GetOmapDataAndDisableTranslation(IDiaSession* session, 524c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org OmapData* omap_data) { 525c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org assert(session != NULL); 526c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org assert(omap_data != NULL); 527c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org 528c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org CComPtr<IDiaAddressMap> address_map; 529c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org if (FAILED(session->QueryInterface(&address_map))) { 530c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org fprintf(stderr, "IDiaSession::QueryInterface(IDiaAddressMap) failed\n"); 531c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org return false; 532c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org } 533c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org assert(address_map.p != NULL); 534c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org 535c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org BOOL omap_enabled = FALSE; 536c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org if (FAILED(address_map->get_addressMapEnabled(&omap_enabled))) { 537c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org fprintf(stderr, "IDiaAddressMap::get_addressMapEnabled failed\n"); 538c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org return false; 539c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org } 540c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org 541c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org if (!omap_enabled) { 542c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org // We indicate the non-presence of OMAP data by returning empty tables. 543c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org omap_data->omap_from.clear(); 544c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org omap_data->omap_to.clear(); 545c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org omap_data->length_original = 0; 546c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org return true; 547c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org } 548c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org 549c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org // OMAP data is present. Disable translation. 550c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org if (FAILED(address_map->put_addressMapEnabled(FALSE))) { 551c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org fprintf(stderr, "IDiaAddressMap::put_addressMapEnabled failed\n"); 552c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org return false; 553c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org } 554c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org 555c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org // Read the OMAP streams. 556c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org if (!FindAndLoadOmapTable(kOmapFromDebugStreamName, 557c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org session, 558c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org &omap_data->omap_from)) { 559c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org return false; 560c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org } 561c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org if (!FindAndLoadOmapTable(kOmapToDebugStreamName, 562c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org session, 563c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org &omap_data->omap_to)) { 564c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org return false; 565c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org } 566c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org 567c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org // Get the lengths of the address spaces. 568c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org if (!GetOriginalImageLength(session, &omap_data->length_original)) 569c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org return false; 570c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org 571c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org return true; 572c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org} 573c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org 574c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.orgvoid BuildImageMap(const OmapData& omap_data, ImageMap* image_map) { 575c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org assert(image_map != NULL); 576c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org 577c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org BuildMapping(omap_data, &image_map->mapping); 578c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org BuildEndpointIndexMap(image_map); 579c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org} 580c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org 581c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.orgvoid MapAddressRange(const ImageMap& image_map, 582c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org const AddressRange& original_range, 583c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org AddressRangeVector* mapped_ranges) { 584c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org assert(mapped_ranges != NULL); 585c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org 586c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org const Mapping& map = image_map.mapping; 587c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org 588c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org // Handle the trivial case of an empty image_map. This means that there is 589c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org // no transformation to be applied, and we can simply return the original 590c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org // range. 591c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org if (map.empty()) { 592c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org mapped_ranges->push_back(original_range); 593c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org return; 594c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org } 595c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org 596c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org // If we get a query of length 0 we need to handle it by using a non-zero 597c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org // query length. 598c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org AddressRange query_range(original_range); 599c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org if (query_range.length == 0) 600c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org query_range.length = 1; 601c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org 602c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org // Find the range of intervals that can potentially intersect our query range. 603c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org size_t imin = 0; 604c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org size_t imax = 0; 605c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org { 606c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org // The index of the earliest possible range that can affect is us done by 607c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org // searching through the secondary indexing structure. 608c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org const EndpointIndexMap& eim = image_map.endpoint_index_map; 609c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org EndpointIndex q1 = { query_range.rva, 0 }; 610c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org EndpointIndexMap::const_iterator it1 = std::lower_bound( 611c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org eim.begin(), eim.end(), q1, EndpointIndexLess); 612c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org if (it1 == eim.end()) { 613c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org imin = map.size(); 614c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org } else { 615c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org // Backup to find the interval that contains our query point. 616c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org if (it1 != eim.begin() && query_range.rva < it1->endpoint) 617c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org --it1; 618c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org imin = it1->index; 619c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org } 620c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org 621c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org // The first range that can't possibly intersect us is found by searching 622c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org // through the image map directly as it is already sorted by interval start 623c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org // point. 624c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org MappedRange q2 = { query_range.end(), 0 }; 625c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org Mapping::const_iterator it2 = std::lower_bound( 626c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org map.begin(), map.end(), q2, MappedRangeOriginalLess); 627c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org imax = it2 - map.begin(); 628c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org } 629c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org 630c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org // Find all intervals that intersect the query range. 631c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org Mapping temp_map; 632c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org for (size_t i = imin; i < imax; ++i) { 633c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org MappedRange mr = map[i]; 634c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org ClipMappedRangeOriginal(query_range, &mr); 635c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org if (mr.length + mr.injected > 0) 636c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org temp_map.push_back(mr); 637c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org } 638c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org 639c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org // If there are no intersecting ranges then the query range has been removed 640c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org // from the image in question. 641c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org if (temp_map.empty()) 642c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org return; 643c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org 644c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org // Sort based on transformed addresses. 645c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org std::sort(temp_map.begin(), temp_map.end(), MappedRangeMappedLess); 646c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org 647c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org // Zero-length queries can't actually be merged. We simply output the set of 648c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org // unique RVAs that correspond to the query RVA. 649c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org if (original_range.length == 0) { 650c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org mapped_ranges->push_back(AddressRange(temp_map[0].rva_transformed, 0)); 651c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org for (size_t i = 1; i < temp_map.size(); ++i) { 652c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org if (temp_map[i].rva_transformed > mapped_ranges->back().rva) 653c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org mapped_ranges->push_back(AddressRange(temp_map[i].rva_transformed, 0)); 654c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org } 655c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org return; 656c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org } 657c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org 658c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org // Merge any ranges that are consecutive in the mapped image. We merge over 659c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org // injected content if it makes ranges contiguous, but we ignore any injected 660c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org // content at the tail end of a range. This allows us to detect symbols that 661c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org // have been lengthened by injecting content in the middle. However, it 662c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org // misses the case where content has been injected at the head or the tail. 663c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org // The problem is that it doesn't know whether to attribute it to the 664c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org // preceding or following symbol. It is up to the author of the transform to 665c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org // output explicit OMAP info in these cases to ensure full coverage of the 666c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org // transformed address space. 667c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org DWORD rva_begin = temp_map[0].rva_transformed; 668c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org DWORD rva_cur_content = rva_begin + temp_map[0].length; 669c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org DWORD rva_cur_injected = rva_cur_content + temp_map[0].injected; 670c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org for (size_t i = 1; i < temp_map.size(); ++i) { 671c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org if (rva_cur_injected < temp_map[i].rva_transformed) { 672c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org // This marks the end of a continuous range in the image. Output the 673c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org // current range and start a new one. 674c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org if (rva_begin < rva_cur_content) { 675c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org mapped_ranges->push_back( 676c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org AddressRange(rva_begin, rva_cur_content - rva_begin)); 677c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org } 678c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org rva_begin = temp_map[i].rva_transformed; 679c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org } 680c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org 681c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org rva_cur_content = temp_map[i].rva_transformed + temp_map[i].length; 682c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org rva_cur_injected = rva_cur_content + temp_map[i].injected; 683c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org } 684c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org 685c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org // Output the range in progress. 686c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org if (rva_begin < rva_cur_content) { 687c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org mapped_ranges->push_back( 688c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org AddressRange(rva_begin, rva_cur_content - rva_begin)); 689c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org } 690c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org 691c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org return; 692c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org} 693c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org 694c5edab4aba29171b5adf0876e59f242072b419c7ivanpe@chromium.org} // namespace google_breakpad