NAME=strcpy lowerdashes
FILE=bins/mach0/strcpy-overflow
CMDS=<<EOF
af;pdc~strcp
EOF
EXPECT=<<EOF
        sym.imp.__strcpy_chk () // char *__strcpy_chk("", -1, -1)
EOF
RUN

NAME=td union
FILE=malloc://32
CMDS=<<EOF
'td union Str { char str0[5]; char str1[11]; }
tu
tuc Str
tu Str
tu
w hello world sucks
pf 0[5]z[11]z str0 str1
.tu Str
EOF
EXPECT=<<EOF
Str
union Str {
  char str0[5];
  char str1[11];
};
pf 0[5]z[11]z str0 str1
Str
 str0 : 0x00000000 = "hello"
 str1 : 0x00000000 = "hello world"
 str0 : 0x00000000 = "hello"
 str1 : 0x00000000 = "hello world"
EOF
RUN

NAME=td union with nested struct
FILE=malloc://32
CMDS=<<EOF
'td struct PadStr { char pad[6]; char str1[11]; }
'td union Str { char str0[5]; PadStr str1; }
w hello world sucks
tu Str
.tu Str
EOF
EXPECT=<<EOF
pf 0[5]z? str0 (PadStr)str1
 str0 : 0x00000000 = "hello"
 str1 : 
                struct<PadStr>
       pad : 0x00000000 = "hello "
      str1 : 0x00000006 = "world sucks"
EOF
RUN

NAME=td anonymous struct in typedef
FILE=--
CMDS=<<EOF
'td struct Foo {int a;};
'td struct Bar { char *hello; int world[]; };
ts~Foo,Bar
ts Foo
ts Bar
EOF
EXPECT=<<EOF
Bar
Foo
pf d a
pf zd hello world
EOF
RUN

NAME=ts add and delete
FILE=--
CMDS=<<EOF
ts-NSString
'td typedef struct {int a;} Foo;
ts
ts Foo
ts-Foo
?e --
ts~Foo
EOF
EXPECT=<<EOF
Foo
pf d a
--
EOF
RUN

NAME=typelinks
FILE=-
CMDS=<<EOF
e asm.arch=x86
e asm.bits=64
wx 41574156415541544989f4555389fd4881eca8030000488b3e64488b042528000000488984249803000031c0e82fb30000488d35d54e0100bf0600000
e asm.comments=false
s 2
tl short
s +6
tl int
s 0
pd 8
EOF
EXPECT=<<EOF
            0x00000000      4157           push r15
(short)
0x00000002 = 0x5641
            0x00000004      4155           push r13
            0x00000006      4154           push r12
(int)
0x00000008 = 0x55f48949
            0x0000000c      53             push rbx
            0x0000000d      89fd           mov ebp, edi
            0x0000000f      4881eca803..   sub rsp, 0x3a8
EOF
RUN

NAME=typelinks 2
FILE=-
CMDS=<<EOF
e asm.arch=x86
e asm.bits=64
wx 48656c6c341248656c6c6f00000000000000000048656c6c6f0000000000000000009090
tk WORD=type
tk type.WORD=w
tk type.WORD.size=16
tk VbHeader=struct
tk struct.VbHeader=szVbMagic,wRuntimeBuild,szLangDll,szSecLangDll
tk struct.VbHeader.szVbMagic=char,0,4
tk struct.VbHeader.wRuntimeBuild=WORD,4,0
tk struct.VbHeader.szLangDll=char,6,14
tk struct.VbHeader.szSecLangDll=char,20,14
tl VbHeader @ 0x00
pd 3
EOF
EXPECT=<<EOF
(VbHeader)
     szVbMagic : 0x00000000 = "Hell"
 wRuntimeBuild : 0x00000004 = 0x1234
     szLangDll : 0x00000006 = "Hello"
  szSecLangDll : 0x00000014 = "Hello"
            0x00000022      90             nop
            0x00000023      90             nop
EOF
RUN

NAME=List type links
CMDS=<<EOF
tl int = 0x4
w test @ 0x10
tl char * = 0x10
tl
EOF
EXPECT=<<EOF
0x00000004 = int
0x00000010 = char *
EOF
RUN

NAME=List readable type links
CMDS=<<EOF
tl int
wB -1
tl int = 0x8
w test @ 0x10
tl char * = 0x10
tll
EOF
EXPECT=<<EOF
(int)
0x00000000 = -1
(int)
0x00000008 = 0x00000000
(char *)
0x00000010 = "test"
EOF
RUN

NAME=jni and SoP
FILE=bins/elf/libverifyPass.so
CMDS=<<EOF
e anal.vars.stackname=true
e asm.lines.bb = false
e asm.lines.jmp = false
e asm.var.summary=0
e io.cache=false
e io.cache.read=false
wc-*
aa
-e types.plugin=tcc
s sym.Java_com_app_ndh_NDHActivity_print
to bins/headers/jni.h
td struct NULL { }
tl JNINativeInterface = 0x464c457f
tl NULL = 0
pdf~JNINativeInterface
pdr~JNI?
EOF
EXPECT=<<EOF
| ; var struct JNINativeInterface @ sp+0x12c
| 0x00000f74      4b93           str r3, [JNINativeInterface]
| 0x00000f76      039b           ldr r3, [var_134h]                    ; JNINativeInterface.reserved0
| 0x00000f7e      d358           ldr r3, [r2, r3]                      ; JNINativeInterface.GetStringUTFChars
| 0x00000f82      019a           ldr r2, [var_13ch]                    ; JNINativeInterface.reserved0
| 0x0000100e      d358           ldr r3, [r2, r3]                      ; JNINativeInterface.GetStringLength
| 0x00001012      019a           ldr r2, [var_13ch]                    ; JNINativeInterface.reserved0
| 0x00001066      d258           ldr r2, [r2, r3]                      ; JNINativeInterface.NewStringUTF
| 0x00001114      d258           ldr r2, [r2, r3]                      ; JNINativeInterface.NewStringUTF
| 0x0000112e      d258           ldr r2, [r2, r3]                      ; JNINativeInterface.NewStringUTF
| 0x00001144      4b9a           ldr r2, [JNINativeInterface]
| 0x00001148      9a42           cmp r2, r3                            ; JNINativeInterface.reserved0
12
EOF
RUN

NAME=t
FILE=-
CMDS=t~char,double,float,int,long,short,size,uid,void # basic universal types
EXPECT=<<EOF
char
char *
char **
double
float
int
int16_t
int32_t
int64_t
int8_t
long
long long
short
size_t
uid_t
uint16_t
uint32_t
uint64_t
uint8_t
unsigned char
unsigned int
unsigned short
void *
EOF
RUN

NAME=t <type>
FILE=-
CMDS=<<EOF
t int
t-*
t int
EOF
EXPECT=<<EOF
pf d
EOF
EXPECT_ERR=<<EOF
ERROR: Cannot find 'int' type
EOF
RUN

NAME=t-enum
FILE=-
CMDS=<<EOF
td enum pe_machine { IMAGE_FILE_MACHINE_IA64=0x200, IMAGE_FILE_MACHINE_I386=0x14c };
te~?pe_machine
t-pe_machine
te~?pe_machine
EOF
EXPECT=<<EOF
1
0
EOF
RUN

NAME=t-struct
FILE=-
CMDS=<<EOF
t-*
'td struct three_elements{int x; char y; float z;}
t-three_elements
ts~?
EOF
EXPECT=<<EOF
0
EOF
RUN

NAME=t-union
FILE=-
CMDS=<<EOF
'td union xoo{int x; int y; int z;}
tk*~union
t-xoo
EOF
EXPECT=<<EOF
union.xoo=x,y,z
union.xoo.x=int,0,0
union.xoo.y=int,0,0
union.xoo.z=int,0,0
xoo=union
EOF
RUN

NAME=typedef
FILE=-
CMDS=<<EOF
'td typedef int Abracadabra
t-Abracadabra
t~?Abracadabra
EOF
EXPECT=<<EOF
0
EOF
RUN

NAME=t-*
FILE=-
CMDS=<<EOF
td enum pe_machine { IMAGE_FILE_MACHINE_IA64=0x200, IMAGE_FILE_MACHINE_I386=0x14c };
t-*
t
EOF
EXPECT=<<EOF
EOF
RUN

NAME=teb
FILE=-
CMDS=<<EOF
td enum pe_machine { IMAGE_FILE_MACHINE_IA64=0x200, IMAGE_FILE_MACHINE_I386=0x14c };
teb pe_machine IMAGE_FILE_MACHINE_I386
EOF
EXPECT=<<EOF
0x14c
EOF
RUN

NAME=te
FILE=-
CMDS=<<EOF
td enum pe_machine { IMAGE_FILE_MACHINE_IA64=0x200, IMAGE_FILE_MACHINE_I386=0x14c };
te pe_machine 0x14c
EOF
EXPECT=<<EOF
IMAGE_FILE_MACHINE_I386
EOF
RUN

NAME=tt
FILE=-
CMDS=<<EOF
td typedef char FILE_NAME;
tt FILE_NAME
'td typedef bool FLAG;
tt FLAG
EOF
EXPECT=<<EOF
char
bool
EOF
RUN

NAME=td struct
FILE=-
CMDS=<<EOF
t-*
'td struct test_struct{int x;int y;};
ts~?test_struct
EOF
EXPECT=<<EOF
1
EOF
RUN

NAME=tsn <size>
FILE=-
CMDS=<<EOF
'td struct One { int a; };
'td struct Two { int a; int b; };
'td struct AlsoTwo { char a[8]; };
tsn 4+4
tsn
tsn?
EOF
EXPECT=<<EOF
AlsoTwo
Two
| tsn <size>  list all structs matching the given size
| tsn <size>  list all structs matching the given size
EOF
RUN

NAME=enum32
FILE=-
CMDS=<<EOF
'td enum v { t=0x123, p=0x321 };
te~?
tk v
tk enum.v.t
tk enum.v.p
EOF
EXPECT=<<EOF
1
enum
0x123
0x321
EOF
RUN

NAME=enum64
FILE=-
CMDS=<<EOF
'td enum v { t=0x8000000000000001, p=0x8000000000000008 };
te~?
tk enum.v.t
tk enum.v.p
EOF
EXPECT=<<EOF
1
0x8000000000000001
0x8000000000000008
EOF
RUN

NAME=to error.h
FILE=-
CMDS=<<EOF
to bins/other/error.h
t~char,double,float,int,long,short,size,uid,void # basic universal types
t~addr,date,dox,name
ts~addr,date,dox,name
t addr
EOF
EXPECT_ERR=<<EOF
ERROR: cpp: your compiler doesn't have support to my API
ERROR: Cannot find 'addr' type
EOF
EXPECT=<<EOF
char
char *
char **
double
float
int
int16_t
int32_t
int64_t
int8_t
long
long long
short
size_t
uid_t
uint16_t
uint32_t
uint64_t
uint8_t
unsigned char
unsigned int
unsigned short
void *
EOF
RUN

NAME=to test.h
FILE=-
CMDS=<<EOF
to bins/other/test.h
t~char,double,float,int,long,short,size,uid,void # basic universal types
ts~addr,date,dox,name
t addr
EOF
EXPECT=<<EOF
char
char *
char **
double
float
int
int16_t
int32_t
int64_t
int8_t
long
long long
short
size_t
uid_t
uint16_t
uint32_t
uint64_t
uint8_t
unsigned char
unsigned int
unsigned short
void *
addr
addr_t
date
date_t
dox
dox_t
name
name_t
pf [127]z[40]zi street city zip
EOF
RUN

