[OpenAFS-devel] fwd> Stack Backtracing Inside Your Program

Nathan Neulinger nneul@umr.edu
Tue, 12 Aug 2003 09:28:01 -0500


This is a multi-part message in MIME format.
--------------000404020907010407050909
Content-Type: text/plain; charset=us-ascii; format=flowed
Content-Transfer-Encoding: 7bit

This might be a worthwhile feature to add to the osi_Panic stuff... It 
would be for glibc only, but that would still be useful for a wide 
audience.

<http://www.linuxjournal.com/article.php?sid=6391>

-- Nathan

------------------------------------------------------------
Nathan Neulinger                       EMail:  nneul@umr.edu
University of Missouri - Rolla         Phone: (573) 341-4841
UMR Information Technology             Fax: (573) 341-4216

--------------000404020907010407050909
Content-Type: text/html; charset=ISO-8859-1;
 name="www.linuxjournal.com/article.php?sid=6391"
Content-Transfer-Encoding: 8bit
Content-Disposition: inline;
 filename="www.linuxjournal.com/article.php?sid=6391"
Content-Base: "http://www.linuxjournal.com/article.ph
	p?sid=6391"
Content-Location: "http://www.linuxjournal.com/article.ph
	p?sid=6391"

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>Stack Backtracing Inside Your Program</title>
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=ISO-8859-1">
<META NAME="AUTHOR" CONTENT="Linux Journal  - The Premier Magazine of the Linux Community">
<META NAME="COPYRIGHT" CONTENT="Copyright (c) 2002 by Linux Journal  - The Premier Magazine of the Linux Community">
<META NAME="KEYWORDS" CONTENT="linux, linux journal, magazine">
<META NAME="DESCRIPTION" CONTENT="The Monthly Magazine of the Linux Community">
<META NAME="GOOGLEBOT" CONTENT="NOARCHIVE">
<META NAME="GENERATOR" CONTENT="PHP-Nuke 5.0 - http://phpnuke.org">


<LINK REL="StyleSheet" HREF="/themes/NewLJ/style/style.css" TYPE="text/css">


<SCRIPT type="text/javascript">
<!--
function showimage() {
if (!document.images)
return
document.images.avatar.src=
'http://www.linuxjournal.com/images/forum/avatar/' + document.Register.user_avatar.options[document.Register.user_avatar.selectedIndex].value
}
//-->
</SCRIPT>

<script type="text/javascript">
<!--
function openwindow(){
        window.open ("","Help","toolbar=no,location=no,directories=no,status=no,scrollbars=yes,resizable=no,copyhistory=no,width=600,height=400");
}
//-->
</SCRIPT>

</head>

<body bgcolor="#505050" text="#000000" link="#363636" vlink="#363636" alink="#d5ae83">
<table><tr><td>
<center><a href="http://www.linuxjournal.com/banners.php?op=click&amp;bid=260&amp;pb=1060698480" target="_blank"><img src="/images/banners/racksaver/racksaver0115.gif" border="1" height="60" width="468" alt=""></a></center><br>
<table cellpadding="0" cellspacing="0" width="100%" border="0" align="center" bgcolor="#ffffff">
<tr>
<td bgcolor="#ffffff">
<img height="16" alt="" hspace="0" src="/themes/NewLJ/images/corner-top-left.png" width="17" align="left">
<a href="/index.php"><img src="/themes/NewLJ/images/logo_blue.png" width="147" height="69" align="left" alt="Welcome to Linux Journal  - The Premier Magazine of the Linux Community" border="0"></a></td>
<td bgcolor="#999999"><IMG src="/themes/NewLJ/images/pixel.gif" width="1" height="1" alt="" border="0" hspace="0"></td>
<td bgcolor="#cfcfbb" align="center">
<center><form action="search.php" method="post"><font class="content" color="#000000"><b>Search </b>
<input type="text" name="query" size="14"></font></form></center></td>
<td bgcolor="#cfcfbb" align="center">
<center><form action="search.php" method="get"><font class="content"><b>Topics </b>
<select name="topic"onChange='submit()'>
<option value="">All Topics</option>
<option  value="11">Book Reviews</option>
<option  value="6">Development Tools</option>
<option  value="36">Embedded</option>
<option  value="17">Games</option>
<option  value="34">German</option>
<option  value="30">Hardware</option>
<option  value="12">Linux Community</option>
<option  value="9">Linux in Business</option>
<option  value="7">Linux in Education</option>
<option  value="29">Linux Journal</option>
<option  value="4">Linux Kernel</option>
<option  value="21">Linux Market</option>
<option  value="1">Miscellaneous</option>
<option  value="13">Multimedia</option>
<option  value="5">Networking</option>
<option  value="31">Other Software</option>
<option  value="32">Product of the Day</option>
<option  value="19">Product Reviews</option>
<option  value="8">Security</option>
<option  value="33">Spanish</option>
<option  value="35">Tutorial</option>
<option  value="28">Web Development</option>
</select></font></form></center></td>
<td bgcolor="#cfcfbb" valign="top"><img height="17" alt="" hspace="0" src="/themes/NewLJ/images/corner-top-right.gif" width="17" align="right"></td>
</tr></table>
<table cellpadding="0" cellspacing="0" width="100%" border="0" align="center" bgcolor="#fefefe">
<tr>
<td bgcolor="#000000" colspan="4"><IMG src="/themes/NewLJ/images/pixel.gif" width="1" height=1 alt="" border="0" hspace="0"></td>
</tr>
<tr valign="middle" bgcolor="#dedebb">
<td width="15%" nowrap><font class="content" color="#363636"><b>
<!-- BEGIN user customization -->&nbsp;&nbsp;<b><font color="#363636"><a href="/user.php">Create</a></font> an account</b>
<!-- END user customization --></b></font></td>
<td align="center" height="20" width="70%"><font class="content"><B>
<A href="/">Home</a>
&nbsp;&middot;&nbsp;
<A href="/subscribe.php">Subscribe</a>
&nbsp;&middot;&nbsp;
<A href="/topics.php">Topics</a>
&nbsp;&middot;&nbsp;
<A href="/advertising.php">Advertise</a>
&nbsp;&middot;&nbsp;
<A href="http://pr.linuxjournal.com" target="_blank">Vendor Press</a>
</B></font>

