From 9b8704a518519f738d5851f5f3f97c39ec89d22d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mirko=20Brku=C5=A1anin?= Date: Wed, 24 Jan 2024 13:43:07 +0100 Subject: [PATCH] [AMDGPU] Add GFX12 WMMA and SWMMAC instructions (#77795) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Petar Avramovic Co-authored-by: Piotr Sobczak [AMDGPU][GFX12] VOP encoding and codegen - add support for v_cvt fp8/… (#78414) …bf8 instructions Add VOP1, VOP1_DPP8, VOP1_DPP16, VOP3, VOP3_DPP8, VOP3_DPP16 instructions that were supported on GFX940 (MI300): - V_CVT_F32_FP8 - V_CVT_F32_BF8 - V_CVT_PK_F32_FP8 - V_CVT_PK_F32_BF8 - V_CVT_PK_FP8_F32 - V_CVT_PK_BF8_F32 - V_CVT_SR_FP8_F32 - V_CVT_SR_BF8_F32 --------- Co-authored-by: Mateja Marjanovic Co-authored-by: Mirko Brkušanin (cherry picked from commit cfddb59be2124f7ec615f48a2d0395c6fdb1bb56) [RISCV] Support __riscv_v_fixed_vlen for vbool types. (#76551) This adopts a similar behavior to AArch64 SVE, where bool vectors are represented as a vector of chars with 1/8 the number of elements. This ensures the vector always occupies a power of 2 number of bytes. A consequence of this is that vbool64_t, vbool32_t, and vool16_t can only be used with a vector length that guarantees at least 8 bits. [Docs] Fix documentation build. Missing ending `` after c92ad411f2f94d8521cd18abcb37285f9a390ecb Backport '[clang] static operators should evaluate object argument (reland)' to release/18.x (#80109) Cherry picked from commit ee01a2c3996f9647f3158f5acdb921a6ede94dc1. Closes #80041, backport #80108. Co-authored-by: Shafik Yaghmour Co-authored-by: cor3ntin Co-authored-by: Aaron Ballman PR for llvm/llvm-project#79568 (#80120) Backporting https://github.com/llvm/llvm-project/pull/79568 to clang 18. [docs] Add release notes for Windows specific changes in 18.x (#80011) [AArch64] Add some release notes items (#79983) [C++20] [Modules] Don't perform ODR checks in GMF Close https://github.com/llvm/llvm-project/issues/79240. See the linked issue for details. Given the frequency of issue reporting about false positive ODR checks (I received private issue reports too), I'd like to backport this to 18.x too. [clang] Fix unexpected `-Wconstant-logical-operand` in C23 (#80724) C23 has `bool`, but logical operators still return int. Check that we're not in C to avoid false-positive -Wconstant-logical-operand. Fixes https://github.com/llvm/llvm-project/issues/64356 (cherry picked from commit a18e92d020b895b712175a3b13a3d021608115a7) [18.x][Docs] Add release note about Clang-defined target OS macros (#80044) The change is included in the 18.x release. Move the release note to the release branch and reformat. (cherry picked from commit b40d5b1b08564d23d5e0769892ebbc32447b2987) ReleaseNotes: mention -mtls-dialect=desc (#82731) [Clang] Fixes to immediate-escalating functions (#82281) * Consider that immediate escalating function can appear at global scope, fixing a crash * Lambda conversion to function pointer was sometimes not performed in an immediate function context when it should be. Fixes #82258 (cherry picked from commit baf6bd303bd58a521809d456dd9b179636982fc5) [Clang] [Sema] Handle placeholders in '.*' expressions (#83103) When analysing whether we should handle a binary expression as an overloaded operator call or a builtin operator, we were calling `checkPlaceholderForOverload()`, which takes care of any placeholders that are not overload sets—which would usually make sense since those need to be handled as part of overload resolution. Unfortunately, we were also doing that for `.*`, which is not overloadable, and then proceeding to create a builtin operator anyway, which would crash if the RHS happened to be an unresolved overload set (due hitting an assertion in `CreateBuiltinBinOp()`—specifically, in one of its callees—in the `.*` case that makes sure its arguments aren’t placeholders). This pr instead makes it so we check for *all* placeholders early if the operator is `.*`. It’s worth noting that, 1. In the `.*` case, we now additionally also check for *any* placeholders (not just non-overload-sets) in the LHS; this shouldn’t make a difference, however—at least I couldn’t think of a way to trigger the assertion with an overload set as the LHS of `.*`; it is worth noting that the assertion in question would also complain if the LHS happened to be of placeholder type, though. 2. There is another case in which we also don’t perform overload resolution—namely `=` if the LHS is not of class or enumeration type after handling non-overload-set placeholders—as in the `.*` case, but similarly to 1., I first couldn’t think of a way of getting this case to crash, and secondly, `CreateBuiltinBinOp()` doesn’t seem to care about placeholders in the LHS or RHS in the `=` case (from what I can tell, it, or rather one of its callees, only checks that the LHS is not a pseudo-object type, but those will have already been handled by the call to `checkPlaceholderForOverload()` by the time we get to this function), so I don’t think this case suffers from the same problem. This fixes #53815. --------- Co-authored-by: Aaron Ballman [InstCombine] Fix miscompilation in PR83947 (#83993) https://github.com/llvm/llvm-project/blob/762f762504967efbe159db5c737154b989afc9bb/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp#L394-L407 Comment from @topperc: > This transforms assumes the mask is a non-zero splat. We only know its a splat and not provably all 0s. The mask is a constexpr that includes the address of the global variable. We can't resolve the constant expression to an exact value. Fixes #83947. SystemZ release notes for 18.x. (#84560) Remove support for EXPORTAS in def files to maintain ABI compatibility for COFFShortExport [clang][Sema] Fix a CTAD regression after 42239d2e9 (#86914) The most recent declaration of a template as a friend can introduce a different template parameter depth compared to what we anticipate from a CTAD guide. Fixes https://github.com/llvm/llvm-project/issues/86769 [clang] Avoid -Wshadow warning when init-capture named same as class field (#74512) Shadowing warning doesn't make much sense since field is not available in lambda's body without capturing this. Fixes https://github.com/llvm/llvm-project/issues/71976 [SLP]Fix a crash if the argument of call was affected by minbitwidth analysis. Need to support proper type conversion for function arguments to avoid compiler crash. Fix override keyword being print to the left side Previously, the `override` keyword in C++ was being print in the left side of a method decl, which is unsupported by C++ standard. This commit fixes that by setting the `CanPrintOnLeft` field to 0, forcing it to be print on the right side of the decl. Signed-off-by: Giuliano Belinassi [clang codegen] Fix MS ABI detection of user-provided constructors. (#90151) In the context of determining whether a class counts as an "aggregate", a constructor template counts as a user-provided constructor. Fixes #86384 (cherry picked from commit 3ab4ae9e58c09dfd8203547ba8916f3458a0a481) release/18.x: [libclc] Fix linking against libIRReader Fixes https://github.com/llvm/llvm-project/issues/91551 Update llvm/test/Transforms/InstCombine/bit_ceil.ll Co-authored-by: Yingwei Zheng [RISCV] Add a unaligned-scalar-mem feature like we had in clang 17. This is ORed with the fast-unaligned-access feature which applies to scalar and vector together.: Regular squash. Cobol/PlI changes from 785ddc60@https://gitlab.phidani.be/Chirag.Patel/lldb.git Cobol/PLI support added from 6cefb217f097ac@https://gitlab.phidani.be/Chirag.Patel/llvm.git [LLDB] added lldb rpmbuild spec file [RPMBuild] Added lldb rpmbuild support. [LLDBRpm] added version for yum update. [lldb_rpm] minor cleanup. Build fix rleated to RTTI. build fix. [DWARFASTParserLegacy] Initial support for union type. [lldb][LegacyTypeSystem] Changed struct/union member offset from bytes to bits to support DW_AT_data_bit_offset. [lldbrpm] changed version suffix. [LegacyASTContext] Fix var string length display. [LLDB][CobolUserExpression] Added AST node Function call place holder. build fix. [LLVM][Test] Fixed assembler round trip test. [LLDB][CobolUserExpression] Added ast evaluation for sizeof operator. [LLDB][CobolUserExpression] Added placeholder in parser for func call. [LLDB][CobolUserExpression] Added sizeof operator, temporary placeholder for LENGTH OF. [LLDB][PLIUserExpression] Fixed array indexing. [LLDB][ValueObjectPrinter] Skip summary if custom format is requested. [LLDB][PLILanguage] changed bitset size, read from array type name. [LLDB][ValueObject] Fixed pli var string length read. [LLDB][PLILanguage] Fixed support for var string summary formatter. [LLVM][DIBuilder][C-API] Added changes to add lexical scope info for auto variable for functions. [LLVM][AsmCodegen] Added raincode extention AT_lexical_scope. [LLDB][SymbolFileDWARF] Added support for RAINCODE_lexical_scope attribute. [LLDB][PLIUserExpression] Added sizeof operator support, it will be renamed to proper functiona name later. [LLDB][ValueObject] minor cleanup. [LLDB][PLIUserExpression] Added STORAGE/STG builtin func support. [LLDB][PLIUserExpression][CobolUserExpression] Added LENGTH() for Cobol and STG/STORAGE() for PL/I, removed sizeof operator for both. [LLDB][DWARFASTParserLegacy] Added placeholder for DW_TAG_reference_type. [LLVM][CodeGen][AsmPrinter] Added DW_AT_name attribute to TAG_array_type. [LLDB][DWARFExpression] minor cleanup. [LLDB][PLILanguage] Fixed bitset array size read from array type. [LLDB][LegacyASTContext] Moved bit array calculation to type system. [LLVM][AsmPrinter] Fixed TAG_array duplicate attribute export. [LLVM][C-API] Changes array type api. [LLDB][PLI/Cobol UserExpression] Fixed array indexing, removed c style [] index access. [LLDB][PLIUserExpression] minor fix. [LLDB] Fixed bug relating struct member name access for Cobol/PL1. fixed coding style/whitespace/typos. [LLDB][LegacyTypeSystem] Place holder beautification for edited types. [LLDB] rpm version upgrade. [LLDB][CobolUserExpression] Fixed pic string ref modifier. [LLDB][TypeSystem] Added support to mutate existing type length, fixed cobolUserExpression refmod for display type. [LLDB][CobolUserExpression] Fixed lower bound ref modifier. [LLDB][Cobol/PLI UserExpression] Fixed error while searching for var, do not fully resolve type. [LLDB][RPM] fixed rpm version. cleanup, reduce number of changes from trunk. cleanup, reduce number of changes fomr trunk. build fix. Build fix. Build fix. [LegacyASTContext] Fixed bug relating packed decimal going through ebcdic iconv. [LLVM][DebugInfo] Fixed DIExpression node uniquness issue. build fix. cleanup. Refactoring, moved LegacyASTContext to Plugin typeSystem Legacy. Refactoring, renamed TypeSystem class. build fix. build fix, cleanup. cleanup fixed assert failure. [CobolUserExpression] Added placeholder for simpe assignment operator. [CobolUserExpression] Added basic support for assigment to variables. [CobolUserExpression] Added cobol move-to set-to syntex support. [LegacyTypeSystem][CobolUserExpression] Added literal type double,string. Added TypeSystem Encoding helper functions. [CobolLexer] Added string,float literal type support. [PLIUserExpression] Added assignment operator support. [CobolUserExpression] Added assignment comp-3 support. [PLIUserExpression] Assignment added pli display type support. temporary build fix. DIExpression asmprinter, print null for invalid entry. [Cobol/PLI UserExpression] Assignment endianity bug fix. [Cobol/PLIUserExpression] fixed data extractpr assert, fixed int precision convertion written as zero. [Cobol/PLIUserExpression] Assignment display type assert failure. build fix. [PLIUserExpression] Added support for var string assignment. [LegacyUserExpression] Simple semantic check place-holder. [CobolUserexpression] Assignment expression fixed display, array types. [TypeSystem] fixed encode int precision bug for i64 to i32. [PLI/Cobol UserExpression] fixed support for assinment into refmod data type. [CobolUserExpression] Fixed assignment display/comp-3 regression. temporary build fix. python3 lib on server needs few changes for this build. [TypeSystemLegacy] Fixed edited type display, skip formatting for edited type. [lldbrpm] package lldb-python-script too. [CobolUserExpression] Fixed SelctorOf expression with array index access e.g (lldb)p LastName1 of VAR(1) of TAB. [CobolUserExpression] Assignment to packed decimal fixed, added digit count read support from dwarf instead of runtime calculation. [CoboUserExpression] Fixed assignment string invalid byte order. [PLIUserExpression] Fixed string padding with space. [CobolUserExpression] Fixed Assignment string space padding. [LegacyTypeSysten] fixed crash in encoding due to long length the assignment. [CobolUserExpression][PLIUserExpression] fixed segfault. [DebugInfo] export identifier case as insensitive for PLI/Cobol compiled units. [TypeSystemLegacy] Fixed minor bug with dataencoding. rebase build fix. [StackFrame] fixed support for cobol/pli modref select syntex. case-insensitive breakpoint resolution for PLI/Cobol languages. cleanup. build fix. added initial support for TAG_dynamic_type. added c/c++ api to create dynamic type debug info. [DebugInfo] Added support to generate dwarf attribute DW_AT_allocated for DW_TAG_dynamic_type [PLIUserExpression][CobolUserExpression] Fixed name variable lookup for few cases. [DWARFASTParserLegacy] Initial support to parse TAG_dynamic_type. [AsmPrinter] Fix minor mistake for TAG_dynamic DW_AT_allocated. [TypeSystemLegacy] Added dynamic type place holder. [LLVM][AsmPrinter] Allow OP_call2/4 expression on local variable location. build fix. [LLDB][CompilerType] Added support to fetch dynamic type info. [lldb][ValueObjectVariable] Added dynamic variable read support. [LLDB][ValueObjectVariable] Added allocated check for dynamic types. [LLDB][ValueObjectVariable] fixed TAG_dynamic type attributes optional. [LLVM][DebugInfoMetadata] Fixed minor function call. [LLDB][TypeSystemLegacy] Added dynamic type info support. build fix. for jekins, use python3 sharedlibs lldbrpm use python3. temporary build fix. [LLDB][DWARFExpression] Added temporary operation extension for address calculation with file address in dwarf v5. [LLVM][CodeGen] Fixed dynamic type dwarf expression call2/call4 assert. [LLVM][Verifier] Added dynamic type check. [LLVM][Verifier] Added debugInfo verifier dynamic type extra checks. [LLDB][TypeSystemLegacy] Added check to avoid direct nested dynaic types. [LLVM][DebugInfo] Adding DW_OP_call2/4 support in TAG_subrange attributes DW_AT_lower_bound, DW_AT_upper_bound. [LLDB] Added option to hide frames with invalid line entry target.hide-invalid-legacy-frames, this is a temporary placeholder and it will be moved to more suitable location in future. [LLDB][DataFormatters] Fixed printing of char arrays with non-default format. [LLDB][StackFrame] Added check for member name lookup to reject array of structs. [lldb][DataFormatters] fixed multi-dimesional string formatting. [LLDB][ValueObjectVariable] cleanup: proper error message. [LLVM][DwarfUnit] Added DW_OP_call2/call4 support for array type. [LLVM][DwarfCompileUnit] fixed assert failure with DW_OP_call2/call4. [DIBuilder] Added DW_AT_static_link support. [LLVM][C-API][DebugInfo] Added support for DW_AT_static_link. [DebugInfo] fixed minor bug with Staticlink attribute generation. [DebugInfo] static link cleanup. rebase build fix. [LLDB][DWARFParser] Added initial support to parse DW_AT_static_link. [LLDB][StackFrame] Added support to read static link address. [LLDB][StackFrameList] Added helper function to search stack list using static link. [LLDB][ValueObjectPrinter] regression fix for hex format value print. [LLDB] build fix. [LLDB][ExpressionParser] bug fixed for positive int expression e.g. p move +3 to var. [LLDB][TypeSystemLegacy] Fixed bcd signed preferred value encoding. [LLVM][DebuggerTuning] default tune for lldb. [LLDB][TypeSystemLegacy] iconv try approximate and ignore if not possible, for character decoding. rebase build fix. [LLDB][CobolUserExpression][PLIUserExpression] fixed variable name overwriting. [LLDB][UserExpression] Temporary revert variable name bug. rebase build fix. rebase build fix. rebase build fix. initial placeholder for DW_AT_RAINCODE_static_link_recv. [LLDB][CobolUserExpression][PLIUserExpression] fixed variable name overwrite. [LLDB][Test] fixed UnsupportedLanguage test failure. [LLDB][CobolUserExpression] Place holder for compare operations. lldbrpm, temporary skip python dir. [CobolUserExpression] Adding placeholder for equality comparision. [PLIUserExpression] PLILexer, added partial support for comparision operators. [LLDB][DataExtractor] bytes compare func. rebase build fix. rebase build fix. Added DW_AT_RAINCODE_frame_base Patch by Amin! [LLDB][DWARFParser] Added support to parse DW_AT_RAINCODE_frame_base. build fix. [LLVM] Fix dynamic type [LLVM-C][API] Add api to create a dynamic DISubrange [LLDB] Add support for DW_AT_count as a DWARFExpression - Add DWARFExpression in ArrayInfo; - Add LegacyDynamicArray type for dynamic arrays; - Evaluate count expression every time we re-evaluate DW_AT_location. Rebase and fix compilation failures Only print case sensitiveness if source language is Cobol or PL/1. Fixes the following regressions: LLVM :: DebugInfo/X86/dwarf-public-names.ll LLVM :: DebugInfo/X86/length_symbol_difference.ll LLVM :: MC/X86/dwarf-size-field-overflow.test LLVM :: tools/llvm-dwarfdump/X86/statistics.ll (cherry picked from commit ff848081162f81ef3c5d8f447b6c28dd564d4ada) Use correct record size of DIDerivedType Use last index for Annotations replace dyn_cast with dyn_cast_or_null to handle invalid input smoothly Rebasing on LLVM-17-init and fixes regressions LZLANG-2470 valgrind vs. lldb_private::TargetCharsetReader::convert - remove the static buffer_length variable, which may not be big enough. - remove the loop - add lldb console errno logging when there is an iconv error. (cherry picked from commit 120402f28f787a90f65f725307519343b5937fee) LZLANG-2470 Fixes for previous lldb_private::TargetCharsetReader::convert changes. (cherry picked from commit 918c9b62a63b71347ebee5a7ccd0bd42bbdfc118) Lexer Bug Fix COBOL/PLI lexer would return variable name with '\n' at the start. 1155199180 (cherry picked from commit 7266c35747b19a11081b3fab07f6773bfb15fa1f) Ported Abhishek's Fix -Set is_singed for int variables [lldb] Bridge the gap when debugging the variable with command and codelldb (cherry picked from commit d88ad8abed856d239628d4cda3fad393fef1ba0e) Build Fixes after cherry-pick previous commit strings set by codelldb must be enclosed in quotes (cherry picked from commit 0072c09fbe9f5ead6bde25060dc8e9f4265989b3) Bug fix: p var = val in PLI didn't work (cherry picked from commit 9f3d16f85434cbd17e26d429622cd6b557eddacb) Port Abhisheks Fixes -Fix for MOVE val TO VAR [lldb] Added the DemangledNameContainsPath overload for pli/cobol (cherry picked from commit 552cf62d001beb59327e4fb81cd4620ee0d62c55) Fix warnings Fields of a struct array can now be used with `p` e.g FIELD(5) is equivalent to FIELD OF ARR(5) See ticket 1152892604 (cherry picked from commit 5e02341b015fddaca13a674b34228fe2b080a54c) Cobol-style multi-index support added (cherry picked from commit 7b0e7ae494ca2a9799e1f09d87146113de2e0f38) Fixed LENGTH(var) expression -get the size of var from lldb (cherry picked from commit 50657e2e7b2ec81a13764ca0105c130cc95ccfc7) Warning Fixes Make breakpoint Cases Insensitive Fixed Build and Regression failure after rebase Fixed warnings seen during lldb build [lldb] Store real bitwidth from debuginfo in Scalar Type Storing in higher bitwidth than required or specified by debug info creates problem when byteswap is done. Make comparison of breakpoint names case insensitive in `findEntryOffsetInCurrentIndex` 1156642284 typo fix: s/key/Key/ [lldb] Fix DWARFASTParser to correctly parse DW_AT_count for dynamic arrays [lldb] Change the way we look for variables in StackFrame for Legacy Languages 1156032652 [lldb] Bugfix in LENGTH(var) [cobol] and STG(var) [pli] We were encoding 4 bytes of LENGTH data and reading 8 bytes which cause a problem. Using size_t instead of uint32_t fixes the problem. [lldb] Fix cast failure in FindFieldInStructArray Complicated expressions in lldb broke the assumption that the expression is an identifier, thus we got a cast error. This fix removes that from happening and also fixes the bug that if the identifier is an array itself the last index specified in the input is used to index that variable itself. e.g 01 SAMPLE-TABLE. 05 TABLE-DEPTH OCCURS 3 TIMES. 10 TABLE-ROW OCCURS 3 TIMES. 15 TABLE-COLUMN OCCURS 3 TIMES PIC 9(8). Here TABLE-ROW(1, 2) means second element of TABLE-ROW OF TABLE-DEPTH(1). Revert "[lldb] Fix cast failure in FindFieldInStructArray" This reverts commit c1bab0e0b6a798698196434c7bb6cbe391fcdc1b. [lldb] Add support for IBM array-indexing syntax see 1156841764 [lldb] Fix cast error and support non-ibm indexing syntax see 1156841764 [lldb] Fixes After Rebase on llvmorg-18.1.4 [lldb] Fix bug in display of varying PLI strings See 1156884604 The STG function also should include the prefix when counting the size, which for now is 2 bytes for all strings because the PLI compiler doesn't support COMPAT(V3) version. If in the future we do support it, we would need to fix this again. (cherry picked from commit 4b39f3e1b55c3df09f5cb89dcdd347682f790ba9) [lldb] Add basic support for Level88 conditions [lldb] Add support for calling the runtime function rc_cob_level88 directly from the "p" command [lldb] Print the value of level88 variables as true/false with parent name. Prints the value of level88 condition names by calling the runtime functions and formatting it nicely. [lldb] Add support for indexed level88 variables [lldb] Fixes After Rebase on llvm main [LLDB] Preparation for upstream --- lldb/include/lldb/Core/ValueObject.h | 6 + .../include/lldb/Expression/DWARFExpression.h | 26 +- .../lldb/Expression/DWARFExpressionList.h | 2 +- lldb/include/lldb/Symbol/CompileUnit.h | 2 + lldb/include/lldb/Symbol/CompilerType.h | 23 + lldb/include/lldb/Symbol/Function.h | 38 + lldb/include/lldb/Symbol/SymbolFile.h | 1 + lldb/include/lldb/Symbol/TypeSystem.h | 28 + lldb/include/lldb/Symbol/Variable.h | 11 +- lldb/include/lldb/Symbol/VariableList.h | 9 +- lldb/include/lldb/Target/StackFrame.h | 67 + lldb/include/lldb/Target/StackFrameList.h | 3 + lldb/include/lldb/Target/Target.h | 4 + lldb/include/lldb/Utility/DataExtractor.h | 2 + lldb/include/lldb/Utility/RegularExpression.h | 3 +- lldb/include/lldb/Utility/Scalar.h | 5 + lldb/include/lldb/lldb-enumerations.h | 53 +- .../lldbsuite/test/lang/cobol/Makefile.rules | 22 + .../test/lang/cobol/global_variables/Makefile | 5 + .../TestCobolGlobalVariables.py | 42 + .../test/lang/cobol/global_variables/gvar.cob | 14 + .../Commands/CommandObjectDWIMPrint.cpp | 4 +- lldb/source/Core/Module.cpp | 5 +- lldb/source/Core/ValueObject.cpp | 119 + lldb/source/Core/ValueObjectVariable.cpp | 82 +- .../DataFormatters/ValueObjectPrinter.cpp | 12 +- lldb/source/Expression/DWARFExpression.cpp | 139 +- .../source/Expression/DWARFExpressionList.cpp | 6 +- .../Plugins/ExpressionParser/CMakeLists.txt | 2 + .../Clang/ClangUserExpression.h | 1 + .../ExpressionParser/Cobol/CMakeLists.txt | 13 + .../Plugins/ExpressionParser/Cobol/CobolAST.h | 393 +++ .../ExpressionParser/Cobol/CobolASTNodes.def | 14 + .../ExpressionParser/Cobol/CobolLexer.cpp | 215 ++ .../ExpressionParser/Cobol/CobolLexer.h | 148 ++ .../ExpressionParser/Cobol/CobolParser.cpp | 265 ++ .../ExpressionParser/Cobol/CobolParser.h | 110 + .../Cobol/CobolUserExpression.cpp | 961 +++++++ .../Cobol/CobolUserExpression.h | 142 ++ .../ExpressionParser/PLI/CMakeLists.txt | 13 + .../Plugins/ExpressionParser/PLI/PLIAST.h | 320 +++ .../Plugins/ExpressionParser/PLI/PLILexer.cpp | 213 ++ .../Plugins/ExpressionParser/PLI/PLILexer.h | 142 ++ .../ExpressionParser/PLI/PLIParser.cpp | 182 ++ .../Plugins/ExpressionParser/PLI/PLIParser.h | 105 + .../PLI/PLIUserExpression.cpp | 678 +++++ .../ExpressionParser/PLI/PLIUserExpression.h | 126 + lldb/source/Plugins/Language/CMakeLists.txt | 2 + .../Plugins/Language/Cobol/CMakeLists.txt | 12 + .../Plugins/Language/Cobol/CobolLanguage.cpp | 167 ++ .../Plugins/Language/Cobol/CobolLanguage.h | 69 + .../Plugins/Language/PLI/CMakeLists.txt | 13 + .../source/Plugins/Language/PLI/PLIBitset.cpp | 96 + .../Plugins/Language/PLI/PLILanguage.cpp | 136 + .../source/Plugins/Language/PLI/PLILanguage.h | 73 + .../BSD-Archive/ObjectContainerBSDArchive.cpp | 10 +- .../Plugins/SymbolFile/DWARF/CMakeLists.txt | 1 + .../SymbolFile/DWARF/DWARFASTParser.cpp | 22 +- .../Plugins/SymbolFile/DWARF/DWARFASTParser.h | 2 +- .../SymbolFile/DWARF/DWARFASTParserClang.cpp | 6 +- .../SymbolFile/DWARF/DWARFASTParserLegacy.cpp | 720 ++++++ .../SymbolFile/DWARF/DWARFASTParserLegacy.h | 93 + .../Plugins/SymbolFile/DWARF/DWARFDIE.cpp | 11 +- .../Plugins/SymbolFile/DWARF/DWARFDIE.h | 4 +- .../SymbolFile/DWARF/DWARFDebugInfoEntry.cpp | 47 +- .../SymbolFile/DWARF/DWARFDebugInfoEntry.h | 18 +- .../Plugins/SymbolFile/DWARF/DWARFUnit.cpp | 26 + .../Plugins/SymbolFile/DWARF/DWARFUnit.h | 7 + .../SymbolFile/DWARF/ManualDWARFIndex.cpp | 4 + .../SymbolFile/DWARF/ManualDWARFIndex.h | 11 + .../Plugins/SymbolFile/DWARF/NameToDIE.cpp | 9 +- .../Plugins/SymbolFile/DWARF/NameToDIE.h | 3 + .../SymbolFile/DWARF/SymbolFileDWARF.cpp | 28 +- .../SymbolFile/DWARF/SymbolFileDWARF.h | 4 +- lldb/source/Plugins/TypeSystem/CMakeLists.txt | 1 + .../TypeSystem/Clang/TypeSystemClang.h | 3 +- .../Plugins/TypeSystem/Legacy/CMakeLists.txt | 16 + .../TypeSystem/Legacy/TypeSystemLegacy.cpp | 2226 +++++++++++++++++ .../TypeSystem/Legacy/TypeSystemLegacy.h | 726 ++++++ lldb/source/Symbol/CompilerType.cpp | 53 + lldb/source/Symbol/Function.cpp | 2 +- lldb/source/Symbol/ObjectFile.cpp | 2 +- lldb/source/Symbol/TypeSystem.cpp | 30 + lldb/source/Symbol/Variable.cpp | 16 +- lldb/source/Symbol/VariableList.cpp | 11 +- lldb/source/Target/StackFrame.cpp | 252 +- lldb/source/Target/StackFrameList.cpp | 21 + lldb/source/Target/Target.cpp | 12 + lldb/source/Target/TargetProperties.td | 6 + lldb/source/Utility/DataExtractor.cpp | 16 + lldb/source/Utility/RegularExpression.cpp | 13 +- lldb/source/Utility/Scalar.cpp | 9 + .../Shell/Process/UnsupportedLanguage.test | 6 +- lldb/tools/lldb-server/CMakeLists.txt | 1 + .../Expression/DWARFExpressionTest.cpp | 22 +- .../ObjectFile/PECOFF/TestPECallFrameInfo.cpp | 3 +- llvm/include/llvm-c/DebugInfo.h | 182 +- llvm/include/llvm/AsmParser/LLToken.h | 5 + llvm/include/llvm/BinaryFormat/Dwarf.def | 60 +- llvm/include/llvm/BinaryFormat/Dwarf.h | 17 +- llvm/include/llvm/IR/DIBuilder.h | 108 +- llvm/include/llvm/IR/DebugInfoFlags.def | 30 +- llvm/include/llvm/IR/DebugInfoMetadata.h | 459 +++- llvm/lib/AsmParser/LLLexer.cpp | 5 + llvm/lib/AsmParser/LLParser.cpp | 89 +- llvm/lib/BinaryFormat/Dwarf.cpp | 7 + llvm/lib/Bitcode/Reader/MetadataLoader.cpp | 96 +- llvm/lib/Bitcode/Writer/BitcodeWriter.cpp | 39 +- .../CodeGen/AsmPrinter/DwarfCompileUnit.cpp | 76 +- .../lib/CodeGen/AsmPrinter/DwarfCompileUnit.h | 5 + llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp | 13 + .../CodeGen/AsmPrinter/DwarfExpression.cpp | 29 +- llvm/lib/CodeGen/AsmPrinter/DwarfExpression.h | 16 +- llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp | 136 +- llvm/lib/CodeGen/AsmPrinter/DwarfUnit.h | 4 + .../DebugInfo/DWARF/DWARFAcceleratorTable.cpp | 4 +- llvm/lib/DebugInfo/DWARF/DWARFExpression.cpp | 11 + llvm/lib/IR/AsmWriter.cpp | 21 +- llvm/lib/IR/DIBuilder.cpp | 108 +- llvm/lib/IR/DebugInfo.cpp | 124 +- llvm/lib/IR/DebugInfoMetadata.cpp | 139 +- llvm/lib/IR/LLVMContextImpl.h | 111 +- llvm/lib/IR/Verifier.cpp | 12 +- llvm/unittests/IR/MetadataTest.cpp | 51 + 124 files changed, 11331 insertions(+), 443 deletions(-) create mode 100644 lldb/packages/Python/lldbsuite/test/lang/cobol/Makefile.rules create mode 100644 lldb/packages/Python/lldbsuite/test/lang/cobol/global_variables/Makefile create mode 100644 lldb/packages/Python/lldbsuite/test/lang/cobol/global_variables/TestCobolGlobalVariables.py create mode 100644 lldb/packages/Python/lldbsuite/test/lang/cobol/global_variables/gvar.cob create mode 100644 lldb/source/Plugins/ExpressionParser/Cobol/CMakeLists.txt create mode 100644 lldb/source/Plugins/ExpressionParser/Cobol/CobolAST.h create mode 100644 lldb/source/Plugins/ExpressionParser/Cobol/CobolASTNodes.def create mode 100644 lldb/source/Plugins/ExpressionParser/Cobol/CobolLexer.cpp create mode 100644 lldb/source/Plugins/ExpressionParser/Cobol/CobolLexer.h create mode 100644 lldb/source/Plugins/ExpressionParser/Cobol/CobolParser.cpp create mode 100644 lldb/source/Plugins/ExpressionParser/Cobol/CobolParser.h create mode 100644 lldb/source/Plugins/ExpressionParser/Cobol/CobolUserExpression.cpp create mode 100644 lldb/source/Plugins/ExpressionParser/Cobol/CobolUserExpression.h create mode 100644 lldb/source/Plugins/ExpressionParser/PLI/CMakeLists.txt create mode 100644 lldb/source/Plugins/ExpressionParser/PLI/PLIAST.h create mode 100644 lldb/source/Plugins/ExpressionParser/PLI/PLILexer.cpp create mode 100644 lldb/source/Plugins/ExpressionParser/PLI/PLILexer.h create mode 100644 lldb/source/Plugins/ExpressionParser/PLI/PLIParser.cpp create mode 100644 lldb/source/Plugins/ExpressionParser/PLI/PLIParser.h create mode 100644 lldb/source/Plugins/ExpressionParser/PLI/PLIUserExpression.cpp create mode 100644 lldb/source/Plugins/ExpressionParser/PLI/PLIUserExpression.h create mode 100644 lldb/source/Plugins/Language/Cobol/CMakeLists.txt create mode 100644 lldb/source/Plugins/Language/Cobol/CobolLanguage.cpp create mode 100644 lldb/source/Plugins/Language/Cobol/CobolLanguage.h create mode 100644 lldb/source/Plugins/Language/PLI/CMakeLists.txt create mode 100644 lldb/source/Plugins/Language/PLI/PLIBitset.cpp create mode 100644 lldb/source/Plugins/Language/PLI/PLILanguage.cpp create mode 100644 lldb/source/Plugins/Language/PLI/PLILanguage.h create mode 100644 lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserLegacy.cpp create mode 100644 lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserLegacy.h create mode 100644 lldb/source/Plugins/TypeSystem/Legacy/CMakeLists.txt create mode 100644 lldb/source/Plugins/TypeSystem/Legacy/TypeSystemLegacy.cpp create mode 100644 lldb/source/Plugins/TypeSystem/Legacy/TypeSystemLegacy.h 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..a27b0d5c1d908b 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,27 @@ 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); + 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..570f4cb9732688 100644 --- a/lldb/include/lldb/Symbol/CompilerType.h +++ b/lldb/include/lldb/Symbol/CompilerType.h @@ -14,6 +14,8 @@ #include #include +#include "lldb/Expression/DWARFExpression.h" +#include "lldb/Expression/DWARFExpressionList.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..7248c359386c21 100644 --- a/lldb/include/lldb/Symbol/Function.h +++ b/lldb/include/lldb/Symbol/Function.h @@ -519,6 +519,36 @@ 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 +687,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..11a524e8ea8c05 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..9c41e81866d8fd 100644 --- a/lldb/include/lldb/Symbol/Variable.h +++ b/lldb/include/lldb/Symbol/Variable.h @@ -34,7 +34,8 @@ class Variable : public UserID, public std::enable_shared_from_this { 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); + 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..019e0cfbcdf26d 100644 --- a/lldb/include/lldb/Symbol/VariableList.h +++ b/lldb/include/lldb/Symbol/VariableList.h @@ -39,11 +39,12 @@ 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); + lldb::VariableSP FindVariable(ConstString name, lldb::ValueType value_type, + 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..94e98ab660c56a 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,25 @@ 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 +498,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 +604,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..904394dcd88c01 100644 --- a/lldb/include/lldb/Utility/RegularExpression.h +++ b/lldb/include/lldb/Utility/RegularExpression.h @@ -37,7 +37,7 @@ class RegularExpression { /// default is NoFlags. explicit RegularExpression( llvm::StringRef string, - llvm::Regex::RegexFlags flags = llvm::Regex::NoFlags); + llvm::Regex::RegexFlags flags = llvm::Regex::NoFlags, bool icase = false); ~RegularExpression() = default; @@ -93,6 +93,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..ebea45bd8c28a7 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, @@ -1116,19 +1131,31 @@ enum MatchType { }; /// Bitmask that describes details about a type. -FLAGS_ENUM(TypeFlags){ - eTypeHasChildren = (1u << 0), eTypeHasValue = (1u << 1), - eTypeIsArray = (1u << 2), eTypeIsBlock = (1u << 3), - eTypeIsBuiltIn = (1u << 4), eTypeIsClass = (1u << 5), - eTypeIsCPlusPlus = (1u << 6), eTypeIsEnumeration = (1u << 7), - eTypeIsFuncPrototype = (1u << 8), eTypeIsMember = (1u << 9), - eTypeIsObjC = (1u << 10), eTypeIsPointer = (1u << 11), - eTypeIsReference = (1u << 12), eTypeIsStructUnion = (1u << 13), - eTypeIsTemplate = (1u << 14), eTypeIsTypedef = (1u << 15), - eTypeIsVector = (1u << 16), eTypeIsScalar = (1u << 17), - eTypeIsInteger = (1u << 18), eTypeIsFloat = (1u << 19), - eTypeIsComplex = (1u << 20), eTypeIsSigned = (1u << 21), - eTypeInstanceIsPointer = (1u << 22)}; +FLAGS_ENUM(TypeFlags){eTypeHasChildren = (1u << 0), + eTypeHasValue = (1u << 1), + eTypeIsArray = (1u << 2), + eTypeIsBlock = (1u << 3), + eTypeIsBuiltIn = (1u << 4), + eTypeIsClass = (1u << 5), + eTypeIsCPlusPlus = (1u << 6), + eTypeIsEnumeration = (1u << 7), + eTypeIsFuncPrototype = (1u << 8), + eTypeIsMember = (1u << 9), + eTypeIsObjC = (1u << 10), + eTypeIsPointer = (1u << 11), + eTypeIsReference = (1u << 12), + eTypeIsStructUnion = (1u << 13), + eTypeIsTemplate = (1u << 14), + eTypeIsTypedef = (1u << 15), + eTypeIsVector = (1u << 16), + eTypeIsScalar = (1u << 17), + eTypeIsInteger = (1u << 18), + eTypeIsFloat = (1u << 19), + eTypeIsComplex = (1u << 20), + eTypeIsSigned = (1u << 21), + 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..7d1b228894b4d8 100644 --- a/lldb/source/Core/Module.cpp +++ b/lldb/source/Core/Module.cpp @@ -765,8 +765,9 @@ 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..1844ea8a1245b4 100644 --- a/lldb/source/Core/ValueObject.cpp +++ b/lldb/source/Core/ValueObject.cpp @@ -42,6 +42,7 @@ #include "lldb/Target/ThreadList.h" #include "lldb/Utility/DataBuffer.h" #include "lldb/Utility/DataBufferHeap.h" +#include "lldb/Utility/DataEncoder.h" #include "lldb/Utility/Flags.h" #include "lldb/Utility/LLDBLog.h" #include "lldb/Utility/Log.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..f935f2883245bf 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,82 @@ 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); + 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 +389,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..c671ec20ee6403 100644 --- a/lldb/source/DataFormatters/ValueObjectPrinter.cpp +++ b/lldb/source/DataFormatters/ValueObjectPrinter.cpp @@ -366,11 +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); - else { + skip_summary = true; + } else { const char *val_cstr = valobj.GetValueAsCString(); if (val_cstr) value.assign(val_cstr); @@ -396,7 +398,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 +840,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..0481f1bb4899ac 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,53 @@ 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 +2100,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 +2126,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 +2353,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..46950c33bcedf5 100644 --- a/lldb/source/Expression/DWARFExpressionList.cpp +++ b/lldb/source/Expression/DWARFExpressionList.cpp @@ -8,6 +8,7 @@ #include "lldb/Expression/DWARFExpressionList.h" #include "Plugins/SymbolFile/DWARF/DWARFUnit.h" +#include "lldb/Core/Value.h" #include "lldb/Symbol/Function.h" #include "lldb/Target/RegisterContext.h" #include "lldb/Target/StackFrame.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..2bf5c62e8da2f4 --- /dev/null +++ b/lldb/source/Plugins/ExpressionParser/Cobol/CobolAST.h @@ -0,0 +1,393 @@ +//===-- 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..12610112ff1498 --- /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..e2e5ec317e3a6f --- /dev/null +++ b/lldb/source/Plugins/ExpressionParser/Cobol/CobolUserExpression.cpp @@ -0,0 +1,961 @@ +//===-- 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..1cc49bd5c0bdb3 --- /dev/null +++ b/lldb/source/Plugins/ExpressionParser/Cobol/CobolUserExpression.h @@ -0,0 +1,142 @@ +//===- 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..867fc137373ea3 --- /dev/null +++ b/lldb/source/Plugins/ExpressionParser/PLI/PLILexer.cpp @@ -0,0 +1,213 @@ +//===-- 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..c1fc2ea0171922 --- /dev/null +++ b/lldb/source/Plugins/ExpressionParser/PLI/PLIUserExpression.cpp @@ -0,0 +1,678 @@ +//===-- 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..f6194f17ea1111 --- /dev/null +++ b/lldb/source/Plugins/ExpressionParser/PLI/PLIUserExpression.h @@ -0,0 +1,126 @@ +//===-- 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..726ed4053dda81 --- /dev/null +++ b/lldb/source/Plugins/Language/Cobol/CobolLanguage.cpp @@ -0,0 +1,167 @@ +//===-- 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 "Plugins/TypeSystem/Legacy/TypeSystemLegacy.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" + +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..d9a4684328fe6c --- /dev/null +++ b/lldb/source/Plugins/Language/PLI/PLIBitset.cpp @@ -0,0 +1,96 @@ +//===-- 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..5b71e457187c66 --- /dev/null +++ b/lldb/source/Plugins/Language/PLI/PLILanguage.cpp @@ -0,0 +1,136 @@ +//===-- 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..8c559957b44196 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,8 +468,8 @@ size_t ObjectContainerBSDArchive::GetModuleSpecifications( continue; FileSpec child = GetChildFileSpecificationsFromThin( object->ar_name.GetStringRef(), file); - if (ObjectFile::GetModuleSpecifications(child, 0, object->file_size, - specs)) { + if (lldb_private::ObjectFile::GetModuleSpecifications( + child, 0, object->file_size, specs)) { ModuleSpec &spec = specs.GetModuleSpecRefAtIndex(specs.GetSize() - 1); llvm::sys::TimePoint<> object_mod_time( @@ -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..d082b12656fbd7 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,19 @@ 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 +109,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..fc88e6fa9522b0 --- /dev/null +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserLegacy.cpp @@ -0,0 +1,720 @@ +//===-- 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..8d388df750b68f --- /dev/null +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserLegacy.h @@ -0,0 +1,93 @@ +//===-- 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..9cd1adec020034 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp @@ -573,11 +573,14 @@ 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); + return m_die->GetDIENamesAndRanges(GetCU(), name, mangled, ranges, + decl_file, decl_line, decl_column, + 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..87f457bc704398 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp @@ -121,11 +121,14 @@ 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 +229,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 +281,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 +309,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..0bc8bffca1e6f8 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h @@ -106,15 +106,15 @@ class DWARFDebugInfoEntry { const char *GetPubname(const DWARFUnit *cu) const; - bool GetDIENamesAndRanges(DWARFUnit *cu, const char *&name, - const char *&mangled, DWARFRangeList &rangeList, - 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 = nullptr) const; + bool GetDIENamesAndRanges( + DWARFUnit *cu, const char *&name, const char *&mangled, + DWARFRangeList &rangeList, 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 = 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..ffd1525775f282 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..9e6a0de198945d 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..670e9132f70253 --- /dev/null +++ b/lldb/source/Plugins/TypeSystem/Legacy/TypeSystemLegacy.cpp @@ -0,0 +1,2226 @@ +//===-- 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..91a48a20f033a8 --- /dev/null +++ b/lldb/source/Plugins/TypeSystem/Legacy/TypeSystemLegacy.h @@ -0,0 +1,726 @@ +//===-- 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/Core/Debugger.h" +#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" + +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..cf87b036518341 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..38c673f807f1a1 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..5a153f9ad8810d 100644 --- a/lldb/source/Symbol/Variable.cpp +++ b/lldb/source/Symbol/Variable.cpp @@ -43,13 +43,16 @@ Variable::Variable(lldb::user_id_t uid, const char *name, const char *mangled, const RangeList &scope_range, Declaration *decl_ptr, const DWARFExpressionList &location_list, bool external, bool artificial, bool location_is_constant_data, - bool static_member) + 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_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_has_descriptor(has_descriptor), + m_lexical_scope(lexical_scope) {} Variable::~Variable() = default; @@ -79,8 +82,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..da7d35456abf98 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,54 @@ 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 +661,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 +722,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 +809,20 @@ 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 +842,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 +1030,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 +1208,60 @@ 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 +1277,44 @@ 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 +1354,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 +1927,35 @@ 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( - 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); + /* + 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)) { + // LegacyLanguages listed above are case insensitive + var_sp = variable_list.FindVariable(name, true, !LegacyLangauage); } if (var_sp) @@ -1806,6 +2018,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 +2094,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..77ab406bf1df29 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..1cb87fe97d975c 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 < GetByteSize(); ++i) { + if (lhs_ptr[i] != rhs_ptr[i]) + return false; + } + return true; +} + bool DataExtractor::Append(DataExtractor &rhs) { if (rhs.GetByteOrder() != GetByteOrder()) return false; diff --git a/lldb/source/Utility/RegularExpression.cpp b/lldb/source/Utility/RegularExpression.cpp index 026793462221ce..0a284ed2be9a40 100644 --- a/lldb/source/Utility/RegularExpression.cpp +++ b/lldb/source/Utility/RegularExpression.cpp @@ -13,13 +13,16 @@ using namespace lldb_private; RegularExpression::RegularExpression(llvm::StringRef str, - llvm::Regex::RegexFlags flags) - : m_regex_text(std::string(str)), - // m_regex does not reference str anymore after it is constructed. - m_regex(llvm::Regex(str, flags)) {} + llvm::Regex::RegexFlags flags, bool icase) + : m_regex_text(std::string(str)) { + unsigned Flags = icase ? llvm::Regex::IgnoreCase : llvm::Regex::NoFlags; + // m_regex does not reference str anymore after it is constructed. + m_regex = llvm::Regex(str, Flags); +} RegularExpression::RegularExpression(const RegularExpression &rhs) - : RegularExpression(rhs.GetText()) {} + : RegularExpression(rhs.GetText(), rhs.icase ? llvm::Regex::IgnoreCase + : llvm::Regex::NoFlags) {} bool RegularExpression::Execute( llvm::StringRef str, diff --git a/lldb/source/Utility/Scalar.cpp b/lldb/source/Utility/Scalar.cpp index 329f5b6e4b9a5b..3d99dfdb1567aa 100644 --- a/lldb/source/Utility/Scalar.cpp +++ b/lldb/source/Utility/Scalar.cpp @@ -501,6 +501,15 @@ bool Scalar::UnaryNegate() { return false; } +bool Scalar::ByteSwap() { + if (m_type == e_int) { + m_integer = m_integer.byteSwap(); + return true; + } + + return false; +} + bool Scalar::OnesComplement() { if (m_type == e_int) { m_integer = ~m_integer; diff --git a/lldb/test/Shell/Process/UnsupportedLanguage.test b/lldb/test/Shell/Process/UnsupportedLanguage.test index d7e6e5de77512f..19dcabc7c89a2f 100644 --- a/lldb/test/Shell/Process/UnsupportedLanguage.test +++ b/lldb/test/Shell/Process/UnsupportedLanguage.test @@ -10,8 +10,8 @@ RUN: %lldb -o "b main" -o r -o q -b %t.exe 2>&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..1588ab617fd06b 100644 --- a/lldb/unittests/Expression/DWARFExpressionTest.cpp +++ b/lldb/unittests/Expression/DWARFExpressionTest.cpp @@ -34,11 +34,19 @@ static llvm::Expected Evaluate(llvm::ArrayRef expr, DataExtractor extractor(expr.data(), expr.size(), lldb::eByteOrderLittle, /*addr_size*/ 4); + std::vector stack; + llvm::Expected 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, 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, stack); if (!result) return result.takeError(); @@ -455,12 +463,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 +540,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 +818,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 +839,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..152b68bd4f8888 100644 --- a/llvm/include/llvm-c/DebugInfo.h +++ b/llvm/include/llvm-c/DebugInfo.h @@ -64,9 +64,10 @@ typedef enum { LLVMDIFlagNonTrivial = 1 << 26, LLVMDIFlagBigEndian = 1 << 27, LLVMDIFlagLittleEndian = 1 << 28, + LLVMDIFlagBinaryScale = 1 << 30, LLVMDIFlagIndirectVirtualBase = (1 << 2) | (1 << 5), - LLVMDIFlagAccessibility = LLVMDIFlagPrivate | LLVMDIFlagProtected | - LLVMDIFlagPublic, + LLVMDIFlagAccessibility = + LLVMDIFlagPrivate | LLVMDIFlagProtected | LLVMDIFlagPublic, LLVMDIFlagPtrToMemberRep = LLVMDIFlagSingleInheritance | LLVMDIFlagMultipleInheritance | LLVMDIFlagVirtualInheritance @@ -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,37 @@ 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 +728,23 @@ 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 +786,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 +972,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 +1204,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 +1248,21 @@ 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 +1476,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 +1552,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..aefff6839aeba1 100644 --- a/llvm/include/llvm/IR/DIBuilder.h +++ b/llvm/include/llvm/IR/DIBuilder.h @@ -251,6 +251,23 @@ 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 +275,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 +619,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 +769,21 @@ 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,32 @@ 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. @@ -798,16 +861,16 @@ namespace llvm { /// \param Annotations Attribute Annotations. /// \param TargetFuncName The name of the target function if this is /// a trampoline. - DISubprogram * - createFunction(DIScope *Scope, StringRef Name, StringRef LinkageName, - DIFile *File, unsigned LineNo, DISubroutineType *Ty, - unsigned ScopeLine, DINode::DIFlags Flags = DINode::FlagZero, - DISubprogram::DISPFlags SPFlags = DISubprogram::SPFlagZero, - DITemplateParameterArray TParams = nullptr, - DISubprogram *Decl = nullptr, - DITypeArray ThrownTypes = nullptr, - DINodeArray Annotations = nullptr, - StringRef TargetFuncName = ""); + DISubprogram *createFunction( + DIScope *Scope, StringRef Name, StringRef LinkageName, DIFile *File, + unsigned LineNo, DISubroutineType *Ty, unsigned ScopeLine, + DINode::DIFlags Flags = DINode::FlagZero, + DISubprogram::DISPFlags SPFlags = DISubprogram::SPFlagZero, + DITemplateParameterArray TParams = nullptr, + DISubprogram *Decl = nullptr, DITypeArray ThrownTypes = nullptr, + DINodeArray Annotations = nullptr, StringRef TargetFuncName = "", + DIExpression *StaticLink = nullptr, + DIExpression *RcFrameBase = nullptr); /// Identical to createFunction, /// except that the resulting DbgNode is meant to be RAUWed. @@ -838,15 +901,14 @@ namespace llvm { /// \param SPFlags Additional flags specific to subprograms. /// \param TParams Function template parameters. /// \param ThrownTypes Exception types this function may throw. - DISubprogram * - createMethod(DIScope *Scope, StringRef Name, StringRef LinkageName, - DIFile *File, unsigned LineNo, DISubroutineType *Ty, - unsigned VTableIndex = 0, int ThisAdjustment = 0, - DIType *VTableHolder = nullptr, - DINode::DIFlags Flags = DINode::FlagZero, - DISubprogram::DISPFlags SPFlags = DISubprogram::SPFlagZero, - DITemplateParameterArray TParams = nullptr, - DITypeArray ThrownTypes = nullptr); + DISubprogram *createMethod( + DIScope *Scope, StringRef Name, StringRef LinkageName, DIFile *File, + unsigned LineNo, DISubroutineType *Ty, unsigned VTableIndex = 0, + int ThisAdjustment = 0, DIType *VTableHolder = nullptr, + DINode::DIFlags Flags = DINode::FlagZero, + DISubprogram::DISPFlags SPFlags = DISubprogram::SPFlagZero, + DITemplateParameterArray TParams = 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 +1117,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..3f3d9f26cff2b4 100644 --- a/llvm/include/llvm/IR/DebugInfoMetadata.h +++ b/llvm/include/llvm/IR/DebugInfoMetadata.h @@ -20,6 +20,7 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/iterator_range.h" +#include "llvm/BinaryFormat/Dwarf.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DbgVariableFragmentInfo.h" #include "llvm/IR/Metadata.h" @@ -582,7 +583,8 @@ 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 +610,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 +795,9 @@ 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 +821,33 @@ 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 +855,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, - ShouldCreate); + 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 +902,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 +910,22 @@ 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 +937,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 +1108,13 @@ 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); + Annotations.get(), Location, Allocated, Storage, + ShouldCreate); } static DIDerivedType * getImpl(LLVMContext &Context, unsigned Tag, MDString *Name, Metadata *File, @@ -1041,30 +1122,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 +1153,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)) + Flags, ExtraData, Annotations, Location, Allocated)) TempDIDerivedType clone() const { return cloneImpl(); } @@ -1130,6 +1213,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 +1250,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. @@ -1178,37 +1289,39 @@ class DICompositeType : public DIType { 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, + 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, Elements.get(), - RuntimeLang, VTableHolder, TemplateParams.get(), + 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); + 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()); + getFlags(), getVendorDIFlags(), getElements(), getRuntimeLang(), + getVTableHolder(), getTemplateParams(), getIdentifier(), + getDiscriminator(), getRawDataLocation(), getRawAssociated(), + getRawAllocated(), getRawRank(), getAnnotations()); } public: @@ -1224,9 +1337,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 +1351,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 +1483,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 +1713,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 +1867,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 +1888,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,7 +1896,9 @@ class DISubprogram : public DILocalScope { Flags, SPFlags, Unit, TemplateParams.get(), Declaration, RetainedNodes.get(), ThrownTypes.get(), Annotations.get(), getCanonicalMDString(Context, TargetFuncName), - Storage, ShouldCreate); + dyn_cast_or_null(StaticLinkExpr), + dyn_cast_or_null(RcFrameBaseExpr), Storage, + ShouldCreate); } static DISubprogram * getImpl(LLVMContext &Context, Metadata *Scope, MDString *Name, @@ -1744,17 +1907,18 @@ 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 { - return getTemporary(getContext(), getScope(), getName(), getLinkageName(), - getFile(), getLine(), getType(), getScopeLine(), - getContainingType(), getVirtualIndex(), - getThisAdjustment(), getFlags(), getSPFlags(), - getUnit(), getTemplateParams(), getDeclaration(), - getRetainedNodes(), getThrownTypes(), getAnnotations(), - getTargetFuncName()); + return getTemporary( + getContext(), getScope(), getName(), getLinkageName(), getFile(), + getLine(), getType(), getScopeLine(), getContainingType(), + getVirtualIndex(), getThisAdjustment(), getFlags(), getSPFlags(), + getUnit(), getTemplateParams(), getDeclaration(), getRetainedNodes(), + getThrownTypes(), getAnnotations(), getTargetFuncName(), + getStaticLinkExpr(), getRcFrameBaseExpr()); } public: @@ -1767,10 +1931,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 +1946,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 +1978,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 +2070,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 +2100,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 +2114,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 +2908,52 @@ 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 +3010,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,13 +3220,13 @@ class DIExpression : public MDNode { EntryValue = 1 << 3 }; - /// Prepend \p DIExpr with a deref and offset operation and optionally turn it - /// into a stack value or/and an entry value. + /// 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 - /// stack value. + /// Prepend \p DIExpr with the given opcodes and std::optionally turn it into + /// a stack value. static DIExpression *prependOpcodes(const DIExpression *Expr, SmallVectorImpl &Ops, bool StackValue = false, @@ -3424,34 +3633,52 @@ 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, + 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(), - Storage, ShouldCreate); + 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, - uint32_t AlignInBits, Metadata *Annotations, - StorageType Storage, - bool ShouldCreate = true); + static DILocalVariable * + getImpl(LLVMContext &Context, Metadata *Scope, MDString *Name, Metadata *File, + unsigned Line, Metadata *Type, unsigned Arg, unsigned LexScope, + DIFlags Flags, DIVarFlags VarFlags, uint32_t AlignInBits, + Metadata *Annotations, StorageType Storage, bool ShouldCreate = true); TempDILocalVariable cloneImpl() const { return getTemporary(getContext(), getScope(), getName(), getFile(), @@ -3464,14 +3691,42 @@ 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, 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, Flags, AlignInBits, - Annotations)) + (Scope, Name, File, Line, Type, Arg, LexScope, Flags, + VarFlags, AlignInBits, Annotations)) TempDILocalVariable clone() const { return cloneImpl(); } @@ -3484,7 +3739,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 +3751,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 +4301,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..6f23b30ab6f55c 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)); \ @@ -5400,11 +5447,11 @@ bool LLParser::parseDIDerivedType(MDNode *&Result, bool IsDistinct) { (unsigned)ptrAuthExtraDiscriminator.Val, ptrAuthIsaPointer.Val, ptrAuthAuthenticatesNullValues.Val); - 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)); + 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, location.Val, allocated.Val)); return false; } @@ -5588,7 +5635,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 +5657,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 +5899,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 +5947,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..9f55711adc8f8b 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,23 +1597,28 @@ 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, - (Context, Record[1], getMDString(Record[2]), - getMDOrNull(Record[3]), Record[4], - getDITypeRefOrNull(Record[5]), - getDITypeRefOrNull(Record[6]), Record[7], Record[8], - Record[9], DWARFAddressSpace, PtrAuthData, Flags, - getDITypeRefOrNull(Record[11]), Annotations)), + GET_OR_DISTINCT( + DIDerivedType, + (Context, Record[1], getMDString(Record[2]), getMDOrNull(Record[3]), + Record[4], getDITypeRefOrNull(Record[5]), + getDITypeRefOrNull(Record[6]), Record[7], Record[8], Record[9], + DWARFAddressSpace, PtrAuthData, Flags, + getDITypeRefOrNull(Record[11]), Annotations, Location, Allocated)), NextMetadataNo); NextMetadataNo++; break; @@ -1793,7 +1817,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 +1867,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 +1910,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 +2193,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..06a9c45ce466ea 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..300be04d147311 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..3b726fe18b57b1 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..753bb3d0432145 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp @@ -482,16 +482,21 @@ static bool isMemoryLocation(DIExpressionCursor ExprCursor) { return true; } -void DwarfExpression::addExpression(DIExpressionCursor &&ExprCursor) { - addExpression(std::move(ExprCursor), - [](unsigned Idx, DIExpressionCursor &Cursor) -> bool { - llvm_unreachable("unhandled opcode found in expression"); - }); +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 +606,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 +688,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..6bbb876320b401 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 @@ -280,7 +284,12 @@ 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). @@ -288,7 +297,8 @@ class DwarfExpression { /// \return false if any call to (\p InsertArg) returns false. bool addExpression( DIExpressionCursor &&Expr, - llvm::function_ref InsertArg); + 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 +334,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 +365,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..2f97eee328890e 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp @@ -75,6 +75,13 @@ 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 +251,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 +739,27 @@ 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 +846,43 @@ 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 +1434,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); @@ -1400,10 +1477,19 @@ void DwarfUnit::constructSubrangeDIE(DIE &Buffer, const DISubrange *SR, if (auto *VarDIE = getDIE(BV)) addDIEEntry(DW_Subrange, Attr, *VarDIE); } 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 +1605,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 +1625,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 +1645,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 +1665,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..2d5c193d8e1ede 100644 --- a/llvm/lib/DebugInfo/DWARF/DWARFExpression.cpp +++ b/llvm/lib/DebugInfo/DWARF/DWARFExpression.cpp @@ -8,7 +8,9 @@ #include "llvm/DebugInfo/DWARF/DWARFExpression.h" #include "llvm/ADT/SmallString.h" +#include "llvm/BinaryFormat/Dwarf.h" #include "llvm/DebugInfo/DWARF/DWARFUnit.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..dc3017bce79b77 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,14 @@ 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 +625,13 @@ 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) @@ -784,16 +815,17 @@ DIGlobalVariable *DIBuilder::createTempGlobalVariableFwdDecl( } static DILocalVariable *createLocalVariable( - LLVMContext &VMContext, - SmallVectorImpl &PreservedNodes, + LLVMContext &VMContext, SmallVectorImpl &PreservedNodes, DIScope *Context, StringRef Name, unsigned ArgNo, DIFile *File, unsigned LineNo, DIType *Ty, bool AlwaysPreserve, DINode::DIFlags Flags, + 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,7 +844,19 @@ 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( @@ -824,7 +868,20 @@ 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 +898,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 @@ -857,14 +922,14 @@ DISubprogram *DIBuilder::createFunction( unsigned LineNo, DISubroutineType *Ty, unsigned ScopeLine, DINode::DIFlags Flags, DISubprogram::DISPFlags SPFlags, DITemplateParameterArray TParams, DISubprogram *Decl, - DITypeArray ThrownTypes, DINodeArray Annotations, - StringRef TargetFuncName) { + DITypeArray ThrownTypes, DINodeArray Annotations, 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); + 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,14 @@ 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..8ef8c0a4804a12 100644 --- a/llvm/lib/IR/DebugInfo.cpp +++ b/llvm/lib/IR/DebugInfo.cpp @@ -1046,8 +1046,15 @@ 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() { @@ -1146,6 +1153,24 @@ LLVMMetadataRef LLVMDIBuilderCreateFunction( 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,17 @@ 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 +1388,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 +1548,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 +1678,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 +1839,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..3c954f9f6dbabe 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); \ @@ -660,17 +665,20 @@ DIEnumerator *DIEnumerator::getImpl(LLVMContext &Context, const APInt &Value, DEFINE_GETIMPL_STORE(DIEnumerator, (Value, IsUnsigned), Ops); } -DIBasicType *DIBasicType::getImpl(LLVMContext &Context, unsigned Tag, - MDString *Name, uint64_t SizeInBits, - uint32_t AlignInBits, unsigned Encoding, - DIFlags Flags, StorageType Storage, - bool ShouldCreate) { +DIBasicType * +DIBasicType::getImpl(LLVMContext &Context, unsigned Tag, 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 { @@ -741,13 +749,15 @@ DIDerivedType *DIDerivedType::getImpl( uint32_t AlignInBits, uint64_t OffsetInBits, std::optional DWARFAddressSpace, std::optional PtrAuthData, DIFlags Flags, Metadata *ExtraData, - Metadata *Annotations, StorageType Storage, bool ShouldCreate) { + 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}; + DEFINE_GETIMPL_LOOKUP( + DIDerivedType, (Tag, Name, File, Line, Scope, BaseType, SizeInBits, + AlignInBits, OffsetInBits, DWARFAddressSpace, 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 +775,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 +793,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 +1040,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,7 +1138,8 @@ DISubprogram *DISubprogram::getImpl( int ThisAdjustment, DIFlags Flags, DISPFlags SPFlags, Metadata *Unit, Metadata *TemplateParams, Metadata *Declaration, Metadata *RetainedNodes, Metadata *ThrownTypes, Metadata *Annotations, MDString *TargetFuncName, - StorageType Storage, bool ShouldCreate) { + Metadata *StaticLink, Metadata *RcFrameBase, StorageType Storage, + bool ShouldCreate) { assert(isCanonical(Name) && "Expected canonical MDString"); assert(isCanonical(LinkageName) && "Expected canonical MDString"); assert(isCanonical(TargetFuncName) && "Expected canonical MDString"); @@ -1136,22 +1148,27 @@ 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) { + File, Scope, Name, LinkageName, Type, + Unit, Declaration, RetainedNodes, ContainingType, TemplateParams, + ThrownTypes, Annotations, TargetFuncName, StaticLink, RcFrameBase}; + if (!RcFrameBase) { Ops.pop_back(); - if (!Annotations) { + if (!StaticLink) { Ops.pop_back(); - if (!ThrownTypes) { + 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(); + } + } } } } @@ -1301,21 +1318,23 @@ DIGlobalVariable::getImpl(LLVMContext &Context, Metadata *Scope, MDString *Name, (Line, IsLocalToUnit, IsDefinition, AlignInBits), Ops); } -DILocalVariable * -DILocalVariable::getImpl(LLVMContext &Context, Metadata *Scope, MDString *Name, - Metadata *File, unsigned Line, Metadata *Type, - unsigned Arg, DIFlags Flags, uint32_t AlignInBits, - Metadata *Annotations, StorageType Storage, - bool ShouldCreate) { +DILocalVariable *DILocalVariable::getImpl( + LLVMContext &Context, Metadata *Scope, MDString *Name, Metadata *File, + unsigned Line, Metadata *Type, 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. assert(Arg <= UINT16_MAX && "Expected argument number to fit in 16-bits"); 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 +1383,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 +1436,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 +1505,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 +2257,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..b9ca86421b4726 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,18 +553,21 @@ 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) + 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) {} + 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()), @@ -564,7 +575,8 @@ template <> struct MDNodeKeyImpl { OffsetInBits(N->getOffsetInBits()), AlignInBits(N->getAlignInBits()), DWARFAddressSpace(N->getDWARFAddressSpace()), PtrAuthData(N->getPtrAuthData()), Flags(N->getFlags()), - ExtraData(N->getRawExtraData()), Annotations(N->getRawAnnotations()) {} + 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,33 @@ 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 +1216,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,9 +1509,10 @@ 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: - /// 1). 0 => threshold disabled. All emarks will be printed. - /// 2). positive int => manual threshold by user. Remarks with hotness exceed + /// 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. /// 3). None => 'auto' threshold by user. The actual value is not /// available at command line, but will be synced with @@ -1526,7 +1563,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..da68f2f17475bf 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()); - 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). diff --git a/llvm/unittests/IR/MetadataTest.cpp b/llvm/unittests/IR/MetadataTest.cpp index 17573ca57e0874..5d9c94ec23056c 100644 --- a/llvm/unittests/IR/MetadataTest.cpp +++ b/llvm/unittests/IR/MetadataTest.cpp @@ -1825,6 +1825,57 @@ 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) {