| /* ****************************************************** |
| * Copyright (c) 2014-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 VMware, 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. |
| */ |
| |
| #ifndef _ANNOTATIONS_H_ |
| #define _ANNOTATIONS_H_ 1 |
| |
| #ifdef ANNOTATIONS /* around whole file */ |
| |
| # include "lib/instrument.h" |
| # include "annotations_api.h" |
| |
| /********************************************************* |
| * INTERNAL ANNOTATION OBJECTS AND ROUTINES |
| */ |
| |
| # ifdef X64 |
| /* x64 encoding of "xchg %ebx,%ebx" (endian reversed) */ |
| # define ENCODED_VALGRIND_ANNOTATION_TAIL 0xdb8748 |
| /* x64 encoding of "rol $0x3,%edi; rol $0xd,%edi; rol $0x1d,%edi; rol $0x13,%edi" |
| * These constants facilitate efficient comparison of the raw bytes (endian |
| * reversed). |
| */ |
| # define ENCODED_VALGRIND_ANNOTATION_WORD_1 0xdc7c14803c7c148ULL |
| # define ENCODED_VALGRIND_ANNOTATION_WORD_2 0x33c7c1483dc7c148ULL |
| # else |
| /* x86 encoding of "xchg %ebx,%ebx" (endian reversed) */ |
| # define ENCODED_VALGRIND_ANNOTATION_TAIL 0xdb87 |
| /* x86 encoding of "rol $0x3,%edi; rol $0xd,%edi; rol $0x1d,%edi; rol $0x13,%edi" |
| * These constants facilitate efficient comparison of the raw bytes (endian |
| * reversed). |
| */ |
| # define ENCODED_VALGRIND_ANNOTATION_WORD_1 0xc103c7c1UL |
| # define ENCODED_VALGRIND_ANNOTATION_WORD_2 0xc7c10dc7UL |
| # define ENCODED_VALGRIND_ANNOTATION_WORD_3 0x13c7c11dUL |
| # endif |
| |
| # if !(defined(WINDOWS) && defined(X64)) |
| # ifdef WINDOWS |
| # define ANNOTATION_JUMP_OVER_LABEL_REFERENCE 0x06eb |
| # else |
| # ifdef X64 |
| # define ANNOTATION_JUMP_OVER_LABEL_REFERENCE 0x11eb |
| # else |
| # define ANNOTATION_JUMP_OVER_LABEL_REFERENCE 0x0ceb |
| # endif |
| # endif |
| # endif |
| |
| # define GET_ANNOTATION_HANDLER(label_data) \ |
| ((dr_annotation_handler_t *)(label_data)->data[0]) |
| # define SET_ANNOTATION_HANDLER(label_data, pc) \ |
| do { \ |
| (label_data)->data[0] = (ptr_uint_t)(pc); \ |
| } while (0) |
| |
| # define GET_ANNOTATION_APP_PC(label_data) ((app_pc)(label_data)->data[1]) |
| # define SET_ANNOTATION_APP_PC(label_data, pc) \ |
| do { \ |
| (label_data)->data[1] = (ptr_uint_t)(pc); \ |
| } while (0) |
| |
| # define GET_ANNOTATION_INSTRUMENTATION_PC(label_data) ((app_pc)(label_data)->data[2]) |
| # define SET_ANNOTATION_INSTRUMENTATION_PC(label_data, pc) \ |
| do { \ |
| (label_data)->data[2] = (ptr_uint_t)(pc); \ |
| } while (0) |
| |
| typedef enum _dr_annotation_handler_type_t { |
| DR_ANNOTATION_HANDLER_CALL, |
| DR_ANNOTATION_HANDLER_RETURN_VALUE, |
| DR_ANNOTATION_HANDLER_VALGRIND, |
| DR_ANNOTATION_HANDLER_LAST |
| } dr_annotation_handler_type_t; |
| |
| /* Each receiver represents one registered client (or core DR). */ |
| typedef struct _dr_annotation_receiver_t { |
| union { /* per annotation_handler_t.type */ |
| void *callback; |
| void *return_value; |
| ptr_uint_t (*vg_callback)(dr_vg_client_request_t *request); |
| } instrumentation; |
| bool save_fpstate; |
| struct _dr_annotation_receiver_t *next; |
| } dr_annotation_receiver_t; |
| |
| /* Each handler represents one distinct annotation name. */ |
| typedef struct _dr_annotation_handler_t { |
| dr_annotation_handler_type_t type; |
| const char *symbol_name; /* not used for Valgrind annotations */ |
| dr_annotation_receiver_t *receiver_list; |
| uint num_args; |
| opnd_t *args; |
| bool is_void; |
| bool pass_pc_in_slot; |
| } dr_annotation_handler_t; |
| |
| void |
| annotation_init(); |
| |
| void |
| annotation_exit(); |
| |
| static inline bool |
| is_annotation_label(instr_t *instr) |
| { |
| if (instr != NULL && instr_is_label(instr)) |
| return (ptr_uint_t)instr_get_note(instr) == DR_NOTE_ANNOTATION; |
| |
| return false; |
| } |
| |
| static inline bool |
| is_annotation_return_placeholder(instr_t *instr) |
| { |
| if (instr != NULL && instr_get_opcode(instr) == OP_mov_st) |
| return (ptr_uint_t)instr_get_note(instr) == DR_NOTE_ANNOTATION; |
| |
| return false; |
| } |
| |
| # if defined(WINDOWS) && defined(X64) |
| /* Win64 uses a compiled annotation, so the jump over dead code is not constant. */ |
| static inline bool |
| is_annotation_jump_over_dead_code(instr_t *instr) |
| { |
| return instr_is_cbr(instr); |
| } |
| # else |
| /* Other platforms use inline assembly, so the annotation starts with a constant jump |
| * instruction for efficient identification. |
| */ |
| static inline bool |
| is_annotation_jump_over_dead_code(instr_t *instr) |
| { |
| app_pc xl8 = instr_get_translation(instr); |
| return xl8 != NULL && *(ushort *)xl8 == ANNOTATION_JUMP_OVER_LABEL_REFERENCE; |
| } |
| # endif |
| |
| static inline bool |
| is_decoded_valgrind_annotation_tail(instr_t *instr) |
| { |
| return instr_get_opcode(instr) == OP_xchg; |
| } |
| |
| # ifdef X64 |
| # ifndef WINDOWS |
| /* Return true if instr_start_pc could be the last instruction of a Valgrind annotation, |
| * or false if it definitely is not a Valgrind annotation. |
| */ |
| static inline bool |
| is_encoded_valgrind_annotation_tail(app_pc instr_start_pc) |
| { |
| return (((*(uint *)instr_start_pc) & 0xffffff) == ENCODED_VALGRIND_ANNOTATION_TAIL); |
| } |
| |
| /* Return true if xchg_start_pc is definitely the last instruction of a Valgrind |
| * annotation. |
| */ |
| static inline bool |
| is_encoded_valgrind_annotation(app_pc xchg_start_pc, app_pc bb_start, app_pc page_start) |
| { |
| uint64 word1, word2; |
| /* It must be safe to read if the whole annotation is on a readable page, or falls |
| * within the range of pcs that have already been decoded for this bb. |
| */ |
| bool safe_to_read = (xchg_start_pc - bb_start) >= (2 * sizeof(uint64)) || |
| (xchg_start_pc - page_start) >= (2 * sizeof(uint64)); |
| if (safe_to_read) { |
| word1 = *(uint64 *)(xchg_start_pc - (2 * sizeof(uint64))); |
| } else { |
| if (!d_r_safe_read(xchg_start_pc - (2 * sizeof(uint64)), sizeof(uint64), &word1)) |
| return false; /* If it's not safe to read, it must not be an annotation. */ |
| } |
| /* This word must be safe to read because it lies directly between two pcs that are |
| * safe to read, with nothing intervening. |
| */ |
| word2 = *(uint64 *)(xchg_start_pc - sizeof(uint64)); |
| |
| return word1 == ENCODED_VALGRIND_ANNOTATION_WORD_1 && |
| word2 == ENCODED_VALGRIND_ANNOTATION_WORD_2; |
| } |
| # endif |
| # else |
| /* Return true if instr_start_pc could be the last instruction of a Valgrind annotation, |
| * or false if it definitely is not a Valgrind annotation. |
| */ |
| static inline bool |
| is_encoded_valgrind_annotation_tail(app_pc instr_start_pc) |
| { |
| return (*(ushort *)instr_start_pc == ENCODED_VALGRIND_ANNOTATION_TAIL); |
| } |
| |
| /* Return true if xchg_start_pc is definitely the last instruction of a Valgrind |
| * annotation. |
| */ |
| static inline bool |
| is_encoded_valgrind_annotation(app_pc xchg_start_pc, app_pc bb_start, app_pc page_start) |
| { |
| uint64 word1, word2, word3; |
| /* It must be safe to read if the whole annotation is on a readable page, or falls |
| * within the range of pcs that have already been decoded for this bb. |
| */ |
| bool safe_to_read = (xchg_start_pc - bb_start) >= (3 * sizeof(uint)) || |
| (xchg_start_pc - page_start) >= (3 * sizeof(uint)); |
| if (safe_to_read) { |
| word1 = *(uint *)(xchg_start_pc - (3 * sizeof(uint))); |
| } else { |
| if (!d_r_safe_read(xchg_start_pc - (3 * sizeof(uint)), sizeof(uint), &word1)) |
| return false; /* If it's not safe to read, it must not be an annotation. */ |
| } |
| /* These words must be safe to read because they lie directly between two pcs that are |
| * safe to read, with nothing intervening. |
| */ |
| word2 = *(uint *)(xchg_start_pc - (2 * sizeof(uint))); |
| word3 = *(uint *)(xchg_start_pc - sizeof(uint)); |
| return word1 == ENCODED_VALGRIND_ANNOTATION_WORD_1 && |
| word2 == ENCODED_VALGRIND_ANNOTATION_WORD_2 && |
| word3 == ENCODED_VALGRIND_ANNOTATION_WORD_3; |
| } |
| # endif |
| |
| /* Instrument the DR annotation at `start_pc` with an instruction sequence `substitution`, |
| * or return false if there is no DR annotation at `start_pc`. For Windows x64, |
| * `hint_is_safe` indicates whether the hint byte following `start_pc` is already known |
| * to be safe for reading. On successful instrumentation, `start_pc` is replaced with the |
| * pc following the annotation, where decoding of app instructions should resume. |
| */ |
| bool |
| instrument_annotation(dcontext_t *dcontext, DR_PARAM_INOUT app_pc *start_pc, |
| DR_PARAM_OUT instr_t **substitution |
| _IF_WINDOWS_X64(DR_PARAM_IN bool hint_is_safe)); |
| |
| # if !(defined(WINDOWS) && defined(X64)) |
| /* Replace the Valgrind annotation code sequence with a clean call to |
| * an internal function which will dispatch to registered handlers. |
| * |
| * Return true if the replacement occurred, and set next_instr to the first |
| * instruction after the annotation sequence. |
| * |
| * Example Valgrind annotation sequence from 'vg-annot' test (x86): |
| * <C code to fill _zzq_args> |
| * lea 0xffffffe4(%ebp) -> %eax ; lea _zzq_args -> %eax |
| * mov 0x08(%ebp) -> %edx ; mov _zzq_default -> %edx |
| * rol $0x00000003 %edi -> %edi ; Special sequence to replace |
| * rol $0x0000000d %edi -> %edi |
| * rol $0x0000001d %edi -> %edi |
| * rol $0x00000013 %edi -> %edi |
| * xchg %ebx %ebx -> %ebx %ebx |
| */ |
| void |
| instrument_valgrind_annotation(dcontext_t *dcontext, instrlist_t *bb, instr_t *xchg_instr, |
| app_pc xchg_pc, app_pc next_pc, uint bb_instr_count); |
| # endif /* !(defined (WINDOWS) && defined (X64)) */ |
| |
| #endif /* ANNOTATIONS */ |
| |
| #endif |