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