IBM Support

PROBEVUE: SIGACTION() [WHO CHANGED MY SIGNAL HANDLER?]

Technical Blog Post


Abstract

PROBEVUE: SIGACTION() [WHO CHANGED MY SIGNAL HANDLER?]

Body

This small script will track calls to 'sigaction()' for a given signal
and executable. This might become useful when a program does not react
as expected when receiving a signal. This might be because somewhere
along the way, something might have reset the signal disposition using
a call to 'sigaction()'.

 

Since such call can be also performed from an external API loaded
via a dynamic library, this script will catch as well the 'dlopen()'
and 'dlclose()'. Also it will print the address at which the 'text' and
'data' sections for the loaded object are located in the process memory.
This will help put function names in front of the stack traces dumped
by the script.

 

The script should be executed like this as root:

 

  probevue -t 10 -e 75 -s 64 -o sigaction2.out sigaction2.pb

 

The output will look like this:

 

  0x0002edd1d5a6620f [ ExecCCommand - 28966926 - 17236451 - 17957030 ]execve( [db2rocm] [1] [DB2] [db2sbx] [3] [MONITOR] )
  0x0002edd1d615e61f [ db2rocm - 28966926 - 17236451 - 17957030 ]  kload(/usr/lib/nls/loc//en_US__64) [t 0x090000000046e000 - d 0x0900000000473200]
  0x0002edd1d6173b00 [ db2rocm - 28966926 - 17236451 - 17957030 ]  kload(libi18n.a(shr_64.o)) [t 0x0900000000477980 - d 0x09001000a3aca000]
  0x0002edd1d655ee03 [ db2rocm - 28966926 - 17236451 - 17957030 ] sigaction(15, 0x0000000110082b38) = 0
  0x1000002f8
  0x100003120
  0x1000009d0
  0x10000711c
  0x900000004ad4660
  0x900000004ad3228

 

Note that the signal number tracked here is 15 and we track any executable
named 'db2rocm'. This can be changed in the script filters below to fit your needs.

 

The script is like this:


/*
 * sigaction2.pb: Track signal settings for a given program. This will track
 *                calls to 'sigaction()' for a given signal and executable.
 *                Also, it will dump a stack (address only) for each call that
 *                is caught. To reconstruct the stack trace with symbols it
 *                will not only catch kload/kunload calls but provide as well
 *                the address at which TEXT and DATA sections are loaded for
 *                the object loaded by dlopen().
 *
 * Run as user 'root' using the following command line:
 *
 *     probevue -t 10 -e 75 -s 64 -o sigaction2.out sigaction2.pb
 *
 * To modify the number of threads that can be traced:
 *
 *     probevctrl -c "num_threads_traced=2048"
 *
 * To modify the per cpu buffer size:
 *
 *     probevctrl -c "default_buffer_size=64"
 *
 * To modify the maximum amount of memory used by probevue:
 *
 *     probevctrl -c "max_total_mem_size=256"
 *
 * To modify the default read rate
 *
 *     probevctrl -c "default_read_rate=10"
 *
 * dalla
 */

 

/*
 * Used to track sigaction() arguments.
 */
typedef struct {
    long long    ss_set[4];
} sigset64_t;

typedef struct sigaction {
    void        *sa_sigaction;
    sigset64_t   sa_mask;
    int          sa_flags;
} sigaction_t;


/*
 * Used for manual stack unwind.
 */
typedef struct ld_info {
    long long    fields[4];
    void        *ldinfo_textorg;
    long long    ldinfo_textsize;
    void        *ldinfo_dataorg;
    long long    ldinfo_datasize;
} ld_info_t;

 

/*
 * Function prototypes (at least what we need).
 */
int              sigaction(int, sigaction_t *);
void            *kload(char *);
int              execve(char *, char *);

 

/*
 * For sigaction probes.
 */
__thread int                 in_sigaction;
__thread int                 sigaction_sig;
__thread void               *sigaction_handler;


/*
 * Restrict probe to only SIGTERM (15) and 'db2rocm' executable.
 */
@@syscall:*:sigaction:entry
when ((__arg1 == 15) && (__pname == "db2rocm"))
{
    __auto sigaction_t new;

    thread:in_sigaction = 1;
    thread:sigaction_sig = __arg1;

    if (__arg2) {
        copy_userdata(__arg2, new);
        thread:sigaction_handler = new.sa_sigaction;
    } else {
        thread:sigaction_handler = 0;
    }
}

@@syscall:*:sigaction:exit
when (thread:in_sigaction == 1)
{
    thread:in_sigaction = 0;

    printf("[ %s - %ld - %ld - %ld ] sigaction(%d, 0x%016llx) = %d\n",
           __pname, __pid, __tid, __ppid,
           thread:sigaction_sig, thread:sigaction_handler, __rv);

    /*
     * Collect a stack trace. Only addresses as this simply doesn't
     * work properly if symbols are requested (PRINT_SYMBOLS).
     * Eventually a raw stack dump in hex can be requested bu adding the
     * following piece of code:
     *
     * String        stackdump[4096];
     *
     * copy_userdata(__mst->r1, stackdump);
     * trace(stackdump);
     */
    stktrace(GET_USER_TRACE, 20);
}


/*
 * Add a probe for loading dynamic libraries. This would be useful
 * for matching stack addresses with symbols.
 */
@@syscallx:*:kload:entry
when (__pname == "db2rocm")
{
    thread:libname = __arg1;
    thread:in_kload = 1;
}

@@syscallx:*:kload:exit
when ((thread:in_kload == 1) && (__rv != (void *) 0))
{
    __auto String       pathname[256];
    __auto ld_info_t    ldinfo;

    pathname = get_userstring(thread:libname, 255);

    copy_userdata(__rv, ldinfo);

    printf("[ %s - %ld - %ld - %ld ]  kload(%s) [t 0x%016llx - d 0x%016llx]\n",
           __pname, __pid, __tid, __ppid, pathname,
           ldinfo.ldinfo_textorg, ldinfo.ldinfo_dataorg);

    thread:in_kload = 0;
}


/*
 * Handle 'execve()' probes so that we can match our 'db2rocm'.
 */
@@syscall:*:execve:entry
{
    __auto String               buf[256];
    __auto long long           *addr[8];
    __auto long long           *ptr;


    buf = get_userstring((void *) __arg1, -1);

    if (strstr(buf, "db2rocm")) {
        copy_userdata(__arg2, addr);
        ptr = (long long *) addr[0];

        buf = get_userstring(ptr, 256);
        if (buf == "db2rocm") {
            printf("[ %s - %ld - %ld - %ld ] execve(",
                   __pname, __pid, __tid, __ppid);

            if (ptr) { /* av[0] */
                printf(" [%s]", buf);

                ptr = (long long *) addr[1];
                if (ptr) { /* av[1] */
                    buf = get_userstring(ptr, 256);
                    printf(" [%s]", buf);

                    ptr = (long long *) addr[2];
                    if (ptr) { /* av[2] */
                        buf = get_userstring(ptr, 256);
                        printf(" [%s]", buf);

                        ptr = (long long *) addr[3];
                        if (ptr) { /* av[3] */
                            buf = get_userstring(ptr, 256);
                            printf(" [%s]", buf);

                            ptr = (long long *) addr[4];
                            if (ptr) { /* av[4] */
                                buf = get_userstring(ptr, 256);
                                printf(" [%s]", buf);

                                ptr = (long long *) addr[5];
                                if (ptr) { /* av[5] */
                                    buf = get_userstring(ptr, 256);
                                    printf(" [%s]", buf);

                                    ptr = (long long *) addr[6];
                                    if (ptr) { /* av[6] */
                                        buf = get_userstring(ptr, 256);
                                        printf(" [%s]", buf);
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }

        printf(" )\n");
    }
}

[{"Business Unit":{"code":"BU058","label":"IBM Infrastructure w\/TPS"},"Product":{"code":"SSEPGG","label":"Db2 for Linux, UNIX and Windows"},"Component":"","Platform":[{"code":"PF025","label":"Platform Independent"}],"Version":"","Edition":"","Line of Business":{"code":"LOB10","label":"Data and AI"}}]

UID

ibm13286269