Skip to content
Zwetan Kjukov edited this page Aug 2, 2016 · 10 revisions

Debug

Everything you can use to debug ActionScript 3 programs.

Runtime

Introduction

Your AS3 source code is first compiled to bytecode (ActionScript Byte Code or ABC).

When you run a SWF file, the runtime read the file and goes trough a serie of tags, when it encounter a tag of type doABC the runtime then execute that bytecode.

A SWF file can contains one or many doABC tags.

A runtime is based on the ActionScript Virtual Machine 2 (AVM2).

The Adobe® ActionScript™ Virtual Machine 2, or AVM2 for short,
was designed to execute programs written in the ActionScript 3.0 language.
ActionScript 3.0 is based on ECMAScript, the international standardized
programming language for scripting. ActionScript 3.0 is compliant with
the ECMAScript Language Specification, Third Edition (ECMA-262).
It also contains functionality based on ongoing work on ECMAScript Edition 4,
occurring within the Ecma International standards body

You can encounter different types of runtimes based on AVM2

  • Adobe Flash Player
  • Adobe AIR
  • Redtamarin

An hybrid system

In the ActionScript 3 Specification, the chapter 2.4 Choosing between reliability and flexibility we can see that AS3 has been based on ECMAScript (3rd edition) and adopted a dual philosophy

  • flexible
    the standard language
  • reliable
    the strict language

The strict language is a subset of the standard language and has three kinds of constraints:

  • Expressions have static types and type errors are verification errors
  • Common programming errors are caught by additional verification rules
  • Verification errors are reported ahead-of-time

Which give us Run-Time Errors by default.

Even if you compile in non-strict mode, disable all the warnings, etc. as soon as your AS3 program run you can encounter those runtime errors telling you something is not right.

Trace

The classic trace function allow to do dumb and blunt debugging.

trace( "hello world" );

TODO

mm.cfg

The Basic

You will need to have Flash Player Debug installed, go to Adobe Flash Player - Debug Downloads.

Once you have that debug player you can then editing the mm.cfg file.

You can create a mm.cfg file in the following locations

  • Windows
    C:\Documents and Settings\USERNAME\mm.cfg
    • Windows 2000/XP
      c:\Documents and settings\USERNAME\mm.cfg (default value)
      %HOMEDRIVE%\%HOMEPATH%\mm.cfg
    • Windows Vista / Windows 7
      c:\Users\USERNAME\mm.cfg (default value)
      %HOMEDRIVE%\%HOMEPATH%\mm.cfg
  • Mac OS X
    ~/mm.cfg
    /Library/Application Support/Macromedia/mm.cfg
  • Linux
    ~/mm.cfg
    /home/USERNAME/mm.cfg

mm.cfg

ErrorReportingEnable=1
TraceOutputFileEnable=1

From that point, when the debug runtime encounter a trace() command, it will write the output to the flashlog.txt file.

You can find the flashlog.txt file at the following locations

  • Windows
    C:\Documents and Settings\USERNAME\Application Data\Macromedia\Flash Player\Logs\flashlog.txt
    %USERPROFILE%\Application Data\Macromedia\Flash Player\Logs\flashlog.txt
    • Windows 95 / 98 / ME / 2000 / XP
      C:\Documents and Settings\USERNAME\Application Data\Macromedia\Flash Player\Logs\flashlog.txt
    • Windows Vista / Windows 7
      C:\Users\USERNAME\AppData\Roaming\Macromedia\Flash Player\Logs\flashlog.txt
  • Mac OS X
    /Users/USERNAME/Library/Preferences/Macromedia/Flash Player/Logs/flashlog.txt
    ~/Library/Preferences/Macromedia/Flash Player/Logs/flashlog.txt
  • Linux
    home/USERNAME/Macromedia/Flash_Player/Logs/flashlog.txt
    /home/USERNAME/.macromedia/Flash_Player/Logs/flashlog.txt
    ~/.macromedia/Flash_Player/Logs/flashlog.txt

If you need to see logs related to crossdomain.xml and other secure access, you can alos enable policy logging

mm.cfg

PolicyFileLog=1   # Enables policy file logging 
PolicyFileLogAppend=1  # Optional; do not clear log at startup

At the same location of flashlog.txt you will find policyfiles.txt.

With AIR apps

This mm.cfg is not only reserved for the Debug Flash Player, it also works with AIR debug apps.

Follow those steps

  1. Produce a debug SWF for AIR
    eg. $ mxmlc -debug=true
  2. At the root of your AIR app
    add a mm.cfg file with
    TraceOutputFileEnable=1
  3. Compile a debug target with ADT
    eg. $ adt -target air myApp.air myApp.xml myApp.swf mm.cfg
    other targets can be
    apk-debug, ipa-debug, ipa-debug-interpreter, ipa-debug-interpreter-simulator
  4. or run the AIR app with ADL
    eg. $ adl myApp.xml (debug is activated by default)

Once the AIR app is running you will find a flashlog.txt file generated at root of the app.

If the AIR app is a mobile app running on a device you will need to access the device file system to read flashlog.txt, to do that you can use a tool like Macroplant iExplorer or Android File Transfer.

It is documented by Adobe here.

Advanced Usage

In the blog post AS3 hidden treasure in the mm.cfg file. Revealing and documenting many Flash secrets! you can find numerous undocumented and advanced options you can setup in mm.cfg.

For example

TraceOutputFileEnable=1
AS3Trace=1

will output something like

30976 AVMINF: MTHD flash.events::ProgressEvent ()
30976 AVMINF: MTHD flash.events::ProgressEvent ()
30977 AVMINF: MTHD flash.events::Event ()
30977 AVMINF: MTHD flash.events::Event ()
30977 AVMINF: MTHD Object ()
30977 AVMINF: MTHD Object ()
30978 AVMINF: MTHD flash.net::URLLoader/onProgress ()
30978 AVMINF: MTHD flash.net::URLLoader/onProgress ()
30978 AVMINF: MTHD flash.events::ProgressEvent/get bytesLoaded ()
30978 AVMINF: MTHD flash.events::ProgressEvent/get bytesTotal ()
30979 AVMINF: MTHD flash.events::EventDispatcher/dispatchEvent ()
30979 AVMINF: MTHD flash.events::ProgressEvent/clone ()
30979 AVMINF: MTHD flash.events::ProgressEvent ()
30979 AVMINF: MTHD flash.events::Event ()
30979 AVMINF: MTHD flash.events::Event ()
30979 AVMINF: MTHD Object ()
30980 AVMINF: MTHD Object ()

Flash Preload Profiler

From the same guy who found out many undocumented features in the mm.cfg file come a very interesting technique for debugging.

In mm.cfg you have this option PreloadSwf=file.swf?flashvar1=value&…

Lets you specify a SWF to be loaded before the main swf.
This is the profiler agent, a little flash app (ProfilerAgent.swf)
that connect to the FlexBuilder Profiler via socket (localhost:9999).

FlexBuilder is only interpreting that data.
PreloadSwf=C:/Documents and Settings/{USER}/My Documents/Flex Builder 3/.metadata/.plugins/com.adobe.flash.profiler/ProfilerAgent.swf?host=localhost&port=9999
By changing localhost by any other machine name you can connect to a
remote FlashBuilder Profiler.
On the Remote profiler you need to check the “wait for application” box
and then start the local SWF on the other machine.

Read Let’s Talk About The Flex Profiler where Clement Wong explains how it works.

Basically, if you use the PreloadSwf option in mm.cfg it allows you to bootstrap any SWF with your own local SWF file.

Yep, any SWF, even online SWF that you don't necessarily own ;).

JP Auclair came up with FlashPreloadProfiler, first a RC1 then a RC2 and later renamed as The Miner (a commercial product).

In another article AS3 – Hacking PreloadSwf for fun and profit, Philippe Elsass (from Flash Develop) explains the basic principle.

You can find the sources of the first experiment MicroProfiler.

And you can also find the sources of FlashPreloadProfiler on Github.

You can follow the evolution it took by reading

TODO provide the SWF files for FlashPreloadProfiler RC1 and RC2

Also you can read about How To Use a Profiler To Get Better Performance from Jackson Dunstan.

Numerous Flash Debug Console

You can find numerous (old and new) debug console and other loggers, yeah developer like to develop their own debug tools, here a little list.

Flash Builder Profiler

If you are using Flash Builder 4.6 or 4.7 you have access to the Flash Builder Profiler.

This is one of the best tool I know to debug live any SWF or AIR app.

See for example a video demo'ing the memory profiling (Youtube).

But it's much more than that, you can take sample of the memory, compare 2 memory samples, explore for loitering objects, and basically inspect the whole stack.

Even if there are alternatives, if you are already using Flash Builder, it's in general a good idea to run from time to time the profiling to watch out for the memory consumption (especially for mobile app).

flash.sampler

From the documentation of the flash.sampler package

The flash.sampler package contains methods and classes for tracking procedure
calls so that you can profile memory usage and optimize applications.
This package is used by the profiling agent distributed with Adobe Flash Builder,
and is provided for your use for customizing the profiling agent or building your
own memory tests. After you know where an application uses the most memory, you can
focus your optimization effort and speed up the application's performance.
The classes and methods in this package require the Flash Player debugger version 9.0.115.0 or later.

One of the greatest and easiest function to use from this package is getSize()

Returns the size in memory of a specified object when used with the Flash Player 9.0.115.0
or later debugger version. If used with a Flash Player that is not the debugger version,
this method returns 0.

And this is extremely useful to know how much size in memory use an instance of a Class.

Follow the two blog posts by Jackson Dunstan

You can use getSize() for many other things like optimizing your data packets with the ActionScript Message Format (AMF).

flash.trace.Trace

You will need a debug runtime and It allows to you trace every single call to any function that is being called in the AVM2 at runtime.

Be careful, this is extremely verbose.

So, why use it from AS3 code vs from the mm.cfg option ?

When you use the option ASTrace=1 in mm.cfg it traces everything from the start and never stop.

But when you use from AS3, you can enable/disable it anytime, and so only enable it for that little part of code execution where you want to really see all the details.

Here an example on how to use it

     import flash.trace.Trace;
     
     //custom trace function
     function traceListener( file_name:String, linenum:int, method_name:String, method_args:String):void
     {
         trace( method_name + "( " + method_args.join( ", " ) + " )" );
     }
     
     //start the tracing
     Trace.setListener( traceListener );
     Trace.setLevel( Trace.METHODS_AND_LINES_WITH_ARGS, Trace.LISTENER );
     
     //more code here
     
     //stop the tracing
     Trace.setLevel( Trace.OFF, Trace.LISTENER );

Read the Undocumented wiki pages for more documentation.

If you are into programming your own debug tools you could for example redirect the output from the trace function listener to an external app via socket for example.

Example

     private var _debug:Socket = new Socket( "localhost", 666 );

     function traceListener( file_name:String, linenum:int, method_name:String, method_args:String):void
     {
         //trace( method_name + "( " + method_args.join( ", " ) + " )" );
         _debug.writeUTFBytes( method_name + "( " + method_args.join( ", " ) + " )" );
         _debug.flush();
     }

Adobe Scout

TODO

GDB / LLDB

TODO (for redtamarin only)

Reference

Some useful links.

See