The Croc Programming Language
Debugging

Functions

void croc_debug_setHookFunc (CrocThread *t, uword_t mask, uword_t hookDelay)
 
word_t croc_debug_pushHookFunc (CrocThread *t)
 
uword_t croc_debug_getHookMask (CrocThread *t)
 
uword_t croc_debug_getHookDelay (CrocThread *t)
 
void croc_debug_printStack (CrocThread *t)
 
void croc_debug_printWholeStack (CrocThread *t)
 
void croc_debug_printCallStack (CrocThread *t)
 

Detailed Description

Debugging.

Function Documentation

void croc_debug_setHookFunc ( CrocThread t,
uword_t  mask,
uword_t  hookDelay 
)

Sets the thread's hook function, which is a special function called at certain points during program execution which allows you to trace execution and inspect the internals of the program as it runs.

This can be used to make a debugger.

This expects the hook function to be on top of the stack. It can be either a function closure or null to remove the hook function instead. The hook function is popped.

There are four places the hook function can be called:

  • When any function is called, right after its stack frame has been set up, but before the function begins execution;
  • When any function returns, right after the last instruction has executed, but before its stack frame is torn down;
  • At a new line of source code;
  • After every n bytecode instructions have been executed.

There is only one hook function, and it will be called for any combination of these events that you specify; it's up to the hook function to see what kind of event it is and respond appropriately.

This hook function (as well as the mask and delay) is inherited by any new threads which the given thread creates after the hook was set.

While the hook function is being run, no hooks will be called (obviously, or else it would result in infinite recursion). When the hook function returns, execution will resume as normal until the hook function is called again.

You cannot yield from within the hook function.

The hook function
When the hook function is called, the thread being hooked will be passed as this (since you could possibly set the same hook function to multiple threads) and the type of the hook event will be a string, its only parameter. This string can be one of the following values:
  • "call" for normal function calls.
  • "tailcall" which is the same as "call" except there will not be a corresponding "return" when this function returns (or more precisely, the previously called function will not have a "return" event).
  • "return" for when a function is about to return.
  • "line" for when execution reaches a new line of source code.
  • "delay" for when a certain number of bytecode instructions have been executed.
Parameters
maskcontrols which of the following events the hook function will be called for. It should be an or-ing together of the CrocThreadHook enum values. Note that if you use either one of CrocThreadHook_Call or CrocThreadHook_TailCall, you will get both kinds of call events. Also, the CrocThreadHook_Delay flag isn't controlled by this mask, but by the hookDelay parameter.

If this parameter is 0, the hook function is removed from the thread.
hookDelaycontrols whether or not the hook function will be called for "delay" events. If this parameter is 0, it won't be. Otherwise, it indicates how often the "delay" hook event will occur. A value of 1 means it will occur after every bytecode instruction; a value of 2 means every other instruction, and so on.
word_t croc_debug_pushHookFunc ( CrocThread t)

Pushes the given thread's hook function onto its stack, or null if none is set on that thread.

uword_t croc_debug_getHookMask ( CrocThread t)

Gets the hook mask of the given thread (like was set with croc_debug_setHookFunc), or 0 if there is no hook set on that thread.

uword_t croc_debug_getHookDelay ( CrocThread t)

Gets the hook delay of the given thread (like was set with croc_debug_setHookFunc), or 0 if there is no delay hook on that thread.

void croc_debug_printStack ( CrocThread t)

Prints out the contents of the current function's stack frame to standard output in the following format:

[xxx:yyyy] val: type

Where xxx is the absolute stack index (within the thread's entire stack), yyyy is the stack index relative to the current function's stack frame, val is a raw string representation of the value, and type is its type.

void croc_debug_printWholeStack ( CrocThread t)

Same as croc_debug_printStack, but prints the thread's whole stack, for all stack frames.

In this case the relative stack indexes can be negative, which means that the slot is in a previous stack frame.

void croc_debug_printCallStack ( CrocThread t)

Prints out the thread's call stack to standard output in reverse, starting with the currently-executing function, in the following format:

Record <name>:
    Base: <base>
    Saved top: <top>
    Vararg base: <vargBase>
    Return slot: <retSlot>
    Expected results: <numResults>

Where name is the name of the function at that level (or ??? if there is no function at that level); base is the absolute stack index where this activation record's stack frame begins; top is the absolute stack index of the end of its stack frame (which may and often does overlap the next frame); vargBase is the absolute stack index of where its variadic arguments, if any, begin; retSlot is the absolute stack index where its return values will be copied upon returning to the calling function; and numResults is the number of results the calling function is expecting it to return (or -1 for "all of them").

This only prints the current thread's call stack; it does not cross thread resume boundaries.