/*! @file CoverageReaderQEMU.cc * @brief CoverageReaderQEMU Implementation * * This file contains the implementation of the functions supporting * reading the QEMU coverage data files. */ #include #include #include #include "app_common.h" #include "CoverageReaderQEMU.h" #include "CoverageMap.h" #include "ExecutableInfo.h" #include "qemu-traces.h" /* hack so this can compile on old Linux versions and FreeBSD */ #if (__GNUC__ <= 2) || defined(__FreeBSD__) #define OPEN fopen #else #define OPEN fopen64 #endif namespace Coverage { CoverageReaderQEMU::CoverageReaderQEMU() { BranchInfoAvailable = true; } CoverageReaderQEMU::~CoverageReaderQEMU() { } void CoverageReaderQEMU::processFile( const char* const file, ExecutableInfo* const executableInformation ) { struct trace_header header; uintptr_t i; int status; FILE* traceFile; uint8_t taken; uint8_t notTaken; uint8_t branchInfo; taken = TargetInfo->qemuTakenBit(); notTaken = TargetInfo->qemuNotTakenBit(); branchInfo = taken | notTaken; // // Open the coverage file and read the header. // traceFile = OPEN( file, "r" ); if (!traceFile) { fprintf( stderr, "ERROR: CoverageReaderQEMU::processFile - Unable to open %s\n", file ); exit( -1 ); } status = fread( &header, sizeof(trace_header), 1, traceFile ); if (status != 1) { fprintf( stderr, "ERROR: CoverageReaderQEMU::processFile - " "Unable to read header from %s\n", file ); exit( -1 ); } #if 0 fprintf( stderr, "magic = %s\n" "version = %d\n" "kind = %d\n" "sizeof_target_pc = %d\n" "big_endian = %d\n" "machine = %02x:%02x\n", header.magic, header.version, header.kind, header.sizeof_target_pc, header.big_endian, header.machine[0], header.machine[1] ); #endif // // Read ENTRIES number of trace entries. // #define ENTRIES 1024 while (1) { CoverageMapBase *aCoverageMap = NULL; struct trace_entry entries[ENTRIES]; struct trace_entry *entry; int num_entries; // Read and process each line of the coverage file. num_entries = fread( entries, sizeof(struct trace_entry), ENTRIES, traceFile ); if (num_entries == 0) break; // Get the coverage map for each entry. Note that the map is // the same for each entry in the coverage map for (int count=0; countgetCoverageMap( entry->pc ); // Ensure that coverage map exists. if (!aCoverageMap) continue; // Set was executed for each TRACE_OP_BLOCK if (entry->op & TRACE_OP_BLOCK) { for (i=0; isize; i++) { aCoverageMap->setWasExecuted( entry->pc + i ); } } // Determine if additional branch information is available. if ( (entry->op & branchInfo) != 0 ) { uint32_t offset_e, offset_a; uint32_t a = entry->pc + entry->size - 1; if ((aCoverageMap->determineOffset( a, &offset_a ) != true) || (aCoverageMap->determineOffset( entry->pc, &offset_e ) != true)) { fprintf( stderr, "*** Trace block is inconsistent with coverage map\n" "*** Trace block (0x%08x - 0x%08x) for %d bytes\n" "*** Coverage map XXX \n", entry->pc, a, entry->size ); } else { while (!aCoverageMap->isStartOfInstruction(a)) a--; if (entry->op & taken) { aCoverageMap->setWasTaken( a ); } else if (entry->op & notTaken) { aCoverageMap->setWasNotTaken( a ); } } } } } fclose( traceFile ); } }