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

NAME=typelinks
FILE=-
CMDS=<<EOF
e asm.bytes=true
e asm.arch=x86
e asm.bits=64
wx 41574156415541544989f4555389fd4881eca8030000488b3e64488b042528000000488984249803000031c0e82fb30000488d35d54e0100bf0600000
e asm.comments=false
s 2
tl short
sd +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 = 1442089289
            0x0000000c      53             push  rbx
            0x0000000d      89fd           mov   ebp, edi
            0x0000000f      4881eca80300.  sub   rsp, 0x3a8
EOF
RUN

NAME=typelinks 2
FILE=-
CMDS=<<EOF
e asm.bytes=true
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=typelinks- test for tlj json
FILE=-
CMDS=<<EOF
wx 41574156415541544989f4555389fd4881eca8030000488b3e64488b042528000000488984249803000031c0e82fb30000488d35d54e0100bf0600000
s 2
tl short
sd +6
tl int
tlj
EOF
EXPECT=<<EOF
[{"0x00000002":"short"},{"0x00000008":"int"}]
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 = 0
(char *)
0x00000010 = "test"
EOF
RUN

NAME=jni and SoP
FILE=bins/elf/libverifyPass.so
CMDS=<<EOF
e analysis.vars.stackname=true
e asm.bytes=true
e asm.lines.bb=false
aa
s sym.Java_com_app_ndh_NDHActivity_print
to bins/headers/jni.h
tl JNINativeInterface 0x464c457f
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 *
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
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=int32_t,0,0
union.xoo.x.meta=0
union.xoo.y=int32_t,0,0
union.xoo.y.meta=0
union.xoo.z=int32_t,0,0
union.xoo.z.meta=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=tef
FILE=-
CMDS=<<EOF
td "enum FOO { A=1, B=0x100, C=0xFF, D=4, E=5 };"
td "enum BAR { G=0x800, Z=0xEE, P=4, E=5 };"
tef 0x800
tef 0x100
tef 4
tef 0x5
EOF
EXPECT=<<EOF
BAR.G
FOO.B
BAR.P
FOO.D
BAR.E
FOO.E
EOF
RUN

NAME=tej
FILE=-
CMDS=<<EOF
td "enum FOO { A=1, B=0x100, C=0xFF, D=4, E=5 };"
td "enum BAR { G=0x800, Z=0xEE, P=4, E=5 };"
tej FOO
tej BAR
tej
EOF
EXPECT=<<EOF
{"name":"FOO","values":{"A":1,"B":256,"C":255,"D":4,"E":5}}
{"name":"BAR","values":{"G":2048,"Z":238,"P":4,"E":5}}
[{"name":"BAR","values":{"G":2048,"Z":238,"P":4,"E":5}},{"name":"FOO","values":{"A":1,"B":256,"C":255,"D":4,"E":5}}]
EOF
RUN

NAME=tek
FILE=-
CMDS=<<EOF
td "enum FOO { A=1, B=0x100, C=0xFF, D=4, E=5 };"
td "enum BAR { G=0x800, Z=0xEE, P=4, E=5 };"
tek FOO
tek BAR
tek
EOF
EXPECT=<<EOF
enum.FOO.0x100=B
enum.FOO.0x1=A
enum.FOO.0x4=D
enum.FOO.0x5=E
enum.FOO.0xff=C
enum.FOO.A=0x1
enum.FOO.B=0x100
enum.FOO.C=0xff
enum.FOO.D=0x4
enum.FOO.E=0x5
enum.FOO=A,B,C,D,E
enum.BAR.0x4=P
enum.BAR.0x5=E
enum.BAR.0x800=G
enum.BAR.0xee=Z
enum.BAR.E=0x5
enum.BAR.G=0x800
enum.BAR.P=0x4
enum.BAR.Z=0xee
enum.BAR=G,Z,P,E
enum.BAR.0x4=P
enum.BAR.0x5=E
enum.BAR.0x800=G
enum.BAR.0xee=Z
enum.BAR.E=0x5
enum.BAR.G=0x800
enum.BAR.P=0x4
enum.BAR.Z=0xee
enum.BAR=G,Z,P,E
enum.FOO.0x100=B
enum.FOO.0x1=A
enum.FOO.0x4=D
enum.FOO.0x5=E
enum.FOO.0xff=C
enum.FOO.A=0x1
enum.FOO.B=0x100
enum.FOO.C=0xff
enum.FOO.D=0x4
enum.FOO.E=0x5
enum.FOO=A,B,C,D,E
EOF
RUN