NAME=t*
FILE=-
CMDS=<<EOF
t-*
tk a=b
t*
EOF
EXPECT=<<EOF
'tk a=b
EOF
RUN

NAME=tp
FILE=-
CMDS=<<EOF
'td struct person { int age; char name[10]; }
s 4
w Carlos
s 0
wx 13
tp person @ 0x0
EOF
EXPECT=<<EOF
  age : 0x00000000 = 0x00000013
 name : 0x00000004 = "Carlos"
EOF
RUN

NAME=unions
FILE=-
CMDS=<<EOF
'td union x{float a;int b;}
tu
EOF
EXPECT=<<EOF
x
EOF
RUN

NAME=Types not reloaded when arch is the same
FILE=-
CMDS=<<EOF
e asm.arch=x86
e anal.arch=x86
e asm.bits=32
t-*
tk a=b
e asm.arch=x68
e asm.bits=32
e anal.arch=x86
tk a
EOF
EXPECT=<<EOF
b
EOF
RUN

NAME=td twice
FILE=-
CMDS=<<EOF
'td int foo(int bar);
'td int foo(int bar);
tk~foo
EOF
EXPECT_ERR=
EXPECT=<<EOF
foo=func
func.foo=bar
func.foo.arg.0=int,bar
func.foo.args=1
func.foo.cc=cdecl
func.foo.ret=int
EOF
RUN

NAME=struct of struct with ts and pf
FILE=-
CMDS=<<EOF
'td struct bar { int a; int b; };
'td struct foo { int x; struct bar moo; };
ts foo
.ts foo
EOF
EXPECT=<<EOF
pf d? x (bar)moo
   x : 0x00000000 = 0x00000000
 moo : 
                struct<bar>
   a : 0x00000004 = 0x00000000
   b : 0x00000008 = 0x00000000
EOF
RUN

NAME=Array of struct with ts
FILE=-
CMDS=<<EOF
'td struct bar { int a; int b; };
'td struct foo { int x; struct bar moo[2]; };
ts foo
.ts foo
EOF
EXPECT=<<EOF
pf d[2]? x (bar)moo
   x : 0x00000000 = 0x00000000
 moo : 
[
                struct<bar>
   a : 0x00000004 = 0x00000000
   b : 0x00000008 = 0x00000000

                struct<bar>
   a : 0x0000000c = 0x00000000
   b : 0x00000010 = 0x00000000
]
EOF
RUN

NAME=te <enum>
FILE=-
CMDS=<<EOF
'td enum Foo {COW=1,BAR=2};
te
te Foo
EOF
EXPECT=<<EOF
Foo
COW = 0x1
BAR = 0x2
EOF
RUN

NAME=te <enum> <value>
FILE=-
CMDS=<<EOF
'td enum Foo {COW=1,BAR=2};
te Foo 1
EOF
EXPECT=<<EOF
COW
EOF
RUN

NAME=teb <enum> <name>
FILE=-
CMDS=<<EOF
'td enum Foo {COW=1,BAR=2};
teb Foo COW
EOF
EXPECT=<<EOF
0x1
EOF
RUN

NAME=ten <value>
FILE=-
CMDS=<<EOF
'td enum Alpha {ONE=1,TWO=2};
'td enum Beta {UNO=2,DOS=3};
ten 1+1
tenq 2
tenj 2
EOF
EXPECT=<<EOF
Alpha.TWO = 0x2
Beta.UNO = 0x2
Alpha.TWO
Beta.UNO
[{"type":"Alpha","name":"TWO","value":2},{"type":"Beta","name":"UNO","value":2}]
EOF
RUN

NAME=afsafv
FILE=bins/mach0/ls-osx-x86_64
CMDS=<<EOF
aa
s main
afs
afs*
?e original
afv~arg
?e deleted
afv-*
afv~arg
?e recovered from signature
.afs*
afv~arg
EOF
EXPECT=<<EOF
int main (int argc, char **argv);
tn main
afc amd64
afvr rdi argc int
afvr rsi argv char **

original
arg int argc @ rdi
arg char ** argv @ rsi
deleted
recovered from signature
arg int argc @ rdi
arg char ** argv @ rsi
EOF
RUN

NAME=truncated tp
FILE=-
CMDS=<<EOF
'td struct foobar{uint32_t a; uint32_t b; uint32_t c; uint32_t d;}
b 64
woe 1
tp foobar
b 4
tp foobar
EOF
EXPECT=<<EOF
 a : 0x00000000 = 0x03020100
 b : 0x00000004 = 0x07060504
 c : 0x00000008 = 0x0b0a0908
 d : 0x0000000c = 0x0f0e0d0c
 a : 0x00000000 = 0x03020100
 b : 0x00000004 = 0x07060504
 c : 0x00000008 = 0x0b0a0908
 d : 0x0000000c = 0x0f0e0d0c
EOF
RUN

NAME=tp with varname
FILE=bins/elf/struct_sample
CMDS=<<EOF
'td struct Books {char  title[50];char  author[50]; char  subject[100];};
aa
s main
aei
aeim
aecu 0x000006d5
?e
tp Books var_e0h
EOF
EXPECT=<<EOF

   title : 0x00177f18 = "Radare2"
  author : 0x00177f4a = "pancake"
 subject : 0x00177f7c = "Reversing"
EOF
RUN

NAME=tpx test
FILE=-
CMDS=<<EOF
'td struct foo {char* a; int b;}
tpx foo 41414141441414141414420010000000
EOF
EXPECT=<<EOF
 a : 0x00000000 = "AAAAD\x14\x14\x14\x14\x14B"
 b : 0x0000000c = 0x00000010
EOF
RUN

NAME=aht and arm
FILE=-
CMDS=<<EOF
e asm.arch = arm
e asm.bits = 32
wx 082090e5040081e5
'td struct foo {int a; int b; int c;};
aht foo.c @ 0x00000000
aht foo.b @ 0x00000004
?e
pd 2
EOF
EXPECT=<<EOF

            0x00000000      082090e5       ldr r2, [r0, foo.c]
            0x00000004      040081e5       str r0, [r1, foo.b]
EOF
RUN

NAME=aht and mips
FILE=-
CMDS=<<EOF
e asm.arch=mips
wx 08007fac040053800800538c
'td struct foo {int a; int b; int c;};
aht foo.c @ 0x00000000
aht foo.c @ 0x00000008
aht foo.b @ 0x00000004
?e
pd 3
EOF
EXPECT=<<EOF

            0x00000000      08007fac       sw ra, foo.c(v1)
            0x00000004      04005380       lb s3, foo.b(v0)
            0x00000008      0800538c       lw s3, foo.c(v0)
EOF
RUN

NAME=struct offset for dst operand with aht
FILE=-
CMDS=<<EOF
e asm.arch=x86
e asm.bits=32
'td struct foo {int a; int b ; int c;}
wx 8b40048951048d500883780800
?e
aht foo.b @ 0x00000000
aht foo.b @ 0x00000003
aht foo.c @ 0x00000006
aht foo.c @ 0x00000009
pd 4
EOF
EXPECT=<<EOF

            0x00000000      8b4004         mov eax, dword [eax + foo.b]
            0x00000003      895104         mov dword [ecx + foo.b], edx
            0x00000006      8d5008         lea edx, [eax + foo.c]
            0x00000009      83780800       cmp dword [eax + foo.c], 0
EOF
RUN

NAME=struct offset propagate via tl
FILE=-
CMDS=<<EOF
e asm.arch=x86
e asm.bits=64
e asm.comments = false
'td struct bar {int a ; int b; int c;}
wx 48C7C058190000488B5004488B4808483B500448BBEFBEADDE00000000488958089090C3
af
tl bar = 0x1958
?e
pdf~bar.
EOF
EXPECT=<<EOF

|           0x00000007      488b5004       mov rdx, qword [rax + bar.b]
|           0x0000000b      488b4808       mov rcx, qword [rax + bar.c]
|           0x0000000f      483b5004       cmp rdx, qword [rax + bar.b]
|           0x0000001d      48895808       mov qword [rax + bar.c], rbx
EOF
RUN

NAME=aat with single struct
FILE=-
CMDS=<<EOF
e asm.arch=x86
e asm.bits=64
e asm.comments = false
'td struct bar {int a ; int b; int c;}
wx 48C7C058190000488B5004488B4808483B500448BBEFBEADDE00000000488958089090C3
tl bar = 0x1958
af
aat @ fcn.00000000
?e
pdf~bar.
EOF
EXPECT=<<EOF

|           0x00000007      488b5004       mov rdx, qword [rax + bar.b]
|           0x0000000b      488b4808       mov rcx, qword [rax + bar.c]
|           0x0000000f      483b5004       cmp rdx, qword [rax + bar.b]
|           0x0000001d      48895808       mov qword [rax + bar.c], rbx
EOF
RUN

NAME=aat with multiple struct
FILE=-
CMDS=<<EOF
e asm.arch=x86
e asm.bits=64
e asm.comments = false
e asm.flags = false
'td struct bar {int x; int y; int z;};
'td struct foo {int a; int b; int c;};
wx 48C7C000010000488B5008488B480448C7C000020000488B5008488B48049090C3
tl bar = 0x200
tl foo = 0x100
af
aat
pdf
EOF
EXPECT=<<EOF
/ 33: fcn.00000000 ();
|           0x00000000      48c7c00001..   mov rax, 0x100
|           0x00000007      488b5008       mov rdx, qword [rax + foo.c]
|           0x0000000b      488b4804       mov rcx, qword [rax + foo.b]
|           0x0000000f      48c7c00002..   mov rax, 0x200
|           0x00000016      488b5008       mov rdx, qword [rax + bar.z]
|           0x0000001a      488b4804       mov rcx, qword [rax + bar.y]
|           0x0000001e      90             nop
|           0x0000001f      90             nop
\           0x00000020      c3             ret
EOF
RUN

NAME=Comments and var in struct offset propagation
FILE=bins/elf/struct_sample
CMDS=<<EOF
e asm.var.summary=0
aa
s main
'td struct Books {char  title[50];char  author[50]; char  subject[100];};
tl Books = 0x00177f18
?e
pdf~Books
EOF
EXPECT=<<EOF

|           ; var struct Books @ rbp-0xe0
|           0x00000684      488d8520ff..   lea rax, [Books]
|           0x00000695      488910         mov qword [rax], rdx        ; Books.title
|           0x00000698      488d8520ff..   lea rax, [Books]
|           0x000006ad      488908         mov qword [rax], rcx        ; Books.author
|           0x000006b0      488d8520ff..   lea rax, [Books]
|           0x000006c5      488930         mov qword [rax], rsi        ; Books.subject
|           0x000006d5      b800000000     mov eax, 0                  ; Books.subject
EOF
RUN

NAME=tl with ahr (return value hint)
FILE=bins/elf/struct_2
CMDS=<<EOF
aa
'td struct Test { int a; int  b; char *c;};
s main
ahr 0x00000597 @ 0x00000592
tl Test = 0x00002020
s 0x000005a8
?e
pd 3
EOF
EXPECT=<<EOF

|           0x000005a8      c70206000000   mov dword [edx], 6          ; Test.a
|           0x000005ae      8b55f4         mov edx, dword [Test]       ; Test.a
|           0x000005b1      c742040700..   mov dword [edx + Test.b], 7
EOF
RUN

