Using breakpad in Linux programs

This article outlines how to use Breakpad in an executable program or dynamic link library on the Linux platform.

Building the Breakpad library

Breakpad provides an Autotools build system that will build Breakpad's Linux client libraries and handlers. Download the source code of Breakpad from breakpad via git. Then run it in the source directory of Breakpad ./configure && make. This will generate the client static library file src/client/linux/libbreakpad_client.a , which contains all the code needed to generate minidumps for the application or dynamic link library. In addition to the client library, the build process also generates the necessary tools.

Google's original Breakpad source code repository does not contain the Linux syscall support library, which will report the following error when building Breakpad:

~/data/opensource/breakpad$ make
depbase=`echo src/tools/linux/core2md/core2md.o | sed 's|[^/]*$|.deps/&|;s|\.o$||'`;\
g++ -DHAVE_CONFIG_H -I. -I./src  -I./src   -Wmissing-braces -Wnon-virtual-dtor -Woverloaded-virtual -Wreorder -Wsign-compare -Wunused-local-typedefs -Wunused-variable -Wvla -Werror -fPIC -g -O2 -MT src/tools/linux/core2md/core2md.o -MD -MP -MF $depbase.Tpo -c -o src/tools/linux/core2md/core2md.o src/tools/linux/core2md/core2md.cc &&\
mv -f $depbase.Tpo $depbase.Po
In file included from ./src/client/linux/dump_writer_common/thread_info.h:37,
                 from ./src/client/linux/minidump_writer/linux_dumper.h:54,
                 from ./src/client/linux/minidump_writer/minidump_writer.h:42,
                 from src/tools/linux/core2md/core2md.cc:34:
./src/common/memory_allocator.h:50:10: fatal error: third_party/lss/linux_syscall_support.h: 没有那个文件或目录
   50 | #include "third_party/lss/linux_syscall_support.h"
      |          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
compilation terminated.
make: *** [Makefile:5701:src/tools/linux/core2md/core2md.o] 错误 1

Debugging diagnostic code like Breakpad is sometimes inconvenient to access the encapsulated C library, but it still needs to access system functions, such as opening files, reading and writing files, etc. In this case, it will directly access system functions through system calls. The Linux syscall support library provides support for accessing system functions directly through system calls. The source code warehouse address of the Linux syscall support library is https://chromium.googlesource.com/linux-syscall-support.git. The author's Breakpad fork warehouse breakpad on GitHub already contains the Linux syscall support library, and it can be compiled directly without doing anything else.

Integrate Breakpad into your application

First, configure your build process to add the directory address of libbreakpad_client.a to the search path of the link library file, add the breakpad_client library for the link, link libbreakpad_client.a into your binary file, and then set the include path to include the google-breakpad source code The **src** directory in the tree. The breakpad_client library depends on the pthread library, so it also needs to add dependency on the pthread library. Next, include the header file for the exception handler:

#include "client/linux/handler/exception_handler.h"

Now you can instantiate an ExceptionHandler object. ExceptionHandler Exception handling is active throughout the object's lifetime, so you should instantiate it as early as possible in your program's startup process and keep it active as close to its shutdown state as possible. To do anything useful, ExceptionHandlerthe constructor needs a path to which the minidump can be written, and a callback function to receive information about the minidump that has been written:

#include <stdlib.h>

#include <unistd.h>

#include "src/client/linux/handler/exception_handler.h"
#include "src/common/linux/linux_libc_support.h"
#include "src/third_party/lss/linux_syscall_support.h"

static bool DumpCallback(const google_breakpad::MinidumpDescriptor &descriptor,
    void *context, bool success) {
  if (!success) {
    static const char msg[] = "Failed to write minidump\n";
    sys_write(2, msg, sizeof(msg) - 1);
    return false;
  }

  static const char msg[] = "Wrote minidump: ";
  sys_write(2, msg, sizeof(msg) - 1);
  sys_write(2, descriptor.path(), strlen(descriptor.path()));
  sys_write(2, "\n", 1);

  return true;
}

static void DoSomethingWhichCrashes() {
  int local_var = 1;
  *reinterpret_cast<volatile char*>(NULL) = 1;
}

int main(int argc, const char *argv[]) {
  google_breakpad::MinidumpDescriptor minidump(".");
  google_breakpad::ExceptionHandler breakpad(minidump, NULL, DumpCallback, NULL,
      true, -1);
  DoSomethingWhichCrashes();
  return 0;
}

Compiling and running this example program should generate a minidump file in the current directory, and it should print the name of the minidump file before exiting. You can read more about the other parameters of the constructor in the source file of exception_handler.h .ExceptionHandler

Note : You should perform as few operations as possible in the callback function. Your program is already in an unsafe state. Allocating memory or calling functions from other shared libraries may be unsafe. The safest thing to do is forkto execcreate a new process to do whatever work you need to do. If you must do something in a callback, the Breakpad source code contains simple reimplementations of some libc functions to avoid calling libc directly, as well as a header file (in src/third_party/lss ) that performs Linux system calls to avoid calling libc Other shared libraries.

Send minidump file

In a real application, you will want to process the minidump in some way, such as sending it to a server for analysis. The Breakpad source tree contains some HTTP upload source code that may be useful , as well as a minidump upload tool .

Generate symbols for your program

In order to generate useful stack traces, Breakpad requires you to convert the debug symbols in your binary into a text-format symbol file . First, make sure you compile your binary with -gthe argument to include debugging symbols. configure && makeNext, run the compile tool in the Breakpad source directory dump_syms. Next, run on your binary dump_symsto generate symbols in text format. For example, if your primary binary name is HelloBreakpad:

$ breakpad/src/tools/linux/dump_syms/dump_syms ./HelloBreakpad > HelloBreakpad.sym

