Jump to content


Photo

Show callstack in AHK window


  • Please log in to reply
9 replies to this topic

#1 fragman

fragman
  • Members
  • 1591 posts

Posted 30 July 2012 - 05:21 PM

I think it would be a good idea to display the callstack in the AHK debugging window. This is especially useful for scripts that make heavy use of OOP (for example, to see where an infinite loop of a container class happens). Easiest would probably be to add a new menu option to keep compatibility with scripts that use the menu to get a list of variables.

#2 fincs

fincs
  • Fellows
  • 1530 posts

Posted 30 July 2012 - 06:50 PM

You can use a DBGp-enabled editor (such as SciTE4AutoHotkey, see my signature) to debug your script, and view the callstack.
Link: SciTE4AutoHotkey debugging

#3 fragman

fragman
  • Members
  • 1591 posts

Posted 30 July 2012 - 09:02 PM

I know, but SciTE4AHK has various problems with it (such as not catching breakpoints) very often. The script in question is very large, ~30k lines. I haven't tried other dbgp editors such as Notepad++ yet, but the issue also lies elsewhere: Debugging with AHK requires that the script is started with the debugger and doesn't support attaching to a running AHK process. If you notice a problem while the script is running that is rare or difficult to reproduce it's rarely of any use.
In case of difficult to reproduce problems it's also important to halt the script at the current line and not at predefined breakpoints.

If a debugger could support these things reliably it would of course be the ideal solution, but I don't see AHK and the relevant editors there yet.

A simple callstack print in the AHK window would help very much for these cases. It might also be good to list the values of the local variables at the last executed line if possible.

#4 Lexikos

Lexikos
  • Administrators
  • 8845 posts

Posted 30 July 2012 - 10:12 PM

Adding support for attaching to a running AHK process should be fairly simple. It's just a matter of sending a message to an existing window instead of running a new script. Attaching halts at the current line and waits for initial commands. However, breaking at the current line while running won't be possible until I add "async" support.

You can use the following to attach the current script to any listening debugger:
F12::
DetectHiddenWindows On
PostMessage DllCall("RegisterWindowMessage", "str", "AHK_ATTACH_DEBUGGER"),,,, ahk_id %A_ScriptHwnd%
return
Tested okay on XDebugClient and Notepad++. XDebugClient didn't show the line pointer until I stepped one line, but it did work. You can detach Notepad++ by clicking the DBG button and sending detach -i whatever, but reattaching doesn't appear to work.

I'm more interested in improving the DBGp-based tools than adding new tools, but I will consider your suggestion.

#5 fragman

fragman
  • Members
  • 1591 posts

Posted 31 July 2012 - 07:59 AM

