NAME=PE JSON test
FILE=bins/pe/ch22.exe
ARGS=-nn
CMDS=<<EOF
e asm.arch=x86
e asm.bits=32
s 0x80
pfj pe_nt_image_headers32
EOF
EXPECT=<<EOF
[{"name":"signature","type":"char*","offset":128,"encoding":"utf8","value":"PE"},{"name":"fileHeader","type":"unknown","offset":132,"struct_type":"pe_image_file_header","fields":[{"name":"machine","type":"enum","size":4,"offset":132,"value":332},{"name":"numberOfSections","type":"hex","size":2,"offset":134,"endian":"little","value":4},{"name":"timeDateStamp","type":"timestamp","size":4,"offset":136,"endian":"little","timefmt":"unix32","raw":1410459706,"value":"2014-09-11 18:21:46 UTC"},{"name":"pointerToSymbolTable","type":"hex","size":4,"offset":140,"endian":"little","value":0},{"name":"numberOfSymbols","type":"hex","size":4,"offset":144,"endian":"little","value":0},{"name":"sizeOfOptionalHeader","type":"hex","size":2,"offset":148,"endian":"little","value":224},{"name":"characteristics","type":"bitfield","size":4,"offset":150,"value":258}]},{"name":"optionalHeader","type":"unknown","offset":152,"struct_type":"pe_image_optional_header32","fields":[{"name":"magic","type":"enum","size":4,"offset":152,"value":267},{"name":"majorLinkerVersion","type":"hex","size":1,"offset":154,"endian":"little","value":11},{"name":"minorLinkerVersion","type":"hex","size":1,"offset":155,"endian":"little","value":0},{"name":"sizeOfCode","type":"hex","size":4,"offset":156,"endian":"little","value":12288},{"name":"sizeOfInitializedData","type":"hex","size":4,"offset":160,"endian":"little","value":13312},{"name":"sizeOfUninitializedData","type":"hex","size":4,"offset":164,"endian":"little","value":0},{"name":"addressOfEntryPoint","type":"hex","size":4,"offset":168,"endian":"little","value":20286},{"name":"baseOfCode","type":"hex","size":4,"offset":172,"endian":"little","value":8192},{"name":"baseOfData","type":"hex","size":4,"offset":176,"endian":"little","value":24576},{"name":"imageBase","type":"hex","size":4,"offset":180,"endian":"little","value":4194304},{"name":"sectionAlignment","type":"hex","size":4,"offset":184,"endian":"little","value":8192},{"name":"fileAlignment","type":"hex","size":4,"offset":188,"endian":"little","value":512},{"name":"majorOperatingSystemVersion","type":"hex","size":2,"offset":192,"endian":"little","value":4},{"name":"minorOperatingSystemVersion","type":"hex","size":2,"offset":194,"endian":"little","value":0},{"name":"majorImageVersion","type":"hex","size":2,"offset":196,"endian":"little","value":0},{"name":"minorImageVersion","type":"hex","size":2,"offset":198,"endian":"little","value":0},{"name":"majorSubsystemVersion","type":"hex","size":2,"offset":200,"endian":"little","value":6},{"name":"minorSubsystemVersion","type":"hex","size":2,"offset":202,"endian":"little","value":0},{"name":"win32VersionValue","type":"hex","size":4,"offset":204,"endian":"little","value":0},{"name":"sizeOfImage","type":"hex","size":4,"offset":208,"endian":"little","value":57344},{"name":"sizeOfHeaders","type":"hex","size":4,"offset":212,"endian":"little","value":1024},{"name":"checkSum","type":"hex","size":4,"offset":216,"endian":"little","value":0},{"name":"subsystem","type":"enum","size":4,"offset":220,"value":2},{"name":"dllCharacteristics","type":"bitfield","size":4,"offset":222,"value":34144},{"name":"sizeOfStackReserve","type":"hex","size":4,"offset":224,"endian":"little","value":1048576},{"name":"sizeOfStackCommit","type":"hex","size":4,"offset":228,"endian":"little","value":4096},{"name":"sizeOfHeapReserve","type":"hex","size":4,"offset":232,"endian":"little","value":1048576},{"name":"sizeOfHeapCommit","type":"hex","size":4,"offset":236,"endian":"little","value":4096},{"name":"loaderFlags","type":"hex","size":4,"offset":240,"endian":"little","value":0},{"name":"numberOfRvaAndSizes","type":"hex","size":4,"offset":244,"endian":"little","value":16},{"name":"dataDirectory","type":"unknown","offset":248,"struct_type":"pe_image_data_directory","fields":[{"name":"virtualAddress","type":"hex","size":4,"offset":248,"endian":"little","value":0},{"name":"size","type":"hex","size":4,"offset":252,"endian":"little","value":0},{"name":"virtualAddress","type":"hex","size":4,"offset":256,"endian":"little","value":20208},{"name":"size","type":"hex","size":4,"offset":260,"endian":"little","value":75},{"name":"virtualAddress","type":"hex","size":4,"offset":264,"endian":"little","value":32768},{"name":"size","type":"hex","size":4,"offset":268,"endian":"little","value":11840},{"name":"virtualAddress","type":"hex","size":4,"offset":272,"endian":"little","value":0},{"name":"size","type":"hex","size":4,"offset":276,"endian":"little","value":0},{"name":"virtualAddress","type":"hex","size":4,"offset":280,"endian":"little","value":0},{"name":"size","type":"hex","size":4,"offset":284,"endian":"little","value":0},{"name":"virtualAddress","type":"hex","size":4,"offset":288,"endian":"little","value":49152},{"name":"size","type":"hex","size":4,"offset":292,"endian":"little","value":12},{"name":"virtualAddress","type":"hex","size":4,"offset":296,"endian":"little","value":24576},{"name":"size","type":"hex","size":4,"offset":300,"endian":"little","value":28},{"name":"virtualAddress","type":"hex","size":4,"offset":304,"endian":"little","value":0},{"name":"size","type":"hex","size":4,"offset":308,"endian":"little","value":0},{"name":"virtualAddress","type":"hex","size":4,"offset":312,"endian":"little","value":0},{"name":"size","type":"hex","size":4,"offset":316,"endian":"little","value":0},{"name":"virtualAddress","type":"hex","size":4,"offset":320,"endian":"little","value":0},{"name":"size","type":"hex","size":4,"offset":324,"endian":"little","value":0},{"name":"virtualAddress","type":"hex","size":4,"offset":328,"endian":"little","value":0},{"name":"size","type":"hex","size":4,"offset":332,"endian":"little","value":0},{"name":"virtualAddress","type":"hex","size":4,"offset":336,"endian":"little","value":0},{"name":"size","type":"hex","size":4,"offset":340,"endian":"little","value":0},{"name":"virtualAddress","type":"hex","size":4,"offset":344,"endian":"little","value":8192},{"name":"size","type":"hex","size":4,"offset":348,"endian":"little","value":8},{"name":"virtualAddress","type":"hex","size":4,"offset":352,"endian":"little","value":0},{"name":"size","type":"hex","size":4,"offset":356,"endian":"little","value":0},{"name":"virtualAddress","type":"hex","size":4,"offset":360,"endian":"little","value":8200},{"name":"size","type":"hex","size":4,"offset":364,"endian":"little","value":72},{"name":"virtualAddress","type":"hex","size":4,"offset":368,"endian":"little","value":0},{"name":"size","type":"hex","size":4,"offset":372,"endian":"little","value":0}]}]}]
EOF
RUN

