brintos

brintos / llvm-project-archived public Read only

0
0
Text · 48.7 KiB · 19e8b57 Raw
1591 lines · cpp
1//===-- x86AssemblyInspectionEngine.cpp -----------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "x86AssemblyInspectionEngine.h"10 11#include <memory>12 13#include "llvm-c/Disassembler.h"14 15#include "lldb/Core/Address.h"16#include "lldb/Symbol/UnwindPlan.h"17#include "lldb/Target/RegisterContext.h"18#include "lldb/Target/UnwindAssembly.h"19 20using namespace lldb_private;21using namespace lldb;22 23x86AssemblyInspectionEngine::x86AssemblyInspectionEngine(const ArchSpec &arch)24    : m_cur_insn(nullptr), m_machine_ip_regnum(LLDB_INVALID_REGNUM),25      m_machine_sp_regnum(LLDB_INVALID_REGNUM),26      m_machine_fp_regnum(LLDB_INVALID_REGNUM),27      m_machine_alt_fp_regnum(LLDB_INVALID_REGNUM),28      m_lldb_ip_regnum(LLDB_INVALID_REGNUM),29      m_lldb_sp_regnum(LLDB_INVALID_REGNUM),30      m_lldb_fp_regnum(LLDB_INVALID_REGNUM),31      m_lldb_alt_fp_regnum(LLDB_INVALID_REGNUM), m_reg_map(), m_arch(arch),32      m_cpu(k_cpu_unspecified), m_wordsize(-1),33      m_register_map_initialized(false), m_disasm_context() {34  m_disasm_context =35      ::LLVMCreateDisasm(arch.GetTriple().getTriple().c_str(), nullptr,36                         /*TagType=*/1, nullptr, nullptr);37}38 39x86AssemblyInspectionEngine::~x86AssemblyInspectionEngine() {40  ::LLVMDisasmDispose(m_disasm_context);41}42 43void x86AssemblyInspectionEngine::Initialize(RegisterContextSP &reg_ctx) {44  m_cpu = k_cpu_unspecified;45  m_wordsize = -1;46  m_register_map_initialized = false;47 48  const llvm::Triple::ArchType cpu = m_arch.GetMachine();49  if (cpu == llvm::Triple::x86)50    m_cpu = k_i386;51  else if (cpu == llvm::Triple::x86_64)52    m_cpu = k_x86_64;53 54  if (m_cpu == k_cpu_unspecified)55    return;56 57  if (reg_ctx.get() == nullptr)58    return;59 60  if (m_cpu == k_i386) {61    m_machine_ip_regnum = k_machine_eip;62    m_machine_sp_regnum = k_machine_esp;63    m_machine_fp_regnum = k_machine_ebp;64    m_machine_alt_fp_regnum = k_machine_ebx;65    m_wordsize = 4;66 67    struct lldb_reg_info reginfo;68    reginfo.name = "eax";69    m_reg_map[k_machine_eax] = reginfo;70    reginfo.name = "edx";71    m_reg_map[k_machine_edx] = reginfo;72    reginfo.name = "esp";73    m_reg_map[k_machine_esp] = reginfo;74    reginfo.name = "esi";75    m_reg_map[k_machine_esi] = reginfo;76    reginfo.name = "eip";77    m_reg_map[k_machine_eip] = reginfo;78    reginfo.name = "ecx";79    m_reg_map[k_machine_ecx] = reginfo;80    reginfo.name = "ebx";81    m_reg_map[k_machine_ebx] = reginfo;82    reginfo.name = "ebp";83    m_reg_map[k_machine_ebp] = reginfo;84    reginfo.name = "edi";85    m_reg_map[k_machine_edi] = reginfo;86  } else {87    m_machine_ip_regnum = k_machine_rip;88    m_machine_sp_regnum = k_machine_rsp;89    m_machine_fp_regnum = k_machine_rbp;90    m_machine_alt_fp_regnum = k_machine_rbx;91    m_wordsize = 8;92 93    struct lldb_reg_info reginfo;94    reginfo.name = "rax";95    m_reg_map[k_machine_rax] = reginfo;96    reginfo.name = "rdx";97    m_reg_map[k_machine_rdx] = reginfo;98    reginfo.name = "rsp";99    m_reg_map[k_machine_rsp] = reginfo;100    reginfo.name = "rsi";101    m_reg_map[k_machine_rsi] = reginfo;102    reginfo.name = "r8";103    m_reg_map[k_machine_r8] = reginfo;104    reginfo.name = "r10";105    m_reg_map[k_machine_r10] = reginfo;106    reginfo.name = "r12";107    m_reg_map[k_machine_r12] = reginfo;108    reginfo.name = "r14";109    m_reg_map[k_machine_r14] = reginfo;110    reginfo.name = "rip";111    m_reg_map[k_machine_rip] = reginfo;112    reginfo.name = "rcx";113    m_reg_map[k_machine_rcx] = reginfo;114    reginfo.name = "rbx";115    m_reg_map[k_machine_rbx] = reginfo;116    reginfo.name = "rbp";117    m_reg_map[k_machine_rbp] = reginfo;118    reginfo.name = "rdi";119    m_reg_map[k_machine_rdi] = reginfo;120    reginfo.name = "r9";121    m_reg_map[k_machine_r9] = reginfo;122    reginfo.name = "r11";123    m_reg_map[k_machine_r11] = reginfo;124    reginfo.name = "r13";125    m_reg_map[k_machine_r13] = reginfo;126    reginfo.name = "r15";127    m_reg_map[k_machine_r15] = reginfo;128  }129 130  for (MachineRegnumToNameAndLLDBRegnum::iterator it = m_reg_map.begin();131       it != m_reg_map.end(); ++it) {132    const RegisterInfo *ri = reg_ctx->GetRegisterInfoByName(it->second.name);133    if (ri)134      it->second.lldb_regnum = ri->kinds[eRegisterKindLLDB];135  }136 137  uint32_t lldb_regno;138  if (machine_regno_to_lldb_regno(m_machine_sp_regnum, lldb_regno))139    m_lldb_sp_regnum = lldb_regno;140  if (machine_regno_to_lldb_regno(m_machine_fp_regnum, lldb_regno))141    m_lldb_fp_regnum = lldb_regno;142  if (machine_regno_to_lldb_regno(m_machine_alt_fp_regnum, lldb_regno))143    m_lldb_alt_fp_regnum = lldb_regno;144  if (machine_regno_to_lldb_regno(m_machine_ip_regnum, lldb_regno))145    m_lldb_ip_regnum = lldb_regno;146 147  m_register_map_initialized = true;148}149 150void x86AssemblyInspectionEngine::Initialize(151    std::vector<lldb_reg_info> &reg_info) {152  m_cpu = k_cpu_unspecified;153  m_wordsize = -1;154  m_register_map_initialized = false;155 156  const llvm::Triple::ArchType cpu = m_arch.GetMachine();157  if (cpu == llvm::Triple::x86)158    m_cpu = k_i386;159  else if (cpu == llvm::Triple::x86_64)160    m_cpu = k_x86_64;161 162  if (m_cpu == k_cpu_unspecified)163    return;164 165  if (m_cpu == k_i386) {166    m_machine_ip_regnum = k_machine_eip;167    m_machine_sp_regnum = k_machine_esp;168    m_machine_fp_regnum = k_machine_ebp;169    m_machine_alt_fp_regnum = k_machine_ebx;170    m_wordsize = 4;171 172    struct lldb_reg_info reginfo;173    reginfo.name = "eax";174    m_reg_map[k_machine_eax] = reginfo;175    reginfo.name = "edx";176    m_reg_map[k_machine_edx] = reginfo;177    reginfo.name = "esp";178    m_reg_map[k_machine_esp] = reginfo;179    reginfo.name = "esi";180    m_reg_map[k_machine_esi] = reginfo;181    reginfo.name = "eip";182    m_reg_map[k_machine_eip] = reginfo;183    reginfo.name = "ecx";184    m_reg_map[k_machine_ecx] = reginfo;185    reginfo.name = "ebx";186    m_reg_map[k_machine_ebx] = reginfo;187    reginfo.name = "ebp";188    m_reg_map[k_machine_ebp] = reginfo;189    reginfo.name = "edi";190    m_reg_map[k_machine_edi] = reginfo;191  } else {192    m_machine_ip_regnum = k_machine_rip;193    m_machine_sp_regnum = k_machine_rsp;194    m_machine_fp_regnum = k_machine_rbp;195    m_machine_alt_fp_regnum = k_machine_rbx;196    m_wordsize = 8;197 198    struct lldb_reg_info reginfo;199    reginfo.name = "rax";200    m_reg_map[k_machine_rax] = reginfo;201    reginfo.name = "rdx";202    m_reg_map[k_machine_rdx] = reginfo;203    reginfo.name = "rsp";204    m_reg_map[k_machine_rsp] = reginfo;205    reginfo.name = "rsi";206    m_reg_map[k_machine_rsi] = reginfo;207    reginfo.name = "r8";208    m_reg_map[k_machine_r8] = reginfo;209    reginfo.name = "r10";210    m_reg_map[k_machine_r10] = reginfo;211    reginfo.name = "r12";212    m_reg_map[k_machine_r12] = reginfo;213    reginfo.name = "r14";214    m_reg_map[k_machine_r14] = reginfo;215    reginfo.name = "rip";216    m_reg_map[k_machine_rip] = reginfo;217    reginfo.name = "rcx";218    m_reg_map[k_machine_rcx] = reginfo;219    reginfo.name = "rbx";220    m_reg_map[k_machine_rbx] = reginfo;221    reginfo.name = "rbp";222    m_reg_map[k_machine_rbp] = reginfo;223    reginfo.name = "rdi";224    m_reg_map[k_machine_rdi] = reginfo;225    reginfo.name = "r9";226    m_reg_map[k_machine_r9] = reginfo;227    reginfo.name = "r11";228    m_reg_map[k_machine_r11] = reginfo;229    reginfo.name = "r13";230    m_reg_map[k_machine_r13] = reginfo;231    reginfo.name = "r15";232    m_reg_map[k_machine_r15] = reginfo;233  }234 235  for (MachineRegnumToNameAndLLDBRegnum::iterator it = m_reg_map.begin();236       it != m_reg_map.end(); ++it) {237    for (size_t i = 0; i < reg_info.size(); ++i) {238      if (::strcmp(reg_info[i].name, it->second.name) == 0) {239        it->second.lldb_regnum = reg_info[i].lldb_regnum;240        break;241      }242    }243  }244 245  uint32_t lldb_regno;246  if (machine_regno_to_lldb_regno(m_machine_sp_regnum, lldb_regno))247    m_lldb_sp_regnum = lldb_regno;248  if (machine_regno_to_lldb_regno(m_machine_fp_regnum, lldb_regno))249    m_lldb_fp_regnum = lldb_regno;250  if (machine_regno_to_lldb_regno(m_machine_alt_fp_regnum, lldb_regno))251    m_lldb_alt_fp_regnum = lldb_regno;252  if (machine_regno_to_lldb_regno(m_machine_ip_regnum, lldb_regno))253    m_lldb_ip_regnum = lldb_regno;254 255  m_register_map_initialized = true;256}257 258// This function expects an x86 native register number (i.e. the bits stripped259// out of the actual instruction), not an lldb register number.260//261// FIXME: This is ABI dependent, it shouldn't be hardcoded here.262 263bool x86AssemblyInspectionEngine::nonvolatile_reg_p(int machine_regno) {264  if (m_cpu == k_i386) {265    switch (machine_regno) {266    case k_machine_ebx:267    case k_machine_ebp: // not actually a nonvolatile but often treated as such268                        // by convention269    case k_machine_esi:270    case k_machine_edi:271    case k_machine_esp:272      return true;273    default:274      return false;275    }276  }277  if (m_cpu == k_x86_64) {278    switch (machine_regno) {279    case k_machine_rbx:280    case k_machine_rsp:281    case k_machine_rbp: // not actually a nonvolatile but often treated as such282                        // by convention283    case k_machine_r12:284    case k_machine_r13:285    case k_machine_r14:286    case k_machine_r15:287      return true;288    default:289      return false;290    }291  }292  return false;293}294 295// Macro to detect if this is a REX mode prefix byte.296#define REX_W_PREFIX_P(opcode) (((opcode) & (~0x5)) == 0x48)297 298// The high bit which should be added to the source register number (the "R"299// bit)300#define REX_W_SRCREG(opcode) (((opcode)&0x4) >> 2)301 302// The high bit which should be added to the destination register number (the303// "B" bit)304#define REX_W_DSTREG(opcode) ((opcode)&0x1)305 306// pushq %rbp [0x55]307bool x86AssemblyInspectionEngine::push_rbp_pattern_p() {308  uint8_t *p = m_cur_insn;309  return *p == 0x55;310}311 312// pushq $0 ; the first instruction in start() [0x6a 0x00]313bool x86AssemblyInspectionEngine::push_0_pattern_p() {314  uint8_t *p = m_cur_insn;315  return *p == 0x6a && *(p + 1) == 0x0;316}317 318// pushq $0319// pushl $0320bool x86AssemblyInspectionEngine::push_imm_pattern_p() {321  uint8_t *p = m_cur_insn;322  return *p == 0x68 || *p == 0x6a;323}324 325// pushl imm8(%esp)326//327// e.g. 0xff 0x74 0x24 0x20 - 'pushl 0x20(%esp)' (same byte pattern for 'pushq328// 0x20(%rsp)' in an x86_64 program)329//330// 0xff (with opcode bits '6' in next byte, PUSH r/m32) 0x74 (ModR/M byte with331// three bits used to specify the opcode)332//      mod == b01, opcode == b110, R/M == b100333//      "+disp8"334// 0x24 (SIB byte - scaled index = 0, r32 == esp) 0x20 imm8 value335 336bool x86AssemblyInspectionEngine::push_extended_pattern_p() {337  if (*m_cur_insn == 0xff) {338    // Get the 3 opcode bits from the ModR/M byte339    uint8_t opcode = (*(m_cur_insn + 1) >> 3) & 7;340    if (opcode == 6) {341      // I'm only looking for 0xff /6 here - I342      // don't really care what value is being pushed, just that we're pushing343      // a 32/64 bit value on to the stack is enough.344      return true;345    }346  }347  return false;348}349 350// instructions only valid in 32-bit mode:351// 0x0e - push cs352// 0x16 - push ss353// 0x1e - push ds354// 0x06 - push es355bool x86AssemblyInspectionEngine::push_misc_reg_p() {356  uint8_t p = *m_cur_insn;357  if (m_wordsize == 4) {358    if (p == 0x0e || p == 0x16 || p == 0x1e || p == 0x06)359      return true;360  }361  return false;362}363 364// pushq %rbx365// pushl %ebx366bool x86AssemblyInspectionEngine::push_reg_p(int &regno) {367  uint8_t *p = m_cur_insn;368  int regno_prefix_bit = 0;369  // If we have a rex prefix byte, check to see if a B bit is set370  if (m_wordsize == 8 && (*p & 0xfe) == 0x40) {371    regno_prefix_bit = (*p & 1) << 3;372    p++;373  }374  if (*p >= 0x50 && *p <= 0x57) {375    regno = (*p - 0x50) | regno_prefix_bit;376    return true;377  }378  return false;379}380 381// movq %rsp, %rbp [0x48 0x8b 0xec] or [0x48 0x89 0xe5] movl %esp, %ebp [0x8b382// 0xec] or [0x89 0xe5]383bool x86AssemblyInspectionEngine::mov_rsp_rbp_pattern_p() {384  uint8_t *p = m_cur_insn;385  if (m_wordsize == 8 && *p == 0x48)386    p++;387  if (*(p) == 0x8b && *(p + 1) == 0xec)388    return true;389  if (*(p) == 0x89 && *(p + 1) == 0xe5)390    return true;391  return false;392}393 394// movq %rsp, %rbx [0x48 0x8b 0xdc] or [0x48 0x89 0xe3]395// movl %esp, %ebx [0x8b 0xdc] or [0x89 0xe3]396bool x86AssemblyInspectionEngine::mov_rsp_rbx_pattern_p() {397  uint8_t *p = m_cur_insn;398  if (m_wordsize == 8 && *p == 0x48)399    p++;400  if (*(p) == 0x8b && *(p + 1) == 0xdc)401    return true;402  if (*(p) == 0x89 && *(p + 1) == 0xe3)403    return true;404  return false;405}406 407// movq %rbp, %rsp [0x48 0x8b 0xe5] or [0x48 0x89 0xec]408// movl %ebp, %esp [0x8b 0xe5] or [0x89 0xec]409bool x86AssemblyInspectionEngine::mov_rbp_rsp_pattern_p() {410  uint8_t *p = m_cur_insn;411  if (m_wordsize == 8 && *p == 0x48)412    p++;413  if (*(p) == 0x8b && *(p + 1) == 0xe5)414    return true;415  if (*(p) == 0x89 && *(p + 1) == 0xec)416    return true;417  return false;418}419 420// movq %rbx, %rsp [0x48 0x8b 0xe3] or [0x48 0x89 0xdc]421// movl %ebx, %esp [0x8b 0xe3] or [0x89 0xdc]422bool x86AssemblyInspectionEngine::mov_rbx_rsp_pattern_p() {423  uint8_t *p = m_cur_insn;424  if (m_wordsize == 8 && *p == 0x48)425    p++;426  if (*(p) == 0x8b && *(p + 1) == 0xe3)427    return true;428  if (*(p) == 0x89 && *(p + 1) == 0xdc)429    return true;430  return false;431}432 433// subq $0x20, %rsp434bool x86AssemblyInspectionEngine::sub_rsp_pattern_p(int &amount) {435  uint8_t *p = m_cur_insn;436  if (m_wordsize == 8 && *p == 0x48)437    p++;438  // 8-bit immediate operand439  if (*p == 0x83 && *(p + 1) == 0xec) {440    amount = (int8_t) * (p + 2);441    return true;442  }443  // 32-bit immediate operand444  if (*p == 0x81 && *(p + 1) == 0xec) {445    amount = (int32_t)extract_4(p + 2);446    return true;447  }448  return false;449}450 451// addq $0x20, %rsp452bool x86AssemblyInspectionEngine::add_rsp_pattern_p(int &amount) {453  uint8_t *p = m_cur_insn;454  if (m_wordsize == 8 && *p == 0x48)455    p++;456  // 8-bit immediate operand457  if (*p == 0x83 && *(p + 1) == 0xc4) {458    amount = (int8_t) * (p + 2);459    return true;460  }461  // 32-bit immediate operand462  if (*p == 0x81 && *(p + 1) == 0xc4) {463    amount = (int32_t)extract_4(p + 2);464    return true;465  }466  return false;467}468 469// lea esp, [esp - 0x28]470// lea esp, [esp + 0x28]471bool x86AssemblyInspectionEngine::lea_rsp_pattern_p(int &amount) {472  uint8_t *p = m_cur_insn;473  if (m_wordsize == 8 && *p == 0x48)474    p++;475 476  // Check opcode477  if (*p != 0x8d)478    return false;479 480  // 8 bit displacement481  if (*(p + 1) == 0x64 && (*(p + 2) & 0x3f) == 0x24) {482    amount = (int8_t) * (p + 3);483    return true;484  }485 486  // 32 bit displacement487  if (*(p + 1) == 0xa4 && (*(p + 2) & 0x3f) == 0x24) {488    amount = (int32_t)extract_4(p + 3);489    return true;490  }491 492  return false;493}494 495// lea -0x28(%ebp), %esp496// (32-bit and 64-bit variants, 8-bit and 32-bit displacement)497bool x86AssemblyInspectionEngine::lea_rbp_rsp_pattern_p(int &amount) {498  uint8_t *p = m_cur_insn;499  if (m_wordsize == 8 && *p == 0x48)500    p++;501 502  // Check opcode503  if (*p != 0x8d)504    return false;505  ++p;506 507  // 8 bit displacement508  if (*p == 0x65) {509    amount = (int8_t)p[1];510    return true;511  }512 513  // 32 bit displacement514  if (*p == 0xa5) {515    amount = (int32_t)extract_4(p + 1);516    return true;517  }518 519  return false;520}521 522// lea -0x28(%ebx), %esp523// (32-bit and 64-bit variants, 8-bit and 32-bit displacement)524bool x86AssemblyInspectionEngine::lea_rbx_rsp_pattern_p(int &amount) {525  uint8_t *p = m_cur_insn;526  if (m_wordsize == 8 && *p == 0x48)527    p++;528 529  // Check opcode530  if (*p != 0x8d)531    return false;532  ++p;533 534  // 8 bit displacement535  if (*p == 0x63) {536    amount = (int8_t)p[1];537    return true;538  }539 540  // 32 bit displacement541  if (*p == 0xa3) {542    amount = (int32_t)extract_4(p + 1);543    return true;544  }545 546  return false;547}548 549// and -0xfffffff0, %esp550// (32-bit and 64-bit variants, 8-bit and 32-bit displacement)551bool x86AssemblyInspectionEngine::and_rsp_pattern_p() {552  uint8_t *p = m_cur_insn;553  if (m_wordsize == 8 && *p == 0x48)554    p++;555 556  if (*p != 0x81 && *p != 0x83)557    return false;558 559  return *++p == 0xe4;560}561 562// popq %rbx563// popl %ebx564bool x86AssemblyInspectionEngine::pop_reg_p(int &regno) {565  uint8_t *p = m_cur_insn;566  int regno_prefix_bit = 0;567  // If we have a rex prefix byte, check to see if a B bit is set568  if (m_wordsize == 8 && (*p & 0xfe) == 0x40) {569    regno_prefix_bit = (*p & 1) << 3;570    p++;571  }572  if (*p >= 0x58 && *p <= 0x5f) {573    regno = (*p - 0x58) | regno_prefix_bit;574    return true;575  }576  return false;577}578 579// popq %rbp [0x5d]580// popl %ebp [0x5d]581bool x86AssemblyInspectionEngine::pop_rbp_pattern_p() {582  uint8_t *p = m_cur_insn;583  return (*p == 0x5d);584}585 586// instructions valid only in 32-bit mode:587// 0x1f - pop ds588// 0x07 - pop es589// 0x17 - pop ss590bool x86AssemblyInspectionEngine::pop_misc_reg_p() {591  uint8_t p = *m_cur_insn;592  if (m_wordsize == 4) {593    if (p == 0x1f || p == 0x07 || p == 0x17)594      return true;595  }596  return false;597}598 599// leave [0xc9]600bool x86AssemblyInspectionEngine::leave_pattern_p() {601  uint8_t *p = m_cur_insn;602  return (*p == 0xc9);603}604 605// call $0 [0xe8 0x0 0x0 0x0 0x0]606bool x86AssemblyInspectionEngine::call_next_insn_pattern_p() {607  uint8_t *p = m_cur_insn;608  return (*p == 0xe8) && (*(p + 1) == 0x0) && (*(p + 2) == 0x0) &&609         (*(p + 3) == 0x0) && (*(p + 4) == 0x0);610}611 612// Look for an instruction sequence storing a nonvolatile register on to the613// stack frame.614 615//  movq %rax, -0x10(%rbp) [0x48 0x89 0x45 0xf0]616//  movl %eax, -0xc(%ebp)  [0x89 0x45 0xf4]617 618// The offset value returned in rbp_offset will be positive -- but it must be619// subtraced from the frame base register to get the actual location.  The620// positive value returned for the offset is a convention used elsewhere for621// CFA offsets et al.622 623bool x86AssemblyInspectionEngine::mov_reg_to_local_stack_frame_p(624    int &regno, int &rbp_offset) {625  uint8_t *p = m_cur_insn;626  int src_reg_prefix_bit = 0;627  int target_reg_prefix_bit = 0;628 629  if (m_wordsize == 8 && REX_W_PREFIX_P(*p)) {630    src_reg_prefix_bit = REX_W_SRCREG(*p) << 3;631    target_reg_prefix_bit = REX_W_DSTREG(*p) << 3;632    if (target_reg_prefix_bit == 1) {633      // rbp/ebp don't need a prefix bit - we know this isn't the reg we care634      // about.635      return false;636    }637    p++;638  }639 640  if (*p == 0x89) {641    /* Mask off the 3-5 bits which indicate the destination register642       if this is a ModR/M byte.  */643    int opcode_destreg_masked_out = *(p + 1) & (~0x38);644 645    /* Is this a ModR/M byte with Mod bits 01 and R/M bits 101646       and three bits between them, e.g. 01nnn101647       We're looking for a destination of ebp-disp8 or ebp-disp32.   */648    int immsize;649    if (opcode_destreg_masked_out == 0x45)650      immsize = 2;651    else if (opcode_destreg_masked_out == 0x85)652      immsize = 4;653    else654      return false;655 656    int offset = 0;657    if (immsize == 2)658      offset = (int8_t) * (p + 2);659    if (immsize == 4)660      offset = (uint32_t)extract_4(p + 2);661    if (offset > 0)662      return false;663 664    regno = ((*(p + 1) >> 3) & 0x7) | src_reg_prefix_bit;665    rbp_offset = offset > 0 ? offset : -offset;666    return true;667  }668  return false;669}670 671// Returns true if this is a jmp instruction where we can't672// know the destination address statically. 673//674// ff e0                                   jmpq   *%rax675// ff e1                                   jmpq   *%rcx676// ff 60 28                                jmpq   *0x28(%rax)677// ff 60 60                                jmpq   *0x60(%rax)678bool x86AssemblyInspectionEngine::jmp_to_reg_p() {679  if (*m_cur_insn != 0xff)680    return false;681 682  // The second byte is a ModR/M /4 byte, strip off the registers683  uint8_t second_byte_sans_reg = *(m_cur_insn + 1) & ~7;684 685  // [reg]686  if (second_byte_sans_reg == 0x20)687    return true;688 689  // [reg]+disp8690  if (second_byte_sans_reg == 0x60)691    return true;692 693  // [reg]+disp32694  if (second_byte_sans_reg == 0xa0)695    return true;696 697  // reg698  if (second_byte_sans_reg == 0xe0)699    return true;700 701  return false;702}703 704// Detect branches to fixed pc-relative offsets.705// Returns the offset from the address of the next instruction706// that may be branch/jumped to.707//708// Cannot determine the offset of a JMP that jumps to the address in709// a register ("jmpq *%rax") or offset from a register value 710// ("jmpq *0x28(%rax)"), this method will return false on those711// instructions.712//713// These instructions all end in either a relative 8/16/32 bit value714// depending on the instruction and the current execution mode of the715// inferior process.  Once we know the size of the opcode instruction, 716// we can use the total instruction length to determine the size of717// the relative offset without having to compute it correctly.718 719bool x86AssemblyInspectionEngine::pc_rel_branch_or_jump_p (720    const int instruction_length, int &offset)721{722  int opcode_size = 0;723 724  uint8_t b1 = m_cur_insn[0];725 726  switch (b1) {727    case 0x77: // JA/JNBE rel8728    case 0x73: // JAE/JNB/JNC rel8729    case 0x72: // JB/JC/JNAE rel8730    case 0x76: // JBE/JNA rel8731    case 0xe3: // JCXZ/JECXZ/JRCXZ rel8732    case 0x74: // JE/JZ rel8733    case 0x7f: // JG/JNLE rel8734    case 0x7d: // JGE/JNL rel8735    case 0x7c: // JL/JNGE rel8736    case 0x7e: // JNG/JLE rel8737    case 0x71: // JNO rel8738    case 0x7b: // JNP/JPO rel8739    case 0x79: // JNS rel8740    case 0x75: // JNE/JNZ rel8741    case 0x70: // JO rel8742    case 0x7a: // JP/JPE rel8743    case 0x78: // JS rel8744    case 0xeb: // JMP rel8745    case 0xe9: // JMP rel16/rel32746      opcode_size = 1;747      break;748    default:749      break;750  }751  if (b1 == 0x0f && opcode_size == 0) {752    uint8_t b2 = m_cur_insn[1];753    switch (b2) {754      case 0x87: // JA/JNBE rel16/rel32755      case 0x86: // JBE/JNA rel16/rel32756      case 0x84: // JE/JZ rel16/rel32757      case 0x8f: // JG/JNLE rel16/rel32758      case 0x8d: // JNL/JGE rel16/rel32759      case 0x8e: // JLE rel16/rel32760      case 0x82: // JB/JC/JNAE rel16/rel32761      case 0x83: // JAE/JNB/JNC rel16/rel32762      case 0x85: // JNE/JNZ rel16/rel32763      case 0x8c: // JL/JNGE rel16/rel32764      case 0x81: // JNO rel16/rel32765      case 0x8b: // JNP/JPO rel16/rel32766      case 0x89: // JNS rel16/rel32767      case 0x80: // JO rel16/rel32768      case 0x8a: // JP rel16/rel32769      case 0x88: // JS rel16/rel32770        opcode_size = 2;771        break;772      default:773        break;774    }775  }776 777  if (opcode_size == 0)778    return false;779 780  offset = 0;781  if (instruction_length - opcode_size == 1) {782    int8_t rel8 = (int8_t) *(m_cur_insn + opcode_size);783    offset = rel8;784  } else if (instruction_length - opcode_size == 2) {785    int16_t rel16 = extract_2_signed (m_cur_insn + opcode_size);786    offset = rel16;787  } else if (instruction_length - opcode_size == 4) {788    int32_t rel32 = extract_4_signed (m_cur_insn + opcode_size);789    offset = rel32;790  } else {791    return false;792  }793  return true;794}795 796// Returns true if this instruction is a intra-function branch or jump -797// a branch/jump within the bounds of this same function.798// Cannot predict where a jump through a register value ("jmpq *%rax")799// will go, so it will return false on that instruction.800bool x86AssemblyInspectionEngine::local_branch_p (801    const addr_t current_func_text_offset,802    const AddressRange &func_range,803    const int instruction_length,804    addr_t &target_insn_offset) {805  int offset;806  if (pc_rel_branch_or_jump_p (instruction_length, offset) && offset != 0) {807    addr_t next_pc_value = current_func_text_offset + instruction_length;808    if (offset < 0 && addr_t(-offset) > current_func_text_offset) {809      // Branch target is before the start of this function810      return false;811    }812    if (offset + next_pc_value >= func_range.GetByteSize()) {813      // Branch targets outside this function's bounds814      return false;815    }816    // This instruction branches to target_insn_offset (byte offset into the function)817    target_insn_offset = next_pc_value + offset;818    return true;819  }820  return false;821}822 823// Returns true if this instruction is a inter-function branch or jump - a824// branch/jump to another function.825// Cannot predict where a jump through a register value ("jmpq *%rax")826// will go, so it will return false on that instruction.827bool x86AssemblyInspectionEngine::non_local_branch_p (828    const addr_t current_func_text_offset,829    const AddressRange &func_range,830    const int instruction_length) {831  int offset;832  addr_t target_insn_offset;833  if (pc_rel_branch_or_jump_p (instruction_length, offset)) {834    return !local_branch_p(current_func_text_offset,func_range,instruction_length,target_insn_offset);835  }836  return false;837}838 839// ret [0xc3] or [0xcb] or [0xc2 imm16] or [0xca imm16]840bool x86AssemblyInspectionEngine::ret_pattern_p() {841  uint8_t *p = m_cur_insn;842  return *p == 0xc3 || *p == 0xc2 || *p == 0xca || *p == 0xcb;843}844 845uint16_t x86AssemblyInspectionEngine::extract_2(uint8_t *b) {846  uint16_t v = 0;847  for (int i = 1; i >= 0; i--)848    v = (v << 8) | b[i];849  return v;850}851 852int16_t x86AssemblyInspectionEngine::extract_2_signed(uint8_t *b) {853  int16_t v = 0;854  for (int i = 1; i >= 0; i--)855    v = (v << 8) | b[i];856  return v;857}858 859uint32_t x86AssemblyInspectionEngine::extract_4(uint8_t *b) {860  uint32_t v = 0;861  for (int i = 3; i >= 0; i--)862    v = (v << 8) | b[i];863  return v;864}865 866int32_t x86AssemblyInspectionEngine::extract_4_signed(uint8_t *b) {867  int32_t v = 0;868  for (int i = 3; i >= 0; i--)869    v = (v << 8) | b[i];870  return v;871}872 873 874bool x86AssemblyInspectionEngine::instruction_length(uint8_t *insn_p,875                                                     int &length, 876                                                     uint32_t buffer_remaining_bytes) {877 878  uint32_t max_op_byte_size = std::min(buffer_remaining_bytes, m_arch.GetMaximumOpcodeByteSize());879  llvm::SmallVector<uint8_t, 32> opcode_data;880  opcode_data.resize(max_op_byte_size);881 882  char out_string[512];883  const size_t inst_size =884      ::LLVMDisasmInstruction(m_disasm_context, insn_p, max_op_byte_size, 0,885                              out_string, sizeof(out_string));886 887  length = inst_size;888  return true;889}890 891bool x86AssemblyInspectionEngine::machine_regno_to_lldb_regno(892    int machine_regno, uint32_t &lldb_regno) {893  MachineRegnumToNameAndLLDBRegnum::iterator it = m_reg_map.find(machine_regno);894  if (it != m_reg_map.end()) {895    lldb_regno = it->second.lldb_regnum;896    return true;897  }898  return false;899}900 901bool x86AssemblyInspectionEngine::GetNonCallSiteUnwindPlanFromAssembly(902    uint8_t *data, size_t size, AddressRange &func_range,903    UnwindPlan &unwind_plan) {904  unwind_plan.Clear();905 906  if (data == nullptr || size == 0)907    return false;908 909  if (!m_register_map_initialized)910    return false;911 912  if (m_disasm_context == nullptr)913    return false;914 915  addr_t current_func_text_offset = 0;916  int current_sp_bytes_offset_from_fa = 0;917  bool is_aligned = false;918  UnwindPlan::Row::AbstractRegisterLocation initial_regloc;919  UnwindPlan::Row row;920 921  unwind_plan.SetPlanValidAddressRanges({func_range});922  unwind_plan.SetRegisterKind(eRegisterKindLLDB);923 924  // At the start of the function, find the CFA by adding wordsize to the SP925  // register926  row.SetOffset(current_func_text_offset);927  row.GetCFAValue().SetIsRegisterPlusOffset(m_lldb_sp_regnum, m_wordsize);928 929  // caller's stack pointer value before the call insn is the CFA address930  initial_regloc.SetIsCFAPlusOffset(0);931  row.SetRegisterInfo(m_lldb_sp_regnum, initial_regloc);932 933  // saved instruction pointer can be found at CFA - wordsize.934  current_sp_bytes_offset_from_fa = m_wordsize;935  initial_regloc.SetAtCFAPlusOffset(-current_sp_bytes_offset_from_fa);936  row.SetRegisterInfo(m_lldb_ip_regnum, initial_regloc);937 938  unwind_plan.AppendRow(row);939 940  // Track which registers have been saved so far in the prologue. If we see941  // another push of that register, it's not part of the prologue. The register942  // numbers used here are the machine register #'s (i386_register_numbers,943  // x86_64_register_numbers).944  std::vector<bool> saved_registers(32, false);945 946  // Once the prologue has completed we'll save a copy of the unwind947  // instructions If there is an epilogue in the middle of the function, after948  // that epilogue we'll reinstate the unwind setup -- we assume that some code949  // path jumps over the mid-function epilogue950 951  std::optional<UnwindPlan::Row>952      prologue_completed_row; // copy of prologue row of CFI953  int prologue_completed_sp_bytes_offset_from_cfa = 0; // The sp value before the954                                                   // epilogue started executed955  bool prologue_completed_is_aligned = false;956  std::vector<bool> prologue_completed_saved_registers;957 958  while (current_func_text_offset < size) {959    int stack_offset, insn_len;960    int machine_regno;   // register numbers masked directly out of instructions961    uint32_t lldb_regno; // register numbers in lldb's eRegisterKindLLDB962                         // numbering scheme963 964    bool in_epilogue = false; // we're in the middle of an epilogue sequence965    bool row_updated = false; // The UnwindPlan::Row 'row' has been updated966    bool current_sp_offset_updated =967        false; // current_sp_bytes_offset_from_fa has been updated this insn968 969    m_cur_insn = data + current_func_text_offset;970    if (!instruction_length(m_cur_insn, insn_len, size - current_func_text_offset)971        || insn_len == 0 972        || insn_len > kMaxInstructionByteSize) {973      // An unrecognized/junk instruction974      break;975    }976 977    auto &cfa_value = row.GetCFAValue();978    auto &afa_value = row.GetAFAValue();979    auto fa_value_ptr = is_aligned ? &afa_value : &cfa_value;980 981    if (mov_rsp_rbp_pattern_p()) {982      if (fa_value_ptr->GetRegisterNumber() == m_lldb_sp_regnum) {983        fa_value_ptr->SetIsRegisterPlusOffset(984            m_lldb_fp_regnum, fa_value_ptr->GetOffset());985        row_updated = true;986      }987    }988 989    else if (mov_rsp_rbx_pattern_p()) {990      if (fa_value_ptr->GetRegisterNumber() == m_lldb_sp_regnum) {991        fa_value_ptr->SetIsRegisterPlusOffset(992            m_lldb_alt_fp_regnum, fa_value_ptr->GetOffset());993        row_updated = true;994      }995    }996 997    else if (and_rsp_pattern_p()) {998      current_sp_bytes_offset_from_fa = 0;999      afa_value.SetIsRegisterPlusOffset(1000          m_lldb_sp_regnum, current_sp_bytes_offset_from_fa);1001      fa_value_ptr = &afa_value;1002      is_aligned = true;1003      row_updated = true;1004    }1005 1006    else if (mov_rbp_rsp_pattern_p()) {1007      if (is_aligned && cfa_value.GetRegisterNumber() == m_lldb_fp_regnum)1008      {1009        is_aligned = false;1010        fa_value_ptr = &cfa_value;1011        afa_value.SetUnspecified();1012        row_updated = true;1013      }1014      if (fa_value_ptr->GetRegisterNumber() == m_lldb_fp_regnum) {1015        current_sp_bytes_offset_from_fa = fa_value_ptr->GetOffset();1016        current_sp_offset_updated = true;1017      }1018    }1019 1020    else if (mov_rbx_rsp_pattern_p()) {1021      if (is_aligned && cfa_value.GetRegisterNumber() == m_lldb_alt_fp_regnum)1022      {1023        is_aligned = false;1024        fa_value_ptr = &cfa_value;1025        afa_value.SetUnspecified();1026        row_updated = true;1027      }1028      if (fa_value_ptr->GetRegisterNumber() == m_lldb_alt_fp_regnum) {1029        current_sp_bytes_offset_from_fa = fa_value_ptr->GetOffset();1030        current_sp_offset_updated = true;1031      }1032    }1033 1034    // This is the start() function (or a pthread equivalent), it starts with a1035    // pushl $0x0 which puts the saved pc value of 0 on the stack.  In this1036    // case we want to pretend we didn't see a stack movement at all --1037    // normally the saved pc value is already on the stack by the time the1038    // function starts executing.1039    else if (push_0_pattern_p()) {1040    }1041 1042    else if (push_reg_p(machine_regno)) {1043      current_sp_bytes_offset_from_fa += m_wordsize;1044      current_sp_offset_updated = true;1045      // the PUSH instruction has moved the stack pointer - if the FA is set1046      // in terms of the stack pointer, we need to add a new row of1047      // instructions.1048      if (fa_value_ptr->GetRegisterNumber() == m_lldb_sp_regnum) {1049        fa_value_ptr->SetOffset(current_sp_bytes_offset_from_fa);1050        row_updated = true;1051      }1052      // record where non-volatile (callee-saved, spilled) registers are saved1053      // on the stack1054      if (nonvolatile_reg_p(machine_regno) &&1055          machine_regno_to_lldb_regno(machine_regno, lldb_regno) &&1056          !saved_registers[machine_regno]) {1057        UnwindPlan::Row::AbstractRegisterLocation regloc;1058        if (is_aligned)1059            regloc.SetAtAFAPlusOffset(-current_sp_bytes_offset_from_fa);1060        else1061            regloc.SetAtCFAPlusOffset(-current_sp_bytes_offset_from_fa);1062        row.SetRegisterInfo(lldb_regno, regloc);1063        saved_registers[machine_regno] = true;1064        row_updated = true;1065      }1066    }1067 1068    else if (pop_reg_p(machine_regno)) {1069      current_sp_bytes_offset_from_fa -= m_wordsize;1070      current_sp_offset_updated = true;1071 1072      if (nonvolatile_reg_p(machine_regno) &&1073          machine_regno_to_lldb_regno(machine_regno, lldb_regno) &&1074          saved_registers[machine_regno]) {1075        saved_registers[machine_regno] = false;1076        row.RemoveRegisterInfo(lldb_regno);1077 1078        if (lldb_regno == fa_value_ptr->GetRegisterNumber()) {1079          fa_value_ptr->SetIsRegisterPlusOffset(1080              m_lldb_sp_regnum, fa_value_ptr->GetOffset());1081        }1082 1083        in_epilogue = true;1084        row_updated = true;1085      }1086 1087      // the POP instruction has moved the stack pointer - if the FA is set in1088      // terms of the stack pointer, we need to add a new row of instructions.1089      if (fa_value_ptr->GetRegisterNumber() == m_lldb_sp_regnum) {1090        fa_value_ptr->SetIsRegisterPlusOffset(1091            m_lldb_sp_regnum, current_sp_bytes_offset_from_fa);1092        row_updated = true;1093      }1094    }1095 1096    else if (pop_misc_reg_p()) {1097      current_sp_bytes_offset_from_fa -= m_wordsize;1098      current_sp_offset_updated = true;1099      if (fa_value_ptr->GetRegisterNumber() == m_lldb_sp_regnum) {1100        fa_value_ptr->SetIsRegisterPlusOffset(1101            m_lldb_sp_regnum, current_sp_bytes_offset_from_fa);1102        row_updated = true;1103      }1104    }1105 1106    // The LEAVE instruction moves the value from rbp into rsp and pops a value1107    // off the stack into rbp (restoring the caller's rbp value). It is the1108    // opposite of ENTER, or 'push rbp, mov rsp rbp'.1109    else if (leave_pattern_p()) {1110      if (saved_registers[m_machine_fp_regnum]) {1111        saved_registers[m_machine_fp_regnum] = false;1112        row.RemoveRegisterInfo(m_lldb_fp_regnum);1113 1114        row_updated = true;1115      }1116 1117      if (is_aligned && cfa_value.GetRegisterNumber() == m_lldb_fp_regnum)1118      {1119        is_aligned = false;1120        fa_value_ptr = &cfa_value;1121        afa_value.SetUnspecified();1122        row_updated = true;1123      }1124 1125      if (fa_value_ptr->GetRegisterNumber() == m_lldb_fp_regnum)1126      {1127        fa_value_ptr->SetIsRegisterPlusOffset(1128            m_lldb_sp_regnum, fa_value_ptr->GetOffset());1129 1130        current_sp_bytes_offset_from_fa = fa_value_ptr->GetOffset();1131      }1132 1133      current_sp_bytes_offset_from_fa -= m_wordsize;1134      current_sp_offset_updated = true;1135 1136      if (fa_value_ptr->GetRegisterNumber() == m_lldb_sp_regnum) {1137        fa_value_ptr->SetIsRegisterPlusOffset(1138            m_lldb_sp_regnum, current_sp_bytes_offset_from_fa);1139        row_updated = true;1140      }1141 1142      in_epilogue = true;1143    }1144 1145    else if (mov_reg_to_local_stack_frame_p(machine_regno, stack_offset) &&1146             nonvolatile_reg_p(machine_regno) &&1147             machine_regno_to_lldb_regno(machine_regno, lldb_regno) &&1148             !saved_registers[machine_regno]) {1149      saved_registers[machine_regno] = true;1150 1151      UnwindPlan::Row::AbstractRegisterLocation regloc;1152 1153      // stack_offset for 'movq %r15, -80(%rbp)' will be 80. In the Row, we1154      // want to express this as the offset from the FA.  If the frame base is1155      // rbp (like the above instruction), the FA offset for rbp is probably1156      // 16.  So we want to say that the value is stored at the FA address -1157      // 96.1158      if (is_aligned)1159          regloc.SetAtAFAPlusOffset(-(stack_offset + fa_value_ptr->GetOffset()));1160      else1161          regloc.SetAtCFAPlusOffset(-(stack_offset + fa_value_ptr->GetOffset()));1162 1163      row.SetRegisterInfo(lldb_regno, regloc);1164 1165      row_updated = true;1166    }1167 1168    else if (sub_rsp_pattern_p(stack_offset)) {1169      current_sp_bytes_offset_from_fa += stack_offset;1170      current_sp_offset_updated = true;1171      if (fa_value_ptr->GetRegisterNumber() == m_lldb_sp_regnum) {1172        fa_value_ptr->SetOffset(current_sp_bytes_offset_from_fa);1173        row_updated = true;1174      }1175    }1176 1177    else if (add_rsp_pattern_p(stack_offset)) {1178      current_sp_bytes_offset_from_fa -= stack_offset;1179      current_sp_offset_updated = true;1180      if (fa_value_ptr->GetRegisterNumber() == m_lldb_sp_regnum) {1181        fa_value_ptr->SetOffset(current_sp_bytes_offset_from_fa);1182        row_updated = true;1183      }1184      in_epilogue = true;1185    }1186 1187    else if (push_extended_pattern_p() || push_imm_pattern_p() ||1188             push_misc_reg_p()) {1189      current_sp_bytes_offset_from_fa += m_wordsize;1190      current_sp_offset_updated = true;1191      if (fa_value_ptr->GetRegisterNumber() == m_lldb_sp_regnum) {1192        fa_value_ptr->SetOffset(current_sp_bytes_offset_from_fa);1193        row_updated = true;1194      }1195    }1196 1197    else if (lea_rsp_pattern_p(stack_offset)) {1198      current_sp_bytes_offset_from_fa -= stack_offset;1199      current_sp_offset_updated = true;1200      if (fa_value_ptr->GetRegisterNumber() == m_lldb_sp_regnum) {1201        fa_value_ptr->SetOffset(current_sp_bytes_offset_from_fa);1202        row_updated = true;1203      }1204      if (stack_offset > 0)1205        in_epilogue = true;1206    }1207 1208    else if (lea_rbp_rsp_pattern_p(stack_offset)) {1209      if (is_aligned &&1210          cfa_value.GetRegisterNumber() == m_lldb_fp_regnum) {1211        is_aligned = false;1212        fa_value_ptr = &cfa_value;1213        afa_value.SetUnspecified();1214        row_updated = true;1215      }1216      if (fa_value_ptr->GetRegisterNumber() == m_lldb_fp_regnum) {1217        current_sp_bytes_offset_from_fa =1218          fa_value_ptr->GetOffset() - stack_offset;1219        current_sp_offset_updated = true;1220      }1221    }1222 1223    else if (lea_rbx_rsp_pattern_p(stack_offset)) {1224      if (is_aligned &&1225          cfa_value.GetRegisterNumber() == m_lldb_alt_fp_regnum) {1226        is_aligned = false;1227        fa_value_ptr = &cfa_value;1228        afa_value.SetUnspecified();1229        row_updated = true;1230      }1231      if (fa_value_ptr->GetRegisterNumber() == m_lldb_alt_fp_regnum) {1232        current_sp_bytes_offset_from_fa = fa_value_ptr->GetOffset() - stack_offset;1233        current_sp_offset_updated = true;1234      }1235    }1236 1237    else if (prologue_completed_row &&1238             (ret_pattern_p() ||1239              non_local_branch_p(current_func_text_offset, func_range,1240                                 insn_len) ||1241              jmp_to_reg_p())) {1242      // Check if the current instruction is the end of an epilogue sequence,1243      // and if so, re-instate the prologue-completed unwind state.1244 1245      // The current instruction is a branch/jump outside this function, 1246      // a ret, or a jump through a register value which we cannot 1247      // determine the effcts of.  Verify that the stack frame state 1248      // has been unwound to the same as it was at function entry to avoid 1249      // mis-identifying a JMP instruction as an epilogue.1250      UnwindPlan::Row::AbstractRegisterLocation sp, pc;1251      if (row.GetRegisterInfo(m_lldb_sp_regnum, sp) &&1252          row.GetRegisterInfo(m_lldb_ip_regnum, pc)) {1253        // Any ret instruction variant is definitely indicative of an1254        // epilogue; for other insn patterns verify that we're back to1255        // the original unwind state.1256        if (ret_pattern_p() ||1257            (sp.IsCFAPlusOffset() && sp.GetOffset() == 0 &&1258            pc.IsAtCFAPlusOffset() && pc.GetOffset() == -m_wordsize)) {1259          // Reinstate the saved prologue setup for any instructions that come1260          // after the epilogue1261 1262          row = *prologue_completed_row;1263          current_sp_bytes_offset_from_fa =1264              prologue_completed_sp_bytes_offset_from_cfa;1265          current_sp_offset_updated = true;1266          is_aligned = prologue_completed_is_aligned;1267 1268          saved_registers = prologue_completed_saved_registers;1269          in_epilogue = true;1270          row_updated = true;1271        }1272      }1273    }1274 1275    // call next instruction1276    //     call 01277    //  => pop  %ebx1278    // This is used in i386 programs to get the PIC base address for finding1279    // global data1280    else if (call_next_insn_pattern_p()) {1281      current_sp_bytes_offset_from_fa += m_wordsize;1282      current_sp_offset_updated = true;1283      if (fa_value_ptr->GetRegisterNumber() == m_lldb_sp_regnum) {1284        fa_value_ptr->SetOffset(current_sp_bytes_offset_from_fa);1285        row_updated = true;1286      }1287    }1288 1289    if (row_updated) {1290      if (current_func_text_offset + insn_len < size) {1291        row.SetOffset(current_func_text_offset + insn_len);1292        unwind_plan.AppendRow(row);1293      }1294    }1295 1296    if (!in_epilogue && row_updated) {1297      // If we're not in an epilogue sequence, save the updated Row1298      prologue_completed_row = row;1299      prologue_completed_saved_registers = saved_registers;1300    }1301 1302    // We may change the sp value without adding a new Row necessarily -- keep1303    // track of it either way.1304    if (!in_epilogue && current_sp_offset_updated) {1305      prologue_completed_sp_bytes_offset_from_cfa =1306          current_sp_bytes_offset_from_fa;1307      prologue_completed_is_aligned = is_aligned;1308    }1309 1310    m_cur_insn = m_cur_insn + insn_len;1311    current_func_text_offset += insn_len;1312  }1313 1314  unwind_plan.SetSourceName("assembly insn profiling");1315  unwind_plan.SetSourcedFromCompiler(eLazyBoolNo);1316  unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolYes);1317  unwind_plan.SetUnwindPlanForSignalTrap(eLazyBoolNo);1318 1319  return true;1320}1321 1322bool x86AssemblyInspectionEngine::AugmentUnwindPlanFromCallSite(1323    uint8_t *data, size_t size, AddressRange &func_range,1324    UnwindPlan &unwind_plan, RegisterContextSP &reg_ctx) {1325  Address addr_start = func_range.GetBaseAddress();1326  if (!addr_start.IsValid())1327    return false;1328 1329  // We either need a live RegisterContext, or we need the UnwindPlan to1330  // already be in the lldb register numbering scheme.1331  if (reg_ctx.get() == nullptr &&1332      unwind_plan.GetRegisterKind() != eRegisterKindLLDB)1333    return false;1334 1335  // Is original unwind_plan valid?1336  // unwind_plan should have at least one row which is ABI-default (CFA1337  // register is sp), and another row in mid-function.1338  if (unwind_plan.GetRowCount() < 2)1339    return false;1340 1341  UnwindPlan::Row first_row = *unwind_plan.GetRowAtIndex(0);1342  if (first_row.GetOffset() != 0)1343    return false;1344  uint32_t cfa_reg = first_row.GetCFAValue().GetRegisterNumber();1345  if (unwind_plan.GetRegisterKind() != eRegisterKindLLDB) {1346    cfa_reg = reg_ctx->ConvertRegisterKindToRegisterNumber(1347        unwind_plan.GetRegisterKind(),1348        first_row.GetCFAValue().GetRegisterNumber());1349  }1350  if (cfa_reg != m_lldb_sp_regnum ||1351      first_row.GetCFAValue().GetOffset() != m_wordsize)1352    return false;1353 1354  UnwindPlan::Row original_last_row = *unwind_plan.GetLastRow();1355 1356  size_t offset = 0;1357  int row_id = 1;1358  bool unwind_plan_updated = false;1359  UnwindPlan::Row row = first_row;1360 1361  // After a mid-function epilogue we will need to re-insert the original1362  // unwind rules so unwinds work for the remainder of the function.  These1363  // aren't common with clang/gcc on x86 but it is possible.1364  bool reinstate_unwind_state = false;1365 1366  while (offset < size) {1367    m_cur_insn = data + offset;1368    int insn_len;1369    if (!instruction_length(m_cur_insn, insn_len, size - offset) ||1370        insn_len == 0 || insn_len > kMaxInstructionByteSize) {1371      // An unrecognized/junk instruction.1372      break;1373    }1374 1375    // Advance offsets.1376    offset += insn_len;1377 1378    // offset is pointing beyond the bounds of the function; stop looping.1379    if (offset >= size)1380      continue;1381 1382    if (reinstate_unwind_state) {1383      row = original_last_row;1384      row.SetOffset(offset);1385      unwind_plan.AppendRow(row);1386      reinstate_unwind_state = false;1387      unwind_plan_updated = true;1388      continue;1389    }1390 1391    // If we already have one row for this instruction, we can continue.1392    while (row_id < unwind_plan.GetRowCount() &&1393           unwind_plan.GetRowAtIndex(row_id)->GetOffset() <=1394               static_cast<int64_t>(offset)) {1395      row_id++;1396    }1397    const UnwindPlan::Row *original_row = unwind_plan.GetRowAtIndex(row_id - 1);1398    if (original_row->GetOffset() == static_cast<int64_t>(offset)) {1399      row = *original_row;1400      continue;1401    }1402 1403    if (row_id == 0) {1404      // If we are here, compiler didn't generate CFI for prologue. This won't1405      // happen to GCC or clang. In this case, bail out directly.1406      return false;1407    }1408 1409    // Inspect the instruction to check if we need a new row for it.1410    cfa_reg = row.GetCFAValue().GetRegisterNumber();1411    if (unwind_plan.GetRegisterKind() != eRegisterKindLLDB) {1412      cfa_reg = reg_ctx->ConvertRegisterKindToRegisterNumber(1413          unwind_plan.GetRegisterKind(), row.GetCFAValue().GetRegisterNumber());1414    }1415    if (cfa_reg == m_lldb_sp_regnum) {1416      // CFA register is sp.1417 1418      // call next instruction1419      //     call 01420      //  => pop  %ebx1421      if (call_next_insn_pattern_p()) {1422        row.SetOffset(offset);1423        row.GetCFAValue().IncOffset(m_wordsize);1424 1425        unwind_plan.InsertRow(row);1426        unwind_plan_updated = true;1427        continue;1428      }1429 1430      // push/pop register1431      int regno;1432      if (push_reg_p(regno)) {1433        row.SetOffset(offset);1434        row.GetCFAValue().IncOffset(m_wordsize);1435 1436        unwind_plan.InsertRow(row);1437        unwind_plan_updated = true;1438        continue;1439      }1440      if (pop_reg_p(regno)) {1441        // Technically, this might be a nonvolatile register recover in1442        // epilogue. We should reset RegisterInfo for the register. But in1443        // practice, previous rule for the register is still valid... So we1444        // ignore this case.1445 1446        row.SetOffset(offset);1447        row.GetCFAValue().IncOffset(-m_wordsize);1448 1449        unwind_plan.InsertRow(row);1450        unwind_plan_updated = true;1451        continue;1452      }1453 1454      if (pop_misc_reg_p()) {1455        row.SetOffset(offset);1456        row.GetCFAValue().IncOffset(-m_wordsize);1457 1458        unwind_plan.InsertRow(row);1459        unwind_plan_updated = true;1460        continue;1461      }1462 1463      // push imm1464      if (push_imm_pattern_p()) {1465        row.SetOffset(offset);1466        row.GetCFAValue().IncOffset(m_wordsize);1467        unwind_plan.InsertRow(row);1468        unwind_plan_updated = true;1469        continue;1470      }1471 1472      // push extended1473      if (push_extended_pattern_p() || push_misc_reg_p()) {1474        row.SetOffset(offset);1475        row.GetCFAValue().IncOffset(m_wordsize);1476        unwind_plan.InsertRow(row);1477        unwind_plan_updated = true;1478        continue;1479      }1480 1481      // add/sub %rsp/%esp1482      int amount;1483      if (add_rsp_pattern_p(amount)) {1484        row.SetOffset(offset);1485        row.GetCFAValue().IncOffset(-amount);1486 1487        unwind_plan.InsertRow(row);1488        unwind_plan_updated = true;1489        continue;1490      }1491      if (sub_rsp_pattern_p(amount)) {1492        row.SetOffset(offset);1493        row.GetCFAValue().IncOffset(amount);1494 1495        unwind_plan.InsertRow(row);1496        unwind_plan_updated = true;1497        continue;1498      }1499 1500      // lea %rsp, [%rsp + $offset]1501      if (lea_rsp_pattern_p(amount)) {1502        row.SetOffset(offset);1503        row.GetCFAValue().IncOffset(-amount);1504 1505        unwind_plan.InsertRow(row);1506        unwind_plan_updated = true;1507        continue;1508      }1509 1510      if (ret_pattern_p()) {1511        reinstate_unwind_state = true;1512        continue;1513      }1514    } else if (cfa_reg == m_lldb_fp_regnum) {1515      // CFA register is fp.1516 1517      // The only case we care about is epilogue:1518      //     [0x5d] pop %rbp/%ebp1519      //  => [0xc3] ret1520      if (pop_rbp_pattern_p() || leave_pattern_p()) {1521        m_cur_insn++;1522        if (ret_pattern_p()) {1523          row.SetOffset(offset);1524          row.GetCFAValue().SetIsRegisterPlusOffset(1525              first_row.GetCFAValue().GetRegisterNumber(), m_wordsize);1526 1527          unwind_plan.InsertRow(row);1528          unwind_plan_updated = true;1529          reinstate_unwind_state = true;1530          continue;1531        }1532      }1533    } else {1534      // CFA register is not sp or fp.1535 1536      // This must be hand-written assembly.1537      // Just trust eh_frame and assume we have finished.1538      break;1539    }1540  }1541 1542  unwind_plan.SetPlanValidAddressRanges({func_range});1543  if (unwind_plan_updated) {1544    std::string unwind_plan_source(unwind_plan.GetSourceName().AsCString());1545    unwind_plan_source += " plus augmentation from assembly parsing";1546    unwind_plan.SetSourceName(unwind_plan_source.c_str());1547    unwind_plan.SetSourcedFromCompiler(eLazyBoolNo);1548    unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolYes);1549  }1550  return true;1551}1552 1553bool x86AssemblyInspectionEngine::FindFirstNonPrologueInstruction(1554    uint8_t *data, size_t size, size_t &offset) {1555  offset = 0;1556 1557  if (!m_register_map_initialized)1558    return false;1559 1560  if (m_disasm_context == nullptr)1561    return false;1562 1563  while (offset < size) {1564    int regno;1565    int insn_len;1566    int scratch;1567 1568    m_cur_insn = data + offset;1569    if (!instruction_length(m_cur_insn, insn_len, size - offset) 1570        || insn_len > kMaxInstructionByteSize 1571        || insn_len == 0) {1572      // An error parsing the instruction, i.e. probably data/garbage - stop1573      // scanning1574      break;1575    }1576 1577    if (push_rbp_pattern_p() || mov_rsp_rbp_pattern_p() ||1578        sub_rsp_pattern_p(scratch) || push_reg_p(regno) ||1579        mov_reg_to_local_stack_frame_p(regno, scratch) ||1580        (lea_rsp_pattern_p(scratch) && offset == 0)) {1581      offset += insn_len;1582      continue;1583    }1584    //1585    // Unknown non-prologue instruction - stop scanning1586    break;1587  }1588 1589  return true;1590}1591