| /* ****************************************************************************** |
| * Copyright (c) 2010-2021 Google, Inc. All rights reserved. |
| * ******************************************************************************/ |
| |
| /* |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions are met: |
| * |
| * * Redistributions of source code must retain the above copyright notice, |
| * this list of conditions and the following disclaimer. |
| * |
| * * Redistributions in binary form must reproduce the above copyright notice, |
| * this list of conditions and the following disclaimer in the documentation |
| * and/or other materials provided with the distribution. |
| * |
| * * Neither the name of Google, Inc. nor the names of its contributors may be |
| * used to endorse or promote products derived from this software without |
| * specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
| * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| * ARE DISCLAIMED. IN NO EVENT SHALL VMWARE, INC. OR CONTRIBUTORS BE LIABLE |
| * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
| * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
| * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
| * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
| * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
| * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH |
| * DAMAGE. |
| */ |
| |
| /** |
| **************************************************************************** |
| \page page_annotations Annotations |
| |
| # Annotation Types |
| |
| -# <b>Statement</b>: the annotation directly precedes the call site |
| - the target app may specify a block of statements to execute only on a native run |
| -# <b>Expression</b>: 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 |
| |
| <b>C function definition</b> |
| ``` |
| DR_DEFINE_ANNOTATION(char, dynamorio_annotate_running_on_dynamorio, (), return 0) |
| ``` |
| |
| <b>C macro</b> 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: ; \ |
| } |
| ``` |
| |
| <b>ASM</b> 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 |
| |
| <b>C code</b> |
| ``` |
| TEST_ANNOTATION_SET_MODE(init->id, MODE_1, |
| { |
| printf("Mode 1 on %d\n", init->id); // native version |
| }); |
| ``` |
| |
| <b>C macro</b> 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) |
| ``` |
| |
| <b>ASM</b> 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 |
| |
| <b>C function definition</b> |
| ``` |
| DR_DEFINE_ANNOTATION(char, dynamorio_annotate_running_on_dynamorio, (), return 0) |
| ``` |
| |
| <b>C macro</b> 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: ; \ |
| } |
| ``` |
| |
| <b>ASM</b> 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 |
| |
| <b>C code</b> |
| ``` |
| TEST_ANNOTATION_SET_MODE(init->id, MODE_1, |
| { |
| printf("Mode 1 on %d\n", init->id); // native version |
| }); |
| ``` |
| |
| <b>C macro</b> 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) |
| ``` |
| |
| <b>ASM</b> 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 |
| |
| <b>C function definition</b> |
| ``` |
| DR_DEFINE_ANNOTATION(char, dynamorio_annotate_running_on_dynamorio, (), return 0) |
| ``` |
| |
| <b>C macro</b> 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) \ |
| } |
| ``` |
| |
| <b>C macro</b> 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; \ |
| } |
| ``` |
| |
| <b>ASM</b> 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 |
| |
| <em>C code</em> |
| ``` |
| TEST_ANNOTATION_SET_MODE(init->id, MODE_1, |
| { |
| printf("Mode 1 on %d\n", init->id); // native version |
| }); |
| ``` |
| |
| <em>C macro</em> 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) |
| ``` |
| |
| <em>ASM</em> 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 |
| |
| <em>C function definition</em> |
| ``` |
| DR_DEFINE_ANNOTATION(char, dynamorio_annotate_running_on_dynamorio, (), return 0) |
| ``` |
| |
| <em>C macro</em> 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) \ |
| } |
| ``` |
| |
| <em>C macro</em> 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) |
| ``` |
| |
| <em>ASM</em> 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 |
| |
| <b>C code</b> |
| ``` |
| TEST_ANNOTATION_SET_MODE(init->id, MODE_1, |
| { |
| printf("Mode 1 on %d\n", init->id); // native version |
| }); |
| ``` |
| |
| <b>C macro</b> 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) |
| ``` |
| |
| <b>ASM</b> 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) |
| |
| <b>C code</b> for nested annotations |
| ``` |
| static __inline int |
| annotated_function() |
| { |
| NOTE2(7, 8); |
| return 9; |
| } |
| |
| int main(void) |
| { |
| NOTE1(1, 2, annotated_function()); |
| } |
| ``` |
| |
| <b>ASM</b> 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) |
| |
| <em>C code</em> 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[} |
| ``` |
| |
| <em>ASM</em> 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 <b>instrumentation pc</b> |
| - 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 <b>instrumentation pc</b> |
| - 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 <b>instrumentation pc</b> |
| - 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 |
| |
| <em>Occurs at the top of an annotation function body</em> |
| |
| - For each annotation handler registered for this annotation (by name) |
| - insert a clean call to the handler at the <b>instrumentation pc</b> (as identified by the Detection Algorithms above) |
| - terminate the basic block |
| |
| ## Statement |
| |
| <em>Occurs at an annotation site</em> |
| |
| - Skip translation of the annotation header |
| - Resume translation at the <b>instrumentation pc</b> (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). |
| |
| **************************************************************************** |
| */ |