NAME=tf and tfk
FILE=-
CMDS=<<EOF
tf write
tfk write
EOF
EXPECT=<<EOF
ssize_t write (int fd, const char * ptr, size_t nbytes);
func.write.arg.0=int,fd
func.write.arg.1=const char *,ptr
func.write.arg.2=size_t,nbytes
func.write.args=3
func.write.ret=ssize_t
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=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
bins/other/error.h:2: warning: #error your compiler doesn't have support to my API
EOF
EXPECT=<<EOF
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]zd street city zip
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 *
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]zd street city zip
EOF
RUN

NAME=t*
FILE=-
CMDS=<<EOF
t-*
tk a=b
t*
EOF
EXPECT=<<EOF
tk a=b
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.archx86
e analysis.arch=x86
e analysis.bits=32
t-*
tk a=b
e asm.arch=x68
e analysis.arch=x86
e analysis.bits=32
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=<<EOF
EOF
EXPECT=<<EOF
foo=func
func.foo.arg.0=int32_t,bar
func.foo.args=1
func.foo.cc=cdecl
func.foo.ret=int32_t
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 = 0
 moo : 
                struct<bar>
   a : 0x00000004 = 0
   b : 0x00000008 = 0
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 = 0
 moo : 
[
                struct<bar>
   a : 0x00000004 = 0
   b : 0x00000008 = 0

                struct<bar>
   a : 0x0000000c = 0
   b : 0x00000010 = 0
]
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=tp
FILE=-
CMDS=<<EOF
td "struct person { int age; char name[10]; }"
s 14
w Carlos
s 10
wx 13
tp person @ 10
tp person 10
EOF
EXPECT=<<EOF
  age : 0x0000000a = 19
 name : 0x0000000e = "Carlos"
  age : 0x0000000a = 19
 name : 0x0000000e = "Carlos"
EOF
RUN

