462 lines · cpp
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-exception6//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 30using namespace lldb;31using namespace lldb_private;32 33LLDB_PLUGIN_DEFINE(ABIMacOSX_i386)34 35enum {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 47size_t ABIMacOSX_i386::GetRedZoneSize() const { return 0; }48 49// Static Functions50 51ABISP52ABIMacOSX_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 62bool 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 to74 // write memory just needs to have the correct size of a 32 bit register, the75 // actual register it pertains to is not important, just the size needs to be76 // 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 happen80 81 // Make room for the argument(s) on the stack82 83 Status error;84 RegisterValue reg_value;85 86 // Write any arguments onto the stack87 sp -= 4 * args.size();88 89 // Align the SP90 sp &= ~(16ull - 1ull); // 16-byte alignment91 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 the104 // 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 125static bool ReadIntegerArgument(Scalar &scalar, unsigned int bit_width,126 bool is_signed, Process *process,127 addr_t ¤t_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 139bool 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 start145 // when reading data146 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 address158 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 we166 // care about others?167 CompilerType compiler_type(value->GetCompilerType());168 std::optional<uint64_t> bit_size =169 llvm::expectedToOptional(compiler_type.GetBitSize(&thread));170 if (bit_size) {171 bool is_signed;172 if (compiler_type.IsIntegerOrEnumerationType(is_signed))173 ReadIntegerArgument(value->GetScalar(), *bit_size, is_signed,174 thread.GetProcess().get(), current_stack_argument);175 else if (compiler_type.IsPointerType())176 ReadIntegerArgument(value->GetScalar(), *bit_size, false,177 thread.GetProcess().get(), current_stack_argument);178 }179 }180 181 return true;182}183 184Status ABIMacOSX_i386::SetReturnValueObject(lldb::StackFrameSP &frame_sp,185 lldb::ValueObjectSP &new_value_sp) {186 Status error;187 if (!new_value_sp) {188 error = Status::FromErrorString("Empty value object for return value.");189 return error;190 }191 192 CompilerType compiler_type = new_value_sp->GetCompilerType();193 if (!compiler_type) {194 error = Status::FromErrorString("Null clang type for return value.");195 return error;196 }197 198 Thread *thread = frame_sp->GetThread().get();199 200 bool is_signed;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(is_complex)) {243 if (is_complex)244 error = Status::FromErrorString(245 "We don't support returning complex values at present");246 else247 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 258ValueObjectSP259ABIMacOSX_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 =279 llvm::expectedToOptional(compiler_type.GetBitSize(&thread));280 if (!bit_width)281 return return_valobj_sp;282 unsigned eax_id =283 reg_ctx->GetRegisterInfoByName("eax", 0)->kinds[eRegisterKindLLDB];284 unsigned edx_id =285 reg_ctx->GetRegisterInfoByName("edx", 0)->kinds[eRegisterKindLLDB];286 287 switch (*bit_width) {288 default:289 case 128:290 // Scalar can't hold 128-bit literals, so we don't handle this291 return return_valobj_sp;292 case 64:293 uint64_t raw_value;294 raw_value =295 thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) &296 0xffffffff;297 raw_value |=298 (thread.GetRegisterContext()->ReadRegisterAsUnsigned(edx_id, 0) &299 0xffffffff)300 << 32;301 if (is_signed)302 value.GetScalar() = (int64_t)raw_value;303 else304 value.GetScalar() = (uint64_t)raw_value;305 break;306 case 32:307 if (is_signed)308 value.GetScalar() = (int32_t)(309 thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) &310 0xffffffff);311 else312 value.GetScalar() = (uint32_t)(313 thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) &314 0xffffffff);315 break;316 case 16:317 if (is_signed)318 value.GetScalar() = (int16_t)(319 thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) &320 0xffff);321 else322 value.GetScalar() = (uint16_t)(323 thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) &324 0xffff);325 break;326 case 8:327 if (is_signed)328 value.GetScalar() = (int8_t)(329 thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) &330 0xff);331 else332 value.GetScalar() = (uint8_t)(333 thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) &334 0xff);335 break;336 }337 } else if (compiler_type.IsPointerType()) {338 unsigned eax_id =339 reg_ctx->GetRegisterInfoByName("eax", 0)->kinds[eRegisterKindLLDB];340 uint32_t ptr =341 thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) &342 0xffffffff;343 value.GetScalar() = ptr;344 } else {345 // not handled yet346 return return_valobj_sp;347 }348 349 // If we get here, we have a valid Value, so make our ValueObject out of it:350 351 return_valobj_sp = ValueObjectConstResult::Create(352 thread.GetStackFrameAtIndex(0).get(), value, ConstString(""));353 return return_valobj_sp;354}355 356// This defines the CFA as esp+4357// the saved pc is at CFA-4 (i.e. esp+0)358// The saved esp is CFA+0359 360UnwindPlanSP ABIMacOSX_i386::CreateFunctionEntryUnwindPlan() {361 uint32_t sp_reg_num = dwarf_esp;362 uint32_t pc_reg_num = dwarf_eip;363 364 UnwindPlan::Row row;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 369 auto plan_sp = std::make_shared<UnwindPlan>(eRegisterKindDWARF);370 plan_sp->AppendRow(std::move(row));371 plan_sp->SetSourceName("i386 at-func-entry default");372 plan_sp->SetSourcedFromCompiler(eLazyBoolNo);373 return plan_sp;374}375 376// This defines the CFA as ebp+8377// 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+0380 381UnwindPlanSP ABIMacOSX_i386::CreateDefaultUnwindPlan() {382 uint32_t fp_reg_num = dwarf_ebp;383 uint32_t sp_reg_num = dwarf_esp;384 uint32_t pc_reg_num = dwarf_eip;385 386 UnwindPlan::Row row;387 const int32_t ptr_size = 4;388 389 row.GetCFAValue().SetIsRegisterPlusOffset(fp_reg_num, 2 * ptr_size);390 row.SetUnspecifiedRegistersAreUndefined(true);391 392 row.SetRegisterLocationToAtCFAPlusOffset(fp_reg_num, ptr_size * -2, true);393 row.SetRegisterLocationToAtCFAPlusOffset(pc_reg_num, ptr_size * -1, true);394 row.SetRegisterLocationToIsCFAPlusOffset(sp_reg_num, 0, true);395 396 auto plan_sp = std::make_shared<UnwindPlan>(eRegisterKindDWARF);397 plan_sp->AppendRow(std::move(row));398 plan_sp->SetSourceName("i386 default unwind plan");399 plan_sp->SetSourcedFromCompiler(eLazyBoolNo);400 plan_sp->SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);401 plan_sp->SetUnwindPlanForSignalTrap(eLazyBoolNo);402 return plan_sp;403}404 405bool 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/130411// -IA-412// 32_Function_Calling_Conventions/IA32.html#//apple_ref/doc/uid/TP40002492-SW4413//414// This document ("OS X ABI Function Call Guide", chapter "IA-32 Function415// Calling Conventions") says that the following registers on i386 are416// preserved aka non-volatile aka callee-saved:417//418// ebx, ebp, esi, edi, esp419 420bool ABIMacOSX_i386::RegisterIsCalleeSaved(const RegisterInfo *reg_info) {421 if (reg_info) {422 // Saved registers are ebx, ebp, esi, edi, esp, eip423 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') // sp445 return true;446 if (name[0] == 'f' && name[1] == 'p' && name[2] == '\0') // fp447 return true;448 if (name[0] == 'p' && name[1] == 'c' && name[2] == '\0') // pc449 return true;450 }451 return false;452}453 454void ABIMacOSX_i386::Initialize() {455 PluginManager::RegisterPlugin(456 GetPluginNameStatic(), "Mac OS X ABI for i386 targets", CreateInstance);457}458 459void ABIMacOSX_i386::Terminate() {460 PluginManager::UnregisterPlugin(CreateInstance);461}462