[svn.haxx.se] · SVN Dev · SVN Users · SVN Org · TSVN Dev · TSVN Users · Subclipse Dev · Subclipse Users · this month's index

Hack to get backtraces for memory allocations...

From: Kirby C. Bohling <kbohling_at_birddog.com>
Date: 2002-02-06 10:36:25 CET

So, this is a complete and utter hack. It should never ever get near
any production code, ever! Just so that is very clear. It has one and
only one purpose, getting enough information to get a back trace of
every single memory allocation you are interested in. Credit where
credit is due, I stole the idea of this code from the guy who wrote
libbtrace, search on freshmeat for it. Basically, he gave me the
pointer to the backtrace function in the glibc2. A lot of the reasons
below are from his docs.

The reasons it is a hack:

It only works with glibc.2.* something or other, I use 2.2.4, but it
works with other glibc2 versions of that series. It uses an
undocumented feature from that library series.

It only works under linux (I believe).

It puts the function prototypes directly in the code rather then finding
the correct header.

It only works on i386 architectures.

Gotta have binutils installed on the box (you should if your doing
development).

So now that we have reviewed the reasons it is bad, here it is:

I hand edited the patch to remove the portions that are local changes
that I have already submitted to the list. So the line numbers might be
off. If nothing else, it doesn't take much to add this stuff back in by
hand. If you applied my previous patch this one will probably get
rejected. They are more useful with each other.

===================================================================
RCS file: /home/cvspublic/apr/memory/unix/apr_pools.c,v
retrieving revision 1.149
diff -u -r1.149 apr_pools.c
--- memory/unix/apr_pools.c 5 Feb 2002 12:09:43 -0000 1.149
+++ memory/unix/apr_pools.c 6 Feb 2002 09:07:24 -0000
@@ -1065,6 +1078,16 @@
   * Memory allocation (debug)
   */

+#define BACK_TRACE_HACK 1
+
+#ifdef BACK_TRACE_HACK
+
+/* I could probably find it in the headers, but headers
+ * are for safe, rational, right-minded people.
+ * The way it is defined in the for glibc.2.2.4 headers... */
+int backtrace ( void **array, int size );
+#endif
+
  static void *pool_alloc(apr_pool_t *pool, apr_size_t size)
  {
      debug_node_t *node;
@@ -1099,6 +1122,48 @@

      pool->stat_alloc++;
      pool->stat_total_alloc++;
+
+
+
+#ifdef BACK_TRACE_HACK
+ {
+#define MAX_BACKTRACE 10
+ int array_size = MAX_BACKTRACE;
+ int size = 0;
+
+
+ /* Implicitly assumes a void* is enought to
+ * store a function address, is that always true?
+ * on i386 in 32-bit mode it is. */
+
+ void * callStack[ MAX_BACKTRACE ];
+
+ printf( "Pool: %p Backtrace: ", pool );
+ size = backtrace( callStack, array_size );
+
+ if( !size ) {
+ printf( "No call stack returned." );
+ }
+ else {
+ int iii = 0;
+ for( ; iii < size ; ++iii ) {
+ printf( "%p ", callStack[ iii ] );
+ }
+ }
+ printf( "\n" );
+ }
+#endif
+

      return mem;
  }

--- End of patch ---

Below is the script I used, I captured all of the output of svn with the
above patch enabled, and piped it thru this script which I called
addr2stack.sh.

---- Start of script
#!/bin/sh

while read line ; do
         echo $line
         for addr in `echo $line | sed -n -e 's/Pool:.* Backtrace:
\(.*\)/\1/p'`
         do
                 echo -n "$addr --> " && addr2line --exe=$1 $addr
         done
done
-- end of script.

Pool: 0x8153228 Backtrace: 0x81248ef 0x81249bd 0x812378d 0x8124c2c
0x81247bd 0x81226bc 0x804d7c5 0x400d3306 0x804b251
0x81248ef --> /u1/subversion/subversion/apr/memory/unix/apr_pools.c:1144
0x81249bd --> /u1/subversion/subversion/apr/memory/unix/apr_pools.c:1194
0x812378d --> /u1/subversion/subversion/apr/locks/unix/thread_mutex.c:84
0x8124c2c --> /u1/subversion/subversion/apr/memory/unix/apr_pools.c:1361
0x81247bd --> /u1/subversion/subversion/apr/memory/unix/apr_pools.c:1034
0x81226bc --> /u1/subversion/subversion/apr/misc/unix/start.c:105
0x804d7c5 -->
/u1/subversion/subversion/subversion/clients/cmdline/main.c:765
0x400d3306 --> ??:0
0x804b251 --> ??:0

Which tells you the pool, the addresses listed out, followed by a
complete backtrace from apr_palloc all the way back to the beginning of
main or 10 stack frames (bump the #define if you like). Which ever
comes first.

Judicious use of this, grep, sort, and a couple of other the patches I
posted should get you a listing of every call stack that allocates
memory on the stack. Bonus points to the first person who does all the
post processing to sort them total memory allocated by this stack frame.
  It is entirely too late at night for me to do it. I gotta get some
sleep before work tomorrow.

If anybody wants a more portable version that isn't quite as filtered, I
can jimmy up something using gdb, .gdbinit, expect and/or shell to get
more detailed information including all the arguments of the calls, but
that seemed less useful for tracking down the worst offenders then this is.

Honest not everything I write is this much of a total hack. Results
count and style doesn't when bug hunting.

        Thanks,

                Kirby

PS: You already know how to fish, I've seen your code :-), the above is
a demonstration of how to gut the fish and turn it into fish spam....

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@subversion.tigris.org
For additional commands, e-mail: dev-help@subversion.tigris.org
Received on Sat Oct 21 14:37:04 2006

This is an archived mail posted to the Subversion Dev mailing list.

This site is subject to the Apache Privacy Policy and the Apache Public Forum Archive Policy.