NAME=Basic union test
FILE=bins/elf/union_sample
CMDS=<<EOF
aa
'td union Books {char  title[50];char  author[50]; char  subject[100];};
tu
tu Books
s main
tl Books = 0x00177f88
afv~Books
s 0x000006d2
pd 1
EOF
EXPECT=<<EOF
Books
pf 0[50]z[50]z[100]z title author subject
var union Books @ rbp-0x70
|           0x000006d2      488d4590       lea rax, [Books]
EOF
RUN

NAME=ts function pointer test
FILE=-
CMDS=<<EOF
e asm.bits=64
ws hello @ 0x10
'td struct foo {int x; int (*fp)(int a , int b ); char *b;};
ts foo
.ts foo
EOF
EXPECT=<<EOF
pf d[4].pz x fp b
  x : 0x00000000 = 0x00000000
 fp : 0x00000008 = (qword)0x0000000000000000
  b : 0x00000010 = "\x05hello"
EOF
RUN

NAME=ts general pointers test
FILE=-
CMDS=<<EOF
'td struct normal {int a;char b;};
'td struct pointer {char *y;struct normal *obj;};
ts pointer
EOF
EXPECT=<<EOF
pf zp y obj
EOF
RUN

NAME=tsc test
FILE=-
CMDS=<<EOF
'td struct three_elements{int x; char y; float z;}
tsc three_elements
EOF
EXPECT=<<EOF
struct three_elements {
  int x;
  char y;
  float z;
};
EOF
RUN

NAME=tsc with array
FILE=-
CMDS=<<EOF
'td struct with_array{int x; char y[50]; float z;}
tsc with_array
EOF
EXPECT=<<EOF
struct with_array {
  int x;
  char y[50];
  float z;
};
EOF
RUN

NAME=tsc pads only non-natural struct gaps
FILE=-
ARGS=-a x86 -b 64
CMDS=<<EOF
tk G=struct
tk struct.G=a,b,c
tk struct.G.a=int32_t,0,0
tk struct.G.b=char *,8,0
tk struct.G.c=int32_t,24,0
tsc G
EOF
EXPECT=<<EOF
struct G {
  int32_t a;
  char *b;
  uint8_t pad_0x10[8]; // gap
  int32_t c;
};
EOF
RUN

NAME=td sizes pointer members by asm.bits
FILE=-
ARGS=-a x86 -b 64
CMDS=<<EOF
'td struct P {char *p; int c;};
tk struct.P.c
EOF
EXPECT=<<EOF
int,8,0
EOF
RUN

NAME=td sizes pointer members by asm.bits on 32bit
FILE=-
ARGS=-a x86 -b 32
CMDS=<<EOF
'td struct P {char *p; int c;};
tk struct.P.c
EOF
EXPECT=<<EOF
int,4,0
EOF
RUN

NAME=pad members keep their offsets across td and tsc
FILE=malloc://1024
ARGS=-a x86 -b 64
CMDS=<<EOF
'td struct H {int32_t a; uint8_t pad[8]; char *b; int32_t c;};
tk struct.H.b
tk struct.H.c
tsc H
EOF
EXPECT=<<EOF
char *,16,0
int32_t,24,0
struct H {
  int32_t a;
  uint8_t pad[8];
  char *b;
  int32_t c;
};
EOF
RUN

NAME=tsc does not pad unions
FILE=-
CMDS=<<EOF
tk U=union
tk union.U=a,b
tk union.U.a=int32_t,0,0
tk union.U.b=int64_t,0,0
tuc U
EOF
EXPECT=<<EOF
union U {
  int32_t a;
  int64_t b;
};
EOF
RUN

NAME=tec test
FILE=-
CMDS=<<EOF
'td enum Foo {COW=1,BAR=2};
tec Foo
EOF
EXPECT=<<EOF
enum Foo {
	COW = 1,
	BAR = 2
};
EOF
RUN

NAME=tuc test
FILE=-
CMDS=<<EOF
'td union x{int x; int y; int z;}
tuc x
EOF
EXPECT=<<EOF
union x {
  int x;
  int y;
  int z;
};
EOF
RUN

NAME=ttc test
FILE=-
CMDS=<<EOF
'td typedef char FILE_NAME;
ttc FILE_NAME
EOF
EXPECT=<<EOF
typedef char FILE_NAME;
EOF
RUN

NAME=tcd test
FILE=-
CMDS=<<EOF
t-*
'td typedef char FILE_NAME;
'td union x{int x; int y; int z;}
'td enum Foo {COW=1,BAR=2};
'td struct three_elements{int x; char y; float z;}
tcd
EOF
EXPECT=<<EOF
union x {int x; int y; int z;};
struct three_elements {int x; char y; float z;};
typedef char FILE_NAME;
enum Foo {COW = 1, BAR = 2};
EOF
RUN

NAME=typedef struct
FILE=-
CMDS=<<EOF
to bins/headers/12273.h
ts A
ts B
ts C  # Broken but shouldn't hang
?e ----
tk~typedef.A=,typedef.B=,typedef.C=,struct.A,struct.B,struct.C
?e
ts~A,B,C,D
EOF
EXPECT=<<EOF
pf f num
pf dF num num2
pf c ch
----
struct.A=num
struct.A.num=float,0,0
struct.B=num,num2
struct.B.num=int,0,0
struct.B.num.meta=0
struct.B.num2=double,4,0
struct.B.num2.meta=0
struct.C=ch
struct.C.ch=char,0,0
struct.C.ch.meta=0
typedef.B=struct B
typedef.C=struct C

A
B
C
D
EOF
RUN

NAME=typedef struct double header
FILE=-
CMDS=<<EOF
to bins/headers/hdr1.h
to bins/headers/hdr2.h
ts A
ts B
?e
to bins/headers/hdr1.h
to bins/headers/hdr2.h
tk~^struct.0,struct.1,struct.2,struct.3
?e
ts~^0,1,2,3,A,B
EOF
EXPECT=<<EOF
pf f num
pf c ch


A
B
EOF
RUN

NAME=Backward param type propgation
FILE=bins/elf/back1
CMDS=<<EOF
aa
s main
aaft
afv
EOF
EXPECT=<<EOF
var char * src @ rbp-0x8
var char * dest @ rbp-0x10
var size_t size @ rbp-0x14
EOF
RUN

NAME=Forward param type propgation
FILE=bins/elf/forward1
CMDS=<<EOF
aa
s main
aaft
afv
EOF
EXPECT=<<EOF
var char * src @ rbp-0x8
var char * ptr @ rbp-0x10
var size_t size @ rbp-0x14
EOF
RUN

NAME=Propgation via value
FILE=bins/elf/follow_ptr
CMDS=<<EOF
aa
s main
aaft
afv
EOF
EXPECT=<<EOF
var char * var_8h @ rbp-0x8
var char * s @ rbp-0x10
var char * var_18h @ rbp-0x18
var size_t var_1ch @ rbp-0x1c
EOF
RUN

NAME=General type propgation
FILE=bins/elf/hello_world
CMDS=<<EOF
aa
s main
aaft
afv
EOF
EXPECT=<<EOF
var char * dest @ rbp-0x8
var char * s2 @ rbp-0x10
var char * src @ rbp-0x18
var size_t size @ rbp-0x1c
var size_t var_20h @ rbp-0x20
EOF
RUN

NAME=32-bit bin type propgation
FILE=bins/elf/hello_world32
CMDS=<<EOF
aa
s main
aaft
afv
EOF
EXPECT=<<EOF
arg char ** argv @ esp+0x44
var int32_t var_8h @ ebp-0x8
var char * dest @ ebp-0xc
var size_t size @ ebp-0x10
var size_t var_14h @ ebp-0x14
var char * s2 @ ebp-0x18
var char * src @ ebp-0x1c
EOF
RUN

NAME=Register based var
FILE=bins/elf/arg
CMDS=<<EOF
aa
s sym.funcarg
afvr
EOF
EXPECT=<<EOF
arg int64_t arg1 @ rdi
arg int64_t arg2 @ rsi
arg int64_t arg3 @ rdx
arg int64_t arg4 @ rcx
EOF
RUN

NAME=Type propgation for reg based arg
FILE=bins/elf/arg
CMDS=<<EOF
aa
aaft
s sym.funcarg
afvr
EOF
EXPECT=<<EOF
arg char * arg1 @ rdi
arg char * arg2 @ rsi
arg int64_t arg3 @ rdx
arg size_t arg4 @ rcx
EOF
RUN

NAME=Caller to callee propgation (64 bits)
FILE=bins/elf/arg_down_prop
CMDS=<<EOF
e asm.var.summary=0
e asm.lines = false
e asm.xrefs = false
aa
aaft
s sym.funcarg
pd 1
EOF
EXPECT=<<EOF
154: sym.funcarg (char *arg1, uint32_t arg2);
; arg char *arg1 @ rdi
; arg uint32_t arg2 @ rsi
; var char *var_8h @ rbp-0x8
; var uint32_t var_ch @ rbp-0xc
0x0000068a      55             push rbp
EOF
RUN

NAME=Caller to caller propgation (32 bits)
FILE=bins/elf/arg_down_32
CMDS=<<EOF
e asm.var.summary=0
e asm.lines = false
e asm.xrefs = false
aa
aaft
s sym.funcarg
pd 1
EOF
EXPECT=<<EOF
147: sym.funcarg (char *arg_8h, uint32_t arg_ch);
; arg char *arg_8h @ ebp+0x8
; arg uint32_t arg_ch @ ebp+0xc
; var int32_t var_4h @ ebp-0x4
0x0000054d      55             push ebp
EOF
RUN

