llvm.org GIT mirror llvm / 5e4931b
InstrProf: Do a better job of reading coverage mapping data. This code was casting regions of a memory buffer to a couple of different structs. This is wrong in a few ways: 1. It breaks aliasing rules. 2. If the buffer isn't aligned, it hits undefined behaviour. 3. It completely ignores endianness differences. 4. The structs being defined for this aren't specifying their padding properly, so this doesn't even represent the data properly on some platforms. This commit is mostly NFC, except that it fixes reading coverage for 32 bit binaries as a side effect of getting rid of the mispadded structs. I've included a test for that. I've also baked in that we only handle little endian more explicitly, since that was true in practice already. I'll fix this to handle endianness properly in a followup commit. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@232346 91177308-0d34-0410-b5e6-96231b3b80d8 Justin Bogner 5 years ago
7 changed file(s) with 68 addition(s) and 74 deletion(s). Raw diff Collapse all Expand all
5757
5858 /// Read a value of a particular endianness from a buffer, and increment the
5959 /// buffer past that value.
60 template
61 inline value_type readNext(const unsigned char *&memory) {
60 template
61 typename CharT>
62 inline value_type readNext(const CharT *&memory) {
6263 value_type ret = read(memory);
6364 memory += sizeof(value_type);
6465 return ret;
1616 #include "llvm/Object/MachOUniversal.h"
1717 #include "llvm/Object/ObjectFile.h"
1818 #include "llvm/Support/Debug.h"
19 #include "llvm/Support/Endian.h"
1920 #include "llvm/Support/LEB128.h"
2021
2122 using namespace llvm;
287288 }
288289
289290 namespace {
290 /// \brief The coverage mapping data for a single function.
291 /// It points to the function's name.
292 template struct CoverageMappingFunctionRecord {
293 IntPtrT FunctionNamePtr;
294 uint32_t FunctionNameSize;
295 uint32_t CoverageMappingSize;
296 uint64_t FunctionHash;
297 };
298
299 /// \brief The coverage mapping data for a single translation unit.
300 /// It points to the array of function coverage mapping records and the encoded
301 /// filenames array.
302 template struct CoverageMappingTURecord {
303 uint32_t FunctionRecordsSize;
304 uint32_t FilenamesSize;
305 uint32_t CoverageMappingsSize;
306 uint32_t Version;
307 };
308291
309292 /// \brief A helper structure to access the data from a section
310293 /// in an object file.
336319 SectionData &ProfileNames, StringRef Data,
337320 std::vector &Records,
338321 std::vector &Filenames) {
322 using namespace support;
339323 llvm::DenseSet UniqueFunctionMappingData;
340324
341325 // Read the records in the coverage data section.
342 while (!Data.empty()) {
343 if (Data.size() < sizeof(CoverageMappingTURecord))
326 for (const char *Buf = Data.data(), *End = Buf + Data.size(); Buf < End;) {
327 if (Buf + 4 * sizeof(uint32_t) > End)
344328 return instrprof_error::malformed;
345 auto TU = reinterpret_cast *>(Data.data());
346 Data = Data.substr(sizeof(CoverageMappingTURecord));
347 switch (TU->Version) {
329 uint32_t NRecords = endian::readNext(Buf);
330 uint32_t FilenamesSize = endian::readNext(Buf);
331 uint32_t CoverageSize = endian::readNext(Buf);
332 uint32_t Version = endian::readNext(Buf);
333
334 switch (Version) {
348335 case CoverageMappingVersion1:
349336 break;
350337 default:
351338 return instrprof_error::unsupported_version;
352339 }
353 auto Version = CoverageMappingVersion(TU->Version);
354
355 // Get the function records.
356 auto FunctionRecords =
357 reinterpret_cast *>(Data.data());
358 if (Data.size() <
359 sizeof(CoverageMappingFunctionRecord) * TU->FunctionRecordsSize)
340
341 // Skip past the function records, saving the start and end for later.
342 const char *FunBuf = Buf;
343 Buf += NRecords * (sizeof(T) + 2 * sizeof(uint32_t) + sizeof(uint64_t));
344 const char *FunEnd = Buf;
345
346 // Get the filenames.
347 if (Buf + FilenamesSize > End)
360348 return instrprof_error::malformed;
361 Data = Data.substr(sizeof(CoverageMappingFunctionRecord) *
362 TU->FunctionRecordsSize);
363
364 // Get the filenames.
365 if (Data.size() < TU->FilenamesSize)
349 size_t FilenamesBegin = Filenames.size();
350 RawCoverageFilenamesReader Reader(StringRef(Buf, FilenamesSize), Filenames);
351 if (auto Err = Reader.read())
352 return Err;
353 Buf += FilenamesSize;
354
355 // We'll read the coverage mapping records in the loop below.
356 const char *CovBuf = Buf;
357 Buf += CoverageSize;
358 const char *CovEnd = Buf;
359 if (Buf > End)
366360 return instrprof_error::malformed;
367 auto RawFilenames = Data.substr(0, TU->FilenamesSize);
368 Data = Data.substr(TU->FilenamesSize);
369 size_t FilenamesBegin = Filenames.size();
370 RawCoverageFilenamesReader Reader(RawFilenames, Filenames);
371 if (auto Err = Reader.read())
372 return Err;
373
374 // Get the coverage mappings.
375 if (Data.size() < TU->CoverageMappingsSize)
376 return instrprof_error::malformed;
377 auto CoverageMappings = Data.substr(0, TU->CoverageMappingsSize);
378 Data = Data.substr(TU->CoverageMappingsSize);
379
380 for (unsigned I = 0; I < TU->FunctionRecordsSize; ++I) {
381 auto &MappingRecord = FunctionRecords[I];
382
383 // Get the coverage mapping.
384 if (CoverageMappings.size() < MappingRecord.CoverageMappingSize)
361
362 while (FunBuf < FunEnd) {
363 // Read the function information
364 T NamePtr = endian::readNext(FunBuf);
365 uint32_t NameSize = endian::readNext(FunBuf);
366 uint32_t DataSize = endian::readNext(FunBuf);
367 uint64_t FuncHash = endian::readNext(FunBuf);
368
369 // Now use that to read the coverage data.
370 if (CovBuf + DataSize > CovEnd)
385371 return instrprof_error::malformed;
386 auto Mapping =
387 CoverageMappings.substr(0, MappingRecord.CoverageMappingSize);
388 CoverageMappings =
389 CoverageMappings.substr(MappingRecord.CoverageMappingSize);
372 auto Mapping = StringRef(CovBuf, DataSize);
373 CovBuf += DataSize;
390374
391375 // Ignore this record if we already have a record that points to the same
392 // function name.
393 // This is useful to ignore the redundant records for the functions
394 // with ODR linkage.
395 if (!UniqueFunctionMappingData.insert(MappingRecord.FunctionNamePtr)
396 .second)
376 // function name. This is useful to ignore the redundant records for the
377 // functions with ODR linkage.
378 if (!UniqueFunctionMappingData.insert(NamePtr).second)
397379 continue;
398 StringRef FunctionName;
399 if (auto Err =
400 ProfileNames.get(MappingRecord.FunctionNamePtr,
401 MappingRecord.FunctionNameSize, FunctionName))
402 return Err;
380
381 // Finally, grab the name and create a record.
382 StringRef FuncName;
383 if (std::error_code EC = ProfileNames.get(NamePtr, NameSize, FuncName))
384 return EC;
403385 Records.push_back(BinaryCoverageReader::ProfileMappingRecord(
404 Version, FunctionName, MappingRecord.FunctionHash, Mapping,
386 CoverageMappingVersion(Version), FuncName, FuncHash, Mapping,
405387 FilenamesBegin, Filenames.size() - FilenamesBegin));
406388 }
407389 }
0 // Checks for reading various formats.
1
2 // CHECK: 100| [[@LINE+1]]|int main
3 int main(int argc, const char *argv[]) {}
4
5 // RUN: llvm-profdata merge %S/Inputs/binary-formats.proftext -o %t.profdata
6 // RUN: llvm-cov show %S/Inputs/binary-formats.macho32l -instr-profile %t.profdata -no-colors -filename-equivalence %s | FileCheck %s
7 // RUN: llvm-cov show %S/Inputs/binary-formats.macho64l -instr-profile %t.profdata -no-colors -filename-equivalence %s | FileCheck %s
8
9 // llvm-cov doesn't work on big endian yet
10 // XFAIL: powerpc64-, s390x, mips-, mips64-, sparc
0 config.suffixes = ['.test', '.m', '.cpp', '.c']
1
2 # http://llvm.org/bugs/show_bug.cgi?id=20979
3 if 'ubsan' in config.available_features:
4 config.unsupported = True