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