Support for OCaml native debugging

This introduces basic support for debugging OCaml binaries.
Use of the native compiler with DWARF emission support (see
https://github.com/ocaml/ocaml/pull/574) is required.

Available variables are considered as 64 bits unsigned integers,
their interpretation will be left to a OCaml-made debugging layer.

Differential revision: https://reviews.llvm.org/D22132

llvm-svn: 277443
This commit is contained in:
Tamas Berghammer 2016-08-02 11:15:55 +00:00
parent adedac68dc
commit 00adc41370
14 changed files with 1600 additions and 0 deletions

View File

@ -27,6 +27,7 @@ set( LLDB_USED_LIBS
lldbPluginJavaLanguage
lldbPluginObjCLanguage
lldbPluginObjCPlusPlusLanguage
lldbPluginOCamlLanguage
lldbPluginObjectFileELF
lldbPluginObjectFileJIT

View File

@ -0,0 +1,355 @@
//===-- OCamlASTContext.h ------------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef liblldb_OCamlASTContext_h_
#define liblldb_OCamlASTContext_h_
// C Includes
// C++ Includes
#include <map>
#include <memory>
#include <set>
#include <string>
#include <vector>
// Other libraries and framework includes
// Project includes
#include "lldb/Core/ConstString.h"
#include "lldb/Symbol/TypeSystem.h"
#include "lldb/Symbol/CompilerType.h"
namespace lldb_private
{
class OCamlASTContext : public TypeSystem
{
public:
class OCamlType;
typedef std::map<ConstString, std::unique_ptr<OCamlType>> OCamlTypeMap;
OCamlASTContext();
~OCamlASTContext() override;
ConstString
GetPluginName() override;
uint32_t
GetPluginVersion() override;
static ConstString
GetPluginNameStatic ();
static lldb::TypeSystemSP
CreateInstance (lldb::LanguageType language, Module *module, Target *target);
static void
EnumerateSupportedLanguages(std::set<lldb::LanguageType> &languages_for_types,
std::set<lldb::LanguageType> &languages_for_expressions);
static void
Initialize ();
static void
Terminate ();
DWARFASTParser *GetDWARFParser() override;
void
SetAddressByteSize(int byte_size)
{
m_pointer_byte_size = byte_size;
}
static bool classof(const TypeSystem *ts)
{
return ts->getKind() == TypeSystem::eKindOCaml;
}
ConstString
DeclGetName (void *opaque_decl) override
{
return ConstString();
}
bool
DeclContextIsStructUnionOrClass(void *opaque_decl_ctx) override
{
return false;
}
ConstString
DeclContextGetName(void *opaque_decl_ctx) override
{
return ConstString();
}
ConstString
DeclContextGetScopeQualifiedName(void *opaque_decl_ctx) override
{
return ConstString();
}
bool
DeclContextIsClassMethod(void *opaque_decl_ctx, lldb::LanguageType *language_ptr,
bool *is_instance_method_ptr,
ConstString *language_object_name_ptr) override
{
return false;
}
bool SupportsLanguage (lldb::LanguageType language) override;
uint32_t GetPointerByteSize() override;
bool
IsArrayType(lldb::opaque_compiler_type_t type, CompilerType *element_type,
uint64_t *size, bool *is_incomplete) override;
bool IsAggregateType(lldb::opaque_compiler_type_t type) override;
bool IsCharType(lldb::opaque_compiler_type_t type) override;
bool IsCompleteType(lldb::opaque_compiler_type_t type) override;
bool IsDefined(lldb::opaque_compiler_type_t type) override;
bool IsFloatingPointType(lldb::opaque_compiler_type_t type, uint32_t &count, bool &is_complex) override;
bool IsFunctionType(lldb::opaque_compiler_type_t type, bool *is_variadic_ptr = nullptr) override;
size_t GetNumberOfFunctionArguments(lldb::opaque_compiler_type_t type) override;
CompilerType GetFunctionArgumentAtIndex(lldb::opaque_compiler_type_t type, const size_t index) override;
bool IsFunctionPointerType(lldb::opaque_compiler_type_t type) override;
bool IsBlockPointerType (lldb::opaque_compiler_type_t type,
CompilerType *function_pointer_type_ptr) override;
bool
IsIntegerType(lldb::opaque_compiler_type_t type, bool &is_signed) override;
bool
IsPossibleDynamicType(lldb::opaque_compiler_type_t type,
CompilerType *target_type,
bool check_cplusplus, bool check_objc) override;
bool IsPointerType(lldb::opaque_compiler_type_t type, CompilerType *pointee_type = nullptr) override;
bool IsScalarType(lldb::opaque_compiler_type_t type) override;
bool IsVoidType(lldb::opaque_compiler_type_t type) override;
bool GetCompleteType(lldb::opaque_compiler_type_t type) override;
ConstString GetTypeName(lldb::opaque_compiler_type_t type) override;
uint32_t
GetTypeInfo(lldb::opaque_compiler_type_t type,
CompilerType *pointee_or_element_compiler_type = nullptr) override;
lldb::LanguageType GetMinimumLanguage(lldb::opaque_compiler_type_t type) override;
lldb::TypeClass GetTypeClass(lldb::opaque_compiler_type_t type) override;
CompilerType
GetArrayElementType(lldb::opaque_compiler_type_t type, uint64_t *stride = nullptr) override;
CompilerType GetCanonicalType(lldb::opaque_compiler_type_t type) override;
int GetFunctionArgumentCount(lldb::opaque_compiler_type_t type) override;
CompilerType
GetFunctionArgumentTypeAtIndex(lldb::opaque_compiler_type_t type, size_t idx) override;
CompilerType
GetFunctionReturnType(lldb::opaque_compiler_type_t type) override;
size_t
GetNumMemberFunctions(lldb::opaque_compiler_type_t type) override;
TypeMemberFunctionImpl
GetMemberFunctionAtIndex(lldb::opaque_compiler_type_t type, size_t idx) override;
CompilerType
GetPointeeType(lldb::opaque_compiler_type_t type) override;
CompilerType
GetPointerType(lldb::opaque_compiler_type_t type) override;
uint64_t
GetBitSize(lldb::opaque_compiler_type_t type, ExecutionContextScope *exe_scope) override;
lldb::Encoding
GetEncoding(lldb::opaque_compiler_type_t type, uint64_t &count) override;
lldb::Format
GetFormat(lldb::opaque_compiler_type_t type) override;
uint32_t
GetNumChildren(lldb::opaque_compiler_type_t type, bool omit_empty_base_classes) override;
lldb::BasicType
GetBasicTypeEnumeration(lldb::opaque_compiler_type_t type) override;
CompilerType
GetBuiltinTypeForEncodingAndBitSize(lldb::Encoding encoding, size_t bit_size) override;
uint32_t
GetNumFields(lldb::opaque_compiler_type_t type) override;
CompilerType
GetFieldAtIndex(lldb::opaque_compiler_type_t type, size_t idx, std::string &name, uint64_t *bit_offset_ptr,
uint32_t *bitfield_bit_size_ptr, bool *is_bitfield_ptr) override;
uint32_t
GetNumDirectBaseClasses(lldb::opaque_compiler_type_t type) override
{
return 0;
}
uint32_t
GetNumVirtualBaseClasses(lldb::opaque_compiler_type_t type) override
{
return 0;
}
CompilerType
GetDirectBaseClassAtIndex(lldb::opaque_compiler_type_t type, size_t idx, uint32_t *bit_offset_ptr) override
{
return CompilerType();
}
CompilerType
GetVirtualBaseClassAtIndex(lldb::opaque_compiler_type_t type, size_t idx, uint32_t *bit_offset_ptr) override
{
return CompilerType();
}
CompilerType
GetChildCompilerTypeAtIndex(lldb::opaque_compiler_type_t type,
ExecutionContext *exe_ctx, size_t idx,
bool transparent_pointers, bool omit_empty_base_classes,
bool ignore_array_bounds, std::string &child_name,
uint32_t &child_byte_size, int32_t &child_byte_offset,
uint32_t &child_bitfield_bit_size,
uint32_t &child_bitfield_bit_offset, bool &child_is_base_class,
bool &child_is_deref_of_parent, ValueObject *valobj,
uint64_t &language_flags) override;
uint32_t
GetIndexOfChildWithName(lldb::opaque_compiler_type_t type, const char *name, bool omit_empty_base_classes) override;
size_t
GetIndexOfChildMemberWithName(lldb::opaque_compiler_type_t type,
const char *name, bool omit_empty_base_classes,
std::vector<uint32_t> &child_indexes) override;
size_t
GetNumTemplateArguments(lldb::opaque_compiler_type_t type) override
{
return 0;
}
CompilerType
GetTemplateArgument(lldb::opaque_compiler_type_t type,
size_t idx, lldb::TemplateArgumentKind &kind) override
{
return CompilerType();
}
void DumpValue(lldb::opaque_compiler_type_t type, ExecutionContext *exe_ctx,
Stream *s, lldb::Format format, const DataExtractor &data,
lldb::offset_t data_offset, size_t data_byte_size,
uint32_t bitfield_bit_size, uint32_t bitfield_bit_offset,
bool show_types, bool show_summary,
bool verbose, uint32_t depth) override;
bool DumpTypeValue(lldb::opaque_compiler_type_t type, Stream *s,
lldb::Format format, const DataExtractor &data,
lldb::offset_t data_offset, size_t data_byte_size,
uint32_t bitfield_bit_size, uint32_t bitfield_bit_offset,
ExecutionContextScope *exe_scope) override;
void
DumpTypeDescription(lldb::opaque_compiler_type_t type) override;
void
DumpTypeDescription(lldb::opaque_compiler_type_t type, Stream *s) override;
bool IsRuntimeGeneratedType(lldb::opaque_compiler_type_t type) override;
void
DumpSummary(lldb::opaque_compiler_type_t type, ExecutionContext *exe_ctx,
Stream *s, const DataExtractor &data,
lldb::offset_t data_offset, size_t data_byte_size) override;
size_t
ConvertStringToFloatValue(lldb::opaque_compiler_type_t type, const char *s,
uint8_t *dst, size_t dst_size) override;
bool IsPointerOrReferenceType(lldb::opaque_compiler_type_t type,
CompilerType *pointee_type = nullptr) override;
unsigned GetTypeQualifiers(lldb::opaque_compiler_type_t type) override;
bool IsCStringType(lldb::opaque_compiler_type_t type, uint32_t &length) override;
size_t GetTypeBitAlign(lldb::opaque_compiler_type_t type) override;
CompilerType GetBasicTypeFromAST(lldb::BasicType basic_type) override;
bool IsBeingDefined(lldb::opaque_compiler_type_t type) override;
bool IsConst(lldb::opaque_compiler_type_t type) override;
uint32_t
IsHomogeneousAggregate(lldb::opaque_compiler_type_t type, CompilerType *base_type_ptr) override;
bool IsPolymorphicClass(lldb::opaque_compiler_type_t type) override;
bool IsTypedefType(lldb::opaque_compiler_type_t type) override;
CompilerType GetTypedefedType(lldb::opaque_compiler_type_t type) override;
bool
IsVectorType(lldb::opaque_compiler_type_t type, CompilerType *element_type,
uint64_t *size) override;
CompilerType GetFullyUnqualifiedType(lldb::opaque_compiler_type_t type) override;
CompilerType GetNonReferenceType(lldb::opaque_compiler_type_t type) override;
bool
IsReferenceType(lldb::opaque_compiler_type_t type,
CompilerType *pointee_type = nullptr,
bool *is_rvalue = nullptr) override;
CompilerType CreateBaseType(const ConstString &name, uint64_t);
private:
int m_pointer_byte_size;
int m_int_byte_size;
std::unique_ptr<DWARFASTParser> m_dwarf_ast_parser_ap;
OCamlTypeMap m_base_type_map;
OCamlASTContext(const OCamlASTContext &) = delete;
const OCamlASTContext &operator=(const OCamlASTContext &) = delete;
};
class OCamlASTContextForExpr : public OCamlASTContext
{
public:
OCamlASTContextForExpr(lldb::TargetSP target) : m_target_wp(target) {}
private:
lldb::TargetWP m_target_wp;
};
}
#endif // liblldb_OCamlASTContext_h_

View File

@ -75,6 +75,7 @@ public:
eKindSwift,
eKindGo,
eKindJava,
eKindOCaml,
kNumKinds
};

View File

@ -27,6 +27,7 @@
#include "lldb/Symbol/ClangASTContext.h"
#include "lldb/Symbol/GoASTContext.h"
#include "lldb/Symbol/JavaASTContext.h"
#include "lldb/Symbol/OCamlASTContext.h"
#include "Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.h"
#include "Plugins/ABI/MacOSX-arm64/ABIMacOSX_arm64.h"
@ -56,6 +57,7 @@
#include "Plugins/Language/Java/JavaLanguage.h"
#include "Plugins/Language/ObjC/ObjCLanguage.h"
#include "Plugins/Language/ObjCPlusPlus/ObjCPlusPlusLanguage.h"
#include "Plugins/Language/OCaml/OCamlLanguage.h"
#include "Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.h"
#include "Plugins/LanguageRuntime/Go/GoLanguageRuntime.h"
#include "Plugins/LanguageRuntime/Java/JavaLanguageRuntime.h"
@ -314,6 +316,7 @@ SystemInitializerFull::Initialize()
ClangASTContext::Initialize();
GoASTContext::Initialize();
JavaASTContext::Initialize();
OCamlASTContext::Initialize();
ABIMacOSX_i386::Initialize();
ABIMacOSX_arm::Initialize();
@ -360,6 +363,7 @@ SystemInitializerFull::Initialize()
JavaLanguage::Initialize();
ObjCLanguage::Initialize();
ObjCPlusPlusLanguage::Initialize();
OCamlLanguage::Initialize();
#if defined(_MSC_VER)
ProcessWindowsLive::Initialize();
@ -444,6 +448,7 @@ SystemInitializerFull::Terminate()
ClangASTContext::Terminate();
GoASTContext::Terminate();
JavaASTContext::Terminate();
OCamlASTContext::Terminate();
ABIMacOSX_i386::Terminate();
ABIMacOSX_arm::Terminate();
@ -488,6 +493,7 @@ SystemInitializerFull::Terminate()
JavaLanguage::Terminate();
ObjCLanguage::Terminate();
ObjCPlusPlusLanguage::Terminate();
OCamlLanguage::Terminate();
#if defined(__APPLE__)
DynamicLoaderDarwinKernel::Terminate();

View File

@ -3,3 +3,4 @@ add_subdirectory(Go)
add_subdirectory(Java)
add_subdirectory(ObjC)
add_subdirectory(ObjCPlusPlus)
add_subdirectory(OCaml)

View File

@ -0,0 +1,4 @@
add_lldb_library(lldbPluginOCamlLanguage
OCamlLanguage.cpp
)

View File

@ -0,0 +1,78 @@
//===-- OCamlLanguage.cpp ----------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// C Includes
#include <string.h>
// C++ Includes
#include <functional>
#include <mutex>
// Other libraries and framework includes
#include "llvm/ADT/StringRef.h"
// Project includes
#include "OCamlLanguage.h"
#include "lldb/Core/ConstString.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/DataFormatters/DataVisualization.h"
#include "lldb/DataFormatters/FormattersHelpers.h"
#include "lldb/Symbol/OCamlASTContext.h"
using namespace lldb;
using namespace lldb_private;
void
OCamlLanguage::Initialize()
{
PluginManager::RegisterPlugin(GetPluginNameStatic(), "OCaml Language", CreateInstance);
}
void
OCamlLanguage::Terminate()
{
PluginManager::UnregisterPlugin(CreateInstance);
}
lldb_private::ConstString
OCamlLanguage::GetPluginNameStatic()
{
static ConstString g_name("OCaml");
return g_name;
}
lldb_private::ConstString
OCamlLanguage::GetPluginName()
{
return GetPluginNameStatic();
}
uint32_t
OCamlLanguage::GetPluginVersion()
{
return 1;
}
Language *
OCamlLanguage::CreateInstance(lldb::LanguageType language)
{
if (language == eLanguageTypeOCaml)
return new OCamlLanguage();
return nullptr;
}
bool
OCamlLanguage::IsNilReference(ValueObject &valobj)
{
if (!valobj.GetCompilerType().IsReferenceType())
return false;
// If we failed to read the value then it is not a nil reference.
return valobj.GetValueAsUnsigned(UINT64_MAX) == 0;
}

View File

@ -0,0 +1,61 @@
//===-- OCamlLanguage.h ------------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef liblldb_OCamlLanguage_h_
#define liblldb_OCamlLanguage_h_
// C Includes
// C++ Includes
#include <vector>
// Other libraries and framework includes
#include "llvm/ADT/StringRef.h"
// Project includes
#include "lldb/Core/ConstString.h"
#include "lldb/Target/Language.h"
#include "lldb/lldb-private.h"
namespace lldb_private
{
class OCamlLanguage : public Language
{
public:
lldb::LanguageType
GetLanguageType() const override
{
return lldb::eLanguageTypeOCaml;
}
static void
Initialize();
static void
Terminate();
static lldb_private::Language *
CreateInstance(lldb::LanguageType language);
static lldb_private::ConstString
GetPluginNameStatic();
ConstString
GetPluginName() override;
uint32_t
GetPluginVersion() override;
bool
IsNilReference(ValueObject &valobj) override;
};
} // namespace lldb_private
#endif // liblldb_OCamlLanguage_h_

View File

@ -4,6 +4,7 @@ add_lldb_library(lldbPluginSymbolFileDWARF
DWARFASTParserClang.cpp
DWARFASTParserGo.cpp
DWARFASTParserJava.cpp
DWARFASTParserOCaml.cpp
DWARFAttribute.cpp
DWARFCompileUnit.cpp
DWARFDataExtractor.cpp

View File

@ -0,0 +1,232 @@
//===-- DWARFASTParserOCaml.cpp ---------------------------------*- C++ -*-===//
#include "DWARFASTParserOCaml.h"
#include "lldb/Core/Error.h"
#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
#include "lldb/Symbol/CompileUnit.h"
#include "lldb/Symbol/Function.h"
#include "lldb/Symbol/ObjectFile.h"
#include "lldb/Symbol/Type.h"
#include "lldb/Symbol/TypeList.h"
using namespace lldb;
using namespace lldb_private;
DWARFASTParserOCaml::DWARFASTParserOCaml (OCamlASTContext &ast) :
m_ast (ast)
{}
DWARFASTParserOCaml::~DWARFASTParserOCaml () {}
TypeSP
DWARFASTParserOCaml::ParseBaseTypeFromDIE(const DWARFDIE &die)
{
SymbolFileDWARF *dwarf = die.GetDWARF();
dwarf->m_die_to_type[die.GetDIE()] = DIE_IS_BEING_PARSED;
ConstString type_name;
uint64_t byte_size = 0;
DWARFAttributes attributes;
const size_t num_attributes = die.GetAttributes(attributes);
for (uint32_t i = 0; i < num_attributes; ++i)
{
DWARFFormValue form_value;
dw_attr_t attr = attributes.AttributeAtIndex(i);
if (attributes.ExtractFormValueAtIndex(i, form_value))
{
switch (attr)
{
case DW_AT_name:
type_name.SetCString(form_value.AsCString());
break;
case DW_AT_byte_size:
byte_size = form_value.Unsigned();
break;
case DW_AT_encoding:
break;
default:
assert(false && "Unsupported attribute for DW_TAG_base_type");
}
}
}
Declaration decl;
CompilerType compiler_type = m_ast.CreateBaseType(type_name, byte_size);
return std::make_shared<Type>(die.GetID(), dwarf, type_name, byte_size, nullptr, LLDB_INVALID_UID,
Type::eEncodingIsUID, decl, compiler_type, Type::eResolveStateFull);
}
lldb::TypeSP
DWARFASTParserOCaml::ParseTypeFromDWARF (const SymbolContext& sc,
const DWARFDIE &die,
Log *log,
bool *type_is_new_ptr)
{
if (type_is_new_ptr)
*type_is_new_ptr = false;
if (!die)
return nullptr;
SymbolFileDWARF *dwarf = die.GetDWARF();
Type *type_ptr = dwarf->m_die_to_type.lookup(die.GetDIE());
if (type_ptr == DIE_IS_BEING_PARSED)
return nullptr;
if (type_ptr != nullptr)
return type_ptr->shared_from_this();
TypeSP type_sp;
if (type_is_new_ptr)
*type_is_new_ptr = true;
switch (die.Tag())
{
case DW_TAG_base_type:
{
type_sp = ParseBaseTypeFromDIE(die);
break;
}
case DW_TAG_array_type:
{
break;
}
case DW_TAG_class_type:
{
break;
}
case DW_TAG_reference_type:
{
break;
}
}
if (!type_sp)
return nullptr;
DWARFDIE sc_parent_die = SymbolFileDWARF::GetParentSymbolContextDIE(die);
dw_tag_t sc_parent_tag = sc_parent_die.Tag();
SymbolContextScope *symbol_context_scope = nullptr;
if (sc_parent_tag == DW_TAG_compile_unit)
{
symbol_context_scope = sc.comp_unit;
}
else if (sc.function != nullptr && sc_parent_die)
{
symbol_context_scope = sc.function->GetBlock(true).FindBlockByID(sc_parent_die.GetID());
if (symbol_context_scope == nullptr)
symbol_context_scope = sc.function;
}
if (symbol_context_scope != nullptr)
type_sp->SetSymbolContextScope(symbol_context_scope);
dwarf->GetTypeList()->Insert(type_sp);
dwarf->m_die_to_type[die.GetDIE()] = type_sp.get();
return type_sp;
}
Function *
DWARFASTParserOCaml::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());
Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_LANGUAGE));
if (die)
{
SymbolFileDWARF *dwarf = die.GetDWARF();
if (log)
{
dwarf->GetObjectFile()->GetModule()->LogMessage(
log, "DWARFASTParserOCaml::ParseFunctionFromDWARF (die = 0x%8.8x) %s name = '%s')", die.GetOffset(),
DW_TAG_value_to_name(die.Tag()), die.GetName());
}
}
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))
{
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), true);
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();
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;
}
lldb_private::CompilerDeclContext
DWARFASTParserOCaml::GetDeclContextForUIDFromDWARF (const DWARFDIE &die)
{
return CompilerDeclContext();
}
lldb_private::CompilerDeclContext
DWARFASTParserOCaml::GetDeclContextContainingUIDFromDWARF (const DWARFDIE &die)
{
return CompilerDeclContext();
}

