NAME=/ad/ search instructions extended regex
FILE=bins/pe/standard.exe
CMDS=<<EOF
e asm.arch = x86
e anal.arch = x86
e asm.bits=32
"/ad/ ror (bh|...), (cl|.)"
q
EOF
EXPECT=<<EOF
0x004019d2                 d3cc  ror esp, cl
0x004019d5                 d0cf  ror bh, 1
0x004019da               c1cde5  ror ebp, 0xe5
EOF
RUN

NAME=/ad/ regex skips immediate range parsing
FILE=malloc://1
ARGS=-a x86 -b 64
CMDS=<<EOF
wx 90
"/ad/ 2|nop 1|nop"
q
EOF
EXPECT=<<EOF
0x00000000                   90  nop
EOF
EXPECT_ERR=
RUN

NAME=/ad/ invalid regex reports an error
FILE=malloc://1
ARGS=-a x86 -b 64
CMDS=<<EOF
wx 90
"/ad/ ("
q
EOF
EXPECT=
EXPECT_ERR=<<EOF
ERROR: Invalid regexp: (
EOF
RUN

NAME=/ad rejects unknown modifiers
FILE=malloc://1
ARGS=-a x86 -b 64
CMDS=<<EOF
wx 90
"/adZ nop"
q
EOF
EXPECT=
EXPECT_ERR=<<EOF
ERROR: Invalid `Z` subcommand, try `/ad?`
EOF
RUN

NAME=/ad/ modifier order is independent
FILE=malloc://1
ARGS=-a x86 -b 64
CMDS=<<EOF
wx 90
"/ad/aj nop"
"/ad/ja nop"
q
EOF
EXPECT=<<EOF
[{"addr":0,"len":1,"code":"nop"}]
[{"addr":0,"len":1,"code":"nop"}]
EOF
EXPECT_ERR=
RUN

NAME=/ad rejects duplicate and conflicting modifiers
FILE=malloc://1
ARGS=-a x86 -b 64
CMDS=<<EOF
wx 90
"/ad/aa nop"
"/ad/jq nop"
q
EOF
EXPECT=
EXPECT_ERR=<<EOF
ERROR: Invalid `a` subcommand, try `/ad?`
ERROR: Invalid `q` subcommand, try `/ad?`
EOF
RUN

NAME=/ad/ search multiple instructions
FILE=bins/pe/standard.exe
CMDS=<<EOF
e asm.arch = x86
e anal.arch = x86
e asm.bits=32
"/ad/ ror bh, 1; shr ebp, cl; clc"
q
EOF
EXPECT=<<EOF
0x004019d5                 d0cf  ror bh, 1
0x004019d7                 d3ed  shr ebp, cl
0x004019d9                   f8  clc
EOF
RUN

NAME=/ad/ search empty next instruction regex
FILE=malloc://2
ARGS=-a x86 -b 64
CMDS=<<EOF
wx 90c3
'/ad/ nop;
q
EOF
EXPECT=<<EOF
0x00000000                   90  nop
0x00000001                   c3  ret
EOF
RUN

NAME=/ad/ search with escaped instruction separator
FILE=malloc://2
ARGS=-a x86 -b 64
CMDS=<<EOF
wx 90c3
/ad/ nop\;ret
q
EOF
EXPECT=<<EOF
0x00000000                   90  nop
0x00000001                   c3  ret
EOF
RUN

NAME=/ad/ search overlapping instruction sequence
FILE=malloc://3
ARGS=-a x86 -b 64
CMDS=<<EOF
wx 9090c3
"/ad/ nop;ret"
q
EOF
EXPECT=<<EOF
0x00000001                   90  nop
0x00000002                   c3  ret
EOF
RUN

NAME=/ad/ search instruction sequence across blocks
FILE=malloc://4098
ARGS=-a x86 -b 64
CMDS=<<EOF
wx 90c3 @ 0xfff
"/ad/ nop;ret"
q
EOF
EXPECT=<<EOF
0x00000fff                   90  nop
0x00001000                   c3  ret
EOF
RUN

NAME=/ad/ decodes instructions across blocks
FILE=malloc://4098
ARGS=-a x86 -b 64
CMDS=<<EOF
wx cc @ 0
wx 6690 @ 0xfff
"/ad/ nop"
q
EOF
EXPECT=<<EOF
0x00000fff                 6690  nop
EOF
RUN

NAME=/ad/ retries overlapping matches across blocks
FILE=malloc://4100
ARGS=-a x86 -b 64
CMDS=<<EOF
wx cc
wx 9090909090c3 @ 0xffd
"/ad/j nop;nop;nop"
"/ad/j nop;nop;ret"
EOF
EXPECT=<<EOF
[{"addr":4093,"len":3,"code":"nop; nop; nop"},{"addr":4094,"len":3,"code":"nop; nop; nop"},{"addr":4095,"len":3,"code":"nop; nop; nop"}]
[{"addr":4096,"len":3,"code":"nop; nop; ret"}]
EOF
EXPECT_ERR=
RUN

NAME=/ad/a resumes after a spanning instruction before retrying each byte
FILE=malloc://4098
ARGS=-a x86 -b 64
CMDS=<<EOF
wx cc
wx 6690c3 @ 0xfff
"/ad/aj nop;ret"
EOF
EXPECT=<<EOF
[{"addr":4095,"len":3,"code":"nop; ret"},{"addr":4096,"len":2,"code":"nop; ret"}]
EOF
EXPECT_ERR=
RUN

NAME=/ad/ block retries preserve alignment and maxhits
FILE=malloc://4100
ARGS=-a x86 -b 64
CMDS=<<EOF
wx cc
wx 9090909090c3 @ 0xffd
e search.align=2
"/ad/j nop;nop;nop"
e search.align=0
e search.maxhits=1
"/ad/j nop;nop;nop"
EOF
EXPECT=<<EOF
[{"addr":4094,"len":3,"code":"nop; nop; nop"}]
[{"addr":4093,"len":3,"code":"nop; nop; nop"}]
EOF
EXPECT_ERR=
RUN

NAME=/ad obeys global search.maxhits across maps
FILE=malloc://1
ARGS=-a x86 -b 64
CMDS=<<EOF
wx 90
om 3 0x1000 1 0 rwx map2
e search.in=io.maps
e search.maxhits=1
/adq nop
q
EOF
EXPECT=<<EOF
0x00000000   # 1: nop
EOF
RUN

NAME=/ad sequence alignment checks hit start
FILE=malloc://5
ARGS=-a x86 -b 64
CMDS=<<EOF
wx 90c3cc90c3
e search.align=2
"/ad/ nop;ret"
q
EOF
EXPECT=<<EOF
0x00000000                   90  nop
0x00000001                   c3  ret
EOF
RUN

NAME=/adj match instructions with json output
FILE=bins/mach0/iGoat-Swift.arm_64.1
CMDS=<<EOF
e search.in=range
e search.from=0x100007e0c
e search.to=0x100007eec
"/adj add;ret"
EOF
EXPECT=<<EOF
[{"addr":4294999692,"len":8,"code":"add sp, sp, 0x40; ret"},{"addr":4294999780,"len":8,"code":"add sp, sp, 0x30; ret"}]
EOF
RUN

NAME=/adj match instructions with json hex numbers
FILE=bins/mach0/iGoat-Swift.arm_64.1
CMDS=<<EOF
e search.in=range
e search.from=0x100007e0c
e search.to=0x100007eec
e cfg.json.num=hex
"/adj add;ret"
EOF
EXPECT=<<EOF
[{"addr":"0x100007e8c","len":8,"code":"add sp, sp, 0x40; ret"},{"addr":"0x100007ee4","len":8,"code":"add sp, sp, 0x30; ret"}]
EOF
RUN

NAME=/ad/ quoted arguments and escaped separators agree
FILE=malloc://8
ARGS=-a arm -b 64
CMDS=<<EOF
wx 618b4191219c46f9
/ad/j "add .*, x27, 0x62, lsl 12;d38]"
/ad/j 'add .*, x27, 0x62, lsl 12;d38]'
"/ad/j add .*, x27, 0x62, lsl 12;d38]"
'/ad/j add .*, x27, 0x62, lsl 12;d38]
/ad/j add .*, x27, 0x62, lsl 12\;d38]
EOF
EXPECT=<<EOF
[{"addr":0,"len":8,"code":"add x1, x27, 0x62, lsl 12; ldr x1, [x1, 0xd38]"}]
[{"addr":0,"len":8,"code":"add x1, x27, 0x62, lsl 12; ldr x1, [x1, 0xd38]"}]
[{"addr":0,"len":8,"code":"add x1, x27, 0x62, lsl 12; ldr x1, [x1, 0xd38]"}]
[{"addr":0,"len":8,"code":"add x1, x27, 0x62, lsl 12; ldr x1, [x1, 0xd38]"}]
[{"addr":0,"len":8,"code":"add x1, x27, 0x62, lsl 12; ldr x1, [x1, 0xd38]"}]
EOF
EXPECT_ERR=
RUN

