HelloBacktrace – A guide to Crash and Error Reporting with C++, C#, and Mixed call stacks

HelloBacktrace

A brief guide to create simple C++, C# and mixed call stack programs integrated with Backtrace

Overview

This series will walk readers through a step by step process to create and run programs that can report crashes and exceptions to Backtrace.

Step 0: Prerequisites

Before you can get started building these programs, you’ll need the following:

  • An account with Backtrace (in order to submit and view the crashes/exceptions).
  • If you are going to work on the C# and Mixed call stacks, you’ll need a 2.0+ .NET Core framework.

For the C++ macOS program, you’ll also need a local Crashpad build.

Additionally, the examples are laid out for users using Visual Studio and Xcode (for macOS) but other IDE’s will work as well.

If you already have these, skip this section! If not, steps to set them up are below.

  1. Create a Backtrace account and generate an error submission token
    1. Create a Backtrace account here
    2. You’ll get an email with instructions on where to log in
    3. Once you log in, you’ll be prompted to create a project. Then you can open the menu options (click on the gray circle in the top right of the home page) and select Project Settings
    4. Select error submission in the menu on the left side of the screen, and then the plus sign to generate a new token for the project
    5. Save these for later!
  2. .NET Core framework (2.0+)
    Windows and macOS: download here
  3. Local Crashpad build
    Windows: Unnecessary
    macOS: brief instructions included in C++ section
  4. Visual Studio
    Windows: download here
    Use the Backtrace Visual Studio Extension to easily get started with Crashpad
  5. Xcode
    Windows: Unnecessary
    macOS: download here

C++

Windows

  1. Open Visual Studio and create a new project, selecting C++ and Console App in template options

    1. From the Tools menu, open the Extensions, search for Backtrace and install Backtrace extension
    2. Right click on the project to open the project menu and select Add Crashpad support, then step through configuration wizard (more info here)
    3. View CrashpadSetup.cpp

std::wstring db_path(L"C:\\Users\\backtrace\\Desktop\\HelloBacktraceMixedCallstack\\Dll1\\crashpad\\crashpad-2019-04-22-debug-x64-45015f77df098b071473cea54e9a5761004c2b42\\bin\\db");

  1. Note that rate limiting is set here and should be changed for any future production apps
  • Replace contents with the code below:

#include "pch.h"
#include <iostream>
#include "CrashpadSetup.hpp"

void DoTheImpossible()
{
int x = 0;
int y = 100 / x;
}

int main()
{

bool result = backtrace::initializeCrashpad();
int response;
std::cout << "Pick an error:\n [1] Invalid arg\n [2] Divide by zero\n [3] Abort\n";
std::cin >> response;

switch (response)
{
case 1:
std::cout << "You chose invalid argument!" << std::endl;
throw std::invalid_argument("Invalid");
case 2:
std::cout << "You chose divide by zero!" << std::endl;
DoTheImpossible();
case 3:
std::cout << "You chose abort!" << std::endl;
abort();

default:
std::cout << "Invalid choice" << std::endl;
break;
}
}

  1. Build in VS
  1. Run in Powershell

  1. View your error(s) in Backtrace! For more information, see our Crashpad integration guide.

MacOS

Additional Prereq: Crashpad Build

Steps to build crashpad locally on macOS are listed below. If you’re already set up with Crashpad, skip ahead to the next section.

  1. Get and build depot_dools (more info). In terminal, open and run
    1. git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git 
    2. export PATH=$PATH:/path/to/depot_tools
  2. Get and build crashpad
    1. Get
      1. mkdir /crashpad && cd /crashpad
      2. ~/depot_tools/fetch crashpap
    2. Build
      1. gn gen out/Default
      2. ninja -C out/Default
    3. Replace Crashpad’s library with Backtrace’s fork
      1. In a separate directory, git clone https://github.com/backtrace-labs/crashpad.git 
      2. Copy the Backtrace library into ~/crashpad/crashpad and override the existing files
    4. Run gclient sync
    5. Build again (repeat step 2b)  Note: if the Crashpad build has never been used before, you’ll also need to create and configure the Crashpad database. To do so, run the two commands below in the directory containing crashpad_database_util
      1. ./crashpad_database_util -d /<path to local db> –create
      2. ./crashpad_database_util -d /<path to local db> –set-uploads-enabled true

