Related
I'm working on adding some restrictions to my build process - to detect cycles, specifically. To achieve this I've been experimenting with user namespaces.
Here's my 'hello world' program:
#include <sched.h>
#include <unistd.h>
int main()
{
if( unshare(CLONE_NEWUSER) != 0)
{
return -1;
}
execl("/bin/sh", "/bin/sh", "-e", "-c", "make", NULL);
return 0;
}
Here is the makefile being run by make, namespace_test.cpp is the name of the file above:
namespace_test: namespace_test.cpp
g++ namespace_test.cpp -o ./namespace_test
When everything is up to date (as determined by make) the exec'd program works as expected:
make: 'namespace_test' is up to date.
But if make actually runs the g++ invocation I get an opaque error:
g++ namespace_test.cpp -o ./namespace_test
make: g++: Invalid argument
make: *** [Makefile:2: namespace_test] Error 127
What is the reason for this behavior?
This error was due to my failure to set up the uid_map and gid_map. I have not produced a satisfactory, explicit, minimal example of the error, but I have written a working minimal solution, that I will share here. Notice that int main() is identical, except before exec'ing the target command we first set up the uid_map and then the gid_map (granting ourselves permission via setgroups).
On my terminal $ id informs me that my real uid and gid are both 1000, so I have hardcoded that in the maps. It is more correct to query for the original id at the start of the process, see this excellent blog post. Also instrumental in this solution is this man page.
#include <cstdio>
#include <cstring>
#include <fcntl.h>
#include <sched.h>
#include <stdlib.h>
#include <unistd.h>
#define fatal_error(...) \
do { \
fprintf(stderr, "namespace_test \033[1;31merror:\033[0m "); \
fprintf(stderr, __VA_ARGS__ ); \
fprintf(stderr, "\n"); \
exit(EXIT_FAILURE); \
} while(0)
void write_string_to_file(const char* filename, const char* str, size_t str_len)
{
int fd = open(filename, O_RDWR);
if(fd == -1)
{
fatal_error("Failed to open %s: %m", filename);
}
if( write(fd, str, str_len) != str_len )
{
fatal_error("Failed to write %s: %m", filename);
}
close(fd);
}
void write_uid_mapping()
{
const char* mapping = "0 1000 1";
write_string_to_file("/proc/self/uid_map", mapping, strlen(mapping));
}
void write_set_groups()
{
const char* deny = "deny\n";
write_string_to_file("/proc/self/setgroups", deny, strlen(deny));
}
void write_gid_mapping()
{
write_set_groups();
const char* mapping = "0 1000 1";
write_string_to_file("/proc/self/gid_map", mapping, strlen(mapping));
}
int main()
{
if(unshare(CLONE_NEWUSER) != 0)
{
fatal_error("Failed to move into new user namespace");
}
write_uid_mapping();
write_gid_mapping();
execl("/bin/sh", "/bin/sh", "-e", "-c", "make", NULL);
return 0;
}
I have a small program that loads 2 modules (X11, and my own):
#include <fcntl.h>
#include <dlfcn.h>
#include <stdlib.h>
#include <stdio.h>
int main(int c, char* argv[])
{
pid_t PID = c > 1 ? atoi(argv[1]) : -1;
if (PID <= 0)
{
fprintf(stderr, "Invalid PID\n");
return -1;
}
const char* path = "/home/brandon/Desktop/mylib.so";
void* x11 = dlmopen(LM_ID_NEWLM, "libX11.so.6", RTLD_NOW);
/*Lmid_t id = 0;
dlinfo(dl, RTLD_DI_LMID, &id);
dl = dlmopen(id, path, RTLD_LAZY);*/
void* dl = dlopen(path, RTLD_LAZY);
if (dl)
{
printf("Loading dll\n");
void (*ptrace_info)(pid_t pid) = (decltype(ptrace_info))dlsym(dl, "ptrace_info");
if (ptrace_info)
{
ptrace_info(PID);
}
dlclose(dl);
printf("Unloaded\n");
}
return 0;
}
If I use dlopen(path, RTLD_*) my module fails to ptrace the specified pid. However, if I uncommented the code above that uses dlmopen everything works fine (even if I create a new namespace, it works)..
If I do not dlmopen(.., X11, ..), it works fine. The only time it does NOT work is if I dlmopen anything and then try to dlopen something else.
Seeing as the only difference is the namespace, is there a way I can use dlopen after using dlmopen?
I want to have a way to report the stack trace to the user if an exception is thrown. What is the best way to do this? Does it take huge amounts of extra code?
To answer questions:
I'd like it to be portable if possible. I want information to pop up, so the user can copy the stack trace and email it to me if an error comes up.
Andrew Grant's answer does not help getting a stack trace of the throwing function, at least not with GCC, because a throw statement does not save the current stack trace on its own, and the catch handler won't have access to the stack trace at that point any more.
The only way - using GCC - to solve this is to make sure to generate a stack trace at the point of the throw instruction, and save that with the exception object.
This method requires, of course, that every code that throws an exception uses that particular Exception class.
Update 11 July 2017: For some helpful code, take a look at cahit beyaz's answer, which points to http://stacktrace.sourceforge.net - I haven't used it yet but it looks promising.
It depends which platform.
On GCC it's pretty trivial, see this post for more details.
On MSVC then you can use the StackWalker library that handles all of the underlying API calls needed for Windows.
You'll have to figure out the best way to integrate this functionality into your app, but the amount of code you need to write should be minimal.
If you are using Boost 1.65 or higher, you can use boost::stacktrace:
#include <boost/stacktrace.hpp>
// ... somewhere inside the bar(int) function that is called recursively:
std::cout << boost::stacktrace::stacktrace();
I would like to add a standard library option (i.e. cross-platform) how to generate exception backtraces, which has become available with C++11:
Use std::nested_exception and std::throw_with_nested
This won't give you a stack unwind, but in my opinion the next best thing.
It is described on StackOverflow here and here, how you can get a backtrace on your exceptions inside your code without need for a debugger or cumbersome logging, by simply writing a proper exception handler which will rethrow nested exceptions.
Since you can do this with any derived exception class, you can add a lot of information to such a backtrace!
You may also take a look at my MWE on GitHub, where a backtrace would look something like this:
Library API: Exception caught in function 'api_function'
Backtrace:
~/Git/mwe-cpp-exception/src/detail/Library.cpp:17 : library_function failed
~/Git/mwe-cpp-exception/src/detail/Library.cpp:13 : could not open file "nonexistent.txt"
Unix: backtrace
Mac: backtrace
Windows: CaptureBackTrace
If you are using C++ and don't want/can't use Boost, you can print backtrace with demangled names using the following code [link to the original site].
Note, this solution is specific to Linux. It uses GNU's libc functions backtrace()/backtrace_symbols() (from execinfo.h) to get the backtraces and then uses __cxa_demangle() (from cxxabi.h) for demangling the backtrace symbol names.
// stacktrace.h (c) 2008, Timo Bingmann from http://idlebox.net/
// published under the WTFPL v2.0
#ifndef _STACKTRACE_H_
#define _STACKTRACE_H_
#include <stdio.h>
#include <stdlib.h>
#include <execinfo.h>
#include <cxxabi.h>
/** Print a demangled stack backtrace of the caller function to FILE* out. */
static inline void print_stacktrace(FILE *out = stderr, unsigned int max_frames = 63)
{
fprintf(out, "stack trace:\n");
// storage array for stack trace address data
void* addrlist[max_frames+1];
// retrieve current stack addresses
int addrlen = backtrace(addrlist, sizeof(addrlist) / sizeof(void*));
if (addrlen == 0) {
fprintf(out, " <empty, possibly corrupt>\n");
return;
}
// resolve addresses into strings containing "filename(function+address)",
// this array must be free()-ed
char** symbollist = backtrace_symbols(addrlist, addrlen);
// allocate string which will be filled with the demangled function name
size_t funcnamesize = 256;
char* funcname = (char*)malloc(funcnamesize);
// iterate over the returned symbol lines. skip the first, it is the
// address of this function.
for (int i = 1; i < addrlen; i++)
{
char *begin_name = 0, *begin_offset = 0, *end_offset = 0;
// find parentheses and +address offset surrounding the mangled name:
// ./module(function+0x15c) [0x8048a6d]
for (char *p = symbollist[i]; *p; ++p)
{
if (*p == '(')
begin_name = p;
else if (*p == '+')
begin_offset = p;
else if (*p == ')' && begin_offset) {
end_offset = p;
break;
}
}
if (begin_name && begin_offset && end_offset
&& begin_name < begin_offset)
{
*begin_name++ = '\0';
*begin_offset++ = '\0';
*end_offset = '\0';
// mangled name is now in [begin_name, begin_offset) and caller
// offset in [begin_offset, end_offset). now apply
// __cxa_demangle():
int status;
char* ret = abi::__cxa_demangle(begin_name,
funcname, &funcnamesize, &status);
if (status == 0) {
funcname = ret; // use possibly realloc()-ed string
fprintf(out, " %s : %s+%s\n",
symbollist[i], funcname, begin_offset);
}
else {
// demangling failed. Output function name as a C function with
// no arguments.
fprintf(out, " %s : %s()+%s\n",
symbollist[i], begin_name, begin_offset);
}
}
else
{
// couldn't parse the line? print the whole line.
fprintf(out, " %s\n", symbollist[i]);
}
}
free(funcname);
free(symbollist);
}
#endif // _STACKTRACE_H_
HTH!
AFAIK libunwind is quite portable and so far I haven't found anything easier to use.
I recommend http://stacktrace.sourceforge.net/ project. It support Windows, Mac OS and also Linux
Since the stack is already unwound when entering the catch block, the solution in my case was to not catch certain exceptions which then lead to a SIGABRT. In the signal handler for SIGABRT I then fork() and execl() either gdb (in debug builds) or Google breakpads stackwalk (in release builds). Also I try to only use signal handler safe functions.
GDB:
static const char BACKTRACE_START[] = "<2>--- backtrace of entire stack ---\n";
static const char BACKTRACE_STOP[] = "<2>--- backtrace finished ---\n";
static char *ltrim(char *s)
{
while (' ' == *s) {
s++;
}
return s;
}
void Backtracer::print()
{
int child_pid = ::fork();
if (child_pid == 0) {
// redirect stdout to stderr
::dup2(2, 1);
// create buffer for parent pid (2+16+1 spaces to allow up to a 64 bit hex parent pid)
char pid_buf[32];
const char* stem = " ";
const char* s = stem;
char* d = &pid_buf[0];
while (static_cast<bool>(*s))
{
*d++ = *s++;
}
*d-- = '\0';
char* hexppid = d;
// write parent pid to buffer and prefix with 0x
int ppid = getppid();
while (ppid != 0) {
*hexppid = ((ppid & 0xF) + '0');
if(*hexppid > '9') {
*hexppid += 'a' - '0' - 10;
}
--hexppid;
ppid >>= 4;
}
*hexppid-- = 'x';
*hexppid = '0';
// invoke GDB
char name_buf[512];
name_buf[::readlink("/proc/self/exe", &name_buf[0], 511)] = 0;
ssize_t r = ::write(STDERR_FILENO, &BACKTRACE_START[0], sizeof(BACKTRACE_START));
(void)r;
::execl("/usr/bin/gdb",
"/usr/bin/gdb", "--batch", "-n", "-ex", "thread apply all bt full", "-ex", "quit",
&name_buf[0], ltrim(&pid_buf[0]), nullptr);
::exit(1); // if GDB failed to start
} else if (child_pid == -1) {
::exit(1); // if forking failed
} else {
// make it work for non root users
if (0 != getuid()) {
::prctl(PR_SET_PTRACER, PR_SET_PTRACER_ANY, 0, 0, 0);
}
::waitpid(child_pid, nullptr, 0);
ssize_t r = ::write(STDERR_FILENO, &BACKTRACE_STOP[0], sizeof(BACKTRACE_STOP));
(void)r;
}
}
minidump_stackwalk:
static bool dumpCallback(const google_breakpad::MinidumpDescriptor& descriptor, void* context, bool succeeded)
{
int child_pid = ::fork();
if (child_pid == 0) {
::dup2(open("/dev/null", O_WRONLY), 2); // ignore verbose output on stderr
ssize_t r = ::write(STDOUT_FILENO, &MINIDUMP_STACKWALK_START[0], sizeof(MINIDUMP_STACKWALK_START));
(void)r;
::execl("/usr/bin/minidump_stackwalk", "/usr/bin/minidump_stackwalk", descriptor.path(), "/usr/share/breakpad-syms", nullptr);
::exit(1); // if minidump_stackwalk failed to start
} else if (child_pid == -1) {
::exit(1); // if forking failed
} else {
::waitpid(child_pid, nullptr, 0);
ssize_t r = ::write(STDOUT_FILENO, &MINIDUMP_STACKWALK_STOP[0], sizeof(MINIDUMP_STACKWALK_STOP));
(void)r;
}
::remove(descriptor.path()); // this is not signal safe anymore but should still work
return succeeded;
}
Edit: To make it work for breakpad I also had to add this:
std::set_terminate([]()
{
ssize_t r = ::write(STDERR_FILENO, EXCEPTION, sizeof(EXCEPTION));
(void)r;
google_breakpad::ExceptionHandler::WriteMinidump(std::string("/tmp"), dumpCallback, NULL);
exit(1); // avoid creating a second dump by not calling std::abort
});
Source: How to get a stack trace for C++ using gcc with line number information? and Is it possible to attach gdb to a crashed process (a.k.a "just-in-time" debugging)
on linux with g++ check out this lib
https://sourceforge.net/projects/libcsdbg
it does all the work for you
On Windows, check out BugTrap. Its not longer at the original link, but its still available on CodeProject.
I have a similar problem, and though I like portability, I only need gcc support. In gcc, execinfo.h and the backtrace calls are available. To demangle the function names, Mr. Bingmann has a nice piece of code. To dump a backtrace on an exception, I create an exception that prints the backtrace in the constructor. If I were expecting this to work with an exception thrown in a library, it might require rebuilding/linking so that the backtracing exception is used.
/******************************************
#Makefile with flags for printing backtrace with function names
# compile with symbols for backtrace
CXXFLAGS=-g
# add symbols to dynamic symbol table for backtrace
LDFLAGS=-rdynamic
turducken: turducken.cc
******************************************/
#include <cstdio>
#include <stdexcept>
#include <execinfo.h>
#include "stacktrace.h" /* https://panthema.net/2008/0901-stacktrace-demangled/ */
// simple exception that prints backtrace when constructed
class btoverflow_error: public std::overflow_error
{
public:
btoverflow_error( const std::string& arg ) :
std::overflow_error( arg )
{
print_stacktrace();
};
};
void chicken(void)
{
throw btoverflow_error( "too big" );
}
void duck(void)
{
chicken();
}
void turkey(void)
{
duck();
}
int main( int argc, char *argv[])
{
try
{
turkey();
}
catch( btoverflow_error e)
{
printf( "caught exception: %s\n", e.what() );
}
}
Compiling and running this with gcc 4.8.4 yields a backtrace with nicely unmangled C++ function names:
stack trace:
./turducken : btoverflow_error::btoverflow_error(std::string const&)+0x43
./turducken : chicken()+0x48
./turducken : duck()+0x9
./turducken : turkey()+0x9
./turducken : main()+0x15
/lib/x86_64-linux-gnu/libc.so.6 : __libc_start_main()+0xf5
./turducken() [0x401629]
Poppy can gather not only the stack trace, but also parameter values, local variables, etc. - everything leading to the crash.
The following code stops the execution right after an exception is thrown. You need to set a windows_exception_handler along with a termination handler. I tested this in MinGW 32bits.
void beforeCrash(void);
static const bool SET_TERMINATE = std::set_terminate(beforeCrash);
void beforeCrash() {
__asm("int3");
}
int main(int argc, char *argv[])
{
SetUnhandledExceptionFilter(windows_exception_handler);
...
}
Check the following code for the windows_exception_handler function:
http://www.codedisqus.com/0ziVPgVPUk/exception-handling-and-stacktrace-under-windows-mingwgcc.html
Cpp-tool ex_diag - easyweight, multiplatform, minimal resource using, simple and flexible at trace.
A working example for OSX (tested right now on Catalina 10.15). Not portable to linux/windows obviously. Probably it will be usefull to somebody.
In the "Mew-exception" string you can use backtrace and/or backtrace_symbols functions
#include <stdexcept>
#include <typeinfo>
#include <dlfcn.h>
extern "C" void __cxa_throw(void *thrown_object, std::type_info *tinfo, void (*dest)(void *));
static void (*__cxa_throw_orig)(void *thrown_object, std::type_info *tinfo, void (*dest)(void *));
extern "C" void luna_cxa_throw(void *thrown_object, std::type_info *tinfo, void (*dest)(void *))
{
printf("Mew-exception you can catch your backtrace here!");
__cxa_throw_orig(thrown_object, tinfo, dest);
}
//__attribute__ ((used))
//__attribute__ ((section ("__DATA,__interpose")))
static struct replace_pair_t {
void *replacement, *replacee;
} replace_pair = { (void*)luna_cxa_throw, (void*)__cxa_throw };
extern "C" const struct mach_header __dso_handle;
extern "C" void dyld_dynamic_interpose(const struct mach_header*,
const replace_pair_t replacements[],
size_t count);
int fn()
{
int a = 10; ++a;
throw std::runtime_error("Mew!");
}
int main(int argc, const char * argv[]) {
__cxa_throw_orig = (void (*)(void *thrown_object, std::type_info *tinfo, void (*dest)(void *)))dlsym(RTLD_DEFAULT, "__cxa_throw");
dyld_dynamic_interpose(&__dso_handle, &replace_pair, 1);
fn();
return 0;
}
I want to have a way to report the stack trace to the user if an exception is thrown. What is the best way to do this? Does it take huge amounts of extra code?
To answer questions:
I'd like it to be portable if possible. I want information to pop up, so the user can copy the stack trace and email it to me if an error comes up.
Andrew Grant's answer does not help getting a stack trace of the throwing function, at least not with GCC, because a throw statement does not save the current stack trace on its own, and the catch handler won't have access to the stack trace at that point any more.
The only way - using GCC - to solve this is to make sure to generate a stack trace at the point of the throw instruction, and save that with the exception object.
This method requires, of course, that every code that throws an exception uses that particular Exception class.
Update 11 July 2017: For some helpful code, take a look at cahit beyaz's answer, which points to http://stacktrace.sourceforge.net - I haven't used it yet but it looks promising.
It depends which platform.
On GCC it's pretty trivial, see this post for more details.
On MSVC then you can use the StackWalker library that handles all of the underlying API calls needed for Windows.
You'll have to figure out the best way to integrate this functionality into your app, but the amount of code you need to write should be minimal.
If you are using Boost 1.65 or higher, you can use boost::stacktrace:
#include <boost/stacktrace.hpp>
// ... somewhere inside the bar(int) function that is called recursively:
std::cout << boost::stacktrace::stacktrace();
I would like to add a standard library option (i.e. cross-platform) how to generate exception backtraces, which has become available with C++11:
Use std::nested_exception and std::throw_with_nested
This won't give you a stack unwind, but in my opinion the next best thing.
It is described on StackOverflow here and here, how you can get a backtrace on your exceptions inside your code without need for a debugger or cumbersome logging, by simply writing a proper exception handler which will rethrow nested exceptions.
Since you can do this with any derived exception class, you can add a lot of information to such a backtrace!
You may also take a look at my MWE on GitHub, where a backtrace would look something like this:
Library API: Exception caught in function 'api_function'
Backtrace:
~/Git/mwe-cpp-exception/src/detail/Library.cpp:17 : library_function failed
~/Git/mwe-cpp-exception/src/detail/Library.cpp:13 : could not open file "nonexistent.txt"
Unix: backtrace
Mac: backtrace
Windows: CaptureBackTrace
If you are using C++ and don't want/can't use Boost, you can print backtrace with demangled names using the following code [link to the original site].
Note, this solution is specific to Linux. It uses GNU's libc functions backtrace()/backtrace_symbols() (from execinfo.h) to get the backtraces and then uses __cxa_demangle() (from cxxabi.h) for demangling the backtrace symbol names.
// stacktrace.h (c) 2008, Timo Bingmann from http://idlebox.net/
// published under the WTFPL v2.0
#ifndef _STACKTRACE_H_
#define _STACKTRACE_H_
#include <stdio.h>
#include <stdlib.h>
#include <execinfo.h>
#include <cxxabi.h>
/** Print a demangled stack backtrace of the caller function to FILE* out. */
static inline void print_stacktrace(FILE *out = stderr, unsigned int max_frames = 63)
{
fprintf(out, "stack trace:\n");
// storage array for stack trace address data
void* addrlist[max_frames+1];
// retrieve current stack addresses
int addrlen = backtrace(addrlist, sizeof(addrlist) / sizeof(void*));
if (addrlen == 0) {
fprintf(out, " <empty, possibly corrupt>\n");
return;
}
// resolve addresses into strings containing "filename(function+address)",
// this array must be free()-ed
char** symbollist = backtrace_symbols(addrlist, addrlen);
// allocate string which will be filled with the demangled function name
size_t funcnamesize = 256;
char* funcname = (char*)malloc(funcnamesize);
// iterate over the returned symbol lines. skip the first, it is the
// address of this function.
for (int i = 1; i < addrlen; i++)
{
char *begin_name = 0, *begin_offset = 0, *end_offset = 0;
// find parentheses and +address offset surrounding the mangled name:
// ./module(function+0x15c) [0x8048a6d]
for (char *p = symbollist[i]; *p; ++p)
{
if (*p == '(')
begin_name = p;
else if (*p == '+')
begin_offset = p;
else if (*p == ')' && begin_offset) {
end_offset = p;
break;
}
}
if (begin_name && begin_offset && end_offset
&& begin_name < begin_offset)
{
*begin_name++ = '\0';
*begin_offset++ = '\0';
*end_offset = '\0';
// mangled name is now in [begin_name, begin_offset) and caller
// offset in [begin_offset, end_offset). now apply
// __cxa_demangle():
int status;
char* ret = abi::__cxa_demangle(begin_name,
funcname, &funcnamesize, &status);
if (status == 0) {
funcname = ret; // use possibly realloc()-ed string
fprintf(out, " %s : %s+%s\n",
symbollist[i], funcname, begin_offset);
}
else {
// demangling failed. Output function name as a C function with
// no arguments.
fprintf(out, " %s : %s()+%s\n",
symbollist[i], begin_name, begin_offset);
}
}
else
{
// couldn't parse the line? print the whole line.
fprintf(out, " %s\n", symbollist[i]);
}
}
free(funcname);
free(symbollist);
}
#endif // _STACKTRACE_H_
HTH!
AFAIK libunwind is quite portable and so far I haven't found anything easier to use.
I recommend http://stacktrace.sourceforge.net/ project. It support Windows, Mac OS and also Linux
Since the stack is already unwound when entering the catch block, the solution in my case was to not catch certain exceptions which then lead to a SIGABRT. In the signal handler for SIGABRT I then fork() and execl() either gdb (in debug builds) or Google breakpads stackwalk (in release builds). Also I try to only use signal handler safe functions.
GDB:
static const char BACKTRACE_START[] = "<2>--- backtrace of entire stack ---\n";
static const char BACKTRACE_STOP[] = "<2>--- backtrace finished ---\n";
static char *ltrim(char *s)
{
while (' ' == *s) {
s++;
}
return s;
}
void Backtracer::print()
{
int child_pid = ::fork();
if (child_pid == 0) {
// redirect stdout to stderr
::dup2(2, 1);
// create buffer for parent pid (2+16+1 spaces to allow up to a 64 bit hex parent pid)
char pid_buf[32];
const char* stem = " ";
const char* s = stem;
char* d = &pid_buf[0];
while (static_cast<bool>(*s))
{
*d++ = *s++;
}
*d-- = '\0';
char* hexppid = d;
// write parent pid to buffer and prefix with 0x
int ppid = getppid();
while (ppid != 0) {
*hexppid = ((ppid & 0xF) + '0');
if(*hexppid > '9') {
*hexppid += 'a' - '0' - 10;
}
--hexppid;
ppid >>= 4;
}
*hexppid-- = 'x';
*hexppid = '0';
// invoke GDB
char name_buf[512];
name_buf[::readlink("/proc/self/exe", &name_buf[0], 511)] = 0;
ssize_t r = ::write(STDERR_FILENO, &BACKTRACE_START[0], sizeof(BACKTRACE_START));
(void)r;
::execl("/usr/bin/gdb",
"/usr/bin/gdb", "--batch", "-n", "-ex", "thread apply all bt full", "-ex", "quit",
&name_buf[0], ltrim(&pid_buf[0]), nullptr);
::exit(1); // if GDB failed to start
} else if (child_pid == -1) {
::exit(1); // if forking failed
} else {
// make it work for non root users
if (0 != getuid()) {
::prctl(PR_SET_PTRACER, PR_SET_PTRACER_ANY, 0, 0, 0);
}
::waitpid(child_pid, nullptr, 0);
ssize_t r = ::write(STDERR_FILENO, &BACKTRACE_STOP[0], sizeof(BACKTRACE_STOP));
(void)r;
}
}
minidump_stackwalk:
static bool dumpCallback(const google_breakpad::MinidumpDescriptor& descriptor, void* context, bool succeeded)
{
int child_pid = ::fork();
if (child_pid == 0) {
::dup2(open("/dev/null", O_WRONLY), 2); // ignore verbose output on stderr
ssize_t r = ::write(STDOUT_FILENO, &MINIDUMP_STACKWALK_START[0], sizeof(MINIDUMP_STACKWALK_START));
(void)r;
::execl("/usr/bin/minidump_stackwalk", "/usr/bin/minidump_stackwalk", descriptor.path(), "/usr/share/breakpad-syms", nullptr);
::exit(1); // if minidump_stackwalk failed to start
} else if (child_pid == -1) {
::exit(1); // if forking failed
} else {
::waitpid(child_pid, nullptr, 0);
ssize_t r = ::write(STDOUT_FILENO, &MINIDUMP_STACKWALK_STOP[0], sizeof(MINIDUMP_STACKWALK_STOP));
(void)r;
}
::remove(descriptor.path()); // this is not signal safe anymore but should still work
return succeeded;
}
Edit: To make it work for breakpad I also had to add this:
std::set_terminate([]()
{
ssize_t r = ::write(STDERR_FILENO, EXCEPTION, sizeof(EXCEPTION));
(void)r;
google_breakpad::ExceptionHandler::WriteMinidump(std::string("/tmp"), dumpCallback, NULL);
exit(1); // avoid creating a second dump by not calling std::abort
});
Source: How to get a stack trace for C++ using gcc with line number information? and Is it possible to attach gdb to a crashed process (a.k.a "just-in-time" debugging)
on linux with g++ check out this lib
https://sourceforge.net/projects/libcsdbg
it does all the work for you
On Windows, check out BugTrap. Its not longer at the original link, but its still available on CodeProject.
I have a similar problem, and though I like portability, I only need gcc support. In gcc, execinfo.h and the backtrace calls are available. To demangle the function names, Mr. Bingmann has a nice piece of code. To dump a backtrace on an exception, I create an exception that prints the backtrace in the constructor. If I were expecting this to work with an exception thrown in a library, it might require rebuilding/linking so that the backtracing exception is used.
/******************************************
#Makefile with flags for printing backtrace with function names
# compile with symbols for backtrace
CXXFLAGS=-g
# add symbols to dynamic symbol table for backtrace
LDFLAGS=-rdynamic
turducken: turducken.cc
******************************************/
#include <cstdio>
#include <stdexcept>
#include <execinfo.h>
#include "stacktrace.h" /* https://panthema.net/2008/0901-stacktrace-demangled/ */
// simple exception that prints backtrace when constructed
class btoverflow_error: public std::overflow_error
{
public:
btoverflow_error( const std::string& arg ) :
std::overflow_error( arg )
{
print_stacktrace();
};
};
void chicken(void)
{
throw btoverflow_error( "too big" );
}
void duck(void)
{
chicken();
}
void turkey(void)
{
duck();
}
int main( int argc, char *argv[])
{
try
{
turkey();
}
catch( btoverflow_error e)
{
printf( "caught exception: %s\n", e.what() );
}
}
Compiling and running this with gcc 4.8.4 yields a backtrace with nicely unmangled C++ function names:
stack trace:
./turducken : btoverflow_error::btoverflow_error(std::string const&)+0x43
./turducken : chicken()+0x48
./turducken : duck()+0x9
./turducken : turkey()+0x9
./turducken : main()+0x15
/lib/x86_64-linux-gnu/libc.so.6 : __libc_start_main()+0xf5
./turducken() [0x401629]
Poppy can gather not only the stack trace, but also parameter values, local variables, etc. - everything leading to the crash.
The following code stops the execution right after an exception is thrown. You need to set a windows_exception_handler along with a termination handler. I tested this in MinGW 32bits.
void beforeCrash(void);
static const bool SET_TERMINATE = std::set_terminate(beforeCrash);
void beforeCrash() {
__asm("int3");
}
int main(int argc, char *argv[])
{
SetUnhandledExceptionFilter(windows_exception_handler);
...
}
Check the following code for the windows_exception_handler function:
http://www.codedisqus.com/0ziVPgVPUk/exception-handling-and-stacktrace-under-windows-mingwgcc.html
Cpp-tool ex_diag - easyweight, multiplatform, minimal resource using, simple and flexible at trace.
A working example for OSX (tested right now on Catalina 10.15). Not portable to linux/windows obviously. Probably it will be usefull to somebody.
In the "Mew-exception" string you can use backtrace and/or backtrace_symbols functions
#include <stdexcept>
#include <typeinfo>
#include <dlfcn.h>
extern "C" void __cxa_throw(void *thrown_object, std::type_info *tinfo, void (*dest)(void *));
static void (*__cxa_throw_orig)(void *thrown_object, std::type_info *tinfo, void (*dest)(void *));
extern "C" void luna_cxa_throw(void *thrown_object, std::type_info *tinfo, void (*dest)(void *))
{
printf("Mew-exception you can catch your backtrace here!");
__cxa_throw_orig(thrown_object, tinfo, dest);
}
//__attribute__ ((used))
//__attribute__ ((section ("__DATA,__interpose")))
static struct replace_pair_t {
void *replacement, *replacee;
} replace_pair = { (void*)luna_cxa_throw, (void*)__cxa_throw };
extern "C" const struct mach_header __dso_handle;
extern "C" void dyld_dynamic_interpose(const struct mach_header*,
const replace_pair_t replacements[],
size_t count);
int fn()
{
int a = 10; ++a;
throw std::runtime_error("Mew!");
}
int main(int argc, const char * argv[]) {
__cxa_throw_orig = (void (*)(void *thrown_object, std::type_info *tinfo, void (*dest)(void *)))dlsym(RTLD_DEFAULT, "__cxa_throw");
dyld_dynamic_interpose(&__dso_handle, &replace_pair, 1);
fn();
return 0;
}
I want to set a watchpoint (break on hardware write) temporarily in my C++ program to find memory corruption.
I've seen all the ways to do it manually through gdb, but I would like to actually set the watchpoint via some method in my code so I don't have to break into gdb, find out the address, set the watchpoint and then continue.
Something like:
#define SET_WATCHPOINT(addr) asm ("set break on hardware write %addr")
Set hardware watchpoint from child process.
#include <signal.h>
#include <syscall.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <linux/user.h>
enum {
DR7_BREAK_ON_EXEC = 0,
DR7_BREAK_ON_WRITE = 1,
DR7_BREAK_ON_RW = 3,
};
enum {
DR7_LEN_1 = 0,
DR7_LEN_2 = 1,
DR7_LEN_4 = 3,
};
typedef struct {
char l0:1;
char g0:1;
char l1:1;
char g1:1;
char l2:1;
char g2:1;
char l3:1;
char g3:1;
char le:1;
char ge:1;
char pad1:3;
char gd:1;
char pad2:2;
char rw0:2;
char len0:2;
char rw1:2;
char len1:2;
char rw2:2;
char len2:2;
char rw3:2;
char len3:2;
} dr7_t;
typedef void sighandler_t(int, siginfo_t*, void*);
int watchpoint(void* addr, sighandler_t handler)
{
pid_t child;
pid_t parent = getpid();
struct sigaction trap_action;
int child_stat = 0;
sigaction(SIGTRAP, NULL, &trap_action);
trap_action.sa_sigaction = handler;
trap_action.sa_flags = SA_SIGINFO | SA_RESTART | SA_NODEFER;
sigaction(SIGTRAP, &trap_action, NULL);
if ((child = fork()) == 0)
{
int retval = EXIT_SUCCESS;
dr7_t dr7 = {0};
dr7.l0 = 1;
dr7.rw0 = DR7_BREAK_ON_WRITE;
dr7.len0 = DR7_LEN_4;
if (ptrace(PTRACE_ATTACH, parent, NULL, NULL))
{
exit(EXIT_FAILURE);
}
sleep(1);
if (ptrace(PTRACE_POKEUSER, parent, offsetof(struct user, u_debugreg[0]), addr))
{
retval = EXIT_FAILURE;
}
if (ptrace(PTRACE_POKEUSER, parent, offsetof(struct user, u_debugreg[7]), dr7))
{
retval = EXIT_FAILURE;
}
if (ptrace(PTRACE_DETACH, parent, NULL, NULL))
{
retval = EXIT_FAILURE;
}
exit(retval);
}
waitpid(child, &child_stat, 0);
if (WEXITSTATUS(child_stat))
{
printf("child exit !0\n");
return 1;
}
return 0;
}
int var;
void trap(int sig, siginfo_t* info, void* context)
{
printf("new value: %d\n", var);
}
int main(int argc, char * argv[])
{
int i;
printf("init value: %d\n", var);
watchpoint(&var, trap);
for (i = 0; i < 100; i++) {
var++;
sleep(1);
}
return 0;
}
Based on user512106's great answer, I coded up a little "library" that someone might find useful:
It's on github at https://github.com/whh8b/hwbp_lib. I wish I could have commented directly on his answer, but I don't have enough rep yet.
Based on feedback from the community, I am going to copy/paste the relevant code here:
#include <stdio.h>
#include <stddef.h>
#include <signal.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/ptrace.h>
#include <sys/user.h>
#include <sys/prctl.h>
#include <stdint.h>
#include <errno.h>
#include <stdbool.h>
extern int errno;
enum {
BREAK_EXEC = 0x0,
BREAK_WRITE = 0x1,
BREAK_READWRITE = 0x3,
};
enum {
BREAK_ONE = 0x0,
BREAK_TWO = 0x1,
BREAK_FOUR = 0x3,
BREAK_EIGHT = 0x2,
};
#define ENABLE_BREAKPOINT(x) (0x1<<(x*2))
#define ENABLE_BREAK_EXEC(x) (BREAK_EXEC<<(16+(x*4)))
#define ENABLE_BREAK_WRITE(x) (BREAK_WRITE<<(16+(x*4)))
#define ENABLE_BREAK_READWRITE(x) (BREAK_READWRITE<<(16+(x*4)))
/*
* This function fork()s a child that will use
* ptrace to set a hardware breakpoint for
* memory r/w at _addr_. When the breakpoint is
* hit, then _handler_ is invoked in a signal-
* handling context.
*/
bool install_breakpoint(void *addr, int bpno, void (*handler)(int)) {
pid_t child = 0;
uint32_t enable_breakpoint = ENABLE_BREAKPOINT(bpno);
uint32_t enable_breakwrite = ENABLE_BREAK_WRITE(bpno);
pid_t parent = getpid();
int child_status = 0;
if (!(child = fork()))
{
int parent_status = 0;
if (ptrace(PTRACE_ATTACH, parent, NULL, NULL))
_exit(1);
while (!WIFSTOPPED(parent_status))
waitpid(parent, &parent_status, 0);
/*
* set the breakpoint address.
*/
if (ptrace(PTRACE_POKEUSER,
parent,
offsetof(struct user, u_debugreg[bpno]),
addr))
_exit(1);
/*
* set parameters for when the breakpoint should be triggered.
*/
if (ptrace(PTRACE_POKEUSER,
parent,
offsetof(struct user, u_debugreg[7]),
enable_breakwrite | enable_breakpoint))
_exit(1);
if (ptrace(PTRACE_DETACH, parent, NULL, NULL))
_exit(1);
_exit(0);
}
waitpid(child, &child_status, 0);
signal(SIGTRAP, handler);
if (WIFEXITED(child_status) && !WEXITSTATUS(child_status))
return true;
return false;
}
/*
* This function will disable a breakpoint by
* invoking install_breakpoint is a 0x0 _addr_
* and no handler function. See comments above
* for implementation details.
*/
bool disable_breakpoint(int bpno)
{
return install_breakpoint(0x0, bpno, NULL);
}
/*
* Example of how to use this /library/.
*/
int handled = 0;
void handle(int s) {
handled = 1;
return;
}
int main(int argc, char **argv) {
int a = 0;
if (!install_breakpoint(&a, 0, handle))
printf("failed to set the breakpoint!\n");
a = 1;
printf("handled: %d\n", handled);
if (!disable_breakpoint(0))
printf("failed to disable the breakpoint!\n");
return 1;
}
I hope that this helps someone!
Will
In GDB, there are two types of watchpoints, hardware and software.
you can't implement easily software watchpoints: (cf. GDB Internals)
Software watchpoints are very slow, since gdb needs to single-step the program being debugged and test the value of the watched expression(s) after each instruction.
EDIT:
I'm still trying to understand what are hardware watchpoint.
for hardware breakpoints, this article gives some technics:
We want to watch reading from or writing into 1 qword at address 100005120h (address range 100005120h-100005127h)
lea rax, [100005120h]
mov dr0, rax
mov rax, dr7
and eax, not ((1111b shl 16) + 11b) ; mask off all
or eax, (1011b shl 16) + 1 ; prepare to set what we want
mov
dr7, rax ; set it finally
Done, now we can wait until code falls into the trap! After accessing any byte at memory range 100005120h-100005127h, int 1 will occur and DR6.B0 bit will be set to 1.
You can also take a look at GDB low-end files (eg, amd64-linux-nat.c) but it (certainly) involves 2 processes: 1/ the one you want to watch 2/a lightweight debugger who attaches to the first one with ptrace, and uses:
ptrace (PTRACE_POKEUSER, tid, __regnum__offset__, address);
to set and handle the watchpoint.
The program itself can supply commands to the GDB. You'll need a special shell script to run GDB though.
Copy this code into the file named untee, and execute chmod 755 untee
#!/bin/bash
if [ -z "$1" ]; then
echo "Usage: $0 PIPE | COMMAND"
echo "This script will read the input from both stdin and PIPE, and supply it to the COMMAND."
echo "If PIPE does not exist it will be created with mkfifo command."
exit 0
fi
PIPE="$1"
if [ \! -e "$PIPE" ]; then
mkfifo "$PIPE"
fi
if [ \! -p "$PIPE" ]; then
echo "File $PIPE does not exist or is not a named pipe" > /dev/stderr
exit 1
fi
# Open the pipe as a FD 3
echo "Waiting for $PIPE to be opened by another process" > /dev/stderr
exec 3<"$PIPE"
echo "$PIPE opened" > /dev/stderr
OPENED=true
while true; do
read -t 1 INPUT
RET=$?
if [ "$RET" = 0 ]; then
echo "$INPUT"
elif [ "$RET" -lt 128 ]; then
echo "stdin closed, exiting" > /dev/stderr
break
fi
if $OPENED; then
while read -t 1 -u 3 INPUT; do
RET=$?
if [ "$RET" = 0 ]; then
echo "$INPUT"
else
if [ "$RET" -lt 128 ]; then
echo "$PIPE closed, ignoring" > /dev/stderr
OPENED=false
fi
break
fi
done
fi
done
And now the C code:
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <signal.h>
#include <unistd.h>
void gdbCommand(const char *c)
{
static FILE * dbgpipe = NULL;
static const char * dbgpath = "/tmp/dbgpipe";
struct stat st;
if( !dbgpipe && stat(dbgpath, &st) == 0 && S_ISFIFO(st.st_mode) )
dbgpipe = fopen(dbgpath, "w");
if( !dbgpipe )
return;
fprintf(dbgpipe, "%s\n", c);
fflush(dbgpipe);
}
void gdbSetWatchpoint(const char *var)
{
char buf[256];
snprintf(buf, sizeof(buf), "watch %s", var);
gdbCommand("up"); /* Go up the stack from the kill() system call - this may vary by the OS, you may need to walk the stack more times */
gdbCommand("up"); /* Go up the stack from the gdbSetWatchpoint() function */
gdbCommand(buf);
gdbCommand("continue");
kill(getpid(), SIGINT); /* Make GDB pause our process and execute commands */
}
int subfunc(int *v)
{
*v += 5; /* GDB should pause after this line, and let you explore stack etc */
return v;
}
int func()
{
int i = 10;
printf("Adding GDB watch for var 'i'\n");
gdbSetWatchpoint("i");
subfunc(&i);
return i;
}
int func2()
{
int j = 20;
return j + func();
}
int main(int argc, char ** argv)
{
func();
func2();
return 0;
}
Copy that to the file named test.c, compile with command gcc test.c -O0 -g -o test then execute ./untee /tmp/dbgpipe | gdb -ex "run" ./test
This works on my 64-bit Ubuntu, with GDB 7.3 (older GDB versions might refuse to read commands from non-terminal)
If you happen to be using Xcode, you can achieve the required effect (automatic setting of watchpoints) by using an action on another breakpoint to set your watchpoint:
Set up a breakpoint somewhere where the variable you want to watch will be in scope that will be hit before you need to start watching the variable,
Right-click on the breakpoint and select Edit Breakpoint...,
Click on Add Action and add a Debugger Command with an LLDB command like: watchpoint set variable <variablename> (or if you're using GDB1, a command like: watch <variablename>),
Check the Automatically continue after evaluating actions checkbox.
1: GDB is no longer supported in more recent versions of Xcode, but I believe it is still possible to set it up manually.