NAME=/ad/ quoted regex preserves escapes and shell metacharacters
FILE=malloc://4
ARGS=-a x86 -b 64
CMDS=<<EOF
wx 488b00c3
/ad/j "^mov rax, qword \[rax\]$;^(ret|nop)$"
/ad/j '^mov rax, qword \[rax\]$;^(ret|nop)$'
/ad/j "(nop|ret)"~{}
/adj "mov;ret"
EOF
EXPECT=<<EOF
[{"addr":0,"len":4,"code":"mov rax, qword [rax]; ret"}]
[{"addr":0,"len":4,"code":"mov rax, qword [rax]; ret"}]
[
  {
    "addr": 3,
    "len": 1,
    "code": "ret"
  }
]
[{"addr":0,"len":4,"code":"mov rax, qword [rax]; ret"}]
EOF
EXPECT_ERR=
RUN

NAME=/ad/ tab separates modifiers from the pattern
FILE=malloc://2
ARGS=-a x86 -b 64
CMDS=<<EOF
wx 90c3
/ad/j	"nop;ret"
EOF
EXPECT=<<EOF
[{"addr":0,"len":2,"code":"nop; ret"}]
EOF
EXPECT_ERR=
RUN

NAME=/ad/ consumes the last expression at the instruction limit
FILE=malloc://1023
ARGS=-a x86 -b 64
CMDS=<<EOF
b 1023
wox 90
/ad/j "$(1022?en 'nop;')ret"
/ad/j "$(1022?en 'nop;')nop"~{[0].len}
EOF
EXPECT=<<EOF
[]
1023
EOF
EXPECT_ERR=
RUN

