BDE 4.39.x Production Release
Loading...
Searching...
No Matches
balst_stacktrace.h
Go to the documentation of this file.
1/// @file balst_stacktrace.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// balst_stacktrace.h -*-C++-*-
8#ifndef INCLUDED_BALST_STACKTRACE
9#define INCLUDED_BALST_STACKTRACE
10
11#include <bsls_ident.h>
12BSLS_IDENT("$Id: $")
13
14/// @defgroup balst_stacktrace balst_stacktrace
15/// @brief Provide a description of a function-call stack.
16/// @addtogroup bal
17/// @{
18/// @addtogroup balst
19/// @{
20/// @addtogroup balst_stacktrace
21/// @{
22///
23/// <h1> Outline </h1>
24/// * <a href="#balst_stacktrace-purpose"> Purpose</a>
25/// * <a href="#balst_stacktrace-classes"> Classes </a>
26/// * <a href="#balst_stacktrace-description"> Description </a>
27/// * <a href="#balst_stacktrace-usage"> Usage </a>
28/// * <a href="#balst_stacktrace-example-1-configuring-a-stack-trace-value"> Example 1: Configuring a Stack-Trace Value </a>
29///
30/// # Purpose {#balst_stacktrace-purpose}
31/// Provide a description of a function-call stack.
32///
33/// # Classes {#balst_stacktrace-classes}
34///
35/// - balst::StackTrace: a description of a function-call stack
36///
37/// @see balst_stacktraceframe, balst_stacktraceutil,
38/// balst_stacktraceprintutil, bdlma_heapbypassallocator
39///
40/// # Description {#balst_stacktrace-description}
41/// This component provides a (value-semantic) container class,
42/// `balst::StackTrace`, that is used to describe a function-call stack. A
43/// stack-trace object contains a sequence of `balst::StackTraceFrame` objects.
44/// By default, a `balst::StackTrace` object is supplied memory by an owned
45/// `bdlma::HeapBypassAllocator` object, though the client may specify another
46/// allocator at construction to be used in its place.
47///
48/// ## Usage {#balst_stacktrace-usage}
49///
50///
51/// This section illustrates intended use of this component.
52///
53/// ### Example 1: Configuring a Stack-Trace Value {#balst_stacktrace-example-1-configuring-a-stack-trace-value}
54///
55///
56/// In this example we demonstrate how to create a `balst::StackTrace` object,
57/// and then to both modify and access its value.
58///
59/// First, we set up a test allocator as default allocator. A
60/// `balst::StackTrace` object, by default, gets all its memory from an owned
61/// `bdlma::HeapBypassAllocator` object. To demonstrate this default behavior
62/// we start by setting the default allocator to a test allocator so we can
63/// verify later that it was unused:
64/// @code
65/// bslma::TestAllocator da;
66/// bslma::DefaultAllocatorGuard guard(&da);
67/// @endcode
68/// Then, we create a stack-trace object. Note that when we don't specify an
69/// allocator, the default allocator is not used -- rather, a heap-bypass
70/// allocator owned by the stack-trace object is used. The heap-bypass
71/// allocator is recommended because this component is often used to obtain
72/// debug information in situations where an error has occurred, and the
73/// possibility of heap corruption can't be ruled out. The heap-bypass
74/// allocator obtains its memory directly from virtual memory rather than going
75/// through the heap, avoiding potential complications due to heap corruption.
76/// @code
77/// balst::StackTrace stackTrace;
78/// assert(0 == stackTrace.length());
79/// @endcode
80/// Next, we `resize` the stack-trace object to contain two default-constructed
81/// frames, and take references to each of the two new frames:
82/// @code
83/// stackTrace.resize(2);
84/// assert(2 == stackTrace.length());
85/// balst::StackTraceFrame& frame0 = stackTrace[0];
86/// balst::StackTraceFrame& frame1 = stackTrace[1];
87/// @endcode
88/// Then, we set the values of the fields of the two new frames.
89/// @code
90/// frame0.setAddress((void *) 0x12ab);
91/// frame0.setLibraryFileName("/a/b/c/balst_stacktrace.t.dbg_exc_mt");
92/// frame0.setLineNumber(5);
93/// frame0.setOffsetFromSymbol(116);
94/// frame0.setSourceFileName("/a/b/c/sourceFile.cpp");
95/// frame0.setMangledSymbolName("_woof_1a");
96/// frame0.setSymbolName("woof");
97///
98/// frame1.setAddress((void *) 0x34cd);
99/// frame1.setLibraryFileName("/lib/libd.a");
100/// frame1.setLineNumber(15);
101/// frame1.setOffsetFromSymbol(228);
102/// frame1.setSourceFileName("/a/b/c/secondSourceFile.cpp");
103/// frame1.setMangledSymbolName("_arf_1a");
104/// frame1.setSymbolName("arf");
105/// @endcode
106/// Next, we verify the frames have the values we expect:
107/// @code
108/// assert((void *) 0x12ab == frame0.address());
109/// assert("/a/b/c/balst_stacktrace.t.dbg_exc_mt"
110/// == frame0.libraryFileName());
111/// assert( 5 == frame0.lineNumber());
112/// assert(116 == frame0.offsetFromSymbol());
113/// assert("/a/b/c/sourceFile.cpp" == frame0.sourceFileName());
114/// assert("_woof_1a" == frame0.mangledSymbolName());
115/// assert("woof" == frame0.symbolName());
116///
117/// assert((void *) 0x34cd == frame1.address());
118/// assert("/lib/libd.a" == frame1.libraryFileName());
119/// assert( 15 == frame1.lineNumber());
120/// assert(228 == frame1.offsetFromSymbol());
121/// assert("/a/b/c/secondSourceFile.cpp" == frame1.sourceFileName());
122/// assert("_arf_1a" == frame1.mangledSymbolName());
123/// assert("arf" == frame1.symbolName());
124/// @endcode
125/// Next, we output the stack-trace object:
126/// @code
127/// stackTrace.print(cout, 1, 2);
128/// @endcode
129/// Finally, we observe the default allocator was never used.
130/// @code
131/// assert(0 == da.numAllocations());
132/// @endcode
133/// The above usage produces the following output:
134/// @code
135/// [
136/// [
137/// address = 0x12ab
138/// library file name = "/a/b/c/balst_stacktrace.t.dbg_exc_mt"
139/// line number = 5
140/// mangled symbol name = "_woof_1a"
141/// offset from symbol = 116
142/// source file name = "/a/b/c/sourceFile.cpp"
143/// symbol name = "woof"
144/// ]
145/// [
146/// address = 0x34cd
147/// library file name = "/lib/libd.a"
148/// line number = 15
149/// mangled symbol name = "_arf_1a"
150/// offset from symbol = 228
151/// source file name = "/a/b/c/secondSourceFile.cpp"
152/// symbol name = "arf"
153/// ]
154/// ]
155/// @endcode
156/// @}
157/** @} */
158/** @} */
159
160/** @addtogroup bal
161 * @{
162 */
163/** @addtogroup balst
164 * @{
165 */
166/** @addtogroup balst_stacktrace
167 * @{
168 */
169
170#include <balscm_version.h>
171
173
175
176#include <bslma_allocator.h>
178
181
182#include <bsls_assert.h>
183#include <bsls_review.h>
184
185#include <bsl_iosfwd.h>
186#include <bsl_vector.h>
187
188
189namespace balst {
190
191 // ================
192 // class StackTrace
193 // ================
194
195/// This value-semantic class describes a function-call stack, represented
196/// as a sequence of randomly accessible `StackTraceFrame` objects, each of which represents one function call on the stack.
197///
198/// \note Note that if no
199/// allocator is supplied at construction, an owned
200/// `bdlma::HeapBypassAllocator` object is used to supply memory.
201///
202/// See @ref balst_stacktrace
204
205 // DATA
206 bdlma::HeapBypassAllocator d_hbpAlloc; // Used if no allocator is
207 // supplied at construction.
208 // Note this member must be
209 // declared and constructed prior
210 // to 'd_frames'.
211
212 bsl::vector<StackTraceFrame> d_frames; // sequence of stack-trace frames
213
214 // FRIENDS
215 friend bool operator==(const StackTrace&, const StackTrace&);
216
217 public:
218 // TRAITS
221
222 // CREATORS
223
224 /// Create an empty `StackTrace` object (having a length of 0).
225 /// Optionally specify `basicAllocator` used to supply memory. If
226 /// `basicAllocator` is 0, then an owned heap-bypass allocator object is used.
227 ///
228 /// \note Note that the heap-bypass allocator is used by default to
229 /// avoid heap allocation in situations where the heap may have been
230 /// corrupted.
231 explicit
232 StackTrace(bslma::Allocator *basicAllocator = 0);
233
234 /// Create a `StackTrace` object having the same value as the
235 /// specified `original` object. Optionally specify a `basicAllocator`
236 /// used to supply memory. If `basicAllocator` is 0, then an owned heap-bypass allocator object is used.
237 ///
238 /// \note Note that the heap-bypass
239 /// allocator is used by default to avoid heap allocation in situations
240 /// where the heap may have been corrupted.
241 StackTrace(const StackTrace& original,
242 bslma::Allocator *basicAllocator = 0);
243
244 ~StackTrace() = default;
245 // Destroy this object.
246
247 // MANIPULATORS
248
249 /// Assign to this object the value of the specified `rhs` object, and
250 /// return a reference providing modifiable access to this object.
251 StackTrace& operator=(const StackTrace& rhs);
252
253 /// Return a reference providing modifiable access to the stack-trace frame at the specified `index`.
254 ///
255 /// \pre The behavior is undefined unless
256 /// `0 <= index < length()`.
257 StackTraceFrame& operator[](int index);
258
259 /// Append to this sequence the specified `value`.
260 void append(const StackTraceFrame& value);
261
262 /// Remove all stack-trace frames from this object. After this
263 /// operation, the `length()` method will return 0.
264 void removeAll();
265
266 /// Add default constructed stack-trace frames to, or remove stack-trace
267 /// frames from, the end of this stack-trace object such that, after the
268 /// operation, `length() == newLength`. Stack trace frames whose
269 /// indices are in the range `0 <= index < min(length, newLength)` will be unchanged.
270 ///
271 /// \pre The behavior is undefined unless `0 <= newLength`.
272 void resize(int newLength);
273
274 // Aspects
275
276 /// Efficiently exchange the value of this object with the value of the
277 /// specified `other` object. This method provides the no-throw exception-safety guarantee.
278 ///
279 /// \pre The behavior is undefined unless this
280 /// object was created with the same allocator as `other`.
281 void swap(StackTrace& other);
282
283 // ACCESSORS
284
285 /// Return a reference providing non-modifiable access to the
286 /// stack-trace frame at the specified `index`.
287 ///
288 /// \pre The behavior is undefined unless `0 <= index < length()`.
289 const StackTraceFrame& operator[](int index) const;
290
291 /// Return the number of stack-trace frames contained in this object.
292 int length() const;
293
294 // Aspects
295
296 /// Return the allocator used by this object to supply memory.
297 ///
298 /// \note Note that if no allocator was supplied at construction the owned
299 /// heap-bypass allocator is used.
301
302 /// Write the value of this object to the specified output `stream` in a
303 /// human-readable format, and return a reference to `stream`.
304 /// Optionally specify an initial indentation `level`, whose absolute
305 /// value is incremented recursively for nested objects. If `level` is
306 /// specified, optionally specify `spacesPerLevel`, whose absolute value
307 /// indicates the number of spaces per indentation level for this and
308 /// all of its nested objects. If `level` is negative, suppress
309 /// indentation of the first line. If `spacesPerLevel` is negative,
310 /// format the entire output on one line, suppressing all but the
311 /// initial indentation (as governed by `level`). If `stream` is not valid on entry, this operation has no effect.
312 ///
313 /// \note Note that the format
314 /// is not fully specified, and can change without notice.
315 bsl::ostream& print(bsl::ostream& stream,
316 int level = 0,
317 int spacesPerLevel = 4) const;
318};
319
320// FREE OPERATORS
321
322/// Return `true` if the specified `lhs` and `rhs` objects have the same
323/// value, and `false` otherwise. Two `StackTrace` objects have the
324/// same value if they have the save length, and each of their corresponding
325/// stack-trace frames have the same value.
326bool operator==(const StackTrace& lhs, const StackTrace& rhs);
327
328/// Return `true` if the specified `lhs` and `rhs` objects do not have the
329/// same value, and `false` otherwise. Two `StackTrace` objects do
330/// not have the same value if they do not have the same length, or any of
331/// their corresponding stack-trace frames do not have the same value.
332bool operator!=(const StackTrace& lhs, const StackTrace& rhs);
333
334/// Write the value of the specified `object` to the specified output
335/// `stream` in a single-line format, and return a reference to `stream`.
336/// If `stream` is not valid on entry, this operation has no effect.
337///
338/// \note Note that this human-readable format is not fully specified and can change
339/// without notice. Also note that this method has the same behavior as
340/// `object.print(stream, 0, -1)`, but with the attribute names elided.
341bsl::ostream& operator<<(bsl::ostream& stream, const StackTrace& object);
342
343// FREE FUNCTIONS
344
345/// Exchange the values of the specified `a` and `b` objects. This function
346/// provides the no-throw exception-safety guarantee if the two objects were
347/// created with the same allocator and the basic guarantee otherwise.
348void swap(StackTrace& a, StackTrace& b);
349
350// ============================================================================
351// INLINE FUNCTION DEFINITIONS
352// ============================================================================
353
354 // ----------------
355 // class StackTrace
356 // ----------------
357
358// ACCESSORS
359inline
361{
362 return d_frames.get_allocator().mechanism();
363}
364
365// CREATORS
366inline
368: d_hbpAlloc()
369, d_frames(basicAllocator ? basicAllocator : &d_hbpAlloc)
370{
371}
372
373inline
375 bslma::Allocator *basicAllocator)
376: d_hbpAlloc()
377, d_frames(original.d_frames,
378 basicAllocator ? basicAllocator : &d_hbpAlloc)
379{
380}
381
382// MANIPULATORS
383inline
385{
386 d_frames = rhs.d_frames;
387
388 return *this;
389}
390
391inline
393{
394 BSLS_ASSERT(index >= 0);
395 BSLS_ASSERT(index < length());
396
397 return d_frames[index];
398}
399
400inline
402{
403 d_frames.push_back(value);
404}
405
406inline
408{
409 d_frames.clear();
410}
411
412inline
413void StackTrace::resize(int newLength)
414{
415 BSLS_ASSERT(newLength >= 0);
416
417 d_frames.resize(newLength);
418}
419
420inline
422{
423 // 'swap' is undefined for objects with non-equal allocators.
424
425 BSLS_ASSERT(allocator() == other.allocator());
426
427 d_frames.swap(other.d_frames);
428}
429
430// ACCESSORS
431inline
433{
434 BSLS_ASSERT(index >= 0);
435 BSLS_ASSERT(index < length());
436
437 return d_frames[index];
438}
439
440inline
442{
443 return (int) d_frames.size();
444}
445
446} // close package namespace
447
448// FREE OPERATORS
449inline
450bool balst::operator==(const StackTrace& lhs, const StackTrace& rhs)
451{
452 return lhs.d_frames == rhs.d_frames;
453}
454
455inline
456bool balst::operator!=(const StackTrace& lhs, const StackTrace& rhs)
457{
458 return !(lhs == rhs);
459}
460
461inline
462bsl::ostream& balst::operator<<(bsl::ostream& stream, const StackTrace& object)
463{
464 object.print(stream, 0, -1);
465
466 return stream;
467}
468
469
470
471#endif
472
473// ----------------------------------------------------------------------------
474// Copyright 2018 Bloomberg Finance L.P.
475//
476// Licensed under the Apache License, Version 2.0 (the "License");
477// you may not use this file except in compliance with the License.
478// You may obtain a copy of the License at
479//
480// http://www.apache.org/licenses/LICENSE-2.0
481//
482// Unless required by applicable law or agreed to in writing, software
483// distributed under the License is distributed on an "AS IS" BASIS,
484// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
485// See the License for the specific language governing permissions and
486// limitations under the License.
487// ----------------------------- END-OF-FILE ----------------------------------
488
489/** @} */
490/** @} */
491/** @} */
Definition balst_stacktraceframe.h:217
Definition balst_stacktrace.h:203
~StackTrace()=default
friend bool operator==(const StackTrace &, const StackTrace &)
BSLMF_NESTED_TRAIT_DECLARATION(StackTrace, bslmf::IsBitwiseMoveable)
bslma::Allocator * allocator() const
Definition balst_stacktrace.h:360
void removeAll()
Definition balst_stacktrace.h:407
bsl::ostream & print(bsl::ostream &stream, int level=0, int spacesPerLevel=4) const
int length() const
Return the number of stack-trace frames contained in this object.
Definition balst_stacktrace.h:441
BSLMF_NESTED_TRAIT_DECLARATION(StackTrace, bslma::UsesBslmaAllocator)
void resize(int newLength)
Definition balst_stacktrace.h:413
StackTrace & operator=(const StackTrace &rhs)
Definition balst_stacktrace.h:384
StackTrace(bslma::Allocator *basicAllocator=0)
Definition balst_stacktrace.h:367
void append(const StackTraceFrame &value)
Append to this sequence the specified value.
Definition balst_stacktrace.h:401
StackTraceFrame & operator[](int index)
Definition balst_stacktrace.h:392
void swap(StackTrace &other)
Definition balst_stacktrace.h:421
Definition bdlma_heapbypassallocator.h:158
Definition bslstl_vector.h:1120
Definition bslma_allocator.h:545
#define BSLS_ASSERT(X)
Definition bsls_assert.h:1976
#define BSLS_IDENT(str)
BSLS_IDENT() - insert string into .comment binary segment (if supported)
Definition bsls_ident.h:238
Definition balst_objectfileformat.h:152
bsl::ostream & operator<<(bsl::ostream &stream, const StackTrace &object)
bool operator==(const StackTrace &lhs, const StackTrace &rhs)
bool operator!=(const StackTrace &lhs, const StackTrace &rhs)
ALLOCATOR const STRING_VIEW_LIKE_TYPE & rhs
Definition bslstl_string.h:3918
ALLOCATOR & lhs
Definition bslstl_string.h:3917
Definition bslma_usesbslmaallocator.h:344
Definition bslmf_isbitwisemoveable.h:718