</td>
<td>&nbsp;</td>
</tr>
<tr>
<td bgcolor="#000000" colspan="4"><IMG src="/themes/NewLJ/images/pixel.gif" width="1" height="1" alt="" border="0" hspace="0"></td>
</tr>
</table>
<!-- FIN DEL TITULO -->
<table width="100%" cellpadding="0" cellspacing="0" border="0" bgcolor="#ffffff" align="center"><tr valign="top">
<td bgcolor="#ffffff"><img src="/themes/NewLJ/images/pixel.gif" width="1" height="20" border="0" alt=""></td></tr></table>
<table width="100%" cellpadding="0" cellspacing="0" border="0" bgcolor="#ffffff" align="center"><tr valign="top">
<td bgcolor="#ffffff"><img src="/themes/NewLJ/images/pixel.gif" width="10" height="1" border="0" alt=""></td>
<td bgcolor="#ffffff" width="150" valign="top">
<table border="0" cellpadding="1" cellspacing="0" bgcolor="#000000" width="150"><tr><td>
<table border="0" cellpadding="3" cellspacing="0" bgcolor="#dedebb" width="100%"><tr><td align=left>
<font class="content" color="#363636"><b>Linux Journal</b></font>
</td></tr></table></td></tr></table>
<table border="0" cellpadding="0" cellspacing="0" bgcolor="#ffffff" width="150">
<tr valign="top"><td bgcolor="#ffffff">
<font class="content"><strong><big>·</big></strong> <a href="/index.php">Home</a><br>
 
<strong><big>·</big></strong> <a href="/modules.php?op=modload&name=NS-subscribe&file=suboptions#new">Subscribe</a>
/ <a href="/modules.php?op=modload&name=NS-subscribe&file=suboptions#renew">Renew</a><br>
 <strong><big>·</big></strong> <a href="/modules.php?op=modload&name=NS-subscribe&file=suboptions#address">Change Address</a><br>
<strong><big>·</big></strong> <a href="/subscribe.php">Subscriber Services</a><br>
<p>
<strong><big>·</big></strong> <a href="/advertising.php">Advertise</a><br> 
<strong><big>·</big></strong> <a href="/modules.php?op=modload&name=NS-author&file=wanted">Write for Us</a><br>
<strong><big>·</big></strong> <a href="/press.php">Press Releases</a><br> 
<strong><big>·</big></strong> <a href="/contact.php">Contact Us</a><br>
<p>
<strong><big>·</big></strong> <a href="http://www.linuxjournal.com/lunacy">Linux Lunacy Cruise</a><br>
<strong><big>·</big></strong> <a href="http://www.linuxjournal.com/ljpress">LJ Press Books</a><br>
<br><b>Other Options</b><br><strong><big>&middot;</big></strong>&nbsp;<a href="/modules.php?op=modload&amp;name=FAQ&amp;file=index">FAQ</a><br><strong><big>&middot;</big></strong>&nbsp;<a href="/modules.php?op=modload&amp;name=Members_List&amp;file=index">Members List</a><br></font>
</td></tr></table>
<br>


