NAME=rawptr
FILE=bins/dectest32
EXPECT=<<EOF

uint sym.get_global_array_entry(void)

{
    return *0x804c034;
}

--

uint sym.get_global_array_entry(void)

{
    return uRam0804c034;
}

EOF
CMDS=<<EOF
s sym.get_global_array_entry
af
e r2ghidra.rawptr=1
pdg
?e --
e r2ghidra.rawptr=0
pdg
EOF
RUN

NAME=global flag
FILE=bins/dectest32
EXPECT=<<EOF

uint sym.get_global_var(void)

{
    return _obj.global_var;
}

--

//WARNING: Globals starting with '_' overlap smaller symbols at the same address

uint sym.get_global_var(void)

{
    return _obj.global_var;
}

EOF
CMDS=<<EOF
s sym.get_global_var
af
e r2ghidra.rawptr=1
pdg
?e --
e r2ghidra.rawptr=0
pdg
EOF
RUN

NAME=function variable annotations
FILE=bins/dectest64
EXPECT=<<EOF
{
  "code": "\nulong main(int argc,char **argv,char **envp)\n\n{\n    ulong uVar1;\n    int64_t in_FS_OFFSET;\n    int64_t var_30h;\n    int32_t var_24h;\n    int64_t var_20h;\n    int64_t var_8h;\n    \n    var_8h = *(in_FS_OFFSET + 0x28);\n    sym.Aeropause(&var_20h,argc,argv);\n    uVar1 = 0;\n    if (var_8h != *(in_FS_OFFSET + 0x28)) {\n        uVar1 = sym.imp.__stack_chk_fail();\n    }\n    return uVar1;\n}\n\n",
  "annotations": [
    {
      "start": 1,
      "end": 6,
      "type": "syntax_highlight",
      "syntax_highlight": "datatype"
    },
    {
      "start": 7,
      "end": 11,
      "type": "function_name",
      "name": "main",
      "offset": 4198782
    },
    {
      "start": 7,
      "end": 11,
      "type": "offset",
      "offset": 4198782
    },
    {
      "start": 7,
      "end": 11,
      "type": "syntax_highlight",
      "syntax_highlight": "function_name"
    },
    {
      "start": 12,
      "end": 15,
      "type": "syntax_highlight",
      "syntax_highlight": "datatype"
    },
    {
      "start": 16,
      "end": 20,
      "type": "function_parameter",
      "name": "argc"
    },
    {
      "start": 16,
      "end": 20,
      "type": "syntax_highlight",
      "syntax_highlight": "function_parameter"
    },
    {
      "start": 21,
      "end": 25,
      "type": "syntax_highlight",
      "syntax_highlight": "datatype"
    },
    {
      "start": 28,
      "end": 32,
      "type": "function_parameter",
      "name": "argv"
    },
    {
      "start": 28,
      "end": 32,
      "type": "syntax_highlight",
      "syntax_highlight": "function_parameter"
    },
    {
      "start": 33,
      "end": 37,
      "type": "syntax_highlight",
      "syntax_highlight": "datatype"
    },
    {
      "start": 40,
      "end": 44,
      "type": "function_parameter",
      "name": "envp"
    },
    {
      "start": 40,
      "end": 44,
      "type": "syntax_highlight",
      "syntax_highlight": "function_parameter"
    },
    {
      "start": 53,
      "end": 58,
      "type": "syntax_highlight",
      "syntax_highlight": "datatype"
    },
    {
      "start": 59,
      "end": 64,
      "type": "local_variable",
      "name": "uVar1"
    },
    {
      "start": 59,
      "end": 64,
      "type": "syntax_highlight",
      "syntax_highlight": "local_variable"
    },
    {
      "start": 70,
      "end": 77,
      "type": "syntax_highlight",
      "syntax_highlight": "datatype"
    },
    {
      "start": 78,
      "end": 90,
      "type": "local_variable",
      "name": "in_FS_OFFSET"
    },
    {
      "start": 78,
      "end": 90,
      "type": "syntax_highlight",
      "syntax_highlight": "local_variable"
    },
    {
      "start": 96,
      "end": 103,
      "type": "syntax_highlight",
      "syntax_highlight": "datatype"
    },
    {
      "start": 104,
      "end": 111,
      "type": "local_variable",
      "name": "var_30h"
    },
    {
      "start": 104,
      "end": 111,
      "type": "syntax_highlight",
      "syntax_highlight": "local_variable"
    },
    {
      "start": 117,
      "end": 124,
      "type": "syntax_highlight",
      "syntax_highlight": "datatype"
    },
    {
      "start": 125,
      "end": 132,
      "type": "local_variable",
      "name": "var_24h"
    },
    {
      "start": 125,
      "end": 132,
      "type": "syntax_highlight",
      "syntax_highlight": "local_variable"
    },
    {
      "start": 138,
      "end": 145,
      "type": "syntax_highlight",
      "syntax_highlight": "datatype"
    },
    {
      "start": 146,
      "end": 153,
      "type": "local_variable",
      "name": "var_20h"
    },
    {
      "start": 146,
      "end": 153,
      "type": "syntax_highlight",
      "syntax_highlight": "local_variable"
    },
    {
      "start": 159,
      "end": 166,
      "type": "syntax_highlight",
      "syntax_highlight": "datatype"
    },
    {
      "start": 167,
      "end": 173,
      "type": "local_variable",
      "name": "var_8h"
    },
    {
      "start": 167,
      "end": 173,
      "type": "syntax_highlight",
      "syntax_highlight": "local_variable"
    },
    {
      "start": 184,
      "end": 190,
      "type": "local_variable",
      "name": "var_8h"
    },
    {
      "start": 184,
      "end": 190,
      "type": "syntax_highlight",
      "syntax_highlight": "local_variable"
    },
    {
      "start": 191,
      "end": 192,
      "type": "offset",
      "offset": 4198797
    },
    {
      "start": 193,
      "end": 194,
      "type": "offset",
      "offset": 4198797
    },
    {
      "start": 195,
      "end": 207,
      "type": "local_variable",
      "name": "in_FS_OFFSET"
    },
    {
      "start": 195,
      "end": 207,
      "type": "syntax_highlight",
      "syntax_highlight": "local_variable"
    },
    {
      "start": 208,
      "end": 209,
      "type": "offset",
      "offset": 4198797
    },
    {
      "start": 210,
      "end": 214,
      "type": "syntax_highlight",
      "syntax_highlight": "constant_variable"
    },
    {
      "start": 184,
      "end": 215,
      "type": "offset",
      "offset": 4198797
    },
    {
      "start": 221,
      "end": 234,
      "type": "function_name",
      "name": "sym.Aeropause",
      "offset": 4199038
    },
    {
      "start": 221,
      "end": 234,
      "type": "syntax_highlight",
      "syntax_highlight": "function_name"
    },
    {
      "start": 235,
      "end": 236,
      "type": "offset",
      "offset": 4198819
    },
    {
      "start": 236,
      "end": 243,
      "type": "syntax_highlight",
      "syntax_highlight": "local_variable"
    },
    {
      "start": 243,
      "end": 244,
      "type": "offset",
      "offset": 4198828
    },
    {
      "start": 244,
      "end": 248,
      "type": "function_parameter",
      "name": "argc"
    },
    {
      "start": 244,
      "end": 248,
      "type": "syntax_highlight",
      "syntax_highlight": "function_parameter"
    },
    {
      "start": 248,
      "end": 249,
      "type": "offset",
      "offset": 4198828
    },
    {
      "start": 249,
      "end": 253,
      "type": "function_parameter",
      "name": "argv"
    },
    {
      "start": 249,
      "end": 253,
      "type": "syntax_highlight",
      "syntax_highlight": "function_parameter"
    },
    {
      "start": 221,
      "end": 254,
      "type": "offset",
      "offset": 4198828
    },
    {
      "start": 260,
      "end": 265,
      "type": "local_variable",
      "name": "uVar1"
    },
    {
      "start": 260,
      "end": 265,
      "type": "syntax_highlight",
      "syntax_highlight": "local_variable"
    },
    {
      "start": 266,
      "end": 267,
      "type": "offset",
      "offset": 4198833
    },
    {
      "start": 268,
      "end": 269,
      "type": "syntax_highlight",
      "syntax_highlight": "constant_variable"
    },
    {
      "start": 260,
      "end": 269,
      "type": "offset",
      "offset": 4198833
    },
    {
      "start": 275,
      "end": 277,
      "type": "offset",
      "offset": 4198851
    },
    {
      "start": 275,
      "end": 277,
      "type": "syntax_highlight",
      "syntax_highlight": "keyword"
    },
    {
      "start": 279,
      "end": 285,
      "type": "local_variable",
      "name": "var_8h"
    },
    {
      "start": 279,
      "end": 285,
      "type": "syntax_highlight",
      "syntax_highlight": "local_variable"
    },
    {
      "start": 286,
      "end": 288,
      "type": "offset",
      "offset": 4198842
    },
    {
      "start": 289,
      "end": 290,
      "type": "offset",
      "offset": 4198842
    },
    {
      "start": 291,
      "end": 303,
      "type": "local_variable",
      "name": "in_FS_OFFSET"
    },
    {
      "start": 291,
      "end": 303,
      "type": "syntax_highlight",
      "syntax_highlight": "local_variable"
    },
    {
      "start": 304,
      "end": 305,
      "type": "offset",
      "offset": 4198842
    },
    {
      "start": 306,
      "end": 310,
      "type": "syntax_highlight",
      "syntax_highlight": "constant_variable"
    },
    {
      "start": 323,
      "end": 328,
      "type": "local_variable",
      "name": "uVar1"
    },
    {
      "start": 323,
      "end": 328,
      "type": "syntax_highlight",
      "syntax_highlight": "local_variable"
    },
    {
      "start": 329,
      "end": 330,
      "type": "offset",
      "offset": 4198853
    },
    {
      "start": 331,
      "end": 355,
      "type": "function_name",
      "name": "sym.imp.__stack_chk_fail",
      "offset": 4198464
    },
    {
      "start": 331,
      "end": 355,
      "type": "syntax_highlight",
      "syntax_highlight": "function_name"
    },
    {
      "start": 323,
      "end": 357,
      "type": "offset",
      "offset": 4198853
    },
    {
      "start": 369,
      "end": 375,
      "type": "offset",
      "offset": 4198859
    },
    {
      "start": 369,
      "end": 375,
      "type": "syntax_highlight",
      "syntax_highlight": "keyword"
    },
    {
      "start": 376,
      "end": 381,
      "type": "local_variable",
      "name": "uVar1"
    },
    {
      "start": 376,
      "end": 381,
      "type": "syntax_highlight",
      "syntax_highlight": "local_variable"
    },
    {
      "start": 369,
      "end": 381,
      "type": "offset",
      "offset": 4198859
    }
  ]
}
EOF
CMDS=<<EOF
s main
af
pdgj~{}
EOF
RUN

