forked from OSchip/llvm-project
				
			
		
			
				
	
	
		
			216 lines
		
	
	
		
			7.0 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			216 lines
		
	
	
		
			7.0 KiB
		
	
	
	
		
			C++
		
	
	
	
| //===-- 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/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/SymbolFile.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 "lldb/Utility/ConstString.h"
 | |
| #include "lldb/Utility/Log.h"
 | |
| #include "lldb/Utility/Status.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()) {
 | |
|     Status 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) {
 | |
|     Status 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();
 | |
|     Status 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;
 | |
|   llvm::DenseSet<SymbolFile *> searched_symbol_files;
 | |
|   uint32_t num_matches = target->GetImages().FindTypes(
 | |
|       sc, const_typename, false, 2, searched_symbol_files, 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)) {
 | |
|     Status 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; }
 |