NAME=/ad/ rejects excess instructions without a partial match
FILE=malloc://1024
ARGS=-a x86 -b 64
CMDS=<<EOF
b 1024
wox 90
/ad/j "$(1023?en 'nop;')ret" || ?e pattern rejected
q
EOF
EXPECT=<<EOF
[]
pattern rejected
EOF
EXPECT_ERR=<<EOF
ERROR: Too many instructions in search pattern (maximum 1023)
EOF
RUN

NAME=/ad/ semicolons in bracket expressions are not separators
FILE=malloc://2
ARGS=-a x86 -b 64
CMDS=<<EOF
wx 90c3
/ad/j "nop[;]?;ret"
/ad/j "nop[];]*;ret"
/ad/j "nop[^];]*;ret"
/ad/j "nop[[:space:];]*;ret"
/ad/j "nop[[.;.];]*;ret"
/ad/j "nop[[=;=];]*;ret"
EOF
EXPECT=<<EOF
[{"addr":0,"len":2,"code":"nop; ret"}]
[{"addr":0,"len":2,"code":"nop; ret"}]
[{"addr":0,"len":2,"code":"nop; ret"}]
[{"addr":0,"len":2,"code":"nop; ret"}]
[{"addr":0,"len":2,"code":"nop; ret"}]
[{"addr":0,"len":2,"code":"nop; ret"}]
EOF
EXPECT_ERR=
RUN

NAME=/ad/ escaped brackets do not hide instruction separators
FILE=malloc://4
ARGS=-a x86 -b 64
CMDS=<<EOF
wx 488b00c3
/ad/j "mov.*\[;ret"
/ad/j "mov.*\[rax\]\;ret"
EOF
EXPECT=<<EOF
[{"addr":0,"len":4,"code":"mov rax, qword [rax]; ret"}]
[{"addr":0,"len":4,"code":"mov rax, qword [rax]; ret"}]
EOF
EXPECT_ERR=
RUN

NAME=/ad/ errors fail shell conditionals and stop at the first map
FILE=malloc://1
ARGS=-a x86 -b 64
CMDS=<<EOF
wx 90
om 3 0x1000 1 0 rwx map2
e search.in=io.maps
/ad/j "(" && ?e unexpected success
/ad/j "(" || ?e invalid regex
/ad/jq nop || ?e invalid modifiers
/ad/j || ?e missing pattern
/ad/j "" || ?e empty pattern
/ad/j "ret" && ?e no hits is success
EOF
EXPECT=<<EOF
[]
[]
invalid regex
invalid modifiers
missing pattern
empty pattern
[]
no hits is success
EOF
EXPECT_ERR=<<EOF
ERROR: Invalid regexp: (
ERROR: Invalid regexp: (
ERROR: Invalid `q` subcommand, try `/ad?`
ERROR: Missing disassembly search pattern
ERROR: Missing disassembly search pattern
EOF
RUN

NAME=/ad glob search
ARGS=-a arm -b64
FILE=bins/mach0/ls-m1
CMDS=<<EOF
/ad ret~?
/ad ret$~?
EOF
EXPECT=<<EOF
40
18
EOF
RUN
