]> git.cworth.org Git - apitrace/blob - retrace/retrace_swizzle.cpp
Use skiplist-based FastCallSet within trace::CallSet
[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 #ifndef NDEBUG
79     if (it != regionMap.end()) {
80         assert(contains(it, address) || it->first > address);
81     }
82 #endif
83
84     return it;
85 }
86
87 // Iterator to the first region that starts after the address
88 static RegionMap::iterator
89 upperBound(unsigned long long address) {
90     RegionMap::iterator it = regionMap.upper_bound(address);
91
92 #ifndef NDEBUG
93     if (it != regionMap.end()) {
94         assert(it->first >= address);
95     }
96 #endif
97
98     return it;
99 }
100
101 void
102 addRegion(unsigned long long address, void *buffer, unsigned long long size)
103 {
104     if (retrace::verbosity >= 2) {
105         std::cout
106             << "region "
107             << std::hex
108             << "0x" << address << "-0x" << (address + size)
109             << " -> "
110             << "0x" << (uintptr_t)buffer << "-0x" << ((uintptr_t)buffer + size)
111             << std::dec
112             << "\n";
113     }
114
115     if (!address) {
116         // Ignore NULL pointer
117         assert(!buffer);
118         return;
119     }
120
121 #ifndef NDEBUG
122     RegionMap::iterator start = lowerBound(address);
123     RegionMap::iterator stop = upperBound(address + size - 1);
124     if (0) {
125         // Forget all regions that intersect this new one.
126         regionMap.erase(start, stop);
127     } else {
128         for (RegionMap::iterator it = start; it != stop; ++it) {
129             std::cerr << std::hex << "warning: "
130                 "region 0x" << address << "-0x" << (address + size) << " "
131                 "intersects existing region 0x" << it->first << "-0x" << (it->first + it->second.size) << "\n" << std::dec;
132             assert(intersects(it, address, size));
133         }
134     }
135 #endif
136
137     assert(buffer);
138
139     Region region;
140     region.buffer = buffer;
141     region.size = size;
142
143     regionMap[address] = region;
144 }
145
146 static RegionMap::iterator
147 lookupRegion(unsigned long long address) {
148     RegionMap::iterator it = regionMap.lower_bound(address);
149
150     if (it == regionMap.end() ||
151         it->first > address) {
152         if (it == regionMap.begin()) {
153             return regionMap.end();
154         } else {
155             --it;
156         }
157     }
158
159     assert(contains(it, address));
160     return it;
161 }
162
163 void
164 delRegion(unsigned long long address) {
165     RegionMap::iterator it = lookupRegion(address);
166     if (it != regionMap.end()) {
167         regionMap.erase(it);
168     } else {
169         assert(0);
170     }
171 }
172
173
174 void
175 delRegionByPointer(void *ptr) {
176     for (RegionMap::iterator it = regionMap.begin(); it != regionMap.end(); ++it) {
177         if (it->second.buffer == ptr) {
178             regionMap.erase(it);
179             return;
180         }
181     }
182     assert(0);
183 }
184
185 void *
186 lookupAddress(unsigned long long address) {
187     RegionMap::iterator it = lookupRegion(address);
188     if (it != regionMap.end()) {
189         unsigned long long offset = address - it->first;
190         assert(offset < it->second.size);
191         void *addr = (char *)it->second.buffer + offset;
192
193         if (retrace::verbosity >= 2) {
194             std::cout
195                 << "region "
196                 << std::hex
197                 << "0x" << address
198                 << " <- "
199                 << "0x" << (uintptr_t)addr
200                 << std::dec
201                 << "\n";
202         }
203
204         return addr;
205     }
206
207     if (retrace::debug && address >= 64 * 1024 * 1024) {
208         /* Likely not an offset, but an address that should had been swizzled */
209         std::cerr << "warning: passing high address 0x" << std::hex << address << std::dec << " as uintptr_t\n";
210     }
211
212     return (void *)(uintptr_t)address;
213 }
214
215
216 class Translator : protected trace::Visitor
217 {
218 protected:
219     bool bind;
220
221     void *result;
222
223     void visit(trace::Null *) {
224         result = NULL;
225     }
226
227     void visit(trace::Blob *blob) {
228         result = blob->toPointer(bind);
229     }
230
231     void visit(trace::Pointer *p) {
232         result = lookupAddress(p->value);
233     }
234
235 public:
236     Translator(bool _bind) :
237         bind(_bind),
238         result(NULL)
239     {}
240
241     void * operator() (trace::Value *node) {
242         _visit(node);
243         return result;
244     }
245 };
246
247
248 void *
249 toPointer(trace::Value &value, bool bind) {
250     return Translator(bind) (&value);
251 }
252
253
254
255 static std::map<unsigned long long, void *> _obj_map;
256
257 void
258 addObj(trace::Call &call, trace::Value &value, void *obj) {
259     unsigned long long address = value.toUIntPtr();
260
261     if (!address) {
262         if (obj) {
263             warning(call) << "unexpected non-null object\n";
264         }
265         return;
266     }
267
268     if (!obj) {
269         warning(call) << "got null for object 0x" << std::hex << address << std::dec << "\n";
270     }
271
272     _obj_map[address] = obj;
273     
274     if (retrace::verbosity >= 2) {
275         std::cout << std::hex << "obj 0x" << address << " -> 0x" << size_t(obj) << std::dec << "\n";
276     }
277 }
278
279 void
280 delObj(trace::Value &value) {
281     unsigned long long address = value.toUIntPtr();
282     _obj_map.erase(address);
283 }
284
285 void *
286 toObjPointer(trace::Call &call, trace::Value &value) {
287     unsigned long long address = value.toUIntPtr();
288
289     void *obj;
290     if (address) {
291         obj = _obj_map[address];
292         if (!obj) {
293             warning(call) << "unknown object 0x" << std::hex << address << std::dec << "\n";
294         }
295     } else {
296         obj = NULL;
297     }
298
299     if (retrace::verbosity >= 2) {
300         std::cout << std::hex << "obj 0x" << address << " <- 0x" << size_t(obj) << std::dec << "\n";
301     }
302
303     return obj;
304 }
305
306
307 } /* retrace */