diff options
Diffstat (limited to 'contrib/llvm/tools/lldb/source/Plugins/LanguageRuntime/Go/GoLanguageRuntime.cpp')
-rw-r--r-- | contrib/llvm/tools/lldb/source/Plugins/LanguageRuntime/Go/GoLanguageRuntime.cpp | 238 |
1 files changed, 238 insertions, 0 deletions
diff --git a/contrib/llvm/tools/lldb/source/Plugins/LanguageRuntime/Go/GoLanguageRuntime.cpp b/contrib/llvm/tools/lldb/source/Plugins/LanguageRuntime/Go/GoLanguageRuntime.cpp new file mode 100644 index 0000000..d59f292 --- /dev/null +++ b/contrib/llvm/tools/lldb/source/Plugins/LanguageRuntime/Go/GoLanguageRuntime.cpp @@ -0,0 +1,238 @@ +//===-- GoLanguageRuntime.cpp --------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "GoLanguageRuntime.h" + +#include "lldb/Breakpoint/BreakpointLocation.h" +#include "lldb/Core/ConstString.h" +#include "lldb/Core/Error.h" +#include "lldb/Core/Log.h" +#include "lldb/Core/Module.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Core/Scalar.h" +#include "lldb/Core/ValueObject.h" +#include "lldb/Core/ValueObjectMemory.h" +#include "lldb/Symbol/GoASTContext.h" +#include "lldb/Symbol/Symbol.h" +#include "lldb/Symbol/TypeList.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/RegisterContext.h" +#include "lldb/Target/SectionLoadList.h" +#include "lldb/Target/StopInfo.h" +#include "lldb/Target/Target.h" +#include "lldb/Target/Thread.h" +#include "llvm/ADT/Twine.h" + +#include <vector> + +using namespace lldb; +using namespace lldb_private; + +namespace { +ValueObjectSP GetChild(ValueObject& obj, const char* name, bool dereference = true) { + ConstString name_const_str(name); + ValueObjectSP result = obj.GetChildMemberWithName(name_const_str, true); + if (dereference && result && result->IsPointerType()) { + Error err; + result = result->Dereference(err); + if (err.Fail()) + result.reset(); + } + return result; +} + +ConstString ReadString(ValueObject& str, Process* process) { + ConstString result; + ValueObjectSP data = GetChild(str, "str", false); + ValueObjectSP len = GetChild(str, "len"); + if (len && data) + { + Error err; + lldb::addr_t addr = data->GetPointerValue(); + if (addr == LLDB_INVALID_ADDRESS) + return result; + uint64_t byte_size = len->GetValueAsUnsigned(0); + char* buf = new char[byte_size + 1]; + buf[byte_size] = 0; + size_t bytes_read = process->ReadMemory (addr, + buf, + byte_size, + err); + if (!(err.Fail() || bytes_read != byte_size)) + result = ConstString(buf, bytes_read); + delete[] buf; + } + return result; +} + +ConstString +ReadTypeName(ValueObjectSP type, Process* process) +{ + if (ValueObjectSP uncommon = GetChild(*type, "x")) + { + ValueObjectSP name = GetChild(*uncommon, "name"); + ValueObjectSP package = GetChild(*uncommon, "pkgpath"); + if (name && name->GetPointerValue() != 0 && package && package->GetPointerValue() != 0) + { + ConstString package_const_str = ReadString(*package, process); + ConstString name_const_str = ReadString(*name, process); + if (package_const_str.GetLength() == 0) + return name_const_str; + return ConstString((package_const_str.GetStringRef() + "." + name_const_str.GetStringRef()).str()); + } + } + ValueObjectSP name = GetChild(*type, "_string"); + if (name) + return ReadString(*name, process); + return ConstString(""); +} + +CompilerType +LookupRuntimeType(ValueObjectSP type, ExecutionContext* exe_ctx, bool* is_direct) +{ + uint8_t kind = GetChild(*type, "kind")->GetValueAsUnsigned(0); + *is_direct = GoASTContext::IsDirectIface(kind); + if (GoASTContext::IsPointerKind(kind)) + { + CompilerType type_ptr = type->GetCompilerType().GetPointerType(); + Error err; + ValueObjectSP elem = type->CreateValueObjectFromAddress("elem", type->GetAddressOf() + type->GetByteSize(), *exe_ctx, type_ptr)->Dereference(err); + if (err.Fail()) + return CompilerType(); + bool tmp_direct; + return LookupRuntimeType(elem, exe_ctx, &tmp_direct).GetPointerType(); + } + Target *target = exe_ctx->GetTargetPtr(); + Process *process = exe_ctx->GetProcessPtr(); + + ConstString const_typename = ReadTypeName(type, process); + if (const_typename.GetLength() == 0) + return CompilerType(); + + SymbolContext sc; + TypeList type_list; + uint32_t num_matches = target->GetImages().FindTypes (sc, + const_typename, + false, + 2, + type_list); + if (num_matches > 0) { + return type_list.GetTypeAtIndex(0)->GetFullCompilerType(); + } + return CompilerType(); +} + +} + +bool +GoLanguageRuntime::CouldHaveDynamicValue (ValueObject &in_value) +{ + return GoASTContext::IsGoInterface(in_value.GetCompilerType()); +} + +bool +GoLanguageRuntime::GetDynamicTypeAndAddress(ValueObject &in_value, lldb::DynamicValueType use_dynamic, + TypeAndOrName &class_type_or_name, Address &dynamic_address, + Value::ValueType &value_type) +{ + value_type = Value::eValueTypeScalar; + class_type_or_name.Clear(); + if (CouldHaveDynamicValue (in_value)) + { + Error err; + ValueObjectSP iface = in_value.GetStaticValue(); + ValueObjectSP data_sp = GetChild(*iface, "data", false); + if (!data_sp) + return false; + + if (ValueObjectSP tab = GetChild(*iface, "tab")) + iface = tab; + ValueObjectSP type = GetChild(*iface, "_type"); + if (!type) + { + return false; + } + + bool direct; + ExecutionContext exe_ctx (in_value.GetExecutionContextRef()); + CompilerType final_type = LookupRuntimeType(type, &exe_ctx, &direct); + if (!final_type) + return false; + if (direct) + { + class_type_or_name.SetCompilerType(final_type); + } + else + { + // TODO: implement reference types or fix caller to support dynamic types that aren't pointers + // so we don't have to introduce this extra pointer. + class_type_or_name.SetCompilerType(final_type.GetPointerType()); + } + + dynamic_address.SetLoadAddress(data_sp->GetPointerValue(), exe_ctx.GetTargetPtr()); + + return true; + } + return false; +} + +TypeAndOrName +GoLanguageRuntime::FixUpDynamicType(const TypeAndOrName &type_and_or_name, ValueObject &static_value) +{ + return type_and_or_name; +} + +//------------------------------------------------------------------ +// Static Functions +//------------------------------------------------------------------ +LanguageRuntime * +GoLanguageRuntime::CreateInstance (Process *process, lldb::LanguageType language) +{ + if (language == eLanguageTypeGo) + return new GoLanguageRuntime (process); + else + return NULL; +} + +void +GoLanguageRuntime::Initialize() +{ + PluginManager::RegisterPlugin (GetPluginNameStatic(), + "Go Language Runtime", + CreateInstance); +} + +void +GoLanguageRuntime::Terminate() +{ + PluginManager::UnregisterPlugin (CreateInstance); +} + +lldb_private::ConstString +GoLanguageRuntime::GetPluginNameStatic() +{ + static ConstString g_name("golang"); + return g_name; +} + +//------------------------------------------------------------------ +// PluginInterface protocol +//------------------------------------------------------------------ +lldb_private::ConstString +GoLanguageRuntime::GetPluginName() +{ + return GetPluginNameStatic(); +} + +uint32_t +GoLanguageRuntime::GetPluginVersion() +{ + return 1; +} + |