Annotations

Derek Bruening edited this page Nov 28, 2014 · 2 revisions

Notes and compiled samples for the new annotation infrastructure

Annotation Types

  1. Statement: the annotation directly precedes the call site - the target app may specify a block of statements to execute only on a native run
  2. Expression: the annotation appears at the beginning of the annotation function - the remainder of the annotation function only executes on a native run - the call site is not annotated

Every annotation function is defined as an expression, i.e., its body begins with the annotation tag. If a particular call site is annotated, that invocation becomes a statement, and the annotation function call is skipped in a native run. When calling an annotation as an expression, the annotation function is invoked (i.e., not skipped) to avoid control flow confusion in nested expressions (especially where annotation expressions are nested). The annotation tag is placed inside the annotation function for the expression context because (1) it is easy to find there, (2) it requires only one instrumentation per run, and (3) the function is being invoked anyway.

Annotation Samples from Debug Builds

Unix x64 Expression

C function definition

  DR_DEFINE_ANNOTATION(char, dynamorio_annotate_running_on_dynamorio, (), return 0)

C macro for definition of dynamorio_annotate_running_on_dynamorio():

#define LABEL_REFERENCE_LENGTH "0x11"
#define LABEL_REFERENCE_REGISTER "%rax"
#define ANNOTATION_FUNCTION_CLOBBER_LIST "%rax","%rcx","%rdx","%rsi","%rdi","%r8","%r9"
#define _CALL_TYPE
#define DR_ANNOTATION_ATTRIBUTES \
    __attribute__((noinline, visibility("hidden") _CALL_TYPE))
