Backtracing a thread in another process

Updated: October 26, 2022

Use the following sample code to repeatedly backtrace a thread in another process by using the remote process's pid and thread tid:

#include <stdio.h>
#include <backtrace.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>

int main(int argc, char *argv[])
{
    char out[1024];
    bt_addr_t pc[16];
    bt_accessor_t acc;
    int remotepid = -1;
    int remotetid = -1;
    char opt;
    bt_memmap_t memmap;

    while((opt = getopt(argc, argv, "p:t:")) != -1)
    {
        switch(opt) {
        case 'p':
            remotepid = strtol(optarg, 0, 0);
            break;
        case 't':
            remotetid = strtol(optarg, 0, 0);
            break;
        default:
            exit(EXIT_FAILURE);
        }
    }

    if ((remotepid == -1) || (remotetid == -1)) {
        fprintf(stderr, "Invalid parameters. Use -p <pid> -t <tid>\n");
        exit(EXIT_FAILURE);
    }

    if (bt_init_accessor( &acc, BT_PROCESS, remotepid, remotetid) == -1)
    {
        fprintf(stderr, "%s:%i %s (%i)%s\n", __FUNCTION__, __LINE__,
                "bt_init_accessor", errno, strerror(errno));
		return EXIT_FAILURE;
    }

    if (bt_load_memmap( &acc, &memmap ) ==-1)
    {
        fprintf( stderr, "%s:%i %s (%i)%s\n", __FUNCTION__, __LINE__,
                 "bt_load_memmap", errno, strerror(errno));
        return EXIT_FAILURE;
    }

    if (bt_sprn_memmap(&memmap, out, sizeof(out)) == -1)
    {
        fprintf( stderr, "%s:%i %s (%i)%s\n", __FUNCTION__, __LINE__,
                 "bt_sprn_memmap", errno, strerror(errno));
        return EXIT_FAILURE;
    }

    /* Make sure that the string is null-terminated. */
    out[sizeof(out) - 1] = '\0';
    puts (out);

    for (int i=0; i < 10; i++)
    {
        int count = bt_get_backtrace( &acc, pc, sizeof(pc) / sizeof(bt_addr_t));
        int w = 0;
        while (count > 0)
        {
            w = bt_sprnf_addrs(&memmap, pc + w, count, "%a\n", out, sizeof(out), 0);
            if (w == -1)
            {
                fprintf( stderr, "%s:%i %s (%i)%s\n", __FUNCTION__, __LINE__,
                         "bt_sprnf_addrs", errno, strerror(errno));
                return EXIT_FAILURE;
            }
            count -= w;
            puts (out);
        }
    }

    bt_unload_memmap( &memmap );

    if (bt_release_accessor( &acc ) == -1)
    {
        fprintf( stderr, "%s:%i %s (%i)%s\n", __FUNCTION__, __LINE__,
                 "bt_release_accessor", errno, strerror(errno));
        return EXIT_FAILURE;
    }
}