LLDB  mainline
UnwindAssembly-x86.cpp
Go to the documentation of this file.
1 //===-- UnwindAssembly-x86.cpp ----------------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "UnwindAssembly-x86.h"
11 
12 #include "llvm-c/Disassembler.h"
13 #include "llvm/ADT/STLExtras.h"
14 #include "llvm/Support/TargetSelect.h"
15 
16 #include "lldb/Core/Address.h"
18 #include "lldb/Symbol/UnwindPlan.h"
19 #include "lldb/Target/ABI.h"
21 #include "lldb/Target/Process.h"
24 #include "lldb/Target/Target.h"
25 #include "lldb/Target/Thread.h"
27 #include "lldb/Utility/ArchSpec.h"
28 #include "lldb/Utility/Status.h"
29 
30 using namespace lldb;
31 using namespace lldb_private;
32 
33 // UnwindAssemblyParser_x86 method definitions
34 
35 UnwindAssembly_x86::UnwindAssembly_x86(const ArchSpec &arch)
37  m_assembly_inspection_engine(new x86AssemblyInspectionEngine(arch)) {}
38 
40  delete m_assembly_inspection_engine;
41 }
42 
44  AddressRange &func, Thread &thread, UnwindPlan &unwind_plan) {
45  if (!func.GetBaseAddress().IsValid() || func.GetByteSize() == 0)
46  return false;
47  if (m_assembly_inspection_engine == nullptr)
48  return false;
49  ProcessSP process_sp(thread.GetProcess());
50  if (process_sp.get() == nullptr)
51  return false;
52  const bool prefer_file_cache = true;
53  std::vector<uint8_t> function_text(func.GetByteSize());
54  Status error;
55  if (process_sp->GetTarget().ReadMemory(
56  func.GetBaseAddress(), prefer_file_cache, function_text.data(),
57  func.GetByteSize(), error) == func.GetByteSize()) {
58  RegisterContextSP reg_ctx(thread.GetRegisterContext());
59  m_assembly_inspection_engine->Initialize(reg_ctx);
60  return m_assembly_inspection_engine->GetNonCallSiteUnwindPlanFromAssembly(
61  function_text.data(), func.GetByteSize(), func, unwind_plan);
62  }
63  return false;
64 }
65 
67  AddressRange &func, Thread &thread, UnwindPlan &unwind_plan) {
68  bool do_augment_unwindplan = true;
69 
70  UnwindPlan::RowSP first_row = unwind_plan.GetRowForFunctionOffset(0);
71  UnwindPlan::RowSP last_row = unwind_plan.GetRowForFunctionOffset(-1);
72 
73  int wordsize = 8;
74  ProcessSP process_sp(thread.GetProcess());
75  if (process_sp.get() == nullptr)
76  return false;
77 
78  wordsize = process_sp->GetTarget().GetArchitecture().GetAddressByteSize();
79 
80  RegisterNumber sp_regnum(thread, eRegisterKindGeneric,
82  RegisterNumber pc_regnum(thread, eRegisterKindGeneric,
84 
85  // Does this UnwindPlan describe the prologue? I want to see that the CFA is
86  // set in terms of the stack pointer plus an offset, and I want to see that
87  // rip is retrieved at the CFA-wordsize. If there is no description of the
88  // prologue, don't try to augment this eh_frame unwinder code, fall back to
89  // assembly parsing instead.
90 
91  if (first_row->GetCFAValue().GetValueType() !=
93  RegisterNumber(thread, unwind_plan.GetRegisterKind(),
94  first_row->GetCFAValue().GetRegisterNumber()) !=
95  sp_regnum ||
96  first_row->GetCFAValue().GetOffset() != wordsize) {
97  return false;
98  }
99  UnwindPlan::Row::RegisterLocation first_row_pc_loc;
100  if (!first_row->GetRegisterInfo(
101  pc_regnum.GetAsKind(unwind_plan.GetRegisterKind()),
102  first_row_pc_loc) ||
103  !first_row_pc_loc.IsAtCFAPlusOffset() ||
104  first_row_pc_loc.GetOffset() != -wordsize) {
105  return false;
106  }
107 
108  // It looks like the prologue is described. Is the epilogue described? If it
109  // is, no need to do any augmentation.
110 
111  if (first_row != last_row &&
112  first_row->GetOffset() != last_row->GetOffset()) {
113  // The first & last row have the same CFA register and the same CFA offset
114  // value and the CFA register is esp/rsp (the stack pointer).
115 
116  // We're checking that both of them have an unwind rule like "CFA=esp+4" or
117  // CFA+rsp+8".
118 
119  if (first_row->GetCFAValue().GetValueType() ==
120  last_row->GetCFAValue().GetValueType() &&
121  first_row->GetCFAValue().GetRegisterNumber() ==
122  last_row->GetCFAValue().GetRegisterNumber() &&
123  first_row->GetCFAValue().GetOffset() ==
124  last_row->GetCFAValue().GetOffset()) {
125  // Get the register locations for eip/rip from the first & last rows. Are
126  // they both CFA plus an offset? Is it the same offset?
127 
128  UnwindPlan::Row::RegisterLocation last_row_pc_loc;
129  if (last_row->GetRegisterInfo(
130  pc_regnum.GetAsKind(unwind_plan.GetRegisterKind()),
131  last_row_pc_loc)) {
132  if (last_row_pc_loc.IsAtCFAPlusOffset() &&
133  first_row_pc_loc.GetOffset() == last_row_pc_loc.GetOffset()) {
134 
135  // One last sanity check: Is the unwind rule for getting the caller
136  // pc value "deref the CFA-4" or "deref the CFA-8"?
137 
138  // If so, we have an UnwindPlan that already describes the epilogue
139  // and we don't need to modify it at all.
140 
141  if (first_row_pc_loc.GetOffset() == -wordsize) {
142  do_augment_unwindplan = false;
143  }
144  }
145  }
146  }
147  }
148 
149  if (do_augment_unwindplan) {
150  if (!func.GetBaseAddress().IsValid() || func.GetByteSize() == 0)
151  return false;
152  if (m_assembly_inspection_engine == nullptr)
153  return false;
154  const bool prefer_file_cache = true;
155  std::vector<uint8_t> function_text(func.GetByteSize());
156  Status error;
157  if (process_sp->GetTarget().ReadMemory(
158  func.GetBaseAddress(), prefer_file_cache, function_text.data(),
159  func.GetByteSize(), error) == func.GetByteSize()) {
160  RegisterContextSP reg_ctx(thread.GetRegisterContext());
161  m_assembly_inspection_engine->Initialize(reg_ctx);
162  return m_assembly_inspection_engine->AugmentUnwindPlanFromCallSite(
163  function_text.data(), func.GetByteSize(), func, unwind_plan, reg_ctx);
164  }
165  }
166 
167  return false;
168 }
169 
171  UnwindPlan &unwind_plan) {
172  // if prologue is
173  // 55 pushl %ebp
174  // 89 e5 movl %esp, %ebp
175  // or
176  // 55 pushq %rbp
177  // 48 89 e5 movq %rsp, %rbp
178 
179  // We should pull in the ABI architecture default unwind plan and return that
180 
181  llvm::SmallVector<uint8_t, 4> opcode_data;
182 
183  ProcessSP process_sp = thread.GetProcess();
184  if (process_sp) {
185  Target &target(process_sp->GetTarget());
186  const bool prefer_file_cache = true;
187  Status error;
188  if (target.ReadMemory(func.GetBaseAddress(), prefer_file_cache,
189  opcode_data.data(), 4, error) == 4) {
190  uint8_t i386_push_mov[] = {0x55, 0x89, 0xe5};
191  uint8_t x86_64_push_mov[] = {0x55, 0x48, 0x89, 0xe5};
192 
193  if (memcmp(opcode_data.data(), i386_push_mov, sizeof(i386_push_mov)) ==
194  0 ||
195  memcmp(opcode_data.data(), x86_64_push_mov,
196  sizeof(x86_64_push_mov)) == 0) {
197  ABISP abi_sp = process_sp->GetABI();
198  if (abi_sp) {
199  return abi_sp->CreateDefaultUnwindPlan(unwind_plan);
200  }
201  }
202  }
203  }
204  return false;
205 }
206 
208  AddressRange &func, const ExecutionContext &exe_ctx,
209  Address &first_non_prologue_insn) {
210 
211  if (!func.GetBaseAddress().IsValid())
212  return false;
213 
214  Target *target = exe_ctx.GetTargetPtr();
215  if (target == nullptr)
216  return false;
217 
218  if (m_assembly_inspection_engine == nullptr)
219  return false;
220 
221  const bool prefer_file_cache = true;
222  std::vector<uint8_t> function_text(func.GetByteSize());
223  Status error;
224  if (target->ReadMemory(func.GetBaseAddress(), prefer_file_cache,
225  function_text.data(), func.GetByteSize(),
226  error) == func.GetByteSize()) {
227  size_t offset;
228  if (m_assembly_inspection_engine->FindFirstNonPrologueInstruction(
229  function_text.data(), func.GetByteSize(), offset)) {
230  first_non_prologue_insn = func.GetBaseAddress();
231  first_non_prologue_insn.Slide(offset);
232  }
233  return true;
234  }
235  return false;
236 }
237 
239  const llvm::Triple::ArchType cpu = arch.GetMachine();
240  if (cpu == llvm::Triple::x86 || cpu == llvm::Triple::x86_64)
241  return new UnwindAssembly_x86(arch);
242  return NULL;
243 }
244 
245 // PluginInterface protocol in UnwindAssemblyParser_x86
246 
248  return GetPluginNameStatic();
249 }
250 
252 
254  PluginManager::RegisterPlugin(GetPluginNameStatic(),
255  GetPluginDescriptionStatic(), CreateInstance);
256 }
257 
259  PluginManager::UnregisterPlugin(CreateInstance);
260 }
261 
263  static ConstString g_name("x86");
264  return g_name;
265 }
266 
268  return "i386 and x86_64 assembly language profiler plugin.";
269 }
#define LLDB_REGNUM_GENERIC_PC
Definition: lldb-defines.h:63
lldb::RegisterKind GetRegisterKind() const
Definition: UnwindPlan.h:406
Enumerations for broadcasting.
Definition: SBLaunchInfo.h:14
lldb::addr_t GetByteSize() const
Get accessor for the byte size of this range.
Definition: AddressRange.h:232
bool AugmentUnwindPlanFromCallSite(lldb_private::AddressRange &func, lldb_private::Thread &thread, lldb_private::UnwindPlan &unwind_plan) override
static lldb_private::ConstString GetPluginNameStatic()
lldb_private::ConstString GetPluginName() override
static bool RegisterPlugin(ConstString name, const char *description, ABICreateInstance create_callback)
An architecture specification class.
Definition: ArchSpec.h:32
uint32_t GetAsKind(lldb::RegisterKind kind)
"lldb/Target/ExecutionContext.h" A class that contains an execution context.
#define LLDB_REGNUM_GENERIC_SP
Definition: lldb-defines.h:64
bool GetNonCallSiteUnwindPlanFromAssembly(lldb_private::AddressRange &func, lldb_private::Thread &thread, lldb_private::UnwindPlan &unwind_plan) override
uint32_t GetPluginVersion() override
bool Slide(int64_t offset)
Definition: Address.h:430
Target * GetTargetPtr() const
Returns a pointer to the target object.
std::shared_ptr< Row > RowSP
Definition: UnwindPlan.h:366
virtual lldb::RegisterContextSP GetRegisterContext()=0
A section + offset based address class.
Definition: Address.h:80
bool IsValid() const
Check if the object state is valid.
Definition: Address.h:343
static const char * GetPluginDescriptionStatic()
lldb::ProcessSP GetProcess() const
Definition: Thread.h:154
bool FirstNonPrologueInsn(lldb_private::AddressRange &func, const lldb_private::ExecutionContext &exe_ctx, lldb_private::Address &first_non_prologue_insn) override
size_t ReadMemory(const Address &addr, bool prefer_file_cache, void *dst, size_t dst_len, Status &error, lldb::addr_t *load_addr_ptr=nullptr)
Definition: Target.cpp:1761
static bool UnregisterPlugin(ABICreateInstance create_callback)
A uniqued constant string class.
Definition: ConstString.h:38
bool GetFastUnwindPlan(lldb_private::AddressRange &func, lldb_private::Thread &thread, lldb_private::UnwindPlan &unwind_plan) override
Definition: SBAddress.h:15
A class to represent register numbers, and able to convert between different register numbering schem...
Address & GetBaseAddress()
Get accessor for the base address of the range.
Definition: AddressRange.h:220
static lldb_private::UnwindAssembly * CreateInstance(const lldb_private::ArchSpec &arch)
UnwindPlan::RowSP GetRowForFunctionOffset(int offset) const
Definition: UnwindPlan.cpp:378
A section + offset based address range class.
Definition: AddressRange.h:32
llvm::Triple::ArchType GetMachine() const
Returns a machine family for the current architecture.
Definition: ArchSpec.cpp:726
An error handling class.
Definition: Status.h:44