How to get backtrace of function only once?

47 views Asked by At

I'm trying to modify DebugInfo/app_backtrace.cpp to print the unique backtraces(call stacks) of a specific function.

Currently(if I understand it correctly), this client prints the backtrace every time the function is called. In the case I'm looking at, the function is called in a loop, inside a function in another loop, and therefore it prints the backtraces seemingly infinitely.

How can I get it to print the backtraces?

I'm including the code in case it is helpful:

void qux_Before(const CONTEXT* ctxt)
{
    void* buf[128];
    PIN_LockClient();
    int nptrs = PIN_Backtrace(ctxt, buf, sizeof(buf) / sizeof(buf[0]));
    ASSERTX(nptrs > 0);
    char** bt = backtrace_symbols(buf, nptrs);
    PIN_UnlockClient();
    ASSERTX(NULL != bt);
    for (int i = 0; i < nptrs; i++)
    {
#ifdef TARGET_MAC
        if (*bt[i] == '_')
        {
            // Demangle the C function name
            bt[i]++;
        }
#endif
        cout << bt[i] << endl;
    }
    free(bt);
}

void InstImage(IMG img, void* v)
{
    if (IMG_IsMainExecutable(img))
    {
        RTN rtn = RTN_FindByName(img, C_MANGLE("qux"));
        ASSERTX(RTN_Valid(rtn));
        RTN_Open(rtn);
        RTN_InsertCall(rtn, IPOINT_BEFORE, (AFUNPTR)qux_Before, IARG_CONST_CONTEXT, IARG_END);
        RTN_Close(rtn);
    }
}

int main(int argc, char** argv)
{
    PIN_InitSymbols();

    if (PIN_Init(argc, argv))
    {
        cerr << "usage..." << endl;
        return EXIT_FAILURE;
    }

    IMG_AddInstrumentFunction(InstImage, 0);

    PIN_StartProgram();
    return EXIT_FAILURE;
}
1

There are 1 answers

0
Jonyleo On

As far as I'm aware, PIN doesn't offer that functionality, however, you can implement it.

Just store the backtrace, and only print it if it's a new one.

For performance reasons, I would store backtraces as pointers and not as the symbols.

Example (Not the only way):

// global variable
std::set<std::vector<void*>> found_traces;

void qux_Before(const CONTEXT* ctxt)
{
    void* buf[128];
    PIN_LockClient();
    int nptrs = PIN_Backtrace(ctxt, buf, sizeof(buf) / sizeof(buf[0]));
    ASSERTX(nptrs > 0);

    // Add this here
    std::vector<void *> trace(buf, buf + nptrs);
    
    // insert returns a pair, second is a bool that is true if the element was inserted
    // i.e: if it wasn't inserted, we found it previously, therefore there is no need to print
    if (!found_traces.insert(trace).second)
        return;
 
    // continue the rest of the code