summaryrefslogtreecommitdiffstats
path: root/covoar/TraceWriterQEMU.cc
blob: 89cfd018e11ab3583c5a10be0eb312b511082f23 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
/*! @file TraceWriterQEMU.cc
 *  @brief TraceWriterQEMU 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 "TraceWriterQEMU.h"
#include "ExecutableInfo.h"
#include "CoverageMap.h"

/* XXX really not always right */
typedef uint32_t target_ulong;

#include "qemu-traces.h"

/* hack so this can compile on old Linux versions and FreeBSD */
#if (__GNUC__ <= 2) || defined(__FreeBSD__)
#define STAT stat
#define OPEN fopen
#else
#define STAT stat64
#define OPEN fopen64
#endif

namespace Trace {

  TraceWriterQEMU::TraceWriterQEMU():
    TraceWriterBase()
  {
  }

  TraceWriterQEMU::~TraceWriterQEMU()
  {
  }

  bool TraceWriterQEMU::writeFile(
    const char* const          file,
    Trace::TraceReaderBase    *log
  )
  {
    struct trace_header header;
    int                 status;
    FILE*               traceFile;
    uint8_t             taken;
    uint8_t             notTaken;

    taken    = TargetInfo->qemuTakenBit();
    notTaken = TargetInfo->qemuNotTakenBit();

    //
    // Verify that the TraceList has a non-zero size.
    //
    if ( log->Trace.set.begin() == log->Trace.set.end() ){
      fprintf( stderr, "ERROR: Empty TraceList\n" );
      return false;
    }

    //
    // Open the trace file.
    //
    traceFile = OPEN( file, "w" );
    if (!traceFile) {
      fprintf( stderr, "Unable to open %s\n", file );
      return false;
    }

    //
    //  Write the Header to the file
    //
    sprintf( header.magic, "%s", QEMU_TRACE_MAGIC );
    header.version = QEMU_TRACE_VERSION;
    header.kind    = QEMU_TRACE_KIND_RAW;  // XXX ??
    header.sizeof_target_pc = 32;
    header.big_endian = false;
    header.machine[0] = 0; // XXX ??
    header.machine[1] = 0; // XXX ??
    status = fwrite( &header, sizeof(trace_header), 1, traceFile );
    if (status != 1) {
      fprintf( stderr, "Unable to write header to %s\n", file );
      return false;
    }

    if (Verbose) 
      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]
       );

    //
    // Loop through log and write each entry.
    //
    struct trace_entry32  entry;
    TraceList::ranges_t::iterator   itr;

    for (itr = log->Trace.set.begin(); (itr != log->Trace.set.end()); itr++ ){
      entry.pc   = itr->lowAddress;
      entry.size = itr-> length;
      entry.op   = TRACE_OP_BLOCK;
      switch (itr->exitReason) {
        case TraceList::EXIT_REASON_BRANCH_TAKEN:
          entry.op |= taken;
          break;
        case TraceList::EXIT_REASON_BRANCH_NOT_TAKEN:
          entry.op |= notTaken;
          break;
        case TraceList::EXIT_REASON_OTHER:
          break;
        default:
          fprintf(stderr, "Unknown exit Reason\n");
          exit(1);
          break;
       }
       
      if ( Verbose )
        fprintf(stderr, "%x %x %x\n", entry.pc, entry.size, entry.op);

      status = fwrite( &entry, sizeof(entry), 1, traceFile );
      if (status != 1) {
        fprintf( stderr, "Unable to emtry to %s\n", file );
        return false;
      }
    }

    fclose( traceFile );
    return true;
  }
}