NAME=tpv
FILE=-
CMDS=<<EOF
td "struct s16ui { uint16_t a_u; int16_t b_i; uint16_t c_u; int16_t d_i;}"
td "struct s16iu { int16_t a_i; uint16_t b_u; int16_t c_i; uint16_t d_u;}"
td "struct s32ui { uint32_t e_u; int16_t f_i;}"
td "struct s32iu { int32_t e_i; uint16_t f_u;}"
e asm.bits=16
e cfg.bigendian=true
tpv s16ui 0xcafebabecafebabe
tpv s16iu 0xcafebabecafebabe
tpv s32ui 0xcafebabecafebabe
tpv s32iu 0xcafebabecafebabe
e cfg.bigendian=false
tpv s16ui 0xcafebabecafebabe
tpv s16iu 0xcafebabecafebabe
tpv s32ui 0xcafebabecafebabe
tpv s32iu 0xcafebabecafebabe
e asm.bits=32
e cfg.bigendian=true
tpv s16ui 0xcafebabecafebabe
tpv s16iu 0xcafebabecafebabe
tpv s32ui 0xcafebabecafebabe
tpv s32iu 0xcafebabecafebabe
e cfg.bigendian=false
tpv s16ui 0xcafebabecafebabe
tpv s16iu 0xcafebabecafebabe
tpv s32ui 0xcafebabecafebabe
tpv s32iu 0xcafebabecafebabe
e asm.bits=64
e cfg.bigendian=true
tpv s16ui 0xcafebabecafebabe
tpv s16iu 0xcafebabecafebabe
tpv s32ui 0xcafebabecafebabe
tpv s32iu 0xcafebabecafebabe
e cfg.bigendian=false
tpv s16ui 0xcafebabecafebabe
tpv s16iu 0xcafebabecafebabe
tpv s32ui 0xcafebabecafebabe
tpv s32iu 0xcafebabecafebabe
EOF
EXPECT=<<EOF
 a_u : 0x00000000 = 0xbabe
 b_i : 0x00000002 = 0x0000
 c_u : 0x00000004 = 0x0000
 d_i : 0x00000006 = 0x0000
 a_i : 0x00000000 = 0xbabe
 b_u : 0x00000002 = 0x0000
 c_i : 0x00000004 = 0x0000
 d_u : 0x00000006 = 0x0000
 e_u : 0x00000000 = 3133014016
 f_i : 0x00000004 = 0x0000
 e_i : 0x00000000 = 3133014016
 f_u : 0x00000004 = 0x0000
 a_u : 0x00000000 = 0xbabe
 b_i : 0x00000002 = 0x0000
 c_u : 0x00000004 = 0x0000
 d_i : 0x00000006 = 0x0000
 a_i : 0x00000000 = 0xbabe
 b_u : 0x00000002 = 0x0000
 c_i : 0x00000004 = 0x0000
 d_u : 0x00000006 = 0x0000
 e_u : 0x00000000 = 47806
 f_i : 0x00000004 = 0x0000
 e_i : 0x00000000 = 47806
 f_u : 0x00000004 = 0x0000
 a_u : 0x00000000 = 0xcafe
 b_i : 0x00000002 = 0xbabe
 c_u : 0x00000004 = 0x0000
 d_i : 0x00000006 = 0x0000
 a_i : 0x00000000 = 0xcafe
 b_u : 0x00000002 = 0xbabe
 c_i : 0x00000004 = 0x0000
 d_u : 0x00000006 = 0x0000
 e_u : 0x00000000 = 3405691582
 f_i : 0x00000004 = 0x0000
 e_i : 0x00000000 = 3405691582
 f_u : 0x00000004 = 0x0000
 a_u : 0x00000000 = 0xbabe
 b_i : 0x00000002 = 0xcafe
 c_u : 0x00000004 = 0x0000
 d_i : 0x00000006 = 0x0000
 a_i : 0x00000000 = 0xbabe
 b_u : 0x00000002 = 0xcafe
 c_i : 0x00000004 = 0x0000
 d_u : 0x00000006 = 0x0000
 e_u : 0x00000000 = 3405691582
 f_i : 0x00000004 = 0x0000
 e_i : 0x00000000 = 3405691582
 f_u : 0x00000004 = 0x0000
 a_u : 0x00000000 = 0xcafe
 b_i : 0x00000002 = 0xbabe
 c_u : 0x00000004 = 0xcafe
 d_i : 0x00000006 = 0xbabe
 a_i : 0x00000000 = 0xcafe
 b_u : 0x00000002 = 0xbabe
 c_i : 0x00000004 = 0xcafe
 d_u : 0x00000006 = 0xbabe
 e_u : 0x00000000 = 3405691582
 f_i : 0x00000004 = 0xcafe
 e_i : 0x00000000 = 3405691582
 f_u : 0x00000004 = 0xcafe
 a_u : 0x00000000 = 0xbabe
 b_i : 0x00000002 = 0xcafe
 c_u : 0x00000004 = 0xbabe
 d_i : 0x00000006 = 0xcafe
 a_i : 0x00000000 = 0xbabe
 b_u : 0x00000002 = 0xcafe
 c_i : 0x00000004 = 0xbabe
 d_u : 0x00000006 = 0xcafe
 e_u : 0x00000000 = 3405691582
 f_i : 0x00000004 = 0xbabe
 e_i : 0x00000000 = 3405691582
 f_u : 0x00000004 = 0xbabe
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 = 16
EOF
RUN