In order to minidump_stackwalkuse these symbols with tools, you will need to place them in a specific directory structure. The first line of the symbol file contains the information you need to generate this directory structure, such as (your output may be different):

~/workspace/HelloBreakpad/Debug$ head -n5 HelloBreakpad.sym 
MODULE Linux x86_64 467289A80132830FD70182B041DC6F960 HelloBreakpad
INFO CODE_ID A889724632010F83D70182B041DC6F96F093FBF2
FILE 0 /home/hanpfei/data/opensource/breakpad/./src/client/linux/handler/exception_handler.h
FILE 1 /home/hanpfei/data/opensource/breakpad/./src/client/linux/handler/microdump_extra_info.h
FILE 2 /home/hanpfei/data/opensource/breakpad/./src/client/linux/handler/minidump_descriptor.h
~/workspace/HelloBreakpad/Debug$ mkdir -p symbols/HelloBreakpad/467289A80132830FD70182B041DC6F960
~/workspace/HelloBreakpad/Debug$ mv HelloBreakpad.sym symbols/HelloBreakpad/467289A80132830FD70182B041DC6F960/

You can also use the symbolstore.py script from the Mozilla repository , which encapsulates these steps.

Process minidump to generate stack trace

Breakpad includes a minidump_stackwalktool called , which takes a minidump and its corresponding symbol in text format and generates a symbolic stack trace. If you compiled the Breakpad source code according to the instructions above, it should be located in the breakpad/src/processor directory. Simply pass in the minidump and symbolic path as command line arguments:

~/workspace/HelloBreakpad/Debug$ minidump_stackwalk efebac08-3b27-40b1-456cd9b4-33b33260.dmp symbols/
Operating system: Linux
                  0.0.0 Linux 5.13.0-40-generic #45~20.04.1-Ubuntu SMP Mon Apr 4 09:38:31 UTC 2022 x86_64
CPU: amd64
     family 6 model 158 stepping 10
     1 CPU

GPU: UNKNOWN

Crash reason:  SIGSEGV /SEGV_MAPERR
Crash address: 0x0
Process uptime: not available

Thread 0 (crashed)
 0  HelloBreakpad!DoSomethingWhichCrashes [HelloBreakpad.cpp : 28 + 0x0]
    rax = 0x0000000000000000   rdx = 0x0000000000000000
    rcx = 0x00005586cc34bf80   rbx = 0x00005586cb3276d0
    rsi = 0x0000000000000000   rdi = 0x00005586cb32f6c0
    rbp = 0x00007fffc54a2b50   rsp = 0x00007fffc54a2b50
     r8 = 0x0000000000000000    r9 = 0x00005586cc34bf78
    r10 = 0x0000000000000008   r11 = 0x00007f3735f21be0
    r12 = 0x00005586cb314df0   r13 = 0x00007fffc54a2e00
    r14 = 0x0000000000000000   r15 = 0x0000000000000000
    rip = 0x00005586cb314ff7
    Found by: given as instruction pointer in context
 1  HelloBreakpad!main [HelloBreakpad.cpp : 35 + 0x5]
    rbx = 0x00005586cb3276d0   rbp = 0x00007fffc54a2d10
    rsp = 0x00007fffc54a2b60   r12 = 0x00005586cb314df0
    r13 = 0x00007fffc54a2e00   r14 = 0x0000000000000000
    r15 = 0x0000000000000000   rip = 0x00005586cb3150c9
    Found by: call frame info
 2  libc.so.6 + 0x240b3
    rbx = 0x00005586cb3276d0   rbp = 0x0000000000000000
    rsp = 0x00007fffc54a2d20   r12 = 0x00005586cb314df0
    r13 = 0x00007fffc54a2e00   r14 = 0x0000000000000000
    r15 = 0x0000000000000000   rip = 0x00007f3735d590b3
    Found by: call frame info
 3  HelloBreakpad!DoSomethingWhichCrashes [HelloBreakpad.cpp : 29 + 0x3]
    rsp = 0x00007fffc54a2d40   rip = 0x00005586cb314ffd
    Found by: stack scanning
 4  HelloBreakpad + 0x156d0
    rbp = 0x00005586cb314ffd   rsp = 0x00007fffc54a2d48
    rip = 0x00005586cb3276d0
    Found by: call frame info
 5  HelloBreakpad!_start + 0x2e
    rsp = 0x00007fffc54a2df0   rip = 0x00005586cb314e1e
    Found by: stack scanning
 6  0x7fffc54a2df8
    rsp = 0x00007fffc54a2df8   rip = 0x00007fffc54a2df8
    Found by: call frame info

Loaded modules:
0x5586cb312000 - 0x5586cb327fff  HelloBreakpad  ???  (main)
0x7f3735be6000 - 0x7f3735c99fff  libm.so.6  ???
0x7f3735d35000 - 0x7f3735ecefff  libc.so.6  ???  (WARNING: No symbols, libc.so.6, E774DB9F17B26CD093172A8243F8547F0)
0x7f3735f27000 - 0x7f3735f3bfff  libgcc_s.so.1  ???
0x7f3735f42000 - 0x7f37360c8fff  libstdc++.so.6  ???
0x7f3736124000 - 0x7f373613afff  libpthread.so.0  ???
0x7f3736161000 - 0x7f3736184fff  ld-linux-x86-64.so.2  ???
0x7fffc54e3000 - 0x7fffc54e4fff  linux-gate.so  ???

It produces verbose output on stderr and a stack trace on stdout, so you may need to redirect stderr.

Reference documentation

Google Breakpad study notes

How To Add Breakpad To Your Linux Application

Google Breakpad

Guess you like

Origin blog.csdn.net/tq08g2z/article/details/125444301