NAME=global variable annotation
FILE=bins/dectest32
EXPECT=<<EOF
{
  "code": "\nuint sym.get_global_array_entry(void)\n\n{\n    return *0x804c034;\n}\n\n",
  "annotations": [
    {
      "start": 1,
      "end": 5,
      "type": "syntax_highlight",
      "syntax_highlight": "datatype"
    },
    {
      "start": 6,
      "end": 32,
      "type": "function_name",
      "name": "sym.get_global_array_entry",
      "offset": 134517184
    },
    {
      "start": 6,
      "end": 32,
      "type": "offset",
      "offset": 134517184
    },
    {
      "start": 6,
      "end": 32,
      "type": "syntax_highlight",
      "syntax_highlight": "function_name"
    },
    {
      "start": 33,
      "end": 37,
      "type": "syntax_highlight",
      "syntax_highlight": "keyword"
    },
    {
      "start": 46,
      "end": 52,
      "type": "offset",
      "offset": 134517193
    },
    {
      "start": 46,
      "end": 52,
      "type": "syntax_highlight",
      "syntax_highlight": "keyword"
    },
    {
      "start": 53,
      "end": 54,
      "type": "offset",
      "offset": 134517187
    },
    {
      "start": 54,
      "end": 63,
      "type": "global_variable",
      "offset": 134529076
    },
    {
      "start": 54,
      "end": 63,
      "type": "syntax_highlight",
      "syntax_highlight": "constant_variable"
    },
    {
      "start": 46,
      "end": 63,
      "type": "offset",
      "offset": 134517193
    }
  ]
}
EOF
CMDS=<<EOF
s sym.get_global_array_entry
af
pdgj~{}
EOF
RUN

