]> git.cworth.org Git - apitrace/blob - retrace_stdc.cpp
Add support for building for Android (currently only build egltrace.so)
[apitrace] / retrace_stdc.cpp
1 /**************************************************************************
2  *
3  * Copyright 2011 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 "glproc.hpp"
32
33
34
35 #include "trace_parser.hpp"
36 #include "retrace.hpp"
37
38
39 namespace retrace {
40
41 struct Region
42 {
43     void *buffer;
44     unsigned long long size;
45 };
46
47 typedef std::map<unsigned long long, Region> RegionMap;
48 static RegionMap regionMap;
49
50
51 static inline bool
52 contains(RegionMap::iterator &it, unsigned long long address) {
53     return it->first <= address && (it->first + it->second.size) > address;
54 }
55
56
57 static inline bool
58 intersects(RegionMap::iterator &it, unsigned long long start, unsigned long long size) {
59     unsigned long it_start = it->first;
60     unsigned long it_stop  = it->first + it->second.size;
61     unsigned long stop = start + size;
62     return it_start < stop && start < it_stop;
63 }
64
65
66 // Iterator to the first region that contains the address, or the first after
67 static RegionMap::iterator
68 lowerBound(unsigned long long address) {
69     RegionMap::iterator it = regionMap.lower_bound(address);
70
71     while (it != regionMap.begin()) {
72         RegionMap::iterator pred = it;
73         --pred;
74         if (contains(pred, address)) {
75             it = pred;
76         } else {
77             break;
78         }
79     }
80
81     return it;
82 }
83
84 // Iterator to the first region that starts after the address
85 static RegionMap::iterator
86 upperBound(unsigned long long address) {
87     RegionMap::iterator it = regionMap.upper_bound(address);
88
89     return it;
90 }
91
92 void
93 addRegion(unsigned long long address, void *buffer, unsigned long long size)
94 {
95     if (!address) {
96         // Ignore NULL pointer
97         assert(!buffer);
98         return;
99     }
100
101 #ifndef NDEBUG
102     RegionMap::iterator start = lowerBound(address);
103     RegionMap::iterator stop = upperBound(address + size);
104     if (0) {
105         // Forget all regions that intersect this new one.
106         regionMap.erase(start, stop);
107     } else {
108         for (RegionMap::iterator it = start; it != stop; ++it) {
109             std::cerr << std::hex << "warning: "
110                 "region 0x" << address << "-0x" << (address + size) << " "
111                 "intersects existing region 0x" << it->first << "-0x" << (it->first + it->second.size) << "\n" << std::dec;
112             assert(intersects(it, address, size));
113         }
114     }
115 #endif
116
117     assert(buffer);
118
119     Region region;
120     region.buffer = buffer;
121     region.size = size;
122
123     regionMap[address] = region;
124 }
125
126 static RegionMap::iterator
127 lookupRegion(unsigned long long address) {
128     RegionMap::iterator it = regionMap.lower_bound(address);
129
130     if (it == regionMap.end() ||
131         it->first > address) {
132         if (it == regionMap.begin()) {
133             return regionMap.end();
134         } else {
135             --it;
136         }
137     }
138
139     assert(contains(it, address));
140     return it;
141 }
142
143 void
144 delRegion(unsigned long long address) {
145     RegionMap::iterator it = lookupRegion(address);
146     if (it != regionMap.end()) {
147         regionMap.erase(it);
148     } else {
149         assert(0);
150     }
151 }
152
153
154 void
155 delRegionByPointer(void *ptr) {
156     for (RegionMap::iterator it = regionMap.begin(); it != regionMap.end(); ++it) {
157         if (it->second.buffer == ptr) {
158             regionMap.erase(it);
159             return;
160         }
161     }
162     assert(0);
163 }
164
165 void *
166 lookupAddress(unsigned long long address) {
167     RegionMap::iterator it = lookupRegion(address);
168     if (it != regionMap.end()) {
169         unsigned long long offset = address - it->first;
170         assert(offset < it->second.size);
171         return (char *)it->second.buffer + offset;
172     }
173
174     if (address >= 0x00400000) {
175         std::cerr << "warning: could not translate address 0x" << std::hex << address << std::dec << "\n";
176     }
177
178     return (void *)(uintptr_t)address;
179 }
180
181
182 class Translator : protected trace::Visitor
183 {
184 protected:
185     bool bind;
186
187     void *result;
188
189     void visit(trace::Null *) {
190         result = NULL;
191     }
192
193     void visit(trace::Blob *blob) {
194         result = blob->toPointer(bind);
195     }
196
197     void visit(trace::Pointer *p) {
198         result = lookupAddress(p->value);
199     }
200
201 public:
202     Translator(bool _bind) :
203         bind(_bind),
204         result(NULL)
205     {}
206
207     void * operator() (trace::Value *node) {
208         _visit(node);
209         return result;
210     }
211 };
212
213
214 void *
215 toPointer(trace::Value &value, bool bind) {
216     return Translator(bind) (&value);
217 }
218
219
220 static void retrace_malloc(trace::Call &call) {
221     size_t size = call.arg(0).toUInt();
222     unsigned long long address = call.ret->toUIntPtr();
223
224     if (!address) {
225         return;
226     }
227
228     void *buffer = malloc(size);
229     if (!buffer) {
230         std::cerr << "error: failed to allocated " << size << " bytes.";
231         return;
232     }
233
234     addRegion(address, buffer, size);
235 }
236
237
238 static void retrace_memcpy(trace::Call &call) {
239     void * dest = toPointer(call.arg(0));
240     void * src  = toPointer(call.arg(1));
241     size_t n    = call.arg(2).toUInt();
242
243     if (!dest || !src || !n) {
244         return;
245     }
246
247     memcpy(dest, src, n);
248 }
249
250
251 const retrace::Entry stdc_callbacks[] = {
252     {"malloc", &retrace_malloc},
253     {"memcpy", &retrace_memcpy},
254     {NULL, NULL}
255 };
256
257
258 } /* retrace */