1// Copyright 2006 The Android Open Source Project
2
3#include <stdio.h>
4#include <unistd.h>
5#include <stdlib.h>
6#include <inttypes.h>
7#include <assert.h>
8#include "trace_reader.h"
9#include "gtrace.h"
10#include "bitvector.h"
11#include "parse_options.h"
12
13struct symbol {
14  int		filenum;	// the file number (for gtrace)
15  int		procnum;	// the procedure number (for gtrace)
16};
17
18typedef TraceReader<symbol> TraceReaderType;
19
20#include "parse_options-inl.h"
21
22const int kMaxProcNum = 4095;
23int next_filenum = 1;
24int next_procnum = 1;
25
26void Usage(const char *program)
27{
28  fprintf(stderr, "Usage: %s [options] trace_file elf_file gtrace_file\n",
29          program);
30  OptionsUsage();
31}
32
33int main(int argc, char **argv)
34{
35  ParseOptions(argc, argv);
36  if (argc - optind != 3) {
37    Usage(argv[0]);
38    exit(1);
39  }
40
41  char *qemu_trace_file = argv[optind++];
42  char *elf_file = argv[optind++];
43  char *gtrace_file = argv[optind++];
44  TraceReader<symbol> *trace = new TraceReader<symbol>;
45  trace->Open(qemu_trace_file);
46  trace->ReadKernelSymbols(elf_file);
47  trace->SetRoot(root);
48  TraceHeader *qheader = trace->GetHeader();
49
50  // Get the first valid event to get the process id for the gtrace header.
51  BBEvent event;
52  BBEvent ignored;
53  symbol_type *sym;
54  if (GetNextValidEvent(trace, &event, &ignored, &sym))
55    return 0;
56
57  Gtrace *gtrace = new Gtrace;
58  gtrace->Open(gtrace_file, qheader->pdate, qheader->ptime);
59  gtrace->WriteFirstHeader(qheader->start_sec, event.pid);
60
61  symbol_type *prev_sym = NULL;
62  bool eof = false;
63  while (!eof) {
64    if (sym != prev_sym) {
65      // This procedure is different from the previous procedure.
66
67      // If we have never seen this symbol before, then add it to the
68      // list of known procedures.
69      if (sym->filenum == 0) {
70        sym->filenum = next_filenum;
71        sym->procnum = next_procnum;
72        gtrace->AddProcedure(sym->filenum, sym->procnum, sym->name);
73        next_procnum += 1;
74        if (next_procnum > kMaxProcNum) {
75          next_filenum += 1;
76          next_procnum = 1;
77        }
78      }
79
80      // If we haven't yet recorded the procedure exit for the previous
81      // procedure, then do it now.
82      if (prev_sym) {
83        gtrace->AddProcExit(prev_sym->filenum, prev_sym->procnum, event.time,
84                            event.pid);
85      }
86
87      // If this is not the terminating record, then record a procedure
88      // entry.
89      if (event.bb_num != 0) {
90        gtrace->AddProcEntry(sym->filenum, sym->procnum, event.time, event.pid);
91        prev_sym = sym;
92      }
93    }
94
95    eof = GetNextValidEvent(trace, &event, &ignored, &sym);
96    if (ignored.time != 0 && prev_sym) {
97      // We read an event that we are ignoring.
98      // If we haven't already recorded a procedure exit, then do so.
99      gtrace->AddProcExit(prev_sym->filenum, prev_sym->procnum, ignored.time,
100                          ignored.pid);
101      prev_sym = NULL;
102    }
103  }
104
105  delete gtrace;
106  delete trace;
107  return 0;
108}
109