I just tried the two debuggers you mentioned but I could not get them to work properly with my script. XDebugClient seems to attach, but opens only the main script file and does not appear to break.
In Notepad++ I changed its settings to break at current line which worked, but a few seconds afterwards I got an error message from AHK that an internal error occured in the debugger engine. In Notepad++ the log looks like this:
Accept: 127.0.0.1
Recv: <?xml version="1.0" encoding="UTF-8"?><init appid="AutoHotkey" ide_key="" session="" thread="7420" parent="" language="AutoHotkey" protocol_version="1.0" fileuri="file:///D%3A/Projekte/Autohotkey/7plus/7plus.ahk"/>
Send: feature_set -i 1 -n max_depth -v 5
Send: feature_set -i 2 -n max_children -v 15
Send: feature_set -i 3 -n max_data -v 512
Send: breakpoint_list -i 4
Send: step_into -i 5
----
Recv: <?xml version="1.0" encoding="UTF-8"?><response command="feature_set" feature="max_depth" success="1" transaction_id="1"/>
Recv: <?xml version="1.0" encoding="UTF-8"?><response command="feature_set" feature="max_children" success="1" transaction_id="2"/>
Recv: <?xml version="1.0" encoding="UTF-8"?><response command="feature_set" feature="max_data" success="1" transaction_id="3"/>
Recv: <?xml version="1.0" encoding="UTF-8"?><response command="breakpoint_list" transaction_id="4"></response>
Recv: <?xml version="1.0" encoding="UTF-8"?><response command="step_into" status="break" reason="ok" transaction_id="5"/>
Send: stack_get -i 6
Send: breakpoint_list -i 7
Send: context_get -i 8 -c 0
Send: context_get -i 9 -c 1
----
Recv: <?xml version="1.0" encoding="UTF-8"?><response command="stack_get" transaction_id="6"><stack level="0" type="file" filename="file:///D%3A/Projekte/Autohotkey/7plus/MessageHooks.ahk" lineno="4" where="HookProc()"/></response>
Recv: <?xml version="1.0" encoding="UTF-8"?><response command="breakpoint_list" transaction_id="7"></response>
Recv: <?xml version="1.0" encoding="UTF-8"?><response command="context_get" context="0" transaction_id="8"><property name="dwEventThread" fullname="dwEventThread" type="integer" facet="" children="0" encoding="base64" size="4">MTIyNA==</property><property name="dwmsEventTime" fullname="dwmsEventTime" type="integer" facet="" children="0" encoding="base64" size="8">Njg5MTY1MzE=</property><property name="event" fullname="event" type="integer" facet="" children="0" encoding="base64" size="5">MzI3Nzg=</property><property name="hWinEventHook" fullname="hWinEventHook" type="integer" facet="" children="0" encoding="base64" size="9">MjA4NDA3NTUz</property><property name="hwnd" fullname="hwnd" type="integer" facet="" children="0" encoding="base64" size="7">Mjk1MDMwNA==</property><property name="idChild" fullname="idChild" type="integer" facet="" children="0" encoding="base64" size="1">MA==</property><property name="idObject" fullname="idObject" type="integer" facet="" children="0" encoding="base64" size="1">MA==</property><property name="state" fullname="state" type="undefined" facet="" children="0" encoding="base64" size="0"></property><property name="style" fullname="style" type="undefined" facet="" children="0" encoding="base64" size="0"></property><property name="Trigger" fullname="Trigger" type="undefined" facet="" children="0" encoding="base64" size="0"></property></response>
----
Disconnect: 127.0.0.1
I tried to disable the shell hook callbacks and it stopped in a timer where the same thing happened. I also tried to disable the AutoExecute section of my script to skip as much code of it as possible but with same results. It then halted during an evaluation of an #if condition and showed the error again.

Using a simple test script like the following works fine though:
x := 1
while(true)
{
	x++
	sleep 1000
}
#y::
DetectHiddenWindows On
PostMessage DllCall("RegisterWindowMessage", "str", "AHK_ATTACH_DEBUGGER"),,,, ahk_id %A_ScriptHwnd%
return
If you want to use my script for testing purposes, you can get it at <!-- m -->http://chriss85.bpla... ... Source.zip<!-- m --> (run 7plus.ahk)
To avoid changes to your system you should run it with the "-portable" command line argument. It should only write to %Temp%\7plus then and revert all changes on exit.

#6 Lexikos

Lexikos
  • Administrators
  • 8845 posts

Posted 01 August 2012 - 08:21 AM

XDebugClient seems to attach, but opens only the main script file and does not appear to break.

That's why I said "XDebugClient didn't show the line pointer until I stepped one line". More precisely, it doesn't retrieve the call stack (including the current line pointer) until it receives a response to a continuation command, which means you need to send a continuation command (run or step).

If the script is idling (i.e. no threads are running when you attach), you'll need to step_into anyway.

In Notepad++ I changed its settings to break at current line which worked,

I think that the DBGp plugin sends step_into if that option is enabled or run if it is not.

but a few seconds afterwards I got an error message from AHK that an internal error occured in the debugger engine.

