1 /*
2 * Copyright (c) 2019, Intel Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included
12 * in all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
21 */
22 // PatchInfo reader.
23 //
24
25 #include <cassert>
26 #include <cstddef>
27 #include <map>
28
29 #include "PatchInfo.h"
30 #include "PatchInfoRecord.h"
31 #include "PatchInfoReader.h"
32
33 namespace {
34
35 class PatchInfoReader {
36 const char *Data;
37 std::size_t Size;
38 unsigned ShEntries;
39
40 const cm::patch::PInfoSectionHdr *Sh;
41
42 // All symbol tables are merged into a single one.
43 std::map<unsigned, cm::patch::Symbol *> SymbolTable;
44
45 typedef std::map<unsigned, cm::patch::Binary *> BinarySectionMapTy;
46 typedef std::map<unsigned, bool> SymbolTableSectionMapTy;
47 BinarySectionMapTy BinarySectionMap;
48 SymbolTableSectionMapTy SymbolTableSectionMap;
49
50 public:
PatchInfoReader(const char * B,std::size_t S)51 PatchInfoReader(const char *B, std::size_t S) : Data(B), Size(S), ShEntries(0){Sh = nullptr;}
52
53 bool read(cm::patch::Collection &C);
54
55 protected:
56 bool readHeader(cm::patch::Collection &C);
57 bool readSections(cm::patch::Collection &C);
58
59 bool readDummySection(cm::patch::Collection &C, unsigned n);
60 bool readUnknownSection(cm::patch::Collection &C, unsigned n);
61 bool readBinarySection(cm::patch::Collection &C, unsigned n);
62 bool readRelocationSection(cm::patch::Collection &C, unsigned n);
63 bool readSymbolTableSection(cm::patch::Collection &C, unsigned n);
64 bool readStringTableSection(cm::patch::Collection &C, unsigned n);
65 bool readInitRegAccessTableSection(cm::patch::Collection &C, unsigned n);
66 bool readFiniRegAccessTableSection(cm::patch::Collection &C, unsigned n);
67 bool readTokenTableSection(cm::patch::Collection &C, unsigned n);
68
69 bool readRegisterAccessTableSection(cm::patch::Collection &C, unsigned n,
70 cm::patch::PInfo_U16 ShType);
71
isValidSection(unsigned n)72 bool isValidSection(unsigned n) {
73 if (n >= ShEntries)
74 return false;
75 if (!Sh ||
76 Sh[n].ShOffset >= Size ||
77 Sh[n].ShOffset + Sh[n].ShSize > Size)
78 return false;
79 return true;
80 }
isValidSectionOfType(unsigned n,cm::patch::PInfo_U16 ShType)81 bool isValidSectionOfType(unsigned n, cm::patch::PInfo_U16 ShType) {
82 if (!isValidSection(n))
83 return false;
84 return Sh[n].ShType == ShType;
85 }
86
getString(unsigned ShIdx,unsigned Idx)87 const char *getString(unsigned ShIdx, unsigned Idx) {
88 const char *StringTable = Data + Sh[ShIdx].ShOffset;
89 return StringTable + Idx;
90 }
91
92 std::pair<BinarySectionMapTy::iterator, bool>
93 getOrReadBinarySection(cm::patch::Collection &C, unsigned n);
94
95 std::pair<SymbolTableSectionMapTy::iterator, bool>
96 getOrReadSymbolTableSection(cm::patch::Collection &C, unsigned n);
97 };
98
99 } // End anonymous namespace
100
readPatchInfo(const char * Buf,std::size_t Sz,cm::patch::Collection & C)101 bool readPatchInfo(const char *Buf, std::size_t Sz, cm::patch::Collection &C) {
102 PatchInfoReader R(Buf, Sz);
103 return R.read(C);
104 }
105
read(cm::patch::Collection & C)106 bool PatchInfoReader::read(cm::patch::Collection &C) {
107 return readHeader(C) || readSections(C);
108 }
109
readHeader(cm::patch::Collection & C)110 bool PatchInfoReader::readHeader(cm::patch::Collection &C) {
111 if (Size < sizeof(cm::patch::PInfoHdr))
112 return true;
113
114 const cm::patch::PInfoHdr *H =
115 reinterpret_cast<const cm::patch::PInfoHdr *>(Data);
116 if (!H->checkMagic())
117 return true;
118 if (H->Version != cm::patch::PV_0)
119 return true;
120 if (!H->isValidPlatform())
121 return true;
122 if (H->ShOffset >= Size)
123 return true;
124 if (H->ShOffset + H->ShNum * sizeof(cm::patch::PInfoSectionHdr) > Size)
125 return true;
126
127 if (C.getPlatform() != cm::patch::PP_NONE && C.getPlatform() != H->Platform)
128 return true;
129
130 C.setPlatform(H->Platform);
131
132 Sh = reinterpret_cast<const cm::patch::PInfoSectionHdr *>(Data + H->ShOffset);
133 ShEntries = H->ShNum;
134
135 return false;
136 }
137
138 std::pair<PatchInfoReader::BinarySectionMapTy::iterator, bool>
getOrReadBinarySection(cm::patch::Collection & C,unsigned n)139 PatchInfoReader::getOrReadBinarySection(cm::patch::Collection &C, unsigned n) {
140 auto BI = BinarySectionMap.end();
141 if (!readBinarySection(C, n)) {
142 BI = BinarySectionMap.find(n);
143 assert(BI != BinarySectionMap.end());
144 }
145 return std::make_pair(BI, BI == BinarySectionMap.end());
146 }
147
148 std::pair<PatchInfoReader::SymbolTableSectionMapTy::iterator, bool>
getOrReadSymbolTableSection(cm::patch::Collection & C,unsigned n)149 PatchInfoReader::getOrReadSymbolTableSection(cm::patch::Collection &C,
150 unsigned n) {
151 auto SI = SymbolTableSectionMap.end();
152 if (!readSymbolTableSection(C, n)) {
153 SI = SymbolTableSectionMap.find(n);
154 assert(SI != SymbolTableSectionMap.end());
155 }
156 return std::make_pair(SI, SI == SymbolTableSectionMap.end());
157 }
158
readSections(cm::patch::Collection & C)159 bool PatchInfoReader::readSections(cm::patch::Collection &C) {
160 if (!Sh)
161 return true;
162
163 for (unsigned n = 0; n != ShEntries; ++n) {
164
165 switch (Sh[n].ShType) {
166 case cm::patch::PSHT_NONE:
167 if (readDummySection(C, n)) return true;
168 break;
169 case cm::patch::PSHT_BINARY:
170 if (readBinarySection(C, n)) return true;
171 break;
172 case cm::patch::PSHT_REL:
173 if (readRelocationSection(C, n)) return true;
174 break;
175 case cm::patch::PSHT_SYMTAB:
176 if (readSymbolTableSection(C, n)) return true;
177 break;
178 case cm::patch::PSHT_STRTAB:
179 if (readStringTableSection(C, n)) return true;
180 break;
181 case cm::patch::PSHT_INITREGTAB:
182 if (readInitRegAccessTableSection(C, n)) return true;
183 break;
184 case cm::patch::PSHT_FINIREGTAB:
185 if (readFiniRegAccessTableSection(C, n)) return true;
186 break;
187 case cm::patch::PSHT_TOKTAB:
188 if (readTokenTableSection(C, n)) return true;
189 break;
190 default:
191 if (readUnknownSection(C, n)) return true;
192 break;
193 }
194 }
195
196 return false;
197 }
198
readDummySection(cm::patch::Collection & C,unsigned n)199 bool PatchInfoReader::readDummySection(cm::patch::Collection &C, unsigned n) {
200 if (!isValidSectionOfType(n, cm::patch::PSHT_NONE)) return true;
201 return false;
202 }
203
readBinarySection(cm::patch::Collection & C,unsigned n)204 bool PatchInfoReader::readBinarySection(cm::patch::Collection &C, unsigned n) {
205 // Skip if this binary section is ready read.
206 if (BinarySectionMap.count(n))
207 return false;
208
209 // Bail out if it's not an valid binary section.
210 if (!isValidSectionOfType(n, cm::patch::PSHT_BINARY))
211 return true;
212
213 const char *Buf = nullptr;
214 std::size_t Sz = Sh[n].ShSize;
215 if (Sz)
216 Buf = Data + Sh[n].ShOffset;
217 cm::patch::Binary *Bin = C.addBinary(Buf, Sz);
218 BinarySectionMap.insert(std::make_pair(n, Bin));
219
220 return false;
221 }
222
readRelocationSection(cm::patch::Collection & C,unsigned n)223 bool PatchInfoReader::readRelocationSection(cm::patch::Collection &C,
224 unsigned n) {
225 // Skip if this relocation section is already read.
226 if (!isValidSectionOfType(n, cm::patch::PSHT_REL))
227 return true;
228
229 bool Ret;
230
231 BinarySectionMapTy::iterator BI;
232 std::tie(BI, Ret) = getOrReadBinarySection(C, Sh[n].ShLink2);
233 if (Ret)
234 return true;
235 cm::patch::Binary *Bin = BI->second;
236
237 SymbolTableSectionMapTy::iterator SI;
238 std::tie(SI, Ret) = getOrReadSymbolTableSection(C, Sh[n].ShLink);
239 if (Ret)
240 return true;
241
242 // Scan through relocations.
243 std::size_t Sz = Sh[n].ShSize;
244 const cm::patch::PInfoRelocation *Rel =
245 reinterpret_cast<const cm::patch::PInfoRelocation *>(Data + Sh[n].ShOffset);
246 for (unsigned i = 0; Sz > 0; ++i, Sz -= sizeof(cm::patch::PInfoRelocation)) {
247 auto I = SymbolTable.find(Rel[i].RelSym);
248 if (I == SymbolTable.end())
249 return true;
250 cm::patch::Symbol *S = I->second;
251 Bin->addReloc(Rel[i].RelAddr, S);
252 }
253
254 return false;
255 }
256
readSymbolTableSection(cm::patch::Collection & C,unsigned n)257 bool PatchInfoReader::readSymbolTableSection(cm::patch::Collection &C,
258 unsigned n) {
259 // Skip if this section is ready read.
260 if (SymbolTableSectionMap.count(n))
261 return false;
262
263 // Bail out if it's an invalid section.
264 if (!isValidSectionOfType(n, cm::patch::PSHT_SYMTAB))
265 return true;
266
267 // Read string table.
268 unsigned ShIdx = Sh[n].ShLink;
269 if (readStringTableSection(C, ShIdx))
270 return true;
271
272 // Scan through the symbol table.
273 const cm::patch::PInfoSymbol *Sym =
274 reinterpret_cast<const cm::patch::PInfoSymbol *>(Data + Sh[n].ShOffset);
275 std::size_t Sz = Sh[n].ShSize;
276 for (unsigned i = 0; Sz > 0; ++i, Sz -= sizeof(cm::patch::PInfoSymbol)) {
277 // Skip unamed symbol.
278 unsigned StrIdx = Sym[i].SymName;
279 if (!StrIdx)
280 continue;
281 const char *Name = getString(ShIdx, StrIdx);
282 cm::patch::Binary *Bin = nullptr;
283 unsigned Ndx = Sym[i].SymShndx;
284 if (Ndx) {
285 // Only support binary section so far.
286 bool Ret;
287 BinarySectionMapTy::iterator BI;
288 std::tie(BI, Ret) = getOrReadBinarySection(C, Ndx);
289 if (Ret)
290 return true;
291 Bin = BI->second;
292 }
293 cm::patch::Symbol *S = C.getSymbol(Name);
294 if (Bin)
295 while (S && !S->isUnresolved()) {
296 // In case a symbol has multiple definitions (due to combining a single
297 // kernel multiple times), rename the conflicting one.
298 Name = C.getUniqueName(Name);
299 S = C.getSymbol(Name);
300 }
301 S = C.addSymbol(Name);
302 if (Bin && S->isUnresolved()) {
303 S->setBinary(Bin);
304 S->setAddr(Sym[i].SymValue);
305 S->setExtra(Sym[i].SymExtra);
306 }
307 // Assume there's just one symbol table section per patch info.
308 SymbolTable.insert(std::make_pair(i, S));
309 }
310 SymbolTableSectionMap.insert(std::make_pair(n, true));
311
312 return false;
313 }
314
readStringTableSection(cm::patch::Collection & C,unsigned n)315 bool PatchInfoReader::readStringTableSection(cm::patch::Collection &C,
316 unsigned n) {
317 if (!isValidSectionOfType(n, cm::patch::PSHT_STRTAB))
318 return true;
319 return false;
320 }
321
322
323 bool
readRegisterAccessTableSection(cm::patch::Collection & C,unsigned n,cm::patch::PInfo_U16 ShType)324 PatchInfoReader::readRegisterAccessTableSection(cm::patch::Collection &C,
325 unsigned n,
326 cm::patch::PInfo_U16 ShType) {
327 if (!isValidSectionOfType(n, ShType))
328 return true;
329
330 BinarySectionMapTy::iterator BI;
331 bool Ret;
332 std::tie(BI, Ret) = getOrReadBinarySection(C, Sh[n].ShLink2);
333 if (Ret)
334 return true;
335 cm::patch::Binary *Bin = BI->second;
336
337 // Scan through register accesses.
338 std::size_t Sz = Sh[n].ShSize;
339 const cm::patch::PInfoRegAccess *Acc =
340 reinterpret_cast<const cm::patch::PInfoRegAccess *>(Data + Sh[n].ShOffset);
341 switch (ShType) {
342 default:
343 return true;
344 case cm::patch::PSHT_INITREGTAB:
345 for (unsigned i = 0; Sz > 0; ++i, Sz -= sizeof(cm::patch::PInfoRegAccess))
346 Bin->addInitRegAccess(Acc[i].RegAccAddr, Acc[i].RegAccRegNo,
347 Acc[i].RegAccDUT);
348 break;
349 case cm::patch::PSHT_FINIREGTAB:
350 for (unsigned i = 0; Sz > 0; ++i, Sz -= sizeof(cm::patch::PInfoRegAccess))
351 Bin->addFiniRegAccess(Acc[i].RegAccAddr, Acc[i].RegAccRegNo,
352 Acc[i].RegAccDUT);
353 break;
354 }
355
356 return false;
357 }
358
readInitRegAccessTableSection(cm::patch::Collection & C,unsigned n)359 bool PatchInfoReader::readInitRegAccessTableSection(cm::patch::Collection &C,
360 unsigned n) {
361
362 return readRegisterAccessTableSection(C, n, cm::patch::PSHT_INITREGTAB);
363 }
364
readFiniRegAccessTableSection(cm::patch::Collection & C,unsigned n)365 bool PatchInfoReader::readFiniRegAccessTableSection(cm::patch::Collection &C,
366 unsigned n) {
367 return readRegisterAccessTableSection(C, n, cm::patch::PSHT_FINIREGTAB);
368 }
369
readTokenTableSection(cm::patch::Collection & C,unsigned n)370 bool PatchInfoReader::readTokenTableSection(cm::patch::Collection &C,
371 unsigned n) {
372 if (!isValidSectionOfType(n, cm::patch::PSHT_TOKTAB))
373 return true;
374
375 BinarySectionMapTy::iterator BI;
376 bool Ret;
377 std::tie(BI, Ret) = getOrReadBinarySection(C, Sh[n].ShLink2);
378 if (Ret)
379 return true;
380 cm::patch::Binary *Bin = BI->second;
381
382 // Scan through tokens.
383 std::size_t Sz = Sh[n].ShSize;
384 const cm::patch::PInfoToken *Tok =
385 reinterpret_cast<const cm::patch::PInfoToken *>(Data + Sh[n].ShOffset);
386 for (unsigned i = 0; Sz > 0; ++i, Sz -= sizeof(cm::patch::PInfoToken))
387 Bin->addToken(Tok[i].TokenNo);
388
389 return false;
390 }
391
392
readUnknownSection(cm::patch::Collection & C,unsigned n)393 bool PatchInfoReader::readUnknownSection(cm::patch::Collection &C, unsigned n) {
394 if (!isValidSection(n))
395 return true;
396 return false;
397 }
398