Home | History | Annotate | Download | only in qtools
      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 
      9 typedef TraceReader<> TraceReaderType;
     10 
     11 #include "parse_options-inl.h"
     12 
     13 struct MyStaticRec {
     14     StaticRec   bb;
     15     symbol_type *sym;
     16     MyStaticRec *inner;    // pointer to an inner basic block
     17     int         is_thumb;
     18 };
     19 
     20 MyStaticRec **assign_inner_blocks(int num_blocks, MyStaticRec *blocks);
     21 
     22 void 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.
     30 int 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 
     42 int 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.
    104 MyStaticRec **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