add viz-mflow tool
add viz-mflow tool

Summary:
Add a tool called 'viz-mflow' which will print out graphviz commands to render the cfg for methods.

This is helpful if you're dumb like me and can't easily see what the CFG looks like for a given sequence of bytecode.

If run without filters, it will dump graphs for every method in the APK. Probably not what you want. Use `-c` to filter by substring of class name, and `-m` to filter by substring of method name. See the example below.

Help:
    blo-mbp:fbandroid blo$ buck run -- native/redex:redex-tool viz-mflow --help

    Usage:
      redex-tool [<options>]
      redex-tool <tool> --help
      redex-tool <tool> [<tool-options>]

    Available tools:
      analyze-throws       analyze blocks ending with throws
      verify               verifies references between dexes
      viz-mflow            visualize method transforms

    Options:
      -h [ --help ]                         show this screen and exit
      -j [ --jars ] foo.jar,bar.jar,...     delimited list of system jars
      -a [ --apkdir ] /tmp/redex_extracted_apk
                                            path of an apk dir obtained from
                                            redex.py -u
      -d [ --dexendir ] /tmp/redex_dexen    path of a dexen dir obtained from
                                            redex.py -u
      -c [ --class-filter ] Lmy/pkg/foo     substring of class name to match
      -m [ --method-filter ] get            substring of method name to match
      -e [ --end-block-before-throw ] true (=1)
                                            should get_method_transform place end
                                            blocks before throw

