diff --git a/lldb/include/lldb/Core/ValueObject.h b/lldb/include/lldb/Core/ValueObject.h index 93eb3e8f590f4e..fc258d7f91b7a6 100644 --- a/lldb/include/lldb/Core/ValueObject.h +++ b/lldb/include/lldb/Core/ValueObject.h @@ -743,6 +743,10 @@ class ValueObject { static lldb::ValueObjectSP CreateValueObjectFromNullptr(lldb::TargetSP target, CompilerType type, llvm::StringRef name); + static lldb::ValueObjectSP + CreateValueObjectFromCString(const char *value_str, + const ExecutionContext &exe_ctx, + CompilerType comp_type, Status &error); lldb::ValueObjectSP Persist(); @@ -754,6 +758,8 @@ class ValueObject { ReadPointedString(lldb::WritableDataBufferSP &buffer_sp, Status &error, bool honor_array); + uint16_t GetVarStringLength(Status &error); + virtual size_t GetPointeeData(DataExtractor &data, uint32_t item_idx = 0, uint32_t item_count = 1); diff --git a/lldb/include/lldb/Expression/DWARFExpression.h b/lldb/include/lldb/Expression/DWARFExpression.h index e85ba464dea6b6..0db0539003cf53 100644 --- a/lldb/include/lldb/Expression/DWARFExpression.h +++ b/lldb/include/lldb/Expression/DWARFExpression.h @@ -11,6 +11,7 @@ #include "lldb/Core/Address.h" #include "lldb/Core/Disassembler.h" +#include "lldb/Core/dwarf.h" #include "lldb/Utility/DataExtractor.h" #include "lldb/Utility/Scalar.h" #include "lldb/Utility/Status.h" @@ -122,22 +123,29 @@ class DWARFExpression { /// A value to put on top of the interpreter stack before evaluating /// the expression, if the expression is parametrized. Can be NULL. /// - /// \param[in] result - /// A value into which the result of evaluating the expression is - /// to be placed. + /// \param[in] stack + /// interpreter stack for evaluation of dwarf expression. It is shared + /// between calls in case of adding/removing entries from stack. /// - /// \param[in] error_ptr - /// If non-NULL, used to report errors in expression evaluation. - /// - /// \return - /// True on success; false otherwise. If error_ptr is non-NULL, - /// details of the failure are provided through it. + /// \return An llvm::Expected that contains the result of the call + /// evaluation on success, or an llvm::Error describing the failure. static llvm::Expected Evaluate(ExecutionContext *exe_ctx, RegisterContext *reg_ctx, - lldb::ModuleSP module_sp, const DataExtractor &opcodes, - const plugin::dwarf::DWARFUnit *dwarf_cu, - const lldb::RegisterKind reg_set, const Value *initial_value_ptr, - const Value *object_address_ptr); + lldb::ModuleSP module_sp, const DataExtractor &opcodes, + const plugin::dwarf::DWARFUnit *dwarf_cu, + const lldb::RegisterKind reg_set, + const Value *initial_value_ptr, + const Value *object_address_ptr, + std::vector &stack, bool expression_call = false); + + static llvm::Error EvaluateCall(ExecutionContext *exe_ctx, RegisterContext *reg_ctx, + lldb::ModuleSP module_sp, + const plugin::dwarf::DWARFUnit *dwarf_cu, + dw_offset_t die_ref_offset, + const lldb::RegisterKind reg_set, + const Value *initial_value_ptr, + const Value *object_address_ptr, + std::vector &stack); static bool ParseDWARFLocationList(const plugin::dwarf::DWARFUnit *dwarf_cu, const DataExtractor &data, diff --git a/lldb/include/lldb/Expression/DWARFExpressionList.h b/lldb/include/lldb/Expression/DWARFExpressionList.h index 664c2603770f62..ed1f7b62b1ebac 100644 --- a/lldb/include/lldb/Expression/DWARFExpressionList.h +++ b/lldb/include/lldb/Expression/DWARFExpressionList.h @@ -9,8 +9,8 @@ #ifndef LLDB_EXPRESSION_DWARFEXPRESSIONLIST_H #define LLDB_EXPRESSION_DWARFEXPRESSIONLIST_H -#include "lldb/Core/Value.h" #include "lldb/Expression/DWARFExpression.h" +#include "lldb/Symbol/CompilerType.h" #include "lldb/Utility/RangeMap.h" #include "lldb/lldb-private.h" diff --git a/lldb/include/lldb/Symbol/CompileUnit.h b/lldb/include/lldb/Symbol/CompileUnit.h index c5bb080d211849..996fd8a1d4905d 100644 --- a/lldb/include/lldb/Symbol/CompileUnit.h +++ b/lldb/include/lldb/Symbol/CompileUnit.h @@ -423,6 +423,8 @@ class CompileUnit : public std::enable_shared_from_this, /// The programming language enumeration value. lldb::LanguageType m_language; /// Compile unit flags that help with partial parsing. + lldb::IdentifierCaseType m_identifier_case; + /// The programming language identifier case type Flags m_flags; /// Maps UIDs to functions. llvm::DenseMap m_functions_by_uid; diff --git a/lldb/include/lldb/Symbol/CompilerType.h b/lldb/include/lldb/Symbol/CompilerType.h index 70dacdcb7986fc..ac8e3e7b170bed 100644 --- a/lldb/include/lldb/Symbol/CompilerType.h +++ b/lldb/include/lldb/Symbol/CompilerType.h @@ -14,6 +14,8 @@ #include #include +#include "lldb/Expression/DWARFExpressionList.h" +#include "lldb/Expression/DWARFExpression.h" #include "lldb/lldb-private.h" #include "llvm/ADT/APSInt.h" #include "llvm/Support/Casting.h" @@ -141,6 +143,8 @@ class CompilerType { bool IsConst() const; + bool IsCStringType(uint32_t &length) const; + bool IsDefined() const; bool IsFloatingPointType(uint32_t &count, bool &is_complex) const; @@ -381,6 +385,21 @@ class CompilerType { /// supports ptrauth modifiers, else return an invalid type. Note that this /// does not check if this type is a pointer. CompilerType AddPtrAuthModifier(uint32_t payload) const; + + /// Dynamic type get base type + CompilerType DynGetBaseType() const; + + /// Dynamic type get location expression + DWARFExpressionList DynGetLocation() const; + + /// Dynamic type get allocated expression + DWARFExpressionList DynGetAllocated() const; + + /// Dynamic array type get count expression + DWARFExpressionList DynArrGetCountExp() const; + + /// Dynamic array type update length + bool DynArrUpdateLength(uint64_t length); /// \} /// Exploring the type. @@ -394,6 +413,10 @@ class CompilerType { lldb::Encoding GetEncoding(uint64_t &count) const; + bool EncodeDataToType(ExecutionContext &exe_scope, + lldb::opaque_compiler_type_t src_type, + const DataExtractor &src_data, + DataExtractor &dest_data); lldb::Format GetFormat() const; std::optional GetTypeBitAlign(ExecutionContextScope *exe_scope) const; diff --git a/lldb/include/lldb/Symbol/Function.h b/lldb/include/lldb/Symbol/Function.h index 8255c2baea7700..a732fd8e5319e0 100644 --- a/lldb/include/lldb/Symbol/Function.h +++ b/lldb/include/lldb/Symbol/Function.h @@ -519,6 +519,32 @@ class Function : public UserID, public SymbolContextScope { /// A const compile unit object pointer. const DWARFExpressionList &GetFrameBaseExpression() const { return m_frame_base; } + /// Get accessor for the RC frame base location. + /// + /// \return + /// A location expression that describes the function frame + /// base. + DWARFExpressionList &GetRCFrameBaseExpression() { return m_rc_frame_base; } + + /// Get const accessor for the RC frame base location. + /// + /// \return + /// A const compile unit object pointer. + const DWARFExpressionList &GetRCFrameBaseExpression() const { return m_rc_frame_base; } + + /// Get accessor for the static link location. + /// + /// \return + /// A location expression that describes the nestee function frame + /// base. + DWARFExpressionList &GetStaticLinkExpression() { return m_static_link; } + + /// Get const accessor for the static link location. + /// + /// \return + /// A const compile unit object pointer. + const DWARFExpressionList &GetStaticLinkExpression() const { return m_static_link; } + ConstString GetName() const; ConstString GetNameNoArguments() const; @@ -657,6 +683,14 @@ class Function : public UserID, public SymbolContextScope { /// pointer. DWARFExpressionList m_frame_base; + /// The raincode frame base expression for variables that are relative to the + /// frame pointer. + DWARFExpressionList m_rc_frame_base; + + /// The static link expression for lexical nested subroutine pointing to the + /// nestee frame + DWARFExpressionList m_static_link; + Flags m_flags; /// Compute the prologue size once and cache it. diff --git a/lldb/include/lldb/Symbol/SymbolFile.h b/lldb/include/lldb/Symbol/SymbolFile.h index 8419495da73a22..2bb03238e39a86 100644 --- a/lldb/include/lldb/Symbol/SymbolFile.h +++ b/lldb/include/lldb/Symbol/SymbolFile.h @@ -222,6 +222,7 @@ class SymbolFile : public PluginInterface { llvm::SmallVector, 1> element_orders; uint32_t byte_stride = 0; uint32_t bit_stride = 0; + llvm::SmallVector element_orders_exp; }; /// If \c type_uid points to an array type, return its characteristics. /// To support variable-length array types, this function takes an diff --git a/lldb/include/lldb/Symbol/TypeSystem.h b/lldb/include/lldb/Symbol/TypeSystem.h index 7d48f9b316138c..c4f13cb05e3f87 100644 --- a/lldb/include/lldb/Symbol/TypeSystem.h +++ b/lldb/include/lldb/Symbol/TypeSystem.h @@ -23,6 +23,7 @@ #include "llvm/Support/JSON.h" #include "lldb/Core/PluginInterface.h" +#include "lldb/Expression/DWARFExpression.h" #include "lldb/Expression/Expression.h" #include "lldb/Symbol/CompilerDecl.h" #include "lldb/Symbol/CompilerDeclContext.h" @@ -288,6 +289,9 @@ class TypeSystem : public PluginInterface, virtual CompilerType GetAtomicType(lldb::opaque_compiler_type_t type); + virtual CompilerType MutateBaseTypeSize(lldb::opaque_compiler_type_t type, + uint64_t sizeInBits); + virtual CompilerType AddConstModifier(lldb::opaque_compiler_type_t type); virtual CompilerType AddVolatileModifier(lldb::opaque_compiler_type_t type); @@ -314,6 +318,13 @@ class TypeSystem : public PluginInterface, virtual lldb::Encoding GetEncoding(lldb::opaque_compiler_type_t type, uint64_t &count) = 0; + virtual bool EncodeDataToType( + ExecutionContext &exe_scope, lldb::opaque_compiler_type_t src_type, + const DataExtractor &src_data, lldb::opaque_compiler_type_t dest_type, + DataExtractor &dest_data, + const lldb::LanguageType lang = lldb::eLanguageTypeUnknown) { + return false; + } virtual lldb::Format GetFormat(lldb::opaque_compiler_type_t type) = 0; @@ -450,6 +461,9 @@ class TypeSystem : public PluginInterface, virtual unsigned GetTypeQualifiers(lldb::opaque_compiler_type_t type) = 0; + virtual bool IsCStringType(lldb::opaque_compiler_type_t type, + uint32_t &length) = 0; + virtual std::optional GetTypeBitAlign(lldb::opaque_compiler_type_t type, ExecutionContextScope *exe_scope) = 0; @@ -460,6 +474,20 @@ class TypeSystem : public PluginInterface, return CompilerType(); } + virtual CompilerType DynGetBaseType(lldb::opaque_compiler_type_t type) const; + + virtual DWARFExpressionList + DynGetLocation(lldb::opaque_compiler_type_t type) const; + + virtual DWARFExpressionList + DynGetAllocated(lldb::opaque_compiler_type_t type) const; + + virtual DWARFExpressionList + DynArrGetCountExp(lldb::opaque_compiler_type_t type) const; + + virtual bool + DynArrUpdateLength(lldb::opaque_compiler_type_t type, uint64_t length); + virtual CompilerType GetBuiltinTypeForEncodingAndBitSize(lldb::Encoding encoding, size_t bit_size) = 0; diff --git a/lldb/include/lldb/Symbol/Variable.h b/lldb/include/lldb/Symbol/Variable.h index c437624d1ea6d7..76507087292f05 100644 --- a/lldb/include/lldb/Symbol/Variable.h +++ b/lldb/include/lldb/Symbol/Variable.h @@ -32,9 +32,10 @@ class Variable : public UserID, public std::enable_shared_from_this { Variable(lldb::user_id_t uid, const char *name, const char *mangled, const lldb::SymbolFileTypeSP &symfile_type_sp, lldb::ValueType scope, SymbolContextScope *owner_scope, const RangeList &scope_range, - Declaration *decl, const DWARFExpressionList &location, - bool external, bool artificial, bool location_is_constant_data, - bool static_member = false); + Declaration *decl, const DWARFExpressionList &location, bool external, + bool artificial, bool location_is_constant_data, + bool static_member = false, + bool has_descriptor = false, uint8_t lexical_scope = 0); virtual ~Variable(); @@ -55,7 +56,7 @@ class Variable : public UserID, public std::enable_shared_from_this { /// namespace)::i", this function will allow a generic match function that can /// be called by commands and expression parsers to make sure we match /// anything we come across. - bool NameMatches(ConstString name) const; + bool NameMatches(ConstString name, bool case_sensitive = true) const; bool NameMatches(const RegularExpression ®ex) const; @@ -73,6 +74,8 @@ class Variable : public UserID, public std::enable_shared_from_this { bool IsStaticMember() const { return m_static_member; } + bool HasDescriptor() const { return m_has_descriptor; } + DWARFExpressionList &LocationExpressionList() { return m_location_list; } const DWARFExpressionList &LocationExpressionList() const { @@ -140,6 +143,10 @@ class Variable : public UserID, public std::enable_shared_from_this { unsigned m_loc_is_const_data : 1; /// Non-zero if variable is static member of a class or struct. unsigned m_static_member : 1; + /// Non-zero if variable has descriptor. + unsigned m_has_descriptor : 1; + /// Lexical scope used in some languages like PL/I + unsigned m_lexical_scope : 8; private: Variable(const Variable &rhs) = delete; diff --git a/lldb/include/lldb/Symbol/VariableList.h b/lldb/include/lldb/Symbol/VariableList.h index fd15f3ae6891f4..2dbb909d0a1f50 100644 --- a/lldb/include/lldb/Symbol/VariableList.h +++ b/lldb/include/lldb/Symbol/VariableList.h @@ -39,11 +39,13 @@ class VariableList { lldb::VariableSP RemoveVariableAtIndex(size_t idx); lldb::VariableSP FindVariable(ConstString name, - bool include_static_members = true); + bool include_static_members = true, + bool case_sensitive = true); lldb::VariableSP FindVariable(ConstString name, lldb::ValueType value_type, - bool include_static_members = true); + bool include_static_members = true, + bool case_sensitive = true); uint32_t FindVariableIndex(const lldb::VariableSP &var_sp); diff --git a/lldb/include/lldb/Target/StackFrame.h b/lldb/include/lldb/Target/StackFrame.h index 5cc0fccee03b8f..41550ff0fe3f10 100644 --- a/lldb/include/lldb/Target/StackFrame.h +++ b/lldb/include/lldb/Target/StackFrame.h @@ -216,6 +216,36 @@ class StackFrame : public ExecutionContextScope, /// Returns the corresponding DWARF expression, or NULL. DWARFExpressionList *GetFrameBaseExpression(Status *error_ptr); + /// Return the Canonical Static Link Address for this frame. + /// + /// For lexical nested funtions, the static link will point to the CFA of + /// nestee function. + /// + /// Live StackFrames will always have a CFA but other types of frames may + /// not be able to supply one. + /// + /// \param [out] value + /// The static link address of the CFA for nestee frame, if available. + /// + /// \param [out] error_ptr + /// If there is an error determining the CFA address, this may contain a + /// string explaining the failure. + /// + /// \return + /// Returns true if the CFA value was successfully set in value. Some + /// Will return false if failed. + bool GetStaticLinkValue(Scalar &value, Status *error_ptr); + + /// Get the DWARFExpression corresponding to the Static link Address. + /// + /// \param [out] error + /// If there is an error determining the CFA address, this may contain a + /// string explaining the failure. + /// + /// \return + /// Returns the corresponding DWARF expression, or NULL. + DWARFExpressionList *GetStaticLinkExpression(Status &error); + /// Get the current lexical scope block for this StackFrame, if possible. /// /// If debug information is available for this stack frame, return a pointer @@ -433,6 +463,27 @@ class StackFrame : public ExecutionContextScope, /// derived from. uint32_t GetConcreteFrameIndex() const { return m_concrete_frame_index; } + /// Searches nested agregate Valobject for named variable for first occurance + /// + /// \params [in] name + /// The name of the Variable to search + /// + /// \param [in] valobj_sp + /// Top level valueObject to search into + /// + /// \params [in] use_dynamic + /// Whether the correct dynamic type of the variable should be + /// determined before creating the ValueObject, or if the static type + /// is sufficient. One of the DynamicValueType enumerated values. + /// + /// \return + // A name matched ValueObject. + lldb::ValueObjectSP + GetValueObjectForFrameAggregateVariable(ConstString name, + lldb::ValueObjectSP &valobj_sp, + lldb::DynamicValueType use_dynamic, + bool look_in_array = false); + /// Create a ValueObject for a given Variable in this StackFrame. /// /// \param [in] variable_sp @@ -449,6 +500,22 @@ class StackFrame : public ExecutionContextScope, GetValueObjectForFrameVariable(const lldb::VariableSP &variable_sp, lldb::DynamicValueType use_dynamic); + /// Add an arbitrary Variable object (e.g. one that specifics a global or + /// static) to a StackFrame's list of ValueObjects. + /// + /// \params [in] variable_sp + /// The Variable to base this ValueObject on + /// + /// \params [in] use_dynamic + /// Whether the correct dynamic type of the variable should be + /// determined before creating the ValueObject, or if the static type + /// is sufficient. One of the DynamicValueType enumerated values. + /// + /// \return + /// A ValueObject for this variable. + lldb::ValueObjectSP TrackGlobalVariable(const lldb::VariableSP &variable_sp, + lldb::DynamicValueType use_dynamic); + /// Query this frame to determine what the default language should be when /// parsing expressions given the execution context. /// @@ -539,6 +606,8 @@ class StackFrame : public ExecutionContextScope, Flags m_flags; Scalar m_frame_base; Status m_frame_base_error; + Scalar m_static_link; + Status m_static_link_error; uint16_t m_frame_recognizer_generation = 0; /// Does this frame have a CFA? Different from CFA == LLDB_INVALID_ADDRESS. bool m_cfa_is_valid; diff --git a/lldb/include/lldb/Target/StackFrameList.h b/lldb/include/lldb/Target/StackFrameList.h index 7d0e7a5b9a71b2..863a963ca13a33 100644 --- a/lldb/include/lldb/Target/StackFrameList.h +++ b/lldb/include/lldb/Target/StackFrameList.h @@ -42,6 +42,9 @@ class StackFrameList { /// Retrieve the stack frame with the given ID \p stack_id. lldb::StackFrameSP GetFrameWithStackID(const StackID &stack_id); + /// Retrieve the stack frame with the given ID \p stack_id. + lldb::StackFrameSP GetFrameWithFrameBaseAddr(const lldb::addr_t frame_base); + /// Mark a stack frame as the currently selected frame and return its index. uint32_t SetSelectedFrame(lldb_private::StackFrame *frame); diff --git a/lldb/include/lldb/Target/Target.h b/lldb/include/lldb/Target/Target.h index 7f4d607f5427df..99235539d83734 100644 --- a/lldb/include/lldb/Target/Target.h +++ b/lldb/include/lldb/Target/Target.h @@ -251,6 +251,10 @@ class TargetProperties : public Properties { void SetRequireHardwareBreakpoints(bool b); + llvm::StringRef GetTargetCharset() const; + + bool GetHideInvalidLegacyFrames() const; + bool GetRequireHardwareBreakpoints() const; bool GetAutoInstallMainExecutable() const; diff --git a/lldb/include/lldb/Utility/DataExtractor.h b/lldb/include/lldb/Utility/DataExtractor.h index 0b7e771ed4f864..feb6ea3725504f 100644 --- a/lldb/include/lldb/Utility/DataExtractor.h +++ b/lldb/include/lldb/Utility/DataExtractor.h @@ -971,6 +971,8 @@ class DataExtractor { bool Append(void *bytes, lldb::offset_t length); + bool Compare(DataExtractor &rhs); + lldb::offset_t BytesLeft(lldb::offset_t offset) const { const lldb::offset_t size = GetByteSize(); if (size > offset) diff --git a/lldb/include/lldb/Utility/RegularExpression.h b/lldb/include/lldb/Utility/RegularExpression.h index e8bd47bb53c29a..8fca50c1e86eee 100644 --- a/lldb/include/lldb/Utility/RegularExpression.h +++ b/lldb/include/lldb/Utility/RegularExpression.h @@ -35,9 +35,8 @@ class RegularExpression { /// \param[in] flags /// An llvm::Regex::RegexFlags that modifies the matching behavior. The /// default is NoFlags. - explicit RegularExpression( - llvm::StringRef string, - llvm::Regex::RegexFlags flags = llvm::Regex::NoFlags); + explicit RegularExpression(llvm::StringRef string, + llvm::Regex::RegexFlags flags = llvm::Regex::NoFlags, bool icase = false); ~RegularExpression() = default; @@ -93,6 +92,7 @@ class RegularExpression { std::string m_regex_text; /// The compiled regular expression. mutable llvm::Regex m_regex; + bool icase = false; }; } // namespace lldb_private diff --git a/lldb/include/lldb/Utility/Scalar.h b/lldb/include/lldb/Utility/Scalar.h index 0d8eba3c9726d5..b4623f2d82fb95 100644 --- a/lldb/include/lldb/Utility/Scalar.h +++ b/lldb/include/lldb/Utility/Scalar.h @@ -139,6 +139,11 @@ class Scalar { // Negates the current value (even for unsigned values). Returns false if the // contained value has a void type. bool UnaryNegate(); // Returns true on success + // Swaps byte in the current value as long as it isn't void/float/double/long + // double types. Returns false if the contained value has a void/float/double + // /long double type, else the value is byte swapped and true is returned. + // usefull to changes the endianity. + bool ByteSwap(); // Returns true on success // Inverts all bits in the current value as long as it isn't void or a // float/double/long double type. Returns false if the contained value has a // void/float/double/long double type, else the value is inverted and true is diff --git a/lldb/include/lldb/lldb-enumerations.h b/lldb/include/lldb/lldb-enumerations.h index 7bfde8b9de1271..51a0c110276832 100644 --- a/lldb/include/lldb/lldb-enumerations.h +++ b/lldb/include/lldb/lldb-enumerations.h @@ -524,6 +524,21 @@ enum LanguageType { eNumLanguageTypes }; +//---------------------------------------------------------------------- +/// Identifier Case type +/// +/// this enumeration indetifies the treatment of identifiers within +/// compilation unit. the default is case sensitive in case it is absent +/// in compilation unit. +//---------------------------------------------------------------------- +enum IdentifierCaseType { + eCaseUnknown = 0, + eCaseSensitive = 1, + eUpperCase = 2, + eLowerCase = 3, + eCaseInsensitive = 4, +}; + enum InstrumentationRuntimeType { eInstrumentationRuntimeTypeAddressSanitizer = 0x0000, eInstrumentationRuntimeTypeThreadSanitizer = 0x0001, @@ -1128,7 +1143,8 @@ FLAGS_ENUM(TypeFlags){ eTypeIsVector = (1u << 16), eTypeIsScalar = (1u << 17), eTypeIsInteger = (1u << 18), eTypeIsFloat = (1u << 19), eTypeIsComplex = (1u << 20), eTypeIsSigned = (1u << 21), - eTypeInstanceIsPointer = (1u << 22)}; + eTypeInstanceIsPointer = (1u << 22), eTypeIsVarString = (1u << 23), + eTypeIsDynamic = (1u << 24)}; FLAGS_ENUM(CommandFlags){ /// eCommandRequiresTarget diff --git a/lldb/packages/Python/lldbsuite/test/lang/cobol/Makefile.rules b/lldb/packages/Python/lldbsuite/test/lang/cobol/Makefile.rules new file mode 100644 index 00000000000000..6ed290b1cdaa27 --- /dev/null +++ b/lldb/packages/Python/lldbsuite/test/lang/cobol/Makefile.rules @@ -0,0 +1,22 @@ +COB_CC ?= cobrc +COB_FLAGS ?= -EXE -Debug -LLVMLink=FALSE +LDFLAGS ?= -no-pie + +COB_FLAGS += $(COBFLAGS_EXTRAS) +EXE ?= a.out +LDLIBS = -lrclz + +#---------------------------------------------------------------------- +# Check if we have any Cobol source files +#---------------------------------------------------------------------- +OBJECTS +=$(strip $(COB_SOURCES:.cob=.o)) + +%.o : %.cob + $(COB_CC) $(COB_FLAGS) $< + +$(EXE) : $(OBJECTS) + $(CC) $(LDFLAGS) $(OBJECTS) -o "$(EXE)" $(LDLIBS) + +all : $(EXE) +.PHONY : clean + $(RM) -rf $(OBJECT) diff --git a/lldb/packages/Python/lldbsuite/test/lang/cobol/global_variables/Makefile b/lldb/packages/Python/lldbsuite/test/lang/cobol/global_variables/Makefile new file mode 100644 index 00000000000000..161eebd089cc9d --- /dev/null +++ b/lldb/packages/Python/lldbsuite/test/lang/cobol/global_variables/Makefile @@ -0,0 +1,5 @@ +LEVEL = .. + +COB_SOURCES := gvar.cob + +include $(LEVEL)/Makefile.rules diff --git a/lldb/packages/Python/lldbsuite/test/lang/cobol/global_variables/TestCobolGlobalVariables.py b/lldb/packages/Python/lldbsuite/test/lang/cobol/global_variables/TestCobolGlobalVariables.py new file mode 100644 index 00000000000000..32f81131d63b10 --- /dev/null +++ b/lldb/packages/Python/lldbsuite/test/lang/cobol/global_variables/TestCobolGlobalVariables.py @@ -0,0 +1,42 @@ +"""Test that Cobol global variables can be inspected by name.""" + +from __future__ import print_function + + +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + + +class GlobalVariablesCobolTestCase(TestBase): + + mydir = TestBase.compute_mydir(__file__) + + def setUp(self): + TestBase.setUp(self) + self.source = lldb.SBFileSpec('gvar.cob') + + @add_test_categories(["dwarf"]) + @skipUnlessPlatform(["linux"]) + def test(self): + self.build() + + (target, _, _, _) = lldbutil.run_to_source_breakpoint(self, "// Set break point #1", self.source) + + # Check that we can access g_file_global_int by its name + self.expect("target variable GLB", VARIABLES_DISPLAYED_CORRECTLY, + substrs=['GLOBAL']) + self.expect("target variable glb", VARIABLES_DISPLAYED_CORRECTLY, + substrs=['GLOBAL']) + + self.expect("target variable glb1", VARIABLES_DISPLAYED_CORRECTLY, + error=True, substrs=['can\'t find global variable']) + self.expect("target variable GLB1", VARIABLES_DISPLAYED_CORRECTLY, + error=True, substrs=['can\'t find global variable']) + + + self.expect("p GLB", substrs=['[8]) $', 'GLOBAL']) + self.expect("p glb", substrs=['[8]) $', 'GLOBAL']) + + self.expect("fr v GLB", substrs=['[8]) $', 'GLOBAL']) + self.expect("fr v glb", substrs=['[8]) $', 'GLOBAL']) diff --git a/lldb/packages/Python/lldbsuite/test/lang/cobol/global_variables/gvar.cob b/lldb/packages/Python/lldbsuite/test/lang/cobol/global_variables/gvar.cob new file mode 100644 index 00000000000000..18eadc9ce7b17c --- /dev/null +++ b/lldb/packages/Python/lldbsuite/test/lang/cobol/global_variables/gvar.cob @@ -0,0 +1,14 @@ + IDENTIFICATION DIVISION. + PROGRAM-ID. main. + + DATA DIVISION. + WORKING-STORAGE SECTION. + 77 GLB PIC X(10) VALUE "GLOBAL". + + PROCEDURE DIVISION. + BEGIN. + DISPLAY GLB + * // Set break point #1. //// break $source:$line + DISPLAY WHEN-COMPILED. + DISPLAY FUNCTION WHEN-COMPILED. + STOP RUN. diff --git a/lldb/source/Commands/CommandObjectDWIMPrint.cpp b/lldb/source/Commands/CommandObjectDWIMPrint.cpp index b7cd955e00203d..b4cfcf0becf157 100644 --- a/lldb/source/Commands/CommandObjectDWIMPrint.cpp +++ b/lldb/source/Commands/CommandObjectDWIMPrint.cpp @@ -154,7 +154,9 @@ void CommandObjectDWIMPrint::DoExecute(StringRef command, // First, try `expr` as the name of a frame variable. if (frame) { auto valobj_sp = frame->FindVariable(ConstString(expr)); - if (valobj_sp && valobj_sp->GetError().Success()) { + if (valobj_sp && valobj_sp->GetTypeName() == "Level88ConditionName") { + /* Evaluate as a source expression and not as a frame variable */ + } else if (valobj_sp && valobj_sp->GetError().Success()) { if (!suppress_result) { if (auto persisted_valobj = valobj_sp->Persist()) valobj_sp = persisted_valobj; diff --git a/lldb/source/Core/Module.cpp b/lldb/source/Core/Module.cpp index 8595a22175d98d..1a2bb11197d7eb 100644 --- a/lldb/source/Core/Module.cpp +++ b/lldb/source/Core/Module.cpp @@ -765,8 +765,8 @@ bool Module::LookupInfo::NameMatchesLookupInfo( if (Language *language = Language::FindPlugin(language_type)) return language->DemangledNameContainsPath(m_name, demangled_function_name); - llvm::StringRef function_name_ref = demangled_function_name; - return function_name_ref.contains(m_name); + llvm::StringRef function_name_ref = demangled_function_name.GetStringRef(); + return function_name_ref.find_insensitive(m_name.GetStringRef()) != llvm::StringRef::npos; } void Module::LookupInfo::Prune(SymbolContextList &sc_list, diff --git a/lldb/source/Core/ValueObject.cpp b/lldb/source/Core/ValueObject.cpp index 1bedd87e943dc3..e9365e12412912 100644 --- a/lldb/source/Core/ValueObject.cpp +++ b/lldb/source/Core/ValueObject.cpp @@ -48,6 +48,7 @@ #include "lldb/Utility/Scalar.h" #include "lldb/Utility/Stream.h" #include "lldb/Utility/StreamString.h" +#include "lldb/Utility/DataEncoder.h" #include "lldb/lldb-private-types.h" #include "llvm/Support/Compiler.h" @@ -57,6 +58,7 @@ #include #include #include +#include #include #include @@ -443,6 +445,10 @@ ValueObjectSP ValueObject::GetChildMemberWithName(llvm::StringRef name, llvm::Expected ValueObject::GetNumChildren(uint32_t max) { UpdateValueIfNeeded(); + static const bool isVarString = GetTypeInfo() & eTypeIsVarString; + if (isVarString) + return CalculateNumChildren(max); + if (max < UINT32_MAX) { if (m_flags.m_children_count_valid) { size_t children_count = m_children.GetChildrenCount(); @@ -989,6 +995,19 @@ ValueObject::ReadPointedString(lldb::WritableDataBufferSP &buffer_sp, return {total_bytes_read, was_capped}; } +uint16_t ValueObject::GetVarStringLength(Status &error) { + const Flags type_flags(GetTypeInfo()); + if (!type_flags.Test(eTypeIsVarString)) + return UINT16_MAX; + + lldb::WritableDataBufferSP buffer_sp; + ReadPointedString(buffer_sp, error, true); + + offset_t offset = 0; + DataExtractor data(buffer_sp, lldb::eByteOrderBig, 8); + return data.GetU16(&offset); +} + llvm::Expected ValueObject::GetObjectDescription() { if (!UpdateValueIfNeeded(true)) return llvm::createStringError("could not update value"); @@ -1632,6 +1651,81 @@ addr_t ValueObject::GetPointerValue(AddressType *address_type) { return address; } +lldb::ValueObjectSP ValueObject::CreateValueObjectFromCString( + const char *value_str, const ExecutionContext &exe_ctx, + CompilerType comp_type, Status &error) { + std::string str(value_str); + llvm::StringRef value_string(str); + size_t data_length = 0; + int64_t iValue; + double dValue; + bool isArray = false; + size_t array_length = 0; + const void *data_ptr = nullptr; + BasicType base_type; + // Regular expressions for integer, string, and float + std::regex intRegex( + "[-+]?\\d+"); // Matches integers with optional negative sign + std::regex floatRegex( + "[-+]?\\d*\\.?\\d+([eE][-+]?\\d+)?"); // Matches floating-point numbers, + // including scientific notation + // with optional sign + + if (std::regex_match(str, intRegex)) { + if (value_string.front() == '+') + value_string = value_string.drop_front(1); + if (value_string.getAsInteger(0, iValue)) { + error = Status::FromErrorStringWithFormat("integer conversion error %s", + value_string.str().c_str()); + return nullptr; + } + data_length = sizeof(iValue); + data_ptr = &iValue; + base_type = eBasicTypeInt; + } else if (std::regex_match(str, floatRegex)) { + if (value_string.getAsDouble(dValue)) { + error = Status::FromErrorStringWithFormat("double conversion error %s", + value_string.str().c_str()); + return nullptr; + } + data_length = sizeof(dValue); + data_ptr = &dValue; + base_type = eBasicTypeDouble; + } else { + if (value_string.front() != '"' || value_string.back() != '"') { + error = Status::FromErrorStringWithFormat("string %s must be enclosed in quotes", + value_string.str().c_str()); + return nullptr; + } + value_string = value_string.drop_front(); + value_string = value_string.drop_back(); + isArray = true; + data_ptr = value_string.data(); + array_length = value_string.size(); + data_length = array_length; + base_type = eBasicTypeChar; + } + + auto type = comp_type.GetBasicTypeFromAST(base_type); + TargetSP target = exe_ctx.GetTargetSP(); + if (!target) + return nullptr; + + ByteOrder byte_order = endian::InlHostByteOrder(); + uint8_t addr_size = target->GetArchitecture().GetAddressByteSize(); + + DataBufferSP buffer(new DataBufferHeap(data_length, 0)); + DataEncoder enc(buffer->GetBytes(), data_length, byte_order, addr_size); + enc.PutData(0, data_ptr, data_length); + DataExtractor data(enc.GetDataBuffer(), byte_order, addr_size); + + if (isArray) { + type = type.GetArrayType(array_length); + } + return ValueObject::CreateValueObjectFromData(llvm::StringRef(), data, + exe_ctx, type); +} + bool ValueObject::SetValueFromCString(const char *value_str, Status &error) { error.Clear(); // Make sure our value is up to date first so that our location and location @@ -1648,6 +1742,31 @@ bool ValueObject::SetValueFromCString(const char *value_str, Status &error) { Value::ValueType value_type = m_value.GetValueType(); + ExecutionContext exe_ctx(GetExecutionContextRef()); + TargetSP target = exe_ctx.GetTargetSP(); + if (!target) + return false; + + const uint8_t addr_size = target->GetArchitecture().GetAddressByteSize(); + auto comp_type = GetCompilerType(); + auto rhsVal = + CreateValueObjectFromCString(value_str, exe_ctx, comp_type, error); + if (error.Fail()) { + return false; + } + DataExtractor data0; + rhsVal->GetData(data0, error); + DataBufferSP buffer_dest(new DataBufferHeap(byte_size, 0)); + DataExtractor dest_data(buffer_dest, ByteOrder::eByteOrderInvalid, addr_size); + const auto src_type = rhsVal->GetCompilerType().GetOpaqueQualType(); + + bool encodedata_to_type = + GetCompilerType().EncodeDataToType(exe_ctx, src_type, data0, dest_data); + if (encodedata_to_type) { + SetData(dest_data, error); + return true; + } + if (value_type == Value::ValueType::Scalar) { // If the value is already a scalar, then let the scalar change itself: m_value.GetScalar().SetValueFromCString(value_str, encoding, byte_size); diff --git a/lldb/source/Core/ValueObjectVariable.cpp b/lldb/source/Core/ValueObjectVariable.cpp index 29aefb270c92c8..6cf46bc3d867f2 100644 --- a/lldb/source/Core/ValueObjectVariable.cpp +++ b/lldb/source/Core/ValueObjectVariable.cpp @@ -107,6 +107,14 @@ ValueObjectVariable::CalculateNumChildren(uint32_t max) { auto child_count = type.GetNumChildren(omit_empty_base_classes, &exe_ctx); if (!child_count) return child_count; + + const Flags type_flags(GetTypeInfo()); + if (type_flags.Test(lldb::eTypeIsVarString)) { + Status error; + auto elements = GetVarStringLength(error); + *child_count = elements < *child_count ? elements : *child_count; + } + return *child_count <= max ? *child_count : max; } @@ -163,12 +171,76 @@ bool ValueObjectVariable::UpdateValue() { sc.function->GetAddressRange().GetBaseAddress().GetLoadAddress( target); } + Value old_value(m_value); - llvm::Expected maybe_value = expr_list.Evaluate( - &exe_ctx, nullptr, loclist_base_load_addr, nullptr, nullptr); + llvm::Expected maybe_value = expr_list.Evaluate(&exe_ctx, nullptr, loclist_base_load_addr, + nullptr, nullptr); + if (maybe_value) + m_value = *maybe_value; + + CompilerType comp_type(GetCompilerType()); + const bool is_dynamic = (comp_type.GetTypeInfo() & lldb::eTypeIsDynamic); + + if (is_dynamic && maybe_value) { + DWARFExpressionList alloc_expr = comp_type.DynGetAllocated(); + if (alloc_expr.IsValid()) { + Value obj_addr(m_value); + Value allocated; + // if (!alloc_expr.Evaluate(&exe_ctx, nullptr, loclist_base_load_addr, + // nullptr, &obj_addr, allocated)) { + if (!alloc_expr.Evaluate(&exe_ctx, nullptr, loclist_base_load_addr, + nullptr, &obj_addr)) { + m_error = Status::FromErrorString( + "dynamic variable allocated attribute read error"); + return m_error.Success(); + } + if (allocated.ResolveValue(&exe_ctx).IsZero()) { + m_error = Status::FromErrorString("dynamic variable not allocated"); + return false; + } + } + } if (maybe_value) { - m_value = *maybe_value; + if (is_dynamic) { + DWARFExpressionList loc_expr = comp_type.DynGetLocation(); + if (loc_expr.IsValid()) { + Value obj_addr(m_value); + if (!loc_expr.Evaluate(&exe_ctx, nullptr, loclist_base_load_addr, + nullptr, &obj_addr)) { + m_error = + Status::FromErrorString("dynamic variable location read error"); + return m_error.Success(); + } + CompilerType base_type = comp_type.DynGetBaseType(); + bool base_type_is_dyn_arr = (base_type.GetTypeInfo() + & (lldb::eTypeIsDynamic | lldb::eTypeIsArray)); + while (base_type_is_dyn_arr) { + DWARFExpressionList count_exp = base_type.DynArrGetCountExp(); + if (count_exp.IsValid()) { + Value length_value; + //if (!count_exp.Evaluate(&exe_ctx, nullptr, loclist_base_load_addr, + // nullptr, &obj_addr, length_value)) { + if (!count_exp.Evaluate(&exe_ctx, nullptr, loclist_base_load_addr, + nullptr, &obj_addr)) { + + m_error = Status::FromErrorString("dynamic array count read error"); + return m_error.Success(); + } + auto m_value = length_value.ResolveValue(&exe_ctx); + uint64_t length = m_value.UInt(); + if (!base_type.DynArrUpdateLength(length)) { + m_error = Status::FromErrorString("dynamic array count update error"); + return m_error.Success(); + } + } + base_type = base_type.GetArrayElementType(exe_ctx.GetBestExecutionContextScope()); + base_type_is_dyn_arr = (base_type.GetTypeInfo() + & (lldb::eTypeIsDynamic | lldb::eTypeIsArray)); + } + } + } + m_resolved_value = m_value; m_value.SetContext(Value::ContextType::Variable, variable); @@ -311,8 +383,6 @@ void ValueObjectVariable::DoUpdateChildrenAddressType(ValueObject &valobj) { } } - - bool ValueObjectVariable::IsInScope() { const ExecutionContextRef &exe_ctx_ref = GetExecutionContextRef(); if (exe_ctx_ref.HasFrameRef()) { diff --git a/lldb/source/DataFormatters/ValueObjectPrinter.cpp b/lldb/source/DataFormatters/ValueObjectPrinter.cpp index ce24a7866e53a5..6938441f60ad39 100644 --- a/lldb/source/DataFormatters/ValueObjectPrinter.cpp +++ b/lldb/source/DataFormatters/ValueObjectPrinter.cpp @@ -366,10 +366,13 @@ void ValueObjectPrinter::GetValueSummaryError(std::string &value, ValueObject &valobj = GetMostSpecializedValue(); // if I am printing synthetized elements, apply the format to those elements // only + bool skip_summary = false; if (m_options.m_pointer_as_array) valobj.GetValueAsCString(lldb::eFormatDefault, value); - else if (format != eFormatDefault && format != valobj.GetFormat()) + else if (format != eFormatDefault && format != valobj.GetFormat()) { valobj.GetValueAsCString(format, value); + skip_summary = true; + } else { const char *val_cstr = valobj.GetValueAsCString(); if (val_cstr) @@ -396,7 +399,7 @@ void ValueObjectPrinter::GetValueSummaryError(std::string &value, } } else if (IsUninitialized()) { summary.assign(""); - } else if (m_options.m_omit_summary_depth == 0) { + } else if (!skip_summary && (m_options.m_omit_summary_depth == 0)) { TypeSummaryImpl *entry = GetSummaryFormatter(); if (entry) { valobj.GetSummaryAsCString(entry, summary, @@ -838,7 +841,9 @@ llvm::Error ValueObjectPrinter::PrintChildrenIfNeeded(bool value_printed, !m_options.m_allow_oneliner_mode || m_options.m_flat_output || (m_options.m_pointer_as_array) || m_options.m_show_location) ? false - : DataVisualization::ShouldPrintAsOneLiner(valobj); + : ((m_options.m_format == eFormatDefault) && + DataVisualization::ShouldPrintAsOneLiner(valobj)); + if (print_children && IsInstancePointer()) { uint64_t instance_ptr_value = valobj.GetValueAsUnsigned(0); if (m_printed_instance_pointers->count(instance_ptr_value)) { diff --git a/lldb/source/Expression/DWARFExpression.cpp b/lldb/source/Expression/DWARFExpression.cpp index 22d899f799d0fd..07b062727f2350 100644 --- a/lldb/source/Expression/DWARFExpression.cpp +++ b/lldb/source/Expression/DWARFExpression.cpp @@ -237,6 +237,8 @@ static lldb::offset_t GetOpcodeDataSize(const DataExtractor &data, case DW_OP_form_tls_address: // 0x9b DWARF3 case DW_OP_call_frame_cfa: // 0x9c DWARF3 case DW_OP_stack_value: // 0x9f DWARF4 + case DW_OP_RC_byte_swap: // 0xea RAINCODE extension + case DW_OP_RC_resolve_file_address: // 0xea RAINCODE extension case DW_OP_GNU_push_tls_address: // 0xe0 GNU extension return 0; @@ -814,22 +816,30 @@ static Scalar DerefSizeExtractDataHelper(uint8_t *addr_bytes, DataExtractor addr_data(addr_bytes, size_addr_bytes, byte_order, size); lldb::offset_t addr_data_offset = 0; - if (size <= 8) - return addr_data.GetMaxU64(&addr_data_offset, size); - else + switch (size) { + case 1: + return addr_data.GetU8(&addr_data_offset); + case 2: + return addr_data.GetU16(&addr_data_offset); + case 4: + return addr_data.GetU32(&addr_data_offset); + case 8: + return addr_data.GetU64(&addr_data_offset); + default: return addr_data.GetAddress(&addr_data_offset); + } } llvm::Expected DWARFExpression::Evaluate( ExecutionContext *exe_ctx, RegisterContext *reg_ctx, lldb::ModuleSP module_sp, const DataExtractor &opcodes, const DWARFUnit *dwarf_cu, const lldb::RegisterKind reg_kind, - const Value *initial_value_ptr, const Value *object_address_ptr) { + const Value *initial_value_ptr, const Value *object_address_ptr, + std::vector &stack, bool expression_call) { if (opcodes.GetByteSize() == 0) return llvm::createStringError( "no location, value may have been optimized out"); - std::vector stack; Process *process = nullptr; StackFrame *frame = nullptr; @@ -1391,6 +1401,50 @@ llvm::Expected DWARFExpression::Evaluate( return llvm::createStringError("unary negate failed"); break; + // OPCODE: DW_OP_RC_byte_swap + // OPERANDS: none + // DESCRIPTION: pops the top stack entry, and pushes its bytes swapped + // result + case DW_OP_RC_byte_swap: + if (stack.empty()) { + return llvm::createStringError("Expression stack needs at least 1 item for DW_OP_RC_byte_swap."); + } else { + if (!stack.back().ResolveValue(exe_ctx).ByteSwap()) { + return llvm::createStringError("Byte Swap failed."); + } + } + break; + + // OPCODE: DW_OP_RC_resolve_file_address + // OPERANDS: none + // DESCRIPTION: pops the top stack entry and tries to resolve the file + // address to target address for address calculations. + case DW_OP_RC_resolve_file_address: + if (stack.empty()) { + return llvm::createStringError("Expression stack needs at least 1 item for DW_OP_RC_byte_swap."); + + } else { + if (stack.back().GetValueType() == Value::ValueType::FileAddress) { + auto file_addr = + stack.back().GetScalar().ULongLong(LLDB_INVALID_ADDRESS); + if (!module_sp) { + return llvm::createStringError("need module to resolve file address for DW_OP_deref"); + } + Address so_addr; + if (!module_sp->ResolveFileAddress(file_addr, so_addr)) { + return llvm::createStringError("failed to resolve file address in module"); + + } + addr_t load_Addr = so_addr.GetLoadAddress(exe_ctx->GetTargetPtr()); + if (load_Addr == LLDB_INVALID_ADDRESS) { + return llvm::createStringError("failed to resolve load address"); + } + stack.back().GetScalar() = load_Addr; + stack.back().SetValueType(Value::ValueType::LoadAddress); + } + } + break; + // OPCODE: DW_OP_not // OPERANDS: none // DESCRIPTION: pops the top stack entry, and pushes its bitwise @@ -2043,8 +2097,13 @@ llvm::Expected DWARFExpression::Evaluate( // may be used as parameters by the called expression and values left on // the stack by the called expression may be used as return values by prior // agreement between the calling and called expressions. - case DW_OP_call2: - return llvm::createStringError("unimplemented opcode DW_OP_call2"); + case DW_OP_call2: { + dw_offset_t die_ref_offset = + opcodes.GetU16(&offset) + dwarf_cu->GetOffset(); + EvaluateCall(exe_ctx, reg_ctx, module_sp, dwarf_cu, die_ref_offset, + reg_kind, initial_value_ptr, object_address_ptr, stack); + } break; + // OPCODE: DW_OP_call4 // OPERANDS: 1 // uint32_t compile unit relative offset of a DIE @@ -2064,8 +2123,12 @@ llvm::Expected DWARFExpression::Evaluate( // may be used as parameters by the called expression and values left on // the stack by the called expression may be used as return values by prior // agreement between the calling and called expressions. - case DW_OP_call4: - return llvm::createStringError("unimplemented opcode DW_OP_call4"); + case DW_OP_call4: { + dw_offset_t die_ref_offset = + opcodes.GetU32(&offset) + dwarf_cu->GetOffset(); + EvaluateCall(exe_ctx, reg_ctx, module_sp, dwarf_cu, die_ref_offset, + reg_kind, initial_value_ptr, object_address_ptr, stack); + } break; // OPCODE: DW_OP_stack_value // OPERANDS: None @@ -2287,6 +2350,61 @@ llvm::Expected DWARFExpression::Evaluate( return stack.back(); } +llvm::Error DWARFExpression::EvaluateCall( + ExecutionContext *exe_ctx, RegisterContext *reg_ctx, ModuleSP module_sp, + const DWARFUnit *dwarf_cu, dw_offset_t die_ref_offset, + const RegisterKind reg_kind, const Value *initial_value_ptr, + const Value *object_address_ptr, std::vector &stack) { + + // Retrieve the DWARF DIE for the given offset + DWARFDIE ref_die = const_cast(dwarf_cu)->GetDIE(die_ref_offset); + if (!ref_die.IsValid()) { + return llvm::createStringError( + llvm::inconvertibleErrorCode(), + "Unable to find DW_OP_call[2|4] reference = %" PRIu32, die_ref_offset); + } + + // Retrieve the attribute value from the DIE + DWARFFormValue form_value; + const dw_offset_t attrib_offset = + ref_die.GetDIE()->GetAttributeValue(dwarf_cu, DW_AT_location, form_value); + if (attrib_offset == 0) { + return llvm::createStringError( + llvm::inconvertibleErrorCode(), + "Attribute offset for DW_OP_call[2|4] reference = %" PRIu32 + " not found", + die_ref_offset); + } + + // Check if the form value is in block form + if (!DWARFFormValue::IsBlockForm(form_value.Form())) { + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "DW_OP_call[2|4] to reference = %" PRIu32 + " with location list is not supported.", + die_ref_offset); + } + + // Extract data for evaluation + const DWARFDataExtractor &ref_debug_info_data = ref_die.GetData(); + uint32_t location_offset = + form_value.BlockData() - ref_debug_info_data.GetDataStart(); + uint32_t location_length = form_value.Unsigned(); + + // Evaluate the expression + auto result_or_error = Evaluate( + exe_ctx, reg_ctx, module_sp, + DataExtractor(ref_debug_info_data, location_offset, location_length), + dwarf_cu, reg_kind, initial_value_ptr, object_address_ptr, stack, true); + + if (!result_or_error) { + // Propagate any error from the Evaluate function + return result_or_error.takeError(); + } + + // If successful, return success + return llvm::Error::success(); +} + bool DWARFExpression::ParseDWARFLocationList( const DWARFUnit *dwarf_cu, const DataExtractor &data, DWARFExpressionList *location_list) { diff --git a/lldb/source/Expression/DWARFExpressionList.cpp b/lldb/source/Expression/DWARFExpressionList.cpp index 7a5cf9f9a0be46..7aa5542558a0f6 100644 --- a/lldb/source/Expression/DWARFExpressionList.cpp +++ b/lldb/source/Expression/DWARFExpressionList.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "lldb/Expression/DWARFExpressionList.h" +#include "lldb/Core/Value.h" #include "Plugins/SymbolFile/DWARF/DWARFUnit.h" #include "lldb/Symbol/Function.h" #include "lldb/Target/RegisterContext.h" @@ -203,6 +204,9 @@ llvm::Expected DWARFExpressionList::Evaluate( lldb::addr_t func_load_addr, const Value *initial_value_ptr, const Value *object_address_ptr) const { ModuleSP module_sp = m_module_wp.lock(); + std::vector stack; + if (initial_value_ptr) + stack.push_back(*initial_value_ptr); DataExtractor data; RegisterKind reg_kind; DWARFExpression expr; @@ -236,5 +240,5 @@ llvm::Expected DWARFExpressionList::Evaluate( reg_kind = expr.GetRegisterKind(); return DWARFExpression::Evaluate(exe_ctx, reg_ctx, module_sp, data, m_dwarf_cu, reg_kind, initial_value_ptr, - object_address_ptr); + object_address_ptr, stack); } diff --git a/lldb/source/Plugins/ExpressionParser/CMakeLists.txt b/lldb/source/Plugins/ExpressionParser/CMakeLists.txt index 17c40aee44cc27..e372eb7bd037a8 100644 --- a/lldb/source/Plugins/ExpressionParser/CMakeLists.txt +++ b/lldb/source/Plugins/ExpressionParser/CMakeLists.txt @@ -1 +1,3 @@ add_subdirectory(Clang) +add_subdirectory(Cobol) +add_subdirectory(PLI) diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h index 09604feea5dec4..9213f971d25e53 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h @@ -26,6 +26,7 @@ #include "lldb/Target/ExecutionContext.h" #include "lldb/lldb-forward.h" #include "lldb/lldb-private.h" +#include "llvm/Support/ExtensibleRTTI.h" namespace lldb_private { diff --git a/lldb/source/Plugins/ExpressionParser/Cobol/CMakeLists.txt b/lldb/source/Plugins/ExpressionParser/Cobol/CMakeLists.txt new file mode 100644 index 00000000000000..74fc07d5c4488c --- /dev/null +++ b/lldb/source/Plugins/ExpressionParser/Cobol/CMakeLists.txt @@ -0,0 +1,13 @@ +add_lldb_library(lldbPluginExpressionParserCobol + CobolLexer.cpp + CobolParser.cpp + CobolUserExpression.cpp + + LINK_LIBS + lldbCore + lldbExpression + lldbSymbol + lldbTarget + LINK_COMPONENTS + Support + ) diff --git a/lldb/source/Plugins/ExpressionParser/Cobol/CobolAST.h b/lldb/source/Plugins/ExpressionParser/Cobol/CobolAST.h new file mode 100644 index 00000000000000..072e6b55ea14c4 --- /dev/null +++ b/lldb/source/Plugins/ExpressionParser/Cobol/CobolAST.h @@ -0,0 +1,397 @@ +//===-- CobolAST.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_CobolAST_h +#define liblldb_CobolAST_h + +#include "Plugins/ExpressionParser/Cobol/CobolLexer.h" +#include "lldb/lldb-forward.h" +#include "lldb/lldb-private.h" +#include "llvm/Support/Casting.h" + +namespace lldb_private { + +class CobolASTNode { +public: + enum NodeKind { + eBasicLit, + eUnaryExpr, + eEmptyStmt, + eExprStmt, + eIdent, + eRefModExpr, + eSelectorExpr, + eFuncCallExpr, + eAssignmentExpr, + eCompareExpr, + eIndexExpr, + }; + + virtual ~CobolASTNode() = default; + virtual const char *GetKindName() const = 0; + NodeKind GetKind() const { return m_kind; } + +protected: + explicit CobolASTNode(NodeKind kind) : m_kind(kind) {} + +private: + const NodeKind m_kind; + + CobolASTNode(const CobolASTNode &) = delete; + const CobolASTNode &operator=(const CobolASTNode &) = delete; +}; + +class CobolASTExpr : public CobolASTNode { +public: + template R Visit(V *v) const; + + static bool classof(const CobolASTNode *node) { + return node->GetKind() == eIdent; + } + +protected: + explicit CobolASTExpr(NodeKind kind) : CobolASTNode(kind) {} + +private: + CobolASTExpr(const CobolASTExpr &) = delete; + const CobolASTExpr &operator=(const CobolASTExpr &) = delete; +}; + +class CobolASTIdent : public CobolASTExpr { +public: + explicit CobolASTIdent(CobolLexer::Token name) + : CobolASTExpr(eIdent), m_name(name) {} + ~CobolASTIdent() override = default; + + const char *GetKindName() const override { return "Identifier"; } + static bool classof(const CobolASTNode *node) { + return node->GetKind() == eIdent; + } + CobolLexer::Token GetName() const { return m_name; } + void SetName(CobolLexer::Token name) { m_name = name; } + +private: + friend class CobolASTNode; + CobolLexer::Token m_name; + CobolASTIdent(const CobolASTIdent &) = delete; + const CobolASTIdent &operator=(const CobolASTIdent &) = delete; +}; + +class CobolASTStmt : public CobolASTNode { +public: + template R Visit(V *v) const; + static bool classof(const CobolASTNode *node) { + return node->GetKind() == eEmptyStmt; + } + +protected: + explicit CobolASTStmt(NodeKind kind) : CobolASTNode(kind) {} + +private: + CobolASTStmt(const CobolASTStmt &) = delete; + const CobolASTNode &operator=(const CobolASTNode &) = delete; +}; + +class CobolASTEmptyStmt : public CobolASTStmt { +public: + CobolASTEmptyStmt() : CobolASTStmt(eEmptyStmt) {} + ~CobolASTEmptyStmt() override = default; + + const char *GetKindName() const override { return "Empty Statement"; } + static bool classof(const CobolASTNode *node) { + return node->GetKind() == eEmptyStmt; + } + + CobolASTEmptyStmt(const CobolASTEmptyStmt &) = delete; + const CobolASTEmptyStmt &operator=(const CobolASTEmptyStmt &) = delete; +}; + +class CobolASTExprStmt : public CobolASTStmt { +public: + explicit CobolASTExprStmt(CobolASTExpr *expr) + : CobolASTStmt(eExprStmt), m_expr(expr) {} + ~CobolASTExprStmt() override = default; + + const char *GetKindName() const override { return "Expr Statement"; } + static bool classof(const CobolASTNode *n) { + return n->GetKind() == eExprStmt; + } + const CobolASTExpr *GetExpr() const { return m_expr.get(); } + void SetExpr(CobolASTExpr *expr) { m_expr.reset(expr); } + +private: + friend class CobolASTNode; + std::unique_ptr m_expr; + CobolASTExprStmt(const CobolASTExprStmt &) = delete; + const CobolASTExprStmt &operator=(const CobolASTExprStmt &) = delete; +}; + +class CobolASTBasicLit : public CobolASTExpr { +public: + explicit CobolASTBasicLit(CobolLexer::Token T) + : CobolASTExpr(eBasicLit), m_value(T) {} + ~CobolASTBasicLit() override = default; + + const char *GetKindName() const override { return "Basic Literal"; } + static bool classof(const CobolASTNode *node) { + return node->GetKind() == eBasicLit; + } + + CobolLexer::Token GetValue() const { return m_value; } + void SetValue(CobolLexer::Token T) { m_value = T; } + +private: + friend class CobolASTNode; + CobolLexer::Token m_value; + + CobolASTBasicLit(const CobolASTBasicLit &) = delete; + const CobolASTBasicLit &operator=(const CobolASTBasicLit &) = delete; +}; + +class CobolASTUnaryExpr : public CobolASTExpr { +public: + CobolASTUnaryExpr(CobolLexer::CobolLexer::TokenType tok, CobolASTExpr *expr) + : CobolASTExpr(eUnaryExpr), m_tt(tok), m_expr(expr) {} + ~CobolASTUnaryExpr() override = default; + + const char *GetKindName() const override { return "Unary Expression"; } + static bool classof(const CobolASTNode *node) { + return node->GetKind() == eUnaryExpr; + } + + CobolLexer::CobolLexer::TokenType GetOp() const { return m_tt; } + void SetOp(CobolLexer::CobolLexer::TokenType tt) { m_tt = tt; } + + const CobolASTExpr *GetExpr() const { return m_expr.get(); } + void Setexpr(CobolASTExpr *expr) { m_expr.reset(expr); } + +private: + friend class CobolASTNode; + CobolLexer::CobolLexer::TokenType m_tt; + std::unique_ptr m_expr; + + CobolASTUnaryExpr(const CobolASTUnaryExpr &) = delete; + const CobolASTUnaryExpr &operator=(const CobolASTUnaryExpr &) = delete; +}; + +class CobolASTSelectorExpr : public CobolASTExpr { +public: + CobolASTSelectorExpr(CobolASTExpr *expr, CobolASTIdent *sel) + : CobolASTExpr(eSelectorExpr), m_expr_up(expr), m_sel_up(sel) {} + ~CobolASTSelectorExpr() override = default; + + const char *GetKindName() const override { return "Selector Expression"; } + + static bool classof(const CobolASTNode *n) { + return n->GetKind() == eSelectorExpr; + } + + const CobolASTExpr *GetExpr() const { return m_expr_up.get(); } + void SetExpr(CobolASTExpr *expr) { m_expr_up.reset(expr); } + void ReplaceExpr(CobolASTExpr *expr) { + m_expr_up.release(); + m_expr_up.reset(expr); + } + + const CobolASTIdent *GetSel() const { return m_sel_up.get(); } + void SetSel(CobolASTIdent *sel) { m_sel_up.reset(sel); } + +private: + friend class CobolASTNode; + std::unique_ptr m_expr_up; + std::unique_ptr m_sel_up; + + CobolASTSelectorExpr(const CobolASTSelectorExpr &) = delete; + const CobolASTSelectorExpr &operator=(const CobolASTSelectorExpr &) = delete; +}; + +class CobolASTIndexExpr : public CobolASTExpr { +public: + CobolASTIndexExpr(std::vector> indices) + : CobolASTExpr(eIndexExpr), m_indices(std::move(indices)) {} + ~CobolASTIndexExpr() override = default; + + static bool classof(const CobolASTNode *n) { + return n->GetKind() == eIndexExpr; + } + + const char *GetKindName() const override { + return "Index Expression"; + } + + size_t GetNumberOfIndices() const { + return m_indices.size(); + } + + const std::vector>& GetIndices() const { + return m_indices; + } +private: + std::vector> m_indices; + + CobolASTIndexExpr(const CobolASTIndexExpr &) = delete; + const CobolASTIndexExpr & + operator=(const CobolASTIndexExpr &) = delete; +}; + +class CobolASTRefModifierExpr : public CobolASTExpr { +public: + CobolASTRefModifierExpr(CobolASTExpr *expr, CobolASTExpr *start, + CobolASTExpr *len) + : CobolASTExpr(eRefModExpr), m_expr(expr), m_expr_start(start), + m_expr_len(len) {} + ~CobolASTRefModifierExpr() override = default; + + static bool classof(const CobolASTNode *n) { + return n->GetKind() == eRefModExpr; + } + + const CobolASTExpr *GetExpr() const { return m_expr.get(); } + void SetExpr(CobolASTExpr *expr) { m_expr.reset(expr); } + void ReplaceExpr(CobolASTExpr *expr) { + m_expr.release(); + m_expr.reset(expr); + } + + const CobolASTExpr *GetStartExpr() const { return m_expr_start.get(); } + void SetStartExpr(CobolASTExpr *expr) { m_expr_start.reset(expr); } + + const CobolASTExpr *GetLenExpr() const { return m_expr_len.get(); } + void SetLenExpr(CobolASTExpr *expr) { m_expr_len.reset(expr); } + + const char *GetKindName() const override { + return "reference modifier Expression"; + } + +private: + std::unique_ptr m_expr; + std::unique_ptr m_expr_start; + std::unique_ptr m_expr_len; + + CobolASTRefModifierExpr(const CobolASTRefModifierExpr &) = delete; + const CobolASTRefModifierExpr & + operator=(const CobolASTRefModifierExpr &) = delete; +}; + +class CobolASTFuncCallExpr : public CobolASTExpr { +public: + CobolASTFuncCallExpr(CobolLexer::Token funcName) + : CobolASTExpr(eFuncCallExpr), funcName(funcName) {} + + static bool classof(const CobolASTNode *n) { + return n->GetKind() == eFuncCallExpr; + } + + CobolLexer::Token GetFuncName() const { return funcName; } + const CobolASTExpr *getParamAtIndex(size_t index) const { + if (index < paramList.size()) + return paramList[index]; + return nullptr; + } + + void addParam(CobolASTExpr *param) { paramList.push_back(param); } + + const char *GetKindName() const override { + return "function call expression"; + } + + size_t getTotalNumParams() const { return paramList.size(); } + +private: + std::vector paramList; + CobolLexer::Token funcName; + + CobolASTFuncCallExpr(const CobolASTFuncCallExpr &) = delete; + const CobolASTFuncCallExpr &operator=(const CobolASTFuncCallExpr &) = delete; +}; + +class CobolASTCompareExpr : public CobolASTExpr { +public: + CobolASTCompareExpr(CobolASTExpr *lhs, CobolASTExpr *rhs, + CobolLexer::CobolLexer::TokenType tt, bool is_not = false) + : CobolASTExpr(eCompareExpr), m_lhsExpr(lhs), m_rhsExpr(rhs), + m_cmp_op(tt), is_not(is_not) {} + + static bool classof(const CobolASTNode *n) { + return n->GetKind() == eCompareExpr; + } + + const CobolASTExpr *GetlhsExpr() const { return m_lhsExpr.get(); } + void SetlhsExpr(CobolASTExpr *expr) { m_lhsExpr.reset(expr); } + + const CobolASTExpr *GetrhsExpr() const { return m_rhsExpr.get(); } + void SetrhsExpr(CobolASTExpr *expr) { m_rhsExpr.reset(expr); } + + CobolLexer::CobolLexer::TokenType GetCmpOp() const { return m_cmp_op; } + bool GetIsNot() const { return is_not; } + const char *GetKindName() const override { return "compare expression"; } + +private: + std::unique_ptr m_lhsExpr; + std::unique_ptr m_rhsExpr; + CobolLexer::CobolLexer::TokenType m_cmp_op; + const bool is_not; + + CobolASTCompareExpr(const CobolASTCompareExpr &) = delete; + const CobolASTCompareExpr &operator=(const CobolASTCompareExpr &) = delete; +}; + +class CobolASTAssignmentExpr : public CobolASTExpr { +public: + CobolASTAssignmentExpr(CobolASTExpr *lhs, CobolASTExpr *rhs) + : CobolASTExpr(eAssignmentExpr), m_lhsExpr(lhs), m_rhsExpr(rhs) {} + + static bool classof(const CobolASTNode *n) { + return n->GetKind() == eAssignmentExpr; + } + + const CobolASTExpr *GetlhsExpr() const { return m_lhsExpr.get(); } + void SetlhsExpr(CobolASTExpr *expr) { m_lhsExpr.reset(expr); } + + const CobolASTExpr *GetrhsExpr() const { return m_rhsExpr.get(); } + void SetrhsExpr(CobolASTExpr *expr) { m_rhsExpr.reset(expr); } + + const char *GetKindName() const override { return "assignment expression"; } + +private: + std::unique_ptr m_lhsExpr; + std::unique_ptr m_rhsExpr; + + CobolASTAssignmentExpr(const CobolASTAssignmentExpr &) = delete; + const CobolASTAssignmentExpr & + operator=(const CobolASTAssignmentExpr &) = delete; +}; + +template R CobolASTExpr::Visit(V *v) const { + switch (GetKind()) { + default: + return R(); + case eBasicLit: + return v->VisitBasicLit(llvm::cast(this)); + case eIdent: + return v->VisitIdent(llvm::cast(this)); + case eUnaryExpr: + return v->VisitUnaryExpr(llvm::cast(this)); + case eSelectorExpr: + return v->VisitSelectorExpr(llvm::cast(this)); + case eRefModExpr: + return v->VisitRefModExpr(llvm::cast(this)); + case eFuncCallExpr: + return v->VisitFuncCallExpr(llvm::cast(this)); + case eAssignmentExpr: + return v->VisitAssignmentExpr( + llvm::cast(this)); + case eCompareExpr: + return v->VisitCompareExpr(llvm::cast(this)); + } +} + +} // namespace lldb_private + +#endif // liblldb_CobolAST_h diff --git a/lldb/source/Plugins/ExpressionParser/Cobol/CobolASTNodes.def b/lldb/source/Plugins/ExpressionParser/Cobol/CobolASTNodes.def new file mode 100644 index 00000000000000..35b539f29662a0 --- /dev/null +++ b/lldb/source/Plugins/ExpressionParser/Cobol/CobolASTNodes.def @@ -0,0 +1,14 @@ +//===-- CobolASTNodes.def ---------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#if !defined(HANDLE_COBOL_NODE) +#error "Cobol node handle not defined" +#endif + +HANDLE_COBOL_NODE(BadDeclTest) diff --git a/lldb/source/Plugins/ExpressionParser/Cobol/CobolLexer.cpp b/lldb/source/Plugins/ExpressionParser/Cobol/CobolLexer.cpp new file mode 100644 index 00000000000000..167eea2114baa5 --- /dev/null +++ b/lldb/source/Plugins/ExpressionParser/Cobol/CobolLexer.cpp @@ -0,0 +1,215 @@ +//===-- CobolLexer.cpp ------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include + +#include "CobolLexer.h" + +using namespace lldb_private; +using namespace llvm; + +const CobolLexer::KeywordMap CobolLexer::m_keywords = { + {"&", OP_AMP}, {":", OP_COLON}, {"(", OP_LPAREN}, + {"[", OP_LBRACK}, {"{", OP_LBRACE}, {")", OP_RPAREN}, + {"]", OP_RBRACK}, {"}", OP_RBRACE}, {"*", OP_STAR}, + {"+", OP_PLUS}, {"-", OP_MINUS}, {".", OP_DOT}, + {"OF", KW_OF}, {"LENGTH", OP_SIZEOF}, {"=", OP_EQ}, + {"MOVE", KW_MV}, {"SET", KW_SET}, {"TO", KW_TO}, + {"IF", KW_IF}, {"EQUALS", KW_EQUALS}, {"IS", KW_IS}, + {"NOT", KW_NOT}, {">", OP_COMP_GT}, {"<", OP_COMP_LT}, + {">=", OP_COMP_GE}, {"<=", OP_COMP_LE}, {",", OP_COMMA}, +}; + +CobolLexer::CobolLexer(const char *expr) + : m_start(expr), m_end(expr + strlen(expr)), m_last_token(TOK_INVALID, "") { +} + +const CobolLexer::Token &CobolLexer::Lex() { + bool newline = false; + SkipWhiteSpace(newline); + + if (m_start >= m_end) { + m_last_token.m_text = llvm::StringRef(""); + m_last_token.m_type = TOK_EOF; + return m_last_token; + } + + const char *start = m_start; + size_t offset = 0; + CobolLexer::TokenType lastTok = m_last_token.m_type; + m_last_token.m_type = TOK_INVALID; + + if (newline) { + switch (lastTok) { + default: + m_start++; + start++; + break; + case TOK_IDENTIFIER: + case LIT_FLOAT: + case LIT_INTEGER: + case LIT_STRING: + m_last_token.m_text = llvm::StringRef(""); + m_last_token.m_type = OP_SEMICOLON; + return m_last_token; + } + } + + if (IsDigit(*m_start)) + m_last_token.m_type = DoNumber(); + else if (*m_start == '-' && IsDigit(m_start[1])) + m_last_token.m_type = DoNumber(); + else if (*m_start == '+' && IsDigit(m_start[1])) + m_last_token.m_type = DoNumber(); + else if (IsOperator(*m_start)) + m_last_token.m_type = DoOperator(); + else { + switch (*m_start) { + // persistant variables + case '$': + default: { + if (IsLetterOrDigit(*m_start)) + m_last_token.m_type = DoIdent(); + } break; + case '.': { + if (IsDigit(m_start[1])) + m_last_token.m_type = DoNumber(); + else + m_last_token.m_type = DoOperator(); + } break; + case '"': + case '`': + m_last_token.m_type = DoString(); + // skip quotes + start++; + offset = 1; + break; + } + } + size_t length = m_start - start; + if (length) + length -= offset; + m_last_token.m_text = llvm::StringRef(start, length); + return m_last_token; +} + +CobolLexer::TokenType CobolLexer::DoString() { + if (*m_start == '`') { + while (++m_start < m_end) { + if (*m_start == '`') + ++m_start; + return LIT_STRING; + } + return TOK_INVALID; + } + + while (++m_start < m_end) { + switch (*m_start) { + // We already have matched openning double quotation + case '"': + ++m_start; + return LIT_STRING; + case '\n': + return TOK_INVALID; + case '\\': + if (m_start[1] == '\n') + return TOK_INVALID; + m_start++; + } + } + return TOK_INVALID; +} + +CobolLexer::TokenType CobolLexer::DoNumber() { + if (m_start[0] == '0' && (m_start[1] == 'x' || m_start[1] == 'X')) { + m_start += 2; + while (IsHexChar(*m_start)) + m_start++; + return LIT_INTEGER; + } + + if (*m_start == '+' || *m_start == '-') + ++m_start; + + bool dot_ok = true; + bool e_ok = true; + while (true) { + while (IsDigit(*m_start)) + ++m_start; + switch (*m_start) { + case '.': + if (!dot_ok) + return LIT_FLOAT; + ++m_start; + dot_ok = false; + break; + case 'e': + case 'E': + if (!e_ok) + return LIT_FLOAT; + dot_ok = e_ok = false; + ++m_start; + if (*m_start == '+' || *m_start == '-') + ++m_start; + break; + default: + if (dot_ok) + return LIT_INTEGER; + return LIT_FLOAT; + } + } +} + +CobolLexer::TokenType CobolLexer::DoIdent() { + const char *start = m_start++; + while (m_start < m_end && IsLetterOrDigit(*m_start)) + ++m_start; + TokenType kw = LookupKeyword(llvm::StringRef(start, m_start - start)); + if (kw != TOK_INVALID) + return kw; + return TOK_IDENTIFIER; +} + +CobolLexer::TokenType CobolLexer::DoOperator() { + size_t longestOp = (m_end - m_start); + if (longestOp > 7) + longestOp = 6; + + for (size_t i = longestOp; i > 0; --i) { + TokenType TT = LookupKeyword(StringRef(m_start, i)); + if (TT != TOK_INVALID) { + m_start += i; + return TT; + } + } + return TOK_INVALID; +} + +CobolLexer::TokenType CobolLexer::DoWord() { + const char *start = m_start; + while ((m_start < m_end) && IsLetterOrDigit(*m_start)) + m_start++; + + TokenType TT = LookupKeyword(StringRef(m_start, m_start - start)); + return (TT == TOK_INVALID) ? TOK_IDENTIFIER : TT; +} + +CobolLexer::TokenType CobolLexer::LookupKeyword(StringRef KW) { + const auto &it = m_keywords.find(KW.upper()); + if (it != m_keywords.end()) + return it->second; + return TOK_INVALID; +} + +StringRef CobolLexer::LookupToken(CobolLexer::TokenType TT) { + for (const auto &entry : m_keywords) + if (entry.getValue() == TT) + return entry.getKey(); + return ""; +} diff --git a/lldb/source/Plugins/ExpressionParser/Cobol/CobolLexer.h b/lldb/source/Plugins/ExpressionParser/Cobol/CobolLexer.h new file mode 100644 index 00000000000000..2e786a39d74808 --- /dev/null +++ b/lldb/source/Plugins/ExpressionParser/Cobol/CobolLexer.h @@ -0,0 +1,148 @@ +//===-- CobolLexer.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_CobolLexer_h +#define liblldb_CobolLexer_h + +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringRef.h" + +namespace lldb_private { + +class CobolLexer { +public: + explicit CobolLexer(const char *expr); + + enum TokenType { + KW_OF, + KW_MV, + KW_SET, + KW_TO, + KW_IF, + KW_IS, + KW_EQUALS, + KW_NOT, + LIT_INTEGER, + LIT_FLOAT, + LIT_STRING, + OP_AMP, + OP_COLON, + OP_COMMA, + OP_DOT, + OP_LPAREN, + OP_LBRACK, + OP_LBRACE, + OP_MINUS, + OP_PLUS, + OP_RPAREN, + OP_RBRACK, + OP_RBRACE, + OP_SEMICOLON, + OP_STAR, + OP_SIZEOF, + OP_EQ, + OP_COMPARE, + OP_COMP_GE, + OP_COMP_GT, + OP_COMP_LE, + OP_COMP_LT, + TOK_EOF, + TOK_INVALID, + TOK_IDENTIFIER, + }; + + struct Token { + explicit Token(TokenType TT, llvm::StringRef text) + : m_type(TT), m_text(text) {} + TokenType m_type; + llvm::StringRef m_text; + bool IsLiteral() const { + return (m_type == LIT_INTEGER) || (m_type == LIT_FLOAT) || + (m_type == LIT_STRING); + } + }; + + const Token &Lex(); + + size_t BytesLeft() const { return m_end - m_start; } + llvm::StringRef GetText(int len) const { + return llvm::StringRef(m_start, len); + } + + static TokenType LookupKeyword(llvm::StringRef KW); + static llvm::StringRef LookupToken(TokenType TT); + +private: + bool IsDigit(char c) { return c >= '0' && c <= '9'; } + bool IsHexChar(char c) { + return IsDigit(c) || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f'); + } + bool IsOperator(char c) { + switch (c) { + default: + return false; + case '&': + case '*': + case '+': + case '-': + case '[': + case ']': + case ':': + case '(': + case ')': + case '=': + case '>': + case '<': + case ',': + break; + } + return true; + } + bool IsLetterOrDigit(char c) { + if (IsDigit(c)) + return true; + if (c >= 'a' && c <= 'z') + return true; + if (c >= 'A' && c <= 'Z') + return true; + switch (c) { + default: + break; + case '_': + case '-': + return true; + } + return false; + } + bool IsWhiteSpace(char c) { return (c == ' ') || (c == '\t') || (c == '\r'); } + void SkipWhiteSpace(bool &newline) { + for (; m_start < m_end; ++m_start) { + if (*m_start == '\n') + newline = true; + if (!IsWhiteSpace(*m_start)) + break; + } + } + + TokenType DoOperator(); + TokenType DoWord(); + TokenType DoString(); + TokenType DoNumber(); + TokenType DoIdent(); + + using KeywordMap = llvm::StringMap; + static const KeywordMap m_keywords; + const char *m_start; + const char *m_end; + Token m_last_token; +}; + +} // namespace lldb_private + +#endif // liblldb_CobolLexer_h diff --git a/lldb/source/Plugins/ExpressionParser/Cobol/CobolParser.cpp b/lldb/source/Plugins/ExpressionParser/Cobol/CobolParser.cpp new file mode 100644 index 00000000000000..36aea031b22f89 --- /dev/null +++ b/lldb/source/Plugins/ExpressionParser/Cobol/CobolParser.cpp @@ -0,0 +1,265 @@ +//===-- CobolParser.cpp -----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "Plugins/ExpressionParser/Cobol/CobolParser.h" +#include "Plugins/ExpressionParser/Cobol/CobolAST.h" +#include "lldb/Utility/Status.h" + +using namespace lldb_private; +using namespace llvm; + +CobolParser::CobolParser(const char *expr) + : m_lexer(expr), m_pos(0), m_last_tok(CobolLexer::TOK_INVALID), + m_failed(false) {} + +void CobolParser::GetError(Status &error) { + if (!m_failed) + return; + + size_t rem = m_lexer.BytesLeft(); + error = Status::FromErrorStringWithFormat( + "Syntex error: expected with bytes remaining %lu.", rem); +} + +CobolASTStmt *CobolParser::Statement() { + Rule r("Statement", this); + + // TODO Add other rules + CobolASTExpr *expr = Expression(); + if (!expr) + return r.error(); + + if (auto ret = ExpressionStmt(expr)) + return ret; + return r.error(); +} + +CobolASTStmt *CobolParser::ExpressionStmt(CobolASTExpr *expr) { + Rule r("ExpressionStmt", this); + if (Semicolon()) + return new CobolASTExprStmt(expr); + return r.error(); +} + +CobolASTExpr *CobolParser::Expression() { + Rule r("Expression", this); + if (CobolASTExpr *result = UnaryExpr()) + return result; + return r.error(); +} + +CobolASTExpr *CobolParser::PrimaryExpr() { + CobolASTExpr *l = Operand(); + CobolASTExpr *r; + while ((r = Selector(l)) || (r = SelectorOf(l)) || (r = RefModifier(l)) || + (r = Assignment(l)) || (r = Compare(l))) + l = r; + return l; +} + +CobolASTExpr *CobolParser::Operand() { + CobolLexer::Token *lit; + if ((lit = match(CobolLexer::LIT_INTEGER)) || + (lit = match(CobolLexer::LIT_FLOAT)) || + (lit = match(CobolLexer::LIT_STRING))) + return new CobolASTBasicLit(*lit); + return Identifier(); +} + +CobolASTIdent *CobolParser::Identifier() { + if (auto *tok = match(CobolLexer::TOK_IDENTIFIER)) { + return new CobolASTIdent(*tok); + } + return nullptr; +} + +CobolASTExpr *CobolParser::UnaryExpr() { + switch (peek()) { + default: + return PrimaryExpr(); + case CobolLexer::OP_AMP: + case CobolLexer::OP_STAR: { + const CobolLexer::Token t = next(); + if (CobolASTExpr *expr = UnaryExpr()) { + return new CobolASTUnaryExpr(t.m_type, expr); + } + } break; + case CobolLexer::OP_SIZEOF: { + next(); // Flush operator token + if (!match(CobolLexer::OP_LPAREN)) + return nullptr; + auto func = new CobolASTFuncCallExpr( + CobolLexer::Token(CobolLexer::OP_SIZEOF, "sizeof")); + func->addParam(PrimaryExpr()); + if (!match(CobolLexer::OP_RPAREN)) + return nullptr; + return func; + } + } + return nullptr; +} + +CobolASTExpr *CobolParser::ModifySelectorASTTree(CobolASTExpr *var, + CobolASTExpr *mem) { + switch (llvm::cast(mem)->GetKind()) { + case CobolASTNode::eRefModExpr: { + auto leftSel = llvm::cast(mem); + auto lSel = ModifySelectorASTTree( + var, const_cast(leftSel->GetExpr())); + leftSel->ReplaceExpr(lSel); + return leftSel; + } + case CobolASTNode::eSelectorExpr: { + auto leftSel = llvm::cast(mem); + auto lSel = ModifySelectorASTTree( + var, const_cast(leftSel->GetExpr())); + leftSel->ReplaceExpr(lSel); + return leftSel; + } + case CobolASTNode::eIdent: { + auto iIdent = llvm::cast(mem); + return new CobolASTSelectorExpr(var, iIdent); + } + default: + break; + } + return nullptr; +} + +CobolASTExpr *CobolParser::SelectorOf(CobolASTExpr *expr) { + if (match(CobolLexer::KW_OF)) { + if (auto *e = PrimaryExpr()) { + return ModifySelectorASTTree(e, expr); + } + } + return nullptr; +} + +CobolASTExpr *CobolParser::Selector(CobolASTExpr *expr) { + if (match(CobolLexer::OP_DOT)) { + if (auto *name = Identifier()) + return new CobolASTSelectorExpr(expr, name); + } + return nullptr; +} + +CobolASTExpr *CobolParser::Indices() { + Rule r("Indices", this); + std::vector> indices_vec; + + while (true) { + indices_vec.push_back(std::unique_ptr(PrimaryExpr())); + auto next_type = peek(); + if (next_type != CobolLexer::OP_COMMA) + break; + next(); + } + + return new CobolASTIndexExpr(std::move(indices_vec)); +} + +CobolASTExpr *CobolParser::RefModifier(CobolASTExpr *expr) { + Rule r("MoveRef", this); + CobolASTExpr *start = nullptr; + CobolASTExpr *len = nullptr; + if (match(CobolLexer::OP_LPAREN)) { + start = Indices(); + CobolLexer::Token t = next(); + if (t.m_type == CobolLexer::OP_COLON) { + len = PrimaryExpr(); + t = next(); + } + if (t.m_type != CobolLexer::OP_RPAREN) + return r.error(); + } + + if (start == nullptr) + return nullptr; + + return new CobolASTRefModifierExpr(expr, start, len); +} + +CobolASTExpr *CobolParser::FuncCall(CobolASTExpr *expr) { + Rule r("funcCall", this); + if (match(CobolLexer::OP_SIZEOF)) { + if (!match(CobolLexer::OP_LPAREN)) + return r.error(); + auto func = new CobolASTFuncCallExpr( + CobolLexer::Token(CobolLexer::OP_SIZEOF, "sizeof")); + func->addParam(PrimaryExpr()); + if (!match(CobolLexer::OP_RPAREN)) + return r.error(); + return func; + } + return nullptr; +} + +CobolASTExpr *CobolParser::Compare(CobolASTExpr *expr) { + Rule r("Compare", this); + bool is_not = false; + if (match(CobolLexer::KW_IS)) { + CobolLexer::Token t = next(); + if (t.m_type == CobolLexer::KW_NOT) { + is_not = true; + t = next(); + } + + auto rhsVal = PrimaryExpr(); + switch (t.m_type) { + default: + break; + case CobolLexer::OP_COMP_GE: + case CobolLexer::OP_COMP_GT: + case CobolLexer::OP_COMP_LE: + case CobolLexer::OP_COMP_LT: + case CobolLexer::OP_EQ: + return new CobolASTCompareExpr(expr, rhsVal, t.m_type, is_not); + } + } + return nullptr; +} + +CobolASTExpr *CobolParser::Assignment(CobolASTExpr *expr) { + Rule r("Assignment", this); + if (match(CobolLexer::KW_MV)) { + auto rhsVal = PrimaryExpr(); + if (rhsVal == nullptr) + return nullptr; + if (!match(CobolLexer::KW_TO)) + return nullptr; + auto lhsRef = PrimaryExpr(); + if (lhsRef == nullptr) + return nullptr; + return new CobolASTAssignmentExpr(lhsRef, rhsVal); + } else if (match(CobolLexer::KW_SET)) { + auto lhsRef = PrimaryExpr(); + if (lhsRef == nullptr) + return nullptr; + if (!match(CobolLexer::KW_TO)) + return nullptr; + auto rhsVal = PrimaryExpr(); + if (rhsVal == nullptr) + return nullptr; + return new CobolASTAssignmentExpr(lhsRef, rhsVal); + } + return nullptr; +} + +bool CobolParser::Semicolon() { + if (match(CobolLexer::OP_SEMICOLON)) + return true; + + switch (peek()) { + default: + break; + case CobolLexer::TOK_EOF: + return true; + } + return false; +} diff --git a/lldb/source/Plugins/ExpressionParser/Cobol/CobolParser.h b/lldb/source/Plugins/ExpressionParser/Cobol/CobolParser.h new file mode 100644 index 00000000000000..4d94e9ee4ca7a3 --- /dev/null +++ b/lldb/source/Plugins/ExpressionParser/Cobol/CobolParser.h @@ -0,0 +1,110 @@ +//===-- CobolParser.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_CobolParser_h_ +#define liblldb_CobolParser_h_ + +#include "Plugins/ExpressionParser/Cobol/CobolAST.h" +#include "Plugins/ExpressionParser/Cobol/CobolLexer.h" +#include "lldb/lldb-private.h" +#include "llvm/ADT/StringRef.h" + +namespace lldb_private { + +class CobolParser { +public: + explicit CobolParser(const char *expr); + + CobolASTStmt *Statement(); + + bool Failed() const { return m_failed; } + bool AtEOF() const { + return m_lexer.BytesLeft() == 0 && m_pos == m_tokens.size(); + } + void GetError(Status &error); + +private: + class Rule { + public: + Rule(llvm::StringRef name, CobolParser *p) + : m_name(name), m_parser(p), m_pos(p->m_pos) {} + + std::nullptr_t error() { + if (!m_parser->m_failed) { + // Set m_error in case this is the top level. + if (m_parser->m_last_tok == CobolLexer::TOK_INVALID) + m_parser->m_error = + llvm::StringRef("Error with Rule " + m_name.str()); + // And set m_last in case it isn't. + m_parser->m_last_tok = CobolLexer::TOK_INVALID; + m_parser->m_pos = m_pos; + } + return nullptr; + } + + private: + llvm::StringRef m_name; + CobolParser *m_parser; + size_t m_pos; + }; + friend class Rule; + + CobolLexer::Token &next() { + if (m_pos >= m_tokens.size()) { + if (m_pos && (m_tokens.back().m_type == CobolLexer::TOK_EOF || + m_tokens.back().m_type == CobolLexer::TOK_INVALID)) + return m_tokens.back(); + + m_pos = m_tokens.size(); + m_tokens.push_back(m_lexer.Lex()); + } + return m_tokens[m_pos++]; + } + + CobolLexer::TokenType peek() { + CobolLexer::Token &tok = next(); + --m_pos; + return tok.m_type; + } + + CobolLexer::Token *match(CobolLexer::TokenType TT) { + CobolLexer::Token &tok = next(); + if (tok.m_type == TT) + return &tok; + --m_pos; + m_last_tok = TT; + return nullptr; + } + bool Semicolon(); + CobolASTIdent *Identifier(); + CobolASTStmt *ExpressionStmt(CobolASTExpr *expr); + CobolASTExpr *Expression(); + CobolASTExpr *PrimaryExpr(); + CobolASTExpr *Operand(); + CobolASTExpr *UnaryExpr(); + CobolASTExpr *ModifySelectorASTTree(CobolASTExpr *var, CobolASTExpr *mem); + CobolASTExpr *Selector(CobolASTExpr *expr); + CobolASTExpr *SelectorOf(CobolASTExpr *expr); + CobolASTExpr *RefModifier(CobolASTExpr *expr); + CobolASTExpr *FuncCall(CobolASTExpr *expr); + CobolASTExpr *Assignment(CobolASTExpr *expr); + CobolASTExpr *Compare(CobolASTExpr *expr); + CobolASTExpr *Indices(); + + CobolLexer m_lexer; + std::vector m_tokens; + size_t m_pos; + CobolLexer::TokenType m_last_tok; + llvm::StringRef m_error; + bool m_failed; +}; + +} // namespace lldb_private + +#endif // liblldb_CobolParser_h_ diff --git a/lldb/source/Plugins/ExpressionParser/Cobol/CobolUserExpression.cpp b/lldb/source/Plugins/ExpressionParser/Cobol/CobolUserExpression.cpp new file mode 100644 index 00000000000000..e73a1dc457065e --- /dev/null +++ b/lldb/source/Plugins/ExpressionParser/Cobol/CobolUserExpression.cpp @@ -0,0 +1,949 @@ +//===-- CobolUserExpression.cpp ---------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/StringRef.h" + +#include "CobolUserExpression.h" + +#include "Plugins/TypeSystem/Legacy/TypeSystemLegacy.h" +#include "lldb/Core/Module.h" +#include "lldb/Core/ValueObjectConstResult.h" +#include "lldb/Core/ValueObjectRegister.h" +#include "lldb/Expression/DiagnosticManager.h" +#include "lldb/Expression/ExpressionVariable.h" +#include "lldb/Host/StreamFile.h" +#include "lldb/Symbol/SymbolFile.h" +#include "lldb/Symbol/TypeList.h" +#include "lldb/Symbol/VariableList.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/StackFrame.h" +#include "lldb/Target/Target.h" +#include "lldb/Utility/DataBufferHeap.h" +#include "lldb/Utility/DataEncoder.h" +#include "lldb/Utility/DataExtractor.h" +#include "lldb/Utility/LLDBLog.h" +#include "lldb/Utility/Log.h" + +#include "llvm/Support/Casting.h" + +using namespace lldb_private; +using namespace lldb; + +char CobolUserExpression::ID; + + +static bool SearchCompilerTypeForMemberWithName(CompilerType *comp_type, + llvm::Twine name) { + + if (!comp_type) + return false; + + CompilerType elem_or_pointee_compiler_type; + const Flags type_flags( + comp_type->GetTypeInfo(&elem_or_pointee_compiler_type)); + if (!type_flags.Test(eTypeIsStructUnion)) + return false; + + std::vector child_indexes; + const size_t index = comp_type->GetIndexOfChildMemberWithName( + name.str().c_str(), true, child_indexes); + if (index != 0) + return true; + + //const llvm::Expected total_count = comp_type->GetNumChildren(true, nullptr); + uint32_t total_count = comp_type->GetNumChildren(true, nullptr).get(); + for (uint32_t i = 0; i < total_count; ++i) { + std::string child_name; + uint32_t child_byte_size; + int32_t child_byte_offset = 0; + uint32_t child_bitfield_bit_size; + uint32_t child_bitfield_bit_offset; + bool child_is_base_class; + bool child_is_deref_of_parent; + uint64_t language_flags; + + llvm::Expected expected_child_type = comp_type->GetChildCompilerTypeAtIndex( + nullptr, i, true, true, true, child_name, child_byte_size, + child_byte_offset, child_bitfield_bit_size, child_bitfield_bit_offset, + child_is_base_class, child_is_deref_of_parent, nullptr, language_flags); + + if (!expected_child_type) { + // Handle the error, e.g., by returning or logging it. + llvm::consumeError(expected_child_type.takeError()); + return false; // or handle accordingly + } + CompilerType child_type = *expected_child_type; // Extract the actual value safely + + if (SearchCompilerTypeForMemberWithName(&child_type, name)) + return true; + } + return false; +} + + +/// TODO: improve performance +static VariableSP SearchMemberByName(TargetSP target, llvm::Twine name) { + VariableList variable_list; + if (!target) { + return nullptr; + } + target->GetImages().FindGlobalVariables( + RegularExpression(llvm::StringRef("^.*$")), 100, variable_list); + + for (size_t i = 0; i < variable_list.GetSize(); ++i) { + VariableSP result = variable_list.GetVariableAtIndex(i); + if (!result) + continue; + + lldb::LanguageType lang = result->GetLanguage(); + if (!((lang == eLanguageTypeCobol85) || (lang == eLanguageTypeCobol74))) + variable_list.RemoveVariableAtIndex(i); + + if (!result->GetType()->IsAggregateType()) + variable_list.RemoveVariableAtIndex(i); + } + + for (size_t i = 0; i < variable_list.GetSize(); ++i) { + VariableSP result = variable_list.GetVariableAtIndex(i); + auto comp_type = result->GetType()->GetForwardCompilerType(); + + if (SearchCompilerTypeForMemberWithName(&comp_type, name)) + return result; + } + return nullptr; +} + +static VariableSP FindGlobalVariable(TargetSP target, llvm::Twine name, + bool &isMember) { + VariableList variable_list; + if (!target) { + return nullptr; + } + target->GetImages().FindGlobalVariables( + RegularExpression(llvm::StringRef("^" + name.str() + "$"), llvm::Regex::NoFlags, + true /* case-insensitive */), + 1, variable_list); + + const auto match_count = variable_list.GetSize(); + for (uint32_t i = 0; i < match_count; ++i) { + VariableSP result = variable_list.GetVariableAtIndex(i); + if (!result) + continue; + + lldb::LanguageType lang = result->GetLanguage(); + if ((lang == eLanguageTypeCobol85) || (lang == eLanguageTypeCobol74)) + return result; + } + + if (match_count > 0) + return variable_list.GetVariableAtIndex(0); + + isMember = true; + return SearchMemberByName(target, name); +} + +char CobolPersistentExpressionState::ID = 0; +CobolPersistentExpressionState::CobolPersistentExpressionState() {} + +void CobolPersistentExpressionState::RemovePersistentVariable( + lldb::ExpressionVariableSP var) { + RemoveVariable(var); +} + +ConstString +CobolPersistentExpressionState::GetNextPersistentVariableName(bool is_error) { + llvm::SmallString<64> name; + { + llvm::raw_svector_ostream os(name); + os << GetPersistentVariablePrefix(is_error) + << m_next_persistent_variable_id++; + } + return ConstString(name); +} + +CobolInterpreter::CobolInterpreter(ExecutionContext &exe_ctx, const char *expr) + : m_exe_ctx(exe_ctx), m_frame(exe_ctx.GetFrameSP()), m_parser(expr) {} + +bool CobolInterpreter::Parse() { + for (std::unique_ptr stmt(m_parser.Statement()); stmt; + stmt.reset(m_parser.Statement())) { + if (m_parser.Failed()) + break; + m_statements.emplace_back(std::move(stmt)); + } + + if (m_parser.Failed() || !m_parser.AtEOF()) + m_parser.GetError(m_error); + + return m_error.Success(); +} + +lldb::ValueObjectSP CobolInterpreter::Evaluate(ExecutionContext &exe_ctx) { + m_exe_ctx = exe_ctx; + ValueObjectSP result; + for (auto &stmt : m_statements) { + result = EvaluateStatement(stmt.get()); + if (m_error.Fail()) + return nullptr; + } + return result; +} + +lldb::ValueObjectSP +CobolInterpreter::EvaluateStatement(const lldb_private::CobolASTStmt *stmt) { + // Handle other + switch (stmt->GetKind()) { + default: + m_error = Status::FromErrorStringWithFormat("%s node not supported", + stmt->GetKindName()); + break; + case CobolASTNode::eExprStmt: + const CobolASTExprStmt *expr = llvm::cast(stmt); + return EvaluateExpr(expr->GetExpr()); + } + return nullptr; +} + +lldb::ValueObjectSP CobolInterpreter::EvaluateExpr(const CobolASTExpr *expr) { + if (expr) + return expr->Visit(this); + return ValueObjectSP(); +} + +lldb::ValueObjectSP CobolInterpreter::GetLevel88(llvm::StringRef var_name, + ValueObjectSP &result, + CompilerType comp_type, + int index = -1) { + auto target = m_exe_ctx.GetTargetSP(); + EvaluateExpressionOptions eval_options; + eval_options.SetLanguage(lldb::eLanguageTypeC); + + /* Get Parent Name from the runtime */ + auto parent_expr = "const char* arg = \"" + var_name.str() + + "\"; rc_cob_get_level88_parent(arg)"; + target->EvaluateExpression(parent_expr, + m_exe_ctx.GetBestExecutionContextScope(), result, + eval_options); + if (!result) + return ValueObjectSP(); + std::string parent_name; + result->GetValueAsCString(eFormatCString, parent_name); + /* Get truth value of level88 */ + auto value_expr = "const char* arg = \"" + var_name.str() + "\"; " + + ((index == -1) ? "rc_cob_level88(arg)" + : "rc_cob_indexed_level88(arg, " + + std::to_string(index) + ")"); + target->EvaluateExpression(value_expr, + m_exe_ctx.GetBestExecutionContextScope(), result, + eval_options); + if (!result) + return ValueObjectSP(); + auto truth_value = GetUIntFromValueObjectSPReportIndex(result, false) == 0 ? "false" : "true"; + + auto result_str = "(" + parent_name + ") " + truth_value; + llvm::StringRef result_ref(result_str); + + auto data_ptr = result_ref.data(); + auto data_length = result_ref.size(); + + auto byte_order = endian::InlHostByteOrder(); + auto addr_size = target->GetArchitecture().GetAddressByteSize(); + + DataBufferSP buffer(new DataBufferHeap(data_length, 0)); + DataEncoder enc(buffer->GetBytes(), data_length, byte_order, addr_size); + enc.PutData(/*offset */ 0, data_ptr, data_length); + DataExtractor data(enc.GetDataBuffer(), byte_order, addr_size); + + result.reset(); + result = ValueObject::CreateValueObjectFromData( + var_name, data, m_exe_ctx, + comp_type.GetBasicTypeFromAST(eBasicTypeOther)); + result->GetValue().SetValueType(Value::ValueType::Invalid); + return result; +} + +lldb::ValueObjectSP CobolInterpreter::VisitIdent(const CobolASTIdent *ident) { + ValueObjectSP result; + llvm::StringRef var_name = ident->GetName().m_text; + if (m_frame) { + VariableSP var_sp; + if (var_name[0] == '$') { + m_error.Clear(); + m_error = Status::FromErrorString("Consistent var lookup not implemented yet"); + return nullptr; + } + + VariableListSP var_list_sp(m_frame->GetInScopeVariableList(true)); + VariableList *var_list = var_list_sp.get(); + if (var_list) { + var_sp = var_list->FindVariable(ConstString(var_name), + /* include_static_members */ true, + /* case_sensitive */ false); + if (var_sp && var_sp->GetType()->GetName() != "Level88ConditionName") { + result = m_frame->GetValueObjectForFrameVariable(var_sp, m_use_dynamic); + } else if (var_sp) { + return GetLevel88(var_name, result, + var_sp->GetType()->GetFullCompilerType()); + } + } + + if (!result && var_list) { + for (size_t i = 0; i < var_list->GetSize(); i++) { + VariableSP variable_sp = var_list->GetVariableAtIndex(i); + if (!variable_sp) + continue; + + Type *var_type = variable_sp->GetType(); + if (!var_type) + continue; + + ValueObjectSP valobj_sp = + m_frame->GetValueObjectForFrameVariable(variable_sp, m_use_dynamic); + if (!valobj_sp) + return valobj_sp; + + valobj_sp = m_frame->GetValueObjectForFrameAggregateVariable( + ConstString(var_name), valobj_sp, m_use_dynamic); + if (valobj_sp) { + result = valobj_sp; + break; + } + } + } + + // search global if available + if (!result) { + TargetSP target = m_frame->CalculateTarget(); + if (!target) { + m_error.Clear(); + m_error = Status::FromErrorString("No target"); + return nullptr; + } + + bool isMember = false; + var_sp = FindGlobalVariable(target, var_name, isMember); + if (var_sp) { + ValueObjectSP valobj_sp = + m_frame->TrackGlobalVariable(var_sp, m_use_dynamic); + if (isMember) + valobj_sp = m_frame->GetValueObjectForFrameAggregateVariable( + ConstString(var_name), valobj_sp, m_use_dynamic); + return valobj_sp; + } + } + } + if (!result) + m_error = Status::FromErrorStringWithFormat("Unknown variable %s", + var_name.str().c_str()); + return result; +} + +ValueObjectSP CobolInterpreter::VisitUnaryExpr(const CobolASTUnaryExpr *expr) { + ValueObjectSP var = EvaluateExpr(expr->GetExpr()); + if (!var) + return nullptr; + + switch (expr->GetOp()) { + default: + return nullptr; + case CobolLexer::OP_AMP: + CompilerType comp_type = var->GetCompilerType().GetPointerType(); + uint64_t address = var->GetAddressOf(); + + ByteOrder byte_order = m_exe_ctx.GetByteOrder(); + DataBufferSP buffer(new DataBufferHeap(&address, sizeof(address))); + DataExtractor data(buffer, byte_order, sizeof(address)); + return ValueObject::CreateValueObjectFromData(llvm::StringRef(), data, + m_exe_ctx, comp_type); + } +} + +ValueObjectSP CobolInterpreter::VisitBasicLit(const CobolASTBasicLit *expr) { + llvm::StringRef value_string = expr->GetValue().m_text; + + lldb::BasicType base_type = eBasicTypeInvalid; + size_t data_length = 0; + int64_t iValue; + double dValue; + bool isArray = false; + size_t array_length = 0; + const void *data_ptr = nullptr; + switch (expr->GetValue().m_type) { + default: + m_error = Status::FromErrorStringWithFormat("Non-Const lexical type for %s", + value_string.str().c_str()); + return nullptr; + case CobolLexer::LIT_INTEGER: + if (value_string.front() == '+') + value_string = value_string.drop_front(1); + if (value_string.getAsInteger(0, iValue)) { + m_error = Status::FromErrorStringWithFormat("integer conversion error %s", + value_string.str().c_str()); + return nullptr; + } + data_length = sizeof(iValue); + base_type = eBasicTypeInt; + data_ptr = &iValue; + break; + case CobolLexer::LIT_FLOAT: + if (value_string.getAsDouble(dValue)) { + m_error = Status::FromErrorStringWithFormat("double conversion error %s", + value_string.str().c_str()); + return nullptr; + } + data_length = sizeof(dValue); + base_type = eBasicTypeDouble; + data_ptr = &dValue; + break; + case CobolLexer::LIT_STRING: + base_type = eBasicTypeChar; + isArray = true; + data_ptr = value_string.data(); + array_length = value_string.size(); + data_length = array_length; + break; + } + + TargetSP target = m_exe_ctx.GetTargetSP(); + if (!target) + return nullptr; + + auto type_sys = target->GetScratchTypeSystemForLanguage(eLanguageTypeCobol85); + if (!type_sys) + return nullptr; + + TypeSystemLegacy *legacy_type_system = + llvm::dyn_cast_or_null(type_sys->get()); + if (!legacy_type_system) + return nullptr; + + ByteOrder byte_order = endian::InlHostByteOrder(); + uint8_t addr_size = target->GetArchitecture().GetAddressByteSize(); + + DataBufferSP buffer(new DataBufferHeap(data_length, 0)); + DataEncoder enc(buffer->GetBytes(), data_length, byte_order, addr_size); + enc.PutData(0, data_ptr, data_length); + DataExtractor data(enc.GetDataBuffer(), byte_order, addr_size); + + CompilerType comp_type = legacy_type_system->GetBasicTypeFromAST(base_type); + if (isArray) { + static ConstString array_name("char []"); + static ConstString empty_name; + comp_type = legacy_type_system->CreateArrayType( + array_name, empty_name, comp_type, array_length, false /*isVarString*/); + } + return ValueObject::CreateValueObjectFromData(llvm::StringRef(), data, + m_exe_ctx, comp_type); +} + +ValueObjectSP +CobolInterpreter::VisitSelectorExpr(const CobolASTSelectorExpr *expr) { + ValueObjectSP target = EvaluateExpr(expr->GetExpr()); + if (target) { + if (target->GetCompilerType().IsPointerType()) { + target = target->Dereference(m_error); + if (m_error.Fail()) + return nullptr; + } + ConstString field(expr->GetSel()->GetName().m_text); + ValueObjectSP result = target->GetChildMemberWithName(field, true); + if (!result) + m_error = Status::FromErrorStringWithFormat("Unknown child %s", field.AsCString()); + return result; + } + if (const CobolASTIdent *package = + llvm::dyn_cast(expr->GetExpr())) { + bool isMember = false; + if (VariableSP global = FindGlobalVariable( + m_exe_ctx.GetTargetSP(), + package->GetName().m_text + "." + expr->GetSel()->GetName().m_text, + isMember)) { + if (m_frame) { + m_error.Clear(); + return m_frame->GetValueObjectForFrameVariable(global, m_use_dynamic); + } + } + } + if (auto ref = llvm::dyn_cast(expr->GetExpr())) { + if (auto ident = llvm::dyn_cast(ref->GetExpr())) { + auto varName = ident->GetName().m_text; + auto isMember = false; + auto target = + FindGlobalVariable(m_exe_ctx.GetTargetSP(), varName, isMember); + if (!target || !m_frame) + return nullptr; + auto targetSP = + m_frame->GetValueObjectForFrameVariable(target, m_use_dynamic); + auto indices = llvm::cast(ref->GetStartExpr()); + auto memberName = expr->GetSel()->GetName().m_text; + auto result = m_frame->GetValueObjectForFrameAggregateVariable( + ConstString(memberName), targetSP, m_use_dynamic, true); + + if (!result) { + m_error = Status::FromErrorStringWithFormat("Unknown child %s", + memberName.str().c_str()); + return nullptr; + } + + return GetIndexedExpression(result, indices, memberName); + } + } + return nullptr; +} + +// Gets an element from array where `var` is shared pointer to array type +ValueObjectSP CobolInterpreter::GetElementAtIndex(lldb::ValueObjectSP var, + uint32_t start, + uint32_t len) { + CompilerType elem_type; + uint64_t max_elem; + bool is_incomplete; + bool substring_select = !var->GetCompilerType().IsArrayType( + &elem_type, &max_elem, &is_incomplete); + DataExtractor var_data; + + if (substring_select) { + Status err; + max_elem = var->GetData(var_data, err); + } + + if ((start < 1) || (start > max_elem)) { + m_error = Status::FromErrorStringWithFormat("Out of bound index: %d.", start); + return nullptr; + } + start -= 1; // convert 1-based indexing to 0-based. + + if ((start + len) > max_elem) + len = max_elem - start; + + DataExtractor result_data; + CompilerType result_type; + if (substring_select) { + TargetSP target = m_exe_ctx.GetTargetSP(); + if (!target) + return nullptr; + + auto type_sys = + target->GetScratchTypeSystemForLanguage(eLanguageTypeCobol85); + if (!type_sys) + return nullptr; + + // FIXME: mutate type with proper size + result_type = type_sys->get()->MutateBaseTypeSize( + var->GetCompilerType().GetOpaqueQualType(), len * 8); + result_data.SetData(var_data, start, len); + } else { + uint32_t child_byte_size = 0; + int32_t child_byte_offset = 0; + uint32_t child_bitfield_bit_size = 0; + uint32_t child_bitfield_bit_offset = 0; + uint64_t ut1 = 0; + bool bt1 = false; + bool bt2 = false; + std::string empty_str; + + if (!(var->GetCompilerType().GetChildCompilerTypeAtIndex( + &m_exe_ctx, 0, true, true, false, empty_str, child_byte_size, + child_byte_offset, child_bitfield_bit_size, + child_bitfield_bit_offset, bt1, bt2, var.get(), ut1))) + return nullptr; + + const uint64_t offset = start * child_byte_size; + AddressType address_type = eAddressTypeInvalid; + auto addr = var->GetAddressOf(true, &address_type); + result_type = len == 1 ? elem_type : elem_type.GetArrayType(len); + return ValueObject::CreateValueObjectFromAddress( + llvm::StringRef(), addr + offset, m_exe_ctx, result_type); + } + return ValueObject::CreateValueObjectFromData(llvm::StringRef(), result_data, + m_exe_ctx, result_type); +} + +ValueObjectListSP CobolInterpreter::FindAllCandidates(ConstString var_name) { + ValueObjectListSP candidates(new ValueObjectList); + + VariableListSP var_list_sp(m_frame->GetInScopeVariableList(true)); + VariableList *var_list = var_list_sp.get(); + + if (var_list) { + for (size_t i = 0; i < var_list->GetSize(); i++) { + VariableSP variable_sp = var_list->GetVariableAtIndex(i); + if (!variable_sp) + continue; + + Type *var_type = variable_sp->GetType(); + if (!var_type) + continue; + + ValueObjectSP valobj_sp = + m_frame->GetValueObjectForFrameVariable(variable_sp, m_use_dynamic); + if (!valobj_sp) + continue; + + valobj_sp = m_frame->GetValueObjectForFrameAggregateVariable( + var_name, valobj_sp, m_use_dynamic, true); + if (valobj_sp) { + candidates->Append(valobj_sp); + } + } + } + + return candidates; +} + +/* +result: Shared pointer to a value corresponding to element with all indices 1. +indices: Index expression +var_name: Name of the field +*/ +ValueObjectSP CobolInterpreter::GetIndexedExpression( + lldb::ValueObjectSP result, const lldb_private::CobolASTIndexExpr *indices, + llvm::StringRef var_name) { + for (size_t i = 0; i < indices->GetNumberOfIndices(); ++i) { + auto index = + GetUIntFromValueObjectSP(EvaluateExpr(indices->GetIndices()[i].get())); + if (m_error.Fail()) { + result = nullptr; + break; + } + + auto level = indices->GetNumberOfIndices() - i; + auto top_level_parent = + result->GetParent()->FollowParentChain([&level](ValueObject *par) { + if (par->GetCompilerType().IsArrayType()) + level--; + return (level != 0); + }); + + if (!top_level_parent) { + result = nullptr; + break; + } + + result = GetElementAtIndex(top_level_parent->GetSP(), index); + if (!result) + break; + + result = m_frame->GetValueObjectForFrameAggregateVariable( + ConstString(var_name), result, m_use_dynamic, true); + } + return result; +} + +ValueObjectSP +CobolInterpreter::FindFieldInStructArray(const CobolASTRefModifierExpr *expr) { + auto ident = llvm::cast(expr->GetExpr()); + auto indices = llvm::cast(expr->GetStartExpr()); + + llvm::StringRef var_name = ident->GetName().m_text; + + auto candidates_sp = FindAllCandidates(ConstString(var_name)); + + if (candidates_sp->GetSize() == 0) { + m_error = Status::FromErrorStringWithFormat("Unknown variable %s", + var_name.str().c_str()); + return nullptr; + } + + for (auto result : candidates_sp->GetObjects()) { + m_error.Clear(); + result = GetIndexedExpression(result, indices, var_name); + if (result) + return result; + } + + return nullptr; +} + +uint32_t CobolInterpreter::GetUIntFromValueObjectSP(ValueObjectSP var) { + return this->GetUIntFromValueObjectSPReportIndex(var, true); +} + +uint32_t CobolInterpreter::GetUIntFromValueObjectSPReportIndex(ValueObjectSP var, bool reportIndex) { + uint32_t index; + llvm::StringRef index_string(var->GetValueAsCString()); + if (index_string.getAsInteger(10, index)) { + m_error = Status::FromErrorStringWithFormat("ref modifier invalid index %s", + reportIndex? index_string.str().c_str(): ""); + return 0; + } + return index; +} + +ValueObjectSP +CobolInterpreter::VisitRefModExpr(const CobolASTRefModifierExpr *expr) { + auto index_expr = llvm::cast(expr->GetStartExpr()); + switch (expr->GetExpr()->GetKind()) { + case CobolASTNode::eIdent: { + auto ident = llvm::cast(expr->GetExpr()); + VariableListSP var_list_sp(m_frame->GetInScopeVariableList(true)); + VariableList *var_list = var_list_sp.get(); + if (var_list) { + auto var_name = ident->GetName().m_text; + auto var_sp = var_list->FindVariable(ConstString(var_name), true, false); + if (var_sp && var_sp->GetType()->GetName() == "Level88ConditionName") { + if (index_expr->GetNumberOfIndices() > 1) { + Host::SystemLog(lldb::eSeverityWarning, + "More than one index for level88 is not supported yet"); + return ValueObjectSP(); + } + auto indices = + llvm::cast(expr->GetStartExpr()); + int index = GetUIntFromValueObjectSP( + EvaluateExpr(indices->GetIndices()[0].get())); + auto result = ValueObjectSP(); + return GetLevel88(var_name, result, + var_sp->GetType()->GetFullCompilerType(), index); + } + } + if (ValueObjectSP var = EvaluateExpr(expr->GetExpr())) { + auto start_var = EvaluateExpr(index_expr->GetIndices()[0].get()); + auto start = GetUIntFromValueObjectSP(start_var); + if (m_error.Fail()) + return nullptr; + auto len_var = EvaluateExpr(expr->GetLenExpr()); + uint32_t len; + if (len_var) { + len = GetUIntFromValueObjectSP(len_var); + if (m_error.Fail()) + return nullptr; + return GetElementAtIndex(var, start, len); + } + return GetElementAtIndex(var, start); + } + return FindFieldInStructArray(expr); + } + + case CobolASTNode::eSelectorExpr: { + auto selector = llvm::cast(expr->GetExpr()); + auto target = EvaluateExpr(selector->GetExpr()); + if (!target) + return nullptr; + auto memberName = selector->GetSel()->GetName().m_text; + auto result = m_frame->GetValueObjectForFrameAggregateVariable( + ConstString(memberName), target, m_use_dynamic, true); + return GetIndexedExpression( + result, llvm::cast(expr->GetStartExpr()), + memberName); + } + default: + return nullptr; + } +} + +ValueObjectSP +CobolInterpreter::VisitFuncCallExpr(const CobolASTFuncCallExpr *expr) { + llvm::StringRef funcName = expr->GetFuncName().m_text; + // if (!funcName.equals(llvm::StringRef("sizeof"))) + if (funcName == (llvm::StringRef("sizeof"))) + // TODO + return nullptr; + + if (expr->getTotalNumParams() != 1) { + m_error = Status::FromErrorString("wrong number of params for sizeof operator."); + return nullptr; + } + + ValueObjectSP param = EvaluateExpr(expr->getParamAtIndex(0)); + if (!param) + return nullptr; + + auto data_size = param->GetByteSize().value(); + DataBufferSP buffer(new DataBufferHeap(sizeof(data_size), 0)); + TargetSP target = m_exe_ctx.GetTargetSP(); + if (!target) + return nullptr; + + auto type_sys = target->GetScratchTypeSystemForLanguage(eLanguageTypeCobol85); + if (!type_sys) + return nullptr; + + ByteOrder byte_order = target->GetArchitecture().GetByteOrder(); + uint8_t addr_size = target->GetArchitecture().GetAddressByteSize(); + DataEncoder enc(buffer->GetBytes(), sizeof(data_size), byte_order, addr_size); + enc.PutData(0, &data_size, sizeof(data_size)); + DataExtractor data(enc.GetDataBuffer(), byte_order, addr_size); + + CompilerType comp_type = + type_sys->get()->GetBasicTypeFromAST(eBasicTypeUnsignedInt); + return ValueObject::CreateValueObjectFromData(llvm::StringRef(), data, + m_exe_ctx, comp_type); +} + +ValueObjectSP +CobolInterpreter::VisitCompareExpr(const CobolASTCompareExpr *expr) { + Value valF(Scalar(0)); + ValueObjectSP ValFalse = ValueObjectConstResult::Create( + m_exe_ctx.GetBestExecutionContextScope(), valF, ConstString("")); + TargetSP target = m_exe_ctx.GetTargetSP(); + if (!target) + return ValFalse; + + auto type_sys = target->GetScratchTypeSystemForLanguage(eLanguageTypeCobol85); + if (!type_sys) + return ValFalse; + + TypeSystemLegacy *legacy_ts = + llvm::dyn_cast_or_null(type_sys->get()); + if (!legacy_ts) + return ValFalse; + + Value valT(Scalar(UINT8_MAX)); + ValueObjectSP ValTrue = ValueObjectConstResult::Create( + m_exe_ctx.GetBestExecutionContextScope(), valT, ConstString("")); + ValueObjectSP lhsVal = EvaluateExpr(expr->GetlhsExpr()); + ValueObjectSP rhsVal = EvaluateExpr(expr->GetrhsExpr()); + + DataExtractor lData, rData; + Status error; + lhsVal->GetData(lData, error); + rhsVal->GetData(rData, error); + auto lhsCompTy = lhsVal->GetCompilerType(); + auto rhsCompTy = rhsVal->GetCompilerType(); + if (lhsCompTy == rhsCompTy) { + if (lData.Compare(rData)) + return ValTrue; + } + return ValFalse; +} + +ValueObjectSP +CobolInterpreter::VisitAssignmentExpr(const CobolASTAssignmentExpr *expr) { + ValueObjectSP lhsRef = EvaluateExpr(expr->GetlhsExpr()); + if (!lhsRef) + return nullptr; + + ValueObjectSP rhsVal = EvaluateExpr(expr->GetrhsExpr()); + if (!rhsVal) + return nullptr; + + DataExtractor data; + Status error; + rhsVal->GetData(data, error); + + if (error.Fail()) + return nullptr; + + TargetSP target = m_exe_ctx.GetTargetSP(); + if (!target) + return nullptr; + + auto type_sys = target->GetScratchTypeSystemForLanguage(eLanguageTypeCobol85); + if (!type_sys) + return nullptr; + + TypeSystemLegacy *legacy_ts = + llvm::dyn_cast_or_null(type_sys->get()); + if (!legacy_ts) + return nullptr; + + const uint8_t addr_size = target->GetArchitecture().GetAddressByteSize(); + const auto dst_type = lhsRef->GetCompilerType().GetOpaqueQualType(); + const auto src_type = rhsVal->GetCompilerType().GetOpaqueQualType(); + const auto data_size = lhsRef->GetByteSize(); + DataBufferSP buffer(new DataBufferHeap(*data_size, 0)); + DataExtractor dest_data(buffer, ByteOrder::eByteOrderInvalid, addr_size); + if (!legacy_ts->EncodeDataToType(m_exe_ctx, src_type, data, dst_type, + dest_data)) + return nullptr; + + lhsRef->SetData(dest_data, error); + return lhsRef; +} + +CobolUserExpression::CobolUserExpression( + ExecutionContextScope &exe_scope, llvm::StringRef expr, + llvm::StringRef prefix, SourceLanguage language, + ResultType desired_type, const EvaluateExpressionOptions &options) + : UserExpression(exe_scope, expr, prefix, language, desired_type, options) { +} + +bool CobolUserExpression::Parse(DiagnosticManager &diagnostic_manager, + ExecutionContext &exe_ctx, + ExecutionPolicy execution_policy, + bool keep_result_in_memory, + bool generate_debug_info) { + Log *log = GetLog(LLDBLog::Expressions); + InstallContext(exe_ctx); + m_interpreter.reset(new CobolInterpreter(exe_ctx, GetUserText())); + if (m_interpreter->Parse()) + return true; + + LLDB_LOGF(log, "error while parsing the following code:%s\n", GetUserText()); + diagnostic_manager.Printf(lldb::eSeverityError, + "cobol expression can't be interpreted"); + return false; +} + +lldb::ExpressionResults +CobolUserExpression::DoExecute(DiagnosticManager &diagnostic_manager, + ExecutionContext &exe_ctx, + const EvaluateExpressionOptions &options, + lldb::UserExpressionSP &shared_ptr_to_me, + lldb::ExpressionVariableSP &result) { + + Log *log = GetLog(LLDBLog::Expressions); + + lldb_private::ExecutionPolicy execution_policy = options.GetExecutionPolicy(); + lldb::ExpressionResults execution_results = lldb::eExpressionSetupError; + + Process *process = exe_ctx.GetProcessPtr(); + Target *target = exe_ctx.GetTargetPtr(); + + if (target == nullptr || process == nullptr || + process->GetState() != lldb::eStateStopped) { + if (execution_policy == eExecutionPolicyAlways) { + if (log) + log->Printf( + "== [CobolUserExpression::Evaluate] Expression may not run, " + "but is not constant =="); + + diagnostic_manager.PutString(lldb::eSeverityError, + "expression needed to run but couldn't"); + + return execution_results; + } + } + + SourceLanguage language = target->GetLanguage(); + + m_interpreter->set_use_dynamic(options.GetUseDynamic()); + ValueObjectSP result_val_sp = m_interpreter->Evaluate(exe_ctx); + Status err = std::move(m_interpreter->error()); + m_interpreter.reset(); + + if (!result_val_sp) { + const char *error_cstr = err.AsCString(); + if (error_cstr && error_cstr[0]) { + diagnostic_manager.PutString(lldb::eSeverityError, error_cstr); + if (log) + LLDB_LOGF(log, "expression interpretation error: %s\n.", error_cstr); + } else { + diagnostic_manager.PutString(lldb::eSeverityError, + "expression can't be interpreted or run"); + if (log) + LLDB_LOGF(log, "expression interpretation Unknown error\n."); + } + return lldb::eExpressionDiscarded; + } + + result_val_sp->UpdateValueIfNeeded(); + result.reset(new ExpressionVariable()); + result->m_live_sp = result->m_frozen_sp = result_val_sp; + result->m_flags |= ExpressionVariable::EVIsProgramReference; + PersistentExpressionState *pv = + target->GetPersistentExpressionStateForLanguage( + language.AsLanguageType()); + if (pv != nullptr) { + if (result_val_sp->GetName().IsEmpty()) + result->SetName(pv->GetNextPersistentVariableName()); + pv->AddVariable(result); + } + return lldb::eExpressionCompleted; +} diff --git a/lldb/source/Plugins/ExpressionParser/Cobol/CobolUserExpression.h b/lldb/source/Plugins/ExpressionParser/Cobol/CobolUserExpression.h new file mode 100644 index 00000000000000..5dafb69692427a --- /dev/null +++ b/lldb/source/Plugins/ExpressionParser/Cobol/CobolUserExpression.h @@ -0,0 +1,140 @@ +//===- CobolUserExpression.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_CobolUserExpression_h_ +#define liblldb_CobolUserExpression_h_ + +#include "lldb/Expression/ExpressionVariable.h" +#include "lldb/Expression/UserExpression.h" +#include "lldb/Target/ExecutionContext.h" +#include "lldb/Utility/Status.h" +#include "lldb/lldb-forward.h" +#include "lldb/lldb-private.h" + +#include "Plugins/ExpressionParser/Cobol/CobolAST.h" +#include "Plugins/ExpressionParser/Cobol/CobolParser.h" +#include + +namespace lldb_private { +/// TODO - not used yet. +class CobolPersistentExpressionState + : public llvm::RTTIExtends { +public: + // LLVM RTTI support + static char ID; + CobolPersistentExpressionState(); + + void RemovePersistentVariable(lldb::ExpressionVariableSP variable) override; + + ConstString GetNextPersistentVariableName(bool is_error = false) override; + +protected: + llvm::StringRef + GetPersistentVariablePrefix(bool is_error = false) const override { + return "$Cobol"; + } + +private: + uint32_t m_next_persistent_variable_id = 0; +}; + +class CobolInterpreter { +public: + CobolInterpreter(ExecutionContext &exe_ctx, const char *expr); + + bool Parse(); + lldb::ValueObjectSP Evaluate(ExecutionContext &exe_ctx); + lldb::ValueObjectSP EvaluateStatement(const lldb_private::CobolASTStmt *s); + lldb::ValueObjectSP EvaluateExpr(const lldb_private::CobolASTExpr *e); + + lldb::ValueObjectSP VisitBasicLit(const lldb_private::CobolASTBasicLit *e); + lldb::ValueObjectSP VisitIdent(const lldb_private::CobolASTIdent *e); + lldb::ValueObjectSP VisitUnaryExpr(const lldb_private::CobolASTUnaryExpr *e); + lldb::ValueObjectSP + VisitSelectorExpr(const lldb_private::CobolASTSelectorExpr *e); + lldb::ValueObjectSP + VisitRefModExpr(const lldb_private::CobolASTRefModifierExpr *expr); + lldb::ValueObjectSP + VisitFuncCallExpr(const lldb_private::CobolASTFuncCallExpr *expr); + lldb::ValueObjectSP + VisitAssignmentExpr(const lldb_private::CobolASTAssignmentExpr *expr); + lldb::ValueObjectSP + VisitCompareExpr(const lldb_private::CobolASTCompareExpr *expr); + + void set_use_dynamic(lldb::DynamicValueType use_dynamic) { + m_use_dynamic = use_dynamic; + } + + Status &error() { return m_error; } + +private: + ExecutionContext m_exe_ctx; + lldb::StackFrameSP m_frame; + Status m_error; + lldb::DynamicValueType m_use_dynamic; + CobolParser m_parser; + std::vector> m_statements; + lldb::ValueObjectSP + FindFieldInStructArray(const lldb_private::CobolASTRefModifierExpr *expr); + lldb::ValueObjectSP GetElementAtIndex(lldb::ValueObjectSP var, uint32_t start, + uint32_t len = 1); + uint32_t GetUIntFromValueObjectSP(lldb::ValueObjectSP var); + uint32_t GetUIntFromValueObjectSPReportIndex(lldb::ValueObjectSP var, bool reportIndex); + lldb::ValueObjectListSP FindAllCandidates(ConstString var_name); + lldb::ValueObjectSP + GetIndexedExpression(lldb::ValueObjectSP result, + const lldb_private::CobolASTIndexExpr *indices, + llvm::StringRef var_name); + lldb::ValueObjectSP GetLevel88(llvm::StringRef var_name, + lldb::ValueObjectSP &result, CompilerType comp_type, int index); +}; + +class CobolUserExpression : public UserExpression { + // LLVM RTTI support + static char ID; + +public: + bool isA(const void *ClassID) const override { + return ClassID == &ID || UserExpression::isA(ClassID); + } + static bool classof(const Expression *obj) { return obj->isA(&ID); } + + CobolUserExpression(ExecutionContextScope &exe_scope, llvm::StringRef expr, + llvm::StringRef prefix, SourceLanguage language, + ResultType desired_type, + const EvaluateExpressionOptions &options); + + bool Parse(DiagnosticManager &diagnostic_manager, ExecutionContext &exe_ctx, + lldb_private::ExecutionPolicy execution_policy, + bool keep_result_in_memory, bool generate_debug_info) override; + + bool CanInterpret() override { return true; } + bool FinalizeJITExecution( + DiagnosticManager &diagnostic_manager, ExecutionContext &exe_ctx, + lldb::ExpressionVariableSP &result, + lldb::addr_t function_stack_bottom = LLDB_INVALID_ADDRESS, + lldb::addr_t function_stack_top = LLDB_INVALID_ADDRESS) override { + return true; + } + +protected: + lldb::ExpressionResults + DoExecute(DiagnosticManager &diagnostic_manager, ExecutionContext &exe_ctx, + const EvaluateExpressionOptions &options, + lldb::UserExpressionSP &shared_ptr_to_me, + lldb::ExpressionVariableSP &result) override; + +private: + std::unique_ptr m_interpreter; +}; + +} // namespace lldb_private + +#endif // liblldb_CobolUserExpression_h_ diff --git a/lldb/source/Plugins/ExpressionParser/PLI/CMakeLists.txt b/lldb/source/Plugins/ExpressionParser/PLI/CMakeLists.txt new file mode 100644 index 00000000000000..bf790cbf85fb2a --- /dev/null +++ b/lldb/source/Plugins/ExpressionParser/PLI/CMakeLists.txt @@ -0,0 +1,13 @@ +add_lldb_library(lldbPluginExpressionParserPLI + PLILexer.cpp + PLIParser.cpp + PLIUserExpression.cpp + + LINK_LIBS + lldbCore + lldbExpression + lldbSymbol + lldbTarget + LINK_COMPONENTS + Support + ) diff --git a/lldb/source/Plugins/ExpressionParser/PLI/PLIAST.h b/lldb/source/Plugins/ExpressionParser/PLI/PLIAST.h new file mode 100644 index 00000000000000..6e38c7ac03e64c --- /dev/null +++ b/lldb/source/Plugins/ExpressionParser/PLI/PLIAST.h @@ -0,0 +1,320 @@ +//===-- PLIAST.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_PLIAST_h +#define liblldb_PLIAST_h + +#include "Plugins/ExpressionParser/PLI/PLILexer.h" +#include "lldb/lldb-forward.h" +#include "lldb/lldb-private.h" +#include "llvm/Support/Casting.h" + +namespace lldb_private { + +class PLIASTNode { +public: + enum NodeKind { + eBasicLit, + eUnaryExpr, + eEmptyStmt, + eExprStmt, + eIdent, + eRefModExpr, + eSelectorExpr, + eFuncCallExpr, + eAssignmentExpr, + }; + + virtual ~PLIASTNode() = default; + virtual const char *GetKindName() const = 0; + NodeKind GetKind() const { return m_kind; } + +protected: + explicit PLIASTNode(NodeKind kind) : m_kind(kind) {} + +private: + const NodeKind m_kind; + + PLIASTNode(const PLIASTNode &) = delete; + const PLIASTNode &operator=(const PLIASTNode &) = delete; +}; + +class PLIASTExpr : public PLIASTNode { +public: + template R Visit(V *v) const; + + static bool classof(const PLIASTNode *node) { + return node->GetKind() == eIdent; + } + +protected: + explicit PLIASTExpr(NodeKind kind) : PLIASTNode(kind) {} + +private: + PLIASTExpr(const PLIASTExpr &) = delete; + const PLIASTExpr &operator=(const PLIASTExpr &) = delete; +}; + +class PLIASTIdent : public PLIASTExpr { +public: + explicit PLIASTIdent(PLILexer::Token name) + : PLIASTExpr(eIdent), m_name(name) {} + ~PLIASTIdent() override = default; + + const char *GetKindName() const override { return "Identifier"; } + static bool classof(const PLIASTNode *node) { + return node->GetKind() == eIdent; + } + PLILexer::Token GetName() const { return m_name; } + void SetName(PLILexer::Token name) { m_name = name; } + +private: + friend class PLIASTNode; + PLILexer::Token m_name; + PLIASTIdent(const PLIASTIdent &) = delete; + const PLIASTIdent &operator=(const PLIASTIdent &) = delete; +}; + +class PLIASTStmt : public PLIASTNode { +public: + template R Visit(V *v) const; + static bool classof(const PLIASTNode *node) { + return node->GetKind() == eEmptyStmt; + } + +protected: + explicit PLIASTStmt(NodeKind kind) : PLIASTNode(kind) {} + +private: + PLIASTStmt(const PLIASTStmt &) = delete; + const PLIASTNode &operator=(const PLIASTNode &) = delete; +}; + +class PLIASTEmptyStmt : public PLIASTStmt { +public: + PLIASTEmptyStmt() : PLIASTStmt(eEmptyStmt) {} + ~PLIASTEmptyStmt() override = default; + + const char *GetKindName() const override { return "Empty Statement"; } + static bool classof(const PLIASTNode *node) { + return node->GetKind() == eEmptyStmt; + } + + PLIASTEmptyStmt(const PLIASTEmptyStmt &) = delete; + const PLIASTEmptyStmt &operator=(const PLIASTEmptyStmt &) = delete; +}; + +class PLIASTExprStmt : public PLIASTStmt { +public: + explicit PLIASTExprStmt(PLIASTExpr *expr) + : PLIASTStmt(eExprStmt), m_expr(expr) {} + ~PLIASTExprStmt() override = default; + + const char *GetKindName() const override { return "Expr Statement"; } + static bool classof(const PLIASTNode *n) { return n->GetKind() == eExprStmt; } + const PLIASTExpr *GetExpr() const { return m_expr.get(); } + void SetExpr(PLIASTExpr *expr) { m_expr.reset(expr); } + +private: + friend class PLIASTNode; + std::unique_ptr m_expr; + PLIASTExprStmt(const PLIASTExprStmt &) = delete; + const PLIASTExprStmt &operator=(const PLIASTExprStmt &) = delete; +}; + +class PLIASTBasicLit : public PLIASTExpr { +public: + explicit PLIASTBasicLit(PLILexer::Token T) + : PLIASTExpr(eBasicLit), m_value(T) {} + ~PLIASTBasicLit() override = default; + + const char *GetKindName() const override { return "Basic Literal"; } + static bool classof(const PLIASTNode *node) { + return node->GetKind() == eBasicLit; + } + + PLILexer::Token GetValue() const { return m_value; } + void SetValue(PLILexer::Token T) { m_value = T; } + +private: + friend class PLIASTNode; + PLILexer::Token m_value; + + PLIASTBasicLit(const PLIASTBasicLit &) = delete; + const PLIASTBasicLit &operator=(const PLIASTBasicLit &) = delete; +}; + +class PLIASTUnaryExpr : public PLIASTExpr { +public: + PLIASTUnaryExpr(PLILexer::PLILexer::TokenType tok, PLIASTExpr *expr) + : PLIASTExpr(eUnaryExpr), m_tt(tok), m_expr(expr) {} + ~PLIASTUnaryExpr() override = default; + + const char *GetKindName() const override { return "Unary Expression"; } + static bool classof(const PLIASTNode *node) { + return node->GetKind() == eUnaryExpr; + } + + PLILexer::PLILexer::TokenType GetOp() const { return m_tt; } + void SetOp(PLILexer::PLILexer::TokenType tt) { m_tt = tt; } + + const PLIASTExpr *GetExpr() const { return m_expr.get(); } + void Setexpr(PLIASTExpr *expr) { m_expr.reset(expr); } + +private: + friend class PLIASTNode; + PLILexer::PLILexer::TokenType m_tt; + std::unique_ptr m_expr; + + PLIASTUnaryExpr(const PLIASTUnaryExpr &) = delete; + const PLIASTUnaryExpr &operator=(const PLIASTUnaryExpr &) = delete; +}; + +class PLIASTSelectorExpr : public PLIASTExpr { +public: + PLIASTSelectorExpr(PLIASTExpr *expr, PLIASTIdent *sel) + : PLIASTExpr(eSelectorExpr), m_expr_up(expr), m_sel_up(sel) {} + ~PLIASTSelectorExpr() override = default; + + const char *GetKindName() const override { return "Selector Expression"; } + + static bool classof(const PLIASTNode *n) { + return n->GetKind() == eSelectorExpr; + } + + const PLIASTExpr *GetExpr() const { return m_expr_up.get(); } + void SetExpr(PLIASTExpr *expr) { m_expr_up.reset(expr); } + + const PLIASTIdent *GetSel() const { return m_sel_up.get(); } + void SetSel(PLIASTIdent *sel) { m_sel_up.reset(sel); } + +private: + friend class PLIASTNode; + std::unique_ptr m_expr_up; + std::unique_ptr m_sel_up; + + PLIASTSelectorExpr(const PLIASTSelectorExpr &) = delete; + const PLIASTSelectorExpr &operator=(const PLIASTSelectorExpr &) = delete; +}; + +class PLIASTRefModifierExpr : public PLIASTExpr { +public: + PLIASTRefModifierExpr(PLIASTExpr *expr, PLIASTExpr *start, PLIASTExpr *len) + : PLIASTExpr(eRefModExpr), m_expr(expr), m_expr_start(start), + m_expr_len(len) {} + ~PLIASTRefModifierExpr() override = default; + + static bool classof(const PLIASTNode *n) { + return n->GetKind() == eRefModExpr; + } + + const PLIASTExpr *GetExpr() const { return m_expr.get(); } + void SetExpr(PLIASTExpr *expr) { m_expr.reset(expr); } + + const PLIASTExpr *GetStartExpr() const { return m_expr_start.get(); } + void SetStartExpr(PLIASTExpr *expr) { m_expr_start.reset(expr); } + + const PLIASTExpr *GetLenExpr() const { return m_expr_len.get(); } + void SetLenExpr(PLIASTExpr *expr) { m_expr_len.reset(expr); } + + const char *GetKindName() const override { + return "reference modifier Expression"; + } + +private: + std::unique_ptr m_expr; + std::unique_ptr m_expr_start; + std::unique_ptr m_expr_len; + + PLIASTRefModifierExpr(const PLIASTRefModifierExpr &) = delete; + const PLIASTRefModifierExpr & + operator=(const PLIASTRefModifierExpr &) = delete; +}; + +class PLIASTFuncCallExpr : public PLIASTExpr { +public: + PLIASTFuncCallExpr(PLILexer::Token funcName) + : PLIASTExpr(eFuncCallExpr), funcName(funcName) {} + + static bool classof(const PLIASTNode *n) { + return n->GetKind() == eFuncCallExpr; + } + + PLILexer::Token GetFuncName() const { return funcName; } + const PLIASTExpr *getParamAtIndex(size_t index) const { + if (index < paramList.size()) + return paramList[index]; + return nullptr; + } + + void addParam(PLIASTExpr *param) { paramList.push_back(param); } + + const char *GetKindName() const override { + return "function call expression"; + } + + size_t getTotalNumParams() const { return paramList.size(); } + +private: + std::vector paramList; + PLILexer::Token funcName; + + PLIASTFuncCallExpr(const PLIASTFuncCallExpr &) = delete; + const PLIASTFuncCallExpr &operator=(const PLIASTFuncCallExpr &) = delete; +}; + +class PLIASTAssignmentExpr : public PLIASTExpr { +public: + PLIASTAssignmentExpr(PLIASTExpr *lhs, PLIASTExpr *rhs) + : PLIASTExpr(eAssignmentExpr), m_lhsExpr(lhs), m_rhsExpr(rhs) {} + + static bool classof(const PLIASTNode *n) { + return n->GetKind() == eAssignmentExpr; + } + + const PLIASTExpr *GetlhsExpr() const { return m_lhsExpr.get(); } + void SetlhsExpr(PLIASTExpr *expr) { m_lhsExpr.reset(expr); } + + const PLIASTExpr *GetrhsExpr() const { return m_rhsExpr.get(); } + void SetrhsExpr(PLIASTExpr *expr) { m_rhsExpr.reset(expr); } + + const char *GetKindName() const override { return "assignment expression"; } + +private: + std::unique_ptr m_lhsExpr; + std::unique_ptr m_rhsExpr; + + PLIASTAssignmentExpr(const PLIASTAssignmentExpr &) = delete; + const PLIASTAssignmentExpr &operator=(const PLIASTAssignmentExpr &) = delete; +}; + +template R PLIASTExpr::Visit(V *v) const { + switch (GetKind()) { + default: + return R(); + case eBasicLit: + return v->VisitBasicLit(llvm::cast(this)); + case eIdent: + return v->VisitIdent(llvm::cast(this)); + case eUnaryExpr: + return v->VisitUnaryExpr(llvm::cast(this)); + case eSelectorExpr: + return v->VisitSelectorExpr(llvm::cast(this)); + case eRefModExpr: + return v->VisitRefModExpr(llvm::cast(this)); + case eFuncCallExpr: + return v->VisitFuncCallExpr(llvm::cast(this)); + case eAssignmentExpr: + return v->VisitAssignmentExpr(llvm::cast(this)); + } +} + +} // namespace lldb_private + +#endif // liblldb_PLIAST_h diff --git a/lldb/source/Plugins/ExpressionParser/PLI/PLILexer.cpp b/lldb/source/Plugins/ExpressionParser/PLI/PLILexer.cpp new file mode 100644 index 00000000000000..d7f8c0a72163af --- /dev/null +++ b/lldb/source/Plugins/ExpressionParser/PLI/PLILexer.cpp @@ -0,0 +1,212 @@ +//===-- PLILexer.cpp ------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include + +#include "PLILexer.h" + +using namespace lldb_private; +using namespace llvm; + +const PLILexer::KeywordMap PLILexer::m_keywords = { + {"&", OP_AMP}, {":", OP_COLON}, {"(", OP_LPAREN}, + {"[", OP_LBRACK}, {"{", OP_LBRACE}, {")", OP_RPAREN}, + {"]", OP_RBRACK}, {"}", OP_RBRACE}, {"*", OP_STAR}, + {"+", OP_PLUS}, {"-", OP_MINUS}, {".", OP_DOT}, + {"OF", KW_OF}, {"STG", OP_SIZEOF}, {"STORAGE", OP_SIZEOF}, + {"=", OP_EQ}, {">", OP_GT}, {"<", OP_LT}, {">=", OP_GE}, + {"<=", OP_LE}, {"~", OP_NOT}, {"^", OP_NOT}, {"<>", OP_NE}}; + +PLILexer::PLILexer(const char *expr) + : m_start(expr), m_end(expr + strlen(expr)), m_last_token(TOK_INVALID, "") { +} + +const PLILexer::Token &PLILexer::Lex() { + bool newline = false; + SkipWhiteSpace(newline); + + if (m_start >= m_end) { + m_last_token.m_text = llvm::StringRef(""); + m_last_token.m_type = TOK_EOF; + return m_last_token; + } + + const char *start = m_start; + PLILexer::TokenType lastTok = m_last_token.m_type; + m_last_token.m_type = TOK_INVALID; + size_t offset = 0; + if (newline) { + switch (lastTok) { + default: + m_start++; + start++; + break; + case TOK_IDENTIFIER: + case LIT_FLOAT: + case LIT_INTEGER: + case LIT_STRING: + m_last_token.m_text = llvm::StringRef(""); + m_last_token.m_type = OP_SEMICOLON; + return m_last_token; + } + } + + if (IsDigit(*m_start)) + m_last_token.m_type = DoNumber(); + else if (*m_start == '-' && IsDigit(m_start[1])) + m_last_token.m_type = DoNumber(); + else if (*m_start == '+' && IsDigit(m_start[1])) + m_last_token.m_type = DoNumber(); + else if (IsOperator(*m_start)) + m_last_token.m_type = DoOperator(); + else { + switch (*m_start) { + // persistant variables + case '$': + default: { + if (IsLetterOrDigit(*m_start)) + m_last_token.m_type = DoIdent(); + } break; + case '.': { + if (IsDigit(m_start[1])) + m_last_token.m_type = DoNumber(); + else + m_last_token.m_type = DoOperator(); + } break; + case '"': + case '`': + m_last_token.m_type = DoString(); + // skip quotes + start++; + offset = 1; + break; + } + } + size_t length = m_start - start; + if (length) + length -= offset; + m_last_token.m_text = llvm::StringRef(start, length); + return m_last_token; +} + +PLILexer::TokenType PLILexer::DoString() { + if (*m_start == '`') { + while (++m_start < m_end) { + if (*m_start == '`') + ++m_start; + return LIT_STRING; + } + return TOK_INVALID; + } + + while (++m_start < m_end) { + switch (*m_start) { + // We already have matched openning double quotation + case '"': + ++m_start; + return LIT_STRING; + case '\n': + return TOK_INVALID; + case '\\': + if (m_start[1] == '\n') + return TOK_INVALID; + m_start++; + } + } + return TOK_INVALID; +} + +PLILexer::TokenType PLILexer::DoNumber() { + if (m_start[0] == '0' && (m_start[1] == 'x' || m_start[1] == 'X')) { + m_start += 2; + while (IsHexChar(*m_start)) + m_start++; + return LIT_INTEGER; + } + + if (m_start[0] == '+' || m_start[0] == '-') { + m_start++; + } + + bool dot_ok = true; + bool e_ok = true; + while (true) { + while (IsDigit(*m_start)) + ++m_start; + switch (*m_start) { + case '.': + if (!dot_ok) + return LIT_FLOAT; + ++m_start; + dot_ok = false; + break; + case 'e': + case 'E': + if (!e_ok) + return LIT_FLOAT; + dot_ok = e_ok = false; + ++m_start; + if (*m_start == '+' || *m_start == '-') + ++m_start; + break; + default: + if (dot_ok) + return LIT_INTEGER; + return LIT_FLOAT; + } + } +} + +PLILexer::TokenType PLILexer::DoIdent() { + const char *start = m_start++; + while (m_start < m_end && IsLetterOrDigit(*m_start)) + ++m_start; + TokenType kw = LookupKeyword(llvm::StringRef(start, m_start - start)); + if (kw != TOK_INVALID) + return kw; + return TOK_IDENTIFIER; +} + +PLILexer::TokenType PLILexer::DoOperator() { + size_t longestOp = (m_end - m_start); + if (longestOp > 8) + longestOp = 7; + + for (size_t i = longestOp; i > 0; --i) { + TokenType TT = LookupKeyword(StringRef(m_start, i)); + if (TT != TOK_INVALID) { + m_start += i; + return TT; + } + } + return TOK_INVALID; +} + +PLILexer::TokenType PLILexer::DoWord() { + const char *start = m_start; + while ((m_start < m_end) && IsLetterOrDigit(*m_start)) + m_start++; + + TokenType TT = LookupKeyword(StringRef(m_start, m_start - start)); + return (TT == TOK_INVALID) ? TOK_IDENTIFIER : TT; +} + +PLILexer::TokenType PLILexer::LookupKeyword(StringRef KW) { + const auto &it = m_keywords.find(KW.upper()); + if (it != m_keywords.end()) + return it->second; + return TOK_INVALID; +} + +StringRef PLILexer::LookupToken(PLILexer::TokenType TT) { + for (const auto &entry : m_keywords) + if (entry.getValue() == TT) + return entry.getKey(); + return ""; +} diff --git a/lldb/source/Plugins/ExpressionParser/PLI/PLILexer.h b/lldb/source/Plugins/ExpressionParser/PLI/PLILexer.h new file mode 100644 index 00000000000000..f67d1f93a97ffd --- /dev/null +++ b/lldb/source/Plugins/ExpressionParser/PLI/PLILexer.h @@ -0,0 +1,142 @@ +//===-- PLILexer.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_PLILexer_h +#define liblldb_PLILexer_h + +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringRef.h" + +namespace lldb_private { + +class PLILexer { +public: + explicit PLILexer(const char *expr); + + enum TokenType { + KW_OF, + LIT_INTEGER, + LIT_FLOAT, + LIT_STRING, + OP_AMP, + OP_COLON, + OP_DOT, + OP_EQ, + OP_GE, + OP_GT, + OP_LPAREN, + OP_LBRACK, + OP_LBRACE, + OP_LE, + OP_LT, + OP_MINUS, + OP_NE, + OP_NOT, + OP_PLUS, + OP_RPAREN, + OP_RBRACK, + OP_RBRACE, + OP_SEMICOLON, + OP_STAR, + OP_SIZEOF, + TOK_EOF, + TOK_INVALID, + TOK_IDENTIFIER, + }; + + struct Token { + explicit Token(TokenType TT, llvm::StringRef text) + : m_type(TT), m_text(text) {} + TokenType m_type; + llvm::StringRef m_text; + bool IsLiteral() const { + return (m_type == LIT_INTEGER) || (m_type == LIT_FLOAT) || + (m_type == LIT_STRING); + } + }; + + const Token &Lex(); + + size_t BytesLeft() const { return m_end - m_start; } + llvm::StringRef GetText(int len) const { + return llvm::StringRef(m_start, len); + } + + static TokenType LookupKeyword(llvm::StringRef KW); + static llvm::StringRef LookupToken(TokenType TT); + +private: + bool IsDigit(char c) { return c >= '0' && c <= '9'; } + bool IsHexChar(char c) { + return IsDigit(c) || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f'); + } + bool IsOperator(char c) { + switch (c) { + default: + return false; + case '&': + case '*': + case '+': + case '-': + case '[': + case ']': + case ':': + case '(': + case ')': + case '=': + case '>': + case '<': + case '~': + case '^': + break; + } + return true; + } + bool IsLetterOrDigit(char c) { + if (IsDigit(c)) + return true; + if (c >= 'a' && c <= 'z') + return true; + if (c >= 'A' && c <= 'Z') + return true; + switch (c) { + default: + break; + case '_': + case '-': + return true; + } + return false; + } + bool IsWhiteSpace(char c) { return (c == ' ') || (c == '\t') || (c == '\r'); } + void SkipWhiteSpace(bool &newline) { + for (; m_start < m_end; ++m_start) { + if (*m_start == '\n') + newline = true; + if (!IsWhiteSpace(*m_start)) + break; + } + } + + TokenType DoOperator(); + TokenType DoWord(); + TokenType DoString(); + TokenType DoNumber(); + TokenType DoIdent(); + + using KeywordMap = llvm::StringMap; + static const KeywordMap m_keywords; + const char *m_start; + const char *m_end; + Token m_last_token; +}; + +} // namespace lldb_private + +#endif // liblldb_PLILexer_h diff --git a/lldb/source/Plugins/ExpressionParser/PLI/PLIParser.cpp b/lldb/source/Plugins/ExpressionParser/PLI/PLIParser.cpp new file mode 100644 index 00000000000000..2c7f4778e52735 --- /dev/null +++ b/lldb/source/Plugins/ExpressionParser/PLI/PLIParser.cpp @@ -0,0 +1,182 @@ +//===-- PLIParser.cpp -----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "Plugins/ExpressionParser/PLI/PLIParser.h" +#include "Plugins/ExpressionParser/PLI/PLIAST.h" +#include "lldb/Utility/Status.h" + +using namespace lldb_private; +using namespace llvm; + +PLIParser::PLIParser(const char *expr) + : m_lexer(expr), m_pos(0), m_last_tok(PLILexer::TOK_INVALID), + m_failed(false) {} + +void PLIParser::GetError(Status &error) { + if (!m_failed) + return; + + size_t rem = m_lexer.BytesLeft(); + error = Status::FromErrorStringWithFormat( + "Syntex error: expected with bytes remaining %lu.", rem); +} + +PLIASTStmt *PLIParser::Statement() { + Rule r("Statement", this); + + // TODO Add other rules + PLIASTExpr *expr = Expression(); + if (!expr) + return r.error(); + + if (auto ret = ExpressionStmt(expr)) + return ret; + return r.error(); +} + +PLIASTStmt *PLIParser::ExpressionStmt(PLIASTExpr *expr) { + Rule r("ExpressionStmt", this); + if (Semicolon()) + return new PLIASTExprStmt(expr); + return r.error(); +} + +PLIASTExpr *PLIParser::Expression() { + Rule r("Expression", this); + if (PLIASTExpr *result = UnaryExpr()) + return result; + return r.error(); +} + +PLIASTExpr *PLIParser::PrimaryExpr() { + PLIASTExpr *l = Operand(); + PLIASTExpr *r; + while ((r = Selector(l)) || (r = SelectorOf(l)) || (r = RefModifier(l)) || + (r = Assignment(l))) + l = r; + return l; +} + +PLIASTExpr *PLIParser::Operand() { + PLILexer::Token *lit; + if ((lit = match(PLILexer::LIT_INTEGER)) || + (lit = match(PLILexer::LIT_FLOAT)) || (lit = match(PLILexer::LIT_STRING))) + return new PLIASTBasicLit(*lit); + return Identifier(); +} + +PLIASTIdent *PLIParser::Identifier() { + if (auto *tok = match(PLILexer::TOK_IDENTIFIER)) + return new PLIASTIdent(*tok); + return nullptr; +} + +PLIASTExpr *PLIParser::UnaryExpr() { + switch (peek()) { + default: + return PrimaryExpr(); + case PLILexer::OP_AMP: + case PLILexer::OP_STAR: { + const PLILexer::Token t = next(); + if (PLIASTExpr *expr = UnaryExpr()) { + return new PLIASTUnaryExpr(t.m_type, expr); + } + } break; + case PLILexer::OP_SIZEOF: { + next(); // Flush operator token + if (!match(PLILexer::OP_LPAREN)) + return nullptr; + auto func = + new PLIASTFuncCallExpr(PLILexer::Token(PLILexer::OP_SIZEOF, "sizeof")); + func->addParam(PrimaryExpr()); + if (!match(PLILexer::OP_RPAREN)) + return nullptr; + return func; + } + } + return nullptr; +} + +PLIASTExpr *PLIParser::SelectorOf(PLIASTExpr *expr) { + if (match(PLILexer::KW_OF)) { + if (auto *e = PrimaryExpr()) { + auto sel = llvm::cast(expr); + return new PLIASTSelectorExpr(e, sel); + } + } + return nullptr; +} + +PLIASTExpr *PLIParser::Selector(PLIASTExpr *expr) { + if (match(PLILexer::OP_DOT)) { + if (auto *name = Identifier()) + return new PLIASTSelectorExpr(expr, name); + } + return nullptr; +} + +PLIASTExpr *PLIParser::RefModifier(PLIASTExpr *expr) { + Rule r("MoveRef", this); + PLIASTExpr *start = nullptr; + PLIASTExpr *len = nullptr; + if (match(PLILexer::OP_LPAREN)) { + start = PrimaryExpr(); + PLILexer::Token t = next(); + if (t.m_type == PLILexer::OP_COLON) { + len = PrimaryExpr(); + t = next(); + } + if (t.m_type != PLILexer::OP_RPAREN) + return r.error(); + } + + if (start == nullptr) + return nullptr; + + return new PLIASTRefModifierExpr(expr, start, len); +} + +PLIASTExpr *PLIParser::FuncCall(PLIASTExpr *expr) { + Rule r("funcCall", this); + if (match(PLILexer::OP_SIZEOF)) { + if (!match(PLILexer::OP_LPAREN)) + return r.error(); + auto func = + new PLIASTFuncCallExpr(PLILexer::Token(PLILexer::OP_SIZEOF, "sizeof")); + func->addParam(PrimaryExpr()); + if (!match(PLILexer::OP_RPAREN)) + return r.error(); + return func; + } + return nullptr; +} + +PLIASTExpr *PLIParser::Assignment(PLIASTExpr *expr) { + Rule r("assignment", this); + if (match(PLILexer::OP_EQ)) { + PLIASTExpr *rhsVal = PrimaryExpr(); + if (!rhsVal) + return nullptr; + return new PLIASTAssignmentExpr(expr, rhsVal); + } + return nullptr; +} + +bool PLIParser::Semicolon() { + if (match(PLILexer::OP_SEMICOLON)) + return true; + + switch (peek()) { + default: + break; + case PLILexer::TOK_EOF: + return true; + } + return false; +} diff --git a/lldb/source/Plugins/ExpressionParser/PLI/PLIParser.h b/lldb/source/Plugins/ExpressionParser/PLI/PLIParser.h new file mode 100644 index 00000000000000..79a99294805c4e --- /dev/null +++ b/lldb/source/Plugins/ExpressionParser/PLI/PLIParser.h @@ -0,0 +1,105 @@ +//===-- PLIParser.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_PLIParser_h_ +#define liblldb_PLIParser_h_ + +#include "Plugins/ExpressionParser/PLI/PLIAST.h" +#include "Plugins/ExpressionParser/PLI/PLILexer.h" +#include "lldb/lldb-private.h" +#include "llvm/ADT/StringRef.h" + +namespace lldb_private { + +class PLIParser { +public: + explicit PLIParser(const char *expr); + + PLIASTStmt *Statement(); + + bool Failed() const { return m_failed; } + bool AtEOF() const { + return m_lexer.BytesLeft() == 0 && m_pos == m_tokens.size(); + } + void GetError(Status &error); + +private: + class Rule { + public: + Rule(llvm::StringRef name, PLIParser *p) + : m_name(name), m_parser(p), m_pos(p->m_pos) {} + + std::nullptr_t error() { + if (!m_parser->m_failed) { + // Set m_error in case this is the top level. + if (m_parser->m_last_tok == PLILexer::TOK_INVALID) + // And set m_last in case it isn't. + m_parser->m_last_tok = PLILexer::TOK_INVALID; + m_parser->m_pos = m_pos; + } + return nullptr; + } + + private: + llvm::StringRef m_name; + PLIParser *m_parser; + size_t m_pos; + }; + friend class Rule; + + PLILexer::Token &next() { + if (m_pos >= m_tokens.size()) { + if (m_pos && (m_tokens.back().m_type == PLILexer::TOK_EOF || + m_tokens.back().m_type == PLILexer::TOK_INVALID)) + return m_tokens.back(); + + m_pos = m_tokens.size(); + m_tokens.push_back(m_lexer.Lex()); + } + return m_tokens[m_pos++]; + } + + PLILexer::TokenType peek() { + PLILexer::Token &tok = next(); + --m_pos; + return tok.m_type; + } + + PLILexer::Token *match(PLILexer::TokenType TT) { + PLILexer::Token &tok = next(); + if (tok.m_type == TT) + return &tok; + --m_pos; + m_last_tok = TT; + return nullptr; + } + bool Semicolon(); + PLIASTIdent *Identifier(); + PLIASTStmt *ExpressionStmt(PLIASTExpr *expr); + PLIASTExpr *Expression(); + PLIASTExpr *PrimaryExpr(); + PLIASTExpr *Operand(); + PLIASTExpr *UnaryExpr(); + PLIASTExpr *Selector(PLIASTExpr *expr); + PLIASTExpr *SelectorOf(PLIASTExpr *expr); + PLIASTExpr *RefModifier(PLIASTExpr *expr); + PLIASTExpr *FuncCall(PLIASTExpr *expr); + PLIASTExpr *Assignment(PLIASTExpr *expr); + + PLILexer m_lexer; + std::vector m_tokens; + size_t m_pos; + PLILexer::TokenType m_last_tok; + llvm::StringRef m_error; + bool m_failed; +}; + +} // namespace lldb_private + +#endif // liblldb_PLIParser_h_ diff --git a/lldb/source/Plugins/ExpressionParser/PLI/PLIUserExpression.cpp b/lldb/source/Plugins/ExpressionParser/PLI/PLIUserExpression.cpp new file mode 100644 index 00000000000000..3a5e14b35cb88c --- /dev/null +++ b/lldb/source/Plugins/ExpressionParser/PLI/PLIUserExpression.cpp @@ -0,0 +1,670 @@ +//===-- PLIUserExpression.cpp ---------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/StringRef.h" + +#include "PLIUserExpression.h" + +#include "Plugins/TypeSystem/Legacy/TypeSystemLegacy.h" +#include "lldb/Core/Module.h" +#include "lldb/Core/ValueObjectConstResult.h" +#include "lldb/Core/ValueObjectRegister.h" +#include "lldb/Expression/DiagnosticManager.h" +#include "lldb/Expression/ExpressionVariable.h" +#include "lldb/Host/StreamFile.h" +#include "lldb/Symbol/SymbolFile.h" +#include "lldb/Symbol/TypeList.h" +#include "lldb/Symbol/VariableList.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/StackFrame.h" +#include "lldb/Target/Target.h" +#include "lldb/Utility/DataBufferHeap.h" +#include "lldb/Utility/DataEncoder.h" +#include "lldb/Utility/DataExtractor.h" +#include "lldb/Utility/LLDBLog.h" +#include "lldb/Utility/Log.h" + +using namespace lldb_private; +using namespace lldb; + +char PLIUserExpression::ID; + +static bool SearchCompilerTypeForMemberWithName(CompilerType *comp_type, + llvm::Twine name) { + + if (!comp_type) + return false; + + CompilerType elem_or_pointee_compiler_type; + const Flags type_flags( + comp_type->GetTypeInfo(&elem_or_pointee_compiler_type)); + if (!type_flags.Test(eTypeIsStructUnion)) + return false; + + std::vector child_indexes; + const size_t index = comp_type->GetIndexOfChildMemberWithName( + name.str().c_str(), true, child_indexes); + if (index != 0) + return true; + + uint32_t total_count = comp_type->GetNumChildren(true, nullptr).get(); + for (uint32_t i = 0; i < total_count; ++i) { + std::string child_name; + uint32_t child_byte_size; + int32_t child_byte_offset = 0; + uint32_t child_bitfield_bit_size; + uint32_t child_bitfield_bit_offset; + bool child_is_base_class; + bool child_is_deref_of_parent; + uint64_t language_flags; + + llvm::Expected expected_child_type = comp_type->GetChildCompilerTypeAtIndex( + nullptr, i, true, true, true, child_name, child_byte_size, + child_byte_offset, child_bitfield_bit_size, child_bitfield_bit_offset, + child_is_base_class, child_is_deref_of_parent, nullptr, language_flags); + + if (!expected_child_type) { + // Handle the error, e.g., by returning or logging it. + llvm::consumeError(expected_child_type.takeError()); + return false; // or handle accordingly + } + CompilerType child_type = *expected_child_type; // Extract the actual value safely + + if (SearchCompilerTypeForMemberWithName(&child_type, name)) + return true; + } + return false; +} + +/// TODO: improve performance +static VariableSP SearchMemberByName(TargetSP target, llvm::Twine name) { + VariableList variable_list; + if (!target) { + return nullptr; + } + target->GetImages().FindGlobalVariables( + RegularExpression(llvm::StringRef("^.*$")), 100, variable_list); + + for (size_t i = 0; i < variable_list.GetSize(); ++i) { + VariableSP result = variable_list.GetVariableAtIndex(i); + if (!result) + continue; + + lldb::LanguageType lang = result->GetLanguage(); + if (lang != eLanguageTypePLI) + variable_list.RemoveVariableAtIndex(i); + + if (!result->GetType()->IsAggregateType()) + variable_list.RemoveVariableAtIndex(i); + } + + for (size_t i = 0; i < variable_list.GetSize(); ++i) { + VariableSP result = variable_list.GetVariableAtIndex(i); + auto comp_type = result->GetType()->GetForwardCompilerType(); + + if (SearchCompilerTypeForMemberWithName(&comp_type, name)) + return result; + } + return nullptr; +} + +static VariableSP FindGlobalVariable(TargetSP target, llvm::Twine name, + bool &isMember) { + VariableList variable_list; + if (!target) { + return nullptr; + } + target->GetImages().FindGlobalVariables( + RegularExpression(llvm::StringRef("^" + name.str() + "$"), llvm::Regex::NoFlags, + true /* case-insensitive */), + 1, variable_list); + + const auto match_count = variable_list.GetSize(); + for (uint32_t i = 0; i < match_count; ++i) { + VariableSP result = variable_list.GetVariableAtIndex(i); + if (!result) + continue; + + lldb::LanguageType lang = result->GetLanguage(); + if (lang == eLanguageTypePLI) + return result; + } + + if (match_count > 0) + return variable_list.GetVariableAtIndex(0); + + isMember = true; + return SearchMemberByName(target, name); +} + +char PLIPersistentExpressionState::ID = 0; +PLIPersistentExpressionState::PLIPersistentExpressionState() {} + +void PLIPersistentExpressionState::RemovePersistentVariable( + lldb::ExpressionVariableSP var) { + RemoveVariable(var); +} + +ConstString +PLIPersistentExpressionState::GetNextPersistentVariableName(bool is_error) { + llvm::SmallString<64> name; + { + llvm::raw_svector_ostream os(name); + os << GetPersistentVariablePrefix(is_error) + << m_next_persistent_variable_id++; + } + return ConstString(name); +} + +PLIInterpreter::PLIInterpreter(ExecutionContext &exe_ctx, const char *expr) + : m_exe_ctx(exe_ctx), m_frame(exe_ctx.GetFrameSP()), m_parser(expr) {} + +bool PLIInterpreter::Parse() { + for (std::unique_ptr stmt(m_parser.Statement()); stmt; + stmt.reset(m_parser.Statement())) { + if (m_parser.Failed()) + break; + m_statements.emplace_back(std::move(stmt)); + } + + if (m_parser.Failed() || !m_parser.AtEOF()) + m_parser.GetError(m_error); + + return m_error.Success(); +} + +lldb::ValueObjectSP PLIInterpreter::Evaluate(ExecutionContext &exe_ctx) { + m_exe_ctx = exe_ctx; + ValueObjectSP result; + for (auto &stmt : m_statements) { + result = EvaluateStatement(stmt.get()); + if (m_error.Fail()) + return nullptr; + } + return result; +} + +lldb::ValueObjectSP +PLIInterpreter::EvaluateStatement(const lldb_private::PLIASTStmt *stmt) { + // Handle other + switch (stmt->GetKind()) { + default: + m_error = Status::FromErrorStringWithFormat("%s node not supported", + stmt->GetKindName()); + break; + case PLIASTNode::eExprStmt: + const PLIASTExprStmt *expr = llvm::cast(stmt); + return EvaluateExpr(expr->GetExpr()); + } + return nullptr; +} + +lldb::ValueObjectSP PLIInterpreter::EvaluateExpr(const PLIASTExpr *expr) { + if (expr) + return expr->Visit(this); + return ValueObjectSP(); +} + +lldb::ValueObjectSP PLIInterpreter::VisitIdent(const PLIASTIdent *ident) { + ValueObjectSP result; + llvm::StringRef var_name = ident->GetName().m_text; + if (m_frame) { + VariableSP var_sp; + if (var_name[0] == '$') { + m_error.Clear(); + m_error = Status::FromErrorString("Consistent var lookup not implemented yet"); + return nullptr; + } + + VariableListSP var_list_sp(m_frame->GetInScopeVariableList(true)); + VariableList *var_list = var_list_sp.get(); + if (var_list) { + var_sp = var_list->FindVariable(ConstString(var_name), + /* include_static_members */ true, + /* case_sensitive */ false); + if (var_sp) { + result = m_frame->GetValueObjectForFrameVariable(var_sp, m_use_dynamic); + } + } + + if (!result && var_list) { + for (size_t i = 0; i < var_list->GetSize(); i++) { + VariableSP variable_sp = var_list->GetVariableAtIndex(i); + if (!variable_sp) + continue; + + Type *var_type = variable_sp->GetType(); + if (!var_type) + continue; + + ValueObjectSP valobj_sp = + m_frame->GetValueObjectForFrameVariable(variable_sp, m_use_dynamic); + if (!valobj_sp) + return valobj_sp; + + valobj_sp = m_frame->GetValueObjectForFrameAggregateVariable( + ConstString(var_name), valobj_sp, m_use_dynamic); + if (valobj_sp) { + result = valobj_sp; + break; + } + } + } + + // search global if available + if (!result) { + TargetSP target = m_frame->CalculateTarget(); + if (!target) { + m_error.Clear(); + m_error = Status::FromErrorString("No target"); + return nullptr; + } + + bool isMember = false; + var_sp = FindGlobalVariable(target, var_name, isMember); + if (var_sp) { + ValueObjectSP valobj_sp = + m_frame->TrackGlobalVariable(var_sp, m_use_dynamic); + if (isMember) + valobj_sp = m_frame->GetValueObjectForFrameAggregateVariable( + ConstString(var_name), valobj_sp, m_use_dynamic); + return valobj_sp; + } + } + } + if (!result) + m_error = Status::FromErrorStringWithFormat("Unknown variable %s", + var_name.str().c_str()); + return result; +} + +ValueObjectSP PLIInterpreter::VisitUnaryExpr(const PLIASTUnaryExpr *expr) { + ValueObjectSP var = EvaluateExpr(expr->GetExpr()); + if (!var) + return nullptr; + + switch (expr->GetOp()) { + default: + return nullptr; + case PLILexer::OP_AMP: + CompilerType comp_type = var->GetCompilerType().GetPointerType(); + uint64_t address = var->GetAddressOf(); + + ByteOrder byte_order = m_exe_ctx.GetByteOrder(); + DataBufferSP buffer(new DataBufferHeap(&address, sizeof(address))); + DataExtractor data(buffer, byte_order, sizeof(address)); + return ValueObject::CreateValueObjectFromData(llvm::StringRef(), data, + m_exe_ctx, comp_type); + } +} + +ValueObjectSP PLIInterpreter::VisitBasicLit(const PLIASTBasicLit *expr) { + llvm::StringRef value_string = expr->GetValue().m_text; + + lldb::BasicType base_type = eBasicTypeInvalid; + size_t data_length = 0; + int64_t iValue; + double dValue; + bool isArray = false; + size_t array_length = 0; + const void *data_ptr = nullptr; + switch (expr->GetValue().m_type) { + default: + m_error = Status::FromErrorStringWithFormat("Non-Const lexical type for %s", + value_string.str().c_str()); + return nullptr; + case PLILexer::LIT_INTEGER: + if (value_string.front() == '+') + value_string = value_string.drop_front(1); + if (value_string.getAsInteger(0, iValue)) { + m_error = Status::FromErrorStringWithFormat("integer conversion error %s", + value_string.str().c_str()); + return nullptr; + } + data_length = sizeof(iValue); + base_type = eBasicTypeUnsignedInt; + data_ptr = &iValue; + break; + case PLILexer::LIT_FLOAT: + if (value_string.getAsDouble(dValue)) { + m_error = Status::FromErrorStringWithFormat("double conversion error %s", + value_string.str().c_str()); + return nullptr; + } + data_length = sizeof(dValue); + base_type = eBasicTypeDouble; + data_ptr = &dValue; + break; + case PLILexer::LIT_STRING: + base_type = eBasicTypeChar; + isArray = true; + data_ptr = value_string.data(); + array_length = value_string.size(); + data_length = array_length; + break; + } + + TargetSP target = m_exe_ctx.GetTargetSP(); + if (!target) + return nullptr; + + auto type_sys = target->GetScratchTypeSystemForLanguage(eLanguageTypePLI); + if (!type_sys) + return nullptr; + + TypeSystemLegacy *legacy_type_system = + llvm::dyn_cast_or_null(type_sys->get()); + if (!legacy_type_system) + return nullptr; + + ByteOrder byte_order = endian::InlHostByteOrder(); + uint8_t addr_size = target->GetArchitecture().GetAddressByteSize(); + + DataBufferSP buffer(new DataBufferHeap(data_length, 0)); + DataEncoder enc(buffer->GetBytes(), data_length, byte_order, addr_size); + enc.PutData(0, data_ptr, data_length); + DataExtractor data(enc.GetDataBuffer(), byte_order, addr_size); + + CompilerType comp_type = legacy_type_system->GetBasicTypeFromAST(base_type); + if (isArray) { + static ConstString array_name("char []"); + static ConstString empty_name; + comp_type = legacy_type_system->CreateArrayType( + array_name, empty_name, comp_type, array_length, false /*isVarString*/); + } + return ValueObject::CreateValueObjectFromData(llvm::StringRef(), data, + m_exe_ctx, comp_type); +} + +ValueObjectSP +PLIInterpreter::VisitSelectorExpr(const PLIASTSelectorExpr *expr) { + ValueObjectSP target = EvaluateExpr(expr->GetExpr()); + if (target) { + if (target->GetCompilerType().IsPointerType()) { + target = target->Dereference(m_error); + if (m_error.Fail()) + return nullptr; + } + ConstString field(expr->GetSel()->GetName().m_text); + ValueObjectSP result = target->GetChildMemberWithName(field, true); + if (!result) + m_error = Status::FromErrorStringWithFormat("Unknown child %s", field.AsCString()); + return result; + } + if (const PLIASTIdent *package = + llvm::dyn_cast(expr->GetExpr())) { + bool isMember = false; + if (VariableSP global = FindGlobalVariable( + m_exe_ctx.GetTargetSP(), + package->GetName().m_text + "." + expr->GetSel()->GetName().m_text, + isMember)) { + if (m_frame) { + m_error.Clear(); + return m_frame->GetValueObjectForFrameVariable(global, m_use_dynamic); + } + } + } + return nullptr; +} + +ValueObjectSP +PLIInterpreter::VisitRefModExpr(const PLIASTRefModifierExpr *expr) { + ValueObjectSP var = EvaluateExpr(expr->GetExpr()); + if (!var) { + m_error = Status::FromErrorString("variable not found."); + return nullptr; + } + + CompilerType elem_type; + uint64_t max_elem; + bool is_incomplete; + + if (!var->GetCompilerType().IsArrayType(&elem_type, &max_elem, + &is_incomplete)) { + m_error = Status::FromErrorStringWithFormat("variable %s is not an array.", + var->GetName().AsCString()); + return nullptr; + } + + const bool is_bit_type = (elem_type.GetTypeName() == "BIT"); + + ValueObjectSP start_var = EvaluateExpr(expr->GetStartExpr()); + if (!start_var) { + m_error = Status::FromErrorString("ref modifier invalid indexes."); + return nullptr; + } + + uint32_t start; + uint8_t bit_pos; + llvm::StringRef index_string(start_var->GetValueAsCString()); + if (index_string.getAsInteger(10, start)) { + m_error = Status::FromErrorStringWithFormat("ref modifier invalid index %s.", + index_string.str().c_str()); + return nullptr; + } + + start -= 1; // convert 1-based indexing to 0-based. + if (is_bit_type) { + bit_pos = 7 - (start % 8); + start /= 8; + } + + if (start >= max_elem) { + m_error = Status::FromErrorStringWithFormat("out of bound index: %d.", start + 1); + return nullptr; + } + + ValueObjectSP len_var = EvaluateExpr(expr->GetLenExpr()); + if (!len_var) { + ValueObjectSP member = var->GetChildAtIndex(start, true); + + // This just an array element select + return is_bit_type + ? member->GetSyntheticBitFieldChild(bit_pos, bit_pos, true) + : member; + } + + uint32_t len; + llvm::StringRef len_string(len_var->GetValueAsCString()); + if (len_string.getAsInteger(10, len)) { + m_error = Status::FromErrorStringWithFormat("ref modifier invalid index %s.", + len_string.str().c_str()); + return nullptr; + } + + if ((start + len) > max_elem) + len = max_elem - start; + + uint32_t child_byte_size = 0; + int32_t child_byte_offset = 0; + uint32_t child_bitfield_bit_size = 0; + uint32_t child_bitfield_bit_offset = 0; + uint64_t ut1 = 0; + bool bt1 = false; + bool bt2 = false; + std::string empty_str; + + if (!(var->GetCompilerType().GetChildCompilerTypeAtIndex( + &m_exe_ctx, 0, true, true, false, empty_str, child_byte_size, + child_byte_offset, child_bitfield_bit_size, child_bitfield_bit_offset, + bt1, bt2, var.get(), ut1))) + return nullptr; + + const uint64_t offset = start * child_byte_size; + AddressType address_type = eAddressTypeInvalid; + auto addr = var->GetAddressOf(true, &address_type); + CompilerType result_type = len == 1 ? elem_type : elem_type.GetArrayType(len); + return ValueObject::CreateValueObjectFromAddress( + llvm::StringRef(), addr + offset, m_exe_ctx, result_type); +} + +ValueObjectSP +PLIInterpreter::VisitFuncCallExpr(const PLIASTFuncCallExpr *expr) { + llvm::StringRef funcName = expr->GetFuncName().m_text; + if (funcName == (llvm::StringRef("sizeof"))) + // TODO + return nullptr; + + if (expr->getTotalNumParams() != 1) { + m_error = Status::FromErrorString("wrong number of params for sizeof operator."); + return nullptr; + } + + ValueObjectSP param = EvaluateExpr(expr->getParamAtIndex(0)); + if (!param) + return nullptr; + + auto data_size = param->GetByteSize().value(); + DataBufferSP buffer(new DataBufferHeap(sizeof(data_size), 0)); + TargetSP target = m_exe_ctx.GetTargetSP(); + if (!target) + return nullptr; + + auto type_sys = target->GetScratchTypeSystemForLanguage(eLanguageTypePLI); + if (!type_sys) + return nullptr; + + ByteOrder byte_order = target->GetArchitecture().GetByteOrder(); + uint8_t addr_size = target->GetArchitecture().GetAddressByteSize(); + DataEncoder enc(buffer->GetBytes(), sizeof(data_size), byte_order, addr_size); + enc.PutData(0, &data_size, sizeof(data_size)); + DataExtractor data(enc.GetDataBuffer(), byte_order, addr_size); + + CompilerType comp_type = type_sys->get()->GetBasicTypeFromAST(eBasicTypeUnsignedInt); + return ValueObject::CreateValueObjectFromData(llvm::StringRef(), data, + m_exe_ctx, comp_type); +} + +ValueObjectSP +PLIInterpreter::VisitAssignmentExpr(const PLIASTAssignmentExpr *expr) { + ValueObjectSP lhsRef = EvaluateExpr(expr->GetlhsExpr()); + if (!lhsRef) + return nullptr; + + ValueObjectSP rhsVal = EvaluateExpr(expr->GetrhsExpr()); + if (!rhsVal) + return nullptr; + + DataExtractor data; + Status error; + rhsVal->GetData(data, error); + + if (error.Fail()) + return nullptr; + + TargetSP target = m_exe_ctx.GetTargetSP(); + if (!target) + return nullptr; + + auto type_sys = target->GetScratchTypeSystemForLanguage(eLanguageTypePLI); + if (!type_sys) + return nullptr; + + TypeSystemLegacy *legacy_ts = + llvm::dyn_cast_or_null(type_sys->get()); + if (!legacy_ts) + return nullptr; + + const uint8_t addr_size = target->GetArchitecture().GetAddressByteSize(); + const auto dst_type = lhsRef->GetCompilerType().GetOpaqueQualType(); + const auto src_type = rhsVal->GetCompilerType().GetOpaqueQualType(); + const auto data_size = lhsRef->GetByteSize(); + DataBufferSP buffer(new DataBufferHeap(*data_size, 0)); + DataExtractor dest_data(buffer, ByteOrder::eByteOrderBig, addr_size); + if (!legacy_ts->EncodeDataToType(m_exe_ctx, src_type, data, dst_type, + dest_data, eLanguageTypePLI)) + return nullptr; + + lhsRef->SetData(dest_data, error); + return lhsRef; +} + +PLIUserExpression::PLIUserExpression(ExecutionContextScope &exe_scope, + llvm::StringRef expr, + llvm::StringRef prefix, + SourceLanguage language, + ResultType desired_type, + const EvaluateExpressionOptions &options) + : UserExpression(exe_scope, expr, prefix, language, desired_type, options) { +} + +bool PLIUserExpression::Parse(DiagnosticManager &diagnostic_manager, + ExecutionContext &exe_ctx, + ExecutionPolicy execution_policy, + bool keep_result_in_memory, + bool generate_debug_info) { + InstallContext(exe_ctx); + m_interpreter.reset(new PLIInterpreter(exe_ctx, GetUserText())); + if (m_interpreter->Parse()) + return true; + + diagnostic_manager.Printf(lldb::eSeverityError, + "PLI expression can't be interpreted"); + return false; +} + +lldb::ExpressionResults +PLIUserExpression::DoExecute(DiagnosticManager &diagnostic_manager, + ExecutionContext &exe_ctx, + const EvaluateExpressionOptions &options, + lldb::UserExpressionSP &shared_ptr_to_me, + lldb::ExpressionVariableSP &result) { + + Log *log = GetLog(LLDBLog::Expressions); + + lldb_private::ExecutionPolicy execution_policy = options.GetExecutionPolicy(); + lldb::ExpressionResults execution_results = lldb::eExpressionSetupError; + + Process *process = exe_ctx.GetProcessPtr(); + Target *target = exe_ctx.GetTargetPtr(); + + if (target == nullptr || process == nullptr || + process->GetState() != lldb::eStateStopped) { + if (execution_policy == eExecutionPolicyAlways) { + if (log) + log->Printf("== [PLIUserExpression::Evaluate] Expression may not run, " + "but is not constant =="); + + diagnostic_manager.PutString(lldb::eSeverityError, + "expression needed to run but couldn't"); + + return execution_results; + } + } + + SourceLanguage language = target->GetLanguage(); + m_interpreter->set_use_dynamic(options.GetUseDynamic()); + ValueObjectSP result_val_sp = m_interpreter->Evaluate(exe_ctx); + Status err = std::move(m_interpreter->error()); + m_interpreter.reset(); + + if (!result_val_sp) { + const char *error_cstr = err.AsCString(); + if (error_cstr && error_cstr[0]) + diagnostic_manager.PutString(lldb::eSeverityError, error_cstr); + else + diagnostic_manager.PutString(lldb::eSeverityError, + "expression can't be interpreted or run"); + return lldb::eExpressionDiscarded; + } + + result_val_sp->UpdateValueIfNeeded(); + result.reset(new ExpressionVariable()); + result->m_live_sp = result->m_frozen_sp = result_val_sp; + result->m_flags |= ExpressionVariable::EVIsProgramReference; + PersistentExpressionState *pv = + target->GetPersistentExpressionStateForLanguage( + language.AsLanguageType()); + if (pv != nullptr) { + if (result_val_sp->GetName().IsEmpty()) + result->SetName(pv->GetNextPersistentVariableName()); + pv->AddVariable(result); + } + return lldb::eExpressionCompleted; +} diff --git a/lldb/source/Plugins/ExpressionParser/PLI/PLIUserExpression.h b/lldb/source/Plugins/ExpressionParser/PLI/PLIUserExpression.h new file mode 100644 index 00000000000000..9db2c7dc2fa269 --- /dev/null +++ b/lldb/source/Plugins/ExpressionParser/PLI/PLIUserExpression.h @@ -0,0 +1,125 @@ +//===-- PLIUserExpression.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_PLIUserExpression_h_ +#define liblldb_PLIUserExpression_h_ + +#include + +#include "lldb/Expression/ExpressionVariable.h" +#include "lldb/Expression/UserExpression.h" +#include "lldb/Target/ExecutionContext.h" +#include "lldb/Utility/Status.h" +#include "lldb/lldb-forward.h" +#include "lldb/lldb-private.h" + +#include "Plugins/ExpressionParser/PLI/PLIAST.h" +#include "Plugins/ExpressionParser/PLI/PLIParser.h" + +namespace lldb_private { +/// TODO - not used yet. +class PLIPersistentExpressionState : public llvm::RTTIExtends { +public: + // LLVM RTTI support + static char ID; + PLIPersistentExpressionState(); + + void RemovePersistentVariable(lldb::ExpressionVariableSP variable) override; + + ConstString GetNextPersistentVariableName(bool is_error = false) override; + +protected: + llvm::StringRef + GetPersistentVariablePrefix(bool is_error = false) const override { + return "$PLI"; + } + +private: + uint32_t m_next_persistent_variable_id = 0; +}; + +class PLIInterpreter { +public: + PLIInterpreter(ExecutionContext &exe_ctx, const char *expr); + + bool Parse(); + lldb::ValueObjectSP Evaluate(ExecutionContext &exe_ctx); + lldb::ValueObjectSP EvaluateStatement(const lldb_private::PLIASTStmt *s); + lldb::ValueObjectSP EvaluateExpr(const lldb_private::PLIASTExpr *e); + + lldb::ValueObjectSP VisitBasicLit(const lldb_private::PLIASTBasicLit *e); + lldb::ValueObjectSP VisitIdent(const lldb_private::PLIASTIdent *e); + lldb::ValueObjectSP VisitUnaryExpr(const lldb_private::PLIASTUnaryExpr *e); + lldb::ValueObjectSP + VisitSelectorExpr(const lldb_private::PLIASTSelectorExpr *e); + lldb::ValueObjectSP + VisitRefModExpr(const lldb_private::PLIASTRefModifierExpr *expr); + lldb::ValueObjectSP + VisitFuncCallExpr(const lldb_private::PLIASTFuncCallExpr *expr); + lldb::ValueObjectSP + VisitAssignmentExpr(const lldb_private::PLIASTAssignmentExpr *expr); + + void set_use_dynamic(lldb::DynamicValueType use_dynamic) { + m_use_dynamic = use_dynamic; + } + + Status &error() { return m_error; } + +private: + ExecutionContext m_exe_ctx; + lldb::StackFrameSP m_frame; + Status m_error; + lldb::DynamicValueType m_use_dynamic; + PLIParser m_parser; + std::vector> m_statements; +}; + +class PLIUserExpression : public UserExpression { + // LLVM RTTI support + static char ID; + +public: + bool isA(const void *ClassID) const override { + return ClassID == &ID || UserExpression::isA(ClassID); + } + static bool classof(const Expression *obj) { return obj->isA(&ID); } + + PLIUserExpression(ExecutionContextScope &exe_scope, llvm::StringRef expr, + llvm::StringRef prefix, SourceLanguage language, + ResultType desired_type, + const EvaluateExpressionOptions &options); + + bool Parse(DiagnosticManager &diagnostic_manager, ExecutionContext &exe_ctx, + lldb_private::ExecutionPolicy execution_policy, + bool keep_result_in_memory, bool generate_debug_info) override; + + bool CanInterpret() override { return true; } + bool FinalizeJITExecution( + DiagnosticManager &diagnostic_manager, ExecutionContext &exe_ctx, + lldb::ExpressionVariableSP &result, + lldb::addr_t function_stack_bottom = LLDB_INVALID_ADDRESS, + lldb::addr_t function_stack_top = LLDB_INVALID_ADDRESS) override { + return true; + } + +protected: + lldb::ExpressionResults + DoExecute(DiagnosticManager &diagnostic_manager, ExecutionContext &exe_ctx, + const EvaluateExpressionOptions &options, + lldb::UserExpressionSP &shared_ptr_to_me, + lldb::ExpressionVariableSP &result) override; + +private: + std::unique_ptr m_interpreter; +}; + +} // namespace lldb_private + +#endif // liblldb_PLIUserExpression_h_ diff --git a/lldb/source/Plugins/Language/CMakeLists.txt b/lldb/source/Plugins/Language/CMakeLists.txt index 7869074566d1e7..af9e6d06034f0c 100644 --- a/lldb/source/Plugins/Language/CMakeLists.txt +++ b/lldb/source/Plugins/Language/CMakeLists.txt @@ -1,4 +1,6 @@ add_subdirectory(ClangCommon) +add_subdirectory(Cobol) add_subdirectory(CPlusPlus) add_subdirectory(ObjC) add_subdirectory(ObjCPlusPlus) +add_subdirectory(PLI) diff --git a/lldb/source/Plugins/Language/Cobol/CMakeLists.txt b/lldb/source/Plugins/Language/Cobol/CMakeLists.txt new file mode 100644 index 00000000000000..3a89b8ab1740a7 --- /dev/null +++ b/lldb/source/Plugins/Language/Cobol/CMakeLists.txt @@ -0,0 +1,12 @@ +add_lldb_library(lldbPluginCobolLanguage PLUGIN + CobolLanguage.cpp + + LINK_LIBS + lldbCore + lldbDataFormatters + lldbExpression + lldbHost + lldbSymbol + lldbTarget + lldbUtility +) diff --git a/lldb/source/Plugins/Language/Cobol/CobolLanguage.cpp b/lldb/source/Plugins/Language/Cobol/CobolLanguage.cpp new file mode 100644 index 00000000000000..987d6575696910 --- /dev/null +++ b/lldb/source/Plugins/Language/Cobol/CobolLanguage.cpp @@ -0,0 +1,166 @@ +//===-- CobolLanguage.cpp ---------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Threading.h" + +#include "CobolLanguage.h" + +#include "lldb/Core/DumpDataExtractor.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/DataFormatters/DataVisualization.h" +#include "lldb/DataFormatters/FormattersHelpers.h" +#include "lldb/Utility/ConstString.h" +#include "Plugins/TypeSystem/Legacy/TypeSystemLegacy.h" + +using namespace llvm; +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::formatters; + +LLDB_PLUGIN_DEFINE(CobolLanguage) + +void CobolLanguage::Initialize() { + PluginManager::RegisterPlugin(GetPluginNameStatic(), "Cobol Language", + CreateInstance); +} + +void CobolLanguage::Terminate() { + PluginManager::UnregisterPlugin(CreateInstance); +} + +llvm::StringRef CobolLanguage::GetPluginNameStatic() { + static llvm::StringRef g_name("Cobol"); + return g_name; +} + +//------------------------------------------------------------------ +// PluginInterface protocol +//------------------------------------------------------------------ +llvm::StringRef CobolLanguage::GetPluginName() { + return GetPluginNameStatic(); +} + +uint32_t CobolLanguage::GetPluginVersion() { return 1; } + +//------------------------------------------------------------------ +// Static Functions +//------------------------------------------------------------------ +Language *CobolLanguage::CreateInstance(lldb::LanguageType language) { + if (language == eLanguageTypeCobol85) + return new CobolLanguage(); + return nullptr; +} + +lldb::TypeCategoryImplSP CobolLanguage::GetFormatters() { + static llvm::once_flag g_initialize; + static TypeCategoryImplSP g_category; + + llvm::call_once(g_initialize, [this]() -> void { + DataVisualization::Categories::GetCategory(ConstString(GetPluginName()), g_category); + if (g_category) { + LoadCobolFormatters(g_category); + } + }); + return g_category; +} + +HardcodedFormatters::HardcodedSummaryFinder +CobolLanguage::GetHardcodedSummaries() { + static HardcodedFormatters::HardcodedSummaryFinder g_formatters; + return g_formatters; +} + +bool CobolLanguage::DemangledNameContainsPath(llvm::StringRef path, + ConstString demangled) const { + return demangled.GetStringRef().contains_insensitive(path); +} + +HardcodedFormatters::HardcodedSyntheticFinder +CobolLanguage::GetHardcodedSynthetics() { + static HardcodedFormatters::HardcodedSyntheticFinder g_formatters; + return g_formatters; +} + +bool CobolLanguage::IsSourceFile(llvm::StringRef file_path) const { + return file_path.ends_with_insensitive(".cob"); +} + +void CobolLanguage::LoadCobolFormatters(lldb::TypeCategoryImplSP category_sp) { + if (!category_sp) + return; + + TypeSummaryImpl::Flags summary_flags; + summary_flags.SetCascades(true) + .SetSkipPointers(false) + .SetSkipReferences(false) + .SetDontShowChildren(true) + .SetDontShowValue(true) + .SetShowMembersOneLiner(false) + .SetHideItemNames(false); + + AddCXXSummary(category_sp, + lldb_private::formatters::RaincodeStringSummaryProvider, + "string summary provider", ConstString("char \\[[0-9]+\\]$"), + summary_flags, true); +} + +bool formatters::RaincodeStringSummaryProvider(ValueObject &valobj, + Stream &stream, + const TypeSummaryOptions &opts) { + ProcessSP process_sp = valobj.GetProcessSP(); + TargetSP target_sp = valobj.GetTargetSP(); + if (!target_sp) + return false; + if (!process_sp) + return false; + + uint32_t length = 0; + if (!valobj.GetCompilerType().IsCStringType(length)) + return false; + + if (length == 0) { + stream.Printf("\"\""); + return true; + } + + lldb::addr_t valobj_addr = valobj.GetAddressOf(); + if (valobj_addr == LLDB_INVALID_ADDRESS) + return false; + + Status error; + length++; // null terminated + ExecutionContext exe_ctx(valobj.GetExecutionContextRef()); + lldb::WritableDataBufferSP buffer_sp(new DataBufferHeap(length, 0)); + char *buffer = reinterpret_cast(buffer_sp->GetBytes()); + + target_sp->ReadStringFromMemory(valobj_addr, buffer, length, error, 1); + + // this is for PLI var string. + const Flags type_flags(valobj.GetTypeInfo()); + if (type_flags.Test(eTypeIsVarString)) { + uint32_t ele = buffer[0] << 8 | buffer[1]; + length = ele < length ? ele + 1 : length; + buffer += 2; + } + + ExecutionContextScope *exe_scope = process_sp.get(); + TargetCharsetReader Conv(exe_scope->CalculateTarget()); + if (!Conv.IsValid()) { + Host::SystemLog(lldb::eSeverityWarning, StringRef(std::string("WARNING: Invalid target charset ") + + std::string(Conv.getTargetFormat().GetCString()) + std::string("\n"))); + return false; + } + + Conv.convert(buffer, length); + DataExtractor data(buffer, length, exe_ctx.GetByteOrder(), + process_sp->GetAddressByteSize()); + return DumpDataExtractor(data, &stream, 0, eFormatCString, 1, length, + UINT32_MAX, LLDB_INVALID_ADDRESS, 0, 0, exe_scope); +} diff --git a/lldb/source/Plugins/Language/Cobol/CobolLanguage.h b/lldb/source/Plugins/Language/Cobol/CobolLanguage.h new file mode 100644 index 00000000000000..45b5f4012654fd --- /dev/null +++ b/lldb/source/Plugins/Language/Cobol/CobolLanguage.h @@ -0,0 +1,69 @@ +//===-- CobolLanguage.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_CobolLanguage_h_ +#define liblldb_CobolLanguage_h_ + +#include "llvm/ADT/StringRef.h" + +#include "lldb/Target/Language.h" +#include "lldb/Utility/ConstString.h" +#include "lldb/lldb-private.h" + +namespace lldb_private { + +class CobolLanguage : public Language { +public: + CobolLanguage() = default; + ~CobolLanguage() override = default; + + lldb::LanguageType GetLanguageType() const override { + return lldb::eLanguageTypeCobol85; + } + + HardcodedFormatters::HardcodedSummaryFinder GetHardcodedSummaries() override; + bool DemangledNameContainsPath(llvm::StringRef path, + ConstString demangled) const override; + HardcodedFormatters::HardcodedSyntheticFinder + GetHardcodedSynthetics() override; + + bool IsSourceFile(llvm::StringRef file_path) const override; + + lldb::TypeCategoryImplSP GetFormatters() override; + + //------------------------------------------------------------------ + // Static Functions + //------------------------------------------------------------------ + static void Initialize(); + + static void Terminate(); + + static lldb_private::Language *CreateInstance(lldb::LanguageType language); + + static llvm::StringRef GetPluginNameStatic(); + + static void LoadCobolFormatters(lldb::TypeCategoryImplSP category_sp); + + //------------------------------------------------------------------ + // PluginInterface protocol + //------------------------------------------------------------------ + llvm::StringRef GetPluginName() override; + + uint32_t GetPluginVersion(); +}; + +namespace formatters { + +bool RaincodeStringSummaryProvider(ValueObject &valobj, Stream &stream, + const TypeSummaryOptions &options); + +} // namespace formatters +} // namespace lldb_private + +#endif // liblldb_CobolLanguage_h_ diff --git a/lldb/source/Plugins/Language/PLI/CMakeLists.txt b/lldb/source/Plugins/Language/PLI/CMakeLists.txt new file mode 100644 index 00000000000000..4eff2bb81d0ed9 --- /dev/null +++ b/lldb/source/Plugins/Language/PLI/CMakeLists.txt @@ -0,0 +1,13 @@ +add_lldb_library(lldbPluginPLILanguage PLUGIN + PLILanguage.cpp + PLIBitset.cpp + + LINK_LIBS + lldbCore + lldbDataFormatters + lldbExpression + lldbHost + lldbSymbol + lldbTarget + lldbUtility +) diff --git a/lldb/source/Plugins/Language/PLI/PLIBitset.cpp b/lldb/source/Plugins/Language/PLI/PLIBitset.cpp new file mode 100644 index 00000000000000..0cc1bcf23f2a96 --- /dev/null +++ b/lldb/source/Plugins/Language/PLI/PLIBitset.cpp @@ -0,0 +1,94 @@ +//===-- PLIBitset.cpp ----------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "PLILanguage.h" +#include "lldb/DataFormatters/FormattersHelpers.h" +#include "lldb/Target/Target.h" + +#include "llvm/ADT/StringRef.h" + +using namespace lldb; +using namespace lldb_private; + +namespace { + +class BitsetFrontEnd : public SyntheticChildrenFrontEnd { +public: + BitsetFrontEnd(ValueObject &valobj); + + size_t GetIndexOfChildWithName(ConstString name) override { + return formatters::ExtractIndexFromString(name.GetCString()); + } + + bool MightHaveChildren() override { return true; } + lldb::ChildCacheState Update() override; + llvm::Expected CalculateNumChildren() override { return m_elements.size(); } + ValueObjectSP GetChildAtIndex(uint32_t idx) override; + +private: + std::vector m_elements; + CompilerType m_bool_type; + ByteOrder m_byte_order = eByteOrderInvalid; + uint8_t m_byte_size = 0; +}; + +} // namespace + +BitsetFrontEnd::BitsetFrontEnd(ValueObject &valobj) + : SyntheticChildrenFrontEnd(valobj) { + m_bool_type = valobj.GetCompilerType().GetBasicTypeFromAST(eBasicTypeBool); + if (auto target_sp = m_backend.GetTargetSP()) { + m_byte_order = target_sp->GetArchitecture().GetByteOrder(); + m_byte_size = target_sp->GetArchitecture().GetAddressByteSize(); + Update(); + } +} + +lldb::ChildCacheState BitsetFrontEnd::Update() { + m_elements.clear(); + + TargetSP target_sp = m_backend.GetTargetSP(); + if (!target_sp) + return lldb::ChildCacheState::eRefetch; + uint32_t capping_size = target_sp->GetMaximumNumberOfChildrenToDisplay(); + + if (!m_backend.IsArrayType()) + return lldb::ChildCacheState::eRefetch; + + const llvm::StringRef type_name( + m_backend.GetCompilerType().GetTypeName().GetStringRef()); + const llvm::StringRef size_str = type_name.split('[').second.split(']').first; + uint32_t num_elements = 0; + if (size_str.getAsInteger(10, num_elements)) + num_elements = *m_backend.GetNumChildren(capping_size / 8) * 8; + m_elements.assign(num_elements, ValueObjectSP()); + return lldb::ChildCacheState::eRefetch; +} + +ValueObjectSP BitsetFrontEnd::GetChildAtIndex(uint32_t idx) { + if (idx >= m_elements.size()) + return ValueObjectSP(); + + if (m_elements[idx]) + return m_elements[idx]; + + size_t chunk_idx = idx / 8; + size_t bit_pos = 7 - (idx % 8); // we have zero bit on 7th pos + m_elements[idx] = m_backend.GetChildAtIndex(chunk_idx, true) + ->GetSyntheticBitFieldChild(bit_pos, bit_pos, true); + m_elements[idx]->SetName(ConstString(llvm::formatv("[{0}]", idx).str())); + return m_elements[idx]; +} + +SyntheticChildrenFrontEnd * +formatters::PLIBitsetSyntheticFrontEndCreator(CXXSyntheticChildren *, + lldb::ValueObjectSP valobj_sp) { + if (valobj_sp) + return new BitsetFrontEnd(*valobj_sp); + return nullptr; +} diff --git a/lldb/source/Plugins/Language/PLI/PLILanguage.cpp b/lldb/source/Plugins/Language/PLI/PLILanguage.cpp new file mode 100644 index 00000000000000..b1662d1858f75c --- /dev/null +++ b/lldb/source/Plugins/Language/PLI/PLILanguage.cpp @@ -0,0 +1,137 @@ +//===-- PLILanguage.cpp ---------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Threading.h" + +#include "PLILanguage.h" + +#include "lldb/Core/DumpDataExtractor.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/DataFormatters/DataVisualization.h" +#include "lldb/DataFormatters/FormattersHelpers.h" +#include "lldb/Utility/ConstString.h" + +#include "Plugins/TypeSystem/Legacy/TypeSystemLegacy.h" + +using namespace llvm; +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::formatters; + +LLDB_PLUGIN_DEFINE(PLILanguage) + +void PLILanguage::Initialize() { + PluginManager::RegisterPlugin(GetPluginNameStatic(), "PLI Language", + CreateInstance); +} + +void PLILanguage::Terminate() { + PluginManager::UnregisterPlugin(CreateInstance); +} + +llvm::StringRef PLILanguage::GetPluginNameStatic() { + static llvm::StringRef g_name("PLI"); + return g_name; +} + +//------------------------------------------------------------------ +// PluginInterface protocol +//------------------------------------------------------------------ +llvm::StringRef PLILanguage::GetPluginName() { + return GetPluginNameStatic(); +} + +uint32_t PLILanguage::GetPluginVersion() { return 1; } + +//------------------------------------------------------------------ +// Static Functions +//------------------------------------------------------------------ +Language *PLILanguage::CreateInstance(lldb::LanguageType language) { + if (language == eLanguageTypePLI) { + return new PLILanguage(); + } + return nullptr; +} + +lldb::TypeCategoryImplSP PLILanguage::GetFormatters() { + static llvm::once_flag g_initialize; + static TypeCategoryImplSP g_category; + + llvm::call_once(g_initialize, [this]() -> void { + DataVisualization::Categories::GetCategory(ConstString(GetPluginName()), g_category); + if (g_category) { + LoadPLIFormatters(g_category); + } + }); + return g_category; +} + +HardcodedFormatters::HardcodedSummaryFinder +PLILanguage::GetHardcodedSummaries() { + static HardcodedFormatters::HardcodedSummaryFinder g_formatters; + return g_formatters; +} + +bool PLILanguage::DemangledNameContainsPath(llvm::StringRef path, + ConstString demangled) const { + return demangled.GetStringRef().contains_insensitive(path); +} + +HardcodedFormatters::HardcodedSyntheticFinder +PLILanguage::GetHardcodedSynthetics() { + static HardcodedFormatters::HardcodedSyntheticFinder g_formatters; + return g_formatters; +} + +bool PLILanguage::IsSourceFile(llvm::StringRef file_path) const { + const auto suffixes = {".pli", ".plirc"}; + for (auto suffix : suffixes) { + if (file_path.ends_with_insensitive(suffix)) + return true; + } + return false; +} + +void PLILanguage::LoadPLIFormatters(lldb::TypeCategoryImplSP category_sp) { + if (!category_sp) + return; + + SyntheticChildren::Flags synth_flags; + synth_flags.SetCascades(true) + .SetSkipPointers(false) + .SetSkipReferences(false) + .SetFrontEndWantsDereference(true); + + TypeFormatImpl::Flags bit_flags; + bit_flags.SetCascades(true).SetSkipPointers(true).SetSkipReferences(true); + + AddFormat(category_sp, lldb::eFormatUnsigned, ConstString("BIT"), bit_flags); + + AddCXXSynthetic(category_sp, + lldb_private::formatters::PLIBitsetSyntheticFrontEndCreator, + "pli bit synthetic children", ConstString("^BIT [[0-9]+]$"), + synth_flags, true); + + TypeSummaryImpl::Flags summary_flags; + summary_flags.SetCascades(true) + .SetSkipPointers(false) + .SetSkipReferences(false) + .SetDontShowChildren(true) + .SetDontShowValue(true) + .SetShowMembersOneLiner(false) + .SetHideItemNames(false); + + AddCXXSummary(category_sp, + lldb_private::formatters::RaincodeStringSummaryProvider, + "string summary provider", ConstString("char \\[[0-9]+\\]"), + summary_flags, true); + + return; +} diff --git a/lldb/source/Plugins/Language/PLI/PLILanguage.h b/lldb/source/Plugins/Language/PLI/PLILanguage.h new file mode 100644 index 00000000000000..fae5df843f797e --- /dev/null +++ b/lldb/source/Plugins/Language/PLI/PLILanguage.h @@ -0,0 +1,73 @@ +//===-- PLILanguage.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_PLILanguage_h_ +#define liblldb_PLILanguage_h_ + +#include "llvm/ADT/StringRef.h" + +#include "lldb/Target/Language.h" +#include "lldb/Utility/ConstString.h" +#include "lldb/lldb-private.h" + +namespace lldb_private { + +class PLILanguage : public Language { +public: + PLILanguage() = default; + ~PLILanguage() override = default; + + lldb::LanguageType GetLanguageType() const override { + return lldb::eLanguageTypePLI; + } + + HardcodedFormatters::HardcodedSummaryFinder GetHardcodedSummaries() override; + bool DemangledNameContainsPath(llvm::StringRef path, + ConstString demangled) const override; + HardcodedFormatters::HardcodedSyntheticFinder + GetHardcodedSynthetics() override; + + bool IsSourceFile(llvm::StringRef file_path) const override; + + lldb::TypeCategoryImplSP GetFormatters() override; + + //------------------------------------------------------------------ + // Static Functions + //------------------------------------------------------------------ + static void Initialize(); + + static void Terminate(); + + static lldb_private::Language *CreateInstance(lldb::LanguageType language); + + static llvm::StringRef GetPluginNameStatic(); + + static void LoadPLIFormatters(lldb::TypeCategoryImplSP category_sp); + + //------------------------------------------------------------------ + // PluginInterface protocol + //------------------------------------------------------------------ + llvm::StringRef GetPluginName() override; + + uint32_t GetPluginVersion(); +}; + +namespace formatters { + +SyntheticChildrenFrontEnd * +PLIBitsetSyntheticFrontEndCreator(CXXSyntheticChildren *, + lldb::ValueObjectSP valobj_sp); + +bool RaincodeStringSummaryProvider(ValueObject &valobj, Stream &stream, + const TypeSummaryOptions &options); + +} // namespace formatters +} // namespace lldb_private + +#endif // liblldb_PLILanguage_h_ diff --git a/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp b/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp index 7aa5b8d81890ae..c7ed3d0d2005f2 100644 --- a/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp +++ b/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp @@ -414,12 +414,12 @@ ObjectFileSP ObjectContainerBSDArchive::GetObjectFile(const FileSpec *file) { child_data_sp->GetByteSize() != object->file_size) return ObjectFileSP(); lldb::offset_t data_offset = 0; - return ObjectFile::FindPlugin( + return lldb_private::ObjectFile::FindPlugin( module_sp, &child, m_offset + object->file_offset, object->file_size, child_data_sp, data_offset); } lldb::offset_t data_offset = object->file_offset; - return ObjectFile::FindPlugin( + return lldb_private::ObjectFile::FindPlugin( module_sp, file, m_offset + object->file_offset, object->file_size, m_archive_sp->GetData().GetSharedDataBuffer(), data_offset); } @@ -468,7 +468,7 @@ size_t ObjectContainerBSDArchive::GetModuleSpecifications( continue; FileSpec child = GetChildFileSpecificationsFromThin( object->ar_name.GetStringRef(), file); - if (ObjectFile::GetModuleSpecifications(child, 0, object->file_size, + if (lldb_private::ObjectFile::GetModuleSpecifications(child, 0, object->file_size, specs)) { ModuleSpec &spec = specs.GetModuleSpecRefAtIndex(specs.GetSize() - 1); @@ -484,7 +484,7 @@ size_t ObjectContainerBSDArchive::GetModuleSpecifications( const lldb::offset_t object_file_offset = file_offset + object->file_offset; if (object->file_offset < file_size && file_size > object_file_offset) { - if (ObjectFile::GetModuleSpecifications( + if (lldb_private::ObjectFile::GetModuleSpecifications( file, object_file_offset, file_size - object_file_offset, specs)) { ModuleSpec &spec = diff --git a/lldb/source/Plugins/SymbolFile/DWARF/CMakeLists.txt b/lldb/source/Plugins/SymbolFile/DWARF/CMakeLists.txt index 0e4fd5b995d1ba..d4049cf1017dca 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/CMakeLists.txt +++ b/lldb/source/Plugins/SymbolFile/DWARF/CMakeLists.txt @@ -12,6 +12,7 @@ add_lldb_library(lldbPluginSymbolFileDWARF PLUGIN DIERef.cpp DWARFASTParser.cpp DWARFASTParserClang.cpp + DWARFASTParserLegacy.cpp DWARFAttribute.cpp DWARFBaseDIE.cpp DWARFCompileUnit.cpp diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParser.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParser.cpp index 4ed523bbb9e760..0f253ca8893244 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParser.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParser.cpp @@ -41,6 +41,8 @@ DWARFASTParser::ParseChildArrayInfo(const DWARFDIE &parent_die, uint64_t lower_bound = 0; uint64_t upper_bound = 0; bool upper_bound_valid = false; + bool is_dynamic = false; + DWARFExpressionList num_elements_exp; for (size_t i = 0; i < attributes.Size(); ++i) { const dw_attr_t attr = attributes.AttributeAtIndex(i); DWARFFormValue form_value; @@ -64,8 +66,18 @@ DWARFASTParser::ParseChildArrayInfo(const DWARFDIE &parent_die, } } } - } else - num_elements = form_value.Unsigned(); + } else if (form_value.BlockData()) { + const DWARFDataExtractor &data = die.GetData(); + uint32_t block_offset = form_value.BlockData() - data.GetDataStart(); + uint32_t block_length = form_value.Unsigned(); + auto cu = die.GetCU(); + auto module = die.GetModule(); + is_dynamic = true; + num_elements_exp = DWARFExpressionList( + module, DataExtractor(data, block_offset, block_length), cu); + break; + } + num_elements = form_value.Unsigned(); break; case DW_AT_bit_stride: @@ -96,7 +108,10 @@ DWARFASTParser::ParseChildArrayInfo(const DWARFDIE &parent_die, num_elements = upper_bound - lower_bound + 1; } - array_info.element_orders.push_back(num_elements); + if (!is_dynamic) + array_info.element_orders.push_back(num_elements); + else + array_info.element_orders_exp.push_back(num_elements_exp); } return array_info; } diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParser.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParser.h index 971cbe47fb702d..f7663083d93ce7 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParser.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParser.h @@ -29,7 +29,7 @@ class SymbolFileDWARF; class DWARFASTParser { public: - enum class Kind { DWARFASTParserClang }; + enum class Kind { DWARFASTParserClang, DWARFASTParserLegacy }; DWARFASTParser(Kind kind) : m_kind(kind) {} virtual ~DWARFASTParser() = default; diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp index 4d688f9a1358b2..8a30ab8f1e6c78 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp @@ -539,6 +539,8 @@ ExtractDataMemberLocation(DWARFDIE const &die, DWARFFormValue const &form_value, return form_value.Unsigned(); Value initialValue(0); + std::vector stack; + stack.push_back(Value(0)); const DWARFDataExtractor &debug_info_data = die.GetData(); uint32_t block_length = form_value.Unsigned(); uint32_t block_offset = @@ -548,7 +550,7 @@ ExtractDataMemberLocation(DWARFDIE const &die, DWARFFormValue const &form_value, /*ExecutionContext=*/nullptr, /*RegisterContext=*/nullptr, module_sp, DataExtractor(debug_info_data, block_offset, block_length), die.GetCU(), - eRegisterKindDWARF, &initialValue, nullptr); + eRegisterKindDWARF, &initialValue, nullptr, stack); if (!memberOffset) { LLDB_LOG_ERROR(log, memberOffset.takeError(), "ExtractDataMemberLocation failed: {0}"); @@ -2367,7 +2369,7 @@ DWARFASTParserClang::ParseFunctionFromDWARF(CompileUnit &comp_unit, if (die.GetDIENamesAndRanges(name, mangled, func_ranges, decl_file, decl_line, decl_column, call_file, call_line, call_column, - &frame_base)) { + &frame_base, nullptr, nullptr)) { Mangled func_name; if (mangled) func_name.SetValue(ConstString(mangled)); diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserLegacy.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserLegacy.cpp new file mode 100644 index 00000000000000..0734eba52aa0af --- /dev/null +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserLegacy.cpp @@ -0,0 +1,723 @@ +//===-- DWARFASTParserLegacy.cpp --------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "DWARFASTParserLegacy.h" + +#include "DWARFDIE.h" +#include "DWARFDebugInfo.h" +#include "DWARFDeclContext.h" +#include "DWARFDefines.h" +#include "SymbolFileDWARF.h" +#include "SymbolFileDWARFDebugMap.h" +#include "UniqueDWARFASTType.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" + +#include "Plugins/SymbolFile/DWARF/DWARFASTParserLegacy.h" + +#include + +//#define ENABLE_DEBUG_PRINTF // COMMENT OUT THIS LINE PRIOR TO CHECKIN + +#ifdef ENABLE_DEBUG_PRINTF +#include +#define DEBUG_PRINTF(fmt, ...) printf(fmt, __VA_ARGS__) +#else +#define DEBUG_PRINTF(fmt, ...) +#endif + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::dwarf; + +DWARFASTParserLegacy::DWARFASTParserLegacy(lldb_private::TypeSystemLegacy &ast) + : DWARFASTParser(Kind::DWARFASTParserLegacy), m_ast(ast) {} + +DWARFASTParserLegacy::~DWARFASTParserLegacy() {} + +TypeSP DWARFASTParserLegacy::ParseTypeFromDWARF( + const lldb_private::SymbolContext &sc, + const lldb_private::plugin::dwarf::DWARFDIE &die, bool *type_is_new_ptr) { + TypeSP type_sp; + + + if (type_is_new_ptr) + *type_is_new_ptr = false; + + Log *log(GetLog(DWARFLog::TypeCompletion | DWARFLog::Lookups)); + if (die) { + plugin::dwarf::SymbolFileDWARF *dwarf = die.GetDWARF(); + if (log) { + dwarf->GetObjectFile()->GetModule()->LogMessage( + log, + "DWARFASTParserLegacy::ParseTypeFromDWARF (die = 0x%8.8x) %s name = " + "'%s')", + die.GetOffset(), plugin::dwarf::DW_TAG_value_to_name(die.Tag()), + die.GetName()); + } + + Type *type_ptr = dwarf->GetDIEToType().lookup(die.GetDIE()); + + if (!type_ptr) { + if (type_is_new_ptr) + *type_is_new_ptr = true; + + const dw_tag_t tag = die.Tag(); + CompilerType compiler_type; + plugin::dwarf::DWARFAttributes attributes; + plugin::dwarf::DWARFFormValue form_value; + dw_attr_t attr; + Declaration decl; + const char *type_name_cstr = nullptr; + const char *pic_cstr = nullptr; + ConstString type_name_const_str; + ConstString pic_const_str; + ByteOrder byte_order = endian::InlHostByteOrder(); + Type::ResolveState resolve_state = Type::ResolveState::Unresolved; + Type::EncodingDataType encoding_data_type = Type::eEncodingIsUID; + + switch (tag) { + case DW_TAG_pointer_type: + case DW_TAG_reference_type: + case DW_TAG_base_type: { + dwarf->GetDIEToType()[die.GetDIE()] = DIE_IS_BEING_PARSED; + plugin::dwarf::DWARFFormValue encoding_uid; + uint32_t bit_size = 0; + uint32_t encoding = 0; + uint32_t sign = 0; + uint32_t digit_count = 0; + int32_t scale = 0; + bool bin_scale = false; + + attributes = die.GetAttributes(); + const size_t num_attributes = attributes.Size(); + for (size_t i = 0; i < num_attributes; ++i) { + attr = attributes.AttributeAtIndex(i); + if (attributes.ExtractFormValueAtIndex(i, form_value)) { + switch (attr) { + case DW_AT_decl_file: + decl.SetFile(sc.comp_unit->GetSupportFiles().GetFileSpecAtIndex( + form_value.Unsigned())); + break; + case DW_AT_decl_line: + decl.SetLine(form_value.Unsigned()); + break; + case DW_AT_decl_column: + decl.SetColumn(form_value.Unsigned()); + break; + 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: + bit_size = form_value.Unsigned() * 8; + break; + case DW_AT_bit_size: + bit_size = form_value.Unsigned(); + break; + case DW_AT_encoding: + encoding = form_value.Unsigned(); + break; + case DW_AT_endianity: + switch (form_value.Unsigned()) { + case DW_END_big: + byte_order = eByteOrderBig; + break; + case DW_END_little: + byte_order = eByteOrderLittle; + break; + } + break; + case DW_AT_decimal_sign: + sign = form_value.Unsigned(); + break; + case DW_AT_decimal_scale: + scale = form_value.Signed(); + break; + case DW_AT_binary_scale: + scale = form_value.Signed(); + bin_scale = true; + break; + case DW_AT_type: + encoding_uid = form_value; + break; + case DW_AT_picture_string: + pic_cstr = form_value.AsCString(); + if (pic_cstr) + pic_const_str.SetCString(pic_cstr); + break; + case DW_AT_digit_count: + digit_count = form_value.Unsigned(); + break; + default: + 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.Reference()); + + switch (tag) { + default: + case DW_TAG_base_type: + compiler_type = m_ast.CreateBaseType( + type_name_const_str, pic_const_str, encoding, bit_size, sign, + scale, digit_count, byte_order, bin_scale); + resolve_state = Type::ResolveState::Full; + break; + case DW_TAG_pointer_type: + encoding_data_type = Type::eEncodingIsPointerUID; + break; + case DW_TAG_reference_type: + encoding_data_type = Type::eEncodingIsLValueReferenceUID; + break; + } + + type_sp = dwarf->MakeType( + die.GetID(), type_name_const_str, (bit_size + 7) / 8, + nullptr, LLDB_INVALID_UID, + encoding_data_type, &decl, compiler_type, resolve_state); + + assert(type_sp.get()); + } break; + case DW_TAG_array_type: { + // Set a bit that lets us know that we are currently parsing this + dwarf->GetDIEToType()[die.GetDIE()] = DIE_IS_BEING_PARSED; + + plugin::dwarf::DWARFFormValue type_die_form; + uint32_t byte_stride = 0; + uint32_t bit_stride = 0; + bool isVarString = false; + + attributes = die.GetAttributes(); + const size_t num_attributes = attributes.Size(); + for (size_t i = 0; i < num_attributes; ++i) { + attr = attributes.AttributeAtIndex(i); + if (attributes.ExtractFormValueAtIndex(i, form_value)) { + switch (attr) { + case DW_AT_decl_file: + decl.SetFile(sc.comp_unit->GetSupportFiles().GetFileSpecAtIndex( + form_value.Unsigned())); + break; + case DW_AT_decl_line: + decl.SetLine(form_value.Unsigned()); + break; + case DW_AT_decl_column: + decl.SetColumn(form_value.Unsigned()); + break; + 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_form = form_value; + break; + case DW_AT_byte_stride: + byte_stride = form_value.Unsigned(); + break; + case DW_AT_bit_stride: + bit_stride = form_value.Unsigned(); + break; + case DW_AT_RAINCODE_str_header: + isVarString = true; + 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_form.Reference(), true); + + if (element_type) { + auto array_info = ParseChildArrayInfo(die); + if (array_info) { + byte_stride = array_info->byte_stride; + bit_stride = array_info->bit_stride; + } + + if ((byte_stride == 0) && (bit_stride == 0)) + byte_stride = element_type->GetByteSize(nullptr).value_or(0); + + ConstString empty_name; + CompilerType array_element_type = + element_type->GetForwardCompilerType(); + if (array_element_type.GetCompleteType()) { + uint64_t array_element_bit_stride = byte_stride * 8 + bit_stride; + + if (array_info && array_info->element_orders.size() > 0) { + auto end = array_info->element_orders.rend(); + uint64_t num_elements = 0; + for (auto pos = array_info->element_orders.rbegin(); pos != end; + ++pos) { + num_elements = pos->value(); // Retrieve the value + compiler_type = m_ast.CreateArrayType( + type_name_const_str, empty_name, array_element_type, + num_elements, isVarString); + array_element_type = compiler_type; + if (num_elements) + array_element_bit_stride *= num_elements; + } + } else if (array_info && array_info->element_orders_exp.size() > 0) { + auto end = array_info->element_orders_exp.rend(); + for (auto pos = array_info->element_orders_exp.rbegin(); pos != end; + ++pos) { + DWARFExpressionList num_elements = *pos; + compiler_type = m_ast.CreateArrayType( + type_name_const_str, empty_name, array_element_type, + num_elements, isVarString); + array_element_type = compiler_type; + // if (num_elements) + // array_element_bit_stride *= num_elements; + array_element_bit_stride = 2; + } + } else + compiler_type = + m_ast.CreateArrayType(type_name_const_str, empty_name, + array_element_type, (size_t) 0, isVarString); + + type_sp = dwarf->MakeType( + die.GetID(), empty_name, array_element_bit_stride / 8, + nullptr, LLDB_INVALID_UID, + Type::eEncodingIsUID, &decl, compiler_type, + Type::ResolveState::Full); + + type_sp->SetEncodingType(element_type); + } else + dwarf->GetObjectFile()->GetModule()->LogMessage( + log, + "DWARFASTParserLegacy::ParseTypeFromDWARF (die = 0x%8.8x) %s " + "name " + "= '%s'), incomplete type array element not supported, yet!.", + die.GetOffset(), plugin::dwarf::DW_TAG_value_to_name(die.Tag()), + die.GetName()); + } + } break; + case DW_TAG_union_type: + case DW_TAG_structure_type: { + dwarf->GetDIEToType()[die.GetDIE()] = DIE_IS_BEING_PARSED; + bool byte_size_valid = false; + unsigned byte_size = 0; + + attributes = die.GetAttributes(); + const size_t num_attributes = attributes.Size(); + for (size_t i = 0; i < num_attributes; ++i) { + attr = attributes.AttributeAtIndex(i); + if (attributes.ExtractFormValueAtIndex(i, form_value)) { + switch (attr) { + default: + break; + 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; + } + } + } + + std::unique_ptr unique_ast_entry_ap( + new plugin::dwarf::UniqueDWARFASTType()); + + bool is_forward_declaration = false; + if (type_name_const_str && + dwarf->GetUniqueDWARFASTTypeMap().Find( + type_name_const_str, die, decl, + byte_size_valid ? byte_size : -1, is_forward_declaration)) { + type_sp = unique_ast_entry_ap->m_type_sp; + if (type_sp) { + dwarf->GetDIEToType()[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->GetForwardDeclDIEToCompilerType().lookup(die.GetDIE())); + if (!compiler_type) { + compiler_type_was_created = true; + compiler_type = + m_ast.CreateStructType(type_name_const_str, byte_size); + } + lldb_private::plugin::dwarf::SymbolFileDWARF *dwarf = die.GetDWARF(); + type_sp = dwarf->MakeType( + die.GetID(), type_name_const_str, byte_size, nullptr, + LLDB_INVALID_UID, Type::eEncodingIsUID, &decl, compiler_type, + Type::ResolveState::Forward); + + 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 (!die.HasChildren()) + m_ast.CompleteStructType(compiler_type); + else if (compiler_type_was_created) { + // dwarf->GetForwardDeclDIEToCompilerType()[die.GetDIE()] = + // compiler_type.GetOpaqueQualType(); + dwarf->GetForwardDeclCompilerTypeToDIE().try_emplace( + compiler_type.GetOpaqueQualType(), *die.GetDIERef()); + } + } break; + case DW_TAG_dynamic_type: { + dwarf->GetDIEToType()[die.GetDIE()] = DIE_IS_BEING_PARSED; + attributes = die.GetAttributes(); + const size_t num_attributes = attributes.Size(); + lldb_private::plugin::dwarf::DWARFFormValue type_die_form; + DWARFExpressionList dw_location, dw_allocated; + ModuleSP module(die.GetModule()); + ConstString empty_name; + + for (size_t i = 0; i < num_attributes; i++) { + attr = attributes.AttributeAtIndex(i); + if (attributes.ExtractFormValueAtIndex(i, form_value)) { + switch (attr) { + default: + break; + case DW_AT_type: + type_die_form = form_value; + break; + case DW_AT_data_location: { + if (!plugin::dwarf::DWARFFormValue::IsBlockForm( + form_value.Form())) { + dwarf->GetObjectFile()->GetModule()->ReportError( + "{0x%8.8x}: dynamic type tag 0x%4.4x (%s), has invalid" + " DW_AT_data_location expression type." + "please file a bug and attach the file at the " + "start of this error message", + die.GetOffset(), tag, + plugin::dwarf::DW_TAG_value_to_name(tag)); + } + + auto data = die.GetData(); + uint32_t offset = form_value.BlockData() - data.GetDataStart(); + uint32_t length = form_value.Unsigned(); + dw_location = DWARFExpressionList( + module, DataExtractor(data, offset, length), die.GetCU()); + } break; + case DW_AT_allocated: { + if (!plugin::dwarf::DWARFFormValue::IsBlockForm( + form_value.Form())) { + dwarf->GetObjectFile()->GetModule()->ReportError( + "{0x%8.8x}: dynamic type tag 0x%4.4x (%s), has invalid" + " DW_AT_allocated expression type." + "please file a bug and attach the file at the " + "start of this error message", + die.GetOffset(), tag, + plugin::dwarf::DW_TAG_value_to_name(tag)); + } + + auto data = die.GetData(); + uint32_t offset = form_value.BlockData() - data.GetDataStart(); + uint32_t length = form_value.Unsigned(); + dw_allocated = DWARFExpressionList( + module, DataExtractor(data, offset, length), die.GetCU()); + } break; + } + } + } + DEBUG_PRINTF("0x%8.8" PRIx64 ": %s (\"%s\")\n", die.GetID(), + DW_TAG_value_to_name(tag), type_name_cstr); + + Type *base_type = + dwarf->ResolveTypeUID(type_die_form.Reference(), true); + compiler_type = m_ast.CreateDynamicType( + base_type->GetForwardCompilerType(), dw_location, dw_allocated); + type_sp = dwarf->MakeType( + die.GetID(), empty_name, 0, nullptr, + LLDB_INVALID_UID, Type::eEncodingIsUID, + &decl, compiler_type, Type::ResolveState::Full); + type_sp->SetEncodingType(base_type); + } break; + case DW_TAG_typedef: + case DW_TAG_unspecified_type: + dwarf->GetObjectFile()->GetModule()->LogMessage( + log, + "DWARFASTParserLegacy::ParseTypeFromDWARF (die = 0x%8.8x) %s name " + "= '%s'), not supported, yet!.", + die.GetOffset(), plugin::dwarf::DW_TAG_value_to_name(die.Tag()), + die.GetName()); + break; + case DW_TAG_subprogram: + case DW_TAG_subroutine_type: { + dwarf->GetDIEToType()[die.GetDIE()] = DIE_IS_BEING_PARSED; + + bool is_variadic = false; + + attributes = die.GetAttributes(); + const size_t num_attr = attributes.Size(); + for (size_t i = 0; i < num_attr; ++i) { + if (attributes.ExtractFormValueAtIndex(i, form_value)) { + switch (attributes.AttributeAtIndex(i)) { + default: + break; + case DW_AT_name: + type_name_cstr = form_value.AsCString(); + type_name_const_str.SetCString(type_name_cstr); + break; + // todo external + } + } + } + + DEBUG_PRINTF("0x%8.8" PRIx64 ": %s (\"%s\")\n", die.GetID(), + DW_TAG_value_to_name(tag), type_name_cstr); + + std::vector function_params_types; + if (die.HasChildren()) + ParseChildParameters(*sc.comp_unit, die, is_variadic, + function_params_types); + + compiler_type = m_ast.CreateFunctionType( + type_name_const_str, function_params_types.data(), + function_params_types.size(), is_variadic); + type_sp = dwarf->MakeType( + die.GetID(), type_name_const_str, 0, nullptr, + LLDB_INVALID_UID, Type::eEncodingIsUID, &decl, compiler_type, + Type::ResolveState::Full); + + assert(type_sp.get()); + } 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, + lldb_private::plugin::dwarf::DW_TAG_value_to_name(tag)); + break; + } + + if (type_sp.get()) { + lldb_private::plugin::dwarf::DWARFDIE sc_parent_die = + plugin::dwarf::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 || + sc_parent_tag == DW_TAG_partial_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) { + type_sp->SetSymbolContextScope(symbol_context_scope); + } + + dwarf->GetDIEToType()[die.GetDIE()] = type_sp.get(); + } + } else if (type_ptr != DIE_IS_BEING_PARSED) { + type_sp = type_ptr->shared_from_this(); + } + } + return type_sp; +} + +lldb_private::Function *DWARFASTParserLegacy::ParseFunctionFromDWARF( + lldb_private::CompileUnit &comp_unit, + const lldb_private::plugin::dwarf::DWARFDIE &die, + const lldb_private::AddressRange &func_range) { + if (die.Tag() != DW_TAG_subprogram) + return nullptr; + + DWARFRangeList func_ranges; + const char *name = nullptr; + const char *mangled = nullptr; + std::optional decl_file = 0; + std::optional decl_line = 0; + std::optional decl_column = 0; + std::optional call_file = 0; + std::optional call_line = 0; + std::optional call_column = 0; + DWARFExpressionList frame_base; + DWARFExpressionList rc_frame_base; + DWARFExpressionList static_link; + + if (die.GetDIENamesAndRanges(name, mangled, func_ranges, decl_file, decl_line, + decl_column, call_file, call_line, call_column, + &frame_base, &static_link, &rc_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)); + + FunctionSP func_sp; + std::unique_ptr decl_ap; + if (decl_file != 0 || decl_line != 0 || decl_column != 0) + decl_ap.reset(new Declaration( + comp_unit.GetSupportFiles().GetFileSpecAtIndex(decl_file.value()), + decl_line.value(), decl_column.value())); + + plugin::dwarf::SymbolFileDWARF *dwarf = die.GetDWARF(); + // Supply the type _only_ if it has already been parsed + Type *func_type = dwarf->GetDIEToType().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 = std::make_shared( + &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() != nullptr) { + if (frame_base.IsValid()) + func_sp->GetFrameBaseExpression() = frame_base; + if (rc_frame_base.IsValid()) + func_sp->GetRCFrameBaseExpression() = rc_frame_base; + if (static_link.IsValid()) + func_sp->GetStaticLinkExpression() = static_link; + comp_unit.AddFunction(func_sp); + return func_sp.get(); + } + } + } + } + return nullptr; +} + +bool DWARFASTParserLegacy::CompleteTypeFromDWARF( + const lldb_private::plugin::dwarf::DWARFDIE &die, Type *type, + const CompilerType &comp_type) { + + if (!die) + return false; + + if (!comp_type) + return false; + + const dw_tag_t tag = die.Tag(); + if (tag == DW_TAG_structure_type || tag == DW_TAG_union_type) { + if (die.HasChildren()) + ParseChildMembers(die, comp_type); + + m_ast.CompleteStructType(comp_type); + return true; + } + return false; +} + +size_t DWARFASTParserLegacy::ParseChildParameters( + CompileUnit &comp_unit, + const lldb_private::plugin::dwarf::DWARFDIE &parent_die, bool &is_variadic, + std::vector &function_param_types) { + + if (!parent_die) + return 0; + + size_t arg_idx = 0; + for (lldb_private::plugin::dwarf::DWARFDIE die = parent_die.GetFirstChild(); + die.IsValid(); die = die.GetSibling()) { + dw_tag_t tag = die.Tag(); + switch (tag) { + case DW_TAG_formal_parameter: + assert(0 && "Funtions with parameters pending, yet!"); + default: + break; + } + } + return arg_idx; +} + +size_t DWARFASTParserLegacy::ParseChildMembers( + const lldb_private::plugin::dwarf::DWARFDIE &parent_die, + const CompilerType &struct_compiler_type) { + size_t member_idx = 0; + + for (lldb_private::plugin::dwarf::DWARFDIE die = parent_die.GetFirstChild(); + die.IsValid(); die = die.GetSibling()) { + dw_tag_t tag = die.Tag(); + + if (tag == DW_TAG_member) { + plugin::dwarf::DWARFAttributes attributes; + const char *name = NULL; + plugin::dwarf::DWARFFormValue encoding_uid; + attributes = die.GetAttributes(); + const size_t num_attributes = attributes.Size(); + uint32_t member_offset_in_bits = UINT32_MAX; + for (size_t i = 0; i < num_attributes; ++i) { + const dw_attr_t attr = attributes.AttributeAtIndex(i); + plugin::dwarf::DWARFFormValue form_value; + + if (attributes.ExtractFormValueAtIndex(i, form_value)) { + switch (attr) { + default: + break; + 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()) { + assert(0 && "Data member location expr pending."); + return 0; + } else { + member_offset_in_bits = form_value.Unsigned() * 8; + } + break; + case DW_AT_data_bit_offset: + member_offset_in_bits = form_value.Unsigned(); + break; + } + } + } + + Type *member_type = die.ResolveTypeUID(encoding_uid.Reference()); + if (member_type) { + CompilerType member_full_type = member_type->GetFullCompilerType(); + m_ast.AddFieldToStruct(struct_compiler_type, ConstString(name), + member_full_type, member_offset_in_bits); + } + ++member_idx; + } + } + + return 0; +} diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserLegacy.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserLegacy.h new file mode 100644 index 00000000000000..5c17c1aabb14f3 --- /dev/null +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserLegacy.h @@ -0,0 +1,91 @@ +//===-- DWARFASTParserLegacy.h---------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef SymbolFileDWARF_DWARFASTParserLegacy_h_ +#define SymbolFileDWARF_DWARFASTParserLegacy_h_ + +#include "DWARFASTParser.h" +#include "DWARFDIE.h" +#include "DWARFDefines.h" +#include "LogChannelDWARF.h" +#include "Plugins/TypeSystem/Legacy/TypeSystemLegacy.h" +#include "lldb/Core/PluginInterface.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallVector.h" + +namespace lldb_private { +class CompileUnit; +} + +class DWARFDebugInfoEntry; +class DWARFDIECollection; + +class DWARFASTParserLegacy + : public lldb_private::plugin::dwarf::DWARFASTParser { +public: + DWARFASTParserLegacy(lldb_private::TypeSystemLegacy &ast); + + ~DWARFASTParserLegacy() override; + + lldb::TypeSP + ParseTypeFromDWARF(const lldb_private::SymbolContext &sc, + const lldb_private::plugin::dwarf::DWARFDIE &die, + bool *type_is_new_ptr) override; + + lldb_private::Function * + ParseFunctionFromDWARF(lldb_private::CompileUnit &comp_unit, + const lldb_private::plugin::dwarf::DWARFDIE &die, + const lldb_private::AddressRange &func_range) override; + + bool CompleteTypeFromDWARF(const lldb_private::plugin::dwarf::DWARFDIE &die, lldb_private::Type *type, + const lldb_private::CompilerType &legacy_type) override; + + + lldb_private::CompilerDeclContext GetDeclContextForUIDFromDWARF( + const lldb_private::plugin::dwarf::DWARFDIE &die) override { + return lldb_private::CompilerDeclContext(); + } + + lldb_private::CompilerDeclContext GetDeclContextContainingUIDFromDWARF( + const lldb_private::plugin::dwarf::DWARFDIE &die) override { + return lldb_private::CompilerDeclContext(); + } + + lldb_private::CompilerDecl GetDeclForUIDFromDWARF( + const lldb_private::plugin::dwarf::DWARFDIE &die) override { + return lldb_private::CompilerDecl(); + } + + void EnsureAllDIEsInDeclContextHaveBeenParsed( + lldb_private::CompilerDeclContext decl_context) override {} + + std::string GetDIEClassTemplateParams( + lldb_private::plugin::dwarf::DWARFDIE die) override { + return {}; + } + lldb_private::ConstString ConstructDemangledNameFromDWARF( + const lldb_private::plugin::dwarf::DWARFDIE &die) override { + return lldb_private::ConstString(); + } + +private: + lldb_private::TypeSystemLegacy &m_ast; + + size_t ParseChildParameters( + lldb_private::CompileUnit &comp_unit, + const lldb_private::plugin::dwarf::DWARFDIE &parent_die, + bool &is_variadic, + std::vector &function_param_types); + + size_t ParseChildMembers(const lldb_private::plugin::dwarf::DWARFDIE &die, + const lldb_private::CompilerType &class_compiler_type); +}; + +#endif // SymbolFileDWARF_DWARFASTParserLegacy_h_ diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp index 0a13c457a307ae..bb62c21f95c8ae 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp @@ -573,11 +573,13 @@ bool DWARFDIE::GetDIENamesAndRanges( std::optional &decl_file, std::optional &decl_line, std::optional &decl_column, std::optional &call_file, std::optional &call_line, std::optional &call_column, - lldb_private::DWARFExpressionList *frame_base) const { + lldb_private::DWARFExpressionList *frame_base, + lldb_private::DWARFExpressionList *static_link, + lldb_private::DWARFExpressionList *rc_frame_base) const { if (IsValid()) { return m_die->GetDIENamesAndRanges( GetCU(), name, mangled, ranges, decl_file, decl_line, decl_column, - call_file, call_line, call_column, frame_base); + call_file, call_line, call_column, frame_base, static_link, rc_frame_base); } else return false; } diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.h index e1318953a384cd..1ca5e840976b7a 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.h @@ -101,7 +101,9 @@ class DWARFDIE : public DWARFBaseDIE { std::optional &decl_file, std::optional &decl_line, std::optional &decl_column, std::optional &call_file, std::optional &call_line, std::optional &call_column, - DWARFExpressionList *frame_base) const; + DWARFExpressionList *frame_base, + lldb_private::DWARFExpressionList *static_link, + lldb_private::DWARFExpressionList *rc_frame_base) const; /// The range of all the children of this DIE. llvm::iterator_range children() const; diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp index e2660735ea7dec..d7f3178eb2c426 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp @@ -121,11 +121,13 @@ bool DWARFDebugInfoEntry::GetDIENamesAndRanges( DWARFRangeList &ranges, std::optional &decl_file, std::optional &decl_line, std::optional &decl_column, std::optional &call_file, std::optional &call_line, - std::optional &call_column, DWARFExpressionList *frame_base) const { + std::optional &call_column, DWARFExpressionList *frame_base, + DWARFExpressionList *static_link, DWARFExpressionList *rc_frame_base) const { dw_addr_t lo_pc = LLDB_INVALID_ADDRESS; dw_addr_t hi_pc = LLDB_INVALID_ADDRESS; std::vector dies; bool set_frame_base_loclist_addr = false; + bool set_static_link_loclist_addr = false; SymbolFileDWARF &dwarf = cu->GetSymbolFileDWARF(); lldb::ModuleSP module = dwarf.GetObjectFile()->GetModule(); @@ -226,6 +228,31 @@ bool DWARFDebugInfoEntry::GetDIENamesAndRanges( call_column = form_value.Unsigned(); break; + case DW_AT_static_link: + if (static_link) { + if (form_value.BlockData()) { + uint32_t block_offset = + form_value.BlockData() - data.GetDataStart(); + uint32_t block_length = form_value.Unsigned(); + *static_link = DWARFExpressionList( + module, DataExtractor(data, block_offset, block_length), cu); + } else { + DataExtractor data = cu->GetLocationData(); + const dw_offset_t offset = form_value.Unsigned(); + if (data.ValidOffset(offset)) { + data = DataExtractor(data, offset, data.GetByteSize() - offset); + *static_link = DWARFExpressionList(module, data, cu); + if (lo_pc != LLDB_INVALID_ADDRESS) { + assert(lo_pc >= cu->GetBaseAddress()); + // static_link->SetLocationListAddresses(cu->GetBaseAddress(), + // lo_pc); + } else { + set_static_link_loclist_addr = true; + } + } + } + } + break; case DW_AT_frame_base: if (frame_base) { if (form_value.BlockData()) { @@ -253,6 +280,18 @@ bool DWARFDebugInfoEntry::GetDIENamesAndRanges( } break; + case DW_AT_RAINCODE_frame_base: + if (rc_frame_base) { + if (form_value.BlockData()) { + uint32_t block_offset = + form_value.BlockData() - data.GetDataStart(); + uint32_t block_length = form_value.Unsigned(); + *rc_frame_base = DWARFExpressionList( + module, DataExtractor(data, block_offset, block_length), cu); + } + } + break; + default: break; } @@ -269,6 +308,11 @@ bool DWARFDebugInfoEntry::GetDIENamesAndRanges( } } + if (set_static_link_loclist_addr) { + dw_addr_t lowest_range_pc = ranges.GetMinRangeBase(0); + assert(lowest_range_pc >= cu->GetBaseAddress()); + } + if (set_frame_base_loclist_addr) { dw_addr_t lowest_range_pc = ranges.GetMinRangeBase(0); assert(lowest_range_pc >= cu->GetBaseAddress()); diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h index 3816c6500717af..53e6db697160aa 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h @@ -114,7 +114,9 @@ class DWARFDebugInfoEntry { std::optional &call_file, std::optional &call_line, std::optional &call_column, - DWARFExpressionList *frame_base = nullptr) const; + DWARFExpressionList *frame_base = nullptr, + lldb_private::DWARFExpressionList *static_link = nullptr, + lldb_private::DWARFExpressionList *rc_frame_base = nullptr) const; const llvm::DWARFAbbreviationDeclaration * GetAbbreviationDeclarationPtr(const DWARFUnit *cu) const; diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp index 0eb882b0e7d4f5..2bf70513435d65 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp @@ -798,6 +798,32 @@ llvm::VersionTuple DWARFUnit::GetProducerVersion() { return m_producer_version; } +IdentifierCaseType DWARFUnit::IdentifierCaseFromDWARF(uint64_t val) { + switch(val) { + case DW_ID_up_case: + return eUpperCase; + case DW_ID_down_case: + return eLowerCase; + case DW_ID_case_insensitive: + return eCaseInsensitive; + default: + return eCaseSensitive; + } +} + +LanguageType DWARFUnit::LanguageTypeFromDWARF(uint64_t val) { + // Note: user languages between lo_user and hi_user must be handled + // explicitly here. + switch (val) { + case DW_LANG_Mips_Assembler: + return eLanguageTypeMipsAssembler; + case DW_LANG_GOOGLE_RenderScript: + return eLanguageTypeRenderScript; + default: + return static_cast(val); + } +} + uint64_t DWARFUnit::GetDWARFLanguageType() { if (m_language_type) return *m_language_type; diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h index 1267e20f087121..8732836678e5e6 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h @@ -186,6 +186,12 @@ class DWARFUnit : public UserID { uint64_t GetDWARFLanguageType(); + static lldb::LanguageType LanguageTypeFromDWARF(uint64_t val); + + static lldb::IdentifierCaseType IdentifierCaseFromDWARF(uint64_t val); + + lldb::LanguageType GetLanguageType(); + bool GetIsOptimized(); const FileSpec &GetCompilationDirectory(); @@ -329,6 +335,7 @@ class DWARFUnit : public UserID { DWARFProducer m_producer = eProducerInvalid; llvm::VersionTuple m_producer_version; std::optional m_language_type; + lldb::IdentifierCaseType m_identifier_case = lldb::eCaseUnknown; LazyBool m_is_optimized = eLazyBoolCalculate; std::optional m_comp_dir; std::optional m_file_spec; diff --git a/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp b/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp index d581d3773ab23e..9d2f15703916d7 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp @@ -151,6 +151,10 @@ void ManualDWARFIndex::IndexUnit(DWARFUnit &unit, SymbolFileDWARFDwo *dwp, } const LanguageType cu_language = SymbolFileDWARF::GetLanguage(unit); + if ((cu_language == eLanguageTypeCobol85) || + (cu_language == eLanguageTypeCobol74) || + (cu_language == eLanguageTypePLI)) + SetNameCaseInsensitive(); // First check if the unit has a DWO ID. If it does then we only want to index // the .dwo file or nothing at all. If we have a compile unit where we can't diff --git a/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.h b/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.h index d8c4a22ab21f7b..75f10725d848ba 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.h @@ -168,6 +168,17 @@ class ManualDWARFIndex : public DWARFIndex { const lldb::LanguageType cu_language, IndexSet &set); + void SetNameCaseInsensitive() { + m_set.function_basenames.SetNameCaseInsensitive(); + m_set.function_fullnames.SetNameCaseInsensitive(); + m_set.function_methods.SetNameCaseInsensitive(); + m_set.function_selectors.SetNameCaseInsensitive(); + m_set.objc_class_selectors.SetNameCaseInsensitive(); + m_set.globals.SetNameCaseInsensitive(); + m_set.types.SetNameCaseInsensitive(); + m_set.namespaces.SetNameCaseInsensitive(); + } + /// The DWARF file which we are indexing. SymbolFileDWARF *m_dwarf; /// Which dwarf units should we skip while building the index. diff --git a/lldb/source/Plugins/SymbolFile/DWARF/NameToDIE.cpp b/lldb/source/Plugins/SymbolFile/DWARF/NameToDIE.cpp index 44d90648700cfb..2cb7aaecbc7873 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/NameToDIE.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/NameToDIE.cpp @@ -33,9 +33,12 @@ void NameToDIE::Insert(ConstString name, const DIERef &die_ref) { bool NameToDIE::Find(ConstString name, llvm::function_ref callback) const { - for (const auto &entry : m_map.equal_range(name)) - if (!callback(entry.value)) - return false; + for (const auto &entry : m_map) + if (ConstString::Equals(ConstString(entry.cstring.GetCString()), name, + !NameCaseInsensitive)) { + if (!callback(entry.value)) + return false; + } return true; } diff --git a/lldb/source/Plugins/SymbolFile/DWARF/NameToDIE.h b/lldb/source/Plugins/SymbolFile/DWARF/NameToDIE.h index 90eac1fa373381..458eef604307ed 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/NameToDIE.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/NameToDIE.h @@ -85,8 +85,11 @@ class NameToDIE { void Clear() { m_map.Clear(); } + void SetNameCaseInsensitive() { NameCaseInsensitive = true; } + protected: UniqueCStringMap m_map; + bool NameCaseInsensitive = false; }; } // namespace dwarf } // namespace lldb_private::plugin diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp index f721ca00fd3559..73d5bcd62db6f2 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -1370,7 +1370,7 @@ size_t SymbolFileDWARF::ParseBlocksRecursive( std::optional call_column; if (die.GetDIENamesAndRanges(name, mangled_name, ranges, decl_file, decl_line, decl_column, call_file, call_line, - call_column, nullptr)) { + call_column, nullptr, nullptr, nullptr)) { if (tag == DW_TAG_subprogram) { assert(subprogram_low_pc == LLDB_INVALID_ADDRESS); subprogram_low_pc = ranges.GetMinRangeBase(0); @@ -3499,8 +3499,12 @@ VariableSP SymbolFileDWARF::ParseVariableDIE(const SymbolContext &sc, DWARFFormValue type_die_form; bool is_external = false; bool is_artificial = false; + bool has_descriptor = false; DWARFFormValue const_value_form, location_form; Variable::RangeList scope_ranges; + uint8_t lexical_scope = 0; + VariableSP var_sp; + DWARFDIE spec_die; for (size_t i = 0; i < attributes.Size(); ++i) { dw_attr_t attr = attributes.AttributeAtIndex(i); @@ -3522,6 +3526,13 @@ VariableSP SymbolFileDWARF::ParseVariableDIE(const SymbolContext &sc, case DW_AT_name: name = form_value.AsCString(); break; + case DW_AT_RAINCODE_desc_type: + // TODO handle descriptor list/locator form values + has_descriptor = true; + break; + case DW_AT_RAINCODE_lexical_scope: + lexical_scope = form_value.Unsigned(); + break; case DW_AT_linkage_name: case DW_AT_MIPS_linkage_name: mangled = form_value.AsCString(); @@ -3549,6 +3560,8 @@ VariableSP SymbolFileDWARF::ParseVariableDIE(const SymbolContext &sc, case DW_AT_endianity: case DW_AT_segment: case DW_AT_specification: + spec_die = form_value.Reference(); + break; case DW_AT_visibility: default: case DW_AT_abstract_origin: @@ -3738,10 +3751,19 @@ VariableSP SymbolFileDWARF::ParseVariableDIE(const SymbolContext &sc, die.GetCU()->GetAddressByteSize()); } - return std::make_shared( + var_sp = std::make_shared( die.GetID(), name, mangled, type_sp, scope, symbol_context_scope, scope_ranges, &decl, location_list, is_external, is_artificial, - location_is_const_value_data, is_static_member); + location_is_const_value_data, is_static_member, has_descriptor, + lexical_scope); + // Cache var_sp even if NULL (the variable was just a specification or was + // missing vital information to be able to be displayed in the debugger + // (missing location due to optimization, etc)) so we don't re-parse this + // DIE over and over later... + GetDIEToVariable()[die.GetDIE()] = var_sp; + if (spec_die) + GetDIEToVariable()[spec_die.GetDIE()] = var_sp; + return var_sp; } DWARFDIE diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h index 4967b37d753a09..e6504229c219b9 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h @@ -83,6 +83,7 @@ class SymbolFileDWARF : public SymbolFileCommon { friend class DWARFCompileUnit; friend class DWARFDIE; friend class DWARFASTParser; + friend class DWARFASTParserLegacy; // Static Functions static void Initialize(); @@ -369,6 +370,7 @@ class SymbolFileDWARF : public SymbolFileCommon { /// Returns the DWARFIndex for this symbol, if it exists. DWARFIndex *getIndex() { return m_index.get(); } + bool FixupAddress(Address &addr); protected: SymbolFileDWARF(const SymbolFileDWARF &) = delete; @@ -477,8 +479,6 @@ class SymbolFileDWARF : public SymbolFileCommon { /// needed, on success and LLDB_INVALID_ADDRESS otherwise. lldb::addr_t FixupAddress(lldb::addr_t file_addr); - bool FixupAddress(Address &addr); - typedef llvm::SetVector TypeSet; void GetTypes(const DWARFDIE &die, dw_offset_t min_die_offset, diff --git a/lldb/source/Plugins/TypeSystem/CMakeLists.txt b/lldb/source/Plugins/TypeSystem/CMakeLists.txt index 17c40aee44cc27..1cc6d101dda601 100644 --- a/lldb/source/Plugins/TypeSystem/CMakeLists.txt +++ b/lldb/source/Plugins/TypeSystem/CMakeLists.txt @@ -1 +1,2 @@ add_subdirectory(Clang) +add_subdirectory(Legacy) diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h index e39aedec7e3902..f58fbfb04ff7ac 100644 --- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h +++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h @@ -647,7 +647,8 @@ class TypeSystemClang : public TypeSystem { bool IsConst(lldb::opaque_compiler_type_t type) override; - bool IsCStringType(lldb::opaque_compiler_type_t type, uint32_t &length); + bool IsCStringType(lldb::opaque_compiler_type_t type, + uint32_t &length) override; static bool IsCXXClassType(const CompilerType &type); diff --git a/lldb/source/Plugins/TypeSystem/Legacy/CMakeLists.txt b/lldb/source/Plugins/TypeSystem/Legacy/CMakeLists.txt new file mode 100644 index 00000000000000..a6f83477d883ea --- /dev/null +++ b/lldb/source/Plugins/TypeSystem/Legacy/CMakeLists.txt @@ -0,0 +1,16 @@ +add_lldb_library(lldbPluginTypeSystemLegacy PLUGIN + TypeSystemLegacy.cpp + + LINK_LIBS + lldbCore + lldbSymbol + lldbTarget + lldbUtility + lldbPluginExpressionParserCobol + lldbPluginExpressionParserPLI + lldbPluginSymbolFileDWARF + lldbPluginSymbolFilePDB + lldbPluginObjCRuntime + LINK_COMPONENTS + Support +) diff --git a/lldb/source/Plugins/TypeSystem/Legacy/TypeSystemLegacy.cpp b/lldb/source/Plugins/TypeSystem/Legacy/TypeSystemLegacy.cpp new file mode 100644 index 00000000000000..b681d25149ecc9 --- /dev/null +++ b/lldb/source/Plugins/TypeSystem/Legacy/TypeSystemLegacy.cpp @@ -0,0 +1,2213 @@ +//===-- TypeSystemLegacy.cpp -------------------------------------*- C++ +//-*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "TypeSystemLegacy.h" +#include "lldb/Core/Module.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Target/ExecutionContext.h" +#include "lldb/Target/Language.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/Target.h" + +#include "Plugins/ExpressionParser/Cobol/CobolUserExpression.h" +#include "Plugins/ExpressionParser/PLI/PLIUserExpression.h" +#include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h" +#include "Plugins/SymbolFile/DWARF/DWARFASTParserLegacy.h" +#include "lldb/Core/DumpDataExtractor.h" +#include "lldb/Host/StreamFile.h" +#include "lldb/Utility/DataExtractor.h" +#include "lldb/Utility/Endian.h" +#include "lldb/Utility/Log.h" + +#include +#include +#include + +using namespace lldb; +using namespace lldb_private; +using namespace llvm; +using namespace lldb_private::dwarf; + +LLDB_PLUGIN_DEFINE(TypeSystemLegacy) + +namespace lldb_private { +class LegacyFunction; +class LegacyArray; +class LegacyStruct; +class LegacyDynamicArray; + +class LegacyType { +public: + enum LLVMTypeKind { + KIND_INT, + KIND_UINT, + KIND_FLOAT, + KIND_DOUBLE, + + KIND_DISPLAY, + KIND_DECIMAL, + KIND_EDITED, + + KIND_ARRAY, + KIND_STRUCT, + KIND_PTR, + KIND_FUNC, + + KIND_DYNAMIC, + KIND_INVALID, + + KIND_L88, + + KIND_MASK = (1 << 5) - 1, + KIND_MAX = (1 << 5), + + }; + + enum LLVMSign { + eUnsigned, + eLeadingOverpunch, + eTrailingOverpunch, + eLeadingSeparate, + eTrailingSeparate, + }; + + LegacyType(int kind, const ConstString &name) + : m_kind(kind & KIND_MASK), m_name(name), m_bitsize(0), m_sign(eUnsigned), + m_digit_count(0), m_byte_order(eByteOrderBig), bin_scale(false) {} + LegacyType(int kind, const ConstString &name, const ConstString &pic_string, + uint32_t bitsize, int sign, int scale, uint32_t digit_count, + ByteOrder byte_order, bool bin_scale) + : m_kind(kind & KIND_MASK), m_name(name), m_pic_string(pic_string), + m_bitsize(bitsize), m_sign(sign), m_scale(scale), + m_digit_count(digit_count), m_byte_order(byte_order), + bin_scale(bin_scale) {} + + virtual ~LegacyType() {} + + int GetLegacyKind() const { return m_kind; } + const ConstString &GetTypeName() const { return m_name; } + const ConstString &GetPicString() const { return m_pic_string; } + ByteOrder GetTypeByteOrder() const { return m_byte_order; } + uint32_t GetTypeBitSize() const { return m_bitsize; } + uint32_t GetSign() const { return m_sign; } + int32_t GetScale() const { return m_scale; } + uint32_t GetDigitCount() const { return m_digit_count; } + bool is_binary_scale() const { return bin_scale; } + void EditString(std::string &data); + virtual CompilerType GetElementType() const { return CompilerType(); } + LegacyFunction *GetFunction(); + LegacyArray *GetArray(); + LegacyStruct *GetStruct(); + LegacyDynamicArray *GetDynamicArray(); + +private: + int m_kind; + ConstString m_name; + ConstString m_pic_string; + uint32_t m_bitsize; + uint32_t m_sign; + int32_t m_scale; + uint32_t m_digit_count; + ByteOrder m_byte_order; + const bool bin_scale; + LegacyType(const LegacyType &) = delete; + const LegacyType &operator=(const LegacyType &) = delete; +}; + +class LegacyElem : public LegacyType { +public: + LegacyElem(int kind, const ConstString &name, const CompilerType &elem) + : LegacyType(kind, name), m_elem(elem) {} + virtual CompilerType GetElementType() const override { return m_elem; } + +private: + CompilerType m_elem; + + LegacyElem(const LegacyElem &) = delete; + const LegacyElem &operator=(const LegacyElem &) = delete; +}; + +class LegacyArray : public LegacyElem { +public: + LegacyArray(const ConstString array_type_name, const ConstString &name, + const CompilerType &elem, uint64_t length, + bool isVarString = false) + : LegacyElem(KIND_ARRAY, name, elem), m_array_type_name(array_type_name), + m_length(length), m_var_string(isVarString) {} + + static bool classof(const LegacyType *type) { + return type->GetLegacyKind() == LegacyType::KIND_ARRAY; + } + + uint64_t GetLength() const { return m_length; } + const ConstString &GetArrayTypeName() const { return m_array_type_name; } + + bool isVarString() const { return m_var_string; } + virtual bool isDynamic() const { return false; } + +protected: + void SetLength(uint64_t length) { m_length = length; } + +private: + ConstString m_array_type_name; + uint64_t m_length; + bool m_var_string; + LegacyArray(const LegacyArray &) = delete; + const LegacyArray &operator=(const LegacyArray &) = delete; +}; + +class LegacyDynamicArray : public LegacyArray { +public: + LegacyDynamicArray(const ConstString array_type_name, const ConstString &name, + const CompilerType &elem, DWARFExpressionList count_exp, + bool isVarString = false) + : LegacyArray(array_type_name, name, elem, 0, isVarString), + m_count_exp(count_exp) {} + + static bool classof(const LegacyType *type) { + return type->GetLegacyKind() == LegacyType::KIND_ARRAY && + (static_cast(type)->isDynamic()); + } + + DWARFExpressionList GetCountExp() const { return m_count_exp; } + + void UpdateLength(uint64_t length) { SetLength(length); } + + bool isDynamic() const override { return true; } + +private: + const DWARFExpressionList m_count_exp; + LegacyDynamicArray(const LegacyDynamicArray &) = delete; + const LegacyDynamicArray &operator=(const LegacyDynamicArray &) = delete; +}; + +class LegacyFunction : public LegacyType { +public: + LegacyFunction(const ConstString &name, const CompilerType *params, + uint32_t numargs, bool is_variadic) + : LegacyType(KIND_FUNC, name), m_is_variadic(is_variadic), + m_params(params, params + numargs) {} + + bool IsVariadic() const { return m_is_variadic; } + CompilerType GetArgumentAtIndex(size_t index) const { + if (index >= m_params.size()) + return CompilerType(); + return m_params[index]; + } + +private: + bool m_is_variadic; + std::vector m_params; + LegacyFunction(const LegacyFunction &) = delete; + const LegacyFunction &operator=(const LegacyFunction &) = delete; +}; + +class LegacyDynamic : public LegacyType { +public: + LegacyDynamic(const CompilerType &base_type, DWARFExpressionList location, + DWARFExpressionList allocated) + : LegacyType(KIND_DYNAMIC, ConstString()), m_type(base_type), + m_location(location), m_allocated(allocated) {} + + CompilerType GetBaseType() const { return m_type; } + DWARFExpressionList getAllocated() const { return m_allocated; } + DWARFExpressionList getLocation() const { return m_location; } + +private: + CompilerType m_type; + DWARFExpressionList m_location; + DWARFExpressionList m_allocated; + + LegacyDynamic(const LegacyDynamic &) = delete; + const LegacyDynamic &operator=(const LegacyDynamic &) = delete; +}; + +class LegacyStruct : public LegacyType { +public: + struct Member { + Member(const ConstString &name, const CompilerType &type, + uint64_t offset_in_bits) + : m_name(name), m_type(type), m_offset_in_bits(offset_in_bits) {} + ConstString m_name; + CompilerType m_type; + uint32_t m_offset_in_bits; + + ConstString GetMemberName() const { return m_name; } + }; + + LegacyStruct(const ConstString &name, int64_t byte_size) + : LegacyType(KIND_STRUCT, name), m_byte_size(byte_size), + m_is_complete(false) {} + + uint32_t GetNumMembers() const { return m_members.size(); } + const Member *GetMemberAtIndex(uint32_t i) const { + return i < GetNumMembers() ? &m_members[i] : nullptr; + } + bool IsComplete() const { return m_is_complete; } + + void SetComplete() { m_is_complete = true; } + int64_t GetByteSize() const { return m_byte_size; } + void AddMember(const ConstString &name, const CompilerType &type, + uint64_t offset_in_bits) { + m_members.push_back(Member(name, type, offset_in_bits)); + } + +private: + int64_t m_byte_size; + bool m_is_complete; + std::vector m_members; + + LegacyStruct(const LegacyStruct &) = delete; + const LegacyStruct &operator=(const LegacyStruct &) = delete; +}; + +LegacyArray *LegacyType::GetArray() { + if (m_kind == KIND_ARRAY) + return static_cast(this); + return nullptr; +} + +LegacyDynamicArray *LegacyType::GetDynamicArray() { + if (m_kind == KIND_ARRAY) { + LegacyArray *array = static_cast(this); + if (array->isDynamic()) + return static_cast(array); + } + return nullptr; +} + +LegacyFunction *LegacyType::GetFunction() { + if (m_kind == KIND_FUNC) + return static_cast(this); + return nullptr; +} + +LegacyStruct *LegacyType::GetStruct() { + if (m_kind == KIND_STRUCT) + return static_cast(this); + return nullptr; +} + +} // namespace lldb_private + +namespace { +static inline bool TypeSystemLegacySupportsLanguage(LanguageType language) { + return language == eLanguageTypePLI || language == eLanguageTypeCobol74 || + language == eLanguageTypeCobol85 || language == eLanguageTypeFortran90; +} + +static inline uint8_t EncodePackedSign(const uint8_t in) { + switch (in) { + default: + return in - '0'; + case '-': + return 0xD; // preferred + return 0xB; + case '+': + case ' ': + return 0xC; // preferred + return 0xF; + } +} + +static inline char EncodeOverpunchDigit(char in, bool isPositive) { + switch (in) { + case '0': + return isPositive ? '{' : '}'; + case '1': + return isPositive ? 'A' : 'J'; + case '2': + return isPositive ? 'B' : 'K'; + case '3': + return isPositive ? 'C' : 'L'; + case '4': + return isPositive ? 'D' : 'M'; + case '5': + return isPositive ? 'E' : 'N'; + case '6': + return isPositive ? 'F' : 'O'; + case '7': + return isPositive ? 'G' : 'P'; + case '8': + return isPositive ? 'H' : 'Q'; + case '9': + return isPositive ? 'I' : 'R'; + } + return 0; +} + +static inline uint8_t DecodePackedSignToString(const uint8_t in) { + switch (in) { + default: + return in + '0'; + case 0xA: + case 0xC: + case 0xE: + return '+'; + case 0xB: + case 0xD: + return '-'; + case 0xF: + return ' '; + } +} + +static inline char DecodeOverpunchDigit(char &in) { + switch (in) { + case '}': + in = '0'; + return '-'; + case 'J': + in = '1'; + return '-'; + case 'K': + in = '2'; + return '-'; + case 'L': + in = '3'; + return '-'; + case 'M': + in = '4'; + return '-'; + case 'N': + in = '5'; + return '-'; + case 'O': + in = '6'; + return '-'; + case 'P': + in = '7'; + return '-'; + case 'Q': + in = '8'; + return '-'; + case 'R': + in = '9'; + return '-'; + case '{': + in = '0'; + return '+'; + case 'A': + in = '1'; + return '+'; + case 'B': + in = '2'; + return '+'; + case 'C': + in = '3'; + return '+'; + case 'D': + in = '4'; + return '+'; + case 'E': + in = '5'; + return '+'; + case 'F': + in = '6'; + return '+'; + case 'G': + in = '7'; + return '+'; + case 'H': + in = '8'; + return '+'; + case 'I': + in = '9'; + return '+'; + } + return 0; +} + +} // namespace + +//---------------------------------------------------------------------- +// Tests +//---------------------------------------------------------------------- + +char TypeSystemLegacy::ID; + +#ifndef NDEBUG +bool TypeSystemLegacy::Verify(lldb::opaque_compiler_type_t type) { + // TODO add more checks. + return type; +} +#endif + +void LegacyType::EditString(std::string &data) { + if (m_kind != KIND_EDITED) + return; + // TODO + std::string buffer(data); + + return; +} + +bool TypeSystemLegacy::IsArrayType(opaque_compiler_type_t type, + CompilerType *element_type, uint64_t *size, + bool *is_incomplete) { + if (element_type) + element_type->Clear(); + if (size) + *size = 0; + if (is_incomplete) + *is_incomplete = false; + + if (LegacyArray *array = static_cast(type)->GetArray()) { + if (element_type) + *element_type = array->GetElementType(); + if (size) + *size = array->GetLength(); + return true; + } + + if (static_cast(type)->GetLegacyKind() == + LegacyType::KIND_DYNAMIC) { + const auto dyn_base_type = + static_cast(type)->GetBaseType(); + return dyn_base_type.IsArrayType(element_type, size, is_incomplete); + } + + return false; +} + +bool TypeSystemLegacy::IsIntegerType(opaque_compiler_type_t type, + bool &is_signed) { + is_signed = false; + + if (type) { + int kind = static_cast(type)->GetLegacyKind(); + switch (kind) { + case LegacyType::KIND_INT: + is_signed = true; + return true; + case LegacyType::KIND_UINT: + case LegacyType::KIND_DECIMAL: + return true; + } + } + + if (static_cast(type)->GetLegacyKind() == + LegacyType::KIND_DYNAMIC) { + const auto dyn_base_type = + static_cast(type)->GetBaseType(); + return dyn_base_type.IsIntegerType(is_signed); + } + + return false; +} + +bool TypeSystemLegacy::IsFloatingPointType(opaque_compiler_type_t type, + uint32_t &count, bool &is_complex) { + count = 0; + is_complex = false; + if (type) { + int kind = static_cast(type)->GetLegacyKind(); + switch (kind) { + case LegacyType::KIND_FLOAT: + case LegacyType::KIND_DOUBLE: + count = 1; + return true; + } + } + + if (static_cast(type)->GetLegacyKind() == + LegacyType::KIND_DYNAMIC) { + const auto dyn_base_type = + static_cast(type)->GetBaseType(); + return dyn_base_type.IsFloatingPointType(count, is_complex); + } + return false; +} + +bool TypeSystemLegacy::IsPointerType(opaque_compiler_type_t type, + CompilerType *pointee_type) { + if (!type) + return false; + + LegacyType *t = static_cast(type); + if (pointee_type) { + *pointee_type = t->GetElementType(); + } + + switch (t->GetLegacyKind()) { + case LegacyType::KIND_PTR: + return true; + case LegacyType::KIND_DYNAMIC: { + const auto dyn_base_type = + static_cast(type)->GetBaseType(); + return dyn_base_type.IsPointerType(pointee_type); + } + default: + return false; + } +} + +bool TypeSystemLegacy::IsAggregateType(opaque_compiler_type_t type) { + if (!type) + return false; + + int kind = static_cast(type)->GetLegacyKind(); + switch (kind) { + case LegacyType::KIND_STRUCT: + case LegacyType::KIND_ARRAY: + return true; + case LegacyType::KIND_DYNAMIC: { + const auto dyn_base_type = + static_cast(type)->GetBaseType(); + return dyn_base_type.IsAggregateType(); + } + } + return false; +} + +bool TypeSystemLegacy::IsCharType(opaque_compiler_type_t type) { + if (static_cast(type)->GetLegacyKind() == + LegacyType::KIND_DISPLAY) { + return true; + } + + if (static_cast(type)->GetLegacyKind() == + LegacyType::KIND_DYNAMIC) { + const auto dyn_base_type = + static_cast(type)->GetBaseType(); + return dyn_base_type.IsCharType(); + } + return false; +} + +unsigned TypeSystemLegacy::GetPtrAuthKey(lldb::opaque_compiler_type_t type) { + // Since TypeSystemLegacy do not handle pointer authentication, return a default value. + return 0; +} + +unsigned TypeSystemLegacy::GetPtrAuthDiscriminator(lldb::opaque_compiler_type_t type) { + // Provide a default implementation. + return 0; +} + +bool TypeSystemLegacy::GetPtrAuthAddressDiversity(lldb::opaque_compiler_type_t type) { + // Return a default value. + return false; +} + +bool TypeSystemLegacy::IsFunctionType(opaque_compiler_type_t type) { + switch (static_cast(type)->GetLegacyKind()) { + default: + break; + case LegacyType::KIND_FUNC: + return true; + case LegacyType::KIND_DYNAMIC: { + const auto dyn_base_type = + static_cast(type)->GetBaseType(); + return dyn_base_type.IsFunctionType(); + } + } + return false; +} + +bool TypeSystemLegacy::IsPointerOrReferenceType(opaque_compiler_type_t type, + CompilerType *pointee_type) { + return IsPointerType(type, pointee_type); +} + +uint32_t TypeSystemLegacy::IsHomogeneousAggregate(opaque_compiler_type_t type, + CompilerType *base_type_ptr) { + return false; +} + +bool TypeSystemLegacy::IsBeingDefined(opaque_compiler_type_t type) { + return false; +} + +bool TypeSystemLegacy::IsPolymorphicClass(opaque_compiler_type_t type) { + return false; +} + +bool TypeSystemLegacy::IsVectorType(opaque_compiler_type_t type, + CompilerType *element_type, + uint64_t *size) { + if (element_type) + element_type->Clear(); + if (size) + *size = 0; + return false; +} + +bool TypeSystemLegacy::IsConst(opaque_compiler_type_t type) { return false; } + +bool TypeSystemLegacy::IsCStringType(opaque_compiler_type_t type, + uint32_t &length) { + if (!type) + return false; + + LegacyType *base_type = static_cast(type); + if (LegacyArray *array = base_type->GetArray()) { + if (array->GetElementType().IsCharType()) { + length = array->GetLength() + (array->isVarString() ? 2UL : 0UL); + return true; + } + } + if (static_cast(type)->GetLegacyKind() == + LegacyType::KIND_DYNAMIC) { + const auto dyn_base_type = + static_cast(type)->GetBaseType(); + return dyn_base_type.IsCStringType(length); + } + return false; +} + +bool TypeSystemLegacy::IsTypedefType(opaque_compiler_type_t type) { + return false; +} + +bool TypeSystemLegacy::IsReferenceType(opaque_compiler_type_t type, + CompilerType *pointee_type, + bool *is_rvalue) { + return false; +} + +CompilerType TypeSystemLegacy::MutateBaseTypeSize(opaque_compiler_type_t type, + uint64_t sizeInBits) { + if (!type) + return CompilerType(); + if (IsAggregateType(type)) + return CompilerType(); + ConstString dst_type_name(GetTypeName(type, true).GetCString() + + std::string(".m.") + std::to_string(sizeInBits)); + LegacyType *dst_type = (*m_mutated_types)[dst_type_name].get(); + if (dst_type) + return CompilerType(weak_from_this(), dst_type); + + LegacyType *src_type = static_cast(type); + if (src_type->GetTypeBitSize() == sizeInBits) + return CompilerType(weak_from_this(), type); + + dst_type = + new LegacyType(src_type->GetLegacyKind(), src_type->GetTypeName(), + src_type->GetPicString(), sizeInBits, src_type->GetSign(), + src_type->GetScale(), src_type->GetDigitCount(), + src_type->GetTypeByteOrder(), src_type->is_binary_scale()); + (*m_mutated_types)[dst_type_name].reset(dst_type); + return CompilerType(weak_from_this(), dst_type); +} + +CompilerType +TypeSystemLegacy::GetFunctionReturnType(opaque_compiler_type_t type) { + if (!type) + return CompilerType(); + if (auto func = static_cast(type)) + return func->GetArgumentAtIndex(0); + return CompilerType(); +} + +CompilerType TypeSystemLegacy::GetPointeeType(opaque_compiler_type_t type) { + if (!type) + return CompilerType(); + return static_cast(type)->GetElementType(); +} + +CompilerType TypeSystemLegacy::GetPointerType(opaque_compiler_type_t type) { + if (!type) + return CompilerType(); + + LegacyType *base_type = static_cast(type); + LegacyType *pointer = (*m_types)[base_type].get(); + if (pointer == nullptr) { + ConstString type_name = GetTypeName(type, true); + ConstString pointer_name(std::string("*") + type_name.GetCString()); + pointer = new LegacyElem(LegacyType::KIND_PTR, pointer_name, + CompilerType(weak_from_this(), type)); + (*m_types)[base_type].reset(pointer); + } + return CompilerType(weak_from_this(), pointer); +} + +CompilerType +TypeSystemLegacy::GetLValueReferenceType(opaque_compiler_type_t type) { + if (!type) + return CompilerType(); + + // TODOa + Host::SystemLog(lldb::eSeverityInfo, "Warning: DW_TAG_reference_type not supported."); + return CompilerType(); +} + +CompilerType TypeSystemLegacy::GetTypedefedType(opaque_compiler_type_t type) { + return CompilerType(); +} + +CompilerType +TypeSystemLegacy::GetNonReferenceType(opaque_compiler_type_t type) { + return CompilerType(weak_from_this(), type); +} + +bool TypeSystemLegacy::GetCompleteType(opaque_compiler_type_t type) { + if (!type) + return false; + + LegacyType *t = static_cast(type); + if (t->GetArray()) + return t->GetElementType().GetCompleteType(); + + if (LegacyStruct *s = t->GetStruct()) { + if (s->IsComplete()) + return true; + CompilerType compiler_type(weak_from_this(), s); + SymbolFile *symbols = GetSymbolFile(); + return symbols && symbols->CompleteType(compiler_type); + } + + if (static_cast(type)->GetLegacyKind() == + LegacyType::KIND_DYNAMIC) { + const auto dyn_base_type = + static_cast(type)->GetBaseType(); + return dyn_base_type.GetCompleteType(); + } + return true; +} + +ConstString TypeSystemLegacy::GetTypeName(opaque_compiler_type_t type, + bool baseType) { + if (!type) + return ConstString(); + + LegacyType *base_type = static_cast(type); + if (LegacyArray *array = base_type->GetArray()) { + ConstString type_name = array->GetArrayTypeName(); + if (!type_name.IsEmpty()) + return type_name; + + ConstString array_base_type_name = array->GetElementType().GetTypeName(); + size_t length = array->GetLength(); + if (array_base_type_name == "BIT") + length *= 8; + ConstString array_type_name(array_base_type_name.GetCString() + + std::string(" [") + std::to_string(length) + + std::string("]")); + return array_type_name; + } + + if (static_cast(type)->GetLegacyKind() == + LegacyType::KIND_DYNAMIC) { + const auto dyn_base_type = + static_cast(type)->GetBaseType(); + return dyn_base_type.GetTypeName(); + } + return base_type->GetTypeName(); +} + +uint32_t +TypeSystemLegacy::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; + + uint32_t flags = eTypeHasValue | eTypeIsBuiltIn | eTypeIsScalar; + auto legacy_type = static_cast(type); + auto type_kind = legacy_type->GetLegacyKind(); + switch (type_kind) { + case LegacyType::KIND_FLOAT: + case LegacyType::KIND_DOUBLE: + flags |= eTypeIsFloat; + break; + case LegacyType::KIND_UINT: + flags |= eTypeIsInteger; + break; + case LegacyType::KIND_INT: + flags |= eTypeIsInteger | eTypeIsSigned; + break; + case LegacyType::KIND_ARRAY: { + if (pointee_or_element_compiler_type) + *pointee_or_element_compiler_type = legacy_type->GetElementType(); + flags = eTypeHasChildren | eTypeIsArray; + + const auto array_type = legacy_type->GetArray(); + if (array_type->isVarString()) + flags |= eTypeIsVarString; + + if (array_type->isDynamic()) + flags |= eTypeIsDynamic; + + // FIXME + uint32_t length; + if (IsCStringType(type, length)) + flags |= eTypeHasValue; + } break; + case LegacyType::KIND_PTR: + flags = eTypeIsPointer | eTypeHasValue | eTypeHasChildren; + break; + case LegacyType::KIND_STRUCT: + flags = eTypeHasChildren | eTypeIsStructUnion; + break; + case LegacyType::KIND_DYNAMIC: { + const auto dyn_base_ty = static_cast(type)->GetBaseType(); + flags = eTypeIsDynamic | (dyn_base_ty.GetTypeInfo()); + break; + } + case LegacyType::KIND_DECIMAL: + case LegacyType::KIND_DISPLAY: + case LegacyType::KIND_EDITED: + default: + break; + } + return flags; +} + +bool TypeSystemLegacy::SupportsLanguage(LanguageType language) { + return TypeSystemLegacySupportsLanguage(language); +} + +LanguageType TypeSystemLegacy::GetMinimumLanguage(opaque_compiler_type_t type) { + return GetLanguage(); +} + +static inline std::string +getStringFromDataExtractor(const lldb_private::DataExtractor &data, + uint32_t src_tyk, int32_t scale, + bool is_binscale = false) { + offset_t offset = 0; + switch (src_tyk) { + case LegacyType::KIND_UINT: + case LegacyType::KIND_INT: { + const size_t length = data.GetByteSize(); + auto value = data.GetMaxS64(&offset, length); + if (is_binscale && scale != 0) + value /= std::pow(2, scale); + return std::to_string(value); + } + case LegacyType::KIND_FLOAT: { + auto value = data.GetFloat(&offset); + if (is_binscale && scale != 0) + value /= std::pow(2, scale); + return std::to_string(value); + } + case LegacyType::KIND_DOUBLE: { + auto value = data.GetDouble(&offset); + if (is_binscale && scale != 0) + value /= std::pow(2, scale); + return std::to_string(value); + } + default: + break; + } + return std::string(data.PeekCStr(0), data.GetByteSize()); +} + +bool TypeSystemLegacy::VerifyEncodeType(opaque_compiler_type_t src_type, + opaque_compiler_type_t dst_type) { + if (!src_type || !dst_type) + return false; + + const auto dst_tyk = static_cast(dst_type)->GetLegacyKind(); + const auto src_tyk = static_cast(src_type)->GetLegacyKind(); + switch (dst_tyk) { + case LegacyType::KIND_PTR: + case LegacyType::KIND_INT: + case LegacyType::KIND_UINT: + return (src_tyk == LegacyType::KIND_UINT) || + (src_tyk == LegacyType::KIND_INT); + case LegacyType::KIND_DOUBLE: + case LegacyType::KIND_FLOAT: + return (src_tyk == LegacyType::KIND_FLOAT) || + (src_tyk == LegacyType::KIND_DOUBLE); + case LegacyType::KIND_DECIMAL: + case LegacyType::KIND_EDITED: + case LegacyType::KIND_DISPLAY: { + return true; + } + case LegacyType::KIND_ARRAY: { + uint32_t ty_len; + return IsCStringType(src_type, ty_len); + } + case LegacyType::KIND_STRUCT: + case LegacyType::KIND_FUNC: + default: + break; + } + return false; +} + +bool TypeSystemLegacy::EncodeDataToType(ExecutionContext &exe_scope, + opaque_compiler_type_t src_type, + const DataExtractor &src_data, + opaque_compiler_type_t dest_type, + DataExtractor &dest_data, + const LanguageType lang) { + if (!VerifyEncodeType(src_type, dest_type)) { + Host::SystemLog(lldb::eSeverityError, "Wrong assignment type.\n"); + return false; + } + + LegacyType *lty = static_cast(dest_type); + LegacyType *src_ty = static_cast(src_type); + const auto type_kind = lty->GetLegacyKind(); + const auto src_type_kind = src_ty->GetLegacyKind(); + const auto type_sign = lty->GetSign(); + const auto type_scale = lty->GetScale(); + const auto type_digits_count = lty->GetDigitCount(); + const auto type_byte_order = lty->GetTypeByteOrder(); + const bool is_binscale = lty->is_binary_scale(); + const auto TypeLengthInBits = lty->GetTypeBitSize(); + const auto ty_length = (TypeLengthInBits + 7) / 8; + const auto src_byte_order = endian::InlHostByteOrder(); + DataBufferSP dest_buffer = dest_data.GetSharedDataBuffer(); + dest_data.SetByteOrder(type_byte_order); + const bool isPackedDecimal = (type_kind == LegacyType::KIND_DECIMAL); + + offset_t offset = 0; + switch (type_kind) { + case LegacyType::KIND_STRUCT: + case LegacyType::KIND_FUNC: + return false; + default: + case LegacyType::KIND_PTR: + case LegacyType::KIND_INT: + case LegacyType::KIND_UINT: { + union { + int8_t i8; + int16_t i16; + int32_t i32; + int64_t i64; + } iu; + const size_t length = src_data.GetByteSize(); + switch (ty_length) { + case 1: + iu.i8 = src_data.GetMaxS64(&offset, length); + break; + case 2: + iu.i16 = src_data.GetMaxS64(&offset, length); + break; + case 4: + iu.i32 = src_data.GetMaxS64(&offset, length); + break; + case 8: + iu.i64 = src_data.GetMaxS64(&offset, length); + break; + } + DataExtractor temp(&iu, ty_length, src_byte_order, GetPointerByteSize()); + temp.CopyByteOrderedData(0, temp.GetByteSize(), + (void *)dest_buffer->GetBytes(), ty_length, + type_byte_order); + return true; + } + case LegacyType::KIND_FLOAT: { + float value; + if (src_type_kind == LegacyType::KIND_FLOAT) + value = src_data.GetFloat(&offset); + else if (src_type_kind == LegacyType::KIND_DOUBLE) + value = src_data.GetDouble(&offset); + else { + Host::SystemLog(lldb::eSeverityError,"Invalid float src data type.\n"); + return false; + } + + if (type_scale) { + auto exp = std::pow(is_binscale ? 2 : 10, type_scale); + value /= exp; + } + DataExtractor temp(&value, sizeof(value), src_byte_order, + GetPointerByteSize()); + temp.CopyByteOrderedData(0, temp.GetByteSize(), + (void *)dest_buffer->GetBytes(), sizeof(value), + type_byte_order); + return true; + } + case LegacyType::KIND_DOUBLE: { + double value; + if (src_type_kind == LegacyType::KIND_FLOAT) + value = src_data.GetFloat(&offset); + else if (src_type_kind == LegacyType::KIND_DOUBLE) + value = src_data.GetDouble(&offset); + else { + Host::SystemLog(lldb::eSeverityError, "Invalid float src data type.\n"); + return false; + } + if (type_scale) { + auto exp = std::pow(is_binscale ? 2 : 10, type_scale); + value /= exp; + } + DataExtractor temp(&value, sizeof(value), src_byte_order, + GetPointerByteSize()); + temp.CopyByteOrderedData(0, temp.GetByteSize(), + (void *)dest_buffer->GetBytes(), sizeof(value), + type_byte_order); + return true; + } + case LegacyType::KIND_ARRAY: { + const auto array_type = lty->GetArray(); + const auto arr_len = array_type->GetLength(); + std::string val_str(getStringFromDataExtractor(src_data, src_type_kind, + type_scale, is_binscale)); + uint16_t str_length = val_str.size(); + if (str_length > arr_len) { + Host::SystemLog(lldb::eSeverityError, "Assignment string longer then available.\n"); + val_str.erase(arr_len, 100); + str_length = val_str.size(); + } + + if (!array_type->isVarString()) { + val_str.append(arr_len - str_length, ' '); + } + + TargetCharsetReader Conv(exe_scope.GetTargetSP(), true); + if (!Conv.IsValid()) { + Host::SystemLog(lldb::eSeverityError, "Assignment charset encoding failure.\n"); + return false; + } + + if (!Conv.convert(val_str)) { + Host::SystemLog(lldb::eSeverityError, "Assignment charset encoding convertion failure.\n"); + return false; + } + + if (array_type->isVarString()) { + const uint8_t lsb = str_length & 0xff; + const uint8_t msb = (str_length >> 8) & 0xff; + + // big endian str length at start in 2 bytes. + val_str.insert(0, 1, lsb); + val_str.insert(0, 1, msb); + } + DataExtractor temp(val_str.c_str(), val_str.size(), type_byte_order, + GetPointerByteSize()); + temp.CopyByteOrderedData(0, temp.GetByteSize(), + (void *)dest_buffer->GetBytes(), val_str.size(), + type_byte_order); + return true; + } break; + case LegacyType::KIND_DECIMAL: + case LegacyType::KIND_EDITED: + case LegacyType::KIND_DISPLAY: + // Encode Display Type + std::string val_str(getStringFromDataExtractor(src_data, src_type_kind, + type_scale, is_binscale)); + char sign; + const auto no_digits = isPackedDecimal ? type_digits_count : ty_length; + if (val_str[0] == '-') { + sign = '-'; + val_str.erase(0, 1); + } else { + sign = '+'; + if (val_str[0] == '+') + val_str.erase(0, 1); + } + val_str.erase(0, val_str.find_first_not_of('0')); + if (val_str.size() == 0) { + val_str = std::string(no_digits, '0'); + } else { + const int digit_len = no_digits + type_scale; + auto pos = val_str.find('.'); + if (pos != std::string::npos) { + val_str.erase(pos, 1); + } else { + pos = val_str.size(); + } + + // FIXME + if (digit_len > (int)pos) + val_str.insert(0, digit_len - pos, '0'); + else + val_str.erase(0, pos - digit_len); + + if (val_str.size() > no_digits) + val_str.erase(no_digits, 100); + else + val_str.append(no_digits - val_str.size(), '0'); + } + + switch (type_sign) { + case LegacyType::eTrailingSeparate: + val_str.push_back(sign); + break; + case LegacyType::eLeadingSeparate: + val_str = sign + val_str; + break; + case LegacyType::eTrailingOverpunch: + val_str.back() = EncodeOverpunchDigit(val_str.back(), sign == '+'); + break; + case LegacyType::eLeadingOverpunch: + val_str.front() = EncodeOverpunchDigit(val_str.front(), sign == '+'); + break; + case LegacyType::eUnsigned: + default: + break; + } + + uint8_t buffer[128]; + size_t count = 0; + if (isPackedDecimal) { + if (val_str.size() % 2) + val_str.insert(0, 1, '0'); + + for (size_t i = 0; i < val_str.size(); i += 2) { + buffer[count++] = (EncodePackedSign(val_str[i]) << 4) | + (EncodePackedSign(val_str[i + 1])); + } + } else { + TargetCharsetReader Conv(exe_scope.GetTargetSP(), true); + if (!Conv.IsValid()) { + Host::SystemLog(lldb::eSeverityError, "Assignment charset encoding failure.\n"); + return false; + } + if (!Conv.convert(val_str)) { + Host::SystemLog(lldb::eSeverityError, "Assignment charset encoding convertion failure.\n"); + return false; + } + count = val_str.size(); + val_str.copy((char *)buffer, count); + } + DataExtractor temp(buffer, count, src_byte_order, GetPointerByteSize()); + temp.CopyByteOrderedData(0, temp.GetByteSize(), + (void *)dest_buffer->GetBytes(), count, + type_byte_order); + return true; + } + return false; +} + +//---------------------------------------------------------------------- +// Exploring the type +//---------------------------------------------------------------------- +std::optional +TypeSystemLegacy::GetBitSize(opaque_compiler_type_t type, + ExecutionContextScope *exe_scope) { + if (!type) + return std::nullopt; + + LegacyType *base_type = static_cast(type); + int kind = base_type->GetLegacyKind(); + + switch (kind) { + default: + break; + case LegacyType::KIND_DECIMAL: + case LegacyType::KIND_DISPLAY: + case LegacyType::KIND_EDITED: + case LegacyType::KIND_FLOAT: + case LegacyType::KIND_DOUBLE: + case LegacyType::KIND_INT: + case LegacyType::KIND_UINT: { + return static_cast(type)->GetTypeBitSize(); + } + case LegacyType::KIND_ARRAY: { + LegacyArray *array = base_type->GetArray(); + if (std::optional bit_size = + array->GetElementType().GetBitSize(exe_scope)) + return (array->GetLength() + (array->isVarString() ? 2UL : 0UL)) * + (*bit_size); + return std::nullopt; + } + case LegacyType::KIND_PTR: + return m_pointer_byte_size * 8; + case LegacyType::KIND_STRUCT: + return base_type->GetStruct()->GetByteSize() * 8; + case LegacyType::KIND_DYNAMIC: { + const auto dyn_base_type = + static_cast(type)->GetBaseType(); + return dyn_base_type.GetBitSize(exe_scope); + } + case LegacyType::KIND_L88: + return 1UL; + } + return std::nullopt; +} + +Format TypeSystemLegacy::GetFormat(opaque_compiler_type_t type) { + if (!type) + return eFormatDefault; + + switch (static_cast(type)->GetLegacyKind()) { + case LegacyType::KIND_DECIMAL: + case LegacyType::KIND_DISPLAY: + case LegacyType::KIND_EDITED: + return eFormatChar; + case LegacyType::KIND_FLOAT: + case LegacyType::KIND_DOUBLE: + return eFormatFloat; + case LegacyType::KIND_INT: + return eFormatDecimal; + case LegacyType::KIND_UINT: + return eFormatUnsigned; + case LegacyType::KIND_PTR: + return eFormatHex; + case LegacyType::KIND_ARRAY: + return eFormatVoid; + case LegacyType::KIND_DYNAMIC: { + const auto dyn_base_type = + static_cast(type)->GetBaseType(); + return dyn_base_type.GetFormat(); + } + case LegacyType::KIND_L88: + return eFormatBoolean; + default: + return eFormatBytes; + } +} + +Encoding TypeSystemLegacy::GetEncoding(opaque_compiler_type_t type, + uint64_t &count) { + bool is_signed; + if (IsIntegerType(type, is_signed)) + return is_signed ? eEncodingSint : eEncodingUint; + count = 1; + + bool is_complex; + uint32_t complex_count; + if (IsFloatingPointType(type, complex_count, is_complex)) { + count = complex_count; + return eEncodingIEEE754; + } + + if (IsPointerType(type)) + return eEncodingUint; + + if (static_cast(type)->GetLegacyKind() == + LegacyType::KIND_DYNAMIC) { + const auto dyn_base_type = + static_cast(type)->GetBaseType(); + return dyn_base_type.GetEncoding(count); + } + + count = 0; + return eEncodingInvalid; +} + +llvm::Expected TypeSystemLegacy::GetNumChildren(opaque_compiler_type_t type, + bool omit_empty_base_classes, + const ExecutionContext *exe_ctx) { + if (!type) + return 0; + + if (!GetCompleteType(type)) + return 0; + + LegacyType *base_type = static_cast(type); + if (LegacyArray *array = base_type->GetArray()) + return array->GetLength(); + + if (LegacyStruct *struct_type = base_type->GetStruct()) + return struct_type->GetNumMembers(); + + if (static_cast(type)->GetLegacyKind() == + LegacyType::KIND_DYNAMIC) { + const auto dyn_base_type = + static_cast(type)->GetBaseType(); + return dyn_base_type.GetNumChildren(omit_empty_base_classes, exe_ctx); + } + + return 0; +} + +std::optional +TypeSystemLegacy::GetTypeBitAlign(opaque_compiler_type_t type, + ExecutionContextScope *exe_scope) { + return 0; +} + +CompilerType TypeSystemLegacy::GetBasicTypeFromAST(BasicType basic_type) { + LegacyType *type = (*m_basic_types)[basic_type].get(); + if (type) + return CompilerType(weak_from_this(), type); + + switch (basic_type) { + default: + return CompilerType(); + case eBasicTypeUnsignedInt: { + type = new LegacyType(LegacyType::KIND_UINT, ConstString("unsigned int"), + ConstString(), 64, 0, 0, 0, + endian::InlHostByteOrder(), false); + (*m_basic_types)[basic_type].reset(type); + break; + } + case eBasicTypeInt: { + type = + new LegacyType(LegacyType::KIND_INT, ConstString("int"), ConstString(), + 64, 0, 0, 0, endian::InlHostByteOrder(), false); + (*m_basic_types)[basic_type].reset(type); + break; + } + case eBasicTypeFloat: { + type = new LegacyType(LegacyType::KIND_FLOAT, ConstString("float"), + ConstString(), 32, 0, 0, 0, + endian::InlHostByteOrder(), false); + (*m_basic_types)[basic_type].reset(type); + break; + } + case eBasicTypeDouble: { + type = new LegacyType(LegacyType::KIND_DOUBLE, ConstString("double"), + ConstString(), 64, 0, 0, 0, + endian::InlHostByteOrder(), false); + (*m_basic_types)[basic_type].reset(type); + break; + } + case eBasicTypeChar: { + type = new LegacyType(LegacyType::KIND_DISPLAY, ConstString("char"), + ConstString(), 8, 0, 0, 0, endian::InlHostByteOrder(), + false); + (*m_basic_types)[basic_type].reset(type); + break; + } + case eBasicTypeBool: + type = + new LegacyType(LegacyType::KIND_UINT, ConstString("bit"), ConstString(), + 8, 0, 0, 0, endian::InlHostByteOrder(), false); + (*m_basic_types)[basic_type].reset(type); + break; + case eBasicTypeOther: + type = new LegacyType(LegacyType::KIND_L88, ConstString("Level88"), + ConstString(), 0, 0, 0, 0, endian::InlHostByteOrder(), + false); + } + return CompilerType(weak_from_this(), type); +} + +CompilerType +TypeSystemLegacy::DynGetBaseType(lldb::opaque_compiler_type_t type) const { + if (!type) + return CompilerType(); + + int kind = static_cast(type)->GetLegacyKind(); + if (kind != LegacyType::KIND_DYNAMIC) + return CompilerType(); + + const auto dyn = static_cast(type); + return dyn->GetBaseType(); +} + +DWARFExpressionList +TypeSystemLegacy::DynGetLocation(lldb::opaque_compiler_type_t type) const { + if (!type) + return DWARFExpressionList(); + + int kind = static_cast(type)->GetLegacyKind(); + if (kind != LegacyType::KIND_DYNAMIC) + return DWARFExpressionList(); + + const auto dyn = static_cast(type); + return dyn->getLocation(); +} + +DWARFExpressionList +TypeSystemLegacy::DynGetAllocated(lldb::opaque_compiler_type_t type) const { + if (!type) + return DWARFExpressionList(); + + int kind = static_cast(type)->GetLegacyKind(); + if (kind != LegacyType::KIND_DYNAMIC) + return DWARFExpressionList(); + + const auto dyn = static_cast(type); + return dyn->getAllocated(); +} + +DWARFExpressionList +TypeSystemLegacy::DynArrGetCountExp(lldb::opaque_compiler_type_t type) const { + if (!type) + return DWARFExpressionList(); + + int kind = static_cast(type)->GetLegacyKind(); + if (kind != LegacyType::KIND_ARRAY || + !static_cast(type)->isDynamic()) + return DWARFExpressionList(); + + const auto dyn_arr = static_cast(type); + return dyn_arr->GetCountExp(); +} + +bool TypeSystemLegacy::DynArrUpdateLength(lldb::opaque_compiler_type_t type, + uint64_t length) { + if (!type) + return false; + + int kind = static_cast(type)->GetLegacyKind(); + if (kind != LegacyType::KIND_ARRAY || + !static_cast(type)->isDynamic()) + return false; + + const auto dyn_array = static_cast(type); + dyn_array->UpdateLength(length); + return true; +} + +lldb::BasicType +TypeSystemLegacy::GetBasicTypeEnumeration(opaque_compiler_type_t type) { + return eBasicTypeUnsignedInt; +} + +CompilerType TypeSystemLegacy::GetFieldAtIndex(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(); + + if (LegacyStruct *st = static_cast(type)->GetStruct()) { + const auto *field = st->GetMemberAtIndex(idx); + if (field) { + name = std::string(field->m_name.GetStringRef()); + if (bit_offset_ptr) + *bit_offset_ptr = field->m_offset_in_bits; + return field->m_type; + } + } + + if (static_cast(type)->GetLegacyKind() == + LegacyType::KIND_DYNAMIC) { + const auto dyn_base_type = + static_cast(type)->GetBaseType(); + return dyn_base_type.GetFieldAtIndex( + idx, name, bit_offset_ptr, bitfield_bit_size_ptr, is_bitfield_ptr); + } + // TODO struct + return CompilerType(); +} + +llvm::Expected TypeSystemLegacy::GetChildCompilerTypeAtIndex( + 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) { + + auto num_children_or_error = + GetNumChildren(type, omit_empty_base_classes, exe_ctx); + if (!num_children_or_error) { + return num_children_or_error.takeError(); + } + + uint32_t num_children = *num_children_or_error; + const bool idx_is_valid = idx < num_children; + + auto get_exe_scope = [&exe_ctx]() { + return exe_ctx ? exe_ctx->GetBestExecutionContextScope() : nullptr; + }; + + int kind = static_cast(type)->GetLegacyKind(); + + switch (kind) { + default: + break; + case LegacyType::KIND_PTR: { + CompilerType pointee_type(GetPointeeType(type)); + + if (transparent_pointers && pointee_type.IsAggregateType()) { + // TODO + return CompilerType(); + } else { + child_is_deref_of_parent = true; + + const char *parent_name = valobj ? valobj->GetName().GetCString() : NULL; + if (parent_name) { + child_name.assign(1, '*'); + child_name += parent_name; + } + + if (idx == 0) { + if (std::optional size = + pointee_type.GetByteSize(get_exe_scope())) { + child_byte_size = *size; + child_byte_offset = 0; + return pointee_type; + } + } + } + } break; + case LegacyType::KIND_ARRAY: { + LegacyArray *array = static_cast(type)->GetArray(); + if (ignore_array_bounds || idx_is_valid) { + CompilerType element_type = array->GetElementType(); + if (element_type.GetCompleteType()) { + child_name = llvm::formatv("[{0}]", idx); + if (auto byte_size = element_type.GetByteSize( + exe_ctx ? exe_ctx->GetBestExecutionContextScope() : NULL)) + child_byte_size = *byte_size; + child_byte_offset = (int32_t)idx * (int32_t)child_byte_size; + if (array->isVarString()) + child_byte_offset += 2; + return element_type; + } + } + } break; + case LegacyType::KIND_STRUCT: { + uint64_t bit_offset; + CompilerType ret = + GetFieldAtIndex(type, idx, child_name, &bit_offset, nullptr, nullptr); + if (std::optional byte_size = ret.GetByteSize( + exe_ctx ? exe_ctx->GetBestExecutionContextScope() : nullptr)) + child_byte_size = *byte_size; + child_byte_offset = bit_offset / 8; + return ret; + } break; + case LegacyType::KIND_DYNAMIC: { + const auto dyn_base_type = + static_cast(type)->GetBaseType(); + return dyn_base_type.GetChildCompilerTypeAtIndex( + exe_ctx, idx, transparent_pointers, omit_empty_base_classes, + ignore_array_bounds, child_name, child_byte_size, child_byte_offset, + child_bitfield_bit_size, child_bitfield_bit_offset, child_is_base_class, + child_is_deref_of_parent, valobj, language_flags); + } + } + return CompilerType(); +} + +uint32_t +TypeSystemLegacy::GetIndexOfChildWithName(lldb::opaque_compiler_type_t type, + llvm::StringRef name, + bool omit_empty_base_classes) { + if (!type) + return UINT32_MAX; + + if (!GetCompleteType(type)) + return UINT32_MAX; + + LegacyType *t = static_cast(type); + if (LegacyStruct *stype = t->GetStruct()) { + for (size_t i = 0; i < stype->GetNumMembers(); ++i) { + if (const auto member = stype->GetMemberAtIndex(i)) { + if (ConstString::Equals(member->GetMemberName(), ConstString(name), + false)) { + return i; + } + } + } + } + if (static_cast(type)->GetLegacyKind() == + LegacyType::KIND_DYNAMIC) { + const auto dyn_base_type = + static_cast(type)->GetBaseType(); + return dyn_base_type.GetIndexOfChildWithName(name, omit_empty_base_classes); + } + return UINT32_MAX; +} + +size_t TypeSystemLegacy::GetIndexOfChildMemberWithName( + lldb::opaque_compiler_type_t type, llvm::StringRef name, + bool omit_empty_base_classes, std::vector &child_indexes) { + uint32_t index = GetIndexOfChildWithName(type, name, omit_empty_base_classes); + if (index == UINT32_MAX) + return 0; + child_indexes.push_back(index); + return 1; +} + +lldb::TypeClass TypeSystemLegacy::GetTypeClass(opaque_compiler_type_t type) { + if (!type) + return eTypeClassInvalid; + + if (IsPointerType(type)) + return eTypeClassPointer; + + int kind = static_cast(type)->GetLegacyKind(); + + if (kind == LegacyType::KIND_FUNC) + return eTypeClassFunction; + + if (kind == LegacyType::KIND_DYNAMIC) { + const auto dyn_base_ty = static_cast(type)->GetBaseType(); + return dyn_base_ty.GetTypeClass(); + } + + switch (kind) { + case LegacyType::KIND_FUNC: + return eTypeClassFunction; + case LegacyType::KIND_DISPLAY: + case LegacyType::KIND_EDITED: + case LegacyType::KIND_DECIMAL: + return eTypeClassBuiltin; + case LegacyType::KIND_ARRAY: + return eTypeClassArray; + case LegacyType::KIND_STRUCT: + return eTypeClassStruct; + } + return eTypeClassInvalid; +} + +int TypeSystemLegacy::GetFunctionArgumentCount(opaque_compiler_type_t type) { + // add param type list + return 0; +} + +unsigned TypeSystemLegacy::GetTypeQualifiers(opaque_compiler_type_t type) { + return 0; +} + +CompilerType +TypeSystemLegacy::GetFullyUnqualifiedType(opaque_compiler_type_t type) { + return CompilerType(weak_from_this(), type); +} + +//---------------------------------------------------------------------- +// Creating Types +//---------------------------------------------------------------------- + +CompilerType TypeSystemLegacy::CreateArrayType( + const ConstString &array_type_name, const ConstString &name, + const CompilerType &element_type, size_t element_count, bool isVarString) { + if (!element_type.IsValid()) + return CompilerType(); + + if (element_count == 0) { + char buffer[128]; + sprintf(buffer, + "Warning: need to add support for " + "DW_TAG_array_type '%s' with dynamic size", + name.GetCString()); + Host::SystemLog(lldb::eSeverityWarning, std::string(buffer)); + return CompilerType(); + } + + if (isVarString && (element_count > 2)) + element_count -= 2; + + LegacyType *array_type = new LegacyArray(array_type_name, name, element_type, + element_count, isVarString); + return CompilerType(weak_from_this(), array_type); +} + +CompilerType TypeSystemLegacy::CreateArrayType( + const ConstString &array_type_name, const ConstString &name, + const CompilerType &element_type, DWARFExpressionList element_count, + bool isVarString) { + if (!element_type.IsValid()) + return CompilerType(); + + LegacyType *array_type = new LegacyDynamicArray( + array_type_name, name, element_type, element_count, isVarString); + return CompilerType(weak_from_this(), array_type); +} + +CompilerType +TypeSystemLegacy::CreateDynamicType(const CompilerType &base_type, + const DWARFExpressionList &dw_location, + const DWARFExpressionList &dw_allocated) { + if (!base_type) + return CompilerType(); + + LegacyType *type = static_cast(base_type.GetOpaqueQualType()); + if (!type) + return CompilerType(); + + if (type->GetLegacyKind() == LegacyType::KIND_DYNAMIC) + return CompilerType(); + + LegacyType *dyn_type = + new LegacyDynamic(base_type, dw_location, dw_allocated); + return CompilerType(weak_from_this(), dyn_type); +} + +CompilerType TypeSystemLegacy::GetArrayType(lldb::opaque_compiler_type_t type, + uint64_t size) { + if (!type) + return CompilerType(); + + if (size == 0) + return CompilerType(); + + LegacyType *element_type = static_cast(type); + LegacyType *array_type = new LegacyArray( + ConstString(), ConstString(""), + CompilerType(weak_from_this(), element_type), size, false); + return CompilerType(weak_from_this(), array_type); +} + +void TypeSystemLegacy::AddFieldToStruct(const CompilerType &struct_type, + const ConstString &member_name, + const CompilerType &member_type, + uint32_t offset_in_bits) { + + if (!struct_type) + return; + + LegacyType *type = static_cast(struct_type.GetOpaqueQualType()); + if (!type) + return; + + if (LegacyStruct *stype = type->GetStruct()) + stype->AddMember(member_name, member_type, offset_in_bits); +} + +void TypeSystemLegacy::CompleteStructType(const CompilerType &struct_type) { + if (!struct_type) + return; + + LegacyType *type = static_cast(struct_type.GetOpaqueQualType()); + if (!type) + return; + + if (LegacyStruct *stype = type->GetStruct()) + stype->SetComplete(); +} + +CompilerType TypeSystemLegacy::CreateStructType(const ConstString &name, + uint32_t byte_size) { + LegacyStruct *type = new LegacyStruct(name, byte_size); + return CompilerType(weak_from_this(), type); +} + +CompilerType TypeSystemLegacy::CreateFunctionType(const ConstString &name, + CompilerType *params, + size_t params_count, + bool is_variadic) { + LegacyType *type = + new LegacyFunction(name, params, params_count, is_variadic); + return CompilerType(weak_from_this(), type); +} + +CompilerType TypeSystemLegacy::CreateBaseType( + const ConstString &name, const ConstString &pic_string, uint32_t dw_ate, + uint32_t bitsize, uint32_t dw_sign, int32_t scale, uint32_t digit_count, + ByteOrder byte_order, bool bin_scale) { + int kind = LegacyType::KIND_INVALID; + + switch (dw_ate) { + case DW_ATE_signed: + case DW_ATE_signed_fixed: + kind = LegacyType::KIND_INT; + break; + case DW_ATE_unsigned: + case DW_ATE_unsigned_fixed: + kind = LegacyType::KIND_UINT; + break; + case DW_ATE_signed_char: + case DW_ATE_unsigned_char: + case DW_ATE_numeric_string: + kind = LegacyType::KIND_DISPLAY; + break; + case DW_ATE_edited: + kind = LegacyType::KIND_EDITED; + break; + case DW_ATE_packed_decimal: + kind = LegacyType::KIND_DECIMAL; + break; + case DW_ATE_float: { + if (bitsize == 64) + kind = LegacyType::KIND_DOUBLE; + else + kind = LegacyType::KIND_FLOAT; + } break; + case DW_ATE_boolean: + kind = LegacyType::KIND_L88; + break; + } + + uint32_t sign; + switch (dw_sign) { + case DW_DS_leading_overpunch: + sign = LegacyType::eLeadingOverpunch; + break; + case DW_DS_trailing_overpunch: + sign = LegacyType::eTrailingOverpunch; + break; + case DW_DS_leading_separate: + sign = LegacyType::eLeadingSeparate; + break; + case DW_DS_trailing_separate: + sign = LegacyType::eTrailingSeparate; + break; + default: + sign = LegacyType::eUnsigned; + } + + if (kind == LegacyType::KIND_INVALID) { + char buffer[256]; + sprintf(buffer, + "Warning: need to add support for " + "DW_TAG_base_type '%s' encoded with " + "DW_ATE = 0x%x, bit_size = %u\n, " + "sign = %u, scale = %d, byte_order = %u.\n", + name.GetCString(), dw_ate, bitsize, dw_sign, scale, byte_order); + std::string message(buffer); + Host::SystemLog(lldb::eSeverityWarning, message); + return CompilerType(); + } + + LegacyType *type = new LegacyType(kind, name, pic_string, bitsize, sign, + scale, digit_count, byte_order, bin_scale); + return CompilerType(weak_from_this(), type); +} + +//---------------------------------------------------------------------- +// Creating related types +//---------------------------------------------------------------------- +CompilerType +TypeSystemLegacy::GetArrayElementType(opaque_compiler_type_t type, + ExecutionContextScope *exe_scope) { + LegacyArray *array = static_cast(type)->GetArray(); + if (array) { + return array->GetElementType(); + } + if (static_cast(type)->GetLegacyKind() == + LegacyType::KIND_DYNAMIC) { + const auto dyn_base_type = + static_cast(type)->GetBaseType(); + return dyn_base_type.GetArrayElementType(exe_scope); + } + return CompilerType(); +} + +TypeMemberFunctionImpl +TypeSystemLegacy::GetMemberFunctionAtIndex(opaque_compiler_type_t type, + size_t idx) { + return TypeMemberFunctionImpl(); +} + +CompilerType TypeSystemLegacy::GetCanonicalType(opaque_compiler_type_t type) { + return CompilerType(weak_from_this(), type); +} + +CompilerType +TypeSystemLegacy::GetEnumerationIntegerType(opaque_compiler_type_t type) { + return CompilerType(weak_from_this(), type); +} + +TypeSystemLegacy::TypeSystemLegacy(TargetSP target) + : m_pointer_byte_size(0), m_target_wp(target), m_types(new TypeMap), + m_basic_types(new BasicTypeMap), m_mutated_types(new MutatedTypeMap) {} + +TypeSystemLegacy::~TypeSystemLegacy() {} + +//------------------------------------------------------------------ +// PluginInterface functions +//------------------------------------------------------------------ + +uint32_t TypeSystemLegacy::GetPluginVersion() { return 1; } +llvm::StringRef TypeSystemLegacy::GetPluginNameStatic() { + return llvm::StringRef("legacy"); +} + +llvm::StringRef TypeSystemLegacy::GetPluginName() { + return TypeSystemLegacy::GetPluginNameStatic(); +} + +TypeSystemSP TypeSystemLegacy::CreateInstance(lldb::LanguageType language, + lldb_private::Module *module, + Target *target) { + if (TypeSystemLegacySupportsLanguage(language)) { + ArchSpec arch; + std::shared_ptr ast_sp; + + if (module) { + arch = module->GetArchitecture(); + ast_sp = std::make_shared(); + } else if (target) { + arch = target->GetArchitecture(); + ast_sp = std::make_shared(target->shared_from_this()); + } + + ast_sp->SetLanguage(language); + + if (arch.IsValid()) + ast_sp->SetAddressByteSize(arch.GetAddressByteSize()); + + return ast_sp; + } + return TypeSystemSP(); +} + +LanguageSet TypeSystemLegacy::GetSupportedLanguagesForTypes() { + LanguageSet languages; + languages.Insert(eLanguageTypePLI); + languages.Insert(eLanguageTypeCobol74); + languages.Insert(eLanguageTypeCobol85); + return languages; +} + +LanguageSet TypeSystemLegacy::GetSupportedLanguagesForExpressions() { + LanguageSet languages; + languages.Insert(eLanguageTypePLI); + languages.Insert(eLanguageTypeCobol74); + languages.Insert(eLanguageTypeCobol85); + return languages; +} + +void TypeSystemLegacy::Initialize() { + PluginManager::RegisterPlugin(GetPluginNameStatic(), "AST context plug-in", + CreateInstance, GetSupportedLanguagesForTypes(), + GetSupportedLanguagesForExpressions()); +} + +void TypeSystemLegacy::Terminate() { + PluginManager::UnregisterPlugin(CreateInstance); +} + +void TypeSystemLegacy::Finalize() {} + +lldb_private::plugin::dwarf::DWARFASTParser * +TypeSystemLegacy::GetDWARFParser() { + if (!m_dwarf_ast_parser_ap) + m_dwarf_ast_parser_ap.reset(new DWARFASTParserLegacy( + *std::static_pointer_cast(weak_from_this().lock()))); + + return m_dwarf_ast_parser_ap.get(); +} + +//---------------------------------------------------------------------- +// Dumping types +//---------------------------------------------------------------------- +#define DEPTH_INCREMENT 2 + +#ifndef NDEBUG +LLVM_DUMP_METHOD void +TypeSystemLegacy::dump(lldb::opaque_compiler_type_t type) const { + // FIXME + return; +} +#endif + +bool TypeSystemLegacy::DumpTypeValue(opaque_compiler_type_t type, Stream &s, + Format format, const DataExtractor &data, + offset_t byte_offset, size_t byte_size, + uint32_t bitfield_bit_size, + uint32_t bitfield_bit_offset, + ExecutionContextScope *exe_scope) { + if (!type) + return false; + + if (IsAggregateType(type)) { + /* + // FIXME + ExecutionContext exe_ctx(exe_scope); + DumpValue(type, &exe_ctx, s, format, data, byte_offset, byte_size, + bitfield_bit_size, bitfield_bit_offset, true, true, true, 0); + */ + return false; + } + + auto type_kind = static_cast(type)->GetLegacyKind(); + auto type_sign = static_cast(type)->GetSign(); + auto type_scale = static_cast(type)->GetScale(); + auto byte_order = static_cast(type)->GetTypeByteOrder(); + const bool is_binscale = static_cast(type)->is_binary_scale(); + const bool skipIconv = (type_kind == LegacyType::KIND_DECIMAL); + const bool skipFormatting = (type_kind == LegacyType::KIND_EDITED); + + switch (type_kind) { + case LegacyType::KIND_INT: + case LegacyType::KIND_UINT: + case LegacyType::KIND_FLOAT: + case LegacyType::KIND_DOUBLE: { + DataExtractor format_data; + format_data.SetData(data, 0, data.GetByteSize()); + format_data.SetAddressByteSize(data.GetAddressByteSize()); + format_data.SetByteOrder(byte_order); + if (type_scale) { + offset_t offset = 0; + // TODO - Fix me + auto data = std::pow(is_binscale ? 2 : 10, type_scale); + if (type_kind == LegacyType::KIND_INT) { + data *= format_data.GetMaxS64(&offset, byte_size); + } else { + data *= format_data.GetMaxU64(&offset, byte_size); + } + format_data.SetData((void *)&data, sizeof(data), + endian::InlHostByteOrder()); + return DumpDataExtractor(format_data, &s, byte_offset, eFormatFloat, + sizeof(data), 1 /*item_count*/, UINT32_MAX, + LLDB_INVALID_ADDRESS, bitfield_bit_size, + bitfield_bit_offset, exe_scope); + } + return DumpDataExtractor(format_data, &s, byte_offset, format, byte_size, + 1 /*item_count*/, UINT32_MAX, LLDB_INVALID_ADDRESS, + bitfield_bit_size, bitfield_bit_offset, exe_scope); + } break; + case LegacyType::KIND_DECIMAL: + case LegacyType::KIND_EDITED: + case LegacyType::KIND_DISPLAY: { + + switch (format) { + default: + return DumpDataExtractor(data, &s, byte_offset, format, 1, byte_size, + UINT32_MAX, LLDB_INVALID_ADDRESS, + bitfield_bit_size, bitfield_bit_offset, + exe_scope); + break; + case eFormatCString: + case eFormatCharArray: + case eFormatCharPrintable: + case eFormatChar: { + DataExtractor format_data; + std::string format_string; + + uint8_t buffer[64]; + + if (byte_size > 64) { + Host::SystemLog(lldb::eSeverityError, "Error: Display/Decimal type with invalid width" + ", Displaying only first 64 bytes.\n"); + byte_size = 64; + } + data.CopyByteOrderedData(0, byte_size, buffer, byte_size, byte_order); + + if (!skipIconv && exe_scope) { + TargetCharsetReader Conv(exe_scope->CalculateTarget()); + if (!Conv.IsValid()) { + char buffer[64]; + sprintf(buffer, "WARNING: Invalid target charset %s.\n", + Conv.getTargetFormat().GetCString()); + Host::SystemLog(lldb::eSeverityWarning, std::string(buffer)); + } else + Conv.convert(reinterpret_cast(buffer), byte_size); + } + + if (type_kind == LegacyType::KIND_DECIMAL) { + for (offset_t i = 0; i < byte_size; ++i) { + format_string += std::to_string((buffer[i] & 0xf0) >> 4); + format_string += DecodePackedSignToString((buffer[i] & 0x0f)); + type_sign = LegacyType::eTrailingSeparate; + } + } else { + format_string.assign(buffer, buffer + byte_size); + } + + /// extract sign and decode over-punch digit + char sign = ' '; + switch (type_sign) { + case LegacyType::eTrailingSeparate: { + sign = format_string.back(); + format_string.pop_back(); + } break; + case LegacyType::eTrailingOverpunch: { + sign = DecodeOverpunchDigit(format_string.back()); + } break; + case LegacyType::eLeadingOverpunch: { + sign = DecodeOverpunchDigit(format_string.front()); + } break; + case LegacyType::eLeadingSeparate: { + sign = format_string.front(); + format_string.erase(0, 1); + } break; + case LegacyType::eUnsigned: + default: + break; + } + + if (!skipFormatting) { + /// remove leading zeros + format_string.erase(0, format_string.find_first_not_of('0')); + + /// check if value is zero then nothing needs to be done furthur + if (format_string.length() == 0) + format_string = '0'; + /// scale the value, add trailing/leading zeros if needed with decimal + /// point + else { + if (type_scale > 0) { + format_string.append(std::string('0', type_scale)); + } else if (type_scale < 0) { + int pos = format_string.length() + type_scale; + if (pos > 0) { + format_string.insert(pos, 1, '.'); + } else { + format_string.insert(0, (-pos + 1), '0'); + format_string.insert(1, 1, '.'); + } + } + if (type_sign != LegacyType::eUnsigned) + format_string.insert(0, 1, sign); + } + } + format_data.SetData((const void *)format_string.c_str(), + format_string.length(), endian::InlHostByteOrder()); + format_data.SetAddressByteSize(data.GetAddressByteSize()); + + return DumpDataExtractor(format_data, &s, byte_offset, format, 1, + format_string.length(), UINT32_MAX, + LLDB_INVALID_ADDRESS, bitfield_bit_size, + bitfield_bit_offset, exe_scope); + } + } + } + case LegacyType::KIND_PTR: + return DumpDataExtractor(data, &s, byte_offset, format, byte_size, 1, + UINT32_MAX, LLDB_INVALID_ADDRESS, + bitfield_bit_size, bitfield_bit_offset, exe_scope); + case LegacyType::KIND_DYNAMIC: { + auto dyn_base_ty = static_cast(type)->GetBaseType(); + return dyn_base_ty.DumpTypeValue(&s, format, data, byte_offset, byte_size, + bitfield_bit_size, bitfield_bit_offset, + exe_scope); + } + case LegacyType::KIND_L88: { + return DumpDataExtractor(data, &s, byte_offset, eFormatCharPrintable, byte_size, + data.GetDataEnd() - data.GetDataStart(), + UINT32_MAX, LLDB_INVALID_ADDRESS, + bitfield_bit_size, bitfield_bit_offset, exe_scope); + } + } + Host::SystemLog(lldb::eSeverityError, "Error: DumpTypeValue not handled yet.\n"); + return false; +} + +void TypeSystemLegacy::DumpTypeDescription(opaque_compiler_type_t type, + DescriptionLevel level) { + // Dump to stdout + StreamFile s(stdout, false); + DumpTypeDescription(type, s, level); +} + +void TypeSystemLegacy::DumpTypeDescription(opaque_compiler_type_t type, + Stream &s, DescriptionLevel level) { + if (!type) + return; + + ConstString name = GetTypeName(type, true); + s.PutCString(name.AsCString()); +} + +UserExpression *TypeSystemLegacy::GetUserExpression( + StringRef expr, StringRef prefix, SourceLanguage language, + Expression::ResultType desired_type, + const EvaluateExpressionOptions &options, ValueObject *ctx_obj) { + TargetSP target = m_target_wp.lock(); + if (target) { + Log *log = GetLog(LLDBLog::Expressions); + + LLDB_LOGF(log, "LegacyTypeSystem: UserExpression %s for %s.\n", + expr.str().c_str(), language.GetDescription().data()); + + switch (language) { + default: + char buffer[64]; + sprintf( + buffer, + "LegacyTypeSystem: UserExpression for language %s not supported.\n", + language.GetDescription().data()); + Host::SystemLog(lldb::eSeverityError, std::string(buffer)); + break; + case eLanguageTypeCobol74: + case eLanguageTypeCobol85: + return new CobolUserExpression(*target, expr, prefix, language, + desired_type, options); + case eLanguageTypePLI: + return new PLIUserExpression(*target, expr, prefix, language, + desired_type, options); + } + } + + Host::SystemLog(lldb::eSeverityError, "LegacyTypeSystem: UserExpression error.\n"); + return nullptr; +} + +PersistentExpressionState *TypeSystemLegacy::GetPersistentExpressionState() { + return nullptr; +} diff --git a/lldb/source/Plugins/TypeSystem/Legacy/TypeSystemLegacy.h b/lldb/source/Plugins/TypeSystem/Legacy/TypeSystemLegacy.h new file mode 100644 index 00000000000000..8159d2026b8df1 --- /dev/null +++ b/lldb/source/Plugins/TypeSystem/Legacy/TypeSystemLegacy.h @@ -0,0 +1,720 @@ +//===-- TypeSystemLegacy.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_TypeSystemLegacy_h_ +#define liblldb_TypeSystemLegacy_h_ + +#include +#include +#include +#include +#include + +#if defined(__linux__) +#include +#define USE_BUILTIN_ICONV +#include "llvm/Support/Errno.h" +#endif + +#include "lldb/Expression/DWARFExpression.h" +#include "lldb/Symbol/CompilerType.h" +#include "lldb/Symbol/TypeSystem.h" +#include "lldb/Target/Target.h" +#include "lldb/Utility/ConstString.h" +#include "lldb/Core/Debugger.h" + +namespace lldb_private { + +class LegacyType; + +class TypeSystemLegacy : public TypeSystem { + // LLVM RTTI support + static char ID; + +public: + // llvm casting support + bool isA(const void *ClassID) const override { return ClassID == &ID; } + static bool classof(const TypeSystem *ts) { return ts->isA(&ID); } + + //------------------------------------------------------------------ + // Constructors and Destructors + //------------------------------------------------------------------ + TypeSystemLegacy(lldb::TargetSP target = nullptr); + + ~TypeSystemLegacy() override; + + void Finalize() override; + + //------------------------------------------------------------------ + // PluginInterface functions + //------------------------------------------------------------------ + llvm::StringRef GetPluginName() override; + + static llvm::StringRef GetPluginNameStatic(); + + uint32_t GetPluginVersion(); + + plugin::dwarf::DWARFASTParser *GetDWARFParser() override; + + static lldb::TypeSystemSP CreateInstance(lldb::LanguageType language, + Module *module, Target *target); + + static LanguageSet GetSupportedLanguagesForTypes(); + + static LanguageSet GetSupportedLanguagesForExpressions(); + + static void Initialize(); + + static void Terminate(); + + void SetAddressByteSize(int byte_size) { m_pointer_byte_size = byte_size; } + + //---------------------------------------------------------------------- + // CompilerDecl functions + //---------------------------------------------------------------------- + ConstString DeclGetName(void *opaque_decl) override { return ConstString(); }; + + CompilerType GetTypeForDecl(void *opaque_decl) override { + return CompilerType(); + } + + //---------------------------------------------------------------------- + // CompilerDeclContext functions + //---------------------------------------------------------------------- + + ConstString DeclContextGetName(void *opaque_decl_ctx) override { + return ConstString(); + } + + ConstString DeclContextGetScopeQualifiedName(void *opaque_decl_ctx) override { + return ConstString(); + } + + bool + DeclContextIsClassMethod(void *opaque_decl_ctx) override { + return false; + } + + bool DeclContextIsContainedInLookup(void *opaque_decl_ctx, + void *other_opaque_decl_ctx) override { + return false; + } + + lldb::LanguageType DeclContextGetLanguage(void *opaque_decl_ctx) override { + return lldb::eLanguageTypeUnknown; + } + + bool IsMemberFunctionPointerType(lldb::opaque_compiler_type_t type) override { + return false; + } + + + //---------------------------------------------------------------------- + // Tests + //---------------------------------------------------------------------- +#ifndef NDEBUG + bool Verify(lldb::opaque_compiler_type_t type) override; +#endif + + 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 IsAnonymousType(lldb::opaque_compiler_type_t type) override { + return false; + } + + bool IsCharType(lldb::opaque_compiler_type_t type) override; + + bool IsCompleteType(lldb::opaque_compiler_type_t type) override { + return true; + } + + bool IsDefined(lldb::opaque_compiler_type_t type) override { + return type != nullptr; + } + + bool IsFloatingPointType(lldb::opaque_compiler_type_t type, uint32_t &count, + bool &is_complex) override; + + unsigned GetPtrAuthKey(lldb::opaque_compiler_type_t type) override; + + unsigned GetPtrAuthDiscriminator(lldb::opaque_compiler_type_t type) override; + + bool GetPtrAuthAddressDiversity(lldb::opaque_compiler_type_t type) override; + + bool IsFunctionType(lldb::opaque_compiler_type_t type) override; + + size_t + GetNumberOfFunctionArguments(lldb::opaque_compiler_type_t type) override { + return 0; + } + + CompilerType GetFunctionArgumentAtIndex(lldb::opaque_compiler_type_t type, + const size_t index) override { + return CompilerType(); + } + + bool IsFunctionPointerType(lldb::opaque_compiler_type_t type) override { + return IsFunctionType(type); + } + + bool IsBlockPointerType(lldb::opaque_compiler_type_t type, + CompilerType *function_pointer_type_ptr) override { + return false; + } + + bool IsIntegerType(lldb::opaque_compiler_type_t type, + bool &is_signed) override; + + bool IsEnumerationType(lldb::opaque_compiler_type_t type, + bool &is_signed) override { + return false; + } + + bool IsScopedEnumerationType(lldb::opaque_compiler_type_t type) override { + return false; + } + + bool IsPossibleDynamicType(lldb::opaque_compiler_type_t type, + CompilerType *target_type, // Can pass NULL + bool check_cplusplus, bool check_objc) override { + return false; + } + + bool IsPointerType(lldb::opaque_compiler_type_t type, + CompilerType *pointee_type = nullptr) override; + + bool IsScalarType(lldb::opaque_compiler_type_t type) override { + return !IsAggregateType(type); + } + + bool IsVoidType(lldb::opaque_compiler_type_t type) override { return false; } + + bool CanPassInRegisters(const CompilerType &type) override { return false; } + + // TypeSystems can support more than one language + bool SupportsLanguage(lldb::LanguageType language) override; + + //---------------------------------------------------------------------- + // Type Completion + //---------------------------------------------------------------------- + + bool GetCompleteType(lldb::opaque_compiler_type_t type) override; + + //---------------------------------------------------------------------- + // AST related queries + //---------------------------------------------------------------------- + + uint32_t GetPointerByteSize() override { return m_pointer_byte_size; } + + //---------------------------------------------------------------------- + // Accessors + //---------------------------------------------------------------------- + + ConstString GetTypeName(lldb::opaque_compiler_type_t type, bool BaseOnly) override; + + ConstString GetDisplayTypeName(lldb::opaque_compiler_type_t type) override { + return GetTypeName(type, true); + } + + uint32_t GetTypeInfo(lldb::opaque_compiler_type_t type, + CompilerType *pointee_or_element_compiler_type) override; + + lldb::LanguageType + GetMinimumLanguage(lldb::opaque_compiler_type_t type) override; + + lldb::TypeClass GetTypeClass(lldb::opaque_compiler_type_t type) override; + + //---------------------------------------------------------------------- + // Creating related types + //---------------------------------------------------------------------- + + CompilerType GetArrayElementType(lldb::opaque_compiler_type_t type, + ExecutionContextScope *exe_scope) override; + + // Returns -1 if this isn't a function of if the function doesn't have a + // prototype Returns a value >= 0 if there is a prototype. + int GetFunctionArgumentCount(lldb::opaque_compiler_type_t type) override; + + CompilerType GetFunctionArgumentTypeAtIndex(lldb::opaque_compiler_type_t type, + size_t idx) override { + assert(0); + return CompilerType(); + } + + CompilerType + GetFunctionReturnType(lldb::opaque_compiler_type_t type) override; + + size_t GetNumMemberFunctions(lldb::opaque_compiler_type_t type) override { + return 0; + } + + CompilerType GetPointeeType(lldb::opaque_compiler_type_t type) override; + + CompilerType GetPointerType(lldb::opaque_compiler_type_t type) override; + + CompilerType + GetLValueReferenceType(lldb::opaque_compiler_type_t type) override; + + CompilerType + GetRValueReferenceType(lldb::opaque_compiler_type_t type) override { + assert(0); + return CompilerType(); + } + + bool VerifyEncodeType(lldb::opaque_compiler_type_t src_type, + lldb::opaque_compiler_type_t dst_type); + + bool EncodeDataToType( + ExecutionContext &exe_scope, lldb::opaque_compiler_type_t src_type, + const DataExtractor &src_data, lldb::opaque_compiler_type_t dest_type, + DataExtractor &dest_data, + const lldb::LanguageType lang = lldb::eLanguageTypeUnknown) override; + /* + CompilerType AddConstModifier(lldb::opaque_compiler_type_t type) override; + + CompilerType AddVolatileModifier(lldb::opaque_compiler_type_t type) + override; + + CompilerType AddRestrictModifier(lldb::opaque_compiler_type_t type) + override; + + CompilerType CreateTypedef(lldb::opaque_compiler_type_t type, + const char *name, + const CompilerDeclContext &decl_ctx) override; + */ + //---------------------------------------------------------------------- + // Exploring the type + //---------------------------------------------------------------------- + const llvm::fltSemantics &GetFloatTypeSemantics(size_t byte_size) override { + return llvm::APFloatBase::Bogus(); + } + + std::optional GetByteSize(lldb::opaque_compiler_type_t type, + ExecutionContextScope *exe_scope) { + if (std::optional bit_size = GetBitSize(type, exe_scope)) + return (*bit_size + 7) / 8; + return std::nullopt; + } + + std::optional + 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; + + llvm::Expected GetNumChildren(lldb::opaque_compiler_type_t type, + bool omit_empty_base_classes, + const ExecutionContext *exe_ctx) override; + + lldb::BasicType + GetBasicTypeEnumeration(lldb::opaque_compiler_type_t type) override; + + /// Dynamic type get base type + CompilerType DynGetBaseType(lldb::opaque_compiler_type_t type) const override; + + /// Dynamic type get location expression + DWARFExpressionList + DynGetLocation(lldb::opaque_compiler_type_t type) const override; + + /// Dynamic type get allocated expression + DWARFExpressionList + DynGetAllocated(lldb::opaque_compiler_type_t type) const override; + + /// Dynamic array type get count expression + DWARFExpressionList + DynArrGetCountExp(lldb::opaque_compiler_type_t type) const override; + + /// Dynamic array type update length value + bool + DynArrUpdateLength(lldb::opaque_compiler_type_t type, uint64_t length) override; + + uint32_t GetNumFields(lldb::opaque_compiler_type_t type) override { + // TODO struct members calculation + return 0; + } + + 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(); + } + + TypeMemberFunctionImpl + GetMemberFunctionAtIndex(lldb::opaque_compiler_type_t type, + size_t idx) override; + + CompilerType GetCanonicalType(lldb::opaque_compiler_type_t type) override; + + CompilerType + GetEnumerationIntegerType(lldb::opaque_compiler_type_t type) override; + + llvm::Expected 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; + + // Lookup a child given a name. This function will match base class names and + // member member names in "clang_type" only, not descendants. + uint32_t GetIndexOfChildWithName(lldb::opaque_compiler_type_t type, + llvm::StringRef name, + bool omit_empty_base_classes) override; + + // Lookup a child member given a name. This function will match member names + // only and will descend into "clang_type" children in search for the first + // member in this class, or any base class that matches "name". + // TODO: Return all matches for a given name by returning a + // vector> + // so we catch all names that match a given child name, not just the first. + size_t + GetIndexOfChildMemberWithName(lldb::opaque_compiler_type_t type, + llvm::StringRef name, bool omit_empty_base_classes, + std::vector &child_indexes) override; + + //---------------------------------------------------------------------- + // Creating Types + //---------------------------------------------------------------------- + + CompilerType CreateArrayType(const ConstString &array_type_name, + const ConstString &name, + const CompilerType &element_type, + size_t element_count, bool isVarString); + + CompilerType CreateArrayType(const ConstString &array_type_name, + const ConstString &name, + const CompilerType &element_type, + DWARFExpressionList element_count, bool isVarString); + + CompilerType CreateDynamicType(const CompilerType &base_type, + const DWARFExpressionList &dw_location, + const DWARFExpressionList &dw_allocated); + + CompilerType GetArrayType(lldb::opaque_compiler_type_t type, + uint64_t size) override; + + CompilerType CreateStructType(const ConstString &name, uint32_t byte_size); + + void AddFieldToStruct(const CompilerType &struct_type, + const ConstString &member_name, + const CompilerType &member_type, uint32_t byte_offset); + + void CompleteStructType(const CompilerType &struct_type); + + CompilerType CreateFunctionType(const ConstString &name, CompilerType *params, + size_t params_count, bool is_variadic); + + CompilerType CreateBaseType(const ConstString &name, + const ConstString &pic_string, uint32_t dw_ate, + uint32_t bitsize, uint32_t sign, int32_t scale, + uint32_t digit_count, lldb::ByteOrder byte_order, + bool bin_scale); + + //---------------------------------------------------------------------- + // Dumping types + //---------------------------------------------------------------------- +#ifndef NDEBUG + /// Convenience LLVM-style dump method for use in the debugger only. + /// In contrast to the other \p Dump() methods this directly invokes + /// \p clang::QualType::dump(). + LLVM_DUMP_METHOD void dump(lldb::opaque_compiler_type_t type) const override; +#endif + + 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, + lldb::DescriptionLevel level = + lldb::eDescriptionLevelFull) override; // Dump to stdout + + void DumpTypeDescription( + lldb::opaque_compiler_type_t type, Stream &s, + lldb::DescriptionLevel level = lldb::eDescriptionLevelFull) override; + + //---------------------------------------------------------------------- + // TODO: These methods appear unused. Should they be removed? + //---------------------------------------------------------------------- + + bool IsRuntimeGeneratedType(lldb::opaque_compiler_type_t type) override { + return false; + } + + //---------------------------------------------------------------------- + // TODO: Determine if these methods should move to ClangASTContext. + //---------------------------------------------------------------------- + + bool IsPointerOrReferenceType(lldb::opaque_compiler_type_t type, + CompilerType *pointee_type) override; + + unsigned GetTypeQualifiers(lldb::opaque_compiler_type_t type) override; + + bool IsCStringType(lldb::opaque_compiler_type_t type, + uint32_t &length) override; + + std::optional + GetTypeBitAlign(lldb::opaque_compiler_type_t type, + ExecutionContextScope *exe_scope) override; + + CompilerType GetBasicTypeFromAST(lldb::BasicType basic_type) override; + + CompilerType GetBuiltinTypeForEncodingAndBitSize(lldb::Encoding encoding, + size_t bit_size) override { + return CompilerType(); + } + + 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; + + // If the current object represents a typedef type, get the underlying type + 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, bool *is_rvalue) override; + CompilerType MutateBaseTypeSize(lldb::opaque_compiler_type_t type, + uint64_t sizeInBits) override; + + UserExpression *GetUserExpression(llvm::StringRef expr, + llvm::StringRef prefix, + SourceLanguage language, + Expression::ResultType desired_type, + const EvaluateExpressionOptions &options, + ValueObject *ctx_obj) override; + + FunctionCaller *GetFunctionCaller(const CompilerType &return_type, + const Address &function_address, + const ValueList &arg_value_list, + const char *name) override { + assert(0); + return nullptr; + } + void Dump(llvm::raw_ostream &output) override {} + PersistentExpressionState *GetPersistentExpressionState() override; + + lldb::LanguageType GetLanguage() const { return m_lang; } + void SetLanguage(lldb::LanguageType lang) { m_lang = lang; } + +private: + typedef std::map> TypeMap; + typedef std::map> BasicTypeMap; + typedef std::map> MutatedTypeMap; + int m_pointer_byte_size; + std::unique_ptr m_dwarf_ast_parser_ap; + lldb::TargetWP m_target_wp; + std::unique_ptr m_types; + std::unique_ptr m_basic_types; + std::unique_ptr m_mutated_types; + lldb::LanguageType m_lang = lldb::eLanguageTypeUnknown; + + TypeSystemLegacy(const TypeSystemLegacy &) = delete; + const TypeSystemLegacy &operator=(const TypeSystemLegacy &) = delete; +}; + +/// TODO cleanup, separate iconv +class TargetCharsetReader { +public: + TargetCharsetReader(lldb::TargetSP target_sp, bool encode = false) + : fromcode("") { +#if defined(USE_BUILTIN_ICONV) + icd = (iconv_t)-1; + if (target_sp) { + fromcode.assign(target_sp->GetTargetCharset().str()); + const char * to{}; + const char * from{}; + if ( encode ) { + to = fromcode.c_str(); + from = ""; + } else { + to = "//TRANSLIT //IGNORE"; + from = fromcode.c_str(); + } + icd = iconv_open(to, from); + } +#endif + } + + ~TargetCharsetReader() { +#if defined(USE_BUILTIN_ICONV) + iconv_close(icd); +#endif + } + + bool convert(std::string &inp) { + if (!IsValid()) + return false; + + bool Converted = false; +#if defined(USE_BUILTIN_ICONV) + size_t in_size = inp.length(); + size_t buffer_size = in_size*2; + char *src_ptr = const_cast(inp.c_str()); + std::vector buffer(buffer_size); + std::string dst; + + char *dst_ptr = &buffer[0]; + size_t out_size = buffer_size; + +#if 0 + // First reset to initial state + size_t iresult = iconv(icd, NULL, NULL, NULL, NULL); + if (iresult == (size_t)-1) { + int e = errno; + + Debugger::ReportError( + llvm::formatv( + "TargetCharsetReader: Failed to reset iconv state. error: {0}({1})\n", + e, llvm::sys::StrError(e).c_str()).str()); + + return false; + } +#endif + + size_t result = iconv(icd, &src_ptr, &in_size, &dst_ptr, &out_size); + if (result == (size_t)-1) { + int e = errno; + Debugger::ReportError( + llvm::formatv( + "TargetCharsetReader: Attempted iconv of {0} host-bytes, failed with error: {1}({2}): in_size={3} out_size={4}", + inp.length(), e, llvm::sys::StrError(e).c_str(), in_size, out_size).str()); + return false; + } + + ssize_t out_len = buffer_size - out_size; + if (out_len > 0) { + if ((size_t)out_len > inp.length()) { + out_len = inp.length(); + } + dst.append(&buffer[0], out_len); + Converted |= true; + } + if (Converted) { + inp.erase(); + inp = dst; + } +#endif + return Converted; + } + + bool convert(char *inp, size_t length) { + if (!IsValid()) + return false; +#if defined(USE_BUILTIN_ICONV) + size_t in_size = length; + size_t buffer_size = in_size*2; + char *src_ptr = inp; + std::vector buffer(buffer_size); + + char *dst_ptr = &buffer[0]; + size_t out_size = buffer_size; + +#if 0 + // First reset to initial state + size_t iresult = iconv(icd, NULL, NULL, NULL, NULL); + if (iresult == (size_t)-1) { + int e = errno; + Debugger::ReportError( + llvm::formatv( + "TargetCharsetReader: Failed to reset iconv state. error: {0}({1})\n", + e, llvm::sys::StrError(e).c_str()).str()); + return false; + } +#endif + + size_t result = iconv(icd, &src_ptr, &in_size, &dst_ptr, &out_size); + if (result == (size_t)-1) { + int e = errno; + Debugger::ReportError( + llvm::formatv( + "TargetCharsetReader: Attempted iconv of {0} host-bytes, failed with error: {1}({2}): in_size={3} out_size={4}", + length, e, llvm::sys::StrError(e).c_str(), in_size, out_size).str()); + return false; + } + ssize_t out_len = buffer_size - out_size; + if (out_len > 0) { + if ((size_t)out_len > length) { + out_len = length; + } + memcpy(inp, &buffer[0], out_len); + return true; + } +#endif + return false; + } + + bool IsValid() const { +#if defined(USE_BUILTIN_ICONV) + return icd != (iconv_t)-1; +#else + return false; +#endif + } + + ConstString getTargetFormat() const { return ConstString(fromcode); } + +private: + TargetCharsetReader(const TargetCharsetReader &) = delete; + const TargetCharsetReader &operator=(const TargetCharsetReader &) = delete; + + std::string fromcode; +#if defined(USE_BUILTIN_ICONV) + iconv_t icd; +#endif +}; + +} // namespace lldb_private + +#endif // liblldb_TypeSystemLegacy_h_ diff --git a/lldb/source/Symbol/CompilerType.cpp b/lldb/source/Symbol/CompilerType.cpp index f8da9ef7b7640d..e97354cd169b6b 100644 --- a/lldb/source/Symbol/CompilerType.cpp +++ b/lldb/source/Symbol/CompilerType.cpp @@ -129,6 +129,13 @@ bool CompilerType::GetPtrAuthAddressDiversity() const { return false; } +bool CompilerType::IsCStringType(uint32_t &length) const { + if (IsValid()) + if (auto type_system_sp = GetTypeSystem()) + return type_system_sp->IsCStringType(m_type, length); + return false; +} + bool CompilerType::IsFunctionType() const { if (IsValid()) if (auto type_system_sp = GetTypeSystem()) @@ -759,6 +766,42 @@ CompilerType::GetBasicTypeFromAST(lldb::BasicType basic_type) const { return type_system_sp->GetBasicTypeFromAST(basic_type); return CompilerType(); } + +CompilerType CompilerType::DynGetBaseType() const { + if (IsValid()) + if (auto type_system_sp = GetTypeSystem()) + return type_system_sp->DynGetBaseType(m_type); + return CompilerType(); +} + +DWARFExpressionList CompilerType::DynGetLocation() const { + if (IsValid()) + if (auto type_system_sp = GetTypeSystem()) + return type_system_sp->DynGetLocation(m_type); + return DWARFExpressionList(); +} + +DWARFExpressionList CompilerType::DynGetAllocated() const { + if (IsValid()) + if (auto type_system_sp = GetTypeSystem()) + return type_system_sp->DynGetAllocated(m_type); + return DWARFExpressionList(); +} + +DWARFExpressionList CompilerType::DynArrGetCountExp() const { + if (IsValid()) + if (auto type_system_sp = GetTypeSystem()) + return type_system_sp->DynArrGetCountExp(m_type); + return DWARFExpressionList(); +} + +bool CompilerType::DynArrUpdateLength(uint64_t length) { + if (IsValid()) + if (auto type_system_sp = GetTypeSystem()) + return type_system_sp->DynArrUpdateLength(m_type, length); + return false; +} + // Exploring the type std::optional @@ -791,6 +834,16 @@ lldb::Encoding CompilerType::GetEncoding(uint64_t &count) const { return lldb::eEncodingInvalid; } +bool CompilerType::EncodeDataToType(ExecutionContext &exe_ctx, + opaque_compiler_type_t src_type, + const DataExtractor &src_data, + DataExtractor &dest_data) { + if (!IsValid()) + return false; + return GetTypeSystem()->EncodeDataToType(exe_ctx, src_type, src_data, + m_type /*dest_type*/, dest_data); +} + lldb::Format CompilerType::GetFormat() const { if (IsValid()) if (auto type_system_sp = GetTypeSystem()) diff --git a/lldb/source/Symbol/Function.cpp b/lldb/source/Symbol/Function.cpp index 96d8322b43d843..79b883d40c5184 100644 --- a/lldb/source/Symbol/Function.cpp +++ b/lldb/source/Symbol/Function.cpp @@ -260,7 +260,7 @@ Function::Function(CompileUnit *comp_unit, lldb::user_id_t func_uid, const AddressRange &range) : UserID(func_uid), m_comp_unit(comp_unit), m_type_uid(type_uid), m_type(type), m_mangled(mangled), m_block(func_uid), m_range(range), - m_frame_base(), m_flags(), m_prologue_byte_size(0) { + m_frame_base(), m_rc_frame_base(), m_flags(), m_prologue_byte_size(0) { m_block.SetParentScope(this); assert(comp_unit != nullptr); } diff --git a/lldb/source/Symbol/ObjectFile.cpp b/lldb/source/Symbol/ObjectFile.cpp index 35317d209de1f9..86d708b8f3abd2 100644 --- a/lldb/source/Symbol/ObjectFile.cpp +++ b/lldb/source/Symbol/ObjectFile.cpp @@ -660,7 +660,7 @@ ObjectFile::GetLoadableData(Target &target) { return loadables; } -std::unique_ptr ObjectFile::CreateCallFrameInfo() { +std::unique_ptr ObjectFile::CreateCallFrameInfo() { return {}; } diff --git a/lldb/source/Symbol/TypeSystem.cpp b/lldb/source/Symbol/TypeSystem.cpp index 931ce1b0203a93..6dee9d63d685f1 100644 --- a/lldb/source/Symbol/TypeSystem.cpp +++ b/lldb/source/Symbol/TypeSystem.cpp @@ -89,6 +89,11 @@ CompilerType TypeSystem::GetAtomicType(lldb::opaque_compiler_type_t type) { return CompilerType(); } +CompilerType TypeSystem::MutateBaseTypeSize(lldb::opaque_compiler_type_t type, + uint64_t sizeInBits) { + return CompilerType(); +} + CompilerType TypeSystem::AddConstModifier(lldb::opaque_compiler_type_t type) { return CompilerType(); } @@ -132,6 +137,31 @@ size_t TypeSystem::GetNumTemplateArguments(lldb::opaque_compiler_type_t type, return 0; } +CompilerType +TypeSystem::DynGetBaseType(lldb::opaque_compiler_type_t type) const { + return CompilerType(); +} + +DWARFExpressionList +TypeSystem::DynGetLocation(lldb::opaque_compiler_type_t type) const { + return DWARFExpressionList(); +} + +DWARFExpressionList +TypeSystem::DynGetAllocated(lldb::opaque_compiler_type_t type) const { + return DWARFExpressionList(); +} + +DWARFExpressionList +TypeSystem::DynArrGetCountExp(lldb::opaque_compiler_type_t type) const { + return DWARFExpressionList(); +} + +bool +TypeSystem::DynArrUpdateLength(lldb::opaque_compiler_type_t type, uint64_t length) { + return false; +} + TemplateArgumentKind TypeSystem::GetTemplateArgumentKind(opaque_compiler_type_t type, size_t idx, bool expand_pack) { diff --git a/lldb/source/Symbol/Variable.cpp b/lldb/source/Symbol/Variable.cpp index d4e1ce43ef1f16..55c6f0b1c9a831 100644 --- a/lldb/source/Symbol/Variable.cpp +++ b/lldb/source/Symbol/Variable.cpp @@ -42,14 +42,16 @@ Variable::Variable(lldb::user_id_t uid, const char *name, const char *mangled, ValueType scope, SymbolContextScope *context, const RangeList &scope_range, Declaration *decl_ptr, const DWARFExpressionList &location_list, bool external, - bool artificial, bool location_is_constant_data, - bool static_member) + bool artificial, bool location_is_constant_data, + bool static_member, bool has_descriptor, + uint8_t lexical_scope) : UserID(uid), m_name(name), m_mangled(ConstString(mangled)), m_symfile_type_sp(symfile_type_sp), m_scope(scope), m_owner_scope(context), m_scope_range(scope_range), m_declaration(decl_ptr), m_location_list(location_list), m_external(external), - m_artificial(artificial), m_loc_is_const_data(location_is_constant_data), - m_static_member(static_member) {} + m_artificial(artificial),m_loc_is_const_data(location_is_constant_data), + m_static_member(static_member), m_has_descriptor(has_descriptor), + m_lexical_scope(lexical_scope) {} Variable::~Variable() = default; @@ -79,8 +81,9 @@ ConstString Variable::GetName() const { ConstString Variable::GetUnqualifiedName() const { return m_name; } -bool Variable::NameMatches(ConstString name) const { - if (m_name == name) +// TODO handle case insentitive mangling +bool Variable::NameMatches(ConstString name, bool case_sensitive) const { + if (ConstString::Equals(m_name, name, case_sensitive)) return true; SymbolContext variable_sc; m_owner_scope->CalculateSymbolContext(&variable_sc); diff --git a/lldb/source/Symbol/VariableList.cpp b/lldb/source/Symbol/VariableList.cpp index b7a396edd70111..8ff426648bf5a5 100644 --- a/lldb/source/Symbol/VariableList.cpp +++ b/lldb/source/Symbol/VariableList.cpp @@ -70,11 +70,12 @@ uint32_t VariableList::FindVariableIndex(const VariableSP &var_sp) { } VariableSP VariableList::FindVariable(ConstString name, - bool include_static_members) { + bool include_static_members, + bool case_sensitive) { VariableSP var_sp; iterator pos, end = m_variables.end(); for (pos = m_variables.begin(); pos != end; ++pos) { - if ((*pos)->NameMatches(name)) { + if ((*pos)->NameMatches(name, case_sensitive)) { if (include_static_members || !(*pos)->IsStaticMember()) { var_sp = (*pos); break; @@ -86,11 +87,13 @@ VariableSP VariableList::FindVariable(ConstString name, VariableSP VariableList::FindVariable(ConstString name, lldb::ValueType value_type, - bool include_static_members) { + bool include_static_members, + bool case_sensitive) { VariableSP var_sp; iterator pos, end = m_variables.end(); for (pos = m_variables.begin(); pos != end; ++pos) { - if ((*pos)->NameMatches(name) && (*pos)->GetScope() == value_type) { + if ((*pos)->NameMatches(name, case_sensitive) && + (*pos)->GetScope() == value_type) { if (include_static_members || !(*pos)->IsStaticMember()) { var_sp = (*pos); break; diff --git a/lldb/source/Target/StackFrame.cpp b/lldb/source/Target/StackFrame.cpp index fe0d4c93c50627..090d9f080d51e1 100644 --- a/lldb/source/Target/StackFrame.cpp +++ b/lldb/source/Target/StackFrame.cpp @@ -49,6 +49,7 @@ using namespace lldb_private; #define GOT_FRAME_BASE (RESOLVED_FRAME_ID_SYMBOL_SCOPE << 1) #define RESOLVED_VARIABLES (GOT_FRAME_BASE << 1) #define RESOLVED_GLOBAL_VARIABLES (RESOLVED_VARIABLES << 1) +#define GOT_STATIC_LINK (RESOLVED_GLOBAL_VARIABLES << 1) StackFrame::StackFrame(const ThreadSP &thread_sp, user_id_t frame_idx, user_id_t unwind_frame_index, addr_t cfa, @@ -58,7 +59,8 @@ StackFrame::StackFrame(const ThreadSP &thread_sp, user_id_t frame_idx, : m_thread_wp(thread_sp), m_frame_index(frame_idx), m_concrete_frame_index(unwind_frame_index), m_reg_context_sp(), m_id(pc, cfa, nullptr), m_frame_code_addr(pc), m_sc(), m_flags(), - m_frame_base(), m_frame_base_error(), m_cfa_is_valid(cfa_is_valid), + m_frame_base(), m_frame_base_error(), m_static_link(), + m_static_link_error(), m_cfa_is_valid(cfa_is_valid), m_stack_frame_kind(kind), m_behaves_like_zeroth_frame(behaves_like_zeroth_frame), m_variable_list_sp(), m_variable_list_value_objects(), @@ -85,8 +87,8 @@ StackFrame::StackFrame(const ThreadSP &thread_sp, user_id_t frame_idx, m_concrete_frame_index(unwind_frame_index), m_reg_context_sp(reg_context_sp), m_id(pc, cfa, nullptr), m_frame_code_addr(pc), m_sc(), m_flags(), m_frame_base(), - m_frame_base_error(), m_cfa_is_valid(true), - m_stack_frame_kind(StackFrame::Kind::Regular), + m_frame_base_error(), m_static_link(), m_static_link_error(), + m_cfa_is_valid(true), m_stack_frame_kind(StackFrame::Kind::Regular), m_behaves_like_zeroth_frame(behaves_like_zeroth_frame), m_variable_list_sp(), m_variable_list_value_objects(), m_recognized_frame_sp(), m_disassembly(), m_mutex() { @@ -113,8 +115,8 @@ StackFrame::StackFrame(const ThreadSP &thread_sp, user_id_t frame_idx, m_id(pc_addr.GetLoadAddress(thread_sp->CalculateTarget().get()), cfa, nullptr), m_frame_code_addr(pc_addr), m_sc(), m_flags(), m_frame_base(), - m_frame_base_error(), m_cfa_is_valid(true), - m_stack_frame_kind(StackFrame::Kind::Regular), + m_frame_base_error(), m_static_link(), m_static_link_error(), + m_cfa_is_valid(true), m_stack_frame_kind(StackFrame::Kind::Regular), m_behaves_like_zeroth_frame(behaves_like_zeroth_frame), m_variable_list_sp(), m_variable_list_value_objects(), m_recognized_frame_sp(), m_disassembly(), m_mutex() { @@ -550,16 +552,53 @@ ValueObjectSP StackFrame::GetValueForVariableExpressionPath( var_expr = var_expr.drop_front(); // Skip the '&' } - size_t separator_idx = var_expr.find_first_of(".-[=+~|&^%#@!/?,<>{}"); + size_t separator_idx = 0; + // TODO needs better handling + SourceLanguage language = + GetLanguage(); // Assume GetLanguage() returns LanguageType. + bool LegacyLangauage = (language == eLanguageTypeCobol85) || + (language == eLanguageTypeCobol74) || + (language == eLanguageTypePLI) || + (language == eLanguageTypeFortran90); + + if (LegacyLangauage) + separator_idx = var_expr.find_first_of(".[(=+~|&^%#@!/?,<>{}"); + else + separator_idx = var_expr.find_first_of(".-[=+~|&^%#@!/?,<>{}"); StreamString var_expr_path_strm; ConstString name_const_string(var_expr.substr(0, separator_idx)); - var_sp = variable_list->FindVariable(name_const_string, false); + // LegacyLanguages listed above are case insesnitive. + var_sp = variable_list->FindVariable(name_const_string, false, !LegacyLangauage); + + if (!var_sp && LegacyLangauage) { + for (size_t i = 0; i < variable_list->GetSize(); i++) { + VariableSP variable_sp = variable_list->GetVariableAtIndex(i); + if (!variable_sp) + continue; + + Type *var_type = variable_sp->GetType(); + if (!var_type) + continue; + + if (!var_type->IsAggregateType()) + continue; + + valobj_sp = GetValueObjectForFrameVariable(variable_sp, use_dynamic); + if (!valobj_sp) + return valobj_sp; + + valobj_sp = GetValueObjectForFrameAggregateVariable( + name_const_string, valobj_sp, use_dynamic); + if (valobj_sp) + break; + } + } bool synthetically_added_instance_object = false; - if (var_sp) { + if (var_sp || valobj_sp) { var_expr = var_expr.drop_front(name_const_string.GetLength()); } @@ -621,11 +660,15 @@ ValueObjectSP StackFrame::GetValueForVariableExpressionPath( return ValueObjectSP(); } + llvm::StringRef type_name(valobj_sp->GetTypeName().GetStringRef()); + const bool is_bit_type = type_name.starts_with("BIT "); + // We are dumping at least one child while (!var_expr.empty()) { // Calculate the next separator index ahead of time ValueObjectSP child_valobj_sp; - const char separator_type = var_expr[0]; + const bool is_sep_mem_select = (LegacyLangauage && (var_expr[0] == '(')); + const char separator_type = is_sep_mem_select ? '[' : var_expr[0]; bool expr_is_ptr = false; switch (separator_type) { case '-': @@ -678,8 +721,9 @@ ValueObjectSP StackFrame::GetValueForVariableExpressionPath( [[fallthrough]]; case '.': { var_expr = var_expr.drop_front(); // Remove the '.' or '>' - separator_idx = var_expr.find_first_of(".-["); - ConstString child_name(var_expr.substr(0, var_expr.find_first_of(".-["))); + separator_idx = LegacyLangauage ? var_expr.find_first_of(".[") + : var_expr.find_first_of(".-["); + ConstString child_name(var_expr.substr(0, separator_idx)); if (check_ptr_vs_member) { // We either have a pointer type and need to verify valobj_sp is a @@ -764,12 +808,19 @@ ValueObjectSP StackFrame::GetValueForVariableExpressionPath( return ValueObjectSP(); } + if (var_expr.find_first_of(':') != llvm::StringRef::npos) { + error = Status::FromErrorString("member select with length not supported."); + return ValueObjectSP(); + } + // Drop the open brace. var_expr = var_expr.drop_front(); long child_index = 0; + long bit_pos = 0; + long old_child_index = 0; // If there's no closing brace, this is an invalid expression. - size_t end_pos = var_expr.find_first_of(']'); + size_t end_pos = var_expr.find_first_of(is_sep_mem_select ? ')' : ']'); if (end_pos == llvm::StringRef::npos) { error = Status::FromErrorStringWithFormat( "missing closing square bracket in expression \"%s\"", @@ -789,9 +840,24 @@ ValueObjectSP StackFrame::GetValueForVariableExpressionPath( return ValueObjectSP(); } + // index correction for legacy languages. + if (is_sep_mem_select) { + if (child_index < 1) { + error = Status::FromErrorString("invalid index."); + return ValueObjectSP(); + } + child_index -= 1; + } + if (index_expr.empty()) { // The entire index expression was a single integer. + if(is_bit_type) { + old_child_index = child_index; + bit_pos = 7 - (child_index % 8); + child_index /= 8; + } + if (valobj_sp->GetCompilerType().IsPointerToScalarType() && deref) { // what we have is *ptr[low]. the most similar C++ syntax is to deref // ptr and extract bit low out of it. reading array item low would be @@ -962,6 +1028,14 @@ ValueObjectSP StackFrame::GetValueForVariableExpressionPath( if (dynamic_value_sp) child_valobj_sp = dynamic_value_sp; } + + if (is_bit_type) { + child_valobj_sp = child_valobj_sp->GetSyntheticBitFieldChild( + bit_pos, bit_pos, true); + child_valobj_sp->SetName( + ConstString(llvm::formatv("[{0}]", old_child_index).str())); + } + // Break out early from the switch since we were able to find the child // member break; @@ -1132,6 +1206,59 @@ DWARFExpressionList *StackFrame::GetFrameBaseExpression(Status *error_ptr) { return &m_sc.function->GetFrameBaseExpression(); } +bool StackFrame::GetStaticLinkValue(Scalar &static_link, Status *error_ptr) { + std::lock_guard guard(m_mutex); + if (!m_cfa_is_valid) { + m_static_link_error = Status::FromErrorString( + "No static link available for this historical stack frame."); + return false; + } + + if (m_flags.IsClear(GOT_STATIC_LINK)) { + if (m_sc.function) { + m_static_link.Clear(); + m_static_link_error.Clear(); + + m_flags.Set(GOT_STATIC_LINK); + ExecutionContext exe_ctx(shared_from_this()); + Value expr_value; + addr_t loclist_base_addr = LLDB_INVALID_ADDRESS; + if (m_sc.function->GetStaticLinkExpression().IsValid()) + loclist_base_addr = + m_sc.function->GetAddressRange().GetBaseAddress().GetLoadAddress( + exe_ctx.GetTargetPtr()); + + if (!m_sc.function->GetStaticLinkExpression().Evaluate( + &exe_ctx, nullptr, loclist_base_addr, nullptr, nullptr)) { + // We should really have an error if evaluate returns, but in case we + // don't, lets set the error to something at least. + if (m_static_link_error.Success()) + m_static_link_error = Status::FromErrorString( + "Evaluation of the static link expression failed."); + } else { + m_static_link = expr_value.ResolveValue(&exe_ctx); + } + } else { + m_static_link_error = Status::FromErrorString("No function in symbol context."); + } + } + + if (m_static_link_error.Success()) + static_link = m_static_link; + + if (error_ptr) + *error_ptr = std::move(m_static_link_error); + return m_static_link_error.Success(); +} + +DWARFExpressionList *StackFrame::GetStaticLinkExpression(Status &error) { + if (!m_sc.function) { + error = Status::FromErrorString("No function in symbol context."); + return nullptr; + } + return &m_sc.function->GetStaticLinkExpression(); +} + RegisterContextSP StackFrame::GetRegisterContext() { std::lock_guard guard(m_mutex); if (!m_reg_context_sp) { @@ -1147,6 +1274,41 @@ bool StackFrame::HasDebugInformation() { return m_sc.line_entry.IsValid(); } +ValueObjectSP StackFrame::GetValueObjectForFrameAggregateVariable( + ConstString name, ValueObjectSP &valobj_sp, DynamicValueType use_dynamic, bool look_in_array) { + + if (!valobj_sp) + return valobj_sp; + + bool is_complete; + if (valobj_sp->GetCompilerType().IsArrayType(nullptr, nullptr, &is_complete)) { + if (!look_in_array || !valobj_sp->GetCompilerType().IsAggregateType()) + return nullptr; + } + + ValueObjectSP result = valobj_sp->GetChildMemberWithName(name, true); + if (result) + return result; + + uint32_t num_children = valobj_sp->GetNumChildren().get(); + // for (size_t index = 0; index < valobj_sp->GetNumChildren(); ++index) { + for (uint32_t index = 0; index < num_children; ++index) { + + ValueObjectSP child = valobj_sp->GetChildAtIndex(index, true); + if (!child) + continue; + + CompilerType child_type = child->GetCompilerType(); + if (!child_type.IsAggregateType()) + continue; + + result = GetValueObjectForFrameAggregateVariable(name, child, use_dynamic, look_in_array); + if (result) + break; + } + return result; +} + ValueObjectSP StackFrame::GetValueObjectForFrameVariable(const VariableSP &variable_sp, DynamicValueType use_dynamic) { @@ -1186,6 +1348,31 @@ StackFrame::GetValueObjectForFrameVariable(const VariableSP &variable_sp, return valobj_sp; } +ValueObjectSP StackFrame::TrackGlobalVariable(const VariableSP &variable_sp, + DynamicValueType use_dynamic) { + std::lock_guard guard(m_mutex); + if (IsHistorical()) + return ValueObjectSP(); + + // Check to make sure we aren't already tracking this variable? + ValueObjectSP valobj_sp( + GetValueObjectForFrameVariable(variable_sp, use_dynamic)); + if (!valobj_sp) { + // We aren't already tracking this global + VariableList *var_list = GetVariableList(true, nullptr); + // If this frame has no variables, create a new list + if (var_list == nullptr) + m_variable_list_sp = std::make_shared(); + + // Add the global/static variable to this frame + m_variable_list_sp->AddVariable(variable_sp); + + // Now make a value object for it so we can track its changes + valobj_sp = GetValueObjectForFrameVariable(variable_sp, use_dynamic); + } + return valobj_sp; +} + bool StackFrame::IsInlined() { if (m_sc.block == nullptr) GetSymbolContext(eSymbolContextBlock); @@ -1734,16 +1921,34 @@ lldb::ValueObjectSP StackFrame::FindVariable(ConstString name) { VariableSP var_sp; SymbolContext sc(GetSymbolContext(eSymbolContextBlock)); + // FIXME optimise this + bool LegacyLangauage = (GetLanguage() == eLanguageTypeCobol85) || + (GetLanguage() == eLanguageTypeCobol74) || + (GetLanguage() == eLanguageTypePLI) || + (GetLanguage() == eLanguageTypeFortran90); + if (sc.block) { const bool can_create = true; const bool get_parent_variables = true; const bool stop_if_block_is_inlined_function = true; - if (sc.block->AppendVariables( + /* + This change is in reference to 1156032652. + `Block::AppendVariable` traverse the parent block-chain and appends all + the in-scope variables to `variable_list`, it may also append file-global + variables as the top-most block must be the file itself. That doesn't work + for Legacy Languages as the parent block is empty. + */ + if (LegacyLangauage) { + VariableListSP var_list_sp(GetInScopeVariableList(true)); + VariableList *var_list = var_list_sp.get(); + var_sp = var_list->FindVariable(name, true, false); + } else if (sc.block->AppendVariables( can_create, get_parent_variables, stop_if_block_is_inlined_function, [this](Variable *v) { return v->IsInScope(this); }, &variable_list)) { - var_sp = variable_list.FindVariable(name); + // LegacyLanguages listed above are case insensitive + var_sp = variable_list.FindVariable(name, true, !LegacyLangauage); } if (var_sp) @@ -1806,6 +2011,10 @@ void StackFrame::DumpUsingSettingsFormat(Stream *strm, bool show_unique, const FormatEntity::Entry *frame_format = nullptr; Target *target = exe_ctx.GetTargetPtr(); if (target) { + bool skip_invalid_line_frames = target->GetHideInvalidLegacyFrames(); + if (skip_invalid_line_frames && m_sc.line_entry.line == 0) + return; + if (show_unique) { frame_format = target->GetDebugger().GetFrameFormatUnique(); } else { @@ -1878,6 +2087,8 @@ void StackFrame::UpdatePreviousFrameFromCurrentFrame(StackFrame &curr_frame) { m_flags.Set(m_sc.GetResolvedMask()); m_frame_base.Clear(); m_frame_base_error.Clear(); + m_static_link.Clear(); + m_static_link_error.Clear(); } bool StackFrame::HasCachedData() const { diff --git a/lldb/source/Target/StackFrameList.cpp b/lldb/source/Target/StackFrameList.cpp index 3849ec5ed178d9..cda31e317e1271 100644 --- a/lldb/source/Target/StackFrameList.cpp +++ b/lldb/source/Target/StackFrameList.cpp @@ -787,6 +787,27 @@ StackFrameSP StackFrameList::GetFrameWithStackID(const StackID &stack_id) { return frame_sp; } +StackFrameSP +StackFrameList::GetFrameWithFrameBaseAddr(const addr_t frame_base) { + StackFrameSP frame_sp; + + uint32_t frame_idx = 0; + do { + frame_sp = GetFrameAtIndex(frame_idx); + if (frame_sp) { + Scalar curr_frame_base; + Status curr_frame_error; + if (frame_sp->GetFrameBaseValue(curr_frame_base, &curr_frame_error)) { + lldb::addr_t fb_addr = curr_frame_base.ULongLong(LLDB_INVALID_ADDRESS); + if (fb_addr == frame_base) + return frame_sp; + } + } + frame_idx++; + } while (frame_sp); + return frame_sp; +} + bool StackFrameList::SetFrameAtIndex(uint32_t idx, StackFrameSP &frame_sp) { if (idx >= m_frames.size()) m_frames.resize(idx + 1); diff --git a/lldb/source/Target/Target.cpp b/lldb/source/Target/Target.cpp index f1c378b968d2ba..954a0552196829 100644 --- a/lldb/source/Target/Target.cpp +++ b/lldb/source/Target/Target.cpp @@ -4847,6 +4847,18 @@ bool TargetProperties::GetAutoInstallMainExecutable() const { idx, g_target_properties[idx].default_uint_value != 0); } +llvm::StringRef TargetProperties::GetTargetCharset() const { + const uint32_t idx = ePropertyCharacterSet; + return GetPropertyAtIndexAs(idx, + g_target_properties[idx].default_cstr_value); +} + +bool TargetProperties::GetHideInvalidLegacyFrames() const { + const uint32_t idx = ePropertyHideInvalidLegacyFrames; + return GetPropertyAtIndexAs( + idx, g_target_properties[idx].default_uint_value != 0); +} + void TargetProperties::Arg0ValueChangedCallback() { m_launch_info.SetArg0(GetArg0()); } diff --git a/lldb/source/Target/TargetProperties.td b/lldb/source/Target/TargetProperties.td index 0f68deb543f90e..e404f8770ab7fa 100644 --- a/lldb/source/Target/TargetProperties.td +++ b/lldb/source/Target/TargetProperties.td @@ -201,6 +201,12 @@ let Definition = "target" in { def DebugUtilityExpression: Property<"debug-utility-expression", "Boolean">, DefaultFalse, Desc<"Enable debugging of LLDB-internal utility expressions.">; + def CharacterSet: Property<"charset", "String">, + DefaultStringValue<"ASCII">, + Desc<"Set Target character set.">; + def HideInvalidLegacyFrames: Property<"hide-invalid-legacy-frames", "Boolean">, + DefaultTrue, + Desc<"hides invalid legacy frames while printing.">; } let Definition = "process_experimental" in { diff --git a/lldb/source/Utility/DataExtractor.cpp b/lldb/source/Utility/DataExtractor.cpp index e9be0cba81f0c3..3d97f95502bdca 100644 --- a/lldb/source/Utility/DataExtractor.cpp +++ b/lldb/source/Utility/DataExtractor.cpp @@ -972,6 +972,22 @@ size_t DataExtractor::Copy(DataExtractor &dest_data) const { return GetByteSize(); } +bool DataExtractor::Compare(DataExtractor &rhs) { + if (rhs.GetByteOrder() != GetByteOrder()) + return false; + if (rhs.GetByteSize() != GetByteSize()) + return false; + + const uint8_t *lhs_ptr = GetDataStart(); + const uint8_t *rhs_ptr = rhs.GetDataStart(); + + for(uint8_t i = 0; i&1 | FileCheck %s --check-prefix AS ASM-NOT: This version of LLDB has no plugin for the language "assembler" RUN: %clang_host %S/Inputs/true.c -std=c99 -g -c -S -emit-llvm -o - \ -RUN: | sed -e 's/DW_LANG_C99/DW_LANG_Cobol74/g' >%t.ll +RUN: | sed -e 's/DW_LANG_C99/DW_LANG_D/g' >%t.ll RUN: %clang_host %t.ll -g -o %t.exe -RUN: %lldb -o "b main" -o r -o q -b %t.exe 2>&1 | FileCheck %s --check-prefix COBOL +RUN: %lldb -o "b main" -o r -o q -b %t.exe 2>&1 | FileCheck %s --check-prefix=D -COBOL: This version of LLDB has no plugin for the language "cobol74" +D: This version of LLDB has no plugin for the language "d" diff --git a/lldb/tools/lldb-server/CMakeLists.txt b/lldb/tools/lldb-server/CMakeLists.txt index 9030ed709a647a..7ea99f674ded9c 100644 --- a/lldb/tools/lldb-server/CMakeLists.txt +++ b/lldb/tools/lldb-server/CMakeLists.txt @@ -55,6 +55,7 @@ add_lldb_tool(lldb-server lldbPluginInstructionMIPS64 lldbPluginInstructionRISCV ${LLDB_SYSTEM_LIBS} + LLVMRuntimeDyld LINK_COMPONENTS Option diff --git a/lldb/unittests/Expression/DWARFExpressionTest.cpp b/lldb/unittests/Expression/DWARFExpressionTest.cpp index f9e0605fce29d6..cc697089e855be 100644 --- a/lldb/unittests/Expression/DWARFExpressionTest.cpp +++ b/lldb/unittests/Expression/DWARFExpressionTest.cpp @@ -34,11 +34,20 @@ static llvm::Expected Evaluate(llvm::ArrayRef expr, DataExtractor extractor(expr.data(), expr.size(), lldb::eByteOrderLittle, /*addr_size*/ 4); - llvm::Expected result = + std::vector stack; + + llvm::Expected result = + DWARFExpression::Evaluate(exe_ctx, /*reg_ctx*/ nullptr, module_sp, + extractor, unit, lldb::eRegisterKindLLDB, + /*object_address_ptr*/ nullptr, nullptr, stack); + if (!result) + return result.takeError(); + + result = DWARFExpression::Evaluate(exe_ctx, /*reg_ctx*/ nullptr, module_sp, extractor, unit, lldb::eRegisterKindLLDB, /*initial_value_ptr*/ nullptr, - /*object_address_ptr*/ nullptr); + /*object_address_ptr*/ nullptr, stack); if (!result) return result.takeError(); @@ -455,12 +464,12 @@ TEST_F(DWARFExpressionMockProcessTest, WASM_DW_OP_addr) { uint8_t expr[] = {DW_OP_addr, 0x40, 0x0, 0x0, 0x0}; DataExtractor extractor(expr, sizeof(expr), lldb::eByteOrderLittle, /*addr_size*/ 4); - + std::vector stack; llvm::Expected result = DWARFExpression::Evaluate( &exe_ctx, /*reg_ctx*/ nullptr, /*module_sp*/ {}, extractor, /*unit*/ nullptr, lldb::eRegisterKindLLDB, /*initial_value_ptr*/ nullptr, - /*object_address_ptr*/ nullptr); + /*object_address_ptr*/ nullptr, stack); ASSERT_THAT_EXPECTED(result, llvm::Succeeded()); ASSERT_EQ(result->GetValueType(), Value::ValueType::LoadAddress); @@ -532,12 +541,13 @@ TEST_F(DWARFExpressionMockProcessTest, WASM_DW_OP_addr_index) { auto evaluate = [&](DWARFExpression &expr) -> llvm::Expected { DataExtractor extractor; + std::vector stack; expr.GetExpressionData(extractor); return DWARFExpression::Evaluate(&exe_ctx, /*reg_ctx*/ nullptr, /*module_sp*/ {}, extractor, dwarf_cu, lldb::eRegisterKindLLDB, /*initial_value_ptr*/ nullptr, - /*object_address_ptr*/ nullptr); + /*object_address_ptr*/ nullptr, stack); }; // DW_OP_addrx takes a single leb128 operand, the index in the addr table: @@ -809,6 +819,7 @@ TEST_F(DWARFExpressionMockProcessTest, DW_OP_piece_file_addr) { lldb::DebuggerSP debugger_sp = Debugger::CreateInstance(); ASSERT_TRUE(debugger_sp); lldb::PlatformSP platform_sp; + std::vector stack; auto target_sp = std::make_shared(*debugger_sp, arch, platform_sp); ASSERT_TRUE(target_sp); @@ -829,7 +840,7 @@ TEST_F(DWARFExpressionMockProcessTest, DW_OP_piece_file_addr) { &exe_ctx, /*reg_ctx*/ nullptr, /*module_sp*/ {}, extractor, /*unit*/ nullptr, lldb::eRegisterKindLLDB, /*initial_value_ptr*/ nullptr, - /*object_address_ptr*/ nullptr); + /*object_address_ptr*/ nullptr, stack); ASSERT_THAT_EXPECTED(result, llvm::Succeeded()); ASSERT_EQ(result->GetValueType(), Value::ValueType::HostAddress); diff --git a/lldb/unittests/ObjectFile/PECOFF/TestPECallFrameInfo.cpp b/lldb/unittests/ObjectFile/PECOFF/TestPECallFrameInfo.cpp index e842df59888670..384d503096e551 100644 --- a/lldb/unittests/ObjectFile/PECOFF/TestPECallFrameInfo.cpp +++ b/lldb/unittests/ObjectFile/PECOFF/TestPECallFrameInfo.cpp @@ -196,7 +196,8 @@ symbols: [] ObjectFile *object_file = module_sp->GetObjectFile(); ASSERT_NE(object_file, nullptr); - std::unique_ptr cfi = object_file->CreateCallFrameInfo(); + std::unique_ptr cfi = + object_file->CreateCallFrameInfo(); ASSERT_NE(cfi.get(), nullptr); SectionList *sect_list = object_file->GetSectionList(); diff --git a/llvm/include/llvm-c/DebugInfo.h b/llvm/include/llvm-c/DebugInfo.h index 6d8891e7057722..59470c62b86064 100644 --- a/llvm/include/llvm-c/DebugInfo.h +++ b/llvm/include/llvm-c/DebugInfo.h @@ -64,6 +64,7 @@ typedef enum { LLVMDIFlagNonTrivial = 1 << 26, LLVMDIFlagBigEndian = 1 << 27, LLVMDIFlagLittleEndian = 1 << 28, + LLVMDIFlagBinaryScale = 1 << 30, LLVMDIFlagIndirectVirtualBase = (1 << 2) | (1 << 5), LLVMDIFlagAccessibility = LLVMDIFlagPrivate | LLVMDIFlagProtected | LLVMDIFlagPublic, @@ -154,6 +155,18 @@ typedef enum { LLVMDWARFEmissionLineTablesOnly } LLVMDWARFEmissionKind; +/** + * Decimal sign attribute knwon by DWARF + */ +typedef enum { + LLVMDWARFDSNone = 0, + LLVMDWARFDSUnsigned, + LLVMDWARFDSLeadingOverpunch, + LLVMDWARFDSTrailingOverpunch, + LLVMDWARFDSLeadingSeparate, + LLVMDWARFDSTrailingSeparate, +} LLVMDWARFDecimalSign; + /** * The kind of metadata nodes. */ @@ -379,6 +392,36 @@ LLVMMetadataRef LLVMDIBuilderCreateFunction( LLVMBool IsLocalToUnit, LLVMBool IsDefinition, unsigned ScopeLine, LLVMDIFlags Flags, LLVMBool IsOptimized); +/** + * Create a new descriptor for the specified subprogram. + * \param Builder The \c DIBuilder. + * \param Scope Function scope. + * \param Name Function name. + * \param NameLen Length of enumeration name. + * \param LinkageName Mangled function name. + * \param LinkageNameLen Length of linkage name. + * \param File File where this variable is defined. + * \param LineNo Line number. + * \param Ty Function type. + * \param IsLocalToUnit True if this function is not externally visible. + * \param IsDefinition True if this is a function definition. + * \param ScopeLine Set to the beginning of the scope this starts + * \param Flags E.g.: \c LLVMDIFlagLValueReference. These flags are + * used to emit dwarf attributes. + * \param IsOptimized True if optimization is ON. + * \param IsDiscList True if descriptor of parameters passed by list. + * \param IsDiscLoc True if descriptor of parameters passed by locator. + * \param StaticLinkExpr DIExpression for static link. + */ +LLVMMetadataRef LLVMDIBuilderCreateFunction2( + LLVMDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name, + size_t NameLen, const char *LinkageName, size_t LinkageNameLen, + LLVMMetadataRef File, unsigned LineNo, LLVMMetadataRef Ty, + LLVMBool IsLocalToUnit, LLVMBool IsDefinition, unsigned ScopeLine, + LLVMDIFlags Flags, LLVMBool IsOptimized, LLVMBool IsDiscList, + // LLVMBool IsDiscLoc, LLVMMetadataRef StaticLinkExpr); + LLVMBool IsDiscLoc, LLVMMetadataRef StaticLinkExpr, LLVMMetadataRef RcFrameBaseExpr); + /** * Create a descriptor for a lexical block with the specified parent context. * \param Builder The \c DIBuilder. @@ -684,6 +727,26 @@ LLVMDIBuilderCreateArrayType(LLVMDIBuilderRef Builder, uint64_t Size, LLVMMetadataRef *Subscripts, unsigned NumSubscripts); +/** + * Create debugging information entry for an array with header + * \param Builder The DIBuilder. + * \param Size Array size. + * \param AlignInBits Alignment. + * \param Ty Element type. + * \param Subscripts Subscripts. + * \param NumSubscripts Number of subscripts. + * \param IsVarString PL/I varying string. + * \param Name Array type name. + * \param NameLen Length of array type name. + */ +LLVMMetadataRef +LLVMDIBuilderCreateArrayType2(LLVMDIBuilderRef Builder, uint64_t Size, + uint32_t AlignInBits, LLVMMetadataRef Ty, + LLVMMetadataRef *Subscripts, + unsigned NumSubscripts, + LLVMBool isVarString, + const char* Name, size_t NameLen); + /** * Create debugging information entry for a vector type. * \param Builder The DIBuilder. @@ -725,6 +788,28 @@ LLVMDIBuilderCreateBasicType(LLVMDIBuilderRef Builder, const char *Name, LLVMDWARFTypeEncoding Encoding, LLVMDIFlags Flags); +/** + * Create debugging information entry for a basic + * type. + * \param Builder The DIBuilder. + * \param Name Type name. + * \param NameLen Length of type name. + * \param PicStrin Picture string. + * \param PicLen Length of Picture string. + * \param SizeInBits Size of the type. + * \param Encoding DWARF encoding code + * \param digits digits count, 0 if not applicable + * \param sign decimal sign, LLVMDWARFDSNone if not applicable +.* \param scale decimal scale, isScalePresent to false, if not N/A + * \param isScalePresent set to True is scale param is applicable + * \param Flags Flags to encode optional attribute like endianity + */ +LLVMMetadataRef LLVMDIBuilderCreateDecimalType( + LLVMDIBuilderRef Builder, const char *Name, size_t NameLen, + const char *PicString, size_t PicLen, uint64_t SizeInBits, + LLVMDWARFTypeEncoding Encoding, uint32_t digits, LLVMDWARFDecimalSign sign, + int32_t scale, LLVMBool isScalePresent, LLVMDIFlags Flags); + /** * Create debugging information entry for a pointer. * \param Builder The DIBuilder. @@ -889,6 +974,19 @@ LLVMMetadataRef LLVMDIBuilderCreateQualifiedType(LLVMDIBuilderRef Builder, unsigned Tag, LLVMMetadataRef Type); +/** + * Create debugging information entry for a dynamic type + * type, e.g. descriptor entry in PL1 + * \param Builder The DIBuilder. + * \param Type Base Type. + * \param Location DIExpression to get to raw data. + * \param Allocated DIExpression to get allocated status. + */ +LLVMMetadataRef LLVMDIBuilderCreateDynamicType(LLVMDIBuilderRef Builder, + LLVMMetadataRef Type, + LLVMMetadataRef Location, + LLVMMetadataRef Allocated); + /** * Create debugging information entry for a c++ * style reference or rvalue reference type. @@ -1108,6 +1206,30 @@ LLVMMetadataRef LLVMDIBuilderGetOrCreateSubrange(LLVMDIBuilderRef Builder, int64_t LowerBound, int64_t Count); +/** + * Create a descriptor for a value range. + * \param Builder The DIBuilder. + * \param LowerBound Lower bound of the subrange, e.g. 0 for C, 1 for Fortran. + * \param Count DI Node of Count of elements in the subrange. + */ +LLVMMetadataRef LLVMDIBuilderGetOrCreateSubrange2(LLVMDIBuilderRef Builder, + int64_t LowerBound, + LLVMMetadataRef Count); + +/** + * Create a descriptor for a value range. + * \param Builder The DIBuilder. + * \param Count DI Node of Count of elements in the subrange. + * \param LB DI Node of Lower Bound of the subrange. + * \param UB DI Node of Upper Bound of the subrange. + * \param Stride DI Node of Stride of the subrange. + */ +LLVMMetadataRef LLVMDIBuilderGetOrCreateSubrange3(LLVMDIBuilderRef Builder, + LLVMMetadataRef Count, + LLVMMetadataRef LB, + LLVMMetadataRef UB, + LLVMMetadataRef Stride); + /** * Create an array of DI Nodes. * \param Builder The DIBuilder. @@ -1128,6 +1250,20 @@ LLVMMetadataRef LLVMDIBuilderGetOrCreateArray(LLVMDIBuilderRef Builder, LLVMMetadataRef LLVMDIBuilderCreateExpression(LLVMDIBuilderRef Builder, uint64_t *Addr, size_t Length); +/** + * Create a new descriptor for the specified variable which has a complex + * address expression for its address. + * \param Builder The DIBuilder. + * \param Addr An array of complex address operations. + * \param Length Length of the address operation array. + * \param Refs An array of Reference used in call2/call4 offset. + * \param RefLength Length of the refrence array. + */ +LLVMMetadataRef LLVMDIBuilderCreateExpressionWithRef(LLVMDIBuilderRef Builder, + int64_t *Addr, size_t Length, + LLVMMetadataRef *Refs, + size_t RefLength); + /** * Create a new descriptor for the specified variable that does not have an * address, but does have a constant value. @@ -1341,6 +1477,46 @@ LLVMDbgRecordRef LLVMDIBuilderInsertDbgValueRecordAtEnd( LLVMDIBuilderRef Builder, LLVMValueRef Val, LLVMMetadataRef VarInfo, LLVMMetadataRef Expr, LLVMMetadataRef DebugLoc, LLVMBasicBlockRef Block); +/** + * Create a new descriptor for a local auto variable. + * \param Builder The DIBuilder. + * \param Scope The local scope the variable is declared in. + * \param Name Variable name. + * \param NameLen Length of variable name. + * \param File File where this variable is defined. + * \param LineNo Line number. + * \param LexicalScope Lexical scope of var for lang like PL/I. + * \param Ty Metadata describing the type of the variable. + * \param AlwaysPreserve If true, this descriptor will survive optimizations. + * \param Flags Flags. + * \param AlignInBits Variable alignment. + */ +LLVMMetadataRef LLVMDIBuilderCreateAutoVariable2( + LLVMDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name, + size_t NameLen, LLVMMetadataRef File, unsigned LineNo, + unsigned LexicalScope, LLVMMetadataRef Ty, LLVMBool AlwaysPreserve, + LLVMDIFlags Flags, uint32_t AlignInBits, LLVMBool IsLocatorDesc); + +/** + * Create a new descriptor for a function parameter variable. + * \param Builder The DIBuilder. + * \param Scope The local scope the variable is declared in. + * \param Name Variable name. + * \param NameLen Length of variable name. + * \param ArgNo Unique argument number for this variable; starts at 1. + * \param LexicalScope Lexical scope of param for lang like PL/I + * \param File File where this variable is defined. + * \param LineNo Line number. + * \param Ty Metadata describing the type of the variable. + * \param AlwaysPreserve If true, this descriptor will survive optimizations. + * \param Flags Flags. + */ +LLVMMetadataRef LLVMDIBuilderCreateParameterVariable2( + LLVMDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name, + size_t NameLen, unsigned ArgNo, unsigned LexicalScope, LLVMMetadataRef File, + unsigned LineNo, LLVMMetadataRef Ty, LLVMBool AlwaysPreserve, + LLVMDIFlags Flags, LLVMBool IsLocatorDesc); + /** * Create a new descriptor for a local auto variable. * \param Builder The DIBuilder. @@ -1377,6 +1553,9 @@ LLVMMetadataRef LLVMDIBuilderCreateParameterVariable( size_t NameLen, unsigned ArgNo, LLVMMetadataRef File, unsigned LineNo, LLVMMetadataRef Ty, LLVMBool AlwaysPreserve, LLVMDIFlags Flags); +void LLVMDIBuilderUpdateDISubprogramRaincodeFrameBase( + LLVMDIBuilderRef Builder, LLVMMetadataRef Subprogram, LLVMValueRef Storage); + /** * Get the metadata of the subprogram attached to a function. * diff --git a/llvm/include/llvm/AsmParser/LLToken.h b/llvm/include/llvm/AsmParser/LLToken.h index 19029842a572a4..a75fa53efccd97 100644 --- a/llvm/include/llvm/AsmParser/LLToken.h +++ b/llvm/include/llvm/AsmParser/LLToken.h @@ -462,6 +462,10 @@ enum Kind { // GV's where the clang++ frontend (when ASan is used) notes that this is // dynamically initialized, and thus needs ODR detection. kw_sanitize_address_dyninit, + kw_pic, + kw_digits, + kw_scale, + kw_sign, // Unsigned Valued tokens (UIntVal). LabelID, // 42: @@ -490,6 +494,7 @@ enum Kind { DwarfMacinfo, // DW_MACINFO_foo ChecksumKind, // CSK_foo DbgRecordType, // dbg_foo + DwarfDecimalSign, // DW_DS_foo // Type valued tokens (TyVal). Type, diff --git a/llvm/include/llvm/BinaryFormat/Dwarf.def b/llvm/include/llvm/BinaryFormat/Dwarf.def index d55947fc5103ac..caac97941adc83 100644 --- a/llvm/include/llvm/BinaryFormat/Dwarf.def +++ b/llvm/include/llvm/BinaryFormat/Dwarf.def @@ -11,20 +11,21 @@ //===----------------------------------------------------------------------===// // TODO: Add other DW-based macros. -#if !(defined HANDLE_DW_TAG || defined HANDLE_DW_AT || \ - defined HANDLE_DW_FORM || defined HANDLE_DW_OP || \ - defined HANDLE_DW_OP_LLVM_USEROP || defined HANDLE_DW_LANG || \ - defined HANDLE_DW_LNAME || defined HANDLE_DW_ATE || \ - defined HANDLE_DW_VIRTUALITY || defined HANDLE_DW_DEFAULTED || \ - defined HANDLE_DW_CC || defined HANDLE_DW_LNS || \ - defined HANDLE_DW_LNE || defined HANDLE_DW_LNCT || \ - defined HANDLE_DW_MACRO || defined HANDLE_DW_MACRO_GNU || \ - defined HANDLE_MACRO_FLAG || defined HANDLE_DW_RLE || \ - defined HANDLE_DW_LLE || \ - (defined HANDLE_DW_CFA && defined HANDLE_DW_CFA_PRED) || \ - defined HANDLE_DW_APPLE_PROPERTY || defined HANDLE_DW_UT || \ - defined HANDLE_DWARF_SECTION || defined HANDLE_DW_IDX || \ - defined HANDLE_DW_END || defined HANDLE_DW_SECT) +#if !( \ + defined HANDLE_DW_TAG || defined HANDLE_DW_AT || defined HANDLE_DW_FORM || \ + defined HANDLE_DW_OP || defined HANDLE_DW_OP_LLVM_USEROP || \ + defined HANDLE_DW_LANG || defined HANDLE_DW_LNAME || \ + defined HANDLE_DW_ATE || \ + defined HANDLE_DW_VIRTUALITY || defined HANDLE_DW_DEFAULTED || \ + defined HANDLE_DW_CC || defined HANDLE_DW_LNS || defined HANDLE_DW_LNE || \ + defined HANDLE_DW_LNCT || defined HANDLE_DW_MACRO || \ + defined HANDLE_DW_MACRO_GNU || defined HANDLE_MACRO_FLAG || \ + defined HANDLE_DW_RLE || defined HANDLE_DW_LLE || \ + (defined HANDLE_DW_CFA && defined HANDLE_DW_CFA_PRED) || \ + defined HANDLE_DW_APPLE_PROPERTY || defined HANDLE_DW_UT || \ + defined HANDLE_DW_RAINCODE_DESC_TYPE || defined HANDLE_DWARF_SECTION || \ + defined HANDLE_DW_IDX || defined HANDLE_DW_END || defined HANDLE_DW_DS || \ + defined HANDLE_DW_SECT) #error "Missing macro definition of HANDLE_DW*" #endif @@ -126,6 +127,10 @@ #define HANDLE_DW_APPLE_PROPERTY(ID, NAME) #endif +#ifndef HANDLE_DW_RAINCODE_DESC_TYPE +#define HANDLE_DW_RAINCODE_DESC_TYPE(ID, NAME) +#endif + #ifndef HANDLE_DW_UT #define HANDLE_DW_UT(ID, NAME) #endif @@ -146,6 +151,10 @@ #define HANDLE_DW_SECT(ID, NAME) #endif +#ifndef HANDLE_DW_DS +#define HANDLE_DW_DS(ID, NAME) +#endif + HANDLE_DW_TAG(0x0000, null, 2, DWARF, DW_KIND_NONE) HANDLE_DW_TAG(0x0001, array_type, 2, DWARF, DW_KIND_TYPE) HANDLE_DW_TAG(0x0002, class_type, 2, DWARF, DW_KIND_TYPE) @@ -637,6 +646,13 @@ HANDLE_DW_AT(0x3fee, APPLE_objc_direct, 0, APPLE) HANDLE_DW_AT(0x3fef, APPLE_sdk, 0, APPLE) HANDLE_DW_AT(0x3ff0, APPLE_origin, 0, APPLE) +// Raincode extension +HANDLE_DW_AT(0x2f12, RAINCODE_str_header, 0, RAINCODE) +HANDLE_DW_AT(0x2f13, RAINCODE_desc_type, 0, RAINCODE) +HANDLE_DW_AT(0x2f14, RAINCODE_lexical_scope, 0, RAINCODE) +HANDLE_DW_AT(0x2f15, RAINCODE_static_link_recv, 0, RAINCODE) +HANDLE_DW_AT(0x2f16, RAINCODE_frame_base, 0, RAINCODE) + // Attribute form encodings. HANDLE_DW_FORM(0x01, addr, 2, DWARF) HANDLE_DW_FORM(0x03, block2, 2, DWARF) @@ -885,6 +901,8 @@ HANDLE_DW_OP(0xf8, PGI_omp_thread_num, -1, -1, 0, PGI) // Extensions for Fission proposal. HANDLE_DW_OP(0xfb, GNU_addr_index, 1, 0, 0, GNU) HANDLE_DW_OP(0xfc, GNU_const_index, 1, 0, 0, GNU) +HANDLE_DW_OP(0xea, RC_byte_swap, 1, 0, 0, RAINCODE) +HANDLE_DW_OP(0xeb, RC_resolve_file_address, 1, 0, 0, RAINCODE) // DW_OP_LLVM_user has two operands: // (1) An unsigned LEB128 "LLVM Vendor Extension Opcode". @@ -1068,6 +1086,13 @@ HANDLE_DW_ATE(0x86, HP_imaginary_float128, 2, HP) // Conflicting: // HANDLE_DW_ATE(0x86, SUN_imaginary_float, 2, SUN) +// DWARF decimal sign +HANDLE_DW_DS(0x01, unsigned) +HANDLE_DW_DS(0x02, leading_overpunch) +HANDLE_DW_DS(0x03, trailing_overpunch) +HANDLE_DW_DS(0x04, leading_separate) +HANDLE_DW_DS(0x05, trailing_separate) + // DWARF attribute endianity HANDLE_DW_END(0x00, default) HANDLE_DW_END(0x01, big) @@ -1264,6 +1289,11 @@ HANDLE_DW_APPLE_PROPERTY(0x1000, nullability) HANDLE_DW_APPLE_PROPERTY(0x2000, null_resettable) HANDLE_DW_APPLE_PROPERTY(0x4000, class) +// Raincode PL/I discriptor types +HANDLE_DW_RAINCODE_DESC_TYPE(0x00, nodisc) +HANDLE_DW_RAINCODE_DESC_TYPE(0x01, desc_list) +HANDLE_DW_RAINCODE_DESC_TYPE(0x02, desc_loc) + // DWARF v5 Unit Types. HANDLE_DW_UT(0x01, compile) HANDLE_DW_UT(0x02, type) @@ -1357,8 +1387,10 @@ HANDLE_DW_SECT(8, RNGLISTS) #undef HANDLE_DW_CFA #undef HANDLE_DW_CFA_PRED #undef HANDLE_DW_APPLE_PROPERTY +#undef HANDLE_DW_RAINCODE_DESC_TYPE #undef HANDLE_DW_UT #undef HANDLE_DWARF_SECTION #undef HANDLE_DW_IDX #undef HANDLE_DW_END #undef HANDLE_DW_SECT +#undef HANDLE_DW_DS diff --git a/llvm/include/llvm/BinaryFormat/Dwarf.h b/llvm/include/llvm/BinaryFormat/Dwarf.h index 4657ad30eb1be4..c25e5c9c802e73 100644 --- a/llvm/include/llvm/BinaryFormat/Dwarf.h +++ b/llvm/include/llvm/BinaryFormat/Dwarf.h @@ -85,6 +85,7 @@ enum LLVMConstants : uint32_t { DWARF_VENDOR_SUN, DWARF_VENDOR_UPC, ///\} + DWARF_VENDOR_RAINCODE }; /// Constants that define the DWARF format as 32 or 64 bit. @@ -163,11 +164,9 @@ enum TypeKind : uint8_t { enum DecimalSignEncoding { // Decimal sign attribute values - DW_DS_unsigned = 0x01, - DW_DS_leading_overpunch = 0x02, - DW_DS_trailing_overpunch = 0x03, - DW_DS_leading_separate = 0x04, - DW_DS_trailing_separate = 0x05 + DW_DS_Invalid = 0, +#define HANDLE_DW_DS(ID, NAME) DW_DS_##NAME = ID, +#include "llvm/BinaryFormat/Dwarf.def" }; enum EndianityEncoding { @@ -864,6 +863,13 @@ enum ApplePropertyAttributes { #include "llvm/BinaryFormat/Dwarf.def" }; +/// Constants for the DW_RAINCODE_DESC_TYPE attrbutes attribute. +enum RaincodeDescTypeAttributes { +#define HANDLE_DW_RAINCODE_DESC_TYPE(ID, NAME) \ + DW_RAINCODE_DESC_TYPE_##NAME = ID, +#include "llvm/BinaryFormat/Dwarf.def" +}; + /// Constants for unit types in DWARF v5. enum UnitType : unsigned char { #define HANDLE_DW_UT(ID, NAME) DW_UT_##NAME = ID, @@ -1009,6 +1015,7 @@ StringRef RLEString(unsigned RLE); /// /// @{ unsigned getTag(StringRef TagString); +unsigned getDecimalSign(StringRef DSString); unsigned getOperationEncoding(StringRef OperationEncodingString); unsigned getSubOperationEncoding(unsigned OpEncoding, StringRef SubOperationEncodingString); diff --git a/llvm/include/llvm/IR/DIBuilder.h b/llvm/include/llvm/IR/DIBuilder.h index 97ea38f041baad..35f7f97f33eca7 100644 --- a/llvm/include/llvm/IR/DIBuilder.h +++ b/llvm/include/llvm/IR/DIBuilder.h @@ -251,6 +251,22 @@ namespace llvm { DIStringType *createStringType(StringRef Name, DIExpression *StringLengthExp, DIExpression *StrLocationExp = nullptr); + /// Create debugging information entry for a basic type with packed decimal + /// type. + /// \param Name Type name. + /// \param Pic Picture String + /// \param SizeInBits Size of the type. + /// \param Encoding DWARF encoding code, e.g., dwarf::DW_ATE_edited_type. + /// \param DigitCount digit count + /// \param DecimalSign decimal sign + /// \param scale scale + /// \param Flags Optional DWARF attributes, e.g., DIFlagsBinaryScale + DIBasicType *createBasicType(StringRef Name, StringRef Pic, + uint64_t SizeInBits, unsigned Encoding, + std::optional DigitCount = std::nullopt, + std::optional DecimalSign = std::nullopt, + std::optional Scale = std::nullopt, + DINode::DIFlags Flags = DINode::FlagZero); /// Create debugging information entry for a qualified /// type, e.g. 'const int'. @@ -258,6 +274,14 @@ namespace llvm { /// \param FromTy Base Type. DIDerivedType *createQualifiedType(unsigned Tag, DIType *FromTy); + /// Create debugging information entry for a dynamic type + /// type, e.g. used in pl1 for decriptors. + /// \param BTy Base type. + /// \param Location Expression list to get to raw data. + /// \param Allocated Expression list to deduct allocation status. + DIDerivedType *createDynamicType(DIType *BTy, DIExpression *Location, + DIExpression *Allocated); + /// Create debugging information entry for a pointer. /// \param PointeeTy Type pointed by this pointer. /// \param SizeInBits Size. @@ -594,7 +618,8 @@ namespace llvm { PointerUnion DataLocation = nullptr, PointerUnion Associated = nullptr, PointerUnion Allocated = nullptr, - PointerUnion Rank = nullptr); + PointerUnion Rank = nullptr, + StringRef ArrayName = "", bool IsStringHeader = false); /// Create debugging information entry for a vector type. /// \param Size Array size. @@ -743,6 +768,22 @@ namespace llvm { DINode::DIFlags Flags = DINode::FlagZero, uint32_t AlignInBits = 0); + /// Create a new descriptor for an auto variable. This is a local variable + /// that is not a subprogram parameter. + /// + /// \c Scope must be a \a DILocalScope, and thus its scope chain eventually + /// leads to a \a DISubprogram. + /// + /// If \c AlwaysPreserve, this variable will be referenced from its + /// containing subprogram, and will survive some optimizations. + DILocalVariable * + createAutoVariable2(DIScope *Scope, StringRef Name, DIFile *File, + unsigned LineNo, unsigned LexicalScope, DIType *Ty, + bool AlwaysPreserve = false, + DINode::DIFlags Flags = DINode::FlagZero, + DILocalVariable::DIVarFlags VarFlags = DILocalVariable::VarFlagZero, + uint32_t AlignInBits = 0); + /// Create a new descriptor for an label. /// /// \c Scope must be a \a DILocalScope, and thus its scope chain eventually @@ -769,10 +810,34 @@ namespace llvm { DINode::DIFlags Flags = DINode::FlagZero, DINodeArray Annotations = nullptr); + /// Create a new descriptor for a parameter variable. + /// + /// \c Scope must be a \a DILocalScope, and thus its scope chain eventually + /// leads to a \a DISubprogram. + /// + /// \c ArgNo is the index (starting from \c 1) of this variable in the + /// subprogram parameters. \c ArgNo should not conflict with other + /// parameters of the same subprogram. + /// + /// If \c AlwaysPreserve, this variable will be referenced from its + /// containing subprogram, and will survive some optimizations. + DILocalVariable * + createParameterVariable2(DIScope *Scope, StringRef Name, unsigned ArgNo, + unsigned LexicalScope, DIFile *File, + unsigned LineNo, DIType *Ty, + bool AlwaysPreserve = false, + DINode::DIFlags Flags = DINode::FlagZero, + DILocalVariable::DIVarFlags VarFlags = DILocalVariable::VarFlagZero, + DINodeArray Annotations = nullptr); + /// Create a new descriptor for the specified /// variable which has a complex address expression for its address. /// \param Addr An array of complex address operations. - DIExpression *createExpression(ArrayRef Addr = std::nullopt); + /// \param Refs An array of Metadata ref for call2/call4 operations. + DIExpression *createExpression(ArrayRef Addr = std::nullopt, + ArrayRef Refs = std::nullopt); + DIExpression *createExpression(ArrayRef Addr, + ArrayRef Refs = std::nullopt); /// Create an expression for a variable that does not have an address, but /// does have a constant value. @@ -807,7 +872,9 @@ namespace llvm { DISubprogram *Decl = nullptr, DITypeArray ThrownTypes = nullptr, DINodeArray Annotations = nullptr, - StringRef TargetFuncName = ""); + StringRef TargetFuncName = "", + DIExpression *StaticLink = nullptr, + DIExpression *RcFrameBase = nullptr); /// Identical to createFunction, /// except that the resulting DbgNode is meant to be RAUWed. @@ -846,7 +913,8 @@ namespace llvm { DINode::DIFlags Flags = DINode::FlagZero, DISubprogram::DISPFlags SPFlags = DISubprogram::SPFlagZero, DITemplateParameterArray TParams = nullptr, - DITypeArray ThrownTypes = nullptr); + DITypeArray ThrownTypes = nullptr, + DIExpression *StaticLink = nullptr); /// Create common block entry for a Fortran common block. /// \param Scope Scope of this common block. @@ -1055,6 +1123,10 @@ namespace llvm { N->replaceAllUsesWith(Replacement); return Replacement; } + + /// Updates the RcFrameBase of a DISubprogram SP + void updateDISubprogramRaincodeFrameBase(DISubprogram *SP, + llvm::Value *Storage); }; // Create wrappers for C Binding types (see CBindingWrapping.h). diff --git a/llvm/include/llvm/IR/DebugInfoFlags.def b/llvm/include/llvm/IR/DebugInfoFlags.def index df375b6c68e810..f4609ff02250d7 100644 --- a/llvm/include/llvm/IR/DebugInfoFlags.def +++ b/llvm/include/llvm/IR/DebugInfoFlags.def @@ -10,7 +10,8 @@ // //===----------------------------------------------------------------------===// -#if !(defined HANDLE_DI_FLAG || defined HANDLE_DISP_FLAG) +#if !(defined HANDLE_DI_FLAG || defined HANDLE_DISP_FLAG || \ + defined HANDLE_DIVAR_FLAG) #error "Missing macro definition of HANDLE_DI*" #endif @@ -22,6 +23,10 @@ #define HANDLE_DISP_FLAG(ID, NAME) #endif +#ifndef HANDLE_DIVAR_FLAG +#define HANDLE_DIVAR_FLAG(ID, NAME) +#endif + // General flags kept in DINode. HANDLE_DI_FLAG(0, Zero) // Use it as zero value. @@ -59,6 +64,8 @@ HANDLE_DI_FLAG((1 << 27), BigEndian) HANDLE_DI_FLAG((1 << 28), LittleEndian) HANDLE_DI_FLAG((1 << 29), AllCallsDescribed) +HANDLE_DI_FLAG((1 << 30), BinaryScale) + // To avoid needing a dedicated value for IndirectVirtualBase, we use // the bitwise or of Virtual and FwdDecl, which does not otherwise // make sense for inheritance. @@ -67,7 +74,7 @@ HANDLE_DI_FLAG((1 << 2) | (1 << 5), IndirectVirtualBase) #ifdef DI_FLAG_LARGEST_NEEDED // intended to be used with ADT/BitmaskEnum.h // NOTE: always must be equal to largest flag, check this when adding new flag -HANDLE_DI_FLAG((1 << 29), Largest) +HANDLE_DI_FLAG((1 << 30), Largest) #undef DI_FLAG_LARGEST_NEEDED #endif @@ -91,13 +98,30 @@ HANDLE_DISP_FLAG((1u << 8), MainSubprogram) // for defaulted functions HANDLE_DISP_FLAG((1u << 9), Deleted) HANDLE_DISP_FLAG((1u << 11), ObjCDirect) +HANDLE_DISP_FLAG((1u << 12), DescList) +HANDLE_DISP_FLAG((1u << 13), DescLoc) #ifdef DISP_FLAG_LARGEST_NEEDED // Intended to be used with ADT/BitmaskEnum.h. // NOTE: Always must be equal to largest flag, check this when adding new flags. -HANDLE_DISP_FLAG((1 << 11), Largest) +HANDLE_DISP_FLAG((1 << 13), Largest) #undef DISP_FLAG_LARGEST_NEEDED #endif +// Variable-Specific flags kept in DIVariable + +// Use this as zero/initialization value. +HANDLE_DIVAR_FLAG(0, Zero) + +HANDLE_DIVAR_FLAG(1u, LocatorDesc) + +#ifdef DIVAR_FLAG_LARGEST_NEEDED +// Intended to be used with ADT/BitmaskEnum.h +// Note: Always must be equal to largest flag, check this when adding new flags. +HANDLE_DIVAR_FLAG((1 << 1), Largest) +#undef DIVAR_FLAG_LARGEST_NEEDED +#endif + #undef HANDLE_DI_FLAG #undef HANDLE_DISP_FLAG +#undef HANDLE_DIVAR_FLAG diff --git a/llvm/include/llvm/IR/DebugInfoMetadata.h b/llvm/include/llvm/IR/DebugInfoMetadata.h index e8fdc0bacc6630..a934fe1c274a00 100644 --- a/llvm/include/llvm/IR/DebugInfoMetadata.h +++ b/llvm/include/llvm/IR/DebugInfoMetadata.h @@ -27,6 +27,7 @@ #include "llvm/Support/Casting.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Discriminator.h" +#include "llvm/BinaryFormat/Dwarf.h" #include #include #include @@ -582,7 +583,7 @@ class DIFile : public DIScope { enum ChecksumKind { // The first variant was originally CSK_None, encoded as 0. The new // internal representation removes the need for this by wrapping the - // ChecksumInfo in an Optional, but to preserve Bitcode compatibility the 0 + // ChecksumInfo in an std::optional, but to preserve Bitcode compatibility the 0 // encoding is reserved. CSK_MD5 = 1, CSK_SHA1 = 2, @@ -608,7 +609,7 @@ class DIFile : public DIScope { private: std::optional> Checksum; - /// An optional source. A nullptr means none. + /// An std::optional source. A nullptr means none. MDString *Source; DIFile(LLVMContext &C, StorageType Storage, @@ -793,6 +794,7 @@ class DIType : public DIScope { bool isBigEndian() const { return getFlags() & FlagBigEndian; } bool isLittleEndian() const { return getFlags() & FlagLittleEndian; } bool getExportSymbols() const { return getFlags() & FlagExportSymbols; } + bool isBinaryScale() const { return (getFlags() & FlagBinaryScale) == FlagBinaryScale; } static bool classof(const Metadata *MD) { switch (MD->getMetadataID()) { @@ -816,14 +818,32 @@ class DIBasicType : public DIType { friend class LLVMContextImpl; friend class MDNode; +public: + /// Basic Type decimal info, used to record std::optional dwarf decimal attributes + /// such as picture_string, digit_counts, decimal_sign, decimal_scale all or + /// some can be absent and std::optional depending on encoding type. + struct DecimalInfo { + std::optional DigitCount; + std::optional DecimalSign; + std::optional Scale; + + bool operator==(const DecimalInfo &RHS) const { + return DigitCount == RHS.DigitCount && DecimalSign == RHS.DecimalSign && + Scale == RHS.Scale; + } + }; + +private: unsigned Encoding; + std::optional DecimalAttrInfo; DIBasicType(LLVMContext &C, StorageType Storage, unsigned Tag, uint64_t SizeInBits, uint32_t AlignInBits, unsigned Encoding, - DIFlags Flags, ArrayRef Ops) + DIFlags Flags, std::optional DecimalAttrInfo, + ArrayRef Ops) : DIType(C, DIBasicTypeKind, Storage, Tag, 0, SizeInBits, AlignInBits, 0, Flags, Ops), - Encoding(Encoding) {} + Encoding(Encoding), DecimalAttrInfo(DecimalAttrInfo) {} ~DIBasicType() = default; static DIBasicType *getImpl(LLVMContext &Context, unsigned Tag, @@ -831,19 +851,43 @@ class DIBasicType : public DIType { uint32_t AlignInBits, unsigned Encoding, DIFlags Flags, StorageType Storage, bool ShouldCreate = true) { - return getImpl(Context, Tag, getCanonicalMDString(Context, Name), - SizeInBits, AlignInBits, Encoding, Flags, Storage, + return getImpl(Context, Tag, getCanonicalMDString(Context, Name), nullptr, + SizeInBits, AlignInBits, Encoding, Flags, std::nullopt, Storage, ShouldCreate); } static DIBasicType *getImpl(LLVMContext &Context, unsigned Tag, MDString *Name, uint64_t SizeInBits, uint32_t AlignInBits, unsigned Encoding, - DIFlags Flags, StorageType Storage, - bool ShouldCreate = true); + DIFlags Flags, + std::optional DecimalAttrInfo, + StorageType Storage, bool ShouldCreate = true) { + return getImpl(Context, Tag, Name, nullptr, SizeInBits, AlignInBits, + Encoding, Flags, DecimalAttrInfo, Storage, ShouldCreate); + } + + static DIBasicType *getImpl(LLVMContext &Context, unsigned Tag, + StringRef Name, MDString *PictureString, + uint64_t SizeInBits, uint32_t AlignInBits, + unsigned Encoding, DIFlags Flags, + std::optional DecimalAttrInfo, + StorageType Storage, bool ShouldCreate = true) { + return getImpl(Context, Tag, getCanonicalMDString(Context, Name), + PictureString, SizeInBits, AlignInBits, Encoding, Flags, + DecimalAttrInfo, Storage, ShouldCreate); + } + + static DIBasicType *getImpl(LLVMContext &Context, unsigned Tag, + MDString *Name, MDString *PictureString, + uint64_t SizeInBits, uint32_t AlignInBits, + unsigned Encoding, DIFlags Flags, + std::optional DecimalAttrInfo, + StorageType Storage, bool ShouldCreate = true); TempDIBasicType cloneImpl() const { - return getTemporary(getContext(), getTag(), getName(), getSizeInBits(), - getAlignInBits(), getEncoding(), getFlags()); + return getTemporary(getContext(), getTag(), getName(), + getRawPictureString(), getSizeInBits(), + getAlignInBits(), getEncoding(), getFlags(), + getDecimalInfo()); } public: @@ -854,7 +898,7 @@ class DIBasicType : public DIType { (Tag, Name, SizeInBits, 0, 0, FlagZero)) DEFINE_MDNODE_GET(DIBasicType, (unsigned Tag, MDString *Name, uint64_t SizeInBits), - (Tag, Name, SizeInBits, 0, 0, FlagZero)) + (Tag, Name, SizeInBits, 0, 0, FlagZero, std::nullopt)) DEFINE_MDNODE_GET(DIBasicType, (unsigned Tag, StringRef Name, uint64_t SizeInBits, uint32_t AlignInBits, unsigned Encoding, DIFlags Flags), @@ -862,7 +906,21 @@ class DIBasicType : public DIType { DEFINE_MDNODE_GET(DIBasicType, (unsigned Tag, MDString *Name, uint64_t SizeInBits, uint32_t AlignInBits, unsigned Encoding, DIFlags Flags), - (Tag, Name, SizeInBits, AlignInBits, Encoding, Flags)) + (Tag, Name, SizeInBits, AlignInBits, Encoding, Flags, std::nullopt)) + DEFINE_MDNODE_GET(DIBasicType, + (unsigned Tag, StringRef Name, MDString *PictureString, + uint64_t SizeInBits, uint32_t AlignInBits, + unsigned Encoding, DIFlags Flags, + std::optional ExtInfo), + (Tag, Name, PictureString, SizeInBits, AlignInBits, + Encoding, Flags, ExtInfo)) + DEFINE_MDNODE_GET(DIBasicType, + (unsigned Tag, MDString *Name, MDString *PictureString, + uint64_t SizeInBits, uint32_t AlignInBits, + unsigned Encoding, DIFlags Flags, + std::optional ExtInfo), + (Tag, Name, PictureString, SizeInBits, AlignInBits, + Encoding, Flags, ExtInfo)) TempDIBasicType clone() const { return cloneImpl(); } @@ -874,6 +932,23 @@ class DIBasicType : public DIType { /// neither signed nor unsigned. std::optional getSignedness() const; + bool hasDecimalInfo() const { return DecimalAttrInfo.has_value(); } + std::optional getDecimalInfo() const { return DecimalAttrInfo; } + StringRef getPictureString() const { return getStringOperand(3); } + MDString *getRawPictureString() const { return getOperandAs(3); } + + std::optional getDigitCount() const { + return DecimalAttrInfo.value().DigitCount; + } + + std::optional getDecimalSign() const { + return DecimalAttrInfo.value().DecimalSign; + } + + std::optional getScale() const { + return DecimalAttrInfo.value().Scale; + } + static bool classof(const Metadata *MD) { return MD->getMetadataID() == DIBasicTypeKind; } @@ -1028,12 +1103,12 @@ class DIDerivedType : public DIType { uint32_t AlignInBits, uint64_t OffsetInBits, std::optional DWARFAddressSpace, std::optional PtrAuthData, DIFlags Flags, - Metadata *ExtraData, DINodeArray Annotations, StorageType Storage, - bool ShouldCreate = true) { + Metadata *ExtraData, DINodeArray Annotations, Metadata *Location, + Metadata *Allocated, StorageType Storage, bool ShouldCreate = true) { return getImpl(Context, Tag, getCanonicalMDString(Context, Name), File, Line, Scope, BaseType, SizeInBits, AlignInBits, OffsetInBits, - DWARFAddressSpace, PtrAuthData, Flags, ExtraData, - Annotations.get(), Storage, ShouldCreate); + DWARFAddressSpace, PtrAuthData, Flags, ExtraData, Annotations.get(), + Location, Allocated, Storage, ShouldCreate); } static DIDerivedType * getImpl(LLVMContext &Context, unsigned Tag, MDString *Name, Metadata *File, @@ -1041,30 +1116,30 @@ class DIDerivedType : public DIType { uint64_t SizeInBits, uint32_t AlignInBits, uint64_t OffsetInBits, std::optional DWARFAddressSpace, std::optional PtrAuthData, DIFlags Flags, - Metadata *ExtraData, Metadata *Annotations, StorageType Storage, - bool ShouldCreate = true); + Metadata *ExtraData, Metadata *Annotations, Metadata *Location, + Metadata *Allocated, StorageType Storage, bool ShouldCreate = true); TempDIDerivedType cloneImpl() const { - return getTemporary(getContext(), getTag(), getName(), getFile(), getLine(), - getScope(), getBaseType(), getSizeInBits(), - getAlignInBits(), getOffsetInBits(), - getDWARFAddressSpace(), getPtrAuthData(), getFlags(), - getExtraData(), getAnnotations()); + return getTemporary( + getContext(), getTag(), getName(), getFile(), getLine(), getScope(), + getBaseType(), getSizeInBits(), getAlignInBits(), getOffsetInBits(), + getDWARFAddressSpace(), getPtrAuthData(), getFlags(), getExtraData(), getAnnotations(), + getLocation(), getAllocated()); } public: - DEFINE_MDNODE_GET(DIDerivedType, - (unsigned Tag, MDString *Name, Metadata *File, - unsigned Line, Metadata *Scope, Metadata *BaseType, - uint64_t SizeInBits, uint32_t AlignInBits, - uint64_t OffsetInBits, - std::optional DWARFAddressSpace, - std::optional PtrAuthData, DIFlags Flags, - Metadata *ExtraData = nullptr, - Metadata *Annotations = nullptr), - (Tag, Name, File, Line, Scope, BaseType, SizeInBits, - AlignInBits, OffsetInBits, DWARFAddressSpace, PtrAuthData, - Flags, ExtraData, Annotations)) + DEFINE_MDNODE_GET( + DIDerivedType, + (unsigned Tag, MDString *Name, Metadata *File, unsigned Line, + Metadata *Scope, Metadata *BaseType, uint64_t SizeInBits, + uint32_t AlignInBits, uint64_t OffsetInBits, + std::optional DWARFAddressSpace, + std::optional PtrAuthData, DIFlags Flags, + Metadata *ExtraData = nullptr, Metadata *Annotations = nullptr, + Metadata *Location = nullptr, Metadata *Allocated = nullptr), + (Tag, Name, File, Line, Scope, BaseType, SizeInBits, AlignInBits, + OffsetInBits, DWARFAddressSpace, PtrAuthData, Flags, ExtraData, Annotations, + Location, Allocated)) DEFINE_MDNODE_GET(DIDerivedType, (unsigned Tag, StringRef Name, DIFile *File, unsigned Line, DIScope *Scope, DIType *BaseType, uint64_t SizeInBits, @@ -1072,10 +1147,12 @@ class DIDerivedType : public DIType { std::optional DWARFAddressSpace, std::optional PtrAuthData, DIFlags Flags, Metadata *ExtraData = nullptr, - DINodeArray Annotations = nullptr), + DINodeArray Annotations = nullptr, + Metadata *Location = nullptr, + Metadata *Allocated = nullptr), (Tag, Name, File, Line, Scope, BaseType, SizeInBits, - AlignInBits, OffsetInBits, DWARFAddressSpace, PtrAuthData, - Flags, ExtraData, Annotations)) + AlignInBits, OffsetInBits, DWARFAddressSpace, PtrAuthData, Flags, + ExtraData, Annotations, Location, Allocated)) TempDIDerivedType clone() const { return cloneImpl(); } @@ -1130,6 +1207,18 @@ class DIDerivedType : public DIType { Constant *getDiscriminantValue() const; /// @} + /// Get location expression associated with this derived type. + /// + /// Used for dynamic type raw data location expression. + Metadata *getLocation() const { return getRawLocation(); } + Metadata *getRawLocation() const { return getOperand(6); } + + /// Get allocated expression associated with this derived type. + /// + /// Used for dynamic type allocation status + Metadata *getAllocated() const { return getRawAllocated(); } + Metadata *getRawAllocated() const { return getOperand(7); } + static bool classof(const Metadata *MD) { return MD->getMetadataID() == DIDerivedTypeKind; } @@ -1155,13 +1244,29 @@ class DICompositeType : public DIType { unsigned RuntimeLang; +public: + enum VendorDIFlags : uint32_t { + VendorDIFlagZero = 0, + VendorDIFlagStrHeader = 1u, + VendorDIFlagLargest = 2u, + LLVM_MARK_AS_BITMASK_ENUM(VendorDIFlagLargest) + }; + + static VendorDIFlags packVendorDIFlags(bool IsRaincodeStrHeader) { + return static_cast( + (IsRaincodeStrHeader ? VendorDIFlagStrHeader : VendorDIFlagZero)); + } + +private: + VendorDIFlags VDIFlags; + DICompositeType(LLVMContext &C, StorageType Storage, unsigned Tag, unsigned Line, unsigned RuntimeLang, uint64_t SizeInBits, uint32_t AlignInBits, uint64_t OffsetInBits, DIFlags Flags, - ArrayRef Ops) + VendorDIFlags VFlags, ArrayRef Ops) : DIType(C, DICompositeTypeKind, Storage, Tag, Line, SizeInBits, AlignInBits, OffsetInBits, Flags, Ops), - RuntimeLang(RuntimeLang) {} + RuntimeLang(RuntimeLang), VDIFlags(VFlags) {} ~DICompositeType() = default; /// Change fields in place. @@ -1174,41 +1279,44 @@ class DICompositeType : public DIType { DIType::mutate(Tag, Line, SizeInBits, AlignInBits, OffsetInBits, Flags); } - static DICompositeType * - getImpl(LLVMContext &Context, unsigned Tag, StringRef Name, Metadata *File, - unsigned Line, DIScope *Scope, DIType *BaseType, uint64_t SizeInBits, - uint32_t AlignInBits, uint64_t OffsetInBits, DIFlags Flags, - DINodeArray Elements, unsigned RuntimeLang, DIType *VTableHolder, - DITemplateParameterArray TemplateParams, StringRef Identifier, - DIDerivedType *Discriminator, Metadata *DataLocation, - Metadata *Associated, Metadata *Allocated, Metadata *Rank, - DINodeArray Annotations, StorageType Storage, - bool ShouldCreate = true) { - return getImpl( - Context, Tag, getCanonicalMDString(Context, Name), File, Line, Scope, - BaseType, SizeInBits, AlignInBits, OffsetInBits, Flags, Elements.get(), - RuntimeLang, VTableHolder, TemplateParams.get(), - getCanonicalMDString(Context, Identifier), Discriminator, DataLocation, - Associated, Allocated, Rank, Annotations.get(), Storage, ShouldCreate); + static DICompositeType *getImpl( + LLVMContext &Context, unsigned Tag, StringRef Name, Metadata *File, + unsigned Line, DIScope *Scope, DIType *BaseType, uint64_t SizeInBits, + uint32_t AlignInBits, uint64_t OffsetInBits, DIFlags Flags, + VendorDIFlags VFlags, DINodeArray Elements, unsigned RuntimeLang, + DIType *VTableHolder, DITemplateParameterArray TemplateParams, + StringRef Identifier, DIDerivedType *Discriminator, + Metadata *DataLocation, Metadata *Associated, Metadata *Allocated, + Metadata *Rank, DINodeArray Annotations, StorageType Storage, + bool ShouldCreate = true) { + return getImpl(Context, Tag, getCanonicalMDString(Context, Name), File, + Line, Scope, BaseType, SizeInBits, AlignInBits, OffsetInBits, + Flags, VFlags, Elements.get(), RuntimeLang, VTableHolder, + TemplateParams.get(), + getCanonicalMDString(Context, Identifier), Discriminator, + DataLocation, Associated, Allocated, Rank, Annotations.get(), + Storage, ShouldCreate); } - static DICompositeType * - getImpl(LLVMContext &Context, unsigned Tag, MDString *Name, Metadata *File, - unsigned Line, Metadata *Scope, Metadata *BaseType, - uint64_t SizeInBits, uint32_t AlignInBits, uint64_t OffsetInBits, - DIFlags Flags, Metadata *Elements, unsigned RuntimeLang, - Metadata *VTableHolder, Metadata *TemplateParams, - MDString *Identifier, Metadata *Discriminator, Metadata *DataLocation, - Metadata *Associated, Metadata *Allocated, Metadata *Rank, - Metadata *Annotations, StorageType Storage, bool ShouldCreate = true); + + static DICompositeType *getImpl( + LLVMContext &Context, unsigned Tag, MDString *Name, Metadata *File, + unsigned Line, Metadata *Scope, Metadata *BaseType, uint64_t SizeInBits, + uint32_t AlignInBits, uint64_t OffsetInBits, DIFlags Flags, + VendorDIFlags VFlags, Metadata *Elements, unsigned RuntimeLang, + Metadata *VTableHolder, Metadata *TemplateParams, MDString *Identifier, + Metadata *Discriminator, Metadata *DataLocation, Metadata *Associated, + Metadata *Allocated, Metadata *Rank, Metadata* Annotations, + StorageType Storage, bool ShouldCreate = true); TempDICompositeType cloneImpl() const { - return getTemporary( - getContext(), getTag(), getName(), getFile(), getLine(), getScope(), - getBaseType(), getSizeInBits(), getAlignInBits(), getOffsetInBits(), - getFlags(), getElements(), getRuntimeLang(), getVTableHolder(), - getTemplateParams(), getIdentifier(), getDiscriminator(), - getRawDataLocation(), getRawAssociated(), getRawAllocated(), - getRawRank(), getAnnotations()); + return getTemporary(getContext(), getTag(), getName(), getFile(), getLine(), + getScope(), getBaseType(), getSizeInBits(), + getAlignInBits(), getOffsetInBits(), getFlags(), + getVendorDIFlags(), getElements(), getRuntimeLang(), + getVTableHolder(), getTemplateParams(), + getIdentifier(), getDiscriminator(), + getRawDataLocation(), getRawAssociated(), + getRawAllocated(), getRawRank(), getAnnotations()); } public: @@ -1224,9 +1332,9 @@ class DICompositeType : public DIType { Metadata *Allocated = nullptr, Metadata *Rank = nullptr, DINodeArray Annotations = nullptr), (Tag, Name, File, Line, Scope, BaseType, SizeInBits, AlignInBits, - OffsetInBits, Flags, Elements, RuntimeLang, VTableHolder, TemplateParams, - Identifier, Discriminator, DataLocation, Associated, Allocated, Rank, - Annotations)) + OffsetInBits, Flags, VendorDIFlagZero, Elements, RuntimeLang, + VTableHolder, TemplateParams, Identifier, Discriminator, + DataLocation, Associated, Allocated, Rank, Annotations)) DEFINE_MDNODE_GET( DICompositeType, (unsigned Tag, MDString *Name, Metadata *File, unsigned Line, @@ -1238,9 +1346,39 @@ class DICompositeType : public DIType { Metadata *Associated = nullptr, Metadata *Allocated = nullptr, Metadata *Rank = nullptr, Metadata *Annotations = nullptr), (Tag, Name, File, Line, Scope, BaseType, SizeInBits, AlignInBits, - OffsetInBits, Flags, Elements, RuntimeLang, VTableHolder, TemplateParams, - Identifier, Discriminator, DataLocation, Associated, Allocated, Rank, - Annotations)) + OffsetInBits, Flags, VendorDIFlagZero, Elements, RuntimeLang, + VTableHolder, TemplateParams, Identifier, Discriminator, + DataLocation, Associated, Allocated, Rank, Annotations)) + DEFINE_MDNODE_GET( + DICompositeType, + (unsigned Tag, StringRef Name, DIFile *File, unsigned Line, + DIScope *Scope, DIType *BaseType, uint64_t SizeInBits, + uint32_t AlignInBits, uint64_t OffsetInBits, DIFlags Flags, + VendorDIFlags VFlags, DINodeArray Elements, unsigned RuntimeLang, + DIType *VTableHolder, DITemplateParameterArray TemplateParams = nullptr, + StringRef Identifier = "", DIDerivedType *Discriminator = nullptr, + Metadata *DataLocation = nullptr, Metadata *Associated = nullptr, + Metadata *Allocated = nullptr, Metadata *Rank = nullptr, + DINodeArray Annotations = nullptr), + (Tag, Name, File, Line, Scope, BaseType, SizeInBits, AlignInBits, + OffsetInBits, Flags, VFlags, Elements, RuntimeLang, VTableHolder, + TemplateParams, Identifier, Discriminator, DataLocation, + Associated, Allocated, Rank, Annotations)) + DEFINE_MDNODE_GET( + DICompositeType, + (unsigned Tag, MDString *Name, Metadata *File, unsigned Line, + Metadata *Scope, Metadata *BaseType, uint64_t SizeInBits, + uint32_t AlignInBits, uint64_t OffsetInBits, DIFlags Flags, + VendorDIFlags VFlags, Metadata *Elements, unsigned RuntimeLang, + Metadata *VTableHolder, Metadata *TemplateParams = nullptr, + MDString *Identifier = nullptr, Metadata *Discriminator = nullptr, + Metadata *DataLocation = nullptr, Metadata *Associated = nullptr, + Metadata *Allocated = nullptr, Metadata *Rank = nullptr, + Metadata *Annotations = nullptr), + (Tag, Name, File, Line, Scope, BaseType, SizeInBits, AlignInBits, + OffsetInBits, Flags, VFlags, Elements, RuntimeLang, VTableHolder, + TemplateParams, Identifier, Discriminator, DataLocation, + Associated, Allocated, Rank, Annotations)) TempDICompositeType clone() const { return cloneImpl(); } @@ -1340,6 +1478,11 @@ class DICompositeType : public DIType { return cast_or_null(getRawAnnotations()); } + VendorDIFlags getVendorDIFlags() const { return VDIFlags; } + bool isRaincodeStrHeader() const { + return getVendorDIFlags() & VendorDIFlagStrHeader; + } + /// Replace operands. /// /// If this \a isUniqued() and not \a isResolved(), on a uniquing collision @@ -1565,6 +1708,17 @@ class DICompileUnit : public DIScope { DebugNameTableKind getNameTableKind() const { return (DebugNameTableKind)NameTableKind; } + unsigned getIdentifierCase() const { + switch (getSourceLanguage()) { + default: + break; + case dwarf::DW_LANG_PLI: + case dwarf::DW_LANG_Cobol74: + case dwarf::DW_LANG_Cobol85: + return dwarf::DW_ID_case_insensitive; + } + return dwarf::DW_ID_case_sensitive; + } bool getRangesBaseAddress() const { return RangesBaseAddress; } StringRef getProducer() const { return getStringOperand(1); } StringRef getFlags() const { return getStringOperand(2); } @@ -1708,7 +1862,8 @@ class DISubprogram : public DILocalScope { static DISPFlags toSPFlags(bool IsLocalToUnit, bool IsDefinition, bool IsOptimized, unsigned Virtuality = SPFlagNonvirtual, - bool IsMainSubprogram = false); + bool IsMainSubprogram = false, + bool IsDescList = false, bool IsDescLoc = false); private: DIFlags Flags; @@ -1728,6 +1883,7 @@ class DISubprogram : public DILocalScope { DITemplateParameterArray TemplateParams, DISubprogram *Declaration, DINodeArray RetainedNodes, DITypeArray ThrownTypes, DINodeArray Annotations, StringRef TargetFuncName, + DIExpression *StaticLinkExpr, DIExpression *RcFrameBaseExpr, StorageType Storage, bool ShouldCreate = true) { return getImpl(Context, Scope, getCanonicalMDString(Context, Name), getCanonicalMDString(Context, LinkageName), File, Line, Type, @@ -1735,6 +1891,8 @@ class DISubprogram : public DILocalScope { Flags, SPFlags, Unit, TemplateParams.get(), Declaration, RetainedNodes.get(), ThrownTypes.get(), Annotations.get(), getCanonicalMDString(Context, TargetFuncName), + dyn_cast_or_null(StaticLinkExpr), + dyn_cast_or_null(RcFrameBaseExpr), Storage, ShouldCreate); } static DISubprogram * @@ -1744,7 +1902,8 @@ class DISubprogram : public DILocalScope { int ThisAdjustment, DIFlags Flags, DISPFlags SPFlags, Metadata *Unit, Metadata *TemplateParams, Metadata *Declaration, Metadata *RetainedNodes, Metadata *ThrownTypes, Metadata *Annotations, - MDString *TargetFuncName, StorageType Storage, + MDString *TargetFuncName, Metadata *StaticLinkExpr, + Metadata *RcFrameBaseExpr, StorageType Storage, bool ShouldCreate = true); TempDISubprogram cloneImpl() const { @@ -1754,7 +1913,8 @@ class DISubprogram : public DILocalScope { getThisAdjustment(), getFlags(), getSPFlags(), getUnit(), getTemplateParams(), getDeclaration(), getRetainedNodes(), getThrownTypes(), getAnnotations(), - getTargetFuncName()); + getTargetFuncName(), getStaticLinkExpr(), + getRcFrameBaseExpr()); } public: @@ -1767,10 +1927,12 @@ class DISubprogram : public DILocalScope { DITemplateParameterArray TemplateParams = nullptr, DISubprogram *Declaration = nullptr, DINodeArray RetainedNodes = nullptr, DITypeArray ThrownTypes = nullptr, DINodeArray Annotations = nullptr, - StringRef TargetFuncName = ""), + StringRef TargetFuncName = "", DIExpression *StaticLink = nullptr, + DIExpression *RcFrameBase = nullptr), (Scope, Name, LinkageName, File, Line, Type, ScopeLine, ContainingType, VirtualIndex, ThisAdjustment, Flags, SPFlags, Unit, TemplateParams, - Declaration, RetainedNodes, ThrownTypes, Annotations, TargetFuncName)) + Declaration, RetainedNodes, ThrownTypes, Annotations, TargetFuncName, StaticLink, + RcFrameBase)) DEFINE_MDNODE_GET( DISubprogram, @@ -1780,10 +1942,12 @@ class DISubprogram : public DILocalScope { DIFlags Flags, DISPFlags SPFlags, Metadata *Unit, Metadata *TemplateParams = nullptr, Metadata *Declaration = nullptr, Metadata *RetainedNodes = nullptr, Metadata *ThrownTypes = nullptr, - Metadata *Annotations = nullptr, MDString *TargetFuncName = nullptr), + Metadata *Annotations = nullptr, MDString *TargetFuncName = nullptr, + Metadata *StaticLink = nullptr, Metadata *RcFrameBase = nullptr), (Scope, Name, LinkageName, File, Line, Type, ScopeLine, ContainingType, VirtualIndex, ThisAdjustment, Flags, SPFlags, Unit, TemplateParams, - Declaration, RetainedNodes, ThrownTypes, Annotations, TargetFuncName)) + Declaration, RetainedNodes, ThrownTypes, Annotations, TargetFuncName, StaticLink, + RcFrameBase)) TempDISubprogram clone() const { return cloneImpl(); } @@ -1810,6 +1974,8 @@ class DISubprogram : public DILocalScope { bool isDefinition() const { return getSPFlags() & SPFlagDefinition; } bool isOptimized() const { return getSPFlags() & SPFlagOptimized; } bool isMainSubprogram() const { return getSPFlags() & SPFlagMainSubprogram; } + bool isDescLocSubProgram() const { return getSPFlags() & SPFlagDescLoc; } + bool isDescListSubProgram() const { return getSPFlags() & SPFlagDescList; } bool isArtificial() const { return getFlags() & FlagArtificial; } bool isPrivate() const { @@ -1900,6 +2066,13 @@ class DISubprogram : public DILocalScope { StringRef getTargetFuncName() const { return (getRawTargetFuncName()) ? getStringOperand(12) : StringRef(); } + DIExpression *getStaticLinkExpr() const { + return dyn_cast_or_null(getRawStaticLinkExpr()); + } + + DIExpression *getRcFrameBaseExpr() const { + return dyn_cast_or_null(getRawRcFrameBaseExpr()); + } Metadata *getRawScope() const { return getOperand(1); } MDString *getRawName() const { return getOperandAs(2); } @@ -1923,6 +2096,12 @@ class DISubprogram : public DILocalScope { MDString *getRawTargetFuncName() const { return getNumOperands() > 12 ? getOperandAs(12) : nullptr; } + Metadata *getRawStaticLinkExpr() const { + return getNumOperands() > 13 ? getOperandAs(13) : nullptr; + } + Metadata *getRawRcFrameBaseExpr() const { + return getNumOperands() > 14 ? getOperandAs(14) : nullptr; + } void replaceRawLinkageName(MDString *LinkageName) { replaceOperandWith(3, LinkageName); @@ -1931,6 +2110,12 @@ class DISubprogram : public DILocalScope { replaceOperandWith(7, N.get()); } + void replaceRawRcFrameBaseExpr(Metadata *RcFrameBaseExpr) { + if (getNumOperands() > 14) { + setOperand(14, RcFrameBaseExpr); + } + } + /// Check if this subprogram describes the given function. /// /// FIXME: Should this be looking through bitcasts? @@ -2719,35 +2904,53 @@ class DIVariable : public DINode { /// This is (almost) a DWARF expression that modifies the location of a /// variable, or the location of a single piece of a variable, or (when using /// DW_OP_stack_value) is the constant variable value. +/// When DW_OP_call2/call4 used, the index in refs metadata array is used for +/// offset. /// /// TODO: Co-allocate the expression elements. /// TODO: Separate from MDNode, or otherwise drop Distinct and Temporary /// storage types. +/// TODO: Seperate reference and make them unique. class DIExpression : public MDNode { friend class LLVMContextImpl; friend class MDNode; std::vector Elements; + std::vector Refs; - DIExpression(LLVMContext &C, StorageType Storage, ArrayRef Elements) - : MDNode(C, DIExpressionKind, Storage, std::nullopt), - Elements(Elements.begin(), Elements.end()) {} + DIExpression(LLVMContext &C, StorageType Storage, ArrayRef Elements, + ArrayRef Refs) + : MDNode(C, DIExpressionKind, Storage, Refs), + Elements(Elements.begin(), Elements.end()), Refs(Refs.begin(), Refs.end()) {} ~DIExpression() = default; static DIExpression *getImpl(LLVMContext &Context, - ArrayRef Elements, StorageType Storage, + ArrayRef Elements, + ArrayRef Refs, StorageType Storage, bool ShouldCreate = true); + static DIExpression *getImpl(LLVMContext &Context, + ArrayRef Elements, StorageType Storage, + bool ShouldCreate = true) { + return getImpl(Context, Elements, {}, Storage, ShouldCreate); + } + TempDIExpression cloneImpl() const { - return getTemporary(getContext(), getElements()); + return getTemporary(getContext(), getElements(), getRefs()); } public: DEFINE_MDNODE_GET(DIExpression, (ArrayRef Elements), (Elements)) + DEFINE_MDNODE_GET(DIExpression, + (ArrayRef Elements, ArrayRef Refs), + (Elements, Refs)) TempDIExpression clone() const { return cloneImpl(); } ArrayRef getElements() const { return Elements; } + ArrayRef getRefs() const { + return Refs; + } unsigned getNumElements() const { return Elements.size(); } @@ -2804,6 +3007,9 @@ class DIExpression : public MDNode { /// Return the number of elements in the operand (1 + args). unsigned getSize() const; + /// Check if op has metadata reference + bool hasRef() const; + /// Append the elements of this operand to \p V. void appendToVector(SmallVectorImpl &V) const { V.append(get(), get() + getSize()); @@ -3011,12 +3217,12 @@ class DIExpression : public MDNode { EntryValue = 1 << 3 }; - /// Prepend \p DIExpr with a deref and offset operation and optionally turn it + /// Prepend \p DIExpr with a deref and offset operation and std::optionally turn it /// into a stack value or/and an entry value. static DIExpression *prepend(const DIExpression *Expr, uint8_t Flags, int64_t Offset = 0); - /// Prepend \p DIExpr with the given opcodes and optionally turn it into a + /// Prepend \p DIExpr with the given opcodes and std::optionally turn it into a /// stack value. static DIExpression *prependOpcodes(const DIExpression *Expr, SmallVectorImpl &Ops, @@ -3424,31 +3630,53 @@ class DILocalVariable : public DIVariable { friend class LLVMContextImpl; friend class MDNode; +public: + /// Debug info variable flags. + enum DIVarFlags : uint32_t { +#define HANDLE_DIVAR_FLAG(ID, NAME) VarFlag##NAME = ID, +#define DIVAR_FLAG_LARGEST_NEEDED +#include "llvm/IR/DebugInfoFlags.def" + LLVM_MARK_AS_BITMASK_ENUM(VarFlagLargest) + }; + + static DIVarFlags toVarFlags(bool IsLocDesc) { + return static_cast( + (IsLocDesc ? VarFlagLocatorDesc : VarFlagZero)); + } + +private: unsigned Arg : 16; + unsigned LexicalScope : 16; DIFlags Flags; + DIVarFlags VarFlags; DILocalVariable(LLVMContext &C, StorageType Storage, unsigned Line, - unsigned Arg, DIFlags Flags, uint32_t AlignInBits, - ArrayRef Ops) + unsigned Arg, unsigned LexScope, DIFlags Flags, + DIVarFlags VarFlags, uint32_t AlignInBits, + ArrayRef Ops) : DIVariable(C, DILocalVariableKind, Storage, Line, Ops, AlignInBits), - Arg(Arg), Flags(Flags) { + Arg(Arg), LexicalScope(LexScope), Flags(Flags), + VarFlags(VarFlags) { assert(Arg < (1 << 16) && "DILocalVariable: Arg out of range"); } ~DILocalVariable() = default; static DILocalVariable *getImpl(LLVMContext &Context, DIScope *Scope, StringRef Name, DIFile *File, unsigned Line, - DIType *Type, unsigned Arg, DIFlags Flags, + DIType *Type, unsigned Arg, unsigned LexScope, + DIFlags Flags, DIVarFlags VarFlags, uint32_t AlignInBits, DINodeArray Annotations, StorageType Storage, bool ShouldCreate = true) { return getImpl(Context, Scope, getCanonicalMDString(Context, Name), File, - Line, Type, Arg, Flags, AlignInBits, Annotations.get(), + Line, Type, Arg, LexScope, Flags, VarFlags, AlignInBits, + Annotations.get(), Storage, ShouldCreate); } static DILocalVariable *getImpl(LLVMContext &Context, Metadata *Scope, MDString *Name, Metadata *File, unsigned Line, - Metadata *Type, unsigned Arg, DIFlags Flags, + Metadata *Type, unsigned Arg, unsigned LexScope, + DIFlags Flags, DIVarFlags VarFlags, uint32_t AlignInBits, Metadata *Annotations, StorageType Storage, bool ShouldCreate = true); @@ -3464,14 +3692,39 @@ class DILocalVariable : public DIVariable { (DILocalScope * Scope, StringRef Name, DIFile *File, unsigned Line, DIType *Type, unsigned Arg, DIFlags Flags, uint32_t AlignInBits, DINodeArray Annotations), - (Scope, Name, File, Line, Type, Arg, Flags, AlignInBits, - Annotations)) + (Scope, Name, File, Line, Type, Arg, 0, Flags, VarFlagZero, + AlignInBits, Annotations)) DEFINE_MDNODE_GET(DILocalVariable, (Metadata * Scope, MDString *Name, Metadata *File, unsigned Line, Metadata *Type, unsigned Arg, DIFlags Flags, uint32_t AlignInBits, Metadata *Annotations), - (Scope, Name, File, Line, Type, Arg, Flags, AlignInBits, - Annotations)) + (Scope, Name, File, Line, Type, Arg, 0, Flags, VarFlagZero, + AlignInBits, Annotations)) + DEFINE_MDNODE_GET(DILocalVariable, + (DILocalScope * Scope, StringRef Name, DIFile *File, + unsigned Line, DIType *Type, unsigned Arg, DIFlags Flags, + DIVarFlags VarFlags, uint32_t AlignInBits, DINodeArray Annotations), + (Scope, Name, File, Line, Type, Arg, 0, Flags, VarFlags, + AlignInBits, Annotations)) + DEFINE_MDNODE_GET(DILocalVariable, + (Metadata * Scope, MDString *Name, Metadata *File, + unsigned Line, Metadata *Type, unsigned Arg, + DIFlags Flags, DIVarFlags VarFlags, uint32_t AlignInBits, Metadata *Annotations), + (Scope, Name, File, Line, Type, Arg, 0, Flags, VarFlags, + AlignInBits, Annotations)) + DEFINE_MDNODE_GET(DILocalVariable, + (DILocalScope * Scope, StringRef Name, DIFile *File, + unsigned Line, DIType *Type, unsigned Arg, unsigned LexScope, + DIFlags Flags, DIVarFlags VarFlags, uint32_t AlignInBits, DINodeArray Annotations), + (Scope, Name, File, Line, Type, Arg, LexScope, Flags, + VarFlags, AlignInBits, Annotations)) + DEFINE_MDNODE_GET(DILocalVariable, + (Metadata * Scope, MDString *Name, Metadata *File, + unsigned Line, Metadata *Type, unsigned Arg, + unsigned LexScope, DIFlags Flags, DIVarFlags VarFlags, + uint32_t AlignInBits, Metadata *Annotations), + (Scope, Name, File, Line, Type, Arg, LexScope, Flags, + VarFlags, AlignInBits, Annotations)) TempDILocalVariable clone() const { return cloneImpl(); } @@ -3484,7 +3737,9 @@ class DILocalVariable : public DIVariable { bool isParameter() const { return Arg; } unsigned getArg() const { return Arg; } + unsigned getLexicalScope() const { return LexicalScope; } DIFlags getFlags() const { return Flags; } + DIVarFlags getVarFlags() const { return VarFlags; } DINodeArray getAnnotations() const { return cast_or_null(getRawAnnotations()); @@ -3494,6 +3749,8 @@ class DILocalVariable : public DIVariable { bool isArtificial() const { return getFlags() & FlagArtificial; } bool isObjectPointer() const { return getFlags() & FlagObjectPointer; } + bool isLocatorDesc() const { return getVarFlags() & VarFlagLocatorDesc; } + /// Check that a location is valid for this variable. /// /// Check that \c DL exists, is in the same subprogram, and has the same @@ -4042,7 +4299,7 @@ template <> struct DenseMapInfo { return DebugVariable(nullptr, std::nullopt, nullptr); } - /// Difference in tombstone is that the Optional is meaningful. + /// Difference in tombstone is that the std::optional is meaningful. static inline DebugVariable getTombstoneKey() { return DebugVariable(nullptr, {{0, 0}}, nullptr); } diff --git a/llvm/lib/AsmParser/LLLexer.cpp b/llvm/lib/AsmParser/LLLexer.cpp index a3e47da77fe776..67e2aa4a6f36ce 100644 --- a/llvm/lib/AsmParser/LLLexer.cpp +++ b/llvm/lib/AsmParser/LLLexer.cpp @@ -818,6 +818,10 @@ lltok::Kind LLLexer::LexIdentifier() { KEYWORD(versions); KEYWORD(memProf); KEYWORD(notcold); + KEYWORD(pic); + KEYWORD(digits); + KEYWORD(scale); + KEYWORD(sign); #undef KEYWORD @@ -931,6 +935,7 @@ lltok::Kind LLLexer::LexIdentifier() { DWKEYWORD(CC, DwarfCC); DWKEYWORD(OP, DwarfOp); DWKEYWORD(MACINFO, DwarfMacinfo); + DWKEYWORD(DS, DwarfDecimalSign); #undef DWKEYWORD diff --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp index 66edf1e5a29573..7a5b9949e8cd07 100644 --- a/llvm/lib/AsmParser/LLParser.cpp +++ b/llvm/lib/AsmParser/LLParser.cpp @@ -4610,6 +4610,11 @@ struct DwarfTagField : public MDUnsignedField { : MDUnsignedField(DefaultTag, dwarf::DW_TAG_hi_user) {} }; +struct DwarfDecimalSignField : public MDUnsignedField { + DwarfDecimalSignField() : MDUnsignedField(dwarf::DW_DS_Invalid) {} + DwarfDecimalSignField(dwarf::DecimalSignEncoding DS) : MDUnsignedField(DS) {} +}; + struct DwarfMacinfoTypeField : public MDUnsignedField { DwarfMacinfoTypeField() : MDUnsignedField(0, dwarf::DW_MACINFO_vendor_ext) {} DwarfMacinfoTypeField(dwarf::MacinfoRecordType DefaultType) @@ -4766,6 +4771,26 @@ bool LLParser::parseMDField(LocTy Loc, StringRef Name, DwarfTagField &Result) { return false; } +template <> +bool LLParser::parseMDField(LocTy Loc, StringRef Name, + DwarfDecimalSignField &Result) { + if (Lex.getKind() == lltok::APSInt) + return parseMDField(Loc, Name, static_cast(Result)); + + if (Lex.getKind() != lltok::DwarfDecimalSign) + return tokError("expected DWARF Decimal sign"); + + unsigned DS = dwarf::getDecimalSign(Lex.getStrVal()); + if (DS == dwarf::DW_DS_Invalid) + return tokError("invalid DWARF decimal sign" + Twine(" '") + + Lex.getStrVal() + "'"); + assert(DS <= Result.Max && "Expected valid DWARF decimal sign"); + + Result.assign(DS); + Lex.Lex(); + return false; +} + template <> bool LLParser::parseMDField(LocTy Loc, StringRef Name, DwarfMacinfoTypeField &Result) { @@ -5317,9 +5342,11 @@ bool LLParser::parseDIEnumerator(MDNode *&Result, bool IsDistinct) { return false; } -/// parseDIBasicType: -/// ::= !DIBasicType(tag: DW_TAG_base_type, name: "int", size: 32, align: 32, -/// encoding: DW_ATE_encoding, flags: 0) +/// ParseDIBasicType: +/// ::= !DIBasicType(tag: DW_TAG_base_type, name: "int", size: 32, align: 1, +/// encoding: DW_ATE_encoding, pic: "picture_string", +/// digits: digit_count, sign: decimal_sign, +/// scale: decimal/binary scale, flags: 0) bool LLParser::parseDIBasicType(MDNode *&Result, bool IsDistinct) { #define VISIT_MD_FIELDS(OPTIONAL, REQUIRED) \ OPTIONAL(tag, DwarfTagField, (dwarf::DW_TAG_base_type)); \ @@ -5327,12 +5354,30 @@ bool LLParser::parseDIBasicType(MDNode *&Result, bool IsDistinct) { OPTIONAL(size, MDUnsignedField, (0, UINT64_MAX)); \ OPTIONAL(align, MDUnsignedField, (0, UINT32_MAX)); \ OPTIONAL(encoding, DwarfAttEncodingField, ); \ + OPTIONAL(pic, MDStringField, ); \ + OPTIONAL(digits, MDUnsignedField, ); \ + OPTIONAL(sign, DwarfDecimalSignField, (dwarf::DW_DS_Invalid)); \ + OPTIONAL(scale, MDSignedField, ); \ OPTIONAL(flags, DIFlagField, ); PARSE_MD_FIELDS(); #undef VISIT_MD_FIELDS - Result = GET_OR_DISTINCT(DIBasicType, (Context, tag.Val, name.Val, size.Val, - align.Val, encoding.Val, flags.Val)); + if (pic.Seen || digits.Seen || sign.Seen || scale.Seen) { + DIBasicType::DecimalInfo DAInfo; + if (digits.Seen) + DAInfo.DigitCount = digits.Val; + if (sign.Seen) + DAInfo.DecimalSign = sign.Val; + if (scale.Seen) + DAInfo.Scale = scale.Val; + + Result = GET_OR_DISTINCT(DIBasicType, + (Context, tag.Val, name.Val, pic.Val, size.Val, + align.Val, encoding.Val, flags.Val, DAInfo)); + } else { + Result = GET_OR_DISTINCT(DIBasicType, (Context, tag.Val, name.Val, size.Val, + align.Val, encoding.Val, flags.Val)); + } return false; } @@ -5380,6 +5425,8 @@ bool LLParser::parseDIDerivedType(MDNode *&Result, bool IsDistinct) { OPTIONAL(offset, MDUnsignedField, (0, UINT64_MAX)); \ OPTIONAL(flags, DIFlagField, ); \ OPTIONAL(extraData, MDField, ); \ + OPTIONAL(location, MDField, ); \ + OPTIONAL(allocated, MDField, ); \ OPTIONAL(dwarfAddressSpace, MDUnsignedField, (UINT32_MAX, UINT32_MAX)); \ OPTIONAL(annotations, MDField, ); \ OPTIONAL(ptrAuthKey, MDUnsignedField, (0, 7)); \ @@ -5403,8 +5450,9 @@ bool LLParser::parseDIDerivedType(MDNode *&Result, bool IsDistinct) { Result = GET_OR_DISTINCT(DIDerivedType, (Context, tag.Val, name.Val, file.Val, line.Val, scope.Val, baseType.Val, size.Val, align.Val, - offset.Val, DWARFAddressSpace, PtrAuthData, - flags.Val, extraData.Val, annotations.Val)); + offset.Val, DWARFAddressSpace, PtrAuthData, flags.Val, + extraData.Val, annotations.Val, location.Val, + allocated.Val)); return false; } @@ -5588,7 +5636,9 @@ bool LLParser::parseDISubprogram(MDNode *&Result, bool IsDistinct) { OPTIONAL(retainedNodes, MDField, ); \ OPTIONAL(thrownTypes, MDField, ); \ OPTIONAL(annotations, MDField, ); \ - OPTIONAL(targetFuncName, MDStringField, ); + OPTIONAL(targetFuncName, MDStringField, ); \ + OPTIONAL(staticLink, MDField, ); \ + OPTIONAL(rcFrameBase, MDField, ); PARSE_MD_FIELDS(); #undef VISIT_MD_FIELDS @@ -5608,7 +5658,7 @@ bool LLParser::parseDISubprogram(MDNode *&Result, bool IsDistinct) { type.Val, scopeLine.Val, containingType.Val, virtualIndex.Val, thisAdjustment.Val, flags.Val, SPFlags, unit.Val, templateParams.Val, declaration.Val, retainedNodes.Val, thrownTypes.Val, annotations.Val, - targetFuncName.Val)); + targetFuncName.Val, staticLink.Val, rcFrameBase.Val)); return false; } @@ -5850,12 +5900,26 @@ bool LLParser::parseDIExpressionBody(MDNode *&Result, bool IsDistinct) { return true; SmallVector Elements; + SmallVector Refs; if (Lex.getKind() != lltok::rparen) do { if (Lex.getKind() == lltok::DwarfOp) { if (unsigned Op = dwarf::getOperationEncoding(Lex.getStrVal())) { Lex.Lex(); Elements.push_back(Op); + if ((Op == dwarf::DW_OP_call2) || (Op == dwarf::DW_OP_call4)) { + MDField offset; + Lex.Lex(); + parseMDField("offset", offset); + if (!offset.Seen) { + return tokError(Twine("expected ref for DWARF op '") + + dwarf::OperationEncodingString(Op) + "'"); + } + const auto it = llvm::find(Refs, offset.Val); + Elements.push_back(it - Refs.begin()); + if (it == Refs.end()) + Refs.push_back(offset.Val); + } continue; } return tokError(Twine("invalid DWARF op '") + Lex.getStrVal() + "'"); @@ -5884,7 +5948,7 @@ bool LLParser::parseDIExpressionBody(MDNode *&Result, bool IsDistinct) { if (parseToken(lltok::rparen, "expected ')' here")) return true; - Result = GET_OR_DISTINCT(DIExpression, (Context, Elements)); + Result = GET_OR_DISTINCT(DIExpression, (Context, Elements, Refs)); return false; } diff --git a/llvm/lib/BinaryFormat/Dwarf.cpp b/llvm/lib/BinaryFormat/Dwarf.cpp index 0cd5dfbd023e4e..11c4cf7a12f3d9 100644 --- a/llvm/lib/BinaryFormat/Dwarf.cpp +++ b/llvm/lib/BinaryFormat/Dwarf.cpp @@ -37,6 +37,13 @@ unsigned llvm::dwarf::getTag(StringRef TagString) { .Default(DW_TAG_invalid); } +unsigned llvm::dwarf::getDecimalSign(StringRef DSString) { + return StringSwitch(DSString) +#define HANDLE_DW_DS(ID, NAME) .Case("DW_DS_" #NAME, DW_DS_##NAME) +#include "llvm/BinaryFormat/Dwarf.def" + .Default(DW_DS_Invalid); +} + unsigned llvm::dwarf::TagVersion(dwarf::Tag Tag) { switch (Tag) { default: diff --git a/llvm/lib/Bitcode/Reader/MetadataLoader.cpp b/llvm/lib/Bitcode/Reader/MetadataLoader.cpp index 5b3b63c2d1e4eb..bd98d17ad56b77 100644 --- a/llvm/lib/Bitcode/Reader/MetadataLoader.cpp +++ b/llvm/lib/Bitcode/Reader/MetadataLoader.cpp @@ -1526,19 +1526,38 @@ Error MetadataLoader::MetadataLoaderImpl::parseOneMetadata( break; } case bitc::METADATA_BASIC_TYPE: { - if (Record.size() < 6 || Record.size() > 7) - return error("Invalid record"); + if (Record.size() < 6 || Record.size() > 12) + return error("Invalid record"); IsDistinct = Record[0]; + DINode::DIFlags Flags = (Record.size() > 6) ? static_cast(Record[6]) : DINode::FlagZero; - MetadataList.assignValue( - GET_OR_DISTINCT(DIBasicType, - (Context, Record[1], getMDString(Record[2]), Record[3], - Record[4], Record[5], Flags)), - NextMetadataNo); + if (Record.size() > 7) { + DIBasicType::DecimalInfo DAInfo; + if (Record[8]) + DAInfo.DigitCount = Record[8]; + if (Record[9]) + DAInfo.DecimalSign = Record[9]; + if (Record[10]) + DAInfo.Scale = Record[11]; + + MetadataList.assignValue( + GET_OR_DISTINCT(DIBasicType, + (Context, Record[1], getMDString(Record[2]), + Record[7] ? getMDString(Record[7]) : nullptr, + Record[3], Record[4], Record[5], Flags, DAInfo)), + NextMetadataNo); + } else { + MetadataList.assignValue( + GET_OR_DISTINCT(DIBasicType, + (Context, Record[1], getMDString(Record[2]), + Record[3], Record[4], Record[5], Flags)), + NextMetadataNo); + } + NextMetadataNo++; break; } @@ -1563,7 +1582,7 @@ Error MetadataLoader::MetadataLoaderImpl::parseOneMetadata( break; } case bitc::METADATA_DERIVED_TYPE: { - if (Record.size() < 12 || Record.size() > 15) + if (Record.size() < 12 || Record.size() > 17) return error("Invalid record"); // DWARF address space is encoded as N->getDWARFAddressSpace() + 1. 0 means @@ -1578,14 +1597,19 @@ Error MetadataLoader::MetadataLoaderImpl::parseOneMetadata( // Only look for annotations/ptrauth if both are allocated. // If not, we can't tell which was intended to be embedded, as both ptrauth // and annotations have been expected at Record[13] at various times. - if (Record.size() > 14) { - if (Record[13]) - Annotations = getMDOrNull(Record[13]); - if (Record[14]) - PtrAuthData.emplace(Record[14]); + if (Record.size() > 16) { + if (Record[15]) + Annotations = getMDOrNull(Record[15]); + if (Record[16]) + PtrAuthData.emplace(Record[16]); } - IsDistinct = Record[0]; + IsDistinct = Record[0] & 0x1; + const unsigned Version = Record[0] & ~(0x1); + Metadata *Location = + Version == (2 << 1) ? getMDOrNull(Record[13]) : nullptr; + Metadata *Allocated = + Version == (2 << 1) ? getMDOrNull(Record[14]) : nullptr; DINode::DIFlags Flags = static_cast(Record[10]); MetadataList.assignValue( GET_OR_DISTINCT(DIDerivedType, @@ -1594,7 +1618,8 @@ Error MetadataLoader::MetadataLoaderImpl::parseOneMetadata( getDITypeRefOrNull(Record[5]), getDITypeRefOrNull(Record[6]), Record[7], Record[8], Record[9], DWARFAddressSpace, PtrAuthData, Flags, - getDITypeRefOrNull(Record[11]), Annotations)), + getDITypeRefOrNull(Record[11]), Annotations, Location, + Allocated)), NextMetadataNo); NextMetadataNo++; break; @@ -1793,7 +1818,7 @@ Error MetadataLoader::MetadataLoaderImpl::parseOneMetadata( break; } case bitc::METADATA_SUBPROGRAM: { - if (Record.size() < 18 || Record.size() > 21) + if (Record.size() < 18 || Record.size() > 22) return error("Invalid record"); bool HasSPFlags = Record[0] & 4; @@ -1843,6 +1868,9 @@ Error MetadataLoader::MetadataLoaderImpl::parseOneMetadata( bool HasThrownTypes = true; bool HasAnnotations = false; bool HasTargetFuncName = false; + const bool HasStaticLink = Record.size() >= 22; + // const bool HasStaticLinkRecv = Record.size() >= 23; + const bool HasRcFrameBase = Record.size() >= 24; unsigned OffsetA = 0; unsigned OffsetB = 0; if (!HasSPFlags) { @@ -1883,7 +1911,11 @@ Error MetadataLoader::MetadataLoaderImpl::parseOneMetadata( HasAnnotations ? getMDOrNull(Record[18 + OffsetB]) : nullptr, // annotations HasTargetFuncName ? getMDString(Record[19 + OffsetB]) - : nullptr // targetFuncName + : nullptr, // targetFuncName + HasStaticLink ? getMDOrNull(Record[20 + OffsetB]) + : nullptr, // StaticLinkExpr + HasRcFrameBase ? getMDOrNull(Record[21 + OffsetB]) + : nullptr // RcFrameBaseExpr )); MetadataList.assignValue(SP, NextMetadataNo); NextMetadataNo++; @@ -2162,15 +2194,26 @@ Error MetadataLoader::MetadataLoaderImpl::parseOneMetadata( return error("Invalid record"); IsDistinct = Record[0] & 1; - uint64_t Version = Record[0] >> 1; - auto Elts = MutableArrayRef(Record).slice(1); + uint64_t Version = (Record[0] >> 1) & (0xF); + uint64_t Ops = (Record[0] >> 6); + auto Elts = Ops ? MutableArrayRef(Record).slice(1, Ops) + : MutableArrayRef(Record).slice(1); SmallVector Buffer; if (Error Err = upgradeDIExpression(Version, Elts, Buffer)) return Err; - MetadataList.assignValue(GET_OR_DISTINCT(DIExpression, (Context, Elts)), - NextMetadataNo); + SmallVector Refs; + /// on old bitcode we will get zero Ops. + if (Ops){ + Ops++; + /// Check presence of refs for OP_call2/call4. + while(Ops < Record.size()) + Refs.push_back(getMDOrNull(Record[Ops++])); + } + + MetadataList.assignValue( + GET_OR_DISTINCT(DIExpression, (Context, Elts, Refs)), NextMetadataNo); NextMetadataNo++; break; } diff --git a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp index a5942153dc2d64..a8547c17b4078d 100644 --- a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp +++ b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -1853,6 +1853,32 @@ void ModuleBitcodeWriter::writeDIBasicType(const DIBasicType *N, Record.push_back(N->getEncoding()); Record.push_back(N->getFlags()); + // Below are the optional decimal attributes in case base type is decimal type + // and one or more attributes are not needed, we encode 0 to mark the missing + // place except the `scale` attribute which is integer and may have valid zero + // value, to mark its validity we add one more non-zero record before it. + if (N->hasDecimalInfo()) { + Record.push_back(VE.getMetadataOrNullID(N->getRawPictureString())); + + if (const auto &digits = N->getDigitCount()) + Record.push_back(*digits); + else + Record.push_back(0); + + if (const auto &sign = N->getDecimalSign()) + Record.push_back(*sign); + else + Record.push_back(0); + + if (const auto &scale = N->getScale()) { + Record.push_back(1); + Record.push_back(*scale); + } else { + Record.push_back(0); + Record.push_back(0); + } + } + Stream.EmitRecord(bitc::METADATA_BASIC_TYPE, Record, Abbrev); Record.clear(); } @@ -1877,7 +1903,8 @@ void ModuleBitcodeWriter::writeDIStringType(const DIStringType *N, void ModuleBitcodeWriter::writeDIDerivedType(const DIDerivedType *N, SmallVectorImpl &Record, unsigned Abbrev) { - Record.push_back(N->isDistinct()); + const uint64_t Version = 2 << 1; + Record.push_back(N->isDistinct() | Version); Record.push_back(N->getTag()); Record.push_back(VE.getMetadataOrNullID(N->getRawName())); Record.push_back(VE.getMetadataOrNullID(N->getFile())); @@ -1896,6 +1923,8 @@ void ModuleBitcodeWriter::writeDIDerivedType(const DIDerivedType *N, Record.push_back(*DWARFAddressSpace + 1); else Record.push_back(0); + Record.push_back(VE.getMetadataOrNullID(N->getLocation())); + Record.push_back(VE.getMetadataOrNullID(N->getAllocated())); Record.push_back(VE.getMetadataOrNullID(N->getAnnotations().get())); @@ -2031,6 +2060,8 @@ void ModuleBitcodeWriter::writeDISubprogram(const DISubprogram *N, Record.push_back(VE.getMetadataOrNullID(N->getThrownTypes().get())); Record.push_back(VE.getMetadataOrNullID(N->getAnnotations().get())); Record.push_back(VE.getMetadataOrNullID(N->getRawTargetFuncName())); + Record.push_back(VE.getMetadataOrNullID(N->getStaticLinkExpr())); + Record.push_back(VE.getMetadataOrNullID(N->getRcFrameBaseExpr())); Stream.EmitRecord(bitc::METADATA_SUBPROGRAM, Record, Abbrev); Record.clear(); @@ -2242,8 +2273,12 @@ void ModuleBitcodeWriter::writeDIExpression(const DIExpression *N, unsigned Abbrev) { Record.reserve(N->getElements().size() + 1); const uint64_t Version = 3 << 1; - Record.push_back((uint64_t)N->isDistinct() | Version); + const uint64_t NumEle = (N->getNumElements()) << 6; + Record.push_back((uint64_t)N->isDistinct() | Version | NumEle); Record.append(N->elements_begin(), N->elements_end()); + for (const Metadata* Ref : N->operands()) { + Record.push_back(VE.getMetadataOrNullID(Ref)); + } Stream.EmitRecord(bitc::METADATA_EXPRESSION, Record, Abbrev); Record.clear(); diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp index 0a1ff189bedbc4..30e7f8e6df1c71 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp @@ -245,7 +245,7 @@ void DwarfCompileUnit::addLocationAttribute( continue; // Nothing to describe without address or constant. - if (!Global && (!Expr || !Expr->isConstant())) + if (!Global && (!Expr || (!Expr->isConstant() && !Expr->getNumOperands()))) continue; if (Global && Global->isThreadLocal() && @@ -258,7 +258,7 @@ void DwarfCompileUnit::addLocationAttribute( DwarfExpr = std::make_unique(*Asm, *this, *Loc); } - if (Expr) { + if (Expr->getFragmentInfo() != std::nullopt) { // According to // https://docs.nvidia.com/cuda/archive/10.0/ptx-writers-guide-to-interoperability/index.html#cuda-specific-dwarf // cuda-gdb requires DW_AT_address_class for all variables to be able to @@ -277,6 +277,17 @@ void DwarfCompileUnit::addLocationAttribute( DwarfExpr->addFragmentOffset(Expr); } + // TODO: Optimize me + SmallVector refs; + if (Expr->getNumElements()) { + for(const Metadata* ref : Expr->operands()) { + if (auto DGV = dyn_cast(ref)) { + ref = DGV->getVariable(); + } + refs.push_back(getDIE((cast(ref)))); + } + } + if (Global) { const MCSymbol *Sym = Asm->getSymbol(Global); // 16-bit platforms like MSP430 and AVR take this path, so sink this @@ -365,7 +376,7 @@ void DwarfCompileUnit::addLocationAttribute( // to detect in the verifier. if (DwarfExpr->isUnknownLocation()) DwarfExpr->setMemoryLocationKind(); - DwarfExpr->addExpression(Expr); + DwarfExpr->addExpression(Expr, 0, &refs); } if (Asm->TM.getTargetTriple().isNVPTX() && DD->tuneForGDB()) { // According to @@ -581,6 +592,11 @@ DIE &DwarfCompileUnit::updateSubprogramScopeDIE(const DISubprogram *SP) { // to have concrete versions of our DW_TAG_subprogram nodes. DD->addSubprogramNames(*this, CUNode->getNameTableKind(), SP, *SPDie); + // Add Static link if exists. + addStaticLink(*SPDie, dwarf::DW_AT_static_link, SP->getStaticLinkExpr()); + + addStaticLink(*SPDie, dwarf::DW_AT_RAINCODE_frame_base, + SP->getRcFrameBaseExpr()); return *SPDie; } @@ -786,12 +802,19 @@ void DwarfCompileUnit::applyConcreteDbgVariableAttributes( } else if (Entry->isInt()) { auto *Expr = Single.getExpr(); if (Expr && Expr->getNumElements()) { + SmallVector Refs; + for (const Metadata *ref : Expr->operands()) { + if (auto DGV = dyn_cast(ref)) { + ref = DGV->getVariable(); + } + Refs.push_back(getDIE((cast(ref)))); + } DIELoc *Loc = new (DIEValueAllocator) DIELoc; DIEDwarfExpression DwarfExpr(*Asm, *this, *Loc); // If there is an expression, emit raw unsigned bytes. DwarfExpr.addFragmentOffset(Expr); DwarfExpr.addUnsignedConstant(Entry->getInt()); - DwarfExpr.addExpression(Expr); + DwarfExpr.addExpression(Expr, 0, &Refs); addBlock(VariableDie, dwarf::DW_AT_location, DwarfExpr.finalize()); if (DwarfExpr.TagOffset) addUInt(VariableDie, dwarf::DW_AT_LLVM_tag_offset, @@ -927,7 +950,15 @@ void DwarfCompileUnit::applyConcreteDbgVariableAttributes(const Loc::MMI &MMI, else DwarfExpr.addMachineRegExpression( *Asm->MF->getSubtarget().getRegisterInfo(), Cursor, FrameReg); - DwarfExpr.addExpression(std::move(Cursor)); + + SmallVector Refs; + for (const Metadata *ref : Expr->operands()) { + if (auto DGV = dyn_cast(ref)) { + ref = DGV->getVariable(); + } + Refs.push_back(getDIE((cast(ref)))); + } + DwarfExpr.addExpression(std::move(Cursor), 0, &Refs); } if (Asm->TM.getTargetTriple().isNVPTX() && DD->tuneForGDB()) { // According to @@ -1569,6 +1600,33 @@ void DwarfCompileUnit::addVariableAddress(const DbgVariable &DV, DIE &Die, addAddress(Die, dwarf::DW_AT_location, Location); } +void DwarfCompileUnit::addStaticLink(DIE &Die, dwarf::Attribute attrib, + const DIExpression *StaticLink) { + if (!StaticLink) + return; + + DIELoc *Loc = new (DIEValueAllocator) DIELoc; + DIEDwarfExpression SLE(*Asm, *this, *Loc); + SLE.setMemoryLocationKind(); + + DIExpressionCursor Cursor({}); + const TargetRegisterInfo &TRI = *Asm->MF->getSubtarget().getRegisterInfo(); + const auto FrameReg = TRI.getFrameRegister(*Asm->MF); + if (!SLE.addMachineRegExpression(TRI, Cursor, FrameReg)) + return; + + if (StaticLink->getNumElements()) { + SmallVector refs; + for(const Metadata *ref : StaticLink->operands()) { + if(auto DGV = dyn_cast(ref)) + ref = DGV->getVariable(); + refs.push_back(getDIE((cast(ref)))); + } + SLE.addExpression(StaticLink, 0, &refs); + } + addBlock(Die, attrib, SLE.finalize()); +} + /// Add an address attribute to a die based on the location provided. void DwarfCompileUnit::addAddress(DIE &Die, dwarf::Attribute Attribute, const MachineLocation &Location) { @@ -1640,8 +1698,14 @@ void DwarfCompileUnit::applyCommonDbgVariableAttributes(const DbgVariable &Var, if (uint32_t AlignInBytes = DIVar->getAlignInBytes()) addUInt(VariableDie, dwarf::DW_AT_alignment, dwarf::DW_FORM_udata, AlignInBytes); - addAnnotation(VariableDie, DIVar->getAnnotations()); + if (DIVar->isLocatorDesc()) + addUInt(VariableDie, dwarf::DW_AT_RAINCODE_desc_type, dwarf::DW_FORM_data1, + dwarf::DW_RAINCODE_DESC_TYPE_desc_list); + if (uint32_t LexicalScope = DIVar->getLexicalScope()) + addUInt(VariableDie, dwarf::DW_AT_RAINCODE_lexical_scope, + dwarf::DW_FORM_udata, LexicalScope); } + addAnnotation(VariableDie, DIVar->getAnnotations()); addSourceLine(VariableDie, DIVar); addType(VariableDie, Var.getType()); diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h index 76584b3eb8e78d..9e40136072337d 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.h @@ -348,6 +348,11 @@ class DwarfCompileUnit final : public DwarfUnit { /// MachineLocation. void addVariableAddress(const DbgVariable &DV, DIE &Die, MachineLocation Location); + + /// Add DW_AT_static_link attribute for a DISubprogram. + void addStaticLink(DIE &Die, dwarf::Attribute attrib, + const DIExpression *StaticLink); + /// Add an address attribute to a die based on the location provided. void addAddress(DIE &Die, dwarf::Attribute Attribute, const MachineLocation &Location); diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp index ea3fed8817d893..ea47ecb051cafc 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -195,6 +195,12 @@ void DebugLocDwarfExpression::emitBaseTypeRef(uint64_t Idx) { getActiveStreamer().emitULEB128(Idx, Twine(Idx), ULEB128PadSize); } +void DebugLocDwarfExpression::emitRef(llvm::DIE *Entry, const unsigned ref_size) { + // Keep duplicate for the time being + // BS.EmitULEB128(Idx, Twine(Idx), ULEB128PadSize); +} + + bool DebugLocDwarfExpression::isFrameRegister(const TargetRegisterInfo &TRI, llvm::Register MachineReg) { // This information is not available while emitting .debug_loc entries. @@ -1025,6 +1031,13 @@ void DwarfDebug::finishUnitAttributes(const DICompileUnit *DIUnit, NewCU.addUInt(Die, dwarf::DW_AT_language, dwarf::DW_FORM_data2, DIUnit->getSourceLanguage()); NewCU.addString(Die, dwarf::DW_AT_name, FN); + unsigned sourceLanguage = DIUnit->getSourceLanguage(); + if (sourceLanguage == dwarf::DW_LANG_PLI + || sourceLanguage == dwarf::DW_LANG_Cobol74 + || sourceLanguage == dwarf::DW_LANG_Cobol85) { + NewCU.addUInt(Die, dwarf::DW_AT_identifier_case, dwarf::DW_FORM_data1, + DIUnit->getIdentifierCase()); + } StringRef SysRoot = DIUnit->getSysRoot(); if (!SysRoot.empty()) NewCU.addString(Die, dwarf::DW_AT_LLVM_sysroot, SysRoot); diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp index 9d6e1bb367bc85..ab9aa5fbbdb2ab 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp @@ -482,16 +482,19 @@ static bool isMemoryLocation(DIExpressionCursor ExprCursor) { return true; } -void DwarfExpression::addExpression(DIExpressionCursor &&ExprCursor) { +void DwarfExpression::addExpression(DIExpressionCursor &&ExprCursor, + unsigned FragmentOffsetInBits, + SmallVectorImpl *DIERefOffset) { addExpression(std::move(ExprCursor), [](unsigned Idx, DIExpressionCursor &Cursor) -> bool { llvm_unreachable("unhandled opcode found in expression"); - }); + }, DIERefOffset); } bool DwarfExpression::addExpression( DIExpressionCursor &&ExprCursor, - llvm::function_ref InsertArg) { + llvm::function_ref InsertArg, + SmallVectorImpl *DIERefOffset) { // Entry values can currently only cover the initial register location, // and not any other parts of the following DWARF expression. assert(!IsEmittingEntryValue && "Can't emit entry value around expression"); @@ -601,6 +604,8 @@ bool DwarfExpression::addExpression( case dwarf::DW_OP_lit0: case dwarf::DW_OP_not: case dwarf::DW_OP_dup: + case dwarf::DW_OP_RC_byte_swap: + case dwarf::DW_OP_RC_resolve_file_address: case dwarf::DW_OP_push_object_address: case dwarf::DW_OP_over: case dwarf::DW_OP_eq: @@ -681,6 +686,16 @@ bool DwarfExpression::addExpression( emitUnsigned(Op->getArg(0)); emitSigned(Op->getArg(1)); break; + case dwarf::DW_OP_call2: + case dwarf::DW_OP_call4: { + assert(LocationKind != Register); + assert(DIERefOffset && "OP_call no references passed"); + emitOp(Op->getOp()); + const unsigned ref = Op->getArg(0); + const unsigned ref_size = Op->getOp() == dwarf::DW_OP_call2 ? 2 : 4; + assert(ref < DIERefOffset->size() && "fragment offset not added?"); + emitRef((*DIERefOffset)[ref], ref_size); + } break; default: llvm_unreachable("unhandled opcode found in expression"); } diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.h b/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.h index 4daa78b15b8e29..984c6401b28fb8 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.h +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.h @@ -30,6 +30,7 @@ class DwarfCompileUnit; class DIELoc; class TargetRegisterInfo; class MachineLocation; +class DIE; /// Base class containing the logic for constructing DWARF expressions /// independently of whether they are emitted into a DIE or into a .debug_loc @@ -133,6 +134,9 @@ class DwarfExpression { virtual void emitData1(uint8_t Value) = 0; + /// Emit a refrence value in local CU + virtual void emitRef(llvm::DIE *Entry, const unsigned ref_size) = 0; + virtual void emitBaseTypeRef(uint64_t Idx) = 0; /// Start emitting data to the temporary buffer. The data stored in the @@ -251,7 +255,9 @@ class DwarfExpression { void setEntryValueFlags(const MachineLocation &Loc); /// Lock this down to become a call site parameter location. - void setCallSiteParamValueFlag() { LocationFlags |= CallSiteParamValue; } + void setCallSiteParamValueFlag() { + LocationFlags |= CallSiteParamValue; + } /// Emit a machine register location. As an optimization this may also consume /// the prefix of a DwarfExpression if a more efficient representation for @@ -280,15 +286,21 @@ class DwarfExpression { /// Emit all remaining operations in the DIExpressionCursor. The /// cursor must not contain any DW_OP_LLVM_arg operations. - void addExpression(DIExpressionCursor &&Expr); + /// \param FragmentOffsetInBits If this is one fragment out of multiple + /// locations, this is the offset of the + /// fragment inside the entire variable. + void addExpression(DIExpressionCursor &&Expr, + unsigned FragmentOffsetInBits = 0, + SmallVectorImpl *DIERefOffset = nullptr); /// Emit all remaining operations in the DIExpressionCursor. /// DW_OP_LLVM_arg operations are resolved by calling (\p InsertArg). // /// \return false if any call to (\p InsertArg) returns false. - bool addExpression( - DIExpressionCursor &&Expr, - llvm::function_ref InsertArg); + bool + addExpression(DIExpressionCursor &&Expr, + llvm::function_ref InsertArg, + SmallVectorImpl *DIERefOffset = nullptr); /// If applicable, emit an empty DW_OP_piece / DW_OP_bit_piece to advance to /// the fragment described by \c Expr. @@ -324,6 +336,7 @@ class DebugLocDwarfExpression final : public DwarfExpression { void emitSigned(int64_t Value) override; void emitUnsigned(uint64_t Value) override; void emitData1(uint8_t Value) override; + void emitRef(DIE *Entry, const unsigned RefByteSize) override; void emitBaseTypeRef(uint64_t Idx) override; void enableTemporaryBuffer() override; @@ -354,6 +367,7 @@ class DIEDwarfExpression final : public DwarfExpression { void emitSigned(int64_t Value) override; void emitUnsigned(uint64_t Value) override; void emitData1(uint8_t Value) override; + void emitRef(llvm::DIE *Entry, const unsigned RefByteSize) override; void emitBaseTypeRef(uint64_t Idx) override; void enableTemporaryBuffer() override; diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp index e76b0fe2081c07..465e766e875836 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp @@ -75,6 +75,11 @@ unsigned DIEDwarfExpression::getTemporaryBufferSize() { void DIEDwarfExpression::commitTemporaryBuffer() { OutDIE.takeValues(TmpDIE); } +void DIEDwarfExpression::emitRef(llvm::DIE *Entry, const unsigned ref_size) { + const dwarf::Form form_type = ref_size == 4 ? dwarf::DW_FORM_ref4 : dwarf::DW_FORM_ref2; + CU.addDIEEntry(getActiveDIE(), (dwarf::Attribute)0, form_type, DIEEntry(*Entry)); +} + bool DIEDwarfExpression::isFrameRegister(const TargetRegisterInfo &TRI, llvm::Register MachineReg) { return MachineReg == TRI.getFrameRegister(*AP.MF); @@ -244,6 +249,11 @@ void DwarfUnit::addSInt(DIELoc &Die, std::optional Form, addSInt(Die, (dwarf::Attribute)0, Form, Integer); } +void DwarfUnit::addDIEEntry(DIEValueList &Die, dwarf::Attribute Attribute, + std::optional Form, DIEEntry Entry) { + Die.addValue(DIEValueAllocator, Attribute, *Form, Entry); +} + void DwarfUnit::addString(DIE &Die, dwarf::Attribute Attribute, StringRef String) { if (CUNode->isDebugDirectivesOnly()) @@ -727,6 +737,25 @@ void DwarfUnit::constructTypeDIE(DIE &Buffer, const DIBasicType *BTy) { addUInt(Buffer, dwarf::DW_AT_endianity, std::nullopt, dwarf::DW_END_big); else if (BTy->isLittleEndian()) addUInt(Buffer, dwarf::DW_AT_endianity, std::nullopt, dwarf::DW_END_little); + + if (BTy->hasDecimalInfo()) { + StringRef PictureString = BTy->getPictureString(); + if (!PictureString.empty()) + addString(Buffer, dwarf::DW_AT_picture_string, PictureString); + + if (const auto &digits = BTy->getDigitCount()) + addUInt(Buffer, dwarf::DW_AT_digit_count, std::nullopt, *digits); + + if (const auto &sign = BTy->getDecimalSign()) + addUInt(Buffer, dwarf::DW_AT_decimal_sign, std::nullopt, *sign); + + if (const auto &scale = BTy->getScale()) { + if (BTy->isBinaryScale()) + addSInt(Buffer, dwarf::DW_AT_binary_scale, dwarf::DW_FORM_sdata, *scale); + else + addSInt(Buffer, dwarf::DW_AT_decimal_scale, dwarf::DW_FORM_sdata, *scale); + } + } } void DwarfUnit::constructTypeDIE(DIE &Buffer, const DIStringType *STy) { @@ -813,6 +842,42 @@ void DwarfUnit::constructTypeDIE(DIE &Buffer, const DIDerivedType *DTy) { if (!DTy->isForwardDecl()) addSourceLine(Buffer, DTy); + // Add DW_AT_data_location expression for dynamic types. + if (DIExpression *Expr = dyn_cast_or_null(DTy->getLocation())) { + SmallVector refs; + if (Expr->getNumElements()) { + for(const Metadata* ref: Expr->operands()) { + if(auto DGV = dyn_cast(ref)) { + ref = DGV->getVariable(); + } + refs.push_back(getDIE((cast(ref)))); + } + } + DIELoc *Loc = new (DIEValueAllocator) DIELoc; + DIEDwarfExpression DwarfExpr(*Asm, getCU(), *Loc); + DwarfExpr.setMemoryLocationKind(); + DwarfExpr.addExpression(Expr, 0, &refs); + addBlock(Buffer, dwarf::DW_AT_data_location, DwarfExpr.finalize()); + } + + // Add DW_AT_allocated expression for dynamic types. + if (DIExpression *Expr = dyn_cast_or_null(DTy->getAllocated())) { + SmallVector refs; + if (Expr->getNumElements()) { + for(const Metadata* ref: Expr->operands()) { + if(auto DGV = dyn_cast(ref)) { + ref = DGV->getVariable(); + } + refs.push_back(getDIE((cast(ref)))); + } + } + DIELoc *Loc = new (DIEValueAllocator) DIELoc; + DIEDwarfExpression DwarfExpr(*Asm, getCU(), *Loc); + DwarfExpr.setMemoryLocationKind(); + DwarfExpr.addExpression(Expr, 0, &refs); + addBlock(Buffer, dwarf::DW_AT_allocated, DwarfExpr.finalize()); + } + // If DWARF address space value is other than None, add it. The IR // verifier checks that DWARF address space only exists for pointer // or reference types. @@ -1364,6 +1429,13 @@ void DwarfUnit::applySubprogramAttributes(const DISubprogram *SP, DIE &SPDie, addAccess(SPDie, SP->getFlags()); + if (SP->isDescLocSubProgram()) + addUInt(SPDie, dwarf::DW_AT_RAINCODE_desc_type, dwarf::DW_FORM_data1, + dwarf::DW_RAINCODE_DESC_TYPE_desc_loc); + else if (SP->isDescListSubProgram()) + addUInt(SPDie, dwarf::DW_AT_RAINCODE_desc_type, dwarf::DW_FORM_data1, + dwarf::DW_RAINCODE_DESC_TYPE_desc_list); + if (SP->isExplicit()) addFlag(SPDie, dwarf::DW_AT_explicit); @@ -1399,11 +1471,20 @@ void DwarfUnit::constructSubrangeDIE(DIE &Buffer, const DISubrange *SR, if (auto *BV = dyn_cast_if_present(Bound)) { if (auto *VarDIE = getDIE(BV)) addDIEEntry(DW_Subrange, Attr, *VarDIE); - } else if (auto *BE = dyn_cast_if_present(Bound)) { + } else if (auto *BE = dyn_cast_if_present(Bound)) { + SmallVector refs; + if (BE->getNumElements()) { + for (const Metadata *ref : BE->operands()) { + if (auto DGV = dyn_cast(ref)) { + ref = DGV->getVariable(); + } + refs.push_back(getDIE((cast(ref)))); + } + } DIELoc *Loc = new (DIEValueAllocator) DIELoc; DIEDwarfExpression DwarfExpr(*Asm, getCU(), *Loc); DwarfExpr.setMemoryLocationKind(); - DwarfExpr.addExpression(BE); + DwarfExpr.addExpression(BE, 0, &refs); addBlock(DW_Subrange, Attr, DwarfExpr.finalize()); } else if (auto *BI = dyn_cast_if_present(Bound)) { if (Attr == dwarf::DW_AT_count) { @@ -1519,10 +1600,19 @@ void DwarfUnit::constructArrayTypeDIE(DIE &Buffer, const DICompositeType *CTy) { if (auto *VarDIE = getDIE(Var)) addDIEEntry(Buffer, dwarf::DW_AT_data_location, *VarDIE); } else if (DIExpression *Expr = CTy->getDataLocationExp()) { + SmallVector refs; + if (Expr->getNumElements()) { + for (const Metadata *ref : Expr->operands()) { + if (auto DGV = dyn_cast(ref)) { + ref = DGV->getVariable(); + } + refs.push_back(getDIE((cast(ref)))); + } + } DIELoc *Loc = new (DIEValueAllocator) DIELoc; DIEDwarfExpression DwarfExpr(*Asm, getCU(), *Loc); DwarfExpr.setMemoryLocationKind(); - DwarfExpr.addExpression(Expr); + DwarfExpr.addExpression(Expr, 0, &refs); addBlock(Buffer, dwarf::DW_AT_data_location, DwarfExpr.finalize()); } @@ -1530,10 +1620,19 @@ void DwarfUnit::constructArrayTypeDIE(DIE &Buffer, const DICompositeType *CTy) { if (auto *VarDIE = getDIE(Var)) addDIEEntry(Buffer, dwarf::DW_AT_associated, *VarDIE); } else if (DIExpression *Expr = CTy->getAssociatedExp()) { + SmallVector refs; + if (Expr->getNumElements()) { + for (const Metadata *ref : Expr->operands()) { + if (auto DGV = dyn_cast(ref)) { + ref = DGV->getVariable(); + } + refs.push_back(getDIE((cast(ref)))); + } + } DIELoc *Loc = new (DIEValueAllocator) DIELoc; DIEDwarfExpression DwarfExpr(*Asm, getCU(), *Loc); DwarfExpr.setMemoryLocationKind(); - DwarfExpr.addExpression(Expr); + DwarfExpr.addExpression(Expr, 0, &refs); addBlock(Buffer, dwarf::DW_AT_associated, DwarfExpr.finalize()); } @@ -1541,10 +1640,19 @@ void DwarfUnit::constructArrayTypeDIE(DIE &Buffer, const DICompositeType *CTy) { if (auto *VarDIE = getDIE(Var)) addDIEEntry(Buffer, dwarf::DW_AT_allocated, *VarDIE); } else if (DIExpression *Expr = CTy->getAllocatedExp()) { + SmallVector refs; + if (Expr->getNumElements()) { + for (const Metadata *ref : Expr->operands()) { + if (auto DGV = dyn_cast(ref)) { + ref = DGV->getVariable(); + } + refs.push_back(getDIE((cast(ref)))); + } + } DIELoc *Loc = new (DIEValueAllocator) DIELoc; DIEDwarfExpression DwarfExpr(*Asm, getCU(), *Loc); DwarfExpr.setMemoryLocationKind(); - DwarfExpr.addExpression(Expr); + DwarfExpr.addExpression(Expr, 0, &refs); addBlock(Buffer, dwarf::DW_AT_allocated, DwarfExpr.finalize()); } @@ -1552,13 +1660,26 @@ void DwarfUnit::constructArrayTypeDIE(DIE &Buffer, const DICompositeType *CTy) { addSInt(Buffer, dwarf::DW_AT_rank, dwarf::DW_FORM_sdata, RankConst->getSExtValue()); } else if (auto *RankExpr = CTy->getRankExp()) { + SmallVector refs; + if (RankExpr->getNumElements()) { + for (const Metadata *ref : RankExpr->operands()) { + if (auto DGV = dyn_cast(ref)) { + ref = DGV->getVariable(); + } + refs.push_back(getDIE((cast(ref)))); + } + } DIELoc *Loc = new (DIEValueAllocator) DIELoc; DIEDwarfExpression DwarfExpr(*Asm, getCU(), *Loc); DwarfExpr.setMemoryLocationKind(); - DwarfExpr.addExpression(RankExpr); + DwarfExpr.addExpression(RankExpr, 0, &refs); addBlock(Buffer, dwarf::DW_AT_rank, DwarfExpr.finalize()); } + // Emit if vendor specific array + if (CTy->isRaincodeStrHeader()) + addFlag(Buffer, dwarf::DW_AT_RAINCODE_str_header); + // Emit the element type. addType(Buffer, CTy->getBaseType()); diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.h b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.h index 02256546b6b80e..1437948dd6c8f9 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.h +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.h @@ -193,6 +193,10 @@ class DwarfUnit : public DIEUnit { void addLabelDelta(DIEValueList &Die, dwarf::Attribute Attribute, const MCSymbol *Hi, const MCSymbol *Lo); + /// Add a DIE attribute data and value. + void addDIEEntry(DIEValueList &Die, dwarf::Attribute Attribute, + std::optional Form, DIEEntry Entry); + /// Add a DIE attribute data and value. void addDIEEntry(DIE &Die, dwarf::Attribute Attribute, DIE &Entry); diff --git a/llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp b/llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp index 7fba00d0e457b6..94bb97aaa745b1 100644 --- a/llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp +++ b/llvm/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp @@ -964,7 +964,7 @@ DWARFDebugNames::ValueIterator::findEntryOffsetInCurrentIndex() { if (Hdr.BucketCount == 0) { // No Hash Table, We need to search through all names in the Name Index. for (const NameTableEntry &NTE : *CurrentIndex) { - if (NTE.sameNameAs(Key)) + if (StringRef(NTE.getString()).equals_insensitive(Key)) return NTE.getEntryOffset(); } return std::nullopt; @@ -988,7 +988,7 @@ DWARFDebugNames::ValueIterator::findEntryOffsetInCurrentIndex() { continue; NameTableEntry NTE = CurrentIndex->getNameTableEntry(Index); - if (NTE.sameNameAs(Key)) + if (StringRef(NTE.getString()).equals_insensitive(Key)) return NTE.getEntryOffset(); } return std::nullopt; diff --git a/llvm/lib/DebugInfo/DWARF/DWARFExpression.cpp b/llvm/lib/DebugInfo/DWARF/DWARFExpression.cpp index 2ae5ff3efc8c5f..7cca91df3227a9 100644 --- a/llvm/lib/DebugInfo/DWARF/DWARFExpression.cpp +++ b/llvm/lib/DebugInfo/DWARF/DWARFExpression.cpp @@ -9,6 +9,8 @@ #include "llvm/DebugInfo/DWARF/DWARFExpression.h" #include "llvm/ADT/SmallString.h" #include "llvm/DebugInfo/DWARF/DWARFUnit.h" +#include "llvm/BinaryFormat/Dwarf.h" +#include "llvm/MC/MCRegisterInfo.h" #include "llvm/Support/Format.h" #include #include @@ -104,6 +106,15 @@ static std::vector getOpDescriptions() { Descriptions[DW_OP_GNU_addr_index] = Desc(Op::Dwarf4, Op::SizeLEB); Descriptions[DW_OP_GNU_const_index] = Desc(Op::Dwarf4, Op::SizeLEB); Descriptions[DW_OP_GNU_entry_value] = Desc(Op::Dwarf4, Op::SizeLEB); + Descriptions[DW_OP_addrx] = Desc(Op::Dwarf5, Op::SizeLEB); + Descriptions[DW_OP_constx] = Desc(Op::Dwarf5, Op::SizeLEB); + + Descriptions[DW_OP_RC_byte_swap] = Desc(Op::Dwarf5); + Descriptions[DW_OP_RC_resolve_file_address] = Desc(Op::Dwarf5); + Descriptions[DW_OP_convert] = Desc(Op::Dwarf5, Op::BaseTypeRef); + Descriptions[DW_OP_entry_value] = Desc(Op::Dwarf5, Op::SizeLEB); + Descriptions[DW_OP_regval_type] = + Desc(Op::Dwarf5, Op::SizeLEB, Op::BaseTypeRef); // This Description acts as a marker that getSubOpDesc must be called // to fetch the final Description for the operation. Each such final // Description must share the same first SizeSubOpLEB operand. diff --git a/llvm/lib/IR/AsmWriter.cpp b/llvm/lib/IR/AsmWriter.cpp index 70e3af941bf77b..9b5905b8820526 100644 --- a/llvm/lib/IR/AsmWriter.cpp +++ b/llvm/lib/IR/AsmWriter.cpp @@ -2029,7 +2029,8 @@ static void writeDISubrange(raw_ostream &Out, const DISubrange *N, Printer.printInt("count", CV->getSExtValue(), /* ShouldSkipZero */ false); } else - Printer.printMetadata("count", Count, /*ShouldSkipNull */ true); + Printer.printMetadata("count", N->getRawCountNode(), + /*ShouldSkipNull */ true); // A lowerBound of constant 0 should not be skipped, since it is different // from an unspecified lower bound (= nullptr). @@ -2133,6 +2134,20 @@ static void writeDIBasicType(raw_ostream &Out, const DIBasicType *N, Printer.printInt("align", N->getAlignInBits()); Printer.printDwarfEnum("encoding", N->getEncoding(), dwarf::AttributeEncodingString); + + if (N->hasDecimalInfo()) { + Printer.printString("pic", N->getPictureString()); + + if (const auto &digits = N->getDigitCount()) + Printer.printInt("digits", *digits); + + if (const auto &sign = N->getDecimalSign()) + Printer.printDwarfEnum("sign", *sign, dwarf::DecimalSignString); + + if (const auto &scale = N->getScale()) + Printer.printInt("scale", *scale, /*ShouldSkipZero*/ false); + } + Printer.printDIFlags("flags", N->getFlags()); Out << ")"; } @@ -2171,6 +2186,8 @@ static void writeDIDerivedType(raw_ostream &Out, const DIDerivedType *N, Printer.printInt("offset", N->getOffsetInBits()); Printer.printDIFlags("flags", N->getFlags()); Printer.printMetadata("extraData", N->getRawExtraData()); + Printer.printMetadata("location", N->getRawLocation()); + Printer.printMetadata("allocated", N->getRawAllocated()); if (const auto &DWARFAddressSpace = N->getDWARFAddressSpace()) Printer.printInt("dwarfAddressSpace", *DWARFAddressSpace, /* ShouldSkipZero */ false); @@ -2302,6 +2319,8 @@ static void writeDISubprogram(raw_ostream &Out, const DISubprogram *N, Printer.printMetadata("thrownTypes", N->getRawThrownTypes()); Printer.printMetadata("annotations", N->getRawAnnotations()); Printer.printString("targetFuncName", N->getTargetFuncName()); + Printer.printMetadata("staticLink", N->getRawStaticLinkExpr()); + Printer.printMetadata("rcFrameBase", N->getRawRcFrameBaseExpr()); Out << ")"; } diff --git a/llvm/lib/IR/DIBuilder.cpp b/llvm/lib/IR/DIBuilder.cpp index 0db82cdd6373c8..40aece2f968f34 100644 --- a/llvm/lib/IR/DIBuilder.cpp +++ b/llvm/lib/IR/DIBuilder.cpp @@ -294,6 +294,27 @@ DIStringType *DIBuilder::createStringType(StringRef Name, StringLengthExp, StrLocationExp, 0, 0, 0); } +DIBasicType *DIBuilder::createBasicType(StringRef Name, StringRef Pic, + uint64_t SizeInBits, unsigned Encoding, + std::optional DigitCount, + std::optional DecimalSign, + std::optional Scale, + DINode::DIFlags Flags) { + assert(!Name.empty() && "Unable to create type without name"); + assert((!Pic.empty() || DigitCount != std::nullopt || DecimalSign != std::nullopt || + Scale != std::nullopt) && + "Unable to create decimal info with empty attributes"); + + MDString *PicString = nullptr; + if (!Pic.empty()) + PicString = MDString::get(VMContext, Pic); + + return DIBasicType::get( + VMContext, dwarf::DW_TAG_base_type, Name, PicString, SizeInBits, 0, + Encoding, Flags, + DIBasicType::DecimalInfo{ DigitCount, DecimalSign, Scale }); +} + DIDerivedType *DIBuilder::createQualifiedType(unsigned Tag, DIType *FromTy) { return DIDerivedType::get(VMContext, Tag, "", nullptr, 0, nullptr, FromTy, 0, 0, 0, std::nullopt, std::nullopt, DINode::FlagZero); @@ -312,6 +333,15 @@ DIDerivedType *DIBuilder::createPtrAuthQualifiedType( DINode::FlagZero); } +DIDerivedType *DIBuilder::createDynamicType(DIType *BTy, + DIExpression *Location, + DIExpression *Allocated) { + return DIDerivedType::get(VMContext, dwarf::DW_TAG_dynamic_type, + MDString::get(VMContext, ""), nullptr, 0, nullptr, + BTy, 0, 0, 0, std::nullopt, std::nullopt, + DINode::FlagZero); +} + DIDerivedType * DIBuilder::createPointerType(DIType *PointeeTy, uint64_t SizeInBits, uint32_t AlignInBits, @@ -596,11 +626,12 @@ DIBuilder::createArrayType(uint64_t Size, uint32_t AlignInBits, DIType *Ty, PointerUnion DL, PointerUnion AS, PointerUnion AL, - PointerUnion RK) { + PointerUnion RK, + StringRef ArrayName, bool IsStringHeader) { auto *R = DICompositeType::get( - VMContext, dwarf::DW_TAG_array_type, "", nullptr, 0, nullptr, Ty, Size, - AlignInBits, 0, DINode::FlagZero, Subscripts, 0, nullptr, nullptr, "", - nullptr, + VMContext, dwarf::DW_TAG_array_type, ArrayName, nullptr, 0, nullptr, Ty, Size, + AlignInBits, 0, DINode::FlagZero, DICompositeType::packVendorDIFlags(IsStringHeader), + Subscripts, 0, nullptr, nullptr, "", nullptr, isa(DL) ? (Metadata *)cast(DL) : (Metadata *)cast(DL), isa(AS) ? (Metadata *)cast(AS) @@ -788,12 +819,12 @@ static DILocalVariable *createLocalVariable( SmallVectorImpl &PreservedNodes, DIScope *Context, StringRef Name, unsigned ArgNo, DIFile *File, unsigned LineNo, DIType *Ty, bool AlwaysPreserve, DINode::DIFlags Flags, - uint32_t AlignInBits, DINodeArray Annotations = nullptr) { + DILocalVariable::DIVarFlags VarFlags, unsigned LexicalScope, uint32_t AlignInBits, DINodeArray Annotations = nullptr) { // FIXME: Why doesn't this check for a subprogram or lexical block (AFAICT // the only valid scopes)? auto *Scope = cast(Context); auto *Node = DILocalVariable::get(VMContext, Scope, Name, File, LineNo, Ty, - ArgNo, Flags, AlignInBits, Annotations); + ArgNo, LexicalScope, Flags, VarFlags, AlignInBits, Annotations); if (AlwaysPreserve) { // The optimizer may remove local variables. If there is an interest // to preserve variable info in such situation then stash it in a @@ -812,9 +843,22 @@ DILocalVariable *DIBuilder::createAutoVariable(DIScope *Scope, StringRef Name, "Unexpected scope for a local variable."); return createLocalVariable( VMContext, getSubprogramNodesTrackingVector(Scope), Scope, Name, - /* ArgNo */ 0, File, LineNo, Ty, AlwaysPreserve, Flags, AlignInBits); + /* ArgNo */ 0, File, LineNo, Ty, AlwaysPreserve, Flags, DILocalVariable::VarFlagZero, 0, AlignInBits); +} + +DILocalVariable *DIBuilder::createAutoVariable2(DIScope *Scope, StringRef Name, + DIFile *File, unsigned LineNo, + unsigned LexicalScope, + DIType *Ty, bool AlwaysPreserve, + DINode::DIFlags Flags, + DILocalVariable::DIVarFlags VarFlags, + uint32_t AlignInBits) { + return createLocalVariable(VMContext, getSubprogramNodesTrackingVector(Scope), Scope, Name, + /* ArgNo */ 0, File, LineNo, Ty, AlwaysPreserve, + Flags, VarFlags, LexicalScope, AlignInBits); } + DILocalVariable *DIBuilder::createParameterVariable( DIScope *Scope, StringRef Name, unsigned ArgNo, DIFile *File, unsigned LineNo, DIType *Ty, bool AlwaysPreserve, DINode::DIFlags Flags, @@ -824,7 +868,18 @@ DILocalVariable *DIBuilder::createParameterVariable( "Unexpected scope for a local variable."); return createLocalVariable( VMContext, getSubprogramNodesTrackingVector(Scope), Scope, Name, ArgNo, - File, LineNo, Ty, AlwaysPreserve, Flags, /*AlignInBits=*/0, Annotations); + File, LineNo, Ty, AlwaysPreserve, Flags, DILocalVariable::VarFlagZero, + /* LexScope */0, /*AlignInBits=*/0, Annotations); +} + +DILocalVariable *DIBuilder::createParameterVariable2( + DIScope *Scope, StringRef Name, unsigned ArgNo, unsigned LexicalScope, + DIFile *File, unsigned LineNo, DIType *Ty, bool AlwaysPreserve, + DINode::DIFlags Flags, DILocalVariable::DIVarFlags VarFlags, DINodeArray Annotations) { + assert(ArgNo && "Expected non-zero argument number for parameter"); + return createLocalVariable(VMContext, getSubprogramNodesTrackingVector(Scope), Scope, Name, ArgNo, + File, LineNo, Ty, AlwaysPreserve, Flags, VarFlags, + LexicalScope, /*AlignInBits=*/0, Annotations); } DILabel *DIBuilder::createLabel(DIScope *Context, StringRef Name, DIFile *File, @@ -841,8 +896,16 @@ DILabel *DIBuilder::createLabel(DIScope *Context, StringRef Name, DIFile *File, return Node; } -DIExpression *DIBuilder::createExpression(ArrayRef Addr) { - return DIExpression::get(VMContext, Addr); +DIExpression *DIBuilder::createExpression(ArrayRef Addr, + ArrayRef Refs) { + return DIExpression::get(VMContext, Addr, Refs); +} + +DIExpression *DIBuilder::createExpression(ArrayRef Signed, + ArrayRef Refs) { + // TODO: Remove the callers of this signed version and delete. + SmallVector Addr(Signed.begin(), Signed.end()); + return createExpression(Addr, Refs); } template @@ -858,13 +921,15 @@ DISubprogram *DIBuilder::createFunction( DINode::DIFlags Flags, DISubprogram::DISPFlags SPFlags, DITemplateParameterArray TParams, DISubprogram *Decl, DITypeArray ThrownTypes, DINodeArray Annotations, - StringRef TargetFuncName) { + StringRef TargetFuncName, DIExpression *StaticLink, + DIExpression *RcFrameBase) { bool IsDefinition = SPFlags & DISubprogram::SPFlagDefinition; auto *Node = getSubprogram( /*IsDistinct=*/IsDefinition, VMContext, getNonCompileUnitScope(Context), Name, LinkageName, File, LineNo, Ty, ScopeLine, nullptr, 0, 0, Flags, - SPFlags, IsDefinition ? CUNode : nullptr, TParams, Decl, nullptr, - ThrownTypes, Annotations, TargetFuncName); + SPFlags, IsDefinition ? CUNode : nullptr, TParams, Decl, + nullptr, ThrownTypes, + Annotations, TargetFuncName, StaticLink, RcFrameBase); if (IsDefinition) AllSubprograms.push_back(Node); @@ -892,7 +957,7 @@ DISubprogram *DIBuilder::createMethod( unsigned LineNo, DISubroutineType *Ty, unsigned VIndex, int ThisAdjustment, DIType *VTableHolder, DINode::DIFlags Flags, DISubprogram::DISPFlags SPFlags, DITemplateParameterArray TParams, - DITypeArray ThrownTypes) { + DITypeArray ThrownTypes, DIExpression *StaticLink) { assert(getNonCompileUnitScope(Context) && "Methods should have both a Context and a context that isn't " "the compile unit."); @@ -902,7 +967,7 @@ DISubprogram *DIBuilder::createMethod( /*IsDistinct=*/IsDefinition, VMContext, cast(Context), Name, LinkageName, F, LineNo, Ty, LineNo, VTableHolder, VIndex, ThisAdjustment, Flags, SPFlags, IsDefinition ? CUNode : nullptr, TParams, nullptr, - nullptr, ThrownTypes); + nullptr, ThrownTypes, nullptr, "", StaticLink); if (IsDefinition) AllSubprograms.push_back(SP); @@ -1226,3 +1291,13 @@ void DIBuilder::replaceArrays(DICompositeType *&T, DINodeArray Elements, if (TParams) trackIfUnresolved(TParams.get()); } + +void DIBuilder::updateDISubprogramRaincodeFrameBase(DISubprogram *SP, + llvm::Value *Storage) { + // nothing to do for now + // now I need to convert llvm::Value to a DIExpression, how can I do that + // and replace SP->RcFrameBaseExpr + // or I can create a DIExpression where I do call on a specific variable + // pointing to the raincode frame base maybe + SP->replaceRawRcFrameBaseExpr(dyn_cast_or_null(ValueAsMetadata::get(Storage))); +} diff --git a/llvm/lib/IR/DebugInfo.cpp b/llvm/lib/IR/DebugInfo.cpp index e50b6f6335ef5f..e80cb57aeb09dc 100644 --- a/llvm/lib/IR/DebugInfo.cpp +++ b/llvm/lib/IR/DebugInfo.cpp @@ -1046,8 +1046,16 @@ static LLVMDIFlags map_to_llvmDIFlags(DINode::DIFlags Flags) { } static DISubprogram::DISPFlags -pack_into_DISPFlags(bool IsLocalToUnit, bool IsDefinition, bool IsOptimized) { - return DISubprogram::toSPFlags(IsLocalToUnit, IsDefinition, IsOptimized); +pack_into_DISPFlags(bool IsLocalToUnit, bool IsDefinition, bool IsOptimized, + bool IsDiscList = false, bool IsDiscLoc = false) { + return DISubprogram::toSPFlags(IsLocalToUnit, IsDefinition, IsOptimized, + DISubprogram::DISPFlags::SPFlagNonvirtual, + false, IsDiscList, IsDiscLoc); +} + +static DILocalVariable::DIVarFlags +pack_into_DIVarFlags(bool IsLocatorDesc) { + return DILocalVariable::toVarFlags(IsLocatorDesc); } unsigned LLVMDebugMetadataVersion() { @@ -1139,13 +1147,30 @@ LLVMMetadataRef LLVMDIBuilderCreateFunction( LLVMBool IsLocalToUnit, LLVMBool IsDefinition, unsigned ScopeLine, LLVMDIFlags Flags, LLVMBool IsOptimized) { return wrap(unwrap(Builder)->createFunction( - unwrapDI(Scope), {Name, NameLen}, {LinkageName, LinkageNameLen}, - unwrapDI(File), LineNo, unwrapDI(Ty), ScopeLine, - map_from_llvmDIFlags(Flags), - pack_into_DISPFlags(IsLocalToUnit, IsDefinition, IsOptimized), nullptr, - nullptr, nullptr)); + unwrapDI(Scope), {Name, NameLen}, + {LinkageName, LinkageNameLen}, unwrapDI(File), LineNo, + unwrapDI(Ty), ScopeLine, map_from_llvmDIFlags(Flags), + pack_into_DISPFlags(IsLocalToUnit, IsDefinition, IsOptimized), + nullptr, nullptr, nullptr)); } +LLVMMetadataRef LLVMDIBuilderCreateFunction2( + LLVMDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name, + size_t NameLen, const char *LinkageName, size_t LinkageNameLen, + LLVMMetadataRef File, unsigned LineNo, LLVMMetadataRef Ty, + LLVMBool IsLocalToUnit, LLVMBool IsDefinition, unsigned ScopeLine, + LLVMDIFlags Flags, LLVMBool IsOptimized, LLVMBool IsDescList, + LLVMBool IsDescLoc, LLVMMetadataRef StaticLinkExpr, + LLVMMetadataRef RcFrameBaseExpr) { + return wrap(unwrap(Builder)->createFunction( + unwrapDI(Scope), {Name, NameLen}, + {LinkageName, LinkageNameLen}, unwrapDI(File), LineNo, + unwrapDI(Ty), ScopeLine, map_from_llvmDIFlags(Flags), + pack_into_DISPFlags(IsLocalToUnit, IsDefinition, IsOptimized, IsDescList, + IsDescLoc), + nullptr, nullptr, nullptr, nullptr, "", unwrapDI(StaticLinkExpr), + unwrapDI(RcFrameBaseExpr))); +} LLVMMetadataRef LLVMDIBuilderCreateLexicalBlock( LLVMDIBuilderRef Builder, LLVMMetadataRef Scope, @@ -1331,6 +1356,22 @@ LLVMDIBuilderCreateArrayType(LLVMDIBuilderRef Builder, uint64_t Size, unwrapDI(Ty), Subs)); } +LLVMMetadataRef +LLVMDIBuilderCreateArrayType2(LLVMDIBuilderRef Builder, uint64_t Size, + uint32_t AlignInBits, LLVMMetadataRef Ty, + LLVMMetadataRef *Subscripts, + unsigned NumSubscripts, + LLVMBool isVarString, + const char *Name, size_t NameLen) { + auto Subs = unwrap(Builder)->getOrCreateArray({unwrap(Subscripts), + NumSubscripts}); + return wrap(unwrap(Builder)->createArrayType(Size, AlignInBits, + unwrapDI(Ty), Subs, + nullptr, nullptr, nullptr, + nullptr, {Name, NameLen}, + isVarString)); +} + LLVMMetadataRef LLVMDIBuilderCreateVectorType(LLVMDIBuilderRef Builder, uint64_t Size, uint32_t AlignInBits, LLVMMetadataRef Ty, @@ -1352,6 +1393,27 @@ LLVMDIBuilderCreateBasicType(LLVMDIBuilderRef Builder, const char *Name, map_from_llvmDIFlags(Flags))); } +LLVMMetadataRef LLVMDIBuilderCreateDecimalType( + LLVMDIBuilderRef Builder, const char *Name, size_t NameLen, + const char *PicString, size_t PicLen, uint64_t SizeInBits, + LLVMDWARFTypeEncoding Encoding, uint32_t digits, LLVMDWARFDecimalSign sign, + int32_t scale, LLVMBool isScalePresent, LLVMDIFlags Flags) { + + std::optional DigitCount; + std::optional DecimalSign; + std::optional Scale; + + if (digits) + DigitCount = digits; + if (sign != LLVMDWARFDSNone) + DecimalSign = sign; + if (isScalePresent) + Scale = scale; + return wrap(unwrap(Builder)->createBasicType( + { Name, NameLen }, { PicString, PicLen }, SizeInBits, Encoding, + DigitCount, DecimalSign, Scale, map_from_llvmDIFlags(Flags))); +} + LLVMMetadataRef LLVMDIBuilderCreatePointerType( LLVMDIBuilderRef Builder, LLVMMetadataRef PointeeTy, uint64_t SizeInBits, uint32_t AlignInBits, unsigned AddressSpace, @@ -1491,6 +1553,15 @@ LLVMDIBuilderCreateQualifiedType(LLVMDIBuilderRef Builder, unsigned Tag, unwrapDI(Type))); } +LLVMMetadataRef LLVMDIBuilderCreateDynamicType(LLVMDIBuilderRef Builder, + LLVMMetadataRef Type, + LLVMMetadataRef Location, + LLVMMetadataRef Allocated) { + return wrap(unwrap(Builder)->createDynamicType( + unwrapDI(Type), unwrapDI(Location), + unwrapDI(Allocated))); +} + LLVMMetadataRef LLVMDIBuilderCreateReferenceType(LLVMDIBuilderRef Builder, unsigned Tag, LLVMMetadataRef Type) { @@ -1612,6 +1683,15 @@ LLVMMetadataRef LLVMDIBuilderCreateExpression(LLVMDIBuilderRef Builder, unwrap(Builder)->createExpression(ArrayRef(Addr, Length))); } +LLVMMetadataRef LLVMDIBuilderCreateExpressionWithRef(LLVMDIBuilderRef Builder, + int64_t *Addr, + size_t Length, + LLVMMetadataRef *Ref, + size_t RefLength) { + return wrap(unwrap(Builder)->createExpression( + ArrayRef(Addr, Length), {unwrap(Ref), RefLength})); +} + LLVMMetadataRef LLVMDIBuilderCreateConstantValueExpression(LLVMDIBuilderRef Builder, uint64_t Value) { @@ -1764,11 +1844,56 @@ LLVMMetadataRef LLVMDIBuilderCreateParameterVariable( map_from_llvmDIFlags(Flags))); } +void LLVMDIBuilderUpdateDISubprogramRaincodeFrameBase( + LLVMDIBuilderRef Builder, LLVMMetadataRef Subprogram, LLVMValueRef Storage) { + unwrap(Builder)->updateDISubprogramRaincodeFrameBase( + unwrap(Subprogram), unwrap(Storage)); +} + +LLVMMetadataRef LLVMDIBuilderCreateAutoVariable2( + LLVMDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name, + size_t NameLen, LLVMMetadataRef File, unsigned LineNo, unsigned LexicalScope, + LLVMMetadataRef Ty, LLVMBool AlwaysPreserve, LLVMDIFlags Flags, + uint32_t AlignInBits, LLVMBool IsLocatorDesc) { + return wrap(unwrap(Builder)->createAutoVariable2( + unwrap(Scope), {Name, NameLen}, unwrap(File), + LineNo, LexicalScope, unwrap(Ty), AlwaysPreserve, + map_from_llvmDIFlags(Flags), + pack_into_DIVarFlags(IsLocatorDesc), AlignInBits)); +} + +LLVMMetadataRef LLVMDIBuilderCreateParameterVariable2( + LLVMDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name, + size_t NameLen, unsigned ArgNo, unsigned LexicalScope, + LLVMMetadataRef File, unsigned LineNo, LLVMMetadataRef Ty, + LLVMBool AlwaysPreserve, LLVMDIFlags Flags, LLVMBool IsLocatorDesc) { + return wrap(unwrap(Builder)->createParameterVariable2( + unwrap(Scope), {Name, NameLen}, ArgNo, LexicalScope, + unwrap(File), LineNo, unwrap(Ty), AlwaysPreserve, + map_from_llvmDIFlags(Flags), + pack_into_DIVarFlags(IsLocatorDesc))); +} + LLVMMetadataRef LLVMDIBuilderGetOrCreateSubrange(LLVMDIBuilderRef Builder, int64_t Lo, int64_t Count) { return wrap(unwrap(Builder)->getOrCreateSubrange(Lo, Count)); } +LLVMMetadataRef LLVMDIBuilderGetOrCreateSubrange2(LLVMDIBuilderRef Builder, + int64_t Lo, + LLVMMetadataRef Count) { + return wrap(unwrap(Builder)->getOrCreateSubrange(Lo, unwrap(Count))); +} + +LLVMMetadataRef LLVMDIBuilderGetOrCreateSubrange3(LLVMDIBuilderRef Builder, + LLVMMetadataRef Count, + LLVMMetadataRef LB, + LLVMMetadataRef UB, + LLVMMetadataRef Stride) { + return wrap(unwrap(Builder)->getOrCreateSubrange(unwrap(Count), unwrap(LB), + unwrap(UB), unwrap(Stride))); +} + LLVMMetadataRef LLVMDIBuilderGetOrCreateArray(LLVMDIBuilderRef Builder, LLVMMetadataRef *Data, size_t Length) { diff --git a/llvm/lib/IR/DebugInfoMetadata.cpp b/llvm/lib/IR/DebugInfoMetadata.cpp index 416cebbe52723c..41b4f7035f7b6f 100644 --- a/llvm/lib/IR/DebugInfoMetadata.cpp +++ b/llvm/lib/IR/DebugInfoMetadata.cpp @@ -332,6 +332,11 @@ DINode::DIFlags DINode::splitFlags(DIFlags Flags, SplitFlags.push_back(FlagIndirectVirtualBase); } + if ((Flags & FlagBinaryScale) == FlagBinaryScale) { + Flags &= ~FlagBinaryScale; + SplitFlags.push_back(FlagBinaryScale); + } + #define HANDLE_DI_FLAG(ID, NAME) \ if (DIFlags Bit = Flags & Flag##NAME) { \ SplitFlags.push_back(Bit); \ @@ -661,16 +666,18 @@ DIEnumerator *DIEnumerator::getImpl(LLVMContext &Context, const APInt &Value, } DIBasicType *DIBasicType::getImpl(LLVMContext &Context, unsigned Tag, - MDString *Name, uint64_t SizeInBits, - uint32_t AlignInBits, unsigned Encoding, - DIFlags Flags, StorageType Storage, - bool ShouldCreate) { + MDString *Name, MDString *PictureString, + uint64_t SizeInBits, uint32_t AlignInBits, + unsigned Encoding, DIFlags Flags, + std::optional DAInfo, + StorageType Storage, bool ShouldCreate) { assert(isCanonical(Name) && "Expected canonical MDString"); - DEFINE_GETIMPL_LOOKUP(DIBasicType, - (Tag, Name, SizeInBits, AlignInBits, Encoding, Flags)); - Metadata *Ops[] = {nullptr, nullptr, Name}; + DEFINE_GETIMPL_LOOKUP(DIBasicType, (Tag, Name, PictureString, SizeInBits, + AlignInBits, Encoding, Flags, DAInfo)); + Metadata *Ops[] = {nullptr, nullptr, Name, PictureString}; DEFINE_GETIMPL_STORE(DIBasicType, - (Tag, SizeInBits, AlignInBits, Encoding, Flags), Ops); + + (Tag, SizeInBits, AlignInBits, Encoding, Flags, DAInfo), Ops); } std::optional DIBasicType::getSignedness() const { @@ -735,19 +742,21 @@ Constant *DIDerivedType::getDiscriminantValue() const { return nullptr; } -DIDerivedType *DIDerivedType::getImpl( - LLVMContext &Context, unsigned Tag, MDString *Name, Metadata *File, - unsigned Line, Metadata *Scope, Metadata *BaseType, uint64_t SizeInBits, - uint32_t AlignInBits, uint64_t OffsetInBits, - std::optional DWARFAddressSpace, - std::optional PtrAuthData, DIFlags Flags, Metadata *ExtraData, - Metadata *Annotations, StorageType Storage, bool ShouldCreate) { +DIDerivedType * +DIDerivedType::getImpl(LLVMContext &Context, unsigned Tag, MDString *Name, + Metadata *File, unsigned Line, Metadata *Scope, + Metadata *BaseType, uint64_t SizeInBits, + uint32_t AlignInBits, uint64_t OffsetInBits, + std::optional DWARFAddressSpace, + std::optional PtrAuthData, DIFlags Flags, + Metadata *ExtraData, Metadata *Annotations, + Metadata *location, Metadata *Allocated, StorageType Storage, bool ShouldCreate) { assert(isCanonical(Name) && "Expected canonical MDString"); DEFINE_GETIMPL_LOOKUP(DIDerivedType, (Tag, Name, File, Line, Scope, BaseType, SizeInBits, AlignInBits, OffsetInBits, DWARFAddressSpace, - PtrAuthData, Flags, ExtraData, Annotations)); - Metadata *Ops[] = {File, Scope, Name, BaseType, ExtraData, Annotations}; + PtrAuthData, Flags, ExtraData, Annotations, location, Allocated )); + Metadata *Ops[] = {File, Scope, Name, BaseType, ExtraData, Annotations, location, Allocated}; DEFINE_GETIMPL_STORE(DIDerivedType, (Tag, Line, SizeInBits, AlignInBits, OffsetInBits, DWARFAddressSpace, PtrAuthData, Flags), @@ -765,17 +774,17 @@ DICompositeType *DICompositeType::getImpl( LLVMContext &Context, unsigned Tag, MDString *Name, Metadata *File, unsigned Line, Metadata *Scope, Metadata *BaseType, uint64_t SizeInBits, uint32_t AlignInBits, uint64_t OffsetInBits, DIFlags Flags, - Metadata *Elements, unsigned RuntimeLang, Metadata *VTableHolder, - Metadata *TemplateParams, MDString *Identifier, Metadata *Discriminator, - Metadata *DataLocation, Metadata *Associated, Metadata *Allocated, - Metadata *Rank, Metadata *Annotations, StorageType Storage, - bool ShouldCreate) { + VendorDIFlags VFlags, Metadata *Elements, unsigned RuntimeLang, + Metadata *VTableHolder, Metadata *TemplateParams, MDString *Identifier, + Metadata *Discriminator, Metadata *DataLocation, Metadata *Associated, + Metadata *Allocated, Metadata *Rank, Metadata *Annotations, + StorageType Storage, bool ShouldCreate) { assert(isCanonical(Name) && "Expected canonical MDString"); // Keep this in sync with buildODRType. DEFINE_GETIMPL_LOOKUP(DICompositeType, (Tag, Name, File, Line, Scope, BaseType, SizeInBits, - AlignInBits, OffsetInBits, Flags, Elements, + AlignInBits, OffsetInBits, Flags, VFlags, Elements, RuntimeLang, VTableHolder, TemplateParams, Identifier, Discriminator, DataLocation, Associated, Allocated, Rank, Annotations)); @@ -783,10 +792,10 @@ DICompositeType *DICompositeType::getImpl( Elements, VTableHolder, TemplateParams, Identifier, Discriminator, DataLocation, Associated, Allocated, Rank, Annotations}; - DEFINE_GETIMPL_STORE( - DICompositeType, - (Tag, Line, RuntimeLang, SizeInBits, AlignInBits, OffsetInBits, Flags), - Ops); + DEFINE_GETIMPL_STORE(DICompositeType, + (Tag, Line, RuntimeLang, SizeInBits, + AlignInBits, OffsetInBits, Flags, VFlags), + Ops); } DICompositeType *DICompositeType::buildODRType( @@ -1030,7 +1039,8 @@ DISubprogram::DISubprogram(LLVMContext &C, StorageType Storage, unsigned Line, } DISubprogram::DISPFlags DISubprogram::toSPFlags(bool IsLocalToUnit, bool IsDefinition, bool IsOptimized, - unsigned Virtuality, bool IsMainSubprogram) { + unsigned Virtuality, bool IsMainSubprogram, + bool IsDescList, bool IsDescLoc) { // We're assuming virtuality is the low-order field. static_assert(int(SPFlagVirtual) == int(dwarf::DW_VIRTUALITY_virtual) && int(SPFlagPureVirtual) == @@ -1127,6 +1137,7 @@ DISubprogram *DISubprogram::getImpl( int ThisAdjustment, DIFlags Flags, DISPFlags SPFlags, Metadata *Unit, Metadata *TemplateParams, Metadata *Declaration, Metadata *RetainedNodes, Metadata *ThrownTypes, Metadata *Annotations, MDString *TargetFuncName, + Metadata *StaticLink, Metadata *RcFrameBase, StorageType Storage, bool ShouldCreate) { assert(isCanonical(Name) && "Expected canonical MDString"); assert(isCanonical(LinkageName) && "Expected canonical MDString"); @@ -1136,22 +1147,28 @@ DISubprogram *DISubprogram::getImpl( ContainingType, VirtualIndex, ThisAdjustment, Flags, SPFlags, Unit, TemplateParams, Declaration, RetainedNodes, ThrownTypes, Annotations, - TargetFuncName)); + TargetFuncName, StaticLink, RcFrameBase)); SmallVector Ops = { File, Scope, Name, LinkageName, Type, Unit, Declaration, RetainedNodes, ContainingType, TemplateParams, ThrownTypes, Annotations, - TargetFuncName}; - if (!TargetFuncName) { + TargetFuncName, StaticLink, RcFrameBase}; + if (!RcFrameBase) { Ops.pop_back(); - if (!Annotations) { - Ops.pop_back(); - if (!ThrownTypes) { + if (!StaticLink) { + Ops.pop_back(); + if (!TargetFuncName) { Ops.pop_back(); - if (!TemplateParams) { + if (!Annotations) { Ops.pop_back(); - if (!ContainingType) + if (!ThrownTypes) { Ops.pop_back(); + if (!TemplateParams) { + Ops.pop_back(); + if (!ContainingType) + Ops.pop_back(); + } + } } } } @@ -1304,7 +1321,8 @@ DIGlobalVariable::getImpl(LLVMContext &Context, Metadata *Scope, MDString *Name, DILocalVariable * DILocalVariable::getImpl(LLVMContext &Context, Metadata *Scope, MDString *Name, Metadata *File, unsigned Line, Metadata *Type, - unsigned Arg, DIFlags Flags, uint32_t AlignInBits, + unsigned Arg, unsigned LexicalScope, + DIFlags Flags, DIVarFlags VarFlags, uint32_t AlignInBits, Metadata *Annotations, StorageType Storage, bool ShouldCreate) { // 64K ought to be enough for any frontend. @@ -1312,10 +1330,13 @@ DILocalVariable::getImpl(LLVMContext &Context, Metadata *Scope, MDString *Name, assert(Scope && "Expected scope"); assert(isCanonical(Name) && "Expected canonical MDString"); - DEFINE_GETIMPL_LOOKUP(DILocalVariable, (Scope, Name, File, Line, Type, Arg, - Flags, AlignInBits, Annotations)); + DEFINE_GETIMPL_LOOKUP(DILocalVariable, + (Scope, Name, File, Line, Type, Arg, LexicalScope, + Flags, VarFlags, AlignInBits, Annotations)); Metadata *Ops[] = {Scope, Name, File, Type, Annotations}; - DEFINE_GETIMPL_STORE(DILocalVariable, (Line, Arg, Flags, AlignInBits), Ops); + DEFINE_GETIMPL_STORE(DILocalVariable, + (Line, Arg, LexicalScope, Flags, VarFlags, + AlignInBits), Ops); } DIVariable::DIVariable(LLVMContext &C, unsigned ID, StorageType Storage, @@ -1364,9 +1385,10 @@ DILabel *DILabel::getImpl(LLVMContext &Context, Metadata *Scope, MDString *Name, DIExpression *DIExpression::getImpl(LLVMContext &Context, ArrayRef Elements, + ArrayRef Refs, StorageType Storage, bool ShouldCreate) { - DEFINE_GETIMPL_LOOKUP(DIExpression, (Elements)); - DEFINE_GETIMPL_STORE_NO_OPS(DIExpression, (Elements)); + DEFINE_GETIMPL_LOOKUP(DIExpression, (Elements, Refs)); + DEFINE_GETIMPL_STORE_N(DIExpression, (Elements), Refs, Refs.size()); } bool DIExpression::isEntryValue() const { if (auto singleLocElts = getSingleLocationExpressionElements()) { @@ -1416,12 +1438,25 @@ unsigned DIExpression::ExprOperand::getSize() const { case dwarf::DW_OP_LLVM_entry_value: case dwarf::DW_OP_LLVM_arg: case dwarf::DW_OP_regx: + case dwarf::DW_OP_call2: + case dwarf::DW_OP_call4: return 2; default: return 1; } } +bool DIExpression::ExprOperand::hasRef() const { + switch (getOp()) { + default: + return false; + case dwarf::DW_OP_call4: + case dwarf::DW_OP_call2: + break; + } + return true; +} + bool DIExpression::isValid() const { for (auto I = expr_op_begin(), E = expr_op_end(); I != E; ++I) { // Check that there's space for the operand. @@ -1472,12 +1507,21 @@ bool DIExpression::isValid() const { ++FirstOp; return I->get() == FirstOp->get() && I->getArg(0) == 1; } + case dwarf::DW_OP_call2: + case dwarf::DW_OP_call4: { + // Check if references are there or not. + if ((I->getArg(0)) >= getNumOperands()) + return false; + break; + } case dwarf::DW_OP_LLVM_implicit_pointer: case dwarf::DW_OP_LLVM_convert: case dwarf::DW_OP_LLVM_arg: case dwarf::DW_OP_LLVM_tag_offset: case dwarf::DW_OP_LLVM_extract_bits_sext: case dwarf::DW_OP_LLVM_extract_bits_zext: + case dwarf::DW_OP_RC_byte_swap: + case dwarf::DW_OP_RC_resolve_file_address: case dwarf::DW_OP_constu: case dwarf::DW_OP_plus_uconst: case dwarf::DW_OP_plus: @@ -2215,6 +2259,7 @@ DIExpression::isConstant() const { // Recognize signed and unsigned constants. // An signed constants can be represented as DW_OP_consts C DW_OP_stack_value // (DW_OP_LLVM_fragment of Len). + // // An unsigned constant can be represented as // DW_OP_constu C DW_OP_stack_value (DW_OP_LLVM_fragment of Len). diff --git a/llvm/lib/IR/LLVMContextImpl.h b/llvm/lib/IR/LLVMContextImpl.h index e76f004b590efe..8755f0331a5286 100644 --- a/llvm/lib/IR/LLVMContextImpl.h +++ b/llvm/lib/IR/LLVMContextImpl.h @@ -462,25 +462,33 @@ template <> struct MDNodeKeyImpl { template <> struct MDNodeKeyImpl { unsigned Tag; MDString *Name; + MDString *PictureString; uint64_t SizeInBits; uint32_t AlignInBits; unsigned Encoding; unsigned Flags; - - MDNodeKeyImpl(unsigned Tag, MDString *Name, uint64_t SizeInBits, - uint32_t AlignInBits, unsigned Encoding, unsigned Flags) - : Tag(Tag), Name(Name), SizeInBits(SizeInBits), AlignInBits(AlignInBits), - Encoding(Encoding), Flags(Flags) {} + std::optional DecimalAttrInfo; + + MDNodeKeyImpl(unsigned Tag, MDString *Name, MDString *PictureString, + uint64_t SizeInBits, uint32_t AlignInBits, unsigned Encoding, + unsigned Flags, + std::optional DecimalAttrInfo) + : Tag(Tag), Name(Name), PictureString(PictureString), + SizeInBits(SizeInBits), AlignInBits(AlignInBits), Encoding(Encoding), + Flags(Flags), DecimalAttrInfo(DecimalAttrInfo) {} MDNodeKeyImpl(const DIBasicType *N) - : Tag(N->getTag()), Name(N->getRawName()), SizeInBits(N->getSizeInBits()), + : Tag(N->getTag()), Name(N->getRawName()), + PictureString(N->getRawPictureString()), SizeInBits(N->getSizeInBits()), AlignInBits(N->getAlignInBits()), Encoding(N->getEncoding()), - Flags(N->getFlags()) {} + Flags(N->getFlags()), DecimalAttrInfo(N->getDecimalInfo()) {} bool isKeyOf(const DIBasicType *RHS) const { return Tag == RHS->getTag() && Name == RHS->getRawName() && + PictureString == RHS->getRawPictureString() && SizeInBits == RHS->getSizeInBits() && AlignInBits == RHS->getAlignInBits() && - Encoding == RHS->getEncoding() && Flags == RHS->getFlags(); + Encoding == RHS->getEncoding() && Flags == RHS->getFlags() && + DecimalAttrInfo == RHS->getDecimalInfo(); } unsigned getHashValue() const { @@ -545,26 +553,30 @@ template <> struct MDNodeKeyImpl { unsigned Flags; Metadata *ExtraData; Metadata *Annotations; + Metadata *Location; + Metadata *Allocated; MDNodeKeyImpl(unsigned Tag, MDString *Name, Metadata *File, unsigned Line, Metadata *Scope, Metadata *BaseType, uint64_t SizeInBits, uint32_t AlignInBits, uint64_t OffsetInBits, std::optional DWARFAddressSpace, - std::optional PtrAuthData, - unsigned Flags, Metadata *ExtraData, Metadata *Annotations) + std::optional PtrAuthData, unsigned Flags, + Metadata *ExtraData, Metadata *Annotations, Metadata *Location, + Metadata *Allocated) : Tag(Tag), Name(Name), File(File), Line(Line), Scope(Scope), BaseType(BaseType), SizeInBits(SizeInBits), OffsetInBits(OffsetInBits), AlignInBits(AlignInBits), DWARFAddressSpace(DWARFAddressSpace), - PtrAuthData(PtrAuthData), Flags(Flags), ExtraData(ExtraData), - Annotations(Annotations) {} + PtrAuthData(PtrAuthData), Flags(Flags), ExtraData(ExtraData), Annotations(Annotations), + Location(Location), Allocated(Allocated) {} MDNodeKeyImpl(const DIDerivedType *N) : Tag(N->getTag()), Name(N->getRawName()), File(N->getRawFile()), Line(N->getLine()), Scope(N->getRawScope()), BaseType(N->getRawBaseType()), SizeInBits(N->getSizeInBits()), OffsetInBits(N->getOffsetInBits()), AlignInBits(N->getAlignInBits()), DWARFAddressSpace(N->getDWARFAddressSpace()), - PtrAuthData(N->getPtrAuthData()), Flags(N->getFlags()), - ExtraData(N->getRawExtraData()), Annotations(N->getRawAnnotations()) {} + PtrAuthData(N->getPtrAuthData()), Flags(N->getFlags()), + ExtraData(N->getRawExtraData()), Annotations(N->getRawAnnotations()), + Location(N->getRawLocation()), Allocated(N->getRawAllocated()) {} bool isKeyOf(const DIDerivedType *RHS) const { return Tag == RHS->getTag() && Name == RHS->getRawName() && @@ -576,7 +588,9 @@ template <> struct MDNodeKeyImpl { DWARFAddressSpace == RHS->getDWARFAddressSpace() && PtrAuthData == RHS->getPtrAuthData() && Flags == RHS->getFlags() && ExtraData == RHS->getRawExtraData() && - Annotations == RHS->getRawAnnotations(); + Annotations == RHS->getRawAnnotations() && + Location == RHS->getRawLocation() && + Allocated == RHS->getRawAllocated(); } unsigned getHashValue() const { @@ -638,6 +652,7 @@ template <> struct MDNodeKeyImpl { uint64_t OffsetInBits; uint32_t AlignInBits; unsigned Flags; + unsigned VFlags; Metadata *Elements; unsigned RuntimeLang; Metadata *VTableHolder; @@ -653,26 +668,28 @@ template <> struct MDNodeKeyImpl { MDNodeKeyImpl(unsigned Tag, MDString *Name, Metadata *File, unsigned Line, Metadata *Scope, Metadata *BaseType, uint64_t SizeInBits, uint32_t AlignInBits, uint64_t OffsetInBits, unsigned Flags, - Metadata *Elements, unsigned RuntimeLang, + unsigned VFlags, Metadata *Elements, unsigned RuntimeLang, Metadata *VTableHolder, Metadata *TemplateParams, MDString *Identifier, Metadata *Discriminator, Metadata *DataLocation, Metadata *Associated, Metadata *Allocated, Metadata *Rank, Metadata *Annotations) : Tag(Tag), Name(Name), File(File), Line(Line), Scope(Scope), BaseType(BaseType), SizeInBits(SizeInBits), OffsetInBits(OffsetInBits), - AlignInBits(AlignInBits), Flags(Flags), Elements(Elements), - RuntimeLang(RuntimeLang), VTableHolder(VTableHolder), - TemplateParams(TemplateParams), Identifier(Identifier), - Discriminator(Discriminator), DataLocation(DataLocation), - Associated(Associated), Allocated(Allocated), Rank(Rank), - Annotations(Annotations) {} + AlignInBits(AlignInBits), Flags(Flags), VFlags(VFlags), + Elements(Elements), RuntimeLang(RuntimeLang), + VTableHolder(VTableHolder), TemplateParams(TemplateParams), + Identifier(Identifier), Discriminator(Discriminator), + DataLocation(DataLocation), Associated(Associated), + Allocated(Allocated), Rank(Rank), Annotations(Annotations) {} + MDNodeKeyImpl(const DICompositeType *N) : Tag(N->getTag()), Name(N->getRawName()), File(N->getRawFile()), Line(N->getLine()), Scope(N->getRawScope()), BaseType(N->getRawBaseType()), SizeInBits(N->getSizeInBits()), OffsetInBits(N->getOffsetInBits()), AlignInBits(N->getAlignInBits()), - Flags(N->getFlags()), Elements(N->getRawElements()), - RuntimeLang(N->getRuntimeLang()), VTableHolder(N->getRawVTableHolder()), + Flags(N->getFlags()), VFlags(N->getVendorDIFlags()), + Elements(N->getRawElements()), RuntimeLang(N->getRuntimeLang()), + VTableHolder(N->getRawVTableHolder()), TemplateParams(N->getRawTemplateParams()), Identifier(N->getRawIdentifier()), Discriminator(N->getRawDiscriminator()), @@ -687,6 +704,7 @@ template <> struct MDNodeKeyImpl { SizeInBits == RHS->getSizeInBits() && AlignInBits == RHS->getAlignInBits() && OffsetInBits == RHS->getOffsetInBits() && Flags == RHS->getFlags() && + VFlags == RHS->getVendorDIFlags() && Elements == RHS->getRawElements() && RuntimeLang == RHS->getRuntimeLang() && VTableHolder == RHS->getRawVTableHolder() && @@ -774,6 +792,8 @@ template <> struct MDNodeKeyImpl { Metadata *ThrownTypes; Metadata *Annotations; MDString *TargetFuncName; + Metadata *StaticLinkExpr; + Metadata *RcFrameBaseExpr; MDNodeKeyImpl(Metadata *Scope, MDString *Name, MDString *LinkageName, Metadata *File, unsigned Line, Metadata *Type, @@ -782,14 +802,16 @@ template <> struct MDNodeKeyImpl { unsigned SPFlags, Metadata *Unit, Metadata *TemplateParams, Metadata *Declaration, Metadata *RetainedNodes, Metadata *ThrownTypes, Metadata *Annotations, - MDString *TargetFuncName) + MDString *TargetFuncName, Metadata *StaticLinkExpr, + Metadata *RcFrameBaseExpr) : Scope(Scope), Name(Name), LinkageName(LinkageName), File(File), Line(Line), Type(Type), ScopeLine(ScopeLine), ContainingType(ContainingType), VirtualIndex(VirtualIndex), ThisAdjustment(ThisAdjustment), Flags(Flags), SPFlags(SPFlags), Unit(Unit), TemplateParams(TemplateParams), Declaration(Declaration), RetainedNodes(RetainedNodes), ThrownTypes(ThrownTypes), - Annotations(Annotations), TargetFuncName(TargetFuncName) {} + Annotations(Annotations), TargetFuncName(TargetFuncName), + StaticLinkExpr(StaticLinkExpr), RcFrameBaseExpr(RcFrameBaseExpr) {} MDNodeKeyImpl(const DISubprogram *N) : Scope(N->getRawScope()), Name(N->getRawName()), LinkageName(N->getRawLinkageName()), File(N->getRawFile()), @@ -803,7 +825,9 @@ template <> struct MDNodeKeyImpl { RetainedNodes(N->getRawRetainedNodes()), ThrownTypes(N->getRawThrownTypes()), Annotations(N->getRawAnnotations()), - TargetFuncName(N->getRawTargetFuncName()) {} + TargetFuncName(N->getRawTargetFuncName()), + StaticLinkExpr(N->getRawStaticLinkExpr()), + RcFrameBaseExpr(N->getRawRcFrameBaseExpr()) {} bool isKeyOf(const DISubprogram *RHS) const { return Scope == RHS->getRawScope() && Name == RHS->getRawName() && @@ -820,7 +844,9 @@ template <> struct MDNodeKeyImpl { RetainedNodes == RHS->getRawRetainedNodes() && ThrownTypes == RHS->getRawThrownTypes() && Annotations == RHS->getRawAnnotations() && - TargetFuncName == RHS->getRawTargetFuncName(); + TargetFuncName == RHS->getRawTargetFuncName() && + StaticLinkExpr == RHS->getRawStaticLinkExpr() && + RcFrameBaseExpr == RHS->getRawRcFrameBaseExpr(); } bool isDefinition() const { return SPFlags & DISubprogram::SPFlagDefinition; } @@ -1125,26 +1151,32 @@ template <> struct MDNodeKeyImpl { unsigned Line; Metadata *Type; unsigned Arg; + unsigned LexicalScope; unsigned Flags; + unsigned VarFlags; uint32_t AlignInBits; Metadata *Annotations; MDNodeKeyImpl(Metadata *Scope, MDString *Name, Metadata *File, unsigned Line, - Metadata *Type, unsigned Arg, unsigned Flags, - uint32_t AlignInBits, Metadata *Annotations) + Metadata *Type, unsigned Arg, unsigned LexicalScope, + unsigned Flags, unsigned VarFlags, uint32_t AlignInBits, Metadata *Annotations) : Scope(Scope), Name(Name), File(File), Line(Line), Type(Type), Arg(Arg), - Flags(Flags), AlignInBits(AlignInBits), Annotations(Annotations) {} + LexicalScope(LexicalScope), Flags(Flags), VarFlags(VarFlags), + AlignInBits(AlignInBits), Annotations(Annotations) {} MDNodeKeyImpl(const DILocalVariable *N) : Scope(N->getRawScope()), Name(N->getRawName()), File(N->getRawFile()), Line(N->getLine()), Type(N->getRawType()), Arg(N->getArg()), - Flags(N->getFlags()), AlignInBits(N->getAlignInBits()), + LexicalScope(N->getLexicalScope()), Flags(N->getFlags()), + VarFlags(N->getVarFlags()), AlignInBits(N->getAlignInBits()), Annotations(N->getRawAnnotations()) {} bool isKeyOf(const DILocalVariable *RHS) const { return Scope == RHS->getRawScope() && Name == RHS->getRawName() && File == RHS->getRawFile() && Line == RHS->getLine() && Type == RHS->getRawType() && Arg == RHS->getArg() && - Flags == RHS->getFlags() && AlignInBits == RHS->getAlignInBits() && + LexicalScope == RHS->getLexicalScope() && + Flags == RHS->getFlags() && VarFlags == RHS->getVarFlags() && + AlignInBits == RHS->getAlignInBits() && Annotations == RHS->getRawAnnotations(); } @@ -1183,12 +1215,15 @@ template <> struct MDNodeKeyImpl { template <> struct MDNodeKeyImpl { ArrayRef Elements; + ArrayRef Refs; - MDNodeKeyImpl(ArrayRef Elements) : Elements(Elements) {} - MDNodeKeyImpl(const DIExpression *N) : Elements(N->getElements()) {} + MDNodeKeyImpl(ArrayRef Elements, ArrayRef Refs) + : Elements(Elements), Refs(Refs) {} + MDNodeKeyImpl(const DIExpression *N) + : Elements(N->getElements()), Refs(N->getRefs()) {} bool isKeyOf(const DIExpression *RHS) const { - return Elements == RHS->getElements(); + return Elements == RHS->getElements() && Refs.equals(RHS->getRefs()); } unsigned getHashValue() const { @@ -1473,7 +1508,7 @@ class LLVMContextImpl { /// The minimum hotness value a diagnostic needs in order to be included in /// optimization diagnostics. /// - /// The threshold is an Optional value, which maps to one of the 3 states: + /// The threshold is an std::optional value, which maps to one of the 3 states: /// 1). 0 => threshold disabled. All emarks will be printed. /// 2). positive int => manual threshold by user. Remarks with hotness exceed /// threshold will be printed. @@ -1526,7 +1561,7 @@ class LLVMContextImpl { DenseSet CLASS##s; #include "llvm/IR/Metadata.def" - // Optional map for looking up composite types by identifier. + // std::optional map for looking up composite types by identifier. std::optional> DITypeMap; // MDNodes may be uniqued or not uniqued. When they're not uniqued, they diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp index d8f3bab45b2a65..c0a46d431521ce 100644 --- a/llvm/lib/IR/Verifier.cpp +++ b/llvm/lib/IR/Verifier.cpp @@ -1228,6 +1228,7 @@ void Verifier::visitDIDerivedType(const DIDerivedType &N) { (N.getTag() == dwarf::DW_TAG_variable && N.isStaticMember()) || N.getTag() == dwarf::DW_TAG_inheritance || N.getTag() == dwarf::DW_TAG_friend || + N.getTag() == dwarf::DW_TAG_dynamic_type || N.getTag() == dwarf::DW_TAG_set_type || N.getTag() == dwarf::DW_TAG_template_alias, "invalid tag", &N); @@ -1251,10 +1252,15 @@ void Verifier::visitDIDerivedType(const DIDerivedType &N) { } } + if (N.getTag() == dwarf::DW_TAG_dynamic_type) { + CheckDI(N.getLocation(), + "missing data location attribute in dynamic type", &N); + CheckDI(cast(N.getLocation())->isValid(), + "invalid data location expression in dynamic type", &N); + } CheckDI(isScope(N.getRawScope()), "invalid scope", &N, N.getRawScope()); CheckDI(isType(N.getRawBaseType()), "invalid base type", &N, - N.getRawBaseType()); - + N.getRawBaseType()); if (N.getDWARFAddressSpace()) { CheckDI(N.getTag() == dwarf::DW_TAG_pointer_type || N.getTag() == dwarf::DW_TAG_reference_type || @@ -1468,6 +1474,10 @@ void Verifier::visitDISubprogram(const DISubprogram &N) { CheckDI(!hasConflictingReferenceFlags(N.getFlags()), "invalid reference flags", &N); + CheckDI(!(N.isDescLocSubProgram() && N.isDescListSubProgram()), + "subprogram cannot have both descriptor list and descriptor locator", + &N); + auto *Unit = N.getRawUnit(); if (N.isDefinition()) { // Subprogram definitions (not part of the type hierarchy). @@ -6630,7 +6640,7 @@ void Verifier::visitConstrainedFPIntrinsic(ConstrainedFPIntrinsic &FPI) { Check(!ValTy->isVectorTy() && !ResultTy->isVectorTy(), "Intrinsic does not support vectors", &FPI); break; - } + } case Intrinsic::experimental_constrained_fcmp: case Intrinsic::experimental_constrained_fcmps: { diff --git a/llvm/unittests/IR/MetadataTest.cpp b/llvm/unittests/IR/MetadataTest.cpp index 17573ca57e0874..66264523e9dd90 100644 --- a/llvm/unittests/IR/MetadataTest.cpp +++ b/llvm/unittests/IR/MetadataTest.cpp @@ -1825,6 +1825,62 @@ TEST_F(DIBasicTypeTest, getUnspecified) { EXPECT_EQ(DINode::FlagZero, N->getFlags()); } +TEST_F(DIBasicTypeTest, getOptionalDecimalInfo) { + auto *N = DIBasicType::get( + Context, dwarf::DW_TAG_base_type, "ext1", + MDString::get(Context, "S999V99"), 40, 1, dwarf::DW_ATE_numeric_string, + DINode::FlagZero, + DIBasicType::DecimalInfo{ 5, dwarf::DW_DS_trailing_overpunch, -2 }); + + EXPECT_EQ(dwarf::DW_TAG_base_type, N->getTag()); + EXPECT_EQ("ext1", N->getName()); + EXPECT_EQ(40u, N->getSizeInBits()); + EXPECT_EQ(1u, N->getAlignInBits()); + EXPECT_EQ(dwarf::DW_ATE_numeric_string, N->getEncoding()); + EXPECT_EQ(DINode::FlagZero, N->getFlags()); + EXPECT_EQ("S999V99", N->getPictureString()); + EXPECT_EQ(dwarf::DW_DS_trailing_overpunch, N->getDecimalSign().value()); + EXPECT_EQ(-2, N->getScale().value()); + EXPECT_EQ(5, N->getDigitCount().value()); + + EXPECT_EQ(N, DIBasicType::get( + Context, dwarf::DW_TAG_base_type, "ext1", + MDString::get(Context, "S999V99"), 40, 1, + dwarf::DW_ATE_numeric_string, DINode::FlagZero, + DIBasicType::DecimalInfo{ 5, dwarf::DW_DS_trailing_overpunch, + -2 })); + + /// Generally this fails verifier as we are trying to create extended encoding + /// without any extended info. + EXPECT_NE(N, DIBasicType::get( + Context, dwarf::DW_TAG_base_type, "ext1", + MDString::get(Context, "S999999"), 40, 1, + dwarf::DW_ATE_numeric_string, DINode::FlagZero, + DIBasicType::DecimalInfo{ 5, dwarf::DW_DS_trailing_overpunch, + -2 })); + EXPECT_NE(N, DIBasicType::get( + Context, dwarf::DW_TAG_base_type, "ext1", + MDString::get(Context, "S999V99"), 40, 1, + dwarf::DW_ATE_numeric_string, DINode::FlagZero, + DIBasicType::DecimalInfo{ 4, dwarf::DW_DS_trailing_overpunch, + -2 })); + EXPECT_NE(N, DIBasicType::get( + Context, dwarf::DW_TAG_base_type, "ext1", + MDString::get(Context, "S999V99"), 40, 1, + dwarf::DW_ATE_numeric_string, DINode::FlagZero, + DIBasicType::DecimalInfo{ 5, dwarf::DW_DS_leading_overpunch, + -2 })); + EXPECT_NE(N, DIBasicType::get( + Context, dwarf::DW_TAG_base_type, "ext1", + MDString::get(Context, "S999V99"), 40, 1, + dwarf::DW_ATE_numeric_string, DINode::FlagZero, + DIBasicType::DecimalInfo{ 5, dwarf::DW_DS_trailing_overpunch, + -1 })); + + TempDIBasicType Temp = N->clone(); + EXPECT_EQ(N, MDNode::replaceWithUniqued(std::move(Temp))); +} + typedef MetadataTest DITypeTest; TEST_F(DITypeTest, clone) {