NAME=JSON output
FILE=malloc://1024
CMDS=<<EOF
e asm.arch=x86
e asm.bits=32
wx 341289679a020000a00f00002a003000000014426416
wx 800600000040 @ 0x20
wx 14000000641620000000 @ 0x30
pfn troll "d4x2*? integer word (troll)Bah"
pfn plop "d4?x2 first (troll)Boh bwa"
pfn gobelin "2x2x2?x4 blah meh (plop)Buh foo"
pfj gobelin
EOF
EXPECT=<<EOF
[{"name":"blah","type":"hex","size":2,"offset":0,"endian":"little","value":4660},{"name":"meh","type":"hex","size":2,"offset":2,"endian":"little","value":26505},{"name":"Buh","type":"unknown","offset":4,"struct_type":"plop","fields":[{"name":"first","type":"signed","size":4,"offset":4,"endian":"little","value":666},{"name":"Boh","type":"unknown","offset":8,"struct_type":"troll","fields":[{"name":"integer","type":"signed","size":4,"offset":8,"endian":"little","value":4000},{"name":"word","type":"hex","size":2,"offset":12,"endian":"little","value":42},{"name":"Bah","type":"unknown","offset":14,"pointer":48}]},{"name":"bwa","type":"hex","size":2,"offset":18,"endian":"little","value":16916}]},{"name":"foo","type":"hex","size":4,"offset":20,"endian":"little","value":5732},{"name":"blah","type":"hex","size":2,"offset":24,"endian":"little","value":0},{"name":"meh","type":"hex","size":2,"offset":26,"endian":"little","value":0},{"name":"Buh","type":"unknown","offset":28,"struct_type":"plop","fields":[{"name":"first","type":"signed","size":4,"offset":28,"endian":"little","value":0},{"name":"Boh","type":"unknown","offset":32,"struct_type":"troll","fields":[{"name":"integer","type":"signed","size":4,"offset":32,"endian":"little","value":1664},{"name":"word","type":"hex","size":2,"offset":36,"endian":"little","value":16384},{"name":"Bah","type":"unknown","offset":38,"pointer":0}]},{"name":"bwa","type":"hex","size":2,"offset":42,"endian":"little","value":0}]},{"name":"foo","type":"hex","size":4,"offset":44,"endian":"little","value":0}]
EOF
RUN

