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