blob: 32a21d2b8bb8720863a7b52d679a1e3e0b805971 [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
807 // We want to add a Row describing how to unwind when we're stopped on the 'ret' instruction where the
808 // 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 +0000809 // (or the 'jmp' instruction in the second case)
Jason Molenda6f5e8c22012-05-25 01:54:06 +0000810
811 uint64_t ret_insn_offset = LLDB_INVALID_ADDRESS;
812 Address end_of_fun(m_func_bounds.GetBaseAddress());
813 end_of_fun.SetOffset (end_of_fun.GetOffset() + m_func_bounds.GetByteSize());
Jason Molenda300dfcd2014-08-04 21:26:55 +0000814
Jason Molenda6f5e8c22012-05-25 01:54:06 +0000815 if (m_func_bounds.GetByteSize() > 7)
Jason Molenda59203332010-11-16 03:01:20 +0000816 {
Jason Molenda6f5e8c22012-05-25 01:54:06 +0000817 uint8_t bytebuf[7];
818 Address last_seven_bytes(end_of_fun);
819 last_seven_bytes.SetOffset (last_seven_bytes.GetOffset() - 7);
Saleem Abdulrasool3985c8c2014-04-02 03:51:35 +0000820 if (target->ReadMemory (last_seven_bytes, prefer_file_cache, bytebuf, 7,
821 error) != static_cast<size_t>(-1))
Jason Molenda59203332010-11-16 03:01:20 +0000822 {
Jason Molenda300dfcd2014-08-04 21:26:55 +0000823 if (bytebuf[5] == 0x5d && bytebuf[6] == 0xc3) // mov & ret
Jason Molenda59203332010-11-16 03:01:20 +0000824 {
Jason Molenda6f5e8c22012-05-25 01:54:06 +0000825 ret_insn_offset = m_func_bounds.GetByteSize() - 1;
826 }
Jason Molenda300dfcd2014-08-04 21:26:55 +0000827 else if (bytebuf[1] == 0x5d && bytebuf[2] == 0xe9) // mov & jmp
828 {
829 // When the pc is sitting on the 'jmp' instruction, we have the same
830 // unwind state as if it was sitting on a 'ret' instruction.
831 ret_insn_offset = m_func_bounds.GetByteSize() - 5;
832 }
833 else if (bytebuf[0] == 0x5d && bytebuf[1] == 0xc3 && bytebuf[2] == 0xe8) // mov & ret & call
Jason Molenda6f5e8c22012-05-25 01:54:06 +0000834 {
835 ret_insn_offset = m_func_bounds.GetByteSize() - 6;
Jason Molenda59203332010-11-16 03:01:20 +0000836 }
837 }
Jason Molenda300dfcd2014-08-04 21:26:55 +0000838 }
839 else if (m_func_bounds.GetByteSize() > 2)
Jason Molenda6f5e8c22012-05-25 01:54:06 +0000840 {
841 uint8_t bytebuf[2];
842 Address last_two_bytes(end_of_fun);
843 last_two_bytes.SetOffset (last_two_bytes.GetOffset() - 2);
Saleem Abdulrasool3985c8c2014-04-02 03:51:35 +0000844 if (target->ReadMemory (last_two_bytes, prefer_file_cache, bytebuf, 2,
845 error) != static_cast<size_t>(-1))
Jason Molenda6f5e8c22012-05-25 01:54:06 +0000846 {
Jason Molenda300dfcd2014-08-04 21:26:55 +0000847 if (bytebuf[0] == 0x5d && bytebuf[1] == 0xc3) // mov & ret
Jason Molenda6f5e8c22012-05-25 01:54:06 +0000848 {
849 ret_insn_offset = m_func_bounds.GetByteSize() - 1;
850 }
851 }
852 }
853
854 if (ret_insn_offset != LLDB_INVALID_ADDRESS)
855 {
856 // Create a fresh, empty Row and RegisterLocation - don't mention any other registers
Jason Molenda1d42c7b2012-07-14 04:52:53 +0000857 UnwindPlan::RowSP epi_row(new UnwindPlan::Row);
Jason Molenda6f5e8c22012-05-25 01:54:06 +0000858 UnwindPlan::Row::RegisterLocation epi_regloc;
859
860 // When the ret instruction is about to be executed, here's our state
Jason Molenda1d42c7b2012-07-14 04:52:53 +0000861 epi_row->SetOffset (ret_insn_offset);
862 epi_row->SetCFARegister (m_lldb_sp_regnum);
863 epi_row->SetCFAOffset (m_wordsize);
Jason Molenda7b967f12014-08-25 23:46:06 +0000864
Jason Molenda6f5e8c22012-05-25 01:54:06 +0000865 // caller's stack pointer value before the call insn is the CFA address
866 epi_regloc.SetIsCFAPlusOffset (0);
Jason Molenda1d42c7b2012-07-14 04:52:53 +0000867 epi_row->SetRegisterInfo (m_lldb_sp_regnum, epi_regloc);
Jason Molenda6f5e8c22012-05-25 01:54:06 +0000868
869 // saved instruction pointer can be found at CFA - wordsize
870 epi_regloc.SetAtCFAPlusOffset (-m_wordsize);
Jason Molenda1d42c7b2012-07-14 04:52:53 +0000871 epi_row->SetRegisterInfo (m_lldb_ip_regnum, epi_regloc);
Jason Molenda6f5e8c22012-05-25 01:54:06 +0000872
873 unwind_plan.AppendRow (epi_row);
Jason Molenda59203332010-11-16 03:01:20 +0000874 }
Jason Molenda7b967f12014-08-25 23:46:06 +0000875
Jason Molendaab4f1922010-10-25 11:12:07 +0000876 unwind_plan.SetSourceName ("assembly insn profiling");
Jason Molenda60f0bd42012-10-26 06:08:58 +0000877 unwind_plan.SetSourcedFromCompiler (eLazyBoolNo);
878 unwind_plan.SetUnwindPlanValidAtAllInstructions (eLazyBoolYes);
Jason Molendaab4f1922010-10-25 11:12:07 +0000879
Jason Molendafbcb7f22010-09-10 07:49:16 +0000880 return true;
881}
882
Todd Fiala05625242014-08-25 20:29:09 +0000883bool
884AssemblyParse_x86::augment_unwind_plan_from_call_site (AddressRange& func, UnwindPlan &unwind_plan)
885{
886 // Is func address valid?
887 Address addr_start = func.GetBaseAddress();
888 if (!addr_start.IsValid())
889 return false;
890
891 // Is original unwind_plan valid?
892 // unwind_plan should have at least one row which is ABI-default (CFA register is sp),
893 // and another row in mid-function.
894 if (unwind_plan.GetRowCount() < 2)
895 return false;
896 UnwindPlan::RowSP first_row = unwind_plan.GetRowAtIndex (0);
897 if (first_row->GetOffset() != 0)
898 return false;
899 uint32_t cfa_reg = m_exe_ctx.GetThreadPtr()->GetRegisterContext()
900 ->ConvertRegisterKindToRegisterNumber (unwind_plan.GetRegisterKind(),
901 first_row->GetCFARegister());
902 if (cfa_reg != m_lldb_sp_regnum || first_row->GetCFAOffset() != m_wordsize)
903 return false;
904
905 Target *target = m_exe_ctx.GetTargetPtr();
906 m_cur_insn = func.GetBaseAddress();
907 uint64_t offset = 0;
908 int row_id = 1;
Jason Molenda1786ebf2014-08-25 22:16:23 +0000909 bool unwind_plan_updated = false;
Todd Fiala05625242014-08-25 20:29:09 +0000910 UnwindPlan::RowSP row(new UnwindPlan::Row(*first_row));
911 while (func.ContainsFileAddress (m_cur_insn))
912 {
913 int insn_len;
914 if (!instruction_length (m_cur_insn, insn_len)
915 || insn_len == 0 || insn_len > kMaxInstructionByteSize)
916 {
917 // An unrecognized/junk instruction.
918 break;
919 }
920 const bool prefer_file_cache = true;
921 Error error;
922 if (target->ReadMemory (m_cur_insn, prefer_file_cache, m_cur_insn_bytes,
923 insn_len, error) == static_cast<size_t>(-1))
924 {
925 // Error reading the instruction out of the file, stop scanning.
926 break;
927 }
928
929 // Advance offsets.
930 offset += insn_len;
931 m_cur_insn.SetOffset(m_cur_insn.GetOffset() + insn_len);
932
933 // If we already have one row for this instruction, we can continue.
934 while (row_id < unwind_plan.GetRowCount()
935 && unwind_plan.GetRowAtIndex (row_id)->GetOffset() <= offset)
936 row_id++;
937 UnwindPlan::RowSP original_row = unwind_plan.GetRowAtIndex (row_id - 1);
938 if (original_row->GetOffset() == offset)
939 {
940 *row = *original_row;
941 continue;
942 }
943
Jason Molenda7b967f12014-08-25 23:46:06 +0000944 if (row_id == 0)
Jason Molenda31e71912014-08-25 23:45:24 +0000945 {
Todd Fiala05625242014-08-25 20:29:09 +0000946 // If we are here, compiler didn't generate CFI for prologue.
947 // This won't happen to GCC or clang.
948 // In this case, bail out directly.
949 return false;
950 }
951
952 // Inspect the instruction to check if we need a new row for it.
953 cfa_reg = m_exe_ctx.GetThreadPtr()->GetRegisterContext()
954 ->ConvertRegisterKindToRegisterNumber (unwind_plan.GetRegisterKind(),
955 row->GetCFARegister());
956 if (cfa_reg == m_lldb_sp_regnum)
957 {
958 // CFA register is sp.
959
960 // call next instruction
961 // call 0
962 // => pop %ebx
963 if (call_next_insn_pattern_p ())
964 {
965 row->SetOffset (offset);
966 row->SetCFAOffset (m_wordsize + row->GetCFAOffset());
967
968 UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row));
969 unwind_plan.InsertRow (new_row);
Jason Molenda1786ebf2014-08-25 22:16:23 +0000970 unwind_plan_updated = true;
Todd Fiala05625242014-08-25 20:29:09 +0000971 continue;
972 }
973
974 // push/pop register
975 int regno;
Jason Molenda7b967f12014-08-25 23:46:06 +0000976 if (push_reg_p (regno))
Jason Molenda31e71912014-08-25 23:45:24 +0000977 {
Todd Fiala05625242014-08-25 20:29:09 +0000978 row->SetOffset (offset);
979 row->SetCFAOffset (m_wordsize + row->GetCFAOffset());
980
981 UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row));
982 unwind_plan.InsertRow (new_row);
Jason Molenda1786ebf2014-08-25 22:16:23 +0000983 unwind_plan_updated = true;
Todd Fiala05625242014-08-25 20:29:09 +0000984 continue;
985 }
Jason Molenda7b967f12014-08-25 23:46:06 +0000986 if (pop_reg_p (regno))
Jason Molenda31e71912014-08-25 23:45:24 +0000987 {
Todd Fiala05625242014-08-25 20:29:09 +0000988 // Technically, this might be a nonvolatile register recover in epilogue.
989 // We should reset RegisterInfo for the register.
990 // But in practice, previous rule for the register is still valid...
991 // So we ignore this case.
992
993 row->SetOffset (offset);
994 row->SetCFAOffset (-m_wordsize + row->GetCFAOffset());
995
996 UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row));
997 unwind_plan.InsertRow (new_row);
Jason Molenda1786ebf2014-08-25 22:16:23 +0000998 unwind_plan_updated = true;
Todd Fiala05625242014-08-25 20:29:09 +0000999 continue;
1000 }
1001
1002 // push imm
Jason Molenda7b967f12014-08-25 23:46:06 +00001003 if (push_imm_pattern_p ())
Jason Molenda31e71912014-08-25 23:45:24 +00001004 {
Todd Fiala05625242014-08-25 20:29:09 +00001005 row->SetOffset (offset);
1006 row->SetCFAOffset (m_wordsize + row->GetCFAOffset());
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 // add/sub %rsp/%esp
1014 int amount;
Jason Molenda7b967f12014-08-25 23:46:06 +00001015 if (add_rsp_pattern_p (amount))
Jason Molenda31e71912014-08-25 23:45:24 +00001016 {
Todd Fiala05625242014-08-25 20:29:09 +00001017 row->SetOffset (offset);
1018 row->SetCFAOffset (-amount + row->GetCFAOffset());
1019
1020 UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row));
1021 unwind_plan.InsertRow (new_row);
Jason Molenda1786ebf2014-08-25 22:16:23 +00001022 unwind_plan_updated = true;
Todd Fiala05625242014-08-25 20:29:09 +00001023 continue;
1024 }
Jason Molenda7b967f12014-08-25 23:46:06 +00001025 if (sub_rsp_pattern_p (amount))
Jason Molenda31e71912014-08-25 23:45:24 +00001026 {
Todd Fiala05625242014-08-25 20:29:09 +00001027 row->SetOffset (offset);
1028 row->SetCFAOffset (amount + row->GetCFAOffset());
1029
1030 UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row));
1031 unwind_plan.InsertRow (new_row);
Jason Molenda1786ebf2014-08-25 22:16:23 +00001032 unwind_plan_updated = true;
Todd Fiala05625242014-08-25 20:29:09 +00001033 continue;
1034 }
1035 }
1036 else if (cfa_reg == m_lldb_fp_regnum)
1037 {
1038 // CFA register is fp.
1039
1040 // The only case we care about is epilogue:
1041 // [0x5d] pop %rbp/%ebp
1042 // => [0xc3] ret
1043 if (pop_rbp_pattern_p ())
1044 {
1045 if (target->ReadMemory (m_cur_insn, prefer_file_cache, m_cur_insn_bytes,
1046 1, error) != static_cast<size_t>(-1)
1047 && ret_pattern_p ())
1048 {
1049 row->SetOffset (offset);
1050 row->SetCFARegister (first_row->GetCFARegister());
1051 row->SetCFAOffset (m_wordsize);
1052
1053 UnwindPlan::RowSP new_row(new UnwindPlan::Row(*row));
1054 unwind_plan.InsertRow (new_row);
Jason Molenda1786ebf2014-08-25 22:16:23 +00001055 unwind_plan_updated = true;
Todd Fiala05625242014-08-25 20:29:09 +00001056 continue;
1057 }
1058 }
1059 }
1060 else
1061 {
1062 // CFA register is not sp or fp.
1063
1064 // This must be hand-written assembly.
1065 // Just trust eh_frame and assume we have finished.
1066 break;
1067 }
1068 }
1069
1070 unwind_plan.SetPlanValidAddressRange (func);
Jason Molenda1786ebf2014-08-25 22:16:23 +00001071 if (unwind_plan_updated)
1072 {
1073 std::string unwind_plan_source (unwind_plan.GetSourceName().AsCString());
1074 unwind_plan_source += " plus augmentation from assembly parsing";
1075 unwind_plan.SetSourceName (unwind_plan_source.c_str());
1076 unwind_plan.SetSourcedFromCompiler (eLazyBoolNo);
1077 }
Todd Fiala05625242014-08-25 20:29:09 +00001078 return true;
1079}
1080
Jason Molenda7b967f12014-08-25 23:46:06 +00001081/* The "fast unwind plan" is valid for functions that follow the usual convention of
Jason Molendaab4f1922010-10-25 11:12:07 +00001082 using the frame pointer register (ebp, rbp), i.e. the function prologue looks like
1083 push %rbp [0x55]
1084 mov %rsp,%rbp [0x48 0x89 0xe5] (this is a 2-byte insn seq on i386)
1085*/
1086
Jason Molenda7b967f12014-08-25 23:46:06 +00001087bool
Jason Molendaab4f1922010-10-25 11:12:07 +00001088AssemblyParse_x86::get_fast_unwind_plan (AddressRange& func, UnwindPlan &unwind_plan)
Jason Molendafbcb7f22010-09-10 07:49:16 +00001089{
Jason Molenda1d42c7b2012-07-14 04:52:53 +00001090 UnwindPlan::RowSP row(new UnwindPlan::Row);
Jason Molendaab4f1922010-10-25 11:12:07 +00001091 UnwindPlan::Row::RegisterLocation pc_reginfo;
1092 UnwindPlan::Row::RegisterLocation sp_reginfo;
1093 UnwindPlan::Row::RegisterLocation fp_reginfo;
1094 unwind_plan.SetRegisterKind (eRegisterKindLLDB);
1095
1096 if (!func.GetBaseAddress().IsValid())
1097 return false;
1098
Greg Clayton1ac04c32012-02-21 00:09:25 +00001099 Target *target = m_exe_ctx.GetTargetPtr();
1100
Jason Molendaab4f1922010-10-25 11:12:07 +00001101 uint8_t bytebuf[4];
1102 Error error;
Greg Claytondb598232011-01-07 01:57:07 +00001103 const bool prefer_file_cache = true;
Saleem Abdulrasool3985c8c2014-04-02 03:51:35 +00001104 if (target->ReadMemory (func.GetBaseAddress(), prefer_file_cache, bytebuf,
1105 sizeof (bytebuf), error) == static_cast<size_t>(-1))
Jason Molendaab4f1922010-10-25 11:12:07 +00001106 return false;
1107
1108 uint8_t i386_prologue[] = {0x55, 0x89, 0xe5};
1109 uint8_t x86_64_prologue[] = {0x55, 0x48, 0x89, 0xe5};
1110 int prologue_size;
1111
1112 if (memcmp (bytebuf, i386_prologue, sizeof (i386_prologue)) == 0)
1113 {
1114 prologue_size = sizeof (i386_prologue);
1115 }
1116 else if (memcmp (bytebuf, x86_64_prologue, sizeof (x86_64_prologue)) == 0)
1117 {
1118 prologue_size = sizeof (x86_64_prologue);
1119 }
1120 else
1121 {
1122 return false;
1123 }
1124
1125 pc_reginfo.SetAtCFAPlusOffset (-m_wordsize);
Jason Molenda1d42c7b2012-07-14 04:52:53 +00001126 row->SetRegisterInfo (m_lldb_ip_regnum, pc_reginfo);
Jason Molendaab4f1922010-10-25 11:12:07 +00001127
1128 sp_reginfo.SetIsCFAPlusOffset (0);
Jason Molenda1d42c7b2012-07-14 04:52:53 +00001129 row->SetRegisterInfo (m_lldb_sp_regnum, sp_reginfo);
Jason Molendaab4f1922010-10-25 11:12:07 +00001130
1131 // Zero instructions into the function
Jason Molenda1d42c7b2012-07-14 04:52:53 +00001132 row->SetCFARegister (m_lldb_sp_regnum);
1133 row->SetCFAOffset (m_wordsize);
1134 row->SetOffset (0);
Jason Molendaab4f1922010-10-25 11:12:07 +00001135 unwind_plan.AppendRow (row);
Jason Molenda1d42c7b2012-07-14 04:52:53 +00001136 UnwindPlan::Row *newrow = new UnwindPlan::Row;
1137 *newrow = *row.get();
1138 row.reset(newrow);
Jason Molendaab4f1922010-10-25 11:12:07 +00001139
1140 // push %rbp has executed - stack moved, rbp now saved
Jason Molenda1d42c7b2012-07-14 04:52:53 +00001141 row->SetCFAOffset (2 * m_wordsize);
Jason Molendaab4f1922010-10-25 11:12:07 +00001142 fp_reginfo.SetAtCFAPlusOffset (2 * -m_wordsize);
Jason Molenda1d42c7b2012-07-14 04:52:53 +00001143 row->SetRegisterInfo (m_lldb_fp_regnum, fp_reginfo);
1144 row->SetOffset (1);
Jason Molendaab4f1922010-10-25 11:12:07 +00001145 unwind_plan.AppendRow (row);
1146
Jason Molenda1d42c7b2012-07-14 04:52:53 +00001147 newrow = new UnwindPlan::Row;
1148 *newrow = *row.get();
1149 row.reset(newrow);
Jason Molenda7b967f12014-08-25 23:46:06 +00001150
Jason Molendaab4f1922010-10-25 11:12:07 +00001151 // mov %rsp, %rbp has executed
Jason Molenda1d42c7b2012-07-14 04:52:53 +00001152 row->SetCFARegister (m_lldb_fp_regnum);
1153 row->SetCFAOffset (2 * m_wordsize);
1154 row->SetOffset (prologue_size); /// 3 or 4 bytes depending on arch
Jason Molendaab4f1922010-10-25 11:12:07 +00001155 unwind_plan.AppendRow (row);
1156
Jason Molenda1d42c7b2012-07-14 04:52:53 +00001157 newrow = new UnwindPlan::Row;
1158 *newrow = *row.get();
1159 row.reset(newrow);
1160
Jason Molendaab4f1922010-10-25 11:12:07 +00001161 unwind_plan.SetPlanValidAddressRange (func);
Jason Molenda60f0bd42012-10-26 06:08:58 +00001162 unwind_plan.SetSourceName ("fast unwind assembly profiling");
1163 unwind_plan.SetSourcedFromCompiler (eLazyBoolNo);
1164 unwind_plan.SetUnwindPlanValidAtAllInstructions (eLazyBoolNo);
Jason Molendaab4f1922010-10-25 11:12:07 +00001165 return true;
Jason Molendafbcb7f22010-09-10 07:49:16 +00001166}
1167
Jason Molenda7b967f12014-08-25 23:46:06 +00001168bool
Jason Molendafbcb7f22010-09-10 07:49:16 +00001169AssemblyParse_x86::find_first_non_prologue_insn (Address &address)
1170{
1171 m_cur_insn = m_func_bounds.GetBaseAddress ();
Jason Molenda59762002010-11-04 00:53:20 +00001172 if (!m_cur_insn.IsValid())
1173 {
1174 return false;
1175 }
1176
Greg Claytondb598232011-01-07 01:57:07 +00001177 const bool prefer_file_cache = true;
Greg Clayton1ac04c32012-02-21 00:09:25 +00001178 Target *target = m_exe_ctx.GetTargetPtr();
Jason Molendafbcb7f22010-09-10 07:49:16 +00001179 while (m_func_bounds.ContainsFileAddress (m_cur_insn))
1180 {
1181 Error error;
1182 int insn_len, offset, regno;
1183 if (!instruction_length (m_cur_insn, insn_len) || insn_len > kMaxInstructionByteSize || insn_len == 0)
1184 {
1185 // An error parsing the instruction, i.e. probably data/garbage - stop scanning
1186 break;
1187 }
Saleem Abdulrasool3985c8c2014-04-02 03:51:35 +00001188 if (target->ReadMemory (m_cur_insn, prefer_file_cache, m_cur_insn_bytes,
1189 insn_len, error) == static_cast<size_t>(-1))
Jason Molendafbcb7f22010-09-10 07:49:16 +00001190 {
1191 // Error reading the instruction out of the file, stop scanning
1192 break;
1193 }
1194
1195 if (push_rbp_pattern_p () || mov_rsp_rbp_pattern_p () || sub_rsp_pattern_p (offset)
1196 || push_reg_p (regno) || mov_reg_to_local_stack_frame_p (regno, offset))
1197 {
1198 m_cur_insn.SetOffset (m_cur_insn.GetOffset() + insn_len);
1199 continue;
1200 }
1201
1202 // Unknown non-prologue instruction - stop scanning
1203 break;
1204 }
1205
1206 address = m_cur_insn;
1207 return true;
1208}
1209
1210
1211
1212
1213
1214
1215//-----------------------------------------------------------------------------------------------
Jason Molenda7b967f12014-08-25 23:46:06 +00001216// UnwindAssemblyParser_x86 method definitions
Jason Molendafbcb7f22010-09-10 07:49:16 +00001217//-----------------------------------------------------------------------------------------------
1218
Jason Molenda7b967f12014-08-25 23:46:06 +00001219UnwindAssembly_x86::UnwindAssembly_x86 (const ArchSpec &arch, int cpu) :
1220 lldb_private::UnwindAssembly(arch),
Jason Molendaa8399a82012-10-10 01:45:33 +00001221 m_cpu(cpu),
1222 m_arch(arch)
Greg Clayton2ed751b2011-04-26 04:39:08 +00001223{
1224}
1225
1226
1227UnwindAssembly_x86::~UnwindAssembly_x86 ()
1228{
1229}
1230
Jason Molendafbcb7f22010-09-10 07:49:16 +00001231bool
Greg Claytonffc922e32011-04-25 21:05:07 +00001232UnwindAssembly_x86::GetNonCallSiteUnwindPlanFromAssembly (AddressRange& func, Thread& thread, UnwindPlan& unwind_plan)
Jason Molendafbcb7f22010-09-10 07:49:16 +00001233{
Greg Clayton1ac04c32012-02-21 00:09:25 +00001234 ExecutionContext exe_ctx (thread.shared_from_this());
Jason Molendaa8399a82012-10-10 01:45:33 +00001235 AssemblyParse_x86 asm_parse(exe_ctx, m_cpu, m_arch, func);
Jason Molendafbcb7f22010-09-10 07:49:16 +00001236 return asm_parse.get_non_call_site_unwind_plan (unwind_plan);
1237}
1238
1239bool
Todd Fiala05625242014-08-25 20:29:09 +00001240UnwindAssembly_x86::AugmentUnwindPlanFromCallSite (AddressRange& func, Thread& thread, UnwindPlan& unwind_plan)
1241{
1242 ExecutionContext exe_ctx (thread.shared_from_this());
1243 AssemblyParse_x86 asm_parse(exe_ctx, m_cpu, m_arch, func);
1244 return asm_parse.augment_unwind_plan_from_call_site (func, unwind_plan);
1245}
1246
1247bool
Greg Claytonffc922e32011-04-25 21:05:07 +00001248UnwindAssembly_x86::GetFastUnwindPlan (AddressRange& func, Thread& thread, UnwindPlan &unwind_plan)
Jason Molendafbcb7f22010-09-10 07:49:16 +00001249{
Greg Clayton1ac04c32012-02-21 00:09:25 +00001250 ExecutionContext exe_ctx (thread.shared_from_this());
Jason Molendaa8399a82012-10-10 01:45:33 +00001251 AssemblyParse_x86 asm_parse(exe_ctx, m_cpu, m_arch, func);
Jason Molendaab4f1922010-10-25 11:12:07 +00001252 return asm_parse.get_fast_unwind_plan (func, unwind_plan);
Jason Molendafbcb7f22010-09-10 07:49:16 +00001253}
1254
1255bool
Greg Clayton1ac04c32012-02-21 00:09:25 +00001256UnwindAssembly_x86::FirstNonPrologueInsn (AddressRange& func, const ExecutionContext &exe_ctx, Address& first_non_prologue_insn)
Jason Molendafbcb7f22010-09-10 07:49:16 +00001257{
Jason Molendaa8399a82012-10-10 01:45:33 +00001258 AssemblyParse_x86 asm_parse(exe_ctx, m_cpu, m_arch, func);
Jason Molendafbcb7f22010-09-10 07:49:16 +00001259 return asm_parse.find_first_non_prologue_insn (first_non_prologue_insn);
1260}
1261
Greg Clayton7be25422011-04-25 21:14:26 +00001262UnwindAssembly *
Greg Claytonffc922e32011-04-25 21:05:07 +00001263UnwindAssembly_x86::CreateInstance (const ArchSpec &arch)
Jason Molendafbcb7f22010-09-10 07:49:16 +00001264{
Greg Clayton64195a22011-02-23 00:35:02 +00001265 const llvm::Triple::ArchType cpu = arch.GetMachine ();
1266 if (cpu == llvm::Triple::x86)
Greg Clayton2ed751b2011-04-26 04:39:08 +00001267 return new UnwindAssembly_x86 (arch, k_i386);
Greg Clayton64195a22011-02-23 00:35:02 +00001268 else if (cpu == llvm::Triple::x86_64)
Greg Clayton2ed751b2011-04-26 04:39:08 +00001269 return new UnwindAssembly_x86 (arch, k_x86_64);
Greg Clayton64195a22011-02-23 00:35:02 +00001270 return NULL;
Jason Molendafbcb7f22010-09-10 07:49:16 +00001271}
1272
1273
1274//------------------------------------------------------------------
1275// PluginInterface protocol in UnwindAssemblyParser_x86
1276//------------------------------------------------------------------
1277
Greg Clayton57abc5d2013-05-10 21:47:16 +00001278ConstString
Greg Claytonffc922e32011-04-25 21:05:07 +00001279UnwindAssembly_x86::GetPluginName()
Jason Molendafbcb7f22010-09-10 07:49:16 +00001280{
Greg Clayton57abc5d2013-05-10 21:47:16 +00001281 return GetPluginNameStatic();
Jason Molendafbcb7f22010-09-10 07:49:16 +00001282}
1283
1284
1285uint32_t
Greg Claytonffc922e32011-04-25 21:05:07 +00001286UnwindAssembly_x86::GetPluginVersion()
Jason Molendafbcb7f22010-09-10 07:49:16 +00001287{
1288 return 1;
1289}
1290
1291void
Greg Claytonffc922e32011-04-25 21:05:07 +00001292UnwindAssembly_x86::Initialize()
Jason Molendafbcb7f22010-09-10 07:49:16 +00001293{
1294 PluginManager::RegisterPlugin (GetPluginNameStatic(),
1295 GetPluginDescriptionStatic(),
1296 CreateInstance);
1297}
1298
1299void
Greg Claytonffc922e32011-04-25 21:05:07 +00001300UnwindAssembly_x86::Terminate()
Jason Molendafbcb7f22010-09-10 07:49:16 +00001301{
1302 PluginManager::UnregisterPlugin (CreateInstance);
1303}
1304
1305
Greg Clayton57abc5d2013-05-10 21:47:16 +00001306lldb_private::ConstString
Greg Claytonffc922e32011-04-25 21:05:07 +00001307UnwindAssembly_x86::GetPluginNameStatic()
Jason Molendafbcb7f22010-09-10 07:49:16 +00001308{
Greg Clayton57abc5d2013-05-10 21:47:16 +00001309 static ConstString g_name("x86");
1310 return g_name;
Jason Molendafbcb7f22010-09-10 07:49:16 +00001311}
1312
1313const char *
Greg Claytonffc922e32011-04-25 21:05:07 +00001314UnwindAssembly_x86::GetPluginDescriptionStatic()
Jason Molendafbcb7f22010-09-10 07:49:16 +00001315{
1316 return "i386 and x86_64 assembly language profiler plugin.";
1317}