libc
on Solaris 9 and later, provides a useful function called printstack
, to print a symbolic stack trace to the specified file descriptor. This is useful for reporting errors from an application during run-time.If the stack trace appears corrupted, or if the stack cannot be read,
printstack()
returns -1.Programmatic example:
% more printstack.c
#include <stdio.h>
#include <ucontext.h>
int callee(int file) {
printstack(file);
return (0);
}
int caller() {
int a;
a = callee (fileno(stdout));
return (a);
}
int main() {
caller();
return (0);
}
% cc -o stacktrace stacktrace.c
% ./stacktrace
/tmp/stacktrace:callee+0x18
/tmp/stacktrace:caller+0x22
/tmp/stacktrace:main+0x14
/tmp/stacktrace:0x6d2
The
printstack()
function uses dladdr1()
to obtain symbolic symbol names. As a result, only global symbols are reported as symbol names by printstack()
.
% CC -o stacktrace stacktrace.c
% ./stacktrace
/tmp/stacktrace:__1cGcallee6Fi_i_+0x18
/tmp/stacktrace:__1cGcaller6F_i_+0x22
/tmp/stacktrace:main+0x14
/tmp/stacktrace:0x91a
The stack trace from a C++ program, will have all the symbols in their mangled form. So as of now, the programmers may need to have their own wrapper functions to print the stack trace in unmangled form.
There has been an RFE (Request For Enhancement) in place against Solaris'
libc
to print the stack trace in unmangled form, when printstack()
has been called from a C++ program. This will be released as a libc
patch for Solaris
% elfdump -CsN.symtab libc.so | grep printstack
[5275] 0x00052629 0x00000051 FUNC GLOB D 0 .text _printstack
[6332] 0x00052629 0x00000051 FUNC WEAK D 0 .text printstack
Since the object code is automatically linked with
libc
during the creation of an executable or a dynamic library, the programmer need not specify -lc
on the compile line.Suggested Reading:
Man page of
walkcontext
or printstack
This is very helpful. Can you show an example of how to printstack to a user-defined file or string?
ReplyDeletewhich version onwards does solaris have printstack()?
ReplyDeleteI am using SunOS 5.8 . printstack returns undefined symbol.
Tom,
ReplyDeleteprintstack() & walkcontext() interfaces were introduced in Solaris 9.
Sorry for not being very specific (and for the typo too, where I mentioned about an RFE for unmangled stack)
Thanks for the prompt clarification.
ReplyDeleteAm currently working to implement that on 5.7.... I wonder why this was so hard to find on Google??? :-)
You can actually look at the implementation for walkstack() and printstack() at opensolaris.org
ReplyDeleteThis comment has been removed by a blog administrator.
ReplyDeletewould it not be easier if it would be possible to have the compiler instrument the actual source code to print stack trace on stdout (might be, use a compile time flag)? its quite painful to put entry and exit statements in a huge system. btw does such an option already exist?
ReplyDeletewould it not be easier if it would be possible to have the compiler instrument the actual source code to print stack trace on stdout
ReplyDeleteApparently it is not the job of the compiler. It is pretty easy to write a simple tool that does it, ourselves though.
btw does such an option already exist?
No
its quite painful to put entry and exit statements in a huge system
One simple solution is not to touch the existing code at all, but to interpose upon the symbols where you want to have the call stack. Of course the symbols must have "global" (but not "protected") scope. Please have a look at hijacking a function call (interposing) blog post, to learn more about writing an interposer.
Another advantage of this approach is that the application code remains clean -- you can plug-in (preload) the interposer when you need to look at the call stack; and remove it when it is no longer useful.
This is really helpful. Keep on sharing such useful tips & tricks in the future too :)
ReplyDelete