NAME=access specific element through nested struct
FILE=malloc://1024
CMDS=<<EOF
e asm.arch=x86
e asm.bits=32
wx 341289679a020000a00f00002a003000000014426416
wx 800600000040 @ 0x20
wx 14000000641620000000 @ 0x30
pfn troll "d4x2*? integer word (troll)Bah"
pfn plop "d4?x2 first (troll)Boh bwa"
pfn gobelin "x2x2?x4 blah meh (plop)Buh foo"
pf. gobelin.Buh.first
pf. gobelin.Buh.Boh.word
EOF
EXPECT=<<EOF
0x00000004 : first = 666 [LE]
0x0000000c : word = 0x002a [LE]
EOF
RUN

NAME=access specific element in an array
FILE=malloc://1024
CMDS=<<EOF
e asm.arch=x86
e asm.bits=32
wx a00f0000adde @ 0x10
pfn plop "d4x2x8x2 one two three four"
pfn troll "[3]? (plop)str"
pf. troll.str[1]
pf. troll.str[1].two
EOF
EXPECT=<<EOF
0x00000010 :   one = 4000 [LE]
0x00000014 :   two = 0xdead [LE]
0x00000016 : three = 0x0000000000000000 [LE]
0x0000001e :  four = 0x0000 [LE]
0x00000014 : two = 0xdead [LE]
EOF
RUN

NAME=Complex request with specific array element and specific field
FILE=bins/pe/ch22.exe
ARGS=-nn
CMDS=<<EOF
e asm.arch=x86
e asm.bits=32
s 0x80
pf. pe_dos_header.e_res[2]
pf. pe_dos_header.e_res2[8]
EOF
EXPECT=<<EOF
0x000000a0 : e_res = 0x3400 [LE]
0x000000b8 : e_res2 = 0x2000 [LE]
EOF
RUN

