1

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:

[gdb of above program. Notably showing p abort with an address that matches above1

I have a few questions:

  1. Why is gdb instead of showing __GI_abort instead of abort as the function name?
  2. How do I get the address of __GI_abort? I tried just swapping out abort with it, but g++ is claiming that it isn't declared.

1 Answer 1

0

Why 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
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.