<table border="0" cellpadding="1" cellspacing="0" bgcolor="#000000" width="150"><tr><td>
<table border="0" cellpadding="3" cellspacing="0" bgcolor="#dedebb" width="100%"><tr><td align=left>
<font class="content" color="#363636"><b>Subscribe (USA)</b></font>
</td></tr></table></td></tr></table>
<table border="0" cellpadding="0" cellspacing="0" bgcolor="#ffffff" width="150">
<tr valign="top"><td bgcolor="#ffffff">
<form method="POST" action="https://www.ssc.com/cgi-bin/lj/USA.py">

<table cellspacing="0" cellpadding="0">
<tr>
   <td align="Right">
     <font face="arial, helvetica, sans-serif" size="-2">Name </font>
   </td>
   <td align="left">
      <font face="arial, helvetica, sans-serif" size="-2">
      <input type="text" size="10" name="name" maxlength="32"/>
      </font>
    </td>
 </tr>
 <tr>
    <td align="right">
      <font face="arial, helvetica, sans-serif" size="-2">Addr </font>
    </td> 
    <td align="left">
      <font face="arial, helvetica, sans-serif" size="-2">
      <input type="text" size="10" name="addr1" maxlength="32"/>
      </font>
    </td>
 </tr>
 <tr>
     <td align="right">
        <font face="arial, helvetica, sans-serif" size="-2">Addr </font>
     </td>
     <td align="left">
	<font face="arial, helvetica, sans-serif" size="-2">
	 <input type="text" size="10" name="addr2" maxlength="32"/>
         </font>
     </td>
 </tr>
 <tr>
    <td align="right">
       <font face="arial, helvetica, sans-serif" size="-2">City </font>
    </td>
    <td align="left">
        <font face="arial, helvetica, sans-serif" size="-2">
	<input type="text" size="10" name="city" maxlength="17"/>
        </font>
     </td> 
 </tr>
 <tr>
     <td align="right">
        <font face="arial, helvetica, sans-serif" size="-2">State </font>
      </td>
      <td align="left">
        <font face="arial, helvetica, sans-serif" size="-2">
        <input type="text" size="3" name="state" maxlength="2"/> 
     </font></td>
<tr>
</tr>
     <td align="right">
        <font face="arial, helvetica, sans-serif" size="-2">Zip </font>
     </td>
     <td align="left">
	<font face="arial, helvetica, sans-serif" size="-2">
        <input type="text" size="6" name="zip" maxlength="10"/>
        </font>
      </td>
 </tr>
 <tr>
      <td align="right">
        <font face="arial, helvetica, sans-serif" SIZE="-2">Email </font>
      </td> 
      <td align="left">
        <font face="arial, helvetica, sans-serif" size="-2">
	<input type="text" size="10" name="email" maxlength="60"/>
      </td>
 </tr> 
</table>
<table>
<tr>
    <td valign="middle" width="80%" nowrap="1">
      <font face="arial, helvetica, sans-serif" size="-2">
          <div><input type="radio" name="term" value="1yr" checked="on"/>
                12 issues for $25
          </div>
          <div><input type="radio" name="term" value="2yr"/>
                24 issues for $45
          </div>
       </td>
</tr>
<tr>
     <td align="center">
        <input type="submit" value="Subscribe"/>
        <p align="center">
        <font face="arial, helvetica, sans-serif" size="-2">
        Click below for:<br>
        <A HREF="https://www.ssc.com/lj/subs/NewCanada.html">Canada</a> *
        <A HREF="https://www.ssc.com/lj/subs/NewMexico.html">Mexico</a> *
        <A HREF="https://www.ssc.com/lj/subs/NewOther.html">Other</a>
        </font>
     </td>
</tr>
</table>
</form>
</td></tr></table>
<br>


<table border="0" cellpadding="1" cellspacing="0" bgcolor="#000000" width="150"><tr><td>
<table border="0" cellpadding="3" cellspacing="0" bgcolor="#dedebb" width="100%"><tr><td align=left>
<font class="content" color="#363636"><b>Store</b></font>
</td></tr></table></td></tr></table>
<table border="0" cellpadding="0" cellspacing="0" bgcolor="#ffffff" width="150">
<tr valign="top"><td bgcolor="#ffffff">
<strong><big>·</big></strong> <a href="http://store.linuxjournal.com/Merchant2/merchant.mv?Screen=PROD&Store_Code=LJS&Product_Code=ljs&Category_Code=LA" target="_blank">Order Back Issues</a><br>


<strong><big>·</big></strong> <a href="http://store.linuxjournal.com/Merchant2/merchant.mv?Screen=CTGY&Store_Code=LJS&Category_Code=T" target="_blank">T-shirts</a><br> 



<strong><big>·</big></strong> <a href="http://store.linuxjournal.com/Merchant2/merchant.mv?Screen=CTGY&Store_Code=LJS&Category_Code=H" target="_blank">Hats</a><br> 

 