NAME=write specific element through nested struct
FILE=malloc://1024
CMDS=<<EOF
e asm.arch=x86
e asm.bits=32
wx 341289679a020000a00f00002a003000000014426416
wx 800600000040 @ 0x20
wx 14000000641620000000 @ 0x30
pfn troll "d4x2*? integer word (troll)Bah"
pfn plop "d4?x2 first (troll)Boh bwa"
pfn gobelin "x2x2?x4 blah meh (plop)Buh foo"
pfw gobelin.Buh.first=42
pfw gobelin.Buh.first=42
pfw gobelin.Buh.Boh.Bah.Bah.word=0xadde
pfw gobelin.Buh.Boh.Bah.Bah.word=0xadde
pf. gobelin
EOF
EXPECT=<<EOF
Buh.first : 0x00000004 = 42
Buh.first : 0x00000004 = 42
Buh.Boh.Bah.Bah.word : 0x00000024 = 44510
Buh.Boh.Bah.Bah.word : 0x00000024 = 44510
0x00000000 : blah = 0x1234 [LE]
0x00000002 :  meh = 0x6789 [LE]
0x00000004 :  Buh = struct<plop> {
   0x00000004 : first = 42 [LE]
   0x00000008 :   Boh = struct<troll> {
      0x00000008 : integer = 4000 [LE]
      0x0000000c :    word = 0x002a [LE]
      0x0000000e :     Bah = (*0x30) struct<troll> {
         0x00000030 : integer = 20 [LE]
         0x00000034 :    word = 0x1664 [LE]
         0x00000036 :     Bah = (*0x20) struct<troll> {
            0x00000020 : integer = 1664 [LE]
            0x00000024 :    word = 0xadde [LE]
            0x00000026 :     Bah = (*0x0)
         }
      }
   }
   0x00000012 :   bwa = 0x4214 [LE]
}
0x00000014 :  foo = 0x00001664 [LE]
EOF
RUN

