Game Development Community

dev|Pro Game Development Curriculum

Script callstack dumping

by Peter Simard · 08/25/2008 (7:20 am) · 4 comments

This resource will allow you to dump to your console the current call stack for Torque Script. This is very handy if you want to determine how a function is being called, without causing the program to break.

Insert this code at the end of console/telnetDebugger.cc:
void writeStack()
{
   const U32 MaxCommandSize = 2048;
   char buffer[MaxCommandSize];
   char scope[MaxCommandSize];

   S32 last = 0;

	for(S32 i = (S32) gEvalState.stack.size() - 1; i >= last; i--)
   {
      CodeBlock *code = gEvalState.stack[i]->code;
      const char *file = "<none>";
      if (code && code->name && code->name[0])
         file = code->name;

      Namespace *ns = gEvalState.stack[i]->scopeNamespace;
      scope[0] = 0;
      if ( ns ) {
         
         if ( ns->mParent && ns->mParent->mPackage && ns->mParent->mPackage[0] ) {
            dStrcat( scope, ns->mParent->mPackage );
            dStrcat( scope, "::" );
         }
         if ( ns->mName && ns->mName[0] ) {
            dStrcat( scope, ns->mName );
            dStrcat( scope, "::" );
         }
      }

      const char *function = gEvalState.stack[i]->scopeName;
      if ((!function) || (!function[0]))
         function = "<none>";
      dStrcat( scope, function );

      U32 line=0, inst;
      U32 ip = gEvalState.stack[i]->ip;
      if (code)
      code->findBreakLine(ip, line, inst);
      dSprintf(buffer, MaxCommandSize, " %s %d %s", file, line, scope);
      Con::printf(buffer);
   }
}


ConsoleFunction( writeStack, void, 1, 1, "" )
{
	writeStack();
}

Then, anywhere you want to see the current callstack, add this code to the top of the function:
writeStack();

That's it!

#1
08/25/2008 (11:07 am)
How is this different from "backtrace();"?
#2
08/25/2008 (9:19 pm)
HOLLY CRAPOLA!! trace() and backtrace() are incredible! Thank you Peter for your work, if wasnt for this I would never know about those fantastic gems.
#3
08/25/2008 (9:20 pm)
Doh! backtace() does exactly what I made this for.
#4
08/25/2008 (10:26 pm)
a related nifty thing we did was keep track of the script callstack for every simobject allocation and deallocation, which makes it super easy to track down sim object leaks: you can dump the results and see "aha: we're leaking 1000s of HTTP Objects or whatever through callchain x()->y()->z(). it's implemented as an [stl] hashmap per simobject class where the key is the script callstack and the value is the number of outstanding allocations. it's important to track the entire callstack rather than just the immediate caller because often z() may be coded correctly but called from many different places, and the real culprit is x(). we currently only enable it in certain builds, but it may be performant enough to just leave on.