]> git.notmuchmail.org Git - apitrace/blob - retrace_stdc.cpp
Avoid output blobs.
[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
32
33 #include "trace_parser.hpp"
34 #include "retrace.hpp"
35
36
37 namespace retrace {
38
39 struct Region
40 {
41     void *buffer;
42     unsigned long long size;
43 };
44
45 typedef std::map<unsigned long long, Region> RegionMap;
46 static RegionMap regionMap;
47
48
49 static inline bool
50 contains(RegionMap::iterator &it, unsigned long long address) {
51     return it->first <= address && (it->first + it->second.size) > address;
52 }
53
54
55 static inline bool
56 intersects(RegionMap::iterator &it, unsigned long long start, unsigned long long size) {
57     unsigned long it_start = it->first;
58     unsigned long it_stop  = it->first + it->second.size;
59     unsigned long stop = start + size;
60     return it_start < stop && start < it_stop;
61 }
62
63
64 // Iterator to the first region that contains the address, or the first after
65 static RegionMap::iterator
66 lowerBound(unsigned long long address) {
67     RegionMap::iterator it = regionMap.lower_bound(address);
68
69     while (it != regionMap.begin()) {
70         RegionMap::iterator pred = it;
71         --pred;
72         if (contains(pred, address)) {
73             it = pred;
74         } else {
75             break;
76         }
77     }
78
79     return it;
80 }
81
82 // Iterator to the first region that starts after the address
83 static RegionMap::iterator
84 upperBound(unsigned long long address) {
85     RegionMap::iterator it = regionMap.upper_bound(address);
86
87     return it;
88 }
89
90 void
91 addRegion(unsigned long long address, void *buffer, unsigned long long size)
92 {
93     if (retrace::verbosity >= 2) {
94         std::cout
95             << "region "
96             << std::hex
97             << "0x" << address << "-0x" << (address + size)
98             << " -> "
99             << "0x" << (uintptr_t)buffer << "-0x" << ((uintptr_t)buffer + size)
100             << std::dec
101             << "\n";
102     }
103
104     if (!address) {
105         // Ignore NULL pointer
106         assert(!buffer);
107         return;
108     }
109
110 #ifndef NDEBUG
111     RegionMap::iterator start = lowerBound(address);
112     RegionMap::iterator stop = upperBound(address + size);
113     if (0) {
114         // Forget all regions that intersect this new one.
115         regionMap.erase(start, stop);
116     } else {
117         for (RegionMap::iterator it = start; it != stop; ++it) {
118             std::cerr << std::hex << "warning: "
119                 "region 0x" << address << "-0x" << (address + size) << " "
120                 "intersects existing region 0x" << it->first << "-0x" << (it->first + it->second.size) << "\n" << std::dec;
121             assert(intersects(it, address, size));
122         }
123     }
124 #endif
125
126     assert(buffer);
127
128     Region region;
129     region.buffer = buffer;
130     region.size = size;
131
132     regionMap[address] = region;
133 }
134
135 static RegionMap::iterator
136 lookupRegion(unsigned long long address) {
137     RegionMap::iterator it = regionMap.lower_bound(address);
138
139     if (it == regionMap.end() ||
140         it->first > address) {
141         if (it == regionMap.begin()) {
142             return regionMap.end();
143         } else {
144             --it;
145         }
146     }
147
148     assert(contains(it, address));
149     return it;
150 }
151
152 void
153 delRegion(unsigned long long address) {
154     RegionMap::iterator it = lookupRegion(address);
155     if (it != regionMap.end()) {
156         regionMap.erase(it);
157     } else {
158         assert(0);
159     }
160 }
161
162
163 void
164 delRegionByPointer(void *ptr) {
165     for (RegionMap::iterator it = regionMap.begin(); it != regionMap.end(); ++it) {
166         if (it->second.buffer == ptr) {
167             regionMap.erase(it);
168             return;
169         }
170     }
171     assert(0);
172 }
173
174 void *
175 lookupAddress(unsigned long long address) {
176     RegionMap::iterator it = lookupRegion(address);
177     if (it != regionMap.end()) {
178         unsigned long long offset = address - it->first;
179         assert(offset < it->second.size);
180         void *addr = (char *)it->second.buffer + offset;
181
182         if (retrace::verbosity >= 2) {
183             std::cout
184                 << "region "
185                 << std::hex
186                 << "0x" << address
187                 << " <- "
188                 << "0x" << (uintptr_t)addr
189                 << std::dec
190                 << "\n";
191         }
192
193         return addr;
194     }
195
196     if (address >= 0x00400000) {
197         std::cerr << "warning: could not translate address 0x" << std::hex << address << std::dec << "\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 static void retrace_malloc(trace::Call &call) {
243     size_t size = call.arg(0).toUInt();
244     unsigned long long address = call.ret->toUIntPtr();
245
246     if (!address) {
247         return;
248     }
249
250     void *buffer = malloc(size);
251     if (!buffer) {
252         std::cerr << "error: failed to allocated " << size << " bytes.";
253         return;
254     }
255
256     addRegion(address, buffer, size);
257 }
258
259
260 static void retrace_memcpy(trace::Call &call) {
261     void * dest = toPointer(call.arg(0));
262     void * src  = toPointer(call.arg(1));
263     size_t n    = call.arg(2).toUInt();
264
265     if (!dest || !src || !n) {
266         return;
267     }
268
269     memcpy(dest, src, n);
270 }
271
272
273 const retrace::Entry stdc_callbacks[] = {
274     {"malloc", &retrace_malloc},
275     {"memcpy", &retrace_memcpy},
276     {NULL, NULL}
277 };
278
279
280 } /* retrace */