| #include <stdio.h> |
| #include <unistd.h> |
| #include <stdlib.h> |
| #include <inttypes.h> |
| #include "trace_reader.h" |
| #include "parse_options.h" |
| |
| typedef TraceReader<> TraceReaderType; |
| |
| #include "parse_options-inl.h" |
| |
| struct frame { |
| uint64_t time; |
| uint32_t addr; |
| const char *name; |
| bool isNative; |
| |
| frame(uint64_t time, uint32_t addr, const char *name, bool isNative) { |
| this->time = time; |
| this->addr = addr; |
| this->name = name; |
| this->isNative = isNative; |
| } |
| }; |
| |
| class Stack { |
| static const int kMaxFrames = 1000; |
| int top; |
| frame *frames[kMaxFrames]; |
| |
| public: |
| Stack() { |
| top = 0; |
| } |
| |
| void push(frame *pframe); |
| frame* pop(); |
| void dump(); |
| }; |
| |
| void Stack::push(frame *pframe) { |
| if (top == kMaxFrames) { |
| fprintf(stderr, "Error: stack overflow\n"); |
| exit(1); |
| } |
| frames[top] = pframe; |
| top += 1; |
| } |
| |
| frame *Stack::pop() { |
| if (top <= 0) |
| return NULL; |
| top -= 1; |
| return frames[top]; |
| } |
| |
| void Stack::dump() { |
| frame *pframe; |
| |
| for (int ii = 0; ii < top; ii++) { |
| pframe = frames[ii]; |
| const char *native = pframe->isNative ? "n" : " "; |
| printf(" %s %d: %llu 0x%x %s\n", |
| native, ii, pframe->time, pframe->addr, |
| pframe->name == NULL ? "" : pframe->name); |
| } |
| } |
| |
| static const int kMaxThreads = (32 * 1024); |
| Stack *stacks[kMaxThreads]; |
| |
| void Usage(const char *program) |
| { |
| fprintf(stderr, "Usage: %s [options] trace_name elf_file\n", |
| program); |
| OptionsUsage(); |
| } |
| |
| int main(int argc, char **argv) { |
| ParseOptions(argc, argv); |
| if (argc - optind != 2) { |
| Usage(argv[0]); |
| exit(1); |
| } |
| |
| char *qemu_trace_file = argv[optind++]; |
| char *elf_file = argv[optind++]; |
| TraceReaderType *trace = new TraceReaderType; |
| trace->Open(qemu_trace_file); |
| trace->ReadKernelSymbols(elf_file); |
| trace->SetRoot(root); |
| |
| while (1) { |
| MethodRec method_record; |
| symbol_type *sym; |
| TraceReaderType::ProcessState *proc; |
| frame *pframe; |
| |
| if (trace->ReadMethodSymbol(&method_record, &sym, &proc)) |
| break; |
| |
| if (!IsValidPid(proc->pid)) |
| continue; |
| |
| if (sym != NULL) { |
| printf("%lld p %d 0x%x %d %s\n", |
| method_record.time, proc->pid, method_record.addr, |
| method_record.flags, sym->name); |
| } else { |
| printf("%lld p %d 0x%x %d\n", |
| method_record.time, proc->pid, method_record.addr, |
| method_record.flags); |
| } |
| |
| // Get the stack for the current thread |
| Stack *pStack = stacks[proc->pid]; |
| |
| // If the stack does not exist, then allocate a new one. |
| if (pStack == NULL) { |
| pStack = new Stack(); |
| stacks[proc->pid] = pStack; |
| } |
| |
| int flags = method_record.flags; |
| if (flags == kMethodEnter || flags == kNativeEnter) { |
| pframe = new frame(method_record.time, method_record.addr, |
| sym == NULL ? NULL: sym->name, |
| method_record.flags == kNativeEnter); |
| pStack->push(pframe); |
| } else { |
| pframe = pStack->pop(); |
| delete pframe; |
| } |
| pStack->dump(); |
| } |
| return 0; |
| } |