1311128Sdim//===-- x86AssemblyInspectionEngine.cpp -------------------------*- C++ -*-===// 2311128Sdim// 3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4353358Sdim// See https://llvm.org/LICENSE.txt for license information. 5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6311128Sdim// 7311128Sdim//===----------------------------------------------------------------------===// 8311128Sdim 9311128Sdim#include "x86AssemblyInspectionEngine.h" 10311128Sdim 11353358Sdim#include <memory> 12353358Sdim 13311128Sdim#include "llvm-c/Disassembler.h" 14311128Sdim 15311128Sdim#include "lldb/Core/Address.h" 16311128Sdim#include "lldb/Symbol/UnwindPlan.h" 17311128Sdim#include "lldb/Target/RegisterContext.h" 18311128Sdim#include "lldb/Target/UnwindAssembly.h" 19311128Sdim 20311128Sdimusing namespace lldb_private; 21311128Sdimusing namespace lldb; 22311128Sdim 23311128Sdimx86AssemblyInspectionEngine::x86AssemblyInspectionEngine(const ArchSpec &arch) 24311128Sdim : m_cur_insn(nullptr), m_machine_ip_regnum(LLDB_INVALID_REGNUM), 25311128Sdim m_machine_sp_regnum(LLDB_INVALID_REGNUM), 26311128Sdim m_machine_fp_regnum(LLDB_INVALID_REGNUM), 27311128Sdim m_lldb_ip_regnum(LLDB_INVALID_REGNUM), 28311128Sdim m_lldb_sp_regnum(LLDB_INVALID_REGNUM), 29311128Sdim m_lldb_fp_regnum(LLDB_INVALID_REGNUM), 30311128Sdim 31311128Sdim m_reg_map(), m_arch(arch), m_cpu(k_cpu_unspecified), m_wordsize(-1), 32311128Sdim m_register_map_initialized(false), m_disasm_context() { 33311128Sdim m_disasm_context = 34311128Sdim ::LLVMCreateDisasm(arch.GetTriple().getTriple().c_str(), nullptr, 35311128Sdim /*TagType=*/1, nullptr, nullptr); 36311128Sdim} 37311128Sdim 38311128Sdimx86AssemblyInspectionEngine::~x86AssemblyInspectionEngine() { 39311128Sdim ::LLVMDisasmDispose(m_disasm_context); 40311128Sdim} 41311128Sdim 42311128Sdimvoid x86AssemblyInspectionEngine::Initialize(RegisterContextSP ®_ctx) { 43311128Sdim m_cpu = k_cpu_unspecified; 44311128Sdim m_wordsize = -1; 45311128Sdim m_register_map_initialized = false; 46311128Sdim 47311128Sdim const llvm::Triple::ArchType cpu = m_arch.GetMachine(); 48311128Sdim if (cpu == llvm::Triple::x86) 49311128Sdim m_cpu = k_i386; 50311128Sdim else if (cpu == llvm::Triple::x86_64) 51311128Sdim m_cpu = k_x86_64; 52311128Sdim 53311128Sdim if (m_cpu == k_cpu_unspecified) 54311128Sdim return; 55311128Sdim 56311128Sdim if (reg_ctx.get() == nullptr) 57311128Sdim return; 58311128Sdim 59311128Sdim if (m_cpu == k_i386) { 60311128Sdim m_machine_ip_regnum = k_machine_eip; 61311128Sdim m_machine_sp_regnum = k_machine_esp; 62311128Sdim m_machine_fp_regnum = k_machine_ebp; 63344779Sdim m_machine_alt_fp_regnum = k_machine_ebx; 64311128Sdim m_wordsize = 4; 65311128Sdim 66311128Sdim struct lldb_reg_info reginfo; 67311128Sdim reginfo.name = "eax"; 68311128Sdim m_reg_map[k_machine_eax] = reginfo; 69311128Sdim reginfo.name = "edx"; 70311128Sdim m_reg_map[k_machine_edx] = reginfo; 71311128Sdim reginfo.name = "esp"; 72311128Sdim m_reg_map[k_machine_esp] = reginfo; 73311128Sdim reginfo.name = "esi"; 74311128Sdim m_reg_map[k_machine_esi] = reginfo; 75311128Sdim reginfo.name = "eip"; 76311128Sdim m_reg_map[k_machine_eip] = reginfo; 77311128Sdim reginfo.name = "ecx"; 78311128Sdim m_reg_map[k_machine_ecx] = reginfo; 79311128Sdim reginfo.name = "ebx"; 80311128Sdim m_reg_map[k_machine_ebx] = reginfo; 81311128Sdim reginfo.name = "ebp"; 82311128Sdim m_reg_map[k_machine_ebp] = reginfo; 83311128Sdim reginfo.name = "edi"; 84311128Sdim m_reg_map[k_machine_edi] = reginfo; 85311128Sdim } else { 86311128Sdim m_machine_ip_regnum = k_machine_rip; 87311128Sdim m_machine_sp_regnum = k_machine_rsp; 88311128Sdim m_machine_fp_regnum = k_machine_rbp; 89344779Sdim m_machine_alt_fp_regnum = k_machine_rbx; 90311128Sdim m_wordsize = 8; 91311128Sdim 92311128Sdim struct lldb_reg_info reginfo; 93311128Sdim reginfo.name = "rax"; 94311128Sdim m_reg_map[k_machine_rax] = reginfo; 95311128Sdim reginfo.name = "rdx"; 96311128Sdim m_reg_map[k_machine_rdx] = reginfo; 97311128Sdim reginfo.name = "rsp"; 98311128Sdim m_reg_map[k_machine_rsp] = reginfo; 99311128Sdim reginfo.name = "rsi"; 100311128Sdim m_reg_map[k_machine_rsi] = reginfo; 101311128Sdim reginfo.name = "r8"; 102311128Sdim m_reg_map[k_machine_r8] = reginfo; 103311128Sdim reginfo.name = "r10"; 104311128Sdim m_reg_map[k_machine_r10] = reginfo; 105311128Sdim reginfo.name = "r12"; 106311128Sdim m_reg_map[k_machine_r12] = reginfo; 107311128Sdim reginfo.name = "r14"; 108311128Sdim m_reg_map[k_machine_r14] = reginfo; 109311128Sdim reginfo.name = "rip"; 110311128Sdim m_reg_map[k_machine_rip] = reginfo; 111311128Sdim reginfo.name = "rcx"; 112311128Sdim m_reg_map[k_machine_rcx] = reginfo; 113311128Sdim reginfo.name = "rbx"; 114311128Sdim m_reg_map[k_machine_rbx] = reginfo; 115311128Sdim reginfo.name = "rbp"; 116311128Sdim m_reg_map[k_machine_rbp] = reginfo; 117311128Sdim reginfo.name = "rdi"; 118311128Sdim m_reg_map[k_machine_rdi] = reginfo; 119311128Sdim reginfo.name = "r9"; 120311128Sdim m_reg_map[k_machine_r9] = reginfo; 121311128Sdim reginfo.name = "r11"; 122311128Sdim m_reg_map[k_machine_r11] = reginfo; 123311128Sdim reginfo.name = "r13"; 124311128Sdim m_reg_map[k_machine_r13] = reginfo; 125311128Sdim reginfo.name = "r15"; 126311128Sdim m_reg_map[k_machine_r15] = reginfo; 127311128Sdim } 128311128Sdim 129311128Sdim for (MachineRegnumToNameAndLLDBRegnum::iterator it = m_reg_map.begin(); 130311128Sdim it != m_reg_map.end(); ++it) { 131311128Sdim const RegisterInfo *ri = reg_ctx->GetRegisterInfoByName(it->second.name); 132311128Sdim if (ri) 133311128Sdim it->second.lldb_regnum = ri->kinds[eRegisterKindLLDB]; 134311128Sdim } 135311128Sdim 136311128Sdim uint32_t lldb_regno; 137311128Sdim if (machine_regno_to_lldb_regno(m_machine_sp_regnum, lldb_regno)) 138311128Sdim m_lldb_sp_regnum = lldb_regno; 139311128Sdim if (machine_regno_to_lldb_regno(m_machine_fp_regnum, lldb_regno)) 140311128Sdim m_lldb_fp_regnum = lldb_regno; 141344779Sdim if (machine_regno_to_lldb_regno(m_machine_alt_fp_regnum, lldb_regno)) 142344779Sdim m_lldb_alt_fp_regnum = lldb_regno; 143311128Sdim if (machine_regno_to_lldb_regno(m_machine_ip_regnum, lldb_regno)) 144311128Sdim m_lldb_ip_regnum = lldb_regno; 145311128Sdim 146311128Sdim m_register_map_initialized = true; 147311128Sdim} 148311128Sdim 149311128Sdimvoid x86AssemblyInspectionEngine::Initialize( 150311128Sdim std::vector<lldb_reg_info> ®_info) { 151311128Sdim m_cpu = k_cpu_unspecified; 152311128Sdim m_wordsize = -1; 153311128Sdim m_register_map_initialized = false; 154311128Sdim 155311128Sdim const llvm::Triple::ArchType cpu = m_arch.GetMachine(); 156311128Sdim if (cpu == llvm::Triple::x86) 157311128Sdim m_cpu = k_i386; 158311128Sdim else if (cpu == llvm::Triple::x86_64) 159311128Sdim m_cpu = k_x86_64; 160311128Sdim 161311128Sdim if (m_cpu == k_cpu_unspecified) 162311128Sdim return; 163311128Sdim 164311128Sdim if (m_cpu == k_i386) { 165311128Sdim m_machine_ip_regnum = k_machine_eip; 166311128Sdim m_machine_sp_regnum = k_machine_esp; 167311128Sdim m_machine_fp_regnum = k_machine_ebp; 168344779Sdim m_machine_alt_fp_regnum = k_machine_ebx; 169311128Sdim m_wordsize = 4; 170311128Sdim 171311128Sdim struct lldb_reg_info reginfo; 172311128Sdim reginfo.name = "eax"; 173311128Sdim m_reg_map[k_machine_eax] = reginfo; 174311128Sdim reginfo.name = "edx"; 175311128Sdim m_reg_map[k_machine_edx] = reginfo; 176311128Sdim reginfo.name = "esp"; 177311128Sdim m_reg_map[k_machine_esp] = reginfo; 178311128Sdim reginfo.name = "esi"; 179311128Sdim m_reg_map[k_machine_esi] = reginfo; 180311128Sdim reginfo.name = "eip"; 181311128Sdim m_reg_map[k_machine_eip] = reginfo; 182311128Sdim reginfo.name = "ecx"; 183311128Sdim m_reg_map[k_machine_ecx] = reginfo; 184311128Sdim reginfo.name = "ebx"; 185311128Sdim m_reg_map[k_machine_ebx] = reginfo; 186311128Sdim reginfo.name = "ebp"; 187311128Sdim m_reg_map[k_machine_ebp] = reginfo; 188311128Sdim reginfo.name = "edi"; 189311128Sdim m_reg_map[k_machine_edi] = reginfo; 190311128Sdim } else { 191311128Sdim m_machine_ip_regnum = k_machine_rip; 192311128Sdim m_machine_sp_regnum = k_machine_rsp; 193311128Sdim m_machine_fp_regnum = k_machine_rbp; 194344779Sdim m_machine_alt_fp_regnum = k_machine_rbx; 195311128Sdim m_wordsize = 8; 196311128Sdim 197311128Sdim struct lldb_reg_info reginfo; 198311128Sdim reginfo.name = "rax"; 199311128Sdim m_reg_map[k_machine_rax] = reginfo; 200311128Sdim reginfo.name = "rdx"; 201311128Sdim m_reg_map[k_machine_rdx] = reginfo; 202311128Sdim reginfo.name = "rsp"; 203311128Sdim m_reg_map[k_machine_rsp] = reginfo; 204311128Sdim reginfo.name = "rsi"; 205311128Sdim m_reg_map[k_machine_rsi] = reginfo; 206311128Sdim reginfo.name = "r8"; 207311128Sdim m_reg_map[k_machine_r8] = reginfo; 208311128Sdim reginfo.name = "r10"; 209311128Sdim m_reg_map[k_machine_r10] = reginfo; 210311128Sdim reginfo.name = "r12"; 211311128Sdim m_reg_map[k_machine_r12] = reginfo; 212311128Sdim reginfo.name = "r14"; 213311128Sdim m_reg_map[k_machine_r14] = reginfo; 214311128Sdim reginfo.name = "rip"; 215311128Sdim m_reg_map[k_machine_rip] = reginfo; 216311128Sdim reginfo.name = "rcx"; 217311128Sdim m_reg_map[k_machine_rcx] = reginfo; 218311128Sdim reginfo.name = "rbx"; 219311128Sdim m_reg_map[k_machine_rbx] = reginfo; 220311128Sdim reginfo.name = "rbp"; 221311128Sdim m_reg_map[k_machine_rbp] = reginfo; 222311128Sdim reginfo.name = "rdi"; 223311128Sdim m_reg_map[k_machine_rdi] = reginfo; 224311128Sdim reginfo.name = "r9"; 225311128Sdim m_reg_map[k_machine_r9] = reginfo; 226311128Sdim reginfo.name = "r11"; 227311128Sdim m_reg_map[k_machine_r11] = reginfo; 228311128Sdim reginfo.name = "r13"; 229311128Sdim m_reg_map[k_machine_r13] = reginfo; 230311128Sdim reginfo.name = "r15"; 231311128Sdim m_reg_map[k_machine_r15] = reginfo; 232311128Sdim } 233311128Sdim 234311128Sdim for (MachineRegnumToNameAndLLDBRegnum::iterator it = m_reg_map.begin(); 235311128Sdim it != m_reg_map.end(); ++it) { 236311128Sdim for (size_t i = 0; i < reg_info.size(); ++i) { 237311128Sdim if (::strcmp(reg_info[i].name, it->second.name) == 0) { 238311128Sdim it->second.lldb_regnum = reg_info[i].lldb_regnum; 239311128Sdim break; 240311128Sdim } 241311128Sdim } 242311128Sdim } 243311128Sdim 244311128Sdim uint32_t lldb_regno; 245311128Sdim if (machine_regno_to_lldb_regno(m_machine_sp_regnum, lldb_regno)) 246311128Sdim m_lldb_sp_regnum = lldb_regno; 247311128Sdim if (machine_regno_to_lldb_regno(m_machine_fp_regnum, lldb_regno)) 248311128Sdim m_lldb_fp_regnum = lldb_regno; 249344779Sdim if (machine_regno_to_lldb_regno(m_machine_alt_fp_regnum, lldb_regno)) 250344779Sdim m_lldb_alt_fp_regnum = lldb_regno; 251311128Sdim if (machine_regno_to_lldb_regno(m_machine_ip_regnum, lldb_regno)) 252311128Sdim m_lldb_ip_regnum = lldb_regno; 253311128Sdim 254311128Sdim m_register_map_initialized = true; 255311128Sdim} 256311128Sdim 257311128Sdim// This function expects an x86 native register number (i.e. the bits stripped 258341825Sdim// out of the actual instruction), not an lldb register number. 259311128Sdim// 260311128Sdim// FIXME: This is ABI dependent, it shouldn't be hardcoded here. 261311128Sdim 262311128Sdimbool x86AssemblyInspectionEngine::nonvolatile_reg_p(int machine_regno) { 263311128Sdim if (m_cpu == k_i386) { 264311128Sdim switch (machine_regno) { 265311128Sdim case k_machine_ebx: 266311128Sdim case k_machine_ebp: // not actually a nonvolatile but often treated as such 267311128Sdim // by convention 268311128Sdim case k_machine_esi: 269311128Sdim case k_machine_edi: 270311128Sdim case k_machine_esp: 271311128Sdim return true; 272311128Sdim default: 273311128Sdim return false; 274311128Sdim } 275311128Sdim } 276311128Sdim if (m_cpu == k_x86_64) { 277311128Sdim switch (machine_regno) { 278311128Sdim case k_machine_rbx: 279311128Sdim case k_machine_rsp: 280311128Sdim case k_machine_rbp: // not actually a nonvolatile but often treated as such 281311128Sdim // by convention 282311128Sdim case k_machine_r12: 283311128Sdim case k_machine_r13: 284311128Sdim case k_machine_r14: 285311128Sdim case k_machine_r15: 286311128Sdim return true; 287311128Sdim default: 288311128Sdim return false; 289311128Sdim } 290311128Sdim } 291311128Sdim return false; 292311128Sdim} 293311128Sdim 294311128Sdim// Macro to detect if this is a REX mode prefix byte. 295311128Sdim#define REX_W_PREFIX_P(opcode) (((opcode) & (~0x5)) == 0x48) 296311128Sdim 297311128Sdim// The high bit which should be added to the source register number (the "R" 298311128Sdim// bit) 299311128Sdim#define REX_W_SRCREG(opcode) (((opcode)&0x4) >> 2) 300311128Sdim 301311128Sdim// The high bit which should be added to the destination register number (the 302311128Sdim// "B" bit) 303311128Sdim#define REX_W_DSTREG(opcode) ((opcode)&0x1) 304311128Sdim 305311128Sdim// pushq %rbp [0x55] 306311128Sdimbool x86AssemblyInspectionEngine::push_rbp_pattern_p() { 307311128Sdim uint8_t *p = m_cur_insn; 308344779Sdim return *p == 0x55; 309311128Sdim} 310311128Sdim 311311128Sdim// pushq $0 ; the first instruction in start() [0x6a 0x00] 312311128Sdimbool x86AssemblyInspectionEngine::push_0_pattern_p() { 313311128Sdim uint8_t *p = m_cur_insn; 314344779Sdim return *p == 0x6a && *(p + 1) == 0x0; 315311128Sdim} 316311128Sdim 317311128Sdim// pushq $0 318311128Sdim// pushl $0 319311128Sdimbool x86AssemblyInspectionEngine::push_imm_pattern_p() { 320311128Sdim uint8_t *p = m_cur_insn; 321344779Sdim return *p == 0x68 || *p == 0x6a; 322311128Sdim} 323311128Sdim 324311128Sdim// pushl imm8(%esp) 325311128Sdim// 326341825Sdim// e.g. 0xff 0x74 0x24 0x20 - 'pushl 0x20(%esp)' (same byte pattern for 'pushq 327341825Sdim// 0x20(%rsp)' in an x86_64 program) 328311128Sdim// 329341825Sdim// 0xff (with opcode bits '6' in next byte, PUSH r/m32) 0x74 (ModR/M byte with 330341825Sdim// three bits used to specify the opcode) 331311128Sdim// mod == b01, opcode == b110, R/M == b100 332311128Sdim// "+disp8" 333341825Sdim// 0x24 (SIB byte - scaled index = 0, r32 == esp) 0x20 imm8 value 334311128Sdim 335311128Sdimbool x86AssemblyInspectionEngine::push_extended_pattern_p() { 336311128Sdim if (*m_cur_insn == 0xff) { 337311128Sdim // Get the 3 opcode bits from the ModR/M byte 338311128Sdim uint8_t opcode = (*(m_cur_insn + 1) >> 3) & 7; 339311128Sdim if (opcode == 6) { 340311128Sdim // I'm only looking for 0xff /6 here - I 341341825Sdim // don't really care what value is being pushed, just that we're pushing 342341825Sdim // a 32/64 bit value on to the stack is enough. 343311128Sdim return true; 344311128Sdim } 345311128Sdim } 346311128Sdim return false; 347311128Sdim} 348311128Sdim 349311128Sdim// instructions only valid in 32-bit mode: 350311128Sdim// 0x0e - push cs 351311128Sdim// 0x16 - push ss 352311128Sdim// 0x1e - push ds 353311128Sdim// 0x06 - push es 354311128Sdimbool x86AssemblyInspectionEngine::push_misc_reg_p() { 355311128Sdim uint8_t p = *m_cur_insn; 356311128Sdim if (m_wordsize == 4) { 357311128Sdim if (p == 0x0e || p == 0x16 || p == 0x1e || p == 0x06) 358311128Sdim return true; 359311128Sdim } 360311128Sdim return false; 361311128Sdim} 362311128Sdim 363311128Sdim// pushq %rbx 364311128Sdim// pushl %ebx 365311128Sdimbool x86AssemblyInspectionEngine::push_reg_p(int ®no) { 366311128Sdim uint8_t *p = m_cur_insn; 367311128Sdim int regno_prefix_bit = 0; 368311128Sdim // If we have a rex prefix byte, check to see if a B bit is set 369353358Sdim if (m_wordsize == 8 && (*p & 0xfe) == 0x40) { 370353358Sdim regno_prefix_bit = (*p & 1) << 3; 371311128Sdim p++; 372311128Sdim } 373311128Sdim if (*p >= 0x50 && *p <= 0x57) { 374311128Sdim regno = (*p - 0x50) | regno_prefix_bit; 375311128Sdim return true; 376311128Sdim } 377311128Sdim return false; 378311128Sdim} 379311128Sdim 380341825Sdim// movq %rsp, %rbp [0x48 0x8b 0xec] or [0x48 0x89 0xe5] movl %esp, %ebp [0x8b 381341825Sdim// 0xec] or [0x89 0xe5] 382311128Sdimbool x86AssemblyInspectionEngine::mov_rsp_rbp_pattern_p() { 383311128Sdim uint8_t *p = m_cur_insn; 384311128Sdim if (m_wordsize == 8 && *p == 0x48) 385311128Sdim p++; 386311128Sdim if (*(p) == 0x8b && *(p + 1) == 0xec) 387311128Sdim return true; 388311128Sdim if (*(p) == 0x89 && *(p + 1) == 0xe5) 389311128Sdim return true; 390311128Sdim return false; 391311128Sdim} 392311128Sdim 393344779Sdim// movq %rsp, %rbx [0x48 0x8b 0xdc] or [0x48 0x89 0xe3] 394344779Sdim// movl %esp, %ebx [0x8b 0xdc] or [0x89 0xe3] 395344779Sdimbool x86AssemblyInspectionEngine::mov_rsp_rbx_pattern_p() { 396344779Sdim uint8_t *p = m_cur_insn; 397344779Sdim if (m_wordsize == 8 && *p == 0x48) 398344779Sdim p++; 399344779Sdim if (*(p) == 0x8b && *(p + 1) == 0xdc) 400344779Sdim return true; 401344779Sdim if (*(p) == 0x89 && *(p + 1) == 0xe3) 402344779Sdim return true; 403344779Sdim return false; 404344779Sdim} 405344779Sdim 406344779Sdim// movq %rbp, %rsp [0x48 0x8b 0xe5] or [0x48 0x89 0xec] 407344779Sdim// movl %ebp, %esp [0x8b 0xe5] or [0x89 0xec] 408344779Sdimbool x86AssemblyInspectionEngine::mov_rbp_rsp_pattern_p() { 409344779Sdim uint8_t *p = m_cur_insn; 410344779Sdim if (m_wordsize == 8 && *p == 0x48) 411344779Sdim p++; 412344779Sdim if (*(p) == 0x8b && *(p + 1) == 0xe5) 413344779Sdim return true; 414344779Sdim if (*(p) == 0x89 && *(p + 1) == 0xec) 415344779Sdim return true; 416344779Sdim return false; 417344779Sdim} 418344779Sdim 419344779Sdim// movq %rbx, %rsp [0x48 0x8b 0xe3] or [0x48 0x89 0xdc] 420344779Sdim// movl %ebx, %esp [0x8b 0xe3] or [0x89 0xdc] 421344779Sdimbool x86AssemblyInspectionEngine::mov_rbx_rsp_pattern_p() { 422344779Sdim uint8_t *p = m_cur_insn; 423344779Sdim if (m_wordsize == 8 && *p == 0x48) 424344779Sdim p++; 425344779Sdim if (*(p) == 0x8b && *(p + 1) == 0xe3) 426344779Sdim return true; 427344779Sdim if (*(p) == 0x89 && *(p + 1) == 0xdc) 428344779Sdim return true; 429344779Sdim return false; 430344779Sdim} 431344779Sdim 432311128Sdim// subq $0x20, %rsp 433311128Sdimbool x86AssemblyInspectionEngine::sub_rsp_pattern_p(int &amount) { 434311128Sdim uint8_t *p = m_cur_insn; 435311128Sdim if (m_wordsize == 8 && *p == 0x48) 436311128Sdim p++; 437311128Sdim // 8-bit immediate operand 438311128Sdim if (*p == 0x83 && *(p + 1) == 0xec) { 439311128Sdim amount = (int8_t) * (p + 2); 440311128Sdim return true; 441311128Sdim } 442311128Sdim // 32-bit immediate operand 443311128Sdim if (*p == 0x81 && *(p + 1) == 0xec) { 444311128Sdim amount = (int32_t)extract_4(p + 2); 445311128Sdim return true; 446311128Sdim } 447311128Sdim return false; 448311128Sdim} 449311128Sdim 450311128Sdim// addq $0x20, %rsp 451311128Sdimbool x86AssemblyInspectionEngine::add_rsp_pattern_p(int &amount) { 452311128Sdim uint8_t *p = m_cur_insn; 453311128Sdim if (m_wordsize == 8 && *p == 0x48) 454311128Sdim p++; 455311128Sdim // 8-bit immediate operand 456311128Sdim if (*p == 0x83 && *(p + 1) == 0xc4) { 457311128Sdim amount = (int8_t) * (p + 2); 458311128Sdim return true; 459311128Sdim } 460311128Sdim // 32-bit immediate operand 461311128Sdim if (*p == 0x81 && *(p + 1) == 0xc4) { 462311128Sdim amount = (int32_t)extract_4(p + 2); 463311128Sdim return true; 464311128Sdim } 465311128Sdim return false; 466311128Sdim} 467311128Sdim 468311128Sdim// lea esp, [esp - 0x28] 469311128Sdim// lea esp, [esp + 0x28] 470311128Sdimbool x86AssemblyInspectionEngine::lea_rsp_pattern_p(int &amount) { 471311128Sdim uint8_t *p = m_cur_insn; 472311128Sdim if (m_wordsize == 8 && *p == 0x48) 473311128Sdim p++; 474311128Sdim 475311128Sdim // Check opcode 476311128Sdim if (*p != 0x8d) 477311128Sdim return false; 478311128Sdim 479311128Sdim // 8 bit displacement 480311128Sdim if (*(p + 1) == 0x64 && (*(p + 2) & 0x3f) == 0x24) { 481311128Sdim amount = (int8_t) * (p + 3); 482311128Sdim return true; 483311128Sdim } 484311128Sdim 485311128Sdim // 32 bit displacement 486311128Sdim if (*(p + 1) == 0xa4 && (*(p + 2) & 0x3f) == 0x24) { 487311128Sdim amount = (int32_t)extract_4(p + 3); 488311128Sdim return true; 489311128Sdim } 490311128Sdim 491311128Sdim return false; 492311128Sdim} 493311128Sdim 494321369Sdim// lea -0x28(%ebp), %esp 495321369Sdim// (32-bit and 64-bit variants, 8-bit and 32-bit displacement) 496321369Sdimbool x86AssemblyInspectionEngine::lea_rbp_rsp_pattern_p(int &amount) { 497321369Sdim uint8_t *p = m_cur_insn; 498321369Sdim if (m_wordsize == 8 && *p == 0x48) 499321369Sdim p++; 500321369Sdim 501321369Sdim // Check opcode 502321369Sdim if (*p != 0x8d) 503321369Sdim return false; 504321369Sdim ++p; 505321369Sdim 506321369Sdim // 8 bit displacement 507321369Sdim if (*p == 0x65) { 508321369Sdim amount = (int8_t)p[1]; 509321369Sdim return true; 510321369Sdim } 511321369Sdim 512321369Sdim // 32 bit displacement 513321369Sdim if (*p == 0xa5) { 514321369Sdim amount = (int32_t)extract_4(p + 1); 515321369Sdim return true; 516321369Sdim } 517321369Sdim 518321369Sdim return false; 519321369Sdim} 520321369Sdim 521344779Sdim// lea -0x28(%ebx), %esp 522344779Sdim// (32-bit and 64-bit variants, 8-bit and 32-bit displacement) 523344779Sdimbool x86AssemblyInspectionEngine::lea_rbx_rsp_pattern_p(int &amount) { 524344779Sdim uint8_t *p = m_cur_insn; 525344779Sdim if (m_wordsize == 8 && *p == 0x48) 526344779Sdim p++; 527344779Sdim 528344779Sdim // Check opcode 529344779Sdim if (*p != 0x8d) 530344779Sdim return false; 531344779Sdim ++p; 532344779Sdim 533344779Sdim // 8 bit displacement 534344779Sdim if (*p == 0x63) { 535344779Sdim amount = (int8_t)p[1]; 536344779Sdim return true; 537344779Sdim } 538344779Sdim 539344779Sdim // 32 bit displacement 540344779Sdim if (*p == 0xa3) { 541344779Sdim amount = (int32_t)extract_4(p + 1); 542344779Sdim return true; 543344779Sdim } 544344779Sdim 545344779Sdim return false; 546344779Sdim} 547344779Sdim 548344779Sdim// and -0xfffffff0, %esp 549344779Sdim// (32-bit and 64-bit variants, 8-bit and 32-bit displacement) 550344779Sdimbool x86AssemblyInspectionEngine::and_rsp_pattern_p() { 551344779Sdim uint8_t *p = m_cur_insn; 552344779Sdim if (m_wordsize == 8 && *p == 0x48) 553344779Sdim p++; 554344779Sdim 555344779Sdim if (*p != 0x81 && *p != 0x83) 556344779Sdim return false; 557344779Sdim 558344779Sdim return *++p == 0xe4; 559344779Sdim} 560344779Sdim 561311128Sdim// popq %rbx 562311128Sdim// popl %ebx 563311128Sdimbool x86AssemblyInspectionEngine::pop_reg_p(int ®no) { 564311128Sdim uint8_t *p = m_cur_insn; 565311128Sdim int regno_prefix_bit = 0; 566311128Sdim // If we have a rex prefix byte, check to see if a B bit is set 567353358Sdim if (m_wordsize == 8 && (*p & 0xfe) == 0x40) { 568353358Sdim regno_prefix_bit = (*p & 1) << 3; 569311128Sdim p++; 570311128Sdim } 571311128Sdim if (*p >= 0x58 && *p <= 0x5f) { 572311128Sdim regno = (*p - 0x58) | regno_prefix_bit; 573311128Sdim return true; 574311128Sdim } 575311128Sdim return false; 576311128Sdim} 577311128Sdim 578311128Sdim// popq %rbp [0x5d] 579311128Sdim// popl %ebp [0x5d] 580311128Sdimbool x86AssemblyInspectionEngine::pop_rbp_pattern_p() { 581311128Sdim uint8_t *p = m_cur_insn; 582311128Sdim return (*p == 0x5d); 583311128Sdim} 584311128Sdim 585311128Sdim// instructions valid only in 32-bit mode: 586311128Sdim// 0x1f - pop ds 587311128Sdim// 0x07 - pop es 588311128Sdim// 0x17 - pop ss 589311128Sdimbool x86AssemblyInspectionEngine::pop_misc_reg_p() { 590311128Sdim uint8_t p = *m_cur_insn; 591311128Sdim if (m_wordsize == 4) { 592311128Sdim if (p == 0x1f || p == 0x07 || p == 0x17) 593311128Sdim return true; 594311128Sdim } 595311128Sdim return false; 596311128Sdim} 597311128Sdim 598311128Sdim// leave [0xc9] 599311128Sdimbool x86AssemblyInspectionEngine::leave_pattern_p() { 600311128Sdim uint8_t *p = m_cur_insn; 601311128Sdim return (*p == 0xc9); 602311128Sdim} 603311128Sdim 604311128Sdim// call $0 [0xe8 0x0 0x0 0x0 0x0] 605311128Sdimbool x86AssemblyInspectionEngine::call_next_insn_pattern_p() { 606311128Sdim uint8_t *p = m_cur_insn; 607311128Sdim return (*p == 0xe8) && (*(p + 1) == 0x0) && (*(p + 2) == 0x0) && 608311128Sdim (*(p + 3) == 0x0) && (*(p + 4) == 0x0); 609311128Sdim} 610311128Sdim 611341825Sdim// Look for an instruction sequence storing a nonvolatile register on to the 612341825Sdim// stack frame. 613311128Sdim 614311128Sdim// movq %rax, -0x10(%rbp) [0x48 0x89 0x45 0xf0] 615311128Sdim// movl %eax, -0xc(%ebp) [0x89 0x45 0xf4] 616311128Sdim 617341825Sdim// The offset value returned in rbp_offset will be positive -- but it must be 618341825Sdim// subtraced from the frame base register to get the actual location. The 619341825Sdim// positive value returned for the offset is a convention used elsewhere for 620341825Sdim// CFA offsets et al. 621311128Sdim 622311128Sdimbool x86AssemblyInspectionEngine::mov_reg_to_local_stack_frame_p( 623311128Sdim int ®no, int &rbp_offset) { 624311128Sdim uint8_t *p = m_cur_insn; 625311128Sdim int src_reg_prefix_bit = 0; 626311128Sdim int target_reg_prefix_bit = 0; 627311128Sdim 628311128Sdim if (m_wordsize == 8 && REX_W_PREFIX_P(*p)) { 629311128Sdim src_reg_prefix_bit = REX_W_SRCREG(*p) << 3; 630311128Sdim target_reg_prefix_bit = REX_W_DSTREG(*p) << 3; 631311128Sdim if (target_reg_prefix_bit == 1) { 632341825Sdim // rbp/ebp don't need a prefix bit - we know this isn't the reg we care 633341825Sdim // about. 634311128Sdim return false; 635311128Sdim } 636311128Sdim p++; 637311128Sdim } 638311128Sdim 639311128Sdim if (*p == 0x89) { 640311128Sdim /* Mask off the 3-5 bits which indicate the destination register 641311128Sdim if this is a ModR/M byte. */ 642311128Sdim int opcode_destreg_masked_out = *(p + 1) & (~0x38); 643311128Sdim 644311128Sdim /* Is this a ModR/M byte with Mod bits 01 and R/M bits 101 645311128Sdim and three bits between them, e.g. 01nnn101 646311128Sdim We're looking for a destination of ebp-disp8 or ebp-disp32. */ 647311128Sdim int immsize; 648311128Sdim if (opcode_destreg_masked_out == 0x45) 649311128Sdim immsize = 2; 650311128Sdim else if (opcode_destreg_masked_out == 0x85) 651311128Sdim immsize = 4; 652311128Sdim else 653311128Sdim return false; 654311128Sdim 655311128Sdim int offset = 0; 656311128Sdim if (immsize == 2) 657311128Sdim offset = (int8_t) * (p + 2); 658311128Sdim if (immsize == 4) 659311128Sdim offset = (uint32_t)extract_4(p + 2); 660311128Sdim if (offset > 0) 661311128Sdim return false; 662311128Sdim 663311128Sdim regno = ((*(p + 1) >> 3) & 0x7) | src_reg_prefix_bit; 664311128Sdim rbp_offset = offset > 0 ? offset : -offset; 665311128Sdim return true; 666311128Sdim } 667311128Sdim return false; 668311128Sdim} 669311128Sdim 670353358Sdim// Returns true if this is a jmp instruction where we can't 671353358Sdim// know the destination address statically. 672353358Sdim// 673353358Sdim// ff e0 jmpq *%rax 674353358Sdim// ff e1 jmpq *%rcx 675353358Sdim// ff 60 28 jmpq *0x28(%rax) 676353358Sdim// ff 60 60 jmpq *0x60(%rax) 677353358Sdimbool x86AssemblyInspectionEngine::jmp_to_reg_p() { 678353358Sdim if (*m_cur_insn != 0xff) 679353358Sdim return false; 680353358Sdim 681353358Sdim // The second byte is a ModR/M /4 byte, strip off the registers 682353358Sdim uint8_t second_byte_sans_reg = *(m_cur_insn + 1) & ~7; 683353358Sdim 684353358Sdim // Don't handle 0x24 disp32, because the target address is 685353358Sdim // knowable statically - pc_rel_branch_or_jump_p() will 686353358Sdim // return the target address. 687353358Sdim 688353358Sdim // [reg] 689353358Sdim if (second_byte_sans_reg == 0x20) 690353358Sdim return true; 691353358Sdim 692353358Sdim // [reg]+disp8 693353358Sdim if (second_byte_sans_reg == 0x60) 694353358Sdim return true; 695353358Sdim 696353358Sdim // [reg]+disp32 697353358Sdim if (second_byte_sans_reg == 0xa0) 698353358Sdim return true; 699353358Sdim 700353358Sdim // reg 701353358Sdim if (second_byte_sans_reg == 0xe0) 702353358Sdim return true; 703353358Sdim 704353358Sdim // disp32 705353358Sdim // jumps to an address stored in memory, the value can't be cached 706353358Sdim // in an unwind plan. 707353358Sdim if (second_byte_sans_reg == 0x24) 708353358Sdim return true; 709353358Sdim 710353358Sdim // use SIB byte 711353358Sdim // ff 24 fe jmpq *(%rsi,%rdi,8) 712353358Sdim if (second_byte_sans_reg == 0x24) 713353358Sdim return true; 714353358Sdim 715353358Sdim return false; 716353358Sdim} 717353358Sdim 718353358Sdim// Detect branches to fixed pc-relative offsets. 719353358Sdim// Returns the offset from the address of the next instruction 720353358Sdim// that may be branch/jumped to. 721353358Sdim// 722353358Sdim// Cannot determine the offset of a JMP that jumps to the address in 723353358Sdim// a register ("jmpq *%rax") or offset from a register value 724353358Sdim// ("jmpq *0x28(%rax)"), this method will return false on those 725353358Sdim// instructions. 726353358Sdim// 727353358Sdim// These instructions all end in either a relative 8/16/32 bit value 728353358Sdim// depending on the instruction and the current execution mode of the 729353358Sdim// inferior process. Once we know the size of the opcode instruction, 730353358Sdim// we can use the total instruction length to determine the size of 731353358Sdim// the relative offset without having to compute it correctly. 732353358Sdim 733353358Sdimbool x86AssemblyInspectionEngine::pc_rel_branch_or_jump_p ( 734353358Sdim const int instruction_length, int &offset) 735353358Sdim{ 736353358Sdim int opcode_size = 0; 737353358Sdim 738353358Sdim uint8_t b1 = m_cur_insn[0]; 739353358Sdim 740353358Sdim switch (b1) { 741353358Sdim case 0x77: // JA/JNBE rel8 742353358Sdim case 0x73: // JAE/JNB/JNC rel8 743353358Sdim case 0x72: // JB/JC/JNAE rel8 744353358Sdim case 0x76: // JBE/JNA rel8 745353358Sdim case 0xe3: // JCXZ/JECXZ/JRCXZ rel8 746353358Sdim case 0x74: // JE/JZ rel8 747353358Sdim case 0x7f: // JG/JNLE rel8 748353358Sdim case 0x7d: // JGE/JNL rel8 749353358Sdim case 0x7c: // JL/JNGE rel8 750353358Sdim case 0x7e: // JNG/JLE rel8 751353358Sdim case 0x71: // JNO rel8 752353358Sdim case 0x7b: // JNP/JPO rel8 753353358Sdim case 0x79: // JNS rel8 754353358Sdim case 0x75: // JNE/JNZ rel8 755353358Sdim case 0x70: // JO rel8 756353358Sdim case 0x7a: // JP/JPE rel8 757353358Sdim case 0x78: // JS rel8 758353358Sdim case 0xeb: // JMP rel8 759353358Sdim case 0xe9: // JMP rel16/rel32 760353358Sdim opcode_size = 1; 761353358Sdim break; 762353358Sdim default: 763353358Sdim break; 764353358Sdim } 765353358Sdim if (b1 == 0x0f && opcode_size == 0) { 766353358Sdim uint8_t b2 = m_cur_insn[1]; 767353358Sdim switch (b2) { 768353358Sdim case 0x87: // JA/JNBE rel16/rel32 769353358Sdim case 0x86: // JBE/JNA rel16/rel32 770353358Sdim case 0x84: // JE/JZ rel16/rel32 771353358Sdim case 0x8f: // JG/JNLE rel16/rel32 772353358Sdim case 0x8d: // JNL/JGE rel16/rel32 773353358Sdim case 0x8e: // JLE rel16/rel32 774353358Sdim case 0x82: // JB/JC/JNAE rel16/rel32 775353358Sdim case 0x83: // JAE/JNB/JNC rel16/rel32 776353358Sdim case 0x85: // JNE/JNZ rel16/rel32 777353358Sdim case 0x8c: // JL/JNGE rel16/rel32 778353358Sdim case 0x81: // JNO rel16/rel32 779353358Sdim case 0x8b: // JNP/JPO rel16/rel32 780353358Sdim case 0x89: // JNS rel16/rel32 781353358Sdim case 0x80: // JO rel16/rel32 782353358Sdim case 0x8a: // JP rel16/rel32 783353358Sdim case 0x88: // JS rel16/rel32 784353358Sdim opcode_size = 2; 785353358Sdim break; 786353358Sdim default: 787353358Sdim break; 788353358Sdim } 789353358Sdim } 790353358Sdim 791353358Sdim if (opcode_size == 0) 792353358Sdim return false; 793353358Sdim 794353358Sdim offset = 0; 795353358Sdim if (instruction_length - opcode_size == 1) { 796353358Sdim int8_t rel8 = (int8_t) *(m_cur_insn + opcode_size); 797353358Sdim offset = rel8; 798353358Sdim } else if (instruction_length - opcode_size == 2) { 799353358Sdim int16_t rel16 = extract_2_signed (m_cur_insn + opcode_size); 800353358Sdim offset = rel16; 801353358Sdim } else if (instruction_length - opcode_size == 4) { 802353358Sdim int32_t rel32 = extract_4_signed (m_cur_insn + opcode_size); 803353358Sdim offset = rel32; 804353358Sdim } else { 805353358Sdim return false; 806353358Sdim } 807353358Sdim return true; 808353358Sdim} 809353358Sdim 810353358Sdim// Returns true if this instruction is a intra-function branch or jump - 811353358Sdim// a branch/jump within the bounds of this same function. 812353358Sdim// Cannot predict where a jump through a register value ("jmpq *%rax") 813353358Sdim// will go, so it will return false on that instruction. 814353358Sdimbool x86AssemblyInspectionEngine::local_branch_p ( 815353358Sdim const addr_t current_func_text_offset, 816353358Sdim const AddressRange &func_range, 817353358Sdim const int instruction_length, 818353358Sdim addr_t &target_insn_offset) { 819353358Sdim int offset; 820353358Sdim if (pc_rel_branch_or_jump_p (instruction_length, offset) && offset != 0) { 821353358Sdim addr_t next_pc_value = current_func_text_offset + instruction_length; 822353358Sdim if (offset < 0 && addr_t(-offset) > current_func_text_offset) { 823353358Sdim // Branch target is before the start of this function 824353358Sdim return false; 825353358Sdim } 826353358Sdim if (offset + next_pc_value > func_range.GetByteSize()) { 827353358Sdim // Branch targets outside this function's bounds 828353358Sdim return false; 829353358Sdim } 830353358Sdim // This instruction branches to target_insn_offset (byte offset into the function) 831353358Sdim target_insn_offset = next_pc_value + offset; 832353358Sdim return true; 833353358Sdim } 834353358Sdim return false; 835353358Sdim} 836353358Sdim 837353358Sdim// Returns true if this instruction is a inter-function branch or jump - a 838353358Sdim// branch/jump to another function. 839353358Sdim// Cannot predict where a jump through a register value ("jmpq *%rax") 840353358Sdim// will go, so it will return false on that instruction. 841353358Sdimbool x86AssemblyInspectionEngine::non_local_branch_p ( 842353358Sdim const addr_t current_func_text_offset, 843353358Sdim const AddressRange &func_range, 844353358Sdim const int instruction_length) { 845353358Sdim int offset; 846353358Sdim addr_t target_insn_offset; 847353358Sdim if (pc_rel_branch_or_jump_p (instruction_length, offset)) { 848353358Sdim return !local_branch_p(current_func_text_offset,func_range,instruction_length,target_insn_offset); 849353358Sdim } 850353358Sdim return false; 851353358Sdim} 852353358Sdim 853353358Sdim// ret [0xc3] or [0xcb] or [0xc2 imm16] or [0xca imm16] 854311128Sdimbool x86AssemblyInspectionEngine::ret_pattern_p() { 855311128Sdim uint8_t *p = m_cur_insn; 856353358Sdim return *p == 0xc3 || *p == 0xc2 || *p == 0xca || *p == 0xcb; 857311128Sdim} 858311128Sdim 859353358Sdimuint16_t x86AssemblyInspectionEngine::extract_2(uint8_t *b) { 860353358Sdim uint16_t v = 0; 861353358Sdim for (int i = 1; i >= 0; i--) 862353358Sdim v = (v << 8) | b[i]; 863353358Sdim return v; 864353358Sdim} 865353358Sdim 866353358Sdimint16_t x86AssemblyInspectionEngine::extract_2_signed(uint8_t *b) { 867353358Sdim int16_t v = 0; 868353358Sdim for (int i = 1; i >= 0; i--) 869353358Sdim v = (v << 8) | b[i]; 870353358Sdim return v; 871353358Sdim} 872353358Sdim 873311128Sdimuint32_t x86AssemblyInspectionEngine::extract_4(uint8_t *b) { 874311128Sdim uint32_t v = 0; 875311128Sdim for (int i = 3; i >= 0; i--) 876311128Sdim v = (v << 8) | b[i]; 877311128Sdim return v; 878311128Sdim} 879311128Sdim 880353358Sdimint32_t x86AssemblyInspectionEngine::extract_4_signed(uint8_t *b) { 881353358Sdim int32_t v = 0; 882353358Sdim for (int i = 3; i >= 0; i--) 883353358Sdim v = (v << 8) | b[i]; 884353358Sdim return v; 885353358Sdim} 886353358Sdim 887353358Sdim 888311128Sdimbool x86AssemblyInspectionEngine::instruction_length(uint8_t *insn_p, 889321369Sdim int &length, 890321369Sdim uint32_t buffer_remaining_bytes) { 891311128Sdim 892321369Sdim uint32_t max_op_byte_size = std::min(buffer_remaining_bytes, m_arch.GetMaximumOpcodeByteSize()); 893311128Sdim llvm::SmallVector<uint8_t, 32> opcode_data; 894311128Sdim opcode_data.resize(max_op_byte_size); 895311128Sdim 896311128Sdim char out_string[512]; 897311128Sdim const size_t inst_size = 898311128Sdim ::LLVMDisasmInstruction(m_disasm_context, insn_p, max_op_byte_size, 0, 899311128Sdim out_string, sizeof(out_string)); 900311128Sdim 901311128Sdim length = inst_size; 902311128Sdim return true; 903311128Sdim} 904311128Sdim 905311128Sdimbool x86AssemblyInspectionEngine::machine_regno_to_lldb_regno( 906311128Sdim int machine_regno, uint32_t &lldb_regno) { 907311128Sdim MachineRegnumToNameAndLLDBRegnum::iterator it = m_reg_map.find(machine_regno); 908311128Sdim if (it != m_reg_map.end()) { 909311128Sdim lldb_regno = it->second.lldb_regnum; 910311128Sdim return true; 911311128Sdim } 912311128Sdim return false; 913311128Sdim} 914311128Sdim 915311128Sdimbool x86AssemblyInspectionEngine::GetNonCallSiteUnwindPlanFromAssembly( 916311128Sdim uint8_t *data, size_t size, AddressRange &func_range, 917311128Sdim UnwindPlan &unwind_plan) { 918311128Sdim unwind_plan.Clear(); 919311128Sdim 920311128Sdim if (data == nullptr || size == 0) 921311128Sdim return false; 922311128Sdim 923344779Sdim if (!m_register_map_initialized) 924311128Sdim return false; 925311128Sdim 926311128Sdim addr_t current_func_text_offset = 0; 927344779Sdim int current_sp_bytes_offset_from_fa = 0; 928344779Sdim bool is_aligned = false; 929311128Sdim UnwindPlan::Row::RegisterLocation initial_regloc; 930311128Sdim UnwindPlan::RowSP row(new UnwindPlan::Row); 931311128Sdim 932311128Sdim unwind_plan.SetPlanValidAddressRange(func_range); 933311128Sdim unwind_plan.SetRegisterKind(eRegisterKindLLDB); 934311128Sdim 935311128Sdim // At the start of the function, find the CFA by adding wordsize to the SP 936311128Sdim // register 937311128Sdim row->SetOffset(current_func_text_offset); 938311128Sdim row->GetCFAValue().SetIsRegisterPlusOffset(m_lldb_sp_regnum, m_wordsize); 939311128Sdim 940311128Sdim // caller's stack pointer value before the call insn is the CFA address 941311128Sdim initial_regloc.SetIsCFAPlusOffset(0); 942311128Sdim row->SetRegisterInfo(m_lldb_sp_regnum, initial_regloc); 943311128Sdim 944311128Sdim // saved instruction pointer can be found at CFA - wordsize. 945344779Sdim current_sp_bytes_offset_from_fa = m_wordsize; 946344779Sdim initial_regloc.SetAtCFAPlusOffset(-current_sp_bytes_offset_from_fa); 947311128Sdim row->SetRegisterInfo(m_lldb_ip_regnum, initial_regloc); 948311128Sdim 949311128Sdim unwind_plan.AppendRow(row); 950311128Sdim 951311128Sdim // Allocate a new Row, populate it with the existing Row contents. 952311128Sdim UnwindPlan::Row *newrow = new UnwindPlan::Row; 953311128Sdim *newrow = *row.get(); 954311128Sdim row.reset(newrow); 955311128Sdim 956341825Sdim // Track which registers have been saved so far in the prologue. If we see 957341825Sdim // another push of that register, it's not part of the prologue. The register 958341825Sdim // numbers used here are the machine register #'s (i386_register_numbers, 959341825Sdim // x86_64_register_numbers). 960311128Sdim std::vector<bool> saved_registers(32, false); 961311128Sdim 962311128Sdim // Once the prologue has completed we'll save a copy of the unwind 963341825Sdim // instructions If there is an epilogue in the middle of the function, after 964341825Sdim // that epilogue we'll reinstate the unwind setup -- we assume that some code 965341825Sdim // path jumps over the mid-function epilogue 966311128Sdim 967311128Sdim UnwindPlan::RowSP prologue_completed_row; // copy of prologue row of CFI 968311128Sdim int prologue_completed_sp_bytes_offset_from_cfa; // The sp value before the 969311128Sdim // epilogue started executed 970344779Sdim bool prologue_completed_is_aligned; 971311128Sdim std::vector<bool> prologue_completed_saved_registers; 972311128Sdim 973311128Sdim while (current_func_text_offset < size) { 974311128Sdim int stack_offset, insn_len; 975311128Sdim int machine_regno; // register numbers masked directly out of instructions 976311128Sdim uint32_t lldb_regno; // register numbers in lldb's eRegisterKindLLDB 977311128Sdim // numbering scheme 978311128Sdim 979311128Sdim bool in_epilogue = false; // we're in the middle of an epilogue sequence 980311128Sdim bool row_updated = false; // The UnwindPlan::Row 'row' has been updated 981311128Sdim 982311128Sdim m_cur_insn = data + current_func_text_offset; 983321369Sdim if (!instruction_length(m_cur_insn, insn_len, size - current_func_text_offset) 984321369Sdim || insn_len == 0 985321369Sdim || insn_len > kMaxInstructionByteSize) { 986311128Sdim // An unrecognized/junk instruction 987311128Sdim break; 988311128Sdim } 989311128Sdim 990344779Sdim auto &cfa_value = row->GetCFAValue(); 991344779Sdim auto &afa_value = row->GetAFAValue(); 992344779Sdim auto fa_value_ptr = is_aligned ? &afa_value : &cfa_value; 993344779Sdim 994344779Sdim if (mov_rsp_rbp_pattern_p()) { 995344779Sdim if (fa_value_ptr->GetRegisterNumber() == m_lldb_sp_regnum) { 996344779Sdim fa_value_ptr->SetIsRegisterPlusOffset( 997344779Sdim m_lldb_fp_regnum, fa_value_ptr->GetOffset()); 998344779Sdim row_updated = true; 999344779Sdim } 1000311128Sdim } 1001311128Sdim 1002344779Sdim else if (mov_rsp_rbx_pattern_p()) { 1003344779Sdim if (fa_value_ptr->GetRegisterNumber() == m_lldb_sp_regnum) { 1004344779Sdim fa_value_ptr->SetIsRegisterPlusOffset( 1005344779Sdim m_lldb_alt_fp_regnum, fa_value_ptr->GetOffset()); 1006344779Sdim row_updated = true; 1007344779Sdim } 1008344779Sdim } 1009344779Sdim 1010344779Sdim else if (and_rsp_pattern_p()) { 1011344779Sdim current_sp_bytes_offset_from_fa = 0; 1012344779Sdim afa_value.SetIsRegisterPlusOffset( 1013344779Sdim m_lldb_sp_regnum, current_sp_bytes_offset_from_fa); 1014344779Sdim fa_value_ptr = &afa_value; 1015344779Sdim is_aligned = true; 1016311128Sdim row_updated = true; 1017311128Sdim } 1018311128Sdim 1019344779Sdim else if (mov_rbp_rsp_pattern_p()) { 1020344779Sdim if (is_aligned && cfa_value.GetRegisterNumber() == m_lldb_fp_regnum) 1021344779Sdim { 1022344779Sdim is_aligned = false; 1023344779Sdim fa_value_ptr = &cfa_value; 1024344779Sdim afa_value.SetUnspecified(); 1025344779Sdim row_updated = true; 1026344779Sdim } 1027344779Sdim if (fa_value_ptr->GetRegisterNumber() == m_lldb_fp_regnum) 1028344779Sdim current_sp_bytes_offset_from_fa = fa_value_ptr->GetOffset(); 1029344779Sdim } 1030344779Sdim 1031344779Sdim else if (mov_rbx_rsp_pattern_p()) { 1032344779Sdim if (is_aligned && cfa_value.GetRegisterNumber() == m_lldb_alt_fp_regnum) 1033344779Sdim { 1034344779Sdim is_aligned = false; 1035344779Sdim fa_value_ptr = &cfa_value; 1036344779Sdim afa_value.SetUnspecified(); 1037344779Sdim row_updated = true; 1038344779Sdim } 1039344779Sdim if (fa_value_ptr->GetRegisterNumber() == m_lldb_alt_fp_regnum) 1040344779Sdim current_sp_bytes_offset_from_fa = fa_value_ptr->GetOffset(); 1041344779Sdim } 1042344779Sdim 1043311128Sdim // This is the start() function (or a pthread equivalent), it starts with a 1044341825Sdim // pushl $0x0 which puts the saved pc value of 0 on the stack. In this 1045341825Sdim // case we want to pretend we didn't see a stack movement at all -- 1046311128Sdim // normally the saved pc value is already on the stack by the time the 1047311128Sdim // function starts executing. 1048311128Sdim else if (push_0_pattern_p()) { 1049311128Sdim } 1050311128Sdim 1051311128Sdim else if (push_reg_p(machine_regno)) { 1052344779Sdim current_sp_bytes_offset_from_fa += m_wordsize; 1053344779Sdim // the PUSH instruction has moved the stack pointer - if the FA is set 1054341825Sdim // in terms of the stack pointer, we need to add a new row of 1055341825Sdim // instructions. 1056344779Sdim if (fa_value_ptr->GetRegisterNumber() == m_lldb_sp_regnum) { 1057344779Sdim fa_value_ptr->SetOffset(current_sp_bytes_offset_from_fa); 1058311128Sdim row_updated = true; 1059311128Sdim } 1060311128Sdim // record where non-volatile (callee-saved, spilled) registers are saved 1061311128Sdim // on the stack 1062311128Sdim if (nonvolatile_reg_p(machine_regno) && 1063311128Sdim machine_regno_to_lldb_regno(machine_regno, lldb_regno) && 1064344779Sdim !saved_registers[machine_regno]) { 1065311128Sdim UnwindPlan::Row::RegisterLocation regloc; 1066344779Sdim if (is_aligned) 1067344779Sdim regloc.SetAtAFAPlusOffset(-current_sp_bytes_offset_from_fa); 1068344779Sdim else 1069344779Sdim regloc.SetAtCFAPlusOffset(-current_sp_bytes_offset_from_fa); 1070311128Sdim row->SetRegisterInfo(lldb_regno, regloc); 1071311128Sdim saved_registers[machine_regno] = true; 1072311128Sdim row_updated = true; 1073311128Sdim } 1074311128Sdim } 1075311128Sdim 1076311128Sdim else if (pop_reg_p(machine_regno)) { 1077344779Sdim current_sp_bytes_offset_from_fa -= m_wordsize; 1078311128Sdim 1079311128Sdim if (nonvolatile_reg_p(machine_regno) && 1080311128Sdim machine_regno_to_lldb_regno(machine_regno, lldb_regno) && 1081344779Sdim saved_registers[machine_regno]) { 1082311128Sdim saved_registers[machine_regno] = false; 1083311128Sdim row->RemoveRegisterInfo(lldb_regno); 1084311128Sdim 1085344779Sdim if (lldb_regno == fa_value_ptr->GetRegisterNumber()) { 1086344779Sdim fa_value_ptr->SetIsRegisterPlusOffset( 1087344779Sdim m_lldb_sp_regnum, fa_value_ptr->GetOffset()); 1088311128Sdim } 1089311128Sdim 1090311128Sdim in_epilogue = true; 1091311128Sdim row_updated = true; 1092311128Sdim } 1093311128Sdim 1094344779Sdim // the POP instruction has moved the stack pointer - if the FA is set in 1095341825Sdim // terms of the stack pointer, we need to add a new row of instructions. 1096344779Sdim if (fa_value_ptr->GetRegisterNumber() == m_lldb_sp_regnum) { 1097344779Sdim fa_value_ptr->SetIsRegisterPlusOffset( 1098344779Sdim m_lldb_sp_regnum, current_sp_bytes_offset_from_fa); 1099311128Sdim row_updated = true; 1100311128Sdim } 1101311128Sdim } 1102311128Sdim 1103311128Sdim else if (pop_misc_reg_p()) { 1104344779Sdim current_sp_bytes_offset_from_fa -= m_wordsize; 1105344779Sdim if (fa_value_ptr->GetRegisterNumber() == m_lldb_sp_regnum) { 1106344779Sdim fa_value_ptr->SetIsRegisterPlusOffset( 1107344779Sdim m_lldb_sp_regnum, current_sp_bytes_offset_from_fa); 1108311128Sdim row_updated = true; 1109311128Sdim } 1110311128Sdim } 1111311128Sdim 1112341825Sdim // The LEAVE instruction moves the value from rbp into rsp and pops a value 1113341825Sdim // off the stack into rbp (restoring the caller's rbp value). It is the 1114341825Sdim // opposite of ENTER, or 'push rbp, mov rsp rbp'. 1115311128Sdim else if (leave_pattern_p()) { 1116344779Sdim if (saved_registers[m_machine_fp_regnum]) { 1117344779Sdim saved_registers[m_machine_fp_regnum] = false; 1118344779Sdim row->RemoveRegisterInfo(m_lldb_fp_regnum); 1119311128Sdim 1120344779Sdim row_updated = true; 1121344779Sdim } 1122311128Sdim 1123344779Sdim if (is_aligned && cfa_value.GetRegisterNumber() == m_lldb_fp_regnum) 1124344779Sdim { 1125344779Sdim is_aligned = false; 1126344779Sdim fa_value_ptr = &cfa_value; 1127344779Sdim afa_value.SetUnspecified(); 1128344779Sdim row_updated = true; 1129344779Sdim } 1130311128Sdim 1131344779Sdim if (fa_value_ptr->GetRegisterNumber() == m_lldb_fp_regnum) 1132344779Sdim { 1133344779Sdim fa_value_ptr->SetIsRegisterPlusOffset( 1134344779Sdim m_lldb_sp_regnum, fa_value_ptr->GetOffset()); 1135344779Sdim 1136344779Sdim current_sp_bytes_offset_from_fa = fa_value_ptr->GetOffset(); 1137344779Sdim } 1138344779Sdim 1139344779Sdim current_sp_bytes_offset_from_fa -= m_wordsize; 1140344779Sdim 1141344779Sdim if (fa_value_ptr->GetRegisterNumber() == m_lldb_sp_regnum) { 1142344779Sdim fa_value_ptr->SetIsRegisterPlusOffset( 1143344779Sdim m_lldb_sp_regnum, current_sp_bytes_offset_from_fa); 1144344779Sdim row_updated = true; 1145344779Sdim } 1146344779Sdim 1147311128Sdim in_epilogue = true; 1148311128Sdim } 1149311128Sdim 1150311128Sdim else if (mov_reg_to_local_stack_frame_p(machine_regno, stack_offset) && 1151311128Sdim nonvolatile_reg_p(machine_regno) && 1152311128Sdim machine_regno_to_lldb_regno(machine_regno, lldb_regno) && 1153344779Sdim !saved_registers[machine_regno]) { 1154311128Sdim saved_registers[machine_regno] = true; 1155311128Sdim 1156311128Sdim UnwindPlan::Row::RegisterLocation regloc; 1157311128Sdim 1158341825Sdim // stack_offset for 'movq %r15, -80(%rbp)' will be 80. In the Row, we 1159344779Sdim // want to express this as the offset from the FA. If the frame base is 1160344779Sdim // rbp (like the above instruction), the FA offset for rbp is probably 1161344779Sdim // 16. So we want to say that the value is stored at the FA address - 1162341825Sdim // 96. 1163344779Sdim if (is_aligned) 1164344779Sdim regloc.SetAtAFAPlusOffset(-(stack_offset + fa_value_ptr->GetOffset())); 1165344779Sdim else 1166344779Sdim regloc.SetAtCFAPlusOffset(-(stack_offset + fa_value_ptr->GetOffset())); 1167311128Sdim 1168311128Sdim row->SetRegisterInfo(lldb_regno, regloc); 1169311128Sdim 1170311128Sdim row_updated = true; 1171311128Sdim } 1172311128Sdim 1173311128Sdim else if (sub_rsp_pattern_p(stack_offset)) { 1174344779Sdim current_sp_bytes_offset_from_fa += stack_offset; 1175344779Sdim if (fa_value_ptr->GetRegisterNumber() == m_lldb_sp_regnum) { 1176344779Sdim fa_value_ptr->SetOffset(current_sp_bytes_offset_from_fa); 1177311128Sdim row_updated = true; 1178311128Sdim } 1179311128Sdim } 1180311128Sdim 1181311128Sdim else if (add_rsp_pattern_p(stack_offset)) { 1182344779Sdim current_sp_bytes_offset_from_fa -= stack_offset; 1183344779Sdim if (fa_value_ptr->GetRegisterNumber() == m_lldb_sp_regnum) { 1184344779Sdim fa_value_ptr->SetOffset(current_sp_bytes_offset_from_fa); 1185311128Sdim row_updated = true; 1186311128Sdim } 1187311128Sdim in_epilogue = true; 1188311128Sdim } 1189311128Sdim 1190311128Sdim else if (push_extended_pattern_p() || push_imm_pattern_p() || 1191311128Sdim push_misc_reg_p()) { 1192344779Sdim current_sp_bytes_offset_from_fa += m_wordsize; 1193344779Sdim if (fa_value_ptr->GetRegisterNumber() == m_lldb_sp_regnum) { 1194344779Sdim fa_value_ptr->SetOffset(current_sp_bytes_offset_from_fa); 1195311128Sdim row_updated = true; 1196311128Sdim } 1197311128Sdim } 1198311128Sdim 1199311128Sdim else if (lea_rsp_pattern_p(stack_offset)) { 1200344779Sdim current_sp_bytes_offset_from_fa -= stack_offset; 1201344779Sdim if (fa_value_ptr->GetRegisterNumber() == m_lldb_sp_regnum) { 1202344779Sdim fa_value_ptr->SetOffset(current_sp_bytes_offset_from_fa); 1203311128Sdim row_updated = true; 1204311128Sdim } 1205311128Sdim if (stack_offset > 0) 1206311128Sdim in_epilogue = true; 1207311128Sdim } 1208311128Sdim 1209344779Sdim else if (lea_rbp_rsp_pattern_p(stack_offset)) { 1210344779Sdim if (is_aligned && 1211344779Sdim cfa_value.GetRegisterNumber() == m_lldb_fp_regnum) { 1212344779Sdim is_aligned = false; 1213344779Sdim fa_value_ptr = &cfa_value; 1214344779Sdim afa_value.SetUnspecified(); 1215344779Sdim row_updated = true; 1216344779Sdim } 1217344779Sdim if (fa_value_ptr->GetRegisterNumber() == m_lldb_fp_regnum) { 1218344779Sdim current_sp_bytes_offset_from_fa = 1219344779Sdim fa_value_ptr->GetOffset() - stack_offset; 1220344779Sdim } 1221321369Sdim } 1222321369Sdim 1223344779Sdim else if (lea_rbx_rsp_pattern_p(stack_offset)) { 1224344779Sdim if (is_aligned && 1225344779Sdim cfa_value.GetRegisterNumber() == m_lldb_alt_fp_regnum) { 1226344779Sdim is_aligned = false; 1227344779Sdim fa_value_ptr = &cfa_value; 1228344779Sdim afa_value.SetUnspecified(); 1229344779Sdim row_updated = true; 1230344779Sdim } 1231344779Sdim if (fa_value_ptr->GetRegisterNumber() == m_lldb_alt_fp_regnum) { 1232344779Sdim current_sp_bytes_offset_from_fa = fa_value_ptr->GetOffset() - stack_offset; 1233344779Sdim } 1234344779Sdim } 1235344779Sdim 1236353358Sdim else if (prologue_completed_row.get() && 1237353358Sdim (ret_pattern_p() || 1238353358Sdim non_local_branch_p (current_func_text_offset, func_range, insn_len) || 1239353358Sdim jmp_to_reg_p())) { 1240353358Sdim // Check if the current instruction is the end of an epilogue sequence, 1241353358Sdim // and if so, re-instate the prologue-completed unwind state. 1242311128Sdim 1243353358Sdim // The current instruction is a branch/jump outside this function, 1244353358Sdim // a ret, or a jump through a register value which we cannot 1245353358Sdim // determine the effcts of. Verify that the stack frame state 1246353358Sdim // has been unwound to the same as it was at function entry to avoid 1247353358Sdim // mis-identifying a JMP instruction as an epilogue. 1248353358Sdim UnwindPlan::Row::RegisterLocation sp, pc; 1249353358Sdim if (row->GetRegisterInfo(m_lldb_sp_regnum, sp) && 1250353358Sdim row->GetRegisterInfo(m_lldb_ip_regnum, pc)) { 1251353358Sdim // Any ret instruction variant is definitely indicative of an 1252353358Sdim // epilogue; for other insn patterns verify that we're back to 1253353358Sdim // the original unwind state. 1254353358Sdim if (ret_pattern_p() || 1255353358Sdim (sp.IsCFAPlusOffset() && sp.GetOffset() == 0 && 1256353358Sdim pc.IsAtCFAPlusOffset() && pc.GetOffset() == -m_wordsize)) { 1257353358Sdim // Reinstate the saved prologue setup for any instructions that come 1258353358Sdim // after the epilogue 1259311128Sdim 1260353358Sdim UnwindPlan::Row *newrow = new UnwindPlan::Row; 1261353358Sdim *newrow = *prologue_completed_row.get(); 1262353358Sdim row.reset(newrow); 1263353358Sdim current_sp_bytes_offset_from_fa = 1264353358Sdim prologue_completed_sp_bytes_offset_from_cfa; 1265353358Sdim is_aligned = prologue_completed_is_aligned; 1266353358Sdim 1267353358Sdim saved_registers.clear(); 1268353358Sdim saved_registers.resize(prologue_completed_saved_registers.size(), false); 1269353358Sdim for (size_t i = 0; i < prologue_completed_saved_registers.size(); ++i) { 1270353358Sdim saved_registers[i] = prologue_completed_saved_registers[i]; 1271353358Sdim } 1272353358Sdim 1273353358Sdim in_epilogue = true; 1274353358Sdim row_updated = true; 1275353358Sdim } 1276311128Sdim } 1277311128Sdim } 1278311128Sdim 1279311128Sdim // call next instruction 1280311128Sdim // call 0 1281311128Sdim // => pop %ebx 1282311128Sdim // This is used in i386 programs to get the PIC base address for finding 1283311128Sdim // global data 1284311128Sdim else if (call_next_insn_pattern_p()) { 1285344779Sdim current_sp_bytes_offset_from_fa += m_wordsize; 1286344779Sdim if (fa_value_ptr->GetRegisterNumber() == m_lldb_sp_regnum) { 1287344779Sdim fa_value_ptr->SetOffset(current_sp_bytes_offset_from_fa); 1288311128Sdim row_updated = true; 1289311128Sdim } 1290311128Sdim } 1291311128Sdim 1292311128Sdim if (row_updated) { 1293311128Sdim if (current_func_text_offset + insn_len < size) { 1294311128Sdim row->SetOffset(current_func_text_offset + insn_len); 1295311128Sdim unwind_plan.AppendRow(row); 1296311128Sdim // Allocate a new Row, populate it with the existing Row contents. 1297311128Sdim newrow = new UnwindPlan::Row; 1298311128Sdim *newrow = *row.get(); 1299311128Sdim row.reset(newrow); 1300311128Sdim } 1301311128Sdim } 1302311128Sdim 1303344779Sdim if (!in_epilogue && row_updated) { 1304311128Sdim // If we're not in an epilogue sequence, save the updated Row 1305311128Sdim UnwindPlan::Row *newrow = new UnwindPlan::Row; 1306311128Sdim *newrow = *row.get(); 1307311128Sdim prologue_completed_row.reset(newrow); 1308311128Sdim 1309311128Sdim prologue_completed_saved_registers.clear(); 1310311128Sdim prologue_completed_saved_registers.resize(saved_registers.size(), false); 1311311128Sdim for (size_t i = 0; i < saved_registers.size(); ++i) { 1312311128Sdim prologue_completed_saved_registers[i] = saved_registers[i]; 1313311128Sdim } 1314311128Sdim } 1315311128Sdim 1316311128Sdim // We may change the sp value without adding a new Row necessarily -- keep 1317311128Sdim // track of it either way. 1318344779Sdim if (!in_epilogue) { 1319311128Sdim prologue_completed_sp_bytes_offset_from_cfa = 1320344779Sdim current_sp_bytes_offset_from_fa; 1321344779Sdim prologue_completed_is_aligned = is_aligned; 1322311128Sdim } 1323311128Sdim 1324311128Sdim m_cur_insn = m_cur_insn + insn_len; 1325311128Sdim current_func_text_offset += insn_len; 1326311128Sdim } 1327311128Sdim 1328311128Sdim unwind_plan.SetSourceName("assembly insn profiling"); 1329311128Sdim unwind_plan.SetSourcedFromCompiler(eLazyBoolNo); 1330311128Sdim unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolYes); 1331360784Sdim unwind_plan.SetUnwindPlanForSignalTrap(eLazyBoolNo); 1332311128Sdim 1333311128Sdim return true; 1334311128Sdim} 1335311128Sdim 1336311128Sdimbool x86AssemblyInspectionEngine::AugmentUnwindPlanFromCallSite( 1337311128Sdim uint8_t *data, size_t size, AddressRange &func_range, 1338311128Sdim UnwindPlan &unwind_plan, RegisterContextSP ®_ctx) { 1339311128Sdim Address addr_start = func_range.GetBaseAddress(); 1340311128Sdim if (!addr_start.IsValid()) 1341311128Sdim return false; 1342311128Sdim 1343341825Sdim // We either need a live RegisterContext, or we need the UnwindPlan to 1344341825Sdim // already be in the lldb register numbering scheme. 1345311128Sdim if (reg_ctx.get() == nullptr && 1346311128Sdim unwind_plan.GetRegisterKind() != eRegisterKindLLDB) 1347311128Sdim return false; 1348311128Sdim 1349311128Sdim // Is original unwind_plan valid? 1350341825Sdim // unwind_plan should have at least one row which is ABI-default (CFA 1351341825Sdim // register is sp), and another row in mid-function. 1352311128Sdim if (unwind_plan.GetRowCount() < 2) 1353311128Sdim return false; 1354311128Sdim 1355311128Sdim UnwindPlan::RowSP first_row = unwind_plan.GetRowAtIndex(0); 1356311128Sdim if (first_row->GetOffset() != 0) 1357311128Sdim return false; 1358311128Sdim uint32_t cfa_reg = first_row->GetCFAValue().GetRegisterNumber(); 1359311128Sdim if (unwind_plan.GetRegisterKind() != eRegisterKindLLDB) { 1360311128Sdim cfa_reg = reg_ctx->ConvertRegisterKindToRegisterNumber( 1361311128Sdim unwind_plan.GetRegisterKind(), 1362311128Sdim first_row->GetCFAValue().GetRegisterNumber()); 1363311128Sdim } 1364311128Sdim if (cfa_reg != m_lldb_sp_regnum || 1365311128Sdim first_row->GetCFAValue().GetOffset() != m_wordsize) 1366311128Sdim return false; 1367311128Sdim 1368311128Sdim UnwindPlan::RowSP original_last_row = unwind_plan.GetRowForFunctionOffset(-1); 1369311128Sdim 1370311128Sdim size_t offset = 0; 1371311128Sdim int row_id = 1; 1372311128Sdim bool unwind_plan_updated = false; 1373311128Sdim UnwindPlan::RowSP row(new UnwindPlan::Row(*first_row)); 1374311128Sdim 1375341825Sdim // After a mid-function epilogue we will need to re-insert the original 1376341825Sdim // unwind rules so unwinds work for the remainder of the function. These 1377341825Sdim // aren't common with clang/gcc on x86 but it is possible. 1378311128Sdim bool reinstate_unwind_state = false; 1379311128Sdim 1380311128Sdim while (offset < size) { 1381311128Sdim m_cur_insn = data + offset; 1382311128Sdim int insn_len; 1383360784Sdim if (!instruction_length(m_cur_insn, insn_len, size - offset) || 1384360784Sdim insn_len == 0 || insn_len > kMaxInstructionByteSize) { 1385311128Sdim // An unrecognized/junk instruction. 1386311128Sdim break; 1387311128Sdim } 1388311128Sdim 1389311128Sdim // Advance offsets. 1390311128Sdim offset += insn_len; 1391311128Sdim 1392341825Sdim // offset is pointing beyond the bounds of the function; stop looping. 1393360784Sdim if (offset >= size) 1394321369Sdim continue; 1395321369Sdim 1396311128Sdim if (reinstate_unwind_state) { 1397311128Sdim UnwindPlan::RowSP new_row(new UnwindPlan::Row()); 1398311128Sdim *new_row = *original_last_row; 1399311128Sdim new_row->SetOffset(offset); 1400311128Sdim unwind_plan.AppendRow(new_row); 1401353358Sdim row = std::make_shared<UnwindPlan::Row>(); 1402311128Sdim *row = *new_row; 1403311128Sdim reinstate_unwind_state = false; 1404311128Sdim unwind_plan_updated = true; 1405311128Sdim continue; 1406311128Sdim } 1407311128Sdim 1408311128Sdim // If we already have one row for this instruction, we can continue. 1409311128Sdim while (row_id < unwind_plan.GetRowCount() && 1410311128Sdim unwind_plan.GetRowAtIndex(row_id)->GetOffset() <= offset) { 1411311128Sdim row_id++; 1412311128Sdim } 1413311128Sdim UnwindPlan::RowSP original_row = unwind_plan.GetRowAtIndex(row_id - 1); 1414311128Sdim if (original_row->GetOffset() == offset) { 1415311128Sdim *row = *original_row; 1416311128Sdim continue; 1417311128Sdim } 1418311128Sdim 1419311128Sdim if (row_id == 0) { 1420341825Sdim // If we are here, compiler didn't generate CFI for prologue. This won't 1421341825Sdim // happen to GCC or clang. In this case, bail out directly. 1422311128Sdim return false; 1423311128Sdim } 1424311128Sdim 1425311128Sdim // Inspect the instruction to check if we need a new row for it. 1426311128Sdim cfa_reg = row->GetCFAValue().GetRegisterNumber(); 1427311128Sdim if (unwind_plan.GetRegisterKind() != eRegisterKindLLDB) { 1428311128Sdim cfa_reg = reg_ctx->ConvertRegisterKindToRegisterNumber( 1429311128Sdim unwind_plan.GetRegisterKind(), 1430311128Sdim row->GetCFAValue().GetRegisterNumber()); 1431311128Sdim } 1432311128Sdim if (cfa_reg == m_lldb_sp_regnum) { 1433311128Sdim // CFA register is sp. 1434311128Sdim 1435311128Sdim // call next instruction 1436311128Sdim // call 0 1437311128Sdim // => pop %ebx 1438311128Sdim if (call_next_insn_pattern_p()) { 1439311128Sdim row->SetOffset(offset); 1440311128Sdim row->GetCFAValue().IncOffset(m_wordsize); 1441311128Sdim 1442311128Sdim UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row)); 1443311128Sdim unwind_plan.InsertRow(new_row); 1444311128Sdim unwind_plan_updated = true; 1445311128Sdim continue; 1446311128Sdim } 1447311128Sdim 1448311128Sdim // push/pop register 1449311128Sdim int regno; 1450311128Sdim if (push_reg_p(regno)) { 1451311128Sdim row->SetOffset(offset); 1452311128Sdim row->GetCFAValue().IncOffset(m_wordsize); 1453311128Sdim 1454311128Sdim UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row)); 1455311128Sdim unwind_plan.InsertRow(new_row); 1456311128Sdim unwind_plan_updated = true; 1457311128Sdim continue; 1458311128Sdim } 1459311128Sdim if (pop_reg_p(regno)) { 1460311128Sdim // Technically, this might be a nonvolatile register recover in 1461341825Sdim // epilogue. We should reset RegisterInfo for the register. But in 1462341825Sdim // practice, previous rule for the register is still valid... So we 1463341825Sdim // ignore this case. 1464311128Sdim 1465311128Sdim row->SetOffset(offset); 1466311128Sdim row->GetCFAValue().IncOffset(-m_wordsize); 1467311128Sdim 1468311128Sdim UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row)); 1469311128Sdim unwind_plan.InsertRow(new_row); 1470311128Sdim unwind_plan_updated = true; 1471311128Sdim continue; 1472311128Sdim } 1473311128Sdim 1474311128Sdim if (pop_misc_reg_p()) { 1475311128Sdim row->SetOffset(offset); 1476311128Sdim row->GetCFAValue().IncOffset(-m_wordsize); 1477311128Sdim 1478311128Sdim UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row)); 1479311128Sdim unwind_plan.InsertRow(new_row); 1480311128Sdim unwind_plan_updated = true; 1481311128Sdim continue; 1482311128Sdim } 1483311128Sdim 1484311128Sdim // push imm 1485311128Sdim if (push_imm_pattern_p()) { 1486311128Sdim row->SetOffset(offset); 1487311128Sdim row->GetCFAValue().IncOffset(m_wordsize); 1488311128Sdim UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row)); 1489311128Sdim unwind_plan.InsertRow(new_row); 1490311128Sdim unwind_plan_updated = true; 1491311128Sdim continue; 1492311128Sdim } 1493311128Sdim 1494311128Sdim // push extended 1495311128Sdim if (push_extended_pattern_p() || push_misc_reg_p()) { 1496311128Sdim row->SetOffset(offset); 1497311128Sdim row->GetCFAValue().IncOffset(m_wordsize); 1498311128Sdim UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row)); 1499311128Sdim unwind_plan.InsertRow(new_row); 1500311128Sdim unwind_plan_updated = true; 1501311128Sdim continue; 1502311128Sdim } 1503311128Sdim 1504311128Sdim // add/sub %rsp/%esp 1505311128Sdim int amount; 1506311128Sdim if (add_rsp_pattern_p(amount)) { 1507311128Sdim row->SetOffset(offset); 1508311128Sdim row->GetCFAValue().IncOffset(-amount); 1509311128Sdim 1510311128Sdim UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row)); 1511311128Sdim unwind_plan.InsertRow(new_row); 1512311128Sdim unwind_plan_updated = true; 1513311128Sdim continue; 1514311128Sdim } 1515311128Sdim if (sub_rsp_pattern_p(amount)) { 1516311128Sdim row->SetOffset(offset); 1517311128Sdim row->GetCFAValue().IncOffset(amount); 1518311128Sdim 1519311128Sdim UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row)); 1520311128Sdim unwind_plan.InsertRow(new_row); 1521311128Sdim unwind_plan_updated = true; 1522311128Sdim continue; 1523311128Sdim } 1524311128Sdim 1525311128Sdim // lea %rsp, [%rsp + $offset] 1526311128Sdim if (lea_rsp_pattern_p(amount)) { 1527311128Sdim row->SetOffset(offset); 1528311128Sdim row->GetCFAValue().IncOffset(-amount); 1529311128Sdim 1530311128Sdim UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row)); 1531311128Sdim unwind_plan.InsertRow(new_row); 1532311128Sdim unwind_plan_updated = true; 1533311128Sdim continue; 1534311128Sdim } 1535311128Sdim 1536311128Sdim if (ret_pattern_p()) { 1537311128Sdim reinstate_unwind_state = true; 1538311128Sdim continue; 1539311128Sdim } 1540311128Sdim } else if (cfa_reg == m_lldb_fp_regnum) { 1541311128Sdim // CFA register is fp. 1542311128Sdim 1543311128Sdim // The only case we care about is epilogue: 1544311128Sdim // [0x5d] pop %rbp/%ebp 1545311128Sdim // => [0xc3] ret 1546311128Sdim if (pop_rbp_pattern_p() || leave_pattern_p()) { 1547360784Sdim m_cur_insn++; 1548360784Sdim if (ret_pattern_p()) { 1549360784Sdim row->SetOffset(offset); 1550360784Sdim row->GetCFAValue().SetIsRegisterPlusOffset( 1551360784Sdim first_row->GetCFAValue().GetRegisterNumber(), m_wordsize); 1552311128Sdim 1553360784Sdim UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row)); 1554360784Sdim unwind_plan.InsertRow(new_row); 1555360784Sdim unwind_plan_updated = true; 1556360784Sdim reinstate_unwind_state = true; 1557360784Sdim continue; 1558360784Sdim } 1559311128Sdim } 1560311128Sdim } else { 1561311128Sdim // CFA register is not sp or fp. 1562311128Sdim 1563311128Sdim // This must be hand-written assembly. 1564311128Sdim // Just trust eh_frame and assume we have finished. 1565311128Sdim break; 1566311128Sdim } 1567311128Sdim } 1568311128Sdim 1569311128Sdim unwind_plan.SetPlanValidAddressRange(func_range); 1570311128Sdim if (unwind_plan_updated) { 1571311128Sdim std::string unwind_plan_source(unwind_plan.GetSourceName().AsCString()); 1572311128Sdim unwind_plan_source += " plus augmentation from assembly parsing"; 1573311128Sdim unwind_plan.SetSourceName(unwind_plan_source.c_str()); 1574311128Sdim unwind_plan.SetSourcedFromCompiler(eLazyBoolNo); 1575311128Sdim unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolYes); 1576311128Sdim } 1577311128Sdim return true; 1578311128Sdim} 1579311128Sdim 1580311128Sdimbool x86AssemblyInspectionEngine::FindFirstNonPrologueInstruction( 1581311128Sdim uint8_t *data, size_t size, size_t &offset) { 1582311128Sdim offset = 0; 1583311128Sdim 1584344779Sdim if (!m_register_map_initialized) 1585311128Sdim return false; 1586311128Sdim 1587311128Sdim while (offset < size) { 1588311128Sdim int regno; 1589311128Sdim int insn_len; 1590311128Sdim int scratch; 1591311128Sdim 1592311128Sdim m_cur_insn = data + offset; 1593321369Sdim if (!instruction_length(m_cur_insn, insn_len, size - offset) 1594321369Sdim || insn_len > kMaxInstructionByteSize 1595321369Sdim || insn_len == 0) { 1596311128Sdim // An error parsing the instruction, i.e. probably data/garbage - stop 1597311128Sdim // scanning 1598311128Sdim break; 1599311128Sdim } 1600311128Sdim 1601311128Sdim if (push_rbp_pattern_p() || mov_rsp_rbp_pattern_p() || 1602311128Sdim sub_rsp_pattern_p(scratch) || push_reg_p(regno) || 1603311128Sdim mov_reg_to_local_stack_frame_p(regno, scratch) || 1604311128Sdim (lea_rsp_pattern_p(scratch) && offset == 0)) { 1605311128Sdim offset += insn_len; 1606311128Sdim continue; 1607311128Sdim } 1608311128Sdim // 1609311128Sdim // Unknown non-prologue instruction - stop scanning 1610311128Sdim break; 1611311128Sdim } 1612311128Sdim 1613311128Sdim return true; 1614311128Sdim} 1615