forked from OSchip/llvm-project
831 lines
36 KiB
C++
831 lines
36 KiB
C++
//===-- DWARFASTParserGo.cpp ---------------------------------*- C++ -*-===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "DWARFASTParserGo.h"
|
|
|
|
#include "DWARFASTParserGo.h"
|
|
#include "DWARFCompileUnit.h"
|
|
#include "DWARFDebugInfo.h"
|
|
#include "DWARFDeclContext.h"
|
|
#include "DWARFDefines.h"
|
|
#include "DWARFDIE.h"
|
|
#include "DWARFDIECollection.h"
|
|
#include "SymbolFileDWARF.h"
|
|
#include "SymbolFileDWARFDebugMap.h"
|
|
#include "UniqueDWARFASTType.h"
|
|
|
|
#include "clang/Basic/Specifiers.h"
|
|
|
|
#include "lldb/Core/Module.h"
|
|
#include "lldb/Core/Value.h"
|
|
#include "lldb/Symbol/CompileUnit.h"
|
|
#include "lldb/Symbol/Function.h"
|
|
#include "lldb/Symbol/ObjectFile.h"
|
|
#include "lldb/Symbol/TypeList.h"
|
|
|
|
//#define ENABLE_DEBUG_PRINTF // COMMENT OUT THIS LINE PRIOR TO CHECKIN
|
|
|
|
#ifdef ENABLE_DEBUG_PRINTF
|
|
#include <stdio.h>
|
|
#define DEBUG_PRINTF(fmt, ...) printf(fmt, __VA_ARGS__)
|
|
#else
|
|
#define DEBUG_PRINTF(fmt, ...)
|
|
#endif
|
|
|
|
#define DW_AT_go_kind 0x2900
|
|
#define DW_AT_go_key 0x2901
|
|
#define DW_AT_go_elem 0x2902
|
|
|
|
using namespace lldb;
|
|
using namespace lldb_private;
|
|
DWARFASTParserGo::DWARFASTParserGo(GoASTContext &ast)
|
|
: m_ast(ast)
|
|
{
|
|
}
|
|
|
|
DWARFASTParserGo::~DWARFASTParserGo()
|
|
{
|
|
}
|
|
|
|
TypeSP
|
|
DWARFASTParserGo::ParseTypeFromDWARF(const lldb_private::SymbolContext &sc, const DWARFDIE &die, lldb_private::Log *log,
|
|
bool *type_is_new_ptr)
|
|
{
|
|
TypeSP type_sp;
|
|
|
|
if (type_is_new_ptr)
|
|
*type_is_new_ptr = false;
|
|
|
|
if (die)
|
|
{
|
|
SymbolFileDWARF *dwarf = die.GetDWARF();
|
|
if (log)
|
|
{
|
|
dwarf->GetObjectFile()->GetModule()->LogMessage(
|
|
log, "DWARFASTParserGo::ParseTypeFromDWARF (die = 0x%8.8x) %s name = '%s')", die.GetOffset(),
|
|
DW_TAG_value_to_name(die.Tag()), die.GetName());
|
|
}
|
|
|
|
Type *type_ptr = dwarf->m_die_to_type.lookup(die.GetDIE());
|
|
TypeList *type_list = dwarf->GetTypeList();
|
|
if (type_ptr == NULL)
|
|
{
|
|
if (type_is_new_ptr)
|
|
*type_is_new_ptr = true;
|
|
|
|
const dw_tag_t tag = die.Tag();
|
|
|
|
bool is_forward_declaration = false;
|
|
DWARFAttributes attributes;
|
|
const char *type_name_cstr = NULL;
|
|
ConstString type_name_const_str;
|
|
Type::ResolveState resolve_state = Type::eResolveStateUnresolved;
|
|
uint64_t byte_size = 0;
|
|
uint64_t go_kind = 0;
|
|
Declaration decl;
|
|
|
|
Type::EncodingDataType encoding_data_type = Type::eEncodingIsUID;
|
|
CompilerType compiler_type;
|
|
DWARFFormValue form_value;
|
|
|
|
dw_attr_t attr;
|
|
|
|
switch (tag)
|
|
{
|
|
case DW_TAG_base_type:
|
|
case DW_TAG_pointer_type:
|
|
case DW_TAG_typedef:
|
|
case DW_TAG_unspecified_type:
|
|
{
|
|
// Set a bit that lets us know that we are currently parsing this
|
|
dwarf->m_die_to_type[die.GetDIE()] = DIE_IS_BEING_PARSED;
|
|
|
|
const size_t num_attributes = die.GetAttributes(attributes);
|
|
lldb::user_id_t encoding_uid = LLDB_INVALID_UID;
|
|
|
|
if (num_attributes > 0)
|
|
{
|
|
uint32_t i;
|
|
for (i = 0; i < num_attributes; ++i)
|
|
{
|
|
attr = attributes.AttributeAtIndex(i);
|
|
if (attributes.ExtractFormValueAtIndex(i, form_value))
|
|
{
|
|
switch (attr)
|
|
{
|
|
case DW_AT_name:
|
|
type_name_cstr = form_value.AsCString();
|
|
if (type_name_cstr)
|
|
type_name_const_str.SetCString(type_name_cstr);
|
|
break;
|
|
case DW_AT_byte_size:
|
|
byte_size = form_value.Unsigned();
|
|
break;
|
|
case DW_AT_encoding:
|
|
// = form_value.Unsigned();
|
|
break;
|
|
case DW_AT_type:
|
|
encoding_uid = form_value.Reference();
|
|
break;
|
|
case DW_AT_go_kind:
|
|
go_kind = form_value.Unsigned();
|
|
break;
|
|
default:
|
|
// Do we care about DW_AT_go_key or DW_AT_go_elem?
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
DEBUG_PRINTF("0x%8.8" PRIx64 ": %s (\"%s\") type => 0x%8.8lx\n", die.GetID(),
|
|
DW_TAG_value_to_name(tag), type_name_cstr, encoding_uid);
|
|
|
|
switch (tag)
|
|
{
|
|
default:
|
|
break;
|
|
|
|
case DW_TAG_unspecified_type:
|
|
resolve_state = Type::eResolveStateFull;
|
|
compiler_type = m_ast.CreateVoidType(type_name_const_str);
|
|
break;
|
|
|
|
case DW_TAG_base_type:
|
|
resolve_state = Type::eResolveStateFull;
|
|
compiler_type = m_ast.CreateBaseType(go_kind, type_name_const_str, byte_size);
|
|
break;
|
|
|
|
case DW_TAG_pointer_type:
|
|
encoding_data_type = Type::eEncodingIsPointerUID;
|
|
break;
|
|
case DW_TAG_typedef:
|
|
encoding_data_type = Type::eEncodingIsTypedefUID;
|
|
CompilerType impl;
|
|
Type *type = dwarf->ResolveTypeUID(encoding_uid);
|
|
if (type)
|
|
{
|
|
if (go_kind == 0 && type->GetName() == type_name_const_str)
|
|
{
|
|
// Go emits extra typedefs as a forward declaration. Ignore these.
|
|
dwarf->m_die_to_type[die.GetDIE()] = type;
|
|
return type->shared_from_this();
|
|
}
|
|
impl = type->GetForwardCompilerType();
|
|
compiler_type = m_ast.CreateTypedefType (go_kind, type_name_const_str, impl);
|
|
}
|
|
break;
|
|
}
|
|
|
|
type_sp.reset(new Type(die.GetID(), dwarf, type_name_const_str, byte_size,
|
|
NULL, encoding_uid, encoding_data_type, &decl, compiler_type, resolve_state));
|
|
|
|
dwarf->m_die_to_type[die.GetDIE()] = type_sp.get();
|
|
}
|
|
break;
|
|
|
|
case DW_TAG_structure_type:
|
|
{
|
|
// Set a bit that lets us know that we are currently parsing this
|
|
dwarf->m_die_to_type[die.GetDIE()] = DIE_IS_BEING_PARSED;
|
|
bool byte_size_valid = false;
|
|
|
|
const size_t num_attributes = die.GetAttributes(attributes);
|
|
if (num_attributes > 0)
|
|
{
|
|
uint32_t i;
|
|
for (i = 0; i < num_attributes; ++i)
|
|
{
|
|
attr = attributes.AttributeAtIndex(i);
|
|
if (attributes.ExtractFormValueAtIndex(i, form_value))
|
|
{
|
|
switch (attr)
|
|
{
|
|
case DW_AT_name:
|
|
type_name_cstr = form_value.AsCString();
|
|
type_name_const_str.SetCString(type_name_cstr);
|
|
break;
|
|
|
|
case DW_AT_byte_size:
|
|
byte_size = form_value.Unsigned();
|
|
byte_size_valid = true;
|
|
break;
|
|
|
|
case DW_AT_go_kind:
|
|
go_kind = form_value.Unsigned();
|
|
break;
|
|
|
|
// TODO: Should we use SLICETYPE's DW_AT_go_elem?
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// TODO(ribrdb): Do we need this?
|
|
|
|
// UniqueDWARFASTType is large, so don't create a local variables on the
|
|
// stack, put it on the heap. This function is often called recursively
|
|
// and clang isn't good and sharing the stack space for variables in different blocks.
|
|
std::unique_ptr<UniqueDWARFASTType> unique_ast_entry_ap(new UniqueDWARFASTType());
|
|
|
|
// Only try and unique the type if it has a name.
|
|
if (type_name_const_str &&
|
|
dwarf->GetUniqueDWARFASTTypeMap().Find(type_name_const_str, die, decl,
|
|
byte_size_valid ? byte_size : -1, *unique_ast_entry_ap))
|
|
{
|
|
// We have already parsed this type or from another
|
|
// compile unit. GCC loves to use the "one definition
|
|
// rule" which can result in multiple definitions
|
|
// of the same class over and over in each compile
|
|
// unit.
|
|
type_sp = unique_ast_entry_ap->m_type_sp;
|
|
if (type_sp)
|
|
{
|
|
dwarf->m_die_to_type[die.GetDIE()] = type_sp.get();
|
|
return type_sp;
|
|
}
|
|
}
|
|
|
|
DEBUG_PRINTF("0x%8.8" PRIx64 ": %s (\"%s\")\n", die.GetID(),
|
|
DW_TAG_value_to_name(tag), type_name_cstr);
|
|
|
|
bool compiler_type_was_created = false;
|
|
compiler_type.SetCompilerType(&m_ast, dwarf->m_forward_decl_die_to_clang_type.lookup(die.GetDIE()));
|
|
if (!compiler_type)
|
|
{
|
|
compiler_type_was_created = true;
|
|
compiler_type = m_ast.CreateStructType(go_kind, type_name_const_str, byte_size);
|
|
}
|
|
|
|
type_sp.reset(new Type(die.GetID(), dwarf, type_name_const_str, byte_size,
|
|
NULL, LLDB_INVALID_UID, Type::eEncodingIsUID, &decl, compiler_type,
|
|
Type::eResolveStateForward));
|
|
|
|
// Add our type to the unique type map so we don't
|
|
// end up creating many copies of the same type over
|
|
// and over in the ASTContext for our module
|
|
unique_ast_entry_ap->m_type_sp = type_sp;
|
|
unique_ast_entry_ap->m_die = die;
|
|
unique_ast_entry_ap->m_declaration = decl;
|
|
unique_ast_entry_ap->m_byte_size = byte_size;
|
|
dwarf->GetUniqueDWARFASTTypeMap().Insert(type_name_const_str, *unique_ast_entry_ap);
|
|
|
|
if (!is_forward_declaration)
|
|
{
|
|
// Always start the definition for a class type so that
|
|
// if the class has child classes or types that require
|
|
// the class to be created for use as their decl contexts
|
|
// the class will be ready to accept these child definitions.
|
|
if (die.HasChildren() == false)
|
|
{
|
|
// No children for this struct/union/class, lets finish it
|
|
m_ast.CompleteStructType(compiler_type);
|
|
}
|
|
else if (compiler_type_was_created)
|
|
{
|
|
// Leave this as a forward declaration until we need
|
|
// to know the details of the type. lldb_private::Type
|
|
// will automatically call the SymbolFile virtual function
|
|
// "SymbolFileDWARF::CompleteType(Type *)"
|
|
// When the definition needs to be defined.
|
|
dwarf->m_forward_decl_die_to_clang_type[die.GetDIE()] = compiler_type.GetOpaqueQualType();
|
|
dwarf->m_forward_decl_clang_type_to_die[compiler_type.GetOpaqueQualType()] = die.GetDIERef();
|
|
// SetHasExternalStorage (compiler_type.GetOpaqueQualType(), true);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case DW_TAG_subprogram:
|
|
case DW_TAG_subroutine_type:
|
|
{
|
|
// Set a bit that lets us know that we are currently parsing this
|
|
dwarf->m_die_to_type[die.GetDIE()] = DIE_IS_BEING_PARSED;
|
|
|
|
bool is_variadic = false;
|
|
clang::StorageClass storage = clang::SC_None; //, Extern, Static, PrivateExtern
|
|
|
|
const size_t num_attributes = die.GetAttributes(attributes);
|
|
if (num_attributes > 0)
|
|
{
|
|
uint32_t i;
|
|
for (i = 0; i < num_attributes; ++i)
|
|
{
|
|
attr = attributes.AttributeAtIndex(i);
|
|
if (attributes.ExtractFormValueAtIndex(i, form_value))
|
|
{
|
|
switch (attr)
|
|
{
|
|
case DW_AT_name:
|
|
type_name_cstr = form_value.AsCString();
|
|
type_name_const_str.SetCString(type_name_cstr);
|
|
break;
|
|
|
|
case DW_AT_external:
|
|
if (form_value.Unsigned())
|
|
{
|
|
if (storage == clang::SC_None)
|
|
storage = clang::SC_Extern;
|
|
else
|
|
storage = clang::SC_PrivateExtern;
|
|
}
|
|
break;
|
|
|
|
case DW_AT_high_pc:
|
|
case DW_AT_low_pc:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
DEBUG_PRINTF("0x%8.8" PRIx64 ": %s (\"%s\")\n", die.GetID(),
|
|
DW_TAG_value_to_name(tag), type_name_cstr);
|
|
|
|
std::vector<CompilerType> function_param_types;
|
|
|
|
// Parse the function children for the parameters
|
|
|
|
if (die.HasChildren())
|
|
{
|
|
ParseChildParameters(sc, die, is_variadic, function_param_types);
|
|
}
|
|
|
|
// compiler_type will get the function prototype clang type after this call
|
|
compiler_type = m_ast.CreateFunctionType(type_name_const_str, function_param_types.data(),
|
|
function_param_types.size(), is_variadic);
|
|
|
|
type_sp.reset(new Type(die.GetID(), dwarf, type_name_const_str, 0, NULL,
|
|
LLDB_INVALID_UID, Type::eEncodingIsUID, &decl, compiler_type,
|
|
Type::eResolveStateFull));
|
|
assert(type_sp.get());
|
|
}
|
|
break;
|
|
|
|
case DW_TAG_array_type:
|
|
{
|
|
// Set a bit that lets us know that we are currently parsing this
|
|
dwarf->m_die_to_type[die.GetDIE()] = DIE_IS_BEING_PARSED;
|
|
|
|
lldb::user_id_t type_die_offset = DW_INVALID_OFFSET;
|
|
int64_t first_index = 0;
|
|
uint32_t byte_stride = 0;
|
|
uint32_t bit_stride = 0;
|
|
const size_t num_attributes = die.GetAttributes(attributes);
|
|
|
|
if (num_attributes > 0)
|
|
{
|
|
uint32_t i;
|
|
for (i = 0; i < num_attributes; ++i)
|
|
{
|
|
attr = attributes.AttributeAtIndex(i);
|
|
if (attributes.ExtractFormValueAtIndex(i, form_value))
|
|
{
|
|
switch (attr)
|
|
{
|
|
case DW_AT_name:
|
|
type_name_cstr = form_value.AsCString();
|
|
type_name_const_str.SetCString(type_name_cstr);
|
|
break;
|
|
|
|
case DW_AT_type:
|
|
type_die_offset = form_value.Reference();
|
|
break;
|
|
case DW_AT_byte_size:
|
|
break; // byte_size = form_value.Unsigned(); break;
|
|
case DW_AT_go_kind:
|
|
go_kind = form_value.Unsigned();
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
DEBUG_PRINTF("0x%8.8" PRIx64 ": %s (\"%s\")\n", die.GetID(),
|
|
DW_TAG_value_to_name(tag), type_name_cstr);
|
|
|
|
Type *element_type = dwarf->ResolveTypeUID(type_die_offset);
|
|
|
|
if (element_type)
|
|
{
|
|
std::vector<uint64_t> element_orders;
|
|
ParseChildArrayInfo(sc, die, first_index, element_orders, byte_stride, bit_stride);
|
|
if (byte_stride == 0)
|
|
byte_stride = element_type->GetByteSize();
|
|
CompilerType array_element_type = element_type->GetForwardCompilerType();
|
|
if (element_orders.size() > 0)
|
|
{
|
|
if (element_orders.size() > 1)
|
|
printf("golang: unsupported multi-dimensional array %s\n", type_name_cstr);
|
|
compiler_type =
|
|
m_ast.CreateArrayType(type_name_const_str, array_element_type, element_orders[0]);
|
|
}
|
|
else
|
|
{
|
|
compiler_type = m_ast.CreateArrayType(type_name_const_str, array_element_type, 0);
|
|
}
|
|
type_sp.reset(new Type(die.GetID(), dwarf, type_name_const_str,
|
|
byte_stride, NULL, type_die_offset, Type::eEncodingIsUID, &decl,
|
|
compiler_type, Type::eResolveStateFull));
|
|
type_sp->SetEncodingType(element_type);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
dwarf->GetObjectFile()->GetModule()->ReportError("{0x%8.8x}: unhandled type tag 0x%4.4x (%s), "
|
|
"please file a bug and attach the file at the "
|
|
"start of this error message",
|
|
die.GetOffset(), tag, DW_TAG_value_to_name(tag));
|
|
break;
|
|
}
|
|
|
|
if (type_sp.get())
|
|
{
|
|
DWARFDIE sc_parent_die = SymbolFileDWARF::GetParentSymbolContextDIE(die);
|
|
dw_tag_t sc_parent_tag = sc_parent_die.Tag();
|
|
|
|
SymbolContextScope *symbol_context_scope = NULL;
|
|
if (sc_parent_tag == DW_TAG_compile_unit)
|
|
{
|
|
symbol_context_scope = sc.comp_unit;
|
|
}
|
|
else if (sc.function != NULL && sc_parent_die)
|
|
{
|
|
symbol_context_scope =
|
|
sc.function->GetBlock(true).FindBlockByID(sc_parent_die.GetID());
|
|
if (symbol_context_scope == NULL)
|
|
symbol_context_scope = sc.function;
|
|
}
|
|
|
|
if (symbol_context_scope != NULL)
|
|
{
|
|
type_sp->SetSymbolContextScope(symbol_context_scope);
|
|
}
|
|
|
|
// We are ready to put this type into the uniqued list up at the module level
|
|
type_list->Insert(type_sp);
|
|
|
|
dwarf->m_die_to_type[die.GetDIE()] = type_sp.get();
|
|
}
|
|
}
|
|
else if (type_ptr != DIE_IS_BEING_PARSED)
|
|
{
|
|
type_sp = type_ptr->shared_from_this();
|
|
}
|
|
}
|
|
return type_sp;
|
|
}
|
|
|
|
size_t
|
|
DWARFASTParserGo::ParseChildParameters(const SymbolContext &sc,
|
|
|
|
const DWARFDIE &parent_die, bool &is_variadic,
|
|
std::vector<CompilerType> &function_param_types)
|
|
{
|
|
if (!parent_die)
|
|
return 0;
|
|
|
|
size_t arg_idx = 0;
|
|
for (DWARFDIE die = parent_die.GetFirstChild(); die.IsValid(); die = die.GetSibling())
|
|
{
|
|
|
|
dw_tag_t tag = die.Tag();
|
|
switch (tag)
|
|
{
|
|
case DW_TAG_formal_parameter:
|
|
{
|
|
DWARFAttributes attributes;
|
|
const size_t num_attributes = die.GetAttributes(attributes);
|
|
if (num_attributes > 0)
|
|
{
|
|
Declaration decl;
|
|
DWARFFormValue param_type_die_offset;
|
|
|
|
uint32_t i;
|
|
for (i = 0; i < num_attributes; ++i)
|
|
{
|
|
const dw_attr_t attr = attributes.AttributeAtIndex(i);
|
|
DWARFFormValue form_value;
|
|
if (attributes.ExtractFormValueAtIndex(i, form_value))
|
|
{
|
|
switch (attr)
|
|
{
|
|
case DW_AT_name:
|
|
// = form_value.AsCString();
|
|
break;
|
|
case DW_AT_type:
|
|
param_type_die_offset = form_value;
|
|
break;
|
|
case DW_AT_location:
|
|
// if (form_value.BlockData())
|
|
// {
|
|
// const DWARFDataExtractor& debug_info_data =
|
|
// debug_info();
|
|
// uint32_t block_length = form_value.Unsigned();
|
|
// DWARFDataExtractor location(debug_info_data,
|
|
// form_value.BlockData() - debug_info_data.GetDataStart(),
|
|
// block_length);
|
|
// }
|
|
// else
|
|
// {
|
|
// }
|
|
// break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
Type *type = parent_die.ResolveTypeUID(DIERef(param_type_die_offset));
|
|
if (type)
|
|
{
|
|
function_param_types.push_back(type->GetForwardCompilerType());
|
|
}
|
|
}
|
|
arg_idx++;
|
|
}
|
|
break;
|
|
|
|
case DW_TAG_unspecified_parameters:
|
|
is_variadic = true;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
return arg_idx;
|
|
}
|
|
|
|
void
|
|
DWARFASTParserGo::ParseChildArrayInfo(const SymbolContext &sc, const DWARFDIE &parent_die, int64_t &first_index,
|
|
std::vector<uint64_t> &element_orders, uint32_t &byte_stride,
|
|
uint32_t &bit_stride)
|
|
{
|
|
if (!parent_die)
|
|
return;
|
|
|
|
for (DWARFDIE die = parent_die.GetFirstChild(); die.IsValid(); die = die.GetSibling())
|
|
{
|
|
const dw_tag_t tag = die.Tag();
|
|
switch (tag)
|
|
{
|
|
case DW_TAG_subrange_type:
|
|
{
|
|
DWARFAttributes attributes;
|
|
const size_t num_child_attributes = die.GetAttributes(attributes);
|
|
if (num_child_attributes > 0)
|
|
{
|
|
uint64_t num_elements = 0;
|
|
uint32_t i;
|
|
for (i = 0; i < num_child_attributes; ++i)
|
|
{
|
|
const dw_attr_t attr = attributes.AttributeAtIndex(i);
|
|
DWARFFormValue form_value;
|
|
if (attributes.ExtractFormValueAtIndex(i, form_value))
|
|
{
|
|
switch (attr)
|
|
{
|
|
case DW_AT_count:
|
|
num_elements = form_value.Unsigned();
|
|
break;
|
|
|
|
default:
|
|
case DW_AT_type:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
element_orders.push_back(num_elements);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
bool
|
|
DWARFASTParserGo::CompleteTypeFromDWARF(const DWARFDIE &die, lldb_private::Type *type, CompilerType &compiler_type)
|
|
{
|
|
if (!die)
|
|
return false;
|
|
|
|
const dw_tag_t tag = die.Tag();
|
|
|
|
SymbolFileDWARF *dwarf = die.GetDWARF();
|
|
Log *log = nullptr; // (LogChannelDWARF::GetLogIfAny(DWARF_LOG_DEBUG_INFO|DWARF_LOG_TYPE_COMPLETION));
|
|
if (log)
|
|
dwarf->GetObjectFile()->GetModule()->LogMessageVerboseBacktrace(
|
|
log, "0x%8.8" PRIx64 ": %s '%s' resolving forward declaration...", die.GetID(),
|
|
DW_TAG_value_to_name(tag), type->GetName().AsCString());
|
|
assert(compiler_type);
|
|
DWARFAttributes attributes;
|
|
|
|
switch (tag)
|
|
{
|
|
case DW_TAG_structure_type:
|
|
{
|
|
{
|
|
if (die.HasChildren())
|
|
{
|
|
SymbolContext sc(die.GetLLDBCompileUnit());
|
|
|
|
ParseChildMembers(sc, die, compiler_type);
|
|
}
|
|
}
|
|
m_ast.CompleteStructType(compiler_type);
|
|
return (bool)compiler_type;
|
|
}
|
|
|
|
default:
|
|
assert(false && "not a forward go type decl!");
|
|
break;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
size_t
|
|
DWARFASTParserGo::ParseChildMembers(const SymbolContext &sc, const DWARFDIE &parent_die, CompilerType &class_compiler_type)
|
|
{
|
|
size_t count = 0;
|
|
uint32_t member_idx = 0;
|
|
|
|
ModuleSP module_sp = parent_die.GetDWARF()->GetObjectFile()->GetModule();
|
|
GoASTContext *ast = llvm::dyn_cast_or_null<GoASTContext>(class_compiler_type.GetTypeSystem());
|
|
if (ast == nullptr)
|
|
return 0;
|
|
|
|
for (DWARFDIE die = parent_die.GetFirstChild(); die.IsValid(); die = die.GetSibling())
|
|
{
|
|
dw_tag_t tag = die.Tag();
|
|
|
|
switch (tag)
|
|
{
|
|
case DW_TAG_member:
|
|
{
|
|
DWARFAttributes attributes;
|
|
const size_t num_attributes = die.GetAttributes(attributes);
|
|
if (num_attributes > 0)
|
|
{
|
|
Declaration decl;
|
|
const char *name = NULL;
|
|
|
|
DWARFFormValue encoding_uid;
|
|
uint32_t member_byte_offset = UINT32_MAX;
|
|
uint32_t i;
|
|
for (i = 0; i < num_attributes; ++i)
|
|
{
|
|
const dw_attr_t attr = attributes.AttributeAtIndex(i);
|
|
DWARFFormValue form_value;
|
|
if (attributes.ExtractFormValueAtIndex(i, form_value))
|
|
{
|
|
switch (attr)
|
|
{
|
|
case DW_AT_name:
|
|
name = form_value.AsCString();
|
|
break;
|
|
case DW_AT_type:
|
|
encoding_uid = form_value;
|
|
break;
|
|
case DW_AT_data_member_location:
|
|
if (form_value.BlockData())
|
|
{
|
|
Value initialValue(0);
|
|
Value memberOffset(0);
|
|
const DWARFDataExtractor &debug_info_data =
|
|
die.GetDWARF()->get_debug_info_data();
|
|
uint32_t block_length = form_value.Unsigned();
|
|
uint32_t block_offset = form_value.BlockData() - debug_info_data.GetDataStart();
|
|
if (DWARFExpression::Evaluate(NULL, // ExecutionContext *
|
|
NULL, // ClangExpressionVariableList *
|
|
NULL, // ClangExpressionDeclMap *
|
|
NULL, // RegisterContext *
|
|
module_sp, debug_info_data, die.GetCU(),
|
|
block_offset, block_length, eRegisterKindDWARF,
|
|
&initialValue, NULL, memberOffset, NULL))
|
|
{
|
|
member_byte_offset = memberOffset.ResolveValue(NULL).UInt();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// With DWARF 3 and later, if the value is an integer constant,
|
|
// this form value is the offset in bytes from the beginning
|
|
// of the containing entity.
|
|
member_byte_offset = form_value.Unsigned();
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
Type *member_type = die.ResolveTypeUID(DIERef(encoding_uid));
|
|
if (member_type)
|
|
{
|
|
CompilerType member_go_type = member_type->GetFullCompilerType();
|
|
ConstString name_const_str(name);
|
|
m_ast.AddFieldToStruct(class_compiler_type, name_const_str, member_go_type, member_byte_offset);
|
|
}
|
|
}
|
|
++member_idx;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
Function *
|
|
DWARFASTParserGo::ParseFunctionFromDWARF(const SymbolContext &sc, const DWARFDIE &die)
|
|
{
|
|
DWARFRangeList func_ranges;
|
|
const char *name = NULL;
|
|
const char *mangled = NULL;
|
|
int decl_file = 0;
|
|
int decl_line = 0;
|
|
int decl_column = 0;
|
|
int call_file = 0;
|
|
int call_line = 0;
|
|
int call_column = 0;
|
|
DWARFExpression frame_base(die.GetCU());
|
|
|
|
assert(die.Tag() == DW_TAG_subprogram);
|
|
|
|
if (die.Tag() != DW_TAG_subprogram)
|
|
return NULL;
|
|
|
|
if (die.GetDIENamesAndRanges(name, mangled, func_ranges, decl_file, decl_line, decl_column, call_file, call_line,
|
|
call_column, &frame_base))
|
|
{
|
|
// Union of all ranges in the function DIE (if the function is discontiguous)
|
|
AddressRange func_range;
|
|
lldb::addr_t lowest_func_addr = func_ranges.GetMinRangeBase(0);
|
|
lldb::addr_t highest_func_addr = func_ranges.GetMaxRangeEnd(0);
|
|
if (lowest_func_addr != LLDB_INVALID_ADDRESS && lowest_func_addr <= highest_func_addr)
|
|
{
|
|
ModuleSP module_sp(die.GetModule());
|
|
func_range.GetBaseAddress().ResolveAddressUsingFileSections(lowest_func_addr, module_sp->GetSectionList());
|
|
if (func_range.GetBaseAddress().IsValid())
|
|
func_range.SetByteSize(highest_func_addr - lowest_func_addr);
|
|
}
|
|
|
|
if (func_range.GetBaseAddress().IsValid())
|
|
{
|
|
Mangled func_name;
|
|
func_name.SetValue(ConstString(name), false);
|
|
|
|
FunctionSP func_sp;
|
|
std::unique_ptr<Declaration> decl_ap;
|
|
if (decl_file != 0 || decl_line != 0 || decl_column != 0)
|
|
decl_ap.reset(new Declaration(sc.comp_unit->GetSupportFiles().GetFileSpecAtIndex(decl_file), decl_line,
|
|
decl_column));
|
|
|
|
SymbolFileDWARF *dwarf = die.GetDWARF();
|
|
// Supply the type _only_ if it has already been parsed
|
|
Type *func_type = dwarf->m_die_to_type.lookup(die.GetDIE());
|
|
|
|
assert(func_type == NULL || func_type != DIE_IS_BEING_PARSED);
|
|
|
|
if (dwarf->FixupAddress(func_range.GetBaseAddress()))
|
|
{
|
|
const user_id_t func_user_id = die.GetID();
|
|
func_sp.reset(new Function(sc.comp_unit,
|
|
func_user_id, // UserID is the DIE offset
|
|
func_user_id,
|
|
func_name,
|
|
func_type,
|
|
func_range)); // first address range
|
|
|
|
if (func_sp.get() != NULL)
|
|
{
|
|
if (frame_base.IsValid())
|
|
func_sp->GetFrameBaseExpression() = frame_base;
|
|
sc.comp_unit->AddFunction(func_sp);
|
|
return func_sp.get();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|