Example:
    blo-mbp:fbandroid blo$ buck run -- native/redex:redex-tool viz-mflow  -c Lcom/facebook/acra/ACRA -m closeStreamNoException -e false --jars /opt/android_sdk/platforms/android-23/android.jar:/opt/android_sdk/platforms/android-23/optional/org.apache.http.legacy.jar --apkdir   /var/folders/hx/v7sps2ks1c35ffp79j4rkndm3qcz6v/T/tmp4IlYrh.redex_extracted_apk --dexendir   /var/folders/hx/v7sps2ks1c35ffp79j4rkndm3qcz6v/T/tmpynv5YK.redex_dexen

    Loading /opt/android_sdk/platforms/android-23/android.jar
    Loading /opt/android_sdk/platforms/android-23/optional/org.apache.http.legacy.jar
    Loading /var/folders/hx/v7sps2ks1c35ffp79j4rkndm3qcz6v/T/tmpynv5YK.redex_dexen/classes.dex
    Loading /var/folders/hx/v7sps2ks1c35ffp79j4rkndm3qcz6v/T/tmpynv5YK.redex_dexen/secondary-1.dex
    Loading /var/folders/hx/v7sps2ks1c35ffp79j4rkndm3qcz6v/T/tmpynv5YK.redex_dexen/secondary-2.dex
    Loading /var/folders/hx/v7sps2ks1c35ffp79j4rkndm3qcz6v/T/tmpynv5YK.redex_dexen/secondary-3.dex
    Loading /var/folders/hx/v7sps2ks1c35ffp79j4rkndm3qcz6v/T/tmpynv5YK.redex_dexen/secondary-4.dex
    Loading /var/folders/hx/v7sps2ks1c35ffp79j4rkndm3qcz6v/T/tmpynv5YK.redex_dexen/secondary-5.dex
    Loading /var/folders/hx/v7sps2ks1c35ffp79j4rkndm3qcz6v/T/tmpynv5YK.redex_dexen/secondary-6.dex
    Loading /var/folders/hx/v7sps2ks1c35ffp79j4rkndm3qcz6v/T/tmpynv5YK.redex_dexen/secondary-7.dex
    Loading /var/folders/hx/v7sps2ks1c35ffp79j4rkndm3qcz6v/T/tmpynv5YK.redex_dexen/secondary-8.dex
    Loading /var/folders/hx/v7sps2ks1c35ffp79j4rkndm3qcz6v/T/tmpynv5YK.redex_dexen/secondary-9.dex
    Initializing reachable classes

    digraph "Lcom/facebook/acra/ACRA;.closeStreamNoException:(Ljava/io/Closeable;)V" {
     "0x7fab30686a20" [label=" DEBUG: DBG_SET_PROLOGUE_END \n  POSITION: ACRA.java:302 \n  OPCODE: [0x7fab73341e30] move-object v0, v5 \n  DEBUG: DBG_START_LOCAL v0 stream:Ljava/io/Closeable; \n  OPCODE: [0x7fab73341d00] move-object v2, v0 \n  OPCODE: [0x7fab73341fb0] if-nez v2 \n "]
     "0x7fab30686a20" -> "0x7fab30686c00"
     "0x7fab30686a20" -> "0x7fab30686ff0"
     "0x7fab30686ff0" [label=" TARGET SIMPLE: 0x7fab73342070 \n  POSITION: ACRA.java:303 \n  POSITION: ACRA.java:310 \n  OPCODE: [0x7fab73341ff0] return-void \n "]
     "0x7fab30686c00" [label=" TARGET SIMPLE: 0x7fab73341fb0 \n  POSITION: ACRA.java:306 \n  OPCODE: [0x7fab73342010] move-object v2, v0 \n "]
     "0x7fab30686c00" -> "0x7fab30686c80"
     "0x7fab30686c80" [label=" TRY: TRY_START (CATCH: 0x7fab30686e20) \n  FALLTHROUGH: [0x7fab30686a00] \n  OPCODE: [0x7fab73341fd0] invoke-interface Ljava/io/Closeable;.close:()V v2 \n "]
     "0x7fab30686c80" -> "0x7fab30687040"
     "0x7fab30686c80" -> "0x7fab30687180"
     "0x7fab30687040" [label=" TARGET SIMPLE: 0x7fab73342260 \n "]
     "0x7fab30687040" -> "0x7fab30687130"
     "0x7fab30687040" -> "0x7fab30687180"
     "0x7fab30687130" [label=" TRY: TRY_END (CATCH: 0x7fab30686e20) \n  POSITION: ACRA.java:309 \n  POSITION: ACRA.java:310 \n  OPCODE: [0x7fab73342070] goto \n "]
     "0x7fab30687130" -> "0x7fab30686ff0"
     "0x7fab30687180" [label=" CATCH: [0x7fab30686e20] Ljava/io/IOException; \n  POSITION: ACRA.java:307 \n  OPCODE: [0x7fab73342090] move-exception v2 \n  OPCODE: [0x7fab733420b0] move-object v1, v2 \n  POSITION: ACRA.java:308 \n  DEBUG: DBG_START_LOCAL v1 e:Ljava/io/IOException; \n  FALLTHROUGH: [0x7fab30686b60] \n  OPCODE: [0x7fab73342150] sget-object Lcom/facebook/acra/ACRA;.LOG_TAG:Ljava/lang/String; v2 \n  OPCODE: [0x7fab733421e0] const-string/jumbo Error while closing stream:  v3 \n  OPCODE: [0x7fab73342200] move-object v4, v1 \n  FALLTHROUGH: [0x7fab306867b0] \n  OPCODE: [0x7fab73342220] invoke-static Landroid/util/Log;.e:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/Throwable;)I v2, v3, v4 \n  OPCODE: [0x7fab73342240] move-result v2 \n  OPCODE: [0x7fab73342260] goto \n "]
     "0x7fab30687180" -> "0x7fab30687040"
    }

Paste the above into something like http://www.webgraphviz.com/, and you will get the following image:

https://our.intern.facebook.com/intern/px/p/6Qj4

Reviewed By: int3

Differential Revision: D4656978

fbshipit-source-id: 6dd9552df532b220e602734c86af1202e4378ccf

facebook/redex,facebook/redex,facebook/redex,facebook/redex,facebook/redex,facebook/redex,facebook/redex,facebook/redex,facebook/redex