1 /*
2 * Copyright 2012, The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 //===----------------------------------------------------------------------===//
18 // This file implements RSInfo::ReadFromFile()
19 //===----------------------------------------------------------------------===//
20
21 #include "bcc/Renderscript/RSInfo.h"
22
23 #include <new>
24
25 #include <utils/FileMap.h>
26
27 #include "bcc/Support/Log.h"
28 #include "bcc/Support/InputFile.h"
29
30 using namespace bcc;
31
32 namespace {
33
34 template<typename ItemType, typename ItemContainer>
35 inline bool helper_read_list_item(const ItemType &pItem,
36 const RSInfo &pInfo,
37 ItemContainer &pResult);
38
39 // Process PragmaItem in the file
40 template<> inline bool
helper_read_list_item(const rsinfo::PragmaItem & pItem,const RSInfo & pInfo,RSInfo::PragmaListTy & pResult)41 helper_read_list_item<rsinfo::PragmaItem, RSInfo::PragmaListTy>(
42 const rsinfo::PragmaItem &pItem,
43 const RSInfo &pInfo,
44 RSInfo::PragmaListTy &pResult)
45 {
46 const char *key = pInfo.getStringFromPool(pItem.key);
47 const char *value =pInfo.getStringFromPool(pItem.value);
48
49 if (key == NULL) {
50 ALOGE("Invalid string index %d for key in RS pragma list.", pItem.key);
51 return false;
52 }
53
54 if (value == NULL) {
55 ALOGE("Invalid string index %d for value in RS pragma list.", pItem.value);
56 return false;
57 }
58
59 pResult.push(std::make_pair(key, value));
60 return true;
61 }
62
63 // Procee ObjectSlotItem in the file
64 template<> inline bool
helper_read_list_item(const rsinfo::ObjectSlotItem & pItem,const RSInfo & pInfo,RSInfo::ObjectSlotListTy & pResult)65 helper_read_list_item<rsinfo::ObjectSlotItem, RSInfo::ObjectSlotListTy>(
66 const rsinfo::ObjectSlotItem &pItem,
67 const RSInfo &pInfo,
68 RSInfo::ObjectSlotListTy &pResult)
69 {
70 pResult.push(pItem.slot);
71 return true;
72 }
73
74 // Procee ExportVarNameItem in the file
75 template<> inline bool
helper_read_list_item(const rsinfo::ExportVarNameItem & pItem,const RSInfo & pInfo,RSInfo::ExportVarNameListTy & pResult)76 helper_read_list_item<rsinfo::ExportVarNameItem, RSInfo::ExportVarNameListTy>(
77 const rsinfo::ExportVarNameItem &pItem,
78 const RSInfo &pInfo,
79 RSInfo::ExportVarNameListTy &pResult)
80 {
81 const char *name = pInfo.getStringFromPool(pItem.name);
82
83 if (name == NULL) {
84 ALOGE("Invalid string index %d for name in RS export vars.", pItem.name);
85 return false;
86 }
87
88 pResult.push(name);
89 return true;
90 }
91
92 // Procee ExportFuncNameItem in the file
93 template<> inline bool
helper_read_list_item(const rsinfo::ExportFuncNameItem & pItem,const RSInfo & pInfo,RSInfo::ExportFuncNameListTy & pResult)94 helper_read_list_item<rsinfo::ExportFuncNameItem, RSInfo::ExportFuncNameListTy>(
95 const rsinfo::ExportFuncNameItem &pItem,
96 const RSInfo &pInfo,
97 RSInfo::ExportFuncNameListTy &pResult)
98 {
99 const char *name = pInfo.getStringFromPool(pItem.name);
100
101 if (name == NULL) {
102 ALOGE("Invalid string index %d for name in RS export funcs.", pItem.name);
103 return false;
104 }
105
106 pResult.push(name);
107 return true;
108 }
109
110 // Procee ExportForeachFuncItem in the file
111 template<> inline bool
helper_read_list_item(const rsinfo::ExportForeachFuncItem & pItem,const RSInfo & pInfo,RSInfo::ExportForeachFuncListTy & pResult)112 helper_read_list_item<rsinfo::ExportForeachFuncItem, RSInfo::ExportForeachFuncListTy>(
113 const rsinfo::ExportForeachFuncItem &pItem,
114 const RSInfo &pInfo,
115 RSInfo::ExportForeachFuncListTy &pResult)
116 {
117 const char *name = pInfo.getStringFromPool(pItem.name);
118
119 if (name == NULL) {
120 ALOGE("Invalid string index %d for name in RS export foreachs.", pItem.name);
121 return false;
122 }
123
124 pResult.push(std::make_pair(name, pItem.signature));
125 return true;
126 }
127
128 template<typename ItemType, typename ItemContainer>
helper_read_list(const uint8_t * pData,const RSInfo & pInfo,const rsinfo::ListHeader & pHeader,ItemContainer & pResult)129 inline bool helper_read_list(const uint8_t *pData,
130 const RSInfo &pInfo,
131 const rsinfo::ListHeader &pHeader,
132 ItemContainer &pResult) {
133 const ItemType *item;
134
135 // Out-of-range exception has been checked.
136 for (uint32_t i = 0; i < pHeader.count; i++) {
137 item = reinterpret_cast<const ItemType *>(pData +
138 pHeader.offset +
139 i * pHeader.itemSize);
140 if (!helper_read_list_item<ItemType, ItemContainer>(*item, pInfo, pResult)) {
141 return false;
142 }
143 }
144 return true;
145 }
146
147 } // end anonymous namespace
148
ReadFromFile(InputFile & pInput)149 RSInfo *RSInfo::ReadFromFile(InputFile &pInput) {
150 android::FileMap *map = NULL;
151 RSInfo *result = NULL;
152 const uint8_t *data;
153 const rsinfo::Header *header;
154 size_t filesize;
155 const char *input_filename = pInput.getName().c_str();
156 const off_t cur_input_offset = pInput.tell();
157
158 if (pInput.hasError()) {
159 ALOGE("Invalid RS info file %s! (%s)", input_filename,
160 pInput.getErrorMessage().c_str());
161 goto bail;
162 }
163
164 filesize = pInput.getSize();
165 if (pInput.hasError()) {
166 ALOGE("Failed to get the size of RS info file %s! (%s)",
167 input_filename, pInput.getErrorMessage().c_str());
168 goto bail;
169 }
170
171 // Create memory map for the file.
172 map = pInput.createMap(/* pOffset */cur_input_offset,
173 /* pLength */filesize - cur_input_offset);
174 if (map == NULL) {
175 ALOGE("Failed to map RS info file %s to the memory! (%s)",
176 input_filename, pInput.getErrorMessage().c_str());
177 goto bail;
178 }
179
180 data = reinterpret_cast<const uint8_t *>(map->getDataPtr());
181
182 // Header starts at the beginning of the file.
183 header = reinterpret_cast<const rsinfo::Header *>(data);
184
185 // Check the magic.
186 if (::memcmp(header->magic, RSINFO_MAGIC, sizeof(header->magic)) != 0) {
187 ALOGV("Wrong magic found in the RS info file %s. Treat it as a dirty "
188 "cache.", input_filename);
189 goto bail;
190 }
191
192 // Check the version.
193 if (::memcmp(header->version,
194 RSINFO_VERSION,
195 sizeof(header->version)) != 0) {
196 ALOGV("Mismatch the version of RS info file %s: (current) %s v.s. (file) "
197 "%s. Treat it as as a dirty cache.", input_filename, RSINFO_VERSION,
198 header->version);
199 goto bail;
200 }
201
202 // Check the size.
203 if ((header->headerSize != sizeof(rsinfo::Header)) ||
204 (header->pragmaList.itemSize != sizeof(rsinfo::PragmaItem)) ||
205 (header->objectSlotList.itemSize != sizeof(rsinfo::ObjectSlotItem)) ||
206 (header->exportVarNameList.itemSize != sizeof(rsinfo::ExportVarNameItem)) ||
207 (header->exportFuncNameList.itemSize != sizeof(rsinfo::ExportFuncNameItem)) ||
208 (header->exportForeachFuncList.itemSize != sizeof(rsinfo::ExportForeachFuncItem))) {
209 ALOGW("Corrupted RS info file %s! (unexpected size found)", input_filename);
210 goto bail;
211 }
212
213 // Check the range.
214 #define LIST_DATA_RANGE(_list_header) \
215 ((_list_header).offset + (_list_header).count * (_list_header).itemSize)
216 if (((header->headerSize + header->strPoolSize) > filesize) ||
217 (LIST_DATA_RANGE(header->pragmaList) > filesize) ||
218 (LIST_DATA_RANGE(header->objectSlotList) > filesize) ||
219 (LIST_DATA_RANGE(header->exportVarNameList) > filesize) ||
220 (LIST_DATA_RANGE(header->exportFuncNameList) > filesize) ||
221 (LIST_DATA_RANGE(header->exportForeachFuncList) > filesize)) {
222 ALOGW("Corrupted RS info file %s! (data out of the range)", input_filename);
223 goto bail;
224 }
225 #undef LIST_DATA_RANGE
226
227 // File seems ok, create result RSInfo object.
228 result = new (std::nothrow) RSInfo(header->strPoolSize);
229 if (result == NULL) {
230 ALOGE("Out of memory when create RSInfo object for %s!", input_filename);
231 goto bail;
232 }
233
234 // Make advice on our access pattern.
235 map->advise(android::FileMap::SEQUENTIAL);
236
237 // Copy the header.
238 ::memcpy(&result->mHeader, header, sizeof(rsinfo::Header));
239
240 if (header->strPoolSize > 0) {
241 // Copy the string pool. The string pool is immediately after the header at
242 // the offset header->headerSize.
243 if (result->mStringPool == NULL) {
244 ALOGE("Out of memory when allocate string pool for RS info file %s!",
245 input_filename);
246 goto bail;
247 }
248 ::memcpy(result->mStringPool, data + result->mHeader.headerSize,
249 result->mHeader.strPoolSize);
250 }
251
252 // Populate all the data to the result object.
253 result->mSourceHash =
254 reinterpret_cast<const uint8_t*>(result->getStringFromPool(header->sourceSha1Idx));
255 if (result->mSourceHash == NULL) {
256 ALOGE("Invalid string index %d for SHA-1 checksum of source.", header->sourceSha1Idx);
257 goto bail;
258 }
259
260 result->mCompileCommandLine = result->getStringFromPool(header->compileCommandLineIdx);
261 if (result->mCompileCommandLine == NULL) {
262 ALOGE("Invalid string index %d for compile command line.", header->compileCommandLineIdx);
263 goto bail;
264 }
265
266 result->mBuildFingerprint = result->getStringFromPool(header->buildFingerprintIdx);
267 if (result->mBuildFingerprint == NULL) {
268 ALOGE("Invalid string index %d for build fingerprint.", header->buildFingerprintIdx);
269 goto bail;
270 }
271
272 if (!helper_read_list<rsinfo::PragmaItem, PragmaListTy>
273 (data, *result, header->pragmaList, result->mPragmas)) {
274 goto bail;
275 }
276
277 if (!helper_read_list<rsinfo::ObjectSlotItem, ObjectSlotListTy>
278 (data, *result, header->objectSlotList, result->mObjectSlots)) {
279 goto bail;
280 }
281
282 if (!helper_read_list<rsinfo::ExportVarNameItem, ExportVarNameListTy>
283 (data, *result, header->exportVarNameList, result->mExportVarNames)) {
284 goto bail;
285 }
286
287 if (!helper_read_list<rsinfo::ExportFuncNameItem, ExportFuncNameListTy>
288 (data, *result, header->exportFuncNameList, result->mExportFuncNames)) {
289 goto bail;
290 }
291
292 if (!helper_read_list<rsinfo::ExportForeachFuncItem, ExportForeachFuncListTy>
293 (data, *result, header->exportForeachFuncList, result->mExportForeachFuncs)) {
294 goto bail;
295 }
296
297 // Clean up.
298 map->release();
299
300 return result;
301
302 bail:
303 if (map != NULL) {
304 map->release();
305 }
306
307 delete result;
308
309 return NULL;
310 } // RSInfo::ReadFromFile
311