LLDB  mainline
ABIMacOSX_i386.cpp
Go to the documentation of this file.
1 //===-- ABIMacOSX_i386.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 "ABIMacOSX_i386.h"
10 
11 #include <vector>
12 
13 #include "llvm/ADT/STLExtras.h"
14 #include "llvm/ADT/Triple.h"
15 
16 #include "lldb/Core/Module.h"
19 #include "lldb/Symbol/UnwindPlan.h"
20 #include "lldb/Target/Process.h"
22 #include "lldb/Target/Target.h"
23 #include "lldb/Target/Thread.h"
26 #include "lldb/Utility/Scalar.h"
27 #include "lldb/Utility/Status.h"
28 
29 using namespace lldb;
30 using namespace lldb_private;
31 
33 
34 enum {
35  dwarf_eax = 0,
44 };
45 
46 size_t ABIMacOSX_i386::GetRedZoneSize() const { return 0; }
47 
48 // Static Functions
49 
50 ABISP
51 ABIMacOSX_i386::CreateInstance(lldb::ProcessSP process_sp, const ArchSpec &arch) {
52  if ((arch.GetTriple().getArch() == llvm::Triple::x86) &&
53  (arch.GetTriple().isMacOSX() || arch.GetTriple().isiOS() ||
54  arch.GetTriple().isWatchOS())) {
55  return ABISP(
56  new ABIMacOSX_i386(std::move(process_sp), MakeMCRegisterInfo(arch)));
57  }
58  return ABISP();
59 }
60 
62  addr_t func_addr, addr_t return_addr,
63  llvm::ArrayRef<addr_t> args) const {
64  RegisterContext *reg_ctx = thread.GetRegisterContext().get();
65  if (!reg_ctx)
66  return false;
67  uint32_t pc_reg_num = reg_ctx->ConvertRegisterKindToRegisterNumber(
69  uint32_t sp_reg_num = reg_ctx->ConvertRegisterKindToRegisterNumber(
71 
72  // When writing a register value down to memory, the register info used to
73  // write memory just needs to have the correct size of a 32 bit register, the
74  // actual register it pertains to is not important, just the size needs to be
75  // correct. Here we use "eax"...
76  const RegisterInfo *reg_info_32 = reg_ctx->GetRegisterInfoByName("eax");
77  if (!reg_info_32)
78  return false; // TODO this should actually never happen
79 
80  // Make room for the argument(s) on the stack
81 
82  Status error;
83  RegisterValue reg_value;
84 
85  // Write any arguments onto the stack
86  sp -= 4 * args.size();
87 
88  // Align the SP
89  sp &= ~(16ull - 1ull); // 16-byte alignment
90 
91  addr_t arg_pos = sp;
92 
93  for (addr_t arg : args) {
94  reg_value.SetUInt32(arg);
95  error = reg_ctx->WriteRegisterValueToMemory(
96  reg_info_32, arg_pos, reg_info_32->byte_size, reg_value);
97  if (error.Fail())
98  return false;
99  arg_pos += 4;
100  }
101 
102  // The return address is pushed onto the stack (yes after we just set the
103  // alignment above!).
104  sp -= 4;
105  reg_value.SetUInt32(return_addr);
106  error = reg_ctx->WriteRegisterValueToMemory(
107  reg_info_32, sp, reg_info_32->byte_size, reg_value);
108  if (error.Fail())
109  return false;
110 
111  // %esp is set to the actual stack value.
112 
113  if (!reg_ctx->WriteRegisterFromUnsigned(sp_reg_num, sp))
114  return false;
115 
116  // %eip is set to the address of the called function.
117 
118  if (!reg_ctx->WriteRegisterFromUnsigned(pc_reg_num, func_addr))
119  return false;
120 
121  return true;
122 }
123 
124 static bool ReadIntegerArgument(Scalar &scalar, unsigned int bit_width,
125  bool is_signed, Process *process,
126  addr_t &current_stack_argument) {
127 
128  uint32_t byte_size = (bit_width + (8 - 1)) / 8;
129  Status error;
130  if (process->ReadScalarIntegerFromMemory(current_stack_argument, byte_size,
131  is_signed, scalar, error)) {
132  current_stack_argument += byte_size;
133  return true;
134  }
135  return false;
136 }
137 
139  ValueList &values) const {
140  unsigned int num_values = values.GetSize();
141  unsigned int value_index;
142 
143  // Get the pointer to the first stack argument so we have a place to start
144  // when reading data
145 
146  RegisterContext *reg_ctx = thread.GetRegisterContext().get();
147 
148  if (!reg_ctx)
149  return false;
150 
151  addr_t sp = reg_ctx->GetSP(0);
152 
153  if (!sp)
154  return false;
155 
156  addr_t current_stack_argument = sp + 4; // jump over return address
157 
158  for (value_index = 0; value_index < num_values; ++value_index) {
159  Value *value = values.GetValueAtIndex(value_index);
160 
161  if (!value)
162  return false;
163 
164  // We currently only support extracting values with Clang QualTypes. Do we
165  // care about others?
166  CompilerType compiler_type(value->GetCompilerType());
167  llvm::Optional<uint64_t> bit_size = compiler_type.GetBitSize(&thread);
168  if (bit_size) {
169  bool is_signed;
170  if (compiler_type.IsIntegerOrEnumerationType(is_signed))
171  ReadIntegerArgument(value->GetScalar(), *bit_size, is_signed,
172  thread.GetProcess().get(), current_stack_argument);
173  else if (compiler_type.IsPointerType())
174  ReadIntegerArgument(value->GetScalar(), *bit_size, false,
175  thread.GetProcess().get(), current_stack_argument);
176  }
177  }
178 
179  return true;
180 }
181 
182 Status ABIMacOSX_i386::SetReturnValueObject(lldb::StackFrameSP &frame_sp,
183  lldb::ValueObjectSP &new_value_sp) {
184  Status error;
185  if (!new_value_sp) {
186  error.SetErrorString("Empty value object for return value.");
187  return error;
188  }
189 
190  CompilerType compiler_type = new_value_sp->GetCompilerType();
191  if (!compiler_type) {
192  error.SetErrorString("Null clang type for return value.");
193  return error;
194  }
195 
196  Thread *thread = frame_sp->GetThread().get();
197 
198  bool is_signed;
199  uint32_t count;
200  bool is_complex;
201 
202  RegisterContext *reg_ctx = thread->GetRegisterContext().get();
203 
204  bool set_it_simple = false;
205  if (compiler_type.IsIntegerOrEnumerationType(is_signed) ||
206  compiler_type.IsPointerType()) {
207  DataExtractor data;
208  Status data_error;
209  size_t num_bytes = new_value_sp->GetData(data, data_error);
210  if (data_error.Fail()) {
212  "Couldn't convert return value to raw data: %s",
213  data_error.AsCString());
214  return error;
215  }
216  lldb::offset_t offset = 0;
217  if (num_bytes <= 8) {
218  const RegisterInfo *eax_info = reg_ctx->GetRegisterInfoByName("eax", 0);
219  if (num_bytes <= 4) {
220  uint32_t raw_value = data.GetMaxU32(&offset, num_bytes);
221 
222  if (reg_ctx->WriteRegisterFromUnsigned(eax_info, raw_value))
223  set_it_simple = true;
224  } else {
225  uint32_t raw_value = data.GetMaxU32(&offset, 4);
226 
227  if (reg_ctx->WriteRegisterFromUnsigned(eax_info, raw_value)) {
228  const RegisterInfo *edx_info =
229  reg_ctx->GetRegisterInfoByName("edx", 0);
230  uint32_t raw_value = data.GetMaxU32(&offset, num_bytes - offset);
231 
232  if (reg_ctx->WriteRegisterFromUnsigned(edx_info, raw_value))
233  set_it_simple = true;
234  }
235  }
236  } else {
237  error.SetErrorString("We don't support returning longer than 64 bit "
238  "integer values at present.");
239  }
240  } else if (compiler_type.IsFloatingPointType(count, is_complex)) {
241  if (is_complex)
242  error.SetErrorString(
243  "We don't support returning complex values at present");
244  else
245  error.SetErrorString(
246  "We don't support returning float values at present");
247  }
248 
249  if (!set_it_simple)
250  error.SetErrorString(
251  "We only support setting simple integer return types at present.");
252 
253  return error;
254 }
255 
256 ValueObjectSP
258  CompilerType &compiler_type) const {
259  Value value;
260  ValueObjectSP return_valobj_sp;
261 
262  if (!compiler_type)
263  return return_valobj_sp;
264 
265  // value.SetContext (Value::eContextTypeClangType,
266  // compiler_type.GetOpaqueQualType());
267  value.SetCompilerType(compiler_type);
268 
269  RegisterContext *reg_ctx = thread.GetRegisterContext().get();
270  if (!reg_ctx)
271  return return_valobj_sp;
272 
273  bool is_signed;
274 
275  if (compiler_type.IsIntegerOrEnumerationType(is_signed)) {
276  llvm::Optional<uint64_t> bit_width = compiler_type.GetBitSize(&thread);
277  if (!bit_width)
278  return return_valobj_sp;
279  unsigned eax_id =
280  reg_ctx->GetRegisterInfoByName("eax", 0)->kinds[eRegisterKindLLDB];
281  unsigned edx_id =
282  reg_ctx->GetRegisterInfoByName("edx", 0)->kinds[eRegisterKindLLDB];
283 
284  switch (*bit_width) {
285  default:
286  case 128:
287  // Scalar can't hold 128-bit literals, so we don't handle this
288  return return_valobj_sp;
289  case 64:
290  uint64_t raw_value;
291  raw_value =
292  thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) &
293  0xffffffff;
294  raw_value |=
295  (thread.GetRegisterContext()->ReadRegisterAsUnsigned(edx_id, 0) &
296  0xffffffff)
297  << 32;
298  if (is_signed)
299  value.GetScalar() = (int64_t)raw_value;
300  else
301  value.GetScalar() = (uint64_t)raw_value;
302  break;
303  case 32:
304  if (is_signed)
305  value.GetScalar() = (int32_t)(
306  thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) &
307  0xffffffff);
308  else
309  value.GetScalar() = (uint32_t)(
310  thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) &
311  0xffffffff);
312  break;
313  case 16:
314  if (is_signed)
315  value.GetScalar() = (int16_t)(
316  thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) &
317  0xffff);
318  else
319  value.GetScalar() = (uint16_t)(
320  thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) &
321  0xffff);
322  break;
323  case 8:
324  if (is_signed)
325  value.GetScalar() = (int8_t)(
326  thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) &
327  0xff);
328  else
329  value.GetScalar() = (uint8_t)(
330  thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) &
331  0xff);
332  break;
333  }
334  } else if (compiler_type.IsPointerType()) {
335  unsigned eax_id =
336  reg_ctx->GetRegisterInfoByName("eax", 0)->kinds[eRegisterKindLLDB];
337  uint32_t ptr =
338  thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) &
339  0xffffffff;
340  value.GetScalar() = ptr;
341  } else {
342  // not handled yet
343  return return_valobj_sp;
344  }
345 
346  // If we get here, we have a valid Value, so make our ValueObject out of it:
347 
348  return_valobj_sp = ValueObjectConstResult::Create(
349  thread.GetStackFrameAtIndex(0).get(), value, ConstString(""));
350  return return_valobj_sp;
351 }
352 
353 // This defines the CFA as esp+4
354 // the saved pc is at CFA-4 (i.e. esp+0)
355 // The saved esp is CFA+0
356 
358  unwind_plan.Clear();
359  unwind_plan.SetRegisterKind(eRegisterKindDWARF);
360 
361  uint32_t sp_reg_num = dwarf_esp;
362  uint32_t pc_reg_num = dwarf_eip;
363 
365  row->GetCFAValue().SetIsRegisterPlusOffset(sp_reg_num, 4);
366  row->SetRegisterLocationToAtCFAPlusOffset(pc_reg_num, -4, false);
367  row->SetRegisterLocationToIsCFAPlusOffset(sp_reg_num, 0, true);
368  unwind_plan.AppendRow(row);
369  unwind_plan.SetSourceName("i386 at-func-entry default");
370  unwind_plan.SetSourcedFromCompiler(eLazyBoolNo);
371  return true;
372 }
373 
374 // This defines the CFA as ebp+8
375 // The saved pc is at CFA-4 (i.e. ebp+4)
376 // The saved ebp is at CFA-8 (i.e. ebp+0)
377 // The saved esp is CFA+0
378 
380  unwind_plan.Clear();
381  unwind_plan.SetRegisterKind(eRegisterKindDWARF);
382 
383  uint32_t fp_reg_num = dwarf_ebp;
384  uint32_t sp_reg_num = dwarf_esp;
385  uint32_t pc_reg_num = dwarf_eip;
386 
388  const int32_t ptr_size = 4;
389 
390  row->GetCFAValue().SetIsRegisterPlusOffset(fp_reg_num, 2 * ptr_size);
391  row->SetOffset(0);
392 
393  row->SetRegisterLocationToAtCFAPlusOffset(fp_reg_num, ptr_size * -2, true);
394  row->SetRegisterLocationToAtCFAPlusOffset(pc_reg_num, ptr_size * -1, true);
395  row->SetRegisterLocationToIsCFAPlusOffset(sp_reg_num, 0, true);
396 
397  unwind_plan.AppendRow(row);
398  unwind_plan.SetSourceName("i386 default unwind plan");
399  unwind_plan.SetSourcedFromCompiler(eLazyBoolNo);
402  return true;
403 }
404 
405 bool ABIMacOSX_i386::RegisterIsVolatile(const RegisterInfo *reg_info) {
406  return !RegisterIsCalleeSaved(reg_info);
407 }
408 
409 // v.
410 // http://developer.apple.com/library/mac/#documentation/developertools/Conceptual/LowLevelABI/130
411 // -IA-
412 // 32_Function_Calling_Conventions/IA32.html#//apple_ref/doc/uid/TP40002492-SW4
413 //
414 // This document ("OS X ABI Function Call Guide", chapter "IA-32 Function
415 // Calling Conventions") says that the following registers on i386 are
416 // preserved aka non-volatile aka callee-saved:
417 //
418 // ebx, ebp, esi, edi, esp
419 
420 bool ABIMacOSX_i386::RegisterIsCalleeSaved(const RegisterInfo *reg_info) {
421  if (reg_info) {
422  // Saved registers are ebx, ebp, esi, edi, esp, eip
423  const char *name = reg_info->name;
424  if (name[0] == 'e') {
425  switch (name[1]) {
426  case 'b':
427  if (name[2] == 'x' || name[2] == 'p')
428  return name[3] == '\0';
429  break;
430  case 'd':
431  if (name[2] == 'i')
432  return name[3] == '\0';
433  break;
434  case 'i':
435  if (name[2] == 'p')
436  return name[3] == '\0';
437  break;
438  case 's':
439  if (name[2] == 'i' || name[2] == 'p')
440  return name[3] == '\0';
441  break;
442  }
443  }
444  if (name[0] == 's' && name[1] == 'p' && name[2] == '\0') // sp
445  return true;
446  if (name[0] == 'f' && name[1] == 'p' && name[2] == '\0') // fp
447  return true;
448  if (name[0] == 'p' && name[1] == 'c' && name[2] == '\0') // pc
449  return true;
450  }
451  return false;
452 }
453 
455  PluginManager::RegisterPlugin(
456  GetPluginNameStatic(), "Mac OS X ABI for i386 targets", CreateInstance);
457 }
458 
460  PluginManager::UnregisterPlugin(CreateInstance);
461 }
462 
464  static ConstString g_short_name("abi.macosx-i386");
465  return g_short_name;
466 }
467 
468 // PluginInterface protocol
469 
471  return GetPluginNameStatic();
472 }
473 
static void Terminate()
#define LLDB_REGNUM_GENERIC_PC
Definition: lldb-defines.h:63
An data extractor class.
Definition: DataExtractor.h:46
void SetSourceName(const char *)
Definition: UnwindPlan.cpp:548
A class that represents a running process on the host machine.
static lldb::ABISP CreateInstance(lldb::ProcessSP process_sp, const lldb_private::ArchSpec &arch)
insn ptr reg, stack ptr reg, etc not specific to any particular target
the register numbers seen DWARF
bool IsIntegerOrEnumerationType(bool &is_signed) const
uint64_t GetSP(uint64_t fail_value=LLDB_INVALID_ADDRESS)
lldb_private::ConstString GetPluginName() override
uint32_t GetPluginVersion() override
virtual uint32_t ConvertRegisterKindToRegisterNumber(lldb::RegisterKind kind, uint32_t num)=0
Convert from a given register numbering scheme to the lldb register numbering scheme.
An architecture specification class.
Definition: ArchSpec.h:33
Value * GetValueAtIndex(size_t idx)
Definition: Value.cpp:705
#define LLDB_REGNUM_GENERIC_SP
Definition: lldb-defines.h:64
virtual Status WriteRegisterValueToMemory(const lldb_private::RegisterInfo *reg_info, lldb::addr_t dst_addr, uint32_t dst_len, const RegisterValue &reg_value)
bool IsPointerType(CompilerType *pointee_type=nullptr) const
llvm::Triple & GetTriple()
Architecture triple accessor.
Definition: ArchSpec.h:434
bool PrepareTrivialCall(lldb_private::Thread &thread, lldb::addr_t sp, lldb::addr_t func_addr, lldb::addr_t return_addr, llvm::ArrayRef< lldb::addr_t > args) const override
bool IsFloatingPointType(uint32_t &count, bool &is_complex) const
lldb_private::Status SetReturnValueObject(lldb::StackFrameSP &frame_sp, lldb::ValueObjectSP &new_value) override
#define LLDB_PLUGIN_DEFINE(PluginName)
Definition: PluginManager.h:31
static lldb_private::ConstString GetPluginNameStatic()
bool GetArgumentValues(lldb_private::Thread &thread, lldb_private::ValueList &values) const override
lldb&#39;s internal register numbers
uint64_t offset_t
Definition: lldb-types.h:87
std::shared_ptr< Row > RowSP
Definition: UnwindPlan.h:379
void AppendRow(const RowSP &row_sp)
Definition: UnwindPlan.cpp:359
bool RegisterIsCalleeSaved(const lldb_private::RegisterInfo *reg_info)
virtual lldb::RegisterContextSP GetRegisterContext()=0
void SetErrorString(llvm::StringRef err_str)
Set the current error string to err_str.
Definition: Status.cpp:242
A plug-in interface definition class for debugging a process.
Definition: Process.h:362
size_t GetRedZoneSize() const override
const RegisterInfo * GetRegisterInfoByName(llvm::StringRef reg_name, uint32_t start_idx=0)
const CompilerType & GetCompilerType()
Definition: Value.cpp:239
void SetRegisterKind(lldb::RegisterKind kind)
Definition: UnwindPlan.h:422
void SetUInt32(uint32_t uint, Type t=eTypeUInt32)
bool WriteRegisterFromUnsigned(uint32_t reg, uint64_t uval)
lldb::ProcessSP GetProcess() const
Definition: Thread.h:152
bool CreateDefaultUnwindPlan(lldb_private::UnwindPlan &unwind_plan) override
bool CreateFunctionEntryUnwindPlan(lldb_private::UnwindPlan &unwind_plan) override
void SetUnwindPlanValidAtAllInstructions(lldb_private::LazyBool valid_at_all_insn)
Definition: UnwindPlan.h:475
uint64_t addr_t
Definition: lldb-types.h:83
bool RegisterIsVolatile(const lldb_private::RegisterInfo *reg_info) override
A uniqued constant string class.
Definition: ConstString.h:40
bool Fail() const
Test for error condition.
Definition: Status.cpp:182
llvm::Optional< uint64_t > GetBitSize(ExecutionContextScope *exe_scope) const
Return the size of the type in bits.
uint32_t GetMaxU32(lldb::offset_t *offset_ptr, size_t byte_size) const
Extract an integer of size byte_size from *offset_ptr.
Definition: SBAddress.h:15
Represents a generic type in a programming language.
Definition: CompilerType.h:33
int SetErrorStringWithFormat(const char *format,...) __attribute__((format(printf
Set the current error string to a formatted error string.
Definition: Status.cpp:256
void SetCompilerType(const CompilerType &compiler_type)
Definition: Value.cpp:268
const Scalar & GetScalar() const
Definition: Value.h:168
static bool ReadIntegerArgument(Scalar &scalar, unsigned int bit_width, bool is_signed, Process *process, addr_t &current_stack_argument)
size_t ReadScalarIntegerFromMemory(lldb::addr_t addr, uint32_t byte_size, bool is_signed, Scalar &scalar, Status &error)
Definition: Process.cpp:2356
const char * AsCString(const char *default_error_str="unknown error") const
Get the error string associated with the current error.
Definition: Status.cpp:131
virtual lldb::StackFrameSP GetStackFrameAtIndex(uint32_t idx)
Definition: Thread.h:397
void SetSourcedFromCompiler(lldb_private::LazyBool from_compiler)
Definition: UnwindPlan.h:463
lldb::ValueObjectSP GetReturnValueObjectImpl(lldb_private::Thread &thread, lldb_private::CompilerType &ast_type) const override
static void Initialize()
An error handling class.
Definition: Status.h:44
void SetUnwindPlanForSignalTrap(lldb_private::LazyBool is_for_signal_trap)
Definition: UnwindPlan.h:487