BDE 4.14.0 Production release
Loading...
Searching...
No Matches
balst_stacktraceutil.h
Go to the documentation of this file.
1/// @file balst_stacktraceutil.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// balst_stacktraceutil.h -*-C++-*-
8#ifndef INCLUDED_BALST_STACKTRACEUTIL
9#define INCLUDED_BALST_STACKTRACEUTIL
10
11#include <bsls_ident.h>
12BSLS_IDENT("$Id: $")
13
14/// @defgroup balst_stacktraceutil balst_stacktraceutil
15/// @brief Provide low-level utilities for obtaining & printing a stack-trace.
16/// @addtogroup bal
17/// @{
18/// @addtogroup balst
19/// @{
20/// @addtogroup balst_stacktraceutil
21/// @{
22///
23/// <h1> Outline </h1>
24/// * <a href="#balst_stacktraceutil-purpose"> Purpose</a>
25/// * <a href="#balst_stacktraceutil-classes"> Classes </a>
26/// * <a href="#balst_stacktraceutil-description"> Description </a>
27/// * <a href="#balst_stacktraceutil-usage"> Usage </a>
28/// * <a href="#balst_stacktraceutil-example-1-loading-stack-trace-directly-from-the-stack"> Example 1: Loading Stack-Trace Directly from the Stack </a>
29/// * <a href="#balst_stacktraceutil-example-2-loading-a-stack-trace-from-an-array-of-stack-addresses"> Example 2: Loading a Stack-Trace from an Array of Stack Addresses </a>
30/// * <a href="#balst_stacktraceutil-example-3-outputting-a-hex-stack-trace"> Example 3: Outputting a Hex Stack Trace </a>
31///
32/// # Purpose {#balst_stacktraceutil-purpose}
33/// Provide low-level utilities for obtaining & printing a stack-trace.
34///
35/// # Classes {#balst_stacktraceutil-classes}
36///
37/// - balst::StackTraceUtil: utilities for `balst::StackTrace` objects
38///
39/// @see balst_stacktraceprintutil
40///
41/// # Description {#balst_stacktraceutil-description}
42/// This component provides a namespace for functions used in
43/// obtaining and printing a stack-trace. Note that clients interested in
44/// simply printing a stack-trace are encouraged to use the
45/// @ref balst_stacktraceprintutil component instead.
46///
47/// ## Usage {#balst_stacktraceutil-usage}
48///
49///
50/// This section illustrates intended usage for this component.
51///
52/// The following examples demonstrate two distinct ways to load and print a
53/// stack-trace with `balst::StackTraceUtil` using (1) `loadStackTraceFromStack`
54/// and (2) `loadStackTraceFromAddresses`.
55///
56/// ### Example 1: Loading Stack-Trace Directly from the Stack {#balst_stacktraceutil-example-1-loading-stack-trace-directly-from-the-stack}
57///
58///
59/// We start by defining a routine, `recurseExample1`, that will recurse the
60/// specified `depth` times, then call `traceExample1`:
61/// @code
62/// int traceExample1(); // forward declaration
63///
64/// int recurseExample1(int *depth)
65/// // Recurse the specified 'depth' number of times, then call
66/// // 'traceExample1'.
67/// {
68/// int rc;
69///
70/// if (--*depth > 0) {
71/// rc = recurseExample1(depth);
72/// }
73/// else {
74/// rc = traceExample1();
75/// }
76///
77/// if (rc) {
78/// return rc; // RETURN
79/// }
80///
81/// ++*depth; // Prevent compiler from optimizing tail recursion as a
82/// // loop.
83///
84/// return 0;
85///
86/// }
87/// @endcode
88/// Then, we define the function `traceExample1`, that will print a stack-trace:
89/// @code
90/// int traceExample1()
91/// {
92/// @endcode
93/// Now, we create a `balst::StackTrace` object and call
94/// `loadStackTraceFrameStack` to load the information from the stack of the
95/// current thread into the stack-trace object.
96///
97/// In this call to `loadStackTraceFromStack`, we use the default value of
98/// `maxFrames`, which is at least 1024 and the default value for
99/// `demanglingPreferredFlag`, which is `true`, meaning that the operation will
100/// attempt to demangle function names. Note that the object `stackTrace` takes
101/// very little room on the stack, and by default allocates most of its memory
102/// directly from virtual memory without going through the heap, minimizing
103/// potential complications due to stack-size limits and possible heap
104/// corruption.
105/// @code
106/// balst::StackTrace stackTrace;
107/// int rc = balst::StackTraceUtil::loadStackTraceFromStack(&stackTrace);
108///
109/// if (rc) { // Error handling is omitted.
110/// return rc; // RETURN
111/// }
112/// @endcode
113/// Finally, we use `printFormatted` to stream out the stack-trace, one frame
114/// per line, in a concise, human-readable format.
115/// @code
116/// balst::StackTraceUtil::printFormatted(bsl::cout, stackTrace);
117/// return 0;
118/// }
119/// @endcode
120/// The output from the preceding example on Solaris is as follows:
121/// @code
122/// (0): traceExample1()+0x28 at 0x327d0 in balst_stacktraceutil.t.dbg_exc_mt
123/// (1): recurseExample1(int*)+0x54 at 0x32e30 in balst_stacktraceutil.t.dbg_exc
124/// (2): recurseExample1(int*)+0x44 at 0x32e20 in balst_stacktraceutil.t.dbg_exc
125/// (3): recurseExample1(int*)+0x44 at 0x32e20 in balst_stacktraceutil.t.dbg_exc
126/// (4): recurseExample1(int*)+0x44 at 0x32e20 in balst_stacktraceutil.t.dbg_exc
127/// (5): recurseExample1(int*)+0x44 at 0x32e20 in balst_stacktraceutil.t.dbg_exc
128/// (6): main+0x24c at 0x36c10 in balst_stacktraceutil.t.dbg_exc_mt
129/// (7): _start+0x5c at 0x31d4c in balst_stacktraceutil.t.dbg_exc_mt
130/// @endcode
131/// Notice that the lines have been truncated to fit this 79 column source file,
132/// and that on AIX or Windows, source file name and line number information
133/// will also be displayed.
134///
135/// ### Example 2: Loading a Stack-Trace from an Array of Stack Addresses {#balst_stacktraceutil-example-2-loading-a-stack-trace-from-an-array-of-stack-addresses}
136///
137///
138/// In this example, we demonstrate obtaining return addresses from the stack
139/// using `bsls::StackAddressUtil`, and later using them to load a
140/// `balst::StackTrace` object with a description of the stack. This approach
141/// may be desirable if one wants to quickly save the addresses that are the
142/// basis for a stack-trace, postponing the more time-consuming translation of
143/// those addresses to more human-readable debug information until later. To do
144/// this, we create an array of pointers to hold the return addresses from the
145/// stack, which may not be desirable if we are in a situation where there isn't
146/// much room on the stack.
147///
148/// First, we define a routine `recurseExample2` which will recurse the
149/// specified `depth` times, then call `traceExample2`.
150/// @code
151/// int traceExample2(); // forward declaration
152///
153/// int recurseExample2(int *depth)
154/// // Recurse the specified 'depth' number of times, then call
155/// // 'traceExample2', which will print a stack-trace.
156/// {
157/// int rc;
158///
159/// if (--*depth > 0) {
160/// rc = recurseExample2(depth);
161/// }
162/// else {
163/// rc = traceExample2();
164/// }
165///
166/// if (rc) {
167/// return rc; // RETURN
168/// }
169///
170/// ++*depth; // Prevent compiler from optimizing tail recursion as a
171/// // loop.
172///
173/// return 0;
174/// }
175///
176/// int traceExample2()
177/// {
178/// @endcode
179/// Then, within `traceExample2`, we create a stack-trace object and an array
180/// `addresses` to hold some addresses.
181/// @code
182/// balst::StackTrace stackTrace;
183/// enum { ARRAY_LENGTH = 50 };
184/// void *addresses[ARRAY_LENGTH];
185/// @endcode
186/// Next, we call `bsls::StackAddressUtil::getStackAddresses` to get the stored
187/// return addresses from the stack and load them into the array `addresses`.
188/// The call returns the number of addresses saved into the array, which will be
189/// less than or equal to `ARRAY_LENGTH`.
190/// @code
191/// int numAddresses = bsls::StackAddressUtil::getStackAddresses(
192/// addresses,
193/// ARRAY_LENGTH);
194/// @endcode
195/// Then, we call `loadStackTraceFromAddressArray` to initialize the information
196/// in the stack-trace object, such as function names, source file names, and
197/// line numbers, if they are available. The optional argument,
198/// `demanglingPreferredFlag`, defaults to `true`.
199/// @code
200/// int rc = balst::StackTraceUtil::loadStackTraceFromAddressArray(
201/// &stackTrace,
202/// addresses,
203/// numAddresses);
204///
205/// if (rc) { // Error handling is omitted.
206/// return rc; // RETURN
207/// }
208/// @endcode
209/// Finally, we can print out the stack-trace object using `printFormatted`, or
210/// iterate through the stack-trace frames, printing them out one by one. In
211/// this example, we want instead to output only function names, and not line
212/// numbers, source file names, or library names, so we iterate through the
213/// stack-trace frames and print out only the properties we want. Note that if
214/// a string is unknown, it is represented as "", here we print it out as
215/// "--unknown--" to let the user see that the name was unresolved.
216/// @code
217/// for (int i = 0; i < stackTrace.length(); ++i) {
218/// const balst::StackTraceFrame& frame = stackTrace[i];
219///
220/// const char *symbol = frame.isSymbolNameKnown()
221/// ? frame.symbolName().c_str()
222/// : "--unknown__";
223/// bsl::cout << '(' << i << "): " << symbol << endl;
224/// }
225///
226/// return 0;
227/// }
228/// @endcode
229/// Running this example would produce the following output:
230/// @code
231/// (0): traceExample2()
232/// (1): recurseExample2(int*)
233/// (2): recurseExample2(int*)
234/// (3): recurseExample2(int*)
235/// (4): recurseExample2(int*)
236/// (5): recurseExample2(int*)
237/// (6): main
238/// (7): _start
239/// @endcode
240///
241/// ### Example 3: Outputting a Hex Stack Trace {#balst_stacktraceutil-example-3-outputting-a-hex-stack-trace}
242///
243///
244/// In this example, we demonstrate how to output return addresses from the
245/// stack to a stream in hex. Note that in this case the stack trace is never
246/// stored to a data object -- when the `operator<<` is passed a pointer to the
247/// `hexStackTrace` function, it calls the `hexStackTrace` function, which
248/// gathers the stack addresses and immediately streams them out. After the
249/// `operator<<` is finished, the stack addresses are no longer stored anywhere.
250///
251/// First, we define a routine `recurseExample3` which will recurse the
252/// specified `depth` times, then call `traceExample3`.
253/// @code
254/// void traceExample3(); // forward declaration
255///
256/// void recurseExample3(int *depth)
257/// // Recurse the specified 'depth' number of times, then call
258/// // 'traceExample3', which will print a stack-trace.
259/// {
260/// if (--*depth > 0) {
261/// recurseExample3(depth);
262/// }
263/// else {
264/// traceExample3();
265/// }
266///
267/// ++*depth; // Prevent compiler from optimizing tail recursion as a
268/// // loop.
269/// }
270///
271/// void traceExample3()
272/// {
273/// // Now, within 'traceExample3', we output the stack addresses in hex by
274/// // streaming the function pointer 'hexStackTrace' to the ostream:
275///
276/// bsl::cout << balst::StackTraceUtil::hexStackTrace << endl;
277/// }
278/// @endcode
279/// Finally, the output appears as a collection of hex values streamed out
280/// separated by spaces.
281/// @code
282/// 0x10001e438 0x10001e3b8 0x10001e3b0 0x10001e3b0 0x10001e3b0 0x10001e3b0 ...
283/// @endcode
284/// The hex stack traces can be translated to a human-readable stack trace
285/// using tools outside of BDE, such as Bloomberg's `/bb/bin/showfunc.tsk`:
286/// @code
287/// $ /bb/bin/showfunc.tsk <path to executable> 0x10001e438 0x10001e3b8 ...
288/// 0x10001e438 .traceExample3__Fv + 64
289/// 0x10001e3b8 .recurseExample3__FPi + 72
290/// 0x10001e3b0 .recurseExample3__FPi + 64
291/// 0x10001e3b0 .recurseExample3__FPi + 64
292/// 0x10001e3b0 .recurseExample3__FPi + 64
293/// 0x10001e3b0 .recurseExample3__FPi + 64
294/// 0x100000ba0 .main + 648
295/// 0x1000002fc .__start + 116
296/// $
297/// @endcode
298/// @}
299/** @} */
300/** @} */
301
302/** @addtogroup bal
303 * @{
304 */
305/** @addtogroup balst
306 * @{
307 */
308/** @addtogroup balst_stacktraceutil
309 * @{
310 */
311
312#include <balscm_version.h>
313
314#include <balst_stacktrace.h>
315
316#include <bslma_allocator.h>
317
318#include <bsl_iosfwd.h>
319
320
321namespace balst {
322
323/// This `struct` serves as a namespace for a collection of functions that
324/// are useful for initializing and printing a stack-trace object.
326
327 // CLASS METHODS
328
329 /// Write to the specified `stream` the stack addresses from a stack
330 /// trace of the current thread, in hex from top to bottom, and return
331 /// `stream`.
332 static
333 bsl::ostream& hexStackTrace(bsl::ostream &stream);
334
335 /// Populate the specified `result` with stack-trace information from
336 /// the stack, described by the specified array of `addresses` of length
337 /// `numAddresses`. Optionally specify `demanglingPreferredFlag` to
338 /// indicate whether or not to attempt to perform demangling, however,
339 /// demangling is always performed on the Windows platform and never
340 /// performed on Solaris using the CC compiler regardless of the value
341 /// of `demanglingPreferredFlag`. If `demanglingPreferredFlag` is not
342 /// specified, demangling is performed on those platforms that support
343 /// it. Return 0 on success, and a non-zero value otherwise. Any
344 /// frames previously contained in the stack-trace object are discarded.
345 /// The behavior is undefined unless `addresses` contains at least
346 /// `numAddresses` addresses. Note that the return addresses from the
347 /// stack can be obtained by calling
348 /// `bsls::StackAddressUtil::getStackAddresses`, and that demangling
349 /// sometimes involves calling `malloc`.
350 static
352 StackTrace *result,
353 const void * const addresses[],
354 int numAddresses,
355 bool demanglingPreferredFlag = true);
356
357 /// Populate the specified `result` object with information about the
358 /// current thread's program stack. Optionally specify `maxFrames` to
359 /// indicate the maximum number of frames to take from the top of the
360 /// stack. If `maxFrames` is not specified, the default limit is at
361 /// least 1024. Optionally specify `demanglingPreferredFlag` to
362 /// indicate whether to attempt to perform demangling, if possible. If
363 /// `demanglingPreferredFlag` is not specfied, demangling is assumed to
364 /// be preferred, however, demangling is always performed on the Windows
365 /// platform and never performed on Solaris using the CC compiler
366 /// regardless of the value of `demanglingPreferredFlag`. Any frames
367 /// previously contained in the `stackTrace` object are discarded.
368 /// Return 0 on success, and a non-zero value otherwise. The behavior
369 /// is undefined unless `maxFrames` (if specified) is greater than 0.
370 /// Note that demangling may involve calling `malloc`.
371 static
373 int maxFrames = -1,
374 bool demanglingPreferredFlag = true);
375
376 /// Stream the specified `stackTrace` to the specified `stream` in some
377 /// multi-line, human-readable format. Note that this operation
378 /// attempts to avoid using the default allocator.
379 static
380 bsl::ostream& printFormatted(bsl::ostream& stream,
381 const StackTrace& stackTrace);
382
383 /// Write the value of the specified `stackTraceFrame` to the specified
384 /// output `stream` in some single-line, human-readable format and
385 /// return a reference to `stream`. The name of the symbol is
386 /// represented by the `symbolName` property of `stackTraceFrame`, if
387 /// known; otherwise, it is represented by the `mangledSymbolName`
388 /// property, if known; otherwise, it is represented by "--unknown--".
389 /// Other frame attributes are written only if their values are known.
390 /// Note that the format is not fully specified, and can change without
391 /// notice. Also note that this method attempts to avoid using the
392 /// default allocator.
393 static
394 bsl::ostream& printFormatted(bsl::ostream& stream,
395 const StackTraceFrame& stackTraceFrame);
396
397 /// Write to the specified `stream` the stack addresses from a stack
398 /// trace of the current thread, in hex from top to bottom, and return
399 /// `stream`. Optionally specify `delimiter`, that is to be written
400 /// between stack addresses. If `delimiter` is not specified, the
401 /// addresses are separated by a single space. Optionally specify
402 /// `maxFrames`, the upper limit of the number of frames to obtain,
403 /// where a negative or unspecified value will be interpreted as a large
404 /// finite default value. Optionally specify `additionalIgnoreFrames`
405 /// to be added to the number of frames from the stack top to be ignored
406 /// and not printed. Optionally specify `allocator` to be used for
407 /// temporary storage; if none is specified, a locally created heap
408 /// bypass allocator will be used. The behavior is undefined unless
409 /// `delimiter != 0` and `additionalIgnoreFrames >= 0`.
410 static
411 bsl::ostream& printHexStackTrace(
412 bsl::ostream& stream,
413 char delimiter = ' ',
414 int maxFrames = -1,
415 int additionalIgnoreFrames = 0,
416 bslma::Allocator *allocator = 0);
417};
418
419} // close package namespace
420
421
422#endif
423
424// ----------------------------------------------------------------------------
425// Copyright 2015 Bloomberg Finance L.P.
426//
427// Licensed under the Apache License, Version 2.0 (the "License");
428// you may not use this file except in compliance with the License.
429// You may obtain a copy of the License at
430//
431// http://www.apache.org/licenses/LICENSE-2.0
432//
433// Unless required by applicable law or agreed to in writing, software
434// distributed under the License is distributed on an "AS IS" BASIS,
435// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
436// See the License for the specific language governing permissions and
437// limitations under the License.
438// ----------------------------- END-OF-FILE ----------------------------------
439
440/** @} */
441/** @} */
442/** @} */
Definition balst_stacktraceframe.h:222
Definition balst_stacktrace.h:206
Definition bslma_allocator.h:457
#define BSLS_IDENT(str)
Definition bsls_ident.h:195
Definition balst_objectfileformat.h:161
Definition balst_stacktraceutil.h:325
static bsl::ostream & printFormatted(bsl::ostream &stream, const StackTraceFrame &stackTraceFrame)
static int loadStackTraceFromAddressArray(StackTrace *result, const void *const addresses[], int numAddresses, bool demanglingPreferredFlag=true)
static bsl::ostream & printHexStackTrace(bsl::ostream &stream, char delimiter=' ', int maxFrames=-1, int additionalIgnoreFrames=0, bslma::Allocator *allocator=0)
static bsl::ostream & printFormatted(bsl::ostream &stream, const StackTrace &stackTrace)
static int loadStackTraceFromStack(StackTrace *result, int maxFrames=-1, bool demanglingPreferredFlag=true)
static bsl::ostream & hexStackTrace(bsl::ostream &stream)