Path: blob/main/contrib/llvm-project/lldb/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.cpp
39648 views
//===-- x86AssemblyInspectionEngine.cpp -----------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "x86AssemblyInspectionEngine.h"910#include <memory>1112#include "llvm-c/Disassembler.h"1314#include "lldb/Core/Address.h"15#include "lldb/Symbol/UnwindPlan.h"16#include "lldb/Target/RegisterContext.h"17#include "lldb/Target/UnwindAssembly.h"1819using namespace lldb_private;20using namespace lldb;2122x86AssemblyInspectionEngine::x86AssemblyInspectionEngine(const ArchSpec &arch)23: m_cur_insn(nullptr), m_machine_ip_regnum(LLDB_INVALID_REGNUM),24m_machine_sp_regnum(LLDB_INVALID_REGNUM),25m_machine_fp_regnum(LLDB_INVALID_REGNUM),26m_machine_alt_fp_regnum(LLDB_INVALID_REGNUM),27m_lldb_ip_regnum(LLDB_INVALID_REGNUM),28m_lldb_sp_regnum(LLDB_INVALID_REGNUM),29m_lldb_fp_regnum(LLDB_INVALID_REGNUM),30m_lldb_alt_fp_regnum(LLDB_INVALID_REGNUM), m_reg_map(), m_arch(arch),31m_cpu(k_cpu_unspecified), m_wordsize(-1),32m_register_map_initialized(false), m_disasm_context() {33m_disasm_context =34::LLVMCreateDisasm(arch.GetTriple().getTriple().c_str(), nullptr,35/*TagType=*/1, nullptr, nullptr);36}3738x86AssemblyInspectionEngine::~x86AssemblyInspectionEngine() {39::LLVMDisasmDispose(m_disasm_context);40}4142void x86AssemblyInspectionEngine::Initialize(RegisterContextSP ®_ctx) {43m_cpu = k_cpu_unspecified;44m_wordsize = -1;45m_register_map_initialized = false;4647const llvm::Triple::ArchType cpu = m_arch.GetMachine();48if (cpu == llvm::Triple::x86)49m_cpu = k_i386;50else if (cpu == llvm::Triple::x86_64)51m_cpu = k_x86_64;5253if (m_cpu == k_cpu_unspecified)54return;5556if (reg_ctx.get() == nullptr)57return;5859if (m_cpu == k_i386) {60m_machine_ip_regnum = k_machine_eip;61m_machine_sp_regnum = k_machine_esp;62m_machine_fp_regnum = k_machine_ebp;63m_machine_alt_fp_regnum = k_machine_ebx;64m_wordsize = 4;6566struct lldb_reg_info reginfo;67reginfo.name = "eax";68m_reg_map[k_machine_eax] = reginfo;69reginfo.name = "edx";70m_reg_map[k_machine_edx] = reginfo;71reginfo.name = "esp";72m_reg_map[k_machine_esp] = reginfo;73reginfo.name = "esi";74m_reg_map[k_machine_esi] = reginfo;75reginfo.name = "eip";76m_reg_map[k_machine_eip] = reginfo;77reginfo.name = "ecx";78m_reg_map[k_machine_ecx] = reginfo;79reginfo.name = "ebx";80m_reg_map[k_machine_ebx] = reginfo;81reginfo.name = "ebp";82m_reg_map[k_machine_ebp] = reginfo;83reginfo.name = "edi";84m_reg_map[k_machine_edi] = reginfo;85} else {86m_machine_ip_regnum = k_machine_rip;87m_machine_sp_regnum = k_machine_rsp;88m_machine_fp_regnum = k_machine_rbp;89m_machine_alt_fp_regnum = k_machine_rbx;90m_wordsize = 8;9192struct lldb_reg_info reginfo;93reginfo.name = "rax";94m_reg_map[k_machine_rax] = reginfo;95reginfo.name = "rdx";96m_reg_map[k_machine_rdx] = reginfo;97reginfo.name = "rsp";98m_reg_map[k_machine_rsp] = reginfo;99reginfo.name = "rsi";100m_reg_map[k_machine_rsi] = reginfo;101reginfo.name = "r8";102m_reg_map[k_machine_r8] = reginfo;103reginfo.name = "r10";104m_reg_map[k_machine_r10] = reginfo;105reginfo.name = "r12";106m_reg_map[k_machine_r12] = reginfo;107reginfo.name = "r14";108m_reg_map[k_machine_r14] = reginfo;109reginfo.name = "rip";110m_reg_map[k_machine_rip] = reginfo;111reginfo.name = "rcx";112m_reg_map[k_machine_rcx] = reginfo;113reginfo.name = "rbx";114m_reg_map[k_machine_rbx] = reginfo;115reginfo.name = "rbp";116m_reg_map[k_machine_rbp] = reginfo;117reginfo.name = "rdi";118m_reg_map[k_machine_rdi] = reginfo;119reginfo.name = "r9";120m_reg_map[k_machine_r9] = reginfo;121reginfo.name = "r11";122m_reg_map[k_machine_r11] = reginfo;123reginfo.name = "r13";124m_reg_map[k_machine_r13] = reginfo;125reginfo.name = "r15";126m_reg_map[k_machine_r15] = reginfo;127}128129for (MachineRegnumToNameAndLLDBRegnum::iterator it = m_reg_map.begin();130it != m_reg_map.end(); ++it) {131const RegisterInfo *ri = reg_ctx->GetRegisterInfoByName(it->second.name);132if (ri)133it->second.lldb_regnum = ri->kinds[eRegisterKindLLDB];134}135136uint32_t lldb_regno;137if (machine_regno_to_lldb_regno(m_machine_sp_regnum, lldb_regno))138m_lldb_sp_regnum = lldb_regno;139if (machine_regno_to_lldb_regno(m_machine_fp_regnum, lldb_regno))140m_lldb_fp_regnum = lldb_regno;141if (machine_regno_to_lldb_regno(m_machine_alt_fp_regnum, lldb_regno))142m_lldb_alt_fp_regnum = lldb_regno;143if (machine_regno_to_lldb_regno(m_machine_ip_regnum, lldb_regno))144m_lldb_ip_regnum = lldb_regno;145146m_register_map_initialized = true;147}148149void x86AssemblyInspectionEngine::Initialize(150std::vector<lldb_reg_info> ®_info) {151m_cpu = k_cpu_unspecified;152m_wordsize = -1;153m_register_map_initialized = false;154155const llvm::Triple::ArchType cpu = m_arch.GetMachine();156if (cpu == llvm::Triple::x86)157m_cpu = k_i386;158else if (cpu == llvm::Triple::x86_64)159m_cpu = k_x86_64;160161if (m_cpu == k_cpu_unspecified)162return;163164if (m_cpu == k_i386) {165m_machine_ip_regnum = k_machine_eip;166m_machine_sp_regnum = k_machine_esp;167m_machine_fp_regnum = k_machine_ebp;168m_machine_alt_fp_regnum = k_machine_ebx;169m_wordsize = 4;170171struct lldb_reg_info reginfo;172reginfo.name = "eax";173m_reg_map[k_machine_eax] = reginfo;174reginfo.name = "edx";175m_reg_map[k_machine_edx] = reginfo;176reginfo.name = "esp";177m_reg_map[k_machine_esp] = reginfo;178reginfo.name = "esi";179m_reg_map[k_machine_esi] = reginfo;180reginfo.name = "eip";181m_reg_map[k_machine_eip] = reginfo;182reginfo.name = "ecx";183m_reg_map[k_machine_ecx] = reginfo;184reginfo.name = "ebx";185m_reg_map[k_machine_ebx] = reginfo;186reginfo.name = "ebp";187m_reg_map[k_machine_ebp] = reginfo;188reginfo.name = "edi";189m_reg_map[k_machine_edi] = reginfo;190} else {191m_machine_ip_regnum = k_machine_rip;192m_machine_sp_regnum = k_machine_rsp;193m_machine_fp_regnum = k_machine_rbp;194m_machine_alt_fp_regnum = k_machine_rbx;195m_wordsize = 8;196197struct lldb_reg_info reginfo;198reginfo.name = "rax";199m_reg_map[k_machine_rax] = reginfo;200reginfo.name = "rdx";201m_reg_map[k_machine_rdx] = reginfo;202reginfo.name = "rsp";203m_reg_map[k_machine_rsp] = reginfo;204reginfo.name = "rsi";205m_reg_map[k_machine_rsi] = reginfo;206reginfo.name = "r8";207m_reg_map[k_machine_r8] = reginfo;208reginfo.name = "r10";209m_reg_map[k_machine_r10] = reginfo;210reginfo.name = "r12";211m_reg_map[k_machine_r12] = reginfo;212reginfo.name = "r14";213m_reg_map[k_machine_r14] = reginfo;214reginfo.name = "rip";215m_reg_map[k_machine_rip] = reginfo;216reginfo.name = "rcx";217m_reg_map[k_machine_rcx] = reginfo;218reginfo.name = "rbx";219m_reg_map[k_machine_rbx] = reginfo;220reginfo.name = "rbp";221m_reg_map[k_machine_rbp] = reginfo;222reginfo.name = "rdi";223m_reg_map[k_machine_rdi] = reginfo;224reginfo.name = "r9";225m_reg_map[k_machine_r9] = reginfo;226reginfo.name = "r11";227m_reg_map[k_machine_r11] = reginfo;228reginfo.name = "r13";229m_reg_map[k_machine_r13] = reginfo;230reginfo.name = "r15";231m_reg_map[k_machine_r15] = reginfo;232}233234for (MachineRegnumToNameAndLLDBRegnum::iterator it = m_reg_map.begin();235it != m_reg_map.end(); ++it) {236for (size_t i = 0; i < reg_info.size(); ++i) {237if (::strcmp(reg_info[i].name, it->second.name) == 0) {238it->second.lldb_regnum = reg_info[i].lldb_regnum;239break;240}241}242}243244uint32_t lldb_regno;245if (machine_regno_to_lldb_regno(m_machine_sp_regnum, lldb_regno))246m_lldb_sp_regnum = lldb_regno;247if (machine_regno_to_lldb_regno(m_machine_fp_regnum, lldb_regno))248m_lldb_fp_regnum = lldb_regno;249if (machine_regno_to_lldb_regno(m_machine_alt_fp_regnum, lldb_regno))250m_lldb_alt_fp_regnum = lldb_regno;251if (machine_regno_to_lldb_regno(m_machine_ip_regnum, lldb_regno))252m_lldb_ip_regnum = lldb_regno;253254m_register_map_initialized = true;255}256257// This function expects an x86 native register number (i.e. the bits stripped258// out of the actual instruction), not an lldb register number.259//260// FIXME: This is ABI dependent, it shouldn't be hardcoded here.261262bool x86AssemblyInspectionEngine::nonvolatile_reg_p(int machine_regno) {263if (m_cpu == k_i386) {264switch (machine_regno) {265case k_machine_ebx:266case k_machine_ebp: // not actually a nonvolatile but often treated as such267// by convention268case k_machine_esi:269case k_machine_edi:270case k_machine_esp:271return true;272default:273return false;274}275}276if (m_cpu == k_x86_64) {277switch (machine_regno) {278case k_machine_rbx:279case k_machine_rsp:280case k_machine_rbp: // not actually a nonvolatile but often treated as such281// by convention282case k_machine_r12:283case k_machine_r13:284case k_machine_r14:285case k_machine_r15:286return true;287default:288return false;289}290}291return false;292}293294// Macro to detect if this is a REX mode prefix byte.295#define REX_W_PREFIX_P(opcode) (((opcode) & (~0x5)) == 0x48)296297// The high bit which should be added to the source register number (the "R"298// bit)299#define REX_W_SRCREG(opcode) (((opcode)&0x4) >> 2)300301// The high bit which should be added to the destination register number (the302// "B" bit)303#define REX_W_DSTREG(opcode) ((opcode)&0x1)304305// pushq %rbp [0x55]306bool x86AssemblyInspectionEngine::push_rbp_pattern_p() {307uint8_t *p = m_cur_insn;308return *p == 0x55;309}310311// pushq $0 ; the first instruction in start() [0x6a 0x00]312bool x86AssemblyInspectionEngine::push_0_pattern_p() {313uint8_t *p = m_cur_insn;314return *p == 0x6a && *(p + 1) == 0x0;315}316317// pushq $0318// pushl $0319bool x86AssemblyInspectionEngine::push_imm_pattern_p() {320uint8_t *p = m_cur_insn;321return *p == 0x68 || *p == 0x6a;322}323324// pushl imm8(%esp)325//326// e.g. 0xff 0x74 0x24 0x20 - 'pushl 0x20(%esp)' (same byte pattern for 'pushq327// 0x20(%rsp)' in an x86_64 program)328//329// 0xff (with opcode bits '6' in next byte, PUSH r/m32) 0x74 (ModR/M byte with330// three bits used to specify the opcode)331// mod == b01, opcode == b110, R/M == b100332// "+disp8"333// 0x24 (SIB byte - scaled index = 0, r32 == esp) 0x20 imm8 value334335bool x86AssemblyInspectionEngine::push_extended_pattern_p() {336if (*m_cur_insn == 0xff) {337// Get the 3 opcode bits from the ModR/M byte338uint8_t opcode = (*(m_cur_insn + 1) >> 3) & 7;339if (opcode == 6) {340// I'm only looking for 0xff /6 here - I341// don't really care what value is being pushed, just that we're pushing342// a 32/64 bit value on to the stack is enough.343return true;344}345}346return false;347}348349// instructions only valid in 32-bit mode:350// 0x0e - push cs351// 0x16 - push ss352// 0x1e - push ds353// 0x06 - push es354bool x86AssemblyInspectionEngine::push_misc_reg_p() {355uint8_t p = *m_cur_insn;356if (m_wordsize == 4) {357if (p == 0x0e || p == 0x16 || p == 0x1e || p == 0x06)358return true;359}360return false;361}362363// pushq %rbx364// pushl %ebx365bool x86AssemblyInspectionEngine::push_reg_p(int ®no) {366uint8_t *p = m_cur_insn;367int regno_prefix_bit = 0;368// If we have a rex prefix byte, check to see if a B bit is set369if (m_wordsize == 8 && (*p & 0xfe) == 0x40) {370regno_prefix_bit = (*p & 1) << 3;371p++;372}373if (*p >= 0x50 && *p <= 0x57) {374regno = (*p - 0x50) | regno_prefix_bit;375return true;376}377return false;378}379380// movq %rsp, %rbp [0x48 0x8b 0xec] or [0x48 0x89 0xe5] movl %esp, %ebp [0x8b381// 0xec] or [0x89 0xe5]382bool x86AssemblyInspectionEngine::mov_rsp_rbp_pattern_p() {383uint8_t *p = m_cur_insn;384if (m_wordsize == 8 && *p == 0x48)385p++;386if (*(p) == 0x8b && *(p + 1) == 0xec)387return true;388if (*(p) == 0x89 && *(p + 1) == 0xe5)389return true;390return false;391}392393// movq %rsp, %rbx [0x48 0x8b 0xdc] or [0x48 0x89 0xe3]394// movl %esp, %ebx [0x8b 0xdc] or [0x89 0xe3]395bool x86AssemblyInspectionEngine::mov_rsp_rbx_pattern_p() {396uint8_t *p = m_cur_insn;397if (m_wordsize == 8 && *p == 0x48)398p++;399if (*(p) == 0x8b && *(p + 1) == 0xdc)400return true;401if (*(p) == 0x89 && *(p + 1) == 0xe3)402return true;403return false;404}405406// movq %rbp, %rsp [0x48 0x8b 0xe5] or [0x48 0x89 0xec]407// movl %ebp, %esp [0x8b 0xe5] or [0x89 0xec]408bool x86AssemblyInspectionEngine::mov_rbp_rsp_pattern_p() {409uint8_t *p = m_cur_insn;410if (m_wordsize == 8 && *p == 0x48)411p++;412if (*(p) == 0x8b && *(p + 1) == 0xe5)413return true;414if (*(p) == 0x89 && *(p + 1) == 0xec)415return true;416return false;417}418419// movq %rbx, %rsp [0x48 0x8b 0xe3] or [0x48 0x89 0xdc]420// movl %ebx, %esp [0x8b 0xe3] or [0x89 0xdc]421bool x86AssemblyInspectionEngine::mov_rbx_rsp_pattern_p() {422uint8_t *p = m_cur_insn;423if (m_wordsize == 8 && *p == 0x48)424p++;425if (*(p) == 0x8b && *(p + 1) == 0xe3)426return true;427if (*(p) == 0x89 && *(p + 1) == 0xdc)428return true;429return false;430}431432// subq $0x20, %rsp433bool x86AssemblyInspectionEngine::sub_rsp_pattern_p(int &amount) {434uint8_t *p = m_cur_insn;435if (m_wordsize == 8 && *p == 0x48)436p++;437// 8-bit immediate operand438if (*p == 0x83 && *(p + 1) == 0xec) {439amount = (int8_t) * (p + 2);440return true;441}442// 32-bit immediate operand443if (*p == 0x81 && *(p + 1) == 0xec) {444amount = (int32_t)extract_4(p + 2);445return true;446}447return false;448}449450// addq $0x20, %rsp451bool x86AssemblyInspectionEngine::add_rsp_pattern_p(int &amount) {452uint8_t *p = m_cur_insn;453if (m_wordsize == 8 && *p == 0x48)454p++;455// 8-bit immediate operand456if (*p == 0x83 && *(p + 1) == 0xc4) {457amount = (int8_t) * (p + 2);458return true;459}460// 32-bit immediate operand461if (*p == 0x81 && *(p + 1) == 0xc4) {462amount = (int32_t)extract_4(p + 2);463return true;464}465return false;466}467468// lea esp, [esp - 0x28]469// lea esp, [esp + 0x28]470bool x86AssemblyInspectionEngine::lea_rsp_pattern_p(int &amount) {471uint8_t *p = m_cur_insn;472if (m_wordsize == 8 && *p == 0x48)473p++;474475// Check opcode476if (*p != 0x8d)477return false;478479// 8 bit displacement480if (*(p + 1) == 0x64 && (*(p + 2) & 0x3f) == 0x24) {481amount = (int8_t) * (p + 3);482return true;483}484485// 32 bit displacement486if (*(p + 1) == 0xa4 && (*(p + 2) & 0x3f) == 0x24) {487amount = (int32_t)extract_4(p + 3);488return true;489}490491return false;492}493494// lea -0x28(%ebp), %esp495// (32-bit and 64-bit variants, 8-bit and 32-bit displacement)496bool x86AssemblyInspectionEngine::lea_rbp_rsp_pattern_p(int &amount) {497uint8_t *p = m_cur_insn;498if (m_wordsize == 8 && *p == 0x48)499p++;500501// Check opcode502if (*p != 0x8d)503return false;504++p;505506// 8 bit displacement507if (*p == 0x65) {508amount = (int8_t)p[1];509return true;510}511512// 32 bit displacement513if (*p == 0xa5) {514amount = (int32_t)extract_4(p + 1);515return true;516}517518return false;519}520521// lea -0x28(%ebx), %esp522// (32-bit and 64-bit variants, 8-bit and 32-bit displacement)523bool x86AssemblyInspectionEngine::lea_rbx_rsp_pattern_p(int &amount) {524uint8_t *p = m_cur_insn;525if (m_wordsize == 8 && *p == 0x48)526p++;527528// Check opcode529if (*p != 0x8d)530return false;531++p;532533// 8 bit displacement534if (*p == 0x63) {535amount = (int8_t)p[1];536return true;537}538539// 32 bit displacement540if (*p == 0xa3) {541amount = (int32_t)extract_4(p + 1);542return true;543}544545return false;546}547548// and -0xfffffff0, %esp549// (32-bit and 64-bit variants, 8-bit and 32-bit displacement)550bool x86AssemblyInspectionEngine::and_rsp_pattern_p() {551uint8_t *p = m_cur_insn;552if (m_wordsize == 8 && *p == 0x48)553p++;554555if (*p != 0x81 && *p != 0x83)556return false;557558return *++p == 0xe4;559}560561// popq %rbx562// popl %ebx563bool x86AssemblyInspectionEngine::pop_reg_p(int ®no) {564uint8_t *p = m_cur_insn;565int regno_prefix_bit = 0;566// If we have a rex prefix byte, check to see if a B bit is set567if (m_wordsize == 8 && (*p & 0xfe) == 0x40) {568regno_prefix_bit = (*p & 1) << 3;569p++;570}571if (*p >= 0x58 && *p <= 0x5f) {572regno = (*p - 0x58) | regno_prefix_bit;573return true;574}575return false;576}577578// popq %rbp [0x5d]579// popl %ebp [0x5d]580bool x86AssemblyInspectionEngine::pop_rbp_pattern_p() {581uint8_t *p = m_cur_insn;582return (*p == 0x5d);583}584585// instructions valid only in 32-bit mode:586// 0x1f - pop ds587// 0x07 - pop es588// 0x17 - pop ss589bool x86AssemblyInspectionEngine::pop_misc_reg_p() {590uint8_t p = *m_cur_insn;591if (m_wordsize == 4) {592if (p == 0x1f || p == 0x07 || p == 0x17)593return true;594}595return false;596}597598// leave [0xc9]599bool x86AssemblyInspectionEngine::leave_pattern_p() {600uint8_t *p = m_cur_insn;601return (*p == 0xc9);602}603604// call $0 [0xe8 0x0 0x0 0x0 0x0]605bool x86AssemblyInspectionEngine::call_next_insn_pattern_p() {606uint8_t *p = m_cur_insn;607return (*p == 0xe8) && (*(p + 1) == 0x0) && (*(p + 2) == 0x0) &&608(*(p + 3) == 0x0) && (*(p + 4) == 0x0);609}610611// Look for an instruction sequence storing a nonvolatile register on to the612// stack frame.613614// movq %rax, -0x10(%rbp) [0x48 0x89 0x45 0xf0]615// movl %eax, -0xc(%ebp) [0x89 0x45 0xf4]616617// The offset value returned in rbp_offset will be positive -- but it must be618// subtraced from the frame base register to get the actual location. The619// positive value returned for the offset is a convention used elsewhere for620// CFA offsets et al.621622bool x86AssemblyInspectionEngine::mov_reg_to_local_stack_frame_p(623int ®no, int &rbp_offset) {624uint8_t *p = m_cur_insn;625int src_reg_prefix_bit = 0;626int target_reg_prefix_bit = 0;627628if (m_wordsize == 8 && REX_W_PREFIX_P(*p)) {629src_reg_prefix_bit = REX_W_SRCREG(*p) << 3;630target_reg_prefix_bit = REX_W_DSTREG(*p) << 3;631if (target_reg_prefix_bit == 1) {632// rbp/ebp don't need a prefix bit - we know this isn't the reg we care633// about.634return false;635}636p++;637}638639if (*p == 0x89) {640/* Mask off the 3-5 bits which indicate the destination register641if this is a ModR/M byte. */642int opcode_destreg_masked_out = *(p + 1) & (~0x38);643644/* Is this a ModR/M byte with Mod bits 01 and R/M bits 101645and three bits between them, e.g. 01nnn101646We're looking for a destination of ebp-disp8 or ebp-disp32. */647int immsize;648if (opcode_destreg_masked_out == 0x45)649immsize = 2;650else if (opcode_destreg_masked_out == 0x85)651immsize = 4;652else653return false;654655int offset = 0;656if (immsize == 2)657offset = (int8_t) * (p + 2);658if (immsize == 4)659offset = (uint32_t)extract_4(p + 2);660if (offset > 0)661return false;662663regno = ((*(p + 1) >> 3) & 0x7) | src_reg_prefix_bit;664rbp_offset = offset > 0 ? offset : -offset;665return true;666}667return false;668}669670// Returns true if this is a jmp instruction where we can't671// know the destination address statically.672//673// ff e0 jmpq *%rax674// ff e1 jmpq *%rcx675// ff 60 28 jmpq *0x28(%rax)676// ff 60 60 jmpq *0x60(%rax)677bool x86AssemblyInspectionEngine::jmp_to_reg_p() {678if (*m_cur_insn != 0xff)679return false;680681// The second byte is a ModR/M /4 byte, strip off the registers682uint8_t second_byte_sans_reg = *(m_cur_insn + 1) & ~7;683684// [reg]685if (second_byte_sans_reg == 0x20)686return true;687688// [reg]+disp8689if (second_byte_sans_reg == 0x60)690return true;691692// [reg]+disp32693if (second_byte_sans_reg == 0xa0)694return true;695696// reg697if (second_byte_sans_reg == 0xe0)698return true;699700return false;701}702703// Detect branches to fixed pc-relative offsets.704// Returns the offset from the address of the next instruction705// that may be branch/jumped to.706//707// Cannot determine the offset of a JMP that jumps to the address in708// a register ("jmpq *%rax") or offset from a register value709// ("jmpq *0x28(%rax)"), this method will return false on those710// instructions.711//712// These instructions all end in either a relative 8/16/32 bit value713// depending on the instruction and the current execution mode of the714// inferior process. Once we know the size of the opcode instruction,715// we can use the total instruction length to determine the size of716// the relative offset without having to compute it correctly.717718bool x86AssemblyInspectionEngine::pc_rel_branch_or_jump_p (719const int instruction_length, int &offset)720{721int opcode_size = 0;722723uint8_t b1 = m_cur_insn[0];724725switch (b1) {726case 0x77: // JA/JNBE rel8727case 0x73: // JAE/JNB/JNC rel8728case 0x72: // JB/JC/JNAE rel8729case 0x76: // JBE/JNA rel8730case 0xe3: // JCXZ/JECXZ/JRCXZ rel8731case 0x74: // JE/JZ rel8732case 0x7f: // JG/JNLE rel8733case 0x7d: // JGE/JNL rel8734case 0x7c: // JL/JNGE rel8735case 0x7e: // JNG/JLE rel8736case 0x71: // JNO rel8737case 0x7b: // JNP/JPO rel8738case 0x79: // JNS rel8739case 0x75: // JNE/JNZ rel8740case 0x70: // JO rel8741case 0x7a: // JP/JPE rel8742case 0x78: // JS rel8743case 0xeb: // JMP rel8744case 0xe9: // JMP rel16/rel32745opcode_size = 1;746break;747default:748break;749}750if (b1 == 0x0f && opcode_size == 0) {751uint8_t b2 = m_cur_insn[1];752switch (b2) {753case 0x87: // JA/JNBE rel16/rel32754case 0x86: // JBE/JNA rel16/rel32755case 0x84: // JE/JZ rel16/rel32756case 0x8f: // JG/JNLE rel16/rel32757case 0x8d: // JNL/JGE rel16/rel32758case 0x8e: // JLE rel16/rel32759case 0x82: // JB/JC/JNAE rel16/rel32760case 0x83: // JAE/JNB/JNC rel16/rel32761case 0x85: // JNE/JNZ rel16/rel32762case 0x8c: // JL/JNGE rel16/rel32763case 0x81: // JNO rel16/rel32764case 0x8b: // JNP/JPO rel16/rel32765case 0x89: // JNS rel16/rel32766case 0x80: // JO rel16/rel32767case 0x8a: // JP rel16/rel32768case 0x88: // JS rel16/rel32769opcode_size = 2;770break;771default:772break;773}774}775776if (opcode_size == 0)777return false;778779offset = 0;780if (instruction_length - opcode_size == 1) {781int8_t rel8 = (int8_t) *(m_cur_insn + opcode_size);782offset = rel8;783} else if (instruction_length - opcode_size == 2) {784int16_t rel16 = extract_2_signed (m_cur_insn + opcode_size);785offset = rel16;786} else if (instruction_length - opcode_size == 4) {787int32_t rel32 = extract_4_signed (m_cur_insn + opcode_size);788offset = rel32;789} else {790return false;791}792return true;793}794795// Returns true if this instruction is a intra-function branch or jump -796// a branch/jump within the bounds of this same function.797// Cannot predict where a jump through a register value ("jmpq *%rax")798// will go, so it will return false on that instruction.799bool x86AssemblyInspectionEngine::local_branch_p (800const addr_t current_func_text_offset,801const AddressRange &func_range,802const int instruction_length,803addr_t &target_insn_offset) {804int offset;805if (pc_rel_branch_or_jump_p (instruction_length, offset) && offset != 0) {806addr_t next_pc_value = current_func_text_offset + instruction_length;807if (offset < 0 && addr_t(-offset) > current_func_text_offset) {808// Branch target is before the start of this function809return false;810}811if (offset + next_pc_value > func_range.GetByteSize()) {812// Branch targets outside this function's bounds813return false;814}815// This instruction branches to target_insn_offset (byte offset into the function)816target_insn_offset = next_pc_value + offset;817return true;818}819return false;820}821822// Returns true if this instruction is a inter-function branch or jump - a823// branch/jump to another function.824// Cannot predict where a jump through a register value ("jmpq *%rax")825// will go, so it will return false on that instruction.826bool x86AssemblyInspectionEngine::non_local_branch_p (827const addr_t current_func_text_offset,828const AddressRange &func_range,829const int instruction_length) {830int offset;831addr_t target_insn_offset;832if (pc_rel_branch_or_jump_p (instruction_length, offset)) {833return !local_branch_p(current_func_text_offset,func_range,instruction_length,target_insn_offset);834}835return false;836}837838// ret [0xc3] or [0xcb] or [0xc2 imm16] or [0xca imm16]839bool x86AssemblyInspectionEngine::ret_pattern_p() {840uint8_t *p = m_cur_insn;841return *p == 0xc3 || *p == 0xc2 || *p == 0xca || *p == 0xcb;842}843844uint16_t x86AssemblyInspectionEngine::extract_2(uint8_t *b) {845uint16_t v = 0;846for (int i = 1; i >= 0; i--)847v = (v << 8) | b[i];848return v;849}850851int16_t x86AssemblyInspectionEngine::extract_2_signed(uint8_t *b) {852int16_t v = 0;853for (int i = 1; i >= 0; i--)854v = (v << 8) | b[i];855return v;856}857858uint32_t x86AssemblyInspectionEngine::extract_4(uint8_t *b) {859uint32_t v = 0;860for (int i = 3; i >= 0; i--)861v = (v << 8) | b[i];862return v;863}864865int32_t x86AssemblyInspectionEngine::extract_4_signed(uint8_t *b) {866int32_t v = 0;867for (int i = 3; i >= 0; i--)868v = (v << 8) | b[i];869return v;870}871872873bool x86AssemblyInspectionEngine::instruction_length(uint8_t *insn_p,874int &length,875uint32_t buffer_remaining_bytes) {876877uint32_t max_op_byte_size = std::min(buffer_remaining_bytes, m_arch.GetMaximumOpcodeByteSize());878llvm::SmallVector<uint8_t, 32> opcode_data;879opcode_data.resize(max_op_byte_size);880881char out_string[512];882const size_t inst_size =883::LLVMDisasmInstruction(m_disasm_context, insn_p, max_op_byte_size, 0,884out_string, sizeof(out_string));885886length = inst_size;887return true;888}889890bool x86AssemblyInspectionEngine::machine_regno_to_lldb_regno(891int machine_regno, uint32_t &lldb_regno) {892MachineRegnumToNameAndLLDBRegnum::iterator it = m_reg_map.find(machine_regno);893if (it != m_reg_map.end()) {894lldb_regno = it->second.lldb_regnum;895return true;896}897return false;898}899900bool x86AssemblyInspectionEngine::GetNonCallSiteUnwindPlanFromAssembly(901uint8_t *data, size_t size, AddressRange &func_range,902UnwindPlan &unwind_plan) {903unwind_plan.Clear();904905if (data == nullptr || size == 0)906return false;907908if (!m_register_map_initialized)909return false;910911if (m_disasm_context == nullptr)912return false;913914addr_t current_func_text_offset = 0;915int current_sp_bytes_offset_from_fa = 0;916bool is_aligned = false;917UnwindPlan::Row::RegisterLocation initial_regloc;918UnwindPlan::RowSP row(new UnwindPlan::Row);919920unwind_plan.SetPlanValidAddressRange(func_range);921unwind_plan.SetRegisterKind(eRegisterKindLLDB);922923// At the start of the function, find the CFA by adding wordsize to the SP924// register925row->SetOffset(current_func_text_offset);926row->GetCFAValue().SetIsRegisterPlusOffset(m_lldb_sp_regnum, m_wordsize);927928// caller's stack pointer value before the call insn is the CFA address929initial_regloc.SetIsCFAPlusOffset(0);930row->SetRegisterInfo(m_lldb_sp_regnum, initial_regloc);931932// saved instruction pointer can be found at CFA - wordsize.933current_sp_bytes_offset_from_fa = m_wordsize;934initial_regloc.SetAtCFAPlusOffset(-current_sp_bytes_offset_from_fa);935row->SetRegisterInfo(m_lldb_ip_regnum, initial_regloc);936937unwind_plan.AppendRow(row);938939// Allocate a new Row, populate it with the existing Row contents.940UnwindPlan::Row *newrow = new UnwindPlan::Row;941*newrow = *row.get();942row.reset(newrow);943944// Track which registers have been saved so far in the prologue. If we see945// another push of that register, it's not part of the prologue. The register946// numbers used here are the machine register #'s (i386_register_numbers,947// x86_64_register_numbers).948std::vector<bool> saved_registers(32, false);949950// Once the prologue has completed we'll save a copy of the unwind951// instructions If there is an epilogue in the middle of the function, after952// that epilogue we'll reinstate the unwind setup -- we assume that some code953// path jumps over the mid-function epilogue954955UnwindPlan::RowSP prologue_completed_row; // copy of prologue row of CFI956int prologue_completed_sp_bytes_offset_from_cfa = 0; // The sp value before the957// epilogue started executed958bool prologue_completed_is_aligned = false;959std::vector<bool> prologue_completed_saved_registers;960961while (current_func_text_offset < size) {962int stack_offset, insn_len;963int machine_regno; // register numbers masked directly out of instructions964uint32_t lldb_regno; // register numbers in lldb's eRegisterKindLLDB965// numbering scheme966967bool in_epilogue = false; // we're in the middle of an epilogue sequence968bool row_updated = false; // The UnwindPlan::Row 'row' has been updated969970m_cur_insn = data + current_func_text_offset;971if (!instruction_length(m_cur_insn, insn_len, size - current_func_text_offset)972|| insn_len == 0973|| insn_len > kMaxInstructionByteSize) {974// An unrecognized/junk instruction975break;976}977978auto &cfa_value = row->GetCFAValue();979auto &afa_value = row->GetAFAValue();980auto fa_value_ptr = is_aligned ? &afa_value : &cfa_value;981982if (mov_rsp_rbp_pattern_p()) {983if (fa_value_ptr->GetRegisterNumber() == m_lldb_sp_regnum) {984fa_value_ptr->SetIsRegisterPlusOffset(985m_lldb_fp_regnum, fa_value_ptr->GetOffset());986row_updated = true;987}988}989990else if (mov_rsp_rbx_pattern_p()) {991if (fa_value_ptr->GetRegisterNumber() == m_lldb_sp_regnum) {992fa_value_ptr->SetIsRegisterPlusOffset(993m_lldb_alt_fp_regnum, fa_value_ptr->GetOffset());994row_updated = true;995}996}997998else if (and_rsp_pattern_p()) {999current_sp_bytes_offset_from_fa = 0;1000afa_value.SetIsRegisterPlusOffset(1001m_lldb_sp_regnum, current_sp_bytes_offset_from_fa);1002fa_value_ptr = &afa_value;1003is_aligned = true;1004row_updated = true;1005}10061007else if (mov_rbp_rsp_pattern_p()) {1008if (is_aligned && cfa_value.GetRegisterNumber() == m_lldb_fp_regnum)1009{1010is_aligned = false;1011fa_value_ptr = &cfa_value;1012afa_value.SetUnspecified();1013row_updated = true;1014}1015if (fa_value_ptr->GetRegisterNumber() == m_lldb_fp_regnum)1016current_sp_bytes_offset_from_fa = fa_value_ptr->GetOffset();1017}10181019else if (mov_rbx_rsp_pattern_p()) {1020if (is_aligned && cfa_value.GetRegisterNumber() == m_lldb_alt_fp_regnum)1021{1022is_aligned = false;1023fa_value_ptr = &cfa_value;1024afa_value.SetUnspecified();1025row_updated = true;1026}1027if (fa_value_ptr->GetRegisterNumber() == m_lldb_alt_fp_regnum)1028current_sp_bytes_offset_from_fa = fa_value_ptr->GetOffset();1029}10301031// This is the start() function (or a pthread equivalent), it starts with a1032// pushl $0x0 which puts the saved pc value of 0 on the stack. In this1033// case we want to pretend we didn't see a stack movement at all --1034// normally the saved pc value is already on the stack by the time the1035// function starts executing.1036else if (push_0_pattern_p()) {1037}10381039else if (push_reg_p(machine_regno)) {1040current_sp_bytes_offset_from_fa += m_wordsize;1041// the PUSH instruction has moved the stack pointer - if the FA is set1042// in terms of the stack pointer, we need to add a new row of1043// instructions.1044if (fa_value_ptr->GetRegisterNumber() == m_lldb_sp_regnum) {1045fa_value_ptr->SetOffset(current_sp_bytes_offset_from_fa);1046row_updated = true;1047}1048// record where non-volatile (callee-saved, spilled) registers are saved1049// on the stack1050if (nonvolatile_reg_p(machine_regno) &&1051machine_regno_to_lldb_regno(machine_regno, lldb_regno) &&1052!saved_registers[machine_regno]) {1053UnwindPlan::Row::RegisterLocation regloc;1054if (is_aligned)1055regloc.SetAtAFAPlusOffset(-current_sp_bytes_offset_from_fa);1056else1057regloc.SetAtCFAPlusOffset(-current_sp_bytes_offset_from_fa);1058row->SetRegisterInfo(lldb_regno, regloc);1059saved_registers[machine_regno] = true;1060row_updated = true;1061}1062}10631064else if (pop_reg_p(machine_regno)) {1065current_sp_bytes_offset_from_fa -= m_wordsize;10661067if (nonvolatile_reg_p(machine_regno) &&1068machine_regno_to_lldb_regno(machine_regno, lldb_regno) &&1069saved_registers[machine_regno]) {1070saved_registers[machine_regno] = false;1071row->RemoveRegisterInfo(lldb_regno);10721073if (lldb_regno == fa_value_ptr->GetRegisterNumber()) {1074fa_value_ptr->SetIsRegisterPlusOffset(1075m_lldb_sp_regnum, fa_value_ptr->GetOffset());1076}10771078in_epilogue = true;1079row_updated = true;1080}10811082// the POP instruction has moved the stack pointer - if the FA is set in1083// terms of the stack pointer, we need to add a new row of instructions.1084if (fa_value_ptr->GetRegisterNumber() == m_lldb_sp_regnum) {1085fa_value_ptr->SetIsRegisterPlusOffset(1086m_lldb_sp_regnum, current_sp_bytes_offset_from_fa);1087row_updated = true;1088}1089}10901091else if (pop_misc_reg_p()) {1092current_sp_bytes_offset_from_fa -= m_wordsize;1093if (fa_value_ptr->GetRegisterNumber() == m_lldb_sp_regnum) {1094fa_value_ptr->SetIsRegisterPlusOffset(1095m_lldb_sp_regnum, current_sp_bytes_offset_from_fa);1096row_updated = true;1097}1098}10991100// The LEAVE instruction moves the value from rbp into rsp and pops a value1101// off the stack into rbp (restoring the caller's rbp value). It is the1102// opposite of ENTER, or 'push rbp, mov rsp rbp'.1103else if (leave_pattern_p()) {1104if (saved_registers[m_machine_fp_regnum]) {1105saved_registers[m_machine_fp_regnum] = false;1106row->RemoveRegisterInfo(m_lldb_fp_regnum);11071108row_updated = true;1109}11101111if (is_aligned && cfa_value.GetRegisterNumber() == m_lldb_fp_regnum)1112{1113is_aligned = false;1114fa_value_ptr = &cfa_value;1115afa_value.SetUnspecified();1116row_updated = true;1117}11181119if (fa_value_ptr->GetRegisterNumber() == m_lldb_fp_regnum)1120{1121fa_value_ptr->SetIsRegisterPlusOffset(1122m_lldb_sp_regnum, fa_value_ptr->GetOffset());11231124current_sp_bytes_offset_from_fa = fa_value_ptr->GetOffset();1125}11261127current_sp_bytes_offset_from_fa -= m_wordsize;11281129if (fa_value_ptr->GetRegisterNumber() == m_lldb_sp_regnum) {1130fa_value_ptr->SetIsRegisterPlusOffset(1131m_lldb_sp_regnum, current_sp_bytes_offset_from_fa);1132row_updated = true;1133}11341135in_epilogue = true;1136}11371138else if (mov_reg_to_local_stack_frame_p(machine_regno, stack_offset) &&1139nonvolatile_reg_p(machine_regno) &&1140machine_regno_to_lldb_regno(machine_regno, lldb_regno) &&1141!saved_registers[machine_regno]) {1142saved_registers[machine_regno] = true;11431144UnwindPlan::Row::RegisterLocation regloc;11451146// stack_offset for 'movq %r15, -80(%rbp)' will be 80. In the Row, we1147// want to express this as the offset from the FA. If the frame base is1148// rbp (like the above instruction), the FA offset for rbp is probably1149// 16. So we want to say that the value is stored at the FA address -1150// 96.1151if (is_aligned)1152regloc.SetAtAFAPlusOffset(-(stack_offset + fa_value_ptr->GetOffset()));1153else1154regloc.SetAtCFAPlusOffset(-(stack_offset + fa_value_ptr->GetOffset()));11551156row->SetRegisterInfo(lldb_regno, regloc);11571158row_updated = true;1159}11601161else if (sub_rsp_pattern_p(stack_offset)) {1162current_sp_bytes_offset_from_fa += stack_offset;1163if (fa_value_ptr->GetRegisterNumber() == m_lldb_sp_regnum) {1164fa_value_ptr->SetOffset(current_sp_bytes_offset_from_fa);1165row_updated = true;1166}1167}11681169else if (add_rsp_pattern_p(stack_offset)) {1170current_sp_bytes_offset_from_fa -= stack_offset;1171if (fa_value_ptr->GetRegisterNumber() == m_lldb_sp_regnum) {1172fa_value_ptr->SetOffset(current_sp_bytes_offset_from_fa);1173row_updated = true;1174}1175in_epilogue = true;1176}11771178else if (push_extended_pattern_p() || push_imm_pattern_p() ||1179push_misc_reg_p()) {1180current_sp_bytes_offset_from_fa += m_wordsize;1181if (fa_value_ptr->GetRegisterNumber() == m_lldb_sp_regnum) {1182fa_value_ptr->SetOffset(current_sp_bytes_offset_from_fa);1183row_updated = true;1184}1185}11861187else if (lea_rsp_pattern_p(stack_offset)) {1188current_sp_bytes_offset_from_fa -= stack_offset;1189if (fa_value_ptr->GetRegisterNumber() == m_lldb_sp_regnum) {1190fa_value_ptr->SetOffset(current_sp_bytes_offset_from_fa);1191row_updated = true;1192}1193if (stack_offset > 0)1194in_epilogue = true;1195}11961197else if (lea_rbp_rsp_pattern_p(stack_offset)) {1198if (is_aligned &&1199cfa_value.GetRegisterNumber() == m_lldb_fp_regnum) {1200is_aligned = false;1201fa_value_ptr = &cfa_value;1202afa_value.SetUnspecified();1203row_updated = true;1204}1205if (fa_value_ptr->GetRegisterNumber() == m_lldb_fp_regnum) {1206current_sp_bytes_offset_from_fa =1207fa_value_ptr->GetOffset() - stack_offset;1208}1209}12101211else if (lea_rbx_rsp_pattern_p(stack_offset)) {1212if (is_aligned &&1213cfa_value.GetRegisterNumber() == m_lldb_alt_fp_regnum) {1214is_aligned = false;1215fa_value_ptr = &cfa_value;1216afa_value.SetUnspecified();1217row_updated = true;1218}1219if (fa_value_ptr->GetRegisterNumber() == m_lldb_alt_fp_regnum) {1220current_sp_bytes_offset_from_fa = fa_value_ptr->GetOffset() - stack_offset;1221}1222}12231224else if (prologue_completed_row.get() &&1225(ret_pattern_p() ||1226non_local_branch_p (current_func_text_offset, func_range, insn_len) ||1227jmp_to_reg_p())) {1228// Check if the current instruction is the end of an epilogue sequence,1229// and if so, re-instate the prologue-completed unwind state.12301231// The current instruction is a branch/jump outside this function,1232// a ret, or a jump through a register value which we cannot1233// determine the effcts of. Verify that the stack frame state1234// has been unwound to the same as it was at function entry to avoid1235// mis-identifying a JMP instruction as an epilogue.1236UnwindPlan::Row::RegisterLocation sp, pc;1237if (row->GetRegisterInfo(m_lldb_sp_regnum, sp) &&1238row->GetRegisterInfo(m_lldb_ip_regnum, pc)) {1239// Any ret instruction variant is definitely indicative of an1240// epilogue; for other insn patterns verify that we're back to1241// the original unwind state.1242if (ret_pattern_p() ||1243(sp.IsCFAPlusOffset() && sp.GetOffset() == 0 &&1244pc.IsAtCFAPlusOffset() && pc.GetOffset() == -m_wordsize)) {1245// Reinstate the saved prologue setup for any instructions that come1246// after the epilogue12471248UnwindPlan::Row *newrow = new UnwindPlan::Row;1249*newrow = *prologue_completed_row.get();1250row.reset(newrow);1251current_sp_bytes_offset_from_fa =1252prologue_completed_sp_bytes_offset_from_cfa;1253is_aligned = prologue_completed_is_aligned;12541255saved_registers.clear();1256saved_registers.resize(prologue_completed_saved_registers.size(), false);1257for (size_t i = 0; i < prologue_completed_saved_registers.size(); ++i) {1258saved_registers[i] = prologue_completed_saved_registers[i];1259}12601261in_epilogue = true;1262row_updated = true;1263}1264}1265}12661267// call next instruction1268// call 01269// => pop %ebx1270// This is used in i386 programs to get the PIC base address for finding1271// global data1272else if (call_next_insn_pattern_p()) {1273current_sp_bytes_offset_from_fa += m_wordsize;1274if (fa_value_ptr->GetRegisterNumber() == m_lldb_sp_regnum) {1275fa_value_ptr->SetOffset(current_sp_bytes_offset_from_fa);1276row_updated = true;1277}1278}12791280if (row_updated) {1281if (current_func_text_offset + insn_len < size) {1282row->SetOffset(current_func_text_offset + insn_len);1283unwind_plan.AppendRow(row);1284// Allocate a new Row, populate it with the existing Row contents.1285newrow = new UnwindPlan::Row;1286*newrow = *row.get();1287row.reset(newrow);1288}1289}12901291if (!in_epilogue && row_updated) {1292// If we're not in an epilogue sequence, save the updated Row1293UnwindPlan::Row *newrow = new UnwindPlan::Row;1294*newrow = *row.get();1295prologue_completed_row.reset(newrow);12961297prologue_completed_saved_registers.clear();1298prologue_completed_saved_registers.resize(saved_registers.size(), false);1299for (size_t i = 0; i < saved_registers.size(); ++i) {1300prologue_completed_saved_registers[i] = saved_registers[i];1301}1302}13031304// We may change the sp value without adding a new Row necessarily -- keep1305// track of it either way.1306if (!in_epilogue) {1307prologue_completed_sp_bytes_offset_from_cfa =1308current_sp_bytes_offset_from_fa;1309prologue_completed_is_aligned = is_aligned;1310}13111312m_cur_insn = m_cur_insn + insn_len;1313current_func_text_offset += insn_len;1314}13151316unwind_plan.SetSourceName("assembly insn profiling");1317unwind_plan.SetSourcedFromCompiler(eLazyBoolNo);1318unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolYes);1319unwind_plan.SetUnwindPlanForSignalTrap(eLazyBoolNo);13201321return true;1322}13231324bool x86AssemblyInspectionEngine::AugmentUnwindPlanFromCallSite(1325uint8_t *data, size_t size, AddressRange &func_range,1326UnwindPlan &unwind_plan, RegisterContextSP ®_ctx) {1327Address addr_start = func_range.GetBaseAddress();1328if (!addr_start.IsValid())1329return false;13301331// We either need a live RegisterContext, or we need the UnwindPlan to1332// already be in the lldb register numbering scheme.1333if (reg_ctx.get() == nullptr &&1334unwind_plan.GetRegisterKind() != eRegisterKindLLDB)1335return false;13361337// Is original unwind_plan valid?1338// unwind_plan should have at least one row which is ABI-default (CFA1339// register is sp), and another row in mid-function.1340if (unwind_plan.GetRowCount() < 2)1341return false;13421343UnwindPlan::RowSP first_row = unwind_plan.GetRowAtIndex(0);1344if (first_row->GetOffset() != 0)1345return false;1346uint32_t cfa_reg = first_row->GetCFAValue().GetRegisterNumber();1347if (unwind_plan.GetRegisterKind() != eRegisterKindLLDB) {1348cfa_reg = reg_ctx->ConvertRegisterKindToRegisterNumber(1349unwind_plan.GetRegisterKind(),1350first_row->GetCFAValue().GetRegisterNumber());1351}1352if (cfa_reg != m_lldb_sp_regnum ||1353first_row->GetCFAValue().GetOffset() != m_wordsize)1354return false;13551356UnwindPlan::RowSP original_last_row = unwind_plan.GetRowForFunctionOffset(-1);13571358size_t offset = 0;1359int row_id = 1;1360bool unwind_plan_updated = false;1361UnwindPlan::RowSP row(new UnwindPlan::Row(*first_row));13621363// After a mid-function epilogue we will need to re-insert the original1364// unwind rules so unwinds work for the remainder of the function. These1365// aren't common with clang/gcc on x86 but it is possible.1366bool reinstate_unwind_state = false;13671368while (offset < size) {1369m_cur_insn = data + offset;1370int insn_len;1371if (!instruction_length(m_cur_insn, insn_len, size - offset) ||1372insn_len == 0 || insn_len > kMaxInstructionByteSize) {1373// An unrecognized/junk instruction.1374break;1375}13761377// Advance offsets.1378offset += insn_len;13791380// offset is pointing beyond the bounds of the function; stop looping.1381if (offset >= size)1382continue;13831384if (reinstate_unwind_state) {1385UnwindPlan::RowSP new_row(new UnwindPlan::Row());1386*new_row = *original_last_row;1387new_row->SetOffset(offset);1388unwind_plan.AppendRow(new_row);1389row = std::make_shared<UnwindPlan::Row>();1390*row = *new_row;1391reinstate_unwind_state = false;1392unwind_plan_updated = true;1393continue;1394}13951396// If we already have one row for this instruction, we can continue.1397while (row_id < unwind_plan.GetRowCount() &&1398unwind_plan.GetRowAtIndex(row_id)->GetOffset() <= offset) {1399row_id++;1400}1401UnwindPlan::RowSP original_row = unwind_plan.GetRowAtIndex(row_id - 1);1402if (original_row->GetOffset() == offset) {1403*row = *original_row;1404continue;1405}14061407if (row_id == 0) {1408// If we are here, compiler didn't generate CFI for prologue. This won't1409// happen to GCC or clang. In this case, bail out directly.1410return false;1411}14121413// Inspect the instruction to check if we need a new row for it.1414cfa_reg = row->GetCFAValue().GetRegisterNumber();1415if (unwind_plan.GetRegisterKind() != eRegisterKindLLDB) {1416cfa_reg = reg_ctx->ConvertRegisterKindToRegisterNumber(1417unwind_plan.GetRegisterKind(),1418row->GetCFAValue().GetRegisterNumber());1419}1420if (cfa_reg == m_lldb_sp_regnum) {1421// CFA register is sp.14221423// call next instruction1424// call 01425// => pop %ebx1426if (call_next_insn_pattern_p()) {1427row->SetOffset(offset);1428row->GetCFAValue().IncOffset(m_wordsize);14291430UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row));1431unwind_plan.InsertRow(new_row);1432unwind_plan_updated = true;1433continue;1434}14351436// push/pop register1437int regno;1438if (push_reg_p(regno)) {1439row->SetOffset(offset);1440row->GetCFAValue().IncOffset(m_wordsize);14411442UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row));1443unwind_plan.InsertRow(new_row);1444unwind_plan_updated = true;1445continue;1446}1447if (pop_reg_p(regno)) {1448// Technically, this might be a nonvolatile register recover in1449// epilogue. We should reset RegisterInfo for the register. But in1450// practice, previous rule for the register is still valid... So we1451// ignore this case.14521453row->SetOffset(offset);1454row->GetCFAValue().IncOffset(-m_wordsize);14551456UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row));1457unwind_plan.InsertRow(new_row);1458unwind_plan_updated = true;1459continue;1460}14611462if (pop_misc_reg_p()) {1463row->SetOffset(offset);1464row->GetCFAValue().IncOffset(-m_wordsize);14651466UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row));1467unwind_plan.InsertRow(new_row);1468unwind_plan_updated = true;1469continue;1470}14711472// push imm1473if (push_imm_pattern_p()) {1474row->SetOffset(offset);1475row->GetCFAValue().IncOffset(m_wordsize);1476UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row));1477unwind_plan.InsertRow(new_row);1478unwind_plan_updated = true;1479continue;1480}14811482// push extended1483if (push_extended_pattern_p() || push_misc_reg_p()) {1484row->SetOffset(offset);1485row->GetCFAValue().IncOffset(m_wordsize);1486UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row));1487unwind_plan.InsertRow(new_row);1488unwind_plan_updated = true;1489continue;1490}14911492// add/sub %rsp/%esp1493int amount;1494if (add_rsp_pattern_p(amount)) {1495row->SetOffset(offset);1496row->GetCFAValue().IncOffset(-amount);14971498UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row));1499unwind_plan.InsertRow(new_row);1500unwind_plan_updated = true;1501continue;1502}1503if (sub_rsp_pattern_p(amount)) {1504row->SetOffset(offset);1505row->GetCFAValue().IncOffset(amount);15061507UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row));1508unwind_plan.InsertRow(new_row);1509unwind_plan_updated = true;1510continue;1511}15121513// lea %rsp, [%rsp + $offset]1514if (lea_rsp_pattern_p(amount)) {1515row->SetOffset(offset);1516row->GetCFAValue().IncOffset(-amount);15171518UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row));1519unwind_plan.InsertRow(new_row);1520unwind_plan_updated = true;1521continue;1522}15231524if (ret_pattern_p()) {1525reinstate_unwind_state = true;1526continue;1527}1528} else if (cfa_reg == m_lldb_fp_regnum) {1529// CFA register is fp.15301531// The only case we care about is epilogue:1532// [0x5d] pop %rbp/%ebp1533// => [0xc3] ret1534if (pop_rbp_pattern_p() || leave_pattern_p()) {1535m_cur_insn++;1536if (ret_pattern_p()) {1537row->SetOffset(offset);1538row->GetCFAValue().SetIsRegisterPlusOffset(1539first_row->GetCFAValue().GetRegisterNumber(), m_wordsize);15401541UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row));1542unwind_plan.InsertRow(new_row);1543unwind_plan_updated = true;1544reinstate_unwind_state = true;1545continue;1546}1547}1548} else {1549// CFA register is not sp or fp.15501551// This must be hand-written assembly.1552// Just trust eh_frame and assume we have finished.1553break;1554}1555}15561557unwind_plan.SetPlanValidAddressRange(func_range);1558if (unwind_plan_updated) {1559std::string unwind_plan_source(unwind_plan.GetSourceName().AsCString());1560unwind_plan_source += " plus augmentation from assembly parsing";1561unwind_plan.SetSourceName(unwind_plan_source.c_str());1562unwind_plan.SetSourcedFromCompiler(eLazyBoolNo);1563unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolYes);1564}1565return true;1566}15671568bool x86AssemblyInspectionEngine::FindFirstNonPrologueInstruction(1569uint8_t *data, size_t size, size_t &offset) {1570offset = 0;15711572if (!m_register_map_initialized)1573return false;15741575if (m_disasm_context == nullptr)1576return false;15771578while (offset < size) {1579int regno;1580int insn_len;1581int scratch;15821583m_cur_insn = data + offset;1584if (!instruction_length(m_cur_insn, insn_len, size - offset)1585|| insn_len > kMaxInstructionByteSize1586|| insn_len == 0) {1587// An error parsing the instruction, i.e. probably data/garbage - stop1588// scanning1589break;1590}15911592if (push_rbp_pattern_p() || mov_rsp_rbp_pattern_p() ||1593sub_rsp_pattern_p(scratch) || push_reg_p(regno) ||1594mov_reg_to_local_stack_frame_p(regno, scratch) ||1595(lea_rsp_pattern_p(scratch) && offset == 0)) {1596offset += insn_len;1597continue;1598}1599//1600// Unknown non-prologue instruction - stop scanning1601break;1602}16031604return true;1605}160616071608