View File

@ -0,0 +1,60 @@
//===-- DWARFASTParserOCaml.h -----------------------------------*- C++ -*-===//
#ifndef SymbolFileDWARF_DWARFASTParserOCaml_h_
#define SymbolFileDWARF_DWARFASTParserOCaml_h_
#include "DWARFASTParser.h"
#include "DWARFCompileUnit.h"
#include "DWARFDebugInfo.h"
#include "DWARFDIE.h"
#include "DWARFDefines.h"
#include "SymbolFileDWARF.h"
#include "lldb/Symbol/OCamlASTContext.h"
class DWARFDebugInfoEntry;
class DWARFDIECollection;
class DWARFASTParserOCaml : public DWARFASTParser
{
public:
DWARFASTParserOCaml (lldb_private::OCamlASTContext &ast);
virtual ~DWARFASTParserOCaml ();
lldb::TypeSP
ParseBaseTypeFromDIE(const DWARFDIE &die);
lldb::TypeSP
ParseTypeFromDWARF (const lldb_private::SymbolContext& sc,
const DWARFDIE &die,
lldb_private::Log *log,
bool *type_is_new_ptr) override;
lldb_private::Function *
ParseFunctionFromDWARF (const lldb_private::SymbolContext& sc,
const DWARFDIE &die) override;
bool
CompleteTypeFromDWARF (const DWARFDIE &die,
lldb_private::Type *type,
lldb_private::CompilerType &compiler_type) override { return false; }
lldb_private::CompilerDecl
GetDeclForUIDFromDWARF (const DWARFDIE &die) override { return lldb_private::CompilerDecl(); }
lldb_private::CompilerDeclContext
GetDeclContextForUIDFromDWARF (const DWARFDIE &die) override;
lldb_private::CompilerDeclContext
GetDeclContextContainingUIDFromDWARF (const DWARFDIE &die) override;
std::vector<DWARFDIE>
GetDIEForDeclContext (lldb_private::CompilerDeclContext decl_context) override { return {}; }
protected:
lldb_private::OCamlASTContext &m_ast;
};
#endif // SymbolFileDWARF_DWARFASTParserOCaml_h_