<strong><big>·</big></strong> <a href="http://store.linuxjournal.com/Merchant2/merchant.mv?Screen=CTGY&Store_Code=LJS&Category_Code=B" target="_blank">Books</a><br> 



<strong><big>·</big></strong> <a href="http://store.linuxjournal.com" target="_blank">Fun Stuff</a><br>



<strong><big>·</big></strong> <a href="http://store.linuxjournal.com/Merchant2/merchant.mv?Screen=CTGY&Store_Code=LJS&Category_Code=RC" target="_blank">Reference Cards</a><br>
</td></tr></table>
<br>


<table border="0" cellpadding="1" cellspacing="0" bgcolor="#000000" width="150"><tr><td>
<table border="0" cellpadding="3" cellspacing="0" bgcolor="#dedebb" width="100%"><tr><td align=left>
<font class="content" color="#363636"><b>Kernel Watch</b></font>
</td></tr></table></td></tr></table>
<table border="0" cellpadding="0" cellspacing="0" bgcolor="#ffffff" width="150">
<tr valign="top"><td bgcolor="#ffffff">

<STRONG>Test</STRONG>&nbsp;&nbsp;<A HREF="http://www.kernel.org/pub/linux/kernel/v2.6" TARGET="_blank">2.6.0-test3</A>
<br>09-Aug-2003
<br><STRONG>Sane</STRONG>&nbsp;&nbsp;<A HREF="http://www.kernel.org/pub/linux/kernel/v2.4" TARGET="_blank">2.4.21</A>
<br>13-Jun-2003
<br><STRONG>Safe</STRONG>&nbsp;&nbsp;<A HREF="http://www.kernel.org/pub/linux/kernel/v2.2" TARGET="_blank">2.2.25</A>
<br>17-Mar-2003
<br><A HREF="http://www.kernel.org" TARGET="_blank">Archives</A>

</td></tr></table>
<br>


<table border="0" cellpadding="1" cellspacing="0" bgcolor="#000000" width="150"><tr><td>
<table border="0" cellpadding="3" cellspacing="0" bgcolor="#dedebb" width="100%"><tr><td align=left>
<font class="content" color="#363636"><b>Other SSC Sites</b></font>
</td></tr></table></td></tr></table>
<table border="0" cellpadding="0" cellspacing="0" bgcolor="#ffffff" width="150">
<tr valign="top"><td bgcolor="#ffffff">
<strong><big>·</big></strong> <a href="http://www.eljonline.com" target="_blank">Embedded LJ</a><br>

<strong><big>·</big></strong> <a href="http://www.linuxgazette.com" target="_blank">Linux Gazette</a><br>

<strong><big>·</big></strong> <a href="http://www.linuxjournal.com/bg" >Linux Buyer's Guide</a><br>

<strong><big>·</big></strong> <a href="http://pr.linuxjournal.com" target="_blank">pr.linuxjournal.com</a><br>

<strong><big>·</big></strong> <a href="http://worldwatch.linuxgazette.com" target="_blank">WorldWatch</a><br>

<strong><big>·</big></strong> <a href="http://www.ssc.com" target="_blank">SSC Publications</a><br>
</td></tr></table>
<br>


<table border="0" cellpadding="1" cellspacing="0" bgcolor="#000000" width="150"><tr><td>
<table border="0" cellpadding="3" cellspacing="0" bgcolor="#dedebb" width="100%"><tr><td align=left>
<font class="content" color="#363636"><b>Contest</b></font>
</td></tr></table></td></tr></table>
<table border="0" cellpadding="0" cellspacing="0" bgcolor="#ffffff" width="150">
<tr valign="top"><td bgcolor="#ffffff">
<p><center><a href="http://www.sangoma.com/linuxgeek.htm"><img src ="/images/linuxgeek-cta-logo.gif"></a></center>
</td></tr></table>
<br>


<table border="0" cellpadding="1" cellspacing="0" bgcolor="#000000" width="150"><tr><td>
<table border="0" cellpadding="3" cellspacing="0" bgcolor="#dedebb" width="100%"><tr><td align=left>
<font class="content" color="#363636"><b>Linux Resources</b></font>
</td></tr></table></td></tr></table>
<table border="0" cellpadding="0" cellspacing="0" bgcolor="#ffffff" width="150">
<tr valign="top"><td bgcolor="#ffffff">
<strong><big>·</big></strong> <a href="/magazine.php">Magazine Archive</a><br>
<strong><big>·</big></strong> <a href="/webindex.php">Web Article Index</a><br>
<strong><big>·</big></strong> <a href="ftp://ftp.ssc.com/pub/lj/listings" target="_blank">Downloads</a><br>
<strong><big>·</big></strong> <a href="/resources.php">Linux Resources</a><br>
<strong><big>·</big></strong> <a href="/helpdesk.php">SSC Help Desk</a><br>
<strong><big>·</big></strong> <a href="/links.php">Linux Links</a><br>
<strong><big>·</big></strong> <a href="/cgi-bin/wish/index.pl">Wishlist</a><br>
<strong><big>·</big></strong> <a href="http://www.ssc.com:8080/glue/" target=_blank>User Groups (GLUE)</a><br>
<strong><big>·</big></strong> <a href="/events.php">Special Events</a><br>
</td></tr></table>
<br>


