1#include <stdio.h>
2#include <unistd.h>
3#include <stdlib.h>
4#include <inttypes.h>
5#include "trace_reader.h"
6#include "parse_options.h"
7
8typedef TraceReader<> TraceReaderType;
9
10#include "parse_options-inl.h"
11
12struct frame {
13    uint64_t    time;
14    uint32_t    addr;
15    const char  *name;
16    bool        isNative;
17
18    frame(uint64_t time, uint32_t addr, const char *name, bool isNative) {
19        this->time = time;
20        this->addr = addr;
21        this->name = name;
22        this->isNative = isNative;
23    }
24};
25
26class Stack {
27    static const int kMaxFrames = 1000;
28    int top;
29    frame *frames[kMaxFrames];
30
31public:
32    Stack() {
33        top = 0;
34    }
35
36    void        push(frame *pframe);
37    frame*      pop();
38    void        dump();
39};
40
41void Stack::push(frame *pframe) {
42    if (top == kMaxFrames) {
43        fprintf(stderr, "Error: stack overflow\n");
44        exit(1);
45    }
46    frames[top] = pframe;
47    top += 1;
48}
49
50frame *Stack::pop() {
51    if (top <= 0)
52        return NULL;
53    top -= 1;
54    return frames[top];
55}
56
57void Stack::dump() {
58    frame *pframe;
59
60    for (int ii = 0; ii < top; ii++) {
61        pframe = frames[ii];
62        const char *native = pframe->isNative ? "n" : " ";
63        printf(" %s %d: %llu 0x%x %s\n",
64               native, ii, pframe->time, pframe->addr,
65               pframe->name == NULL ? "" : pframe->name);
66    }
67}
68
69static const int kMaxThreads = (32 * 1024);
70Stack *stacks[kMaxThreads];
71
72void Usage(const char *program)
73{
74    fprintf(stderr, "Usage: %s [options] trace_name elf_file\n",
75            program);
76    OptionsUsage();
77}
78
79int main(int argc, char **argv) {
80    ParseOptions(argc, argv);
81    if (argc - optind != 2) {
82        Usage(argv[0]);
83        exit(1);
84    }
85
86    char *qemu_trace_file = argv[optind++];
87    char *elf_file = argv[optind++];
88    TraceReaderType *trace = new TraceReaderType;
89    trace->Open(qemu_trace_file);
90    trace->ReadKernelSymbols(elf_file);
91    trace->SetRoot(root);
92
93    while (1) {
94        MethodRec method_record;
95        symbol_type *sym;
96        TraceReaderType::ProcessState *proc;
97        frame *pframe;
98
99        if (trace->ReadMethodSymbol(&method_record, &sym, &proc))
100            break;
101
102        if (!IsValidPid(proc->pid))
103            continue;
104
105        if (sym != NULL) {
106            printf("%lld p %d 0x%x %d %s\n",
107                   method_record.time, proc->pid, method_record.addr,
108                   method_record.flags, sym->name);
109        } else {
110            printf("%lld p %d 0x%x %d\n",
111                   method_record.time, proc->pid, method_record.addr,
112                   method_record.flags);
113        }
114
115        // Get the stack for the current thread
116        Stack *pStack = stacks[proc->pid];
117
118        // If the stack does not exist, then allocate a new one.
119        if (pStack == NULL) {
120            pStack = new Stack();
121            stacks[proc->pid] = pStack;
122        }
123
124        int flags = method_record.flags;
125        if (flags == kMethodEnter || flags == kNativeEnter) {
126            pframe = new frame(method_record.time, method_record.addr,
127                               sym == NULL ? NULL: sym->name,
128                               method_record.flags == kNativeEnter);
129            pStack->push(pframe);
130        } else {
131            pframe = pStack->pop();
132            delete pframe;
133        }
134        pStack->dump();
135    }
136    return 0;
137}
138