NAME=constant variable annotation
FILE=bins/dectest32
EXPECT=<<EOF
{
  "code": "\nvoid sym.PrintAmbassador(int32_t arg_8h)\n\n{\n    sym.imp.printf(\"Ambassador value: \");\n    if (arg_8h < 5) {\n        switch(arg_8h) {\n        case 0:\n            sym.imp.printf(\"pure\");\n            break;\n        case 1:\n            sym.imp.printf(\"reason\");\n            break;\n        case 2:\n            sym.imp.printf(\"revolution\");\n            break;\n        case 3:\n            sym.imp.printf(\"echoes\");\n            break;\n        case 4:\n            sym.imp.printf(\"wall\");\n        }\n    }\n    else if (arg_8h == 1000000) {\n        sym.imp.printf(\"million\");\n    }\n    sym.imp.putchar(10);\n    return;\n}\n\n",
  "annotations": [
    {
      "start": 1,
      "end": 5,
      "type": "syntax_highlight",
      "syntax_highlight": "datatype"
    },
    {
      "start": 6,
      "end": 25,
      "type": "function_name",
      "name": "sym.PrintAmbassador",
      "offset": 134517281
    },
    {
      "start": 6,
      "end": 25,
      "type": "offset",
      "offset": 134517281
    },
    {
      "start": 6,
      "end": 25,
      "type": "syntax_highlight",
      "syntax_highlight": "function_name"
    },
    {
      "start": 26,
      "end": 33,
      "type": "syntax_highlight",
      "syntax_highlight": "datatype"
    },
    {
      "start": 34,
      "end": 40,
      "type": "function_parameter",
      "name": "arg_8h"
    },
    {
      "start": 34,
      "end": 40,
      "type": "syntax_highlight",
      "syntax_highlight": "function_parameter"
    },
    {
      "start": 49,
      "end": 63,
      "type": "function_name",
      "name": "sym.imp.printf",
      "offset": 134516816
    },
    {
      "start": 49,
      "end": 63,
      "type": "syntax_highlight",
      "syntax_highlight": "function_name"
    },
    {
      "start": 64,
      "end": 84,
      "type": "constant_variable",
      "offset": 134520840
    },
    {
      "start": 64,
      "end": 84,
      "type": "syntax_highlight",
      "syntax_highlight": "constant_variable"
    },
    {
      "start": 49,
      "end": 85,
      "type": "offset",
      "offset": 134517295
    },
    {
      "start": 91,
      "end": 93,
      "type": "offset",
      "offset": 134517307
    },
    {
      "start": 91,
      "end": 93,
      "type": "syntax_highlight",
      "syntax_highlight": "keyword"
    },
    {
      "start": 95,
      "end": 101,
      "type": "function_parameter",
      "name": "arg_8h"
    },
    {
      "start": 95,
      "end": 101,
      "type": "syntax_highlight",
      "syntax_highlight": "function_parameter"
    },
    {
      "start": 102,
      "end": 103,
      "type": "offset",
      "offset": 134517307
    },
    {
      "start": 104,
      "end": 105,
      "type": "syntax_highlight",
      "syntax_highlight": "constant_variable"
    },
    {
      "start": 117,
      "end": 123,
      "type": "offset",
      "offset": 134517332
    },
    {
      "start": 117,
      "end": 123,
      "type": "syntax_highlight",
      "syntax_highlight": "keyword"
    },
    {
      "start": 124,
      "end": 130,
      "type": "function_parameter",
      "name": "arg_8h"
    },
    {
      "start": 124,
      "end": 130,
      "type": "syntax_highlight",
      "syntax_highlight": "function_parameter"
    },
    {
      "start": 142,
      "end": 146,
      "type": "syntax_highlight",
      "syntax_highlight": "keyword"
    },
    {
      "start": 162,
      "end": 176,
      "type": "function_name",
      "name": "sym.imp.printf",
      "offset": 134516816
    },
    {
      "start": 162,
      "end": 176,
      "type": "syntax_highlight",
      "syntax_highlight": "function_name"
    },
    {
      "start": 177,
      "end": 183,
      "type": "constant_variable",
      "offset": 134520859
    },
    {
      "start": 177,
      "end": 183,
      "type": "syntax_highlight",
      "syntax_highlight": "constant_variable"
    },
    {
      "start": 162,
      "end": 184,
      "type": "offset",
      "offset": 134517353
    },
    {
      "start": 198,
      "end": 203,
      "type": "syntax_highlight",
      "syntax_highlight": "keyword"
    },
    {
      "start": 198,
      "end": 204,
      "type": "offset",
      "offset": 134517361
    },
    {
      "start": 213,
      "end": 217,
      "type": "syntax_highlight",
      "syntax_highlight": "keyword"
    },
    {
      "start": 233,
      "end": 247,
      "type": "function_name",
      "name": "sym.imp.printf",
      "offset": 134516816
    },
    {
      "start": 233,
      "end": 247,
      "type": "syntax_highlight",
      "syntax_highlight": "function_name"
    },
    {
      "start": 248,
      "end": 256,
      "type": "constant_variable",
      "offset": 134520864
    },
    {
      "start": 248,
      "end": 256,
      "type": "syntax_highlight",
      "syntax_highlight": "constant_variable"
    },
    {
      "start": 233,
      "end": 257,
      "type": "offset",
      "offset": 134517371
    },
    {
      "start": 271,
      "end": 276,
      "type": "syntax_highlight",
      "syntax_highlight": "keyword"
    },
    {
      "start": 271,
      "end": 277,
      "type": "offset",
      "offset": 134517379
    },
    {
      "start": 286,
      "end": 290,
      "type": "syntax_highlight",
      "syntax_highlight": "keyword"
    },
    {
      "start": 306,
      "end": 320,
      "type": "function_name",
      "name": "sym.imp.printf",
      "offset": 134516816
    },
    {
      "start": 306,
      "end": 320,
      "type": "syntax_highlight",
      "syntax_highlight": "function_name"
    },
    {
      "start": 321,
      "end": 333,
      "type": "constant_variable",
      "offset": 134520871
    },
    {
      "start": 321,
      "end": 333,
      "type": "syntax_highlight",
      "syntax_highlight": "constant_variable"
    },
    {
      "start": 306,
      "end": 334,
      "type": "offset",
      "offset": 134517389
    },
    {
      "start": 348,
      "end": 353,
      "type": "syntax_highlight",
      "syntax_highlight": "keyword"
    },
    {
      "start": 348,
      "end": 354,
      "type": "offset",
      "offset": 134517397
    },
    {
      "start": 363,
      "end": 367,
      "type": "syntax_highlight",
      "syntax_highlight": "keyword"
    },
    {
      "start": 383,
      "end": 397,
      "type": "function_name",
      "name": "sym.imp.printf",
      "offset": 134516816
    },
    {
      "start": 383,
      "end": 397,
      "type": "syntax_highlight",
      "syntax_highlight": "function_name"
    },
    {
      "start": 398,
      "end": 406,
      "type": "constant_variable",
      "offset": 134520882
    },
    {
      "start": 398,
      "end": 406,
      "type": "syntax_highlight",
      "syntax_highlight": "constant_variable"
    },
    {
      "start": 383,
      "end": 407,
      "type": "offset",
      "offset": 134517407
    },
    {
      "start": 421,
      "end": 426,
      "type": "syntax_highlight",
      "syntax_highlight": "keyword"
    },
    {
      "start": 421,
      "end": 427,
      "type": "offset",
      "offset": 134517415
    },
    {
      "start": 436,
      "end": 440,
      "type": "syntax_highlight",
      "syntax_highlight": "keyword"
    },
    {
      "start": 456,
      "end": 470,
      "type": "function_name",
      "name": "sym.imp.printf",
      "offset": 134516816
    },
    {
      "start": 456,
      "end": 470,
      "type": "syntax_highlight",
      "syntax_highlight": "function_name"
    },
    {
      "start": 471,
      "end": 477,
      "type": "constant_variable",
      "offset": 134520889
    },
    {
      "start": 471,
      "end": 477,
      "type": "syntax_highlight",
      "syntax_highlight": "constant_variable"
    },
    {
      "start": 456,
      "end": 478,
      "type": "offset",
      "offset": 134517425
    },
    {
      "start": 500,
      "end": 504,
      "type": "syntax_highlight",
      "syntax_highlight": "keyword"
    },
    {
      "start": 505,
      "end": 507,
      "type": "offset",
      "offset": 134517341
    },
    {
      "start": 505,
      "end": 507,
      "type": "syntax_highlight",
      "syntax_highlight": "keyword"
    },
    {
      "start": 509,
      "end": 515,
      "type": "function_parameter",
      "name": "arg_8h"
    },
    {
      "start": 509,
      "end": 515,
      "type": "syntax_highlight",
      "syntax_highlight": "function_parameter"
    },
    {
      "start": 516,
      "end": 518,
      "type": "offset",
      "offset": 134517334
    },
    {
      "start": 519,
      "end": 526,
      "type": "syntax_highlight",
      "syntax_highlight": "constant_variable"
    },
    {
      "start": 538,
      "end": 552,
      "type": "function_name",
      "name": "sym.imp.printf",
      "offset": 134516816
    },
    {
      "start": 538,
      "end": 552,
      "type": "syntax_highlight",
      "syntax_highlight": "function_name"
    },
    {
      "start": 553,
      "end": 562,
      "type": "constant_variable",
      "offset": 134520894
    },
    {
      "start": 553,
      "end": 562,
      "type": "syntax_highlight",
      "syntax_highlight": "constant_variable"
    },
    {
      "start": 538,
      "end": 563,
      "type": "offset",
      "offset": 134517443
    },
    {
      "start": 575,
      "end": 590,
      "type": "function_name",
      "name": "sym.imp.putchar",
      "offset": 134516880
    },
    {
      "start": 575,
      "end": 590,
      "type": "syntax_highlight",
      "syntax_highlight": "function_name"
    },
    {
      "start": 591,
      "end": 593,
      "type": "syntax_highlight",
      "syntax_highlight": "constant_variable"
    },
    {
      "start": 575,
      "end": 594,
      "type": "offset",
      "offset": 134517459
    },
    {
      "start": 600,
      "end": 606,
      "type": "offset",
      "offset": 134517469
    },
    {
      "start": 600,
      "end": 606,
      "type": "syntax_highlight",
      "syntax_highlight": "keyword"
    },
    {
      "start": 600,
      "end": 606,
      "type": "offset",
      "offset": 134517469
    }
  ]
}
EOF
CMDS=<<EOF
s sym.PrintAmbassador
af
pdgj~{}
EOF
RUN

