x86AssemblyInspectionEngine.cpp revision 344779
1311128Sdim//===-- x86AssemblyInspectionEngine.cpp -------------------------*- C++ -*-===// 2311128Sdim// 3311128Sdim// The LLVM Compiler Infrastructure 4311128Sdim// 5311128Sdim// This file is distributed under the University of Illinois Open Source 6311128Sdim// License. See LICENSE.TXT for details. 7311128Sdim// 8311128Sdim//===----------------------------------------------------------------------===// 9311128Sdim 10311128Sdim#include "x86AssemblyInspectionEngine.h" 11311128Sdim 12311128Sdim#include "llvm-c/Disassembler.h" 13311128Sdim 14311128Sdim#include "lldb/Core/Address.h" 15311128Sdim#include "lldb/Symbol/UnwindPlan.h" 16311128Sdim#include "lldb/Target/RegisterContext.h" 17311128Sdim#include "lldb/Target/UnwindAssembly.h" 18311128Sdim 19311128Sdimusing namespace lldb_private; 20311128Sdimusing namespace lldb; 21311128Sdim 22311128Sdimx86AssemblyInspectionEngine::x86AssemblyInspectionEngine(const ArchSpec &arch) 23311128Sdim : m_cur_insn(nullptr), m_machine_ip_regnum(LLDB_INVALID_REGNUM), 24311128Sdim m_machine_sp_regnum(LLDB_INVALID_REGNUM), 25311128Sdim m_machine_fp_regnum(LLDB_INVALID_REGNUM), 26311128Sdim m_lldb_ip_regnum(LLDB_INVALID_REGNUM), 27311128Sdim m_lldb_sp_regnum(LLDB_INVALID_REGNUM), 28311128Sdim m_lldb_fp_regnum(LLDB_INVALID_REGNUM), 29311128Sdim 30311128Sdim m_reg_map(), m_arch(arch), m_cpu(k_cpu_unspecified), m_wordsize(-1), 31311128Sdim m_register_map_initialized(false), m_disasm_context() { 32311128Sdim m_disasm_context = 33311128Sdim ::LLVMCreateDisasm(arch.GetTriple().getTriple().c_str(), nullptr, 34311128Sdim /*TagType=*/1, nullptr, nullptr); 35311128Sdim} 36311128Sdim 37311128Sdimx86AssemblyInspectionEngine::~x86AssemblyInspectionEngine() { 38311128Sdim ::LLVMDisasmDispose(m_disasm_context); 39311128Sdim} 40311128Sdim 41311128Sdimvoid x86AssemblyInspectionEngine::Initialize(RegisterContextSP ®_ctx) { 42311128Sdim m_cpu = k_cpu_unspecified; 43311128Sdim m_wordsize = -1; 44311128Sdim m_register_map_initialized = false; 45311128Sdim 46311128Sdim const llvm::Triple::ArchType cpu = m_arch.GetMachine(); 47311128Sdim if (cpu == llvm::Triple::x86) 48311128Sdim m_cpu = k_i386; 49311128Sdim else if (cpu == llvm::Triple::x86_64) 50311128Sdim m_cpu = k_x86_64; 51311128Sdim 52311128Sdim if (m_cpu == k_cpu_unspecified) 53311128Sdim return; 54311128Sdim 55311128Sdim if (reg_ctx.get() == nullptr) 56311128Sdim return; 57311128Sdim 58311128Sdim if (m_cpu == k_i386) { 59311128Sdim m_machine_ip_regnum = k_machine_eip; 60311128Sdim m_machine_sp_regnum = k_machine_esp; 61311128Sdim m_machine_fp_regnum = k_machine_ebp; 62344779Sdim m_machine_alt_fp_regnum = k_machine_ebx; 63311128Sdim m_wordsize = 4; 64311128Sdim 65311128Sdim struct lldb_reg_info reginfo; 66311128Sdim reginfo.name = "eax"; 67311128Sdim m_reg_map[k_machine_eax] = reginfo; 68311128Sdim reginfo.name = "edx"; 69311128Sdim m_reg_map[k_machine_edx] = reginfo; 70311128Sdim reginfo.name = "esp"; 71311128Sdim m_reg_map[k_machine_esp] = reginfo; 72311128Sdim reginfo.name = "esi"; 73311128Sdim m_reg_map[k_machine_esi] = reginfo; 74311128Sdim reginfo.name = "eip"; 75311128Sdim m_reg_map[k_machine_eip] = reginfo; 76311128Sdim reginfo.name = "ecx"; 77311128Sdim m_reg_map[k_machine_ecx] = reginfo; 78311128Sdim reginfo.name = "ebx"; 79311128Sdim m_reg_map[k_machine_ebx] = reginfo; 80311128Sdim reginfo.name = "ebp"; 81311128Sdim m_reg_map[k_machine_ebp] = reginfo; 82311128Sdim reginfo.name = "edi"; 83311128Sdim m_reg_map[k_machine_edi] = reginfo; 84311128Sdim } else { 85311128Sdim m_machine_ip_regnum = k_machine_rip; 86311128Sdim m_machine_sp_regnum = k_machine_rsp; 87311128Sdim m_machine_fp_regnum = k_machine_rbp; 88344779Sdim m_machine_alt_fp_regnum = k_machine_rbx; 89311128Sdim m_wordsize = 8; 90311128Sdim 91311128Sdim struct lldb_reg_info reginfo; 92311128Sdim reginfo.name = "rax"; 93311128Sdim m_reg_map[k_machine_rax] = reginfo; 94311128Sdim reginfo.name = "rdx"; 95311128Sdim m_reg_map[k_machine_rdx] = reginfo; 96311128Sdim reginfo.name = "rsp"; 97311128Sdim m_reg_map[k_machine_rsp] = reginfo; 98311128Sdim reginfo.name = "rsi"; 99311128Sdim m_reg_map[k_machine_rsi] = reginfo; 100311128Sdim reginfo.name = "r8"; 101311128Sdim m_reg_map[k_machine_r8] = reginfo; 102311128Sdim reginfo.name = "r10"; 103311128Sdim m_reg_map[k_machine_r10] = reginfo; 104311128Sdim reginfo.name = "r12"; 105311128Sdim m_reg_map[k_machine_r12] = reginfo; 106311128Sdim reginfo.name = "r14"; 107311128Sdim m_reg_map[k_machine_r14] = reginfo; 108311128Sdim reginfo.name = "rip"; 109311128Sdim m_reg_map[k_machine_rip] = reginfo; 110311128Sdim reginfo.name = "rcx"; 111311128Sdim m_reg_map[k_machine_rcx] = reginfo; 112311128Sdim reginfo.name = "rbx"; 113311128Sdim m_reg_map[k_machine_rbx] = reginfo; 114311128Sdim reginfo.name = "rbp"; 115311128Sdim m_reg_map[k_machine_rbp] = reginfo; 116311128Sdim reginfo.name = "rdi"; 117311128Sdim m_reg_map[k_machine_rdi] = reginfo; 118311128Sdim reginfo.name = "r9"; 119311128Sdim m_reg_map[k_machine_r9] = reginfo; 120311128Sdim reginfo.name = "r11"; 121311128Sdim m_reg_map[k_machine_r11] = reginfo; 122311128Sdim reginfo.name = "r13"; 123311128Sdim m_reg_map[k_machine_r13] = reginfo; 124311128Sdim reginfo.name = "r15"; 125311128Sdim m_reg_map[k_machine_r15] = reginfo; 126311128Sdim } 127311128Sdim 128311128Sdim for (MachineRegnumToNameAndLLDBRegnum::iterator it = m_reg_map.begin(); 129311128Sdim it != m_reg_map.end(); ++it) { 130311128Sdim const RegisterInfo *ri = reg_ctx->GetRegisterInfoByName(it->second.name); 131311128Sdim if (ri) 132311128Sdim it->second.lldb_regnum = ri->kinds[eRegisterKindLLDB]; 133311128Sdim } 134311128Sdim 135311128Sdim uint32_t lldb_regno; 136311128Sdim if (machine_regno_to_lldb_regno(m_machine_sp_regnum, lldb_regno)) 137311128Sdim m_lldb_sp_regnum = lldb_regno; 138311128Sdim if (machine_regno_to_lldb_regno(m_machine_fp_regnum, lldb_regno)) 139311128Sdim m_lldb_fp_regnum = lldb_regno; 140344779Sdim if (machine_regno_to_lldb_regno(m_machine_alt_fp_regnum, lldb_regno)) 141344779Sdim m_lldb_alt_fp_regnum = lldb_regno; 142311128Sdim if (machine_regno_to_lldb_regno(m_machine_ip_regnum, lldb_regno)) 143311128Sdim m_lldb_ip_regnum = lldb_regno; 144311128Sdim 145311128Sdim m_register_map_initialized = true; 146311128Sdim} 147311128Sdim 148311128Sdimvoid x86AssemblyInspectionEngine::Initialize( 149311128Sdim std::vector<lldb_reg_info> ®_info) { 150311128Sdim m_cpu = k_cpu_unspecified; 151311128Sdim m_wordsize = -1; 152311128Sdim m_register_map_initialized = false; 153311128Sdim 154311128Sdim const llvm::Triple::ArchType cpu = m_arch.GetMachine(); 155311128Sdim if (cpu == llvm::Triple::x86) 156311128Sdim m_cpu = k_i386; 157311128Sdim else if (cpu == llvm::Triple::x86_64) 158311128Sdim m_cpu = k_x86_64; 159311128Sdim 160311128Sdim if (m_cpu == k_cpu_unspecified) 161311128Sdim return; 162311128Sdim 163311128Sdim if (m_cpu == k_i386) { 164311128Sdim m_machine_ip_regnum = k_machine_eip; 165311128Sdim m_machine_sp_regnum = k_machine_esp; 166311128Sdim m_machine_fp_regnum = k_machine_ebp; 167344779Sdim m_machine_alt_fp_regnum = k_machine_ebx; 168311128Sdim m_wordsize = 4; 169311128Sdim 170311128Sdim struct lldb_reg_info reginfo; 171311128Sdim reginfo.name = "eax"; 172311128Sdim m_reg_map[k_machine_eax] = reginfo; 173311128Sdim reginfo.name = "edx"; 174311128Sdim m_reg_map[k_machine_edx] = reginfo; 175311128Sdim reginfo.name = "esp"; 176311128Sdim m_reg_map[k_machine_esp] = reginfo; 177311128Sdim reginfo.name = "esi"; 178311128Sdim m_reg_map[k_machine_esi] = reginfo; 179311128Sdim reginfo.name = "eip"; 180311128Sdim m_reg_map[k_machine_eip] = reginfo; 181311128Sdim reginfo.name = "ecx"; 182311128Sdim m_reg_map[k_machine_ecx] = reginfo; 183311128Sdim reginfo.name = "ebx"; 184311128Sdim m_reg_map[k_machine_ebx] = reginfo; 185311128Sdim reginfo.name = "ebp"; 186311128Sdim m_reg_map[k_machine_ebp] = reginfo; 187311128Sdim reginfo.name = "edi"; 188311128Sdim m_reg_map[k_machine_edi] = reginfo; 189311128Sdim } else { 190311128Sdim m_machine_ip_regnum = k_machine_rip; 191311128Sdim m_machine_sp_regnum = k_machine_rsp; 192311128Sdim m_machine_fp_regnum = k_machine_rbp; 193344779Sdim m_machine_alt_fp_regnum = k_machine_rbx; 194311128Sdim m_wordsize = 8; 195311128Sdim 196311128Sdim struct lldb_reg_info reginfo; 197311128Sdim reginfo.name = "rax"; 198311128Sdim m_reg_map[k_machine_rax] = reginfo; 199311128Sdim reginfo.name = "rdx"; 200311128Sdim m_reg_map[k_machine_rdx] = reginfo; 201311128Sdim reginfo.name = "rsp"; 202311128Sdim m_reg_map[k_machine_rsp] = reginfo; 203311128Sdim reginfo.name = "rsi"; 204311128Sdim m_reg_map[k_machine_rsi] = reginfo; 205311128Sdim reginfo.name = "r8"; 206311128Sdim m_reg_map[k_machine_r8] = reginfo; 207311128Sdim reginfo.name = "r10"; 208311128Sdim m_reg_map[k_machine_r10] = reginfo; 209311128Sdim reginfo.name = "r12"; 210311128Sdim m_reg_map[k_machine_r12] = reginfo; 211311128Sdim reginfo.name = "r14"; 212311128Sdim m_reg_map[k_machine_r14] = reginfo; 213311128Sdim reginfo.name = "rip"; 214311128Sdim m_reg_map[k_machine_rip] = reginfo; 215311128Sdim reginfo.name = "rcx"; 216311128Sdim m_reg_map[k_machine_rcx] = reginfo; 217311128Sdim reginfo.name = "rbx"; 218311128Sdim m_reg_map[k_machine_rbx] = reginfo; 219311128Sdim reginfo.name = "rbp"; 220311128Sdim m_reg_map[k_machine_rbp] = reginfo; 221311128Sdim reginfo.name = "rdi"; 222311128Sdim m_reg_map[k_machine_rdi] = reginfo; 223311128Sdim reginfo.name = "r9"; 224311128Sdim m_reg_map[k_machine_r9] = reginfo; 225311128Sdim reginfo.name = "r11"; 226311128Sdim m_reg_map[k_machine_r11] = reginfo; 227311128Sdim reginfo.name = "r13"; 228311128Sdim m_reg_map[k_machine_r13] = reginfo; 229311128Sdim reginfo.name = "r15"; 230311128Sdim m_reg_map[k_machine_r15] = reginfo; 231311128Sdim } 232311128Sdim 233311128Sdim for (MachineRegnumToNameAndLLDBRegnum::iterator it = m_reg_map.begin(); 234311128Sdim it != m_reg_map.end(); ++it) { 235311128Sdim for (size_t i = 0; i < reg_info.size(); ++i) { 236311128Sdim if (::strcmp(reg_info[i].name, it->second.name) == 0) { 237311128Sdim it->second.lldb_regnum = reg_info[i].lldb_regnum; 238311128Sdim break; 239311128Sdim } 240311128Sdim } 241311128Sdim } 242311128Sdim 243311128Sdim uint32_t lldb_regno; 244311128Sdim if (machine_regno_to_lldb_regno(m_machine_sp_regnum, lldb_regno)) 245311128Sdim m_lldb_sp_regnum = lldb_regno; 246311128Sdim if (machine_regno_to_lldb_regno(m_machine_fp_regnum, lldb_regno)) 247311128Sdim m_lldb_fp_regnum = lldb_regno; 248344779Sdim if (machine_regno_to_lldb_regno(m_machine_alt_fp_regnum, lldb_regno)) 249344779Sdim m_lldb_alt_fp_regnum = lldb_regno; 250311128Sdim if (machine_regno_to_lldb_regno(m_machine_ip_regnum, lldb_regno)) 251311128Sdim m_lldb_ip_regnum = lldb_regno; 252311128Sdim 253311128Sdim m_register_map_initialized = true; 254311128Sdim} 255311128Sdim 256311128Sdim// This function expects an x86 native register number (i.e. the bits stripped 257341825Sdim// out of the actual instruction), not an lldb register number. 258311128Sdim// 259311128Sdim// FIXME: This is ABI dependent, it shouldn't be hardcoded here. 260311128Sdim 261311128Sdimbool x86AssemblyInspectionEngine::nonvolatile_reg_p(int machine_regno) { 262311128Sdim if (m_cpu == k_i386) { 263311128Sdim switch (machine_regno) { 264311128Sdim case k_machine_ebx: 265311128Sdim case k_machine_ebp: // not actually a nonvolatile but often treated as such 266311128Sdim // by convention 267311128Sdim case k_machine_esi: 268311128Sdim case k_machine_edi: 269311128Sdim case k_machine_esp: 270311128Sdim return true; 271311128Sdim default: 272311128Sdim return false; 273311128Sdim } 274311128Sdim } 275311128Sdim if (m_cpu == k_x86_64) { 276311128Sdim switch (machine_regno) { 277311128Sdim case k_machine_rbx: 278311128Sdim case k_machine_rsp: 279311128Sdim case k_machine_rbp: // not actually a nonvolatile but often treated as such 280311128Sdim // by convention 281311128Sdim case k_machine_r12: 282311128Sdim case k_machine_r13: 283311128Sdim case k_machine_r14: 284311128Sdim case k_machine_r15: 285311128Sdim return true; 286311128Sdim default: 287311128Sdim return false; 288311128Sdim } 289311128Sdim } 290311128Sdim return false; 291311128Sdim} 292311128Sdim 293311128Sdim// Macro to detect if this is a REX mode prefix byte. 294311128Sdim#define REX_W_PREFIX_P(opcode) (((opcode) & (~0x5)) == 0x48) 295311128Sdim 296311128Sdim// The high bit which should be added to the source register number (the "R" 297311128Sdim// bit) 298311128Sdim#define REX_W_SRCREG(opcode) (((opcode)&0x4) >> 2) 299311128Sdim 300311128Sdim// The high bit which should be added to the destination register number (the 301311128Sdim// "B" bit) 302311128Sdim#define REX_W_DSTREG(opcode) ((opcode)&0x1) 303311128Sdim 304311128Sdim// pushq %rbp [0x55] 305311128Sdimbool x86AssemblyInspectionEngine::push_rbp_pattern_p() { 306311128Sdim uint8_t *p = m_cur_insn; 307344779Sdim return *p == 0x55; 308311128Sdim} 309311128Sdim 310311128Sdim// pushq $0 ; the first instruction in start() [0x6a 0x00] 311311128Sdimbool x86AssemblyInspectionEngine::push_0_pattern_p() { 312311128Sdim uint8_t *p = m_cur_insn; 313344779Sdim return *p == 0x6a && *(p + 1) == 0x0; 314311128Sdim} 315311128Sdim 316311128Sdim// pushq $0 317311128Sdim// pushl $0 318311128Sdimbool x86AssemblyInspectionEngine::push_imm_pattern_p() { 319311128Sdim uint8_t *p = m_cur_insn; 320344779Sdim return *p == 0x68 || *p == 0x6a; 321311128Sdim} 322311128Sdim 323311128Sdim// pushl imm8(%esp) 324311128Sdim// 325341825Sdim// e.g. 0xff 0x74 0x24 0x20 - 'pushl 0x20(%esp)' (same byte pattern for 'pushq 326341825Sdim// 0x20(%rsp)' in an x86_64 program) 327311128Sdim// 328341825Sdim// 0xff (with opcode bits '6' in next byte, PUSH r/m32) 0x74 (ModR/M byte with 329341825Sdim// three bits used to specify the opcode) 330311128Sdim// mod == b01, opcode == b110, R/M == b100 331311128Sdim// "+disp8" 332341825Sdim// 0x24 (SIB byte - scaled index = 0, r32 == esp) 0x20 imm8 value 333311128Sdim 334311128Sdimbool x86AssemblyInspectionEngine::push_extended_pattern_p() { 335311128Sdim if (*m_cur_insn == 0xff) { 336311128Sdim // Get the 3 opcode bits from the ModR/M byte 337311128Sdim uint8_t opcode = (*(m_cur_insn + 1) >> 3) & 7; 338311128Sdim if (opcode == 6) { 339311128Sdim // I'm only looking for 0xff /6 here - I 340341825Sdim // don't really care what value is being pushed, just that we're pushing 341341825Sdim // a 32/64 bit value on to the stack is enough. 342311128Sdim return true; 343311128Sdim } 344311128Sdim } 345311128Sdim return false; 346311128Sdim} 347311128Sdim 348311128Sdim// instructions only valid in 32-bit mode: 349311128Sdim// 0x0e - push cs 350311128Sdim// 0x16 - push ss 351311128Sdim// 0x1e - push ds 352311128Sdim// 0x06 - push es 353311128Sdimbool x86AssemblyInspectionEngine::push_misc_reg_p() { 354311128Sdim uint8_t p = *m_cur_insn; 355311128Sdim if (m_wordsize == 4) { 356311128Sdim if (p == 0x0e || p == 0x16 || p == 0x1e || p == 0x06) 357311128Sdim return true; 358311128Sdim } 359311128Sdim return false; 360311128Sdim} 361311128Sdim 362311128Sdim// pushq %rbx 363311128Sdim// pushl %ebx 364311128Sdimbool x86AssemblyInspectionEngine::push_reg_p(int ®no) { 365311128Sdim uint8_t *p = m_cur_insn; 366311128Sdim int regno_prefix_bit = 0; 367311128Sdim // If we have a rex prefix byte, check to see if a B bit is set 368311128Sdim if (m_wordsize == 8 && *p == 0x41) { 369311128Sdim regno_prefix_bit = 1 << 3; 370311128Sdim p++; 371311128Sdim } 372311128Sdim if (*p >= 0x50 && *p <= 0x57) { 373311128Sdim regno = (*p - 0x50) | regno_prefix_bit; 374311128Sdim return true; 375311128Sdim } 376311128Sdim return false; 377311128Sdim} 378311128Sdim 379341825Sdim// movq %rsp, %rbp [0x48 0x8b 0xec] or [0x48 0x89 0xe5] movl %esp, %ebp [0x8b 380341825Sdim// 0xec] or [0x89 0xe5] 381311128Sdimbool x86AssemblyInspectionEngine::mov_rsp_rbp_pattern_p() { 382311128Sdim uint8_t *p = m_cur_insn; 383311128Sdim if (m_wordsize == 8 && *p == 0x48) 384311128Sdim p++; 385311128Sdim if (*(p) == 0x8b && *(p + 1) == 0xec) 386311128Sdim return true; 387311128Sdim if (*(p) == 0x89 && *(p + 1) == 0xe5) 388311128Sdim return true; 389311128Sdim return false; 390311128Sdim} 391311128Sdim 392344779Sdim// movq %rsp, %rbx [0x48 0x8b 0xdc] or [0x48 0x89 0xe3] 393344779Sdim// movl %esp, %ebx [0x8b 0xdc] or [0x89 0xe3] 394344779Sdimbool x86AssemblyInspectionEngine::mov_rsp_rbx_pattern_p() { 395344779Sdim uint8_t *p = m_cur_insn; 396344779Sdim if (m_wordsize == 8 && *p == 0x48) 397344779Sdim p++; 398344779Sdim if (*(p) == 0x8b && *(p + 1) == 0xdc) 399344779Sdim return true; 400344779Sdim if (*(p) == 0x89 && *(p + 1) == 0xe3) 401344779Sdim return true; 402344779Sdim return false; 403344779Sdim} 404344779Sdim 405344779Sdim// movq %rbp, %rsp [0x48 0x8b 0xe5] or [0x48 0x89 0xec] 406344779Sdim// movl %ebp, %esp [0x8b 0xe5] or [0x89 0xec] 407344779Sdimbool x86AssemblyInspectionEngine::mov_rbp_rsp_pattern_p() { 408344779Sdim uint8_t *p = m_cur_insn; 409344779Sdim if (m_wordsize == 8 && *p == 0x48) 410344779Sdim p++; 411344779Sdim if (*(p) == 0x8b && *(p + 1) == 0xe5) 412344779Sdim return true; 413344779Sdim if (*(p) == 0x89 && *(p + 1) == 0xec) 414344779Sdim return true; 415344779Sdim return false; 416344779Sdim} 417344779Sdim 418344779Sdim// movq %rbx, %rsp [0x48 0x8b 0xe3] or [0x48 0x89 0xdc] 419344779Sdim// movl %ebx, %esp [0x8b 0xe3] or [0x89 0xdc] 420344779Sdimbool x86AssemblyInspectionEngine::mov_rbx_rsp_pattern_p() { 421344779Sdim uint8_t *p = m_cur_insn; 422344779Sdim if (m_wordsize == 8 && *p == 0x48) 423344779Sdim p++; 424344779Sdim if (*(p) == 0x8b && *(p + 1) == 0xe3) 425344779Sdim return true; 426344779Sdim if (*(p) == 0x89 && *(p + 1) == 0xdc) 427344779Sdim return true; 428344779Sdim return false; 429344779Sdim} 430344779Sdim 431311128Sdim// subq $0x20, %rsp 432311128Sdimbool x86AssemblyInspectionEngine::sub_rsp_pattern_p(int &amount) { 433311128Sdim uint8_t *p = m_cur_insn; 434311128Sdim if (m_wordsize == 8 && *p == 0x48) 435311128Sdim p++; 436311128Sdim // 8-bit immediate operand 437311128Sdim if (*p == 0x83 && *(p + 1) == 0xec) { 438311128Sdim amount = (int8_t) * (p + 2); 439311128Sdim return true; 440311128Sdim } 441311128Sdim // 32-bit immediate operand 442311128Sdim if (*p == 0x81 && *(p + 1) == 0xec) { 443311128Sdim amount = (int32_t)extract_4(p + 2); 444311128Sdim return true; 445311128Sdim } 446311128Sdim return false; 447311128Sdim} 448311128Sdim 449311128Sdim// addq $0x20, %rsp 450311128Sdimbool x86AssemblyInspectionEngine::add_rsp_pattern_p(int &amount) { 451311128Sdim uint8_t *p = m_cur_insn; 452311128Sdim if (m_wordsize == 8 && *p == 0x48) 453311128Sdim p++; 454311128Sdim // 8-bit immediate operand 455311128Sdim if (*p == 0x83 && *(p + 1) == 0xc4) { 456311128Sdim amount = (int8_t) * (p + 2); 457311128Sdim return true; 458311128Sdim } 459311128Sdim // 32-bit immediate operand 460311128Sdim if (*p == 0x81 && *(p + 1) == 0xc4) { 461311128Sdim amount = (int32_t)extract_4(p + 2); 462311128Sdim return true; 463311128Sdim } 464311128Sdim return false; 465311128Sdim} 466311128Sdim 467311128Sdim// lea esp, [esp - 0x28] 468311128Sdim// lea esp, [esp + 0x28] 469311128Sdimbool x86AssemblyInspectionEngine::lea_rsp_pattern_p(int &amount) { 470311128Sdim uint8_t *p = m_cur_insn; 471311128Sdim if (m_wordsize == 8 && *p == 0x48) 472311128Sdim p++; 473311128Sdim 474311128Sdim // Check opcode 475311128Sdim if (*p != 0x8d) 476311128Sdim return false; 477311128Sdim 478311128Sdim // 8 bit displacement 479311128Sdim if (*(p + 1) == 0x64 && (*(p + 2) & 0x3f) == 0x24) { 480311128Sdim amount = (int8_t) * (p + 3); 481311128Sdim return true; 482311128Sdim } 483311128Sdim 484311128Sdim // 32 bit displacement 485311128Sdim if (*(p + 1) == 0xa4 && (*(p + 2) & 0x3f) == 0x24) { 486311128Sdim amount = (int32_t)extract_4(p + 3); 487311128Sdim return true; 488311128Sdim } 489311128Sdim 490311128Sdim return false; 491311128Sdim} 492311128Sdim 493321369Sdim// lea -0x28(%ebp), %esp 494321369Sdim// (32-bit and 64-bit variants, 8-bit and 32-bit displacement) 495321369Sdimbool x86AssemblyInspectionEngine::lea_rbp_rsp_pattern_p(int &amount) { 496321369Sdim uint8_t *p = m_cur_insn; 497321369Sdim if (m_wordsize == 8 && *p == 0x48) 498321369Sdim p++; 499321369Sdim 500321369Sdim // Check opcode 501321369Sdim if (*p != 0x8d) 502321369Sdim return false; 503321369Sdim ++p; 504321369Sdim 505321369Sdim // 8 bit displacement 506321369Sdim if (*p == 0x65) { 507321369Sdim amount = (int8_t)p[1]; 508321369Sdim return true; 509321369Sdim } 510321369Sdim 511321369Sdim // 32 bit displacement 512321369Sdim if (*p == 0xa5) { 513321369Sdim amount = (int32_t)extract_4(p + 1); 514321369Sdim return true; 515321369Sdim } 516321369Sdim 517321369Sdim return false; 518321369Sdim} 519321369Sdim 520344779Sdim// lea -0x28(%ebx), %esp 521344779Sdim// (32-bit and 64-bit variants, 8-bit and 32-bit displacement) 522344779Sdimbool x86AssemblyInspectionEngine::lea_rbx_rsp_pattern_p(int &amount) { 523344779Sdim uint8_t *p = m_cur_insn; 524344779Sdim if (m_wordsize == 8 && *p == 0x48) 525344779Sdim p++; 526344779Sdim 527344779Sdim // Check opcode 528344779Sdim if (*p != 0x8d) 529344779Sdim return false; 530344779Sdim ++p; 531344779Sdim 532344779Sdim // 8 bit displacement 533344779Sdim if (*p == 0x63) { 534344779Sdim amount = (int8_t)p[1]; 535344779Sdim return true; 536344779Sdim } 537344779Sdim 538344779Sdim // 32 bit displacement 539344779Sdim if (*p == 0xa3) { 540344779Sdim amount = (int32_t)extract_4(p + 1); 541344779Sdim return true; 542344779Sdim } 543344779Sdim 544344779Sdim return false; 545344779Sdim} 546344779Sdim 547344779Sdim// and -0xfffffff0, %esp 548344779Sdim// (32-bit and 64-bit variants, 8-bit and 32-bit displacement) 549344779Sdimbool x86AssemblyInspectionEngine::and_rsp_pattern_p() { 550344779Sdim uint8_t *p = m_cur_insn; 551344779Sdim if (m_wordsize == 8 && *p == 0x48) 552344779Sdim p++; 553344779Sdim 554344779Sdim if (*p != 0x81 && *p != 0x83) 555344779Sdim return false; 556344779Sdim 557344779Sdim return *++p == 0xe4; 558344779Sdim} 559344779Sdim 560311128Sdim// popq %rbx 561311128Sdim// popl %ebx 562311128Sdimbool x86AssemblyInspectionEngine::pop_reg_p(int ®no) { 563311128Sdim uint8_t *p = m_cur_insn; 564311128Sdim int regno_prefix_bit = 0; 565311128Sdim // If we have a rex prefix byte, check to see if a B bit is set 566311128Sdim if (m_wordsize == 8 && *p == 0x41) { 567311128Sdim regno_prefix_bit = 1 << 3; 568311128Sdim p++; 569311128Sdim } 570311128Sdim if (*p >= 0x58 && *p <= 0x5f) { 571311128Sdim regno = (*p - 0x58) | regno_prefix_bit; 572311128Sdim return true; 573311128Sdim } 574311128Sdim return false; 575311128Sdim} 576311128Sdim 577311128Sdim// popq %rbp [0x5d] 578311128Sdim// popl %ebp [0x5d] 579311128Sdimbool x86AssemblyInspectionEngine::pop_rbp_pattern_p() { 580311128Sdim uint8_t *p = m_cur_insn; 581311128Sdim return (*p == 0x5d); 582311128Sdim} 583311128Sdim 584311128Sdim// instructions valid only in 32-bit mode: 585311128Sdim// 0x1f - pop ds 586311128Sdim// 0x07 - pop es 587311128Sdim// 0x17 - pop ss 588311128Sdimbool x86AssemblyInspectionEngine::pop_misc_reg_p() { 589311128Sdim uint8_t p = *m_cur_insn; 590311128Sdim if (m_wordsize == 4) { 591311128Sdim if (p == 0x1f || p == 0x07 || p == 0x17) 592311128Sdim return true; 593311128Sdim } 594311128Sdim return false; 595311128Sdim} 596311128Sdim 597311128Sdim// leave [0xc9] 598311128Sdimbool x86AssemblyInspectionEngine::leave_pattern_p() { 599311128Sdim uint8_t *p = m_cur_insn; 600311128Sdim return (*p == 0xc9); 601311128Sdim} 602311128Sdim 603311128Sdim// call $0 [0xe8 0x0 0x0 0x0 0x0] 604311128Sdimbool x86AssemblyInspectionEngine::call_next_insn_pattern_p() { 605311128Sdim uint8_t *p = m_cur_insn; 606311128Sdim return (*p == 0xe8) && (*(p + 1) == 0x0) && (*(p + 2) == 0x0) && 607311128Sdim (*(p + 3) == 0x0) && (*(p + 4) == 0x0); 608311128Sdim} 609311128Sdim 610341825Sdim// Look for an instruction sequence storing a nonvolatile register on to the 611341825Sdim// stack frame. 612311128Sdim 613311128Sdim// movq %rax, -0x10(%rbp) [0x48 0x89 0x45 0xf0] 614311128Sdim// movl %eax, -0xc(%ebp) [0x89 0x45 0xf4] 615311128Sdim 616341825Sdim// The offset value returned in rbp_offset will be positive -- but it must be 617341825Sdim// subtraced from the frame base register to get the actual location. The 618341825Sdim// positive value returned for the offset is a convention used elsewhere for 619341825Sdim// CFA offsets et al. 620311128Sdim 621311128Sdimbool x86AssemblyInspectionEngine::mov_reg_to_local_stack_frame_p( 622311128Sdim int ®no, int &rbp_offset) { 623311128Sdim uint8_t *p = m_cur_insn; 624311128Sdim int src_reg_prefix_bit = 0; 625311128Sdim int target_reg_prefix_bit = 0; 626311128Sdim 627311128Sdim if (m_wordsize == 8 && REX_W_PREFIX_P(*p)) { 628311128Sdim src_reg_prefix_bit = REX_W_SRCREG(*p) << 3; 629311128Sdim target_reg_prefix_bit = REX_W_DSTREG(*p) << 3; 630311128Sdim if (target_reg_prefix_bit == 1) { 631341825Sdim // rbp/ebp don't need a prefix bit - we know this isn't the reg we care 632341825Sdim // about. 633311128Sdim return false; 634311128Sdim } 635311128Sdim p++; 636311128Sdim } 637311128Sdim 638311128Sdim if (*p == 0x89) { 639311128Sdim /* Mask off the 3-5 bits which indicate the destination register 640311128Sdim if this is a ModR/M byte. */ 641311128Sdim int opcode_destreg_masked_out = *(p + 1) & (~0x38); 642311128Sdim 643311128Sdim /* Is this a ModR/M byte with Mod bits 01 and R/M bits 101 644311128Sdim and three bits between them, e.g. 01nnn101 645311128Sdim We're looking for a destination of ebp-disp8 or ebp-disp32. */ 646311128Sdim int immsize; 647311128Sdim if (opcode_destreg_masked_out == 0x45) 648311128Sdim immsize = 2; 649311128Sdim else if (opcode_destreg_masked_out == 0x85) 650311128Sdim immsize = 4; 651311128Sdim else 652311128Sdim return false; 653311128Sdim 654311128Sdim int offset = 0; 655311128Sdim if (immsize == 2) 656311128Sdim offset = (int8_t) * (p + 2); 657311128Sdim if (immsize == 4) 658311128Sdim offset = (uint32_t)extract_4(p + 2); 659311128Sdim if (offset > 0) 660311128Sdim return false; 661311128Sdim 662311128Sdim regno = ((*(p + 1) >> 3) & 0x7) | src_reg_prefix_bit; 663311128Sdim rbp_offset = offset > 0 ? offset : -offset; 664311128Sdim return true; 665311128Sdim } 666311128Sdim return false; 667311128Sdim} 668311128Sdim 669311128Sdim// ret [0xc9] or [0xc2 imm8] or [0xca imm8] 670311128Sdimbool x86AssemblyInspectionEngine::ret_pattern_p() { 671311128Sdim uint8_t *p = m_cur_insn; 672344779Sdim return *p == 0xc9 || *p == 0xc2 || *p == 0xca || *p == 0xc3; 673311128Sdim} 674311128Sdim 675311128Sdimuint32_t x86AssemblyInspectionEngine::extract_4(uint8_t *b) { 676311128Sdim uint32_t v = 0; 677311128Sdim for (int i = 3; i >= 0; i--) 678311128Sdim v = (v << 8) | b[i]; 679311128Sdim return v; 680311128Sdim} 681311128Sdim 682311128Sdimbool x86AssemblyInspectionEngine::instruction_length(uint8_t *insn_p, 683321369Sdim int &length, 684321369Sdim uint32_t buffer_remaining_bytes) { 685311128Sdim 686321369Sdim uint32_t max_op_byte_size = std::min(buffer_remaining_bytes, m_arch.GetMaximumOpcodeByteSize()); 687311128Sdim llvm::SmallVector<uint8_t, 32> opcode_data; 688311128Sdim opcode_data.resize(max_op_byte_size); 689311128Sdim 690311128Sdim char out_string[512]; 691311128Sdim const size_t inst_size = 692311128Sdim ::LLVMDisasmInstruction(m_disasm_context, insn_p, max_op_byte_size, 0, 693311128Sdim out_string, sizeof(out_string)); 694311128Sdim 695311128Sdim length = inst_size; 696311128Sdim return true; 697311128Sdim} 698311128Sdim 699311128Sdimbool x86AssemblyInspectionEngine::machine_regno_to_lldb_regno( 700311128Sdim int machine_regno, uint32_t &lldb_regno) { 701311128Sdim MachineRegnumToNameAndLLDBRegnum::iterator it = m_reg_map.find(machine_regno); 702311128Sdim if (it != m_reg_map.end()) { 703311128Sdim lldb_regno = it->second.lldb_regnum; 704311128Sdim return true; 705311128Sdim } 706311128Sdim return false; 707311128Sdim return false; 708311128Sdim} 709311128Sdim 710311128Sdimbool x86AssemblyInspectionEngine::GetNonCallSiteUnwindPlanFromAssembly( 711311128Sdim uint8_t *data, size_t size, AddressRange &func_range, 712311128Sdim UnwindPlan &unwind_plan) { 713311128Sdim unwind_plan.Clear(); 714311128Sdim 715311128Sdim if (data == nullptr || size == 0) 716311128Sdim return false; 717311128Sdim 718344779Sdim if (!m_register_map_initialized) 719311128Sdim return false; 720311128Sdim 721311128Sdim addr_t current_func_text_offset = 0; 722344779Sdim int current_sp_bytes_offset_from_fa = 0; 723344779Sdim bool is_aligned = false; 724311128Sdim UnwindPlan::Row::RegisterLocation initial_regloc; 725311128Sdim UnwindPlan::RowSP row(new UnwindPlan::Row); 726311128Sdim 727311128Sdim unwind_plan.SetPlanValidAddressRange(func_range); 728311128Sdim unwind_plan.SetRegisterKind(eRegisterKindLLDB); 729311128Sdim 730311128Sdim // At the start of the function, find the CFA by adding wordsize to the SP 731311128Sdim // register 732311128Sdim row->SetOffset(current_func_text_offset); 733311128Sdim row->GetCFAValue().SetIsRegisterPlusOffset(m_lldb_sp_regnum, m_wordsize); 734311128Sdim 735311128Sdim // caller's stack pointer value before the call insn is the CFA address 736311128Sdim initial_regloc.SetIsCFAPlusOffset(0); 737311128Sdim row->SetRegisterInfo(m_lldb_sp_regnum, initial_regloc); 738311128Sdim 739311128Sdim // saved instruction pointer can be found at CFA - wordsize. 740344779Sdim current_sp_bytes_offset_from_fa = m_wordsize; 741344779Sdim initial_regloc.SetAtCFAPlusOffset(-current_sp_bytes_offset_from_fa); 742311128Sdim row->SetRegisterInfo(m_lldb_ip_regnum, initial_regloc); 743311128Sdim 744311128Sdim unwind_plan.AppendRow(row); 745311128Sdim 746311128Sdim // Allocate a new Row, populate it with the existing Row contents. 747311128Sdim UnwindPlan::Row *newrow = new UnwindPlan::Row; 748311128Sdim *newrow = *row.get(); 749311128Sdim row.reset(newrow); 750311128Sdim 751341825Sdim // Track which registers have been saved so far in the prologue. If we see 752341825Sdim // another push of that register, it's not part of the prologue. The register 753341825Sdim // numbers used here are the machine register #'s (i386_register_numbers, 754341825Sdim // x86_64_register_numbers). 755311128Sdim std::vector<bool> saved_registers(32, false); 756311128Sdim 757311128Sdim // Once the prologue has completed we'll save a copy of the unwind 758341825Sdim // instructions If there is an epilogue in the middle of the function, after 759341825Sdim // that epilogue we'll reinstate the unwind setup -- we assume that some code 760341825Sdim // path jumps over the mid-function epilogue 761311128Sdim 762311128Sdim UnwindPlan::RowSP prologue_completed_row; // copy of prologue row of CFI 763311128Sdim int prologue_completed_sp_bytes_offset_from_cfa; // The sp value before the 764311128Sdim // epilogue started executed 765344779Sdim bool prologue_completed_is_aligned; 766311128Sdim std::vector<bool> prologue_completed_saved_registers; 767311128Sdim 768311128Sdim while (current_func_text_offset < size) { 769311128Sdim int stack_offset, insn_len; 770311128Sdim int machine_regno; // register numbers masked directly out of instructions 771311128Sdim uint32_t lldb_regno; // register numbers in lldb's eRegisterKindLLDB 772311128Sdim // numbering scheme 773311128Sdim 774311128Sdim bool in_epilogue = false; // we're in the middle of an epilogue sequence 775311128Sdim bool row_updated = false; // The UnwindPlan::Row 'row' has been updated 776311128Sdim 777311128Sdim m_cur_insn = data + current_func_text_offset; 778321369Sdim if (!instruction_length(m_cur_insn, insn_len, size - current_func_text_offset) 779321369Sdim || insn_len == 0 780321369Sdim || insn_len > kMaxInstructionByteSize) { 781311128Sdim // An unrecognized/junk instruction 782311128Sdim break; 783311128Sdim } 784311128Sdim 785344779Sdim auto &cfa_value = row->GetCFAValue(); 786344779Sdim auto &afa_value = row->GetAFAValue(); 787344779Sdim auto fa_value_ptr = is_aligned ? &afa_value : &cfa_value; 788344779Sdim 789344779Sdim if (mov_rsp_rbp_pattern_p()) { 790344779Sdim if (fa_value_ptr->GetRegisterNumber() == m_lldb_sp_regnum) { 791344779Sdim fa_value_ptr->SetIsRegisterPlusOffset( 792344779Sdim m_lldb_fp_regnum, fa_value_ptr->GetOffset()); 793344779Sdim row_updated = true; 794344779Sdim } 795311128Sdim } 796311128Sdim 797344779Sdim else if (mov_rsp_rbx_pattern_p()) { 798344779Sdim if (fa_value_ptr->GetRegisterNumber() == m_lldb_sp_regnum) { 799344779Sdim fa_value_ptr->SetIsRegisterPlusOffset( 800344779Sdim m_lldb_alt_fp_regnum, fa_value_ptr->GetOffset()); 801344779Sdim row_updated = true; 802344779Sdim } 803344779Sdim } 804344779Sdim 805344779Sdim else if (and_rsp_pattern_p()) { 806344779Sdim current_sp_bytes_offset_from_fa = 0; 807344779Sdim afa_value.SetIsRegisterPlusOffset( 808344779Sdim m_lldb_sp_regnum, current_sp_bytes_offset_from_fa); 809344779Sdim fa_value_ptr = &afa_value; 810344779Sdim is_aligned = true; 811311128Sdim row_updated = true; 812311128Sdim } 813311128Sdim 814344779Sdim else if (mov_rbp_rsp_pattern_p()) { 815344779Sdim if (is_aligned && cfa_value.GetRegisterNumber() == m_lldb_fp_regnum) 816344779Sdim { 817344779Sdim is_aligned = false; 818344779Sdim fa_value_ptr = &cfa_value; 819344779Sdim afa_value.SetUnspecified(); 820344779Sdim row_updated = true; 821344779Sdim } 822344779Sdim if (fa_value_ptr->GetRegisterNumber() == m_lldb_fp_regnum) 823344779Sdim current_sp_bytes_offset_from_fa = fa_value_ptr->GetOffset(); 824344779Sdim } 825344779Sdim 826344779Sdim else if (mov_rbx_rsp_pattern_p()) { 827344779Sdim if (is_aligned && cfa_value.GetRegisterNumber() == m_lldb_alt_fp_regnum) 828344779Sdim { 829344779Sdim is_aligned = false; 830344779Sdim fa_value_ptr = &cfa_value; 831344779Sdim afa_value.SetUnspecified(); 832344779Sdim row_updated = true; 833344779Sdim } 834344779Sdim if (fa_value_ptr->GetRegisterNumber() == m_lldb_alt_fp_regnum) 835344779Sdim current_sp_bytes_offset_from_fa = fa_value_ptr->GetOffset(); 836344779Sdim } 837344779Sdim 838311128Sdim // This is the start() function (or a pthread equivalent), it starts with a 839341825Sdim // pushl $0x0 which puts the saved pc value of 0 on the stack. In this 840341825Sdim // case we want to pretend we didn't see a stack movement at all -- 841311128Sdim // normally the saved pc value is already on the stack by the time the 842311128Sdim // function starts executing. 843311128Sdim else if (push_0_pattern_p()) { 844311128Sdim } 845311128Sdim 846311128Sdim else if (push_reg_p(machine_regno)) { 847344779Sdim current_sp_bytes_offset_from_fa += m_wordsize; 848344779Sdim // the PUSH instruction has moved the stack pointer - if the FA is set 849341825Sdim // in terms of the stack pointer, we need to add a new row of 850341825Sdim // instructions. 851344779Sdim if (fa_value_ptr->GetRegisterNumber() == m_lldb_sp_regnum) { 852344779Sdim fa_value_ptr->SetOffset(current_sp_bytes_offset_from_fa); 853311128Sdim row_updated = true; 854311128Sdim } 855311128Sdim // record where non-volatile (callee-saved, spilled) registers are saved 856311128Sdim // on the stack 857311128Sdim if (nonvolatile_reg_p(machine_regno) && 858311128Sdim machine_regno_to_lldb_regno(machine_regno, lldb_regno) && 859344779Sdim !saved_registers[machine_regno]) { 860311128Sdim UnwindPlan::Row::RegisterLocation regloc; 861344779Sdim if (is_aligned) 862344779Sdim regloc.SetAtAFAPlusOffset(-current_sp_bytes_offset_from_fa); 863344779Sdim else 864344779Sdim regloc.SetAtCFAPlusOffset(-current_sp_bytes_offset_from_fa); 865311128Sdim row->SetRegisterInfo(lldb_regno, regloc); 866311128Sdim saved_registers[machine_regno] = true; 867311128Sdim row_updated = true; 868311128Sdim } 869311128Sdim } 870311128Sdim 871311128Sdim else if (pop_reg_p(machine_regno)) { 872344779Sdim current_sp_bytes_offset_from_fa -= m_wordsize; 873311128Sdim 874311128Sdim if (nonvolatile_reg_p(machine_regno) && 875311128Sdim machine_regno_to_lldb_regno(machine_regno, lldb_regno) && 876344779Sdim saved_registers[machine_regno]) { 877311128Sdim saved_registers[machine_regno] = false; 878311128Sdim row->RemoveRegisterInfo(lldb_regno); 879311128Sdim 880344779Sdim if (lldb_regno == fa_value_ptr->GetRegisterNumber()) { 881344779Sdim fa_value_ptr->SetIsRegisterPlusOffset( 882344779Sdim m_lldb_sp_regnum, fa_value_ptr->GetOffset()); 883311128Sdim } 884311128Sdim 885311128Sdim in_epilogue = true; 886311128Sdim row_updated = true; 887311128Sdim } 888311128Sdim 889344779Sdim // the POP instruction has moved the stack pointer - if the FA is set in 890341825Sdim // terms of the stack pointer, we need to add a new row of instructions. 891344779Sdim if (fa_value_ptr->GetRegisterNumber() == m_lldb_sp_regnum) { 892344779Sdim fa_value_ptr->SetIsRegisterPlusOffset( 893344779Sdim m_lldb_sp_regnum, current_sp_bytes_offset_from_fa); 894311128Sdim row_updated = true; 895311128Sdim } 896311128Sdim } 897311128Sdim 898311128Sdim else if (pop_misc_reg_p()) { 899344779Sdim current_sp_bytes_offset_from_fa -= m_wordsize; 900344779Sdim if (fa_value_ptr->GetRegisterNumber() == m_lldb_sp_regnum) { 901344779Sdim fa_value_ptr->SetIsRegisterPlusOffset( 902344779Sdim m_lldb_sp_regnum, current_sp_bytes_offset_from_fa); 903311128Sdim row_updated = true; 904311128Sdim } 905311128Sdim } 906311128Sdim 907341825Sdim // The LEAVE instruction moves the value from rbp into rsp and pops a value 908341825Sdim // off the stack into rbp (restoring the caller's rbp value). It is the 909341825Sdim // opposite of ENTER, or 'push rbp, mov rsp rbp'. 910311128Sdim else if (leave_pattern_p()) { 911344779Sdim if (saved_registers[m_machine_fp_regnum]) { 912344779Sdim saved_registers[m_machine_fp_regnum] = false; 913344779Sdim row->RemoveRegisterInfo(m_lldb_fp_regnum); 914311128Sdim 915344779Sdim row_updated = true; 916344779Sdim } 917311128Sdim 918344779Sdim if (is_aligned && cfa_value.GetRegisterNumber() == m_lldb_fp_regnum) 919344779Sdim { 920344779Sdim is_aligned = false; 921344779Sdim fa_value_ptr = &cfa_value; 922344779Sdim afa_value.SetUnspecified(); 923344779Sdim row_updated = true; 924344779Sdim } 925311128Sdim 926344779Sdim if (fa_value_ptr->GetRegisterNumber() == m_lldb_fp_regnum) 927344779Sdim { 928344779Sdim fa_value_ptr->SetIsRegisterPlusOffset( 929344779Sdim m_lldb_sp_regnum, fa_value_ptr->GetOffset()); 930344779Sdim 931344779Sdim current_sp_bytes_offset_from_fa = fa_value_ptr->GetOffset(); 932344779Sdim } 933344779Sdim 934344779Sdim current_sp_bytes_offset_from_fa -= m_wordsize; 935344779Sdim 936344779Sdim if (fa_value_ptr->GetRegisterNumber() == m_lldb_sp_regnum) { 937344779Sdim fa_value_ptr->SetIsRegisterPlusOffset( 938344779Sdim m_lldb_sp_regnum, current_sp_bytes_offset_from_fa); 939344779Sdim row_updated = true; 940344779Sdim } 941344779Sdim 942311128Sdim in_epilogue = true; 943311128Sdim } 944311128Sdim 945311128Sdim else if (mov_reg_to_local_stack_frame_p(machine_regno, stack_offset) && 946311128Sdim nonvolatile_reg_p(machine_regno) && 947311128Sdim machine_regno_to_lldb_regno(machine_regno, lldb_regno) && 948344779Sdim !saved_registers[machine_regno]) { 949311128Sdim saved_registers[machine_regno] = true; 950311128Sdim 951311128Sdim UnwindPlan::Row::RegisterLocation regloc; 952311128Sdim 953341825Sdim // stack_offset for 'movq %r15, -80(%rbp)' will be 80. In the Row, we 954344779Sdim // want to express this as the offset from the FA. If the frame base is 955344779Sdim // rbp (like the above instruction), the FA offset for rbp is probably 956344779Sdim // 16. So we want to say that the value is stored at the FA address - 957341825Sdim // 96. 958344779Sdim if (is_aligned) 959344779Sdim regloc.SetAtAFAPlusOffset(-(stack_offset + fa_value_ptr->GetOffset())); 960344779Sdim else 961344779Sdim regloc.SetAtCFAPlusOffset(-(stack_offset + fa_value_ptr->GetOffset())); 962311128Sdim 963311128Sdim row->SetRegisterInfo(lldb_regno, regloc); 964311128Sdim 965311128Sdim row_updated = true; 966311128Sdim } 967311128Sdim 968311128Sdim else if (sub_rsp_pattern_p(stack_offset)) { 969344779Sdim current_sp_bytes_offset_from_fa += stack_offset; 970344779Sdim if (fa_value_ptr->GetRegisterNumber() == m_lldb_sp_regnum) { 971344779Sdim fa_value_ptr->SetOffset(current_sp_bytes_offset_from_fa); 972311128Sdim row_updated = true; 973311128Sdim } 974311128Sdim } 975311128Sdim 976311128Sdim else if (add_rsp_pattern_p(stack_offset)) { 977344779Sdim current_sp_bytes_offset_from_fa -= stack_offset; 978344779Sdim if (fa_value_ptr->GetRegisterNumber() == m_lldb_sp_regnum) { 979344779Sdim fa_value_ptr->SetOffset(current_sp_bytes_offset_from_fa); 980311128Sdim row_updated = true; 981311128Sdim } 982311128Sdim in_epilogue = true; 983311128Sdim } 984311128Sdim 985311128Sdim else if (push_extended_pattern_p() || push_imm_pattern_p() || 986311128Sdim push_misc_reg_p()) { 987344779Sdim current_sp_bytes_offset_from_fa += m_wordsize; 988344779Sdim if (fa_value_ptr->GetRegisterNumber() == m_lldb_sp_regnum) { 989344779Sdim fa_value_ptr->SetOffset(current_sp_bytes_offset_from_fa); 990311128Sdim row_updated = true; 991311128Sdim } 992311128Sdim } 993311128Sdim 994311128Sdim else if (lea_rsp_pattern_p(stack_offset)) { 995344779Sdim current_sp_bytes_offset_from_fa -= stack_offset; 996344779Sdim if (fa_value_ptr->GetRegisterNumber() == m_lldb_sp_regnum) { 997344779Sdim fa_value_ptr->SetOffset(current_sp_bytes_offset_from_fa); 998311128Sdim row_updated = true; 999311128Sdim } 1000311128Sdim if (stack_offset > 0) 1001311128Sdim in_epilogue = true; 1002311128Sdim } 1003311128Sdim 1004344779Sdim else if (lea_rbp_rsp_pattern_p(stack_offset)) { 1005344779Sdim if (is_aligned && 1006344779Sdim cfa_value.GetRegisterNumber() == m_lldb_fp_regnum) { 1007344779Sdim is_aligned = false; 1008344779Sdim fa_value_ptr = &cfa_value; 1009344779Sdim afa_value.SetUnspecified(); 1010344779Sdim row_updated = true; 1011344779Sdim } 1012344779Sdim if (fa_value_ptr->GetRegisterNumber() == m_lldb_fp_regnum) { 1013344779Sdim current_sp_bytes_offset_from_fa = 1014344779Sdim fa_value_ptr->GetOffset() - stack_offset; 1015344779Sdim } 1016321369Sdim } 1017321369Sdim 1018344779Sdim else if (lea_rbx_rsp_pattern_p(stack_offset)) { 1019344779Sdim if (is_aligned && 1020344779Sdim cfa_value.GetRegisterNumber() == m_lldb_alt_fp_regnum) { 1021344779Sdim is_aligned = false; 1022344779Sdim fa_value_ptr = &cfa_value; 1023344779Sdim afa_value.SetUnspecified(); 1024344779Sdim row_updated = true; 1025344779Sdim } 1026344779Sdim if (fa_value_ptr->GetRegisterNumber() == m_lldb_alt_fp_regnum) { 1027344779Sdim current_sp_bytes_offset_from_fa = fa_value_ptr->GetOffset() - stack_offset; 1028344779Sdim } 1029344779Sdim } 1030344779Sdim 1031311128Sdim else if (ret_pattern_p() && prologue_completed_row.get()) { 1032341825Sdim // Reinstate the saved prologue setup for any instructions that come 1033341825Sdim // after the ret instruction 1034311128Sdim 1035311128Sdim UnwindPlan::Row *newrow = new UnwindPlan::Row; 1036311128Sdim *newrow = *prologue_completed_row.get(); 1037311128Sdim row.reset(newrow); 1038344779Sdim current_sp_bytes_offset_from_fa = 1039311128Sdim prologue_completed_sp_bytes_offset_from_cfa; 1040344779Sdim is_aligned = prologue_completed_is_aligned; 1041311128Sdim 1042311128Sdim saved_registers.clear(); 1043311128Sdim saved_registers.resize(prologue_completed_saved_registers.size(), false); 1044311128Sdim for (size_t i = 0; i < prologue_completed_saved_registers.size(); ++i) { 1045311128Sdim saved_registers[i] = prologue_completed_saved_registers[i]; 1046311128Sdim } 1047311128Sdim 1048311128Sdim in_epilogue = true; 1049311128Sdim row_updated = true; 1050311128Sdim } 1051311128Sdim 1052311128Sdim // call next instruction 1053311128Sdim // call 0 1054311128Sdim // => pop %ebx 1055311128Sdim // This is used in i386 programs to get the PIC base address for finding 1056311128Sdim // global data 1057311128Sdim else if (call_next_insn_pattern_p()) { 1058344779Sdim current_sp_bytes_offset_from_fa += m_wordsize; 1059344779Sdim if (fa_value_ptr->GetRegisterNumber() == m_lldb_sp_regnum) { 1060344779Sdim fa_value_ptr->SetOffset(current_sp_bytes_offset_from_fa); 1061311128Sdim row_updated = true; 1062311128Sdim } 1063311128Sdim } 1064311128Sdim 1065311128Sdim if (row_updated) { 1066311128Sdim if (current_func_text_offset + insn_len < size) { 1067311128Sdim row->SetOffset(current_func_text_offset + insn_len); 1068311128Sdim unwind_plan.AppendRow(row); 1069311128Sdim // Allocate a new Row, populate it with the existing Row contents. 1070311128Sdim newrow = new UnwindPlan::Row; 1071311128Sdim *newrow = *row.get(); 1072311128Sdim row.reset(newrow); 1073311128Sdim } 1074311128Sdim } 1075311128Sdim 1076344779Sdim if (!in_epilogue && row_updated) { 1077311128Sdim // If we're not in an epilogue sequence, save the updated Row 1078311128Sdim UnwindPlan::Row *newrow = new UnwindPlan::Row; 1079311128Sdim *newrow = *row.get(); 1080311128Sdim prologue_completed_row.reset(newrow); 1081311128Sdim 1082311128Sdim prologue_completed_saved_registers.clear(); 1083311128Sdim prologue_completed_saved_registers.resize(saved_registers.size(), false); 1084311128Sdim for (size_t i = 0; i < saved_registers.size(); ++i) { 1085311128Sdim prologue_completed_saved_registers[i] = saved_registers[i]; 1086311128Sdim } 1087311128Sdim } 1088311128Sdim 1089311128Sdim // We may change the sp value without adding a new Row necessarily -- keep 1090311128Sdim // track of it either way. 1091344779Sdim if (!in_epilogue) { 1092311128Sdim prologue_completed_sp_bytes_offset_from_cfa = 1093344779Sdim current_sp_bytes_offset_from_fa; 1094344779Sdim prologue_completed_is_aligned = is_aligned; 1095311128Sdim } 1096311128Sdim 1097311128Sdim m_cur_insn = m_cur_insn + insn_len; 1098311128Sdim current_func_text_offset += insn_len; 1099311128Sdim } 1100311128Sdim 1101311128Sdim unwind_plan.SetSourceName("assembly insn profiling"); 1102311128Sdim unwind_plan.SetSourcedFromCompiler(eLazyBoolNo); 1103311128Sdim unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolYes); 1104311128Sdim 1105311128Sdim return true; 1106311128Sdim} 1107311128Sdim 1108311128Sdimbool x86AssemblyInspectionEngine::AugmentUnwindPlanFromCallSite( 1109311128Sdim uint8_t *data, size_t size, AddressRange &func_range, 1110311128Sdim UnwindPlan &unwind_plan, RegisterContextSP ®_ctx) { 1111311128Sdim Address addr_start = func_range.GetBaseAddress(); 1112311128Sdim if (!addr_start.IsValid()) 1113311128Sdim return false; 1114311128Sdim 1115341825Sdim // We either need a live RegisterContext, or we need the UnwindPlan to 1116341825Sdim // already be in the lldb register numbering scheme. 1117311128Sdim if (reg_ctx.get() == nullptr && 1118311128Sdim unwind_plan.GetRegisterKind() != eRegisterKindLLDB) 1119311128Sdim return false; 1120311128Sdim 1121311128Sdim // Is original unwind_plan valid? 1122341825Sdim // unwind_plan should have at least one row which is ABI-default (CFA 1123341825Sdim // register is sp), and another row in mid-function. 1124311128Sdim if (unwind_plan.GetRowCount() < 2) 1125311128Sdim return false; 1126311128Sdim 1127311128Sdim UnwindPlan::RowSP first_row = unwind_plan.GetRowAtIndex(0); 1128311128Sdim if (first_row->GetOffset() != 0) 1129311128Sdim return false; 1130311128Sdim uint32_t cfa_reg = first_row->GetCFAValue().GetRegisterNumber(); 1131311128Sdim if (unwind_plan.GetRegisterKind() != eRegisterKindLLDB) { 1132311128Sdim cfa_reg = reg_ctx->ConvertRegisterKindToRegisterNumber( 1133311128Sdim unwind_plan.GetRegisterKind(), 1134311128Sdim first_row->GetCFAValue().GetRegisterNumber()); 1135311128Sdim } 1136311128Sdim if (cfa_reg != m_lldb_sp_regnum || 1137311128Sdim first_row->GetCFAValue().GetOffset() != m_wordsize) 1138311128Sdim return false; 1139311128Sdim 1140311128Sdim UnwindPlan::RowSP original_last_row = unwind_plan.GetRowForFunctionOffset(-1); 1141311128Sdim 1142311128Sdim size_t offset = 0; 1143311128Sdim int row_id = 1; 1144311128Sdim bool unwind_plan_updated = false; 1145311128Sdim UnwindPlan::RowSP row(new UnwindPlan::Row(*first_row)); 1146311128Sdim m_cur_insn = data + offset; 1147311128Sdim 1148341825Sdim // After a mid-function epilogue we will need to re-insert the original 1149341825Sdim // unwind rules so unwinds work for the remainder of the function. These 1150341825Sdim // aren't common with clang/gcc on x86 but it is possible. 1151311128Sdim bool reinstate_unwind_state = false; 1152311128Sdim 1153311128Sdim while (offset < size) { 1154311128Sdim m_cur_insn = data + offset; 1155311128Sdim int insn_len; 1156321369Sdim if (!instruction_length(m_cur_insn, insn_len, size - offset) 1157321369Sdim || insn_len == 0 1158321369Sdim || insn_len > kMaxInstructionByteSize) { 1159311128Sdim // An unrecognized/junk instruction. 1160311128Sdim break; 1161311128Sdim } 1162311128Sdim 1163311128Sdim // Advance offsets. 1164311128Sdim offset += insn_len; 1165311128Sdim m_cur_insn = data + offset; 1166311128Sdim 1167341825Sdim // offset is pointing beyond the bounds of the function; stop looping. 1168321369Sdim if (offset >= size) 1169321369Sdim continue; 1170321369Sdim 1171311128Sdim if (reinstate_unwind_state) { 1172311128Sdim UnwindPlan::RowSP new_row(new UnwindPlan::Row()); 1173311128Sdim *new_row = *original_last_row; 1174311128Sdim new_row->SetOffset(offset); 1175311128Sdim unwind_plan.AppendRow(new_row); 1176311128Sdim row.reset(new UnwindPlan::Row()); 1177311128Sdim *row = *new_row; 1178311128Sdim reinstate_unwind_state = false; 1179311128Sdim unwind_plan_updated = true; 1180311128Sdim continue; 1181311128Sdim } 1182311128Sdim 1183311128Sdim // If we already have one row for this instruction, we can continue. 1184311128Sdim while (row_id < unwind_plan.GetRowCount() && 1185311128Sdim unwind_plan.GetRowAtIndex(row_id)->GetOffset() <= offset) { 1186311128Sdim row_id++; 1187311128Sdim } 1188311128Sdim UnwindPlan::RowSP original_row = unwind_plan.GetRowAtIndex(row_id - 1); 1189311128Sdim if (original_row->GetOffset() == offset) { 1190311128Sdim *row = *original_row; 1191311128Sdim continue; 1192311128Sdim } 1193311128Sdim 1194311128Sdim if (row_id == 0) { 1195341825Sdim // If we are here, compiler didn't generate CFI for prologue. This won't 1196341825Sdim // happen to GCC or clang. In this case, bail out directly. 1197311128Sdim return false; 1198311128Sdim } 1199311128Sdim 1200311128Sdim // Inspect the instruction to check if we need a new row for it. 1201311128Sdim cfa_reg = row->GetCFAValue().GetRegisterNumber(); 1202311128Sdim if (unwind_plan.GetRegisterKind() != eRegisterKindLLDB) { 1203311128Sdim cfa_reg = reg_ctx->ConvertRegisterKindToRegisterNumber( 1204311128Sdim unwind_plan.GetRegisterKind(), 1205311128Sdim row->GetCFAValue().GetRegisterNumber()); 1206311128Sdim } 1207311128Sdim if (cfa_reg == m_lldb_sp_regnum) { 1208311128Sdim // CFA register is sp. 1209311128Sdim 1210311128Sdim // call next instruction 1211311128Sdim // call 0 1212311128Sdim // => pop %ebx 1213311128Sdim if (call_next_insn_pattern_p()) { 1214311128Sdim row->SetOffset(offset); 1215311128Sdim row->GetCFAValue().IncOffset(m_wordsize); 1216311128Sdim 1217311128Sdim UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row)); 1218311128Sdim unwind_plan.InsertRow(new_row); 1219311128Sdim unwind_plan_updated = true; 1220311128Sdim continue; 1221311128Sdim } 1222311128Sdim 1223311128Sdim // push/pop register 1224311128Sdim int regno; 1225311128Sdim if (push_reg_p(regno)) { 1226311128Sdim row->SetOffset(offset); 1227311128Sdim row->GetCFAValue().IncOffset(m_wordsize); 1228311128Sdim 1229311128Sdim UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row)); 1230311128Sdim unwind_plan.InsertRow(new_row); 1231311128Sdim unwind_plan_updated = true; 1232311128Sdim continue; 1233311128Sdim } 1234311128Sdim if (pop_reg_p(regno)) { 1235311128Sdim // Technically, this might be a nonvolatile register recover in 1236341825Sdim // epilogue. We should reset RegisterInfo for the register. But in 1237341825Sdim // practice, previous rule for the register is still valid... So we 1238341825Sdim // ignore this case. 1239311128Sdim 1240311128Sdim row->SetOffset(offset); 1241311128Sdim row->GetCFAValue().IncOffset(-m_wordsize); 1242311128Sdim 1243311128Sdim UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row)); 1244311128Sdim unwind_plan.InsertRow(new_row); 1245311128Sdim unwind_plan_updated = true; 1246311128Sdim continue; 1247311128Sdim } 1248311128Sdim 1249311128Sdim if (pop_misc_reg_p()) { 1250311128Sdim row->SetOffset(offset); 1251311128Sdim row->GetCFAValue().IncOffset(-m_wordsize); 1252311128Sdim 1253311128Sdim UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row)); 1254311128Sdim unwind_plan.InsertRow(new_row); 1255311128Sdim unwind_plan_updated = true; 1256311128Sdim continue; 1257311128Sdim } 1258311128Sdim 1259311128Sdim // push imm 1260311128Sdim if (push_imm_pattern_p()) { 1261311128Sdim row->SetOffset(offset); 1262311128Sdim row->GetCFAValue().IncOffset(m_wordsize); 1263311128Sdim UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row)); 1264311128Sdim unwind_plan.InsertRow(new_row); 1265311128Sdim unwind_plan_updated = true; 1266311128Sdim continue; 1267311128Sdim } 1268311128Sdim 1269311128Sdim // push extended 1270311128Sdim if (push_extended_pattern_p() || push_misc_reg_p()) { 1271311128Sdim row->SetOffset(offset); 1272311128Sdim row->GetCFAValue().IncOffset(m_wordsize); 1273311128Sdim UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row)); 1274311128Sdim unwind_plan.InsertRow(new_row); 1275311128Sdim unwind_plan_updated = true; 1276311128Sdim continue; 1277311128Sdim } 1278311128Sdim 1279311128Sdim // add/sub %rsp/%esp 1280311128Sdim int amount; 1281311128Sdim if (add_rsp_pattern_p(amount)) { 1282311128Sdim row->SetOffset(offset); 1283311128Sdim row->GetCFAValue().IncOffset(-amount); 1284311128Sdim 1285311128Sdim UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row)); 1286311128Sdim unwind_plan.InsertRow(new_row); 1287311128Sdim unwind_plan_updated = true; 1288311128Sdim continue; 1289311128Sdim } 1290311128Sdim if (sub_rsp_pattern_p(amount)) { 1291311128Sdim row->SetOffset(offset); 1292311128Sdim row->GetCFAValue().IncOffset(amount); 1293311128Sdim 1294311128Sdim UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row)); 1295311128Sdim unwind_plan.InsertRow(new_row); 1296311128Sdim unwind_plan_updated = true; 1297311128Sdim continue; 1298311128Sdim } 1299311128Sdim 1300311128Sdim // lea %rsp, [%rsp + $offset] 1301311128Sdim if (lea_rsp_pattern_p(amount)) { 1302311128Sdim row->SetOffset(offset); 1303311128Sdim row->GetCFAValue().IncOffset(-amount); 1304311128Sdim 1305311128Sdim UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row)); 1306311128Sdim unwind_plan.InsertRow(new_row); 1307311128Sdim unwind_plan_updated = true; 1308311128Sdim continue; 1309311128Sdim } 1310311128Sdim 1311311128Sdim if (ret_pattern_p()) { 1312311128Sdim reinstate_unwind_state = true; 1313311128Sdim continue; 1314311128Sdim } 1315311128Sdim } else if (cfa_reg == m_lldb_fp_regnum) { 1316311128Sdim // CFA register is fp. 1317311128Sdim 1318311128Sdim // The only case we care about is epilogue: 1319311128Sdim // [0x5d] pop %rbp/%ebp 1320311128Sdim // => [0xc3] ret 1321311128Sdim if (pop_rbp_pattern_p() || leave_pattern_p()) { 1322311128Sdim offset += 1; 1323311128Sdim row->SetOffset(offset); 1324311128Sdim row->GetCFAValue().SetIsRegisterPlusOffset( 1325311128Sdim first_row->GetCFAValue().GetRegisterNumber(), m_wordsize); 1326311128Sdim 1327311128Sdim UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row)); 1328311128Sdim unwind_plan.InsertRow(new_row); 1329311128Sdim unwind_plan_updated = true; 1330311128Sdim reinstate_unwind_state = true; 1331311128Sdim continue; 1332311128Sdim } 1333311128Sdim } else { 1334311128Sdim // CFA register is not sp or fp. 1335311128Sdim 1336311128Sdim // This must be hand-written assembly. 1337311128Sdim // Just trust eh_frame and assume we have finished. 1338311128Sdim break; 1339311128Sdim } 1340311128Sdim } 1341311128Sdim 1342311128Sdim unwind_plan.SetPlanValidAddressRange(func_range); 1343311128Sdim if (unwind_plan_updated) { 1344311128Sdim std::string unwind_plan_source(unwind_plan.GetSourceName().AsCString()); 1345311128Sdim unwind_plan_source += " plus augmentation from assembly parsing"; 1346311128Sdim unwind_plan.SetSourceName(unwind_plan_source.c_str()); 1347311128Sdim unwind_plan.SetSourcedFromCompiler(eLazyBoolNo); 1348311128Sdim unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolYes); 1349311128Sdim } 1350311128Sdim return true; 1351311128Sdim} 1352311128Sdim 1353311128Sdimbool x86AssemblyInspectionEngine::FindFirstNonPrologueInstruction( 1354311128Sdim uint8_t *data, size_t size, size_t &offset) { 1355311128Sdim offset = 0; 1356311128Sdim 1357344779Sdim if (!m_register_map_initialized) 1358311128Sdim return false; 1359311128Sdim 1360311128Sdim while (offset < size) { 1361311128Sdim int regno; 1362311128Sdim int insn_len; 1363311128Sdim int scratch; 1364311128Sdim 1365311128Sdim m_cur_insn = data + offset; 1366321369Sdim if (!instruction_length(m_cur_insn, insn_len, size - offset) 1367321369Sdim || insn_len > kMaxInstructionByteSize 1368321369Sdim || insn_len == 0) { 1369311128Sdim // An error parsing the instruction, i.e. probably data/garbage - stop 1370311128Sdim // scanning 1371311128Sdim break; 1372311128Sdim } 1373311128Sdim 1374311128Sdim if (push_rbp_pattern_p() || mov_rsp_rbp_pattern_p() || 1375311128Sdim sub_rsp_pattern_p(scratch) || push_reg_p(regno) || 1376311128Sdim mov_reg_to_local_stack_frame_p(regno, scratch) || 1377311128Sdim (lea_rsp_pattern_p(scratch) && offset == 0)) { 1378311128Sdim offset += insn_len; 1379311128Sdim continue; 1380311128Sdim } 1381311128Sdim // 1382311128Sdim // Unknown non-prologue instruction - stop scanning 1383311128Sdim break; 1384311128Sdim } 1385311128Sdim 1386311128Sdim return true; 1387311128Sdim} 1388