blob: 411e95e75aeb720e5c310c4f62007b46cfe5b172 [file] [log] [blame]
Greg Clayton078daac2011-04-25 21:07:40 +00001//===-- UnwindAssembly-x86.cpp ----------------------------------*- C++ -*-===//
Jason Molendafbcb7f22010-09-10 07:49:16 +00002//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
Greg Clayton078daac2011-04-25 21:07:40 +000010#include "UnwindAssembly-x86.h"
Jason Molendafbcb7f22010-09-10 07:49:16 +000011
Jason Molendaa8399a82012-10-10 01:45:33 +000012#include "llvm-c/Disassembler.h"
Johnny Chen62212f02011-11-29 01:09:49 +000013#include "llvm/Support/TargetSelect.h"
Greg Claytondc5eb692011-04-25 18:36:36 +000014
Jason Molendafbcb7f22010-09-10 07:49:16 +000015#include "lldb/Core/Address.h"
16#include "lldb/Core/Error.h"
17#include "lldb/Core/ArchSpec.h"
18#include "lldb/Core/PluginManager.h"
Greg Claytondc5eb692011-04-25 18:36:36 +000019#include "lldb/Symbol/UnwindPlan.h"
Jason Molendafbcb7f22010-09-10 07:49:16 +000020#include "lldb/Target/ExecutionContext.h"
21#include "lldb/Target/Process.h"
22#include "lldb/Target/RegisterContext.h"
23#include "lldb/Target/Thread.h"
24#include "lldb/Target/Target.h"
Greg Clayton7be25422011-04-25 21:14:26 +000025#include "lldb/Target/UnwindAssembly.h"
Jason Molendafbcb7f22010-09-10 07:49:16 +000026
27using namespace lldb;
28using namespace lldb_private;
29
Jason Molenda7b967f12014-08-25 23:46:06 +000030enum CPU
Jason Molenda31e71912014-08-25 23:45:24 +000031{
Jason Molendafbcb7f22010-09-10 07:49:16 +000032 k_i386,
33 k_x86_64
34};
35
Jason Molenda7b967f12014-08-25 23:46:06 +000036enum i386_register_numbers
Jason Molenda31e71912014-08-25 23:45:24 +000037{
Jason Molendafbcb7f22010-09-10 07:49:16 +000038 k_machine_eax = 0,
39 k_machine_ecx = 1,
40 k_machine_edx = 2,
41 k_machine_ebx = 3,
42 k_machine_esp = 4,
43 k_machine_ebp = 5,
44 k_machine_esi = 6,
45 k_machine_edi = 7,
46 k_machine_eip = 8
47};
48
Jason Molenda7b967f12014-08-25 23:46:06 +000049enum x86_64_register_numbers
Jason Molenda31e71912014-08-25 23:45:24 +000050{
Jason Molendafbcb7f22010-09-10 07:49:16 +000051 k_machine_rax = 0,
52 k_machine_rcx = 1,
53 k_machine_rdx = 2,
54 k_machine_rbx = 3,
55 k_machine_rsp = 4,
56 k_machine_rbp = 5,
57 k_machine_rsi = 6,
58 k_machine_rdi = 7,
59 k_machine_r8 = 8,
60 k_machine_r9 = 9,
61 k_machine_r10 = 10,
62 k_machine_r11 = 11,
63 k_machine_r12 = 12,
64 k_machine_r13 = 13,
65 k_machine_r14 = 14,
66 k_machine_r15 = 15,
67 k_machine_rip = 16
68};
69
Jason Molenda7b967f12014-08-25 23:46:06 +000070struct regmap_ent
Jason Molenda31e71912014-08-25 23:45:24 +000071{
Jason Molendafbcb7f22010-09-10 07:49:16 +000072 const char *name;
73 int machine_regno;
74 int lldb_regno;
75};
76
Jason Molenda7b967f12014-08-25 23:46:06 +000077static struct regmap_ent i386_register_map[] =
Jason Molenda31e71912014-08-25 23:45:24 +000078{
Jason Molendafbcb7f22010-09-10 07:49:16 +000079 {"eax", k_machine_eax, -1},
80 {"ecx", k_machine_ecx, -1},
81 {"edx", k_machine_edx, -1},
82 {"ebx", k_machine_ebx, -1},
83 {"esp", k_machine_esp, -1},
84 {"ebp", k_machine_ebp, -1},
85 {"esi", k_machine_esi, -1},
86 {"edi", k_machine_edi, -1},
87 {"eip", k_machine_eip, -1}
88};
89
Jason Molenda31e71912014-08-25 23:45:24 +000090const int size_of_i386_register_map = llvm::array_lengthof (i386_register_map);
Jason Molendafbcb7f22010-09-10 07:49:16 +000091
92static int i386_register_map_initialized = 0;
93
Jason Molenda7b967f12014-08-25 23:46:06 +000094static struct regmap_ent x86_64_register_map[] =
Jason Molenda31e71912014-08-25 23:45:24 +000095{
Jason Molendafbcb7f22010-09-10 07:49:16 +000096 {"rax", k_machine_rax, -1},
97 {"rcx", k_machine_rcx, -1},
98 {"rdx", k_machine_rdx, -1},
99 {"rbx", k_machine_rbx, -1},
100 {"rsp", k_machine_rsp, -1},
101 {"rbp", k_machine_rbp, -1},
102 {"rsi", k_machine_rsi, -1},
103 {"rdi", k_machine_rdi, -1},
104 {"r8", k_machine_r8, -1},
105 {"r9", k_machine_r9, -1},
106 {"r10", k_machine_r10, -1},
107 {"r11", k_machine_r11, -1},
108 {"r12", k_machine_r12, -1},
109 {"r13", k_machine_r13, -1},
110 {"r14", k_machine_r14, -1},
111 {"r15", k_machine_r15, -1},
112 {"rip", k_machine_rip, -1}
113};
114
Jason Molenda31e71912014-08-25 23:45:24 +0000115const int size_of_x86_64_register_map = llvm::array_lengthof (x86_64_register_map);
Jason Molendafbcb7f22010-09-10 07:49:16 +0000116
117static int x86_64_register_map_initialized = 0;
118
119//-----------------------------------------------------------------------------------------------
120// AssemblyParse_x86 local-file class definition & implementation functions
121//-----------------------------------------------------------------------------------------------
122
Jason Molenda7b967f12014-08-25 23:46:06 +0000123class AssemblyParse_x86
Jason Molenda31e71912014-08-25 23:45:24 +0000124{
Jason Molendafbcb7f22010-09-10 07:49:16 +0000125public:
126
Jason Molendaa8399a82012-10-10 01:45:33 +0000127 AssemblyParse_x86 (const ExecutionContext &exe_ctx, int cpu, ArchSpec &arch, AddressRange func);
128
129 ~AssemblyParse_x86 ();
Jason Molendafbcb7f22010-09-10 07:49:16 +0000130
131 bool get_non_call_site_unwind_plan (UnwindPlan &unwind_plan);
132
Todd Fiala05625242014-08-25 20:29:09 +0000133 bool augment_unwind_plan_from_call_site (AddressRange& func, UnwindPlan &unwind_plan);
134
Jason Molendaab4f1922010-10-25 11:12:07 +0000135 bool get_fast_unwind_plan (AddressRange& func, UnwindPlan &unwind_plan);
Jason Molendafbcb7f22010-09-10 07:49:16 +0000136
137 bool find_first_non_prologue_insn (Address &address);
138
139private:
140 enum { kMaxInstructionByteSize = 32 };
141
142 bool nonvolatile_reg_p (int machine_regno);
143 bool push_rbp_pattern_p ();
144 bool push_0_pattern_p ();
145 bool mov_rsp_rbp_pattern_p ();
146 bool sub_rsp_pattern_p (int& amount);
Todd Fiala05625242014-08-25 20:29:09 +0000147 bool add_rsp_pattern_p (int& amount);
Jason Molendafbcb7f22010-09-10 07:49:16 +0000148 bool push_reg_p (int& regno);
Todd Fiala05625242014-08-25 20:29:09 +0000149 bool pop_reg_p (int& regno);
150 bool push_imm_pattern_p ();
Jason Molendafbcb7f22010-09-10 07:49:16 +0000151 bool mov_reg_to_local_stack_frame_p (int& regno, int& fp_offset);
152 bool ret_pattern_p ();
Todd Fiala05625242014-08-25 20:29:09 +0000153 bool pop_rbp_pattern_p ();
154 bool call_next_insn_pattern_p();
Jason Molendafbcb7f22010-09-10 07:49:16 +0000155 uint32_t extract_4 (uint8_t *b);
156 bool machine_regno_to_lldb_regno (int machine_regno, uint32_t& lldb_regno);
157 bool instruction_length (Address addr, int &length);
158
Greg Clayton1ac04c32012-02-21 00:09:25 +0000159 const ExecutionContext m_exe_ctx;
Jason Molendafbcb7f22010-09-10 07:49:16 +0000160
161 AddressRange m_func_bounds;
162
163 Address m_cur_insn;
164 uint8_t m_cur_insn_bytes[kMaxInstructionByteSize];
165
Todd Fiala05625242014-08-25 20:29:09 +0000166 uint32_t m_machine_ip_regnum;
167 uint32_t m_machine_sp_regnum;
168 uint32_t m_machine_fp_regnum;
Jason Molendafbcb7f22010-09-10 07:49:16 +0000169
Todd Fiala05625242014-08-25 20:29:09 +0000170 uint32_t m_lldb_ip_regnum;
171 uint32_t m_lldb_sp_regnum;
172 uint32_t m_lldb_fp_regnum;
Jason Molendafbcb7f22010-09-10 07:49:16 +0000173
174 int m_wordsize;
175 int m_cpu;
Jason Molendaa8399a82012-10-10 01:45:33 +0000176 ArchSpec m_arch;
177 ::LLVMDisasmContextRef m_disasm_context;
Jason Molendafa19c3e72010-11-04 09:40:56 +0000178
179 DISALLOW_COPY_AND_ASSIGN (AssemblyParse_x86);
Jason Molendafbcb7f22010-09-10 07:49:16 +0000180};
181
Jason Molendaa8399a82012-10-10 01:45:33 +0000182AssemblyParse_x86::AssemblyParse_x86 (const ExecutionContext &exe_ctx, int cpu, ArchSpec &arch, AddressRange func) :
Jason Molenda7b967f12014-08-25 23:46:06 +0000183 m_exe_ctx (exe_ctx),
184 m_func_bounds(func),
Greg Clayton1ac04c32012-02-21 00:09:25 +0000185 m_cur_insn (),
186 m_machine_ip_regnum (LLDB_INVALID_REGNUM),
187 m_machine_sp_regnum (LLDB_INVALID_REGNUM),
188 m_machine_fp_regnum (LLDB_INVALID_REGNUM),
Jason Molenda7b967f12014-08-25 23:46:06 +0000189 m_lldb_ip_regnum (LLDB_INVALID_REGNUM),
Greg Clayton1ac04c32012-02-21 00:09:25 +0000190 m_lldb_sp_regnum (LLDB_INVALID_REGNUM),
191 m_lldb_fp_regnum (LLDB_INVALID_REGNUM),
Jason Molenda7b967f12014-08-25 23:46:06 +0000192 m_wordsize (-1),
Jason Molendaa8399a82012-10-10 01:45:33 +0000193 m_cpu(cpu),
Jason Molenda22f2fff2012-10-11 06:04:37 +0000194 m_arch(arch)
Jason Molendaab4f1922010-10-25 11:12:07 +0000195{
Jason Molendafbcb7f22010-09-10 07:49:16 +0000196 int *initialized_flag = NULL;
Jason Molendafbcb7f22010-09-10 07:49:16 +0000197 if (cpu == k_i386)
198 {
199 m_machine_ip_regnum = k_machine_eip;
200 m_machine_sp_regnum = k_machine_esp;
201 m_machine_fp_regnum = k_machine_ebp;
202 m_wordsize = 4;
203 initialized_flag = &i386_register_map_initialized;
204 }
205 else
206 {
207 m_machine_ip_regnum = k_machine_rip;
208 m_machine_sp_regnum = k_machine_rsp;
209 m_machine_fp_regnum = k_machine_rbp;
210 m_wordsize = 8;
211 initialized_flag = &x86_64_register_map_initialized;
212 }
213
214 // we only look at prologue - it will be complete earlier than 512 bytes into func
215 if (m_func_bounds.GetByteSize() == 0)
216 m_func_bounds.SetByteSize(512);
217
Greg Clayton1ac04c32012-02-21 00:09:25 +0000218 Thread *thread = m_exe_ctx.GetThreadPtr();
219 if (thread && *initialized_flag == 0)
Jason Molendafbcb7f22010-09-10 07:49:16 +0000220 {
Greg Clayton1ac04c32012-02-21 00:09:25 +0000221 RegisterContext *reg_ctx = thread->GetRegisterContext().get();
Greg Clayton5ccbd292011-01-06 22:15:06 +0000222 if (reg_ctx)
Jason Molendafbcb7f22010-09-10 07:49:16 +0000223 {
224 struct regmap_ent *ent;
225 int count, i;
226 if (cpu == k_i386)
227 {
228 ent = i386_register_map;
229 count = size_of_i386_register_map;
230 }
231 else
232 {
233 ent = x86_64_register_map;
234 count = size_of_x86_64_register_map;
235 }
236 for (i = 0; i < count; i++, ent++)
237 {
Greg Clayton5ccbd292011-01-06 22:15:06 +0000238 const RegisterInfo *ri = reg_ctx->GetRegisterInfoByName (ent->name);
Jason Molendafbcb7f22010-09-10 07:49:16 +0000239 if (ri)
240 ent->lldb_regno = ri->kinds[eRegisterKindLLDB];
241 }
242 *initialized_flag = 1;
243 }
244 }
245
246 // on initial construction we may not have a Thread so these have to remain
247 // uninitialized until we can get a RegisterContext to set up the register map table
248 if (*initialized_flag == 1)
249 {
250 uint32_t lldb_regno;
251 if (machine_regno_to_lldb_regno (m_machine_sp_regnum, lldb_regno))
252 m_lldb_sp_regnum = lldb_regno;
253 if (machine_regno_to_lldb_regno (m_machine_fp_regnum, lldb_regno))
254 m_lldb_fp_regnum = lldb_regno;
255 if (machine_regno_to_lldb_regno (m_machine_ip_regnum, lldb_regno))
256 m_lldb_ip_regnum = lldb_regno;
257 }
Jason Molendaa8399a82012-10-10 01:45:33 +0000258
Jason Molenda7b967f12014-08-25 23:46:06 +0000259 m_disasm_context = ::LLVMCreateDisasm(m_arch.GetTriple().getTriple().c_str(),
260 (void*)this,
Jason Molendaa8399a82012-10-10 01:45:33 +0000261 /*TagType=*/1,
262 NULL,
263 NULL);
Jason Molendafbcb7f22010-09-10 07:49:16 +0000264}
265
Jason Molendaa8399a82012-10-10 01:45:33 +0000266AssemblyParse_x86::~AssemblyParse_x86 ()
267{
268 ::LLVMDisasmDispose(m_disasm_context);
269}
Jason Molendafbcb7f22010-09-10 07:49:16 +0000270
Jason Molenda7b967f12014-08-25 23:46:06 +0000271// This function expects an x86 native register number (i.e. the bits stripped out of the
Jason Molendafbcb7f22010-09-10 07:49:16 +0000272// actual instruction), not an lldb register number.
273
274bool
275AssemblyParse_x86::nonvolatile_reg_p (int machine_regno)
276{
277 if (m_cpu == k_i386)
278 {
Jason Molenda7b967f12014-08-25 23:46:06 +0000279 switch (machine_regno)
Jason Molenda31e71912014-08-25 23:45:24 +0000280 {
Jason Molendafbcb7f22010-09-10 07:49:16 +0000281 case k_machine_ebx:
282 case k_machine_ebp: // not actually a nonvolatile but often treated as such by convention
283 case k_machine_esi:
284 case k_machine_edi:
285 case k_machine_esp:
286 return true;
287 default:
288 return false;
289 }
290 }
291 if (m_cpu == k_x86_64)
292 {
Jason Molenda7b967f12014-08-25 23:46:06 +0000293 switch (machine_regno)
Jason Molenda31e71912014-08-25 23:45:24 +0000294 {
Jason Molendafbcb7f22010-09-10 07:49:16 +0000295 case k_machine_rbx:
296 case k_machine_rsp:
297 case k_machine_rbp: // not actually a nonvolatile but often treated as such by convention
298 case k_machine_r12:
299 case k_machine_r13:
300 case k_machine_r14:
301 case k_machine_r15:
302 return true;
303 default:
304 return false;
305 }
306 }
307 return false;
308}
309
310
Jason Molenda7b967f12014-08-25 23:46:06 +0000311// Macro to detect if this is a REX mode prefix byte.
Jason Molendafbcb7f22010-09-10 07:49:16 +0000312#define REX_W_PREFIX_P(opcode) (((opcode) & (~0x5)) == 0x48)
313
314// The high bit which should be added to the source register number (the "R" bit)
315#define REX_W_SRCREG(opcode) (((opcode) & 0x4) >> 2)
316
317// The high bit which should be added to the destination register number (the "B" bit)
318#define REX_W_DSTREG(opcode) ((opcode) & 0x1)
319
320// pushq %rbp [0x55]
Jason Molenda7b967f12014-08-25 23:46:06 +0000321bool AssemblyParse_x86::push_rbp_pattern_p ()
Jason Molenda31e71912014-08-25 23:45:24 +0000322{
Jason Molendafbcb7f22010-09-10 07:49:16 +0000323 uint8_t *p = m_cur_insn_bytes;
324 if (*p == 0x55)
325 return true;
326 return false;
327}
328
329// pushq $0 ; the first instruction in start() [0x6a 0x00]
330bool AssemblyParse_x86::push_0_pattern_p ()
331{
332 uint8_t *p = m_cur_insn_bytes;
333 if (*p == 0x6a && *(p + 1) == 0x0)
334 return true;
335 return false;
336}
337
Todd Fiala05625242014-08-25 20:29:09 +0000338// pushq $0
339// pushl $0
Jason Molenda7b967f12014-08-25 23:46:06 +0000340bool AssemblyParse_x86::push_imm_pattern_p ()
Jason Molenda31e71912014-08-25 23:45:24 +0000341{
Todd Fiala05625242014-08-25 20:29:09 +0000342 uint8_t *p = m_cur_insn_bytes;
343 if (*p == 0x68 || *p == 0x6a)
344 return true;
345 return false;
346}
347
Jason Molendafbcb7f22010-09-10 07:49:16 +0000348// movq %rsp, %rbp [0x48 0x8b 0xec] or [0x48 0x89 0xe5]
349// movl %esp, %ebp [0x8b 0xec] or [0x89 0xe5]
Jason Molenda7b967f12014-08-25 23:46:06 +0000350bool AssemblyParse_x86::mov_rsp_rbp_pattern_p ()
Jason Molenda31e71912014-08-25 23:45:24 +0000351{
Jason Molendafbcb7f22010-09-10 07:49:16 +0000352 uint8_t *p = m_cur_insn_bytes;
353 if (m_wordsize == 8 && *p == 0x48)
354 p++;
355 if (*(p) == 0x8b && *(p + 1) == 0xec)
356 return true;
357 if (*(p) == 0x89 && *(p + 1) == 0xe5)
358 return true;
359 return false;
360}
361
Jason Molenda7b967f12014-08-25 23:46:06 +0000362// subq $0x20, %rsp
363bool AssemblyParse_x86::sub_rsp_pattern_p (int& amount)
Jason Molenda31e71912014-08-25 23:45:24 +0000364{
Jason Molendafbcb7f22010-09-10 07:49:16 +0000365 uint8_t *p = m_cur_insn_bytes;
366 if (m_wordsize == 8 && *p == 0x48)
367 p++;
368 // 8-bit immediate operand
Jason Molenda7b967f12014-08-25 23:46:06 +0000369 if (*p == 0x83 && *(p + 1) == 0xec)
Jason Molenda31e71912014-08-25 23:45:24 +0000370 {
Jason Molendafbcb7f22010-09-10 07:49:16 +0000371 amount = (int8_t) *(p + 2);
372 return true;
373 }
374 // 32-bit immediate operand
Jason Molenda7b967f12014-08-25 23:46:06 +0000375 if (*p == 0x81 && *(p + 1) == 0xec)
Jason Molenda31e71912014-08-25 23:45:24 +0000376 {
Jason Molendafbcb7f22010-09-10 07:49:16 +0000377 amount = (int32_t) extract_4 (p + 2);
378 return true;
379 }
Todd Fiala05625242014-08-25 20:29:09 +0000380 return false;
381}
382
Jason Molenda7b967f12014-08-25 23:46:06 +0000383// addq $0x20, %rsp
384bool AssemblyParse_x86::add_rsp_pattern_p (int& amount)
Jason Molenda31e71912014-08-25 23:45:24 +0000385{
Todd Fiala05625242014-08-25 20:29:09 +0000386 uint8_t *p = m_cur_insn_bytes;
387 if (m_wordsize == 8 && *p == 0x48)
388 p++;
389 // 8-bit immediate operand
Jason Molenda7b967f12014-08-25 23:46:06 +0000390 if (*p == 0x83 && *(p + 1) == 0xc4)
Jason Molenda31e71912014-08-25 23:45:24 +0000391 {
Todd Fiala05625242014-08-25 20:29:09 +0000392 amount = (int8_t) *(p + 2);
393 return true;
394 }
395 // 32-bit immediate operand
Jason Molenda7b967f12014-08-25 23:46:06 +0000396 if (*p == 0x81 && *(p + 1) == 0xc4)
Jason Molenda31e71912014-08-25 23:45:24 +0000397 {
Todd Fiala05625242014-08-25 20:29:09 +0000398 amount = (int32_t) extract_4 (p + 2);
399 return true;
400 }
Jason Molendafbcb7f22010-09-10 07:49:16 +0000401 return false;
402}
403
404// pushq %rbx
Todd Fiala05625242014-08-25 20:29:09 +0000405// pushl %ebx
Jason Molenda7b967f12014-08-25 23:46:06 +0000406bool AssemblyParse_x86::push_reg_p (int& regno)
Jason Molenda31e71912014-08-25 23:45:24 +0000407{
Jason Molendafbcb7f22010-09-10 07:49:16 +0000408 uint8_t *p = m_cur_insn_bytes;
409 int regno_prefix_bit = 0;
410 // If we have a rex prefix byte, check to see if a B bit is set
Jason Molenda7b967f12014-08-25 23:46:06 +0000411 if (m_wordsize == 8 && *p == 0x41)
Jason Molenda31e71912014-08-25 23:45:24 +0000412 {
Jason Molendafbcb7f22010-09-10 07:49:16 +0000413 regno_prefix_bit = 1 << 3;
414 p++;
415 }
Jason Molenda7b967f12014-08-25 23:46:06 +0000416 if (*p >= 0x50 && *p <= 0x57)
Jason Molenda31e71912014-08-25 23:45:24 +0000417 {
Jason Molendafbcb7f22010-09-10 07:49:16 +0000418 regno = (*p - 0x50) | regno_prefix_bit;
419 return true;
420 }
421 return false;
422}
423
Todd Fiala05625242014-08-25 20:29:09 +0000424// popq %rbx
425// popl %ebx
Jason Molenda7b967f12014-08-25 23:46:06 +0000426bool AssemblyParse_x86::pop_reg_p (int& regno)
Jason Molenda31e71912014-08-25 23:45:24 +0000427{
Todd Fiala05625242014-08-25 20:29:09 +0000428 uint8_t *p = m_cur_insn_bytes;
429 int regno_prefix_bit = 0;
430 // If we have a rex prefix byte, check to see if a B bit is set
Jason Molenda7b967f12014-08-25 23:46:06 +0000431 if (m_wordsize == 8 && *p == 0x41)
Jason Molenda31e71912014-08-25 23:45:24 +0000432 {
Todd Fiala05625242014-08-25 20:29:09 +0000433 regno_prefix_bit = 1 << 3;
434 p++;
435 }
Jason Molenda7b967f12014-08-25 23:46:06 +0000436 if (*p >= 0x58 && *p <= 0x5f)
Jason Molenda31e71912014-08-25 23:45:24 +0000437 {
Todd Fiala05625242014-08-25 20:29:09 +0000438 regno = (*p - 0x58) | regno_prefix_bit;
439 return true;
440 }
441 return false;
442}
443
444// popq %rbp [0x5d]
445// popl %ebp [0x5d]
Jason Molenda7b967f12014-08-25 23:46:06 +0000446bool AssemblyParse_x86::pop_rbp_pattern_p ()
Jason Molenda31e71912014-08-25 23:45:24 +0000447{
Todd Fiala05625242014-08-25 20:29:09 +0000448 uint8_t *p = m_cur_insn_bytes;
449 return (*p == 0x5d);
450}
451
452// call $0 [0xe8 0x0 0x0 0x0 0x0]
Jason Molenda7b967f12014-08-25 23:46:06 +0000453bool AssemblyParse_x86::call_next_insn_pattern_p ()
Jason Molenda31e71912014-08-25 23:45:24 +0000454{
Todd Fiala05625242014-08-25 20:29:09 +0000455 uint8_t *p = m_cur_insn_bytes;
456 return (*p == 0xe8) && (*(p+1) == 0x0) && (*(p+2) == 0x0)
457 && (*(p+3) == 0x0) && (*(p+4) == 0x0);
458}
459
Jason Molendafbcb7f22010-09-10 07:49:16 +0000460// Look for an instruction sequence storing a nonvolatile register
461// on to the stack frame.
462
463// movq %rax, -0x10(%rbp) [0x48 0x89 0x45 0xf0]
464// movl %eax, -0xc(%ebp) [0x89 0x45 0xf4]
Todd Fialad9474062014-07-25 01:15:34 +0000465
Jason Molenda7b967f12014-08-25 23:46:06 +0000466// The offset value returned in rbp_offset will be positive --
Todd Fialad9474062014-07-25 01:15:34 +0000467// but it must be subtraced from the frame base register to get
468// the actual location. The positive value returned for the offset
469// is a convention used elsewhere for CFA offsets et al.
470
Jason Molenda7b967f12014-08-25 23:46:06 +0000471bool AssemblyParse_x86::mov_reg_to_local_stack_frame_p (int& regno, int& rbp_offset)
Jason Molenda31e71912014-08-25 23:45:24 +0000472{
Jason Molendafbcb7f22010-09-10 07:49:16 +0000473 uint8_t *p = m_cur_insn_bytes;
474 int src_reg_prefix_bit = 0;
475 int target_reg_prefix_bit = 0;
476
Jason Molenda7b967f12014-08-25 23:46:06 +0000477 if (m_wordsize == 8 && REX_W_PREFIX_P (*p))
Jason Molenda31e71912014-08-25 23:45:24 +0000478 {
Jason Molendafbcb7f22010-09-10 07:49:16 +0000479 src_reg_prefix_bit = REX_W_SRCREG (*p) << 3;
480 target_reg_prefix_bit = REX_W_DSTREG (*p) << 3;
Jason Molenda7b967f12014-08-25 23:46:06 +0000481 if (target_reg_prefix_bit == 1)
Jason Molenda31e71912014-08-25 23:45:24 +0000482 {
Jason Molendafbcb7f22010-09-10 07:49:16 +0000483 // rbp/ebp don't need a prefix bit - we know this isn't the
484 // reg we care about.
485 return false;
486 }
487 p++;
488 }
489
Jason Molenda7b967f12014-08-25 23:46:06 +0000490 if (*p == 0x89)
Jason Molenda31e71912014-08-25 23:45:24 +0000491 {
Jason Molendafbcb7f22010-09-10 07:49:16 +0000492 /* Mask off the 3-5 bits which indicate the destination register
493 if this is a ModR/M byte. */
494 int opcode_destreg_masked_out = *(p + 1) & (~0x38);
495
Jason Molenda7b967f12014-08-25 23:46:06 +0000496 /* Is this a ModR/M byte with Mod bits 01 and R/M bits 101
Jason Molendafbcb7f22010-09-10 07:49:16 +0000497 and three bits between them, e.g. 01nnn101
498 We're looking for a destination of ebp-disp8 or ebp-disp32. */
499 int immsize;
500 if (opcode_destreg_masked_out == 0x45)
501 immsize = 2;
502 else if (opcode_destreg_masked_out == 0x85)
503 immsize = 4;
504 else
505 return false;
506
507 int offset = 0;
508 if (immsize == 2)
509 offset = (int8_t) *(p + 2);
510 if (immsize == 4)
511 offset = (uint32_t) extract_4 (p + 2);
512 if (offset > 0)
513 return false;
514
515 regno = ((*(p + 1) >> 3) & 0x7) | src_reg_prefix_bit;
516 rbp_offset = offset > 0 ? offset : -offset;
517 return true;
518 }
519 return false;
520}
521
522// ret [0xc9] or [0xc2 imm8] or [0xca imm8]
Jason Molenda7b967f12014-08-25 23:46:06 +0000523bool
524AssemblyParse_x86::ret_pattern_p ()
Jason Molendafbcb7f22010-09-10 07:49:16 +0000525{
526 uint8_t *p = m_cur_insn_bytes;
527 if (*p == 0xc9 || *p == 0xc2 || *p == 0xca || *p == 0xc3)
528 return true;
529 return false;
530}
531
532uint32_t
533AssemblyParse_x86::extract_4 (uint8_t *b)
534{
535 uint32_t v = 0;
536 for (int i = 3; i >= 0; i--)
537 v = (v << 8) | b[i];
538 return v;
539}
540
Jason Molenda7b967f12014-08-25 23:46:06 +0000541bool
Jason Molendafbcb7f22010-09-10 07:49:16 +0000542AssemblyParse_x86::machine_regno_to_lldb_regno (int machine_regno, uint32_t &lldb_regno)
543{
544 struct regmap_ent *ent;
545 int count, i;
546 if (m_cpu == k_i386)
547 {
548 ent = i386_register_map;
549 count = size_of_i386_register_map;
550 }
551 else
552 {
553 ent = x86_64_register_map;
554 count = size_of_x86_64_register_map;
555 }
556 for (i = 0; i < count; i++, ent++)
557 {
558 if (ent->machine_regno == machine_regno)
559 if (ent->lldb_regno != -1)
560 {
561 lldb_regno = ent->lldb_regno;
562 return true;
563 }
564 }
565 return false;
566}
567
Jason Molendafbcb7f22010-09-10 07:49:16 +0000568bool
569AssemblyParse_x86::instruction_length (Address addr, int &length)
570{
Jason Molendaa8399a82012-10-10 01:45:33 +0000571 const uint32_t max_op_byte_size = m_arch.GetMaximumOpcodeByteSize();
Jason Molenda22f2fff2012-10-11 06:04:37 +0000572 llvm::SmallVector <uint8_t, 32> opcode_data;
573 opcode_data.resize (max_op_byte_size);
Jason Molenda59762002010-11-04 00:53:20 +0000574
575 if (!addr.IsValid())
576 return false;
577
Jason Molendaa8399a82012-10-10 01:45:33 +0000578 const bool prefer_file_cache = true;
579 Error error;
580 Target *target = m_exe_ctx.GetTargetPtr();
Saleem Abdulrasool3985c8c2014-04-02 03:51:35 +0000581 if (target->ReadMemory (addr, prefer_file_cache, opcode_data.data(),
582 max_op_byte_size, error) == static_cast<size_t>(-1))
Jason Molendafbcb7f22010-09-10 07:49:16 +0000583 {
Jason Molendaab4f1922010-10-25 11:12:07 +0000584 return false;
Jason Molendafbcb7f22010-09-10 07:49:16 +0000585 }
Jason Molenda7b967f12014-08-25 23:46:06 +0000586
Jason Molendaa8399a82012-10-10 01:45:33 +0000587 char out_string[512];
588 const addr_t pc = addr.GetFileAddress();
589 const size_t inst_size = ::LLVMDisasmInstruction (m_disasm_context,
Jason Molenda22f2fff2012-10-11 06:04:37 +0000590 opcode_data.data(),
Jason Molendaa8399a82012-10-10 01:45:33 +0000591 max_op_byte_size,
592 pc, // PC value
593 out_string,
594 sizeof(out_string));
595
596 length = inst_size;
Jason Molendafbcb7f22010-09-10 07:49:16 +0000597 return true;
598}
599
600
Jason Molenda7b967f12014-08-25 23:46:06 +0000601bool
Jason Molendafbcb7f22010-09-10 07:49:16 +0000602AssemblyParse_x86::get_non_call_site_unwind_plan (UnwindPlan &unwind_plan)
603{
Jason Molenda1d42c7b2012-07-14 04:52:53 +0000604 UnwindPlan::RowSP row(new UnwindPlan::Row);
Jason Molendafbcb7f22010-09-10 07:49:16 +0000605 int non_prologue_insn_count = 0;
Jason Molenda59762002010-11-04 00:53:20 +0000606 m_cur_insn = m_func_bounds.GetBaseAddress ();
Jason Molendafbcb7f22010-09-10 07:49:16 +0000607 int current_func_text_offset = 0;
608 int current_sp_bytes_offset_from_cfa = 0;
Jason Molendafa19c3e72010-11-04 09:40:56 +0000609 UnwindPlan::Row::RegisterLocation initial_regloc;
Jason Molenda59203332010-11-16 03:01:20 +0000610 Error error;
Jason Molendafbcb7f22010-09-10 07:49:16 +0000611
Jason Molenda59762002010-11-04 00:53:20 +0000612 if (!m_cur_insn.IsValid())
613 {
614 return false;
615 }
616
Jason Molendafbcb7f22010-09-10 07:49:16 +0000617 unwind_plan.SetPlanValidAddressRange (m_func_bounds);
618 unwind_plan.SetRegisterKind (eRegisterKindLLDB);
619
620 // At the start of the function, find the CFA by adding wordsize to the SP register
Jason Molenda1d42c7b2012-07-14 04:52:53 +0000621 row->SetOffset (current_func_text_offset);
622 row->SetCFARegister (m_lldb_sp_regnum);
623 row->SetCFAOffset (m_wordsize);
Jason Molendafbcb7f22010-09-10 07:49:16 +0000624
625 // caller's stack pointer value before the call insn is the CFA address
Jason Molendafa19c3e72010-11-04 09:40:56 +0000626 initial_regloc.SetIsCFAPlusOffset (0);
Jason Molenda1d42c7b2012-07-14 04:52:53 +0000627 row->SetRegisterInfo (m_lldb_sp_regnum, initial_regloc);
Jason Molendafbcb7f22010-09-10 07:49:16 +0000628
629 // saved instruction pointer can be found at CFA - wordsize.
630 current_sp_bytes_offset_from_cfa = m_wordsize;
Jason Molendafa19c3e72010-11-04 09:40:56 +0000631 initial_regloc.SetAtCFAPlusOffset (-current_sp_bytes_offset_from_cfa);
Jason Molenda1d42c7b2012-07-14 04:52:53 +0000632 row->SetRegisterInfo (m_lldb_ip_regnum, initial_regloc);
Jason Molendafbcb7f22010-09-10 07:49:16 +0000633
634 unwind_plan.AppendRow (row);
Jason Molenda1d42c7b2012-07-14 04:52:53 +0000635
636 // Allocate a new Row, populate it with the existing Row contents.
637 UnwindPlan::Row *newrow = new UnwindPlan::Row;
638 *newrow = *row.get();
639 row.reset(newrow);
640
Greg Claytondb598232011-01-07 01:57:07 +0000641 const bool prefer_file_cache = true;
Jason Molendafbcb7f22010-09-10 07:49:16 +0000642
Greg Clayton1ac04c32012-02-21 00:09:25 +0000643 Target *target = m_exe_ctx.GetTargetPtr();
Jason Molendafbcb7f22010-09-10 07:49:16 +0000644 while (m_func_bounds.ContainsFileAddress (m_cur_insn) && non_prologue_insn_count < 10)
645 {
646 int stack_offset, insn_len;
647 int machine_regno; // register numbers masked directly out of instructions
648 uint32_t lldb_regno; // register numbers in lldb's eRegisterKindLLDB numbering scheme
Jason Molendafbcb7f22010-09-10 07:49:16 +0000649
650 if (!instruction_length (m_cur_insn, insn_len) || insn_len == 0 || insn_len > kMaxInstructionByteSize)
651 {
652 // An unrecognized/junk instruction
653 break;
654 }
Saleem Abdulrasool3985c8c2014-04-02 03:51:35 +0000655 if (target->ReadMemory (m_cur_insn, prefer_file_cache, m_cur_insn_bytes,
656 insn_len, error) == static_cast<size_t>(-1))
Jason Molendafbcb7f22010-09-10 07:49:16 +0000657 {
658 // Error reading the instruction out of the file, stop scanning
659 break;
660 }
661
662 if (push_rbp_pattern_p ())
663 {
Jason Molenda1d42c7b2012-07-14 04:52:53 +0000664 row->SetOffset (current_func_text_offset + insn_len);
Jason Molendafbcb7f22010-09-10 07:49:16 +0000665 current_sp_bytes_offset_from_cfa += m_wordsize;
Jason Molenda1d42c7b2012-07-14 04:52:53 +0000666 row->SetCFAOffset (current_sp_bytes_offset_from_cfa);
Jason Molendafbcb7f22010-09-10 07:49:16 +0000667 UnwindPlan::Row::RegisterLocation regloc;
Jason Molenda1d42c7b2012-07-14 04:52:53 +0000668 regloc.SetAtCFAPlusOffset (-row->GetCFAOffset());
669 row->SetRegisterInfo (m_lldb_fp_regnum, regloc);
Jason Molendafbcb7f22010-09-10 07:49:16 +0000670 unwind_plan.AppendRow (row);
Jason Molenda1d42c7b2012-07-14 04:52:53 +0000671 // Allocate a new Row, populate it with the existing Row contents.
672 newrow = new UnwindPlan::Row;
673 *newrow = *row.get();
674 row.reset(newrow);
Jason Molendafbcb7f22010-09-10 07:49:16 +0000675 goto loopnext;
676 }
Jason Molenda5c01cb62010-10-26 00:47:17 +0000677
678 if (mov_rsp_rbp_pattern_p ())
679 {
Jason Molenda1d42c7b2012-07-14 04:52:53 +0000680 row->SetOffset (current_func_text_offset + insn_len);
681 row->SetCFARegister (m_lldb_fp_regnum);
Jason Molenda5c01cb62010-10-26 00:47:17 +0000682 unwind_plan.AppendRow (row);
Jason Molenda1d42c7b2012-07-14 04:52:53 +0000683 // Allocate a new Row, populate it with the existing Row contents.
684 newrow = new UnwindPlan::Row;
685 *newrow = *row.get();
686 row.reset(newrow);
Jason Molenda5c01cb62010-10-26 00:47:17 +0000687 goto loopnext;
688 }
689
Jason Molendaab4f1922010-10-25 11:12:07 +0000690 // This is the start() function (or a pthread equivalent), it starts with a pushl $0x0 which puts the
691 // saved pc value of 0 on the stack. In this case we want to pretend we didn't see a stack movement at all --
692 // normally the saved pc value is already on the stack by the time the function starts executing.
Jason Molendafbcb7f22010-09-10 07:49:16 +0000693 if (push_0_pattern_p ())
694 {
Jason Molendafbcb7f22010-09-10 07:49:16 +0000695 goto loopnext;
696 }
697
698 if (push_reg_p (machine_regno))
699 {
700 current_sp_bytes_offset_from_cfa += m_wordsize;
Jason Molenda378a4622013-09-24 03:28:54 +0000701 bool need_to_push_row = false;
702 // the PUSH instruction has moved the stack pointer - if the CFA is set in terms of the stack pointer,
703 // we need to add a new row of instructions.
Todd Fiala05625242014-08-25 20:29:09 +0000704 if (row->GetCFARegister() == m_lldb_sp_regnum)
Jason Molenda378a4622013-09-24 03:28:54 +0000705 {
706 need_to_push_row = true;
707 row->SetCFAOffset (current_sp_bytes_offset_from_cfa);
708 }
709 // record where non-volatile (callee-saved, spilled) registers are saved on the stack
Jason Molendafbcb7f22010-09-10 07:49:16 +0000710 if (nonvolatile_reg_p (machine_regno) && machine_regno_to_lldb_regno (machine_regno, lldb_regno))
711 {
Jason Molenda378a4622013-09-24 03:28:54 +0000712 need_to_push_row = true;
Jason Molendafbcb7f22010-09-10 07:49:16 +0000713 UnwindPlan::Row::RegisterLocation regloc;
714 regloc.SetAtCFAPlusOffset (-current_sp_bytes_offset_from_cfa);
Jason Molenda1d42c7b2012-07-14 04:52:53 +0000715 row->SetRegisterInfo (lldb_regno, regloc);
Jason Molenda378a4622013-09-24 03:28:54 +0000716 }
717 if (need_to_push_row)
718 {
719 row->SetOffset (current_func_text_offset + insn_len);
Jason Molendafbcb7f22010-09-10 07:49:16 +0000720 unwind_plan.AppendRow (row);
Jason Molenda1d42c7b2012-07-14 04:52:53 +0000721 // Allocate a new Row, populate it with the existing Row contents.
722 newrow = new UnwindPlan::Row;
723 *newrow = *row.get();
724 row.reset(newrow);
Jason Molendafbcb7f22010-09-10 07:49:16 +0000725 }
726 goto loopnext;
727 }
728
729 if (mov_reg_to_local_stack_frame_p (machine_regno, stack_offset) && nonvolatile_reg_p (machine_regno))
730 {
731 if (machine_regno_to_lldb_regno (machine_regno, lldb_regno))
732 {
Jason Molenda1d42c7b2012-07-14 04:52:53 +0000733 row->SetOffset (current_func_text_offset + insn_len);
Jason Molendafbcb7f22010-09-10 07:49:16 +0000734 UnwindPlan::Row::RegisterLocation regloc;
Todd Fialad9474062014-07-25 01:15:34 +0000735
736 // stack_offset for 'movq %r15, -80(%rbp)' will be 80.
737 // In the Row, we want to express this as the offset from the CFA. If the frame base
738 // is rbp (like the above instruction), the CFA offset for rbp is probably 16. So we
739 // want to say that the value is stored at the CFA address - 96.
740 regloc.SetAtCFAPlusOffset (-(stack_offset + row->GetCFAOffset()));
741
Jason Molenda1d42c7b2012-07-14 04:52:53 +0000742 row->SetRegisterInfo (lldb_regno, regloc);
Jason Molendafbcb7f22010-09-10 07:49:16 +0000743 unwind_plan.AppendRow (row);
Jason Molenda1d42c7b2012-07-14 04:52:53 +0000744 // Allocate a new Row, populate it with the existing Row contents.
745 newrow = new UnwindPlan::Row;
746 *newrow = *row.get();
747 row.reset(newrow);
Jason Molendafbcb7f22010-09-10 07:49:16 +0000748 goto loopnext;
749 }
750 }
751
752 if (sub_rsp_pattern_p (stack_offset))
753 {
754 current_sp_bytes_offset_from_cfa += stack_offset;
Todd Fiala05625242014-08-25 20:29:09 +0000755 if (row->GetCFARegister() == m_lldb_sp_regnum)
Jason Molendafbcb7f22010-09-10 07:49:16 +0000756 {
Jason Molenda1d42c7b2012-07-14 04:52:53 +0000757 row->SetOffset (current_func_text_offset + insn_len);
758 row->SetCFAOffset (current_sp_bytes_offset_from_cfa);
Jason Molendafbcb7f22010-09-10 07:49:16 +0000759 unwind_plan.AppendRow (row);
Jason Molenda1d42c7b2012-07-14 04:52:53 +0000760 // Allocate a new Row, populate it with the existing Row contents.
761 newrow = new UnwindPlan::Row;
762 *newrow = *row.get();
763 row.reset(newrow);
Jason Molendafbcb7f22010-09-10 07:49:16 +0000764 }
765 goto loopnext;
766 }
767
Jason Molendafbcb7f22010-09-10 07:49:16 +0000768 if (ret_pattern_p ())
769 {
770 // we know where the end of the function is; set the limit on the PlanValidAddressRange
771 // in case our initial "high pc" value was overly large
772 // int original_size = m_func_bounds.GetByteSize();
773 // int calculated_size = m_cur_insn.GetOffset() - m_func_bounds.GetBaseAddress().GetOffset() + insn_len + 1;
774 // m_func_bounds.SetByteSize (calculated_size);
775 // unwind_plan.SetPlanValidAddressRange (m_func_bounds);
776 break;
777 }
778
779 // FIXME recognize the i386 picbase setup instruction sequence,
780 // 0x1f16: call 0x1f1b ; main + 11 at /private/tmp/a.c:3
781 // 0x1f1b: popl %eax
782 // and record the temporary stack movements if the CFA is not expressed in terms of ebp.
783
784 non_prologue_insn_count++;
785loopnext:
786 m_cur_insn.SetOffset (m_cur_insn.GetOffset() + insn_len);
787 current_func_text_offset += insn_len;
788 }
Jason Molenda7b967f12014-08-25 23:46:06 +0000789
Jason Molenda59203332010-11-16 03:01:20 +0000790 // Now look at the byte at the end of the AddressRange for a limited attempt at describing the
Jason Molenda6f5e8c22012-05-25 01:54:06 +0000791 // epilogue. We're looking for the sequence
Jason Molenda59203332010-11-16 03:01:20 +0000792
Jason Molenda300dfcd2014-08-04 21:26:55 +0000793 // [ 0x5d ] mov %rbp, %rsp (aka pop %rbp)
794 // [ 0xc3 ] ret
795
796 // or
797
798 // [ 0x5d ] mov %rbp, %rsp (aka pop %rbp)
799 // [ 0xe9 xx xx xx xx ] jmp objc_retainAutoreleaseReturnValue (this is sometimes the final insn in the function)
800
801 // or
802
803 // [ 0x5d ] mov %rbp, %rsp (aka pop %rbp)
Jason Molenda6f5e8c22012-05-25 01:54:06 +0000804 // [ 0xc3 ] ret
805 // [ 0xe8 xx xx xx xx ] call __stack_chk_fail (this is sometimes the final insn in the function)
806
Jason Molenda8030ffd2014-11-04 05:48:11 +0000807 // or
808
809 // [ 0x5d ] mov %rbp, %rsp (aka pop %rbp)
810 // [ 0xc3 ] ret
811 // [ 0x0f 0x1f 0x44 xx xx ] nopl (%rax,%rax) (aka nop)
812
Jason Molenda6f5e8c22012-05-25 01:54:06 +0000813 // We want to add a Row describing how to unwind when we're stopped on the 'ret' instruction where the
814 // CFA is no longer defined in terms of rbp, but is now defined in terms of rsp like on function entry.
Jason Molenda300dfcd2014-08-04 21:26:55 +0000815 // (or the 'jmp' instruction in the second case)
Jason Molenda6f5e8c22012-05-25 01:54:06 +0000816
817 uint64_t ret_insn_offset = LLDB_INVALID_ADDRESS;
818 Address end_of_fun(m_func_bounds.GetBaseAddress());
819 end_of_fun.SetOffset (end_of_fun.GetOffset() + m_func_bounds.GetByteSize());
Jason Molenda300dfcd2014-08-04 21:26:55 +0000820
Jason Molenda6f5e8c22012-05-25 01:54:06 +0000821 if (m_func_bounds.GetByteSize() > 7)
Jason Molenda59203332010-11-16 03:01:20 +0000822 {
Jason Molenda6f5e8c22012-05-25 01:54:06 +0000823 uint8_t bytebuf[7];
824 Address last_seven_bytes(end_of_fun);
825 last_seven_bytes.SetOffset (last_seven_bytes.GetOffset() - 7);
Saleem Abdulrasool3985c8c2014-04-02 03:51:35 +0000826 if (target->ReadMemory (last_seven_bytes, prefer_file_cache, bytebuf, 7,
827 error) != static_cast<size_t>(-1))
Jason Molenda59203332010-11-16 03:01:20 +0000828 {
Jason Molenda300dfcd2014-08-04 21:26:55 +0000829 if (bytebuf[5] == 0x5d && bytebuf[6] == 0xc3) // mov & ret
Jason Molenda59203332010-11-16 03:01:20 +0000830 {
Jason Molenda6f5e8c22012-05-25 01:54:06 +0000831 ret_insn_offset = m_func_bounds.GetByteSize() - 1;
832 }
Jason Molenda300dfcd2014-08-04 21:26:55 +0000833 else if (bytebuf[1] == 0x5d && bytebuf[2] == 0xe9) // mov & jmp
834 {
835 // When the pc is sitting on the 'jmp' instruction, we have the same
836 // unwind state as if it was sitting on a 'ret' instruction.
837 ret_insn_offset = m_func_bounds.GetByteSize() - 5;
838 }
839 else if (bytebuf[0] == 0x5d && bytebuf[1] == 0xc3 && bytebuf[2] == 0xe8) // mov & ret & call
Jason Molenda6f5e8c22012-05-25 01:54:06 +0000840 {
841 ret_insn_offset = m_func_bounds.GetByteSize() - 6;
Jason Molenda59203332010-11-16 03:01:20 +0000842 }
Zachary Turnerba80da62014-11-10 22:31:51 +0000843 else if (bytebuf[0] == 0x5d && bytebuf[1] == 0xc3
844 && bytebuf[2] == 0x0f && bytebuf[3] == 0x1f && bytebuf[4] == 0x44) // mov & ret & nop
Jason Molenda8030ffd2014-11-04 05:48:11 +0000845 {
846 ret_insn_offset = m_func_bounds.GetByteSize() - 6;
847 }
Jason Molenda59203332010-11-16 03:01:20 +0000848 }
Jason Molenda300dfcd2014-08-04 21:26:55 +0000849 }
850 else if (m_func_bounds.GetByteSize() > 2)
Jason Molenda6f5e8c22012-05-25 01:54:06 +0000851 {
852 uint8_t bytebuf[2];
853 Address last_two_bytes(end_of_fun);
854 last_two_bytes.SetOffset (last_two_bytes.GetOffset() - 2);
Saleem Abdulrasool3985c8c2014-04-02 03:51:35 +0000855 if (target->ReadMemory (last_two_bytes, prefer_file_cache, bytebuf, 2,
856 error) != static_cast<size_t>(-1))
Jason Molenda6f5e8c22012-05-25 01:54:06 +0000857 {
Jason Molenda300dfcd2014-08-04 21:26:55 +0000858 if (bytebuf[0] == 0x5d && bytebuf[1] == 0xc3) // mov & ret
Jason Molenda6f5e8c22012-05-25 01:54:06 +0000859 {
860 ret_insn_offset = m_func_bounds.GetByteSize() - 1;
861 }
862 }
863 }
864
865 if (ret_insn_offset != LLDB_INVALID_ADDRESS)
866 {
867 // Create a fresh, empty Row and RegisterLocation - don't mention any other registers
Jason Molenda1d42c7b2012-07-14 04:52:53 +0000868 UnwindPlan::RowSP epi_row(new UnwindPlan::Row);
Jason Molenda6f5e8c22012-05-25 01:54:06 +0000869 UnwindPlan::Row::RegisterLocation epi_regloc;
870
871 // When the ret instruction is about to be executed, here's our state
Jason Molenda1d42c7b2012-07-14 04:52:53 +0000872 epi_row->SetOffset (ret_insn_offset);
873 epi_row->SetCFARegister (m_lldb_sp_regnum);
874 epi_row->SetCFAOffset (m_wordsize);
Jason Molenda7b967f12014-08-25 23:46:06 +0000875
Jason Molenda6f5e8c22012-05-25 01:54:06 +0000876 // caller's stack pointer value before the call insn is the CFA address
877 epi_regloc.SetIsCFAPlusOffset (0);
Jason Molenda1d42c7b2012-07-14 04:52:53 +0000878 epi_row->SetRegisterInfo (m_lldb_sp_regnum, epi_regloc);
Jason Molenda6f5e8c22012-05-25 01:54:06 +0000879
880 // saved instruction pointer can be found at CFA - wordsize
881 epi_regloc.SetAtCFAPlusOffset (-m_wordsize);
Jason Molenda1d42c7b2012-07-14 04:52:53 +0000882 epi_row->SetRegisterInfo (m_lldb_ip_regnum, epi_regloc);
Jason Molenda6f5e8c22012-05-25 01:54:06 +0000883
884 unwind_plan.AppendRow (epi_row);
Jason Molenda59203332010-11-16 03:01:20 +0000885 }
Jason Molenda7b967f12014-08-25 23:46:06 +0000886
Jason Molendaab4f1922010-10-25 11:12:07 +0000887 unwind_plan.SetSourceName ("assembly insn profiling");
Jason Molenda60f0bd42012-10-26 06:08:58 +0000888 unwind_plan.SetSourcedFromCompiler (eLazyBoolNo);
889 unwind_plan.SetUnwindPlanValidAtAllInstructions (eLazyBoolYes);
Jason Molendaab4f1922010-10-25 11:12:07 +0000890
Jason Molendafbcb7f22010-09-10 07:49:16 +0000891 return true;
892}
893
Todd Fiala05625242014-08-25 20:29:09 +0000894bool
895AssemblyParse_x86::augment_unwind_plan_from_call_site (AddressRange& func, UnwindPlan &unwind_plan)
896{
897 // Is func address valid?
898 Address addr_start = func.GetBaseAddress();
899 if (!addr_start.IsValid())
900 return false;
901
902 // Is original unwind_plan valid?
903 // unwind_plan should have at least one row which is ABI-default (CFA register is sp),
904 // and another row in mid-function.
905 if (unwind_plan.GetRowCount() < 2)
906 return false;
907 UnwindPlan::RowSP first_row = unwind_plan.GetRowAtIndex (0);
908 if (first_row->GetOffset() != 0)
909 return false;
910 uint32_t cfa_reg = m_exe_ctx.GetThreadPtr()->GetRegisterContext()
911 ->ConvertRegisterKindToRegisterNumber (unwind_plan.GetRegisterKind(),
912 first_row->GetCFARegister());
913 if (cfa_reg != m_lldb_sp_regnum || first_row->GetCFAOffset() != m_wordsize)
914 return false;
915
916 Target *target = m_exe_ctx.GetTargetPtr();
917 m_cur_insn = func.GetBaseAddress();
918 uint64_t offset = 0;
919 int row_id = 1;
Jason Molenda1786ebf2014-08-25 22:16:23 +0000920 bool unwind_plan_updated = false;
Todd Fiala05625242014-08-25 20:29:09 +0000921 UnwindPlan::RowSP row(new UnwindPlan::Row(*first_row));
922 while (func.ContainsFileAddress (m_cur_insn))
923 {
924 int insn_len;
925 if (!instruction_length (m_cur_insn, insn_len)
926 || insn_len == 0 || insn_len > kMaxInstructionByteSize)
927 {
928 // An unrecognized/junk instruction.
929 break;
930 }
931 const bool prefer_file_cache = true;
932 Error error;
933 if (target->ReadMemory (m_cur_insn, prefer_file_cache, m_cur_insn_bytes,
934 insn_len, error) == static_cast<size_t>(-1))
935 {
936 // Error reading the instruction out of the file, stop scanning.
937 break;
938 }
939
940 // Advance offsets.
941 offset += insn_len;
942 m_cur_insn.SetOffset(m_cur_insn.GetOffset() + insn_len);
943
944 // If we already have one row for this instruction, we can continue.
945 while (row_id < unwind_plan.GetRowCount()
946 && unwind_plan.GetRowAtIndex (row_id)->GetOffset() <= offset)
947 row_id++;
948 UnwindPlan::RowSP original_row = unwind_plan.GetRowAtIndex (row_id - 1);
949 if (original_row->GetOffset() == offset)
950 {
951 *row = *original_row;
952 continue;
953 }
954
Jason Molenda7b967f12014-08-25 23:46:06 +0000955 if (row_id == 0)
Jason Molenda31e71912014-08-25 23:45:24 +0000956 {
Todd Fiala05625242014-08-25 20:29:09 +0000957 // If we are here, compiler didn't generate CFI for prologue.
958 // This won't happen to GCC or clang.
959 // In this case, bail out directly.
960 return false;
961 }
962
963 // Inspect the instruction to check if we need a new row for it.
964 cfa_reg = m_exe_ctx.GetThreadPtr()->GetRegisterContext()
965 ->ConvertRegisterKindToRegisterNumber (unwind_plan.GetRegisterKind(),
966 row->GetCFARegister());
967 if (cfa_reg == m_lldb_sp_regnum)
968 {
969 // CFA register is sp.
970
971 // call next instruction
972 // call 0
973 // => pop %ebx
974 if (call_next_insn_pattern_p ())
975 {
976 row->SetOffset (offset);
977 row->SetCFAOffset (m_wordsize + row->GetCFAOffset());
978
979 UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row));
980 unwind_plan.InsertRow (new_row);
Jason Molenda1786ebf2014-08-25 22:16:23 +0000981 unwind_plan_updated = true;
Todd Fiala05625242014-08-25 20:29:09 +0000982 continue;
983 }
984
985 // push/pop register
986 int regno;
Jason Molenda7b967f12014-08-25 23:46:06 +0000987 if (push_reg_p (regno))
Jason Molenda31e71912014-08-25 23:45:24 +0000988 {
Todd Fiala05625242014-08-25 20:29:09 +0000989 row->SetOffset (offset);
990 row->SetCFAOffset (m_wordsize + row->GetCFAOffset());
991
992 UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row));
993 unwind_plan.InsertRow (new_row);
Jason Molenda1786ebf2014-08-25 22:16:23 +0000994 unwind_plan_updated = true;
Todd Fiala05625242014-08-25 20:29:09 +0000995 continue;
996 }
Jason Molenda7b967f12014-08-25 23:46:06 +0000997 if (pop_reg_p (regno))
Jason Molenda31e71912014-08-25 23:45:24 +0000998 {
Todd Fiala05625242014-08-25 20:29:09 +0000999 // Technically, this might be a nonvolatile register recover in epilogue.
1000 // We should reset RegisterInfo for the register.
1001 // But in practice, previous rule for the register is still valid...
1002 // So we ignore this case.
1003
1004 row->SetOffset (offset);
1005 row->SetCFAOffset (-m_wordsize + row->GetCFAOffset());
1006
1007 UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row));
1008 unwind_plan.InsertRow (new_row);
Jason Molenda1786ebf2014-08-25 22:16:23 +00001009 unwind_plan_updated = true;
Todd Fiala05625242014-08-25 20:29:09 +00001010 continue;
1011 }
1012
1013 // push imm
Jason Molenda7b967f12014-08-25 23:46:06 +00001014 if (push_imm_pattern_p ())
Jason Molenda31e71912014-08-25 23:45:24 +00001015 {
Todd Fiala05625242014-08-25 20:29:09 +00001016 row->SetOffset (offset);
1017 row->SetCFAOffset (m_wordsize + row->GetCFAOffset());
1018 UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row));
1019 unwind_plan.InsertRow (new_row);
Jason Molenda1786ebf2014-08-25 22:16:23 +00001020 unwind_plan_updated = true;
Todd Fiala05625242014-08-25 20:29:09 +00001021 continue;
1022 }
1023
1024 // add/sub %rsp/%esp
1025 int amount;
Jason Molenda7b967f12014-08-25 23:46:06 +00001026 if (add_rsp_pattern_p (amount))
Jason Molenda31e71912014-08-25 23:45:24 +00001027 {
Todd Fiala05625242014-08-25 20:29:09 +00001028 row->SetOffset (offset);
1029 row->SetCFAOffset (-amount + row->GetCFAOffset());
1030
1031 UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row));
1032 unwind_plan.InsertRow (new_row);
Jason Molenda1786ebf2014-08-25 22:16:23 +00001033 unwind_plan_updated = true;
Todd Fiala05625242014-08-25 20:29:09 +00001034 continue;
1035 }
Jason Molenda7b967f12014-08-25 23:46:06 +00001036 if (sub_rsp_pattern_p (amount))
Jason Molenda31e71912014-08-25 23:45:24 +00001037 {
Todd Fiala05625242014-08-25 20:29:09 +00001038 row->SetOffset (offset);
1039 row->SetCFAOffset (amount + row->GetCFAOffset());
1040
1041 UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row));
1042 unwind_plan.InsertRow (new_row);
Jason Molenda1786ebf2014-08-25 22:16:23 +00001043 unwind_plan_updated = true;
Todd Fiala05625242014-08-25 20:29:09 +00001044 continue;
1045 }
1046 }
1047 else if (cfa_reg == m_lldb_fp_regnum)
1048 {
1049 // CFA register is fp.
1050
1051 // The only case we care about is epilogue:
1052 // [0x5d] pop %rbp/%ebp
1053 // => [0xc3] ret
1054 if (pop_rbp_pattern_p ())
1055 {
1056 if (target->ReadMemory (m_cur_insn, prefer_file_cache, m_cur_insn_bytes,
1057 1, error) != static_cast<size_t>(-1)
1058 && ret_pattern_p ())
1059 {
1060 row->SetOffset (offset);
1061 row->SetCFARegister (first_row->GetCFARegister());
1062 row->SetCFAOffset (m_wordsize);
1063
1064 UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row));
1065 unwind_plan.InsertRow (new_row);
Jason Molenda1786ebf2014-08-25 22:16:23 +00001066 unwind_plan_updated = true;
Todd Fiala05625242014-08-25 20:29:09 +00001067 continue;
1068 }
1069 }
1070 }
1071 else
1072 {
1073 // CFA register is not sp or fp.
1074
1075 // This must be hand-written assembly.
1076 // Just trust eh_frame and assume we have finished.
1077 break;
1078 }
1079 }
1080
1081 unwind_plan.SetPlanValidAddressRange (func);
Jason Molenda1786ebf2014-08-25 22:16:23 +00001082 if (unwind_plan_updated)
1083 {
1084 std::string unwind_plan_source (unwind_plan.GetSourceName().AsCString());
1085 unwind_plan_source += " plus augmentation from assembly parsing";
1086 unwind_plan.SetSourceName (unwind_plan_source.c_str());
1087 unwind_plan.SetSourcedFromCompiler (eLazyBoolNo);
Jason Molendae589e7e2014-12-08 03:09:00 +00001088 unwind_plan.SetUnwindPlanValidAtAllInstructions (eLazyBoolYes);
Jason Molenda1786ebf2014-08-25 22:16:23 +00001089 }
Todd Fiala05625242014-08-25 20:29:09 +00001090 return true;
1091}
1092
Jason Molenda7b967f12014-08-25 23:46:06 +00001093/* The "fast unwind plan" is valid for functions that follow the usual convention of
Jason Molendaab4f1922010-10-25 11:12:07 +00001094 using the frame pointer register (ebp, rbp), i.e. the function prologue looks like
1095 push %rbp [0x55]
1096 mov %rsp,%rbp [0x48 0x89 0xe5] (this is a 2-byte insn seq on i386)
1097*/
1098
Jason Molenda7b967f12014-08-25 23:46:06 +00001099bool
Jason Molendaab4f1922010-10-25 11:12:07 +00001100AssemblyParse_x86::get_fast_unwind_plan (AddressRange& func, UnwindPlan &unwind_plan)
Jason Molendafbcb7f22010-09-10 07:49:16 +00001101{
Jason Molenda1d42c7b2012-07-14 04:52:53 +00001102 UnwindPlan::RowSP row(new UnwindPlan::Row);
Jason Molendaab4f1922010-10-25 11:12:07 +00001103 UnwindPlan::Row::RegisterLocation pc_reginfo;
1104 UnwindPlan::Row::RegisterLocation sp_reginfo;
1105 UnwindPlan::Row::RegisterLocation fp_reginfo;
1106 unwind_plan.SetRegisterKind (eRegisterKindLLDB);
1107
1108 if (!func.GetBaseAddress().IsValid())
1109 return false;
1110
Greg Clayton1ac04c32012-02-21 00:09:25 +00001111 Target *target = m_exe_ctx.GetTargetPtr();
1112
Jason Molendaab4f1922010-10-25 11:12:07 +00001113 uint8_t bytebuf[4];
1114 Error error;
Greg Claytondb598232011-01-07 01:57:07 +00001115 const bool prefer_file_cache = true;
Saleem Abdulrasool3985c8c2014-04-02 03:51:35 +00001116 if (target->ReadMemory (func.GetBaseAddress(), prefer_file_cache, bytebuf,
1117 sizeof (bytebuf), error) == static_cast<size_t>(-1))
Jason Molendaab4f1922010-10-25 11:12:07 +00001118 return false;
1119
1120 uint8_t i386_prologue[] = {0x55, 0x89, 0xe5};
1121 uint8_t x86_64_prologue[] = {0x55, 0x48, 0x89, 0xe5};
1122 int prologue_size;
1123
1124 if (memcmp (bytebuf, i386_prologue, sizeof (i386_prologue)) == 0)
1125 {
1126 prologue_size = sizeof (i386_prologue);
1127 }
1128 else if (memcmp (bytebuf, x86_64_prologue, sizeof (x86_64_prologue)) == 0)
1129 {
1130 prologue_size = sizeof (x86_64_prologue);
1131 }
1132 else
1133 {
1134 return false;
1135 }
1136
1137 pc_reginfo.SetAtCFAPlusOffset (-m_wordsize);
Jason Molenda1d42c7b2012-07-14 04:52:53 +00001138 row->SetRegisterInfo (m_lldb_ip_regnum, pc_reginfo);
Jason Molendaab4f1922010-10-25 11:12:07 +00001139
1140 sp_reginfo.SetIsCFAPlusOffset (0);
Jason Molenda1d42c7b2012-07-14 04:52:53 +00001141 row->SetRegisterInfo (m_lldb_sp_regnum, sp_reginfo);
Jason Molendaab4f1922010-10-25 11:12:07 +00001142
1143 // Zero instructions into the function
Jason Molenda1d42c7b2012-07-14 04:52:53 +00001144 row->SetCFARegister (m_lldb_sp_regnum);
1145 row->SetCFAOffset (m_wordsize);
1146 row->SetOffset (0);
Jason Molendaab4f1922010-10-25 11:12:07 +00001147 unwind_plan.AppendRow (row);
Jason Molenda1d42c7b2012-07-14 04:52:53 +00001148 UnwindPlan::Row *newrow = new UnwindPlan::Row;
1149 *newrow = *row.get();
1150 row.reset(newrow);
Jason Molendaab4f1922010-10-25 11:12:07 +00001151
1152 // push %rbp has executed - stack moved, rbp now saved
Jason Molenda1d42c7b2012-07-14 04:52:53 +00001153 row->SetCFAOffset (2 * m_wordsize);
Jason Molendaab4f1922010-10-25 11:12:07 +00001154 fp_reginfo.SetAtCFAPlusOffset (2 * -m_wordsize);
Jason Molenda1d42c7b2012-07-14 04:52:53 +00001155 row->SetRegisterInfo (m_lldb_fp_regnum, fp_reginfo);
1156 row->SetOffset (1);
Jason Molendaab4f1922010-10-25 11:12:07 +00001157 unwind_plan.AppendRow (row);
1158
Jason Molenda1d42c7b2012-07-14 04:52:53 +00001159 newrow = new UnwindPlan::Row;
1160 *newrow = *row.get();
1161 row.reset(newrow);
Jason Molenda7b967f12014-08-25 23:46:06 +00001162
Jason Molendaab4f1922010-10-25 11:12:07 +00001163 // mov %rsp, %rbp has executed
Jason Molenda1d42c7b2012-07-14 04:52:53 +00001164 row->SetCFARegister (m_lldb_fp_regnum);
1165 row->SetCFAOffset (2 * m_wordsize);
1166 row->SetOffset (prologue_size); /// 3 or 4 bytes depending on arch
Jason Molendaab4f1922010-10-25 11:12:07 +00001167 unwind_plan.AppendRow (row);
1168
Jason Molenda1d42c7b2012-07-14 04:52:53 +00001169 newrow = new UnwindPlan::Row;
1170 *newrow = *row.get();
1171 row.reset(newrow);
1172
Jason Molendaab4f1922010-10-25 11:12:07 +00001173 unwind_plan.SetPlanValidAddressRange (func);
Jason Molenda60f0bd42012-10-26 06:08:58 +00001174 unwind_plan.SetSourceName ("fast unwind assembly profiling");
1175 unwind_plan.SetSourcedFromCompiler (eLazyBoolNo);
1176 unwind_plan.SetUnwindPlanValidAtAllInstructions (eLazyBoolNo);
Jason Molendaab4f1922010-10-25 11:12:07 +00001177 return true;
Jason Molendafbcb7f22010-09-10 07:49:16 +00001178}
1179
Jason Molenda7b967f12014-08-25 23:46:06 +00001180bool
Jason Molendafbcb7f22010-09-10 07:49:16 +00001181AssemblyParse_x86::find_first_non_prologue_insn (Address &address)
1182{
1183 m_cur_insn = m_func_bounds.GetBaseAddress ();
Jason Molenda59762002010-11-04 00:53:20 +00001184 if (!m_cur_insn.IsValid())
1185 {
1186 return false;
1187 }
1188
Greg Claytondb598232011-01-07 01:57:07 +00001189 const bool prefer_file_cache = true;
Greg Clayton1ac04c32012-02-21 00:09:25 +00001190 Target *target = m_exe_ctx.GetTargetPtr();
Jason Molendafbcb7f22010-09-10 07:49:16 +00001191 while (m_func_bounds.ContainsFileAddress (m_cur_insn))
1192 {
1193 Error error;
1194 int insn_len, offset, regno;
1195 if (!instruction_length (m_cur_insn, insn_len) || insn_len > kMaxInstructionByteSize || insn_len == 0)
1196 {
1197 // An error parsing the instruction, i.e. probably data/garbage - stop scanning
1198 break;
1199 }
Saleem Abdulrasool3985c8c2014-04-02 03:51:35 +00001200 if (target->ReadMemory (m_cur_insn, prefer_file_cache, m_cur_insn_bytes,
1201 insn_len, error) == static_cast<size_t>(-1))
Jason Molendafbcb7f22010-09-10 07:49:16 +00001202 {
1203 // Error reading the instruction out of the file, stop scanning
1204 break;
1205 }
1206
1207 if (push_rbp_pattern_p () || mov_rsp_rbp_pattern_p () || sub_rsp_pattern_p (offset)
1208 || push_reg_p (regno) || mov_reg_to_local_stack_frame_p (regno, offset))
1209 {
1210 m_cur_insn.SetOffset (m_cur_insn.GetOffset() + insn_len);
1211 continue;
1212 }
1213
1214 // Unknown non-prologue instruction - stop scanning
1215 break;
1216 }
1217
1218 address = m_cur_insn;
1219 return true;
1220}
1221
1222
1223
1224
1225
1226
1227//-----------------------------------------------------------------------------------------------
Jason Molenda7b967f12014-08-25 23:46:06 +00001228// UnwindAssemblyParser_x86 method definitions
Jason Molendafbcb7f22010-09-10 07:49:16 +00001229//-----------------------------------------------------------------------------------------------
1230
Jason Molenda7b967f12014-08-25 23:46:06 +00001231UnwindAssembly_x86::UnwindAssembly_x86 (const ArchSpec &arch, int cpu) :
1232 lldb_private::UnwindAssembly(arch),
Jason Molendaa8399a82012-10-10 01:45:33 +00001233 m_cpu(cpu),
1234 m_arch(arch)
Greg Clayton2ed751b2011-04-26 04:39:08 +00001235{
1236}
1237
1238
1239UnwindAssembly_x86::~UnwindAssembly_x86 ()
1240{
1241}
1242
Jason Molendafbcb7f22010-09-10 07:49:16 +00001243bool
Greg Claytonffc922e32011-04-25 21:05:07 +00001244UnwindAssembly_x86::GetNonCallSiteUnwindPlanFromAssembly (AddressRange& func, Thread& thread, UnwindPlan& unwind_plan)
Jason Molendafbcb7f22010-09-10 07:49:16 +00001245{
Greg Clayton1ac04c32012-02-21 00:09:25 +00001246 ExecutionContext exe_ctx (thread.shared_from_this());
Jason Molendaa8399a82012-10-10 01:45:33 +00001247 AssemblyParse_x86 asm_parse(exe_ctx, m_cpu, m_arch, func);
Jason Molendafbcb7f22010-09-10 07:49:16 +00001248 return asm_parse.get_non_call_site_unwind_plan (unwind_plan);
1249}
1250
1251bool
Todd Fiala05625242014-08-25 20:29:09 +00001252UnwindAssembly_x86::AugmentUnwindPlanFromCallSite (AddressRange& func, Thread& thread, UnwindPlan& unwind_plan)
1253{
1254 ExecutionContext exe_ctx (thread.shared_from_this());
1255 AssemblyParse_x86 asm_parse(exe_ctx, m_cpu, m_arch, func);
1256 return asm_parse.augment_unwind_plan_from_call_site (func, unwind_plan);
1257}
1258
1259bool
Greg Claytonffc922e32011-04-25 21:05:07 +00001260UnwindAssembly_x86::GetFastUnwindPlan (AddressRange& func, Thread& thread, UnwindPlan &unwind_plan)
Jason Molendafbcb7f22010-09-10 07:49:16 +00001261{
Jason Molenda5c45c542014-12-21 10:44:54 +00001262 // if prologue is
1263 // 55 pushl %ebp
1264 // 89 e5 movl %esp, %ebp
1265 // or
1266 // 55 pushq %rbp
1267 // 48 89 e5 movq %rsp, %rbp
1268
1269 // We should pull in the ABI architecture default unwind plan and return that
1270
1271 llvm::SmallVector <uint8_t, 4> opcode_data;
1272
1273 ProcessSP process_sp = thread.GetProcess();
1274 if (process_sp)
1275 {
1276 Target &target (process_sp->GetTarget());
1277 const bool prefer_file_cache = true;
1278 Error error;
1279 if (target.ReadMemory (func.GetBaseAddress (), prefer_file_cache, opcode_data.data(),
1280 4, error) == 4)
1281 {
1282 uint8_t i386_push_mov[] = {0x55, 0x89, 0xe5};
1283 uint8_t x86_64_push_mov[] = {0x55, 0x48, 0x89, 0xe5};
1284
1285 if (memcmp (opcode_data.data(), i386_push_mov, sizeof (i386_push_mov)) == 0
1286 || memcmp (opcode_data.data(), x86_64_push_mov, sizeof (x86_64_push_mov)) == 0)
1287 {
1288 ABISP abi_sp = process_sp->GetABI();
1289 if (abi_sp)
1290 {
1291 return abi_sp->CreateDefaultUnwindPlan (unwind_plan);
1292 }
1293 }
1294 }
1295 }
1296 return false;
Jason Molendafbcb7f22010-09-10 07:49:16 +00001297}
1298
1299bool
Greg Clayton1ac04c32012-02-21 00:09:25 +00001300UnwindAssembly_x86::FirstNonPrologueInsn (AddressRange& func, const ExecutionContext &exe_ctx, Address& first_non_prologue_insn)
Jason Molendafbcb7f22010-09-10 07:49:16 +00001301{
Jason Molendaa8399a82012-10-10 01:45:33 +00001302 AssemblyParse_x86 asm_parse(exe_ctx, m_cpu, m_arch, func);
Jason Molendafbcb7f22010-09-10 07:49:16 +00001303 return asm_parse.find_first_non_prologue_insn (first_non_prologue_insn);
1304}
1305
Greg Clayton7be25422011-04-25 21:14:26 +00001306UnwindAssembly *
Greg Claytonffc922e32011-04-25 21:05:07 +00001307UnwindAssembly_x86::CreateInstance (const ArchSpec &arch)
Jason Molendafbcb7f22010-09-10 07:49:16 +00001308{
Greg Clayton64195a22011-02-23 00:35:02 +00001309 const llvm::Triple::ArchType cpu = arch.GetMachine ();
1310 if (cpu == llvm::Triple::x86)
Greg Clayton2ed751b2011-04-26 04:39:08 +00001311 return new UnwindAssembly_x86 (arch, k_i386);
Greg Clayton64195a22011-02-23 00:35:02 +00001312 else if (cpu == llvm::Triple::x86_64)
Greg Clayton2ed751b2011-04-26 04:39:08 +00001313 return new UnwindAssembly_x86 (arch, k_x86_64);
Greg Clayton64195a22011-02-23 00:35:02 +00001314 return NULL;
Jason Molendafbcb7f22010-09-10 07:49:16 +00001315}
1316
1317
1318//------------------------------------------------------------------
1319// PluginInterface protocol in UnwindAssemblyParser_x86
1320//------------------------------------------------------------------
1321
Greg Clayton57abc5d2013-05-10 21:47:16 +00001322ConstString
Greg Claytonffc922e32011-04-25 21:05:07 +00001323UnwindAssembly_x86::GetPluginName()
Jason Molendafbcb7f22010-09-10 07:49:16 +00001324{
Greg Clayton57abc5d2013-05-10 21:47:16 +00001325 return GetPluginNameStatic();
Jason Molendafbcb7f22010-09-10 07:49:16 +00001326}
1327
1328
1329uint32_t
Greg Claytonffc922e32011-04-25 21:05:07 +00001330UnwindAssembly_x86::GetPluginVersion()
Jason Molendafbcb7f22010-09-10 07:49:16 +00001331{
1332 return 1;
1333}
1334
1335void
Greg Claytonffc922e32011-04-25 21:05:07 +00001336UnwindAssembly_x86::Initialize()
Jason Molendafbcb7f22010-09-10 07:49:16 +00001337{
1338 PluginManager::RegisterPlugin (GetPluginNameStatic(),
1339 GetPluginDescriptionStatic(),
1340 CreateInstance);
1341}
1342
1343void
Greg Claytonffc922e32011-04-25 21:05:07 +00001344UnwindAssembly_x86::Terminate()
Jason Molendafbcb7f22010-09-10 07:49:16 +00001345{
1346 PluginManager::UnregisterPlugin (CreateInstance);
1347}
1348
1349
Greg Clayton57abc5d2013-05-10 21:47:16 +00001350lldb_private::ConstString
Greg Claytonffc922e32011-04-25 21:05:07 +00001351UnwindAssembly_x86::GetPluginNameStatic()
Jason Molendafbcb7f22010-09-10 07:49:16 +00001352{
Greg Clayton57abc5d2013-05-10 21:47:16 +00001353 static ConstString g_name("x86");
1354 return g_name;
Jason Molendafbcb7f22010-09-10 07:49:16 +00001355}
1356
1357const char *
Greg Claytonffc922e32011-04-25 21:05:07 +00001358UnwindAssembly_x86::GetPluginDescriptionStatic()
Jason Molendafbcb7f22010-09-10 07:49:16 +00001359{
1360 return "i386 and x86_64 assembly language profiler plugin.";
1361}