</td><td><img src="/themes/NewLJ/images/pixel.gif" width="15" height="1" border="0" alt=""></td><td width="100%">
<!-- END HEADER -->
<table width="100%" border="0"><tr><td valign="top">
<table border="0" cellpadding="0" cellspacing="0" bgcolor="#ffffff" width="100%"><tr><td>
<table border="0" cellpadding="1" cellspacing="0" bgcolor="#000000" width="100%"><tr><td>
<table border="0" cellpadding="3" cellspacing="0" bgcolor="#cfcfbb" width="100%"><tr><td align="left">
<font class="option" color="#363636"><b><a href="categories.php?op=newindex&amp;catid=36">HOWTO</a>: <font color="navy">Stack Backtracing Inside Your Program</font></b></font><br>
<font class="content">Posted on Monday, August 11, 2003 by <a href="mailto:g.insolvibile@cpr.it">Gianluca Insolvibile</a></td><td align="right"><a href="print.php?sid=6391"><img src="/images/print2.png" border=0 Alt="Printer Friendly Page" width="15" height="11"></a>&nbsp;&nbsp;<a href="friend.php?op=FriendSend&amp;sid=6391"><img src="/images/friend.png" border="0" Alt="Send this Article to a Friend" width="15" height="11"></a>
</td></tr></table></td></tr></table><br><a href="search.php?query=&amp;topic=6"><img src="/images/topics/tools2.png" border="0" Alt="Development Tools" align="right" hspace="10" vspace="10"></a>
<font class="content" color="#000000"><i>How to use a backtrace to follow the execution path and find out what went wrong and where.</i><br><br><P>
If you usually work with non-trivial C sources, you may have wondered 
which execution path (that is, which sequence of function calls)
brought you to a certain point in your program. Also, it would be even
more useful if you could have that piece of information whenever your
beautiful, bug-free program suddenly crashes, and you have no debugger at
hand. What is needed is a <I>stack backtrace</I> and, thanks to a little
known feature of the GNU C library, obtaining it is a fairly easy task.
<P>
<h3>Stack Frames and Backtraces<h3>
<P>
Before diving into the article, let's briefly go over how function 
calls and parameters pass work in C. In order to
prepare for the function call, parameters are pushed on the stack in
reverse order. Afterwards, the caller's return address also is pushed
on the stack and the function is called. Finally, the called function's
entry code creates some more space on the stack for storage of automatic
variables. This layout commonly is called a stack frame for that
particular instance of the function call. When more function calls
are nested, the whole procedure is repeated, causing the stack to keep
growing downwards and building a chain of stack frames (see Figure
1). Thus, at any given point in a program it theoretically is possible
to backtrace the sequence of stack frames to the originating
calling point, up to the main() function (to be exact, up to the libc
function, which calls main() when the process starts up).
<P>
<A href="/modules/NS-articles/HOWTO/6391f1.png"><h4>Figure 1. Nested Function Calls</h4></a>
<P>
<h3>Stack Backtracing from within GDB</h3>
<P>
Getting the stack backtrace with GDB (or an equivalent graphical front
end) for a program that crashed while running is straightforward:
you simply issue the bt command, which returns the list of functions
called up to the point of the crash. As this is a standard practice,
we do not provide any more details here; have a look at the GDB
info page if you need specifics (<code>info gdb stack</code> gets you there).
<P>
<h3>Stack Backtracing Using libc</h3>
<P>
If for some reason you're not running inside a debugger, two options are
available for tracing what the program is doing. The first method is 
to disseminate it with print and log messages in order to pinpoint the
execution path. In a complex program, this option can become cumbersome and
tedious even if, with the help of some GCC-specific macros, it can be
simplified a bit. Consider, for example, a debug macro such as
<P>
<pre>
#define TRACE_MSG fprintf(stderr, __FUNCTION__     &#92;
				         "() [%s:%d] here I am&#92;n", &#92;
                         __FILE__, __LINE__)