NAME=aeropause32 (many features combined)
FILE=bins/dectest32
EXPECT=<<EOF

void sym.Aeropause(Bright *bright,int32_t argc,char **argv)

{
    Ambassador AVar1;
    Morning *pMVar2;
    int iVar3;
    
    pMVar2 = sym.imp.malloc(8);
    bright->morning = pMVar2;
    bright->morning->saved_argc = argc;
    bright->morning->saved_argv = argv;
    if (bright->morning->saved_argc < 2) {
        bright->ambassador = AMBASSADOR_PURE;
    }
    else {
        (bright->window).sunlight = bright->morning->saved_argv[1];
        iVar3 = sym.imp.strcmp((bright->window).sunlight,0x804a05c);
        if (iVar3 == 0) {
            bright->ambassador = AMBASSADOR_REASON;
        }
        else {
            iVar3 = sym.imp.strcmp((bright->window).sunlight,"dark");
            if (iVar3 == 0) {
                bright->ambassador = AMBASSADOR_REVOLUTION;
            }
            else {
                iVar3 = sym.imp.strcmp((bright->window).sunlight,"third");
                if (iVar3 == 0) {
                    bright->ambassador = AMBASSADOR_ECHOES;
                }
                else {
                    bright->ambassador = AMBASSADOR_MILLION;
                }
            }
        }
    }
    AVar1 = bright->ambassador;
    if (AVar1 < (AMBASSADOR_WALL|AMBASSADOR_REASON)) {
    //switch table (5 cases) at 0x804a070
        switch(AVar1) {
        case AMBASSADOR_PURE:
            sym.imp.printf("pure");
            break;
        case AMBASSADOR_REASON:
            sym.imp.printf("reason");
            break;
        case AMBASSADOR_REVOLUTION:
            sym.imp.printf("revolution");
            break;
        case AMBASSADOR_ECHOES:
            sym.imp.printf("echoes");
            break;
        case AMBASSADOR_WALL:
            sym.imp.printf("wall");
        }
    }
    else if (AVar1 == AMBASSADOR_MILLION) {
        sym.imp.printf("million");
    }
    sym.PrintAmbassador(bright->ambassador);
    return;
}

