So that we don't need to send the same frames over and over again.
size_t bufSize;
void (*dumpBacktrace)(const DebugOutputTarget*, void*);
DebugOutputTarget debugTarget;
+ Id nextFrameId;
public:
DalvikBacktraceProvider() {
+ nextFrameId = 0;
FILE* (*open_memstream_exp)(char**, size_t*);
void (*createDebugTarget)(DebugOutputTarget*, FILE*);
void* handle = dlopen("/system/lib/libdvm.so", 0);
char* rawBacktrace_it = rawBacktrace;
while (*rawBacktrace_it != '\0') {
RawStackFrame stackFrame;
+ // TODO: Keep a cache of stack frames
+ stackFrame->id = nextFrameId++;
/* skip leading space */
while (*rawBacktrace_it == ' ') {
rawBacktrace_it++;
* functions on the stack to avoid recording these frames.
*/
int numOfNestedFunctions;
+ Id nextFrameId;
private:
/*
* Parse a stack frame, expecting:
char* frame_symbol_copy = new char[strlen(frame_symbol) + 1];
strcpy(frame_symbol_copy, frame_symbol);
RawStackFrame* parsedFrame = new RawStackFrame;
+ parsedFrame->id = nextFrameId++;
char* frame_it = frame_symbol_copy;
parsedFrame->module = frame_it;
char* offset = NULL;
}
public:
GlibcBacktraceProvider() :
- numOfNestedFunctions(0) {
- }
+ numOfNestedFunctions(0),
+ nextFrameId(0)
+ {}
+
std::vector<RawStackFrame> getParsedBacktrace() {
std::vector<RawStackFrame> parsedBacktrace;
void *array[numOfNestedFunctions + BT_DEPTH];
void visit(Backtrace & backtrace) {
for (int i = 0; i < backtrace.size(); i ++) {
- visit(&backtrace[i]);
+ visit(backtrace[i]);
os << "\n";
}
}
* | OPAQUE int
* | REPR value value
*
- * frame = frame_detail+
+ * frame = id frame_detail+
+ * | id
*
* frame_detail = MODULE string
* | FUNCTION string
};
struct RawStackFrame {
+ Id id;
const char * module;
const char * function;
const char * filename;
~StackFrame();
};
-typedef std::vector<StackFrame> Backtrace;
+typedef std::vector<StackFrame *> Backtrace;
class Visitor
{
}
sig->arg_names = arg_names;
sig->flags = lookupCallFlags(sig->name);
- sig->offset = file->currentOffset();
+ sig->fileOffset = file->currentOffset();
functions[id] = sig;
/**
glGetErrorSig = sig;
}
- } else if (file->currentOffset() < sig->offset) {
+ } else if (file->currentOffset() < sig->fileOffset) {
/* skip over the signature */
skip_string(); /* name */
unsigned num_args = read_uint();
member_names[i] = read_string();
}
sig->member_names = member_names;
- sig->offset = file->currentOffset();
+ sig->fileOffset = file->currentOffset();
structs[id] = sig;
- } else if (file->currentOffset() < sig->offset) {
+ } else if (file->currentOffset() < sig->fileOffset) {
/* skip over the signature */
skip_string(); /* name */
unsigned num_members = read_uint();
values->name = read_string();
values->value = read_sint();
sig->values = values;
- sig->offset = file->currentOffset();
+ sig->fileOffset = file->currentOffset();
enums[id] = sig;
- } else if (file->currentOffset() < sig->offset) {
+ } else if (file->currentOffset() < sig->fileOffset) {
/* skip over the signature */
skip_string(); /*name*/
scan_value();
it->value = read_sint();
}
sig->values = values;
- sig->offset = file->currentOffset();
+ sig->fileOffset = file->currentOffset();
enums[id] = sig;
- } else if (file->currentOffset() < sig->offset) {
+ } else if (file->currentOffset() < sig->fileOffset) {
/* skip over the signature */
int num_values = read_uint();
for (int i = 0; i < num_values; ++i) {
}
}
sig->flags = flags;
- sig->offset = file->currentOffset();
+ sig->fileOffset = file->currentOffset();
bitmasks[id] = sig;
- } else if (file->currentOffset() < sig->offset) {
+ } else if (file->currentOffset() < sig->fileOffset) {
/* skip over the signature */
int num_flags = read_uint();
for (int i = 0; i < num_flags; ++i) {
unsigned num_frames = read_uint();
Backtrace* backtrace = new Backtrace(num_frames);
for (unsigned i = 0; i < num_frames; ++i) {
- parse_backtrace_frame(&(*backtrace)[i], mode);
+ (*backtrace)[i] = parse_backtrace_frame(mode);
}
call->backtrace = backtrace;
return true;
}
-bool Parser::parse_backtrace_frame(StackFrame *frame, Mode mode) {
- do {
+StackFrame * Parser::parse_backtrace_frame(Mode mode) {
+ size_t id = read_uint();
+
+ StackFrameState *frame = lookup(frames, id);
+
+ if (!frame) {
+ frame = new StackFrameState;
int c = read_byte();
- switch (c) {
- case trace::BACKTRACE_END:
- return true;
- case trace::BACKTRACE_MODULE:
- frame->module = read_string();
- break;
- case trace::BACKTRACE_FUNCTION:
- frame->function = read_string();
- break;
- case trace::BACKTRACE_FILENAME:
- frame->filename = read_string();
- break;
- case trace::BACKTRACE_LINENUMBER:
- frame->linenumber = read_uint();
- break;
- case trace::BACKTRACE_OFFSET:
- frame->offset = read_uint();
- break;
- default:
- std::cerr << "error: unknown backtrace detail "
- << c << "\n";
- exit(1);
- case -1:
- return false;
+ while (c != trace::BACKTRACE_END &&
+ c != -1) {
+ switch (c) {
+ case trace::BACKTRACE_MODULE:
+ frame->module = read_string();
+ break;
+ case trace::BACKTRACE_FUNCTION:
+ frame->function = read_string();
+ break;
+ case trace::BACKTRACE_FILENAME:
+ frame->filename = read_string();
+ break;
+ case trace::BACKTRACE_LINENUMBER:
+ frame->linenumber = read_uint();
+ break;
+ case trace::BACKTRACE_OFFSET:
+ frame->offset = read_uint();
+ break;
+ default:
+ std::cerr << "error: unknown backtrace detail "
+ << c << "\n";
+ exit(1);
+ }
+ c = read_byte();
}
- } while(true);
+
+ frame->fileOffset = file->currentOffset();
+ frames[id] = frame;
+ } else if (file->currentOffset() < frame->fileOffset) {
+ int c = read_byte();
+ while (c != trace::BACKTRACE_END &&
+ c != -1) {
+ switch (c) {
+ case trace::BACKTRACE_MODULE:
+ scan_string();
+ break;
+ case trace::BACKTRACE_FUNCTION:
+ scan_string();
+ break;
+ case trace::BACKTRACE_FILENAME:
+ scan_string();
+ break;
+ case trace::BACKTRACE_LINENUMBER:
+ scan_uint();
+ break;
+ case trace::BACKTRACE_OFFSET:
+ scan_uint();
+ break;
+ default:
+ std::cerr << "error: unknown backtrace detail "
+ << c << "\n";
+ exit(1);
+ }
+ c = read_byte();
+ }
+ }
+
+ return frame;
}
/**
// Offset in the file of where signature was defined. It is used when
// reparsing to determine whether the signature definition is to be
// expected next or not.
- File::Offset offset;
+ File::Offset fileOffset;
};
typedef SigState<FunctionSigFlags> FunctionSigState;
typedef SigState<StructSig> StructSigState;
typedef SigState<EnumSig> EnumSigState;
typedef SigState<BitmaskSig> BitmaskSigState;
+ typedef SigState<StackFrame> StackFrameState;
typedef std::vector<FunctionSigState *> FunctionMap;
typedef std::vector<StructSigState *> StructMap;
typedef std::vector<EnumSigState *> EnumMap;
typedef std::vector<BitmaskSigState *> BitmaskMap;
+ typedef std::vector<StackFrameState *> StackFrameMap;
FunctionMap functions;
StructMap structs;
EnumMap enums;
BitmaskMap bitmasks;
+ StackFrameMap frames;
FunctionSig *glGetErrorSig;
bool parse_call_details(Call *call, Mode mode);
bool parse_call_backtrace(Call *call, Mode mode);
- bool parse_backtrace_frame(StackFrame *frame, Mode mode);
+ StackFrame * parse_backtrace_frame(Mode mode);
void adjust_call_flags(Call *call);
structs.clear();
enums.clear();
bitmasks.clear();
+ frames.clear();
_writeUInt(TRACE_VERSION);
}
}
-void Writer::writeStackFrame(const RawStackFrame &frame) {
- if (frame.module != NULL) {
- _writeByte(trace::BACKTRACE_MODULE);
- _writeString(frame.module);
- }
- if (frame.function != NULL) {
- _writeByte(trace::BACKTRACE_FUNCTION);
- _writeString(frame.function);
- }
- if (frame.filename != NULL) {
- _writeByte(trace::BACKTRACE_FILENAME);
- _writeString(frame.filename);
- }
- if (frame.linenumber >= 0) {
- _writeByte(trace::BACKTRACE_LINENUMBER);
- _writeUInt(frame.linenumber);
- }
- if (frame.offset >= 0) {
- _writeByte(trace::BACKTRACE_OFFSET);
- _writeUInt(frame.offset);
+void Writer::writeStackFrame(const RawStackFrame *frame) {
+ _writeUInt(frame->id);
+ if (!lookup(frames, frame->id)) {
+ if (frame->module != NULL) {
+ _writeByte(trace::BACKTRACE_MODULE);
+ _writeString(frame->module);
+ }
+ if (frame->function != NULL) {
+ _writeByte(trace::BACKTRACE_FUNCTION);
+ _writeString(frame->function);
+ }
+ if (frame->filename != NULL) {
+ _writeByte(trace::BACKTRACE_FILENAME);
+ _writeString(frame->filename);
+ }
+ if (frame->linenumber >= 0) {
+ _writeByte(trace::BACKTRACE_LINENUMBER);
+ _writeUInt(frame->linenumber);
+ }
+ if (frame->offset >= 0) {
+ _writeByte(trace::BACKTRACE_OFFSET);
+ _writeUInt(frame->offset);
+ }
+ _writeByte(trace::BACKTRACE_END);
+ frames[frame->id] = true;
}
- _writeByte(trace::BACKTRACE_END);
}
unsigned Writer::beginEnter(const FunctionSig *sig, unsigned thread_id) {
std::vector<bool> structs;
std::vector<bool> enums;
std::vector<bool> bitmasks;
+ std::vector<bool> frames;
public:
Writer();
inline void endReturn(void) {}
void beginBacktrace(unsigned num_frames);
- void writeStackFrame(const RawStackFrame &frame);
+ void writeStackFrame(const RawStackFrame *frame);
inline void endBacktrace(void) {}
void beginArray(size_t length);
std::vector<RawStackFrame> backtrace = get_backtrace();
beginBacktrace(backtrace.size());
for (unsigned i = 0; i < backtrace.size(); ++i) {
- writeStackFrame(backtrace[i]);
+ writeStackFrame(&backtrace[i]);
}
endBacktrace();
}
if (call->backtrace != NULL) {
QString qbacktrace;
for (int i = 0; i < call->backtrace->size(); i++) {
- const trace::StackFrame & frame = (*call->backtrace)[i];
- if (frame.module != NULL) {
- qbacktrace += QString("%1 ").arg(frame.module);
+ const trace::StackFrame * frame = (*call->backtrace)[i];
+ if (frame->module != NULL) {
+ qbacktrace += QString("%1 ").arg(frame->module);
}
- if (frame.function != NULL) {
- qbacktrace += QString("at %1() ").arg(frame.function);
+ if (frame->function != NULL) {
+ qbacktrace += QString("at %1() ").arg(frame->function);
}
- if (frame.filename != NULL) {
- qbacktrace += QString("at %1").arg(frame.filename);
- if (frame.linenumber >= 0) {
- qbacktrace += QString(":%1 ").arg(frame.linenumber);
+ if (frame->filename != NULL) {
+ qbacktrace += QString("at %1").arg(frame->filename);
+ if (frame->linenumber >= 0) {
+ qbacktrace += QString(":%1 ").arg(frame->linenumber);
}
}
else {
- if (frame.offset >= 0) {
- qbacktrace += QString("[0x%1]").arg(frame.offset, 0, 16);
+ if (frame->offset >= 0) {
+ qbacktrace += QString("[0x%1]").arg(frame->offset, 0, 16);
}
}
qbacktrace += "\n";