</pre>
<P>
You can propagate this macro quickly throughout your program by cutting
and pasting it. When you do not need it anymore, switch it off simply by 
defining it to no-op.
<P>
A nicer way to get a stack backtrace, however, is to use some of the specific
support functions provided by glibc. The key one is backtrace(),
which navigates the stack frames from the calling point to the beginning
of the program and provides an array of return addresses. You then can
map each address to the body of a particular function in your
code by having a look at the object file with the nm command. Or, you
can do it a simpler way--use backtrace_symbols(). This function
transforms a list of return addresses, as returned by backtrace(), into
a list of strings, each containing the function name offset within
the function and the return address. The list of strings is allocated
from your heap space (as if you called malloc()), so you should free()
it as soon as you are done with it.
<P>
If you prefer to avoid dynamic memory allocation during the
backtrace--reasonable, as the backtrace is likely to happen under
faulty conditions--you can resort to backtrace_symbols_fd(). This 
prints the strings directly to the given file descriptor and does not
allocate new memory for strings storage. It is a safer choice in those
cases where memory heap potentially is corrupted.
<P>
In order to convert an address to a function name, the last two functions
rely on symbol information to be available inside the program itself. To 
enable this feature, compile your program with the -rdynamic option 
(see man dlopen for more details).
<P>
<a href="/modules.php?op=modload&name=NS-articles/HOWTO&file=6391l1"><h4>Listing 1. How to Use the Backtrace
Functions</h4></a>	 
<P>
Listing 1 demonstrates how to use these functions. The test() function calls
either func_low() or func_high(), both of which call show_stackframe()
to print out the execution path. The program is compiled with
<P>
<pre>
gcc -rdynamic listing1.c -o listing1
</pre>
<P>
The output should look something like:
<P>
<pre>
Execution path:
./listing1(show_stackframe+0x2e) [0x80486de]
./listing1(func_high+0x11) [0x8048799]
./listing1(test+0x43) [0x80487eb]
./listing1(main+0x13) [0x8048817]
/lib/libc.so.6(__libc_start_main+0xbd) [0x4003e17d]
./listing1(backtrace_symbols+0x31) [0x80485f1]
First call: 167