Sorry, you found a bug in the debugger engine: the property depth limit is ignored in certain cases. To work around it, open the DBGp config and set "Maximum depth of elements" to twice the limit you want, and if using the "Watches" pane, only add variables and not objects (CTrigger is okay, CTrigger.Categories is not).

The debugger crashes with your script (when the depth limit is ignored) because of circular references like CTrigger.Categories.7plus.1.base -> CTrigger.


I just remembered that scripts can retrieve the call stack by calling Exception() repeatedly. See [AHK_L] How to get CallStack - solution. It's unlikely that any ListLines-style built-in feature would provide any more information than this.

#7 fragman

fragman
  • Members
  • 1591 posts

Posted 01 August 2012 - 09:24 AM

In what cases is the depth limit ignored? Is there any way to work around it? I tried using large values (see here: <!-- m -->http://i.imgur.com/Zj7he.png<!-- m --> ) and it still happens. I have not been using the Watches pane as the error occurs two or three seconds after debugging already. Before I had low values (Max depth: 5, Number of child elements: 15) when the issue occured.

I knew about the Exception-callstack method, but I thought it would need to be used at the place of code in question. After trying it however, I saw that the new pseudo thread from a hotkey is simply placed on top of the stack so it might work out.

#8 Lexikos

Lexikos
  • Administrators
  • 8845 posts

Posted 02 August 2012 - 10:22 PM

Picture your script's variables and objects as a tree, where each object branches out. If even one object has a circular reference, this tree has infinite depth. If more than one circular reference, each step deeper may increase the number of nodes exponentially. The entire tree in XML form must fit into the debugger's response buffer. Even 20 is too deep for your script; I tested, got impatient and stopped it at this property (RAM usage was at ~300MB):

C7plusStartTrigger.base.Categories.7plus.1.base.Categories.System.3.base.Categories.Hotkeys.3.base.Categories.Hotkeys.1.base.base.base

Maybe that gives you an idea of how much branching there is: each type of trigger leads to Categories, and each category leads back to Categories.

This setting limits the amount of nesting in a single query. Note that the debugger client may opt to expand further by re-querying a child property. XDebugClient does this, but Notepad++ does not. However, you can add something like Var.x.y[42].z to the watch list to drill deeper. (This is a subset of expression syntax, not an expression.)

With a limit of 5, the debugger engine takes maybe a second or two to return all global variables, but Notepad++ takes much longer and a lot of RAM to populate its display.

I'm having trouble with autohotkey.net, but you can get v1.1.08.01 here:
dropbox/AutoHotkey_L_Install.exe
The only change is a fix for this bug.

Before I had low values (Max depth: 5, Number of child elements: 15) when the issue occured.

There are two reasons that I said to use "twice the limit":
[*:1ouf8t1v]Each nesting level was counted twice toward the depth.
[*:1ouf8t1v]If the remaining depth is 1 and you subtract 2, the depth is now -1, and the limit no longer applies. Therefore any even number will be okay. Twice any whole number is always an even number.
The exception was that if you query an object (x.y) directly, the first level is counted once toward the depth, so the limit must be odd...

#9 fragman

fragman
  • Members
  • 1591 posts

Posted 03 August 2012 - 06:13 AM

Ah, it seems I underestimated the size of the variables, didn't thought it would be as problematic because I already tested with a depth of 5 which didn't work too well (I also assumed that Notepad++ was hanging completely). Using a depth of 2 works but is rather slow. I'll try to get in contact with the author of the dbgp plugin and see if he can add dynamic re-querying of child properties. This might even speed it up a little when there isn't too much data that needs to be transferred on each refresh.

#10 fragman

fragman
  • Members
  • 1591 posts

Posted 09 August 2012 - 08:38 AM

I talked to the developer of the Notepad++ dbgp plugin and he updated it to use dynamic inspection of objects and will release an update soon.