| /* |
| * Copyright (c) 2016-2019, Intel Corporation |
| * |
| * 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 Intel Corporation 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 THE COPYRIGHT OWNER 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 PT_INSN_H |
| #define PT_INSN_H |
| |
| #include <inttypes.h> |
| |
| #include "intel-pt.h" |
| |
| struct pt_insn_ext; |
| |
| |
| /* A finer-grain classification of instructions used internally. */ |
| typedef enum { |
| PTI_INST_INVALID, |
| |
| PTI_INST_CALL_9A, |
| PTI_INST_CALL_FFr3, |
| PTI_INST_CALL_FFr2, |
| PTI_INST_CALL_E8, |
| PTI_INST_INT, |
| |
| PTI_INST_INT3, |
| PTI_INST_INT1, |
| PTI_INST_INTO, |
| PTI_INST_IRET, /* includes IRETD and IRETQ (EOSZ determines) */ |
| |
| PTI_INST_JMP_E9, |
| PTI_INST_JMP_EB, |
| PTI_INST_JMP_EA, |
| PTI_INST_JMP_FFr5, /* REXW? */ |
| PTI_INST_JMP_FFr4, |
| PTI_INST_JCC, |
| PTI_INST_JrCXZ, |
| PTI_INST_LOOP, |
| PTI_INST_LOOPE, /* aka Z */ |
| PTI_INST_LOOPNE, /* aka NE */ |
| |
| PTI_INST_MOV_CR3, |
| |
| PTI_INST_RET_C3, |
| PTI_INST_RET_C2, |
| PTI_INST_RET_CB, |
| PTI_INST_RET_CA, |
| |
| PTI_INST_SYSCALL, |
| PTI_INST_SYSENTER, |
| PTI_INST_SYSEXIT, |
| PTI_INST_SYSRET, |
| |
| PTI_INST_VMLAUNCH, |
| PTI_INST_VMRESUME, |
| PTI_INST_VMCALL, |
| PTI_INST_VMPTRLD, |
| |
| PTI_INST_PTWRITE, |
| |
| PTI_INST_LAST |
| } pti_inst_enum_t; |
| |
| /* Information about an instruction we need internally in addition to the |
| * information provided in struct pt_insn. |
| */ |
| struct pt_insn_ext { |
| /* A more detailed instruction class. */ |
| pti_inst_enum_t iclass; |
| |
| /* Instruction-specific information. */ |
| union { |
| /* For branch instructions. */ |
| struct { |
| /* The branch displacement. |
| * |
| * This is only valid for direct calls/jumps. |
| * |
| * The displacement is applied to the address of the |
| * instruction following the branch. |
| */ |
| int32_t displacement; |
| |
| /* A flag saying whether the branch is direct. |
| * |
| * non-zero: direct |
| * zero: indirect |
| * |
| * This is expected to go away someday when we extend |
| * enum pt_insn_class to distinguish direct and indirect |
| * branches. |
| */ |
| uint8_t is_direct; |
| } branch; |
| } variant; |
| }; |
| |
| |
| /* Check if the instruction @insn/@iext changes the current privilege level. |
| * |
| * Returns non-zero if it does, zero if it doesn't (or @insn/@iext is NULL). |
| */ |
| extern int pt_insn_changes_cpl(const struct pt_insn *insn, |
| const struct pt_insn_ext *iext); |
| |
| /* Check if the instruction @insn/@iext changes CR3. |
| * |
| * Returns non-zero if it does, zero if it doesn't (or @insn/@iext is NULL). |
| */ |
| extern int pt_insn_changes_cr3(const struct pt_insn *insn, |
| const struct pt_insn_ext *iext); |
| |
| /* Check if the instruction @insn/@iext is a (near or far) branch. |
| * |
| * Returns non-zero if it is, zero if it isn't (or @insn/@iext is NULL). |
| */ |
| extern int pt_insn_is_branch(const struct pt_insn *insn, |
| const struct pt_insn_ext *iext); |
| |
| /* Check if the instruction @insn/@iext is a far branch. |
| * |
| * Returns non-zero if it is, zero if it isn't (or @insn/@iext is NULL). |
| */ |
| extern int pt_insn_is_far_branch(const struct pt_insn *insn, |
| const struct pt_insn_ext *iext); |
| |
| /* Check if the instruction @insn/@iext binds to a PIP packet. |
| * |
| * Returns non-zero if it does, zero if it doesn't (or @insn/@iext is NULL). |
| */ |
| extern int pt_insn_binds_to_pip(const struct pt_insn *insn, |
| const struct pt_insn_ext *iext); |
| |
| /* Check if the instruction @insn/@iext binds to a VMCS packet. |
| * |
| * Returns non-zero if it does, zero if it doesn't (or @insn/@iext is NULL). |
| */ |
| extern int pt_insn_binds_to_vmcs(const struct pt_insn *insn, |
| const struct pt_insn_ext *iext); |
| |
| /* Check if the instruction @insn/@iext is a ptwrite instruction. |
| * |
| * Returns non-zero if it is, zero if it isn't (or @insn/@iext is NULL). |
| */ |
| extern int pt_insn_is_ptwrite(const struct pt_insn *insn, |
| const struct pt_insn_ext *iext); |
| |
| /* Determine the IP of the next instruction. |
| * |
| * Tries to determine the IP of the next instruction without using trace and |
| * provides it in @ip unless @ip is NULL. |
| * |
| * Returns zero on success, a negative error code otherwise. |
| * Returns -pte_bad_query if the IP can't be determined. |
| * Returns -pte_internal if @insn or @iext is NULL. |
| */ |
| extern int pt_insn_next_ip(uint64_t *ip, const struct pt_insn *insn, |
| const struct pt_insn_ext *iext); |
| |
| /* Decode and analyze one instruction. |
| * |
| * Decodes the instructruction at @insn->ip in @insn->mode into @insn and @iext. |
| * |
| * If the instruction can not be decoded using a single memory read in a single |
| * section, sets @insn->truncated and reads the missing bytes from one or more |
| * other sections until either the instruction can be decoded or we're sure it |
| * is invalid. |
| * |
| * Returns the size in bytes on success, a negative error code otherwise. |
| * Returns -pte_bad_insn if the instruction could not be decoded. |
| */ |
| extern int pt_insn_decode(struct pt_insn *insn, struct pt_insn_ext *iext, |
| struct pt_image *image, const struct pt_asid *asid); |
| |
| /* Determine if a range of instructions is contiguous. |
| * |
| * Try to proceed from IP @begin to IP @end in @asid without using trace. |
| * |
| * Returns a positive integer if we reach @end from @begin. |
| * Returns zero if we couldn't reach @end within @nsteps steps. |
| * Returns a negative error code otherwise. |
| */ |
| extern int pt_insn_range_is_contiguous(uint64_t begin, uint64_t end, |
| enum pt_exec_mode mode, |
| struct pt_image *image, |
| const struct pt_asid *asid, |
| size_t nsteps); |
| |
| #endif /* PT_INSN_H */ |