views:

123

answers:

3

Hi! Does anybody know of a better/ faster way to get the call stack than "StackWalk"? I also think that stackwalk can also be slower on methods with a lot of variables... (I wonder what commercial profilers do?) I'm using C++ on windows. :) thanks :)

A: 

I don't know if it's faster, and it won't show you any symbols, and I'm sure you can do better than that, but this is some code I wrote a while back when I needed this info (only works for Windows):

struct CallStackItem
{
    void* pc;
    CallStackItem* next;

    CallStackItem()
    {
        pc = NULL;
        next = NULL;
    }
};

typedef void* CallStackHandle;

CallStackHandle CreateCurrentCallStack(int nLevels)
{
    void** ppCurrent = NULL;

    // Get the current saved stack pointer (saved by the compiler on the function prefix).
    __asm { mov ppCurrent, ebp };

    // Don't limit if nLevels is not positive
    if (nLevels <= 0)
        nLevels = 1000000;

    // ebp points to the old call stack, where the first two items look like this:
    // ebp -> [0] Previous ebp
    //        [1] previous program counter
    CallStackItem* pResult = new CallStackItem;
    CallStackItem* pCurItem = pResult;
    int nCurLevel = 0;

    // We need to read two pointers from the stack
    int nRequiredMemorySize = sizeof(void*) * 2;
    while (nCurLevel < nLevels && ppCurrent && !IsBadReadPtr(ppCurrent, nRequiredMemorySize))
    {
        // Keep the previous program counter (where the function will return to)
        pCurItem->pc = ppCurrent[1];
        pCurItem->next = new CallStackItem;

        // Go the the previously kept ebp
        ppCurrent = (void**)*ppCurrent;
        pCurItem = pCurItem->next;
        ++nCurLevel;
    }

    return pResult;
}

void PrintCallStack(CallStackHandle hCallStack)
{
    CallStackItem* pCurItem = (CallStackItem*)hCallStack;
    printf("----- Call stack start -----\n");
    while (pCurItem)
    {
        printf("0x%08x\n", pCurItem->pc);
        pCurItem = pCurItem->next;
    }
    printf("-----  Call stack end  -----\n");
}

void ReleaseCallStack(CallStackHandle hCallStack)
{
    CallStackItem* pCurItem = (CallStackItem*)hCallStack;
    CallStackItem* pPrevItem;
    while (pCurItem)
    {
        pPrevItem = pCurItem;
        pCurItem = pCurItem->next;
        delete pPrevItem;
    }
}
Asaf
+1  A: 

Check out http://msdn.microsoft.com/en-us/library/bb204633%28VS.85%29.aspx - this is "CaptureStackBackTrace", although it's called as "RtlCaptureStackBackTrace".

Damyan
A: 

Ok, thanks :) It's supposed to be faster because I'm looking at another process' stack and I'm guessing that StackWalk uses ReadProcessMemory every call instead of just once.

Idov