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