Quick Links:

bal | bbl | bdl | bsl

Namespaces

Component balst_stacktrace
[Package balst]

Provide a description of a function-call stack. More...

Namespaces

namespace  balst

Detailed Description

Outline
Purpose:
Provide a description of a function-call stack.
Classes:
balst::StackTrace a description of a function-call stack
See also:
Component balst_stacktraceframe, Component balst_stacktraceutil, Component balst_stacktraceprintutil, Component bdlma_heapbypassallocator
Description:
This component provides a (value-semantic) container class, balst::StackTrace, that is used to describe a function-call stack. A stack-trace object contains a sequence of balst::StackTraceFrame objects. By default, a balst::StackTrace object is supplied memory by an owned bdlma::HeapBypassAllocator object, though the client may specify another allocator at construction to be used in its place.
Usage:
In this section we show the intended usage of this component.
Example 1: Configuring a Stack-Trace Value:
In this example we demonstrate how to create a balst::StackTrace object, and then to both modify and access its value.
First, we set up a test allocator as default allocator. A balst::StackTrace object, by default, gets all its memory from an owned bdlma::HeapBypassAllocator object. To demonstrate this default behavior we start by setting the default allocator to a test allocator so we can verify later that it was unused: Then, we create a stack-trace object. Note that when we don't specify an allocator, the default allocator is not used -- rather, a heap-bypass allocator owned by the stack-trace object is used. The heap-bypass allocator is recommended because this component is often used to obtain debug information in situations where an error has occurred, and the possibility of heap corruption can't be ruled out. The heap-bypass allocator obtains its memory directly from virtual memory rather than going through the heap, avoiding potential complications due to heap corruption.
  balst::StackTrace stackTrace;
  assert(0 == stackTrace.length());
Next, we resize the stack-trace object to contain two default-constructed frames, and take references to each of the two new frames:
  stackTrace.resize(2);
  assert(2 == stackTrace.length());
  balst::StackTraceFrame& frame0 = stackTrace[0];
  balst::StackTraceFrame& frame1 = stackTrace[1];
Then, we set the values of the fields of the two new frames.
  frame0.setAddress((void *) 0x12ab);
  frame0.setLibraryFileName("/a/b/c/balst_stacktrace.t.dbg_exc_mt");
  frame0.setLineNumber(5);
  frame0.setOffsetFromSymbol(116);
  frame0.setSourceFileName("/a/b/c/sourceFile.cpp");
  frame0.setMangledSymbolName("_woof_1a");
  frame0.setSymbolName("woof");

  frame1.setAddress((void *) 0x34cd);
  frame1.setLibraryFileName("/lib/libd.a");
  frame1.setLineNumber(15);
  frame1.setOffsetFromSymbol(228);
  frame1.setSourceFileName("/a/b/c/secondSourceFile.cpp");
  frame1.setMangledSymbolName("_arf_1a");
  frame1.setSymbolName("arf");
Next, we verify the frames have the values we expect:
  assert((void *) 0x12ab               == frame0.address());
  assert("/a/b/c/balst_stacktrace.t.dbg_exc_mt"
                                       == frame0.libraryFileName());
  assert(  5                           == frame0.lineNumber());
  assert(116                           == frame0.offsetFromSymbol());
  assert("/a/b/c/sourceFile.cpp"       == frame0.sourceFileName());
  assert("_woof_1a"                    == frame0.mangledSymbolName());
  assert("woof"                        == frame0.symbolName());

  assert((void *) 0x34cd               == frame1.address());
  assert("/lib/libd.a"                 == frame1.libraryFileName());
  assert( 15                           == frame1.lineNumber());
  assert(228                           == frame1.offsetFromSymbol());
  assert("/a/b/c/secondSourceFile.cpp" == frame1.sourceFileName());
  assert("_arf_1a"                     == frame1.mangledSymbolName());
  assert("arf"                         == frame1.symbolName());
Next, we output the stack-trace object:
  stackTrace.print(cout, 1, 2);
Finally, we observe the default allocator was never used.
  assert(0 == da.numAllocations());
The above usage produces the following output:
  [
    [
      address = 0x12ab
      library file name = "/a/b/c/balst_stacktrace.t.dbg_exc_mt"
      line number = 5
      mangled symbol name = "_woof_1a"
      offset from symbol = 116
      source file name = "/a/b/c/sourceFile.cpp"
      symbol name = "woof"
    ]
    [
      address = 0x34cd
      library file name = "/lib/libd.a"
      line number = 15
      mangled symbol name = "_arf_1a"
      offset from symbol = 228
      source file name = "/a/b/c/secondSourceFile.cpp"
      symbol name = "arf"
    ]
  ]