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