1 // Copyright 2006 The Android Open Source Project 2 3 #include <stdio.h> 4 #include <unistd.h> 5 #include <stdlib.h> 6 #include <inttypes.h> 7 #include <assert.h> 8 #include "trace_reader.h" 9 #include "bitvector.h" 10 #include "parse_options.h" 11 #include "dmtrace.h" 12 #include "armdis.h" 13 14 struct symbol { 15 uint32_t id; 16 }; 17 18 typedef TraceReader<symbol> TraceReaderType; 19 20 #include "parse_options-inl.h" 21 #include "callstack.h" 22 23 DmTrace *dmtrace; 24 25 class MyFrame : public StackFrame<symbol_type> { 26 public: 27 void push(int stackLevel, uint64_t time, CallStackBase *base); 28 void pop(int stackLevel, uint64_t time, CallStackBase *base); 29 }; 30 31 typedef CallStack<MyFrame> CallStackType; 32 33 static const int kNumStackFrames = 500; 34 static const int kMaxThreads = (32 * 1024); 35 uint64_t thread_time[kMaxThreads]; 36 37 class FunctionStack { 38 public: 39 FunctionStack() { 40 top = 0; 41 } 42 void push(symbol_type *sym) { 43 if (top >= kNumStackFrames) 44 return; 45 frames[top] = sym; 46 top += 1; 47 } 48 49 symbol_type* pop() { 50 if (top <= 0) { 51 return NULL; 52 } 53 top -= 1; 54 return frames[top]; 55 } 56 57 void showStack() { 58 fprintf(stderr, "top %d\n", top); 59 for (int ii = 0; ii < top; ii++) { 60 fprintf(stderr, " %d: %s\n", ii, frames[ii]->name); 61 } 62 } 63 64 private: 65 int top; 66 symbol_type *frames[kNumStackFrames]; 67 }; 68 69 FunctionStack *dmtrace_stack[kMaxThreads]; 70 71 void MyFrame::push(int stackLevel, uint64_t time, CallStackBase *base) 72 { 73 int pid = base->getId(); 74 CallStackType *stack = (CallStackType *) base; 75 76 #if 0 77 fprintf(stderr, "native push t %llu p %d s %d fid %d 0x%x %s\n", 78 stack->getGlobalTime(time), pid, stackLevel, 79 function->id, function->addr, function->name); 80 #endif 81 82 FunctionStack *fstack = dmtrace_stack[pid]; 83 if (fstack == NULL) { 84 fstack = new FunctionStack(); 85 dmtrace_stack[pid] = fstack; 86 } 87 88 fstack->push(function); 89 thread_time[pid] = time; 90 dmtrace->addFunctionEntry(function->id, time, pid); 91 } 92 93 void MyFrame::pop(int stackLevel, uint64_t time, CallStackBase *base) 94 { 95 int pid = base->getId(); 96 CallStackType *stack = (CallStackType *) base; 97 98 #if 0 99 fprintf(stderr, "native pop t %llu p %d s %d fid %d 0x%x %s\n", 100 stack->getGlobalTime(time), pid, stackLevel, 101 function->id, function->addr, function->name); 102 #endif 103 104 FunctionStack *fstack = dmtrace_stack[pid]; 105 if (fstack == NULL) { 106 fstack = new FunctionStack(); 107 dmtrace_stack[pid] = fstack; 108 } 109 110 symbol_type *sym = fstack->pop(); 111 if (sym != NULL && sym != function) { 112 fprintf(stderr, "Error: q2dm function mismatch at time %llu pid %d sym %s\n", 113 stack->getGlobalTime(time), pid, sym->name); 114 fstack->showStack(); 115 exit(1); 116 } 117 118 thread_time[pid] = time; 119 dmtrace->addFunctionExit(function->id, time, pid); 120 } 121 122 uint32_t nextFunctionId = 4; 123 CallStackType *stacks[kMaxThreads]; 124 125 void Usage(const char *program) 126 { 127 fprintf(stderr, "Usage: %s [options] trace_name elf_file dmtrace_name\n", 128 program); 129 OptionsUsage(); 130 } 131 132 int main(int argc, char **argv) 133 { 134 bool useKernelStack = true; 135 136 ParseOptions(argc, argv); 137 if (argc - optind != 3) { 138 Usage(argv[0]); 139 exit(1); 140 } 141 142 char *qemu_trace_file = argv[optind++]; 143 char *elf_file = argv[optind++]; 144 char *dmtrace_file = argv[optind++]; 145 TraceReaderType *trace = new TraceReaderType; 146 trace->Open(qemu_trace_file); 147 trace->SetDemangle(demangle); 148 trace->ReadKernelSymbols(elf_file); 149 trace->SetRoot(root); 150 TraceHeader *qheader = trace->GetHeader(); 151 uint64_t startTime = qheader->start_sec; 152 startTime = (startTime << 32) | qheader->start_usec; 153 int kernelPid = qheader->first_unused_pid; 154 155 dmtrace = new DmTrace; 156 dmtrace->open(dmtrace_file, startTime); 157 158 bool inKernel = false; 159 CallStackType *kernelStack = NULL; 160 if (useKernelStack) { 161 // Create a fake kernel thread stack where we will put all the kernel 162 // code. 163 kernelStack = new CallStackType(kernelPid, kNumStackFrames, trace); 164 dmtrace->addThread(kernelPid, "(kernel)"); 165 } 166 167 CallStackType *prevStack = NULL; 168 BBEvent event; 169 while (1) { 170 BBEvent ignored; 171 symbol_type *function; 172 173 if (GetNextValidEvent(trace, &event, &ignored, &function)) 174 break; 175 if (event.bb_num == 0) 176 break; 177 #if 0 178 fprintf(stderr, "event t %llu p %d %s\n", 179 event.time, event.pid, function->name); 180 #endif 181 182 CallStackType *pStack; 183 if (useKernelStack) { 184 uint32_t flags = function->region->flags; 185 uint32_t region_mask = region_type::kIsKernelRegion 186 | region_type::kIsUserMappedRegion; 187 if ((flags & region_mask) == region_type::kIsKernelRegion) { 188 // Use the kernel stack 189 pStack = kernelStack; 190 inKernel = true; 191 } else { 192 // If we were just in the kernel then pop off all of the 193 // stack frames for the kernel thread. 194 if (inKernel == true) { 195 inKernel = false; 196 kernelStack->popAll(event.time); 197 } 198 199 // Get the stack for the current thread 200 pStack = stacks[event.pid]; 201 } 202 } else { 203 // Get the stack for the current thread 204 pStack = stacks[event.pid]; 205 } 206 207 // If the stack does not exist, then allocate a new one. 208 if (pStack == NULL) { 209 pStack = new CallStackType(event.pid, kNumStackFrames, trace); 210 stacks[event.pid] = pStack; 211 const char *name = trace->GetProcessName(event.pid); 212 dmtrace->addThread(event.pid, name); 213 } 214 215 if (prevStack != pStack) { 216 pStack->threadStart(event.time); 217 if (prevStack) 218 prevStack->threadStop(event.time); 219 } 220 prevStack = pStack; 221 222 // If we have never seen this function before, then add it to the 223 // list of known functions. 224 if (function->id == 0) { 225 function->id = nextFunctionId; 226 nextFunctionId += 4; 227 uint32_t flags = function->region->flags; 228 const char *name = function->name; 229 if (flags & region_type::kIsKernelRegion) { 230 // To distinguish kernel function names from user library 231 // names, add a marker to the name. 232 int len = strlen(name) + strlen(" [kernel]") + 1; 233 char *kernelName = new char[len]; 234 strcpy(kernelName, name); 235 strcat(kernelName, " [kernel]"); 236 name = kernelName; 237 } 238 dmtrace->parseAndAddFunction(function->id, name); 239 } 240 241 // Update the stack 242 pStack->updateStack(&event, function); 243 } 244 245 if (prevStack == NULL) { 246 fprintf(stderr, "Error: no events in trace.\n"); 247 exit(1); 248 } 249 prevStack->threadStop(event.time); 250 for (int ii = 0; ii < kMaxThreads; ++ii) { 251 if (stacks[ii]) { 252 stacks[ii]->threadStart(event.time); 253 stacks[ii]->popAll(event.time); 254 } 255 } 256 if (useKernelStack) { 257 kernelStack->popAll(event.time); 258 } 259 260 // Read the pid events to find the names of the processes 261 while (1) { 262 PidEvent pid_event; 263 if (trace->ReadPidEvent(&pid_event)) 264 break; 265 if (pid_event.rec_type == kPidName) { 266 dmtrace->updateName(pid_event.pid, pid_event.path); 267 } 268 } 269 270 dmtrace->close(); 271 delete dmtrace; 272 delete trace; 273 return 0; 274 } 275