]> git.cworth.org Git - apitrace/blob - retrace_stdc.cpp
Remove unneeded include.
[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 (!address) {
94         // Ignore NULL pointer
95         assert(!buffer);
96         return;
97     }
98
99 #ifndef NDEBUG
100     RegionMap::iterator start = lowerBound(address);
101     RegionMap::iterator stop = upperBound(address + size);
102     if (0) {
103         // Forget all regions that intersect this new one.
104         regionMap.erase(start, stop);
105     } else {
106         for (RegionMap::iterator it = start; it != stop; ++it) {
107             std::cerr << std::hex << "warning: "
108                 "region 0x" << address << "-0x" << (address + size) << " "
109                 "intersects existing region 0x" << it->first << "-0x" << (it->first + it->second.size) << "\n" << std::dec;
110             assert(intersects(it, address, size));
111         }
112     }
113 #endif
114
115     assert(buffer);
116
117     Region region;
118     region.buffer = buffer;
119     region.size = size;
120
121     regionMap[address] = region;
122 }
123
124 static RegionMap::iterator
125 lookupRegion(unsigned long long address) {
126     RegionMap::iterator it = regionMap.lower_bound(address);
127
128     if (it == regionMap.end() ||
129         it->first > address) {
130         if (it == regionMap.begin()) {
131             return regionMap.end();
132         } else {
133             --it;
134         }
135     }
136
137     assert(contains(it, address));
138     return it;
139 }
140
141 void
142 delRegion(unsigned long long address) {
143     RegionMap::iterator it = lookupRegion(address);
144     if (it != regionMap.end()) {
145         regionMap.erase(it);
146     } else {
147         assert(0);
148     }
149 }
150
151
152 void
153 delRegionByPointer(void *ptr) {
154     for (RegionMap::iterator it = regionMap.begin(); it != regionMap.end(); ++it) {
155         if (it->second.buffer == ptr) {
156             regionMap.erase(it);
157             return;
158         }
159     }
160     assert(0);
161 }
162
163 void *
164 lookupAddress(unsigned long long address) {
165     RegionMap::iterator it = lookupRegion(address);
166     if (it != regionMap.end()) {
167         unsigned long long offset = address - it->first;
168         assert(offset < it->second.size);
169         return (char *)it->second.buffer + offset;
170     }
171
172     if (address >= 0x00400000) {
173         std::cerr << "warning: could not translate address 0x" << std::hex << address << std::dec << "\n";
174     }
175
176     return (void *)(uintptr_t)address;
177 }
178
179
180 class Translator : protected trace::Visitor
181 {
182 protected:
183     bool bind;
184
185     void *result;
186
187     void visit(trace::Null *) {
188         result = NULL;
189     }
190
191     void visit(trace::Blob *blob) {
192         result = blob->toPointer(bind);
193     }
194
195     void visit(trace::Pointer *p) {
196         result = lookupAddress(p->value);
197     }
198
199 public:
200     Translator(bool _bind) :
201         bind(_bind),
202         result(NULL)
203     {}
204
205     void * operator() (trace::Value *node) {
206         _visit(node);
207         return result;
208     }
209 };
210
211
212 void *
213 toPointer(trace::Value &value, bool bind) {
214     return Translator(bind) (&value);
215 }
216
217
218 static void retrace_malloc(trace::Call &call) {
219     size_t size = call.arg(0).toUInt();
220     unsigned long long address = call.ret->toUIntPtr();
221
222     if (!address) {
223         return;
224     }
225
226     void *buffer = malloc(size);
227     if (!buffer) {
228         std::cerr << "error: failed to allocated " << size << " bytes.";
229         return;
230     }
231
232     addRegion(address, buffer, size);
233 }
234
235
236 static void retrace_memcpy(trace::Call &call) {
237     void * dest = toPointer(call.arg(0));
238     void * src  = toPointer(call.arg(1));
239     size_t n    = call.arg(2).toUInt();
240
241     if (!dest || !src || !n) {
242         return;
243     }
244
245     memcpy(dest, src, n);
246 }
247
248
249 const retrace::Entry stdc_callbacks[] = {
250     {"malloc", &retrace_malloc},
251     {"memcpy", &retrace_memcpy},
252     {NULL, NULL}
253 };
254
255
256 } /* retrace */