EOF
CMDS=<<EOF
aaa
to bins/types.h
s sym.Aeropause
afvb 8 bright Bright *
afvb 12 argc int32_t
afvb 16 argv const char **
pdg
EOF
RUN

NAME=aeropause64 (many features combined)
FILE=bins/dectest64
EXPECT=<<EOF

void sym.Aeropause(Bright *bright,int32_t argc,char **argv)

{
    uint uVar1;
    int iVar2;
    Morning *pMVar3;
    int64_t var_18h;
    int32_t var_ch;
    char *s1;
    
    pMVar3 = sym.imp.malloc(0x10);
    bright->morning = pMVar3;
    bright->morning->saved_argc = argc;
    bright->morning->saved_argv = argv;
    if (bright->morning->saved_argc < 2) {
        *&bright->ambassador = AMBASSADOR_PURE;
    }
    else {
        (bright->window).sunlight = bright->morning->saved_argv[1];
        iVar2 = sym.imp.strcmp((bright->window).sunlight,"the  ");
        if (iVar2 == 0) {
            *&bright->ambassador = AMBASSADOR_REASON;
        }
        else {
            iVar2 = sym.imp.strcmp((bright->window).sunlight,"dark");
            if (iVar2 == 0) {
                *&bright->ambassador = AMBASSADOR_REVOLUTION;
            }
            else {
                iVar2 = sym.imp.strcmp((bright->window).sunlight,"third");
                if (iVar2 == 0) {
                    *&bright->ambassador = AMBASSADOR_ECHOES;
                }
                else {
                    *&bright->ambassador = AMBASSADOR_MILLION;
                }
            }
        }
    }
    uVar1 = bright->ambassador;
    if (uVar1 < (AMBASSADOR_WALL|AMBASSADOR_REASON)) {
    //switch table (5 cases) at 0x402088
        switch(uVar1) {
        case 0:
            sym.imp.printf("pure");
            break;
        case 1:
            sym.imp.printf("reason");
            break;
        case 2:
            sym.imp.printf("revolution");
            break;
        case 3:
            sym.imp.printf("echoes");
            break;
        case 4:
            sym.imp.printf("wall");
        }
    }
    else if (uVar1 == AMBASSADOR_MILLION) {
        sym.imp.printf("million");
    }
    sym.PrintAmbassador(bright->ambassador);
    return;
}

EOF
CMDS=<<EOF
aaa
to bins/types.h

s sym.Aeropause
pdg
EOF
RUN

NAME=typedef
FILE=bins/dectest32
EXPECT=<<EOF

void sym.Aeropause(Bright *bright,int32_t argc,char **argv)

{
    Ambassador AVar1;
    Morning *pMVar2;
    int iVar3;
    
    pMVar2 = sym.imp.malloc(8);
    bright->morning = pMVar2;
    bright->morning->saved_argc = argc;
    bright->morning->saved_argv = argv;
    if (bright->morning->saved_argc < 2) {
        bright->ambassador = AMBASSADOR_PURE;
    }
    else {
        (bright->window).sunlight = bright->morning->saved_argv[1];
        iVar3 = sym.imp.strcmp((bright->window).sunlight,0x804a05c);
        if (iVar3 == 0) {
            bright->ambassador = AMBASSADOR_REASON;
        }
        else {
            iVar3 = sym.imp.strcmp((bright->window).sunlight,"dark");
            if (iVar3 == 0) {
                bright->ambassador = AMBASSADOR_REVOLUTION;
            }
            else {
                iVar3 = sym.imp.strcmp((bright->window).sunlight,"third");
                if (iVar3 == 0) {
                    bright->ambassador = AMBASSADOR_ECHOES;
                }
                else {
                    bright->ambassador = AMBASSADOR_MILLION;
                }
            }
        }
    }
    AVar1 = bright->ambassador;
    if (AVar1 < (AMBASSADOR_WALL|AMBASSADOR_REASON)) {
    //switch table (5 cases) at 0x804a070
        switch(AVar1) {
        case AMBASSADOR_PURE:
            sym.imp.printf("pure");
            break;
        case AMBASSADOR_REASON:
            sym.imp.printf("reason");
            break;
        case AMBASSADOR_REVOLUTION:
            sym.imp.printf("revolution");
            break;
        case AMBASSADOR_ECHOES:
            sym.imp.printf("echoes");
            break;
        case AMBASSADOR_WALL:
            sym.imp.printf("wall");
        }
    }
    else if (AVar1 == AMBASSADOR_MILLION) {
        sym.imp.printf("million");
    }
    sym.PrintAmbassador(bright->ambassador);
    return;
}

