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 <optional>
12#include <vector>
13
14#include "llvm/ADT/STLExtras.h"
15#include "llvm/TargetParser/Triple.h"
16
17#include "lldb/Core/Module.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"
29
30using namespace lldb;
31using namespace lldb_private;
32
34
35enum {
45};
46
47size_t ABIMacOSX_i386::GetRedZoneSize() const { return 0; }
48
49// Static Functions
50
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
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(
70 uint32_t sp_reg_num = reg_ctx->ConvertRegisterKindToRegisterNumber(
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
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);
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);
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
125static 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;
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
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
184 lldb::ValueObjectSP &new_value_sp) {
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()) {
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 {
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)
245 "We don't support returning complex values at present");
246 else
248 "We don't support returning float values at present");
249 }
250
251 if (!set_it_simple)
253 "We only support setting simple integer return types at present.");
254
255 return error;
256}
257
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
360 unwind_plan.Clear();
362
363 uint32_t sp_reg_num = dwarf_esp;
364 uint32_t pc_reg_num = dwarf_eip;
365
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");
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
382 unwind_plan.Clear();
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
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");
405 return true;
406}
407
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
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
459 GetPluginNameStatic(), "Mac OS X ABI for i386 targets", CreateInstance);
460}
461
464}
static bool ReadIntegerArgument(Scalar &scalar, unsigned int bit_width, bool is_signed, Process *process, addr_t &current_stack_argument)
@ dwarf_edx
@ dwarf_ecx
@ dwarf_eip
@ dwarf_eax
@ dwarf_esi
@ dwarf_edi
@ dwarf_esp
@ dwarf_ebx
@ dwarf_ebp
static bool ReadIntegerArgument(Scalar &scalar, unsigned int bit_width, bool is_signed, Thread &thread, uint32_t *argument_register_ids, unsigned int &current_argument_register, addr_t &current_stack_argument)
static llvm::raw_ostream & error(Stream &strm)
#define LLDB_PLUGIN_DEFINE(PluginName)
Definition: PluginManager.h:32
bool RegisterIsCalleeSaved(const lldb_private::RegisterInfo *reg_info)
static void Initialize()
static void Terminate()
bool GetArgumentValues(lldb_private::Thread &thread, lldb_private::ValueList &values) const override
bool CreateDefaultUnwindPlan(lldb_private::UnwindPlan &unwind_plan) override
static lldb::ABISP CreateInstance(lldb::ProcessSP process_sp, const lldb_private::ArchSpec &arch)
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 RegisterIsVolatile(const lldb_private::RegisterInfo *reg_info) override
bool CreateFunctionEntryUnwindPlan(lldb_private::UnwindPlan &unwind_plan) override
lldb::ValueObjectSP GetReturnValueObjectImpl(lldb_private::Thread &thread, lldb_private::CompilerType &ast_type) const override
lldb_private::Status SetReturnValueObject(lldb::StackFrameSP &frame_sp, lldb::ValueObjectSP &new_value) override
static llvm::StringRef GetPluginNameStatic()
size_t GetRedZoneSize() const override
static std::unique_ptr< llvm::MCRegisterInfo > MakeMCRegisterInfo(const ArchSpec &arch)
Utility function to construct a MCRegisterInfo using the ArchSpec triple.
Definition: ABI.cpp:234
An architecture specification class.
Definition: ArchSpec.h:31
llvm::Triple & GetTriple()
Architecture triple accessor.
Definition: ArchSpec.h:461
Generic representation of a type in a programming language.
Definition: CompilerType.h:36
bool IsFloatingPointType(uint32_t &count, bool &is_complex) const
bool IsIntegerOrEnumerationType(bool &is_signed) const
std::optional< uint64_t > GetBitSize(ExecutionContextScope *exe_scope) const
Return the size of the type in bits.
bool IsPointerType(CompilerType *pointee_type=nullptr) const
A uniqued constant string class.
Definition: ConstString.h:40
An data extractor class.
Definition: DataExtractor.h:48
uint32_t GetMaxU32(lldb::offset_t *offset_ptr, size_t byte_size) const
Extract an integer of size byte_size from *offset_ptr.
static bool RegisterPlugin(llvm::StringRef name, llvm::StringRef description, ABICreateInstance create_callback)
static bool UnregisterPlugin(ABICreateInstance create_callback)
A plug-in interface definition class for debugging a process.
Definition: Process.h:343
size_t ReadScalarIntegerFromMemory(lldb::addr_t addr, uint32_t byte_size, bool is_signed, Scalar &scalar, Status &error)
Definition: Process.cpp:2375
virtual uint32_t ConvertRegisterKindToRegisterNumber(lldb::RegisterKind kind, uint32_t num)
Convert from a given register numbering scheme to the lldb register numbering scheme.
uint64_t GetSP(uint64_t fail_value=LLDB_INVALID_ADDRESS)
virtual Status WriteRegisterValueToMemory(const lldb_private::RegisterInfo *reg_info, lldb::addr_t dst_addr, uint32_t dst_len, const RegisterValue &reg_value)
bool WriteRegisterFromUnsigned(uint32_t reg, uint64_t uval)
const RegisterInfo * GetRegisterInfoByName(llvm::StringRef reg_name, uint32_t start_idx=0)
void SetUInt32(uint32_t uint, Type t=eTypeUInt32)
An error handling class.
Definition: Status.h:115
static Status FromErrorStringWithFormat(const char *format,...) __attribute__((format(printf
Definition: Status.cpp:106
static Status FromErrorString(const char *str)
Definition: Status.h:138
bool Fail() const
Test for error condition.
Definition: Status.cpp:270
const char * AsCString(const char *default_error_str="unknown error") const
Get the error string associated with the current error.
Definition: Status.cpp:195
virtual lldb::StackFrameSP GetStackFrameAtIndex(uint32_t idx)
Definition: Thread.h:408
virtual lldb::RegisterContextSP GetRegisterContext()=0
lldb::ProcessSP GetProcess() const
Definition: Thread.h:157
void SetUnwindPlanForSignalTrap(lldb_private::LazyBool is_for_signal_trap)
Definition: UnwindPlan.h:536
void SetRegisterKind(lldb::RegisterKind kind)
Definition: UnwindPlan.h:471
void AppendRow(const RowSP &row_sp)
Definition: UnwindPlan.cpp:392
std::shared_ptr< Row > RowSP
Definition: UnwindPlan.h:429
void SetSourcedFromCompiler(lldb_private::LazyBool from_compiler)
Definition: UnwindPlan.h:512
void SetSourceName(const char *)
Definition: UnwindPlan.cpp:594
void SetUnwindPlanValidAtAllInstructions(lldb_private::LazyBool valid_at_all_insn)
Definition: UnwindPlan.h:524
Value * GetValueAtIndex(size_t idx)
Definition: Value.cpp:691
static lldb::ValueObjectSP Create(ExecutionContextScope *exe_scope, lldb::ByteOrder byte_order, uint32_t addr_byte_size, lldb::addr_t address=LLDB_INVALID_ADDRESS)
const Scalar & GetScalar() const
Definition: Value.h:112
void SetCompilerType(const CompilerType &compiler_type)
Definition: Value.cpp:268
const CompilerType & GetCompilerType()
Definition: Value.cpp:239
#define LLDB_REGNUM_GENERIC_SP
Definition: lldb-defines.h:57
#define LLDB_REGNUM_GENERIC_PC
Definition: lldb-defines.h:56
A class that represents a running process on the host machine.
Definition: SBAddress.h:15
std::shared_ptr< lldb_private::ABI > ABISP
Definition: lldb-forward.h:317
std::shared_ptr< lldb_private::StackFrame > StackFrameSP
Definition: lldb-forward.h:424
std::shared_ptr< lldb_private::ValueObject > ValueObjectSP
Definition: lldb-forward.h:484
uint64_t offset_t
Definition: lldb-types.h:85
std::shared_ptr< lldb_private::Process > ProcessSP
Definition: lldb-forward.h:389
uint64_t addr_t
Definition: lldb-types.h:80
@ eRegisterKindGeneric
insn ptr reg, stack ptr reg, etc not specific to any particular target
@ eRegisterKindLLDB
lldb's internal register numbers
@ eRegisterKindDWARF
the register numbers seen DWARF
Every register is described in detail including its name, alternate name (optional),...
uint32_t byte_size
Size in bytes of the register.
uint32_t kinds[lldb::kNumRegisterKinds]
Holds all of the various register numbers for all register kinds.
const char * name
Name of this register, can't be NULL.