NAME=cxx class analysis simple (x86-64)
FILE=bins/elf/analysis/x86-class-C
CMDS=<<EOF
aaaa
avD @ main
pdf @ main
EOF
EXPECT=<<EOF
            ; DATA XREF from sym._start_c @ 0x40074b
            ;-- rip:
/ int main(int argc, char **argv, char **envp);
|           ; var struct C *var_20h @ stack - 0x20
|           0x0040088d      push  rbp
|           0x0040088e      mov   rbp, rsp
|           0x00400891      push  rbx
|           0x00400892      sub   rsp, 0x18
|           0x00400896      mov   edi, 0x10                            ; 16
|           0x0040089b      call  sym.imp.operator_new_unsigned_long
|           0x004008a0      mov   rbx, rax
|           0x004008a3      mov   esi, 0x05                            ; int64_t arg2
|           0x004008a8      mov   rdi, rbx                             ; int64_t arg1
|           0x004008ab      call  method.C.C_int                       ;  method.C.C_int(int64_t arg1, int64_t arg2)
|           0x004008b0      mov   qword [var_20h], rbx
|           0x004008b4      mov   rax, qword [var_20h]
|           0x004008b8      mov   rax, qword [rax]
|           0x004008bb      mov   rdx, qword [rax]
|           0x004008be      mov   rax, qword [var_20h]
|           0x004008c2      mov   rdi, rax
|           0x004008c5      call  rdx                                  ; Virtual Call : method.C.print
|           0x004008c7      mov   eax, 0x00
|           0x004008cc      add   rsp, 0x18
|           0x004008d0      pop   rbx
|           0x004008d1      pop   rbp
\           0x004008d2      ret
EOF
RUN

NAME=cxx class analysis for inherited classes (x86-64)
FILE=bins/elf/analysis/x86-class-inherit
CMDS=<<EOF
aaaa
avD @ main
pdf @ main
EOF
EXPECT=<<EOF
            ; DATA XREF from sym._start_c @ 0x40096b
            ;-- rip:
/ int main(int argc, char **argv, char **envp);
|           ; var struct Human *var_30h @ stack - 0x30
|           ; var struct Cat *var_28h @ stack - 0x28
|           ; var struct Dog *var_20h @ stack - 0x20
|           0x00400aad      push  rbp
|           0x00400aae      mov   rbp, rsp
|           0x00400ab1      push  r12
|           0x00400ab3      push  rbx
|           0x00400ab4      sub   rsp, 0x20
|           0x00400ab8      mov   edi, 0x08
|           0x00400abd      call  sym.imp.operator_new_unsigned_long
|           0x00400ac2      mov   rbx, rax
|           0x00400ac5      mov   rdi, rbx                             ; int64_t arg1
|           0x00400ac8      call  method.Dog.Dog                       ;  method.Dog.Dog(int64_t arg1)
|           0x00400acd      mov   qword [var_20h], rbx
|           0x00400ad1      mov   rax, qword [var_20h]
|           0x00400ad5      mov   rax, qword [rax]
|           0x00400ad8      add   rax, 0x10                            ; 16
|           0x00400adc      mov   rdx, qword [rax]
|           0x00400adf      mov   rax, qword [var_20h]
|           0x00400ae3      mov   rdi, rax
|           0x00400ae6      call  rdx                                  ; Virtual Call : method.Dog.run
|           0x00400ae8      mov   edi, 0x08
|           0x00400aed      call  sym.imp.operator_new_unsigned_long
|           0x00400af2      mov   rbx, rax
|           0x00400af5      mov   rdi, rbx                             ; int64_t arg1
|           0x00400af8      call  method.Cat.Cat                       ;  method.Cat.Cat(int64_t arg1)
|           0x00400afd      mov   qword [var_28h], rbx
|           0x00400b01      mov   rax, qword [var_28h]
|           0x00400b05      mov   rax, qword [rax]
|           0x00400b08      add   rax, 0x10                            ; 16
|           0x00400b0c      mov   rdx, qword [rax]
|           0x00400b0f      mov   rax, qword [var_28h]
|           0x00400b13      mov   rdi, rax
|           0x00400b16      call  rdx                                  ; Virtual Call : method.Cat.run
|           0x00400b18      mov   edi, 0x08
|           0x00400b1d      call  sym.imp.operator_new_unsigned_long
|           0x00400b22      mov   rbx, rax
|           0x00400b25      mov   rdi, rbx                             ; int64_t arg1
|           0x00400b28      call  method.Human.Human                   ;  method.Human.Human(int64_t arg1)
|           0x00400b2d      mov   qword [var_30h], rbx
|           0x00400b31      mov   rax, qword [var_30h]
|           0x00400b35      mov   rax, qword [rax]
|           0x00400b38      add   rax, 0x10                            ; 16
|           0x00400b3c      mov   rdx, qword [rax]
|           0x00400b3f      mov   rax, qword [var_30h]
|           0x00400b43      mov   rdi, rax
|           0x00400b46      call  rdx                                  ; Virtual Call : method.Human.run
|           0x00400b48      mov   rax, qword [var_20h]
|           0x00400b4c      test  rax, rax
|       ,=< 0x00400b4f      jz    0x400b60
|       |   0x00400b51      mov   rdx, qword [rax]
|       |   0x00400b54      add   rdx, 0x08
|       |   0x00400b58      mov   rdx, qword [rdx]
|       |   0x00400b5b      mov   rdi, rax
|       |   0x00400b5e      call  rdx                                  ; Virtual Call : sym.Dog::_Dog_0x400e6e
|       `-> 0x00400b60      mov   rax, qword [var_28h]
|           0x00400b64      test  rax, rax
|       ,=< 0x00400b67      jz    0x400b78
|       |   0x00400b69      mov   rdx, qword [rax]
|       |   0x00400b6c      add   rdx, 0x08
|       |   0x00400b70      mov   rdx, qword [rdx]
|       |   0x00400b73      mov   rdi, rax
|       |   0x00400b76      call  rdx                                  ; Virtual Call : sym.Cat::_Cat_0x400d78
|       `-> 0x00400b78      mov   rax, qword [var_30h]
|           0x00400b7c      test  rax, rax
|       ,=< 0x00400b7f      jz    0x400b90
|       |   0x00400b81      mov   rdx, qword [rax]
|       |   0x00400b84      add   rdx, 0x08
|       |   0x00400b88      mov   rdx, qword [rdx]
|       |   0x00400b8b      mov   rdi, rax
|       |   0x00400b8e      call  rdx                                  ; Virtual Call : sym.Human::_Human_0x400f64
|       |   ;-- rbp:
|       `-> 0x00400b90      mov   eax, 0x00
|       ,=< 0x00400b95      jmp   0x400be8
..
        |   ;-- r12:
        |   ;-- rbx:
|       |   ; CODE XREF from main @ 0x400b95
|       `-> 0x00400be8      add   rsp, 0x20
|           0x00400bec      pop   rbx
|           0x00400bed      pop   r12
|           0x00400bef      pop   rbp
\           0x00400bf0      ret
EOF
RUN

NAME=cxx class analysis for classes with conditionals (x86-64)
FILE=bins/elf/analysis/x86-class-conditional
CMDS=<<EOF
aaaa
avD @ main
pdf @ main
EOF
EXPECT=<<EOF
            ; DATA XREF from sym._start_c @ 0x400a3b
            ;-- rip:
/ int main(int argc, char **argv, char **envp);
|           ; var int var_24h @ stack - 0x24
|           ; var union RZ_var_20h_HYBRID var_20h @ stack - 0x20
|           0x00400b7d      push  rbp
|           0x00400b7e      mov   rbp, rsp
|           0x00400b81      push  r12
|           0x00400b83      push  rbx
|           0x00400b84      sub   rsp, 0x10
|           0x00400b88      mov   edi, 0x00                            ; time_t *timer
|           0x00400b8d      call  sym.imp.time                         ; time_t time(time_t *timer)
|           0x00400b92      mov   edi, eax                             ; int seed
|           0x00400b94      call  sym.imp.srand                        ; void srand(int seed)
|           0x00400b99      call  sym.imp.rand                         ; int rand(void)
|           0x00400b9e      mov   dword [var_24h], eax
|           0x00400ba1      mov   ecx, dword [var_24h]
|           0x00400ba4      movsxd rax, ecx
|           0x00400ba7      imul  rax, rax, 0x55555556
|           0x00400bae      shr   rax, 0x20
|           0x00400bb2      mov   rdx, rax
|           0x00400bb5      mov   eax, ecx
|           0x00400bb7      sar   eax, 0x1f
|           0x00400bba      sub   edx, eax
|           0x00400bbc      mov   eax, edx
|           0x00400bbe      add   eax, eax
|           0x00400bc0      add   eax, edx
|           0x00400bc2      sub   ecx, eax
|           0x00400bc4      mov   edx, ecx
|           0x00400bc6      cmp   edx, 0x02                            ; 2
|       ,=< 0x00400bc9      jnz   0x400c00
|       |   0x00400bcb      mov   edi, 0x08
|       |   0x00400bd0      call  sym.imp.operator_new_unsigned_long
|       |   0x00400bd5      mov   rbx, rax
|       |   0x00400bd8      mov   rdi, rbx                             ; int64_t arg1
|       |   0x00400bdb      call  method.Dog.Dog                       ;  method.Dog.Dog(int64_t arg1)
|       |   0x00400be0      mov   qword [var_20h.var_20h], rbx
|       |   0x00400be4      mov   rax, qword [var_20h.var_20h]
|       |   0x00400be8      mov   rax, qword [rax]
|       |   0x00400beb      add   rax, 0x10                            ; 16
|       |   0x00400bef      mov   rdx, qword [rax]
|       |   0x00400bf2      mov   rax, qword [var_20h.var_20h]
|       |   0x00400bf6      mov   rdi, rax
|       |   0x00400bf9      call  rdx                                  ; Virtual Call : method.Dog.run / method.Human.run / method.Cat.run
|      ,==< 0x00400bfb      jmp   0x400c8c
|      |`-> 0x00400c00      mov   ecx, dword [var_24h]
|      |    0x00400c03      movsxd rax, ecx
|      |    0x00400c06      imul  rax, rax, 0x55555556
|      |    0x00400c0d      shr   rax, 0x20
|      |    0x00400c11      mov   rdx, rax
|      |    0x00400c14      mov   eax, ecx
|      |    0x00400c16      sar   eax, 0x1f
|      |    0x00400c19      sub   edx, eax
|      |    0x00400c1b      mov   eax, edx
|      |    0x00400c1d      add   eax, eax
|      |    0x00400c1f      add   eax, edx
|      |    0x00400c21      sub   ecx, eax
|      |    0x00400c23      mov   edx, ecx
|      |    0x00400c25      cmp   edx, 0x01                            ; 1
|      |,=< 0x00400c28      jnz   0x400c5c
|      ||   0x00400c2a      mov   edi, 0x08
|      ||   0x00400c2f      call  sym.imp.operator_new_unsigned_long
|      ||   0x00400c34      mov   rbx, rax
|      ||   0x00400c37      mov   rdi, rbx                             ; int64_t arg1
|      ||   0x00400c3a      call  method.Cat.Cat                       ;  method.Cat.Cat(int64_t arg1)
|      ||   0x00400c3f      mov   qword [var_20h.var_20h], rbx
|      ||   0x00400c43      mov   rax, qword [var_20h.var_20h]
|      ||   0x00400c47      mov   rax, qword [rax]
|      ||   0x00400c4a      add   rax, 0x10                            ; 16
|      ||   0x00400c4e      mov   rdx, qword [rax]
|      ||   0x00400c51      mov   rax, qword [var_20h.var_20h]
|      ||   0x00400c55      mov   rdi, rax
|      ||   0x00400c58      call  rdx                                  ; Virtual Call : method.Dog.run / method.Human.run / method.Cat.run
|     ,===< 0x00400c5a      jmp   0x400c8c
|     ||`-> 0x00400c5c      mov   edi, 0x08
|     ||    0x00400c61      call  sym.imp.operator_new_unsigned_long
|     ||    0x00400c66      mov   rbx, rax
|     ||    0x00400c69      mov   rdi, rbx                             ; int64_t arg1
|     ||    0x00400c6c      call  method.Human.Human                   ;  method.Human.Human(int64_t arg1)
|     ||    0x00400c71      mov   qword [var_20h.var_20h], rbx
|     ||    0x00400c75      mov   rax, qword [var_20h.var_20h]
|     ||    0x00400c79      mov   rax, qword [rax]
|     ||    0x00400c7c      add   rax, 0x10                            ; 16
|     ||    0x00400c80      mov   rdx, qword [rax]
|     ||    0x00400c83      mov   rax, qword [var_20h.var_20h]
|     ||    0x00400c87      mov   rdi, rax
|     ||    0x00400c8a      call  rdx                                  ; Virtual Call : method.Dog.run / method.Human.run / method.Cat.run
|     ||    ; CODE XREFS from main @ 0x400bfb, 0x400c5a
|     ``--> 0x00400c8c      mov   rax, qword [var_20h.var_20h]
|           0x00400c90      mov   rax, qword [rax]
|           0x00400c93      add   rax, 0x18                            ; 24
|           0x00400c97      mov   rdx, qword [rax]
|           0x00400c9a      mov   rax, qword [var_20h.var_20h]
|           0x00400c9e      mov   rdi, rax
|           0x00400ca1      call  rdx                                  ; Virtual Call : method.Dog.walk / method.Human.walk / method.Cat.walk
|           0x00400ca3      mov   rax, qword [var_20h.var_20h]
|           0x00400ca7      test  rax, rax
|       ,=< 0x00400caa      jz    0x400cbb
|       |   0x00400cac      mov   rdx, qword [rax]
|       |   0x00400caf      add   rdx, 0x08
|       |   0x00400cb3      mov   rdx, qword [rdx]
|       |   0x00400cb6      mov   rdi, rax
|       |   0x00400cb9      call  rdx                                  ; Virtual Call : sym.Cat::_Cat_0x400ea4 / sym.Human::_Human_0x401090 / sym.Dog::_Dog_0x400f9a
|       `-> 0x00400cbb      mov   eax, 0x00
|       ,=< 0x00400cc0      jmp   0x400d13
..
        |   ;-- rbp:
        |   ;-- r12:
        |   ;-- rbx:
|       |   ; CODE XREF from main @ 0x400cc0
|       `-> 0x00400d13      add   rsp, 0x10
|           0x00400d17      pop   rbx
|           0x00400d18      pop   r12
|           0x00400d1a      pop   rbp
\           0x00400d1b      ret
EOF
RUN

NAME=cxx class analysis for classes with multiple vtables (x86-64)
FILE=bins/elf/analysis/x86-class-multi-vtable
CMDS=<<EOF
aaaa
avD @ main
pdf @ main
EOF
EXPECT=<<EOF
            ; DATA XREF from sym._start_c @ 0x40088b
            ;-- rip:
/ int main(int argc, char **argv, char **envp);
|           ; var struct C *var_20h @ stack - 0x20
|           0x004009cd      push  rbp
|           0x004009ce      mov   rbp, rsp
|           0x004009d1      push  rbx
|           0x004009d2      sub   rsp, 0x18
|           0x004009d6      mov   edi, 0x10                            ; rflags
|           0x004009db      call  sym.imp.operator_new_unsigned_long
|           ;-- rbp:
|           0x004009e0      mov   rbx, rax
|           0x004009e3      mov   qword [rbx], 0x00
|           0x004009ea      mov   qword [rbx+0x08], 0x00
|           0x004009f2      mov   rdi, rbx                             ; int64_t arg1
|           0x004009f5      call  method.C.C                           ;  method.C.C(int64_t arg1)
|           ;-- rbx:
|           0x004009fa      mov   qword [var_20h], rbx
|           0x004009fe      mov   rax, qword [var_20h]
|           0x00400a02      mov   rax, qword [rax]
|           0x00400a05      mov   rdx, qword [rax]
|           0x00400a08      mov   rax, qword [var_20h]
|           0x00400a0c      mov   rdi, rax
|           0x00400a0f      call  rdx                                  ; Virtual Call : sym.non_virtual_thunk_to_C::showB / method.C.showA
|           0x00400a11      mov   rax, qword [var_20h]
|           0x00400a15      mov   rax, qword [rax]
|           0x00400a18      add   rax, 0x08
|           0x00400a1c      mov   rdx, qword [rax]
|           0x00400a1f      mov   rax, qword [var_20h]
|           0x00400a23      mov   rdi, rax
|           0x00400a26      call  rdx                                  ; Virtual Call : method.C.showB
|           0x00400a28      mov   rax, qword [var_20h]
|           0x00400a2c      mov   rax, qword [rax]
|           0x00400a2f      add   rax, 0x10                            ; rflags
|           0x00400a33      mov   rdx, qword [rax]
|           0x00400a36      mov   rax, qword [var_20h]
|           0x00400a3a      mov   rdi, rax
|           0x00400a3d      call  rdx                                  ; Virtual Call : method.C.showC
|           0x00400a3f      mov   eax, 0x00
|           0x00400a44      add   rsp, 0x18
|           0x00400a48      pop   rbx
|           0x00400a49      pop   rbp
\           0x00400a4a      ret
EOF
RUN

NAME=cxx class analysis for inherited classes (arm64)
FILE=bins/mach0/arm64-class-inherit
CMDS=<<EOF
aaaa
avD @ main
pdf @ main
EOF
EXPECT=<<EOF
            ; UNKNOWN XREF from aav.0x100000028 @ +0xa8
            ;-- main:
            ;-- section.0.__TEXT.__text:
            ;-- _main:
            ;-- func.100002878:
            ;-- pc:
