1

I use following code

#include <boost/stacktrace.hpp>
#include <iostream>
#include <stdexcept>

// Define a custom exception type
struct CustomException : std::runtime_error {
    CustomException(const std::string& msg) : std::runtime_error(msg) {}
};

// Function to throw an error with message and stack trace
void throw_err(const std::string& err_msg) {
    // Capture the stack trace
    boost::stacktrace::stacktrace trace;

    // Formulate the error message
    std::string full_msg = "Error: " + err_msg + "\n";

    // Append the stack trace to the error message
    full_msg += "Stack Trace:\n";
    for (const auto& frame : trace) {
        full_msg += "  " + frame.name() + " at " + frame.source_file() + ":" + std::to_string(frame.source_line()) + "\n";
    }

    // Throw the custom exception with the error message
    throw CustomException(full_msg);
}

int main() {
    try {
        throw_err("An error occurred!");
    } catch (const CustomException& e) {
        std::cerr << e.what() << std::endl;
    }

    return 0;
}

it out:

/home/roroco/Dropbox/cpp/cpp_lib/cmake-build-debug/draft/draft/test_out_backtrace
Error: An error occurred!
Stack Trace:
   at :0
   at :0
  __libc_start_main at :0
   at :0

I hope it out real err source file and line num, how to do

I use g++ cli reproduce this err, no any err is raised, so how to fix it

/tmp $ g++-13 -I/home/roroco/Dropbox/cpp/cpp-global-deps/boost_1_85_0/dist/include -o test_out_backtrace /home/roroco/Dropbox/cpp/cpp_lib/draft/draft/test_out_backtrace.cpp -ldl
/tmp $ ./test_out_backtrace 
Error: An error occurred!
Stack Trace:
   at :0
   at :0
  __libc_start_main at :0
   at :0
3
  • Do you remember to build with debug information? Commented May 5, 2024 at 10:20
  • @Someprogrammerdude I use g++ cli reproduce this err, no err when build Commented May 5, 2024 at 10:25
  • When building, do you add the -g flag? That tells the compiler to add debug information. Commented May 5, 2024 at 10:27

1 Answer 1

0

The standard backend on linuxen is backtrace_light:

In header only mode library could be tuned by macro. If one of the link macro from above is defined, you have to manually link with one of the libraries: [...] (docs)

So, to get more support you might want to switch to addr2line if your system has it, or switch to libbacktrace. Here's some live demonstrations of the differences (and also demonstrating the effect of debug information):

It shows, in order:

  1. build of your exact program without libbacktrace or configuration;

    the output is as your question shows

  2. adding libbacktrace to the linked libraries;

    the output shows it is not installed

  3. adding libbacktrace to the shell environment;

    compilation passes but output is still lacking all info

  4. adding -DBOOST_STACKTRACE_USE_BACKTRACE to the compiler flags to configure Boost Stacktrace to use the backend we want;

    output is now showing promise! Just our functions have no file/line information

  5. enabling debug information (by adding -g or -ggdb options);

Now output is complete:

Error: An error occurred!
Stack Trace:
  throw_err(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) at /home/sehe/Projects/stackoverflow/test.cpp:13
  main at /home/sehe/Projects/stackoverflow/test.cpp:26
  __libc_start_call_main at :0
  __libc_start_main at :0
  _start at :0

The used files for reference:

  • File test.cpp

     #include <boost/stacktrace.hpp>
     #include <iostream>
     #include <stdexcept>
    
     struct CustomException : std::runtime_error {
         CustomException(std::string const& msg) : std::runtime_error(msg) {}
     };
    
     void throw_err(std::string const& err_msg) {
         boost::stacktrace::stacktrace trace;
    
         // Formulate the error message
         std::string full_msg = "Error: " + err_msg + "\n";
    
         full_msg += "Stack Trace:\n";
         for (auto const& frame : trace) {
             full_msg += "  " + frame.name() + " at " + frame.source_file() + ":" +
                 std::to_string(frame.source_line()) + "\n";
         }
    
         throw CustomException(full_msg);
     }
    
     int main() {
         try {
             throw_err("An error occurred!");
         } catch (CustomException const& e) {
             std::cerr << e.what() << std::endl;
         }
     }
    
  • File CMakeLists.txt

     cmake_minimum_required(VERSION 3.28)
     project(sotest)
     set(CMAKE_EXPORT_COMPILE_COMMANDS On)
    
     set(CMAKE_CXX_STANDARD 23)
     #set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g ")
     set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ggdb ")
     set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O2 ")
     #set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address,undefined")
     set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -pedantic")
     find_package(Boost CONFIG 1.84.0 COMPONENTS system REQUIRED)
    
     link_libraries(Boost::system)
    
     add_executable(sotest test.cpp)
     target_link_libraries(sotest backtrace)
     target_compile_definitions(sotest PRIVATE BOOST_STACKTRACE_USE_BACKTRACE)
    
  • File flake.nix

     {
       description = "A basic flake with a shell";
       inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
       inputs.flake-utils.url = "github:numtide/flake-utils";
    
       outputs = {
         nixpkgs,
         flake-utils,
         ...
       }:
         flake-utils.lib.eachDefaultSystem (system: let
           pkgs = nixpkgs.legacyPackages.${system};
         in {
           devShells.default = pkgs.stdenvNoCC.mkDerivation {
             name = "stackoverflow shell";
    
             nativeBuildInputs = with pkgs; [
               libbacktrace
               cmake
               gcc13
             ];
    
             env = {
               Boost_DIR = "/home/sehe/custom/boost/stage/lib/cmake";
             };
           };
         });
     }
    
Sign up to request clarification or add additional context in comments.

1 Comment

I forgot to mention that libbacktrace is just a choice for the demonstration. I have had success with addr2line, although the default backend should be able to save dumps with raw addresses that can be converted to source/line information later using these tools as well (addr2line is usually shipped with compilers and in packages like binutils).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.