blob: 0e2a4a7f7195155c14389394e8d39c90605ae480 [file] [log] [blame]
Jason Molenda3a4ea242010-09-10 07:49:16 +00001//===-- UnwindAssemblyProfiler-x86.cpp --------------------------*- C++ -*-===//
2//
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
10#include "UnwindAssemblyProfiler-x86.h"
11
12#include "lldb/lldb-private.h"
13#include "lldb/Utility/UnwindAssemblyProfiler.h"
14#include "lldb/Core/Address.h"
15#include "lldb/Core/Error.h"
16#include "lldb/Core/ArchSpec.h"
17#include "lldb/Core/PluginManager.h"
18#include "lldb/Target/ExecutionContext.h"
19#include "lldb/Target/Process.h"
20#include "lldb/Target/RegisterContext.h"
21#include "lldb/Target/Thread.h"
22#include "lldb/Target/Target.h"
23#include "lldb/Symbol/UnwindPlan.h"
24
25#include "lldb/lldb-enumerations.h"
26#include "llvm-c/EnhancedDisassembly.h"
27
28#include "UnwindAssemblyProfiler-x86.h"
29
30
31using namespace lldb;
32using namespace lldb_private;
33
34enum CPU {
35 k_i386,
36 k_x86_64
37};
38
39enum i386_register_numbers {
40 k_machine_eax = 0,
41 k_machine_ecx = 1,
42 k_machine_edx = 2,
43 k_machine_ebx = 3,
44 k_machine_esp = 4,
45 k_machine_ebp = 5,
46 k_machine_esi = 6,
47 k_machine_edi = 7,
48 k_machine_eip = 8
49};
50
51enum x86_64_register_numbers {
52 k_machine_rax = 0,
53 k_machine_rcx = 1,
54 k_machine_rdx = 2,
55 k_machine_rbx = 3,
56 k_machine_rsp = 4,
57 k_machine_rbp = 5,
58 k_machine_rsi = 6,
59 k_machine_rdi = 7,
60 k_machine_r8 = 8,
61 k_machine_r9 = 9,
62 k_machine_r10 = 10,
63 k_machine_r11 = 11,
64 k_machine_r12 = 12,
65 k_machine_r13 = 13,
66 k_machine_r14 = 14,
67 k_machine_r15 = 15,
68 k_machine_rip = 16
69};
70
71struct regmap_ent {
72 const char *name;
73 int machine_regno;
74 int lldb_regno;
75};
76
77static struct regmap_ent i386_register_map[] = {
78 {"eax", k_machine_eax, -1},
79 {"ecx", k_machine_ecx, -1},
80 {"edx", k_machine_edx, -1},
81 {"ebx", k_machine_ebx, -1},
82 {"esp", k_machine_esp, -1},
83 {"ebp", k_machine_ebp, -1},
84 {"esi", k_machine_esi, -1},
85 {"edi", k_machine_edi, -1},
86 {"eip", k_machine_eip, -1}
87};
88
89const int size_of_i386_register_map = sizeof (i386_register_map) / sizeof (struct regmap_ent);
90
91static int i386_register_map_initialized = 0;
92
93static struct regmap_ent x86_64_register_map[] = {
94 {"rax", k_machine_rax, -1},
95 {"rcx", k_machine_rcx, -1},
96 {"rdx", k_machine_rdx, -1},
97 {"rbx", k_machine_rbx, -1},
98 {"rsp", k_machine_rsp, -1},
99 {"rbp", k_machine_rbp, -1},
100 {"rsi", k_machine_rsi, -1},
101 {"rdi", k_machine_rdi, -1},
102 {"r8", k_machine_r8, -1},
103 {"r9", k_machine_r9, -1},
104 {"r10", k_machine_r10, -1},
105 {"r11", k_machine_r11, -1},
106 {"r12", k_machine_r12, -1},
107 {"r13", k_machine_r13, -1},
108 {"r14", k_machine_r14, -1},
109 {"r15", k_machine_r15, -1},
110 {"rip", k_machine_rip, -1}
111};
112
113const int size_of_x86_64_register_map = sizeof (x86_64_register_map) / sizeof (struct regmap_ent);
114
115static int x86_64_register_map_initialized = 0;
116
117//-----------------------------------------------------------------------------------------------
118// AssemblyParse_x86 local-file class definition & implementation functions
119//-----------------------------------------------------------------------------------------------
120
121class AssemblyParse_x86 {
122public:
123
124 AssemblyParse_x86 (Target &target, Thread *thread, int cpu, AddressRange func);
125
126 bool get_non_call_site_unwind_plan (UnwindPlan &unwind_plan);
127
Jason Molenda8280cbe2010-10-25 11:12:07 +0000128 bool get_fast_unwind_plan (AddressRange& func, UnwindPlan &unwind_plan);
Jason Molenda3a4ea242010-09-10 07:49:16 +0000129
130 bool find_first_non_prologue_insn (Address &address);
131
132private:
133 enum { kMaxInstructionByteSize = 32 };
134
135 bool nonvolatile_reg_p (int machine_regno);
136 bool push_rbp_pattern_p ();
137 bool push_0_pattern_p ();
138 bool mov_rsp_rbp_pattern_p ();
139 bool sub_rsp_pattern_p (int& amount);
140 bool push_reg_p (int& regno);
141 bool mov_reg_to_local_stack_frame_p (int& regno, int& fp_offset);
142 bool ret_pattern_p ();
143 uint32_t extract_4 (uint8_t *b);
144 bool machine_regno_to_lldb_regno (int machine_regno, uint32_t& lldb_regno);
145 bool instruction_length (Address addr, int &length);
146
147 Target &m_target;
148 Thread* m_thread;
149
150 AddressRange m_func_bounds;
151
152 Address m_cur_insn;
153 uint8_t m_cur_insn_bytes[kMaxInstructionByteSize];
154
155 int m_machine_ip_regnum;
156 int m_machine_sp_regnum;
157 int m_machine_fp_regnum;
158
159 int m_lldb_ip_regnum;
160 int m_lldb_sp_regnum;
161 int m_lldb_fp_regnum;
162
163 int m_wordsize;
164 int m_cpu;
165};
166
167AssemblyParse_x86::AssemblyParse_x86 (Target& target, Thread* thread, int cpu, AddressRange func) :
168 m_target (target), m_thread (thread), m_cpu(cpu), m_func_bounds(func)
Jason Molenda8280cbe2010-10-25 11:12:07 +0000169{
Jason Molenda3a4ea242010-09-10 07:49:16 +0000170 int *initialized_flag = NULL;
171 m_lldb_ip_regnum = m_lldb_sp_regnum = m_lldb_fp_regnum = -1;
172 if (cpu == k_i386)
173 {
174 m_machine_ip_regnum = k_machine_eip;
175 m_machine_sp_regnum = k_machine_esp;
176 m_machine_fp_regnum = k_machine_ebp;
177 m_wordsize = 4;
178 initialized_flag = &i386_register_map_initialized;
179 }
180 else
181 {
182 m_machine_ip_regnum = k_machine_rip;
183 m_machine_sp_regnum = k_machine_rsp;
184 m_machine_fp_regnum = k_machine_rbp;
185 m_wordsize = 8;
186 initialized_flag = &x86_64_register_map_initialized;
187 }
188
189 // we only look at prologue - it will be complete earlier than 512 bytes into func
190 if (m_func_bounds.GetByteSize() == 0)
191 m_func_bounds.SetByteSize(512);
192
193 if (m_thread && *initialized_flag == 0)
194 {
195 RegisterContext *rctx = m_thread->GetRegisterContext();
196 if (rctx)
197 {
198 struct regmap_ent *ent;
199 int count, i;
200 if (cpu == k_i386)
201 {
202 ent = i386_register_map;
203 count = size_of_i386_register_map;
204 }
205 else
206 {
207 ent = x86_64_register_map;
208 count = size_of_x86_64_register_map;
209 }
210 for (i = 0; i < count; i++, ent++)
211 {
212 const RegisterInfo *ri = rctx->GetRegisterInfoByName (ent->name);
213 if (ri)
214 ent->lldb_regno = ri->kinds[eRegisterKindLLDB];
215 }
216 *initialized_flag = 1;
217 }
218 }
219
220 // on initial construction we may not have a Thread so these have to remain
221 // uninitialized until we can get a RegisterContext to set up the register map table
222 if (*initialized_flag == 1)
223 {
224 uint32_t lldb_regno;
225 if (machine_regno_to_lldb_regno (m_machine_sp_regnum, lldb_regno))
226 m_lldb_sp_regnum = lldb_regno;
227 if (machine_regno_to_lldb_regno (m_machine_fp_regnum, lldb_regno))
228 m_lldb_fp_regnum = lldb_regno;
229 if (machine_regno_to_lldb_regno (m_machine_ip_regnum, lldb_regno))
230 m_lldb_ip_regnum = lldb_regno;
231 }
232}
233
234
235// This function expects an x86 native register number (i.e. the bits stripped out of the
236// actual instruction), not an lldb register number.
237
238bool
239AssemblyParse_x86::nonvolatile_reg_p (int machine_regno)
240{
241 if (m_cpu == k_i386)
242 {
243 switch (machine_regno) {
244 case k_machine_ebx:
245 case k_machine_ebp: // not actually a nonvolatile but often treated as such by convention
246 case k_machine_esi:
247 case k_machine_edi:
248 case k_machine_esp:
249 return true;
250 default:
251 return false;
252 }
253 }
254 if (m_cpu == k_x86_64)
255 {
256 switch (machine_regno) {
257 case k_machine_rbx:
258 case k_machine_rsp:
259 case k_machine_rbp: // not actually a nonvolatile but often treated as such by convention
260 case k_machine_r12:
261 case k_machine_r13:
262 case k_machine_r14:
263 case k_machine_r15:
264 return true;
265 default:
266 return false;
267 }
268 }
269 return false;
270}
271
272
273// Macro to detect if this is a REX mode prefix byte.
274#define REX_W_PREFIX_P(opcode) (((opcode) & (~0x5)) == 0x48)
275
276// The high bit which should be added to the source register number (the "R" bit)
277#define REX_W_SRCREG(opcode) (((opcode) & 0x4) >> 2)
278
279// The high bit which should be added to the destination register number (the "B" bit)
280#define REX_W_DSTREG(opcode) ((opcode) & 0x1)
281
282// pushq %rbp [0x55]
283bool AssemblyParse_x86::push_rbp_pattern_p () {
284 uint8_t *p = m_cur_insn_bytes;
285 if (*p == 0x55)
286 return true;
287 return false;
288}
289
290// pushq $0 ; the first instruction in start() [0x6a 0x00]
291bool AssemblyParse_x86::push_0_pattern_p ()
292{
293 uint8_t *p = m_cur_insn_bytes;
294 if (*p == 0x6a && *(p + 1) == 0x0)
295 return true;
296 return false;
297}
298
299// movq %rsp, %rbp [0x48 0x8b 0xec] or [0x48 0x89 0xe5]
300// movl %esp, %ebp [0x8b 0xec] or [0x89 0xe5]
301bool AssemblyParse_x86::mov_rsp_rbp_pattern_p () {
302 uint8_t *p = m_cur_insn_bytes;
303 if (m_wordsize == 8 && *p == 0x48)
304 p++;
305 if (*(p) == 0x8b && *(p + 1) == 0xec)
306 return true;
307 if (*(p) == 0x89 && *(p + 1) == 0xe5)
308 return true;
309 return false;
310}
311
312// subq $0x20, %rsp
313bool AssemblyParse_x86::sub_rsp_pattern_p (int& amount) {
314 uint8_t *p = m_cur_insn_bytes;
315 if (m_wordsize == 8 && *p == 0x48)
316 p++;
317 // 8-bit immediate operand
318 if (*p == 0x83 && *(p + 1) == 0xec) {
319 amount = (int8_t) *(p + 2);
320 return true;
321 }
322 // 32-bit immediate operand
323 if (*p == 0x81 && *(p + 1) == 0xec) {
324 amount = (int32_t) extract_4 (p + 2);
325 return true;
326 }
327 // Not handled: [0x83 0xc4] for imm8 with neg values
328 // [0x81 0xc4] for imm32 with neg values
329 return false;
330}
331
332// pushq %rbx
333// pushl $ebx
334bool AssemblyParse_x86::push_reg_p (int& regno) {
335 uint8_t *p = m_cur_insn_bytes;
336 int regno_prefix_bit = 0;
337 // If we have a rex prefix byte, check to see if a B bit is set
338 if (m_wordsize == 8 && *p == 0x41) {
339 regno_prefix_bit = 1 << 3;
340 p++;
341 }
342 if (*p >= 0x50 && *p <= 0x57) {
343 regno = (*p - 0x50) | regno_prefix_bit;
344 return true;
345 }
346 return false;
347}
348
349// Look for an instruction sequence storing a nonvolatile register
350// on to the stack frame.
351
352// movq %rax, -0x10(%rbp) [0x48 0x89 0x45 0xf0]
353// movl %eax, -0xc(%ebp) [0x89 0x45 0xf4]
354bool AssemblyParse_x86::mov_reg_to_local_stack_frame_p (int& regno, int& rbp_offset) {
355 uint8_t *p = m_cur_insn_bytes;
356 int src_reg_prefix_bit = 0;
357 int target_reg_prefix_bit = 0;
358
359 if (m_wordsize == 8 && REX_W_PREFIX_P (*p)) {
360 src_reg_prefix_bit = REX_W_SRCREG (*p) << 3;
361 target_reg_prefix_bit = REX_W_DSTREG (*p) << 3;
362 if (target_reg_prefix_bit == 1) {
363 // rbp/ebp don't need a prefix bit - we know this isn't the
364 // reg we care about.
365 return false;
366 }
367 p++;
368 }
369
370 if (*p == 0x89) {
371 /* Mask off the 3-5 bits which indicate the destination register
372 if this is a ModR/M byte. */
373 int opcode_destreg_masked_out = *(p + 1) & (~0x38);
374
375 /* Is this a ModR/M byte with Mod bits 01 and R/M bits 101
376 and three bits between them, e.g. 01nnn101
377 We're looking for a destination of ebp-disp8 or ebp-disp32. */
378 int immsize;
379 if (opcode_destreg_masked_out == 0x45)
380 immsize = 2;
381 else if (opcode_destreg_masked_out == 0x85)
382 immsize = 4;
383 else
384 return false;
385
386 int offset = 0;
387 if (immsize == 2)
388 offset = (int8_t) *(p + 2);
389 if (immsize == 4)
390 offset = (uint32_t) extract_4 (p + 2);
391 if (offset > 0)
392 return false;
393
394 regno = ((*(p + 1) >> 3) & 0x7) | src_reg_prefix_bit;
395 rbp_offset = offset > 0 ? offset : -offset;
396 return true;
397 }
398 return false;
399}
400
401// ret [0xc9] or [0xc2 imm8] or [0xca imm8]
402bool
403AssemblyParse_x86::ret_pattern_p ()
404{
405 uint8_t *p = m_cur_insn_bytes;
406 if (*p == 0xc9 || *p == 0xc2 || *p == 0xca || *p == 0xc3)
407 return true;
408 return false;
409}
410
411uint32_t
412AssemblyParse_x86::extract_4 (uint8_t *b)
413{
414 uint32_t v = 0;
415 for (int i = 3; i >= 0; i--)
416 v = (v << 8) | b[i];
417 return v;
418}
419
420bool
421AssemblyParse_x86::machine_regno_to_lldb_regno (int machine_regno, uint32_t &lldb_regno)
422{
423 struct regmap_ent *ent;
424 int count, i;
425 if (m_cpu == k_i386)
426 {
427 ent = i386_register_map;
428 count = size_of_i386_register_map;
429 }
430 else
431 {
432 ent = x86_64_register_map;
433 count = size_of_x86_64_register_map;
434 }
435 for (i = 0; i < count; i++, ent++)
436 {
437 if (ent->machine_regno == machine_regno)
438 if (ent->lldb_regno != -1)
439 {
440 lldb_regno = ent->lldb_regno;
441 return true;
442 }
443 }
444 return false;
445}
446
447struct edis_byte_read_token
448{
449 Address *address;
450 Target *target;
451};
452
453
454static int
455read_byte_for_edis (uint8_t *buf, uint64_t offset_address, void *arg)
456{
457 if (arg == 0)
458 return -1;
459 struct edis_byte_read_token *tok = (edis_byte_read_token *) arg;
460 Address *base_address = tok->address;
461 Target *target = tok->target;
462
463 Address read_addr = *base_address;
464 read_addr.SetOffset (offset_address);
465
466 uint8_t onebyte_buf[1];
467 Error error;
468 if (target->ReadMemory (read_addr, onebyte_buf, 1, error) != -1)
469 {
470 *buf = onebyte_buf[0];
471 return 0;
472 }
473 return -1;
474}
475
476
477bool
478AssemblyParse_x86::instruction_length (Address addr, int &length)
479{
480 const char *triple;
481 // FIXME should probably pass down the ArchSpec and work from that to make a portable triple
482 if (m_cpu == k_i386)
483 triple = "i386-apple-darwin";
484 else
485 triple = "x86_64-apple-darwin";
486
487 EDDisassemblerRef disasm;
488 EDInstRef cur_insn;
489
490 if (EDGetDisassembler (&disasm, "i386-apple-darwin", kEDAssemblySyntaxX86ATT) != 0)
491 {
Jason Molenda8280cbe2010-10-25 11:12:07 +0000492 return false;
Jason Molenda3a4ea242010-09-10 07:49:16 +0000493 }
494
495 uint64_t addr_offset = addr.GetOffset();
496 struct edis_byte_read_token arg;
497 arg.address = &addr;
498 arg.target = &m_target;
499 if (EDCreateInsts (&cur_insn, 1, disasm, read_byte_for_edis, addr_offset, &arg) != 1)
500 {
Jason Molenda8280cbe2010-10-25 11:12:07 +0000501 return false;
Jason Molenda3a4ea242010-09-10 07:49:16 +0000502 }
503 length = EDInstByteSize (cur_insn);
504 EDReleaseInst (cur_insn);
505 return true;
506}
507
508
509bool
510AssemblyParse_x86::get_non_call_site_unwind_plan (UnwindPlan &unwind_plan)
511{
512 UnwindPlan up;
513 UnwindPlan::Row row;
514 int non_prologue_insn_count = 0;
515 Address m_cur_insn = m_func_bounds.GetBaseAddress ();
516 int current_func_text_offset = 0;
517 int current_sp_bytes_offset_from_cfa = 0;
518 UnwindPlan::Row::RegisterLocation regloc;
519
520 unwind_plan.SetPlanValidAddressRange (m_func_bounds);
521 unwind_plan.SetRegisterKind (eRegisterKindLLDB);
522
523 // At the start of the function, find the CFA by adding wordsize to the SP register
524 row.SetOffset (current_func_text_offset);
525 row.SetCFARegister (m_lldb_sp_regnum);
526 row.SetCFAOffset (m_wordsize);
527
528 // caller's stack pointer value before the call insn is the CFA address
529 regloc.SetIsCFAPlusOffset (0);
530 row.SetRegisterInfo (m_lldb_sp_regnum, regloc);
531
532 // saved instruction pointer can be found at CFA - wordsize.
533 current_sp_bytes_offset_from_cfa = m_wordsize;
534 regloc.SetAtCFAPlusOffset (-current_sp_bytes_offset_from_cfa);
535 row.SetRegisterInfo (m_lldb_ip_regnum, regloc);
536
537 unwind_plan.AppendRow (row);
538
539 while (m_func_bounds.ContainsFileAddress (m_cur_insn) && non_prologue_insn_count < 10)
540 {
541 int stack_offset, insn_len;
542 int machine_regno; // register numbers masked directly out of instructions
543 uint32_t lldb_regno; // register numbers in lldb's eRegisterKindLLDB numbering scheme
544 Error error;
545
546 if (!instruction_length (m_cur_insn, insn_len) || insn_len == 0 || insn_len > kMaxInstructionByteSize)
547 {
548 // An unrecognized/junk instruction
549 break;
550 }
551 if (m_target.ReadMemory (m_cur_insn, m_cur_insn_bytes, insn_len, error) == -1)
552 {
553 // Error reading the instruction out of the file, stop scanning
554 break;
555 }
556
557 if (push_rbp_pattern_p ())
558 {
559 row.SetOffset (current_func_text_offset + insn_len);
560 current_sp_bytes_offset_from_cfa += m_wordsize;
561 row.SetCFAOffset (current_sp_bytes_offset_from_cfa);
562 UnwindPlan::Row::RegisterLocation regloc;
563 regloc.SetAtCFAPlusOffset (-row.GetCFAOffset());
564 row.SetRegisterInfo (m_lldb_fp_regnum, regloc);
565 unwind_plan.AppendRow (row);
566 goto loopnext;
567 }
568
Jason Molenda8280cbe2010-10-25 11:12:07 +0000569 // This is the start() function (or a pthread equivalent), it starts with a pushl $0x0 which puts the
570 // saved pc value of 0 on the stack. In this case we want to pretend we didn't see a stack movement at all --
571 // normally the saved pc value is already on the stack by the time the function starts executing.
Jason Molenda3a4ea242010-09-10 07:49:16 +0000572 if (push_0_pattern_p ())
573 {
Jason Molenda3a4ea242010-09-10 07:49:16 +0000574 goto loopnext;
575 }
576
577 if (push_reg_p (machine_regno))
578 {
579 current_sp_bytes_offset_from_cfa += m_wordsize;
580 if (nonvolatile_reg_p (machine_regno) && machine_regno_to_lldb_regno (machine_regno, lldb_regno))
581 {
582 row.SetOffset (current_func_text_offset + insn_len);
583 if (row.GetCFARegister() == m_lldb_sp_regnum)
584 {
585 row.SetCFAOffset (current_sp_bytes_offset_from_cfa);
586 }
587 UnwindPlan::Row::RegisterLocation regloc;
588 regloc.SetAtCFAPlusOffset (-current_sp_bytes_offset_from_cfa);
589 row.SetRegisterInfo (lldb_regno, regloc);
590 unwind_plan.AppendRow (row);
591 }
592 goto loopnext;
593 }
594
595 if (mov_reg_to_local_stack_frame_p (machine_regno, stack_offset) && nonvolatile_reg_p (machine_regno))
596 {
597 if (machine_regno_to_lldb_regno (machine_regno, lldb_regno))
598 {
599 row.SetOffset (current_func_text_offset + insn_len);
600 UnwindPlan::Row::RegisterLocation regloc;
601 regloc.SetAtCFAPlusOffset (-row.GetCFAOffset());
602 row.SetRegisterInfo (lldb_regno, regloc);
603 unwind_plan.AppendRow (row);
604 goto loopnext;
605 }
606 }
607
608 if (sub_rsp_pattern_p (stack_offset))
609 {
610 current_sp_bytes_offset_from_cfa += stack_offset;
611 if (row.GetCFARegister() == m_lldb_sp_regnum)
612 {
613 row.SetOffset (current_func_text_offset + insn_len);
614 row.SetCFAOffset (current_sp_bytes_offset_from_cfa);
615 unwind_plan.AppendRow (row);
616 }
617 goto loopnext;
618 }
619
620 if (mov_rsp_rbp_pattern_p ())
621 {
622 row.SetOffset (current_func_text_offset + insn_len);
623 row.SetCFARegister (m_lldb_fp_regnum);
624 unwind_plan.AppendRow (row);
625 goto loopnext;
626 }
627
628 if (ret_pattern_p ())
629 {
630 // we know where the end of the function is; set the limit on the PlanValidAddressRange
631 // in case our initial "high pc" value was overly large
632 // int original_size = m_func_bounds.GetByteSize();
633 // int calculated_size = m_cur_insn.GetOffset() - m_func_bounds.GetBaseAddress().GetOffset() + insn_len + 1;
634 // m_func_bounds.SetByteSize (calculated_size);
635 // unwind_plan.SetPlanValidAddressRange (m_func_bounds);
636 break;
637 }
638
639 // FIXME recognize the i386 picbase setup instruction sequence,
640 // 0x1f16: call 0x1f1b ; main + 11 at /private/tmp/a.c:3
641 // 0x1f1b: popl %eax
642 // and record the temporary stack movements if the CFA is not expressed in terms of ebp.
643
644 non_prologue_insn_count++;
645loopnext:
646 m_cur_insn.SetOffset (m_cur_insn.GetOffset() + insn_len);
647 current_func_text_offset += insn_len;
648 }
649
Jason Molenda8280cbe2010-10-25 11:12:07 +0000650 unwind_plan.SetSourceName ("assembly insn profiling");
651
Jason Molenda3a4ea242010-09-10 07:49:16 +0000652 return true;
653}
654
Jason Molenda8280cbe2010-10-25 11:12:07 +0000655/* The "fast unwind plan" is valid for functions that follow the usual convention of
656 using the frame pointer register (ebp, rbp), i.e. the function prologue looks like
657 push %rbp [0x55]
658 mov %rsp,%rbp [0x48 0x89 0xe5] (this is a 2-byte insn seq on i386)
659*/
660
Jason Molenda3a4ea242010-09-10 07:49:16 +0000661bool
Jason Molenda8280cbe2010-10-25 11:12:07 +0000662AssemblyParse_x86::get_fast_unwind_plan (AddressRange& func, UnwindPlan &unwind_plan)
Jason Molenda3a4ea242010-09-10 07:49:16 +0000663{
Jason Molenda8280cbe2010-10-25 11:12:07 +0000664 UnwindPlan::Row row;
665 UnwindPlan::Row::RegisterLocation pc_reginfo;
666 UnwindPlan::Row::RegisterLocation sp_reginfo;
667 UnwindPlan::Row::RegisterLocation fp_reginfo;
668 unwind_plan.SetRegisterKind (eRegisterKindLLDB);
669
670 if (!func.GetBaseAddress().IsValid())
671 return false;
672
673 uint8_t bytebuf[4];
674 Error error;
675 if (m_target.ReadMemory (func.GetBaseAddress(), bytebuf, sizeof (bytebuf), error) == -1)
676 return false;
677
678 uint8_t i386_prologue[] = {0x55, 0x89, 0xe5};
679 uint8_t x86_64_prologue[] = {0x55, 0x48, 0x89, 0xe5};
680 int prologue_size;
681
682 if (memcmp (bytebuf, i386_prologue, sizeof (i386_prologue)) == 0)
683 {
684 prologue_size = sizeof (i386_prologue);
685 }
686 else if (memcmp (bytebuf, x86_64_prologue, sizeof (x86_64_prologue)) == 0)
687 {
688 prologue_size = sizeof (x86_64_prologue);
689 }
690 else
691 {
692 return false;
693 }
694
695 pc_reginfo.SetAtCFAPlusOffset (-m_wordsize);
696 row.SetRegisterInfo (m_lldb_ip_regnum, pc_reginfo);
697
698 sp_reginfo.SetIsCFAPlusOffset (0);
699 row.SetRegisterInfo (m_lldb_sp_regnum, sp_reginfo);
700
701 // Zero instructions into the function
702 row.SetCFARegister (m_lldb_sp_regnum);
703 row.SetCFAOffset (m_wordsize);
704 row.SetOffset (0);
705 unwind_plan.AppendRow (row);
706
707 // push %rbp has executed - stack moved, rbp now saved
708 row.SetCFAOffset (2 * m_wordsize);
709 fp_reginfo.SetAtCFAPlusOffset (2 * -m_wordsize);
710 row.SetRegisterInfo (m_lldb_fp_regnum, fp_reginfo);
711 row.SetOffset (1);
712 unwind_plan.AppendRow (row);
713
714 // mov %rsp, %rbp has executed
715 row.SetCFARegister (m_lldb_fp_regnum);
716 row.SetCFAOffset (2 * m_wordsize);
717 row.SetOffset (prologue_size); /// 3 or 4 bytes depending on arch
718 unwind_plan.AppendRow (row);
719
720 unwind_plan.SetPlanValidAddressRange (func);
721 return true;
Jason Molenda3a4ea242010-09-10 07:49:16 +0000722}
723
724bool
725AssemblyParse_x86::find_first_non_prologue_insn (Address &address)
726{
727 m_cur_insn = m_func_bounds.GetBaseAddress ();
728 while (m_func_bounds.ContainsFileAddress (m_cur_insn))
729 {
730 Error error;
731 int insn_len, offset, regno;
732 if (!instruction_length (m_cur_insn, insn_len) || insn_len > kMaxInstructionByteSize || insn_len == 0)
733 {
734 // An error parsing the instruction, i.e. probably data/garbage - stop scanning
735 break;
736 }
737 if (m_target.ReadMemory (m_cur_insn, m_cur_insn_bytes, insn_len, error) == -1)
738 {
739 // Error reading the instruction out of the file, stop scanning
740 break;
741 }
742
743 if (push_rbp_pattern_p () || mov_rsp_rbp_pattern_p () || sub_rsp_pattern_p (offset)
744 || push_reg_p (regno) || mov_reg_to_local_stack_frame_p (regno, offset))
745 {
746 m_cur_insn.SetOffset (m_cur_insn.GetOffset() + insn_len);
747 continue;
748 }
749
750 // Unknown non-prologue instruction - stop scanning
751 break;
752 }
753
754 address = m_cur_insn;
755 return true;
756}
757
758
759
760
761
762
763//-----------------------------------------------------------------------------------------------
764// UnwindAssemblyParser_x86 method definitions
765//-----------------------------------------------------------------------------------------------
766
767bool
768UnwindAssemblyProfiler_x86::GetNonCallSiteUnwindPlanFromAssembly (AddressRange& func, Thread& thread, UnwindPlan& unwind_plan)
769{
770 AssemblyParse_x86 asm_parse(thread.GetProcess().GetTarget(), &thread, m_cpu, func);
771 return asm_parse.get_non_call_site_unwind_plan (unwind_plan);
772}
773
774bool
775UnwindAssemblyProfiler_x86::GetFastUnwindPlan (AddressRange& func, Thread& thread, UnwindPlan &unwind_plan)
776{
777 AssemblyParse_x86 asm_parse(thread.GetProcess().GetTarget(), &thread, m_cpu, func);
Jason Molenda8280cbe2010-10-25 11:12:07 +0000778 return asm_parse.get_fast_unwind_plan (func, unwind_plan);
Jason Molenda3a4ea242010-09-10 07:49:16 +0000779}
780
781bool
782UnwindAssemblyProfiler_x86::FirstNonPrologueInsn (AddressRange& func, Target& target, Thread* thread, Address& first_non_prologue_insn)
783{
784 AssemblyParse_x86 asm_parse(target, thread, m_cpu, func);
785 return asm_parse.find_first_non_prologue_insn (first_non_prologue_insn);
786}
787
788lldb_private::UnwindAssemblyProfiler *
789UnwindAssemblyProfiler_x86::CreateInstance (const lldb_private::ArchSpec &arch)
790{
791 uint32_t cpu = arch.GetCPUType ();
792 if (cpu != CPU_TYPE_X86_64 && cpu != CPU_TYPE_I386)
793 return NULL;
794
795 return new UnwindAssemblyProfiler_x86 (cpu == CPU_TYPE_X86_64 ? k_x86_64 : k_i386);
796}
797
798
799//------------------------------------------------------------------
800// PluginInterface protocol in UnwindAssemblyParser_x86
801//------------------------------------------------------------------
802
803const char *
804UnwindAssemblyProfiler_x86::GetPluginName()
805{
806 return "UnwindAssemblyProfiler_x86";
807}
808
809const char *
810UnwindAssemblyProfiler_x86::GetShortPluginName()
811{
812 return "unwindassemblyprofiler.x86";
813}
814
815
816uint32_t
817UnwindAssemblyProfiler_x86::GetPluginVersion()
818{
819 return 1;
820}
821
822void
823UnwindAssemblyProfiler_x86::GetPluginCommandHelp (const char *command, Stream *strm)
824{
825}
826
827Error
828UnwindAssemblyProfiler_x86::ExecutePluginCommand (Args &command, Stream *strm)
829{
830 Error error;
831 error.SetErrorString("No plug-in command are currently supported.");
832 return error;
833}
834
835Log *
836UnwindAssemblyProfiler_x86::EnablePluginLogging (Stream *strm, Args &command)
837{
838 return NULL;
839}
840
841void
842UnwindAssemblyProfiler_x86::Initialize()
843{
844 PluginManager::RegisterPlugin (GetPluginNameStatic(),
845 GetPluginDescriptionStatic(),
846 CreateInstance);
847}
848
849void
850UnwindAssemblyProfiler_x86::Terminate()
851{
852 PluginManager::UnregisterPlugin (CreateInstance);
853}
854
855
856const char *
857UnwindAssemblyProfiler_x86::GetPluginNameStatic()
858{
859 return "UnwindAssemblyProfiler_x86";
860}
861
862const char *
863UnwindAssemblyProfiler_x86::GetPluginDescriptionStatic()
864{
865 return "i386 and x86_64 assembly language profiler plugin.";
866}