Once Crashpad is all set, follow the steps below.

  1. Open XCode
  2. Create a new project (File >> New Project), select macOS Command Line Tool in the template options and C++ for language
  3. Name the project, select or create a directory for the project to live and save
  4. Replace main.cpp with the following (be sure to fill in the file paths, token and submission URL appropriately)

    #include <iostream>
    #include <base/files/file_path.h>
    #include <client/crash_report_database.h>
    #include <client/settings.h>
    #include <client/crashpad_client.h>

    using namespace crashpad;

    void InvArg()
    {
    throw std::invalid_argument("Invalid");
    }
    void DoTheImpossible()
    {
    int x=0;
    int y=100/x;
    }

    int main()
    {
    std::map<std::string, std::string> annotations;
    std::vector<std::string> arguments;
    CrashpadClient client;

    arguments.push_back("--no-rate-limit");
    client.StartHandler(base::FilePath{"<PathToYour>/crashpad_handler"},
    base::FilePath{"<PathToYour>/crashpad/db"},
    base::FilePath{"<PathToYour>/crashpad/db"},
    "https://submit.backtrace.io/<YourUniverseName>/<YourToken>/minidump",
    annotations,
    arguments,
    true,
    true);

    int response;
    std::cout << "Pick an error:\n [1] Invalid arg\n [2] Divide by zero\n [3] Abort\n";
    std::cin >> response;

    switch(response)
    {
    case 1:
    std::cout << "You chose invalid argument!" << std::endl;
    InvArg();
    case 2:
    DoTheImpossible();
    case 3:
    abort();
    default:
    std::cout << "Invalid choice" << std::endl;
    break;
    }
    }

  5. Link libraries, compile and run
  6. View your error(s) in Backtrace! For more information, see our Crashpad integration guide.

C#

Windows

  1. Open Visual Studio and create a new project, selecting C#, Windows Desktop and Console App (.NET Framework) in the template options
  2. From the Tools menu, under NugGet Package Manager select Manage NuGet Packages for Solution. Under the Browse tab, search for and install Backtrace
  3. Within Program.cs,
    1. Make sure the following are added:
      using System;
      using System.Collections.Generic;
      using Backtrace;
      using Backtrace.Model;
      using Backtrace.Types;
    2. replace your main() with the example code below:
      static void Main(string[] args)
      {
      //Set up Backtrace credentials
      var credentials = new BacktraceCredentials("https://<YourUniverse>.sp.backtrace.io:6098/", "<YourToken");
      var backtraceClient = new BacktraceClient(credentials);
      //Grab unhandled exceptions too
      backtraceClient.HandleApplicationException();

      //Prompt user to select exception, and throw if selected.
      Console.WriteLine("Please enter a selection: \n Aa-Zz: Unhandled format exception \n 1: Parameter cannot be null handled exception \n 2: Out of memory handled exception \n 3: File not found handled exception \n 4: Divide by zero uncaught exception \n Any other number: exit");

      string resp;
      int response;
      resp = Console.ReadLine();
      //int.TryParse(resp, out response);
      response = Convert.ToInt32(resp);

      switch (response)
      {
      case 1:
      try
      {
      Console.WriteLine("Okay, throwing a parameter cannot be null exception now.");
      throw new System.Exception("Parameter cannot be null");
      }
      catch (System.Exception e)
      {
      var report = new BacktraceReport(
      exception: e,
      //Adding an attribute that will show in Backtrace
      //as "Testing" with a value of "True"
      attributes: new Dictionary<string, object>() { { "Testing", "True" } }
      );
      var result = backtraceClient.Send(report);
      if (result.Status == BacktraceResultStatus.Ok)
      {
      Console.WriteLine("Report sent to Backtrace");
      }
      else
      {
      Console.WriteLine($"Something went wrong. Please check exception below \n ${result.GetException()}");
      }
      }
      break;
      case 2:
      try
      {
      Console.WriteLine("Okay, throwing out of memory exception now.");
      throw new InsufficientMemoryException("Insuff mem.");
      }
      catch (InsufficientMemoryException e)
      {
      var report = new BacktraceReport(e);
      var result = backtraceClient.Send(report);
      if (result.Status == BacktraceResultStatus.Ok)
      {
      Console.WriteLine("Report sent to Backtrace");
      }
      else
      {
      Console.WriteLine($"Something went wrong. Please check exception below \n ${result.GetException()}");
      }
      }
      break;
      case 3:
      try
      {
      Console.WriteLine("Throwing a file not found exception now.");
      System.IO.File.ReadAllBytes("Path to not existing file");
      }
      catch (Exception e)
      {
      var report = new BacktraceReport(e);
      var result = backtraceClient.Send(report);
      if (result.Status == BacktraceResultStatus.Ok)
      {
      Console.WriteLine("Report sent to Backtrace");
      }
      else
      {
      Console.WriteLine($"Something went wrong. Please check exception below \n ${result.GetException()}");
      }
      }
      break;
      case 4:
      {
      int x = 0;
      int y = 100 / x;
      }
      break;
      default:
      Console.WriteLine("Okay, bai!");
      break;
      }
      }

  4. Build in VS
  5. Run in Powershell
  6. View your errors in Backtrace! For more information, see our C# integration guide and our library’s ReadMe

