brintos

brintos / llvm-project-archived public Read only

0
0
Text · 14.3 KiB · ee79abe Raw
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 &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 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