NAME=print anonymous nested struct
FILE=malloc://1024
# Inline anonymous struct definitions like `?(format inner_names)field` are a
# legacy quirk: the `?` typename is itself a parenthesised format+names string.
# The new parser does not recurse into them (it only expands
# typedb-registered struct names), so the nested `(pf ...)` is rendered as a
# plain field instead of being expanded. This test locks in that behavior.
CMDS=<<EOF
e asm.arch=x86
e asm.bits=32
wx 71776572747975696f706173646667686a6b6c7a786376626e6d71776572747975696f706173646667686a6b6c7a786376626e6d
pfn dsf "d4d4 a b"
pfn abc "d4c...?d4 a b (pf i?i a (dsf)b c)c d"
pfn def "d4c...*?d4 a b (pf i?i a (dsf)b c)c d"
pf. abc
pf. def
EOF
EXPECT=<<EOF
0x00000000 :   a = 1919252337 [LE]
0x00000004 :   b = 't'
0x00000008 : (pf =
0x00000008 : i?i = 1935765615 [LE]
0x00000000 :   a = 1919252337 [LE]
0x00000004 :   b = 't'
0x00000008 : (pf = (*0x7361706f)
0x0000000c : i?i = 1751606884 [LE]
EOF
RUN

NAME=pf field name
FILE=malloc://1024
CMDS=<<EOF
e asm.arch=x86
pf 2x x2
EOF
EXPECT=<<EOF
0x00000000 : x2 = 0x00000000 [LE]
0x00000004 : x2 = 0x00000000 [LE]
EOF
RUN

NAME=pf *z (64bit addr)
FILE==
CMDS=<<EOF
e asm.arch=arm
e asm.bits=64
e io.cache=true
e cfg.bigendian=false
wz root @ 0x0000000100000faf
pf z @ 0x0000000100000faf
e cfg.bigendian=false
16wx cc @ 0x200 @e:cfg.wseek=true
wv8 0x0000000100000faf @ 0x204
pf *z @ 0x204
e cfg.bigendian=true
16wx cc @ 0x200 @e:cfg.wseek=true
wv8 0x0000000100000faf @ 0x204
pf *z @ 0x204
EOF
EXPECT=<<EOF
0x100000faf = "root"
0x00000204 = (*0x100000faf) "root"
0x00000204 = (*0x100000faf) "root"
EOF
RUN

NAME=pf F max precision (#13027)
# Issue #13027 was about losing precision when rendering doubles --
# the fix landed in the legacy parser. The new parser keeps that
# precision (17 significant digits). The numeric values here differ
# from the original #13027 expected output because the legacy `F`
# specifier read bytes as LE-then-reinterpret, while the new parser
# follows the documented "UPPERCASE = BE" rule literally; the bytes
# on disk (LE-written via `wv8`) therefore decode to a different but
# correct BE double. The precision -- the actual subject of the
# test -- is unchanged.
FILE==
CMDS=<<EOF
e asm.arch=x86
wv8 0x400921fb54442d18
pf F
echo
wv8 0x3e901b2b20000000
pf x8
pf F
EOF
EXPECT=<<EOF
0x00000000 = 3.2073756306763658e-192 [BE]

0x00000000 = 0x3e901b2b20000000 [LE]
0x00000000 = 6.8261186770596929e-313 [BE]
EOF
RUN

NAME=pf f max precision
FILE==
CMDS=<<EOF
e asm.arch=x86
wv4 0x40490fdb
pf f
EOF
EXPECT=<<EOF
0x00000000 = 3.14159274 [LE]
EOF
RUN

NAME=pfj z not-at-start fix
FILE==
CMDS=<<EOF
e asm.arch=x86
wx 46
wz ABCDE @ 0x1
pf x1z
pfj bz
EOF
EXPECT=<<EOF
0x00000000 = 0x46 [LE]
0x00000001 = "ABCDE"
[{"type":"binary","size":1,"offset":0,"endian":"little","value":70},{"type":"char*","offset":1,"encoding":"utf8","value":"ABCDE"}]
EOF
RUN

NAME=pf/pfj z with size
FILE==
CMDS=<<EOF
e asm.arch=x86
wz ABCDE
(pf2 format; pf ${format}; pfj ${format})
.(pf2 z)
echo
.(pf2 [3]z)
echo
.(pf2 [7]z)
EOF
EXPECT=<<EOF
0x00000000 = "ABCDE"
[{"type":"char*","offset":0,"encoding":"utf8","value":"ABCDE"}]

0x00000000 = "ABC"
[{"type":"char*","offset":0,"encoding":"utf8","value":"ABC"}]

0x00000000 = "ABCDE"
[{"type":"char*","offset":0,"encoding":"utf8","value":"ABCDE"}]
EOF
RUN

NAME=pf z overflow
FILE=malloc://2048
ARGS=-m 1000
CMDS=<<EOF
e asm.arch=x86
e io.cache=false
echo --- io.unalloc = true ---
echo
e io.unalloc=true
e io.va=true
s 3046
w AB
pf [2]z
pf z
pf [5]z
pf z @ 0xfffff
echo
e io.va=false
s 2046
pf [2]z
pf z
pf [5]z
pf z @ 0xfffff
echo
e io.va=true
oml
echo ----
om-*
om 3 1000 1024 0 rwx
om 3 2024 1024 1024 rwx
oml
wz CD @ 2023
pf z @ 2023
echo ----
om- 2
om 3 2024 1024 1024 -wx
oml
pf z @ 2023
echo ----
om- 2
oml
pf z @ 2023
om-*
EOF
EXPECT=<<EOF
--- io.unalloc = true ---

0x00000be6 = "AB"
0x00000be6 = ovf "AB"
0x00000be6 = ovf "AB"
0x000fffff = ovf ""

0x000007fe = "AB"
0x000007fe = ovf "AB"
0x000007fe = ovf "AB"
0x000fffff = ovf ""

 1 fd: 3 +0x00000000 0x000003e8 * 0x00000be7 rwx 
----
 1 fd: 3 +0x00000000 0x000003e8 - 0x000007e7 rwx 
 2 fd: 3 +0x00000400 0x000007e8 * 0x00000be7 rwx 
0x000007e7 = "CD"
----
 1 fd: 3 +0x00000000 0x000003e8 - 0x000007e7 rwx 
 2 fd: 3 +0x00000400 0x000007e8 * 0x00000be7 -wx 
0x000007e7 = ovf "C"
----
 1 fd: 3 +0x00000000 0x000003e8 - 0x000007e7 rwx 
0x000007e7 = ovf "C"
EOF
RUN

NAME=pfj z overflow
FILE=malloc://2048
ARGS=-m 1000
CMDS=<<EOF
e asm.arch=x86
e io.unalloc=true
s 3046
w AB
pfj [2]z
pfj z
pfj [5]z
pfj z @ 0xfffff
e io.unalloc=false
pfj z @ 0xfffff
EOF
EXPECT=<<EOF
[{"type":"char*","offset":3046,"encoding":"utf8","value":"AB"}]
[{"type":"char*","offset":3046,"encoding":"utf8","value":"AB"}]
[{"type":"char*","offset":3046,"encoding":"utf8","value":"AB"}]
[{"type":"char*","offset":1048575,"encoding":"utf8","value":""}]
[{"type":"char*","offset":1048575,"encoding":"utf8","value":""}]
EOF
RUN

NAME=pfn
FILE==
CMDS=<<EOF
e asm.arch=x86
pfo elf32
pfn elf_header
pfn cat_sat_on_keyboard
EOF
EXPECT=<<EOF
?[2]E[2]E[4]En4n4n4n4n2n2n2n2n2n2 (elf_ident)ident (elf_type)type (elf_machine)machine (elf_obj_version)version entry phoff shoff flags ehsize phentsize phnum shentsize shnum shstrndx
EOF
EXPECT_ERR=<<EOF
ERROR: Format with "cat_sat_on_keyboard" name not found
EOF
RUN

NAME=-nn filename with @
FILE=bins/elf/analysis/tiny1@invalid_addr
ARGS=-nn
CMDS=<<EOF
e asm.arch=x86
e io.va=0
pf. elf_header @ elf_header
EOF
EXPECT=<<EOF
0x00000000 :     ident = struct<elf_ident> {
   0x00000000 :   magic = "\x7fELF"
   0x00000004 :   class = 0x00000001 ; ELFCLASS32
   0x00000005 :    data = 0x00000001 ; ELFDATA2LSB
   0x00000006 : version = 0x00000001 ; EV_CURRENT
}
0x00000010 :      type = 0x00000002 ; ET_EXEC
0x00000012 :   machine = 0x00000003 ; EM_386
0x00000014 :   version = 0x00000001 ; EV_CURRENT
0x00000018 :     entry = 0x08048054
0x0000001c :     phoff = 0x00000034
0x00000020 :     shoff = 0x00000000
0x00000024 :     flags = 0x00000000
0x00000028 :    ehsize = 0x0034
0x0000002a : phentsize = 0x0020
0x0000002c :     phnum = 0x0001
0x0000002e : shentsize = 0x0000
0x00000030 :     shnum = 0x0000
0x00000032 :  shstrndx = 0x0000
EOF
RUN

NAME=pfc sized hex
FILE==
ARGS=-a x86 -b 64
CMDS=<<EOF
(wneg num size; wv${size} -${num}; sd +${size})
.(wneg 1 1)
.(wneg 2 2)
.(wneg 3 4)
.(wneg 4 8)
s 0
pfc X1X2X4X8 byte word dword qword
pfc x1x2x4x8 byte word dword qword
pfc n1n2n4n8 byte word dword qword
EOF
EXPECT=<<EOF
struct {
    uint8_t byte; /* big, 0xff */
    uint16_t word; /* big, 0xfeff */
    uint32_t dword; /* big, 0xfdffffff */
    uint64_t qword; /* big, 0xfcffffffffffffff */
};
struct {
    uint8_t byte; /* little, 0xff */
    uint16_t word; /* little, 0xfffe */
    uint32_t dword; /* little, 0xfffffffd */
    uint64_t qword; /* little, 0xfffffffffffffffc */
};
struct {
    uint8_t byte; /* 0xff */
    uint16_t word; /* 0xfffe */
    uint32_t dword; /* 0xfffffffd */
    uint64_t qword; /* 0xfffffffffffffffc */
};
EOF
RUN