MacOS

  1. Create a new Visual Studio solution, selecting a .NET Console Project (C#)
  2. Select Console Application and .Net Core App in the template options
  3. Install Backtrace via NuGet
    1. Project >> Add NuGet Package >> Search for Backtrace >> Check and click “Add Package”
    2. Or in terminal, cd to your project’s directory and run dotnet add package Backtrace
  4. Replace Program.cs with [same example code from Windows above]
    1. Be sure to fill in the token and submission URL appropriately
  5. Build and run in VS
  6. View your errors in Backtrace! For more information, see our C# integration guide and our library’s ReadMe

Mixed Call Stacks

Windows

  1. Open VS and create a new project
      1. For template select Visual C#, Windows Desktop, Console App (.NET Framework)
      2. Right click solution and click add >> project
        1. For template select Visual C++, Windows Desktop, DLL
      3. If you do not already have the Backtrace Visual Studio Crashpad Extension, download and install it
        1. Tools >> Extensions >> Search for Backtrace >> select and install Backtrace extensions
      4. Right click the newly created DLL project and select add crashpad support
        1. Enter submission URL and token and click through install (more details here)
      5. Open CrashpadSetup.cpp and replace database and handler path values
        1. These will be in the bin folder of your crashpad build (be sure to escape backslashes)
        2. Example:
          std::wstring db_path(L"C:\\Users\\backtrace\\Desktop\\HelloBacktraceMixedCallstack\\Dll1\\crashpad\\crashpad-2019-04-22-debug-x64-45015f77df098b071473cea54e9a5761004c2b42\\bin\\db");
      6. Replace Dll1.cpp with example code
        // Dll1.cpp : Defines the exported functions for the DLL application.
        //
        #include "stdafx.h"
        #include <iostream>
        #include "CrashpadSetup.hpp"

        #define DLL __declspec(dllexport)
        // Define the C# Crashcallback in case of C++ crash
        typedef void(__stdcall * CrashCallback)();
        CrashCallback cc;

        // We have to ignore certain crash types
        LONG WINAPI VectoredExceptionHandler(PEXCEPTION_POINTERS pExceptionInfo)
        {
        // Ignoring Access Violation because it’s handled in C#
        if (pExceptionInfo->ExceptionRecord->ExceptionCode == 0xE0434F4D || pExceptionInfo->ExceptionRecord->ExceptionCode == 0xE0434352) {
        return EXCEPTION_CONTINUE_SEARCH;
        }
        else {
        // Call the C# to output a crash
        cc();
        // Here we call the Crashpad client to generate a dump and send it
        backtrace::client.DumpAndCrash(pExceptionInfo);
        return EXCEPTION_EXECUTE_HANDLER;
        }
        return EXCEPTION_CONTINUE_SEARCH;
        }

        // Used to generate a C++ crash
        using ptr_void = void*;
        volatile ptr_void dest;

        static void DumpWithoutCrashWithException(EXCEPTION_POINTERS* pointer);

        // Accepts a pointer to the C# crash callbck
        extern "C" __declspec(dllexport) void InitializeCP(CrashCallback crashCallback) {
        backtrace::initializeCrashpad();
        cc = crashCallback;
        AddVectoredExceptionHandler(0, &::VectoredExceptionHandler);
        }
        extern "C" __declspec(dllexport) void Crash() {
        memset(dest, 0x42, 20000000);
        }
        extern "C" __declspec(dllexport) void IllegalDivide() {
        int x = 0;
        int y = 100 / x;
        int z = y + 10;
        }
        int main() {

        return 0;
        }

      7. Replace Crashpad.hpp with example code:

    #include <client/crash_report_database.h>
    #include <client/settings.h>
    #include "client/crashpad_client.h"

    namespace backtrace
    {
    bool initializeCrashpad();
    static crashpad::CrashpadClient client;
    }

    1. Right click Dll1 project in solution explorer and build
    2. Add Backtrace NuGet package to C# project
      1. Tools >> NuGet Package Manager >> Manage Packages for Solutions >> Search for and Install Backtrace
    3. Open C# project’s Program.cs and replace with example code <CODE>
    4. Build
    5. Copy the C++ project’s DLL into the bin directory where the C# project .exe lives
    6. Open powershell and run the C#’s project .exe
    7. View your errors in Backtrace! The quickest way to see these incoming errors is the Explore Tool -> List view. As seen in the video below, you can add the columns timestamp, application, error message and callstack, amongst other attributes. By doing so, you can see reports from C# and C++ components side by side.

For more information, see our Mixed Callstack Integration Guide and a video demo here

By | 2019-11-03T16:45:01+00:00 May 21st, 2019|Backtrace, How To|