NAME=aht and arm
FILE=-
CMDS=<<EOF
e asm.bytes=true
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.bytes=true
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.bytes=true
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.bytes=true
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.bytes=true
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.bytes=true
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
/ fcn.00000000 ();
|           0x00000000      48c7c0000100.  mov   rax, 0x100
|           0x00000007      488b5008       mov   rdx, qword [rax + foo.c]
|           0x0000000b      488b4804       mov   rcx, qword [rax + foo.b]
|           0x0000000f      48c7c0000200.  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.bytes=true
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      488d8520ffff.  lea   rax, [Books]
|           0x00000695      488910         mov   qword [rax], rdx      ; Books.title
|           0x00000698      488d8520ffff.  lea   rax, [Books]
|           0x000006ad      488908         mov   qword [rax], rcx      ; Books.author
|           0x000006b0      488d8520ffff.  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
e asm.bytes=true
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      c74204070000.  mov   dword [edx + Test.b], 7
EOF
RUN

NAME=Basic union test
FILE=bins/elf/union_sample
CMDS=<<EOF
e asm.bytes=true
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 [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 @ 0xc
td "struct foo {int x; int (*fp)(int a , int b ); char *b;};"
ts foo
.ts foo
EOF
EXPECT=<<EOF
pf dpz x fp b
  x : 0x00000000 = 0
 fp : 0x00000004 = (qword)0x0000000000000000
  b : 0x0000000c = "\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 {
	int32_t 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 {
	int32_t x;
	char y[50];
	float z;
};
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=ted test
FILE=-
CMDS=<<EOF
td "enum Foo {COW=1,BAR=2};"
ted 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 {
	int32_t x;
	int32_t y;
	int32_t 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 {int32_t x; int32_t y; int32_t z;};
struct three_elements {int32_t 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/12272.h
ts A
ts B
ts O  # Broken but shouldn't hang
?e ----
tk~typedef.A=,typedef.B=,typedef.O=,struct.A,struct.B,struct.O
?e
ts~A,B,O
EOF
EXPECT=<<EOF
pf dF num num2
pf c ch
----
struct.A=num
struct.A.num=float,0,0
struct.A.num.meta=9
struct.O=ptr
struct.O.ptr=char *,0,0
struct.O.ptr.meta=4
typedef.A=struct
typedef.B=struct
typedef.O=struct O

A
B
O
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 size_t size @ rbp-0x14
var char * dest @ rbp-0x10
var char * src @ rbp-0x8
EOF
RUN

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

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

NAME=General type propgation
FILE=bins/elf/hello_world
CMDS=<<EOF
aa
s main
aaft
afv
EOF
EXPECT=<<EOF
var size_t var_20h @ rbp-0x20
var size_t size @ rbp-0x1c
var char * src @ rbp-0x18
var char * s2 @ rbp-0x10
var char * dest @ rbp-0x8
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 char * src @ ebp-0x1c
var char * s2 @ ebp-0x18
var size_t var_14h @ ebp-0x14
var size_t size @ ebp-0x10
var char * dest @ ebp-0xc
var int32_t var_8h @ ebp-0x8
EOF
RUN

NAME=Register based var
FILE=bins/elf/arg
CMDS=<<EOF
aa
s sym.funcarg
afvr
EOF
EXPECT=<<EOF
arg int64_t arg4 @ rcx
arg int64_t arg3 @ rdx
arg int64_t arg2 @ rsi
arg int64_t arg1 @ rdi
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 size_t arg4 @ rcx
arg int64_t arg3 @ rdx
arg char * arg2 @ rsi
arg char * arg1 @ rdi
EOF
RUN

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

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

NAME=Type Propagation
FILE=bins/pe/debugme.exe
BROKEN=1
CMDS=<<EOF
aaaa
pd 1 @ 0x00401792~?[n
pd 1 @ 0x00401796~?[c
pd 1 @ 0x0040179e~?[s
pd 1 @ 0x004017b1~?[n
pd 1 @ 0x004017b5~?[c
pd 1 @ 0x004017bd~?[s
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 int64_t var_34h @ rbp-0x34
var signed int64_t var_30h @ rbp-0x30
var uint32_t var_28h @ rbp-0x28
EOF
RUN

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

NAME=bashbot test (arm 32-bits)
FILE=bins/elf/bashbot.arm.gcc.O0.elf
CMDS=<<EOF
e analysis.vars.stackname=true
s main
af
aaft
afv
EOF
EXPECT=<<EOF
var int32_t var_1454h @ sp+0x0
var void * var_1438h @ fp-0x1440
var char * s1 @ fp-0x1040
var int32_t wstatus @ fp-0x4c
var int32_t var_40h @ fp-0x48
var char * var_3ch @ fp-0x44
var int32_t var_38h @ fp-0x40
var int32_t var_34h @ fp-0x3c
var int32_t var_30h @ fp-0x38
var pid_t pid @ fp-0x34
var char * v2 @ fp-0x30
var int32_t var_24h @ fp-0x2c
var char * src @ fp-0x28
var int32_t var_1ch @ fp-0x24
var char * var_18h @ fp-0x20
var char * s @ fp-0x1c
var char * var_10h @ fp-0x18
var int32_t var_ch @ fp-0x14
var int32_t var_8h @ fp-0x10
var char * option @ fp-0xc
arg int argc @ r0
arg char ** argv @ r1
EOF
RUN

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

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

NAME=constrained type
FILE=bins/elf/constr_type
CMDS=<<EOF
e analysis.types.constraint=true
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 int64_t var_4h  { > 0xa} @ rbp-0x4
|           ; var signed int64_t var_14h  { > 0x0 && <= 0x9} @ rbp-0x14
|           ; var signed int64_t var_4h  { > 0x64 && <= 0xc7} @ rbp-0x4
|           ; var signed int64_t var_4h  { > 0xff && <= 0x12b || > 0x14 && <= 0x31 || > 0x6f && <= 0xdd} @ rbp-0x4
EOF
RUN

NAME=mov str
FILE=bins/elf/movstr
CMDS=<<EOF
e analysis.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=int32_t,0,0
struct.s1.a.meta=0
struct.s1.b=int32_t,8,0
struct.s1.b.meta=0
struct.s1.size=int32_t,4,0
struct.s1.size.meta=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.arg.0=int32_t,argc
func.main.args=1
func.main.cc=cdecl
func.main.ret=int32_t
EOF
RUN

NAME=afs without type
FILE=bins/elf/analysis/pid_stripped
CMDS=<<EOF
e analysis.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);
int32_t no_type (int32_t a, char **b);
char type (int32_t 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 arg3);
int32_t foo.bar ();
char foo.bar (int32_t 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
tn 8
tn
tn- 0x8
tn
tn-*
tn
EOF
EXPECT=<<EOF
0x8
ExitProcess
ExitThread
FatalExit
FreeLibraryAndExitThread
RaiseException
RtlRaiseException
ExitProcess
ExitThread
FatalExit
FreeLibraryAndExitThread
RaiseException
RtlRaiseException
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 dc a b
tk foo=union
tk union.foo=a,b
tk union.foo.a=int32_t,0,0
tk union.foo.a.meta=0
tk union.foo.b=char,0,0
tk union.foo.b.meta=2
pf dc a b
pf.foo dc 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 = 4000
 b : 0x00000004 = 8000
 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 =
tx size_t
?e =
tx "size_t *"
EOF
EXPECT=<<EOF
int
char **
int64_t
char *
=
uint32_t
int64_t
char *
size_t *
size_t
void *
wint_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.bytes=true
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      c74004000000.  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
