This now keeps track of the names of the methods on the stack instead of just the addresses. This makes it easier to debug when something goes wrong.
133 lines
3.0 KiB
C++
133 lines
3.0 KiB
C++
#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;
|
|
|
|
frame(uint64_t time, uint32_t addr, const char *name) {
|
|
this->time = time;
|
|
this->addr = addr;
|
|
this->name = name;
|
|
}
|
|
};
|
|
|
|
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];
|
|
printf(" %d: %llu 0x%x %s\n",
|
|
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;
|
|
}
|
|
|
|
if (method_record.flags == 0) {
|
|
pframe = new frame(method_record.time, method_record.addr,
|
|
sym == NULL ? NULL: sym->name);
|
|
pStack->push(pframe);
|
|
} else {
|
|
pframe = pStack->pop();
|
|
delete pframe;
|
|
}
|
|
pStack->dump();
|
|
}
|
|
return 0;
|
|
}
|