Execution path:
./listing1(show_stackframe+0x2e) [0x80486de]
./listing1(func_low+0x11) [0x8048779]
./listing1(test+0x21) [0x80487c9]
./listing1(main+0x33) [0x8048837]
/lib/libc.so.6(__libc_start_main+0xbd) [0x4003e17d]
./listing1(backtrace_symbols+0x31) [0x80485f1]
Second call: -3
</pre>
<P>
By the way, function prototypes for the backtrace functions reside in
the header file execinfo.h.
<P>
<h3>One Step Farther</h3>
<P>
At this point, we have in hand a tool that is able to print the list of function
calls up to the current execution point. This can be a useful tool in
many different contexts. Think of having a complex program
and needing to know who's calling a given function with the
wrong parameters. With a simple check and a call to our show_stackframe()
function, the faulty caller can be spotted easily.
<P>
An even more useful application for this technique is putting 
a stack backtrace inside a signal handler and having the latter catch
all the "bad" signals your program can receive (SIGSEGV, SIGBUS, SIGILL,
SIGFPE and the like). This way, if your program unfortunately crashes
and you were not running it with a debugger, you can get a stack trace
and know where the fault happened. This technique also can be used to 
understand where your program is looping in case it stops responding. All 
you need to do is set up a SIGUSR1/2 handler and send such a signal
when needed. Before presenting an example, we need to open a parenthesis
on signal handling.
<P>
<h3>Signal Handling and Stack Frames</h3>
<p>
Backtracing from within a signal handler requires some interesting
intricacies that take us on a little detour through signal delivery to
processes. Going into deep detail on this matter is outside
the scope of this article, but we briefly can summarize it this way:
<P>
<ul>
<li>When the kernel needs to notify a signal of a given process, it
prepares some data structures attached to the process' task struct and
sets a signal-pending bit.
<P>
<li>Later on, when the signalee process is scheduled for execution,
its stack frame is altered by the kernel in order to have EIP point to
the process' signal handler. This way, when the process runs it behaves
as if it had called its own signal handler by itself before
being suspended.
<P>
<li>The initial steps of user space signal management are taken care
of inside libc, which eventually calls the real process' signal handling
routines which, in turn, execute our stack backtrace function.
</ul>
<P>
As a consequence of this mechanism, the first two entries in the stack
frame chain when you get into the signal handler contain, respectively,
a return address inside your signal handler and one inside sigaction()
in libc. The stack frame of the last function called before the signal
(which, in case of fault signals, also is the one that supposedly caused
the problem) is lost. Thus, if function B called function A, which in
turn caused a SIGSEGV, a plain backtrace would list these entry points:
<P>
<pre>
your_sig_handler()
sigaction() in libc.so
func_B()
main()
</pre>
<P>
and no trace of the call to function A would be found. For more details,
have a look at the manuals for signal() and sigaction().
<P>
<h3>Back to Backtrace</h3>
<P>
In order to get a meaningful backtrace, we need a workaround. Luckily,
when you have the sources of both the kernel and libc, you can find
a workaround for nearly anything. In Listing 2 we exploit an
undocumented parameter of type sigcontext that is passed to the signal
handler (see the UNDOCUMENTED section in man sigaction) and contains, 
among other things, the value of EIP when the signal was
raised. After the call to backtrace(), we use this value to overwrite
the useless entry corresponding to the sigaction() return address in
the trace array. When we later call backtrace_symbols(), the
address we inserted is resolved the same as any other entry in the
array. Finally, when we print the backtrace, we start from the second
entry (<code>i=1</code> in the loop), because the first one always would be 
inside our signal handler.
<P>
<a href="/modules.php?op=modload&name=NS-articles/HOWTO&file=6391l2"><h4>Listing 2. Using sigcontext</h4></a> 
<P>
Since kernel version 2.2 the undocumented parameter to the signal handler
has been declared obsolete in adherence with POSIX.1b. A more correct
way to retrieve additional information is to use the SA_SIGINFO option 
when setting the handler, as shown in Listing 3 and documented in
the man page. Unfortunately, the siginfo_t structure provided to
the handler does not contain the EIP value we need, so we are forced
to resort again to an undocumented feature: the third parameter to the
signal handler. No man page is going to tell you that such a parameter
points to an ucontext_t structure that contains the values of the
CPU registers when the signal was raised.  From this structure, we are
able to extract the value of EIP and proceed as in the previous case.
<P>
<a href="/modules.php?op=modload&name=NS-articles/HOWTO&file=6391l3"><h4>Listing 3. Using the SA_SIGINFO
Option</h4></a>
<P>
<h3>Hazards and Limitations</h3>
<P>
A couple of points are important to keep in mind when
you use the backtrace functions. First, backtrace_symbols() internally
calls malloc() and, thus, can fail if the memory heap is corrupted--which
might be the case if you are dealing with a fault signal handler. If
you need to resolve the return addresses in such a situation, calling
backtrace_symbols_fd() is safer, because it directly writes to the given
file descriptor without allocating memory. The same reasoning implies
that it is safer to use either static or automatic (non dynamic)
storage space for the array passed to backtrace().
<P>
Also, there are some limitations to the ability of automatically tracing
back the execution of a program. The most relevant are some compiler
optimizations that, in one way or another, alter the contents of
the stack frame or even prevent a function from having one (think of
function inlining). Obviously, the stack frame does not even exist for
macros, which are not function calls at all. Finally, a stack backtrace
is impossible to perform if the stack itself has been corrupted by a
memory trash.
<P>
Regarding symbol resolution, the current glibc (version 2.3.1
at the time of this writing) allows users to obtain the function name and
offset only on systems based on the ELF binary format. Furthermore,
static symbols' names cannot be resolved internally, because they cannot be
accessed by the dynamic linking facilities. In this case, the external
command addr2line can be used instead.
<P>
<h3>Inner Workings</h3>
<P>
In case you wonder how would you access stack information in a C program,
the answer is simple: you can't. Stack handling, in fact, depends
heavily on the platform your program runs on, and the C language
does not provide any means to do it in a standard way. The implementation
of backtrace() in the glibc library contains platform-specific
code for each platform, which is based either on GCC internal variables
(__builtin_frame_address and __builtin_return_address) or on assembly
code.
<P>
In the case of the i386 platform (in 
glibc-x.x.x/sysdeps/i386/backtrace.c), a couple of lines of assembly
code are used to access the contents of the ebp and esp CPU registers,
which hold the address of the current stack frame and of the stack
pointer for any given function:
<P>
<pre>
register void *ebp __asm__ ("ebp");
register void *esp __asm__ ("esp");
</pre>
<P>
Starting from the value of ebp, it is easy to follow the chain of
pointers and move up to the initial stack frame. In this way you gather
the sequence of return addresses and build the backtrace.
<P>
At this point, you still have to resolve the return addresses
into function names, an operation dependent on the binary
format you are using. In the case of ELF, it is performed
by using a dynamic linker internal function (_dl_addr(), see
glibc-x.x.x/sysdeps/generic/elf/backtracesyms.c).
<P>
<h3>Conclusion</h3>
<P>
Are you working on a complex program that contains a lot of different
execution paths that make you cluelessly wander through hundreds of
functions, desperately trying to understand which one called which
other function? Wander no more and print a backtrace. It's free, fast and easy.
While you are at it, do yourself a favour and also use that function 
inside a fault signal handler--it's guaranteed to help you with those
nasty bugs that appear once in a thousand runs.
<P>
<B>Gianluca Insolvibile</b> has been a Linux enthusiast since kernel
0.99pl4. He currently deals with networking and digital video research
and development. 
<P><br><br><center><a href="https://www.ssc.com/lj/subs/NewUSA.html"><img src="/images/ljsubsbutton.png" height="88" width="90"></a></center></font>
</td></tr></table><br>


