]> git.cworth.org Git - apitrace/blob - retrace/retrace_swizzle.cpp
Split retrace swizlling helpers.
[apitrace] / retrace / retrace_swizzle.cpp
1 /**************************************************************************
2  *
3  * Copyright 2011-2012 Jose Fonseca
4  * All Rights Reserved.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to deal
8  * in the Software without restriction, including without limitation the rights
9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22  * THE SOFTWARE.
23  *
24  **************************************************************************/
25
26
27 #include <assert.h>
28
29 #include <string.h>
30
31 #include "retrace.hpp"
32 #include "retrace_swizzle.hpp"
33
34
35 namespace retrace {
36
37
38 struct Region
39 {
40     void *buffer;
41     unsigned long long size;
42 };
43
44 typedef std::map<unsigned long long, Region> RegionMap;
45 static RegionMap regionMap;
46
47
48 static inline bool
49 contains(RegionMap::iterator &it, unsigned long long address) {
50     return it->first <= address && (it->first + it->second.size) > address;
51 }
52
53
54 static inline bool
55 intersects(RegionMap::iterator &it, unsigned long long start, unsigned long long size) {
56     unsigned long it_start = it->first;
57     unsigned long it_stop  = it->first + it->second.size;
58     unsigned long stop = start + size;
59     return it_start < stop && start < it_stop;
60 }
61
62
63 // Iterator to the first region that contains the address, or the first after
64 static RegionMap::iterator
65 lowerBound(unsigned long long address) {
66     RegionMap::iterator it = regionMap.lower_bound(address);
67
68     while (it != regionMap.begin()) {
69         RegionMap::iterator pred = it;
70         --pred;
71         if (contains(pred, address)) {
72             it = pred;
73         } else {
74             break;
75         }
76     }
77
78     return it;
79 }
80
81 // Iterator to the first region that starts after the address
82 static RegionMap::iterator
83 upperBound(unsigned long long address) {
84     RegionMap::iterator it = regionMap.upper_bound(address);
85
86     return it;
87 }
88
89 void
90 addRegion(unsigned long long address, void *buffer, unsigned long long size)
91 {
92     if (retrace::verbosity >= 2) {
93         std::cout
94             << "region "
95             << std::hex
96             << "0x" << address << "-0x" << (address + size)
97             << " -> "
98             << "0x" << (uintptr_t)buffer << "-0x" << ((uintptr_t)buffer + size)
99             << std::dec
100             << "\n";
101     }
102
103     if (!address) {
104         // Ignore NULL pointer
105         assert(!buffer);
106         return;
107     }
108
109 #ifndef NDEBUG
110     RegionMap::iterator start = lowerBound(address);
111     RegionMap::iterator stop = upperBound(address + size);
112     if (0) {
113         // Forget all regions that intersect this new one.
114         regionMap.erase(start, stop);
115     } else {
116         for (RegionMap::iterator it = start; it != stop; ++it) {
117             std::cerr << std::hex << "warning: "
118                 "region 0x" << address << "-0x" << (address + size) << " "
119                 "intersects existing region 0x" << it->first << "-0x" << (it->first + it->second.size) << "\n" << std::dec;
120             assert(intersects(it, address, size));
121         }
122     }
123 #endif
124
125     assert(buffer);
126
127     Region region;
128     region.buffer = buffer;
129     region.size = size;
130
131     regionMap[address] = region;
132 }
133
134 static RegionMap::iterator
135 lookupRegion(unsigned long long address) {
136     RegionMap::iterator it = regionMap.lower_bound(address);
137
138     if (it == regionMap.end() ||
139         it->first > address) {
140         if (it == regionMap.begin()) {
141             return regionMap.end();
142         } else {
143             --it;
144         }
145     }
146
147     assert(contains(it, address));
148     return it;
149 }
150
151 void
152 delRegion(unsigned long long address) {
153     RegionMap::iterator it = lookupRegion(address);
154     if (it != regionMap.end()) {
155         regionMap.erase(it);
156     } else {
157         assert(0);
158     }
159 }
160
161
162 void
163 delRegionByPointer(void *ptr) {
164     for (RegionMap::iterator it = regionMap.begin(); it != regionMap.end(); ++it) {
165         if (it->second.buffer == ptr) {
166             regionMap.erase(it);
167             return;
168         }
169     }
170     assert(0);
171 }
172
173 void *
174 lookupAddress(unsigned long long address) {
175     RegionMap::iterator it = lookupRegion(address);
176     if (it != regionMap.end()) {
177         unsigned long long offset = address - it->first;
178         assert(offset < it->second.size);
179         void *addr = (char *)it->second.buffer + offset;
180
181         if (retrace::verbosity >= 2) {
182             std::cout
183                 << "region "
184                 << std::hex
185                 << "0x" << address
186                 << " <- "
187                 << "0x" << (uintptr_t)addr
188                 << std::dec
189                 << "\n";
190         }
191
192         return addr;
193     }
194
195     if (retrace::debug && address >= 64 * 1024 * 1024) {
196         /* Likely not an offset, but an address that should had been swizzled */
197         std::cerr << "warning: passing high address 0x" << std::hex << address << std::dec << " as uintptr_t\n";
198     }
199
200     return (void *)(uintptr_t)address;
201 }
202
203
204 class Translator : protected trace::Visitor
205 {
206 protected:
207     bool bind;
208
209     void *result;
210
211     void visit(trace::Null *) {
212         result = NULL;
213     }
214
215     void visit(trace::Blob *blob) {
216         result = blob->toPointer(bind);
217     }
218
219     void visit(trace::Pointer *p) {
220         result = lookupAddress(p->value);
221     }
222
223 public:
224     Translator(bool _bind) :
225         bind(_bind),
226         result(NULL)
227     {}
228
229     void * operator() (trace::Value *node) {
230         _visit(node);
231         return result;
232     }
233 };
234
235
236 void *
237 toPointer(trace::Value &value, bool bind) {
238     return Translator(bind) (&value);
239 }
240
241
242 } /* retrace */