1#include <stdio.h>
2#include <unistd.h>
3#include <stdlib.h>
4#include <inttypes.h>
5#include <assert.h>
6#include "trace_reader.h"
7#include "parse_options.h"
8
9typedef TraceReader<> TraceReaderType;
10
11#include "parse_options-inl.h"
12
13struct MyStaticRec {
14    StaticRec   bb;
15    symbol_type *sym;
16    MyStaticRec *inner;    // pointer to an inner basic block
17    int         is_thumb;
18};
19
20MyStaticRec **assign_inner_blocks(int num_blocks, MyStaticRec *blocks);
21
22void Usage(const char *program)
23{
24    fprintf(stderr, "Usage: %s [options] trace_file elf_file\n", program);
25    OptionsUsage();
26}
27
28// This function is called from quicksort to compare addresses of basic
29// blocks.
30int cmp_inc_addr(const void *a, const void *b) {
31    MyStaticRec *bb1, *bb2;
32
33    bb1 = *(MyStaticRec**)a;
34    bb2 = *(MyStaticRec**)b;
35    if (bb1->bb.bb_addr < bb2->bb.bb_addr)
36        return -1;
37    if (bb1->bb.bb_addr > bb2->bb.bb_addr)
38        return 1;
39    return bb1->bb.bb_num - bb2->bb.bb_num;
40}
41
42int main(int argc, char **argv) {
43    uint32_t insns[kMaxInsnPerBB];
44
45    // Parse the options
46    ParseOptions(argc, argv);
47    if (argc - optind != 2) {
48        Usage(argv[0]);
49        exit(1);
50    }
51
52    char *trace_filename = argv[optind++];
53    char *elf_file = argv[optind++];
54    TraceReader<> *trace = new TraceReader<>;
55    trace->Open(trace_filename);
56    trace->ReadKernelSymbols(elf_file);
57    trace->SetRoot(root);
58
59    TraceHeader *header = trace->GetHeader();
60    uint32_t num_static_bb = header->num_static_bb;
61
62    // Allocate space for all of the static blocks
63    MyStaticRec *blocks = new MyStaticRec[num_static_bb];
64
65    // Read in all the static blocks
66    for (uint32_t ii = 0; ii < num_static_bb; ++ii) {
67        trace->ReadStatic(&blocks[ii].bb);
68        blocks[ii].is_thumb = blocks[ii].bb.bb_addr & 1;
69        blocks[ii].bb.bb_addr &= ~1;
70        blocks[ii].sym = NULL;
71        blocks[ii].inner = NULL;
72        trace->ReadStaticInsns(blocks[ii].bb.num_insns, insns);
73    }
74
75    MyStaticRec **sorted = assign_inner_blocks(num_static_bb, blocks);
76
77    while (1) {
78        symbol_type *sym;
79        BBEvent event;
80        BBEvent ignored;
81
82        if (GetNextValidEvent(trace, &event, &ignored, &sym))
83            break;
84
85        uint64_t bb_num = event.bb_num;
86        blocks[bb_num].sym = sym;
87    }
88
89    printf("#     bb num_insns     bb_addr file  symbol\n");
90    for (uint32_t ii = 0; ii < num_static_bb; ++ii) {
91        if (sorted[ii]->bb.bb_addr == 0 || sorted[ii]->bb.num_insns == 0
92            || sorted[ii]->sym == NULL)
93            continue;
94
95        printf("%8lld       %3d  0x%08x %s %s\n",
96               sorted[ii]->bb.bb_num, sorted[ii]->bb.num_insns,
97               sorted[ii]->bb.bb_addr, sorted[ii]->sym->region->path,
98               sorted[ii]->sym->name);
99    }
100    return 0;
101}
102
103// Find the basic blocks that are subsets of other basic blocks.
104MyStaticRec **assign_inner_blocks(int num_blocks, MyStaticRec *blocks)
105{
106    int ii;
107    uint32_t addr_end, addr_diff;
108
109    // Create a list of pointers to the basic blocks that we can sort.
110    MyStaticRec **sorted = new MyStaticRec*[num_blocks];
111    for (ii = 0; ii < num_blocks; ++ii) {
112        sorted[ii] = &blocks[ii];
113    }
114
115    // Sort the basic blocks into increasing address order
116    qsort(sorted, num_blocks, sizeof(MyStaticRec*), cmp_inc_addr);
117
118    // Create pointers to inner blocks and break up the enclosing block
119    // so that there is no overlap.
120    for (ii = 0; ii < num_blocks - 1; ++ii) {
121        int num_bytes;
122        if (sorted[ii]->is_thumb)
123            num_bytes = sorted[ii]->bb.num_insns << 1;
124        else
125            num_bytes = sorted[ii]->bb.num_insns << 2;
126        addr_end = sorted[ii]->bb.bb_addr + num_bytes;
127        if (addr_end > sorted[ii + 1]->bb.bb_addr) {
128            sorted[ii]->inner = sorted[ii + 1];
129            addr_diff = sorted[ii + 1]->bb.bb_addr - sorted[ii]->bb.bb_addr;
130            uint32_t num_insns;
131            if (sorted[ii]->is_thumb)
132                num_insns = addr_diff >> 1;
133            else
134                num_insns = addr_diff >> 2;
135            sorted[ii]->bb.num_insns = num_insns;
136        }
137    }
138
139    return sorted;
140}
141