--

void sym.Aeropause(Bright *bright,int32_t argc,char **argv)

{
    Ambassador AVar1;
    Morning *pMVar2;
    int iVar3;
    
    pMVar2 = sym.imp.malloc(8);
    bright->morning = pMVar2;
    bright->morning->saved_argc = argc;
    bright->morning->saved_argv = argv;
    if (bright->morning->saved_argc < 2) {
        bright->ambassador = AMBASSADOR_PURE;
    }
    else {
        (bright->window).sunlight = bright->morning->saved_argv[1];
        iVar3 = sym.imp.strcmp((bright->window).sunlight,0x804a05c);
        if (iVar3 == 0) {
            bright->ambassador = AMBASSADOR_REASON;
        }
        else {
            iVar3 = sym.imp.strcmp((bright->window).sunlight,"dark");
            if (iVar3 == 0) {
                bright->ambassador = AMBASSADOR_REVOLUTION;
            }
            else {
                iVar3 = sym.imp.strcmp((bright->window).sunlight,"third");
                if (iVar3 == 0) {
                    bright->ambassador = AMBASSADOR_ECHOES;
                }
                else {
                    bright->ambassador = AMBASSADOR_MILLION;
                }
            }
        }
    }
    AVar1 = bright->ambassador;
    if (AVar1 < (AMBASSADOR_WALL|AMBASSADOR_REASON)) {
    //switch table (5 cases) at 0x804a070
        switch(AVar1) {
        case AMBASSADOR_PURE:
            sym.imp.printf("pure");
            break;
        case AMBASSADOR_REASON:
            sym.imp.printf("reason");
            break;
        case AMBASSADOR_REVOLUTION:
            sym.imp.printf("revolution");
            break;
        case AMBASSADOR_ECHOES:
            sym.imp.printf("echoes");
            break;
        case AMBASSADOR_WALL:
            sym.imp.printf("wall");
        }
    }
    else if (AVar1 == AMBASSADOR_MILLION) {
        sym.imp.printf("million");
    }
    sym.PrintAmbassador(bright->ambassador);
    return;
}

--

void sym.Aeropause(Bright *bright,int32_t argc,char **argv)

{
    Ambassador AVar1;
    Morning *pMVar2;
    int iVar3;
    
    pMVar2 = sym.imp.malloc(8);
    bright->morning = pMVar2;
    bright->morning->saved_argc = argc;
    bright->morning->saved_argv = argv;
    if (bright->morning->saved_argc < 2) {
        bright->ambassador = AMBASSADOR_PURE;
    }
    else {
        (bright->window).sunlight = bright->morning->saved_argv[1];
        iVar3 = sym.imp.strcmp((bright->window).sunlight,0x804a05c);
        if (iVar3 == 0) {
            bright->ambassador = AMBASSADOR_REASON;
        }
        else {
            iVar3 = sym.imp.strcmp((bright->window).sunlight,"dark");
            if (iVar3 == 0) {
                bright->ambassador = AMBASSADOR_REVOLUTION;
            }
            else {
                iVar3 = sym.imp.strcmp((bright->window).sunlight,"third");
                if (iVar3 == 0) {
                    bright->ambassador = AMBASSADOR_ECHOES;
                }
                else {
                    bright->ambassador = AMBASSADOR_MILLION;
                }
            }
        }
    }
    AVar1 = bright->ambassador;
    if (AVar1 < (AMBASSADOR_WALL|AMBASSADOR_REASON)) {
    //switch table (5 cases) at 0x804a070
        switch(AVar1) {
        case AMBASSADOR_PURE:
            sym.imp.printf("pure");
            break;
        case AMBASSADOR_REASON:
            sym.imp.printf("reason");
            break;
        case AMBASSADOR_REVOLUTION:
            sym.imp.printf("revolution");
            break;
        case AMBASSADOR_ECHOES:
            sym.imp.printf("echoes");
            break;
        case AMBASSADOR_WALL:
            sym.imp.printf("wall");
        }
    }
    else if (AVar1 == AMBASSADOR_MILLION) {
        sym.imp.printf("million");
    }
    sym.PrintAmbassador(bright->ambassador);
    return;
}

EOF
CMDS=<<EOF
aaa
to bins/types.h
s sym.Aeropause
afvb 8 bright BrightPtr
afvb 12 argc Bright *
afvb 16 argv const char **
pdg
?e --
afvb 8 bright BrightTypedefd *
afvb 12 argc int32_t
afvb 16 argv const char **
pdg
?e --
afvb 8 bright BrightTypedefdPtr
pdg
EOF
RUN

NAME=recursive type
FILE=bins/rec
CMDS=<<EOF
to bins/types_rec.h
aaa
s sym.KillList
afvt arg1 LL
afvt ptr LL
pdg
EOF
EXPECT=<<EOF

void sym.KillList(LL arg1)

{
    LL pLVar1;
    LL ptr;
    int64_t var_8h;
    
    ptr = arg1;
    while (ptr != NULL) {
        pLVar1 = *&ptr->next;
        sym.imp.free(ptr);
        ptr = pLVar1;
    }
    return;
}

EOF
RUN

NAME=ppc64 variadic prototype recovers call-site register args under pdg
FILE=bins/elf/ppc64v1-vararg
CMDS=<<EOF
aa
"td int vfmt(const char *tag, ...);"
pdg @ sym.caller~vfmt
EOF
EXPECT=<<EOF
    iVar1 = sym.vfmt(0x100001c8,arg1,arg2);
EOF
RUN

