xref: /openbsd-src/gnu/llvm/lldb/source/Plugins/UnwindAssembly/x86/x86AssemblyInspectionEngine.cpp (revision 101d251d5caf88a9341f3045ab62e122abae1b90)
1dda28197Spatrick //===-- x86AssemblyInspectionEngine.cpp -----------------------------------===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick 
9061da546Spatrick #include "x86AssemblyInspectionEngine.h"
10061da546Spatrick 
11061da546Spatrick #include <memory>
12061da546Spatrick 
13061da546Spatrick #include "llvm-c/Disassembler.h"
14061da546Spatrick 
15061da546Spatrick #include "lldb/Core/Address.h"
16061da546Spatrick #include "lldb/Symbol/UnwindPlan.h"
17061da546Spatrick #include "lldb/Target/RegisterContext.h"
18061da546Spatrick #include "lldb/Target/UnwindAssembly.h"
19061da546Spatrick 
20061da546Spatrick using namespace lldb_private;
21061da546Spatrick using namespace lldb;
22061da546Spatrick 
x86AssemblyInspectionEngine(const ArchSpec & arch)23061da546Spatrick x86AssemblyInspectionEngine::x86AssemblyInspectionEngine(const ArchSpec &arch)
24061da546Spatrick     : m_cur_insn(nullptr), m_machine_ip_regnum(LLDB_INVALID_REGNUM),
25061da546Spatrick       m_machine_sp_regnum(LLDB_INVALID_REGNUM),
26061da546Spatrick       m_machine_fp_regnum(LLDB_INVALID_REGNUM),
27*101d251dSrobert       m_machine_alt_fp_regnum(LLDB_INVALID_REGNUM),
28061da546Spatrick       m_lldb_ip_regnum(LLDB_INVALID_REGNUM),
29061da546Spatrick       m_lldb_sp_regnum(LLDB_INVALID_REGNUM),
30061da546Spatrick       m_lldb_fp_regnum(LLDB_INVALID_REGNUM),
31*101d251dSrobert       m_lldb_alt_fp_regnum(LLDB_INVALID_REGNUM), m_reg_map(), m_arch(arch),
32*101d251dSrobert       m_cpu(k_cpu_unspecified), m_wordsize(-1),
33061da546Spatrick       m_register_map_initialized(false), m_disasm_context() {
34061da546Spatrick   m_disasm_context =
35061da546Spatrick       ::LLVMCreateDisasm(arch.GetTriple().getTriple().c_str(), nullptr,
36061da546Spatrick                          /*TagType=*/1, nullptr, nullptr);
37061da546Spatrick }
38061da546Spatrick 
~x86AssemblyInspectionEngine()39061da546Spatrick x86AssemblyInspectionEngine::~x86AssemblyInspectionEngine() {
40061da546Spatrick   ::LLVMDisasmDispose(m_disasm_context);
41061da546Spatrick }
42061da546Spatrick 
Initialize(RegisterContextSP & reg_ctx)43061da546Spatrick void x86AssemblyInspectionEngine::Initialize(RegisterContextSP &reg_ctx) {
44061da546Spatrick   m_cpu = k_cpu_unspecified;
45061da546Spatrick   m_wordsize = -1;
46061da546Spatrick   m_register_map_initialized = false;
47061da546Spatrick 
48061da546Spatrick   const llvm::Triple::ArchType cpu = m_arch.GetMachine();
49061da546Spatrick   if (cpu == llvm::Triple::x86)
50061da546Spatrick     m_cpu = k_i386;
51061da546Spatrick   else if (cpu == llvm::Triple::x86_64)
52061da546Spatrick     m_cpu = k_x86_64;
53061da546Spatrick 
54061da546Spatrick   if (m_cpu == k_cpu_unspecified)
55061da546Spatrick     return;
56061da546Spatrick 
57061da546Spatrick   if (reg_ctx.get() == nullptr)
58061da546Spatrick     return;
59061da546Spatrick 
60061da546Spatrick   if (m_cpu == k_i386) {
61061da546Spatrick     m_machine_ip_regnum = k_machine_eip;
62061da546Spatrick     m_machine_sp_regnum = k_machine_esp;
63061da546Spatrick     m_machine_fp_regnum = k_machine_ebp;
64061da546Spatrick     m_machine_alt_fp_regnum = k_machine_ebx;
65061da546Spatrick     m_wordsize = 4;
66061da546Spatrick 
67061da546Spatrick     struct lldb_reg_info reginfo;
68061da546Spatrick     reginfo.name = "eax";
69061da546Spatrick     m_reg_map[k_machine_eax] = reginfo;
70061da546Spatrick     reginfo.name = "edx";
71061da546Spatrick     m_reg_map[k_machine_edx] = reginfo;
72061da546Spatrick     reginfo.name = "esp";
73061da546Spatrick     m_reg_map[k_machine_esp] = reginfo;
74061da546Spatrick     reginfo.name = "esi";
75061da546Spatrick     m_reg_map[k_machine_esi] = reginfo;
76061da546Spatrick     reginfo.name = "eip";
77061da546Spatrick     m_reg_map[k_machine_eip] = reginfo;
78061da546Spatrick     reginfo.name = "ecx";
79061da546Spatrick     m_reg_map[k_machine_ecx] = reginfo;
80061da546Spatrick     reginfo.name = "ebx";
81061da546Spatrick     m_reg_map[k_machine_ebx] = reginfo;
82061da546Spatrick     reginfo.name = "ebp";
83061da546Spatrick     m_reg_map[k_machine_ebp] = reginfo;
84061da546Spatrick     reginfo.name = "edi";
85061da546Spatrick     m_reg_map[k_machine_edi] = reginfo;
86061da546Spatrick   } else {
87061da546Spatrick     m_machine_ip_regnum = k_machine_rip;
88061da546Spatrick     m_machine_sp_regnum = k_machine_rsp;
89061da546Spatrick     m_machine_fp_regnum = k_machine_rbp;
90061da546Spatrick     m_machine_alt_fp_regnum = k_machine_rbx;
91061da546Spatrick     m_wordsize = 8;
92061da546Spatrick 
93061da546Spatrick     struct lldb_reg_info reginfo;
94061da546Spatrick     reginfo.name = "rax";
95061da546Spatrick     m_reg_map[k_machine_rax] = reginfo;
96061da546Spatrick     reginfo.name = "rdx";
97061da546Spatrick     m_reg_map[k_machine_rdx] = reginfo;
98061da546Spatrick     reginfo.name = "rsp";
99061da546Spatrick     m_reg_map[k_machine_rsp] = reginfo;
100061da546Spatrick     reginfo.name = "rsi";
101061da546Spatrick     m_reg_map[k_machine_rsi] = reginfo;
102061da546Spatrick     reginfo.name = "r8";
103061da546Spatrick     m_reg_map[k_machine_r8] = reginfo;
104061da546Spatrick     reginfo.name = "r10";
105061da546Spatrick     m_reg_map[k_machine_r10] = reginfo;
106061da546Spatrick     reginfo.name = "r12";
107061da546Spatrick     m_reg_map[k_machine_r12] = reginfo;
108061da546Spatrick     reginfo.name = "r14";
109061da546Spatrick     m_reg_map[k_machine_r14] = reginfo;
110061da546Spatrick     reginfo.name = "rip";
111061da546Spatrick     m_reg_map[k_machine_rip] = reginfo;
112061da546Spatrick     reginfo.name = "rcx";
113061da546Spatrick     m_reg_map[k_machine_rcx] = reginfo;
114061da546Spatrick     reginfo.name = "rbx";
115061da546Spatrick     m_reg_map[k_machine_rbx] = reginfo;
116061da546Spatrick     reginfo.name = "rbp";
117061da546Spatrick     m_reg_map[k_machine_rbp] = reginfo;
118061da546Spatrick     reginfo.name = "rdi";
119061da546Spatrick     m_reg_map[k_machine_rdi] = reginfo;
120061da546Spatrick     reginfo.name = "r9";
121061da546Spatrick     m_reg_map[k_machine_r9] = reginfo;
122061da546Spatrick     reginfo.name = "r11";
123061da546Spatrick     m_reg_map[k_machine_r11] = reginfo;
124061da546Spatrick     reginfo.name = "r13";
125061da546Spatrick     m_reg_map[k_machine_r13] = reginfo;
126061da546Spatrick     reginfo.name = "r15";
127061da546Spatrick     m_reg_map[k_machine_r15] = reginfo;
128061da546Spatrick   }
129061da546Spatrick 
130061da546Spatrick   for (MachineRegnumToNameAndLLDBRegnum::iterator it = m_reg_map.begin();
131061da546Spatrick        it != m_reg_map.end(); ++it) {
132061da546Spatrick     const RegisterInfo *ri = reg_ctx->GetRegisterInfoByName(it->second.name);
133061da546Spatrick     if (ri)
134061da546Spatrick       it->second.lldb_regnum = ri->kinds[eRegisterKindLLDB];
135061da546Spatrick   }
136061da546Spatrick 
137061da546Spatrick   uint32_t lldb_regno;
138061da546Spatrick   if (machine_regno_to_lldb_regno(m_machine_sp_regnum, lldb_regno))
139061da546Spatrick     m_lldb_sp_regnum = lldb_regno;
140061da546Spatrick   if (machine_regno_to_lldb_regno(m_machine_fp_regnum, lldb_regno))
141061da546Spatrick     m_lldb_fp_regnum = lldb_regno;
142061da546Spatrick   if (machine_regno_to_lldb_regno(m_machine_alt_fp_regnum, lldb_regno))
143061da546Spatrick     m_lldb_alt_fp_regnum = lldb_regno;
144061da546Spatrick   if (machine_regno_to_lldb_regno(m_machine_ip_regnum, lldb_regno))
145061da546Spatrick     m_lldb_ip_regnum = lldb_regno;
146061da546Spatrick 
147061da546Spatrick   m_register_map_initialized = true;
148061da546Spatrick }
149061da546Spatrick 
Initialize(std::vector<lldb_reg_info> & reg_info)150061da546Spatrick void x86AssemblyInspectionEngine::Initialize(
151061da546Spatrick     std::vector<lldb_reg_info> &reg_info) {
152061da546Spatrick   m_cpu = k_cpu_unspecified;
153061da546Spatrick   m_wordsize = -1;
154061da546Spatrick   m_register_map_initialized = false;
155061da546Spatrick 
156061da546Spatrick   const llvm::Triple::ArchType cpu = m_arch.GetMachine();
157061da546Spatrick   if (cpu == llvm::Triple::x86)
158061da546Spatrick     m_cpu = k_i386;
159061da546Spatrick   else if (cpu == llvm::Triple::x86_64)
160061da546Spatrick     m_cpu = k_x86_64;
161061da546Spatrick 
162061da546Spatrick   if (m_cpu == k_cpu_unspecified)
163061da546Spatrick     return;
164061da546Spatrick 
165061da546Spatrick   if (m_cpu == k_i386) {
166061da546Spatrick     m_machine_ip_regnum = k_machine_eip;
167061da546Spatrick     m_machine_sp_regnum = k_machine_esp;
168061da546Spatrick     m_machine_fp_regnum = k_machine_ebp;
169061da546Spatrick     m_machine_alt_fp_regnum = k_machine_ebx;
170061da546Spatrick     m_wordsize = 4;
171061da546Spatrick 
172061da546Spatrick     struct lldb_reg_info reginfo;
173061da546Spatrick     reginfo.name = "eax";
174061da546Spatrick     m_reg_map[k_machine_eax] = reginfo;
175061da546Spatrick     reginfo.name = "edx";
176061da546Spatrick     m_reg_map[k_machine_edx] = reginfo;
177061da546Spatrick     reginfo.name = "esp";
178061da546Spatrick     m_reg_map[k_machine_esp] = reginfo;
179061da546Spatrick     reginfo.name = "esi";
180061da546Spatrick     m_reg_map[k_machine_esi] = reginfo;
181061da546Spatrick     reginfo.name = "eip";
182061da546Spatrick     m_reg_map[k_machine_eip] = reginfo;
183061da546Spatrick     reginfo.name = "ecx";
184061da546Spatrick     m_reg_map[k_machine_ecx] = reginfo;
185061da546Spatrick     reginfo.name = "ebx";
186061da546Spatrick     m_reg_map[k_machine_ebx] = reginfo;
187061da546Spatrick     reginfo.name = "ebp";
188061da546Spatrick     m_reg_map[k_machine_ebp] = reginfo;
189061da546Spatrick     reginfo.name = "edi";
190061da546Spatrick     m_reg_map[k_machine_edi] = reginfo;
191061da546Spatrick   } else {
192061da546Spatrick     m_machine_ip_regnum = k_machine_rip;
193061da546Spatrick     m_machine_sp_regnum = k_machine_rsp;
194061da546Spatrick     m_machine_fp_regnum = k_machine_rbp;
195061da546Spatrick     m_machine_alt_fp_regnum = k_machine_rbx;
196061da546Spatrick     m_wordsize = 8;
197061da546Spatrick 
198061da546Spatrick     struct lldb_reg_info reginfo;
199061da546Spatrick     reginfo.name = "rax";
200061da546Spatrick     m_reg_map[k_machine_rax] = reginfo;
201061da546Spatrick     reginfo.name = "rdx";
202061da546Spatrick     m_reg_map[k_machine_rdx] = reginfo;
203061da546Spatrick     reginfo.name = "rsp";
204061da546Spatrick     m_reg_map[k_machine_rsp] = reginfo;
205061da546Spatrick     reginfo.name = "rsi";
206061da546Spatrick     m_reg_map[k_machine_rsi] = reginfo;
207061da546Spatrick     reginfo.name = "r8";
208061da546Spatrick     m_reg_map[k_machine_r8] = reginfo;
209061da546Spatrick     reginfo.name = "r10";
210061da546Spatrick     m_reg_map[k_machine_r10] = reginfo;
211061da546Spatrick     reginfo.name = "r12";
212061da546Spatrick     m_reg_map[k_machine_r12] = reginfo;
213061da546Spatrick     reginfo.name = "r14";
214061da546Spatrick     m_reg_map[k_machine_r14] = reginfo;
215061da546Spatrick     reginfo.name = "rip";
216061da546Spatrick     m_reg_map[k_machine_rip] = reginfo;
217061da546Spatrick     reginfo.name = "rcx";
218061da546Spatrick     m_reg_map[k_machine_rcx] = reginfo;
219061da546Spatrick     reginfo.name = "rbx";
220061da546Spatrick     m_reg_map[k_machine_rbx] = reginfo;
221061da546Spatrick     reginfo.name = "rbp";
222061da546Spatrick     m_reg_map[k_machine_rbp] = reginfo;
223061da546Spatrick     reginfo.name = "rdi";
224061da546Spatrick     m_reg_map[k_machine_rdi] = reginfo;
225061da546Spatrick     reginfo.name = "r9";
226061da546Spatrick     m_reg_map[k_machine_r9] = reginfo;
227061da546Spatrick     reginfo.name = "r11";
228061da546Spatrick     m_reg_map[k_machine_r11] = reginfo;
229061da546Spatrick     reginfo.name = "r13";
230061da546Spatrick     m_reg_map[k_machine_r13] = reginfo;
231061da546Spatrick     reginfo.name = "r15";
232061da546Spatrick     m_reg_map[k_machine_r15] = reginfo;
233061da546Spatrick   }
234061da546Spatrick 
235061da546Spatrick   for (MachineRegnumToNameAndLLDBRegnum::iterator it = m_reg_map.begin();
236061da546Spatrick        it != m_reg_map.end(); ++it) {
237061da546Spatrick     for (size_t i = 0; i < reg_info.size(); ++i) {
238061da546Spatrick       if (::strcmp(reg_info[i].name, it->second.name) == 0) {
239061da546Spatrick         it->second.lldb_regnum = reg_info[i].lldb_regnum;
240061da546Spatrick         break;
241061da546Spatrick       }
242061da546Spatrick     }
243061da546Spatrick   }
244061da546Spatrick 
245061da546Spatrick   uint32_t lldb_regno;
246061da546Spatrick   if (machine_regno_to_lldb_regno(m_machine_sp_regnum, lldb_regno))
247061da546Spatrick     m_lldb_sp_regnum = lldb_regno;
248061da546Spatrick   if (machine_regno_to_lldb_regno(m_machine_fp_regnum, lldb_regno))
249061da546Spatrick     m_lldb_fp_regnum = lldb_regno;
250061da546Spatrick   if (machine_regno_to_lldb_regno(m_machine_alt_fp_regnum, lldb_regno))
251061da546Spatrick     m_lldb_alt_fp_regnum = lldb_regno;
252061da546Spatrick   if (machine_regno_to_lldb_regno(m_machine_ip_regnum, lldb_regno))
253061da546Spatrick     m_lldb_ip_regnum = lldb_regno;
254061da546Spatrick 
255061da546Spatrick   m_register_map_initialized = true;
256061da546Spatrick }
257061da546Spatrick 
258061da546Spatrick // This function expects an x86 native register number (i.e. the bits stripped
259061da546Spatrick // out of the actual instruction), not an lldb register number.
260061da546Spatrick //
261061da546Spatrick // FIXME: This is ABI dependent, it shouldn't be hardcoded here.
262061da546Spatrick 
nonvolatile_reg_p(int machine_regno)263061da546Spatrick bool x86AssemblyInspectionEngine::nonvolatile_reg_p(int machine_regno) {
264061da546Spatrick   if (m_cpu == k_i386) {
265061da546Spatrick     switch (machine_regno) {
266061da546Spatrick     case k_machine_ebx:
267061da546Spatrick     case k_machine_ebp: // not actually a nonvolatile but often treated as such
268061da546Spatrick                         // by convention
269061da546Spatrick     case k_machine_esi:
270061da546Spatrick     case k_machine_edi:
271061da546Spatrick     case k_machine_esp:
272061da546Spatrick       return true;
273061da546Spatrick     default:
274061da546Spatrick       return false;
275061da546Spatrick     }
276061da546Spatrick   }
277061da546Spatrick   if (m_cpu == k_x86_64) {
278061da546Spatrick     switch (machine_regno) {
279061da546Spatrick     case k_machine_rbx:
280061da546Spatrick     case k_machine_rsp:
281061da546Spatrick     case k_machine_rbp: // not actually a nonvolatile but often treated as such
282061da546Spatrick                         // by convention
283061da546Spatrick     case k_machine_r12:
284061da546Spatrick     case k_machine_r13:
285061da546Spatrick     case k_machine_r14:
286061da546Spatrick     case k_machine_r15:
287061da546Spatrick       return true;
288061da546Spatrick     default:
289061da546Spatrick       return false;
290061da546Spatrick     }
291061da546Spatrick   }
292061da546Spatrick   return false;
293061da546Spatrick }
294061da546Spatrick 
295061da546Spatrick // Macro to detect if this is a REX mode prefix byte.
296061da546Spatrick #define REX_W_PREFIX_P(opcode) (((opcode) & (~0x5)) == 0x48)
297061da546Spatrick 
298061da546Spatrick // The high bit which should be added to the source register number (the "R"
299061da546Spatrick // bit)
300061da546Spatrick #define REX_W_SRCREG(opcode) (((opcode)&0x4) >> 2)
301061da546Spatrick 
302061da546Spatrick // The high bit which should be added to the destination register number (the
303061da546Spatrick // "B" bit)
304061da546Spatrick #define REX_W_DSTREG(opcode) ((opcode)&0x1)
305061da546Spatrick 
306061da546Spatrick // pushq %rbp [0x55]
push_rbp_pattern_p()307061da546Spatrick bool x86AssemblyInspectionEngine::push_rbp_pattern_p() {
308061da546Spatrick   uint8_t *p = m_cur_insn;
309061da546Spatrick   return *p == 0x55;
310061da546Spatrick }
311061da546Spatrick 
312061da546Spatrick // pushq $0 ; the first instruction in start() [0x6a 0x00]
push_0_pattern_p()313061da546Spatrick bool x86AssemblyInspectionEngine::push_0_pattern_p() {
314061da546Spatrick   uint8_t *p = m_cur_insn;
315061da546Spatrick   return *p == 0x6a && *(p + 1) == 0x0;
316061da546Spatrick }
317061da546Spatrick 
318061da546Spatrick // pushq $0
319061da546Spatrick // pushl $0
push_imm_pattern_p()320061da546Spatrick bool x86AssemblyInspectionEngine::push_imm_pattern_p() {
321061da546Spatrick   uint8_t *p = m_cur_insn;
322061da546Spatrick   return *p == 0x68 || *p == 0x6a;
323061da546Spatrick }
324061da546Spatrick 
325061da546Spatrick // pushl imm8(%esp)
326061da546Spatrick //
327061da546Spatrick // e.g. 0xff 0x74 0x24 0x20 - 'pushl 0x20(%esp)' (same byte pattern for 'pushq
328061da546Spatrick // 0x20(%rsp)' in an x86_64 program)
329061da546Spatrick //
330061da546Spatrick // 0xff (with opcode bits '6' in next byte, PUSH r/m32) 0x74 (ModR/M byte with
331061da546Spatrick // three bits used to specify the opcode)
332061da546Spatrick //      mod == b01, opcode == b110, R/M == b100
333061da546Spatrick //      "+disp8"
334061da546Spatrick // 0x24 (SIB byte - scaled index = 0, r32 == esp) 0x20 imm8 value
335061da546Spatrick 
push_extended_pattern_p()336061da546Spatrick bool x86AssemblyInspectionEngine::push_extended_pattern_p() {
337061da546Spatrick   if (*m_cur_insn == 0xff) {
338061da546Spatrick     // Get the 3 opcode bits from the ModR/M byte
339061da546Spatrick     uint8_t opcode = (*(m_cur_insn + 1) >> 3) & 7;
340061da546Spatrick     if (opcode == 6) {
341061da546Spatrick       // I'm only looking for 0xff /6 here - I
342061da546Spatrick       // don't really care what value is being pushed, just that we're pushing
343061da546Spatrick       // a 32/64 bit value on to the stack is enough.
344061da546Spatrick       return true;
345061da546Spatrick     }
346061da546Spatrick   }
347061da546Spatrick   return false;
348061da546Spatrick }
349061da546Spatrick 
350061da546Spatrick // instructions only valid in 32-bit mode:
351061da546Spatrick // 0x0e - push cs
352061da546Spatrick // 0x16 - push ss
353061da546Spatrick // 0x1e - push ds
354061da546Spatrick // 0x06 - push es
push_misc_reg_p()355061da546Spatrick bool x86AssemblyInspectionEngine::push_misc_reg_p() {
356061da546Spatrick   uint8_t p = *m_cur_insn;
357061da546Spatrick   if (m_wordsize == 4) {
358061da546Spatrick     if (p == 0x0e || p == 0x16 || p == 0x1e || p == 0x06)
359061da546Spatrick       return true;
360061da546Spatrick   }
361061da546Spatrick   return false;
362061da546Spatrick }
363061da546Spatrick 
364061da546Spatrick // pushq %rbx
365061da546Spatrick // pushl %ebx
push_reg_p(int & regno)366061da546Spatrick bool x86AssemblyInspectionEngine::push_reg_p(int &regno) {
367061da546Spatrick   uint8_t *p = m_cur_insn;
368061da546Spatrick   int regno_prefix_bit = 0;
369061da546Spatrick   // If we have a rex prefix byte, check to see if a B bit is set
370061da546Spatrick   if (m_wordsize == 8 && (*p & 0xfe) == 0x40) {
371061da546Spatrick     regno_prefix_bit = (*p & 1) << 3;
372061da546Spatrick     p++;
373061da546Spatrick   }
374061da546Spatrick   if (*p >= 0x50 && *p <= 0x57) {
375061da546Spatrick     regno = (*p - 0x50) | regno_prefix_bit;
376061da546Spatrick     return true;
377061da546Spatrick   }
378061da546Spatrick   return false;
379061da546Spatrick }
380061da546Spatrick 
381061da546Spatrick // movq %rsp, %rbp [0x48 0x8b 0xec] or [0x48 0x89 0xe5] movl %esp, %ebp [0x8b
382061da546Spatrick // 0xec] or [0x89 0xe5]
mov_rsp_rbp_pattern_p()383061da546Spatrick bool x86AssemblyInspectionEngine::mov_rsp_rbp_pattern_p() {
384061da546Spatrick   uint8_t *p = m_cur_insn;
385061da546Spatrick   if (m_wordsize == 8 && *p == 0x48)
386061da546Spatrick     p++;
387061da546Spatrick   if (*(p) == 0x8b && *(p + 1) == 0xec)
388061da546Spatrick     return true;
389061da546Spatrick   if (*(p) == 0x89 && *(p + 1) == 0xe5)
390061da546Spatrick     return true;
391061da546Spatrick   return false;
392061da546Spatrick }
393061da546Spatrick 
394061da546Spatrick // movq %rsp, %rbx [0x48 0x8b 0xdc] or [0x48 0x89 0xe3]
395061da546Spatrick // movl %esp, %ebx [0x8b 0xdc] or [0x89 0xe3]
mov_rsp_rbx_pattern_p()396061da546Spatrick bool x86AssemblyInspectionEngine::mov_rsp_rbx_pattern_p() {
397061da546Spatrick   uint8_t *p = m_cur_insn;
398061da546Spatrick   if (m_wordsize == 8 && *p == 0x48)
399061da546Spatrick     p++;
400061da546Spatrick   if (*(p) == 0x8b && *(p + 1) == 0xdc)
401061da546Spatrick     return true;
402061da546Spatrick   if (*(p) == 0x89 && *(p + 1) == 0xe3)
403061da546Spatrick     return true;
404061da546Spatrick   return false;
405061da546Spatrick }
406061da546Spatrick 
407061da546Spatrick // movq %rbp, %rsp [0x48 0x8b 0xe5] or [0x48 0x89 0xec]
408061da546Spatrick // movl %ebp, %esp [0x8b 0xe5] or [0x89 0xec]
mov_rbp_rsp_pattern_p()409061da546Spatrick bool x86AssemblyInspectionEngine::mov_rbp_rsp_pattern_p() {
410061da546Spatrick   uint8_t *p = m_cur_insn;
411061da546Spatrick   if (m_wordsize == 8 && *p == 0x48)
412061da546Spatrick     p++;
413061da546Spatrick   if (*(p) == 0x8b && *(p + 1) == 0xe5)
414061da546Spatrick     return true;
415061da546Spatrick   if (*(p) == 0x89 && *(p + 1) == 0xec)
416061da546Spatrick     return true;
417061da546Spatrick   return false;
418061da546Spatrick }
419061da546Spatrick 
420061da546Spatrick // movq %rbx, %rsp [0x48 0x8b 0xe3] or [0x48 0x89 0xdc]
421061da546Spatrick // movl %ebx, %esp [0x8b 0xe3] or [0x89 0xdc]
mov_rbx_rsp_pattern_p()422061da546Spatrick bool x86AssemblyInspectionEngine::mov_rbx_rsp_pattern_p() {
423061da546Spatrick   uint8_t *p = m_cur_insn;
424061da546Spatrick   if (m_wordsize == 8 && *p == 0x48)
425061da546Spatrick     p++;
426061da546Spatrick   if (*(p) == 0x8b && *(p + 1) == 0xe3)
427061da546Spatrick     return true;
428061da546Spatrick   if (*(p) == 0x89 && *(p + 1) == 0xdc)
429061da546Spatrick     return true;
430061da546Spatrick   return false;
431061da546Spatrick }
432061da546Spatrick 
433061da546Spatrick // subq $0x20, %rsp
sub_rsp_pattern_p(int & amount)434061da546Spatrick bool x86AssemblyInspectionEngine::sub_rsp_pattern_p(int &amount) {
435061da546Spatrick   uint8_t *p = m_cur_insn;
436061da546Spatrick   if (m_wordsize == 8 && *p == 0x48)
437061da546Spatrick     p++;
438061da546Spatrick   // 8-bit immediate operand
439061da546Spatrick   if (*p == 0x83 && *(p + 1) == 0xec) {
440061da546Spatrick     amount = (int8_t) * (p + 2);
441061da546Spatrick     return true;
442061da546Spatrick   }
443061da546Spatrick   // 32-bit immediate operand
444061da546Spatrick   if (*p == 0x81 && *(p + 1) == 0xec) {
445061da546Spatrick     amount = (int32_t)extract_4(p + 2);
446061da546Spatrick     return true;
447061da546Spatrick   }
448061da546Spatrick   return false;
449061da546Spatrick }
450061da546Spatrick 
451061da546Spatrick // addq $0x20, %rsp
add_rsp_pattern_p(int & amount)452061da546Spatrick bool x86AssemblyInspectionEngine::add_rsp_pattern_p(int &amount) {
453061da546Spatrick   uint8_t *p = m_cur_insn;
454061da546Spatrick   if (m_wordsize == 8 && *p == 0x48)
455061da546Spatrick     p++;
456061da546Spatrick   // 8-bit immediate operand
457061da546Spatrick   if (*p == 0x83 && *(p + 1) == 0xc4) {
458061da546Spatrick     amount = (int8_t) * (p + 2);
459061da546Spatrick     return true;
460061da546Spatrick   }
461061da546Spatrick   // 32-bit immediate operand
462061da546Spatrick   if (*p == 0x81 && *(p + 1) == 0xc4) {
463061da546Spatrick     amount = (int32_t)extract_4(p + 2);
464061da546Spatrick     return true;
465061da546Spatrick   }
466061da546Spatrick   return false;
467061da546Spatrick }
468061da546Spatrick 
469061da546Spatrick // lea esp, [esp - 0x28]
470061da546Spatrick // lea esp, [esp + 0x28]
lea_rsp_pattern_p(int & amount)471061da546Spatrick bool x86AssemblyInspectionEngine::lea_rsp_pattern_p(int &amount) {
472061da546Spatrick   uint8_t *p = m_cur_insn;
473061da546Spatrick   if (m_wordsize == 8 && *p == 0x48)
474061da546Spatrick     p++;
475061da546Spatrick 
476061da546Spatrick   // Check opcode
477061da546Spatrick   if (*p != 0x8d)
478061da546Spatrick     return false;
479061da546Spatrick 
480061da546Spatrick   // 8 bit displacement
481061da546Spatrick   if (*(p + 1) == 0x64 && (*(p + 2) & 0x3f) == 0x24) {
482061da546Spatrick     amount = (int8_t) * (p + 3);
483061da546Spatrick     return true;
484061da546Spatrick   }
485061da546Spatrick 
486061da546Spatrick   // 32 bit displacement
487061da546Spatrick   if (*(p + 1) == 0xa4 && (*(p + 2) & 0x3f) == 0x24) {
488061da546Spatrick     amount = (int32_t)extract_4(p + 3);
489061da546Spatrick     return true;
490061da546Spatrick   }
491061da546Spatrick 
492061da546Spatrick   return false;
493061da546Spatrick }
494061da546Spatrick 
495061da546Spatrick // lea -0x28(%ebp), %esp
496061da546Spatrick // (32-bit and 64-bit variants, 8-bit and 32-bit displacement)
lea_rbp_rsp_pattern_p(int & amount)497061da546Spatrick bool x86AssemblyInspectionEngine::lea_rbp_rsp_pattern_p(int &amount) {
498061da546Spatrick   uint8_t *p = m_cur_insn;
499061da546Spatrick   if (m_wordsize == 8 && *p == 0x48)
500061da546Spatrick     p++;
501061da546Spatrick 
502061da546Spatrick   // Check opcode
503061da546Spatrick   if (*p != 0x8d)
504061da546Spatrick     return false;
505061da546Spatrick   ++p;
506061da546Spatrick 
507061da546Spatrick   // 8 bit displacement
508061da546Spatrick   if (*p == 0x65) {
509061da546Spatrick     amount = (int8_t)p[1];
510061da546Spatrick     return true;
511061da546Spatrick   }
512061da546Spatrick 
513061da546Spatrick   // 32 bit displacement
514061da546Spatrick   if (*p == 0xa5) {
515061da546Spatrick     amount = (int32_t)extract_4(p + 1);
516061da546Spatrick     return true;
517061da546Spatrick   }
518061da546Spatrick 
519061da546Spatrick   return false;
520061da546Spatrick }
521061da546Spatrick 
522061da546Spatrick // lea -0x28(%ebx), %esp
523061da546Spatrick // (32-bit and 64-bit variants, 8-bit and 32-bit displacement)
lea_rbx_rsp_pattern_p(int & amount)524061da546Spatrick bool x86AssemblyInspectionEngine::lea_rbx_rsp_pattern_p(int &amount) {
525061da546Spatrick   uint8_t *p = m_cur_insn;
526061da546Spatrick   if (m_wordsize == 8 && *p == 0x48)
527061da546Spatrick     p++;
528061da546Spatrick 
529061da546Spatrick   // Check opcode
530061da546Spatrick   if (*p != 0x8d)
531061da546Spatrick     return false;
532061da546Spatrick   ++p;
533061da546Spatrick 
534061da546Spatrick   // 8 bit displacement
535061da546Spatrick   if (*p == 0x63) {
536061da546Spatrick     amount = (int8_t)p[1];
537061da546Spatrick     return true;
538061da546Spatrick   }
539061da546Spatrick 
540061da546Spatrick   // 32 bit displacement
541061da546Spatrick   if (*p == 0xa3) {
542061da546Spatrick     amount = (int32_t)extract_4(p + 1);
543061da546Spatrick     return true;
544061da546Spatrick   }
545061da546Spatrick 
546061da546Spatrick   return false;
547061da546Spatrick }
548061da546Spatrick 
549061da546Spatrick // and -0xfffffff0, %esp
550061da546Spatrick // (32-bit and 64-bit variants, 8-bit and 32-bit displacement)
and_rsp_pattern_p()551061da546Spatrick bool x86AssemblyInspectionEngine::and_rsp_pattern_p() {
552061da546Spatrick   uint8_t *p = m_cur_insn;
553061da546Spatrick   if (m_wordsize == 8 && *p == 0x48)
554061da546Spatrick     p++;
555061da546Spatrick 
556061da546Spatrick   if (*p != 0x81 && *p != 0x83)
557061da546Spatrick     return false;
558061da546Spatrick 
559061da546Spatrick   return *++p == 0xe4;
560061da546Spatrick }
561061da546Spatrick 
562061da546Spatrick // popq %rbx
563061da546Spatrick // popl %ebx
pop_reg_p(int & regno)564061da546Spatrick bool x86AssemblyInspectionEngine::pop_reg_p(int &regno) {
565061da546Spatrick   uint8_t *p = m_cur_insn;
566061da546Spatrick   int regno_prefix_bit = 0;
567061da546Spatrick   // If we have a rex prefix byte, check to see if a B bit is set
568061da546Spatrick   if (m_wordsize == 8 && (*p & 0xfe) == 0x40) {
569061da546Spatrick     regno_prefix_bit = (*p & 1) << 3;
570061da546Spatrick     p++;
571061da546Spatrick   }
572061da546Spatrick   if (*p >= 0x58 && *p <= 0x5f) {
573061da546Spatrick     regno = (*p - 0x58) | regno_prefix_bit;
574061da546Spatrick     return true;
575061da546Spatrick   }
576061da546Spatrick   return false;
577061da546Spatrick }
578061da546Spatrick 
579061da546Spatrick // popq %rbp [0x5d]
580061da546Spatrick // popl %ebp [0x5d]
pop_rbp_pattern_p()581061da546Spatrick bool x86AssemblyInspectionEngine::pop_rbp_pattern_p() {
582061da546Spatrick   uint8_t *p = m_cur_insn;
583061da546Spatrick   return (*p == 0x5d);
584061da546Spatrick }
585061da546Spatrick 
586061da546Spatrick // instructions valid only in 32-bit mode:
587061da546Spatrick // 0x1f - pop ds
588061da546Spatrick // 0x07 - pop es
589061da546Spatrick // 0x17 - pop ss
pop_misc_reg_p()590061da546Spatrick bool x86AssemblyInspectionEngine::pop_misc_reg_p() {
591061da546Spatrick   uint8_t p = *m_cur_insn;
592061da546Spatrick   if (m_wordsize == 4) {
593061da546Spatrick     if (p == 0x1f || p == 0x07 || p == 0x17)
594061da546Spatrick       return true;
595061da546Spatrick   }
596061da546Spatrick   return false;
597061da546Spatrick }
598061da546Spatrick 
599061da546Spatrick // leave [0xc9]
leave_pattern_p()600061da546Spatrick bool x86AssemblyInspectionEngine::leave_pattern_p() {
601061da546Spatrick   uint8_t *p = m_cur_insn;
602061da546Spatrick   return (*p == 0xc9);
603061da546Spatrick }
604061da546Spatrick 
605061da546Spatrick // call $0 [0xe8 0x0 0x0 0x0 0x0]
call_next_insn_pattern_p()606061da546Spatrick bool x86AssemblyInspectionEngine::call_next_insn_pattern_p() {
607061da546Spatrick   uint8_t *p = m_cur_insn;
608061da546Spatrick   return (*p == 0xe8) && (*(p + 1) == 0x0) && (*(p + 2) == 0x0) &&
609061da546Spatrick          (*(p + 3) == 0x0) && (*(p + 4) == 0x0);
610061da546Spatrick }
611061da546Spatrick 
612061da546Spatrick // Look for an instruction sequence storing a nonvolatile register on to the
613061da546Spatrick // stack frame.
614061da546Spatrick 
615061da546Spatrick //  movq %rax, -0x10(%rbp) [0x48 0x89 0x45 0xf0]
616061da546Spatrick //  movl %eax, -0xc(%ebp)  [0x89 0x45 0xf4]
617061da546Spatrick 
618061da546Spatrick // The offset value returned in rbp_offset will be positive -- but it must be
619061da546Spatrick // subtraced from the frame base register to get the actual location.  The
620061da546Spatrick // positive value returned for the offset is a convention used elsewhere for
621061da546Spatrick // CFA offsets et al.
622061da546Spatrick 
mov_reg_to_local_stack_frame_p(int & regno,int & rbp_offset)623061da546Spatrick bool x86AssemblyInspectionEngine::mov_reg_to_local_stack_frame_p(
624061da546Spatrick     int &regno, int &rbp_offset) {
625061da546Spatrick   uint8_t *p = m_cur_insn;
626061da546Spatrick   int src_reg_prefix_bit = 0;
627061da546Spatrick   int target_reg_prefix_bit = 0;
628061da546Spatrick 
629061da546Spatrick   if (m_wordsize == 8 && REX_W_PREFIX_P(*p)) {
630061da546Spatrick     src_reg_prefix_bit = REX_W_SRCREG(*p) << 3;
631061da546Spatrick     target_reg_prefix_bit = REX_W_DSTREG(*p) << 3;
632061da546Spatrick     if (target_reg_prefix_bit == 1) {
633061da546Spatrick       // rbp/ebp don't need a prefix bit - we know this isn't the reg we care
634061da546Spatrick       // about.
635061da546Spatrick       return false;
636061da546Spatrick     }
637061da546Spatrick     p++;
638061da546Spatrick   }
639061da546Spatrick 
640061da546Spatrick   if (*p == 0x89) {
641061da546Spatrick     /* Mask off the 3-5 bits which indicate the destination register
642061da546Spatrick        if this is a ModR/M byte.  */
643061da546Spatrick     int opcode_destreg_masked_out = *(p + 1) & (~0x38);
644061da546Spatrick 
645061da546Spatrick     /* Is this a ModR/M byte with Mod bits 01 and R/M bits 101
646061da546Spatrick        and three bits between them, e.g. 01nnn101
647061da546Spatrick        We're looking for a destination of ebp-disp8 or ebp-disp32.   */
648061da546Spatrick     int immsize;
649061da546Spatrick     if (opcode_destreg_masked_out == 0x45)
650061da546Spatrick       immsize = 2;
651061da546Spatrick     else if (opcode_destreg_masked_out == 0x85)
652061da546Spatrick       immsize = 4;
653061da546Spatrick     else
654061da546Spatrick       return false;
655061da546Spatrick 
656061da546Spatrick     int offset = 0;
657061da546Spatrick     if (immsize == 2)
658061da546Spatrick       offset = (int8_t) * (p + 2);
659061da546Spatrick     if (immsize == 4)
660061da546Spatrick       offset = (uint32_t)extract_4(p + 2);
661061da546Spatrick     if (offset > 0)
662061da546Spatrick       return false;
663061da546Spatrick 
664061da546Spatrick     regno = ((*(p + 1) >> 3) & 0x7) | src_reg_prefix_bit;
665061da546Spatrick     rbp_offset = offset > 0 ? offset : -offset;
666061da546Spatrick     return true;
667061da546Spatrick   }
668061da546Spatrick   return false;
669061da546Spatrick }
670061da546Spatrick 
671061da546Spatrick // Returns true if this is a jmp instruction where we can't
672061da546Spatrick // know the destination address statically.
673061da546Spatrick //
674061da546Spatrick // ff e0                                   jmpq   *%rax
675061da546Spatrick // ff e1                                   jmpq   *%rcx
676061da546Spatrick // ff 60 28                                jmpq   *0x28(%rax)
677061da546Spatrick // ff 60 60                                jmpq   *0x60(%rax)
jmp_to_reg_p()678061da546Spatrick bool x86AssemblyInspectionEngine::jmp_to_reg_p() {
679061da546Spatrick   if (*m_cur_insn != 0xff)
680061da546Spatrick     return false;
681061da546Spatrick 
682061da546Spatrick   // The second byte is a ModR/M /4 byte, strip off the registers
683061da546Spatrick   uint8_t second_byte_sans_reg = *(m_cur_insn + 1) & ~7;
684061da546Spatrick 
685061da546Spatrick   // [reg]
686061da546Spatrick   if (second_byte_sans_reg == 0x20)
687061da546Spatrick     return true;
688061da546Spatrick 
689061da546Spatrick   // [reg]+disp8
690061da546Spatrick   if (second_byte_sans_reg == 0x60)
691061da546Spatrick     return true;
692061da546Spatrick 
693061da546Spatrick   // [reg]+disp32
694061da546Spatrick   if (second_byte_sans_reg == 0xa0)
695061da546Spatrick     return true;
696061da546Spatrick 
697061da546Spatrick   // reg
698061da546Spatrick   if (second_byte_sans_reg == 0xe0)
699061da546Spatrick     return true;
700061da546Spatrick 
701061da546Spatrick   return false;
702061da546Spatrick }
703061da546Spatrick 
704061da546Spatrick // Detect branches to fixed pc-relative offsets.
705061da546Spatrick // Returns the offset from the address of the next instruction
706061da546Spatrick // that may be branch/jumped to.
707061da546Spatrick //
708061da546Spatrick // Cannot determine the offset of a JMP that jumps to the address in
709061da546Spatrick // a register ("jmpq *%rax") or offset from a register value
710061da546Spatrick // ("jmpq *0x28(%rax)"), this method will return false on those
711061da546Spatrick // instructions.
712061da546Spatrick //
713061da546Spatrick // These instructions all end in either a relative 8/16/32 bit value
714061da546Spatrick // depending on the instruction and the current execution mode of the
715061da546Spatrick // inferior process.  Once we know the size of the opcode instruction,
716061da546Spatrick // we can use the total instruction length to determine the size of
717061da546Spatrick // the relative offset without having to compute it correctly.
718061da546Spatrick 
pc_rel_branch_or_jump_p(const int instruction_length,int & offset)719061da546Spatrick bool x86AssemblyInspectionEngine::pc_rel_branch_or_jump_p (
720061da546Spatrick     const int instruction_length, int &offset)
721061da546Spatrick {
722061da546Spatrick   int opcode_size = 0;
723061da546Spatrick 
724061da546Spatrick   uint8_t b1 = m_cur_insn[0];
725061da546Spatrick 
726061da546Spatrick   switch (b1) {
727061da546Spatrick     case 0x77: // JA/JNBE rel8
728061da546Spatrick     case 0x73: // JAE/JNB/JNC rel8
729061da546Spatrick     case 0x72: // JB/JC/JNAE rel8
730061da546Spatrick     case 0x76: // JBE/JNA rel8
731061da546Spatrick     case 0xe3: // JCXZ/JECXZ/JRCXZ rel8
732061da546Spatrick     case 0x74: // JE/JZ rel8
733061da546Spatrick     case 0x7f: // JG/JNLE rel8
734061da546Spatrick     case 0x7d: // JGE/JNL rel8
735061da546Spatrick     case 0x7c: // JL/JNGE rel8
736061da546Spatrick     case 0x7e: // JNG/JLE rel8
737061da546Spatrick     case 0x71: // JNO rel8
738061da546Spatrick     case 0x7b: // JNP/JPO rel8
739061da546Spatrick     case 0x79: // JNS rel8
740061da546Spatrick     case 0x75: // JNE/JNZ rel8
741061da546Spatrick     case 0x70: // JO rel8
742061da546Spatrick     case 0x7a: // JP/JPE rel8
743061da546Spatrick     case 0x78: // JS rel8
744061da546Spatrick     case 0xeb: // JMP rel8
745061da546Spatrick     case 0xe9: // JMP rel16/rel32
746061da546Spatrick       opcode_size = 1;
747061da546Spatrick       break;
748061da546Spatrick     default:
749061da546Spatrick       break;
750061da546Spatrick   }
751061da546Spatrick   if (b1 == 0x0f && opcode_size == 0) {
752061da546Spatrick     uint8_t b2 = m_cur_insn[1];
753061da546Spatrick     switch (b2) {
754061da546Spatrick       case 0x87: // JA/JNBE rel16/rel32
755061da546Spatrick       case 0x86: // JBE/JNA rel16/rel32
756061da546Spatrick       case 0x84: // JE/JZ rel16/rel32
757061da546Spatrick       case 0x8f: // JG/JNLE rel16/rel32
758061da546Spatrick       case 0x8d: // JNL/JGE rel16/rel32
759061da546Spatrick       case 0x8e: // JLE rel16/rel32
760061da546Spatrick       case 0x82: // JB/JC/JNAE rel16/rel32
761061da546Spatrick       case 0x83: // JAE/JNB/JNC rel16/rel32
762061da546Spatrick       case 0x85: // JNE/JNZ rel16/rel32
763061da546Spatrick       case 0x8c: // JL/JNGE rel16/rel32
764061da546Spatrick       case 0x81: // JNO rel16/rel32
765061da546Spatrick       case 0x8b: // JNP/JPO rel16/rel32
766061da546Spatrick       case 0x89: // JNS rel16/rel32
767061da546Spatrick       case 0x80: // JO rel16/rel32
768061da546Spatrick       case 0x8a: // JP rel16/rel32
769061da546Spatrick       case 0x88: // JS rel16/rel32
770061da546Spatrick         opcode_size = 2;
771061da546Spatrick         break;
772061da546Spatrick       default:
773061da546Spatrick         break;
774061da546Spatrick     }
775061da546Spatrick   }
776061da546Spatrick 
777061da546Spatrick   if (opcode_size == 0)
778061da546Spatrick     return false;
779061da546Spatrick 
780061da546Spatrick   offset = 0;
781061da546Spatrick   if (instruction_length - opcode_size == 1) {
782061da546Spatrick     int8_t rel8 = (int8_t) *(m_cur_insn + opcode_size);
783061da546Spatrick     offset = rel8;
784061da546Spatrick   } else if (instruction_length - opcode_size == 2) {
785061da546Spatrick     int16_t rel16 = extract_2_signed (m_cur_insn + opcode_size);
786061da546Spatrick     offset = rel16;
787061da546Spatrick   } else if (instruction_length - opcode_size == 4) {
788061da546Spatrick     int32_t rel32 = extract_4_signed (m_cur_insn + opcode_size);
789061da546Spatrick     offset = rel32;
790061da546Spatrick   } else {
791061da546Spatrick     return false;
792061da546Spatrick   }
793061da546Spatrick   return true;
794061da546Spatrick }
795061da546Spatrick 
796061da546Spatrick // Returns true if this instruction is a intra-function branch or jump -
797061da546Spatrick // a branch/jump within the bounds of this same function.
798061da546Spatrick // Cannot predict where a jump through a register value ("jmpq *%rax")
799061da546Spatrick // will go, so it will return false on that instruction.
local_branch_p(const addr_t current_func_text_offset,const AddressRange & func_range,const int instruction_length,addr_t & target_insn_offset)800061da546Spatrick bool x86AssemblyInspectionEngine::local_branch_p (
801061da546Spatrick     const addr_t current_func_text_offset,
802061da546Spatrick     const AddressRange &func_range,
803061da546Spatrick     const int instruction_length,
804061da546Spatrick     addr_t &target_insn_offset) {
805061da546Spatrick   int offset;
806061da546Spatrick   if (pc_rel_branch_or_jump_p (instruction_length, offset) && offset != 0) {
807061da546Spatrick     addr_t next_pc_value = current_func_text_offset + instruction_length;
808061da546Spatrick     if (offset < 0 && addr_t(-offset) > current_func_text_offset) {
809061da546Spatrick       // Branch target is before the start of this function
810061da546Spatrick       return false;
811061da546Spatrick     }
812061da546Spatrick     if (offset + next_pc_value > func_range.GetByteSize()) {
813061da546Spatrick       // Branch targets outside this function's bounds
814061da546Spatrick       return false;
815061da546Spatrick     }
816061da546Spatrick     // This instruction branches to target_insn_offset (byte offset into the function)
817061da546Spatrick     target_insn_offset = next_pc_value + offset;
818061da546Spatrick     return true;
819061da546Spatrick   }
820061da546Spatrick   return false;
821061da546Spatrick }
822061da546Spatrick 
823061da546Spatrick // Returns true if this instruction is a inter-function branch or jump - a
824061da546Spatrick // branch/jump to another function.
825061da546Spatrick // Cannot predict where a jump through a register value ("jmpq *%rax")
826061da546Spatrick // will go, so it will return false on that instruction.
non_local_branch_p(const addr_t current_func_text_offset,const AddressRange & func_range,const int instruction_length)827061da546Spatrick bool x86AssemblyInspectionEngine::non_local_branch_p (
828061da546Spatrick     const addr_t current_func_text_offset,
829061da546Spatrick     const AddressRange &func_range,
830061da546Spatrick     const int instruction_length) {
831061da546Spatrick   int offset;
832061da546Spatrick   addr_t target_insn_offset;
833061da546Spatrick   if (pc_rel_branch_or_jump_p (instruction_length, offset)) {
834061da546Spatrick     return !local_branch_p(current_func_text_offset,func_range,instruction_length,target_insn_offset);
835061da546Spatrick   }
836061da546Spatrick   return false;
837061da546Spatrick }
838061da546Spatrick 
839061da546Spatrick // ret [0xc3] or [0xcb] or [0xc2 imm16] or [0xca imm16]
ret_pattern_p()840061da546Spatrick bool x86AssemblyInspectionEngine::ret_pattern_p() {
841061da546Spatrick   uint8_t *p = m_cur_insn;
842061da546Spatrick   return *p == 0xc3 || *p == 0xc2 || *p == 0xca || *p == 0xcb;
843061da546Spatrick }
844061da546Spatrick 
extract_2(uint8_t * b)845061da546Spatrick uint16_t x86AssemblyInspectionEngine::extract_2(uint8_t *b) {
846061da546Spatrick   uint16_t v = 0;
847061da546Spatrick   for (int i = 1; i >= 0; i--)
848061da546Spatrick     v = (v << 8) | b[i];
849061da546Spatrick   return v;
850061da546Spatrick }
851061da546Spatrick 
extract_2_signed(uint8_t * b)852061da546Spatrick int16_t x86AssemblyInspectionEngine::extract_2_signed(uint8_t *b) {
853061da546Spatrick   int16_t v = 0;
854061da546Spatrick   for (int i = 1; i >= 0; i--)
855061da546Spatrick     v = (v << 8) | b[i];
856061da546Spatrick   return v;
857061da546Spatrick }
858061da546Spatrick 
859adae0cfdSpatrick // movq $0x????????(%rip), $reg [(0x4c || 0x48) 0x8b ?? ?? ?? ?? ??]
860adae0cfdSpatrick // xorq $off(%rsp), $reg        [(0x4c || 0x48) 0x33 ?? 0x24]
retguard_prologue_p(size_t offset,int insn_len)861adae0cfdSpatrick bool x86AssemblyInspectionEngine::retguard_prologue_p(size_t offset, int insn_len) {
862adae0cfdSpatrick   uint8_t *p = m_cur_insn;
863adae0cfdSpatrick   if (offset == 0 && insn_len == 7)
864adae0cfdSpatrick     return (*p == 0x48 || *p == 0x4c) && (*(p + 1) == 0x8b);
865adae0cfdSpatrick   else if (offset == 7 && insn_len == 4)
866adae0cfdSpatrick     return (*p == 0x48 || *p == 0x4c) && (*(p + 1) == 0x33) && (*(p + 3) == 0x24);
867adae0cfdSpatrick 
868adae0cfdSpatrick   return false;
869adae0cfdSpatrick }
870adae0cfdSpatrick 
extract_4(uint8_t * b)871061da546Spatrick uint32_t x86AssemblyInspectionEngine::extract_4(uint8_t *b) {
872061da546Spatrick   uint32_t v = 0;
873061da546Spatrick   for (int i = 3; i >= 0; i--)
874061da546Spatrick     v = (v << 8) | b[i];
875061da546Spatrick   return v;
876061da546Spatrick }
877061da546Spatrick 
extract_4_signed(uint8_t * b)878061da546Spatrick int32_t x86AssemblyInspectionEngine::extract_4_signed(uint8_t *b) {
879061da546Spatrick   int32_t v = 0;
880061da546Spatrick   for (int i = 3; i >= 0; i--)
881061da546Spatrick     v = (v << 8) | b[i];
882061da546Spatrick   return v;
883061da546Spatrick }
884061da546Spatrick 
885061da546Spatrick 
instruction_length(uint8_t * insn_p,int & length,uint32_t buffer_remaining_bytes)886061da546Spatrick bool x86AssemblyInspectionEngine::instruction_length(uint8_t *insn_p,
887061da546Spatrick                                                      int &length,
888061da546Spatrick                                                      uint32_t buffer_remaining_bytes) {
889061da546Spatrick 
890061da546Spatrick   uint32_t max_op_byte_size = std::min(buffer_remaining_bytes, m_arch.GetMaximumOpcodeByteSize());
891061da546Spatrick   llvm::SmallVector<uint8_t, 32> opcode_data;
892061da546Spatrick   opcode_data.resize(max_op_byte_size);
893061da546Spatrick 
894061da546Spatrick   char out_string[512];
895061da546Spatrick   const size_t inst_size =
896061da546Spatrick       ::LLVMDisasmInstruction(m_disasm_context, insn_p, max_op_byte_size, 0,
897061da546Spatrick                               out_string, sizeof(out_string));
898061da546Spatrick 
899061da546Spatrick   length = inst_size;
900061da546Spatrick   return true;
901061da546Spatrick }
902061da546Spatrick 
machine_regno_to_lldb_regno(int machine_regno,uint32_t & lldb_regno)903061da546Spatrick bool x86AssemblyInspectionEngine::machine_regno_to_lldb_regno(
904061da546Spatrick     int machine_regno, uint32_t &lldb_regno) {
905061da546Spatrick   MachineRegnumToNameAndLLDBRegnum::iterator it = m_reg_map.find(machine_regno);
906061da546Spatrick   if (it != m_reg_map.end()) {
907061da546Spatrick     lldb_regno = it->second.lldb_regnum;
908061da546Spatrick     return true;
909061da546Spatrick   }
910061da546Spatrick   return false;
911061da546Spatrick }
912061da546Spatrick 
GetNonCallSiteUnwindPlanFromAssembly(uint8_t * data,size_t size,AddressRange & func_range,UnwindPlan & unwind_plan)913061da546Spatrick bool x86AssemblyInspectionEngine::GetNonCallSiteUnwindPlanFromAssembly(
914061da546Spatrick     uint8_t *data, size_t size, AddressRange &func_range,
915061da546Spatrick     UnwindPlan &unwind_plan) {
916061da546Spatrick   unwind_plan.Clear();
917061da546Spatrick 
918061da546Spatrick   if (data == nullptr || size == 0)
919061da546Spatrick     return false;
920061da546Spatrick 
921061da546Spatrick   if (!m_register_map_initialized)
922061da546Spatrick     return false;
923061da546Spatrick 
924061da546Spatrick   addr_t current_func_text_offset = 0;
925061da546Spatrick   int current_sp_bytes_offset_from_fa = 0;
926061da546Spatrick   bool is_aligned = false;
927061da546Spatrick   UnwindPlan::Row::RegisterLocation initial_regloc;
928061da546Spatrick   UnwindPlan::RowSP row(new UnwindPlan::Row);
929061da546Spatrick 
930061da546Spatrick   unwind_plan.SetPlanValidAddressRange(func_range);
931061da546Spatrick   unwind_plan.SetRegisterKind(eRegisterKindLLDB);
932061da546Spatrick 
933061da546Spatrick   // At the start of the function, find the CFA by adding wordsize to the SP
934061da546Spatrick   // register
935061da546Spatrick   row->SetOffset(current_func_text_offset);
936061da546Spatrick   row->GetCFAValue().SetIsRegisterPlusOffset(m_lldb_sp_regnum, m_wordsize);
937061da546Spatrick 
938061da546Spatrick   // caller's stack pointer value before the call insn is the CFA address
939061da546Spatrick   initial_regloc.SetIsCFAPlusOffset(0);
940061da546Spatrick   row->SetRegisterInfo(m_lldb_sp_regnum, initial_regloc);
941061da546Spatrick 
942061da546Spatrick   // saved instruction pointer can be found at CFA - wordsize.
943061da546Spatrick   current_sp_bytes_offset_from_fa = m_wordsize;
944061da546Spatrick   initial_regloc.SetAtCFAPlusOffset(-current_sp_bytes_offset_from_fa);
945061da546Spatrick   row->SetRegisterInfo(m_lldb_ip_regnum, initial_regloc);
946061da546Spatrick 
947061da546Spatrick   unwind_plan.AppendRow(row);
948061da546Spatrick 
949061da546Spatrick   // Allocate a new Row, populate it with the existing Row contents.
950061da546Spatrick   UnwindPlan::Row *newrow = new UnwindPlan::Row;
951061da546Spatrick   *newrow = *row.get();
952061da546Spatrick   row.reset(newrow);
953061da546Spatrick 
954061da546Spatrick   // Track which registers have been saved so far in the prologue. If we see
955061da546Spatrick   // another push of that register, it's not part of the prologue. The register
956061da546Spatrick   // numbers used here are the machine register #'s (i386_register_numbers,
957061da546Spatrick   // x86_64_register_numbers).
958061da546Spatrick   std::vector<bool> saved_registers(32, false);
959061da546Spatrick 
960061da546Spatrick   // Once the prologue has completed we'll save a copy of the unwind
961061da546Spatrick   // instructions If there is an epilogue in the middle of the function, after
962061da546Spatrick   // that epilogue we'll reinstate the unwind setup -- we assume that some code
963061da546Spatrick   // path jumps over the mid-function epilogue
964061da546Spatrick 
965061da546Spatrick   UnwindPlan::RowSP prologue_completed_row; // copy of prologue row of CFI
966*101d251dSrobert   int prologue_completed_sp_bytes_offset_from_cfa = 0; // The sp value before the
967061da546Spatrick                                                    // epilogue started executed
968*101d251dSrobert   bool prologue_completed_is_aligned = false;
969061da546Spatrick   std::vector<bool> prologue_completed_saved_registers;
970061da546Spatrick 
971061da546Spatrick   while (current_func_text_offset < size) {
972061da546Spatrick     int stack_offset, insn_len;
973061da546Spatrick     int machine_regno;   // register numbers masked directly out of instructions
974061da546Spatrick     uint32_t lldb_regno; // register numbers in lldb's eRegisterKindLLDB
975061da546Spatrick                          // numbering scheme
976061da546Spatrick 
977061da546Spatrick     bool in_epilogue = false; // we're in the middle of an epilogue sequence
978061da546Spatrick     bool row_updated = false; // The UnwindPlan::Row 'row' has been updated
979061da546Spatrick 
980061da546Spatrick     m_cur_insn = data + current_func_text_offset;
981061da546Spatrick     if (!instruction_length(m_cur_insn, insn_len, size - current_func_text_offset)
982061da546Spatrick         || insn_len == 0
983061da546Spatrick         || insn_len > kMaxInstructionByteSize) {
984061da546Spatrick       // An unrecognized/junk instruction
985061da546Spatrick       break;
986061da546Spatrick     }
987061da546Spatrick 
988061da546Spatrick     auto &cfa_value = row->GetCFAValue();
989061da546Spatrick     auto &afa_value = row->GetAFAValue();
990061da546Spatrick     auto fa_value_ptr = is_aligned ? &afa_value : &cfa_value;
991061da546Spatrick 
992061da546Spatrick     if (mov_rsp_rbp_pattern_p()) {
993061da546Spatrick       if (fa_value_ptr->GetRegisterNumber() == m_lldb_sp_regnum) {
994061da546Spatrick         fa_value_ptr->SetIsRegisterPlusOffset(
995061da546Spatrick             m_lldb_fp_regnum, fa_value_ptr->GetOffset());
996061da546Spatrick         row_updated = true;
997061da546Spatrick       }
998061da546Spatrick     }
999061da546Spatrick 
1000061da546Spatrick     else if (mov_rsp_rbx_pattern_p()) {
1001061da546Spatrick       if (fa_value_ptr->GetRegisterNumber() == m_lldb_sp_regnum) {
1002061da546Spatrick         fa_value_ptr->SetIsRegisterPlusOffset(
1003061da546Spatrick             m_lldb_alt_fp_regnum, fa_value_ptr->GetOffset());
1004061da546Spatrick         row_updated = true;
1005061da546Spatrick       }
1006061da546Spatrick     }
1007061da546Spatrick 
1008061da546Spatrick     else if (and_rsp_pattern_p()) {
1009061da546Spatrick       current_sp_bytes_offset_from_fa = 0;
1010061da546Spatrick       afa_value.SetIsRegisterPlusOffset(
1011061da546Spatrick           m_lldb_sp_regnum, current_sp_bytes_offset_from_fa);
1012061da546Spatrick       fa_value_ptr = &afa_value;
1013061da546Spatrick       is_aligned = true;
1014061da546Spatrick       row_updated = true;
1015061da546Spatrick     }
1016061da546Spatrick 
1017061da546Spatrick     else if (mov_rbp_rsp_pattern_p()) {
1018061da546Spatrick       if (is_aligned && cfa_value.GetRegisterNumber() == m_lldb_fp_regnum)
1019061da546Spatrick       {
1020061da546Spatrick         is_aligned = false;
1021061da546Spatrick         fa_value_ptr = &cfa_value;
1022061da546Spatrick         afa_value.SetUnspecified();
1023061da546Spatrick         row_updated = true;
1024061da546Spatrick       }
1025061da546Spatrick       if (fa_value_ptr->GetRegisterNumber() == m_lldb_fp_regnum)
1026061da546Spatrick         current_sp_bytes_offset_from_fa = fa_value_ptr->GetOffset();
1027061da546Spatrick     }
1028061da546Spatrick 
1029061da546Spatrick     else if (mov_rbx_rsp_pattern_p()) {
1030061da546Spatrick       if (is_aligned && cfa_value.GetRegisterNumber() == m_lldb_alt_fp_regnum)
1031061da546Spatrick       {
1032061da546Spatrick         is_aligned = false;
1033061da546Spatrick         fa_value_ptr = &cfa_value;
1034061da546Spatrick         afa_value.SetUnspecified();
1035061da546Spatrick         row_updated = true;
1036061da546Spatrick       }
1037061da546Spatrick       if (fa_value_ptr->GetRegisterNumber() == m_lldb_alt_fp_regnum)
1038061da546Spatrick         current_sp_bytes_offset_from_fa = fa_value_ptr->GetOffset();
1039061da546Spatrick     }
1040061da546Spatrick 
1041061da546Spatrick     // This is the start() function (or a pthread equivalent), it starts with a
1042061da546Spatrick     // pushl $0x0 which puts the saved pc value of 0 on the stack.  In this
1043061da546Spatrick     // case we want to pretend we didn't see a stack movement at all --
1044061da546Spatrick     // normally the saved pc value is already on the stack by the time the
1045061da546Spatrick     // function starts executing.
1046061da546Spatrick     else if (push_0_pattern_p()) {
1047061da546Spatrick     }
1048061da546Spatrick 
1049061da546Spatrick     else if (push_reg_p(machine_regno)) {
1050061da546Spatrick       current_sp_bytes_offset_from_fa += m_wordsize;
1051061da546Spatrick       // the PUSH instruction has moved the stack pointer - if the FA is set
1052061da546Spatrick       // in terms of the stack pointer, we need to add a new row of
1053061da546Spatrick       // instructions.
1054061da546Spatrick       if (fa_value_ptr->GetRegisterNumber() == m_lldb_sp_regnum) {
1055061da546Spatrick         fa_value_ptr->SetOffset(current_sp_bytes_offset_from_fa);
1056061da546Spatrick         row_updated = true;
1057061da546Spatrick       }
1058061da546Spatrick       // record where non-volatile (callee-saved, spilled) registers are saved
1059061da546Spatrick       // on the stack
1060061da546Spatrick       if (nonvolatile_reg_p(machine_regno) &&
1061061da546Spatrick           machine_regno_to_lldb_regno(machine_regno, lldb_regno) &&
1062061da546Spatrick           !saved_registers[machine_regno]) {
1063061da546Spatrick         UnwindPlan::Row::RegisterLocation regloc;
1064061da546Spatrick         if (is_aligned)
1065061da546Spatrick             regloc.SetAtAFAPlusOffset(-current_sp_bytes_offset_from_fa);
1066061da546Spatrick         else
1067061da546Spatrick             regloc.SetAtCFAPlusOffset(-current_sp_bytes_offset_from_fa);
1068061da546Spatrick         row->SetRegisterInfo(lldb_regno, regloc);
1069061da546Spatrick         saved_registers[machine_regno] = true;
1070061da546Spatrick         row_updated = true;
1071061da546Spatrick       }
1072061da546Spatrick     }
1073061da546Spatrick 
1074061da546Spatrick     else if (pop_reg_p(machine_regno)) {
1075061da546Spatrick       current_sp_bytes_offset_from_fa -= m_wordsize;
1076061da546Spatrick 
1077061da546Spatrick       if (nonvolatile_reg_p(machine_regno) &&
1078061da546Spatrick           machine_regno_to_lldb_regno(machine_regno, lldb_regno) &&
1079061da546Spatrick           saved_registers[machine_regno]) {
1080061da546Spatrick         saved_registers[machine_regno] = false;
1081061da546Spatrick         row->RemoveRegisterInfo(lldb_regno);
1082061da546Spatrick 
1083061da546Spatrick         if (lldb_regno == fa_value_ptr->GetRegisterNumber()) {
1084061da546Spatrick           fa_value_ptr->SetIsRegisterPlusOffset(
1085061da546Spatrick               m_lldb_sp_regnum, fa_value_ptr->GetOffset());
1086061da546Spatrick         }
1087061da546Spatrick 
1088061da546Spatrick         in_epilogue = true;
1089061da546Spatrick         row_updated = true;
1090061da546Spatrick       }
1091061da546Spatrick 
1092061da546Spatrick       // the POP instruction has moved the stack pointer - if the FA is set in
1093061da546Spatrick       // terms of the stack pointer, we need to add a new row of instructions.
1094061da546Spatrick       if (fa_value_ptr->GetRegisterNumber() == m_lldb_sp_regnum) {
1095061da546Spatrick         fa_value_ptr->SetIsRegisterPlusOffset(
1096061da546Spatrick             m_lldb_sp_regnum, current_sp_bytes_offset_from_fa);
1097061da546Spatrick         row_updated = true;
1098061da546Spatrick       }
1099061da546Spatrick     }
1100061da546Spatrick 
1101061da546Spatrick     else if (pop_misc_reg_p()) {
1102061da546Spatrick       current_sp_bytes_offset_from_fa -= m_wordsize;
1103061da546Spatrick       if (fa_value_ptr->GetRegisterNumber() == m_lldb_sp_regnum) {
1104061da546Spatrick         fa_value_ptr->SetIsRegisterPlusOffset(
1105061da546Spatrick             m_lldb_sp_regnum, current_sp_bytes_offset_from_fa);
1106061da546Spatrick         row_updated = true;
1107061da546Spatrick       }
1108061da546Spatrick     }
1109061da546Spatrick 
1110061da546Spatrick     // The LEAVE instruction moves the value from rbp into rsp and pops a value
1111061da546Spatrick     // off the stack into rbp (restoring the caller's rbp value). It is the
1112061da546Spatrick     // opposite of ENTER, or 'push rbp, mov rsp rbp'.
1113061da546Spatrick     else if (leave_pattern_p()) {
1114061da546Spatrick       if (saved_registers[m_machine_fp_regnum]) {
1115061da546Spatrick         saved_registers[m_machine_fp_regnum] = false;
1116061da546Spatrick         row->RemoveRegisterInfo(m_lldb_fp_regnum);
1117061da546Spatrick 
1118061da546Spatrick         row_updated = true;
1119061da546Spatrick       }
1120061da546Spatrick 
1121061da546Spatrick       if (is_aligned && cfa_value.GetRegisterNumber() == m_lldb_fp_regnum)
1122061da546Spatrick       {
1123061da546Spatrick         is_aligned = false;
1124061da546Spatrick         fa_value_ptr = &cfa_value;
1125061da546Spatrick         afa_value.SetUnspecified();
1126061da546Spatrick         row_updated = true;
1127061da546Spatrick       }
1128061da546Spatrick 
1129061da546Spatrick       if (fa_value_ptr->GetRegisterNumber() == m_lldb_fp_regnum)
1130061da546Spatrick       {
1131061da546Spatrick         fa_value_ptr->SetIsRegisterPlusOffset(
1132061da546Spatrick             m_lldb_sp_regnum, fa_value_ptr->GetOffset());
1133061da546Spatrick 
1134061da546Spatrick         current_sp_bytes_offset_from_fa = fa_value_ptr->GetOffset();
1135061da546Spatrick       }
1136061da546Spatrick 
1137061da546Spatrick       current_sp_bytes_offset_from_fa -= m_wordsize;
1138061da546Spatrick 
1139061da546Spatrick       if (fa_value_ptr->GetRegisterNumber() == m_lldb_sp_regnum) {
1140061da546Spatrick         fa_value_ptr->SetIsRegisterPlusOffset(
1141061da546Spatrick             m_lldb_sp_regnum, current_sp_bytes_offset_from_fa);
1142061da546Spatrick         row_updated = true;
1143061da546Spatrick       }
1144061da546Spatrick 
1145061da546Spatrick       in_epilogue = true;
1146061da546Spatrick     }
1147061da546Spatrick 
1148061da546Spatrick     else if (mov_reg_to_local_stack_frame_p(machine_regno, stack_offset) &&
1149061da546Spatrick              nonvolatile_reg_p(machine_regno) &&
1150061da546Spatrick              machine_regno_to_lldb_regno(machine_regno, lldb_regno) &&
1151061da546Spatrick              !saved_registers[machine_regno]) {
1152061da546Spatrick       saved_registers[machine_regno] = true;
1153061da546Spatrick 
1154061da546Spatrick       UnwindPlan::Row::RegisterLocation regloc;
1155061da546Spatrick 
1156061da546Spatrick       // stack_offset for 'movq %r15, -80(%rbp)' will be 80. In the Row, we
1157061da546Spatrick       // want to express this as the offset from the FA.  If the frame base is
1158061da546Spatrick       // rbp (like the above instruction), the FA offset for rbp is probably
1159061da546Spatrick       // 16.  So we want to say that the value is stored at the FA address -
1160061da546Spatrick       // 96.
1161061da546Spatrick       if (is_aligned)
1162061da546Spatrick           regloc.SetAtAFAPlusOffset(-(stack_offset + fa_value_ptr->GetOffset()));
1163061da546Spatrick       else
1164061da546Spatrick           regloc.SetAtCFAPlusOffset(-(stack_offset + fa_value_ptr->GetOffset()));
1165061da546Spatrick 
1166061da546Spatrick       row->SetRegisterInfo(lldb_regno, regloc);
1167061da546Spatrick 
1168061da546Spatrick       row_updated = true;
1169061da546Spatrick     }
1170061da546Spatrick 
1171061da546Spatrick     else if (sub_rsp_pattern_p(stack_offset)) {
1172061da546Spatrick       current_sp_bytes_offset_from_fa += stack_offset;
1173061da546Spatrick       if (fa_value_ptr->GetRegisterNumber() == m_lldb_sp_regnum) {
1174061da546Spatrick         fa_value_ptr->SetOffset(current_sp_bytes_offset_from_fa);
1175061da546Spatrick         row_updated = true;
1176061da546Spatrick       }
1177061da546Spatrick     }
1178061da546Spatrick 
1179061da546Spatrick     else if (add_rsp_pattern_p(stack_offset)) {
1180061da546Spatrick       current_sp_bytes_offset_from_fa -= stack_offset;
1181061da546Spatrick       if (fa_value_ptr->GetRegisterNumber() == m_lldb_sp_regnum) {
1182061da546Spatrick         fa_value_ptr->SetOffset(current_sp_bytes_offset_from_fa);
1183061da546Spatrick         row_updated = true;
1184061da546Spatrick       }
1185061da546Spatrick       in_epilogue = true;
1186061da546Spatrick     }
1187061da546Spatrick 
1188061da546Spatrick     else if (push_extended_pattern_p() || push_imm_pattern_p() ||
1189061da546Spatrick              push_misc_reg_p()) {
1190061da546Spatrick       current_sp_bytes_offset_from_fa += m_wordsize;
1191061da546Spatrick       if (fa_value_ptr->GetRegisterNumber() == m_lldb_sp_regnum) {
1192061da546Spatrick         fa_value_ptr->SetOffset(current_sp_bytes_offset_from_fa);
1193061da546Spatrick         row_updated = true;
1194061da546Spatrick       }
1195061da546Spatrick     }
1196061da546Spatrick 
1197061da546Spatrick     else if (lea_rsp_pattern_p(stack_offset)) {
1198061da546Spatrick       current_sp_bytes_offset_from_fa -= stack_offset;
1199061da546Spatrick       if (fa_value_ptr->GetRegisterNumber() == m_lldb_sp_regnum) {
1200061da546Spatrick         fa_value_ptr->SetOffset(current_sp_bytes_offset_from_fa);
1201061da546Spatrick         row_updated = true;
1202061da546Spatrick       }
1203061da546Spatrick       if (stack_offset > 0)
1204061da546Spatrick         in_epilogue = true;
1205061da546Spatrick     }
1206061da546Spatrick 
1207061da546Spatrick     else if (lea_rbp_rsp_pattern_p(stack_offset)) {
1208061da546Spatrick       if (is_aligned &&
1209061da546Spatrick           cfa_value.GetRegisterNumber() == m_lldb_fp_regnum) {
1210061da546Spatrick         is_aligned = false;
1211061da546Spatrick         fa_value_ptr = &cfa_value;
1212061da546Spatrick         afa_value.SetUnspecified();
1213061da546Spatrick         row_updated = true;
1214061da546Spatrick       }
1215061da546Spatrick       if (fa_value_ptr->GetRegisterNumber() == m_lldb_fp_regnum) {
1216061da546Spatrick         current_sp_bytes_offset_from_fa =
1217061da546Spatrick           fa_value_ptr->GetOffset() - stack_offset;
1218061da546Spatrick       }
1219061da546Spatrick     }
1220061da546Spatrick 
1221061da546Spatrick     else if (lea_rbx_rsp_pattern_p(stack_offset)) {
1222061da546Spatrick       if (is_aligned &&
1223061da546Spatrick           cfa_value.GetRegisterNumber() == m_lldb_alt_fp_regnum) {
1224061da546Spatrick         is_aligned = false;
1225061da546Spatrick         fa_value_ptr = &cfa_value;
1226061da546Spatrick         afa_value.SetUnspecified();
1227061da546Spatrick         row_updated = true;
1228061da546Spatrick       }
1229061da546Spatrick       if (fa_value_ptr->GetRegisterNumber() == m_lldb_alt_fp_regnum) {
1230061da546Spatrick         current_sp_bytes_offset_from_fa = fa_value_ptr->GetOffset() - stack_offset;
1231061da546Spatrick       }
1232061da546Spatrick     }
1233061da546Spatrick 
1234061da546Spatrick     else if (prologue_completed_row.get() &&
1235061da546Spatrick              (ret_pattern_p() ||
1236061da546Spatrick               non_local_branch_p (current_func_text_offset, func_range, insn_len) ||
1237061da546Spatrick               jmp_to_reg_p())) {
1238061da546Spatrick       // Check if the current instruction is the end of an epilogue sequence,
1239061da546Spatrick       // and if so, re-instate the prologue-completed unwind state.
1240061da546Spatrick 
1241061da546Spatrick       // The current instruction is a branch/jump outside this function,
1242061da546Spatrick       // a ret, or a jump through a register value which we cannot
1243061da546Spatrick       // determine the effcts of.  Verify that the stack frame state
1244061da546Spatrick       // has been unwound to the same as it was at function entry to avoid
1245061da546Spatrick       // mis-identifying a JMP instruction as an epilogue.
1246061da546Spatrick       UnwindPlan::Row::RegisterLocation sp, pc;
1247061da546Spatrick       if (row->GetRegisterInfo(m_lldb_sp_regnum, sp) &&
1248061da546Spatrick           row->GetRegisterInfo(m_lldb_ip_regnum, pc)) {
1249061da546Spatrick         // Any ret instruction variant is definitely indicative of an
1250061da546Spatrick         // epilogue; for other insn patterns verify that we're back to
1251061da546Spatrick         // the original unwind state.
1252061da546Spatrick         if (ret_pattern_p() ||
1253061da546Spatrick             (sp.IsCFAPlusOffset() && sp.GetOffset() == 0 &&
1254061da546Spatrick             pc.IsAtCFAPlusOffset() && pc.GetOffset() == -m_wordsize)) {
1255061da546Spatrick           // Reinstate the saved prologue setup for any instructions that come
1256061da546Spatrick           // after the epilogue
1257061da546Spatrick 
1258061da546Spatrick           UnwindPlan::Row *newrow = new UnwindPlan::Row;
1259061da546Spatrick           *newrow = *prologue_completed_row.get();
1260061da546Spatrick           row.reset(newrow);
1261061da546Spatrick           current_sp_bytes_offset_from_fa =
1262061da546Spatrick               prologue_completed_sp_bytes_offset_from_cfa;
1263061da546Spatrick           is_aligned = prologue_completed_is_aligned;
1264061da546Spatrick 
1265061da546Spatrick           saved_registers.clear();
1266061da546Spatrick           saved_registers.resize(prologue_completed_saved_registers.size(), false);
1267061da546Spatrick           for (size_t i = 0; i < prologue_completed_saved_registers.size(); ++i) {
1268061da546Spatrick             saved_registers[i] = prologue_completed_saved_registers[i];
1269061da546Spatrick           }
1270061da546Spatrick 
1271061da546Spatrick           in_epilogue = true;
1272061da546Spatrick           row_updated = true;
1273061da546Spatrick         }
1274061da546Spatrick       }
1275061da546Spatrick     }
1276061da546Spatrick 
1277061da546Spatrick     // call next instruction
1278061da546Spatrick     //     call 0
1279061da546Spatrick     //  => pop  %ebx
1280061da546Spatrick     // This is used in i386 programs to get the PIC base address for finding
1281061da546Spatrick     // global data
1282061da546Spatrick     else if (call_next_insn_pattern_p()) {
1283061da546Spatrick       current_sp_bytes_offset_from_fa += m_wordsize;
1284061da546Spatrick       if (fa_value_ptr->GetRegisterNumber() == m_lldb_sp_regnum) {
1285061da546Spatrick         fa_value_ptr->SetOffset(current_sp_bytes_offset_from_fa);
1286061da546Spatrick         row_updated = true;
1287061da546Spatrick       }
1288061da546Spatrick     }
1289061da546Spatrick 
1290061da546Spatrick     if (row_updated) {
1291061da546Spatrick       if (current_func_text_offset + insn_len < size) {
1292061da546Spatrick         row->SetOffset(current_func_text_offset + insn_len);
1293061da546Spatrick         unwind_plan.AppendRow(row);
1294061da546Spatrick         // Allocate a new Row, populate it with the existing Row contents.
1295061da546Spatrick         newrow = new UnwindPlan::Row;
1296061da546Spatrick         *newrow = *row.get();
1297061da546Spatrick         row.reset(newrow);
1298061da546Spatrick       }
1299061da546Spatrick     }
1300061da546Spatrick 
1301061da546Spatrick     if (!in_epilogue && row_updated) {
1302061da546Spatrick       // If we're not in an epilogue sequence, save the updated Row
1303061da546Spatrick       UnwindPlan::Row *newrow = new UnwindPlan::Row;
1304061da546Spatrick       *newrow = *row.get();
1305061da546Spatrick       prologue_completed_row.reset(newrow);
1306061da546Spatrick 
1307061da546Spatrick       prologue_completed_saved_registers.clear();
1308061da546Spatrick       prologue_completed_saved_registers.resize(saved_registers.size(), false);
1309061da546Spatrick       for (size_t i = 0; i < saved_registers.size(); ++i) {
1310061da546Spatrick         prologue_completed_saved_registers[i] = saved_registers[i];
1311061da546Spatrick       }
1312061da546Spatrick     }
1313061da546Spatrick 
1314061da546Spatrick     // We may change the sp value without adding a new Row necessarily -- keep
1315061da546Spatrick     // track of it either way.
1316061da546Spatrick     if (!in_epilogue) {
1317061da546Spatrick       prologue_completed_sp_bytes_offset_from_cfa =
1318061da546Spatrick           current_sp_bytes_offset_from_fa;
1319061da546Spatrick       prologue_completed_is_aligned = is_aligned;
1320061da546Spatrick     }
1321061da546Spatrick 
1322061da546Spatrick     m_cur_insn = m_cur_insn + insn_len;
1323061da546Spatrick     current_func_text_offset += insn_len;
1324061da546Spatrick   }
1325061da546Spatrick 
1326061da546Spatrick   unwind_plan.SetSourceName("assembly insn profiling");
1327061da546Spatrick   unwind_plan.SetSourcedFromCompiler(eLazyBoolNo);
1328061da546Spatrick   unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolYes);
1329061da546Spatrick   unwind_plan.SetUnwindPlanForSignalTrap(eLazyBoolNo);
1330061da546Spatrick 
1331061da546Spatrick   return true;
1332061da546Spatrick }
1333061da546Spatrick 
AugmentUnwindPlanFromCallSite(uint8_t * data,size_t size,AddressRange & func_range,UnwindPlan & unwind_plan,RegisterContextSP & reg_ctx)1334061da546Spatrick bool x86AssemblyInspectionEngine::AugmentUnwindPlanFromCallSite(
1335061da546Spatrick     uint8_t *data, size_t size, AddressRange &func_range,
1336061da546Spatrick     UnwindPlan &unwind_plan, RegisterContextSP &reg_ctx) {
1337061da546Spatrick   Address addr_start = func_range.GetBaseAddress();
1338061da546Spatrick   if (!addr_start.IsValid())
1339061da546Spatrick     return false;
1340061da546Spatrick 
1341061da546Spatrick   // We either need a live RegisterContext, or we need the UnwindPlan to
1342061da546Spatrick   // already be in the lldb register numbering scheme.
1343061da546Spatrick   if (reg_ctx.get() == nullptr &&
1344061da546Spatrick       unwind_plan.GetRegisterKind() != eRegisterKindLLDB)
1345061da546Spatrick     return false;
1346061da546Spatrick 
1347061da546Spatrick   // Is original unwind_plan valid?
1348061da546Spatrick   // unwind_plan should have at least one row which is ABI-default (CFA
1349061da546Spatrick   // register is sp), and another row in mid-function.
1350061da546Spatrick   if (unwind_plan.GetRowCount() < 2)
1351061da546Spatrick     return false;
1352061da546Spatrick 
1353061da546Spatrick   UnwindPlan::RowSP first_row = unwind_plan.GetRowAtIndex(0);
1354061da546Spatrick   if (first_row->GetOffset() != 0)
1355061da546Spatrick     return false;
1356061da546Spatrick   uint32_t cfa_reg = first_row->GetCFAValue().GetRegisterNumber();
1357061da546Spatrick   if (unwind_plan.GetRegisterKind() != eRegisterKindLLDB) {
1358061da546Spatrick     cfa_reg = reg_ctx->ConvertRegisterKindToRegisterNumber(
1359061da546Spatrick         unwind_plan.GetRegisterKind(),
1360061da546Spatrick         first_row->GetCFAValue().GetRegisterNumber());
1361061da546Spatrick   }
1362061da546Spatrick   if (cfa_reg != m_lldb_sp_regnum ||
1363061da546Spatrick       first_row->GetCFAValue().GetOffset() != m_wordsize)
1364061da546Spatrick     return false;
1365061da546Spatrick 
1366061da546Spatrick   UnwindPlan::RowSP original_last_row = unwind_plan.GetRowForFunctionOffset(-1);
1367061da546Spatrick 
1368061da546Spatrick   size_t offset = 0;
1369061da546Spatrick   int row_id = 1;
1370061da546Spatrick   bool unwind_plan_updated = false;
1371061da546Spatrick   UnwindPlan::RowSP row(new UnwindPlan::Row(*first_row));
1372061da546Spatrick 
1373061da546Spatrick   // After a mid-function epilogue we will need to re-insert the original
1374061da546Spatrick   // unwind rules so unwinds work for the remainder of the function.  These
1375061da546Spatrick   // aren't common with clang/gcc on x86 but it is possible.
1376061da546Spatrick   bool reinstate_unwind_state = false;
1377061da546Spatrick 
1378061da546Spatrick   while (offset < size) {
1379061da546Spatrick     m_cur_insn = data + offset;
1380061da546Spatrick     int insn_len;
1381061da546Spatrick     if (!instruction_length(m_cur_insn, insn_len, size - offset) ||
1382061da546Spatrick         insn_len == 0 || insn_len > kMaxInstructionByteSize) {
1383061da546Spatrick       // An unrecognized/junk instruction.
1384061da546Spatrick       break;
1385061da546Spatrick     }
1386061da546Spatrick 
1387061da546Spatrick     // Advance offsets.
1388061da546Spatrick     offset += insn_len;
1389061da546Spatrick 
1390061da546Spatrick     // offset is pointing beyond the bounds of the function; stop looping.
1391061da546Spatrick     if (offset >= size)
1392061da546Spatrick       continue;
1393061da546Spatrick 
1394061da546Spatrick     if (reinstate_unwind_state) {
1395061da546Spatrick       UnwindPlan::RowSP new_row(new UnwindPlan::Row());
1396061da546Spatrick       *new_row = *original_last_row;
1397061da546Spatrick       new_row->SetOffset(offset);
1398061da546Spatrick       unwind_plan.AppendRow(new_row);
1399061da546Spatrick       row = std::make_shared<UnwindPlan::Row>();
1400061da546Spatrick       *row = *new_row;
1401061da546Spatrick       reinstate_unwind_state = false;
1402061da546Spatrick       unwind_plan_updated = true;
1403061da546Spatrick       continue;
1404061da546Spatrick     }
1405061da546Spatrick 
1406061da546Spatrick     // If we already have one row for this instruction, we can continue.
1407061da546Spatrick     while (row_id < unwind_plan.GetRowCount() &&
1408061da546Spatrick            unwind_plan.GetRowAtIndex(row_id)->GetOffset() <= offset) {
1409061da546Spatrick       row_id++;
1410061da546Spatrick     }
1411061da546Spatrick     UnwindPlan::RowSP original_row = unwind_plan.GetRowAtIndex(row_id - 1);
1412061da546Spatrick     if (original_row->GetOffset() == offset) {
1413061da546Spatrick       *row = *original_row;
1414061da546Spatrick       continue;
1415061da546Spatrick     }
1416061da546Spatrick 
1417061da546Spatrick     if (row_id == 0) {
1418061da546Spatrick       // If we are here, compiler didn't generate CFI for prologue. This won't
1419061da546Spatrick       // happen to GCC or clang. In this case, bail out directly.
1420061da546Spatrick       return false;
1421061da546Spatrick     }
1422061da546Spatrick 
1423061da546Spatrick     // Inspect the instruction to check if we need a new row for it.
1424061da546Spatrick     cfa_reg = row->GetCFAValue().GetRegisterNumber();
1425061da546Spatrick     if (unwind_plan.GetRegisterKind() != eRegisterKindLLDB) {
1426061da546Spatrick       cfa_reg = reg_ctx->ConvertRegisterKindToRegisterNumber(
1427061da546Spatrick           unwind_plan.GetRegisterKind(),
1428061da546Spatrick           row->GetCFAValue().GetRegisterNumber());
1429061da546Spatrick     }
1430061da546Spatrick     if (cfa_reg == m_lldb_sp_regnum) {
1431061da546Spatrick       // CFA register is sp.
1432061da546Spatrick 
1433061da546Spatrick       // call next instruction
1434061da546Spatrick       //     call 0
1435061da546Spatrick       //  => pop  %ebx
1436061da546Spatrick       if (call_next_insn_pattern_p()) {
1437061da546Spatrick         row->SetOffset(offset);
1438061da546Spatrick         row->GetCFAValue().IncOffset(m_wordsize);
1439061da546Spatrick 
1440061da546Spatrick         UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row));
1441061da546Spatrick         unwind_plan.InsertRow(new_row);
1442061da546Spatrick         unwind_plan_updated = true;
1443061da546Spatrick         continue;
1444061da546Spatrick       }
1445061da546Spatrick 
1446061da546Spatrick       // push/pop register
1447061da546Spatrick       int regno;
1448061da546Spatrick       if (push_reg_p(regno)) {
1449061da546Spatrick         row->SetOffset(offset);
1450061da546Spatrick         row->GetCFAValue().IncOffset(m_wordsize);
1451061da546Spatrick 
1452061da546Spatrick         UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row));
1453061da546Spatrick         unwind_plan.InsertRow(new_row);
1454061da546Spatrick         unwind_plan_updated = true;
1455061da546Spatrick         continue;
1456061da546Spatrick       }
1457061da546Spatrick       if (pop_reg_p(regno)) {
1458061da546Spatrick         // Technically, this might be a nonvolatile register recover in
1459061da546Spatrick         // epilogue. We should reset RegisterInfo for the register. But in
1460061da546Spatrick         // practice, previous rule for the register is still valid... So we
1461061da546Spatrick         // ignore this case.
1462061da546Spatrick 
1463061da546Spatrick         row->SetOffset(offset);
1464061da546Spatrick         row->GetCFAValue().IncOffset(-m_wordsize);
1465061da546Spatrick 
1466061da546Spatrick         UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row));
1467061da546Spatrick         unwind_plan.InsertRow(new_row);
1468061da546Spatrick         unwind_plan_updated = true;
1469061da546Spatrick         continue;
1470061da546Spatrick       }
1471061da546Spatrick 
1472061da546Spatrick       if (pop_misc_reg_p()) {
1473061da546Spatrick         row->SetOffset(offset);
1474061da546Spatrick         row->GetCFAValue().IncOffset(-m_wordsize);
1475061da546Spatrick 
1476061da546Spatrick         UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row));
1477061da546Spatrick         unwind_plan.InsertRow(new_row);
1478061da546Spatrick         unwind_plan_updated = true;
1479061da546Spatrick         continue;
1480061da546Spatrick       }
1481061da546Spatrick 
1482061da546Spatrick       // push imm
1483061da546Spatrick       if (push_imm_pattern_p()) {
1484061da546Spatrick         row->SetOffset(offset);
1485061da546Spatrick         row->GetCFAValue().IncOffset(m_wordsize);
1486061da546Spatrick         UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row));
1487061da546Spatrick         unwind_plan.InsertRow(new_row);
1488061da546Spatrick         unwind_plan_updated = true;
1489061da546Spatrick         continue;
1490061da546Spatrick       }
1491061da546Spatrick 
1492061da546Spatrick       // push extended
1493061da546Spatrick       if (push_extended_pattern_p() || push_misc_reg_p()) {
1494061da546Spatrick         row->SetOffset(offset);
1495061da546Spatrick         row->GetCFAValue().IncOffset(m_wordsize);
1496061da546Spatrick         UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row));
1497061da546Spatrick         unwind_plan.InsertRow(new_row);
1498061da546Spatrick         unwind_plan_updated = true;
1499061da546Spatrick         continue;
1500061da546Spatrick       }
1501061da546Spatrick 
1502061da546Spatrick       // add/sub %rsp/%esp
1503061da546Spatrick       int amount;
1504061da546Spatrick       if (add_rsp_pattern_p(amount)) {
1505061da546Spatrick         row->SetOffset(offset);
1506061da546Spatrick         row->GetCFAValue().IncOffset(-amount);
1507061da546Spatrick 
1508061da546Spatrick         UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row));
1509061da546Spatrick         unwind_plan.InsertRow(new_row);
1510061da546Spatrick         unwind_plan_updated = true;
1511061da546Spatrick         continue;
1512061da546Spatrick       }
1513061da546Spatrick       if (sub_rsp_pattern_p(amount)) {
1514061da546Spatrick         row->SetOffset(offset);
1515061da546Spatrick         row->GetCFAValue().IncOffset(amount);
1516061da546Spatrick 
1517061da546Spatrick         UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row));
1518061da546Spatrick         unwind_plan.InsertRow(new_row);
1519061da546Spatrick         unwind_plan_updated = true;
1520061da546Spatrick         continue;
1521061da546Spatrick       }
1522061da546Spatrick 
1523061da546Spatrick       // lea %rsp, [%rsp + $offset]
1524061da546Spatrick       if (lea_rsp_pattern_p(amount)) {
1525061da546Spatrick         row->SetOffset(offset);
1526061da546Spatrick         row->GetCFAValue().IncOffset(-amount);
1527061da546Spatrick 
1528061da546Spatrick         UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row));
1529061da546Spatrick         unwind_plan.InsertRow(new_row);
1530061da546Spatrick         unwind_plan_updated = true;
1531061da546Spatrick         continue;
1532061da546Spatrick       }
1533061da546Spatrick 
1534061da546Spatrick       if (ret_pattern_p()) {
1535061da546Spatrick         reinstate_unwind_state = true;
1536061da546Spatrick         continue;
1537061da546Spatrick       }
1538061da546Spatrick     } else if (cfa_reg == m_lldb_fp_regnum) {
1539061da546Spatrick       // CFA register is fp.
1540061da546Spatrick 
1541061da546Spatrick       // The only case we care about is epilogue:
1542061da546Spatrick       //     [0x5d] pop %rbp/%ebp
1543061da546Spatrick       //  => [0xc3] ret
1544061da546Spatrick       if (pop_rbp_pattern_p() || leave_pattern_p()) {
1545061da546Spatrick         m_cur_insn++;
1546061da546Spatrick         if (ret_pattern_p()) {
1547061da546Spatrick           row->SetOffset(offset);
1548061da546Spatrick           row->GetCFAValue().SetIsRegisterPlusOffset(
1549061da546Spatrick               first_row->GetCFAValue().GetRegisterNumber(), m_wordsize);
1550061da546Spatrick 
1551061da546Spatrick           UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row));
1552061da546Spatrick           unwind_plan.InsertRow(new_row);
1553061da546Spatrick           unwind_plan_updated = true;
1554061da546Spatrick           reinstate_unwind_state = true;
1555061da546Spatrick           continue;
1556061da546Spatrick         }
1557061da546Spatrick       }
1558061da546Spatrick     } else {
1559061da546Spatrick       // CFA register is not sp or fp.
1560061da546Spatrick 
1561061da546Spatrick       // This must be hand-written assembly.
1562061da546Spatrick       // Just trust eh_frame and assume we have finished.
1563061da546Spatrick       break;
1564061da546Spatrick     }
1565061da546Spatrick   }
1566061da546Spatrick 
1567061da546Spatrick   unwind_plan.SetPlanValidAddressRange(func_range);
1568061da546Spatrick   if (unwind_plan_updated) {
1569061da546Spatrick     std::string unwind_plan_source(unwind_plan.GetSourceName().AsCString());
1570061da546Spatrick     unwind_plan_source += " plus augmentation from assembly parsing";
1571061da546Spatrick     unwind_plan.SetSourceName(unwind_plan_source.c_str());
1572061da546Spatrick     unwind_plan.SetSourcedFromCompiler(eLazyBoolNo);
1573061da546Spatrick     unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolYes);
1574061da546Spatrick   }
1575061da546Spatrick   return true;
1576061da546Spatrick }
1577061da546Spatrick 
FindFirstNonPrologueInstruction(uint8_t * data,size_t size,size_t & offset)1578061da546Spatrick bool x86AssemblyInspectionEngine::FindFirstNonPrologueInstruction(
1579061da546Spatrick     uint8_t *data, size_t size, size_t &offset) {
1580061da546Spatrick   offset = 0;
1581061da546Spatrick 
1582061da546Spatrick   if (!m_register_map_initialized)
1583061da546Spatrick     return false;
1584061da546Spatrick 
1585061da546Spatrick   while (offset < size) {
1586061da546Spatrick     int regno;
1587061da546Spatrick     int insn_len;
1588061da546Spatrick     int scratch;
1589061da546Spatrick 
1590061da546Spatrick     m_cur_insn = data + offset;
1591061da546Spatrick     if (!instruction_length(m_cur_insn, insn_len, size - offset)
1592061da546Spatrick         || insn_len > kMaxInstructionByteSize
1593061da546Spatrick         || insn_len == 0) {
1594061da546Spatrick       // An error parsing the instruction, i.e. probably data/garbage - stop
1595061da546Spatrick       // scanning
1596061da546Spatrick       break;
1597061da546Spatrick     }
1598061da546Spatrick 
1599061da546Spatrick     if (push_rbp_pattern_p() || mov_rsp_rbp_pattern_p() ||
1600061da546Spatrick         sub_rsp_pattern_p(scratch) || push_reg_p(regno) ||
1601061da546Spatrick         mov_reg_to_local_stack_frame_p(regno, scratch) ||
1602adae0cfdSpatrick         retguard_prologue_p(offset, insn_len) ||
1603061da546Spatrick         (lea_rsp_pattern_p(scratch) && offset == 0)) {
1604061da546Spatrick       offset += insn_len;
1605061da546Spatrick       continue;
1606061da546Spatrick     }
1607061da546Spatrick     //
1608061da546Spatrick     // Unknown non-prologue instruction - stop scanning
1609061da546Spatrick     break;
1610061da546Spatrick   }
1611061da546Spatrick 
1612061da546Spatrick   return true;
1613061da546Spatrick }
1614