I'm trying to capture when a child executes an abort.
The following is a MCVE that should give an idea of what I'm trying to do.
#include <iostream>
#include <cstdio>
#include <iomanip> //to make things legible
#include <sys/ptrace.h>
#include <sys/wait.h>
#include <libunwind-ptrace.h>
#include <unistd.h>
#include <sys/types.h>
using namespace std;
int getBacktrace(pid_t pid)
{
int rv = 0;
unw_addr_space_t as = unw_create_addr_space(&_UPT_accessors, 0);
if(!as)
{
return rv;
}
void *context = _UPT_create(pid);
unw_cursor_t cursor;
if(unw_init_remote(&cursor, as, context) == 0)
{
cout << "Abort: " << std::hex << (long)*abort << endl;
do
{
unw_proc_info_t pi;
if(unw_get_proc_info(&cursor, &pi) >= 0)
{
if((long)pi.start_ip == (long)abort)
{
cout << "abort found!\n";
//do some recovery stuff here.so WIFEXITED won't work and WIFSIGNALED can give a false alarm
rv = 1;
break;
}
//Just for fun, let's print the backtrace
unw_word_t offset, pc;
char sym[4096];
if(unw_get_reg(&cursor, UNW_REG_IP, &pc) != 0)
{
cout << "Unknown PC\n";
}
else
{
cout << "0x" << std::hex << pc << " ";
}
if(unw_get_proc_name(&cursor, sym, sizeof(sym), &offset) != 0)
{
cout << "<unknown>\n";
}
else
{
cout << sym << "+0x" << std::hex << offset << endl;
}
cout << "\tfunction range: " << std::hex << pi.start_ip << "-" << pi.end_ip << endl;
}
}while(unw_step(&cursor) > 0);
cout << endl << endl; //Add spacing to make it easier to read.
}
if(context)
{
_UPT_destroy(context);
}
cout << std::dec;
return rv;
}
int childFunction()
{
//This is just an example function maybe it throws maybe it doesn't
sleep(5);
throw 42;
}
int main()
{
pid_t childPid;
if((childPid = fork()) == 0)
{
ptrace(PTRACE_TRACEME, 0, nullptr, nullptr);
//child
childFunction();
}
else
{
while(true)
{
waitpid(childPid, nullptr, 0);
if(getBacktrace(childPid))
{
//do some logging or functionality here
cout << "Child aborted\n";
break;
}
ptrace(PTRACE_CONT, childPid, nullptr, nullptr);
}
}
}
However, I get output similar to the following:
Abort: 3fffac87c3b8
0x3fffac6e4bc0 <unknown>
function range: 3fffac6e4a70-3fffac6e4c30
0x3fffac6c9540 <unknown>
function range: 3fffac6c92f8-3fffac6c95a0
0x3fffaca9e338 <unknown>
function range: 3fffaca9e1f0-3fffaca9e434
0x3fffaca9a964 <unknown>
function range: 3fffaca9a940-3fffaca9a988
0x3fffaca9aa28 <unknown>
function range: 3fffaca9aa10-3fffaca9aa38
0x3fffaca9af18 <unknown>
function range: 3fffaca9aea0-3fffaca9af28
0x12af30a88 <unknown>
function range: 12af30a38-12af30a98
0x12af30af0 <unknown>
function range: 12af30a98-12af30b98
0x3fffac6c98c4 <unknown>
function range: 3fffac6c9770-3fffac6c9a34
0x3fffac6c9ae0 <unknown>
function range: 3fffac6c9a40-3fffac6c9aec
Now I know that the second frame from the top is the abort; however, none of the addresses match up.
If I debug with gdb, I get this:
[1
I have a few questions:
- Why is gdb instead of showing
__GI_abort
instead ofabort
as the function name? - How do I get the address of
__GI_abort
? I tried just swapping outabort
with it, but g++ is claiming that it isn't declared.
I'm trying to capture when a child executes an abort.
The following is a MCVE that should give an idea of what I'm trying to do.
#include <iostream>
#include <cstdio>
#include <iomanip> //to make things legible
#include <sys/ptrace.h>
#include <sys/wait.h>
#include <libunwind-ptrace.h>
#include <unistd.h>
#include <sys/types.h>
using namespace std;
int getBacktrace(pid_t pid)
{
int rv = 0;
unw_addr_space_t as = unw_create_addr_space(&_UPT_accessors, 0);
if(!as)
{
return rv;
}
void *context = _UPT_create(pid);
unw_cursor_t cursor;
if(unw_init_remote(&cursor, as, context) == 0)
{
cout << "Abort: " << std::hex << (long)*abort << endl;
do
{
unw_proc_info_t pi;
if(unw_get_proc_info(&cursor, &pi) >= 0)
{
if((long)pi.start_ip == (long)abort)
{
cout << "abort found!\n";
//do some recovery stuff here.so WIFEXITED won't work and WIFSIGNALED can give a false alarm
rv = 1;
break;
}
//Just for fun, let's print the backtrace
unw_word_t offset, pc;
char sym[4096];
if(unw_get_reg(&cursor, UNW_REG_IP, &pc) != 0)
{
cout << "Unknown PC\n";
}
else
{
cout << "0x" << std::hex << pc << " ";
}
if(unw_get_proc_name(&cursor, sym, sizeof(sym), &offset) != 0)
{
cout << "<unknown>\n";
}
else
{
cout << sym << "+0x" << std::hex << offset << endl;
}
cout << "\tfunction range: " << std::hex << pi.start_ip << "-" << pi.end_ip << endl;
}
}while(unw_step(&cursor) > 0);
cout << endl << endl; //Add spacing to make it easier to read.
}
if(context)
{
_UPT_destroy(context);
}
cout << std::dec;
return rv;
}
int childFunction()
{
//This is just an example function maybe it throws maybe it doesn't
sleep(5);
throw 42;
}
int main()
{
pid_t childPid;
if((childPid = fork()) == 0)
{
ptrace(PTRACE_TRACEME, 0, nullptr, nullptr);
//child
childFunction();
}
else
{
while(true)
{
waitpid(childPid, nullptr, 0);
if(getBacktrace(childPid))
{
//do some logging or functionality here
cout << "Child aborted\n";
break;
}
ptrace(PTRACE_CONT, childPid, nullptr, nullptr);
}
}
}
However, I get output similar to the following:
Abort: 3fffac87c3b8
0x3fffac6e4bc0 <unknown>
function range: 3fffac6e4a70-3fffac6e4c30
0x3fffac6c9540 <unknown>
function range: 3fffac6c92f8-3fffac6c95a0
0x3fffaca9e338 <unknown>
function range: 3fffaca9e1f0-3fffaca9e434
0x3fffaca9a964 <unknown>
function range: 3fffaca9a940-3fffaca9a988
0x3fffaca9aa28 <unknown>
function range: 3fffaca9aa10-3fffaca9aa38
0x3fffaca9af18 <unknown>
function range: 3fffaca9aea0-3fffaca9af28
0x12af30a88 <unknown>
function range: 12af30a38-12af30a98
0x12af30af0 <unknown>
function range: 12af30a98-12af30b98
0x3fffac6c98c4 <unknown>
function range: 3fffac6c9770-3fffac6c9a34
0x3fffac6c9ae0 <unknown>
function range: 3fffac6c9a40-3fffac6c9aec
Now I know that the second frame from the top is the abort; however, none of the addresses match up.
If I debug with gdb, I get this:
[1
I have a few questions:
- Why is gdb instead of showing
__GI_abort
instead ofabort
as the function name? - How do I get the address of
__GI_abort
? I tried just swapping outabort
with it, but g++ is claiming that it isn't declared.
1 Answer
Reset to default 0Why is gdb instead of showing __GI_abort instead of abort as the function name?
These are aliases of each other (note that they are at the same address):
readelf -Ws glibc-build/libc.so | grep 'abort$'
7155: 0000000000024ec0 116 FUNC LOCAL DEFAULT 15 __GI_abort
7947: 0000000000024ec0 116 FUNC GLOBAL DEFAULT 15 abort
You can't use the __GI_abort
symbol because it is local to libc.so.6
.
On my Linux x86_64
system your MCVE works, and I don't see anything immediately wrong with it.
$ ./a.out
terminate called after throwing an instance of 'int'
Abort: 7fb23783f41a
0x7fb2378a53ac pthread_key_delete+0x14c
function range: 7fb2378a52a0-7fb2378a53ea
0x7fb2378564f2 gsignal+0x12
function range: 7fb2378564e0-7fb237856511
abort found!
Child aborted