//===-- x86AssemblyInspectionEngine.cpp -----------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "x86AssemblyInspectionEngine.h" #include <memory> #include "llvm-c/Disassembler.h" #include "lldb/Core/Address.h" #include "lldb/Symbol/UnwindPlan.h" #include "lldb/Target/RegisterContext.h" #include "lldb/Target/UnwindAssembly.h" usingnamespacelldb_private; usingnamespacelldb; x86AssemblyInspectionEngine::x86AssemblyInspectionEngine(const ArchSpec &arch) : … { … } x86AssemblyInspectionEngine::~x86AssemblyInspectionEngine() { … } void x86AssemblyInspectionEngine::Initialize(RegisterContextSP ®_ctx) { … } void x86AssemblyInspectionEngine::Initialize( std::vector<lldb_reg_info> ®_info) { … } // This function expects an x86 native register number (i.e. the bits stripped // out of the actual instruction), not an lldb register number. // // FIXME: This is ABI dependent, it shouldn't be hardcoded here. bool x86AssemblyInspectionEngine::nonvolatile_reg_p(int machine_regno) { … } // Macro to detect if this is a REX mode prefix byte. #define REX_W_PREFIX_P(opcode) … // The high bit which should be added to the source register number (the "R" // bit) #define REX_W_SRCREG(opcode) … // The high bit which should be added to the destination register number (the // "B" bit) #define REX_W_DSTREG(opcode) … // pushq %rbp [0x55] bool x86AssemblyInspectionEngine::push_rbp_pattern_p() { … } // pushq $0 ; the first instruction in start() [0x6a 0x00] bool x86AssemblyInspectionEngine::push_0_pattern_p() { … } // pushq $0 // pushl $0 bool x86AssemblyInspectionEngine::push_imm_pattern_p() { … } // pushl imm8(%esp) // // e.g. 0xff 0x74 0x24 0x20 - 'pushl 0x20(%esp)' (same byte pattern for 'pushq // 0x20(%rsp)' in an x86_64 program) // // 0xff (with opcode bits '6' in next byte, PUSH r/m32) 0x74 (ModR/M byte with // three bits used to specify the opcode) // mod == b01, opcode == b110, R/M == b100 // "+disp8" // 0x24 (SIB byte - scaled index = 0, r32 == esp) 0x20 imm8 value bool x86AssemblyInspectionEngine::push_extended_pattern_p() { … } // instructions only valid in 32-bit mode: // 0x0e - push cs // 0x16 - push ss // 0x1e - push ds // 0x06 - push es bool x86AssemblyInspectionEngine::push_misc_reg_p() { … } // pushq %rbx // pushl %ebx bool x86AssemblyInspectionEngine::push_reg_p(int ®no) { … } // movq %rsp, %rbp [0x48 0x8b 0xec] or [0x48 0x89 0xe5] movl %esp, %ebp [0x8b // 0xec] or [0x89 0xe5] bool x86AssemblyInspectionEngine::mov_rsp_rbp_pattern_p() { … } // movq %rsp, %rbx [0x48 0x8b 0xdc] or [0x48 0x89 0xe3] // movl %esp, %ebx [0x8b 0xdc] or [0x89 0xe3] bool x86AssemblyInspectionEngine::mov_rsp_rbx_pattern_p() { … } // movq %rbp, %rsp [0x48 0x8b 0xe5] or [0x48 0x89 0xec] // movl %ebp, %esp [0x8b 0xe5] or [0x89 0xec] bool x86AssemblyInspectionEngine::mov_rbp_rsp_pattern_p() { … } // movq %rbx, %rsp [0x48 0x8b 0xe3] or [0x48 0x89 0xdc] // movl %ebx, %esp [0x8b 0xe3] or [0x89 0xdc] bool x86AssemblyInspectionEngine::mov_rbx_rsp_pattern_p() { … } // subq $0x20, %rsp bool x86AssemblyInspectionEngine::sub_rsp_pattern_p(int &amount) { … } // addq $0x20, %rsp bool x86AssemblyInspectionEngine::add_rsp_pattern_p(int &amount) { … } // lea esp, [esp - 0x28] // lea esp, [esp + 0x28] bool x86AssemblyInspectionEngine::lea_rsp_pattern_p(int &amount) { … } // lea -0x28(%ebp), %esp // (32-bit and 64-bit variants, 8-bit and 32-bit displacement) bool x86AssemblyInspectionEngine::lea_rbp_rsp_pattern_p(int &amount) { … } // lea -0x28(%ebx), %esp // (32-bit and 64-bit variants, 8-bit and 32-bit displacement) bool x86AssemblyInspectionEngine::lea_rbx_rsp_pattern_p(int &amount) { … } // and -0xfffffff0, %esp // (32-bit and 64-bit variants, 8-bit and 32-bit displacement) bool x86AssemblyInspectionEngine::and_rsp_pattern_p() { … } // popq %rbx // popl %ebx bool x86AssemblyInspectionEngine::pop_reg_p(int ®no) { … } // popq %rbp [0x5d] // popl %ebp [0x5d] bool x86AssemblyInspectionEngine::pop_rbp_pattern_p() { … } // instructions valid only in 32-bit mode: // 0x1f - pop ds // 0x07 - pop es // 0x17 - pop ss bool x86AssemblyInspectionEngine::pop_misc_reg_p() { … } // leave [0xc9] bool x86AssemblyInspectionEngine::leave_pattern_p() { … } // call $0 [0xe8 0x0 0x0 0x0 0x0] bool x86AssemblyInspectionEngine::call_next_insn_pattern_p() { … } // Look for an instruction sequence storing a nonvolatile register on to the // stack frame. // movq %rax, -0x10(%rbp) [0x48 0x89 0x45 0xf0] // movl %eax, -0xc(%ebp) [0x89 0x45 0xf4] // The offset value returned in rbp_offset will be positive -- but it must be // subtraced from the frame base register to get the actual location. The // positive value returned for the offset is a convention used elsewhere for // CFA offsets et al. bool x86AssemblyInspectionEngine::mov_reg_to_local_stack_frame_p( int ®no, int &rbp_offset) { … } // Returns true if this is a jmp instruction where we can't // know the destination address statically. // // ff e0 jmpq *%rax // ff e1 jmpq *%rcx // ff 60 28 jmpq *0x28(%rax) // ff 60 60 jmpq *0x60(%rax) bool x86AssemblyInspectionEngine::jmp_to_reg_p() { … } // Detect branches to fixed pc-relative offsets. // Returns the offset from the address of the next instruction // that may be branch/jumped to. // // Cannot determine the offset of a JMP that jumps to the address in // a register ("jmpq *%rax") or offset from a register value // ("jmpq *0x28(%rax)"), this method will return false on those // instructions. // // These instructions all end in either a relative 8/16/32 bit value // depending on the instruction and the current execution mode of the // inferior process. Once we know the size of the opcode instruction, // we can use the total instruction length to determine the size of // the relative offset without having to compute it correctly. bool x86AssemblyInspectionEngine::pc_rel_branch_or_jump_p ( const int instruction_length, int &offset) { … } // Returns true if this instruction is a intra-function branch or jump - // a branch/jump within the bounds of this same function. // Cannot predict where a jump through a register value ("jmpq *%rax") // will go, so it will return false on that instruction. bool x86AssemblyInspectionEngine::local_branch_p ( const addr_t current_func_text_offset, const AddressRange &func_range, const int instruction_length, addr_t &target_insn_offset) { … } // Returns true if this instruction is a inter-function branch or jump - a // branch/jump to another function. // Cannot predict where a jump through a register value ("jmpq *%rax") // will go, so it will return false on that instruction. bool x86AssemblyInspectionEngine::non_local_branch_p ( const addr_t current_func_text_offset, const AddressRange &func_range, const int instruction_length) { … } // ret [0xc3] or [0xcb] or [0xc2 imm16] or [0xca imm16] bool x86AssemblyInspectionEngine::ret_pattern_p() { … } uint16_t x86AssemblyInspectionEngine::extract_2(uint8_t *b) { … } int16_t x86AssemblyInspectionEngine::extract_2_signed(uint8_t *b) { … } uint32_t x86AssemblyInspectionEngine::extract_4(uint8_t *b) { … } int32_t x86AssemblyInspectionEngine::extract_4_signed(uint8_t *b) { … } bool x86AssemblyInspectionEngine::instruction_length(uint8_t *insn_p, int &length, uint32_t buffer_remaining_bytes) { … } bool x86AssemblyInspectionEngine::machine_regno_to_lldb_regno( int machine_regno, uint32_t &lldb_regno) { … } bool x86AssemblyInspectionEngine::GetNonCallSiteUnwindPlanFromAssembly( uint8_t *data, size_t size, AddressRange &func_range, UnwindPlan &unwind_plan) { … } bool x86AssemblyInspectionEngine::AugmentUnwindPlanFromCallSite( uint8_t *data, size_t size, AddressRange &func_range, UnwindPlan &unwind_plan, RegisterContextSP ®_ctx) { … } bool x86AssemblyInspectionEngine::FindFirstNonPrologueInstruction( uint8_t *data, size_t size, size_t &offset) { … }