#define DR_DEFINE_ANNOTATION(return_type, annotation, parameters, body) \
    const char *annotation##_label = "dynamorio-annotation:"#annotation; \
    DR_ANNOTATION_ATTRIBUTES return_type annotation parameters \
    { \
        __label__ native_run, native_end_marker; \
        extern const char *annotation##_label; \
        __asm__ volatile goto (".byte 0xeb; .byte "LABEL_REFERENCE_LENGTH"; \
                               mov _GLOBAL_OFFSET_TABLE_,%"LABEL_REFERENCE_REGISTER"; \
                               bsr "#annotation"_label@GOT,%"LABEL_REFERENCE_REGISTER"; \
                               jmp %l0;" \
                               ::: ANNOTATION_FUNCTION_CLOBBER_LIST \
                               : native_run); \
        goto native_end_marker; \
        native_run: body; \
        native_end_marker: ; \
    }

ASM for dynamorio_annotate_running_on_dynamorio():

  40213e:   55                      push   %rbp                       # function preamble
  40213f:   48 89 e5                mov    %rsp,%rbp
  402142:   eb 11                   jmp    402155                     # jump to native version
  402144:   48 8b 04 25 b8 0e 20    mov    0x200eb8,%rax              # GOT offset from (%rip + 4)
  40214b:   00 
  40214c:   48 0f bd 04 25 b0 ff    bsr    0xffffffffffffffb0,%rax    # annotation name offset in GOT 
  402153:   ff ff                                                     # `bsr` indicates function tag
  402155:   eb 02                   jmp    402159 
  402157:   eb 07                   jmp    402160 
  402159:   b8 00 00 00 00          mov    $0x0,%eax                  # native version
  40215e:   eb 00                   jmp    402160
  402160:   5d                      pop    %rbp
  402161:   c3                      retq  

Unix x64 Statement

C code

  TEST_ANNOTATION_SET_MODE(init->id, MODE_1, 
  {
      printf("Mode 1 on %d\n", init->id); // native version
  });

C macro for TEST_ANNOTATION_SET_MODE():

#define LABEL_REFERENCE_LENGTH "0x11"
#define LABEL_REFERENCE_REGISTER "%rax"
#define ANNOTATION_FUNCTION_CLOBBER_LIST "%rax","%rcx","%rdx","%rsi","%rdi","%r8","%r9"
#define DR_ANNOTATION_OR_NATIVE(annotation, native_version, ...) \
({ \
    __label__ native_run, native_end_marker; \
    extern const char *annotation##_label; \
    __asm__ volatile goto (".byte 0xeb; .byte "LABEL_REFERENCE_LENGTH"; \
                            mov _GLOBAL_OFFSET_TABLE_,%"LABEL_REFERENCE_REGISTER"; \
                            bsf "#annotation"_label@GOT,%"LABEL_REFERENCE_REGISTER"; \
                            jmp %l0;" \
                            ::: LABEL_REFERENCE_REGISTER \
                            : native_run); \
    annotation(__VA_ARGS__); \
    goto native_end_marker; \
    native_run: native_version; \
    native_end_marker: ; \
})
#define TEST_ANNOTATION_SET_MODE(context_id, mode, native_version) \
    DR_ANNOTATION_OR_NATIVE(test_annotation_set_mode, native_version, context_id, mode)

ASM for annotated call to TEST_ANNOTATION_SET_MODE():

  401b60:   eb 11                   jmp    401b73 <main+0x7e6>      # jump over the annotation name reference
  401b62:   48 8b 04 25 9a 14 20    mov    0x20149a,%rax            # GOT offset from %eip
  401b69:   00                                                      
  401b6a:   48 0f bc 04 25 e0 ff    bsf    0xffffffffffffffe0,%rax  # offset of name reference within GOT (bsf indicates call site tag)
  401b71:   ff ff                                                   
  401b73:   eb 14                   jmp    401b89 <main+0x7fc>      # jump to the native version
  401b75:   8b 05 e5 15 20 00       mov    0x2015e5(%rip),%eax      # annotation args  
  401b7b:   be 01 00 00 00          mov    $0x1,%esi                
  401b80:   89 c7                   mov    %eax,%edi                
  401b82:   e8 20 06 00 00          callq  4021a7                   # annotation call
  401b87:   eb 17                   jmp    401ba0                   
  401b89:   8b 05 d1 15 20 00       mov    0x2015d1(%rip),%eax      # native version  
  401b8f:   89 c6                   mov    %eax,%esi               
  401b91:   bf b2 25 40 00          mov    $0x4025b2,%edi          
  401b96:   b8 00 00 00 00          mov    $0x0,%eax               
  401b9b:   e8 f0 f5 ff ff          callq  401190 <printf@plt>     
  401ba0:   c7 45 e8 00 00 00 00    movl   $0x0,-0x18(%rbp)         # app code...

Unix x86 Expression

C function definition

  DR_DEFINE_ANNOTATION(char, dynamorio_annotate_running_on_dynamorio, (), return 0)

C macro for definition of dynamorio_annotate_running_on_dynamorio():

#define LABEL_REFERENCE_LENGTH "0xc"
#define LABEL_REFERENCE_REGISTER "%eax"
#define ANNOTATION_FUNCTION_CLOBBER_LIST "%rax","%rcx","%rdx"
#define _CALL_TYPE , fastcall
#define DR_ANNOTATION_ATTRIBUTES \
    __attribute__((noinline, visibility("hidden") _CALL_TYPE))
#define DR_DEFINE_ANNOTATION(return_type, annotation, parameters, body) \
    const char *annotation##_label = "dynamorio-annotation:"#annotation; \
    DR_ANNOTATION_ATTRIBUTES return_type annotation parameters \
    { \
        __label__ native_run, native_end_marker; \
        extern const char *annotation##_label; \
        __asm__ volatile goto (".byte 0xeb; .byte "LABEL_REFERENCE_LENGTH"; \
                               mov _GLOBAL_OFFSET_TABLE_,%"LABEL_REFERENCE_REGISTER"; \
                               bsr "#annotation"_label@GOT,%"LABEL_REFERENCE_REGISTER"; \
                               jmp %l0;" \
                               ::: ANNOTATION_FUNCTION_CLOBBER_LIST \
                               : native_run); \
        goto native_end_marker; \
        native_run: body; \
        native_end_marker: ; \
    }

ASM for dynamorio_annotate_running_on_dynamorio():

 8049b68:   55                      push   %ebp              # function preamble
 8049b69:   89 e5                   mov    %esp,%ebp
 8049b6b:   eb 0c                   jmp    8049b79           # jump to native version
 8049b6d:   a1 93 24 00 00          mov    0x2493,%eax       # GOT offset from (%rip + 4)
 8049b72:   0f bd 05 d8 ff ff ff    bsr    0xffffffd8,%eax   # annotation name offset in GOT 
 8049b79:   eb 02                   jmp    8049b7d           # intermediate jump to native version
 8049b7b:   eb 07                   jmp    8049b84           # jump over native version
 8049b7d:   b8 00 00 00 00          mov    $0x0,%eax         # native version
 8049b82:   eb 00                   jmp    8049b84 
 8049b84:   5d                      pop    %ebp
 8049b85:   c3                      ret 

Unix x86 Statement

C code

  TEST_ANNOTATION_SET_MODE(init->id, MODE_1, 
  {
      printf("Mode 1 on %d\n", init->id); // native version
  });

C macro for TEST_ANNOTATION_SET_MODE():

#define LABEL_REFERENCE_LENGTH "0xc"
#define LABEL_REFERENCE_REGISTER "%eax"
#define ANNOTATION_FUNCTION_CLOBBER_LIST "%rax","%rcx","%rdx"
#define DR_ANNOTATION_OR_NATIVE(annotation, native_version, ...) \
({ \
    __label__ native_run, native_end_marker; \
    extern const char *annotation##_label; \
    __asm__ volatile goto (".byte 0xeb; .byte "LABEL_REFERENCE_LENGTH"; \
                            mov _GLOBAL_OFFSET_TABLE_,%"LABEL_REFERENCE_REGISTER"; \
                            bsf "#annotation"_label@GOT,%"LABEL_REFERENCE_REGISTER"; \
                            jmp %l0;" \
                            ::: LABEL_REFERENCE_REGISTER \
                            : native_run); \
    annotation(__VA_ARGS__); \
    goto native_end_marker; \
    native_run: native_version; \
    native_end_marker: ; \
})
#define TEST_ANNOTATION_SET_MODE(context_id, mode, native_version) \
    DR_ANNOTATION_OR_NATIVE(test_annotation_set_mode, native_version, context_id, mode)

ASM for annotated call to TEST_ANNOTATION_SET_MODE():

 8049610:   eb 0c                   jmp    804961e <main+0x6f1>  # jump over the annotation name reference
 8049612:   a1 ee 29 00 00          mov    0x29ee,%eax           # GOT offset from %eip
 8049617:   0f bc 05 f0 ff ff ff    bsf    0xfffffff0,%eax       # offset of name reference within GOT (bsf indicates call site tag)
 804961e:   eb 13                   jmp    8049633 <main+0x706>  # jump to the native version
 8049620:   a1 b8 c0 04 08          mov    0x804c0b8,%eax        # annotation args
 8049625:   ba 01 00 00 00          mov    $0x1,%edx             
 804962a:   89 c1                   mov    %eax,%ecx             
 804962c:   e8 92 05 00 00          call   8049bc3               # annotation call
 8049631:   eb 15                   jmp    8049648 <main+0x71b>  # jump over the native version
 8049633:   a1 b8 c0 04 08          mov    0x804c0b8,%eax        # native version
 8049638:   89 44 24 04             mov    %eax,0x4(%esp)
 804963c:   c7 04 24 9a 9f 04 08    movl   $0x8049f9a,(%esp)
 8049643:   e8 88 f6 ff ff          call   8048cd0 <printf@plt>
 8049648:   c7 45 e8 00 00 00 00    movl   $0x0,-0x18(%ebp)      # app code...

Windows x64 Expression

C function definition

  DR_DEFINE_ANNOTATION(char, dynamorio_annotate_running_on_dynamorio, (), return 0)

C macro for definition of dynamorio_annotate_running_on_dynamorio():

#define DR_DEFINE_ANNOTATION_LABELS(annotation) \
    const char *annotation##_expression_label = "dynamorio-annotation:expression:"#annotation; \
    const char *annotation##_statement_label = "dynamorio-annotation:statement:"#annotation;
#define DR_DEFINE_ANNOTATION(return_type, annotation, parameters, body) \
    DR_DEFINE_ANNOTATION_LABELS(annotation) \
    return_type __fastcall annotation parameters \
    { \
        DR_ANNOTATION_FUNCTION(annotation, body) \
    }

C macro for function tag of dynamorio_annotate_running_on_dynamorio():

#define DR_ANNOTATION_FUNCTION(annotation, body) \
    if (GET_RETURN_PTR() == (void *) 0) { \
        extern const char *annotation##_expression_label; \
        __int2c(); \
        _m_prefetchw(annotation##_expression_label); \
        __debugbreak(); \
    } else { \
        body; \
    }

ASM for annotation in dynamorio_annotate_running_on_dynamorio():

  0000000140001FF0: 48 8D 04 24        lea         rax,[# _AddressOfReturnAddress()
  0000000140001FF4: 48 85 C0           test        rax,rax            
  0000000140001FF7: 75 0F              jne         0000000140002008   # jump to the native version
  0000000140001FF9: CD 2C              int         2Ch                # detection hint
  0000000140001FFB: 48 8B 05 FE BF 02  mov         rax,qword ptr [dynamorio_annotate_running_on_dynamorio_expression_label](rsp])
                    00
  0000000140002002: 0F 0D 08           prefetchw   [# (guarantee that the label variable gets used)
  0000000140002005: CC                 int         3                  # (discourage compiler reorderings)
  0000000140002006: EB 02              jmp         000000014000200A   # jump over the native version
  0000000140002008: 32 C0              xor         al,al              # native version (return 0)
  000000014000200A: F3 C3              rep ret

Windows x64 Statement

C code

  TEST_ANNOTATION_SET_MODE(init->id, MODE_1, 
  {
      printf("Mode 1 on %d\n", init->id); // native version
  });

C macro for TEST_ANNOTATION_SET_MODE():

#define DR_ANNOTATION_OR_NATIVE(annotation, native_version, ...) \
do { \
    if ((unsigned __int64) GET_RETURN_PTR() > (0xfffffffffffffff1 - (2 * __LINE__))) { \
        extern const char *annotation##_statement_label; \
        __int2c(); \
        _m_prefetchw(annotation##_statement_label); \
        __debugbreak(); \
        annotation(__VA_ARGS__); \
    } else { \
        native_version; \
    } \
} while ((unsigned __int64) GET_RETURN_PTR() > (0xfffffffffffffff0 - (2 * __LINE__)))
#define TEST_ANNOTATION_SET_MODE(context_id, mode, native_version) \
    DR_ANNOTATION_OR_NATIVE(test_annotation_set_mode, native_version, context_id, mode)

ASM for annotated call to TEST_ANNOTATION_SET_MODE():

  00000001400019B6: 48 8D 84 24 C8 00  lea         rax,[rsp+0C8h](rax])           # _AddressOfReturnAddress() (annotation head)
                    00 00                                                   
  00000001400019BE: 48 3D EF FD FF FF  cmp         rax,0FFFFFFFFFFFFFDEFh   
  00000001400019C4: 76 1F              jbe         00000001400019E5         # jump to the native version (always taken)
  00000001400019C6: CD 2C              int         2Ch                      # detection hint
  00000001400019C8: 48 8B 05 41 C8 02  mov         rax,qword ptr [00
  00000001400019CF: 0F 0D 08           prefetchw   [rax](test_annotation_set_mode_statement_label])                       # (guarantee that the label variable gets used)
  00000001400019D2: CC                 int         3                           # (discourage compiler reorderings)
  00000001400019D3: BA 01 00 00 00     mov         edx,1                       # annotations args
  00000001400019D8: 8B 0D 82 E7 02 00  mov         ecx,dword ptr [# (arbitrary code may appear among the args)
  00000001400019DE: E8 8D 06 00 00     call        test_annotation_set_mode    # annotation call
  00000001400019E3: EB 12              jmp         00000001400019F7            # jump over the native version
  00000001400019E5: 8B 15 75 E7 02 00  mov         edx,dword ptr [140030160h](140030160h])  # native version--calls printf()
  00000001400019EB: 48 8D 0D 56 26 02  lea         rcx,[00
  00000001400019F2: E8 5D 0C 00 00     call        printf
  00000001400019F7: 48 8D 84 24 C8 00  lea         rax,[rsp+0C8h](??_C@_0O@NICOHPLL@Mode?51?5on?5?$CFd?6?$AA@])           # _AddressOfReturnAddress() (annotation tail)
                    00 00
  00000001400019FF: 48 3D EE FD FF FF  cmp         rax,0FFFFFFFFFFFFFDEEh   
  0000000140001A05: 77 AF              ja          00000001400019B6         # loopback to annotation head (never taken)
  0000000140001A07: C7 44 24 50 00 00  mov         dword ptr [# app code...
                    00 00                                                   

Windows x86 Expression

C function definition

  DR_DEFINE_ANNOTATION(char, dynamorio_annotate_running_on_dynamorio, (), return 0)

C macro for definition of dynamorio_annotate_running_on_dynamorio():

#define DR_DEFINE_ANNOTATION(return_type, annotation, parameters, body) \
    DR_DEFINE_ANNOTATION_LABELS(annotation) \
    return_type __fastcall annotation parameters \
    { \
        DR_ANNOTATION_FUNCTION(annotation, body) \
    }

C macro for function tag of dynamorio_annotate_running_on_dynamorio():

#define DR_ANNOTATION_FUNCTION_INSTANCE(unique_id, annotation, body) \
    __asm { \
        __asm _emit 0xeb \
        __asm _emit 0x06 \
        __asm mov eax, annotation##_label \
        __asm nop \
        __asm jmp PASTE(native_run, unique_id) \
    } \
    goto PASTE(native_end_marker, unique_id); \
    PASTE(native_run, unique_id): body; \
    PASTE(native_end_marker, unique_id): ;
#define DR_ANNOTATION_FUNCTION(annotation, body) \
    DR_ANNOTATION_FUNCTION_INSTANCE(__COUNTER__, annotation, body)

ASM for dynamorio_annotate_running_on_dynamorio():

  00401990: 55                 push        ebp
  00401991: 8B EC              mov         ebp,esp
  00401993: EB 06              jmp         0040199B   # jump over annotation
  00401995: A1 00 B0 42 00     mov         eax,dword ptr [_dynamorio_annotate_running_on_dynamorio_label](rsp+50h],0)
  0040199A: 90                 nop
  0040199B: EB 02              jmp         0040199F   # jump to native version
  0040199D: EB 02              jmp         004019A1   # jump over native version
  0040199F: 32 C0              xor         al,al      # native version
  004019A1: 5D                 pop         ebp
  004019A2: C3                 ret

Windows x86 Statement

C code

  TEST_ANNOTATION_SET_MODE(init->id, MODE_1, 
  {
      printf("Mode 1 on %d\n", init->id); // native version
  });

C macro for TEST_ANNOTATION_SET_MODE():

#define DR_ANNOTATION_OR_NATIVE(annotation, native_version, ...) \
    { \
        extern const char *annotation##_name; \
        __asm { \
            __asm _emit 0xeb \
            __asm _emit 0x06 \
            __asm mov eax, annotation##_name \
            __asm _emit 0x01 \
            __asm jmp PASTE(native_execution_, __LINE__) \
            __asm jmp PASTE(native_end_marker_, __LINE__) \
        } \
        annotation(__VA_ARGS__); \
        PASTE(native_execution_, __LINE__) : native_version; \
        PASTE(native_end_marker_, __LINE__): ; \
    }
#define TEST_ANNOTATION_SET_MODE(context_id, mode, native_version) \
    DR_ANNOTATION_OR_NATIVE(test_annotation_set_mode, native_version, context_id, mode)

ASM for annotated call to TEST_ANNOTATION_SET_MODE():

  00401782: EB 06              jmp         0040178A
  00401784: A1 BC B0 42 00     mov         eax,dword ptr [00401789: 58                 pop         eax        # indicates call site tag (avoids EB 05, which is common in windows core libs)
  0040178A: EB 12              jmp         0040179E                              # jump to the native version
  0040178C: BA 01 00 00 00     mov         edx,1                                 # annotation args
  00401791: 8B 0D 70 C7 42 00  mov         ecx,dword ptr ds:[42C770h](_test_annotation_set_mode_label])
  00401797: E8 96 F8 FF FF     call        @ILT+45(@test_annotation_set_mode@8)  # annotation call
  0040179C: EB 14              jmp         004017B2                              # jump over the native version 
  0040179E: 8B 0D 70 C7 42 00  mov         ecx,dword ptr ds:[# native version 
  004017A4: 51                 push        ecx
  004017A5: 68 80 3F 42 00     push        offset ??_C@_0O@NICOHPLL@Mode?51?5on?5?$CFd?6?$AA@
  004017AA: E8 BB 09 00 00     call        _printf
  004017AF: 83 C4 08           add         esp,8
  004017B2: C7 45 FC 00 00 00  mov         dword ptr [ebp-4](42C770h]),0                   # app code...
            00

Samples of Special Cases

Nested annotations: Windows x64 (/Ox /GL)

C code for nested annotations

static __inline int
annotated_function()
{
    NOTE2(7, 8);
    return 9;
}

int main(void)
{
    NOTE1(1, 2, annotated_function());
}

ASM for nested annotations:

  000000014000F936: 48 8D 5C 24 28     lea         rbx,[# _AddressOfReturnAddress()
  000000014000F93B: 0F 1F 44 00 00     nop         dword ptr [rax+rax](rsp+28h])        
  000000014000F940: 48 81 FB 6D FF FF  cmp         rbx,0FFFFFFFFFFFFFF6Dh     # NOTE1 head
                    FF                                                        
  000000014000F947: 76 44              jbe         000000014000F98D           # target is NOTE1 tail
  000000014000F949: CD 2C              int         2Ch                        # annotation hint
  000000014000F94B: 0F 0D 0D 9E A9 00  prefetchw   [# operand is ((char *) NOTE1 label)
                    00                                                        
  000000014000F952: CC                 int         3                          # (discourage compiler reorderings)
  000000014000F953: 48 81 FB 79 FF FF  cmp         rbx,0FFFFFFFFFFFFFF79h     # NOTE2 head
                    FF                                                        
  000000014000F95A: 76 17              jbe         000000014000F973           # target is NOTE2 tail
  000000014000F95C: CD 2C              int         2Ch                        # annotation hint
  000000014000F95E: 0F 0D 0D DB A9 00  prefetchw   [14001A340h](14001A2F0h])               
                    00                                                        
  000000014000F965: CC                 int         3                          # (discourage compiler reorderings)
  000000014000F966: BA 08 00 00 00     mov         edx,8                      # NOTE2 args
  000000014000F96B: 8D 4A FF           lea         ecx,[000000014000F96E: E8 9D 00 00 00     call        note2                      
  000000014000F973: 48 81 FB 78 FF FF  cmp         rbx,0FFFFFFFFFFFFFF78h     # NOTE2 tail
                    FF                                                        
  000000014000F97A: 77 D7              ja          000000014000F953           
  000000014000F97C: BA 02 00 00 00     mov         edx,2                      # NOTE1 args
  000000014000F981: 44 8D 42 07        lea         r8d,[rdx+7](rdx-1])                
  000000014000F985: 8D 4A FF           lea         ecx,[000000014000F988: E8 B3 00 00 00     call        note1                      
  000000014000F98D: 48 81 FB 6C FF FF  cmp         rbx,0FFFFFFFFFFFFFF6Ch     # NOTE1 tail
                    FF
  000000014000F994: 77 AA              ja          000000014000F940
  000000014000F996: 33 C0              xor         eax,eax                    # app code...

Nested annotations with shared label: Windows x64 (/Ox /GL)

C code for nested annotations with shared label

INLINE double Triangle::get_b()
{
    TEST_ANNOTATION_TWO_ARGS(__LINE__, (unsigned int) get_c(), {
        printf("Native two-args in Triangle::get_b()\n");
    });

    return lengths[1](rdx-1]);
}

INLINE double Triangle::get_c()
{
    TEST_ANNOTATION_TWO_ARGS(__LINE__, (unsigned int) get_a(), {
        printf("Native two-args in Triangle::get_c()\n");
    });
    TEST_ANNOTATION_THREE_ARGS(__LINE__, 0x77, 0x7890);

    return lengths[}

ASM for nested annotations with shared label

  00000001400011AD: 48 8D 7C 24 28     lea         rdi,[rsp+28h](2];)             # _AddressOfReturnAddress()
  00000001400011B2: 48 81 FF D9 FE FF  cmp         rdi,0FFFFFFFFFFFFFED9h    
                    FF                                                       
  00000001400011B9: 76 79              jbe         0000000140001234          # outer annotation head
  00000001400011BB: CD 2C              int         2Ch                       # outer annotation hint
  00000001400011BD: 48 8B 05 84 FE 02  mov         rax,qword ptr [# shared!!
                    00
  00000001400011C4: 0F 0D 08           prefetchw   [rax](test_annotation_two_args_statement_label])                     # outer annotation label use
  00000001400011C7: CC                 int         3                         # (discourage compiler reorderings)
  00000001400011C8: 0F 1F 84 00 00 00  nop         dword ptr [# (compiler padded)
                    00 00                                                    
  00000001400011D0: 48 81 FF C7 FE FF  cmp         rdi,0FFFFFFFFFFFFFEC7h    # inner annotation head
                    FF                                                       
  00000001400011D7: 76 18              jbe         00000001400011F1          
  00000001400011D9: CD 2C              int         2Ch                       # inner annotation hint
  00000001400011DB: 0F 0D 08           prefetchw   [rax](rax+rax])                     # inner annotation uses shared label
  00000001400011DE: CC                 int         3                         # (discourage compiler reorderings)
  00000001400011DF: F2 48 0F 2C 53 08  cvttsd2si   rdx,mmword ptr [# inner annotation args
  00000001400011E5: B9 95 00 00 00     mov         ecx,95h                   
  00000001400011EA: E8 A1 02 00 00     call        test_annotation_two_args  # inner annotation call
  00000001400011EF: EB 0C              jmp         00000001400011FD          # inner annotation jump over native version
  00000001400011F1: 48 8D 0D 50 B2 02  lea         rcx,[??_C@_0CG@OGPOCELO@Native?5two?9args?5in?5Triangle?3?3get@](rbx+8])
                    00                                                       # inner annotation native version
  00000001400011F8: E8 07 08 00 00     call        printf
  00000001400011FD: 48 81 FF C6 FE FF  cmp         rdi,0FFFFFFFFFFFFFEC6h
                    FF
  0000000140001204: 76 09              jbe         000000014000120F          # jump over inner annotation tail
  0000000140001206: 48 8B 05 3B FE 02  mov         rax,qword ptr [00                                                       # inner annotation tail
  000000014000120D: EB C1              jmp         00000001400011D0
  000000014000120F: BA 77 00 00 00     mov         edx,77h                   # inner three-arg expression args
  0000000140001214: 41 B8 90 78 00 00  mov         r8d,7890h
  000000014000121A: 8D 4A 1F           lea         ecx,[rdx+1Fh](test_annotation_two_args_statement_label])
  000000014000121D: E8 9E 02 00 00     call        test_annotation_three_args  # inner three-arg expression call
  0000000140001222: B9 8C 00 00 00     mov         ecx,8Ch                   # outer annotation args
  0000000140001227: F2 48 0F 2C 53 18  cvttsd2si   rdx,mmword ptr [000000014000122D: E8 5E 02 00 00     call        test_annotation_two_args  # outer annotation call
  0000000140001232: EB 0C              jmp         0000000140001240          # jump over native version
  0000000140001234: 48 8D 0D E5 B1 02  lea         rcx,[??_C@_0CG@NLJOANAO@Native?5two?9args?5in?5Triangle?3?3get@](rbx+18h])
                    00
  000000014000123B: E8 C4 07 00 00     call        printf
  0000000140001240: 48 81 FF D8 FE FF  cmp         rdi,0FFFFFFFFFFFFFED8h    # outer annotation tail
                    FF
  0000000140001247: 0F 87 65 FF FF FF  ja          00000001400011B2

Detection Algorithms

Unix

  • For each ubr with exact byte sequence "EB XX" (where "XX" is "11" on x64 and "0c" on x86)
    • TRY_EXCEPT:
      • Attempt to read the operands of the next 2 instructions as (GOT + offset)
        • The first instruction (referring to GOT) must be a mov
          • The only src operand must be base/disp
        • The second instruction (referring to offset) must be a bsr or bsf
          • The only src operand must be base/disp
      • If the (GOT + offset) can be dereferenced as **(const char ***), and the string matches "dynamorio-annotation:(.*)"
        • The name of the annotation is the first regex group of the (GOT + offset) match
        • If the offset instruction was bsr, the code sequence is an expression (appearing at the top of an annotation function body)
        • If the offset instruction was bsf, the code sequence is a statement (appearing at an annotation site)
        • The current instruction will be a jump to the native version, and the following instruction will be the instrumentation pc
    • On EXCEPT: clean up resources and ignore any annotations found

Windows x86

  • For each ubr with exact byte sequence "EB 06"
    • TRY_EXCEPT:
    • Attempt to read the operand of the next instruction as a memory reference
      • The instruction must be a mov
        • The only src operand must be base/disp
    • If the operand can be dereferenced as *(const char **), and the resulting string matches "dynamorio-annotation:(.*)"
      • The name of the annotation is the first regex group of the match
      • Skip the next 1-byte instruction
        • If it is "nop" (0x90), the code sequence appears at the top of an annotation function body
        • If it is "pop eax" (0x58), the code sequence appears at an annotation site
      • The current instruction will be a jump to the native version, and the following instruction will be the instrumentation pc
    • On EXCEPT: clean up resources and ignore any annotations found

Windows x64

  • For each cbr
    • If (bb->checked_end == bb->cur_pc), execute a safe read of 1 byte; otherwise just read the byte
      • Return if the safe read is attempted and fails
    • Compare the byte to "CD" (interrupt)
      • Note: the interrupt should never execute, but this needs to be verified for C# and VB apps
      • TRY_EXCEPT:
      • Attempt to read the operand of the next instruction as a memory reference
        • The instruction may be a mov or a prefetchw
          • The only src operand must be rel addr
      • If the operand can be dereferenced as *(const char **), and the resulting string matches "dynamorio-annotation:(.**)"
        • Match the first regex group (i.e., above) against a second regex "(.**):(.*)"
          • If the first group of the second regex matches "expression", the code sequence appears at the top of an annotation function body
          • If the first group of the second regex matches "statement", the code sequence appears at an annotation site
        • Skip arbitrary instructions past the next "int 3" (there should usually just be one intervening instruction)
          • Memo the current pc as the instrumentation pc
          • If the next 2 instructions are "<cbr>; int 2c", repeat "skip arbitrary instructions..."
      • On EXCEPT: clean up resources and ignore any annotations found

Instrumentation Algorithms

Expression

Occurs at the top of an annotation function body

  • For each annotation handler registered for this annotation (by name)
    • insert a clean call to the handler at the instrumentation pc (as identified by the Detection Algorithms above)
    • terminate the basic block

Statement

Occurs at an annotation site

  • Skip translation of the annotation header
  • Resume translation at the instrumentation pc (as identified by the Detection Algorithms above)
    • Do not terminate the basic block at this point

Arbitrary code can appear within the annotation statement body, for example when the compiler inlines a call that appears in the annotation argument list, like this:

DYNAMORIO_SOME_ANNOTATION(foo(), bar());

Such inlined code can be very complex, including other calls and unrolled loops. To simplify the instrumentation, the annotation statement body is translated into the code cache without annotation-specific introspection. Instead of attempting to insert a clean call in place of the annotation function call (which occurs inside the annotation statement body), that call is translated like any other. The clean calls for registered annotation handlers are only inserted at the top of the annotation function body (see above).

You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.
Press h to open a hovercard with more details.