NAME=string literals render inline instead of as flag symbols
FILE=bins/elf/crackme0x05
CMDS=<<EOF
aaa
pdg @ main~printf
EOF
EXPECT=<<EOF
    sym.imp.printf("IOLI Crackme Level 0x05\n");
    sym.imp.printf("Password: ");
EOF
RUN

NAME=return type from r2 prototype is preserved
FILE=bins/elf/crackme0x05
EXPECT=<<EOF
int mycheck(int code)
EOF
CMDS=<<EOF
s sym.check
af
afn mycheck
afc cdecl
'afs int mycheck(int code)
pdg~mycheck(
EOF
RUN

NAME=return type preserved for argument-less prototype
FILE=bins/elf/crackme0x05
EXPECT=<<EOF
int mycheck(void)
EOF
CMDS=<<EOF
s sym.check
af
afn mycheck
afc cdecl
'afs int mycheck(void)
pdg~mycheck(
EOF
RUN

# r2 renamed this stub after 6.2.0, so assert the call shape, not the name
NAME=ppc64 noreturn void callee gets no phantom canary arg under pdg
FILE=bins/elf/ppc64-noreturn-arg.so
ARGS=-e bin.relocs.apply=true
CMDS=<<EOF2
aaa
pdg @ sym.withbuf~stack_chk_fail()?
EOF2
EXPECT=<<EOF2
1
EOF2
RUN

NAME=ppc64 noreturn callee that takes an argument keeps it under pdg
FILE=bins/elf/ppc64-noreturn-arg.so
ARGS=-e bin.relocs.apply=true
CMDS=<<EOF2
aaa
pdg @ sym.doexit~0x2a
EOF2
EXPECT=<<EOF2
        entry0(0x2a);
EOF2
RUN

NAME=aarch64 ET_REL noreturn stops flow and preserves argument counts
FILE=bins/elf/arm64-noreturn-etrel.o
ARGS=-e bin.relocs.apply=true
CMDS=<<EOF2
aaa
pdg @ sym.sum~?int sym.sum(
pdg @ sym.sum~?stack_chk_fail()
pdg @ sym.sum~?reloc.exit,halt_baddata
pdg @ sym.quit~?exit(0x2a
EOF2
EXPECT=<<EOF2
1
1
0
1
EOF2
RUN

NAME=noreturn flags preserve known and unknown arguments
FILE=bins/elf/noreturn-prototypes-x86_64.o
ARGS=-e bin.relocs.apply=true
CMDS=<<EOF2
aaa
pdg @ sym.call_err~?reloc.err(0x2a
pdg @ sym.call_errx~?reloc.errx(0x2a
tna reloc.custom_fatal
pdg @ sym.call_custom~?reloc.custom_fatal(0x2a)
pdg @ sym.call_custom~?halt_baddata
tk custom_fatal=func
pdg @ sym.call_custom~?reloc.custom_fatal(0x2a)
tk func.custom_fatal.args=0
tk reloc.custom_fatal=func
tk func.reloc.custom_fatal.args=1
pdg @ sym.call_custom~?reloc.custom_fatal(0x2a)
tk func.reloc.custom_fatal.args=invalid
pdg @ sym.call_custom~?reloc.custom_fatal(0x2a)
tk func.reloc.custom_fatal.args=0x0
pdg @ sym.call_custom~?reloc.custom_fatal()
EOF2
EXPECT=<<EOF2
1
1
1
0
1
1
1
1
EOF2
RUN

NAME=pdg survives an unparseable var type string instead of recursing
FILE=bins/dectest64
CMDS=<<EOF
s sym.Aeropause
af
afvt arg1 int (*)(int)
pdg~Aeropause(
EOF
EXPECT=<<EOF
void sym.Aeropause(int arg1,int64_t arg2,int64_t arg3)
EOF
RUN

NAME=afvt pointer type on a register arg applies under pdg
FILE=bins/dectest64
CMDS=<<EOF
s sym.Aeropause
af
"afvt arg1 char *"
pdg~Aeropause(
EOF
EXPECT=<<EOF
void sym.Aeropause(char *arg1,int64_t arg2,int64_t arg3)
EOF
RUN

NAME=pdgw writes the recovered register-arg type and signature
FILE=bins/dectest64
ARGS=-e log.level=0
CMDS=<<EOF
s sym.Aeropause
af
e r2ghidra.vars=false
e log.level=2
pdgw
afv
afs
EOF
EXPECT=<<EOF
arg int64_t * arg1 @ rdi
arg int64_t arg2 @ rsi
arg int64_t arg3 @ rdx
var int64_t var_8h @ rbp-0x8
var int32_t var_ch @ rbp-0xc
var int64_t var_18h @ rbp-0x18
void sym.Aeropause (int64_t *arg1, int64_t arg2, int64_t arg3);
EOF
EXPECT_ERR=<<EOF
INFO: pdgw: wrote 1 types, 0 names
EOF
RUN

NAME=pdgw run twice makes no further changes
FILE=bins/dectest64
ARGS=-e log.level=0
CMDS=<<EOF
s sym.Aeropause
af
e r2ghidra.vars=false
e log.level=2
pdgw
pdgw
afv
EOF
EXPECT=<<EOF
arg int64_t * arg1 @ rdi
arg int64_t arg2 @ rsi
arg int64_t arg3 @ rdx
var int64_t var_8h @ rbp-0x8
var int32_t var_ch @ rbp-0xc
var int64_t var_18h @ rbp-0x18
EOF
EXPECT_ERR=<<EOF
INFO: pdgw: wrote 1 types, 0 names
INFO: pdgw: no changes
EOF
RUN

NAME=pdg output improves after pdgw writes types
FILE=bins/dectest64
CMDS=<<EOF
s sym.Aeropause
af
pdg~Aeropause(
e r2ghidra.vars=false
pdgw
e r2ghidra.vars=true
pdg~Aeropause(
EOF
EXPECT=<<EOF
void sym.Aeropause(int64_t arg1,int64_t arg2,int64_t arg3)
void sym.Aeropause(int64_t *arg1,int64_t arg2,int64_t arg3)
EOF
RUN

NAME=pdgw with write gates disabled changes nothing
FILE=bins/dectest64
ARGS=-e log.level=0
CMDS=<<EOF
s sym.Aeropause
af
e r2ghidra.vars=false
e r2ghidra.write.vars=false
e r2ghidra.write.sig=false
e log.level=2
pdgw
afv~arg1
EOF
EXPECT=<<EOF
arg int64_t arg1 @ rdi
EOF
EXPECT_ERR=<<EOF
INFO: pdgw: no changes
EOF
RUN

NAME=pdgw writes the recovered signature on big endian ppc64
FILE=bins/elf/ppc64v1-crc32_generic.ko
ARGS=-e bin.relocs.apply=true -e log.level=0
CMDS=<<EOF
aaa
s sym..crc32_init
e log.level=2
pdgw
afs
pdgw
EOF
EXPECT=<<EOF
void sym..crc32_init (int64_t arg1);
EOF
EXPECT_ERR=<<EOF
INFO: pdgw: wrote 0 types, 0 names, signature
INFO: pdgw: no changes
EOF
RUN

NAME=pdgw preserves an existing explicit prototype
FILE=bins/elf/hello_world
ARGS=-e log.level=0
CMDS=<<EOF
aaa
s main
"afs int main(int argc, char **argv)"
e log.level=2
pdgw
afs
EOF
EXPECT=<<EOF
int main (int argc, char **argv);
EOF
EXPECT_ERR=<<EOF
INFO: pdgw: no changes
EOF
RUN

NAME=pdgw writes the recovered signature on arm64
FILE=bins/elf/arm64-varargs.so
ARGS=-e log.level=0
CMDS=<<EOF
aaa
s sym.p_snprintf
e log.level=2
pdgw
afs
pdgw
EOF
EXPECT=<<EOF
int sym.p_snprintf (int64_t arg1, int64_t arg2);
EOF
EXPECT_ERR=<<EOF
INFO: pdgw: wrote 0 types, 0 names, signature
INFO: pdgw: no changes
EOF
RUN

NAME=pdgw is stable on 32-bit x86 stack arguments
FILE=bins/elf/crackme0x05
ARGS=-e log.level=0
CMDS=<<EOF
s sym.check
af
e r2ghidra.vars=false
e log.level=2
pdgw
pdgw
afv
EOF
EXPECT=<<EOF
arg int32_t arg_8h @ ebp+0x8
var int32_t var_8h @ ebp-0x8
var int32_t var_ch @ ebp-0xc
EOF
EXPECT_ERR=<<EOF
INFO: pdgw: no changes
INFO: pdgw: no changes
EOF
RUN

NAME=pdgw does not import auto-generated ghidra variable names
FILE=bins/dectest64
ARGS=-e log.level=0
CMDS=<<EOF
s main
af
e r2ghidra.vars=false
e log.level=2
pdgw
afv
EOF
EXPECT=<<EOF
arg int argc @ rdi
arg char ** argv @ rsi
var int64_t var_8h @ rbp-0x8
var int64_t var_20h @ rbp-0x20
var int32_t var_24h @ rbp-0x24
var int64_t var_30h @ rbp-0x30
EOF
EXPECT_ERR=<<EOF
INFO: pdgw: no changes
EOF
RUN

NAME=pdgw converges when a ghidra local shares storage with a parameter
FILE=bins/elf/arm64-varargs.so
ARGS=-e log.level=0
CMDS=<<EOF
aaa
s sym.p_snprintf
e r2ghidra.varargs=true
e log.level=2
pdgw
pdgw
afv~arg1
EOF
EXPECT=<<EOF
arg int64_t arg1 @ x0
EOF
EXPECT_ERR=<<EOF
INFO: pdgw: wrote 0 types, 0 names, signature
INFO: pdgw: no changes
EOF
RUN

NAME=typed HFA parameter decodes join-space storage under pdg
FILE=bins/elf/join-hfa-arm64
CMDS=<<EOF
s sym.sum2
af
'td struct V2 { float x; float y; };
'afs float sum2(V2 v)
pdg~v.x
EOF
EXPECT=<<EOF
    return v.x + v.y;
EOF
RUN

NAME=scalar float parameter keeps regular storage under pdg
FILE=bins/elf/join-hfa-arm64
CMDS=<<EOF
s sym.scale1
af
'afs float scale1(float a)
pdg~return
EOF
EXPECT=<<EOF
    return a + a;
EOF
RUN

NAME=typed function pointer struct field is stored as a pointer
FILE=bins/elf/function-pointer-field-arm64
CMDS=<<EOF
to bins/function-pointer-field-arm64.h
s sym.call_short_slot
af
'afs float call_short_slot(ShortSlot* slot, Receiver* receiver)
pdg~methodPtr
EOF
EXPECT=<<EOF
    fVar1 = (*slot->methodPtr)(receiver,slot->method);
EOF
RUN

NAME=typed function pointer field preserves return type with a long owner name
FILE=bins/elf/function-pointer-field-arm64
CMDS=<<EOF
to bins/function-pointer-field-arm64.h
s sym.call_long_slot
af
'afs float call_long_slot(VeryLongConcreteGenericOwnerName_VTableSlot* slot, Receiver* receiver)
pdg~methodPtr
EOF
EXPECT=<<EOF
    fVar1 = (*slot->methodPtr)(receiver,slot->method);
EOF
RUN

NAME=typed function pointer union member is stored as a pointer
FILE=bins/elf/function-pointer-field-arm64.o
CMDS=<<EOF
to bins/function-pointer-union-arm64.h
s sym.call_short_slot
af
'afs float call_short_slot(UnionSlot* slot, Receiver* receiver)
pdg~cb
EOF
EXPECT=<<EOF
    fVar1 = (*(slot->cb).fn)(receiver,slot->method);
EOF
RUN
