You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@subversion.apache.org by "Kirby C. Bohling" <kb...@birddog.com> on 2002/02/06 09:36:25 UTC

Hack to get backtraces for memory allocations...

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

Re: Hack to get backtraces for memory allocations...

Posted by "Kirby C. Bohling" <kb...@birddog.com>.
Sander,

Sander Striker wrote:
>>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.
>>
> 
> Woah!  Ok, this is indeed a hack ;)
> A usefull one imo, but it poses a lot of requirements on the platform.
> 

Given it is my only platform, I don't mind.  Yes an unfortuante side 
affect of how it was done.  I did some poking about in glibc, and 
actually it appears that it backtrace might be supported on more 
platforms, but I couldn't test that if my life depended on it.  So 
somebody with a different arch/platform might try it.  I have no way of 
testing it.  It looks like it might work on any platform using glibc on 
the following list:

./sysdeps/i386/backtrace.c
./sysdeps/powerpc/backtrace.c
./sysdeps/s390/s390-32/backtrace.c
./sysdeps/s390/s390-64/backtrace.c
./sysdeps/generic/backtrace.c

So I might have missed the boat on how portable it is.  Sorry.
All those had the same function that takes the same arguments, I presume 
the symantics are the same.  I thought the libbtrace docs said it was a 
lot less portable, but maybe it is slightly more portable then I put 
forward.  No, it can't get folded into the main tree all things 
considered.  I know there is a way to do in win32 on a VC++ compiler 
also, but it has been to long, I don't remember the details.


> I know the output of the pools debug mode is very (if not extremely)
> verbose, but it is more portable and with a bit of grep magic
> you can get all the info you need.  I recently added another option
> to --enable-pool-debug: verbose-alloc.  This will spit out all the
> invocations of apr_p[c]alloc.  This only leaves one more point in
> the pools code where memory is allocated: apr_pvsprintf.
> 
> Btw, I liked your walk_pool_tree, I know I can use that (or at least
> the concept).  Thanks.
> 

I stole the idea from the apr code.  Yeah it isn't at all threadsafe, 
but I didn't have any way of testing that.  I tried to leave it obvious 
that it was broken rather then mock up that it might do the right thing.
There is a identical functionality in the count the memory recursively, 
just strip out the summation and put in the function pointer if I 
remember correctly.


[..snip...]

	Thanks,
		Kirby


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@subversion.tigris.org
For additional commands, e-mail: dev-help@subversion.tigris.org

RE: Hack to get backtraces for memory allocations...

Posted by Sander Striker <st...@apache.org>.
> 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.

Woah!  Ok, this is indeed a hack ;)
A usefull one imo, but it poses a lot of requirements on the platform.

I know the output of the pools debug mode is very (if not extremely)
verbose, but it is more portable and with a bit of grep magic
you can get all the info you need.  I recently added another option
to --enable-pool-debug: verbose-alloc.  This will spit out all the
invocations of apr_p[c]alloc.  This only leaves one more point in
the pools code where memory is allocated: apr_pvsprintf.

Btw, I liked your walk_pool_tree, I know I can use that (or at least
the concept).  Thanks.

[...] 
> 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 for the effort.  We definately need some decent bug hunting
tools.  I am staring at some code at the moment that will hopefully
make our lives a bit easier (relies heavily on mprotect), by segfaulting
on us at the point the app does something we don't want.  This is
the behaviour electric fence gives you, with the bonus that we can
write protect memory we know shouldn't be touched.  This will be the
more portable implementation of apr_pool_lock, that wrowe introduced
for win32 (and I left out in the rewrite)...


Sander

> 	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....

*grin*

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@subversion.tigris.org
For additional commands, e-mail: dev-help@subversion.tigris.org