BDE 4.14.0 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#ifndef BDE_DONT_ALLOW_TRANSITIVE_INCLUDES
189#include <bsl_algorithm.h>
190#endif // BDE_DONT_ALLOW_TRANSITIVE_INCLUDES
191
192
193namespace balst {
194
195 // ================
196 // class StackTrace
197 // ================
198
199/// This value-semantic class describes a function-call stack, represented
200/// as a sequence of randomly accessible `StackTraceFrame` objects, each of
201/// which represents one function call on the stack. Note that if no
202/// allocator is supplied at construction, an owned
203/// `bdlma::HeapBypassAllocator` object is used to supply memory.
204///
205/// See @ref balst_stacktrace
207
208 // DATA
209 bdlma::HeapBypassAllocator d_hbpAlloc; // Used if no allocator is
210 // supplied at construction.
211 // Note this member must be
212 // declared and constructed prior
213 // to 'd_frames'.
214
215 bsl::vector<StackTraceFrame> d_frames; // sequence of stack-trace frames
216
217 // FRIENDS
218 friend bool operator==(const StackTrace&, const StackTrace&);
219
220 public:
221 // TRAITS
224
225 // CREATORS
226
227 /// Create an empty `StackTrace` object (having a length of 0).
228 /// Optionally specify `basicAllocator` used to supply memory. If
229 /// `basicAllocator` is 0, then an owned heap-bypass allocator object is
230 /// used. Note that the heap-bypass allocator is used by default to
231 /// avoid heap allocation in situations where the heap may have been
232 /// corrupted.
233 explicit
234 StackTrace(bslma::Allocator *basicAllocator = 0);
235
236 /// Create a `StackTrace` object having the same value as the
237 /// specified `original` object. Optionally specify a `basicAllocator`
238 /// used to supply memory. If `basicAllocator` is 0, then an owned
239 /// heap-bypass allocator object is used. Note that the heap-bypass
240 /// allocator is used by default to avoid heap allocation in situations
241 /// where the heap may have been corrupted.
242 StackTrace(const StackTrace& original,
243 bslma::Allocator *basicAllocator = 0);
244
245 ~StackTrace() = default;
246 // Destroy this object.
247
248 // MANIPULATORS
249
250 /// Assign to this object the value of the specified `rhs` object, and
251 /// return a reference providing modifiable access to this object.
252 StackTrace& operator=(const StackTrace& rhs);
253
254 /// Return a reference providing modifiable access to the stack-trace
255 /// frame at the specified `index`. 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
270 /// be unchanged. The behavior is undefined unless `0 <= newLength`.
271 void resize(int newLength);
272
273 // Aspects
274
275 /// Efficiently exchange the value of this object with the value of the
276 /// specified `other` object. This method provides the no-throw
277 /// exception-safety guarantee. The behavior is undefined unless this
278 /// object was created with the same allocator as `other`.
279 void swap(StackTrace& other);
280
281 // ACCESSORS
282
283 /// Return a reference providing non-modifiable access to the
284 /// stack-trace frame at the specified `index`. The behavior is
285 /// undefined unless `0 <= index < length()`.
286 const StackTraceFrame& operator[](int index) const;
287
288 /// Return the number of stack-trace frames contained in this object.
289 int length() const;
290
291 // Aspects
292
293 /// Return the allocator used by this object to supply memory. Note
294 /// that if no allocator was supplied at construction the owned
295 /// heap-bypass allocator is used.
297
298 /// Write the value of this object to the specified output `stream` in a
299 /// human-readable format, and return a reference to `stream`.
300 /// Optionally specify an initial indentation `level`, whose absolute
301 /// value is incremented recursively for nested objects. If `level` is
302 /// specified, optionally specify `spacesPerLevel`, whose absolute value
303 /// indicates the number of spaces per indentation level for this and
304 /// all of its nested objects. If `level` is negative, suppress
305 /// indentation of the first line. If `spacesPerLevel` is negative,
306 /// format the entire output on one line, suppressing all but the
307 /// initial indentation (as governed by `level`). If `stream` is not
308 /// valid on entry, this operation has no effect. Note that the format
309 /// is not fully specified, and can change without notice.
310 bsl::ostream& print(bsl::ostream& stream,
311 int level = 0,
312 int spacesPerLevel = 4) const;
313};
314
315// FREE OPERATORS
316
317/// Return `true` if the specified `lhs` and `rhs` objects have the same
318/// value, and `false` otherwise. Two `StackTrace` objects have the
319/// same value if they have the save length, and each of their corresponding
320/// stack-trace frames have the same value.
321bool operator==(const StackTrace& lhs, const StackTrace& rhs);
322
323/// Return `true` if the specified `lhs` and `rhs` objects do not have the
324/// same value, and `false` otherwise. Two `StackTrace` objects do
325/// not have the same value if they do not have the same length, or any of
326/// their corresponding stack-trace frames do not have the same value.
327bool operator!=(const StackTrace& lhs, const StackTrace& rhs);
328
329/// Write the value of the specified `object` to the specified output
330/// `stream` in a single-line format, and return a reference to `stream`.
331/// If `stream` is not valid on entry, this operation has no effect. Note
332/// that this human-readable format is not fully specified and can change
333/// without notice. Also note that this method has the same behavior as
334/// `object.print(stream, 0, -1)`, but with the attribute names elided.
335bsl::ostream& operator<<(bsl::ostream& stream, const StackTrace& object);
336
337// FREE FUNCTIONS
338
339/// Exchange the values of the specified `a` and `b` objects. This function
340/// provides the no-throw exception-safety guarantee if the two objects were
341/// created with the same allocator and the basic guarantee otherwise.
342void swap(StackTrace& a, StackTrace& b);
343
344// ============================================================================
345// INLINE FUNCTION DEFINITIONS
346// ============================================================================
347
348 // ----------------
349 // class StackTrace
350 // ----------------
351
352// ACCESSORS
353inline
355{
356 return d_frames.get_allocator().mechanism();
357}
358
359// CREATORS
360inline
362: d_hbpAlloc()
363, d_frames(basicAllocator ? basicAllocator : &d_hbpAlloc)
364{
365}
366
367inline
369 bslma::Allocator *basicAllocator)
370: d_hbpAlloc()
371, d_frames(original.d_frames,
372 basicAllocator ? basicAllocator : &d_hbpAlloc)
373{
374}
375
376// MANIPULATORS
377inline
379{
380 d_frames = rhs.d_frames;
381
382 return *this;
383}
384
385inline
387{
388 BSLS_ASSERT(index >= 0);
389 BSLS_ASSERT(index < length());
390
391 return d_frames[index];
392}
393
394inline
396{
397 d_frames.push_back(value);
398}
399
400inline
402{
403 d_frames.clear();
404}
405
406inline
407void StackTrace::resize(int newLength)
408{
409 BSLS_ASSERT(newLength >= 0);
410
411 d_frames.resize(newLength);
412}
413
414inline
416{
417 // 'swap' is undefined for objects with non-equal allocators.
418
419 BSLS_ASSERT(allocator() == other.allocator());
420
421 d_frames.swap(other.d_frames);
422}
423
424// ACCESSORS
425inline
427{
428 BSLS_ASSERT(index >= 0);
429 BSLS_ASSERT(index < length());
430
431 return d_frames[index];
432}
433
434inline
436{
437 return (int) d_frames.size();
438}
439
440} // close package namespace
441
442// FREE OPERATORS
443inline
444bool balst::operator==(const StackTrace& lhs, const StackTrace& rhs)
445{
446 return lhs.d_frames == rhs.d_frames;
447}
448
449inline
450bool balst::operator!=(const StackTrace& lhs, const StackTrace& rhs)
451{
452 return !(lhs == rhs);
453}
454
455inline
456bsl::ostream& balst::operator<<(bsl::ostream& stream, const StackTrace& object)
457{
458 object.print(stream, 0, -1);
459
460 return stream;
461}
462
463
464
465#endif
466
467// ----------------------------------------------------------------------------
468// Copyright 2018 Bloomberg Finance L.P.
469//
470// Licensed under the Apache License, Version 2.0 (the "License");
471// you may not use this file except in compliance with the License.
472// You may obtain a copy of the License at
473//
474// http://www.apache.org/licenses/LICENSE-2.0
475//
476// Unless required by applicable law or agreed to in writing, software
477// distributed under the License is distributed on an "AS IS" BASIS,
478// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
479// See the License for the specific language governing permissions and
480// limitations under the License.
481// ----------------------------- END-OF-FILE ----------------------------------
482
483/** @} */
484/** @} */
485/** @} */
Definition balst_stacktraceframe.h:222
Definition balst_stacktrace.h:206
~StackTrace()=default
friend bool operator==(const StackTrace &, const StackTrace &)
BSLMF_NESTED_TRAIT_DECLARATION(StackTrace, bslmf::IsBitwiseMoveable)
bslma::Allocator * allocator() const
Definition balst_stacktrace.h:354
void removeAll()
Definition balst_stacktrace.h:401
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:435
BSLMF_NESTED_TRAIT_DECLARATION(StackTrace, bslma::UsesBslmaAllocator)
void resize(int newLength)
Definition balst_stacktrace.h:407
StackTrace & operator=(const StackTrace &rhs)
Definition balst_stacktrace.h:378
StackTrace(bslma::Allocator *basicAllocator=0)
Definition balst_stacktrace.h:361
void append(const StackTraceFrame &value)
Append to this sequence the specified value.
Definition balst_stacktrace.h:395
StackTraceFrame & operator[](int index)
Definition balst_stacktrace.h:386
void swap(StackTrace &other)
Definition balst_stacktrace.h:415
Definition bdlma_heapbypassallocator.h:157
Definition bslstl_vector.h:1025
Definition bslma_allocator.h:457
#define BSLS_ASSERT(X)
Definition bsls_assert.h:1804
#define BSLS_IDENT(str)
Definition bsls_ident.h:195
Definition balst_objectfileformat.h:161
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)
Definition bslma_usesbslmaallocator.h:343
Definition bslmf_isbitwisemoveable.h:718