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