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/ADT/Triple.h"
16 
17 #include "lldb/Core/Module.h"
18 #include "lldb/Core/PluginManager.h"
19 #include "lldb/Core/ValueObjectConstResult.h"
20 #include "lldb/Symbol/UnwindPlan.h"
21 #include "lldb/Target/Process.h"
22 #include "lldb/Target/RegisterContext.h"
23 #include "lldb/Target/Target.h"
24 #include "lldb/Target/Thread.h"
25 #include "lldb/Utility/ConstString.h"
26 #include "lldb/Utility/RegisterValue.h"
27 #include "lldb/Utility/Scalar.h"
28 #include "lldb/Utility/Status.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.SetErrorString("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.SetErrorString("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.SetErrorStringWithFormat(
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.SetErrorString("We don't support returning longer than 64 bit "
239                            "integer values at present.");
240     }
241   } else if (compiler_type.IsFloatingPointType(count, is_complex)) {
242     if (is_complex)
243       error.SetErrorString(
244           "We don't support returning complex values at present");
245     else
246       error.SetErrorString(
247           "We don't support returning float values at present");
248   }
249 
250   if (!set_it_simple)
251     error.SetErrorString(
252         "We only support setting simple integer return types at present.");
253 
254   return error;
255 }
256 
257 ValueObjectSP
258 ABIMacOSX_i386::GetReturnValueObjectImpl(Thread &thread,
259                                          CompilerType &compiler_type) const {
260   Value value;
261   ValueObjectSP return_valobj_sp;
262 
263   if (!compiler_type)
264     return return_valobj_sp;
265 
266   // value.SetContext (Value::eContextTypeClangType,
267   // compiler_type.GetOpaqueQualType());
268   value.SetCompilerType(compiler_type);
269 
270   RegisterContext *reg_ctx = thread.GetRegisterContext().get();
271   if (!reg_ctx)
272     return return_valobj_sp;
273 
274   bool is_signed;
275 
276   if (compiler_type.IsIntegerOrEnumerationType(is_signed)) {
277     std::optional<uint64_t> bit_width = compiler_type.GetBitSize(&thread);
278     if (!bit_width)
279       return return_valobj_sp;
280     unsigned eax_id =
281         reg_ctx->GetRegisterInfoByName("eax", 0)->kinds[eRegisterKindLLDB];
282     unsigned edx_id =
283         reg_ctx->GetRegisterInfoByName("edx", 0)->kinds[eRegisterKindLLDB];
284 
285     switch (*bit_width) {
286     default:
287     case 128:
288       // Scalar can't hold 128-bit literals, so we don't handle this
289       return return_valobj_sp;
290     case 64:
291       uint64_t raw_value;
292       raw_value =
293           thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) &
294           0xffffffff;
295       raw_value |=
296           (thread.GetRegisterContext()->ReadRegisterAsUnsigned(edx_id, 0) &
297            0xffffffff)
298           << 32;
299       if (is_signed)
300         value.GetScalar() = (int64_t)raw_value;
301       else
302         value.GetScalar() = (uint64_t)raw_value;
303       break;
304     case 32:
305       if (is_signed)
306         value.GetScalar() = (int32_t)(
307             thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) &
308             0xffffffff);
309       else
310         value.GetScalar() = (uint32_t)(
311             thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) &
312             0xffffffff);
313       break;
314     case 16:
315       if (is_signed)
316         value.GetScalar() = (int16_t)(
317             thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) &
318             0xffff);
319       else
320         value.GetScalar() = (uint16_t)(
321             thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) &
322             0xffff);
323       break;
324     case 8:
325       if (is_signed)
326         value.GetScalar() = (int8_t)(
327             thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) &
328             0xff);
329       else
330         value.GetScalar() = (uint8_t)(
331             thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) &
332             0xff);
333       break;
334     }
335   } else if (compiler_type.IsPointerType()) {
336     unsigned eax_id =
337         reg_ctx->GetRegisterInfoByName("eax", 0)->kinds[eRegisterKindLLDB];
338     uint32_t ptr =
339         thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) &
340         0xffffffff;
341     value.GetScalar() = ptr;
342   } else {
343     // not handled yet
344     return return_valobj_sp;
345   }
346 
347   // If we get here, we have a valid Value, so make our ValueObject out of it:
348 
349   return_valobj_sp = ValueObjectConstResult::Create(
350       thread.GetStackFrameAtIndex(0).get(), value, ConstString(""));
351   return return_valobj_sp;
352 }
353 
354 // This defines the CFA as esp+4
355 // the saved pc is at CFA-4 (i.e. esp+0)
356 // The saved esp is CFA+0
357 
358 bool ABIMacOSX_i386::CreateFunctionEntryUnwindPlan(UnwindPlan &unwind_plan) {
359   unwind_plan.Clear();
360   unwind_plan.SetRegisterKind(eRegisterKindDWARF);
361 
362   uint32_t sp_reg_num = dwarf_esp;
363   uint32_t pc_reg_num = dwarf_eip;
364 
365   UnwindPlan::RowSP row(new UnwindPlan::Row);
366   row->GetCFAValue().SetIsRegisterPlusOffset(sp_reg_num, 4);
367   row->SetRegisterLocationToAtCFAPlusOffset(pc_reg_num, -4, false);
368   row->SetRegisterLocationToIsCFAPlusOffset(sp_reg_num, 0, true);
369   unwind_plan.AppendRow(row);
370   unwind_plan.SetSourceName("i386 at-func-entry default");
371   unwind_plan.SetSourcedFromCompiler(eLazyBoolNo);
372   return true;
373 }
374 
375 // This defines the CFA as ebp+8
376 // The saved pc is at CFA-4 (i.e. ebp+4)
377 // The saved ebp is at CFA-8 (i.e. ebp+0)
378 // The saved esp is CFA+0
379 
380 bool ABIMacOSX_i386::CreateDefaultUnwindPlan(UnwindPlan &unwind_plan) {
381   unwind_plan.Clear();
382   unwind_plan.SetRegisterKind(eRegisterKindDWARF);
383 
384   uint32_t fp_reg_num = dwarf_ebp;
385   uint32_t sp_reg_num = dwarf_esp;
386   uint32_t pc_reg_num = dwarf_eip;
387 
388   UnwindPlan::RowSP row(new UnwindPlan::Row);
389   const int32_t ptr_size = 4;
390 
391   row->GetCFAValue().SetIsRegisterPlusOffset(fp_reg_num, 2 * ptr_size);
392   row->SetOffset(0);
393   row->SetUnspecifiedRegistersAreUndefined(true);
394 
395   row->SetRegisterLocationToAtCFAPlusOffset(fp_reg_num, ptr_size * -2, true);
396   row->SetRegisterLocationToAtCFAPlusOffset(pc_reg_num, ptr_size * -1, true);
397   row->SetRegisterLocationToIsCFAPlusOffset(sp_reg_num, 0, true);
398 
399   unwind_plan.AppendRow(row);
400   unwind_plan.SetSourceName("i386 default unwind plan");
401   unwind_plan.SetSourcedFromCompiler(eLazyBoolNo);
402   unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);
403   unwind_plan.SetUnwindPlanForSignalTrap(eLazyBoolNo);
404   return true;
405 }
406 
407 bool ABIMacOSX_i386::RegisterIsVolatile(const RegisterInfo *reg_info) {
408   return !RegisterIsCalleeSaved(reg_info);
409 }
410 
411 // v.
412 // http://developer.apple.com/library/mac/#documentation/developertools/Conceptual/LowLevelABI/130
413 // -IA-
414 // 32_Function_Calling_Conventions/IA32.html#//apple_ref/doc/uid/TP40002492-SW4
415 //
416 // This document ("OS X ABI Function Call Guide", chapter "IA-32 Function
417 // Calling Conventions") says that the following registers on i386 are
418 // preserved aka non-volatile aka callee-saved:
419 //
420 // ebx, ebp, esi, edi, esp
421 
422 bool ABIMacOSX_i386::RegisterIsCalleeSaved(const RegisterInfo *reg_info) {
423   if (reg_info) {
424     // Saved registers are ebx, ebp, esi, edi, esp, eip
425     const char *name = reg_info->name;
426     if (name[0] == 'e') {
427       switch (name[1]) {
428       case 'b':
429         if (name[2] == 'x' || name[2] == 'p')
430           return name[3] == '\0';
431         break;
432       case 'd':
433         if (name[2] == 'i')
434           return name[3] == '\0';
435         break;
436       case 'i':
437         if (name[2] == 'p')
438           return name[3] == '\0';
439         break;
440       case 's':
441         if (name[2] == 'i' || name[2] == 'p')
442           return name[3] == '\0';
443         break;
444       }
445     }
446     if (name[0] == 's' && name[1] == 'p' && name[2] == '\0') // sp
447       return true;
448     if (name[0] == 'f' && name[1] == 'p' && name[2] == '\0') // fp
449       return true;
450     if (name[0] == 'p' && name[1] == 'c' && name[2] == '\0') // pc
451       return true;
452   }
453   return false;
454 }
455 
456 void ABIMacOSX_i386::Initialize() {
457   PluginManager::RegisterPlugin(
458       GetPluginNameStatic(), "Mac OS X ABI for i386 targets", CreateInstance);
459 }
460 
461 void ABIMacOSX_i386::Terminate() {
462   PluginManager::UnregisterPlugin(CreateInstance);
463 }
464