/ entry0(int64_t arg1);
|           ; arg int64_t arg1 @ x0
|           ; var int64_t var_70h @ stack - 0x70
|           ; var int64_t var_68h @ stack - 0x68
|           ; var int64_t var_60h @ stack - 0x60
|           ; var int64_t var_58h @ stack - 0x58
|           ; var int64_t var_50h @ stack - 0x50
|           ; var int64_t var_48h @ stack - 0x48
|           ; var struct Human *var_30h @ stack - 0x30
|           ; var struct Cat *var_28h @ stack - 0x28
|           ; var struct Dog *var_20h @ stack - 0x20
|           ; var int64_t var_14h @ stack - 0x14
|           ; var int64_t var_10h @ stack - 0x10
|           ; var int64_t var_8h @ stack - 0x8
|           0x100002878      sub   sp, sp, 0x70                        ; [00] -r-x section size 4944 named 0.__TEXT.__text
|           0x10000287c      stp   fp, lr, [var_10h]
|           0x100002880      add   fp, sp, 0x60
|           0x100002884      stur  wzr, [var_14h]                      ; arg1
|           0x100002888      mov   x0, 8
|           0x10000288c      bl    sym.imp.operator_new_unsigned_long
|           0x100002890      str   x0, [var_48h]
|           0x100002894      bl    method.Dog.Dog                      ;  method.Dog.Dog(int64_t arg1)
|       ,=< 0x100002898      b     0x10000289c
|       |   ; CODE XREF from entry0 @ 0x100002898
|       `-> 0x10000289c      ldr   x8, [var_48h]                       ; [0x28:4]=-1 ; 40
|           0x1000028a0      stur  x8, [var_20h]
|           0x1000028a4      ldur  x0, [var_20h]
|           0x1000028a8      ldr   x8, [x0]
|           0x1000028ac      ldr   x8, [x8, 0x10]                      ; [0x10:4]=-1 ; 16
|           0x1000028b0      blr   x8                                  ; Virtual Call : method.Dog.run
|           0x1000028b4      mov   x0, 8
|           0x1000028b8      bl    sym.imp.operator_new_unsigned_long
|           0x1000028bc      str   x0, [var_50h]
|           0x1000028c0      bl    method.Cat.Cat                      ;  method.Cat.Cat(int64_t arg1)
|       ,=< 0x1000028c4      b     0x1000028c8
|       |   ; CODE XREF from entry0 @ 0x1000028c4
|       `-> 0x1000028c8      ldr   x8, [var_50h]                       ; [0x20:4]=-1 ; 32
|           0x1000028cc      stur  x8, [var_28h]
|           0x1000028d0      ldur  x0, [var_28h]
|           0x1000028d4      ldr   x8, [x0]
|           0x1000028d8      ldr   x8, [x8, 0x10]                      ; [0x10:4]=-1 ; 16
|           0x1000028dc      blr   x8                                  ; Virtual Call : method.Cat.run
|           0x1000028e0      mov   x0, 8
|           0x1000028e4      bl    sym.imp.operator_new_unsigned_long
|           0x1000028e8      str   x0, [var_58h]
|           0x1000028ec      bl    method.Human.Human                  ;  method.Human.Human(int64_t arg1)
|       ,=< 0x1000028f0      b     0x1000028f4
|       |   ; CODE XREF from entry0 @ 0x1000028f0
|       `-> 0x1000028f4      ldr   x8, [var_58h]                       ; [0x18:4]=-1 ; 24
|           0x1000028f8      stur  x8, [var_30h]
|           0x1000028fc      ldur  x0, [var_30h]
|           0x100002900      ldr   x8, [x0]
|           0x100002904      ldr   x8, [x8, 0x10]                      ; [0x10:4]=-1 ; 16
|           0x100002908      blr   x8                                  ; Virtual Call : method.Human.run
|           0x10000290c      ldur  x8, [var_20h]
|           0x100002910      str   x8, [var_60h]
|           0x100002914      subs  x8, x8, 0
|           0x100002918      cset  w8, eq
|       ,=< 0x10000291c      tbnz  w8, 0, 0x100002938
|      ,==< 0x100002920      b     0x100002924
|      ||   ; CODE XREF from entry0 @ 0x100002920
|      `--> 0x100002924      ldr   x0, [var_60h]                       ; [0x10:4]=-1 ; 16
|       |   0x100002928      ldr   x8, [x0]
|       |   0x10000292c      ldr   x8, [x8, 8]                         ; [0x8:4]=-1 ; 8
|       |   0x100002930      blr   x8                                  ; Virtual Call : sym.Dog::_Dog_0x100002c18
|      ,==< 0x100002934      b     0x100002938
|      ||   ; CODE XREF from entry0 @ 0x100002934
|      ``-> 0x100002938      ldur  x8, [var_28h]
|           0x10000293c      str   x8, [var_68h]
|           0x100002940      subs  x8, x8, 0
|           0x100002944      cset  w8, eq
|       ,=< 0x100002948      tbnz  w8, 0, 0x100002964
|      ,==< 0x10000294c      b     0x100002950
|      ||   ; CODE XREF from entry0 @ 0x10000294c
|      `--> 0x100002950      ldr   x0, [var_68h]                       ; [0x8:4]=-1 ; 8
|       |   0x100002954      ldr   x8, [x0]
|       |   0x100002958      ldr   x8, [x8, 8]                         ; [0x8:4]=-1 ; 8
|       |   0x10000295c      blr   x8                                  ; Virtual Call : sym.Cat::_Cat_0x100003940
|      ,==< 0x100002960      b     0x100002964
|      ||   ; CODE XREF from entry0 @ 0x100002960
|      ``-> 0x100002964      ldur  x8, [var_30h]
|           0x100002968      str   x8, [sp]
|           0x10000296c      subs  x8, x8, 0
|           0x100002970      cset  w8, eq
|       ,=< 0x100002974      tbnz  w8, 0, 0x100002990
|      ,==< 0x100002978      b     0x10000297c
|      ||   ; CODE XREF from entry0 @ 0x100002978
|      `--> 0x10000297c      ldr   x0, [sp]
|       |   0x100002980      ldr   x8, [x0]
|       |   0x100002984      ldr   x8, [x8, 8]                         ; [0x8:4]=-1 ; 8
|       |   0x100002988      blr   x8                                  ; Virtual Call : sym.Human::_Human_0x100003adc
|      ,==< 0x10000298c      b     0x100002990
|      ||   ; CODE XREF from entry0 @ 0x10000298c
|      ``-> 0x100002990      ldur  w0, [var_14h]
|           0x100002994      ldp   fp, lr, [var_10h]
|           0x100002998      add   sp, sp, 0x70
\           0x10000299c      ret
EOF
RUN

NAME=cxx class analysis for classes with conditionals (arm64)
FILE=bins/mach0/arm64-class-conditional
CMDS=<<EOF
aaaa
avD @ main
pdf @ main
EOF
EXPECT=<<EOF
            ; UNKNOWN XREF from aav.0x100000028 @ +0xa8
            ;-- main:
            ;-- section.0.__TEXT.__text:
            ;-- _main:
            ;-- func.10000282c:
            ;-- pc:
/ entry0(int64_t arg1);
|           ; arg int64_t arg1 @ x0
|           ; var int64_t var_58h @ stack - 0x58
|           ; var int64_t var_50h @ stack - 0x50
|           ; var int64_t var_48h @ stack - 0x48
|           ; var int64_t var_40h @ stack - 0x40
|           ; var int64_t var_24h @ stack - 0x24
|           ; var union RZ_var_20h_HYBRID var_20h @ stack - 0x20
|           ; var int64_t var_14h @ stack - 0x14
|           ; var int64_t var_10h @ stack - 0x10
|           ; var int64_t var_8h @ stack - 0x8
|           0x10000282c      sub   sp, sp, 0x60                        ; [00] -r-x section size 4980 named 0.__TEXT.__text
|           0x100002830      stp   fp, lr, [var_10h]
|           0x100002834      add   fp, sp, 0x50
|           0x100002838      stur  wzr, [var_14h]                      ; arg1
|           0x10000283c      mov   x0, 0                               ; int seed
|           0x100002840      bl    sym.imp.time                        ; time_t time(time_t *timer)
|           0x100002844      bl    sym.imp.srand                       ; void srand(int seed)
|           0x100002848      bl    sym.imp.rand                        ; int rand(void)
|           0x10000284c      stur  w0, [var_24h]
|           0x100002850      ldur  w8, [var_24h]
|           0x100002854      mov   w10, 3
|           0x100002858      sdiv  w9, w8, w10
|           0x10000285c      mul   w9, w9, w10
|           0x100002860      subs  w8, w8, w9
|           0x100002864      subs  w8, w8, 2
|           0x100002868      cset  w8, ne
|       ,=< 0x10000286c      tbnz  w8, 0, 0x1000028c0
|      ,==< 0x100002870      b     0x100002874
|      ||   ; CODE XREF from entry0 @ 0x100002870
|      `--> 0x100002874      mov   x0, 8
|       |   0x100002878      bl    sym.imp.operator_new_unsigned_long
|       |   0x10000287c      str   x0, [var_40h]
|       |   0x100002880      bl    method.Dog.Dog                      ;  method.Dog.Dog(int64_t arg1)
|      ,==< 0x100002884      b     0x100002888
|      ||   ; CODE XREF from entry0 @ 0x100002884
|      `--> 0x100002888      ldr   x8, [var_40h]                       ; [0x20:4]=-1 ; 32
|       |   0x10000288c      stur  x8, [var_20h.var_20h]
|       |   0x100002890      ldur  x0, [var_20h.var_20h]
|       |   0x100002894      ldr   x8, [x0]
|       |   0x100002898      ldr   x8, [x8, 0x10]                      ; [0x10:4]=-1 ; 16
|       |   0x10000289c      blr   x8                                  ; Virtual Call : method.Dog.run / method.Human.run / method.Cat.run
|      ,==< 0x1000028a0      b     0x100002980
..
|     ||`-> 0x1000028c0      ldur  w8, [var_24h]
|     ||    0x1000028c4      mov   w10, 3
|     ||    0x1000028c8      sdiv  w9, w8, w10
|     ||    0x1000028cc      mul   w9, w9, w10
|     ||    0x1000028d0      subs  w8, w8, w9
|     ||    0x1000028d4      subs  w8, w8, 1
|     ||    0x1000028d8      cset  w8, ne
|     ||,=< 0x1000028dc      tbnz  w8, 0, 0x100002930
|    ,====< 0x1000028e0      b     0x1000028e4
|    ||||   ; CODE XREF from entry0 @ 0x1000028e0
|    `----> 0x1000028e4      mov   x0, 8
|     |||   0x1000028e8      bl    sym.imp.operator_new_unsigned_long
|     |||   0x1000028ec      str   x0, [var_48h]
|     |||   0x1000028f0      bl    method.Cat.Cat                      ;  method.Cat.Cat(int64_t arg1)
|    ,====< 0x1000028f4      b     0x1000028f8
|    ||||   ; CODE XREF from entry0 @ 0x1000028f4
|    `----> 0x1000028f8      ldr   x8, [var_48h]                       ; [0x18:4]=-1 ; 24
|     |||   0x1000028fc      stur  x8, [var_20h.var_20h]
|     |||   0x100002900      ldur  x0, [var_20h.var_20h]
|     |||   0x100002904      ldr   x8, [x0]
|     |||   0x100002908      ldr   x8, [x8, 0x10]                      ; [0x10:4]=-1 ; 16
|     |||   0x10000290c      blr   x8                                  ; Virtual Call : method.Dog.run / method.Human.run / method.Cat.run
|    ,====< 0x100002910      b     0x10000297c
..
|   ||||`-> 0x100002930      mov   x0, 8
|   ||||    0x100002934      bl    sym.imp.operator_new_unsigned_long
|   ||||    0x100002938      str   x0, [var_50h]
|   ||||    0x10000293c      bl    method.Human.Human                  ;  method.Human.Human(int64_t arg1)
|   ||||,=< 0x100002940      b     0x100002944
|   |||||   ; CODE XREF from entry0 @ 0x100002940
|   ||||`-> 0x100002944      ldr   x8, [var_50h]                       ; [0x10:4]=-1 ; 16
|   ||||    0x100002948      stur  x8, [var_20h.var_20h]
|   ||||    0x10000294c      ldur  x0, [var_20h.var_20h]
|   ||||    0x100002950      ldr   x8, [x0]
|   ||||    0x100002954      ldr   x8, [x8, 0x10]                      ; [0x10:4]=-1 ; 16
|   ||||    0x100002958      blr   x8                                  ; Virtual Call : method.Dog.run / method.Human.run / method.Cat.run
|   ||||,=< 0x10000295c      b     0x10000297c
..
|  ||||||   ; CODE XREFS from entry0 @ 0x100002910, 0x10000295c
| ,==`--`-> 0x10000297c      b     0x100002980
| ||| ||    ; CODE XREFS from entry0 @ 0x1000028a0, 0x10000297c
| `----`--> 0x100002980      ldur  x0, [var_20h.var_20h]
|  || |     0x100002984      ldr   x8, [x0]
|  || |     0x100002988      ldr   x8, [x8, 0x18]                      ; [0x18:4]=-1 ; 24
|  || |     0x10000298c      blr   x8                                  ; Virtual Call : method.Dog.walk / method.Human.walk / method.Cat.walk
|  || |     0x100002990      ldur  x8, [var_20h.var_20h]
|  || |     0x100002994      str   x8, [var_58h]
|  || |     0x100002998      subs  x8, x8, 0
|  || |     0x10000299c      cset  w8, eq
|  || | ,=< 0x1000029a0      tbnz  w8, 0, 0x1000029bc
|  || |,==< 0x1000029a4      b     0x1000029a8
|  || |||   ; CODE XREF from entry0 @ 0x1000029a4
|  || |`--> 0x1000029a8      ldr   x0, [var_58h]                       ; [0x8:4]=-1 ; 8
|  || | |   0x1000029ac      ldr   x8, [x0]
|  || | |   0x1000029b0      ldr   x8, [x8, 8]                         ; [0x8:4]=-1 ; 8
|  || | |   0x1000029b4      blr   x8                                  ; Virtual Call : sym.Dog::_Dog_0x100002bf0 / sym.Human::_Human_0x100003ab4 / sym.Cat::_Cat_0x100003918
|  || |,==< 0x1000029b8      b     0x1000029bc
|  || |||   ; CODE XREF from entry0 @ 0x1000029b8
|  || |``-> 0x1000029bc      ldur  w0, [var_14h]
|  || |     0x1000029c0      ldp   fp, lr, [var_10h]
|  || |     0x1000029c4      add   sp, sp, 0x60
\  || |     0x1000029c8      ret
EOF
RUN

NAME=cxx class analysis for classes with multiple vtables (arm64)
FILE=bins/mach0/arm64-class-multi-vtable
CMDS=<<EOF
aaaa
avD @ main
pdf @ main
EOF
EXPECT=<<EOF
            ; UNKNOWN XREF from aav.0x100000028 @ +0xa8
            ;-- main:
            ;-- section.0.__TEXT.__text:
            ;-- _main:
            ;-- func.100002ea0:
            ;-- pc:
/ entry0(int64_t arg1);
|           ; arg int64_t arg1 @ x0
|           ; var int64_t var_30h @ stack - 0x30
|           ; var int64_t var_24h @ stack - 0x24
|           ; var struct C *var_20h @ stack - 0x20
|           ; var int64_t var_14h @ stack - 0x14
|           ; var int64_t var_10h @ stack - 0x10
|           ; var int64_t var_8h @ stack - 0x8
|           0x100002ea0      sub   sp, sp, 0x30                        ; [00] -r-x section size 3740 named 0.__TEXT.__text
|           0x100002ea4      stp   fp, lr, [var_10h]
|           0x100002ea8      add   fp, sp, 0x20
|           0x100002eac      mov   w8, 0
|           0x100002eb0      str   w8, [var_24h]
|           0x100002eb4      stur  wzr, [var_14h]                      ; arg1
|           0x100002eb8      mov   x0, 0x10
|           0x100002ebc      bl    sym.imp.operator_new_unsigned_long
|           0x100002ec0      str   x0, [sp]
|           0x100002ec4      str   xzr, [x0]
|           0x100002ec8      str   xzr, [x0, 8]
|           0x100002ecc      bl    method.C.C                          ;  method.C.C(int64_t arg1)
|           0x100002ed0      ldr   x0, [sp]
|           0x100002ed4      str   x0, [var_20h]
|           0x100002ed8      ldr   x0, [var_20h]                       ; [0x10:4]=-1 ; 16
|           0x100002edc      ldr   x8, [x0]
|           0x100002ee0      ldr   x8, [x8]
|           0x100002ee4      blr   x8                                  ; Virtual Call : sym.non_virtual_thunk_to_C::showB / method.C.showA
|           0x100002ee8      ldr   x0, [var_20h]                       ; [0x10:4]=-1 ; 16
|           0x100002eec      ldr   x8, [x0]
|           0x100002ef0      ldr   x8, [x8, 8]                         ; [0x8:4]=-1 ; 8
|           0x100002ef4      blr   x8                                  ; Virtual Call : method.C.showB
|           0x100002ef8      ldr   x0, [var_20h]                       ; [0x10:4]=-1 ; 16
|           0x100002efc      ldr   x8, [x0]
|           0x100002f00      ldr   x8, [x8, 0x10]                      ; [0x10:4]=-1 ; 16
|           0x100002f04      blr   x8                                  ; Virtual Call : method.C.showC
|           0x100002f08      ldr   w0, [var_24h]                       ; [0xc:4]=-1 ; 12
|           0x100002f0c      ldp   fp, lr, [var_10h]
|           0x100002f10      add   sp, sp, 0x30
\           0x100002f14      ret
EOF
RUN

NAME=cxx class analysis for classes with multiple vtables & w/o rtti (x86)
FILE=bins/elf/analysis/x86-no-rtti-class-multi-vtable
CMDS=<<EOF
aaaa
avD @ main
pdf @ main
EOF
EXPECT=<<EOF
            ; DATA XREF from sym._start_c @ 0x40086b
            ;-- rip:
/ int main(int argc, char **argv, char **envp);
|           ; var struct Dog *var_20h @ stack - 0x20
|           0x004009ad      push  rbp
|           0x004009ae      mov   rbp, rsp
|           0x004009b1      push  r12
|           0x004009b3      push  rbx
|           0x004009b4      sub   rsp, 0x10
|           0x004009b8      mov   edi, 0x10                            ; rsi
|           0x004009bd      call  sym.imp.operator_new_unsigned_long
|           0x004009c2      mov   rbx, rax
|           0x004009c5      mov   rdi, rbx                             ; int64_t arg1
|           0x004009c8      call  method.Dog.Dog                       ;  method.Dog.Dog(int64_t arg1)
|           0x004009cd      mov   qword [var_20h], rbx
|           0x004009d1      mov   rax, qword [var_20h]
|           0x004009d5      mov   rax, qword [rax]
|           0x004009d8      add   rax, 0x18                            ; 24
|           0x004009dc      mov   rdx, qword [rax]
|           0x004009df      mov   rax, qword [var_20h]
|           0x004009e3      mov   rdi, rax
|           0x004009e6      call  rdx                                  ; Virtual Call : method.Dog.walk
|           ;-- rbp:
|           0x004009e8      mov   rax, qword [var_20h]
|           0x004009ec      mov   rax, qword [rax]
|           0x004009ef      add   rax, 0x10                            ; rsi
|           0x004009f3      mov   rdx, qword [rax]
|           0x004009f6      mov   rax, qword [var_20h]
|           0x004009fa      mov   rdi, rax
|           0x004009fd      call  rdx                                  ; Virtual Call : method.Dog.eat / sym.non_virtual_thunk_to_Dog::walk
|           ;-- r12:
|           0x004009ff      mov   rax, qword [var_20h]
|           0x00400a03      test  rax, rax
|       ,=< 0x00400a06      jz    0x400a17
|       |   0x00400a08      mov   rdx, qword [rax]
|       |   0x00400a0b      add   rdx, 0x08
|       |   0x00400a0f      mov   rdx, qword [rdx]
|       |   0x00400a12      mov   rdi, rax
|       |   0x00400a15      call  rdx                                  ; Virtual Call : sym.non_virtual_thunk_to_Dog::_Dog_0x400ca5 / sym.Dog::_Dog_0x400c7a
|       |   ;-- rbx:
|       `-> 0x00400a17      mov   eax, 0x00
|       ,=< 0x00400a1c      jmp   0x400a39
..
|       |   ; CODE XREF from main @ 0x400a1c
|       `-> 0x00400a39      add   rsp, 0x10
|           0x00400a3d      pop   rbx
|           0x00400a3e      pop   r12
|           0x00400a40      pop   rbp
\           0x00400a41      ret
EOF
RUN

