How to get detail information from the callstack
by
, 24-Aug-2009 at 07:30 AM (4657 Views)
Recently I received a support call from a developer who was very pleased with the fact that the product now has a command to return the current callstack. He said however it is one string and I would like to retrieve detailed information from the callstack. I told the developer to look at string manipulation functions and that made him not so happy. The amount of work was high he thought.
Because I said it is not so difficult he challenged me to make a function that makes it easier to digest information from the callstack dump.
I started to examine the result of the command CallStackDump. The following is an example;
It contains a CR/LF pair for each line in the stack. This means we can iterate the callstack by searching for the CR/LF combination. Each stack line contains the message name, the line number, the object name, the object handle and the address where the instruction started. The address only when the message is not inside the virtual machine. The initiating callstack line is always "[start] - at address NNN".Code:GET_GETCALLSTACK (8853) - OSYSTEM_LAST_COMPANY_ID (349) - at address 52034 MSG_SHOWSTACK (8854) - OSYSTEM_LAST_COMPANY_ID (349) - at address 52092 MSG_PROCESS_ACCELERATOR (455) - OSYSTEM_LAST_COMPANY_ID (349) - in native code [start] - at address 52131
Because of the structured information I created a struct with the following definition.
In the following function an array variable of this struct is created to store the determined information. Via string manipulation functions as Pos, Left, Right information is retrieved and stored in the struct members of an array element.Code:Struct tCallStack String sMessage UInteger uiLine String sObjectName Handle hObject Handle hAddress String sStackLine End_Struct
Now we have two ways to use the call stack in a Visual DataFlex program, a string based dump and an array.Code:Function GetCallStack Returns tCallStack[] String sStack sTmpStackLine sChar sAddress tCallStack[] CallStackInfo Integer iPos iElement iLength CallStackDump sStack While (sStack <> "") Move (Pos (Character (13) + Character (10), sStack)) to iPos If (iPos > 0) Begin Move (SizeOfArray (CallStackInfo)) to iElement Move (Left (sStack, iPos - 1)) to sTmpStackLine Move (Right (sStack, Length (sStack) - iPos - 1)) to sStack Move sTmpStackLine to CallStackInfo[iElement].sStackLine Move (Pos ('(', sTmpStackLine)) to iPos If (iPos > 0) Begin Move (Left (sTmpStackLine, iPos - 1)) to CallStackInfo[iElement].sMessage Move (Right (sTmpStackLine, Length (sTmpStackLine) - iPos)) to sTmpStackLine Move (Pos (')', sTmpStackLine)) to iPos If (iPos > 0) Begin Move (Left (sTmpStackLine, iPos - 1)) to CallStackInfo[iElement].uiLine Move (Right (sTmpStackLine, Length (sTmpStackLine) - iPos)) to sTmpStackLine Move (Replace (' - ', sTmpStackLine, '')) to sTmpStackLine Move (Pos ('(', sTmpStackLine)) to iPos If (iPos > 0) Begin Move (Left (sTmpStackLine, iPos - 1)) to CallStackInfo[iElement].sObjectName Move (Right (sTmpStackLine, Length (sTmpStackLine) - iPos)) to sTmpStackLine Move (Pos (')', sTmpStackLine)) to iPos If (iPos > 0) Begin Move (Left (sTmpStackLine, iPos - 1)) to CallStackInfo[iElement].hObject Move (Right (sTmpStackLine, Length (sTmpStackLine) - iPos)) to sTmpStackLine Move (Replace (' - ', sTmpStackLine, '')) to sTmpStackLine Move (Length (sTmpStackLine)) to iLength Move '' to sAddress For iPos from 1 to iLength Move (Mid (sTmpStackLine, 1, iPos)) to sChar If ('0123456789' contains sChar) Begin Move (sAddress - sChar) to sAddress End Loop Move sAddress to CallStackInfo[iElement].hAddress End End End End End Else Begin Move sStack to CallStackInfo[SizeOfArray (CallStackInfo)].sStackLine Move "" to sStack End Loop Function_Return CallStackInfo End_Function