From aa1b2136cc72893e519ff73c47e2ecd29cafe1da Mon Sep 17 00:00:00 2001 From: Eugene Velesevich Date: Tue, 23 Apr 2013 17:56:14 +0400 Subject: Backtrace via call detail Hello, Changes from v3: Instead of writing the backtrace as Array, the backtrace is now recorded as a list of stack frame nodes with optional stack frame details (the scheme is below). This patch implements backtrace recording during tracing, and adds support in 'apitrace dump' and QApitrace. Backtrace is obtained via platform-specific functions (and, internally, in platform-specific format). Then it is parsed to produce an std::vector of stack frame structs: { char *module, *function, *filename, *linenumber, *offset } (some fields may be NULL) and is written into the trace file in the Enter call section as a call detail: BACKTRACE FRAME MODULE "module" FUNCTION "Foo" FILENAME "foo.cpp" LINENUMBER "1234" OFFSET "0xSDF" FRAME FUNCTION "Boo" // no filename line info available for this frame END_BACKTRACE A platform-dependent mechanism is provided to specify a set of traced calls for which backtraces will be recorded. It is possible to specify either function names, or prefixes of names by appending a '*' (e.g. "glUniform*"). On Android the backtrace is retrieved from Dalvik via libdvm functions imported at runtime. Function set is specified in /data/apitrace.fnames, one per line. On Linux the backtrace is retrieved via glibc backtrace(), and will not always yield filename:linenumber information. Function set is specified via APITRACE_BT_FUNCTIONS environment variable. On other platforms, obtaining a backtrace is not implemented by this patch. --- wrappers/gltrace.py | 2 +- wrappers/trace.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'wrappers') diff --git a/wrappers/gltrace.py b/wrappers/gltrace.py index c40fbb36..fcb48bba 100644 --- a/wrappers/gltrace.py +++ b/wrappers/gltrace.py @@ -520,7 +520,7 @@ class GlTracer(Tracer): # Emit a fake function print ' {' - print ' static const trace::FunctionSig &_sig = %s ? _glEnableClientState_sig : _glDisableClientState_sig;' % flag_name + print ' static trace::FunctionSig &_sig = %s ? _glEnableClientState_sig : _glDisableClientState_sig;' % flag_name print ' unsigned _call = trace::localWriter.beginEnter(&_sig);' print ' trace::localWriter.beginArg(0);' self.serializeValue(glapi.GLenum, enable_name) diff --git a/wrappers/trace.py b/wrappers/trace.py index d9c29009..9ff54104 100644 --- a/wrappers/trace.py +++ b/wrappers/trace.py @@ -452,7 +452,7 @@ class Tracer: print 'static const char * _%s_args[%u] = {%s};' % (function.name, len(function.args), ', '.join(['"%s"' % arg.name for arg in function.args])) else: print 'static const char ** _%s_args = NULL;' % (function.name,) - print 'static const trace::FunctionSig _%s_sig = {%u, "%s", %u, _%s_args};' % (function.name, self.getFunctionSigId(), function.name, len(function.args), function.name) + print 'static trace::FunctionSig _%s_sig = {%u, "%s", %u, _%s_args};' % (function.name, self.getFunctionSigId(), function.name, len(function.args), function.name) print def getFunctionSigId(self): @@ -685,7 +685,7 @@ class Tracer: assert not method.internal print ' static const char * _args[%u] = {%s};' % (len(method.args) + 1, ', '.join(['"this"'] + ['"%s"' % arg.name for arg in method.args])) - print ' static const trace::FunctionSig _sig = {%u, "%s", %u, _args};' % (self.getFunctionSigId(), interface.name + '::' + method.name, len(method.args) + 1) + print ' static trace::FunctionSig _sig = {%u, "%s", %u, _args};' % (self.getFunctionSigId(), interface.name + '::' + method.name, len(method.args) + 1) print ' %s *_this = static_cast<%s *>(m_pInstance);' % (base, base) -- cgit v1.2.3 From 69909e3853c23d0ce062b6c9f232191970da9aee Mon Sep 17 00:00:00 2001 From: José Fonseca Date: Sat, 4 May 2013 11:10:33 +0100 Subject: Remove FunctionSig::backtrace member. Backtraces are really disjoint from signature. This puts back const keyword in most FunctionSig usages. --- common/trace_model.hpp | 5 ++--- common/trace_parser.cpp | 2 +- common/trace_writer.cpp | 3 +-- common/trace_writer.hpp | 2 +- common/trace_writer_local.cpp | 12 ++++++------ common/trace_writer_local.hpp | 10 +++++----- wrappers/gltrace.py | 2 +- wrappers/trace.py | 6 +++--- 8 files changed, 20 insertions(+), 22 deletions(-) (limited to 'wrappers') diff --git a/common/trace_model.hpp b/common/trace_model.hpp index 7c4cdc78..fbfa1fbb 100644 --- a/common/trace_model.hpp +++ b/common/trace_model.hpp @@ -49,7 +49,6 @@ struct FunctionSig { const char *name; unsigned num_args; const char **arg_names; - bool backtrace; }; @@ -488,14 +487,14 @@ class Call public: unsigned thread_id; unsigned no; - FunctionSig *sig; + const FunctionSig *sig; std::vector args; Value *ret; CallFlags flags; Backtrace* backtrace; - Call(FunctionSig *_sig, const CallFlags &_flags, unsigned _thread_id) : + Call(const FunctionSig *_sig, const CallFlags &_flags, unsigned _thread_id) : thread_id(_thread_id), sig(_sig), args(_sig->num_args), diff --git a/common/trace_parser.cpp b/common/trace_parser.cpp index 8ba9bdcd..6ccc68db 100644 --- a/common/trace_parser.cpp +++ b/common/trace_parser.cpp @@ -463,7 +463,7 @@ Call *Parser::parse_leave(Mode mode) { * between two frames. We won't return this call, but we still need to skip * over its data. */ - FunctionSig sig = {0, NULL, 0, NULL}; + const FunctionSig sig = {0, NULL, 0, NULL}; call = new Call(&sig, 0, 0); parse_call_details(call, SCAN); delete call; diff --git a/common/trace_writer.cpp b/common/trace_writer.cpp index 2dc7a00e..be013761 100644 --- a/common/trace_writer.cpp +++ b/common/trace_writer.cpp @@ -200,12 +200,11 @@ void Writer::beginStackFrameOffset(void ) { _writeByte(trace::CALL_BACKTRACE_OFFSET); } -unsigned Writer::beginEnter(FunctionSig *sig, unsigned thread_id) { +unsigned Writer::beginEnter(const FunctionSig *sig, unsigned thread_id) { _writeByte(trace::EVENT_ENTER); _writeUInt(thread_id); _writeUInt(sig->id); if (!lookup(functions, sig->id)) { - sig->backtrace = backtrace_is_needed(sig->name); _writeString(sig->name); _writeUInt(sig->num_args); for (unsigned i = 0; i < sig->num_args; ++i) { diff --git a/common/trace_writer.hpp b/common/trace_writer.hpp index 6440ab9c..f8d0afb1 100644 --- a/common/trace_writer.hpp +++ b/common/trace_writer.hpp @@ -74,7 +74,7 @@ namespace trace { void beginStackFrameOffset(void); inline void endStackFrameOffset(void) {} - unsigned beginEnter(FunctionSig *sig, unsigned thread_id); + unsigned beginEnter(const FunctionSig *sig, unsigned thread_id); void endEnter(void); void beginLeave(unsigned call); diff --git a/common/trace_writer_local.cpp b/common/trace_writer_local.cpp index b894bf9d..86617013 100644 --- a/common/trace_writer_local.cpp +++ b/common/trace_writer_local.cpp @@ -43,16 +43,16 @@ namespace trace { static const char *memcpy_args[3] = {"dest", "src", "n"}; -FunctionSig memcpy_sig = {0, "memcpy", 3, memcpy_args, false}; +const FunctionSig memcpy_sig = {0, "memcpy", 3, memcpy_args}; static const char *malloc_args[1] = {"size"}; -FunctionSig malloc_sig = {1, "malloc", 1, malloc_args, false}; +const FunctionSig malloc_sig = {1, "malloc", 1, malloc_args}; static const char *free_args[1] = {"ptr"}; -FunctionSig free_sig = {2, "free", 1, free_args, false}; +const FunctionSig free_sig = {2, "free", 1, free_args}; static const char *realloc_args[2] = {"ptr", "size"}; -FunctionSig realloc_sig = {3, "realloc", 2, realloc_args, false}; +const FunctionSig realloc_sig = {3, "realloc", 2, realloc_args}; static void exceptionCallback(void) @@ -134,7 +134,7 @@ static uintptr_t next_thread_num = 1; static OS_THREAD_SPECIFIC_PTR(void) thread_num; -unsigned LocalWriter::beginEnter(FunctionSig *sig) { +unsigned LocalWriter::beginEnter(const FunctionSig *sig, bool fake) { mutex.lock(); ++acquired; @@ -153,7 +153,7 @@ unsigned LocalWriter::beginEnter(FunctionSig *sig) { assert(this_thread_num); unsigned thread_id = this_thread_num - 1; unsigned call_no = Writer::beginEnter(sig, thread_id); - if (sig->backtrace) { + if (!fake) { std::vector backtrace = get_backtrace(); beginBacktrace(); writeBacktrace(backtrace); diff --git a/common/trace_writer_local.hpp b/common/trace_writer_local.hpp index 1da22501..18593540 100644 --- a/common/trace_writer_local.hpp +++ b/common/trace_writer_local.hpp @@ -39,10 +39,10 @@ namespace trace { - extern FunctionSig memcpy_sig; - extern FunctionSig malloc_sig; - extern FunctionSig free_sig; - extern FunctionSig realloc_sig; + extern const FunctionSig memcpy_sig; + extern const FunctionSig malloc_sig; + extern const FunctionSig free_sig; + extern const FunctionSig realloc_sig; /** * A specialized Writer class, mean to trace the current process. @@ -83,7 +83,7 @@ namespace trace { /** * It will acquire the mutex. */ - unsigned beginEnter(FunctionSig *sig); + unsigned beginEnter(const FunctionSig *sig, bool fake = false); /** * It will release the mutex. diff --git a/wrappers/gltrace.py b/wrappers/gltrace.py index fcb48bba..c40fbb36 100644 --- a/wrappers/gltrace.py +++ b/wrappers/gltrace.py @@ -520,7 +520,7 @@ class GlTracer(Tracer): # Emit a fake function print ' {' - print ' static trace::FunctionSig &_sig = %s ? _glEnableClientState_sig : _glDisableClientState_sig;' % flag_name + print ' static const trace::FunctionSig &_sig = %s ? _glEnableClientState_sig : _glDisableClientState_sig;' % flag_name print ' unsigned _call = trace::localWriter.beginEnter(&_sig);' print ' trace::localWriter.beginArg(0);' self.serializeValue(glapi.GLenum, enable_name) diff --git a/wrappers/trace.py b/wrappers/trace.py index 9ff54104..252db492 100644 --- a/wrappers/trace.py +++ b/wrappers/trace.py @@ -452,7 +452,7 @@ class Tracer: print 'static const char * _%s_args[%u] = {%s};' % (function.name, len(function.args), ', '.join(['"%s"' % arg.name for arg in function.args])) else: print 'static const char ** _%s_args = NULL;' % (function.name,) - print 'static trace::FunctionSig _%s_sig = {%u, "%s", %u, _%s_args};' % (function.name, self.getFunctionSigId(), function.name, len(function.args), function.name) + print 'static const trace::FunctionSig _%s_sig = {%u, "%s", %u, _%s_args};' % (function.name, self.getFunctionSigId(), function.name, len(function.args), function.name) print def getFunctionSigId(self): @@ -685,7 +685,7 @@ class Tracer: assert not method.internal print ' static const char * _args[%u] = {%s};' % (len(method.args) + 1, ', '.join(['"this"'] + ['"%s"' % arg.name for arg in method.args])) - print ' static trace::FunctionSig _sig = {%u, "%s", %u, _args};' % (self.getFunctionSigId(), interface.name + '::' + method.name, len(method.args) + 1) + print ' static const trace::FunctionSig _sig = {%u, "%s", %u, _args};' % (self.getFunctionSigId(), interface.name + '::' + method.name, len(method.args) + 1) print ' %s *_this = static_cast<%s *>(m_pInstance);' % (base, base) @@ -782,7 +782,7 @@ class Tracer: print ' %s_this->%s(%s);' % (result, method.name, ', '.join([str(arg.name) for arg in method.args])) def emit_memcpy(self, dest, src, length): - print ' unsigned _call = trace::localWriter.beginEnter(&trace::memcpy_sig);' + print ' unsigned _call = trace::localWriter.beginEnter(&trace::memcpy_sig, true);' print ' trace::localWriter.beginArg(0);' print ' trace::localWriter.writePointer((uintptr_t)%s);' % dest print ' trace::localWriter.endArg();' -- cgit v1.2.3