15ffd83dbSDimitry Andric //===-- x86AssemblyInspectionEngine.cpp -----------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric 
90b57cec5SDimitry Andric #include "x86AssemblyInspectionEngine.h"
100b57cec5SDimitry Andric 
110b57cec5SDimitry Andric #include <memory>
120b57cec5SDimitry Andric 
130b57cec5SDimitry Andric #include "llvm-c/Disassembler.h"
140b57cec5SDimitry Andric 
150b57cec5SDimitry Andric #include "lldb/Core/Address.h"
160b57cec5SDimitry Andric #include "lldb/Symbol/UnwindPlan.h"
170b57cec5SDimitry Andric #include "lldb/Target/RegisterContext.h"
180b57cec5SDimitry Andric #include "lldb/Target/UnwindAssembly.h"
190b57cec5SDimitry Andric 
200b57cec5SDimitry Andric using namespace lldb_private;
210b57cec5SDimitry Andric using namespace lldb;
220b57cec5SDimitry Andric 
230b57cec5SDimitry Andric x86AssemblyInspectionEngine::x86AssemblyInspectionEngine(const ArchSpec &arch)
240b57cec5SDimitry Andric     : m_cur_insn(nullptr), m_machine_ip_regnum(LLDB_INVALID_REGNUM),
250b57cec5SDimitry Andric       m_machine_sp_regnum(LLDB_INVALID_REGNUM),
260b57cec5SDimitry Andric       m_machine_fp_regnum(LLDB_INVALID_REGNUM),
27fcaf7f86SDimitry Andric       m_machine_alt_fp_regnum(LLDB_INVALID_REGNUM),
280b57cec5SDimitry Andric       m_lldb_ip_regnum(LLDB_INVALID_REGNUM),
290b57cec5SDimitry Andric       m_lldb_sp_regnum(LLDB_INVALID_REGNUM),
300b57cec5SDimitry Andric       m_lldb_fp_regnum(LLDB_INVALID_REGNUM),
31fcaf7f86SDimitry Andric       m_lldb_alt_fp_regnum(LLDB_INVALID_REGNUM), m_reg_map(), m_arch(arch),
32fcaf7f86SDimitry Andric       m_cpu(k_cpu_unspecified), m_wordsize(-1),
330b57cec5SDimitry Andric       m_register_map_initialized(false), m_disasm_context() {
340b57cec5SDimitry Andric   m_disasm_context =
350b57cec5SDimitry Andric       ::LLVMCreateDisasm(arch.GetTriple().getTriple().c_str(), nullptr,
360b57cec5SDimitry Andric                          /*TagType=*/1, nullptr, nullptr);
370b57cec5SDimitry Andric }
380b57cec5SDimitry Andric 
390b57cec5SDimitry Andric x86AssemblyInspectionEngine::~x86AssemblyInspectionEngine() {
400b57cec5SDimitry Andric   ::LLVMDisasmDispose(m_disasm_context);
410b57cec5SDimitry Andric }
420b57cec5SDimitry Andric 
430b57cec5SDimitry Andric void x86AssemblyInspectionEngine::Initialize(RegisterContextSP &reg_ctx) {
440b57cec5SDimitry Andric   m_cpu = k_cpu_unspecified;
450b57cec5SDimitry Andric   m_wordsize = -1;
460b57cec5SDimitry Andric   m_register_map_initialized = false;
470b57cec5SDimitry Andric 
480b57cec5SDimitry Andric   const llvm::Triple::ArchType cpu = m_arch.GetMachine();
490b57cec5SDimitry Andric   if (cpu == llvm::Triple::x86)
500b57cec5SDimitry Andric     m_cpu = k_i386;
510b57cec5SDimitry Andric   else if (cpu == llvm::Triple::x86_64)
520b57cec5SDimitry Andric     m_cpu = k_x86_64;
530b57cec5SDimitry Andric 
540b57cec5SDimitry Andric   if (m_cpu == k_cpu_unspecified)
550b57cec5SDimitry Andric     return;
560b57cec5SDimitry Andric 
570b57cec5SDimitry Andric   if (reg_ctx.get() == nullptr)
580b57cec5SDimitry Andric     return;
590b57cec5SDimitry Andric 
600b57cec5SDimitry Andric   if (m_cpu == k_i386) {
610b57cec5SDimitry Andric     m_machine_ip_regnum = k_machine_eip;
620b57cec5SDimitry Andric     m_machine_sp_regnum = k_machine_esp;
630b57cec5SDimitry Andric     m_machine_fp_regnum = k_machine_ebp;
640b57cec5SDimitry Andric     m_machine_alt_fp_regnum = k_machine_ebx;
650b57cec5SDimitry Andric     m_wordsize = 4;
660b57cec5SDimitry Andric 
670b57cec5SDimitry Andric     struct lldb_reg_info reginfo;
680b57cec5SDimitry Andric     reginfo.name = "eax";
690b57cec5SDimitry Andric     m_reg_map[k_machine_eax] = reginfo;
700b57cec5SDimitry Andric     reginfo.name = "edx";
710b57cec5SDimitry Andric     m_reg_map[k_machine_edx] = reginfo;
720b57cec5SDimitry Andric     reginfo.name = "esp";
730b57cec5SDimitry Andric     m_reg_map[k_machine_esp] = reginfo;
740b57cec5SDimitry Andric     reginfo.name = "esi";
750b57cec5SDimitry Andric     m_reg_map[k_machine_esi] = reginfo;
760b57cec5SDimitry Andric     reginfo.name = "eip";
770b57cec5SDimitry Andric     m_reg_map[k_machine_eip] = reginfo;
780b57cec5SDimitry Andric     reginfo.name = "ecx";
790b57cec5SDimitry Andric     m_reg_map[k_machine_ecx] = reginfo;
800b57cec5SDimitry Andric     reginfo.name = "ebx";
810b57cec5SDimitry Andric     m_reg_map[k_machine_ebx] = reginfo;
820b57cec5SDimitry Andric     reginfo.name = "ebp";
830b57cec5SDimitry Andric     m_reg_map[k_machine_ebp] = reginfo;
840b57cec5SDimitry Andric     reginfo.name = "edi";
850b57cec5SDimitry Andric     m_reg_map[k_machine_edi] = reginfo;
860b57cec5SDimitry Andric   } else {
870b57cec5SDimitry Andric     m_machine_ip_regnum = k_machine_rip;
880b57cec5SDimitry Andric     m_machine_sp_regnum = k_machine_rsp;
890b57cec5SDimitry Andric     m_machine_fp_regnum = k_machine_rbp;
900b57cec5SDimitry Andric     m_machine_alt_fp_regnum = k_machine_rbx;
910b57cec5SDimitry Andric     m_wordsize = 8;
920b57cec5SDimitry Andric 
930b57cec5SDimitry Andric     struct lldb_reg_info reginfo;
940b57cec5SDimitry Andric     reginfo.name = "rax";
950b57cec5SDimitry Andric     m_reg_map[k_machine_rax] = reginfo;
960b57cec5SDimitry Andric     reginfo.name = "rdx";
970b57cec5SDimitry Andric     m_reg_map[k_machine_rdx] = reginfo;
980b57cec5SDimitry Andric     reginfo.name = "rsp";
990b57cec5SDimitry Andric     m_reg_map[k_machine_rsp] = reginfo;
1000b57cec5SDimitry Andric     reginfo.name = "rsi";
1010b57cec5SDimitry Andric     m_reg_map[k_machine_rsi] = reginfo;
1020b57cec5SDimitry Andric     reginfo.name = "r8";
1030b57cec5SDimitry Andric     m_reg_map[k_machine_r8] = reginfo;
1040b57cec5SDimitry Andric     reginfo.name = "r10";
1050b57cec5SDimitry Andric     m_reg_map[k_machine_r10] = reginfo;
1060b57cec5SDimitry Andric     reginfo.name = "r12";
1070b57cec5SDimitry Andric     m_reg_map[k_machine_r12] = reginfo;
1080b57cec5SDimitry Andric     reginfo.name = "r14";
1090b57cec5SDimitry Andric     m_reg_map[k_machine_r14] = reginfo;
1100b57cec5SDimitry Andric     reginfo.name = "rip";
1110b57cec5SDimitry Andric     m_reg_map[k_machine_rip] = reginfo;
1120b57cec5SDimitry Andric     reginfo.name = "rcx";
1130b57cec5SDimitry Andric     m_reg_map[k_machine_rcx] = reginfo;
1140b57cec5SDimitry Andric     reginfo.name = "rbx";
1150b57cec5SDimitry Andric     m_reg_map[k_machine_rbx] = reginfo;
1160b57cec5SDimitry Andric     reginfo.name = "rbp";
1170b57cec5SDimitry Andric     m_reg_map[k_machine_rbp] = reginfo;
1180b57cec5SDimitry Andric     reginfo.name = "rdi";
1190b57cec5SDimitry Andric     m_reg_map[k_machine_rdi] = reginfo;
1200b57cec5SDimitry Andric     reginfo.name = "r9";
1210b57cec5SDimitry Andric     m_reg_map[k_machine_r9] = reginfo;
1220b57cec5SDimitry Andric     reginfo.name = "r11";
1230b57cec5SDimitry Andric     m_reg_map[k_machine_r11] = reginfo;
1240b57cec5SDimitry Andric     reginfo.name = "r13";
1250b57cec5SDimitry Andric     m_reg_map[k_machine_r13] = reginfo;
1260b57cec5SDimitry Andric     reginfo.name = "r15";
1270b57cec5SDimitry Andric     m_reg_map[k_machine_r15] = reginfo;
1280b57cec5SDimitry Andric   }
1290b57cec5SDimitry Andric 
1300b57cec5SDimitry Andric   for (MachineRegnumToNameAndLLDBRegnum::iterator it = m_reg_map.begin();
1310b57cec5SDimitry Andric        it != m_reg_map.end(); ++it) {
1320b57cec5SDimitry Andric     const RegisterInfo *ri = reg_ctx->GetRegisterInfoByName(it->second.name);
1330b57cec5SDimitry Andric     if (ri)
1340b57cec5SDimitry Andric       it->second.lldb_regnum = ri->kinds[eRegisterKindLLDB];
1350b57cec5SDimitry Andric   }
1360b57cec5SDimitry Andric 
1370b57cec5SDimitry Andric   uint32_t lldb_regno;
1380b57cec5SDimitry Andric   if (machine_regno_to_lldb_regno(m_machine_sp_regnum, lldb_regno))
1390b57cec5SDimitry Andric     m_lldb_sp_regnum = lldb_regno;
1400b57cec5SDimitry Andric   if (machine_regno_to_lldb_regno(m_machine_fp_regnum, lldb_regno))
1410b57cec5SDimitry Andric     m_lldb_fp_regnum = lldb_regno;
1420b57cec5SDimitry Andric   if (machine_regno_to_lldb_regno(m_machine_alt_fp_regnum, lldb_regno))
1430b57cec5SDimitry Andric     m_lldb_alt_fp_regnum = lldb_regno;
1440b57cec5SDimitry Andric   if (machine_regno_to_lldb_regno(m_machine_ip_regnum, lldb_regno))
1450b57cec5SDimitry Andric     m_lldb_ip_regnum = lldb_regno;
1460b57cec5SDimitry Andric 
1470b57cec5SDimitry Andric   m_register_map_initialized = true;
1480b57cec5SDimitry Andric }
1490b57cec5SDimitry Andric 
1500b57cec5SDimitry Andric void x86AssemblyInspectionEngine::Initialize(
1510b57cec5SDimitry Andric     std::vector<lldb_reg_info> &reg_info) {
1520b57cec5SDimitry Andric   m_cpu = k_cpu_unspecified;
1530b57cec5SDimitry Andric   m_wordsize = -1;
1540b57cec5SDimitry Andric   m_register_map_initialized = false;
1550b57cec5SDimitry Andric 
1560b57cec5SDimitry Andric   const llvm::Triple::ArchType cpu = m_arch.GetMachine();
1570b57cec5SDimitry Andric   if (cpu == llvm::Triple::x86)
1580b57cec5SDimitry Andric     m_cpu = k_i386;
1590b57cec5SDimitry Andric   else if (cpu == llvm::Triple::x86_64)
1600b57cec5SDimitry Andric     m_cpu = k_x86_64;
1610b57cec5SDimitry Andric 
1620b57cec5SDimitry Andric   if (m_cpu == k_cpu_unspecified)
1630b57cec5SDimitry Andric     return;
1640b57cec5SDimitry Andric 
1650b57cec5SDimitry Andric   if (m_cpu == k_i386) {
1660b57cec5SDimitry Andric     m_machine_ip_regnum = k_machine_eip;
1670b57cec5SDimitry Andric     m_machine_sp_regnum = k_machine_esp;
1680b57cec5SDimitry Andric     m_machine_fp_regnum = k_machine_ebp;
1690b57cec5SDimitry Andric     m_machine_alt_fp_regnum = k_machine_ebx;
1700b57cec5SDimitry Andric     m_wordsize = 4;
1710b57cec5SDimitry Andric 
1720b57cec5SDimitry Andric     struct lldb_reg_info reginfo;
1730b57cec5SDimitry Andric     reginfo.name = "eax";
1740b57cec5SDimitry Andric     m_reg_map[k_machine_eax] = reginfo;
1750b57cec5SDimitry Andric     reginfo.name = "edx";
1760b57cec5SDimitry Andric     m_reg_map[k_machine_edx] = reginfo;
1770b57cec5SDimitry Andric     reginfo.name = "esp";
1780b57cec5SDimitry Andric     m_reg_map[k_machine_esp] = reginfo;
1790b57cec5SDimitry Andric     reginfo.name = "esi";
1800b57cec5SDimitry Andric     m_reg_map[k_machine_esi] = reginfo;
1810b57cec5SDimitry Andric     reginfo.name = "eip";
1820b57cec5SDimitry Andric     m_reg_map[k_machine_eip] = reginfo;
1830b57cec5SDimitry Andric     reginfo.name = "ecx";
1840b57cec5SDimitry Andric     m_reg_map[k_machine_ecx] = reginfo;
1850b57cec5SDimitry Andric     reginfo.name = "ebx";
1860b57cec5SDimitry Andric     m_reg_map[k_machine_ebx] = reginfo;
1870b57cec5SDimitry Andric     reginfo.name = "ebp";
1880b57cec5SDimitry Andric     m_reg_map[k_machine_ebp] = reginfo;
1890b57cec5SDimitry Andric     reginfo.name = "edi";
1900b57cec5SDimitry Andric     m_reg_map[k_machine_edi] = reginfo;
1910b57cec5SDimitry Andric   } else {
1920b57cec5SDimitry Andric     m_machine_ip_regnum = k_machine_rip;
1930b57cec5SDimitry Andric     m_machine_sp_regnum = k_machine_rsp;
1940b57cec5SDimitry Andric     m_machine_fp_regnum = k_machine_rbp;
1950b57cec5SDimitry Andric     m_machine_alt_fp_regnum = k_machine_rbx;
1960b57cec5SDimitry Andric     m_wordsize = 8;
1970b57cec5SDimitry Andric 
1980b57cec5SDimitry Andric     struct lldb_reg_info reginfo;
1990b57cec5SDimitry Andric     reginfo.name = "rax";
2000b57cec5SDimitry Andric     m_reg_map[k_machine_rax] = reginfo;
2010b57cec5SDimitry Andric     reginfo.name = "rdx";
2020b57cec5SDimitry Andric     m_reg_map[k_machine_rdx] = reginfo;
2030b57cec5SDimitry Andric     reginfo.name = "rsp";
2040b57cec5SDimitry Andric     m_reg_map[k_machine_rsp] = reginfo;
2050b57cec5SDimitry Andric     reginfo.name = "rsi";
2060b57cec5SDimitry Andric     m_reg_map[k_machine_rsi] = reginfo;
2070b57cec5SDimitry Andric     reginfo.name = "r8";
2080b57cec5SDimitry Andric     m_reg_map[k_machine_r8] = reginfo;
2090b57cec5SDimitry Andric     reginfo.name = "r10";
2100b57cec5SDimitry Andric     m_reg_map[k_machine_r10] = reginfo;
2110b57cec5SDimitry Andric     reginfo.name = "r12";
2120b57cec5SDimitry Andric     m_reg_map[k_machine_r12] = reginfo;
2130b57cec5SDimitry Andric     reginfo.name = "r14";
2140b57cec5SDimitry Andric     m_reg_map[k_machine_r14] = reginfo;
2150b57cec5SDimitry Andric     reginfo.name = "rip";
2160b57cec5SDimitry Andric     m_reg_map[k_machine_rip] = reginfo;
2170b57cec5SDimitry Andric     reginfo.name = "rcx";
2180b57cec5SDimitry Andric     m_reg_map[k_machine_rcx] = reginfo;
2190b57cec5SDimitry Andric     reginfo.name = "rbx";
2200b57cec5SDimitry Andric     m_reg_map[k_machine_rbx] = reginfo;
2210b57cec5SDimitry Andric     reginfo.name = "rbp";
2220b57cec5SDimitry Andric     m_reg_map[k_machine_rbp] = reginfo;
2230b57cec5SDimitry Andric     reginfo.name = "rdi";
2240b57cec5SDimitry Andric     m_reg_map[k_machine_rdi] = reginfo;
2250b57cec5SDimitry Andric     reginfo.name = "r9";
2260b57cec5SDimitry Andric     m_reg_map[k_machine_r9] = reginfo;
2270b57cec5SDimitry Andric     reginfo.name = "r11";
2280b57cec5SDimitry Andric     m_reg_map[k_machine_r11] = reginfo;
2290b57cec5SDimitry Andric     reginfo.name = "r13";
2300b57cec5SDimitry Andric     m_reg_map[k_machine_r13] = reginfo;
2310b57cec5SDimitry Andric     reginfo.name = "r15";
2320b57cec5SDimitry Andric     m_reg_map[k_machine_r15] = reginfo;
2330b57cec5SDimitry Andric   }
2340b57cec5SDimitry Andric 
2350b57cec5SDimitry Andric   for (MachineRegnumToNameAndLLDBRegnum::iterator it = m_reg_map.begin();
2360b57cec5SDimitry Andric        it != m_reg_map.end(); ++it) {
2370b57cec5SDimitry Andric     for (size_t i = 0; i < reg_info.size(); ++i) {
2380b57cec5SDimitry Andric       if (::strcmp(reg_info[i].name, it->second.name) == 0) {
2390b57cec5SDimitry Andric         it->second.lldb_regnum = reg_info[i].lldb_regnum;
2400b57cec5SDimitry Andric         break;
2410b57cec5SDimitry Andric       }
2420b57cec5SDimitry Andric     }
2430b57cec5SDimitry Andric   }
2440b57cec5SDimitry Andric 
2450b57cec5SDimitry Andric   uint32_t lldb_regno;
2460b57cec5SDimitry Andric   if (machine_regno_to_lldb_regno(m_machine_sp_regnum, lldb_regno))
2470b57cec5SDimitry Andric     m_lldb_sp_regnum = lldb_regno;
2480b57cec5SDimitry Andric   if (machine_regno_to_lldb_regno(m_machine_fp_regnum, lldb_regno))
2490b57cec5SDimitry Andric     m_lldb_fp_regnum = lldb_regno;
2500b57cec5SDimitry Andric   if (machine_regno_to_lldb_regno(m_machine_alt_fp_regnum, lldb_regno))
2510b57cec5SDimitry Andric     m_lldb_alt_fp_regnum = lldb_regno;
2520b57cec5SDimitry Andric   if (machine_regno_to_lldb_regno(m_machine_ip_regnum, lldb_regno))
2530b57cec5SDimitry Andric     m_lldb_ip_regnum = lldb_regno;
2540b57cec5SDimitry Andric 
2550b57cec5SDimitry Andric   m_register_map_initialized = true;
2560b57cec5SDimitry Andric }
2570b57cec5SDimitry Andric 
2580b57cec5SDimitry Andric // This function expects an x86 native register number (i.e. the bits stripped
2590b57cec5SDimitry Andric // out of the actual instruction), not an lldb register number.
2600b57cec5SDimitry Andric //
2610b57cec5SDimitry Andric // FIXME: This is ABI dependent, it shouldn't be hardcoded here.
2620b57cec5SDimitry Andric 
2630b57cec5SDimitry Andric bool x86AssemblyInspectionEngine::nonvolatile_reg_p(int machine_regno) {
2640b57cec5SDimitry Andric   if (m_cpu == k_i386) {
2650b57cec5SDimitry Andric     switch (machine_regno) {
2660b57cec5SDimitry Andric     case k_machine_ebx:
2670b57cec5SDimitry Andric     case k_machine_ebp: // not actually a nonvolatile but often treated as such
2680b57cec5SDimitry Andric                         // by convention
2690b57cec5SDimitry Andric     case k_machine_esi:
2700b57cec5SDimitry Andric     case k_machine_edi:
2710b57cec5SDimitry Andric     case k_machine_esp:
2720b57cec5SDimitry Andric       return true;
2730b57cec5SDimitry Andric     default:
2740b57cec5SDimitry Andric       return false;
2750b57cec5SDimitry Andric     }
2760b57cec5SDimitry Andric   }
2770b57cec5SDimitry Andric   if (m_cpu == k_x86_64) {
2780b57cec5SDimitry Andric     switch (machine_regno) {
2790b57cec5SDimitry Andric     case k_machine_rbx:
2800b57cec5SDimitry Andric     case k_machine_rsp:
2810b57cec5SDimitry Andric     case k_machine_rbp: // not actually a nonvolatile but often treated as such
2820b57cec5SDimitry Andric                         // by convention
2830b57cec5SDimitry Andric     case k_machine_r12:
2840b57cec5SDimitry Andric     case k_machine_r13:
2850b57cec5SDimitry Andric     case k_machine_r14:
2860b57cec5SDimitry Andric     case k_machine_r15:
2870b57cec5SDimitry Andric       return true;
2880b57cec5SDimitry Andric     default:
2890b57cec5SDimitry Andric       return false;
2900b57cec5SDimitry Andric     }
2910b57cec5SDimitry Andric   }
2920b57cec5SDimitry Andric   return false;
2930b57cec5SDimitry Andric }
2940b57cec5SDimitry Andric 
2950b57cec5SDimitry Andric // Macro to detect if this is a REX mode prefix byte.
2960b57cec5SDimitry Andric #define REX_W_PREFIX_P(opcode) (((opcode) & (~0x5)) == 0x48)
2970b57cec5SDimitry Andric 
2980b57cec5SDimitry Andric // The high bit which should be added to the source register number (the "R"
2990b57cec5SDimitry Andric // bit)
3000b57cec5SDimitry Andric #define REX_W_SRCREG(opcode) (((opcode)&0x4) >> 2)
3010b57cec5SDimitry Andric 
3020b57cec5SDimitry Andric // The high bit which should be added to the destination register number (the
3030b57cec5SDimitry Andric // "B" bit)
3040b57cec5SDimitry Andric #define REX_W_DSTREG(opcode) ((opcode)&0x1)
3050b57cec5SDimitry Andric 
3060b57cec5SDimitry Andric // pushq %rbp [0x55]
3070b57cec5SDimitry Andric bool x86AssemblyInspectionEngine::push_rbp_pattern_p() {
3080b57cec5SDimitry Andric   uint8_t *p = m_cur_insn;
3090b57cec5SDimitry Andric   return *p == 0x55;
3100b57cec5SDimitry Andric }
3110b57cec5SDimitry Andric 
3120b57cec5SDimitry Andric // pushq $0 ; the first instruction in start() [0x6a 0x00]
3130b57cec5SDimitry Andric bool x86AssemblyInspectionEngine::push_0_pattern_p() {
3140b57cec5SDimitry Andric   uint8_t *p = m_cur_insn;
3150b57cec5SDimitry Andric   return *p == 0x6a && *(p + 1) == 0x0;
3160b57cec5SDimitry Andric }
3170b57cec5SDimitry Andric 
3180b57cec5SDimitry Andric // pushq $0
3190b57cec5SDimitry Andric // pushl $0
3200b57cec5SDimitry Andric bool x86AssemblyInspectionEngine::push_imm_pattern_p() {
3210b57cec5SDimitry Andric   uint8_t *p = m_cur_insn;
3220b57cec5SDimitry Andric   return *p == 0x68 || *p == 0x6a;
3230b57cec5SDimitry Andric }
3240b57cec5SDimitry Andric 
3250b57cec5SDimitry Andric // pushl imm8(%esp)
3260b57cec5SDimitry Andric //
3270b57cec5SDimitry Andric // e.g. 0xff 0x74 0x24 0x20 - 'pushl 0x20(%esp)' (same byte pattern for 'pushq
3280b57cec5SDimitry Andric // 0x20(%rsp)' in an x86_64 program)
3290b57cec5SDimitry Andric //
3300b57cec5SDimitry Andric // 0xff (with opcode bits '6' in next byte, PUSH r/m32) 0x74 (ModR/M byte with
3310b57cec5SDimitry Andric // three bits used to specify the opcode)
3320b57cec5SDimitry Andric //      mod == b01, opcode == b110, R/M == b100
3330b57cec5SDimitry Andric //      "+disp8"
3340b57cec5SDimitry Andric // 0x24 (SIB byte - scaled index = 0, r32 == esp) 0x20 imm8 value
3350b57cec5SDimitry Andric 
3360b57cec5SDimitry Andric bool x86AssemblyInspectionEngine::push_extended_pattern_p() {
3370b57cec5SDimitry Andric   if (*m_cur_insn == 0xff) {
3380b57cec5SDimitry Andric     // Get the 3 opcode bits from the ModR/M byte
3390b57cec5SDimitry Andric     uint8_t opcode = (*(m_cur_insn + 1) >> 3) & 7;
3400b57cec5SDimitry Andric     if (opcode == 6) {
3410b57cec5SDimitry Andric       // I'm only looking for 0xff /6 here - I
3420b57cec5SDimitry Andric       // don't really care what value is being pushed, just that we're pushing
3430b57cec5SDimitry Andric       // a 32/64 bit value on to the stack is enough.
3440b57cec5SDimitry Andric       return true;
3450b57cec5SDimitry Andric     }
3460b57cec5SDimitry Andric   }
3470b57cec5SDimitry Andric   return false;
3480b57cec5SDimitry Andric }
3490b57cec5SDimitry Andric 
3500b57cec5SDimitry Andric // instructions only valid in 32-bit mode:
3510b57cec5SDimitry Andric // 0x0e - push cs
3520b57cec5SDimitry Andric // 0x16 - push ss
3530b57cec5SDimitry Andric // 0x1e - push ds
3540b57cec5SDimitry Andric // 0x06 - push es
3550b57cec5SDimitry Andric bool x86AssemblyInspectionEngine::push_misc_reg_p() {
3560b57cec5SDimitry Andric   uint8_t p = *m_cur_insn;
3570b57cec5SDimitry Andric   if (m_wordsize == 4) {
3580b57cec5SDimitry Andric     if (p == 0x0e || p == 0x16 || p == 0x1e || p == 0x06)
3590b57cec5SDimitry Andric       return true;
3600b57cec5SDimitry Andric   }
3610b57cec5SDimitry Andric   return false;
3620b57cec5SDimitry Andric }
3630b57cec5SDimitry Andric 
3640b57cec5SDimitry Andric // pushq %rbx
3650b57cec5SDimitry Andric // pushl %ebx
3660b57cec5SDimitry Andric bool x86AssemblyInspectionEngine::push_reg_p(int &regno) {
3670b57cec5SDimitry Andric   uint8_t *p = m_cur_insn;
3680b57cec5SDimitry Andric   int regno_prefix_bit = 0;
3690b57cec5SDimitry Andric   // If we have a rex prefix byte, check to see if a B bit is set
3700b57cec5SDimitry Andric   if (m_wordsize == 8 && (*p & 0xfe) == 0x40) {
3710b57cec5SDimitry Andric     regno_prefix_bit = (*p & 1) << 3;
3720b57cec5SDimitry Andric     p++;
3730b57cec5SDimitry Andric   }
3740b57cec5SDimitry Andric   if (*p >= 0x50 && *p <= 0x57) {
3750b57cec5SDimitry Andric     regno = (*p - 0x50) | regno_prefix_bit;
3760b57cec5SDimitry Andric     return true;
3770b57cec5SDimitry Andric   }
3780b57cec5SDimitry Andric   return false;
3790b57cec5SDimitry Andric }
3800b57cec5SDimitry Andric 
3810b57cec5SDimitry Andric // movq %rsp, %rbp [0x48 0x8b 0xec] or [0x48 0x89 0xe5] movl %esp, %ebp [0x8b
3820b57cec5SDimitry Andric // 0xec] or [0x89 0xe5]
3830b57cec5SDimitry Andric bool x86AssemblyInspectionEngine::mov_rsp_rbp_pattern_p() {
3840b57cec5SDimitry Andric   uint8_t *p = m_cur_insn;
3850b57cec5SDimitry Andric   if (m_wordsize == 8 && *p == 0x48)
3860b57cec5SDimitry Andric     p++;
3870b57cec5SDimitry Andric   if (*(p) == 0x8b && *(p + 1) == 0xec)
3880b57cec5SDimitry Andric     return true;
3890b57cec5SDimitry Andric   if (*(p) == 0x89 && *(p + 1) == 0xe5)
3900b57cec5SDimitry Andric     return true;
3910b57cec5SDimitry Andric   return false;
3920b57cec5SDimitry Andric }
3930b57cec5SDimitry Andric 
3940b57cec5SDimitry Andric // movq %rsp, %rbx [0x48 0x8b 0xdc] or [0x48 0x89 0xe3]
3950b57cec5SDimitry Andric // movl %esp, %ebx [0x8b 0xdc] or [0x89 0xe3]
3960b57cec5SDimitry Andric bool x86AssemblyInspectionEngine::mov_rsp_rbx_pattern_p() {
3970b57cec5SDimitry Andric   uint8_t *p = m_cur_insn;
3980b57cec5SDimitry Andric   if (m_wordsize == 8 && *p == 0x48)
3990b57cec5SDimitry Andric     p++;
4000b57cec5SDimitry Andric   if (*(p) == 0x8b && *(p + 1) == 0xdc)
4010b57cec5SDimitry Andric     return true;
4020b57cec5SDimitry Andric   if (*(p) == 0x89 && *(p + 1) == 0xe3)
4030b57cec5SDimitry Andric     return true;
4040b57cec5SDimitry Andric   return false;
4050b57cec5SDimitry Andric }
4060b57cec5SDimitry Andric 
4070b57cec5SDimitry Andric // movq %rbp, %rsp [0x48 0x8b 0xe5] or [0x48 0x89 0xec]
4080b57cec5SDimitry Andric // movl %ebp, %esp [0x8b 0xe5] or [0x89 0xec]
4090b57cec5SDimitry Andric bool x86AssemblyInspectionEngine::mov_rbp_rsp_pattern_p() {
4100b57cec5SDimitry Andric   uint8_t *p = m_cur_insn;
4110b57cec5SDimitry Andric   if (m_wordsize == 8 && *p == 0x48)
4120b57cec5SDimitry Andric     p++;
4130b57cec5SDimitry Andric   if (*(p) == 0x8b && *(p + 1) == 0xe5)
4140b57cec5SDimitry Andric     return true;
4150b57cec5SDimitry Andric   if (*(p) == 0x89 && *(p + 1) == 0xec)
4160b57cec5SDimitry Andric     return true;
4170b57cec5SDimitry Andric   return false;
4180b57cec5SDimitry Andric }
4190b57cec5SDimitry Andric 
4200b57cec5SDimitry Andric // movq %rbx, %rsp [0x48 0x8b 0xe3] or [0x48 0x89 0xdc]
4210b57cec5SDimitry Andric // movl %ebx, %esp [0x8b 0xe3] or [0x89 0xdc]
4220b57cec5SDimitry Andric bool x86AssemblyInspectionEngine::mov_rbx_rsp_pattern_p() {
4230b57cec5SDimitry Andric   uint8_t *p = m_cur_insn;
4240b57cec5SDimitry Andric   if (m_wordsize == 8 && *p == 0x48)
4250b57cec5SDimitry Andric     p++;
4260b57cec5SDimitry Andric   if (*(p) == 0x8b && *(p + 1) == 0xe3)
4270b57cec5SDimitry Andric     return true;
4280b57cec5SDimitry Andric   if (*(p) == 0x89 && *(p + 1) == 0xdc)
4290b57cec5SDimitry Andric     return true;
4300b57cec5SDimitry Andric   return false;
4310b57cec5SDimitry Andric }
4320b57cec5SDimitry Andric 
4330b57cec5SDimitry Andric // subq $0x20, %rsp
4340b57cec5SDimitry Andric bool x86AssemblyInspectionEngine::sub_rsp_pattern_p(int &amount) {
4350b57cec5SDimitry Andric   uint8_t *p = m_cur_insn;
4360b57cec5SDimitry Andric   if (m_wordsize == 8 && *p == 0x48)
4370b57cec5SDimitry Andric     p++;
4380b57cec5SDimitry Andric   // 8-bit immediate operand
4390b57cec5SDimitry Andric   if (*p == 0x83 && *(p + 1) == 0xec) {
4400b57cec5SDimitry Andric     amount = (int8_t) * (p + 2);
4410b57cec5SDimitry Andric     return true;
4420b57cec5SDimitry Andric   }
4430b57cec5SDimitry Andric   // 32-bit immediate operand
4440b57cec5SDimitry Andric   if (*p == 0x81 && *(p + 1) == 0xec) {
4450b57cec5SDimitry Andric     amount = (int32_t)extract_4(p + 2);
4460b57cec5SDimitry Andric     return true;
4470b57cec5SDimitry Andric   }
4480b57cec5SDimitry Andric   return false;
4490b57cec5SDimitry Andric }
4500b57cec5SDimitry Andric 
4510b57cec5SDimitry Andric // addq $0x20, %rsp
4520b57cec5SDimitry Andric bool x86AssemblyInspectionEngine::add_rsp_pattern_p(int &amount) {
4530b57cec5SDimitry Andric   uint8_t *p = m_cur_insn;
4540b57cec5SDimitry Andric   if (m_wordsize == 8 && *p == 0x48)
4550b57cec5SDimitry Andric     p++;
4560b57cec5SDimitry Andric   // 8-bit immediate operand
4570b57cec5SDimitry Andric   if (*p == 0x83 && *(p + 1) == 0xc4) {
4580b57cec5SDimitry Andric     amount = (int8_t) * (p + 2);
4590b57cec5SDimitry Andric     return true;
4600b57cec5SDimitry Andric   }
4610b57cec5SDimitry Andric   // 32-bit immediate operand
4620b57cec5SDimitry Andric   if (*p == 0x81 && *(p + 1) == 0xc4) {
4630b57cec5SDimitry Andric     amount = (int32_t)extract_4(p + 2);
4640b57cec5SDimitry Andric     return true;
4650b57cec5SDimitry Andric   }
4660b57cec5SDimitry Andric   return false;
4670b57cec5SDimitry Andric }
4680b57cec5SDimitry Andric 
4690b57cec5SDimitry Andric // lea esp, [esp - 0x28]
4700b57cec5SDimitry Andric // lea esp, [esp + 0x28]
4710b57cec5SDimitry Andric bool x86AssemblyInspectionEngine::lea_rsp_pattern_p(int &amount) {
4720b57cec5SDimitry Andric   uint8_t *p = m_cur_insn;
4730b57cec5SDimitry Andric   if (m_wordsize == 8 && *p == 0x48)
4740b57cec5SDimitry Andric     p++;
4750b57cec5SDimitry Andric 
4760b57cec5SDimitry Andric   // Check opcode
4770b57cec5SDimitry Andric   if (*p != 0x8d)
4780b57cec5SDimitry Andric     return false;
4790b57cec5SDimitry Andric 
4800b57cec5SDimitry Andric   // 8 bit displacement
4810b57cec5SDimitry Andric   if (*(p + 1) == 0x64 && (*(p + 2) & 0x3f) == 0x24) {
4820b57cec5SDimitry Andric     amount = (int8_t) * (p + 3);
4830b57cec5SDimitry Andric     return true;
4840b57cec5SDimitry Andric   }
4850b57cec5SDimitry Andric 
4860b57cec5SDimitry Andric   // 32 bit displacement
4870b57cec5SDimitry Andric   if (*(p + 1) == 0xa4 && (*(p + 2) & 0x3f) == 0x24) {
4880b57cec5SDimitry Andric     amount = (int32_t)extract_4(p + 3);
4890b57cec5SDimitry Andric     return true;
4900b57cec5SDimitry Andric   }
4910b57cec5SDimitry Andric 
4920b57cec5SDimitry Andric   return false;
4930b57cec5SDimitry Andric }
4940b57cec5SDimitry Andric 
4950b57cec5SDimitry Andric // lea -0x28(%ebp), %esp
4960b57cec5SDimitry Andric // (32-bit and 64-bit variants, 8-bit and 32-bit displacement)
4970b57cec5SDimitry Andric bool x86AssemblyInspectionEngine::lea_rbp_rsp_pattern_p(int &amount) {
4980b57cec5SDimitry Andric   uint8_t *p = m_cur_insn;
4990b57cec5SDimitry Andric   if (m_wordsize == 8 && *p == 0x48)
5000b57cec5SDimitry Andric     p++;
5010b57cec5SDimitry Andric 
5020b57cec5SDimitry Andric   // Check opcode
5030b57cec5SDimitry Andric   if (*p != 0x8d)
5040b57cec5SDimitry Andric     return false;
5050b57cec5SDimitry Andric   ++p;
5060b57cec5SDimitry Andric 
5070b57cec5SDimitry Andric   // 8 bit displacement
5080b57cec5SDimitry Andric   if (*p == 0x65) {
5090b57cec5SDimitry Andric     amount = (int8_t)p[1];
5100b57cec5SDimitry Andric     return true;
5110b57cec5SDimitry Andric   }
5120b57cec5SDimitry Andric 
5130b57cec5SDimitry Andric   // 32 bit displacement
5140b57cec5SDimitry Andric   if (*p == 0xa5) {
5150b57cec5SDimitry Andric     amount = (int32_t)extract_4(p + 1);
5160b57cec5SDimitry Andric     return true;
5170b57cec5SDimitry Andric   }
5180b57cec5SDimitry Andric 
5190b57cec5SDimitry Andric   return false;
5200b57cec5SDimitry Andric }
5210b57cec5SDimitry Andric 
5220b57cec5SDimitry Andric // lea -0x28(%ebx), %esp
5230b57cec5SDimitry Andric // (32-bit and 64-bit variants, 8-bit and 32-bit displacement)
5240b57cec5SDimitry Andric bool x86AssemblyInspectionEngine::lea_rbx_rsp_pattern_p(int &amount) {
5250b57cec5SDimitry Andric   uint8_t *p = m_cur_insn;
5260b57cec5SDimitry Andric   if (m_wordsize == 8 && *p == 0x48)
5270b57cec5SDimitry Andric     p++;
5280b57cec5SDimitry Andric 
5290b57cec5SDimitry Andric   // Check opcode
5300b57cec5SDimitry Andric   if (*p != 0x8d)
5310b57cec5SDimitry Andric     return false;
5320b57cec5SDimitry Andric   ++p;
5330b57cec5SDimitry Andric 
5340b57cec5SDimitry Andric   // 8 bit displacement
5350b57cec5SDimitry Andric   if (*p == 0x63) {
5360b57cec5SDimitry Andric     amount = (int8_t)p[1];
5370b57cec5SDimitry Andric     return true;
5380b57cec5SDimitry Andric   }
5390b57cec5SDimitry Andric 
5400b57cec5SDimitry Andric   // 32 bit displacement
5410b57cec5SDimitry Andric   if (*p == 0xa3) {
5420b57cec5SDimitry Andric     amount = (int32_t)extract_4(p + 1);
5430b57cec5SDimitry Andric     return true;
5440b57cec5SDimitry Andric   }
5450b57cec5SDimitry Andric 
5460b57cec5SDimitry Andric   return false;
5470b57cec5SDimitry Andric }
5480b57cec5SDimitry Andric 
5490b57cec5SDimitry Andric // and -0xfffffff0, %esp
5500b57cec5SDimitry Andric // (32-bit and 64-bit variants, 8-bit and 32-bit displacement)
5510b57cec5SDimitry Andric bool x86AssemblyInspectionEngine::and_rsp_pattern_p() {
5520b57cec5SDimitry Andric   uint8_t *p = m_cur_insn;
5530b57cec5SDimitry Andric   if (m_wordsize == 8 && *p == 0x48)
5540b57cec5SDimitry Andric     p++;
5550b57cec5SDimitry Andric 
5560b57cec5SDimitry Andric   if (*p != 0x81 && *p != 0x83)
5570b57cec5SDimitry Andric     return false;
5580b57cec5SDimitry Andric 
5590b57cec5SDimitry Andric   return *++p == 0xe4;
5600b57cec5SDimitry Andric }
5610b57cec5SDimitry Andric 
5620b57cec5SDimitry Andric // popq %rbx
5630b57cec5SDimitry Andric // popl %ebx
5640b57cec5SDimitry Andric bool x86AssemblyInspectionEngine::pop_reg_p(int &regno) {
5650b57cec5SDimitry Andric   uint8_t *p = m_cur_insn;
5660b57cec5SDimitry Andric   int regno_prefix_bit = 0;
5670b57cec5SDimitry Andric   // If we have a rex prefix byte, check to see if a B bit is set
5680b57cec5SDimitry Andric   if (m_wordsize == 8 && (*p & 0xfe) == 0x40) {
5690b57cec5SDimitry Andric     regno_prefix_bit = (*p & 1) << 3;
5700b57cec5SDimitry Andric     p++;
5710b57cec5SDimitry Andric   }
5720b57cec5SDimitry Andric   if (*p >= 0x58 && *p <= 0x5f) {
5730b57cec5SDimitry Andric     regno = (*p - 0x58) | regno_prefix_bit;
5740b57cec5SDimitry Andric     return true;
5750b57cec5SDimitry Andric   }
5760b57cec5SDimitry Andric   return false;
5770b57cec5SDimitry Andric }
5780b57cec5SDimitry Andric 
5790b57cec5SDimitry Andric // popq %rbp [0x5d]
5800b57cec5SDimitry Andric // popl %ebp [0x5d]
5810b57cec5SDimitry Andric bool x86AssemblyInspectionEngine::pop_rbp_pattern_p() {
5820b57cec5SDimitry Andric   uint8_t *p = m_cur_insn;
5830b57cec5SDimitry Andric   return (*p == 0x5d);
5840b57cec5SDimitry Andric }
5850b57cec5SDimitry Andric 
5860b57cec5SDimitry Andric // instructions valid only in 32-bit mode:
5870b57cec5SDimitry Andric // 0x1f - pop ds
5880b57cec5SDimitry Andric // 0x07 - pop es
5890b57cec5SDimitry Andric // 0x17 - pop ss
5900b57cec5SDimitry Andric bool x86AssemblyInspectionEngine::pop_misc_reg_p() {
5910b57cec5SDimitry Andric   uint8_t p = *m_cur_insn;
5920b57cec5SDimitry Andric   if (m_wordsize == 4) {
5930b57cec5SDimitry Andric     if (p == 0x1f || p == 0x07 || p == 0x17)
5940b57cec5SDimitry Andric       return true;
5950b57cec5SDimitry Andric   }
5960b57cec5SDimitry Andric   return false;
5970b57cec5SDimitry Andric }
5980b57cec5SDimitry Andric 
5990b57cec5SDimitry Andric // leave [0xc9]
6000b57cec5SDimitry Andric bool x86AssemblyInspectionEngine::leave_pattern_p() {
6010b57cec5SDimitry Andric   uint8_t *p = m_cur_insn;
6020b57cec5SDimitry Andric   return (*p == 0xc9);
6030b57cec5SDimitry Andric }
6040b57cec5SDimitry Andric 
6050b57cec5SDimitry Andric // call $0 [0xe8 0x0 0x0 0x0 0x0]
6060b57cec5SDimitry Andric bool x86AssemblyInspectionEngine::call_next_insn_pattern_p() {
6070b57cec5SDimitry Andric   uint8_t *p = m_cur_insn;
6080b57cec5SDimitry Andric   return (*p == 0xe8) && (*(p + 1) == 0x0) && (*(p + 2) == 0x0) &&
6090b57cec5SDimitry Andric          (*(p + 3) == 0x0) && (*(p + 4) == 0x0);
6100b57cec5SDimitry Andric }
6110b57cec5SDimitry Andric 
6120b57cec5SDimitry Andric // Look for an instruction sequence storing a nonvolatile register on to the
6130b57cec5SDimitry Andric // stack frame.
6140b57cec5SDimitry Andric 
6150b57cec5SDimitry Andric //  movq %rax, -0x10(%rbp) [0x48 0x89 0x45 0xf0]
6160b57cec5SDimitry Andric //  movl %eax, -0xc(%ebp)  [0x89 0x45 0xf4]
6170b57cec5SDimitry Andric 
6180b57cec5SDimitry Andric // The offset value returned in rbp_offset will be positive -- but it must be
6190b57cec5SDimitry Andric // subtraced from the frame base register to get the actual location.  The
6200b57cec5SDimitry Andric // positive value returned for the offset is a convention used elsewhere for
6210b57cec5SDimitry Andric // CFA offsets et al.
6220b57cec5SDimitry Andric 
6230b57cec5SDimitry Andric bool x86AssemblyInspectionEngine::mov_reg_to_local_stack_frame_p(
6240b57cec5SDimitry Andric     int &regno, int &rbp_offset) {
6250b57cec5SDimitry Andric   uint8_t *p = m_cur_insn;
6260b57cec5SDimitry Andric   int src_reg_prefix_bit = 0;
6270b57cec5SDimitry Andric   int target_reg_prefix_bit = 0;
6280b57cec5SDimitry Andric 
6290b57cec5SDimitry Andric   if (m_wordsize == 8 && REX_W_PREFIX_P(*p)) {
6300b57cec5SDimitry Andric     src_reg_prefix_bit = REX_W_SRCREG(*p) << 3;
6310b57cec5SDimitry Andric     target_reg_prefix_bit = REX_W_DSTREG(*p) << 3;
6320b57cec5SDimitry Andric     if (target_reg_prefix_bit == 1) {
6330b57cec5SDimitry Andric       // rbp/ebp don't need a prefix bit - we know this isn't the reg we care
6340b57cec5SDimitry Andric       // about.
6350b57cec5SDimitry Andric       return false;
6360b57cec5SDimitry Andric     }
6370b57cec5SDimitry Andric     p++;
6380b57cec5SDimitry Andric   }
6390b57cec5SDimitry Andric 
6400b57cec5SDimitry Andric   if (*p == 0x89) {
6410b57cec5SDimitry Andric     /* Mask off the 3-5 bits which indicate the destination register
6420b57cec5SDimitry Andric        if this is a ModR/M byte.  */
6430b57cec5SDimitry Andric     int opcode_destreg_masked_out = *(p + 1) & (~0x38);
6440b57cec5SDimitry Andric 
6450b57cec5SDimitry Andric     /* Is this a ModR/M byte with Mod bits 01 and R/M bits 101
6460b57cec5SDimitry Andric        and three bits between them, e.g. 01nnn101
6470b57cec5SDimitry Andric        We're looking for a destination of ebp-disp8 or ebp-disp32.   */
6480b57cec5SDimitry Andric     int immsize;
6490b57cec5SDimitry Andric     if (opcode_destreg_masked_out == 0x45)
6500b57cec5SDimitry Andric       immsize = 2;
6510b57cec5SDimitry Andric     else if (opcode_destreg_masked_out == 0x85)
6520b57cec5SDimitry Andric       immsize = 4;
6530b57cec5SDimitry Andric     else
6540b57cec5SDimitry Andric       return false;
6550b57cec5SDimitry Andric 
6560b57cec5SDimitry Andric     int offset = 0;
6570b57cec5SDimitry Andric     if (immsize == 2)
6580b57cec5SDimitry Andric       offset = (int8_t) * (p + 2);
6590b57cec5SDimitry Andric     if (immsize == 4)
6600b57cec5SDimitry Andric       offset = (uint32_t)extract_4(p + 2);
6610b57cec5SDimitry Andric     if (offset > 0)
6620b57cec5SDimitry Andric       return false;
6630b57cec5SDimitry Andric 
6640b57cec5SDimitry Andric     regno = ((*(p + 1) >> 3) & 0x7) | src_reg_prefix_bit;
6650b57cec5SDimitry Andric     rbp_offset = offset > 0 ? offset : -offset;
6660b57cec5SDimitry Andric     return true;
6670b57cec5SDimitry Andric   }
6680b57cec5SDimitry Andric   return false;
6690b57cec5SDimitry Andric }
6700b57cec5SDimitry Andric 
6710b57cec5SDimitry Andric // Returns true if this is a jmp instruction where we can't
6720b57cec5SDimitry Andric // know the destination address statically.
6730b57cec5SDimitry Andric //
6740b57cec5SDimitry Andric // ff e0                                   jmpq   *%rax
6750b57cec5SDimitry Andric // ff e1                                   jmpq   *%rcx
6760b57cec5SDimitry Andric // ff 60 28                                jmpq   *0x28(%rax)
6770b57cec5SDimitry Andric // ff 60 60                                jmpq   *0x60(%rax)
6780b57cec5SDimitry Andric bool x86AssemblyInspectionEngine::jmp_to_reg_p() {
6790b57cec5SDimitry Andric   if (*m_cur_insn != 0xff)
6800b57cec5SDimitry Andric     return false;
6810b57cec5SDimitry Andric 
6820b57cec5SDimitry Andric   // The second byte is a ModR/M /4 byte, strip off the registers
6830b57cec5SDimitry Andric   uint8_t second_byte_sans_reg = *(m_cur_insn + 1) & ~7;
6840b57cec5SDimitry Andric 
6850b57cec5SDimitry Andric   // [reg]
6860b57cec5SDimitry Andric   if (second_byte_sans_reg == 0x20)
6870b57cec5SDimitry Andric     return true;
6880b57cec5SDimitry Andric 
6890b57cec5SDimitry Andric   // [reg]+disp8
6900b57cec5SDimitry Andric   if (second_byte_sans_reg == 0x60)
6910b57cec5SDimitry Andric     return true;
6920b57cec5SDimitry Andric 
6930b57cec5SDimitry Andric   // [reg]+disp32
6940b57cec5SDimitry Andric   if (second_byte_sans_reg == 0xa0)
6950b57cec5SDimitry Andric     return true;
6960b57cec5SDimitry Andric 
6970b57cec5SDimitry Andric   // reg
6980b57cec5SDimitry Andric   if (second_byte_sans_reg == 0xe0)
6990b57cec5SDimitry Andric     return true;
7000b57cec5SDimitry Andric 
7010b57cec5SDimitry Andric   return false;
7020b57cec5SDimitry Andric }
7030b57cec5SDimitry Andric 
7040b57cec5SDimitry Andric // Detect branches to fixed pc-relative offsets.
7050b57cec5SDimitry Andric // Returns the offset from the address of the next instruction
7060b57cec5SDimitry Andric // that may be branch/jumped to.
7070b57cec5SDimitry Andric //
7080b57cec5SDimitry Andric // Cannot determine the offset of a JMP that jumps to the address in
7090b57cec5SDimitry Andric // a register ("jmpq *%rax") or offset from a register value
7100b57cec5SDimitry Andric // ("jmpq *0x28(%rax)"), this method will return false on those
7110b57cec5SDimitry Andric // instructions.
7120b57cec5SDimitry Andric //
7130b57cec5SDimitry Andric // These instructions all end in either a relative 8/16/32 bit value
7140b57cec5SDimitry Andric // depending on the instruction and the current execution mode of the
7150b57cec5SDimitry Andric // inferior process.  Once we know the size of the opcode instruction,
7160b57cec5SDimitry Andric // we can use the total instruction length to determine the size of
7170b57cec5SDimitry Andric // the relative offset without having to compute it correctly.
7180b57cec5SDimitry Andric 
7190b57cec5SDimitry Andric bool x86AssemblyInspectionEngine::pc_rel_branch_or_jump_p (
7200b57cec5SDimitry Andric     const int instruction_length, int &offset)
7210b57cec5SDimitry Andric {
7220b57cec5SDimitry Andric   int opcode_size = 0;
7230b57cec5SDimitry Andric 
7240b57cec5SDimitry Andric   uint8_t b1 = m_cur_insn[0];
7250b57cec5SDimitry Andric 
7260b57cec5SDimitry Andric   switch (b1) {
7270b57cec5SDimitry Andric     case 0x77: // JA/JNBE rel8
7280b57cec5SDimitry Andric     case 0x73: // JAE/JNB/JNC rel8
7290b57cec5SDimitry Andric     case 0x72: // JB/JC/JNAE rel8
7300b57cec5SDimitry Andric     case 0x76: // JBE/JNA rel8
7310b57cec5SDimitry Andric     case 0xe3: // JCXZ/JECXZ/JRCXZ rel8
7320b57cec5SDimitry Andric     case 0x74: // JE/JZ rel8
7330b57cec5SDimitry Andric     case 0x7f: // JG/JNLE rel8
7340b57cec5SDimitry Andric     case 0x7d: // JGE/JNL rel8
7350b57cec5SDimitry Andric     case 0x7c: // JL/JNGE rel8
7360b57cec5SDimitry Andric     case 0x7e: // JNG/JLE rel8
7370b57cec5SDimitry Andric     case 0x71: // JNO rel8
7380b57cec5SDimitry Andric     case 0x7b: // JNP/JPO rel8
7390b57cec5SDimitry Andric     case 0x79: // JNS rel8
7400b57cec5SDimitry Andric     case 0x75: // JNE/JNZ rel8
7410b57cec5SDimitry Andric     case 0x70: // JO rel8
7420b57cec5SDimitry Andric     case 0x7a: // JP/JPE rel8
7430b57cec5SDimitry Andric     case 0x78: // JS rel8
7440b57cec5SDimitry Andric     case 0xeb: // JMP rel8
7450b57cec5SDimitry Andric     case 0xe9: // JMP rel16/rel32
7460b57cec5SDimitry Andric       opcode_size = 1;
7470b57cec5SDimitry Andric       break;
7480b57cec5SDimitry Andric     default:
7490b57cec5SDimitry Andric       break;
7500b57cec5SDimitry Andric   }
7510b57cec5SDimitry Andric   if (b1 == 0x0f && opcode_size == 0) {
7520b57cec5SDimitry Andric     uint8_t b2 = m_cur_insn[1];
7530b57cec5SDimitry Andric     switch (b2) {
7540b57cec5SDimitry Andric       case 0x87: // JA/JNBE rel16/rel32
7550b57cec5SDimitry Andric       case 0x86: // JBE/JNA rel16/rel32
7560b57cec5SDimitry Andric       case 0x84: // JE/JZ rel16/rel32
7570b57cec5SDimitry Andric       case 0x8f: // JG/JNLE rel16/rel32
7580b57cec5SDimitry Andric       case 0x8d: // JNL/JGE rel16/rel32
7590b57cec5SDimitry Andric       case 0x8e: // JLE rel16/rel32
7600b57cec5SDimitry Andric       case 0x82: // JB/JC/JNAE rel16/rel32
7610b57cec5SDimitry Andric       case 0x83: // JAE/JNB/JNC rel16/rel32
7620b57cec5SDimitry Andric       case 0x85: // JNE/JNZ rel16/rel32
7630b57cec5SDimitry Andric       case 0x8c: // JL/JNGE rel16/rel32
7640b57cec5SDimitry Andric       case 0x81: // JNO rel16/rel32
7650b57cec5SDimitry Andric       case 0x8b: // JNP/JPO rel16/rel32
7660b57cec5SDimitry Andric       case 0x89: // JNS rel16/rel32
7670b57cec5SDimitry Andric       case 0x80: // JO rel16/rel32
7680b57cec5SDimitry Andric       case 0x8a: // JP rel16/rel32
7690b57cec5SDimitry Andric       case 0x88: // JS rel16/rel32
7700b57cec5SDimitry Andric         opcode_size = 2;
7710b57cec5SDimitry Andric         break;
7720b57cec5SDimitry Andric       default:
7730b57cec5SDimitry Andric         break;
7740b57cec5SDimitry Andric     }
7750b57cec5SDimitry Andric   }
7760b57cec5SDimitry Andric 
7770b57cec5SDimitry Andric   if (opcode_size == 0)
7780b57cec5SDimitry Andric     return false;
7790b57cec5SDimitry Andric 
7800b57cec5SDimitry Andric   offset = 0;
7810b57cec5SDimitry Andric   if (instruction_length - opcode_size == 1) {
7820b57cec5SDimitry Andric     int8_t rel8 = (int8_t) *(m_cur_insn + opcode_size);
7830b57cec5SDimitry Andric     offset = rel8;
7840b57cec5SDimitry Andric   } else if (instruction_length - opcode_size == 2) {
7850b57cec5SDimitry Andric     int16_t rel16 = extract_2_signed (m_cur_insn + opcode_size);
7860b57cec5SDimitry Andric     offset = rel16;
7870b57cec5SDimitry Andric   } else if (instruction_length - opcode_size == 4) {
7880b57cec5SDimitry Andric     int32_t rel32 = extract_4_signed (m_cur_insn + opcode_size);
7890b57cec5SDimitry Andric     offset = rel32;
7900b57cec5SDimitry Andric   } else {
7910b57cec5SDimitry Andric     return false;
7920b57cec5SDimitry Andric   }
7930b57cec5SDimitry Andric   return true;
7940b57cec5SDimitry Andric }
7950b57cec5SDimitry Andric 
7960b57cec5SDimitry Andric // Returns true if this instruction is a intra-function branch or jump -
7970b57cec5SDimitry Andric // a branch/jump within the bounds of this same function.
7980b57cec5SDimitry Andric // Cannot predict where a jump through a register value ("jmpq *%rax")
7990b57cec5SDimitry Andric // will go, so it will return false on that instruction.
8000b57cec5SDimitry Andric bool x86AssemblyInspectionEngine::local_branch_p (
8010b57cec5SDimitry Andric     const addr_t current_func_text_offset,
8020b57cec5SDimitry Andric     const AddressRange &func_range,
8030b57cec5SDimitry Andric     const int instruction_length,
8040b57cec5SDimitry Andric     addr_t &target_insn_offset) {
8050b57cec5SDimitry Andric   int offset;
8060b57cec5SDimitry Andric   if (pc_rel_branch_or_jump_p (instruction_length, offset) && offset != 0) {
8070b57cec5SDimitry Andric     addr_t next_pc_value = current_func_text_offset + instruction_length;
8080b57cec5SDimitry Andric     if (offset < 0 && addr_t(-offset) > current_func_text_offset) {
8090b57cec5SDimitry Andric       // Branch target is before the start of this function
8100b57cec5SDimitry Andric       return false;
8110b57cec5SDimitry Andric     }
8120b57cec5SDimitry Andric     if (offset + next_pc_value > func_range.GetByteSize()) {
8130b57cec5SDimitry Andric       // Branch targets outside this function's bounds
8140b57cec5SDimitry Andric       return false;
8150b57cec5SDimitry Andric     }
8160b57cec5SDimitry Andric     // This instruction branches to target_insn_offset (byte offset into the function)
8170b57cec5SDimitry Andric     target_insn_offset = next_pc_value + offset;
8180b57cec5SDimitry Andric     return true;
8190b57cec5SDimitry Andric   }
8200b57cec5SDimitry Andric   return false;
8210b57cec5SDimitry Andric }
8220b57cec5SDimitry Andric 
8230b57cec5SDimitry Andric // Returns true if this instruction is a inter-function branch or jump - a
8240b57cec5SDimitry Andric // branch/jump to another function.
8250b57cec5SDimitry Andric // Cannot predict where a jump through a register value ("jmpq *%rax")
8260b57cec5SDimitry Andric // will go, so it will return false on that instruction.
8270b57cec5SDimitry Andric bool x86AssemblyInspectionEngine::non_local_branch_p (
8280b57cec5SDimitry Andric     const addr_t current_func_text_offset,
8290b57cec5SDimitry Andric     const AddressRange &func_range,
8300b57cec5SDimitry Andric     const int instruction_length) {
8310b57cec5SDimitry Andric   int offset;
8320b57cec5SDimitry Andric   addr_t target_insn_offset;
8330b57cec5SDimitry Andric   if (pc_rel_branch_or_jump_p (instruction_length, offset)) {
8340b57cec5SDimitry Andric     return !local_branch_p(current_func_text_offset,func_range,instruction_length,target_insn_offset);
8350b57cec5SDimitry Andric   }
8360b57cec5SDimitry Andric   return false;
8370b57cec5SDimitry Andric }
8380b57cec5SDimitry Andric 
8390b57cec5SDimitry Andric // ret [0xc3] or [0xcb] or [0xc2 imm16] or [0xca imm16]
8400b57cec5SDimitry Andric bool x86AssemblyInspectionEngine::ret_pattern_p() {
8410b57cec5SDimitry Andric   uint8_t *p = m_cur_insn;
8420b57cec5SDimitry Andric   return *p == 0xc3 || *p == 0xc2 || *p == 0xca || *p == 0xcb;
8430b57cec5SDimitry Andric }
8440b57cec5SDimitry Andric 
8450b57cec5SDimitry Andric uint16_t x86AssemblyInspectionEngine::extract_2(uint8_t *b) {
8460b57cec5SDimitry Andric   uint16_t v = 0;
8470b57cec5SDimitry Andric   for (int i = 1; i >= 0; i--)
8480b57cec5SDimitry Andric     v = (v << 8) | b[i];
8490b57cec5SDimitry Andric   return v;
8500b57cec5SDimitry Andric }
8510b57cec5SDimitry Andric 
8520b57cec5SDimitry Andric int16_t x86AssemblyInspectionEngine::extract_2_signed(uint8_t *b) {
8530b57cec5SDimitry Andric   int16_t v = 0;
8540b57cec5SDimitry Andric   for (int i = 1; i >= 0; i--)
8550b57cec5SDimitry Andric     v = (v << 8) | b[i];
8560b57cec5SDimitry Andric   return v;
8570b57cec5SDimitry Andric }
8580b57cec5SDimitry Andric 
8590b57cec5SDimitry Andric uint32_t x86AssemblyInspectionEngine::extract_4(uint8_t *b) {
8600b57cec5SDimitry Andric   uint32_t v = 0;
8610b57cec5SDimitry Andric   for (int i = 3; i >= 0; i--)
8620b57cec5SDimitry Andric     v = (v << 8) | b[i];
8630b57cec5SDimitry Andric   return v;
8640b57cec5SDimitry Andric }
8650b57cec5SDimitry Andric 
8660b57cec5SDimitry Andric int32_t x86AssemblyInspectionEngine::extract_4_signed(uint8_t *b) {
8670b57cec5SDimitry Andric   int32_t v = 0;
8680b57cec5SDimitry Andric   for (int i = 3; i >= 0; i--)
8690b57cec5SDimitry Andric     v = (v << 8) | b[i];
8700b57cec5SDimitry Andric   return v;
8710b57cec5SDimitry Andric }
8720b57cec5SDimitry Andric 
8730b57cec5SDimitry Andric 
8740b57cec5SDimitry Andric bool x86AssemblyInspectionEngine::instruction_length(uint8_t *insn_p,
8750b57cec5SDimitry Andric                                                      int &length,
8760b57cec5SDimitry Andric                                                      uint32_t buffer_remaining_bytes) {
8770b57cec5SDimitry Andric 
8780b57cec5SDimitry Andric   uint32_t max_op_byte_size = std::min(buffer_remaining_bytes, m_arch.GetMaximumOpcodeByteSize());
8790b57cec5SDimitry Andric   llvm::SmallVector<uint8_t, 32> opcode_data;
8800b57cec5SDimitry Andric   opcode_data.resize(max_op_byte_size);
8810b57cec5SDimitry Andric 
8820b57cec5SDimitry Andric   char out_string[512];
8830b57cec5SDimitry Andric   const size_t inst_size =
8840b57cec5SDimitry Andric       ::LLVMDisasmInstruction(m_disasm_context, insn_p, max_op_byte_size, 0,
8850b57cec5SDimitry Andric                               out_string, sizeof(out_string));
8860b57cec5SDimitry Andric 
8870b57cec5SDimitry Andric   length = inst_size;
8880b57cec5SDimitry Andric   return true;
8890b57cec5SDimitry Andric }
8900b57cec5SDimitry Andric 
8910b57cec5SDimitry Andric bool x86AssemblyInspectionEngine::machine_regno_to_lldb_regno(
8920b57cec5SDimitry Andric     int machine_regno, uint32_t &lldb_regno) {
8930b57cec5SDimitry Andric   MachineRegnumToNameAndLLDBRegnum::iterator it = m_reg_map.find(machine_regno);
8940b57cec5SDimitry Andric   if (it != m_reg_map.end()) {
8950b57cec5SDimitry Andric     lldb_regno = it->second.lldb_regnum;
8960b57cec5SDimitry Andric     return true;
8970b57cec5SDimitry Andric   }
8980b57cec5SDimitry Andric   return false;
8990b57cec5SDimitry Andric }
9000b57cec5SDimitry Andric 
9010b57cec5SDimitry Andric bool x86AssemblyInspectionEngine::GetNonCallSiteUnwindPlanFromAssembly(
9020b57cec5SDimitry Andric     uint8_t *data, size_t size, AddressRange &func_range,
9030b57cec5SDimitry Andric     UnwindPlan &unwind_plan) {
9040b57cec5SDimitry Andric   unwind_plan.Clear();
9050b57cec5SDimitry Andric 
9060b57cec5SDimitry Andric   if (data == nullptr || size == 0)
9070b57cec5SDimitry Andric     return false;
9080b57cec5SDimitry Andric 
9090b57cec5SDimitry Andric   if (!m_register_map_initialized)
9100b57cec5SDimitry Andric     return false;
9110b57cec5SDimitry Andric 
912*0fca6ea1SDimitry Andric   if (m_disasm_context == nullptr)
913*0fca6ea1SDimitry Andric     return false;
914*0fca6ea1SDimitry Andric 
9150b57cec5SDimitry Andric   addr_t current_func_text_offset = 0;
9160b57cec5SDimitry Andric   int current_sp_bytes_offset_from_fa = 0;
9170b57cec5SDimitry Andric   bool is_aligned = false;
9180b57cec5SDimitry Andric   UnwindPlan::Row::RegisterLocation initial_regloc;
9190b57cec5SDimitry Andric   UnwindPlan::RowSP row(new UnwindPlan::Row);
9200b57cec5SDimitry Andric 
9210b57cec5SDimitry Andric   unwind_plan.SetPlanValidAddressRange(func_range);
9220b57cec5SDimitry Andric   unwind_plan.SetRegisterKind(eRegisterKindLLDB);
9230b57cec5SDimitry Andric 
9240b57cec5SDimitry Andric   // At the start of the function, find the CFA by adding wordsize to the SP
9250b57cec5SDimitry Andric   // register
9260b57cec5SDimitry Andric   row->SetOffset(current_func_text_offset);
9270b57cec5SDimitry Andric   row->GetCFAValue().SetIsRegisterPlusOffset(m_lldb_sp_regnum, m_wordsize);
9280b57cec5SDimitry Andric 
9290b57cec5SDimitry Andric   // caller's stack pointer value before the call insn is the CFA address
9300b57cec5SDimitry Andric   initial_regloc.SetIsCFAPlusOffset(0);
9310b57cec5SDimitry Andric   row->SetRegisterInfo(m_lldb_sp_regnum, initial_regloc);
9320b57cec5SDimitry Andric 
9330b57cec5SDimitry Andric   // saved instruction pointer can be found at CFA - wordsize.
9340b57cec5SDimitry Andric   current_sp_bytes_offset_from_fa = m_wordsize;
9350b57cec5SDimitry Andric   initial_regloc.SetAtCFAPlusOffset(-current_sp_bytes_offset_from_fa);
9360b57cec5SDimitry Andric   row->SetRegisterInfo(m_lldb_ip_regnum, initial_regloc);
9370b57cec5SDimitry Andric 
9380b57cec5SDimitry Andric   unwind_plan.AppendRow(row);
9390b57cec5SDimitry Andric 
9400b57cec5SDimitry Andric   // Allocate a new Row, populate it with the existing Row contents.
9410b57cec5SDimitry Andric   UnwindPlan::Row *newrow = new UnwindPlan::Row;
9420b57cec5SDimitry Andric   *newrow = *row.get();
9430b57cec5SDimitry Andric   row.reset(newrow);
9440b57cec5SDimitry Andric 
9450b57cec5SDimitry Andric   // Track which registers have been saved so far in the prologue. If we see
9460b57cec5SDimitry Andric   // another push of that register, it's not part of the prologue. The register
9470b57cec5SDimitry Andric   // numbers used here are the machine register #'s (i386_register_numbers,
9480b57cec5SDimitry Andric   // x86_64_register_numbers).
9490b57cec5SDimitry Andric   std::vector<bool> saved_registers(32, false);
9500b57cec5SDimitry Andric 
9510b57cec5SDimitry Andric   // Once the prologue has completed we'll save a copy of the unwind
9520b57cec5SDimitry Andric   // instructions If there is an epilogue in the middle of the function, after
9530b57cec5SDimitry Andric   // that epilogue we'll reinstate the unwind setup -- we assume that some code
9540b57cec5SDimitry Andric   // path jumps over the mid-function epilogue
9550b57cec5SDimitry Andric 
9560b57cec5SDimitry Andric   UnwindPlan::RowSP prologue_completed_row; // copy of prologue row of CFI
957bdd1243dSDimitry Andric   int prologue_completed_sp_bytes_offset_from_cfa = 0; // The sp value before the
9580b57cec5SDimitry Andric                                                    // epilogue started executed
959972a253aSDimitry Andric   bool prologue_completed_is_aligned = false;
9600b57cec5SDimitry Andric   std::vector<bool> prologue_completed_saved_registers;
9610b57cec5SDimitry Andric 
9620b57cec5SDimitry Andric   while (current_func_text_offset < size) {
9630b57cec5SDimitry Andric     int stack_offset, insn_len;
9640b57cec5SDimitry Andric     int machine_regno;   // register numbers masked directly out of instructions
9650b57cec5SDimitry Andric     uint32_t lldb_regno; // register numbers in lldb's eRegisterKindLLDB
9660b57cec5SDimitry Andric                          // numbering scheme
9670b57cec5SDimitry Andric 
9680b57cec5SDimitry Andric     bool in_epilogue = false; // we're in the middle of an epilogue sequence
9690b57cec5SDimitry Andric     bool row_updated = false; // The UnwindPlan::Row 'row' has been updated
9700b57cec5SDimitry Andric 
9710b57cec5SDimitry Andric     m_cur_insn = data + current_func_text_offset;
9720b57cec5SDimitry Andric     if (!instruction_length(m_cur_insn, insn_len, size - current_func_text_offset)
9730b57cec5SDimitry Andric         || insn_len == 0
9740b57cec5SDimitry Andric         || insn_len > kMaxInstructionByteSize) {
9750b57cec5SDimitry Andric       // An unrecognized/junk instruction
9760b57cec5SDimitry Andric       break;
9770b57cec5SDimitry Andric     }
9780b57cec5SDimitry Andric 
9790b57cec5SDimitry Andric     auto &cfa_value = row->GetCFAValue();
9800b57cec5SDimitry Andric     auto &afa_value = row->GetAFAValue();
9810b57cec5SDimitry Andric     auto fa_value_ptr = is_aligned ? &afa_value : &cfa_value;
9820b57cec5SDimitry Andric 
9830b57cec5SDimitry Andric     if (mov_rsp_rbp_pattern_p()) {
9840b57cec5SDimitry Andric       if (fa_value_ptr->GetRegisterNumber() == m_lldb_sp_regnum) {
9850b57cec5SDimitry Andric         fa_value_ptr->SetIsRegisterPlusOffset(
9860b57cec5SDimitry Andric             m_lldb_fp_regnum, fa_value_ptr->GetOffset());
9870b57cec5SDimitry Andric         row_updated = true;
9880b57cec5SDimitry Andric       }
9890b57cec5SDimitry Andric     }
9900b57cec5SDimitry Andric 
9910b57cec5SDimitry Andric     else if (mov_rsp_rbx_pattern_p()) {
9920b57cec5SDimitry Andric       if (fa_value_ptr->GetRegisterNumber() == m_lldb_sp_regnum) {
9930b57cec5SDimitry Andric         fa_value_ptr->SetIsRegisterPlusOffset(
9940b57cec5SDimitry Andric             m_lldb_alt_fp_regnum, fa_value_ptr->GetOffset());
9950b57cec5SDimitry Andric         row_updated = true;
9960b57cec5SDimitry Andric       }
9970b57cec5SDimitry Andric     }
9980b57cec5SDimitry Andric 
9990b57cec5SDimitry Andric     else if (and_rsp_pattern_p()) {
10000b57cec5SDimitry Andric       current_sp_bytes_offset_from_fa = 0;
10010b57cec5SDimitry Andric       afa_value.SetIsRegisterPlusOffset(
10020b57cec5SDimitry Andric           m_lldb_sp_regnum, current_sp_bytes_offset_from_fa);
10030b57cec5SDimitry Andric       fa_value_ptr = &afa_value;
10040b57cec5SDimitry Andric       is_aligned = true;
10050b57cec5SDimitry Andric       row_updated = true;
10060b57cec5SDimitry Andric     }
10070b57cec5SDimitry Andric 
10080b57cec5SDimitry Andric     else if (mov_rbp_rsp_pattern_p()) {
10090b57cec5SDimitry Andric       if (is_aligned && cfa_value.GetRegisterNumber() == m_lldb_fp_regnum)
10100b57cec5SDimitry Andric       {
10110b57cec5SDimitry Andric         is_aligned = false;
10120b57cec5SDimitry Andric         fa_value_ptr = &cfa_value;
10130b57cec5SDimitry Andric         afa_value.SetUnspecified();
10140b57cec5SDimitry Andric         row_updated = true;
10150b57cec5SDimitry Andric       }
10160b57cec5SDimitry Andric       if (fa_value_ptr->GetRegisterNumber() == m_lldb_fp_regnum)
10170b57cec5SDimitry Andric         current_sp_bytes_offset_from_fa = fa_value_ptr->GetOffset();
10180b57cec5SDimitry Andric     }
10190b57cec5SDimitry Andric 
10200b57cec5SDimitry Andric     else if (mov_rbx_rsp_pattern_p()) {
10210b57cec5SDimitry Andric       if (is_aligned && cfa_value.GetRegisterNumber() == m_lldb_alt_fp_regnum)
10220b57cec5SDimitry Andric       {
10230b57cec5SDimitry Andric         is_aligned = false;
10240b57cec5SDimitry Andric         fa_value_ptr = &cfa_value;
10250b57cec5SDimitry Andric         afa_value.SetUnspecified();
10260b57cec5SDimitry Andric         row_updated = true;
10270b57cec5SDimitry Andric       }
10280b57cec5SDimitry Andric       if (fa_value_ptr->GetRegisterNumber() == m_lldb_alt_fp_regnum)
10290b57cec5SDimitry Andric         current_sp_bytes_offset_from_fa = fa_value_ptr->GetOffset();
10300b57cec5SDimitry Andric     }
10310b57cec5SDimitry Andric 
10320b57cec5SDimitry Andric     // This is the start() function (or a pthread equivalent), it starts with a
10330b57cec5SDimitry Andric     // pushl $0x0 which puts the saved pc value of 0 on the stack.  In this
10340b57cec5SDimitry Andric     // case we want to pretend we didn't see a stack movement at all --
10350b57cec5SDimitry Andric     // normally the saved pc value is already on the stack by the time the
10360b57cec5SDimitry Andric     // function starts executing.
10370b57cec5SDimitry Andric     else if (push_0_pattern_p()) {
10380b57cec5SDimitry Andric     }
10390b57cec5SDimitry Andric 
10400b57cec5SDimitry Andric     else if (push_reg_p(machine_regno)) {
10410b57cec5SDimitry Andric       current_sp_bytes_offset_from_fa += m_wordsize;
10420b57cec5SDimitry Andric       // the PUSH instruction has moved the stack pointer - if the FA is set
10430b57cec5SDimitry Andric       // in terms of the stack pointer, we need to add a new row of
10440b57cec5SDimitry Andric       // instructions.
10450b57cec5SDimitry Andric       if (fa_value_ptr->GetRegisterNumber() == m_lldb_sp_regnum) {
10460b57cec5SDimitry Andric         fa_value_ptr->SetOffset(current_sp_bytes_offset_from_fa);
10470b57cec5SDimitry Andric         row_updated = true;
10480b57cec5SDimitry Andric       }
10490b57cec5SDimitry Andric       // record where non-volatile (callee-saved, spilled) registers are saved
10500b57cec5SDimitry Andric       // on the stack
10510b57cec5SDimitry Andric       if (nonvolatile_reg_p(machine_regno) &&
10520b57cec5SDimitry Andric           machine_regno_to_lldb_regno(machine_regno, lldb_regno) &&
10530b57cec5SDimitry Andric           !saved_registers[machine_regno]) {
10540b57cec5SDimitry Andric         UnwindPlan::Row::RegisterLocation regloc;
10550b57cec5SDimitry Andric         if (is_aligned)
10560b57cec5SDimitry Andric             regloc.SetAtAFAPlusOffset(-current_sp_bytes_offset_from_fa);
10570b57cec5SDimitry Andric         else
10580b57cec5SDimitry Andric             regloc.SetAtCFAPlusOffset(-current_sp_bytes_offset_from_fa);
10590b57cec5SDimitry Andric         row->SetRegisterInfo(lldb_regno, regloc);
10600b57cec5SDimitry Andric         saved_registers[machine_regno] = true;
10610b57cec5SDimitry Andric         row_updated = true;
10620b57cec5SDimitry Andric       }
10630b57cec5SDimitry Andric     }
10640b57cec5SDimitry Andric 
10650b57cec5SDimitry Andric     else if (pop_reg_p(machine_regno)) {
10660b57cec5SDimitry Andric       current_sp_bytes_offset_from_fa -= m_wordsize;
10670b57cec5SDimitry Andric 
10680b57cec5SDimitry Andric       if (nonvolatile_reg_p(machine_regno) &&
10690b57cec5SDimitry Andric           machine_regno_to_lldb_regno(machine_regno, lldb_regno) &&
10700b57cec5SDimitry Andric           saved_registers[machine_regno]) {
10710b57cec5SDimitry Andric         saved_registers[machine_regno] = false;
10720b57cec5SDimitry Andric         row->RemoveRegisterInfo(lldb_regno);
10730b57cec5SDimitry Andric 
10740b57cec5SDimitry Andric         if (lldb_regno == fa_value_ptr->GetRegisterNumber()) {
10750b57cec5SDimitry Andric           fa_value_ptr->SetIsRegisterPlusOffset(
10760b57cec5SDimitry Andric               m_lldb_sp_regnum, fa_value_ptr->GetOffset());
10770b57cec5SDimitry Andric         }
10780b57cec5SDimitry Andric 
10790b57cec5SDimitry Andric         in_epilogue = true;
10800b57cec5SDimitry Andric         row_updated = true;
10810b57cec5SDimitry Andric       }
10820b57cec5SDimitry Andric 
10830b57cec5SDimitry Andric       // the POP instruction has moved the stack pointer - if the FA is set in
10840b57cec5SDimitry Andric       // terms of the stack pointer, we need to add a new row of instructions.
10850b57cec5SDimitry Andric       if (fa_value_ptr->GetRegisterNumber() == m_lldb_sp_regnum) {
10860b57cec5SDimitry Andric         fa_value_ptr->SetIsRegisterPlusOffset(
10870b57cec5SDimitry Andric             m_lldb_sp_regnum, current_sp_bytes_offset_from_fa);
10880b57cec5SDimitry Andric         row_updated = true;
10890b57cec5SDimitry Andric       }
10900b57cec5SDimitry Andric     }
10910b57cec5SDimitry Andric 
10920b57cec5SDimitry Andric     else if (pop_misc_reg_p()) {
10930b57cec5SDimitry Andric       current_sp_bytes_offset_from_fa -= m_wordsize;
10940b57cec5SDimitry Andric       if (fa_value_ptr->GetRegisterNumber() == m_lldb_sp_regnum) {
10950b57cec5SDimitry Andric         fa_value_ptr->SetIsRegisterPlusOffset(
10960b57cec5SDimitry Andric             m_lldb_sp_regnum, current_sp_bytes_offset_from_fa);
10970b57cec5SDimitry Andric         row_updated = true;
10980b57cec5SDimitry Andric       }
10990b57cec5SDimitry Andric     }
11000b57cec5SDimitry Andric 
11010b57cec5SDimitry Andric     // The LEAVE instruction moves the value from rbp into rsp and pops a value
11020b57cec5SDimitry Andric     // off the stack into rbp (restoring the caller's rbp value). It is the
11030b57cec5SDimitry Andric     // opposite of ENTER, or 'push rbp, mov rsp rbp'.
11040b57cec5SDimitry Andric     else if (leave_pattern_p()) {
11050b57cec5SDimitry Andric       if (saved_registers[m_machine_fp_regnum]) {
11060b57cec5SDimitry Andric         saved_registers[m_machine_fp_regnum] = false;
11070b57cec5SDimitry Andric         row->RemoveRegisterInfo(m_lldb_fp_regnum);
11080b57cec5SDimitry Andric 
11090b57cec5SDimitry Andric         row_updated = true;
11100b57cec5SDimitry Andric       }
11110b57cec5SDimitry Andric 
11120b57cec5SDimitry Andric       if (is_aligned && cfa_value.GetRegisterNumber() == m_lldb_fp_regnum)
11130b57cec5SDimitry Andric       {
11140b57cec5SDimitry Andric         is_aligned = false;
11150b57cec5SDimitry Andric         fa_value_ptr = &cfa_value;
11160b57cec5SDimitry Andric         afa_value.SetUnspecified();
11170b57cec5SDimitry Andric         row_updated = true;
11180b57cec5SDimitry Andric       }
11190b57cec5SDimitry Andric 
11200b57cec5SDimitry Andric       if (fa_value_ptr->GetRegisterNumber() == m_lldb_fp_regnum)
11210b57cec5SDimitry Andric       {
11220b57cec5SDimitry Andric         fa_value_ptr->SetIsRegisterPlusOffset(
11230b57cec5SDimitry Andric             m_lldb_sp_regnum, fa_value_ptr->GetOffset());
11240b57cec5SDimitry Andric 
11250b57cec5SDimitry Andric         current_sp_bytes_offset_from_fa = fa_value_ptr->GetOffset();
11260b57cec5SDimitry Andric       }
11270b57cec5SDimitry Andric 
11280b57cec5SDimitry Andric       current_sp_bytes_offset_from_fa -= m_wordsize;
11290b57cec5SDimitry Andric 
11300b57cec5SDimitry Andric       if (fa_value_ptr->GetRegisterNumber() == m_lldb_sp_regnum) {
11310b57cec5SDimitry Andric         fa_value_ptr->SetIsRegisterPlusOffset(
11320b57cec5SDimitry Andric             m_lldb_sp_regnum, current_sp_bytes_offset_from_fa);
11330b57cec5SDimitry Andric         row_updated = true;
11340b57cec5SDimitry Andric       }
11350b57cec5SDimitry Andric 
11360b57cec5SDimitry Andric       in_epilogue = true;
11370b57cec5SDimitry Andric     }
11380b57cec5SDimitry Andric 
11390b57cec5SDimitry Andric     else if (mov_reg_to_local_stack_frame_p(machine_regno, stack_offset) &&
11400b57cec5SDimitry Andric              nonvolatile_reg_p(machine_regno) &&
11410b57cec5SDimitry Andric              machine_regno_to_lldb_regno(machine_regno, lldb_regno) &&
11420b57cec5SDimitry Andric              !saved_registers[machine_regno]) {
11430b57cec5SDimitry Andric       saved_registers[machine_regno] = true;
11440b57cec5SDimitry Andric 
11450b57cec5SDimitry Andric       UnwindPlan::Row::RegisterLocation regloc;
11460b57cec5SDimitry Andric 
11470b57cec5SDimitry Andric       // stack_offset for 'movq %r15, -80(%rbp)' will be 80. In the Row, we
11480b57cec5SDimitry Andric       // want to express this as the offset from the FA.  If the frame base is
11490b57cec5SDimitry Andric       // rbp (like the above instruction), the FA offset for rbp is probably
11500b57cec5SDimitry Andric       // 16.  So we want to say that the value is stored at the FA address -
11510b57cec5SDimitry Andric       // 96.
11520b57cec5SDimitry Andric       if (is_aligned)
11530b57cec5SDimitry Andric           regloc.SetAtAFAPlusOffset(-(stack_offset + fa_value_ptr->GetOffset()));
11540b57cec5SDimitry Andric       else
11550b57cec5SDimitry Andric           regloc.SetAtCFAPlusOffset(-(stack_offset + fa_value_ptr->GetOffset()));
11560b57cec5SDimitry Andric 
11570b57cec5SDimitry Andric       row->SetRegisterInfo(lldb_regno, regloc);
11580b57cec5SDimitry Andric 
11590b57cec5SDimitry Andric       row_updated = true;
11600b57cec5SDimitry Andric     }
11610b57cec5SDimitry Andric 
11620b57cec5SDimitry Andric     else if (sub_rsp_pattern_p(stack_offset)) {
11630b57cec5SDimitry Andric       current_sp_bytes_offset_from_fa += stack_offset;
11640b57cec5SDimitry Andric       if (fa_value_ptr->GetRegisterNumber() == m_lldb_sp_regnum) {
11650b57cec5SDimitry Andric         fa_value_ptr->SetOffset(current_sp_bytes_offset_from_fa);
11660b57cec5SDimitry Andric         row_updated = true;
11670b57cec5SDimitry Andric       }
11680b57cec5SDimitry Andric     }
11690b57cec5SDimitry Andric 
11700b57cec5SDimitry Andric     else if (add_rsp_pattern_p(stack_offset)) {
11710b57cec5SDimitry Andric       current_sp_bytes_offset_from_fa -= stack_offset;
11720b57cec5SDimitry Andric       if (fa_value_ptr->GetRegisterNumber() == m_lldb_sp_regnum) {
11730b57cec5SDimitry Andric         fa_value_ptr->SetOffset(current_sp_bytes_offset_from_fa);
11740b57cec5SDimitry Andric         row_updated = true;
11750b57cec5SDimitry Andric       }
11760b57cec5SDimitry Andric       in_epilogue = true;
11770b57cec5SDimitry Andric     }
11780b57cec5SDimitry Andric 
11790b57cec5SDimitry Andric     else if (push_extended_pattern_p() || push_imm_pattern_p() ||
11800b57cec5SDimitry Andric              push_misc_reg_p()) {
11810b57cec5SDimitry Andric       current_sp_bytes_offset_from_fa += m_wordsize;
11820b57cec5SDimitry Andric       if (fa_value_ptr->GetRegisterNumber() == m_lldb_sp_regnum) {
11830b57cec5SDimitry Andric         fa_value_ptr->SetOffset(current_sp_bytes_offset_from_fa);
11840b57cec5SDimitry Andric         row_updated = true;
11850b57cec5SDimitry Andric       }
11860b57cec5SDimitry Andric     }
11870b57cec5SDimitry Andric 
11880b57cec5SDimitry Andric     else if (lea_rsp_pattern_p(stack_offset)) {
11890b57cec5SDimitry Andric       current_sp_bytes_offset_from_fa -= stack_offset;
11900b57cec5SDimitry Andric       if (fa_value_ptr->GetRegisterNumber() == m_lldb_sp_regnum) {
11910b57cec5SDimitry Andric         fa_value_ptr->SetOffset(current_sp_bytes_offset_from_fa);
11920b57cec5SDimitry Andric         row_updated = true;
11930b57cec5SDimitry Andric       }
11940b57cec5SDimitry Andric       if (stack_offset > 0)
11950b57cec5SDimitry Andric         in_epilogue = true;
11960b57cec5SDimitry Andric     }
11970b57cec5SDimitry Andric 
11980b57cec5SDimitry Andric     else if (lea_rbp_rsp_pattern_p(stack_offset)) {
11990b57cec5SDimitry Andric       if (is_aligned &&
12000b57cec5SDimitry Andric           cfa_value.GetRegisterNumber() == m_lldb_fp_regnum) {
12010b57cec5SDimitry Andric         is_aligned = false;
12020b57cec5SDimitry Andric         fa_value_ptr = &cfa_value;
12030b57cec5SDimitry Andric         afa_value.SetUnspecified();
12040b57cec5SDimitry Andric         row_updated = true;
12050b57cec5SDimitry Andric       }
12060b57cec5SDimitry Andric       if (fa_value_ptr->GetRegisterNumber() == m_lldb_fp_regnum) {
12070b57cec5SDimitry Andric         current_sp_bytes_offset_from_fa =
12080b57cec5SDimitry Andric           fa_value_ptr->GetOffset() - stack_offset;
12090b57cec5SDimitry Andric       }
12100b57cec5SDimitry Andric     }
12110b57cec5SDimitry Andric 
12120b57cec5SDimitry Andric     else if (lea_rbx_rsp_pattern_p(stack_offset)) {
12130b57cec5SDimitry Andric       if (is_aligned &&
12140b57cec5SDimitry Andric           cfa_value.GetRegisterNumber() == m_lldb_alt_fp_regnum) {
12150b57cec5SDimitry Andric         is_aligned = false;
12160b57cec5SDimitry Andric         fa_value_ptr = &cfa_value;
12170b57cec5SDimitry Andric         afa_value.SetUnspecified();
12180b57cec5SDimitry Andric         row_updated = true;
12190b57cec5SDimitry Andric       }
12200b57cec5SDimitry Andric       if (fa_value_ptr->GetRegisterNumber() == m_lldb_alt_fp_regnum) {
12210b57cec5SDimitry Andric         current_sp_bytes_offset_from_fa = fa_value_ptr->GetOffset() - stack_offset;
12220b57cec5SDimitry Andric       }
12230b57cec5SDimitry Andric     }
12240b57cec5SDimitry Andric 
12250b57cec5SDimitry Andric     else if (prologue_completed_row.get() &&
12260b57cec5SDimitry Andric              (ret_pattern_p() ||
12270b57cec5SDimitry Andric               non_local_branch_p (current_func_text_offset, func_range, insn_len) ||
12280b57cec5SDimitry Andric               jmp_to_reg_p())) {
12290b57cec5SDimitry Andric       // Check if the current instruction is the end of an epilogue sequence,
12300b57cec5SDimitry Andric       // and if so, re-instate the prologue-completed unwind state.
12310b57cec5SDimitry Andric 
12320b57cec5SDimitry Andric       // The current instruction is a branch/jump outside this function,
12330b57cec5SDimitry Andric       // a ret, or a jump through a register value which we cannot
12340b57cec5SDimitry Andric       // determine the effcts of.  Verify that the stack frame state
12350b57cec5SDimitry Andric       // has been unwound to the same as it was at function entry to avoid
12360b57cec5SDimitry Andric       // mis-identifying a JMP instruction as an epilogue.
12370b57cec5SDimitry Andric       UnwindPlan::Row::RegisterLocation sp, pc;
12380b57cec5SDimitry Andric       if (row->GetRegisterInfo(m_lldb_sp_regnum, sp) &&
12390b57cec5SDimitry Andric           row->GetRegisterInfo(m_lldb_ip_regnum, pc)) {
12400b57cec5SDimitry Andric         // Any ret instruction variant is definitely indicative of an
12410b57cec5SDimitry Andric         // epilogue; for other insn patterns verify that we're back to
12420b57cec5SDimitry Andric         // the original unwind state.
12430b57cec5SDimitry Andric         if (ret_pattern_p() ||
12440b57cec5SDimitry Andric             (sp.IsCFAPlusOffset() && sp.GetOffset() == 0 &&
12450b57cec5SDimitry Andric             pc.IsAtCFAPlusOffset() && pc.GetOffset() == -m_wordsize)) {
12460b57cec5SDimitry Andric           // Reinstate the saved prologue setup for any instructions that come
12470b57cec5SDimitry Andric           // after the epilogue
12480b57cec5SDimitry Andric 
12490b57cec5SDimitry Andric           UnwindPlan::Row *newrow = new UnwindPlan::Row;
12500b57cec5SDimitry Andric           *newrow = *prologue_completed_row.get();
12510b57cec5SDimitry Andric           row.reset(newrow);
12520b57cec5SDimitry Andric           current_sp_bytes_offset_from_fa =
12530b57cec5SDimitry Andric               prologue_completed_sp_bytes_offset_from_cfa;
12540b57cec5SDimitry Andric           is_aligned = prologue_completed_is_aligned;
12550b57cec5SDimitry Andric 
12560b57cec5SDimitry Andric           saved_registers.clear();
12570b57cec5SDimitry Andric           saved_registers.resize(prologue_completed_saved_registers.size(), false);
12580b57cec5SDimitry Andric           for (size_t i = 0; i < prologue_completed_saved_registers.size(); ++i) {
12590b57cec5SDimitry Andric             saved_registers[i] = prologue_completed_saved_registers[i];
12600b57cec5SDimitry Andric           }
12610b57cec5SDimitry Andric 
12620b57cec5SDimitry Andric           in_epilogue = true;
12630b57cec5SDimitry Andric           row_updated = true;
12640b57cec5SDimitry Andric         }
12650b57cec5SDimitry Andric       }
12660b57cec5SDimitry Andric     }
12670b57cec5SDimitry Andric 
12680b57cec5SDimitry Andric     // call next instruction
12690b57cec5SDimitry Andric     //     call 0
12700b57cec5SDimitry Andric     //  => pop  %ebx
12710b57cec5SDimitry Andric     // This is used in i386 programs to get the PIC base address for finding
12720b57cec5SDimitry Andric     // global data
12730b57cec5SDimitry Andric     else if (call_next_insn_pattern_p()) {
12740b57cec5SDimitry Andric       current_sp_bytes_offset_from_fa += m_wordsize;
12750b57cec5SDimitry Andric       if (fa_value_ptr->GetRegisterNumber() == m_lldb_sp_regnum) {
12760b57cec5SDimitry Andric         fa_value_ptr->SetOffset(current_sp_bytes_offset_from_fa);
12770b57cec5SDimitry Andric         row_updated = true;
12780b57cec5SDimitry Andric       }
12790b57cec5SDimitry Andric     }
12800b57cec5SDimitry Andric 
12810b57cec5SDimitry Andric     if (row_updated) {
12820b57cec5SDimitry Andric       if (current_func_text_offset + insn_len < size) {
12830b57cec5SDimitry Andric         row->SetOffset(current_func_text_offset + insn_len);
12840b57cec5SDimitry Andric         unwind_plan.AppendRow(row);
12850b57cec5SDimitry Andric         // Allocate a new Row, populate it with the existing Row contents.
12860b57cec5SDimitry Andric         newrow = new UnwindPlan::Row;
12870b57cec5SDimitry Andric         *newrow = *row.get();
12880b57cec5SDimitry Andric         row.reset(newrow);
12890b57cec5SDimitry Andric       }
12900b57cec5SDimitry Andric     }
12910b57cec5SDimitry Andric 
12920b57cec5SDimitry Andric     if (!in_epilogue && row_updated) {
12930b57cec5SDimitry Andric       // If we're not in an epilogue sequence, save the updated Row
12940b57cec5SDimitry Andric       UnwindPlan::Row *newrow = new UnwindPlan::Row;
12950b57cec5SDimitry Andric       *newrow = *row.get();
12960b57cec5SDimitry Andric       prologue_completed_row.reset(newrow);
12970b57cec5SDimitry Andric 
12980b57cec5SDimitry Andric       prologue_completed_saved_registers.clear();
12990b57cec5SDimitry Andric       prologue_completed_saved_registers.resize(saved_registers.size(), false);
13000b57cec5SDimitry Andric       for (size_t i = 0; i < saved_registers.size(); ++i) {
13010b57cec5SDimitry Andric         prologue_completed_saved_registers[i] = saved_registers[i];
13020b57cec5SDimitry Andric       }
13030b57cec5SDimitry Andric     }
13040b57cec5SDimitry Andric 
13050b57cec5SDimitry Andric     // We may change the sp value without adding a new Row necessarily -- keep
13060b57cec5SDimitry Andric     // track of it either way.
13070b57cec5SDimitry Andric     if (!in_epilogue) {
13080b57cec5SDimitry Andric       prologue_completed_sp_bytes_offset_from_cfa =
13090b57cec5SDimitry Andric           current_sp_bytes_offset_from_fa;
13100b57cec5SDimitry Andric       prologue_completed_is_aligned = is_aligned;
13110b57cec5SDimitry Andric     }
13120b57cec5SDimitry Andric 
13130b57cec5SDimitry Andric     m_cur_insn = m_cur_insn + insn_len;
13140b57cec5SDimitry Andric     current_func_text_offset += insn_len;
13150b57cec5SDimitry Andric   }
13160b57cec5SDimitry Andric 
13170b57cec5SDimitry Andric   unwind_plan.SetSourceName("assembly insn profiling");
13180b57cec5SDimitry Andric   unwind_plan.SetSourcedFromCompiler(eLazyBoolNo);
13190b57cec5SDimitry Andric   unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolYes);
13209dba64beSDimitry Andric   unwind_plan.SetUnwindPlanForSignalTrap(eLazyBoolNo);
13210b57cec5SDimitry Andric 
13220b57cec5SDimitry Andric   return true;
13230b57cec5SDimitry Andric }
13240b57cec5SDimitry Andric 
13250b57cec5SDimitry Andric bool x86AssemblyInspectionEngine::AugmentUnwindPlanFromCallSite(
13260b57cec5SDimitry Andric     uint8_t *data, size_t size, AddressRange &func_range,
13270b57cec5SDimitry Andric     UnwindPlan &unwind_plan, RegisterContextSP &reg_ctx) {
13280b57cec5SDimitry Andric   Address addr_start = func_range.GetBaseAddress();
13290b57cec5SDimitry Andric   if (!addr_start.IsValid())
13300b57cec5SDimitry Andric     return false;
13310b57cec5SDimitry Andric 
13320b57cec5SDimitry Andric   // We either need a live RegisterContext, or we need the UnwindPlan to
13330b57cec5SDimitry Andric   // already be in the lldb register numbering scheme.
13340b57cec5SDimitry Andric   if (reg_ctx.get() == nullptr &&
13350b57cec5SDimitry Andric       unwind_plan.GetRegisterKind() != eRegisterKindLLDB)
13360b57cec5SDimitry Andric     return false;
13370b57cec5SDimitry Andric 
13380b57cec5SDimitry Andric   // Is original unwind_plan valid?
13390b57cec5SDimitry Andric   // unwind_plan should have at least one row which is ABI-default (CFA
13400b57cec5SDimitry Andric   // register is sp), and another row in mid-function.
13410b57cec5SDimitry Andric   if (unwind_plan.GetRowCount() < 2)
13420b57cec5SDimitry Andric     return false;
13430b57cec5SDimitry Andric 
13440b57cec5SDimitry Andric   UnwindPlan::RowSP first_row = unwind_plan.GetRowAtIndex(0);
13450b57cec5SDimitry Andric   if (first_row->GetOffset() != 0)
13460b57cec5SDimitry Andric     return false;
13470b57cec5SDimitry Andric   uint32_t cfa_reg = first_row->GetCFAValue().GetRegisterNumber();
13480b57cec5SDimitry Andric   if (unwind_plan.GetRegisterKind() != eRegisterKindLLDB) {
13490b57cec5SDimitry Andric     cfa_reg = reg_ctx->ConvertRegisterKindToRegisterNumber(
13500b57cec5SDimitry Andric         unwind_plan.GetRegisterKind(),
13510b57cec5SDimitry Andric         first_row->GetCFAValue().GetRegisterNumber());
13520b57cec5SDimitry Andric   }
13530b57cec5SDimitry Andric   if (cfa_reg != m_lldb_sp_regnum ||
13540b57cec5SDimitry Andric       first_row->GetCFAValue().GetOffset() != m_wordsize)
13550b57cec5SDimitry Andric     return false;
13560b57cec5SDimitry Andric 
13570b57cec5SDimitry Andric   UnwindPlan::RowSP original_last_row = unwind_plan.GetRowForFunctionOffset(-1);
13580b57cec5SDimitry Andric 
13590b57cec5SDimitry Andric   size_t offset = 0;
13600b57cec5SDimitry Andric   int row_id = 1;
13610b57cec5SDimitry Andric   bool unwind_plan_updated = false;
13620b57cec5SDimitry Andric   UnwindPlan::RowSP row(new UnwindPlan::Row(*first_row));
13630b57cec5SDimitry Andric 
13640b57cec5SDimitry Andric   // After a mid-function epilogue we will need to re-insert the original
13650b57cec5SDimitry Andric   // unwind rules so unwinds work for the remainder of the function.  These
13660b57cec5SDimitry Andric   // aren't common with clang/gcc on x86 but it is possible.
13670b57cec5SDimitry Andric   bool reinstate_unwind_state = false;
13680b57cec5SDimitry Andric 
13690b57cec5SDimitry Andric   while (offset < size) {
13700b57cec5SDimitry Andric     m_cur_insn = data + offset;
13710b57cec5SDimitry Andric     int insn_len;
13729dba64beSDimitry Andric     if (!instruction_length(m_cur_insn, insn_len, size - offset) ||
13739dba64beSDimitry Andric         insn_len == 0 || insn_len > kMaxInstructionByteSize) {
13740b57cec5SDimitry Andric       // An unrecognized/junk instruction.
13750b57cec5SDimitry Andric       break;
13760b57cec5SDimitry Andric     }
13770b57cec5SDimitry Andric 
13780b57cec5SDimitry Andric     // Advance offsets.
13790b57cec5SDimitry Andric     offset += insn_len;
13800b57cec5SDimitry Andric 
13810b57cec5SDimitry Andric     // offset is pointing beyond the bounds of the function; stop looping.
13820b57cec5SDimitry Andric     if (offset >= size)
13830b57cec5SDimitry Andric       continue;
13840b57cec5SDimitry Andric 
13850b57cec5SDimitry Andric     if (reinstate_unwind_state) {
13860b57cec5SDimitry Andric       UnwindPlan::RowSP new_row(new UnwindPlan::Row());
13870b57cec5SDimitry Andric       *new_row = *original_last_row;
13880b57cec5SDimitry Andric       new_row->SetOffset(offset);
13890b57cec5SDimitry Andric       unwind_plan.AppendRow(new_row);
13900b57cec5SDimitry Andric       row = std::make_shared<UnwindPlan::Row>();
13910b57cec5SDimitry Andric       *row = *new_row;
13920b57cec5SDimitry Andric       reinstate_unwind_state = false;
13930b57cec5SDimitry Andric       unwind_plan_updated = true;
13940b57cec5SDimitry Andric       continue;
13950b57cec5SDimitry Andric     }
13960b57cec5SDimitry Andric 
13970b57cec5SDimitry Andric     // If we already have one row for this instruction, we can continue.
13980b57cec5SDimitry Andric     while (row_id < unwind_plan.GetRowCount() &&
13990b57cec5SDimitry Andric            unwind_plan.GetRowAtIndex(row_id)->GetOffset() <= offset) {
14000b57cec5SDimitry Andric       row_id++;
14010b57cec5SDimitry Andric     }
14020b57cec5SDimitry Andric     UnwindPlan::RowSP original_row = unwind_plan.GetRowAtIndex(row_id - 1);
14030b57cec5SDimitry Andric     if (original_row->GetOffset() == offset) {
14040b57cec5SDimitry Andric       *row = *original_row;
14050b57cec5SDimitry Andric       continue;
14060b57cec5SDimitry Andric     }
14070b57cec5SDimitry Andric 
14080b57cec5SDimitry Andric     if (row_id == 0) {
14090b57cec5SDimitry Andric       // If we are here, compiler didn't generate CFI for prologue. This won't
14100b57cec5SDimitry Andric       // happen to GCC or clang. In this case, bail out directly.
14110b57cec5SDimitry Andric       return false;
14120b57cec5SDimitry Andric     }
14130b57cec5SDimitry Andric 
14140b57cec5SDimitry Andric     // Inspect the instruction to check if we need a new row for it.
14150b57cec5SDimitry Andric     cfa_reg = row->GetCFAValue().GetRegisterNumber();
14160b57cec5SDimitry Andric     if (unwind_plan.GetRegisterKind() != eRegisterKindLLDB) {
14170b57cec5SDimitry Andric       cfa_reg = reg_ctx->ConvertRegisterKindToRegisterNumber(
14180b57cec5SDimitry Andric           unwind_plan.GetRegisterKind(),
14190b57cec5SDimitry Andric           row->GetCFAValue().GetRegisterNumber());
14200b57cec5SDimitry Andric     }
14210b57cec5SDimitry Andric     if (cfa_reg == m_lldb_sp_regnum) {
14220b57cec5SDimitry Andric       // CFA register is sp.
14230b57cec5SDimitry Andric 
14240b57cec5SDimitry Andric       // call next instruction
14250b57cec5SDimitry Andric       //     call 0
14260b57cec5SDimitry Andric       //  => pop  %ebx
14270b57cec5SDimitry Andric       if (call_next_insn_pattern_p()) {
14280b57cec5SDimitry Andric         row->SetOffset(offset);
14290b57cec5SDimitry Andric         row->GetCFAValue().IncOffset(m_wordsize);
14300b57cec5SDimitry Andric 
14310b57cec5SDimitry Andric         UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row));
14320b57cec5SDimitry Andric         unwind_plan.InsertRow(new_row);
14330b57cec5SDimitry Andric         unwind_plan_updated = true;
14340b57cec5SDimitry Andric         continue;
14350b57cec5SDimitry Andric       }
14360b57cec5SDimitry Andric 
14370b57cec5SDimitry Andric       // push/pop register
14380b57cec5SDimitry Andric       int regno;
14390b57cec5SDimitry Andric       if (push_reg_p(regno)) {
14400b57cec5SDimitry Andric         row->SetOffset(offset);
14410b57cec5SDimitry Andric         row->GetCFAValue().IncOffset(m_wordsize);
14420b57cec5SDimitry Andric 
14430b57cec5SDimitry Andric         UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row));
14440b57cec5SDimitry Andric         unwind_plan.InsertRow(new_row);
14450b57cec5SDimitry Andric         unwind_plan_updated = true;
14460b57cec5SDimitry Andric         continue;
14470b57cec5SDimitry Andric       }
14480b57cec5SDimitry Andric       if (pop_reg_p(regno)) {
14490b57cec5SDimitry Andric         // Technically, this might be a nonvolatile register recover in
14500b57cec5SDimitry Andric         // epilogue. We should reset RegisterInfo for the register. But in
14510b57cec5SDimitry Andric         // practice, previous rule for the register is still valid... So we
14520b57cec5SDimitry Andric         // ignore this case.
14530b57cec5SDimitry Andric 
14540b57cec5SDimitry Andric         row->SetOffset(offset);
14550b57cec5SDimitry Andric         row->GetCFAValue().IncOffset(-m_wordsize);
14560b57cec5SDimitry Andric 
14570b57cec5SDimitry Andric         UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row));
14580b57cec5SDimitry Andric         unwind_plan.InsertRow(new_row);
14590b57cec5SDimitry Andric         unwind_plan_updated = true;
14600b57cec5SDimitry Andric         continue;
14610b57cec5SDimitry Andric       }
14620b57cec5SDimitry Andric 
14630b57cec5SDimitry Andric       if (pop_misc_reg_p()) {
14640b57cec5SDimitry Andric         row->SetOffset(offset);
14650b57cec5SDimitry Andric         row->GetCFAValue().IncOffset(-m_wordsize);
14660b57cec5SDimitry Andric 
14670b57cec5SDimitry Andric         UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row));
14680b57cec5SDimitry Andric         unwind_plan.InsertRow(new_row);
14690b57cec5SDimitry Andric         unwind_plan_updated = true;
14700b57cec5SDimitry Andric         continue;
14710b57cec5SDimitry Andric       }
14720b57cec5SDimitry Andric 
14730b57cec5SDimitry Andric       // push imm
14740b57cec5SDimitry Andric       if (push_imm_pattern_p()) {
14750b57cec5SDimitry Andric         row->SetOffset(offset);
14760b57cec5SDimitry Andric         row->GetCFAValue().IncOffset(m_wordsize);
14770b57cec5SDimitry Andric         UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row));
14780b57cec5SDimitry Andric         unwind_plan.InsertRow(new_row);
14790b57cec5SDimitry Andric         unwind_plan_updated = true;
14800b57cec5SDimitry Andric         continue;
14810b57cec5SDimitry Andric       }
14820b57cec5SDimitry Andric 
14830b57cec5SDimitry Andric       // push extended
14840b57cec5SDimitry Andric       if (push_extended_pattern_p() || push_misc_reg_p()) {
14850b57cec5SDimitry Andric         row->SetOffset(offset);
14860b57cec5SDimitry Andric         row->GetCFAValue().IncOffset(m_wordsize);
14870b57cec5SDimitry Andric         UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row));
14880b57cec5SDimitry Andric         unwind_plan.InsertRow(new_row);
14890b57cec5SDimitry Andric         unwind_plan_updated = true;
14900b57cec5SDimitry Andric         continue;
14910b57cec5SDimitry Andric       }
14920b57cec5SDimitry Andric 
14930b57cec5SDimitry Andric       // add/sub %rsp/%esp
14940b57cec5SDimitry Andric       int amount;
14950b57cec5SDimitry Andric       if (add_rsp_pattern_p(amount)) {
14960b57cec5SDimitry Andric         row->SetOffset(offset);
14970b57cec5SDimitry Andric         row->GetCFAValue().IncOffset(-amount);
14980b57cec5SDimitry Andric 
14990b57cec5SDimitry Andric         UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row));
15000b57cec5SDimitry Andric         unwind_plan.InsertRow(new_row);
15010b57cec5SDimitry Andric         unwind_plan_updated = true;
15020b57cec5SDimitry Andric         continue;
15030b57cec5SDimitry Andric       }
15040b57cec5SDimitry Andric       if (sub_rsp_pattern_p(amount)) {
15050b57cec5SDimitry Andric         row->SetOffset(offset);
15060b57cec5SDimitry Andric         row->GetCFAValue().IncOffset(amount);
15070b57cec5SDimitry Andric 
15080b57cec5SDimitry Andric         UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row));
15090b57cec5SDimitry Andric         unwind_plan.InsertRow(new_row);
15100b57cec5SDimitry Andric         unwind_plan_updated = true;
15110b57cec5SDimitry Andric         continue;
15120b57cec5SDimitry Andric       }
15130b57cec5SDimitry Andric 
15140b57cec5SDimitry Andric       // lea %rsp, [%rsp + $offset]
15150b57cec5SDimitry Andric       if (lea_rsp_pattern_p(amount)) {
15160b57cec5SDimitry Andric         row->SetOffset(offset);
15170b57cec5SDimitry Andric         row->GetCFAValue().IncOffset(-amount);
15180b57cec5SDimitry Andric 
15190b57cec5SDimitry Andric         UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row));
15200b57cec5SDimitry Andric         unwind_plan.InsertRow(new_row);
15210b57cec5SDimitry Andric         unwind_plan_updated = true;
15220b57cec5SDimitry Andric         continue;
15230b57cec5SDimitry Andric       }
15240b57cec5SDimitry Andric 
15250b57cec5SDimitry Andric       if (ret_pattern_p()) {
15260b57cec5SDimitry Andric         reinstate_unwind_state = true;
15270b57cec5SDimitry Andric         continue;
15280b57cec5SDimitry Andric       }
15290b57cec5SDimitry Andric     } else if (cfa_reg == m_lldb_fp_regnum) {
15300b57cec5SDimitry Andric       // CFA register is fp.
15310b57cec5SDimitry Andric 
15320b57cec5SDimitry Andric       // The only case we care about is epilogue:
15330b57cec5SDimitry Andric       //     [0x5d] pop %rbp/%ebp
15340b57cec5SDimitry Andric       //  => [0xc3] ret
15350b57cec5SDimitry Andric       if (pop_rbp_pattern_p() || leave_pattern_p()) {
15369dba64beSDimitry Andric         m_cur_insn++;
15379dba64beSDimitry Andric         if (ret_pattern_p()) {
15380b57cec5SDimitry Andric           row->SetOffset(offset);
15390b57cec5SDimitry Andric           row->GetCFAValue().SetIsRegisterPlusOffset(
15400b57cec5SDimitry Andric               first_row->GetCFAValue().GetRegisterNumber(), m_wordsize);
15410b57cec5SDimitry Andric 
15420b57cec5SDimitry Andric           UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row));
15430b57cec5SDimitry Andric           unwind_plan.InsertRow(new_row);
15440b57cec5SDimitry Andric           unwind_plan_updated = true;
15450b57cec5SDimitry Andric           reinstate_unwind_state = true;
15460b57cec5SDimitry Andric           continue;
15470b57cec5SDimitry Andric         }
15489dba64beSDimitry Andric       }
15490b57cec5SDimitry Andric     } else {
15500b57cec5SDimitry Andric       // CFA register is not sp or fp.
15510b57cec5SDimitry Andric 
15520b57cec5SDimitry Andric       // This must be hand-written assembly.
15530b57cec5SDimitry Andric       // Just trust eh_frame and assume we have finished.
15540b57cec5SDimitry Andric       break;
15550b57cec5SDimitry Andric     }
15560b57cec5SDimitry Andric   }
15570b57cec5SDimitry Andric 
15580b57cec5SDimitry Andric   unwind_plan.SetPlanValidAddressRange(func_range);
15590b57cec5SDimitry Andric   if (unwind_plan_updated) {
15600b57cec5SDimitry Andric     std::string unwind_plan_source(unwind_plan.GetSourceName().AsCString());
15610b57cec5SDimitry Andric     unwind_plan_source += " plus augmentation from assembly parsing";
15620b57cec5SDimitry Andric     unwind_plan.SetSourceName(unwind_plan_source.c_str());
15630b57cec5SDimitry Andric     unwind_plan.SetSourcedFromCompiler(eLazyBoolNo);
15640b57cec5SDimitry Andric     unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolYes);
15650b57cec5SDimitry Andric   }
15660b57cec5SDimitry Andric   return true;
15670b57cec5SDimitry Andric }
15680b57cec5SDimitry Andric 
15690b57cec5SDimitry Andric bool x86AssemblyInspectionEngine::FindFirstNonPrologueInstruction(
15700b57cec5SDimitry Andric     uint8_t *data, size_t size, size_t &offset) {
15710b57cec5SDimitry Andric   offset = 0;
15720b57cec5SDimitry Andric 
15730b57cec5SDimitry Andric   if (!m_register_map_initialized)
15740b57cec5SDimitry Andric     return false;
15750b57cec5SDimitry Andric 
1576*0fca6ea1SDimitry Andric   if (m_disasm_context == nullptr)
1577*0fca6ea1SDimitry Andric     return false;
1578*0fca6ea1SDimitry Andric 
15790b57cec5SDimitry Andric   while (offset < size) {
15800b57cec5SDimitry Andric     int regno;
15810b57cec5SDimitry Andric     int insn_len;
15820b57cec5SDimitry Andric     int scratch;
15830b57cec5SDimitry Andric 
15840b57cec5SDimitry Andric     m_cur_insn = data + offset;
15850b57cec5SDimitry Andric     if (!instruction_length(m_cur_insn, insn_len, size - offset)
15860b57cec5SDimitry Andric         || insn_len > kMaxInstructionByteSize
15870b57cec5SDimitry Andric         || insn_len == 0) {
15880b57cec5SDimitry Andric       // An error parsing the instruction, i.e. probably data/garbage - stop
15890b57cec5SDimitry Andric       // scanning
15900b57cec5SDimitry Andric       break;
15910b57cec5SDimitry Andric     }
15920b57cec5SDimitry Andric 
15930b57cec5SDimitry Andric     if (push_rbp_pattern_p() || mov_rsp_rbp_pattern_p() ||
15940b57cec5SDimitry Andric         sub_rsp_pattern_p(scratch) || push_reg_p(regno) ||
15950b57cec5SDimitry Andric         mov_reg_to_local_stack_frame_p(regno, scratch) ||
15960b57cec5SDimitry Andric         (lea_rsp_pattern_p(scratch) && offset == 0)) {
15970b57cec5SDimitry Andric       offset += insn_len;
15980b57cec5SDimitry Andric       continue;
15990b57cec5SDimitry Andric     }
16000b57cec5SDimitry Andric     //
16010b57cec5SDimitry Andric     // Unknown non-prologue instruction - stop scanning
16020b57cec5SDimitry Andric     break;
16030b57cec5SDimitry Andric   }
16040b57cec5SDimitry Andric 
16050b57cec5SDimitry Andric   return true;
16060b57cec5SDimitry Andric }
1607