</td></tr></table>


<!-- COMMENTS NAVIGATION BAR START -->


<a name="comments"></a>
<table width="99%" border="0" cellspacing="0" cellpadding="0">
<tr><td bgcolor="#cfcfbb" align="center"><font class="content" color="#000000">"Stack Backtracing Inside Your Program" | <a href="user.php"><font color="#000000">Login/Create an Account</font></a> | <B>1</B> comment</font></td></tr>
<tr><td bgcolor="#efefef" align="center" width="100%">
<table border="0"><tr><td><font class="content">
<form method="get" action="article.php">
<font color="#000000">Threshold</font> <select name="thold">
<option value="-1">-1</option>
<option value="0" selected>0</option>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
<option value="5">5</option>
</select> <select name=mode><option value="nocomments">No Comments</option>
<option value="nested">Nested</option>
<option value="flat">Flat</option>
<option value="thread" selected>Thread</option>
</select> <select name="order"><option value="0" selected>Oldest First</option>
<option value="1">Newest First</option>
<option value="2">Highest Scores First</option>
</select>
<input type="hidden" name="sid" value="6391">
<input type="submit" value="Refresh"></form>
</font></td><td bgcolor="#efefef"><font class="content"><form action="comments.php" method="post"><input type="hidden" name="pid" value=""><input type="hidden" name="sid" value="6391"><input type="hidden" name="op" value="Reply">&nbsp;&nbsp;<input type="submit" value="Post Comment"></form></font></td></tr></table>
</td></tr><tr><td bgcolor="#cfcfbb" align="center"><font class="tiny">The comments are owned by the poster. We aren't responsible for their content.</font></td></tr>
</table>

<!-- COMMENTS NAVIGATION BAR END -->

<a name="8735"></a><table width="99%" border="0"><tr bgcolor="#efefef"><td width="500"><b>Re: Stack Backtracing Inside Your Program</b> <font class="content">(Score: 0)<br>by Anonymous on Tuesday, August 12, 2003</font></td></tr><tr><td>printf in a signal handler? All y'all are just <em>asking</em> for trouble in the future.<br />
</td></tr></table><br><br><font class="content"> [ <a href="comments.php?op=Reply&amp;pid=8735&amp;sid=6391&amp;mode=&amp;order=&amp;thold=">Reply to This</a> ]</font><br><br></ul><!-- Finished article caching (or not caching). --></td><td bgcolor="#ffffff"><img src="/themes/NewLJ/images/pixel.gif" width=10 height=1 border=0 alt="">
</td></tr></table>
<table width="100%" cellpadding="0" cellspacing="0" border="0" bgcolor="#ffffff" align="center"><tr valign="top">
<td align="center" height="17">
<IMG height="17" alt="" hspace="0" src="/themes/NewLJ/images/corner-bottom-left.png" width="17" align="left">
<IMG height="17" alt="" hspace="0" src="/themes/NewLJ/images/corner-bottom-right.png" width="17" align="right">
</td></tr></table>
<br><table width="100%" cellpadding="0" cellspacing="0" border="0" bgcolor="#ffffff" align="center"><tr valign="top">
<td><IMG height="17" alt="" hspace="0" src="/themes/NewLJ/images/corner-top-left.png" width="17" align="left"></td>
<td width="100%">&nbsp;</td>
<td><IMG height="17" alt="" hspace="0" src="/themes/NewLJ/images/corner-top-right.gif" width="17" align="right"></td>
</tr><tr align="center">
<td width="100%" colspan="3">
<!-- BEGIN FOOTER -->
    <center><font class=tiny>

    <a href="http://www.ssc.com" target="blank"><img src="/images/ssc_logo.png" border=0></a> <br>

    © 1994-2003 Specialized Systems Consultants, Inc. (SSC) publishers of <i>Linux Journal</i>. <br>

    <center> <a href="http://www.ssc.com/ssc/privacy.html">Privacy Statement</a> <br>

    Syndicated news file: <a href="/news.rss">news.rss</a><br>Powered by <a href="http://phpnuke.org" target="_blank">PHP-Nuke</a> <br>

    </font>
    </td>
</tr><tr>
<td><IMG height="17" alt="" hspace="0" src="/themes/NewLJ/images/corner-bottom-left.png" width="17" align="left"></td>
<td width="100%">&nbsp;</td>
<td><IMG height="17" alt="" hspace="0" src="/themes/NewLJ/images/corner-bottom-right.png" width="17" align="right"></td>
</tr></table>
</TD></TR></TABLE>

    </body>

    </html>
--------------000404020907010407050909--