aboutsummaryrefslogtreecommitdiffstats
path: root/emulator/qtools/bb2sym.cpp
blob: 8a18b672cd4cbeb09a7238cbf502332d1e0a6161 (plain)
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
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <inttypes.h>
#include <assert.h>
#include "trace_reader.h"
#include "parse_options.h"

typedef TraceReader<> TraceReaderType;

#include "parse_options-inl.h"

struct MyStaticRec {
    StaticRec   bb;
    symbol_type *sym;
    MyStaticRec *inner;    // pointer to an inner basic block
    int         is_thumb;
};

MyStaticRec **assign_inner_blocks(int num_blocks, MyStaticRec *blocks);

void Usage(const char *program)
{
    fprintf(stderr, "Usage: %s [options] trace_file elf_file\n", program);
    OptionsUsage();
}

// This function is called from quicksort to compare addresses of basic
// blocks.
int cmp_inc_addr(const void *a, const void *b) {
    MyStaticRec *bb1, *bb2;

    bb1 = *(MyStaticRec**)a;
    bb2 = *(MyStaticRec**)b;
    if (bb1->bb.bb_addr < bb2->bb.bb_addr)
        return -1;
    if (bb1->bb.bb_addr > bb2->bb.bb_addr)
        return 1;
    return bb1->bb.bb_num - bb2->bb.bb_num;
}

int main(int argc, char **argv) {
    uint32_t insns[kMaxInsnPerBB];

    // Parse the options
    ParseOptions(argc, argv);
    if (argc - optind != 2) {
        Usage(argv[0]);
        exit(1);
    }

    char *trace_filename = argv[optind++];
    char *elf_file = argv[optind++];
    TraceReader<> *trace = new TraceReader<>;
    trace->Open(trace_filename);
    trace->ReadKernelSymbols(elf_file);
    trace->SetRoot(root);

    TraceHeader *header = trace->GetHeader();
    uint32_t num_static_bb = header->num_static_bb;

    // Allocate space for all of the static blocks
    MyStaticRec *blocks = new MyStaticRec[num_static_bb];

    // Read in all the static blocks
    for (uint32_t ii = 0; ii < num_static_bb; ++ii) {
        trace->ReadStatic(&blocks[ii].bb);
        blocks[ii].is_thumb = blocks[ii].bb.bb_addr & 1;
        blocks[ii].bb.bb_addr &= ~1;
        blocks[ii].sym = NULL;
        blocks[ii].inner = NULL;
        trace->ReadStaticInsns(blocks[ii].bb.num_insns, insns);
    }

    MyStaticRec **sorted = assign_inner_blocks(num_static_bb, blocks);

    while (1) {
        symbol_type *sym;
        BBEvent event;
        BBEvent ignored;

        if (GetNextValidEvent(trace, &event, &ignored, &sym))
            break;

        uint64_t bb_num = event.bb_num;
        blocks[bb_num].sym = sym;
    }
        
    printf("#     bb num_insns     bb_addr file  symbol\n");
    for (uint32_t ii = 0; ii < num_static_bb; ++ii) {
        if (sorted[ii]->bb.bb_addr == 0 || sorted[ii]->bb.num_insns == 0
            || sorted[ii]->sym == NULL)
            continue;

        printf("%8lld       %3d  0x%08x %s %s\n",
               sorted[ii]->bb.bb_num, sorted[ii]->bb.num_insns,
               sorted[ii]->bb.bb_addr, sorted[ii]->sym->region->path,
               sorted[ii]->sym->name);
    }
    return 0;
}

// Find the basic blocks that are subsets of other basic blocks.
MyStaticRec **assign_inner_blocks(int num_blocks, MyStaticRec *blocks)
{
    int ii;
    uint32_t addr_end, addr_diff;

    // Create a list of pointers to the basic blocks that we can sort.
    MyStaticRec **sorted = new MyStaticRec*[num_blocks];
    for (ii = 0; ii < num_blocks; ++ii) {
        sorted[ii] = &blocks[ii];
    }

    // Sort the basic blocks into increasing address order
    qsort(sorted, num_blocks, sizeof(MyStaticRec*), cmp_inc_addr);

    // Create pointers to inner blocks and break up the enclosing block
    // so that there is no overlap.
    for (ii = 0; ii < num_blocks - 1; ++ii) {
        int num_bytes;
        if (sorted[ii]->is_thumb)
            num_bytes = sorted[ii]->bb.num_insns << 1;
        else
            num_bytes = sorted[ii]->bb.num_insns << 2;
        addr_end = sorted[ii]->bb.bb_addr + num_bytes;
        if (addr_end > sorted[ii + 1]->bb.bb_addr) {
            sorted[ii]->inner = sorted[ii + 1];
            addr_diff = sorted[ii + 1]->bb.bb_addr - sorted[ii]->bb.bb_addr;
            uint32_t num_insns;
            if (sorted[ii]->is_thumb)
                num_insns = addr_diff >> 1;
            else
                num_insns = addr_diff >> 2;
            sorted[ii]->bb.num_insns = num_insns;
        }
    }

    return sorted;
}