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