summaryrefslogblamecommitdiffstats
path: root/covoar/CoverageReaderQEMU.cc
blob: c8df89aee8559108f478a59b882ce8f81c55bac1 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

















                                                                     

                                                                




















































































































                                                                          

                                                                   




                                                                             



                                                                   
                                        

                        

                         







                                                          
           
         

       


                        
/*! @file CoverageReaderQEMU.cc
 *  @brief CoverageReaderQEMU Implementation
 *
 *  This file contains the implementation of the functions supporting
 *  reading the QEMU coverage data files.
 */

#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>

#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; count<num_entries; count++) {

        entry = &entries[count];
      
        // Mark block as fully executed.
        // Obtain the coverage map containing the specified address.
        aCoverageMap = executableInformation->getCoverageMap( 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; i<entry->size; 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 );
  }
}