BDE 4.39.x Production Release
Loading...
Searching...
No Matches
bsls_stackaddressutil.h
Go to the documentation of this file.
1/// @file bsls_stackaddressutil.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// bsls_stackaddressutil.h -*-C++-*-
8#ifndef INCLUDED_BSLS_STACKADDRESSUTIL
9#define INCLUDED_BSLS_STACKADDRESSUTIL
10
11#include <bsls_ident.h>
12BSLS_IDENT("$Id: $")
13
14/// @defgroup bsls_stackaddressutil bsls_stackaddressutil
15/// @brief Provide a utility for obtaining return addresses from the stack.
16/// @addtogroup bsl
17/// @{
18/// @addtogroup bsls
19/// @{
20/// @addtogroup bsls_stackaddressutil
21/// @{
22///
23/// <h1> Outline </h1>
24/// * <a href="#bsls_stackaddressutil-purpose"> Purpose</a>
25/// * <a href="#bsls_stackaddressutil-classes"> Classes </a>
26/// * <a href="#bsls_stackaddressutil-description"> Description </a>
27/// * <a href="#bsls_stackaddressutil-usage"> Usage </a>
28/// * <a href="#bsls_stackaddressutil-example-1-obtaining-return-addresses-and-verifying-their-validity"> Example 1: Obtaining Return Addresses and Verifying Their Validity </a>
29/// * <a href="#bsls_stackaddressutil-define-func_address"> define FUNC_ADDRESS(p) (((void **) (void *) (p))[0]) </a>
30/// * <a href="#bsls_stackaddressutil-define-func_address"> define FUNC_ADDRESS(p) ((void *) (p)) </a>
31/// * <a href="#bsls_stackaddressutil-example-2-obtaining-a-cheapstack"> Example 2: Obtaining a "Cheapstack" </a>
32///
33/// # Purpose {#bsls_stackaddressutil-purpose}
34/// Provide a utility for obtaining return addresses from the stack.
35///
36/// # Classes {#bsls_stackaddressutil-classes}
37///
38/// - bsls::StackAddressUtil: utilities for obtaining addresses from the stack
39///
40/// @see balst_stacktraceutil
41///
42/// # Description {#bsls_stackaddressutil-description}
43/// This component defines a `struct`, `bsls::StackAddressUtil`,
44/// that provides a namespace for a function, `getStackAddresses`, that
45/// populates an array with an ordered sequence of return addresses from the
46/// current thread's function call stack. Each return address points to the
47/// (text) memory location of the first instruction to be executed upon
48/// returning from a called routine.
49///
50/// This component also provides a function, `formatCheapStack`, that builds a
51/// current stack trace and formats it with instructions on how to use
52/// `showfunc.tsk` to print out a stack trace matching where this function was
53/// called. This is a Bloomberg standard "cheapstack" output.
54///
55/// ## Usage {#bsls_stackaddressutil-usage}
56///
57///
58/// In this section we show the intended usage of this component.
59///
60/// ### Example 1: Obtaining Return Addresses and Verifying Their Validity {#bsls_stackaddressutil-example-1-obtaining-return-addresses-and-verifying-their-validity}
61///
62///
63/// In the following example we demonstrate how to obtain the sequence of
64/// function return addresses from the stack using `getStackAddresses`.
65///
66/// First, we define `AddressEntry`, which will contain a pointer to the
67/// beginning of a function and an index corresponding to the function. The `<`
68/// operator is defined so that a vector of address entries can be sorted in the
69/// order of the function addresses. The address entries will be populated so
70/// that the entry containing `&funcN` when `N` is an integer will have an index
71/// of `N`.
72/// @code
73/// struct AddressEntry {
74/// void *d_funcAddress;
75/// int d_index;
76///
77/// // CREATORS
78/// AddressEntry(void *funcAddress, int index)
79/// : d_funcAddress(funcAddress)
80/// , d_index(index)
81/// // Create an 'AddressEntry' object and initialize it with the
82/// // specified 'funcAddress' and 'index'.
83/// {}
84///
85/// bool operator<(const AddressEntry& rhs) const
86/// // Return 'true' if the address stored in the object is lower than
87/// // the address stored in 'rhs' and 'false' otherwise. Note that
88/// // this is a member function for brevity, it only exists to
89/// // facilitate sorting 'AddressEntry' objects in a vector.
90/// {
91/// return d_funcAddress < rhs.d_funcAddress;
92/// }
93/// };
94/// @endcode
95/// Then, we define `entries`, a vector of address entries. This will be
96/// populated such that a given entry will contain function address `&funcN` and
97/// index `N`. The elements will be sorted according to function address.
98/// @code
99/// bsl::vector<AddressEntry> entries;
100/// @endcode
101/// Next, we define `findIndex`:
102/// @code
103/// static int findIndex(const void *retAddress)
104/// // Return the index of the address entry whose function uses an
105/// // instruction located at specified 'retAddress'. The behavior is
106/// // undefined unless 'retAddress' is the address of an instruction in
107/// // use by a function referred to by an address entry in 'entries'.
108/// {
109/// unsigned int u = 0;
110/// while (u < entries.size()-1 &&
111/// retAddress >= entries[u+1].d_funcAddress) {
112/// ++u;
113/// }
114/// assert(u < entries.size());
115/// assert(retAddress >= entries[u].d_funcAddress);
116///
117/// int ret = entries[u].d_index;
118///
119/// if (veryVerbose) {
120/// P_(retAddress) P_(entries[u].d_funcAddress) P(ret);
121/// }
122///
123/// return ret;
124/// }
125/// @endcode
126/// Then, we define a volatile global variable that we will use in calculation
127/// to discourage compiler optimizers from inlining:
128/// @code
129/// volatile unsigned int volatileGlobal = 1;
130/// @endcode
131/// Next, we define a set of functions that will be called in a nested fashion
132/// -- `func5` calls `func4` who calls `fun3` and so on. In each function, we
133/// will perform some inconsequential instructions to prevent the compiler from
134/// inlining the functions.
135///
136/// Note that we know the `if` conditions in these 5 subroutines never evaluate
137/// to `true`, however, the optimizer cannot figure that out, and that will
138/// prevent it from inlining here.
139/// @code
140/// static unsigned int func1();
141/// static unsigned int func2()
142/// {
143/// if (volatileGlobal > 10) {
144/// return (volatileGlobal -= 100) * 2 * func2(); // RETURN
145/// }
146/// else {
147/// return volatileGlobal * 2 * func1(); // RETURN
148/// }
149/// }
150/// static unsigned int func3()
151/// {
152/// if (volatileGlobal > 10) {
153/// return (volatileGlobal -= 100) * 2 * func3(); // RETURN
154/// }
155/// else {
156/// return volatileGlobal * 3 * func2(); // RETURN
157/// }
158/// }
159/// static unsigned int func4()
160/// {
161/// if (volatileGlobal > 10) {
162/// return (volatileGlobal -= 100) * 2 * func4(); // RETURN
163/// }
164/// else {
165/// return volatileGlobal * 4 * func3(); // RETURN
166/// }
167/// }
168/// static unsigned int func5()
169/// {
170/// if (volatileGlobal > 10) {
171/// return (volatileGlobal -= 100) * 2 * func5(); // RETURN
172/// }
173/// else {
174/// return volatileGlobal * 5 * func4(); // RETURN
175/// }
176/// }
177/// static unsigned int func6()
178/// {
179/// if (volatileGlobal > 10) {
180/// return (volatileGlobal -= 100) * 2 * func6(); // RETURN
181/// }
182/// else {
183/// return volatileGlobal * 6 * func5(); // RETURN
184/// }
185/// }
186/// @endcode
187/// Next, we define the macro FUNC_ADDRESS, which will take a parameter of
188/// `&<function name>` and return a pointer to the actual beginning of the
189/// function's code, which is a non-trivial and platform-dependent exercise.
190/// Note: this doesn't work on Windows for global routines.
191/// @code
192/// #if defined(BSLS_PLATFORM_OS_AIX)
193/// # define FUNC_ADDRESS(p) (((void **) (void *) (p))[0]) {#bsls_stackaddressutil-define-func_address}
194///
195/// #else
196/// # define FUNC_ADDRESS(p) ((void *) (p)) {#bsls_stackaddressutil-define-func_address}
197///
198/// #endif
199/// @endcode
200/// Then, we define `func1`, the last function to be called in the chain of
201/// nested function calls. `func1` uses
202/// `bsls::StackAddressUtil::getStackAddresses` to get an ordered sequence of
203/// return addresses from the current thread's function call stack and uses the
204/// previously defined `findIndex` function to verify those address are correct.
205/// @code
206/// unsigned int func1()
207/// // Call 'getAddresses' and verify that the returned set of addresses
208/// // matches our expectations.
209/// {
210/// @endcode
211/// Next, we populate and sort the `entries` table, a sorted array of
212/// `AddressEntry` objects that will allow `findIndex` to look up within which
213/// function a given return address can be found.
214/// @code
215/// entries.clear();
216/// entries.push_back(AddressEntry(0, 0));
217/// entries.push_back(AddressEntry(FUNC_ADDRESS(&func1), 1));
218/// entries.push_back(AddressEntry(FUNC_ADDRESS(&func2), 2));
219/// entries.push_back(AddressEntry(FUNC_ADDRESS(&func3), 3));
220/// entries.push_back(AddressEntry(FUNC_ADDRESS(&func4), 4));
221/// entries.push_back(AddressEntry(FUNC_ADDRESS(&func5), 5));
222/// entries.push_back(AddressEntry(FUNC_ADDRESS(&func6), 6));
223/// bsl::sort(entries.begin(), entries.end());
224/// @endcode
225/// Then, we obtain the stack addresses with `getStackAddresses`.
226/// @code
227/// enum { BUFFER_LENGTH = 100 };
228/// void *buffer[BUFFER_LENGTH];
229/// bsl::memset(buffer, 0, sizeof(buffer));
230/// int numAddresses = bsls::StackAddressUtil::getStackAddresses(
231/// buffer,
232/// BUFFER_LENGTH);
233/// assert(numAddresses >= (int) entries.size());
234/// assert(numAddresses < BUFFER_LENGTH);
235/// assert(0 != buffer[numAddresses-1]);
236/// assert(0 == buffer[numAddresses]);
237/// @endcode
238/// Finally, we go through several of the first addresses returned in `buffer`
239/// and verify that each address corresponds to the routine we expect it to.
240///
241/// Note that on some, but not all, platforms there is an extra "narcissistic"
242/// frame describing `getStackAddresses` itself at the beginning of `buffer`.
243/// By starting our iteration through `buffer` at `k_IGNORE_FRAMES`, we
244/// guarantee that the first address we examine will be in `func1` on all
245/// platforms.
246/// @code
247/// int funcIdx = 1;
248/// int stackIdx = bsls::StackAddressUtil::k_IGNORE_FRAMES;
249/// for (; funcIdx < (int) entries.size(); ++funcIdx, ++stackIdx) {
250/// assert(stackIdx < numAddresses);
251/// assert(funcIdx == findIndex(buffer[stackIdx]));
252/// }
253///
254/// if (testStatus || veryVerbose) {
255/// Q(Entries:);
256/// for (unsigned int u = 0; u < entries.size(); ++u) {
257/// P_(u); P_((void *) entries[u].d_funcAddress);
258/// P(entries[u].d_index);
259/// }
260///
261/// Q(Stack:);
262/// for (int i = 0; i < numAddresses; ++i) {
263/// P_(i); P(buffer[i]);
264/// }
265/// }
266///
267/// return volatileGlobal;
268/// }
269/// @endcode
270///
271/// ### Example 2: Obtaining a "Cheapstack" {#bsls_stackaddressutil-example-2-obtaining-a-cheapstack}
272///
273///
274/// In this example we demonstrate how to use `formatCheapStack` to generate a
275/// string containing the current stack trace and instructions on how to print
276/// it out from `showfunc.tsk`. Note that `showfunc.tsk` is a Bloomberg tool
277/// that, when given an executable along with a series of function addresses
278/// from a process that was running that executable, will print out a
279/// human-readable stack trace with the names of the functions being called in
280/// that stack trace.
281///
282/// First, we define our function where we want to format the stack:
283/// @code
284/// struct MyTest {
285/// static void printCheapStack()
286/// {
287/// char str[128];
288/// bsls::StackAddressUtil::formatCheapStack(str, 128);
289/// printf("%s", str);
290/// }
291/// };
292/// @endcode
293/// Calling this function will then result in something like this being printed
294/// to standard output:
295/// @code
296/// Please run "/bb/bin/showfunc.tsk <binary_name_here> 403308 402641 ...
297/// ... 3710C1ED1D 400F49" to see the stack trace.
298/// @endcode
299/// Then, if you had encountered this output running the binary "mybinary.tsk",
300/// you could see your stack trace by running this command:
301/// @code
302/// /bb/bin/showfunc.tsk mybinary.tsk 403308 402641 3710C1ED1D 400F49
303/// @endcode
304/// This will produce output like this:
305/// @code
306/// 0x403308 _ZN6MyTest15printCheapStackEv + 30
307/// 0x402641 main + 265
308/// 0x3710c1ed1d ???
309/// 0x400f49 ???
310/// @endcode
311/// telling you that `MyTest::printCheapStack` was called directly from `main`.
312/// Note that if you had access to the binary name that was invoked, then that
313/// could be provided as the optional last argument to `printCheapStack` to get
314/// a `showfunc.tsk` command that can be more easily invoked, like this:
315/// @code
316/// struct MyTest2 {
317/// static void printCheapStack()
318/// {
319/// char str[128];
320/// bsls::StackAddressUtil::formatCheapStack(str, 128, "mybinary.tsk");
321/// printf("%s", str);
322/// }
323/// };
324/// @endcode
325/// resulting in output that looks like this:
326/// @code
327/// Please run "/bb/bin/showfunc.tsk mybinary.tsk 403308 402641 3710C1ED1D ...
328/// ... 400F49" to see the stack trace.
329/// @endcode
330/// @}
331/** @} */
332/** @} */
333
334/** @addtogroup bsl
335 * @{
336 */
337/** @addtogroup bsls
338 * @{
339 */
340/** @addtogroup bsls_stackaddressutil
341 * @{
342 */
343
344#include <bsls_platform.h>
345
346 // ============================
347 // class bsls::StackAddressUtil
348 // ============================
349
350
351namespace bsls {
352
353/// This struct provides a namespace for the function to obtain return
354/// addresses from the stack.
355///
356/// See @ref bsls_stackaddressutil
358
359#if defined(__SANITIZE_ADDRESS__) || defined(__SANITIZE_THREAD__)
360 enum { k_SANITIZER_ADJUST = 1 };
361#elif defined(__has_feature)
362# if __has_feature(address_sanitizer) || __has_feature(thread_sanitizer) \
363 || __has_feature(memory_sanitizer)
364 enum { k_SANITIZER_ADJUST = 1 };
365# else
366 enum { k_SANITIZER_ADJUST = 0 };
367# endif
368#else
369 enum { k_SANITIZER_ADJUST = 0 };
370#endif
371
372 public:
373
374 // On some platforms, 'getStackAddresses' finds a frame representing
375 // 'getStackAddresses' itself and possibly another frame representing
376 // another function it calls. These frames are usually unwanted.
377 // 'k_IGNORE_FRAMES' instructs the caller as to whether the first N frames
378 // are such unwanted frames.
379
380#if defined(BSLS_PLATFORM_OS_LINUX) || defined(BSLS_PLATFORM_OS_DARWIN)
381 enum { k_IGNORE_FRAMES = 1 + k_SANITIZER_ADJUST };
382#else
383 enum { k_IGNORE_FRAMES = 0 + k_SANITIZER_ADJUST };
384#endif
385
386 // CLASS METHODS
387
388 /// Get an sequence of return addresses from the current thread's
389 /// function call stack, ordered from most recent call to least recent,
390 /// and load them into the specified array `*buffer`, which is at least
391 /// the specified `maxFrames` in length. A return address is an address
392 /// stored on the stack that points to the first instruction that will
393 /// be executed after the called subroutine returns. If there are more
394 /// than `maxFrames` frames on the stack, only the return addresses for
395 /// the `maxFrames` most recent routine calls are stored. When this
396 /// routine completes, `buffer` will contain an ordered sequence of
397 /// return addresses, sorted such that recent calls occur in the array
398 /// before calls that took place before them. Return the number of
399 /// stack frames stored into `buffer` on success, and a negative value otherwise.
400 ///
401 /// \pre The behavior is undefined unless `maxFrames >= 0` and
402 /// `buffer` has room for at least `maxFrames` addresses.
403 ///
404 /// \note Note that this routine may fill `buffer` with garbage if the stack is corrupt,
405 /// or on Windows if some stack frames represent optimized routines.
406 static
407 int getStackAddresses(void **buffer,
408 int maxFrames);
409
410 /// Load the specified `output` buffer having the specified `length`
411 /// with the Bloomberg standard "cheapstack" contents as a
412 /// null-terminated string. On successfully obtaining the current call
413 /// stack, this will be instructions on how to run the Bloomberg tool
414 /// `showfunc.tsk` (with the optionally specified `taskname`, otherwise
415 /// with an attempt to obtain the system-specific process name) to get
416 /// details of the current call stack where `formatCheapStack` was
417 /// called. On failure, text indicating that the call stack was not
418 /// obtainable will be written to `output`. If `length` is not long
419 /// enough for the entire output it will be truncated.
420 ///
421 /// \pre The behavior is undefined unless `0 <= length` and `output` has the capacity for at
422 /// least `length` bytes.
423 static
424 void formatCheapStack(char *output, int length, const char *taskname = 0);
425};
426
427} // close package namespace
428
429
430#endif
431
432// ----------------------------------------------------------------------------
433// Copyright 2018 Bloomberg Finance L.P.
434//
435// Licensed under the Apache License, Version 2.0 (the "License");
436// you may not use this file except in compliance with the License.
437// You may obtain a copy of the License at
438//
439// http://www.apache.org/licenses/LICENSE-2.0
440//
441// Unless required by applicable law or agreed to in writing, software
442// distributed under the License is distributed on an "AS IS" BASIS,
443// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
444// See the License for the specific language governing permissions and
445// limitations under the License.
446// ----------------------------- END-OF-FILE ----------------------------------
447
448/** @} */
449/** @} */
450/** @} */
Definition bsls_stackaddressutil.h:357
static int getStackAddresses(void **buffer, int maxFrames)
@ k_IGNORE_FRAMES
Definition bsls_stackaddressutil.h:383
static void formatCheapStack(char *output, int length, const char *taskname=0)
#define BSLS_IDENT(str)
BSLS_IDENT() - insert string into .comment binary segment (if supported)
Definition bsls_ident.h:238
Definition bdlt_iso8601util.h:707