LLDB  mainline
UnwindAssembly-x86.cpp
Go to the documentation of this file.
1 //===-- UnwindAssembly-x86.cpp --------------------------------------------===//
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 
34 
35 // UnwindAssemblyParser_x86 method definitions
36 
39  m_assembly_inspection_engine(new x86AssemblyInspectionEngine(arch)) {}
40 
42  delete m_assembly_inspection_engine;
43 }
44 
46  AddressRange &func, Thread &thread, UnwindPlan &unwind_plan) {
47  if (!func.GetBaseAddress().IsValid() || func.GetByteSize() == 0)
48  return false;
49  if (m_assembly_inspection_engine == nullptr)
50  return false;
51  ProcessSP process_sp(thread.GetProcess());
52  if (process_sp.get() == nullptr)
53  return false;
54  std::vector<uint8_t> function_text(func.GetByteSize());
55  Status error;
56  if (process_sp->GetTarget().ReadMemory(
57  func.GetBaseAddress(), function_text.data(), func.GetByteSize(),
58  error) == func.GetByteSize()) {
59  RegisterContextSP reg_ctx(thread.GetRegisterContext());
60  m_assembly_inspection_engine->Initialize(reg_ctx);
61  return m_assembly_inspection_engine->GetNonCallSiteUnwindPlanFromAssembly(
62  function_text.data(), func.GetByteSize(), func, unwind_plan);
63  }
64  return false;
65 }
66 
68  AddressRange &func, Thread &thread, UnwindPlan &unwind_plan) {
69  bool do_augment_unwindplan = true;
70 
71  UnwindPlan::RowSP first_row = unwind_plan.GetRowForFunctionOffset(0);
72  UnwindPlan::RowSP last_row = unwind_plan.GetRowForFunctionOffset(-1);
73 
74  int wordsize = 8;
75  ProcessSP process_sp(thread.GetProcess());
76  if (process_sp.get() == nullptr)
77  return false;
78 
79  wordsize = process_sp->GetTarget().GetArchitecture().GetAddressByteSize();
80 
81  RegisterNumber sp_regnum(thread, eRegisterKindGeneric,
83  RegisterNumber pc_regnum(thread, eRegisterKindGeneric,
85 
86  // Does this UnwindPlan describe the prologue? I want to see that the CFA is
87  // set in terms of the stack pointer plus an offset, and I want to see that
88  // rip is retrieved at the CFA-wordsize. If there is no description of the
89  // prologue, don't try to augment this eh_frame unwinder code, fall back to
90  // assembly parsing instead.
91 
92  if (first_row->GetCFAValue().GetValueType() !=
93  UnwindPlan::Row::FAValue::isRegisterPlusOffset ||
94  RegisterNumber(thread, unwind_plan.GetRegisterKind(),
95  first_row->GetCFAValue().GetRegisterNumber()) !=
96  sp_regnum ||
97  first_row->GetCFAValue().GetOffset() != wordsize) {
98  return false;
99  }
100  UnwindPlan::Row::RegisterLocation first_row_pc_loc;
101  if (!first_row->GetRegisterInfo(
102  pc_regnum.GetAsKind(unwind_plan.GetRegisterKind()),
103  first_row_pc_loc) ||
104  !first_row_pc_loc.IsAtCFAPlusOffset() ||
105  first_row_pc_loc.GetOffset() != -wordsize) {
106  return false;
107  }
108 
109  // It looks like the prologue is described. Is the epilogue described? If it
110  // is, no need to do any augmentation.
111 
112  if (first_row != last_row &&
113  first_row->GetOffset() != last_row->GetOffset()) {
114  // The first & last row have the same CFA register and the same CFA offset
115  // value and the CFA register is esp/rsp (the stack pointer).
116 
117  // We're checking that both of them have an unwind rule like "CFA=esp+4" or
118  // CFA+rsp+8".
119 
120  if (first_row->GetCFAValue().GetValueType() ==
121  last_row->GetCFAValue().GetValueType() &&
122  first_row->GetCFAValue().GetRegisterNumber() ==
123  last_row->GetCFAValue().GetRegisterNumber() &&
124  first_row->GetCFAValue().GetOffset() ==
125  last_row->GetCFAValue().GetOffset()) {
126  // Get the register locations for eip/rip from the first & last rows. Are
127  // they both CFA plus an offset? Is it the same offset?
128 
129  UnwindPlan::Row::RegisterLocation last_row_pc_loc;
130  if (last_row->GetRegisterInfo(
131  pc_regnum.GetAsKind(unwind_plan.GetRegisterKind()),
132  last_row_pc_loc)) {
133  if (last_row_pc_loc.IsAtCFAPlusOffset() &&
134  first_row_pc_loc.GetOffset() == last_row_pc_loc.GetOffset()) {
135 
136  // One last sanity check: Is the unwind rule for getting the caller
137  // pc value "deref the CFA-4" or "deref the CFA-8"?
138 
139  // If so, we have an UnwindPlan that already describes the epilogue
140  // and we don't need to modify it at all.
141 
142  if (first_row_pc_loc.GetOffset() == -wordsize) {
143  return true;
144  }
145  }
146  }
147  }
148  }
149 
150  if (do_augment_unwindplan) {
151  if (!func.GetBaseAddress().IsValid() || func.GetByteSize() == 0)
152  return false;
153  if (m_assembly_inspection_engine == nullptr)
154  return false;
155  std::vector<uint8_t> function_text(func.GetByteSize());
156  Status error;
157  if (process_sp->GetTarget().ReadMemory(
158  func.GetBaseAddress(), function_text.data(), func.GetByteSize(),
159  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  Status error;
187  if (target.ReadMemory(func.GetBaseAddress(), opcode_data.data(), 4,
188  error) == 4) {
189  uint8_t i386_push_mov[] = {0x55, 0x89, 0xe5};
190  uint8_t x86_64_push_mov[] = {0x55, 0x48, 0x89, 0xe5};
191 
192  if (memcmp(opcode_data.data(), i386_push_mov, sizeof(i386_push_mov)) ==
193  0 ||
194  memcmp(opcode_data.data(), x86_64_push_mov,
195  sizeof(x86_64_push_mov)) == 0) {
196  ABISP abi_sp = process_sp->GetABI();
197  if (abi_sp) {
198  return abi_sp->CreateDefaultUnwindPlan(unwind_plan);
199  }
200  }
201  }
202  }
203  return false;
204 }
205 
207  AddressRange &func, const ExecutionContext &exe_ctx,
208  Address &first_non_prologue_insn) {
209 
210  if (!func.GetBaseAddress().IsValid())
211  return false;
212 
213  Target *target = exe_ctx.GetTargetPtr();
214  if (target == nullptr)
215  return false;
216 
217  if (m_assembly_inspection_engine == nullptr)
218  return false;
219 
220  std::vector<uint8_t> function_text(func.GetByteSize());
221  Status error;
222  if (target->ReadMemory(func.GetBaseAddress(), function_text.data(),
223  func.GetByteSize(), error) == func.GetByteSize()) {
224  size_t offset;
225  if (m_assembly_inspection_engine->FindFirstNonPrologueInstruction(
226  function_text.data(), func.GetByteSize(), offset)) {
227  first_non_prologue_insn = func.GetBaseAddress();
228  first_non_prologue_insn.Slide(offset);
229  }
230  return true;
231  }
232  return false;
233 }
234 
236  const llvm::Triple::ArchType cpu = arch.GetMachine();
237  if (cpu == llvm::Triple::x86 || cpu == llvm::Triple::x86_64)
238  return new UnwindAssembly_x86(arch);
239  return nullptr;
240 }
241 
242 // PluginInterface protocol in UnwindAssemblyParser_x86
243 
245  return GetPluginNameStatic();
246 }
247 
249 
251  PluginManager::RegisterPlugin(GetPluginNameStatic(),
252  GetPluginDescriptionStatic(), CreateInstance);
253 }
254 
256  PluginManager::UnregisterPlugin(CreateInstance);
257 }
258 
260  static ConstString g_name("x86");
261  return g_name;
262 }
263 
265  return "i386 and x86_64 assembly language profiler plugin.";
266 }
lldb_private::UnwindPlan::Row::RegisterLocation::GetOffset
int32_t GetOffset() const
Definition: UnwindPlan.h:141
lldb_private::AddressRange::GetBaseAddress
Address & GetBaseAddress()
Get accessor for the base address of the range.
Definition: AddressRange.h:209
lldb_private::ExecutionContext
Definition: ExecutionContext.h:292
lldb_private::ArchSpec
Definition: ArchSpec.h:33
UnwindAssembly_x86::GetPluginVersion
uint32_t GetPluginVersion() override
Definition: UnwindAssembly-x86.cpp:248
UnwindAssembly_x86::Initialize
static void Initialize()
Definition: UnwindAssembly-x86.cpp:250
lldb_private::Address::IsValid
bool IsValid() const
Check if the object state is valid.
Definition: Address.h:332
lldb_private::ArchSpec::GetMachine
llvm::Triple::ArchType GetMachine() const
Returns a machine family for the current architecture.
Definition: ArchSpec.cpp:667
UnwindAssembly_x86::GetFastUnwindPlan
bool GetFastUnwindPlan(lldb_private::AddressRange &func, lldb_private::Thread &thread, lldb_private::UnwindPlan &unwind_plan) override
Definition: UnwindAssembly-x86.cpp:170
lldb::eRegisterKindGeneric
@ eRegisterKindGeneric
insn ptr reg, stack ptr reg, etc not specific to any particular target
Definition: lldb-enumerations.h:230
lldb_private::x86AssemblyInspectionEngine
Definition: x86AssemblyInspectionEngine.h:28
UnwindAssembly-x86.h
lldb_private::AddressRange::GetByteSize
lldb::addr_t GetByteSize() const
Get accessor for the byte size of this range.
Definition: AddressRange.h:221
x86AssemblyInspectionEngine.h
lldb_private::UnwindPlan::GetRowForFunctionOffset
UnwindPlan::RowSP GetRowForFunctionOffset(int offset) const
Definition: UnwindPlan.cpp:384
UnwindAssembly_x86::~UnwindAssembly_x86
~UnwindAssembly_x86() override
Definition: UnwindAssembly-x86.cpp:41
lldb_private::UnwindAssembly
Definition: UnwindAssembly.h:18
UnwindAssembly_x86
Definition: UnwindAssembly-x86.h:17
lldb_private::Target
Definition: Target.h:445
lldb_private::UnwindPlan::GetRegisterKind
lldb::RegisterKind GetRegisterKind() const
Definition: UnwindPlan.h:437
LLDB_PLUGIN_DEFINE_ADV
LLDB_PLUGIN_DEFINE_ADV(ObjectContainerUniversalMachO, ObjectContainerMachOArchive) void ObjectContainerUniversalMachO
Definition: ObjectContainerUniversalMachO.cpp:23
ABI.h
UnwindAssembly_x86::GetPluginDescriptionStatic
static const char * GetPluginDescriptionStatic()
Definition: UnwindAssembly-x86.cpp:264
Process.h
Target.h
lldb_private::Thread::GetProcess
lldb::ProcessSP GetProcess() const
Definition: Thread.h:154
error
static llvm::raw_ostream & error(Stream &strm)
Definition: CommandReturnObject.cpp:17
UnwindAssembly_x86::CreateInstance
static lldb_private::UnwindAssembly * CreateInstance(const lldb_private::ArchSpec &arch)
Definition: UnwindAssembly-x86.cpp:235
RegisterNumber
A class to represent register numbers, and able to convert between different register numbering schem...
Definition: RegisterNumber.h:19
lldb_private::Thread
Definition: Thread.h:62
lldb_private::ConstString
Definition: ConstString.h:40
lldb_private::AddressRange
Definition: AddressRange.h:25
RegisterNumber::GetAsKind
uint32_t GetAsKind(lldb::RegisterKind kind)
Definition: RegisterNumber.cpp:80
lldb_private::UnwindPlan::Row::RegisterLocation::IsAtCFAPlusOffset
bool IsAtCFAPlusOffset() const
Definition: UnwindPlan.h:96
Thread.h
Address.h
UnwindPlan.h
lldb_private::UnwindPlan::Row::RegisterLocation
Definition: UnwindPlan.h:57
lldb_private::UnwindPlan::RowSP
std::shared_ptr< Row > RowSP
Definition: UnwindPlan.h:395
UnwindAssembly_x86::AugmentUnwindPlanFromCallSite
bool AugmentUnwindPlanFromCallSite(lldb_private::AddressRange &func, lldb_private::Thread &thread, lldb_private::UnwindPlan &unwind_plan) override
Definition: UnwindAssembly-x86.cpp:67
UnwindAssembly_x86::GetPluginNameStatic
static lldb_private::ConstString GetPluginNameStatic()
Definition: UnwindAssembly-x86.cpp:259
lldb_private::Status
Definition: Status.h:44
lldb_private::Target::ReadMemory
size_t ReadMemory(const Address &addr, void *dst, size_t dst_len, Status &error, bool force_live_memory=false, lldb::addr_t *load_addr_ptr=nullptr)
Definition: Target.cpp:1721
uint32_t
lldb_private::Address
Definition: Address.h:59
LLDB_REGNUM_GENERIC_SP
#define LLDB_REGNUM_GENERIC_SP
Definition: lldb-defines.h:64
ArchSpec.h
UnwindAssembly_x86::Terminate
static void Terminate()
Definition: UnwindAssembly-x86.cpp:255
UnwindAssembly_x86::GetNonCallSiteUnwindPlanFromAssembly
bool GetNonCallSiteUnwindPlanFromAssembly(lldb_private::AddressRange &func, lldb_private::Thread &thread, lldb_private::UnwindPlan &unwind_plan) override
Definition: UnwindAssembly-x86.cpp:45
PluginManager.h
Status.h
lldb_private
A class that represents a running process on the host machine.
Definition: SBCommandInterpreterRunOptions.h:16
LLDB_REGNUM_GENERIC_PC
#define LLDB_REGNUM_GENERIC_PC
Definition: lldb-defines.h:63
UnwindAssembly_x86::GetPluginName
lldb_private::ConstString GetPluginName() override
Definition: UnwindAssembly-x86.cpp:244
UnwindAssembly.h
RegisterNumber.h
lldb_private::Thread::GetRegisterContext
virtual lldb::RegisterContextSP GetRegisterContext()=0
lldb_private::Address::Slide
bool Slide(int64_t offset)
Definition: Address.h:436
lldb_private::UnwindPlan
Definition: UnwindPlan.h:53
lldb
Definition: SBAddress.h:15
RegisterContext.h
UnwindAssembly_x86::FirstNonPrologueInsn
bool FirstNonPrologueInsn(lldb_private::AddressRange &func, const lldb_private::ExecutionContext &exe_ctx, lldb_private::Address &first_non_prologue_insn) override
Definition: UnwindAssembly-x86.cpp:206
lldb_private::ExecutionContext::GetTargetPtr
Target * GetTargetPtr() const
Returns a pointer to the target object.
Definition: ExecutionContext.cpp:200
ExecutionContext.h