NAME=Type Propagation
FILE=bins/pe/debugme.exe
CMDS=<<EOF
aaaa
s 0x0040151f
a:tp
pd 1 @ 0x00401792~?size_t n
pd 1 @ 0x00401796~?int c
pd 1 @ 0x0040179e~?void
pd 1 @ 0x004017b1~?size_t n
pd 1 @ 0x004017b5~?int c
pd 1 @ 0x004017bd~?void
pd 1 @ 0x0040186a~?[s2
pd 1 @ 0x0040186e~?s1
pd 1 @ 0x0040152f~?[dwInitParam
pd 1 @ 0x00401537~?[lpDialogFunc
pd 1 @ 0x0040153f~?[hWndParent
pd 1 @ 0x00401547~?[lpTemplateName
pd 1 @ 0x00401554~?hInstance
EOF
EXPECT=<<EOF
1
1
1
1
1
1
1
1
1
1
1
1
1
EOF
RUN

NAME=Double pointer test
FILE=bins/elf/double_ptr
CMDS=<<EOF
aa
aaft
s main
afv~ptr
EOF
EXPECT=<<EOF
var char ** ptr @ rbp-0x18
EOF
RUN

NAME=Signed and unsigned test
FILE=bins/elf/signed_test
CMDS=<<EOF
aa
aaft
s main
afv~sign
afv~uint
EOF
EXPECT=<<EOF
var signed int var_30h @ rbp-0x30
var signed int var_34h @ rbp-0x34
var uint32_t var_28h @ rbp-0x28
EOF
RUN

NAME=callee argument loaded through a pointer argument gets the pointee type
FILE=malloc://64
ARGS=-a x86 -b 64
CMDS=<<EOF
wx 488b3ee808000000c3909090909090904889f8c3
af @ 0x10
af @ 0
afvt arg1 char **
s 0
aaft
afv @ 0x10
EOF
EXPECT=<<EOF
arg char * arg1 @ rdi
EOF
RUN

NAME=callee argument loaded through a copy chain strips one level only
FILE=malloc://64
ARGS=-a x86 -b 64
CMDS=<<EOF
wx 488b064889c7e805000000c39090904889f8c3
af @ 0x10
af @ 0
afvt arg1 char **
s 0
aaft
afv @ 0x10
EOF
EXPECT=<<EOF
arg char * arg1 @ rdi
EOF
RUN

NAME=lea on a register pointer argument keeps the callee type flat
FILE=malloc://64
ARGS=-a x86 -b 64
CMDS=<<EOF
wx 488d7e08e807000000c39090909090904889f8c3
af @ 0x10
af @ 0
afvt arg1 char *
s 0
aaft
afv @ 0x10
EOF
EXPECT=<<EOF
arg char * arg1 @ rdi
EOF
RUN

NAME=dereferencing a void pointer argument leaves the callee type alone
FILE=malloc://64
ARGS=-a x86 -b 64
CMDS=<<EOF
wx 488b3ee808000000c3909090909090904889f8c3
af @ 0x10
af @ 0
afvt arg1 void *
s 0
aaft
afv @ 0x10
EOF
EXPECT=<<EOF
arg int64_t arg1 @ rdi
EOF
RUN

NAME=callee argument loaded through an arm64 load and register copy
FILE=malloc://64
ARGS=-a arm -b 64
CMDS=<<EOF
wx 080040f9e00308aa02000094c0035fd600040091c0035fd6
af @ 0x10
af @ 0
afvt arg1 char **
s 0
aaft
afv @ 0x10
EOF
EXPECT=<<EOF
arg char * arg1 @ x0
EOF
RUN

NAME=a taken conditional move from memory counts as a dereference
FILE=malloc://64
ARGS=-a x86 -b 64
CMDS=<<EOF
wx 480f453ee807000000c39090909090904889f8c3
af @ 0x10
af @ 0
afvt arg1 char **
s 0
aaft
afv @ 0x10
EOF
EXPECT=<<EOF
arg char * arg1 @ rdi
EOF
RUN

NAME=a void pointer callee arg does not overwrite an existing type fact
FILE=malloc://256
ARGS=-a x86 -b 64
CMDS=<<EOF
wx 554889e54883ec20837df80577029090488d7df831f6ba04000000e810000000c9c3
wx c3 @ 0x30
af @ 0x30
afn memset @ 0x30
'td void *memset(void *s, int c, size_t n);
af @ 0
aft
afv
EOF
EXPECT=<<EOF
var uint32_t s @ rbp-0x8
EOF
RUN

NAME=callee argument dereferenced through an arm64 load gets the pointee type
FILE=malloc://64
ARGS=-a arm -b 64
CMDS=<<EOF
wx 200040f903000094c0035fd61f2003d500040091c0035fd6
af @ 0x10
af @ 0
afvt arg1 char **
s 0
aaft
afv @ 0x10
EOF
EXPECT=<<EOF
arg char * arg1 @ x0
EOF
RUN

NAME=canary named from the guard compare and not from the trace position
FILE=malloc://512
ARGS=-a x86 -b 64
CMDS=<<EOF
wx 554889e54883ec2064488b042528000000488945f8488b45f88b55ef6448330425280000007405e814000000c9c3
wx c3 @ 0x40
af+ 0x40 sym.imp.__stack_chk_fail
afb+ 0x40 0x40 1
af @ 0
s 0
aaft
afv
EOF
EXPECT=<<EOF
var int64_t canary @ rbp-0x8
var int32_t var_11h @ rbp-0x11
EOF
RUN

NAME=canary named when the success path overwrites the compared register
FILE=malloc://512
ARGS=-a x86 -b 64
CMDS=<<EOF
wx 554889e54883ec2064488b042528000000488945f8488b45f864482b0425280000007507c9b801000000c3e810000000
wx c3 @ 0x40
af+ 0x40 sym.imp.__stack_chk_fail
afb+ 0x40 0x40 1
af @ 0
s 0
aaft
afv
EOF
EXPECT=<<EOF
var int64_t canary @ rbp-0x8
EOF
RUN

NAME=canary named when the guard compares the slot in memory
FILE=malloc://512
ARGS=-a x86 -b 64
CMDS=<<EOF
wx 554889e54883ec2064488b0c252800000048894df864488b0c2528000000483b4df87405e817000000c9c3
wx c3 @ 0x40
af+ 0x40 sym.imp.__stack_chk_fail
afb+ 0x40 0x40 1
af @ 0
s 0
aaft
afv
EOF
EXPECT=<<EOF
var uint32_t canary @ rbp-0x8
EOF
RUN

NAME=canary named when stack_chk_fail sits in an out of line block
FILE=malloc://512
ARGS=-a x86 -b 64
CMDS=<<EOF
wx 554889e54883ec2064488b042528000000488945f8488b45f86448330425280000007502c9c3e815000000
wx c3 @ 0x40
af+ 0x40 sym.imp.__stack_chk_fail
afb+ 0x40 0x40 1
af @ 0
s 0
aaft
afv
EOF
EXPECT=<<EOF
var int64_t canary @ rbp-0x8
EOF
RUN

NAME=flagspace analysis
FILE=bins/elf/flagspace
CMDS=<<EOF
aa
aaft
s main
afv
EOF
EXPECT=<<EOF
var int64_t canary @ rbp-0x8
var char * var_10h @ rbp-0x10
var char * var_18h @ rbp-0x18
var char * s @ rbp-0x20
var FILE * stream @ rbp-0x28
var uint32_t var_2ch @ rbp-0x2c
var signed int var_30h @ rbp-0x30
var int32_t var_34h @ rbp-0x34
EOF
RUN

NAME=bashbot test (x86_64)
FILE=bins/elf/bashbot.x86_64.O0.elf
CMDS=<<EOF
aa
aaft
s main
afv
s sym.processCmd
afv
EOF
EXPECT=<<EOF
arg int argc @ rdi
arg char ** argv @ rsi
var int64_t var_18h @ rbp-0x18
var char * s1 @ rbp-0x1020
var void * var_1420h @ rbp-0x1420
var char * dest @ rbp-0x1470
var void * var_1478h @ rbp-0x1478
var char * var_1480h @ rbp-0x1480
var char * v2 @ rbp-0x1488
var char * src @ rbp-0x1490
var char * var_1498h @ rbp-0x1498
var char * s @ rbp-0x14a0
var char * var_14a8h @ rbp-0x14a8
var int32_t var_14ach @ rbp-0x14ac
var uint32_t var_14b0h @ rbp-0x14b0
var uint32_t var_14b4h @ rbp-0x14b4
var pid_t pid @ rbp-0x14b8
var int32_t var_14bch @ rbp-0x14bc
var signed int var_14c0h @ rbp-0x14c0
var int32_t var_14c4h @ rbp-0x14c4
var int32_t options @ rbp-0x14c8
var int64_t wstatus @ rbp-0x14cc
var int32_t var_14d4h @ rbp-0x14d4
var char ** var_14e0h @ rbp-0x14e0
arg signed int arg1 @ rdi
arg char * arg2 @ rsi
var int64_t var_8h @ rbp-0x8
var int64_t var_18h @ rbp-0x18
var char * var_20h @ rbp-0x20
var char * var_28h @ rbp-0x28
var char * s @ rbp-0x30
var char * s1 @ rbp-0x38
var uint32_t var_40h @ rbp-0x40
var char * var_48h @ rbp-0x48
var char * var_50h @ rbp-0x50
var char * var_58h @ rbp-0x58
var char * var_60h @ rbp-0x60
var int32_t var_64h @ rbp-0x64
var int32_t var_68h @ rbp-0x68
var int32_t var_6ch @ rbp-0x6c
var int32_t var_70h @ rbp-0x70
var int32_t var_74h @ rbp-0x74
var int32_t var_78h @ rbp-0x78
var int32_t var_7ch @ rbp-0x7c
var int32_t var_80h @ rbp-0x80
var int32_t var_84h @ rbp-0x84
var int32_t var_88h @ rbp-0x88
var int32_t var_8ch @ rbp-0x8c
var int32_t var_90h @ rbp-0x90
var int32_t var_94h @ rbp-0x94
var int32_t var_98h @ rbp-0x98
var uint32_t var_9ch @ rbp-0x9c
var signed int var_a0h @ rbp-0xa0
var signed int var_a4h @ rbp-0xa4
var char * str @ rbp-0xb0
EOF
RUN

NAME=bashbot test (arm 32-bits)
FILE=bins/elf/bashbot.arm.gcc.O0.elf
CMDS=<<EOF
e anal.vars.stackname=true
s main
af
aaft
afv
EOF
EXPECT=<<EOF
arg int argc @ r0
arg char ** argv @ r1
var uint32_t v5 @ sp+0x0
var char * option @ fp-0xc
var int32_t var_14h @ fp-0x10
var int32_t var_18h @ fp-0x14
var char * options @ fp-0x18
var char * s @ fp-0x1c
var char * var_24h @ fp-0x20
var int32_t var_28h @ fp-0x24
var char * src @ fp-0x28
var int32_t var_30h @ fp-0x2c
var char * v4 @ fp-0x30
var pid_t pid @ fp-0x34
var int32_t var_3ch @ fp-0x38
var int32_t var_40h @ fp-0x3c
var void * var_44h @ fp-0x40
var char * var_48h @ fp-0x44
var int32_t var_4ch @ fp-0x48
var int32_t wstatus @ fp-0x4c
var char * s1 @ fp-0x1040
var void * var_1444h @ fp-0x1440
EOF
RUN

NAME=aft propagates a callee stack argument past the register args on arm32
FILE=malloc://256
ARGS=-a arm -b 32
CMDS=<<EOF
wx 0730a0e300308de50c0000eb1eff2fe1
wx 1eff2fe1 @ 0x40
af @ 0x40
afn five @ 0x40
'td int five(int a, int b, int c, int d, int myarg5);
af @ 0
aaft
afv
EOF
EXPECT=<<EOF
arg int a @ r0
arg int b @ r1
arg int c @ r2
arg int32_t myarg5 @ sp+0x0
EOF
RUN

NAME=aft propagates a callee stack argument above the mips o32 home area
FILE=malloc://256
ARGS=-a mips -b 32 -e cfg.bigendian=true -e anal.cc=o32
CMDS=<<EOF
wx 24080007afa800100c0000100000000003e0000800000000
wx 03e0000800000000 @ 0x40
af @ 0x40
afn five @ 0x40
'td int five(int a, int b, int c, int d, int myarg5);
tk func.five.cc=o32
af @ 0
aaft
afv
EOF
EXPECT=<<EOF
arg int a @ a0
arg int b @ a1
arg int c @ a2
arg int d @ a3
arg int32_t myarg5 @ sp+0x10
EOF
RUN

NAME=format string parse
FILE=bins/elf/format
CMDS=<<EOF
aa
aaft
s main
afv
EOF
EXPECT=<<EOF
var char * var_8h @ rbp-0x8
var long int var_10h @ rbp-0x10
var char * var_18h @ rbp-0x18
var int32_t var_1ch @ rbp-0x1c
var uint32_t var_20h @ rbp-0x20
var signed int var_24h @ rbp-0x24
var int8_t var_25h @ rbp-0x25
EOF
RUN

NAME=local to register var type propgation
FILE=bins/elf/l2rbin
CMDS=<<EOF
aa
aaft
s main
afv
EOF
EXPECT=<<EOF
arg int argc @ rdi
arg char ** argv @ rsi
arg char ** envp @ rdx
var int32_t var_4h @ rbp-0x4
var void * var_10h @ rbp-0x10
var int32_t var_14h @ rbp-0x14
var char ** var_20h @ rbp-0x20
var char ** var_28h @ rbp-0x28
EOF
RUN

NAME=constrained type
FILE=bins/elf/constr_type
CMDS=<<EOF
e types.constraint = true
e asm.var.summary=0
aaa
s sym.single_cond
pd 1~4h
s sym.range_small
pd 1~14h
s sym.range_high
pd 1~4h
s sym.range_or
pd 1~4h
EOF
EXPECT=<<EOF
|           ; var signed int var_4h  { > 0xa } @ rbp-0x4
|           ; var signed int var_14h  { > 0x0 && <= 0x9 } @ rbp-0x14
|           ; var signed int var_4h  { > 0x64 && <= 0xc7 } @ rbp-0x4
|           ; var signed int var_4h  { > 0xff && <= 0x12b || > 0x14 && <= 0x31 || > 0x6f && <= 0xdd } @ rbp-0x4
EOF
RUN

NAME=mov str
FILE=bins/elf/movstr
CMDS=<<EOF
e anal.vars.stackname=true
aaa
s main
afv~var_28h
EOF
EXPECT=<<EOF
var char * var_28h @ esp+0x4
EOF
RUN

NAME=ret type pointer
FILE=bins/elf/tie-test
CMDS=<<EOF
aaa
s sym.foo
afv~var_20h
EOF
EXPECT=<<EOF
var size_t * var_20h @ rbp-0x20
EOF
RUN

NAME=types size
CMDS=<<EOF
'td struct s1 { int a; int size; int b; };
tk~struct.s1
EOF
EXPECT=<<EOF
struct.s1=a,size,b
struct.s1.a=int,0,0
struct.s1.b=int,8,0
struct.s1.size=int,4,0
EOF
RUN

NAME=types afs [before]
FILE=bins/elf/hello_world
CMDS=<<EOF
s main
af
tk~func.main
EOF
EXPECT=<<EOF
func.main.arg.0=int,argc
func.main.arg.1=char **,argv
func.main.arg.2=char **,envp
func.main.args=3
func.main.ret=int
EOF
RUN

NAME=types afs [after]
FILE=bins/elf/hello_world
CMDS=<<EOF
s main
af
'afs int main(int argc);
tk~func.main
EOF
EXPECT=<<EOF
func.main=argc
func.main.arg.0=int,argc
func.main.args=1
func.main.cc=cdecl
func.main.ret=int
EOF
RUN

NAME=afs without type
FILE=bins/elf/analysis/pid_stripped
CMDS=<<EOF
e anal.vars.stackname=true
s 0x4e2420
af
afs
'afs no_type(int a, char **b);
afs
'afs char type(int a, char **b);
afs
EOF
EXPECT=<<EOF
void fcn.004e2420 (int64_t arg1, int64_t arg2, int64_t arg3, int64_t arg4, int64_t arg5, int64_t arg6, int64_t arg_8h);
void no_type (int a, char **b);
char type (int a, char **b);
EOF
RUN

NAME=afs fcnname with dots
FILE=bins/elf/hello_world
CMDS=<<EOF
af
afs
'afs foo.bar();
afs
'afs char foo.bar(int a, ...);
afs
EOF
EXPECT=<<EOF
void entry0 (int64_t arg1);
void foo.bar ();
char foo.bar (int a, ...);
EOF
RUN

NAME=afs sym.imp.*
FILE=bins/elf/hello_world
CMDS=<<EOF
s sym.imp.strlen
af
afs
EOF
EXPECT=<<EOF
size_t strlen (const char *s);
EOF
RUN

NAME=td crash
FILE=-
CMDS=<<EOF
'td struct;
'td struct crash __attribute__((packed)) { };
EOF
EXPECT=<<EOF
EOF
RUN

NAME=tn common
FILE=bins/pe/pe.exe
CMDS=<<EOF
tna 8
tnn 8
tn
tn- 0x8
tn- 8
tn
tn-*
tn
EOF
EXPECT=<<EOF
err
errc
RtlRaiseException
FreeLibraryAndExitThread
ExitProcess
FatalExit
RaiseException
errx
ExitThread
8
0x8
err
errc
RtlRaiseException
FreeLibraryAndExitThread
ExitProcess
FatalExit
RaiseException
errx
ExitThread
EOF
RUN

NAME=td union
FILE=-
CMDS=<<EOF
'td union foo {int a;char b;}
tu*~foo
ts*~foo
t*~foo
t foo
tu* foo
EOF
EXPECT=<<EOF
pf.foo 0dc a b
'tk foo=union
'tk union.foo=a,b
'tk union.foo.a=int,0,0
'tk union.foo.b=char,0,0
pf 0dc a b
pf.foo 0dc a b
EOF
RUN

NAME=td uint64_t
FILE=-
CMDS=<<EOF
wx 0xa00f
wx 0x401f @ 0x4
wx 0800000000000080 @ 0x8
'td struct foo {int a; int b; uint64_t c;};
tl foo @ 0x0
pd 1
EOF
EXPECT=<<EOF
(foo)
 a : 0x00000000 = 0x00000fa0
 b : 0x00000004 = 0x00001f40
 c : 0x00000008 = (qword)0x8000000000000008
EOF
RUN

NAME=td empty struct
FILE=-
CMDS=<<EOF
wx 0xa00f
wx 0x401f @ 0x4
wx 0800000000000080 @ 0x8
'td struct foo {};
tl foo @ 0x0
pd 1
EOF
EXPECT=<<EOF
(foo)
EOF
RUN

NAME=type xrefs
FILE=bins/elf/ls.odd
CMDS=<<EOF
aaaa
txf main
?e =
txf fcn.00011b90
?e =
txt size_t
?e =
txt size_t *
EOF
EXPECT=<<EOF
int64_t
uint32_t
char *
int16_t
int8_t
int
char **
=
int64_t
char *
uint32_t
int32_t
size_t
void *
mbstate_t *
wint_t
int8_t
size_t *
=
fcn.0000f770
fcn.00011b90
fcn.00010010
fcn.0000e780
fcn.0000c0f0
=
fcn.00011b90
fcn.00014d50
EOF
RUN

NAME=aht aligned
FILE=-
CMDS=<<EOF
e asm.arch=x86
e asm.bits=64
'td struct foo {char gap;int bar __attribute__((__aligned__(4)));};
'td struct foo2 {char gap[1];int bar __attribute__((__aligned__(4)));};
'td struct foo3 {char gap[3];int bar __attribute__((__aligned__(4)));};
'td struct foo4 {char gap[4];int bar;};
'td struct foo5 {int gap;int bar;};
ahts 4 ~foo
?e =
wx c7400400000000
aht foo.bar
pd 1
EOF
EXPECT=<<EOF
foo.bar
foo2.bar
foo3.bar
foo4.bar
foo5.bar
=
            0x00000000      c740040000..   mov dword [rax + foo.bar], 0
EOF
RUN

NAME=ahts nested
FILE=-
CMDS=<<EOF
'td struct foo {int bar;int cow;};
'td struct spam {int ham;struct foo _foo;int eggs;};
ahts 8 ~spam
EOF
EXPECT=<<EOF
spam._foo.cow
EOF
RUN

NAME=ahts union nested
FILE=-
CMDS=<<EOF
'td struct ahtpair {int a;int b;};
'td union ahtunion {int raw;struct ahtpair pair;};
ahts 4 ~ahtunion.
EOF
EXPECT=<<EOF
ahtunion.pair.b
EOF
RUN

NAME=aaft io.va side effect
FILE=-
ARGS=-eio.va=0 -a x86 -b 64
CMDS=<<EOF
af
aaft
e io.va
EOF
EXPECT=<<EOF
false
EOF
RUN

NAME=types afs [before] 2
FILE=bins/elf/hello_world
CMDS=<<EOF
aaa
s main
afs
afsj~{}
s sym.imp.strcpy
afs
afsj~{}
EOF
EXPECT=<<EOF
int main (int argc, char **argv, char **envp);
{
  "name": "main",
  "noreturn": false,
  "ret": "int",
  "callconv": "amd64",
  "argc": 3,
  "args": [
    {
      "name": "argc",
      "type": "int",
      "cc": "rdi"
    },
    {
      "name": "argv",
      "type": "char **",
      "cc": "rsi"
    },
    {
      "name": "envp",
      "type": "char **",
      "cc": "rdx"
    }
  ]
}
char * strcpy (char *dest, const char *src);
{
  "name": "sym.imp.strcpy",
  "noreturn": false,
  "ret": "char *",
  "callconv": "amd64",
  "argc": 2,
  "args": [
    {
      "name": "dest",
      "type": "char *",
      "cc": "rdi"
    },
    {
      "name": "src",
      "type": "const char *",
      "cc": "rsi"
    }
  ]
}
EOF
RUN

NAME=typedef stuff
FILE=--
CMDS=<<EOF
'td typedef int Number;
tt
tt Number
tk~Number
t Number
EOF
EXPECT=<<EOF
Number
int
Number=typedef
typedef.Number=int
pf d
EOF
RUN

NAME=x86-32 type propagation (no double counting)
FILE=bins/elf/ioli/crackme0x07
CMDS=<<EOF
e anal.vars.stackname=true
aaa
s fcn.080485b9
afv~format
afv~var_11h
EOF
EXPECT=<<EOF
var char * format @ esp+0x4
var char * var_11h @ ebp-0xd
EOF
RUN

NAME=Double pointer via chain dereference
FILE=bins/elf/double_ptr
CMDS=<<EOF
aa
aaft
s main
afv~ptr
EOF
EXPECT=<<EOF
var char ** ptr @ rbp-0x18
EOF
RUN

NAME=a:tp plugin type propagation single function
FILE=bins/elf/double_ptr
CMDS=<<EOF
aa
s main
a:tp
afv~ptr
EOF
EXPECT=<<EOF
var char ** ptr @ rbp-0x18
EOF
RUN

NAME=a:tp plugin help
FILE=--
CMDS=<<EOF
aei
a:tp?
EOF
EXPECT=<<EOF
Usage: a:tp  propagate types for current function
| a:tpall     propagate types for every function (aaft)
| a:tpsynth   synthesize struct types from pointer-argument and allocator-return accesses (afts)
| a:tpsynth*  show the synthesis as r2 commands without applying (afts*)
| a:tpsynthj  apply the synthesis and report it in json (aftsj)
| a:tp?       show this help
EOF
RUN

NAME=a:tp all functions
FILE=bins/elf/double_ptr
CMDS=<<EOF
aa
a:tpall
s main
afv~ptr
EOF
EXPECT=<<EOF
var char ** ptr @ rbp-0x18
EOF
RUN

NAME=a:tp with rollback enabled
FILE=bins/elf/double_ptr
CMDS=<<EOF
aa
e types.rollback=true
s main
a:tp
afv~ptr
EOF
EXPECT=<<EOF
var char ** ptr @ rbp-0x18
EOF
RUN

NAME=a:tp config rollback default off
FILE=bins/elf/double_ptr
CMDS=<<EOF
e types.rollback
EOF
EXPECT=<<EOF
false
EOF
RUN

NAME=a:tp config rollback can be enabled
FILE=bins/elf/double_ptr
CMDS=<<EOF
e types.rollback=true
e types.rollback
EOF
EXPECT=<<EOF
true
EOF
RUN

NAME=a:tp preserves variable after rollback
FILE=bins/elf/double_ptr
CMDS=<<EOF
aa
e types.rollback=true
s main
a:tp
afv~ptr
EOF
EXPECT=<<EOF
var char ** ptr @ rbp-0x18
EOF
RUN

NAME=a:tp disabled in debugger mode
FILE=bins/elf/double_ptr
ARGS=-e bin.relocs.apply=true
CMDS=<<EOF
e cfg.debug=true
af
a:tp
EOF
EXPECT=<<EOF
EOF
EXPECT_ERR=<<EOF
WARN: Type propagation is disabled in debugger mode
EOF
RUN

NAME=a:tp no function at current offset
FILE=bins/elf/double_ptr
ARGS=-e bin.relocs.apply=true
CMDS=<<EOF
aei
s 0
a:tp
EOF
EXPECT=<<EOF
EOF
EXPECT_ERR=<<EOF
WARN: Cannot find function at current offset
EOF
RUN

NAME=a:tp works after manual aei
FILE=bins/elf/double_ptr
ARGS=-e bin.relocs.apply=true
CMDS=<<EOF
s main
aei
af
afva
a:tp
afv~var_18h
EOF
EXPECT=<<EOF
var uint32_t var_18h @ rbp-0x18
EOF
RUN

NAME=a:tp works after manual aei
FILE=-
ARGS=-a x86 -b 64
CMDS=<<EOF
aei
aeim
e io.cache=true
wx 48c745f810000000488b7df8e805000000c3
f sym.imp.myfunc @ 0x16
af @ 0x16
afs void sym.imp.myfunc(size_t sz) @ 0x16
af @ 0
aft
afv
EOF
EXPECT=<<EOF
var size_t sz @ rbp-0x8
EOF
RUN

NAME=types json fields
FILE=bins/mach0/mac-ls
ARGS=-b64
CMDS=<<EOF
tsj NSString~{}
-b32
?e --
tsj NSString~{}
EOF
EXPECT=<<EOF
{
  "name": "NSString",
  "format": "pxzd p0 p1 str len",
  "fields": [
    {
      "name": "p0",
      "type": "void *",
      "offset": 0,
      "size": 8
    },
    {
      "name": "p1",
      "type": "size_t",
      "offset": 8,
      "size": 8
    },
    {
      "name": "str",
      "type": "char *",
      "offset": 16,
      "size": 8
    },
    {
      "name": "len",
      "type": "int",
      "offset": 24,
      "size": 4
    }
  ]
}
--
{
  "name": "NSString",
  "format": "pdzd p0 p1 str len",
  "fields": [
    {
      "name": "p0",
      "type": "void *",
      "offset": 0,
      "size": 4
    },
    {
      "name": "p1",
      "type": "size_t",
      "offset": 4,
      "size": 4
    },
    {
      "name": "str",
      "type": "char *",
      "offset": 8,
      "size": 4
    },
    {
      "name": "len",
      "type": "int",
      "offset": 12,
      "size": 4
    }
  ]
}
EOF
RUN

NAME=visibility hidden metadata parsing
FILE=--
CMDS=<<CMDS
to bins/other/visibility_test.h
tk ~PadStr
CMDS
EXPECT=<<EXPECT
PadStr=struct
struct.PadStr=pad,str1
struct.PadStr.pad=char,0,6
struct.PadStr.pad.@.visibility=hidden
struct.PadStr.str1=char,6,11
EXPECT
RUN

NAME=visibility hidden pf format
FILE=malloc://32
CMDS=<<CMDS
to bins/other/visibility_test.h
ts PadStr
CMDS
EXPECT=<<EXPECT
pf [6].[11]z str1
EXPECT
RUN

NAME=visibility hidden tsc output
FILE=--
CMDS=<<CMDS
to bins/other/visibility_test.h
tsc PadStr
CMDS
EXPECT=<<EXPECT
struct PadStr {
  char pad[6]; /// @visibility(hidden)
  char str1[11];
};
EXPECT
RUN

NAME=visibility hidden field display
FILE=malloc://32
CMDS=<<CMDS
to bins/other/visibility_test.h
w hello world sucks
.ts PadStr
CMDS
EXPECT=<<EXPECT
 str1 : 0x00000006 = "world sucks"
EXPECT
RUN

NAME=@pack(1) attribute removes padding
FILE=--
CMDS=<<CMDS
to bins/other/packed_test.h
tk ~struct.packed
CMDS
EXPECT=<<EXPECT
struct.packed=a,b,c
struct.packed.@.pack=1
struct.packed.a=char,0,0
struct.packed.b=int,1,0
struct.packed.c=char,5,0
EXPECT
RUN

NAME=struct without pack has natural alignment
FILE=--
CMDS=<<CMDS
to bins/other/packed_test.h
tk ~struct.normal
CMDS
EXPECT=<<EXPECT
struct.normal=a,b,c
struct.normal.a=char,0,0
struct.normal.b=int,4,0
struct.normal.c=char,8,0
EXPECT
RUN

NAME=packed struct pf format (no padding)
FILE=--
CMDS=<<CMDS
to bins/other/packed_test.h
ts packed
CMDS
EXPECT=<<EXPECT
pf cdc a b c
EXPECT
RUN

NAME=normal struct pf format (with padding)
FILE=--
CMDS=<<CMDS
to bins/other/packed_test.h
ts normal
CMDS
EXPECT=<<EXPECT
pf c[3].dc a b c
EXPECT
RUN

NAME=__attribute__((packed)) syntax
FILE=--
CMDS=<<CMDS
'td struct foo __attribute__((packed)) { char a; int b; };
tk ~struct.foo
CMDS
EXPECT=<<EXPECT
struct.foo=a,b
struct.foo.@.packed=true
struct.foo.a=char,0,0
struct.foo.b=int,1,0
EXPECT
RUN

NAME=@aligned attribute on field
FILE=--
CMDS=<<CMDS
'td struct bar { char gap; int val __attribute__((__aligned__(8))); };
tk ~struct.bar
CMDS
EXPECT=<<EXPECT
struct.bar=gap,val
struct.bar.gap=char,0,0
struct.bar.val=int,8,0
struct.bar.val.@.aligned=8
EXPECT
RUN

NAME=packed struct type print
FILE=malloc://32
CMDS=<<CMDS
to bins/other/packed_test.h
wx 4112345678ff
tp packed
CMDS
EXPECT=<<EXPECT
 a : 0x00000000 = 'A'
 b : 0x00000001 = 0x78563412
 c : 0x00000005 = '.'
EXPECT
RUN

NAME=normal struct type print
FILE=malloc://32
CMDS=<<CMDS
to bins/other/packed_test.h
wx 41000000123456784200000000000000
tp normal
CMDS
EXPECT=<<EXPECT
 a : 0x00000000 = 'A'
 b : 0x00000004 = 0x78563412
 c : 0x00000008 = 'B'
EXPECT
RUN

NAME=tsv struct with offsets
FILE=--
CMDS=<<EOF
'td struct foo {int a;int b;}
tsv foo
EOF
EXPECT=<<EOF
0x00000000 struct foo {
0x00000000   int a;
0x00000004   int b;
0x00000008 };
EOF
RUN

NAME=tuv union with offsets
FILE=--
CMDS=<<EOF
'td union bar {int a;short b;}
tuv bar
EOF
EXPECT=<<EOF
0x00000000 union bar {
0x00000000   int a;
0x00000000   short b;
0x00000000 };
EOF
RUN

NAME=tv struct view
FILE=--
CMDS=<<EOF
'td struct point {int x;int y;}
tv point
EOF
EXPECT=<<EOF
0x00000000 struct point {
0x00000000   int x;
0x00000004   int y;
0x00000008 };
EOF
RUN

NAME=tv union view
FILE=--
CMDS=<<EOF
'td union value {int i;float f;}
tv value
EOF
EXPECT=<<EOF
0x00000000 union value {
0x00000000   int i;
0x00000000   float f;
0x00000000 };
EOF
RUN

NAME=tv enum view
FILE=--
CMDS=<<EOF
'td enum status {ok=0,err=1}
tv status
EOF
EXPECT=<<EOF
0x00000000 enum status {
0x00000000   ok = 0x0;
0x00000001   err = 0x1;
0x00000000 };
EOF
RUN

NAME=tv basic type view
FILE=--
CMDS=<<EOF
tv int
EOF
EXPECT=<<EOF
0x00000000 type int; // size=4
0x00000004
EOF
RUN

NAME=tfv xref resolves afs prototype on prefixed function name
FILE=malloc://64
ARGS=-a x86 -b 64 -e types.xrefs=true
CMDS=<<EOF
wa mov edi, 5
wa call 0x20 @ 0x5
wa ret @ 0x20
af @ 0x20
afn sym.foo @ 0x20
s 0x20
'afs int sym.foo(int myarg)
af @ 0x0
afn caller @ 0x0
tfv sym.foo
EOF
EXPECT=<<EOF
             ; XREF[x] 0x00000005 caller
0x00000000 int sym.foo ( // cc:cdecl ret:?
0x00000000   int myarg // stack
0x00000004 );
EOF
RUN

NAME=tfv xref resolves afs prototype on import-prefixed function name
FILE=malloc://64
ARGS=-a x86 -b 64 -e types.xrefs=true
CMDS=<<EOF
wa mov edi, 5
wa call 0x20 @ 0x5
wa ret @ 0x20
af @ 0x20
afn sym.imp.bar @ 0x20
s 0x20
'afs int sym.imp.bar(int myarg)
af @ 0x0
afn caller @ 0x0
tfv sym.imp.bar
EOF
EXPECT=<<EOF
             ; XREF[x] 0x00000005 caller
0x00000000 int sym.imp.bar ( // cc:cdecl ret:?
0x00000000   int myarg // stack
0x00000004 );
EOF
RUN

NAME=aaft function with switch table
FILE=bins/jmptbl/test_gcc_5.5.0_64.out
CMDS=<<EOF
aa
aaft
s main
afv
?e =
afb
EOF
EXPECT=<<EOF
arg uint32_t argc @ rdi
=
0x00000580 0x0000058d 00:0000 13 j 0x00000622 f 0x0000058d
0x0000058d 0x0000059f 00:0000 18 s 0x00000622 s 0x000005b2 s 0x000005c0 s 0x000005ce s 0x000005dc s 0x000005ea s 0x000005f8 s 0x00000606 s 0x00000614 s 0x0000059f
0x0000059f 0x000005ab 00:0000 12 j 0x000005ab
0x000005ab 0x000005b2 00:0000 7
0x000005b2 0x000005c0 00:0000 14 j 0x000005ab
0x000005c0 0x000005ce 00:0000 14 j 0x000005ab
0x000005ce 0x000005dc 00:0000 14 j 0x000005ab
0x000005dc 0x000005ea 00:0000 14 j 0x000005ab
0x000005ea 0x000005f8 00:0000 14 j 0x000005ab
0x000005f8 0x00000606 00:0000 14 j 0x000005ab
0x00000606 0x00000614 00:0000 14 j 0x000005ab
0x00000614 0x00000622 00:0000 14 j 0x000005ab
0x00000622 0x00000633 00:0000 17 j 0x000005ab
EOF
RUN

NAME=aaft function with unreachable block
FILE=malloc://64
ARGS=-a x86 -b 64
CMDS=<<EOF
wx 4889f8c3
wx 48c7c303000000c3 @ 0x10
af+ 0 fcn.unreach
afb+ 0 0 4
afb+ 0 0x10 8
aaft
afb
?e ok
EOF
EXPECT=<<EOF
0x00000000 0x00000004 00:0000 4
0x00000010 0x00000018 00:0000 8
ok
EOF
RUN

NAME=aaft function without basic blocks
FILE=malloc://64
ARGS=-a x86 -b 64
CMDS=<<EOF
af+ 0 fcn.empty
aaft
?e ok
EOF
EXPECT=<<EOF
ok
EOF
RUN

NAME=td struct and union array counts reach sdb via base type serializer
FILE=-
CMDS=<<EOF
'td struct KS {int a; char buf[16];}
'td union KU {char buf[8]; int x;}
tk KS
tk struct.KS
tk struct.KS.buf
tk KU
tk union.KU
tk union.KU.buf
tsc KS
tuc KU
EOF
EXPECT=<<EOF
struct
a,buf
char,4,16
union
buf,x
char,0,8
struct KS {
  int a;
  char buf[16];
};
union KU {
  char buf[8];
  int x;
};
EOF
RUN

NAME=td array dimensions in hex
FILE=malloc://32
CMDS=<<EOF
"td struct Hex { char pad[0x8]; int x; char tail[0x10]; };"
tk struct.Hex.x
tk struct.Hex.tail
"td typedef struct Tg { char b[0x10]; } TgT;"
tk struct.Tg.b
"td typedef union Ug { char c[0x18]; int v; } UgT;"
tk union.Ug.c
tsc Hex
EOF
EXPECT=<<EOF
int,8,0
char,12,16
char,0,16
char,0,24
struct Hex {
  char pad[8];
  int x;
  char tail[16];
};
EOF
RUN

NAME=tsc struct member type with comma survives
FILE=-
CMDS=<<EOF
tk tpl=struct
tk struct.tpl=p
'tk struct.tpl.p=pair<int, char>,8,0
tsc tpl
tsv tpl
EOF
EXPECT=<<EOF
struct tpl {
  uint8_t pad_0x0[8]; // gap
  pair<int, char> p;
};
0x00000000 struct tpl {
0x00000000   pair<int, char> p;
0x00000001 };
EOF
RUN

NAME=tuc union member type with comma survives
FILE=-
CMDS=<<EOF
tk utpl=union
tk union.utpl=p,q
'tk union.utpl.p=pair<int, char>,0,4
tk union.utpl.q=int32_t,0,0
tuc utpl
tuv utpl
EOF
EXPECT=<<EOF
union utpl {
  pair<int, char> p[4];
  int32_t q;
};
0x00000000 union utpl {
0x00000000   pair<int, char> p[4];
0x00000000   int32_t q;
0x00000000 };
EOF
RUN

NAME=comma member type resolves for sizeof and pf format
FILE=-
CMDS=<<EOF
'tk pair<int, char>=struct
'tk struct.pair<int, char>=a,b
'tk struct.pair<int, char>.a=int32_t,0,0
'tk struct.pair<int, char>.b=int32_t,4,0
tk outer=struct
tk struct.outer=p,x
'tk struct.outer.p=pair<int, char>,0,0
tk struct.outer.x=int32_t,8,0
tss outer
ts outer
EOF
EXPECT=<<EOF
12
pf ?[4].d (pair<int, char>)p x
EOF
RUN

NAME=aaft conflicting types from parallel branches meet to void pointer
FILE=malloc://512
ARGS=-a x86 -b 64
CMDS=<<EOF2
wx 554889e54883ec2085ff7424488b7df8e84b000000eb39 @ 0
wx 488d0549000000488945f8eb13 @ 0x30
wx c9c3 @ 0x50
wx c3 @ 0x60
w hello @ 0x80
f str.hello @ 0x80
af @ 0x60
afn takes_file @ 0x60
"td struct fobj {int x;}; int takes_file(struct fobj *f);"
af @ 0
aaft
afv @ 0
EOF2
EXPECT=<<EOF2
arg int64_t arg1 @ rdi
var void * f @ rbp-0x8
EOF2
RUN

NAME=aaft parallel-branch meet is independent of the branch order
FILE=malloc://512
ARGS=-a x86 -b 64
CMDS=<<EOF2
wx 554889e54883ec2085ff7424488d056d000000488945f8eb37 @ 0
wx 488b7df8e827000000eb15 @ 0x30
wx c9c3 @ 0x50
wx c3 @ 0x60
w hello @ 0x80
f str.hello @ 0x80
af @ 0x60
afn takes_file @ 0x60
"td struct fobj {int x;}; int takes_file(struct fobj *f);"
af @ 0
aaft
afv @ 0
EOF2
EXPECT=<<EOF2
arg int64_t arg1 @ rdi
var void * f @ rbp-0x8
EOF2
RUN

NAME=aaft later stronger evidence on the same path upgrades the type
FILE=malloc://512
ARGS=-a x86 -b 64
CMDS=<<EOF2
wx 554889e54883ec20488b7df8e84f000000488d0568000000488945f8c9c3 @ 0
wx c3 @ 0x60
w hello @ 0x80
f str.hello @ 0x80
af @ 0x60
afn takes_u64 @ 0x60
"td int takes_u64(uint64_t v);"
af @ 0
aaft
afv @ 0
EOF2
EXPECT=<<EOF2
var char * v @ rbp-0x8
EOF2
RUN

NAME=aaft matching types from parallel branches stay intact
FILE=malloc://512
ARGS=-a x86 -b 64
CMDS=<<EOF2
wx 554889e54883ec2085ff7424488d057d000000488945f8eb37 @ 0
wx 488d0549000000488945f8eb13 @ 0x30
wx c9c3 @ 0x50
w hello @ 0x80
w world @ 0x90
f str.hello @ 0x80
f str.world @ 0x90
af @ 0
aaft
afv @ 0
EOF2
EXPECT=<<EOF2
arg int64_t arg1 @ rdi
var char * var_8h @ rbp-0x8
EOF2
RUN

NAME=aaft equal-rank scalar conflict from parallel branches meets to the wider default int
FILE=malloc://512
ARGS=-a x86 -b 64
CMDS=<<EOF2
wx 554889e54883ec2085ff7424488b7df8e84b000000eb39 @ 0
wx 488b7df8e837000000eb15 @ 0x30
wx c9c3 @ 0x50
wx c3 @ 0x60
wx c3 @ 0x70
af @ 0x60
afn takes_size @ 0x60
af @ 0x70
afn takes_wint @ 0x70
"td typedef unsigned int wint_t;"
"td int takes_size(size_t v); int takes_wint(wint_t v);"
af @ 0
aaft
afv @ 0
EOF2
EXPECT=<<EOF2
arg int64_t arg1 @ rdi
var int64_t v @ rbp-0x8
EOF2
RUN

NAME=aaft equal-rank scalar meet is independent of the branch order
FILE=malloc://512
ARGS=-a x86 -b 64
CMDS=<<EOF2
wx 554889e54883ec2085ff7424488b7df8e85b000000eb39 @ 0
wx 488b7df8e827000000eb15 @ 0x30
wx c9c3 @ 0x50
wx c3 @ 0x60
wx c3 @ 0x70
af @ 0x60
afn takes_size @ 0x60
af @ 0x70
afn takes_wint @ 0x70
"td typedef unsigned int wint_t;"
"td int takes_size(size_t v); int takes_wint(wint_t v);"
af @ 0
aaft
afv @ 0
EOF2
EXPECT=<<EOF2
arg int64_t arg1 @ rdi
var int64_t v @ rbp-0x8
EOF2
RUN

NAME=aaft const and plain string pointers from parallel branches meet to char pointer
FILE=malloc://512
ARGS=-a x86 -b 64
CMDS=<<EOF2
wx 554889e54883ec2085ff7424488d056d000000488945f8eb37 @ 0
wx 488b7df8e827000000eb15 @ 0x30
wx c9c3 @ 0x50
wx c3 @ 0x60
w hello @ 0x80
f str.hello @ 0x80
af @ 0x60
afn takes_str @ 0x60
"td int takes_str(char *s);"
af @ 0
aaft
afv @ 0
EOF2
EXPECT=<<EOF2
arg int64_t arg1 @ rdi
var char * s @ rbp-0x8
EOF2
RUN

NAME=aaft typed and primitive pointer conflict from parallel branches meets to void pointer
FILE=malloc://512
ARGS=-a x86 -b 64
CMDS=<<EOF2
wx 554889e54883ec2085ff7424488b7df8e84b000000eb39 @ 0
wx 488b7df8e837000000eb15 @ 0x30
wx c9c3 @ 0x50
wx c3 @ 0x60
wx c3 @ 0x70
af @ 0x60
afn takes_file @ 0x60
af @ 0x70
afn takes_szp @ 0x70
"td struct fobj {int x;}; int takes_file(struct fobj *f); int takes_szp(size_t *p);"
af @ 0
aaft
afv @ 0
EOF2
EXPECT=<<EOF2
arg int64_t arg1 @ rdi
var void * p @ rbp-0x8
EOF2
RUN

NAME=aaft typed and primitive pointer meet is independent of the branch order
FILE=malloc://512
ARGS=-a x86 -b 64
CMDS=<<EOF2
wx 554889e54883ec2085ff7424488b7df8e85b000000eb39 @ 0
wx 488b7df8e827000000eb15 @ 0x30
wx c9c3 @ 0x50
wx c3 @ 0x60
wx c3 @ 0x70
af @ 0x60
afn takes_file @ 0x60
af @ 0x70
afn takes_szp @ 0x70
"td struct fobj {int x;}; int takes_file(struct fobj *f); int takes_szp(size_t *p);"
af @ 0
aaft
afv @ 0
EOF2
EXPECT=<<EOF2
arg int64_t arg1 @ rdi
var void * f @ rbp-0x8
EOF2
RUN

NAME=aaft three parallel pointer facts meet to void pointer
FILE=malloc://512
ARGS=-a x86 -b 64
CMDS=<<EOF2
wx 554889e54883ec2085ff742483ff05742f488b7df8e846000000eb34 @ 0
wx 488b7df8e837000000eb15 @ 0x30
wx 488d0539000000488945f8eb03 @ 0x40
wx c9c3 @ 0x50
wx c3 @ 0x60
wx c3 @ 0x70
w hello @ 0x80
f str.hello @ 0x80
af @ 0x60
afn takes_file @ 0x60
af @ 0x70
afn takes_szp @ 0x70
"td struct fobj {int x;}; int takes_file(struct fobj *f); int takes_szp(size_t *p);"
af @ 0
aaft
afv @ 0
EOF2
EXPECT=<<EOF2
arg uint32_t arg1 @ rdi
var void * p @ rbp-0x8
EOF2
RUN

NAME=aaft three parallel pointer facts meet independent of the branch order
FILE=malloc://512
ARGS=-a x86 -b 64
CMDS=<<EOF2
wx 554889e54883ec2085ff742483ff05742f488d0568000000488945f8eb32 @ 0
wx 488b7df8e827000000eb15 @ 0x30
wx 488b7df8e827000000eb05 @ 0x40
wx c9c3 @ 0x50
wx c3 @ 0x60
wx c3 @ 0x70
w hello @ 0x80
f str.hello @ 0x80
af @ 0x60
afn takes_file @ 0x60
af @ 0x70
afn takes_szp @ 0x70
"td struct fobj {int x;}; int takes_file(struct fobj *f); int takes_szp(size_t *p);"
af @ 0
aaft
afv @ 0
EOF2
EXPECT=<<EOF2
arg uint32_t arg1 @ rdi
var void * f @ rbp-0x8
EOF2
RUN

NAME=aaft float and double facts from parallel branches meet to double
FILE=malloc://512
ARGS=-a x86 -b 64
CMDS=<<EOF2
wx 554889e54883ec2085ff7424488b7df8e84b000000eb39 @ 0
wx 488b7df8e837000000eb15 @ 0x30
wx c9c3 @ 0x50
wx c3 @ 0x60
wx c3 @ 0x70
af @ 0x60
afn takes_f @ 0x60
af @ 0x70
afn takes_d @ 0x70
"td int takes_f(float v); int takes_d(double v);"
af @ 0
aaft
afv @ 0
EOF2
EXPECT=<<EOF2
arg int64_t arg1 @ rdi
var double v @ rbp-0x8
EOF2
RUN

NAME=aft types a memset stack local from the stated object size
FILE=malloc://256
ARGS=-a x86 -b 64 -e types.sizes=true
CMDS=<<EOF
wx 554889e54881eca0000000c78578ffffff01000000488dbd78ffffffba8800000031f6e808000000c9c3
wx c3 @ 0x30
af @ 0x30
afn memset @ 0x30
'td void *memset(void *s, int c, size_t n);
af @ 0
aft
afv
EOF
EXPECT=<<EOF
var uint8_t [136] var_88h @ rbp-0x88
EOF
RUN

NAME=aft keeps a named type on a memset stack local
FILE=malloc://256
ARGS=-a x86 -b 64 -e types.sizes=true
CMDS=<<EOF
wx 554889e54881eca0000000c78578ffffff01000000488dbd78ffffffba8800000031f6e808000000c9c3
wx c3 @ 0x30
af @ 0x30
afn memset @ 0x30
'td void *memset(void *s, int c, size_t n);
'td struct mys {int a; int b;};
af @ 0
'afvt var_88h struct mys
aft
afv
EOF
EXPECT=<<EOF
var struct mys var_88h @ rbp-0x88
EOF
RUN

NAME=aft does not shrink a local below its width on a partial clear
FILE=malloc://256
ARGS=-a x86 -b 64 -e types.sizes=true
CMDS=<<EOF
wx 554889e548c745f800000000488d7df831f6ba04000000e814000000c9c3
wx c3 @ 0x30
af @ 0x30
afn memset @ 0x30
'td void *memset(void *s, int c, size_t n);
af @ 0
aft
afv
EOF
EXPECT=<<EOF
var int64_t var_8h @ rbp-0x8
EOF
RUN

NAME=aft ignores a size-function call through an adjusted pointer
FILE=malloc://256
ARGS=-a x86 -b 64 -e types.sizes=true
CMDS=<<EOF
wx 554889e54881eca0000000c78578ffffff01000000488dbd78ffffff4883c71031f6ba20000000e814000000c9c3
wx c3 @ 0x40
af @ 0x40
afn memset @ 0x40
'td void *memset(void *s, int c, size_t n);
af @ 0
aft
afv
EOF
EXPECT=<<EOF
var int32_t s @ rbp-0x88
EOF
RUN

NAME=aft types a memset stack local through the x86-32 push chain
FILE=malloc://256
ARGS=-a x86 -b 32 -e types.sizes=true
CMDS=<<EOF
wx 5589e581eca0000000c78578ffffff010000008d8578ffffff68880000006a0050e81a00000083c40cc9c3
wx c3 @ 0x40
af @ 0x40
afn memset @ 0x40
'td void *memset(void *s, int c, size_t n);
af @ 0
aft
afv
EOF
EXPECT=<<EOF
var uint8_t [136] var_88h @ ebp-0x88
EOF
RUN

NAME=aft merges branch-dependent memset sizes to the larger one
FILE=malloc://256
ARGS=-a x86 -b 64 -e types.sizes=true
CMDS=<<EOF
wx 554889e54881eca0000000c78578ffffff0100000085ff7415488dbd78ffffff31f6ba40000000e824000000eb12488dbd78ffffff31f6ba88000000e80f000000c9c3
wx c3 @ 0x50
af @ 0x50
afn memset @ 0x50
'td void *memset(void *s, int c, size_t n);
af @ 0
aft
afv~var_88h
EOF
EXPECT=<<EOF
var uint8_t [136] var_88h @ rbp-0x88
EOF
RUN

NAME=single block function with the state restore enabled
FILE=malloc://64
ARGS=-a x86 -b 64 -e types.bbstate=true
CMDS=<<EOF
wx 488b3ee808000000c3909090909090904889f8c3
af @ 0x10
af @ 0
afvt arg1 char **
s 0
aaft
afv @ 0x10
EOF
EXPECT=<<EOF
arg char * arg1 @ rdi
EOF
RUN

NAME=a loop body value does not survive the header that overwrites it
FILE=malloc://128
ARGS=-a x86 -b 64 -e types.sizes=true
CMDS=<<EOF
wx 554889e54883ec20ba0400000085ff740aba00010000ebf0909090488d7de031f6e81a000000c9c3
wx c3 @ 0x40
af+ 0x40 memset
afb+ 0x40 0x40 1
'td void *memset(void *s, int c, size_t n);
af @ 0
s 0
aft
afv~var_20h
EOF
EXPECT=<<EOF
var int64_t var_20h @ rbp-0x20
EOF
RUN

NAME=a sibling branch size does not leak into a call on another path
FILE=malloc://128
ARGS=-a x86 -b 64 -e types.sizes=true
CMDS=<<EOF
wx 554889e54883ec2085ff740cba00010000eb149090909090488d7de031f6e81d000000eb029090c9c3
wx c3 @ 0x40
af+ 0x40 memset
afb+ 0x40 0x40 1
'td void *memset(void *s, int c, size_t n);
af @ 0
s 0
aft
afv
EOF
EXPECT=<<EOF
arg int64_t arg1 @ rdi
arg size_t n @ rdx
var int64_t s @ rbp-0x20
EOF
RUN

NAME=disabling the per-block state restore keeps the inherited sibling branch state
FILE=malloc://128
ARGS=-a x86 -b 64 -e types.sizes=true -e types.bbstate=false
CMDS=<<EOF
wx 554889e54883ec2085ff740cba00010000eb149090909090488d7de031f6e81d000000eb029090c9c3
wx c3 @ 0x40
af+ 0x40 memset
afb+ 0x40 0x40 1
'td void *memset(void *s, int c, size_t n);
af @ 0
s 0
aft
afv~var_20h
EOF
EXPECT=<<EOF
var uint8_t [256] var_20h @ rbp-0x20
EOF
RUN

NAME=a loop body value the header never touches is also lost after the loop
FILE=malloc://128
ARGS=-a x86 -b 64 -e types.sizes=true
CMDS=<<EOF2
wx 554889e54883ec20ba0400000085ff7407ba00010000ebf5488d7de031f6e81d000000c9c3
wx c3 @ 0x40
af+ 0x40 memset
afb+ 0x40 0x40 1
'td void *memset(void *s, int c, size_t n);
af @ 0
s 0
aft
afv~var_20h
EOF2
EXPECT=<<EOF2
var int64_t var_20h @ rbp-0x20
EOF2
RUN

NAME=disabling bbstate keeps the loop body value after the loop
FILE=malloc://128
ARGS=-a x86 -b 64 -e types.sizes=true -e types.bbstate=false
CMDS=<<EOF2
wx 554889e54883ec20ba0400000085ff7407ba00010000ebf5488d7de031f6e81d000000c9c3
wx c3 @ 0x40
af+ 0x40 memset
afb+ 0x40 0x40 1
'td void *memset(void *s, int c, size_t n);
af @ 0
s 0
aft
afv~var_20h
EOF2
EXPECT=<<EOF2
var uint8_t [256] var_20h @ rbp-0x20
EOF2
RUN

NAME=td keeps the pointer with the type in function pointer members
FILE=-
CMDS=<<EOF
'td struct S { int (*cb)(int *n, char *s); };
tk~func.S
EOF
EXPECT=<<EOF
func.S.cb=n,s
func.S.cb.arg.0=int *,n
func.S.cb.arg.1=char *,s
func.S.cb.args=2
func.S.cb.cc=cdecl
func.S.cb.ret=int
EOF
RUN

NAME=td stores an empty parameter list as zero arguments
FILE=-
CMDS=<<EOF
'td int voidfn(void);
'td int spacedfn( );
tk~func.voidfn
tk~func.spacedfn
EOF
EXPECT=<<EOF
func.voidfn.args=0
func.voidfn.cc=cdecl
func.voidfn.ret=int
func.spacedfn.args=0
func.spacedfn.cc=cdecl
func.spacedfn.ret=int
EOF
RUN

NAME=td stores a void parameter list on a member as zero arguments
FILE=-
CMDS=<<EOF
'td struct A2 { float (*m)(void); void *x; };
tk~func.A2
EOF
EXPECT=<<EOF
func.A2.m.args=0
func.A2.m.cc=cdecl
func.A2.m.ret=float
EOF
RUN

NAME=tss reports the target word size for pointers
FILE=-
ARGS=-b 64
CMDS=<<EOF
tss int *
tss void *
tss int
EOF
EXPECT=<<EOF
8
8
4
EOF
RUN

NAME=an array of pointers uses the target word size as its stride
FILE=malloc://64
ARGS=-a x86 -b 64 -e asm.sub.var=true
CMDS=<<EOF
wx 48890424488944240848894424104889442418c3
af
"afvt arg_8h int *[4]"
pdf~mov
EOF
EXPECT=<<EOF
|           0x00000000      48890424       mov qword [rsp], rax
|           0x00000004      4889442408     mov qword [arg_8h], rax
|           0x00000009      4889442410     mov qword [arg_8h[1]], rax
|           0x0000000e      4889442418     mov qword [arg_8h[2]], rax
EOF
RUN

NAME=td stores the variadic slot in the canonical ,... form
FILE=-
CMDS=<<EOF
'td int myvarfn(const char *fmt, ...);
tk~func.myvarfn
EOF
EXPECT=<<EOF
func.myvarfn=fmt,...
func.myvarfn.arg.0=const char *,fmt
func.myvarfn.arg.1=,...
func.myvarfn.args=2
func.myvarfn.cc=cdecl
func.myvarfn.ret=int
EOF
RUN

NAME=td parses function pointer parameters in prototypes
FILE=-
CMDS=<<EOF
'td void once(void (*cb)(int));
'td int apply(int (*fn)(int, int), int seed);
'td void qual(void (* const q)(int));
tk~func.once
tk~func.apply
tk~func.qual
EOF
EXPECT=<<EOF
func.once=cb
func.once.arg.0=void (*)(int),cb
func.once.args=1
func.once.cc=cdecl
func.once.ret=void
func.apply=fn,seed
func.apply.arg.0=int (*)(),fn
func.apply.arg.1=int,seed
func.apply.args=2
func.apply.cc=cdecl
func.apply.ret=int
func.qual=q
func.qual.arg.0=void (*)(int),q
func.qual.args=1
func.qual.cc=cdecl
func.qual.ret=void
EOF
RUN

NAME=td keeps a nested function pointer argument in one slot
FILE=-
CMDS=<<EOF
'td struct N { int (*cb)(int (*inner)(int, int), char c); };
tk~func.N
EOF
EXPECT=<<EOF
func.N.cb=inner,c
func.N.cb.arg.0=int (*)(),inner
func.N.cb.arg.1=char,c
func.N.cb.args=2
func.N.cb.cc=cdecl
func.N.cb.ret=int
EOF
RUN