View File

@ -74,6 +74,7 @@ public:
friend class DWARFASTParserClang;
friend class DWARFASTParserGo;
friend class DWARFASTParserJava;
friend class DWARFASTParserOCaml;
//------------------------------------------------------------------
// Static Functions

View File

@ -21,6 +21,7 @@ add_lldb_library(lldbSymbol
LineEntry.cpp
LineTable.cpp
ObjectFile.cpp
OCamlASTContext.cpp
Symbol.cpp
SymbolContext.cpp
SymbolFile.cpp

View File

@ -0,0 +1,798 @@
//===-- OCamlASTContext.cpp ----------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/StreamFile.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/Symbol/ObjectFile.h"
#include "lldb/Symbol/SymbolFile.h"
#include "lldb/Symbol/OCamlASTContext.h"
#include "lldb/Symbol/Type.h"
#include "lldb/Target/ExecutionContext.h"
#include "lldb/Target/Target.h"
#include "Plugins/SymbolFile/DWARF/DWARFASTParserOCaml.h"
using namespace lldb;
using namespace lldb_private;
namespace lldb_private
{
class OCamlASTContext::OCamlType
{
public:
enum LLVMCastKind
{
eKindPrimitive,
eKindObject,
eKindReference,
eKindArray,
kNumKinds
};
OCamlType(LLVMCastKind kind) : m_kind(kind) {}
virtual ~OCamlType() = default;
virtual ConstString
GetName() = 0;
virtual void
Dump(Stream *s) = 0;
virtual bool
IsCompleteType() = 0;
LLVMCastKind
getKind() const
{
return m_kind;
}
private:
LLVMCastKind m_kind;
};
} // end of namespace lldb_private
namespace
{
class OCamlPrimitiveType : public OCamlASTContext::OCamlType
{
public:
enum TypeKind
{
eTypeInt,
};
OCamlPrimitiveType(TypeKind type_kind, uint32_t byte_size) : OCamlType(OCamlType::eKindPrimitive), m_type_kind(type_kind), m_type(ConstString()), m_byte_size(byte_size) {}
OCamlPrimitiveType(TypeKind type_kind, ConstString s, uint32_t byte_size) : OCamlType(OCamlType::eKindPrimitive), m_type_kind(type_kind), m_type(s), m_byte_size(byte_size) {}
ConstString
GetName() override
{
switch (m_type_kind)
{
case eTypeInt:
return m_type;
}
return ConstString();
}
TypeKind
GetTypeKind()
{
return m_type_kind;
}
void
Dump(Stream *s) override
{
s->Printf("%s\n", GetName().GetCString());
}
bool
IsCompleteType() override
{
return true;
}
static bool
classof(const OCamlType *ot)
{
return ot->getKind() == OCamlType::eKindPrimitive;
}
uint64_t
GetByteSize() const
{
return m_byte_size;
}
private:
const TypeKind m_type_kind;
const ConstString m_type;
uint64_t m_byte_size;
};
}
OCamlASTContext::OCamlASTContext()
: TypeSystem(eKindOCaml),
m_pointer_byte_size(0),
m_int_byte_size(0)
{
}
OCamlASTContext::~OCamlASTContext()
{
}
ConstString
OCamlASTContext::GetPluginNameStatic()
{
return ConstString("ocaml");
}
ConstString
OCamlASTContext::GetPluginName()
{
return OCamlASTContext::GetPluginNameStatic();
}
uint32_t
OCamlASTContext::GetPluginVersion()
{
return 1;
}
lldb::TypeSystemSP
OCamlASTContext::CreateInstance (lldb::LanguageType language, Module *module, Target *target)
{
Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_LANGUAGE));
if (language == lldb::eLanguageTypeOCaml)
{
std::shared_ptr<OCamlASTContext> ocaml_ast_sp;
ArchSpec arch;
if (module)
{
arch = module->GetArchitecture();
ObjectFile *objfile = module->GetObjectFile();
ArchSpec object_arch;
if (!objfile || !objfile->GetArchitecture(object_arch))
return lldb::TypeSystemSP();
ocaml_ast_sp = std::shared_ptr<OCamlASTContext>(new OCamlASTContext);
if (log) {
log->Printf ("((Module*)%p) [%s]->GetOCamlASTContext() = %p",
(void *)module,
module->GetFileSpec().GetFilename().AsCString("<anonymous>"),
(void *)ocaml_ast_sp.get());
}
} else if (target) {
arch = target->GetArchitecture();
ocaml_ast_sp = std::shared_ptr<OCamlASTContextForExpr>(new OCamlASTContextForExpr(target->shared_from_this()));
if (log)
{
log->Printf ("((Target*)%p)->GetOCamlASTContext() = %p",
(void *)target,
(void *)ocaml_ast_sp.get());
}
}
if (arch.IsValid()) {
ocaml_ast_sp->SetAddressByteSize(arch.GetAddressByteSize());
return ocaml_ast_sp;
}
}
return lldb::TypeSystemSP();
}
void
OCamlASTContext::EnumerateSupportedLanguages
(std::set<lldb::LanguageType> &languages_for_types,
std::set<lldb::LanguageType> &languages_for_expressions)
{
static std::vector<lldb::LanguageType> s_supported_languages_for_types({lldb::eLanguageTypeOCaml});
static std::vector<lldb::LanguageType> s_supported_languages_for_expressions({});
languages_for_types.insert(s_supported_languages_for_types.begin(), s_supported_languages_for_types.end());
languages_for_expressions.insert(s_supported_languages_for_expressions.begin(), s_supported_languages_for_expressions.end());
}
void
OCamlASTContext::Initialize()
{
PluginManager::RegisterPlugin (GetPluginNameStatic(),
"OCaml AST context plug-in",
CreateInstance,
EnumerateSupportedLanguages);
}
void
OCamlASTContext::Terminate()
{
PluginManager::UnregisterPlugin (CreateInstance);
}
DWARFASTParser *
OCamlASTContext::GetDWARFParser()
{
if (!m_dwarf_ast_parser_ap) {
m_dwarf_ast_parser_ap.reset(new DWARFASTParserOCaml(*this));
}
return m_dwarf_ast_parser_ap.get();
}
bool
OCamlASTContext::IsArrayType(lldb::opaque_compiler_type_t type,
CompilerType *element_type, uint64_t *size,
bool *is_incomplete)
{
return false;
}
bool
OCamlASTContext::IsVectorType(lldb::opaque_compiler_type_t type, CompilerType *element_type, uint64_t *size)
{
return false;
}
bool
OCamlASTContext::IsAggregateType(lldb::opaque_compiler_type_t type)
{
return false;
}
bool
OCamlASTContext::IsBeingDefined(lldb::opaque_compiler_type_t type)
{
return false;
}
bool
OCamlASTContext::IsCharType(lldb::opaque_compiler_type_t type)
{
return false;
}
bool
OCamlASTContext::IsCompleteType(lldb::opaque_compiler_type_t type)
{
return static_cast<OCamlPrimitiveType *>(type)->IsCompleteType();
}
bool
OCamlASTContext::IsConst(lldb::opaque_compiler_type_t type)
{
return false;
}
bool
OCamlASTContext::IsCStringType(lldb::opaque_compiler_type_t type, uint32_t &length)
{
return false;
}
bool
OCamlASTContext::IsDefined(lldb::opaque_compiler_type_t type)
{
return type != nullptr;
}
bool
OCamlASTContext::IsFloatingPointType(lldb::opaque_compiler_type_t type, uint32_t &count, bool &is_complex)
{
return false;
}
bool
OCamlASTContext::IsFunctionType(lldb::opaque_compiler_type_t type, bool *is_variadic_ptr)
{
return false;
}
uint32_t
OCamlASTContext::IsHomogeneousAggregate(lldb::opaque_compiler_type_t type, CompilerType *base_type_ptr)
{
return false;
}
size_t
OCamlASTContext::GetNumberOfFunctionArguments(lldb::opaque_compiler_type_t type)
{
return 0;
}
CompilerType
OCamlASTContext::GetFunctionArgumentAtIndex(lldb::opaque_compiler_type_t type, const size_t index)
{
return CompilerType();
}
bool
OCamlASTContext::IsFunctionPointerType(lldb::opaque_compiler_type_t type)
{
return IsFunctionType(type);
}
bool
OCamlASTContext::IsBlockPointerType (lldb::opaque_compiler_type_t type, CompilerType *function_pointer_type_ptr)
{
return false;
}
bool
OCamlASTContext::IsIntegerType(lldb::opaque_compiler_type_t type, bool &is_signed)
{
if (OCamlPrimitiveType *ptype = llvm::dyn_cast<OCamlPrimitiveType>(static_cast<OCamlType *>(type)))
{
switch (ptype->GetTypeKind())
{
case OCamlPrimitiveType::eTypeInt:
is_signed = true;
return true;
default:
break;
}
}
is_signed = false;
return false;
}
bool
OCamlASTContext::IsPolymorphicClass(lldb::opaque_compiler_type_t type)
{
return false;
}
bool
OCamlASTContext::IsPossibleDynamicType(lldb::opaque_compiler_type_t type,
CompilerType *target_type,
bool check_cplusplus, bool check_objc)
{
return false;
}
bool
OCamlASTContext::IsRuntimeGeneratedType(lldb::opaque_compiler_type_t type)
{
return false;
}
bool
OCamlASTContext::IsPointerType(lldb::opaque_compiler_type_t type, CompilerType *pointee_type)
{
if (pointee_type)
pointee_type->Clear();
return false;
}
bool
OCamlASTContext::IsPointerOrReferenceType(lldb::opaque_compiler_type_t type, CompilerType *pointee_type)
{
return IsPointerType(type, pointee_type);
}
bool
OCamlASTContext::IsReferenceType(lldb::opaque_compiler_type_t type, CompilerType *pointee_type, bool *is_rvalue)
{
return false;
}
bool
OCamlASTContext::IsScalarType(lldb::opaque_compiler_type_t type)
{
return llvm::isa<OCamlPrimitiveType>(static_cast<OCamlType *>(type));
}
bool
OCamlASTContext::IsTypedefType(lldb::opaque_compiler_type_t type)
{
return false;
}
bool
OCamlASTContext::IsVoidType(lldb::opaque_compiler_type_t type)
{
return false;
}
bool
OCamlASTContext::SupportsLanguage (lldb::LanguageType language)
{
return language == lldb::eLanguageTypeOCaml;
}
bool
OCamlASTContext::GetCompleteType(lldb::opaque_compiler_type_t type)
{
if (IsCompleteType(type))
return true;
return false;
}
uint32_t
OCamlASTContext::GetPointerByteSize()
{
return m_pointer_byte_size;
}
ConstString
OCamlASTContext::GetTypeName(lldb::opaque_compiler_type_t type)
{
if (type)
return static_cast<OCamlPrimitiveType *>(type)->GetName();
return ConstString();
}
uint32_t
OCamlASTContext::GetTypeInfo(lldb::opaque_compiler_type_t type, CompilerType *pointee_or_element_compiler_type)
{
if (pointee_or_element_compiler_type)
pointee_or_element_compiler_type->Clear();
if (!type)
return 0;
if (OCamlPrimitiveType *ptype = llvm::dyn_cast<OCamlPrimitiveType>(static_cast<OCamlType *>(type)))
{
switch (ptype->GetTypeKind())
{
case OCamlPrimitiveType::eTypeInt:
return eTypeHasValue | eTypeIsBuiltIn | eTypeIsScalar | eTypeIsInteger | eTypeIsSigned;
}
}
return 0;
}
lldb::TypeClass
OCamlASTContext::GetTypeClass(lldb::opaque_compiler_type_t type)
{
if (llvm::isa<OCamlPrimitiveType>(static_cast<OCamlType *>(type)))
return eTypeClassBuiltin;
return lldb::eTypeClassInvalid;
}
lldb::BasicType
OCamlASTContext::GetBasicTypeEnumeration(lldb::opaque_compiler_type_t type)
{
return lldb::eBasicTypeInvalid;
}
lldb::LanguageType
OCamlASTContext::GetMinimumLanguage(lldb::opaque_compiler_type_t type)
{
return lldb::eLanguageTypeOCaml;
}
unsigned
OCamlASTContext::GetTypeQualifiers(lldb::opaque_compiler_type_t type)
{
return 0;
}
//----------------------------------------------------------------------
// Creating related types
//----------------------------------------------------------------------
CompilerType
OCamlASTContext::GetArrayElementType(lldb::opaque_compiler_type_t type, uint64_t *stride)
{
return CompilerType();
}
CompilerType
OCamlASTContext::GetCanonicalType(lldb::opaque_compiler_type_t type)
{
return CompilerType(this, type);
}
CompilerType
OCamlASTContext::GetFullyUnqualifiedType(lldb::opaque_compiler_type_t type)
{
return CompilerType(this, type);
}
int
OCamlASTContext::GetFunctionArgumentCount(lldb::opaque_compiler_type_t type)
{
return GetNumberOfFunctionArguments(type);
}
CompilerType
OCamlASTContext::GetFunctionArgumentTypeAtIndex(lldb::opaque_compiler_type_t type, size_t idx)
{
return GetFunctionArgumentAtIndex(type, idx);
}
CompilerType
OCamlASTContext::GetFunctionReturnType(lldb::opaque_compiler_type_t type)
{
return CompilerType();
}
size_t
OCamlASTContext::GetNumMemberFunctions(lldb::opaque_compiler_type_t type)
{
return 0;
}
TypeMemberFunctionImpl
OCamlASTContext::GetMemberFunctionAtIndex(lldb::opaque_compiler_type_t type, size_t idx)
{
return TypeMemberFunctionImpl();
}
CompilerType
OCamlASTContext::GetNonReferenceType(lldb::opaque_compiler_type_t type)
{
return CompilerType(this, type);
}
CompilerType
OCamlASTContext::GetPointeeType(lldb::opaque_compiler_type_t type)
{
return CompilerType();
}
CompilerType
OCamlASTContext::GetPointerType(lldb::opaque_compiler_type_t type)
{
return CompilerType();
}
CompilerType
OCamlASTContext::GetTypedefedType(lldb::opaque_compiler_type_t type)
{
return CompilerType();
}
CompilerType
OCamlASTContext::GetBasicTypeFromAST(lldb::BasicType basic_type)
{
return CompilerType();
}
CompilerType
OCamlASTContext::GetBuiltinTypeForEncodingAndBitSize (lldb::Encoding encoding,
size_t bit_size)
{
return CompilerType();
}
uint64_t
OCamlASTContext::GetBitSize(lldb::opaque_compiler_type_t type, ExecutionContextScope *exe_scope)
{
if (OCamlPrimitiveType *ptype = llvm::dyn_cast<OCamlPrimitiveType>(static_cast<OCamlType *>(type)))
{
switch (ptype->GetTypeKind())
{
case OCamlPrimitiveType::eTypeInt:
return ptype->GetByteSize() * 8;
}
}
return 0;
}
lldb::Encoding
OCamlASTContext::GetEncoding(lldb::opaque_compiler_type_t type, uint64_t &count)
{
count = 1;
bool is_signed;
if (IsIntegerType(type, is_signed))
return is_signed ? lldb::eEncodingSint : lldb::eEncodingUint;
bool is_complex;
uint32_t complex_count;
if (IsFloatingPointType(type, complex_count, is_complex))
{
count = complex_count;
return lldb::eEncodingIEEE754;
}
if (IsPointerType(type))
return lldb::eEncodingUint;
return lldb::eEncodingInvalid;
}
lldb::Format
OCamlASTContext::GetFormat(lldb::opaque_compiler_type_t type)
{
if (!type)
return lldb::eFormatDefault;
return lldb::eFormatBytes;
}
size_t
OCamlASTContext::GetTypeBitAlign(lldb::opaque_compiler_type_t type)
{
return 0;
}
uint32_t
OCamlASTContext::GetNumChildren(lldb::opaque_compiler_type_t type, bool omit_empty_base_classes)
{
if (!type || !GetCompleteType(type))
return 0;
return GetNumFields(type);
}
uint32_t
OCamlASTContext::GetNumFields(lldb::opaque_compiler_type_t type)
{
if (!type || !GetCompleteType(type))
return 0;
return 0;
}
CompilerType
OCamlASTContext::GetFieldAtIndex(lldb::opaque_compiler_type_t type, size_t idx,
std::string &name, uint64_t *bit_offset_ptr,
uint32_t *bitfield_bit_size_ptr, bool *is_bitfield_ptr)
{
if (bit_offset_ptr)
*bit_offset_ptr = 0;
if (bitfield_bit_size_ptr)
*bitfield_bit_size_ptr = 0;
if (is_bitfield_ptr)
*is_bitfield_ptr = false;
if (!type || !GetCompleteType(type))
return CompilerType();
return CompilerType();
}
CompilerType
OCamlASTContext::GetChildCompilerTypeAtIndex(lldb::opaque_compiler_type_t type, ExecutionContext *exe_ctx, size_t idx,
bool transparent_pointers, bool omit_empty_base_classes,
bool ignore_array_bounds, std::string &child_name,
uint32_t &child_byte_size, int32_t &child_byte_offset,
uint32_t &child_bitfield_bit_size, uint32_t &child_bitfield_bit_offset,
bool &child_is_base_class, bool &child_is_deref_of_parent, ValueObject *valobj,
uint64_t &language_flags)
{
child_name.clear();
child_byte_size = 0;
child_byte_offset = 0;
child_bitfield_bit_size = 0;
child_bitfield_bit_offset = 0;
child_is_base_class = false;
child_is_deref_of_parent = false;
language_flags = 0;
if (!type || !GetCompleteType(type))
return CompilerType();
return CompilerType();
}
uint32_t
OCamlASTContext::GetIndexOfChildWithName(lldb::opaque_compiler_type_t type, const char *name, bool omit_empty_base_classes)
{
if (!type || !GetCompleteType(type))
return UINT_MAX;
return UINT_MAX;
}
size_t
OCamlASTContext::GetIndexOfChildMemberWithName(lldb::opaque_compiler_type_t type, const char *name,
bool omit_empty_base_classes, std::vector<uint32_t> &child_indexes)
{
uint32_t index = GetIndexOfChildWithName(type, name, omit_empty_base_classes);
if (index == UINT_MAX)
return 0;
child_indexes.push_back(index);
return 1;
}
size_t
OCamlASTContext::ConvertStringToFloatValue(lldb::opaque_compiler_type_t type, const char *s, uint8_t *dst, size_t dst_size)
{
assert(false);
return 0;
}
//----------------------------------------------------------------------
// Dumping types
//----------------------------------------------------------------------
void
OCamlASTContext::DumpValue(lldb::opaque_compiler_type_t type, ExecutionContext *exe_ctx, Stream *s, lldb::Format format,
const DataExtractor &data, lldb::offset_t data_byte_offset, size_t data_byte_size,
uint32_t bitfield_bit_size, uint32_t bitfield_bit_offset, bool show_types, bool show_summary,
bool verbose, uint32_t depth)
{
if (!type) {
s->Printf("no type\n");
return;
}
s->Printf("no value\n");
if (show_summary)
DumpSummary (type, exe_ctx, s, data, data_byte_offset, data_byte_size);
}
bool
OCamlASTContext::DumpTypeValue(lldb::opaque_compiler_type_t type, Stream *s,
lldb::Format format, const DataExtractor &data,
lldb::offset_t byte_offset, size_t byte_size, uint32_t bitfield_bit_size,
uint32_t bitfield_bit_offset, ExecutionContextScope *exe_scope)
{
if (!type) {
s->Printf("no type value\n");
return false;
}
if (IsScalarType(type))
{
return
data.Dump(s, byte_offset, format, byte_size, 1, UINT64_MAX,
LLDB_INVALID_ADDRESS, bitfield_bit_size, bitfield_bit_offset, exe_scope);
}
return false;
}
void
OCamlASTContext::DumpSummary(lldb::opaque_compiler_type_t type, ExecutionContext *exe_ctx, Stream *s,
const DataExtractor &data, lldb::offset_t data_offset, size_t data_byte_size)
{
s->Printf("no summary\n");
}
void
OCamlASTContext::DumpTypeDescription(lldb::opaque_compiler_type_t type)
{
StreamFile s(stdout, false);
DumpTypeDescription(type, &s);
}
void
OCamlASTContext::DumpTypeDescription(lldb::opaque_compiler_type_t type, Stream *s)
{
static_cast<OCamlType *>(type)->Dump(s);
}
CompilerType
OCamlASTContext::CreateBaseType(const ConstString &name, uint64_t byte_size)
{
if (m_base_type_map.empty())
{
OCamlPrimitiveType *type = new OCamlPrimitiveType(OCamlPrimitiveType::eTypeInt, ConstString("ocaml_int"), byte_size);
m_base_type_map.emplace(type->GetName(), std::unique_ptr<OCamlASTContext::OCamlType>(type));
}
auto it = m_base_type_map.find(name);
if (it == m_base_type_map.end())
{
OCamlPrimitiveType *type = new OCamlPrimitiveType(OCamlPrimitiveType::eTypeInt, name, byte_size);
it = m_base_type_map.emplace(name, std::unique_ptr<OCamlASTContext::OCamlType>(type)).first;
}
return CompilerType(this, it->second.get());
}