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