BDE 4.14.0 Production release
|
Provide a utility for obtaining return addresses from the stack.
This component defines a struct
, bsls::StackAddressUtil
, that provides a namespace for a function, getStackAddresses
, that populates an array with an ordered sequence of return addresses from the current thread's function call stack. Each return address points to the (text) memory location of the first instruction to be executed upon returning from a called routine.
This component also provides a function, formatCheapStack
, that builds a current stack trace and formats it with instructions on how to use showfunc.tsk
to print out a stack trace matching where this function was called. This is a Bloomberg standard "cheapstack" output.
In this section we show the intended usage of this component.
In the following example we demonstrate how to obtain the sequence of function return addresses from the stack using getStackAddresses
.
First, we define AddressEntry
, which will contain a pointer to the beginning of a function and an index corresponding to the function. The <
operator is defined so that a vector of address entries can be sorted in the order of the function addresses. The address entries will be populated so that the entry containing &funcN
when N
is an integer will have an index of N
.
Then, we define entries
, a vector of address entries. This will be populated such that a given entry will contain function address &funcN
and index N
. The elements will be sorted according to function address.
Next, we define findIndex
:
Then, we define a volatile global variable that we will use in calculation to discourage compiler optimizers from inlining:
Next, we define a set of functions that will be called in a nested fashion – func5
calls func4
who calls fun3
and so on. In each function, we will perform some inconsequential instructions to prevent the compiler from inlining the functions.
Note that we know the if
conditions in these 5 subroutines never evaluate to true
, however, the optimizer cannot figure that out, and that will prevent it from inlining here.
Next, we define the macro FUNC_ADDRESS, which will take a parameter of &<function name>
and return a pointer to the actual beginning of the function's code, which is a non-trivial and platform-dependent exercise. Note: this doesn't work on Windows for global routines.
Then, we define func1
, the last function to be called in the chain of nested function calls. func1
uses bsls::StackAddressUtil::getStackAddresses
to get an ordered sequence of return addresses from the current thread's function call stack and uses the previously defined findIndex
function to verify those address are correct.
Next, we populate and sort the entries
table, a sorted array of AddressEntry
objects that will allow findIndex
to look up within which function a given return address can be found.
Then, we obtain the stack addresses with getStackAddresses
.
Finally, we go through several of the first addresses returned in buffer
and verify that each address corresponds to the routine we expect it to.
Note that on some, but not all, platforms there is an extra "narcissistic" frame describing getStackAddresses
itself at the beginning of buffer
. By starting our iteration through buffer
at k_IGNORE_FRAMES
, we guarantee that the first address we examine will be in func1
on all platforms.
In this example we demonstrate how to use formatCheapStack
to generate a string containing the current stack trace and instructions on how to print it out from showfunc.tsk
. Note that showfunc.tsk
is a Bloomberg tool that, when given an executable along with a series of function addresses from a process that was running that executable, will print out a human-readable stack trace with the names of the functions being called in that stack trace.
First, we define our function where we want to format the stack:
Calling this function will then result in something like this being printed to standard output:
Then, if you had encountered this output running the binary "mybinary.tsk", you could see your stack trace by running this command:
This will produce output like this:
telling you that MyTest::printCheapStack
was called directly from main
. Note that if you had access to the binary name that was invoked, then that could be provided as the optional last argument to printCheapStack
to get a showfunc.tsk
command that can be more easily invoked, like this:
resulting in output that looks like this: