summaryrefslogtreecommitdiffstats
path: root/lldb/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lldb/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.cpp')
-rw-r--r--lldb/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.cpp578
1 files changed, 578 insertions, 0 deletions
diff --git a/lldb/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.cpp b/lldb/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.cpp
new file mode 100644
index 00000000000..09cc09d024c
--- /dev/null
+++ b/lldb/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.cpp
@@ -0,0 +1,578 @@
+//===-- ABIMacOSX_i386.cpp --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ABIMacOSX_i386.h"
+
+#include "lldb/Core/ConstString.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/Scalar.h"
+#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+
+#include "llvm/ADT/Triple.h"
+
+#include <vector>
+
+using namespace lldb;
+using namespace lldb_private;
+
+static const char *pluginName = "ABIMacOSX_i386";
+static const char *pluginDesc = "Mac OS X ABI for i386 targets";
+static const char *pluginShort = "abi.macosx-i386";
+
+size_t
+ABIMacOSX_i386::GetRedZoneSize () const
+{
+ return 0;
+}
+
+//------------------------------------------------------------------
+// Static Functions
+//------------------------------------------------------------------
+lldb_private::ABI *
+ABIMacOSX_i386::CreateInstance (const ConstString &triple)
+{
+ llvm::StringRef tripleStr(triple.GetCString());
+ llvm::Triple llvmTriple(tripleStr);
+
+ if (llvmTriple.getArch() != llvm::Triple::x86)
+ return NULL;
+
+ return new ABIMacOSX_i386;
+}
+
+bool
+ABIMacOSX_i386::PrepareTrivialCall (Thread &thread,
+ lldb::addr_t sp,
+ lldb::addr_t functionAddress,
+ lldb::addr_t returnAddress,
+ lldb::addr_t arg) const
+{
+ RegisterContext *reg_ctx = thread.GetRegisterContext();
+ if (!reg_ctx)
+ return false;
+
+ uint32_t ebpID = reg_ctx->ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FP);
+ uint32_t eipID = reg_ctx->ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);
+ uint32_t espID = reg_ctx->ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP);
+
+ // Make room for the argument on the stack
+
+ sp -= 4;
+
+ // Align the SP
+
+ sp &= ~(0xfull); // 16-byte alignment
+
+ // Write the argument on the stack
+
+ uint32_t argU32 = arg & 0xffffffffull;
+ Error error;
+ if (thread.GetProcess().WriteMemory (sp, &argU32, sizeof(argU32), error) != sizeof(argU32))
+ return false;
+
+ // The return address is pushed onto the stack.
+
+ sp -= 4;
+ uint32_t returnAddressU32 = returnAddress;
+ if (thread.GetProcess().WriteMemory (sp, &returnAddressU32, sizeof(returnAddressU32), error) != sizeof(returnAddressU32))
+ return false;
+
+ // %esp is set to the actual stack value.
+
+ if (!reg_ctx->WriteRegisterFromUnsigned(espID, sp))
+ return false;
+
+ // %ebp is set to a fake value, in our case 0x0x00000000
+
+ if (!reg_ctx->WriteRegisterFromUnsigned(ebpID, 0x00000000))
+ return false;
+
+ // %eip is set to the address of the called function.
+
+ if (!reg_ctx->WriteRegisterFromUnsigned(eipID, functionAddress))
+ return false;
+
+ return true;
+}
+
+bool
+ABIMacOSX_i386::PrepareNormalCall (Thread &thread,
+ lldb::addr_t sp,
+ lldb::addr_t functionAddress,
+ lldb::addr_t returnAddress,
+ ValueList &args) const
+{
+ RegisterContext *reg_ctx = thread.GetRegisterContext();
+ if (!reg_ctx)
+ return false;
+ Error error;
+ uint32_t ebpID = reg_ctx->ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FP);
+ uint32_t eipID = reg_ctx->ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);
+ uint32_t espID = reg_ctx->ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP);
+
+ // Do the argument layout
+
+ std::vector <uint32_t> argLayout; // 4-byte chunks, as discussed in the ABI Function Call Guide
+
+ size_t numArgs = args.GetSize();
+ size_t index;
+
+ for (index = 0; index < numArgs; ++index)
+ {
+ Value *val = args.GetValueAtIndex(index);
+
+ if (!val)
+ return false;
+
+ switch (val->GetValueType())
+ {
+ case Value::eValueTypeScalar:
+ {
+ Scalar &scalar = val->GetScalar();
+ switch (scalar.GetType())
+ {
+ case Scalar::e_void:
+ default:
+ return false;
+ case Scalar::e_sint:
+ case Scalar::e_uint:
+ case Scalar::e_slong:
+ case Scalar::e_ulong:
+ case Scalar::e_slonglong:
+ case Scalar::e_ulonglong:
+ {
+ uint64_t data = scalar.ULongLong();
+
+ switch (scalar.GetByteSize())
+ {
+ default:
+ return false;
+ case 1:
+ argLayout.push_back((uint32_t)(data & 0xffull));
+ break;
+ case 2:
+ argLayout.push_back((uint32_t)(data & 0xffffull));
+ break;
+ case 4:
+ argLayout.push_back((uint32_t)(data & 0xffffffffull));
+ break;
+ case 8:
+ argLayout.push_back((uint32_t)(data & 0xffffffffull));
+ argLayout.push_back((uint32_t)(data >> 32));
+ break;
+ }
+ }
+ break;
+ case Scalar::e_float:
+ {
+ float data = scalar.Float();
+ uint32_t dataRaw = *((uint32_t*)(&data));
+ argLayout.push_back(dataRaw);
+ }
+ break;
+ case Scalar::e_double:
+ {
+ double data = scalar.Double();
+ uint32_t *dataRaw = ((uint32_t*)(&data));
+ argLayout.push_back(dataRaw[0]);
+ argLayout.push_back(dataRaw[1]);
+ }
+ break;
+ case Scalar::e_long_double:
+ {
+ long double data = scalar.Double();
+ uint32_t *dataRaw = ((uint32_t*)(&data));
+ while ((argLayout.size() * 4) & 0xf)
+ argLayout.push_back(0);
+ argLayout.push_back(dataRaw[0]);
+ argLayout.push_back(dataRaw[1]);
+ argLayout.push_back(dataRaw[2]);
+ argLayout.push_back(dataRaw[3]);
+ }
+ break;
+ }
+ }
+ break;
+ case Value::eValueTypeHostAddress:
+ switch (val->GetContextType())
+ {
+ default:
+ return false;
+ case Value::eContextTypeOpaqueClangQualType:
+ {
+ void *val_type = val->GetOpaqueClangQualType();
+ uint32_t cstr_length;
+
+ if (ClangASTContext::IsCStringType (val_type, cstr_length))
+ {
+ const char *cstr = (const char*)val->GetScalar().ULongLong();
+ cstr_length = strlen(cstr);
+
+ // Push the string onto the stack immediately.
+
+ sp -= (cstr_length + 1);
+
+ if (thread.GetProcess().WriteMemory(sp, cstr, cstr_length + 1, error) != (cstr_length + 1))
+ return false;
+
+ // Put the address of the string into the argument array.
+
+ argLayout.push_back((uint32_t)(sp & 0xffffffff));
+ }
+ else
+ {
+ return false;
+ }
+ }
+ break;
+ }
+ break;
+ case Value::eValueTypeFileAddress:
+ case Value::eValueTypeLoadAddress:
+ default:
+ return false;
+ }
+ }
+
+ // Make room for the arguments on the stack
+
+ sp -= 4 * argLayout.size();
+
+ // Align the SP
+
+ sp &= ~(0xfull); // 16-byte alignment
+
+ // Write the arguments on the stack
+
+ size_t numChunks = argLayout.size();
+
+ for (index = 0; index < numChunks; ++index)
+ if (thread.GetProcess().WriteMemory(sp + (index * 4), &argLayout[index], sizeof(uint32_t), error) != sizeof(uint32_t))
+ return false;
+
+ // The return address is pushed onto the stack.
+
+ sp -= 4;
+ uint32_t returnAddressU32 = returnAddress;
+ if (thread.GetProcess().WriteMemory (sp, &returnAddressU32, sizeof(returnAddressU32), error) != sizeof(returnAddressU32))
+ return false;
+
+ // %esp is set to the actual stack value.
+
+ if (!reg_ctx->WriteRegisterFromUnsigned(espID, sp))
+ return false;
+
+ // %ebp is set to a fake value, in our case 0x0x00000000
+
+ if (!reg_ctx->WriteRegisterFromUnsigned(ebpID, 0x00000000))
+ return false;
+
+ // %eip is set to the address of the called function.
+
+ if (!reg_ctx->WriteRegisterFromUnsigned(eipID, functionAddress))
+ return false;
+
+ return true;
+}
+
+static bool ReadIntegerArgument(Scalar &scalar,
+ unsigned int bit_width,
+ bool is_signed,
+ Process &process,
+ addr_t &current_stack_argument)
+{
+ if (bit_width > 64)
+ return false; // Scalar can't hold large integer arguments
+
+ uint64_t arg_contents;
+ uint32_t read_data;
+ Error error;
+
+ if (bit_width > 32)
+ {
+ if (process.ReadMemory(current_stack_argument, &read_data, sizeof(read_data), error) != sizeof(read_data))
+ return false;
+
+ arg_contents = read_data;
+
+ if (process.ReadMemory(current_stack_argument + 4, &read_data, sizeof(read_data), error) != sizeof(read_data))
+ return false;
+
+ arg_contents |= ((uint64_t)read_data) << 32;
+
+ current_stack_argument += 8;
+ }
+ else {
+ if (process.ReadMemory(current_stack_argument, &read_data, sizeof(read_data), error) != sizeof(read_data))
+ return false;
+
+ arg_contents = read_data;
+
+ current_stack_argument += 4;
+ }
+
+ if (is_signed)
+ {
+ switch (bit_width)
+ {
+ default:
+ return false;
+ case 8:
+ scalar = (int8_t)(arg_contents & 0xff);
+ break;
+ case 16:
+ scalar = (int16_t)(arg_contents & 0xffff);
+ break;
+ case 32:
+ scalar = (int32_t)(arg_contents & 0xffffffff);
+ break;
+ case 64:
+ scalar = (int64_t)arg_contents;
+ break;
+ }
+ }
+ else
+ {
+ switch (bit_width)
+ {
+ default:
+ return false;
+ case 8:
+ scalar = (uint8_t)(arg_contents & 0xff);
+ break;
+ case 16:
+ scalar = (uint16_t)(arg_contents & 0xffff);
+ break;
+ case 32:
+ scalar = (uint32_t)(arg_contents & 0xffffffff);
+ break;
+ case 64:
+ scalar = (uint64_t)arg_contents;
+ break;
+ }
+ }
+
+ return true;
+}
+
+bool
+ABIMacOSX_i386::GetArgumentValues (Thread &thread,
+ ValueList &values) const
+{
+ unsigned int num_values = values.GetSize();
+ unsigned int value_index;
+
+ // Extract the Clang AST context from the PC so that we can figure out type
+ // sizes
+
+ clang::ASTContext *ast_context = thread.CalculateTarget()->GetScratchClangASTContext()->getASTContext();
+
+ // Get the pointer to the first stack argument so we have a place to start
+ // when reading data
+
+ RegisterContext *reg_ctx = thread.GetRegisterContext();
+
+ if (!reg_ctx)
+ return false;
+
+ addr_t sp = reg_ctx->GetSP(0);
+
+ if (!sp)
+ return false;
+
+ addr_t current_stack_argument = sp + 4; // jump over return address
+
+ for (value_index = 0;
+ value_index < num_values;
+ ++value_index)
+ {
+ Value *value = values.GetValueAtIndex(value_index);
+
+ if (!value)
+ return false;
+
+ // We currently only support extracting values with Clang QualTypes.
+ // Do we care about others?
+ switch (value->GetContextType())
+ {
+ default:
+ return false;
+ case Value::eContextTypeOpaqueClangQualType:
+ {
+ void *value_type = value->GetOpaqueClangQualType();
+ bool is_signed;
+
+ if (ClangASTContext::IsIntegerType (value_type, is_signed))
+ {
+ size_t bit_width = ClangASTContext::GetTypeBitSize(ast_context, value_type);
+
+ ReadIntegerArgument(value->GetScalar(),
+ bit_width,
+ is_signed,
+ thread.GetProcess(),
+ current_stack_argument);
+ }
+ else if (ClangASTContext::IsPointerType (value_type))
+ {
+ ReadIntegerArgument(value->GetScalar(),
+ 32,
+ false,
+ thread.GetProcess(),
+ current_stack_argument);
+ }
+ }
+ break;
+ }
+ }
+
+ return true;
+}
+
+bool
+ABIMacOSX_i386::GetReturnValue (Thread &thread,
+ Value &value) const
+{
+ switch (value.GetContextType())
+ {
+ default:
+ return false;
+ case Value::eContextTypeOpaqueClangQualType:
+ {
+ // Extract the Clang AST context from the PC so that we can figure out type
+ // sizes
+
+ clang::ASTContext *ast_context = thread.CalculateTarget()->GetScratchClangASTContext()->getASTContext();
+
+ // Get the pointer to the first stack argument so we have a place to start
+ // when reading data
+
+ RegisterContext *reg_ctx = thread.GetRegisterContext();
+
+ void *value_type = value.GetOpaqueClangQualType();
+ bool is_signed;
+
+ if (ClangASTContext::IsIntegerType (value_type, is_signed))
+ {
+ size_t bit_width = ClangASTContext::GetTypeBitSize(ast_context, value_type);
+
+ unsigned eax_id = reg_ctx->GetRegisterInfoByName("eax", 0)->reg;
+ unsigned edx_id = reg_ctx->GetRegisterInfoByName("edx", 0)->reg;
+
+ switch (bit_width)
+ {
+ default:
+ case 128:
+ // Scalar can't hold 128-bit literals, so we don't handle this
+ return false;
+ case 64:
+ uint64_t raw_value;
+ raw_value = thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) & 0xffffffff;
+ raw_value |= (thread.GetRegisterContext()->ReadRegisterAsUnsigned(edx_id, 0) & 0xffffffff) << 32;
+ if (is_signed)
+ value.GetScalar() = (int64_t)raw_value;
+ else
+ value.GetScalar() = (uint64_t)raw_value;
+ break;
+ case 32:
+ if (is_signed)
+ value.GetScalar() = (int32_t)(thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) & 0xffffffff);
+ else
+ value.GetScalar() = (uint32_t)(thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) & 0xffffffff);
+ break;
+ case 16:
+ if (is_signed)
+ value.GetScalar() = (int16_t)(thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) & 0xffff);
+ else
+ value.GetScalar() = (uint16_t)(thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) & 0xffff);
+ break;
+ case 8:
+ if (is_signed)
+ value.GetScalar() = (int8_t)(thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) & 0xff);
+ else
+ value.GetScalar() = (uint8_t)(thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) & 0xff);
+ break;
+ }
+ }
+ else if (ClangASTContext::IsPointerType (value_type))
+ {
+ unsigned eax_id = reg_ctx->GetRegisterInfoByName("eax", 0)->reg;
+ uint32_t ptr = thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) & 0xffffffff;
+ value.GetScalar() = ptr;
+ }
+ else
+ {
+ // not handled yet
+ return false;
+ }
+ }
+ break;
+ }
+
+ return true;
+}
+
+void
+ABIMacOSX_i386::Initialize()
+{
+ PluginManager::RegisterPlugin (pluginName,
+ pluginDesc,
+ CreateInstance);
+}
+
+void
+ABIMacOSX_i386::Terminate()
+{
+ PluginManager::UnregisterPlugin (CreateInstance);
+}
+
+//------------------------------------------------------------------
+// PluginInterface protocol
+//------------------------------------------------------------------
+const char *
+ABIMacOSX_i386::GetPluginName()
+{
+ return pluginName;
+}
+
+const char *
+ABIMacOSX_i386::GetShortPluginName()
+{
+ return pluginShort;
+}
+
+uint32_t
+ABIMacOSX_i386::GetPluginVersion()
+{
+ return 1;
+}
+
+void
+ABIMacOSX_i386::GetPluginCommandHelp (const char *command, Stream *strm)
+{
+}
+
+Error
+ABIMacOSX_i386::ExecutePluginCommand (Args &command, Stream *strm)
+{
+ Error error;
+ error.SetErrorString("No plug-in command are currently supported.");
+ return error;
+}
+
+Log *
+ABIMacOSX_i386::EnablePluginLogging (Stream *strm, Args &command)
+{
+ return NULL;
+}
OpenPOWER on IntegriCloud