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, ExceptionHandler
the 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 fork
to exec
create 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 -g
the argument to include debugging symbols. configure && make
Next, run the compile tool in the Breakpad source directory dump_syms
. Next, run on your binary dump_syms
to 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_stackwalk
use 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_stackwalk
tool 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