NAME=cxx class analysis for classes with multiple vtables & w/o rtti (arm64)
FILE=bins/mach0/arm64-no-rtti-class-multi-vtable
CMDS=<<EOF
aaaa
avD @ main
pdf @ main
EOF
EXPECT=<<EOF
            ; UNKNOWN XREF from aav.0x100000028 @ +0xa8
            ;-- main:
            ;-- section.0.__TEXT.__text:
            ;-- _main:
            ;-- func.100002c70:
            ;-- pc:
/ entry0(int64_t arg1);
|           ; arg int64_t arg1 @ x0
|           ; var int64_t var_40h @ stack - 0x40
|           ; var int64_t var_38h @ stack - 0x38
|           ; var struct Dog *var_20h @ stack - 0x20
|           ; var int64_t var_14h @ stack - 0x14
|           ; var int64_t var_10h @ stack - 0x10
|           ; var int64_t var_8h @ stack - 0x8
|           0x100002c70      sub   sp, sp, 0x40                        ; [00] -r-x section size 4120 named 0.__TEXT.__text
|           0x100002c74      stp   fp, lr, [sp, 0lr]
|           0x100002c78      add   fp, sp, 0x30
|           0x100002c7c      stur  wzr, [var_14h]                      ; arg1
|           0x100002c80      mov   x0, 0x10
|           0x100002c84      bl    sym.imp.operator_new_unsigned_long
|           0x100002c88      str   x0, [var_38h]
|           0x100002c8c      bl    method.Dog.Dog                      ;  method.Dog.Dog(int64_t arg1)
|       ,=< 0x100002c90      b     0x100002c94
|       |   ; CODE XREF from entry0 @ 0x100002c90
|       `-> 0x100002c94      ldr   x8, [var_38h]                       ; [0x8:4]=-1 ; 8
|           0x100002c98      stur  x8, [var_20h]
|           0x100002c9c      ldur  x0, [var_20h]
|           0x100002ca0      ldr   x8, [x0]
|           0x100002ca4      ldr   x8, [x8, 0x18]                      ; [0x18:4]=-1 ; 24
|           0x100002ca8      blr   x8                                  ; Virtual Call : method.Dog.walk
|           0x100002cac      ldur  x0, [var_20h]
|           0x100002cb0      ldr   x8, [x0]
|           0x100002cb4      ldr   x8, [x8, 0x10]                      ; [0x10:4]=-1 ; 16
|           0x100002cb8      blr   x8                                  ; Virtual Call : method.Dog.eat / sym.non_virtual_thunk_to_Dog::walk
|           0x100002cbc      ldur  x8, [var_20h]
|           0x100002cc0      str   x8, [sp]
|           0x100002cc4      subs  x8, x8, 0
|           0x100002cc8      cset  w8, eq
|       ,=< 0x100002ccc      tbnz  w8, 0, 0x100002ce8
|      ,==< 0x100002cd0      b     0x100002cd4
|      ||   ; CODE XREF from entry0 @ 0x100002cd0
|      `--> 0x100002cd4      ldr   x0, [sp]
|       |   0x100002cd8      ldr   x8, [x0]
|       |   0x100002cdc      ldr   x8, [x8, 8]                         ; [0x8:4]=-1 ; 8
|       |   0x100002ce0      blr   x8                                  ; Virtual Call : sym.non_virtual_thunk_to_Dog::_Dog_0x100003068 / sym.Dog::_Dog_0x100002fbc
|      ,==< 0x100002ce4      b     0x100002ce8
|      ||   ; CODE XREF from entry0 @ 0x100002ce4
|      ``-> 0x100002ce8      ldur  w0, [var_14h]
|           0x100002cec      ldp   fp, lr, [sp, 0lr]
|           0x100002cf0      add   sp, sp, 0x40
\           0x100002cf4      ret
EOF
RUN

NAME=objc msg dispatch (amd64)
FILE=bins/mach0/objc-employee
CMDS=<<EOF
aaaa
avD @ main
pdf @ main
EOF
EXPECT=<<EOF
            ;-- main:
            ;-- section.0.__TEXT.__text:
            ;-- _main:
            ;-- func.1000018c0:
/ entry0(int64_t arg1, int64_t arg2);
|           ; arg int64_t arg1 @ rdi
|           ; arg int64_t arg2 @ rsi
|           ; var int var_a8h @ stack - 0xa8
|           ; var int var_a4h @ stack - 0xa4
|           ; var int var_a0h @ stack - 0xa0
|           ; var int var_9ch @ stack - 0x9c
|           ; var void *var_98h @ stack - 0x98
|           ; var int var_8ch @ stack - 0x8c
|           ; var void *var_88h @ stack - 0x88
|           ; var int var_7ch @ stack - 0x7c
|           ; var void *var_78h @ stack - 0x78
|           ; var int var_6ch @ stack - 0x6c
|           ; var void *var_68h @ stack - 0x68
|           ; var int64_t var_60h @ stack - 0x60
|           ; var int64_t var_58h @ stack - 0x58
|           ; var void *var_50h @ stack - 0x50
|           ; var int64_t var_48h @ stack - 0x48
|           ; var const char *var_40h @ stack - 0x40
|           ; var int64_t var_34h @ stack - 0x34
|           ; var int64_t var_30h @ stack - 0x30
|           ; var void *var_28h @ stack - 0x28
|           ; var const char **format @ stack - 0x20
|           ; var int64_t var_18h @ stack - 0x18
|           ; var int64_t var_10h @ stack - 0x10
|           ; var int64_t var_ch @ stack - 0xc
|           0x1000018c0      push  rbp                                 ; [00] -r-x section size 1126 named 0.__TEXT.__text
|           0x1000018c1      mov   rbp, rsp
|           0x1000018c4      sub   rsp, 0xb0
|           0x1000018cb      mov   dword [var_ch], 0x00
|           0x1000018d2      mov   dword [var_10h], edi                ; arg1
|           0x1000018d5      mov   qword [var_18h], rsi                ; arg2
|           0x1000018d9      call  sym.imp.objc_autoreleasePoolPush
|           0x1000018de      lea   rsi, qword reloc.__CFConstantStringClassReference ; str.cstr.Hello_World_Object
|                                                                      ; 0x100002010
|           0x1000018e5      mov   rdi, rsi
|           0x1000018e8      mov   qword [var_48h], rax
|           0x1000018ec      mov   al, 0x00
|           0x1000018ee      call  sym.imp.NSLog
|           0x1000018f3      mov   rsi, qword [section.15.__DATA.__objc_classrefs] ; [0x100003320:8]=0x100003370 sym.class_Employee ; "p3"
|           0x1000018fa      mov   rdi, rsi
|           0x1000018fd      call  sym.imp.objc_alloc_init
|           0x100001902      mov   qword [format], rax
|           0x100001906      mov   rax, qword [format]
|           0x10000190a      mov   rsi, qword [section.14.__DATA.__objc_selrefs] ; [0x1000032f8:8]=0x100001ecf section.4.__TEXT.__objc_methname
|           0x100001911      mov   rdi, rax
|           0x100001914      call  qword [reloc.objc_msgSend]          ; [0x100002000:8]=0 ; Message dispatch to method_Employee_sayHello
|           0x10000191a      mov   rsi, qword [section.15.__DATA.__objc_classrefs] ; [0x100003320:8]=0x100003370 sym.class_Employee ; "p3"
|           0x100001921      mov   rdi, qword [section.14.__DATA.__objc_selrefs] ; [0x1000032f8:8]=0x100001ecf section.4.__TEXT.__objc_methname
|           0x100001928      mov   qword [var_50h], rdi
|           0x10000192c      mov   rdi, rsi
|           0x10000192f      mov   rsi, qword [var_50h]
|           0x100001933      mov   qword [var_58h], rax
|           0x100001937      call  qword [reloc.objc_msgSend]          ; [0x100002000:8]=0 ; Message dispatch to method_Employee_sayHello
|           0x10000193d      mov   rsi, qword [format]
|           0x100001941      lea   rdi, qword str.base__p              ; 0x100001dbe ; "base %p\n" ; const char *format
|           0x100001948      mov   qword [var_60h], rax
|           0x10000194c      mov   al, 0x00
|           0x10000194e      call  sym.imp.printf                      ; int printf(const char *format)
|           0x100001953      mov   rsi, qword [format]
|           0x100001957      mov   qword [var_28h], rsi
|           0x10000195b      mov   rsi, qword [format]
|           0x10000195f      mov   rdi, qword [data.100003300]         ; [0x100003300:8]=0x100001ed8 "p0"
|           0x100001966      mov   qword [var_68h], rdi
|           0x10000196a      mov   rdi, rsi
|           0x10000196d      mov   rsi, qword [var_68h]
|           0x100001971      mov   dword [var_6ch], eax
|           0x100001974      call  qword [reloc.objc_msgSend]          ; [0x100002000:8]=0
|           0x10000197a      mov   rsi, qword [var_28h]
|           0x10000197e      sub   rax, rsi
|           0x100001981      lea   rdi, qword str.iii__p__username     ; 0x100001dc7 ; "iii %p _username\n" ; const char *format
|           0x100001988      mov   rsi, rax
|           0x10000198b      mov   al, 0x00
|           0x10000198d      call  sym.imp.printf                      ; int printf(const char *format)
|           0x100001992      mov   rsi, qword [format]
|           0x100001996      mov   rdi, qword [data.100003308]         ; [0x100003308:8]=0x100001edb "p1"
|           0x10000199d      mov   qword [var_78h], rdi
|           0x1000019a1      mov   rdi, rsi
|           0x1000019a4      mov   rsi, qword [var_78h]
|           0x1000019a8      mov   dword [var_7ch], eax
|           0x1000019ab      call  qword [reloc.objc_msgSend]          ; [0x100002000:8]=0
|           0x1000019b1      mov   rsi, qword [var_28h]
|           0x1000019b5      sub   rax, rsi
|           0x1000019b8      lea   rdi, qword str.iii__p__firstName    ; 0x100001dd9 ; "iii %p _firstName\n" ; const char *format
|           0x1000019bf      mov   rsi, rax
|           0x1000019c2      mov   al, 0x00
|           0x1000019c4      call  sym.imp.printf                      ; int printf(const char *format)
|           0x1000019c9      mov   rsi, qword [format]
|           0x1000019cd      mov   rdi, qword [data.100003310]         ; [0x100003310:8]=0x100001ede "p2"
|           0x1000019d4      mov   qword [var_88h], rdi
|           0x1000019d8      mov   rdi, rsi
|           0x1000019db      mov   rsi, qword [var_88h]
|           0x1000019df      mov   dword [var_8ch], eax
|           0x1000019e5      call  qword [reloc.objc_msgSend]          ; [0x100002000:8]=0
|           0x1000019eb      mov   rsi, qword [var_28h]
|           0x1000019ef      sub   rax, rsi
|           0x1000019f2      lea   rdi, qword str.iii__p__shortWord    ; 0x100001dec ; "iii %p _shortWord\n" ; const char *format
|           0x1000019f9      mov   rsi, rax
|           0x1000019fc      mov   al, 0x00
|           0x1000019fe      call  sym.imp.printf                      ; int printf(const char *format)
|           0x100001a03      mov   rsi, qword [format]
|           0x100001a07      mov   rdi, qword [data.100003318]         ; [0x100003318:8]=0x100001ee1 "p3"
|           0x100001a0e      mov   qword [var_98h], rdi
|           0x100001a15      mov   rdi, rsi
|           0x100001a18      mov   rsi, qword [var_98h]
|           0x100001a1f      mov   dword [var_9ch], eax
|           0x100001a25      call  qword [reloc.objc_msgSend]          ; [0x100002000:8]=0
|           0x100001a2b      mov   rsi, qword [var_28h]
|           0x100001a2f      sub   rax, rsi
|           0x100001a32      lea   rdi, qword str.iii__p__wideWord     ; 0x100001dff ; "iii %p _wideWord\n" ; const char *format
|           0x100001a39      mov   rsi, rax
|           0x100001a3c      mov   al, 0x00
|           0x100001a3e      call  sym.imp.printf                      ; int printf(const char *format)
|           0x100001a43      mov   rsi, qword [format]
|           0x100001a47      mov   qword [var_30h], rsi
|           0x100001a4b      mov   dword [var_34h], 0x00
|           0x100001a52      mov   dword [var_a0h], eax
|           ; CODE XREF from entry0 @ 0x100001a8b
|       .-> 0x100001a58      cmp   dword [var_34h], 0x20
|      ,==< 0x100001a5c      jnl   0x100001a90
|      |:   0x100001a62      mov   rax, qword [var_30h]
|      |:   0x100001a66      movsxd rcx, dword [var_34h]
|      |:   0x100001a6a      movzx esi, byte [rax+rcx*1]
|      |:   0x100001a6e      lea   rdi, qword str.02x                  ; 0x100001e11 ; "%02x " ; const char *format
|      |:   0x100001a75      mov   al, 0x00
|      |:   0x100001a77      call  sym.imp.printf                      ; int printf(const char *format)
|      |:   0x100001a7c      mov   dword [var_a4h], eax
|      |:   0x100001a82      mov   eax, dword [var_34h]
|      |:   0x100001a85      add   eax, 0x01
|      |:   0x100001a88      mov   dword [var_34h], eax
|      |`=< 0x100001a8b      jmp   0x100001a58
|      `--> 0x100001a90      lea   rdi, qword str.                     ; 0x100001e17 ; "\n" ; const char *format
|           0x100001a97      mov   al, 0x00
|           0x100001a99      call  sym.imp.printf                      ; int printf(const char *format)
|           0x100001a9e      lea   rdi, qword reloc.__CFConstantStringClassReference.100002030 ; rsi
|                                                                      ; 0x100002030
|           0x100001aa5      mov   qword [var_40h], rdi
|           0x100001aa9      mov   rsi, qword [var_40h]
|           0x100001aad      lea   rdi, qword str.p                    ; 0x100001e28 ; "%p\n" ; const char *format
|           0x100001ab4      mov   dword [var_a8h], eax
|           0x100001aba      mov   al, 0x00
|           0x100001abc      call  sym.imp.printf                      ; int printf(const char *format)
\           0x100001ac1      int3
EOF
RUN

NAME=objc msg dispatch (arm64)
FILE=bins/mach0/objc-employee-ios14-arm64
CMDS=<<EOF
aaaa
avD @ main
pdf @ main
EOF
EXPECT=<<EOF
            ; UNKNOWN XREF from segment.TEXT @ +0xd0
            ;-- main:
            ;-- section.0.__TEXT.__text:
            ;-- _main:
            ;-- func.100007714:
/ entry0(int64_t arg1, int64_t arg2);
|           ; arg int64_t arg1 @ x0
|           ; arg int64_t arg2 @ x1
|           ; var int64_t var_80h @ stack - 0x80
|           ; var int64_t var_68h @ stack - 0x68
|           ; var int64_t var_60h @ stack - 0x60
|           ; var int64_t var_58h @ stack - 0x58
|           ; var int64_t var_50h @ stack - 0x50
|           ; var int64_t var_48h @ stack - 0x48
|           ; var int64_t var_3ch @ stack - 0x3c
|           ; var int64_t var_38h @ stack - 0x38
|           ; var int64_t var_30h @ stack - 0x30
|           ; var int64_t var_28h @ stack - 0x28
|           ; var int64_t var_20h @ stack - 0x20
|           ; var int64_t var_18h @ stack - 0x18
|           ; var int64_t var_14h @ stack - 0x14
|           ; var int64_t var_10h @ stack - 0x10
|           ; var int64_t var_8h @ stack - 0x8
|           0x100007714      sub   sp, sp, 0x80                        ; [00] -r-x section size 1180 named 0.__TEXT.__text
|           0x100007718      stp   fp, lr, [var_10h]
|           0x10000771c      add   fp, sp, 0x70
|           0x100007720      stur  wzr, [var_14h]                      ; arg1
|           0x100007724      stur  w0, [var_18h]                       ; arg1
|           0x100007728      stur  x1, [var_20h]                       ; arg2
|           0x10000772c      bl    fcn.100007bd4
|           0x100007730      adrp  x8, reloc.dyld_stub_binder          ; 0x100008000
|           0x100007734      add   x8, x8, 8                           ; 0x100008008
|                                                                      ; reloc.__CFConstantStringClassReference
|           0x100007738      str   x0, [var_50h]
|           0x10000773c      mov   x0, x8
|           0x100007740      bl    section.1.__TEXT.__stubs            ;  section.1.__TEXT.__stubs(void)
|           0x100007744      adrp  x8, reloc.NSLog                     ; 0x10000c000
|           0x100007748      add   x8, x8, 0x220                       ; 0x10000c220 ; "`\xc2"
|           0x10000774c      ldr   x0, [x8]                            ; [0x10000c220:4]=0xc260 ; "`\xc2"
|           0x100007750      str   x8, [var_58h]
|           0x100007754      bl    fcn.100007bbc
|           0x100007758      stur  x0, [var_28h]
|           0x10000775c      ldur  x0, [var_28h]
|           0x100007760      adrp  x8, reloc.NSLog                     ; 0x10000c000
|           0x100007764      add   x8, x8, 0x1f0
|           0x100007768      ldr   x1, [x8]                            ; [0x100007ea9:4]=0x48796173 ; "sayHello"
|           0x10000776c      str   x8, [var_60h]
|           0x100007770      bl    fcn.100007bec                       ; Message dispatch to method_Employee_sayHello
|           0x100007774      ldr   x8, [var_58h]                       ; [0x28:4]=-1 ; 40
|           0x100007778      ldr   x0, [x8]
|           0x10000777c      ldr   x9, [var_60h]                       ; [0x20:4]=-1 ; 32
|           0x100007780      ldr   x1, [x9]
|           0x100007784      bl    fcn.100007bec                       ; Message dispatch to method_Employee_sayHello
|           0x100007788      ldur  x8, [var_28h]
|           0x10000778c      adrp  x0, data.100007000                  ; 0x100007000
|           0x100007790      add   x0, x0, 0xd98                       ; 0x100007d98 ; "base %p\n"
|           0x100007794      mov   x9, sp
|           0x100007798      str   x8, [x9]
|           0x10000779c      bl    fcn.100007c1c
|           0x1000077a0      ldur  x8, [var_28h]
|           0x1000077a4      adrp  x9, reloc.NSLog                     ; 0x10000c000
|           0x1000077a8      add   x9, x9, 0x1f8
|           0x1000077ac      ldr   x1, [x9]                            ; [0x100007eb2:4]=0x65736162 ; "base"
|           0x1000077b0      mov   x0, x8
|           0x1000077b4      bl    fcn.100007bec                       ; Message dispatch to method_Employee_base
|           0x1000077b8      stur  x0, [var_30h]
|           0x1000077bc      ldur  x0, [var_28h]
|           0x1000077c0      adrp  x8, reloc.NSLog                     ; 0x10000c000
|           0x1000077c4      add   x8, x8, 0x200
|           0x1000077c8      ldr   x1, [x8]
|           0x1000077cc      bl    fcn.100007bec
|           0x1000077d0      ldur  x8, [var_30h]
|           0x1000077d4      subs  x8, x0, x8
|           0x1000077d8      adrp  x0, data.100007000                  ; 0x100007000
|           0x1000077dc      add   x0, x0, 0xda1                       ; 0x100007da1 ; "iii %p _username\n"
|           0x1000077e0      mov   x9, sp
|           0x1000077e4      str   x8, [x9]
|           0x1000077e8      bl    fcn.100007c1c
|           0x1000077ec      ldur  x8, [var_28h]
|           0x1000077f0      adrp  x9, reloc.NSLog                     ; 0x10000c000
|           0x1000077f4      add   x9, x9, 0x208
|           0x1000077f8      ldr   x1, [x9]
|           0x1000077fc      mov   x0, x8
|           0x100007800      bl    fcn.100007bec
|           0x100007804      ldur  x8, [var_30h]
|           0x100007808      subs  x8, x0, x8
|           0x10000780c      adrp  x0, data.100007000                  ; 0x100007000
|           0x100007810      add   x0, x0, 0xdb3                       ; 0x100007db3 ; "iii %p _firstName\n"
|           0x100007814      mov   x9, sp
|           0x100007818      str   x8, [x9]
|           0x10000781c      bl    fcn.100007c1c
|           0x100007820      ldur  x8, [var_28h]
|           0x100007824      adrp  x9, reloc.NSLog                     ; 0x10000c000
|           0x100007828      add   x9, x9, 0x210
|           0x10000782c      ldr   x1, [x9]
|           0x100007830      mov   x0, x8
|           0x100007834      bl    fcn.100007bec
|           0x100007838      ldur  x8, [var_30h]
|           0x10000783c      subs  x8, x0, x8
|           0x100007840      adrp  x0, data.100007000                  ; 0x100007000
|           0x100007844      add   x0, x0, 0xdc6                       ; 0x100007dc6 ; "iii %p _shortWord\n"
|           0x100007848      mov   x9, sp
|           0x10000784c      str   x8, [x9]
|           0x100007850      bl    fcn.100007c1c
|           0x100007854      ldur  x8, [var_28h]
|           0x100007858      adrp  x9, reloc.NSLog                     ; 0x10000c000
|           0x10000785c      add   x9, x9, 0x218
|           0x100007860      ldr   x1, [x9]
|           0x100007864      mov   x0, x8
|           0x100007868      bl    fcn.100007bec
|           0x10000786c      ldur  x8, [var_30h]
|           0x100007870      subs  x8, x0, x8
|           0x100007874      adrp  x0, data.100007000                  ; 0x100007000
|           0x100007878      add   x0, x0, 0xdd9                       ; 0x100007dd9 ; "iii %p _wideWord\n"
|           0x10000787c      mov   x9, sp
|           0x100007880      str   x8, [x9]
|           0x100007884      bl    fcn.100007c1c
|           0x100007888      ldur  x8, [var_28h]
|           0x10000788c      stur  x8, [var_38h]
|           0x100007890      stur  wzr, [var_3ch]
|           ; CODE XREF from entry0 @ 0x1000078d0
|       .-> 0x100007894      ldur  w8, [var_3ch]
|       :   0x100007898      cmp   w8, 0x20
|      ,==< 0x10000789c      b.ge  0x1000078d4
|      |:   0x1000078a0      ldur  x8, [var_38h]
|      |:   0x1000078a4      ldursw x9, [var_3ch]
|      |:   0x1000078a8      ldrb  w10, [x8, x9]
|      |:   0x1000078ac      adrp  x0, data.100007000                  ; 0x100007000
|      |:   0x1000078b0      add   x0, x0, 0xdeb                       ; 0x100007deb ; "%02x "
|      |:   0x1000078b4      mov   x8, sp
|      |:   0x1000078b8      mov   x1, x10
|      |:   0x1000078bc      str   x1, [x8]
|      |:   0x1000078c0      bl    fcn.100007c1c
|      |:   0x1000078c4      ldur  w8, [var_3ch]
|      |:   0x1000078c8      add   w8, w8, 1
|      |:   0x1000078cc      stur  w8, [var_3ch]
|      |`=< 0x1000078d0      b     0x100007894
|      `--> 0x1000078d4      adrp  x0, data.100007000                  ; 0x100007000
|           0x1000078d8      add   x0, x0, 0xdf1
|           0x1000078dc      bl    fcn.100007c1c
|           0x1000078e0      adrp  x8, reloc.dyld_stub_binder          ; 0x100008000
|           0x1000078e4      add   x8, x8, 0x28                        ; 0x100008028
|                                                                      ; x9
|           0x1000078e8      mov   x0, x8
|           0x1000078ec      bl    fcn.100007bf8
|           0x1000078f0      add   x8, var_48h
|           0x1000078f4      str   x0, [var_48h]
|           0x1000078f8      ldr   x9, [var_48h]                       ; x1
|                                                                      ; [0x38:4]=-1
|           0x1000078fc      adrp  x0, data.100007000                  ; 0x100007000
|           0x100007900      add   x0, x0, 0xe02                       ; 0x100007e02 ; "%p\n"
|           0x100007904      mov   x10, sp
|           0x100007908      str   x9, [x10]
|           0x10000790c      str   x8, [var_68h]
|           0x100007910      bl    fcn.100007c1c
|           ;-- x30:
|           ;-- lr:
|           ;-- pc:
\           0x100007914      brk   1
EOF
RUN

NAME=objc msg dispatch (arm64)
FILE=bins/mach0/objc-employee-ios14-arm64e
CMDS=<<EOF
aaaa
avD @ main
pdf @ main
EOF
EXPECT=<<EOF
            ; UNKNOWN XREF from segment.TEXT @ +0xd0
            ;-- main:
            ;-- section.0.__TEXT.__text:
            ;-- _main:
            ;-- func.100007760:
/ entry0(int64_t arg1, int64_t arg2);
|           ; arg int64_t arg1 @ x0
|           ; arg int64_t arg2 @ x1
|           ; var int64_t var_80h @ stack - 0x80
|           ; var int64_t var_68h @ stack - 0x68
|           ; var int64_t var_60h @ stack - 0x60
|           ; var int64_t var_58h @ stack - 0x58
|           ; var int64_t var_50h @ stack - 0x50
|           ; var int64_t var_48h @ stack - 0x48
|           ; var int64_t var_3ch @ stack - 0x3c
|           ; var int64_t var_38h @ stack - 0x38
|           ; var int64_t var_30h @ stack - 0x30
|           ; var void *instance @ stack - 0x28
|           ; var int64_t var_20h @ stack - 0x20
|           ; var int64_t var_18h @ stack - 0x18
|           ; var int64_t var_14h @ stack - 0x14
|           ; var int64_t var_10h @ stack - 0x10
|           ; var int64_t var_8h @ stack - 0x8
|           0x100007760      pacibsp                                   ; [00] -r-x section size 1208 named 0.__TEXT.__text
|           0x100007764      sub   sp, sp, 0x80
|           0x100007768      stp   fp, lr, [var_10h]
|           0x10000776c      add   fp, sp, 0x70
|           0x100007770      stur  wzr, [var_14h]                      ; arg1
|           0x100007774      stur  w0, [var_18h]                       ; arg1
|           0x100007778      stur  x1, [var_20h]                       ; arg2
|           0x10000777c      bl    sym.imp.objc_autoreleasePoolPush
|           0x100007780      adrp  x8, reloc.NSLog                     ; 0x100008000
|           0x100007784      add   x8, x8, 0x50                        ; 0x100008050 ; "X\x80\U00000001"
|           0x100007788      str   x0, [var_50h]
|           0x10000778c      mov   x0, x8
|           0x100007790      bl    sym.imp.NSLog
|           0x100007794      adrp  x8, sym.__OBJC_METACLASS_RO___Employee ; 0x10000c000
|           0x100007798      add   x8, x8, 0x1d0                       ; 0x10000c1d0
|                                                                      ; section.14.__DATA.__objc_classrefs
|           0x10000779c      ldr   x0, [x8]                            ; [0x10000c1d0:4]=0xc210 ; section.14.__DATA.__objc_classrefs
|           0x1000077a0      str   x8, [var_58h]
|           0x1000077a4      bl    sym.imp.objc_alloc_init
|           0x1000077a8      stur  x0, [instance]
|           0x1000077ac      ldur  x0, [instance]                      ; void *instance
|           0x1000077b0      adrp  x8, sym.__OBJC_METACLASS_RO___Employee ; 0x10000c000
|           0x1000077b4      add   x8, x8, 0x1a0
|           0x1000077b8      ldr   x1, [x8]                            ; [0x100007ea9:4]=0x48796173 ; "sayHello" ; char *selector
|           0x1000077bc      str   x8, [var_60h]
|           0x1000077c0      bl    sym.imp.objc_msgSend                ; Message dispatch to method_Employee_sayHello ; void *objc_msgSend(void *instance, char *selector)
|           0x1000077c4      ldr   x8, [var_58h]                       ; [0x28:4]=-1 ; 40
|           0x1000077c8      ldr   x0, [x8]                            ; void *instance
|           0x1000077cc      ldr   x9, [var_60h]                       ; [0x20:4]=-1 ; 32
|           0x1000077d0      ldr   x1, [x9]                            ; char *selector
|           0x1000077d4      bl    sym.imp.objc_msgSend                ; Message dispatch to method_Employee_sayHello ; void *objc_msgSend(void *instance, char *selector)
|           0x1000077d8      ldur  x8, [instance]
|           0x1000077dc      adrp  x0, data.100007000                  ; 0x100007000
|           0x1000077e0      add   x0, x0, 0xd98                       ; 0x100007d98 ; "base %p\n" ; const char *format
|           0x1000077e4      mov   x9, sp
|           0x1000077e8      str   x8, [x9]
|           0x1000077ec      bl    sym.imp.printf                      ; int printf(const char *format)
|           0x1000077f0      ldur  x8, [instance]
|           0x1000077f4      adrp  x9, sym.__OBJC_METACLASS_RO___Employee ; 0x10000c000
|           0x1000077f8      add   x9, x9, 0x1a8
|           0x1000077fc      ldr   x1, [x9]                            ; [0x100007eb2:4]=0x65736162 ; "base" ; char *selector
|           0x100007800      mov   x0, x8                              ; void *instance
|           0x100007804      bl    sym.imp.objc_msgSend                ; Message dispatch to method_Employee_base ; void *objc_msgSend(void *instance, char *selector)
|           0x100007808      stur  x0, [var_30h]
|           0x10000780c      ldur  x0, [instance]                      ; void *instance
|           0x100007810      adrp  x8, sym.__OBJC_METACLASS_RO___Employee ; 0x10000c000
|           0x100007814      add   x8, x8, 0x1b0
|           0x100007818      ldr   x1, [x8]                            ; char *selector
|           0x10000781c      bl    sym.imp.objc_msgSend                ; void *objc_msgSend(void *instance, char *selector)
|           0x100007820      ldur  x8, [var_30h]
|           0x100007824      subs  x8, x0, x8
|           0x100007828      adrp  x0, data.100007000                  ; 0x100007000
|           0x10000782c      add   x0, x0, 0xda1                       ; 0x100007da1 ; "iii %p _username\n" ; const char *format
|           0x100007830      mov   x9, sp
|           0x100007834      str   x8, [x9]
|           0x100007838      bl    sym.imp.printf                      ; int printf(const char *format)
|           0x10000783c      ldur  x8, [instance]
|           0x100007840      adrp  x9, sym.__OBJC_METACLASS_RO___Employee ; 0x10000c000
|           0x100007844      add   x9, x9, 0x1b8
|           0x100007848      ldr   x1, [x9]                            ; char *selector
|           0x10000784c      mov   x0, x8                              ; void *instance
|           0x100007850      bl    sym.imp.objc_msgSend                ; void *objc_msgSend(void *instance, char *selector)
|           0x100007854      ldur  x8, [var_30h]
|           0x100007858      subs  x8, x0, x8
|           0x10000785c      adrp  x0, data.100007000                  ; 0x100007000
|           0x100007860      add   x0, x0, 0xdb3                       ; 0x100007db3 ; "iii %p _firstName\n" ; const char *format
|           0x100007864      mov   x9, sp
|           0x100007868      str   x8, [x9]
|           0x10000786c      bl    sym.imp.printf                      ; int printf(const char *format)
|           0x100007870      ldur  x8, [instance]
|           0x100007874      adrp  x9, sym.__OBJC_METACLASS_RO___Employee ; 0x10000c000
|           0x100007878      add   x9, x9, 0x1c0
|           0x10000787c      ldr   x1, [x9]                            ; char *selector
|           0x100007880      mov   x0, x8                              ; void *instance
|           0x100007884      bl    sym.imp.objc_msgSend                ; void *objc_msgSend(void *instance, char *selector)
|           0x100007888      ldur  x8, [var_30h]
|           0x10000788c      subs  x8, x0, x8
|           0x100007890      adrp  x0, data.100007000                  ; 0x100007000
|           0x100007894      add   x0, x0, 0xdc6                       ; 0x100007dc6 ; "iii %p _shortWord\n" ; const char *format
|           0x100007898      mov   x9, sp
|           0x10000789c      str   x8, [x9]
|           0x1000078a0      bl    sym.imp.printf                      ; int printf(const char *format)
|           0x1000078a4      ldur  x8, [instance]
|           0x1000078a8      adrp  x9, sym.__OBJC_METACLASS_RO___Employee ; 0x10000c000
|           0x1000078ac      add   x9, x9, 0x1c8
|           0x1000078b0      ldr   x1, [x9]                            ; char *selector
|           0x1000078b4      mov   x0, x8                              ; void *instance
|           0x1000078b8      bl    sym.imp.objc_msgSend                ; void *objc_msgSend(void *instance, char *selector)
|           0x1000078bc      ldur  x8, [var_30h]
|           0x1000078c0      subs  x8, x0, x8
|           0x1000078c4      adrp  x0, data.100007000                  ; 0x100007000
|           0x1000078c8      add   x0, x0, 0xdd9                       ; 0x100007dd9 ; "iii %p _wideWord\n" ; const char *format
|           0x1000078cc      mov   x9, sp
|           0x1000078d0      str   x8, [x9]
|           0x1000078d4      bl    sym.imp.printf                      ; int printf(const char *format)
|           0x1000078d8      ldur  x8, [instance]
|           0x1000078dc      stur  x8, [var_38h]
|           0x1000078e0      stur  wzr, [var_3ch]
|           ; CODE XREF from entry0 @ 0x100007920
|       .-> 0x1000078e4      ldur  w8, [var_3ch]
|       :   0x1000078e8      cmp   w8, 0x20
|      ,==< 0x1000078ec      b.ge  0x100007924
|      |:   0x1000078f0      ldur  x8, [var_38h]
|      |:   0x1000078f4      ldursw x9, [var_3ch]
|      |:   0x1000078f8      ldrb  w10, [x8, x9]
|      |:   0x1000078fc      adrp  x0, data.100007000                  ; 0x100007000
|      |:   0x100007900      add   x0, x0, 0xdeb                       ; 0x100007deb ; "%02x " ; const char *format
|      |:   0x100007904      mov   x8, sp
|      |:   0x100007908      mov   x1, x10
|      |:   0x10000790c      str   x1, [x8]
|      |:   0x100007910      bl    sym.imp.printf                      ; int printf(const char *format)
|      |:   0x100007914      ldur  w8, [var_3ch]
|      |:   0x100007918      add   w8, w8, 1
|      |:   0x10000791c      stur  w8, [var_3ch]
|      |`=< 0x100007920      b     0x1000078e4
|      `--> 0x100007924      adrp  x0, data.100007000                  ; 0x100007000
|           0x100007928      add   x0, x0, 0xdf1                       ; const char *format
|           0x10000792c      bl    sym.imp.printf                      ; int printf(const char *format)
|           0x100007930      adrp  x8, reloc.NSLog                     ; 0x100008000
|           0x100007934      add   x8, x8, 0x70                        ; 0x100008070 ; "X\x80\U00000001"
|           0x100007938      mov   x0, x8                              ; void *instance
|           0x10000793c      bl    sym.imp.objc_retain                 ; void objc_retain(void *instance)
|           0x100007940      add   x8, var_48h
|           0x100007944      str   x0, [var_48h]
|           0x100007948      ldr   x9, [var_48h]                       ; [0x38:4]=-1 ; 56
|           0x10000794c      adrp  x0, data.100007000                  ; 0x100007000
|           0x100007950      add   x0, x0, 0xe02                       ; 0x100007e02 ; "%p\n" ; const char *format
|           0x100007954      mov   x10, sp
|           0x100007958      str   x9, [x10]
|           0x10000795c      str   x8, [var_68h]
|           0x100007960      bl    sym.imp.printf                      ; int printf(const char *format)
|           ;-- x30:
|           ;-- lr:
|           ;-- pc:
\           0x100007964      brk   1
EOF
RUN